[
  {
    "path": ".artifacts",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# Please add new modules to the end of the list.\n\ndubbo\ndubbo-auth\ndubbo-apache-release\ndubbo-all-shaded\ndubbo-bom\ndubbo-cluster\ndubbo-common\ndubbo-compatible\ndubbo-compiler\ndubbo-config\ndubbo-config-api\ndubbo-config-spring\ndubbo-config-spring6\ndubbo-configcenter\ndubbo-configcenter-file\ndubbo-configcenter-apollo\ndubbo-configcenter-nacos\ndubbo-configcenter-zookeeper\ndubbo-core-spi\ndubbo-dependencies-all\ndubbo-dependencies-bom\ndubbo-filter-cache\ndubbo-filter-validation\ndubbo-kubernetes\ndubbo-maven-plugin\ndubbo-mcp\ndubbo-metadata\ndubbo-metadata-api\ndubbo-metadata-definition-protobuf\ndubbo-metadata-processor\ndubbo-metadata-report-nacos\ndubbo-metadata-report-zookeeper\ndubbo-metrics\ndubbo-metrics-api\ndubbo-metrics-default\ndubbo-metrics-metadata\ndubbo-metrics-prometheus\ndubbo-metrics-otlp\ndubbo-metrics-registry\ndubbo-metrics-config-center\ndubbo-metrics-netty\ndubbo-metrics-event\ndubbo-mutiny\ndubbo-native\ndubbo-parent\ndubbo-plugin\ndubbo-qos\ndubbo-qos-api\ndubbo-reactive\ndubbo-registry\ndubbo-registry-api\ndubbo-registry-multicast\ndubbo-registry-multiple\ndubbo-registry-nacos\ndubbo-registry-zookeeper\ndubbo-remoting\ndubbo-remoting-api\ndubbo-remoting-http12\ndubbo-remoting-http3\ndubbo-remoting-websocket\ndubbo-remoting-netty\ndubbo-remoting-netty4\ndubbo-remoting-zookeeper-curator5\ndubbo-rpc\ndubbo-rpc-api\ndubbo-rpc-dubbo\ndubbo-rpc-injvm\ndubbo-rpc-triple\ndubbo-security\ndubbo-serialization\ndubbo-serialization-api\ndubbo-serialization-fastjson2\ndubbo-serialization-hessian2\ndubbo-spring-boot\ndubbo-spring-boot-actuator\ndubbo-spring-boot-actuator-autoconfigure\ndubbo-spring-boot-actuator-compatible\ndubbo-spring-boot-autoconfigure\ndubbo-spring-boot-3-autoconfigure\ndubbo-spring-boot-autoconfigure-compatible\ndubbo-spring-boot-actuator-autoconfigure-compatible\ndubbo-spring-boot-compatible\ndubbo-tracing-brave-zipkin-spring-boot-starter\ndubbo-tracing-otel-zipkin-spring-boot-starter\ndubbo-tracing-otel-otlp-spring-boot-starter\ndubbo-observability-spring-boot-starter\ndubbo-spring-boot-starter\ndubbo-spring-boot-starters\ndubbo-spring-boot-interceptor\ndubbo-nacos-spring-boot-starter\ndubbo-zookeeper-curator5-spring-boot-starter\ndubbo-sentinel-spring-boot-starter\ndubbo-seata-spring-boot-starter\ndubbo-spring-security\ndubbo-spring6-security\ndubbo-tracing\ndubbo-xds\ndubbo-plugin-loom\ndubbo-rest-jaxrs\ndubbo-rest-spring\ndubbo-rest-openapi\ndubbo-triple-servlet\ndubbo-triple-websocket\n"
  },
  {
    "path": ".asf.yaml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\nnotifications:\n  commits:      commits@dubbo.apache.org\n  issues:       notifications@dubbo.apache.org\n  pullrequests: notifications@dubbo.apache.org\n  jira_options: link label link label\n  discussions: notifications@dubbo.apache.org\n\ngithub:\n  homepage: https://dubbo.apache.org/\n  description: \"The java implementation of Apache Dubbo. An RPC and microservice framework.\"\n  features:\n    # Enable wiki for documentation\n    wiki: true\n    # Enable issue management\n    issues: true\n    # Enable projects for project management boards\n    projects: true\n    # Enable GitHub Discussions for community discussions\n    discussions: true\n  protected_branches:\n    master: \n      required_pull_request_reviews:\n        dismiss_stale_reviews: true\n        require_last_push_approval: true\n        required_approving_review_count: 2\n    2.5.x: \n      required_pull_request_reviews:\n        dismiss_stale_reviews: true\n        require_last_push_approval: true\n        required_approving_review_count: 2\n    2.6.x: \n      required_pull_request_reviews:\n        dismiss_stale_reviews: true\n        require_last_push_approval: true\n        required_approving_review_count: 2\n    2.7.x: \n      required_pull_request_reviews:\n        dismiss_stale_reviews: true\n        require_last_push_approval: true\n        required_approving_review_count: 2\n    3.0: \n      required_pull_request_reviews:\n        dismiss_stale_reviews: true\n        require_last_push_approval: true\n        required_approving_review_count: 2\n    3.1: \n      required_pull_request_reviews:\n        dismiss_stale_reviews: true\n        require_last_push_approval: true\n        required_approving_review_count: 2\n    3.2: \n      required_pull_request_reviews:\n        dismiss_stale_reviews: true\n        require_last_push_approval: true\n        required_approving_review_count: 2\n    3.3: \n      required_pull_request_reviews:\n        dismiss_stale_reviews: true\n        require_last_push_approval: true\n        required_approving_review_count: 2\n    3.4: \n      required_pull_request_reviews:\n        dismiss_stale_reviews: true\n        require_last_push_approval: true\n        required_approving_review_count: 2\n  labels:\n    - java\n    - rpc\n    - microservices\n    - framework\n    - restful\n    - distributed-systems\n    - dubbo\n    - service-mesh\n    - http\n    - grpc\n    - web\n"
  },
  {
    "path": ".editorconfig",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# EditorConfig is awesome: https://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ntab_width = 4\nmax_line_length = 120\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.java]\nij_java_continuation_indent_size = 8\nij_java_keep_control_statement_in_one_line = false\nij_java_for_brace_force = always\nij_java_if_brace_force = always\nij_java_keep_first_column_comment = false\nij_java_keep_line_breaks = false\nij_java_keep_simple_blocks_in_one_line = true\nij_java_keep_simple_classes_in_one_line = true\nij_java_keep_simple_lambdas_in_one_line = true\nij_java_keep_simple_methods_in_one_line = true\nij_java_keep_blank_lines_in_code = 1\nij_java_keep_blank_lines_in_declarations = 1\nij_java_blank_lines_after_class_header = 1\nij_java_class_count_to_use_import_on_demand = 999\nij_java_names_count_to_use_import_on_demand = 999\nij_java_imports_layout = org.apache.dubbo.**, |, javax.**, |, java.**, |, *, |, $*\nij_java_insert_inner_class_imports = true\nij_java_space_before_array_initializer_left_brace = true\nij_java_method_parameters_new_line_after_left_paren = true\nij_java_wrap_comments = false\nij_java_wrap_long_lines = false\nij_java_enum_constants_wrap = split_into_lines\nij_java_method_call_chain_wrap = on_every_item\nij_java_method_parameters_wrap = on_every_item\nij_java_extends_list_wrap = normal\nij_java_extends_keyword_wrap = normal\nij_java_binary_operation_wrap = normal\nij_java_binary_operation_sign_on_next_line = true\nij_java_generate_final_locals = false\nij_java_generate_final_parameters = false\n\n[*.groovy]\nmax_line_length = 180\nij_groovy_label_indent_size = 4\nij_groovy_keep_blank_lines_in_code = 1\nij_groovy_keep_blank_lines_in_declarations = 1\nij_groovy_blank_lines_after_class_header = 1\nij_groovy_class_count_to_use_import_on_demand = 999\nij_groovy_names_count_to_use_import_on_demand = 999\nij_groovy_imports_layout = org.apache.dubbo.**, |, javax.**, |, java.**, |, *, |, $*\nij_groovy_space_after_type_cast = false\n\n[*.json]\ntab_width = 2\nindent_size = 2\n\n[*.{yml,yaml}]\ntab_width = 2\nindent_size = 2\n\n[*.xml]\nij_xml_attribute_wrap = off\nij_xml_text_wrap = off\nij_xml_keep_blank_lines = 1\n\n[pom.xml]\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# Auto detect text files and perform LF normalization\n*        text=auto\n\n*.java   text eol=lf"
  },
  {
    "path": ".github/DISCUSSION_TEMPLATE/general.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ntitle: \"[General][Java SDK (Component)] xxx\"\nbody:\n- type: markdown\n  attributes:\n    value: |\n      <img src=\"https://dubbo.apache.org/imgs/nav_logo2.png\" alt=\"Dubbo logo\" height=\"90px\" align=\"right\" />\n\n      Thank you for finding the time to share your idea! We really appreciate the community efforts to improve Dubbo.\n\n      If you need to report a security issue, please visit [our security policy](https://github.com/apache/dubbo/security/policy).\n\n      **Dubbo is open for world wide collaboration, please make sure that all the content you provide is in English.**\n      Remember that non-English idea is quite not friendly for everyone, and might unable to get the response!\n\n- type: checkboxes\n  attributes:\n    label: Pre-check\n    options:\n      - label: >\n          I am sure that all the content I provide is in English.\n        required: true\n\n- type: dropdown\n  attributes:\n    label: Apache Dubbo Component\n    description: |\n      What Apache Dubbo component are you using? Apache Dubbo has many subprojects, please make sure\n      to choose the component that you want to ask questions about.\n    multiple: false\n    options:\n      - \"Java SDK (apache/dubbo)\"\n      - \"Java Samples (apache/dubbo-samples)\"\n      - \"Java Integration Cases (apache/dubbo-integration-cases)\"\n      - \"Java SPI Extensions (apache/dubbo-spi-extensions)\"\n      - \"Java Benchmark (apache/dubbo-benchmark)\"\n      - \"Go SDK (apache/dubbo-go)\"\n      - \"Go Samples (apache/dubbo-go-samples)\"\n      - \"Rust SDK (apache/dubbo-rust)\"\n      - \"Node.js SDK (apache/dubbo-js)\"\n      - \"Python SDK (apache/dubbo-python)\"\n      - \"Kubernetes Integration (apache/dubbo-kubernetes)\"\n      - \"Pixiu Gateway (apache/dubbo-go-pixiu)\"\n      - \"Pixiu Gateway Samples (apache/dubbo-go-pixiu-samples)\"\n      - \"Admin (apache/dubbo-admin)\"\n      - \"Website (apache/dubbo-website)\"\n      - \"Awesome (apache/dubbo-awesome)\"\n      - \"Initializer (apache/dubbo-intializer)\"\n      - \"Others (apache/dubbo-xxx)\"\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: Details\n    description: Anything you want to ask?\n  validations:\n    required: true\n\n- type: checkboxes\n  attributes:\n    label: Code of Conduct\n    description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.\n    options:\n      - label: >\n          I agree to follow this project's\n          [Code of Conduct](https://www.apache.org/foundation/policies/conduct)\n        required: true\n\n- type: markdown\n  attributes:\n    value: \"Thanks for completing our form!\"\n"
  },
  {
    "path": ".github/DISCUSSION_TEMPLATE/question.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ntitle: \"[Q/A][Java SDK (Component)] xxx\"\nbody:\n- type: markdown\n  attributes:\n    value: |\n      <img src=\"https://dubbo.apache.org/imgs/nav_logo2.png\" alt=\"Dubbo logo\" height=\"90px\" align=\"right\" />\n\n      Thank you for finding the time to report the question! We really appreciate the community efforts to improve Dubbo.\n\n      If you need to report a security issue, please visit [our security policy](https://github.com/apache/dubbo/security/policy).\n\n      **Dubbo is open for world wide collaboration, please make sure that all the content you provide is in English.**\n      Remember that non-English question is quite not friendly for everyone, and might unable to get the response!\n\n- type: checkboxes\n  attributes:\n    label: Pre-check\n    options:\n      - label: >\n          I am sure that all the content I provide is in English.\n        required: true\n\n- type: dropdown\n  attributes:\n    label: Apache Dubbo Component\n    description: |\n      What Apache Dubbo component are you using? Apache Dubbo has many subprojects, please make sure\n      to choose the component that you want to ask questions about.\n    multiple: false\n    options:\n      - \"Java SDK (apache/dubbo)\"\n      - \"Java Samples (apache/dubbo-samples)\"\n      - \"Java Integration Cases (apache/dubbo-integration-cases)\"\n      - \"Java SPI Extensions (apache/dubbo-spi-extensions)\"\n      - \"Java Benchmark (apache/dubbo-benchmark)\"\n      - \"Go SDK (apache/dubbo-go)\"\n      - \"Go Samples (apache/dubbo-go-samples)\"\n      - \"Rust SDK (apache/dubbo-rust)\"\n      - \"Node.js SDK (apache/dubbo-js)\"\n      - \"Python SDK (apache/dubbo-python)\"\n      - \"Kubernetes Integration (apache/dubbo-kubernetes)\"\n      - \"Pixiu Gateway (apache/dubbo-go-pixiu)\"\n      - \"Pixiu Gateway Samples (apache/dubbo-go-pixiu-samples)\"\n      - \"Admin (apache/dubbo-admin)\"\n      - \"Website (apache/dubbo-website)\"\n      - \"Awesome (apache/dubbo-awesome)\"\n      - \"Initializer (apache/dubbo-intializer)\"\n      - \"Others (apache/dubbo-xxx)\"\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: Details\n    description: Anything you want to know?\n  validations:\n    required: true\n\n- type: checkboxes\n  attributes:\n    label: Code of Conduct\n    description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.\n    options:\n      - label: >\n          I agree to follow this project's\n          [Code of Conduct](https://www.apache.org/foundation/policies/conduct)\n        required: true\n\n- type: markdown\n  attributes:\n    value: \"Thanks for completing our form!\"\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1-bug.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nname: Bug Report\ndescription: File a bug report\ntitle: \"[Bug] \"\nlabels: [\"type/need-triage\", \"component/need-triage\"]\nprojects: [\"apache/337\"]\nbody:\n- type: markdown\n  attributes:\n    value: |\n      <img src=\"https://dubbo.apache.org/imgs/nav_logo2.png\" alt=\"Dubbo logo\" height=\"90px\" align=\"right\" />\n\n      Thank you for finding the time to report the problem! We really appreciate the community efforts to improve Dubbo.\n\n      Please make sure what you are reporting is indeed a bug with reproducible steps, if you want to ask questions\n      or share ideas, please [subscribe to our mailing list](mailto:dev-subscribe@dubbo.apache.org) and sent\n      emails to [our mailing list](mailto:dev@dubbo.apache.org), you can also head to our\n      [Discussion](https://github.com/apache/dubbo/discussions) tab.\n\n      If you need to report a security issue, please visit [our security policy](https://github.com/apache/dubbo/security/policy).\n\n      **Dubbo is open for world wide collaboration, please make sure that all the content you provide is in English.**\n      Remember that non-English issues is quite not friendly for everyone, and might unable to get the response!\n\n- type: checkboxes\n  attributes:\n    label: Pre-check\n    options:\n      - label: >\n          I am sure that all the content I provide is in English.\n        required: true\n\n- type: checkboxes\n  attributes:\n    label: Search before asking\n    description: >\n      Please make sure to search in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) first to see\n      whether the same issue was reported already.\n    options:\n      - label: >\n          I had searched in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) and found no similar\n          issues.\n        required: true\n\n- type: dropdown\n  attributes:\n    label: Apache Dubbo Component\n    description: |\n      What Apache Dubbo component are you using? Apache Dubbo has many subprojects, please make sure\n      to choose the component that you want to ask questions about.\n    multiple: false\n    options:\n      - \"Java SDK (apache/dubbo)\"\n      - \"Java Samples (apache/dubbo-samples)\"\n      - \"Java Integration Cases (apache/dubbo-integration-cases)\"\n      - \"Java SPI Extensions (apache/dubbo-spi-extensions)\"\n      - \"Java Benchmark (apache/dubbo-benchmark)\"\n      - \"Python SDK (apache/dubbo-python)\"\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: Dubbo Version\n    description: \"Which Dubbo version, JDK version and operating system did you use?\"\n    placeholder: \"Example: Dubbo Java 3.2.12, OpenJDK 1.8, Ubuntu 20.04\"\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: Steps to reproduce this issue\n    description: >\n      Describe how to reproduce this issue.If you are not able to provide a reproducible case,\n      please open a [Discussion](https://github.com/apache/dubbo/discussions) instead.\n    placeholder: >\n      Please provide the context in which the problem occurred and explain what happened.\n      A [GitHub address] would be helpful for maintainers to reproduce the problem.\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: What you expected to happen\n    description: What do you think went wrong?\n    placeholder: >\n      Please explain why you think the behaviour is erroneous. It is extremely helpful if you copy and paste\n      the fragment of logs showing the exact error messages or wrong behaviour and screenshots for\n      UI problems. You can include files by dragging and dropping them here.\n\n      **NOTE**: please copy and paste texts instead of taking screenshots of them for easy future search.\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: Anything else\n    description: Anything else we need to know?\n    placeholder: >\n      How often does this problem occur? (Once? Every time? Only when certain conditions are met?)\n      Any relevant logs to include? Put them here inside fenced\n      ``` ``` blocks or inside a collapsable details tag if it's too long:\n      <details><summary>x.log</summary> lots of stuff </details>\n\n- type: checkboxes\n  attributes:\n    label: Do you have a (mini) reproduction demo?\n    description: >\n      This is not strictly required, but if you have one (a minimal reproduction demo), \n      it will greatly help us resolve this issue efficiently. \n      Additionally, the community will prioritize this issue over others.\n    options:\n      - label: Yes, I have a minimal reproduction demo to help resolve this issue more effectively!\n\n- type: checkboxes\n  attributes:\n    label: Are you willing to submit a pull request to fix on your own?\n    description: >\n      This is absolutely not required, but we are happy to guide you in the contribution process\n      especially if you already have a good understanding of how to implement the fix.\n      Dubbo is a totally community-driven project and we love to bring new contributors in.\n    options:\n      - label: Yes I am willing to submit a pull request on my own!\n\n- type: checkboxes\n  attributes:\n    label: Code of Conduct\n    description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.\n    options:\n      - label: >\n          I agree to follow this project's\n          [Code of Conduct](https://www.apache.org/foundation/policies/conduct)\n        required: true\n\n- type: markdown\n  attributes:\n    value: \"Thanks for completing our form!\"\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2-feature.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nname: Feature Request\ndescription: Create a Feature Request for Dubbo\ntitle: \"[Feature] \"\nlabels: [\"type/need-triage\", \"component/need-triage\"]\nprojects: [\"apache/337\"]\nbody:\n- type: markdown\n  attributes:\n    value: |\n      <img src=\"https://dubbo.apache.org/imgs/nav_logo2.png\" alt=\"Dubbo logo\" height=\"90px\" align=\"right\" />\n\n      Thank you for finding the time to propose new feature!\n\n      We really appreciate the community efforts to improve Dubbo.\n\n      **Dubbo is open for world wide collaboration, please make sure that all the content you provide is in English.**\n      Remember that non-English issues is quite not friendly for everyone, and might unable to get the response!\n\n- type: checkboxes\n  attributes:\n    label: Pre-check\n    options:\n      - label: >\n          I am sure that all the content I provide is in English.\n        required: true\n\n- type: checkboxes\n  attributes:\n    label: Search before asking\n    description: >\n      Please make sure to search in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) first to see\n      whether the same feature was requested already.\n    options:\n      - label: >\n          I had searched in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) and found no similar\n          feature requirement.\n        required: true\n\n- type: dropdown\n  attributes:\n    label: Apache Dubbo Component\n    description: |\n      What Apache Dubbo component are you using? Apache Dubbo has many subprojects, please make sure\n      to choose the component that you want to ask questions about.\n    multiple: false\n    options:\n      - \"Java SDK (apache/dubbo)\"\n      - \"Java Samples (apache/dubbo-samples)\"\n      - \"Java Integration Cases (apache/dubbo-integration-cases)\"\n      - \"Java SPI Extensions (apache/dubbo-spi-extensions)\"\n      - \"Java Benchmark (apache/dubbo-benchmark)\"\n      - \"Python SDK (apache/dubbo-python)\"\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: Descriptions\n    description: A short description of your feature\n  validations:\n    required: true\n\n- type: textarea\n  attributes:\n    label: Related issues\n    description: Is there currently another issue associated with this?\n\n- type: checkboxes\n  attributes:\n    label: Are you willing to submit a pull request to fix on your own?\n    description: >\n      This is absolutely not required, but we are happy to guide you in the contribution process\n      especially if you already have a good understanding of how to implement the feature.\n      Dubbo is a totally community-driven project and we love to bring new contributors in.\n    options:\n      - label: Yes I am willing to submit a pull request on my own!\n\n- type: checkboxes\n  attributes:\n    label: Code of Conduct\n    description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.\n    options:\n      - label: >\n          I agree to follow this project's\n          [Code of Conduct](https://www.apache.org/foundation/policies/conduct)\n        required: true\n\n- type: markdown\n  attributes:\n    value: \"Thanks for completing our form!\"\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nblank_issues_enabled: false\ncontact_links:\n  - name: Question & FAQ & Proposal\n    url: https://github.com/apache/dubbo/discussions/\n    about: Ask a question, request support or submit a proposal for Apache Dubbo.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "## What is the purpose of the change?\n\n\n## Checklist\n- [x] Make sure there is a [GitHub_issue](https://github.com/apache/dubbo/issues) field for the change.\n- [x] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.\n- [x] Write necessary unit-test to verify your logic correction. If the new feature or significant change is committed, please remember to add sample in [dubbo samples](https://github.com/apache/dubbo-samples) project.\n- [x] Make sure gitHub actions can pass. [Why the workflow is failing and how to fix it?](../CONTRIBUTING.md)\n"
  },
  {
    "path": ".github/dependabot.yaml",
    "content": "version: 2\nupdates:\n\n  - package-ecosystem: \"maven\"\n    directory: \"/\"\n    open-pull-requests-limit: 20\n    # Ignore major version updates\n    ignore:\n      - dependency-name: \"*\"\n        update-types: [\"version-update:semver-major\"]\n    schedule:\n      interval: \"weekly\"\n      day: \"monday\"\n      time: \"03:00\"\n      timezone: \"US/Eastern\"\n"
  },
  {
    "path": ".github/workflows/build-and-test-pr.yml",
    "content": "name: \"Build and Test For PR\"\n\non: [push, pull_request, workflow_dispatch]\n\npermissions:\n  contents: read\n\nenv:\n  FORK_COUNT: 2\n  FAIL_FAST: 0\n  SHOW_ERROR_DETAIL: 1\n  #multi-version size limit\n  VERSIONS_LIMIT: 4\n  JACOCO_ENABLE: true\n  CANDIDATE_VERSIONS: '\n    spring.version:5.3.24,6.1.5;\n    spring-boot.version:2.7.6,3.2.3;\n    '\n  MAVEN_OPTS: >-\n    -XX:+UseG1GC\n    -XX:InitiatingHeapOccupancyPercent=45\n    -XX:+UseStringDeduplication\n    -XX:-TieredCompilation\n    -XX:TieredStopAtLevel=1\n    -Dmaven.javadoc.skip=true\n    -Dmaven.wagon.http.retryHandler.count=5\n    -Dmaven.wagon.httpconnectionManager.ttlSeconds=120\n  MAVEN_ARGS: >-\n    -e\n    --batch-mode\n    --no-snapshot-updates\n    --no-transfer-progress\n    --fail-fast\n\njobs:\n  check-format:\n    name: \"Check if code needs formatting\"\n    runs-on: ubuntu-22.04\n    steps:\n      - name: \"Checkout\"\n        uses: actions/checkout@v4\n      - name: \"Setup maven\"\n        uses: actions/setup-java@v4\n        with:\n          java-version: 21\n          distribution: zulu\n      - name: \"Check if code aligns with code style\"\n        id: check\n        run: mvn --log-file mvn.log spotless:check\n        continue-on-error: true\n      - name: \"Upload checkstyle result\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: checkstyle-result\n          path: mvn.log\n      - name: \"Generate Summary for successful run\"\n        if: ${{ steps.check.outcome == 'success' }}\n        run: |\n          echo \":ballot_box_with_check: Kudos! No formatting issues found!\" >> $GITHUB_STEP_SUMMARY\n      - name: \"Generate Summary for failed run\"\n        if: ${{ steps.check.outcome == 'failure' }}\n        run: |\n          echo \"## :negative_squared_cross_mark: Formatting issues found!\" >> $GITHUB_STEP_SUMMARY\n          echo \"\\`\\`\\`\" >> $GITHUB_STEP_SUMMARY\n          cat mvn.log | grep \"ERROR\" | sed 's/Check if code needs formatting    Check if code aligns with code style   [0-9A-Z:.-]\\+//' | sed 's/\\[ERROR] //' | head -n -11 >> $GITHUB_STEP_SUMMARY\n          echo \"\\`\\`\\`\" >> $GITHUB_STEP_SUMMARY\n          echo \"Please run \\`mvn spotless:apply\\` to fix the formatting issues.\" >> $GITHUB_STEP_SUMMARY\n      - name: \"Fail if code needs formatting\"\n        if: ${{ steps.check.outcome == 'failure' }}\n        uses: actions/github-script@v7.0.1\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          script: |\n            core.setFailed(\"Formatting issues found! \\nRun \\`mvn spotless:apply\\` to fix.\")\n\n  license:\n    name: \"Check License\"\n    needs: check-format\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n      - name: \"Check License\"\n        uses: apache/skywalking-eyes@e1a02359b239bd28de3f6d35fdc870250fa513d5\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      - name: \"Set up JDK 21\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 21\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          ./mvnw ${{ env.MAVEN_ARGS }} -T 2C clean install -Pskip-spotless -Dmaven.test.skip=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true\n      - name: \"Check Dependencies' License\"\n        uses: apache/skywalking-eyes/dependency@e1a02359b239bd28de3f6d35fdc870250fa513d5\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          config: .licenserc.yaml\n          mode: check\n\n  build-source:\n    name: \"Build Dubbo\"\n    needs: check-format\n    runs-on: ubuntu-22.04\n    outputs:\n      version: ${{ steps.dubbo-version.outputs.version }}\n    steps:\n      - name: \"Checkout code\"\n        uses: actions/checkout@v4\n      - name: \"Set up JDK\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 21\n      - name: \"Set current date as env variable\"\n        run: echo \"TODAY=$(date +'%Y%m%d')\" >> $GITHUB_ENV\n      - name: \"Restore local maven repository cache\"\n        uses: actions/cache/restore@v4\n        id: cache-maven-repository\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}\n      - name: \"Restore common local maven repository cache\"\n        uses: actions/cache/restore@v4\n        if: steps.cache-maven-repository.outputs.cache-hit != 'true'\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n          restore-keys: |\n            ${{ runner.os }}-maven-\n      - name: \"Clean dubbo cache\"\n        run: rm -rf ~/.m2/repository/org/apache/dubbo\n      - name: \"Build Dubbo with maven\"\n        run: |\n          ./mvnw ${{ env.MAVEN_ARGS }} clean install -Psources,skip-spotless,checkstyle -Dmaven.test.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Save dubbo cache\"\n        uses: actions/cache/save@v4\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n      - name: \"Clean dubbo cache\"\n        run: rm -rf ~/.m2/repository/org/apache/dubbo\n      - name: \"Save local maven repository cache\"\n        uses: actions/cache/save@v4\n        if: steps.cache-maven-repository.outputs.cache-hit != 'true'\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}\n      - name: \"Pack class result\"\n        run: |\n          shopt -s globstar\n          zip ${{ github.workspace }}/class.zip **/target/classes/* -r\n      - name: \"Upload class result\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: \"class-file\"\n          path: ${{ github.workspace }}/class.zip\n      - name: \"Pack checkstyle file if failure\"\n        if: failure()\n        run: zip ${{ github.workspace }}/checkstyle.zip *checkstyle* -r\n      - name: \"Upload checkstyle file if failure\"\n        uses: actions/upload-artifact@v4\n        if: failure()\n        with:\n          name: \"checkstyle-file\"\n          path: ${{ github.workspace }}/checkstyle.zip\n      - name: \"Calculate Dubbo Version\"\n        id: dubbo-version\n        run: |\n          REVISION=`awk '/<revision>[^<]+<\\/revision>/{gsub(/<revision>|<\\/revision>/,\"\",$1);print $1;exit;}' ./pom.xml`\n          echo \"version=$REVISION\" >> $GITHUB_OUTPUT\n          echo \"dubbo version: $REVISION\"\n\n  unit-test-prepare:\n    name: \"Preparation for Unit Test\"\n    needs: check-format\n    runs-on: ubuntu-22.04\n    strategy:\n      fail-fast: false\n    env:\n      ZOOKEEPER_VERSION: 3.7.2\n    steps:\n      - name: \"Cache zookeeper binary archive\"\n        uses: actions/cache@v3\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n      - name: \"Set up msys2 if necessary\"\n        uses: msys2/setup-msys2@v2\n        if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        with:\n          release: false  # support cache, see https://github.com/msys2/setup-msys2#context\n      - name: \"Download zookeeper binary archive in Linux OS\"\n        run: |\n          mkdir -p ${{ github.workspace }}/.tmp/zookeeper\n          wget -t 1 -T 120 -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n          echo \"list the downloaded zookeeper binary archive\"\n          ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n\n  unit-test:\n    needs: [check-format, unit-test-prepare]\n    name: \"Unit Test On ubuntu-22.04 Java: ${{ matrix.java }}\"\n    runs-on: ubuntu-22.04\n    strategy:\n      fail-fast: false\n      matrix:\n        java: [ 8, 11, 17, 21, 25 ]\n    env:\n      DISABLE_FILE_SYSTEM_TEST: true\n      CURRENT_ROLE: ${{ matrix.case-role }}\n      ZOOKEEPER_VERSION: 3.7.2\n    steps:\n      - name: \"Set MAVEN_OPTS for JDK 24+\"\n        if: ${{ matrix.java >= 24 }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $GITHUB_ENV\n      - name: \"Checkout code\"\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - name: \"Set up JDK ${{ matrix.java }}\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: ${{ matrix.java }}\n      - name: \"Set current date as env variable\"\n        run: echo \"TODAY=$(date +'%Y%m%d')\" >> $GITHUB_ENV\n      - name: \"Cache local maven repository\"\n        uses: actions/cache/restore@v4\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Cache zookeeper binary archive\"\n        uses: actions/cache@v3\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-\n      - name: \"Test with maven on Java: 8\"\n        timeout-minutes: 90\n        if: ${{ matrix.java == '8' }}\n        run: |\n          set -o pipefail\n          ./mvnw ${{ env.MAVEN_ARGS }} clean test verify -Pjacoco,'!jdk15ge-add-open',skip-spotless -DtrimStackTrace=false -Dmaven.test.skip=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper 2>&1 | tee >(grep -n -B 1 -A 200 \"FAILURE! -- in\" > test_errors.log)\n      - name: \"Test with maven on Java: ${{ matrix.java }}\"\n        timeout-minutes: 90\n        if: ${{ matrix.java != '8' }}\n        run: |\n          set -o pipefail\n          ./mvnw ${{ env.MAVEN_ARGS }} clean test verify -Pjacoco,jdk15ge-simple,'!jdk15ge-add-open',skip-spotless -DtrimStackTrace=false -Dmaven.test.skip=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper 2>&1 | tee >(grep -n -B 1 -A 200 \"FAILURE! -- in\" > test_errors.log)\n      - name: \"Print test error log\"\n        if: failure()\n        run: cat test_errors.log\n      - name: \"Upload coverage to Codecov\"\n        uses: codecov/codecov-action@v5\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          verbose: true\n          flags: unit-tests-java${{ matrix.java }}\n        env:\n          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n      - name: \"Upload surefire reports\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: surefire-reports-java${{ matrix.java }}\n          path: \"**/target/surefire-reports/**\"\n\n  samples-test-prepare:\n    needs: check-format\n    runs-on: ubuntu-22.04\n    env:\n      JOB_COUNT: 3\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Prepare test list\"\n        run: bash ./test/scripts/prepare-test.sh\n      - name: \"Upload test list\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-list\n          path: test/jobs\n  samples-test-job:\n    needs: [check-format, build-source, samples-test-prepare]\n    name: \"Samples Test on ubuntu-22.04 (JobId: ${{matrix.job_id}} Java: ${{matrix.java}})\"\n    runs-on: ubuntu-22.04\n    timeout-minutes: 90\n    env:\n      JAVA_VER: ${{matrix.java}}\n      TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt\n    strategy:\n      fail-fast: false\n      matrix:\n        java: [ 8, 21 ]\n        job_id: [1,2,3]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Set current date as env variable\"\n        run: echo \"TODAY=$(date +'%Y%m%d')\" >> $GITHUB_ENV\n      - name: \"Restore local maven repository cache\"\n        uses: actions/cache/restore@v4\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Restore Dubbo cache\"\n        uses: actions/cache/restore@v4\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}\n            ${{ runner.os }}-dubbo-snapshot-\n      - name: \"Download test list\"\n        uses: actions/download-artifact@v4\n        with:\n          name: samples-test-list\n          path: test/jobs/\n      - name: \"Set up JDK ${{matrix.java}}\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: ${{matrix.java}}\n      - name: \"Init Candidate Versions\"\n        run: |\n          DUBBO_VERSION=\"${{needs.build-source.outputs.version}}\"\n          CANDIDATE_VERSIONS=\"dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION\"\n          echo \"CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS\" >> $GITHUB_ENV\n      - name: \"Build test image\"\n        run: cd test && bash -c ./build-test-image.sh\n      - name: \"Run tests\"\n        run: cd test && bash ./run-tests.sh\n      - name: \"merge jacoco result\"\n        run: cd test/dubbo-test-jacoco-merger && mvn clean compile exec:java -Dexec.mainClass=\"org.apache.dubbo.test.JacocoMerge\" -Dexec.args=\"${{github.workspace}}\"\n      - name: \"Upload jacoco\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-jacoco-result-${{matrix.job_id}}-java${{matrix.java}}\n          path: target/jacoco*.exec\n      - name: \"Upload test result\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-result-${{matrix.job_id}}-java${{matrix.java}}\n          path: test/jobs/*-result*\n      - name: \"Upload test logs\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-logs-${{matrix.job_id}}-java${{matrix.java}}\n          path: test/logs/*\n  samples-test-result:\n    needs: [check-format, samples-test-job]\n    name: \"Samples Test Result on ubuntu-22.04 (JobId: ${{matrix.job_id}} Java: ${{matrix.java}})\"\n    if: always()\n    runs-on: ubuntu-22.04\n    env:\n      JAVA_VER: ${{matrix.java}}\n    strategy:\n      matrix:\n        java: [ 8, 21 ]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Download test result\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: samples-test-result-*-java${{matrix.java}}\n          path: test/jobs/\n          merge-multiple: true\n      - name: \"Merge test result\"\n        run: ./test/scripts/merge-test-results.sh\n\n  integration-test-prepare:\n    needs: check-format\n    runs-on: ubuntu-22.04\n    env:\n      JOB_COUNT: 3\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Prepare test list\"\n        run: bash ./test/scripts/prepare-test.sh\n      - name: \"Upload test list\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: test-list\n          path: test/jobs\n  integration-test-job:\n    needs: [check-format, build-source, integration-test-prepare]\n    name: \"Integration Test on ubuntu-22.04 (JobId: ${{matrix.job_id}} Java: ${{matrix.java}})\"\n    runs-on: ubuntu-22.04\n    timeout-minutes: 90\n    env:\n      JAVA_VER: ${{matrix.java}}\n      TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt\n    strategy:\n      fail-fast: false\n      matrix:\n        java: [ 8, 21 ]\n        job_id: [1,2,3]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Set current date as env variable\"\n        run: echo \"TODAY=$(date +'%Y%m%d')\" >> $GITHUB_ENV\n      - name: \"Restore local maven repository cache\"\n        uses: actions/cache/restore@v4\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Restore Dubbo cache\"\n        uses: actions/cache/restore@v4\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}\n            ${{ runner.os }}-dubbo-snapshot-\n      - name: \"Download test list\"\n        uses: actions/download-artifact@v4\n        with:\n          name: test-list\n          path: test/jobs/\n      - name: \"Set up JDK ${{matrix.java}}\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: ${{matrix.java}}\n      - name: \"Init Candidate Versions\"\n        run: |\n          DUBBO_VERSION=\"${{needs.build-source.outputs.version}}\"\n          CANDIDATE_VERSIONS=\"dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION\"\n          echo \"CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS\" >> $GITHUB_ENV\n      - name: \"Build test image\"\n        run: cd test && bash -c ./build-test-image.sh\n      - name: \"Run tests\"\n        run: cd test && bash ./run-tests.sh\n      - name: \"merge jacoco result\"\n        run: cd test/dubbo-test-jacoco-merger && mvn clean compile exec:java -Dexec.mainClass=\"org.apache.dubbo.test.JacocoMerge\" -Dexec.args=\"${{github.workspace}}\"\n      - name: \"Upload jacoco\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: jacoco-result-${{matrix.job_id}}-java${{matrix.java}}\n          path: target/jacoco*.exec\n      - name: \"Upload test result\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: test-result-${{matrix.job_id}}-java${{matrix.java}}\n          path: test/jobs/*-result*\n      - name: \"Upload test logs\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-logs-${{matrix.job_id}}-java${{matrix.java}}\n          path: test/logs/*\n  integration-test-result:\n    name: \"Integration Test Result on ubuntu-22.04 (JobId: ${{matrix.job_id}} Java: ${{matrix.java}})\"\n    needs: [check-format, integration-test-job]\n    if: always()\n    runs-on: ubuntu-22.04\n    env:\n      JAVA_VER: ${{matrix.java}}\n    strategy:\n      matrix:\n        java: [ 8, 21 ]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Download test result\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: test-result-*-java${{matrix.java}}\n          path: test/jobs/\n          merge-multiple: true\n      - name: \"Merge test result\"\n        run: ./test/scripts/merge-test-results.sh\n\n  samples-jacoco-result-merge:\n    name: \"Samples Jacoco Result on ubuntu-22.04 (JobId: ${{matrix.job_id}} Java: ${{matrix.java}})\"\n    runs-on: ubuntu-22.04\n    needs: [check-format, samples-test-result]\n    strategy:\n      matrix:\n        java: [ 8, 21 ]\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          path: \"./dubbo-samples\"\n      - name: \"Set up JDK 21\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 21\n      - name: \"Restore class result\"\n        uses: actions/download-artifact@v4\n        with:\n          name: \"class-file\"\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: ${{ github.workspace }}\n      - name: \"Unpack class result\"\n        run: |\n          unzip -o ${{ github.workspace }}/class.zip\n      - name: \"Restore samples jacoco exec\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: samples-jacoco-result-*-java${{matrix.java}}\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: dubbo-samples/target/\n          merge-multiple: true\n      - name: \"Merge samples jacoco result\"\n        run: |\n          cd ${{ github.workspace }}/dubbo-samples/test/dubbo-test-jacoco-merger\n          mvn clean compile exec:java -Dexec.mainClass=\"org.apache.dubbo.test.JacocoReport\" -Dexec.args=\"${{github.workspace}}/dubbo-samples ${{github.workspace}}\"\n      - name: \"Remove old test result\"\n        run: |\n          rm -rf ${{ github.workspace }}/dubbo-samples\n      - name: \"Upload coverage to Codecov\"\n        uses: codecov/codecov-action@v4\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          flags: samples-tests-java${{matrix.java}}\n          verbose: true\n        env:\n          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n\n  integration-jacoco-result-merge:\n    name: \"Integration Jacoco Result on ubuntu-22.04 (JobId: ${{matrix.job_id}} Java: ${{matrix.java}})\"\n    runs-on: ubuntu-22.04\n    needs: [check-format, integration-test-result, samples-test-result]\n    strategy:\n      matrix:\n        java: [ 8, 21 ]\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          path: \"./dubbo-integration-cases\"\n      - name: \"Set up JDK 21\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 21\n      - name: \"Restore class result\"\n        uses: actions/download-artifact@v4\n        with:\n          name: \"class-file\"\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: ${{ github.workspace }}\n      - name: \"Unpack class result\"\n        run: |\n          unzip -o ${{ github.workspace }}/class.zip\n      - name: \"Restore integration test jacoco exec\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: jacoco-result-*-java${{matrix.java}}\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: dubbo-integration-cases/target/\n          merge-multiple: true\n      - name: \"Merge integration test jacoco result\"\n        run: |\n          cd ${{ github.workspace }}/dubbo-integration-cases/test/dubbo-test-jacoco-merger\n          mvn clean compile exec:java -Dexec.mainClass=\"org.apache.dubbo.test.JacocoReport\" -Dexec.args=\"${{github.workspace}}/dubbo-integration-cases ${{github.workspace}}\"\n      - name: \"Remove old test result\"\n        run: |\n          rm -rf ${{ github.workspace }}/dubbo-integration-cases\n      - name: \"Upload coverage to Codecov\"\n        uses: codecov/codecov-action@v4\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          flags: integration-tests-java${{matrix.java}}\n          verbose: true\n        env:\n          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n\n\n  error-code-inspecting:\n    needs: check-format\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          path: \"./dubbo\"\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-test-tools'\n          ref: main\n          path: \"./dubbo-test-tools\"\n      - name: \"Set up JDK 21\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 21\n      - name: \"Restore local maven repository cache\"\n        uses: actions/cache/restore@v4\n        id: cache-maven-repository\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo\n          ./mvnw ${{ env.MAVEN_ARGS }} -T 2C clean install -P skip-spotless -Dmaven.test.skip=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true\n      - name: \"Run Error Code Inspecting\"\n        env:\n          DUBBO_ECI_REPORT_AS_ERROR: true\n        run: |\n          cd ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector\n          ../mvnw ${{ env.MAVEN_ARGS }} -T 2C package exec:java -Ddubbo.eci.report-as-error=${DUBBO_ECI_REPORT_AS_ERROR} -Dmaven.test.skip=true -Ddubbo.eci.path=${{ github.workspace }}/dubbo\n      - name: \"Upload error code inspection result\"\n        # always() should not be used here, since we don't need to handle the 'canceled' situation.\n        if: ${{ success() || failure() }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: \"error-inspection-result\"\n          path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt\n\n  native-image-inspecting:\n    needs: check-format\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          path: \"./dubbo\"\n      - name: \"Set up GraalVM environment\"\n        uses: graalvm/setup-graalvm@v1\n        with:\n          version: '22.3.0'\n          java-version: '17'\n          components: 'native-image'\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          native-image-job-reports: 'true'\n      - name: \"Set up Zookeeper environment\"\n        run: |\n          wget -t 1 -T 120 https://archive.apache.org/dist/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz\n          tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz\n          mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg\n          apache-zookeeper-3.8.4-bin/bin/zkServer.sh start\n      - name: \"Check environment\"\n        run: |\n          java --version\n          native-image --version\n      - name: \"Set current date as env variable\"\n        run: echo \"TODAY=$(date +'%Y%m%d')\" >> $GITHUB_ENV\n      - name: \"Restore local Maven repository cache\"\n        uses: actions/cache/restore@v4\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo\n          ./mvnw ${{ env.MAVEN_ARGS }} -T 2C clean install -P skip-spotless -Dmaven.test.skip=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true\n      - name: \"Checkout dubbo-samples repository\"\n        uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n          path: \"./dubbo-samples\"\n      - name: \"Compile and run Dubbo native image demo\"\n        run: |\n          MVNW=\"${{ github.workspace }}/dubbo-samples/mvnw ${{ env.MAVEN_ARGS }} -Dmaven.test.skip=true\"\n          cd ${{ github.workspace }}/dubbo-samples/2-advanced/dubbo-samples-native-image/dubbo-samples-native-image-provider\n          $MVNW clean package -P native native:compile\n          nohup ./target/dubbo-samples-native-image-provider &\n          sleep 10\n          curl \\\n            --header \"Content-Type: application/json\" \\\n            --data '{\"name\":\"Dubbo\"}' \\\n            http://localhost:50052/org.apache.dubbo.nativeimage.DemoService/sayHello/\n\n"
  },
  {
    "path": ".github/workflows/build-and-test-scheduled-3.1.yml",
    "content": "name: Build and Test Scheduled On 3.1\n\non:\n  schedule:\n    - cron: '0 0/6 * * *'\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nenv:\n  FORK_COUNT: 2\n  FAIL_FAST: 0\n  SHOW_ERROR_DETAIL: 1\n  #multi-version size limit\n  VERSIONS_LIMIT: 4\n  ALL_REMOTE_VERSION: true\n  CANDIDATE_VERSIONS: '\n    spring.version:5.3.24;\n    spring-boot.version:2.7.6;\n    '\n\njobs:\n  license:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.1\"\n      - name: Check License\n        uses: apache/skywalking-eyes@main\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n  build-source:\n    runs-on: ubuntu-22.04\n    outputs:\n      version: ${{ steps.dubbo-version.outputs.version }}\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.1\"\n          path: dubbo\n      - uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 8\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n      - name: \"Build Dubbo with Maven\"\n        run: |\n          cd ./dubbo\n          ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Pack checkstyle file if failure\"\n        if: failure()\n        run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r\n      - name: \"Upload checkstyle file if failure\"\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: \"checkstyle-file\"\n          path: ${{ github.workspace }}/checkstyle.zip\n      - name: \"Calculate Dubbo Version\"\n        id: dubbo-version\n        run: |\n          REVISION=`awk '/<revision>[^<]+<\\/revision>/{gsub(/<revision>|<\\/revision>/,\"\",$1);print $1;exit;}' ./dubbo/pom.xml`\n          echo \"version=$REVISION\" >> $GITHUB_OUTPUT\n          echo \"dubbo version: $REVISION\"\n\n  unit-test-prepare:\n    name: \" Preparation for Unit Test On ${{ matrix.os }}\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n    env:\n      ZOOKEEPER_VERSION: 3.7.2\n    steps:\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n      - name: \"Set up msys2 if necessary\"\n        if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        uses: msys2/setup-msys2@v2\n        with:\n          release: false  # support cache, see https://github.com/msys2/setup-msys2#context\n      - name: \"Download zookeeper binary archive in Linux OS\"\n        if: ${{ startsWith( matrix.os, 'ubuntu') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        run: |\n          mkdir -p ${{ github.workspace }}/.tmp/zookeeper\n          wget -t 1 -T 120 -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n          echo \"list the downloaded zookeeper binary archive\"\n          ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n      - name: \"Download zookeeper binary archive in Windows OS\"\n        if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        shell: msys2 {0}\n        run: |\n          mkdir -p ${{ github.workspace }}/.tmp/zookeeper\n          wget -t 1 -T 120 -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n          echo \"list the downloaded zookeeper binary archive\"\n          ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n\n  unit-test:\n    needs: [build-source, unit-test-prepare]\n    name: \"Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }})\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n        jdk: [ 8, 11, 17, 21 ]\n    env:\n      DISABLE_FILE_SYSTEM_TEST: true\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.1\"\n      - name: \"Set up JDK ${{ matrix.jdk }}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{ matrix.jdk }}\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-\n      - name: \"Test with Maven with Integration Tests\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n\n  unit-test-fastjson2:\n    needs: [build-source, unit-test-prepare]\n    name: \"Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }}, Serialization: fastjson2)\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n        jdk: [ 8, 11, 17, 21 ]\n    env:\n      DISABLE_FILE_SYSTEM_TEST: true\n      DUBBO_DEFAULT_SERIALIZATION: fastjson2\n      MAVEN_SUREFIRE_ADD_OPENS: true\n    steps:\n      - uses: actions/checkout@v4\n      - name: \"Set up JDK ${{ matrix.jdk }}\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: ${{ matrix.jdk }}\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-\n      - name: \"Test with Maven with Integration Tests on JDK 8\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk == '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,'!jdk15ge' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests on JDK 8\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk == '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P\"jacoco,'!jdk15ge'\" -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n      - name: \"Test with Maven with Integration Tests\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk != '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,'!jdk15ge' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk != '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P\"jacoco,'!jdk15ge'\" -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n\n  samples-test-prepare:\n    runs-on: ubuntu-22.04\n    env:\n      JOB_COUNT: 5\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Prepare test list\"\n        run: |\n          bash ./test/scripts/prepare-test.sh\n      - name: \"Upload test list\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-list\n          path: test/jobs\n  samples-test-job:\n    needs: [build-source, samples-test-prepare]\n    name: \"Samples Test on ubuntu-22.04 (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})\"\n    runs-on: ubuntu-22.04\n    timeout-minutes: 90\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n      TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt\n    strategy:\n      fail-fast: false\n      matrix:\n        jdk: [ 8, 11 ]\n        job_id: [1, 2, 3, 4, 5]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Cache local Maven repository\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Restore Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}\n            ${{ runner.os }}-dubbo-snapshot-\n      - name: \"Download test list\"\n        uses: actions/download-artifact@v4\n        with:\n          name: samples-test-list\n          path: test/jobs/\n      - name: \"Set up JDK ${{matrix.jdk}}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{matrix.jdk}}\n      - name: \"Init Candidate Versions\"\n        run: |\n          DUBBO_VERSION=\"${{needs.build-source.outputs.version}}\"\n          CANDIDATE_VERSIONS=\"dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION\"\n          echo \"CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS\" >> $GITHUB_ENV\n      - name: \"Build test image\"\n        run: |\n          cd test && bash -c ./build-test-image.sh\n      - name: \"Run tests\"\n        run: cd test && bash ./run-tests.sh\n      - name: \"Upload test logs\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-logs-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/logs/*\n      - name: \"Upload test result\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-result-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/jobs/*-result*\n  samples-test-result:\n    needs: [samples-test-job]\n    if: always()\n    runs-on: ubuntu-22.04\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n    strategy:\n      matrix:\n        jdk: [ 8, 11 ]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Download test result\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: samples-test-result-${{matrix.jdk}}-*\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: test/jobs/\n          merge-multiple: true\n      - name: \"Merge test result\"\n        run: ./test/scripts/merge-test-results.sh\n\n  integration-test-prepare:\n    runs-on: ubuntu-22.04\n    env:\n      JOB_COUNT: 5\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Prepare test list\"\n        run: |\n          bash ./test/scripts/prepare-test.sh\n      - name: \"Upload test list\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-list\n          path: test/jobs\n  integration-test-job:\n    needs: [build-source, integration-test-prepare]\n    name: \"Integration Test on ubuntu-22.04 (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})\"\n    runs-on: ubuntu-22.04\n    timeout-minutes: 90\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n      TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt\n    strategy:\n      fail-fast: false\n      matrix:\n        jdk: [ 8, 11 ]\n        job_id: [1, 2, 3, 4, 5]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Cache local Maven repository\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Restore Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}\n            ${{ runner.os }}-dubbo-snapshot-\n      - name: \"Download test list\"\n        uses: actions/download-artifact@v4\n        with:\n          name: integration-test-list\n          path: test/jobs/\n      - name: \"Set up JDK ${{matrix.jdk}}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{matrix.jdk}}\n      - name: \"Init Candidate Versions\"\n        run: |\n          DUBBO_VERSION=\"${{needs.build-source.outputs.version}}\"\n          CANDIDATE_VERSIONS=\"dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION\"\n          echo \"CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS\" >> $GITHUB_ENV\n      - name: \"Build test image\"\n        run: |\n          cd test && bash -c ./build-test-image.sh\n      - name: \"Run tests\"\n        run: cd test && bash ./run-tests.sh\n      - name: \"Upload test logs\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-logs-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/logs/*\n      - name: \"Upload test result\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-result-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/jobs/*-result*\n  integration-test-result:\n    needs: [integration-test-job]\n    if: always()\n    runs-on: ubuntu-22.04\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n    strategy:\n      matrix:\n        jdk: [ 8, 11 ]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Download test result\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: integration-test-result-${{matrix.jdk}}-*\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: test/jobs/\n          merge-multiple: true\n      - name: \"Merge test result\"\n        run: ./test/scripts/merge-test-results.sh\n\n  error-code-inspecting:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.1\"\n          path: \"./dubbo\"\n\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-test-tools'\n          ref: main\n          path: \"./dubbo-test-tools\"\n\n      - name: \"Set up JDK 21\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 21\n\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo\n          ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true\n      - name: \"Run Error Code Inspecting\"\n        env:\n          DUBBO_ECI_REPORT_AS_ERROR: true\n        run: |\n          cd ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector\n          ../mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C package exec:java -Ddubbo.eci.report-as-error=${DUBBO_ECI_REPORT_AS_ERROR} -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -Ddubbo.eci.path=${{ github.workspace }}/dubbo\n\n      - name: \"Upload error code inspection result\"\n        # always() should not be used here, since we don't need to handle the 'canceled' situation.\n        if: ${{ success() || failure() }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: \"error-inspection-result\"\n          path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt\n\n  native-image-inspecting:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.1\"\n          path: \"./dubbo\"\n\n      - name: \"Setup GraalVM environment\"\n        uses: graalvm/setup-graalvm@v1\n        with:\n          version: '22.3.0'\n          java-version: '17'\n          components: 'native-image'\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          native-image-job-reports: 'true'\n\n      - name: \"Setup Zookeeper environment\"\n        run: |\n          wget -t 1 -T 120 https://archive.apache.org/dist/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz\n          tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz\n          mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg\n          apache-zookeeper-3.8.4-bin/bin/zkServer.sh start\n\n      - name: \"Check environment\"\n        run: |\n          java --version\n          native-image --version\n\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo\n          ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true\n\n      - name: \"Compile and run Dubbo demo for native (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider\n          ${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile\n          nohup ./target/dubbo-demo-native-provider &\n          cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer\n          ${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile\n          ./target/dubbo-demo-native-consumer\n"
  },
  {
    "path": ".github/workflows/build-and-test-scheduled-3.2.yml",
    "content": "name: Build and Test Scheduled On 3.2\n\non:\n  schedule:\n    - cron: '0 0/6 * * *'\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nenv:\n  FORK_COUNT: 2\n  FAIL_FAST: 0\n  SHOW_ERROR_DETAIL: 1\n  #multi-version size limit\n  VERSIONS_LIMIT: 4\n  ALL_REMOTE_VERSION: true\n  CANDIDATE_VERSIONS: '\n    spring.version:5.3.24;\n    spring-boot.version:2.7.6;\n    '\n\njobs:\n  license:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.2\"\n      - name: Check License\n        uses: apache/skywalking-eyes@main\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n  build-source:\n    runs-on: ubuntu-22.04\n    outputs:\n      version: ${{ steps.dubbo-version.outputs.version }}\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.2\"\n          path: dubbo\n      - uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 8\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n      - name: \"Build Dubbo with Maven\"\n        run: |\n          cd ./dubbo\n          ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Pack checkstyle file if failure\"\n        if: failure()\n        run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r\n      - name: \"Upload checkstyle file if failure\"\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: \"checkstyle-file\"\n          path: ${{ github.workspace }}/checkstyle.zip\n      - name: \"Calculate Dubbo Version\"\n        id: dubbo-version\n        run: |\n          REVISION=`awk '/<revision>[^<]+<\\/revision>/{gsub(/<revision>|<\\/revision>/,\"\",$1);print $1;exit;}' ./dubbo/pom.xml`\n          echo \"version=$REVISION\" >> $GITHUB_OUTPUT\n          echo \"dubbo version: $REVISION\"\n\n  unit-test-prepare:\n    name: \" Preparation for Unit Test On ${{ matrix.os }}\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n    env:\n      ZOOKEEPER_VERSION: 3.7.2\n    steps:\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n      - name: \"Set up msys2 if necessary\"\n        if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        uses: msys2/setup-msys2@v2\n        with:\n          release: false  # support cache, see https://github.com/msys2/setup-msys2#context\n      - name: \"Download zookeeper binary archive in Linux OS\"\n        if: ${{ startsWith( matrix.os, 'ubuntu') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        run: |\n          mkdir -p ${{ github.workspace }}/.tmp/zookeeper\n          wget -t 1 -T 120 -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n          echo \"list the downloaded zookeeper binary archive\"\n          ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n      - name: \"Download zookeeper binary archive in Windows OS\"\n        if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        shell: msys2 {0}\n        run: |\n          mkdir -p ${{ github.workspace }}/.tmp/zookeeper\n          wget -t 1 -T 120 -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n          echo \"list the downloaded zookeeper binary archive\"\n          ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n\n  unit-test:\n    needs: [build-source, unit-test-prepare]\n    name: \"Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }})\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n        jdk: [ 8, 11, 17, 21 ]\n    env:\n      DISABLE_FILE_SYSTEM_TEST: true\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.2\"\n      - name: \"Set up JDK ${{ matrix.jdk }}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{ matrix.jdk }}\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-\n      - name: \"Test with Maven with Integration Tests\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n\n  unit-test-fastjson2:\n    needs: [build-source, unit-test-prepare]\n    name: \"Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }}, Serialization: fastjson2)\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n        jdk: [ 8, 11, 17, 21 ]\n    env:\n      DISABLE_FILE_SYSTEM_TEST: true\n      DUBBO_DEFAULT_SERIALIZATION: fastjson2\n      MAVEN_SUREFIRE_ADD_OPENS: true\n    steps:\n      - uses: actions/checkout@v4\n      - name: \"Set up JDK ${{ matrix.jdk }}\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: ${{ matrix.jdk }}\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-\n      - name: \"Test with Maven with Integration Tests on JDK 8\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk == '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,'!jdk15ge-add-open' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests on JDK 8\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk == '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P\"jacoco,'!jdk15ge-add-open'\" -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n      - name: \"Test with Maven with Integration Tests\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk != '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,jdk15ge-simple,'!jdk15ge-add-open' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk != '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P\"jacoco,jdk15ge-simple,'!jdk15ge-add-open'\" -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n\n  samples-test-prepare:\n    runs-on: ubuntu-22.04\n    env:\n      JOB_COUNT: 5\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Prepare test list\"\n        run: |\n          bash ./test/scripts/prepare-test.sh\n      - name: \"Upload test list\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-list\n          path: test/jobs\n  samples-test-job:\n    needs: [build-source, samples-test-prepare]\n    name: \"Samples Test on ubuntu-22.04 (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})\"\n    runs-on: ubuntu-22.04\n    timeout-minutes: 90\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n      TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt\n    strategy:\n      fail-fast: false\n      matrix:\n        jdk: [ 8, 11, 17, 21 ]\n        job_id: [1, 2, 3, 4, 5]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Cache local Maven repository\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Restore Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}\n            ${{ runner.os }}-dubbo-snapshot-\n      - name: \"Download test list\"\n        uses: actions/download-artifact@v4\n        with:\n          name: samples-test-list\n          path: test/jobs/\n      - name: \"Set up JDK ${{matrix.jdk}}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{matrix.jdk}}\n      - name: \"Init Candidate Versions\"\n        run: |\n          DUBBO_VERSION=\"${{needs.build-source.outputs.version}}\"\n          CANDIDATE_VERSIONS=\"dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION\"\n          echo \"CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS\" >> $GITHUB_ENV\n      - name: \"Build test image\"\n        run: |\n          cd test && bash -c ./build-test-image.sh\n      - name: \"Run tests\"\n        run: cd test && bash ./run-tests.sh\n      - name: \"Upload test logs\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-logs-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/logs/*\n      - name: \"Upload test result\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-result-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/jobs/*-result*\n  samples-test-result:\n    needs: [samples-test-job]\n    if: always()\n    runs-on: ubuntu-22.04\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n    strategy:\n      matrix:\n        jdk: [ 8, 11, 17, 21 ]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Download test result\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: samples-test-result-${{matrix.jdk}}-*\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: test/jobs/\n          merge-multiple: true\n      - name: \"Merge test result\"\n        run: ./test/scripts/merge-test-results.sh\n\n  integration-test-prepare:\n    runs-on: ubuntu-22.04\n    env:\n      JOB_COUNT: 5\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Prepare test list\"\n        run: |\n          bash ./test/scripts/prepare-test.sh\n      - name: \"Upload test list\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-list\n          path: test/jobs\n  integration-test-job:\n    needs: [build-source, integration-test-prepare]\n    name: \"Integration Test on ubuntu-22.04 (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})\"\n    runs-on: ubuntu-22.04\n    timeout-minutes: 90\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n      TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt\n    strategy:\n      fail-fast: false\n      matrix:\n        jdk: [ 8, 11, 17, 21 ]\n        job_id: [1, 2, 3, 4, 5]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Cache local Maven repository\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Restore Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}\n            ${{ runner.os }}-dubbo-snapshot-\n      - name: \"Download test list\"\n        uses: actions/download-artifact@v4\n        with:\n          name: integration-test-list\n          path: test/jobs/\n      - name: \"Set up JDK ${{matrix.jdk}}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{matrix.jdk}}\n      - name: \"Init Candidate Versions\"\n        run: |\n          DUBBO_VERSION=\"${{needs.build-source.outputs.version}}\"\n          CANDIDATE_VERSIONS=\"dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION\"\n          echo \"CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS\" >> $GITHUB_ENV\n      - name: \"Build test image\"\n        run: |\n          cd test && bash -c ./build-test-image.sh\n      - name: \"Run tests\"\n        run: cd test && bash ./run-tests.sh\n      - name: \"Upload test logs\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-logs-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/logs/*\n      - name: \"Upload test result\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-result-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/jobs/*-result*\n  integration-test-result:\n    needs: [integration-test-job]\n    if: always()\n    runs-on: ubuntu-22.04\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n    strategy:\n      matrix:\n        jdk: [ 8, 11, 17, 21 ]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Download test result\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: integration-test-result-${{matrix.jdk}}-*\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: test/jobs/\n          merge-multiple: true\n      - name: \"Merge test result\"\n        run: ./test/scripts/merge-test-results.sh\n\n  error-code-inspecting:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.2\"\n          path: \"./dubbo\"\n\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-test-tools'\n          ref: main\n          path: \"./dubbo-test-tools\"\n\n      - name: \"Set up JDK 21\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 21\n\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo\n          ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true\n      - name: \"Run Error Code Inspecting\"\n        env:\n          DUBBO_ECI_REPORT_AS_ERROR: true\n        run: |\n          cd ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector\n          ../mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C package exec:java -Ddubbo.eci.report-as-error=${DUBBO_ECI_REPORT_AS_ERROR} -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -Ddubbo.eci.path=${{ github.workspace }}/dubbo\n\n      - name: \"Upload error code inspection result\"\n        # always() should not be used here, since we don't need to handle the 'canceled' situation.\n        if: ${{ success() || failure() }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: \"error-inspection-result\"\n          path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt\n\n  native-image-inspecting:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.2\"\n          path: \"./dubbo\"\n\n      - name: \"Setup GraalVM environment\"\n        uses: graalvm/setup-graalvm@v1\n        with:\n          version: '22.3.0'\n          java-version: '17'\n          components: 'native-image'\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          native-image-job-reports: 'true'\n\n      - name: \"Setup Zookeeper environment\"\n        run: |\n          wget -t 1 -T 120 https://archive.apache.org/dist/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz\n          tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz\n          mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg\n          apache-zookeeper-3.8.4-bin/bin/zkServer.sh start\n\n      - name: \"Check environment\"\n        run: |\n          java --version\n          native-image --version\n\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo\n          ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true\n\n      - name: \"Compile and run Dubbo demo for native (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider\n          ${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile\n          nohup ./target/dubbo-demo-native-provider &\n          cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer\n          ${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile\n          ./target/dubbo-demo-native-consumer\n"
  },
  {
    "path": ".github/workflows/build-and-test-scheduled-3.3.yml",
    "content": "name: Build and Test Scheduled On 3.3\n\non:\n  schedule:\n    - cron: '0 0/6 * * *'\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nenv:\n  FORK_COUNT: 2\n  FAIL_FAST: 0\n  SHOW_ERROR_DETAIL: 1\n  #multi-version size limit\n  VERSIONS_LIMIT: 4\n  ALL_REMOTE_VERSION: true\n  CANDIDATE_VERSIONS: '\n    spring.version:5.3.24,6.1.5;\n    spring-boot.version:2.7.6,3.2.3;\n    '\n\njobs:\n  license:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.3\"\n      - name: Check License\n        uses: apache/skywalking-eyes@main\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n  build-source:\n    runs-on: ubuntu-22.04\n    outputs:\n      version: ${{ steps.dubbo-version.outputs.version }}\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.3\"\n          path: dubbo\n      - uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 21\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n      - name: \"Build Dubbo with Maven\"\n        run: |\n          cd ./dubbo\n          ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Pack checkstyle file if failure\"\n        if: failure()\n        run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r\n      - name: \"Upload checkstyle file if failure\"\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: \"checkstyle-file\"\n          path: ${{ github.workspace }}/checkstyle.zip\n      - name: \"Calculate Dubbo Version\"\n        id: dubbo-version\n        run: |\n          REVISION=`awk '/<revision>[^<]+<\\/revision>/{gsub(/<revision>|<\\/revision>/,\"\",$1);print $1;exit;}' ./dubbo/pom.xml`\n          echo \"version=$REVISION\" >> $GITHUB_OUTPUT\n          echo \"dubbo version: $REVISION\"\n\n  unit-test-prepare:\n    name: \" Preparation for Unit Test On ${{ matrix.os }}\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n    env:\n      ZOOKEEPER_VERSION: 3.7.2\n    steps:\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n      - name: \"Set up msys2 if necessary\"\n        if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        uses: msys2/setup-msys2@v2\n        with:\n          release: false  # support cache, see https://github.com/msys2/setup-msys2#context\n      - name: \"Download zookeeper binary archive in Linux OS\"\n        if: ${{ startsWith( matrix.os, 'ubuntu') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        run: |\n          mkdir -p ${{ github.workspace }}/.tmp/zookeeper\n          wget -t 1 -T 120 -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n          echo \"list the downloaded zookeeper binary archive\"\n          ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n      - name: \"Download zookeeper binary archive in Windows OS\"\n        if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        shell: msys2 {0}\n        run: |\n          mkdir -p ${{ github.workspace }}/.tmp/zookeeper\n          wget -t 1 -T 120 -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120-c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n          echo \"list the downloaded zookeeper binary archive\"\n          ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n\n  unit-test:\n    needs: [build-source, unit-test-prepare]\n    name: \"Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }})\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n        jdk: [ 8, 11, 17, 21, 25 ]\n    env:\n      DISABLE_FILE_SYSTEM_TEST: true\n    steps:\n      - name: \"Set MAVEN_OPTS for JDK 24+ on Linux\"\n        if: ${{ matrix.jdk >= 24 && startsWith(matrix.os, 'ubuntu') }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $GITHUB_ENV\n      - name: \"Set MAVEN_OPTS for JDK 24+ on Windows\"\n        if: ${{ matrix.jdk >= 24 && startsWith(matrix.os, 'windows') }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $env:GITHUB_ENV\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.3\"\n      - name: \"Set up JDK ${{ matrix.jdk }}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{ matrix.jdk }}\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-\n      - name: \"Test with Maven with Integration Tests\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n\n  unit-test-fastjson2:\n    needs: [build-source, unit-test-prepare]\n    name: \"Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }}, Serialization: fastjson2)\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n        jdk: [ 8, 11, 17, 21, 25 ]\n    env:\n      DISABLE_FILE_SYSTEM_TEST: true\n      DUBBO_DEFAULT_SERIALIZATION: fastjson2\n      MAVEN_SUREFIRE_ADD_OPENS: true\n    steps:\n      - name: \"Set MAVEN_OPTS for JDK 24+ on Linux\"\n        if: ${{ matrix.jdk >= 24 && startsWith(matrix.os, 'ubuntu') }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $GITHUB_ENV\n      - name: \"Set MAVEN_OPTS for JDK 24+ on Windows\"\n        if: ${{ matrix.jdk >= 24 && startsWith(matrix.os, 'windows') }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $env:GITHUB_ENV\n      - uses: actions/checkout@v4\n      - name: \"Set up JDK ${{ matrix.jdk }}\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: ${{ matrix.jdk }}\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-\n      - name: \"Test with Maven with Integration Tests on JDK 8\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk == '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,'!jdk15ge-add-open' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests on JDK 8\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk == '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P\"jacoco,'!jdk15ge-add-open'\" -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n      - name: \"Test with Maven with Integration Tests\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk != '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,jdk15ge-simple,'!jdk15ge-add-open' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk != '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P\"jacoco,jdk15ge-simple,'!jdk15ge-add-open'\" -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n\n  samples-test-prepare:\n    runs-on: ubuntu-22.04\n    env:\n      JOB_COUNT: 5\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Prepare test list\"\n        run: |\n          bash ./test/scripts/prepare-test.sh\n      - name: \"Upload test list\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-list\n          path: test/jobs\n  samples-test-job:\n    needs: [build-source, samples-test-prepare]\n    name: \"Samples Test on ubuntu-22.04 (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})\"\n    runs-on: ubuntu-22.04\n    timeout-minutes: 90\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n      TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt\n    strategy:\n      fail-fast: false\n      matrix:\n        jdk: [ 8, 11, 17, 21, 25 ]\n        job_id: [1, 2, 3, 4, 5]\n    steps:\n      - name: \"Set MAVEN_OPTS for JDK 24+\"\n        if: ${{ matrix.jdk >= 24 }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $GITHUB_ENV\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Cache local Maven repository\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Restore Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}\n            ${{ runner.os }}-dubbo-snapshot-\n      - name: \"Download test list\"\n        uses: actions/download-artifact@v4\n        with:\n          name: samples-test-list\n          path: test/jobs/\n      - name: \"Set up JDK ${{matrix.jdk}}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{matrix.jdk}}\n      - name: \"Init Candidate Versions\"\n        run: |\n          DUBBO_VERSION=\"${{needs.build-source.outputs.version}}\"\n          CANDIDATE_VERSIONS=\"dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION\"\n          echo \"CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS\" >> $GITHUB_ENV\n      - name: \"Build test image\"\n        run: |\n          cd test && bash -c ./build-test-image.sh\n      - name: \"Run tests\"\n        run: cd test && bash ./run-tests.sh\n      - name: \"Upload test logs\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-logs-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/logs/*\n      - name: \"Upload test result\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-result-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/jobs/*-result*\n  samples-test-result:\n    needs: [samples-test-job]\n    if: always()\n    runs-on: ubuntu-22.04\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n    strategy:\n      matrix:\n        jdk: [ 8, 11, 17, 21, 25 ]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Download test result\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: samples-test-result-${{matrix.jdk}}-*\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: test/jobs/\n          merge-multiple: true\n      - name: \"Merge test result\"\n        run: ./test/scripts/merge-test-results.sh\n\n  integration-test-prepare:\n    runs-on: ubuntu-22.04\n    env:\n      JOB_COUNT: 5\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Prepare test list\"\n        run: |\n          bash ./test/scripts/prepare-test.sh\n      - name: \"Upload test list\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-list\n          path: test/jobs\n  integration-test-job:\n    needs: [build-source, integration-test-prepare]\n    name: \"Integration Test on ubuntu-22.04 (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})\"\n    runs-on: ubuntu-22.04\n    timeout-minutes: 90\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n      TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt\n    strategy:\n      fail-fast: false\n      matrix:\n        jdk: [ 8, 11, 17, 21, 25 ]\n        job_id: [1, 2, 3, 4, 5]\n    steps:\n      - name: \"Set MAVEN_OPTS for JDK 24+\"\n        if: ${{ matrix.jdk >= 24 }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $GITHUB_ENV\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Cache local Maven repository\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Restore Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}\n            ${{ runner.os }}-dubbo-snapshot-\n      - name: \"Download test list\"\n        uses: actions/download-artifact@v4\n        with:\n          name: integration-test-list\n          path: test/jobs/\n      - name: \"Set up JDK ${{matrix.jdk}}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{matrix.jdk}}\n      - name: \"Init Candidate Versions\"\n        run: |\n          DUBBO_VERSION=\"${{needs.build-source.outputs.version}}\"\n          CANDIDATE_VERSIONS=\"dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION\"\n          echo \"CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS\" >> $GITHUB_ENV\n      - name: \"Build test image\"\n        run: |\n          cd test && bash -c ./build-test-image.sh\n      - name: \"Run tests\"\n        run: cd test && bash ./run-tests.sh\n      - name: \"Upload test logs\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-logs-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/logs/*\n      - name: \"Upload test result\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-result-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/jobs/*-result*\n  integration-test-result:\n    needs: [integration-test-job]\n    if: always()\n    runs-on: ubuntu-22.04\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n    strategy:\n      matrix:\n        jdk: [ 8, 11, 17, 21, 25 ]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Download test result\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: integration-test-result-${{matrix.jdk}}-*\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: test/jobs/\n          merge-multiple: true\n      - name: \"Merge test result\"\n        run: ./test/scripts/merge-test-results.sh\n\n  error-code-inspecting:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: \"3.3\"\n          path: \"./dubbo\"\n\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-test-tools'\n          ref: main\n          path: \"./dubbo-test-tools\"\n\n      - name: \"Set up JDK 21\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 21\n\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo\n          ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true\n      - name: \"Run Error Code Inspecting\"\n        env:\n          DUBBO_ECI_REPORT_AS_ERROR: true\n        run: |\n          cd ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector\n          ../mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C package exec:java -Ddubbo.eci.report-as-error=${DUBBO_ECI_REPORT_AS_ERROR} -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -Ddubbo.eci.path=${{ github.workspace }}/dubbo\n\n      - name: \"Upload error code inspection result\"\n        # always() should not be used here, since we don't need to handle the 'canceled' situation.\n        if: ${{ success() || failure() }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: \"error-inspection-result\"\n          path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt\n\n  native-image-inspecting:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          path: \"./dubbo\"\n      - name: \"Set up GraalVM environment\"\n        uses: graalvm/setup-graalvm@v1\n        with:\n          version: '22.3.0'\n          java-version: '17'\n          components: 'native-image'\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          native-image-job-reports: 'true'\n      - name: \"Set up Zookeeper environment\"\n        run: |\n          wget -t 1 -T 120 https://archive.apache.org/dist/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz\n          tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz\n          mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg\n          apache-zookeeper-3.8.4-bin/bin/zkServer.sh start\n      - name: \"Check environment\"\n        run: |\n          java --version\n          native-image --version\n      - name: \"Set current date as env variable\"\n        run: echo \"TODAY=$(date +'%Y%m%d')\" >> $GITHUB_ENV\n      - name: \"Restore local Maven repository cache\"\n        uses: actions/cache/restore@v4\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo\n          ./mvnw ${{ env.MAVEN_ARGS }} -T 2C clean install -P skip-spotless -Dmaven.test.skip=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true\n      - name: \"Checkout dubbo-samples repository\"\n        uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n          path: \"./dubbo-samples\"\n      - name: \"Compile and run Dubbo native image demo\"\n        run: |\n          MVNW=\"${{ github.workspace }}/dubbo-samples/mvnw ${{ env.MAVEN_ARGS }} -Dmaven.test.skip=true\"\n          cd ${{ github.workspace }}/dubbo-samples/2-advanced/dubbo-samples-native-image/dubbo-samples-native-image-provider\n          $MVNW clean package -P native native:compile\n          nohup ./target/dubbo-samples-native-image-provider &\n          sleep 10\n          curl \\\n            --header \"Content-Type: application/json\" \\\n            --data '{\"name\":\"Dubbo\"}' \\\n            http://localhost:50052/org.apache.dubbo.nativeimage.DemoService/sayHello/\n"
  },
  {
    "path": ".github/workflows/release-test.yml",
    "content": "name: Release Test\n\non:\n  push:\n    branches:\n      - '**-release'\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\nenv:\n  FORK_COUNT: 2\n  FAIL_FAST: 0\n  SHOW_ERROR_DETAIL: 1\n  #multi-version size limit\n  VERSIONS_LIMIT: 4\n  ALL_REMOTE_VERSION: true\n  CANDIDATE_VERSIONS: '\n    spring.version:5.3.24,6.1.5;\n    spring-boot.version:2.7.6,3.2.3;\n    '\n\njobs:\n  license:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n      - name: Check License\n        uses: apache/skywalking-eyes@main\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n  build-source:\n    runs-on: ubuntu-22.04\n    outputs:\n      version: ${{ steps.dubbo-version.outputs.version }}\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          path: dubbo\n      - uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 21\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n      - name: \"Build Dubbo with Maven\"\n        run: |\n          cd ./dubbo\n          ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Pack checkstyle file if failure\"\n        if: failure()\n        run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r\n      - name: \"Upload checkstyle file if failure\"\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: \"checkstyle-file\"\n          path: ${{ github.workspace }}/checkstyle.zip\n      - name: \"Calculate Dubbo Version\"\n        id: dubbo-version\n        run: |\n          REVISION=`awk '/<revision>[^<]+<\\/revision>/{gsub(/<revision>|<\\/revision>/,\"\",$1);print $1;exit;}' ./dubbo/pom.xml`\n          echo \"version=$REVISION\" >> $GITHUB_OUTPUT\n          echo \"dubbo version: $REVISION\"\n  unit-test-prepare:\n    name: \" Preparation for Unit Test On ${{ matrix.os }}\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n    env:\n      ZOOKEEPER_VERSION: 3.7.2\n    steps:\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n      - name: \"Set up msys2 if necessary\"\n        if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        uses: msys2/setup-msys2@v2\n        with:\n          release: false  # support cache, see https://github.com/msys2/setup-msys2#context\n      - name: \"Download zookeeper binary archive in Linux OS\"\n        if: ${{ startsWith( matrix.os, 'ubuntu') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        run: |\n          mkdir -p ${{ github.workspace }}/.tmp/zookeeper\n          wget -t 1 -T 120 -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120-c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n          echo \"list the downloaded zookeeper binary archive\"\n          ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n      - name: \"Download zookeeper binary archive in Windows OS\"\n        if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}\n        shell: msys2 {0}\n        run: |\n          mkdir -p ${{ github.workspace }}/.tmp/zookeeper\n          wget -t 1 -T 120 -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||\n          wget -t 1 -T 120 -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n          echo \"list the downloaded zookeeper binary archive\"\n          ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz\n  unit-test:\n    needs: [build-source, unit-test-prepare]\n    name: \"Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }})\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n        jdk: [ 8, 11, 17, 21, 25 ]\n    env:\n      DISABLE_FILE_SYSTEM_TEST: true\n    steps:\n      - uses: actions/checkout@v4\n      - name: \"Set MAVEN_OPTS for JDK 24+ on Linux\"\n        if: ${{ matrix.jdk >= 24 && startsWith(matrix.os, 'ubuntu') }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $GITHUB_ENV\n      - name: \"Set MAVEN_OPTS for JDK 24+ on Windows\"\n        if: ${{ matrix.jdk >= 24 && startsWith(matrix.os, 'windows') }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $env:GITHUB_ENV\n      - name: \"Set up JDK ${{ matrix.jdk }}\"\n        uses: actions/setup-java@v4\n        with:\n          java-version: ${{ matrix.jdk }}\n          distribution: 'zulu'\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-\n      - name: \"Test with Maven with Integration Tests\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n\n  unit-test-fastjson2:\n    needs: [build-source, unit-test-prepare]\n    name: \"Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }}, Serialization: fastjson2)\"\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-22.04, windows-latest ]\n        jdk: [ 8, 11, 17, 21, 25 ]\n    env:\n      DISABLE_FILE_SYSTEM_TEST: true\n      DUBBO_DEFAULT_SERIALIZATION: fastjson2\n      MAVEN_SUREFIRE_ADD_OPENS: true\n    steps:\n      - uses: actions/checkout@v4\n      - name: \"Set MAVEN_OPTS for JDK 24+ on Linux\"\n        if: ${{ matrix.jdk >= 24 && startsWith(matrix.os, 'ubuntu') }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $GITHUB_ENV\n      - name: \"Set MAVEN_OPTS for JDK 24+ on Windows\"\n        if: ${{ matrix.jdk >= 24 && startsWith(matrix.os, 'windows') }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $env:GITHUB_ENV\n      - name: \"Set up JDK ${{ matrix.jdk }}\"\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: ${{ matrix.jdk }}\n      - uses: actions/cache@v3\n        name: \"Cache local Maven repository\"\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - uses: actions/cache@v3\n        name: \"Cache zookeeper binary archive\"\n        id: \"cache-zookeeper\"\n        with:\n          path: ${{ github.workspace }}/.tmp/zookeeper\n          key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}\n          restore-keys: |\n            zookeeper-${{ runner.os }}-\n      - name: \"Test with Maven with Integration Tests on JDK 8\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk == '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,'!jdk15ge-add-open' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests on JDK 8\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk == '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P\"jacoco,'!jdk15ge-add-open'\" -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n      - name: \"Test with Maven with Integration Tests\"\n        timeout-minutes: 70\n        if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk != '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,jdk15ge-simple,'!jdk15ge-add-open' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\n      - name: \"Test with Maven without Integration Tests\"\n        timeout-minutes: 90\n        if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk != '8' }}\n        run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P\"jacoco,jdk15ge-simple,'!jdk15ge-add-open'\" -D\"http.keepAlive=false\" -D\"maven.wagon.http.pool=false\" -D\"maven.wagon.httpconnectionManager.ttlSeconds=120\" -D\"maven.wagon.http.retryHandler.count=5\" -DskipTests=false -DskipIntegrationTests=true -D\"checkstyle.skip=false\" -D\"checkstyle_unix.skip=true\" -D\"rat.skip=false\" -D\"maven.javadoc.skip=true\" -D\"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper\"\n\n  samples-test-prepare:\n    runs-on: ubuntu-22.04\n    env:\n      JOB_COUNT: 5\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Prepare test list\"\n        run: |\n          bash ./test/scripts/prepare-test.sh\n      - name: \"Upload test list\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-list\n          path: test/jobs\n  samples-test-job:\n    needs: [build-source, samples-test-prepare]\n    name: \"Samples Test on ubuntu-22.04 (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})\"\n    runs-on: ubuntu-22.04\n    timeout-minutes: 90\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n      TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt\n    strategy:\n      fail-fast: false\n      matrix:\n        jdk: [ 8, 11, 17, 21, 25 ]\n        job_id: [1, 2, 3, 4, 5]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Set MAVEN_OPTS for JDK 24+\"\n        if: ${{ matrix.jdk >= 24 }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $GITHUB_ENV\n      - name: \"Cache local Maven repository\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Restore Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}\n            ${{ runner.os }}-dubbo-snapshot-\n      - name: \"Download test list\"\n        uses: actions/download-artifact@v4\n        with:\n          name: samples-test-list\n          path: test/jobs/\n      - name: \"Set up JDK ${{matrix.jdk}}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{matrix.jdk}}\n      - name: \"Init Candidate Versions\"\n        run: |\n          DUBBO_VERSION=\"${{needs.build-source.outputs.version}}\"\n          CANDIDATE_VERSIONS=\"dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION\"\n          echo \"CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS\" >> $GITHUB_ENV\n      - name: \"Build test image\"\n        run: |\n          cd test && bash -c ./build-test-image.sh\n      - name: \"Run tests\"\n        run: cd test && bash ./run-tests.sh\n      - name: \"Upload test result\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: samples-test-result-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/jobs/*-result*\n  samples-test-result:\n    needs: [samples-test-job]\n    if: always()\n    runs-on: ubuntu-22.04\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n    strategy:\n      matrix:\n        jdk: [ 8, 11, 17, 21, 25 ]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n      - name: \"Download test result\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: samples-test-result-${{matrix.jdk}}-*\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: test/jobs/\n          merge-multiple: true\n      - name: \"Merge test result\"\n        run: ./test/scripts/merge-test-results.sh\n\n  integration-test-prepare:\n    runs-on: ubuntu-22.04\n    env:\n      JOB_COUNT: 5\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Prepare test list\"\n        run: |\n          bash ./test/scripts/prepare-test.sh\n      - name: \"Upload test list\"\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-list\n          path: test/jobs\n  integration-test-job:\n    needs: [build-source, integration-test-prepare]\n    name: \"Integration Test on ubuntu-22.04 (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})\"\n    runs-on: ubuntu-22.04\n    timeout-minutes: 90\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n      TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt\n    strategy:\n      fail-fast: false\n      matrix:\n        jdk: [ 8, 11, 17, 21, 25 ]\n        job_id: [1, 2, 3, 4, 5]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Set MAVEN_OPTS for JDK 24+\"\n        if: ${{ matrix.jdk >= 24 }}\n        run: echo \"MAVEN_OPTS=--sun-misc-unsafe-memory-access=allow\" >> $GITHUB_ENV\n      - name: \"Cache local Maven repository\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Restore Dubbo cache\"\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2/repository/org/apache/dubbo\n          key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}\n            ${{ runner.os }}-dubbo-snapshot-\n      - name: \"Download test list\"\n        uses: actions/download-artifact@v4\n        with:\n          name: integration-test-list\n          path: test/jobs/\n      - name: \"Set up JDK ${{matrix.jdk}}\"\n        uses: actions/setup-java@v1\n        with:\n          java-version: ${{matrix.jdk}}\n      - name: \"Init Candidate Versions\"\n        run: |\n          DUBBO_VERSION=\"${{needs.build-source.outputs.version}}\"\n          CANDIDATE_VERSIONS=\"dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION\"\n          echo \"CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS\" >> $GITHUB_ENV\n      - name: \"Build test image\"\n        run: |\n          cd test && bash -c ./build-test-image.sh\n      - name: \"Run tests\"\n        run: cd test && bash ./run-tests.sh\n      - name: \"Upload test result\"\n        if: always()\n        uses: actions/upload-artifact@v4\n        with:\n          name: integration-test-result-${{matrix.jdk}}-${{matrix.job_id}}\n          path: test/jobs/*-result*\n  integration-test-result:\n    needs: [integration-test-job]\n    if: always()\n    runs-on: ubuntu-22.04\n    env:\n      JAVA_VER: ${{matrix.jdk}}\n    strategy:\n      matrix:\n        jdk: [ 8, 11, 17, 21, 25 ]\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-integration-cases'\n          ref: main\n      - name: \"Download test result\"\n        uses: actions/download-artifact@v4\n        with:\n          pattern: integration-test-result-${{matrix.jdk}}-*\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          path: test/jobs/\n          merge-multiple: true\n      - name: \"Merge test result\"\n        run: ./test/scripts/merge-test-results.sh\n\n  error-code-inspecting:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          path: \"./dubbo\"\n\n      - uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-test-tools'\n          ref: main\n          path: \"./dubbo-test-tools\"\n\n      - name: \"Set up JDK 21\"\n        uses: actions/setup-java@v4\n        with:\n          java-version: 21\n          distribution: 'zulu'\n\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo\n          ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true\n      - name: \"Run Error Code Inspecting\"\n        env:\n          DUBBO_ECI_REPORT_AS_ERROR: true\n        run: |\n          cd ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector\n          ../mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C package exec:java -Ddubbo.eci.report-as-error=${DUBBO_ECI_REPORT_AS_ERROR} -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -Ddubbo.eci.path=${{ github.workspace }}/dubbo\n      - name: \"Upload error code inspection result\"\n        # always() should not be used here, since we don't need to handle the 'canceled' situation.\n        if: ${{ success() || failure() }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: \"error-inspection-result\"\n          path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt\n\n  native-image-inspecting:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          path: \"./dubbo\"\n      - name: \"Set up GraalVM environment\"\n        uses: graalvm/setup-graalvm@v1\n        with:\n          version: '22.3.0'\n          java-version: '17'\n          components: 'native-image'\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          native-image-job-reports: 'true'\n      - name: \"Set up Zookeeper environment\"\n        run: |\n          wget -t 1 -T 120 https://archive.apache.org/dist/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz\n          tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz\n          mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg\n          apache-zookeeper-3.8.4-bin/bin/zkServer.sh start\n      - name: \"Check environment\"\n        run: |\n          java --version\n          native-image --version\n      - name: \"Set current date as env variable\"\n        run: echo \"TODAY=$(date +'%Y%m%d')\" >> $GITHUB_ENV\n      - name: \"Restore local Maven repository cache\"\n        uses: actions/cache/restore@v4\n        with:\n          path: ~/.m2/repository\n          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }}\n          restore-keys: |\n            ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}\n            ${{ runner.os }}-maven-\n      - name: \"Compile Dubbo (Linux)\"\n        run: |\n          cd ${{ github.workspace }}/dubbo\n          ./mvnw ${{ env.MAVEN_ARGS }} -T 2C clean install -P skip-spotless -Dmaven.test.skip=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true\n      - name: \"Checkout dubbo-samples repository\"\n        uses: actions/checkout@v4\n        with:\n          repository: 'apache/dubbo-samples'\n          ref: master\n          path: \"./dubbo-samples\"\n      - name: \"Compile and run Dubbo native image demo\"\n        run: |\n          MVNW=\"${{ github.workspace }}/dubbo-samples/mvnw ${{ env.MAVEN_ARGS }} -Dmaven.test.skip=true\"\n          cd ${{ github.workspace }}/dubbo-samples/2-advanced/dubbo-samples-native-image/dubbo-samples-native-image-provider\n          $MVNW clean package -P native native:compile\n          nohup ./target/dubbo-samples-native-image-provider &\n          sleep 10\n          curl \\\n            --header \"Content-Type: application/json\" \\\n            --data '{\"name\":\"Dubbo\"}' \\\n            http://localhost:50052/org.apache.dubbo.nativeimage.DemoService/sayHello/\n"
  },
  {
    "path": ".gitignore",
    "content": "# maven ignore\ntarget/\n*.jar\n*.war\n*.zip\n*.tar\n*.tar.gz\n.flattened-pom.xml\n\n# eclipse ignore\n.settings/\n.project\n.classpath\n.externalToolBuilders\nmaven-eclipse.xml\n\n# idea ignore\n.idea/\n*.ipr\n*.iml\n*.iws\n\n# visual-studio-code ignore\n.vscode/\n\n# temp ignore\n*.log\n*.cache\n*.diff\n*.patch\n*.tmp\n\n# system ignore\n.DS_Store\nThumbs.db\n*.orig\n\n# license check result\nlicense-list\n\n# grpc compiler\ncompiler/gradle.properties\ncompiler/build/*\ncompiler/.gradle/*\n\n# protobuf\ndubbo-serialization/dubbo-serialization-protobuf/build/*\ndubbo-demo/dubbo-demo-triple/build/*\n\n# global registry center\n.tmp\n\n.git.exec.error\n\n# log files generated by testcase.\ndubbo-rpc/dubbo-rpc-api/custom-access.log*\n\n"
  },
  {
    "path": ".licenserc.yaml",
    "content": "header:\n  license:\n    spdx-id: Apache-2.0\n    content: |\n      Licensed to the Apache Software Foundation (ASF) under one or more\n      contributor license agreements.  See the NOTICE file distributed with\n      this work for additional information regarding copyright ownership.\n      The ASF licenses this file to You under the Apache License, Version 2.0\n      (the \"License\"); you may not use this file except in compliance with\n      the License.  You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n      Unless required by applicable law or agreed to in writing, software\n      distributed under the License is distributed on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n      See the License for the specific language governing permissions and\n      limitations under the License.\n\n  paths-ignore:\n    - '**/*.versionsBackup'\n    - '**/.idea/'\n    - '**/*.iml'\n    - '**/.settings/*'\n    - '**/.classpath'\n    - '**/.project'\n    - '**/target/**'\n    - '**/generated/**'\n    - '**/*.log'\n    - '**/codestyle/*'\n    - '**/resources/META-INF/**'\n    - '**/resources/mockito-extensions/**'\n    - '**/*.proto'\n    - '**/*.cache'\n    - '**/*.txt'\n    - '**/*.load'\n    - '**/*.flex'\n    - '**/*.fc'\n    - '**/*.javascript'\n    - '**/*.properties'\n    - '**/*.sh'\n    - '**/*.bat'\n    - '**/*.md'\n    - '**/*.svg'\n    - '**/*.png'\n    - '**/*.json'\n    - '**/*.conf'\n    - '**/*.ftl'\n    - '**/*.tpl'\n    - '**/*.factories'\n    - '**/*.handlers'\n    - '**/*.schemas'\n    - '**/*.nojekyll'\n    - '.git/'\n    - '.github/**'\n    - '**/.gitignore'\n    - '**/.helmignore'\n    - '.repository/'\n    - 'compiler/**'\n    - '.gitmodules'\n    - '.mvn'\n    - 'mvnw'\n    - 'mvnw.cmd'\n    - 'LICENSE'\n    - 'NOTICE'\n    - 'CNAME'\n    - 'Jenkinsfile'\n    - '**/vendor/**'\n    - '**/src/test/resources/certs/**'\n    - '**/src/test/resources/definition/**'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocalMap.java'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/timer/Timeout.java'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/timer/Timer.java'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/timer/TimerTask.java'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/utils/CIDRUtils.java'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/utils/Utf8Utils.java'\n    - 'dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/EmbeddedZooKeeper.java'\n    - 'dubbo-test/dubbo-test-common/src/main/java/org/apache/dubbo/test/common/utils/TestSocketUtils.java'\n    - 'dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TriHttp2RemoteFlowController.java'\n    - 'dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/cors/CorsHeaderFilter.java'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/serial/SerializingExecutor.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/AbstractAotMojo.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/AbstractDependencyFilterMojo.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/CommandLineBuilder.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/DependencyFilter.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/Exclude.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/ExcludeFilter.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/FilterableDependency.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/Include.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/IncludeFilter.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/JavaCompilerPluginConfiguration.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/JavaExecutable.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/JavaProcessExecutor.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/MatchingGroupIdFilter.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunArguments.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunProcess.java'\n    - 'dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/BasicJsonWriter.java'\n    - 'dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/ExecutableMode.java'\n    - 'dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/MemberCategory.java'\n    - 'dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboMergingDigest.java'\n    - 'dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboAbstractTDigest.java'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/logger/helpers/FormattingTuple.java'\n    - 'dubbo-common/src/main/java/org/apache/dubbo/common/logger/helpers/MessageFormatter.java'\n    - 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/DubboProtocCompilerMojo.java'\n    - 'dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/utils/ProtoTypeMap.java'\n\n  comment: on-failure\n\n  license-location-threshold: 130\n\ndependency:\n  files:\n    - pom.xml\n    - dubbo-dependencies-bom/pom.xml\n  licenses:\n    - name: com.fasterxml.jackson.core:jackson-annotations\n      license: Apache-2.0\n    - name: com.fasterxml.jackson.core:jackson-core\n      license: Apache-2.0\n    - name: com.fasterxml.jackson.core:jackson-databind\n      license: Apache-2.0\n    - name: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml\n      license: Apache-2.0\n    - name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310\n      license: Apache-2.0\n    - name: com.google.code.gson:gson\n      license: Apache-2.0\n    - name: com.google.guava:listenablefuture\n      license: Apache-2.0\n    - name: com.salesforce.servicelibs:grpc-contrib\n      license: BSD 3-clause\n    - name: com.squareup.okhttp3:logging-interceptor\n      license: Apache-2.0\n    - name: com.squareup.okhttp3:okhttp\n      license: Apache-2.0\n    - name: com.squareup.okio:okio\n      license: Apache-2.0\n    - name: com.sun.xml.fastinfoset:FastInfoset\n      license: Apache-2.0\n    - name: io.envoyproxy.controlplane:api\n      license: Apache-2.0\n    - name: io.swagger:swagger-annotations\n      license: Apache-2.0\n    - name: io.swagger:swagger-models\n      license: Apache-2.0\n    - name: org.springframework.boot:spring-boot\n      license: Apache-2.0\n    - name: org.springframework.boot:spring-boot-actuator\n      license: Apache-2.0\n    - name: org.springframework.boot:spring-boot-autoconfigure\n      license: Apache-2.0\n    - name: org.springframework.boot:spring-boot-configuration-processor\n      license: Apache-2.0\n    - name: org.springframework.boot:spring-boot-starter\n      license: Apache-2.0\n    - name: org.springframework.boot:spring-boot-starter-actuator\n      license: Apache-2.0\n    - name: org.springframework.boot:spring-boot-starter-logging\n      license: Apache-2.0\n    - name: org.springframework.boot:spring-boot-starter-tomcat\n      license: Apache-2.0\n    - name: org.springframework.boot:spring-boot-starter-web\n      license: Apache-2.0\n    - name: org.slf4j:slf4j-api\n      license: MIT\n    - name: org.slf4j:slf4j-log4j12\n      license: MIT\n    - name: org.jboss.resteasy:resteasy-jaxrs\n      license: Apache-2.0\n    - name: org.jboss.resteasy:resteasy-client\n      license: Apache-2.0\n    - name: org.jboss.resteasy:resteasy-netty4\n      license: Apache-2.0\n    - name: org.jboss.resteasy:resteasy-jdk-http\n      license: Apache-2.0\n    - name: org.jboss.resteasy:resteasy-jackson-provider\n      license: Apache-2.0\n    - name: org.jboss.resteasy:resteasy-jaxb-provider\n      license: Apache-2.0\n    - name: net.jcip:jcip-annotations\n      license: Apache-2.0\n    - name: org.apache.zookeeper:zookeeper\n      license: Apache-2.0\n    - name: org.apache.zookeeper:zookeeper-jute\n      license: Apache-2.0\n    - name: net.bytebuddy:byte-buddy\n      license: Apache-2.0\n    - name: javax.enterprise:cdi-api\n      license: Apache-2.0\n    - name: org.codehaus.plexus:plexus-component-annotations\n      license: Apache-2.0\n    - name: org.slf4j:jcl-over-slf4j\n      license: Apache-2.0\n    - name: org.slf4j:jul-to-slf4j\n      license: Apache-2.0\n    - name: org.codehaus.plexus:plexus-interpolation\n      license: Apache-2.0\n    - name: org.sonatype.plexus:plexus-sec-dispatcher\n      license: Apache-2.0\n    - name: org.sonatype.plexus:plexus-cipher\n      license: Apache-2.0\n    - name: com.alibaba.csp:sentinel-apache-dubbo3-adapter\n      license: Apache-2.0\n    - name: com.alibaba.csp:sentinel-transport-simple-http\n      license: Apache-2.0\n    - name: com.alibaba.csp:sentinel-transport-common\n      license: Apache-2.0\n    - name: com.alibaba.csp:sentinel-datasource-extension\n      license: Apache-2.0\n    - name: com.alibaba.csp:sentinel-core\n      license: Apache-2.0\n    - name: com.google.protobuf:protobuf-java\n      license: BSD 3-clause\n    - name: com.google.protobuf:protobuf-java-util\n      license: BSD 3-clause\n    - name: org.antlr:antlr4\n      license: BSD 3-clause\n    - name: org.antlr:antlr-runtime\n      license: BSD 3-clause\n    - name: org.antlr:ST4\n      license: BSD 3-clause\n    # multi license\n    - name: org.javassist:javassist\n      license: Apache-2.0\n    - name: javax.annotation:javax.annotation-api\n      license: CDDL-1.0\n    - name: com.salesforce.servicelibs:jprotoc\n      license: CDDL-1.0\n    - name: org.checkerframework:checker-compat-qual\n      license: MIT\n    - name: ch.qos.logback:logback-classic\n      license: EPL-1.0\n    - name: ch.qos.logback:logback-core\n      license: EPL-1.0\n    - name: javax.servlet:javax.servlet-api\n      license: CDDL-1.1\n    - name: com.sun.activation:javax.activation\n      license: CDDL-1.1\n    - name: javax.activation:activation\n      license: CDDL-1.1\n    - name: jakarta.annotation:jakarta.annotation-api\n      license: EPL-2.0\n    - name: org.glassfish:jakarta.el\n      license: EPL-2.0\n    - name: org.jboss.spec.javax.annotation:jboss-annotations-api_1.2_spec\n      license: CDDL-1.1\n    - name: org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec\n      license: EPL-2.0\n    - name: org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec\n      license: EPL-2.0\n  excludes:\n    - name: javax.xml.bind:jsr173_api\n"
  },
  {
    "path": ".mvn/jvm.config",
    "content": "-Dfile.encoding=UTF-8\n-Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8\n-Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8"
  },
  {
    "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#   https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\ndistributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip\nwrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar\n"
  },
  {
    "path": "CHANGES.md",
    "content": "# Release Notes\n\nPlease refer to https://github.com/apache/dubbo/releases for notes of future releases.\n\n## 2.7.6 \n\n### Features\n* Support Service Authentication https://github.com/apache/dubbo/issues/5461\n\n### Enhancement\n* Removing the internal JDK API from FileSystemDynamicConfiguration\n* Refactor the APT test-cases implementation of dubbo-metadata-processor in Java 9+\n* Remove feature envy\n* JsonRpcProtocol support Generalization \n* Reduce object allocation for ProtocolUtils.serviceKey\n* Reduce object allocation for ContextFilter.invoke\n\n### Bugfixes\n* Fixed bugs reported from 2.7.5 or lower versions, check [2.7.6 milestone](https://github.com/apache/dubbo/milestone/30) for details.\n\n### Compatibility\n1. Filter refactor, the callback method `onResponse` annotated as @Deprecated has been removed, users of lower versions that \nhave extended Filter implementations and enabled Filter callbacks should be careful of this change.\n2. RpcContext added some experimental APIs to support generic Object transmission.\n\n## 2.7.5\n\n### Features\n* Support HTTP/2 through gRPC, offers all features supported by HTTP/2 and gRPC\n    * Stream communication: client stream, server stream and bi-stream.\n    * Reactive stream style RPC call.\n    * Back pressure based on HTTP/2 flow-control mechanism.\n    * TLS secure transport layer.\n    * Define service using IDL\n* Protobuf support for native Dubbo\n    * Define service using IDL\n    * Protobuf serialization\n* TLS for netty4 server\n* New SPI for dynamically adding extra parameters into provider URL, especially env parameters.\n* **[BETA]** Brand new Service Discovery mechanism: Service Reflection - instance (application) level service discovery.\n* **[BETA]** Brand new API for bootstraping Dubbo projects\n\n### Performance Tuning\n* Overall performance improved by nearly 30% compared to v2.7.3 (by QPS in certain circumstances)\n* Improved consumer side thread model to avoid thread allocation and context switch, especially useful for services serving big traffic.\n\n### Enhancement\n* Load balance strategy among multiple registries:\n    * Preferred\n    * Same zone first\n    * Weighted LB\n    * The first one available\n* New callback SPI for receiving address change notifications\n* Refactoring of config module\n\n### Bugfixes\ncheck 2.7.5 milestone for details.\n\n## 2.7.4.1\n\n### Enhancement\n\n* Enhance ProtobufTypeBuilder support generate type definition which contains Bytes List or Bytes Map. #5083\n* Using the ID of Dubbo Config as the alias of Bean. #5094\n* tag router supports anyhost. #4431\n* optimize generic invoke. #4076\n* dubbo zookeeper registry too slow #4828\n* use consul with group and version. #4755\n* qos support host config. #4720\n* migrate http protocol #4781\n* Some unit test optimization. #5026 #4803 #4687\n\n### Bugfixes\n\n* Apollo namespace optimization.  #5105\n* Simplify dubbo-common transitive dependencies. #5107 \n* Delete 'config.' prefix for url generated from ConfigCenterConfig. #5001\n* fix set generic method error. #5079\n* Add support for overriding Map properties in AbstractConfig.refresh. #4882\n* Fix travis javax.ex dependency issue. (unit test)\n* Fix: ExtensionLoader load duplicate filter，no log or exception. #4340 \n* When the provider interrupts abnormally, the consumer cannot return quickly and still waits for the timeout to end. #4694\n* Fix register config not take effect because of url simplified。 #4397\n* Don't support metadata for generic service. #4641 \n* Avoid resize in ClassUtils.java. #5009 \n* default attribute in <dubbo:registry> doesn't work as expected. #4412\n* make RegistryDirectory can refresh the invokers when providers number become 0 when using nacos registry. #4793\n* Multiple @Reference annotations only have one effect #4674\n* Fix RpcContext.getContext().getRemoteApplicationName() returns null #4351\n* Security issue: upgrade fastjson version to 1.2.60. #5018\n* nacos-registry:serviceName split error #4974\n* AbstractConfig.java-getMetaData set default depend on getmethod sequence #4678\n* fix protocol register set false not work. #4776 \n* Fix: In Rest protocol, the limitation of Dubbo-Attachments. #4898\n* The logic of org.apache.dubbo.config.MonitorConfig#isValid is incorrect #4892\n* protostuff return stackoverflow and other error msg #4861\n* fix method parameter bean generation. #3796 \n* replace hardcode with regex pattern #4810\n* Fix warm up issue when provider's timestamp is bigger than local machine's timestamp. #4870\n* Fix use generic invocation via API , lost #4238 ion\" value #4784\n* In consumer side the app cannot catch the exception from provider that is configured serialization=\"kryo\". #4238\n* fix StringUtils#isBlank #4725\n* when the interfaceName of the Reference annotation has duplicated,the exception is puzzled #4160\n* when anonymity  bean is defined in spring context，dubbo throw npe #\n* add Thread ContextClassLoader #4712\n* Fix judgment ipv4 address #4729\n* The compilation of static methods should be excluded when generating the proxy. #4647\n* check EOF of inputstream in IOUtils.write #4648\n\n\n## 2.7.3\n\n### Change List\n\n1. Asynchronous support\n    * Unified asynchronous and synchronous callback process, exception scenario triggers onError callback, #4401\n    * Performance degradation caused by CompletableFuture.get() in JDK1.8 environment, #4279\n\n2. Configuration Center\n    * ConfigCenter custom namespace does not take effect, #4411\n    * Unify the models implemented by several configuration centers such as Zookeeper, Nacos, and Etcd. Please refer to the description for possible incompatibility issues, #4388\n    * Adjust Override Coverage Rule Center Priority: Service Level > Application Level, #4175\n\n3. 2.6.x compatibility\n    * Support Zipkin tracing feature provided by Zipkin officially, #3728, #4471\n    * DubboComponentScan supports simultaneous scanning of annotations under the `com.alibaba.*` and `org.apache.*` packages, #4330\n\n4. The Nacos Registration Center only subscribes to the address list and no longer subscribes to configuration information, #4454.\n\n5. Support to read the environment configuration from the specified location, which can be specified by -D or OS VARIABLE. Please refer to [automatically loading environment variables](http://dubbo.apache.org/en-us/docs/user/configuration/environment-variables.html)\n\n6. Fix consumer cannot downgrade to providers with no tags when there's no tagged providers can match, #4525\n\n7. Some other bugfixes, #4346 #4338 #4349 #4377\n\n### Change List\n\n1. 异步支持相关\n\n    - 统一异步和同步的回调流程，异常场景触发onError回调 #4401\n    - CompletableFuture.get()在JDK1.8环境下带来的性能下降问题 #4279\n\n2. 配置中心相关\n\n    - ConfigCenter自定义namespace不生效的问题 #4411\n    - 统一Zookeeper、Nacos、Etcd等几个配置中心实现的模型，可能带来的不兼容性问题请参见说明。相关修改：#4388\n    - 调整Override覆盖规则中心优先级：服务级别 > 应用级别 #4175\n\n3. 2.6.x兼容性\n\n    - 兼容zipkin官方提供的基于Dubbo-2.6 API的集成 #3728, #4471\n    - DubboComponentScan支持同时扫描 `com.alibaba.*` 和 `org.apache.*` 两个包下的注解 #4330\n\n4. Nacos注册中心只订阅地址列表，不再订阅配置信息 #4454\n\n5. 支持从指定位置读取环境配置，可通过-D或OS VARIABLE指定，具体请参见[使用说明](http://dubbo.apache.org/zh-cn/docs/user/configuration/environment-variables.html)\n\n6. 标签路由在消费端使用静态打标方式时，无法实现自动降级以消费无标签提供者 #4525\n\n7. 其他一些bugfix，#4346 #4338 #4349 #4377 \n\n## 2.7.2\n\n### New Features\n\n- nacos config center / metadata center support. [#3846](https://github.com/apache/dubbo/issues/3846)\n- Etcd support as config center and metadata center [#3653](https://github.com/apache/dubbo/issues/3653)\n- Support Redis cluster in Metadata Report. [#3817](https://github.com/apache/dubbo/issues/3817)\n- add new module for Dubbo Event. [#4096](https://github.com/apache/dubbo/issues/4096)\n- Support multiple registry that including some effective registry, such as zk, redis [#3599](https://github.com/apache/dubbo/issues/3599)\n- support nacos metadata [#4025](https://github.com/apache/dubbo/issues/4025)\n- Dubbo support Google Protobuf generic reference [#3829](https://github.com/apache/dubbo/issues/3829)\n- Merge serialization-native-hessian-for-apache-dubbo into incubator-dubbo [#3961](https://github.com/apache/dubbo/issues/3961)\n- Merge rpc-native-thrift-for-apache-dubbo into incubator-dubbo [#3960](https://github.com/apache/dubbo/issues/3960)\n- add socks5 proxy support [#3624](https://github.com/apache/dubbo/issues/3624)\n- Integrate with SOFARegistry [#3874](https://github.com/apache/dubbo/issues/3874)\n- Introduce CompletableFuture $invokeAsync for GenericService, now, for generic call, you can use:  \n  $invoke for sync method call with normal return type.\n  $invokeAsync for async method call with CompletableFuture<T> signature. [#3163](https://github.com/apache/dubbo/issues/3163)\n\n### Enhancement\n\n- Performance tuning for TimeoutTask in DefaultFuture. [#4129](https://github.com/apache/dubbo/issues/4129)\n- Add a script to check dependencies license. [#3840](https://github.com/apache/dubbo/issues/3840)\n- Change DynamicConfiguration definition to better adapt to Apollo's namespace storage model.[#3266](https://github.com/apache/dubbo/issues/3266)\n- use equal explicit class to replace anonymous class [#4027](https://github.com/apache/dubbo/issues/4027)\n- Separate Constants.java into some SubConstants Class [#3137](https://github.com/apache/dubbo/issues/3137)\n- Need to enhance DecodeableRpcResult error message [#3994](https://github.com/apache/dubbo/issues/3994)\n- Provide more meaningful binary releases. [#2491](https://github.com/apache/dubbo/issues/2491)\n- remove useless module-dubbo-test-integration [#3573](https://github.com/apache/dubbo/issues/3573)\n- complete lookup method of consul registry and add integration test [#3890](https://github.com/apache/dubbo/issues/3890)\n- Metrics Service [#3702](https://github.com/apache/dubbo/issues/3702)\n- Update nacos-client to 1.0.0 [#3804](https://github.com/apache/dubbo/issues/3804)\n- Fluent style builder API support [#3431](https://github.com/apache/dubbo/issues/3431)\n- Update readme to remove the incubator prefix [#4159](https://github.com/apache/dubbo/issues/4159)\n- update erlang link [#4100](https://github.com/apache/dubbo/issues/4100)\n- optimize array code style [#4031](https://github.com/apache/dubbo/issues/4031)\n- optimize some code style [#4006](https://github.com/apache/dubbo/issues/4006)\n- remove useless module-dubbo-test-integration [#3989](https://github.com/apache/dubbo/issues/3989)\n- optimize constant naming style [#3970](https://github.com/apache/dubbo/issues/3970)\n- Use maven CI friendly versions: revision. [#3851](https://github.com/apache/dubbo/issues/3851)\n- remove-parse-error-log [#3862](https://github.com/apache/dubbo/issues/3862)\n- Complete xsd definition for ConfigCenterConfig. [#3854](https://github.com/apache/dubbo/issues/3854)\n- add remoteApplicationName field in RpcContext [#3816](https://github.com/apache/dubbo/issues/3816)\n\n### Bugfixes\n\n- @Reference can't match the local @Service beans. [#4071](https://github.com/apache/dubbo/issues/4071)\n- remove some illegal licence: jcip-annotations, jsr173_api. [#3790](https://github.com/apache/dubbo/issues/3790)\n- Qos port can't be disabled by externalized property. [#3958](https://github.com/apache/dubbo/issues/3958)\n- Fix consumer will generate wrong stackTrace. [#4137](https://github.com/apache/dubbo/issues/4137)\n- nacos registry serviceName may conflict. [#4111](https://github.com/apache/dubbo/issues/4111)\n- The client loses the listener when the network is reconnected. [#4115](https://github.com/apache/dubbo/issues/4115)\n- fix registry urls increase forever when recreate reference proxy. [#4109](https://github.com/apache/dubbo/issues/4109)\n- In dubbo 2.7.1，the watcher processor of zookeeper client throw Nullpointexception. [#3866](https://github.com/apache/dubbo/issues/3866)\n- ReferenceConfig initialized not changed to false once subscribe throws exception [#4068](https://github.com/apache/dubbo/issues/4068)\n- dubbo registry extension compatibility with dubbo 2.6.x. [#3882](https://github.com/apache/dubbo/issues/3882)\n- Annotation mode cannot set service parameters in 2.7.0. [#3778](https://github.com/apache/dubbo/issues/3778)\n- compatibility with Zipkin. [#3728](https://github.com/apache/dubbo/issues/3728)\n- do local export before register any listener. [#3669](https://github.com/apache/dubbo/issues/3669)\n- Cannot recognize 2.6.x compatible rules from dubbo-admin. [#4059](https://github.com/apache/dubbo/issues/4059)\n- In Dubbo 2.7.0, the provider can't be configured to async [#3650](https://github.com/apache/dubbo/issues/3650)\n- dubbox compatibility [#3991](https://github.com/apache/dubbo/issues/3991)\n- dubbo-2.7.1 providers repeat register [#3785](https://github.com/apache/dubbo/issues/3785)\n- consul registry: NullPointerException [#3923](https://github.com/apache/dubbo/issues/3923)\n- cannot publish local ip address when local ip and public ip exist at the same time [#3802](https://github.com/apache/dubbo/issues/3802)\n- roll back change made by 3520. [#3935](https://github.com/apache/dubbo/issues/3935)\n- dubbo-registry-nacos module is not bundled into Apache Dubbo 2.7.1 [#3797](https://github.com/apache/dubbo/issues/3797)\n- switch from CopyOnWriteArrayList to regular list in order to avoid potential UnsupportedOperationException [#3242](https://github.com/apache/dubbo/issues/3242)\n- Serialization ContentTypeId conflict between avro protocol and protocoluff protocol [#3926](https://github.com/apache/dubbo/issues/3926)\n- delay export function doesn't work. [#3952](https://github.com/apache/dubbo/issues/3952)\n- org.apache.dubbo.rpc.support.MockInvoker#getInterface should not return null [#3713](https://github.com/apache/dubbo/issues/3713)\n- dubbo TagRouter does not work with dubbo:parameter [#3875](https://github.com/apache/dubbo/issues/3875)\n- make protocols a mutable list (a concrete ArrayList) [#3841](https://github.com/apache/dubbo/issues/3841)\n- javadoc lint issue [#3646](https://github.com/apache/dubbo/issues/3646)\n- The etcd3 lease should be recycled correctly [#3684](https://github.com/apache/dubbo/issues/3684)\n- telnet can't work when parameter has no nullary constructor and some fields is primitive [#4007](https://github.com/apache/dubbo/issues/4007)\n- Sort added router list before set the 'routers' field of the RouterChain [#3969](https://github.com/apache/dubbo/issues/3969)\n- fix injvm and local call [#3638](https://github.com/apache/dubbo/issues/3638)\n- spelling error in org.apache.dubbo.common.extension.AdaptiveClassCodeGenerator#generateReturnAndInovation [#3933](https://github.com/apache/dubbo/issues/3933)\n- metadata report doesn't support redis with password [#3826](https://github.com/apache/dubbo/issues/3826)\n- The dubbo protostuff protocol serializes the bug of java.sql.Timestamp [#3914](https://github.com/apache/dubbo/issues/3914)\n- do not filter thread pool by port [#3919](https://github.com/apache/dubbo/issues/3919)\n- 'dubbo-serialization-gson' maven package error [#3903](https://github.com/apache/dubbo/issues/3903)\n- AbstractRegistry will be endless loop, when doSaveProperties method have no permission to save the file [#3746](https://github.com/apache/dubbo/issues/3746)\n- fix fastjson serialization with generic return type [#3771](https://github.com/apache/dubbo/issues/3771)\n- The dubbo-serialization -api modules should not dependency on third-party jar packages [#3762](https://github.com/apache/dubbo/issues/3762)\n- when using protostuff to serialize, there is not to check whether the data is null [#3727](https://github.com/apache/dubbo/issues/3727)\n- bugfix and enhancement for async [#3287](https://github.com/apache/dubbo/issues/3287)\n\n## 2.7.1\n\n### Notice\n\n'zkclient' extension for 'org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter' is removed from Dubbo 2.7.1, and 'curator' extension becomes the default extension. If you happen to config your application to use 'zkclient' explicitly, pls. switch to use 'curator' instead.\n\n### New Features\n\n- service register support on nacos [#3582](https://github.com/apache/dubbo/issues/3582)\n- support consul as registry center, config center and metadata center [#983](https://github.com/apache/dubbo/issues/983)\n- service registry support/config center support on etcd [#808](https://github.com/apache/dubbo/issues/808)\n- metrics support in dubbo 2.7.1 [#3598](https://github.com/apache/dubbo/issues/3598)\n- @Argument @Method support [#2405](https://github.com/apache/dubbo/issues/2045)\n\n### Enhancement\n\n- [Enhancement] @EnableDubboConfigBinding annotates @Repeatable [#1770](https://github.com/apache/dubbo/issues/1770)\n- [Enhancement] Change the default behavior of @EnableDubboConfig.multiple() [#3193](https://github.com/apache/dubbo/issues/3193)\n- Should make annotation easier to use in multiple items circumstance [#3039](https://github.com/apache/dubbo/issues/3039)\n- NoSuchMethodError are thrown when add custom Filter using dubbo2.6.5 and JDK1.6 and upgrade to dubbo2.7.0 [#3570](https://github.com/apache/dubbo/issues/3570)\n- introduce dubbo-dependencies-zookeeper [#3607](https://github.com/apache/dubbo/pull/3607)\n- Zookeeper ConfigCenter reuse the client abstraction and connection session [#3288](https://github.com/apache/dubbo/issues/3288)\n- [Survey] Is it necessary to continue to maintain zkclient in dubbo project? [#3569](https://github.com/apache/dubbo/issues/3569)\n- Start to use IdleStateHandler in Netty4 [#3341](https://github.com/apache/dubbo/pull/3341)\n- Support multiple shared links [#2457](https://github.com/apache/dubbo/pull/2457)\n- Optimize heartbeat [#3299](https://github.com/apache/dubbo/pull/3299)\n- AccessLogFilter simple date format reduce instance creation [#3026](https://github.com/apache/dubbo/issues/3026)\n- Support wildcard ip for tag router rule. [#3289](https://github.com/apache/dubbo/issues/3289)\n- ScriptRouter should cache CompiledScript [#390](https://github.com/apache/dubbo/issues/390)\n- Optimize compareTo in Router to guarantee consistent behaviour. [#3302](https://github.com/apache/dubbo/issues/3302)\n- RMI protocol doesn't support generic invocation [#2779](https://github.com/apache/dubbo/issues/2779)\n- a more elegant way to enhance HashedWheelTimer [#3567](https://github.com/apache/dubbo/pull/3567)\n- obtain local address incorrectly sometimes in dubbo [#538](https://github.com/apache/dubbo/issues/538)\n- implement pull request #3412 on master branch [#3418](https://github.com/apache/dubbo/pull/3418)\n- enhancement for event of response (follow up for pull request #3043) [#3244](https://github.com/apache/dubbo/issues/3244)\n- bump up hessian-lite version #3423 [#3513](https://github.com/apache/dubbo/pull/3513)\n- [Dubbo-3610]make snakeyaml transitive, should we do this? [#3659](https://github.com/apache/dubbo/pull/3659)\n\n### Bugfixes\n\n- cannot register REST service in 2.7 due to the changes in RestProtoco#getContextPath [#3445](https://github.com/apache/dubbo/issues/3445)\n- Conflict between curator client and dubbo [#3574](https://github.com/apache/dubbo/issues/3574)\n- is there a problem in NettyBackedChannelBuffer.setBytes(...)? [#2619](https://github.com/apache/dubbo/issues/2619)\n- [Dubbo - client always reconnect offline provider] Dubbo client bug [#3158](https://github.com/apache/dubbo/issues/3158)\n- fix heartbeat internal [#3579](https://github.com/apache/dubbo/pull/3579)\n- logic issue in RedisRegistry leads to services cannot be discovered. [#3291](https://github.com/apache/dubbo/pull/3291)\n- Multicast demo fails with message \"Can't assign requested address\" [#2423](https://github.com/apache/dubbo/issues/2423)\n- Fix thrift protocol, use path to locate exporter. [#3331](https://github.com/apache/dubbo/pull/3331)\n- cannot use override to modify provider's configuration when hessian protocol is used [#900](https://github.com/apache/dubbo/issues/900)\n- Condition is not properly used ? [#1917](https://github.com/apache/dubbo/issues/1917)\n- connectionMonitor in RestProtocol seems not work [#3237](https://github.com/apache/dubbo/issues/3237)\n- fail to parse config text with white space [#3367](https://github.com/apache/dubbo/issues/3367)\n- @Reference check=false doesn't take effect [#195](https://github.com/apache/dubbo/issues/195)\n- [Issue] SpringStatusChecker execute errors on non-XML Spring configuration [#3615](https://github.com/apache/dubbo/issues/3615)\n- monitor's cluster config is set to failsafe and set to failsafe only [#274](https://github.com/apache/dubbo/issues/274)\n- A question for ReferenceConfigCache. [#1293](https://github.com/apache/dubbo/issues/1293)\n- referenceconfig#destroy never invoke unregister [#3294](https://github.com/apache/dubbo/issues/3294)\n- Fix when qos is disable,log will print every time [#3397](https://github.com/apache/dubbo/pull/3397)\n- service group is not supported in generic direct invocation [#3555](https://github.com/apache/dubbo/issues/3555)\n- setOnreturn doesn't take effect in async generic invocation [#208](https://github.com/apache/dubbo/issues/208)\n- Fix timeout filter not work in async way [#3174](https://github.com/apache/dubbo/pull/3174)\n- java.lang.NumberFormatException: For input string: \"\" [#3069](https://github.com/apache/dubbo/issues/3069)\n- NPE occurred when the configuration was deleted [#3533](https://github.com/apache/dubbo/issues/3533)\n- NPE when package of interface is empty [#3556](https://github.com/apache/dubbo/issues/3556)\n- NPE when exporting rest service using a given path. [#3477](https://github.com/apache/dubbo/issues/3477)\n- NullPointerException happened when using SpringContainer.getContext() [#3476](https://github.com/apache/dubbo/issues/3476)\n- Why does not tomcat throw an exception when `server.start` failed with a socket binding error.  [#3236](https://github.com/apache/dubbo/issues/3236)\n- No such extension org.apache.dubbo.metadata.store.MetadataReportFactory by name redis [#3514](https://github.com/apache/dubbo/issues/3514)\n- dubbo 2.7.1-SNAPSHOT NoClassDefFoundError when use springboot [#3426](https://github.com/apache/dubbo/issues/3426)\n- NPE occurs when use @Reference in junit in spring boot application [#3429](https://github.com/apache/dubbo/issues/3429)\n- When refer the same service with more than one @References(with different configs) on consumer side, only one take effect [#1306](https://github.com/apache/dubbo/issues/1306)\n- consumer always catch java.lang.reflect.UndeclaredThrowableException for the exception thrown from provider [#3386](https://github.com/apache/dubbo/issues/3386)\n- dubbo2.7.0 com.alibaba.com.caucho.hessian.io.HessianProtocolException: 'com.alibaba.dubbo.common.URL' could not be instantiated [#3342](https://github.com/apache/dubbo/issues/3342)\n- Close Resources Properly [#3473](https://github.com/apache/dubbo/issues/3473)\n- SPI entires dup by 3 times. [#2842](https://github.com/apache/dubbo/issues/2842)\n- provider gets wrong interface name from attachment when use generic invocation in 2.6.3 [#2981](https://github.com/apache/dubbo/issues/2981)\n- HashedWheelTimer's queue gets full [#3449](https://github.com/apache/dubbo/issues/3449)\n- Modify MetadataReportRetry ThreadName [#3550](https://github.com/apache/dubbo/pull/3550)\n- Keep interface key in the URL in simplify mode when it's different from path. [#3478](https://github.com/apache/dubbo/issues/3478)\n- nc is not stable in dubbo's bootstrap script [#936](https://github.com/apache/dubbo/issues/936)\n\n## 2.7.0\n\nRequirements: **Java 8+** required\n\nPlease check [here](https://github.com/apache/dubbo/blob/2.7.0-release/CHANGES.md#upgrading-and-compatibility-notifications) for notes and possible compatibility issues for upgrading from 2.6.x or lower to 2.7.0.\n\n### New Features\n\n- Enhancement of service governance rules.\n  - Enriched Routing Rules.\n    1. Conditional Routing. Supports both application-level and service-level conditions.\n    2. Tag Routing. Newly introduced to better support traffic isolation, such as grey deployment.\n  - Decoupling governance rules with the registry, making it easier to extend. Apollo and Zookeeper are available in this version. Nacos support is on the way...\n  - Application-level Dynamic Configuration support.\n  - Use YAML as the configuration language, which is more friendly to read and use.\n\n- Externalized Configuration. Supports reading `dubbo.properties` hosted in remote centralized configuration center - centralized configuration.\n\n- Simplified registry URL. With lower Registry memory use and less notification pressure from Service Directory, separates Configuration notification from Service Discovery.\n\n- Metadata Center. A totally new concept since 2.7.0,  used to store service metadata including static configuration, service definition, method signature, etc.. By default, Zookeeper and Redis are supported as the backend storage. Will work as the basis of service testing, mock and other service governance features going to be supported in [Dubbo-Admin](https://github.com/apache/dubbo-admin).\n\n- Asynchronous Programming Model (only works for Dubbo protocol now)\n  - Built-in support for the method with CompletableFuture<T> signature.\n  - Server-side asynchronous support, with an AsyncContext API works like Servlet 3.0.\n  - Asynchronous filter chain callback.\n\n- Serialization Extension: Protobuf.\n\n- Caching Policy Extension: Expiring Cache.\n\n### Enhancements / Bugfixes\n\n- Load Balancing strategy enhancement: ConsitentHash #2190, LeastActive #2171, Random #2597, RoundRobin #2650.\n\n- Third-party dependency upgrading.\n  - Switch default remoting to Netty 4.\n  - Switch default Zookeeper client to Curator.\n  - Upgrade Jetty to 9.x.\n\n- IPV6 support #2079.\n\n- Performance tuning, check hanging requests on a closed channel, make them return directly #2185.\n\n- Fixed the serialization problem of JDK primitive types in Kryo #2178.\n\n- Fixed the problem of failing to notify Consumer as early as possible after the Provider side deserialization failed #1903.\n\n### Upgrading and Compatibility Notifications\n\nWe have always keep compatibility in mind during the whole process of 2.7.0. We even want old users to upgrade with only on pom version upgrade, but it's hard to achieve that, especially when considering that we have the package renamed in this version, so we had some tradeoffs. If you only used the Dubbo's most basic features, you may have little problems of upgrading, but if you have used some advanced features or have some SPI extensions inside, you'd better read the upgrade notifications carefully. The compatibility issues can be classified into the following 5 categories, for each part, there will have detailed dos and don'ts published later in the official website.\n\n1. Interoperability between 2.7.0 and lower versions\n\n2. Package renaming\n\n   com.alibaba.dubbo -> org.apache.dubbo\n\n3. Simplification of registered URLs\n\n4. Service Governance Rules\n\n5. Configuration\n\n## 2.6.6\n\nEnhancement / New feature：\n\n* tag route.  #3065 \n* Use Netty4 as default Netty version. #3029 \n* upporting Java 8 Date/Time type when serializing with Kryo #3519 \n* support config telnet  #3511\n* add annotation driven in MethodConfig and ArgumentConfig #2603\n* add nacos-registry module #3296  \n* add `protocol` attribute in `@Rerefence` #3555 \n*support the hierarchical interface in @Service  #3251  \n* change the default behavior in `@EnableDubboConfig.multiple()` #3193 \n* inline source code of `spring-context-support` #3192 \n* Simplify externalized configuration of Dubbo Protocol name  #3189 \n\nBugFix：\n \n* update hessian-lite to 2.3.5, fix unnecessary class load #3538 \n* Fix unregister when client destroyed（referenceconfig#destroy) #3502 \n* SPI entires dup by 3 times #3315 \n* fix Consumer throws RpcException after RegistryDirectory notify in high QPS #2016 \n* fix NPE in @Reference when using Junit to test dubbo service #3429 \n* fix consumer always catch java.lang.reflect.UndeclaredThrowableException for any exception throws in provider  #3386 \n* fix the priority of `DubboConfigConfigurationSelector ` #2897 \n* fix `@Rerefence#parameters()` not work #2301 \n\n## 2.6.5\n\nEnhancements / Features：    \n\n- Reactor the generation rule for @Service Bean name [#2235](https://github.com/apache/dubbo/issues/2235) \n- Introduce a new Spring ApplicationEvent for ServiceBean exporting [#2251](https://github.com/apache/dubbo/issues/2251) \n- [Enhancement] the algorithm of load issue on Windows. [#1641](https://github.com/apache/dubbo/issues/1641)\n- add javadoc to dubbo-all module good first issue. [#2600](https://github.com/apache/dubbo/issues/2600) \n- [Enhancement] Reactor the generation rule for @Service Bean name type/enhancement [#2235](https://github.com/apache/dubbo/issues/2235) \n- Optimize LeastActiveLoadBalance and add weight test case. [#2540](https://github.com/apache/dubbo/issues/2540) \n- Smooth Round Robin selection. [#2578](https://github.com/apache/dubbo/issues/2578) [#2647](https://github.com/apache/dubbo/pull/2647) \n- [Enhancement] Resolve the placeholders for sub-properties. [#2297](https://github.com/apache/dubbo/issues/2297) \n- Add ability to turn off SPI auto injection, special support for generic Object type injection. [#2681](https://github.com/apache/dubbo/pull/2681)\n\n\nBugfixes：    \n\n- @Service(register=false) is not work. [#2063](https://github.com/apache/dubbo/issues/2063) \n- Our customized serialization id exceeds the maximum limit, now it cannot work on 2.6.2 anymore. [#1903](https://github.com/apache/dubbo/issues/1903) \n- Consumer throws RpcException after RegistryDirectory notify in high QPS. [#2016](https://github.com/apache/dubbo/issues/2016)   \n- Annotation @Reference can't support to export a service with a sync one and an async one . [#2194](https://github.com/apache/dubbo/issues/2194) \n- `org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#generateReferenceBeanCacheKey` has a bug. [#2522](https://github.com/apache/dubbo/issues/2522) \n- 2.6.x Spring Event & Bugfix. [#2256](https://github.com/apache/dubbo/issues/2256) \n- Fix incorrect descriptions for dubbo-serialization module. [#2665](https://github.com/apache/dubbo/issues/2665) \n- A empty directory dubbo-config/dubbo-config-spring/src/test/resources/work after package source tgz. [#2560](https://github.com/apache/dubbo/issues/2560)\n- Fixed 2.6.x branch a minor issue with doConnect not using getConnectTimeout() in NettyClient.  (*No issue*). [#2622](https://github.com/apache/dubbo/pull/2622) \n- Bean name of @service annotated class does not resolve placeholder. [#1755](https://github.com/apache/dubbo/issues/1755) \n\n\n\nIssues and Pull Requests, check [milestone-2.6.5](https://github.com/apache/dubbo/milestone/21).\n\n## 2.6.4\n\nEnhancements / Features\n\n- Support access Redis with password, [#2146](https://github.com/apache/dubbo/pull/2146)\n- Support char array for GenericService, [#2137](https://github.com/apache/dubbo/pull/2137)\n- Direct return when the server goes down abnormally, [#2451](https://github.com/apache/dubbo/pull/2451)\n- Add log for trouble-shooting when qos start failed, [#2455](https://github.com/apache/dubbo/pull/2455)\n- PojoUtil support subclasses of java.util.Date, [#2502](https://github.com/apache/dubbo/pull/2502)\n- Add ip and application name for MonitorService, [#2166](https://github.com/apache/dubbo/pull/2166)\n- New ASCII logo, [#2402](https://github.com/apache/dubbo/pull/2402)\n\nBugfixes\n\n- Change consumer retries default value from 0 to 2, [#2303](https://github.com/apache/dubbo/pull/2303)\n- Fix the problem that attachment is lost when retry, [#2024](https://github.com/apache/dubbo/pull/2024)\n- Fix NPE when telnet get a null parameter, [#2453](https://github.com/apache/dubbo/pull/2453)\n\nUT stability\n\n- Improve the stability by changing different port, setting timeout to 3000ms, [#2501](https://github.com/apache/dubbo/pull/2501)\n\nIssues and Pull Requests, check [milestone-2.6.4](https://github.com/apache/dubbo/milestone/19).\n\n## 2.6.3\n\nEnhancements / Features\n\n- Support implicit delivery of attachments from provider to consumer, #889\n- Support inject Spring bean to SPI by bean type, #1837\n- Add generic invoke and attachments support for http&hessian protocol, #1827\n- Get the real methodname to support consistenthash for generic invoke, #1872\n- Remove validation key from provider url on Consumer side, config depedently, #1386\n- Introducing the Bootstrap module as a unified entry for Dubbo startup and resource destruction, #1820\n- Open TCP_NODELAY on Netty 3, #1746\n- Support specify proxy type on provider side, #1873\n- Support dbindex in redis, #1831\n- Upgrade tomcat to 8.5.31, #1781\n\nBugfixes\n\n- ExecutionDispatcher meet with user docs, #1089\n- Remove side effects of Dubbo custom loggers on Netty logger, #1717\n- Fix isShutdown() judge of Dubbo biz threadpool always return true, #1426\n- Selection of invoker node under the critical condition of only two nodes, #1759\n- Listener cann't be removed during unsubscribe when use ZK as registry, #1792\n- URL parsing problem when user filed contains '@',  #1808\n- Check null in CacheFilter to avoid NPE, #1828\n- Fix potential deadlock in DubboProtocol, #1836\n- Restore the bug that attachment has not been updated in the RpcContext when the Dubbo built-in retry mechanism is triggered, #1453\n- Some other small bugfixes\n\nPerformance Tuning\n\n- ChannelState branch prediction optimization. #1643\n- Optimize AtomicPositiveInteger, less memory and compute cost, #348\n- Introduce embedded Threadlocal to replace the JDK implementation, #1745\n\nHessian-lite\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at dev@dubbo.apache.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "\n## Contributing to Dubbo\nDubbo is released under the non-restrictive Apache 2.0 licenses and follows a very standard Github development process, using Github tracker for issues and merging pull requests into master. Contributions of all form to this repository is acceptable, as long as it follows the prescribed community guidelines enumerated below.\n\n### Sign the Contributor License Agreement\nBefore we accept a non-trivial patch or pull request (PRs), we will need you to sign the Contributor License Agreement. Signing the contributors' agreement does not grant anyone commits rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. Active contributors may get invited to join the core team that will grant them privileges to merge existing PRs. \n\n### Contact\n\n#### Mailing list\n\nThe mailing list is the recommended way of pursuing a discussion on almost anything related to Dubbo. Please refer to this [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide) for detailed documentation on how to subscribe.\n\n- [dev@dubbo.apache.org](mailto:dev-subscribe@dubbo.apache.org): the developer mailing list where you can ask questions about an issue you may have encountered while working with Dubbo. \n- [commits@dubbo.apache.org](mailto:commits-subscribe@dubbo.apache.org): the commit updates will get broadcasted on this mailing list. You can subscribe to it, should you be interested in following Dubbo's development.\n- [notifications@dubbo.apache.org](mailto:notifications-subscribe@dubbo.apache.org): all the Github [issue](https://github.com/apache/dubbo/issues) updates and [pull request](https://github.com/apache/dubbo/pulls) updates will be sent to this mailing list.\n\n### Reporting issue\n\nPlease follow the [template](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md) for reporting any issues.\n\n### Code Conventions\nOur code style is almost in line with the standard java conventions (Popular IDE's default setting satisfy this), with the following additional restricts:  \n* If there are more than 120 characters in the current line, begin a new line.\n\n* Make sure all new .java files to have a simple Javadoc class comment with at least a @date tag identifying birth, and preferably at least a paragraph on the intended purpose of the class.\n\n* Add the ASF license header comment to all new .java files (copy from existing files in the project)\n\n* Make sure no @author tag gets appended to the file you contribute to as the @author tag is incompatible with Apache. Rest assured, other ways, including CVS, will ensure transparency, fairness in recording your contributions. \n\n* Add some Javadocs and, if you change the namespace, some XSD doc elements.\n\n* Sufficient unit-tests should accompany new feature development or non-trivial bug fixes. \n\n* If no-one else is using your branch, please rebase it against the current master (or another target branch in the main project).\n\n* When writing a commit message, please follow the following conventions: should your commit address an open issue, please add Fixes #XXX at the end of the commit message (where XXX is the issue number).\n\n### Contribution flow\n\nA rough outline of an ideal contributors' workflow is as follows:\n\n* Fork the current repository\n* Create a topic branch from where to base the contribution. Mostly, it's the master branch.\n* Make commits of logical units.\n* Make sure the commit messages are in the proper format (see below).\n* Push changes in a topic branch to your forked repository.\n* Follow the checklist in the [pull request template](https://github.com/apache/dubbo/blob/master/PULL_REQUEST_TEMPLATE.md)\n* Before sending out the pull request, please sync your forked repository with the remote repository to ensure that your PR is elegant, concise. Reference the guide below:\n```\ngit remote add upstream git@github.com:apache/dubbo.git\ngit fetch upstream\ngit rebase upstream/master\ngit checkout -b your_awesome_patch\n... add some work\ngit push origin your_awesome_patch\n```\n* Submit a pull request to apache/dubbo and wait for the reply.\n\nThanks for contributing!\n\n### Code style\n\nWe provide a template file [dubbo_codestyle_for_idea.xml](https://github.com/apache/dubbo/tree/master/codestyle/dubbo_codestyle_for_idea.xml) for IntelliJ idea that you can import it to your workplace. \nIf you use Eclipse, you can use the IntelliJ Idea template for manually configuring your file.\n\n**NOTICE**\n\nIt's critical to set the dubbo_codestyle_for_idea.xml to avoid the failure of your Travis CI builds. Steps to configure the code styles are as follows:\n\n1. Enter `Editor > Code Style`\n2. To manage a code style scheme, in the Code Style page, select the desired scheme from the drop-down list, and click on ![manage profiles](codestyle/manage_profiles.png).\nFrom the drop-down list, select `Import Scheme`, then choose the option `IntelliJ IDEA code style XML` to import the scheme. \n3. In the Scheme field, type the name of the new scheme and press ⏎ to save the changes.\n\n"
  },
  {
    "path": "Jenkinsfile",
    "content": "import groovy.json.JsonSlurper\n\npipeline {\n    agent {\n        node {\n            label 'ubuntu'\n        }\n    }\n\n    options {\n        buildDiscarder(logRotator(daysToKeepStr: '14', artifactNumToKeepStr: '10'))\n    }\n\n    environment {\n        JAVA_HOME = \"${tool 'JDK 1.8 (latest)'}\"\n    }\n\n    tools {\n        maven 'Maven 3 (latest)'\n        jdk 'JDK 1.8 (latest)'\n    }\n\n    triggers {\n        cron '''TZ=Asia/Shanghai\n        H 2,14 * * *'''\n        pollSCM '''TZ=Asia/Shanghai\n        H H/2 * * *'''\n    }\n\n\n    stages {\n        stage('Clone') {\n            steps {\n                checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'CloneOption', noTags: true, reference: '', shallow: true]], gitTool: 'Default', submoduleCfg: [], userRemoteConfigs: [[url: 'https://github.com/apache/dubbo.git']]])\n            }\n        }\n\n        stage('Duplicate deploy check') {\n            steps {\n                script {\n                    def deployedCommitId = sh(returnStdout: true, script: \"curl --silent https://builds.apache.org/job/Apache%20Dubbo/job/${env.JOB_BASE_NAME}/lastSuccessfulBuild/artifact/DEPLOY_COMMIT_ID || true\").trim()\n                    env.DEPLOYED_COMMIT_ID = deployedCommitId\n                    def commitId = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()\n                    env.COMMIT_ID = commitId\n\n                    if (commitId == deployedCommitId) {\n                        env.STATUS_CHECK = \"false\"\n                        println \"Latest deployed commit id is $deployedCommitId, Skip deployment this time\"\n                    } else {\n                        env.STATUS_CHECK = \"true\"\n                        println \"Current commit id hasn't been deployed, continue\"\n                    }\n                }\n            }\n        }\n\n        stage('Commit status check') {\n            when {\n                expression {\n                    return env.STATUS_CHECK == \"true\";\n                }\n            }\n            steps {\n                script {\n                    def commitId = env.COMMIT_ID\n                    println \"Current commit id: $commitId\"\n\n                    def commitStatusJson = sh(script: \"curl --silent https://api.github.com/repos/apache/dubbo/commits/$commitId/status\", returnStdout: true).trim()\n                    println \"Commit status: \\r\\n$commitStatusJson\"\n\n                    def jsonSlurper = new JsonSlurper()\n                    def jsonObject = jsonSlurper.parseText(commitStatusJson)\n\n                    def status = jsonObject.state\n\n                    println \"Current commit status is $status\"\n\n                    if (status == \"success\") {\n                        env.STATUS_CHECK = \"true\"\n                        println \"Continue to deploy snapshot\"\n                    } else {\n                        env.STATUS_CHECK = \"false\"\n                        println \"Current commit status not allow to deploy snapshot\"\n                    }\n                }\n            }\n        }\n\n        stage('Snapshot version check') {\n            when {\n                expression {\n                    return env.STATUS_CHECK == \"true\";\n                }\n            }\n            steps {\n                sh 'env'\n                sh 'java -version'\n                sh './mvnw clean install -pl \"dubbo-dependencies-bom\" && ./mvnw clean install -DskipTests=true && ./mvnw clean validate -Psnapshot-ci-deploy -pl \"dubbo-all\"'\n            }\n        }\n\n        stage('Deploy snapshot') {\n            when {\n                expression {\n                    return env.STATUS_CHECK == \"true\";\n                }\n            }\n            steps {\n                timeout(40) {\n                    sh './mvnw --version'\n                    sh './mvnw clean package deploy -pl dubbo-dependencies-bom && ./mvnw clean source:jar javadoc:jar package deploy -DskipTests=true'\n                }\n            }\n        }\n\n        stage('Save deployed commit id') {\n            steps {\n                script {\n                    if (env.STATUS_CHECK != \"true\") {\n                        println \"Not pass status check\"\n                        env.COMMIT_ID = env.DEPLOYED_COMMIT_ID\n                    }\n                }\n                writeFile file: 'DEPLOY_COMMIT_ID', text: \"${env.COMMIT_ID}\"\n                archiveArtifacts 'DEPLOY_COMMIT_ID'\n            }\n        }\n    }\n\n    post {\n        failure {\n            mail bcc: '', body: '''Project: ${env.JOB_NAME}\n            Build Number: ${env.BUILD_NUMBER}\n            URL: ${env.BUILD_URL}''', cc: '', from: '', replyTo: '', subject: 'Apache Dubbo snapshot deployment fail', to: 'dev@dubbo.apache.org'\n        }\n    }\n\n}\n"
  },
  {
    "path": "Jenkinsfile.sonar",
    "content": "/*\n *\n *  Licensed to the Apache Software Foundation (ASF) under one or more\n *  contributor license agreements.  See the NOTICE file distributed with\n *  this work for additional information regarding copyright ownership.\n *  The ASF licenses this file to You under the Apache License, Version 2.0\n *  (the \"License\"); you may not use this file except in compliance with\n *  the License.  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\npipeline {\n    agent {\n        label 'ubuntu'\n    }\n\n    tools {\n        maven 'maven_3_latest'\n        jdk 'jdk_11_latest'\n    }\n\n    stages {\n        stage('Code Quality') {\n            steps {\n                echo 'Checking Code Quality on SonarCloud'\n                script {\n                    // Main parameters\n                    def sonarcloudParams=\"\"\n                    if ( env.BRANCH_NAME.startsWith(\"PR-\") ) {\n                        // this is a pull request\n                        withCredentials([string(credentialsId: 'sonarcloud-token', variable: 'SONAR_TOKEN')]) {\n                            sh './mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean verify sonar:sonar -Dmaven.test.skip=true -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=apache -Dsonar.projectKey=apache_dubbo -Dsonar.coverage.jacoco.xmlReportPaths=dubbo-test/dubbo-dependencies-all/target/site/jacoco-aggregate/jacoco.xml -Dsonar.pullrequest.branch=${CHANGE_BRANCH} -Dsonar.pullrequest.base=${CHANGE_TARGET} -Dsonar.pullrequest.key=${CHANGE_ID} -Dsonar.login=${SONAR_TOKEN}'\n                        }\n                    } else {\n                        // this is just a branch\n                        withCredentials([string(credentialsId: 'sonarcloud-token', variable: 'SONAR_TOKEN')]) {\n                            sh './mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean verify sonar:sonar -Dmaven.test.skip=true -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=apache -Dsonar.projectKey=apache_dubbo -Dsonar.coverage.jacoco.xmlReportPaths=dubbo-test/dubbo-dependencies-all/target/site/jacoco-aggregate/jacoco.xml -Dsonar.branch.name=${BRANCH_NAME} -Dsonar.login=${SONAR_TOKEN}'\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\nApache Dubbo Submodules:\n\nApache Dubbo includes a number of submodules with separate copyright notices\nand license terms. Your use of these submodules is subject to the terms and\nconditions of the following licenses.\n\nFor the package org.apache.dubbo.common.threadlocal and org.apache.dubbo.common.timer:\n\nThis product contains a modified portion of 'Netty', an event-driven asynchronous network application framework also\n under a \"Apache License 2.0\" license, see https://github.com/netty/netty/blob/4.1/LICENSE.txt:\n\n * io.netty.util.concurrent.FastThreadLocal\n * io.netty.util.internal.InternalThreadLocalMap\n * io.netty.util.Timer\n * io.netty.util.TimerTask\n * io.netty.util.Timeout\n * io.netty.util.HashedWheelTimer\n\nFor the org.apache.dubbo.common.utils.CIDRUtils :\n\nThis product contains a modified portion of 'edazdarevic.commons.net.CIDRUtils' published at\nhttps://github.com/edazdarevic/CIDRUtils. The project is licensed under a MIT License:\n    * The MIT License\n    *\n    * Copyright (c) 2013 Edin Dazdarevic (edin.dazdarevic@gmail.com)\n    * Permission is hereby granted, free of charge, to any person obtaining a copy\n    * of this software and associated documentation files (the \"Software\"), to deal\n    * in the Software without restriction, including without limitation the rights\n    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n    * copies of the Software, and to permit persons to whom the Software is\n    * furnished to do so, subject to the following conditions:\n    * The above copyright notice and this permission notice shall be included in\n    * all copies or substantial portions of the Software.\n    * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n    * THE SOFTWARE.\n\nFor the file org.apache.dubbo.common.utils.Utf8Utils.java:\n\nThis product contains a portion of the Protocol Buffers project, which is published at\nhttps://developers.google.com/protocol-buffers/ and is licensed under the following License:\n\n    Copyright 2008 Google Inc.  All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are\n    met:\n\n        * Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n        * Redistributions in binary form must reproduce the above\n    copyright notice, this list of conditions and the following disclaimer\n    in the documentation and/or other materials provided with the\n    distribution.\n        * Neither the name of Google Inc. nor the names of its\n    contributors may be used to endorse or promote products derived from\n    this software without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n    \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n    Code generated by the Protocol Buffer compiler is owned by the owner\n    of the input file used when generating it.  This code is not\n    standalone and requires a support library to be linked with it.  This\n    support library is itself covered by the above license.\n\nFor the ca.proto in dubbo-registry-xds:\n\nThis product contains a modified portion of 'Istio', an open platform to connect, manage, and secure microservices also\n under a \"Apache License 2.0\" license, see https://github.com/istio/api/blob/master/LICENSE:\n\n * security/v1alpha1/ca.proto\n\nFor the file dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/swagger-ui/index.html:\n\nUnder a \"Apache License 2.0\" license, see https://github.com/swagger-api/swagger-ui/blob/master/LICENSE\n\nFor the file dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/redoc/index.html:\n\nUnder a \"MIT License\" license, see https://github.com/Redocly/redoc/blob/main/LICENSE\n"
  },
  {
    "path": "NOTICE",
    "content": "Apache Dubbo\nCopyright 2018-2024 The Apache Software Foundation\n\nThis product includes software developed at\nThe Apache Software Foundation (http://www.apache.org/).\n\nThis product contains code form the Netty Project:\n\nThe Netty Project\n=================\nPlease visit the Netty web site for more information:\n  * http://netty.io/\n\nCopyright 2014 The Netty Project\n\nThis product contains code form the t-digest Project:\nThe code for the t-digest was originally authored by Ted Dunning\nAdrien Grand contributed the heart of the AVLTreeDigest (https://github.com/jpountz)\n\nThis product contains the following code copied from Maven Protocol Buffers Plugin:\ndubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/DubboProtocCompilerMojo.java\n\nMaven Protocol Buffers Plugin\n=============================\nCopyright (c) 2016 Maven Protocol Buffers Plugin Authors. All rights reserved.\n\nThis product contains the following code copied from grpc-java-contrib:\ndubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/utils/ProtoTypeMap.java\nSome portions of this file Copyright (c) 2019, Salesforce.com, Inc. and licensed under the BSD 3-Clause License\n\ngrpc-java-contrib\n====================\nCopyright (c) 2019, Salesforce.com, Inc.\nAll rights reserved.\n\n\n\n\n"
  },
  {
    "path": "README.md",
    "content": "\n# Apache Dubbo Project\n\n[![Build and Test For PR](https://github.com/apache/dubbo/actions/workflows/build-and-test-pr.yml/badge.svg)](https://github.com/apache/dubbo/actions/workflows/build-and-test-pr.yml)\n[![Codecov](https://codecov.io/gh/apache/dubbo/branch/3.3/graph/badge.svg)](https://codecov.io/gh/apache/dubbo)\n[![Maven](https://img.shields.io/github/v/release/apache/dubbo.svg?sort=semver)](https://github.com/apache/dubbo/releases)\n[![License](https://img.shields.io/github/license/apache/dubbo.svg)](https://github.com/apache/dubbo/blob/3.3/LICENSE)\n[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/apache/dubbo.svg)](http://isitmaintained.com/project/apache/dubbo)\n[![Percentage of issues still open](http://isitmaintained.com/badge/open/apache/dubbo.svg)](http://isitmaintained.com/project/apache/dubbo)\n\nApache Dubbo is a powerful and user-friendly Web and RPC framework. It supports multiple language implementations such as Java, [Go](https://github.com/apache/dubbo-go), [Python](https://github.com/dubbo/py-client-for-apache-dubbo), [PHP](https://github.com/apache/dubbo-php-framework), [Erlang](https://github.com/apache/dubbo-erlang), [Rust](https://github.com/apache/dubbo-rust), and [Node.js/Web](https://github.com/apache/dubbo-js).\n\nDubbo provides solutions for communication, service discovery, traffic management, observability, security, tooling, and best practices for building enterprise-grade microservices.\n\n> 🚀 We're collecting user info to improve Dubbo. Help us out here: [Who's using Dubbo](https://github.com/apache/dubbo/discussions/13842)\n\n---\n\n## 🧱 Architecture\n\n![Architecture](https://dubbo.apache.org/imgs/architecture.png)\n\n- Communication between consumers and providers is done via RPC protocols like Triple, TCP, REST, etc.\n- Consumers dynamically discover provider instances from registries (e.g., Zookeeper, Nacos) and manage traffic using defined strategies.\n- Built-in support for dynamic config, metrics, tracing, security, and a visualized console.\n\n---\n\n## 🚀 Getting Started\n\n### 📦 Lightweight RPC API\n\nStart quickly with our [5-minute guide](https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/tasks/framework/lightweight-rpc/)\n\nDubbo allows you to build RPC services using a minimal codebase and a lightweight SDK. It supports protocols like:\n\n- [Triple (gRPC-compatible)](https://dubbo.apache.org/zh-cn/overview/reference/protocols/triple/)\n- Dubbo2 (TCP)\n- REST\n- Custom protocols\n\n### 🌱 Microservices with Spring Boot\n\nKickstart your project using [Spring Boot Starter](https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/tasks/develop/springboot/).\n\nUsing just a dependency and a YAML config, you can unlock the full power of Dubbo: service discovery, observability, tracing, etc.\n\n➡️ Learn how to [deploy](https://dubbo.apache.org/zh-cn/overview/tasks/deploy/), [monitor](https://dubbo.apache.org/zh-cn/overview/tasks/observability/), and [manage traffic](https://dubbo.apache.org/zh-cn/overview/tasks/traffic-management/) for Dubbo services.\n\n---\n\n## 🛠️ More Features\n\nExplore more through our hands-on tasks:\n\n- [Launch a Dubbo project](https://dubbo.apache.org/zh-cn/overview/tasks/develop/template/)\n- [RPC protocols](https://dubbo.apache.org/zh-cn/overview/core-features/protocols/)\n- [Traffic management](https://dubbo.apache.org/zh-cn/overview/core-features/traffic/)\n- [Service discovery](https://dubbo.apache.org/zh-cn/overview/core-features/service-discovery/)\n- [Observability](https://dubbo.apache.org/zh-cn/overview/core-features/observability/)\n- [Extensibility](https://dubbo.apache.org/zh-cn/overview/core-features/extensibility/)\n- [Security](https://dubbo.apache.org/zh-cn/overview/core-features/security/)\n- [Visualized Console](https://dubbo.apache.org/zh-cn/overview/reference/admin/)\n- [Kubernetes & Service Mesh](https://dubbo.apache.org/zh-cn/overview/core-features/service-mesh/)\n\n---\n\n## 📦 Which Dubbo Version Should I Use?\n\n### Dubbo3\n\n## 📦 Version Compatibility\n\n| Version            | JDK Support | Dependencies                                                                                              | Highlights                                                                                                     |\n|--------------------|-------------|-----------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|\n| **3.3.7-SNAPSHOT** | 1.8 – 25    | Coming Soon                                                                                               | ✅ JDK 25 Support\n| **3.3.6**          | 1.8 – 21    | [View Dependencies](https://github.com/apache/dubbo/blob/dubbo-3.3.6/dubbo-dependencies-bom/pom.xml#L92)  | ✅ Mutiny Reactive Support <br> ✅ Affinity Router <br> ✅ Method-level TPS Limiting <br> ✅ Spring 6 Security Plugin <br> ✅ Enhanced Environment Variable Config |\n| **3.3.5**          | 1.8 – 21    | [View Dependencies](https://github.com/apache/dubbo/blob/dubbo-3.3.5/dubbo-dependencies-bom/pom.xml#L92)  | ✅ Actively Maintained <br> ✅ Triple Protocol (gRPC/cURL) <br> ✅ REST Support <br> ✅ Spring Boot Starters      |\n| **3.2.16**         | 1.8 – 17    | [View Dependencies](https://github.com/apache/dubbo/blob/dubbo-3.2.5/dubbo-dependencies-bom/pom.xml#L94)  | ✅ Actively Maintained <br> ✅ Metrics & Tracing <br> ✅ Thread Pool Isolation <br> ✅ +30% Performance <br> ✅ Native Image Support |\n| **3.1.11**         | 1.8 – 17    | [View Dependencies](https://github.com/apache/dubbo/blob/dubbo-3.2.11/dubbo-dependencies-bom/pom.xml#L90) | ⚠️ Stable, but Not Actively Maintained                                                                         |\n\n### Dubbo2\n\n| Version     | JDK       | Dependencies                                                                                          | Description |\n|-------------|-----------|--------------------------------------------------------------------------------------------------------|-------------|\n| 2.7.23      | 1.8       | [dependency list](https://github.com/apache/dubbo/blob/dubbo-2.7.23/dubbo-dependencies-bom/pom.xml#L92) | ❌ EOL       |\n| 2.6.x, 2.5.x| 1.6 - 1.7 | [dependency list](https://github.com/apache/dubbo/blob/dubbo-2.6.12/dependencies-bom/pom.xml#L90)       | ❌ EOL       |\n\n---\n\n## 🤝 Contributing\n\nSee our [CONTRIBUTING](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md) guide to get started!\n\n### 🔁 Community Collaboration\n\n- **Issues**: For bugs or tasks – [GitHub Issues](https://github.com/apache/dubbo/issues)\n- **Discussions**: For questions, ideas – [GitHub Discussions](https://github.com/apache/dubbo/discussions)\n- **PRs**: For merging your contributions – [GitHub Pull Requests](https://github.com/apache/dubbo/pulls)\n- **Project Board**: [Dubbo Project Board](https://github.com/orgs/apache/projects/337)\n\n### 💡 How You Can Help\n\n- Check out \"help wanted\" issues: [Project Board](https://github.com/orgs/apache/projects/337)\n- Join [mailing list discussions](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide)\n- Engage in [discussions](https://github.com/apache/dubbo/discussions)\n- Fix [bugs](https://github.com/apache/dubbo/issues) or review [pull requests](https://github.com/apache/dubbo/pulls)\n- Enhance the [website](https://github.com/apache/dubbo-website)\n- Improve [dubbo-admin](https://github.com/apache/dubbo-admin)\n- Contribute to the [ecosystem](https://github.com/apache/?q=dubbo&type=all&language=&sort=)\n\nIf you're interested in contributing, email us at [dev@dubbo.apache.org](mailto:dev@dubbo.apache.org).\n\n---\n\n## 🐞 Reporting Issues\n\nPlease use our [issue template](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md) when reporting bugs.\n\n---\n\n## 🔐 Reporting Security Vulnerabilities\n\nPlease report vulnerabilities **privately** to [security@dubbo.apache.org](mailto:security@dubbo.apache.org).\n\n---\n\n## 📬 Contact\n\n- **WeChat**: `apachedubbo`\n- **DingTalk**: Group ID `37290003945`\n- **Mailing List**: [Contact Guide](https://dubbo.apache.org/zh-cn/contact/)\n- **Twitter**: [@ApacheDubbo](https://twitter.com/ApacheDubbo)\n- **Security**: [security@dubbo.apache.org](mailto:security@dubbo.apache.org)\n\n---\n\n## 📄 License\n\nApache Dubbo is licensed under the [Apache License 2.0](https://github.com/apache/dubbo/blob/3.3/LICENSE).\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nBelow is a table that shows versions that we accept security fixes.\n\n| Version | Supported          |\n|---------| ------------------ |\n| 3.3.x   | :white_check_mark: |\n| 3.2.x   | :white_check_mark: |\n| 3.1.x   | :white_check_mark: |\n| 3.0.x   | :x: |\n| 2.7.x   | :x: |\n| 2.6.x   | :x: |\n| 2.5.x   | :x: |\n\n## Reporting a Vulnerability\n\nThe Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its software projects. Apache Dubbo is highly sensitive and forthcoming to issues pertaining to its features and functionality.\n\nIf you have apprehensions regarding Dubbo's security or you discover vulnerability or potential threat, don’t hesitate to get in touch with the Apache Dubbo Security Team by dropping a mail at security@dubbo.apache.org. In the email, specify the description of the issue or potential threat. You are also urged to recommend the way to reproduce and replicate the issue. The Dubbo community will get back to you after assessing and analysing the findings.\n\nPLEASE PAY ATTENTION to report the security issue on the security email before disclosing it on public domain.\n\n## Vulnerability Handling\n\nAn overview of the vulnerability handling process is:\n\n* The reporter reports the vulnerability privately to Apache.\n* The appropriate project's security team works privately with the reporter to resolve the vulnerability.\n* A new release of the Apache product concerned is made that includes the fix.\n* The vulnerability is publicly announced.\n\nA more detailed description of the process can be found [here](https://www.apache.org/security/committers.html).\n"
  },
  {
    "path": "build",
    "content": "#!/bin/sh\n\n#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nset -eu\n\ncd \"$(dirname \"$0\")\"\n\nexport MAVEN_OPTS=\"\\\n-Xms2g \\\n-Xmx2g \\\n-XX:+UseG1GC \\\n-XX:InitiatingHeapOccupancyPercent=45 \\\n-XX:+UseStringDeduplication \\\n-XX:-TieredCompilation \\\n-XX:TieredStopAtLevel=1 \\\n-Dmaven.build.cache.enabled=true \\\n-Dmaven.build.cache.lazyRestore=true \\\n-Dmaven.compiler.useIncrementalCompilation=false \\\n-Dmaven.test.skip=true \\\n-Dcheckstyle.skip=true \\\n-Dcheckstyle_unix.skip=true \\\n-Drat.skip=true \\\n-Dmaven.javadoc.skip=true\n\"\n\nCMD=\"./mvnw -e --batch-mode --no-snapshot-updates --fail-fast -T 2C\"\nARGS=\"\"\nMODULES=\"\"\nPROFILES=\"sources,skip-spotless\"\nDEFAULT_MODULES=\"dubbo-distribution/dubbo-all,dubbo-spring-boot/dubbo-spring-boot-starter\"\n\nprint_help() {\n    echo \"Usage: $0 [options]\"\n    echo \"Fast local compilation with incremental build and caching\"\n    echo \"Options:\"\n    echo \"  -c    Execute clean goal (removes build artifacts)\"\n    echo \"  -p    Execute compile goal (compiles the source code)\"\n    echo \"  -i    Execute install goal (builds and installs the project)\"\n    echo \"  -t    Execute test goal (runs the tests)\"\n    echo \"  -s    Execute spotless:apply (format the code)\"\n    echo \"  -d    Execute dependency:tree (displays the dependency tree)\"\n    echo \"  -m    Specify modules, default is $DEFAULT_MODULES\"\n    echo \"  -f    Specify profiles, default is $PROFILES\"\n    echo \"  -h    Display this help message\"\n    echo \"\"\n    echo \"Examples:\"\n    echo \"  $0                        Execute install goal compilation\"\n    echo \"  $0 -m                     Execute a minimal compilation\"\n    echo \"  $0 -ci                    Execute clean, install goals compilation\"\n    echo \"  $0 -s                     Execute spotless:apply\"\n    echo \"  $0 -d                     Display the dependency tree\"\n    echo \"  $0 -t -m dubbo-config     Execute test goal for dubbo-config module\"\n    echo \"  $0 -cp -m dubbo-common    Execute clean, compile the dubbo-common module\"\n    exit 0\n}\n\nwhile getopts \":cpitstdm:f:h\" opt; do\n  case $opt in\n    c)\n      ARGS=\"$ARGS clean\"\n      ;;\n    p)\n      ARGS=\"$ARGS compile\"\n      ;;\n    i)\n      ARGS=\"$ARGS install\"\n      ;;\n    t)\n      ARGS=\"$ARGS test\"\n      export MAVEN_OPTS=$(echo \"$MAVEN_OPTS\" | sed 's/-Dmaven\\.test\\.skip=true/-Dmaven.test.skip=false/')\n      ;;\n    s)\n      ARGS=\"$ARGS spotless:apply\"\n      PROFILES=\"sources\"\n      ;;\n    d)\n      ARGS=\"$ARGS dependency:tree\"\n      ;;\n    m)\n      MODULES=\" -pl $OPTARG -am\"\n      ;;\n    f)\n      PROFILES=\"$OPTARG\"\n      ;;\n    h)\n      print_help\n      ;;\n    *)\n      if [ \"$OPTARG\" = \"m\" ]; then\n        MODULES=\" -pl $DEFAULT_MODULES -am\"\n      else\n        ARGS=\"$ARGS $@\"\n      fi\n      ;;\n  esac\ndone\n\nif [ -z \"$ARGS\" ] ; then\n  ARGS=\" install\"\nfi\n\nset -x\n$CMD$ARGS$MODULES -P $PROFILES\n"
  },
  {
    "path": "build.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one or more\n@REM contributor license agreements.  See the NOTICE file distributed with\n@REM this work for additional information regarding copyright ownership.\n@REM The ASF licenses this file to You under the Apache License, Version 2.0\n@REM (the \"License\"); you may not use this file except in compliance with\n@REM the License.  You may obtain a copy of the License at\n@REM\n@REM     http://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing, software\n@REM distributed under the License is distributed on an \"AS IS\" BASIS,\n@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@REM See the License for the specific language governing permissions and\n@REM limitations under the License.\n@REM ----------------------------------------------------------------------------\n\n@echo off\nsetlocal enabledelayedexpansion\n\nset MAVEN_OPTS=^\n-Xms2g ^\n-Xmx2g ^\n-XX:+UseG1GC ^\n-XX:InitiatingHeapOccupancyPercent=45 ^\n-XX:+UseStringDeduplication ^\n-XX:-TieredCompilation ^\n-XX:TieredStopAtLevel=1 ^\n-Dmaven.build.cache.enabled=true ^\n-Dmaven.build.cache.lazyRestore=true ^\n-Dmaven.compiler.useIncrementalCompilation=false ^\n-Dcheckstyle.skip=true ^\n-Dcheckstyle_unix.skip=true ^\n-Drat.skip=true ^\n-Dmaven.javadoc.skip=true\n\nset CMD=mvnw.cmd -e --batch-mode --no-snapshot-updates --fail-fast -T 2C\nset ARGS=\nset MODULES=\nset PROFILES=sources,skip-spotless\nset DEFAULT_MODULES=dubbo-distribution/dubbo-all,dubbo-spring-boot/dubbo-spring-boot-starter\nset TEST_SKIP=true\n\ngoto parse_args\n\n:print_help\necho Usage: %~n0 [options]\necho Fast local compilation with incremental build and caching\necho Options:\necho   -c    Execute clean goal (removes build artifacts)\necho   -p    Execute compile goal (compiles the source code)\necho   -i    Execute install goal (builds and installs the project)\necho   -t    Execute test goal (runs the tests)\necho   -s    Execute spotless:apply (format the code)\necho   -d    Execute dependency:tree (displays the dependency tree)\necho   -m    Specify modules, default is %DEFAULT_MODULES%\necho   -f    Specify profiles, default is %PROFILES%\necho   -h    Display this help message\necho.\necho Examples:\necho   %~n0                          Execute install goal compilation\necho   %~n0 -m                       Execute a minimal compilation\necho   %~n0 -c -i                    Execute clean, install goals compilation\necho   %~n0 -s                       Execute spotless:apply\necho   %~n0 -d                       Display the dependency tree\necho   %~n0 -t -m dubbo-config       Execute test goal for dubbo-config module\necho   %~n0 -c -p -m dubbo-common    Execute clean, compile the dubbo-common module\nexit /b\n\n:parse_args\nset ARG=%~1\nif \"%ARG%\"==\"\" goto check_args\nif \"%ARG%\"==\"-c\" (\n    set ARGS=%ARGS% clean\n) else if \"%ARG%\"==\"-p\" (\n    set ARGS=%ARGS% compile\n) else if \"%ARG%\"==\"-i\" (\n    set ARGS=%ARGS% install\n) else if \"%ARG%\"==\"-t\" (\n    set ARGS=%ARGS% test\n    set TEST_SKIP=false\n) else if \"%ARG%\"==\"-s\" (\n    set ARGS=%ARGS% spotless:apply\n    set PROFILES=sources\n) else if \"%ARG%\"==\"-d\" (\n    set ARGS=%ARGS% dependency:tree\n) else if \"%ARG%\"==\"-m\" (\n    if \"%~2\"==\"\" (\n        set MODULES= -pl %DEFAULT_MODULES% -am\n    ) else (\n        set MODULES= -pl %~2 -am\n        shift\n    )\n) else if \"%ARG%\"==\"-f\" (\n    set PROFILES=%~2\n    shift\n) else if \"%ARG%\"==\"-h\" (\n    goto print_help\n) else (\n    set ARGS=%ARGS% %ARG%\n)\n\nshift\ngoto parse_args\n\n:check_args\nif \"%TEST_SKIP%\"==\"true\" (\n    set MAVEN_OPTS=%MAVEN_OPTS% -Dmaven.test.skip=true\n)\nif \"%ARGS%\"==\"\" (\n    set ARGS= install\n)\n\n@echo on\n%CMD%%ARGS%%MODULES% -P %PROFILES%\n\nendlocal\n"
  },
  {
    "path": "codecov.yml",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\ncodecov:\n  require_ci_to_pass: false\n  notify:\n    wait_for_ci: false\ncoverage:\n  status:\n    # pull-requests only\n    patch:\n      default:\n        threshold: 0.1%\nignore:\n  - \"**/aot/**/*\"\n  - \"dubbo-demo/**/*\"\n  - \"dubbo-compiler/**/*\"\n  - \"dubbo-test/**/*\"\n  - \"dubbo-compatible/**/*\"\n  - \"dubbo-native/**/*\"\n  - \"dubbo-maven-plugin/**/*\"\n"
  },
  {
    "path": "codestyle/checkstyle-suppressions.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE suppressions PUBLIC\n        \"-//Puppy Crawl//DTD Suppressions 1.1//EN\"\n        \"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd\">\n<suppressions>\n    <suppress files=\"[\\\\/]src[\\\\/]main[\\\\/]java[\\\\/]com[\\\\/]alibaba[\\\\/]com[\\\\/]caucho[\\\\/]hessian\" checks=\".*\"/>\n    <suppress files=\"[\\\\/]build[\\\\/]generated[\\\\/]source[\\\\/]proto\" checks=\".*\"/>\n    <suppress files=\"[\\\\/]target[\\\\/]generated-sources[\\\\/]protobuf\" checks=\".*\"/>\n    <suppress files=\"Yylex\\.java\" checks=\"AvoidEscapedUnicodeCharacters\"/>\n</suppressions>\n"
  },
  {
    "path": "codestyle/checkstyle.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n        \"-//Puppy Crawl//DTD Check Configuration 1.3//EN\"\n        \"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd\">\n\n<module name=\"Checker\">\n    <property name=\"charset\" value=\"UTF-8\"/>\n    <property name=\"fileExtensions\" value=\"java\"/>\n\n    <module name=\"Header\">\n        <property name=\"headerFile\" value=\"/checkstyle-header.txt\"/>\n        <property name=\"fileExtensions\" value=\"java\"/>\n    </module>\n\n    <module name=\"FileTabCharacter\">\n        <property name=\"fileExtensions\" value=\"java,xml\"/>\n    </module>\n\n    <!-- TreeWalker Checks -->\n    <module name=\"TreeWalker\">\n        <module name=\"SuppressWarningsHolder\"/>\n\n        <module name=\"AvoidStarImport\"/>\n        <module name=\"AvoidEscapedUnicodeCharacters\">\n            <property name=\"allowEscapesForControlCharacters\" value=\"true\"/>\n            <property name=\"allowByTailComment\" value=\"true\"/>\n            <property name=\"allowNonPrintableEscapes\" value=\"true\"/>\n        </module>\n        <module name=\"NoLineWrap\"/>\n        <module name=\"OuterTypeFilename\"/>\n        <module name=\"UnusedImports\"/>\n        <module name=\"RedundantImport\"/>\n\n        <module name=\"EqualsHashCode\"/>\n\n        <!--<module name=\"CustomImportOrder\">-->\n        <!--<property name=\"specialImportsRegExp\" value=\"org.apache.dubbo.*\"/>-->\n        <!--<property name=\"sortImportsInGroupAlphabetically\" value=\"false\"/>-->\n        <!--<property name=\"customImportOrderRules\" value=\"SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE###STATIC\"/>-->\n        <!--</module>-->\n    </module>\n</module>\n"
  },
  {
    "path": "codestyle/checkstyle_unix.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n        \"-//Puppy Crawl//DTD Check Configuration 1.3//EN\"\n        \"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd\">\n\n<module name=\"Checker\">\n    <module name=\"NewlineAtEndOfFile\">\n        <property name=\"lineSeparator\" value=\"lf\" />\n    </module>\n</module>\n"
  },
  {
    "path": "codestyle/dubbo_codestyle_for_idea.xml",
    "content": "<code_scheme name=\"dubbo_codestyle\">\n    <option name=\"CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND\" value=\"99\"/>\n    <option name=\"NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND\" value=\"99\"/>\n    <option name=\"IMPORT_LAYOUT_TABLE\">\n        <value>\n            <package name=\"org.apache.dubbo\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"javax\" withSubpackages=\"true\" static=\"false\"/>\n            <package name=\"java\" withSubpackages=\"true\" static=\"false\"/>\n            <emptyLine/>\n            <package name=\"\" withSubpackages=\"true\" static=\"true\"/>\n        </value>\n    </option>\n</code_scheme>"
  },
  {
    "path": "dubbo-cluster/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-cluster</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The cluster module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n    <nashorn-core.version>15.7</nashorn-core.version>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.yaml</groupId>\n      <artifactId>snakeyaml</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-injvm</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-fastjson2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-registry</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>compile</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-tracing-integration-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <profiles>\n    <!--\n            https://github.com/openjdk/nashorn\n            Nashorn used to be part of the JDK until Java 14.\n            This project provides a standalone version of Nashorn suitable for use with Java 11 and later.\n        -->\n    <profile>\n      <id>nashorn-jdk11</id>\n      <activation>\n        <jdk>[11,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.openjdk.nashorn</groupId>\n          <artifactId>nashorn-core</artifactId>\n          <version>${nashorn-core.version}</version>\n          <scope>test</scope>\n        </dependency>\n      </dependencies>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/registry/AddressListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\nimport java.util.List;\n\n@SPI(scope = ExtensionScope.MODULE)\npublic interface AddressListener {\n\n    /**\n     * processing when receiving the address list\n     *\n     * @param addresses         provider address list\n     * @param consumerUrl\n     * @param registryDirectory\n     */\n    List<URL> notify(List<URL> addresses, URL consumerUrl, Directory registryDirectory);\n\n    default void destroy(URL consumerUrl, Directory registryDirectory) {}\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/CacheableRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * If you want to provide a router implementation based on design of v2.7.0, please extend from this abstract class.\n * For 2.6.x style router, please implement and use RouterFactory directly.\n */\npublic abstract class CacheableRouterFactory implements RouterFactory {\n    private ConcurrentMap<String, Router> routerMap = new ConcurrentHashMap<>();\n\n    @Override\n    public Router getRouter(URL url) {\n        return ConcurrentHashMapUtils.computeIfAbsent(routerMap, url.getServiceKey(), k -> createRouter(url));\n    }\n\n    protected abstract Router createRouter(URL url);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\n/**\n * Cluster. (SPI, Singleton, ThreadSafe)\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Computer_cluster\">Cluster</a>\n * <a href=\"http://en.wikipedia.org/wiki/Fault-tolerant_system\">Fault-Tolerant</a>\n *\n */\n@SPI(Cluster.DEFAULT)\npublic interface Cluster {\n\n    String DEFAULT = \"failover\";\n\n    /**\n     * Merge the directory invokers to a virtual invoker.\n     *\n     * @param <T>\n     * @param directory\n     * @return cluster invoker\n     * @throws RpcException\n     */\n    @Adaptive\n    <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException;\n\n    static Cluster getCluster(ScopeModel scopeModel, String name) {\n        return getCluster(scopeModel, name, true);\n    }\n\n    static Cluster getCluster(ScopeModel scopeModel, String name, boolean wrap) {\n        if (StringUtils.isEmpty(name)) {\n            name = Cluster.DEFAULT;\n        }\n        return ScopeModelUtil.getApplicationModel(scopeModel)\n                .getExtensionLoader(Cluster.class)\n                .getExtension(name, wrap);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invoker;\n\n/**\n * This is the final Invoker type referenced by the RPC proxy on Consumer side.\n * <p>\n * A ClusterInvoker holds a group of normal invokers, stored in a Directory, mapping to one Registry.\n * The ClusterInvoker implementation usually provides LB or HA policies, like FailoverClusterInvoker.\n * <p>\n * In multi-registry subscription scenario, the final ClusterInvoker will refer to several sub ClusterInvokers, with each\n * sub ClusterInvoker representing one Registry. Take ZoneAwareClusterInvoker as an example, it is specially customized for\n * multi-registry use cases: first, pick up one ClusterInvoker, then do LB inside the chose ClusterInvoker.\n *\n * @param <T>\n */\npublic interface ClusterInvoker<T> extends Invoker<T> {\n\n    URL getRegistryUrl();\n\n    Directory<T> getDirectory();\n\n    boolean isDestroyed();\n\n    default boolean isServiceDiscovery() {\n        Directory<T> directory = getDirectory();\n        if (directory == null) {\n            return false;\n        }\n        return directory.isServiceDiscovery();\n    }\n\n    default boolean hasProxyInvokers() {\n        Directory<T> directory = getDirectory();\n        if (directory == null) {\n            return false;\n        }\n        return !directory.isEmpty();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;\nimport org.apache.dubbo.rpc.cluster.support.ClusterUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\npublic class ClusterScopeModelInitializer implements ScopeModelInitializer {\n\n    @Override\n    public void initializeFrameworkModel(FrameworkModel frameworkModel) {\n        ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();\n        beanFactory.registerBean(RouterSnapshotSwitcher.class);\n    }\n\n    @Override\n    public void initializeApplicationModel(ApplicationModel applicationModel) {\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        beanFactory.registerBean(ClusterUtils.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;\n\n/**\n * Configurator. (SPI, Prototype, ThreadSafe)\n *\n */\npublic interface Configurator extends Comparable<Configurator> {\n\n    /**\n     * Get the configurator url.\n     *\n     * @return configurator url.\n     */\n    URL getUrl();\n\n    /**\n     * Configure the provider url.\n     *\n     * @param url - old provider url.\n     * @return new provider url.\n     */\n    URL configure(URL url);\n\n    /**\n     * Convert override urls to map for use when re-refer. Send all rules every time, the urls will be reassembled and\n     * calculated\n     *\n     * URL contract:\n     * <ol>\n     * <li>override://0.0.0.0/...( or override://ip:port...?anyhost=true)&para1=value1... means global rules\n     * (all of the providers take effect)</li>\n     * <li>override://ip:port...?anyhost=false Special rules (only for a certain provider)</li>\n     * <li>override:// rule is not supported... ,needs to be calculated by registry itself</li>\n     * <li>override://0.0.0.0/ without parameters means clearing the override</li>\n     * </ol>\n     *\n     * @param urls URL list to convert\n     * @return converted configurator list\n     */\n    static Optional<List<Configurator>> toConfigurators(List<URL> urls) {\n        if (CollectionUtils.isEmpty(urls)) {\n            return Optional.empty();\n        }\n\n        ConfiguratorFactory configuratorFactory = urls.get(0)\n                .getOrDefaultApplicationModel()\n                .getExtensionLoader(ConfiguratorFactory.class)\n                .getAdaptiveExtension();\n\n        List<Configurator> configurators = new ArrayList<>(urls.size());\n        for (URL url : urls) {\n            if (EMPTY_PROTOCOL.equals(url.getProtocol())) {\n                configurators.clear();\n                break;\n            }\n            Map<String, String> override = new HashMap<>(url.getParameters());\n            // The anyhost parameter of override may be added automatically, it can't change the judgement of changing\n            // url\n            override.remove(ANYHOST_KEY);\n            if (CollectionUtils.isEmptyMap(override)) {\n                continue;\n            }\n            configurators.add(configuratorFactory.getConfigurator(url));\n        }\n        Collections.sort(configurators);\n        return Optional.of(configurators);\n    }\n\n    /**\n     * Sort by host, then by priority\n     * 1. the url with a specific host ip should have higher priority than 0.0.0.0\n     * 2. if two url has the same host, compare by priority value；\n     */\n    @Override\n    default int compareTo(Configurator o) {\n        if (o == null) {\n            return -1;\n        }\n\n        int ipCompare = getUrl().getHost().compareTo(o.getUrl().getHost());\n        // host is the same, sort by priority\n        if (ipCompare == 0) {\n            int i = getUrl().getParameter(PRIORITY_KEY, 0);\n            int j = o.getUrl().getParameter(PRIORITY_KEY, 0);\n            return Integer.compare(i, j);\n        } else {\n            return ipCompare;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ConfiguratorFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * ConfiguratorFactory. (SPI, Singleton, ThreadSafe)\n *\n */\n@SPI\npublic interface ConfiguratorFactory {\n\n    /**\n     * get the configurator instance.\n     *\n     * @param url - configurator url.\n     * @return configurator instance.\n     */\n    @Adaptive(CommonConstants.PROTOCOL_KEY)\n    Configurator getConfigurator(URL url);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\npublic interface Constants {\n\n    String FAIL_BACK_TASKS_KEY = \"failbacktasks\";\n\n    int DEFAULT_FAILBACK_TASKS = 100;\n\n    int DEFAULT_FORKS = 2;\n\n    String WEIGHT_KEY = \"weight\";\n\n    int DEFAULT_WEIGHT = 100;\n\n    String MOCK_PROTOCOL = \"mock\";\n\n    String FORCE_KEY = \"force\";\n\n    String RAW_RULE_KEY = \"rawRule\";\n\n    String VALID_KEY = \"valid\";\n\n    String ENABLED_KEY = \"enabled\";\n\n    String DYNAMIC_KEY = \"dynamic\";\n\n    String SCOPE_KEY = \"scope\";\n\n    String KEY_KEY = \"key\";\n\n    String CONDITIONS_KEY = \"conditions\";\n\n    String AFFINITY_KEY = \"affinityAware\";\n\n    String TAGS_KEY = \"tags\";\n\n    /**\n     * To decide whether to exclude unavailable invoker from the cluster\n     */\n    String CLUSTER_AVAILABLE_CHECK_KEY = \"cluster.availablecheck\";\n\n    /**\n     * The default value of cluster.availablecheck\n     *\n     * @see #CLUSTER_AVAILABLE_CHECK_KEY\n     */\n    boolean DEFAULT_CLUSTER_AVAILABLE_CHECK = true;\n\n    /**\n     * To decide whether to enable sticky strategy for cluster\n     */\n    String CLUSTER_STICKY_KEY = \"sticky\";\n\n    /**\n     * The default value of sticky\n     *\n     * @see #CLUSTER_STICKY_KEY\n     */\n    boolean DEFAULT_CLUSTER_STICKY = false;\n\n    /**\n     * When this attribute appears in invocation's attachment, mock invoker will be used\n     */\n    String INVOCATION_NEED_MOCK = \"invocation.need.mock\";\n\n    /**\n     * when ROUTER_KEY's value is set to ROUTER_TYPE_CLEAR, RegistryDirectory will clean all current routers\n     */\n    String ROUTER_TYPE_CLEAR = \"clean\";\n\n    String DEFAULT_SCRIPT_TYPE_KEY = \"javascript\";\n\n    String PRIORITY_KEY = \"priority\";\n\n    String RULE_KEY = \"rule\";\n\n    String TYPE_KEY = \"type\";\n\n    String RUNTIME_KEY = \"runtime\";\n\n    String WARMUP_KEY = \"warmup\";\n\n    int DEFAULT_WARMUP = 10 * 60 * 1000;\n\n    String CONFIG_VERSION_KEY = \"configVersion\";\n\n    String OVERRIDE_PROVIDERS_KEY = \"providerAddresses\";\n\n    /**\n     * key for router type, for e.g., \"script\"/\"file\",  corresponding to ScriptRouterFactory.NAME, FileRouterFactory.NAME\n     */\n    String ROUTER_KEY = \"router\";\n\n    /**\n     * The key name for reference URL in register center\n     */\n    String REFER_KEY = \"refer\";\n\n    String ATTRIBUTE_KEY = \"attribute\";\n\n    /**\n     * The key name for export URL in register center\n     */\n    String EXPORT_KEY = \"export\";\n\n    String PEER_KEY = \"peer\";\n\n    String CONSUMER_URL_KEY = \"CONSUMER_URL\";\n\n    /**\n     * prefix of arguments router key\n     */\n    String ARGUMENTS = \"arguments\";\n\n    String NEED_REEXPORT = \"need-reexport\";\n\n    /**\n     * The key of shortestResponseSlidePeriod\n     */\n    String SHORTEST_RESPONSE_SLIDE_PERIOD = \"shortestResponseSlidePeriod\";\n\n    String SHOULD_FAIL_FAST_KEY = \"dubbo.router.should-fail-fast\";\n\n    String RULE_VERSION_V27 = \"v2.7\";\n\n    String RULE_VERSION_V30 = \"v3.0\";\n\n    String RULE_VERSION_V31 = \"v3.1\";\n\n    public static final String TRAFFIC_DISABLE_KEY = \"trafficDisable\";\n    public static final String RATIO_KEY = \"ratio\";\n    public static final int DefaultRouteRatio = 0;\n    public static final int DefaultRouteConditionSubSetWeight = 100;\n    public static final int DefaultRoutePriority = 0;\n    public static final double DefaultAffinityRatio = 0;\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.Node;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport java.util.List;\n\n/**\n * Directory. (SPI, Prototype, ThreadSafe)\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Directory_service\">Directory Service</a>\n *\n * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)\n */\npublic interface Directory<T> extends Node {\n\n    /**\n     * get service type.\n     *\n     * @return service type.\n     */\n    Class<T> getInterface();\n\n    /**\n     * list invokers.\n     * filtered by invocation\n     *\n     * @return invokers\n     */\n    List<Invoker<T>> list(Invocation invocation) throws RpcException;\n\n    /**\n     * list invokers\n     * include all invokers from registry\n     */\n    List<Invoker<T>> getAllInvokers();\n\n    URL getConsumerUrl();\n\n    boolean isDestroyed();\n\n    default boolean isEmpty() {\n        return CollectionUtils.isEmpty(getAllInvokers());\n    }\n\n    default boolean isServiceDiscovery() {\n        return false;\n    }\n\n    void discordAddresses();\n\n    RouterChain<T> getRouterChain();\n\n    /**\n     * invalidate an invoker, add it into reconnect task, remove from list next time\n     * will be recovered by address refresh notification or reconnect success notification\n     *\n     * @param invoker invoker to invalidate\n     */\n    void addInvalidateInvoker(Invoker<T> invoker);\n\n    /**\n     * disable an invoker, remove from list next time\n     * will be removed when invoker is removed by address refresh notification\n     * using in service offline notification\n     *\n     * @param invoker invoker to invalidate\n     */\n    void addDisabledInvoker(Invoker<T> invoker);\n\n    /**\n     * recover a disabled invoker\n     *\n     * @param invoker invoker to invalidate\n     */\n    void recoverDisabledInvoker(Invoker<T> invoker);\n\n    default boolean isNotificationReceived() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/LoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;\n\nimport java.util.List;\n\n/**\n * LoadBalance. (SPI, Singleton, ThreadSafe)\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Load_balancing_(computing)\">Load-Balancing</a>\n *\n * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)\n */\n@SPI(RandomLoadBalance.NAME)\npublic interface LoadBalance {\n\n    /**\n     * select one invoker in list.\n     *\n     * @param invokers   invokers.\n     * @param url        refer url\n     * @param invocation invocation.\n     * @return selected invoker.\n     */\n    @Adaptive(\"loadbalance\")\n    <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/MergeableClusterScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.rpc.cluster.merger.MergerFactory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\npublic class MergeableClusterScopeModelInitializer implements ScopeModelInitializer {\n\n    @Override\n    public void initializeApplicationModel(ApplicationModel applicationModel) {\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        beanFactory.registerBean(MergerFactory.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Merger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface Merger<T> {\n\n    T merge(T... items);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ProviderURLMergeProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.Map;\n\n@SPI(\"default\")\npublic interface ProviderURLMergeProcessor {\n\n    /**\n     * Merging the URL parameters of provider and consumer\n     *\n     * @param remoteUrl          providerUrl\n     * @param localParametersMap consumer url parameters\n     * @return\n     */\n    URL mergeUrl(URL remoteUrl, Map<String, String> localParametersMap);\n\n    default Map<String, String> mergeLocalParams(Map<String, String> localMap) {\n        return localMap;\n    }\n\n    default boolean accept(URL providerUrl, Map<String, String> localParametersMap) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.RouterResult;\n\nimport java.util.List;\n\n/**\n * Router. (SPI, Prototype, ThreadSafe)\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Routing\">Routing</a>\n *\n * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory, boolean)\n * @see org.apache.dubbo.rpc.cluster.Directory#list(Invocation)\n */\npublic interface Router extends Comparable<Router> {\n\n    int DEFAULT_PRIORITY = Integer.MAX_VALUE;\n\n    /**\n     * Get the router url.\n     *\n     * @return url\n     */\n    URL getUrl();\n\n    /**\n     * Filter invokers with current routing rule and only return the invokers that comply with the rule.\n     *\n     * @param invokers   invoker list\n     * @param url        refer url\n     * @param invocation invocation\n     * @return routed invokers\n     * @throws RpcException\n     */\n    @Deprecated\n    default <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {\n        return null;\n    }\n\n    /**\n     * ** This method can return the state of whether routerChain needed to continue route. **\n     * Filter invokers with current routing rule and only return the invokers that comply with the rule.\n     *\n     * @param invokers   invoker list\n     * @param url        refer url\n     * @param invocation invocation\n     * @param needToPrintMessage whether to print router state. Such as `use router branch a`.\n     * @return state with route result\n     * @throws RpcException\n     */\n    default <T> RouterResult<Invoker<T>> route(\n            List<Invoker<T>> invokers, URL url, Invocation invocation, boolean needToPrintMessage) throws RpcException {\n        return new RouterResult<>(route(invokers, url, invocation));\n    }\n\n    /**\n     * Notify the router the invoker list. Invoker list may change from time to time. This method gives the router a\n     * chance to prepare before {@link Router#route(List, URL, Invocation)} gets called.\n     *\n     * @param invokers invoker list\n     * @param <T>      invoker's type\n     */\n    default <T> void notify(List<Invoker<T>> invokers) {}\n\n    /**\n     * To decide whether this router need to execute every time an RPC comes or should only execute when addresses or\n     * rule change.\n     *\n     * @return true if the router need to execute every time.\n     */\n    boolean isRuntime();\n\n    /**\n     * To decide whether this router should take effect when none of the invoker can match the router rule, which\n     * means the {@link #route(List, URL, Invocation)} would be empty. Most of time, most router implementation would\n     * default this value to false.\n     *\n     * @return true to execute if none of invokers matches the current router\n     */\n    boolean isForce();\n\n    /**\n     * Router's priority, used to sort routers.\n     *\n     * @return router's priority\n     */\n    int getPriority();\n\n    default void stop() {\n        // do nothing by default\n    }\n\n    @Override\n    default int compareTo(Router o) {\n        if (o == null) {\n            throw new IllegalArgumentException();\n        }\n        return Integer.compare(this.getPriority(), o.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.concurrent.locks.ReadWriteLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;\n\n/**\n * Router chain\n */\npublic class RouterChain<T> {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(RouterChain.class);\n\n    private volatile SingleRouterChain<T> mainChain;\n    private volatile SingleRouterChain<T> backupChain;\n    private volatile SingleRouterChain<T> currentChain;\n\n    @SuppressWarnings({\"rawtypes\", \"unchecked\"})\n    public static <T> RouterChain<T> buildChain(Class<T> interfaceClass, URL url) {\n        SingleRouterChain<T> chain1 = buildSingleChain(interfaceClass, url);\n        SingleRouterChain<T> chain2 = buildSingleChain(interfaceClass, url);\n        return new RouterChain<>(new SingleRouterChain[] {chain1, chain2});\n    }\n\n    public static <T> SingleRouterChain<T> buildSingleChain(Class<T> interfaceClass, URL url) {\n        ModuleModel moduleModel = url.getOrDefaultModuleModel();\n\n        List<RouterFactory> extensionFactories =\n                moduleModel.getExtensionLoader(RouterFactory.class).getActivateExtension(url, ROUTER_KEY);\n\n        List<Router> routers = extensionFactories.stream()\n                .map(factory -> factory.getRouter(url))\n                .sorted(Router::compareTo)\n                .collect(Collectors.toList());\n\n        List<StateRouter<T>> stateRouters =\n                moduleModel.getExtensionLoader(StateRouterFactory.class).getActivateExtension(url, ROUTER_KEY).stream()\n                        .map(factory -> factory.getRouter(interfaceClass, url))\n                        .collect(Collectors.toList());\n\n        boolean shouldFailFast = Boolean.parseBoolean(\n                ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, \"true\"));\n\n        RouterSnapshotSwitcher routerSnapshotSwitcher =\n                ScopeModelUtil.getFrameworkModel(moduleModel).getBeanFactory().getBean(RouterSnapshotSwitcher.class);\n\n        return new SingleRouterChain<>(routers, stateRouters, shouldFailFast, routerSnapshotSwitcher);\n    }\n\n    public RouterChain(SingleRouterChain<T>[] chains) {\n        if (chains.length != 2) {\n            throw new IllegalArgumentException(\"chains' size should be 2.\");\n        }\n        this.mainChain = chains[0];\n        this.backupChain = chains[1];\n        this.currentChain = this.mainChain;\n    }\n\n    private final AtomicReference<BitList<Invoker<T>>> notifyingInvokers = new AtomicReference<>();\n\n    private final ReadWriteLock lock = new ReentrantReadWriteLock();\n\n    public ReadWriteLock getLock() {\n        return lock;\n    }\n\n    public SingleRouterChain<T> getSingleChain(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {\n        // If current is in:\n        // 1. `setInvokers` is in progress\n        // 2. Most of the invocation should use backup chain => currentChain == backupChain\n        // 3. Main chain has been update success => notifyingInvokers.get() != null\n        //     If `availableInvokers` is created from origin invokers => use backup chain\n        //     If `availableInvokers` is created from newly invokers  => use main chain\n        BitList<Invoker<T>> notifying = notifyingInvokers.get();\n        if (notifying != null\n                && currentChain == backupChain\n                && availableInvokers.getOriginList() == notifying.getOriginList()) {\n            return mainChain;\n        }\n        return currentChain;\n    }\n\n    /**\n     * @deprecated use {@link RouterChain#getSingleChain(URL, BitList, Invocation)} and {@link SingleRouterChain#route(URL, BitList, Invocation)} instead\n     */\n    @Deprecated\n    public List<Invoker<T>> route(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {\n        return getSingleChain(url, availableInvokers, invocation).route(url, availableInvokers, invocation);\n    }\n\n    /**\n     * Notify router chain of the initial addresses from registry at the first time.\n     * Notify whenever addresses in registry change.\n     */\n    public synchronized void setInvokers(BitList<Invoker<T>> invokers, Runnable switchAction) {\n        try {\n            // Lock to prevent directory continue list\n            lock.writeLock().lock();\n\n            // Switch to back up chain. Will update main chain first.\n            currentChain = backupChain;\n        } finally {\n            // Release lock to minimize the impact for each newly created invocations as much as possible.\n            // Should not release lock until main chain update finished. Or this may cause long hang.\n            lock.writeLock().unlock();\n        }\n\n        // Refresh main chain.\n        // No one can request to use main chain. `currentChain` is backup chain. `route` method cannot access main\n        // chain.\n        try {\n            // Lock main chain to wait all invocation end\n            // To wait until no one is using main chain.\n            mainChain.getLock().writeLock().lock();\n\n            // refresh\n            mainChain.setInvokers(invokers);\n        } catch (Throwable t) {\n            logger.error(LoggerCodeConstants.INTERNAL_ERROR, \"\", \"\", \"Error occurred when refreshing router chain.\", t);\n            throw t;\n        } finally {\n            // Unlock main chain\n            mainChain.getLock().writeLock().unlock();\n        }\n\n        // Set the reference of newly invokers to temp variable.\n        // Reason: The next step will switch the invokers reference in directory, so we should check the\n        // `availableInvokers`\n        //         argument when `route`. If the current invocation use newly invokers, we should use main chain to\n        // route, and\n        //         this can prevent use newly invokers to route backup chain, which can only route origin invokers now.\n        notifyingInvokers.set(invokers);\n\n        // Switch the invokers reference in directory.\n        // Cannot switch before update main chain or after backup chain update success. Or that will cause state\n        // inconsistent.\n        switchAction.run();\n\n        try {\n            // Lock to prevent directory continue list\n            // The invokers reference in directory now should be the newly one and should always use the newly one once\n            // lock released.\n            lock.writeLock().lock();\n\n            // Switch to main chain. Will update backup chain later.\n            currentChain = mainChain;\n\n            // Clean up temp variable.\n            // `availableInvokers` check is useless now, because `route` method will no longer receive any\n            // `availableInvokers` related\n            // with the origin invokers. The getter of invokers reference in directory is locked now, and will return\n            // newly invokers\n            // once lock released.\n            notifyingInvokers.set(null);\n        } finally {\n            // Release lock to minimize the impact for each newly created invocations as much as possible.\n            // Will use newly invokers and main chain now.\n            lock.writeLock().unlock();\n        }\n\n        // Refresh main chain.\n        // No one can request to use main chain. `currentChain` is main chain. `route` method cannot access backup\n        // chain.\n        try {\n            // Lock main chain to wait all invocation end\n            backupChain.getLock().writeLock().lock();\n\n            // refresh\n            backupChain.setInvokers(invokers);\n        } catch (Throwable t) {\n            logger.error(LoggerCodeConstants.INTERNAL_ERROR, \"\", \"\", \"Error occurred when refreshing router chain.\", t);\n            throw t;\n        } finally {\n            // Unlock backup chain\n            backupChain.getLock().writeLock().unlock();\n        }\n    }\n\n    public synchronized void destroy() {\n        // 1. destroy another\n        backupChain.destroy();\n\n        // 2. switch\n        lock.writeLock().lock();\n        currentChain = backupChain;\n        lock.writeLock().unlock();\n\n        // 4. destroy\n        mainChain.destroy();\n    }\n\n    public void addRouters(List<Router> routers) {\n        mainChain.addRouters(routers);\n        backupChain.addRouters(routers);\n    }\n\n    public SingleRouterChain<T> getCurrentChain() {\n        return currentChain;\n    }\n\n    public List<Router> getRouters() {\n        return currentChain.getRouters();\n    }\n\n    public StateRouter<T> getHeadStateRouter() {\n        return currentChain.getHeadStateRouter();\n    }\n\n    @Deprecated\n    public List<StateRouter<T>> getStateRouters() {\n        return currentChain.getStateRouters();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * RouterFactory. (SPI, Singleton, ThreadSafe)\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Routing\">Routing</a>\n *\n * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)\n * @see org.apache.dubbo.rpc.cluster.Directory#list(org.apache.dubbo.rpc.Invocation)\n * <p>\n * Note Router has a different behaviour since 2.7.0, for each type of Router, there will only has one Router instance\n * for each service. See {@link CacheableRouterFactory} and {@link RouterChain} for how to extend a new Router or how\n * the Router instances are loaded.\n */\n@SPI\npublic interface RouterFactory {\n\n    /**\n     * Create router.\n     * Since 2.7.0, most of the time, we will not use @Adaptive feature, so it's kept only for compatibility.\n     *\n     * @param url url\n     * @return router instance\n     */\n    @Adaptive(CommonConstants.PROTOCOL_KEY)\n    Router getRouter(URL url);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RuleConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.List;\n\n@SPI\npublic interface RuleConverter {\n\n    List<URL> convert(URL subscribeUrl, Object source);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/SingleRouterChain.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.cluster.router.RouterResult;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.TailStateRouter;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.locks.ReadWriteLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_STOP;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_NO_VALID_PROVIDER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\n\n/**\n * Router chain\n */\npublic class SingleRouterChain<T> {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SingleRouterChain.class);\n\n    /**\n     * full list of addresses from registry, classified by method name.\n     */\n    private volatile BitList<Invoker<T>> invokers = BitList.emptyList();\n\n    /**\n     * containing all routers, reconstruct every time 'route://' urls change.\n     */\n    private volatile List<Router> routers = Collections.emptyList();\n\n    /**\n     * Fixed router instances: ConfigConditionRouter, TagRouter, e.g.,\n     * the rule for each instance may change but the instance will never delete or recreate.\n     */\n    private volatile List<Router> builtinRouters = Collections.emptyList();\n\n    private volatile StateRouter<T> headStateRouter;\n\n    private volatile List<StateRouter<T>> stateRouters;\n\n    /**\n     * Should continue route if current router's result is empty\n     */\n    private final boolean shouldFailFast;\n\n    private final RouterSnapshotSwitcher routerSnapshotSwitcher;\n\n    private final ReadWriteLock lock = new ReentrantReadWriteLock();\n\n    public SingleRouterChain(\n            List<Router> routers,\n            List<StateRouter<T>> stateRouters,\n            boolean shouldFailFast,\n            RouterSnapshotSwitcher routerSnapshotSwitcher) {\n        initWithRouters(routers);\n\n        initWithStateRouters(stateRouters);\n\n        this.shouldFailFast = shouldFailFast;\n        this.routerSnapshotSwitcher = routerSnapshotSwitcher;\n    }\n\n    private void initWithStateRouters(List<StateRouter<T>> stateRouters) {\n        StateRouter<T> stateRouter = TailStateRouter.getInstance();\n        for (int i = stateRouters.size() - 1; i >= 0; i--) {\n            StateRouter<T> nextStateRouter = stateRouters.get(i);\n            nextStateRouter.setNextRouter(stateRouter);\n            stateRouter = nextStateRouter;\n        }\n        this.headStateRouter = stateRouter;\n        this.stateRouters = Collections.unmodifiableList(stateRouters);\n    }\n\n    /**\n     * the resident routers must being initialized before address notification.\n     * only for ut\n     */\n    public void initWithRouters(List<Router> builtinRouters) {\n        this.builtinRouters = builtinRouters;\n        this.routers = new LinkedList<>(builtinRouters);\n    }\n\n    /**\n     * If we use route:// protocol in version before 2.7.0, each URL will generate a Router instance, so we should\n     * keep the routers up to date, that is, each time router URLs changes, we should update the routers list, only\n     * keep the builtinRouters which are available all the time and the latest notified routers which are generated\n     * from URLs.\n     *\n     * @param routers routers from 'router://' rules in 2.6.x or before.\n     */\n    public void addRouters(List<Router> routers) {\n        List<Router> newRouters = new LinkedList<>();\n        newRouters.addAll(builtinRouters);\n        newRouters.addAll(routers);\n        CollectionUtils.sort(newRouters);\n        this.routers = newRouters;\n    }\n\n    public List<Router> getRouters() {\n        return routers;\n    }\n\n    public StateRouter<T> getHeadStateRouter() {\n        return headStateRouter;\n    }\n\n    public List<Invoker<T>> route(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {\n        if (invokers.getOriginList() != availableInvokers.getOriginList()) {\n            logger.error(\n                    INTERNAL_ERROR,\n                    \"\",\n                    \"Router's invoker size: \" + invokers.getOriginList().size() + \" Invocation's invoker size: \"\n                            + availableInvokers.getOriginList().size(),\n                    \"Reject to route, because the invokers has changed.\");\n            throw new IllegalStateException(\"reject to route, because the invokers has changed.\");\n        }\n        if (RpcContext.getServiceContext().isNeedPrintRouterSnapshot()) {\n            return routeAndPrint(url, availableInvokers, invocation);\n        } else {\n            return simpleRoute(url, availableInvokers, invocation);\n        }\n    }\n\n    public List<Invoker<T>> routeAndPrint(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {\n        RouterSnapshotNode<T> snapshot = buildRouterSnapshot(url, availableInvokers, invocation);\n        logRouterSnapshot(url, invocation, snapshot);\n        return snapshot.getChainOutputInvokers();\n    }\n\n    public List<Invoker<T>> simpleRoute(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {\n        BitList<Invoker<T>> resultInvokers = availableInvokers.clone();\n\n        // 1. route state router\n        resultInvokers = headStateRouter.route(resultInvokers, url, invocation, false, null);\n        if (resultInvokers.isEmpty() && (shouldFailFast || routers.isEmpty())) {\n            printRouterSnapshot(url, availableInvokers, invocation);\n            return BitList.emptyList();\n        }\n\n        if (routers.isEmpty()) {\n            return resultInvokers;\n        }\n        List<Invoker<T>> commonRouterResult = resultInvokers.cloneToArrayList();\n        // 2. route common router\n        for (Router router : routers) {\n            // Copy resultInvokers to a arrayList. BitList not support\n            RouterResult<Invoker<T>> routeResult = router.route(commonRouterResult, url, invocation, false);\n            commonRouterResult = routeResult.getResult();\n            if (CollectionUtils.isEmpty(commonRouterResult) && shouldFailFast) {\n                printRouterSnapshot(url, availableInvokers, invocation);\n                return BitList.emptyList();\n            }\n\n            // stop continue routing\n            if (!routeResult.isNeedContinueRoute()) {\n                return commonRouterResult;\n            }\n        }\n\n        if (commonRouterResult.isEmpty()) {\n            printRouterSnapshot(url, availableInvokers, invocation);\n            return BitList.emptyList();\n        }\n\n        return commonRouterResult;\n    }\n\n    /**\n     * store each router's input and output, log out if empty\n     */\n    private void printRouterSnapshot(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {\n        if (logger.isWarnEnabled()) {\n            logRouterSnapshot(url, invocation, buildRouterSnapshot(url, availableInvokers, invocation));\n        }\n    }\n\n    /**\n     * Build each router's result\n     */\n    public RouterSnapshotNode<T> buildRouterSnapshot(\n            URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {\n        BitList<Invoker<T>> resultInvokers = availableInvokers.clone();\n        RouterSnapshotNode<T> parentNode = new RouterSnapshotNode<>(\"Parent\", resultInvokers.clone());\n        parentNode.setNodeOutputInvokers(resultInvokers.clone());\n\n        // 1. route state router\n        Holder<RouterSnapshotNode<T>> nodeHolder = new Holder<>();\n        nodeHolder.set(parentNode);\n\n        resultInvokers = headStateRouter.route(resultInvokers, url, invocation, true, nodeHolder);\n\n        // result is empty, log out\n        if (routers.isEmpty() || (resultInvokers.isEmpty() && shouldFailFast)) {\n            parentNode.setChainOutputInvokers(resultInvokers.clone());\n            return parentNode;\n        }\n\n        RouterSnapshotNode<T> commonRouterNode = new RouterSnapshotNode<>(\"CommonRouter\", resultInvokers.clone());\n        parentNode.appendNode(commonRouterNode);\n        List<Invoker<T>> commonRouterResult = resultInvokers;\n\n        // 2. route common router\n        for (Router router : routers) {\n            // Copy resultInvokers to a arrayList. BitList not support\n            List<Invoker<T>> inputInvokers = new ArrayList<>(commonRouterResult);\n\n            RouterSnapshotNode<T> currentNode =\n                    new RouterSnapshotNode<>(router.getClass().getSimpleName(), inputInvokers);\n\n            // append to router node chain\n            commonRouterNode.appendNode(currentNode);\n            commonRouterNode = currentNode;\n\n            RouterResult<Invoker<T>> routeStateResult = router.route(inputInvokers, url, invocation, true);\n            List<Invoker<T>> routeResult = routeStateResult.getResult();\n            String routerMessage = routeStateResult.getMessage();\n\n            currentNode.setNodeOutputInvokers(routeResult);\n            currentNode.setRouterMessage(routerMessage);\n\n            commonRouterResult = routeResult;\n\n            // result is empty, log out\n            if (CollectionUtils.isEmpty(routeResult) && shouldFailFast) {\n                break;\n            }\n\n            if (!routeStateResult.isNeedContinueRoute()) {\n                break;\n            }\n        }\n        commonRouterNode.setChainOutputInvokers(commonRouterNode.getNodeOutputInvokers());\n\n        // 3. set router chain output reverse\n        RouterSnapshotNode<T> currentNode = commonRouterNode;\n        while (currentNode != null) {\n            RouterSnapshotNode<T> parent = currentNode.getParentNode();\n            if (parent != null) {\n                // common router only has one child invoke\n                parent.setChainOutputInvokers(currentNode.getChainOutputInvokers());\n            }\n            currentNode = parent;\n        }\n        return parentNode;\n    }\n\n    private void logRouterSnapshot(URL url, Invocation invocation, RouterSnapshotNode<T> snapshotNode) {\n        if (snapshotNode.getChainOutputInvokers() == null\n                || snapshotNode.getChainOutputInvokers().isEmpty()) {\n            if (logger.isWarnEnabled()) {\n                String message = \"No provider available after route for the service \" + url.getServiceKey()\n                        + \" from registry \" + url.getAddress()\n                        + \" on the consumer \" + NetUtils.getLocalHost()\n                        + \" using the dubbo version \" + Version.getVersion() + \". Router snapshot is below: \\n\"\n                        + snapshotNode.toString();\n                if (routerSnapshotSwitcher.isEnable()) {\n                    routerSnapshotSwitcher.setSnapshot(message);\n                }\n                logger.warn(\n                        CLUSTER_NO_VALID_PROVIDER, \"No provider available after route for the service\", \"\", message);\n            }\n        } else {\n            if (logger.isInfoEnabled()) {\n                String message = \"Router snapshot service \" + url.getServiceKey()\n                        + \" from registry \" + url.getAddress()\n                        + \" on the consumer \" + NetUtils.getLocalHost()\n                        + \" using the dubbo version \" + Version.getVersion() + \" is below: \\n\"\n                        + snapshotNode.toString();\n                if (routerSnapshotSwitcher.isEnable()) {\n                    routerSnapshotSwitcher.setSnapshot(message);\n                }\n                logger.info(message);\n            }\n        }\n    }\n\n    /**\n     * Notify router chain of the initial addresses from registry at the first time.\n     * Notify whenever addresses in registry change.\n     */\n    public void setInvokers(BitList<Invoker<T>> invokers) {\n        this.invokers = (invokers == null ? BitList.emptyList() : invokers);\n        routers.forEach(router -> router.notify(this.invokers));\n        stateRouters.forEach(router -> router.notify(this.invokers));\n    }\n\n    /**\n     * for uts only\n     */\n    @Deprecated\n    public void setHeadStateRouter(StateRouter<T> headStateRouter) {\n        this.headStateRouter = headStateRouter;\n    }\n\n    /**\n     * for uts only\n     */\n    @Deprecated\n    public List<StateRouter<T>> getStateRouters() {\n        return stateRouters;\n    }\n\n    public ReadWriteLock getLock() {\n        return lock;\n    }\n\n    public void destroy() {\n        invokers = BitList.emptyList();\n        for (Router router : routers) {\n            try {\n                router.stop();\n            } catch (Exception e) {\n                logger.error(\n                        CLUSTER_FAILED_STOP,\n                        \"route stop failed\",\n                        \"\",\n                        \"Error trying to stop router \" + router.getClass(),\n                        e);\n            }\n        }\n        routers = Collections.emptyList();\n        builtinRouters = Collections.emptyList();\n\n        for (StateRouter<T> router : stateRouters) {\n            try {\n                router.stop();\n            } catch (Exception e) {\n                logger.error(\n                        CLUSTER_FAILED_STOP,\n                        \"StateRouter stop failed\",\n                        \"\",\n                        \"Error trying to stop StateRouter \" + router.getClass(),\n                        e);\n            }\n        }\n        stateRouters = Collections.emptyList();\n        headStateRouter = TailStateRouter.getInstance();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.rpc.cluster.Configurator;\nimport org.apache.dubbo.rpc.cluster.configurator.parser.model.ConditionMatch;\n\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACES;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CONFIG_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_VERSION_V30;\nimport static org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig.MATCH_CONDITION;\n\npublic abstract class AbstractConfigurator implements Configurator {\n    private static final Logger logger = LoggerFactory.getLogger(AbstractConfigurator.class);\n    private static final String TILDE = \"~\";\n\n    private final URL configuratorUrl;\n\n    public AbstractConfigurator(URL url) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"configurator url == null\");\n        }\n        this.configuratorUrl = url;\n    }\n\n    @Override\n    public URL getUrl() {\n        return configuratorUrl;\n    }\n\n    @Override\n    public URL configure(URL url) {\n        // If override url is not enabled or is invalid, just return.\n        if (!configuratorUrl.getParameter(ENABLED_KEY, true)\n                || configuratorUrl.getHost() == null\n                || url == null\n                || url.getHost() == null) {\n            logger.info(\"Cannot apply configurator rule, the rule is disabled or is invalid: \\n\" + configuratorUrl);\n            return url;\n        }\n\n        String apiVersion = configuratorUrl.getParameter(CONFIG_VERSION_KEY);\n        if (StringUtils.isNotEmpty(apiVersion)) { // v2.7 or above\n            String currentSide = url.getSide();\n            String configuratorSide = configuratorUrl.getSide();\n            if (currentSide.equals(configuratorSide) && CONSUMER.equals(configuratorSide)) {\n                url = configureIfMatch(NetUtils.getLocalHost(), url);\n            } else if (currentSide.equals(configuratorSide) && PROVIDER.equals(configuratorSide)) {\n                url = configureIfMatch(url.getHost(), url);\n            }\n        }\n        /*\n         * This else branch is deprecated and is left only to keep compatibility with versions before 2.7.0\n         */\n        else {\n            url = configureDeprecated(url);\n        }\n        return url;\n    }\n\n    @Deprecated\n    private URL configureDeprecated(URL url) {\n        // If override url has port, means it is a provider address. We want to control a specific provider with this\n        // override url, it may take effect on the specific provider instance or on consumers holding this provider\n        // instance.\n        if (configuratorUrl.getPort() != 0) {\n            if (url.getPort() == configuratorUrl.getPort()) {\n                return configureIfMatch(url.getHost(), url);\n            }\n        } else {\n            /*\n             *  override url don't have a port, means the ip override url specify is a consumer address or 0.0.0.0.\n             *  1.If it is a consumer ip address, the intention is to control a specific consumer instance, it must takes effect at the consumer side, any provider received this override url should ignore.\n             *  2.If the ip is 0.0.0.0, this override url can be used on consumer, and also can be used on provider.\n             */\n            if (url.getSide(PROVIDER).equals(CONSUMER)) {\n                // NetUtils.getLocalHost is the ip address consumer registered to registry.\n                return configureIfMatch(NetUtils.getLocalHost(), url);\n            } else if (url.getSide(CONSUMER).equals(PROVIDER)) {\n                // take effect on all providers, so address must be 0.0.0.0, otherwise it won't flow to this if branch\n                return configureIfMatch(ANYHOST_VALUE, url);\n            }\n        }\n        return url;\n    }\n\n    private URL configureIfMatch(String host, URL url) {\n        if (ANYHOST_VALUE.equals(configuratorUrl.getHost()) || host.equals(configuratorUrl.getHost())) {\n            if (isV27ConditionMatchOrUnset(url)) {\n                Set<String> conditionKeys = genConditionKeys();\n                String apiVersion = configuratorUrl.getParameter(CONFIG_VERSION_KEY);\n                if (apiVersion != null && apiVersion.startsWith(RULE_VERSION_V30)) {\n                    ConditionMatch matcher = (ConditionMatch) configuratorUrl.getAttribute(MATCH_CONDITION);\n                    if (matcher != null) {\n                        if (matcher.isMatch(host, url)) {\n                            return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));\n                        } else {\n                            logger.debug(\"Cannot apply configurator rule, param mismatch, current params are \" + url\n                                    + \", params in rule is \" + matcher);\n                        }\n                    } else {\n                        return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));\n                    }\n                } else if (isDeprecatedConditionMatch(conditionKeys, url)) {\n                    return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));\n                }\n            }\n        } else {\n            logger.debug(\"Cannot apply configurator rule, host mismatch, current host is \" + host + \", host in rule is \"\n                    + configuratorUrl.getHost());\n        }\n        return url;\n    }\n\n    /**\n     * Check if v2.7 configurator rule is set and can be matched.\n     *\n     * @param url the configurator rule url\n     * @return true if v2.7 configurator rule is not set or the rule can be matched.\n     */\n    private boolean isV27ConditionMatchOrUnset(URL url) {\n        String providers = configuratorUrl.getParameter(OVERRIDE_PROVIDERS_KEY);\n        if (StringUtils.isNotEmpty(providers)) {\n            boolean match = false;\n            String[] providerAddresses = providers.split(CommonConstants.COMMA_SEPARATOR);\n            for (String address : providerAddresses) {\n                if (address.equals(url.getAddress())\n                        || address.equals(ANYHOST_VALUE)\n                        || address.equals(ANYHOST_VALUE + CommonConstants.GROUP_CHAR_SEPARATOR + ANY_VALUE)\n                        || address.equals(ANYHOST_VALUE + CommonConstants.GROUP_CHAR_SEPARATOR + url.getPort())\n                        || address.equals(url.getHost())) {\n                    match = true;\n                }\n            }\n            if (!match) {\n                logger.debug(\"Cannot apply configurator rule, provider address mismatch, current address \"\n                        + url.getAddress() + \", address in rule is \" + providers);\n                return false;\n            }\n        }\n\n        String configApplication = configuratorUrl.getApplication(configuratorUrl.getUsername());\n        String currentApplication = url.getApplication(url.getUsername());\n        if (configApplication != null\n                && !ANY_VALUE.equals(configApplication)\n                && !configApplication.equals(currentApplication)) {\n            logger.debug(\"Cannot apply configurator rule, application name mismatch, current application is \"\n                    + currentApplication + \", application in rule is \" + configApplication);\n            return false;\n        }\n\n        String configServiceKey = configuratorUrl.getServiceKey();\n        String currentServiceKey = url.getServiceKey();\n        if (!ANY_VALUE.equals(configServiceKey) && !configServiceKey.equals(currentServiceKey)) {\n            logger.debug(\"Cannot apply configurator rule, service mismatch, current service is \" + currentServiceKey\n                    + \", service in rule is \" + configServiceKey);\n            return false;\n        }\n\n        return true;\n    }\n\n    private boolean isDeprecatedConditionMatch(Set<String> conditionKeys, URL url) {\n        boolean result = true;\n        for (Map.Entry<String, String> entry : configuratorUrl.getParameters().entrySet()) {\n            String key = entry.getKey();\n            String value = entry.getValue();\n            boolean startWithTilde = startWithTilde(key);\n            if (startWithTilde || APPLICATION_KEY.equals(key) || SIDE_KEY.equals(key)) {\n                if (startWithTilde) {\n                    conditionKeys.add(key);\n                }\n                if (value != null\n                        && !ANY_VALUE.equals(value)\n                        && !value.equals(url.getParameter(startWithTilde ? key.substring(1) : key))) {\n                    result = false;\n                    break;\n                }\n            }\n        }\n        return result;\n    }\n\n    private Set<String> genConditionKeys() {\n        Set<String> conditionKeys = new HashSet<>();\n        conditionKeys.add(CATEGORY_KEY);\n        conditionKeys.add(Constants.CHECK_KEY);\n        conditionKeys.add(DYNAMIC_KEY);\n        conditionKeys.add(ENABLED_KEY);\n        conditionKeys.add(GROUP_KEY);\n        conditionKeys.add(VERSION_KEY);\n        conditionKeys.add(APPLICATION_KEY);\n        conditionKeys.add(SIDE_KEY);\n        conditionKeys.add(CONFIG_VERSION_KEY);\n        conditionKeys.add(COMPATIBLE_CONFIG_KEY);\n        conditionKeys.add(INTERFACES);\n        return conditionKeys;\n    }\n\n    private boolean startWithTilde(String key) {\n        return StringUtils.isNotEmpty(key) && key.startsWith(TILDE);\n    }\n\n    protected abstract URL doConfigure(URL currentUrl, URL configUrl);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfigurator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.absent;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;\n\npublic class AbsentConfigurator extends AbstractConfigurator {\n\n    public AbsentConfigurator(URL url) {\n        super(url);\n    }\n\n    @Override\n    public URL doConfigure(URL currentUrl, URL configUrl) {\n        return currentUrl.addParametersIfAbsent(configUrl.getParameters());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.absent;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.Configurator;\nimport org.apache.dubbo.rpc.cluster.ConfiguratorFactory;\n\n/**\n * AbsentConfiguratorFactory\n *\n */\npublic class AbsentConfiguratorFactory implements ConfiguratorFactory {\n\n    @Override\n    public Configurator getConfigurator(URL url) {\n        return new AbsentConfigurator(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.override;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;\n\npublic class OverrideConfigurator extends AbstractConfigurator {\n    public static final Logger logger = LoggerFactory.getLogger(OverrideConfigurator.class);\n\n    public OverrideConfigurator(URL url) {\n        super(url);\n    }\n\n    @Override\n    public URL doConfigure(URL currentUrl, URL configUrl) {\n        logger.info(\"Start overriding url \" + currentUrl + \" with override url \" + configUrl);\n        return currentUrl.addParameters(configUrl.getParameters());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.override;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.Configurator;\nimport org.apache.dubbo.rpc.cluster.ConfiguratorFactory;\n\n/**\n * OverrideConfiguratorFactory\n *\n */\npublic class OverrideConfiguratorFactory implements ConfiguratorFactory {\n\n    @Override\n    public Configurator getConfigurator(URL url) {\n        return new OverrideConfigurator(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/parser/ConfigParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.parser;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfigItem;\nimport org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;\nimport static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;\nimport static org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig.MATCH_CONDITION;\n\n/**\n * Config parser\n */\npublic class ConfigParser {\n\n    public static List<URL> parseConfigurators(String rawConfig) {\n        // compatible url JsonArray, such as [ \"override://xxx\", \"override://xxx\" ]\n        List<URL> compatibleUrls = parseJsonArray(rawConfig);\n        if (CollectionUtils.isNotEmpty(compatibleUrls)) {\n            return compatibleUrls;\n        }\n\n        List<URL> urls = new ArrayList<>();\n        ConfiguratorConfig configuratorConfig = parseObject(rawConfig);\n\n        String scope = configuratorConfig.getScope();\n        List<ConfigItem> items = configuratorConfig.getConfigs();\n\n        if (ConfiguratorConfig.SCOPE_APPLICATION.equals(scope)) {\n            items.forEach(item -> urls.addAll(appItemToUrls(item, configuratorConfig)));\n        } else {\n            // service scope by default.\n            items.forEach(item -> urls.addAll(serviceItemToUrls(item, configuratorConfig)));\n        }\n\n        return urls;\n    }\n\n    private static List<URL> parseJsonArray(String rawConfig) {\n        List<URL> urls = new ArrayList<>();\n        try {\n            List<String> list = JsonUtils.toJavaList(rawConfig, String.class);\n            if (!CollectionUtils.isEmpty(list)) {\n                list.forEach(u -> urls.add(URL.valueOf(u)));\n            }\n        } catch (Throwable t) {\n            return null;\n        }\n        return urls;\n    }\n\n    private static ConfiguratorConfig parseObject(String rawConfig) {\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Map<String, Object> map = yaml.load(rawConfig);\n        return ConfiguratorConfig.parseFromMap(map);\n    }\n\n    private static List<URL> serviceItemToUrls(ConfigItem item, ConfiguratorConfig config) {\n        List<URL> urls = new ArrayList<>();\n        List<String> addresses = parseAddresses(item);\n\n        addresses.forEach(addr -> {\n            StringBuilder urlBuilder = new StringBuilder();\n            urlBuilder.append(\"override://\").append(addr).append('/');\n\n            urlBuilder.append(appendService(config.getKey()));\n            urlBuilder.append(toParameterString(item));\n\n            parseEnabled(item, config, urlBuilder);\n\n            urlBuilder.append(\"&configVersion=\").append(config.getConfigVersion());\n\n            List<String> apps = item.getApplications();\n            if (CollectionUtils.isNotEmpty(apps)) {\n                apps.forEach(app -> {\n                    StringBuilder tmpUrlBuilder = new StringBuilder(urlBuilder);\n                    urls.add(appendMatchCondition(\n                            URL.valueOf(tmpUrlBuilder\n                                    .append(\"&application=\")\n                                    .append(app)\n                                    .toString()),\n                            item));\n                });\n            } else {\n                urls.add(appendMatchCondition(URL.valueOf(urlBuilder.toString()), item));\n            }\n        });\n\n        return urls;\n    }\n\n    private static List<URL> appItemToUrls(ConfigItem item, ConfiguratorConfig config) {\n        List<URL> urls = new ArrayList<>();\n        List<String> addresses = parseAddresses(item);\n        for (String addr : addresses) {\n            StringBuilder urlBuilder = new StringBuilder();\n            urlBuilder.append(\"override://\").append(addr).append('/');\n            List<String> services = item.getServices();\n            if (services == null) {\n                services = new ArrayList<>();\n            }\n            if (services.isEmpty()) {\n                services.add(\"*\");\n            }\n            for (String s : services) {\n                StringBuilder tmpUrlBuilder = new StringBuilder(urlBuilder);\n                tmpUrlBuilder.append(appendService(s));\n                tmpUrlBuilder.append(toParameterString(item));\n\n                tmpUrlBuilder.append(\"&application=\").append(config.getKey());\n\n                parseEnabled(item, config, tmpUrlBuilder);\n\n                tmpUrlBuilder.append(\"&category=\").append(APP_DYNAMIC_CONFIGURATORS_CATEGORY);\n                tmpUrlBuilder.append(\"&configVersion=\").append(config.getConfigVersion());\n\n                urls.add(appendMatchCondition(URL.valueOf(tmpUrlBuilder.toString()), item));\n            }\n        }\n        return urls;\n    }\n\n    private static String toParameterString(ConfigItem item) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"category=\");\n        sb.append(DYNAMIC_CONFIGURATORS_CATEGORY);\n        if (item.getSide() != null) {\n            sb.append(\"&side=\");\n            sb.append(item.getSide());\n        }\n        Map<String, String> parameters = item.getParameters();\n        if (CollectionUtils.isEmptyMap(parameters)) {\n            throw new IllegalStateException(\"Invalid configurator rule, please specify at least one parameter \"\n                    + \"you want to change in the rule.\");\n        }\n\n        parameters.forEach((k, v) -> {\n            sb.append('&');\n            sb.append(k);\n            sb.append('=');\n            sb.append(v);\n        });\n\n        if (CollectionUtils.isNotEmpty(item.getProviderAddresses())) {\n            sb.append('&');\n            sb.append(OVERRIDE_PROVIDERS_KEY);\n            sb.append('=');\n            sb.append(CollectionUtils.join(item.getProviderAddresses(), \",\"));\n        } else if (PROVIDER.equals(item.getSide())) {\n            sb.append('&');\n            sb.append(OVERRIDE_PROVIDERS_KEY);\n            sb.append('=');\n            sb.append(CollectionUtils.join(parseAddresses(item), \",\"));\n        }\n\n        return sb.toString();\n    }\n\n    private static String appendService(String serviceKey) {\n        StringBuilder sb = new StringBuilder();\n        if (StringUtils.isEmpty(serviceKey)) {\n            throw new IllegalStateException(\"service field in configuration is null.\");\n        }\n\n        String interfaceName = serviceKey;\n        int i = interfaceName.indexOf('/');\n        if (i > 0) {\n            sb.append(\"group=\");\n            sb.append(interfaceName, 0, i);\n            sb.append('&');\n\n            interfaceName = interfaceName.substring(i + 1);\n        }\n        int j = interfaceName.indexOf(':');\n        if (j > 0) {\n            sb.append(\"version=\");\n            sb.append(interfaceName.substring(j + 1));\n            sb.append('&');\n            interfaceName = interfaceName.substring(0, j);\n        }\n        sb.insert(0, interfaceName + \"?\");\n\n        return sb.toString();\n    }\n\n    private static void parseEnabled(ConfigItem item, ConfiguratorConfig config, StringBuilder urlBuilder) {\n        urlBuilder.append(\"&enabled=\");\n        if (item.getType() == null || ConfigItem.GENERAL_TYPE.equals(item.getType())) {\n            urlBuilder.append(config.getEnabled());\n        } else {\n            urlBuilder.append(item.getEnabled());\n        }\n    }\n\n    private static List<String> parseAddresses(ConfigItem item) {\n        List<String> addresses = item.getAddresses();\n        if (addresses == null) {\n            addresses = new ArrayList<>();\n        }\n        if (addresses.isEmpty()) {\n            addresses.add(ANYHOST_VALUE);\n        }\n        return addresses;\n    }\n\n    private static URL appendMatchCondition(URL url, ConfigItem item) {\n        if (item.getMatch() != null) {\n            url = url.putAttribute(MATCH_CONDITION, item.getMatch());\n        }\n        return url;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/parser/model/ConditionMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.parser.model;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.AddressMatch;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.ListStringMatch;\n\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\n\npublic class ConditionMatch {\n    private AddressMatch address;\n    private AddressMatch providerAddress;\n    private ListStringMatch service;\n    private ListStringMatch app;\n    private List<ParamMatch> param;\n\n    public AddressMatch getAddress() {\n        return address;\n    }\n\n    public void setAddress(AddressMatch address) {\n        this.address = address;\n    }\n\n    public AddressMatch getProviderAddress() {\n        return providerAddress;\n    }\n\n    public void setProviderAddress(AddressMatch providerAddress) {\n        this.providerAddress = providerAddress;\n    }\n\n    public ListStringMatch getService() {\n        return service;\n    }\n\n    public void setService(ListStringMatch service) {\n        this.service = service;\n    }\n\n    public ListStringMatch getApp() {\n        return app;\n    }\n\n    public void setApp(ListStringMatch app) {\n        this.app = app;\n    }\n\n    public List<ParamMatch> getParam() {\n        return param;\n    }\n\n    public void setParam(List<ParamMatch> param) {\n        this.param = param;\n    }\n\n    public boolean isMatch(String host, URL url) {\n        if (getAddress() != null && !getAddress().isMatch(host)) {\n            return false;\n        }\n\n        if (getProviderAddress() != null && !getProviderAddress().isMatch(url.getAddress())) {\n            return false;\n        }\n\n        if (getService() != null && !getService().isMatch(url.getServiceKey())) {\n            return false;\n        }\n\n        if (getApp() != null && !getApp().isMatch(url.getParameter(APPLICATION_KEY))) {\n            return false;\n        }\n\n        if (getParam() != null) {\n            for (ParamMatch match : param) {\n                if (!match.isMatch(url)) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        return \"ConditionMatch{\" + \"address='\"\n                + address + '\\'' + \"providerAddress='\"\n                + providerAddress + '\\'' + \", service='\"\n                + service + '\\'' + \", app='\"\n                + app + '\\'' + \", param='\"\n                + param + '\\'' + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/parser/model/ConfigItem.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.parser.model;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.PojoUtils;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RECEIVE_RULE;\n\npublic class ConfigItem {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConfigItem.class);\n\n    public static final String GENERAL_TYPE = \"general\";\n    public static final String WEIGHT_TYPE = \"weight\";\n    public static final String BALANCING_TYPE = \"balancing\";\n    public static final String DISABLED_TYPE = \"disabled\";\n    public static final String CONFIG_ITEM_TYPE = \"type\";\n    public static final String ENABLED_KEY = \"enabled\";\n    public static final String ADDRESSES_KEY = \"addresses\";\n    public static final String PROVIDER_ADDRESSES_KEY = \"providerAddresses\";\n    public static final String SERVICES_KEY = \"services\";\n    public static final String APPLICATIONS_KEY = \"applications\";\n    public static final String PARAMETERS_KEY = \"parameters\";\n    public static final String MATCH_KEY = \"match\";\n    public static final String SIDE_KEY = \"side\";\n\n    private String type;\n    private Boolean enabled;\n    private List<String> addresses;\n    private List<String> providerAddresses;\n    private List<String> services;\n    private List<String> applications;\n    private Map<String, String> parameters;\n    private ConditionMatch match;\n    private String side;\n\n    @SuppressWarnings(\"unchecked\")\n    public static ConfigItem parseFromMap(Map<String, Object> map) {\n        ConfigItem configItem = new ConfigItem();\n        configItem.setType((String) map.get(CONFIG_ITEM_TYPE));\n\n        Object enabled = map.get(ENABLED_KEY);\n        if (enabled != null) {\n            configItem.setEnabled(Boolean.parseBoolean(enabled.toString()));\n        }\n\n        Object addresses = map.get(ADDRESSES_KEY);\n        if (addresses != null && List.class.isAssignableFrom(addresses.getClass())) {\n            configItem.setAddresses(\n                    ((List<Object>) addresses).stream().map(String::valueOf).collect(Collectors.toList()));\n        }\n\n        Object providerAddresses = map.get(PROVIDER_ADDRESSES_KEY);\n        if (providerAddresses != null && List.class.isAssignableFrom(providerAddresses.getClass())) {\n            configItem.setProviderAddresses(((List<Object>) providerAddresses)\n                    .stream().map(String::valueOf).collect(Collectors.toList()));\n        }\n\n        Object services = map.get(SERVICES_KEY);\n        if (services != null && List.class.isAssignableFrom(services.getClass())) {\n            configItem.setServices(\n                    ((List<Object>) services).stream().map(String::valueOf).collect(Collectors.toList()));\n        }\n\n        Object applications = map.get(APPLICATIONS_KEY);\n        if (applications != null && List.class.isAssignableFrom(applications.getClass())) {\n            configItem.setApplications(\n                    ((List<Object>) applications).stream().map(String::valueOf).collect(Collectors.toList()));\n        }\n\n        Object parameters = map.get(PARAMETERS_KEY);\n        if (parameters != null && Map.class.isAssignableFrom(parameters.getClass())) {\n            configItem.setParameters(((Map<String, Object>) parameters)\n                    .entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()\n                            .toString())));\n        }\n\n        try {\n            Object match = map.get(MATCH_KEY);\n            if (match != null && Map.class.isAssignableFrom(match.getClass())) {\n                configItem.setMatch(PojoUtils.mapToPojo((Map<String, Object>) match, ConditionMatch.class));\n            }\n        } catch (Throwable t) {\n            logger.error(\n                    CLUSTER_FAILED_RECEIVE_RULE,\n                    \" Failed to parse dynamic configuration rule\",\n                    String.valueOf(map.get(MATCH_KEY)),\n                    \"Error occurred when parsing rule component.\",\n                    t);\n        }\n\n        configItem.setSide((String) map.get(SIDE_KEY));\n        return configItem;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public List<String> getAddresses() {\n        return addresses;\n    }\n\n    public void setAddresses(List<String> addresses) {\n        this.addresses = addresses;\n    }\n\n    public List<String> getServices() {\n        return services;\n    }\n\n    public void setServices(List<String> services) {\n        this.services = services;\n    }\n\n    public List<String> getApplications() {\n        return applications;\n    }\n\n    public void setApplications(List<String> applications) {\n        this.applications = applications;\n    }\n\n    public List<String> getProviderAddresses() {\n        return providerAddresses;\n    }\n\n    public void setProviderAddresses(List<String> providerAddresses) {\n        this.providerAddresses = providerAddresses;\n    }\n\n    public Map<String, String> getParameters() {\n        return parameters;\n    }\n\n    public void setParameters(Map<String, String> parameters) {\n        this.parameters = parameters;\n    }\n\n    public String getSide() {\n        return side;\n    }\n\n    public void setSide(String side) {\n        this.side = side;\n    }\n\n    public ConditionMatch getMatch() {\n        return match;\n    }\n\n    public void setMatch(ConditionMatch match) {\n        this.match = match;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/parser/model/ConfiguratorConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.parser.model;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\npublic class ConfiguratorConfig {\n    public static final String MATCH_CONDITION = \"MATCH_CONDITION\";\n    public static final String SCOPE_SERVICE = \"service\";\n    public static final String SCOPE_APPLICATION = \"application\";\n    public static final String CONFIG_VERSION_KEY = \"configVersion\";\n    public static final String SCOPE_KEY = \"scope\";\n    public static final String CONFIG_KEY = \"key\";\n    public static final String ENABLED_KEY = \"enabled\";\n    public static final String CONFIGS_KEY = \"configs\";\n    private String configVersion;\n    private String scope;\n    private String key;\n    private Boolean enabled = true;\n    private List<ConfigItem> configs;\n\n    @SuppressWarnings(\"unchecked\")\n    public static ConfiguratorConfig parseFromMap(Map<String, Object> map) {\n        ConfiguratorConfig configuratorConfig = new ConfiguratorConfig();\n        configuratorConfig.setConfigVersion((String) map.get(CONFIG_VERSION_KEY));\n        configuratorConfig.setScope((String) map.get(SCOPE_KEY));\n        configuratorConfig.setKey((String) map.get(CONFIG_KEY));\n\n        Object enabled = map.get(ENABLED_KEY);\n        if (enabled != null) {\n            configuratorConfig.setEnabled(Boolean.parseBoolean(enabled.toString()));\n        }\n\n        Object configs = map.get(CONFIGS_KEY);\n        if (configs != null && List.class.isAssignableFrom(configs.getClass())) {\n            configuratorConfig.setConfigs(((List<Map<String, Object>>) configs)\n                    .stream().map(ConfigItem::parseFromMap).collect(Collectors.toList()));\n        }\n\n        return configuratorConfig;\n    }\n\n    public String getConfigVersion() {\n        return configVersion;\n    }\n\n    public void setConfigVersion(String configVersion) {\n        this.configVersion = configVersion;\n    }\n\n    public String getScope() {\n        return scope;\n    }\n\n    public void setScope(String scope) {\n        this.scope = scope;\n    }\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public List<ConfigItem> getConfigs() {\n        return configs;\n    }\n\n    public void setConfigs(List<ConfigItem> configs) {\n        this.configs = configs;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/parser/model/ParamMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.parser.model;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.StringMatch;\n\npublic class ParamMatch {\n    private String key;\n    private StringMatch value;\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public StringMatch getValue() {\n        return value;\n    }\n\n    public void setValue(StringMatch value) {\n        this.value = value;\n    }\n\n    public boolean isMatch(URL url) {\n        if (key == null || value == null) {\n            return false;\n        }\n\n        String input = url.getParameter(key);\n        return value.isMatch(input);\n    }\n\n    @Override\n    public String toString() {\n        return \"ParamMatch{\" + \"key='\" + key + '\\'' + \", value='\" + value + '\\'' + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.directory;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.LockUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.registry.event.RegistryEvent;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.Router;\nimport org.apache.dubbo.rpc.cluster.RouterChain;\nimport org.apache.dubbo.rpc.cluster.SingleRouterChain;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.support.ClusterUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RECONNECT_TASK_PERIOD;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RECONNECT_TASK_TRY_COUNT;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RECONNECT_TASK_PERIOD;\nimport static org.apache.dubbo.common.constants.CommonConstants.RECONNECT_TASK_TRY_COUNT;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTER_IP_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_NO_VALID_PROVIDER;\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\nimport static org.apache.dubbo.rpc.cluster.Constants.CONSUMER_URL_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\n\n/**\n * Abstract implementation of Directory: Invoker list returned from this Directory's list method have been filtered by Routers\n */\npublic abstract class AbstractDirectory<T> implements Directory<T> {\n\n    // logger\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractDirectory.class);\n\n    private final URL url;\n\n    private volatile boolean destroyed = false;\n\n    protected volatile URL consumerUrl;\n\n    protected RouterChain<T> routerChain;\n\n    protected final Map<String, String> queryMap;\n\n    /**\n     * Invokers initialized flag.\n     */\n    private volatile boolean invokersInitialized = false;\n\n    /**\n     * All invokers from registry\n     */\n    private volatile BitList<Invoker<T>> invokers = BitList.emptyList();\n\n    /**\n     * Valid Invoker. All invokers from registry exclude unavailable and disabled invokers.\n     */\n    private volatile BitList<Invoker<T>> validInvokers = BitList.emptyList();\n\n    /**\n     * Waiting to reconnect invokers.\n     */\n    protected volatile List<Invoker<T>> invokersToReconnect = new CopyOnWriteArrayList<>();\n\n    /**\n     * Disabled Invokers. Will not be recovered in reconnect task, but be recovered if registry remove it.\n     */\n    protected final Set<Invoker<T>> disabledInvokers = new ConcurrentHashSet<>();\n\n    private final Semaphore checkConnectivityPermit = new Semaphore(1);\n\n    private final ScheduledExecutorService connectivityExecutor;\n\n    private volatile ScheduledFuture<?> connectivityCheckFuture;\n\n    private final ReentrantReadWriteLock invokerRefreshLock = new ReentrantReadWriteLock(true);\n\n    private final ReentrantReadWriteLock.ReadLock invokerRefreshReadLock = invokerRefreshLock.readLock();\n    private final ReentrantReadWriteLock.WriteLock invokerRefreshWriteLock = invokerRefreshLock.writeLock();\n\n    /**\n     * The max count of invokers for each reconnect task select to try to reconnect.\n     */\n    private final int reconnectTaskTryCount;\n\n    /**\n     * The period of reconnect task if needed. (in ms)\n     */\n    private final int reconnectTaskPeriod;\n\n    private ApplicationModel applicationModel;\n\n    public AbstractDirectory(URL url) {\n        this(url, null, false);\n    }\n\n    public AbstractDirectory(URL url, boolean isUrlFromRegistry) {\n        this(url, null, isUrlFromRegistry);\n    }\n\n    public AbstractDirectory(URL url, RouterChain<T> routerChain, boolean isUrlFromRegistry) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n\n        this.url = url.removeAttribute(REFER_KEY).removeAttribute(MONITOR_KEY);\n\n        Map<String, String> queryMap;\n        Object referParams = url.getAttribute(REFER_KEY);\n        if (referParams instanceof Map) {\n            queryMap = (Map<String, String>) referParams;\n            this.consumerUrl = (URL) url.getAttribute(CONSUMER_URL_KEY);\n        } else {\n            queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));\n        }\n\n        // remove some local only parameters\n        applicationModel = url.getOrDefaultApplicationModel();\n        this.queryMap =\n                applicationModel.getBeanFactory().getBean(ClusterUtils.class).mergeLocalParams(queryMap);\n\n        if (consumerUrl == null) {\n            String host =\n                    isNotEmpty(queryMap.get(REGISTER_IP_KEY)) ? queryMap.get(REGISTER_IP_KEY) : this.url.getHost();\n            String path = isNotEmpty(queryMap.get(PATH_KEY)) ? queryMap.get(PATH_KEY) : queryMap.get(INTERFACE_KEY);\n            String consumedProtocol = isNotEmpty(queryMap.get(PROTOCOL_KEY)) ? queryMap.get(PROTOCOL_KEY) : CONSUMER;\n\n            URL consumerUrlFrom = this.url\n                    .setHost(host)\n                    .setPort(0)\n                    .setProtocol(consumedProtocol)\n                    .setPath(path);\n            if (isUrlFromRegistry) {\n                // reserve parameters if url is already a consumer url\n                consumerUrlFrom = consumerUrlFrom.clearParameters();\n            }\n            this.consumerUrl = consumerUrlFrom.addParameters(queryMap);\n        }\n\n        this.connectivityExecutor = applicationModel\n                .getFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getConnectivityScheduledExecutor();\n        Configuration configuration = ConfigurationUtils.getGlobalConfiguration(url.getOrDefaultModuleModel());\n        this.reconnectTaskTryCount = configuration.getInt(RECONNECT_TASK_TRY_COUNT, DEFAULT_RECONNECT_TASK_TRY_COUNT);\n        this.reconnectTaskPeriod = configuration.getInt(RECONNECT_TASK_PERIOD, DEFAULT_RECONNECT_TASK_PERIOD);\n        setRouterChain(routerChain);\n    }\n\n    @Override\n    public List<Invoker<T>> list(Invocation invocation) throws RpcException {\n        if (destroyed) {\n            throw new RpcException(\n                    \"Directory of type \" + this.getClass().getSimpleName() + \" already destroyed for service \"\n                            + getConsumerUrl().getServiceKey() + \" from registry \" + getUrl());\n        }\n\n        BitList<Invoker<T>> availableInvokers;\n        SingleRouterChain<T> singleChain = null;\n        try {\n            if (routerChain != null) {\n                routerChain.getLock().readLock().lock();\n            }\n            boolean lockAcquired = false;\n            try {\n                if (!invokerRefreshReadLock.tryLock(LockUtils.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)) {\n                    throw new RpcException(\n                            \"Failed to acquire read lock on invokerRefreshLock within timeout. \" + \"Timeout: \"\n                                    + LockUtils.DEFAULT_TIMEOUT + \"ms, \" + \"Lock state: [readLockHeld=\"\n                                    + invokerRefreshLock.getReadLockCount() + \", writeLockHeld=\"\n                                    + invokerRefreshLock.isWriteLocked() + \", writeLockHeldByCurrentThread=\"\n                                    + invokerRefreshLock.isWriteLockedByCurrentThread() + \"], Service: \"\n                                    + getConsumerUrl().getServiceKey());\n                }\n                lockAcquired = true;\n                // use clone to avoid being modified at doList().\n                if (invokersInitialized) {\n                    availableInvokers = validInvokers.clone();\n                } else {\n                    availableInvokers = invokers.clone();\n                }\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                throw new RpcException(\n                        \"Interrupted while acquiring read lock for invoker access, cause: \" + e.getMessage(), e);\n            } finally {\n                if (lockAcquired) {\n                    invokerRefreshReadLock.unlock();\n                }\n            }\n\n            if (routerChain != null) {\n                singleChain = routerChain.getSingleChain(getConsumerUrl(), availableInvokers, invocation);\n                singleChain.getLock().readLock().lock();\n            }\n            List<Invoker<T>> routedResult = doList(singleChain, availableInvokers, invocation);\n            if (routedResult.isEmpty()) {\n                // 2-2 - No provider available.\n\n                logger.warn(\n                        CLUSTER_NO_VALID_PROVIDER,\n                        \"provider server or registry center crashed\",\n                        \"\",\n                        \"No provider available after connectivity filter for the service \"\n                                + getConsumerUrl().getServiceKey()\n                                + \" All routed invokers' size: \" + routedResult.size()\n                                + \" from registry \" + this\n                                + \" on the consumer \" + NetUtils.getLocalHost()\n                                + \" using the dubbo version \" + Version.getVersion() + \".\");\n            }\n            return Collections.unmodifiableList(routedResult);\n        } finally {\n            if (singleChain != null) {\n                singleChain.getLock().readLock().unlock();\n            }\n            if (routerChain != null) {\n                routerChain.getLock().readLock().unlock();\n            }\n        }\n    }\n\n    @Override\n    public URL getUrl() {\n        return url;\n    }\n\n    public RouterChain<T> getRouterChain() {\n        return routerChain;\n    }\n\n    public void setRouterChain(RouterChain<T> routerChain) {\n        this.routerChain = routerChain;\n    }\n\n    protected void addRouters(List<Router> routers) {\n        routers = routers == null ? Collections.emptyList() : routers;\n        routerChain.addRouters(routers);\n    }\n\n    public URL getConsumerUrl() {\n        return consumerUrl;\n    }\n\n    public void setConsumerUrl(URL consumerUrl) {\n        this.consumerUrl = consumerUrl;\n    }\n\n    @Override\n    public boolean isDestroyed() {\n        return destroyed;\n    }\n\n    @Override\n    public void destroy() {\n        destroyed = true;\n        destroyInvokers();\n        invokersToReconnect.clear();\n        disabledInvokers.clear();\n    }\n\n    @Override\n    public void discordAddresses() {\n        // do nothing by default\n    }\n\n    @Override\n    public void addInvalidateInvoker(Invoker<T> invoker) {\n        LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n            // 1. remove this invoker from validInvokers list, this invoker will not be listed in the next time\n            if (removeValidInvoker(invoker)) {\n                // 2. add this invoker to reconnect list\n                invokersToReconnect.add(invoker);\n                // 3. try start check connectivity task\n                checkConnectivity();\n\n                logger.info(\"The invoker \" + invoker.getUrl()\n                        + \" has been added to invalidate list due to connectivity problem. \"\n                        + \"Will trying to reconnect to it in the background.\");\n            }\n        });\n    }\n\n    public void checkConnectivity() {\n        // try to submit task, to ensure there is only one task at most for each directory\n        if (checkConnectivityPermit.tryAcquire()) {\n            this.connectivityCheckFuture = connectivityExecutor.schedule(\n                    () -> {\n                        try {\n                            if (isDestroyed()) {\n                                return;\n                            }\n                            RpcContext.getServiceContext().setConsumerUrl(getConsumerUrl());\n                            List<Invoker<T>> needDeleteList = new ArrayList<>();\n                            List<Invoker<T>> invokersToTry = new ArrayList<>();\n\n                            // 1. pick invokers from invokersToReconnect\n                            // limit max reconnectTaskTryCount, prevent this task hang up all the connectivityExecutor\n                            // for long time\n                            LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n                                if (invokersToReconnect.size() < reconnectTaskTryCount) {\n                                    invokersToTry.addAll(invokersToReconnect);\n                                } else {\n                                    for (int i = 0; i < reconnectTaskTryCount; i++) {\n                                        Invoker<T> tInvoker = invokersToReconnect.get(\n                                                ThreadLocalRandom.current().nextInt(invokersToReconnect.size()));\n                                        if (!invokersToTry.contains(tInvoker)) {\n                                            // ignore if is selected, invokersToTry's size is always smaller than\n                                            // reconnectTaskTryCount + 1\n                                            invokersToTry.add(tInvoker);\n                                        }\n                                    }\n                                }\n                            });\n\n                            // 2. try to check the invoker's status\n                            for (Invoker<T> invoker : invokersToTry) {\n                                AtomicBoolean invokerExist = new AtomicBoolean(false);\n                                LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n                                    invokerExist.set(invokers.contains(invoker));\n                                });\n                                // Should not lock here, `invoker.isAvailable` may need some time to check\n                                if (invokerExist.get()) {\n                                    if (invoker.isAvailable()) {\n                                        needDeleteList.add(invoker);\n                                    }\n                                } else {\n                                    needDeleteList.add(invoker);\n                                }\n                            }\n\n                            // 3. recover valid invoker\n                            LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n                                for (Invoker<T> tInvoker : needDeleteList) {\n                                    if (invokers.contains(tInvoker)) {\n                                        addValidInvoker(tInvoker);\n                                        logger.info(\"Recover service address: \" + tInvoker.getUrl()\n                                                + \"  from invalid list.\");\n                                    } else {\n                                        logger.info(\n                                                \"The invoker \" + tInvoker.getUrl()\n                                                        + \" has been removed from invokers list. Will remove it in reconnect list.\");\n                                    }\n                                    invokersToReconnect.remove(tInvoker);\n                                }\n                            });\n                        } catch (Throwable t) {\n                            logger.error(\n                                    LoggerCodeConstants.INTERNAL_ERROR,\n                                    \"\",\n                                    \"\",\n                                    \"Error occurred when check connectivity. \",\n                                    t);\n                        } finally {\n                            checkConnectivityPermit.release();\n                        }\n\n                        // 4. submit new task if it has more to recover\n                        LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n                            if (!invokersToReconnect.isEmpty()) {\n                                checkConnectivity();\n                            }\n                        });\n                        MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(\n                                applicationModel, getSummary(), getDirectoryMeta()));\n                    },\n                    reconnectTaskPeriod,\n                    TimeUnit.MILLISECONDS);\n        }\n        MetricsEventBus.publish(\n                RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));\n    }\n\n    /**\n     * Refresh invokers from total invokers\n     * 1. all the invokers in need to reconnect list should be removed in the valid invokers list\n     * 2. all the invokers in disabled invokers list should be removed in the valid invokers list\n     * 3. all the invokers disappeared from total invokers should be removed in the need to reconnect list\n     * 4. all the invokers disappeared from total invokers should be removed in the disabled invokers list\n     */\n    public void refreshInvoker() {\n        LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n            if (invokersInitialized) {\n                refreshInvokerInternal();\n            }\n        });\n        MetricsEventBus.publish(\n                RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));\n    }\n\n    protected Map<String, String> getDirectoryMeta() {\n        return Collections.emptyMap();\n    }\n\n    private void refreshInvokerInternal() {\n        BitList<Invoker<T>> copiedInvokers = invokers.clone();\n        refreshInvokers(copiedInvokers, invokersToReconnect);\n        refreshInvokers(copiedInvokers, disabledInvokers);\n        validInvokers = copiedInvokers;\n    }\n\n    private void refreshInvokers(BitList<Invoker<T>> targetInvokers, Collection<Invoker<T>> invokersToRemove) {\n        List<Invoker<T>> needToRemove = new LinkedList<>();\n        for (Invoker<T> tInvoker : invokersToRemove) {\n            if (targetInvokers.contains(tInvoker)) {\n                targetInvokers.remove(tInvoker);\n            } else {\n                needToRemove.add(tInvoker);\n            }\n        }\n        invokersToRemove.removeAll(needToRemove);\n    }\n\n    @Override\n    public void addDisabledInvoker(Invoker<T> invoker) {\n        LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n            if (invokers.contains(invoker)) {\n                disabledInvokers.add(invoker);\n                removeValidInvoker(invoker);\n                logger.info(\"Disable service address: \" + invoker.getUrl() + \".\");\n            }\n        });\n        MetricsEventBus.publish(\n                RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));\n    }\n\n    @Override\n    public void recoverDisabledInvoker(Invoker<T> invoker) {\n        LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n            if (disabledInvokers.remove(invoker)) {\n                try {\n                    addValidInvoker(invoker);\n                    logger.info(\"Recover service address: \" + invoker.getUrl() + \"  from disabled list.\");\n                } catch (Throwable ignore) {\n\n                }\n            }\n        });\n        MetricsEventBus.publish(\n                RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));\n    }\n\n    protected final void refreshRouter(BitList<Invoker<T>> newlyInvokers, Runnable switchAction) {\n        try {\n            routerChain.setInvokers(newlyInvokers.clone(), switchAction);\n        } catch (Throwable t) {\n            logger.error(\n                    LoggerCodeConstants.INTERNAL_ERROR,\n                    \"\",\n                    \"\",\n                    \"Error occurred when refreshing router chain. \" + \"The addresses from notification: \"\n                            + newlyInvokers.stream()\n                                    .map(Invoker::getUrl)\n                                    .map(URL::getAddress)\n                                    .collect(Collectors.joining(\", \")),\n                    t);\n\n            throw t;\n        }\n    }\n\n    /**\n     * for ut only\n     */\n    @Deprecated\n    public Semaphore getCheckConnectivityPermit() {\n        return checkConnectivityPermit;\n    }\n\n    /**\n     * for ut only\n     */\n    @Deprecated\n    public ScheduledFuture<?> getConnectivityCheckFuture() {\n        return connectivityCheckFuture;\n    }\n\n    public BitList<Invoker<T>> getInvokers() {\n        // return clone to avoid being modified.\n        return invokers.clone();\n    }\n\n    public BitList<Invoker<T>> getValidInvokers() {\n        // return clone to avoid being modified.\n        return validInvokers.clone();\n    }\n\n    public List<Invoker<T>> getInvokersToReconnect() {\n        return invokersToReconnect;\n    }\n\n    public Set<Invoker<T>> getDisabledInvokers() {\n        return disabledInvokers;\n    }\n\n    protected void setInvokers(BitList<Invoker<T>> invokers) {\n        LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n            this.invokers = invokers;\n            refreshInvokerInternal();\n            this.invokersInitialized = true;\n        });\n\n        MetricsEventBus.publish(\n                RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));\n    }\n\n    protected void destroyInvokers() {\n        // set empty instead of clearing to support concurrent access.\n        LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n            this.invokers = BitList.emptyList();\n            this.validInvokers = BitList.emptyList();\n            this.invokersInitialized = false;\n        });\n    }\n\n    private boolean addValidInvoker(Invoker<T> invoker) {\n        AtomicBoolean result = new AtomicBoolean(false);\n        LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n            result.set(this.validInvokers.add(invoker));\n        });\n        MetricsEventBus.publish(\n                RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));\n        return result.get();\n    }\n\n    private boolean removeValidInvoker(Invoker<T> invoker) {\n        AtomicBoolean result = new AtomicBoolean(false);\n        LockUtils.safeLock(invokerRefreshWriteLock, LockUtils.DEFAULT_TIMEOUT, () -> {\n            result.set(this.validInvokers.remove(invoker));\n        });\n        MetricsEventBus.publish(\n                RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));\n        return result.get();\n    }\n\n    protected abstract List<Invoker<T>> doList(\n            SingleRouterChain<T> singleRouterChain, BitList<Invoker<T>> invokers, Invocation invocation)\n            throws RpcException;\n\n    protected String joinValidInvokerAddresses() {\n        BitList<Invoker<T>> validInvokers = getValidInvokers().clone();\n        if (validInvokers.isEmpty()) {\n            return \"empty\";\n        }\n        return validInvokers.stream()\n                .limit(5)\n                .map(Invoker::getUrl)\n                .map(URL::getAddress)\n                .collect(Collectors.joining(\",\"));\n    }\n\n    private Map<MetricsKey, Map<String, Integer>> getSummary() {\n        Map<MetricsKey, Map<String, Integer>> summaryMap = new HashMap<>();\n\n        summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_VALID, groupByServiceKey(getValidInvokers()));\n        summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_DISABLE, groupByServiceKey(getDisabledInvokers()));\n        summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_TO_RECONNECT, groupByServiceKey(getInvokersToReconnect()));\n        summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_ALL, groupByServiceKey(getInvokers()));\n        return summaryMap;\n    }\n\n    private Map<String, Integer> groupByServiceKey(Collection<Invoker<T>> invokers) {\n        return Collections.singletonMap(getConsumerUrl().getServiceKey(), invokers.size());\n    }\n\n    @Override\n    public String toString() {\n        return \"Directory(\" + \"invokers: \"\n                + invokers.size() + \"[\"\n                + invokers.stream()\n                        .map(Invoker::getUrl)\n                        .map(URL::getAddress)\n                        .limit(3)\n                        .collect(Collectors.joining(\", \"))\n                + \"]\" + \", validInvokers: \"\n                + validInvokers.size() + \"[\"\n                + validInvokers.stream()\n                        .map(Invoker::getUrl)\n                        .map(URL::getAddress)\n                        .limit(3)\n                        .collect(Collectors.joining(\", \"))\n                + \"]\" + \", invokersToReconnect: \"\n                + invokersToReconnect.size() + \"[\"\n                + invokersToReconnect.stream()\n                        .map(Invoker::getUrl)\n                        .map(URL::getAddress)\n                        .limit(3)\n                        .collect(Collectors.joining(\", \"))\n                + \"]\" + ')';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.directory;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.RouterChain;\nimport org.apache.dubbo.rpc.cluster.SingleRouterChain;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_SITE_SELECTION;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;\n\n/**\n * StaticDirectory\n */\npublic class StaticDirectory<T> extends AbstractDirectory<T> {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(StaticDirectory.class);\n    private final Class<T> interfaceClass;\n\n    public StaticDirectory(List<Invoker<T>> invokers) {\n        this(null, invokers, null);\n    }\n\n    public StaticDirectory(List<Invoker<T>> invokers, RouterChain<T> routerChain) {\n        this(null, invokers, routerChain);\n    }\n\n    public StaticDirectory(URL url, List<Invoker<T>> invokers) {\n        this(url, invokers, null);\n    }\n\n    public StaticDirectory(URL url, List<Invoker<T>> invokers, RouterChain<T> routerChain) {\n        super(\n                url == null && CollectionUtils.isNotEmpty(invokers)\n                        ? invokers.get(0).getUrl()\n                        : url,\n                routerChain,\n                false);\n        if (CollectionUtils.isEmpty(invokers)) {\n            throw new IllegalArgumentException(\"invokers == null\");\n        }\n        this.setInvokers(new BitList<>(invokers));\n        this.interfaceClass = invokers.get(0).getInterface();\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return interfaceClass;\n    }\n\n    @Override\n    public List<Invoker<T>> getAllInvokers() {\n        return getInvokers();\n    }\n\n    @Override\n    public boolean isAvailable() {\n        if (isDestroyed()) {\n            return false;\n        }\n        for (Invoker<T> invoker : getValidInvokers()) {\n            if (invoker.isAvailable()) {\n                return true;\n            } else {\n                addInvalidateInvoker(invoker);\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public void destroy() {\n        if (isDestroyed()) {\n            return;\n        }\n        for (Invoker<T> invoker : getInvokers()) {\n            invoker.destroy();\n        }\n        super.destroy();\n    }\n\n    public void buildRouterChain() {\n        RouterChain<T> routerChain = RouterChain.buildChain(getInterface(), getUrl());\n        routerChain.setInvokers(getInvokers(), () -> {});\n        this.setRouterChain(routerChain);\n    }\n\n    public void notify(List<Invoker<T>> invokers) {\n        BitList<Invoker<T>> bitList = new BitList<>(invokers);\n        if (routerChain != null) {\n            refreshRouter(bitList.clone(), () -> this.setInvokers(bitList));\n        } else {\n            this.setInvokers(bitList);\n        }\n    }\n\n    @Override\n    protected List<Invoker<T>> doList(\n            SingleRouterChain<T> singleRouterChain, BitList<Invoker<T>> invokers, Invocation invocation)\n            throws RpcException {\n        if (singleRouterChain != null) {\n            try {\n                List<Invoker<T>> finalInvokers = singleRouterChain.route(getConsumerUrl(), invokers, invocation);\n                return finalInvokers == null ? BitList.emptyList() : finalInvokers;\n            } catch (Throwable t) {\n                logger.error(\n                        CLUSTER_FAILED_SITE_SELECTION,\n                        \"Failed to execute router\",\n                        \"\",\n                        \"Failed to execute router: \" + getUrl() + \", cause: \" + t.getMessage(),\n                        t);\n                return BitList.emptyList();\n            }\n        }\n        return invokers;\n    }\n\n    @Override\n    protected Map<String, String> getDirectoryMeta() {\n        Map<String, String> metas = new HashMap<>();\n        metas.put(REGISTRY_KEY, \"static\");\n        metas.put(REGISTER_MODE_KEY, \"static\");\n        return metas;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/DefaultFilterChainBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.ExtensionDirector;\nimport org.apache.dubbo.common.extension.support.ActivateComparator;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\n\n@Activate\npublic class DefaultFilterChainBuilder implements FilterChainBuilder {\n\n    /**\n     * build consumer/provider filter chain\n     */\n    @Override\n    public <T> Invoker<T> buildInvokerChain(final Invoker<T> originalInvoker, String key, String group) {\n        Invoker<T> last = originalInvoker;\n        URL url = originalInvoker.getUrl();\n        List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);\n        List<Filter> filters;\n        if (moduleModels != null && moduleModels.size() == 1) {\n            filters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0))\n                    .getActivateExtension(url, key, group);\n        } else if (moduleModels != null && moduleModels.size() > 1) {\n            filters = new ArrayList<>();\n            List<ExtensionDirector> directors = new ArrayList<>();\n            for (ModuleModel moduleModel : moduleModels) {\n                List<Filter> tempFilters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModel)\n                        .getActivateExtension(url, key, group);\n                filters.addAll(tempFilters);\n                directors.add(moduleModel.getExtensionDirector());\n            }\n            filters = sortingAndDeduplication(filters, directors);\n\n        } else {\n            filters = ScopeModelUtil.getExtensionLoader(Filter.class, null).getActivateExtension(url, key, group);\n        }\n\n        if (!CollectionUtils.isEmpty(filters)) {\n            for (int i = filters.size() - 1; i >= 0; i--) {\n                final Filter filter = filters.get(i);\n                final Invoker<T> next = last;\n                last = new CopyOfFilterChainNode<>(originalInvoker, next, filter);\n            }\n            return new CallbackRegistrationInvoker<>(last, filters);\n        }\n\n        return last;\n    }\n\n    /**\n     * build consumer cluster filter chain\n     */\n    @Override\n    public <T> ClusterInvoker<T> buildClusterInvokerChain(\n            final ClusterInvoker<T> originalInvoker, String key, String group) {\n        ClusterInvoker<T> last = originalInvoker;\n        URL url = originalInvoker.getUrl();\n        List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);\n        List<ClusterFilter> filters;\n        if (moduleModels != null && moduleModels.size() == 1) {\n            filters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModels.get(0))\n                    .getActivateExtension(url, key, group);\n        } else if (moduleModels != null && moduleModels.size() > 1) {\n            filters = new ArrayList<>();\n            List<ExtensionDirector> directors = new ArrayList<>();\n            for (ModuleModel moduleModel : moduleModels) {\n                List<ClusterFilter> tempFilters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModel)\n                        .getActivateExtension(url, key, group);\n                filters.addAll(tempFilters);\n                directors.add(moduleModel.getExtensionDirector());\n            }\n            filters = sortingAndDeduplication(filters, directors);\n\n        } else {\n            filters =\n                    ScopeModelUtil.getExtensionLoader(ClusterFilter.class, null).getActivateExtension(url, key, group);\n        }\n\n        if (!CollectionUtils.isEmpty(filters)) {\n            for (int i = filters.size() - 1; i >= 0; i--) {\n                final ClusterFilter filter = filters.get(i);\n                final Invoker<T> next = last;\n                last = new CopyOfClusterFilterChainNode<>(originalInvoker, next, filter);\n            }\n            return new ClusterCallbackRegistrationInvoker<>(originalInvoker, last, filters);\n        }\n\n        return last;\n    }\n\n    private <T> List<T> sortingAndDeduplication(List<T> filters, List<ExtensionDirector> directors) {\n        Map<Class<?>, T> filtersSet = new TreeMap<>(new ActivateComparator(directors));\n        for (T filter : filters) {\n            filtersSet.putIfAbsent(filter.getClass(), filter);\n        }\n        return new ArrayList<>(filtersSet.values());\n    }\n\n    /**\n     * When the application-level service registration and discovery strategy is adopted, the URL will be of type InstanceAddressURL,\n     * and InstanceAddressURL belongs to the application layer and holds the ApplicationModel,\n     * but the filter is at the module layer and holds the ModuleModel,\n     * so it needs to be based on the url in the ScopeModel type to parse out all the moduleModels held by the url\n     * to obtain the filter configuration.\n     *\n     * @param url URL\n     * @return All ModuleModels in the url\n     */\n    private List<ModuleModel> getModuleModelsFromUrl(URL url) {\n        List<ModuleModel> moduleModels = null;\n        ScopeModel scopeModel = url.getScopeModel();\n        if (scopeModel instanceof ApplicationModel) {\n            moduleModels = ((ApplicationModel) scopeModel).getPubModuleModels();\n        } else if (scopeModel instanceof ModuleModel) {\n            moduleModels = new ArrayList<>();\n            moduleModels.add((ModuleModel) scopeModel);\n        }\n        return moduleModels;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/FilterChainBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nimport org.apache.dubbo.common.Experimental;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.BaseFilter;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.InvocationProfilerUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.ListenableFilter;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_EXECUTE_FILTER_EXCEPTION;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.extension.ExtensionScope.APPLICATION;\n\n@SPI(value = \"default\", scope = APPLICATION)\npublic interface FilterChainBuilder {\n    /**\n     * build consumer/provider filter chain\n     */\n    <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group);\n\n    /**\n     * build consumer cluster filter chain\n     */\n    <T> ClusterInvoker<T> buildClusterInvokerChain(final ClusterInvoker<T> invoker, String key, String group);\n\n    /**\n     * Works on provider side\n     *\n     * @param <T>\n     * @param <TYPE>\n     */\n    class FilterChainNode<T, TYPE extends Invoker<T>, FILTER extends BaseFilter> implements Invoker<T> {\n        TYPE originalInvoker;\n        Invoker<T> nextNode;\n        FILTER filter;\n\n        public FilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {\n            this.originalInvoker = originalInvoker;\n            this.nextNode = nextNode;\n            this.filter = filter;\n        }\n\n        public TYPE getOriginalInvoker() {\n            return originalInvoker;\n        }\n\n        @Override\n        public Class<T> getInterface() {\n            return originalInvoker.getInterface();\n        }\n\n        @Override\n        public URL getUrl() {\n            return originalInvoker.getUrl();\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return originalInvoker.isAvailable();\n        }\n\n        @Override\n        public Result invoke(Invocation invocation) throws RpcException {\n            Result asyncResult;\n            try {\n                InvocationProfilerUtils.enterDetailProfiler(\n                        invocation, () -> \"Filter \" + filter.getClass().getName() + \" invoke.\");\n                asyncResult = filter.invoke(nextNode, invocation);\n            } catch (Exception e) {\n                InvocationProfilerUtils.releaseDetailProfiler(invocation);\n                if (filter instanceof ListenableFilter) {\n                    ListenableFilter listenableFilter = ((ListenableFilter) filter);\n                    try {\n                        Filter.Listener listener = listenableFilter.listener(invocation);\n                        if (listener != null) {\n                            listener.onError(e, originalInvoker, invocation);\n                        }\n                    } finally {\n                        listenableFilter.removeListener(invocation);\n                    }\n                } else if (filter instanceof FILTER.Listener) {\n                    FILTER.Listener listener = (FILTER.Listener) filter;\n                    listener.onError(e, originalInvoker, invocation);\n                }\n                throw e;\n            } finally {\n\n            }\n            return asyncResult.whenCompleteWithContext((r, t) -> {\n                InvocationProfilerUtils.releaseDetailProfiler(invocation);\n                if (filter instanceof ListenableFilter) {\n                    ListenableFilter listenableFilter = ((ListenableFilter) filter);\n                    Filter.Listener listener = listenableFilter.listener(invocation);\n                    try {\n                        if (listener != null) {\n                            if (t == null) {\n                                listener.onResponse(r, originalInvoker, invocation);\n                            } else {\n                                listener.onError(t, originalInvoker, invocation);\n                            }\n                        }\n                    } finally {\n                        listenableFilter.removeListener(invocation);\n                    }\n                } else if (filter instanceof FILTER.Listener) {\n                    FILTER.Listener listener = (FILTER.Listener) filter;\n                    if (t == null) {\n                        listener.onResponse(r, originalInvoker, invocation);\n                    } else {\n                        listener.onError(t, originalInvoker, invocation);\n                    }\n                }\n            });\n        }\n\n        @Override\n        public void destroy() {\n            originalInvoker.destroy();\n        }\n\n        @Override\n        public String toString() {\n            return originalInvoker.toString();\n        }\n    }\n\n    /**\n     * Works on consumer side\n     *\n     * @param <T>\n     * @param <TYPE>\n     */\n    class ClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter>\n            extends FilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {\n        public ClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {\n            super(originalInvoker, nextNode, filter);\n        }\n\n        @Override\n        public URL getRegistryUrl() {\n            return getOriginalInvoker().getRegistryUrl();\n        }\n\n        @Override\n        public Directory<T> getDirectory() {\n            return getOriginalInvoker().getDirectory();\n        }\n\n        @Override\n        public boolean isDestroyed() {\n            return getOriginalInvoker().isDestroyed();\n        }\n    }\n\n    class CallbackRegistrationInvoker<T, FILTER extends BaseFilter> implements Invoker<T> {\n        private static final ErrorTypeAwareLogger LOGGER =\n                LoggerFactory.getErrorTypeAwareLogger(CallbackRegistrationInvoker.class);\n        final Invoker<T> filterInvoker;\n        final List<FILTER> filters;\n\n        public CallbackRegistrationInvoker(Invoker<T> filterInvoker, List<FILTER> filters) {\n            this.filterInvoker = filterInvoker;\n            this.filters = filters;\n        }\n\n        @Override\n        public Result invoke(Invocation invocation) throws RpcException {\n            Result asyncResult = filterInvoker.invoke(invocation);\n            asyncResult.whenCompleteWithContext((r, t) -> {\n                RuntimeException filterRuntimeException = null;\n                for (int i = filters.size() - 1; i >= 0; i--) {\n                    FILTER filter = filters.get(i);\n                    try {\n                        InvocationProfilerUtils.releaseDetailProfiler(invocation);\n                        if (filter instanceof ListenableFilter) {\n                            ListenableFilter listenableFilter = ((ListenableFilter) filter);\n                            Filter.Listener listener = listenableFilter.listener(invocation);\n                            try {\n                                if (listener != null) {\n                                    if (t == null) {\n                                        listener.onResponse(r, filterInvoker, invocation);\n                                    } else {\n                                        listener.onError(t, filterInvoker, invocation);\n                                    }\n                                }\n                            } finally {\n                                listenableFilter.removeListener(invocation);\n                            }\n                        } else if (filter instanceof FILTER.Listener) {\n                            FILTER.Listener listener = (FILTER.Listener) filter;\n                            if (t == null) {\n                                listener.onResponse(r, filterInvoker, invocation);\n                            } else {\n                                listener.onError(t, filterInvoker, invocation);\n                            }\n                        }\n                    } catch (RuntimeException runtimeException) {\n                        LOGGER.error(\n                                CLUSTER_EXECUTE_FILTER_EXCEPTION,\n                                \"the custom filter is abnormal\",\n                                \"\",\n                                String.format(\n                                        \"Exception occurred while executing the %s filter named %s.\",\n                                        i, filter.getClass().getSimpleName()));\n                        if (LOGGER.isDebugEnabled()) {\n                            LOGGER.debug(String.format(\n                                    \"Whole filter list is: %s\",\n                                    filters.stream()\n                                            .map(tmpFilter ->\n                                                    tmpFilter.getClass().getSimpleName())\n                                            .collect(Collectors.toList())));\n                        }\n                        filterRuntimeException = runtimeException;\n                        t = runtimeException;\n                    }\n                }\n                if (filterRuntimeException != null) {\n                    throw filterRuntimeException;\n                }\n            });\n\n            return asyncResult;\n        }\n\n        public Invoker<T> getFilterInvoker() {\n            return filterInvoker;\n        }\n\n        @Override\n        public Class<T> getInterface() {\n            return filterInvoker.getInterface();\n        }\n\n        @Override\n        public URL getUrl() {\n            return filterInvoker.getUrl();\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return filterInvoker.isAvailable();\n        }\n\n        @Override\n        public void destroy() {\n            filterInvoker.destroy();\n        }\n    }\n\n    class ClusterCallbackRegistrationInvoker<T, FILTER extends BaseFilter>\n            extends CallbackRegistrationInvoker<T, FILTER> implements ClusterInvoker<T> {\n        private ClusterInvoker<T> originalInvoker;\n\n        public ClusterCallbackRegistrationInvoker(\n                ClusterInvoker<T> originalInvoker, Invoker<T> filterInvoker, List<FILTER> filters) {\n            super(filterInvoker, filters);\n            this.originalInvoker = originalInvoker;\n        }\n\n        public ClusterInvoker<T> getOriginalInvoker() {\n            return originalInvoker;\n        }\n\n        @Override\n        public URL getRegistryUrl() {\n            return getOriginalInvoker().getRegistryUrl();\n        }\n\n        @Override\n        public Directory<T> getDirectory() {\n            return getOriginalInvoker().getDirectory();\n        }\n\n        @Override\n        public boolean isDestroyed() {\n            return getOriginalInvoker().isDestroyed();\n        }\n    }\n\n    @Experimental(\n            \"Works for the same purpose as FilterChainNode, replace FilterChainNode with this one when proved stable enough\")\n    class CopyOfFilterChainNode<T, TYPE extends Invoker<T>, FILTER extends BaseFilter> implements Invoker<T> {\n        private static final ErrorTypeAwareLogger LOGGER =\n                LoggerFactory.getErrorTypeAwareLogger(CopyOfFilterChainNode.class);\n        TYPE originalInvoker;\n        Invoker<T> nextNode;\n        FILTER filter;\n\n        public CopyOfFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {\n            this.originalInvoker = originalInvoker;\n            this.nextNode = nextNode;\n            this.filter = filter;\n        }\n\n        public TYPE getOriginalInvoker() {\n            return originalInvoker;\n        }\n\n        @Override\n        public Class<T> getInterface() {\n            return originalInvoker.getInterface();\n        }\n\n        @Override\n        public URL getUrl() {\n            return originalInvoker.getUrl();\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return originalInvoker.isAvailable();\n        }\n\n        @Override\n        public Result invoke(Invocation invocation) throws RpcException {\n            Result asyncResult;\n            try {\n                InvocationProfilerUtils.enterDetailProfiler(\n                        invocation, () -> \"Filter \" + filter.getClass().getName() + \" invoke.\");\n                asyncResult = filter.invoke(nextNode, invocation);\n                if (!(asyncResult instanceof AsyncRpcResult)) {\n                    String msg =\n                            \"The result of filter invocation must be AsyncRpcResult. (If you want to recreate a result, please use AsyncRpcResult.newDefaultAsyncResult.) \"\n                                    + \"Filter class: \" + filter.getClass().getName() + \". Result class: \"\n                                    + asyncResult.getClass().getName() + \".\";\n                    LOGGER.error(INTERNAL_ERROR, \"\", \"\", msg);\n                    throw new RpcException(msg);\n                }\n            } catch (Exception e) {\n                InvocationProfilerUtils.releaseDetailProfiler(invocation);\n                if (filter instanceof ListenableFilter) {\n                    ListenableFilter listenableFilter = ((ListenableFilter) filter);\n                    try {\n                        Filter.Listener listener = listenableFilter.listener(invocation);\n                        if (listener != null) {\n                            listener.onError(e, originalInvoker, invocation);\n                        }\n                    } finally {\n                        listenableFilter.removeListener(invocation);\n                    }\n                } else if (filter instanceof FILTER.Listener) {\n                    FILTER.Listener listener = (FILTER.Listener) filter;\n                    listener.onError(e, originalInvoker, invocation);\n                }\n                throw e;\n            } finally {\n\n            }\n            return asyncResult;\n        }\n\n        @Override\n        public void destroy() {\n            originalInvoker.destroy();\n        }\n\n        @Override\n        public String toString() {\n            return originalInvoker.toString();\n        }\n    }\n\n    @Experimental(\n            \"Works for the same purpose as ClusterFilterChainNode, replace ClusterFilterChainNode with this one when proved stable enough\")\n    class CopyOfClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter>\n            extends CopyOfFilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {\n        public CopyOfClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {\n            super(originalInvoker, nextNode, filter);\n        }\n\n        @Override\n        public URL getRegistryUrl() {\n            return getOriginalInvoker().getRegistryUrl();\n        }\n\n        @Override\n        public Directory<T> getDirectory() {\n            return getOriginalInvoker().getDirectory();\n        }\n\n        @Override\n        public boolean isDestroyed() {\n            return getOriginalInvoker().isDestroyed();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/InvocationInterceptorBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\n@SPI(\"default\")\npublic interface InvocationInterceptorBuilder {\n    <T> ClusterInvoker<T> buildClusterInterceptorChain(final ClusterInvoker<T> invoker, String key, String group);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/ProtocolFilterWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProtocolServer;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SERVICE_FILTER_KEY;\n\n@Activate(order = 100)\npublic class ProtocolFilterWrapper implements Protocol {\n\n    private final Protocol protocol;\n\n    public ProtocolFilterWrapper(Protocol protocol) {\n        if (protocol == null) {\n            throw new IllegalArgumentException(\"protocol == null\");\n        }\n        this.protocol = protocol;\n    }\n\n    @Override\n    public int getDefaultPort() {\n        return protocol.getDefaultPort();\n    }\n\n    @Override\n    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {\n        if (UrlUtils.isRegistry(invoker.getUrl())) {\n            return protocol.export(invoker);\n        }\n        FilterChainBuilder builder = getFilterChainBuilder(invoker.getUrl());\n        return protocol.export(builder.buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));\n    }\n\n    private <T> FilterChainBuilder getFilterChainBuilder(URL url) {\n        return ScopeModelUtil.getExtensionLoader(FilterChainBuilder.class, url.getScopeModel())\n                .getDefaultExtension();\n    }\n\n    @Override\n    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {\n        if (UrlUtils.isRegistry(url)) {\n            return protocol.refer(type, url);\n        }\n        FilterChainBuilder builder = getFilterChainBuilder(url);\n        return builder.buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);\n    }\n\n    @Override\n    public void destroy() {\n        protocol.destroy();\n    }\n\n    @Override\n    public List<ProtocolServer> getServers() {\n        return protocol.getServers();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/CallbackConsumerContextFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter.support;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CALLBACK;\n\n/**\n * CallbackConsumerContextFilter set current RpcContext with invoker,invocation, local host, remote host and port\n * for consumer callback invoker.It does it to make the requires info available to execution thread's RpcContext.\n * @see ConsumerContextFilter\n */\n@Activate(group = CALLBACK, order = Integer.MIN_VALUE)\npublic class CallbackConsumerContextFilter extends ConsumerContextFilter implements Filter {\n\n    public CallbackConsumerContextFilter(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/ConsumerClassLoaderFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter.support;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.Optional;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\n\n@Activate(group = CONSUMER, order = Integer.MIN_VALUE + 100)\npublic class ConsumerClassLoaderFilter implements ClusterFilter {\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();\n        try {\n            Optional.ofNullable(invocation.getServiceModel())\n                    .map(ServiceModel::getClassLoader)\n                    .ifPresent(Thread.currentThread()::setContextClassLoader);\n            return invoker.invoke(invocation);\n        } finally {\n            Thread.currentThread().setContextClassLoader(originClassLoader);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/ConsumerContextFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter.support;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.InvokeMode;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.PenetrateAttachmentSelector;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.TimeoutCountDown;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLE_TIMEOUT_COUNTDOWN_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIME_COUNTDOWN_KEY;\n\n/**\n * ConsumerContextFilter set current RpcContext with invoker,invocation, local host, remote host and port\n * for consumer invoker.It does it to make the requires info available to execution thread's RpcContext.\n *\n * @see Filter\n * @see RpcContext\n */\n@Activate(group = CONSUMER, order = Integer.MIN_VALUE)\npublic class ConsumerContextFilter implements ClusterFilter, ClusterFilter.Listener {\n\n    private Set<PenetrateAttachmentSelector> supportedSelectors;\n\n    public ConsumerContextFilter(ApplicationModel applicationModel) {\n        ExtensionLoader<PenetrateAttachmentSelector> selectorExtensionLoader =\n                applicationModel.getExtensionLoader(PenetrateAttachmentSelector.class);\n        supportedSelectors = selectorExtensionLoader.getSupportedExtensionInstances();\n    }\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        RpcContext.getServiceContext().setInvoker(invoker).setInvocation(invocation);\n\n        RpcContext context = RpcContext.getClientAttachment();\n        context.setAttachment(REMOTE_APPLICATION_KEY, invoker.getUrl().getApplication());\n        if (invocation instanceof RpcInvocation) {\n            ((RpcInvocation) invocation).setInvoker(invoker);\n        }\n\n        if (CollectionUtils.isNotEmpty(supportedSelectors)) {\n            for (PenetrateAttachmentSelector supportedSelector : supportedSelectors) {\n                Map<String, Object> selected = supportedSelector.select(\n                        invocation, RpcContext.getClientAttachment(), RpcContext.getServerAttachment());\n                if (CollectionUtils.isNotEmptyMap(selected)) {\n                    ((RpcInvocation) invocation).addObjectAttachments(selected);\n                }\n            }\n        } else {\n            ((RpcInvocation) invocation)\n                    .addObjectAttachments(RpcContext.getServerAttachment().getObjectAttachments());\n        }\n        Map<String, Object> contextAttachments =\n                RpcContext.getClientAttachment().getObjectAttachments();\n        if (CollectionUtils.isNotEmptyMap(contextAttachments)) {\n            /**\n             * invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here,\n             * because the {@link RpcContext#setAttachment(String, String)} is passed in the Filter when the call is triggered\n             * by the built-in retry mechanism of the Dubbo. The attachment to update RpcContext will no longer work, which is\n             * a mistake in most cases (for example, through Filter to RpcContext output traceId and spanId and other information).\n             */\n            ((RpcInvocation) invocation).addObjectAttachments(contextAttachments);\n        }\n\n        // pass default timeout set by end user (ReferenceConfig)\n        Object countDown = RpcContext.getServerAttachment().getObjectAttachment(TIME_COUNTDOWN_KEY);\n        if (countDown != null) {\n            String methodName = RpcUtils.getMethodName(invocation);\n            // When the client has enabled the timeout-countdown function,\n            // the subsequent calls launched by the Server side will be enabled by default,\n            // and support to turn off the function on a node to get rid of the timeout control.\n            if (invoker.getUrl().getMethodParameter(methodName, ENABLE_TIMEOUT_COUNTDOWN_KEY, true)) {\n                context.setObjectAttachment(TIME_COUNTDOWN_KEY, countDown);\n\n                TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown;\n                if (timeoutCountDown.isExpired()) {\n                    return AsyncRpcResult.newDefaultAsyncResult(\n                            new RpcException(\n                                    RpcException.TIMEOUT_TERMINATE,\n                                    \"No time left for making the following call: \" + invocation.getServiceName() + \".\"\n                                            + RpcUtils.getMethodName(invocation) + \", terminate directly.\"),\n                            invocation);\n                }\n            }\n        }\n        RpcContext.removeClientResponseContext();\n        return invoker.invoke(invocation);\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {\n        // pass attachments to result\n        Map<String, Object> map = appResponse.getObjectAttachments();\n        RpcContext.getClientResponseContext().setObjectAttachments(map);\n        removeContext(invocation);\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        removeContext(invocation);\n    }\n\n    private void removeContext(Invocation invocation) {\n        RpcContext.removeClientAttachment();\n        if (invocation instanceof RpcInvocation) {\n            RpcInvocation rpcInvocation = (RpcInvocation) invocation;\n            if (rpcInvocation.getInvokeMode() != null) {\n                // clear service context if not in sync mode\n                if (rpcInvocation.getInvokeMode() == InvokeMode.ASYNC\n                        || rpcInvocation.getInvokeMode() == InvokeMode.FUTURE) {\n                    RpcContext.removeServiceContext();\n                }\n            }\n        }\n        // server context must not be removed because user might use it on callback.\n        // So the clear of is delayed til the start of the next rpc call, see RpcContext.removeServerContext(); in\n        // invoke() above\n        // RpcContext.removeServerContext();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsConsumerFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter.support;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.metrics.filter.MetricsFilter;\nimport org.apache.dubbo.rpc.BaseFilter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\n\n@Activate(\n        group = {CONSUMER},\n        order = Integer.MIN_VALUE + 100)\npublic class MetricsConsumerFilter extends MetricsFilter implements ClusterFilter, BaseFilter.Listener {\n    public MetricsConsumerFilter() {}\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        return super.invoke(invoker, invocation, false);\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {\n        super.onResponse(appResponse, invoker, invocation, false);\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        super.onError(t, invoker, invocation, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/governance/DefaultGovernanceRuleRepositoryImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.governance;\n\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\npublic class DefaultGovernanceRuleRepositoryImpl implements GovernanceRuleRepository {\n\n    private final ModuleModel moduleModel;\n\n    public DefaultGovernanceRuleRepositoryImpl(ModuleModel moduleModel) {\n        this.moduleModel = moduleModel;\n    }\n\n    @Override\n    public void addListener(String key, String group, ConfigurationListener listener) {\n        DynamicConfiguration dynamicConfiguration = getDynamicConfiguration();\n        if (dynamicConfiguration != null) {\n            dynamicConfiguration.addListener(key, group, listener);\n        }\n    }\n\n    @Override\n    public void removeListener(String key, String group, ConfigurationListener listener) {\n        DynamicConfiguration dynamicConfiguration = getDynamicConfiguration();\n        if (dynamicConfiguration != null) {\n            dynamicConfiguration.removeListener(key, group, listener);\n        }\n    }\n\n    @Override\n    public String getRule(String key, String group, long timeout) throws IllegalStateException {\n        DynamicConfiguration dynamicConfiguration = getDynamicConfiguration();\n        if (dynamicConfiguration != null) {\n            return dynamicConfiguration.getConfig(key, group, timeout);\n        }\n        return null;\n    }\n\n    private DynamicConfiguration getDynamicConfiguration() {\n        return moduleModel.modelEnvironment().getDynamicConfiguration().orElse(null);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/governance/GovernanceRuleRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.governance;\n\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport static org.apache.dubbo.common.extension.ExtensionScope.MODULE;\n\n@SPI(value = \"default\", scope = MODULE)\npublic interface GovernanceRuleRepository {\n\n    String DEFAULT_GROUP = \"dubbo\";\n\n    /**\n     * {@link #addListener(String, String, ConfigurationListener)}\n     *\n     * @param key      the key to represent a configuration\n     * @param listener configuration listener\n     */\n    default void addListener(String key, ConfigurationListener listener) {\n        addListener(key, DEFAULT_GROUP, listener);\n    }\n\n    /**\n     * {@link #removeListener(String, String, ConfigurationListener)}\n     *\n     * @param key      the key to represent a configuration\n     * @param listener configuration listener\n     */\n    default void removeListener(String key, ConfigurationListener listener) {\n        removeListener(key, DEFAULT_GROUP, listener);\n    }\n\n    /**\n     * Register a configuration listener for a specified key\n     * The listener only works for service governance purpose, so the target group would always be the value user\n     * specifies at startup or 'dubbo' by default. This method will only register listener, which means it will not\n     * trigger a notification that contains the current value.\n     *\n     * @param key      the key to represent a configuration\n     * @param group    the group where the key belongs to\n     * @param listener configuration listener\n     */\n    void addListener(String key, String group, ConfigurationListener listener);\n\n    /**\n     * Stops one listener from listening to value changes in the specified key.\n     *\n     * @param key      the key to represent a configuration\n     * @param group    the group where the key belongs to\n     * @param listener configuration listener\n     */\n    void removeListener(String key, String group, ConfigurationListener listener);\n\n    /**\n     * Get the governance rule mapped to the given key and the given group\n     *\n     * @param key   the key to represent a configuration\n     * @param group the group where the key belongs to\n     * @return target configuration mapped to the given key and the given group\n     */\n    default String getRule(String key, String group) {\n        return getRule(key, group, -1L);\n    }\n\n    /**\n     * Get the governance rule mapped to the given key and the given group. If the\n     * rule fails to return after timeout exceeds, IllegalStateException will be thrown.\n     *\n     * @param key     the key to represent a configuration\n     * @param group   the group where the key belongs to\n     * @param timeout timeout value for fetching the target config\n     * @return target configuration mapped to the given key and the given group, IllegalStateException will be thrown\n     * if timeout exceeds.\n     */\n    String getRule(String key, String group, long timeout) throws IllegalStateException;\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/interceptor/ClusterInterceptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.interceptor;\n\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;\n\n/**\n * Different from {@link Filter}, ClusterInterceptor works at the outmost layer, before one specific address/invoker is picked.\n */\n@Deprecated\n@SPI\npublic interface ClusterInterceptor {\n\n    void before(AbstractClusterInvoker<?> clusterInvoker, Invocation invocation);\n\n    void after(AbstractClusterInvoker<?> clusterInvoker, Invocation invocation);\n\n    /**\n     * Override this method or {@link #before(AbstractClusterInvoker, Invocation)}\n     * and {@link #after(AbstractClusterInvoker, Invocation)} methods to add your own logic expected to be\n     * executed before and after invoke.\n     *\n     * @param clusterInvoker\n     * @param invocation\n     * @return\n     * @throws RpcException\n     */\n    default Result intercept(AbstractClusterInvoker<?> clusterInvoker, Invocation invocation) throws RpcException {\n        return clusterInvoker.invoke(invocation);\n    }\n\n    interface Listener {\n\n        void onMessage(Result appResponse, AbstractClusterInvoker<?> clusterInvoker, Invocation invocation);\n\n        void onError(Throwable t, AbstractClusterInvoker<?> clusterInvoker, Invocation invocation);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_SERVICE_REFERENCE_PATH;\nimport static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WARMUP;\nimport static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WEIGHT;\nimport static org.apache.dubbo.rpc.cluster.Constants.WARMUP_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY;\n\npublic abstract class AbstractLoadBalance implements LoadBalance {\n    /**\n     * Calculate the weight according to the uptime proportion of warmup time\n     * the new weight will be within 1(inclusive) to weight(inclusive)\n     *\n     * @param uptime the uptime in milliseconds\n     * @param warmup the warmup time in milliseconds\n     * @param weight the weight of an invoker\n     * @return weight which takes warmup into account\n     */\n    static int calculateWarmupWeight(int uptime, int warmup, int weight) {\n        int ww = (int) (uptime / ((float) warmup / weight));\n        return ww < 1 ? 1 : (Math.min(ww, weight));\n    }\n\n    @Override\n    public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) {\n        if (CollectionUtils.isEmpty(invokers)) {\n            return null;\n        }\n        if (invokers.size() == 1) {\n            return invokers.get(0);\n        }\n        return doSelect(invokers, url, invocation);\n    }\n\n    protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation);\n\n    /**\n     * Get the weight of the invoker's invocation which takes warmup time into account\n     * if the uptime is within the warmup time, the weight will be reduce proportionally\n     *\n     * @param invoker    the invoker\n     * @param invocation the invocation of this invoker\n     * @return weight\n     */\n    protected int getWeight(Invoker<?> invoker, Invocation invocation) {\n        int weight;\n        URL url = invoker.getUrl();\n        if (invoker instanceof ClusterInvoker) {\n            url = ((ClusterInvoker<?>) invoker).getRegistryUrl();\n        }\n\n        // Multiple registry scenario, load balance among multiple registries.\n        if (REGISTRY_SERVICE_REFERENCE_PATH.equals(url.getServiceInterface())) {\n            weight = url.getParameter(WEIGHT_KEY, DEFAULT_WEIGHT);\n        } else {\n            weight = url.getMethodParameter(RpcUtils.getMethodName(invocation), WEIGHT_KEY, DEFAULT_WEIGHT);\n            if (weight > 0) {\n                long timestamp = invoker.getUrl().getParameter(TIMESTAMP_KEY, 0L);\n                if (timestamp > 0L) {\n                    long uptime = System.currentTimeMillis() - timestamp;\n                    if (uptime < 0) {\n                        return 1;\n                    }\n                    int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP);\n                    if (uptime > 0 && uptime < warmup) {\n                        weight = calculateWarmupWeight((int) uptime, warmup, weight);\n                    }\n                }\n            }\n        }\n        return Math.max(weight, 0);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AdaptiveLoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.LoadbalanceRules;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.AdaptiveMetrics;\nimport org.apache.dubbo.rpc.Constants;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.List;\nimport java.util.concurrent.ThreadLocalRandom;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;\n\npublic class AdaptiveLoadBalance extends AbstractLoadBalance {\n\n    public static final String NAME = \"adaptive\";\n\n    // default key\n    private String attachmentKey = \"mem,load\";\n\n    private final AdaptiveMetrics adaptiveMetrics;\n\n    public AdaptiveLoadBalance(ApplicationModel scopeModel) {\n        adaptiveMetrics = scopeModel.getBeanFactory().getBean(AdaptiveMetrics.class);\n    }\n\n    @Override\n    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {\n        Invoker<T> invoker = selectByP2C(invokers, invocation);\n        invocation.setAttachment(Constants.ADAPTIVE_LOADBALANCE_ATTACHMENT_KEY, attachmentKey);\n        long startTime = System.currentTimeMillis();\n        invocation.getAttributes().put(Constants.ADAPTIVE_LOADBALANCE_START_TIME, startTime);\n        invocation.getAttributes().put(LOADBALANCE_KEY, LoadbalanceRules.ADAPTIVE);\n        adaptiveMetrics.addConsumerReq(getServiceKey(invoker, invocation));\n        adaptiveMetrics.setPickTime(getServiceKey(invoker, invocation), startTime);\n\n        return invoker;\n    }\n\n    private <T> Invoker<T> selectByP2C(List<Invoker<T>> invokers, Invocation invocation) {\n        int length = invokers.size();\n        if (length == 1) {\n            return invokers.get(0);\n        }\n\n        if (length == 2) {\n            return chooseLowLoadInvoker(invokers.get(0), invokers.get(1), invocation);\n        }\n\n        int pos1 = ThreadLocalRandom.current().nextInt(length);\n        int pos2 = ThreadLocalRandom.current().nextInt(length - 1);\n        if (pos2 >= pos1) {\n            pos2 = pos2 + 1;\n        }\n\n        return chooseLowLoadInvoker(invokers.get(pos1), invokers.get(pos2), invocation);\n    }\n\n    private String getServiceKey(Invoker<?> invoker, Invocation invocation) {\n\n        String key = (String) invocation.getAttributes().get(invoker);\n        if (StringUtils.isNotEmpty(key)) {\n            return key;\n        }\n\n        key = buildServiceKey(invoker, invocation);\n        invocation.getAttributes().put(invoker, key);\n        return key;\n    }\n\n    private String buildServiceKey(Invoker<?> invoker, Invocation invocation) {\n        URL url = invoker.getUrl();\n        StringBuilder sb = new StringBuilder(128);\n        sb.append(url.getAddress()).append(\":\").append(invocation.getProtocolServiceKey());\n        return sb.toString();\n    }\n\n    private int getTimeout(Invoker<?> invoker, Invocation invocation) {\n        URL url = invoker.getUrl();\n        String methodName = RpcUtils.getMethodName(invocation);\n        return (int)\n                RpcUtils.getTimeout(url, methodName, RpcContext.getClientAttachment(), invocation, DEFAULT_TIMEOUT);\n    }\n\n    private <T> Invoker<T> chooseLowLoadInvoker(Invoker<T> invoker1, Invoker<T> invoker2, Invocation invocation) {\n        int weight1 = getWeight(invoker1, invocation);\n        int weight2 = getWeight(invoker2, invocation);\n        int timeout1 = getTimeout(invoker1, invocation);\n        int timeout2 = getTimeout(invoker2, invocation);\n        long load1 = Double.doubleToLongBits(\n                adaptiveMetrics.getLoad(getServiceKey(invoker1, invocation), weight1, timeout1));\n        long load2 = Double.doubleToLongBits(\n                adaptiveMetrics.getLoad(getServiceKey(invoker2, invocation), weight2, timeout2));\n\n        if (load1 == load2) {\n            // The sum of weights\n            int totalWeight = weight1 + weight2;\n            if (totalWeight > 0) {\n                int offset = ThreadLocalRandom.current().nextInt(totalWeight);\n                if (offset < weight1) {\n                    return invoker1;\n                }\n                return invoker2;\n            }\n            return ThreadLocalRandom.current().nextInt(2) == 0 ? invoker1 : invoker2;\n        }\n        return load1 > load2 ? invoker2 : invoker1;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.io.Bytes;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\n\npublic class ConsistentHashLoadBalance extends AbstractLoadBalance {\n    public static final String NAME = \"consistenthash\";\n\n    /**\n     * Hash nodes name\n     */\n    public static final String HASH_NODES = \"hash.nodes\";\n\n    /**\n     * Hash arguments name\n     */\n    public static final String HASH_ARGUMENTS = \"hash.arguments\";\n\n    private final ConcurrentMap<String, ConsistentHashSelector<?>> selectors = new ConcurrentHashMap<>();\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {\n        String methodName = RpcUtils.getMethodName(invocation);\n        String key = invokers.get(0).getUrl().getServiceKey() + \".\" + methodName;\n        int invokersHashCode = invokers.hashCode();\n        // If the detection is successful, return in advance. it may be different from selector, but it doesn't matter\n        ConsistentHashSelector<T> oldSelector0;\n        if ((oldSelector0 = (ConsistentHashSelector<T>) selectors.get(key)) != null\n                && oldSelector0.identityHashCode == invokersHashCode) {\n            return oldSelector0.select(invocation);\n        }\n\n        // using the hashcode of invoker list to create consistent selector by atomic computation.\n        ConsistentHashSelector<T> selector = (ConsistentHashSelector<T>) selectors.compute(\n                key,\n                (k, oldSelector) -> (oldSelector == null || oldSelector.identityHashCode != invokersHashCode)\n                        ? new ConsistentHashSelector<>(invokers, methodName, invokersHashCode)\n                        : oldSelector);\n        return selector.select(invocation);\n    }\n\n    private static final class ConsistentHashSelector<T> {\n\n        private final TreeMap<Long, Invoker<T>> virtualInvokers;\n\n        private final int replicaNumber;\n\n        private final int identityHashCode;\n\n        private final int[] argumentIndex;\n\n        ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) {\n            this.virtualInvokers = new TreeMap<>();\n            this.identityHashCode = identityHashCode;\n            URL url = invokers.get(0).getUrl();\n            this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160);\n            String[] index = COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, HASH_ARGUMENTS, \"0\"));\n            argumentIndex = new int[index.length];\n            for (int i = 0; i < index.length; i++) {\n                argumentIndex[i] = Integer.parseInt(index[i]);\n            }\n            for (Invoker<T> invoker : invokers) {\n                String address = invoker.getUrl().getAddress();\n                for (int i = 0; i < replicaNumber / 4; i++) {\n                    byte[] digest = Bytes.getMD5(address + i);\n                    for (int h = 0; h < 4; h++) {\n                        long m = hash(digest, h);\n                        virtualInvokers.put(m, invoker);\n                    }\n                }\n            }\n        }\n\n        public Invoker<T> select(Invocation invocation) {\n            String key = toKey(RpcUtils.getArguments(invocation));\n\n            byte[] digest = Bytes.getMD5(key);\n            return selectForKey(hash(digest, 0));\n        }\n\n        private String toKey(Object[] args) {\n            StringBuilder buf = new StringBuilder();\n            for (int i : argumentIndex) {\n                if (i >= 0 && args != null && i < args.length) {\n                    buf.append(args[i]);\n                }\n            }\n            return buf.toString();\n        }\n\n        private Invoker<T> selectForKey(long hash) {\n            Map.Entry<Long, Invoker<T>> entry = virtualInvokers.ceilingEntry(hash);\n            if (entry == null) {\n                entry = virtualInvokers.firstEntry();\n            }\n            return entry.getValue();\n        }\n\n        private long hash(byte[] digest, int number) {\n            return (((long) (digest[3 + number * 4] & 0xFF) << 24)\n                            | ((long) (digest[2 + number * 4] & 0xFF) << 16)\n                            | ((long) (digest[1 + number * 4] & 0xFF) << 8)\n                            | (digest[number * 4] & 0xFF))\n                    & 0xFFFFFFFFL;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcStatus;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.List;\nimport java.util.concurrent.ThreadLocalRandom;\n\n/**\n * LeastActiveLoadBalance\n * <p>\n * Filter the number of invokers with the least number of active calls and count the weights and quantities of these invokers.\n * If there is only one invoker, use the invoker directly;\n * If there are multiple invokers and the weights are not the same, then random according to the total weight;\n * If there are multiple invokers and the same weight, then randomly called.\n */\npublic class LeastActiveLoadBalance extends AbstractLoadBalance {\n\n    public static final String NAME = \"leastactive\";\n\n    @Override\n    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {\n        // Number of invokers\n        int length = invokers.size();\n        // The least active value of all invokers\n        int leastActive = -1;\n        // The number of invokers having the same least active value (leastActive)\n        int leastCount = 0;\n        // The index of invokers having the same least active value (leastActive)\n        int[] leastIndexes = new int[length];\n        // the weight of every invokers\n        int[] weights = new int[length];\n        // The sum of the warmup weights of all the least active invokers\n        int totalWeight = 0;\n        // The weight of the first least active invoker\n        int firstWeight = 0;\n        // Every least active invoker has the same weight value?\n        boolean sameWeight = true;\n\n        // Filter out all the least active invokers\n        for (int i = 0; i < length; i++) {\n            Invoker<T> invoker = invokers.get(i);\n            // Get the active number of the invoker\n            int active = RpcStatus.getStatus(invoker.getUrl(), RpcUtils.getMethodName(invocation))\n                    .getActive();\n            // Get the weight of the invoker's configuration. The default value is 100.\n            int afterWarmup = getWeight(invoker, invocation);\n            // save for later use\n            weights[i] = afterWarmup;\n            // If it is the first invoker or the active number of the invoker is less than the current least active\n            // number\n            if (leastActive == -1 || active < leastActive) {\n                // Reset the active number of the current invoker to the least active number\n                leastActive = active;\n                // Reset the number of least active invokers\n                leastCount = 1;\n                // Put the first least active invoker first in leastIndexes\n                leastIndexes[0] = i;\n                // Reset totalWeight\n                totalWeight = afterWarmup;\n                // Record the weight the first least active invoker\n                firstWeight = afterWarmup;\n                // Each invoke has the same weight (only one invoker here)\n                sameWeight = true;\n                // If current invoker's active value equals with leaseActive, then accumulating.\n            } else if (active == leastActive) {\n                // Record the index of the least active invoker in leastIndexes order\n                leastIndexes[leastCount++] = i;\n                // Accumulate the total weight of the least active invoker\n                totalWeight += afterWarmup;\n                // If every invoker has the same weight?\n                if (sameWeight && afterWarmup != firstWeight) {\n                    sameWeight = false;\n                }\n            }\n        }\n        // Choose an invoker from all the least active invokers\n        if (leastCount == 1) {\n            // If we got exactly one invoker having the least active value, return this invoker directly.\n            return invokers.get(leastIndexes[0]);\n        }\n        if (!sameWeight && totalWeight > 0) {\n            // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on\n            // totalWeight.\n            int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);\n            // Return a invoker based on the random value.\n            for (int i = 0; i < leastCount; i++) {\n                int leastIndex = leastIndexes[i];\n                offsetWeight -= weights[leastIndex];\n                if (offsetWeight < 0) {\n                    return invokers.get(leastIndex);\n                }\n            }\n        }\n        // If all invokers have the same weight value or totalWeight=0, return evenly.\n        return invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RandomLoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.ThreadLocalRandom;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_SERVICE_REFERENCE_PATH;\nimport static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY;\n\n/**\n * This class select one provider from multiple providers randomly.\n * You can define weights for each provider:\n * If the weights are all the same then it will use random.nextInt(number of invokers).\n * If the weights are different then it will use random.nextInt(w1 + w2 + ... + wn)\n * Note that if the performance of the machine is better than others, you can set a larger weight.\n * If the performance is not so good, you can set a smaller weight.\n */\npublic class RandomLoadBalance extends AbstractLoadBalance {\n\n    public static final String NAME = \"random\";\n\n    /**\n     * Select one invoker between a list using a random criteria\n     *\n     * @param invokers   List of possible invokers\n     * @param url        URL\n     * @param invocation Invocation\n     * @param <T>\n     * @return The selected invoker\n     */\n    @Override\n    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {\n        // Number of invokers\n        int length = invokers.size();\n\n        if (!needWeightLoadBalance(invokers, invocation)) {\n            return invokers.get(ThreadLocalRandom.current().nextInt(length));\n        }\n\n        // Every invoker has the same weight?\n        boolean sameWeight = true;\n        // the maxWeight of every invoker, the minWeight = 0 or the maxWeight of the last invoker\n        int[] weights = new int[length];\n        // The sum of weights\n        int totalWeight = 0;\n        for (int i = 0; i < length; i++) {\n            int weight = getWeight(invokers.get(i), invocation);\n            // Sum\n            totalWeight += weight;\n            // save for later use\n            weights[i] = totalWeight;\n            if (sameWeight && totalWeight != weight * (i + 1)) {\n                sameWeight = false;\n            }\n        }\n        if (totalWeight > 0 && !sameWeight) {\n            // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on\n            // totalWeight.\n            int offset = ThreadLocalRandom.current().nextInt(totalWeight);\n            // Return an invoker based on the random value.\n            if (length <= 4) {\n                for (int i = 0; i < length; i++) {\n                    if (offset < weights[i]) {\n                        return invokers.get(i);\n                    }\n                }\n            } else {\n                int i = Arrays.binarySearch(weights, offset);\n                if (i < 0) {\n                    i = -i - 1;\n                } else {\n                    while (weights[i + 1] == offset) {\n                        i++;\n                    }\n                    i++;\n                }\n                return invokers.get(i);\n            }\n        }\n        // If all invokers have the same weight value or totalWeight=0, return evenly.\n        return invokers.get(ThreadLocalRandom.current().nextInt(length));\n    }\n\n    private <T> boolean needWeightLoadBalance(List<Invoker<T>> invokers, Invocation invocation) {\n        Invoker<T> invoker = invokers.get(0);\n        URL invokerUrl = invoker.getUrl();\n        if (invoker instanceof ClusterInvoker) {\n            invokerUrl = ((ClusterInvoker<?>) invoker).getRegistryUrl();\n        }\n\n        // Multiple registry scenario, load balance among multiple registries.\n        if (REGISTRY_SERVICE_REFERENCE_PATH.equals(invokerUrl.getServiceInterface())) {\n            String weight = invokerUrl.getParameter(WEIGHT_KEY);\n            return StringUtils.isNotEmpty(weight);\n        } else {\n            String weight = invokerUrl.getMethodParameter(RpcUtils.getMethodName(invocation), WEIGHT_KEY);\n            if (StringUtils.isNotEmpty(weight)) {\n                return true;\n            } else {\n                String timeStamp = invoker.getUrl().getParameter(TIMESTAMP_KEY);\n                return StringUtils.isNotEmpty(timeStamp);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Round robin load balance.\n */\npublic class RoundRobinLoadBalance extends AbstractLoadBalance {\n    public static final String NAME = \"roundrobin\";\n\n    private static final int RECYCLE_PERIOD = 60000;\n\n    private final ConcurrentMap<String, ConcurrentMap<String, WeightedRoundRobin>> methodWeightMap =\n            new ConcurrentHashMap<>();\n\n    protected static class WeightedRoundRobin {\n        private int weight;\n        private final AtomicLong current = new AtomicLong(0);\n        private long lastUpdate;\n\n        public int getWeight() {\n            return weight;\n        }\n\n        public void setWeight(int weight) {\n            this.weight = weight;\n            current.set(0);\n        }\n\n        public long increaseCurrent() {\n            return current.addAndGet(weight);\n        }\n\n        public void sel(int total) {\n            current.addAndGet(-1 * total);\n        }\n\n        public long getLastUpdate() {\n            return lastUpdate;\n        }\n\n        public void setLastUpdate(long lastUpdate) {\n            this.lastUpdate = lastUpdate;\n        }\n    }\n\n    /**\n     * get invoker addr list cached for specified invocation\n     * <p>\n     * <b>for unit test only</b>\n     *\n     * @param invokers\n     * @param invocation\n     * @return\n     */\n    protected <T> Collection<String> getInvokerAddrList(List<Invoker<T>> invokers, Invocation invocation) {\n        String key = invokers.get(0).getUrl().getServiceKey() + \".\" + RpcUtils.getMethodName(invocation);\n        Map<String, WeightedRoundRobin> map = methodWeightMap.get(key);\n        if (map != null) {\n            return map.keySet();\n        }\n        return null;\n    }\n\n    @Override\n    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {\n        String key = invokers.get(0).getUrl().getServiceKey() + \".\" + RpcUtils.getMethodName(invocation);\n        ConcurrentMap<String, WeightedRoundRobin> map =\n                ConcurrentHashMapUtils.computeIfAbsent(methodWeightMap, key, k -> new ConcurrentHashMap<>());\n        int totalWeight = 0;\n        long maxCurrent = Long.MIN_VALUE;\n        long now = System.currentTimeMillis();\n        Invoker<T> selectedInvoker = null;\n        WeightedRoundRobin selectedWRR = null;\n        for (Invoker<T> invoker : invokers) {\n            String identifyString = invoker.getUrl().toIdentityString();\n            int weight = getWeight(invoker, invocation);\n            WeightedRoundRobin weightedRoundRobin = ConcurrentHashMapUtils.computeIfAbsent(map, identifyString, k -> {\n                WeightedRoundRobin wrr = new WeightedRoundRobin();\n                wrr.setWeight(weight);\n                return wrr;\n            });\n\n            if (weight != weightedRoundRobin.getWeight()) {\n                // weight changed\n                weightedRoundRobin.setWeight(weight);\n            }\n            long cur = weightedRoundRobin.increaseCurrent();\n            weightedRoundRobin.setLastUpdate(now);\n            if (cur > maxCurrent) {\n                maxCurrent = cur;\n                selectedInvoker = invoker;\n                selectedWRR = weightedRoundRobin;\n            }\n            totalWeight += weight;\n        }\n        if (invokers.size() != map.size()) {\n            map.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > RECYCLE_PERIOD);\n        }\n        if (selectedInvoker != null) {\n            selectedWRR.sel(totalWeight);\n            return selectedInvoker;\n        }\n        // should not happen here\n        return invokers.get(0);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ShortestResponseLoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcStatus;\nimport org.apache.dubbo.rpc.cluster.Constants;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * ShortestResponseLoadBalance\n * </p>\n * Filter the number of invokers with the shortest response time of\n * success calls and count the weights and quantities of these invokers in last slide window.\n * If there is only one invoker, use the invoker directly;\n * If there are multiple invokers and the weights are not the same, then random according to the total weight;\n * If there are multiple invokers and the same weight, then randomly called.\n */\npublic class ShortestResponseLoadBalance extends AbstractLoadBalance implements ScopeModelAware {\n\n    public static final String NAME = \"shortestresponse\";\n\n    private int slidePeriod = 30_000;\n\n    private final ConcurrentMap<RpcStatus, SlideWindowData> methodMap = new ConcurrentHashMap<>();\n\n    private final AtomicBoolean onResetSlideWindow = new AtomicBoolean(false);\n\n    private volatile long lastUpdateTime = System.currentTimeMillis();\n\n    private ExecutorService executorService;\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        slidePeriod = applicationModel\n                .modelEnvironment()\n                .getConfiguration()\n                .getInt(Constants.SHORTEST_RESPONSE_SLIDE_PERIOD, 30_000);\n        executorService = applicationModel\n                .getFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getSharedExecutor();\n    }\n\n    protected static class SlideWindowData {\n\n        private long succeededOffset;\n        private long succeededElapsedOffset;\n        private final RpcStatus rpcStatus;\n\n        public SlideWindowData(RpcStatus rpcStatus) {\n            this.rpcStatus = rpcStatus;\n            this.succeededOffset = 0;\n            this.succeededElapsedOffset = 0;\n        }\n\n        public void reset() {\n            this.succeededOffset = rpcStatus.getSucceeded();\n            this.succeededElapsedOffset = rpcStatus.getSucceededElapsed();\n        }\n\n        private long getSucceededAverageElapsed() {\n            long succeed = this.rpcStatus.getSucceeded() - this.succeededOffset;\n            if (succeed == 0) {\n                return 0;\n            }\n            return (this.rpcStatus.getSucceededElapsed() - this.succeededElapsedOffset) / succeed;\n        }\n\n        public long getEstimateResponse() {\n            int active = this.rpcStatus.getActive() + 1;\n            return getSucceededAverageElapsed() * active;\n        }\n    }\n\n    @Override\n    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {\n        // Number of invokers\n        int length = invokers.size();\n        // Estimated shortest response time of all invokers\n        long shortestResponse = Long.MAX_VALUE;\n        // The number of invokers having the same estimated shortest response time\n        int shortestCount = 0;\n        // The index of invokers having the same estimated shortest response time\n        int[] shortestIndexes = new int[length];\n        // the weight of every invokers\n        int[] weights = new int[length];\n        // The sum of the warmup weights of all the shortest response  invokers\n        int totalWeight = 0;\n        // The weight of the first shortest response invokers\n        int firstWeight = 0;\n        // Every shortest response invoker has the same weight value?\n        boolean sameWeight = true;\n\n        // Filter out all the shortest response invokers\n        for (int i = 0; i < length; i++) {\n            Invoker<T> invoker = invokers.get(i);\n            RpcStatus rpcStatus = RpcStatus.getStatus(invoker.getUrl(), RpcUtils.getMethodName(invocation));\n            SlideWindowData slideWindowData =\n                    ConcurrentHashMapUtils.computeIfAbsent(methodMap, rpcStatus, SlideWindowData::new);\n\n            // Calculate the estimated response time from the product of active connections and succeeded average\n            // elapsed time.\n            long estimateResponse = slideWindowData.getEstimateResponse();\n            int afterWarmup = getWeight(invoker, invocation);\n            weights[i] = afterWarmup;\n            // Same as LeastActiveLoadBalance\n            if (estimateResponse < shortestResponse) {\n                shortestResponse = estimateResponse;\n                shortestCount = 1;\n                shortestIndexes[0] = i;\n                totalWeight = afterWarmup;\n                firstWeight = afterWarmup;\n                sameWeight = true;\n            } else if (estimateResponse == shortestResponse) {\n                shortestIndexes[shortestCount++] = i;\n                totalWeight += afterWarmup;\n                if (sameWeight && i > 0 && afterWarmup != firstWeight) {\n                    sameWeight = false;\n                }\n            }\n        }\n\n        if (System.currentTimeMillis() - lastUpdateTime > slidePeriod\n                && onResetSlideWindow.compareAndSet(false, true)) {\n            // reset slideWindowData in async way\n            executorService.execute(() -> {\n                methodMap.values().forEach(SlideWindowData::reset);\n                lastUpdateTime = System.currentTimeMillis();\n                onResetSlideWindow.set(false);\n            });\n        }\n\n        if (shortestCount == 1) {\n            return invokers.get(shortestIndexes[0]);\n        }\n        if (!sameWeight && totalWeight > 0) {\n            int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);\n            for (int i = 0; i < shortestCount; i++) {\n                int shortestIndex = shortestIndexes[i];\n                offsetWeight -= weights[shortestIndex];\n                if (offsetWeight < 0) {\n                    return invokers.get(shortestIndex);\n                }\n            }\n        }\n        return invokers.get(shortestIndexes[ThreadLocalRandom.current().nextInt(shortestCount)]);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/ArrayMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.lang.reflect.Array;\n\npublic class ArrayMerger implements Merger<Object[]> {\n\n    public static final ArrayMerger INSTANCE = new ArrayMerger();\n\n    @Override\n    public Object[] merge(Object[]... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return new Object[0];\n        }\n\n        int i = 0;\n        while (i < items.length && items[i] == null) {\n            i++;\n        }\n\n        if (i == items.length) {\n            return new Object[0];\n        }\n\n        Class<?> type = items[i].getClass().getComponentType();\n\n        int totalLen = 0;\n        for (; i < items.length; i++) {\n            if (items[i] == null) {\n                continue;\n            }\n            Class<?> itemType = items[i].getClass().getComponentType();\n            if (itemType != type) {\n                throw new IllegalArgumentException(\"Arguments' types are different\");\n            }\n            totalLen += items[i].length;\n        }\n\n        if (totalLen == 0) {\n            return new Object[0];\n        }\n\n        Object result = Array.newInstance(type, totalLen);\n\n        int index = 0;\n        for (Object[] array : items) {\n            if (array != null) {\n                System.arraycopy(array, 0, result, index, array.length);\n                index += array.length;\n            }\n        }\n        return (Object[]) result;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/BooleanArrayMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\npublic class BooleanArrayMerger implements Merger<boolean[]> {\n\n    @Override\n    public boolean[] merge(boolean[]... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return new boolean[0];\n        }\n        int totalLen = 0;\n        for (boolean[] array : items) {\n            if (array != null) {\n                totalLen += array.length;\n            }\n        }\n        boolean[] result = new boolean[totalLen];\n        int index = 0;\n        for (boolean[] array : items) {\n            if (array != null) {\n                System.arraycopy(array, 0, result, index, array.length);\n                index += array.length;\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/ByteArrayMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\npublic class ByteArrayMerger implements Merger<byte[]> {\n\n    @Override\n    public byte[] merge(byte[]... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return new byte[0];\n        }\n        int total = 0;\n        for (byte[] array : items) {\n            if (array != null) {\n                total += array.length;\n            }\n        }\n        byte[] result = new byte[total];\n        int index = 0;\n        for (byte[] array : items) {\n            if (array != null) {\n                System.arraycopy(array, 0, result, index, array.length);\n                index += array.length;\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/CharArrayMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\npublic class CharArrayMerger implements Merger<char[]> {\n\n    @Override\n    public char[] merge(char[]... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return new char[0];\n        }\n        int total = 0;\n        for (char[] array : items) {\n            if (array != null) {\n                total += array.length;\n            }\n        }\n        char[] result = new char[total];\n        int index = 0;\n        for (char[] array : items) {\n            if (array != null) {\n                System.arraycopy(array, 0, result, index, array.length);\n                index += array.length;\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/DoubleArrayMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\npublic class DoubleArrayMerger implements Merger<double[]> {\n\n    @Override\n    public double[] merge(double[]... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return new double[0];\n        }\n        return Arrays.stream(items)\n                .filter(Objects::nonNull)\n                .flatMapToDouble(Arrays::stream)\n                .toArray();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/FloatArrayMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\npublic class FloatArrayMerger implements Merger<float[]> {\n\n    @Override\n    public float[] merge(float[]... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return new float[0];\n        }\n        int total = 0;\n        for (float[] array : items) {\n            if (array != null) {\n                total += array.length;\n            }\n        }\n        float[] result = new float[total];\n        int index = 0;\n        for (float[] array : items) {\n            if (array != null) {\n                System.arraycopy(array, 0, result, index, array.length);\n                index += array.length;\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/IntArrayMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\npublic class IntArrayMerger implements Merger<int[]> {\n\n    @Override\n    public int[] merge(int[]... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return new int[0];\n        }\n        return Arrays.stream(items)\n                .filter(Objects::nonNull)\n                .flatMapToInt(Arrays::stream)\n                .toArray();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/ListMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\npublic class ListMerger implements Merger<List<?>> {\n\n    @Override\n    public List<Object> merge(List<?>... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return Collections.emptyList();\n        }\n        return Stream.of(items)\n                .filter(Objects::nonNull)\n                .flatMap(Collection::stream)\n                .collect(Collectors.toList());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/LongArrayMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\npublic class LongArrayMerger implements Merger<long[]> {\n\n    @Override\n    public long[] merge(long[]... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return new long[0];\n        }\n        return Arrays.stream(items)\n                .filter(Objects::nonNull)\n                .flatMapToLong(Arrays::stream)\n                .toArray();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/MapMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.stream.Stream;\n\npublic class MapMerger implements Merger<Map<?, ?>> {\n\n    @Override\n    public Map<?, ?> merge(Map<?, ?>... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return Collections.emptyMap();\n        }\n        Map<Object, Object> result = new HashMap<>();\n        Stream.of(items).filter(Objects::nonNull).forEach(result::putAll);\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/MergerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.TypeUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_LOAD_MERGER;\n\npublic class MergerFactory implements ScopeModelAware {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MergerFactory.class);\n\n    private ConcurrentMap<Class<?>, Merger<?>> MERGER_CACHE = new ConcurrentHashMap<>();\n    private ScopeModel scopeModel;\n\n    @Override\n    public void setScopeModel(ScopeModel scopeModel) {\n        this.scopeModel = scopeModel;\n    }\n\n    /**\n     * Find the merger according to the returnType class, the merger will\n     * merge an array of returnType into one\n     *\n     * @param returnType the merger will return this type\n     * @return the merger which merges an array of returnType into one, return null if not exist\n     * @throws IllegalArgumentException if returnType is null\n     */\n    public <T> Merger<T> getMerger(Class<T> returnType) {\n        if (returnType == null) {\n            throw new IllegalArgumentException(\"returnType is null\");\n        }\n\n        if (CollectionUtils.isEmptyMap(MERGER_CACHE)) {\n            loadMergers();\n        }\n        Merger merger = MERGER_CACHE.get(returnType);\n        if (merger == null && returnType.isArray()) {\n            merger = ArrayMerger.INSTANCE;\n        }\n        return merger;\n    }\n\n    private void loadMergers() {\n        Set<String> names = scopeModel.getExtensionLoader(Merger.class).getSupportedExtensions();\n        for (String name : names) {\n            Merger m = scopeModel.getExtensionLoader(Merger.class).getExtension(name);\n            Class<?> actualTypeArg = getActualTypeArgument(m.getClass());\n            if (actualTypeArg == null) {\n                logger.warn(\n                        CLUSTER_FAILED_LOAD_MERGER,\n                        \"load merger config failed\",\n                        \"\",\n                        \"Failed to get actual type argument from merger \"\n                                + m.getClass().getName());\n                continue;\n            }\n            MERGER_CACHE.putIfAbsent(actualTypeArg, m);\n        }\n    }\n\n    /**\n     * get merger's actual type argument (same as return type)\n     * @param mergerCls\n     * @return\n     */\n    private Class<?> getActualTypeArgument(Class<? extends Merger> mergerCls) {\n        Class<?> superClass = mergerCls;\n        while (superClass != Object.class) {\n            Type[] interfaceTypes = superClass.getGenericInterfaces();\n            ParameterizedType mergerType;\n            for (Type it : interfaceTypes) {\n                if (it instanceof ParameterizedType\n                        && (mergerType = ((ParameterizedType) it)).getRawType() == Merger.class) {\n                    Type typeArg = mergerType.getActualTypeArguments()[0];\n                    return TypeUtils.getRawClass(typeArg);\n                }\n            }\n\n            superClass = superClass.getSuperclass();\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/SetMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\npublic class SetMerger implements Merger<Set<?>> {\n\n    @Override\n    public Set<Object> merge(Set<?>... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return Collections.emptySet();\n        }\n        Set<Object> result = new HashSet<>();\n        Stream.of(items).filter(Objects::nonNull).forEach(result::addAll);\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/merger/ShortArrayMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.rpc.cluster.Merger;\n\npublic class ShortArrayMerger implements Merger<short[]> {\n\n    @Override\n    public short[] merge(short[]... items) {\n        if (ArrayUtils.isEmpty(items)) {\n            return new short[0];\n        }\n        int total = 0;\n        for (short[] array : items) {\n            if (array != null) {\n                total += array.length;\n            }\n        }\n        short[] result = new short[total];\n        int index = 0;\n        for (short[] array : items) {\n            if (array != null) {\n                System.arraycopy(array, 0, result, index, array.length);\n                index += array.length;\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/AbstractRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.Router;\nimport org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository;\n\npublic abstract class AbstractRouter implements Router {\n    private int priority = DEFAULT_PRIORITY;\n    private boolean force = false;\n    private URL url;\n\n    private GovernanceRuleRepository ruleRepository;\n\n    public AbstractRouter(URL url) {\n        this.ruleRepository = url.getOrDefaultModuleModel()\n                .getExtensionLoader(GovernanceRuleRepository.class)\n                .getDefaultExtension();\n        this.url = url;\n    }\n\n    public AbstractRouter() {}\n\n    @Override\n    public URL getUrl() {\n        return url;\n    }\n\n    public void setUrl(URL url) {\n        this.url = url;\n    }\n\n    @Override\n    public boolean isRuntime() {\n        return true;\n    }\n\n    @Override\n    public boolean isForce() {\n        return force;\n    }\n\n    public void setForce(boolean force) {\n        this.force = force;\n    }\n\n    @Override\n    public int getPriority() {\n        return priority;\n    }\n\n    public void setPriority(int priority) {\n        this.priority = priority;\n    }\n\n    public GovernanceRuleRepository getRuleRepository() {\n        return this.ruleRepository;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/AbstractRouterRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router;\n\nimport java.util.Map;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.DYNAMIC_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.ENABLED_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.KEY_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RAW_RULE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.SCOPE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.VALID_KEY;\n\n/**\n * TODO Extract more code here if necessary\n */\npublic abstract class AbstractRouterRule {\n    private String rawRule;\n    private boolean runtime = true;\n    private boolean force = false;\n    private boolean valid = true;\n    private boolean enabled = true;\n    private int priority;\n    private boolean dynamic = false;\n\n    private String version;\n    private String scope;\n    private String key;\n\n    protected void parseFromMap0(Map<String, Object> map) {\n        setRawRule((String) map.get(RAW_RULE_KEY));\n\n        Object runtime = map.get(RUNTIME_KEY);\n        if (runtime != null) {\n            setRuntime(Boolean.parseBoolean(runtime.toString()));\n        }\n\n        Object force = map.get(FORCE_KEY);\n        if (force != null) {\n            setForce(Boolean.parseBoolean(force.toString()));\n        }\n\n        Object valid = map.get(VALID_KEY);\n        if (valid != null) {\n            setValid(Boolean.parseBoolean(valid.toString()));\n        }\n\n        Object enabled = map.get(ENABLED_KEY);\n        if (enabled != null) {\n            setEnabled(Boolean.parseBoolean(enabled.toString()));\n        }\n\n        Object priority = map.get(PRIORITY_KEY);\n        if (priority != null) {\n            setPriority(Integer.parseInt(priority.toString()));\n        }\n\n        Object dynamic = map.get(DYNAMIC_KEY);\n        if (dynamic != null) {\n            setDynamic(Boolean.parseBoolean(dynamic.toString()));\n        }\n\n        setScope((String) map.get(SCOPE_KEY));\n        setKey((String) map.get(KEY_KEY));\n        setVersion((String) map.get(CONFIG_VERSION_KEY));\n    }\n\n    public String getRawRule() {\n        return rawRule;\n    }\n\n    public void setRawRule(String rawRule) {\n        this.rawRule = rawRule;\n    }\n\n    public boolean isRuntime() {\n        return runtime;\n    }\n\n    public void setRuntime(boolean runtime) {\n        this.runtime = runtime;\n    }\n\n    public boolean isForce() {\n        return force;\n    }\n\n    public void setForce(boolean force) {\n        this.force = force;\n    }\n\n    public boolean isValid() {\n        return valid;\n    }\n\n    public void setValid(boolean valid) {\n        this.valid = valid;\n    }\n\n    public boolean isEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public int getPriority() {\n        return priority;\n    }\n\n    public void setPriority(int priority) {\n        this.priority = priority;\n    }\n\n    public boolean isDynamic() {\n        return dynamic;\n    }\n\n    public void setDynamic(boolean dynamic) {\n        this.dynamic = dynamic;\n    }\n\n    public String getScope() {\n        return scope;\n    }\n\n    public void setScope(String scope) {\n        this.scope = scope;\n    }\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/RouterResult.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router;\n\nimport java.util.List;\n\npublic class RouterResult<T> {\n    private final boolean needContinueRoute;\n    private final List<T> result;\n    private final String message;\n\n    public RouterResult(List<T> result) {\n        this.needContinueRoute = true;\n        this.result = result;\n        this.message = null;\n    }\n\n    public RouterResult(List<T> result, String message) {\n        this.needContinueRoute = true;\n        this.result = result;\n        this.message = message;\n    }\n\n    public RouterResult(boolean needContinueRoute, List<T> result, String message) {\n        this.needContinueRoute = needContinueRoute;\n        this.result = result;\n        this.message = message;\n    }\n\n    public boolean isNeedContinueRoute() {\n        return needContinueRoute;\n    }\n\n    public List<T> getResult() {\n        return result;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/RouterSnapshotFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.BaseFilter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\n\n@Activate(group = {CONSUMER})\npublic class RouterSnapshotFilter implements ClusterFilter, BaseFilter.Listener {\n\n    private final RouterSnapshotSwitcher switcher;\n    private static final Logger logger = LoggerFactory.getLogger(RouterSnapshotFilter.class);\n\n    public RouterSnapshotFilter(FrameworkModel frameworkModel) {\n        this.switcher = frameworkModel.getBeanFactory().getBean(RouterSnapshotSwitcher.class);\n    }\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        if (!switcher.isEnable()) {\n            return invoker.invoke(invocation);\n        }\n\n        if (!logger.isInfoEnabled()) {\n            return invoker.invoke(invocation);\n        }\n\n        if (!switcher.isEnable(invocation.getServiceModel().getServiceKey())) {\n            return invoker.invoke(invocation);\n        }\n\n        RpcContext.getServiceContext().setNeedPrintRouterSnapshot(true);\n        return invoker.invoke(invocation);\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {\n        RpcContext.getServiceContext().setNeedPrintRouterSnapshot(false);\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        RpcContext.getServiceContext().setNeedPrintRouterSnapshot(false);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/RouterSnapshotNode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\npublic class RouterSnapshotNode<T> {\n    private final String name;\n    private final int beforeSize;\n    private int nodeOutputSize;\n    private int chainOutputSize;\n    private String routerMessage;\n    private final List<Invoker<T>> inputInvokers;\n    private List<Invoker<T>> nodeOutputInvokers;\n    private List<Invoker<T>> chainOutputInvokers;\n    private final List<RouterSnapshotNode<T>> nextNode = new LinkedList<>();\n    private RouterSnapshotNode<T> parentNode;\n\n    public RouterSnapshotNode(String name, List<Invoker<T>> inputInvokers) {\n        this.name = name;\n        this.beforeSize = inputInvokers.size();\n        if (inputInvokers instanceof BitList) {\n            this.inputInvokers = inputInvokers;\n        } else {\n            this.inputInvokers = new ArrayList<>(5);\n            for (int i = 0; i < Math.min(5, beforeSize); i++) {\n                this.inputInvokers.add(inputInvokers.get(i));\n            }\n        }\n        this.nodeOutputSize = 0;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public int getBeforeSize() {\n        return beforeSize;\n    }\n\n    public int getNodeOutputSize() {\n        return nodeOutputSize;\n    }\n\n    public String getRouterMessage() {\n        return routerMessage;\n    }\n\n    public void setRouterMessage(String routerMessage) {\n        this.routerMessage = routerMessage;\n    }\n\n    public List<Invoker<T>> getNodeOutputInvokers() {\n        return nodeOutputInvokers;\n    }\n\n    public void setNodeOutputInvokers(List<Invoker<T>> outputInvokers) {\n        this.nodeOutputInvokers = outputInvokers;\n        this.nodeOutputSize = outputInvokers == null ? 0 : outputInvokers.size();\n    }\n\n    public void setChainOutputInvokers(List<Invoker<T>> outputInvokers) {\n        this.chainOutputInvokers = outputInvokers;\n        this.chainOutputSize = outputInvokers == null ? 0 : outputInvokers.size();\n    }\n\n    public int getChainOutputSize() {\n        return chainOutputSize;\n    }\n\n    public List<Invoker<T>> getChainOutputInvokers() {\n        return chainOutputInvokers;\n    }\n\n    public List<RouterSnapshotNode<T>> getNextNode() {\n        return nextNode;\n    }\n\n    public RouterSnapshotNode<T> getParentNode() {\n        return parentNode;\n    }\n\n    public void appendNode(RouterSnapshotNode<T> nextNode) {\n        this.nextNode.add(nextNode);\n        nextNode.parentNode = this;\n    }\n\n    @Override\n    public String toString() {\n        return toString(1);\n    }\n\n    public String toString(int level) {\n        StringBuilder stringBuilder = new StringBuilder();\n        stringBuilder\n                .append(\"[ \")\n                .append(name)\n                .append(' ')\n                .append(\"(Input: \")\n                .append(beforeSize)\n                .append(\") \")\n                .append(\"(Current Node Output: \")\n                .append(nodeOutputSize)\n                .append(\") \")\n                .append(\"(Chain Node Output: \")\n                .append(chainOutputSize)\n                .append(')')\n                .append(routerMessage == null ? \"\" : \" Router message: \")\n                .append(routerMessage == null ? \"\" : routerMessage)\n                .append(\" ] \");\n        if (level == 1) {\n            stringBuilder\n                    .append(\"Input: \")\n                    .append(\n                            CollectionUtils.isEmpty(inputInvokers)\n                                    ? \"Empty\"\n                                    : inputInvokers.subList(0, Math.min(5, inputInvokers.size())).stream()\n                                            .map(Invoker::getUrl)\n                                            .map(URL::getAddress)\n                                            .collect(Collectors.joining(\",\")))\n                    .append(\" -> \");\n\n            stringBuilder\n                    .append(\"Chain Node Output: \")\n                    .append(\n                            CollectionUtils.isEmpty(chainOutputInvokers)\n                                    ? \"Empty\"\n                                    : chainOutputInvokers.subList(0, Math.min(5, chainOutputInvokers.size())).stream()\n                                            .map(Invoker::getUrl)\n                                            .map(URL::getAddress)\n                                            .collect(Collectors.joining(\",\")));\n        } else {\n            stringBuilder\n                    .append(\"Current Node Output: \")\n                    .append(\n                            CollectionUtils.isEmpty(nodeOutputInvokers)\n                                    ? \"Empty\"\n                                    : nodeOutputInvokers.subList(0, Math.min(5, nodeOutputInvokers.size())).stream()\n                                            .map(Invoker::getUrl)\n                                            .map(URL::getAddress)\n                                            .collect(Collectors.joining(\",\")));\n        }\n\n        if (nodeOutputInvokers != null && nodeOutputInvokers.size() > 5) {\n            stringBuilder.append(\"...\");\n        }\n        for (RouterSnapshotNode<T> node : nextNode) {\n            stringBuilder.append(\"\\n\");\n            for (int i = 0; i < level; i++) {\n                stringBuilder.append(\"  \");\n            }\n            stringBuilder.append(node.toString(level + 1));\n        }\n        return stringBuilder.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/RouterSnapshotSwitcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router;\n\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\n\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicInteger;\n\npublic class RouterSnapshotSwitcher {\n    private volatile boolean enable;\n    private final Set<String> enabledService = new ConcurrentHashSet<>();\n\n    private static final int MAX_LENGTH = 1 << 5; // 2 ^ 5 = 31\n\n    private final AtomicInteger offset = new AtomicInteger(0);\n    private volatile String[] recentSnapshot = new String[MAX_LENGTH];\n\n    public boolean isEnable() {\n        return enable;\n    }\n\n    public synchronized void addEnabledService(String service) {\n        enabledService.add(service);\n        enable = true;\n        recentSnapshot = new String[MAX_LENGTH];\n    }\n\n    public boolean isEnable(String service) {\n        return enabledService.contains(service);\n    }\n\n    public synchronized void removeEnabledService(String service) {\n        enabledService.remove(service);\n        enable = enabledService.size() > 0;\n        recentSnapshot = new String[MAX_LENGTH];\n    }\n\n    public synchronized Set<String> getEnabledService() {\n        return Collections.unmodifiableSet(enabledService);\n    }\n\n    public void setSnapshot(String snapshot) {\n        if (enable) {\n            // lock free\n            recentSnapshot[offset.getAndIncrement() % MAX_LENGTH] = System.currentTimeMillis() + \" - \" + snapshot;\n        }\n    }\n\n    public String[] cloneSnapshot() {\n        String[] clonedSnapshot = new String[MAX_LENGTH];\n        for (int i = 0; i < MAX_LENGTH; i++) {\n            clonedSnapshot[i] = recentSnapshot[i];\n        }\n        return clonedSnapshot;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/affinity/AffinityStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.affinity;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcher;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.text.ParseException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_EXEC_CONDITION_ROUTER;\nimport static org.apache.dubbo.rpc.cluster.Constants.AFFINITY_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.DefaultAffinityRatio;\nimport static org.apache.dubbo.rpc.cluster.Constants.RATIO_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;\n\n/**\n * # dubbo/config/group/{$name}.affinity-router\n * configVersion: v3.1\n * scope: service # Or application\n * key: service.apache.com\n * enabled: true\n * runtime: true\n * affinityAware:\n *   key: region\n *   ratio: 20\n */\npublic class AffinityStateRouter<T> extends AbstractStateRouter<T> {\n    public static final String NAME = \"affinity\";\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractStateRouter.class);\n\n    protected String affinityKey;\n    protected Double ratio;\n    protected ConditionMatcher matchMatcher;\n    protected List<ConditionMatcherFactory> matcherFactories;\n\n    private final boolean enabled;\n\n    public AffinityStateRouter(URL url) {\n        super(url);\n        this.enabled = url.getParameter(ENABLED_KEY, true);\n        this.affinityKey = url.getParameter(AFFINITY_KEY, \"\");\n        this.ratio = url.getParameter(RATIO_KEY, DefaultAffinityRatio);\n        this.matcherFactories =\n                moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();\n        if (this.enabled) {\n            this.init(affinityKey);\n        }\n    }\n\n    public AffinityStateRouter(URL url, String affinityKey, Double ratio, boolean enabled) {\n        super(url);\n        this.enabled = enabled;\n        this.affinityKey = affinityKey;\n        this.ratio = ratio;\n        matcherFactories =\n                moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();\n        if (this.enabled) {\n            this.init(affinityKey);\n        }\n    }\n\n    public void init(String rule) {\n        try {\n            if (rule == null || rule.trim().isEmpty()) {\n                throw new IllegalArgumentException(\"Illegal affinity rule!\");\n            }\n            this.matchMatcher = parseRule(affinityKey);\n        } catch (ParseException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    private ConditionMatcher parseRule(String rule) throws ParseException {\n        ConditionMatcher matcher = getMatcher(rule);\n        // Multiple values\n        Set<String> values = matcher.getMatches();\n        values.add(getUrl().getParameter(rule));\n        return matcher;\n    }\n\n    @Override\n    protected BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException {\n        if (!enabled) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Directly return. Reason: AffinityRouter disabled.\");\n            }\n            return invokers;\n        }\n\n        if (CollectionUtils.isEmpty(invokers)) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Directly return. Reason: Invokers from previous router is empty.\");\n            }\n            return invokers;\n        }\n        try {\n            BitList<Invoker<T>> result = invokers.clone();\n            result.removeIf(invoker -> !matchInvoker(invoker.getUrl(), url));\n\n            if (result.size() / (double) invokers.size() >= ratio / (double) 100) {\n                if (needToPrintMessage) {\n                    messageHolder.set(\"Match return.\");\n                }\n                return result;\n            } else {\n                logger.warn(\n                        CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,\n                        \"execute affinity state router result is less than defined\" + this.ratio,\n                        \"\",\n                        \"The affinity result is ignored. consumer: \" + NetUtils.getLocalHost()\n                                + \", service: \" + url.getServiceKey() + \", router: \"\n                                + url.getParameterAndDecoded(RULE_KEY));\n                if (needToPrintMessage) {\n                    messageHolder.set(\"Directly return. Reason: Affinity state router result is less than defined.\");\n                }\n                return invokers;\n            }\n        } catch (Throwable t) {\n            logger.error(\n                    CLUSTER_FAILED_EXEC_CONDITION_ROUTER,\n                    \"execute affinity state router exception\",\n                    \"\",\n                    \"Failed to execute affinity router rule: \" + getUrl() + \", invokers: \" + invokers + \", cause: \"\n                            + t.getMessage(),\n                    t);\n        }\n        if (needToPrintMessage) {\n            messageHolder.set(\"Directly return. Reason: Error occurred ( or result is empty ).\");\n        }\n        return invokers;\n    }\n\n    @Override\n    public boolean isRuntime() {\n        // We always return true for previously defined Router, that is, old Router doesn't support cache anymore.\n        //        return true;\n        return this.getUrl().getParameter(RUNTIME_KEY, false);\n    }\n\n    private ConditionMatcher getMatcher(String key) {\n        return moduleModel\n                .getExtensionLoader(ConditionMatcherFactory.class)\n                .getExtension(\"param\")\n                .createMatcher(key, moduleModel);\n    }\n\n    private boolean matchInvoker(URL url, URL param) {\n        return doMatch(url, param, null, matchMatcher);\n    }\n\n    private boolean doMatch(URL url, URL param, Invocation invocation, ConditionMatcher matcher) {\n        Map<String, String> sample = url.toOriginalMap();\n        if (!matcher.isMatch(sample, param, invocation, false)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/affinity/AffinityStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.affinity;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.router.state.CacheableStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\n\n/**\n * affinity router factory\n */\npublic class AffinityStateRouterFactory extends CacheableStateRouterFactory {\n\n    public static final String NAME = \"affinity\";\n\n    @Override\n    protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {\n        return new AffinityStateRouter<T>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/affinity/config/AffinityListenableStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.affinity.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.affinity.AffinityStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.affinity.config.model.AffinityRouterRule;\nimport org.apache.dubbo.rpc.cluster.router.affinity.config.model.AffinityRuleParser;\nimport org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.state.TailStateRouter;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RULE_PARSING;\n\n/**\n * Abstract router which listens to dynamic configuration\n */\npublic abstract class AffinityListenableStateRouter<T> extends AbstractStateRouter<T> implements ConfigurationListener {\n    public static final String NAME = \"Affinity_LISTENABLE_ROUTER\";\n    public static final String RULE_SUFFIX = \".affinity-router\";\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(AffinityListenableStateRouter.class);\n    private volatile AffinityRouterRule affinityRouterRule;\n    private volatile AffinityStateRouter<T> affinityRouter;\n    private final String ruleKey;\n\n    public AffinityListenableStateRouter(URL url, String ruleKey) {\n        super(url);\n        this.setForce(false);\n        this.init(ruleKey);\n        this.ruleKey = ruleKey;\n    }\n\n    @Override\n    public synchronized void process(ConfigChangedEvent event) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Notification of affinity rule, change type is: \" + event.getChangeType() + \", raw rule is:\\n \"\n                    + event.getContent());\n        }\n\n        if (event.getChangeType().equals(ConfigChangeType.DELETED)) {\n            affinityRouterRule = null;\n            affinityRouter = null;\n        } else {\n            try {\n                affinityRouterRule = AffinityRuleParser.parse(event.getContent());\n                generateConditions(affinityRouterRule);\n            } catch (Exception e) {\n                logger.error(\n                        CLUSTER_FAILED_RULE_PARSING,\n                        \"Failed to parse the raw affinity rule\",\n                        \"\",\n                        \"Failed to parse the raw affinity rule and it will not take effect, please check \"\n                                + \"if the affinity rule matches with the template, the raw rule is:\\n \"\n                                + event.getContent(),\n                        e);\n            }\n        }\n    }\n\n    @Override\n    public BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException {\n        if (CollectionUtils.isEmpty(invokers) || affinityRouter == null) {\n            if (needToPrintMessage) {\n                messageHolder.set(\n                        \"Directly return. Reason: Invokers from previous router is empty or affinityRouter is null.\");\n            }\n            return invokers;\n        }\n\n        // We will check enabled status inside each router.\n        StringBuilder resultMessage = null;\n        if (needToPrintMessage) {\n            resultMessage = new StringBuilder();\n        }\n        invokers = affinityRouter.route(invokers, url, invocation, needToPrintMessage, nodeHolder);\n        if (needToPrintMessage) {\n            resultMessage.append(messageHolder.get());\n        }\n\n        if (needToPrintMessage) {\n            messageHolder.set(resultMessage.toString());\n        }\n\n        return invokers;\n    }\n\n    @Override\n    public boolean isForce() {\n        return (affinityRouterRule != null && affinityRouterRule.isForce());\n    }\n\n    private boolean isRuleRuntime() {\n        return affinityRouterRule != null && affinityRouterRule.isValid() && affinityRouterRule.isRuntime();\n    }\n\n    private void generateConditions(AbstractRouterRule rule) {\n        if (rule == null || !rule.isValid()) {\n            return;\n        }\n        AffinityRouterRule affinityRule = (AffinityRouterRule) rule;\n        affinityRouter = new AffinityStateRouter<>(\n                getUrl(), affinityRule.getAffinityKey(), affinityRule.getRatio(), affinityRule.isEnabled());\n        affinityRouter.setNextRouter(TailStateRouter.getInstance());\n    }\n\n    private synchronized void init(String ruleKey) {\n        if (StringUtils.isEmpty(ruleKey)) {\n            return;\n        }\n        String routerKey = ruleKey + RULE_SUFFIX;\n        this.getRuleRepository().addListener(routerKey, this);\n        String rule = this.getRuleRepository().getRule(routerKey, DynamicConfiguration.DEFAULT_GROUP);\n        if (StringUtils.isNotEmpty(rule)) {\n            this.process(new ConfigChangedEvent(routerKey, DynamicConfiguration.DEFAULT_GROUP, rule));\n        }\n    }\n\n    public AffinityStateRouter<T> getAffinityRouter() {\n        return affinityRouter;\n    }\n\n    @Override\n    public void stop() {\n        this.getRuleRepository().removeListener(ruleKey + RULE_SUFFIX, this);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/affinity/config/AffinityProviderAppStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.affinity.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.router.condition.config.ListenableStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_TAG_ROUTE_EMPTY;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\n\n/**\n * Application level affinity router, \"application.affinity-router\"\n */\npublic class AffinityProviderAppStateRouter<T> extends ListenableStateRouter<T> {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ListenableStateRouter.class);\n    public static final String NAME = \"AFFINITY_PROVIDER_APP_ROUTER\";\n    private String application;\n    private final String currentApplication;\n\n    public AffinityProviderAppStateRouter(URL url) {\n        super(url, url.getApplication());\n        this.currentApplication = url.getApplication();\n    }\n\n    @Override\n    public void notify(BitList<Invoker<T>> invokers) {\n        if (CollectionUtils.isEmpty(invokers)) {\n            return;\n        }\n\n        Invoker<T> invoker = invokers.get(0);\n        URL url = invoker.getUrl();\n        String providerApplication = url.getRemoteApplication();\n\n        // provider application is empty or equals with the current application\n        if (isEmpty(providerApplication)) {\n            logger.warn(\n                    CLUSTER_TAG_ROUTE_EMPTY,\n                    \"affinity router get providerApplication is empty, will not subscribe to provider app rules.\",\n                    \"\",\n                    \"\");\n            return;\n        }\n        if (providerApplication.equals(currentApplication)) {\n            return;\n        }\n\n        synchronized (this) {\n            if (!providerApplication.equals(application)) {\n                if (StringUtils.isNotEmpty(application)) {\n                    this.getRuleRepository().removeListener(application + RULE_SUFFIX, this);\n                }\n                String key = providerApplication + RULE_SUFFIX;\n                this.getRuleRepository().addListener(key, this);\n                application = providerApplication;\n                String rawRule = this.getRuleRepository().getRule(key, DynamicConfiguration.DEFAULT_GROUP);\n                if (StringUtils.isNotEmpty(rawRule)) {\n                    this.process(new ConfigChangedEvent(key, DynamicConfiguration.DEFAULT_GROUP, rawRule));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/affinity/config/AffinityProviderAppStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.affinity.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.state.CacheableStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\n\n/**\n * AffinityProvider router factory\n */\n@Activate(order = 135)\npublic class AffinityProviderAppStateRouterFactory extends CacheableStateRouterFactory {\n\n    public static final String NAME = \"affinity-provider-app\";\n\n    @Override\n    protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {\n        return new AffinityProviderAppStateRouter<>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/affinity/config/AffinityServiceStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.affinity.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\n\n/**\n * Service level router, \"server-unique-name.affinity-router\"\n */\npublic class AffinityServiceStateRouter<T> extends AffinityListenableStateRouter<T> {\n    public static final String NAME = \"AFFINITY_SERVICE_ROUTER\";\n\n    public AffinityServiceStateRouter(URL url) {\n        super(url, DynamicConfiguration.getRuleKey(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/affinity/config/AffinityServiceStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.affinity.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.state.CacheableStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\n\n/**\n * Service level affinity router factory\n */\n@Activate(order = 130)\npublic class AffinityServiceStateRouterFactory extends CacheableStateRouterFactory {\n\n    public static final String NAME = \"affinity_service\";\n\n    @Override\n    protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {\n        return new AffinityServiceStateRouter<T>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/affinity/config/model/AffinityRouterRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.affinity.config.model;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;\n\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RULE_PARSING;\nimport static org.apache.dubbo.rpc.cluster.Constants.AFFINITY_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.DefaultAffinityRatio;\n\npublic class AffinityRouterRule extends AbstractRouterRule {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AffinityRouterRule.class);\n    private String affinityKey;\n    private Double ratio;\n\n    @SuppressWarnings(\"unchecked\")\n    public static AffinityRouterRule parseFromMap(Map<String, Object> map) {\n        AffinityRouterRule affinityRouterRule = new AffinityRouterRule();\n        affinityRouterRule.parseFromMap0(map);\n        Object conditions = map.get(AFFINITY_KEY);\n\n        Map<String, String> conditionMap = (Map<String, String>) conditions;\n        affinityRouterRule.setAffinityKey(conditionMap.get(\"key\"));\n        Object ratio = conditionMap.getOrDefault(\"ratio\", String.valueOf(DefaultAffinityRatio));\n        affinityRouterRule.setRatio(Double.valueOf(String.valueOf(ratio)));\n\n        if (affinityRouterRule.getRatio() > 100 || affinityRouterRule.getRatio() < 0) {\n            logger.error(\n                    CLUSTER_FAILED_RULE_PARSING,\n                    \"Invalid affinity router config.\",\n                    \"\",\n                    \"The ratio value must range from 0 to 100\");\n            affinityRouterRule.setValid(false);\n        }\n        return affinityRouterRule;\n    }\n\n    public AffinityRouterRule() {}\n\n    public String getAffinityKey() {\n        return affinityKey;\n    }\n\n    public void setAffinityKey(String affinityKey) {\n        this.affinityKey = affinityKey;\n    }\n\n    public Double getRatio() {\n        return ratio;\n    }\n\n    public void setRatio(Double ratio) {\n        this.ratio = ratio;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/affinity/config/model/AffinityRuleParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.affinity.config.model;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Map;\n\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_VERSION_V31;\n\n/**\n * # dubbo/config/group/{$name}.affinity-router\n * configVersion: v3.1\n * scope: service # Or application\n * key: service.apache.com\n * enabled: true\n * runtime: true\n * affinityAware:\n *   key: region\n *   ratio: 20\n */\npublic class AffinityRuleParser {\n\n    public static AffinityRouterRule parse(String rawRule) {\n        AffinityRouterRule rule;\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Map<String, Object> map = yaml.load(rawRule);\n        String confVersion = (String) map.get(CONFIG_VERSION_KEY);\n\n        rule = AffinityRouterRule.parseFromMap(map);\n        if (StringUtils.isEmpty(rule.getAffinityKey()) || !confVersion.startsWith(RULE_VERSION_V31)) {\n            rule.setValid(false);\n        }\n        rule.setRawRule(rawRule);\n\n        return rule;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcher;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.ValuePattern;\nimport org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.text.ParseException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_EXEC_CONDITION_ROUTER;\nimport static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;\n\n/**\n * Condition Router directs traffics matching the 'when condition' to a particular address subset determined by the 'then condition'.\n * One typical condition rule is like below, with\n * 1. the 'when condition' on the left side of '=>' contains matching rule like 'method=sayHello' and 'method=sayHi'\n * 2. the 'then condition' on the right side of '=>' contains matching rule like 'region=hangzhou' and 'address=*:20881'\n * <p>\n * By default, condition router support matching rules like 'foo=bar', 'foo=bar*', 'arguments[0]=bar', 'attachments[foo]=bar', 'attachments[foo]=1~100', etc.\n * It's also very easy to add customized matching rules by extending {@link ConditionMatcherFactory}\n * and {@link ValuePattern}\n * <p>\n * ---\n * scope: service\n * force: true\n * runtime: true\n * enabled: true\n * key: org.apache.dubbo.samples.governance.api.DemoService\n * conditions:\n * - method=sayHello => region=hangzhou\n * - method=sayHi => address=*:20881\n * ...\n */\npublic class ConditionStateRouter<T> extends AbstractStateRouter<T> {\n    public static final String NAME = \"condition\";\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractStateRouter.class);\n    protected static final Pattern ROUTE_PATTERN = Pattern.compile(\"([&!=,]*)\\\\s*([^&!=,\\\\s]+)\");\n    protected Map<String, ConditionMatcher> whenCondition;\n    protected Map<String, ConditionMatcher> thenCondition;\n    protected List<ConditionMatcherFactory> matcherFactories;\n\n    private final boolean enabled;\n\n    public ConditionStateRouter(URL url, String rule, boolean force, boolean enabled) {\n        super(url);\n        this.setForce(force);\n        this.enabled = enabled;\n        matcherFactories =\n                moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();\n        if (enabled) {\n            this.init(rule);\n        }\n    }\n\n    public ConditionStateRouter(URL url) {\n        super(url);\n        this.setUrl(url);\n        this.setForce(url.getParameter(FORCE_KEY, false));\n        matcherFactories =\n                moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();\n        this.enabled = url.getParameter(ENABLED_KEY, true);\n        if (enabled) {\n            init(url.getParameterAndDecoded(RULE_KEY));\n        }\n    }\n\n    public void init(String rule) {\n        try {\n            if (rule == null || rule.trim().length() == 0) {\n                throw new IllegalArgumentException(\"Illegal route rule!\");\n            }\n            rule = rule.replace(\"consumer.\", \"\").replace(\"provider.\", \"\");\n            int i = rule.indexOf(\"=>\");\n            String whenRule = i < 0 ? null : rule.substring(0, i).trim();\n            String thenRule = i < 0 ? rule.trim() : rule.substring(i + 2).trim();\n            Map<String, ConditionMatcher> when =\n                    StringUtils.isBlank(whenRule) || \"true\".equals(whenRule) ? new HashMap<>() : parseRule(whenRule);\n            Map<String, ConditionMatcher> then =\n                    StringUtils.isBlank(thenRule) || \"false\".equals(thenRule) ? null : parseRule(thenRule);\n            // NOTE: It should be determined on the business level whether the `When condition` can be empty or not.\n            this.whenCondition = when;\n            this.thenCondition = then;\n        } catch (ParseException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    private Map<String, ConditionMatcher> parseRule(String rule) throws ParseException {\n        Map<String, ConditionMatcher> condition = new HashMap<>();\n        if (StringUtils.isBlank(rule)) {\n            return condition;\n        }\n        // Key-Value pair, stores both match and mismatch conditions\n        ConditionMatcher matcherPair = null;\n        // Multiple values\n        Set<String> values = null;\n        final Matcher matcher = ROUTE_PATTERN.matcher(rule);\n        while (matcher.find()) { // Try to match one by one\n            String separator = matcher.group(1);\n            String content = matcher.group(2);\n            // Start part of the condition expression.\n            if (StringUtils.isEmpty(separator)) {\n                matcherPair = this.getMatcher(content);\n                condition.put(content, matcherPair);\n            }\n            // The KV part of the condition expression\n            else if (\"&\".equals(separator)) {\n                if (condition.get(content) == null) {\n                    matcherPair = this.getMatcher(content);\n                    condition.put(content, matcherPair);\n                } else {\n                    matcherPair = condition.get(content);\n                }\n            }\n            // The Value in the KV part.\n            else if (\"=\".equals(separator)) {\n                if (matcherPair == null) {\n                    throw new ParseException(\n                            \"Illegal route rule \\\"\"\n                                    + rule + \"\\\", The error char '\" + separator\n                                    + \"' at index \" + matcher.start() + \" before \\\"\"\n                                    + content + \"\\\".\",\n                            matcher.start());\n                }\n\n                values = matcherPair.getMatches();\n                values.add(content);\n            }\n            // The Value in the KV part.\n            else if (\"!=\".equals(separator)) {\n                if (matcherPair == null) {\n                    throw new ParseException(\n                            \"Illegal route rule \\\"\"\n                                    + rule + \"\\\", The error char '\" + separator\n                                    + \"' at index \" + matcher.start() + \" before \\\"\"\n                                    + content + \"\\\".\",\n                            matcher.start());\n                }\n\n                values = matcherPair.getMismatches();\n                values.add(content);\n            }\n            // The Value in the KV part, if Value have more than one items.\n            else if (\",\".equals(separator)) { // Should be separated by ','\n                if (values == null || values.isEmpty()) {\n                    throw new ParseException(\n                            \"Illegal route rule \\\"\"\n                                    + rule + \"\\\", The error char '\" + separator\n                                    + \"' at index \" + matcher.start() + \" before \\\"\"\n                                    + content + \"\\\".\",\n                            matcher.start());\n                }\n                values.add(content);\n            } else {\n                throw new ParseException(\n                        \"Illegal route rule \\\"\" + rule\n                                + \"\\\", The error char '\" + separator + \"' at index \"\n                                + matcher.start() + \" before \\\"\" + content + \"\\\".\",\n                        matcher.start());\n            }\n        }\n        return condition;\n    }\n\n    @Override\n    protected BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException {\n        if (!enabled) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Directly return. Reason: ConditionRouter disabled.\");\n            }\n            return invokers;\n        }\n\n        if (CollectionUtils.isEmpty(invokers)) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Directly return. Reason: Invokers from previous router is empty.\");\n            }\n            return invokers;\n        }\n        try {\n            if (!matchWhen(url, invocation)) {\n                if (needToPrintMessage) {\n                    messageHolder.set(\"Directly return. Reason: WhenCondition not match.\");\n                }\n                return invokers;\n            }\n            if (thenCondition == null) {\n                logger.warn(\n                        CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,\n                        \"condition state router thenCondition is empty\",\n                        \"\",\n                        \"The current consumer in the service blocklist. consumer: \" + NetUtils.getLocalHost()\n                                + \", service: \" + url.getServiceKey());\n                if (needToPrintMessage) {\n                    messageHolder.set(\"Empty return. Reason: ThenCondition is empty.\");\n                }\n                return BitList.emptyList();\n            }\n            BitList<Invoker<T>> result = invokers.clone();\n            result.removeIf(invoker -> !matchThen(invoker.getUrl(), url));\n\n            if (!result.isEmpty()) {\n                if (needToPrintMessage) {\n                    messageHolder.set(\"Match return.\");\n                }\n                return result;\n            } else if (this.isForce()) {\n                logger.warn(\n                        CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,\n                        \"execute condition state router result list is empty. and force=true\",\n                        \"\",\n                        \"The route result is empty and force execute. consumer: \" + NetUtils.getLocalHost()\n                                + \", service: \" + url.getServiceKey() + \", router: \"\n                                + url.getParameterAndDecoded(RULE_KEY));\n                if (needToPrintMessage) {\n                    messageHolder.set(\"Empty return. Reason: Empty result from condition and condition is force.\");\n                }\n                return result;\n            }\n        } catch (Throwable t) {\n            logger.error(\n                    CLUSTER_FAILED_EXEC_CONDITION_ROUTER,\n                    \"execute condition state router exception\",\n                    \"\",\n                    \"Failed to execute condition router rule: \" + getUrl() + \", invokers: \" + invokers + \", cause: \"\n                            + t.getMessage(),\n                    t);\n        }\n        if (needToPrintMessage) {\n            messageHolder.set(\"Directly return. Reason: Error occurred ( or result is empty ).\");\n        }\n        return invokers;\n    }\n\n    @Override\n    public boolean isRuntime() {\n        // We always return true for previously defined Router, that is, old Router doesn't support cache anymore.\n        //        return true;\n        return this.getUrl().getParameter(RUNTIME_KEY, false);\n    }\n\n    private ConditionMatcher getMatcher(String key) {\n        for (ConditionMatcherFactory factory : matcherFactories) {\n            if (factory.shouldMatch(key)) {\n                return factory.createMatcher(key, moduleModel);\n            }\n        }\n        return moduleModel\n                .getExtensionLoader(ConditionMatcherFactory.class)\n                .getExtension(\"param\")\n                .createMatcher(key, moduleModel);\n    }\n\n    boolean matchWhen(URL url, Invocation invocation) {\n        if (CollectionUtils.isEmptyMap(whenCondition)) {\n            return true;\n        }\n\n        return doMatch(url, null, invocation, whenCondition, true);\n    }\n\n    private boolean matchThen(URL url, URL param) {\n        if (CollectionUtils.isEmptyMap(thenCondition)) {\n            return false;\n        }\n\n        return doMatch(url, param, null, thenCondition, false);\n    }\n\n    private boolean doMatch(\n            URL url,\n            URL param,\n            Invocation invocation,\n            Map<String, ConditionMatcher> conditions,\n            boolean isWhenCondition) {\n        Map<String, String> sample = url.toOriginalMap();\n        for (Map.Entry<String, ConditionMatcher> entry : conditions.entrySet()) {\n            ConditionMatcher matchPair = entry.getValue();\n            if (!matchPair.isMatch(sample, param, invocation, isWhenCondition)) {\n                return false;\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.router.state.CacheableStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\n\n/**\n * ConditionRouterFactory\n * Load when \"override://\" is configured {@link ConditionStateRouter}\n */\npublic class ConditionStateRouterFactory extends CacheableStateRouterFactory {\n\n    public static final String NAME = \"condition\";\n\n    @Override\n    protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {\n        return new ConditionStateRouter<>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/MultiDestConditionRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.condition.config.model.ConditionSubSet;\nimport org.apache.dubbo.rpc.cluster.router.condition.config.model.DestinationSet;\nimport org.apache.dubbo.rpc.cluster.router.condition.config.model.MultiDestCondition;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcher;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_EXEC_CONDITION_ROUTER;\nimport static org.apache.dubbo.rpc.cluster.Constants.DefaultRouteConditionSubSetWeight;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;\n\npublic class MultiDestConditionRouter<T> extends AbstractStateRouter<T> {\n    public static final String NAME = \"multi_condition\";\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractStateRouter.class);\n    protected static final Pattern ROUTE_PATTERN = Pattern.compile(\"([&!=,]*)\\\\s*([^&!=,\\\\s]+)\");\n    private Map<String, ConditionMatcher> whenCondition;\n    private List<ConditionSubSet> thenCondition;\n    private boolean force;\n    protected List<ConditionMatcherFactory> matcherFactories;\n    private boolean enabled;\n\n    public MultiDestConditionRouter(URL url, MultiDestCondition multiDestCondition, boolean force, boolean enabled) {\n        super(url);\n        this.setForce(force);\n        this.enabled = enabled;\n        matcherFactories =\n                moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();\n        this.init(multiDestCondition.getFrom(), multiDestCondition.getTo());\n    }\n\n    public void init(Map<String, String> from, List<Map<String, String>> to) {\n        try {\n            if (from == null || to == null) {\n                throw new IllegalArgumentException(\"Illegal route rule!\");\n            }\n            String whenRule = from.get(\"match\");\n            Map<String, ConditionMatcher> when =\n                    StringUtils.isBlank(whenRule) || \"true\".equals(whenRule) ? new HashMap<>() : parseRule(whenRule);\n            this.whenCondition = when;\n\n            List<ConditionSubSet> thenConditions = new ArrayList<>();\n            for (Map<String, String> toMap : to) {\n                String thenRule = toMap.get(\"match\");\n                Map<String, ConditionMatcher> then = StringUtils.isBlank(thenRule) || \"false\".equals(thenRule)\n                        ? new HashMap<>()\n                        : parseRule(thenRule);\n                // NOTE: It should be determined on the business level whether the `When condition` can be empty or not.\n\n                thenConditions.add(new ConditionSubSet(\n                        then,\n                        Integer.valueOf(\n                                toMap.getOrDefault(\"weight\", String.valueOf(DefaultRouteConditionSubSetWeight)))));\n            }\n            this.thenCondition = thenConditions;\n        } catch (ParseException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    private Map<String, ConditionMatcher> parseRule(String rule) throws ParseException {\n        Map<String, ConditionMatcher> condition = new HashMap<>();\n        if (StringUtils.isBlank(rule)) {\n            return condition;\n        }\n        // Key-Value pair, stores both match and mismatch conditions\n        ConditionMatcher matcherPair = null;\n        // Multiple values\n        Set<String> values = null;\n        final Matcher matcher = ROUTE_PATTERN.matcher(rule);\n        while (matcher.find()) { // Try to match one by one\n            String separator = matcher.group(1);\n            String content = matcher.group(2);\n            // Start part of the condition expression.\n            if (StringUtils.isEmpty(separator)) {\n                matcherPair = this.getMatcher(content);\n                condition.put(content, matcherPair);\n            }\n            // The KV part of the condition expression\n            else if (\"&\".equals(separator)) {\n                if (condition.get(content) == null) {\n                    matcherPair = this.getMatcher(content);\n                    condition.put(content, matcherPair);\n                } else {\n                    matcherPair = condition.get(content);\n                }\n            }\n            // The Value in the KV part.\n            else if (\"=\".equals(separator)) {\n                if (matcherPair == null) {\n                    throw new ParseException(\n                            \"Illegal route rule \\\"\" + rule + \"\\\", The error char '\" + separator + \"' at index \"\n                                    + matcher.start() + \" before \\\"\" + content + \"\\\".\",\n                            matcher.start());\n                }\n\n                values = matcherPair.getMatches();\n                values.add(content);\n            }\n            // The Value in the KV part.\n            else if (\"!=\".equals(separator)) {\n                if (matcherPair == null) {\n                    throw new ParseException(\n                            \"Illegal route rule \\\"\" + rule + \"\\\", The error char '\" + separator + \"' at index \"\n                                    + matcher.start() + \" before \\\"\" + content + \"\\\".\",\n                            matcher.start());\n                }\n\n                values = matcherPair.getMismatches();\n                values.add(content);\n            }\n            // The Value in the KV part, if Value have more than one items.\n            else if (\",\".equals(separator)) { // Should be separated by ','\n                if (values == null || values.isEmpty()) {\n                    throw new ParseException(\n                            \"Illegal route rule \\\"\" + rule + \"\\\", The error char '\" + separator + \"' at index \"\n                                    + matcher.start() + \" before \\\"\" + content + \"\\\".\",\n                            matcher.start());\n                }\n                values.add(content);\n            } else {\n                throw new ParseException(\n                        \"Illegal route rule \\\"\" + rule + \"\\\", The error char '\" + separator + \"' at index \"\n                                + matcher.start() + \" before \\\"\" + content + \"\\\".\",\n                        matcher.start());\n            }\n        }\n        return condition;\n    }\n\n    private ConditionMatcher getMatcher(String key) {\n        for (ConditionMatcherFactory factory : matcherFactories) {\n            if (factory.shouldMatch(key)) {\n                return factory.createMatcher(key, moduleModel);\n            }\n        }\n        return moduleModel\n                .getExtensionLoader(ConditionMatcherFactory.class)\n                .getExtension(\"param\")\n                .createMatcher(key, moduleModel);\n    }\n\n    @Override\n    protected BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> routerSnapshotNodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException {\n\n        if (!enabled) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Directly return. Reason: ConditionRouter disabled.\");\n            }\n            return invokers;\n        }\n\n        if (CollectionUtils.isEmpty(invokers)) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Directly return. Reason: Invokers from previous router is empty.\");\n            }\n            return invokers;\n        }\n\n        try {\n            if (!matchWhen(url, invocation)) {\n                if (needToPrintMessage) {\n                    messageHolder.set(\"Directly return. Reason: WhenCondition not match.\");\n                }\n                return invokers;\n            }\n            if (thenCondition == null || thenCondition.size() == 0) {\n                logger.warn(\n                        CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,\n                        \"condition state router thenCondition is empty\",\n                        \"\",\n                        \"The current consumer in the service blocklist. consumer: \" + NetUtils.getLocalHost()\n                                + \", service: \" + url.getServiceKey());\n                if (needToPrintMessage) {\n                    messageHolder.set(\"Empty return. Reason: ThenCondition is empty.\");\n                }\n                return BitList.emptyList();\n            }\n\n            DestinationSet destinations = new DestinationSet();\n            for (ConditionSubSet condition : thenCondition) {\n                BitList<Invoker<T>> res = invokers.clone();\n\n                for (Invoker invoker : invokers) {\n                    if (!doMatch(invoker.getUrl(), url, null, condition.getCondition(), false)) {\n                        res.remove(invoker);\n                    }\n                }\n                if (!res.isEmpty()) {\n                    destinations.addDestination(\n                            condition.getSubSetWeight() == null\n                                    ? DefaultRouteConditionSubSetWeight\n                                    : condition.getSubSetWeight(),\n                            res.clone());\n                }\n            }\n\n            if (!destinations.getDestinations().isEmpty()) {\n                BitList<Invoker<T>> res = destinations.randDestination();\n                return res;\n            } else if (this.isForce()) {\n                logger.warn(\n                        CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,\n                        \"execute condition state router result list is \" + \"empty. and force=true\",\n                        \"\",\n                        \"The route result is empty and force execute. consumer: \" + NetUtils.getLocalHost()\n                                + \", service: \" + url.getServiceKey() + \", router: \"\n                                + url.getParameterAndDecoded(RULE_KEY));\n                if (needToPrintMessage) {\n                    messageHolder.set(\"Empty return. Reason: Empty result from condition and condition is force.\");\n                }\n                return BitList.emptyList();\n            }\n\n        } catch (Throwable t) {\n            logger.error(\n                    CLUSTER_FAILED_EXEC_CONDITION_ROUTER,\n                    \"execute condition state router exception\",\n                    \"\",\n                    \"Failed to execute condition router rule: \" + getUrl() + \", invokers: \" + invokers + \", cause: \"\n                            + t.getMessage(),\n                    t);\n        }\n        if (needToPrintMessage) {\n            messageHolder.set(\"Directly return. Reason: Error occurred ( or result is empty ).\");\n        }\n        return invokers;\n    }\n\n    boolean matchWhen(URL url, Invocation invocation) {\n        if (CollectionUtils.isEmptyMap(whenCondition)) {\n            return true;\n        }\n\n        return doMatch(url, null, invocation, whenCondition, true);\n    }\n\n    private boolean doMatch(\n            URL url,\n            URL param,\n            Invocation invocation,\n            Map<String, ConditionMatcher> conditions,\n            boolean isWhenCondition) {\n        Map<String, String> sample = url.toOriginalMap();\n        for (Map.Entry<String, ConditionMatcher> entry : conditions.entrySet()) {\n            ConditionMatcher matchPair = entry.getValue();\n\n            if (!matchPair.isMatch(sample, param, invocation, isWhenCondition)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public void setWhenCondition(Map<String, ConditionMatcher> whenCondition) {\n        this.whenCondition = whenCondition;\n    }\n\n    public void setThenCondition(List<ConditionSubSet> thenCondition) {\n        this.thenCondition = thenCondition;\n    }\n\n    public void setForce(boolean force) {\n        this.force = force;\n    }\n\n    public Map<String, ConditionMatcher> getWhenCondition() {\n        return whenCondition;\n    }\n\n    public boolean isForce() {\n        return force;\n    }\n\n    public List<ConditionSubSet> getThenCondition() {\n        return thenCondition;\n    }\n\n    public List<ConditionMatcherFactory> getMatcherFactories() {\n        return matcherFactories;\n    }\n\n    public void setMatcherFactories(List<ConditionMatcherFactory> matcherFactories) {\n        this.matcherFactories = matcherFactories;\n    }\n\n    public boolean isEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(boolean enabled) {\n        this.enabled = enabled;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/AppStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config;\n\nimport org.apache.dubbo.common.URL;\n\n/**\n * Application level router, \"application.condition-router\"\n */\npublic class AppStateRouter<T> extends ListenableStateRouter<T> {\n    public static final String NAME = \"APP_ROUTER\";\n\n    public AppStateRouter(URL url) {\n        super(url, url.getApplication());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/AppStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;\n\n/**\n * Application level router factory\n * AppRouter should after ServiceRouter\n */\n@Activate(order = 150)\npublic class AppStateRouterFactory implements StateRouterFactory {\n    public static final String NAME = \"app\";\n\n    @SuppressWarnings(\"rawtypes\")\n    private volatile StateRouter router;\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public <T> StateRouter<T> getRouter(Class<T> interfaceClass, URL url) {\n        if (router != null) {\n            return router;\n        }\n        synchronized (this) {\n            if (router == null) {\n                router = createRouter(url);\n            }\n        }\n        return router;\n    }\n\n    private <T> StateRouter<T> createRouter(URL url) {\n        return new AppStateRouter<>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ListenableStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.condition.ConditionStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.condition.MultiDestConditionRouter;\nimport org.apache.dubbo.rpc.cluster.router.condition.config.model.ConditionRouterRule;\nimport org.apache.dubbo.rpc.cluster.router.condition.config.model.ConditionRuleParser;\nimport org.apache.dubbo.rpc.cluster.router.condition.config.model.MultiDestConditionRouterRule;\nimport org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.state.TailStateRouter;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RULE_PARSING;\n\n/**\n * Abstract router which listens to dynamic configuration\n */\npublic abstract class ListenableStateRouter<T> extends AbstractStateRouter<T> implements ConfigurationListener {\n    public static final String NAME = \"LISTENABLE_ROUTER\";\n    public static final String RULE_SUFFIX = \".condition-router\";\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ListenableStateRouter.class);\n    private volatile AbstractRouterRule routerRule;\n    private volatile List<ConditionStateRouter<T>> conditionRouters = Collections.emptyList();\n\n    // for v3.1\n    private volatile List<MultiDestConditionRouter<T>> multiDestConditionRouters = Collections.emptyList();\n    private final String ruleKey;\n\n    public ListenableStateRouter(URL url, String ruleKey) {\n        super(url);\n        this.setForce(false);\n        this.init(ruleKey);\n        this.ruleKey = ruleKey;\n    }\n\n    @Override\n    public synchronized void process(ConfigChangedEvent event) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Notification of condition rule, change type is: \" + event.getChangeType() + \", raw rule is:\\n \"\n                    + event.getContent());\n        }\n\n        if (event.getChangeType().equals(ConfigChangeType.DELETED)) {\n            routerRule = null;\n            conditionRouters = Collections.emptyList();\n            // for v3.1\n            multiDestConditionRouters = Collections.emptyList();\n        } else {\n            try {\n                routerRule = ConditionRuleParser.parse(event.getContent());\n                generateConditions(routerRule);\n            } catch (Exception e) {\n                logger.error(\n                        CLUSTER_FAILED_RULE_PARSING,\n                        \"Failed to parse the raw condition rule\",\n                        \"\",\n                        \"Failed to parse the raw condition rule and it will not take effect, please check \"\n                                + \"if the condition rule matches with the template, the raw rule is:\\n \"\n                                + event.getContent(),\n                        e);\n            }\n        }\n    }\n\n    @Override\n    public BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException {\n        if (CollectionUtils.isEmpty(invokers)\n                || (conditionRouters.size() == 0 && multiDestConditionRouters.size() == 0)) {\n            if (needToPrintMessage) {\n                messageHolder.set(\n                        \"Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty.\");\n            }\n            return invokers;\n        }\n\n        // We will check enabled status inside each router.\n        StringBuilder resultMessage = null;\n        if (needToPrintMessage) {\n            resultMessage = new StringBuilder();\n        }\n\n        List<? extends AbstractStateRouter<T>> routers;\n        if (routerRule instanceof MultiDestConditionRouterRule) {\n            routers = multiDestConditionRouters;\n        } else {\n            routers = conditionRouters;\n        }\n\n        for (AbstractStateRouter<T> router : routers) {\n            invokers = router.route(invokers, url, invocation, needToPrintMessage, nodeHolder);\n            if (needToPrintMessage) {\n                resultMessage.append(messageHolder.get());\n            }\n        }\n\n        if (needToPrintMessage) {\n            messageHolder.set(resultMessage.toString());\n        }\n\n        return invokers;\n    }\n\n    @Override\n    public boolean isForce() {\n        return (routerRule != null && routerRule.isForce());\n    }\n\n    private boolean isRuleRuntime() {\n        return routerRule != null && routerRule.isValid() && routerRule.isRuntime();\n    }\n\n    private void generateConditions(AbstractRouterRule rule) {\n        if (rule == null || !rule.isValid()) {\n            return;\n        }\n\n        if (rule instanceof ConditionRouterRule) {\n            this.conditionRouters = ((ConditionRouterRule) rule)\n                    .getConditions().stream()\n                            .map(condition ->\n                                    new ConditionStateRouter<T>(getUrl(), condition, rule.isForce(), rule.isEnabled()))\n                            .collect(Collectors.toList());\n\n            for (ConditionStateRouter<T> conditionRouter : this.conditionRouters) {\n                conditionRouter.setNextRouter(TailStateRouter.getInstance());\n            }\n        } else if (rule instanceof MultiDestConditionRouterRule) {\n            this.multiDestConditionRouters = ((MultiDestConditionRouterRule) rule)\n                    .getConditions().stream()\n                            .map(condition -> new MultiDestConditionRouter<T>(\n                                    getUrl(), condition, rule.isForce(), rule.isEnabled()))\n                            .collect(Collectors.toList());\n\n            for (MultiDestConditionRouter<T> conditionRouter : this.multiDestConditionRouters) {\n                conditionRouter.setNextRouter(TailStateRouter.getInstance());\n            }\n        }\n    }\n\n    private synchronized void init(String ruleKey) {\n        if (StringUtils.isEmpty(ruleKey)) {\n            return;\n        }\n        String routerKey = ruleKey + RULE_SUFFIX;\n        this.getRuleRepository().addListener(routerKey, this);\n        String rule = this.getRuleRepository().getRule(routerKey, DynamicConfiguration.DEFAULT_GROUP);\n        if (StringUtils.isNotEmpty(rule)) {\n            this.process(new ConfigChangedEvent(routerKey, DynamicConfiguration.DEFAULT_GROUP, rule));\n        }\n    }\n\n    @Override\n    public void stop() {\n        this.getRuleRepository().removeListener(ruleKey + RULE_SUFFIX, this);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ProviderAppStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_TAG_ROUTE_EMPTY;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\n\n/**\n * Application level router, \"application.condition-router\"\n */\npublic class ProviderAppStateRouter<T> extends ListenableStateRouter<T> {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ListenableStateRouter.class);\n    public static final String NAME = \"PROVIDER_APP_ROUTER\";\n    private String application;\n    private final String currentApplication;\n\n    public ProviderAppStateRouter(URL url) {\n        super(url, url.getApplication());\n        this.currentApplication = url.getApplication();\n    }\n\n    @Override\n    public void notify(BitList<Invoker<T>> invokers) {\n        if (CollectionUtils.isEmpty(invokers)) {\n            return;\n        }\n\n        Invoker<T> invoker = invokers.get(0);\n        URL url = invoker.getUrl();\n        String providerApplication = url.getRemoteApplication();\n\n        // provider application is empty or equals with the current application\n        if (isEmpty(providerApplication)) {\n            logger.warn(\n                    CLUSTER_TAG_ROUTE_EMPTY,\n                    \"condition router get providerApplication is empty, will not subscribe to provider app rules.\",\n                    \"\",\n                    \"\");\n            return;\n        }\n        if (providerApplication.equals(currentApplication)) {\n            return;\n        }\n\n        synchronized (this) {\n            if (!providerApplication.equals(application)) {\n                if (StringUtils.isNotEmpty(application)) {\n                    this.getRuleRepository().removeListener(application + RULE_SUFFIX, this);\n                }\n                String key = providerApplication + RULE_SUFFIX;\n                this.getRuleRepository().addListener(key, this);\n                application = providerApplication;\n                String rawRule = this.getRuleRepository().getRule(key, DynamicConfiguration.DEFAULT_GROUP);\n                if (StringUtils.isNotEmpty(rawRule)) {\n                    this.process(new ConfigChangedEvent(key, DynamicConfiguration.DEFAULT_GROUP, rawRule));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ProviderAppStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.state.CacheableStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\n\n@Activate(order = 145)\npublic class ProviderAppStateRouterFactory extends CacheableStateRouterFactory {\n\n    public static final String NAME = \"provider-app\";\n\n    @Override\n    protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {\n        return new ProviderAppStateRouter<>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ServiceStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\n\n/**\n * Service level router, \"server-unique-name.condition-router\"\n */\npublic class ServiceStateRouter<T> extends ListenableStateRouter<T> {\n    public static final String NAME = \"SERVICE_ROUTER\";\n\n    public ServiceStateRouter(URL url) {\n        super(url, DynamicConfiguration.getRuleKey(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ServiceStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.state.CacheableStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\n\n/**\n * Service level router factory\n * ServiceRouter should before AppRouter\n */\n@Activate(order = 140)\npublic class ServiceStateRouterFactory extends CacheableStateRouterFactory {\n\n    public static final String NAME = \"service\";\n\n    @Override\n    protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {\n        return new ServiceStateRouter<>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionRouterRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config.model;\n\nimport org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.CONDITIONS_KEY;\n\npublic class ConditionRouterRule extends AbstractRouterRule {\n    private List<String> conditions;\n\n    @SuppressWarnings(\"unchecked\")\n    public static AbstractRouterRule parseFromMap(Map<String, Object> map) {\n        ConditionRouterRule conditionRouterRule = new ConditionRouterRule();\n        conditionRouterRule.parseFromMap0(map);\n\n        Object conditions = map.get(CONDITIONS_KEY);\n        if (conditions != null && List.class.isAssignableFrom(conditions.getClass())) {\n            conditionRouterRule.setConditions(\n                    ((List<Object>) conditions).stream().map(String::valueOf).collect(Collectors.toList()));\n        }\n\n        return conditionRouterRule;\n    }\n\n    public ConditionRouterRule() {}\n\n    public List<String> getConditions() {\n        return conditions;\n    }\n\n    public void setConditions(List<String> conditions) {\n        this.conditions = conditions;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionRuleParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config.model;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;\n\nimport java.util.Map;\n\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RULE_PARSING;\nimport static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_VERSION_V31;\n\n/**\n * %YAML1.2\n *\n * scope: application\n * runtime: true\n * force: false\n * conditions:\n *   - >\n *     method!=sayHello =>\n *   - >\n *     ip=127.0.0.1\n *     =>\n *     1.1.1.1\n */\npublic class ConditionRuleParser {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConditionRuleParser.class);\n\n    public static AbstractRouterRule parse(String rawRule) {\n        AbstractRouterRule rule;\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Map<String, Object> map = yaml.load(rawRule);\n        String confVersion = (String) map.get(CONFIG_VERSION_KEY);\n\n        if (confVersion != null && confVersion.toLowerCase().startsWith(RULE_VERSION_V31)) {\n            rule = MultiDestConditionRouterRule.parseFromMap(map);\n            if (CollectionUtils.isEmpty(((MultiDestConditionRouterRule) rule).getConditions())) {\n                rule.setValid(false);\n            }\n        } else if (confVersion != null && confVersion.compareToIgnoreCase(RULE_VERSION_V31) > 0) {\n            logger.warn(\n                    CLUSTER_FAILED_RULE_PARSING,\n                    \"Invalid condition config version number.\",\n                    \"\",\n                    \"Ignore this configuration. Only \" + RULE_VERSION_V31 + \" and below are supported in this release\");\n            rule = null;\n        } else {\n            // for under v3.1\n            rule = ConditionRouterRule.parseFromMap(map);\n            if (CollectionUtils.isEmpty(((ConditionRouterRule) rule).getConditions())) {\n                rule.setValid(false);\n            }\n        }\n\n        if (rule != null) {\n            rule.setRawRule(rawRule);\n        }\n\n        return rule;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionSubSet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config.model;\n\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcher;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.DefaultRouteConditionSubSetWeight;\n\npublic class ConditionSubSet {\n    private Map<String, ConditionMatcher> condition = new HashMap<>();\n    private Integer subSetWeight;\n\n    public ConditionSubSet() {}\n\n    public ConditionSubSet(Map<String, ConditionMatcher> condition, Integer subSetWeight) {\n        this.condition = condition;\n        this.subSetWeight = subSetWeight;\n        if (subSetWeight <= 0) {\n            this.subSetWeight = DefaultRouteConditionSubSetWeight;\n        }\n    }\n\n    public Map<String, ConditionMatcher> getCondition() {\n        return condition;\n    }\n\n    public void setCondition(Map<String, ConditionMatcher> condition) {\n        this.condition = condition;\n    }\n\n    public Integer getSubSetWeight() {\n        return subSetWeight;\n    }\n\n    public void setSubSetWeight(int subSetWeight) {\n        this.subSetWeight = subSetWeight;\n    }\n\n    @Override\n    public String toString() {\n        return \"ConditionSubSet{\" + \"cond=\" + condition + \", subSetWeight=\" + subSetWeight + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/Destination.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config.model;\n\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\npublic class Destination<T> {\n    private int weight;\n    private BitList<Invoker<T>> invokers;\n\n    Destination(int weight, BitList<Invoker<T>> invokers) {\n        this.weight = weight;\n        this.invokers = invokers;\n    }\n\n    public int getWeight() {\n        return weight;\n    }\n\n    public void setWeight(int weight) {\n        this.weight = weight;\n    }\n\n    public BitList<Invoker<T>> getInvokers() {\n        return invokers;\n    }\n\n    public void setInvokers(BitList<Invoker<T>> invokers) {\n        this.invokers = invokers;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/DestinationSet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config.model;\n\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.concurrent.ThreadLocalRandom;\n\npublic class DestinationSet<T> {\n    private final List<Destination<T>> destinations;\n    private long weightSum;\n    private final ThreadLocalRandom random;\n\n    public DestinationSet() {\n        this.destinations = new ArrayList<>();\n        this.weightSum = 0;\n        this.random = ThreadLocalRandom.current();\n    }\n\n    public void addDestination(int weight, BitList<Invoker<T>> invokers) {\n        destinations.add(new Destination(weight, invokers));\n        weightSum += weight;\n    }\n\n    public BitList<Invoker<T>> randDestination() {\n        if (destinations.size() == 1) {\n            return destinations.get(0).getInvokers();\n        }\n\n        long sum = random.nextLong(weightSum);\n        for (Destination destination : destinations) {\n            sum -= destination.getWeight();\n            if (sum <= 0) {\n                return destination.getInvokers();\n            }\n        }\n        return BitList.emptyList();\n    }\n\n    public List<Destination<T>> getDestinations() {\n        return destinations;\n    }\n\n    public long getWeightSum() {\n        return weightSum;\n    }\n\n    public void setWeightSum(long weightSum) {\n        this.weightSum = weightSum;\n    }\n\n    public Random getRandom() {\n        return random;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/MultiDestCondition.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config.model;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class MultiDestCondition {\n    private Map<String, String> from = new HashMap<>();\n    private List<Map<String, String>> to = new ArrayList<>();\n\n    public Map<String, String> getFrom() {\n        return from;\n    }\n\n    public void setFrom(Map<String, String> from) {\n        this.from = from;\n    }\n\n    public List<Map<String, String>> getTo() {\n        return to;\n    }\n\n    public void setTo(List<Map<String, String>> to) {\n        this.to = to;\n    }\n\n    @Override\n    public String toString() {\n        return \"MultiDestCondition{\" + \"from=\" + from + \", to=\" + to + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/MultiDestConditionRouterRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config.model;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.CONDITIONS_KEY;\n\npublic class MultiDestConditionRouterRule extends AbstractRouterRule {\n\n    private List<MultiDestCondition> conditions;\n\n    public static AbstractRouterRule parseFromMap(Map<String, Object> map) {\n\n        MultiDestConditionRouterRule multiDestConditionRouterRule = new MultiDestConditionRouterRule();\n        multiDestConditionRouterRule.parseFromMap0(map);\n        List<Map<String, String>> conditions = (List<Map<String, String>>) map.get(CONDITIONS_KEY);\n        List<MultiDestCondition> multiDestConditions = new ArrayList<>();\n\n        for (Map<String, String> condition : conditions) {\n            multiDestConditions.add((MultiDestCondition) JsonUtils.convertObject(condition, MultiDestCondition.class));\n        }\n        multiDestConditionRouterRule.setConditions(multiDestConditions);\n\n        return multiDestConditionRouterRule;\n    }\n\n    public List<MultiDestCondition> getConditions() {\n        return conditions;\n    }\n\n    public void setConditions(List<MultiDestCondition> conditions) {\n        this.conditions = conditions;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/AbstractConditionMatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.ValuePattern;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_EXEC_CONDITION_ROUTER;\n\n/**\n * The abstract implementation of ConditionMatcher, records the match and mismatch patterns of this matcher while at the same time\n * provides the common match logics.\n */\npublic abstract class AbstractConditionMatcher implements ConditionMatcher {\n    public static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(AbstractConditionMatcher.class);\n    public static final String DOES_NOT_FOUND_VALUE = \"dubbo_internal_not_found_argument_condition_value\";\n    final Set<String> matches = new HashSet<>();\n    final Set<String> mismatches = new HashSet<>();\n    private final ModuleModel model;\n    private final List<ValuePattern> valueMatchers;\n    protected final String key;\n\n    public AbstractConditionMatcher(String key, ModuleModel model) {\n        this.key = key;\n        this.model = model;\n        this.valueMatchers = model.getExtensionLoader(ValuePattern.class).getActivateExtensions();\n    }\n\n    public static String getSampleValueFromUrl(\n            String conditionKey, Map<String, String> sample, URL param, Invocation invocation) {\n        String sampleValue;\n        // get real invoked method name from invocation\n        if (invocation != null && (METHOD_KEY.equals(conditionKey) || METHODS_KEY.equals(conditionKey))) {\n            sampleValue = RpcUtils.getMethodName(invocation);\n        } else {\n            sampleValue = sample.get(conditionKey);\n        }\n\n        return sampleValue;\n    }\n\n    public boolean isMatch(Map<String, String> sample, URL param, Invocation invocation, boolean isWhenCondition) {\n        String value = getValue(sample, param, invocation);\n        if (value == null) {\n            // if key does not present in whichever of url, invocation or attachment based on the matcher type, then\n            // return false.\n            return false;\n        }\n\n        if (!matches.isEmpty() && mismatches.isEmpty()) {\n            for (String match : matches) {\n                if (doPatternMatch(match, value, param, invocation, isWhenCondition)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        if (!mismatches.isEmpty() && matches.isEmpty()) {\n            for (String mismatch : mismatches) {\n                if (doPatternMatch(mismatch, value, param, invocation, isWhenCondition)) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        if (!matches.isEmpty() && !mismatches.isEmpty()) {\n            // when both mismatches and matches contain the same value, then using mismatches first\n            for (String mismatch : mismatches) {\n                if (doPatternMatch(mismatch, value, param, invocation, isWhenCondition)) {\n                    return false;\n                }\n            }\n            for (String match : matches) {\n                if (doPatternMatch(match, value, param, invocation, isWhenCondition)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n        return false;\n    }\n\n    @Override\n    public Set<String> getMatches() {\n        return matches;\n    }\n\n    @Override\n    public Set<String> getMismatches() {\n        return mismatches;\n    }\n\n    // range, equal or other methods\n    protected boolean doPatternMatch(\n            String pattern, String value, URL url, Invocation invocation, boolean isWhenCondition) {\n        for (ValuePattern valueMatcher : valueMatchers) {\n            if (valueMatcher.shouldMatch(pattern)) {\n                return valueMatcher.match(pattern, value, url, invocation, isWhenCondition);\n            }\n        }\n        // this should never happen.\n        logger.error(\n                CLUSTER_FAILED_EXEC_CONDITION_ROUTER,\n                \"Executing condition rule value match expression error.\",\n                \"pattern is \" + pattern + \", value is \" + value + \", condition type \"\n                        + (isWhenCondition ? \"when\" : \"then\"),\n                \"There should at least has one ValueMatcher instance that applies to all patterns, will force to use wildcard matcher now.\");\n\n        ValuePattern paramValueMatcher =\n                model.getExtensionLoader(ValuePattern.class).getExtension(\"wildcard\");\n        return paramValueMatcher.match(pattern, value, url, invocation, isWhenCondition);\n    }\n\n    /**\n     * Used to get value from different places of the request context, for example, url, attachment and invocation.\n     * This makes condition rule possible to check values in any place of a request.\n     */\n    protected abstract String getValue(Map<String, String> sample, URL url, Invocation invocation);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/ConditionMatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\n\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * ConditionMatcher represents a specific match condition of a condition rule.\n * <p>\n * The following condition rule '=bar&arguments[0]=hello* => region=hangzhou' consists of three ConditionMatchers:\n * 1. UrlParamConditionMatcher represented by 'foo=bar'\n * 2. ArgumentsConditionMatcher represented by 'arguments[0]=hello*'\n * 3. UrlParamConditionMatcher represented by 'region=hangzhou'\n * <p>\n * It's easy to define your own matcher by extending {@link ConditionMatcherFactory}\n */\npublic interface ConditionMatcher {\n\n    /**\n     * Determines if the patterns of this matcher matches with request context.\n     *\n     * @param sample          request context in provider url\n     * @param param           request context in consumer url\n     * @param invocation      request context in invocation, typically, service, method, arguments and attachments\n     * @param isWhenCondition condition type\n     * @return the matching result\n     */\n    boolean isMatch(Map<String, String> sample, URL param, Invocation invocation, boolean isWhenCondition);\n\n    /**\n     * match patterns extracted from when condition\n     *\n     * @return\n     */\n    Set<String> getMatches();\n\n    /**\n     * mismatch patterns extracted from then condition\n     *\n     * @return\n     */\n    Set<String> getMismatches();\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/ConditionMatcherFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher;\n\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\n/**\n * Factory of ConditionMatcher instances.\n */\n@SPI\npublic interface ConditionMatcherFactory {\n    /**\n     * Check if the key is of the form of the current matcher type which this factory instance represents..\n     *\n     * @param key the key of a particular form\n     * @return true if matches, otherwise false\n     */\n    boolean shouldMatch(String key);\n\n    /**\n     * Create a matcher instance for the key.\n     *\n     * @param key   the key value conforms to a specific matcher specification\n     * @param model module model\n     * @return the specific matcher instance\n     */\n    ConditionMatcher createMatcher(String key, ModuleModel model);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/argument/ArgumentConditionMatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher.argument;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.AbstractConditionMatcher;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_EXEC_CONDITION_ROUTER;\n\n/**\n * analysis the arguments in the rule.\n * Examples would be like this:\n * \"arguments[0]=1\", whenCondition is that the first argument is equal to '1'.\n * \"arguments[1]=a\", whenCondition is that the second argument is equal to 'a'.\n */\n@Activate\npublic class ArgumentConditionMatcher extends AbstractConditionMatcher {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ArgumentConditionMatcher.class);\n    private static final Pattern ARGUMENTS_PATTERN = Pattern.compile(\"arguments\\\\[([0-9]+)\\\\]\");\n\n    public ArgumentConditionMatcher(String key, ModuleModel model) {\n        super(key, model);\n    }\n\n    @Override\n    public String getValue(Map<String, String> sample, URL url, Invocation invocation) {\n        try {\n            // split the rule\n            String[] expressArray = key.split(\"\\\\.\");\n            String argumentExpress = expressArray[0];\n            final Matcher matcher = ARGUMENTS_PATTERN.matcher(argumentExpress);\n            if (!matcher.find()) {\n                return DOES_NOT_FOUND_VALUE;\n            }\n\n            // extract the argument index\n            int index = Integer.parseInt(matcher.group(1));\n            if (index < 0 || index > invocation.getArguments().length) {\n                return DOES_NOT_FOUND_VALUE;\n            }\n\n            // extract the argument value\n            return String.valueOf(invocation.getArguments()[index]);\n        } catch (Exception e) {\n            logger.warn(\n                    CLUSTER_FAILED_EXEC_CONDITION_ROUTER,\n                    \"Parse argument match condition failed\",\n                    \"\",\n                    \"Invalid , will ignore., \",\n                    e);\n        }\n        return DOES_NOT_FOUND_VALUE;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/argument/ArgumentConditionMatcherFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher.argument;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.Constants;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcher;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\n@Activate(order = 300)\npublic class ArgumentConditionMatcherFactory implements ConditionMatcherFactory {\n\n    @Override\n    public boolean shouldMatch(String key) {\n        return key.startsWith(Constants.ARGUMENTS);\n    }\n\n    @Override\n    public ConditionMatcher createMatcher(String key, ModuleModel model) {\n        return new ArgumentConditionMatcher(key, model);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/attachment/AttachmentConditionMatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher.attachment;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.AbstractConditionMatcher;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_EXEC_CONDITION_ROUTER;\n\n/**\n * analysis the arguments in the rule.\n * Examples would be like this:\n * \"attachments[foo]=bar\", whenCondition is that the attachment value of 'foo' is equal to 'bar'.\n */\n@Activate\npublic class AttachmentConditionMatcher extends AbstractConditionMatcher {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(AttachmentConditionMatcher.class);\n    private static final Pattern ATTACHMENTS_PATTERN = Pattern.compile(\"attachments\\\\[(.+)\\\\]\");\n\n    public AttachmentConditionMatcher(String key, ModuleModel model) {\n        super(key, model);\n    }\n\n    @Override\n    protected String getValue(Map<String, String> sample, URL url, Invocation invocation) {\n        try {\n            // split the rule\n            String[] expressArray = key.split(\"\\\\.\");\n            String argumentExpress = expressArray[0];\n            final Matcher matcher = ATTACHMENTS_PATTERN.matcher(argumentExpress);\n            if (!matcher.find()) {\n                return DOES_NOT_FOUND_VALUE;\n            }\n\n            // extract the argument index\n            String attachmentKey = matcher.group(1);\n            if (StringUtils.isEmpty(attachmentKey)) {\n                return DOES_NOT_FOUND_VALUE;\n            }\n\n            // extract the argument value\n            return invocation.getAttachment(attachmentKey);\n        } catch (Exception e) {\n            logger.warn(\n                    CLUSTER_FAILED_EXEC_CONDITION_ROUTER,\n                    \"condition state router attachment match failed\",\n                    \"\",\n                    \"Invalid match condition: \" + key,\n                    e);\n        }\n        return DOES_NOT_FOUND_VALUE;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/attachment/AttachmentConditionMatcherFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher.attachment;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcher;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\n@Activate(order = 200)\npublic class AttachmentConditionMatcherFactory implements ConditionMatcherFactory {\n    private static final String ATTACHMENTS = \"attachments\";\n\n    @Override\n    public boolean shouldMatch(String key) {\n        return key.startsWith(ATTACHMENTS);\n    }\n\n    @Override\n    public ConditionMatcher createMatcher(String key, ModuleModel model) {\n        return new AttachmentConditionMatcher(key, model);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/param/UrlParamConditionMatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher.param;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.AbstractConditionMatcher;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Map;\n\n/**\n * This instance will be loaded separately to ensure it always gets executed as the last matcher.\n * So we don't put Active annotation here.\n */\npublic class UrlParamConditionMatcher extends AbstractConditionMatcher {\n\n    public UrlParamConditionMatcher(String key, ModuleModel model) {\n        super(key, model);\n    }\n\n    @Override\n    protected String getValue(Map<String, String> sample, URL url, Invocation invocation) {\n        return getSampleValueFromUrl(key, sample, url, invocation);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/param/UrlParamConditionMatcherFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher.param;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcher;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\n// Make sure this is the last matcher being executed.\n@Activate(order = Integer.MAX_VALUE)\npublic class UrlParamConditionMatcherFactory implements ConditionMatcherFactory {\n    @Override\n    public boolean shouldMatch(String key) {\n        return true;\n    }\n\n    @Override\n    public ConditionMatcher createMatcher(String key, ModuleModel model) {\n        return new UrlParamConditionMatcher(key, model);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/pattern/ValuePattern.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.Invocation;\n\n@SPI\npublic interface ValuePattern {\n    /**\n     * Is the input pattern of a specific form, for example, range pattern '1~100', wildcard pattern 'hello*', etc.\n     *\n     * @param pattern the match or mismatch pattern\n     * @return true or false\n     */\n    boolean shouldMatch(String pattern);\n\n    /**\n     * Is the pattern matches with the request context\n     *\n     * @param pattern         pattern value extracted from condition rule\n     * @param value           the real value extracted from request context\n     * @param url             request context in consumer url\n     * @param invocation      request context in invocation\n     * @param isWhenCondition condition type\n     * @return true if successfully match\n     */\n    boolean match(String pattern, String value, URL url, Invocation invocation, boolean isWhenCondition);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/pattern/range/RangeValuePattern.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.range;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.ValuePattern;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_EXEC_CONDITION_ROUTER;\n\n/**\n * Matches with patterns like 'key=1~100', 'key=~100' or 'key=1~'\n */\n@Activate(order = 100)\npublic class RangeValuePattern implements ValuePattern {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(RangeValuePattern.class);\n\n    @Override\n    public boolean shouldMatch(String pattern) {\n        return pattern.contains(\"~\");\n    }\n\n    @Override\n    public boolean match(String pattern, String value, URL url, Invocation invocation, boolean isWhenCondition) {\n        boolean defaultValue = !isWhenCondition;\n        try {\n            int intValue = StringUtils.parseInteger(value);\n\n            String[] arr = pattern.split(\"~\");\n            if (arr.length < 2) {\n                logger.error(\n                        CLUSTER_FAILED_EXEC_CONDITION_ROUTER,\n                        \"\",\n                        \"\",\n                        \"Invalid condition rule \" + pattern + \" or value \" + value + \", will ignore.\");\n                return defaultValue;\n            }\n\n            String rawStart = arr[0];\n            String rawEnd = arr[1];\n\n            if (StringUtils.isEmpty(rawStart) && StringUtils.isEmpty(rawEnd)) {\n                return defaultValue;\n            }\n\n            if (StringUtils.isEmpty(rawStart)) {\n                int end = StringUtils.parseInteger(rawEnd);\n                if (intValue > end) {\n                    return false;\n                }\n            } else if (StringUtils.isEmpty(rawEnd)) {\n                int start = StringUtils.parseInteger(rawStart);\n                if (intValue < start) {\n                    return false;\n                }\n            } else {\n                int start = StringUtils.parseInteger(rawStart);\n                int end = StringUtils.parseInteger(rawEnd);\n                if (intValue < start || intValue > end) {\n                    return false;\n                }\n            }\n        } catch (Exception e) {\n            logger.error(\n                    CLUSTER_FAILED_EXEC_CONDITION_ROUTER,\n                    \"Parse integer error\",\n                    \"\",\n                    \"Invalid condition rule \" + pattern + \" or value \" + value + \", will ignore.\",\n                    e);\n            return defaultValue;\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/matcher/pattern/wildcard/WildcardValuePattern.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.wildcard;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.ValuePattern;\n\n/**\n * Matches with patterns like 'key=hello', 'key=hello*', 'key=*hello', 'key=h*o' or 'key=*'\n * <p>\n * This pattern evaluator must be the last one being executed.\n */\n@Activate(order = Integer.MAX_VALUE)\npublic class WildcardValuePattern implements ValuePattern {\n    @Override\n    public boolean shouldMatch(String key) {\n        return true;\n    }\n\n    @Override\n    public boolean match(String pattern, String value, URL url, Invocation invocation, boolean isWhenCondition) {\n        return UrlUtils.isMatchGlobPattern(pattern, value, url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/file/FileStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.file;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.utils.IOUtils;\nimport org.apache.dubbo.rpc.cluster.router.script.ScriptStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;\n\nimport java.io.FileReader;\nimport java.io.IOException;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.TYPE_KEY;\n\npublic class FileStateRouterFactory implements StateRouterFactory {\n\n    public static final String NAME = \"file\";\n\n    private StateRouterFactory routerFactory;\n\n    public void setRouterFactory(StateRouterFactory routerFactory) {\n        this.routerFactory = routerFactory;\n    }\n\n    @Override\n    public <T> StateRouter<T> getRouter(Class<T> interfaceClass, URL url) {\n        try {\n            // Transform File URL into Script Route URL, and Load\n            // file:///d:/path/to/route.js?router=script ==> script:///d:/path/to/route.js?type=js&rule=<file-content>\n            String protocol = url.getParameter(\n                    ROUTER_KEY,\n                    ScriptStateRouterFactory.NAME); // Replace original protocol (maybe 'file') with 'script'\n            String type = null; // Use file suffix to config script type, e.g., js, groovy ...\n            String path = url.getPath();\n            if (path != null) {\n                int i = path.lastIndexOf('.');\n                if (i > 0) {\n                    type = path.substring(i + 1);\n                }\n            }\n            String rule = IOUtils.read(new FileReader(url.getAbsolutePath()));\n\n            // FIXME: this code looks useless\n            boolean runtime = url.getParameter(RUNTIME_KEY, false);\n            URL script = URLBuilder.from(url)\n                    .setProtocol(protocol)\n                    .addParameter(TYPE_KEY, type)\n                    .addParameter(RUNTIME_KEY, runtime)\n                    .addParameterAndEncoded(RULE_KEY, rule)\n                    .build();\n\n            return routerFactory.getRouter(interfaceClass, script);\n        } catch (IOException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/MeshScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleManager;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\npublic class MeshScopeModelInitializer implements ScopeModelInitializer {\n\n    public void initializeModuleModel(ModuleModel moduleModel) {\n        ScopeBeanFactory beanFactory = moduleModel.getBeanFactory();\n        beanFactory.registerBean(MeshRuleManager.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshAppRuleListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.MeshRuleDispatcher;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.MeshRuleListener;\n\nimport java.text.MessageFormat;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.yaml.snakeyaml.DumperOptions;\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\nimport org.yaml.snakeyaml.representer.Representer;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RECEIVE_RULE;\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.METADATA_KEY;\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.NAME_KEY;\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.STANDARD_ROUTER_KEY;\n\npublic class MeshAppRuleListener implements ConfigurationListener {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MeshAppRuleListener.class);\n\n    private final MeshRuleDispatcher meshRuleDispatcher;\n\n    private final String appName;\n\n    private volatile Map<String, List<Map<String, Object>>> ruleMapHolder;\n\n    public MeshAppRuleListener(String appName) {\n        this.appName = appName;\n        this.meshRuleDispatcher = new MeshRuleDispatcher(appName);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void receiveConfigInfo(String configInfo) {\n        if (logger.isDebugEnabled()) {\n            logger.debug(MessageFormat.format(\"[MeshAppRule] Received rule for app [{0}]: {1}.\", appName, configInfo));\n        }\n        try {\n            Map<String, List<Map<String, Object>>> groupMap = new HashMap<>();\n\n            Representer representer = new Representer(new DumperOptions());\n            representer.getPropertyUtils().setSkipMissingProperties(true);\n            Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()), representer);\n            Iterable<Object> yamlIterator = yaml.loadAll(configInfo);\n\n            for (Object obj : yamlIterator) {\n                if (obj instanceof Map) {\n                    Map<String, Object> resultMap = (Map<String, Object>) obj;\n\n                    String ruleType = computeRuleType(resultMap);\n                    if (ruleType != null) {\n                        groupMap.computeIfAbsent(ruleType, (k) -> new LinkedList<>())\n                                .add(resultMap);\n                    } else {\n                        logger.error(\n                                CLUSTER_FAILED_RECEIVE_RULE,\n                                \"receive mesh app route rule is invalid\",\n                                \"\",\n                                \"Unable to get rule type from raw rule. \"\n                                        + \"Probably the metadata.name is absent. App Name: \" + appName + \" RawRule: \"\n                                        + configInfo);\n                    }\n                } else {\n                    logger.error(\n                            CLUSTER_FAILED_RECEIVE_RULE,\n                            \"receive mesh app route rule is invalid\",\n                            \"\",\n                            \"Rule format is unacceptable. App Name: \" + appName + \" RawRule: \" + configInfo);\n                }\n            }\n\n            ruleMapHolder = groupMap;\n        } catch (Exception e) {\n            logger.error(\n                    CLUSTER_FAILED_RECEIVE_RULE,\n                    \"failed to receive mesh app route rule\",\n                    \"\",\n                    \"[MeshAppRule] parse failed: \" + configInfo,\n                    e);\n        }\n        if (ruleMapHolder != null) {\n            meshRuleDispatcher.post(ruleMapHolder);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private String computeRuleType(Map<String, Object> rule) {\n        Object obj = rule.get(METADATA_KEY);\n        if (obj instanceof Map && CollectionUtils.isNotEmptyMap((Map<String, String>) obj)) {\n            Map<String, String> metadata = (Map<String, String>) obj;\n            String name = metadata.get(NAME_KEY);\n            if (!name.contains(\".\")) {\n                return STANDARD_ROUTER_KEY;\n            } else {\n                return name.substring(name.indexOf(\".\") + 1);\n            }\n        }\n        return null;\n    }\n\n    public <T> void register(MeshRuleListener subscriber) {\n        if (ruleMapHolder != null) {\n            List<Map<String, Object>> rule = ruleMapHolder.get(subscriber.ruleSuffix());\n            if (rule != null) {\n                subscriber.onRuleChange(appName, rule);\n            }\n        }\n        meshRuleDispatcher.register(subscriber);\n    }\n\n    public <T> void unregister(MeshRuleListener subscriber) {\n        meshRuleDispatcher.unregister(subscriber);\n    }\n\n    @Override\n    public void process(ConfigChangedEvent event) {\n        if (event.getChangeType() == ConfigChangeType.DELETED) {\n            receiveConfigInfo(\"\");\n            return;\n        }\n        receiveConfigInfo(event.getContent());\n    }\n\n    public boolean isEmpty() {\n        return meshRuleDispatcher.isEmpty();\n    }\n\n    /**\n     * For ut only\n     */\n    @Deprecated\n    public MeshRuleDispatcher getMeshRuleDispatcher() {\n        return meshRuleDispatcher;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshEnvListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\n/**\n * Mesh Rule Listener\n * Such as Kubernetes, Service Mesh (xDS) environment support define rule in env\n */\npublic interface MeshEnvListener {\n    /**\n     * @return whether current environment support listen\n     */\n    default boolean isEnable() {\n        return false;\n    }\n\n    void onSubscribe(String appName, MeshAppRuleListener listener);\n\n    void onUnSubscribe(String appName);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshEnvListenerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface MeshEnvListenerFactory {\n    MeshEnvListener getListener();\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshRuleCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.VsDestinationGroup;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.DestinationRule;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.DestinationRuleSpec;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.Subset;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.INVALID_APP_NAME;\n\npublic class MeshRuleCache<T> {\n    private final List<String> appList;\n    private final Map<String, VsDestinationGroup> appToVDGroup;\n    private final Map<String, Map<String, BitList<Invoker<T>>>> totalSubsetMap;\n    private final BitList<Invoker<T>> unmatchedInvokers;\n\n    private MeshRuleCache(\n            List<String> appList,\n            Map<String, VsDestinationGroup> appToVDGroup,\n            Map<String, Map<String, BitList<Invoker<T>>>> totalSubsetMap,\n            BitList<Invoker<T>> unmatchedInvokers) {\n        this.appList = appList;\n        this.appToVDGroup = appToVDGroup;\n        this.totalSubsetMap = totalSubsetMap;\n        this.unmatchedInvokers = unmatchedInvokers;\n    }\n\n    public List<String> getAppList() {\n        return appList;\n    }\n\n    public Map<String, VsDestinationGroup> getAppToVDGroup() {\n        return appToVDGroup;\n    }\n\n    public Map<String, Map<String, BitList<Invoker<T>>>> getTotalSubsetMap() {\n        return totalSubsetMap;\n    }\n\n    public BitList<Invoker<T>> getUnmatchedInvokers() {\n        return unmatchedInvokers;\n    }\n\n    public VsDestinationGroup getVsDestinationGroup(String appName) {\n        return appToVDGroup.get(appName);\n    }\n\n    public BitList<Invoker<T>> getSubsetInvokers(String appName, String subset) {\n        Map<String, BitList<Invoker<T>>> appToSubSets = totalSubsetMap.get(appName);\n        if (CollectionUtils.isNotEmptyMap(appToSubSets)) {\n            BitList<Invoker<T>> subsetInvokers = appToSubSets.get(subset);\n            if (CollectionUtils.isNotEmpty(subsetInvokers)) {\n                return subsetInvokers;\n            }\n        }\n        return BitList.emptyList();\n    }\n\n    public boolean containsRule() {\n        return !totalSubsetMap.isEmpty();\n    }\n\n    public static <T> MeshRuleCache<T> build(\n            String protocolServiceKey,\n            BitList<Invoker<T>> invokers,\n            Map<String, VsDestinationGroup> vsDestinationGroupMap) {\n        if (CollectionUtils.isNotEmptyMap(vsDestinationGroupMap)) {\n            BitList<Invoker<T>> unmatchedInvokers = new BitList<>(invokers.getOriginList(), true);\n            Map<String, Map<String, BitList<Invoker<T>>>> totalSubsetMap = new HashMap<>();\n\n            for (Invoker<T> invoker : invokers) {\n                String remoteApplication = invoker.getUrl().getRemoteApplication();\n                if (StringUtils.isEmpty(remoteApplication) || INVALID_APP_NAME.equals(remoteApplication)) {\n                    unmatchedInvokers.add(invoker);\n                    continue;\n                }\n                VsDestinationGroup vsDestinationGroup = vsDestinationGroupMap.get(remoteApplication);\n                if (vsDestinationGroup == null) {\n                    unmatchedInvokers.add(invoker);\n                    continue;\n                }\n                Map<String, BitList<Invoker<T>>> subsetMap =\n                        totalSubsetMap.computeIfAbsent(remoteApplication, (k) -> new HashMap<>());\n\n                boolean matched = false;\n                for (DestinationRule destinationRule : vsDestinationGroup.getDestinationRuleList()) {\n                    DestinationRuleSpec destinationRuleSpec = destinationRule.getSpec();\n                    List<Subset> subsetList = destinationRuleSpec.getSubsets();\n                    for (Subset subset : subsetList) {\n                        String subsetName = subset.getName();\n                        List<Invoker<T>> subsetInvokers = subsetMap.computeIfAbsent(\n                                subsetName, (k) -> new BitList<>(invokers.getOriginList(), true));\n\n                        Map<String, String> labels = subset.getLabels();\n                        if (isLabelMatch(invoker.getUrl(), protocolServiceKey, labels)) {\n                            subsetInvokers.add(invoker);\n                            matched = true;\n                        }\n                    }\n                }\n                if (!matched) {\n                    unmatchedInvokers.add(invoker);\n                }\n            }\n\n            return new MeshRuleCache<>(\n                    new LinkedList<>(vsDestinationGroupMap.keySet()),\n                    Collections.unmodifiableMap(vsDestinationGroupMap),\n                    Collections.unmodifiableMap(totalSubsetMap),\n                    unmatchedInvokers);\n        } else {\n            return new MeshRuleCache<>(\n                    Collections.emptyList(), Collections.emptyMap(), Collections.emptyMap(), invokers);\n        }\n    }\n\n    public static <T> MeshRuleCache<T> emptyCache() {\n        return new MeshRuleCache<>(\n                Collections.emptyList(), Collections.emptyMap(), Collections.emptyMap(), BitList.emptyList());\n    }\n\n    protected static boolean isLabelMatch(URL url, String protocolServiceKey, Map<String, String> inputMap) {\n        if (inputMap == null || inputMap.size() == 0) {\n            return true;\n        }\n\n        for (Map.Entry<String, String> entry : inputMap.entrySet()) {\n            String key = entry.getKey();\n            String value = entry.getValue();\n\n            String originMapValue = url.getOriginalServiceParameter(protocolServiceKey, key);\n            if (!value.equals(originMapValue)) {\n                return false;\n            }\n        }\n\n        return true;\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        MeshRuleCache<?> ruleCache = (MeshRuleCache<?>) o;\n        return Objects.equals(appList, ruleCache.appList)\n                && Objects.equals(appToVDGroup, ruleCache.appToVDGroup)\n                && Objects.equals(totalSubsetMap, ruleCache.totalSubsetMap)\n                && Objects.equals(unmatchedInvokers, ruleCache.unmatchedInvokers);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(appList, appToVDGroup, totalSubsetMap, unmatchedInvokers);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshRuleConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\npublic class MeshRuleConstants {\n    public static final String INVALID_APP_NAME = \"unknown\";\n\n    public static final String DESTINATION_RULE_KEY = \"DestinationRule\";\n\n    public static final String VIRTUAL_SERVICE_KEY = \"VirtualService\";\n\n    public static final String KIND_KEY = \"kind\";\n\n    public static final String MESH_RULE_DATA_ID_SUFFIX = \".MESHAPPRULE\";\n\n    public static final String NAME_KEY = \"name\";\n\n    public static final String METADATA_KEY = \"metadata\";\n\n    public static final String STANDARD_ROUTER_KEY = \"standard\";\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshRuleManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.MeshRuleListener;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RECEIVE_RULE;\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.MESH_RULE_DATA_ID_SUFFIX;\n\npublic class MeshRuleManager {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MeshRuleManager.class);\n\n    private final ConcurrentHashMap<String, MeshAppRuleListener> APP_RULE_LISTENERS = new ConcurrentHashMap<>();\n\n    private final GovernanceRuleRepository ruleRepository;\n\n    private final Set<MeshEnvListener> envListeners;\n\n    public MeshRuleManager(ModuleModel moduleModel) {\n        this.ruleRepository = moduleModel.getDefaultExtension(GovernanceRuleRepository.class);\n        Set<MeshEnvListenerFactory> envListenerFactories =\n                moduleModel.getExtensionLoader(MeshEnvListenerFactory.class).getSupportedExtensionInstances();\n        this.envListeners = envListenerFactories.stream()\n                .map(MeshEnvListenerFactory::getListener)\n                .filter(Objects::nonNull)\n                .collect(Collectors.toSet());\n    }\n\n    private synchronized MeshAppRuleListener subscribeAppRule(String app) {\n\n        MeshAppRuleListener meshAppRuleListener = new MeshAppRuleListener(app);\n        // demo-app.MESHAPPRULE\n        String appRuleDataId = app + MESH_RULE_DATA_ID_SUFFIX;\n\n        // Add listener to rule repository ( dynamic configuration )\n        try {\n            String rawConfig = ruleRepository.getRule(appRuleDataId, DynamicConfiguration.DEFAULT_GROUP, 5000L);\n            if (rawConfig != null) {\n                meshAppRuleListener.receiveConfigInfo(rawConfig);\n            }\n        } catch (Throwable throwable) {\n            logger.error(\n                    CLUSTER_FAILED_RECEIVE_RULE,\n                    \"failed to get mesh app route rule\",\n                    \"\",\n                    \"get MeshRuleManager app rule failed.\",\n                    throwable);\n        }\n\n        ruleRepository.addListener(appRuleDataId, DynamicConfiguration.DEFAULT_GROUP, meshAppRuleListener);\n\n        // Add listener to env ( kubernetes, xDS )\n        for (MeshEnvListener envListener : envListeners) {\n            if (envListener.isEnable()) {\n                envListener.onSubscribe(app, meshAppRuleListener);\n            }\n        }\n\n        APP_RULE_LISTENERS.put(app, meshAppRuleListener);\n        return meshAppRuleListener;\n    }\n\n    private synchronized void unsubscribeAppRule(String app, MeshAppRuleListener meshAppRuleListener) {\n        // demo-app.MESHAPPRULE\n        String appRuleDataId = app + MESH_RULE_DATA_ID_SUFFIX;\n\n        // Remove listener from rule repository ( dynamic configuration )\n        ruleRepository.removeListener(appRuleDataId, DynamicConfiguration.DEFAULT_GROUP, meshAppRuleListener);\n\n        // Remove listener from env ( kubernetes, xDS )\n        for (MeshEnvListener envListener : envListeners) {\n            if (envListener.isEnable()) {\n                envListener.onUnSubscribe(app);\n            }\n        }\n    }\n\n    public synchronized <T> void register(String app, MeshRuleListener subscriber) {\n        MeshAppRuleListener meshAppRuleListener = APP_RULE_LISTENERS.get(app);\n        if (meshAppRuleListener == null) {\n            meshAppRuleListener = subscribeAppRule(app);\n        }\n        meshAppRuleListener.register(subscriber);\n    }\n\n    public synchronized <T> void unregister(String app, MeshRuleListener subscriber) {\n        MeshAppRuleListener meshAppRuleListener = APP_RULE_LISTENERS.get(app);\n        meshAppRuleListener.unregister(subscriber);\n        if (meshAppRuleListener.isEmpty()) {\n            unsubscribeAppRule(app, meshAppRuleListener);\n            APP_RULE_LISTENERS.remove(app);\n        }\n    }\n\n    /**\n     * for ut only\n     */\n    @Deprecated\n    public ConcurrentHashMap<String, MeshAppRuleListener> getAppRuleListeners() {\n        return APP_RULE_LISTENERS;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshRuleRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.PojoUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.VsDestinationGroup;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.DestinationRule;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.DubboMatchRequest;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.DubboRoute;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.DubboRouteDetail;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.VirtualServiceRule;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.VirtualServiceSpec;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination.DubboDestination;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination.DubboRouteDestination;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.StringMatch;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.MeshRuleListener;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider;\nimport org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ThreadLocalRandom;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RECEIVE_RULE;\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.DESTINATION_RULE_KEY;\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.INVALID_APP_NAME;\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.KIND_KEY;\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.VIRTUAL_SERVICE_KEY;\n\npublic abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implements MeshRuleListener {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MeshRuleRouter.class);\n\n    private final Map<String, String> sourcesLabels;\n    private volatile BitList<Invoker<T>> invokerList = BitList.emptyList();\n    private volatile Set<String> remoteAppName = Collections.emptySet();\n\n    protected MeshRuleManager meshRuleManager;\n    protected Set<TracingContextProvider> tracingContextProviders;\n\n    protected volatile MeshRuleCache<T> meshRuleCache = MeshRuleCache.emptyCache();\n\n    public MeshRuleRouter(URL url) {\n        super(url);\n        sourcesLabels = Collections.unmodifiableMap(new HashMap<>(url.getParameters()));\n        this.meshRuleManager = url.getOrDefaultModuleModel().getBeanFactory().getBean(MeshRuleManager.class);\n        this.tracingContextProviders = url.getOrDefaultModuleModel()\n                .getExtensionLoader(TracingContextProvider.class)\n                .getSupportedExtensionInstances();\n    }\n\n    @Override\n    protected BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException {\n        MeshRuleCache<T> ruleCache = this.meshRuleCache;\n        if (!ruleCache.containsRule()) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"MeshRuleCache has not been built. Skip route.\");\n            }\n            return invokers;\n        }\n\n        BitList<Invoker<T>> result = new BitList<>(invokers.getOriginList(), true, invokers.getTailList());\n\n        StringBuilder stringBuilder = needToPrintMessage ? new StringBuilder() : null;\n\n        // loop each application\n        for (String appName : ruleCache.getAppList()) {\n            // find destination by invocation\n            List<DubboRouteDestination> routeDestination =\n                    getDubboRouteDestination(ruleCache.getVsDestinationGroup(appName), invocation);\n            if (routeDestination != null) {\n                // aggregate target invokers\n                String subset = randomSelectDestination(ruleCache, appName, routeDestination, invokers);\n                if (subset != null) {\n                    BitList<Invoker<T>> destination = meshRuleCache.getSubsetInvokers(appName, subset);\n                    result = result.or(destination);\n                    if (stringBuilder != null) {\n                        stringBuilder\n                                .append(\"Match App: \")\n                                .append(appName)\n                                .append(\" Subset: \")\n                                .append(subset)\n                                .append(' ');\n                    }\n                }\n            }\n        }\n\n        // result = result.or(ruleCache.getUnmatchedInvokers());\n\n        // empty protection\n        if (result.isEmpty()) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Empty protection after routed.\");\n            }\n            return invokers;\n        }\n\n        if (needToPrintMessage) {\n            messageHolder.set(stringBuilder.toString());\n        }\n        return invokers.and(result);\n    }\n\n    /**\n     * Select RouteDestination by Invocation\n     */\n    protected List<DubboRouteDestination> getDubboRouteDestination(\n            VsDestinationGroup vsDestinationGroup, Invocation invocation) {\n        if (vsDestinationGroup != null) {\n            List<VirtualServiceRule> virtualServiceRuleList = vsDestinationGroup.getVirtualServiceRuleList();\n            if (CollectionUtils.isNotEmpty(virtualServiceRuleList)) {\n                for (VirtualServiceRule virtualServiceRule : virtualServiceRuleList) {\n                    // match virtual service (by serviceName)\n                    DubboRoute dubboRoute = getDubboRoute(virtualServiceRule, invocation);\n                    if (dubboRoute != null) {\n                        // match route detail (by params)\n                        return getDubboRouteDestination(dubboRoute, invocation);\n                    }\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Match virtual service (by serviceName)\n     */\n    protected DubboRoute getDubboRoute(VirtualServiceRule virtualServiceRule, Invocation invocation) {\n        String serviceName = invocation.getServiceName();\n\n        VirtualServiceSpec spec = virtualServiceRule.getSpec();\n        List<DubboRoute> dubboRouteList = spec.getDubbo();\n        if (CollectionUtils.isNotEmpty(dubboRouteList)) {\n            for (DubboRoute dubboRoute : dubboRouteList) {\n                List<StringMatch> stringMatchList = dubboRoute.getServices();\n                if (CollectionUtils.isEmpty(stringMatchList)) {\n                    return dubboRoute;\n                }\n                for (StringMatch stringMatch : stringMatchList) {\n                    if (stringMatch.isMatch(serviceName)) {\n                        return dubboRoute;\n                    }\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Match route detail (by params)\n     */\n    protected List<DubboRouteDestination> getDubboRouteDestination(DubboRoute dubboRoute, Invocation invocation) {\n        List<DubboRouteDetail> dubboRouteDetailList = dubboRoute.getRoutedetail();\n        if (CollectionUtils.isNotEmpty(dubboRouteDetailList)) {\n            for (DubboRouteDetail dubboRouteDetail : dubboRouteDetailList) {\n                List<DubboMatchRequest> matchRequestList = dubboRouteDetail.getMatch();\n                if (CollectionUtils.isEmpty(matchRequestList)) {\n                    return dubboRouteDetail.getRoute();\n                }\n\n                if (matchRequestList.stream()\n                        .allMatch(request -> request.isMatch(invocation, sourcesLabels, tracingContextProviders))) {\n                    return dubboRouteDetail.getRoute();\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Find out target invokers from RouteDestination\n     */\n    protected String randomSelectDestination(\n            MeshRuleCache<T> meshRuleCache,\n            String appName,\n            List<DubboRouteDestination> routeDestination,\n            BitList<Invoker<T>> availableInvokers)\n            throws RpcException {\n        // randomly select one DubboRouteDestination from list by weight\n        int totalWeight = 0;\n        for (DubboRouteDestination dubboRouteDestination : routeDestination) {\n            totalWeight += Math.max(dubboRouteDestination.getWeight(), 1);\n        }\n        int target = ThreadLocalRandom.current().nextInt(totalWeight);\n        for (DubboRouteDestination destination : routeDestination) {\n            target -= Math.max(destination.getWeight(), 1);\n            if (target <= 0) {\n                // match weight\n                String result =\n                        computeDestination(meshRuleCache, appName, destination.getDestination(), availableInvokers);\n                if (result != null) {\n                    return result;\n                }\n            }\n        }\n\n        // fall back\n        for (DubboRouteDestination destination : routeDestination) {\n            String result = computeDestination(meshRuleCache, appName, destination.getDestination(), availableInvokers);\n            if (result != null) {\n                return result;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Compute Destination Subset\n     */\n    protected String computeDestination(\n            MeshRuleCache<T> meshRuleCache,\n            String appName,\n            DubboDestination dubboDestination,\n            BitList<Invoker<T>> availableInvokers)\n            throws RpcException {\n        String subset = dubboDestination.getSubset();\n\n        do {\n            BitList<Invoker<T>> result = meshRuleCache.getSubsetInvokers(appName, subset);\n\n            if (CollectionUtils.isNotEmpty(result)\n                    && !availableInvokers.clone().and(result).isEmpty()) {\n                return subset;\n            }\n\n            // fall back\n            DubboRouteDestination dubboRouteDestination = dubboDestination.getFallback();\n            if (dubboRouteDestination == null) {\n                break;\n            }\n            dubboDestination = dubboRouteDestination.getDestination();\n\n            if (dubboDestination == null) {\n                break;\n            }\n            subset = dubboDestination.getSubset();\n        } while (true);\n\n        return null;\n    }\n\n    @Override\n    public void notify(BitList<Invoker<T>> invokers) {\n        BitList<Invoker<T>> invokerList = invokers == null ? BitList.emptyList() : invokers;\n        this.invokerList = invokerList.clone();\n        registerAppRule(invokerList);\n        computeSubset(this.meshRuleCache.getAppToVDGroup());\n    }\n\n    private void registerAppRule(BitList<Invoker<T>> invokers) {\n        Set<String> currentApplication = new HashSet<>();\n        if (CollectionUtils.isNotEmpty(invokers)) {\n            for (Invoker<T> invoker : invokers) {\n                String applicationName = invoker.getUrl().getRemoteApplication();\n                if (StringUtils.isNotEmpty(applicationName) && !INVALID_APP_NAME.equals(applicationName)) {\n                    currentApplication.add(applicationName);\n                }\n            }\n        }\n\n        if (!remoteAppName.equals(currentApplication)) {\n            synchronized (this) {\n                Set<String> current = new HashSet<>(currentApplication);\n                Set<String> previous = new HashSet<>(remoteAppName);\n                previous.removeAll(currentApplication);\n                current.removeAll(remoteAppName);\n                for (String app : current) {\n                    meshRuleManager.register(app, this);\n                }\n                for (String app : previous) {\n                    meshRuleManager.unregister(app, this);\n                }\n                remoteAppName = currentApplication;\n            }\n        }\n    }\n\n    @Override\n    public synchronized void onRuleChange(String appName, List<Map<String, Object>> rules) {\n        // only update specified app's rule\n        Map<String, VsDestinationGroup> appToVDGroup = new ConcurrentHashMap<>(this.meshRuleCache.getAppToVDGroup());\n        try {\n            VsDestinationGroup vsDestinationGroup = new VsDestinationGroup();\n            vsDestinationGroup.setAppName(appName);\n\n            for (Map<String, Object> rule : rules) {\n                if (DESTINATION_RULE_KEY.equals(rule.get(KIND_KEY))) {\n                    DestinationRule destinationRule = PojoUtils.mapToPojo(rule, DestinationRule.class);\n                    vsDestinationGroup.getDestinationRuleList().add(destinationRule);\n                } else if (VIRTUAL_SERVICE_KEY.equals(rule.get(KIND_KEY))) {\n                    VirtualServiceRule virtualServiceRule = PojoUtils.mapToPojo(rule, VirtualServiceRule.class);\n                    vsDestinationGroup.getVirtualServiceRuleList().add(virtualServiceRule);\n                }\n            }\n            if (vsDestinationGroup.isValid()) {\n                appToVDGroup.put(appName, vsDestinationGroup);\n            }\n        } catch (Throwable t) {\n            logger.error(\n                    CLUSTER_FAILED_RECEIVE_RULE,\n                    \"failed to parse mesh route rule\",\n                    \"\",\n                    \"Error occurred when parsing rule component.\",\n                    t);\n        }\n\n        computeSubset(appToVDGroup);\n    }\n\n    @Override\n    public synchronized void clearRule(String appName) {\n        Map<String, VsDestinationGroup> appToVDGroup = new ConcurrentHashMap<>(this.meshRuleCache.getAppToVDGroup());\n        appToVDGroup.remove(appName);\n        computeSubset(appToVDGroup);\n    }\n\n    protected void computeSubset(Map<String, VsDestinationGroup> vsDestinationGroupMap) {\n        this.meshRuleCache =\n                MeshRuleCache.build(getUrl().getProtocolServiceKey(), this.invokerList, vsDestinationGroupMap);\n    }\n\n    @Override\n    public void stop() {\n        for (String app : remoteAppName) {\n            meshRuleManager.unregister(app, this);\n        }\n    }\n\n    /**\n     * for ut only\n     */\n    @Deprecated\n    public Set<String> getRemoteAppName() {\n        return remoteAppName;\n    }\n\n    /**\n     * for ut only\n     */\n    @Deprecated\n    public BitList<Invoker<T>> getInvokerList() {\n        return invokerList;\n    }\n\n    /**\n     * for ut only\n     */\n    @Deprecated\n    public MeshRuleCache<T> getMeshRuleCache() {\n        return meshRuleCache;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/route/StandardMeshRuleRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.URL;\n\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.STANDARD_ROUTER_KEY;\n\npublic class StandardMeshRuleRouter<T> extends MeshRuleRouter<T> {\n\n    public StandardMeshRuleRouter(URL url) {\n        super(url);\n    }\n\n    @Override\n    public String ruleSuffix() {\n        return STANDARD_ROUTER_KEY;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/route/StandardMeshRuleRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;\n\n@Activate(order = -50)\npublic class StandardMeshRuleRouterFactory implements StateRouterFactory {\n    @Override\n    public <T> StateRouter<T> getRouter(Class<T> interfaceClass, URL url) {\n        return new StandardMeshRuleRouter<>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/BaseRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule;\n\nimport java.util.Map;\n\npublic class BaseRule {\n    private String apiVersion;\n    private String kind;\n    private Map<String, String> metadata;\n\n    public String getApiVersion() {\n        return apiVersion;\n    }\n\n    public void setApiVersion(String apiVersion) {\n        this.apiVersion = apiVersion;\n    }\n\n    public String getKind() {\n        return kind;\n    }\n\n    public void setKind(String kind) {\n        this.kind = kind;\n    }\n\n    public Map<String, String> getMetadata() {\n        return metadata;\n    }\n\n    public void setMetadata(Map<String, String> metadata) {\n        this.metadata = metadata;\n    }\n\n    @Override\n    public String toString() {\n        return \"BaseRule{\" + \"apiVersion='\"\n                + apiVersion + '\\'' + \", kind='\"\n                + kind + '\\'' + \", metadata=\"\n                + metadata + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/VsDestinationGroup.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule;\n\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.DestinationRule;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.VirtualServiceRule;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class VsDestinationGroup {\n    private String appName;\n    private List<VirtualServiceRule> virtualServiceRuleList = new LinkedList<>();\n    private List<DestinationRule> destinationRuleList = new LinkedList<>();\n\n    public String getAppName() {\n        return appName;\n    }\n\n    public void setAppName(String appName) {\n        this.appName = appName;\n    }\n\n    public List<VirtualServiceRule> getVirtualServiceRuleList() {\n        return virtualServiceRuleList;\n    }\n\n    public void setVirtualServiceRuleList(List<VirtualServiceRule> virtualServiceRuleList) {\n        this.virtualServiceRuleList = virtualServiceRuleList;\n    }\n\n    public List<DestinationRule> getDestinationRuleList() {\n        return destinationRuleList;\n    }\n\n    public void setDestinationRuleList(List<DestinationRule> destinationRuleList) {\n        this.destinationRuleList = destinationRuleList;\n    }\n\n    public boolean isValid() {\n        return virtualServiceRuleList.size() > 0 && destinationRuleList.size() > 0;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/destination/ConnectionPoolSettings.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;\n\npublic class ConnectionPoolSettings {}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/destination/DestinationRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;\n\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.BaseRule;\n\npublic class DestinationRule extends BaseRule {\n    private DestinationRuleSpec spec;\n\n    public DestinationRuleSpec getSpec() {\n        return spec;\n    }\n\n    public void setSpec(DestinationRuleSpec spec) {\n        this.spec = spec;\n    }\n\n    @Override\n    public String toString() {\n        return \"DestinationRule{\" + \"base=\" + super.toString() + \", spec=\" + spec + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/destination/DestinationRuleSpec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;\n\nimport java.util.List;\n\npublic class DestinationRuleSpec {\n    private String host;\n    private List<Subset> subsets;\n    private TrafficPolicy trafficPolicy;\n\n    public String getHost() {\n        return host;\n    }\n\n    public void setHost(String host) {\n        this.host = host;\n    }\n\n    public List<Subset> getSubsets() {\n        return subsets;\n    }\n\n    public void setSubsets(List<Subset> subsets) {\n        this.subsets = subsets;\n    }\n\n    public TrafficPolicy getTrafficPolicy() {\n        return trafficPolicy;\n    }\n\n    public void setTrafficPolicy(TrafficPolicy trafficPolicy) {\n        this.trafficPolicy = trafficPolicy;\n    }\n\n    @Override\n    public String toString() {\n        return \"DestinationRuleSpec{\" + \"host='\"\n                + host + '\\'' + \", subsets=\"\n                + subsets + \", trafficPolicy=\"\n                + trafficPolicy + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/destination/Subset.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;\n\nimport java.util.Map;\n\npublic class Subset {\n    private String name;\n    private Map<String, String> labels;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Map<String, String> getLabels() {\n        return labels;\n    }\n\n    public void setLabels(Map<String, String> labels) {\n        this.labels = labels;\n    }\n\n    @Override\n    public String toString() {\n        return \"Subset{\" + \"name='\" + name + '\\'' + \", labels=\" + labels + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/destination/TCPSettings.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;\n\npublic class TCPSettings {\n    private int maxConnections;\n    private int connectTimeout;\n    private TcpKeepalive tcpKeepalive;\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/destination/TcpKeepalive.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;\n\npublic class TcpKeepalive {\n    private int probes;\n    private int time;\n    private int interval;\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/destination/TrafficPolicy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;\n\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance.LoadBalancerSettings;\n\npublic class TrafficPolicy {\n    private LoadBalancerSettings loadBalancer;\n\n    public LoadBalancerSettings getLoadBalancer() {\n        return loadBalancer;\n    }\n\n    public void setLoadBalancer(LoadBalancerSettings loadBalancer) {\n        this.loadBalancer = loadBalancer;\n    }\n\n    @Override\n    public String toString() {\n        return \"TrafficPolicy{\" + \"loadBalancer=\" + loadBalancer + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/destination/loadbalance/ConsistentHashLB.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance;\n\npublic class ConsistentHashLB {}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/destination/loadbalance/LoadBalancerSettings.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance;\n\npublic class LoadBalancerSettings {\n    private SimpleLB simple;\n    private ConsistentHashLB consistentHash;\n\n    public SimpleLB getSimple() {\n        return simple;\n    }\n\n    public void setSimple(SimpleLB simple) {\n        this.simple = simple;\n    }\n\n    public ConsistentHashLB getConsistentHash() {\n        return consistentHash;\n    }\n\n    public void setConsistentHash(ConsistentHashLB consistentHash) {\n        this.consistentHash = consistentHash;\n    }\n\n    @Override\n    public String toString() {\n        return \"LoadBalancerSettings{\" + \"simple=\" + simple + \", consistentHash=\" + consistentHash + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/destination/loadbalance/SimpleLB.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance;\n\npublic enum SimpleLB {\n    ROUND_ROBIN,\n    LEAST_CONN,\n    RANDOM,\n    PASSTHROUGH\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/DubboMatchRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;\n\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.DubboAttachmentMatch;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.DubboMethodMatch;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.StringMatch;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider;\n\nimport java.util.Map;\nimport java.util.Set;\n\npublic class DubboMatchRequest {\n    private String name;\n    private DubboMethodMatch method;\n    private Map<String, String> sourceLabels;\n    private DubboAttachmentMatch attachments;\n    private Map<String, StringMatch> headers;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public DubboMethodMatch getMethod() {\n        return method;\n    }\n\n    public void setMethod(DubboMethodMatch method) {\n        this.method = method;\n    }\n\n    public Map<String, String> getSourceLabels() {\n        return sourceLabels;\n    }\n\n    public void setSourceLabels(Map<String, String> sourceLabels) {\n        this.sourceLabels = sourceLabels;\n    }\n\n    public DubboAttachmentMatch getAttachments() {\n        return attachments;\n    }\n\n    public void setAttachments(DubboAttachmentMatch attachments) {\n        this.attachments = attachments;\n    }\n\n    public Map<String, StringMatch> getHeaders() {\n        return headers;\n    }\n\n    public void setHeaders(Map<String, StringMatch> headers) {\n        this.headers = headers;\n    }\n\n    @Override\n    public String toString() {\n        return \"DubboMatchRequest{\" + \"name='\"\n                + name + '\\'' + \", method=\"\n                + method + \", sourceLabels=\"\n                + sourceLabels + \", attachments=\"\n                + attachments + \", headers=\"\n                + headers + '}';\n    }\n\n    public boolean isMatch(\n            Invocation invocation, Map<String, String> sourceLabels, Set<TracingContextProvider> contextProviders) {\n        // Match method\n        if (getMethod() != null) {\n            if (!getMethod().isMatch(invocation)) {\n                return false;\n            }\n        }\n\n        // Match Source Labels\n        if (getSourceLabels() != null) {\n            for (Map.Entry<String, String> entry : getSourceLabels().entrySet()) {\n                String value = sourceLabels.get(entry.getKey());\n                if (!entry.getValue().equals(value)) {\n                    return false;\n                }\n            }\n        }\n\n        // Match attachment\n        if (getAttachments() != null) {\n            return getAttachments().isMatch(invocation, contextProviders);\n        }\n\n        // TODO Match headers\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/DubboRoute.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;\n\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.StringMatch;\n\nimport java.util.List;\n\npublic class DubboRoute {\n    private String name;\n    private List<StringMatch> services;\n    private List<DubboRouteDetail> routedetail;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public List<StringMatch> getServices() {\n        return services;\n    }\n\n    public void setServices(List<StringMatch> services) {\n        this.services = services;\n    }\n\n    public List<DubboRouteDetail> getRoutedetail() {\n        return routedetail;\n    }\n\n    public void setRoutedetail(List<DubboRouteDetail> routedetail) {\n        this.routedetail = routedetail;\n    }\n\n    @Override\n    public String toString() {\n        return \"DubboRoute{\" + \"name='\" + name + '\\'' + \", services=\" + services + \", routedetail=\" + routedetail + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/DubboRouteDetail.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;\n\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination.DubboRouteDestination;\n\nimport java.util.List;\n\npublic class DubboRouteDetail {\n    private String name;\n    private List<DubboMatchRequest> match;\n    private List<DubboRouteDestination> route;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public List<DubboMatchRequest> getMatch() {\n        return match;\n    }\n\n    public void setMatch(List<DubboMatchRequest> match) {\n        this.match = match;\n    }\n\n    public List<DubboRouteDestination> getRoute() {\n        return route;\n    }\n\n    public void setRoute(List<DubboRouteDestination> route) {\n        this.route = route;\n    }\n\n    @Override\n    public String toString() {\n        return \"DubboRouteDetail{\" + \"name='\" + name + '\\'' + \", match=\" + match + \", route=\" + route + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/VirtualServiceRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;\n\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.BaseRule;\n\npublic class VirtualServiceRule extends BaseRule {\n    private VirtualServiceSpec spec;\n\n    public VirtualServiceSpec getSpec() {\n        return spec;\n    }\n\n    public void setSpec(VirtualServiceSpec spec) {\n        this.spec = spec;\n    }\n\n    @Override\n    public String toString() {\n        return \"VirtualServiceRule{\" + \"base=\" + super.toString() + \", spec=\" + spec + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/VirtualServiceSpec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;\n\nimport java.util.List;\n\npublic class VirtualServiceSpec {\n    private List<String> hosts;\n    private List<DubboRoute> dubbo;\n\n    public List<String> getHosts() {\n        return hosts;\n    }\n\n    public void setHosts(List<String> hosts) {\n        this.hosts = hosts;\n    }\n\n    public List<DubboRoute> getDubbo() {\n        return dubbo;\n    }\n\n    public void setDubbo(List<DubboRoute> dubbo) {\n        this.dubbo = dubbo;\n    }\n\n    @Override\n    public String toString() {\n        return \"VirtualServiceSpec{\" + \"hosts=\" + hosts + \", dubbo=\" + dubbo + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/destination/DubboDestination.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination;\n\npublic class DubboDestination {\n    private String host;\n    private String subset;\n    private int port;\n    private DubboRouteDestination fallback;\n\n    public String getHost() {\n        return host;\n    }\n\n    public void setHost(String host) {\n        this.host = host;\n    }\n\n    public String getSubset() {\n        return subset;\n    }\n\n    public void setSubset(String subset) {\n        this.subset = subset;\n    }\n\n    public int getPort() {\n        return port;\n    }\n\n    public void setPort(int port) {\n        this.port = port;\n    }\n\n    public DubboRouteDestination getFallback() {\n        return fallback;\n    }\n\n    public void setFallback(DubboRouteDestination fallback) {\n        this.fallback = fallback;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/destination/DubboRouteDestination.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination;\n\npublic class DubboRouteDestination {\n    private DubboDestination destination;\n    private int weight;\n\n    public DubboDestination getDestination() {\n        return destination;\n    }\n\n    public void setDestination(DubboDestination destination) {\n        this.destination = destination;\n    }\n\n    public int getWeight() {\n        return weight;\n    }\n\n    public void setWeight(int weight) {\n        this.weight = weight;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/AddressMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.net.UnknownHostException;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_EXEC_CONDITION_ROUTER;\nimport static org.apache.dubbo.common.utils.NetUtils.matchIpExpression;\nimport static org.apache.dubbo.common.utils.UrlUtils.isMatchGlobPattern;\n\npublic class AddressMatch {\n    public static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AddressMatch.class);\n    private String wildcard;\n    private String cird;\n    private String exact;\n\n    public String getWildcard() {\n        return wildcard;\n    }\n\n    public void setWildcard(String wildcard) {\n        this.wildcard = wildcard;\n    }\n\n    public String getCird() {\n        return cird;\n    }\n\n    public void setCird(String cird) {\n        this.cird = cird;\n    }\n\n    public String getExact() {\n        return exact;\n    }\n\n    public void setExact(String exact) {\n        this.exact = exact;\n    }\n\n    public boolean isMatch(String input) {\n        if (getCird() != null && input != null) {\n            try {\n                return input.equals(getCird()) || matchIpExpression(getCird(), input);\n            } catch (UnknownHostException e) {\n                logger.error(\n                        CLUSTER_FAILED_EXEC_CONDITION_ROUTER,\n                        \"Executing routing rule match expression error.\",\n                        \"\",\n                        String.format(\n                                \"Error trying to match cird formatted address %s with input %s in AddressMatch.\",\n                                getCird(), input),\n                        e);\n            }\n        }\n        if (getWildcard() != null && input != null) {\n            if (ANYHOST_VALUE.equals(getWildcard()) || ANY_VALUE.equals(getWildcard())) {\n                return true;\n            }\n            // FIXME\n            return isMatchGlobPattern(getWildcard(), input);\n        }\n        if (getExact() != null && input != null) {\n            return input.equals(getExact());\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/BoolMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\npublic class BoolMatch {\n    private Boolean exact;\n\n    public Boolean getExact() {\n        return exact;\n    }\n\n    public void setExact(Boolean exact) {\n        this.exact = exact;\n    }\n\n    public boolean isMatch(boolean input) {\n        if (exact != null) {\n            return input == exact;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/DoubleMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\npublic class DoubleMatch {\n    private Double exact;\n    private DoubleRangeMatch range;\n    private Double mod;\n\n    public Double getExact() {\n        return exact;\n    }\n\n    public void setExact(Double exact) {\n        this.exact = exact;\n    }\n\n    public DoubleRangeMatch getRange() {\n        return range;\n    }\n\n    public void setRange(DoubleRangeMatch range) {\n        this.range = range;\n    }\n\n    public Double getMod() {\n        return mod;\n    }\n\n    public void setMod(Double mod) {\n        this.mod = mod;\n    }\n\n    public boolean isMatch(Double input) {\n        if (exact != null && mod == null) {\n            return input.equals(exact);\n        } else if (range != null) {\n            return range.isMatch(input);\n        } else if (exact != null) {\n            Double result = input % mod;\n            return result.equals(exact);\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/DoubleRangeMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\npublic class DoubleRangeMatch {\n    private Double start;\n    private Double end;\n\n    public Double getStart() {\n        return start;\n    }\n\n    public void setStart(Double start) {\n        this.start = start;\n    }\n\n    public Double getEnd() {\n        return end;\n    }\n\n    public void setEnd(Double end) {\n        this.end = end;\n    }\n\n    public boolean isMatch(Double input) {\n        if (start != null && end != null) {\n            return input.compareTo(start) >= 0 && input.compareTo(end) < 0;\n        } else if (start != null) {\n            return input.compareTo(start) >= 0;\n        } else if (end != null) {\n            return input.compareTo(end) < 0;\n        } else {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/DubboAttachmentMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider;\n\nimport java.util.Map;\nimport java.util.Set;\n\npublic class DubboAttachmentMatch {\n    private Map<String, StringMatch> tracingContext;\n    private Map<String, StringMatch> dubboContext;\n\n    public Map<String, StringMatch> getTracingContext() {\n        return tracingContext;\n    }\n\n    public void setTracingContext(Map<String, StringMatch> tracingContext) {\n        this.tracingContext = tracingContext;\n    }\n\n    public Map<String, StringMatch> getDubboContext() {\n        return dubboContext;\n    }\n\n    public void setDubboContext(Map<String, StringMatch> dubboContext) {\n        this.dubboContext = dubboContext;\n    }\n\n    public boolean isMatch(Invocation invocation, Set<TracingContextProvider> contextProviders) {\n        // Match Dubbo Context\n        if (dubboContext != null) {\n            for (Map.Entry<String, StringMatch> entry : dubboContext.entrySet()) {\n                String key = entry.getKey();\n                if (!entry.getValue().isMatch(invocation.getAttachment(key))) {\n                    return false;\n                }\n            }\n        }\n\n        // Match Tracing Context\n        if (tracingContext != null) {\n            for (Map.Entry<String, StringMatch> entry : tracingContext.entrySet()) {\n                String key = entry.getKey();\n                boolean match = false;\n                for (TracingContextProvider contextProvider : contextProviders) {\n                    if (entry.getValue().isMatch(contextProvider.getValue(invocation, key))) {\n                        match = true;\n                    }\n                }\n                if (!match) {\n                    return false;\n                }\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/DubboMethodArg.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\npublic class DubboMethodArg {\n    private int index;\n    private String type;\n    private ListStringMatch str_value;\n    private ListDoubleMatch num_value;\n    private BoolMatch bool_value;\n\n    public int getIndex() {\n        return index;\n    }\n\n    public void setIndex(int index) {\n        this.index = index;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public ListStringMatch getStr_value() {\n        return str_value;\n    }\n\n    public void setStr_value(ListStringMatch str_value) {\n        this.str_value = str_value;\n    }\n\n    public ListDoubleMatch getNum_value() {\n        return num_value;\n    }\n\n    public void setNum_value(ListDoubleMatch num_value) {\n        this.num_value = num_value;\n    }\n\n    public BoolMatch getBool_value() {\n        return bool_value;\n    }\n\n    public void setBool_value(BoolMatch bool_value) {\n        this.bool_value = bool_value;\n    }\n\n    public boolean isMatch(Object input) {\n\n        if (str_value != null) {\n            return input instanceof String && str_value.isMatch((String) input);\n        } else if (num_value != null) {\n            return num_value.isMatch(Double.valueOf(input.toString()));\n        } else if (bool_value != null) {\n            return input instanceof Boolean && bool_value.isMatch((Boolean) input);\n        }\n        return false;\n    }\n\n    @Override\n    public String toString() {\n        return \"DubboMethodArg{\" + \"index=\"\n                + index + \", type='\"\n                + type + '\\'' + \", str_value=\"\n                + str_value + \", num_value=\"\n                + num_value + \", bool_value=\"\n                + bool_value + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/DubboMethodMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic class DubboMethodMatch {\n    private StringMatch name_match;\n    private Integer argc;\n    private List<DubboMethodArg> args;\n    private List<StringMatch> argp;\n    private Map<String, StringMatch> headers;\n\n    public StringMatch getName_match() {\n        return name_match;\n    }\n\n    public void setName_match(StringMatch name_match) {\n        this.name_match = name_match;\n    }\n\n    public Integer getArgc() {\n        return argc;\n    }\n\n    public void setArgc(Integer argc) {\n        this.argc = argc;\n    }\n\n    public List<DubboMethodArg> getArgs() {\n        return args;\n    }\n\n    public void setArgs(List<DubboMethodArg> args) {\n        this.args = args;\n    }\n\n    public List<StringMatch> getArgp() {\n        return argp;\n    }\n\n    public void setArgp(List<StringMatch> argp) {\n        this.argp = argp;\n    }\n\n    public Map<String, StringMatch> getHeaders() {\n        return headers;\n    }\n\n    public void setHeaders(Map<String, StringMatch> headers) {\n        this.headers = headers;\n    }\n\n    @Override\n    public String toString() {\n        return \"DubboMethodMatch{\" + \"name_match=\"\n                + name_match + \", argc=\"\n                + argc + \", args=\"\n                + args + \", argp=\"\n                + argp + \", headers=\"\n                + headers + '}';\n    }\n\n    public boolean isMatch(Invocation invocation) {\n        StringMatch nameMatch = getName_match();\n        if (nameMatch != null && !nameMatch.isMatch(RpcUtils.getMethodName(invocation))) {\n            return false;\n        }\n\n        Integer argc = getArgc();\n        Object[] arguments = invocation.getArguments();\n        if (argc != null\n                && ((argc != 0 && (arguments == null || arguments.length == 0)) || (argc != arguments.length))) {\n            return false;\n        }\n\n        List<StringMatch> argp = getArgp();\n        Class<?>[] parameterTypes = invocation.getParameterTypes();\n        if (argp != null && argp.size() > 0) {\n            if (parameterTypes == null || parameterTypes.length == 0) {\n                return false;\n            }\n            if (argp.size() != parameterTypes.length) {\n                return false;\n            }\n\n            for (int index = 0; index < argp.size(); index++) {\n                boolean match = argp.get(index).isMatch(parameterTypes[index].getName())\n                        || argp.get(index).isMatch(parameterTypes[index].getSimpleName());\n                if (!match) {\n                    return false;\n                }\n            }\n        }\n\n        List<DubboMethodArg> args = getArgs();\n        if (args != null && args.size() > 0) {\n            if (arguments == null || arguments.length == 0) {\n                return false;\n            }\n\n            for (DubboMethodArg dubboMethodArg : args) {\n                int index = dubboMethodArg.getIndex();\n                if (index >= arguments.length) {\n                    throw new IndexOutOfBoundsException(\"DubboMethodArg index >= parameters.length\");\n                }\n                if (!dubboMethodArg.isMatch(arguments[index])) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/ListBoolMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport java.util.List;\n\npublic class ListBoolMatch {\n    private List<BoolMatch> oneof;\n\n    public List<BoolMatch> getOneof() {\n        return oneof;\n    }\n\n    public void setOneof(List<BoolMatch> oneof) {\n        this.oneof = oneof;\n    }\n\n    public boolean isMatch(boolean input) {\n\n        for (BoolMatch boolMatch : oneof) {\n            if (boolMatch.isMatch(input)) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/ListDoubleMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport java.util.List;\n\npublic class ListDoubleMatch {\n    private List<DoubleMatch> oneof;\n\n    public List<DoubleMatch> getOneof() {\n        return oneof;\n    }\n\n    public void setOneof(List<DoubleMatch> oneof) {\n        this.oneof = oneof;\n    }\n\n    public boolean isMatch(Double input) {\n\n        for (DoubleMatch doubleMatch : oneof) {\n            if (doubleMatch.isMatch(input)) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/ListStringMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport java.util.List;\n\npublic class ListStringMatch {\n    private List<StringMatch> oneof;\n\n    public List<StringMatch> getOneof() {\n        return oneof;\n    }\n\n    public void setOneof(List<StringMatch> oneof) {\n        this.oneof = oneof;\n    }\n\n    public boolean isMatch(String input) {\n\n        for (StringMatch stringMatch : oneof) {\n            if (stringMatch.isMatch(input)) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/StringMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\n\npublic class StringMatch {\n    private String exact;\n    private String prefix;\n    private String regex;\n    private String noempty;\n    private String empty;\n    private String wildcard;\n\n    public String getExact() {\n        return exact;\n    }\n\n    public void setExact(String exact) {\n        this.exact = exact;\n    }\n\n    public String getPrefix() {\n        return prefix;\n    }\n\n    public void setPrefix(String prefix) {\n        this.prefix = prefix;\n    }\n\n    public String getRegex() {\n        return regex;\n    }\n\n    public void setRegex(String regex) {\n        this.regex = regex;\n    }\n\n    public String getNoempty() {\n        return noempty;\n    }\n\n    public void setNoempty(String noempty) {\n        this.noempty = noempty;\n    }\n\n    public String getEmpty() {\n        return empty;\n    }\n\n    public void setEmpty(String empty) {\n        this.empty = empty;\n    }\n\n    public String getWildcard() {\n        return wildcard;\n    }\n\n    public void setWildcard(String wildcard) {\n        this.wildcard = wildcard;\n    }\n\n    public boolean isMatch(String input) {\n        if (getExact() != null && input != null) {\n            return input.equals(getExact());\n        } else if (getPrefix() != null && input != null) {\n            return input.startsWith(getPrefix());\n        } else if (getRegex() != null && input != null) {\n            return input.matches(getRegex());\n        } else if (getWildcard() != null && input != null) {\n            // only supports \"*\"\n            return input.equals(getWildcard()) || ANY_VALUE.equals(getWildcard());\n        } else if (getEmpty() != null) {\n            return input == null || \"\".equals(input);\n        } else if (getNoempty() != null) {\n            return input != null && input.length() > 0;\n        } else {\n            return false;\n        }\n    }\n\n    @Override\n    public String toString() {\n        return \"StringMatch{\" + \"exact='\"\n                + exact + '\\'' + \", prefix='\"\n                + prefix + '\\'' + \", regex='\"\n                + regex + '\\'' + \", noempty='\"\n                + noempty + '\\'' + \", empty='\"\n                + empty + '\\'' + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/util/MeshRuleDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.util;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_NO_RULE_LISTENER;\n\npublic class MeshRuleDispatcher {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MeshRuleDispatcher.class);\n\n    private final String appName;\n    private final ConcurrentMap<String, Set<MeshRuleListener>> listenerMap = new ConcurrentHashMap<>();\n\n    public MeshRuleDispatcher(String appName) {\n        this.appName = appName;\n    }\n\n    public synchronized void post(Map<String, List<Map<String, Object>>> ruleMap) {\n        if (ruleMap.isEmpty()) {\n            // clear rule\n            for (Map.Entry<String, Set<MeshRuleListener>> entry : listenerMap.entrySet()) {\n                for (MeshRuleListener listener : entry.getValue()) {\n                    listener.clearRule(appName);\n                }\n            }\n        } else {\n            for (Map.Entry<String, List<Map<String, Object>>> entry : ruleMap.entrySet()) {\n                String ruleType = entry.getKey();\n                Set<MeshRuleListener> listeners = listenerMap.get(ruleType);\n                if (CollectionUtils.isNotEmpty(listeners)) {\n                    for (MeshRuleListener listener : listeners) {\n                        listener.onRuleChange(appName, entry.getValue());\n                    }\n                } else {\n                    logger.warn(\n                            CLUSTER_NO_RULE_LISTENER,\n                            \"Receive mesh rule but none of listener has been registered\",\n                            \"\",\n                            \"Receive rule but none of listener has been registered. Maybe type not matched. Rule Type: \"\n                                    + ruleType);\n                }\n            }\n            // clear rule listener not being notified in this time\n            for (Map.Entry<String, Set<MeshRuleListener>> entry : listenerMap.entrySet()) {\n                if (!ruleMap.containsKey(entry.getKey())) {\n                    for (MeshRuleListener listener : entry.getValue()) {\n                        listener.clearRule(appName);\n                    }\n                }\n            }\n        }\n    }\n\n    public synchronized void register(MeshRuleListener listener) {\n        if (listener == null) {\n            return;\n        }\n        ConcurrentHashMapUtils.computeIfAbsent(listenerMap, listener.ruleSuffix(), (k) -> new ConcurrentHashSet<>())\n                .add(listener);\n    }\n\n    public synchronized void unregister(MeshRuleListener listener) {\n        if (listener == null) {\n            return;\n        }\n        Set<MeshRuleListener> listeners = listenerMap.get(listener.ruleSuffix());\n        if (CollectionUtils.isNotEmpty(listeners)) {\n            listeners.remove(listener);\n        }\n        if (CollectionUtils.isEmpty(listeners)) {\n            listenerMap.remove(listener.ruleSuffix());\n        }\n    }\n\n    public boolean isEmpty() {\n        return listenerMap.isEmpty();\n    }\n\n    /**\n     * For ut only\n     */\n    @Deprecated\n    public Map<String, Set<MeshRuleListener>> getListenerMap() {\n        return listenerMap;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/util/MeshRuleListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.util;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface MeshRuleListener {\n    void onRuleChange(String appName, List<Map<String, Object>> rules);\n\n    void clearRule(String appName);\n\n    String ruleSuffix();\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/util/TracingContextProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.util;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.Invocation;\n\n/**\n * SPI to get tracing context from 3rd-party tracing utils ( e.g. OpenTracing )\n */\n@SPI(scope = ExtensionScope.APPLICATION)\npublic interface TracingContextProvider {\n\n    /**\n     * Get value from context\n     *\n     * @param invocation invocation\n     * @param key key of value\n     * @return value (null if absent)\n     */\n    String getValue(Invocation invocation, String key);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.state.RouterGroupingState;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.INVOCATION_NEED_MOCK;\nimport static org.apache.dubbo.rpc.cluster.Constants.MOCK_PROTOCOL;\n\n/**\n * A specific Router designed to realize mock feature.\n * If a request is configured to use mock, then this router guarantees that only the invokers with protocol MOCK appear in final the invoker list, all other invokers will be excluded.\n */\npublic class MockInvokersSelector<T> extends AbstractStateRouter<T> {\n\n    public static final String NAME = \"MOCK_ROUTER\";\n\n    private volatile BitList<Invoker<T>> normalInvokers = BitList.emptyList();\n    private volatile BitList<Invoker<T>> mockedInvokers = BitList.emptyList();\n\n    public MockInvokersSelector(URL url) {\n        super(url);\n    }\n\n    @Override\n    protected BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException {\n        if (CollectionUtils.isEmpty(invokers)) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Empty invokers. Directly return.\");\n            }\n            return invokers;\n        }\n\n        if (invocation.getObjectAttachments() == null) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"ObjectAttachments from invocation are null. Return normal Invokers.\");\n            }\n            return invokers.and(normalInvokers);\n        } else {\n            String value = (String) invocation.getObjectAttachmentWithoutConvert(INVOCATION_NEED_MOCK);\n            if (value == null) {\n                if (needToPrintMessage) {\n                    messageHolder.set(\"invocation.need.mock not set. Return normal Invokers.\");\n                }\n                return invokers.and(normalInvokers);\n            } else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {\n                if (needToPrintMessage) {\n                    messageHolder.set(\"invocation.need.mock is true. Return mocked Invokers.\");\n                }\n                return invokers.and(mockedInvokers);\n            }\n        }\n        if (needToPrintMessage) {\n            messageHolder.set(\"Directly Return. Reason: invocation.need.mock is set but not match true\");\n        }\n        return invokers;\n    }\n\n    @Override\n    public void notify(BitList<Invoker<T>> invokers) {\n        cacheMockedInvokers(invokers);\n        cacheNormalInvokers(invokers);\n    }\n\n    private void cacheMockedInvokers(BitList<Invoker<T>> invokers) {\n        BitList<Invoker<T>> clonedInvokers = invokers.clone();\n        clonedInvokers.removeIf((invoker) -> !invoker.getUrl().getProtocol().equals(MOCK_PROTOCOL));\n        mockedInvokers = clonedInvokers;\n    }\n\n    @SuppressWarnings(\"rawtypes\")\n    private void cacheNormalInvokers(BitList<Invoker<T>> invokers) {\n        BitList<Invoker<T>> clonedInvokers = invokers.clone();\n        clonedInvokers.removeIf((invoker) -> invoker.getUrl().getProtocol().equals(MOCK_PROTOCOL));\n        normalInvokers = clonedInvokers;\n    }\n\n    @Override\n    protected String doBuildSnapshot() {\n        Map<String, BitList<Invoker<T>>> grouping = new HashMap<>();\n        grouping.put(\"Mocked\", mockedInvokers);\n        grouping.put(\"Normal\", normalInvokers);\n        return new RouterGroupingState<>(\n                        this.getClass().getSimpleName(), mockedInvokers.size() + normalInvokers.size(), grouping)\n                .toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;\n\n@Activate(order = -100)\npublic class MockStateRouterFactory implements StateRouterFactory {\n    public static final String NAME = \"mock\";\n\n    @Override\n    public <T> StateRouter<T> getRouter(Class<T> interfaceClass, URL url) {\n        return new MockInvokersSelector<>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.script;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport javax.script.Bindings;\nimport javax.script.Compilable;\nimport javax.script.CompiledScript;\nimport javax.script.ScriptEngine;\nimport javax.script.ScriptEngineManager;\nimport javax.script.ScriptException;\n\nimport java.security.AccessControlContext;\nimport java.security.AccessController;\nimport java.security.CodeSource;\nimport java.security.Permissions;\nimport java.security.PrivilegedAction;\nimport java.security.ProtectionDomain;\nimport java.security.cert.Certificate;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_SCRIPT_EXCEPTION;\nimport static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_SCRIPT_TYPE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.TYPE_KEY;\n\n/**\n * ScriptRouter\n */\npublic class ScriptStateRouter<T> extends AbstractStateRouter<T> {\n    public static final String NAME = \"SCRIPT_ROUTER\";\n    private static final int SCRIPT_ROUTER_DEFAULT_PRIORITY = 0;\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ScriptStateRouter.class);\n\n    private static final ConcurrentMap<String, ScriptEngine> ENGINES = new ConcurrentHashMap<>();\n\n    private final ScriptEngine engine;\n\n    private final String rule;\n\n    private CompiledScript function;\n\n    private AccessControlContext accessControlContext;\n\n    {\n        // Just give permission of reflect to access member.\n        Permissions perms = new Permissions();\n        perms.add(new RuntimePermission(\"accessDeclaredMembers\"));\n        // Cast to Certificate[] required because of ambiguity:\n        ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms);\n        accessControlContext = new AccessControlContext(new ProtectionDomain[] {domain});\n    }\n\n    public ScriptStateRouter(URL url) {\n        super(url);\n        this.setUrl(url);\n\n        engine = getEngine(url);\n        rule = getRule(url);\n        try {\n            Compilable compilable = (Compilable) engine;\n            function = compilable.compile(rule);\n        } catch (ScriptException e) {\n            logger.error(\n                    CLUSTER_SCRIPT_EXCEPTION,\n                    \"script route rule invalid\",\n                    \"\",\n                    \"script route error, rule has been ignored. rule: \" + rule + \", url: \"\n                            + RpcContext.getServiceContext().getUrl(),\n                    e);\n        }\n    }\n\n    /**\n     * get rule from url parameters.\n     */\n    private String getRule(URL url) {\n        String vRule = url.getParameterAndDecoded(RULE_KEY);\n        if (StringUtils.isEmpty(vRule)) {\n            throw new IllegalStateException(\"route rule can not be empty.\");\n        }\n        return vRule;\n    }\n\n    /**\n     * create ScriptEngine instance by type from url parameters, then cache it\n     */\n    private ScriptEngine getEngine(URL url) {\n        String type = url.getParameter(TYPE_KEY, DEFAULT_SCRIPT_TYPE_KEY);\n\n        return ConcurrentHashMapUtils.computeIfAbsent(ENGINES, type, t -> {\n            ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName(type);\n            if (scriptEngine == null) {\n                throw new IllegalStateException(\"unsupported route engine type: \" + type);\n            }\n            return scriptEngine;\n        });\n    }\n\n    @Override\n    protected BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException {\n        if (engine == null || function == null) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Directly Return. Reason: engine or function is null\");\n            }\n            return invokers;\n        }\n        Bindings bindings = createBindings(invokers, invocation);\n        return getRoutedInvokers(\n                invokers,\n                AccessController.doPrivileged(\n                        (PrivilegedAction<Object>) () -> {\n                            try {\n                                return function.eval(bindings);\n                            } catch (ScriptException e) {\n                                logger.error(\n                                        CLUSTER_SCRIPT_EXCEPTION,\n                                        \"Scriptrouter exec script error\",\n                                        \"\",\n                                        \"Script route error, rule has been ignored. rule: \" + rule + \", method:\"\n                                                + RpcUtils.getMethodName(invocation) + \", url: \"\n                                                + RpcContext.getContext().getUrl(),\n                                        e);\n                                return invokers;\n                            }\n                        },\n                        accessControlContext));\n    }\n\n    /**\n     * get routed invokers from result of script rule evaluation\n     */\n    @SuppressWarnings(\"unchecked\")\n    protected BitList<Invoker<T>> getRoutedInvokers(BitList<Invoker<T>> invokers, Object obj) {\n        BitList<Invoker<T>> result = invokers.clone();\n        if (obj instanceof Invoker[]) {\n            result.retainAll(Arrays.asList((Invoker<T>[]) obj));\n        } else if (obj instanceof Object[]) {\n            result.retainAll(\n                    Arrays.stream((Object[]) obj).map(item -> (Invoker<T>) item).collect(Collectors.toList()));\n        } else {\n            result.retainAll((List<Invoker<T>>) obj);\n        }\n        return result;\n    }\n\n    /**\n     * create bindings for script engine\n     */\n    private Bindings createBindings(List<Invoker<T>> invokers, Invocation invocation) {\n        Bindings bindings = engine.createBindings();\n        // create a new List of invokers\n        bindings.put(\"invokers\", new ArrayList<>(invokers));\n        bindings.put(\"invocation\", invocation);\n        bindings.put(\"context\", RpcContext.getClientAttachment());\n        return bindings;\n    }\n\n    @Override\n    public boolean isRuntime() {\n        return this.getUrl().getParameter(RUNTIME_KEY, false);\n    }\n\n    @Override\n    public boolean isForce() {\n        return this.getUrl().getParameter(FORCE_KEY, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.script;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;\n\n/**\n * ScriptRouterFactory\n * <p>\n * Example URLS used by Script Router Factory：\n * <ol>\n * <li> script://registryAddress?type=js&rule=xxxx\n * <li> script:///path/to/routerfile.js?type=js&rule=xxxx\n * <li> script://D:\\path\\to\\routerfile.js?type=js&rule=xxxx\n * <li> script://C:/path/to/routerfile.js?type=js&rule=xxxx\n * </ol>\n * The host value in URL points out the address of the source content of the Script Router，Registry、File etc\n *\n */\npublic class ScriptStateRouterFactory implements StateRouterFactory {\n\n    public static final String NAME = \"script\";\n\n    @Override\n    public <T> StateRouter<T> getRouter(Class<T> interfaceClass, URL url) {\n        return new ScriptStateRouter<>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/config/AppScriptRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.script.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.state.CacheableStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\n\n@Activate(order = 200)\npublic class AppScriptRouterFactory extends CacheableStateRouterFactory {\n    public static final String NAME = \"script\";\n\n    @Override\n    protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {\n        return new AppScriptStateRouter<>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/config/AppScriptStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.script.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.script.ScriptStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.script.config.model.ScriptRule;\nimport org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_TAG_ROUTE_EMPTY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_TAG_ROUTE_INVALID;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\nimport static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_SCRIPT_TYPE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.TYPE_KEY;\n\npublic class AppScriptStateRouter<T> extends AbstractStateRouter<T> implements ConfigurationListener {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(AppScriptStateRouter.class);\n    private static final String RULE_SUFFIX = \".script-router\";\n\n    private ScriptRule scriptRule;\n    private ScriptStateRouter<T> scriptRouter;\n    private String application;\n\n    public AppScriptStateRouter(URL url) {\n        super(url);\n    }\n\n    @Override\n    protected BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> routerSnapshotNodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException {\n        if (scriptRouter == null || !scriptRule.isValid() || !scriptRule.isEnabled()) {\n            if (needToPrintMessage) {\n                messageHolder.set(\n                        \"Directly return from script router. Reason: Invokers from previous router is empty or script is not enabled. Script rule is: \"\n                                + (scriptRule == null ? \"null\" : scriptRule.getRawRule()));\n            }\n            return invokers;\n        }\n\n        invokers = scriptRouter.route(invokers, url, invocation, needToPrintMessage, routerSnapshotNodeHolder);\n\n        if (needToPrintMessage) {\n            messageHolder.set(messageHolder.get());\n        }\n\n        return invokers;\n    }\n\n    @Override\n    public synchronized void process(ConfigChangedEvent event) {\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Notification of script rule change, type is: \" + event.getChangeType() + \", raw rule is:\\n \"\n                    + event.getContent());\n        }\n\n        try {\n            if (event.getChangeType().equals(ConfigChangeType.DELETED)) {\n                this.scriptRule = null;\n            } else {\n                this.scriptRule = ScriptRule.parse(event.getContent());\n                URL scriptUrl = getUrl().addParameter(\n                                TYPE_KEY,\n                                isEmpty(scriptRule.getType()) ? DEFAULT_SCRIPT_TYPE_KEY : scriptRule.getType())\n                        .addParameterAndEncoded(RULE_KEY, scriptRule.getScript())\n                        .addParameter(FORCE_KEY, scriptRule.isForce())\n                        .addParameter(RUNTIME_KEY, scriptRule.isRuntime());\n                scriptRouter = new ScriptStateRouter<>(scriptUrl);\n            }\n        } catch (Exception e) {\n            logger.error(\n                    CLUSTER_TAG_ROUTE_INVALID,\n                    \"Failed to parse the raw tag router rule\",\n                    \"\",\n                    \"Failed to parse the raw tag router rule and it will not take effect, please check if the \"\n                            + \"rule matches with the template, the raw rule is:\\n \",\n                    e);\n        }\n    }\n\n    @Override\n    public void notify(BitList<Invoker<T>> invokers) {\n        if (CollectionUtils.isEmpty(invokers)) {\n            return;\n        }\n\n        Invoker<T> invoker = invokers.get(0);\n        URL url = invoker.getUrl();\n        String providerApplication = url.getRemoteApplication();\n\n        if (isEmpty(providerApplication)) {\n            logger.error(\n                    CLUSTER_TAG_ROUTE_EMPTY,\n                    \"tag router get providerApplication is empty\",\n                    \"\",\n                    \"TagRouter must getConfig from or subscribe to a specific application, but the application \"\n                            + \"in this TagRouter is not specified.\");\n            return;\n        }\n\n        synchronized (this) {\n            if (!providerApplication.equals(application)) {\n                if (StringUtils.isNotEmpty(application)) {\n                    this.getRuleRepository().removeListener(application + RULE_SUFFIX, this);\n                }\n                String key = providerApplication + RULE_SUFFIX;\n                this.getRuleRepository().addListener(key, this);\n                application = providerApplication;\n                String rawRule = this.getRuleRepository().getRule(key, DynamicConfiguration.DEFAULT_GROUP);\n                if (StringUtils.isNotEmpty(rawRule)) {\n                    this.process(new ConfigChangedEvent(key, DynamicConfiguration.DEFAULT_GROUP, rawRule));\n                }\n            }\n        }\n    }\n\n    @Override\n    public void stop() {\n        if (StringUtils.isNotEmpty(application)) {\n            this.getRuleRepository().removeListener(application + RULE_SUFFIX, this);\n        }\n    }\n\n    // for testing purpose\n    public void setScriptRule(ScriptRule scriptRule) {\n        this.scriptRule = scriptRule;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/config/model/ScriptRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.script.config.model;\n\nimport org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;\n\nimport java.util.Map;\n\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\n\npublic class ScriptRule extends AbstractRouterRule {\n    private static final String TYPE_KEY = \"type\";\n    private static final String SCRIPT_KEY = \"script\";\n    private String type;\n    private String script;\n\n    public static ScriptRule parse(String rawRule) {\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Map<String, Object> map = yaml.load(rawRule);\n\n        ScriptRule rule = new ScriptRule();\n        rule.parseFromMap0(map);\n        rule.setRawRule(rawRule);\n\n        Object rawType = map.get(TYPE_KEY);\n        if (rawType != null) {\n            rule.setType((String) rawType);\n        }\n\n        Object rawScript = map.get(SCRIPT_KEY);\n        if (rawScript != null) {\n            rule.setScript((String) rawScript);\n        } else {\n            rule.setValid(false);\n        }\n\n        return rule;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public String getScript() {\n        return script;\n    }\n\n    public void setScript(String script) {\n        this.script = script;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/AbstractStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.state;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Constants;\nimport org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\n/***\n * The abstract class of StateRoute.\n * @since 3.0\n */\npublic abstract class AbstractStateRouter<T> implements StateRouter<T> {\n    private volatile boolean force = false;\n    private volatile URL url;\n    private volatile StateRouter<T> nextRouter = null;\n\n    private final GovernanceRuleRepository ruleRepository;\n\n    /**\n     * Should continue route if current router's result is empty\n     */\n    private final boolean shouldFailFast;\n\n    protected ModuleModel moduleModel;\n\n    public AbstractStateRouter(URL url) {\n        moduleModel = url.getOrDefaultModuleModel();\n        this.ruleRepository =\n                moduleModel.getExtensionLoader(GovernanceRuleRepository.class).getDefaultExtension();\n        this.url = url;\n        this.shouldFailFast = Boolean.parseBoolean(\n                ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, \"true\"));\n    }\n\n    @Override\n    public URL getUrl() {\n        return url;\n    }\n\n    public void setUrl(URL url) {\n        this.url = url;\n    }\n\n    @Override\n    public boolean isRuntime() {\n        return true;\n    }\n\n    @Override\n    public boolean isForce() {\n        return force;\n    }\n\n    public void setForce(boolean force) {\n        this.force = force;\n    }\n\n    public GovernanceRuleRepository getRuleRepository() {\n        return this.ruleRepository;\n    }\n\n    public StateRouter<T> getNextRouter() {\n        return nextRouter;\n    }\n\n    @Override\n    public void notify(BitList<Invoker<T>> invokers) {\n        // default empty implement\n    }\n\n    @Override\n    public final BitList<Invoker<T>> route(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder)\n            throws RpcException {\n        if (needToPrintMessage && (nodeHolder == null || nodeHolder.get() == null)) {\n            needToPrintMessage = false;\n        }\n\n        RouterSnapshotNode<T> currentNode = null;\n        RouterSnapshotNode<T> parentNode = null;\n        Holder<String> messageHolder = null;\n\n        // pre-build current node\n        if (needToPrintMessage) {\n            parentNode = nodeHolder.get();\n            currentNode = new RouterSnapshotNode<>(this.getClass().getSimpleName(), invokers.clone());\n            parentNode.appendNode(currentNode);\n\n            // set parent node's output size in the first child invoke\n            // initial node output size is zero, first child will override it\n            if (parentNode.getNodeOutputSize() < invokers.size()) {\n                parentNode.setNodeOutputInvokers(invokers.clone());\n            }\n\n            messageHolder = new Holder<>();\n            nodeHolder.set(currentNode);\n        }\n        BitList<Invoker<T>> routeResult;\n\n        routeResult = doRoute(invokers, url, invocation, needToPrintMessage, nodeHolder, messageHolder);\n        if (routeResult != invokers) {\n            routeResult = invokers.and(routeResult);\n        }\n        // check if router support call continue route by itself\n        if (!supportContinueRoute()) {\n            // use current node's result as next node's parameter\n            if (!shouldFailFast || !routeResult.isEmpty()) {\n                routeResult = continueRoute(routeResult, url, invocation, needToPrintMessage, nodeHolder);\n            }\n        }\n\n        // post-build current node\n        if (needToPrintMessage) {\n            currentNode.setRouterMessage(messageHolder.get());\n            if (currentNode.getNodeOutputSize() == 0) {\n                // no child call\n                currentNode.setNodeOutputInvokers(routeResult.clone());\n            }\n            currentNode.setChainOutputInvokers(routeResult.clone());\n            nodeHolder.set(parentNode);\n        }\n        return routeResult;\n    }\n\n    /**\n     * Filter invokers with current routing rule and only return the invokers that comply with the rule.\n     *\n     * @param invokers all invokers to be routed\n     * @param url consumerUrl\n     * @param invocation invocation\n     * @param needToPrintMessage should current router print message\n     * @param nodeHolder RouterSnapshotNode In general, router itself no need to care this param, just pass to continueRoute\n     * @param messageHolder message holder when router should current router print message\n     * @return routed result\n     */\n    protected abstract BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException;\n\n    /**\n     * Call next router to get result\n     *\n     * @param invokers current router filtered invokers\n     */\n    protected final BitList<Invoker<T>> continueRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder) {\n        if (nextRouter != null) {\n            return nextRouter.route(invokers, url, invocation, needToPrintMessage, nodeHolder);\n        } else {\n            return invokers;\n        }\n    }\n\n    /**\n     * Whether current router's implementation support call\n     * {@link AbstractStateRouter#continueRoute(BitList, URL, Invocation, boolean, Holder)}\n     * by router itself.\n     *\n     * @return support or not\n     */\n    protected boolean supportContinueRoute() {\n        return false;\n    }\n\n    /**\n     * Next Router node state is maintained by AbstractStateRouter and this method is not allow to override.\n     * If a specified router wants to control the behaviour of continue route or not,\n     * please override {@link AbstractStateRouter#supportContinueRoute()}\n     */\n    @Override\n    public final void setNextRouter(StateRouter<T> nextRouter) {\n        this.nextRouter = nextRouter;\n    }\n\n    @Override\n    public final String buildSnapshot() {\n        return doBuildSnapshot() + \"            v \\n\" + nextRouter.buildSnapshot();\n    }\n\n    protected String doBuildSnapshot() {\n        return this.getClass().getSimpleName() + \" not support\\n\";\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/BitList.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.state;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\n\nimport java.util.AbstractList;\nimport java.util.ArrayList;\nimport java.util.BitSet;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.NoSuchElementException;\nimport java.util.concurrent.ThreadLocalRandom;\n\n/**\n * BitList based on BitMap implementation.\n * BitList is consists of `originList`, `rootSet` and `tailList`.\n * <p>\n * originList: Initial elements of the list. This list will not be changed\n * in modification actions (expect clear all).\n * rootSet: A bitMap to store the indexes of originList are still exist.\n * Most of the modification actions are operated on this bitMap.\n * tailList: An additional list for BitList. Worked when adding totally new\n * elements to list. These elements will be appended to the last\n * of the BitList.\n * <p>\n * An example of BitList:\n * originList:  A  B  C  D  E             (5 elements)\n * rootSet:     x  v  x  v  v\n * 0  1  0  1  1             (5 elements)\n * tailList:                   F  G  H    (3 elements)\n * resultList:     B     D  E  F  G  H    (6 elements)\n *\n * @param <E>\n * @since 3.0\n */\npublic class BitList<E> extends AbstractList<E> implements Cloneable {\n    private final BitSet rootSet;\n    private volatile List<E> originList;\n    private static final BitList emptyList = new BitList(Collections.emptyList());\n    private volatile List<E> tailList = null;\n\n    public BitList(List<E> originList) {\n        this(originList, false);\n    }\n\n    public BitList(List<E> originList, boolean empty) {\n        if (originList instanceof BitList) {\n            this.originList = ((BitList<E>) originList).getOriginList();\n            this.tailList = ((BitList<E>) originList).getTailList();\n        } else {\n            this.originList = originList;\n        }\n        this.rootSet = new BitSet();\n        if (!empty) {\n            this.rootSet.set(0, originList.size());\n        } else {\n            this.tailList = null;\n        }\n    }\n\n    public BitList(List<E> originList, boolean empty, List<E> tailList) {\n        this.originList = originList;\n        this.rootSet = new BitSet();\n        if (!empty) {\n            this.rootSet.set(0, originList.size());\n        }\n        this.tailList = tailList;\n    }\n\n    public BitList(List<E> originList, BitSet rootSet, List<E> tailList) {\n        this.originList = originList;\n        this.rootSet = rootSet;\n        this.tailList = tailList;\n    }\n\n    // Provided by BitList only\n    public synchronized List<E> getOriginList() {\n        return originList;\n    }\n\n    public synchronized void addIndex(int index) {\n        this.rootSet.set(index);\n    }\n\n    public synchronized int totalSetSize() {\n        return this.originList.size();\n    }\n\n    public synchronized boolean indexExist(int index) {\n        return this.rootSet.get(index);\n    }\n\n    public synchronized E getByIndex(int index) {\n        return this.originList.get(index);\n    }\n\n    /**\n     * And operation between two bitList. Return a new cloned list.\n     * TailList in source bitList will be totally saved even if it is not appeared in the target bitList.\n     *\n     * @param target target bitList\n     * @return this bitList only contains those elements contain in both two list and source bitList's tailList\n     */\n    public synchronized BitList<E> and(BitList<E> target) {\n        rootSet.and(target.rootSet);\n        if (target.getTailList() != null) {\n            target.getTailList().forEach(this::addToTailList);\n        }\n        return this;\n    }\n\n    public synchronized BitList<E> or(BitList<E> target) {\n        BitSet resultSet = (BitSet) rootSet.clone();\n        resultSet.or(target.rootSet);\n        return new BitList<>(originList, resultSet, tailList);\n    }\n\n    public synchronized boolean hasMoreElementInTailList() {\n        return CollectionUtils.isNotEmpty(tailList);\n    }\n\n    public synchronized List<E> getTailList() {\n        return tailList;\n    }\n\n    public synchronized void addToTailList(E e) {\n        if (tailList == null) {\n            tailList = new LinkedList<>();\n        }\n        tailList.add(e);\n    }\n\n    public synchronized E randomSelectOne() {\n        int originSize = originList.size();\n        int tailSize = tailList != null ? tailList.size() : 0;\n        int totalSize = originSize + tailSize;\n        int cardinality = rootSet.cardinality();\n\n        // example 1 : origin size is 1000, cardinality is 50, rate is 1/20. 20 * 2 = 40 < 50, try random select\n        // example 2 : origin size is 1000, cardinality is 25, rate is 1/40. 40 * 2 = 80 > 50, directly use iterator\n        int rate = originSize / cardinality;\n        if (rate <= cardinality * 2) {\n            int count = rate * 5;\n            for (int i = 0; i < count; i++) {\n                int random = ThreadLocalRandom.current().nextInt(totalSize);\n                if (random < originSize) {\n                    if (rootSet.get(random)) {\n                        return originList.get(random);\n                    }\n                } else {\n                    return tailList.get(random - originSize);\n                }\n            }\n        }\n        return get(ThreadLocalRandom.current().nextInt(cardinality + tailSize));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> BitList<T> emptyList() {\n        return emptyList;\n    }\n\n    // Provided by JDK List interface\n    @Override\n    public synchronized int size() {\n        return rootSet.cardinality() + (CollectionUtils.isNotEmpty(tailList) ? tailList.size() : 0);\n    }\n\n    @Override\n    public synchronized boolean contains(Object o) {\n        int idx = originList.indexOf(o);\n        return (idx >= 0 && rootSet.get(idx)) || (CollectionUtils.isNotEmpty(tailList) && tailList.contains(o));\n    }\n\n    @Override\n    public synchronized Iterator<E> iterator() {\n        return new BitListIterator<>(this, 0);\n    }\n\n    /**\n     * If the element to added is appeared in originList even if it is not in rootSet,\n     * directly set its index in rootSet to true. (This may change the order of elements.)\n     * <p>\n     * If the element is not contained in originList, allocate tailList and add to tailList.\n     * <p>\n     * Notice: It is not recommended adding duplicated element.\n     */\n    @Override\n    public synchronized boolean add(E e) {\n        int index = originList.indexOf(e);\n        if (index > -1) {\n            rootSet.set(index);\n            return true;\n        } else {\n            if (tailList == null) {\n                tailList = new LinkedList<>();\n            }\n            return tailList.add(e);\n        }\n    }\n\n    /**\n     * If the element to added is appeared in originList,\n     * directly set its index in rootSet to false. (This may change the order of elements.)\n     * <p>\n     * If the element is not contained in originList, try to remove from tailList.\n     */\n    @Override\n    public synchronized boolean remove(Object o) {\n        int idx = originList.indexOf(o);\n        if (idx > -1 && rootSet.get(idx)) {\n            rootSet.set(idx, false);\n            return true;\n        }\n        if (CollectionUtils.isNotEmpty(tailList)) {\n            return tailList.remove(o);\n        }\n        return false;\n    }\n\n    /**\n     * Caution: This operation will clear originList for removing references purpose.\n     * This may change the default behaviour when adding new element later.\n     */\n    @Override\n    public synchronized void clear() {\n        rootSet.clear();\n        // to remove references\n        originList = Collections.emptyList();\n        if (CollectionUtils.isNotEmpty(tailList)) {\n            tailList = null;\n        }\n    }\n\n    @Override\n    public synchronized E get(int index) {\n        int bitIndex = -1;\n        if (index < 0) {\n            throw new IndexOutOfBoundsException();\n        }\n        if (index >= rootSet.cardinality()) {\n            if (CollectionUtils.isNotEmpty(tailList)) {\n                return tailList.get(index - rootSet.cardinality());\n            } else {\n                throw new IndexOutOfBoundsException();\n            }\n        } else {\n            for (int i = 0; i <= index; i++) {\n                bitIndex = rootSet.nextSetBit(bitIndex + 1);\n            }\n            return originList.get(bitIndex);\n        }\n    }\n\n    @Override\n    public synchronized E remove(int index) {\n        int bitIndex = -1;\n        if (index >= rootSet.cardinality()) {\n            if (CollectionUtils.isNotEmpty(tailList)) {\n                return tailList.remove(index - rootSet.cardinality());\n            } else {\n                throw new IndexOutOfBoundsException();\n            }\n        } else {\n            for (int i = 0; i <= index; i++) {\n                bitIndex = rootSet.nextSetBit(bitIndex + 1);\n            }\n            rootSet.set(bitIndex, false);\n            return originList.get(bitIndex);\n        }\n    }\n\n    @Override\n    public synchronized int indexOf(Object o) {\n        int bitIndex = -1;\n        for (int i = 0; i < rootSet.cardinality(); i++) {\n            bitIndex = rootSet.nextSetBit(bitIndex + 1);\n            if (originList.get(bitIndex).equals(o)) {\n                return i;\n            }\n        }\n        if (CollectionUtils.isNotEmpty(tailList)) {\n            int indexInTailList = tailList.indexOf(o);\n            if (indexInTailList != -1) {\n                return indexInTailList + rootSet.cardinality();\n            } else {\n                return -1;\n            }\n        }\n        return -1;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public synchronized boolean addAll(Collection<? extends E> c) {\n        if (c instanceof BitList) {\n            rootSet.or(((BitList<? extends E>) c).rootSet);\n            if (((BitList<? extends E>) c).hasMoreElementInTailList()) {\n                for (E e : ((BitList<? extends E>) c).tailList) {\n                    addToTailList(e);\n                }\n            }\n            return true;\n        }\n        return super.addAll(c);\n    }\n\n    @Override\n    public synchronized int lastIndexOf(Object o) {\n        int bitIndex = -1;\n        int index = -1;\n        if (CollectionUtils.isNotEmpty(tailList)) {\n            int indexInTailList = tailList.lastIndexOf(o);\n            if (indexInTailList > -1) {\n                return indexInTailList + rootSet.cardinality();\n            }\n        }\n        for (int i = 0; i < rootSet.cardinality(); i++) {\n            bitIndex = rootSet.nextSetBit(bitIndex + 1);\n            if (originList.get(bitIndex).equals(o)) {\n                index = i;\n            }\n        }\n        return index;\n    }\n\n    @Override\n    public synchronized boolean isEmpty() {\n        return this.rootSet.isEmpty() && CollectionUtils.isEmpty(tailList);\n    }\n\n    @Override\n    public synchronized ListIterator<E> listIterator() {\n        return new BitListIterator<>(this, 0);\n    }\n\n    @Override\n    public synchronized ListIterator<E> listIterator(int index) {\n        return new BitListIterator<>(this, index);\n    }\n\n    @Override\n    public synchronized BitList<E> subList(int fromIndex, int toIndex) {\n        BitSet resultSet = (BitSet) rootSet.clone();\n        List<E> copiedTailList = tailList == null ? null : new LinkedList<>(tailList);\n        if (toIndex < size()) {\n            if (toIndex < rootSet.cardinality()) {\n                copiedTailList = null;\n                resultSet.set(toIndex, resultSet.length(), false);\n            } else {\n                copiedTailList =\n                        copiedTailList == null ? null : copiedTailList.subList(0, toIndex - rootSet.cardinality());\n            }\n        }\n        if (fromIndex > 0) {\n            if (fromIndex < rootSet.cardinality()) {\n                resultSet.set(0, fromIndex, false);\n            } else {\n                resultSet.clear();\n                copiedTailList = copiedTailList == null\n                        ? null\n                        : copiedTailList.subList(fromIndex - rootSet.cardinality(), copiedTailList.size());\n            }\n        }\n        return new BitList<>(originList, resultSet, copiedTailList);\n    }\n\n    public static class BitListIterator<E> implements ListIterator<E> {\n        private BitList<E> bitList;\n        private int index;\n        private ListIterator<E> tailListIterator;\n        private int curBitIndex = -1;\n        private boolean isInTailList = false;\n        private int lastReturnedIndex = -1;\n\n        public BitListIterator(BitList<E> bitList, int index) {\n            this.bitList = bitList;\n            this.index = index - 1;\n            for (int i = 0; i < index; i++) {\n                if (!isInTailList) {\n                    curBitIndex = bitList.rootSet.nextSetBit(curBitIndex + 1);\n                    if (curBitIndex == -1) {\n                        if (CollectionUtils.isNotEmpty(bitList.tailList)) {\n                            isInTailList = true;\n                            tailListIterator = bitList.tailList.listIterator();\n                            tailListIterator.next();\n                        } else {\n                            break;\n                        }\n                    }\n                } else {\n                    tailListIterator.next();\n                }\n            }\n        }\n\n        @Override\n        public synchronized boolean hasNext() {\n            if (isInTailList) {\n                return tailListIterator.hasNext();\n            } else {\n                int nextBit = bitList.rootSet.nextSetBit(curBitIndex + 1);\n                if (nextBit == -1) {\n                    return bitList.hasMoreElementInTailList();\n                } else {\n                    return true;\n                }\n            }\n        }\n\n        @Override\n        public synchronized E next() {\n            if (isInTailList) {\n                if (tailListIterator.hasNext()) {\n                    index += 1;\n                    lastReturnedIndex = index;\n                }\n                return tailListIterator.next();\n            } else {\n                int nextBitIndex = bitList.rootSet.nextSetBit(curBitIndex + 1);\n                if (nextBitIndex == -1) {\n                    if (bitList.hasMoreElementInTailList()) {\n                        tailListIterator = bitList.tailList.listIterator();\n                        isInTailList = true;\n                        index += 1;\n                        lastReturnedIndex = index;\n                        return tailListIterator.next();\n                    } else {\n                        throw new NoSuchElementException();\n                    }\n                } else {\n                    index += 1;\n                    lastReturnedIndex = index;\n                    curBitIndex = nextBitIndex;\n                    return bitList.originList.get(nextBitIndex);\n                }\n            }\n        }\n\n        @Override\n        public synchronized boolean hasPrevious() {\n            if (isInTailList) {\n                boolean hasPreviousInTailList = tailListIterator.hasPrevious();\n                if (hasPreviousInTailList) {\n                    return true;\n                } else {\n                    return bitList.rootSet.previousSetBit(bitList.rootSet.size()) != -1;\n                }\n            } else {\n                return curBitIndex != -1;\n            }\n        }\n\n        @Override\n        public synchronized E previous() {\n            if (isInTailList) {\n                boolean hasPreviousInTailList = tailListIterator.hasPrevious();\n                if (hasPreviousInTailList) {\n                    lastReturnedIndex = index;\n                    index -= 1;\n                    return tailListIterator.previous();\n                } else {\n                    int lastIndexInBit = bitList.rootSet.previousSetBit(bitList.rootSet.size());\n                    if (lastIndexInBit == -1) {\n                        throw new NoSuchElementException();\n                    } else {\n                        isInTailList = false;\n                        curBitIndex = bitList.rootSet.previousSetBit(lastIndexInBit - 1);\n                        lastReturnedIndex = index;\n                        index -= 1;\n                        return bitList.originList.get(lastIndexInBit);\n                    }\n                }\n            } else {\n                if (curBitIndex == -1) {\n                    throw new NoSuchElementException();\n                }\n                int nextBitIndex = curBitIndex;\n                curBitIndex = bitList.rootSet.previousSetBit(curBitIndex - 1);\n                lastReturnedIndex = index;\n                index -= 1;\n                return bitList.originList.get(nextBitIndex);\n            }\n        }\n\n        @Override\n        public synchronized int nextIndex() {\n            return hasNext() ? index + 1 : index;\n        }\n\n        @Override\n        public synchronized int previousIndex() {\n            return index;\n        }\n\n        @Override\n        public synchronized void remove() {\n            if (lastReturnedIndex == -1) {\n                throw new IllegalStateException();\n            } else {\n                if (lastReturnedIndex >= bitList.rootSet.cardinality()) {\n                    tailListIterator.remove();\n                } else {\n                    int bitIndex = -1;\n                    for (int i = 0; i <= lastReturnedIndex; i++) {\n                        bitIndex = bitList.rootSet.nextSetBit(bitIndex + 1);\n                    }\n                    bitList.rootSet.set(bitIndex, false);\n                }\n            }\n            if (lastReturnedIndex <= index) {\n                index -= 1;\n            }\n        }\n\n        @Override\n        public synchronized void set(E e) {\n            throw new UnsupportedOperationException(\"Set method is not supported in BitListIterator!\");\n        }\n\n        @Override\n        public synchronized void add(E e) {\n            throw new UnsupportedOperationException(\"Add method is not supported in BitListIterator!\");\n        }\n    }\n\n    public synchronized ArrayList<E> cloneToArrayList() {\n        if (rootSet.cardinality() == originList.size() && (CollectionUtils.isEmpty(tailList))) {\n            return new ArrayList<>(originList);\n        }\n        ArrayList<E> arrayList = new ArrayList<>(size());\n        arrayList.addAll(this);\n        return arrayList;\n    }\n\n    @Override\n    public synchronized BitList<E> clone() {\n        return new BitList<>(\n                originList, (BitSet) rootSet.clone(), tailList == null ? null : new LinkedList<>(tailList));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/CacheableStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.state;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * If you want to provide a router implementation based on design of v2.7.0, please extend from this abstract class.\n * For 2.6.x style router, please implement and use RouterFactory directly.\n */\npublic abstract class CacheableStateRouterFactory implements StateRouterFactory {\n    // TODO reuse StateRouter for all routerChain\n    private final ConcurrentMap<String, StateRouter> routerMap = new ConcurrentHashMap<>();\n\n    @Override\n    public <T> StateRouter<T> getRouter(Class<T> interfaceClass, URL url) {\n        return ConcurrentHashMapUtils.computeIfAbsent(\n                routerMap, url.getServiceKey(), k -> createRouter(interfaceClass, url));\n    }\n\n    protected abstract <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/RouterGroupingState.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.state;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invoker;\n\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\npublic class RouterGroupingState<T> {\n    private final String routerName;\n    private final int total;\n    private final Map<String, BitList<Invoker<T>>> grouping;\n\n    public RouterGroupingState(String routerName, int total, Map<String, BitList<Invoker<T>>> grouping) {\n        this.routerName = routerName;\n        this.total = total;\n        this.grouping = grouping;\n    }\n\n    public String getRouterName() {\n        return routerName;\n    }\n\n    public int getTotal() {\n        return total;\n    }\n\n    public Map<String, BitList<Invoker<T>>> getGrouping() {\n        return grouping;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder stringBuilder = new StringBuilder();\n        stringBuilder\n                .append(routerName)\n                .append(' ')\n                .append(\" Total: \")\n                .append(total)\n                .append(\"\\n\");\n\n        for (Map.Entry<String, BitList<Invoker<T>>> entry : grouping.entrySet()) {\n            BitList<Invoker<T>> invokers = entry.getValue();\n            stringBuilder\n                    .append(\"[ \")\n                    .append(entry.getKey())\n                    .append(\" -> \")\n                    .append(\n                            invokers.isEmpty()\n                                    ? \"Empty\"\n                                    : invokers.stream()\n                                            .limit(5)\n                                            .map(Invoker::getUrl)\n                                            .map(URL::getAddress)\n                                            .collect(Collectors.joining(\",\")))\n                    .append(invokers.size() > 5 ? \"...\" : \"\")\n                    .append(\" (Total: \")\n                    .append(invokers.size())\n                    .append(\") ]\")\n                    .append(\"\\n\");\n        }\n        return stringBuilder.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/StateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.state;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\n\n/**\n * State Router. (SPI, Prototype, ThreadSafe)\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Routing\">Routing</a>\n *\n * It is recommended to implement StateRouter by extending {@link AbstractStateRouter}\n *\n * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory, boolean)\n * @see AbstractStateRouter\n * @see Directory#list(Invocation)\n * @since 3.0\n */\npublic interface StateRouter<T> {\n\n    /**\n     * Get the router url.\n     *\n     * @return url\n     */\n    URL getUrl();\n\n    /***\n     * Filter invokers with current routing rule and only return the invokers that comply with the rule.\n     * Caching address lists in BitMap mode improves routing performance.\n     * @param invokers  invoker bit list\n     * @param url        refer url\n     * @param invocation invocation\n     * @param needToPrintMessage whether to print router state. Such as `use router branch a`.\n     * @return state with route result\n     * @since 3.0\n     */\n    BitList<Invoker<T>> route(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder)\n            throws RpcException;\n\n    /**\n     * To decide whether this router need to execute every time an RPC comes or should only execute when addresses or\n     * rule change.\n     *\n     * @return true if the router need to execute every time.\n     */\n    boolean isRuntime();\n\n    /**\n     * To decide whether this router should take effect when none of the invoker can match the router rule, which\n     * means the {@link #route(BitList, URL, Invocation, boolean, Holder)} would be empty. Most of time, most router implementation would\n     * default this value to false.\n     *\n     * @return true to execute if none of invokers matches the current router\n     */\n    boolean isForce();\n\n    /**\n     * Notify the router the invoker list. Invoker list may change from time to time. This method gives the router a\n     * chance to prepare before {@link StateRouter#route(BitList, URL, Invocation, boolean, Holder)} gets called.\n     * No need to notify next node.\n     *\n     * @param invokers invoker list\n     */\n    void notify(BitList<Invoker<T>> invokers);\n\n    /**\n     * Build Router's Current State Snapshot for QoS\n     *\n     * @return Current State\n     */\n    String buildSnapshot();\n\n    default void stop() {\n        // do nothing by default\n    }\n\n    /**\n     * Notify next router node to current router.\n     *\n     * @param nextRouter next router node\n     */\n    void setNextRouter(StateRouter<T> nextRouter);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/StateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.state;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface StateRouterFactory {\n    /**\n     * Create state router.\n     *\n     * @param url url\n     * @return router instance\n     * @since 3.0\n     */\n    @Adaptive(CommonConstants.PROTOCOL_KEY)\n    <T> StateRouter<T> getRouter(Class<T> interfaceClass, URL url);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/TailStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.state;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\n\npublic class TailStateRouter<T> implements StateRouter<T> {\n    private static final TailStateRouter INSTANCE = new TailStateRouter();\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> TailStateRouter<T> getInstance() {\n        return INSTANCE;\n    }\n\n    private TailStateRouter() {}\n\n    @Override\n    public void setNextRouter(StateRouter<T> nextRouter) {}\n\n    @Override\n    public URL getUrl() {\n        return null;\n    }\n\n    @Override\n    public BitList<Invoker<T>> route(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder)\n            throws RpcException {\n        return invokers;\n    }\n\n    @Override\n    public boolean isRuntime() {\n        return false;\n    }\n\n    @Override\n    public boolean isForce() {\n        return false;\n    }\n\n    @Override\n    public void notify(BitList<Invoker<T>> invokers) {}\n\n    @Override\n    public String buildSnapshot() {\n        return \"TailStateRouter End\";\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.tag;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;\nimport org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule;\nimport org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser;\n\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_TAG_ROUTE_EMPTY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_TAG_ROUTE_INVALID;\nimport static org.apache.dubbo.rpc.Constants.FORCE_USE_TAG;\n\n/**\n * TagRouter, \"application.tag-router\"\n */\npublic class TagStateRouter<T> extends AbstractStateRouter<T> implements ConfigurationListener {\n    public static final String NAME = \"TAG_ROUTER\";\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(TagStateRouter.class);\n    private static final String RULE_SUFFIX = \".tag-router\";\n    public static final char TAG_SEPERATOR = '|';\n\n    private volatile TagRouterRule tagRouterRule;\n    private String application;\n    private volatile BitList<Invoker<T>> invokers = BitList.emptyList();\n\n    public TagStateRouter(URL url) {\n        super(url);\n    }\n\n    @Override\n    public synchronized void process(ConfigChangedEvent event) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Notification of tag rule, change type is: \" + event.getChangeType() + \", raw rule is:\\n \"\n                    + event.getContent());\n        }\n\n        try {\n            if (event.getChangeType().equals(ConfigChangeType.DELETED)) {\n                this.tagRouterRule = null;\n            } else {\n                TagRouterRule rule = TagRuleParser.parse(event.getContent());\n                rule.init(this);\n                this.tagRouterRule = rule;\n            }\n        } catch (Exception e) {\n            logger.error(\n                    CLUSTER_TAG_ROUTE_INVALID,\n                    \"Failed to parse the raw tag router rule\",\n                    \"\",\n                    \"Failed to parse the raw tag router rule and it will not take effect, please check if the \"\n                            + \"rule matches with the template, the raw rule is:\\n \",\n                    e);\n        }\n    }\n\n    @Override\n    public BitList<Invoker<T>> doRoute(\n            BitList<Invoker<T>> invokers,\n            URL url,\n            Invocation invocation,\n            boolean needToPrintMessage,\n            Holder<RouterSnapshotNode<T>> nodeHolder,\n            Holder<String> messageHolder)\n            throws RpcException {\n        if (CollectionUtils.isEmpty(invokers)) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Directly Return. Reason: Invokers from previous router is empty.\");\n            }\n            return invokers;\n        }\n\n        String tag = StringUtils.isEmpty(invocation.getAttachment(TAG_KEY))\n                ? url.getParameter(TAG_KEY)\n                : invocation.getAttachment(TAG_KEY);\n        if (ANY_VALUE.equals(tag)) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Skip tag routing. Reason: wildcard tag request\");\n            }\n            return invokers;\n        }\n\n        // since the rule can be changed by config center, we should copy one to use.\n        final TagRouterRule tagRouterRuleCopy = tagRouterRule;\n        if (tagRouterRuleCopy == null || !tagRouterRuleCopy.isValid() || !tagRouterRuleCopy.isEnabled()) {\n            if (needToPrintMessage) {\n                messageHolder.set(\"Disable Tag Router. Reason: tagRouterRule is invalid or disabled\");\n            }\n            return filterUsingStaticTag(invokers, url, invocation);\n        }\n\n        BitList<Invoker<T>> result = invokers;\n\n        // if we are requesting for a Provider with a specific tag\n        if (StringUtils.isNotEmpty(tag)) {\n            Map<String, Set<String>> tagnameToAddresses = tagRouterRuleCopy.getTagnameToAddresses();\n            Set<String> addresses = selectAddressByTagLevel(tagnameToAddresses, tag, isForceUseTag(invocation));\n            // filter by dynamic tag group first\n            if (addresses != null) { // null means tag not set\n                result = filterInvoker(invokers, invoker -> addressMatches(invoker.getUrl(), addresses));\n                // if result is not null OR it's null but force=true, return result directly\n                if (CollectionUtils.isNotEmpty(result) || tagRouterRuleCopy.isForce()) {\n                    if (needToPrintMessage) {\n                        messageHolder.set(\n                                \"Use tag \" + tag + \" to route. Reason: result is not null OR it's null but force=true\");\n                    }\n                    return result;\n                }\n            } else {\n                // dynamic tag group doesn't have any item about the requested app OR it's null after filtered by\n                // dynamic tag group but force=false. check static tag\n                result = filterInvoker(\n                        invokers, invoker -> tag.equals(invoker.getUrl().getParameter(TAG_KEY)));\n            }\n            // If there's no tagged providers that can match the current tagged request. force.tag is set by default\n            // to false, which means it will invoke any providers without a tag unless it's explicitly disallowed.\n            if (CollectionUtils.isNotEmpty(result) || isForceUseTag(invocation)) {\n                if (needToPrintMessage) {\n                    messageHolder.set(\"Use tag \" + tag\n                            + \" to route. Reason: result is not empty or ForceUseTag key is true in invocation\");\n                }\n                return result;\n            }\n            // FAILOVER: return all Providers without any tags.\n            else {\n                BitList<Invoker<T>> tmp = filterInvoker(\n                        invokers, invoker -> addressNotMatches(invoker.getUrl(), tagRouterRuleCopy.getAddresses()));\n                if (needToPrintMessage) {\n                    messageHolder.set(\"FAILOVER: return all Providers without any tags\");\n                }\n                return filterInvoker(\n                        tmp, invoker -> StringUtils.isEmpty(invoker.getUrl().getParameter(TAG_KEY)));\n            }\n        } else {\n            // List<String> addresses = tagRouterRule.filter(providerApp);\n            // return all addresses in dynamic tag group.\n            Set<String> addresses = tagRouterRuleCopy.getAddresses();\n            if (CollectionUtils.isNotEmpty(addresses)) {\n                result = filterInvoker(invokers, invoker -> addressNotMatches(invoker.getUrl(), addresses));\n                // 1. all addresses are in dynamic tag group, return empty list.\n                if (CollectionUtils.isEmpty(result)) {\n                    if (needToPrintMessage) {\n                        messageHolder.set(\"all addresses are in dynamic tag group, return empty list\");\n                    }\n                    return result;\n                }\n                // 2. if there are some addresses that are not in any dynamic tag group, continue to filter using the\n                // static tag group.\n            }\n            if (needToPrintMessage) {\n                messageHolder.set(\"filter using the static tag group\");\n            }\n            return filterInvoker(result, invoker -> {\n                String localTag = invoker.getUrl().getParameter(TAG_KEY);\n                return StringUtils.isEmpty(localTag);\n            });\n        }\n    }\n\n    /**\n     * If there's no dynamic tag rule being set, use static tag in URL.\n     * <p>\n     * A typical scenario is a Consumer using version 2.7.x calls Providers using version 2.6.x or lower,\n     * the Consumer should always respect the tag in provider URL regardless of whether a dynamic tag rule has been set to it or not.\n     * <p>\n     * TODO, to guarantee consistent behavior of interoperability between 2.6- and 2.7+, this method should has the same logic with the TagRouter in 2.6.x.\n     *\n     * @param invokers\n     * @param url\n     * @param invocation\n     * @param <T>\n     * @return\n     */\n    private <T> BitList<Invoker<T>> filterUsingStaticTag(BitList<Invoker<T>> invokers, URL url, Invocation invocation) {\n        BitList<Invoker<T>> result;\n        // Dynamic param\n        String tag = StringUtils.isEmpty(invocation.getAttachment(TAG_KEY))\n                ? url.getParameter(TAG_KEY)\n                : invocation.getAttachment(TAG_KEY);\n        // Tag request\n        if (!StringUtils.isEmpty(tag)) {\n            result = filterInvoker(\n                    invokers,\n                    invoker ->\n                            ANY_VALUE.equals(tag) || tag.equals(invoker.getUrl().getParameter(TAG_KEY)));\n            if (CollectionUtils.isEmpty(result) && !isForceUseTag(invocation)) {\n                result = filterInvoker(\n                        invokers,\n                        invoker -> StringUtils.isEmpty(invoker.getUrl().getParameter(TAG_KEY)));\n            }\n        } else {\n            result = filterInvoker(\n                    invokers, invoker -> StringUtils.isEmpty(invoker.getUrl().getParameter(TAG_KEY)));\n        }\n        return result;\n    }\n\n    @Override\n    public boolean isRuntime() {\n        return tagRouterRule != null && tagRouterRule.isRuntime();\n    }\n\n    @Override\n    public boolean isForce() {\n        // FIXME\n        return tagRouterRule != null && tagRouterRule.isForce();\n    }\n\n    private boolean isForceUseTag(Invocation invocation) {\n        return Boolean.parseBoolean(\n                invocation.getAttachment(FORCE_USE_TAG, this.getUrl().getParameter(FORCE_USE_TAG, \"false\")));\n    }\n\n    private <T> BitList<Invoker<T>> filterInvoker(BitList<Invoker<T>> invokers, Predicate<Invoker<T>> predicate) {\n        if (invokers.stream().allMatch(predicate)) {\n            return invokers;\n        }\n\n        BitList<Invoker<T>> newInvokers = invokers.clone();\n        newInvokers.removeIf(invoker -> !predicate.test(invoker));\n\n        return newInvokers;\n    }\n\n    private boolean addressMatches(URL url, Set<String> addresses) {\n        return addresses != null && checkAddressMatch(addresses, url.getHost(), url.getPort());\n    }\n\n    private boolean addressNotMatches(URL url, Set<String> addresses) {\n        return addresses == null || !checkAddressMatch(addresses, url.getHost(), url.getPort());\n    }\n\n    private boolean checkAddressMatch(Set<String> addresses, String host, int port) {\n        for (String address : addresses) {\n            try {\n                if (NetUtils.matchIpExpression(address, host, port)) {\n                    return true;\n                }\n                if ((ANYHOST_VALUE + \":\" + port).equals(address)) {\n                    return true;\n                }\n            } catch (Exception e) {\n                logger.error(\n                        CLUSTER_TAG_ROUTE_INVALID,\n                        \"tag route address is invalid\",\n                        \"\",\n                        \"The format of ip address is invalid in tag route. Address :\" + address,\n                        e);\n            }\n        }\n        return false;\n    }\n\n    public void setApplication(String app) {\n        this.application = app;\n    }\n\n    @Override\n    public void notify(BitList<Invoker<T>> invokers) {\n        this.invokers = invokers;\n        if (CollectionUtils.isEmpty(invokers)) {\n            return;\n        }\n\n        Invoker<T> invoker = invokers.get(0);\n        URL url = invoker.getUrl();\n        String providerApplication = url.getRemoteApplication();\n\n        if (StringUtils.isEmpty(providerApplication)) {\n            logger.error(\n                    CLUSTER_TAG_ROUTE_EMPTY,\n                    \"tag router get providerApplication is empty\",\n                    \"\",\n                    \"TagRouter must getConfig from or subscribe to a specific application, but the application \"\n                            + \"in this TagRouter is not specified.\");\n            return;\n        }\n\n        synchronized (this) {\n            if (!providerApplication.equals(application)) {\n                if (StringUtils.isNotEmpty(application)) {\n                    this.getRuleRepository().removeListener(application + RULE_SUFFIX, this);\n                }\n                String key = providerApplication + RULE_SUFFIX;\n                this.getRuleRepository().addListener(key, this);\n                application = providerApplication;\n                String rawRule = this.getRuleRepository().getRule(key, DynamicConfiguration.DEFAULT_GROUP);\n                if (StringUtils.isNotEmpty(rawRule)) {\n                    this.process(new ConfigChangedEvent(key, DynamicConfiguration.DEFAULT_GROUP, rawRule));\n                }\n            } else {\n                if (this.tagRouterRule != null) {\n                    TagRouterRule newRule = TagRuleParser.parse(this.tagRouterRule.getRawRule());\n                    newRule.init(this);\n                    this.tagRouterRule = newRule;\n                }\n            }\n        }\n    }\n\n    public BitList<Invoker<T>> getInvokers() {\n        return invokers;\n    }\n\n    @Override\n    public void stop() {\n        if (StringUtils.isNotEmpty(application)) {\n            this.getRuleRepository().removeListener(application + RULE_SUFFIX, this);\n        }\n    }\n\n    // for testing purpose\n    public void setTagRouterRule(TagRouterRule tagRouterRule) {\n        this.tagRouterRule = tagRouterRule;\n    }\n\n    /**\n     * select addresses by tag with level\n     * <p>\n     * example:\n     * selector=beta|team1|partner1\n     * step1.select tagAddresses with selector=beta|team1|partner1, if result is empty, then run step2\n     * step2.select tagAddresses with selector=beta|team1, if result is empty, then run step3\n     * step3.select tagAddresses with selector=beta, if result is empty, result is null\n     * </p>\n     *\n     * @param tagAddresses\n     * @param tagSelector  eg: beta|team1|partner1\n     * @return\n     */\n    public static Set<String> selectAddressByTagLevel(\n            Map<String, Set<String>> tagAddresses, String tagSelector, boolean isForce) {\n        if (isForce || StringUtils.isNotContains(tagSelector, TAG_SEPERATOR)) {\n            return tagAddresses.get(tagSelector);\n        }\n        String[] selectors = StringUtils.split(tagSelector, TAG_SEPERATOR);\n        for (int i = selectors.length; i > 0; i--) {\n            String selectorTmp = StringUtils.join(selectors, TAG_SEPERATOR, 0, i);\n            Set<String> addresses = tagAddresses.get(selectorTmp);\n            if (CollectionUtils.isNotEmpty(addresses)) {\n                return addresses;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.tag;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.router.state.CacheableStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\n\n/**\n * Tag router factory\n */\n@Activate(order = 100)\npublic class TagStateRouterFactory extends CacheableStateRouterFactory {\n\n    public static final String NAME = \"tag\";\n\n    @Override\n    protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {\n        return new TagStateRouter<>(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/model/ParamMatch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.tag.model;\n\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.StringMatch;\n\npublic class ParamMatch {\n    private String key;\n    private StringMatch value;\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public StringMatch getValue() {\n        return value;\n    }\n\n    public void setValue(StringMatch value) {\n        this.value = value;\n    }\n\n    public boolean isMatch(String input) {\n        if (getValue() != null) {\n            return getValue().isMatch(input);\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/model/Tag.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.tag.model;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.PojoUtils;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RULE_PARSING;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_VERSION_V30;\n\npublic class Tag {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(Tag.class);\n\n    private String name;\n    private List<ParamMatch> match;\n    private List<String> addresses;\n\n    @SuppressWarnings(\"unchecked\")\n    public static Tag parseFromMap(Map<String, Object> map, String version) {\n        Tag tag = new Tag();\n        tag.setName((String) map.get(\"name\"));\n\n        if (version != null && version.startsWith(RULE_VERSION_V30)) {\n            if (map.get(\"match\") != null) {\n                tag.setMatch(((List<Map<String, Object>>) map.get(\"match\"))\n                        .stream()\n                                .map((objectMap) -> {\n                                    try {\n                                        return PojoUtils.mapToPojo(objectMap, ParamMatch.class);\n                                    } catch (ReflectiveOperationException e) {\n                                        logger.error(\n                                                CLUSTER_FAILED_RULE_PARSING,\n                                                \" Failed to parse tag rule \",\n                                                String.valueOf(objectMap),\n                                                \"Error occurred when parsing rule component.\",\n                                                e);\n                                    }\n                                    return null;\n                                })\n                                .collect(Collectors.toList()));\n            } else {\n                logger.warn(\n                        CLUSTER_FAILED_RULE_PARSING,\n                        \"\",\n                        String.valueOf(map),\n                        \"It's recommended to use 'match' instead of 'addresses' for v3.0 tag rule.\");\n            }\n        }\n\n        Object addresses = map.get(\"addresses\");\n        if (addresses != null && List.class.isAssignableFrom(addresses.getClass())) {\n            tag.setAddresses(\n                    ((List<Object>) addresses).stream().map(String::valueOf).collect(Collectors.toList()));\n        }\n\n        return tag;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public List<String> getAddresses() {\n        return addresses;\n    }\n\n    public void setAddresses(List<String> addresses) {\n        this.addresses = addresses;\n    }\n\n    public List<ParamMatch> getMatch() {\n        return match;\n    }\n\n    public void setMatch(List<ParamMatch> match) {\n        this.match = match;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/model/TagRouterRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.tag.model;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.tag.TagStateRouter;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_VERSION_V30;\nimport static org.apache.dubbo.rpc.cluster.Constants.TAGS_KEY;\n\n/**\n * %YAML1.2\n * ---\n * force: true\n * runtime: false\n * enabled: true\n * priority: 1\n * key: demo-provider\n * tags:\n * - name: tag1\n * addresses: [ip1, ip2]\n * - name: tag2\n * addresses: [ip3, ip4]\n * ...\n */\npublic class TagRouterRule extends AbstractRouterRule {\n    private List<Tag> tags;\n\n    private final Map<String, Set<String>> addressToTagnames = new HashMap<>();\n    private final Map<String, Set<String>> tagnameToAddresses = new HashMap<>();\n\n    @SuppressWarnings(\"unchecked\")\n    public static TagRouterRule parseFromMap(Map<String, Object> map) {\n        TagRouterRule tagRouterRule = new TagRouterRule();\n        tagRouterRule.parseFromMap0(map);\n\n        Object tags = map.get(TAGS_KEY);\n        if (tags != null && List.class.isAssignableFrom(tags.getClass())) {\n            tagRouterRule.setTags(((List<Map<String, Object>>) tags)\n                    .stream()\n                            .map(objMap -> Tag.parseFromMap(objMap, tagRouterRule.getVersion()))\n                            .collect(Collectors.toList()));\n        }\n\n        return tagRouterRule;\n    }\n\n    public void init(TagStateRouter<?> router) {\n        if (!isValid()) {\n            return;\n        }\n\n        BitList<? extends Invoker<?>> invokers = router.getInvokers();\n\n        // for tags with 'addresses` field set and 'match' field not set\n        tags.stream()\n                .filter(tag -> CollectionUtils.isNotEmpty(tag.getAddresses()))\n                .forEach(tag -> {\n                    tagnameToAddresses.put(tag.getName(), new HashSet<>(tag.getAddresses()));\n                    tag.getAddresses().forEach(addr -> {\n                        Set<String> tagNames = addressToTagnames.computeIfAbsent(addr, k -> new HashSet<>());\n                        tagNames.add(tag.getName());\n                    });\n                });\n\n        if (this.getVersion() != null && this.getVersion().startsWith(RULE_VERSION_V30)) {\n            // for tags with 'match` field set and 'addresses' field not set\n            if (CollectionUtils.isNotEmpty(invokers)) {\n                tags.stream()\n                        .filter(tag -> CollectionUtils.isEmpty(tag.getAddresses()))\n                        .forEach(tag -> {\n                            Set<String> addresses = new HashSet<>();\n                            List<ParamMatch> paramMatchers = tag.getMatch();\n                            invokers.forEach(invoker -> {\n                                boolean isMatch = true;\n                                for (ParamMatch matcher : paramMatchers) {\n                                    if (!matcher.isMatch(invoker.getUrl().getOriginalParameter(matcher.getKey()))) {\n                                        isMatch = false;\n                                        break;\n                                    }\n                                }\n                                if (isMatch) {\n                                    addresses.add(invoker.getUrl().getAddress());\n                                }\n                            });\n                            if (CollectionUtils.isNotEmpty(addresses)) { // null means tag not set\n                                tagnameToAddresses.put(tag.getName(), addresses);\n                            }\n                        });\n            }\n        }\n    }\n\n    public Set<String> getAddresses() {\n        return tagnameToAddresses.entrySet().stream()\n                .filter(entry -> CollectionUtils.isNotEmpty(entry.getValue()))\n                .flatMap(entry -> entry.getValue().stream())\n                .collect(Collectors.toSet());\n    }\n\n    public List<String> getTagNames() {\n        return tags.stream().map(Tag::getName).collect(Collectors.toList());\n    }\n\n    public Map<String, Set<String>> getAddressToTagnames() {\n        return addressToTagnames;\n    }\n\n    public Map<String, Set<String>> getTagnameToAddresses() {\n        return tagnameToAddresses;\n    }\n\n    public List<Tag> getTags() {\n        return tags;\n    }\n\n    public void setTags(List<Tag> tags) {\n        this.tags = tags;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/model/TagRuleParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.tag.model;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\n\nimport java.util.Map;\n\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\n\n/**\n * Parse raw rule into structured tag rule\n */\npublic class TagRuleParser {\n\n    public static TagRouterRule parse(String rawRule) {\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Map<String, Object> map = yaml.load(rawRule);\n        TagRouterRule rule = TagRouterRule.parseFromMap(map);\n        rule.setRawRule(rawRule);\n        if (CollectionUtils.isEmpty(rule.getTags())) {\n            rule.setValid(false);\n        }\n\n        return rule;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.profiler.ProfilerSwitch;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.InvocationProfilerUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcServiceContext;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_LOADBALANCE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RESELECT_COUNT;\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLE_CONNECTIVITY_VALIDATION;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RESELECT_COUNT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RESELECT_INVOKERS;\nimport static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_AVAILABLE_CHECK_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_STICKY_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_CLUSTER_AVAILABLE_CHECK;\nimport static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_CLUSTER_STICKY;\n\n/**\n * AbstractClusterInvoker\n */\npublic abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(AbstractClusterInvoker.class);\n\n    protected Directory<T> directory;\n\n    protected boolean availableCheck;\n\n    private volatile int reselectCount = DEFAULT_RESELECT_COUNT;\n\n    private volatile boolean enableConnectivityValidation = true;\n\n    private final AtomicBoolean destroyed = new AtomicBoolean(false);\n\n    private volatile Invoker<T> stickyInvoker = null;\n\n    public AbstractClusterInvoker() {}\n\n    public AbstractClusterInvoker(Directory<T> directory) {\n        this(directory, directory.getUrl());\n    }\n\n    public AbstractClusterInvoker(Directory<T> directory, URL url) {\n        if (directory == null) {\n            throw new IllegalArgumentException(\"service directory == null\");\n        }\n\n        this.directory = directory;\n        // sticky: invoker.isAvailable() should always be checked before using when availablecheck is true.\n        this.availableCheck = url.getParameter(CLUSTER_AVAILABLE_CHECK_KEY, DEFAULT_CLUSTER_AVAILABLE_CHECK);\n        Configuration configuration = ConfigurationUtils.getGlobalConfiguration(url.getOrDefaultModuleModel());\n        this.reselectCount = configuration.getInt(RESELECT_COUNT, DEFAULT_RESELECT_COUNT);\n        this.enableConnectivityValidation = configuration.getBoolean(ENABLE_CONNECTIVITY_VALIDATION, true);\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return getDirectory().getInterface();\n    }\n\n    @Override\n    public URL getUrl() {\n        return getDirectory().getConsumerUrl();\n    }\n\n    @Override\n    public URL getRegistryUrl() {\n        return getDirectory().getUrl();\n    }\n\n    @Override\n    public boolean isAvailable() {\n        Invoker<T> invoker = stickyInvoker;\n        if (invoker != null) {\n            return invoker.isAvailable();\n        }\n        return getDirectory().isAvailable();\n    }\n\n    @Override\n    public Directory<T> getDirectory() {\n        return directory;\n    }\n\n    @Override\n    public void destroy() {\n        if (destroyed.compareAndSet(false, true)) {\n            getDirectory().destroy();\n        }\n    }\n\n    @Override\n    public boolean isDestroyed() {\n        return destroyed.get();\n    }\n\n    /**\n     * Select a invoker using loadbalance policy.</br>\n     * a) Firstly, select an invoker using loadbalance. If this invoker is in previously selected list, or,\n     * if this invoker is unavailable, then continue step b (reselect), otherwise return the first selected invoker</br>\n     * <p>\n     * b) Reselection, the validation rule for reselection: selected > available. This rule guarantees that\n     * the selected invoker has the minimum chance to be one in the previously selected list, and also\n     * guarantees this invoker is available.\n     *\n     * @param loadbalance load balance policy\n     * @param invocation  invocation\n     * @param invokers    invoker candidates\n     * @param selected    exclude selected invokers or not\n     * @return the invoker which will final to do invoke.\n     * @throws RpcException exception\n     */\n    protected Invoker<T> select(\n            LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected)\n            throws RpcException {\n\n        if (CollectionUtils.isEmpty(invokers)) {\n            return null;\n        }\n        String methodName = invocation == null ? StringUtils.EMPTY_STRING : RpcUtils.getMethodName(invocation);\n\n        boolean sticky =\n                invokers.get(0).getUrl().getMethodParameter(methodName, CLUSTER_STICKY_KEY, DEFAULT_CLUSTER_STICKY);\n\n        // ignore overloaded method\n        if (stickyInvoker != null && !invokers.contains(stickyInvoker)) {\n            stickyInvoker = null;\n        }\n        // ignore concurrency problem\n        if (sticky && stickyInvoker != null && (selected == null || !selected.contains(stickyInvoker))) {\n            if (availableCheck && stickyInvoker.isAvailable()) {\n                return stickyInvoker;\n            }\n        }\n\n        Invoker<T> invoker = doSelect(loadbalance, invocation, invokers, selected);\n\n        if (sticky) {\n            stickyInvoker = invoker;\n        }\n\n        return invoker;\n    }\n\n    private Invoker<T> doSelect(\n            LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected)\n            throws RpcException {\n\n        if (CollectionUtils.isEmpty(invokers)) {\n            return null;\n        }\n        if (invokers.size() == 1) {\n            Invoker<T> tInvoker = invokers.get(0);\n            checkShouldInvalidateInvoker(tInvoker);\n            return tInvoker;\n        }\n        Invoker<T> invoker = loadbalance.select(invokers, getUrl(), invocation);\n\n        // If the `invoker` is in the  `selected` or invoker is unavailable && availablecheck is true, reselect.\n        boolean isSelected = selected != null && selected.contains(invoker);\n        boolean isUnavailable = availableCheck && !invoker.isAvailable() && getUrl() != null;\n\n        if (isUnavailable) {\n            invalidateInvoker(invoker);\n        }\n        if (isSelected || isUnavailable) {\n            try {\n                Invoker<T> rInvoker = reselect(loadbalance, invocation, invokers, selected, availableCheck);\n                if (rInvoker != null) {\n                    invoker = rInvoker;\n                } else {\n                    // Check the index of current selected invoker, if it's not the last one, choose the one at index+1.\n                    int index = invokers.indexOf(invoker);\n                    try {\n                        // Avoid collision\n                        invoker = invokers.get((index + 1) % invokers.size());\n                    } catch (Exception e) {\n                        logger.warn(\n                                CLUSTER_FAILED_RESELECT_INVOKERS,\n                                \"select invokers exception\",\n                                \"\",\n                                e.getMessage() + \" may because invokers list dynamic change, ignore.\",\n                                e);\n                    }\n                }\n            } catch (Throwable t) {\n                logger.error(\n                        CLUSTER_FAILED_RESELECT_INVOKERS,\n                        \"failed to reselect invokers\",\n                        \"\",\n                        \"cluster reselect fail reason is :\" + t.getMessage()\n                                + \" if can not solve, you can set cluster.availablecheck=false in url\",\n                        t);\n            }\n        }\n\n        return invoker;\n    }\n\n    /**\n     * Reselect, use invokers not in `selected` first, if all invokers are in `selected`,\n     * just pick an available one using loadbalance policy.\n     *\n     * @param loadbalance    load balance policy\n     * @param invocation     invocation\n     * @param invokers       invoker candidates\n     * @param selected       exclude selected invokers or not\n     * @param availableCheck check invoker available if true\n     * @return the reselect result to do invoke\n     * @throws RpcException exception\n     */\n    private Invoker<T> reselect(\n            LoadBalance loadbalance,\n            Invocation invocation,\n            List<Invoker<T>> invokers,\n            List<Invoker<T>> selected,\n            boolean availableCheck)\n            throws RpcException {\n\n        // Allocating one in advance, this list is certain to be used.\n        List<Invoker<T>> reselectInvokers = new ArrayList<>(Math.min(invokers.size(), reselectCount));\n\n        // 1. Try picking some invokers not in `selected`.\n        //    1.1. If all selectable invokers' size is smaller than reselectCount, just add all\n        //    1.2. If all selectable invokers' size is greater than reselectCount, randomly select reselectCount.\n        //            The result size of invokers might smaller than reselectCount due to disAvailable or de-duplication\n        // (might be zero).\n        //            This means there is probable that reselectInvokers is empty however all invoker list may contain\n        // available invokers.\n        //            Use reselectCount can reduce retry times if invokers' size is huge, which may lead to long time\n        // hang up.\n        if (reselectCount >= invokers.size()) {\n            for (Invoker<T> invoker : invokers) {\n                // check if available\n                if (availableCheck && !invoker.isAvailable()) {\n                    // add to invalidate invoker\n                    invalidateInvoker(invoker);\n                    continue;\n                }\n\n                if (selected == null || !selected.contains(invoker)) {\n                    reselectInvokers.add(invoker);\n                }\n            }\n        } else {\n            for (int i = 0; i < reselectCount; i++) {\n                // select one randomly\n                Invoker<T> invoker = invokers.get(ThreadLocalRandom.current().nextInt(invokers.size()));\n                // check if available\n                if (availableCheck && !invoker.isAvailable()) {\n                    // add to invalidate invoker\n                    invalidateInvoker(invoker);\n                    continue;\n                }\n                // de-duplication\n                if (selected == null || !selected.contains(invoker) || !reselectInvokers.contains(invoker)) {\n                    reselectInvokers.add(invoker);\n                }\n            }\n        }\n\n        // 2. Use loadBalance to select one (all the reselectInvokers are available)\n        if (!reselectInvokers.isEmpty()) {\n            return loadbalance.select(reselectInvokers, getUrl(), invocation);\n        }\n\n        // 3. reselectInvokers is empty. Unable to find at least one available invoker.\n        //    Re-check all the selected invokers. If some in the selected list are available, add to reselectInvokers.\n        if (selected != null) {\n            for (Invoker<T> invoker : selected) {\n                if ((invoker.isAvailable()) // available first\n                        && !reselectInvokers.contains(invoker)) {\n                    reselectInvokers.add(invoker);\n                }\n            }\n        }\n\n        // 4. If reselectInvokers is not empty after re-check.\n        //    Pick an available invoker using loadBalance policy\n        if (!reselectInvokers.isEmpty()) {\n            return loadbalance.select(reselectInvokers, getUrl(), invocation);\n        }\n\n        // 5. No invoker match, return null.\n        return null;\n    }\n\n    private void checkShouldInvalidateInvoker(Invoker<T> invoker) {\n        if (availableCheck && !invoker.isAvailable()) {\n            invalidateInvoker(invoker);\n        }\n    }\n\n    private void invalidateInvoker(Invoker<T> invoker) {\n        if (enableConnectivityValidation) {\n            if (getDirectory() != null) {\n                getDirectory().addInvalidateInvoker(invoker);\n            }\n        }\n    }\n\n    @Override\n    public Result invoke(final Invocation invocation) throws RpcException {\n        checkWhetherDestroyed();\n\n        // binding attachments into invocation.\n        //        Map<String, Object> contextAttachments = RpcContext.getClientAttachment().getObjectAttachments();\n        //        if (contextAttachments != null && contextAttachments.size() != 0) {\n        //            ((RpcInvocation) invocation).addObjectAttachmentsIfAbsent(contextAttachments);\n        //        }\n\n        InvocationProfilerUtils.enterDetailProfiler(invocation, () -> \"Router route.\");\n        List<Invoker<T>> invokers = list(invocation);\n        InvocationProfilerUtils.releaseDetailProfiler(invocation);\n\n        checkInvokers(invokers, invocation);\n\n        LoadBalance loadbalance = initLoadBalance(invokers, invocation);\n        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);\n\n        InvocationProfilerUtils.enterDetailProfiler(\n                invocation, () -> \"Cluster \" + this.getClass().getName() + \" invoke.\");\n        try {\n            return doInvoke(invocation, invokers, loadbalance);\n        } finally {\n            InvocationProfilerUtils.releaseDetailProfiler(invocation);\n        }\n    }\n\n    protected void checkWhetherDestroyed() {\n        if (destroyed.get()) {\n            throw new RpcException(\n                    \"Rpc cluster invoker for \" + getInterface() + \" on consumer \" + NetUtils.getLocalHost()\n                            + \" use dubbo version \" + Version.getVersion()\n                            + \" is now destroyed! Can not invoke any more.\");\n        }\n    }\n\n    @Override\n    public String toString() {\n        return getInterface() + \" -> \" + getUrl().toString();\n    }\n\n    protected void checkInvokers(List<Invoker<T>> invokers, Invocation invocation) {\n        if (CollectionUtils.isEmpty(invokers)) {\n            throw new RpcException(\n                    RpcException.NO_INVOKER_AVAILABLE_AFTER_FILTER,\n                    \"Failed to invoke the method \"\n                            + RpcUtils.getMethodName(invocation) + \" in the service \"\n                            + getInterface().getName()\n                            + \". No provider available for the service \"\n                            + getDirectory().getConsumerUrl().getServiceKey()\n                            + \" from registry \" + getDirectory()\n                            + \" on the consumer \" + NetUtils.getLocalHost()\n                            + \" using the dubbo version \" + Version.getVersion()\n                            + \". Please check if the providers have been started and registered.\");\n        }\n    }\n\n    protected Result invokeWithContext(Invoker<T> invoker, Invocation invocation) {\n        Invoker<T> originInvoker = setContext(invoker);\n        Result result;\n        try {\n            if (ProfilerSwitch.isEnableSimpleProfiler()) {\n                InvocationProfilerUtils.enterProfiler(\n                        invocation,\n                        \"Invoker invoke. Target Address: \" + invoker.getUrl().getAddress());\n            }\n            setRemote(invoker, invocation);\n            result = invoker.invoke(invocation);\n        } finally {\n            clearContext(originInvoker);\n            InvocationProfilerUtils.releaseSimpleProfiler(invocation);\n        }\n        return result;\n    }\n\n    /**\n     * Set the remoteAddress and remoteApplicationName so that filter can get them.\n     *\n     */\n    private void setRemote(Invoker<?> invoker, Invocation invocation) {\n        invocation.addInvokedInvoker(invoker);\n        RpcServiceContext serviceContext = RpcContext.getServiceContext();\n        serviceContext.setRemoteAddress(invoker.getUrl().toInetSocketAddress());\n        serviceContext.setRemoteApplicationName(invoker.getUrl().getRemoteApplication());\n    }\n\n    /**\n     * When using a thread pool to fork a child thread, ThreadLocal cannot be passed.\n     * In this scenario, please use the invokeWithContextAsync method.\n     *\n     * @return\n     */\n    protected Result invokeWithContextAsync(Invoker<T> invoker, Invocation invocation, URL consumerUrl) {\n        Invoker<T> originInvoker = setContext(invoker, consumerUrl);\n        Result result;\n        try {\n            result = invoker.invoke(invocation);\n        } finally {\n            clearContext(originInvoker);\n        }\n        return result;\n    }\n\n    protected abstract Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n            throws RpcException;\n\n    protected List<Invoker<T>> list(Invocation invocation) throws RpcException {\n        return getDirectory().list(invocation);\n    }\n\n    /**\n     * Init LoadBalance.\n     * <p>\n     * if invokers is not empty, init from the first invoke's url and invocation\n     * if invokes is empty, init a default LoadBalance(RandomLoadBalance)\n     * </p>\n     *\n     * @param invokers   invokers\n     * @param invocation invocation\n     * @return LoadBalance instance. if not need init, return null.\n     */\n    protected LoadBalance initLoadBalance(List<Invoker<T>> invokers, Invocation invocation) {\n        ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(invocation.getModuleModel());\n        if (CollectionUtils.isNotEmpty(invokers)) {\n            return applicationModel\n                    .getExtensionLoader(LoadBalance.class)\n                    .getExtension(invokers.get(0)\n                            .getUrl()\n                            .getMethodParameter(\n                                    RpcUtils.getMethodName(invocation), LOADBALANCE_KEY, DEFAULT_LOADBALANCE));\n        } else {\n            return applicationModel.getExtensionLoader(LoadBalance.class).getExtension(DEFAULT_LOADBALANCE);\n        }\n    }\n\n    private Invoker<T> setContext(Invoker<T> invoker) {\n        return setContext(invoker, null);\n    }\n\n    private Invoker<T> setContext(Invoker<T> invoker, URL consumerUrl) {\n        RpcServiceContext context = RpcContext.getServiceContext();\n        Invoker<?> originInvoker = context.getInvoker();\n        context.setInvoker(invoker)\n                .setConsumerUrl(\n                        null != consumerUrl\n                                ? consumerUrl\n                                : RpcContext.getServiceContext().getConsumerUrl());\n        return (Invoker<T>) originInvoker;\n    }\n\n    private void clearContext(Invoker<T> invoker) {\n        // do nothing\n        RpcContext context = RpcContext.getServiceContext();\n        context.setInvoker(invoker);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;\n\n/**\n * AvailableCluster\n *\n */\npublic class AvailableCluster extends AbstractCluster {\n\n    public static final String NAME = \"available\";\n\n    @Override\n    public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {\n        return new AvailableClusterInvoker<>(directory);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\n\nimport java.util.List;\n\n/**\n * AvailableClusterInvoker\n *\n */\npublic class AvailableClusterInvoker<T> extends AbstractClusterInvoker<T> {\n\n    public AvailableClusterInvoker(Directory<T> directory) {\n        super(directory);\n    }\n\n    @Override\n    public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n            throws RpcException {\n        for (Invoker<T> invoker : invokers) {\n            if (invoker.isAvailable()) {\n                return invokeWithContext(invoker, invocation);\n            }\n        }\n        throw new RpcException(\"No provider available in \" + invokers);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;\n\n/**\n * BroadcastCluster\n *\n */\npublic class BroadcastCluster extends AbstractCluster {\n\n    @Override\n    public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {\n        return new BroadcastClusterInvoker<>(directory);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_ERROR_RESPONSE;\n\n/**\n * BroadcastClusterInvoker\n */\npublic class BroadcastClusterInvoker<T> extends AbstractClusterInvoker<T> {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(BroadcastClusterInvoker.class);\n    private static final String BROADCAST_FAIL_PERCENT_KEY = \"broadcast.fail.percent\";\n    private static final int MAX_BROADCAST_FAIL_PERCENT = 100;\n    private static final int MIN_BROADCAST_FAIL_PERCENT = 0;\n\n    public BroadcastClusterInvoker(Directory<T> directory) {\n        super(directory);\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n            throws RpcException {\n        RpcContext.getServiceContext().setInvokers((List) invokers);\n        RpcException exception = null;\n        Result result = null;\n        URL url = getUrl();\n        // The value range of broadcast.fail.threshold must be 0～100.\n        // 100 means that an exception will be thrown last, and 0 means that as long as an exception occurs, it will be\n        // thrown.\n        // see https://github.com/apache/dubbo/pull/7174\n        int broadcastFailPercent = url.getParameter(BROADCAST_FAIL_PERCENT_KEY, MAX_BROADCAST_FAIL_PERCENT);\n\n        if (broadcastFailPercent < MIN_BROADCAST_FAIL_PERCENT || broadcastFailPercent > MAX_BROADCAST_FAIL_PERCENT) {\n            logger.info(String.format(\n                    \"The value corresponding to the broadcast.fail.percent parameter must be between 0 and 100. \"\n                            + \"The current setting is %s, which is reset to 100.\",\n                    broadcastFailPercent));\n            broadcastFailPercent = MAX_BROADCAST_FAIL_PERCENT;\n        }\n\n        int failThresholdIndex = invokers.size() * broadcastFailPercent / MAX_BROADCAST_FAIL_PERCENT;\n        int failIndex = 0;\n        for (int i = 0, invokersSize = invokers.size(); i < invokersSize; i++) {\n            Invoker<T> invoker = invokers.get(i);\n            RpcContext.RestoreContext restoreContext = new RpcContext.RestoreContext();\n            try {\n                RpcInvocation subInvocation = new RpcInvocation(\n                        invocation.getTargetServiceUniqueName(),\n                        invocation.getServiceModel(),\n                        invocation.getMethodName(),\n                        invocation.getServiceName(),\n                        invocation.getProtocolServiceKey(),\n                        invocation.getParameterTypes(),\n                        invocation.getArguments(),\n                        invocation.copyObjectAttachments(),\n                        invocation.getInvoker(),\n                        Collections.synchronizedMap(new HashMap<>(invocation.getAttributes())),\n                        invocation instanceof RpcInvocation ? ((RpcInvocation) invocation).getInvokeMode() : null);\n                result = invokeWithContext(invoker, subInvocation);\n                if (null != result && result.hasException()) {\n                    Throwable resultException = result.getException();\n                    if (null != resultException) {\n                        exception = getRpcException(result.getException());\n                        logger.warn(\n                                CLUSTER_ERROR_RESPONSE,\n                                \"provider return error response\",\n                                \"\",\n                                exception.getMessage(),\n                                exception);\n                        failIndex++;\n                        if (failIndex == failThresholdIndex) {\n                            break;\n                        }\n                    }\n                }\n            } catch (Throwable e) {\n                exception = getRpcException(e);\n                logger.warn(\n                        CLUSTER_ERROR_RESPONSE,\n                        \"provider return error response\",\n                        \"\",\n                        exception.getMessage(),\n                        exception);\n                failIndex++;\n                if (failIndex == failThresholdIndex) {\n                    break;\n                }\n            } finally {\n                if (i != invokersSize - 1) {\n                    restoreContext.restore();\n                }\n            }\n        }\n\n        if (exception != null) {\n            if (failIndex == failThresholdIndex) {\n                if (logger.isDebugEnabled()) {\n                    logger.debug(String.format(\n                            \"The number of BroadcastCluster call failures has reached the threshold %s\",\n                            failThresholdIndex));\n                }\n            } else {\n                if (logger.isDebugEnabled()) {\n                    logger.debug(String.format(\n                            \"The number of BroadcastCluster call failures has not reached the threshold %s, fail size is %s\",\n                            failThresholdIndex, failIndex));\n                }\n            }\n            throw exception;\n        }\n\n        return result;\n    }\n\n    private RpcException getRpcException(Throwable throwable) {\n        RpcException rpcException;\n        if (throwable instanceof RpcException) {\n            rpcException = (RpcException) throwable;\n        } else {\n            rpcException = new RpcException(throwable.getMessage(), throwable);\n        }\n        return rpcException;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.URL_MERGE_PROCESSOR_KEY;\n\npublic class ClusterUtils implements ScopeModelAware {\n\n    private ApplicationModel applicationModel;\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    public URL mergeUrl(URL remoteUrl, Map<String, String> localMap) {\n\n        String ump = localMap.get(URL_MERGE_PROCESSOR_KEY);\n        ProviderURLMergeProcessor providerUrlMergeProcessor;\n\n        if (StringUtils.isNotEmpty(ump)) {\n            providerUrlMergeProcessor = applicationModel\n                    .getExtensionLoader(ProviderURLMergeProcessor.class)\n                    .getExtension(ump);\n        } else {\n            providerUrlMergeProcessor = applicationModel\n                    .getExtensionLoader(ProviderURLMergeProcessor.class)\n                    .getExtension(\"default\");\n        }\n\n        return providerUrlMergeProcessor.mergeUrl(remoteUrl, localMap);\n    }\n\n    public Map<String, String> mergeLocalParams(Map<String, String> localMap) {\n        String ump = localMap.get(URL_MERGE_PROCESSOR_KEY);\n        ProviderURLMergeProcessor providerUrlMergeProcessor;\n\n        if (StringUtils.isNotEmpty(ump)) {\n            providerUrlMergeProcessor = applicationModel\n                    .getExtensionLoader(ProviderURLMergeProcessor.class)\n                    .getExtension(ump);\n        } else {\n            providerUrlMergeProcessor = applicationModel\n                    .getExtensionLoader(ProviderURLMergeProcessor.class)\n                    .getExtension(\"default\");\n        }\n\n        return providerUrlMergeProcessor.mergeLocalParams(localMap);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;\n\n/**\n * {@link FailbackClusterInvoker}\n *\n */\npublic class FailbackCluster extends AbstractCluster {\n\n    public static final String NAME = \"failback\";\n\n    @Override\n    public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {\n        return new FailbackClusterInvoker<>(directory);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.common.timer.Timeout;\nimport org.apache.dubbo.common.timer.Timer;\nimport org.apache.dubbo.common.timer.TimerTask;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_FAILBACK_TIMES;\nimport static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_INVOKE_SERVICE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_TIMER_RETRY_FAILED;\nimport static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_FAILBACK_TASKS;\nimport static org.apache.dubbo.rpc.cluster.Constants.FAIL_BACK_TASKS_KEY;\n\n/**\n * When fails, record failure requests and schedule for retry on a regular interval.\n * Especially useful for services of notification.\n *\n * <a href=\"http://en.wikipedia.org/wiki/Failback\">Failback</a>\n */\npublic class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(FailbackClusterInvoker.class);\n\n    private static final long RETRY_FAILED_PERIOD = 5;\n\n    /**\n     * Number of retries obtained from the configuration, don't contain the first invoke.\n     */\n    private final int retries;\n\n    private final int failbackTasks;\n\n    private volatile Timer failTimer;\n\n    public FailbackClusterInvoker(Directory<T> directory) {\n        super(directory);\n\n        int retriesConfig = getUrl().getParameter(RETRIES_KEY, DEFAULT_FAILBACK_TIMES);\n        if (retriesConfig < 0) {\n            retriesConfig = DEFAULT_FAILBACK_TIMES;\n        }\n        int failbackTasksConfig = getUrl().getParameter(FAIL_BACK_TASKS_KEY, DEFAULT_FAILBACK_TASKS);\n        if (failbackTasksConfig <= 0) {\n            failbackTasksConfig = DEFAULT_FAILBACK_TASKS;\n        }\n        retries = retriesConfig;\n        failbackTasks = failbackTasksConfig;\n    }\n\n    private void addFailed(\n            LoadBalance loadbalance,\n            Invocation invocation,\n            List<Invoker<T>> invokers,\n            Invoker<T> lastInvoker,\n            URL consumerUrl) {\n        if (failTimer == null) {\n            synchronized (this) {\n                if (failTimer == null) {\n                    failTimer = new HashedWheelTimer(\n                            new NamedThreadFactory(\"failback-cluster-timer\", true),\n                            1,\n                            TimeUnit.SECONDS,\n                            32,\n                            failbackTasks);\n                }\n            }\n        }\n        RetryTimerTask retryTimerTask = new RetryTimerTask(\n                loadbalance, invocation, invokers, lastInvoker, retries, RETRY_FAILED_PERIOD, consumerUrl);\n        try {\n            failTimer.newTimeout(retryTimerTask, RETRY_FAILED_PERIOD, TimeUnit.SECONDS);\n        } catch (Throwable e) {\n            logger.error(\n                    CLUSTER_TIMER_RETRY_FAILED,\n                    \"add newTimeout exception\",\n                    \"\",\n                    \"Failback background works error, invocation->\" + invocation + \", exception: \" + e.getMessage(),\n                    e);\n        }\n    }\n\n    @Override\n    protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n            throws RpcException {\n        Invoker<T> invoker = null;\n        URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n        try {\n            invoker = select(loadbalance, invocation, invokers, null);\n            // Asynchronous call method must be used here, because failback will retry in the background.\n            // Then the serviceContext will be cleared after the call is completed.\n            return invokeWithContextAsync(invoker, invocation, consumerUrl);\n        } catch (Throwable e) {\n            logger.error(\n                    CLUSTER_FAILED_INVOKE_SERVICE,\n                    \"Failback to invoke method and start to retries\",\n                    \"\",\n                    \"Failback to invoke method \" + RpcUtils.getMethodName(invocation)\n                            + \", wait for retry in background. Ignored exception: \"\n                            + e.getMessage() + \", \",\n                    e);\n            if (retries > 0) {\n                addFailed(loadbalance, invocation, invokers, invoker, consumerUrl);\n            }\n            return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore\n        }\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n        if (failTimer != null) {\n            failTimer.stop();\n        }\n    }\n\n    /**\n     * RetryTimerTask\n     */\n    private class RetryTimerTask implements TimerTask {\n        private final Invocation invocation;\n        private final LoadBalance loadbalance;\n        private final List<Invoker<T>> invokers;\n        private final long tick;\n        private Invoker<T> lastInvoker;\n        private URL consumerUrl;\n\n        /**\n         * Number of retries obtained from the configuration, don't contain the first invoke.\n         */\n        private final int retries;\n\n        /**\n         * Number of retried.\n         */\n        private int retriedTimes = 0;\n\n        RetryTimerTask(\n                LoadBalance loadbalance,\n                Invocation invocation,\n                List<Invoker<T>> invokers,\n                Invoker<T> lastInvoker,\n                int retries,\n                long tick,\n                URL consumerUrl) {\n            this.loadbalance = loadbalance;\n            this.invocation = invocation;\n            this.invokers = invokers;\n            this.retries = retries;\n            this.tick = tick;\n            this.lastInvoker = lastInvoker;\n            this.consumerUrl = consumerUrl;\n        }\n\n        @Override\n        public void run(Timeout timeout) {\n            try {\n                logger.info(\"Attempt to retry to invoke method \" + RpcUtils.getMethodName(invocation)\n                        + \". The total will retry \" + retries + \" times, the current is the \" + retriedTimes\n                        + \" retry\");\n                Invoker<T> retryInvoker =\n                        select(loadbalance, invocation, invokers, Collections.singletonList(lastInvoker));\n                lastInvoker = retryInvoker;\n                invokeWithContextAsync(retryInvoker, invocation, consumerUrl);\n            } catch (Throwable e) {\n                logger.error(\n                        CLUSTER_FAILED_INVOKE_SERVICE,\n                        \"Failed retry to invoke method\",\n                        \"\",\n                        \"Failed retry to invoke method \" + RpcUtils.getMethodName(invocation) + \", waiting again.\",\n                        e);\n                if ((++retriedTimes) >= retries) {\n                    logger.error(\n                            CLUSTER_FAILED_INVOKE_SERVICE,\n                            \"Failed retry to invoke method and retry times exceed threshold\",\n                            \"\",\n                            \"Failed retry times exceed threshold (\" + retries + \"), We have to abandon, invocation->\"\n                                    + invocation,\n                            e);\n                } else {\n                    rePut(timeout);\n                }\n            }\n        }\n\n        private void rePut(Timeout timeout) {\n            if (timeout == null) {\n                return;\n            }\n\n            Timer timer = timeout.timer();\n            if (timer.isStop() || timeout.isCancelled()) {\n                return;\n            }\n\n            timer.newTimeout(timeout.task(), tick, TimeUnit.SECONDS);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;\n\n/**\n * {@link FailfastClusterInvoker}\n *\n */\npublic class FailfastCluster extends AbstractCluster {\n\n    public static final String NAME = \"failfast\";\n\n    @Override\n    public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {\n        return new FailfastClusterInvoker<>(directory);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.List;\n\n/**\n * Execute exactly once, which means this policy will throw an exception immediately in case of an invocation error.\n * Usually used for non-idempotent write operations\n *\n * <a href=\"http://en.wikipedia.org/wiki/Fail-fast\">Fail-fast</a>\n */\npublic class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T> {\n\n    public FailfastClusterInvoker(Directory<T> directory) {\n        super(directory);\n    }\n\n    @Override\n    public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n            throws RpcException {\n        Invoker<T> invoker = select(loadbalance, invocation, invokers, null);\n        try {\n            return invokeWithContext(invoker, invocation);\n        } catch (Throwable e) {\n            if (e instanceof RpcException && ((RpcException) e).isBiz()) { // biz exception.\n                throw (RpcException) e;\n            }\n            throw new RpcException(\n                    e instanceof RpcException ? ((RpcException) e).getCode() : 0,\n                    \"Failfast invoke providers \" + invoker.getUrl() + \" \"\n                            + loadbalance.getClass().getSimpleName()\n                            + \" for service \" + getInterface().getName()\n                            + \" method \" + RpcUtils.getMethodName(invocation) + \" on consumer \"\n                            + NetUtils.getLocalHost()\n                            + \" use dubbo version \" + Version.getVersion()\n                            + \", but no luck to perform the invocation. Last error is: \" + e.getMessage(),\n                    e.getCause() != null ? e.getCause() : e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;\n\n/**\n * {@link FailoverClusterInvoker}\n *\n */\npublic class FailoverCluster extends AbstractCluster {\n\n    public static final String NAME = \"failover\";\n\n    @Override\n    public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {\n        return new FailoverClusterInvoker<>(directory);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RETRIES;\nimport static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_MULTIPLE_RETRIES;\n\n/**\n * When invoke fails, log the initial error and retry other invokers (retry n times, which means at most n different invokers will be invoked)\n * Note that retry causes latency.\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Failover\">Failover</a>\n *\n */\npublic class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(FailoverClusterInvoker.class);\n\n    public FailoverClusterInvoker(Directory<T> directory) {\n        super(directory);\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance)\n            throws RpcException {\n        List<Invoker<T>> copyInvokers = invokers;\n        String methodName = RpcUtils.getMethodName(invocation);\n        int len = calculateInvokeTimes(methodName);\n        // retry loop.\n        RpcException le = null; // last exception.\n        List<Invoker<T>> invoked = new ArrayList<>(copyInvokers.size()); // invoked invokers.\n        Set<String> providers = new HashSet<>(len);\n        for (int i = 0; i < len; i++) {\n            // Reselect before retry to avoid a change of candidate `invokers`.\n            // NOTE: if `invokers` changed, then `invoked` also lose accuracy.\n            if (i > 0) {\n                checkWhetherDestroyed();\n                copyInvokers = list(invocation);\n                // check again\n                checkInvokers(copyInvokers, invocation);\n            }\n            Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);\n            invoked.add(invoker);\n            RpcContext.getServiceContext().setInvokers((List) invoked);\n            boolean success = false;\n            try {\n                Result result = invokeWithContext(invoker, invocation);\n                if (le != null && logger.isWarnEnabled()) {\n                    logger.warn(\n                            CLUSTER_FAILED_MULTIPLE_RETRIES,\n                            \"failed to retry do invoke\",\n                            \"\",\n                            \"Although retry the method \" + methodName\n                                    + \" in the service \" + getInterface().getName()\n                                    + \" was successful by the provider \"\n                                    + invoker.getUrl().getAddress()\n                                    + \", but there have been failed providers \" + providers\n                                    + \" (\" + providers.size() + \"/\" + copyInvokers.size()\n                                    + \") from the registry \"\n                                    + directory.getUrl().getAddress()\n                                    + \" on the consumer \" + NetUtils.getLocalHost()\n                                    + \" using the dubbo version \" + Version.getVersion() + \". Last error is: \"\n                                    + le.getMessage(),\n                            le);\n                }\n                success = true;\n                return result;\n            } catch (RpcException e) {\n                if (e.isBiz()) { // biz exception.\n                    throw e;\n                }\n                le = e;\n            } catch (Throwable e) {\n                le = new RpcException(e.getMessage(), e);\n            } finally {\n                if (!success) {\n                    providers.add(invoker.getUrl().getAddress());\n                }\n            }\n        }\n        throw new RpcException(\n                le.getCode(),\n                \"Failed to invoke the method \"\n                        + methodName + \" in the service \" + getInterface().getName()\n                        + \". Tried \" + len + \" times of the providers \" + providers\n                        + \" (\" + providers.size() + \"/\" + copyInvokers.size()\n                        + \") from the registry \" + directory.getUrl().getAddress()\n                        + \" on the consumer \" + NetUtils.getLocalHost() + \" using the dubbo version \"\n                        + Version.getVersion() + \". Last error is: \"\n                        + le.getMessage(),\n                le.getCause() != null ? le.getCause() : le);\n    }\n\n    private int calculateInvokeTimes(String methodName) {\n        int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;\n        RpcContext rpcContext = RpcContext.getClientAttachment();\n        Object retry = rpcContext.getObjectAttachment(RETRIES_KEY);\n        if (retry instanceof Number) {\n            len = ((Number) retry).intValue() + 1;\n            rpcContext.removeAttachment(RETRIES_KEY);\n        }\n        if (len <= 0) {\n            len = 1;\n        }\n\n        return len;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;\n\n/**\n * {@link FailsafeClusterInvoker}\n *\n */\npublic class FailsafeCluster extends AbstractCluster {\n\n    public static final String NAME = \"failsafe\";\n\n    @Override\n    public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {\n        return new FailsafeClusterInvoker<>(directory);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\n\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_ERROR_RESPONSE;\n\n/**\n * When invoke fails, log the error message and ignore this error by returning an empty Result.\n * Usually used to write audit logs and other operations\n *\n * <a href=\"http://en.wikipedia.org/wiki/Fail-safe\">Fail-safe</a>\n *\n */\npublic class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T> {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(FailsafeClusterInvoker.class);\n\n    public FailsafeClusterInvoker(Directory<T> directory) {\n        super(directory);\n    }\n\n    @Override\n    public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n            throws RpcException {\n        try {\n            Invoker<T> invoker = select(loadbalance, invocation, invokers, null);\n            return invokeWithContext(invoker, invocation);\n        } catch (Throwable e) {\n            logger.error(\n                    CLUSTER_ERROR_RESPONSE,\n                    \"Failsafe for provider exception\",\n                    \"\",\n                    \"Failsafe ignore exception: \" + e.getMessage(),\n                    e);\n            return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;\n\n/**\n * {@link ForkingClusterInvoker}\n *\n */\npublic class ForkingCluster extends AbstractCluster {\n\n    public static final String NAME = \"forking\";\n\n    @Override\n    public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {\n        return new ForkingClusterInvoker<>(directory);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CompletionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.FORKS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_FORKS;\n\n/**\n * NOTICE! This implementation does not work well with async call.\n * <p>\n * Invoke a specific number of invokers concurrently, usually used for demanding real-time operations, but need to waste more service resources.\n *\n * <a href=\"http://en.wikipedia.org/wiki/Fork_(topology)\">Fork</a>\n */\npublic class ForkingClusterInvoker<T> extends AbstractClusterInvoker<T> {\n\n    /**\n     * Use {@link NamedInternalThreadFactory} to produce {@link org.apache.dubbo.common.threadlocal.InternalThread}\n     * which with the use of {@link org.apache.dubbo.common.threadlocal.InternalThreadLocal} in {@link RpcContext}.\n     */\n    private final ExecutorService executor;\n\n    public ForkingClusterInvoker(Directory<T> directory) {\n        super(directory);\n        executor = directory\n                .getUrl()\n                .getOrDefaultFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getSharedExecutor();\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n            throws RpcException {\n        try {\n            final List<Invoker<T>> selected;\n            final int forks = getUrl().getParameter(FORKS_KEY, DEFAULT_FORKS);\n            final int timeout = getUrl().getParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);\n            if (forks <= 0 || forks >= invokers.size()) {\n                selected = invokers;\n            } else {\n                selected = new ArrayList<>(forks);\n                while (selected.size() < forks) {\n                    Invoker<T> invoker = select(loadbalance, invocation, invokers, selected);\n                    if (!selected.contains(invoker)) {\n                        // Avoid add the same invoker several times.\n                        selected.add(invoker);\n                    }\n                }\n            }\n            RpcContext.getServiceContext().setInvokers((List) selected);\n            final AtomicInteger count = new AtomicInteger();\n            final BlockingQueue<Object> ref = new LinkedBlockingQueue<>(1);\n            selected.forEach(invoker -> {\n                URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n                CompletableFuture.<Object>supplyAsync(\n                                () -> {\n                                    if (ref.size() > 0) {\n                                        return null;\n                                    }\n                                    return invokeWithContextAsync(invoker, invocation, consumerUrl);\n                                },\n                                executor)\n                        .whenComplete((v, t) -> {\n                            if (t == null) {\n                                ref.offer(v);\n                            } else {\n                                int value = count.incrementAndGet();\n                                if (value >= selected.size()) {\n                                    ref.offer(t);\n                                }\n                            }\n                        });\n            });\n            try {\n                Object ret = ref.poll(timeout, TimeUnit.MILLISECONDS);\n                if (ret instanceof Throwable) {\n                    Throwable e = ret instanceof CompletionException\n                            ? ((CompletionException) ret).getCause()\n                            : (Throwable) ret;\n                    throw new RpcException(\n                            e instanceof RpcException ? ((RpcException) e).getCode() : RpcException.UNKNOWN_EXCEPTION,\n                            \"Failed to forking invoke provider \" + selected\n                                    + \", but no luck to perform the invocation. \" + \"Last error is: \" + e.getMessage(),\n                            e.getCause() != null ? e.getCause() : e);\n                }\n                return (Result) ret;\n            } catch (InterruptedException e) {\n                throw new RpcException(\n                        \"Failed to forking invoke provider \" + selected + \", \"\n                                + \"but no luck to perform the invocation. Last error is: \" + e.getMessage(),\n                        e);\n            }\n        } finally {\n            // clear attachments which is binding to current thread.\n            RpcContext.getClientAttachment().clearAttachments();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;\n\npublic class MergeableCluster extends AbstractCluster {\n\n    public static final String NAME = \"mergeable\";\n\n    @Override\n    public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {\n        return new MergeableClusterInvoker<>(directory);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Constants;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.Merger;\nimport org.apache.dubbo.rpc.cluster.merger.MergerFactory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.rpc.Constants.MERGER_KEY;\n\n/**\n * @param <T>\n */\n@SuppressWarnings(\"unchecked\")\npublic class MergeableClusterInvoker<T> extends AbstractClusterInvoker<T> {\n\n    private static final ErrorTypeAwareLogger log =\n            LoggerFactory.getErrorTypeAwareLogger(MergeableClusterInvoker.class);\n\n    public MergeableClusterInvoker(Directory<T> directory) {\n        super(directory);\n    }\n\n    @Override\n    protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n            throws RpcException {\n        String merger = getUrl().getMethodParameter(invocation.getMethodName(), MERGER_KEY);\n        if (ConfigUtils.isEmpty(merger)) { // If a method doesn't have a merger, only invoke one Group\n            for (final Invoker<T> invoker : invokers) {\n                if (invoker.isAvailable()) {\n                    try {\n                        return invokeWithContext(invoker, invocation);\n                    } catch (RpcException e) {\n                        if (e.isNoInvokerAvailableAfterFilter()) {\n                            log.debug(\n                                    \"No available provider for service\" + getUrl().getServiceKey() + \" on group \"\n                                            + invoker.getUrl().getGroup() + \", will continue to try another group.\",\n                                    e);\n                        } else {\n                            throw e;\n                        }\n                    }\n                }\n            }\n            return invokeWithContext(invokers.iterator().next(), invocation);\n        }\n\n        Class<?> returnType;\n        try {\n            returnType = getInterface()\n                    .getMethod(invocation.getMethodName(), invocation.getParameterTypes())\n                    .getReturnType();\n        } catch (NoSuchMethodException e) {\n            returnType = null;\n        }\n\n        Map<String, Result> results = new HashMap<>();\n        for (final Invoker<T> invoker : invokers) {\n            RpcInvocation subInvocation = new RpcInvocation(invocation, invoker);\n            subInvocation.setAttachment(Constants.ASYNC_KEY, \"true\");\n            try {\n                results.put(invoker.getUrl().getServiceKey(), invokeWithContext(invoker, subInvocation));\n            } catch (RpcException e) {\n                if (e.isNoInvokerAvailableAfterFilter()) {\n                    log.warn(\n                            LoggerCodeConstants.CLUSTER_NO_VALID_PROVIDER,\n                            e.getCause().getMessage(),\n                            \"\",\n                            \"No available provider for service\" + getUrl().getServiceKey() + \" on group \"\n                                    + invoker.getUrl().getGroup() + \", will continue to try another group.\",\n                            e);\n                } else {\n                    throw e;\n                }\n            }\n        }\n\n        Object result;\n\n        List<Result> resultList = new ArrayList<>(results.size());\n\n        for (Map.Entry<String, Result> entry : results.entrySet()) {\n            Result asyncResult = entry.getValue();\n            try {\n                Result r = asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);\n                if (r.hasException()) {\n                    log.error(\n                            LoggerCodeConstants.CLUSTER_FAILED_GROUP_MERGE,\n                            \"Invoke \" + getGroupDescFromServiceKey(entry.getKey()) + \" failed: \"\n                                    + r.getException().getMessage(),\n                            \"\",\n                            r.getException().getMessage());\n                } else {\n                    resultList.add(r);\n                }\n            } catch (Exception e) {\n                throw new RpcException(\"Failed to invoke service \" + entry.getKey() + \": \" + e.getMessage(), e);\n            }\n        }\n\n        if (resultList.isEmpty()) {\n            return AsyncRpcResult.newDefaultAsyncResult(invocation);\n        } else if (resultList.size() == 1) {\n            return AsyncRpcResult.newDefaultAsyncResult(resultList.get(0).getValue(), invocation);\n        }\n\n        if (returnType == void.class) {\n            return AsyncRpcResult.newDefaultAsyncResult(invocation);\n        }\n\n        if (merger.startsWith(\".\")) {\n            merger = merger.substring(1);\n            Method method;\n            try {\n                method = returnType.getMethod(merger, returnType);\n            } catch (NoSuchMethodException | NullPointerException e) {\n                throw new RpcException(\"Can not merge result because missing method [ \" + merger + \" ] in class [ \"\n                        + returnType.getName() + \" ]\");\n            }\n            if (!Modifier.isPublic(method.getModifiers())) {\n                method.setAccessible(true);\n            }\n            result = resultList.remove(0).getValue();\n            try {\n                if (method.getReturnType() != void.class\n                        && method.getReturnType().isAssignableFrom(result.getClass())) {\n                    for (Result r : resultList) {\n                        result = method.invoke(result, r.getValue());\n                    }\n                } else {\n                    for (Result r : resultList) {\n                        method.invoke(result, r.getValue());\n                    }\n                }\n            } catch (Exception e) {\n                throw new RpcException(\"Can not merge result: \" + e.getMessage(), e);\n            }\n        } else {\n            Merger resultMerger;\n            ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(\n                    invocation.getModuleModel().getApplicationModel());\n\n            if (ConfigUtils.isDefault(merger)) {\n                resultMerger = applicationModel\n                        .getBeanFactory()\n                        .getBean(MergerFactory.class)\n                        .getMerger(returnType);\n            } else {\n                resultMerger = applicationModel.getExtensionLoader(Merger.class).getExtension(merger);\n            }\n            if (resultMerger != null) {\n                List<Object> rets = new ArrayList<>(resultList.size());\n                for (Result r : resultList) {\n                    rets.add(r.getValue());\n                }\n                result = resultMerger.merge(rets.toArray((Object[]) Array.newInstance(returnType, 0)));\n            } else {\n                throw new RpcException(\"There is no merger to merge result.\");\n            }\n        }\n        return AsyncRpcResult.newDefaultAsyncResult(result, invocation);\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return directory.getInterface();\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return directory.isAvailable();\n    }\n\n    @Override\n    public void destroy() {\n        directory.destroy();\n    }\n\n    private String getGroupDescFromServiceKey(String key) {\n        int index = key.indexOf(\"/\");\n        if (index > 0) {\n            return \"group [ \" + key.substring(0, index) + \" ]\";\n        }\n        return key;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/merger/DefaultProviderURLMergeProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.merger;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INVOKER_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\n\npublic class DefaultProviderURLMergeProcessor implements ProviderURLMergeProcessor {\n\n    @Override\n    public URL mergeUrl(URL remoteUrl, Map<String, String> localParametersMap) {\n        Map<String, String> map = new HashMap<>();\n        Map<String, String> remoteMap = remoteUrl.getParameters();\n\n        if (remoteMap != null && remoteMap.size() > 0) {\n            map.putAll(remoteMap);\n\n            // Remove configurations from provider, some items should be affected by provider.\n            map.remove(THREAD_NAME_KEY);\n            map.remove(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY);\n\n            map.remove(THREADPOOL_KEY);\n            map.remove(DEFAULT_KEY_PREFIX + THREADPOOL_KEY);\n\n            map.remove(CORE_THREADS_KEY);\n            map.remove(DEFAULT_KEY_PREFIX + CORE_THREADS_KEY);\n\n            map.remove(THREADS_KEY);\n            map.remove(DEFAULT_KEY_PREFIX + THREADS_KEY);\n\n            map.remove(QUEUES_KEY);\n            map.remove(DEFAULT_KEY_PREFIX + QUEUES_KEY);\n\n            map.remove(ALIVE_KEY);\n            map.remove(DEFAULT_KEY_PREFIX + ALIVE_KEY);\n\n            map.remove(Constants.TRANSPORTER_KEY);\n            map.remove(DEFAULT_KEY_PREFIX + Constants.TRANSPORTER_KEY);\n        }\n\n        if (localParametersMap != null && localParametersMap.size() > 0) {\n            Map<String, String> copyOfLocalMap = new HashMap<>(localParametersMap);\n\n            if (map.containsKey(GROUP_KEY)) {\n                copyOfLocalMap.remove(GROUP_KEY);\n            }\n            if (map.containsKey(VERSION_KEY)) {\n                copyOfLocalMap.remove(VERSION_KEY);\n            }\n            if (map.containsKey(GENERIC_KEY)) {\n                copyOfLocalMap.remove(GENERIC_KEY);\n            }\n\n            copyOfLocalMap.remove(RELEASE_KEY);\n            copyOfLocalMap.remove(DUBBO_VERSION_KEY);\n            copyOfLocalMap.remove(METHODS_KEY);\n            copyOfLocalMap.remove(TIMESTAMP_KEY);\n            copyOfLocalMap.remove(TAG_KEY);\n\n            map.putAll(copyOfLocalMap);\n\n            if (remoteMap != null) {\n                map.put(REMOTE_APPLICATION_KEY, remoteMap.get(APPLICATION_KEY));\n\n                // Combine filters and listeners on Provider and Consumer\n                String remoteFilter = remoteMap.get(REFERENCE_FILTER_KEY);\n                String localFilter = copyOfLocalMap.get(REFERENCE_FILTER_KEY);\n                if (remoteFilter != null\n                        && remoteFilter.length() > 0\n                        && localFilter != null\n                        && localFilter.length() > 0) {\n                    map.put(REFERENCE_FILTER_KEY, remoteFilter + \",\" + localFilter);\n                }\n                String remoteListener = remoteMap.get(INVOKER_LISTENER_KEY);\n                String localListener = copyOfLocalMap.get(INVOKER_LISTENER_KEY);\n                if (remoteListener != null\n                        && remoteListener.length() > 0\n                        && localListener != null\n                        && localListener.length() > 0) {\n                    map.put(INVOKER_LISTENER_KEY, remoteListener + \",\" + localListener);\n                }\n            }\n        }\n\n        return remoteUrl.clearParameters().addParameters(map);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.registry;\n\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;\n\npublic class ZoneAwareCluster extends AbstractCluster {\n\n    public static final String NAME = \"zone-aware\";\n\n    @Override\n    protected <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {\n        return new ZoneAwareClusterInvoker<>(directory);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.registry;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.ZoneDetector;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PREFERRED_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE_FORCE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ZONE_KEY;\n\n/**\n * When there are more than one registry for subscription.\n * <p>\n * This extension provides a strategy to decide how to distribute traffics among them:\n * 1. registry marked as 'preferred=true' has the highest priority.\n * 2. check the zone the current request belongs, pick the registry that has the same zone first.\n * 3. Evenly balance traffic between all registries based on each registry's weight.\n */\npublic class ZoneAwareClusterInvoker<T> extends AbstractClusterInvoker<T> {\n\n    private static final Logger logger = LoggerFactory.getLogger(ZoneAwareClusterInvoker.class);\n\n    private ZoneDetector zoneDetector;\n\n    public ZoneAwareClusterInvoker(Directory<T> directory) {\n        super(directory);\n        ExtensionLoader<ZoneDetector> loader =\n                directory.getConsumerUrl().getOrDefaultApplicationModel().getExtensionLoader(ZoneDetector.class);\n        if (loader.hasExtension(\"default\")) {\n            zoneDetector = loader.getExtension(\"default\");\n        }\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance)\n            throws RpcException {\n        // First, pick the invoker (XXXClusterInvoker) that comes from the local registry, distinguish by a 'preferred'\n        // key.\n        for (Invoker<T> invoker : invokers) {\n            ClusterInvoker<T> clusterInvoker = (ClusterInvoker<T>) invoker;\n            if (clusterInvoker.isAvailable() && clusterInvoker.getRegistryUrl().getParameter(PREFERRED_KEY, false)) {\n                return clusterInvoker.invoke(invocation);\n            }\n        }\n\n        RpcContext rpcContext = RpcContext.getClientAttachment();\n        String zone = rpcContext.getAttachment(REGISTRY_ZONE);\n        String force = rpcContext.getAttachment(REGISTRY_ZONE_FORCE);\n        if (StringUtils.isEmpty(zone) && zoneDetector != null) {\n            zone = zoneDetector.getZoneOfCurrentRequest(invocation);\n            force = zoneDetector.isZoneForcingEnabled(invocation, zone);\n        }\n\n        // providers in the registry with the same zone\n        if (StringUtils.isNotEmpty(zone)) {\n            for (Invoker<T> invoker : invokers) {\n                ClusterInvoker<T> clusterInvoker = (ClusterInvoker<T>) invoker;\n                if (clusterInvoker.isAvailable()\n                        && zone.equals(clusterInvoker.getRegistryUrl().getParameter(ZONE_KEY))) {\n                    return clusterInvoker.invoke(invocation);\n                }\n            }\n            if (StringUtils.isNotEmpty(force) && \"true\".equalsIgnoreCase(force)) {\n                throw new IllegalStateException(\n                        \"No registry instance in zone or no available providers in the registry, zone: \"\n                                + zone\n                                + \", registries: \"\n                                + invokers.stream()\n                                        .map(invoker -> ((ClusterInvoker<T>) invoker)\n                                                .getRegistryUrl()\n                                                .toString())\n                                        .collect(Collectors.joining(\",\")));\n            }\n        }\n\n        // load balance among all registries, with registry weight count in.\n        Invoker<T> balancedInvoker = select(loadbalance, invocation, invokers, null);\n        if (balancedInvoker != null && balancedInvoker.isAvailable()) {\n            return balancedInvoker.invoke(invocation);\n        }\n\n        // If none of the invokers has a preferred signal or is picked by the loadbalancer, pick the first one\n        // available.\n        for (Invoker<T> invoker : invokers) {\n            ClusterInvoker<T> clusterInvoker = (ClusterInvoker<T>) invoker;\n            if (clusterInvoker.isAvailable()) {\n                return clusterInvoker.invoke(invocation);\n            }\n        }\n\n        throw new RpcException(\"No provider available in \" + invokers);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;\nimport org.apache.dubbo.rpc.cluster.filter.InvocationInterceptorBuilder;\nimport org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor;\nimport org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_INTERCEPTOR_COMPATIBLE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INVOCATION_INTERCEPTOR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\n\npublic abstract class AbstractCluster implements Cluster {\n\n    private <T> Invoker<T> buildClusterInterceptors(AbstractClusterInvoker<T> clusterInvoker) {\n        AbstractClusterInvoker<T> last = buildInterceptorInvoker(new ClusterFilterInvoker<>(clusterInvoker));\n\n        if (Boolean.parseBoolean(ConfigurationUtils.getProperty(\n                clusterInvoker.getDirectory().getConsumerUrl().getScopeModel(),\n                CLUSTER_INTERCEPTOR_COMPATIBLE_KEY,\n                \"false\"))) {\n            return build27xCompatibleClusterInterceptors(clusterInvoker, last);\n        }\n        return last;\n    }\n\n    @Override\n    public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {\n        if (buildFilterChain) {\n            return buildClusterInterceptors(doJoin(directory));\n        } else {\n            return doJoin(directory);\n        }\n    }\n\n    private <T> AbstractClusterInvoker<T> buildInterceptorInvoker(AbstractClusterInvoker<T> invoker) {\n        List<InvocationInterceptorBuilder> builders = ScopeModelUtil.getApplicationModel(\n                        invoker.getUrl().getScopeModel())\n                .getExtensionLoader(InvocationInterceptorBuilder.class)\n                .getActivateExtensions();\n        if (CollectionUtils.isEmpty(builders)) {\n            return invoker;\n        }\n        return new InvocationInterceptorInvoker<>(invoker, builders);\n    }\n\n    protected abstract <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException;\n\n    static class ClusterFilterInvoker<T> extends AbstractClusterInvoker<T> {\n        private final ClusterInvoker<T> filterInvoker;\n\n        public ClusterFilterInvoker(AbstractClusterInvoker<T> invoker) {\n            List<FilterChainBuilder> builders = ScopeModelUtil.getApplicationModel(\n                            invoker.getUrl().getScopeModel())\n                    .getExtensionLoader(FilterChainBuilder.class)\n                    .getActivateExtensions();\n            if (CollectionUtils.isEmpty(builders)) {\n                filterInvoker = invoker;\n            } else {\n                ClusterInvoker<T> tmpInvoker = invoker;\n                for (FilterChainBuilder builder : builders) {\n                    tmpInvoker = builder.buildClusterInvokerChain(\n                            tmpInvoker, REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);\n                }\n                filterInvoker = tmpInvoker;\n            }\n        }\n\n        @Override\n        public Result invoke(Invocation invocation) throws RpcException {\n            return filterInvoker.invoke(invocation);\n        }\n\n        @Override\n        public Directory<T> getDirectory() {\n            return filterInvoker.getDirectory();\n        }\n\n        @Override\n        public URL getRegistryUrl() {\n            return filterInvoker.getRegistryUrl();\n        }\n\n        @Override\n        public boolean isDestroyed() {\n            return filterInvoker.isDestroyed();\n        }\n\n        @Override\n        public URL getUrl() {\n            return filterInvoker.getUrl();\n        }\n\n        /**\n         * The only purpose is to build a interceptor chain, so the cluster related logic doesn't matter.\n         * Use ClusterInvoker<T> to replace AbstractClusterInvoker<T> in the future.\n         */\n        @Override\n        protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n                throws RpcException {\n            return null;\n        }\n\n        public ClusterInvoker<T> getFilterInvoker() {\n            return filterInvoker;\n        }\n    }\n\n    static class InvocationInterceptorInvoker<T> extends AbstractClusterInvoker<T> {\n        private ClusterInvoker<T> interceptorInvoker;\n\n        public InvocationInterceptorInvoker(\n                AbstractClusterInvoker<T> invoker, List<InvocationInterceptorBuilder> builders) {\n            ClusterInvoker<T> tmpInvoker = invoker;\n            for (InvocationInterceptorBuilder builder : builders) {\n                tmpInvoker = builder.buildClusterInterceptorChain(\n                        tmpInvoker, INVOCATION_INTERCEPTOR_KEY, CommonConstants.CONSUMER);\n            }\n            interceptorInvoker = tmpInvoker;\n        }\n\n        @Override\n        public Result invoke(Invocation invocation) throws RpcException {\n            return interceptorInvoker.invoke(invocation);\n        }\n\n        @Override\n        public Directory<T> getDirectory() {\n            return interceptorInvoker.getDirectory();\n        }\n\n        @Override\n        public URL getRegistryUrl() {\n            return interceptorInvoker.getRegistryUrl();\n        }\n\n        @Override\n        public boolean isDestroyed() {\n            return interceptorInvoker.isDestroyed();\n        }\n\n        @Override\n        public URL getUrl() {\n            return interceptorInvoker.getUrl();\n        }\n\n        /**\n         * The only purpose is to build a interceptor chain, so the cluster related logic doesn't matter.\n         * Use ClusterInvoker<T> to replace AbstractClusterInvoker<T> in the future.\n         */\n        @Override\n        protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n                throws RpcException {\n            return null;\n        }\n    }\n\n    @Deprecated\n    private <T> ClusterInvoker<T> build27xCompatibleClusterInterceptors(\n            AbstractClusterInvoker<T> clusterInvoker, AbstractClusterInvoker<T> last) {\n        List<ClusterInterceptor> interceptors = ScopeModelUtil.getApplicationModel(\n                        clusterInvoker.getUrl().getScopeModel())\n                .getExtensionLoader(ClusterInterceptor.class)\n                .getActivateExtensions();\n\n        if (!interceptors.isEmpty()) {\n            for (int i = interceptors.size() - 1; i >= 0; i--) {\n                final ClusterInterceptor interceptor = interceptors.get(i);\n                final AbstractClusterInvoker<T> next = last;\n                last = new InterceptorInvokerNode<>(clusterInvoker, interceptor, next);\n            }\n        }\n        return last;\n    }\n\n    @Deprecated\n    static class InterceptorInvokerNode<T> extends AbstractClusterInvoker<T> {\n\n        private final AbstractClusterInvoker<T> clusterInvoker;\n        private final ClusterInterceptor interceptor;\n        private final AbstractClusterInvoker<T> next;\n\n        public InterceptorInvokerNode(\n                AbstractClusterInvoker<T> clusterInvoker,\n                ClusterInterceptor interceptor,\n                AbstractClusterInvoker<T> next) {\n            this.clusterInvoker = clusterInvoker;\n            this.interceptor = interceptor;\n            this.next = next;\n        }\n\n        @Override\n        public Class<T> getInterface() {\n            return clusterInvoker.getInterface();\n        }\n\n        @Override\n        public URL getUrl() {\n            return clusterInvoker.getUrl();\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return clusterInvoker.isAvailable();\n        }\n\n        @Override\n        public Result invoke(Invocation invocation) throws RpcException {\n            Result asyncResult;\n            try {\n                interceptor.before(next, invocation);\n                asyncResult = interceptor.intercept(next, invocation);\n            } catch (Exception e) {\n                // onError callback\n                if (interceptor instanceof ClusterInterceptor.Listener) {\n                    ClusterInterceptor.Listener listener = (ClusterInterceptor.Listener) interceptor;\n                    listener.onError(e, clusterInvoker, invocation);\n                }\n                throw e;\n            } finally {\n                interceptor.after(next, invocation);\n            }\n            return asyncResult.whenCompleteWithContext((r, t) -> {\n                // onResponse callback\n                if (interceptor instanceof ClusterInterceptor.Listener) {\n                    ClusterInterceptor.Listener listener = (ClusterInterceptor.Listener) interceptor;\n                    if (t == null) {\n                        listener.onMessage(r, clusterInvoker, invocation);\n                    } else {\n                        listener.onError(t, clusterInvoker, invocation);\n                    }\n                }\n            });\n        }\n\n        @Override\n        public void destroy() {\n            clusterInvoker.destroy();\n        }\n\n        @Override\n        public String toString() {\n            return clusterInvoker.toString();\n        }\n\n        @Override\n        protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n                throws RpcException {\n            // The only purpose is to build an interceptor chain, so the cluster related logic doesn't matter.\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.InvokeMode;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.protocol.dubbo.FutureAdapter;\nimport org.apache.dubbo.rpc.support.MockInvoker;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_MOCK_REQUEST;\nimport static org.apache.dubbo.rpc.Constants.MOCK_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.INVOCATION_NEED_MOCK;\n\npublic class MockClusterInvoker<T> implements ClusterInvoker<T> {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MockClusterInvoker.class);\n    private static final boolean setFutureWhenSync = Boolean.parseBoolean(SystemPropertyConfigUtils.getSystemProperty(\n            CommonConstants.ThirdPartyProperty.SET_FUTURE_IN_SYNC_MODE, \"true\"));\n\n    private final Directory<T> directory;\n\n    private final Invoker<T> invoker;\n\n    public MockClusterInvoker(Directory<T> directory, Invoker<T> invoker) {\n        this.directory = directory;\n        this.invoker = invoker;\n    }\n\n    @Override\n    public URL getUrl() {\n        return directory.getConsumerUrl();\n    }\n\n    @Override\n    public URL getRegistryUrl() {\n        return directory.getUrl();\n    }\n\n    @Override\n    public Directory<T> getDirectory() {\n        return directory;\n    }\n\n    @Override\n    public boolean isDestroyed() {\n        return directory.isDestroyed();\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return directory.isAvailable();\n    }\n\n    @Override\n    public void destroy() {\n        this.invoker.destroy();\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return directory.getInterface();\n    }\n\n    @Override\n    public Result invoke(Invocation invocation) throws RpcException {\n        Result result;\n\n        String value = getUrl().getMethodParameter(\n                        RpcUtils.getMethodName(invocation), MOCK_KEY, Boolean.FALSE.toString())\n                .trim();\n        if (ConfigUtils.isEmpty(value)) {\n            // no mock\n            result = this.invoker.invoke(invocation);\n        } else if (value.startsWith(FORCE_KEY)) {\n            if (logger.isWarnEnabled()) {\n                logger.warn(\n                        CLUSTER_FAILED_MOCK_REQUEST,\n                        \"force mock\",\n                        \"\",\n                        \"force-mock: \" + RpcUtils.getMethodName(invocation) + \" force-mock enabled , url : \"\n                                + getUrl());\n            }\n            // force:direct mock\n            result = doMockInvoke(invocation, null);\n        } else {\n            // fail-mock\n            try {\n                result = this.invoker.invoke(invocation);\n\n                // fix:#4585\n                if (result.getException() != null && result.getException() instanceof RpcException) {\n                    RpcException rpcException = (RpcException) result.getException();\n                    if (rpcException.isBiz()) {\n                        throw rpcException;\n                    } else {\n                        result = doMockInvoke(invocation, rpcException);\n                    }\n                }\n\n            } catch (RpcException e) {\n                if (e.isBiz()) {\n                    throw e;\n                }\n\n                if (logger.isWarnEnabled()) {\n                    logger.warn(\n                            CLUSTER_FAILED_MOCK_REQUEST,\n                            \"failed to mock invoke\",\n                            \"\",\n                            \"fail-mock: \" + RpcUtils.getMethodName(invocation) + \" fail-mock enabled , url : \"\n                                    + getUrl(),\n                            e);\n                }\n                result = doMockInvoke(invocation, e);\n            }\n        }\n        return result;\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private Result doMockInvoke(Invocation invocation, RpcException e) {\n        Result result;\n        Invoker<T> mockInvoker;\n\n        RpcInvocation rpcInvocation = (RpcInvocation) invocation;\n        rpcInvocation.setInvokeMode(RpcUtils.getInvokeMode(getUrl(), invocation));\n\n        List<Invoker<T>> mockInvokers = selectMockInvoker(invocation);\n        if (CollectionUtils.isEmpty(mockInvokers)) {\n            mockInvoker = (Invoker<T>) new MockInvoker(getUrl(), directory.getInterface());\n        } else {\n            mockInvoker = mockInvokers.get(0);\n        }\n        try {\n            result = mockInvoker.invoke(invocation);\n        } catch (RpcException mockException) {\n            if (mockException.isBiz()) {\n                result = AsyncRpcResult.newDefaultAsyncResult(mockException.getCause(), invocation);\n            } else {\n                throw new RpcException(\n                        mockException.getCode(), getMockExceptionMessage(e, mockException), mockException.getCause());\n            }\n        } catch (Throwable me) {\n            throw new RpcException(getMockExceptionMessage(e, me), me.getCause());\n        }\n        if (setFutureWhenSync || rpcInvocation.getInvokeMode() != InvokeMode.SYNC) {\n            // set server context\n            RpcContext.getServiceContext()\n                    .setFuture(new FutureAdapter<>(((AsyncRpcResult) result).getResponseFuture()));\n        }\n        return result;\n    }\n\n    private String getMockExceptionMessage(Throwable t, Throwable mt) {\n        String msg = \"mock error : \" + mt.getMessage();\n        if (t != null) {\n            msg = msg + \", invoke error is :\" + StringUtils.toString(t);\n        }\n        return msg;\n    }\n\n    /**\n     * Return MockInvoker\n     * Contract：\n     * directory.list() will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is absent or not true in invocation, otherwise, a list of mock invokers will return.\n     * if directory.list() returns more than one mock invoker, only one of them will be used.\n     *\n     * @param invocation\n     * @return\n     */\n    private List<Invoker<T>> selectMockInvoker(Invocation invocation) {\n        List<Invoker<T>> invokers = null;\n        // TODO generic invoker？\n        if (invocation instanceof RpcInvocation) {\n            // Note the implicit contract (although the description is added to the interface declaration, but\n            // extensibility is a problem. The practice placed in the attachment needs to be improved)\n            invocation.setAttachment(INVOCATION_NEED_MOCK, Boolean.TRUE.toString());\n            // directory will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is absent or not true\n            // in invocation, otherwise, a list of mock invokers will return.\n            try {\n                RpcContext.getServiceContext().setConsumerUrl(getUrl());\n                invokers = directory.list(invocation);\n            } catch (RpcException e) {\n                if (logger.isInfoEnabled()) {\n                    logger.info(\n                            \"Exception when try to invoke mock. Get mock invokers error for service:\"\n                                    + getUrl().getServiceInterface() + \", method:\" + RpcUtils.getMethodName(invocation)\n                                    + \", will construct a new mock with 'new MockInvoker()'.\",\n                            e);\n                }\n            }\n        }\n        return invokers;\n    }\n\n    @Override\n    public String toString() {\n        return \"invoker :\" + this.invoker + \",directory: \" + this.directory;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\n/**\n * mock impl\n *\n */\npublic class MockClusterWrapper implements Cluster {\n\n    private final Cluster cluster;\n\n    public MockClusterWrapper(Cluster cluster) {\n        this.cluster = cluster;\n    }\n\n    @Override\n    public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {\n        return new MockClusterInvoker<>(directory, this.cluster.join(directory, buildFilterChain));\n    }\n\n    public Cluster getCluster() {\n        return cluster;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/ScopeClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.url.component.DubboServiceAddressURL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.listener.ExporterChangeListener;\nimport org.apache.dubbo.rpc.listener.InjvmExporterListener;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.BROADCAST_CLUSTER;\nimport static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;\nimport static org.apache.dubbo.rpc.Constants.GENERIC_KEY;\nimport static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;\nimport static org.apache.dubbo.rpc.Constants.SCOPE_KEY;\nimport static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;\nimport static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;\nimport static org.apache.dubbo.rpc.cluster.Constants.PEER_KEY;\n\n/**\n * ScopeClusterInvoker is a cluster invoker which handles the invocation logic of a single service in a specific scope.\n * <p>\n * It selects between local and remote invoker at runtime.\n *\n * @param <T> the type of service interface\n */\npublic class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChangeListener {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ScopeClusterInvoker.class);\n\n    private final Object createLock = new Object();\n    private Protocol protocolSPI;\n    private final Directory<T> directory;\n    private final Invoker<T> invoker;\n    private final AtomicBoolean isExported;\n    private volatile Invoker<T> injvmInvoker;\n    private volatile InjvmExporterListener injvmExporterListener;\n    private boolean peerFlag;\n    private boolean injvmFlag;\n\n    public ScopeClusterInvoker(Directory<T> directory, Invoker<T> invoker) {\n        this.directory = directory;\n        this.invoker = invoker;\n        this.isExported = new AtomicBoolean(false);\n        init();\n    }\n\n    @Override\n    public URL getUrl() {\n        return directory.getConsumerUrl();\n    }\n\n    @Override\n    public URL getRegistryUrl() {\n        return directory.getUrl();\n    }\n\n    @Override\n    public Directory<T> getDirectory() {\n        return directory;\n    }\n\n    @Override\n    public boolean isDestroyed() {\n        return directory.isDestroyed();\n    }\n\n    @Override\n    public boolean isAvailable() {\n        if (peerFlag || isBroadcast()) {\n            // If it's a point-to-point direct connection or broadcasting, it should be called remotely.\n            return invoker.isAvailable();\n        }\n        if (injvmFlag && isForceLocal()) {\n            // If it's a local call, it should be called locally.\n            return isExported.get();\n        }\n        if (injvmFlag && isExported.get()) {\n            // If allow local call, check if local exported first\n            return true;\n        }\n        return invoker.isAvailable();\n    }\n\n    @Override\n    public void destroy() {\n        if (injvmExporterListener != null) {\n            injvmExporterListener.removeExporterChangeListener(this, getUrl().getServiceKey());\n        }\n        destroyInjvmInvoker();\n        this.invoker.destroy();\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return directory.getInterface();\n    }\n\n    /**\n     * Checks if the current ScopeClusterInvoker is exported to the local JVM and invokes the corresponding Invoker.\n     * If it's not exported locally, then it delegates the invocation to the original Invoker.\n     *\n     * @param invocation the invocation to be performed\n     * @return the result of the invocation\n     * @throws RpcException if there was an error during the invocation\n     */\n    @Override\n    public Result invoke(Invocation invocation) throws RpcException {\n        // When broadcasting, it should be called remotely.\n        if (isBroadcast()) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Performing broadcast call for method: \" + RpcUtils.getMethodName(invocation)\n                        + \" of service: \" + getUrl().getServiceKey());\n            }\n            return invoker.invoke(invocation);\n        }\n        if (peerFlag) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Performing point-to-point call for method: \" + RpcUtils.getMethodName(invocation)\n                        + \" of service: \" + getUrl().getServiceKey());\n            }\n            // If it's a point-to-point direct connection, invoke the original Invoker\n            return invoker.invoke(invocation);\n        }\n        if (isInjvmExported()) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Performing local JVM call for method: \" + RpcUtils.getMethodName(invocation)\n                        + \" of service: \" + getUrl().getServiceKey());\n            }\n            // If it's exported to the local JVM, invoke the corresponding Invoker\n            return injvmInvoker.invoke(invocation);\n        }\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Performing remote call for method: \" + RpcUtils.getMethodName(invocation) + \" of service: \"\n                    + getUrl().getServiceKey());\n        }\n        // Otherwise, delegate the invocation to the original Invoker\n        return invoker.invoke(invocation);\n    }\n\n    private boolean isBroadcast() {\n        return BROADCAST_CLUSTER.equalsIgnoreCase(getUrl().getParameter(CLUSTER_KEY));\n    }\n\n    @Override\n    public void onExporterChangeExport(Exporter<?> exporter) {\n        if (isExported.get()) {\n            return;\n        }\n        if (getUrl().getServiceKey().equals(exporter.getInvoker().getUrl().getServiceKey())\n                && exporter.getInvoker().getUrl().getProtocol().equalsIgnoreCase(LOCAL_PROTOCOL)) {\n            createInjvmInvoker(exporter);\n            isExported.compareAndSet(false, true);\n        }\n    }\n\n    @Override\n    public void onExporterChangeUnExport(Exporter<?> exporter) {\n        if (getUrl().getServiceKey().equals(exporter.getInvoker().getUrl().getServiceKey())\n                && exporter.getInvoker().getUrl().getProtocol().equalsIgnoreCase(LOCAL_PROTOCOL)) {\n            destroyInjvmInvoker();\n            isExported.compareAndSet(true, false);\n        }\n    }\n\n    public Invoker<?> getInvoker() {\n        return invoker;\n    }\n\n    /**\n     * Initializes the ScopeClusterInvoker instance.\n     */\n    private void init() {\n        Boolean peer = (Boolean) getUrl().getAttribute(PEER_KEY);\n        String isInjvm = getUrl().getParameter(LOCAL_PROTOCOL);\n        // When the point-to-point direct connection is directly connected,\n        // the initialization is directly ended\n        if (peer != null && peer) {\n            peerFlag = true;\n            return;\n        }\n        // Check if the service has been exported through Injvm protocol\n        if (injvmInvoker == null\n                && LOCAL_PROTOCOL.equalsIgnoreCase(getRegistryUrl().getProtocol())) {\n            injvmInvoker = invoker;\n            isExported.compareAndSet(false, true);\n            injvmFlag = true;\n            return;\n        }\n        // Check if the service has been exported through Injvm protocol or the SCOPE_LOCAL parameter is set\n        if (Boolean.TRUE.toString().equalsIgnoreCase(isInjvm)\n                || SCOPE_LOCAL.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY))) {\n            injvmFlag = true;\n        } else if (isInjvm == null) {\n            injvmFlag = isNotRemoteOrGeneric();\n        }\n\n        protocolSPI = getUrl().getApplicationModel()\n                .getExtensionLoader(Protocol.class)\n                .getAdaptiveExtension();\n        injvmExporterListener =\n                getUrl().getOrDefaultFrameworkModel().getBeanFactory().getBean(InjvmExporterListener.class);\n        injvmExporterListener.addExporterChangeListener(this, getUrl().getServiceKey());\n    }\n\n    /**\n     * Check if the service is a generalized call or the SCOPE_REMOTE parameter is set\n     *\n     * @return boolean\n     */\n    private boolean isNotRemoteOrGeneric() {\n        return !SCOPE_REMOTE.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY))\n                && !getUrl().getParameter(GENERIC_KEY, false);\n    }\n\n    /**\n     * Checks whether the current ScopeClusterInvoker is exported to the local JVM and returns a boolean value.\n     *\n     * @return true if the ScopeClusterInvoker is exported to the local JVM, false otherwise\n     * @throws RpcException if there was an error during the invocation\n     */\n    private boolean isInjvmExported() {\n        Boolean localInvoke = RpcContext.getServiceContext().getLocalInvoke();\n        boolean isExportedValue = isExported.get();\n        boolean localOnce = (localInvoke != null && localInvoke);\n        // Determine whether this call is local\n        if (isExportedValue && localOnce) {\n            return true;\n        }\n\n        // Determine whether this call is remote\n        if (localInvoke != null && !localInvoke) {\n            return false;\n        }\n\n        // When calling locally, determine whether it does not meet the requirements\n        if (!isExportedValue && (isForceLocal() || localOnce)) {\n            // If it's supposed to be exported to the local JVM ,but it's not, throw an exception\n            throw new RpcException(\n                    \"Local service for \" + getUrl().getServiceInterface() + \" has not been exposed yet!\");\n        }\n\n        return isExportedValue && injvmFlag;\n    }\n\n    private boolean isForceLocal() {\n        return SCOPE_LOCAL.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY))\n                || Boolean.TRUE.toString().equalsIgnoreCase(getUrl().getParameter(LOCAL_PROTOCOL));\n    }\n\n    /**\n     * Creates a new Invoker for the current ScopeClusterInvoker and exports it to the local JVM.\n     */\n    private void createInjvmInvoker(Exporter<?> exporter) {\n        if (injvmInvoker == null) {\n            synchronized (createLock) {\n                if (injvmInvoker == null) {\n                    URL url = new ServiceConfigURL(\n                            LOCAL_PROTOCOL,\n                            NetUtils.getLocalHost(),\n                            getUrl().getPort(),\n                            getInterface().getName(),\n                            getUrl().getParameters());\n                    url = url.setScopeModel(getUrl().getScopeModel());\n                    url = url.setServiceModel(getUrl().getServiceModel());\n\n                    DubboServiceAddressURL consumerUrl = new DubboServiceAddressURL(\n                            url.getUrlAddress(),\n                            url.getUrlParam(),\n                            exporter.getInvoker().getUrl(),\n                            null);\n\n                    Invoker<?> invoker = protocolSPI.refer(getInterface(), consumerUrl);\n                    List<Invoker<?>> invokers = new ArrayList<>();\n                    invokers.add(invoker);\n                    injvmInvoker = Cluster.getCluster(url.getScopeModel(), Cluster.DEFAULT, false)\n                            .join(new StaticDirectory(url, invokers), true);\n                }\n            }\n        }\n    }\n\n    /**\n     * Destroy the existing InjvmInvoker.\n     */\n    private void destroyInjvmInvoker() {\n        if (injvmInvoker != null) {\n            injvmInvoker.destroy();\n            injvmInvoker = null;\n        }\n    }\n\n    @Override\n    public String toString() {\n        return \"ScopeClusterInvoker{\" + \"directory=\"\n                + directory + \", isExported=\"\n                + isExported + \", peerFlag=\"\n                + peerFlag + \", injvmFlag=\"\n                + injvmFlag + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/ScopeClusterWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\nimport org.apache.dubbo.common.extension.Wrapper;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\n/**\n * Introducing ScopeClusterInvoker section through Dubbo SPI mechanism\n */\n@Wrapper(order = -1)\npublic class ScopeClusterWrapper implements Cluster {\n    private final Cluster cluster;\n\n    public ScopeClusterWrapper(Cluster cluster) {\n        this.cluster = cluster;\n    }\n\n    @Override\n    public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {\n        return new ScopeClusterInvoker<>(directory, this.cluster.join(directory, buildFilterChain));\n    }\n\n    public Cluster getCluster() {\n        return cluster;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter",
    "content": "callback-consumer-context=org.apache.dubbo.rpc.cluster.filter.support.CallbackConsumerContextFilter\n"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol",
    "content": "filter=org.apache.dubbo.rpc.cluster.filter.ProtocolFilterWrapper"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster",
    "content": "mock=org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper\nscope=org.apache.dubbo.rpc.cluster.support.wrapper.ScopeClusterWrapper\nfailover=org.apache.dubbo.rpc.cluster.support.FailoverCluster\nfailfast=org.apache.dubbo.rpc.cluster.support.FailfastCluster\nfailsafe=org.apache.dubbo.rpc.cluster.support.FailsafeCluster\nfailback=org.apache.dubbo.rpc.cluster.support.FailbackCluster\nforking=org.apache.dubbo.rpc.cluster.support.ForkingCluster\navailable=org.apache.dubbo.rpc.cluster.support.AvailableCluster\nmergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster\nbroadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster\nzone-aware=org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster\n"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory",
    "content": "override=org.apache.dubbo.rpc.cluster.configurator.override.OverrideConfiguratorFactory\nabsent=org.apache.dubbo.rpc.cluster.configurator.absent.AbsentConfiguratorFactory"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance",
    "content": "random=org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance\nroundrobin=org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance\nleastactive=org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance\nconsistenthash=org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance\nshortestresponse=org.apache.dubbo.rpc.cluster.loadbalance.ShortestResponseLoadBalance\nadaptive=org.apache.dubbo.rpc.cluster.loadbalance.AdaptiveLoadBalance\n"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger",
    "content": "map=org.apache.dubbo.rpc.cluster.merger.MapMerger\nset=org.apache.dubbo.rpc.cluster.merger.SetMerger\nlist=org.apache.dubbo.rpc.cluster.merger.ListMerger\nbyte=org.apache.dubbo.rpc.cluster.merger.ByteArrayMerger\nchar=org.apache.dubbo.rpc.cluster.merger.CharArrayMerger\nshort=org.apache.dubbo.rpc.cluster.merger.ShortArrayMerger\nint=org.apache.dubbo.rpc.cluster.merger.IntArrayMerger\nlong=org.apache.dubbo.rpc.cluster.merger.LongArrayMerger\nfloat=org.apache.dubbo.rpc.cluster.merger.FloatArrayMerger\ndouble=org.apache.dubbo.rpc.cluster.merger.DoubleArrayMerger\nboolean=org.apache.dubbo.rpc.cluster.merger.BooleanArrayMerger\n"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor",
    "content": "default=org.apache.dubbo.rpc.cluster.support.merger.DefaultProviderURLMergeProcessor"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.ClusterFilter",
    "content": "consumercontext=org.apache.dubbo.rpc.cluster.filter.support.ConsumerContextFilter\nconsumer-classloader=org.apache.dubbo.rpc.cluster.filter.support.ConsumerClassLoaderFilter\nrouter-snapshot=org.apache.dubbo.rpc.cluster.router.RouterSnapshotFilter\nmetricsConsumerFilter=org.apache.dubbo.rpc.cluster.filter.support.MetricsConsumerFilter\n"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder",
    "content": "default=org.apache.dubbo.rpc.cluster.filter.DefaultFilterChainBuilder"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository",
    "content": "default=org.apache.dubbo.rpc.cluster.governance.DefaultGovernanceRuleRepositoryImpl"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory",
    "content": "attachment=org.apache.dubbo.rpc.cluster.router.condition.matcher.attachment.AttachmentConditionMatcherFactory\nargument=org.apache.dubbo.rpc.cluster.router.condition.matcher.argument.ArgumentConditionMatcherFactory\nparam=org.apache.dubbo.rpc.cluster.router.condition.matcher.param.UrlParamConditionMatcherFactory\n"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.ValuePattern",
    "content": "range=org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.range.RangeValuePattern\nwildcard=org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.wildcard.WildcardValuePattern\n"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory",
    "content": "mock=org.apache.dubbo.rpc.cluster.router.mock.MockStateRouterFactory\ncondition=org.apache.dubbo.rpc.cluster.router.condition.ConditionStateRouterFactory\nservice=org.apache.dubbo.rpc.cluster.router.condition.config.ServiceStateRouterFactory\napp=org.apache.dubbo.rpc.cluster.router.condition.config.AppStateRouterFactory\nprovider-app=org.apache.dubbo.rpc.cluster.router.condition.config.ProviderAppStateRouterFactory\nstandard-mesh-rule=org.apache.dubbo.rpc.cluster.router.mesh.route.StandardMeshRuleRouterFactory\nscript-app=org.apache.dubbo.rpc.cluster.router.script.config.AppScriptRouterFactory\ntag=org.apache.dubbo.rpc.cluster.router.tag.TagStateRouterFactory\n"
  },
  {
    "path": "dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "dubbo-cluster=org.apache.dubbo.rpc.cluster.ClusterScopeModelInitializer\ndubbo-cluster-mergeable=org.apache.dubbo.rpc.cluster.MergeableClusterScopeModelInitializer\nmesh=org.apache.dubbo.rpc.cluster.router.mesh.MeshScopeModelInitializer\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/ConfiguratorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.configurator.absent.AbsentConfigurator;\nimport org.apache.dubbo.rpc.cluster.configurator.override.OverrideConfigurator;\nimport org.apache.dubbo.rpc.cluster.configurator.parser.ConfigParser;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link Configurator}\n */\nclass ConfiguratorTest {\n\n    @Test\n    void test() {\n\n        Optional<List<Configurator>> emptyOptional = Configurator.toConfigurators(Collections.emptyList());\n        Assertions.assertEquals(Optional.empty(), emptyOptional);\n\n        String configData =\n                \"[\\\"override://0.0.0.0/com.xx.Service?category=configurators&timeout=6666&disabled=true&dynamic=false&enabled=true&group=dubbo&priority=2&version=1.0\\\"\"\n                        + \", \\\"absent://0.0.0.0/com.xx.Service?category=configurators&timeout=6666&disabled=true&dynamic=false&enabled=true&group=dubbo&priority=1&version=1.0\\\" ]\";\n        List<URL> urls = ConfigParser.parseConfigurators(configData);\n        Optional<List<Configurator>> optionalList = Configurator.toConfigurators(urls);\n        Assertions.assertTrue(optionalList.isPresent());\n        List<Configurator> configurators = optionalList.get();\n        Assertions.assertEquals(configurators.size(), 2);\n        // The hosts of AbsentConfigurator and OverrideConfigurator are equal, but the priority of OverrideConfigurator\n        // is higher\n        Assertions.assertTrue(configurators.get(0) instanceof AbsentConfigurator);\n        Assertions.assertTrue(configurators.get(1) instanceof OverrideConfigurator);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/StickyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_STICKY_KEY;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n@SuppressWarnings(\"unchecked\")\nclass StickyTest {\n\n    private List<Invoker<StickyTest>> invokers = new ArrayList<Invoker<StickyTest>>();\n\n    private Invoker<StickyTest> invoker1 = mock(Invoker.class);\n    private Invoker<StickyTest> invoker2 = mock(Invoker.class);\n    private RpcInvocation invocation;\n    private Directory<StickyTest> dic;\n    private Result result = new AppResponse();\n    private StickyClusterInvoker<StickyTest> clusterinvoker = null;\n    private URL url =\n            URL.valueOf(\"test://test:11/test?\" + \"&loadbalance=roundrobin\" + \"&\" + CLUSTER_STICKY_KEY + \"=true\");\n    private int runs = 1;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        dic = mock(Directory.class);\n\n        invocation = new RpcInvocation();\n\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(invokers);\n        given(dic.getInterface()).willReturn(StickyTest.class);\n\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n\n        clusterinvoker = new StickyClusterInvoker<StickyTest>(dic);\n    }\n\n    @Test\n    void testStickyNoCheck() {\n        int count = testSticky(\"t1\", false);\n        Assertions.assertTrue(count > 0 && count <= runs);\n    }\n\n    @Test\n    void testStickyForceCheck() {\n        int count = testSticky(\"t2\", true);\n        Assertions.assertTrue(count == 0 || count == runs);\n    }\n\n    @Test\n    void testMethodStickyNoCheck() {\n        int count = testSticky(\"method1\", false);\n        Assertions.assertTrue(count > 0 && count <= runs);\n    }\n\n    @Test\n    void testMethodStickyForceCheck() {\n        int count = testSticky(\"method1\", true);\n        Assertions.assertTrue(count == 0 || count == runs);\n    }\n\n    @Test\n    void testMethodsSticky() {\n        for (int i = 0; i < 100; i++) { // Two different methods should always use the same invoker every time.\n            int count1 = testSticky(\"method1\", true);\n            int count2 = testSticky(\"method2\", true);\n            Assertions.assertEquals(count1, count2);\n        }\n    }\n\n    public int testSticky(String methodName, boolean check) {\n        if (methodName == null) {\n            url = url.addParameter(CLUSTER_STICKY_KEY, String.valueOf(check));\n        } else {\n            url = url.addParameter(methodName + \".\" + CLUSTER_STICKY_KEY, String.valueOf(check));\n        }\n\n        given(invoker1.invoke(invocation)).willReturn(result);\n        given(invoker1.isAvailable()).willReturn(true);\n        given(invoker1.getUrl()).willReturn(url.setPort(1));\n        given(invoker1.getInterface()).willReturn(StickyTest.class);\n\n        given(invoker2.invoke(invocation)).willReturn(result);\n        given(invoker2.isAvailable()).willReturn(true);\n        given(invoker2.getUrl()).willReturn(url.setPort(2));\n        given(invoker2.getInterface()).willReturn(StickyTest.class);\n\n        invocation.setMethodName(methodName);\n\n        int count = 0;\n        for (int i = 0; i < runs; i++) {\n            Assertions.assertNull(clusterinvoker.invoke(invocation));\n            if (invoker1 == clusterinvoker.getSelectedInvoker()) {\n                count++;\n            }\n        }\n        return count;\n    }\n\n    static class StickyClusterInvoker<T> extends AbstractClusterInvoker<T> {\n        private Invoker<T> selectedInvoker;\n\n        public StickyClusterInvoker(Directory<T> directory) {\n            super(directory);\n        }\n\n        public StickyClusterInvoker(Directory<T> directory, URL url) {\n            super(directory, url);\n        }\n\n        @Override\n        protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n                throws RpcException {\n            Invoker<T> invoker = select(loadbalance, invocation, invokers, null);\n            selectedInvoker = invoker;\n            return null;\n        }\n\n        public Invoker<T> getSelectedInvoker() {\n            return selectedInvoker;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.absent;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.rpc.cluster.configurator.consts.UrlConstant;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass AbsentConfiguratorTest {\n\n    @Test\n    void testOverrideApplication() {\n        AbsentConfigurator configurator =\n                new AbsentConfigurator(URL.valueOf(\"override://foo@0.0.0.0/com.foo.BarService?timeout=200\"));\n\n        URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));\n        Assertions.assertEquals(\"200\", url.getParameter(\"timeout\"));\n\n        url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));\n        Assertions.assertEquals(\"1000\", url.getParameter(\"timeout\"));\n\n        url = configurator.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_11));\n        Assertions.assertNull(url.getParameter(\"timeout\"));\n\n        url = configurator.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_11));\n        Assertions.assertEquals(\"1000\", url.getParameter(\"timeout\"));\n    }\n\n    @Test\n    void testOverrideHost() {\n        AbsentConfigurator configurator = new AbsentConfigurator(\n                URL.valueOf(\"override://\" + NetUtils.getLocalHost() + \"/com.foo.BarService?timeout=200\"));\n\n        URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));\n        Assertions.assertEquals(\"200\", url.getParameter(\"timeout\"));\n\n        url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));\n        Assertions.assertEquals(\"1000\", url.getParameter(\"timeout\"));\n\n        AbsentConfigurator configurator1 = new AbsentConfigurator(URL.valueOf(UrlConstant.SERVICE_TIMEOUT_200));\n\n        url = configurator1.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_10));\n        Assertions.assertNull(url.getParameter(\"timeout\"));\n\n        url = configurator1.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_10));\n        Assertions.assertEquals(\"1000\", url.getParameter(\"timeout\"));\n    }\n\n    // Test the version after 2.7\n    @Test\n    void testAbsentForVersion27() {\n        {\n            String consumerUrlV27 =\n                    \"dubbo://172.24.160.179/com.foo.BarService?application=foo&side=consumer&timeout=100\";\n\n            URL consumerConfiguratorUrl = URL.valueOf(\"absent://0.0.0.0/com.foo.BarService\");\n            Map<String, String> params = new HashMap<>();\n            params.put(\"side\", \"consumer\");\n            params.put(\"configVersion\", \"2.7\");\n            params.put(\"application\", \"foo\");\n            params.put(\"timeout\", \"10000\");\n            params.put(\"weight\", \"200\");\n            consumerConfiguratorUrl = consumerConfiguratorUrl.addParameters(params);\n\n            AbsentConfigurator configurator = new AbsentConfigurator(consumerConfiguratorUrl);\n            // Meet the configured conditions:\n            // same side\n            // The port of configuratorUrl is 0\n            // The host of configuratorUrl is 0.0.0.0 or the local address is the same as consumerUrlV27\n            // same appName\n            URL url = configurator.configure(URL.valueOf(consumerUrlV27));\n            Assertions.assertEquals(\"100\", url.getParameter(\"timeout\"));\n            Assertions.assertEquals(\"200\", url.getParameter(\"weight\"));\n        }\n\n        {\n            String providerUrlV27 =\n                    \"dubbo://172.24.160.179:21880/com.foo.BarService?application=foo&side=provider&weight=100\";\n\n            URL providerConfiguratorUrl = URL.valueOf(\"absent://172.24.160.179:21880/com.foo.BarService\");\n            Map<String, String> params = new HashMap<>();\n            params.put(\"side\", \"provider\");\n            params.put(\"configVersion\", \"2.7\");\n            params.put(\"application\", \"foo\");\n            params.put(\"timeout\", \"20000\");\n            params.put(\"weight\", \"200\");\n            providerConfiguratorUrl = providerConfiguratorUrl.addParameters(params);\n            // Meet the configured conditions:\n            // same side\n            // same port\n            // The host of configuratorUrl is 0.0.0.0 or the host of providerConfiguratorUrl is the same as\n            // consumerUrlV27\n            // same appName\n            AbsentConfigurator configurator = new AbsentConfigurator(providerConfiguratorUrl);\n            URL url = configurator.configure(URL.valueOf(providerUrlV27));\n            Assertions.assertEquals(\"20000\", url.getParameter(\"timeout\"));\n            Assertions.assertEquals(\"100\", url.getParameter(\"weight\"));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/consts/UrlConstant.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.consts;\n\n/**\n * test case url constant\n */\npublic class UrlConstant {\n    public static final String URL_CONSUMER =\n            \"dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&side=consumer\";\n    public static final String URL_ONE =\n            \"dubbo://10.20.153.10:20880/com.foo.BarService?application=foo&timeout=1000&side=consumer\";\n    public static final String APPLICATION_BAR_SIDE_CONSUMER_11 =\n            \"dubbo://10.20.153.11:20880/com.foo.BarService?application=bar&side=consumer\";\n    public static final String TIMEOUT_1000_SIDE_CONSUMER_11 =\n            \"dubbo://10.20.153.11:20880/com.foo.BarService?application=bar&timeout=1000&side=consumer\";\n    public static final String SERVICE_TIMEOUT_200 = \"override://10.20.153.10/com.foo.BarService?timeout=200\";\n    public static final String APPLICATION_BAR_SIDE_CONSUMER_10 =\n            \"dubbo://10.20.153.10:20880/com.foo.BarService?application=bar&side=consumer\";\n    public static final String TIMEOUT_1000_SIDE_CONSUMER_10 =\n            \"dubbo://10.20.153.10:20880/com.foo.BarService?application=bar&timeout=1000&side=consumer\";\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.override;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.rpc.cluster.configurator.absent.AbsentConfigurator;\nimport org.apache.dubbo.rpc.cluster.configurator.consts.UrlConstant;\nimport org.apache.dubbo.rpc.cluster.configurator.parser.model.ConditionMatch;\nimport org.apache.dubbo.rpc.cluster.configurator.parser.model.ParamMatch;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.StringMatch;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig.MATCH_CONDITION;\n\nclass OverrideConfiguratorTest {\n\n    @Test\n    void testOverride_Application() {\n        OverrideConfigurator configurator =\n                new OverrideConfigurator(URL.valueOf(\"override://foo@0.0.0.0/com.foo.BarService?timeout=200\"));\n\n        URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));\n        Assertions.assertEquals(\"200\", url.getParameter(\"timeout\"));\n\n        url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));\n        Assertions.assertEquals(\"200\", url.getParameter(\"timeout\"));\n\n        url = configurator.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_11));\n        Assertions.assertNull(url.getParameter(\"timeout\"));\n\n        url = configurator.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_11));\n        Assertions.assertEquals(\"1000\", url.getParameter(\"timeout\"));\n    }\n\n    @Test\n    void testOverride_Host() {\n        OverrideConfigurator configurator = new OverrideConfigurator(\n                URL.valueOf(\"override://\" + NetUtils.getLocalHost() + \"/com.foo.BarService?timeout=200\"));\n\n        URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));\n        Assertions.assertEquals(\"200\", url.getParameter(\"timeout\"));\n\n        url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));\n        Assertions.assertEquals(\"200\", url.getParameter(\"timeout\"));\n\n        AbsentConfigurator configurator1 =\n                new AbsentConfigurator(URL.valueOf(\"override://10.20.153.10/com.foo.BarService?timeout=200\"));\n\n        url = configurator1.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_10));\n        Assertions.assertNull(url.getParameter(\"timeout\"));\n\n        url = configurator1.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_10));\n        Assertions.assertEquals(\"1000\", url.getParameter(\"timeout\"));\n    }\n\n    // Test the version after 2.7\n    @Test\n    void testOverrideForVersion27() {\n        {\n            String consumerUrlV27 =\n                    \"dubbo://172.24.160.179/com.foo.BarService?application=foo&side=consumer&timeout=100\";\n\n            URL consumerConfiguratorUrl = URL.valueOf(\"override://0.0.0.0/com.foo.BarService\");\n            Map<String, String> params = new HashMap<>();\n            params.put(\"side\", \"consumer\");\n            params.put(\"configVersion\", \"2.7\");\n            params.put(\"application\", \"foo\");\n            params.put(\"timeout\", \"10000\");\n\n            consumerConfiguratorUrl = consumerConfiguratorUrl.addParameters(params);\n\n            OverrideConfigurator configurator = new OverrideConfigurator(consumerConfiguratorUrl);\n            // Meet the configured conditions:\n            // same side\n            // The port of configuratorUrl is 0\n            // The host of configuratorUrl is 0.0.0.0 or the local address is the same as consumerUrlV27\n            // same appName\n            URL url = configurator.configure(URL.valueOf(consumerUrlV27));\n            Assertions.assertEquals(url.getParameter(\"timeout\"), \"10000\");\n        }\n\n        {\n            String providerUrlV27 =\n                    \"dubbo://172.24.160.179:21880/com.foo.BarService?application=foo&side=provider&weight=100\";\n\n            URL providerConfiguratorUrl = URL.valueOf(\"override://172.24.160.179:21880/com.foo.BarService\");\n            Map<String, String> params = new HashMap<>();\n            params.put(\"side\", \"provider\");\n            params.put(\"configVersion\", \"2.7\");\n            params.put(\"application\", \"foo\");\n            params.put(\"weight\", \"200\");\n            providerConfiguratorUrl = providerConfiguratorUrl.addParameters(params);\n            // Meet the configured conditions:\n            // same side\n            // same port\n            // The host of configuratorUrl is 0.0.0.0 or the host of providerConfiguratorUrl is the same as\n            // consumerUrlV27\n            // same appName\n            OverrideConfigurator configurator = new OverrideConfigurator(providerConfiguratorUrl);\n            URL url = configurator.configure(URL.valueOf(providerUrlV27));\n            Assertions.assertEquals(url.getParameter(\"weight\"), \"200\");\n        }\n    }\n\n    // Test the version after 2.7\n    @Test\n    void testOverrideForVersion3() {\n        // match\n        {\n            String consumerUrlV3 =\n                    \"dubbo://172.24.160.179/com.foo.BarService?match_key=value&application=foo&side=consumer&timeout=100\";\n\n            URL consumerConfiguratorUrl = URL.valueOf(\"override://0.0.0.0/com.foo.BarService\");\n            Map<String, String> params = new HashMap<>();\n            params.put(\"side\", \"consumer\");\n            params.put(\"configVersion\", \"v3.0\");\n            params.put(\"application\", \"foo\");\n            params.put(\"timeout\", \"10000\");\n\n            ConditionMatch matcher = new ConditionMatch();\n            ParamMatch paramMatch = new ParamMatch();\n            paramMatch.setKey(\"match_key\");\n            StringMatch stringMatch = new StringMatch();\n            stringMatch.setExact(\"value\");\n            paramMatch.setValue(stringMatch);\n            matcher.setParam(Arrays.asList(paramMatch));\n            consumerConfiguratorUrl = consumerConfiguratorUrl.putAttribute(MATCH_CONDITION, matcher);\n\n            consumerConfiguratorUrl = consumerConfiguratorUrl.addParameters(params);\n\n            OverrideConfigurator configurator = new OverrideConfigurator(consumerConfiguratorUrl);\n            // Meet the configured conditions:\n            // same side\n            // The port of configuratorUrl is 0\n            // The host of configuratorUrl is 0.0.0.0 or the local address is the same as consumerUrlV27\n            // same appName\n            URL originalURL = URL.valueOf(consumerUrlV3);\n            Assertions.assertEquals(\"100\", originalURL.getParameter(\"timeout\"));\n            URL url = configurator.configure(originalURL);\n            Assertions.assertEquals(\"10000\", url.getParameter(\"timeout\"));\n        }\n\n        // mismatch\n        {\n            String consumerUrlV3 =\n                    \"dubbo://172.24.160.179/com.foo.BarService?match_key=value&application=foo&side=consumer&timeout=100\";\n\n            URL consumerConfiguratorUrl = URL.valueOf(\"override://0.0.0.0/com.foo.BarService\");\n            Map<String, String> params = new HashMap<>();\n            params.put(\"side\", \"consumer\");\n            params.put(\"configVersion\", \"v3.0\");\n            params.put(\"application\", \"foo\");\n            params.put(\"timeout\", \"10000\");\n\n            ConditionMatch matcher = new ConditionMatch();\n            ParamMatch paramMatch = new ParamMatch();\n            paramMatch.setKey(\"match_key\");\n            StringMatch stringMatch = new StringMatch();\n            stringMatch.setExact(\"not_match_value\");\n            paramMatch.setValue(stringMatch);\n            matcher.setParam(Arrays.asList(paramMatch));\n            consumerConfiguratorUrl = consumerConfiguratorUrl.putAttribute(MATCH_CONDITION, matcher);\n\n            consumerConfiguratorUrl = consumerConfiguratorUrl.addParameters(params);\n\n            OverrideConfigurator configurator = new OverrideConfigurator(consumerConfiguratorUrl);\n            // Meet the configured conditions:\n            // same side\n            // The port of configuratorUrl is 0\n            // The host of configuratorUrl is 0.0.0.0 or the local address is the same as consumerUrlV27\n            // same appName\n            URL originalURL = URL.valueOf(consumerUrlV3);\n            Assertions.assertEquals(\"100\", originalURL.getParameter(\"timeout\"));\n            URL url = configurator.configure(originalURL);\n            Assertions.assertEquals(\"100\", url.getParameter(\"timeout\"));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/parser/ConfigParserTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.configurator.parser;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.configurator.parser.model.ConditionMatch;\nimport org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY;\nimport static org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig.MATCH_CONDITION;\n\nclass ConfigParserTest {\n\n    private String streamToString(InputStream stream) throws IOException {\n        byte[] bytes = new byte[stream.available()];\n        stream.read(bytes);\n        return new String(bytes);\n    }\n\n    @Test\n    void snakeYamlBasicTest() throws IOException {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/ServiceNoApp.yml\")) {\n            Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n            Map<String, Object> map = yaml.load(yamlStream);\n            ConfiguratorConfig config = ConfiguratorConfig.parseFromMap(map);\n            Assertions.assertNotNull(config);\n        }\n    }\n\n    @Test\n    void parseConfiguratorsServiceNoAppTest() throws Exception {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/ServiceNoApp.yml\")) {\n            List<URL> urls = ConfigParser.parseConfigurators(streamToString(yamlStream));\n            Assertions.assertNotNull(urls);\n            Assertions.assertEquals(2, urls.size());\n            URL url = urls.get(0);\n            Assertions.assertEquals(\"127.0.0.1:20880\", url.getAddress());\n            Assertions.assertEquals(222, url.getParameter(WEIGHT_KEY, 0));\n        }\n    }\n\n    @Test\n    void parseConfiguratorsServiceGroupVersionTest() throws Exception {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/ServiceGroupVersion.yml\")) {\n            List<URL> urls = ConfigParser.parseConfigurators(streamToString(yamlStream));\n            Assertions.assertNotNull(urls);\n            Assertions.assertEquals(1, urls.size());\n            URL url = urls.get(0);\n            Assertions.assertEquals(\"testgroup\", url.getGroup());\n            Assertions.assertEquals(\"1.0.0\", url.getVersion());\n        }\n    }\n\n    @Test\n    void parseConfiguratorsServiceMultiAppsTest() throws IOException {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/ServiceMultiApps.yml\")) {\n            List<URL> urls = ConfigParser.parseConfigurators(streamToString(yamlStream));\n            Assertions.assertNotNull(urls);\n            Assertions.assertEquals(4, urls.size());\n            URL url = urls.get(0);\n            Assertions.assertEquals(\"127.0.0.1\", url.getAddress());\n            Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));\n            Assertions.assertNotNull(url.getApplication());\n        }\n    }\n\n    @Test\n    void parseConfiguratorsServiceNoRuleTest() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/ServiceNoRule.yml\")) {\n                ConfigParser.parseConfigurators(streamToString(yamlStream));\n                Assertions.fail();\n            }\n        });\n    }\n\n    @Test\n    void parseConfiguratorsAppMultiServicesTest() throws IOException {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/AppMultiServices.yml\")) {\n            String yamlFile = streamToString(yamlStream);\n            List<URL> urls = ConfigParser.parseConfigurators(yamlFile);\n            Assertions.assertNotNull(urls);\n            Assertions.assertEquals(4, urls.size());\n            URL url = urls.get(0);\n            Assertions.assertEquals(\"127.0.0.1\", url.getAddress());\n            Assertions.assertEquals(\"service1\", url.getServiceInterface());\n            Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));\n            Assertions.assertEquals(\"random\", url.getParameter(LOADBALANCE_KEY));\n            Assertions.assertEquals(\"demo-consumer\", url.getApplication());\n        }\n    }\n\n    @Test\n    void parseConfiguratorsAppAnyServicesTest() throws IOException {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/AppAnyServices.yml\")) {\n            List<URL> urls = ConfigParser.parseConfigurators(streamToString(yamlStream));\n            Assertions.assertNotNull(urls);\n            Assertions.assertEquals(2, urls.size());\n            URL url = urls.get(0);\n            Assertions.assertEquals(\"127.0.0.1\", url.getAddress());\n            Assertions.assertEquals(\"*\", url.getServiceInterface());\n            Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));\n            Assertions.assertEquals(\"random\", url.getParameter(LOADBALANCE_KEY));\n            Assertions.assertEquals(\"demo-consumer\", url.getApplication());\n        }\n    }\n\n    @Test\n    void parseConfiguratorsAppNoServiceTest() throws IOException {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/AppNoService.yml\")) {\n            List<URL> urls = ConfigParser.parseConfigurators(streamToString(yamlStream));\n            Assertions.assertNotNull(urls);\n            Assertions.assertEquals(1, urls.size());\n            URL url = urls.get(0);\n            Assertions.assertEquals(\"127.0.0.1\", url.getAddress());\n            Assertions.assertEquals(\"*\", url.getServiceInterface());\n            Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));\n            Assertions.assertEquals(\"random\", url.getParameter(LOADBALANCE_KEY));\n            Assertions.assertEquals(\"demo-consumer\", url.getApplication());\n        }\n    }\n\n    @Test\n    void parseConsumerSpecificProvidersTest() throws IOException {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/ConsumerSpecificProviders.yml\")) {\n            List<URL> urls = ConfigParser.parseConfigurators(streamToString(yamlStream));\n            Assertions.assertNotNull(urls);\n            Assertions.assertEquals(1, urls.size());\n            URL url = urls.get(0);\n            Assertions.assertEquals(\"127.0.0.1\", url.getAddress());\n            Assertions.assertEquals(\"*\", url.getServiceInterface());\n            Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));\n            Assertions.assertEquals(\"random\", url.getParameter(LOADBALANCE_KEY));\n            Assertions.assertEquals(\"127.0.0.1:20880\", url.getParameter(OVERRIDE_PROVIDERS_KEY));\n            Assertions.assertEquals(\"demo-consumer\", url.getApplication());\n        }\n    }\n\n    @Test\n    void parseProviderConfigurationV3() throws IOException {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/ConfiguratorV3.yml\")) {\n            List<URL> urls = ConfigParser.parseConfigurators(streamToString(yamlStream));\n            Assertions.assertNotNull(urls);\n            Assertions.assertEquals(1, urls.size());\n            URL url = urls.get(0);\n            Assertions.assertEquals(\"0.0.0.0\", url.getAddress());\n            Assertions.assertEquals(\"*\", url.getServiceInterface());\n            Assertions.assertEquals(200, url.getParameter(WEIGHT_KEY, 0));\n            Assertions.assertEquals(\"demo-provider\", url.getApplication());\n\n            URL matchURL1 = URL.valueOf(\"dubbo://10.0.0.1:20880/DemoService?match_key1=value1\");\n            URL matchURL2 = URL.valueOf(\"dubbo://10.0.0.1:20880/DemoService2?match_key1=value1\");\n            URL notMatchURL1 = URL.valueOf(\"dubbo://10.0.0.2:20880/DemoService?match_key1=value1\"); // address not match\n            URL notMatchURL2 =\n                    URL.valueOf(\"dubbo://10.0.0.1:20880/DemoServiceNotMatch?match_key1=value1\"); // service not match\n            URL notMatchURL3 =\n                    URL.valueOf(\"dubbo://10.0.0.1:20880/DemoService?match_key1=value_not_match\"); // key not match\n\n            ConditionMatch matcher = (ConditionMatch) url.getAttribute(MATCH_CONDITION);\n            Assertions.assertTrue(matcher.isMatch(matchURL1.getAddress(), matchURL1));\n            Assertions.assertTrue(matcher.isMatch(matchURL2.getAddress(), matchURL2));\n            Assertions.assertFalse(matcher.isMatch(notMatchURL1.getAddress(), notMatchURL1));\n            Assertions.assertFalse(matcher.isMatch(notMatchURL2.getAddress(), notMatchURL2));\n            Assertions.assertFalse(matcher.isMatch(notMatchURL3.getAddress(), notMatchURL3));\n        }\n    }\n\n    @Test\n    void parseProviderConfigurationV3Compatibility() throws IOException {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/ConfiguratorV3Compatibility.yml\")) {\n            List<URL> urls = ConfigParser.parseConfigurators(streamToString(yamlStream));\n            Assertions.assertNotNull(urls);\n            Assertions.assertEquals(1, urls.size());\n            URL url = urls.get(0);\n            Assertions.assertEquals(\"10.0.0.1:20880\", url.getAddress());\n            Assertions.assertEquals(\"DemoService\", url.getServiceInterface());\n            Assertions.assertEquals(200, url.getParameter(WEIGHT_KEY, 0));\n            Assertions.assertEquals(\"demo-provider\", url.getApplication());\n\n            URL matchURL = URL.valueOf(\"dubbo://10.0.0.1:20880/DemoService?match_key1=value1\");\n            URL notMatchURL =\n                    URL.valueOf(\"dubbo://10.0.0.1:20880/DemoService?match_key1=value_not_match\"); // key not match\n\n            ConditionMatch matcher = (ConditionMatch) url.getAttribute(MATCH_CONDITION);\n            Assertions.assertTrue(matcher.isMatch(matchURL.getAddress(), matchURL));\n            Assertions.assertFalse(matcher.isMatch(notMatchURL.getAddress(), notMatchURL));\n        }\n    }\n\n    @Test\n    void parseProviderConfigurationV3Conflict() throws IOException {\n        try (InputStream yamlStream = this.getClass().getResourceAsStream(\"/ConfiguratorV3Duplicate.yml\")) {\n            List<URL> urls = ConfigParser.parseConfigurators(streamToString(yamlStream));\n            Assertions.assertNotNull(urls);\n            Assertions.assertEquals(1, urls.size());\n            URL url = urls.get(0);\n            Assertions.assertEquals(\"10.0.0.1:20880\", url.getAddress());\n            Assertions.assertEquals(\"DemoService\", url.getServiceInterface());\n            Assertions.assertEquals(200, url.getParameter(WEIGHT_KEY, 0));\n            Assertions.assertEquals(\"demo-provider\", url.getApplication());\n\n            URL matchURL = URL.valueOf(\"dubbo://10.0.0.1:20880/DemoService?match_key1=value1\");\n            URL notMatchURL =\n                    URL.valueOf(\"dubbo://10.0.0.1:20880/DemoService?match_key1=value_not_match\"); // key not match\n\n            ConditionMatch matcher = (ConditionMatch) url.getAttribute(MATCH_CONDITION);\n            Assertions.assertTrue(matcher.isMatch(matchURL.getAddress(), matchURL));\n            Assertions.assertFalse(matcher.isMatch(notMatchURL.getAddress(), notMatchURL));\n        }\n    }\n\n    @Test\n    void parseURLJsonArrayCompatible() {\n\n        String configData =\n                \"[\\\"override://0.0.0.0/com.xx.Service?category=configurators&timeout=6666&disabled=true&dynamic=false&enabled=true&group=dubbo&priority=1&version=1.0\\\" ]\";\n\n        List<URL> urls = ConfigParser.parseConfigurators(configData);\n\n        Assertions.assertNotNull(urls);\n        Assertions.assertEquals(1, urls.size());\n        URL url = urls.get(0);\n\n        Assertions.assertEquals(\"0.0.0.0\", url.getAddress());\n        Assertions.assertEquals(\"com.xx.Service\", url.getServiceInterface());\n        Assertions.assertEquals(6666, url.getParameter(TIMEOUT_KEY, 0));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectoryConcurrencyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.directory;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.RouterChain;\nimport org.apache.dubbo.rpc.cluster.SingleRouterChain;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.mock;\n\nclass AbstractDirectoryConcurrencyTest {\n\n    private TestDirectory directory;\n    private URL url;\n    private ExecutorService executor;\n\n    @BeforeEach\n    void setUp() {\n        url = URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":20880/com.foo.BarService\");\n        directory = new TestDirectory(url);\n        executor = Executors.newFixedThreadPool(10);\n    }\n\n    @AfterEach\n    void tearDown() {\n        if (directory != null) {\n            directory.destroy();\n        }\n        if (executor != null) {\n            executor.shutdownNow();\n        }\n    }\n\n    @Test\n    void testMultipleReadLocks() throws InterruptedException {\n        int threadCount = 5;\n        CountDownLatch latch = new CountDownLatch(1);\n        CountDownLatch doneLatch = new CountDownLatch(threadCount);\n        AtomicBoolean failed = new AtomicBoolean(false);\n\n        // Setup the directory with a slow list implementation to simulate work holding the read lock\n        directory.setListAction(() -> {\n            try {\n                // Wait for the latch to ensure all threads are in doList\n                latch.await(5, TimeUnit.SECONDS);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        });\n\n        for (int i = 0; i < threadCount; i++) {\n            executor.submit(() -> {\n                try {\n                    directory.list(mock(Invocation.class));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    failed.set(true);\n                } finally {\n                    doneLatch.countDown();\n                }\n            });\n        }\n\n        // Give threads time to start and acquire read lock\n        Thread.sleep(100);\n        // Release the latch, letting them proceed\n        latch.countDown();\n\n        Assertions.assertTrue(doneLatch.await(5, TimeUnit.SECONDS), \"All list calls should complete\");\n        Assertions.assertFalse(failed.get(), \"No exceptions should occur during concurrent reads\");\n    }\n\n    @Test\n    void testWriteBlocksRead() throws InterruptedException {\n        CountDownLatch writeLockAcquiredLatch = new CountDownLatch(1);\n        CountDownLatch releaseWriteLockLatch = new CountDownLatch(1);\n        AtomicReference<Boolean> readBlocked = new AtomicReference<>(false);\n\n        // Thread to hold write lock\n        executor.submit(() -> {\n            directory.simulateWriteLock(writeLockAcquiredLatch, releaseWriteLockLatch);\n        });\n\n        // Wait for write lock to be acquired\n        Assertions.assertTrue(writeLockAcquiredLatch.await(5, TimeUnit.SECONDS));\n\n        // Try to read in another thread\n        Future<?> readFuture = executor.submit(() -> {\n            long start = System.currentTimeMillis();\n            directory.list(mock(Invocation.class));\n            long duration = System.currentTimeMillis() - start;\n            // If duration is > 100ms, we assume it was blocked\n            readBlocked.set(duration >= 100);\n        });\n\n        // Sleep to ensure read thread tries to acquire lock and blocks\n        Thread.sleep(200);\n\n        // Release write lock\n        releaseWriteLockLatch.countDown();\n\n        try {\n            readFuture.get(5, TimeUnit.SECONDS);\n        } catch (Exception e) {\n            Assertions.fail(\"Read execution failed\");\n        }\n\n        Assertions.assertTrue(readBlocked.get(), \"Read operation should be blocked by write lock\");\n    }\n\n    @Test\n    void testConcurrentReadAndWrite() throws InterruptedException {\n        int readThreads = 10;\n        int writeThreads = 2;\n        int iterations = 100;\n        CountDownLatch doneLatch = new CountDownLatch(readThreads + writeThreads);\n        AtomicBoolean failed = new AtomicBoolean(false);\n\n        directory.setListAction(() -> {\n            // Simulate some work\n            try {\n                Thread.sleep(1);\n            } catch (InterruptedException e) {\n            }\n        });\n\n        // Start read threads\n        for (int i = 0; i < readThreads; i++) {\n            executor.submit(() -> {\n                try {\n                    for (int j = 0; j < iterations; j++) {\n                        directory.list(mock(Invocation.class));\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    failed.set(true);\n                } finally {\n                    doneLatch.countDown();\n                }\n            });\n        }\n\n        // Start write threads\n        for (int i = 0; i < writeThreads; i++) {\n            executor.submit(() -> {\n                try {\n                    for (int j = 0; j < iterations; j++) {\n                        // Use setInvokers to trigger write lock\n                        directory.setInvokers(new BitList<>(Collections.emptyList()));\n                        Thread.sleep(2);\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    failed.set(true);\n                } finally {\n                    doneLatch.countDown();\n                }\n            });\n        }\n\n        Assertions.assertTrue(doneLatch.await(30, TimeUnit.SECONDS), \"All operations should complete\");\n        Assertions.assertFalse(failed.get(), \"No exceptions should occur during concurrent read/write\");\n    }\n\n    // Helper class to expose protected methods and hook into list()\n    static class TestDirectory extends AbstractDirectory<Object> {\n        private Runnable listAction = () -> {};\n\n        public TestDirectory(URL url) {\n            super(url);\n            // Initialize with empty router chain to avoid NPE\n            setRouterChain(RouterChain.buildChain(Object.class, url));\n        }\n\n        public void setListAction(Runnable listAction) {\n            this.listAction = listAction;\n        }\n\n        @Override\n        public Class<Object> getInterface() {\n            return Object.class;\n        }\n\n        @Override\n        public List<Invoker<Object>> getAllInvokers() {\n            return Collections.emptyList();\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return true;\n        }\n\n        @Override\n        protected List<Invoker<Object>> doList(\n                SingleRouterChain<Object> singleRouterChain, BitList<Invoker<Object>> invokers, Invocation invocation)\n                throws RpcException {\n            listAction.run();\n            return Collections.emptyList();\n        }\n\n        // Helper to simulate holding write lock\n        public void simulateWriteLock(CountDownLatch acquired, CountDownLatch release) {\n            // We use refreshInvoker to acquire write lock, but we need to inject our blocking logic\n            // Since we can't easily inject into refreshInvoker without complex mocking,\n            // we'll use a trick: override setInvokers logic? No, setInvokers uses lock internally.\n            // But we can use the fact that addRouters/etc might not use the same lock? No.\n            // We can't access the lock directly.\n            // However, we can use 'addInvalidateInvoker' or similar if we can hook into it.\n\n            // Actually, we can use a method that holds the lock and calls something we can override?\n            // AbstractDirectory doesn't call many overridable methods inside the lock.\n            // refreshInvoker calls refreshInvokerInternal (private).\n\n            // Wait, we can use reflection to get the lock and lock it manually for this test helper.\n            try {\n                java.lang.reflect.Field lockField = AbstractDirectory.class.getDeclaredField(\"invokerRefreshLock\");\n                lockField.setAccessible(true);\n                java.util.concurrent.locks.ReadWriteLock lock =\n                        (java.util.concurrent.locks.ReadWriteLock) lockField.get(this);\n\n                lock.writeLock().lock();\n                try {\n                    acquired.countDown();\n                    release.await();\n                } catch (InterruptedException e) {\n                    Thread.currentThread().interrupt();\n                } finally {\n                    lock.writeLock().unlock();\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n\n        // Expose setInvokers for test\n        @Override\n        public void setInvokers(BitList<Invoker<Object>> invokers) {\n            super.setInvokers(invokers);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/directory/MockDirInvocation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.directory;\n\nimport org.apache.dubbo.rpc.AttachmentsAdapter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.rpc.Constants.TOKEN_KEY;\n\nclass MockDirInvocation implements Invocation {\n\n    private Map<String, Object> attachments;\n\n    public MockDirInvocation() {\n        attachments = new HashMap<>();\n        attachments.put(PATH_KEY, \"dubbo\");\n        attachments.put(GROUP_KEY, \"dubbo\");\n        attachments.put(VERSION_KEY, \"1.0.0\");\n        attachments.put(DUBBO_VERSION_KEY, \"1.0.0\");\n        attachments.put(TOKEN_KEY, \"sfag\");\n        attachments.put(TIMEOUT_KEY, \"1000\");\n    }\n\n    @Override\n    public String getTargetServiceUniqueName() {\n        return null;\n    }\n\n    @Override\n    public String getProtocolServiceKey() {\n        return null;\n    }\n\n    public String getMethodName() {\n        return \"echo\";\n    }\n\n    @Override\n    public String getServiceName() {\n        return \"DemoService\";\n    }\n\n    public Class<?>[] getParameterTypes() {\n        return new Class[] {String.class};\n    }\n\n    public Object[] getArguments() {\n        return new Object[] {\"aa\"};\n    }\n\n    public Map<String, String> getAttachments() {\n        return new AttachmentsAdapter.ObjectToStringMap(attachments);\n    }\n\n    @Override\n    public Map<String, Object> getObjectAttachments() {\n        return attachments;\n    }\n\n    @Override\n    public Map<String, Object> copyObjectAttachments() {\n        return new HashMap<>(attachments);\n    }\n\n    @Override\n    public void foreachAttachment(Consumer<Map.Entry<String, Object>> consumer) {\n        attachments.entrySet().forEach(consumer);\n    }\n\n    @Override\n    public void setAttachment(String key, String value) {\n        setObjectAttachment(key, value);\n    }\n\n    @Override\n    public void setAttachment(String key, Object value) {\n        setObjectAttachment(key, value);\n    }\n\n    @Override\n    public void setObjectAttachment(String key, Object value) {\n        attachments.put(key, value);\n    }\n\n    @Override\n    public void setAttachmentIfAbsent(String key, String value) {\n        setObjectAttachmentIfAbsent(key, value);\n    }\n\n    @Override\n    public void setAttachmentIfAbsent(String key, Object value) {\n        setObjectAttachmentIfAbsent(key, value);\n    }\n\n    @Override\n    public void setObjectAttachmentIfAbsent(String key, Object value) {\n        attachments.putIfAbsent(key, value);\n    }\n\n    public Invoker<?> getInvoker() {\n        return null;\n    }\n\n    @Override\n    public Object put(Object key, Object value) {\n        return null;\n    }\n\n    @Override\n    public Object get(Object key) {\n        return null;\n    }\n\n    @Override\n    public void setServiceModel(ServiceModel serviceModel) {}\n\n    @Override\n    public ServiceModel getServiceModel() {\n        return null;\n    }\n\n    @Override\n    public Map<Object, Object> getAttributes() {\n        return null;\n    }\n\n    public String getAttachment(String key) {\n        return (String) getObjectAttachment(key);\n    }\n\n    @Override\n    public Object getObjectAttachment(String key) {\n        return attachments.get(key);\n    }\n\n    public String getAttachment(String key, String defaultValue) {\n        return (String) getObjectAttachment(key, defaultValue);\n    }\n\n    @Override\n    public void addInvokedInvoker(Invoker<?> invoker) {}\n\n    @Override\n    public List<Invoker<?>> getInvokedInvokers() {\n        return null;\n    }\n\n    @Override\n    public Object getObjectAttachment(String key, Object defaultValue) {\n        Object result = attachments.get(key);\n        if (result == null) {\n            return defaultValue;\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.directory;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.router.MockInvoker;\nimport org.apache.dubbo.rpc.cluster.router.condition.ConditionStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;\n\nclass StaticDirectoryTest {\n    private URL SCRIPT_URL = URL.valueOf(\"condition://0.0.0.0/com.foo.BarService\");\n\n    private URL getRouteUrl(String rule) {\n        return SCRIPT_URL.addParameterAndEncoded(RULE_KEY, rule);\n    }\n\n    @Test\n    void testStaticDirectory() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\" => \" + \" host = \" + NetUtils.getLocalHost()));\n        List<StateRouter> routers = new ArrayList<StateRouter>();\n        routers.add(router);\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService\"), true);\n        Invoker<String> invoker2 = new MockInvoker<String>(\n                URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":20880/com.foo.BarService\"), true);\n        Invoker<String> invoker3 = new MockInvoker<String>(\n                URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":20880/com.foo.BarService\"), true);\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + NetUtils.getLocalHost() + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);\n        StaticDirectory<String> staticDirectory = new StaticDirectory<>(filteredInvokers);\n        boolean isAvailable = staticDirectory.isAvailable();\n        Assertions.assertTrue(isAvailable);\n        List<Invoker<String>> newInvokers = staticDirectory.list(new MockDirInvocation());\n        Assertions.assertTrue(newInvokers.size() > 0);\n        staticDirectory.destroy();\n        Assertions.assertEquals(0, staticDirectory.getInvokers().size());\n        Assertions.assertEquals(0, staticDirectory.getValidInvokers().size());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DefaultFilterChainBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.protocol.AbstractInvoker;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\n\nclass DefaultFilterChainBuilderTest {\n\n    @Test\n    void testBuildInvokerChainForLocalReference() {\n        DefaultFilterChainBuilder defaultFilterChainBuilder = new DefaultFilterChainBuilder();\n\n        // verify that no filter is built by default\n        URL urlWithoutFilter =\n                URL.valueOf(\"injvm://127.0.0.1/DemoService\").addParameter(INTERFACE_KEY, DemoService.class.getName());\n        urlWithoutFilter = urlWithoutFilter.setScopeModel(ApplicationModel.defaultModel());\n        AbstractInvoker<DemoService> invokerWithoutFilter =\n                new AbstractInvoker<DemoService>(DemoService.class, urlWithoutFilter) {\n                    @Override\n                    protected Result doInvoke(Invocation invocation) {\n                        return null;\n                    }\n                };\n\n        Invoker<?> invokerAfterBuild =\n                defaultFilterChainBuilder.buildInvokerChain(invokerWithoutFilter, REFERENCE_FILTER_KEY, CONSUMER);\n\n        // verify that if LogFilter is configured, LogFilter should exist in the filter chain\n        URL urlWithFilter = URL.valueOf(\"injvm://127.0.0.1/DemoService\")\n                .addParameter(INTERFACE_KEY, DemoService.class.getName())\n                .addParameter(REFERENCE_FILTER_KEY, \"log\");\n        urlWithFilter = urlWithFilter.setScopeModel(ApplicationModel.defaultModel());\n        AbstractInvoker<DemoService> invokerWithFilter =\n                new AbstractInvoker<DemoService>(DemoService.class, urlWithFilter) {\n                    @Override\n                    protected Result doInvoke(Invocation invocation) {\n                        return null;\n                    }\n                };\n        invokerAfterBuild =\n                defaultFilterChainBuilder.buildInvokerChain(invokerWithFilter, REFERENCE_FILTER_KEY, CONSUMER);\n        Assertions.assertTrue(invokerAfterBuild instanceof FilterChainBuilder.CallbackRegistrationInvoker);\n    }\n\n    @Test\n    void testBuildInvokerChainForRemoteReference() {\n        DefaultFilterChainBuilder defaultFilterChainBuilder = new DefaultFilterChainBuilder();\n\n        // verify that no filter is built by default\n        URL urlWithoutFilter = URL.valueOf(\"dubbo://127.0.0.1:20880/DemoService\")\n                .addParameter(INTERFACE_KEY, DemoService.class.getName());\n        urlWithoutFilter = urlWithoutFilter.setScopeModel(ApplicationModel.defaultModel());\n        AbstractInvoker<DemoService> invokerWithoutFilter =\n                new AbstractInvoker<DemoService>(DemoService.class, urlWithoutFilter) {\n                    @Override\n                    protected Result doInvoke(Invocation invocation) {\n                        return null;\n                    }\n                };\n\n        Invoker<?> invokerAfterBuild =\n                defaultFilterChainBuilder.buildInvokerChain(invokerWithoutFilter, REFERENCE_FILTER_KEY, CONSUMER);\n        //        Assertions.assertTrue(invokerAfterBuild instanceof AbstractInvoker);\n\n        // verify that if LogFilter is configured, LogFilter should exist in the filter chain\n        URL urlWithFilter = URL.valueOf(\"dubbo://127.0.0.1:20880/DemoService\")\n                .addParameter(INTERFACE_KEY, DemoService.class.getName())\n                .addParameter(REFERENCE_FILTER_KEY, \"log\");\n        urlWithFilter = urlWithFilter.setScopeModel(ApplicationModel.defaultModel());\n        AbstractInvoker<DemoService> invokerWithFilter =\n                new AbstractInvoker<DemoService>(DemoService.class, urlWithFilter) {\n                    @Override\n                    protected Result doInvoke(Invocation invocation) {\n                        return null;\n                    }\n                };\n        invokerAfterBuild =\n                defaultFilterChainBuilder.buildInvokerChain(invokerWithFilter, REFERENCE_FILTER_KEY, CONSUMER);\n        Assertions.assertTrue(invokerAfterBuild instanceof FilterChainBuilder.CallbackRegistrationInvoker);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\npublic interface DemoService {\n    String sayHello(String name);\n\n    int plus(int a, int b);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nclass DemoServiceImpl implements DemoService {\n\n    @Override\n    public String sayHello(String name) {\n        return name;\n    }\n\n    @Override\n    public int plus(int a, int b) {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceLocal.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nclass DemoServiceLocal implements DemoService {\n\n    public DemoServiceLocal(DemoService demoService) {}\n\n    public String sayHello(String name) {\n        return name;\n    }\n\n    public int plus(int a, int b) {\n        return a + b;\n    }\n\n    public void ondisconnect() {}\n\n    public void onconnect() {}\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceMock.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nclass DemoServiceMock implements DemoService {\n    public String sayHello(String name) {\n        return name;\n    }\n\n    public int plus(int a, int b) {\n        return a + b;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceStub.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nclass DemoServiceStub implements DemoService {\n\n    public DemoServiceStub(DemoService demoService) {}\n\n    public String sayHello(String name) {\n        return name;\n    }\n\n    public int plus(int a, int b) {\n        return a + b;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/LogFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\n\n@Activate(group = CONSUMER, value = \"log\")\npublic class LogFilter implements Filter, Filter.Listener {\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        return invoker.invoke(invocation);\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {}\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {}\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/MockService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nclass MockService implements DemoService {\n    public String sayHello(String name) {\n        return name;\n    }\n\n    public int plus(int a, int b) {\n        return a + b;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\nimport java.util.HashMap;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\nclass AbstractLoadBalanceTest {\n\n    private AbstractLoadBalance balance = new AbstractLoadBalance() {\n        @Override\n        protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {\n            return null;\n        }\n    };\n\n    @Test\n    void testGetWeight() {\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"say\");\n\n        Invoker invoker1 = mock(Invoker.class, Mockito.withSettings().stubOnly());\n        URL url1 = new ServiceConfigURL(\"\", \"\", 0, \"DemoService\", new HashMap<>());\n        url1 = url1.addParameter(TIMESTAMP_KEY, System.currentTimeMillis() - Integer.MAX_VALUE - 1);\n        given(invoker1.getUrl()).willReturn(url1);\n\n        Invoker invoker2 = mock(Invoker.class, Mockito.withSettings().stubOnly());\n        URL url2 = new ServiceConfigURL(\"\", \"\", 0, \"DemoService\", new HashMap<>());\n        url2 = url2.addParameter(TIMESTAMP_KEY, System.currentTimeMillis() - 10 * 60 * 1000L - 1);\n        given(invoker2.getUrl()).willReturn(url2);\n\n        Assertions.assertEquals(balance.getWeight(invoker1, invocation), balance.getWeight(invoker2, invocation));\n    }\n\n    @Test\n    void testGetRegistryWeight() {\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"say\");\n\n        Invoker invoker1 = mock(Invoker.class, Mockito.withSettings().stubOnly());\n        URL url1 = new ServiceConfigURL(\"\", \"\", 0, \"DemoService\", new HashMap<>());\n        given(invoker1.getUrl()).willReturn(url1);\n\n        ClusterInvoker invoker2 =\n                mock(ClusterInvoker.class, Mockito.withSettings().stubOnly());\n        URL url2 = new ServiceConfigURL(\"\", \"\", 0, \"org.apache.dubbo.registry.RegistryService\", new HashMap<>());\n        url2 = url2.addParameter(WEIGHT_KEY, 20);\n        URL registryUrl2 =\n                new ServiceConfigURL(\"\", \"\", 0, \"org.apache.dubbo.registry.RegistryService\", new HashMap<>());\n        registryUrl2 = registryUrl2.addParameter(WEIGHT_KEY, 30);\n        given(invoker2.getUrl()).willReturn(url2);\n        given(invoker2.getRegistryUrl()).willReturn(registryUrl2);\n\n        Assertions.assertEquals(100, balance.getWeight(invoker1, invocation));\n        Assertions.assertEquals(30, balance.getWeight(invoker2, invocation));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/AdaptiveLoadBalanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.AdaptiveMetrics;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.MethodOrderer;\nimport org.junit.jupiter.api.Order;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestMethodOrder;\n\n@TestMethodOrder(MethodOrderer.OrderAnnotation.class)\nclass AdaptiveLoadBalanceTest extends LoadBalanceBaseTest {\n\n    private ApplicationModel scopeModel;\n\n    private AdaptiveMetrics adaptiveMetrics;\n\n    @Test\n    @Order(0)\n    void testSelectByWeight() {\n        int sumInvoker1 = 0;\n        int sumInvoker2 = 0;\n        int sumInvoker3 = 0;\n        int loop = 10000;\n\n        ApplicationModel scopeModel = ApplicationModel.defaultModel();\n\n        AdaptiveLoadBalance lb = new AdaptiveLoadBalance(scopeModel);\n        for (int i = 0; i < loop; i++) {\n            Invoker selected = lb.select(weightInvokers, null, weightTestInvocation);\n\n            if (selected.getUrl().getProtocol().equals(\"test1\")) {\n                sumInvoker1++;\n            }\n\n            if (selected.getUrl().getProtocol().equals(\"test2\")) {\n                sumInvoker2++;\n            }\n\n            if (selected.getUrl().getProtocol().equals(\"test3\")) {\n                sumInvoker3++;\n            }\n        }\n\n        // 1 : 9 : 6\n        Assertions.assertEquals(sumInvoker1 + sumInvoker2 + sumInvoker3, loop, \"select failed!\");\n    }\n\n    private String buildServiceKey(Invoker invoker) {\n        URL url = invoker.getUrl();\n        return url.getAddress() + \":\" + invocation.getProtocolServiceKey();\n    }\n\n    private AdaptiveMetrics getAdaptiveMetricsInstance() {\n        if (adaptiveMetrics == null) {\n            adaptiveMetrics = scopeModel.getBeanFactory().getBean(AdaptiveMetrics.class);\n        }\n        return adaptiveMetrics;\n    }\n\n    @Test\n    @Order(1)\n    void testSelectByAdaptive() {\n        int sumInvoker1 = 0;\n        int sumInvoker2 = 0;\n        int sumInvoker5 = 0;\n        int loop = 10000;\n\n        scopeModel = ApplicationModel.defaultModel();\n        AdaptiveLoadBalance lb = new AdaptiveLoadBalance(scopeModel);\n\n        lb.select(weightInvokersSR, null, weightTestInvocation);\n\n        for (int i = 0; i < loop; i++) {\n            Invoker selected = lb.select(weightInvokersSR, null, weightTestInvocation);\n\n            Map<String, String> metricsMap = new HashMap<>();\n            String idKey = buildServiceKey(selected);\n\n            if (selected.getUrl().getProtocol().equals(\"test1\")) {\n                sumInvoker1++;\n                metricsMap.put(\"rt\", \"10\");\n                metricsMap.put(\"load\", \"10\");\n                metricsMap.put(\"curTime\", String.valueOf(System.currentTimeMillis() - 10));\n                getAdaptiveMetricsInstance().addConsumerSuccess(idKey);\n            }\n\n            if (selected.getUrl().getProtocol().equals(\"test2\")) {\n                sumInvoker2++;\n                metricsMap.put(\"rt\", \"100\");\n                metricsMap.put(\"load\", \"40\");\n                metricsMap.put(\"curTime\", String.valueOf(System.currentTimeMillis() - 100));\n                getAdaptiveMetricsInstance().addConsumerSuccess(idKey);\n            }\n\n            if (selected.getUrl().getProtocol().equals(\"test5\")) {\n                metricsMap.put(\"rt\", \"5000\");\n                metricsMap.put(\"load\", \"400\"); // 400%\n                metricsMap.put(\"curTime\", String.valueOf(System.currentTimeMillis() - 5000));\n\n                getAdaptiveMetricsInstance().addErrorReq(idKey);\n                sumInvoker5++;\n            }\n            getAdaptiveMetricsInstance().setProviderMetrics(idKey, metricsMap);\n        }\n        Map<Invoker<LoadBalanceBaseTest>, Integer> weightMap = weightInvokersSR.stream()\n                .collect(Collectors.toMap(\n                        Function.identity(), e -> Integer.valueOf(e.getUrl().getParameter(\"weight\"))));\n        Integer totalWeight = weightMap.values().stream().reduce(0, Integer::sum);\n        // max deviation = expectWeightValue * 2\n        int expectWeightValue = loop / totalWeight;\n        int maxDeviation = expectWeightValue * 2;\n        double beta = 0.5;\n        // this EMA is an approximate value\n        double ewma1 = beta * 50 + (1 - beta) * 10;\n        double ewma2 = beta * 50 + (1 - beta) * 100;\n        double ewma5 = beta * 50 + (1 - beta) * 5000;\n\n        AtomicInteger weight1 = new AtomicInteger();\n        AtomicInteger weight2 = new AtomicInteger();\n        AtomicInteger weight5 = new AtomicInteger();\n        weightMap.forEach((k, v) -> {\n            if (k.getUrl().getProtocol().equals(\"test1\")) {\n                weight1.set(v);\n            } else if (k.getUrl().getProtocol().equals(\"test2\")) {\n                weight2.set(v);\n            } else if (k.getUrl().getProtocol().equals(\"test5\")) {\n                weight5.set(v);\n            }\n        });\n\n        Assertions.assertEquals(sumInvoker1 + sumInvoker2 + sumInvoker5, loop, \"select failed!\");\n        Assertions.assertTrue(\n                Math.abs(sumInvoker1 / (weightMap.get(weightInvoker1) * ewma1) - expectWeightValue) < maxDeviation,\n                \"select failed!\");\n        Assertions.assertTrue(\n                Math.abs(sumInvoker2 / (weightMap.get(weightInvoker2) * ewma2) - expectWeightValue) < maxDeviation,\n                \"select failed!\");\n        Assertions.assertTrue(\n                Math.abs(sumInvoker5 / (weightMap.get(weightInvoker5) * ewma5) - expectWeightValue) < maxDeviation,\n                \"select failed!\");\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.RouterChain;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n@SuppressWarnings(\"rawtypes\")\nclass ConsistentHashLoadBalanceTest extends LoadBalanceBaseTest {\n\n    @Test\n    void testConsistentHashLoadBalanceInGenericCall() {\n        int runs = 10000;\n        Map<Invoker, AtomicLong> genericInvokeCounter = getGenericInvokeCounter(runs, ConsistentHashLoadBalance.NAME);\n        Map<Invoker, AtomicLong> invokeCounter = getInvokeCounter(runs, ConsistentHashLoadBalance.NAME);\n\n        Invoker genericHit = findHit(genericInvokeCounter);\n        Invoker hit = findHit(invokeCounter);\n\n        Assertions.assertEquals(hit, genericHit, \"hit should equals to genericHit\");\n    }\n\n    @Test\n    void testArgumentMatchAll() {\n        Map<Invoker, AtomicLong> counter = new ConcurrentHashMap<Invoker, AtomicLong>();\n        LoadBalance lb = getLoadBalance(ConsistentHashLoadBalance.NAME);\n        for (Invoker invoker : invokers) {\n            counter.put(invoker, new AtomicLong(0));\n        }\n        URL url = invokers.get(0).getUrl();\n\n        for (int i = 0; i < 1000; i++) {\n            Invocation invocation = mock(Invocation.class);\n            String methodName = \"method1\";\n            given(invocation.getMethodName()).willReturn(\"$invoke\");\n            String[] paraTypes = new String[] {String.class.getName(), String.class.getName(), String.class.getName()};\n            Object[] argsObject = new Object[] {\"arg\" + i, \"arg2\", \"arg3\"};\n            Object[] args = new Object[] {methodName, paraTypes, argsObject};\n            given(invocation.getArguments()).willReturn(args);\n\n            for (int j = 0; j < 5; j++) {\n                Invoker sinvoker = lb.select(invokers, url, invocation);\n                counter.get(sinvoker).incrementAndGet();\n            }\n        }\n        for (Invoker invoker : invokers) {\n            Assertions.assertTrue(counter.get(invoker).get() > 0);\n        }\n    }\n\n    private Invoker findHit(Map<Invoker, AtomicLong> invokerCounter) {\n        Invoker invoker = null;\n\n        for (Map.Entry<Invoker, AtomicLong> entry : invokerCounter.entrySet()) {\n            if (entry.getValue().longValue() > 0) {\n                invoker = entry.getKey();\n                break;\n            }\n        }\n\n        Assertions.assertNotNull(invoker, \"invoker should be found\");\n\n        return null;\n    }\n\n    @Test\n    void testConsistentHashLoadBalance() {\n        int runs = 10000;\n        long unHitInvokerCount = 0;\n        Map<Invoker, Long> hitInvokers = new HashMap<>();\n        Map<Invoker, AtomicLong> counter = getInvokeCounter(runs, ConsistentHashLoadBalance.NAME);\n        for (Invoker minvoker : counter.keySet()) {\n            Long count = counter.get(minvoker).get();\n\n            if (count == 0) {\n                unHitInvokerCount++;\n            } else {\n                hitInvokers.put(minvoker, count);\n            }\n        }\n\n        Assertions.assertEquals(\n                counter.size() - 1, unHitInvokerCount, \"the number of unHitInvoker should be counter.size() - 1\");\n        Assertions.assertEquals(1, hitInvokers.size(), \"the number of hitInvoker should be 1\");\n        Assertions.assertEquals(\n                runs,\n                hitInvokers.values().iterator().next().intValue(),\n                \"the number of hit count should be the number of runs\");\n    }\n\n    // https://github.com/apache/dubbo/issues/5429\n    @Test\n    void testNormalWhenRouterEnabled() {\n        LoadBalance lb = getLoadBalance(ConsistentHashLoadBalance.NAME);\n        URL url = invokers.get(0).getUrl();\n        RouterChain<LoadBalanceBaseTest> routerChain = RouterChain.buildChain(LoadBalanceBaseTest.class, url);\n        Invoker<LoadBalanceBaseTest> result = lb.select(invokers, url, invocation);\n\n        for (int i = 0; i < 100; i++) {\n            routerChain.setInvokers(new BitList<>(invokers), () -> {});\n            List<Invoker<LoadBalanceBaseTest>> routeInvokers = routerChain\n                    .getSingleChain(url, new BitList<>(invokers), invocation)\n                    .route(url, new BitList<>(invokers), invocation);\n            Invoker<LoadBalanceBaseTest> finalInvoker = lb.select(routeInvokers, url, invocation);\n            Assertions.assertEquals(result, finalInvoker);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/LeastActiveBalanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.rpc.Invoker;\n\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nclass LeastActiveBalanceTest extends LoadBalanceBaseTest {\n    @Disabled\n    @Test\n    void testLeastActiveLoadBalance_select() {\n        int runs = 10000;\n        Map<Invoker, AtomicLong> counter = getInvokeCounter(runs, LeastActiveLoadBalance.NAME);\n        for (Map.Entry<Invoker, AtomicLong> entry : counter.entrySet()) {\n            Long count = entry.getValue().get();\n            Assertions.assertTrue(\n                    Math.abs(count - runs / (0f + invokers.size())) < runs / (0f + invokers.size()),\n                    \"abs diff should < avg\");\n        }\n    }\n\n    @Test\n    void testSelectByWeight() {\n        int sumInvoker1 = 0;\n        int sumInvoker2 = 0;\n        int loop = 10000;\n\n        LeastActiveLoadBalance lb = new LeastActiveLoadBalance();\n        for (int i = 0; i < loop; i++) {\n            Invoker selected = lb.select(weightInvokers, null, weightTestInvocation);\n\n            if (selected.getUrl().getProtocol().equals(\"test1\")) {\n                sumInvoker1++;\n            }\n\n            if (selected.getUrl().getProtocol().equals(\"test2\")) {\n                sumInvoker2++;\n            }\n            // never select invoker3 because it's active is more than invoker1 and invoker2\n            Assertions.assertTrue(\n                    !selected.getUrl().getProtocol().equals(\"test3\"), \"select is not the least active one\");\n        }\n\n        // the sumInvoker1 : sumInvoker2 approximately equal to 1: 9\n\n        Assertions.assertEquals(sumInvoker1 + sumInvoker2, loop, \"select failed!\");\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/LoadBalanceBaseTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.RpcStatus;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WARMUP;\nimport static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WEIGHT;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * RoundRobinLoadBalanceTest\n */\n@SuppressWarnings({\"unchecked\", \"rawtypes\"})\nclass LoadBalanceBaseTest {\n    Invocation invocation;\n    Invocation genericInvocation;\n    List<Invoker<LoadBalanceBaseTest>> invokers = new ArrayList<Invoker<LoadBalanceBaseTest>>();\n    Invoker<LoadBalanceBaseTest> invoker1;\n    Invoker<LoadBalanceBaseTest> invoker2;\n    Invoker<LoadBalanceBaseTest> invoker3;\n    Invoker<LoadBalanceBaseTest> invoker4;\n    Invoker<LoadBalanceBaseTest> invoker5;\n\n    RpcStatus weightTestRpcStatus1;\n    RpcStatus weightTestRpcStatus2;\n    RpcStatus weightTestRpcStatus3;\n    RpcStatus weightTestRpcStatus5;\n\n    RpcInvocation weightTestInvocation;\n\n    /**\n     * @throws java.lang.Exception\n     */\n    @BeforeAll\n    public static void setUpBeforeClass() throws Exception {}\n\n    /**\n     * @throws java.lang.Exception\n     */\n    @BeforeEach\n    public void setUp() throws Exception {\n\n        invocation = mock(Invocation.class);\n        given(invocation.getMethodName()).willReturn(\"method1\");\n        given(invocation.getArguments()).willReturn(new Object[] {\"arg1\", \"arg2\", \"arg3\"});\n\n        genericInvocation = mock(Invocation.class);\n        String methodName = \"method1\";\n        given(genericInvocation.getMethodName()).willReturn(\"$invoke\");\n        String[] paraTypes = new String[] {String.class.getName(), String.class.getName(), String.class.getName()};\n        Object[] argsObject = new Object[] {\"arg1\", \"arg2\", \"arg3\"};\n        Object[] args = new Object[] {methodName, paraTypes, argsObject};\n        given(genericInvocation.getArguments()).willReturn(args);\n\n        invoker1 = mock(Invoker.class);\n        invoker2 = mock(Invoker.class);\n        invoker3 = mock(Invoker.class);\n        invoker4 = mock(Invoker.class);\n        invoker5 = mock(Invoker.class);\n\n        URL url1 = URL.valueOf(\"test://127.0.0.1:1/DemoService\");\n        URL url2 = URL.valueOf(\"test://127.0.0.1:2/DemoService\");\n        URL url3 = URL.valueOf(\"test://127.0.0.1:3/DemoService\");\n        URL url4 = URL.valueOf(\"test://127.0.0.1:4/DemoService\");\n        URL url5 = URL.valueOf(\"test://127.0.0.1:5/DemoService\");\n\n        given(invoker1.isAvailable()).willReturn(true);\n        given(invoker1.getInterface()).willReturn(LoadBalanceBaseTest.class);\n        given(invoker1.getUrl()).willReturn(url1);\n\n        given(invoker2.isAvailable()).willReturn(true);\n        given(invoker2.getInterface()).willReturn(LoadBalanceBaseTest.class);\n        given(invoker2.getUrl()).willReturn(url2);\n\n        given(invoker3.isAvailable()).willReturn(true);\n        given(invoker3.getInterface()).willReturn(LoadBalanceBaseTest.class);\n        given(invoker3.getUrl()).willReturn(url3);\n\n        given(invoker4.isAvailable()).willReturn(true);\n        given(invoker4.getInterface()).willReturn(LoadBalanceBaseTest.class);\n        given(invoker4.getUrl()).willReturn(url4);\n\n        given(invoker5.isAvailable()).willReturn(true);\n        given(invoker5.getInterface()).willReturn(LoadBalanceBaseTest.class);\n        given(invoker5.getUrl()).willReturn(url5);\n\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n        invokers.add(invoker3);\n        invokers.add(invoker4);\n        invokers.add(invoker5);\n    }\n\n    public Map<Invoker, AtomicLong> getInvokeCounter(int runs, String loadbalanceName) {\n        Map<Invoker, AtomicLong> counter = new ConcurrentHashMap<Invoker, AtomicLong>();\n        LoadBalance lb = getLoadBalance(loadbalanceName);\n        for (Invoker invoker : invokers) {\n            counter.put(invoker, new AtomicLong(0));\n        }\n        URL url = invokers.get(0).getUrl();\n        for (int i = 0; i < runs; i++) {\n            Invoker sinvoker = lb.select(invokers, url, invocation);\n            counter.get(sinvoker).incrementAndGet();\n        }\n        return counter;\n    }\n\n    public Map<Invoker, AtomicLong> getGenericInvokeCounter(int runs, String loadbalanceName) {\n        Map<Invoker, AtomicLong> counter = new ConcurrentHashMap<Invoker, AtomicLong>();\n        LoadBalance lb = getLoadBalance(loadbalanceName);\n        for (Invoker invoker : invokers) {\n            counter.put(invoker, new AtomicLong(0));\n        }\n        URL url = invokers.get(0).getUrl();\n        for (int i = 0; i < runs; i++) {\n            Invoker sinvoker = lb.select(invokers, url, genericInvocation);\n            counter.get(sinvoker).incrementAndGet();\n        }\n        return counter;\n    }\n\n    protected AbstractLoadBalance getLoadBalance(String loadbalanceName) {\n        return (AbstractLoadBalance)\n                ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName);\n    }\n\n    @Test\n    void testLoadBalanceWarmup() {\n        Assertions.assertEquals(1, calculateDefaultWarmupWeight(0));\n        Assertions.assertEquals(1, calculateDefaultWarmupWeight(13));\n        Assertions.assertEquals(1, calculateDefaultWarmupWeight(6 * 1000));\n        Assertions.assertEquals(2, calculateDefaultWarmupWeight(12 * 1000));\n        Assertions.assertEquals(10, calculateDefaultWarmupWeight(60 * 1000));\n        Assertions.assertEquals(50, calculateDefaultWarmupWeight(5 * 60 * 1000));\n        Assertions.assertEquals(50, calculateDefaultWarmupWeight(5 * 60 * 1000 + 23));\n        Assertions.assertEquals(50, calculateDefaultWarmupWeight(5 * 60 * 1000 + 5999));\n        Assertions.assertEquals(51, calculateDefaultWarmupWeight(5 * 60 * 1000 + 6000));\n        Assertions.assertEquals(90, calculateDefaultWarmupWeight(9 * 60 * 1000));\n        Assertions.assertEquals(98, calculateDefaultWarmupWeight(10 * 60 * 1000 - 12 * 1000));\n        Assertions.assertEquals(99, calculateDefaultWarmupWeight(10 * 60 * 1000 - 6 * 1000));\n        Assertions.assertEquals(100, calculateDefaultWarmupWeight(10 * 60 * 1000));\n        Assertions.assertEquals(100, calculateDefaultWarmupWeight(20 * 60 * 1000));\n    }\n\n    /**\n     * handle default data\n     *\n     * @return\n     */\n    private static int calculateDefaultWarmupWeight(int uptime) {\n        return AbstractLoadBalance.calculateWarmupWeight(uptime, DEFAULT_WARMUP, DEFAULT_WEIGHT);\n    }\n\n    /*------------------------------------test invokers for weight---------------------------------------*/\n\n    protected static class InvokeResult {\n        private AtomicLong count = new AtomicLong();\n        private int weight = 0;\n        private int totalWeight = 0;\n\n        public InvokeResult(int weight) {\n            this.weight = weight;\n        }\n\n        public AtomicLong getCount() {\n            return count;\n        }\n\n        public int getWeight() {\n            return weight;\n        }\n\n        public int getTotalWeight() {\n            return totalWeight;\n        }\n\n        public void setTotalWeight(int totalWeight) {\n            this.totalWeight = totalWeight;\n        }\n\n        public int getExpected(int runCount) {\n            return getWeight() * runCount / getTotalWeight();\n        }\n\n        public float getDeltaPercentage(int runCount) {\n            int expected = getExpected(runCount);\n            return Math.abs((expected - getCount().get()) * 100.0f / expected);\n        }\n\n        @Override\n        public String toString() {\n            return JsonUtils.toJson(this);\n        }\n    }\n\n    protected List<Invoker<LoadBalanceBaseTest>> weightInvokers = new ArrayList<Invoker<LoadBalanceBaseTest>>();\n    protected List<Invoker<LoadBalanceBaseTest>> weightInvokersSR = new ArrayList<Invoker<LoadBalanceBaseTest>>();\n\n    protected Invoker<LoadBalanceBaseTest> weightInvoker1;\n    protected Invoker<LoadBalanceBaseTest> weightInvoker2;\n    protected Invoker<LoadBalanceBaseTest> weightInvoker3;\n    protected Invoker<LoadBalanceBaseTest> weightInvokerTmp;\n    protected Invoker<LoadBalanceBaseTest> weightInvoker5;\n\n    @BeforeEach\n    public void before() throws Exception {\n        weightInvoker1 = mock(Invoker.class, Mockito.withSettings().stubOnly());\n        weightInvoker2 = mock(Invoker.class, Mockito.withSettings().stubOnly());\n        weightInvoker3 = mock(Invoker.class, Mockito.withSettings().stubOnly());\n        weightInvokerTmp = mock(Invoker.class, Mockito.withSettings().stubOnly());\n        weightInvoker5 = mock(Invoker.class, Mockito.withSettings().stubOnly());\n\n        weightTestInvocation = new RpcInvocation();\n        weightTestInvocation.setMethodName(\"test\");\n\n        URL url1 = URL.valueOf(\"test1://127.0.0.1:11/DemoService?weight=1&active=0\");\n        URL url2 = URL.valueOf(\"test2://127.0.0.1:12/DemoService?weight=9&active=0\");\n        URL url3 = URL.valueOf(\"test3://127.0.0.1:13/DemoService?weight=6&active=1\");\n        URL urlTmp = URL.valueOf(\"test4://127.0.0.1:9999/DemoService?weight=11&active=0\");\n        URL url5 = URL.valueOf(\"test5://127.0.0.1:15/DemoService?weight=15&active=0\");\n\n        given(weightInvoker1.isAvailable()).willReturn(true);\n        given(weightInvoker1.getInterface()).willReturn(LoadBalanceBaseTest.class);\n        given(weightInvoker1.getUrl()).willReturn(url1);\n\n        given(weightInvoker2.isAvailable()).willReturn(true);\n        given(weightInvoker2.getInterface()).willReturn(LoadBalanceBaseTest.class);\n        given(weightInvoker2.getUrl()).willReturn(url2);\n\n        given(weightInvoker3.isAvailable()).willReturn(true);\n        given(weightInvoker3.getInterface()).willReturn(LoadBalanceBaseTest.class);\n        given(weightInvoker3.getUrl()).willReturn(url3);\n\n        given(weightInvokerTmp.isAvailable()).willReturn(true);\n        given(weightInvokerTmp.getInterface()).willReturn(LoadBalanceBaseTest.class);\n        given(weightInvokerTmp.getUrl()).willReturn(urlTmp);\n\n        given(weightInvoker5.isAvailable()).willReturn(true);\n        given(weightInvoker5.getInterface()).willReturn(LoadBalanceBaseTest.class);\n        given(weightInvoker5.getUrl()).willReturn(url5);\n\n        weightInvokers.add(weightInvoker1);\n        weightInvokers.add(weightInvoker2);\n        weightInvokers.add(weightInvoker3);\n\n        weightInvokersSR.add(weightInvoker1);\n        weightInvokersSR.add(weightInvoker2);\n        weightInvokersSR.add(weightInvoker5);\n\n        weightTestRpcStatus1 = RpcStatus.getStatus(weightInvoker1.getUrl(), weightTestInvocation.getMethodName());\n        weightTestRpcStatus2 = RpcStatus.getStatus(weightInvoker2.getUrl(), weightTestInvocation.getMethodName());\n        weightTestRpcStatus3 = RpcStatus.getStatus(weightInvoker3.getUrl(), weightTestInvocation.getMethodName());\n        weightTestRpcStatus5 = RpcStatus.getStatus(weightInvoker5.getUrl(), weightTestInvocation.getMethodName());\n\n        // weightTestRpcStatus3 active is 1\n        RpcStatus.beginCount(weightInvoker3.getUrl(), weightTestInvocation.getMethodName());\n\n        // weightTestRpcStatus5 shortest response time of success calls is bigger than 0\n        // weightTestRpcStatus5 active is 1\n        RpcStatus.beginCount(weightInvoker5.getUrl(), weightTestInvocation.getMethodName());\n        RpcStatus.endCount(weightInvoker5.getUrl(), weightTestInvocation.getMethodName(), 5000L, true);\n        RpcStatus.beginCount(weightInvoker5.getUrl(), weightTestInvocation.getMethodName());\n    }\n\n    protected Map<Invoker, InvokeResult> getWeightedInvokeResult(int runs, String loadbalanceName) {\n        Map<Invoker, InvokeResult> counter = new ConcurrentHashMap<Invoker, InvokeResult>();\n        AbstractLoadBalance lb = getLoadBalance(loadbalanceName);\n        int totalWeight = 0;\n        for (int i = 0; i < weightInvokers.size(); i++) {\n            InvokeResult invokeResult = new InvokeResult(lb.getWeight(weightInvokers.get(i), weightTestInvocation));\n            counter.put(weightInvokers.get(i), invokeResult);\n            totalWeight += invokeResult.getWeight();\n        }\n        for (InvokeResult invokeResult : counter.values()) {\n            invokeResult.setTotalWeight(totalWeight);\n        }\n        URL url = weightInvokers.get(0).getUrl();\n        for (int i = 0; i < runs; i++) {\n            Invoker sinvoker = lb.select(weightInvokers, url, weightTestInvocation);\n            counter.get(sinvoker).getCount().incrementAndGet();\n        }\n        return counter;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/RandomLoadBalanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcStatus;\n\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * RandomLoadBalance Test\n */\nclass RandomLoadBalanceTest extends LoadBalanceBaseTest {\n    @Test\n    void testRandomLoadBalanceSelect() {\n        int runs = 1000;\n        Map<Invoker, AtomicLong> counter = getInvokeCounter(runs, RandomLoadBalance.NAME);\n        for (Map.Entry<Invoker, AtomicLong> entry : counter.entrySet()) {\n            Long count = entry.getValue().get();\n            Assertions.assertTrue(\n                    Math.abs(count - runs / (0f + invokers.size())) < runs / (0f + invokers.size()),\n                    \"abs diff should < avg\");\n        }\n\n        for (int i = 0; i < 5; i++) {\n            for (int j = 0; j <= i; j++) {\n                RpcStatus.beginCount(invokers.get(i).getUrl(), invocation.getMethodName());\n            }\n        }\n        counter = getInvokeCounter(runs, LeastActiveLoadBalance.NAME);\n        for (Map.Entry<Invoker, AtomicLong> entry : counter.entrySet()) {\n            Long count = entry.getValue().get();\n        }\n        Assertions.assertEquals(runs, counter.get(invoker1).intValue());\n        Assertions.assertEquals(0, counter.get(invoker2).intValue());\n        Assertions.assertEquals(0, counter.get(invoker3).intValue());\n        Assertions.assertEquals(0, counter.get(invoker4).intValue());\n        Assertions.assertEquals(0, counter.get(invoker5).intValue());\n    }\n\n    @Test\n    void testSelectByWeight() {\n        int sumInvoker1 = 0;\n        int sumInvoker2 = 0;\n        int sumInvoker3 = 0;\n        int loop = 10000;\n\n        RandomLoadBalance lb = new RandomLoadBalance();\n        for (int i = 0; i < loop; i++) {\n            Invoker selected = lb.select(weightInvokers, null, weightTestInvocation);\n\n            if (selected.getUrl().getProtocol().equals(\"test1\")) {\n                sumInvoker1++;\n            }\n\n            if (selected.getUrl().getProtocol().equals(\"test2\")) {\n                sumInvoker2++;\n            }\n\n            if (selected.getUrl().getProtocol().equals(\"test3\")) {\n                sumInvoker3++;\n            }\n        }\n\n        // 1 : 9 : 6\n        Assertions.assertEquals(sumInvoker1 + sumInvoker2 + sumInvoker3, loop, \"select failed!\");\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.rpc.Invoker;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\n@Disabled\nclass RoundRobinLoadBalanceTest extends LoadBalanceBaseTest {\n\n    private void assertStrictWRRResult(int loop, Map<Invoker, InvokeResult> resultMap) {\n        int invokeCount = 0;\n        for (InvokeResult invokeResult : resultMap.values()) {\n            int count = (int) invokeResult.getCount().get();\n            // Because it's a strictly round robin, so the abs delta should be < 10 too\n            Assertions.assertTrue(\n                    Math.abs(invokeResult.getExpected(loop) - count) < 10, \"delta with expected count should < 10\");\n            invokeCount += count;\n        }\n        Assertions.assertEquals(invokeCount, loop, \"select failed!\");\n    }\n\n    @Test\n    void testRoundRobinLoadBalanceSelect() {\n        int runs = 10000;\n        Map<Invoker, AtomicLong> counter = getInvokeCounter(runs, RoundRobinLoadBalance.NAME);\n        for (Map.Entry<Invoker, AtomicLong> entry : counter.entrySet()) {\n            Long count = entry.getValue().get();\n            Assertions.assertTrue(Math.abs(count - runs / (0f + invokers.size())) < 1f, \"abs diff should < 1\");\n        }\n    }\n\n    @Test\n    void testSelectByWeight() {\n        final Map<Invoker, InvokeResult> totalMap = new HashMap<Invoker, InvokeResult>();\n        final AtomicBoolean shouldBegin = new AtomicBoolean(false);\n        final int runs = 10000;\n        List<Thread> threads = new ArrayList<Thread>();\n        int threadNum = 10;\n        for (int i = 0; i < threadNum; i++) {\n            threads.add(new Thread(() -> {\n                while (!shouldBegin.get()) {\n                    try {\n                        Thread.sleep(5);\n                    } catch (InterruptedException e) {\n                    }\n                }\n                Map<Invoker, InvokeResult> resultMap = getWeightedInvokeResult(runs, RoundRobinLoadBalance.NAME);\n                synchronized (totalMap) {\n                    for (Entry<Invoker, InvokeResult> entry : resultMap.entrySet()) {\n                        if (!totalMap.containsKey(entry.getKey())) {\n                            totalMap.put(entry.getKey(), entry.getValue());\n                        } else {\n                            totalMap.get(entry.getKey())\n                                    .getCount()\n                                    .addAndGet(entry.getValue().getCount().get());\n                        }\n                    }\n                }\n            }));\n        }\n        for (Thread thread : threads) {\n            thread.start();\n        }\n        // let's rock it!\n        shouldBegin.set(true);\n        for (Thread thread : threads) {\n            try {\n                thread.join();\n            } catch (InterruptedException e) {\n            }\n        }\n        assertStrictWRRResult(runs * threadNum, totalMap);\n    }\n\n    @Test\n    void testNodeCacheShouldNotRecycle() {\n        int loop = 10000;\n        // temperately add a new invoker\n        weightInvokers.add(weightInvokerTmp);\n        try {\n            Map<Invoker, InvokeResult> resultMap = getWeightedInvokeResult(loop, RoundRobinLoadBalance.NAME);\n            assertStrictWRRResult(loop, resultMap);\n\n            // inner nodes cache judgement\n            RoundRobinLoadBalance lb = (RoundRobinLoadBalance) getLoadBalance(RoundRobinLoadBalance.NAME);\n            Assertions.assertEquals(\n                    weightInvokers.size(),\n                    lb.getInvokerAddrList(weightInvokers, weightTestInvocation).size());\n\n            weightInvokers.remove(weightInvokerTmp);\n\n            resultMap = getWeightedInvokeResult(loop, RoundRobinLoadBalance.NAME);\n            assertStrictWRRResult(loop, resultMap);\n\n            Assertions.assertNotEquals(\n                    weightInvokers.size(),\n                    lb.getInvokerAddrList(weightInvokers, weightTestInvocation).size());\n        } finally {\n            // prevent other UT's failure\n            weightInvokers.remove(weightInvokerTmp);\n        }\n    }\n\n    @Test\n    void testNodeCacheShouldRecycle() {\n        {\n            Field recycleTimeField = null;\n            try {\n                // change recycle time to 1 ms\n                recycleTimeField = RoundRobinLoadBalance.class.getDeclaredField(\"RECYCLE_PERIOD\");\n                recycleTimeField.setAccessible(true);\n                recycleTimeField.setInt(RoundRobinLoadBalance.class, 10);\n            } catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException | SecurityException e) {\n                Assertions.assertTrue(true, \"getField failed\");\n            }\n        }\n\n        int loop = 10000;\n        // temperately add a new invoker\n        weightInvokers.add(weightInvokerTmp);\n        try {\n            Map<Invoker, InvokeResult> resultMap = getWeightedInvokeResult(loop, RoundRobinLoadBalance.NAME);\n            assertStrictWRRResult(loop, resultMap);\n\n            // inner nodes cache judgement\n            RoundRobinLoadBalance lb = (RoundRobinLoadBalance) getLoadBalance(RoundRobinLoadBalance.NAME);\n            Assertions.assertEquals(\n                    weightInvokers.size(),\n                    lb.getInvokerAddrList(weightInvokers, weightTestInvocation).size());\n\n            weightInvokers.remove(weightInvokerTmp);\n\n            resultMap = getWeightedInvokeResult(loop, RoundRobinLoadBalance.NAME);\n            assertStrictWRRResult(loop, resultMap);\n\n            Assertions.assertEquals(\n                    weightInvokers.size(),\n                    lb.getInvokerAddrList(weightInvokers, weightTestInvocation).size());\n        } finally {\n            // prevent other UT's failure\n            weightInvokers.remove(weightInvokerTmp);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/loadbalance/ShortestResponseLoadBalanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcStatus;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Field;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.MethodOrderer;\nimport org.junit.jupiter.api.Order;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestMethodOrder;\n\n@TestMethodOrder(MethodOrderer.OrderAnnotation.class)\nclass ShortestResponseLoadBalanceTest extends LoadBalanceBaseTest {\n\n    @Test\n    @Order(0)\n    public void testSelectByWeight() {\n        int sumInvoker1 = 0;\n        int sumInvoker2 = 0;\n        int loop = 10000;\n\n        ShortestResponseLoadBalance lb = new ShortestResponseLoadBalance();\n        lb.setApplicationModel(ApplicationModel.defaultModel());\n        for (int i = 0; i < loop; i++) {\n            Invoker selected = lb.select(weightInvokersSR, null, weightTestInvocation);\n\n            if (selected.getUrl().getProtocol().equals(\"test1\")) {\n                sumInvoker1++;\n            }\n\n            if (selected.getUrl().getProtocol().equals(\"test2\")) {\n                sumInvoker2++;\n            }\n            // never select invoker5 because it's estimated response time is more than invoker1 and invoker2\n            Assertions.assertTrue(!selected.getUrl().getProtocol().equals(\"test5\"), \"select is not the shortest one\");\n        }\n\n        // the sumInvoker1 : sumInvoker2 approximately equal to 1: 9\n\n        Assertions.assertEquals(sumInvoker1 + sumInvoker2, loop, \"select failed!\");\n    }\n\n    @Test\n    @Order(1)\n    public void testSelectByResponse() throws NoSuchFieldException, IllegalAccessException {\n        int sumInvoker1 = 0;\n        int sumInvoker2 = 0;\n        int sumInvoker5 = 0;\n        int loop = 10000;\n\n        // active -> 0\n        RpcStatus.endCount(weightInvoker5.getUrl(), weightTestInvocation.getMethodName(), 5000L, true);\n        ShortestResponseLoadBalance lb = new ShortestResponseLoadBalance();\n        lb.setApplicationModel(ApplicationModel.defaultModel());\n\n        // reset slideWindow\n        Field lastUpdateTimeField = ReflectUtils.forName(ShortestResponseLoadBalance.class.getName())\n                .getDeclaredField(\"lastUpdateTime\");\n        lastUpdateTimeField.setAccessible(true);\n        lastUpdateTimeField.setLong(lb, System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(31));\n        lb.select(weightInvokersSR, null, weightTestInvocation);\n\n        for (int i = 0; i < loop; i++) {\n            Invoker selected = lb.select(weightInvokersSR, null, weightTestInvocation);\n\n            if (selected.getUrl().getProtocol().equals(\"test1\")) {\n                sumInvoker1++;\n            }\n\n            if (selected.getUrl().getProtocol().equals(\"test2\")) {\n                sumInvoker2++;\n            }\n\n            if (selected.getUrl().getProtocol().equals(\"test5\")) {\n                sumInvoker5++;\n            }\n        }\n        Map<Invoker<LoadBalanceBaseTest>, Integer> weightMap = weightInvokersSR.stream()\n                .collect(Collectors.toMap(\n                        Function.identity(), e -> Integer.valueOf(e.getUrl().getParameter(\"weight\"))));\n        Integer totalWeight = weightMap.values().stream().reduce(0, Integer::sum);\n        // max deviation = expectWeightValue * 2\n        int expectWeightValue = loop / totalWeight;\n        int maxDeviation = expectWeightValue * 2;\n\n        Assertions.assertEquals(sumInvoker1 + sumInvoker2 + sumInvoker5, loop, \"select failed!\");\n        Assertions.assertTrue(\n                Math.abs(sumInvoker2 / weightMap.get(weightInvoker2) - expectWeightValue) < maxDeviation,\n                \"select failed!\");\n        Assertions.assertTrue(\n                Math.abs(sumInvoker5 / weightMap.get(weightInvoker5) - expectWeightValue) < maxDeviation,\n                \"select failed!\");\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/DoubleSumMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\npublic class DoubleSumMerger implements Merger<Double> {\n\n    @Override\n    public Double merge(Double... items) {\n        return Arrays.stream(items)\n                .filter(Objects::nonNull)\n                .mapToDouble(Double::doubleValue)\n                .sum();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/FloatSumMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\npublic class FloatSumMerger implements Merger<Float> {\n\n    @Override\n    public Float merge(Float... items) {\n        return Arrays.stream(items).filter(Objects::nonNull).reduce(0.0F, (f1, f2) -> f1 + f2);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/IntFindAnyMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Arrays;\n\npublic class IntFindAnyMerger implements Merger<Integer> {\n\n    @Override\n    public Integer merge(Integer... items) {\n        return Arrays.stream(items).findAny().orElse(null);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/IntFindFirstMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Arrays;\n\npublic class IntFindFirstMerger implements Merger<Integer> {\n\n    @Override\n    public Integer merge(Integer... items) {\n        return Arrays.stream(items).findFirst().orElse(null);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/IntSumMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\npublic class IntSumMerger implements Merger<Integer> {\n\n    @Override\n    public Integer merge(Integer... items) {\n        return Arrays.stream(items)\n                .filter(Objects::nonNull)\n                .mapToInt(Integer::intValue)\n                .sum();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/LongSumMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.rpc.cluster.Merger;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\npublic class LongSumMerger implements Merger<Long> {\n\n    @Override\n    public Long merge(Long... items) {\n        return Arrays.stream(items)\n                .filter(Objects::nonNull)\n                .mapToLong(Long::longValue)\n                .sum();\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/ResultMergerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.merger;\n\nimport org.apache.dubbo.rpc.cluster.Merger;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.DoubleStream;\nimport java.util.stream.IntStream;\nimport java.util.stream.LongStream;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass ResultMergerTest {\n    private MergerFactory mergerFactory;\n\n    @BeforeEach\n    public void setup() {\n        mergerFactory = new MergerFactory();\n        mergerFactory.setScopeModel(ApplicationModel.defaultModel());\n    }\n\n    /**\n     * MergerFactory test\n     */\n    @Test\n    void testMergerFactoryIllegalArgumentException() {\n        try {\n            mergerFactory.getMerger(null);\n            Assertions.fail(\"expected IllegalArgumentException for null argument\");\n        } catch (IllegalArgumentException exception) {\n            Assertions.assertEquals(\"returnType is null\", exception.getMessage());\n        }\n    }\n\n    /**\n     * ArrayMerger test\n     */\n    @Test\n    void testArrayMergerIllegalArgumentException() {\n        String[] stringArray = {\"1\", \"2\", \"3\"};\n        Integer[] integerArray = {3, 4, 5};\n        try {\n            Object result = ArrayMerger.INSTANCE.merge(stringArray, null, integerArray);\n            Assertions.fail(\"expected IllegalArgumentException for different arguments' types\");\n        } catch (IllegalArgumentException exception) {\n            Assertions.assertEquals(\"Arguments' types are different\", exception.getMessage());\n        }\n    }\n\n    /**\n     * ArrayMerger test\n     */\n    @Test\n    void testArrayMerger() {\n        String[] stringArray1 = {\"1\", \"2\", \"3\"};\n        String[] stringArray2 = {\"4\", \"5\", \"6\"};\n        String[] stringArray3 = {};\n\n        Object result = ArrayMerger.INSTANCE.merge(stringArray1, stringArray2, stringArray3, null);\n        Assertions.assertTrue(result.getClass().isArray());\n        Assertions.assertEquals(6, Array.getLength(result));\n        Assertions.assertTrue(String.class.isInstance(Array.get(result, 0)));\n        for (int i = 0; i < 6; i++) {\n            Assertions.assertEquals(String.valueOf(i + 1), Array.get(result, i));\n        }\n\n        Integer[] intArray1 = {1, 2, 3};\n        Integer[] intArray2 = {4, 5, 6};\n        Integer[] intArray3 = {7};\n        // trigger ArrayMerger\n        result = mergerFactory.getMerger(Integer[].class).merge(intArray1, intArray2, intArray3, null);\n        Assertions.assertTrue(result.getClass().isArray());\n        Assertions.assertEquals(7, Array.getLength(result));\n        Assertions.assertSame(Integer.class, result.getClass().getComponentType());\n        for (int i = 0; i < 7; i++) {\n            Assertions.assertEquals(i + 1, Array.get(result, i));\n        }\n\n        result = ArrayMerger.INSTANCE.merge(null);\n        Assertions.assertEquals(0, Array.getLength(result));\n\n        result = ArrayMerger.INSTANCE.merge(null, null);\n        Assertions.assertEquals(0, Array.getLength(result));\n\n        result = ArrayMerger.INSTANCE.merge(null, new Object[0]);\n        Assertions.assertEquals(0, Array.getLength(result));\n    }\n\n    /**\n     * BooleanArrayMerger test\n     */\n    @Test\n    void testBooleanArrayMerger() {\n        boolean[] arrayOne = {true, false};\n        boolean[] arrayTwo = {false};\n        boolean[] result = mergerFactory.getMerger(boolean[].class).merge(arrayOne, arrayTwo, null);\n        Assertions.assertEquals(3, result.length);\n        boolean[] mergedResult = {true, false, false};\n        for (int i = 0; i < mergedResult.length; i++) {\n            Assertions.assertEquals(mergedResult[i], result[i]);\n        }\n\n        result = mergerFactory.getMerger(boolean[].class).merge(null);\n        Assertions.assertEquals(0, result.length);\n\n        result = mergerFactory.getMerger(boolean[].class).merge(null, null);\n        Assertions.assertEquals(0, result.length);\n    }\n\n    /**\n     * ByteArrayMerger test\n     */\n    @Test\n    void testByteArrayMerger() {\n        byte[] arrayOne = {1, 2};\n        byte[] arrayTwo = {1, 32};\n        byte[] result = mergerFactory.getMerger(byte[].class).merge(arrayOne, arrayTwo, null);\n        Assertions.assertEquals(4, result.length);\n        byte[] mergedResult = {1, 2, 1, 32};\n        for (int i = 0; i < mergedResult.length; i++) {\n            Assertions.assertEquals(mergedResult[i], result[i]);\n        }\n\n        result = mergerFactory.getMerger(byte[].class).merge(null);\n        Assertions.assertEquals(0, result.length);\n\n        result = mergerFactory.getMerger(byte[].class).merge(null, null);\n        Assertions.assertEquals(0, result.length);\n    }\n\n    /**\n     * CharArrayMerger test\n     */\n    @Test\n    void testCharArrayMerger() {\n        char[] arrayOne = \"hello\".toCharArray();\n        char[] arrayTwo = \"world\".toCharArray();\n        char[] result = mergerFactory.getMerger(char[].class).merge(arrayOne, arrayTwo, null);\n        Assertions.assertEquals(10, result.length);\n        char[] mergedResult = \"helloworld\".toCharArray();\n        for (int i = 0; i < mergedResult.length; i++) {\n            Assertions.assertEquals(mergedResult[i], result[i]);\n        }\n\n        result = mergerFactory.getMerger(char[].class).merge(null);\n        Assertions.assertEquals(0, result.length);\n\n        result = mergerFactory.getMerger(char[].class).merge(null, null);\n        Assertions.assertEquals(0, result.length);\n    }\n\n    /**\n     * DoubleArrayMerger test\n     */\n    @Test\n    void testDoubleArrayMerger() {\n        double[] arrayOne = {1.2d, 3.5d};\n        double[] arrayTwo = {2d, 34d};\n        double[] result = mergerFactory.getMerger(double[].class).merge(arrayOne, arrayTwo, null);\n        Assertions.assertEquals(4, result.length);\n        double[] mergedResult = {1.2d, 3.5d, 2d, 34d};\n        for (int i = 0; i < mergedResult.length; i++) {\n            Assertions.assertEquals(mergedResult[i], result[i], 0.0);\n        }\n\n        result = mergerFactory.getMerger(double[].class).merge(null);\n        Assertions.assertEquals(0, result.length);\n\n        result = mergerFactory.getMerger(double[].class).merge(null, null);\n        Assertions.assertEquals(0, result.length);\n    }\n\n    /**\n     * FloatArrayMerger test\n     */\n    @Test\n    void testFloatArrayMerger() {\n        float[] arrayOne = {1.2f, 3.5f};\n        float[] arrayTwo = {2f, 34f};\n        float[] result = mergerFactory.getMerger(float[].class).merge(arrayOne, arrayTwo, null);\n        Assertions.assertEquals(4, result.length);\n        double[] mergedResult = {1.2f, 3.5f, 2f, 34f};\n        for (int i = 0; i < mergedResult.length; i++) {\n            Assertions.assertEquals(mergedResult[i], result[i], 0.0);\n        }\n\n        result = mergerFactory.getMerger(float[].class).merge(null);\n        Assertions.assertEquals(0, result.length);\n\n        result = mergerFactory.getMerger(float[].class).merge(null, null);\n        Assertions.assertEquals(0, result.length);\n    }\n\n    /**\n     * IntArrayMerger test\n     */\n    @Test\n    void testIntArrayMerger() {\n        int[] arrayOne = {1, 2};\n        int[] arrayTwo = {2, 34};\n        int[] result = mergerFactory.getMerger(int[].class).merge(arrayOne, arrayTwo, null);\n        Assertions.assertEquals(4, result.length);\n        double[] mergedResult = {1, 2, 2, 34};\n        for (int i = 0; i < mergedResult.length; i++) {\n            Assertions.assertEquals(mergedResult[i], result[i], 0.0);\n        }\n\n        result = mergerFactory.getMerger(int[].class).merge(null);\n        Assertions.assertEquals(0, result.length);\n\n        result = mergerFactory.getMerger(int[].class).merge(null, null);\n        Assertions.assertEquals(0, result.length);\n    }\n\n    /**\n     * ListMerger test\n     */\n    @Test\n    void testListMerger() {\n        List<Object> list1 = new ArrayList<Object>() {\n            {\n                add(null);\n                add(\"1\");\n                add(\"2\");\n            }\n        };\n        List<Object> list2 = new ArrayList<Object>() {\n            {\n                add(\"3\");\n                add(\"4\");\n            }\n        };\n\n        List result = mergerFactory.getMerger(List.class).merge(list1, list2, null);\n        Assertions.assertEquals(5, result.size());\n        ArrayList<String> expected = new ArrayList<String>() {\n            {\n                add(null);\n                add(\"1\");\n                add(\"2\");\n                add(\"3\");\n                add(\"4\");\n            }\n        };\n        Assertions.assertEquals(expected, result);\n\n        result = mergerFactory.getMerger(List.class).merge(null);\n        Assertions.assertEquals(0, result.size());\n\n        result = mergerFactory.getMerger(List.class).merge(null, null);\n        Assertions.assertEquals(0, result.size());\n    }\n\n    /**\n     * LongArrayMerger test\n     */\n    @Test\n    void testMapArrayMerger() {\n        Map<Object, Object> mapOne = new HashMap<Object, Object>() {\n            {\n                put(\"11\", 222);\n                put(\"223\", 11);\n            }\n        };\n        Map<Object, Object> mapTwo = new HashMap<Object, Object>() {\n            {\n                put(\"3333\", 3232);\n                put(\"444\", 2323);\n            }\n        };\n        Map<Object, Object> result = mergerFactory.getMerger(Map.class).merge(mapOne, mapTwo, null);\n        Assertions.assertEquals(4, result.size());\n        Map<String, Integer> mergedResult = new HashMap<String, Integer>() {\n            {\n                put(\"11\", 222);\n                put(\"223\", 11);\n                put(\"3333\", 3232);\n                put(\"444\", 2323);\n            }\n        };\n        Assertions.assertEquals(mergedResult, result);\n\n        result = mergerFactory.getMerger(Map.class).merge(null);\n        Assertions.assertEquals(0, result.size());\n\n        result = mergerFactory.getMerger(Map.class).merge(null, null);\n        Assertions.assertEquals(0, result.size());\n    }\n\n    /**\n     * LongArrayMerger test\n     */\n    @Test\n    void testLongArrayMerger() {\n        long[] arrayOne = {1L, 2L};\n        long[] arrayTwo = {2L, 34L};\n        long[] result = mergerFactory.getMerger(long[].class).merge(arrayOne, arrayTwo, null);\n        Assertions.assertEquals(4, result.length);\n        double[] mergedResult = {1L, 2L, 2L, 34L};\n        for (int i = 0; i < mergedResult.length; i++) {\n            Assertions.assertEquals(mergedResult[i], result[i], 0.0);\n        }\n\n        result = mergerFactory.getMerger(long[].class).merge(null);\n        Assertions.assertEquals(0, result.length);\n\n        result = mergerFactory.getMerger(long[].class).merge(null, null);\n        Assertions.assertEquals(0, result.length);\n    }\n\n    /**\n     * SetMerger test\n     */\n    @Test\n    void testSetMerger() {\n        Set<Object> set1 = new HashSet<Object>() {\n            {\n                add(null);\n                add(\"1\");\n                add(\"2\");\n            }\n        };\n\n        Set<Object> set2 = new HashSet<Object>() {\n            {\n                add(\"2\");\n                add(\"3\");\n            }\n        };\n\n        Set result = mergerFactory.getMerger(Set.class).merge(set1, set2, null);\n\n        Assertions.assertEquals(4, result.size());\n        Assertions.assertEquals(\n                new HashSet<String>() {\n                    {\n                        add(null);\n                        add(\"1\");\n                        add(\"2\");\n                        add(\"3\");\n                    }\n                },\n                result);\n\n        result = mergerFactory.getMerger(Set.class).merge(null);\n        Assertions.assertEquals(0, result.size());\n\n        result = mergerFactory.getMerger(Set.class).merge(null, null);\n        Assertions.assertEquals(0, result.size());\n    }\n\n    /**\n     * ShortArrayMerger test\n     */\n    @Test\n    void testShortArrayMerger() {\n        short[] arrayOne = {1, 2};\n        short[] arrayTwo = {2, 34};\n        short[] result = mergerFactory.getMerger(short[].class).merge(arrayOne, arrayTwo, null);\n        Assertions.assertEquals(4, result.length);\n        double[] mergedResult = {1, 2, 2, 34};\n        for (int i = 0; i < mergedResult.length; i++) {\n            Assertions.assertEquals(mergedResult[i], result[i], 0.0);\n        }\n\n        result = mergerFactory.getMerger(short[].class).merge(null);\n        Assertions.assertEquals(0, result.length);\n\n        result = mergerFactory.getMerger(short[].class).merge(null, null);\n        Assertions.assertEquals(0, result.length);\n    }\n\n    /**\n     * IntSumMerger test\n     */\n    @Test\n    void testIntSumMerger() {\n        Integer[] intArr = IntStream.rangeClosed(1, 100).boxed().toArray(Integer[]::new);\n        Merger<Integer> merger = ApplicationModel.defaultModel().getExtension(Merger.class, \"intsum\");\n        Assertions.assertEquals(5050, merger.merge(intArr));\n\n        intArr = new Integer[] {};\n        Assertions.assertEquals(0, merger.merge(intArr));\n    }\n\n    /**\n     * DoubleSumMerger test\n     */\n    @Test\n    void testDoubleSumMerger() {\n        Double[] doubleArr =\n                DoubleStream.iterate(1, v -> ++v).limit(100).boxed().toArray(Double[]::new);\n        Merger<Double> merger = ApplicationModel.defaultModel().getExtension(Merger.class, \"doublesum\");\n        Assertions.assertEquals(5050, merger.merge(doubleArr));\n\n        doubleArr = new Double[] {};\n        Assertions.assertEquals(0, merger.merge(doubleArr));\n    }\n\n    /**\n     * FloatSumMerger test\n     */\n    @Test\n    void testFloatSumMerger() {\n        Float[] floatArr = Stream.iterate(1.0F, v -> ++v).limit(100).toArray(Float[]::new);\n        Merger<Float> merger = ApplicationModel.defaultModel().getExtension(Merger.class, \"floatsum\");\n        Assertions.assertEquals(5050, merger.merge(floatArr));\n\n        floatArr = new Float[] {};\n        Assertions.assertEquals(0, merger.merge(floatArr));\n    }\n\n    /**\n     * LongSumMerger test\n     */\n    @Test\n    void testLongSumMerger() {\n        Long[] longArr = LongStream.rangeClosed(1, 100).boxed().toArray(Long[]::new);\n        Merger<Long> merger = ApplicationModel.defaultModel().getExtension(Merger.class, \"longsum\");\n        Assertions.assertEquals(5050, merger.merge(longArr));\n\n        longArr = new Long[] {};\n        Assertions.assertEquals(0, merger.merge(longArr));\n    }\n\n    /**\n     * IntFindAnyMerger test\n     */\n    @Test\n    void testIntFindAnyMerger() {\n        Integer[] intArr = {1, 2, 3, 4};\n        Merger<Integer> merger = ApplicationModel.defaultModel().getExtension(Merger.class, \"intany\");\n        Assertions.assertNotNull(merger.merge(intArr));\n\n        intArr = new Integer[] {};\n        Assertions.assertNull(merger.merge(intArr));\n    }\n\n    /**\n     * IntFindFirstMerger test\n     */\n    @Test\n    void testIntFindFirstMerger() {\n        Integer[] intArr = {1, 2, 3, 4};\n        Merger<Integer> merger = ApplicationModel.defaultModel().getExtension(Merger.class, \"intfirst\");\n        Assertions.assertEquals(1, merger.merge(intArr));\n\n        intArr = new Integer[] {};\n        Assertions.assertNull(merger.merge(intArr));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/MockInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\npublic class MockInvoker<T> implements Invoker<T> {\n    private boolean available = false;\n    private URL url;\n\n    public MockInvoker() {}\n\n    public MockInvoker(URL url) {\n        super();\n        this.url = url;\n    }\n\n    public MockInvoker(URL url, boolean available) {\n        super();\n        this.url = url;\n        this.available = available;\n    }\n\n    public MockInvoker(boolean available) {\n        this.available = available;\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return null;\n    }\n\n    public URL getUrl() {\n        return url;\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return available;\n    }\n\n    @Override\n    public Result invoke(Invocation invocation) throws RpcException {\n        return null;\n    }\n\n    @Override\n    public void destroy() {}\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/RouterSnapshotFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router;\n\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass RouterSnapshotFilterTest {\n\n    @BeforeAll\n    static void setUp() {\n        RpcContext.getServiceContext().setNeedPrintRouterSnapshot(false);\n    }\n\n    @Test\n    void test() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        RouterSnapshotSwitcher routerSnapshotSwitcher =\n                frameworkModel.getBeanFactory().getBean(RouterSnapshotSwitcher.class);\n        RouterSnapshotFilter routerSnapshotFilter = new RouterSnapshotFilter(frameworkModel);\n\n        Invoker invoker = Mockito.mock(Invoker.class);\n        Invocation invocation = Mockito.mock(Invocation.class);\n        ServiceModel serviceModel = Mockito.mock(ServiceModel.class);\n        Mockito.when(serviceModel.getServiceKey()).thenReturn(\"TestKey\");\n        Mockito.when(invocation.getServiceModel()).thenReturn(serviceModel);\n\n        routerSnapshotFilter.invoke(invoker, invocation);\n        Mockito.verify(invoker, Mockito.times(1)).invoke(invocation);\n        Assertions.assertFalse(RpcContext.getServiceContext().isNeedPrintRouterSnapshot());\n\n        routerSnapshotSwitcher.addEnabledService(\"Test\");\n        routerSnapshotFilter.invoke(invoker, invocation);\n        Assertions.assertFalse(RpcContext.getServiceContext().isNeedPrintRouterSnapshot());\n\n        routerSnapshotSwitcher.removeEnabledService(\"Test\");\n        routerSnapshotFilter.invoke(invoker, invocation);\n        Assertions.assertFalse(RpcContext.getServiceContext().isNeedPrintRouterSnapshot());\n\n        routerSnapshotSwitcher.addEnabledService(\"TestKey\");\n        routerSnapshotFilter.invoke(invoker, invocation);\n        Assertions.assertTrue(RpcContext.getServiceContext().isNeedPrintRouterSnapshot());\n        routerSnapshotFilter.onResponse(null, null, null);\n        Assertions.assertFalse(RpcContext.getServiceContext().isNeedPrintRouterSnapshot());\n\n        routerSnapshotSwitcher.addEnabledService(\"TestKey\");\n        routerSnapshotFilter.invoke(invoker, invocation);\n        Assertions.assertTrue(RpcContext.getServiceContext().isNeedPrintRouterSnapshot());\n        routerSnapshotFilter.onError(null, null, null);\n        Assertions.assertFalse(RpcContext.getServiceContext().isNeedPrintRouterSnapshot());\n\n        routerSnapshotSwitcher.removeEnabledService(\"TestKey\");\n        routerSnapshotFilter.invoke(invoker, invocation);\n        Assertions.assertFalse(RpcContext.getServiceContext().isNeedPrintRouterSnapshot());\n        routerSnapshotFilter.onError(null, null, null);\n        Assertions.assertFalse(RpcContext.getServiceContext().isNeedPrintRouterSnapshot());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/affinity/AffinityRouteTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.affinity;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.router.MockInvoker;\nimport org.apache.dubbo.rpc.cluster.router.affinity.config.AffinityServiceStateRouter;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\npublic class AffinityRouteTest {\n    private static final Logger logger = LoggerFactory.getLogger(AffinityRouteTest.class);\n\n    private static BitList<Invoker<String>> invokers;\n\n    private static List<String> providerUrls;\n\n    @BeforeAll\n    public static void setUp() {\n\n        providerUrls = Arrays.asList(\n                \"dubbo://127.0.0.1/com.foo.BarService\",\n                \"dubbo://127.0.0.1/com.foo.BarService\",\n                \"dubbo://127.0.0.1/com.foo.BarService?env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing&env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou&env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou&env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou&env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing&env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou&env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou&env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou&env=normal\");\n\n        List<Invoker<String>> invokerList = providerUrls.stream()\n                .map(url -> new MockInvoker<String>(URL.valueOf(url)))\n                .collect(Collectors.toList());\n\n        invokers = new BitList<>(invokerList);\n    }\n\n    public List<String> filtrate(List<String> invokers, String key) {\n\n        return invokers.stream().filter(invoker -> invoker.contains(key)).collect(Collectors.toList());\n    }\n\n    @Test\n    void testMetAffinityRoute() {\n        String config = \"configVersion: v3.1\\n\"\n                + \"scope: service\\n\"\n                + \"key: service.apache.com\\n\"\n                + \"enabled: true\\n\"\n                + \"runtime: true\\n\"\n                + \"affinityAware:\\n\"\n                + \"  key: region\\n\"\n                + \"  ratio: 20\\n\";\n\n        AffinityServiceStateRouter<String> affinityRoute = new AffinityServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n\n        affinityRoute.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", config, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> res = affinityRoute.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                invocation,\n                false,\n                new Holder<>());\n        List<String> filtered = filtrate(new ArrayList<String>(providerUrls), \"region=beijing\");\n\n        assertEquals(filtered.size(), res.size());\n        logger.info(\"The affinity routing condition is met and the result is routed\");\n    }\n\n    @Test\n    void testUnMetAffinityRoute() {\n        String config = \"configVersion: v3.1\\n\"\n                + \"scope: service\\n\"\n                + \"key: service.apache.com\\n\"\n                + \"enabled: true\\n\"\n                + \"runtime: true\\n\"\n                + \"affinityAware:\\n\"\n                + \"  key: region\\n\"\n                + \"  ratio: 80\\n\";\n\n        AffinityServiceStateRouter<String> affinityRoute = new AffinityServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n\n        affinityRoute.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", config, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> res = affinityRoute.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                invocation,\n                false,\n                new Holder<>());\n        List<String> filtered = filtrate(new ArrayList<String>(providerUrls), \"region=beijing\");\n\n        assertEquals(invokers.size(), res.size());\n        logger.info(\"The affinity routing condition was not met and the result was not routed\");\n    }\n\n    @Test\n    void testRatioEqualsAffinityRoute() {\n        String config = \"configVersion: v3.1\\n\"\n                + \"scope: service\\n\"\n                + \"key: service.apache.com\\n\"\n                + \"enabled: true\\n\"\n                + \"runtime: true\\n\"\n                + \"affinityAware:\\n\"\n                + \"  key: region\\n\"\n                + \"  ratio: 40\\n\";\n\n        AffinityServiceStateRouter<String> affinityRoute = new AffinityServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n\n        affinityRoute.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", config, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> res = affinityRoute.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                invocation,\n                false,\n                new Holder<>());\n        List<String> filtered = filtrate(new ArrayList<String>(providerUrls), \"region=beijing\");\n\n        assertEquals(filtered.size(), res.size());\n        logger.info(\"The affinity routing condition is met and the result is routed\");\n    }\n\n    @Test\n    void testRatioNotEqualsAffinityRoute() {\n        String config = \"configVersion: v3.1\\n\"\n                + \"scope: service\\n\"\n                + \"key: service.apache.com\\n\"\n                + \"enabled: true\\n\"\n                + \"runtime: true\\n\"\n                + \"affinityAware:\\n\"\n                + \"  key: region\\n\"\n                + \"  ratio: 40.1\\n\";\n\n        AffinityServiceStateRouter<String> affinityRoute = new AffinityServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n\n        affinityRoute.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", config, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> res = affinityRoute.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                invocation,\n                false,\n                new Holder<>());\n        List<String> filtered = filtrate(new ArrayList<String>(providerUrls), \"region=beijing\");\n\n        assertEquals(invokers.size(), res.size());\n        logger.info(\"The affinity routing condition was not met and the result was not routed\");\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.router.MockInvoker;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;\n\nclass ConditionStateRouterTest {\n    private static final String LOCAL_HOST = \"127.0.0.1\";\n    private URL SCRIPT_URL = URL.valueOf(\"condition://0.0.0.0/com.foo.BarService\");\n\n    @BeforeAll\n    public static void setUpBeforeClass() throws Exception {}\n\n    @BeforeEach\n    public void setUp() throws Exception {}\n\n    private URL getRouteUrl(String rule) {\n        return SCRIPT_URL.addParameterAndEncoded(RULE_KEY, rule);\n    }\n\n    @Test\n    void testRoute_matchWhen() {\n        Invocation invocation = new RpcInvocation();\n\n        StateRouter router =\n                new ConditionStateRouterFactory().getRouter(String.class, getRouteUrl(\" => host = 1.2.3.4\"));\n        boolean matchWhen = ((ConditionStateRouter) router)\n                .matchWhen(URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService\"), invocation);\n        Assertions.assertTrue(matchWhen);\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4\"));\n        matchWhen = ((ConditionStateRouter) router)\n                .matchWhen(URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService\"), invocation);\n        Assertions.assertTrue(matchWhen);\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class, getRouteUrl(\"host = 2.2.2.2,1.1.1.1,3.3.3.3 & host !=1.1.1.1 => host = 1.2.3.4\"));\n        matchWhen = ((ConditionStateRouter) router)\n                .matchWhen(URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService\"), invocation);\n        Assertions.assertFalse(matchWhen);\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class, getRouteUrl(\"host !=4.4.4.4 & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4\"));\n        matchWhen = ((ConditionStateRouter) router)\n                .matchWhen(URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService\"), invocation);\n        Assertions.assertTrue(matchWhen);\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class, getRouteUrl(\"host !=4.4.4.* & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4\"));\n        matchWhen = ((ConditionStateRouter) router)\n                .matchWhen(URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService\"), invocation);\n        Assertions.assertTrue(matchWhen);\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = 2.2.2.2,1.1.1.*,3.3.3.3 & host != 1.1.1.1 => host = 1.2.3.4\"));\n        matchWhen = ((ConditionStateRouter) router)\n                .matchWhen(URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService\"), invocation);\n        Assertions.assertFalse(matchWhen);\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = 2.2.2.2,1.1.1.*,3.3.3.3 & host != 1.1.1.2 => host = 1.2.3.4\"));\n        matchWhen = ((ConditionStateRouter) router)\n                .matchWhen(URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService\"), invocation);\n        Assertions.assertTrue(matchWhen);\n    }\n\n    @Test\n    void testRoute_matchFilter() {\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(\n                URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService?serialization=fastjson\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        System.err.println(\"The localhost address: \" + invoker2.getUrl().getAddress());\n        System.err.println(invoker3.getUrl().getAddress());\n\n        StateRouter router1 = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" host = 10.20.3.3\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        StateRouter router2 = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" host = 10.20.3.* & host != 10.20.3.3\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        StateRouter router3 = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" host = 10.20.3.3  & host != 10.20.3.3\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        StateRouter router4 = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" host = 10.20.3.2,10.20.3.3,10.20.3.4\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        StateRouter router5 = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" host != 10.20.3.3\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        StateRouter router6 = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" serialization = fastjson\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n\n        List<Invoker<String>> filteredInvokers1 = router1.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        List<Invoker<String>> filteredInvokers2 = router2.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        List<Invoker<String>> filteredInvokers3 = router3.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        List<Invoker<String>> filteredInvokers4 = router4.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        List<Invoker<String>> filteredInvokers5 = router5.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        List<Invoker<String>> filteredInvokers6 = router6.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        Assertions.assertEquals(1, filteredInvokers1.size());\n        Assertions.assertEquals(0, filteredInvokers2.size());\n        Assertions.assertEquals(0, filteredInvokers3.size());\n        Assertions.assertEquals(1, filteredInvokers4.size());\n        Assertions.assertEquals(2, filteredInvokers5.size());\n        Assertions.assertEquals(1, filteredInvokers6.size());\n    }\n\n    @Test\n    void testRoute_methodRoute() {\n        Invocation invocation = new RpcInvocation(\"getFoo\", \"com.foo.BarService\", \"\", new Class<?>[0], new Object[0]);\n        // More than one methods, mismatch\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"methods=getFoo => host = 1.2.3.4\"));\n        boolean matchWhen = ((ConditionStateRouter) router)\n                .matchWhen(\n                        URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo\"), invocation);\n        Assertions.assertTrue(matchWhen);\n        // Exactly one method, match\n        matchWhen = ((ConditionStateRouter) router)\n                .matchWhen(URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService?methods=getFoo\"), invocation);\n        Assertions.assertTrue(matchWhen);\n        // Method routing and Other condition routing can work together\n        StateRouter router2 = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"methods=getFoo & host!=1.1.1.1 => host = 1.2.3.4\"));\n        matchWhen = ((ConditionStateRouter) router2)\n                .matchWhen(URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService?methods=getFoo\"), invocation);\n        Assertions.assertFalse(matchWhen);\n\n        StateRouter router3 = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"methods=getFoo & host=1.1.1.1 => host = 1.2.3.4\"));\n        matchWhen = ((ConditionStateRouter) router3)\n                .matchWhen(URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService?methods=getFoo\"), invocation);\n        Assertions.assertTrue(matchWhen);\n        // Test filter condition\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        StateRouter router4 = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = \" + LOCAL_HOST + \" & methods = getFoo => \" + \" host = 10.20.3.3\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        List<Invoker<String>> filteredInvokers1 = router4.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(1, filteredInvokers1.size());\n\n        StateRouter router5 = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = \" + LOCAL_HOST + \" & methods = unvalidmethod => \" + \" host = 10.20.3.3\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        List<Invoker<String>> filteredInvokers2 = router5.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers2.size());\n        // Request a non-exists method\n    }\n\n    @Test\n    void testRoute_ReturnFalse() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"host = \" + LOCAL_HOST + \" => false\"));\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        originInvokers.add(new MockInvoker<String>());\n        originInvokers.add(new MockInvoker<String>());\n        originInvokers.add(new MockInvoker<String>());\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        Assertions.assertEquals(0, filteredInvokers.size());\n    }\n\n    @Test\n    void testRoute_ReturnEmpty() {\n        StateRouter router =\n                new ConditionStateRouterFactory().getRouter(String.class, getRouteUrl(\"host = \" + LOCAL_HOST + \" => \"));\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        originInvokers.add(new MockInvoker<String>());\n        originInvokers.add(new MockInvoker<String>());\n        originInvokers.add(new MockInvoker<String>());\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        Assertions.assertEquals(0, filteredInvokers.size());\n    }\n\n    @Test\n    void testRoute_ReturnAll() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" host = \" + LOCAL_HOST));\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        originInvokers.add(new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\")));\n        originInvokers.add(new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\")));\n        originInvokers.add(new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\")));\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        Assertions.assertEquals(invokers, filteredInvokers);\n    }\n\n    @Test\n    void testRoute_HostFilter() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" host = \" + LOCAL_HOST));\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        Assertions.assertEquals(2, filteredInvokers.size());\n        Assertions.assertEquals(invoker2, filteredInvokers.get(0));\n        Assertions.assertEquals(invoker3, filteredInvokers.get(1));\n    }\n\n    @Test\n    void testRoute_Empty_HostFilter() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\" => \" + \" host = \" + LOCAL_HOST));\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        Assertions.assertEquals(2, filteredInvokers.size());\n        Assertions.assertEquals(invoker2, filteredInvokers.get(0));\n        Assertions.assertEquals(invoker3, filteredInvokers.get(1));\n    }\n\n    @Test\n    void testRoute_False_HostFilter() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"true => \" + \" host = \" + LOCAL_HOST));\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        Assertions.assertEquals(2, filteredInvokers.size());\n        Assertions.assertEquals(invoker2, filteredInvokers.get(0));\n        Assertions.assertEquals(invoker3, filteredInvokers.get(1));\n    }\n\n    @Test\n    void testRoute_Placeholder() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" host = $host\"));\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        Assertions.assertEquals(2, filteredInvokers.size());\n        Assertions.assertEquals(invoker2, filteredInvokers.get(0));\n        Assertions.assertEquals(invoker3, filteredInvokers.get(1));\n    }\n\n    @Test\n    void testRoute_NoForce() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" host = 1.2.3.4\"));\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        Assertions.assertEquals(invokers, filteredInvokers);\n    }\n\n    @Test\n    void testRoute_Force() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"host = \" + LOCAL_HOST + \" => \" + \" host = 1.2.3.4\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                new RpcInvocation(),\n                false,\n                new Holder<>());\n        Assertions.assertEquals(0, filteredInvokers.size());\n    }\n\n    @Test\n    void testRoute_Arguments() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"arguments[0] = a \" + \" => \" + \" host = 1.2.3.4\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        List<Invoker<String>> originInvokers = new ArrayList<>();\n        Invoker<String> invoker1 = new MockInvoker<>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        RpcInvocation invocation = new RpcInvocation();\n        String p = \"a\";\n        invocation.setArguments(new Object[] {null});\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n\n        invocation.setArguments(new Object[] {p});\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(0, filteredInvokers.size());\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"arguments = b \" + \" => \" + \" host = 1.2.3.4\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"arguments[10].inner = a \" + \" => \" + \" host = 1.2.3.4\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n\n        int integer = 1;\n        invocation.setArguments(new Object[] {integer});\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"arguments[0].inner = 1 \" + \" => \" + \" host = 1.2.3.4\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(0, filteredInvokers.size());\n    }\n\n    @Test\n    void testRoute_Attachments() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"attachments[foo] = a \" + \" => \" + \" host = 1.2.3.4\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        List<Invoker<String>> originInvokers = new ArrayList<>();\n        Invoker<String> invoker1 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService?region=hangzhou\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        RpcInvocation invocation = new RpcInvocation();\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n\n        invocation.setAttachment(\"foo\", \"a\");\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(0, filteredInvokers.size());\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"attachments = a \" + \" => \" + \" host = 1.2.3.4\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"attachments[foo] = a \" + \" => \" + \" region = hangzhou\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(1, filteredInvokers.size());\n    }\n\n    @Test\n    void testRoute_Range_Pattern() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"attachments[user_id] = 1~100 \" + \" => \" + \" region=hangzhou\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        List<Invoker<String>> originInvokers = new ArrayList<>();\n        Invoker<String> invoker1 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService?region=hangzhou\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        RpcInvocation invocation = new RpcInvocation();\n        List<Invoker<String>> filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n\n        invocation.setAttachment(\"user_id\", \"80\");\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(1, filteredInvokers.size());\n\n        invocation.setAttachment(\"user_id\", \"101\");\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"attachments[user_id] = ~100 \" + \" => \" + \" region = hangzhou\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        invocation.setAttachment(\"user_id\", \"1\");\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(1, filteredInvokers.size());\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"attachments[user_id] = ~100 \" + \" => \" + \" region = hangzhou\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        invocation.setAttachment(\"user_id\", \"101\");\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"attachments[user_id] = ~100 \" + \" => \" + \" region = hangzhou\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        filteredInvokers = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n    }\n\n    @Test\n    void testRoute_Key_Not_Exist() {\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"when_key=a \" + \" => \" + \" not_exist_then_key = any_value\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        List<Invoker<String>> originInvokers = new ArrayList<>();\n        Invoker<String> invoker1 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService?then_key=a\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        URL consumer = URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService?when_key=a\");\n\n        List<Invoker<String>> filteredInvokers = router.route(invokers.clone(), consumer, null, false, new Holder<>());\n        Assertions.assertEquals(0, filteredInvokers.size());\n\n        router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"not_exist_when_key=a \" + \" => \" + \" then_key = a\")\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        filteredInvokers = router.route(invokers, consumer, null, false, new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n    }\n\n    @Test\n    void testRoute_Multiple_Conditions() {\n        List<Invoker<String>> originInvokers = new ArrayList<>();\n        Invoker<String> invoker1 = new MockInvoker<>(URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        Invoker<String> invoker3 =\n                new MockInvoker<>(URL.valueOf(\"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        RpcInvocation invocation = new RpcInvocation();\n        String p = \"a\";\n        invocation.setArguments(new Object[] {p});\n\n        // all conditions match\n        URL consumer1 = URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService?application=consumer_app\");\n        StateRouter router = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"application=consumer_app&arguments[0]=a\" + \" => \" + \" host = \" + LOCAL_HOST)\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        List<Invoker<String>> filteredInvokers =\n                router.route(invokers.clone(), consumer1, invocation, false, new Holder<>());\n        Assertions.assertEquals(2, filteredInvokers.size());\n\n        // one of the conditions does not match\n        URL consume2 = URL.valueOf(\"consumer://\" + LOCAL_HOST + \"/com.foo.BarService?application=another_consumer_app\");\n        StateRouter router2 = new ConditionStateRouterFactory()\n                .getRouter(\n                        String.class,\n                        getRouteUrl(\"application=consumer_app&arguments[0]=a\" + \" => \" + \" host = \" + LOCAL_HOST)\n                                .addParameter(FORCE_KEY, String.valueOf(true)));\n        filteredInvokers = router2.route(invokers.clone(), consume2, invocation, false, new Holder<>());\n        Assertions.assertEquals(3, filteredInvokers.size());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionStateRouterTestV31.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;\nimport org.apache.dubbo.rpc.cluster.router.MockInvoker;\nimport org.apache.dubbo.rpc.cluster.router.condition.config.model.ConditionRuleParser;\nimport org.apache.dubbo.rpc.cluster.router.condition.config.model.MultiDestConditionRouterRule;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\npublic class ConditionStateRouterTestV31 {\n\n    private static BitList<Invoker<String>> invokers;\n\n    @BeforeAll\n    public static void setUp() {\n\n        List<String> providerUrls = Arrays.asList(\n                \"dubbo://127.0.0.1/com.foo.BarService\",\n                \"dubbo://127.0.0.1/com.foo.BarService\",\n                \"dubbo://127.0.0.1/com.foo.BarService?env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=beijing&env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou&env=gray\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou&env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou&env=normal\",\n                \"dubbo://127.0.0.1/com.foo.BarService?region=hangzhou&env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=beijing&env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou&env=gray\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou&env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou&env=normal\",\n                \"dubbo://dubbo.apache.org/com.foo.BarService?region=hangzhou&env=normal\");\n\n        List<Invoker<String>> invokerList = providerUrls.stream()\n                .map(url -> new MockInvoker<String>(URL.valueOf(url)))\n                .collect(Collectors.toList());\n\n        invokers = new BitList<>(invokerList);\n    }\n\n    @Test\n    public void testParseRawRule() {\n        String config =\n                \"configVersion: v3.1\\n\" + \"scope: service\\n\" + \"force: false\\n\" + \"runtime: true\\n\" + \"enabled: true\\n\"\n                        + \"key: shop\\n\" + \"conditions:\\n\" + \"  - from:\\n\" + \"      match:\\n\" + \"    to:\\n\"\n                        + \"      - match: region=$region & version=v1\\n\"\n                        + \"      - match: region=$region & version=v2\\n\" + \"        weight: 200\\n\"\n                        + \"      - match: region=$region & version=v3\\n\" + \"        weight: 300\\n\" + \"  - from:\\n\"\n                        + \"      match: region=beijing & version=v1\\n\" + \"    to:\\n\"\n                        + \"      - match: env=$env & region=beijing\\n\";\n\n        AbstractRouterRule routerRule = ConditionRuleParser.parse(config);\n        Assertions.assertInstanceOf(MultiDestConditionRouterRule.class, routerRule);\n        MultiDestConditionRouterRule rule = (MultiDestConditionRouterRule) routerRule;\n        Assertions.assertEquals(rule.getConditions().size(), 2);\n        Assertions.assertEquals(rule.getConditions().get(0).getTo().size(), 3);\n        Assertions.assertEquals(rule.getConditions().get(1).getTo().size(), 1);\n    }\n\n    @Test\n    public void testMultiplyConditionRoute() {\n\n        String rawRule = \"configVersion: v3.1\\n\" + \"scope: service\\n\"\n                + \"key: com.foo.BarService\\n\"\n                + \"force: false\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: true\\n\"\n                + \"conditions:\\n\"\n                + \"  - from:\\n\"\n                + \"      match: env=gray\\n\"\n                + \"    to:\\n\"\n                + \"      - match: env!=gray\\n\"\n                + \"        weight: 100\";\n\n        ServiceStateRouter<String> router = new ServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n        router.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", rawRule, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> result = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing&version=v1\"),\n                invocation,\n                false,\n                new Holder<>());\n\n        int count = 0;\n        for (Invoker<String> invoker : invokers) {\n            String url = invoker.getUrl().toString();\n            if (url.contains(\"env\") && !url.contains(\"gray\")) {\n                count++;\n            }\n        }\n        Assertions.assertEquals(count, result.size());\n    }\n\n    @Test\n    public void testRemoveDuplicatesCondition() {\n        String rawRule = \"configVersion: v3.1\\n\" + \"scope: service\\n\"\n                + \"key: org.apache.dubbo.samples.CommentService\\n\"\n                + \"force: false\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: true\\n\"\n                + \"conditions:\\n\"\n                + \"  - from:\\n\"\n                + \"      match: env=gray\\n\"\n                + \"    to:\\n\"\n                + \"      - match: env!=gray\\n\"\n                + \"        weight: 100\\n\"\n                + \"  - from:\\n\"\n                + \"      match: env=gray\\n\"\n                + \"    to:\\n\"\n                + \"      - match: env!=gray\\n\"\n                + \"        weight: 100\";\n        ServiceStateRouter<String> router = new ServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n        router.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", rawRule, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> result = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                invocation,\n                false,\n                new Holder<>());\n\n        int count = 0;\n        for (Invoker<String> invoker : invokers) {\n            String url = invoker.getUrl().toString();\n            if (url.contains(\"env\") && !url.contains(\"gray\")) {\n                count++;\n            }\n        }\n        Assertions.assertEquals(count, result.size());\n    }\n\n    @Test\n    public void testConsequentCondition() {\n        String rawRule = \"configVersion: v3.1\\n\" + \"scope: service\\n\"\n                + \"key: org.apache.dubbo.samples.CommentService\\n\"\n                + \"force: false\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: true\\n\"\n                + \"conditions:\\n\"\n                + \"  - from:\\n\"\n                + \"      match: env=gray\\n\"\n                + \"    to:\\n\"\n                + \"      - match: env!=gray\\n\"\n                + \"        weight: 100\\n\"\n                + \"  - from:\\n\"\n                + \"      match: region=beijing\\n\"\n                + \"    to:\\n\"\n                + \"      - match: region=beijing\\n\"\n                + \"        weight: 100\\n\"\n                + \"  - from:\\n\"\n                + \"    to:\\n\"\n                + \"      - match: host!=127.0.0.1\";\n\n        ServiceStateRouter<String> router = new ServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n        router.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", rawRule, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> result = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                invocation,\n                false,\n                new Holder<>());\n\n        int count = 0;\n        for (Invoker<String> invoker : invokers) {\n            String url = invoker.getUrl().toString();\n            if ((url.contains(\"env\") && !url.contains(\"gray\"))\n                    && url.contains(\"region=beijing\")\n                    && !url.contains(\"127.0.0.1\")) {\n                count++;\n            }\n        }\n        Assertions.assertEquals(count, result.size());\n    }\n\n    @Test\n    public void testUnMatchCondition() {\n        String rawRule = \"configVersion: v3.1\\n\" + \"scope: service\\n\"\n                + \"key: org.apache.dubbo.samples.CommentService\\n\"\n                + \"force: false\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: true\\n\"\n                + \"conditions:\\n\"\n                + \"  - from:\\n\"\n                + \"      match: env!=gray\\n\"\n                + \"    to:\\n\"\n                + \"      - match: env=gray\\n\"\n                + \"        weight: 100\\n\"\n                + \"  - from:\\n\"\n                + \"      match: region!=beijing\\n\"\n                + \"    to:\\n\"\n                + \"      - match: region=beijing\\n\"\n                + \"        weight: 100\\n\"\n                + \"  - from:\\n\"\n                + \"    to:\\n\"\n                + \"      - match: host!=127.0.0.1\";\n\n        ServiceStateRouter<String> router = new ServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n        router.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", rawRule, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> result = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                invocation,\n                false,\n                new Holder<>());\n\n        int count = 0;\n        for (Invoker<String> invoker : invokers) {\n            String url = invoker.getUrl().toString();\n            if (!url.contains(\"127.0.0.1\")) {\n                count++;\n            }\n        }\n        Assertions.assertEquals(count, result.size());\n    }\n\n    @Test\n    public void testMatchAndRouteZero() {\n        String rawRule = \"configVersion: v3.1\\n\" + \"scope: service\\n\"\n                + \"key: org.apache.dubbo.samples.CommentService\\n\"\n                + \"force: true\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: true\\n\"\n                + \"conditions:\\n\"\n                + \"  - from:\\n\"\n                + \"      match: env=gray\\n\"\n                + \"    to:\\n\"\n                + \"      - match: env=ErrTag\\n\"\n                + \"        weight: 100\\n\"\n                + \"  - from:\\n\"\n                + \"      match: region!=beijing\\n\"\n                + \"    to:\\n\"\n                + \"      - match: region=beijing\\n\"\n                + \"        weight: 100\\n\"\n                + \"  - from:\\n\"\n                + \"    to:\\n\"\n                + \"      - match: host!=127.0.0.1\";\n\n        ServiceStateRouter<String> router = new ServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n        router.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", rawRule, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> result = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                invocation,\n                false,\n                new Holder<>());\n        Assertions.assertEquals(0, result.size());\n    }\n\n    @Test\n    public void testMatchRouteZeroAndIgnore() {\n        String rawRule = \"configVersion: v3.1\\n\" + \"scope: service\\n\"\n                + \"key: org.apache.dubbo.samples.CommentService\\n\"\n                + \"force: false\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: true\\n\"\n                + \"conditions:\\n\"\n                + \"  - from:\\n\"\n                + \"      match: region=beijing\\n\"\n                + \"    to:\\n\"\n                + \"      - match: region!=beijing\\n\"\n                + \"        weight: 100\\n\"\n                + \"  - from:\\n\"\n                + \"    to:\\n\"\n                + \"      - match: host!=127.0.0.1\\n\"\n                + \"  - from:\\n\"\n                + \"      match: env=gray\\n\"\n                + \"    to:\\n\"\n                + \"      - match: env=ErrTag\\n\"\n                + \"        weight: 100\";\n\n        ServiceStateRouter<String> router = new ServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n        router.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", rawRule, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> result = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                invocation,\n                false,\n                new Holder<>());\n\n        int count = 0;\n        for (Invoker<String> invoker : invokers) {\n            String url = invoker.getUrl().toString();\n            if ((url.contains(\"region\") && !url.contains(\"beijing\") && !url.contains(\"127.0.0.1\"))) {\n                count++;\n            }\n        }\n        Assertions.assertEquals(count, result.size());\n    }\n\n    @Test\n    public void testTrafficDisabledAndIgnoreConditionRouteForce() {\n        String rawRule = \"configVersion: v3.1\\n\" + \"scope: service\\n\"\n                + \"key: org.apache.dubbo.samples.CommentService\\n\"\n                + \"force: false\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: true\\n\"\n                + \"conditions:\\n\"\n                + \"  - from:\\n\"\n                + \"      match: host=127.0.0.1\\n\"\n                + \"  - from:\\n\"\n                + \"      match: env=gray\\n\"\n                + \"    to:\\n\"\n                + \"      - match: env!=gray\\n\"\n                + \"        weight: 100\\n\"\n                + \"  - to:\\n\"\n                + \"      - match: region!=beijing\";\n\n        ServiceStateRouter<String> router = new ServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n        router.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", rawRule, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        BitList<Invoker<String>> result = router.route(\n                invokers.clone(),\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                invocation,\n                false,\n                new Holder<>());\n\n        Assertions.assertEquals(0, result.size());\n    }\n\n    @Test\n    public void testMultiplyDestination() {\n        String rawRule = \"configVersion: v3.1\\n\" + \"scope: service\\n\"\n                + \"key: org.apache.dubbo.samples.CommentService\\n\"\n                + \"force: false\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: true\\n\"\n                + \"conditions:\\n\"\n                + \"  - from:\\n\"\n                + \"      match: env=gray\\n\"\n                + \"    to:\\n\"\n                + \"      - match: env!=gray\\n\"\n                + \"        weight: 100\\n\"\n                + \"      - match: env=gray\\n\"\n                + \"        weight: 900\\n\"\n                + \"  - from:\\n\"\n                + \"      match: region=beijing\\n\"\n                + \"    to:\\n\"\n                + \"      - match: region!=beijing\\n\"\n                + \"        weight: 100\\n\"\n                + \"      - match: region=beijing\\n\"\n                + \"        weight: 200\";\n\n        ServiceStateRouter<String> router = new ServiceStateRouter<>(\n                URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"));\n        router.process(new ConfigChangedEvent(\"com.foo.BarService\", \"\", rawRule, ConfigChangeType.ADDED));\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getComment\");\n\n        Map<Integer, Integer> actualDistribution = new HashMap<>();\n        for (int i = 0; i < 1000; i++) {\n            BitList<Invoker<String>> result = router.route(\n                    invokers.clone(),\n                    URL.valueOf(\"consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing\"),\n                    invocation,\n                    false,\n                    new Holder<>());\n\n            actualDistribution.put(result.size(), actualDistribution.getOrDefault(result.size(), 0) + 1);\n        }\n        int sum = 0;\n        for (Map.Entry<Integer, Integer> entry : actualDistribution.entrySet()) {\n            sum += entry.getValue();\n        }\n        assertEquals(actualDistribution.size(), 4); // 8 6 4 2\n        Assertions.assertNotNull(actualDistribution.get(8));\n        Assertions.assertNotNull(actualDistribution.get(6));\n        Assertions.assertNotNull(actualDistribution.get(4));\n        Assertions.assertNotNull(actualDistribution.get(2));\n        assertEquals(sum, 1000);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/config/ProviderAppConditionStateRouterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.condition.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository;\nimport org.apache.dubbo.rpc.cluster.router.MockInvoker;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;\n\npublic class ProviderAppConditionStateRouterTest {\n    private static final String LOCAL_HOST = \"127.0.0.1\";\n    private static final String RULE_SUFFIX = \".condition-router\";\n\n    private static GovernanceRuleRepository ruleRepository;\n    private URL url = URL.valueOf(\"consumer://1.1.1.1/com.foo.BarService\");\n    private String rawRule = \"---\\n\" + \"configVersion: v3.0\\n\"\n            + \"scope: application\\n\"\n            + \"force: true\\n\"\n            + \"runtime: false\\n\"\n            + \"enabled: true\\n\"\n            + \"priority: 1\\n\"\n            + \"key: demo-provider\\n\"\n            + \"conditions:\\n\"\n            + \"- method=sayHello => region=hangzhou\\n\"\n            + \"...\";\n\n    @BeforeAll\n    public static void setUpBeforeClass() throws Exception {\n        ruleRepository = Mockito.mock(GovernanceRuleRepository.class);\n    }\n\n    @Test\n    void test() {\n        ProviderAppStateRouter<String> router = new ProviderAppStateRouter<>(url);\n        router = Mockito.spy(router);\n        Mockito.when(router.getRuleRepository()).thenReturn(ruleRepository);\n        Mockito.when(ruleRepository.getRule(\"demo-provider\" + RULE_SUFFIX, DynamicConfiguration.DEFAULT_GROUP))\n                .thenReturn(rawRule);\n        //        Mockito.when(ruleRepository.addListener()).thenReturn();\n\n        BitList<Invoker<String>> invokers = getInvokers();\n        router.notify(invokers);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        List<Invoker<String>> result = router.route(invokers.clone(), url, invocation, false, new Holder<>());\n        Assertions.assertEquals(1, result.size());\n\n        invocation.setMethodName(\"sayHi\");\n        result = router.route(invokers.clone(), url, invocation, false, new Holder<>());\n        Assertions.assertEquals(3, result.size());\n    }\n\n    private BitList<Invoker<String>> getInvokers() {\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(\n                URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService?\" + REMOTE_APPLICATION_KEY + \"=demo-provider\"));\n        Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf(\"dubbo://\" + LOCAL_HOST\n                + \":20880/com.foo.BarService?\" + REMOTE_APPLICATION_KEY + \"=demo-provider&region=hangzhou\"));\n        Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf(\n                \"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService?\" + REMOTE_APPLICATION_KEY + \"=demo-provider\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n        return invokers;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.file;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport javax.script.ScriptEngineManager;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLE_CONNECTIVITY_VALIDATION;\nimport static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n@SuppressWarnings(\"unchecked\")\nclass FileRouterEngineTest {\n    private static boolean isScriptUnsupported = new ScriptEngineManager().getEngineByName(\"javascript\") == null;\n    List<Invoker<FileRouterEngineTest>> invokers = new ArrayList<Invoker<FileRouterEngineTest>>();\n    Invoker<FileRouterEngineTest> invoker1 = mock(Invoker.class);\n    Invoker<FileRouterEngineTest> invoker2 = mock(Invoker.class);\n    Invocation invocation;\n    StaticDirectory<FileRouterEngineTest> dic;\n    Result result = new AppResponse();\n    private StateRouterFactory routerFactory =\n            ExtensionLoader.getExtensionLoader(StateRouterFactory.class).getAdaptiveExtension();\n\n    @BeforeAll\n    public static void setUpBeforeClass() throws Exception {\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);\n        System.setProperty(ENABLE_CONNECTIVITY_VALIDATION, \"false\");\n    }\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n    }\n\n    @AfterEach\n    public void teardown() throws Exception {\n        System.clearProperty(ENABLE_CONNECTIVITY_VALIDATION);\n        RpcContext.removeContext();\n    }\n\n    @Test\n    void testRouteNotAvailable() {\n        if (isScriptUnsupported) return;\n        URL url = initUrl(\"notAvailablerule.javascript\");\n        initInvocation(\"method1\");\n        initInvokers(url, true, false);\n        initDic(url);\n\n        MockClusterInvoker<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(dic, url);\n        for (int i = 0; i < 100; i++) {\n            sinvoker.invoke(invocation);\n            Invoker<FileRouterEngineTest> invoker = sinvoker.getSelectedInvoker();\n            Assertions.assertEquals(invoker2, invoker);\n        }\n    }\n\n    @Test\n    void testRouteAvailable() {\n        if (isScriptUnsupported) return;\n        URL url = initUrl(\"availablerule.javascript\");\n        initInvocation(\"method1\");\n        initInvokers(url);\n        initDic(url);\n\n        MockClusterInvoker<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(dic, url);\n        for (int i = 0; i < 100; i++) {\n            sinvoker.invoke(invocation);\n            Invoker<FileRouterEngineTest> invoker = sinvoker.getSelectedInvoker();\n            Assertions.assertEquals(invoker1, invoker);\n        }\n    }\n\n    @Test\n    void testRouteByMethodName() {\n        if (isScriptUnsupported) return;\n        URL url = initUrl(\"methodrule.javascript\");\n        {\n            initInvocation(\"method1\");\n            initInvokers(url, true, true);\n            initDic(url);\n\n            MockClusterInvoker<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(dic, url);\n            for (int i = 0; i < 100; i++) {\n                sinvoker.invoke(invocation);\n                Invoker<FileRouterEngineTest> invoker = sinvoker.getSelectedInvoker();\n                Assertions.assertEquals(invoker1, invoker);\n            }\n        }\n        {\n            initInvocation(\"method2\");\n            initInvokers(url, true, true);\n            initDic(url);\n            MockClusterInvoker<FileRouterEngineTest> sinvoker = new MockClusterInvoker<FileRouterEngineTest>(dic, url);\n            for (int i = 0; i < 100; i++) {\n                sinvoker.invoke(invocation);\n                Invoker<FileRouterEngineTest> invoker = sinvoker.getSelectedInvoker();\n                Assertions.assertEquals(invoker2, invoker);\n            }\n        }\n    }\n\n    private URL initUrl(String filename) {\n        filename = getClass()\n                .getClassLoader()\n                .getResource(getClass().getPackage().getName().replace('.', '/') + \"/\" + filename)\n                .toString();\n        URL url = URL.valueOf(filename);\n        url = url.addParameter(RUNTIME_KEY, true);\n        return url;\n    }\n\n    private void initInvocation(String methodName) {\n        invocation = new RpcInvocation();\n        ((RpcInvocation) invocation).setMethodName(methodName);\n    }\n\n    private void initInvokers(URL url) {\n        initInvokers(url, true, false);\n    }\n\n    private void initInvokers(URL url, boolean invoker1Status, boolean invoker2Status) {\n        given(invoker1.invoke(invocation)).willReturn(result);\n        given(invoker1.isAvailable()).willReturn(invoker1Status);\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.getInterface()).willReturn(FileRouterEngineTest.class);\n\n        given(invoker2.invoke(invocation)).willReturn(result);\n        given(invoker2.isAvailable()).willReturn(invoker2Status);\n        given(invoker2.getUrl()).willReturn(url);\n        given(invoker2.getInterface()).willReturn(FileRouterEngineTest.class);\n    }\n\n    private void initDic(URL url) {\n        // FIXME: this exposes the design flaw in RouterChain\n        URL dicInitUrl = URL.valueOf(\n                \"consumer://localhost:20880/org.apache.dubbo.rpc.cluster.router.file.FileRouterEngineTest?application=FileRouterEngineTest\");\n        dic = new StaticDirectory<>(dicInitUrl, invokers);\n        dic.buildRouterChain();\n        dic.getRouterChain()\n                .getCurrentChain()\n                .setHeadStateRouter(routerFactory.getRouter(FileRouterEngineTest.class, url));\n    }\n\n    static class MockClusterInvoker<T> extends AbstractClusterInvoker<T> {\n        private Invoker<T> selectedInvoker;\n\n        public MockClusterInvoker(Directory<T> directory) {\n            super(directory);\n        }\n\n        public MockClusterInvoker(Directory<T> directory, URL url) {\n            super(directory, url);\n        }\n\n        @Override\n        protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n                throws RpcException {\n            Invoker<T> invoker = select(loadbalance, invocation, invokers, null);\n            selectedInvoker = invoker;\n            return null;\n        }\n\n        public Invoker<T> getSelectedInvoker() {\n            return selectedInvoker;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshAppRuleListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.MeshRuleListener;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\n\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.MESH_RULE_DATA_ID_SUFFIX;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nclass MeshAppRuleListenerTest {\n\n    private static final String rule1 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: DestinationRule\\n\"\n            + \"metadata: { name: demo-route }\\n\"\n            + \"spec:\\n\"\n            + \"  host: demo\\n\"\n            + \"  subsets:\\n\"\n            + \"    - labels: { env-sign: xxx, tag1: hello }\\n\"\n            + \"      name: isolation\\n\"\n            + \"    - labels: { env-sign: yyy }\\n\"\n            + \"      name: testing-trunk\\n\"\n            + \"    - labels: { env-sign: zzz }\\n\"\n            + \"      name: testing\\n\"\n            + \"  trafficPolicy:\\n\"\n            + \"    loadBalancer: { simple: ROUND_ROBIN }\\n\"\n            + \"\\n\";\n    private static final String rule2 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: VirtualService\\n\"\n            + \"metadata: { name: demo-route }\\n\"\n            + \"spec:\\n\"\n            + \"  dubbo:\\n\"\n            + \"    - routedetail:\\n\"\n            + \"        - match:\\n\"\n            + \"            - sourceLabels: {trafficLabel: xxx}\\n\"\n            + \"          name: xxx-project\\n\"\n            + \"          route:\\n\"\n            + \"            - destination: {host: demo, subset: isolation}\\n\"\n            + \"        - match:\\n\"\n            + \"            - sourceLabels: {trafficLabel: testing-trunk}\\n\"\n            + \"          name: testing-trunk\\n\"\n            + \"          route:\\n\"\n            + \"            - destination: {host: demo, subset: testing-trunk}\\n\"\n            + \"        - name: testing\\n\"\n            + \"          route:\\n\"\n            + \"            - destination: {host: demo, subset: testing}\\n\"\n            + \"      services:\\n\"\n            + \"        - {regex: ccc}\\n\"\n            + \"  hosts: [demo]\\n\";\n    private static final String rule3 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: DestinationRule\\n\"\n            + \"spec:\\n\"\n            + \"  host: demo\\n\"\n            + \"  subsets:\\n\"\n            + \"    - labels: { env-sign: xxx, tag1: hello }\\n\"\n            + \"      name: isolation\\n\"\n            + \"    - labels: { env-sign: yyy }\\n\"\n            + \"      name: testing-trunk\\n\"\n            + \"    - labels: { env-sign: zzz }\\n\"\n            + \"      name: testing\\n\"\n            + \"  trafficPolicy:\\n\"\n            + \"    loadBalancer: { simple: ROUND_ROBIN }\\n\";\n    private static final String rule4 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\";\n    private static final String rule5 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: DestinationRule\\n\"\n            + \"metadata: { name: demo-route.Type1 }\\n\"\n            + \"spec:\\n\"\n            + \"  host: demo\\n\"\n            + \"\\n\";\n    private static final String rule6 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: VirtualService\\n\"\n            + \"metadata: { name: demo-route.Type1 }\\n\"\n            + \"spec:\\n\"\n            + \"  hosts: [demo]\\n\";\n    private static final String rule7 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: DestinationRule\\n\"\n            + \"metadata: { name: demo-route.Type2 }\\n\"\n            + \"spec:\\n\"\n            + \"  host: demo\\n\"\n            + \"\\n\";\n    private static final String rule8 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: VirtualService\\n\"\n            + \"metadata: { name: demo-route.Type2 }\\n\"\n            + \"spec:\\n\"\n            + \"  hosts: [demo]\\n\";\n\n    @Test\n    void testStandard() {\n        MeshAppRuleListener meshAppRuleListener = new MeshAppRuleListener(\"demo-route\");\n\n        StandardMeshRuleRouter standardMeshRuleRouter = Mockito.spy(new StandardMeshRuleRouter(URL.valueOf(\"\")));\n        meshAppRuleListener.register(standardMeshRuleRouter);\n\n        meshAppRuleListener.receiveConfigInfo(rule1 + \"---\\n\" + rule2);\n\n        ArgumentCaptor<String> appCaptor = ArgumentCaptor.forClass(String.class);\n        ArgumentCaptor<List<Map<String, Object>>> ruleCaptor = ArgumentCaptor.forClass(List.class);\n\n        verify(standardMeshRuleRouter, times(1)).onRuleChange(appCaptor.capture(), ruleCaptor.capture());\n\n        List<Map<String, Object>> rulesReceived = ruleCaptor.getValue();\n        assertEquals(2, rulesReceived.size());\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));\n\n        Assertions.assertEquals(\"demo-route\", appCaptor.getValue());\n\n        meshAppRuleListener.receiveConfigInfo(\"\");\n        verify(standardMeshRuleRouter, times(1)).clearRule(\"demo-route\");\n    }\n\n    @Test\n    void register() {\n        MeshAppRuleListener meshAppRuleListener = new MeshAppRuleListener(\"demo-route\");\n\n        StandardMeshRuleRouter standardMeshRuleRouter1 = Mockito.spy(new StandardMeshRuleRouter(URL.valueOf(\"\")));\n        StandardMeshRuleRouter standardMeshRuleRouter2 = Mockito.spy(new StandardMeshRuleRouter(URL.valueOf(\"\")));\n\n        meshAppRuleListener.register(standardMeshRuleRouter1);\n\n        Assertions.assertEquals(\n                1,\n                meshAppRuleListener\n                        .getMeshRuleDispatcher()\n                        .getListenerMap()\n                        .get(MeshRuleConstants.STANDARD_ROUTER_KEY)\n                        .size());\n        meshAppRuleListener.receiveConfigInfo(rule1 + \"---\\n\" + rule2);\n        meshAppRuleListener.register(standardMeshRuleRouter2);\n        Assertions.assertEquals(\n                2,\n                meshAppRuleListener\n                        .getMeshRuleDispatcher()\n                        .getListenerMap()\n                        .get(MeshRuleConstants.STANDARD_ROUTER_KEY)\n                        .size());\n\n        ArgumentCaptor<String> appCaptor = ArgumentCaptor.forClass(String.class);\n        ArgumentCaptor<List<Map<String, Object>>> ruleCaptor = ArgumentCaptor.forClass(List.class);\n\n        verify(standardMeshRuleRouter1, times(1)).onRuleChange(appCaptor.capture(), ruleCaptor.capture());\n\n        List<Map<String, Object>> rulesReceived = ruleCaptor.getValue();\n        assertEquals(2, rulesReceived.size());\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));\n\n        Assertions.assertEquals(\"demo-route\", appCaptor.getValue());\n\n        verify(standardMeshRuleRouter2, times(1)).onRuleChange(appCaptor.capture(), ruleCaptor.capture());\n        rulesReceived = ruleCaptor.getValue();\n        assertEquals(2, rulesReceived.size());\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));\n\n        Assertions.assertEquals(\"demo-route\", appCaptor.getValue());\n    }\n\n    @Test\n    void unregister() {\n        MeshAppRuleListener meshAppRuleListener = new MeshAppRuleListener(\"demo-route\");\n\n        StandardMeshRuleRouter standardMeshRuleRouter1 = Mockito.spy(new StandardMeshRuleRouter(URL.valueOf(\"\")));\n        StandardMeshRuleRouter standardMeshRuleRouter2 = Mockito.spy(new StandardMeshRuleRouter(URL.valueOf(\"\")));\n\n        meshAppRuleListener.register(standardMeshRuleRouter1);\n\n        Assertions.assertEquals(\n                1,\n                meshAppRuleListener\n                        .getMeshRuleDispatcher()\n                        .getListenerMap()\n                        .get(MeshRuleConstants.STANDARD_ROUTER_KEY)\n                        .size());\n        meshAppRuleListener.receiveConfigInfo(rule1 + \"---\\n\" + rule2);\n        meshAppRuleListener.register(standardMeshRuleRouter2);\n        Assertions.assertEquals(\n                2,\n                meshAppRuleListener\n                        .getMeshRuleDispatcher()\n                        .getListenerMap()\n                        .get(MeshRuleConstants.STANDARD_ROUTER_KEY)\n                        .size());\n\n        meshAppRuleListener.unregister(standardMeshRuleRouter1);\n        Assertions.assertEquals(\n                1,\n                meshAppRuleListener\n                        .getMeshRuleDispatcher()\n                        .getListenerMap()\n                        .get(MeshRuleConstants.STANDARD_ROUTER_KEY)\n                        .size());\n\n        meshAppRuleListener.unregister(standardMeshRuleRouter2);\n        Assertions.assertEquals(\n                0, meshAppRuleListener.getMeshRuleDispatcher().getListenerMap().size());\n    }\n\n    @Test\n    void process() {\n        MeshAppRuleListener meshAppRuleListener = new MeshAppRuleListener(\"demo-route\");\n\n        StandardMeshRuleRouter standardMeshRuleRouter = Mockito.spy(new StandardMeshRuleRouter(URL.valueOf(\"\")));\n        meshAppRuleListener.register(standardMeshRuleRouter);\n\n        ConfigChangedEvent configChangedEvent = new ConfigChangedEvent(\n                \"demo-route\" + MESH_RULE_DATA_ID_SUFFIX,\n                DynamicConfiguration.DEFAULT_GROUP,\n                rule1 + \"---\\n\" + rule2,\n                ConfigChangeType.ADDED);\n\n        meshAppRuleListener.process(configChangedEvent);\n\n        ArgumentCaptor<String> appCaptor = ArgumentCaptor.forClass(String.class);\n        ArgumentCaptor<List<Map<String, Object>>> ruleCaptor = ArgumentCaptor.forClass(List.class);\n\n        verify(standardMeshRuleRouter, times(1)).onRuleChange(appCaptor.capture(), ruleCaptor.capture());\n\n        List<Map<String, Object>> rulesReceived = ruleCaptor.getValue();\n        assertEquals(2, rulesReceived.size());\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));\n\n        configChangedEvent = new ConfigChangedEvent(\n                \"demo-route\" + MESH_RULE_DATA_ID_SUFFIX,\n                DynamicConfiguration.DEFAULT_GROUP,\n                rule1 + \"---\\n\" + rule2,\n                ConfigChangeType.MODIFIED);\n\n        meshAppRuleListener.process(configChangedEvent);\n\n        verify(standardMeshRuleRouter, times(2)).onRuleChange(appCaptor.capture(), ruleCaptor.capture());\n\n        rulesReceived = ruleCaptor.getValue();\n        assertEquals(2, rulesReceived.size());\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));\n\n        configChangedEvent = new ConfigChangedEvent(\n                \"demo-route\" + MESH_RULE_DATA_ID_SUFFIX,\n                DynamicConfiguration.DEFAULT_GROUP,\n                \"\",\n                ConfigChangeType.DELETED);\n        meshAppRuleListener.process(configChangedEvent);\n\n        verify(standardMeshRuleRouter, times(1)).clearRule(\"demo-route\");\n    }\n\n    @Test\n    void testUnknownRule() {\n        MeshAppRuleListener meshAppRuleListener = new MeshAppRuleListener(\"demo-route\");\n\n        StandardMeshRuleRouter standardMeshRuleRouter = Mockito.spy(new StandardMeshRuleRouter(URL.valueOf(\"\")));\n\n        meshAppRuleListener.register(standardMeshRuleRouter);\n\n        meshAppRuleListener.receiveConfigInfo(rule3 + \"---\\n\" + rule2);\n        ArgumentCaptor<String> appCaptor = ArgumentCaptor.forClass(String.class);\n        ArgumentCaptor<List<Map<String, Object>>> ruleCaptor = ArgumentCaptor.forClass(List.class);\n\n        verify(standardMeshRuleRouter, times(1)).onRuleChange(appCaptor.capture(), ruleCaptor.capture());\n\n        List<Map<String, Object>> rulesReceived = ruleCaptor.getValue();\n        assertEquals(1, rulesReceived.size());\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));\n\n        meshAppRuleListener.receiveConfigInfo(rule1 + \"---\\n\" + rule4);\n\n        verify(standardMeshRuleRouter, times(2)).onRuleChange(appCaptor.capture(), ruleCaptor.capture());\n\n        rulesReceived = ruleCaptor.getValue();\n        assertEquals(1, rulesReceived.size());\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));\n\n        meshAppRuleListener.receiveConfigInfo(rule3 + \"---\\n\" + rule4);\n        verify(standardMeshRuleRouter, times(1)).clearRule(\"demo-route\");\n    }\n\n    @Test\n    void testMultipleRule() {\n        MeshAppRuleListener meshAppRuleListener = new MeshAppRuleListener(\"demo-route\");\n\n        AtomicInteger count = new AtomicInteger(0);\n        MeshRuleListener listener1 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                Assertions.assertEquals(\"demo-route\", appName);\n                Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n                Assertions.assertTrue(rules.contains(yaml.load(rule5)));\n                Assertions.assertTrue(rules.contains(yaml.load(rule6)));\n                count.incrementAndGet();\n            }\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type1\";\n            }\n        };\n\n        MeshRuleListener listener2 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                Assertions.assertEquals(\"demo-route\", appName);\n                Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n                Assertions.assertTrue(rules.contains(yaml.load(rule7)));\n                Assertions.assertTrue(rules.contains(yaml.load(rule8)));\n                count.incrementAndGet();\n            }\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type2\";\n            }\n        };\n\n        MeshRuleListener listener4 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                Assertions.fail();\n            }\n\n            @Override\n            public void clearRule(String appName) {\n                Assertions.assertEquals(\"demo-route\", appName);\n                count.incrementAndGet();\n            }\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type4\";\n            }\n        };\n\n        StandardMeshRuleRouter standardMeshRuleRouter = Mockito.spy(new StandardMeshRuleRouter(URL.valueOf(\"\")));\n\n        meshAppRuleListener.register(standardMeshRuleRouter);\n        meshAppRuleListener.register(listener1);\n        meshAppRuleListener.register(listener2);\n        meshAppRuleListener.register(listener4);\n\n        meshAppRuleListener.receiveConfigInfo(\n                rule1 + \"---\\n\" + rule2 + \"---\\n\" + rule5 + \"---\\n\" + rule6 + \"---\\n\" + rule7 + \"---\\n\" + rule8);\n        ArgumentCaptor<String> appCaptor = ArgumentCaptor.forClass(String.class);\n        ArgumentCaptor<List<Map<String, Object>>> ruleCaptor = ArgumentCaptor.forClass(List.class);\n\n        verify(standardMeshRuleRouter, times(1)).onRuleChange(appCaptor.capture(), ruleCaptor.capture());\n\n        List<Map<String, Object>> rulesReceived = ruleCaptor.getValue();\n        assertEquals(2, rulesReceived.size());\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));\n        Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));\n\n        Assertions.assertEquals(\"demo-route\", appCaptor.getValue());\n\n        Assertions.assertEquals(3, count.get());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshRuleCacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.VsDestinationGroup;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.DestinationRule;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.DestinationRuleSpec;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.Subset;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass MeshRuleCacheTest {\n\n    private Invoker<Object> createInvoker(String app) {\n        URL url = URL.valueOf(\n                \"dubbo://localhost/DemoInterface?\" + (StringUtils.isEmpty(app) ? \"\" : \"remote.application=\" + app));\n        Invoker invoker = Mockito.mock(Invoker.class);\n        when(invoker.getUrl()).thenReturn(url);\n        return invoker;\n    }\n\n    @Test\n    void containMapKeyValue() {\n        URL url = mock(URL.class);\n        when(url.getOriginalServiceParameter(\"test\", \"key1\")).thenReturn(\"value1\");\n        when(url.getOriginalServiceParameter(\"test\", \"key2\")).thenReturn(\"value2\");\n        when(url.getOriginalServiceParameter(\"test\", \"key3\")).thenReturn(\"value3\");\n        when(url.getOriginalServiceParameter(\"test\", \"key4\")).thenReturn(\"value4\");\n\n        Map<String, String> originMap = new HashMap<>();\n\n        originMap.put(\"key1\", \"value1\");\n        originMap.put(\"key2\", \"value2\");\n        originMap.put(\"key3\", \"value3\");\n\n        Map<String, String> inputMap = new HashMap<>();\n\n        inputMap.put(\"key1\", \"value1\");\n        inputMap.put(\"key2\", \"value2\");\n\n        assertTrue(MeshRuleCache.isLabelMatch(url, \"test\", inputMap));\n\n        inputMap.put(\"key4\", \"value4\");\n        assertTrue(MeshRuleCache.isLabelMatch(url, \"test\", inputMap));\n    }\n\n    @Test\n    void testBuild() {\n        BitList<Invoker<Object>> invokers =\n                new BitList<>(Arrays.asList(createInvoker(\"\"), createInvoker(\"unknown\"), createInvoker(\"app1\")));\n\n        Subset subset = new Subset();\n        subset.setName(\"TestSubset\");\n        DestinationRule destinationRule = new DestinationRule();\n        DestinationRuleSpec destinationRuleSpec = new DestinationRuleSpec();\n        destinationRuleSpec.setSubsets(Collections.singletonList(subset));\n        destinationRule.setSpec(destinationRuleSpec);\n        VsDestinationGroup vsDestinationGroup = new VsDestinationGroup();\n        vsDestinationGroup.getDestinationRuleList().add(destinationRule);\n        Map<String, VsDestinationGroup> vsDestinationGroupMap = new HashMap<>();\n        vsDestinationGroupMap.put(\"app1\", vsDestinationGroup);\n\n        MeshRuleCache<Object> cache = MeshRuleCache.build(\"test\", invokers, vsDestinationGroupMap);\n        assertEquals(2, cache.getUnmatchedInvokers().size());\n        assertEquals(1, cache.getSubsetInvokers(\"app1\", \"TestSubset\").size());\n\n        subset.setLabels(Collections.singletonMap(\"test\", \"test\"));\n        cache = MeshRuleCache.build(\"test\", invokers, vsDestinationGroupMap);\n        assertEquals(3, cache.getUnmatchedInvokers().size());\n        assertEquals(0, cache.getSubsetInvokers(\"app1\", \"TestSubset\").size());\n\n        invokers = new BitList<>(Arrays.asList(\n                createInvoker(\"\"), createInvoker(\"unknown\"), createInvoker(\"app1\"), createInvoker(\"app2\")));\n        subset.setLabels(null);\n        cache = MeshRuleCache.build(\"test\", invokers, vsDestinationGroupMap);\n        assertEquals(3, cache.getUnmatchedInvokers().size());\n        assertEquals(1, cache.getSubsetInvokers(\"app1\", \"TestSubset\").size());\n        assertEquals(0, cache.getSubsetInvokers(\"app2\", \"TestSubset\").size());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshRuleManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.MeshRuleListener;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass MeshRuleManagerTest {\n    private static final String rule1 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: DestinationRule\\n\"\n            + \"metadata: { name: demo-route.Type1 }\\n\"\n            + \"spec:\\n\"\n            + \"  host: demo\\n\"\n            + \"\\n\";\n    private static final String rule2 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: VirtualService\\n\"\n            + \"metadata: { name: demo-route.Type1 }\\n\"\n            + \"spec:\\n\"\n            + \"  hosts: [demo]\\n\";\n    private static final String rule3 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: DestinationRule\\n\"\n            + \"metadata: { name: demo-route.Type2 }\\n\"\n            + \"spec:\\n\"\n            + \"  host: demo\\n\"\n            + \"\\n\";\n    private static final String rule4 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: VirtualService\\n\"\n            + \"metadata: { name: demo-route.Type2 }\\n\"\n            + \"spec:\\n\"\n            + \"  hosts: [demo]\\n\";\n\n    private ModuleModel originModule;\n    private ModuleModel moduleModel;\n    private GovernanceRuleRepository ruleRepository;\n    private Set<MeshEnvListenerFactory> envListenerFactories;\n\n    @BeforeEach\n    public void setup() {\n        originModule = ApplicationModel.defaultModel().getDefaultModule();\n        moduleModel = Mockito.spy(originModule);\n\n        ruleRepository = Mockito.mock(GovernanceRuleRepository.class);\n        when(moduleModel.getDefaultExtension(GovernanceRuleRepository.class)).thenReturn(ruleRepository);\n\n        ExtensionLoader<MeshEnvListenerFactory> envListenerFactoryLoader = Mockito.mock(ExtensionLoader.class);\n        envListenerFactories = new HashSet<>();\n        when(envListenerFactoryLoader.getSupportedExtensionInstances()).thenReturn(envListenerFactories);\n        when(moduleModel.getExtensionLoader(MeshEnvListenerFactory.class)).thenReturn(envListenerFactoryLoader);\n    }\n\n    @AfterEach\n    public void teardown() {\n        originModule.destroy();\n    }\n\n    @Test\n    void testRegister1() {\n        MeshRuleManager meshRuleManager = new MeshRuleManager(moduleModel);\n\n        MeshRuleListener meshRuleListener1 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                fail();\n            }\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type1\";\n            }\n        };\n\n        meshRuleManager.register(\"dubbo-demo\", meshRuleListener1);\n\n        assertEquals(1, meshRuleManager.getAppRuleListeners().size());\n        verify(ruleRepository, times(1)).getRule(\"dubbo-demo.MESHAPPRULE\", \"dubbo\", 5000L);\n\n        MeshAppRuleListener meshAppRuleListener =\n                meshRuleManager.getAppRuleListeners().values().iterator().next();\n        verify(ruleRepository, times(1)).addListener(\"dubbo-demo.MESHAPPRULE\", \"dubbo\", meshAppRuleListener);\n\n        meshRuleManager.register(\"dubbo-demo\", meshRuleListener1);\n        assertEquals(1, meshRuleManager.getAppRuleListeners().size());\n\n        MeshRuleListener meshRuleListener2 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                fail();\n            }\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type2\";\n            }\n        };\n        meshRuleManager.register(\"dubbo-demo\", meshRuleListener2);\n        assertEquals(1, meshRuleManager.getAppRuleListeners().size());\n        assertEquals(\n                2, meshAppRuleListener.getMeshRuleDispatcher().getListenerMap().size());\n\n        meshRuleManager.unregister(\"dubbo-demo\", meshRuleListener1);\n        assertEquals(1, meshRuleManager.getAppRuleListeners().size());\n        assertEquals(\n                1, meshAppRuleListener.getMeshRuleDispatcher().getListenerMap().size());\n\n        meshRuleManager.unregister(\"dubbo-demo\", meshRuleListener2);\n        assertEquals(0, meshRuleManager.getAppRuleListeners().size());\n\n        verify(ruleRepository, times(1)).removeListener(\"dubbo-demo.MESHAPPRULE\", \"dubbo\", meshAppRuleListener);\n    }\n\n    @Test\n    void testRegister2() {\n        MeshRuleManager meshRuleManager = new MeshRuleManager(moduleModel);\n\n        AtomicInteger invokeTimes = new AtomicInteger(0);\n        MeshRuleListener meshRuleListener = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                assertEquals(\"dubbo-demo\", appName);\n                Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n                assertTrue(rules.contains(yaml.load(rule1)));\n                assertTrue(rules.contains(yaml.load(rule2)));\n\n                invokeTimes.incrementAndGet();\n            }\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type1\";\n            }\n        };\n\n        when(ruleRepository.getRule(\"dubbo-demo.MESHAPPRULE\", \"dubbo\", 5000L)).thenReturn(rule1 + \"---\\n\" + rule2);\n\n        meshRuleManager.register(\"dubbo-demo\", meshRuleListener);\n\n        assertEquals(1, meshRuleManager.getAppRuleListeners().size());\n        verify(ruleRepository, times(1)).getRule(\"dubbo-demo.MESHAPPRULE\", \"dubbo\", 5000L);\n        verify(ruleRepository, times(1))\n                .addListener(\n                        \"dubbo-demo.MESHAPPRULE\",\n                        \"dubbo\",\n                        meshRuleManager\n                                .getAppRuleListeners()\n                                .values()\n                                .iterator()\n                                .next());\n        assertEquals(1, invokeTimes.get());\n\n        meshRuleManager.register(\"dubbo-demo\", meshRuleListener);\n        assertEquals(1, meshRuleManager.getAppRuleListeners().size());\n    }\n\n    @Test\n    void testRegister3() {\n        MeshEnvListenerFactory meshEnvListenerFactory1 = Mockito.mock(MeshEnvListenerFactory.class);\n        MeshEnvListenerFactory meshEnvListenerFactory2 = Mockito.mock(MeshEnvListenerFactory.class);\n\n        MeshEnvListener meshEnvListener1 = Mockito.mock(MeshEnvListener.class);\n        when(meshEnvListenerFactory1.getListener()).thenReturn(meshEnvListener1);\n        MeshEnvListener meshEnvListener2 = Mockito.mock(MeshEnvListener.class);\n        when(meshEnvListenerFactory2.getListener()).thenReturn(meshEnvListener2);\n\n        envListenerFactories.add(meshEnvListenerFactory1);\n        envListenerFactories.add(meshEnvListenerFactory2);\n\n        MeshRuleManager meshRuleManager = new MeshRuleManager(moduleModel);\n\n        MeshRuleListener meshRuleListener1 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                fail();\n            }\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type1\";\n            }\n        };\n\n        when(meshEnvListener1.isEnable()).thenReturn(false);\n        when(meshEnvListener2.isEnable()).thenReturn(true);\n\n        meshRuleManager.register(\"dubbo-demo\", meshRuleListener1);\n\n        assertEquals(1, meshRuleManager.getAppRuleListeners().size());\n        verify(ruleRepository, times(1)).getRule(\"dubbo-demo.MESHAPPRULE\", \"dubbo\", 5000L);\n        MeshAppRuleListener meshAppRuleListener =\n                meshRuleManager.getAppRuleListeners().values().iterator().next();\n        verify(ruleRepository, times(1)).addListener(\"dubbo-demo.MESHAPPRULE\", \"dubbo\", meshAppRuleListener);\n\n        verify(meshEnvListener2, times(1)).onSubscribe(\"dubbo-demo\", meshAppRuleListener);\n\n        meshRuleManager.register(\"dubbo-demo\", meshRuleListener1);\n        assertEquals(1, meshRuleManager.getAppRuleListeners().size());\n\n        MeshRuleListener meshRuleListener2 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                fail();\n            }\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type2\";\n            }\n        };\n        meshRuleManager.register(\"dubbo-demo\", meshRuleListener2);\n        assertEquals(1, meshRuleManager.getAppRuleListeners().size());\n        assertEquals(\n                2, meshAppRuleListener.getMeshRuleDispatcher().getListenerMap().size());\n\n        meshRuleManager.unregister(\"dubbo-demo\", meshRuleListener1);\n        assertEquals(1, meshRuleManager.getAppRuleListeners().size());\n        assertEquals(\n                1, meshAppRuleListener.getMeshRuleDispatcher().getListenerMap().size());\n\n        meshRuleManager.unregister(\"dubbo-demo\", meshRuleListener2);\n        assertEquals(0, meshRuleManager.getAppRuleListeners().size());\n\n        verify(ruleRepository, times(1)).removeListener(\"dubbo-demo.MESHAPPRULE\", \"dubbo\", meshAppRuleListener);\n        verify(meshEnvListener2, times(1)).onUnSubscribe(\"dubbo-demo\");\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshRuleRouterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass MeshRuleRouterTest {\n    private static final String rule1 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: DestinationRule\\n\"\n            + \"metadata: { name: demo-route }\\n\"\n            + \"spec:\\n\"\n            + \"  host: demo\\n\"\n            + \"  subsets:\\n\"\n            + \"    - labels: { env-sign: xxx, tag1: hello }\\n\"\n            + \"      name: isolation\\n\"\n            + \"    - labels: { env-sign: yyy }\\n\"\n            + \"      name: testing-trunk\\n\"\n            + \"    - labels: { env-sign: zzz }\\n\"\n            + \"      name: testing\\n\"\n            + \"  trafficPolicy:\\n\"\n            + \"    loadBalancer: { simple: ROUND_ROBIN }\\n\"\n            + \"\\n\";\n    private static final String rule2 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: VirtualService\\n\"\n            + \"metadata: { name: demo-route }\\n\"\n            + \"spec:\\n\"\n            + \"  dubbo:\\n\"\n            + \"    - routedetail:\\n\"\n            + \"        - match:\\n\"\n            + \"            - attachments: \\n\"\n            + \"                dubboContext: {trafficLabel: {regex: xxx}}\\n\"\n            + \"          name: xxx-project\\n\"\n            + \"          route:\\n\"\n            + \"            - destination: {host: demo, subset: isolation}\\n\"\n            + \"        - match:\\n\"\n            + \"            - attachments: \\n\"\n            + \"                dubboContext: {trafficLabel: {regex: testing-trunk}}\\n\"\n            + \"          name: testing-trunk\\n\"\n            + \"          route:\\n\"\n            + \"            - destination:\\n\"\n            + \"                host: demo\\n\"\n            + \"                subset: testing-trunk\\n\"\n            + \"                fallback:\\n\"\n            + \"                  host: demo\\n\"\n            + \"                  subset: testing\\n\"\n            + \"        - name: testing\\n\"\n            + \"          route:\\n\"\n            + \"            - destination: {host: demo, subset: testing}\\n\"\n            + \"      services:\\n\"\n            + \"        - {regex: ccc}\\n\"\n            + \"  hosts: [demo]\\n\";\n    private static final String rule3 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: VirtualService\\n\"\n            + \"metadata: { name: demo-route }\\n\"\n            + \"spec:\\n\"\n            + \"  dubbo:\\n\"\n            + \"    - routedetail:\\n\"\n            + \"        - match:\\n\"\n            + \"            - attachments: \\n\"\n            + \"                dubboContext: {trafficLabel: {regex: xxx}}\\n\"\n            + \"          name: xxx-project\\n\"\n            + \"          route:\\n\"\n            + \"            - destination: {host: demo, subset: isolation}\\n\"\n            + \"        - match:\\n\"\n            + \"            - attachments: \\n\"\n            + \"                dubboContext: {trafficLabel: {regex: testing-trunk}}\\n\"\n            + \"          name: testing-trunk\\n\"\n            + \"          route:\\n\"\n            + \"            - destination:\\n\"\n            + \"                host: demo\\n\"\n            + \"                subset: testing-trunk\\n\"\n            + \"                fallback:\\n\"\n            + \"                  host: demo\\n\"\n            + \"                  subset: testing\\n\"\n            + \"        - match:\\n\"\n            + \"            - attachments: \\n\"\n            + \"                dubboContext: {trafficLabel: {regex: testing}}\\n\"\n            + \"          name: testing\\n\"\n            + \"          route:\\n\"\n            + \"            - destination: {host: demo, subset: testing}\\n\"\n            + \"  hosts: [demo]\\n\";\n    private static final String rule4 = \"apiVersion: service.dubbo.apache.org/v1alpha1\\n\" + \"kind: VirtualService\\n\"\n            + \"metadata: { name: demo-route }\\n\"\n            + \"spec:\\n\"\n            + \"  dubbo:\\n\"\n            + \"    - routedetail:\\n\"\n            + \"        - match:\\n\"\n            + \"            - attachments: \\n\"\n            + \"                dubboContext: {trafficLabel: {regex: xxx}}\\n\"\n            + \"          name: xxx-project\\n\"\n            + \"          route:\\n\"\n            + \"            - destination: {host: demo, subset: isolation}\\n\"\n            + \"        - match:\\n\"\n            + \"            - attachments: \\n\"\n            + \"                dubboContext: {trafficLabel: {regex: testing-trunk}}\\n\"\n            + \"          name: testing-trunk\\n\"\n            + \"          route:\\n\"\n            + \"            - destination:\\n\"\n            + \"                host: demo\\n\"\n            + \"                subset: testing-trunk\\n\"\n            + \"                fallback:\\n\"\n            + \"                  destination:\\n\"\n            + \"                    host: demo\\n\"\n            + \"                    subset: testing\\n\"\n            + \"            - weight: 10\\n\"\n            + \"              destination:\\n\"\n            + \"                host: demo\\n\"\n            + \"                subset: isolation\\n\"\n            + \"        - match:\\n\"\n            + \"            - attachments: \\n\"\n            + \"                dubboContext: {trafficLabel: {regex: testing}}\\n\"\n            + \"          name: testing\\n\"\n            + \"          route:\\n\"\n            + \"            - destination: {host: demo, subset: testing}\\n\"\n            + \"  hosts: [demo]\\n\";\n\n    private ModuleModel originModel;\n    private ModuleModel moduleModel;\n    private MeshRuleManager meshRuleManager;\n    private Set<TracingContextProvider> tracingContextProviders;\n    private URL url;\n\n    @BeforeEach\n    public void setup() {\n        originModel = ApplicationModel.defaultModel().getDefaultModule();\n        moduleModel = Mockito.spy(originModel);\n\n        ScopeBeanFactory originBeanFactory = originModel.getBeanFactory();\n        ScopeBeanFactory beanFactory = Mockito.spy(originBeanFactory);\n        when(moduleModel.getBeanFactory()).thenReturn(beanFactory);\n\n        meshRuleManager = Mockito.mock(MeshRuleManager.class);\n        when(beanFactory.getBean(MeshRuleManager.class)).thenReturn(meshRuleManager);\n\n        ExtensionLoader<TracingContextProvider> extensionLoader = Mockito.mock(ExtensionLoader.class);\n        tracingContextProviders = new HashSet<>();\n        when(extensionLoader.getSupportedExtensionInstances()).thenReturn(tracingContextProviders);\n        when(moduleModel.getExtensionLoader(TracingContextProvider.class)).thenReturn(extensionLoader);\n\n        url = URL.valueOf(\"test://localhost/DemoInterface\").setScopeModel(moduleModel);\n    }\n\n    @AfterEach\n    public void teardown() {\n        originModel.destroy();\n    }\n\n    private Invoker<Object> createInvoker(String app) {\n        URL url = URL.valueOf(\n                \"dubbo://localhost/DemoInterface?\" + (StringUtils.isEmpty(app) ? \"\" : \"remote.application=\" + app));\n        Invoker invoker = Mockito.mock(Invoker.class);\n        when(invoker.getUrl()).thenReturn(url);\n        return invoker;\n    }\n\n    private Invoker<Object> createInvoker(Map<String, String> parameters) {\n        URL url = URL.valueOf(\"dubbo://localhost/DemoInterface?remote.application=app1\")\n                .addParameters(parameters);\n        Invoker invoker = Mockito.mock(Invoker.class);\n        when(invoker.getUrl()).thenReturn(url);\n        return invoker;\n    }\n\n    @Test\n    void testNotify() {\n        StandardMeshRuleRouter<Object> meshRuleRouter = new StandardMeshRuleRouter<>(url);\n        meshRuleRouter.notify(null);\n        assertEquals(0, meshRuleRouter.getRemoteAppName().size());\n\n        BitList<Invoker<Object>> invokers =\n                new BitList<>(Arrays.asList(createInvoker(\"\"), createInvoker(\"unknown\"), createInvoker(\"app1\")));\n\n        meshRuleRouter.notify(invokers);\n\n        assertEquals(1, meshRuleRouter.getRemoteAppName().size());\n        assertTrue(meshRuleRouter.getRemoteAppName().contains(\"app1\"));\n        assertEquals(invokers, meshRuleRouter.getInvokerList());\n\n        verify(meshRuleManager, times(1)).register(\"app1\", meshRuleRouter);\n\n        invokers = new BitList<>(Arrays.asList(createInvoker(\"unknown\"), createInvoker(\"app2\")));\n        meshRuleRouter.notify(invokers);\n        verify(meshRuleManager, times(1)).register(\"app2\", meshRuleRouter);\n        verify(meshRuleManager, times(1)).unregister(\"app1\", meshRuleRouter);\n        assertEquals(invokers, meshRuleRouter.getInvokerList());\n\n        meshRuleRouter.stop();\n        verify(meshRuleManager, times(1)).unregister(\"app2\", meshRuleRouter);\n    }\n\n    @Test\n    void testRuleChange() {\n        StandardMeshRuleRouter<Object> meshRuleRouter = new StandardMeshRuleRouter<>(url);\n\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        List<Map<String, Object>> rules = new LinkedList<>();\n        rules.add(yaml.load(rule1));\n\n        meshRuleRouter.onRuleChange(\"app1\", rules);\n        assertEquals(0, meshRuleRouter.getMeshRuleCache().getAppToVDGroup().size());\n\n        rules.add(yaml.load(rule2));\n        meshRuleRouter.onRuleChange(\"app1\", rules);\n        assertEquals(1, meshRuleRouter.getMeshRuleCache().getAppToVDGroup().size());\n        assertTrue(meshRuleRouter.getMeshRuleCache().getAppToVDGroup().containsKey(\"app1\"));\n\n        meshRuleRouter.onRuleChange(\"app2\", rules);\n        assertEquals(2, meshRuleRouter.getMeshRuleCache().getAppToVDGroup().size());\n        assertTrue(meshRuleRouter.getMeshRuleCache().getAppToVDGroup().containsKey(\"app1\"));\n        assertTrue(meshRuleRouter.getMeshRuleCache().getAppToVDGroup().containsKey(\"app2\"));\n\n        meshRuleRouter.clearRule(\"app1\");\n        assertEquals(1, meshRuleRouter.getMeshRuleCache().getAppToVDGroup().size());\n        assertTrue(meshRuleRouter.getMeshRuleCache().getAppToVDGroup().containsKey(\"app2\"));\n    }\n\n    @Test\n    void testRoute1() {\n        StandardMeshRuleRouter<Object> meshRuleRouter = new StandardMeshRuleRouter<>(url);\n        BitList<Invoker<Object>> invokers =\n                new BitList<>(Arrays.asList(createInvoker(\"\"), createInvoker(\"unknown\"), createInvoker(\"app1\")));\n        assertEquals(invokers, meshRuleRouter.route(invokers.clone(), null, null, false, null));\n        Holder<String> message = new Holder<>();\n        meshRuleRouter.doRoute(invokers.clone(), null, null, true, null, message);\n        assertEquals(\"MeshRuleCache has not been built. Skip route.\", message.get());\n    }\n\n    @Test\n    void testRoute2() {\n        StandardMeshRuleRouter<Object> meshRuleRouter = new StandardMeshRuleRouter<>(url);\n\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        List<Map<String, Object>> rules = new LinkedList<>();\n        rules.add(yaml.load(rule1));\n        rules.add(yaml.load(rule2));\n        meshRuleRouter.onRuleChange(\"app1\", rules);\n\n        Invoker<Object> isolation = createInvoker(new HashMap<String, String>() {\n            {\n                put(\"env-sign\", \"xxx\");\n                put(\"tag1\", \"hello\");\n            }\n        });\n        Invoker<Object> testingTrunk = createInvoker(Collections.singletonMap(\"env-sign\", \"yyy\"));\n        Invoker<Object> testing = createInvoker(Collections.singletonMap(\"env-sign\", \"zzz\"));\n\n        BitList<Invoker<Object>> invokers = new BitList<>(Arrays.asList(isolation, testingTrunk, testing));\n        meshRuleRouter.notify(invokers);\n\n        RpcInvocation rpcInvocation = new RpcInvocation();\n\n        rpcInvocation.setServiceName(\"ccc\");\n        rpcInvocation.setAttachment(\"trafficLabel\", \"xxx\");\n        assertEquals(\n                1,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .size());\n        assertEquals(\n                isolation,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .get(0));\n        Holder<String> message = new Holder<>();\n        meshRuleRouter.doRoute(invokers.clone(), null, rpcInvocation, true, null, message);\n        assertEquals(\"Match App: app1 Subset: isolation \", message.get());\n\n        rpcInvocation.setAttachment(\"trafficLabel\", \"testing-trunk\");\n        assertEquals(\n                1,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .size());\n        assertEquals(\n                testingTrunk,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .get(0));\n\n        rpcInvocation.setAttachment(\"trafficLabel\", null);\n        assertEquals(\n                1,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .size());\n        assertEquals(\n                testing,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .get(0));\n\n        rpcInvocation.setServiceName(\"aaa\");\n        assertEquals(invokers, meshRuleRouter.route(invokers.clone(), null, rpcInvocation, false, null));\n        message = new Holder<>();\n        meshRuleRouter.doRoute(invokers.clone(), null, rpcInvocation, true, null, message);\n        assertEquals(\"Empty protection after routed.\", message.get());\n\n        rules = new LinkedList<>();\n        rules.add(yaml.load(rule1));\n        rules.add(yaml.load(rule3));\n        meshRuleRouter.onRuleChange(\"app1\", rules);\n\n        rpcInvocation.setServiceName(\"ccc\");\n        rpcInvocation.setAttachment(\"trafficLabel\", \"xxx\");\n        assertEquals(\n                1,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .size());\n        assertEquals(\n                isolation,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .get(0));\n\n        rpcInvocation.setAttachment(\"trafficLabel\", \"testing-trunk\");\n        assertEquals(\n                1,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .size());\n        assertEquals(\n                testingTrunk,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .get(0));\n\n        rpcInvocation.setAttachment(\"trafficLabel\", \"testing\");\n        assertEquals(\n                1,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .size());\n        assertEquals(\n                testing,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .get(0));\n\n        rpcInvocation.setServiceName(\"aaa\");\n        assertEquals(\n                1,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .size());\n        assertEquals(\n                testing,\n                meshRuleRouter\n                        .route(invokers.clone(), null, rpcInvocation, false, null)\n                        .get(0));\n\n        rpcInvocation.setAttachment(\"trafficLabel\", null);\n        assertEquals(invokers, meshRuleRouter.route(invokers.clone(), null, rpcInvocation, false, null));\n\n        rules = new LinkedList<>();\n        rules.add(yaml.load(rule1));\n        rules.add(yaml.load(rule4));\n        meshRuleRouter.onRuleChange(\"app1\", rules);\n\n        rpcInvocation.setAttachment(\"trafficLabel\", \"testing-trunk\");\n\n        int testingCount = 0;\n        int isolationCount = 0;\n        for (int i = 0; i < 1000; i++) {\n            BitList<Invoker<Object>> result = meshRuleRouter.route(invokers.clone(), null, rpcInvocation, false, null);\n            assertEquals(1, result.size());\n            if (result.contains(testing)) {\n                testingCount++;\n            } else {\n                isolationCount++;\n            }\n        }\n        assertTrue(isolationCount > testingCount * 10);\n\n        invokers.removeAll(Arrays.asList(isolation, testingTrunk));\n        for (int i = 0; i < 1000; i++) {\n            assertEquals(\n                    1,\n                    meshRuleRouter\n                            .route(invokers.clone(), null, rpcInvocation, false, null)\n                            .size());\n            assertEquals(\n                    testing,\n                    meshRuleRouter\n                            .route(invokers.clone(), null, rpcInvocation, false, null)\n                            .get(0));\n        }\n\n        meshRuleRouter.notify(invokers);\n\n        for (int i = 0; i < 1000; i++) {\n            assertEquals(\n                    1,\n                    meshRuleRouter\n                            .route(invokers.clone(), null, rpcInvocation, false, null)\n                            .size());\n            assertEquals(\n                    testing,\n                    meshRuleRouter\n                            .route(invokers.clone(), null, rpcInvocation, false, null)\n                            .get(0));\n        }\n\n        Invoker<Object> mock = createInvoker(Collections.singletonMap(\"env-sign\", \"mock\"));\n        invokers = new BitList<>(Arrays.asList(isolation, testingTrunk, testing, mock));\n\n        meshRuleRouter.notify(invokers);\n        invokers.removeAll(Arrays.asList(isolation, testingTrunk, testing));\n        assertEquals(invokers, meshRuleRouter.route(invokers.clone(), null, rpcInvocation, false, null));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/route/StandardMeshRuleRouterFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.route;\n\nimport org.apache.dubbo.common.URL;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass StandardMeshRuleRouterFactoryTest {\n\n    @Test\n    void getRouter() {\n        StandardMeshRuleRouterFactory ruleRouterFactory = new StandardMeshRuleRouterFactory();\n        Assertions.assertTrue(\n                ruleRouterFactory.getRouter(Object.class, URL.valueOf(\"\")) instanceof StandardMeshRuleRouter);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/DestinationRuleTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule;\n\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.DestinationRule;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance.SimpleLB;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.VirtualServiceRule;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.yaml.snakeyaml.Yaml;\n\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.DESTINATION_RULE_KEY;\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.KIND_KEY;\nimport static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.VIRTUAL_SERVICE_KEY;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\n\nclass DestinationRuleTest {\n\n    @Test\n    void parserTest() {\n        Yaml yaml = new Yaml();\n        DestinationRule destinationRule = yaml.loadAs(\n                this.getClass().getClassLoader().getResourceAsStream(\"DestinationRuleTest.yaml\"),\n                DestinationRule.class);\n\n        //        apiVersion: service.dubbo.apache.org/v1alpha1\n        //        kind: DestinationRule\n        //        metadata: { name: demo-route }\n        //        spec:\n        //        host: demo\n        //        subsets:\n        //        - labels: { env-sign: xxx,tag1: hello }\n        //        name: isolation\n        //                - labels: { env-sign: yyy }\n        //        name: testing-trunk\n        //                - labels: { env-sign: zzz }\n        //        name: testing\n\n        assertEquals(\"service.dubbo.apache.org/v1alpha1\", destinationRule.getApiVersion());\n        assertEquals(DESTINATION_RULE_KEY, destinationRule.getKind());\n        assertEquals(\"demo-route\", destinationRule.getMetadata().get(\"name\"));\n        assertEquals(\"demo\", destinationRule.getSpec().getHost());\n        assertEquals(3, destinationRule.getSpec().getSubsets().size());\n\n        assertEquals(\"isolation\", destinationRule.getSpec().getSubsets().get(0).getName());\n        assertEquals(\n                2, destinationRule.getSpec().getSubsets().get(0).getLabels().size());\n        assertEquals(\n                \"xxx\", destinationRule.getSpec().getSubsets().get(0).getLabels().get(\"env-sign\"));\n        assertEquals(\n                \"hello\",\n                destinationRule.getSpec().getSubsets().get(0).getLabels().get(\"tag1\"));\n\n        assertEquals(\n                \"testing-trunk\", destinationRule.getSpec().getSubsets().get(1).getName());\n        assertEquals(\n                1, destinationRule.getSpec().getSubsets().get(1).getLabels().size());\n        assertEquals(\n                \"yyy\", destinationRule.getSpec().getSubsets().get(1).getLabels().get(\"env-sign\"));\n\n        assertEquals(\"testing\", destinationRule.getSpec().getSubsets().get(2).getName());\n        assertEquals(\n                1, destinationRule.getSpec().getSubsets().get(2).getLabels().size());\n        assertEquals(\n                \"zzz\", destinationRule.getSpec().getSubsets().get(2).getLabels().get(\"env-sign\"));\n\n        assertEquals(\n                SimpleLB.ROUND_ROBIN,\n                destinationRule.getSpec().getTrafficPolicy().getLoadBalancer().getSimple());\n        assertEquals(\n                null,\n                destinationRule.getSpec().getTrafficPolicy().getLoadBalancer().getConsistentHash());\n    }\n\n    @Test\n    void parserMultiRuleTest() {\n        Yaml yaml = new Yaml();\n        Yaml yaml2 = new Yaml();\n        Iterable objectIterable =\n                yaml.loadAll(this.getClass().getClassLoader().getResourceAsStream(\"DestinationRuleTest2.yaml\"));\n        for (Object result : objectIterable) {\n\n            Map resultMap = (Map) result;\n            if (resultMap.get(\"kind\").equals(DESTINATION_RULE_KEY)) {\n                DestinationRule destinationRule = yaml2.loadAs(yaml2.dump(result), DestinationRule.class);\n                assertNotNull(destinationRule);\n            } else if (resultMap.get(KIND_KEY).equals(VIRTUAL_SERVICE_KEY)) {\n                VirtualServiceRule virtualServiceRule = yaml2.loadAs(yaml2.dump(result), VirtualServiceRule.class);\n                assertNotNull(virtualServiceRule);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/VirtualServiceRuleTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule;\n\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.DubboRoute;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.DubboRouteDetail;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.VirtualServiceRule;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.yaml.snakeyaml.Yaml;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass VirtualServiceRuleTest {\n\n    @Test\n    void parserTest() {\n        Yaml yaml = new Yaml();\n        VirtualServiceRule virtualServiceRule = yaml.loadAs(\n                this.getClass().getClassLoader().getResourceAsStream(\"VirtualServiceTest.yaml\"),\n                VirtualServiceRule.class);\n\n        assertNotNull(virtualServiceRule);\n\n        assertEquals(\"service.dubbo.apache.org/v1alpha1\", virtualServiceRule.getApiVersion());\n        assertEquals(\"VirtualService\", virtualServiceRule.getKind());\n        assertEquals(\"demo-route\", virtualServiceRule.getMetadata().get(\"name\"));\n\n        List<String> hosts = virtualServiceRule.getSpec().getHosts();\n        assertEquals(1, hosts.size());\n        assertEquals(\"demo\", hosts.get(0));\n\n        List<DubboRoute> dubboRoutes = virtualServiceRule.getSpec().getDubbo();\n        assertEquals(1, dubboRoutes.size());\n\n        DubboRoute dubboRoute = dubboRoutes.get(0);\n        assertNull(dubboRoute.getName());\n\n        assertEquals(1, dubboRoute.getServices().size());\n        assertEquals(\"ccc\", dubboRoute.getServices().get(0).getRegex());\n\n        List<DubboRouteDetail> routedetail = dubboRoute.getRoutedetail();\n        DubboRouteDetail firstDubboRouteDetail = routedetail.get(0);\n        DubboRouteDetail secondDubboRouteDetail = routedetail.get(1);\n        DubboRouteDetail thirdDubboRouteDetail = routedetail.get(2);\n\n        assertEquals(\"xxx-project\", firstDubboRouteDetail.getName());\n        assertEquals(\n                \"xxx\", firstDubboRouteDetail.getMatch().get(0).getSourceLabels().get(\"trafficLabel\"));\n        assertEquals(\n                \"demo\", firstDubboRouteDetail.getRoute().get(0).getDestination().getHost());\n        assertEquals(\n                \"isolation\",\n                firstDubboRouteDetail.getRoute().get(0).getDestination().getSubset());\n\n        assertEquals(\"testing-trunk\", secondDubboRouteDetail.getName());\n        assertEquals(\n                \"testing-trunk\",\n                secondDubboRouteDetail.getMatch().get(0).getSourceLabels().get(\"trafficLabel\"));\n        assertEquals(\n                \"demo\",\n                secondDubboRouteDetail.getRoute().get(0).getDestination().getHost());\n        assertEquals(\n                \"testing-trunk\",\n                secondDubboRouteDetail.getRoute().get(0).getDestination().getSubset());\n\n        assertEquals(\"testing\", thirdDubboRouteDetail.getName());\n        assertNull(thirdDubboRouteDetail.getMatch());\n        assertEquals(\n                \"demo\", thirdDubboRouteDetail.getRoute().get(0).getDestination().getHost());\n        assertEquals(\n                \"testing\",\n                thirdDubboRouteDetail.getRoute().get(0).getDestination().getSubset());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/DubboMatchRequestTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;\n\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.DubboAttachmentMatch;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.DubboMethodMatch;\nimport org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.StringMatch;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass DubboMatchRequestTest {\n\n    @Test\n    void isMatch() {\n        DubboMatchRequest dubboMatchRequest = new DubboMatchRequest();\n\n        // methodMatch\n        DubboMethodMatch dubboMethodMatch = new DubboMethodMatch();\n        StringMatch nameStringMatch = new StringMatch();\n        nameStringMatch.setExact(\"sayHello\");\n        dubboMethodMatch.setName_match(nameStringMatch);\n\n        dubboMatchRequest.setMethod(dubboMethodMatch);\n\n        RpcInvocation rpcInvocation = new RpcInvocation();\n        rpcInvocation.setMethodName(\"sayHello\");\n        assertTrue(dubboMatchRequest.isMatch(rpcInvocation, new HashMap<>(), Collections.emptySet()));\n\n        rpcInvocation.setMethodName(\"satHi\");\n        assertFalse(dubboMatchRequest.isMatch(rpcInvocation, new HashMap<>(), Collections.emptySet()));\n\n        // sourceLabels\n        Map<String, String> sourceLabels = new HashMap<>();\n        sourceLabels.put(\"key1\", \"value1\");\n        sourceLabels.put(\"key2\", \"value2\");\n\n        dubboMatchRequest.setSourceLabels(sourceLabels);\n\n        Map<String, String> inputSourceLabelsMap = new HashMap<>();\n        inputSourceLabelsMap.put(\"key1\", \"value1\");\n        inputSourceLabelsMap.put(\"key2\", \"value2\");\n        inputSourceLabelsMap.put(\"key3\", \"value3\");\n\n        Map<String, String> inputSourceLabelsMap2 = new HashMap<>();\n        inputSourceLabelsMap2.put(\"key1\", \"other\");\n        inputSourceLabelsMap2.put(\"key2\", \"value2\");\n        inputSourceLabelsMap2.put(\"key3\", \"value3\");\n\n        rpcInvocation.setMethodName(\"sayHello\");\n        assertTrue(dubboMatchRequest.isMatch(rpcInvocation, inputSourceLabelsMap, Collections.emptySet()));\n        assertFalse(dubboMatchRequest.isMatch(rpcInvocation, inputSourceLabelsMap2, Collections.emptySet()));\n\n        // tracingContext\n        DubboAttachmentMatch dubboAttachmentMatch = new DubboAttachmentMatch();\n        Map<String, StringMatch> tracingContextMatchMap = new HashMap<>();\n        StringMatch nameMatch = new StringMatch();\n        nameMatch.setExact(\"qinliujie\");\n        tracingContextMatchMap.put(\"name\", nameMatch);\n        dubboAttachmentMatch.setTracingContext(tracingContextMatchMap);\n        dubboMatchRequest.setAttachments(dubboAttachmentMatch);\n\n        Map<String, String> invokeTracingContextMap = new HashMap<>();\n        invokeTracingContextMap.put(\"name\", \"qinliujie\");\n        invokeTracingContextMap.put(\"machineGroup\", \"test_host\");\n        invokeTracingContextMap.put(\"other\", \"other\");\n\n        TracingContextProvider tracingContextProvider = (invocation, key) -> invokeTracingContextMap.get(key);\n        assertTrue(dubboMatchRequest.isMatch(\n                rpcInvocation, inputSourceLabelsMap, Collections.singleton(tracingContextProvider)));\n\n        Map<String, String> invokeTracingContextMap2 = new HashMap<>();\n        invokeTracingContextMap2.put(\"name\", \"jack\");\n        invokeTracingContextMap2.put(\"machineGroup\", \"test_host\");\n        invokeTracingContextMap2.put(\"other\", \"other\");\n\n        TracingContextProvider tracingContextProvider2 = (invocation, key) -> invokeTracingContextMap2.get(key);\n        assertFalse(dubboMatchRequest.isMatch(\n                rpcInvocation, inputSourceLabelsMap, Collections.singleton(tracingContextProvider2)));\n\n        // dubbo context\n        dubboAttachmentMatch = new DubboAttachmentMatch();\n\n        Map<String, StringMatch> eagleeyecontextMatchMap = new HashMap<>();\n        nameMatch = new StringMatch();\n        nameMatch.setExact(\"qinliujie\");\n        eagleeyecontextMatchMap.put(\"name\", nameMatch);\n        dubboAttachmentMatch.setTracingContext(eagleeyecontextMatchMap);\n\n        Map<String, StringMatch> dubboContextMatchMap = new HashMap<>();\n        StringMatch dpathMatch = new StringMatch();\n        dpathMatch.setExact(\"PRE\");\n        dubboContextMatchMap.put(\"dpath\", dpathMatch);\n        dubboAttachmentMatch.setDubboContext(dubboContextMatchMap);\n\n        dubboMatchRequest.setAttachments(dubboAttachmentMatch);\n\n        Map<String, String> invokeDubboContextMap = new HashMap<>();\n        invokeDubboContextMap.put(\"dpath\", \"PRE\");\n\n        rpcInvocation.setAttachments(invokeDubboContextMap);\n        TracingContextProvider tracingContextProvider3 = (invocation, key) -> invokeTracingContextMap.get(key);\n        assertTrue(dubboMatchRequest.isMatch(\n                rpcInvocation, inputSourceLabelsMap, Collections.singleton(tracingContextProvider3)));\n\n        Map<String, String> invokeDubboContextMap2 = new HashMap<>();\n        invokeDubboContextMap.put(\"dpath\", \"other\");\n\n        rpcInvocation.setAttachments(invokeDubboContextMap2);\n        assertFalse(dubboMatchRequest.isMatch(\n                rpcInvocation, inputSourceLabelsMap, Collections.singleton(tracingContextProvider3)));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/BoolMatchTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass BoolMatchTest {\n\n    @Test\n    void isMatch() {\n        BoolMatch boolMatch = new BoolMatch();\n        boolMatch.setExact(true);\n\n        assertTrue(boolMatch.isMatch(true));\n        assertFalse(boolMatch.isMatch(false));\n\n        boolMatch.setExact(false);\n        assertFalse(boolMatch.isMatch(true));\n        assertTrue(boolMatch.isMatch(false));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/DoubleMatchTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass DoubleMatchTest {\n\n    @Test\n    void exactMatch() {\n        DoubleMatch doubleMatch = new DoubleMatch();\n        doubleMatch.setExact(10.0);\n\n        assertTrue(doubleMatch.isMatch(10.0));\n        assertFalse(doubleMatch.isMatch(9.0));\n    }\n\n    @Test\n    void rangeStartMatch() {\n        DoubleMatch doubleMatch = new DoubleMatch();\n\n        DoubleRangeMatch doubleRangeMatch = new DoubleRangeMatch();\n        doubleRangeMatch.setStart(10.0);\n\n        doubleMatch.setRange(doubleRangeMatch);\n\n        assertTrue(doubleMatch.isMatch(10.0));\n        assertFalse(doubleMatch.isMatch(9.0));\n    }\n\n    @Test\n    void rangeEndMatch() {\n        DoubleMatch doubleMatch = new DoubleMatch();\n\n        DoubleRangeMatch doubleRangeMatch = new DoubleRangeMatch();\n        doubleRangeMatch.setEnd(10.0);\n\n        doubleMatch.setRange(doubleRangeMatch);\n\n        assertFalse(doubleMatch.isMatch(10.0));\n        assertTrue(doubleMatch.isMatch(9.0));\n    }\n\n    @Test\n    void rangeStartEndMatch() {\n        DoubleMatch doubleMatch = new DoubleMatch();\n\n        DoubleRangeMatch doubleRangeMatch = new DoubleRangeMatch();\n        doubleRangeMatch.setStart(5.0);\n        doubleRangeMatch.setEnd(10.0);\n\n        doubleMatch.setRange(doubleRangeMatch);\n\n        assertTrue(doubleMatch.isMatch(5.0));\n        assertFalse(doubleMatch.isMatch(10.0));\n\n        assertFalse(doubleMatch.isMatch(4.9));\n        assertFalse(doubleMatch.isMatch(10.1));\n\n        assertTrue(doubleMatch.isMatch(6.0));\n    }\n\n    @Test\n    void modMatch() {\n        DoubleMatch doubleMatch = new DoubleMatch();\n\n        doubleMatch.setMod(2.0);\n        doubleMatch.setExact(3.0);\n\n        assertFalse(doubleMatch.isMatch(3.0));\n\n        doubleMatch.setExact(1.0);\n\n        assertTrue(doubleMatch.isMatch(1.0));\n        assertFalse(doubleMatch.isMatch(2.0));\n        assertTrue(doubleMatch.isMatch(3.0));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/DubboAttachmentMatchTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass DubboAttachmentMatchTest {\n\n    @Test\n    void dubboContextMatch() {\n        DubboAttachmentMatch dubboAttachmentMatch = new DubboAttachmentMatch();\n\n        Map<String, StringMatch> dubbocontextMatchMap = new HashMap<>();\n\n        StringMatch nameMatch = new StringMatch();\n        nameMatch.setExact(\"qinliujie\");\n        dubbocontextMatchMap.put(\"name\", nameMatch);\n\n        StringMatch machineGroupMatch = new StringMatch();\n        machineGroupMatch.setExact(\"test_host\");\n        dubbocontextMatchMap.put(\"machineGroup\", machineGroupMatch);\n\n        dubboAttachmentMatch.setDubboContext(dubbocontextMatchMap);\n\n        Map<String, String> invokeDubboContextMap = new HashMap<>();\n        invokeDubboContextMap.put(\"name\", \"qinliujie\");\n        invokeDubboContextMap.put(\"machineGroup\", \"test_host\");\n        invokeDubboContextMap.put(\"other\", \"other\");\n\n        RpcInvocation rpcInvocation = new RpcInvocation();\n        rpcInvocation.setAttachments(invokeDubboContextMap);\n\n        assertTrue(dubboAttachmentMatch.isMatch(rpcInvocation, Collections.emptySet()));\n\n        Map<String, String> invokeDubboContextMap2 = new HashMap<>();\n        invokeDubboContextMap2.put(\"name\", \"jack\");\n        invokeDubboContextMap2.put(\"machineGroup\", \"test_host\");\n        invokeDubboContextMap2.put(\"other\", \"other\");\n\n        RpcInvocation rpcInvocation2 = new RpcInvocation();\n        rpcInvocation2.setAttachments(invokeDubboContextMap2);\n\n        assertFalse(dubboAttachmentMatch.isMatch(rpcInvocation2, Collections.emptySet()));\n\n        Map<String, String> invokeDubboContextMap3 = new HashMap<>();\n        invokeDubboContextMap3.put(\"name\", \"qinliujie\");\n        invokeDubboContextMap3.put(\"machineGroup\", \"my_host\");\n        invokeDubboContextMap3.put(\"other\", \"other\");\n\n        RpcInvocation rpcInvocation3 = new RpcInvocation();\n        rpcInvocation3.setAttachments(invokeDubboContextMap3);\n\n        assertFalse(dubboAttachmentMatch.isMatch(rpcInvocation3, Collections.emptySet()));\n    }\n\n    @Test\n    void tracingContextMatch() {\n        DubboAttachmentMatch dubboAttachmentMatch = new DubboAttachmentMatch();\n\n        Map<String, StringMatch> tracingContextMatchMap = new HashMap<>();\n\n        StringMatch nameMatch = new StringMatch();\n        nameMatch.setExact(\"qinliujie\");\n        tracingContextMatchMap.put(\"name\", nameMatch);\n\n        StringMatch machineGroupMatch = new StringMatch();\n        machineGroupMatch.setExact(\"test_host\");\n        tracingContextMatchMap.put(\"machineGroup\", machineGroupMatch);\n\n        dubboAttachmentMatch.setTracingContext(tracingContextMatchMap);\n\n        Map<String, String> invokeEagleEyeContextMap = new HashMap<>();\n        invokeEagleEyeContextMap.put(\"name\", \"qinliujie\");\n        invokeEagleEyeContextMap.put(\"machineGroup\", \"test_host\");\n        invokeEagleEyeContextMap.put(\"other\", \"other\");\n\n        TracingContextProvider tracingContextProvider = (invocation, key) -> invokeEagleEyeContextMap.get(key);\n        assertTrue(dubboAttachmentMatch.isMatch(\n                Mockito.mock(Invocation.class), Collections.singleton(tracingContextProvider)));\n\n        Map<String, String> invokeTracingContextMap2 = new HashMap<>();\n        invokeTracingContextMap2.put(\"name\", \"jack\");\n        invokeTracingContextMap2.put(\"machineGroup\", \"test_host\");\n        invokeTracingContextMap2.put(\"other\", \"other\");\n\n        TracingContextProvider tracingContextProvider2 = (invocation, key) -> invokeTracingContextMap2.get(key);\n        assertFalse(dubboAttachmentMatch.isMatch(\n                Mockito.mock(Invocation.class), Collections.singleton(tracingContextProvider2)));\n\n        Map<String, String> invokeEagleEyeContextMap3 = new HashMap<>();\n        invokeEagleEyeContextMap3.put(\"name\", \"qinliujie\");\n        invokeEagleEyeContextMap3.put(\"machineGroup\", \"my_host\");\n        invokeEagleEyeContextMap3.put(\"other\", \"other\");\n\n        TracingContextProvider tracingContextProvider3 = (invocation, key) -> invokeEagleEyeContextMap3.get(key);\n        assertFalse(dubboAttachmentMatch.isMatch(\n                Mockito.mock(Invocation.class), Collections.singleton(tracingContextProvider3)));\n    }\n\n    @Test\n    void contextMatch() {\n        DubboAttachmentMatch dubboAttachmentMatch = new DubboAttachmentMatch();\n\n        Map<String, StringMatch> tracingContextMatchMap = new HashMap<>();\n        StringMatch nameMatch = new StringMatch();\n        nameMatch.setExact(\"qinliujie\");\n        tracingContextMatchMap.put(\"name\", nameMatch);\n        dubboAttachmentMatch.setTracingContext(tracingContextMatchMap);\n\n        Map<String, String> invokeTracingContextMap = new HashMap<>();\n        invokeTracingContextMap.put(\"name\", \"qinliujie\");\n        invokeTracingContextMap.put(\"machineGroup\", \"test_host\");\n        invokeTracingContextMap.put(\"other\", \"other\");\n\n        Map<String, StringMatch> dubboContextMatchMap = new HashMap<>();\n        StringMatch dpathMatch = new StringMatch();\n        dpathMatch.setExact(\"PRE\");\n        dubboContextMatchMap.put(\"dpath\", dpathMatch);\n        dubboAttachmentMatch.setDubboContext(dubboContextMatchMap);\n\n        Map<String, String> invokeDubboContextMap = new HashMap<>();\n        invokeDubboContextMap.put(\"dpath\", \"PRE\");\n\n        TracingContextProvider tracingContextProvider = (invocation, key) -> invokeTracingContextMap.get(key);\n        RpcInvocation rpcInvocation = new RpcInvocation();\n        rpcInvocation.setAttachments(invokeDubboContextMap);\n        assertTrue(dubboAttachmentMatch.isMatch(rpcInvocation, Collections.singleton(tracingContextProvider)));\n\n        Map<String, String> invokeTracingContextMap1 = new HashMap<>();\n        invokeTracingContextMap1.put(\"name\", \"jack\");\n        invokeTracingContextMap1.put(\"machineGroup\", \"test_host\");\n        invokeTracingContextMap1.put(\"other\", \"other\");\n\n        TracingContextProvider tracingContextProvider1 = (invocation, key) -> invokeTracingContextMap1.get(key);\n        RpcInvocation rpcInvocation1 = new RpcInvocation();\n        rpcInvocation1.setAttachments(invokeDubboContextMap);\n        assertFalse(dubboAttachmentMatch.isMatch(rpcInvocation1, Collections.singleton(tracingContextProvider1)));\n\n        Map<String, String> invokeDubboContextMap1 = new HashMap<>();\n        invokeDubboContextMap1.put(\"dpath\", \"PRE-2\");\n\n        TracingContextProvider tracingContextProvider2 = (invocation, key) -> invokeTracingContextMap.get(key);\n        RpcInvocation rpcInvocation2 = new RpcInvocation();\n        rpcInvocation2.setAttachments(invokeDubboContextMap1);\n        assertFalse(dubboAttachmentMatch.isMatch(rpcInvocation2, Collections.singleton(tracingContextProvider2)));\n\n        TracingContextProvider tracingContextProvider3 = (invocation, key) -> invokeTracingContextMap1.get(key);\n        RpcInvocation rpcInvocation3 = new RpcInvocation();\n        rpcInvocation3.setAttachments(invokeDubboContextMap1);\n        assertFalse(dubboAttachmentMatch.isMatch(rpcInvocation3, Collections.singleton(tracingContextProvider3)));\n\n        Map<String, String> invokeTracingContextMap2 = new HashMap<>();\n        invokeTracingContextMap2.put(\"machineGroup\", \"test_host\");\n        invokeTracingContextMap2.put(\"other\", \"other\");\n\n        TracingContextProvider tracingContextProvider4 = (invocation, key) -> invokeTracingContextMap2.get(key);\n        RpcInvocation rpcInvocation4 = new RpcInvocation();\n        rpcInvocation4.setAttachments(invokeDubboContextMap);\n        assertFalse(dubboAttachmentMatch.isMatch(rpcInvocation4, Collections.singleton(tracingContextProvider4)));\n\n        Map<String, String> invokeDubboContextMap2 = new HashMap<>();\n        TracingContextProvider tracingContextProvider5 = (invocation, key) -> invokeTracingContextMap.get(key);\n        RpcInvocation rpcInvocation5 = new RpcInvocation();\n        rpcInvocation5.setAttachments(invokeDubboContextMap2);\n        assertFalse(dubboAttachmentMatch.isMatch(rpcInvocation5, Collections.singleton(tracingContextProvider5)));\n\n        TracingContextProvider tracingContextProvider6 = (invocation, key) -> invokeTracingContextMap2.get(key);\n        RpcInvocation rpcInvocation6 = new RpcInvocation();\n        rpcInvocation5.setAttachments(invokeDubboContextMap2);\n        assertFalse(dubboAttachmentMatch.isMatch(rpcInvocation6, Collections.singleton(tracingContextProvider6)));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/DubboMethodMatchTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport org.apache.dubbo.rpc.RpcInvocation;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass DubboMethodMatchTest {\n\n    @Test\n    void nameMatch() {\n        DubboMethodMatch dubboMethodMatch = new DubboMethodMatch();\n\n        StringMatch nameStringMatch = new StringMatch();\n        nameStringMatch.setExact(\"sayHello\");\n\n        dubboMethodMatch.setName_match(nameStringMatch);\n\n        assertTrue(\n                dubboMethodMatch.isMatch(new RpcInvocation(null, \"sayHello\", \"\", \"\", new Class[] {}, new Object[] {})));\n    }\n\n    @Test\n    void argcMatch() {\n        DubboMethodMatch dubboMethodMatch = new DubboMethodMatch();\n        dubboMethodMatch.setArgc(1);\n\n        assertFalse(\n                dubboMethodMatch.isMatch(new RpcInvocation(null, \"sayHello\", \"\", \"\", new Class[] {}, new Object[] {})));\n        assertTrue(dubboMethodMatch.isMatch(\n                new RpcInvocation(null, \"sayHello\", \"\", \"\", new Class[] {}, new Object[] {\"1\"})));\n    }\n\n    @Test\n    void argpMatch() {\n        DubboMethodMatch dubboMethodMatch = new DubboMethodMatch();\n\n        List<StringMatch> argpMatch = new ArrayList<>();\n\n        StringMatch first = new StringMatch();\n        first.setExact(\"java.lang.Long\");\n\n        StringMatch second = new StringMatch();\n        second.setRegex(\".*\");\n\n        argpMatch.add(first);\n        argpMatch.add(second);\n\n        dubboMethodMatch.setArgp(argpMatch);\n\n        assertTrue(dubboMethodMatch.isMatch(\n                new RpcInvocation(null, \"sayHello\", \"\", \"\", new Class[] {Long.class, String.class}, new Object[] {})));\n        assertFalse(dubboMethodMatch.isMatch(new RpcInvocation(\n                null, \"sayHello\", \"\", \"\", new Class[] {Long.class, String.class, String.class}, new Object[] {})));\n        assertFalse(\n                dubboMethodMatch.isMatch(new RpcInvocation(null, \"sayHello\", \"\", \"\", new Class[] {}, new Object[] {})));\n    }\n\n    @Test\n    void parametersMatch() {\n\n        DubboMethodMatch dubboMethodMatch = new DubboMethodMatch();\n\n        List<DubboMethodArg> parametersMatch = new ArrayList<>();\n\n        // ----- index 0\n        {\n            DubboMethodArg dubboMethodArg0 = new DubboMethodArg();\n            dubboMethodArg0.setIndex(0);\n\n            ListDoubleMatch listDoubleMatch = new ListDoubleMatch();\n            List<DoubleMatch> oneof = new ArrayList<>();\n\n            DoubleMatch doubleMatch1 = new DoubleMatch();\n            doubleMatch1.setExact(10.0);\n\n            oneof.add(doubleMatch1);\n\n            listDoubleMatch.setOneof(oneof);\n\n            dubboMethodArg0.setNum_value(listDoubleMatch);\n\n            parametersMatch.add(dubboMethodArg0);\n        }\n\n        // -----index 1\n\n        {\n            DubboMethodArg dubboMethodArg1 = new DubboMethodArg();\n            dubboMethodArg1.setIndex(1);\n\n            ListStringMatch listStringMatch = new ListStringMatch();\n\n            List<StringMatch> oneof = new ArrayList<>();\n\n            StringMatch stringMatch1 = new StringMatch();\n            stringMatch1.setExact(\"sayHello\");\n\n            oneof.add(stringMatch1);\n\n            listStringMatch.setOneof(oneof);\n\n            dubboMethodArg1.setStr_value(listStringMatch);\n\n            parametersMatch.add(dubboMethodArg1);\n        }\n\n        dubboMethodMatch.setArgs(parametersMatch);\n\n        assertTrue(dubboMethodMatch.isMatch(new RpcInvocation(\n                null, \"test\", \"\", \"\", new Class[] {int.class, String.class}, new Object[] {10, \"sayHello\"})));\n        assertFalse(dubboMethodMatch.isMatch(new RpcInvocation(\n                null, \"test\", \"\", \"\", new Class[] {int.class, String.class}, new Object[] {10, \"sayHi\"})));\n\n        // -----index 2\n\n        {\n            DubboMethodArg dubboMethodArg2 = new DubboMethodArg();\n            dubboMethodArg2.setIndex(2);\n\n            BoolMatch boolMatch = new BoolMatch();\n            boolMatch.setExact(true);\n\n            dubboMethodArg2.setBool_value(boolMatch);\n\n            parametersMatch.add(dubboMethodArg2);\n        }\n\n        assertTrue(dubboMethodMatch.isMatch(new RpcInvocation(\n                null, \"test\", \"\", \"\", new Class[] {int.class, String.class, boolean.class}, new Object[] {\n                    10, \"sayHello\", true\n                })));\n        assertFalse(dubboMethodMatch.isMatch(new RpcInvocation(\n                null, \"test\", \"\", \"\", new Class[] {int.class, String.class, boolean.class}, new Object[] {\n                    10, \"sayHello\", false\n                })));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/ListBoolMatchTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ListBoolMatchTest {\n\n    @Test\n    void isMatch() {\n        ListBoolMatch listBoolMatch = new ListBoolMatch();\n        List<BoolMatch> oneof = new ArrayList<>();\n\n        BoolMatch boolMatch1 = new BoolMatch();\n        boolMatch1.setExact(true);\n        oneof.add(boolMatch1);\n        listBoolMatch.setOneof(oneof);\n\n        assertTrue(listBoolMatch.isMatch(true));\n        assertFalse(listBoolMatch.isMatch(false));\n\n        BoolMatch boolMatch2 = new BoolMatch();\n        boolMatch2.setExact(false);\n        oneof.add(boolMatch2);\n        listBoolMatch.setOneof(oneof);\n\n        assertTrue(listBoolMatch.isMatch(false));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/ListDoubleMatchTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ListDoubleMatchTest {\n\n    @Test\n    void isMatch() {\n        ListDoubleMatch listDoubleMatch = new ListDoubleMatch();\n        List<DoubleMatch> oneof = new ArrayList<>();\n\n        DoubleMatch doubleMatch1 = new DoubleMatch();\n        doubleMatch1.setExact(10.0);\n\n        DoubleMatch doubleMatch2 = new DoubleMatch();\n        doubleMatch2.setExact(11.0);\n\n        oneof.add(doubleMatch1);\n        oneof.add(doubleMatch2);\n\n        listDoubleMatch.setOneof(oneof);\n\n        assertTrue(listDoubleMatch.isMatch(10.0));\n        assertTrue(listDoubleMatch.isMatch(11.0));\n        assertFalse(listDoubleMatch.isMatch(12.0));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/ListStringMatchTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ListStringMatchTest {\n\n    @Test\n    void isMatch() {\n        ListStringMatch listStringMatch = new ListStringMatch();\n\n        List<StringMatch> oneof = new ArrayList<>();\n\n        StringMatch stringMatch1 = new StringMatch();\n        stringMatch1.setExact(\"1\");\n\n        StringMatch stringMatch2 = new StringMatch();\n        stringMatch2.setExact(\"2\");\n\n        oneof.add(stringMatch1);\n        oneof.add(stringMatch2);\n\n        listStringMatch.setOneof(oneof);\n\n        assertTrue(listStringMatch.isMatch(\"1\"));\n        assertTrue(listStringMatch.isMatch(\"2\"));\n        assertFalse(listStringMatch.isMatch(\"3\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/match/StringMatchTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass StringMatchTest {\n\n    @Test\n    void exactMatch() {\n        StringMatch stringMatch = new StringMatch();\n        stringMatch.setExact(\"qinliujie\");\n\n        assertTrue(stringMatch.isMatch(\"qinliujie\"));\n        assertFalse(stringMatch.isMatch(\"other\"));\n        assertFalse(stringMatch.isMatch(null));\n    }\n\n    @Test\n    void prefixMatch() {\n        StringMatch stringMatch = new StringMatch();\n        stringMatch.setPrefix(\"org.apache.dubbo.rpc.cluster.router.mesh\");\n\n        assertTrue(stringMatch.isMatch(\"org.apache.dubbo.rpc.cluster.router.mesh.test\"));\n        assertFalse(stringMatch.isMatch(\"com.alibaba.hsf\"));\n        assertFalse(stringMatch.isMatch(null));\n    }\n\n    @Test\n    void regxMatch() {\n        StringMatch stringMatch = new StringMatch();\n        stringMatch.setRegex(\"org.apache.dubbo.rpc.cluster.router.mesh.*\");\n\n        assertTrue(stringMatch.isMatch(\"org.apache.dubbo.rpc.cluster.router.mesh\"));\n        assertTrue(stringMatch.isMatch(\"org.apache.dubbo.rpc.cluster.router.mesh.test\"));\n        assertFalse(stringMatch.isMatch(\"com.alibaba.hsf\"));\n        assertFalse(stringMatch.isMatch(\"com.taobao\"));\n    }\n\n    @Test\n    void emptyMatch() {\n        StringMatch stringMatch = new StringMatch();\n        stringMatch.setEmpty(\"empty\");\n\n        assertFalse(stringMatch.isMatch(\"com.alibaba.hsf\"));\n        assertTrue(stringMatch.isMatch(\"\"));\n        assertTrue(stringMatch.isMatch(null));\n    }\n\n    @Test\n    void noEmptyMatch() {\n        StringMatch stringMatch = new StringMatch();\n        stringMatch.setNoempty(\"noempty\");\n\n        assertTrue(stringMatch.isMatch(\"com.alibaba.hsf\"));\n        assertFalse(stringMatch.isMatch(\"\"));\n        assertFalse(stringMatch.isMatch(null));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/util/MeshRuleDispatcherTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mesh.util;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass MeshRuleDispatcherTest {\n\n    @Test\n    void post() {\n        MeshRuleDispatcher meshRuleDispatcher = new MeshRuleDispatcher(\"TestApp\");\n\n        Map<String, List<Map<String, Object>>> ruleMap = new HashMap<>();\n        List<Map<String, Object>> type1 = new LinkedList<>();\n        List<Map<String, Object>> type2 = new LinkedList<>();\n        List<Map<String, Object>> type3 = new LinkedList<>();\n        ruleMap.put(\"Type1\", type1);\n        ruleMap.put(\"Type2\", type2);\n        ruleMap.put(\"Type3\", type3);\n\n        AtomicInteger count = new AtomicInteger(0);\n        MeshRuleListener listener1 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                Assertions.assertEquals(\"TestApp\", appName);\n                Assertions.assertEquals(System.identityHashCode(type1), System.identityHashCode(rules));\n                count.incrementAndGet();\n            }\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type1\";\n            }\n        };\n\n        MeshRuleListener listener2 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                Assertions.assertEquals(\"TestApp\", appName);\n                Assertions.assertEquals(System.identityHashCode(type2), System.identityHashCode(rules));\n                count.incrementAndGet();\n            }\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type2\";\n            }\n        };\n\n        MeshRuleListener listener4 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {\n                Assertions.fail();\n            }\n\n            @Override\n            public void clearRule(String appName) {\n                Assertions.assertEquals(\"TestApp\", appName);\n                count.incrementAndGet();\n            }\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type4\";\n            }\n        };\n\n        meshRuleDispatcher.register(listener1);\n        meshRuleDispatcher.register(listener2);\n        meshRuleDispatcher.register(listener4);\n\n        meshRuleDispatcher.post(ruleMap);\n\n        Assertions.assertEquals(3, count.get());\n    }\n\n    @Test\n    void register() {\n        MeshRuleDispatcher meshRuleDispatcher = new MeshRuleDispatcher(\"TestApp\");\n\n        MeshRuleListener listener1 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {}\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type1\";\n            }\n        };\n\n        meshRuleDispatcher.register(listener1);\n        meshRuleDispatcher.register(listener1);\n\n        Assertions.assertEquals(\n                1, meshRuleDispatcher.getListenerMap().get(\"Type1\").size());\n        Assertions.assertTrue(meshRuleDispatcher.getListenerMap().get(\"Type1\").contains(listener1));\n    }\n\n    @Test\n    void unregister() {\n        MeshRuleDispatcher meshRuleDispatcher = new MeshRuleDispatcher(\"TestApp\");\n\n        MeshRuleListener listener1 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {}\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type1\";\n            }\n        };\n\n        MeshRuleListener listener2 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {}\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type1\";\n            }\n        };\n\n        MeshRuleListener listener3 = new MeshRuleListener() {\n            @Override\n            public void onRuleChange(String appName, List<Map<String, Object>> rules) {}\n\n            @Override\n            public void clearRule(String appName) {}\n\n            @Override\n            public String ruleSuffix() {\n                return \"Type2\";\n            }\n        };\n\n        meshRuleDispatcher.register(listener1);\n        meshRuleDispatcher.register(listener2);\n        meshRuleDispatcher.register(listener3);\n\n        Assertions.assertEquals(\n                2, meshRuleDispatcher.getListenerMap().get(\"Type1\").size());\n        Assertions.assertTrue(meshRuleDispatcher.getListenerMap().get(\"Type1\").contains(listener1));\n        Assertions.assertTrue(meshRuleDispatcher.getListenerMap().get(\"Type1\").contains(listener2));\n        Assertions.assertEquals(\n                1, meshRuleDispatcher.getListenerMap().get(\"Type2\").size());\n        Assertions.assertTrue(meshRuleDispatcher.getListenerMap().get(\"Type2\").contains(listener3));\n\n        meshRuleDispatcher.unregister(listener1);\n        Assertions.assertEquals(\n                1, meshRuleDispatcher.getListenerMap().get(\"Type1\").size());\n        Assertions.assertTrue(meshRuleDispatcher.getListenerMap().get(\"Type1\").contains(listener2));\n        Assertions.assertEquals(\n                1, meshRuleDispatcher.getListenerMap().get(\"Type2\").size());\n        Assertions.assertTrue(meshRuleDispatcher.getListenerMap().get(\"Type2\").contains(listener3));\n\n        meshRuleDispatcher.unregister(listener2);\n        Assertions.assertNull(meshRuleDispatcher.getListenerMap().get(\"Type1\"));\n        Assertions.assertEquals(\n                1, meshRuleDispatcher.getListenerMap().get(\"Type2\").size());\n        Assertions.assertTrue(meshRuleDispatcher.getListenerMap().get(\"Type2\").contains(listener3));\n\n        meshRuleDispatcher.unregister(listener3);\n        Assertions.assertNull(meshRuleDispatcher.getListenerMap().get(\"Type1\"));\n        Assertions.assertNull(meshRuleDispatcher.getListenerMap().get(\"Type2\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelectorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.INVOCATION_NEED_MOCK;\n\nclass MockInvokersSelectorTest {\n    @Test\n    void test() {\n\n        MockInvokersSelector selector = new MockInvokersSelector(URL.valueOf(\"\"));\n\n        // Data preparation\n        Invoker<DemoService> invoker1 = Mockito.mock(Invoker.class);\n        Invoker<DemoService> invoker2 = Mockito.mock(Invoker.class);\n        Invoker<DemoService> invoker3 = Mockito.mock(Invoker.class);\n        Mockito.when(invoker1.getUrl()).thenReturn(URL.valueOf(\"mock://127.0.0.1/test\"));\n        Mockito.when(invoker2.getUrl()).thenReturn(URL.valueOf(\"mock://127.0.0.1/test\"));\n        Mockito.when(invoker3.getUrl()).thenReturn(URL.valueOf(\"dubbo://127.0.0.1/test\"));\n        BitList<Invoker<DemoService>> providers = new BitList<>(Arrays.asList(invoker1, invoker2, invoker3));\n\n        RpcInvocation rpcInvocation = Mockito.mock(RpcInvocation.class);\n\n        URL consumerURL = URL.valueOf(\"test://127.0.0.1\");\n\n        selector.notify(providers);\n        // rpcInvocation does not have an attached \"invocation.need.mock\" parameter, so normal invokers will be filtered\n        // out\n        List<Invoker<DemoService>> invokers =\n                selector.route(providers.clone(), consumerURL, rpcInvocation, false, new Holder<>());\n        Assertions.assertEquals(invokers.size(), 1);\n        Assertions.assertTrue(invokers.contains(invoker3));\n\n        // rpcInvocation have an attached \"invocation.need.mock\" parameter, so it will filter out the invoker whose\n        // protocol is mock\n        Mockito.when(rpcInvocation.getObjectAttachmentWithoutConvert(INVOCATION_NEED_MOCK))\n                .thenReturn(\"true\");\n        invokers = selector.route(providers.clone(), consumerURL, rpcInvocation, false, new Holder<>());\n        Assertions.assertEquals(invokers.size(), 2);\n        Assertions.assertTrue(invokers.contains(invoker1));\n        Assertions.assertTrue(invokers.contains(invoker2));\n    }\n\n    class DemoService {}\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/script/ScriptStateRouterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.script;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.router.MockInvoker;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;\n\n@DisabledForJreRange(min = JRE.JAVA_16)\nclass ScriptStateRouterTest {\n\n    private URL SCRIPT_URL = URL.valueOf(\"script://javascript?type=javascript\");\n\n    @BeforeAll\n    public static void setUpBeforeClass() throws Exception {}\n\n    @BeforeEach\n    public void setUp() throws Exception {}\n\n    private URL getRouteUrl(String rule) {\n        return SCRIPT_URL.addParameterAndEncoded(RULE_KEY, rule);\n    }\n\n    @Test\n    void testRouteReturnAll() {\n        StateRouter router = new ScriptStateRouterFactory()\n                .getRouter(String.class, getRouteUrl(\"function route(op1,op2){return op1} route(invokers)\"));\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        originInvokers.add(new MockInvoker<String>());\n        originInvokers.add(new MockInvoker<String>());\n        originInvokers.add(new MockInvoker<String>());\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers =\n                router.route(invokers.clone(), invokers.get(0).getUrl(), new RpcInvocation(), false, new Holder<>());\n        Assertions.assertEquals(invokers, filteredInvokers);\n    }\n\n    @Test\n    void testRoutePickInvokers() {\n        String rule = \"var result = new java.util.ArrayList(invokers.size());\" + \"for (i=0;i<invokers.size(); i++){ \"\n                + \"if (invokers.get(i).isAvailable()) {\"\n                + \"result.add(invokers.get(i)) ;\"\n                + \"}\"\n                + \"} ; \"\n                + \"return result;\";\n        String script = \"function route(invokers,invocation,context){\" + rule + \"} route(invokers,invocation,context)\";\n        StateRouter router = new ScriptStateRouterFactory().getRouter(String.class, getRouteUrl(script));\n\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(false);\n        Invoker<String> invoker2 = new MockInvoker<String>(true);\n        Invoker<String> invoker3 = new MockInvoker<String>(true);\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        List<Invoker<String>> filteredInvokers =\n                router.route(invokers.clone(), invokers.get(0).getUrl(), new RpcInvocation(), false, new Holder<>());\n        Assertions.assertEquals(2, filteredInvokers.size());\n        Assertions.assertEquals(invoker2, filteredInvokers.get(0));\n        Assertions.assertEquals(invoker3, filteredInvokers.get(1));\n    }\n\n    @Test\n    void testRouteHostFilter() {\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        MockInvoker<String> invoker1 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://10.134.108.1:20880/com.dubbo.HelloService\"));\n        MockInvoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://10.134.108.2:20880/com.dubbo.HelloService\"));\n        MockInvoker<String> invoker3 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://10.134.108.3:20880/com.dubbo.HelloService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        String script = \"function route(invokers, invocation, context){ \"\n                + \"    var result = new java.util.ArrayList(invokers.size()); \"\n                + \"    var targetHost = new java.util.ArrayList(); \"\n                + \"    targetHost.add(\\\"10.134.108.2\\\"); \"\n                + \"    for (var i = 0; i < invokers.length; i++) { \"\n                + \"        if(targetHost.contains(invokers[i].getUrl().getHost())){ \"\n                + \"            result.add(invokers[i]); \"\n                + \"        } \"\n                + \"    } \"\n                + \"    return result; \"\n                + \"} \"\n                + \"route(invokers, invocation, context) \";\n\n        StateRouter router = new ScriptStateRouterFactory().getRouter(String.class, getRouteUrl(script));\n        List<Invoker<String>> routeResult =\n                router.route(invokers.clone(), invokers.get(0).getUrl(), new RpcInvocation(), false, new Holder<>());\n        Assertions.assertEquals(1, routeResult.size());\n        Assertions.assertEquals(invoker2, routeResult.get(0));\n    }\n\n    @Test\n    void testRoute_throwException() {\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        MockInvoker<String> invoker1 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://10.134.108.1:20880/com.dubbo.HelloService\"));\n        MockInvoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://10.134.108.2:20880/com.dubbo.HelloService\"));\n        MockInvoker<String> invoker3 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://10.134.108.3:20880/com.dubbo.HelloService\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        String script = \"/\";\n        StateRouter router = new ScriptStateRouterFactory().getRouter(String.class, getRouteUrl(script));\n        List<Invoker<String>> routeResult =\n                router.route(invokers.clone(), invokers.get(0).getUrl(), new RpcInvocation(), false, new Holder<>());\n        Assertions.assertEquals(3, routeResult.size());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/script/config/AppScriptStateRouterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.script.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository;\nimport org.apache.dubbo.rpc.cluster.router.MockInvoker;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;\n\n@DisabledForJreRange(min = JRE.JAVA_16)\npublic class AppScriptStateRouterTest {\n    private static final String LOCAL_HOST = \"127.0.0.1\";\n    private static final String RULE_SUFFIX = \".script-router\";\n\n    private static GovernanceRuleRepository ruleRepository;\n    private URL url = URL.valueOf(\"dubbo://1.1.1.1/com.foo.BarService\");\n    private String rawRule = \"---\\n\" + \"configVersion: v3.0\\n\"\n            + \"key: demo-provider\\n\"\n            + \"type: javascript\\n\"\n            + \"script: |\\n\"\n            + \"  (function route(invokers,invocation,context) {\\n\"\n            + \"      var result = new java.util.ArrayList(invokers.size());\\n\"\n            + \"      for (i = 0; i < invokers.size(); i ++) {\\n\"\n            + \"          if (\\\"10.20.3.3\\\".equals(invokers.get(i).getUrl().getHost())) {\\n\"\n            + \"              result.add(invokers.get(i));\\n\"\n            + \"          }\\n\"\n            + \"      }\\n\"\n            + \"      return result;\\n\"\n            + \"  } (invokers, invocation, context)); // 表示立即执行方法\\n\"\n            + \"...\";\n\n    @BeforeAll\n    public static void setUpBeforeClass() throws Exception {\n        ruleRepository = Mockito.mock(GovernanceRuleRepository.class);\n    }\n\n    @Test\n    void testConfigScriptRoute() {\n        AppScriptStateRouter<String> router = new AppScriptStateRouter<>(url);\n        router = Mockito.spy(router);\n        Mockito.when(router.getRuleRepository()).thenReturn(ruleRepository);\n        Mockito.when(ruleRepository.getRule(\"demo-provider\" + RULE_SUFFIX, DynamicConfiguration.DEFAULT_GROUP))\n                .thenReturn(rawRule);\n        //        Mockito.when(ruleRepository.addListener()).thenReturn();\n\n        BitList<Invoker<String>> invokers = getInvokers();\n        router.notify(invokers);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        List<Invoker<String>> result = router.route(invokers.clone(), url, invocation, false, new Holder<>());\n        Assertions.assertEquals(1, result.size());\n    }\n\n    private BitList<Invoker<String>> getInvokers() {\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(\n                URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService?\" + REMOTE_APPLICATION_KEY + \"=demo-provider\"));\n        Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf(\n                \"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService?\" + REMOTE_APPLICATION_KEY + \"=demo-provider\"));\n        Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf(\n                \"dubbo://\" + LOCAL_HOST + \":20880/com.foo.BarService?\" + REMOTE_APPLICATION_KEY + \"=demo-provider\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n        return invokers;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/state/BitListTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.state;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nclass BitListTest {\n    @Test\n    void test() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\");\n        BitList<String> bitList = new BitList<>(list);\n        Assertions.assertEquals(bitList.getOriginList(), list);\n        Assertions.assertEquals(3, bitList.size());\n\n        Assertions.assertEquals(\"A\", bitList.get(0));\n        Assertions.assertEquals(\"B\", bitList.get(1));\n        Assertions.assertEquals(\"C\", bitList.get(2));\n\n        Assertions.assertTrue(bitList.contains(\"A\"));\n        Assertions.assertTrue(bitList.contains(\"B\"));\n        Assertions.assertTrue(bitList.contains(\"C\"));\n\n        for (String str : bitList) {\n            Assertions.assertTrue(list.contains(str));\n        }\n\n        Assertions.assertEquals(0, bitList.indexOf(\"A\"));\n        Assertions.assertEquals(1, bitList.indexOf(\"B\"));\n        Assertions.assertEquals(2, bitList.indexOf(\"C\"));\n\n        Object[] objects = bitList.toArray();\n        for (Object obj : objects) {\n            Assertions.assertTrue(list.contains(obj));\n        }\n\n        Object[] newObjects = new Object[1];\n        Object[] copiedList = bitList.toArray(newObjects);\n        Assertions.assertEquals(3, copiedList.length);\n        Assertions.assertArrayEquals(copiedList, list.toArray());\n\n        newObjects = new Object[10];\n        copiedList = bitList.toArray(newObjects);\n        Assertions.assertEquals(10, copiedList.length);\n        Assertions.assertEquals(\"A\", copiedList[0]);\n        Assertions.assertEquals(\"B\", copiedList[1]);\n        Assertions.assertEquals(\"C\", copiedList[2]);\n\n        bitList.remove(0);\n        Assertions.assertEquals(\"B\", bitList.get(0));\n        bitList.addIndex(0);\n        Assertions.assertEquals(\"A\", bitList.get(0));\n\n        bitList.removeAll(list);\n        Assertions.assertEquals(0, bitList.size());\n        bitList.clear();\n    }\n\n    @Test\n    void testIntersect() {\n        List<String> aList = Arrays.asList(\"A\", \"B\", \"C\");\n        List<String> bList = Arrays.asList(\"A\", \"B\");\n        List<String> totalList = Arrays.asList(\"A\", \"B\", \"C\");\n\n        BitList<String> aBitList = new BitList<>(aList);\n        BitList<String> bBitList = new BitList<>(bList);\n\n        BitList<String> intersectBitList = aBitList.and(bBitList);\n        Assertions.assertEquals(2, intersectBitList.size());\n        Assertions.assertEquals(totalList.get(0), intersectBitList.get(0));\n        Assertions.assertEquals(totalList.get(1), intersectBitList.get(1));\n\n        aBitList.add(\"D\");\n        intersectBitList = aBitList.and(bBitList);\n        Assertions.assertEquals(3, intersectBitList.size());\n        Assertions.assertEquals(totalList.get(0), intersectBitList.get(0));\n        Assertions.assertEquals(totalList.get(1), intersectBitList.get(1));\n        Assertions.assertEquals(\"D\", intersectBitList.get(2));\n    }\n\n    @Test\n    void testIsEmpty() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\");\n        BitList<String> bitList = new BitList<>(list);\n        bitList.add(\"D\");\n\n        bitList.removeAll(list);\n        Assertions.assertEquals(1, bitList.size());\n\n        bitList.remove(\"D\");\n        Assertions.assertTrue(bitList.isEmpty());\n    }\n\n    @Test\n    void testAdd() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\");\n        BitList<String> bitList = new BitList<>(list);\n\n        bitList.remove(\"A\");\n\n        Assertions.assertEquals(2, bitList.size());\n\n        bitList.addAll(Collections.singletonList(\"A\"));\n        Assertions.assertEquals(3, bitList.size());\n\n        bitList.addAll(Collections.singletonList(\"D\"));\n        Assertions.assertEquals(4, bitList.size());\n        Assertions.assertEquals(\"D\", bitList.get(3));\n        Assertions.assertTrue(bitList.hasMoreElementInTailList());\n        Assertions.assertEquals(Collections.singletonList(\"D\"), bitList.getTailList());\n\n        bitList.clear();\n\n        bitList.addAll(Collections.singletonList(\"A\"));\n        Assertions.assertEquals(1, bitList.size());\n        Assertions.assertEquals(\"A\", bitList.get(0));\n    }\n\n    @Test\n    void testAddAll() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\");\n        BitList<String> bitList1 = new BitList<>(list);\n        BitList<String> bitList2 = new BitList<>(list);\n\n        bitList1.removeAll(list);\n        Assertions.assertEquals(0, bitList1.size());\n\n        bitList1.addAll(bitList2);\n\n        Assertions.assertEquals(3, bitList1.size());\n        Assertions.assertFalse(bitList1.hasMoreElementInTailList());\n\n        bitList1.addAll(bitList2);\n\n        Assertions.assertEquals(3, bitList1.size());\n    }\n\n    @Test\n    void testGet() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\");\n        BitList<String> bitList = new BitList<>(list);\n\n        Assertions.assertEquals(\"A\", bitList.get(0));\n        Assertions.assertEquals(\"B\", bitList.get(1));\n        Assertions.assertEquals(\"C\", bitList.get(2));\n\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> bitList.get(-1));\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> bitList.get(3));\n\n        bitList.add(\"D\");\n        Assertions.assertEquals(\"D\", bitList.get(3));\n\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> bitList.get(-1));\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> bitList.get(4));\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> bitList.get(5));\n    }\n\n    @Test\n    void testRemove() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\");\n        BitList<String> bitList = new BitList<>(list);\n\n        Assertions.assertTrue(bitList.remove(\"A\"));\n        Assertions.assertFalse(bitList.remove(\"A\"));\n\n        Assertions.assertTrue(bitList.removeAll(Collections.singletonList(\"B\")));\n        Assertions.assertFalse(bitList.removeAll(Collections.singletonList(\"B\")));\n\n        Assertions.assertFalse(bitList.removeAll(Collections.singletonList(\"D\")));\n\n        bitList.add(\"D\");\n        Assertions.assertTrue(bitList.removeAll(Collections.singletonList(\"D\")));\n        Assertions.assertFalse(bitList.hasMoreElementInTailList());\n\n        bitList.add(\"A\");\n        bitList.add(\"E\");\n        bitList.add(\"F\");\n\n        Assertions.assertEquals(4, bitList.size());\n\n        Assertions.assertFalse(bitList.removeAll(Collections.singletonList(\"D\")));\n        Assertions.assertTrue(bitList.removeAll(Collections.singletonList(\"A\")));\n        Assertions.assertTrue(bitList.removeAll(Collections.singletonList(\"C\")));\n        Assertions.assertTrue(bitList.removeAll(Collections.singletonList(\"E\")));\n        Assertions.assertTrue(bitList.removeAll(Collections.singletonList(\"F\")));\n\n        Assertions.assertTrue(bitList.isEmpty());\n    }\n\n    @Test\n    void testRemoveIndex() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\");\n        BitList<String> bitList = new BitList<>(list);\n\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> bitList.remove(3));\n        Assertions.assertNotNull(bitList.remove(1));\n        Assertions.assertNotNull(bitList.remove(0));\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> bitList.remove(1));\n\n        bitList.add(\"D\");\n        Assertions.assertNotNull(bitList.remove(1));\n\n        bitList.add(\"A\");\n        bitList.add(\"E\");\n        bitList.add(\"F\");\n        // A C E F\n        Assertions.assertEquals(4, bitList.size());\n\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> bitList.remove(4));\n        Assertions.assertEquals(\"F\", bitList.remove(3));\n        Assertions.assertEquals(\"E\", bitList.remove(2));\n        Assertions.assertEquals(\"C\", bitList.remove(1));\n        Assertions.assertEquals(\"A\", bitList.remove(0));\n\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> bitList.remove(0));\n\n        Assertions.assertTrue(bitList.isEmpty());\n    }\n\n    @Test\n    void testRetain() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\");\n        BitList<String> bitList = new BitList<>(list);\n\n        List<String> list1 = Arrays.asList(\"B\", \"C\");\n        Assertions.assertTrue(bitList.retainAll(list1));\n\n        Assertions.assertTrue(bitList.containsAll(list1));\n        Assertions.assertFalse(bitList.containsAll(list));\n        Assertions.assertFalse(bitList.contains(\"A\"));\n\n        bitList = new BitList<>(list);\n        bitList.add(\"D\");\n        bitList.add(\"E\");\n        List<String> list2 = Arrays.asList(\"B\", \"C\", \"D\");\n        Assertions.assertTrue(bitList.retainAll(list2));\n\n        Assertions.assertTrue(bitList.containsAll(list2));\n        Assertions.assertFalse(bitList.containsAll(list));\n        Assertions.assertFalse(bitList.contains(\"A\"));\n        Assertions.assertFalse(bitList.contains(\"E\"));\n    }\n\n    @Test\n    void testIndex() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"A\");\n        BitList<String> bitList = new BitList<>(list);\n\n        Assertions.assertEquals(0, bitList.indexOf(\"A\"));\n        Assertions.assertEquals(2, bitList.lastIndexOf(\"A\"));\n\n        Assertions.assertEquals(-1, bitList.indexOf(\"D\"));\n        Assertions.assertEquals(-1, bitList.lastIndexOf(\"D\"));\n\n        bitList.add(\"D\");\n        bitList.add(\"E\");\n\n        Assertions.assertEquals(0, bitList.indexOf(\"A\"));\n        Assertions.assertEquals(2, bitList.lastIndexOf(\"A\"));\n        Assertions.assertEquals(3, bitList.indexOf(\"D\"));\n        Assertions.assertEquals(3, bitList.lastIndexOf(\"D\"));\n\n        Assertions.assertEquals(-1, bitList.indexOf(\"F\"));\n    }\n\n    @Test\n    void testSubList() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n        bitList.addAll(Arrays.asList(\"F\", \"G\", \"H\", \"I\"));\n\n        BitList<String> subList1 = bitList.subList(0, 5);\n        Assertions.assertEquals(Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\"), subList1);\n\n        BitList<String> subList2 = bitList.subList(1, 5);\n        Assertions.assertEquals(Arrays.asList(\"B\", \"C\", \"D\", \"E\"), subList2);\n\n        BitList<String> subList3 = bitList.subList(0, 4);\n        Assertions.assertEquals(Arrays.asList(\"A\", \"B\", \"C\", \"D\"), subList3);\n\n        BitList<String> subList4 = bitList.subList(1, 4);\n        Assertions.assertEquals(Arrays.asList(\"B\", \"C\", \"D\"), subList4);\n\n        BitList<String> subList5 = bitList.subList(2, 3);\n        Assertions.assertEquals(Collections.singletonList(\"C\"), subList5);\n        Assertions.assertFalse(subList5.hasMoreElementInTailList());\n\n        BitList<String> subList6 = bitList.subList(0, 9);\n        Assertions.assertEquals(Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\"), subList6);\n        Assertions.assertEquals(Arrays.asList(\"F\", \"G\", \"H\", \"I\"), subList6.getTailList());\n\n        BitList<String> subList7 = bitList.subList(1, 8);\n        Assertions.assertEquals(Arrays.asList(\"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\"), subList7);\n        Assertions.assertEquals(Arrays.asList(\"F\", \"G\", \"H\"), subList7.getTailList());\n\n        BitList<String> subList8 = bitList.subList(4, 8);\n        Assertions.assertEquals(Arrays.asList(\"E\", \"F\", \"G\", \"H\"), subList8);\n        Assertions.assertEquals(Arrays.asList(\"F\", \"G\", \"H\"), subList8.getTailList());\n\n        BitList<String> subList9 = bitList.subList(5, 8);\n        Assertions.assertEquals(Arrays.asList(\"F\", \"G\", \"H\"), subList9);\n        Assertions.assertEquals(Arrays.asList(\"F\", \"G\", \"H\"), subList9.getTailList());\n\n        BitList<String> subList10 = bitList.subList(6, 8);\n        Assertions.assertEquals(Arrays.asList(\"G\", \"H\"), subList10);\n        Assertions.assertEquals(Arrays.asList(\"G\", \"H\"), subList10.getTailList());\n\n        BitList<String> subList11 = bitList.subList(6, 7);\n        Assertions.assertEquals(Collections.singletonList(\"G\"), subList11);\n        Assertions.assertEquals(Collections.singletonList(\"G\"), subList11.getTailList());\n    }\n\n    @Test\n    void testListIterator1() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n\n        ListIterator<String> listIterator = bitList.listIterator(2);\n        ListIterator<String> expectedIterator = list.listIterator(2);\n\n        while (listIterator.hasNext()) {\n            Assertions.assertEquals(expectedIterator.nextIndex(), listIterator.nextIndex());\n            Assertions.assertEquals(expectedIterator.next(), listIterator.next());\n        }\n\n        while (listIterator.hasPrevious()) {\n            Assertions.assertEquals(expectedIterator.previousIndex(), listIterator.previousIndex());\n            Assertions.assertEquals(expectedIterator.previous(), listIterator.previous());\n        }\n    }\n\n    @Test\n    @ValueSource(\n            ints = {\n                2,\n            })\n    void testListIterator2() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n        bitList.addAll(Arrays.asList(\"F\", \"G\", \"H\", \"I\"));\n        List<String> expectedResult = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\");\n\n        ListIterator<String> listIterator = bitList.listIterator(2);\n        ListIterator<String> expectedIterator = expectedResult.listIterator(2);\n\n        while (listIterator.hasNext()) {\n            Assertions.assertEquals(expectedIterator.nextIndex(), listIterator.nextIndex());\n            Assertions.assertEquals(expectedIterator.next(), listIterator.next());\n        }\n\n        while (listIterator.hasPrevious()) {\n            Assertions.assertEquals(expectedIterator.previousIndex(), listIterator.previousIndex());\n            Assertions.assertEquals(expectedIterator.previous(), listIterator.previous());\n        }\n    }\n\n    @Test\n    void testListIterator3() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n        bitList.addAll(Arrays.asList(\"F\", \"G\", \"H\", \"I\"));\n        List<String> expectedResult = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\");\n\n        ListIterator<String> listIterator = bitList.listIterator(7);\n        ListIterator<String> expectedIterator = expectedResult.listIterator(7);\n\n        while (listIterator.hasNext()) {\n            Assertions.assertEquals(expectedIterator.nextIndex(), listIterator.nextIndex());\n            Assertions.assertEquals(expectedIterator.next(), listIterator.next());\n        }\n\n        while (listIterator.hasPrevious()) {\n            Assertions.assertEquals(expectedIterator.previousIndex(), listIterator.previousIndex());\n            Assertions.assertEquals(expectedIterator.previous(), listIterator.previous());\n        }\n    }\n\n    @Test\n    void testListIterator4() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n        bitList.addAll(Arrays.asList(\"F\", \"G\", \"H\", \"I\"));\n        List<String> expectedResult = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\");\n\n        ListIterator<String> listIterator = bitList.listIterator(8);\n        ListIterator<String> expectedIterator = expectedResult.listIterator(8);\n\n        while (listIterator.hasNext()) {\n            Assertions.assertEquals(expectedIterator.nextIndex(), listIterator.nextIndex());\n            Assertions.assertEquals(expectedIterator.next(), listIterator.next());\n        }\n\n        while (listIterator.hasPrevious()) {\n            Assertions.assertEquals(expectedIterator.previousIndex(), listIterator.previousIndex());\n            Assertions.assertEquals(expectedIterator.previous(), listIterator.previous());\n        }\n    }\n\n    @Test\n    void testListIterator5() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n        bitList.addAll(Arrays.asList(\"F\", \"G\", \"H\", \"I\"));\n        List<String> expectedResult = new LinkedList<>(Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\"));\n\n        ListIterator<String> listIterator = bitList.listIterator(2);\n        ListIterator<String> expectedIterator = expectedResult.listIterator(2);\n\n        while (listIterator.hasNext()) {\n            Assertions.assertEquals(expectedIterator.nextIndex(), listIterator.nextIndex());\n            Assertions.assertEquals(expectedIterator.next(), listIterator.next());\n            listIterator.remove();\n            expectedIterator.remove();\n        }\n\n        Assertions.assertEquals(expectedResult, bitList);\n\n        while (listIterator.hasPrevious()) {\n            Assertions.assertEquals(expectedIterator.previousIndex(), listIterator.previousIndex());\n            Assertions.assertEquals(expectedIterator.previous(), listIterator.previous());\n            listIterator.remove();\n            expectedIterator.remove();\n        }\n\n        Assertions.assertEquals(expectedResult, bitList);\n    }\n\n    @Test\n    void testListIterator6() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n        bitList.addAll(Arrays.asList(\"F\", \"G\", \"H\", \"I\"));\n        List<String> expectedResult = new LinkedList<>(Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\"));\n\n        ListIterator<String> listIterator = bitList.listIterator(2);\n        ListIterator<String> expectedIterator = expectedResult.listIterator(2);\n\n        while (listIterator.hasPrevious()) {\n            Assertions.assertEquals(expectedIterator.previousIndex(), listIterator.previousIndex());\n            Assertions.assertEquals(expectedIterator.previous(), listIterator.previous());\n            listIterator.remove();\n            expectedIterator.remove();\n        }\n\n        Assertions.assertEquals(expectedResult, bitList);\n\n        while (listIterator.hasNext()) {\n            Assertions.assertEquals(expectedIterator.nextIndex(), listIterator.nextIndex());\n            Assertions.assertEquals(expectedIterator.next(), listIterator.next());\n            listIterator.remove();\n            expectedIterator.remove();\n        }\n\n        Assertions.assertEquals(expectedResult, bitList);\n    }\n\n    @Test\n    void testListIterator7() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n        bitList.addAll(Arrays.asList(\"F\", \"G\", \"H\", \"I\"));\n        List<String> expectedResult = new LinkedList<>(Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\"));\n\n        ListIterator<String> listIterator = bitList.listIterator(7);\n        ListIterator<String> expectedIterator = expectedResult.listIterator(7);\n\n        while (listIterator.hasNext()) {\n            Assertions.assertEquals(expectedIterator.nextIndex(), listIterator.nextIndex());\n            Assertions.assertEquals(expectedIterator.next(), listIterator.next());\n            listIterator.remove();\n            expectedIterator.remove();\n        }\n\n        Assertions.assertEquals(expectedResult, bitList);\n\n        while (listIterator.hasPrevious()) {\n            Assertions.assertEquals(expectedIterator.previousIndex(), listIterator.previousIndex());\n            Assertions.assertEquals(expectedIterator.previous(), listIterator.previous());\n            listIterator.remove();\n            expectedIterator.remove();\n        }\n\n        Assertions.assertEquals(expectedResult, bitList);\n    }\n\n    @Test\n    void testListIterator8() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n        bitList.addAll(Arrays.asList(\"F\", \"G\", \"H\", \"I\"));\n        List<String> expectedResult = new LinkedList<>(Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\"));\n\n        ListIterator<String> listIterator = bitList.listIterator(7);\n        ListIterator<String> expectedIterator = expectedResult.listIterator(7);\n\n        while (listIterator.hasPrevious()) {\n            Assertions.assertEquals(expectedIterator.previousIndex(), listIterator.previousIndex());\n            Assertions.assertEquals(expectedIterator.previous(), listIterator.previous());\n            listIterator.remove();\n            expectedIterator.remove();\n        }\n\n        Assertions.assertEquals(expectedResult, bitList);\n\n        while (listIterator.hasNext()) {\n            Assertions.assertEquals(expectedIterator.nextIndex(), listIterator.nextIndex());\n            Assertions.assertEquals(expectedIterator.next(), listIterator.next());\n            listIterator.remove();\n            expectedIterator.remove();\n        }\n\n        Assertions.assertEquals(expectedResult, bitList);\n    }\n\n    @Test\n    void testClone1() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n\n        BitList<String> clone1 = bitList.clone();\n        Assertions.assertNotSame(bitList, clone1);\n        Assertions.assertEquals(bitList, clone1);\n\n        HashSet<Object> set = new HashSet<>();\n        set.add(bitList);\n        set.add(clone1);\n        Assertions.assertEquals(1, set.size());\n\n        set.add(new LinkedList<>());\n        Assertions.assertEquals(2, set.size());\n\n        set.add(new LinkedList<>(Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\")));\n        Assertions.assertEquals(2, set.size());\n    }\n\n    @Test\n    void testClone2() {\n        List<String> list = Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\");\n        BitList<String> bitList = new BitList<>(list);\n        bitList.addAll(Arrays.asList(\"F\", \"G\"));\n\n        BitList<String> clone1 = bitList.clone();\n        Assertions.assertNotSame(bitList, clone1);\n        Assertions.assertEquals(bitList, clone1);\n\n        HashSet<Object> set = new HashSet<>();\n        set.add(bitList);\n        set.add(clone1);\n        Assertions.assertEquals(1, set.size());\n\n        set.add(new LinkedList<>());\n        Assertions.assertEquals(2, set.size());\n\n        set.add(new LinkedList<>(Arrays.asList(\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\")));\n        Assertions.assertEquals(2, set.size());\n    }\n\n    @Test\n    void testConcurrent() throws InterruptedException {\n        for (int i = 0; i < 100000; i++) {\n            BitList<String> bitList = new BitList<>(Collections.singletonList(\"test\"));\n            bitList.remove(\"test\");\n\n            CountDownLatch countDownLatch = new CountDownLatch(1);\n            CountDownLatch countDownLatch2 = new CountDownLatch(2);\n\n            Thread thread1 = new Thread(() -> {\n                try {\n                    countDownLatch.await();\n                } catch (InterruptedException e) {\n                    throw new RuntimeException(e);\n                }\n                bitList.add(\"test\");\n                countDownLatch2.countDown();\n            });\n\n            AtomicReference<BitList<String>> ref = new AtomicReference<>();\n            Thread thread2 = new Thread(() -> {\n                try {\n                    countDownLatch.await();\n                } catch (InterruptedException e) {\n                    throw new RuntimeException(e);\n                }\n                ref.set(bitList.clone());\n                countDownLatch2.countDown();\n            });\n\n            thread1.start();\n            thread2.start();\n\n            countDownLatch.countDown();\n            countDownLatch2.await();\n\n            Assertions.assertDoesNotThrow(() -> ref.get().iterator().hasNext());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.router.tag;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.router.MockInvoker;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\nimport org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule;\nimport org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.google.common.collect.Sets;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;\nimport static org.mockito.Mockito.when;\n\nclass TagStateRouterTest {\n    private URL url;\n    private ModuleModel originModel;\n    private ModuleModel moduleModel;\n\n    @BeforeEach\n    public void setup() {\n        originModel = ApplicationModel.defaultModel().getDefaultModule();\n        moduleModel = Mockito.spy(originModel);\n\n        ScopeBeanFactory originBeanFactory = originModel.getBeanFactory();\n        ScopeBeanFactory beanFactory = Mockito.spy(originBeanFactory);\n        when(moduleModel.getBeanFactory()).thenReturn(beanFactory);\n\n        url = URL.valueOf(\"test://localhost/DemoInterface\").setScopeModel(moduleModel);\n    }\n\n    @Test\n    void testTagRoutePickInvokers() {\n        StateRouter router = new TagStateRouterFactory().getRouter(TagRouterRule.class, url);\n\n        List<Invoker<String>> originInvokers = new ArrayList<>();\n\n        URL url1 = URL.valueOf(\"test://127.0.0.1:7777/DemoInterface?dubbo.tag=tag2\")\n                .setScopeModel(moduleModel);\n        URL url2 = URL.valueOf(\"test://127.0.0.1:7778/DemoInterface\").setScopeModel(moduleModel);\n        URL url3 = URL.valueOf(\"test://127.0.0.1:7779/DemoInterface\").setScopeModel(moduleModel);\n        Invoker<String> invoker1 = new MockInvoker<>(url1, true);\n        Invoker<String> invoker2 = new MockInvoker<>(url2, true);\n        Invoker<String> invoker3 = new MockInvoker<>(url3, true);\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setAttachment(TAG_KEY, \"tag2\");\n        List<Invoker<String>> filteredInvokers =\n                router.route(invokers.clone(), invokers.get(0).getUrl(), invocation, false, new Holder<>());\n        Assertions.assertEquals(1, filteredInvokers.size());\n        Assertions.assertEquals(invoker1, filteredInvokers.get(0));\n    }\n\n    @Test\n    void testTagRouteWithDynamicRuleV3() {\n        TagStateRouter router = (TagStateRouter) new TagStateRouterFactory().getRouter(TagRouterRule.class, url);\n        router = Mockito.spy(router);\n\n        List<Invoker<String>> originInvokers = new ArrayList<>();\n\n        URL url1 = URL.valueOf(\"test://127.0.0.1:7777/DemoInterface?application=foo&dubbo.tag=tag2&match_key=value\")\n                .setScopeModel(moduleModel);\n        URL url2 = URL.valueOf(\"test://127.0.0.1:7778/DemoInterface?application=foo&match_key=value\")\n                .setScopeModel(moduleModel);\n        URL url3 = URL.valueOf(\"test://127.0.0.1:7779/DemoInterface?application=foo\")\n                .setScopeModel(moduleModel);\n        Invoker<String> invoker1 = new MockInvoker<>(url1, true);\n        Invoker<String> invoker2 = new MockInvoker<>(url2, true);\n        Invoker<String> invoker3 = new MockInvoker<>(url3, true);\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setAttachment(TAG_KEY, \"tag2\");\n        TagRouterRule rule = getTagRule();\n        Mockito.when(router.getInvokers()).thenReturn(invokers);\n        rule.init(router);\n        router.setTagRouterRule(rule);\n        List<Invoker<String>> filteredInvokers =\n                router.route(invokers, invokers.get(0).getUrl(), invocation, false, new Holder<>());\n        Assertions.assertEquals(2, filteredInvokers.size());\n        //        Assertions.(invoker1, filteredInvokers.get(0));\n    }\n\n    /**\n     * TagRouterRule parse test when the tags addresses is null\n     *\n     * <pre>\n     *     ~ -> null\n     *     null -> null\n     * </pre>\n     */\n    @Test\n    void tagRouterRuleParseTest() {\n        String tagRouterRuleConfig = \"---\\n\" + \"force: false\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: false\\n\"\n                + \"priority: 1\\n\"\n                + \"key: demo-provider\\n\"\n                + \"tags:\\n\"\n                + \"  - name: tag1\\n\"\n                + \"    addresses: null\\n\"\n                + \"  - name: tag2\\n\"\n                + \"    addresses: [\\\"30.5.120.37:20880\\\"]\\n\"\n                + \"  - name: tag3\\n\"\n                + \"    addresses: []\\n\"\n                + \"  - name: tag4\\n\"\n                + \"    addresses: ~\\n\"\n                + \"...\";\n\n        TagRouterRule tagRouterRule = TagRuleParser.parse(tagRouterRuleConfig);\n        TagStateRouter<?> router = Mockito.mock(TagStateRouter.class);\n        Mockito.when(router.getInvokers()).thenReturn(BitList.emptyList());\n        tagRouterRule.init(router);\n\n        // assert tags\n        assert tagRouterRule.getKey().equals(\"demo-provider\");\n        assert tagRouterRule.getPriority() == 1;\n        assert tagRouterRule.getTagNames().contains(\"tag1\");\n        assert tagRouterRule.getTagNames().contains(\"tag2\");\n        assert tagRouterRule.getTagNames().contains(\"tag3\");\n        assert tagRouterRule.getTagNames().contains(\"tag4\");\n        // assert addresses\n        assert tagRouterRule.getAddresses().contains(\"30.5.120.37:20880\");\n        assert tagRouterRule.getTagnameToAddresses().get(\"tag1\") == null;\n        assert tagRouterRule.getTagnameToAddresses().get(\"tag2\").size() == 1;\n        assert tagRouterRule.getTagnameToAddresses().get(\"tag3\") == null;\n        assert tagRouterRule.getTagnameToAddresses().get(\"tag4\") == null;\n        assert tagRouterRule.getAddresses().size() == 1;\n    }\n\n    @Test\n    void tagRouterRuleParseTestV3() {\n        String tagRouterRuleConfig = \"---\\n\" + \"configVersion: v3.0\\n\"\n                + \"force: false\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: true\\n\"\n                + \"priority: 1\\n\"\n                + \"key: demo-provider\\n\"\n                + \"tags:\\n\"\n                + \"  - name: tag1\\n\"\n                + \"    match:\\n\"\n                + \"    - key: match_key1\\n\"\n                + \"      value:\\n\"\n                + \"       exact: value1\\n\"\n                + \"  - name: tag2\\n\"\n                + \"    addresses:\\n\"\n                + \"     - \\\"10.20.3.3:20880\\\"\\n\"\n                + \"     - \\\"10.20.3.4:20880\\\"\\n\"\n                + \"    match:\\n\"\n                + \"    - key: match_key2\\n\"\n                + \"      value:\\n\"\n                + \"       exact: value2\\n\"\n                + \"  - name: tag3\\n\"\n                + \"    match:\\n\"\n                + \"    - key: match_key2\\n\"\n                + \"      value:\\n\"\n                + \"       exact: value2\\n\"\n                + \"  - name: tag4\\n\"\n                + \"    match:\\n\"\n                + \"    - key: not_exist\\n\"\n                + \"      value:\\n\"\n                + \"       exact: not_exist\\n\"\n                + \"  - name: tag5\\n\"\n                + \"    match:\\n\"\n                + \"    - key: match_key2\\n\"\n                + \"      value:\\n\"\n                + \"       wildcard: \\\"*\\\"\\n\"\n                + \"...\";\n\n        TagRouterRule tagRouterRule = TagRuleParser.parse(tagRouterRuleConfig);\n        TagStateRouter<String> router = Mockito.mock(TagStateRouter.class);\n        Mockito.when(router.getInvokers()).thenReturn(getInvokers());\n        tagRouterRule.init(router);\n\n        // assert tags\n        assert tagRouterRule.getKey().equals(\"demo-provider\");\n        assert tagRouterRule.getPriority() == 1;\n        assert tagRouterRule.getTagNames().contains(\"tag1\");\n        assert tagRouterRule.getTagNames().contains(\"tag2\");\n        assert tagRouterRule.getTagNames().contains(\"tag3\");\n        assert tagRouterRule.getTagNames().contains(\"tag4\");\n        // assert addresses\n        assert tagRouterRule.getAddresses().size() == 2;\n        assert tagRouterRule.getAddresses().contains(\"10.20.3.3:20880\");\n        assert tagRouterRule.getTagnameToAddresses().get(\"tag1\").size() == 2;\n        assert tagRouterRule.getTagnameToAddresses().get(\"tag2\").size() == 2;\n        assert tagRouterRule.getTagnameToAddresses().get(\"tag3\").size() == 1;\n        assert tagRouterRule.getTagnameToAddresses().get(\"tag5\").size() == 1;\n        assert tagRouterRule.getTagnameToAddresses().get(\"tag4\") == null;\n    }\n\n    public BitList<Invoker<String>> getInvokers() {\n        List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();\n        Invoker<String> invoker1 = new MockInvoker<String>(\n                URL.valueOf(\"dubbo://10.20.3.3:20880/com.foo.BarService?match_key1=value1&match_key2=value2\"));\n        Invoker<String> invoker2 =\n                new MockInvoker<String>(URL.valueOf(\"dubbo://10.20.3.4:20880/com.foo.BarService?match_key1=value1\"));\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n        return invokers;\n    }\n\n    private TagRouterRule getTagRule() {\n        String tagRouterRuleConfig = \"---\\n\" + \"configVersion: v3.0\\n\"\n                + \"force: false\\n\"\n                + \"runtime: true\\n\"\n                + \"enabled: true\\n\"\n                + \"priority: 1\\n\"\n                + \"key: demo-provider\\n\"\n                + \"tags:\\n\"\n                + \"  - name: tag2\\n\"\n                + \"    match:\\n\"\n                + \"    - key: match_key\\n\"\n                + \"      value:\\n\"\n                + \"       exact: value\\n\"\n                + \"...\";\n\n        TagRouterRule tagRouterRule = TagRuleParser.parse(tagRouterRuleConfig);\n        return tagRouterRule;\n    }\n\n    @Test\n    public void tagMultiLevelTest() {\n        String tagSelector = \"beta|team1|partner1\";\n        Set<String> address1 = Sets.newHashSet(\"192.168.5.1:20880\");\n        Map<String, Set<String>> tagAddresses = new HashMap<>();\n        tagAddresses.put(\"beta\", address1);\n        Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));\n\n        Set<String> address2 = Sets.newHashSet(\"192.168.5.2:20880\");\n        tagAddresses.put(\"beta|team1\", address2);\n        Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));\n\n        Set<String> address3 = Sets.newHashSet(\"192.168.5.3:20880\");\n        tagAddresses.put(\"beta|team1|partner1\", address3);\n        Assertions.assertEquals(address3, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));\n\n        tagSelector = \"beta\";\n        Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));\n        tagSelector = \"beta|team1\";\n        Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));\n        tagSelector = \"beta|team1|partner1\";\n        Assertions.assertEquals(address3, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));\n\n        tagSelector = \"beta2\";\n        Assertions.assertNull(TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));\n        tagSelector = \"beta|team2\";\n        Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));\n        tagSelector = \"beta|team1|partner2\";\n        Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));\n    }\n\n    @Test\n    public void tagLevelForceTest() {\n        Set<String> addresses = Sets.newHashSet(\"192.168.1.223:20880\");\n        Map<String, Set<String>> tagAddresses = new HashMap<>();\n        tagAddresses.put(\"beta\", addresses);\n        Set<String> selectedAddresses = TagStateRouter.selectAddressByTagLevel(tagAddresses, \"beta\", true);\n        Assertions.assertEquals(addresses, selectedAddresses);\n    }\n\n    @Test\n    void testTagRouteWithWildcardShouldReturnAllProviders() {\n        StateRouter<TagRouterRule> router = new TagStateRouterFactory().getRouter(TagRouterRule.class, url);\n\n        List<Invoker<TagRouterRule>> originInvokers = new ArrayList<>();\n\n        URL url1 = URL.valueOf(\"test://127.0.0.1:7777/DemoInterface?dubbo.tag=t-01\")\n                .setScopeModel(moduleModel);\n        URL url2 = URL.valueOf(\"test://127.0.0.1:7778/DemoInterface?dubbo.tag=t-02\")\n                .setScopeModel(moduleModel);\n        URL url3 = URL.valueOf(\"test://127.0.0.1:7779/DemoInterface?dubbo.tag=t-03\")\n                .setScopeModel(moduleModel);\n        URL url4 = URL.valueOf(\"test://127.0.0.1:7780/DemoInterface?dubbo.tag=t-04\")\n                .setScopeModel(moduleModel);\n\n        Invoker<TagRouterRule> invoker1 = new MockInvoker<>(url1, true);\n        Invoker<TagRouterRule> invoker2 = new MockInvoker<>(url2, true);\n        Invoker<TagRouterRule> invoker3 = new MockInvoker<>(url3, true);\n        Invoker<TagRouterRule> invoker4 = new MockInvoker<>(url4, true);\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        originInvokers.add(invoker4);\n        BitList<Invoker<TagRouterRule>> invokers = new BitList<>(originInvokers);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setAttachment(TAG_KEY, ANY_VALUE);\n\n        List<Invoker<TagRouterRule>> filteredInvokers =\n                router.route(invokers.clone(), invokers.get(0).getUrl(), invocation, false, new Holder<>());\n\n        Assertions.assertEquals(4, filteredInvokers.size());\n        Assertions.assertEquals(invoker1, filteredInvokers.get(0));\n        Assertions.assertEquals(invoker2, filteredInvokers.get(1));\n        Assertions.assertEquals(invoker3, filteredInvokers.get(2));\n        Assertions.assertEquals(invoker4, filteredInvokers.get(3));\n    }\n\n    @Test\n    void testTagRouteWithDynamicRuleWildcardShouldReturnAllProviders() {\n        TagStateRouter router = (TagStateRouter) new TagStateRouterFactory().getRouter(TagRouterRule.class, url);\n        router = Mockito.spy(router);\n\n        List<Invoker<String>> originInvokers = new ArrayList<>();\n\n        URL url1 = URL.valueOf(\"test://127.0.0.1:7777/DemoInterface?application=foo&dubbo.tag=tag2&match_key=value\")\n                .setScopeModel(moduleModel);\n        URL url2 = URL.valueOf(\"test://127.0.0.1:7778/DemoInterface?application=foo&match_key=value\")\n                .setScopeModel(moduleModel);\n        URL url3 = URL.valueOf(\"test://127.0.0.1:7779/DemoInterface?application=foo\")\n                .setScopeModel(moduleModel);\n        Invoker<String> invoker1 = new MockInvoker<>(url1, true);\n        Invoker<String> invoker2 = new MockInvoker<>(url2, true);\n        Invoker<String> invoker3 = new MockInvoker<>(url3, true);\n        originInvokers.add(invoker1);\n        originInvokers.add(invoker2);\n        originInvokers.add(invoker3);\n        BitList<Invoker<String>> invokers = new BitList<>(originInvokers);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setAttachment(TAG_KEY, ANY_VALUE);\n        TagRouterRule rule = getTagRule();\n        Mockito.when(router.getInvokers()).thenReturn(invokers);\n        rule.init(router);\n        router.setTagRouterRule(rule);\n        List<Invoker<String>> filteredInvokers = router.route(invokers.clone(), url, invocation, false, new Holder<>());\n\n        Assertions.assertEquals(3, filteredInvokers.size());\n        Assertions.assertEquals(invoker1, filteredInvokers.get(0));\n        Assertions.assertEquals(invoker2, filteredInvokers.get(1));\n        Assertions.assertEquals(invoker3, filteredInvokers.get(2));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.cluster.filter.DemoService;\nimport org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance;\nimport org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;\nimport org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLE_CONNECTIVITY_VALIDATION;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_AVAILABLE_CHECK_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.ArgumentMatchers.same;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\n@SuppressWarnings(\"rawtypes\")\nclass AbstractClusterInvokerTest {\n    List<Invoker<IHelloService>> invokers = new ArrayList<Invoker<IHelloService>>();\n    List<Invoker<IHelloService>> selectedInvokers = new ArrayList<Invoker<IHelloService>>();\n    AbstractClusterInvoker<IHelloService> cluster;\n    AbstractClusterInvoker<IHelloService> cluster_nocheck;\n    StaticDirectory<IHelloService> dic;\n    RpcInvocation invocation = new RpcInvocation();\n    URL url = URL.valueOf(\n            \"registry://localhost:9090/org.apache.dubbo.rpc.cluster.support.AbstractClusterInvokerTest.IHelloService?refer=\"\n                    + URL.encode(\"application=abstractClusterInvokerTest\"));\n    URL consumerUrl = URL.valueOf(\n            \"dubbo://localhost?application=abstractClusterInvokerTest&refer=application%3DabstractClusterInvokerTest\");\n\n    Invoker<IHelloService> invoker1;\n    Invoker<IHelloService> invoker2;\n    Invoker<IHelloService> invoker3;\n    Invoker<IHelloService> invoker4;\n    Invoker<IHelloService> invoker5;\n    Invoker<IHelloService> mockedInvoker1;\n\n    @BeforeAll\n    public static void setUpBeforeClass() throws Exception {\n        System.setProperty(ENABLE_CONNECTIVITY_VALIDATION, \"false\");\n    }\n\n    @AfterEach\n    public void teardown() throws Exception {\n        RpcContext.removeContext();\n    }\n\n    @AfterAll\n    public static void afterClass() {\n        System.clearProperty(ENABLE_CONNECTIVITY_VALIDATION);\n    }\n\n    @SuppressWarnings({\"unchecked\"})\n    @BeforeEach\n    public void setUp() throws Exception {\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);\n        Map<String, Object> attributes = new HashMap<>();\n        attributes.put(\"application\", \"abstractClusterInvokerTest\");\n        url = url.putAttribute(REFER_KEY, attributes);\n\n        invocation.setMethodName(\"sayHello\");\n\n        invoker1 = mock(Invoker.class);\n        invoker2 = mock(Invoker.class);\n        invoker3 = mock(Invoker.class);\n        invoker4 = mock(Invoker.class);\n        invoker5 = mock(Invoker.class);\n        mockedInvoker1 = mock(Invoker.class);\n\n        URL turl = URL.valueOf(\"test://test:11/test\");\n\n        given(invoker1.isAvailable()).willReturn(false);\n        given(invoker1.getInterface()).willReturn(IHelloService.class);\n        given(invoker1.getUrl()).willReturn(turl.setPort(1).addParameter(\"name\", \"invoker1\"));\n\n        given(invoker2.isAvailable()).willReturn(true);\n        given(invoker2.getInterface()).willReturn(IHelloService.class);\n        given(invoker2.getUrl()).willReturn(turl.setPort(2).addParameter(\"name\", \"invoker2\"));\n\n        given(invoker3.isAvailable()).willReturn(false);\n        given(invoker3.getInterface()).willReturn(IHelloService.class);\n        given(invoker3.getUrl()).willReturn(turl.setPort(3).addParameter(\"name\", \"invoker3\"));\n\n        given(invoker4.isAvailable()).willReturn(true);\n        given(invoker4.getInterface()).willReturn(IHelloService.class);\n        given(invoker4.getUrl()).willReturn(turl.setPort(4).addParameter(\"name\", \"invoker4\"));\n\n        given(invoker5.isAvailable()).willReturn(false);\n        given(invoker5.getInterface()).willReturn(IHelloService.class);\n        given(invoker5.getUrl()).willReturn(turl.setPort(5).addParameter(\"name\", \"invoker5\"));\n\n        given(mockedInvoker1.isAvailable()).willReturn(false);\n        given(mockedInvoker1.getInterface()).willReturn(IHelloService.class);\n        given(mockedInvoker1.getUrl()).willReturn(turl.setPort(999).setProtocol(\"mock\"));\n\n        invokers.add(invoker1);\n        dic = new StaticDirectory<IHelloService>(url, invokers, null);\n        cluster = new AbstractClusterInvoker(dic) {\n            @Override\n            protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)\n                    throws RpcException {\n                return null;\n            }\n        };\n\n        cluster_nocheck =\n                new AbstractClusterInvoker(\n                        dic, url.addParameterIfAbsent(CLUSTER_AVAILABLE_CHECK_KEY, Boolean.FALSE.toString())) {\n                    @Override\n                    protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)\n                            throws RpcException {\n                        return null;\n                    }\n                };\n    }\n\n    @Disabled(\n            \"RpcContext attachments will be set to Invocation twice, first in ConsumerContextFilter, second AbstractInvoker\")\n    @Test\n    void testBindingAttachment() {\n        final String attachKey = \"attach\";\n        final String attachValue = \"value\";\n\n        // setup attachment\n        RpcContext.getClientAttachment().setAttachment(attachKey, attachValue);\n        Map<String, Object> attachments = RpcContext.getClientAttachment().getObjectAttachments();\n        Assertions.assertTrue(attachments != null && attachments.size() == 1, \"set attachment failed!\");\n\n        cluster = new AbstractClusterInvoker(dic) {\n            @Override\n            protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)\n                    throws RpcException {\n                // attachment will be bind to invocation\n                String value = invocation.getAttachment(attachKey);\n                Assertions.assertNotNull(value);\n                Assertions.assertEquals(attachValue, value, \"binding attachment failed!\");\n                return null;\n            }\n        };\n\n        // invoke\n        cluster.invoke(invocation);\n    }\n\n    @Test\n    void testSelect_Invokersize0() {\n        LoadBalance l = cluster.initLoadBalance(invokers, invocation);\n        Assertions.assertNotNull(l, \"cluster.initLoadBalance returns null!\");\n        {\n            Invoker invoker = cluster.select(l, null, null, null);\n            Assertions.assertNull(invoker);\n        }\n        {\n            invokers.clear();\n            selectedInvokers.clear();\n            Invoker invoker = cluster.select(l, null, invokers, null);\n            Assertions.assertNull(invoker);\n        }\n    }\n\n    @Test\n    void testSelectedInvokers() {\n        cluster = new AbstractClusterInvoker(dic) {\n            @Override\n            protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)\n                    throws RpcException {\n                checkInvokers(invokers, invocation);\n                Invoker invoker = select(loadbalance, invocation, invokers, null);\n                return invokeWithContext(invoker, invocation);\n            }\n        };\n\n        // invoke\n        cluster.invoke(invocation);\n\n        Assertions.assertEquals(Collections.singletonList(invoker1), invocation.getInvokedInvokers());\n    }\n\n    @Test\n    void testSelect_Invokersize1() {\n        invokers.clear();\n        invokers.add(invoker1);\n        LoadBalance l = cluster.initLoadBalance(invokers, invocation);\n        Assertions.assertNotNull(l, \"cluster.initLoadBalance returns null!\");\n        Invoker invoker = cluster.select(l, null, invokers, null);\n        Assertions.assertEquals(invoker1, invoker);\n    }\n\n    @Test\n    void testSelect_Invokersize2AndselectNotNull() {\n        invokers.clear();\n        invokers.add(invoker2);\n        invokers.add(invoker4);\n        LoadBalance l = cluster.initLoadBalance(invokers, invocation);\n        Assertions.assertNotNull(l, \"cluster.initLoadBalance returns null!\");\n        {\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker4);\n            Invoker invoker = cluster.select(l, invocation, invokers, selectedInvokers);\n            Assertions.assertEquals(invoker2, invoker);\n        }\n        {\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker2);\n            Invoker invoker = cluster.select(l, invocation, invokers, selectedInvokers);\n            Assertions.assertEquals(invoker4, invoker);\n        }\n    }\n\n    @Test\n    void testSelect_multiInvokers() {\n        testSelect_multiInvokers(RoundRobinLoadBalance.NAME);\n        testSelect_multiInvokers(LeastActiveLoadBalance.NAME);\n        testSelect_multiInvokers(RandomLoadBalance.NAME);\n    }\n\n    @Test\n    void testCloseAvailablecheck() {\n        LoadBalance lb = mock(LoadBalance.class);\n        Map<String, String> queryMap = (Map<String, String>) url.getAttribute(REFER_KEY);\n        URL tmpUrl = turnRegistryUrlToConsumerUrl(url, queryMap);\n\n        when(lb.select(same(invokers), eq(tmpUrl), same(invocation))).thenReturn(invoker1);\n        initlistsize5();\n\n        Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers);\n        Assertions.assertFalse(sinvoker.isAvailable());\n        Assertions.assertEquals(invoker1, sinvoker);\n    }\n\n    private URL turnRegistryUrlToConsumerUrl(URL url, Map<String, String> queryMap) {\n        String host =\n                StringUtils.isNotEmpty(queryMap.get(\"register.ip\")) ? queryMap.get(\"register.ip\") : this.url.getHost();\n        String path = queryMap.get(PATH_KEY);\n        String consumedProtocol = queryMap.get(PROTOCOL_KEY) == null ? CONSUMER : queryMap.get(PROTOCOL_KEY);\n\n        URL consumerUrlFrom = this.url\n                .setHost(host)\n                .setPort(0)\n                .setProtocol(consumedProtocol)\n                .setPath(path == null ? queryMap.get(INTERFACE_KEY) : path);\n        return consumerUrlFrom.addParameters(queryMap).removeParameter(MONITOR_KEY);\n    }\n\n    @Test\n    void testDonotSelectAgainAndNoCheckAvailable() {\n\n        LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(RoundRobinLoadBalance.NAME);\n        initlistsize5();\n        {\n            // Boundary condition test .\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker2);\n            selectedInvokers.add(invoker3);\n            selectedInvokers.add(invoker4);\n            selectedInvokers.add(invoker5);\n            Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertSame(invoker1, sinvoker);\n        }\n        {\n            // Boundary condition test .\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker1);\n            selectedInvokers.add(invoker3);\n            selectedInvokers.add(invoker4);\n            selectedInvokers.add(invoker5);\n            Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertSame(invoker2, sinvoker);\n        }\n        {\n            // Boundary condition test .\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker1);\n            selectedInvokers.add(invoker2);\n            selectedInvokers.add(invoker4);\n            selectedInvokers.add(invoker5);\n            Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertSame(invoker3, sinvoker);\n        }\n        {\n            // Boundary condition test .\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker1);\n            selectedInvokers.add(invoker2);\n            selectedInvokers.add(invoker3);\n            selectedInvokers.add(invoker4);\n            Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertSame(invoker5, sinvoker);\n        }\n        {\n            // Boundary condition test .\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker1);\n            selectedInvokers.add(invoker2);\n            selectedInvokers.add(invoker3);\n            selectedInvokers.add(invoker4);\n            selectedInvokers.add(invoker5);\n            Invoker sinvoker = cluster_nocheck.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertTrue(invokers.contains(sinvoker));\n        }\n    }\n\n    @Test\n    void testSelectAgainAndCheckAvailable() {\n\n        LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(RoundRobinLoadBalance.NAME);\n        initlistsize5();\n        {\n            // Boundary condition test .\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker1);\n            selectedInvokers.add(invoker2);\n            selectedInvokers.add(invoker3);\n            selectedInvokers.add(invoker5);\n            Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertSame(sinvoker, invoker4);\n        }\n        {\n            // Boundary condition test .\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker2);\n            selectedInvokers.add(invoker3);\n            selectedInvokers.add(invoker4);\n            selectedInvokers.add(invoker5);\n            Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertTrue(sinvoker == invoker2 || sinvoker == invoker4);\n        }\n        {\n            // Boundary condition test .\n            for (int i = 0; i < 100; i++) {\n                selectedInvokers.clear();\n                Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n                Assertions.assertTrue(sinvoker == invoker2 || sinvoker == invoker4);\n            }\n        }\n        {\n            // Boundary condition test .\n            for (int i = 0; i < 100; i++) {\n                selectedInvokers.clear();\n                selectedInvokers.add(invoker1);\n                selectedInvokers.add(invoker3);\n                selectedInvokers.add(invoker5);\n                Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n                Assertions.assertTrue(sinvoker == invoker2 || sinvoker == invoker4);\n            }\n        }\n        {\n            // Boundary condition test .\n            for (int i = 0; i < 100; i++) {\n                selectedInvokers.clear();\n                selectedInvokers.add(invoker1);\n                selectedInvokers.add(invoker3);\n                selectedInvokers.add(invoker2);\n                selectedInvokers.add(invoker4);\n                selectedInvokers.add(invoker5);\n                Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n                Assertions.assertTrue(sinvoker == invoker2 || sinvoker == invoker4);\n            }\n        }\n    }\n\n    public void testSelect_multiInvokers(String lbname) {\n\n        int min = 100, max = 500;\n        Double d = (Math.random() * (max - min + 1) + min);\n        int runs = d.intValue();\n        Assertions.assertTrue(runs >= min);\n        LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(lbname);\n        initlistsize5();\n        for (int i = 0; i < runs; i++) {\n            Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertTrue(sinvoker.isAvailable());\n\n            Mockito.clearInvocations(invoker1, invoker2, invoker3, invoker4, invoker5);\n        }\n        for (int i = 0; i < runs; i++) {\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker1);\n            Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertTrue(sinvoker.isAvailable());\n\n            Mockito.clearInvocations(invoker1, invoker2, invoker3, invoker4, invoker5);\n        }\n        for (int i = 0; i < runs; i++) {\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker2);\n            Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertTrue(sinvoker.isAvailable());\n\n            Mockito.clearInvocations(invoker1, invoker2, invoker3, invoker4, invoker5);\n        }\n        for (int i = 0; i < runs; i++) {\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker2);\n            selectedInvokers.add(invoker4);\n            Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertTrue(sinvoker.isAvailable());\n\n            Mockito.clearInvocations(invoker1, invoker2, invoker3, invoker4, invoker5);\n        }\n        for (int i = 0; i < runs; i++) {\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker1);\n            selectedInvokers.add(invoker3);\n            selectedInvokers.add(invoker5);\n            Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertTrue(sinvoker.isAvailable());\n\n            Mockito.clearInvocations(invoker1, invoker2, invoker3, invoker4, invoker5);\n        }\n        for (int i = 0; i < runs; i++) {\n\n            selectedInvokers.clear();\n            selectedInvokers.add(invoker1);\n            selectedInvokers.add(invoker2);\n            selectedInvokers.add(invoker3);\n            Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n            Assertions.assertTrue(sinvoker.isAvailable());\n\n            Mockito.clearInvocations(invoker1, invoker2, invoker3, invoker4, invoker5);\n        }\n    }\n\n    /**\n     * Test balance.\n     */\n    @Test\n    void testSelectBalance() {\n\n        LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(RoundRobinLoadBalance.NAME);\n        initlistsize5();\n\n        Map<Invoker, AtomicLong> counter = new ConcurrentHashMap<Invoker, AtomicLong>();\n        for (Invoker invoker : invokers) {\n            counter.put(invoker, new AtomicLong(0));\n        }\n        int runs = 1000;\n        for (int i = 0; i < runs; i++) {\n            selectedInvokers.clear();\n            Invoker sinvoker = cluster.select(lb, invocation, invokers, selectedInvokers);\n            counter.get(sinvoker).incrementAndGet();\n        }\n\n        for (Map.Entry<Invoker, AtomicLong> entry : counter.entrySet()) {\n            Long count = entry.getValue().get();\n            if (entry.getKey().isAvailable())\n                Assertions.assertTrue(count > runs / invokers.size(), \"count should > avg\");\n        }\n\n        Assertions.assertEquals(\n                runs, counter.get(invoker2).get() + counter.get(invoker4).get());\n    }\n\n    private void initlistsize5() {\n        invokers.clear();\n        selectedInvokers\n                .clear(); // Clear first, previous test case will make sure that the right invoker2 will be used.\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n        invokers.add(invoker3);\n        invokers.add(invoker4);\n        invokers.add(invoker5);\n    }\n\n    private void initDic() {\n        dic.notify(invokers);\n        dic.buildRouterChain();\n    }\n\n    @Test\n    void testTimeoutExceptionCode() {\n        List<Invoker<DemoService>> invokers = new ArrayList<Invoker<DemoService>>();\n        invokers.add(new Invoker<DemoService>() {\n\n            @Override\n            public Class<DemoService> getInterface() {\n                return DemoService.class;\n            }\n\n            public URL getUrl() {\n                return URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":20880/\" + DemoService.class.getName());\n            }\n\n            @Override\n            public boolean isAvailable() {\n                return false;\n            }\n\n            @Override\n            public Result invoke(Invocation invocation) throws RpcException {\n                throw new RpcException(RpcException.TIMEOUT_EXCEPTION, \"test timeout\");\n            }\n\n            @Override\n            public void destroy() {}\n        });\n        Directory<DemoService> directory = new StaticDirectory<DemoService>(invokers);\n        FailoverClusterInvoker<DemoService> failoverClusterInvoker = new FailoverClusterInvoker<DemoService>(directory);\n        RpcInvocation invocation =\n                new RpcInvocation(\"sayHello\", DemoService.class.getName(), \"\", new Class<?>[0], new Object[0]);\n        try {\n            failoverClusterInvoker.invoke(invocation);\n            Assertions.fail();\n        } catch (RpcException e) {\n            Assertions.assertEquals(RpcException.TIMEOUT_EXCEPTION, e.getCode());\n        }\n        ForkingClusterInvoker<DemoService> forkingClusterInvoker = new ForkingClusterInvoker<DemoService>(directory);\n        invocation = new RpcInvocation(\"sayHello\", DemoService.class.getName(), \"\", new Class<?>[0], new Object[0]);\n        try {\n            forkingClusterInvoker.invoke(invocation);\n            Assertions.fail();\n        } catch (RpcException e) {\n            Assertions.assertEquals(RpcException.TIMEOUT_EXCEPTION, e.getCode());\n        }\n        FailfastClusterInvoker<DemoService> failfastClusterInvoker = new FailfastClusterInvoker<DemoService>(directory);\n        invocation = new RpcInvocation(\"sayHello\", DemoService.class.getName(), \"\", new Class<?>[0], new Object[0]);\n        try {\n            failfastClusterInvoker.invoke(invocation);\n            Assertions.fail();\n        } catch (RpcException e) {\n            Assertions.assertEquals(RpcException.TIMEOUT_EXCEPTION, e.getCode());\n        }\n    }\n\n    public static interface IHelloService {}\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AvailableClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test for AvailableClusterInvoker\n */\nclass AvailableClusterInvokerTest {\n\n    private final URL url = URL.valueOf(\"test://test:80/test\");\n    private final Invoker<AvailableClusterInvokerTest> invoker1 = mock(Invoker.class);\n    private final Invoker<AvailableClusterInvokerTest> invoker2 = mock(Invoker.class);\n    private final Invoker<AvailableClusterInvokerTest> invoker3 = mock(Invoker.class);\n    private final RpcInvocation invocation = new RpcInvocation();\n    private final Result result = new AppResponse();\n    private final List<Invoker<AvailableClusterInvokerTest>> invokers = new ArrayList<>();\n    private Directory<AvailableClusterInvokerTest> dic;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n\n        dic = mock(Directory.class);\n\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(invokers);\n        given(dic.getInterface()).willReturn(AvailableClusterInvokerTest.class);\n\n        invocation.setMethodName(\"method1\");\n\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n        invokers.add(invoker3);\n    }\n\n    private void resetInvokerToNoException() {\n\n        given(invoker1.invoke(invocation)).willReturn(result);\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.isAvailable()).willReturn(true);\n        given(invoker1.getInterface()).willReturn(AvailableClusterInvokerTest.class);\n\n        given(invoker2.invoke(invocation)).willReturn(result);\n        given(invoker2.getUrl()).willReturn(url);\n        given(invoker2.isAvailable()).willReturn(true);\n        given(invoker2.getInterface()).willReturn(AvailableClusterInvokerTest.class);\n\n        given(invoker3.invoke(invocation)).willReturn(result);\n        given(invoker3.getUrl()).willReturn(url);\n        given(invoker3.isAvailable()).willReturn(true);\n        given(invoker3.getInterface()).willReturn(AvailableClusterInvokerTest.class);\n    }\n\n    @Test\n    void testInvokeNoException() {\n\n        resetInvokerToNoException();\n\n        AvailableClusterInvoker<AvailableClusterInvokerTest> invoker = new AvailableClusterInvoker<>(dic);\n        Result ret = invoker.invoke(invocation);\n        Assertions.assertSame(result, ret);\n    }\n\n    @Test\n    void testInvokeWithException() {\n\n        // remove invokers for test exception\n        dic.list(invocation).removeAll(invokers);\n\n        AvailableClusterInvoker<AvailableClusterInvokerTest> invoker = new AvailableClusterInvoker<>(dic);\n        try {\n            invoker.invoke(invocation);\n            fail();\n        } catch (RpcException e) {\n            Assertions.assertTrue(e.getMessage().contains(\"No provider available\"));\n            assertFalse(e.getCause() instanceof RpcException);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/BroadCastClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.filter.DemoService;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * @see BroadcastClusterInvoker\n */\nclass BroadCastClusterInvokerTest {\n    private URL url;\n    private Directory<DemoService> dic;\n    private RpcInvocation invocation;\n    private BroadcastClusterInvoker clusterInvoker;\n\n    private MockInvoker invoker1;\n    private MockInvoker invoker2;\n    private MockInvoker invoker3;\n    private MockInvoker invoker4;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n\n        dic = mock(Directory.class);\n\n        invoker1 = new MockInvoker();\n        invoker2 = new MockInvoker();\n        invoker3 = new MockInvoker();\n        invoker4 = new MockInvoker();\n\n        url = URL.valueOf(\"test://127.0.0.1:8080/test\");\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.getInterface()).willReturn(DemoService.class);\n\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"test\");\n\n        clusterInvoker = new BroadcastClusterInvoker(dic);\n    }\n\n    @Test\n    void testNormal() {\n        given(dic.list(invocation)).willReturn(Arrays.asList(invoker1, invoker2, invoker3, invoker4));\n        // Every invoker will be called\n        clusterInvoker.invoke(invocation);\n        assertTrue(invoker1.isInvoked());\n        assertTrue(invoker2.isInvoked());\n        assertTrue(invoker3.isInvoked());\n        assertTrue(invoker4.isInvoked());\n    }\n\n    @Test\n    void testEx() {\n        given(dic.list(invocation)).willReturn(Arrays.asList(invoker1, invoker2, invoker3, invoker4));\n        invoker1.invokeThrowEx();\n        assertThrows(RpcException.class, () -> {\n            clusterInvoker.invoke(invocation);\n        });\n        // The default failure percentage is 100, even if a certain invoker#invoke throws an exception, other invokers\n        // will still be called\n        assertTrue(invoker1.isInvoked());\n        assertTrue(invoker2.isInvoked());\n        assertTrue(invoker3.isInvoked());\n        assertTrue(invoker4.isInvoked());\n    }\n\n    @Test\n    void testFailPercent() {\n        given(dic.list(invocation)).willReturn(Arrays.asList(invoker1, invoker2, invoker3, invoker4));\n        // We set the failure percentage to 75, which means that when the number of call failures is 4*(75/100) = 3,\n        // an exception will be thrown directly and subsequent invokers will not be called.\n        url = url.addParameter(\"broadcast.fail.percent\", 75);\n        given(dic.getConsumerUrl()).willReturn(url);\n        invoker1.invokeThrowEx();\n        invoker2.invokeThrowEx();\n        invoker3.invokeThrowEx();\n        invoker4.invokeThrowEx();\n        assertThrows(RpcException.class, () -> {\n            clusterInvoker.invoke(invocation);\n        });\n        assertTrue(invoker1.isInvoked());\n        assertTrue(invoker2.isInvoked());\n        assertTrue(invoker3.isInvoked());\n        assertFalse(invoker4.isInvoked());\n    }\n}\n\nclass MockInvoker implements Invoker<DemoService> {\n    private static int count = 0;\n    private URL url = URL.valueOf(\"test://127.0.0.1:8080/test\");\n    private boolean throwEx = false;\n    private boolean invoked = false;\n\n    @Override\n    public URL getUrl() {\n        return url;\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return false;\n    }\n\n    @Override\n    public void destroy() {}\n\n    @Override\n    public Class<DemoService> getInterface() {\n        return DemoService.class;\n    }\n\n    @Override\n    public Result invoke(Invocation invocation) throws RpcException {\n        invoked = true;\n        if (throwEx) {\n            throwEx = false;\n            throw new RpcException();\n        }\n        return null;\n    }\n\n    public void invokeThrowEx() {\n        throwEx = true;\n    }\n\n    public boolean isInvoked() {\n        return invoked;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.URL_MERGE_PROCESSOR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\n\nclass ClusterUtilsTest {\n\n    private ClusterUtils clusterUtils;\n\n    @BeforeEach\n    public void setup() {\n        clusterUtils = new ClusterUtils();\n        clusterUtils.setApplicationModel(ApplicationModel.defaultModel());\n    }\n\n    @Test\n    void testMergeUrl() {\n        URL providerURL = URL.valueOf(\"dubbo://localhost:55555\");\n        providerURL = providerURL.setPath(\"path\").setUsername(\"username\").setPassword(\"password\");\n\n        providerURL = URLBuilder.from(providerURL)\n                .addParameter(GROUP_KEY, \"dubbo\")\n                .addParameter(VERSION_KEY, \"1.2.3\")\n                .addParameter(DUBBO_VERSION_KEY, \"2.3.7\")\n                .addParameter(THREADPOOL_KEY, \"fixed\")\n                .addParameter(THREADS_KEY, Integer.MAX_VALUE)\n                .addParameter(THREAD_NAME_KEY, \"test\")\n                .addParameter(CORE_THREADS_KEY, Integer.MAX_VALUE)\n                .addParameter(QUEUES_KEY, Integer.MAX_VALUE)\n                .addParameter(ALIVE_KEY, Integer.MAX_VALUE)\n                .addParameter(DEFAULT_KEY_PREFIX + THREADS_KEY, Integer.MAX_VALUE)\n                .addParameter(DEFAULT_KEY_PREFIX + THREADPOOL_KEY, \"fixed\")\n                .addParameter(DEFAULT_KEY_PREFIX + CORE_THREADS_KEY, Integer.MAX_VALUE)\n                .addParameter(DEFAULT_KEY_PREFIX + QUEUES_KEY, Integer.MAX_VALUE)\n                .addParameter(DEFAULT_KEY_PREFIX + ALIVE_KEY, Integer.MAX_VALUE)\n                .addParameter(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY, \"test\")\n                .addParameter(APPLICATION_KEY, \"provider\")\n                .addParameter(REFERENCE_FILTER_KEY, \"filter1,filter2\")\n                .addParameter(TAG_KEY, \"TTT\")\n                .build();\n\n        // Verify default ProviderURLMergeProcessor\n        URL consumerURL = new URLBuilder(DUBBO_PROTOCOL, \"localhost\", 55555)\n                .addParameter(PID_KEY, \"1234\")\n                .addParameter(THREADPOOL_KEY, \"foo\")\n                .addParameter(APPLICATION_KEY, \"consumer\")\n                .addParameter(REFERENCE_FILTER_KEY, \"filter3\")\n                .addParameter(TAG_KEY, \"UUU\")\n                .build();\n\n        URL url = clusterUtils.mergeUrl(providerURL, consumerURL.getParameters());\n\n        Assertions.assertFalse(url.hasParameter(THREADS_KEY));\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + THREADS_KEY));\n\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + THREADPOOL_KEY));\n\n        Assertions.assertFalse(url.hasParameter(CORE_THREADS_KEY));\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + CORE_THREADS_KEY));\n\n        Assertions.assertFalse(url.hasParameter(QUEUES_KEY));\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + QUEUES_KEY));\n\n        Assertions.assertFalse(url.hasParameter(ALIVE_KEY));\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + ALIVE_KEY));\n\n        Assertions.assertFalse(url.hasParameter(THREAD_NAME_KEY));\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY));\n\n        Assertions.assertEquals(\"path\", url.getPath());\n        Assertions.assertEquals(\"username\", url.getUsername());\n        Assertions.assertEquals(\"password\", url.getPassword());\n        Assertions.assertEquals(\"1234\", url.getParameter(PID_KEY));\n        Assertions.assertEquals(\"foo\", url.getParameter(THREADPOOL_KEY));\n        Assertions.assertEquals(\"consumer\", url.getApplication());\n        Assertions.assertEquals(\"provider\", url.getRemoteApplication());\n        Assertions.assertEquals(\"filter1,filter2,filter3\", url.getParameter(REFERENCE_FILTER_KEY));\n\n        Assertions.assertEquals(\"TTT\", url.getParameter(TAG_KEY));\n\n        // Verify custom ProviderURLMergeProcessor\n        URL consumerUrlForTag = new URLBuilder(DUBBO_PROTOCOL, \"localhost\", 55555)\n                .addParameter(PID_KEY, \"1234\")\n                .addParameter(THREADPOOL_KEY, \"foo\")\n                .addParameter(APPLICATION_KEY, \"consumer\")\n                .addParameter(REFERENCE_FILTER_KEY, \"filter3\")\n                .addParameter(TAG_KEY, \"UUU\")\n                .addParameter(URL_MERGE_PROCESSOR_KEY, \"tag\")\n                .build();\n\n        URL urlForTag = clusterUtils.mergeUrl(providerURL, consumerUrlForTag.getParameters());\n        Assertions.assertEquals(\"UUU\", urlForTag.getParameter(TAG_KEY));\n    }\n\n    @Test\n    void testMergeLocalParams() {\n\n        // Verify default ProviderURLMergeProcessor\n        URL consumerURL = new URLBuilder(DUBBO_PROTOCOL, \"localhost\", 55555)\n                .addParameter(PID_KEY, \"1234\")\n                .addParameter(THREADPOOL_KEY, \"foo\")\n                .addParameter(APPLICATION_KEY, \"consumer\")\n                .addParameter(REFERENCE_FILTER_KEY, \"filter3\")\n                .addParameter(TAG_KEY, \"UUU\")\n                .build();\n\n        Map<String, String> params = clusterUtils.mergeLocalParams(consumerURL.getParameters());\n\n        Assertions.assertEquals(\"1234\", params.get(PID_KEY));\n        Assertions.assertEquals(\"foo\", params.get(THREADPOOL_KEY));\n        Assertions.assertEquals(\"consumer\", params.get(APPLICATION_KEY));\n        Assertions.assertEquals(\"filter3\", params.get(REFERENCE_FILTER_KEY));\n        Assertions.assertEquals(\"UUU\", params.get(TAG_KEY));\n\n        // Verify custom ProviderURLMergeProcessor\n        URL consumerUrlForTag = new URLBuilder(DUBBO_PROTOCOL, \"localhost\", 55555)\n                .addParameter(PID_KEY, \"1234\")\n                .addParameter(THREADPOOL_KEY, \"foo\")\n                .addParameter(APPLICATION_KEY, \"consumer\")\n                .addParameter(REFERENCE_FILTER_KEY, \"filter3\")\n                .addParameter(TAG_KEY, \"UUU\")\n                .addParameter(URL_MERGE_PROCESSOR_KEY, \"tag\")\n                .build();\n\n        Map<String, String> paramsForTag = clusterUtils.mergeLocalParams(consumerUrlForTag.getParameters());\n\n        Assertions.assertEquals(\"1234\", paramsForTag.get(PID_KEY));\n        Assertions.assertEquals(\"foo\", paramsForTag.get(THREADPOOL_KEY));\n        Assertions.assertEquals(\"consumer\", paramsForTag.get(APPLICATION_KEY));\n        Assertions.assertEquals(\"filter3\", paramsForTag.get(REFERENCE_FILTER_KEY));\n        Assertions.assertNull(paramsForTag.get(TAG_KEY));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ConnectivityValidationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ThreadLocalRandom;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.mockito.Mockito.when;\n\n@SuppressWarnings(\"all\")\nclass ConnectivityValidationTest {\n    private Invoker invoker1;\n    private Invoker invoker2;\n    private Invoker invoker3;\n    private Invoker invoker4;\n    private Invoker invoker5;\n    private Invoker invoker6;\n    private Invoker invoker7;\n    private Invoker invoker8;\n    private Invoker invoker9;\n    private Invoker invoker10;\n    private Invoker invoker11;\n    private Invoker invoker12;\n    private Invoker invoker13;\n    private Invoker invoker14;\n    private Invoker invoker15;\n\n    private List<Invoker> invokerList;\n\n    private StaticDirectory directory;\n    private ConnectivityClusterInvoker clusterInvoker;\n\n    @BeforeEach\n    public void setup() {\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);\n        invoker1 = Mockito.mock(Invoker.class);\n        invoker2 = Mockito.mock(Invoker.class);\n        invoker3 = Mockito.mock(Invoker.class);\n        invoker4 = Mockito.mock(Invoker.class);\n        invoker5 = Mockito.mock(Invoker.class);\n        invoker6 = Mockito.mock(Invoker.class);\n        invoker7 = Mockito.mock(Invoker.class);\n        invoker8 = Mockito.mock(Invoker.class);\n        invoker9 = Mockito.mock(Invoker.class);\n        invoker10 = Mockito.mock(Invoker.class);\n        invoker11 = Mockito.mock(Invoker.class);\n        invoker12 = Mockito.mock(Invoker.class);\n        invoker13 = Mockito.mock(Invoker.class);\n        invoker14 = Mockito.mock(Invoker.class);\n        invoker15 = Mockito.mock(Invoker.class);\n\n        configInvoker(invoker1);\n        configInvoker(invoker2);\n        configInvoker(invoker3);\n        configInvoker(invoker4);\n        configInvoker(invoker5);\n        configInvoker(invoker6);\n        configInvoker(invoker7);\n        configInvoker(invoker8);\n        configInvoker(invoker9);\n        configInvoker(invoker10);\n        configInvoker(invoker11);\n        configInvoker(invoker12);\n        configInvoker(invoker13);\n        configInvoker(invoker14);\n        configInvoker(invoker15);\n\n        invokerList = new LinkedList<>();\n        invokerList.add(invoker1);\n        invokerList.add(invoker2);\n        invokerList.add(invoker3);\n        invokerList.add(invoker4);\n        invokerList.add(invoker5);\n\n        directory = new StaticDirectory(invokerList);\n        clusterInvoker = new ConnectivityClusterInvoker(directory);\n    }\n\n    @AfterEach\n    public void tearDown() {\n        clusterInvoker.destroy();\n    }\n\n    private void configInvoker(Invoker invoker) {\n        when(invoker.getUrl()).thenReturn(URL.valueOf(\"\"));\n        when(invoker.isAvailable()).thenReturn(true);\n    }\n\n    @BeforeAll\n    public static void setupClass() {\n        System.setProperty(CommonConstants.RECONNECT_TASK_PERIOD, \"1\");\n    }\n\n    @AfterAll\n    public static void clearAfterClass() {\n        System.clearProperty(CommonConstants.RECONNECT_TASK_PERIOD);\n    }\n\n    @Test\n    void testBasic() throws InterruptedException {\n        Invocation invocation = new RpcInvocation();\n        LoadBalance loadBalance = new RandomLoadBalance();\n\n        Assertions.assertEquals(5, directory.list(invocation).size());\n\n        Assertions.assertNotNull(\n                clusterInvoker.select(loadBalance, invocation, directory.list(invocation), Collections.emptyList()));\n\n        when(invoker1.isAvailable()).thenReturn(false);\n        when(invoker2.isAvailable()).thenReturn(false);\n        when(invoker3.isAvailable()).thenReturn(false);\n        when(invoker4.isAvailable()).thenReturn(false);\n        when(invoker5.isAvailable()).thenReturn(false);\n\n        clusterInvoker.select(loadBalance, invocation, directory.list(invocation), Collections.emptyList());\n        Assertions.assertEquals(0, directory.list(invocation).size());\n\n        when(invoker1.isAvailable()).thenReturn(true);\n        Set<Invoker> invokerSet = new HashSet<>();\n        invokerSet.add(invoker1);\n        waitRefresh(invokerSet);\n        Assertions.assertEquals(1, directory.list(invocation).size());\n        Assertions.assertNotNull(\n                clusterInvoker.select(loadBalance, invocation, directory.list(invocation), Collections.emptyList()));\n\n        when(invoker2.isAvailable()).thenReturn(true);\n        invokerSet.add(invoker2);\n        waitRefresh(invokerSet);\n        Assertions.assertEquals(2, directory.list(invocation).size());\n        Assertions.assertNotNull(\n                clusterInvoker.select(loadBalance, invocation, directory.list(invocation), Collections.emptyList()));\n\n        invokerList.remove(invoker5);\n        directory.notify(invokerList);\n        when(invoker2.isAvailable()).thenReturn(true);\n        waitRefresh(invokerSet);\n        Assertions.assertEquals(2, directory.list(invocation).size());\n        Assertions.assertNotNull(\n                clusterInvoker.select(loadBalance, invocation, directory.list(invocation), Collections.emptyList()));\n\n        when(invoker3.isAvailable()).thenReturn(true);\n        when(invoker4.isAvailable()).thenReturn(true);\n        invokerSet.add(invoker3);\n        invokerSet.add(invoker4);\n        waitRefresh(invokerSet);\n        Assertions.assertEquals(4, directory.list(invocation).size());\n        Assertions.assertNotNull(\n                clusterInvoker.select(loadBalance, invocation, directory.list(invocation), Collections.emptyList()));\n    }\n\n    @Test\n    void testRetry() throws InterruptedException {\n        Invocation invocation = new RpcInvocation();\n        LoadBalance loadBalance = new RandomLoadBalance();\n\n        invokerList.clear();\n        invokerList.add(invoker1);\n        invokerList.add(invoker2);\n        directory.notify(invokerList);\n\n        Assertions.assertEquals(2, directory.list(invocation).size());\n\n        when(invoker1.isAvailable()).thenReturn(false);\n        Assertions.assertEquals(\n                invoker2,\n                clusterInvoker.select(\n                        loadBalance, invocation, directory.list(invocation), Collections.singletonList(invoker2)));\n        Assertions.assertEquals(1, directory.list(invocation).size());\n\n        when(invoker1.isAvailable()).thenReturn(true);\n        Set<Invoker> invokerSet = new HashSet<>();\n        invokerSet.add(invoker1);\n        waitRefresh(invokerSet);\n        Assertions.assertEquals(2, directory.list(invocation).size());\n    }\n\n    @Test\n    void testRandomSelect() throws InterruptedException {\n        Invocation invocation = new RpcInvocation();\n        LoadBalance loadBalance = new RandomLoadBalance();\n\n        invokerList.add(invoker6);\n        invokerList.add(invoker7);\n        invokerList.add(invoker8);\n        invokerList.add(invoker9);\n        invokerList.add(invoker10);\n        invokerList.add(invoker11);\n        invokerList.add(invoker12);\n        invokerList.add(invoker13);\n        invokerList.add(invoker14);\n        invokerList.add(invoker15);\n\n        directory.notify(invokerList);\n\n        Assertions.assertEquals(15, directory.list(invocation).size());\n\n        when(invoker2.isAvailable()).thenReturn(false);\n        when(invoker3.isAvailable()).thenReturn(false);\n        when(invoker4.isAvailable()).thenReturn(false);\n        when(invoker5.isAvailable()).thenReturn(false);\n        when(invoker6.isAvailable()).thenReturn(false);\n        when(invoker7.isAvailable()).thenReturn(false);\n        when(invoker8.isAvailable()).thenReturn(false);\n        when(invoker9.isAvailable()).thenReturn(false);\n        when(invoker10.isAvailable()).thenReturn(false);\n        when(invoker11.isAvailable()).thenReturn(false);\n        when(invoker12.isAvailable()).thenReturn(false);\n        when(invoker13.isAvailable()).thenReturn(false);\n        when(invoker14.isAvailable()).thenReturn(false);\n        when(invoker15.isAvailable()).thenReturn(false);\n        for (int i = 0; i < 15; i++) {\n            clusterInvoker.select(loadBalance, invocation, directory.list(invocation), Collections.emptyList());\n        }\n        for (int i = 0; i < 5; i++) {\n            Assertions.assertEquals(\n                    invoker1,\n                    clusterInvoker.select(\n                            loadBalance, invocation, directory.list(invocation), Collections.emptyList()));\n        }\n\n        when(invoker1.isAvailable()).thenReturn(false);\n        clusterInvoker.select(loadBalance, invocation, directory.list(invocation), Collections.emptyList());\n        Assertions.assertEquals(0, directory.list(invocation).size());\n\n        when(invoker1.isAvailable()).thenReturn(true);\n        when(invoker2.isAvailable()).thenReturn(true);\n        when(invoker3.isAvailable()).thenReturn(true);\n        when(invoker4.isAvailable()).thenReturn(true);\n        when(invoker5.isAvailable()).thenReturn(true);\n        when(invoker6.isAvailable()).thenReturn(true);\n        when(invoker7.isAvailable()).thenReturn(true);\n        when(invoker8.isAvailable()).thenReturn(true);\n        when(invoker9.isAvailable()).thenReturn(true);\n        when(invoker10.isAvailable()).thenReturn(true);\n        when(invoker11.isAvailable()).thenReturn(true);\n        when(invoker12.isAvailable()).thenReturn(true);\n        when(invoker13.isAvailable()).thenReturn(true);\n        when(invoker14.isAvailable()).thenReturn(true);\n        when(invoker15.isAvailable()).thenReturn(true);\n\n        Set<Invoker> invokerSet = new HashSet<>();\n        invokerSet.add(invoker1);\n        invokerSet.add(invoker2);\n        invokerSet.add(invoker3);\n        invokerSet.add(invoker4);\n        invokerSet.add(invoker5);\n        invokerSet.add(invoker6);\n        invokerSet.add(invoker7);\n        invokerSet.add(invoker8);\n        invokerSet.add(invoker9);\n        invokerSet.add(invoker10);\n        invokerSet.add(invoker11);\n        invokerSet.add(invoker12);\n        invokerSet.add(invoker13);\n        invokerSet.add(invoker14);\n        invokerSet.add(invoker15);\n        waitRefresh(invokerSet);\n        Assertions.assertTrue(directory.list(invocation).size() > 1);\n    }\n\n    private static class ConnectivityClusterInvoker<T> extends AbstractClusterInvoker<T> {\n        public ConnectivityClusterInvoker(Directory<T> directory) {\n            super(directory);\n        }\n\n        @Override\n        public Invoker<T> select(\n                LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected)\n                throws RpcException {\n            return super.select(loadbalance, invocation, invokers, selected);\n        }\n\n        @Override\n        protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)\n                throws RpcException {\n            return null;\n        }\n    }\n\n    private void waitRefresh(Set<Invoker> invokerSet) throws InterruptedException {\n        directory.checkConnectivity();\n        while (true) {\n            List<Invoker> reconnectList = directory.getInvokersToReconnect();\n            if (reconnectList.stream().anyMatch(invoker -> invokerSet.contains(invoker))) {\n                Thread.sleep(10);\n                continue;\n            }\n            break;\n        }\n    }\n\n    private static class RandomLoadBalance implements LoadBalance {\n        @Override\n        public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {\n            return CollectionUtils.isNotEmpty(invokers)\n                    ? invokers.get(ThreadLocalRandom.current().nextInt(invokers.size()))\n                    : null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/DemoServiceA.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\npublic interface DemoServiceA {\n    String methodA();\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/DemoServiceAMock.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\n/**\n * default mock service for DemoServiceA\n */\npublic class DemoServiceAMock implements DemoServiceA {\n    public static final String MOCK_VALUE = \"mockA\";\n\n    @Override\n    public String methodA() {\n        return MOCK_VALUE;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/DemoServiceB.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\npublic interface DemoServiceB {\n    String methodB();\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/DemoServiceBMock.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\n/**\n * default mock service for DemoServiceA\n */\npublic class DemoServiceBMock implements DemoServiceB {\n    public static final String MOCK_VALUE = \"mockB\";\n\n    @Override\n    public String methodB() {\n        return MOCK_VALUE;\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.filter.DemoService;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * FailfastClusterInvokerTest\n *\n */\n@SuppressWarnings(\"unchecked\")\nclass FailSafeClusterInvokerTest {\n    List<Invoker<DemoService>> invokers = new ArrayList<Invoker<DemoService>>();\n    URL url = URL.valueOf(\"test://test:11/test\");\n    Invoker<DemoService> invoker = mock(Invoker.class);\n    RpcInvocation invocation = new RpcInvocation();\n    Directory<DemoService> dic;\n    Result result = new AppResponse();\n\n    /**\n     * @throws java.lang.Exception\n     */\n    @BeforeEach\n    public void setUp() throws Exception {\n        RpcContext.removeServiceContext();\n\n        dic = mock(Directory.class);\n\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(invokers);\n        given(dic.getInterface()).willReturn(DemoService.class);\n        invocation.setMethodName(\"method1\");\n\n        invokers.add(invoker);\n    }\n\n    private void resetInvokerToException() {\n        given(invoker.invoke(invocation)).willThrow(new RuntimeException());\n        given(invoker.getUrl()).willReturn(url);\n        given(invoker.getInterface()).willReturn(DemoService.class);\n    }\n\n    private void resetInvokerToNoException() {\n        given(invoker.invoke(invocation)).willReturn(result);\n        given(invoker.getUrl()).willReturn(url);\n        given(invoker.getInterface()).willReturn(DemoService.class);\n    }\n\n    // TODO assert error log\n    @Test\n    void testInvokeException() {\n        resetInvokerToException();\n        FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);\n        invoker.invoke(invocation);\n        Assertions.assertNull(RpcContext.getServiceContext().getInvoker());\n    }\n\n    @Test\n    void testInvokeNoException() {\n        resetInvokerToNoException();\n\n        FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);\n        Result ret = invoker.invoke(invocation);\n        Assertions.assertSame(result, ret);\n    }\n\n    @Test\n    void testNoInvoke() {\n        dic = mock(Directory.class);\n\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(null);\n        given(dic.getInterface()).willReturn(DemoService.class);\n\n        invocation.setMethodName(\"method1\");\n\n        resetInvokerToNoException();\n\n        FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);\n\n        try {\n            invoker.invoke(invocation);\n        } catch (RpcException e) {\n            Assertions.assertTrue(e.getMessage().contains(\"No provider available\"));\n            assertFalse(e.getCause() instanceof RpcException);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.utils.DubboAppender;\nimport org.apache.dubbo.common.utils.LogUtil;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.MethodOrderer;\nimport org.junit.jupiter.api.Order;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestMethodOrder;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * FailbackClusterInvokerTest\n * <p>\n * add annotation @TestMethodOrder, the testARetryFailed Method must to first execution\n */\n@TestMethodOrder(MethodOrderer.OrderAnnotation.class)\nclass FailbackClusterInvokerTest {\n\n    List<Invoker<FailbackClusterInvokerTest>> invokers = new ArrayList<>();\n    URL url = URL.valueOf(\"test://test:11/test?retries=2&failbacktasks=2\");\n    Invoker<FailbackClusterInvokerTest> invoker = mock(Invoker.class);\n    RpcInvocation invocation = new RpcInvocation();\n    Directory<FailbackClusterInvokerTest> dic;\n    Result result = new AppResponse();\n\n    /**\n     * @throws java.lang.Exception\n     */\n    @BeforeEach\n    public void setUp() throws Exception {\n        RpcContext.removeServiceContext();\n\n        dic = mock(Directory.class);\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(invokers);\n        given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class);\n\n        invocation.setMethodName(\"method1\");\n\n        invokers.add(invoker);\n    }\n\n    @AfterEach\n    public void tearDown() {\n\n        dic = null;\n        invocation = new RpcInvocation();\n        invokers.clear();\n    }\n\n    private void resetInvokerToException() {\n        given(invoker.invoke(invocation)).willThrow(new RuntimeException());\n        given(invoker.getUrl()).willReturn(url);\n        given(invoker.getInterface()).willReturn(FailbackClusterInvokerTest.class);\n    }\n\n    private void resetInvokerToNoException() {\n        given(invoker.invoke(invocation)).willReturn(result);\n        given(invoker.getUrl()).willReturn(url);\n        given(invoker.getInterface()).willReturn(FailbackClusterInvokerTest.class);\n    }\n\n    @Test\n    void testInvokeWithIllegalRetriesParam() {\n        URL url = URL.valueOf(\"test://test:11/test?retries=-1&failbacktasks=2\");\n        Directory<FailbackClusterInvokerTest> dic = mock(Directory.class);\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class);\n        given(dic.list(invocation)).willReturn(invokers);\n        given(invoker.getUrl()).willReturn(url);\n\n        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<>(dic);\n        invoker.invoke(invocation);\n        Assertions.assertNull(RpcContext.getServiceContext().getInvoker());\n        DubboAppender.clear();\n    }\n\n    @Test\n    void testInvokeWithIllegalFailbacktasksParam() {\n        URL url = URL.valueOf(\"test://test:11/test?retries=2&failbacktasks=-1\");\n        Directory<FailbackClusterInvokerTest> dic = mock(Directory.class);\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class);\n        given(dic.list(invocation)).willReturn(invokers);\n        given(invoker.getUrl()).willReturn(url);\n\n        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<>(dic);\n        invoker.invoke(invocation);\n        Assertions.assertNull(RpcContext.getServiceContext().getInvoker());\n        DubboAppender.clear();\n    }\n\n    @Test\n    @Order(1)\n    public void testInvokeException() {\n        resetInvokerToException();\n        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<>(dic);\n        invoker.invoke(invocation);\n        Assertions.assertNull(RpcContext.getServiceContext().getInvoker());\n        DubboAppender.clear();\n    }\n\n    @Test\n    @Order(2)\n    public void testInvokeNoException() {\n\n        resetInvokerToNoException();\n\n        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<>(dic);\n        Result ret = invoker.invoke(invocation);\n        Assertions.assertSame(result, ret);\n    }\n\n    @Test\n    @Order(3)\n    public void testNoInvoke() {\n        dic = mock(Directory.class);\n\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(null);\n        given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class);\n\n        invocation.setMethodName(\"method1\");\n        invokers.add(invoker);\n\n        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<>(dic);\n        try {\n            invoker.invoke(invocation);\n        } catch (RpcException e) {\n            Assertions.assertTrue(e.getMessage().contains(\"No provider available\"));\n            assertFalse(e.getCause() instanceof RpcException);\n        }\n    }\n\n    @Disabled\n    @Test\n    @Order(4)\n    public void testARetryFailed() throws Exception {\n        // Test retries and\n\n        resetInvokerToException();\n\n        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<>(dic);\n        LogUtil.start();\n        DubboAppender.clear();\n        invoker.invoke(invocation);\n        invoker.invoke(invocation);\n        invoker.invoke(invocation);\n        Assertions.assertNull(RpcContext.getServiceContext().getInvoker());\n        //        invoker.retryFailed();// when retry the invoker which get from failed map already is not the mocked\n        // invoker,so\n        // Ensure that the main thread is online\n        CountDownLatch countDown = new CountDownLatch(1);\n        countDown.await(15000L, TimeUnit.MILLISECONDS);\n        LogUtil.stop();\n        Assertions.assertEquals(\n                4, LogUtil.findMessage(Level.ERROR, \"Failed retry to invoke method\"), \"must have four error message \");\n        Assertions.assertEquals(\n                2,\n                LogUtil.findMessage(Level.ERROR, \"Failed retry times exceed threshold\"),\n                \"must have two error message \");\n        Assertions.assertEquals(\n                1, LogUtil.findMessage(Level.ERROR, \"Failback background works error\"), \"must have one error message \");\n        // it can be invoke successfully\n    }\n\n    private long getRetryFailedPeriod() throws NoSuchFieldException, IllegalAccessException {\n        Field retryFailedPeriod = FailbackClusterInvoker.class.getDeclaredField(\"RETRY_FAILED_PERIOD\");\n        retryFailedPeriod.setAccessible(true);\n        return retryFailedPeriod.getLong(FailbackClusterInvoker.class);\n    }\n\n    @Test\n    @Order(5)\n    public void testInvokeRetryTimesWithZeroValue()\n            throws InterruptedException, NoSuchFieldException, IllegalAccessException {\n        int retries = 0;\n        resetInvokerToException();\n        given(dic.getConsumerUrl()).willReturn(url.addParameter(RETRIES_KEY, retries));\n\n        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<>(dic);\n        LogUtil.start();\n        DubboAppender.clear();\n\n        invocation.setMethodName(\"testInvokeRetryTimesWithZeroValue\");\n        invoker.invoke(invocation);\n\n        CountDownLatch countDown = new CountDownLatch(1);\n        countDown.await(getRetryFailedPeriod() * (retries + 1), TimeUnit.SECONDS);\n        LogUtil.stop();\n        Assertions.assertEquals(\n                0,\n                LogUtil.findMessage(\n                        Level.INFO, \"Attempt to retry to invoke method \" + \"testInvokeRetryTimesWithZeroValue\"),\n                \"No retry messages allowed\");\n    }\n\n    @Test\n    @Order(6)\n    public void testInvokeRetryTimesWithTwoValue()\n            throws InterruptedException, NoSuchFieldException, IllegalAccessException {\n        int retries = 2;\n        resetInvokerToException();\n        given(dic.getConsumerUrl()).willReturn(url.addParameter(RETRIES_KEY, retries));\n\n        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<>(dic);\n        LogUtil.start();\n        DubboAppender.clear();\n\n        invocation.setMethodName(\"testInvokeRetryTimesWithTwoValue\");\n        invoker.invoke(invocation);\n\n        CountDownLatch countDown = new CountDownLatch(1);\n        countDown.await(getRetryFailedPeriod() * (retries + 1), TimeUnit.SECONDS);\n        LogUtil.stop();\n        Assertions.assertEquals(\n                2,\n                LogUtil.findMessage(\n                        Level.INFO, \"Attempt to retry to invoke method \" + \"testInvokeRetryTimesWithTwoValue\"),\n                \"Must have two error message \");\n    }\n\n    @Test\n    @Order(7)\n    public void testInvokeRetryTimesWithDefaultValue()\n            throws InterruptedException, NoSuchFieldException, IllegalAccessException {\n        resetInvokerToException();\n        given(dic.getConsumerUrl()).willReturn(URL.valueOf(\"test://test:11/test\"));\n\n        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<>(dic);\n        LogUtil.start();\n        DubboAppender.clear();\n\n        invocation.setMethodName(\"testInvokeRetryTimesWithDefaultValue\");\n        invoker.invoke(invocation);\n\n        CountDownLatch countDown = new CountDownLatch(1);\n        countDown.await(getRetryFailedPeriod() * (CommonConstants.DEFAULT_FAILBACK_TIMES + 1), TimeUnit.SECONDS);\n        LogUtil.stop();\n        Assertions.assertEquals(\n                3,\n                LogUtil.findMessage(\n                        Level.INFO, \"Attempt to retry to invoke method \" + \"testInvokeRetryTimesWithDefaultValue\"),\n                \"Must have three error message \");\n    }\n\n    @Test\n    @Order(8)\n    public void testInvokeRetryTimesWithIllegalValue()\n            throws InterruptedException, NoSuchFieldException, IllegalAccessException {\n        resetInvokerToException();\n        given(dic.getConsumerUrl()).willReturn(url.addParameter(RETRIES_KEY, -100));\n\n        FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<>(dic);\n        LogUtil.start();\n        DubboAppender.clear();\n\n        invocation.setMethodName(\"testInvokeRetryTimesWithIllegalValue\");\n        invoker.invoke(invocation);\n\n        CountDownLatch countDown = new CountDownLatch(1);\n        countDown.await(getRetryFailedPeriod() * (CommonConstants.DEFAULT_FAILBACK_TIMES + 1), TimeUnit.SECONDS);\n        LogUtil.stop();\n        Assertions.assertEquals(\n                3,\n                LogUtil.findMessage(\n                        Level.INFO, \"Attempt to retry to invoke method \" + \"testInvokeRetryTimesWithIllegalValue\"),\n                \"Must have three error message \");\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n@SuppressWarnings(\"unchecked\")\nclass FailfastClusterInvokerTest {\n    List<Invoker<FailfastClusterInvokerTest>> invokers = new ArrayList<>();\n    URL url = URL.valueOf(\"test://test:11/test\");\n    Invoker<FailfastClusterInvokerTest> invoker1 = mock(Invoker.class);\n    RpcInvocation invocation = new RpcInvocation();\n    Directory<FailfastClusterInvokerTest> dic;\n    Result result = new AppResponse();\n\n    /**\n     * @throws java.lang.Exception\n     */\n    @BeforeEach\n    public void setUp() throws Exception {\n\n        dic = mock(Directory.class);\n\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(invokers);\n        given(dic.getInterface()).willReturn(FailfastClusterInvokerTest.class);\n\n        invocation.setMethodName(\"method1\");\n\n        invokers.add(invoker1);\n    }\n\n    private void resetInvoker1ToException() {\n        given(invoker1.invoke(invocation)).willThrow(new RuntimeException());\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.getInterface()).willReturn(FailfastClusterInvokerTest.class);\n    }\n\n    private void resetInvoker1ToNoException() {\n        given(invoker1.invoke(invocation)).willReturn(result);\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.getInterface()).willReturn(FailfastClusterInvokerTest.class);\n    }\n\n    @Test\n    void testInvokeException() {\n        Assertions.assertThrows(RpcException.class, () -> {\n            resetInvoker1ToException();\n            FailfastClusterInvoker<FailfastClusterInvokerTest> invoker = new FailfastClusterInvoker<>(dic);\n            invoker.invoke(invocation);\n            assertSame(invoker1, RpcContext.getServiceContext().getInvoker());\n        });\n    }\n\n    @Test\n    void testInvokeBizException() {\n        given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.BIZ_EXCEPTION));\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.getInterface()).willReturn(FailfastClusterInvokerTest.class);\n        FailfastClusterInvoker<FailfastClusterInvokerTest> invoker = new FailfastClusterInvoker<>(dic);\n\n        try {\n            Result ret = invoker.invoke(invocation);\n            assertSame(result, ret);\n            fail();\n        } catch (RpcException expected) {\n            assertEquals(expected.getCode(), RpcException.BIZ_EXCEPTION);\n        }\n    }\n\n    @Test\n    void testInvokeNoException() {\n\n        resetInvoker1ToNoException();\n\n        FailfastClusterInvoker<FailfastClusterInvokerTest> invoker = new FailfastClusterInvoker<>(dic);\n        Result ret = invoker.invoke(invocation);\n        assertSame(result, ret);\n    }\n\n    @Test\n    void testNoInvoke() {\n        dic = mock(Directory.class);\n\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(null);\n        given(dic.getInterface()).willReturn(FailfastClusterInvokerTest.class);\n\n        invocation.setMethodName(\"method1\");\n\n        invokers.add(invoker1);\n\n        resetInvoker1ToNoException();\n\n        FailfastClusterInvoker<FailfastClusterInvokerTest> invoker = new FailfastClusterInvoker<>(dic);\n        try {\n            invoker.invoke(invocation);\n            fail();\n        } catch (RpcException expected) {\n            assertFalse(expected.getCause() instanceof RpcException);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.SingleRouterChain;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.protocol.AbstractInvoker;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Callable;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n@SuppressWarnings(\"unchecked\")\nclass FailoverClusterInvokerTest {\n    private final int retries = 5;\n    private final URL url = URL.valueOf(\"test://test:11/test?retries=\" + retries);\n    private final Invoker<FailoverClusterInvokerTest> invoker1 = mock(Invoker.class);\n    private final Invoker<FailoverClusterInvokerTest> invoker2 = mock(Invoker.class);\n    private final RpcInvocation invocation = new RpcInvocation();\n    private final Result expectedResult = new AppResponse();\n    private final List<Invoker<FailoverClusterInvokerTest>> invokers = new ArrayList<>();\n    private Directory<FailoverClusterInvokerTest> dic;\n\n    /**\n     * @throws java.lang.Exception\n     */\n    @BeforeEach\n    public void setUp() throws Exception {\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);\n        dic = mock(Directory.class);\n\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(invokers);\n        given(dic.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n        invocation.setMethodName(\"method1\");\n\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n    }\n\n    @Test\n    void testInvokeWithRuntimeException() {\n        given(invoker1.invoke(invocation)).willThrow(new RuntimeException());\n        given(invoker1.isAvailable()).willReturn(true);\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n\n        given(invoker2.invoke(invocation)).willThrow(new RuntimeException());\n        given(invoker2.isAvailable()).willReturn(true);\n        given(invoker2.getUrl()).willReturn(url);\n        given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n\n        FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<>(dic);\n        try {\n            invoker.invoke(invocation);\n            fail();\n        } catch (RpcException actualException) {\n            assertEquals(0, actualException.getCode());\n            assertFalse(actualException.getCause() instanceof RpcException);\n        }\n    }\n\n    @Test\n    void testInvokeWithRPCException() {\n        given(invoker1.invoke(invocation)).willThrow(new RpcException());\n        given(invoker1.isAvailable()).willReturn(true);\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n\n        given(invoker2.invoke(invocation)).willReturn(expectedResult);\n        given(invoker2.isAvailable()).willReturn(true);\n        given(invoker2.getUrl()).willReturn(url);\n        given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n\n        FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<>(dic);\n        for (int i = 0; i < 100; i++) {\n            Result actualResult = invoker.invoke(invocation);\n            assertSame(expectedResult, actualResult);\n        }\n    }\n\n    @Test\n    void testInvoke_retryTimes() {\n        given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION));\n        given(invoker1.isAvailable()).willReturn(false);\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n\n        given(invoker2.invoke(invocation)).willThrow(new RpcException());\n        given(invoker2.isAvailable()).willReturn(false);\n        given(invoker2.getUrl()).willReturn(url);\n        given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n\n        FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<>(dic);\n        try {\n            Result actualResult = invoker.invoke(invocation);\n            assertSame(expectedResult, actualResult);\n            fail();\n        } catch (RpcException actualException) {\n            assertTrue((actualException.isTimeout() || actualException.getCode() == 0));\n            assertTrue(actualException.getMessage().indexOf((retries + 1) + \" times\") > 0);\n        }\n    }\n\n    @Test\n    void testInvoke_retryTimes2() {\n        int finalRetries = 1;\n        given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION));\n        given(invoker1.isAvailable()).willReturn(false);\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n\n        given(invoker2.invoke(invocation)).willThrow(new RpcException());\n        given(invoker2.isAvailable()).willReturn(false);\n        given(invoker2.getUrl()).willReturn(url);\n        given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n\n        RpcContext rpcContext = RpcContext.getContext();\n        rpcContext.setAttachment(\"retries\", finalRetries);\n\n        FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<>(dic);\n        try {\n            Result actualResult = invoker.invoke(invocation);\n            assertSame(expectedResult, actualResult);\n            fail();\n        } catch (RpcException actualException) {\n            assertTrue((actualException.isTimeout() || actualException.getCode() == 0));\n            assertTrue(actualException.getMessage().indexOf((finalRetries + 1) + \" times\") > 0);\n        }\n    }\n\n    @Test\n    void testInvoke_retryTimes_withBizException() {\n        given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.BIZ_EXCEPTION));\n        given(invoker1.isAvailable()).willReturn(false);\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n\n        given(invoker2.invoke(invocation)).willThrow(new RpcException(RpcException.BIZ_EXCEPTION));\n        given(invoker2.isAvailable()).willReturn(false);\n        given(invoker2.getUrl()).willReturn(url);\n        given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n\n        FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<>(dic);\n        try {\n            Result actualResult = invoker.invoke(invocation);\n            assertSame(expectedResult, actualResult);\n            fail();\n        } catch (RpcException actualException) {\n            assertEquals(RpcException.BIZ_EXCEPTION, actualException.getCode());\n        }\n    }\n\n    @Test\n    void testInvoke_without_retry() {\n        int withoutRetry = 0;\n        final URL url = URL.valueOf(\n                \"test://localhost/\" + Demo.class.getName() + \"?loadbalance=roundrobin&retries=\" + withoutRetry);\n        RpcException exception = new RpcException(RpcException.TIMEOUT_EXCEPTION);\n        MockInvoker<Demo> invoker1 = new MockInvoker<>(Demo.class, url);\n        invoker1.setException(exception);\n\n        MockInvoker<Demo> invoker2 = new MockInvoker<>(Demo.class, url);\n        invoker2.setException(exception);\n\n        final List<Invoker<Demo>> invokers = new ArrayList<>();\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n\n        try {\n            Directory<Demo> dic = new MockDirectory<>(url, invokers);\n            FailoverClusterInvoker<Demo> clusterInvoker = new FailoverClusterInvoker<>(dic);\n            RpcInvocation inv = new RpcInvocation();\n            inv.setMethodName(\"test\");\n            clusterInvoker.invoke(inv);\n        } catch (RpcException actualException) {\n            assertTrue(actualException.getCause() instanceof RpcException);\n            assertEquals(RpcException.TIMEOUT_EXCEPTION, actualException.getCode());\n        }\n    }\n\n    @Test\n    void testInvoke_when_retry_illegal() {\n        int illegalRetry = -1;\n        final URL url = URL.valueOf(\n                \"test://localhost/\" + Demo.class.getName() + \"?loadbalance=roundrobin&retries=\" + illegalRetry);\n        RpcException exception = new RpcException(RpcException.TIMEOUT_EXCEPTION);\n        MockInvoker<Demo> invoker1 = new MockInvoker<>(Demo.class, url);\n        invoker1.setException(exception);\n\n        MockInvoker<Demo> invoker2 = new MockInvoker<>(Demo.class, url);\n        invoker2.setException(exception);\n\n        final List<Invoker<Demo>> invokers = new ArrayList<>();\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n\n        try {\n            Directory<Demo> dic = new MockDirectory<>(url, invokers);\n            FailoverClusterInvoker<Demo> clusterInvoker = new FailoverClusterInvoker<>(dic);\n            RpcInvocation inv = new RpcInvocation();\n            inv.setMethodName(\"test\");\n            clusterInvoker.invoke(inv);\n        } catch (RpcException actualException) {\n            assertTrue(actualException.getCause() instanceof RpcException);\n            assertEquals(RpcException.TIMEOUT_EXCEPTION, actualException.getCode());\n        }\n    }\n\n    @Test\n    void testNoInvoke() {\n        dic = mock(Directory.class);\n\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(null);\n        given(dic.getInterface()).willReturn(FailoverClusterInvokerTest.class);\n        invocation.setMethodName(\"method1\");\n\n        invokers.add(invoker1);\n\n        FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<>(dic);\n        try {\n            invoker.invoke(invocation);\n            fail();\n        } catch (RpcException actualException) {\n            assertFalse(actualException.getCause() instanceof RpcException);\n        }\n    }\n\n    /**\n     * When invokers in directory changes after a failed request but just before a retry effort,\n     * then we should reselect from the latest invokers before retry.\n     */\n    @Test\n    void testInvokerDestroyAndReList() {\n        final URL url =\n                URL.valueOf(\"test://localhost/\" + Demo.class.getName() + \"?loadbalance=roundrobin&retries=\" + retries);\n        RpcException exception = new RpcException(RpcException.TIMEOUT_EXCEPTION);\n        MockInvoker<Demo> invoker1 = new MockInvoker<>(Demo.class, url);\n        invoker1.setException(exception);\n\n        MockInvoker<Demo> invoker2 = new MockInvoker<>(Demo.class, url);\n        invoker2.setException(exception);\n\n        final List<Invoker<Demo>> invokers = new ArrayList<>();\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n\n        MockDirectory<Demo> dic = new MockDirectory<>(url, invokers);\n\n        Callable<Object> callable = () -> {\n            // Simulation: all invokers are destroyed\n            for (Invoker<Demo> invoker : invokers) {\n                invoker.destroy();\n            }\n            invokers.clear();\n            MockInvoker<Demo> invoker3 = new MockInvoker<>(Demo.class, url);\n            invoker3.setResult(AsyncRpcResult.newDefaultAsyncResult(mock(RpcInvocation.class)));\n            invokers.add(invoker3);\n            dic.notify(invokers);\n            return null;\n        };\n        invoker1.setCallable(callable);\n        invoker2.setCallable(callable);\n\n        RpcInvocation inv = new RpcInvocation();\n        inv.setMethodName(\"test\");\n\n        FailoverClusterInvoker<Demo> clusterInvoker = new FailoverClusterInvoker<>(dic);\n        clusterInvoker.invoke(inv);\n    }\n\n    public interface Demo {}\n\n    public static class MockInvoker<T> extends AbstractInvoker<T> {\n        URL url;\n        boolean available = true;\n        boolean destroyed = false;\n        Result result;\n        RpcException exception;\n        Callable<?> callable;\n\n        public MockInvoker(Class<T> type, URL url) {\n            super(type, url);\n        }\n\n        public void setResult(Result result) {\n            this.result = result;\n        }\n\n        public void setException(RpcException exception) {\n            this.exception = exception;\n        }\n\n        public void setCallable(Callable<?> callable) {\n            this.callable = callable;\n        }\n\n        @Override\n        protected Result doInvoke(Invocation invocation) throws Throwable {\n            if (callable != null) {\n                try {\n                    callable.call();\n                } catch (Exception e) {\n                    throw new RpcException(e);\n                }\n            }\n            if (exception != null) {\n                throw exception;\n            } else {\n                return result;\n            }\n        }\n    }\n\n    public static class MockDirectory<T> extends StaticDirectory<T> {\n        public MockDirectory(URL url, List<Invoker<T>> invokers) {\n            super(url, invokers);\n        }\n\n        @Override\n        protected List<Invoker<T>> doList(\n                SingleRouterChain<T> singleRouterChain, BitList<Invoker<T>> invokers, Invocation invocation)\n                throws RpcException {\n            return super.doList(singleRouterChain, invokers, invocation);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n@SuppressWarnings(\"unchecked\")\nclass ForkingClusterInvokerTest {\n\n    private List<Invoker<ForkingClusterInvokerTest>> invokers = new ArrayList<>();\n    private URL url = URL.valueOf(\"test://test:11/test?forks=2\");\n    private Invoker<ForkingClusterInvokerTest> invoker1 = mock(Invoker.class);\n    private Invoker<ForkingClusterInvokerTest> invoker2 = mock(Invoker.class);\n    private Invoker<ForkingClusterInvokerTest> invoker3 = mock(Invoker.class);\n    private RpcInvocation invocation = new RpcInvocation();\n    private Directory<ForkingClusterInvokerTest> dic;\n    private Result result = new AppResponse();\n\n    @BeforeEach\n    public void setUp() throws Exception {\n\n        dic = mock(Directory.class);\n\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(dic.list(invocation)).willReturn(invokers);\n        given(dic.getInterface()).willReturn(ForkingClusterInvokerTest.class);\n\n        invocation.setMethodName(\"method1\");\n\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n        invokers.add(invoker3);\n    }\n\n    private void resetInvokerToException() {\n        given(invoker1.invoke(invocation)).willThrow(new RuntimeException());\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.isAvailable()).willReturn(true);\n        given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);\n\n        given(invoker2.invoke(invocation)).willThrow(new RuntimeException());\n        given(invoker2.getUrl()).willReturn(url);\n        given(invoker2.isAvailable()).willReturn(true);\n        given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);\n\n        given(invoker3.invoke(invocation)).willThrow(new RuntimeException());\n        given(invoker3.getUrl()).willReturn(url);\n        given(invoker3.isAvailable()).willReturn(true);\n        given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);\n    }\n\n    private void resetInvokerToNoException() {\n        given(invoker1.invoke(invocation)).willReturn(result);\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.isAvailable()).willReturn(true);\n        given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);\n\n        given(invoker2.invoke(invocation)).willReturn(result);\n        given(invoker2.getUrl()).willReturn(url);\n        given(invoker2.isAvailable()).willReturn(true);\n        given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);\n\n        given(invoker3.invoke(invocation)).willReturn(result);\n        given(invoker3.getUrl()).willReturn(url);\n        given(invoker3.isAvailable()).willReturn(true);\n        given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);\n    }\n\n    @Test\n    void testInvokeException() {\n        resetInvokerToException();\n        ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<>(dic);\n\n        try {\n            invoker.invoke(invocation);\n            Assertions.fail();\n        } catch (RpcException expected) {\n            Assertions.assertTrue(expected.getMessage().contains(\"Failed to forking invoke provider\"));\n            assertFalse(expected.getCause() instanceof RpcException);\n        }\n    }\n\n    @Test\n    void testClearRpcContext() {\n        resetInvokerToException();\n        ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<>(dic);\n\n        String attachKey = \"attach\";\n        String attachValue = \"value\";\n\n        RpcContext.getClientAttachment().setAttachment(attachKey, attachValue);\n\n        Map<String, Object> attachments = RpcContext.getClientAttachment().getObjectAttachments();\n        Assertions.assertTrue(attachments != null && attachments.size() == 1, \"set attachment failed!\");\n        try {\n            invoker.invoke(invocation);\n            Assertions.fail();\n        } catch (RpcException expected) {\n            Assertions.assertTrue(\n                    expected.getMessage().contains(\"Failed to forking invoke provider\"),\n                    \"Succeeded to forking invoke provider !\");\n            assertFalse(expected.getCause() instanceof RpcException);\n        }\n        Map<String, Object> afterInvoke = RpcContext.getClientAttachment().getObjectAttachments();\n        Assertions.assertTrue(afterInvoke != null && afterInvoke.size() == 0, \"clear attachment failed!\");\n    }\n\n    @Test\n    void testInvokeNoException() {\n\n        resetInvokerToNoException();\n\n        ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<>(dic);\n        Result ret = invoker.invoke(invocation);\n        Assertions.assertSame(result, ret);\n    }\n\n    @Test\n    void testInvokeWithIllegalForksParam() {\n        URL url = URL.valueOf(\"test://test:11/test?forks=-1\");\n        given(dic.getUrl()).willReturn(url);\n        given(dic.getConsumerUrl()).willReturn(url);\n        given(invoker1.invoke(invocation)).willReturn(result);\n        given(invoker1.getUrl()).willReturn(url);\n        given(invoker1.isAvailable()).willReturn(true);\n        given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);\n\n        ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<>(dic);\n        Result ret = invoker.invoke(invocation);\n        Assertions.assertSame(result, ret);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/Greeting.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface Greeting {\n    String hello();\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/GreetingMock1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\npublic class GreetingMock1 {}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/GreetingMock2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\npublic class GreetingMock2 implements Greeting {\n    private GreetingMock2() {}\n\n    @Override\n    public String hello() {\n        return \"mock\";\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/Menu.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nclass Menu {\n\n    private Map<String, List<String>> menus = new HashMap<String, List<String>>();\n\n    public Menu() {}\n\n    public Menu(Map<String, List<String>> menus) {\n        for (Map.Entry<String, List<String>> entry : menus.entrySet()) {\n            this.menus.put(entry.getKey(), new ArrayList<String>(entry.getValue()));\n        }\n    }\n\n    public void putMenuItem(String menu, String item) {\n        List<String> items = menus.get(menu);\n        if (item == null) {\n            items = new ArrayList<String>();\n            menus.put(menu, items);\n        }\n        items.add(item);\n    }\n\n    public void addMenu(String menu, List<String> items) {\n        List<String> menuItems = menus.get(menu);\n        if (menuItems == null) {\n            menus.put(menu, new ArrayList<String>(items));\n        } else {\n            menuItems.addAll(new ArrayList<String>(items));\n        }\n    }\n\n    public Map<String, List<String>> getMenus() {\n        return Collections.unmodifiableMap(menus);\n    }\n\n    public void merge(Menu menu) {\n        for (Map.Entry<String, List<String>> entry : menu.menus.entrySet()) {\n            addMenu(entry.getKey(), entry.getValue());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/MenuService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport java.util.List;\n\npublic interface MenuService {\n\n    Menu getMenu();\n\n    void addMenu(String menu, List<String> items);\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.lang.reflect.Proxy;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.rpc.Constants.MERGER_KEY;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\nclass MergeableClusterInvokerTest {\n\n    private Directory directory = mock(Directory.class);\n    private Invoker firstInvoker = mock(Invoker.class);\n    private Invoker secondInvoker = mock(Invoker.class);\n    private Invocation invocation = mock(RpcInvocation.class);\n    private ModuleModel moduleModel = mock(ModuleModel.class);\n\n    private MergeableClusterInvoker<MenuService> mergeableClusterInvoker;\n\n    private String[] list1 = {\"10\", \"11\", \"12\"};\n    private String[] list2 = {\"20\", \"21\", \"22\"};\n    private final Map<String, List<String>> firstMenuMap = new HashMap<String, List<String>>() {\n        {\n            put(\"1\", Arrays.asList(list1));\n            put(\"2\", Arrays.asList(list2));\n        }\n    };\n    private final Menu firstMenu = new Menu(firstMenuMap);\n    private String[] list3 = {\"23\", \"24\", \"25\"};\n    private String[] list4 = {\"30\", \"31\", \"32\"};\n    private final Map<String, List<String>> secondMenuMap = new HashMap<String, List<String>>() {\n        {\n            put(\"2\", Arrays.asList(list3));\n            put(\"3\", Arrays.asList(list4));\n        }\n    };\n    private final Menu secondMenu = new Menu(secondMenuMap);\n\n    private URL url = URL.valueOf(\"test://test/\" + MenuService.class.getName());\n\n    static void merge(Map<String, List<String>> first, Map<String, List<String>> second) {\n        for (Map.Entry<String, List<String>> entry : second.entrySet()) {\n            List<String> value = first.get(entry.getKey());\n            if (value != null) {\n                value.addAll(entry.getValue());\n            } else {\n                first.put(entry.getKey(), new ArrayList<>(entry.getValue()));\n            }\n        }\n    }\n\n    @BeforeEach\n    public void setUp() throws Exception {\n\n        directory = mock(Directory.class);\n        firstInvoker = mock(Invoker.class);\n        secondInvoker = mock(Invoker.class);\n        invocation = mock(RpcInvocation.class);\n    }\n\n    @Test\n    void testGetMenuSuccessfully() {\n\n        // setup\n        url = url.addParameter(MERGER_KEY, \".merge\");\n\n        given(invocation.getMethodName()).willReturn(\"getMenu\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {});\n        given(invocation.getArguments()).willReturn(new Object[] {});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n        given(invocation.getInvoker()).willReturn(firstInvoker);\n\n        firstInvoker = (Invoker) Proxy.newProxyInstance(\n                getClass().getClassLoader(), new Class<?>[] {Invoker.class}, (proxy, method, args) -> {\n                    if (\"getUrl\".equals(method.getName())) {\n                        return url.addParameter(GROUP_KEY, \"first\");\n                    }\n                    if (\"getInterface\".equals(method.getName())) {\n                        return MenuService.class;\n                    }\n                    if (\"invoke\".equals(method.getName())) {\n                        return AsyncRpcResult.newDefaultAsyncResult(firstMenu, invocation);\n                    }\n                    return null;\n                });\n\n        secondInvoker = (Invoker) Proxy.newProxyInstance(\n                getClass().getClassLoader(), new Class<?>[] {Invoker.class}, (proxy, method, args) -> {\n                    if (\"getUrl\".equals(method.getName())) {\n                        return url.addParameter(GROUP_KEY, \"second\");\n                    }\n                    if (\"getInterface\".equals(method.getName())) {\n                        return MenuService.class;\n                    }\n                    if (\"invoke\".equals(method.getName())) {\n                        return AsyncRpcResult.newDefaultAsyncResult(secondMenu, invocation);\n                    }\n                    return null;\n                });\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n            }\n        });\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getInterface()).willReturn(MenuService.class);\n\n        mergeableClusterInvoker = new MergeableClusterInvoker<MenuService>(directory);\n\n        // invoke\n        Result result = mergeableClusterInvoker.invoke(invocation);\n        assertTrue(result.getValue() instanceof Menu);\n        Menu menu = (Menu) result.getValue();\n        Map<String, List<String>> expected = new HashMap<>();\n        merge(expected, firstMenuMap);\n        merge(expected, secondMenuMap);\n        assertEquals(expected.keySet(), menu.getMenus().keySet());\n        for (Map.Entry<String, List<String>> entry : expected.entrySet()) {\n            // FIXME: cannot guarantee the sequence of the merge result, check implementation in\n            // MergeableClusterInvoker#invoke\n            List<String> values1 = new ArrayList<>(entry.getValue());\n            List<String> values2 = new ArrayList<>(menu.getMenus().get(entry.getKey()));\n            Collections.sort(values1);\n            Collections.sort(values2);\n            assertEquals(values1, values2);\n        }\n    }\n\n    @Test\n    void testAddMenu() {\n\n        String menu = \"first\";\n        List<String> menuItems = new ArrayList<String>() {\n            {\n                add(\"1\");\n                add(\"2\");\n            }\n        };\n\n        given(invocation.getMethodName()).willReturn(\"addMenu\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {String.class, List.class});\n        given(invocation.getArguments()).willReturn(new Object[] {menu, menuItems});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n        given(invocation.getInvoker()).willReturn(firstInvoker);\n\n        given(firstInvoker.getUrl()).willReturn(url.addParameter(GROUP_KEY, \"first\"));\n        given(firstInvoker.getInterface()).willReturn(MenuService.class);\n        given(firstInvoker.invoke(invocation)).willReturn(new AppResponse());\n        given(firstInvoker.isAvailable()).willReturn(true);\n\n        given(secondInvoker.getUrl()).willReturn(url.addParameter(GROUP_KEY, \"second\"));\n        given(secondInvoker.getInterface()).willReturn(MenuService.class);\n        given(secondInvoker.invoke(invocation)).willReturn(new AppResponse());\n        given(secondInvoker.isAvailable()).willReturn(true);\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n            }\n        });\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getInterface()).willReturn(MenuService.class);\n\n        mergeableClusterInvoker = new MergeableClusterInvoker<MenuService>(directory);\n\n        Result result = mergeableClusterInvoker.invoke(invocation);\n        Assertions.assertNull(result.getValue());\n    }\n\n    @Test\n    void testAddMenu1() {\n\n        // setup\n        url = url.addParameter(MERGER_KEY, \".merge\");\n\n        String menu = \"first\";\n        List<String> menuItems = new ArrayList<String>() {\n            {\n                add(\"1\");\n                add(\"2\");\n            }\n        };\n\n        given(invocation.getMethodName()).willReturn(\"addMenu\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {String.class, List.class});\n        given(invocation.getArguments()).willReturn(new Object[] {menu, menuItems});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n        given(invocation.getInvoker()).willReturn(firstInvoker);\n\n        firstInvoker = (Invoker) Proxy.newProxyInstance(\n                getClass().getClassLoader(), new Class<?>[] {Invoker.class}, (proxy, method, args) -> {\n                    if (\"getUrl\".equals(method.getName())) {\n                        return url.addParameter(GROUP_KEY, \"first\");\n                    }\n                    if (\"getInterface\".equals(method.getName())) {\n                        return MenuService.class;\n                    }\n                    if (\"invoke\".equals(method.getName())) {\n                        return AsyncRpcResult.newDefaultAsyncResult(firstMenu, invocation);\n                    }\n                    return null;\n                });\n\n        secondInvoker = (Invoker) Proxy.newProxyInstance(\n                getClass().getClassLoader(), new Class<?>[] {Invoker.class}, (proxy, method, args) -> {\n                    if (\"getUrl\".equals(method.getName())) {\n                        return url.addParameter(GROUP_KEY, \"second\");\n                    }\n                    if (\"getInterface\".equals(method.getName())) {\n                        return MenuService.class;\n                    }\n                    if (\"invoke\".equals(method.getName())) {\n                        return AsyncRpcResult.newDefaultAsyncResult(secondMenu, invocation);\n                    }\n                    return null;\n                });\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n            }\n        });\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getInterface()).willReturn(MenuService.class);\n\n        mergeableClusterInvoker = new MergeableClusterInvoker<MenuService>(directory);\n\n        Result result = mergeableClusterInvoker.invoke(invocation);\n        Assertions.assertNull(result.getValue());\n    }\n\n    @Test\n    void testInvokerToNoInvokerAvailableException() {\n        String menu = \"first\";\n        List<String> menuItems = new ArrayList<String>() {\n            {\n                add(\"1\");\n                add(\"2\");\n            }\n        };\n\n        given(invocation.getMethodName()).willReturn(\"addMenu\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {String.class, List.class});\n        given(invocation.getArguments()).willReturn(new Object[] {menu, menuItems});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n        given(invocation.getInvoker()).willReturn(firstInvoker);\n\n        given(firstInvoker.getUrl()).willReturn(url.addParameter(GROUP_KEY, \"first\"));\n        given(firstInvoker.getInterface()).willReturn(MenuService.class);\n        given(firstInvoker.invoke(invocation)).willReturn(new AppResponse());\n        given(firstInvoker.isAvailable()).willReturn(true);\n        given(firstInvoker.invoke(invocation))\n                .willThrow(new RpcException(RpcException.NO_INVOKER_AVAILABLE_AFTER_FILTER));\n\n        given(secondInvoker.getUrl()).willReturn(url.addParameter(GROUP_KEY, \"second\"));\n        given(secondInvoker.getInterface()).willReturn(MenuService.class);\n        given(secondInvoker.invoke(invocation)).willReturn(new AppResponse());\n        given(secondInvoker.isAvailable()).willReturn(true);\n        given(secondInvoker.invoke(invocation))\n                .willThrow(new RpcException(RpcException.NO_INVOKER_AVAILABLE_AFTER_FILTER));\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n            }\n        });\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getInterface()).willReturn(MenuService.class);\n\n        mergeableClusterInvoker = new MergeableClusterInvoker<MenuService>(directory);\n\n        // invoke\n        try {\n            Result result = mergeableClusterInvoker.invoke(invocation);\n            fail();\n            Assertions.assertNull(result.getValue());\n        } catch (RpcException expected) {\n            assertEquals(expected.getCode(), RpcException.NO_INVOKER_AVAILABLE_AFTER_FILTER);\n        }\n    }\n\n    /**\n     * test when network exception\n     */\n    @Test\n    void testInvokerToException() {\n        String menu = \"first\";\n        List<String> menuItems = new ArrayList<String>() {\n            {\n                add(\"1\");\n                add(\"2\");\n            }\n        };\n\n        given(invocation.getMethodName()).willReturn(\"addMenu\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {String.class, List.class});\n        given(invocation.getArguments()).willReturn(new Object[] {menu, menuItems});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n        given(invocation.getInvoker()).willReturn(firstInvoker);\n\n        given(firstInvoker.getUrl()).willReturn(url.addParameter(GROUP_KEY, \"first\"));\n        given(firstInvoker.getInterface()).willReturn(MenuService.class);\n        given(firstInvoker.invoke(invocation)).willReturn(new AppResponse());\n        given(firstInvoker.isAvailable()).willReturn(true);\n        given(firstInvoker.invoke(invocation)).willThrow(new RpcException(RpcException.NETWORK_EXCEPTION));\n\n        given(secondInvoker.getUrl()).willReturn(url.addParameter(GROUP_KEY, \"second\"));\n        given(secondInvoker.getInterface()).willReturn(MenuService.class);\n        given(secondInvoker.invoke(invocation)).willReturn(new AppResponse());\n        given(secondInvoker.isAvailable()).willReturn(true);\n        given(secondInvoker.invoke(invocation)).willThrow(new RpcException(RpcException.NETWORK_EXCEPTION));\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n            }\n        });\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getInterface()).willReturn(MenuService.class);\n\n        mergeableClusterInvoker = new MergeableClusterInvoker<MenuService>(directory);\n\n        // invoke\n        try {\n            Result result = mergeableClusterInvoker.invoke(invocation);\n            fail();\n            Assertions.assertNull(result.getValue());\n        } catch (RpcException expected) {\n            assertEquals(expected.getCode(), RpcException.NETWORK_EXCEPTION);\n        }\n    }\n\n    @Test\n    void testGetMenuResultHasException() {\n\n        // setup\n        url = url.addParameter(MERGER_KEY, \".merge\");\n\n        given(invocation.getMethodName()).willReturn(\"getMenu\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {});\n        given(invocation.getArguments()).willReturn(new Object[] {});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n        given(invocation.getInvoker()).willReturn(firstInvoker);\n\n        given(firstInvoker.getUrl()).willReturn(url.addParameter(GROUP_KEY, \"first\"));\n        given(firstInvoker.getInterface()).willReturn(MenuService.class);\n        given(firstInvoker.invoke(invocation)).willReturn(new AppResponse());\n        given(firstInvoker.isAvailable()).willReturn(true);\n\n        given(secondInvoker.getUrl()).willReturn(url.addParameter(GROUP_KEY, \"second\"));\n        given(secondInvoker.getInterface()).willReturn(MenuService.class);\n        given(secondInvoker.invoke(invocation)).willReturn(new AppResponse());\n        given(secondInvoker.isAvailable()).willReturn(true);\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n            }\n        });\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getInterface()).willReturn(MenuService.class);\n\n        mergeableClusterInvoker = new MergeableClusterInvoker<MenuService>(directory);\n\n        // invoke\n        try {\n            Result result = mergeableClusterInvoker.invoke(invocation);\n            fail();\n            Assertions.assertNull(result.getValue());\n        } catch (RpcException expected) {\n            Assertions.assertTrue(expected.getMessage().contains(\"Failed to invoke service\"));\n        }\n    }\n\n    @Test\n    void testGetMenuWithMergerDefault() {\n\n        // setup\n        url = url.addParameter(MERGER_KEY, \"default\");\n\n        given(invocation.getMethodName()).willReturn(\"getMenu\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {});\n        given(invocation.getArguments()).willReturn(new Object[] {});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n        given(invocation.getInvoker()).willReturn(firstInvoker);\n        // mock ApplicationModel\n        given(invocation.getModuleModel()).willReturn(moduleModel);\n        given(invocation.getModuleModel().getApplicationModel()).willReturn(ApplicationModel.defaultModel());\n\n        firstInvoker = (Invoker) Proxy.newProxyInstance(\n                getClass().getClassLoader(), new Class<?>[] {Invoker.class}, (proxy, method, args) -> {\n                    if (\"getUrl\".equals(method.getName())) {\n                        return url.addParameter(GROUP_KEY, \"first\");\n                    }\n                    if (\"getInterface\".equals(method.getName())) {\n                        return MenuService.class;\n                    }\n                    if (\"invoke\".equals(method.getName())) {\n                        return AsyncRpcResult.newDefaultAsyncResult(firstMenu, invocation);\n                    }\n                    return null;\n                });\n\n        secondInvoker = (Invoker) Proxy.newProxyInstance(\n                getClass().getClassLoader(), new Class<?>[] {Invoker.class}, (proxy, method, args) -> {\n                    if (\"getUrl\".equals(method.getName())) {\n                        return url.addParameter(GROUP_KEY, \"second\");\n                    }\n                    if (\"getInterface\".equals(method.getName())) {\n                        return MenuService.class;\n                    }\n                    if (\"invoke\".equals(method.getName())) {\n                        return AsyncRpcResult.newDefaultAsyncResult(secondMenu, invocation);\n                    }\n                    return null;\n                });\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n            }\n        });\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getInterface()).willReturn(MenuService.class);\n\n        mergeableClusterInvoker = new MergeableClusterInvoker<MenuService>(directory);\n\n        // invoke\n        try {\n            mergeableClusterInvoker.invoke(invocation);\n        } catch (RpcException exception) {\n            Assertions.assertTrue(exception.getMessage().contains(\"There is no merger to merge result.\"));\n        }\n    }\n\n    @Test\n    void testDestroy() {\n        given(invocation.getMethodName()).willReturn(\"getMenu\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {});\n        given(invocation.getArguments()).willReturn(new Object[] {});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n        given(invocation.getInvoker()).willReturn(firstInvoker);\n\n        given(firstInvoker.getUrl()).willReturn(url.addParameter(GROUP_KEY, \"first\"));\n        given(firstInvoker.getInterface()).willReturn(MenuService.class);\n        given(firstInvoker.invoke(invocation)).willReturn(new AppResponse());\n\n        given(secondInvoker.getUrl()).willReturn(url.addParameter(GROUP_KEY, \"second\"));\n        given(secondInvoker.getInterface()).willReturn(MenuService.class);\n        given(secondInvoker.invoke(invocation)).willReturn(new AppResponse());\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n            }\n        });\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.getInterface()).willReturn(MenuService.class);\n\n        mergeableClusterInvoker = new MergeableClusterInvoker<MenuService>(directory);\n        mergeableClusterInvoker.destroy();\n\n        assertFalse(firstInvoker.isAvailable());\n        assertFalse(secondInvoker.isAvailable());\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/MockAbstractClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLE_CONNECTIVITY_VALIDATION;\nimport static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_AVAILABLE_CHECK_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.INVOCATION_NEED_MOCK;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * AbstractClusterInvokerTest\n */\n@SuppressWarnings(\"rawtypes\")\nclass MockAbstractClusterInvokerTest {\n    List<Invoker<IHelloService>> invokers = new ArrayList<Invoker<IHelloService>>();\n    List<Invoker<IHelloService>> selectedInvokers = new ArrayList<Invoker<IHelloService>>();\n    AbstractClusterInvoker<IHelloService> cluster;\n    AbstractClusterInvoker<IHelloService> cluster_nocheck;\n    StaticDirectory<IHelloService> dic;\n    RpcInvocation invocation = new RpcInvocation();\n    URL url = URL.valueOf(\n            \"registry://localhost:9090/org.apache.dubbo.rpc.cluster.support.AbstractClusterInvokerTest.IHelloService?refer=\"\n                    + URL.encode(\"application=abstractClusterInvokerTest\"));\n    URL consumerUrl = URL.valueOf(\n            \"dubbo://localhost?application=abstractClusterInvokerTest&refer=application%3DabstractClusterInvokerTest\");\n\n    Invoker<IHelloService> invoker1;\n    Invoker<IHelloService> invoker2;\n    Invoker<IHelloService> invoker3;\n    Invoker<IHelloService> invoker4;\n    Invoker<IHelloService> invoker5;\n    Invoker<IHelloService> mockedInvoker1;\n\n    @BeforeAll\n    public static void setUpBeforeClass() throws Exception {\n        System.setProperty(ENABLE_CONNECTIVITY_VALIDATION, \"false\");\n    }\n\n    @AfterEach\n    public void teardown() throws Exception {\n        RpcContext.removeContext();\n    }\n\n    @AfterAll\n    public static void afterClass() {\n        System.clearProperty(ENABLE_CONNECTIVITY_VALIDATION);\n    }\n\n    @SuppressWarnings({\"unchecked\"})\n    @BeforeEach\n    public void setUp() throws Exception {\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);\n        Map<String, Object> attributes = new HashMap<>();\n        attributes.put(\"application\", \"abstractClusterInvokerTest\");\n        url = url.putAttribute(REFER_KEY, attributes);\n\n        invocation.setMethodName(\"sayHello\");\n\n        invoker1 = mock(Invoker.class);\n        invoker2 = mock(Invoker.class);\n        invoker3 = mock(Invoker.class);\n        invoker4 = mock(Invoker.class);\n        invoker5 = mock(Invoker.class);\n        mockedInvoker1 = mock(Invoker.class);\n\n        URL turl = URL.valueOf(\"test://test:11/test\");\n\n        given(invoker1.isAvailable()).willReturn(false);\n        given(invoker1.getInterface()).willReturn(IHelloService.class);\n        given(invoker1.getUrl()).willReturn(turl.setPort(1).addParameter(\"name\", \"invoker1\"));\n\n        given(invoker2.isAvailable()).willReturn(true);\n        given(invoker2.getInterface()).willReturn(IHelloService.class);\n        given(invoker2.getUrl()).willReturn(turl.setPort(2).addParameter(\"name\", \"invoker2\"));\n\n        given(invoker3.isAvailable()).willReturn(false);\n        given(invoker3.getInterface()).willReturn(IHelloService.class);\n        given(invoker3.getUrl()).willReturn(turl.setPort(3).addParameter(\"name\", \"invoker3\"));\n\n        given(invoker4.isAvailable()).willReturn(true);\n        given(invoker4.getInterface()).willReturn(IHelloService.class);\n        given(invoker4.getUrl()).willReturn(turl.setPort(4).addParameter(\"name\", \"invoker4\"));\n\n        given(invoker5.isAvailable()).willReturn(false);\n        given(invoker5.getInterface()).willReturn(IHelloService.class);\n        given(invoker5.getUrl()).willReturn(turl.setPort(5).addParameter(\"name\", \"invoker5\"));\n\n        given(mockedInvoker1.isAvailable()).willReturn(false);\n        given(mockedInvoker1.getInterface()).willReturn(IHelloService.class);\n        given(mockedInvoker1.getUrl()).willReturn(turl.setPort(999).setProtocol(\"mock\"));\n\n        invokers.add(invoker1);\n        dic = new StaticDirectory<IHelloService>(url, invokers, null);\n        cluster = new AbstractClusterInvoker(dic) {\n            @Override\n            protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)\n                    throws RpcException {\n                return null;\n            }\n        };\n\n        cluster_nocheck =\n                new AbstractClusterInvoker(\n                        dic, url.addParameterIfAbsent(CLUSTER_AVAILABLE_CHECK_KEY, Boolean.FALSE.toString())) {\n                    @Override\n                    protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)\n                            throws RpcException {\n                        return null;\n                    }\n                };\n    }\n\n    private void initlistsize5() {\n        invokers.clear();\n        selectedInvokers\n                .clear(); // Clear first, previous test case will make sure that the right invoker2 will be used.\n        invokers.add(invoker1);\n        invokers.add(invoker2);\n        invokers.add(invoker3);\n        invokers.add(invoker4);\n        invokers.add(invoker5);\n    }\n\n    private void initDic() {\n        dic.notify(invokers);\n        dic.buildRouterChain();\n    }\n\n    /**\n     * Test mock invoker selector works as expected\n     */\n    @Test\n    void testMockedInvokerSelect() {\n        initlistsize5();\n        invokers.add(mockedInvoker1);\n\n        initDic();\n\n        RpcInvocation mockedInvocation = new RpcInvocation();\n        mockedInvocation.setMethodName(\"sayHello\");\n        mockedInvocation.setAttachment(INVOCATION_NEED_MOCK, \"true\");\n        List<Invoker<IHelloService>> mockedInvokers = dic.list(mockedInvocation);\n        Assertions.assertEquals(1, mockedInvokers.size());\n\n        List<Invoker<IHelloService>> invokers = dic.list(invocation);\n        Assertions.assertEquals(5, invokers.size());\n    }\n\n    public static interface IHelloService {}\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/MockInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.support.MockInvoker;\n\nimport java.io.Serializable;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.rpc.Constants.MOCK_KEY;\n\nclass MockInvokerTest {\n\n    @Test\n    void testParseMockValue() throws Exception {\n        Assertions.assertNull(MockInvoker.parseMockValue(\"null\"));\n        Assertions.assertNull(MockInvoker.parseMockValue(\"empty\"));\n\n        Assertions.assertTrue((Boolean) MockInvoker.parseMockValue(\"true\"));\n        Assertions.assertFalse((Boolean) MockInvoker.parseMockValue(\"false\"));\n\n        Assertions.assertEquals(123, MockInvoker.parseMockValue(\"123\"));\n        Assertions.assertEquals(\"foo\", MockInvoker.parseMockValue(\"foo\"));\n        Assertions.assertEquals(\"foo\", MockInvoker.parseMockValue(\"\\\"foo\\\"\"));\n        Assertions.assertEquals(\"foo\", MockInvoker.parseMockValue(\"\\'foo\\'\"));\n\n        Assertions.assertEquals(new HashMap<>(), MockInvoker.parseMockValue(\"{}\"));\n        Assertions.assertEquals(new ArrayList<>(), MockInvoker.parseMockValue(\"[]\"));\n        Assertions.assertEquals(\"foo\", MockInvoker.parseMockValue(\"foo\", new Type[] {String.class}));\n    }\n\n    @Test\n    void testInvoke() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + String.class.getName());\n        url = url.addParameter(MOCK_KEY, \"return \");\n        MockInvoker mockInvoker = new MockInvoker(url, String.class);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Assertions.assertEquals(new HashMap<>(), mockInvoker.invoke(invocation).getObjectAttachments());\n    }\n\n    @Test\n    void testGetDefaultObject() {\n        // test methodA in DemoServiceAMock\n        final Class<DemoServiceA> demoServiceAClass = DemoServiceA.class;\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + demoServiceAClass.getName());\n        url = url.addParameter(MOCK_KEY, \"force:true\");\n        MockInvoker mockInvoker = new MockInvoker(url, demoServiceAClass);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"methodA\");\n        Assertions.assertEquals(new HashMap<>(), mockInvoker.invoke(invocation).getObjectAttachments());\n\n        // test methodB in DemoServiceBMock\n        final Class<DemoServiceB> demoServiceBClass = DemoServiceB.class;\n        url = URL.valueOf(\"remote://1.2.3.4/\" + demoServiceBClass.getName());\n        url = url.addParameter(MOCK_KEY, \"force:true\");\n        mockInvoker = new MockInvoker(url, demoServiceBClass);\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"methodB\");\n        Assertions.assertEquals(new HashMap<>(), mockInvoker.invoke(invocation).getObjectAttachments());\n    }\n\n    @Test\n    void testInvokeThrowsRpcException1() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + String.class.getName());\n        MockInvoker mockInvoker = new MockInvoker(url, null);\n\n        Assertions.assertThrows(RpcException.class, () -> mockInvoker.invoke(new RpcInvocation()));\n    }\n\n    @Test\n    void testInvokeThrowsRpcException2() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + String.class.getName());\n        url = url.addParameter(MOCK_KEY, \"fail\");\n        MockInvoker mockInvoker = new MockInvoker(url, String.class);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Assertions.assertThrows(RpcException.class, () -> mockInvoker.invoke(invocation));\n    }\n\n    @Test\n    void testInvokeThrowsRpcException3() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + String.class.getName());\n        url = url.addParameter(MOCK_KEY, \"throw\");\n        MockInvoker mockInvoker = new MockInvoker(url, String.class);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Assertions.assertThrows(RpcException.class, () -> mockInvoker.invoke(invocation));\n    }\n\n    @Test\n    void testGetThrowable() {\n        Assertions.assertThrows(\n                RpcException.class, () -> org.apache.dubbo.rpc.support.MockInvoker.getThrowable(\"Exception.class\"));\n    }\n\n    @Test\n    void testGetMockObject() {\n        Assertions.assertEquals(\n                \"\",\n                MockInvoker.getMockObject(\n                        ApplicationModel.defaultModel().getExtensionDirector(), \"java.lang.String\", String.class));\n\n        Assertions.assertThrows(\n                IllegalStateException.class,\n                () -> MockInvoker.getMockObject(\n                        ApplicationModel.defaultModel().getExtensionDirector(), \"true\", String.class));\n        Assertions.assertThrows(\n                IllegalStateException.class,\n                () -> MockInvoker.getMockObject(\n                        ApplicationModel.defaultModel().getExtensionDirector(), \"default\", String.class));\n        Assertions.assertThrows(\n                IllegalStateException.class,\n                () -> MockInvoker.getMockObject(\n                        ApplicationModel.defaultModel().getExtensionDirector(), \"java.lang.String\", Integer.class));\n        Assertions.assertThrows(\n                IllegalStateException.class,\n                () -> MockInvoker.getMockObject(\n                        ApplicationModel.defaultModel().getExtensionDirector(),\n                        \"java.io.Serializable\",\n                        Serializable.class));\n    }\n\n    @Test\n    void testNormalizeMock() {\n        Assertions.assertNull(MockInvoker.normalizeMock(null));\n\n        Assertions.assertEquals(\"\", MockInvoker.normalizeMock(\"\"));\n        Assertions.assertEquals(\"\", MockInvoker.normalizeMock(\"fail:\"));\n        Assertions.assertEquals(\"\", MockInvoker.normalizeMock(\"force:\"));\n        Assertions.assertEquals(\"throw\", MockInvoker.normalizeMock(\"throw\"));\n        Assertions.assertEquals(\"default\", MockInvoker.normalizeMock(\"fail\"));\n        Assertions.assertEquals(\"default\", MockInvoker.normalizeMock(\"force\"));\n        Assertions.assertEquals(\"default\", MockInvoker.normalizeMock(\"true\"));\n        Assertions.assertEquals(\"default\", MockInvoker.normalizeMock(\"default\"));\n        Assertions.assertEquals(\"return null\", MockInvoker.normalizeMock(\"return\"));\n        Assertions.assertEquals(\"return null\", MockInvoker.normalizeMock(\"return null\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/TagProviderURLMergeProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor;\n\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;\n\npublic class TagProviderURLMergeProcessor implements ProviderURLMergeProcessor {\n\n    @Override\n    public URL mergeUrl(URL remoteUrl, Map<String, String> localParametersMap) {\n        String tag = localParametersMap.get(TAG_KEY);\n        remoteUrl = remoteUrl.removeParameter(TAG_KEY);\n        remoteUrl = remoteUrl.addParameter(TAG_KEY, tag);\n        return remoteUrl;\n    }\n\n    @Override\n    public Map<String, String> mergeLocalParams(Map<String, String> localMap) {\n        localMap.remove(TAG_KEY);\n        return ProviderURLMergeProcessor.super.mergeLocalParams(localMap);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/merger/DefaultProviderURLMergeProcessorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.merger;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\n\nclass DefaultProviderURLMergeProcessorTest {\n\n    private ProviderURLMergeProcessor providerURLMergeProcessor;\n\n    @BeforeEach\n    public void setup() {\n        providerURLMergeProcessor = new DefaultProviderURLMergeProcessor();\n    }\n\n    @Test\n    void testMergeUrl() {\n        URL providerURL = URL.valueOf(\"dubbo://localhost:55555\");\n        providerURL = providerURL.setPath(\"path\").setUsername(\"username\").setPassword(\"password\");\n\n        providerURL = URLBuilder.from(providerURL)\n                .addParameter(GROUP_KEY, \"dubbo\")\n                .addParameter(VERSION_KEY, \"1.2.3\")\n                .addParameter(DUBBO_VERSION_KEY, \"2.3.7\")\n                .addParameter(THREADPOOL_KEY, \"fixed\")\n                .addParameter(THREADS_KEY, Integer.MAX_VALUE)\n                .addParameter(THREAD_NAME_KEY, \"test\")\n                .addParameter(CORE_THREADS_KEY, Integer.MAX_VALUE)\n                .addParameter(QUEUES_KEY, Integer.MAX_VALUE)\n                .addParameter(ALIVE_KEY, Integer.MAX_VALUE)\n                .addParameter(DEFAULT_KEY_PREFIX + THREADS_KEY, Integer.MAX_VALUE)\n                .addParameter(DEFAULT_KEY_PREFIX + THREADPOOL_KEY, \"fixed\")\n                .addParameter(DEFAULT_KEY_PREFIX + CORE_THREADS_KEY, Integer.MAX_VALUE)\n                .addParameter(DEFAULT_KEY_PREFIX + QUEUES_KEY, Integer.MAX_VALUE)\n                .addParameter(DEFAULT_KEY_PREFIX + ALIVE_KEY, Integer.MAX_VALUE)\n                .addParameter(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY, \"test\")\n                .addParameter(APPLICATION_KEY, \"provider\")\n                .addParameter(REFERENCE_FILTER_KEY, \"filter1,filter2\")\n                .addParameter(TAG_KEY, \"TTT\")\n                .build();\n\n        URL consumerURL = new URLBuilder(DUBBO_PROTOCOL, \"localhost\", 55555)\n                .addParameter(PID_KEY, \"1234\")\n                .addParameter(THREADPOOL_KEY, \"foo\")\n                .addParameter(APPLICATION_KEY, \"consumer\")\n                .addParameter(REFERENCE_FILTER_KEY, \"filter3\")\n                .addParameter(TAG_KEY, \"UUU\")\n                .build();\n\n        URL url = providerURLMergeProcessor.mergeUrl(providerURL, consumerURL.getParameters());\n\n        Assertions.assertFalse(url.hasParameter(THREADS_KEY));\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + THREADS_KEY));\n\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + THREADPOOL_KEY));\n\n        Assertions.assertFalse(url.hasParameter(CORE_THREADS_KEY));\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + CORE_THREADS_KEY));\n\n        Assertions.assertFalse(url.hasParameter(QUEUES_KEY));\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + QUEUES_KEY));\n\n        Assertions.assertFalse(url.hasParameter(ALIVE_KEY));\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + ALIVE_KEY));\n\n        Assertions.assertFalse(url.hasParameter(THREAD_NAME_KEY));\n        Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY));\n\n        Assertions.assertEquals(\"path\", url.getPath());\n        Assertions.assertEquals(\"username\", url.getUsername());\n        Assertions.assertEquals(\"password\", url.getPassword());\n        Assertions.assertEquals(\"1234\", url.getParameter(PID_KEY));\n        Assertions.assertEquals(\"foo\", url.getParameter(THREADPOOL_KEY));\n        Assertions.assertEquals(\"consumer\", url.getApplication());\n        Assertions.assertEquals(\"provider\", url.getRemoteApplication());\n        Assertions.assertEquals(\"filter1,filter2,filter3\", url.getParameter(REFERENCE_FILTER_KEY));\n\n        Assertions.assertEquals(\"TTT\", url.getParameter(TAG_KEY));\n    }\n\n    @Test\n    void testUseProviderParams() {\n        // present in both local and remote, but uses remote value.\n        URL localURL =\n                URL.valueOf(\"dubbo://localhost:20880/DemoService?version=local&group=local&dubbo=local&release=local\"\n                        + \"&methods=local&tag=local&timestamp=local\");\n        URL remoteURL = URL.valueOf(\n                \"dubbo://localhost:20880/DemoService?version=remote&group=remote&dubbo=remote&release=remote\"\n                        + \"&methods=remote&tag=remote&timestamp=remote\");\n        URL mergedUrl = providerURLMergeProcessor.mergeUrl(remoteURL, localURL.getParameters());\n\n        Assertions.assertEquals(remoteURL.getVersion(), mergedUrl.getVersion());\n        Assertions.assertEquals(remoteURL.getGroup(), mergedUrl.getGroup());\n        Assertions.assertEquals(remoteURL.getParameter(DUBBO_VERSION_KEY), mergedUrl.getParameter(DUBBO_VERSION_KEY));\n        Assertions.assertEquals(remoteURL.getParameter(RELEASE_KEY), mergedUrl.getParameter(RELEASE_KEY));\n        Assertions.assertEquals(remoteURL.getParameter(METHODS_KEY), mergedUrl.getParameter(METHODS_KEY));\n        Assertions.assertEquals(remoteURL.getParameter(TIMESTAMP_KEY), mergedUrl.getParameter(TIMESTAMP_KEY));\n        Assertions.assertEquals(remoteURL.getParameter(TAG_KEY), mergedUrl.getParameter(TAG_KEY));\n\n        // present in local url but not in remote url, parameters of remote url is empty\n        localURL = URL.valueOf(\"dubbo://localhost:20880/DemoService?version=local&group=local&dubbo=local&release=local\"\n                + \"&methods=local&tag=local&timestamp=local\");\n        remoteURL = URL.valueOf(\"dubbo://localhost:20880/DemoService\");\n        mergedUrl = providerURLMergeProcessor.mergeUrl(remoteURL, localURL.getParameters());\n\n        Assertions.assertEquals(localURL.getVersion(), mergedUrl.getVersion());\n        Assertions.assertEquals(localURL.getGroup(), mergedUrl.getGroup());\n        Assertions.assertNull(mergedUrl.getParameter(DUBBO_VERSION_KEY));\n        Assertions.assertNull(mergedUrl.getParameter(RELEASE_KEY));\n        Assertions.assertNull(mergedUrl.getParameter(METHODS_KEY));\n        Assertions.assertNull(mergedUrl.getParameter(TIMESTAMP_KEY));\n        Assertions.assertNull(mergedUrl.getParameter(TAG_KEY));\n\n        // present in local url but not in remote url\n        localURL = URL.valueOf(\"dubbo://localhost:20880/DemoService?version=local&group=local&dubbo=local&release=local\"\n                + \"&methods=local&tag=local&timestamp=local\");\n        remoteURL = URL.valueOf(\"dubbo://localhost:20880/DemoService?key=value\");\n        mergedUrl = providerURLMergeProcessor.mergeUrl(remoteURL, localURL.getParameters());\n\n        Assertions.assertEquals(localURL.getVersion(), mergedUrl.getVersion());\n        Assertions.assertEquals(localURL.getGroup(), mergedUrl.getGroup());\n        Assertions.assertNull(mergedUrl.getParameter(DUBBO_VERSION_KEY));\n        Assertions.assertNull(mergedUrl.getParameter(RELEASE_KEY));\n        Assertions.assertNull(mergedUrl.getParameter(METHODS_KEY));\n        Assertions.assertNull(mergedUrl.getParameter(TIMESTAMP_KEY));\n        Assertions.assertNull(mergedUrl.getParameter(TAG_KEY));\n\n        // present in both local and remote, uses local url params\n        localURL = URL.valueOf(\"dubbo://localhost:20880/DemoService?loadbalance=local&timeout=1000&cluster=local\");\n        remoteURL = URL.valueOf(\"dubbo://localhost:20880/DemoService?loadbalance=remote&timeout=2000&cluster=remote\");\n        mergedUrl = providerURLMergeProcessor.mergeUrl(remoteURL, localURL.getParameters());\n\n        Assertions.assertEquals(localURL.getParameter(CLUSTER_KEY), mergedUrl.getParameter(CLUSTER_KEY));\n        Assertions.assertEquals(localURL.getParameter(TIMEOUT_KEY), mergedUrl.getParameter(TIMEOUT_KEY));\n        Assertions.assertEquals(localURL.getParameter(LOADBALANCE_KEY), mergedUrl.getParameter(LOADBALANCE_KEY));\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\nimport java.lang.reflect.Proxy;\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PREFERRED_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE_FORCE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ZONE_KEY;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\nclass ZoneAwareClusterInvokerTest {\n\n    private Directory directory = mock(Directory.class);\n    private ClusterInvoker firstInvoker = mock(ClusterInvoker.class);\n    private ClusterInvoker secondInvoker = mock(ClusterInvoker.class);\n    private ClusterInvoker thirdInvoker = mock(ClusterInvoker.class);\n    private Invocation invocation = mock(Invocation.class);\n\n    private ZoneAwareClusterInvoker<ZoneAwareClusterInvokerTest> zoneAwareClusterInvoker;\n\n    private URL url = URL.valueOf(\"test://test\");\n    private URL registryUrl = URL.valueOf(\"localhost://test\");\n\n    String expectedValue = \"expected\";\n    String unexpectedValue = \"unexpected\";\n\n    @Test\n    void testPreferredStrategy() {\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {});\n        given(invocation.getArguments()).willReturn(new Object[] {});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n\n        firstInvoker = newUnexpectedInvoker();\n        thirdInvoker = newUnexpectedInvoker();\n\n        secondInvoker = (ClusterInvoker) Proxy.newProxyInstance(\n                getClass().getClassLoader(), new Class<?>[] {ClusterInvoker.class}, (proxy, method, args) -> {\n                    if (\"getUrl\".equals(method.getName())) {\n                        return url;\n                    }\n                    if (\"getRegistryUrl\".equals(method.getName())) {\n                        return registryUrl.addParameter(PREFERRED_KEY, true);\n                    }\n                    if (\"isAvailable\".equals(method.getName())) {\n                        return true;\n                    }\n                    if (\"invoke\".equals(method.getName())) {\n                        return new AppResponse(expectedValue);\n                    }\n                    return null;\n                });\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n                add(thirdInvoker);\n            }\n        });\n\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n\n        zoneAwareClusterInvoker = new ZoneAwareClusterInvoker<>(directory);\n        AppResponse response = (AppResponse) zoneAwareClusterInvoker.invoke(invocation);\n        Assertions.assertEquals(expectedValue, response.getValue());\n    }\n\n    @Test\n    void testRegistryZoneStrategy() {\n        String zoneKey = \"zone\";\n\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {});\n        given(invocation.getArguments()).willReturn(new Object[] {});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n        RpcContext.getClientAttachment().setAttachment(REGISTRY_ZONE, zoneKey);\n\n        firstInvoker = newUnexpectedInvoker();\n        thirdInvoker = newUnexpectedInvoker();\n\n        secondInvoker = (ClusterInvoker) Proxy.newProxyInstance(\n                getClass().getClassLoader(), new Class<?>[] {ClusterInvoker.class}, (proxy, method, args) -> {\n                    if (\"getUrl\".equals(method.getName())) {\n                        return url;\n                    }\n                    if (\"getRegistryUrl\".equals(method.getName())) {\n                        return registryUrl.addParameter(ZONE_KEY, zoneKey);\n                    }\n                    if (\"isAvailable\".equals(method.getName())) {\n                        return true;\n                    }\n                    if (\"invoke\".equals(method.getName())) {\n                        return new AppResponse(expectedValue);\n                    }\n                    return null;\n                });\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n                add(thirdInvoker);\n            }\n        });\n\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n\n        zoneAwareClusterInvoker = new ZoneAwareClusterInvoker<>(directory);\n        AppResponse response = (AppResponse) zoneAwareClusterInvoker.invoke(invocation);\n        Assertions.assertEquals(expectedValue, response.getValue());\n    }\n\n    @Test\n    void testRegistryZoneForceStrategy() {\n        String zoneKey = \"zone\";\n\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {});\n        given(invocation.getArguments()).willReturn(new Object[] {});\n        given(invocation.getObjectAttachments()).willReturn(new HashMap<>());\n        RpcContext.getClientAttachment().setAttachment(REGISTRY_ZONE, zoneKey);\n        RpcContext.getClientAttachment().setAttachment(REGISTRY_ZONE_FORCE, \"true\");\n\n        firstInvoker = newUnexpectedInvoker();\n        secondInvoker = newUnexpectedInvoker();\n        thirdInvoker = newUnexpectedInvoker();\n\n        given(directory.list(invocation)).willReturn(new ArrayList() {\n            {\n                add(firstInvoker);\n                add(secondInvoker);\n                add(thirdInvoker);\n            }\n        });\n\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n\n        zoneAwareClusterInvoker = new ZoneAwareClusterInvoker<>(directory);\n        Assertions.assertThrows(IllegalStateException.class, () -> zoneAwareClusterInvoker.invoke(invocation));\n    }\n\n    @Test\n    public void testNoAvailableInvoker() {\n        given(directory.getUrl()).willReturn(url);\n        given(directory.getConsumerUrl()).willReturn(url);\n        given(directory.list(invocation)).willReturn(new ArrayList<>(0));\n        given(directory.getInterface()).willReturn(ZoneAwareClusterInvokerTest.class);\n\n        zoneAwareClusterInvoker = new ZoneAwareClusterInvoker<>(directory);\n\n        Assertions.assertThrows(RpcException.class, () -> zoneAwareClusterInvoker.invoke(invocation));\n    }\n\n    private ClusterInvoker newUnexpectedInvoker() {\n        return (ClusterInvoker) Proxy.newProxyInstance(\n                getClass().getClassLoader(), new Class<?>[] {ClusterInvoker.class}, (proxy, method, args) -> {\n                    if (\"getUrl\".equals(method.getName())) {\n                        return url;\n                    }\n                    if (\"getRegistryUrl\".equals(method.getName())) {\n                        return registryUrl;\n                    }\n                    if (\"isAvailable\".equals(method.getName())) {\n                        return true;\n                    }\n                    if (\"invoke\".equals(method.getName())) {\n                        return new AppResponse(unexpectedValue);\n                    }\n                    return null;\n                });\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/AbstractClusterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.filter.DemoService;\nimport org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;\nimport org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass AbstractClusterTest {\n\n    @Test\n    void testBuildClusterInvokerChain() {\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(REFERENCE_FILTER_KEY, \"demo\");\n        ServiceConfigURL url = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        URL consumerUrl = new ServiceConfigURL(\"dubbo\", \"127.0.0.1\", 20881, DemoService.class.getName(), parameters);\n        consumerUrl = consumerUrl.setScopeModel(ApplicationModel.defaultModel().getInternalModule());\n        Directory<?> directory = mock(Directory.class);\n        when(directory.getUrl()).thenReturn(url);\n        when(directory.getConsumerUrl()).thenReturn(consumerUrl);\n        DemoCluster demoCluster = new DemoCluster();\n        Invoker<?> invoker = demoCluster.join(directory, true);\n        Assertions.assertTrue(invoker instanceof AbstractCluster.ClusterFilterInvoker);\n        Assertions.assertTrue(\n                ((AbstractCluster.ClusterFilterInvoker<?>) invoker).getFilterInvoker()\n                        instanceof FilterChainBuilder.ClusterCallbackRegistrationInvoker);\n    }\n\n    static class DemoCluster extends AbstractCluster {\n        @Override\n        public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {\n            return super.join(directory, buildFilterChain);\n        }\n\n        @Override\n        protected <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {\n            return new DemoAbstractClusterInvoker<>(directory, directory.getUrl());\n        }\n    }\n\n    static class DemoAbstractClusterInvoker<T> extends AbstractClusterInvoker<T> {\n\n        @Override\n        public URL getUrl() {\n            return super.getUrl();\n        }\n\n        public DemoAbstractClusterInvoker(Directory<T> directory, URL url) {\n            super(directory, url);\n        }\n\n        @Override\n        protected Result doInvoke(Invocation invocation, List list, LoadBalance loadbalance) throws RpcException {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/DemoClusterFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\n\n@Activate(\n        value = \"demo\",\n        group = {CONSUMER})\npublic class DemoClusterFilter implements ClusterFilter {\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        return invoker.invoke(invocation);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.support.MockProtocol;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\n\nclass MockClusterInvokerTest {\n    private static final Logger logger = LoggerFactory.getLogger(MockClusterInvokerTest.class);\n\n    List<Invoker<IHelloService>> invokers = new ArrayList<Invoker<IHelloService>>();\n\n    @BeforeEach\n    public void beforeMethod() {\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);\n        invokers.clear();\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerInvoke_normal() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName());\n        url = url.addParameter(\n                REFER_KEY, URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"mock=fail\"));\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        URL mockUrl = URL.valueOf(\"mock://localhost/\" + IHelloService.class.getName() + \"?getSomething.mock=return aa\");\n\n        Protocol protocol = new MockProtocol();\n        Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);\n        invokers.add(mInvoker1);\n\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"something\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertNull(ret.getValue());\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerInvoke_failmock() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"mock=fail:return null\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        URL mockUrl = URL.valueOf(\"mock://localhost/\" + IHelloService.class.getName())\n                .addParameter(\"mock\", \"fail:return null\")\n                .addParameter(\"getSomething.mock\", \"return aa\")\n                .addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName()))\n                .addParameter(\"invoke_return_error\", \"true\");\n\n        Protocol protocol = new MockProtocol();\n        Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);\n        Invoker<IHelloService> cluster = getClusterInvokerMock(url, mInvoker1);\n\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"aa\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething2\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertNull(ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertNull(ret.getValue());\n    }\n\n    /**\n     * Test if mock policy works fine: force-mock\n     */\n    @Test\n    void testMockInvokerInvoke_forcemock() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"mock=force:return null\"));\n\n        URL mockUrl = URL.valueOf(\"mock://localhost/\" + IHelloService.class.getName())\n                .addParameter(\"mock\", \"force:return null\")\n                .addParameter(\"getSomething.mock\", \"return aa\")\n                .addParameter(\"getSomething3xx.mock\", \"return xx\")\n                .addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName()));\n\n        Protocol protocol = new MockProtocol();\n        Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);\n        Invoker<IHelloService> cluster = getClusterInvokerMock(url, mInvoker1);\n\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"aa\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething2\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertNull(ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertNull(ret.getValue());\n    }\n\n    @Test\n    void testMockInvokerInvoke_forcemock_defaultreturn() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY, URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"mock=force\"));\n\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        URL mockUrl = URL.valueOf(\"mock://localhost/\" + IHelloService.class.getName()\n                        + \"?getSomething.mock=return aa&getSomething3xx.mock=return xx&sayHello.mock=return \")\n                .addParameters(url.getParameters());\n\n        Protocol protocol = new MockProtocol();\n        Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);\n        invokers.add(mInvoker1);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertNull(ret.getValue());\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerFromOverride_Invoke_Fock_someMethods() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName()\n                                + \"&\" + \"getSomething.mock=fail:return x\"\n                                + \"&\" + \"getSomething2.mock=force:return y\"));\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"something\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething2\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"y\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething3\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"something3\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertNull(ret.getValue());\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerFromOverride_Invoke_Fock_WithOutDefault() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName()\n                                + \"&\" + \"getSomething.mock=fail:return x\"\n                                + \"&\" + \"getSomething2.mock=fail:return y\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"x\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething2\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"y\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething3\");\n        try {\n            ret = cluster.invoke(invocation);\n            Assertions.fail();\n        } catch (RpcException e) {\n\n        }\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerFromOverride_Invoke_Fock_WithDefault() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName()\n                                + \"&\" + \"mock\" + \"=\" + \"fail:return null\"\n                                + \"&\" + \"getSomething.mock\" + \"=\" + \"fail:return x\"\n                                + \"&\" + \"getSomething2.mock\" + \"=\" + \"fail:return y\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"x\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething2\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"y\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething3\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertNull(ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertNull(ret.getValue());\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerFromOverride_Invoke_Fock_WithFailDefault() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName()\n                                + \"&\" + \"mock=fail:return z\"\n                                + \"&\" + \"getSomething.mock=fail:return x\"\n                                + \"&\" + \"getSomething2.mock=force:return y\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"x\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething2\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"y\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething3\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"z\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"z\", ret.getValue());\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerFromOverride_Invoke_Fock_WithForceDefault() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName()\n                                + \"&\" + \"mock=force:return z\"\n                                + \"&\" + \"getSomething.mock=fail:return x\"\n                                + \"&\" + \"getSomething2.mock=force:return y\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"x\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething2\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"y\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething3\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"z\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"z\", ret.getValue());\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerFromOverride_Invoke_Fock_Default() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"mock=fail:return x\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"x\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething2\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"x\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"sayHello\");\n        ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"x\", ret.getValue());\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerFromOverride_Invoke_checkCompatible_return() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"getSomething.mock=return x\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"x\", ret.getValue());\n\n        // If no mock was configured, return null directly\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething3\");\n        try {\n            ret = cluster.invoke(invocation);\n            Assertions.fail(\"fail invoke\");\n        } catch (RpcException e) {\n\n        }\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerFromOverride_Invoke_checkCompatible_ImplMock() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(\n                                PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"mock=true\" + \"&\" + \"proxy=jdk\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"somethingmock\", ret.getValue());\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerFromOverride_Invoke_checkCompatible_ImplMock2() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"mock=fail\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"somethingmock\", ret.getValue());\n    }\n\n    /**\n     * Test if mock policy works fine: fail-mock\n     */\n    @Test\n    void testMockInvokerFromOverride_Invoke_checkCompatible_ImplMock3() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY, URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"mock=force\"));\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"somethingmock\", ret.getValue());\n    }\n\n    @Test\n    void testMockInvokerFromOverride_Invoke_check_String() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\"getSomething.mock\", \"force:return 1688\")\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                + \"getSomething.mock=force:return 1688\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertTrue(\n                ret.getValue() instanceof String,\n                \"result type must be String but was : \" + ret.getValue().getClass());\n        Assertions.assertEquals(\"1688\", ret.getValue());\n    }\n\n    @Test\n    void testMockInvokerFromOverride_Invoke_check_int() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                + \"getInt1.mock=force:return 1688\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getInt1\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertTrue(\n                ret.getValue() instanceof Integer,\n                \"result type must be integer but was : \" + ret.getValue().getClass());\n        Assertions.assertEquals(new Integer(1688), (Integer) ret.getValue());\n    }\n\n    @Test\n    void testMockInvokerFromOverride_Invoke_check_boolean() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                + \"getBoolean1.mock=force:return true\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getBoolean1\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertTrue(\n                ret.getValue() instanceof Boolean,\n                \"result type must be Boolean but was : \" + ret.getValue().getClass());\n        Assertions.assertTrue(Boolean.parseBoolean(ret.getValue().toString()));\n    }\n\n    @Test\n    void testMockInvokerFromOverride_Invoke_check_Boolean() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                + \"getBoolean2.mock=force:return true\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getBoolean2\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertTrue(Boolean.parseBoolean(ret.getValue().toString()));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void testMockInvokerFromOverride_Invoke_check_ListString_empty() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                + \"getListString.mock=force:return empty\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getListString\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(0, ((List<String>) ret.getValue()).size());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void testMockInvokerFromOverride_Invoke_check_ListString() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                + \"getListString.mock=force:return [\\\"hi\\\",\\\"hi2\\\"]\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getListString\");\n        Result ret = cluster.invoke(invocation);\n        List<String> rl = (List<String>) ret.getValue();\n        Assertions.assertEquals(2, rl.size());\n        Assertions.assertEquals(\"hi\", rl.get(0));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void testMockInvokerFromOverride_Invoke_check_ListPojo_empty() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                + \"getUsers.mock=force:return empty\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getUsers\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(0, ((List<User>) ret.getValue()).size());\n    }\n\n    @Test\n    void testMockInvokerFromOverride_Invoke_check_ListPojoAsync() throws ExecutionException, InterruptedException {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"getUsersAsync.mock=force\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getUsersAsync\");\n        invocation.setReturnType(CompletableFuture.class);\n        Result ret = cluster.invoke(invocation);\n        CompletableFuture<List<User>> cf = null;\n        try {\n            cf = (CompletableFuture<List<User>>) ret.recreate();\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        Assertions.assertEquals(2, cf.get().size());\n        Assertions.assertEquals(\"Tommock\", cf.get().get(0).getName());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void testMockInvokerFromOverride_Invoke_check_ListPojo() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                + \"getUsers.mock=force:return [{id:1, name:\\\"hi1\\\"}, {id:2, name:\\\"hi2\\\"}]\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getUsers\");\n        Result ret = cluster.invoke(invocation);\n        List<User> rl = (List<User>) ret.getValue();\n        Assertions.assertEquals(2, rl.size());\n        Assertions.assertEquals(\"hi1\", rl.get(0).getName());\n    }\n\n    @Test\n    void testMockInvokerFromOverride_Invoke_check_ListPojo_error() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                + \"getUsers.mock=force:return [{id:x, name:\\\"hi1\\\"}]\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getUsers\");\n        try {\n            cluster.invoke(invocation);\n        } catch (RpcException e) {\n        }\n    }\n\n    @Test\n    void testMockInvokerFromOverride_Invoke_force_throw() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(\n                                PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"getBoolean2.mock=force:throw \"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getBoolean2\");\n        try {\n            cluster.invoke(invocation);\n            Assertions.fail();\n        } catch (RpcException e) {\n            Assertions.assertFalse(e.isBiz(), \"not custom exception\");\n        }\n    }\n\n    @Test\n    void testMockInvokerFromOverride_Invoke_force_throwCustemException() throws Throwable {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(\n                                PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                        + \"getBoolean2.mock=force:throw org.apache.dubbo.rpc.cluster.support.wrapper.MyMockException\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getBoolean2\");\n        try {\n            cluster.invoke(invocation).recreate();\n            Assertions.fail();\n        } catch (MyMockException e) {\n\n        }\n    }\n\n    @Test\n    void testMockInvokerFromOverride_Invoke_force_throwCustemExceptionNotFound() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\"\n                                + \"getBoolean2.mock=force:throw java.lang.RuntimeException2\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getBoolean2\");\n        try {\n            cluster.invoke(invocation);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e.getCause() instanceof IllegalStateException);\n        }\n    }\n\n    @Test\n    void testMockInvokerFromOverride_Invoke_mock_false() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloService.class.getName())\n                .addParameter(\n                        REFER_KEY, URL.encode(PATH_KEY + \"=\" + IHelloService.class.getName() + \"&\" + \"mock=false\"))\n                .addParameter(\"invoke_return_error\", \"true\");\n        Invoker<IHelloService> cluster = getClusterInvoker(url);\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getBoolean2\");\n        try {\n            cluster.invoke(invocation);\n            Assertions.fail();\n        } catch (RpcException e) {\n            Assertions.assertTrue(e.isTimeout());\n        }\n    }\n\n    private Invoker<IHelloService> getClusterInvokerMock(URL url, Invoker<IHelloService> mockInvoker) {\n        // As `javassist` have a strict restriction of argument types, request will fail if Invocation do not contains\n        // complete parameter type information\n        final URL durl = url.addParameter(\"proxy\", \"jdk\");\n        invokers.clear();\n        ProxyFactory proxy =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(\"jdk\");\n        Invoker<IHelloService> invoker1 = proxy.getInvoker(new HelloService(), IHelloService.class, durl);\n        invokers.add(invoker1);\n        if (mockInvoker != null) {\n            invokers.add(mockInvoker);\n        }\n\n        StaticDirectory<IHelloService> dic = new StaticDirectory<IHelloService>(durl, invokers, null);\n        dic.buildRouterChain();\n        AbstractClusterInvoker<IHelloService> cluster = new AbstractClusterInvoker(dic) {\n            @Override\n            protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)\n                    throws RpcException {\n                if (durl.getParameter(\"invoke_return_error\", false)) {\n                    throw new RpcException(RpcException.TIMEOUT_EXCEPTION, \"test rpc exception\");\n                } else {\n                    return ((Invoker<?>) invokers.get(0)).invoke(invocation);\n                }\n            }\n        };\n        return new MockClusterInvoker<IHelloService>(dic, cluster);\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private Invoker<IHelloService> getClusterInvoker(URL url) {\n        return getClusterInvokerMock(url, null);\n    }\n\n    public interface IHelloService {\n        String getSomething();\n\n        String getSomething2();\n\n        String getSomething3();\n\n        String getSomething4();\n\n        int getInt1();\n\n        boolean getBoolean1();\n\n        Boolean getBoolean2();\n\n        List<String> getListString();\n\n        List<User> getUsers();\n\n        CompletableFuture<List<User>> getUsersAsync();\n\n        void sayHello();\n    }\n\n    public static class HelloService implements IHelloService {\n        public String getSomething() {\n            return \"something\";\n        }\n\n        public String getSomething2() {\n            return \"something2\";\n        }\n\n        public String getSomething3() {\n            return \"something3\";\n        }\n\n        public String getSomething4() {\n            throw new RpcException(\"getSomething4|RpcException\");\n        }\n\n        public int getInt1() {\n            return 1;\n        }\n\n        public boolean getBoolean1() {\n            return false;\n        }\n\n        public Boolean getBoolean2() {\n            return Boolean.FALSE;\n        }\n\n        public List<String> getListString() {\n            return Arrays.asList(new String[] {\"Tom\", \"Jerry\"});\n        }\n\n        public List<User> getUsers() {\n            return Arrays.asList(new User[] {new User(1, \"Tom\"), new User(2, \"Jerry\")});\n        }\n\n        @Override\n        public CompletableFuture<List<User>> getUsersAsync() {\n            CompletableFuture<List<User>> cf = new CompletableFuture<>();\n            cf.complete(Arrays.asList(new User[] {new User(1, \"Tom\"), new User(2, \"Jerry\")}));\n            return cf;\n        }\n\n        public void sayHello() {\n            logger.info(\"hello prety\");\n        }\n    }\n\n    public static class IHelloServiceMock implements IHelloService {\n        public IHelloServiceMock() {}\n\n        public String getSomething() {\n            return \"somethingmock\";\n        }\n\n        public String getSomething2() {\n            return \"something2mock\";\n        }\n\n        public String getSomething3() {\n            return \"something3mock\";\n        }\n\n        public String getSomething4() {\n            return \"something4mock\";\n        }\n\n        public List<String> getListString() {\n            return Arrays.asList(new String[] {\"Tommock\", \"Jerrymock\"});\n        }\n\n        public List<User> getUsers() {\n            return Arrays.asList(new User[] {new User(1, \"Tommock\"), new User(2, \"Jerrymock\")});\n        }\n\n        @Override\n        public CompletableFuture<List<User>> getUsersAsync() {\n            CompletableFuture<List<User>> cf = new CompletableFuture<>();\n            cf.complete(Arrays.asList(new User[] {new User(1, \"Tommock\"), new User(2, \"Jerrymock\")}));\n            return cf;\n        }\n\n        public int getInt1() {\n            return 1;\n        }\n\n        public boolean getBoolean1() {\n            return false;\n        }\n\n        public Boolean getBoolean2() {\n            return Boolean.FALSE;\n        }\n\n        public void sayHello() {\n            logger.info(\"hello prety\");\n        }\n    }\n\n    public static class User {\n        private int id;\n        private String name;\n\n        public User() {}\n\n        public User(int id, String name) {\n            super();\n            this.id = id;\n            this.name = name;\n        }\n\n        public int getId() {\n            return id;\n        }\n\n        public void setId(int id) {\n            this.id = id;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockProviderRpcExceptionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.rpc.Constants.MOCK_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\n\nclass MockProviderRpcExceptionTest {\n    private static final Logger logger = LoggerFactory.getLogger(MockProviderRpcExceptionTest.class);\n\n    List<Invoker<IHelloRpcService>> invokers = new ArrayList<Invoker<IHelloRpcService>>();\n\n    @BeforeEach\n    public void beforeMethod() {\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);\n        invokers.clear();\n    }\n\n    /**\n     * Test if mock policy works fine: ProviderRpcException\n     */\n    @Test\n    void testMockInvokerProviderRpcException() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + IHelloRpcService.class.getName());\n        url = url.addParameter(MOCK_KEY, \"true\")\n                .addParameter(\"invoke_return_error\", \"true\")\n                .addParameter(\n                        REFER_KEY,\n                        URL.encode(PATH_KEY + \"=\" + IHelloRpcService.class.getName()\n                                + \"&\" + \"mock=true\"\n                                + \"&\" + \"proxy=jdk\"));\n        Invoker<IHelloRpcService> cluster = getClusterInvoker(url);\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"getSomething4\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"something4mock\", ret.getValue());\n    }\n\n    private Invoker<IHelloRpcService> getClusterInvokerMock(URL url, Invoker<IHelloRpcService> mockInvoker) {\n        // As `javassist` have a strict restriction of argument types, request will fail if Invocation do not contains\n        // complete parameter type information\n        final URL durl = url.addParameter(\"proxy\", \"jdk\");\n        invokers.clear();\n        ProxyFactory proxy =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(\"jdk\");\n        Invoker<IHelloRpcService> invoker1 = proxy.getInvoker(new HelloRpcService(), IHelloRpcService.class, durl);\n        invokers.add(invoker1);\n        if (mockInvoker != null) {\n            invokers.add(mockInvoker);\n        }\n\n        StaticDirectory<IHelloRpcService> dic = new StaticDirectory<IHelloRpcService>(durl, invokers, null);\n        dic.buildRouterChain();\n        AbstractClusterInvoker<IHelloRpcService> cluster = new AbstractClusterInvoker(dic) {\n            @Override\n            protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)\n                    throws RpcException {\n                if (durl.getParameter(\"invoke_return_error\", false)) {\n                    throw new RpcException(RpcException.TIMEOUT_EXCEPTION, \"test rpc exception \");\n                } else {\n                    return ((Invoker<?>) invokers.get(0)).invoke(invocation);\n                }\n            }\n        };\n        return new MockClusterInvoker<IHelloRpcService>(dic, cluster);\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private Invoker<IHelloRpcService> getClusterInvoker(URL url) {\n        return getClusterInvokerMock(url, null);\n    }\n\n    public static interface IHelloRpcService {\n        String getSomething();\n\n        String getSomething2();\n\n        String getSomething3();\n\n        String getSomething4();\n\n        int getInt1();\n\n        boolean getBoolean1();\n\n        Boolean getBoolean2();\n\n        public List<String> getListString();\n\n        public List<User> getUsers();\n\n        void sayHello();\n    }\n\n    public static class HelloRpcService implements IHelloRpcService {\n        public String getSomething() {\n            return \"something\";\n        }\n\n        public String getSomething2() {\n            return \"something2\";\n        }\n\n        public String getSomething3() {\n            return \"something3\";\n        }\n\n        public String getSomething4() {\n            throw new RpcException(\"getSomething4|RpcException\");\n        }\n\n        public int getInt1() {\n            return 1;\n        }\n\n        public boolean getBoolean1() {\n            return false;\n        }\n\n        public Boolean getBoolean2() {\n            return Boolean.FALSE;\n        }\n\n        public List<String> getListString() {\n            return Arrays.asList(new String[] {\"Tom\", \"Jerry\"});\n        }\n\n        public List<User> getUsers() {\n            return Arrays.asList(new User[] {new User(1, \"Tom\"), new User(2, \"Jerry\")});\n        }\n\n        public void sayHello() {\n            logger.info(\"hello prety\");\n        }\n    }\n\n    public static class IHelloRpcServiceMock implements IHelloRpcService {\n        public IHelloRpcServiceMock() {}\n\n        public String getSomething() {\n            return \"somethingmock\";\n        }\n\n        public String getSomething2() {\n            return \"something2mock\";\n        }\n\n        public String getSomething3() {\n            return \"something3mock\";\n        }\n\n        public String getSomething4() {\n            return \"something4mock\";\n        }\n\n        public List<String> getListString() {\n            return Arrays.asList(new String[] {\"Tommock\", \"Jerrymock\"});\n        }\n\n        public List<User> getUsers() {\n            return Arrays.asList(new User[] {new User(1, \"Tommock\"), new User(2, \"Jerrymock\")});\n        }\n\n        public int getInt1() {\n            return 1;\n        }\n\n        public boolean getBoolean1() {\n            return false;\n        }\n\n        public Boolean getBoolean2() {\n            return Boolean.FALSE;\n        }\n\n        public void sayHello() {\n            logger.info(\"hello prety\");\n        }\n    }\n\n    public static class User {\n        private int id;\n        private String name;\n\n        public User() {}\n\n        public User(int id, String name) {\n            super();\n            this.id = id;\n            this.name = name;\n        }\n\n        public int getId() {\n            return id;\n        }\n\n        public void setId(int id) {\n            this.id = id;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MyMockException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\npublic class MyMockException extends RuntimeException {\n\n    private static final long serialVersionUID = 2851692379597990457L;\n\n    public MyMockException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/ScopeClusterInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.support.wrapper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.EXPORTER_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;\nimport static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;\nimport static org.apache.dubbo.rpc.cluster.Constants.PEER_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.SCOPE_KEY;\n\nclass ScopeClusterInvokerTest {\n\n    private final List<Invoker<DemoService>> invokers = new ArrayList<>();\n\n    private final Protocol protocol =\n            ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n    private final ProxyFactory proxy =\n            ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n\n    private final List<Exporter<?>> exporters = new ArrayList<>();\n\n    @BeforeEach\n    void beforeMonth() {\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);\n    }\n\n    @AfterEach\n    void after() throws Exception {\n        for (Exporter<?> exporter : exporters) {\n            exporter.unexport();\n        }\n        exporters.clear();\n        for (Invoker<DemoService> invoker : invokers) {\n            invoker.destroy();\n            if (invoker instanceof ScopeClusterInvoker) {\n                Assertions.assertTrue(((ScopeClusterInvoker) invoker).isDestroyed());\n            }\n        }\n        invokers.clear();\n    }\n\n    @Test\n    void testScopeNull_RemoteInvoke() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + DemoService.class.getName());\n        url = url.addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + DemoService.class.getName()));\n        url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n\n        Invoker<DemoService> cluster = getClusterInvoker(url);\n        invokers.add(cluster);\n\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething1\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething1\", ret.getValue());\n    }\n\n    @Test\n    void testScopeNull_LocalInvoke() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + DemoService.class.getName());\n        url = url.addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + DemoService.class.getName()));\n        url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n\n        URL injvmUrl = URL.valueOf(\"injvm://127.0.0.1/TestService\")\n                .addParameter(INTERFACE_KEY, DemoService.class.getName())\n                .setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n        Exporter<?> exporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, injvmUrl));\n        exporters.add(exporter);\n\n        Invoker<DemoService> cluster = getClusterInvoker(url);\n        invokers.add(cluster);\n\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething2\");\n        invocation.setParameterTypes(new Class[] {});\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething2\", ret.getValue());\n    }\n\n    @Test\n    void testScopeRemoteInvoke() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + DemoService.class.getName());\n        url = url.addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + DemoService.class.getName()));\n        url = url.addParameter(SCOPE_KEY, \"remote\");\n        url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n\n        URL injvmUrl = URL.valueOf(\"injvm://127.0.0.1/TestService\")\n                .addParameter(INTERFACE_KEY, DemoService.class.getName())\n                .setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n        Exporter<?> exporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, injvmUrl));\n        exporters.add(exporter);\n\n        Invoker<DemoService> cluster = getClusterInvoker(url);\n        invokers.add(cluster);\n\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething3\");\n        invocation.setParameterTypes(new Class[] {});\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething3\", ret.getValue());\n    }\n\n    @Test\n    void testScopeLocalInvoke() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + DemoService.class.getName());\n        url = url.addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + DemoService.class.getName()));\n        url = url.addParameter(SCOPE_KEY, SCOPE_LOCAL);\n        url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n\n        Invoker<DemoService> cluster = getClusterInvoker(url);\n        invokers.add(cluster);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething4\");\n        invocation.setParameterTypes(new Class[] {});\n        Assertions.assertFalse(cluster.isAvailable(), \"\");\n        RpcInvocation finalInvocation = invocation;\n        Assertions.assertThrows(RpcException.class, () -> cluster.invoke(finalInvocation));\n\n        URL injvmUrl =\n                URL.valueOf(\"injvm://127.0.0.1/TestService\").addParameter(INTERFACE_KEY, DemoService.class.getName());\n        injvmUrl = injvmUrl.addParameter(EXPORTER_LISTENER_KEY, LOCAL_PROTOCOL)\n                .setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n        Exporter<?> exporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, injvmUrl));\n        exporters.add(exporter);\n\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething4\");\n        invocation.setParameterTypes(new Class[] {});\n        Assertions.assertTrue(cluster.isAvailable(), \"\");\n        Result ret2 = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething4\", ret2.getValue());\n    }\n\n    @Test\n    void testInjvmRefer() {\n        URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, DemoService.class.getName());\n        url = url.addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + DemoService.class.getName()));\n        url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n\n        URL injvmUrl = URL.valueOf(\"injvm://127.0.0.1/TestService\")\n                .addParameter(INTERFACE_KEY, DemoService.class.getName())\n                .setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n        Exporter<?> exporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, injvmUrl));\n        exporters.add(exporter);\n\n        Invoker<DemoService> cluster = getClusterInvoker(url);\n        invokers.add(cluster);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething5\");\n        invocation.setParameterTypes(new Class[] {});\n        Assertions.assertTrue(cluster.isAvailable(), \"\");\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething5\", ret.getValue());\n    }\n\n    @Test\n    void testListenUnExport() throws NoSuchFieldException, IllegalAccessException {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + DemoService.class.getName());\n        url = url.addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + DemoService.class.getName()));\n        url = url.addParameter(SCOPE_KEY, \"local\");\n        url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n\n        URL injvmUrl = URL.valueOf(\"injvm://127.0.0.1/TestService\")\n                .addParameter(INTERFACE_KEY, DemoService.class.getName())\n                .setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n        Exporter<?> exporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, injvmUrl));\n\n        Invoker<DemoService> cluster = getClusterInvoker(url);\n        invokers.add(cluster);\n\n        exporter.unexport();\n\n        Assertions.assertTrue(cluster instanceof ScopeClusterInvoker);\n\n        Field injvmInvoker = cluster.getClass().getDeclaredField(\"injvmInvoker\");\n        injvmInvoker.setAccessible(true);\n        Assertions.assertNull(injvmInvoker.get(cluster));\n\n        Field isExported = cluster.getClass().getDeclaredField(\"isExported\");\n        isExported.setAccessible(true);\n        Assertions.assertFalse(((AtomicBoolean) isExported.get(cluster)).get());\n    }\n\n    @Test\n    void testPeerInvoke() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + DemoService.class.getName());\n        url = url.addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + DemoService.class.getName()));\n        Map<String, Object> peer = new HashMap<>();\n        peer.put(PEER_KEY, true);\n        url = url.addAttributes(peer);\n        url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n\n        Invoker<DemoService> cluster = getClusterInvoker(url);\n        invokers.add(cluster);\n\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething6\");\n        invocation.setParameterTypes(new Class[] {});\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething6\", ret.getValue());\n    }\n\n    @Test\n    void testInjvmUrlInvoke() {\n        URL url = URL.valueOf(\"injvm://1.2.3.4/\" + DemoService.class.getName());\n        url = url.addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + DemoService.class.getName()));\n        url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n\n        Invoker<DemoService> cluster = getClusterInvoker(url);\n        invokers.add(cluster);\n\n        // Configured with mock\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething7\");\n        invocation.setParameterTypes(new Class[] {});\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething7\", ret.getValue());\n    }\n\n    @Test\n    void testDynamicInvoke() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + DemoService.class.getName());\n        url = url.addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + DemoService.class.getName()));\n        url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n\n        Invoker<DemoService> cluster = getClusterInvoker(url);\n        invokers.add(cluster);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething8\");\n        invocation.setParameterTypes(new Class[] {});\n        Result ret1 = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething8\", ret1.getValue());\n\n        RpcContext.getServiceContext().setLocalInvoke(true);\n\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething8\");\n        invocation.setParameterTypes(new Class[] {});\n        RpcInvocation finalInvocation = invocation;\n        Assertions.assertThrows(RpcException.class, () -> cluster.invoke(finalInvocation));\n\n        URL injvmUrl = URL.valueOf(\"injvm://127.0.0.1/TestService\")\n                .addParameter(INTERFACE_KEY, DemoService.class.getName())\n                .setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n        Exporter<?> exporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, injvmUrl));\n        exporters.add(exporter);\n\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething8\");\n        invocation.setParameterTypes(new Class[] {});\n        Result ret2 = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething8\", ret2.getValue());\n\n        RpcContext.getServiceContext().setLocalInvoke(false);\n\n        invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething8\");\n        invocation.setParameterTypes(new Class[] {});\n        Result ret3 = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething8\", ret3.getValue());\n    }\n\n    @Test\n    void testBroadcast() {\n        URL url = URL.valueOf(\"remote://1.2.3.4/\" + DemoService.class.getName());\n        url = url.addParameter(REFER_KEY, URL.encode(PATH_KEY + \"=\" + DemoService.class.getName()));\n        url = url.addParameter(\"cluster\", \"broadcast\");\n        url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n        Invoker<DemoService> cluster = getClusterInvoker(url);\n\n        invokers.add(cluster);\n\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"doSomething8\");\n        invocation.setParameterTypes(new Class[] {});\n        Result ret = cluster.invoke(invocation);\n        Assertions.assertEquals(\"doSomething8\", ret.getValue());\n    }\n\n    private Invoker<DemoService> getClusterInvoker(URL url) {\n        final URL durl = url.addParameter(\"proxy\", \"jdk\");\n        invokers.clear();\n        ProxyFactory proxy =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(\"jdk\");\n        Invoker<DemoService> invoker1 = proxy.getInvoker(new DemoServiceImpl(), DemoService.class, durl);\n        invokers.add(invoker1);\n\n        StaticDirectory<DemoService> dic = new StaticDirectory<>(durl, invokers, null);\n        dic.buildRouterChain();\n        AbstractClusterInvoker<DemoService> cluster = new AbstractClusterInvoker(dic) {\n            @Override\n            protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)\n                    throws RpcException {\n                if (durl.getParameter(\"invoke_return_error\", false)) {\n                    throw new RpcException(RpcException.TIMEOUT_EXCEPTION, \"test rpc exception\");\n                } else {\n                    return ((Invoker<?>) invokers.get(0)).invoke(invocation);\n                }\n            }\n        };\n        ScopeClusterInvoker<DemoService> demoServiceScopeClusterInvoker = new ScopeClusterInvoker<>(dic, cluster);\n        Assertions.assertNotNull(demoServiceScopeClusterInvoker.getDirectory());\n        Assertions.assertNotNull(demoServiceScopeClusterInvoker.getInvoker());\n        return demoServiceScopeClusterInvoker;\n    }\n\n    public static interface DemoService {\n        String doSomething1();\n\n        String doSomething2();\n\n        String doSomething3();\n\n        String doSomething4();\n\n        String doSomething5();\n\n        String doSomething6();\n\n        String doSomething7();\n\n        String doSomething8();\n    }\n\n    public static class DemoServiceImpl implements DemoService {\n\n        @Override\n        public String doSomething1() {\n            return \"doSomething1\";\n        }\n\n        @Override\n        public String doSomething2() {\n            return \"doSomething2\";\n        }\n\n        @Override\n        public String doSomething3() {\n            return \"doSomething3\";\n        }\n\n        @Override\n        public String doSomething4() {\n            return \"doSomething4\";\n        }\n\n        @Override\n        public String doSomething5() {\n            return \"doSomething5\";\n        }\n\n        @Override\n        public String doSomething6() {\n            return \"doSomething6\";\n        }\n\n        @Override\n        public String doSomething7() {\n            return \"doSomething7\";\n        }\n\n        @Override\n        public String doSomething8() {\n            return \"doSomething8\";\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/AppAnyServices.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Application scope, apply to all services.\n---\nconfigVersion: v2.7\nscope: application\nkey: demo-consumer\nconfigs:\n- addresses: [127.0.0.1, 0.0.0.0]\n  services: ['*']\n  parameters:\n    loadbalance: random\n    cluster: failfast\n    timeout: 6666\n...\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/AppMultiServices.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Application scope, apply to the specified services\n---\nconfigVersion: v2.7\nscope: application\nkey: demo-consumer\nconfigs:\n- addresses: [127.0.0.1, 0.0.0.0]\n  services: ['service1', 'service2']\n  parameters:\n    loadbalance: random\n    cluster: failfast\n    timeout: 6666\n..."
  },
  {
    "path": "dubbo-cluster/src/test/resources/AppNoService.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Application scope, no service means apply to all\n---\nconfigVersion: v2.7\nscope: application\nkey: demo-consumer\nconfigs:\n- addresses:\n  - 127.0.0.1\n  parameters:\n    loadbalance: random\n    cluster: failfast\n    timeout: 6666\n..."
  },
  {
    "path": "dubbo-cluster/src/test/resources/ConditionRule.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# application level, applies to all services\n---\nscope: application\nforce: true\nruntime: false\nenabled: true\npriority: 1\nkey: demo-consumer\nconditions:\n- method!=sayHello => address=30.5.120.16:20880\n- method=routeMethod1 =>\n...\n\n# application level, only applies to a specific service\n---\nscope: application\nforce: true\nruntime: false\nenabled: true\npriority: 1\nkey: demo-consumer\nconditions:\n- interface=org.apache.dubbo.demo.DemoService&method!=sayHello => host=30.5.120.16\n- interface=org.apache.dubbo.demo.DemoService&method=routeMethod1 => address=30.5.120.16:20880\n...\n\n---\nscope: service\nforce: true\nruntime: false\nenabled: true\npriority: 1\nkey: org.apache.dubbo.demo.DemoService\nconditions:\n- method!=sayHello =>\n- method=routeMethod1 => address=30.5.120.16:20880\n..."
  },
  {
    "path": "dubbo-cluster/src/test/resources/ConfiguratorV3.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Application scope, apply to all services.\n---\nconfigVersion: v3.0\nscope: application\nkey: demo-provider\nconfigs:\n  - match:\n      address:\n        wildcard: \"10.0.0.1:20880\"\n      service:\n        oneof:\n          - exact: \"DemoService\"\n          - exact: \"DemoService2\"\n      param:\n        - key: match_key1\n          value:\n            exact: value1\n    side: provider\n    parameters:\n      weight: 200\n...\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/ConfiguratorV3Compatibility.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Application scope, apply to all services.\n---\nconfigVersion: v3.0\nscope: application\nkey: demo-provider\nconfigs:\n  - addresses:\n      - \"10.0.0.1:20880\" # compatibility test\n    services:\n      - \"DemoService\" # compatibility test\n    match:\n      param:\n        - key: match_key1\n          value:\n            exact: value1\n    side: provider\n    parameters:\n      weight: 200\n...\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/ConfiguratorV3Duplicate.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Application scope, apply to all services.\n---\nconfigVersion: v3.0\nscope: application\nkey: demo-provider\nconfigs:\n  - addresses:\n      - \"10.0.0.1:20880\" # duplicate test\n    services: [ \"DemoService\" ] # duplicate test\n    match:\n      address:\n        wildcard: \"10.0.0.1:20880\"\n      service:\n        oneof:\n          - exact: \"DemoService\"\n          - exact: \"DemoService2\"\n      param:\n        - key: match_key1\n          value:\n            exact: value1\n    side: provider\n    parameters:\n      weight: 200\n...\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/ConsumerSpecificProviders.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Application scope, no service means apply to all\n---\nconfigVersion: v2.7\nscope: application\nkey: demo-consumer\nconfigs:\n- addresses:\n  - 127.0.0.1\n  providerAddresses: ['127.0.0.1:20880']\n  parameters:\n    loadbalance: random\n    cluster: failfast\n    timeout: 6666\n    weight: 222\n..."
  },
  {
    "path": "dubbo-cluster/src/test/resources/DestinationRuleTest.yaml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\napiVersion: service.dubbo.apache.org/v1alpha1\nkind: DestinationRule\nmetadata: { name: demo-route }\nspec:\n  host: demo\n  subsets:\n    - labels: { env-sign: xxx, tag1: hello }\n      name: isolation\n    - labels: { env-sign: yyy }\n      name: testing-trunk\n    - labels: { env-sign: zzz }\n      name: testing\n  trafficPolicy:\n    loadBalancer: { simple: ROUND_ROBIN }\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/DestinationRuleTest2.yaml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\napiVersion: service.dubbo.apache.org/v1alpha1\nkind: DestinationRule\nmetadata: { name: demo-route }\nspec:\n  host: demo\n  subsets:\n    - labels: { env-sign: xxx, tag1: hello }\n      name: isolation\n    - labels: { env-sign: yyy }\n      name: testing-trunk\n    - labels: { env-sign: zzz }\n      name: testing\n  trafficPolicy:\n    loadBalancer: { simple: ROUND_ROBIN }\n\n---\n\napiVersion: service.dubbo.apache.org/v1alpha1\nkind: VirtualService\nmetadata: {name: demo-route}\nspec:\n  dubbo:\n    - routedetail:\n        - match:\n            - sourceLabels: {trafficLabel: xxx}\n          name: xxx-project\n          route:\n            - destination: {host: demo, subset: isolation}\n        - match:\n            - sourceLabels: {trafficLabel: testing-trunk}\n          name: testing-trunk\n          route:\n            - destination: {host: demo, subset: testing-trunk}\n        - name: testing\n          route:\n            - destination: {host: demo, subset: testing}\n      services:\n        - {regex: ccc}\n  hosts: [demo]\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter",
    "content": "log=org.apache.dubbo.rpc.cluster.filter.LogFilter\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger",
    "content": "intsum=org.apache.dubbo.rpc.cluster.merger.IntSumMerger\nlongsum=org.apache.dubbo.rpc.cluster.merger.LongSumMerger\nfloatsum=org.apache.dubbo.rpc.cluster.merger.FloatSumMerger\ndoublesum=org.apache.dubbo.rpc.cluster.merger.DoubleSumMerger\nintfirst=org.apache.dubbo.rpc.cluster.merger.IntFindFirstMerger\nintany=org.apache.dubbo.rpc.cluster.merger.IntFindAnyMerger\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor",
    "content": "tag=org.apache.dubbo.rpc.cluster.support.TagProviderURLMergeProcessor\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.ClusterFilter",
    "content": "demo=org.apache.dubbo.rpc.cluster.support.wrapper.DemoClusterFilter\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory",
    "content": "script=org.apache.dubbo.rpc.cluster.router.script.ScriptStateRouterFactory\nfile=org.apache.dubbo.rpc.cluster.router.file.FileStateRouterFactory\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/ScriptRule.yaml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Application scope, no service means apply to all\n---\nconfigVersion: v3.0\nkey: demo-provider\ntype: javascript\nscript: |\n  （function route(invokers) {\n      var result = new java.util.ArrayList(invokers.size());\n      for (i = 0; i < invokers.size(); i ++) {\n          if (\"10.20.153.10\".equals(invokers.get(i).getUrl().getHost())) {\n              result.add(invokers.get(i));\n          }\n      }\n      return result;\n  } (invokers)）; // 表示立即执行方法\n...\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/ServiceGroupVersion.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Service scope, without any app\n---\nconfigVersion: v2.7\nscope: service\nkey: testgroup/servicekey:1.0.0\nconfigs:\n- addresses: ['127.0.0.1:20880']\n  parameters:\n    weight: 222\n..."
  },
  {
    "path": "dubbo-cluster/src/test/resources/ServiceMultiApps.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Service scope, with multiple apps\n---\nconfigVersion: v2.7\nscope: service\nkey: serviceKey\nconfigs:\n- addresses: [127.0.0.1, 0.0.0.0]\n  applications: [app1, app2]\n  parameters:\n    timeout: 6666\n..."
  },
  {
    "path": "dubbo-cluster/src/test/resources/ServiceNoApp.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Service scope, without any app\n---\nconfigVersion: v2.7\nscope: service\nkey: serviceKey\nconfigs:\n- addresses: ['127.0.0.1:20880', '0.0.0.0:20881']\n  parameters:\n    weight: 222\n..."
  },
  {
    "path": "dubbo-cluster/src/test/resources/ServiceNoRule.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n# Service scope, without specific App\n---\nconfigVersion: v2.7\nscope: service\nkey: serviceKey\nconfigs:\n- addresses: [127.0.0.1, 0.0.0.0]\n  applications: [app1, app2]\n..."
  },
  {
    "path": "dubbo-cluster/src/test/resources/TagRule.yml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\n---\nforce: true\nruntime: false\nenabled: true\npriority: 1\nkey: demo-provider\ntags:\n- name: tag1\n  addresses: [30.5.120.16:20880]\n- name: tag2\n  addresses: [30.5.120.16:20881]\n..."
  },
  {
    "path": "dubbo-cluster/src/test/resources/VirtualServiceTest.yaml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\napiVersion: service.dubbo.apache.org/v1alpha1\nkind: VirtualService\nmetadata: {name: demo-route}\nspec:\n  dubbo:\n    - routedetail:\n        - match:\n            - sourceLabels: {trafficLabel: xxx}\n          name: xxx-project\n          route:\n            - destination: {host: demo, subset: isolation}\n        - match:\n            - sourceLabels: {trafficLabel: testing-trunk}\n          name: testing-trunk\n          route:\n            - destination: {host: demo, subset: testing-trunk}\n        - name: testing\n          route:\n            - destination: {host: demo, subset: testing}\n      services:\n        - {regex: ccc}\n  hosts: [demo]\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/dubbo.properties",
    "content": "dubbo.application.enable-file-cache=false\ndubbo.service.shutdown.wait=200\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Dubbo name=\"Dubbo\" fileName=\"../dubbo.log\">\n            <PatternLayout pattern=\"[%d{HH:mm:ss:SSS}] %5p %t %c{2}: %m%n%ex\" charset=\"UTF-8\"/>\n        </Dubbo>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Dubbo\"/>\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-cluster/src/test/resources/org/apache/dubbo/rpc/cluster/router/file/availablerule.javascript",
    "content": "// Licensed to the Apache Software Foundation (ASF) under one or more\n// contributor license agreements.  See the NOTICE file distributed with\n// this work for additional information regarding copyright ownership.\n// The ASF licenses this file to You under the Apache License, Version 2.0\n// (the \"License\"); you may not use this file except in compliance with\n// the License.  You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nfunction route(invokers,invocation,context){\n\tvar result = new java.util.ArrayList(invokers.size());\n\t\n\tfor (i=0;i<invokers.size(); i++){ \n\t    if (invokers.get(i).isAvailable()) {\n\t        result.add(invokers.get(i)) ;\n\t    }\n\t} ; \n\treturn result;\n};\nroute(invokers,invocation,context);"
  },
  {
    "path": "dubbo-cluster/src/test/resources/org/apache/dubbo/rpc/cluster/router/file/methodrule.javascript",
    "content": "// Licensed to the Apache Software Foundation (ASF) under one or more\n// contributor license agreements.  See the NOTICE file distributed with\n// this work for additional information regarding copyright ownership.\n// The ASF licenses this file to You under the Apache License, Version 2.0\n// (the \"License\"); you may not use this file except in compliance with\n// the License.  You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nfunction route(invokers,invocation,context){\n\tvar result = new java.util.ArrayList();\n\tif (invokers.size()>1 && invocation.getMethodName() .equals(\"method1\")) {\n\t   \tresult.add(invokers.get(0)) ;\n\t} else {\n\t\tresult.add(invokers.get(1)) ;\n\t}\n\treturn result;\n};\nroute(invokers,invocation,context);"
  },
  {
    "path": "dubbo-cluster/src/test/resources/org/apache/dubbo/rpc/cluster/router/file/notAvailablerule.javascript",
    "content": "// Licensed to the Apache Software Foundation (ASF) under one or more\n// contributor license agreements.  See the NOTICE file distributed with\n// this work for additional information regarding copyright ownership.\n// The ASF licenses this file to You under the Apache License, Version 2.0\n// (the \"License\"); you may not use this file except in compliance with\n// the License.  You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nfunction route(invokers,invocation,context){\n\tvar result = new java.util.ArrayList(invokers.size());\n\t\n\tfor (i=0;i<invokers.size(); i++){ \n\t    if (!invokers.get(i).isAvailable()) {\n\t        result.add(invokers.get(i)) ;\n\t    }\n\t} ; \n\treturn result;\n};\nroute(invokers,invocation,context);"
  },
  {
    "path": "dubbo-common/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-common</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The common module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.slf4j</groupId>\n      <artifactId>slf4j-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>commons-logging</groupId>\n      <artifactId>commons-logging</artifactId>\n      <scope>provided</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>log4j</groupId>\n      <artifactId>log4j</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-core</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.javassist</groupId>\n      <artifactId>javassist</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.alibaba</groupId>\n      <artifactId>fastjson</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>com.google.code.gson</groupId>\n      <artifactId>gson</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <artifactId>jackson-core</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <artifactId>jackson-databind</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>com.fasterxml.jackson.datatype</groupId>\n      <artifactId>jackson-datatype-jsr310</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>com.alibaba.fastjson2</groupId>\n      <artifactId>fastjson2</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>commons-io</groupId>\n      <artifactId>commons-io</artifactId>\n    </dependency>\n    <!-- Common Annotations API -->\n    <dependency>\n      <groupId>javax.annotation</groupId>\n      <artifactId>javax.annotation-api</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>cglib</groupId>\n      <artifactId>cglib-nodep</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/BaseServiceMetadata.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_VERSION;\n\n/**\n * 2019-10-10\n */\npublic class BaseServiceMetadata {\n    public static final char COLON_SEPARATOR = ':';\n\n    protected String serviceKey;\n    protected String serviceInterfaceName;\n    protected String version;\n    protected volatile String group;\n    private ServiceModel serviceModel;\n\n    public static String buildServiceKey(String path, String group, String version) {\n        int length = path == null ? 0 : path.length();\n        length += group == null ? 0 : group.length();\n        length += version == null ? 0 : version.length();\n        length += 2;\n        StringBuilder buf = new StringBuilder(length);\n        if (StringUtils.isNotEmpty(group)) {\n            buf.append(group).append('/');\n        }\n        buf.append(path);\n        if (StringUtils.isNotEmpty(version)) {\n            buf.append(':').append(version);\n        }\n        return buf.toString();\n    }\n\n    public static String versionFromServiceKey(String serviceKey) {\n        int index = serviceKey.indexOf(\":\");\n        if (index == -1) {\n            return DEFAULT_VERSION;\n        }\n        return serviceKey.substring(index + 1);\n    }\n\n    public static String groupFromServiceKey(String serviceKey) {\n        int index = serviceKey.indexOf(\"/\");\n        if (index == -1) {\n            return null;\n        }\n        return serviceKey.substring(0, index);\n    }\n\n    public static String interfaceFromServiceKey(String serviceKey) {\n        int groupIndex = serviceKey.indexOf(\"/\");\n        int versionIndex = serviceKey.indexOf(\":\");\n        groupIndex = (groupIndex == -1) ? 0 : groupIndex + 1;\n        versionIndex = (versionIndex == -1) ? serviceKey.length() : versionIndex;\n        return serviceKey.substring(groupIndex, versionIndex);\n    }\n\n    /**\n     * Format : interface:version\n     *\n     * @return\n     */\n    public String getDisplayServiceKey() {\n        StringBuilder serviceNameBuilder = new StringBuilder();\n        serviceNameBuilder.append(serviceInterfaceName);\n        serviceNameBuilder.append(COLON_SEPARATOR).append(version);\n        return serviceNameBuilder.toString();\n    }\n\n    /**\n     * revert of org.apache.dubbo.common.ServiceDescriptor#getDisplayServiceKey()\n     *\n     * @param displayKey\n     * @return\n     */\n    public static BaseServiceMetadata revertDisplayServiceKey(String displayKey) {\n        String[] eles = StringUtils.split(displayKey, COLON_SEPARATOR);\n        if (eles == null || eles.length < 1 || eles.length > 2) {\n            return new BaseServiceMetadata();\n        }\n        BaseServiceMetadata serviceDescriptor = new BaseServiceMetadata();\n        serviceDescriptor.setServiceInterfaceName(eles[0]);\n        if (eles.length == 2) {\n            serviceDescriptor.setVersion(eles[1]);\n        }\n        return serviceDescriptor;\n    }\n\n    public static String keyWithoutGroup(String interfaceName, String version) {\n        if (StringUtils.isEmpty(version)) {\n            return interfaceName + \":\" + DEFAULT_VERSION;\n        }\n        return interfaceName + \":\" + version;\n    }\n\n    public String getServiceKey() {\n        return serviceKey;\n    }\n\n    public void generateServiceKey() {\n        this.serviceKey = buildServiceKey(serviceInterfaceName, group, version);\n    }\n\n    public void setServiceKey(String serviceKey) {\n        this.serviceKey = serviceKey;\n    }\n\n    public String getServiceInterfaceName() {\n        return serviceInterfaceName;\n    }\n\n    public void setServiceInterfaceName(String serviceInterfaceName) {\n        this.serviceInterfaceName = serviceInterfaceName;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public ServiceModel getServiceModel() {\n        return serviceModel;\n    }\n\n    public void setServiceModel(ServiceModel serviceModel) {\n        this.serviceModel = serviceModel;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/BatchExecutorQueue.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport java.util.LinkedList;\nimport java.util.Queue;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class BatchExecutorQueue<T> {\n\n    static final int DEFAULT_QUEUE_SIZE = 128;\n    private final Queue<T> queue;\n    private final AtomicBoolean scheduled;\n    private final int chunkSize;\n\n    public BatchExecutorQueue() {\n        this(DEFAULT_QUEUE_SIZE);\n    }\n\n    public BatchExecutorQueue(int chunkSize) {\n        this.queue = new ConcurrentLinkedQueue<>();\n        this.scheduled = new AtomicBoolean(false);\n        this.chunkSize = chunkSize;\n    }\n\n    public void enqueue(T message, Executor executor) {\n        queue.add(message);\n        scheduleFlush(executor);\n    }\n\n    protected void scheduleFlush(Executor executor) {\n        if (scheduled.compareAndSet(false, true)) {\n            executor.execute(() -> this.run(executor));\n        }\n    }\n\n    private void run(Executor executor) {\n        try {\n            Queue<T> snapshot = new LinkedList<>();\n            T item;\n            while ((item = queue.poll()) != null) {\n                snapshot.add(item);\n            }\n            int i = 0;\n            boolean flushedOnce = false;\n            while ((item = snapshot.poll()) != null) {\n                if (snapshot.size() == 0) {\n                    flushedOnce = false;\n                    break;\n                }\n                if (i == chunkSize) {\n                    i = 0;\n                    flush(item);\n                    flushedOnce = true;\n                } else {\n                    prepare(item);\n                    i++;\n                }\n            }\n            if (!flushedOnce && item != null) {\n                flush(item);\n            }\n        } finally {\n            scheduled.set(false);\n            if (!queue.isEmpty()) {\n                scheduleFlush(executor);\n            }\n        }\n    }\n\n    protected void prepare(T item) {}\n\n    protected void flush(T item) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.config.ConfigurationCache;\nimport org.apache.dubbo.common.convert.ConverterUtil;\nimport org.apache.dubbo.common.lang.ShutdownHookCallbacks;\nimport org.apache.dubbo.common.serialization.ClassHolder;\nimport org.apache.dubbo.common.ssl.CertManager;\nimport org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.DefaultSerializeClassChecker;\nimport org.apache.dubbo.common.utils.SerializeSecurityConfigurator;\nimport org.apache.dubbo.common.utils.SerializeSecurityManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\npublic class CommonScopeModelInitializer implements ScopeModelInitializer {\n    @Override\n    public void initializeFrameworkModel(FrameworkModel frameworkModel) {\n        ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();\n        beanFactory.registerBean(FrameworkExecutorRepository.class);\n        beanFactory.registerBean(ConverterUtil.class);\n        beanFactory.registerBean(SerializeSecurityManager.class);\n        beanFactory.registerBean(DefaultSerializeClassChecker.class);\n        beanFactory.registerBean(CertManager.class);\n        beanFactory.registerBean(ClassHolder.class);\n    }\n\n    @Override\n    public void initializeApplicationModel(ApplicationModel applicationModel) {\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        beanFactory.registerBean(ShutdownHookCallbacks.class);\n        beanFactory.registerBean(FrameworkStatusReportService.class);\n        beanFactory.registerBean(new ConfigurationCache());\n    }\n\n    @Override\n    public void initializeModuleModel(ModuleModel moduleModel) {\n        ScopeBeanFactory beanFactory = moduleModel.getBeanFactory();\n        beanFactory.registerBean(new ConfigurationCache());\n        beanFactory.registerBean(SerializeSecurityConfigurator.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/Experimental.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Indicating unstable API, may get removed or changed in future releases.\n */\n@Retention(RetentionPolicy.CLASS)\n@Target({\n    ElementType.ANNOTATION_TYPE,\n    ElementType.CONSTRUCTOR,\n    ElementType.FIELD,\n    ElementType.METHOD,\n    ElementType.PACKAGE,\n    ElementType.TYPE\n})\npublic @interface Experimental {\n    String value();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/Extension.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Marker for extension interface\n * <p/>\n * Changes on extension configuration file <br/>\n * Use <code>Protocol</code> as an example, its configuration file 'META-INF/dubbo/com.xxx.Protocol' is changes from: <br/>\n * <pre>\n *     com.foo.XxxProtocol\n *     com.foo.YyyProtocol\n * </pre>\n * <p>\n * to key-value pair <br/>\n * <pre>\n *     xxx=com.foo.XxxProtocol\n *     yyy=com.foo.YyyProtocol\n * </pre>\n * <br/>\n * The reason for this change is:\n * <p>\n * If there's third party library referenced by static field or by method in extension implementation, its class will\n * fail to initialize if the third party library doesn't exist. In this case, dubbo cannot figure out extension's id\n * therefore cannot be able to map the exception information with the extension, if the previous format is used.\n * <p/>\n * For example:\n * <p>\n * Fails to load Extension(\"mina\"). When user configure to use mina, dubbo will complain the extension cannot be loaded,\n * instead of reporting which extract extension implementation fails and the extract reason.\n * </p>\n *\n * @deprecated because it's too general, switch to use {@link org.apache.dubbo.common.extension.SPI}\n */\n@Deprecated\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE})\npublic @interface Extension {\n\n    /**\n     * @deprecated\n     */\n    @Deprecated\n    String value() default \"\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/Node.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\n/**\n * Node. (API/SPI, Prototype, ThreadSafe)\n */\npublic interface Node {\n\n    /**\n     * get url.\n     *\n     * @return url.\n     */\n    URL getUrl();\n\n    /**\n     * is available.\n     *\n     * @return available.\n     */\n    boolean isAvailable();\n\n    /**\n     * destroy.\n     */\n    void destroy();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLDecoder;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.HIDE_KEY_PREFIX;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\n/**\n * Parameters for backward compatibility for version prior to 2.0.5\n *\n * @deprecated\n */\n@Deprecated\npublic class Parameters {\n    protected static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(Parameters.class);\n    private final Map<String, String> parameters;\n\n    public Parameters(String... pairs) {\n        this(toMap(pairs));\n    }\n\n    public Parameters(Map<String, String> parameters) {\n        this.parameters =\n                Collections.unmodifiableMap(parameters != null ? new HashMap<>(parameters) : new HashMap<>(0));\n    }\n\n    private static Map<String, String> toMap(String... pairs) {\n        return CollectionUtils.toStringMap(pairs);\n    }\n\n    public static Parameters parseParameters(String query) {\n        return new Parameters(StringUtils.parseQueryString(query));\n    }\n\n    public Map<String, String> getParameters() {\n        return parameters;\n    }\n\n    /**\n     * @deprecated will be removed in 3.3.0\n     */\n    @Deprecated\n    public <T> T getExtension(Class<T> type, String key) {\n        String name = getParameter(key);\n        return ExtensionLoader.getExtensionLoader(type).getExtension(name);\n    }\n\n    /**\n     * @deprecated will be removed in 3.3.0\n     */\n    @Deprecated\n    public <T> T getExtension(Class<T> type, String key, String defaultValue) {\n        String name = getParameter(key, defaultValue);\n        return ExtensionLoader.getExtensionLoader(type).getExtension(name);\n    }\n\n    /**\n     * @deprecated will be removed in 3.3.0\n     */\n    @Deprecated\n    public <T> T getMethodExtension(Class<T> type, String method, String key) {\n        String name = getMethodParameter(method, key);\n        return ExtensionLoader.getExtensionLoader(type).getExtension(name);\n    }\n\n    /**\n     * @deprecated will be removed in 3.3.0\n     */\n    @Deprecated\n    public <T> T getMethodExtension(Class<T> type, String method, String key, String defaultValue) {\n        String name = getMethodParameter(method, key, defaultValue);\n        return ExtensionLoader.getExtensionLoader(type).getExtension(name);\n    }\n\n    public String getDecodedParameter(String key) {\n        return getDecodedParameter(key, null);\n    }\n\n    public String getDecodedParameter(String key, String defaultValue) {\n        String value = getParameter(key, defaultValue);\n        if (value != null && value.length() > 0) {\n            try {\n                value = URLDecoder.decode(value, \"UTF-8\");\n            } catch (UnsupportedEncodingException e) {\n                logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", e.getMessage(), e);\n            }\n        }\n        return value;\n    }\n\n    public String getParameter(String key) {\n        String value = parameters.get(key);\n        if (StringUtils.isEmpty(value)) {\n            value = parameters.get(HIDE_KEY_PREFIX + key);\n        }\n        if (StringUtils.isEmpty(value)) {\n            value = parameters.get(DEFAULT_KEY_PREFIX + key);\n        }\n        if (StringUtils.isEmpty(value)) {\n            value = parameters.get(HIDE_KEY_PREFIX + DEFAULT_KEY_PREFIX + key);\n        }\n        return value;\n    }\n\n    public String getParameter(String key, String defaultValue) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return value;\n    }\n\n    public int getIntParameter(String key) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return 0;\n        }\n        return Integer.parseInt(value);\n    }\n\n    public int getIntParameter(String key, int defaultValue) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Integer.parseInt(value);\n    }\n\n    public int getPositiveIntParameter(String key, int defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        int i = Integer.parseInt(value);\n        if (i > 0) {\n            return i;\n        }\n        return defaultValue;\n    }\n\n    public boolean getBooleanParameter(String key) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return false;\n        }\n        return Boolean.parseBoolean(value);\n    }\n\n    public boolean getBooleanParameter(String key, boolean defaultValue) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Boolean.parseBoolean(value);\n    }\n\n    public boolean hasParameter(String key) {\n        String value = getParameter(key);\n        return value != null && value.length() > 0;\n    }\n\n    public String getMethodParameter(String method, String key) {\n        String value = parameters.get(method + \".\" + key);\n        if (StringUtils.isEmpty(value)) {\n            value = parameters.get(HIDE_KEY_PREFIX + method + \".\" + key);\n        }\n        if (StringUtils.isEmpty(value)) {\n            return getParameter(key);\n        }\n        return value;\n    }\n\n    public String getMethodParameter(String method, String key, String defaultValue) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return value;\n    }\n\n    public int getMethodIntParameter(String method, String key) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return 0;\n        }\n        return Integer.parseInt(value);\n    }\n\n    public int getMethodIntParameter(String method, String key, int defaultValue) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Integer.parseInt(value);\n    }\n\n    public int getMethodPositiveIntParameter(String method, String key, int defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        int i = Integer.parseInt(value);\n        if (i > 0) {\n            return i;\n        }\n        return defaultValue;\n    }\n\n    public boolean getMethodBooleanParameter(String method, String key) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return false;\n        }\n        return Boolean.parseBoolean(value);\n    }\n\n    public boolean getMethodBooleanParameter(String method, String key, boolean defaultValue) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Boolean.parseBoolean(value);\n    }\n\n    public boolean hasMethodParameter(String method, String key) {\n        String value = getMethodParameter(method, key);\n        return value != null && value.length() > 0;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        return parameters.equals(o);\n    }\n\n    @Override\n    public int hashCode() {\n        return parameters.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return StringUtils.toQueryString(getParameters());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/ProtocolServiceKey.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Objects;\n\npublic class ProtocolServiceKey extends ServiceKey {\n    private final String protocol;\n\n    public ProtocolServiceKey(String interfaceName, String version, String group, String protocol) {\n        super(interfaceName, version, group);\n        this.protocol = protocol;\n    }\n\n    public String getProtocol() {\n        return protocol;\n    }\n\n    public String getServiceKeyString() {\n        return super.toString();\n    }\n\n    public boolean isSameWith(ProtocolServiceKey protocolServiceKey) {\n        // interface version group should be the same\n        if (!super.equals(protocolServiceKey)) {\n            return false;\n        }\n\n        // origin protocol is *, can not match any protocol\n        if (CommonConstants.ANY_VALUE.equals(protocol)) {\n            return false;\n        }\n\n        // origin protocol is null, can match any protocol\n        if (StringUtils.isEmpty(protocol) || StringUtils.isEmpty(protocolServiceKey.getProtocol())) {\n            return true;\n        }\n\n        // origin protocol is not *, match itself\n        return Objects.equals(protocol, protocolServiceKey.getProtocol());\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        if (!super.equals(o)) {\n            return false;\n        }\n        ProtocolServiceKey that = (ProtocolServiceKey) o;\n        return Objects.equals(protocol, that.protocol);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), protocol);\n    }\n\n    @Override\n    public String toString() {\n        return super.toString() + CommonConstants.GROUP_CHAR_SEPARATOR + protocol;\n    }\n\n    public static class Matcher {\n        public static boolean isMatch(ProtocolServiceKey rule, ProtocolServiceKey target) {\n            // 1. 2. 3. match interface / version / group\n            if (!ServiceKey.Matcher.isMatch(rule, target)) {\n                return false;\n            }\n\n            // 4.match protocol\n            // 4.1. if rule protocol is *, match all\n            if (!CommonConstants.ANY_VALUE.equals(rule.getProtocol())) {\n                // 4.2. if rule protocol is null, match all\n                if (StringUtils.isNotEmpty(rule.getProtocol())) {\n                    // 4.3. if rule protocol contains ',', split and match each\n                    if (rule.getProtocol().contains(CommonConstants.COMMA_SEPARATOR)) {\n                        String[] protocols = rule.getProtocol().split(\"\\\\\" + CommonConstants.COMMA_SEPARATOR, -1);\n                        boolean match = false;\n                        for (String protocol : protocols) {\n                            protocol = protocol.trim();\n                            if (StringUtils.isEmpty(protocol) && StringUtils.isEmpty(target.getProtocol())) {\n                                match = true;\n                                break;\n                            } else if (protocol.equals(target.getProtocol())) {\n                                match = true;\n                                break;\n                            }\n                        }\n                        if (!match) {\n                            return false;\n                        }\n                    }\n                    // 4.3. if rule protocol is not contains ',', match directly\n                    else if (!Objects.equals(rule.getProtocol(), target.getProtocol())) {\n                        return false;\n                    }\n                }\n            }\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/Resetable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\n/**\n * Resetable.\n */\npublic interface Resetable {\n\n    /**\n     * reset.\n     *\n     * @param url\n     */\n    void reset(URL url);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/ServiceKey.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Objects;\n\npublic class ServiceKey {\n    private final String interfaceName;\n    private final String group;\n    private final String version;\n\n    public ServiceKey(String interfaceName, String version, String group) {\n        this.interfaceName = interfaceName;\n        this.group = group;\n        this.version = version;\n    }\n\n    public String getInterfaceName() {\n        return interfaceName;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public String getVersion() {\n        return version;\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        ServiceKey that = (ServiceKey) o;\n        return Objects.equals(interfaceName, that.interfaceName)\n                && Objects.equals(group, that.group)\n                && Objects.equals(version, that.version);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(interfaceName, group, version);\n    }\n\n    @Override\n    public String toString() {\n        return BaseServiceMetadata.buildServiceKey(interfaceName, group, version);\n    }\n\n    public static class Matcher {\n        public static boolean isMatch(ServiceKey rule, ServiceKey target) {\n            // 1. match interface (accurate match)\n            if (!Objects.equals(rule.getInterfaceName(), target.getInterfaceName())) {\n                return false;\n            }\n\n            // 2. match version (accurate match)\n            // 2.1. if rule version is *, match all\n            if (!CommonConstants.ANY_VALUE.equals(rule.getVersion())) {\n                // 2.2. if rule version is null, target version should be null\n                if (StringUtils.isEmpty(rule.getVersion()) && !StringUtils.isEmpty(target.getVersion())) {\n                    return false;\n                }\n                if (!StringUtils.isEmpty(rule.getVersion())) {\n                    // 2.3. if rule version contains ',', split and match each\n                    if (rule.getVersion().contains(CommonConstants.COMMA_SEPARATOR)) {\n                        String[] versions = rule.getVersion().split(\"\\\\\" + CommonConstants.COMMA_SEPARATOR, -1);\n                        boolean match = false;\n                        for (String version : versions) {\n                            version = version.trim();\n                            if (StringUtils.isEmpty(version) && StringUtils.isEmpty(target.getVersion())) {\n                                match = true;\n                                break;\n                            } else if (version.equals(target.getVersion())) {\n                                match = true;\n                                break;\n                            }\n                        }\n                        if (!match) {\n                            return false;\n                        }\n                    }\n                    // 2.4. if rule version is not contains ',', match directly\n                    else if (!Objects.equals(rule.getVersion(), target.getVersion())) {\n                        return false;\n                    }\n                }\n            }\n\n            // 3. match group (wildcard match)\n            // 3.1. if rule group is *, match all\n            if (!CommonConstants.ANY_VALUE.equals(rule.getGroup())) {\n                // 3.2. if rule group is null, target group should be null\n                if (StringUtils.isEmpty(rule.getGroup()) && !StringUtils.isEmpty(target.getGroup())) {\n                    return false;\n                }\n                if (!StringUtils.isEmpty(rule.getGroup())) {\n                    // 3.3. if rule group contains ',', split and match each\n                    if (rule.getGroup().contains(CommonConstants.COMMA_SEPARATOR)) {\n                        String[] groups = rule.getGroup().split(\"\\\\\" + CommonConstants.COMMA_SEPARATOR, -1);\n                        boolean match = false;\n                        for (String group : groups) {\n                            group = group.trim();\n                            if (StringUtils.isEmpty(group) && StringUtils.isEmpty(target.getGroup())) {\n                                match = true;\n                                break;\n                            } else if (group.equals(target.getGroup())) {\n                                match = true;\n                                break;\n                            }\n                        }\n                        if (!match) {\n                            return false;\n                        }\n                    }\n                    // 3.4. if rule group is not contains ',', match directly\n                    else if (!Objects.equals(rule.getGroup(), target.getGroup())) {\n                        return false;\n                    }\n                }\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/URL.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.InmemoryConfiguration;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.constants.RemotingConstants;\nimport org.apache.dubbo.common.convert.ConverterUtil;\nimport org.apache.dubbo.common.url.component.PathURLAddress;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.url.component.URLAddress;\nimport org.apache.dubbo.common.url.component.URLParam;\nimport org.apache.dubbo.common.url.component.URLPlainParam;\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.LRUCache;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.io.Serializable;\nimport java.io.UnsupportedEncodingException;\nimport java.net.InetSocketAddress;\nimport java.net.MalformedURLException;\nimport java.net.URLDecoder;\nimport java.net.URLEncoder;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.TreeMap;\nimport java.util.function.Predicate;\n\nimport static org.apache.dubbo.common.BaseServiceMetadata.COLON_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.ADDRESS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.utils.StringUtils.isBlank;\n\n/**\n * URL - Uniform Resource Locator (Immutable, ThreadSafe)\n * <p>\n * url example:\n * <ul>\n * <li>http://www.facebook.com/friends?param1=value1&amp;param2=value2\n * <li>http://username:password@10.20.130.230:8080/list?version=1.0.0\n * <li>ftp://username:password@192.168.1.7:21/1/read.txt\n * <li>registry://192.168.1.7:9090/org.apache.dubbo.service1?param1=value1&amp;param2=value2\n * </ul>\n * <p>\n * Some strange example below:\n * <ul>\n * <li>192.168.1.3:20880<br>\n * for this case, url protocol = null, url host = 192.168.1.3, port = 20880, url path = null\n * <li>file:///home/user1/router.js?type=script<br>\n * for this case, url protocol = file, url host = null, url path = home/user1/router.js\n * <li>file://home/user1/router.js?type=script<br>\n * for this case, url protocol = file, url host = home, url path = user1/router.js\n * <li>file:///D:/1/router.js?type=script<br>\n * for this case, url protocol = file, url host = null, url path = D:/1/router.js\n * <li>file:/D:/1/router.js?type=script<br>\n * same as above file:///D:/1/router.js?type=script\n * <li>/home/user1/router.js?type=script <br>\n * for this case, url protocol = null, url host = null, url path = home/user1/router.js\n * <li>home/user1/router.js?type=script <br>\n * for this case, url protocol = null, url host = home, url path = user1/router.js\n * </ul>\n *\n * @see java.net.URL\n * @see java.net.URI\n */\npublic /*final**/ class URL implements Serializable {\n\n    private static final long serialVersionUID = -1985165475234910535L;\n\n    private static final Map<String, URL> cachedURLs = new LRUCache<>();\n\n    private final URLAddress urlAddress;\n    private final URLParam urlParam;\n\n    // ==== cache ====\n\n    private transient String serviceKey;\n    private transient String protocolServiceKey;\n    protected volatile Map<String, Object> attributes;\n\n    protected URL() {\n        this.urlAddress = null;\n        this.urlParam = URLParam.parse(new HashMap<>());\n        this.attributes = null;\n    }\n\n    public URL(URLAddress urlAddress, URLParam urlParam) {\n        this(urlAddress, urlParam, null);\n    }\n\n    public URL(URLAddress urlAddress, URLParam urlParam, Map<String, Object> attributes) {\n        this.urlAddress = urlAddress;\n        this.urlParam = null == urlParam ? URLParam.parse(new HashMap<>()) : urlParam;\n\n        if (attributes != null && !attributes.isEmpty()) {\n            this.attributes = attributes;\n        } else {\n            this.attributes = null;\n        }\n    }\n\n    public URL(String protocol, String host, int port) {\n        this(protocol, null, null, host, port, null, (Map<String, String>) null);\n    }\n\n    public URL(\n            String protocol,\n            String host,\n            int port,\n            String[] pairs) { // varargs ... conflict with the following path argument, use array instead.\n        this(protocol, null, null, host, port, null, CollectionUtils.toStringMap(pairs));\n    }\n\n    public URL(String protocol, String host, int port, Map<String, String> parameters) {\n        this(protocol, null, null, host, port, null, parameters);\n    }\n\n    public URL(String protocol, String host, int port, String path) {\n        this(protocol, null, null, host, port, path, (Map<String, String>) null);\n    }\n\n    public URL(String protocol, String host, int port, String path, String... pairs) {\n        this(protocol, null, null, host, port, path, CollectionUtils.toStringMap(pairs));\n    }\n\n    public URL(String protocol, String host, int port, String path, Map<String, String> parameters) {\n        this(protocol, null, null, host, port, path, parameters);\n    }\n\n    public URL(String protocol, String username, String password, String host, int port, String path) {\n        this(protocol, username, password, host, port, path, (Map<String, String>) null);\n    }\n\n    public URL(String protocol, String username, String password, String host, int port, String path, String... pairs) {\n        this(protocol, username, password, host, port, path, CollectionUtils.toStringMap(pairs));\n    }\n\n    public URL(\n            String protocol,\n            String username,\n            String password,\n            String host,\n            int port,\n            String path,\n            Map<String, String> parameters) {\n        if (StringUtils.isEmpty(username) && StringUtils.isNotEmpty(password)) {\n            throw new IllegalArgumentException(\"Invalid url, password without username!\");\n        }\n\n        this.urlAddress = new PathURLAddress(protocol, username, password, path, host, port);\n        this.urlParam = URLParam.parse(parameters);\n        this.attributes = null;\n    }\n\n    protected URL(\n            String protocol,\n            String username,\n            String password,\n            String host,\n            int port,\n            String path,\n            Map<String, String> parameters,\n            boolean modifiable) {\n        if (StringUtils.isEmpty(username) && StringUtils.isNotEmpty(password)) {\n            throw new IllegalArgumentException(\"Invalid url, password without username!\");\n        }\n\n        this.urlAddress = new PathURLAddress(protocol, username, password, path, host, port);\n        this.urlParam = URLParam.parse(parameters);\n        this.attributes = null;\n    }\n\n    public static URL cacheableValueOf(String url) {\n        URL cachedURL = cachedURLs.get(url);\n        if (cachedURL != null) {\n            return cachedURL;\n        }\n        cachedURL = valueOf(url, false);\n        cachedURLs.put(url, cachedURL);\n        return cachedURL;\n    }\n\n    /**\n     * parse decoded url string, formatted dubbo://host:port/path?param=value, into strutted URL.\n     *\n     * @param url, decoded url string\n     * @return\n     */\n    public static URL valueOf(String url) {\n        return valueOf(url, false);\n    }\n\n    public static URL valueOf(String url, ScopeModel scopeModel) {\n        return valueOf(url).setScopeModel(scopeModel);\n    }\n\n    /**\n     * parse normal or encoded url string into strutted URL:\n     * - dubbo://host:port/path?param=value\n     * - URL.encode(\"dubbo://host:port/path?param=value\")\n     *\n     * @param url,     url string\n     * @param encoded, encoded or decoded\n     * @return\n     */\n    public static URL valueOf(String url, boolean encoded) {\n        if (encoded) {\n            return URLStrParser.parseEncodedStr(url);\n        }\n        return URLStrParser.parseDecodedStr(url);\n    }\n\n    public static URL valueOf(String url, String... reserveParams) {\n        URL result = valueOf(url);\n        if (reserveParams == null || reserveParams.length == 0) {\n            return result;\n        }\n        Map<String, String> newMap = new HashMap<>(reserveParams.length);\n        Map<String, String> oldMap = result.getParameters();\n        for (String reserveParam : reserveParams) {\n            String tmp = oldMap.get(reserveParam);\n            if (StringUtils.isNotEmpty(tmp)) {\n                newMap.put(reserveParam, tmp);\n            }\n        }\n        return result.clearParameters().addParameters(newMap);\n    }\n\n    public static URL valueOf(URL url, String[] reserveParams, String[] reserveParamPrefixes) {\n        Map<String, String> newMap = new HashMap<>();\n        Map<String, String> oldMap = url.getParameters();\n        if (reserveParamPrefixes != null && reserveParamPrefixes.length != 0) {\n            for (Map.Entry<String, String> entry : oldMap.entrySet()) {\n                for (String reserveParamPrefix : reserveParamPrefixes) {\n                    if (entry.getKey().startsWith(reserveParamPrefix) && StringUtils.isNotEmpty(entry.getValue())) {\n                        newMap.put(entry.getKey(), entry.getValue());\n                    }\n                }\n            }\n        }\n\n        if (reserveParams != null) {\n            for (String reserveParam : reserveParams) {\n                String tmp = oldMap.get(reserveParam);\n                if (StringUtils.isNotEmpty(tmp)) {\n                    newMap.put(reserveParam, tmp);\n                }\n            }\n        }\n        return newMap.isEmpty()\n                ? new ServiceConfigURL(\n                        url.getProtocol(),\n                        url.getUsername(),\n                        url.getPassword(),\n                        url.getHost(),\n                        url.getPort(),\n                        url.getPath(),\n                        (Map<String, String>) null,\n                        url.getAttributes())\n                : new ServiceConfigURL(\n                        url.getProtocol(),\n                        url.getUsername(),\n                        url.getPassword(),\n                        url.getHost(),\n                        url.getPort(),\n                        url.getPath(),\n                        newMap,\n                        url.getAttributes());\n    }\n\n    public static String encode(String value) {\n        if (StringUtils.isEmpty(value)) {\n            return \"\";\n        }\n        try {\n            return URLEncoder.encode(value, \"UTF-8\");\n        } catch (UnsupportedEncodingException e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n    }\n\n    public static String decode(String value) {\n        if (StringUtils.isEmpty(value)) {\n            return \"\";\n        }\n        try {\n            return URLDecoder.decode(value, \"UTF-8\");\n        } catch (UnsupportedEncodingException e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n    }\n\n    static String appendDefaultPort(String address, int defaultPort) {\n        if (StringUtils.isNotEmpty(address) && defaultPort > 0) {\n            int i = address.indexOf(':');\n            if (i < 0) {\n                return address + \":\" + defaultPort;\n            } else if (Integer.parseInt(address.substring(i + 1)) == 0) {\n                return address.substring(0, i + 1) + defaultPort;\n            }\n        }\n        return address;\n    }\n\n    public URLAddress getUrlAddress() {\n        return urlAddress;\n    }\n\n    public URLParam getUrlParam() {\n        return urlParam;\n    }\n\n    public String getProtocol() {\n        return urlAddress == null ? null : urlAddress.getProtocol();\n    }\n\n    public URL setProtocol(String protocol) {\n        if (urlAddress == null) {\n            return new ServiceConfigURL(protocol, getHost(), getPort(), getPath(), getParameters());\n        } else {\n            URLAddress newURLAddress = urlAddress.setProtocol(protocol);\n            return returnURL(newURLAddress);\n        }\n    }\n\n    public String getUsername() {\n        return urlAddress == null ? null : urlAddress.getUsername();\n    }\n\n    public URL setUsername(String username) {\n        if (urlAddress == null) {\n            return new ServiceConfigURL(getProtocol(), getHost(), getPort(), getPath(), getParameters())\n                    .setUsername(username);\n        } else {\n            URLAddress newURLAddress = urlAddress.setUsername(username);\n            return returnURL(newURLAddress);\n        }\n    }\n\n    public String getPassword() {\n        return urlAddress == null ? null : urlAddress.getPassword();\n    }\n\n    public URL setPassword(String password) {\n        if (urlAddress == null) {\n            return new ServiceConfigURL(getProtocol(), getHost(), getPort(), getPath(), getParameters())\n                    .setPassword(password);\n        } else {\n            URLAddress newURLAddress = urlAddress.setPassword(password);\n            return returnURL(newURLAddress);\n        }\n    }\n\n    /**\n     * refer to https://datatracker.ietf.org/doc/html/rfc3986\n     *\n     * @return authority\n     */\n    public String getAuthority() {\n        StringBuilder ret = new StringBuilder();\n\n        ret.append(getUserInformation());\n\n        if (StringUtils.isNotEmpty(getHost())) {\n            if (StringUtils.isNotEmpty(getUsername()) || StringUtils.isNotEmpty(getPassword())) {\n                ret.append('@');\n            }\n            ret.append(getHost());\n            if (getPort() != 0) {\n                ret.append(':');\n                ret.append(getPort());\n            }\n        }\n\n        return ret.length() == 0 ? null : ret.toString();\n    }\n\n    /**\n     * refer to https://datatracker.ietf.org/doc/html/rfc3986\n     *\n     * @return user information\n     */\n    public String getUserInformation() {\n        StringBuilder ret = new StringBuilder();\n\n        if (StringUtils.isEmpty(getUsername()) && StringUtils.isEmpty(getPassword())) {\n            return ret.toString();\n        }\n\n        if (StringUtils.isNotEmpty(getUsername())) {\n            ret.append(getUsername());\n        }\n\n        ret.append(':');\n\n        if (StringUtils.isNotEmpty(getPassword())) {\n            ret.append(getPassword());\n        }\n\n        return ret.length() == 0 ? null : ret.toString();\n    }\n\n    public String getHost() {\n        return urlAddress == null ? null : urlAddress.getHost();\n    }\n\n    public URL setHost(String host) {\n        if (urlAddress == null) {\n            return new ServiceConfigURL(getProtocol(), host, getPort(), getPath(), getParameters());\n        } else {\n            URLAddress newURLAddress = urlAddress.setHost(host);\n            return returnURL(newURLAddress);\n        }\n    }\n\n    public int getPort() {\n        return urlAddress == null ? 0 : urlAddress.getPort();\n    }\n\n    public URL setPort(int port) {\n        if (urlAddress == null) {\n            return new ServiceConfigURL(getProtocol(), getHost(), port, getPath(), getParameters());\n        } else {\n            URLAddress newURLAddress = urlAddress.setPort(port);\n            return returnURL(newURLAddress);\n        }\n    }\n\n    public int getPort(int defaultPort) {\n        int port = getPort();\n        return port <= 0 ? defaultPort : port;\n    }\n\n    public String getAddress() {\n        return urlAddress == null ? null : urlAddress.getAddress();\n    }\n\n    public URL setAddress(String address) {\n        int i = address.lastIndexOf(':');\n        String host;\n        int port = this.getPort();\n        if (i >= 0) {\n            host = address.substring(0, i);\n            port = Integer.parseInt(address.substring(i + 1));\n        } else {\n            host = address;\n        }\n        if (urlAddress == null) {\n            return new ServiceConfigURL(getProtocol(), host, port, getPath(), getParameters());\n        } else {\n            URLAddress newURLAddress = urlAddress.setAddress(host, port);\n            return returnURL(newURLAddress);\n        }\n    }\n\n    public String getIp() {\n        return urlAddress == null ? null : urlAddress.getIp();\n    }\n\n    public String getBackupAddress() {\n        return getBackupAddress(0);\n    }\n\n    public String getBackupAddress(int defaultPort) {\n        StringBuilder address = new StringBuilder(appendDefaultPort(getAddress(), defaultPort));\n        String[] backups = getParameter(RemotingConstants.BACKUP_KEY, new String[0]);\n        if (ArrayUtils.isNotEmpty(backups)) {\n            for (String backup : backups) {\n                address.append(',');\n                address.append(appendDefaultPort(backup, defaultPort));\n            }\n        }\n        return address.toString();\n    }\n\n    public List<URL> getBackupUrls() {\n        List<URL> urls = new ArrayList<>();\n        urls.add(this);\n        String[] backups = getParameter(RemotingConstants.BACKUP_KEY, new String[0]);\n        if (ArrayUtils.isNotEmpty(backups)) {\n            for (String backup : backups) {\n                urls.add(this.setAddress(backup));\n            }\n        }\n        return urls;\n    }\n\n    public String getPath() {\n        return urlAddress == null ? null : urlAddress.getPath();\n    }\n\n    public URL setPath(String path) {\n        if (urlAddress == null) {\n            return new ServiceConfigURL(getProtocol(), getHost(), getPort(), path, getParameters());\n        } else {\n            URLAddress newURLAddress = urlAddress.setPath(path);\n            return returnURL(newURLAddress);\n        }\n    }\n\n    public String getAbsolutePath() {\n        String path = getPath();\n        if (path != null && !path.startsWith(\"/\")) {\n            return \"/\" + path;\n        }\n        return path;\n    }\n\n    public Map<String, String> getOriginalParameters() {\n        return this.getParameters();\n    }\n\n    public Map<String, String> getParameters() {\n        return urlParam.getParameters();\n    }\n\n    public Map<String, String> getAllParameters() {\n        return this.getParameters();\n    }\n\n    /**\n     * Get the parameters to be selected(filtered)\n     *\n     * @param nameToSelect the {@link Predicate} to select the parameter name\n     * @return non-null {@link Map}\n     * @since 2.7.8\n     */\n    public Map<String, String> getParameters(Predicate<String> nameToSelect) {\n        Map<String, String> selectedParameters = new LinkedHashMap<>();\n        for (Map.Entry<String, String> entry : getParameters().entrySet()) {\n            String name = entry.getKey();\n            if (nameToSelect.test(name)) {\n                selectedParameters.put(name, entry.getValue());\n            }\n        }\n        return Collections.unmodifiableMap(selectedParameters);\n    }\n\n    public String getParameterAndDecoded(String key) {\n        return getParameterAndDecoded(key, null);\n    }\n\n    public String getParameterAndDecoded(String key, String defaultValue) {\n        return decode(getParameter(key, defaultValue));\n    }\n\n    public String getOriginalParameter(String key) {\n        return getParameter(key);\n    }\n\n    public String getParameter(String key) {\n        return urlParam.getParameter(key);\n    }\n\n    public String getParameter(String key, String defaultValue) {\n        String value = getParameter(key);\n        return StringUtils.isEmpty(value) ? defaultValue : value;\n    }\n\n    public String[] getParameter(String key, String[] defaultValue) {\n        String value = getParameter(key);\n        return StringUtils.isEmpty(value) ? defaultValue : COMMA_SPLIT_PATTERN.split(value);\n    }\n\n    public List<String> getParameter(String key, List<String> defaultValue) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        String[] strArray = COMMA_SPLIT_PATTERN.split(value);\n        return Arrays.asList(strArray);\n    }\n\n    /**\n     * Get parameter\n     *\n     * @param key       the key of parameter\n     * @param valueType the type of parameter value\n     * @param <T>       the type of parameter value\n     * @return get the parameter if present, or <code>null</code>\n     * @since 2.7.8\n     */\n    public <T> T getParameter(String key, Class<T> valueType) {\n        return getParameter(key, valueType, null);\n    }\n\n    /**\n     * Get parameter\n     *\n     * @param key          the key of parameter\n     * @param valueType    the type of parameter value\n     * @param defaultValue the default value if parameter is absent\n     * @param <T>          the type of parameter value\n     * @return get the parameter if present, or <code>defaultValue</code> will be used.\n     * @since 2.7.8\n     */\n    public <T> T getParameter(String key, Class<T> valueType, T defaultValue) {\n        String value = getParameter(key);\n        T result = null;\n        if (!isBlank(value)) {\n            result = getOrDefaultFrameworkModel()\n                    .getBeanFactory()\n                    .getBean(ConverterUtil.class)\n                    .convertIfPossible(value, valueType);\n        }\n        if (result == null) {\n            result = defaultValue;\n        }\n        return result;\n    }\n\n    public URL setScopeModel(ScopeModel scopeModel) {\n        return putAttribute(CommonConstants.SCOPE_MODEL, scopeModel);\n    }\n\n    public ScopeModel getScopeModel() {\n        return (ScopeModel) getAttribute(CommonConstants.SCOPE_MODEL);\n    }\n\n    public FrameworkModel getOrDefaultFrameworkModel() {\n        return ScopeModelUtil.getFrameworkModel(getScopeModel());\n    }\n\n    public ApplicationModel getOrDefaultApplicationModel() {\n        return ScopeModelUtil.getApplicationModel(getScopeModel());\n    }\n\n    public ApplicationModel getApplicationModel() {\n        return ScopeModelUtil.getOrNullApplicationModel(getScopeModel());\n    }\n\n    public ModuleModel getOrDefaultModuleModel() {\n        return ScopeModelUtil.getModuleModel(getScopeModel());\n    }\n\n    public URL setServiceModel(ServiceModel serviceModel) {\n        return putAttribute(CommonConstants.SERVICE_MODEL, serviceModel);\n    }\n\n    public ServiceModel getServiceModel() {\n        return (ServiceModel) getAttribute(CommonConstants.SERVICE_MODEL);\n    }\n\n    public URL getUrlParameter(String key) {\n        String value = getParameterAndDecoded(key);\n        if (StringUtils.isEmpty(value)) {\n            return null;\n        }\n        return URL.valueOf(value);\n    }\n\n    public double getParameter(String key, double defaultValue) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Double.parseDouble(value);\n    }\n\n    public float getParameter(String key, float defaultValue) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Float.parseFloat(value);\n    }\n\n    public long getParameter(String key, long defaultValue) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Long.parseLong(value);\n    }\n\n    public int getParameter(String key, int defaultValue) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Integer.parseInt(value);\n    }\n\n    public short getParameter(String key, short defaultValue) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Short.parseShort(value);\n    }\n\n    public byte getParameter(String key, byte defaultValue) {\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Byte.parseByte(value);\n    }\n\n    public float getPositiveParameter(String key, float defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        float value = getParameter(key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public double getPositiveParameter(String key, double defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        double value = getParameter(key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public long getPositiveParameter(String key, long defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        long value = getParameter(key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public int getPositiveParameter(String key, int defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        int value = getParameter(key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public short getPositiveParameter(String key, short defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        short value = getParameter(key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public byte getPositiveParameter(String key, byte defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        byte value = getParameter(key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public char getParameter(String key, char defaultValue) {\n        String value = getParameter(key);\n        return StringUtils.isEmpty(value) ? defaultValue : value.charAt(0);\n    }\n\n    public boolean getParameter(String key, boolean defaultValue) {\n        String value = getParameter(key);\n        return StringUtils.isEmpty(value) ? defaultValue : Boolean.parseBoolean(value);\n    }\n\n    public boolean hasParameter(String key) {\n        String value = getParameter(key);\n        return StringUtils.isNotEmpty(value);\n    }\n\n    public String getMethodParameterAndDecoded(String method, String key) {\n        return URL.decode(getMethodParameter(method, key));\n    }\n\n    public String getMethodParameterAndDecoded(String method, String key, String defaultValue) {\n        return URL.decode(getMethodParameter(method, key, defaultValue));\n    }\n\n    public String getMethodParameter(String method, String key) {\n        return urlParam.getMethodParameter(method, key);\n    }\n\n    public String getMethodParameterStrict(String method, String key) {\n        return urlParam.getMethodParameterStrict(method, key);\n    }\n\n    public String getMethodParameter(String method, String key, String defaultValue) {\n        String value = getMethodParameter(method, key);\n        return StringUtils.isEmpty(value) ? defaultValue : value;\n    }\n\n    public double getMethodParameter(String method, String key, double defaultValue) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Double.parseDouble(value);\n    }\n\n    public float getMethodParameter(String method, String key, float defaultValue) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Float.parseFloat(value);\n    }\n\n    public long getMethodParameter(String method, String key, long defaultValue) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Long.parseLong(value);\n    }\n\n    public int getMethodParameter(String method, String key, int defaultValue) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Integer.parseInt(value);\n    }\n\n    public short getMethodParameter(String method, String key, short defaultValue) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Short.parseShort(value);\n    }\n\n    public byte getMethodParameter(String method, String key, byte defaultValue) {\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Byte.parseByte(value);\n    }\n\n    public double getMethodPositiveParameter(String method, String key, double defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        double value = getMethodParameter(method, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public float getMethodPositiveParameter(String method, String key, float defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        float value = getMethodParameter(method, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public long getMethodPositiveParameter(String method, String key, long defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        long value = getMethodParameter(method, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public int getMethodPositiveParameter(String method, String key, int defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        int value = getMethodParameter(method, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public short getMethodPositiveParameter(String method, String key, short defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        short value = getMethodParameter(method, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public byte getMethodPositiveParameter(String method, String key, byte defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        byte value = getMethodParameter(method, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public char getMethodParameter(String method, String key, char defaultValue) {\n        String value = getMethodParameter(method, key);\n        return StringUtils.isEmpty(value) ? defaultValue : value.charAt(0);\n    }\n\n    public boolean getMethodParameter(String method, String key, boolean defaultValue) {\n        String value = getMethodParameter(method, key);\n        return StringUtils.isEmpty(value) ? defaultValue : Boolean.parseBoolean(value);\n    }\n\n    public boolean hasMethodParameter(String method, String key) {\n        if (method == null) {\n            String suffix = \".\" + key;\n            for (String fullKey : getParameters().keySet()) {\n                if (fullKey.endsWith(suffix)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n        if (key == null) {\n            String prefix = method + \".\";\n            for (String fullKey : getParameters().keySet()) {\n                if (fullKey.startsWith(prefix)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n        String value = getMethodParameterStrict(method, key);\n        return StringUtils.isNotEmpty(value);\n    }\n\n    public String getAnyMethodParameter(String key) {\n        return urlParam.getAnyMethodParameter(key);\n    }\n\n    public boolean hasMethodParameter(String method) {\n        return urlParam.hasMethodParameter(method);\n    }\n\n    public boolean isLocalHost() {\n        return NetUtils.isLocalHost(getHost()) || getParameter(LOCALHOST_KEY, false);\n    }\n\n    public boolean isAnyHost() {\n        return ANYHOST_VALUE.equals(getHost()) || getParameter(ANYHOST_KEY, false);\n    }\n\n    public URL addParameterAndEncoded(String key, String value) {\n        if (StringUtils.isEmpty(value)) {\n            return this;\n        }\n        return addParameter(key, encode(value));\n    }\n\n    public URL addParameter(String key, boolean value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, char value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, byte value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, short value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, int value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, long value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, float value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, double value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, Enum<?> value) {\n        if (value == null) {\n            return this;\n        }\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, Number value) {\n        if (value == null) {\n            return this;\n        }\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, CharSequence value) {\n        if (value == null || value.length() == 0) {\n            return this;\n        }\n        return addParameter(key, String.valueOf(value));\n    }\n\n    public URL addParameter(String key, String value) {\n        URLParam newParam = urlParam.addParameter(key, value);\n        return returnURL(newParam);\n    }\n\n    public URL addParameterIfAbsent(String key, String value) {\n        URLParam newParam = urlParam.addParameterIfAbsent(key, value);\n        return returnURL(newParam);\n    }\n\n    /**\n     * Add parameters to a new url.\n     *\n     * @param parameters parameters in key-value pairs\n     * @return A new URL\n     */\n    public URL addParameters(Map<String, String> parameters) {\n        URLParam newParam = urlParam.addParameters(parameters);\n        return returnURL(newParam);\n    }\n\n    public URL addParametersIfAbsent(Map<String, String> parameters) {\n        URLParam newURLParam = urlParam.addParametersIfAbsent(parameters);\n        return returnURL(newURLParam);\n    }\n\n    public URL addParameters(String... pairs) {\n        if (ArrayUtils.isEmpty(pairs)) {\n            return this;\n        }\n        if (pairs.length % 2 != 0) {\n            throw new IllegalArgumentException(\"Map pairs can not be odd number.\");\n        }\n        Map<String, String> map = new HashMap<>();\n        int len = pairs.length / 2;\n        for (int i = 0; i < len; i++) {\n            map.put(pairs[2 * i], pairs[2 * i + 1]);\n        }\n        return addParameters(map);\n    }\n\n    public URL addParameterString(String query) {\n        if (StringUtils.isEmpty(query)) {\n            return this;\n        }\n        return addParameters(StringUtils.parseQueryString(query));\n    }\n\n    public URL removeParameter(String key) {\n        if (StringUtils.isEmpty(key)) {\n            return this;\n        }\n        return removeParameters(key);\n    }\n\n    public URL removeParameters(Collection<String> keys) {\n        if (CollectionUtils.isEmpty(keys)) {\n            return this;\n        }\n        return removeParameters(keys.toArray(new String[0]));\n    }\n\n    public URL removeParameters(String... keys) {\n        URLParam newURLParam = urlParam.removeParameters(keys);\n        return returnURL(newURLParam);\n    }\n\n    public URL clearParameters() {\n        URLParam newURLParam = urlParam.clearParameters();\n        return returnURL(newURLParam);\n    }\n\n    public String getRawParameter(String key) {\n        if (PROTOCOL_KEY.equals(key)) {\n            return urlAddress.getProtocol();\n        }\n        if (USERNAME_KEY.equals(key)) {\n            return urlAddress.getUsername();\n        }\n        if (PASSWORD_KEY.equals(key)) {\n            return urlAddress.getPassword();\n        }\n        if (HOST_KEY.equals(key)) {\n            return urlAddress.getHost();\n        }\n        if (PORT_KEY.equals(key)) {\n            return String.valueOf(urlAddress.getPort());\n        }\n        if (PATH_KEY.equals(key)) {\n            return urlAddress.getPath();\n        }\n        return urlParam.getParameter(key);\n    }\n\n    public Map<String, String> toOriginalMap() {\n        Map<String, String> map = new HashMap<>(getOriginalParameters());\n        return addSpecialKeys(map);\n    }\n\n    public Map<String, String> toMap() {\n        Map<String, String> map = new HashMap<>(getParameters());\n        return addSpecialKeys(map);\n    }\n\n    private Map<String, String> addSpecialKeys(Map<String, String> map) {\n        if (getProtocol() != null) {\n            map.put(PROTOCOL_KEY, getProtocol());\n        }\n        if (getUsername() != null) {\n            map.put(USERNAME_KEY, getUsername());\n        }\n        if (getPassword() != null) {\n            map.put(PASSWORD_KEY, getPassword());\n        }\n        if (getHost() != null) {\n            map.put(HOST_KEY, getHost());\n        }\n        if (getPort() > 0) {\n            map.put(PORT_KEY, String.valueOf(getPort()));\n        }\n        if (getPath() != null) {\n            map.put(PATH_KEY, getPath());\n        }\n        if (getAddress() != null) {\n            map.put(ADDRESS_KEY, getAddress());\n        }\n        return map;\n    }\n\n    @Override\n    public String toString() {\n        return buildString(false, true); // no show username and password\n    }\n\n    public String toString(String... parameters) {\n        return buildString(false, true, parameters); // no show username and password\n    }\n\n    public String toIdentityString() {\n        return buildString(true, false); // only return identity message, see the method \"equals\" and \"hashCode\"\n    }\n\n    public String toIdentityString(String... parameters) {\n        return buildString(\n                true, false, parameters); // only return identity message, see the method \"equals\" and \"hashCode\"\n    }\n\n    public String toFullString() {\n        return buildString(true, true);\n    }\n\n    public String toFullString(String... parameters) {\n        return buildString(true, true, parameters);\n    }\n\n    public String toParameterString() {\n        return toParameterString(new String[0]);\n    }\n\n    public String toParameterString(String... parameters) {\n        StringBuilder buf = new StringBuilder();\n        buildParameters(buf, false, parameters);\n        return buf.toString();\n    }\n\n    protected void buildParameters(StringBuilder buf, boolean concat, String[] parameters) {\n        if (CollectionUtils.isNotEmptyMap(getParameters())) {\n            List<String> includes = (ArrayUtils.isEmpty(parameters) ? null : Arrays.asList(parameters));\n            boolean first = true;\n            for (Map.Entry<String, String> entry : new TreeMap<>(getParameters()).entrySet()) {\n                if (StringUtils.isNotEmpty(entry.getKey()) && (includes == null || includes.contains(entry.getKey()))) {\n                    if (first) {\n                        if (concat) {\n                            buf.append('?');\n                        }\n                        first = false;\n                    } else {\n                        buf.append('&');\n                    }\n                    buf.append(entry.getKey());\n                    buf.append('=');\n                    buf.append(entry.getValue() == null ? \"\" : entry.getValue().trim());\n                }\n            }\n        }\n    }\n\n    private String buildString(boolean appendUser, boolean appendParameter, String... parameters) {\n        return buildString(appendUser, appendParameter, false, false, parameters);\n    }\n\n    private String buildString(\n            boolean appendUser, boolean appendParameter, boolean useIP, boolean useService, String... parameters) {\n        StringBuilder buf = new StringBuilder();\n        if (StringUtils.isNotEmpty(getProtocol())) {\n            buf.append(getProtocol());\n            buf.append(\"://\");\n        }\n        if (appendUser && StringUtils.isNotEmpty(getUsername())) {\n            buf.append(getUsername());\n            if (StringUtils.isNotEmpty(getPassword())) {\n                buf.append(':');\n                buf.append(getPassword());\n            }\n            buf.append('@');\n        }\n        String host;\n        if (useIP) {\n            host = urlAddress.getIp();\n        } else {\n            host = getHost();\n        }\n        if (StringUtils.isNotEmpty(host)) {\n            buf.append(host);\n            if (getPort() > 0) {\n                buf.append(':');\n                buf.append(getPort());\n            }\n        }\n        String path;\n        if (useService) {\n            path = getServiceKey();\n        } else {\n            path = getPath();\n        }\n        if (StringUtils.isNotEmpty(path)) {\n            buf.append('/');\n            buf.append(path);\n        }\n\n        if (appendParameter) {\n            buildParameters(buf, true, parameters);\n        }\n        return buf.toString();\n    }\n\n    public java.net.URL toJavaURL() {\n        try {\n            return new java.net.URL(toString());\n        } catch (MalformedURLException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    public InetSocketAddress toInetSocketAddress() {\n        return new InetSocketAddress(getHost(), getPort());\n    }\n\n    /**\n     * The format is \"{interface}:[version]:[group]\"\n     *\n     * @return\n     */\n    public String getColonSeparatedKey() {\n        StringBuilder serviceNameBuilder = new StringBuilder();\n        serviceNameBuilder.append(this.getServiceInterface());\n        append(serviceNameBuilder, VERSION_KEY, false);\n        append(serviceNameBuilder, GROUP_KEY, false);\n        return serviceNameBuilder.toString();\n    }\n\n    /**\n     * The format is \"{interface}:[version]\"\n     *\n     * @return\n     */\n    public String getCompatibleColonSeparatedKey() {\n        StringBuilder serviceNameBuilder = new StringBuilder();\n        serviceNameBuilder.append(this.getServiceInterface());\n        compatibleAppend(serviceNameBuilder, VERSION_KEY);\n        compatibleAppend(serviceNameBuilder, GROUP_KEY);\n        return serviceNameBuilder.toString();\n    }\n\n    private void append(StringBuilder target, String parameterName, boolean first) {\n        String parameterValue = this.getParameter(parameterName);\n        if (!isBlank(parameterValue)) {\n            if (!first) {\n                target.append(':');\n            }\n            target.append(parameterValue);\n        } else {\n            target.append(':');\n        }\n    }\n\n    private void compatibleAppend(StringBuilder target, String parameterName) {\n        String parameterValue = this.getParameter(parameterName);\n        if (!isBlank(parameterValue)) {\n            target.append(':');\n            target.append(parameterValue);\n        }\n    }\n\n    /**\n     * The format of return value is '{group}/{interfaceName}:{version}'\n     *\n     * @return\n     */\n    public String getServiceKey() {\n        if (serviceKey != null) {\n            return serviceKey;\n        }\n        String inf = getServiceInterface();\n        if (inf == null) {\n            return null;\n        }\n        serviceKey = buildKey(inf, getGroup(), getVersion());\n        return serviceKey;\n    }\n\n    /**\n     * Format : interface:version\n     *\n     * @return\n     */\n    public String getDisplayServiceKey() {\n        if (StringUtils.isEmpty(getVersion())) {\n            return getServiceInterface();\n        }\n        return getServiceInterface() + COLON_SEPARATOR + getVersion();\n    }\n\n    /**\n     * The format of return value is '{group}/{path/interfaceName}:{version}'\n     *\n     * @return\n     */\n    public String getPathKey() {\n        String inf = StringUtils.isNotEmpty(getPath()) ? getPath() : getServiceInterface();\n        if (inf == null) {\n            return null;\n        }\n        return buildKey(inf, getGroup(), getVersion());\n    }\n\n    public static String buildKey(String path, String group, String version) {\n        return BaseServiceMetadata.buildServiceKey(path, group, version);\n    }\n\n    public String getProtocolServiceKey() {\n        if (protocolServiceKey != null) {\n            return protocolServiceKey;\n        }\n        this.protocolServiceKey = getServiceKey();\n        /*\n        Special treatment for urls begins with 'consumer://', that is, a consumer subscription url instance with no protocol specified.\n        If protocol is specified on the consumer side, then this method will return as normal.\n        */\n        if (!CONSUMER.equals(getProtocol())) {\n            this.protocolServiceKey += (GROUP_CHAR_SEPARATOR + getProtocol());\n        }\n        return protocolServiceKey;\n    }\n\n    public String toServiceStringWithoutResolving() {\n        return buildString(true, false, false, true);\n    }\n\n    public String toServiceString() {\n        return buildString(true, false, true, true);\n    }\n\n    public String toServiceString(String... parameters) {\n        return buildString(true, true, true, true, parameters);\n    }\n\n    @Deprecated\n    public String getServiceName() {\n        return getServiceInterface();\n    }\n\n    public String getServiceInterface() {\n        return getParameter(INTERFACE_KEY, getPath());\n    }\n\n    public URL setServiceInterface(String service) {\n        return addParameter(INTERFACE_KEY, service);\n    }\n\n    /**\n     * @see #getParameter(String, int)\n     * @deprecated Replace to <code>getParameter(String, int)</code>\n     */\n    @Deprecated\n    public int getIntParameter(String key) {\n        return getParameter(key, 0);\n    }\n\n    /**\n     * @see #getParameter(String, int)\n     * @deprecated Replace to <code>getParameter(String, int)</code>\n     */\n    @Deprecated\n    public int getIntParameter(String key, int defaultValue) {\n        return getParameter(key, defaultValue);\n    }\n\n    /**\n     * @see #getPositiveParameter(String, int)\n     * @deprecated Replace to <code>getPositiveParameter(String, int)</code>\n     */\n    @Deprecated\n    public int getPositiveIntParameter(String key, int defaultValue) {\n        return getPositiveParameter(key, defaultValue);\n    }\n\n    /**\n     * @see #getParameter(String, boolean)\n     * @deprecated Replace to <code>getParameter(String, boolean)</code>\n     */\n    @Deprecated\n    public boolean getBooleanParameter(String key) {\n        return getParameter(key, false);\n    }\n\n    /**\n     * @see #getParameter(String, boolean)\n     * @deprecated Replace to <code>getParameter(String, boolean)</code>\n     */\n    @Deprecated\n    public boolean getBooleanParameter(String key, boolean defaultValue) {\n        return getParameter(key, defaultValue);\n    }\n\n    /**\n     * @see #getMethodParameter(String, String, int)\n     * @deprecated Replace to <code>getMethodParameter(String, String, int)</code>\n     */\n    @Deprecated\n    public int getMethodIntParameter(String method, String key) {\n        return getMethodParameter(method, key, 0);\n    }\n\n    /**\n     * @see #getMethodParameter(String, String, int)\n     * @deprecated Replace to <code>getMethodParameter(String, String, int)</code>\n     */\n    @Deprecated\n    public int getMethodIntParameter(String method, String key, int defaultValue) {\n        return getMethodParameter(method, key, defaultValue);\n    }\n\n    /**\n     * @see #getMethodPositiveParameter(String, String, int)\n     * @deprecated Replace to <code>getMethodPositiveParameter(String, String, int)</code>\n     */\n    @Deprecated\n    public int getMethodPositiveIntParameter(String method, String key, int defaultValue) {\n        return getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    /**\n     * @see #getMethodParameter(String, String, boolean)\n     * @deprecated Replace to <code>getMethodParameter(String, String, boolean)</code>\n     */\n    @Deprecated\n    public boolean getMethodBooleanParameter(String method, String key) {\n        return getMethodParameter(method, key, false);\n    }\n\n    /**\n     * @see #getMethodParameter(String, String, boolean)\n     * @deprecated Replace to <code>getMethodParameter(String, String, boolean)</code>\n     */\n    @Deprecated\n    public boolean getMethodBooleanParameter(String method, String key, boolean defaultValue) {\n        return getMethodParameter(method, key, defaultValue);\n    }\n\n    public Configuration toConfiguration() {\n        InmemoryConfiguration configuration = new InmemoryConfiguration();\n        configuration.addProperties(getParameters());\n        return configuration;\n    }\n\n    private volatile int hashCodeCache = -1;\n\n    @Override\n    public int hashCode() {\n        if (hashCodeCache == -1) {\n            hashCodeCache = Objects.hash(urlAddress, urlParam);\n        }\n        return hashCodeCache;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof URL)) {\n            return false;\n        }\n        URL other = (URL) obj;\n        return Objects.equals(this.getUrlAddress(), other.getUrlAddress())\n                && Objects.equals(this.getUrlParam(), other.getUrlParam());\n    }\n\n    public static void putMethodParameter(\n            String method, String key, String value, Map<String, Map<String, String>> methodParameters) {\n        Map<String, String> subParameter = methodParameters.computeIfAbsent(method, k -> new HashMap<>());\n        subParameter.put(key, value);\n    }\n\n    protected <T extends URL> T newURL(URLAddress urlAddress, URLParam urlParam) {\n        return (T) new ServiceConfigURL(urlAddress, urlParam, attributes);\n    }\n\n    /* methods introduced for CompositeURL, CompositeURL must override to make the implementations meaningful */\n\n    public String getApplication(String defaultValue) {\n        String value = getApplication();\n        return StringUtils.isEmpty(value) ? defaultValue : value;\n    }\n\n    public String getApplication() {\n        return getParameter(APPLICATION_KEY);\n    }\n\n    public String getRemoteApplication() {\n        return getParameter(REMOTE_APPLICATION_KEY);\n    }\n\n    public String getGroup() {\n        return getParameter(GROUP_KEY);\n    }\n\n    public String getGroup(String defaultValue) {\n        String value = getGroup();\n        return StringUtils.isEmpty(value) ? defaultValue : value;\n    }\n\n    public String getVersion() {\n        return getParameter(VERSION_KEY);\n    }\n\n    public String getVersion(String defaultValue) {\n        String value = getVersion();\n        return StringUtils.isEmpty(value) ? defaultValue : value;\n    }\n\n    public String getConcatenatedParameter(String key) {\n        return getParameter(key);\n    }\n\n    public String getCategory(String defaultValue) {\n        String value = getCategory();\n        if (StringUtils.isEmpty(value)) {\n            value = defaultValue;\n        }\n        return value;\n    }\n\n    public String[] getCategory(String[] defaultValue) {\n        String value = getCategory();\n        return StringUtils.isEmpty(value) ? defaultValue : COMMA_SPLIT_PATTERN.split(value);\n    }\n\n    public String getCategory() {\n        return getParameter(CATEGORY_KEY);\n    }\n\n    public String getSide(String defaultValue) {\n        String value = getSide();\n        return StringUtils.isEmpty(value) ? defaultValue : value;\n    }\n\n    public String getSide() {\n        return getParameter(SIDE_KEY);\n    }\n\n    /* Service Config URL, START*/\n    public Map<String, Object> getAttributes() {\n        return attributes == null ? Collections.emptyMap() : attributes;\n    }\n\n    public URL addAttributes(Map<String, Object> attributeMap) {\n        if (attributeMap != null) {\n            attributes.putAll(attributeMap);\n        }\n        return this;\n    }\n\n    public Object getAttribute(String key) {\n        return attributes == null ? null : attributes.get(key);\n    }\n\n    public Object getAttribute(String key, Object defaultValue) {\n        Object val = attributes == null ? null : attributes.get(key);\n        return val != null ? val : defaultValue;\n    }\n\n    public URL putAttribute(String key, Object obj) {\n        if (attributes == null) {\n            this.attributes = new HashMap<>();\n        }\n        attributes.put(key, obj);\n        return this;\n    }\n\n    public URL removeAttribute(String key) {\n        if (attributes != null) {\n            attributes.remove(key);\n        }\n        return this;\n    }\n\n    public boolean hasAttribute(String key) {\n        return attributes != null && attributes.containsKey(key);\n    }\n\n    /* Service Config URL, END*/\n\n    private URL returnURL(URLAddress newURLAddress) {\n        if (urlAddress == newURLAddress) {\n            return this;\n        }\n        return newURL(newURLAddress, urlParam);\n    }\n\n    private URL returnURL(URLParam newURLParam) {\n        if (urlParam == newURLParam) {\n            return this;\n        }\n        return newURL(urlAddress, newURLParam);\n    }\n\n    /* add service scope operations, see InstanceAddressURL */\n    public Map<String, String> getOriginalServiceParameters(String service) {\n        return getServiceParameters(service);\n    }\n\n    public Map<String, String> getServiceParameters(String service) {\n        return getParameters();\n    }\n\n    public String getOriginalServiceParameter(String service, String key) {\n        return this.getServiceParameter(service, key);\n    }\n\n    public String getServiceParameter(String service, String key) {\n        return getParameter(key);\n    }\n\n    public String getServiceParameter(String service, String key, String defaultValue) {\n        String value = getServiceParameter(service, key);\n        return StringUtils.isEmpty(value) ? defaultValue : value;\n    }\n\n    public int getServiceParameter(String service, String key, int defaultValue) {\n        return getParameter(key, defaultValue);\n    }\n\n    public double getServiceParameter(String service, String key, double defaultValue) {\n        String value = getServiceParameter(service, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Double.parseDouble(value);\n    }\n\n    public float getServiceParameter(String service, String key, float defaultValue) {\n        String value = getServiceParameter(service, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Float.parseFloat(value);\n    }\n\n    public long getServiceParameter(String service, String key, long defaultValue) {\n        String value = getServiceParameter(service, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Long.parseLong(value);\n    }\n\n    public short getServiceParameter(String service, String key, short defaultValue) {\n        String value = getServiceParameter(service, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Short.parseShort(value);\n    }\n\n    public byte getServiceParameter(String service, String key, byte defaultValue) {\n        String value = getServiceParameter(service, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Byte.parseByte(value);\n    }\n\n    public char getServiceParameter(String service, String key, char defaultValue) {\n        String value = getServiceParameter(service, key);\n        return StringUtils.isEmpty(value) ? defaultValue : value.charAt(0);\n    }\n\n    public boolean getServiceParameter(String service, String key, boolean defaultValue) {\n        String value = getServiceParameter(service, key);\n        return StringUtils.isEmpty(value) ? defaultValue : Boolean.parseBoolean(value);\n    }\n\n    public boolean hasServiceParameter(String service, String key) {\n        String value = getServiceParameter(service, key);\n        return StringUtils.isNotEmpty(value);\n    }\n\n    public float getPositiveServiceParameter(String service, String key, float defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        float value = getServiceParameter(service, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public double getPositiveServiceParameter(String service, String key, double defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        double value = getServiceParameter(service, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public long getPositiveServiceParameter(String service, String key, long defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        long value = getServiceParameter(service, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public int getPositiveServiceParameter(String service, String key, int defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        int value = getServiceParameter(service, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public short getPositiveServiceParameter(String service, String key, short defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        short value = getServiceParameter(service, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public byte getPositiveServiceParameter(String service, String key, byte defaultValue) {\n        if (defaultValue <= 0) {\n            throw new IllegalArgumentException(\"defaultValue <= 0\");\n        }\n        byte value = getServiceParameter(service, key, defaultValue);\n        return value <= 0 ? defaultValue : value;\n    }\n\n    public String getServiceMethodParameterAndDecoded(String service, String method, String key) {\n        return URL.decode(getServiceMethodParameter(service, method, key));\n    }\n\n    public String getServiceMethodParameterAndDecoded(String service, String method, String key, String defaultValue) {\n        return URL.decode(getServiceMethodParameter(service, method, key, defaultValue));\n    }\n\n    public String getServiceMethodParameterStrict(String service, String method, String key) {\n        return getMethodParameterStrict(method, key);\n    }\n\n    public String getServiceMethodParameter(String service, String method, String key) {\n        return getMethodParameter(method, key);\n    }\n\n    public String getServiceMethodParameter(String service, String method, String key, String defaultValue) {\n        String value = getServiceMethodParameter(service, method, key);\n        return StringUtils.isEmpty(value) ? defaultValue : value;\n    }\n\n    public double getServiceMethodParameter(String service, String method, String key, double defaultValue) {\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Double.parseDouble(value);\n    }\n\n    public float getServiceMethodParameter(String service, String method, String key, float defaultValue) {\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Float.parseFloat(value);\n    }\n\n    public long getServiceMethodParameter(String service, String method, String key, long defaultValue) {\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Long.parseLong(value);\n    }\n\n    public int getServiceMethodParameter(String service, String method, String key, int defaultValue) {\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Integer.parseInt(value);\n    }\n\n    public short getServiceMethodParameter(String service, String method, String key, short defaultValue) {\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Short.parseShort(value);\n    }\n\n    public byte getServiceMethodParameter(String service, String method, String key, byte defaultValue) {\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        return Byte.parseByte(value);\n    }\n\n    public boolean hasServiceMethodParameter(String service, String method, String key) {\n        return hasMethodParameter(method, key);\n    }\n\n    public boolean hasServiceMethodParameter(String service, String method) {\n        return hasMethodParameter(method);\n    }\n\n    public URL toSerializableURL() {\n        return returnURL(URLPlainParam.toURLPlainParam(urlParam));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/URLBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SCOPE_MODEL;\n\npublic final class URLBuilder extends ServiceConfigURL {\n    private String protocol;\n\n    private String username;\n\n    private String password;\n\n    // by default, host to registry\n    private String host;\n\n    // by default, port to registry\n    private int port;\n\n    private String path;\n\n    private final Map<String, String> parameters;\n\n    private final Map<String, Object> attributes;\n\n    private Map<String, Map<String, String>> methodParameters;\n\n    public URLBuilder() {\n        protocol = null;\n        username = null;\n        password = null;\n        host = null;\n        port = 0;\n        path = null;\n        parameters = new HashMap<>();\n        attributes = new HashMap<>();\n        methodParameters = new HashMap<>();\n    }\n\n    public URLBuilder(String protocol, String host, int port) {\n        this(protocol, null, null, host, port, null, null);\n    }\n\n    public URLBuilder(String protocol, String host, int port, String[] pairs) {\n        this(protocol, null, null, host, port, null, CollectionUtils.toStringMap(pairs));\n    }\n\n    public URLBuilder(String protocol, String host, int port, Map<String, String> parameters) {\n        this(protocol, null, null, host, port, null, parameters);\n    }\n\n    public URLBuilder(String protocol, String host, int port, String path) {\n        this(protocol, null, null, host, port, path, null);\n    }\n\n    public URLBuilder(String protocol, String host, int port, String path, String... pairs) {\n        this(protocol, null, null, host, port, path, CollectionUtils.toStringMap(pairs));\n    }\n\n    public URLBuilder(String protocol, String host, int port, String path, Map<String, String> parameters) {\n        this(protocol, null, null, host, port, path, parameters);\n    }\n\n    public URLBuilder(\n            String protocol,\n            String username,\n            String password,\n            String host,\n            int port,\n            String path,\n            Map<String, String> parameters) {\n        this(protocol, username, password, host, port, path, parameters, null);\n    }\n\n    public URLBuilder(\n            String protocol,\n            String username,\n            String password,\n            String host,\n            int port,\n            String path,\n            Map<String, String> parameters,\n            Map<String, Object> attributes) {\n        this.protocol = protocol;\n        this.username = username;\n        this.password = password;\n        this.host = host;\n        this.port = port;\n        this.path = path;\n        this.parameters = parameters != null ? parameters : new HashMap<>();\n        this.attributes = attributes != null ? attributes : new HashMap<>();\n    }\n\n    public static URLBuilder from(URL url) {\n        String protocol = url.getProtocol();\n        String username = url.getUsername();\n        String password = url.getPassword();\n        String host = url.getHost();\n        int port = url.getPort();\n        String path = url.getPath();\n        Map<String, String> parameters = new HashMap<>(url.getParameters());\n        Map<String, Object> attributes = new HashMap<>(url.getAttributes());\n        return new URLBuilder(protocol, username, password, host, port, path, parameters, attributes);\n    }\n\n    public ServiceConfigURL build() {\n        if (StringUtils.isEmpty(username) && StringUtils.isNotEmpty(password)) {\n            throw new IllegalArgumentException(\"Invalid url, password without username!\");\n        }\n        port = Math.max(port, 0);\n        // trim the leading \"/\"\n        int firstNonSlash = 0;\n        if (path != null) {\n            while (firstNonSlash < path.length() && path.charAt(firstNonSlash) == '/') {\n                firstNonSlash++;\n            }\n            if (firstNonSlash >= path.length()) {\n                path = \"\";\n            } else if (firstNonSlash > 0) {\n                path = path.substring(firstNonSlash);\n            }\n        }\n        return new ServiceConfigURL(protocol, username, password, host, port, path, parameters, attributes);\n    }\n\n    @Override\n    public URLBuilder putAttribute(String key, Object obj) {\n        attributes.put(key, obj);\n        return this;\n    }\n\n    @Override\n    public URLBuilder removeAttribute(String key) {\n        attributes.remove(key);\n        return this;\n    }\n\n    @Override\n    public URLBuilder setProtocol(String protocol) {\n        this.protocol = protocol;\n        return this;\n    }\n\n    @Override\n    public URLBuilder setUsername(String username) {\n        this.username = username;\n        return this;\n    }\n\n    @Override\n    public URLBuilder setPassword(String password) {\n        this.password = password;\n        return this;\n    }\n\n    @Override\n    public URLBuilder setHost(String host) {\n        this.host = host;\n        return this;\n    }\n\n    @Override\n    public URLBuilder setPort(int port) {\n        this.port = port;\n        return this;\n    }\n\n    @Override\n    public URLBuilder setAddress(String address) {\n        int i = address.lastIndexOf(':');\n        String host;\n        int port = this.port;\n        if (i >= 0) {\n            host = address.substring(0, i);\n            port = Integer.parseInt(address.substring(i + 1));\n        } else {\n            host = address;\n        }\n        this.host = host;\n        this.port = port;\n        return this;\n    }\n\n    @Override\n    public URLBuilder setPath(String path) {\n        this.path = path;\n        return this;\n    }\n\n    @Override\n    public URLBuilder setScopeModel(ScopeModel scopeModel) {\n        this.attributes.put(SCOPE_MODEL, scopeModel);\n        return this;\n    }\n\n    @Override\n    public URLBuilder addParameterAndEncoded(String key, String value) {\n        if (StringUtils.isEmpty(value)) {\n            return this;\n        }\n        return addParameter(key, URL.encode(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, boolean value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, char value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, byte value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, short value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, int value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, long value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, float value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, double value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, Enum<?> value) {\n        if (value == null) {\n            return this;\n        }\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, Number value) {\n        if (value == null) {\n            return this;\n        }\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, CharSequence value) {\n        if (value == null || value.length() == 0) {\n            return this;\n        }\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URLBuilder addParameter(String key, String value) {\n        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {\n            return this;\n        }\n\n        parameters.put(key, value);\n        return this;\n    }\n\n    public URLBuilder addMethodParameter(String method, String key, String value) {\n        if (StringUtils.isEmpty(method) || StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {\n            return this;\n        }\n        URL.putMethodParameter(method, key, value, methodParameters);\n        return this;\n    }\n\n    @Override\n    public URLBuilder addParameterIfAbsent(String key, String value) {\n        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {\n            return this;\n        }\n        if (hasParameter(key)) {\n            return this;\n        }\n        parameters.put(key, value);\n        return this;\n    }\n\n    public URLBuilder addMethodParameterIfAbsent(String method, String key, String value) {\n        if (StringUtils.isEmpty(method) || StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {\n            return this;\n        }\n        if (hasMethodParameter(method, key)) {\n            return this;\n        }\n        URL.putMethodParameter(method, key, value, methodParameters);\n        return this;\n    }\n\n    @Override\n    public URLBuilder addParameters(Map<String, String> parameters) {\n        if (CollectionUtils.isEmptyMap(parameters)) {\n            return this;\n        }\n\n        boolean hasAndEqual = true;\n        for (Map.Entry<String, String> entry : parameters.entrySet()) {\n            String oldValue = this.parameters.get(entry.getKey());\n            String newValue = entry.getValue();\n            if (!Objects.equals(oldValue, newValue)) {\n                hasAndEqual = false;\n                break;\n            }\n        }\n        // return immediately if there's no change\n        if (hasAndEqual) {\n            return this;\n        }\n\n        this.parameters.putAll(parameters);\n        return this;\n    }\n\n    public URLBuilder addMethodParameters(Map<String, Map<String, String>> methodParameters) {\n        if (CollectionUtils.isEmptyMap(methodParameters)) {\n            return this;\n        }\n\n        this.methodParameters.putAll(methodParameters);\n        return this;\n    }\n\n    @Override\n    public URLBuilder addParametersIfAbsent(Map<String, String> parameters) {\n        if (CollectionUtils.isEmptyMap(parameters)) {\n            return this;\n        }\n        for (Map.Entry<String, String> entry : parameters.entrySet()) {\n            this.parameters.putIfAbsent(entry.getKey(), entry.getValue());\n        }\n        return this;\n    }\n\n    @Override\n    public URLBuilder addParameters(String... pairs) {\n        if (ArrayUtils.isEmpty(pairs)) {\n            return this;\n        }\n        if (pairs.length % 2 != 0) {\n            throw new IllegalArgumentException(\"Map pairs can not be odd number.\");\n        }\n        Map<String, String> map = new HashMap<>();\n        int len = pairs.length / 2;\n        for (int i = 0; i < len; i++) {\n            map.put(pairs[2 * i], pairs[2 * i + 1]);\n        }\n        return addParameters(map);\n    }\n\n    @Override\n    public URLBuilder addParameterString(String query) {\n        if (StringUtils.isEmpty(query)) {\n            return this;\n        }\n        return addParameters(StringUtils.parseQueryString(query));\n    }\n\n    @Override\n    public URLBuilder removeParameter(String key) {\n        if (StringUtils.isEmpty(key)) {\n            return this;\n        }\n        return removeParameters(key);\n    }\n\n    @Override\n    public URLBuilder removeParameters(Collection<String> keys) {\n        if (CollectionUtils.isEmpty(keys)) {\n            return this;\n        }\n        return removeParameters(keys.toArray(new String[0]));\n    }\n\n    @Override\n    public URLBuilder removeParameters(String... keys) {\n        if (ArrayUtils.isEmpty(keys)) {\n            return this;\n        }\n        for (String key : keys) {\n            parameters.remove(key);\n        }\n        return this;\n    }\n\n    @Override\n    public URLBuilder clearParameters() {\n        parameters.clear();\n        return this;\n    }\n\n    @Override\n    public boolean hasParameter(String key) {\n        String value = getParameter(key);\n        return StringUtils.isNotEmpty(value);\n    }\n\n    @Override\n    public boolean hasMethodParameter(String method, String key) {\n        if (method == null) {\n            String suffix = \".\" + key;\n            for (String fullKey : parameters.keySet()) {\n                if (fullKey.endsWith(suffix)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n        if (key == null) {\n            String prefix = method + \".\";\n            for (String fullKey : parameters.keySet()) {\n                if (fullKey.startsWith(prefix)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n        String value = getMethodParameter(method, key);\n        return StringUtils.isNotEmpty(value);\n    }\n\n    @Override\n    public String getParameter(String key) {\n        return parameters.get(key);\n    }\n\n    @Override\n    public String getMethodParameter(String method, String key) {\n        Map<String, String> keyMap = methodParameters.get(method);\n        String value = null;\n        if (keyMap != null) {\n            value = keyMap.get(key);\n        }\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/URLStrParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.url.component.URLItemCache;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;\nimport static org.apache.dubbo.common.utils.StringUtils.EMPTY_STRING;\nimport static org.apache.dubbo.common.utils.StringUtils.decodeHexByte;\nimport static org.apache.dubbo.common.utils.Utf8Utils.decodeUtf8;\n\npublic final class URLStrParser {\n    public static final String ENCODED_QUESTION_MARK = \"%3F\";\n    public static final String ENCODED_TIMESTAMP_KEY = \"timestamp%3D\";\n    public static final String ENCODED_PID_KEY = \"pid%3D\";\n    public static final String ENCODED_AND_MARK = \"%26\";\n    private static final char SPACE = 0x20;\n\n    private static final ThreadLocal<TempBuf> DECODE_TEMP_BUF = ThreadLocal.withInitial(() -> new TempBuf(1024));\n\n    private URLStrParser() {\n        // empty\n    }\n\n    /**\n     * @param decodedURLStr : after {@link URL#decode} string\n     *                      decodedURLStr format: protocol://username:password@host:port/path?k1=v1&k2=v2\n     *                      [protocol://][username:password@][host:port]/[path][?k1=v1&k2=v2]\n     */\n    public static URL parseDecodedStr(String decodedURLStr) {\n        Map<String, String> parameters = null;\n        int pathEndIdx = decodedURLStr.indexOf('?');\n        if (pathEndIdx >= 0) {\n            parameters = parseDecodedParams(decodedURLStr, pathEndIdx + 1);\n        } else {\n            pathEndIdx = decodedURLStr.length();\n        }\n\n        String decodedBody = decodedURLStr.substring(0, pathEndIdx);\n        return parseURLBody(decodedURLStr, decodedBody, parameters);\n    }\n\n    private static Map<String, String> parseDecodedParams(String str, int from) {\n        int len = str.length();\n        if (from >= len) {\n            return Collections.emptyMap();\n        }\n\n        TempBuf tempBuf = DECODE_TEMP_BUF.get();\n        Map<String, String> params = new HashMap<>();\n        int nameStart = from;\n        int valueStart = -1;\n        int i;\n        for (i = from; i < len; i++) {\n            char ch = str.charAt(i);\n            switch (ch) {\n                case '=':\n                    if (nameStart == i) {\n                        nameStart = i + 1;\n                    } else if (valueStart < nameStart) {\n                        valueStart = i + 1;\n                    }\n                    break;\n                case ';':\n                case '&':\n                    addParam(str, false, nameStart, valueStart, i, params, tempBuf);\n                    nameStart = i + 1;\n                    break;\n                default:\n                    // continue\n            }\n        }\n        addParam(str, false, nameStart, valueStart, i, params, tempBuf);\n        return params;\n    }\n\n    /**\n     * @param fullURLStr  : fullURLString\n     * @param decodedBody : format: [protocol://][username:password@][host:port]/[path]\n     * @param parameters  :\n     * @return URL\n     */\n    private static URL parseURLBody(String fullURLStr, String decodedBody, Map<String, String> parameters) {\n        int starIdx = 0, endIdx = decodedBody.length();\n        // ignore the url content following '#'\n        int poundIndex = decodedBody.indexOf('#');\n        if (poundIndex != -1) {\n            endIdx = poundIndex;\n        }\n\n        String protocol = null;\n        int protoEndIdx = decodedBody.indexOf(\"://\");\n        if (protoEndIdx >= 0) {\n            if (protoEndIdx == 0) {\n                throw new IllegalStateException(\"url missing protocol: \\\"\" + fullURLStr + \"\\\"\");\n            }\n            protocol = decodedBody.substring(0, protoEndIdx);\n            starIdx = protoEndIdx + 3;\n        } else {\n            // case: file:/path/to/file.txt\n            protoEndIdx = decodedBody.indexOf(\":/\");\n            if (protoEndIdx >= 0) {\n                if (protoEndIdx == 0) {\n                    throw new IllegalStateException(\"url missing protocol: \\\"\" + fullURLStr + \"\\\"\");\n                }\n                protocol = decodedBody.substring(0, protoEndIdx);\n                starIdx = protoEndIdx + 1;\n            }\n        }\n\n        String path = null;\n        int pathStartIdx = indexOf(decodedBody, '/', starIdx, endIdx);\n        if (pathStartIdx >= 0) {\n            path = decodedBody.substring(pathStartIdx + 1, endIdx);\n            endIdx = pathStartIdx;\n        }\n\n        String username = null;\n        String password = null;\n        int pwdEndIdx = lastIndexOf(decodedBody, '@', starIdx, endIdx);\n        if (pwdEndIdx > 0) {\n            int passwordStartIdx = indexOf(decodedBody, ':', starIdx, pwdEndIdx);\n            if (passwordStartIdx != -1) { // tolerate incomplete user pwd input, like '1234@'\n                username = decodedBody.substring(starIdx, passwordStartIdx);\n                password = decodedBody.substring(passwordStartIdx + 1, pwdEndIdx);\n            } else {\n                username = decodedBody.substring(starIdx, pwdEndIdx);\n            }\n            starIdx = pwdEndIdx + 1;\n        }\n\n        String host = null;\n        int port = 0;\n        int hostEndIdx = lastIndexOf(decodedBody, ':', starIdx, endIdx);\n        if (hostEndIdx > 0 && hostEndIdx < decodedBody.length() - 1) {\n            if (lastIndexOf(decodedBody, '%', starIdx, endIdx) > hostEndIdx) {\n                // ipv6 address with scope id\n                // e.g. fe80:0:0:0:894:aeec:f37d:23e1%en0\n                // see https://howdoesinternetwork.com/2013/ipv6-zone-id\n                // ignore\n            } else {\n                port = Integer.parseInt(decodedBody.substring(hostEndIdx + 1, endIdx));\n                endIdx = hostEndIdx;\n            }\n        }\n\n        if (endIdx > starIdx) {\n            host = decodedBody.substring(starIdx, endIdx);\n        }\n\n        // check cache\n        protocol = URLItemCache.intern(protocol);\n        path = URLItemCache.checkPath(path);\n\n        return new ServiceConfigURL(protocol, username, password, host, port, path, parameters);\n    }\n\n    public static String[] parseRawURLToArrays(String rawURLStr, int pathEndIdx) {\n        String[] parts = new String[2];\n        int paramStartIdx = pathEndIdx + 3; // skip ENCODED_QUESTION_MARK\n        if (pathEndIdx == -1) {\n            pathEndIdx = rawURLStr.indexOf('?');\n            if (pathEndIdx == -1) {\n                // url with no params, decode anyway\n                rawURLStr = URL.decode(rawURLStr);\n            } else {\n                paramStartIdx = pathEndIdx + 1;\n            }\n        }\n        if (pathEndIdx >= 0) {\n            parts[0] = rawURLStr.substring(0, pathEndIdx);\n            parts[1] = rawURLStr.substring(paramStartIdx);\n        } else {\n            parts = new String[] {rawURLStr};\n        }\n        return parts;\n    }\n\n    public static Map<String, String> parseParams(String rawParams, boolean encoded) {\n        if (encoded) {\n            return parseEncodedParams(rawParams, 0);\n        }\n        return parseDecodedParams(rawParams, 0);\n    }\n\n    /**\n     * @param encodedURLStr : after {@link URL#encode(String)} string\n     *                      encodedURLStr after decode format: protocol://username:password@host:port/path?k1=v1&k2=v2\n     *                      [protocol://][username:password@][host:port]/[path][?k1=v1&k2=v2]\n     */\n    public static URL parseEncodedStr(String encodedURLStr) {\n        Map<String, String> parameters = null;\n        int pathEndIdx = encodedURLStr.toUpperCase().indexOf(\"%3F\"); // '?'\n        if (pathEndIdx >= 0) {\n            parameters = parseEncodedParams(encodedURLStr, pathEndIdx + 3);\n        } else {\n            pathEndIdx = encodedURLStr.length();\n        }\n\n        // decodedBody format: [protocol://][username:password@][host:port]/[path]\n        String decodedBody = decodeComponent(encodedURLStr, 0, pathEndIdx, false, DECODE_TEMP_BUF.get());\n        return parseURLBody(encodedURLStr, decodedBody, parameters);\n    }\n\n    private static Map<String, String> parseEncodedParams(String str, int from) {\n        int len = str.length();\n        if (from >= len) {\n            return Collections.emptyMap();\n        }\n\n        TempBuf tempBuf = DECODE_TEMP_BUF.get();\n        Map<String, String> params = new HashMap<>();\n        int nameStart = from;\n        int valueStart = -1;\n        int i;\n        for (i = from; i < len; i++) {\n            char ch = str.charAt(i);\n            if (ch == '%') {\n                if (i + 3 > len) {\n                    throw new IllegalArgumentException(\"unterminated escape sequence at index \" + i + \" of: \" + str);\n                }\n                ch = (char) decodeHexByte(str, i + 1);\n                i += 2;\n            }\n\n            switch (ch) {\n                case '=':\n                    if (nameStart == i) {\n                        nameStart = i + 1;\n                    } else if (valueStart < nameStart) {\n                        valueStart = i + 1;\n                    }\n                    break;\n                case ';':\n                case '&':\n                    addParam(str, true, nameStart, valueStart, i - 2, params, tempBuf);\n                    nameStart = i + 1;\n                    break;\n                default:\n                    // continue\n            }\n        }\n        addParam(str, true, nameStart, valueStart, i, params, tempBuf);\n        return params;\n    }\n\n    private static boolean addParam(\n            String str,\n            boolean isEncoded,\n            int nameStart,\n            int valueStart,\n            int valueEnd,\n            Map<String, String> params,\n            TempBuf tempBuf) {\n        if (nameStart >= valueEnd) {\n            return false;\n        }\n\n        if (valueStart <= nameStart) {\n            valueStart = valueEnd + 1;\n        }\n\n        if (isEncoded) {\n            String name = decodeComponent(str, nameStart, valueStart - 3, false, tempBuf);\n            String value;\n            if (valueStart >= valueEnd) {\n                value = \"\";\n            } else {\n                value = decodeComponent(str, valueStart, valueEnd, false, tempBuf);\n            }\n            URLItemCache.putParams(params, name, value);\n            // compatible with lower versions registering \"default.\" keys\n            if (name.startsWith(DEFAULT_KEY_PREFIX)) {\n                params.putIfAbsent(name.substring(DEFAULT_KEY_PREFIX.length()), value);\n            }\n        } else {\n            String name = str.substring(nameStart, valueStart - 1);\n            String value;\n            if (valueStart >= valueEnd) {\n                value = \"\";\n            } else {\n                value = str.substring(valueStart, valueEnd);\n            }\n            URLItemCache.putParams(params, name, value);\n            // compatible with lower versions registering \"default.\" keys\n            if (name.startsWith(DEFAULT_KEY_PREFIX)) {\n                params.putIfAbsent(name.substring(DEFAULT_KEY_PREFIX.length()), value);\n            }\n        }\n        return true;\n    }\n\n    private static String decodeComponent(String s, int from, int toExcluded, boolean isPath, TempBuf tempBuf) {\n        int len = toExcluded - from;\n        if (len <= 0) {\n            return EMPTY_STRING;\n        }\n\n        int firstEscaped = -1;\n        for (int i = from; i < toExcluded; i++) {\n            char c = s.charAt(i);\n            if (c == '%' || c == '+' && !isPath) {\n                firstEscaped = i;\n                break;\n            }\n        }\n        if (firstEscaped == -1) {\n            return s.substring(from, toExcluded);\n        }\n\n        // Each encoded byte takes 3 characters (e.g. \"%20\")\n        int decodedCapacity = (toExcluded - firstEscaped) / 3;\n        byte[] buf = tempBuf.byteBuf(decodedCapacity);\n        char[] charBuf = tempBuf.charBuf(len);\n        s.getChars(from, firstEscaped, charBuf, 0);\n\n        int charBufIdx = firstEscaped - from;\n        return decodeUtf8Component(s, firstEscaped, toExcluded, isPath, buf, charBuf, charBufIdx);\n    }\n\n    private static String decodeUtf8Component(\n            String str, int firstEscaped, int toExcluded, boolean isPath, byte[] buf, char[] charBuf, int charBufIdx) {\n        int bufIdx;\n        for (int i = firstEscaped; i < toExcluded; i++) {\n            char c = str.charAt(i);\n            if (c != '%') {\n                charBuf[charBufIdx++] = c != '+' || isPath ? c : SPACE;\n                continue;\n            }\n\n            bufIdx = 0;\n            do {\n                if (i + 3 > toExcluded) {\n                    throw new IllegalArgumentException(\"unterminated escape sequence at index \" + i + \" of: \" + str);\n                }\n                buf[bufIdx++] = decodeHexByte(str, i + 1);\n                i += 3;\n            } while (i < toExcluded && str.charAt(i) == '%');\n            i--;\n\n            charBufIdx += decodeUtf8(buf, 0, bufIdx, charBuf, charBufIdx);\n        }\n        return new String(charBuf, 0, charBufIdx);\n    }\n\n    private static int indexOf(String str, char ch, int from, int toExclude) {\n        from = Math.max(from, 0);\n        toExclude = Math.min(toExclude, str.length());\n        if (from > toExclude) {\n            return -1;\n        }\n\n        for (int i = from; i < toExclude; i++) {\n            if (str.charAt(i) == ch) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    private static int lastIndexOf(String str, char ch, int from, int toExclude) {\n        from = Math.max(from, 0);\n        toExclude = Math.min(toExclude, str.length() - 1);\n        if (from > toExclude) {\n            return -1;\n        }\n\n        for (int i = toExclude; i >= from; i--) {\n            if (str.charAt(i) == ch) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    private static final class TempBuf {\n\n        private final char[] chars;\n\n        private final byte[] bytes;\n\n        TempBuf(int bufSize) {\n            this.chars = new char[bufSize];\n            this.bytes = new byte[bufSize];\n        }\n\n        public char[] charBuf(int size) {\n            char[] chars = this.chars;\n            if (size <= chars.length) {\n                return chars;\n            }\n            return new char[size];\n        }\n\n        public byte[] byteBuf(int size) {\n            byte[] bytes = this.bytes;\n            if (size <= bytes.length) {\n                return bytes;\n            }\n            return new byte[size];\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/Version.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.security.CodeSource;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\npublic final class Version {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(Version.class);\n\n    private static final Pattern PREFIX_DIGITS_PATTERN = Pattern.compile(\"^([0-9]*).*\");\n\n    // Dubbo RPC protocol version, for compatibility, it must not be between 2.0.10 ~ 2.6.2\n    public static final String DEFAULT_DUBBO_PROTOCOL_VERSION = \"2.0.2\";\n    // version 1.0.0 represents Dubbo rpc protocol before v2.6.2\n    public static final int LEGACY_DUBBO_PROTOCOL_VERSION = 10000; // 1.0.0\n    // Dubbo implementation version.\n    private static String VERSION;\n    private static String LATEST_COMMIT_ID;\n\n    /**\n     * For protocol compatibility purpose.\n     * Because {@link #isSupportResponseAttachment} is checked for every call, int compare expect to has higher\n     * performance than string.\n     */\n    public static final int LOWEST_VERSION_FOR_RESPONSE_ATTACHMENT = 2000200; // 2.0.2\n\n    public static final int HIGHEST_PROTOCOL_VERSION = 2009900; // 2.0.99\n    private static final Map<String, Integer> VERSION2INT = new HashMap<>();\n\n    static {\n        // get dubbo version and last commit id\n        try {\n            tryLoadVersionFromResource();\n            checkDuplicate();\n        } catch (Throwable e) {\n            logger.warn(\n                    COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"continue the old logic, ignore exception \" + e.getMessage(),\n                    e);\n        }\n        if (StringUtils.isEmpty(VERSION)) {\n            VERSION = getVersion(Version.class, \"\");\n        }\n        if (StringUtils.isEmpty(LATEST_COMMIT_ID)) {\n            LATEST_COMMIT_ID = \"\";\n        }\n    }\n\n    private static void tryLoadVersionFromResource() throws IOException {\n        Enumeration<URL> configLoader =\n                Version.class.getClassLoader().getResources(CommonConstants.DUBBO_VERSIONS_KEY + \"/dubbo-common\");\n        if (configLoader.hasMoreElements()) {\n            URL url = configLoader.nextElement();\n            try (BufferedReader reader =\n                    new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {\n                String line;\n                while ((line = reader.readLine()) != null) {\n                    if (line.startsWith(\"revision=\")) {\n                        VERSION = line.substring(\"revision=\".length());\n                    } else if (line.startsWith(\"git.commit.id=\")) {\n                        LATEST_COMMIT_ID = line.substring(\"git.commit.id=\".length());\n                    }\n                }\n            }\n        }\n    }\n\n    private Version() {}\n\n    public static String getProtocolVersion() {\n        return DEFAULT_DUBBO_PROTOCOL_VERSION;\n    }\n\n    public static String getVersion() {\n        return VERSION;\n    }\n\n    public static String getLastCommitId() {\n        return LATEST_COMMIT_ID;\n    }\n\n    /**\n     * Compare versions\n     *\n     * @return the value {@code 0} if {@code version1 == version2};\n     * a value less than {@code 0} if {@code version1 < version2}; and\n     * a value greater than {@code 0} if {@code version1 > version2}\n     */\n    public static int compare(String version1, String version2) {\n        return Integer.compare(getIntVersion(version1), getIntVersion(version2));\n    }\n\n    /**\n     * Check the framework release version number to decide if it's 2.7.0 or higher\n     */\n    public static boolean isRelease270OrHigher(String version) {\n        if (StringUtils.isEmpty(version)) {\n            return false;\n        }\n\n        return getIntVersion(version) >= 2070000;\n    }\n\n    /**\n     * Check the framework release version number to decide if it's 2.6.3 or higher\n     *\n     * @param version, the sdk version\n     */\n    public static boolean isRelease263OrHigher(String version) {\n        return getIntVersion(version) >= 2060300;\n    }\n\n    /**\n     * Dubbo 2.x protocol version numbers are limited to 2.0.2/2000200 ~ 2.0.99/2009900, other versions are consider as\n     * invalid or not from official release.\n     *\n     * @param version, the protocol version.\n     * @return\n     */\n    public static boolean isSupportResponseAttachment(String version) {\n        if (StringUtils.isEmpty(version)) {\n            return false;\n        }\n        int iVersion = getIntVersion(version);\n        if (iVersion >= LOWEST_VERSION_FOR_RESPONSE_ATTACHMENT && iVersion <= HIGHEST_PROTOCOL_VERSION) {\n            return true;\n        }\n\n        return false;\n    }\n\n    public static int getIntVersion(String version) {\n        Integer v = VERSION2INT.get(version);\n        if (v == null) {\n            try {\n                v = parseInt(version);\n                // e.g., version number 2.6.3 will convert to 2060300\n                if (version.split(\"\\\\.\").length == 3) {\n                    v = v * 100;\n                }\n            } catch (Exception e) {\n                logger.warn(\n                        COMMON_UNEXPECTED_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Please make sure your version value has the right format: \"\n                                + \"\\n 1. only contains digital number: 2.0.0; \\n 2. with string suffix: 2.6.7-stable. \"\n                                + \"\\nIf you are using Dubbo before v2.6.2, the version value is the same with the jar version.\");\n                v = LEGACY_DUBBO_PROTOCOL_VERSION;\n            }\n            VERSION2INT.put(version, v);\n        }\n        return v;\n    }\n\n    private static int parseInt(String version) {\n        int v = 0;\n        String[] vArr = version.split(\"\\\\.\");\n        int len = vArr.length;\n        for (int i = 0; i < len; i++) {\n            String subV = getPrefixDigits(vArr[i]);\n            if (StringUtils.isNotEmpty(subV)) {\n                v += Integer.parseInt(subV) * Math.pow(10, (len - i - 1) * 2);\n            }\n        }\n        return v;\n    }\n\n    /**\n     * get prefix digits from given version string\n     */\n    private static String getPrefixDigits(String v) {\n        Matcher matcher = PREFIX_DIGITS_PATTERN.matcher(v);\n        if (matcher.find()) {\n            return matcher.group(1);\n        }\n        return \"\";\n    }\n\n    public static String getVersion(Class<?> cls, String defaultVersion) {\n        try {\n            // find version info from MANIFEST.MF first\n            Package pkg = cls.getPackage();\n            String version = null;\n            if (pkg != null) {\n                version = pkg.getImplementationVersion();\n                if (StringUtils.isNotEmpty(version)) {\n                    return version;\n                }\n\n                version = pkg.getSpecificationVersion();\n                if (StringUtils.isNotEmpty(version)) {\n                    return version;\n                }\n            }\n\n            // guess version from jar file name if nothing's found from MANIFEST.MF\n            CodeSource codeSource = cls.getProtectionDomain().getCodeSource();\n            if (codeSource == null) {\n                logger.info(\"No codeSource for class \" + cls.getName() + \" when getVersion, use default version \"\n                        + defaultVersion);\n                return defaultVersion;\n            }\n\n            URL location = codeSource.getLocation();\n            if (location == null) {\n                logger.info(\"No location for class \" + cls.getName() + \" when getVersion, use default version \"\n                        + defaultVersion);\n                return defaultVersion;\n            }\n            String file = location.getFile();\n            if (!StringUtils.isEmpty(file) && file.endsWith(\".jar\")) {\n                version = getFromFile(file);\n            }\n\n            // return default version if no version info is found\n            return StringUtils.isEmpty(version) ? defaultVersion : version;\n        } catch (Throwable e) {\n            // return default version when any exception is thrown\n            logger.error(\n                    COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"return default version, ignore exception \" + e.getMessage(),\n                    e);\n            return defaultVersion;\n        }\n    }\n\n    /**\n     * get version from file: path/to/group-module-x.y.z.jar, returns x.y.z\n     */\n    private static String getFromFile(String file) {\n        // remove suffix \".jar\": \"path/to/group-module-x.y.z\"\n        file = file.substring(0, file.length() - 4);\n\n        // remove path: \"group-module-x.y.z\"\n        int i = file.lastIndexOf('/');\n        if (i >= 0) {\n            file = file.substring(i + 1);\n        }\n\n        // remove group: \"module-x.y.z\"\n        i = file.indexOf(\"-\");\n        if (i >= 0) {\n            file = file.substring(i + 1);\n        }\n\n        // remove module: \"x.y.z\"\n        while (file.length() > 0 && !Character.isDigit(file.charAt(0))) {\n            i = file.indexOf(\"-\");\n            if (i >= 0) {\n                file = file.substring(i + 1);\n            } else {\n                break;\n            }\n        }\n        return file;\n    }\n\n    private static void checkDuplicate() {\n        try {\n            checkArtifacts(loadArtifactIds());\n        } catch (Throwable e) {\n            logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", e.getMessage(), e);\n        }\n    }\n\n    private static void checkArtifacts(Set<String> artifactIds) throws IOException {\n        if (!artifactIds.isEmpty()) {\n            for (String artifactId : artifactIds) {\n                checkArtifact(artifactId);\n            }\n        }\n    }\n\n    private static void checkArtifact(String artifactId) throws IOException {\n        Enumeration<URL> artifactEnumeration =\n                Version.class.getClassLoader().getResources(CommonConstants.DUBBO_VERSIONS_KEY + artifactId);\n        while (artifactEnumeration.hasMoreElements()) {\n            URL url = artifactEnumeration.nextElement();\n            try (BufferedReader reader =\n                    new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {\n                String line;\n                while ((line = reader.readLine()) != null) {\n                    if (line.startsWith(\"#\")) {\n                        continue;\n                    }\n                    String[] artifactInfo = line.split(\"=\");\n                    if (artifactInfo.length == 2) {\n                        String key = artifactInfo[0];\n                        String value = artifactInfo[1];\n                        checkVersion(artifactId, url, key, value);\n                    }\n                }\n            }\n        }\n    }\n\n    private static void checkVersion(String artifactId, URL url, String key, String value) {\n        if (\"revision\".equals(key) && !value.equals(VERSION)) {\n            String error = \"Inconsistent version \" + value + \" found in \" + artifactId + \" from \" + url.getPath() + \", \"\n                    + \"expected dubbo-common version is \" + VERSION;\n            logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", error);\n        }\n        if (\"git.commit.id\".equals(key) && !value.equals(LATEST_COMMIT_ID)) {\n            String error = \"Inconsistent git build commit id \" + value + \" found in \" + artifactId + \" from \"\n                    + url.getPath() + \", \" + \"expected dubbo-common version is \" + LATEST_COMMIT_ID;\n            logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", error);\n        }\n    }\n\n    private static Set<String> loadArtifactIds() throws IOException {\n        Enumeration<URL> artifactsEnumeration =\n                Version.class.getClassLoader().getResources(CommonConstants.DUBBO_VERSIONS_KEY + \"/.artifacts\");\n        Set<String> artifactIds = new HashSet<>();\n        while (artifactsEnumeration.hasMoreElements()) {\n            URL url = artifactsEnumeration.nextElement();\n            try (BufferedReader reader =\n                    new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {\n                String line;\n                while ((line = reader.readLine()) != null) {\n                    if (line.startsWith(\"#\")) {\n                        continue;\n                    }\n                    if (StringUtils.isEmpty(line)) {\n                        continue;\n                    }\n                    artifactIds.add(line);\n                }\n            }\n        }\n        return artifactIds;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/aot/NativeDetector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.aot;\n\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ThirdPartyProperty.GRAALVM_NATIVEIMAGE_IMAGECODE;\n\npublic abstract class NativeDetector {\n\n    /**\n     * See https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java\n     */\n    private static final boolean IMAGE_CODE =\n            (SystemPropertyConfigUtils.getSystemProperty(GRAALVM_NATIVEIMAGE_IMAGECODE) != null);\n\n    /**\n     * Returns {@code true} if invoked in the context of image building or during image runtime, else {@code false}.\n     */\n    public static boolean inNativeImage() {\n        return IMAGE_CODE;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/beans/ScopeBeanException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans;\n\npublic class ScopeBeanException extends RuntimeException {\n\n    public ScopeBeanException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public ScopeBeanException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/beans/ScopeBeanExtensionInjector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.extension.ExtensionInjector;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\n/**\n * Inject scope bean to SPI extension instance\n */\npublic class ScopeBeanExtensionInjector implements ExtensionInjector, ScopeModelAware {\n\n    private ScopeBeanFactory beanFactory;\n\n    @Override\n    public void setScopeModel(final ScopeModel scopeModel) {\n        this.beanFactory = scopeModel.getBeanFactory();\n    }\n\n    @Override\n    public <T> T getInstance(final Class<T> type, final String name) {\n        return beanFactory == null ? null : beanFactory.getBean(name, type);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans.factory;\n\nimport org.apache.dubbo.common.beans.ScopeBeanException;\nimport org.apache.dubbo.common.beans.support.InstantiationStrategy;\nimport org.apache.dubbo.common.extension.ExtensionAccessor;\nimport org.apache.dubbo.common.extension.ExtensionAccessorAware;\nimport org.apache.dubbo.common.extension.ExtensionPostProcessor;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.common.resource.Initializable;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.Pair;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.TypeUtils;\nimport org.apache.dubbo.rpc.model.ScopeModelAccessor;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_DESTROY_INVOKER;\n\n/**\n * A bean factory for internal sharing.\n */\npublic final class ScopeBeanFactory {\n\n    private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(ScopeBeanFactory.class);\n\n    private final ScopeBeanFactory parent;\n    private final ExtensionAccessor extensionAccessor;\n    private final List<ExtensionPostProcessor> extensionPostProcessors;\n    private final Map<Class<?>, AtomicInteger> beanNameIdCounterMap = CollectionUtils.newConcurrentHashMap();\n    private final List<BeanInfo> registeredBeanInfos = new CopyOnWriteArrayList<>();\n    private final List<BeanDefinition<?>> registeredBeanDefinitions = new CopyOnWriteArrayList<>();\n    private InstantiationStrategy instantiationStrategy;\n    private final AtomicBoolean destroyed = new AtomicBoolean();\n    private final Set<Class<?>> registeredClasses = new ConcurrentHashSet<>();\n    private final Map<Pair<Class<?>, String>, Optional<Object>> beanCache = CollectionUtils.newConcurrentHashMap();\n\n    public ScopeBeanFactory(ScopeBeanFactory parent, ExtensionAccessor extensionAccessor) {\n        this.parent = parent;\n        this.extensionAccessor = extensionAccessor;\n        extensionPostProcessors = extensionAccessor.getExtensionDirector().getExtensionPostProcessors();\n        initInstantiationStrategy();\n    }\n\n    private void initInstantiationStrategy() {\n        for (ExtensionPostProcessor extensionPostProcessor : extensionPostProcessors) {\n            if (extensionPostProcessor instanceof ScopeModelAccessor) {\n                instantiationStrategy = new InstantiationStrategy((ScopeModelAccessor) extensionPostProcessor);\n                break;\n            }\n        }\n        if (instantiationStrategy == null) {\n            instantiationStrategy = new InstantiationStrategy();\n        }\n    }\n\n    public <T> T registerBean(Class<T> clazz) throws ScopeBeanException {\n        return getOrRegisterBean(null, clazz);\n    }\n\n    public <T> T registerBean(String name, Class<T> clazz) throws ScopeBeanException {\n        return getOrRegisterBean(name, clazz);\n    }\n\n    public <T> void registerBeanDefinition(Class<T> clazz) {\n        registerBeanDefinition(null, clazz);\n    }\n\n    public <T> void registerBeanDefinition(String name, Class<T> clazz) {\n        registeredBeanDefinitions.add(new BeanDefinition<>(name, clazz));\n    }\n\n    public <T> void registerBeanFactory(Supplier<T> factory) {\n        registerBeanFactory(null, factory);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> void registerBeanFactory(String name, Supplier<T> factory) {\n        Class<T> clazz = (Class<T>) TypeUtils.getSuperGenericType(factory.getClass(), 0);\n        if (clazz == null) {\n            throw new ScopeBeanException(\"unable to determine bean class from factory's superclass or interface\");\n        }\n        registeredBeanDefinitions.add(new BeanDefinition<>(name, clazz, factory));\n    }\n\n    private <T> T createAndRegisterBean(String name, Class<T> clazz) {\n        checkDestroyed();\n        T instance = getBean(name, clazz);\n        if (instance != null) {\n            throw new ScopeBeanException(\n                    \"already exists bean with same name and type, name=\" + name + \", type=\" + clazz.getName());\n        }\n        try {\n            instance = instantiationStrategy.instantiate(clazz);\n        } catch (Throwable e) {\n            throw new ScopeBeanException(\"create bean instance failed, type=\" + clazz.getName(), e);\n        }\n        registerBean(name, instance);\n        return instance;\n    }\n\n    public void registerBean(Object bean) {\n        registerBean(null, bean);\n    }\n\n    public void registerBean(String name, Object bean) {\n        checkDestroyed();\n        // avoid duplicated register same bean\n        if (containsBean(name, bean)) {\n            return;\n        }\n\n        Class<?> beanClass = bean.getClass();\n        if (name == null) {\n            name = beanClass.getName() + \"#\" + getNextId(beanClass);\n        }\n        initializeBean(name, bean);\n\n        registeredBeanInfos.add(new BeanInfo(name, bean));\n        beanCache.entrySet().removeIf(e -> e.getKey().getLeft().isAssignableFrom(beanClass));\n    }\n\n    public <T> T getOrRegisterBean(Class<T> type) {\n        return getOrRegisterBean(null, type);\n    }\n\n    @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n    public <T> T getOrRegisterBean(String name, Class<T> type) {\n        T bean = getBean(name, type);\n        if (bean == null) {\n            // lock by type\n            synchronized (type) {\n                bean = getBean(name, type);\n                if (bean == null) {\n                    bean = createAndRegisterBean(name, type);\n                }\n            }\n        }\n        registeredClasses.add(type);\n        return bean;\n    }\n\n    public <T> T getOrRegisterBean(Class<T> type, Function<? super Class<T>, ? extends T> mappingFunction) {\n        return getOrRegisterBean(null, type, mappingFunction);\n    }\n\n    @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n    public <T> T getOrRegisterBean(\n            String name, Class<T> type, Function<? super Class<T>, ? extends T> mappingFunction) {\n        T bean = getBean(name, type);\n        if (bean == null) {\n            // lock by type\n            synchronized (type) {\n                bean = getBean(name, type);\n                if (bean == null) {\n                    bean = mappingFunction.apply(type);\n                    registerBean(name, bean);\n                }\n            }\n        }\n        return bean;\n    }\n\n    private void initializeBean(String name, Object bean) {\n        checkDestroyed();\n        try {\n            if (bean instanceof ExtensionAccessorAware) {\n                ((ExtensionAccessorAware) bean).setExtensionAccessor(extensionAccessor);\n            }\n            for (ExtensionPostProcessor processor : extensionPostProcessors) {\n                processor.postProcessAfterInitialization(bean, name);\n            }\n            if (bean instanceof Initializable) {\n                ((Initializable) bean).initialize(extensionAccessor);\n            }\n        } catch (Exception e) {\n            throw new ScopeBeanException(\n                    \"register bean failed! name=\" + name + \", type=\"\n                            + bean.getClass().getName(),\n                    e);\n        }\n    }\n\n    @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n    private void initializeBeanDefinitions(Class<?> type) {\n        for (int i = 0, size = registeredBeanDefinitions.size(); i < size; i++) {\n            BeanDefinition<?> definition = registeredBeanDefinitions.get(i);\n            if (definition.initialized) {\n                continue;\n            }\n\n            Class<?> beanClass = definition.beanClass;\n            if (!type.isAssignableFrom(beanClass)) {\n                continue;\n            }\n            synchronized (type) {\n                if (definition.initialized) {\n                    continue;\n                }\n\n                Object bean;\n                Supplier<?> factory = definition.beanFactory;\n                if (factory == null) {\n                    try {\n                        bean = instantiationStrategy.instantiate(beanClass);\n                    } catch (Throwable e) {\n                        throw new ScopeBeanException(\"create bean instance failed, type=\" + beanClass.getName(), e);\n                    }\n                } else {\n                    initializeBean(definition.name, factory);\n                    try {\n                        bean = factory.get();\n                    } catch (Exception e) {\n                        throw new ScopeBeanException(\"create bean instance failed, type=\" + beanClass.getName(), e);\n                    }\n                }\n                registerBean(definition.name, bean);\n                definition.initialized = true;\n            }\n        }\n    }\n\n    private boolean containsBean(String name, Object bean) {\n        for (BeanInfo beanInfo : registeredBeanInfos) {\n            if (beanInfo.instance == bean && (name == null || name.equals(beanInfo.name))) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private int getNextId(Class<?> beanClass) {\n        return beanNameIdCounterMap\n                .computeIfAbsent(beanClass, key -> new AtomicInteger())\n                .incrementAndGet();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> List<T> getBeansOfType(Class<T> type) {\n        initializeBeanDefinitions(type);\n        List<T> currentBeans = (List<T>) registeredBeanInfos.stream()\n                .filter(beanInfo -> type.isInstance(beanInfo.instance))\n                .map(beanInfo -> beanInfo.instance)\n                .collect(Collectors.toList());\n        if (parent != null) {\n            currentBeans.addAll(parent.getBeansOfType(type));\n        }\n        return currentBeans;\n    }\n\n    public <T> T getBean(Class<T> type) {\n        return getBean(null, type);\n    }\n\n    public <T> T getBean(String name, Class<T> type) {\n        T bean = getBeanFromCache(name, type);\n        if (bean == null && parent != null) {\n            return parent.getBean(name, type);\n        }\n        return bean;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T> T getBeanFromCache(String name, Class<T> type) {\n        Pair<Class<?>, String> key = Pair.of(type, name);\n        Optional<Object> value = beanCache.get(key);\n        if (value == null) {\n            initializeBeanDefinitions(type);\n            value = beanCache.computeIfAbsent(key, k -> {\n                try {\n                    return Optional.ofNullable(getBeanInternal(name, type));\n                } catch (ScopeBeanException e) {\n                    return Optional.of(e);\n                }\n            });\n        }\n        Object bean = value.orElse(null);\n        if (bean instanceof ScopeBeanException) {\n            throw (ScopeBeanException) bean;\n        }\n        return (T) bean;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T> T getBeanInternal(String name, Class<T> type) {\n        // All classes are derived from java.lang.Object, cannot filter bean by it\n        if (type == Object.class) {\n            return null;\n        }\n        List<BeanInfo> candidates = null;\n        BeanInfo firstCandidate = null;\n        for (BeanInfo beanInfo : registeredBeanInfos) {\n            // if required bean type is same class/superclass/interface of the registered bean\n            if (type.isAssignableFrom(beanInfo.instance.getClass())) {\n                if (StringUtils.isEquals(beanInfo.name, name)) {\n                    return (T) beanInfo.instance;\n                } else {\n                    // optimize for only one matched bean\n                    if (firstCandidate == null) {\n                        firstCandidate = beanInfo;\n                    } else {\n                        if (candidates == null) {\n                            candidates = new ArrayList<>();\n                            candidates.add(firstCandidate);\n                        }\n                        candidates.add(beanInfo);\n                    }\n                }\n            }\n        }\n\n        // if bean name not matched and only single candidate\n        if (candidates != null) {\n            if (candidates.size() == 1) {\n                return (T) candidates.get(0).instance;\n            } else if (candidates.size() > 1) {\n                List<String> candidateBeanNames =\n                        candidates.stream().map(beanInfo -> beanInfo.name).collect(Collectors.toList());\n                throw new ScopeBeanException(\"expected single matching bean but found \" + candidates.size()\n                        + \" candidates for type [\" + type.getName() + \"]: \" + candidateBeanNames);\n            }\n        } else if (firstCandidate != null) {\n            return (T) firstCandidate.instance;\n        }\n        return null;\n    }\n\n    public void destroy() {\n        if (destroyed.compareAndSet(false, true)) {\n            for (BeanInfo beanInfo : registeredBeanInfos) {\n                if (beanInfo.instance instanceof Disposable) {\n                    try {\n                        Disposable beanInstance = (Disposable) beanInfo.instance;\n                        beanInstance.destroy();\n                    } catch (Throwable e) {\n                        LOGGER.error(\n                                CONFIG_FAILED_DESTROY_INVOKER,\n                                \"\",\n                                \"\",\n                                \"An error occurred when destroy bean [name=\" + beanInfo.name + \", bean=\"\n                                        + beanInfo.instance + \"]: \" + e,\n                                e);\n                    }\n                }\n            }\n            registeredBeanInfos.clear();\n            registeredBeanDefinitions.clear();\n            beanCache.clear();\n        }\n    }\n\n    public boolean isDestroyed() {\n        return destroyed.get();\n    }\n\n    private void checkDestroyed() {\n        if (destroyed.get()) {\n            throw new IllegalStateException(\"ScopeBeanFactory is destroyed\");\n        }\n    }\n\n    static final class BeanInfo {\n        private final String name;\n        private final Object instance;\n\n        BeanInfo(String name, Object instance) {\n            this.name = name;\n            this.instance = instance;\n        }\n    }\n\n    static final class BeanDefinition<T> {\n\n        private final String name;\n        private final Class<T> beanClass;\n        private final Supplier<T> beanFactory;\n        private volatile boolean initialized;\n\n        BeanDefinition(String name, Class<T> beanClass) {\n            this.name = name;\n            this.beanClass = beanClass;\n            beanFactory = null;\n        }\n\n        BeanDefinition(String name, Class<T> beanClass, Supplier<T> beanFactory) {\n            this.name = name;\n            this.beanClass = beanClass;\n            this.beanFactory = beanFactory;\n        }\n    }\n\n    public Set<Class<?>> getRegisteredClasses() {\n        return registeredClasses;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/beans/support/InstantiationStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans.support;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAccessor;\n\nimport java.lang.reflect.Constructor;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Interface to create instance for specify type, using both in {@link ExtensionLoader} and {@link ScopeBeanFactory}.\n */\npublic class InstantiationStrategy {\n\n    private final ScopeModelAccessor scopeModelAccessor;\n\n    public InstantiationStrategy() {\n        this(null);\n    }\n\n    public InstantiationStrategy(ScopeModelAccessor scopeModelAccessor) {\n        this.scopeModelAccessor = scopeModelAccessor;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> T instantiate(Class<T> type) throws ReflectiveOperationException {\n\n        // should not use default constructor directly, maybe also has another constructor matched scope model arguments\n        // 1. try to get default constructor\n        Constructor<T> defaultConstructor = null;\n        try {\n            defaultConstructor = type.getConstructor();\n        } catch (NoSuchMethodException e) {\n            // ignore no default constructor\n        }\n\n        // 2. use matched constructor if found\n        List<Constructor<?>> matchedConstructors = new ArrayList<>();\n        Constructor<?>[] declaredConstructors = type.getConstructors();\n        for (Constructor<?> constructor : declaredConstructors) {\n            if (isMatched(constructor)) {\n                matchedConstructors.add(constructor);\n            }\n        }\n        // remove default constructor from matchedConstructors\n        if (defaultConstructor != null) {\n            matchedConstructors.remove(defaultConstructor);\n        }\n\n        // match order:\n        // 1. the only matched constructor with parameters\n        // 2. default constructor if absent\n\n        Constructor<?> targetConstructor;\n        if (matchedConstructors.size() > 1) {\n            throw new IllegalArgumentException(\"Expect only one but found \" + matchedConstructors.size()\n                    + \" matched constructors for type: \" + type.getName() + \", matched constructors: \"\n                    + matchedConstructors);\n        } else if (matchedConstructors.size() == 1) {\n            targetConstructor = matchedConstructors.get(0);\n        } else if (defaultConstructor != null) {\n            targetConstructor = defaultConstructor;\n        } else {\n            throw new IllegalArgumentException(\"None matched constructor was found for type: \" + type.getName());\n        }\n\n        // create instance with arguments\n        Class<?>[] parameterTypes = targetConstructor.getParameterTypes();\n        Object[] args = new Object[parameterTypes.length];\n        for (int i = 0; i < parameterTypes.length; i++) {\n            args[i] = getArgumentValueForType(parameterTypes[i]);\n        }\n        return (T) targetConstructor.newInstance(args);\n    }\n\n    private boolean isMatched(Constructor<?> constructor) {\n        for (Class<?> parameterType : constructor.getParameterTypes()) {\n            if (!isSupportedConstructorParameterType(parameterType)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private boolean isSupportedConstructorParameterType(Class<?> parameterType) {\n        return ScopeModel.class.isAssignableFrom(parameterType);\n    }\n\n    private Object getArgumentValueForType(Class<?> parameterType) {\n        // get scope mode value\n        if (scopeModelAccessor != null) {\n            if (parameterType == ScopeModel.class) {\n                return scopeModelAccessor.getScopeModel();\n            } else if (parameterType == FrameworkModel.class) {\n                return scopeModelAccessor.getFrameworkModel();\n            } else if (parameterType == ApplicationModel.class) {\n                return scopeModelAccessor.getApplicationModel();\n            } else if (parameterType == ModuleModel.class) {\n                return scopeModelAccessor.getModuleModel();\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanAccessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beanutil;\n\npublic enum JavaBeanAccessor {\n\n    /**\n     * Field accessor.\n     */\n    FIELD,\n    /**\n     * Method accessor.\n     */\n    METHOD,\n    /**\n     * Method prefer to field.\n     */\n    ALL;\n\n    public static boolean isAccessByMethod(JavaBeanAccessor accessor) {\n        return METHOD.equals(accessor) || ALL.equals(accessor);\n    }\n\n    public static boolean isAccessByField(JavaBeanAccessor accessor) {\n        return FIELD.equals(accessor) || ALL.equals(accessor);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanDescriptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beanutil;\n\nimport java.io.Serializable;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\npublic final class JavaBeanDescriptor implements Serializable, Iterable<Map.Entry<Object, Object>> {\n\n    private static final long serialVersionUID = -8505586483570518029L;\n\n    public static final int TYPE_CLASS = 1;\n    public static final int TYPE_ENUM = 2;\n    public static final int TYPE_COLLECTION = 3;\n    public static final int TYPE_MAP = 4;\n    public static final int TYPE_ARRAY = 5;\n    /**\n     * @see org.apache.dubbo.common.utils.ReflectUtils#isPrimitive(Class)\n     */\n    public static final int TYPE_PRIMITIVE = 6;\n\n    public static final int TYPE_BEAN = 7;\n\n    private static final String ENUM_PROPERTY_NAME = \"name\";\n    private static final String CLASS_PROPERTY_NAME = \"name\";\n    private static final String PRIMITIVE_PROPERTY_VALUE = \"value\";\n\n    /**\n     * Used to define a type is valid.\n     *\n     * @see #isValidType(int)\n     */\n    private static final int TYPE_MAX = TYPE_BEAN;\n    /**\n     * Used to define a type is valid.\n     *\n     * @see #isValidType(int)\n     */\n    private static final int TYPE_MIN = TYPE_CLASS;\n\n    private String className;\n    private int type;\n\n    private final Map<Object, Object> properties = new LinkedHashMap<>();\n\n    public JavaBeanDescriptor() {}\n\n    public JavaBeanDescriptor(String className, int type) {\n        notEmpty(className, \"class name is empty\");\n        if (!isValidType(type)) {\n            throw new IllegalArgumentException(\"type [ \" + type + \" ] is unsupported\");\n        }\n\n        this.className = className;\n        this.type = type;\n    }\n\n    public boolean isClassType() {\n        return TYPE_CLASS == type;\n    }\n\n    public boolean isEnumType() {\n        return TYPE_ENUM == type;\n    }\n\n    public boolean isCollectionType() {\n        return TYPE_COLLECTION == type;\n    }\n\n    public boolean isMapType() {\n        return TYPE_MAP == type;\n    }\n\n    public boolean isArrayType() {\n        return TYPE_ARRAY == type;\n    }\n\n    public boolean isPrimitiveType() {\n        return TYPE_PRIMITIVE == type;\n    }\n\n    public boolean isBeanType() {\n        return TYPE_BEAN == type;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public String getClassName() {\n        return className;\n    }\n\n    public void setClassName(String className) {\n        this.className = className;\n    }\n\n    public Object setProperty(Object propertyName, Object propertyValue) {\n        notNull(propertyName, \"Property name is null\");\n        return properties.put(propertyName, propertyValue);\n    }\n\n    public String setEnumNameProperty(String name) {\n        if (isEnumType()) {\n            Object result = setProperty(ENUM_PROPERTY_NAME, name);\n            return result == null ? null : result.toString();\n        }\n        throw new IllegalStateException(\"The instance is not a enum wrapper\");\n    }\n\n    public String getEnumPropertyName() {\n        if (isEnumType()) {\n            Object result = getProperty(ENUM_PROPERTY_NAME);\n            return result == null ? null : result.toString();\n        }\n        throw new IllegalStateException(\"The instance is not a enum wrapper\");\n    }\n\n    public String setClassNameProperty(String name) {\n        if (isClassType()) {\n            Object result = setProperty(CLASS_PROPERTY_NAME, name);\n            return result == null ? null : result.toString();\n        }\n        throw new IllegalStateException(\"The instance is not a class wrapper\");\n    }\n\n    public String getClassNameProperty() {\n        if (isClassType()) {\n            Object result = getProperty(CLASS_PROPERTY_NAME);\n            return result == null ? null : result.toString();\n        }\n        throw new IllegalStateException(\"The instance is not a class wrapper\");\n    }\n\n    public Object setPrimitiveProperty(Object primitiveValue) {\n        if (isPrimitiveType()) {\n            return setProperty(PRIMITIVE_PROPERTY_VALUE, primitiveValue);\n        }\n        throw new IllegalStateException(\"The instance is not a primitive type wrapper\");\n    }\n\n    public Object getPrimitiveProperty() {\n        if (isPrimitiveType()) {\n            return getProperty(PRIMITIVE_PROPERTY_VALUE);\n        }\n        throw new IllegalStateException(\"The instance is not a primitive type wrapper\");\n    }\n\n    public Object getProperty(Object propertyName) {\n        notNull(propertyName, \"Property name is null\");\n        return properties.get(propertyName);\n    }\n\n    public boolean containsProperty(Object propertyName) {\n        notNull(propertyName, \"Property name is null\");\n        return properties.containsKey(propertyName);\n    }\n\n    @Override\n    public Iterator<Map.Entry<Object, Object>> iterator() {\n        return properties.entrySet().iterator();\n    }\n\n    public int propertySize() {\n        return properties.size();\n    }\n\n    private boolean isValidType(int type) {\n        return TYPE_MIN <= type && type <= TYPE_MAX;\n    }\n\n    private void notNull(Object obj, String message) {\n        if (obj == null) {\n            throw new IllegalArgumentException(message);\n        }\n    }\n\n    private void notEmpty(String string, String message) {\n        if (isEmpty(string)) {\n            throw new IllegalArgumentException(message);\n        }\n    }\n\n    private boolean isEmpty(String string) {\n        return string == null || \"\".equals(string.trim());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beanutil;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.DefaultSerializeClassChecker;\nimport org.apache.dubbo.common.utils.LogHelper;\nimport org.apache.dubbo.common.utils.ReflectUtils;\n\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic final class JavaBeanSerializeUtil {\n\n    private static final Logger logger = LoggerFactory.getLogger(JavaBeanSerializeUtil.class);\n    private static final Map<String, Class<?>> TYPES = new HashMap<>();\n    private static final String ARRAY_PREFIX = \"[\";\n    private static final String REFERENCE_TYPE_PREFIX = \"L\";\n    private static final String REFERENCE_TYPE_SUFFIX = \";\";\n\n    static {\n        TYPES.put(boolean.class.getName(), boolean.class);\n        TYPES.put(byte.class.getName(), byte.class);\n        TYPES.put(short.class.getName(), short.class);\n        TYPES.put(int.class.getName(), int.class);\n        TYPES.put(long.class.getName(), long.class);\n        TYPES.put(float.class.getName(), float.class);\n        TYPES.put(double.class.getName(), double.class);\n        TYPES.put(void.class.getName(), void.class);\n        TYPES.put(\"Z\", boolean.class);\n        TYPES.put(\"B\", byte.class);\n        TYPES.put(\"C\", char.class);\n        TYPES.put(\"D\", double.class);\n        TYPES.put(\"F\", float.class);\n        TYPES.put(\"I\", int.class);\n        TYPES.put(\"J\", long.class);\n        TYPES.put(\"S\", short.class);\n    }\n\n    private JavaBeanSerializeUtil() {}\n\n    public static JavaBeanDescriptor serialize(Object obj) {\n        return serialize(obj, JavaBeanAccessor.FIELD);\n    }\n\n    public static JavaBeanDescriptor serialize(Object obj, JavaBeanAccessor accessor) {\n        if (obj == null) {\n            return null;\n        }\n        if (obj instanceof JavaBeanDescriptor) {\n            return (JavaBeanDescriptor) obj;\n        }\n        IdentityHashMap<Object, JavaBeanDescriptor> cache = new IdentityHashMap<>();\n        return createDescriptorIfAbsent(obj, accessor, cache);\n    }\n\n    private static JavaBeanDescriptor createDescriptorForSerialize(Class<?> cl) {\n        if (cl.isEnum()) {\n            return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_ENUM);\n        }\n\n        if (cl.isArray()) {\n            return new JavaBeanDescriptor(cl.getComponentType().getName(), JavaBeanDescriptor.TYPE_ARRAY);\n        }\n\n        if (ReflectUtils.isPrimitive(cl)) {\n            return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_PRIMITIVE);\n        }\n\n        if (Class.class.equals(cl)) {\n            return new JavaBeanDescriptor(Class.class.getName(), JavaBeanDescriptor.TYPE_CLASS);\n        }\n\n        if (Collection.class.isAssignableFrom(cl)) {\n            return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_COLLECTION);\n        }\n\n        if (Map.class.isAssignableFrom(cl)) {\n            return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_MAP);\n        }\n\n        return new JavaBeanDescriptor(cl.getName(), JavaBeanDescriptor.TYPE_BEAN);\n    }\n\n    private static JavaBeanDescriptor createDescriptorIfAbsent(\n            Object obj, JavaBeanAccessor accessor, IdentityHashMap<Object, JavaBeanDescriptor> cache) {\n        if (cache.containsKey(obj)) {\n            return cache.get(obj);\n        }\n\n        if (obj instanceof JavaBeanDescriptor) {\n            return (JavaBeanDescriptor) obj;\n        }\n\n        JavaBeanDescriptor result = createDescriptorForSerialize(obj.getClass());\n        cache.put(obj, result);\n        serializeInternal(result, obj, accessor, cache);\n        return result;\n    }\n\n    private static void serializeInternal(\n            JavaBeanDescriptor descriptor,\n            Object obj,\n            JavaBeanAccessor accessor,\n            IdentityHashMap<Object, JavaBeanDescriptor> cache) {\n        if (obj == null || descriptor == null) {\n            return;\n        }\n\n        if (obj.getClass().isEnum()) {\n            descriptor.setEnumNameProperty(((Enum<?>) obj).name());\n        } else if (ReflectUtils.isPrimitive(obj.getClass())) {\n            descriptor.setPrimitiveProperty(obj);\n        } else if (Class.class.equals(obj.getClass())) {\n            descriptor.setClassNameProperty(((Class<?>) obj).getName());\n        } else if (obj.getClass().isArray()) {\n            int len = Array.getLength(obj);\n            for (int i = 0; i < len; i++) {\n                Object item = Array.get(obj, i);\n                if (item == null) {\n                    descriptor.setProperty(i, null);\n                } else {\n                    JavaBeanDescriptor itemDescriptor = createDescriptorIfAbsent(item, accessor, cache);\n                    descriptor.setProperty(i, itemDescriptor);\n                }\n            }\n        } else if (obj instanceof Collection) {\n            Collection collection = (Collection) obj;\n            int index = 0;\n            for (Object item : collection) {\n                if (item == null) {\n                    descriptor.setProperty(index++, null);\n                } else {\n                    JavaBeanDescriptor itemDescriptor = createDescriptorIfAbsent(item, accessor, cache);\n                    descriptor.setProperty(index++, itemDescriptor);\n                }\n            }\n        } else if (obj instanceof Map) {\n            Map map = (Map) obj;\n            map.forEach((key, value) -> {\n                Object keyDescriptor = key == null ? null : createDescriptorIfAbsent(key, accessor, cache);\n                Object valueDescriptor = value == null ? null : createDescriptorIfAbsent(value, accessor, cache);\n                descriptor.setProperty(keyDescriptor, valueDescriptor);\n            }); // ~ end of loop map\n        } else {\n            if (JavaBeanAccessor.isAccessByMethod(accessor)) {\n                Map<String, Method> methods = ReflectUtils.getBeanPropertyReadMethods(obj.getClass());\n                for (Map.Entry<String, Method> entry : methods.entrySet()) {\n                    try {\n                        Object value = entry.getValue().invoke(obj);\n                        if (value == null) {\n                            continue;\n                        }\n                        JavaBeanDescriptor valueDescriptor = createDescriptorIfAbsent(value, accessor, cache);\n                        descriptor.setProperty(entry.getKey(), valueDescriptor);\n                    } catch (Exception e) {\n                        throw new RuntimeException(e.getMessage(), e);\n                    }\n                } // ~ end of loop method map\n            } // ~ end of if (JavaBeanAccessor.isAccessByMethod(accessor))\n\n            if (JavaBeanAccessor.isAccessByField(accessor)) {\n                Map<String, Field> fields = ReflectUtils.getBeanPropertyFields(obj.getClass());\n                for (Map.Entry<String, Field> entry : fields.entrySet()) {\n                    if (!descriptor.containsProperty(entry.getKey())) {\n                        try {\n                            Object value = entry.getValue().get(obj);\n                            if (value == null) {\n                                continue;\n                            }\n                            JavaBeanDescriptor valueDescriptor = createDescriptorIfAbsent(value, accessor, cache);\n                            descriptor.setProperty(entry.getKey(), valueDescriptor);\n                        } catch (Exception e) {\n                            throw new RuntimeException(e.getMessage(), e);\n                        }\n                    }\n                } // ~ end of loop field map\n            } // ~ end of if (JavaBeanAccessor.isAccessByField(accessor))\n        } // ~ end of else\n    } // ~ end of method serializeInternal\n\n    public static Object deserialize(JavaBeanDescriptor beanDescriptor) {\n        return deserialize(beanDescriptor, Thread.currentThread().getContextClassLoader());\n    }\n\n    public static Object deserialize(JavaBeanDescriptor beanDescriptor, ClassLoader loader) {\n        if (beanDescriptor == null) {\n            return null;\n        }\n        IdentityHashMap<JavaBeanDescriptor, Object> cache = new IdentityHashMap<>();\n        Object result = instantiateForDeserialize(beanDescriptor, loader, cache);\n        deserializeInternal(result, beanDescriptor, loader, cache);\n        return result;\n    }\n\n    private static void deserializeInternal(\n            Object result,\n            JavaBeanDescriptor beanDescriptor,\n            ClassLoader loader,\n            IdentityHashMap<JavaBeanDescriptor, Object> cache) {\n        if (beanDescriptor.isEnumType() || beanDescriptor.isClassType() || beanDescriptor.isPrimitiveType()) {\n            return;\n        }\n\n        if (beanDescriptor.isArrayType()) {\n            int index = 0;\n            for (Map.Entry<Object, Object> entry : beanDescriptor) {\n                Object item = entry.getValue();\n                if (item instanceof JavaBeanDescriptor) {\n                    JavaBeanDescriptor itemDescriptor = (JavaBeanDescriptor) entry.getValue();\n                    item = instantiateForDeserialize(itemDescriptor, loader, cache);\n                    deserializeInternal(item, itemDescriptor, loader, cache);\n                }\n                Array.set(result, index++, item);\n            }\n        } else if (beanDescriptor.isCollectionType()) {\n            Collection collection = (Collection) result;\n            for (Map.Entry<Object, Object> entry : beanDescriptor) {\n                Object item = entry.getValue();\n                if (item instanceof JavaBeanDescriptor) {\n                    JavaBeanDescriptor itemDescriptor = (JavaBeanDescriptor) entry.getValue();\n                    item = instantiateForDeserialize(itemDescriptor, loader, cache);\n                    deserializeInternal(item, itemDescriptor, loader, cache);\n                }\n                collection.add(item);\n            }\n        } else if (beanDescriptor.isMapType()) {\n            Map map = (Map) result;\n            for (Map.Entry<Object, Object> entry : beanDescriptor) {\n                Object key = entry.getKey();\n                Object value = entry.getValue();\n                if (key instanceof JavaBeanDescriptor) {\n                    JavaBeanDescriptor keyDescriptor = (JavaBeanDescriptor) entry.getKey();\n                    key = instantiateForDeserialize(keyDescriptor, loader, cache);\n                    deserializeInternal(key, keyDescriptor, loader, cache);\n                }\n                if (value instanceof JavaBeanDescriptor) {\n                    JavaBeanDescriptor valueDescriptor = (JavaBeanDescriptor) entry.getValue();\n                    value = instantiateForDeserialize(valueDescriptor, loader, cache);\n                    deserializeInternal(value, valueDescriptor, loader, cache);\n                }\n                map.put(key, value);\n            }\n        } else if (beanDescriptor.isBeanType()) {\n            for (Map.Entry<Object, Object> entry : beanDescriptor) {\n                String property = entry.getKey().toString();\n                Object value = entry.getValue();\n                if (value == null) {\n                    continue;\n                }\n\n                if (value instanceof JavaBeanDescriptor) {\n                    JavaBeanDescriptor valueDescriptor = (JavaBeanDescriptor) entry.getValue();\n                    value = instantiateForDeserialize(valueDescriptor, loader, cache);\n                    deserializeInternal(value, valueDescriptor, loader, cache);\n                }\n\n                Method method = getSetterMethod(result.getClass(), property, value.getClass());\n                boolean setByMethod = false;\n                try {\n                    if (method != null) {\n                        method.invoke(result, value);\n                        setByMethod = true;\n                    }\n                } catch (Exception e) {\n                    LogHelper.warn(logger, \"Failed to set property through method \" + method, e);\n                }\n\n                if (!setByMethod) {\n                    try {\n                        Field field = result.getClass().getField(property);\n                        if (field != null) {\n                            field.set(result, value);\n                        }\n                    } catch (NoSuchFieldException | IllegalAccessException e1) {\n                        LogHelper.warn(logger, \"Failed to set field value\", e1);\n                    }\n                }\n            }\n        } else {\n            throw new IllegalArgumentException(\n                    \"Unsupported type \" + beanDescriptor.getClassName() + \":\" + beanDescriptor.getType());\n        }\n    }\n\n    private static Method getSetterMethod(Class<?> cls, String property, Class<?> valueCls) {\n        String name = \"set\" + property.substring(0, 1).toUpperCase() + property.substring(1);\n        Method method = null;\n        try {\n            method = cls.getMethod(name, valueCls);\n        } catch (NoSuchMethodException e) {\n            for (Method m : cls.getMethods()) {\n                if (ReflectUtils.isBeanPropertyWriteMethod(m) && m.getName().equals(name)) {\n                    method = m;\n                }\n            }\n        }\n        if (method != null) {\n            method.setAccessible(true);\n        }\n        return method;\n    }\n\n    private static Object instantiate(Class<?> cl) throws Exception {\n        Constructor<?>[] constructors = cl.getDeclaredConstructors();\n        Constructor<?> constructor = null;\n        int argc = Integer.MAX_VALUE;\n        for (Constructor<?> c : constructors) {\n            if (c.getParameterTypes().length < argc) {\n                argc = c.getParameterTypes().length;\n                constructor = c;\n            }\n        }\n\n        if (constructor != null) {\n            Class<?>[] paramTypes = constructor.getParameterTypes();\n            Object[] constructorArgs = new Object[paramTypes.length];\n            for (int i = 0; i < constructorArgs.length; i++) {\n                constructorArgs[i] = getConstructorArg(paramTypes[i]);\n            }\n            try {\n                constructor.setAccessible(true);\n                return constructor.newInstance(constructorArgs);\n            } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {\n                LogHelper.warn(logger, e.getMessage(), e);\n            }\n        }\n\n        return cl.getDeclaredConstructor().newInstance();\n    }\n\n    public static Object getConstructorArg(Class<?> cl) {\n        if (boolean.class.equals(cl) || Boolean.class.equals(cl)) {\n            return Boolean.FALSE;\n        }\n\n        if (byte.class.equals(cl) || Byte.class.equals(cl)) {\n            return (byte) 0;\n        }\n\n        if (short.class.equals(cl) || Short.class.equals(cl)) {\n            return (short) 0;\n        }\n\n        if (int.class.equals(cl) || Integer.class.equals(cl)) {\n            return 0;\n        }\n\n        if (long.class.equals(cl) || Long.class.equals(cl)) {\n            return 0L;\n        }\n\n        if (float.class.equals(cl) || Float.class.equals(cl)) {\n            return (float) 0;\n        }\n\n        if (double.class.equals(cl) || Double.class.equals(cl)) {\n            return (double) 0;\n        }\n\n        if (char.class.equals(cl) || Character.class.equals(cl)) {\n            return (char) 0;\n        }\n        return null;\n    }\n\n    private static Object instantiateForDeserialize(\n            JavaBeanDescriptor beanDescriptor, ClassLoader loader, IdentityHashMap<JavaBeanDescriptor, Object> cache) {\n        if (cache.containsKey(beanDescriptor)) {\n            return cache.get(beanDescriptor);\n        }\n\n        if (beanDescriptor.isClassType()) {\n            try {\n                return name2Class(loader, beanDescriptor.getClassNameProperty());\n            } catch (ClassNotFoundException e) {\n                throw new RuntimeException(e.getMessage(), e);\n            }\n        }\n\n        if (beanDescriptor.isEnumType()) {\n            try {\n                Class<?> enumType = name2Class(loader, beanDescriptor.getClassName());\n                Method method = getEnumValueOfMethod(enumType);\n                return method.invoke(null, enumType, beanDescriptor.getEnumPropertyName());\n            } catch (Exception e) {\n                throw new RuntimeException(e.getMessage(), e);\n            }\n        }\n\n        if (beanDescriptor.isPrimitiveType()) {\n            return beanDescriptor.getPrimitiveProperty();\n        }\n\n        Object result;\n        if (beanDescriptor.isArrayType()) {\n            Class<?> componentType;\n            try {\n                componentType = name2Class(loader, beanDescriptor.getClassName());\n            } catch (ClassNotFoundException e) {\n                throw new RuntimeException(e.getMessage(), e);\n            }\n            result = Array.newInstance(componentType, beanDescriptor.propertySize());\n            cache.put(beanDescriptor, result);\n        } else {\n            try {\n                Class<?> cl = name2Class(loader, beanDescriptor.getClassName());\n                result = instantiate(cl);\n                cache.put(beanDescriptor, result);\n            } catch (Exception e) {\n                throw new RuntimeException(e.getMessage(), e);\n            }\n        }\n\n        return result;\n    }\n\n    /**\n     * Transform the Class.forName String to Class Object.\n     *\n     * @param name Class.getName()\n     * @return Class\n     * @throws ClassNotFoundException Class.forName\n     */\n    public static Class<?> name2Class(ClassLoader loader, String name) throws ClassNotFoundException {\n        if (TYPES.containsKey(name)) {\n            return TYPES.get(name);\n        }\n        if (isArray(name)) {\n            int dimension = 0;\n            while (isArray(name)) {\n                ++dimension;\n                name = name.substring(1);\n            }\n            Class type = name2Class(loader, name);\n            int[] dimensions = new int[dimension];\n            for (int i = 0; i < dimension; i++) {\n                dimensions[i] = 0;\n            }\n            return Array.newInstance(type, dimensions).getClass();\n        }\n        if (isReferenceType(name)) {\n            name = name.substring(1, name.length() - 1);\n        }\n        return DefaultSerializeClassChecker.getInstance().loadClass(loader, name);\n    }\n\n    private static boolean isArray(String type) {\n        return type != null && type.startsWith(ARRAY_PREFIX);\n    }\n\n    private static boolean isReferenceType(String type) {\n        return type != null && type.startsWith(REFERENCE_TYPE_PREFIX) && type.endsWith(REFERENCE_TYPE_SUFFIX);\n    }\n\n    private static Method getEnumValueOfMethod(Class cl) throws NoSuchMethodException {\n        return cl.getMethod(\"valueOf\", Class.class, String.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.security.ProtectionDomain;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\nimport javassist.CannotCompileException;\nimport javassist.ClassPool;\nimport javassist.CtClass;\nimport javassist.CtConstructor;\nimport javassist.CtField;\nimport javassist.CtMethod;\nimport javassist.CtNewConstructor;\nimport javassist.CtNewMethod;\nimport javassist.LoaderClassPath;\nimport javassist.NotFoundException;\n\npublic final class ClassGenerator {\n\n    private static final AtomicLong CLASS_NAME_COUNTER = new AtomicLong(0);\n    private static final String SIMPLE_NAME_TAG = \"<init>\";\n    private static final Map<ClassLoader, ClassPool> POOL_MAP = new ConcurrentHashMap<>(); // ClassLoader - ClassPool\n    private ClassPool mPool;\n    private CtClass mCtc;\n    private String mClassName;\n    private String mSuperClass;\n    private Set<String> mInterfaces;\n    private List<String> mFields;\n    private List<String> mConstructors;\n    private List<String> mMethods;\n    private ClassLoader mClassLoader;\n    private Map<String, Method> mCopyMethods; // <method desc,method instance>\n    private Map<String, Constructor<?>> mCopyConstructors; // <constructor desc,constructor instance>\n    private boolean mDefaultConstructor = false;\n\n    private ClassGenerator() {}\n\n    private ClassGenerator(ClassLoader classLoader, ClassPool pool) {\n        mClassLoader = classLoader;\n        mPool = pool;\n    }\n\n    public static ClassGenerator newInstance() {\n        return new ClassGenerator(\n                Thread.currentThread().getContextClassLoader(),\n                getClassPool(Thread.currentThread().getContextClassLoader()));\n    }\n\n    public static ClassGenerator newInstance(ClassLoader loader) {\n        return new ClassGenerator(loader, getClassPool(loader));\n    }\n\n    public static boolean isDynamicClass(Class<?> cl) {\n        return ClassGenerator.DC.class.isAssignableFrom(cl);\n    }\n\n    public static ClassPool getClassPool(ClassLoader loader) {\n        if (loader == null) {\n            return ClassPool.getDefault();\n        }\n\n        ClassPool pool = POOL_MAP.get(loader);\n        if (pool == null) {\n            synchronized (POOL_MAP) {\n                pool = POOL_MAP.get(loader);\n                if (pool == null) {\n                    pool = new ClassPool(true);\n                    pool.insertClassPath(new LoaderClassPath(loader));\n                    pool.insertClassPath(new DubboLoaderClassPath());\n                    POOL_MAP.put(loader, pool);\n                }\n            }\n        }\n        return pool;\n    }\n\n    private static String modifier(int mod) {\n        StringBuilder modifier = new StringBuilder();\n        if (Modifier.isPublic(mod)) {\n            modifier.append(\"public\");\n        } else if (Modifier.isProtected(mod)) {\n            modifier.append(\"protected\");\n        } else if (Modifier.isPrivate(mod)) {\n            modifier.append(\"private\");\n        }\n\n        if (Modifier.isStatic(mod)) {\n            modifier.append(\" static\");\n        }\n        if (Modifier.isVolatile(mod)) {\n            modifier.append(\" volatile\");\n        }\n\n        return modifier.toString();\n    }\n\n    public String getClassName() {\n        return mClassName;\n    }\n\n    public ClassGenerator setClassName(String name) {\n        mClassName = name;\n        return this;\n    }\n\n    public ClassGenerator addInterface(String cn) {\n        if (mInterfaces == null) {\n            mInterfaces = new HashSet<>();\n        }\n        mInterfaces.add(cn);\n        return this;\n    }\n\n    public ClassGenerator addInterface(Class<?> cl) {\n        return addInterface(cl.getName());\n    }\n\n    public ClassGenerator setSuperClass(String cn) {\n        mSuperClass = cn;\n        return this;\n    }\n\n    public ClassGenerator setSuperClass(Class<?> cl) {\n        mSuperClass = cl.getName();\n        return this;\n    }\n\n    public ClassGenerator addField(String code) {\n        if (mFields == null) {\n            mFields = new ArrayList<>();\n        }\n        mFields.add(code);\n        return this;\n    }\n\n    public ClassGenerator addField(String name, int mod, Class<?> type) {\n        return addField(name, mod, type, null);\n    }\n\n    public ClassGenerator addField(String name, int mod, Class<?> type, String def) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(modifier(mod)).append(' ').append(ReflectUtils.getName(type)).append(' ');\n        sb.append(name);\n        if (StringUtils.isNotEmpty(def)) {\n            sb.append('=');\n            sb.append(def);\n        }\n        sb.append(';');\n        return addField(sb.toString());\n    }\n\n    public ClassGenerator addMethod(String code) {\n        if (mMethods == null) {\n            mMethods = new ArrayList<>();\n        }\n        mMethods.add(code);\n        return this;\n    }\n\n    public ClassGenerator addMethod(String name, int mod, Class<?> rt, Class<?>[] pts, String body) {\n        return addMethod(name, mod, rt, pts, null, body);\n    }\n\n    public ClassGenerator addMethod(String name, int mod, Class<?> rt, Class<?>[] pts, Class<?>[] ets, String body) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(modifier(mod))\n                .append(' ')\n                .append(ReflectUtils.getName(rt))\n                .append(' ')\n                .append(name);\n        sb.append('(');\n        if (ArrayUtils.isNotEmpty(pts)) {\n            for (int i = 0; i < pts.length; i++) {\n                if (i > 0) {\n                    sb.append(',');\n                }\n                sb.append(ReflectUtils.getName(pts[i]));\n                sb.append(\" arg\").append(i);\n            }\n        }\n        sb.append(')');\n        if (ArrayUtils.isNotEmpty(ets)) {\n            sb.append(\" throws \");\n            for (int i = 0; i < ets.length; i++) {\n                if (i > 0) {\n                    sb.append(',');\n                }\n                sb.append(ReflectUtils.getName(ets[i]));\n            }\n        }\n        sb.append('{').append(body).append('}');\n        return addMethod(sb.toString());\n    }\n\n    public ClassGenerator addMethod(Method m) {\n        addMethod(m.getName(), m);\n        return this;\n    }\n\n    public ClassGenerator addMethod(String name, Method m) {\n        String desc = name + ReflectUtils.getDescWithoutMethodName(m);\n        addMethod(':' + desc);\n        if (mCopyMethods == null) {\n            mCopyMethods = new ConcurrentHashMap<>(8);\n        }\n        mCopyMethods.put(desc, m);\n        return this;\n    }\n\n    public ClassGenerator addConstructor(String code) {\n        if (mConstructors == null) {\n            mConstructors = new LinkedList<>();\n        }\n        mConstructors.add(code);\n        return this;\n    }\n\n    public ClassGenerator addConstructor(int mod, Class<?>[] pts, String body) {\n        return addConstructor(mod, pts, null, body);\n    }\n\n    public ClassGenerator addConstructor(int mod, Class<?>[] pts, Class<?>[] ets, String body) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(modifier(mod)).append(' ').append(SIMPLE_NAME_TAG);\n        sb.append('(');\n        for (int i = 0; i < pts.length; i++) {\n            if (i > 0) {\n                sb.append(',');\n            }\n            sb.append(ReflectUtils.getName(pts[i]));\n            sb.append(\" arg\").append(i);\n        }\n        sb.append(')');\n        if (ArrayUtils.isNotEmpty(ets)) {\n            sb.append(\" throws \");\n            for (int i = 0; i < ets.length; i++) {\n                if (i > 0) {\n                    sb.append(',');\n                }\n                sb.append(ReflectUtils.getName(ets[i]));\n            }\n        }\n        sb.append('{').append(body).append('}');\n        return addConstructor(sb.toString());\n    }\n\n    public ClassGenerator addConstructor(Constructor<?> c) {\n        String desc = ReflectUtils.getDesc(c);\n        addConstructor(\":\" + desc);\n        if (mCopyConstructors == null) {\n            mCopyConstructors = new ConcurrentHashMap<>(4);\n        }\n        mCopyConstructors.put(desc, c);\n        return this;\n    }\n\n    public ClassGenerator addDefaultConstructor() {\n        mDefaultConstructor = true;\n        return this;\n    }\n\n    public ClassPool getClassPool() {\n        return mPool;\n    }\n\n    /**\n     * @param neighbor    A class belonging to the same package that this\n     *                    class belongs to.  It is used to load the class.\n     */\n    public Class<?> toClass(Class<?> neighbor) {\n        return toClass(neighbor, mClassLoader, getClass().getProtectionDomain());\n    }\n\n    public Class<?> toClass(Class<?> neighborClass, ClassLoader loader, ProtectionDomain pd) {\n        if (mCtc != null) {\n            mCtc.detach();\n        }\n        long id = CLASS_NAME_COUNTER.getAndIncrement();\n        try {\n            CtClass ctcs = mSuperClass == null ? null : mPool.get(mSuperClass);\n            if (mClassName == null) {\n                mClassName = (mSuperClass == null || javassist.Modifier.isPublic(ctcs.getModifiers())\n                                ? ClassGenerator.class.getName()\n                                : mSuperClass + \"$sc\")\n                        + id;\n            }\n            mCtc = mPool.makeClass(mClassName);\n            if (mSuperClass != null) {\n                mCtc.setSuperclass(ctcs);\n            }\n            mCtc.addInterface(mPool.get(DC.class.getName())); // add dynamic class tag.\n            if (mInterfaces != null) {\n                for (String cl : mInterfaces) {\n                    mCtc.addInterface(mPool.get(cl));\n                }\n            }\n            if (mFields != null) {\n                for (String code : mFields) {\n                    mCtc.addField(CtField.make(code, mCtc));\n                }\n            }\n            if (mMethods != null) {\n                for (String code : mMethods) {\n                    if (code.charAt(0) == ':') {\n                        mCtc.addMethod(CtNewMethod.copy(\n                                getCtMethod(mCopyMethods.get(code.substring(1))),\n                                code.substring(1, code.indexOf('(')),\n                                mCtc,\n                                null));\n                    } else {\n                        mCtc.addMethod(CtNewMethod.make(code, mCtc));\n                    }\n                }\n            }\n            if (mDefaultConstructor) {\n                mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc));\n            }\n            if (mConstructors != null) {\n                for (String code : mConstructors) {\n                    if (code.charAt(0) == ':') {\n                        mCtc.addConstructor(CtNewConstructor.copy(\n                                getCtConstructor(mCopyConstructors.get(code.substring(1))), mCtc, null));\n                    } else {\n                        String[] sn = mCtc.getSimpleName().split(\"\\\\$+\"); // inner class name include $.\n                        mCtc.addConstructor(\n                                CtNewConstructor.make(code.replaceFirst(SIMPLE_NAME_TAG, sn[sn.length - 1]), mCtc));\n                    }\n                }\n            }\n\n            try {\n                return mPool.toClass(mCtc, neighborClass, loader, pd);\n            } catch (Throwable t) {\n                if (!(t instanceof CannotCompileException)) {\n                    return mPool.toClass(mCtc, loader, pd);\n                }\n                throw t;\n            }\n        } catch (RuntimeException e) {\n            throw e;\n        } catch (NotFoundException | CannotCompileException e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n    }\n\n    public void release() {\n        if (mCtc != null) {\n            mCtc.detach();\n        }\n        if (mInterfaces != null) {\n            mInterfaces.clear();\n        }\n        if (mFields != null) {\n            mFields.clear();\n        }\n        if (mMethods != null) {\n            mMethods.clear();\n        }\n        if (mConstructors != null) {\n            mConstructors.clear();\n        }\n        if (mCopyMethods != null) {\n            mCopyMethods.clear();\n        }\n        if (mCopyConstructors != null) {\n            mCopyConstructors.clear();\n        }\n    }\n\n    private CtClass getCtClass(Class<?> c) throws NotFoundException {\n        return mPool.get(c.getName());\n    }\n\n    private CtMethod getCtMethod(Method m) throws NotFoundException {\n        return getCtClass(m.getDeclaringClass()).getMethod(m.getName(), ReflectUtils.getDescWithoutMethodName(m));\n    }\n\n    private CtConstructor getCtConstructor(Constructor<?> c) throws NotFoundException {\n        return getCtClass(c.getDeclaringClass()).getConstructor(ReflectUtils.getDesc(c));\n    }\n\n    public static interface DC {} // dynamic class tag interface.\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/DubboLoaderClassPath.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\nimport java.io.InputStream;\nimport java.net.URL;\nimport javassist.LoaderClassPath;\nimport javassist.NotFoundException;\n\n/**\n * Ensure javassist will load Dubbo's class from Dubbo's classLoader\n */\npublic class DubboLoaderClassPath extends LoaderClassPath {\n    public DubboLoaderClassPath() {\n        super(DubboLoaderClassPath.class.getClassLoader());\n    }\n\n    @Override\n    public InputStream openClassfile(String classname) throws NotFoundException {\n        if (!classname.startsWith(\"org.apache.dubbo\")\n                && !classname.startsWith(\"grpc.health\")\n                && !classname.startsWith(\"com.google\")) {\n            return null;\n        }\n        return super.openClassfile(classname);\n    }\n\n    @Override\n    public URL find(String classname) {\n        if (!classname.startsWith(\"org.apache.dubbo\")) {\n            return null;\n        }\n        return super.find(classname);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Mixin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.ReflectUtils;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic abstract class Mixin {\n    private static final String PACKAGE_NAME = Mixin.class.getPackage().getName();\n    private static final AtomicLong MIXIN_CLASS_COUNTER = new AtomicLong(0);\n\n    protected Mixin() {}\n\n    /**\n     * mixin interface and delegates.\n     * all class must be public.\n     *\n     * @param ics interface class array.\n     * @param dc  delegate class.\n     * @return Mixin instance.\n     */\n    public static Mixin mixin(Class<?>[] ics, Class<?> dc) {\n        return mixin(ics, new Class[] {dc});\n    }\n\n    /**\n     * mixin interface and delegates.\n     * all class must be public.\n     *\n     * @param ics interface class array.\n     * @param dc  delegate class.\n     * @param cl  class loader.\n     * @return Mixin instance.\n     */\n    public static Mixin mixin(Class<?>[] ics, Class<?> dc, ClassLoader cl) {\n        return mixin(ics, new Class[] {dc}, cl);\n    }\n\n    /**\n     * mixin interface and delegates.\n     * all class must be public.\n     *\n     * @param ics interface class array.\n     * @param dcs delegate class array.\n     * @return Mixin instance.\n     */\n    public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs) {\n        return mixin(ics, dcs, ClassUtils.getCallerClassLoader(Mixin.class));\n    }\n\n    /**\n     * mixin interface and delegates.\n     * all class must be public.\n     *\n     * @param ics interface class array.\n     * @param dcs delegate class array.\n     * @param cl  class loader.\n     * @return Mixin instance.\n     */\n    public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs, ClassLoader cl) {\n        assertInterfaceArray(ics);\n\n        long id = MIXIN_CLASS_COUNTER.getAndIncrement();\n        String pkg = null;\n        ClassGenerator ccp = null, ccm = null;\n        try {\n            ccp = ClassGenerator.newInstance(cl);\n\n            // impl constructor\n            StringBuilder code = new StringBuilder();\n            for (int i = 0; i < dcs.length; i++) {\n                if (!Modifier.isPublic(dcs[i].getModifiers())) {\n                    String npkg = dcs[i].getPackage().getName();\n                    if (pkg == null) {\n                        pkg = npkg;\n                    } else {\n                        if (!pkg.equals(npkg)) {\n                            throw new IllegalArgumentException(\"non-public interfaces class from different packages\");\n                        }\n                    }\n                }\n\n                ccp.addField(\"private \" + dcs[i].getName() + \" d\" + i + \";\");\n\n                code.append('d')\n                        .append(i)\n                        .append(\" = (\")\n                        .append(dcs[i].getName())\n                        .append(\")$1[\")\n                        .append(i)\n                        .append(\"];\\n\");\n                if (MixinAware.class.isAssignableFrom(dcs[i])) {\n                    code.append('d').append(i).append(\".setMixinInstance(this);\\n\");\n                }\n            }\n            ccp.addConstructor(Modifier.PUBLIC, new Class<?>[] {Object[].class}, code.toString());\n\n            Class<?> neighbor = null;\n            // impl methods.\n            Set<String> worked = new HashSet<>();\n            for (int i = 0; i < ics.length; i++) {\n                if (!Modifier.isPublic(ics[i].getModifiers())) {\n                    String npkg = ics[i].getPackage().getName();\n                    if (pkg == null) {\n                        pkg = npkg;\n                        neighbor = ics[i];\n                    } else {\n                        if (!pkg.equals(npkg)) {\n                            throw new IllegalArgumentException(\"non-public delegate class from different packages\");\n                        }\n                    }\n                }\n\n                ccp.addInterface(ics[i]);\n\n                for (Method method : ics[i].getMethods()) {\n                    if (\"java.lang.Object\".equals(method.getDeclaringClass().getName())) {\n                        continue;\n                    }\n\n                    String desc = ReflectUtils.getDesc(method);\n                    if (worked.contains(desc)) {\n                        continue;\n                    }\n                    worked.add(desc);\n\n                    int ix = findMethod(dcs, desc);\n                    if (ix < 0) {\n                        throw new RuntimeException(\"Missing method [\" + desc + \"] implement.\");\n                    }\n\n                    Class<?> rt = method.getReturnType();\n                    String mn = method.getName();\n                    if (Void.TYPE.equals(rt)) {\n                        ccp.addMethod(\n                                mn,\n                                method.getModifiers(),\n                                rt,\n                                method.getParameterTypes(),\n                                method.getExceptionTypes(),\n                                \"d\" + ix + \".\" + mn + \"($$);\");\n                    } else {\n                        ccp.addMethod(\n                                mn,\n                                method.getModifiers(),\n                                rt,\n                                method.getParameterTypes(),\n                                method.getExceptionTypes(),\n                                \"return ($r)d\" + ix + \".\" + mn + \"($$);\");\n                    }\n                }\n            }\n\n            if (pkg == null) {\n                pkg = PACKAGE_NAME;\n                neighbor = Mixin.class;\n            }\n\n            // create MixinInstance class.\n            String micn = pkg + \".mixin\" + id;\n            ccp.setClassName(micn);\n            ccp.toClass(neighbor);\n\n            // create Mixin class.\n            String fcn = Mixin.class.getName() + id;\n            ccm = ClassGenerator.newInstance(cl);\n            ccm.setClassName(fcn);\n            ccm.addDefaultConstructor();\n            ccm.setSuperClass(Mixin.class.getName());\n            ccm.addMethod(\"public Object newInstance(Object[] delegates){ return new \" + micn + \"($1); }\");\n            Class<?> mixin = ccm.toClass(Mixin.class);\n            return (Mixin) mixin.getDeclaredConstructor().newInstance();\n        } catch (RuntimeException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage(), e);\n        } finally {\n            // release ClassGenerator\n            if (ccp != null) {\n                ccp.release();\n            }\n            if (ccm != null) {\n                ccm.release();\n            }\n        }\n    }\n\n    private static int findMethod(Class<?>[] dcs, String desc) {\n        Class<?> cl;\n        Method[] methods;\n        for (int i = 0; i < dcs.length; i++) {\n            cl = dcs[i];\n            methods = cl.getMethods();\n            for (Method method : methods) {\n                if (desc.equals(ReflectUtils.getDesc(method))) {\n                    return i;\n                }\n            }\n        }\n        return -1;\n    }\n\n    private static void assertInterfaceArray(Class<?>[] ics) {\n        for (int i = 0; i < ics.length; i++) {\n            if (!ics[i].isInterface()) {\n                throw new RuntimeException(\"Class \" + ics[i].getName() + \" is not a interface.\");\n            }\n        }\n    }\n\n    /**\n     * new Mixin instance.\n     *\n     * @param ds delegates instance.\n     * @return instance.\n     */\n    public abstract Object newInstance(Object[] ds);\n\n    public static interface MixinAware {\n        void setMixinInstance(Object instance);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/NoSuchMethodException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\n/**\n * NoSuchMethodException.\n */\npublic class NoSuchMethodException extends RuntimeException {\n    private static final long serialVersionUID = -2725364246023268766L;\n\n    public NoSuchMethodException() {\n        super();\n    }\n\n    public NoSuchMethodException(String msg) {\n        super(msg);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/NoSuchPropertyException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\n/**\n * NoSuchPropertyException.\n */\npublic class NoSuchPropertyException extends RuntimeException {\n    private static final long serialVersionUID = -2725364246023268766L;\n\n    public NoSuchPropertyException() {\n        super();\n    }\n\n    public NoSuchPropertyException(String msg) {\n        super(msg);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\nimport org.apache.dubbo.common.utils.ReflectUtils;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.security.ProtectionDomain;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.WeakHashMap;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.MAX_PROXY_COUNT;\n\n/**\n * Proxy.\n */\npublic class Proxy {\n    public static final InvocationHandler THROW_UNSUPPORTED_INVOKER = new InvocationHandler() {\n        @Override\n        public Object invoke(Object proxy, Method method, Object[] args) {\n            throw new UnsupportedOperationException(\"Method [\" + ReflectUtils.getName(method) + \"] unimplemented.\");\n        }\n    };\n\n    private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);\n    private static final Map<ClassLoader, Map<String, Proxy>> PROXY_CACHE_MAP = new WeakHashMap<>();\n\n    private final Class<?> classToCreate;\n\n    protected Proxy(Class<?> classToCreate) {\n        this.classToCreate = classToCreate;\n    }\n\n    /**\n     * Get proxy.\n     *\n     * @param ics interface class array.\n     * @return Proxy instance.\n     */\n    public static Proxy getProxy(Class<?>... ics) {\n        if (ics.length > MAX_PROXY_COUNT) {\n            throw new IllegalArgumentException(\"interface limit exceeded\");\n        }\n\n        // ClassLoader from App Interface should support load some class from Dubbo\n        ClassLoader cl = ics[0].getClassLoader();\n        ProtectionDomain domain = ics[0].getProtectionDomain();\n\n        // use interface class name list as key.\n        String key = buildInterfacesKey(cl, ics);\n\n        // get cache by class loader.\n        final Map<String, Proxy> cache;\n        synchronized (PROXY_CACHE_MAP) {\n            cache = PROXY_CACHE_MAP.computeIfAbsent(cl, k -> new ConcurrentHashMap<>());\n        }\n\n        Proxy proxy = cache.get(key);\n        if (proxy == null) {\n            synchronized (ics[0]) {\n                proxy = cache.get(key);\n                if (proxy == null) {\n                    // create Proxy class.\n                    proxy = new Proxy(buildProxyClass(cl, ics, domain));\n                    cache.put(key, proxy);\n                }\n            }\n        }\n        return proxy;\n    }\n\n    private static String buildInterfacesKey(ClassLoader cl, Class<?>[] ics) {\n        StringBuilder sb = new StringBuilder();\n        for (Class<?> ic : ics) {\n            String itf = ic.getName();\n            if (!ic.isInterface()) {\n                throw new RuntimeException(itf + \" is not a interface.\");\n            }\n\n            Class<?> tmp = null;\n            try {\n                tmp = Class.forName(itf, false, cl);\n            } catch (ClassNotFoundException ignore) {\n            }\n\n            if (tmp != ic) {\n                throw new IllegalArgumentException(ic + \" is not visible from class loader\");\n            }\n\n            sb.append(itf).append(';');\n        }\n        return sb.toString();\n    }\n\n    private static Class<?> buildProxyClass(ClassLoader cl, Class<?>[] ics, ProtectionDomain domain) {\n        ClassGenerator ccp = null;\n        try {\n            ccp = ClassGenerator.newInstance(cl);\n\n            Set<String> worked = new HashSet<>();\n            List<Method> methods = new ArrayList<>();\n\n            String pkg = ics[0].getPackage().getName();\n            Class<?> neighbor = ics[0];\n\n            for (Class<?> ic : ics) {\n                String npkg = ic.getPackage().getName();\n                if (!Modifier.isPublic(ic.getModifiers())) {\n                    if (!pkg.equals(npkg)) {\n                        throw new IllegalArgumentException(\"non-public interfaces from different packages\");\n                    }\n                }\n\n                ccp.addInterface(ic);\n\n                for (Method method : ic.getMethods()) {\n                    String desc = ReflectUtils.getDesc(method);\n                    if (worked.contains(desc) || Modifier.isStatic(method.getModifiers())) {\n                        continue;\n                    }\n                    worked.add(desc);\n\n                    int ix = methods.size();\n                    Class<?> rt = method.getReturnType();\n                    Class<?>[] pts = method.getParameterTypes();\n\n                    StringBuilder code = new StringBuilder(\"Object[] args = new Object[\")\n                            .append(pts.length)\n                            .append(\"];\");\n                    for (int j = 0; j < pts.length; j++) {\n                        code.append(\" args[\")\n                                .append(j)\n                                .append(\"] = ($w)$\")\n                                .append(j + 1)\n                                .append(';');\n                    }\n                    code.append(\" Object ret = handler.invoke(this, methods[\")\n                            .append(ix)\n                            .append(\"], args);\");\n                    if (!Void.TYPE.equals(rt)) {\n                        code.append(\" return \").append(asArgument(rt, \"ret\")).append(';');\n                    }\n\n                    methods.add(method);\n                    ccp.addMethod(\n                            method.getName(),\n                            method.getModifiers(),\n                            rt,\n                            pts,\n                            method.getExceptionTypes(),\n                            code.toString());\n                }\n            }\n\n            // create ProxyInstance class.\n            String pcn = neighbor.getName() + \"DubboProxy\" + PROXY_CLASS_COUNTER.getAndIncrement();\n            ccp.setClassName(pcn);\n            ccp.addField(\"public static java.lang.reflect.Method[] methods;\");\n            ccp.addField(\"private \" + InvocationHandler.class.getName() + \" handler;\");\n            ccp.addConstructor(\n                    Modifier.PUBLIC, new Class<?>[] {InvocationHandler.class}, new Class<?>[0], \"handler=$1;\");\n            ccp.addDefaultConstructor();\n            Class<?> clazz = ccp.toClass(neighbor, cl, domain);\n            clazz.getField(\"methods\").set(null, methods.toArray(new Method[0]));\n            return clazz;\n        } catch (RuntimeException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage(), e);\n        } finally {\n            // release ClassGenerator\n            if (ccp != null) {\n                ccp.release();\n            }\n        }\n    }\n\n    private static String asArgument(Class<?> cl, String name) {\n        if (cl.isPrimitive()) {\n            if (Boolean.TYPE == cl) {\n                return name + \"==null?false:((Boolean)\" + name + \").booleanValue()\";\n            }\n            if (Byte.TYPE == cl) {\n                return name + \"==null?(byte)0:((Byte)\" + name + \").byteValue()\";\n            }\n            if (Character.TYPE == cl) {\n                return name + \"==null?(char)0:((Character)\" + name + \").charValue()\";\n            }\n            if (Double.TYPE == cl) {\n                return name + \"==null?(double)0:((Double)\" + name + \").doubleValue()\";\n            }\n            if (Float.TYPE == cl) {\n                return name + \"==null?(float)0:((Float)\" + name + \").floatValue()\";\n            }\n            if (Integer.TYPE == cl) {\n                return name + \"==null?(int)0:((Integer)\" + name + \").intValue()\";\n            }\n            if (Long.TYPE == cl) {\n                return name + \"==null?(long)0:((Long)\" + name + \").longValue()\";\n            }\n            if (Short.TYPE == cl) {\n                return name + \"==null?(short)0:((Short)\" + name + \").shortValue()\";\n            }\n            throw new RuntimeException(name + \" is unknown primitive type.\");\n        }\n        return \"(\" + ReflectUtils.getName(cl) + \")\" + name;\n    }\n\n    /**\n     * get instance with default handler.\n     *\n     * @return instance.\n     */\n    public Object newInstance() {\n        return newInstance(THROW_UNSUPPORTED_INVOKER);\n    }\n\n    /**\n     * get instance with special handler.\n     *\n     * @return instance.\n     */\n    public Object newInstance(InvocationHandler handler) {\n        Constructor<?> constructor;\n        try {\n            constructor = classToCreate.getDeclaredConstructor(InvocationHandler.class);\n            return constructor.newInstance(handler);\n        } catch (ReflectiveOperationException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public Class<?> getClassToCreate() {\n        return classToCreate;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ReflectUtils;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.regex.Matcher;\nimport java.util.stream.Collectors;\nimport javassist.ClassPool;\nimport javassist.CtMethod;\n\n/**\n * Wrapper.\n */\npublic abstract class Wrapper {\n    // class wrapper map\n    private static final ConcurrentMap<Class<?>, Wrapper> WRAPPER_MAP = new ConcurrentHashMap<>();\n    private static final String[] EMPTY_STRING_ARRAY = new String[0];\n    private static final String[] OBJECT_METHODS = new String[] {\"getClass\", \"hashCode\", \"toString\", \"equals\"};\n    private static final Wrapper OBJECT_WRAPPER = new Wrapper() {\n        @Override\n        public String[] getMethodNames() {\n            return OBJECT_METHODS;\n        }\n\n        @Override\n        public String[] getDeclaredMethodNames() {\n            return OBJECT_METHODS;\n        }\n\n        @Override\n        public String[] getPropertyNames() {\n            return EMPTY_STRING_ARRAY;\n        }\n\n        @Override\n        public Class<?> getPropertyType(String pn) {\n            return null;\n        }\n\n        @Override\n        public Object getPropertyValue(Object instance, String pn) throws NoSuchPropertyException {\n            throw new NoSuchPropertyException(\"Property [\" + pn + \"] not found.\");\n        }\n\n        @Override\n        public void setPropertyValue(Object instance, String pn, Object pv) throws NoSuchPropertyException {\n            throw new NoSuchPropertyException(\"Property [\" + pn + \"] not found.\");\n        }\n\n        @Override\n        public boolean hasProperty(String name) {\n            return false;\n        }\n\n        @Override\n        public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args)\n                throws NoSuchMethodException {\n            if (\"getClass\".equals(mn)) {\n                return instance.getClass();\n            }\n            if (\"hashCode\".equals(mn)) {\n                return instance.hashCode();\n            }\n            if (\"toString\".equals(mn)) {\n                return instance.toString();\n            }\n            if (\"equals\".equals(mn)) {\n                if (args.length == 1) {\n                    return instance.equals(args[0]);\n                }\n                throw new IllegalArgumentException(\"Invoke method [\" + mn + \"] argument number error.\");\n            }\n            throw new NoSuchMethodException(\"Method [\" + mn + \"] not found.\");\n        }\n    };\n    private static AtomicLong WRAPPER_CLASS_COUNTER = new AtomicLong(0);\n\n    /**\n     * get wrapper.\n     *\n     * @param c Class instance.\n     * @return Wrapper instance(not null).\n     */\n    public static Wrapper getWrapper(Class<?> c) {\n        return ConcurrentHashMapUtils.computeIfAbsent(WRAPPER_MAP, c, (clazz) -> {\n            while (ClassGenerator.isDynamicClass(clazz)) // can not wrapper on dynamic class.\n            {\n                clazz = clazz.getSuperclass();\n            }\n\n            if (clazz == Object.class) {\n                return OBJECT_WRAPPER;\n            }\n            return makeWrapper(clazz);\n        });\n    }\n\n    private static Wrapper makeWrapper(Class<?> c) {\n        if (c.isPrimitive()) {\n            throw new IllegalArgumentException(\"Can not create wrapper for primitive type: \" + c);\n        }\n\n        String name = c.getName();\n        ClassLoader cl = ClassUtils.getClassLoader(c);\n\n        StringBuilder c1 = new StringBuilder(\"public void setPropertyValue(Object o, String n, Object v){ \");\n        StringBuilder c2 = new StringBuilder(\"public Object getPropertyValue(Object o, String n){ \");\n        StringBuilder c3 =\n                new StringBuilder(\"public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws \"\n                        + InvocationTargetException.class.getName() + \"{ \");\n\n        c1.append(name)\n                .append(\" w; try{ w = ((\")\n                .append(name)\n                .append(\")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }\");\n        c2.append(name)\n                .append(\" w; try{ w = ((\")\n                .append(name)\n                .append(\")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }\");\n        c3.append(name)\n                .append(\" w; try{ w = ((\")\n                .append(name)\n                .append(\")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }\");\n\n        Map<String, Class<?>> pts = new HashMap<>(); // <property name, property types>\n        Map<String, Method> ms = new LinkedHashMap<>(); // <method desc, Method instance>\n        List<String> mns = new ArrayList<>(); // method names.\n        List<String> dmns = new ArrayList<>(); // declaring method names.\n\n        // get all public field.\n        for (Field f : c.getFields()) {\n            String fn = f.getName();\n            Class<?> ft = f.getType();\n            if (Modifier.isStatic(f.getModifiers())\n                    || Modifier.isTransient(f.getModifiers())\n                    || Modifier.isFinal(f.getModifiers())) {\n                continue;\n            }\n\n            c1.append(\" if( $2.equals(\\\"\")\n                    .append(fn)\n                    .append(\"\\\") ){ ((\")\n                    .append(f.getDeclaringClass().getName())\n                    .append(\")w).\")\n                    .append(fn)\n                    .append('=')\n                    .append(arg(ft, \"$3\"))\n                    .append(\"; return; }\");\n            c2.append(\" if( $2.equals(\\\"\")\n                    .append(fn)\n                    .append(\"\\\") ){ return ($w)((\")\n                    .append(f.getDeclaringClass().getName())\n                    .append(\")w).\")\n                    .append(fn)\n                    .append(\"; }\");\n            pts.put(fn, ft);\n        }\n\n        final ClassPool classPool = ClassGenerator.getClassPool(cl);\n\n        List<String> allMethod = new ArrayList<>();\n        try {\n            final CtMethod[] ctMethods = classPool.get(c.getName()).getMethods();\n            for (CtMethod method : ctMethods) {\n                allMethod.add(ReflectUtils.getDesc(method));\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        Method[] methods = Arrays.stream(c.getMethods())\n                .filter(method -> allMethod.contains(ReflectUtils.getDesc(method)))\n                .collect(Collectors.toList())\n                .toArray(new Method[] {});\n        // get all public method.\n        boolean hasMethod = ClassUtils.hasMethods(methods);\n        if (hasMethod) {\n            Map<String, Integer> sameNameMethodCount = new HashMap<>((int) (methods.length / 0.75f) + 1);\n            for (Method m : methods) {\n                sameNameMethodCount.compute(m.getName(), (key, oldValue) -> oldValue == null ? 1 : oldValue + 1);\n            }\n\n            c3.append(\" try{\");\n            for (Method m : methods) {\n                // ignore Object's method.\n                if (m.getDeclaringClass() == Object.class) {\n                    continue;\n                }\n\n                String mn = m.getName();\n                c3.append(\" if( \\\"\").append(mn).append(\"\\\".equals( $2 ) \");\n                int len = m.getParameterTypes().length;\n                c3.append(\" && \").append(\" $3.length == \").append(len);\n\n                boolean overload = sameNameMethodCount.get(m.getName()) > 1;\n                if (overload) {\n                    if (len > 0) {\n                        for (int l = 0; l < len; l++) {\n                            c3.append(\" && \")\n                                    .append(\" $3[\")\n                                    .append(l)\n                                    .append(\"].getName().equals(\\\"\")\n                                    .append(m.getParameterTypes()[l].getName())\n                                    .append(\"\\\")\");\n                        }\n                    }\n                }\n\n                c3.append(\" ) { \");\n\n                if (m.getReturnType() == Void.TYPE) {\n                    c3.append(\" w.\")\n                            .append(mn)\n                            .append('(')\n                            .append(args(m.getParameterTypes(), \"$4\"))\n                            .append(\");\")\n                            .append(\" return null;\");\n                } else {\n                    c3.append(\" return ($w)w.\")\n                            .append(mn)\n                            .append('(')\n                            .append(args(m.getParameterTypes(), \"$4\"))\n                            .append(\");\");\n                }\n\n                c3.append(\" }\");\n\n                mns.add(mn);\n                if (m.getDeclaringClass() == c) {\n                    dmns.add(mn);\n                }\n                ms.put(ReflectUtils.getDesc(m), m);\n            }\n            c3.append(\" } catch(Throwable e) { \");\n            c3.append(\"     throw new java.lang.reflect.InvocationTargetException(e); \");\n            c3.append(\" }\");\n        }\n\n        c3.append(\" throw new \")\n                .append(NoSuchMethodException.class.getName())\n                .append(\"(\\\"Not found method \\\\\\\"\\\"+$2+\\\"\\\\\\\" in class \")\n                .append(c.getName())\n                .append(\".\\\"); }\");\n\n        // deal with get/set method.\n        Matcher matcher;\n        for (Map.Entry<String, Method> entry : ms.entrySet()) {\n            String md = entry.getKey();\n            Method method = entry.getValue();\n            if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {\n                String pn = propertyName(matcher.group(1));\n                c2.append(\" if( $2.equals(\\\"\")\n                        .append(pn)\n                        .append(\"\\\") ){ return ($w)w.\")\n                        .append(method.getName())\n                        .append(\"(); }\");\n                pts.put(pn, method.getReturnType());\n            } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {\n                String pn = propertyName(matcher.group(1));\n                c2.append(\" if( $2.equals(\\\"\")\n                        .append(pn)\n                        .append(\"\\\") ){ return ($w)w.\")\n                        .append(method.getName())\n                        .append(\"(); }\");\n                pts.put(pn, method.getReturnType());\n            } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {\n                Class<?> pt = method.getParameterTypes()[0];\n                String pn = propertyName(matcher.group(1));\n                c1.append(\" if( $2.equals(\\\"\")\n                        .append(pn)\n                        .append(\"\\\") ){ w.\")\n                        .append(method.getName())\n                        .append('(')\n                        .append(arg(pt, \"$3\"))\n                        .append(\"); return; }\");\n                pts.put(pn, pt);\n            }\n        }\n        c1.append(\" throw new \")\n                .append(NoSuchPropertyException.class.getName())\n                .append(\"(\\\"Not found property \\\\\\\"\\\"+$2+\\\"\\\\\\\" field or setter method in class \")\n                .append(c.getName())\n                .append(\".\\\"); }\");\n        c2.append(\" throw new \")\n                .append(NoSuchPropertyException.class.getName())\n                .append(\"(\\\"Not found property \\\\\\\"\\\"+$2+\\\"\\\\\\\" field or getter method in class \")\n                .append(c.getName())\n                .append(\".\\\"); }\");\n\n        // make class\n        long id = WRAPPER_CLASS_COUNTER.getAndIncrement();\n        ClassGenerator cc = ClassGenerator.newInstance(cl);\n        cc.setClassName(c.getName() + \"DubboWrap\" + id);\n        cc.setSuperClass(Wrapper.class);\n\n        cc.addDefaultConstructor();\n        cc.addField(\"public static String[] pns;\"); // property name array.\n        cc.addField(\"public static \" + Map.class.getName() + \" pts;\"); // property type map.\n        cc.addField(\"public static String[] mns;\"); // all method name array.\n        cc.addField(\"public static String[] dmns;\"); // declared method name array.\n        for (int i = 0, len = ms.size(); i < len; i++) {\n            cc.addField(\"public static Class[] mts\" + i + \";\");\n        }\n\n        cc.addMethod(\"public String[] getPropertyNames(){ return pns; }\");\n        cc.addMethod(\"public boolean hasProperty(String n){ return pts.containsKey($1); }\");\n        cc.addMethod(\"public Class getPropertyType(String n){ return (Class)pts.get($1); }\");\n        cc.addMethod(\"public String[] getMethodNames(){ return mns; }\");\n        cc.addMethod(\"public String[] getDeclaredMethodNames(){ return dmns; }\");\n        cc.addMethod(c1.toString());\n        cc.addMethod(c2.toString());\n        cc.addMethod(c3.toString());\n\n        try {\n            Class<?> wc = cc.toClass(c);\n            // setup static field.\n            wc.getField(\"pts\").set(null, pts);\n            wc.getField(\"pns\").set(null, pts.keySet().toArray(new String[0]));\n            wc.getField(\"mns\").set(null, mns.toArray(new String[0]));\n            wc.getField(\"dmns\").set(null, dmns.toArray(new String[0]));\n            int ix = 0;\n            for (Method m : ms.values()) {\n                wc.getField(\"mts\" + ix++).set(null, m.getParameterTypes());\n            }\n            return (Wrapper) wc.getDeclaredConstructor().newInstance();\n        } catch (RuntimeException e) {\n            throw e;\n        } catch (Throwable e) {\n            throw new RuntimeException(e.getMessage(), e);\n        } finally {\n            cc.release();\n            pts.clear();\n            ms.clear();\n            mns.clear();\n            dmns.clear();\n        }\n    }\n\n    private static String arg(Class<?> cl, String name) {\n        if (cl.isPrimitive()) {\n            if (cl == Boolean.TYPE) {\n                return \"((Boolean)\" + name + \").booleanValue()\";\n            }\n            if (cl == Byte.TYPE) {\n                return \"((Byte)\" + name + \").byteValue()\";\n            }\n            if (cl == Character.TYPE) {\n                return \"((Character)\" + name + \").charValue()\";\n            }\n            if (cl == Double.TYPE) {\n                return \"((Number)\" + name + \").doubleValue()\";\n            }\n            if (cl == Float.TYPE) {\n                return \"((Number)\" + name + \").floatValue()\";\n            }\n            if (cl == Integer.TYPE) {\n                return \"((Number)\" + name + \").intValue()\";\n            }\n            if (cl == Long.TYPE) {\n                return \"((Number)\" + name + \").longValue()\";\n            }\n            if (cl == Short.TYPE) {\n                return \"((Number)\" + name + \").shortValue()\";\n            }\n            throw new RuntimeException(\"Unknown primitive type: \" + cl.getName());\n        }\n        return \"(\" + ReflectUtils.getName(cl) + \")\" + name;\n    }\n\n    private static String args(Class<?>[] cs, String name) {\n        int len = cs.length;\n        if (len == 0) {\n            return \"\";\n        }\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < len; i++) {\n            if (i > 0) {\n                sb.append(',');\n            }\n            sb.append(arg(cs[i], name + \"[\" + i + \"]\"));\n        }\n        return sb.toString();\n    }\n\n    private static String propertyName(String pn) {\n        return pn.length() == 1 || Character.isLowerCase(pn.charAt(1))\n                ? Character.toLowerCase(pn.charAt(0)) + pn.substring(1)\n                : pn;\n    }\n\n    /**\n     * get property name array.\n     *\n     * @return property name array.\n     */\n    public abstract String[] getPropertyNames();\n\n    /**\n     * get property type.\n     *\n     * @param pn property name.\n     * @return Property type or nul.\n     */\n    public abstract Class<?> getPropertyType(String pn);\n\n    /**\n     * has property.\n     *\n     * @param name property name.\n     * @return has or has not.\n     */\n    public abstract boolean hasProperty(String name);\n\n    /**\n     * get property value.\n     *\n     * @param instance instance.\n     * @param pn       property name.\n     * @return value.\n     */\n    public abstract Object getPropertyValue(Object instance, String pn)\n            throws NoSuchPropertyException, IllegalArgumentException;\n\n    /**\n     * set property value.\n     *\n     * @param instance instance.\n     * @param pn       property name.\n     * @param pv       property value.\n     */\n    public abstract void setPropertyValue(Object instance, String pn, Object pv)\n            throws NoSuchPropertyException, IllegalArgumentException;\n\n    /**\n     * get property value.\n     *\n     * @param instance instance.\n     * @param pns      property name array.\n     * @return value array.\n     */\n    public Object[] getPropertyValues(Object instance, String[] pns)\n            throws NoSuchPropertyException, IllegalArgumentException {\n        Object[] ret = new Object[pns.length];\n        for (int i = 0; i < ret.length; i++) {\n            ret[i] = getPropertyValue(instance, pns[i]);\n        }\n        return ret;\n    }\n\n    /**\n     * set property value.\n     *\n     * @param instance instance.\n     * @param pns      property name array.\n     * @param pvs      property value array.\n     */\n    public void setPropertyValues(Object instance, String[] pns, Object[] pvs)\n            throws NoSuchPropertyException, IllegalArgumentException {\n        if (pns.length != pvs.length) {\n            throw new IllegalArgumentException(\"pns.length != pvs.length\");\n        }\n\n        for (int i = 0; i < pns.length; i++) {\n            setPropertyValue(instance, pns[i], pvs[i]);\n        }\n    }\n\n    /**\n     * get method name array.\n     *\n     * @return method name array.\n     */\n    public abstract String[] getMethodNames();\n\n    /**\n     * get method name array.\n     *\n     * @return method name array.\n     */\n    public abstract String[] getDeclaredMethodNames();\n\n    /**\n     * has method.\n     *\n     * @param name method name.\n     * @return has or has not.\n     */\n    public boolean hasMethod(String name) {\n        for (String mn : getMethodNames()) {\n            if (mn.equals(name)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * invoke method.\n     *\n     * @param instance instance.\n     * @param mn       method name.\n     * @param types\n     * @param args     argument array.\n     * @return return value.\n     */\n    public abstract Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args)\n            throws NoSuchMethodException, InvocationTargetException;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/cache/FileCacheStore.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.cache;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.OutputStreamWriter;\nimport java.io.Writer;\nimport java.nio.channels.FileLock;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CACHE_MAX_ENTRY_COUNT_LIMIT_EXCEED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CACHE_MAX_FILE_SIZE_LIMIT_EXCEED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CACHE_PATH_INACCESSIBLE;\n\n/**\n * Local file interaction class that can back different caches.\n * <p>\n * All items in local file are of human friendly format.\n */\npublic class FileCacheStore {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(FileCacheStore.class);\n\n    private final String cacheFilePath;\n    private final File cacheFile;\n    private final File lockFile;\n    private final FileLock directoryLock;\n\n    private FileCacheStore(String cacheFilePath, File cacheFile, File lockFile, FileLock directoryLock) {\n        this.cacheFilePath = cacheFilePath;\n        this.cacheFile = cacheFile;\n        this.lockFile = lockFile;\n        this.directoryLock = directoryLock;\n    }\n\n    public synchronized Map<String, String> loadCache(int entrySize) throws IOException {\n        Map<String, String> properties = new HashMap<>();\n        try (BufferedReader reader = new BufferedReader(new FileReader(cacheFile))) {\n            int count = 1;\n            String line = reader.readLine();\n            while (line != null && count <= entrySize) {\n                // content has '=' need to be encoded before write\n                if (!line.startsWith(\"#\") && line.contains(\"=\")) {\n                    String[] pairs = line.split(\"=\");\n                    properties.put(pairs[0], pairs[1]);\n                    count++;\n                }\n                line = reader.readLine();\n            }\n\n            if (count > entrySize) {\n                logger.warn(\n                        COMMON_CACHE_MAX_FILE_SIZE_LIMIT_EXCEED,\n                        \"mis-configuration of system properties\",\n                        \"Check Java system property 'dubbo.mapping.cache.entrySize' and 'dubbo.meta.cache.entrySize'.\",\n                        \"Cache file was truncated for exceeding the maximum entry size: \" + entrySize);\n            }\n        } catch (IOException e) {\n            logger.warn(COMMON_CACHE_PATH_INACCESSIBLE, \"inaccessible of cache path\", \"\", \"Load cache failed \", e);\n\n            throw e;\n        }\n        return properties;\n    }\n\n    private void unlock() {\n        if (directoryLock != null && directoryLock.isValid()) {\n            try {\n                directoryLock.release();\n                directoryLock.channel().close();\n                deleteFile(lockFile);\n            } catch (IOException e) {\n                logger.error(\n                        COMMON_CACHE_PATH_INACCESSIBLE,\n                        \"inaccessible of cache path\",\n                        \"\",\n                        \"Failed to release cache path's lock file:\" + lockFile,\n                        e);\n\n                throw new RuntimeException(\"Failed to release cache path's lock file:\" + lockFile, e);\n            }\n        }\n    }\n\n    public synchronized void refreshCache(Map<String, String> properties, String comment, long maxFileSize) {\n        if (CollectionUtils.isEmptyMap(properties)) {\n            return;\n        }\n\n        try (LimitedLengthBufferedWriter bw = new LimitedLengthBufferedWriter(\n                new OutputStreamWriter(new FileOutputStream(cacheFile, false), StandardCharsets.UTF_8), maxFileSize)) {\n\n            bw.write(\"#\" + comment);\n            bw.newLine();\n            bw.write(\"#\" + new Date());\n            bw.newLine();\n\n            for (Map.Entry<String, String> e : properties.entrySet()) {\n                String key = e.getKey();\n                String val = e.getValue();\n                bw.write(key + \"=\" + val);\n                bw.newLine();\n            }\n\n            bw.flush();\n\n            long remainSize = bw.getRemainSize();\n            if (remainSize < 0) {\n                logger.warn(\n                        COMMON_CACHE_MAX_ENTRY_COUNT_LIMIT_EXCEED,\n                        \"mis-configuration of system properties\",\n                        \"Check Java system property 'dubbo.mapping.cache.maxFileSize' and 'dubbo.meta.cache.maxFileSize'.\",\n                        \"Cache file was truncated for exceeding the maximum file size \" + maxFileSize\n                                + \" byte. Exceeded by \" + (-remainSize) + \" byte.\");\n            }\n        } catch (IOException e) {\n            logger.warn(COMMON_CACHE_PATH_INACCESSIBLE, \"inaccessible of cache path\", \"\", \"Update cache error.\", e);\n        }\n    }\n\n    private static void deleteFile(File f) {\n\n        Path pathOfFile = f.toPath();\n\n        try {\n            Files.delete(pathOfFile);\n        } catch (IOException ioException) {\n            logger.debug(\"Failed to delete file \" + f.getAbsolutePath(), ioException);\n        }\n    }\n\n    public synchronized void destroy() {\n        unlock();\n        FileCacheStoreFactory.removeCache(cacheFilePath);\n    }\n\n    public static Builder newBuilder() {\n        return new Builder();\n    }\n\n    public static class Builder {\n        private String cacheFilePath;\n        private File cacheFile;\n        private File lockFile;\n        private FileLock directoryLock;\n\n        private Builder() {}\n\n        public Builder cacheFilePath(String cacheFilePath) {\n            this.cacheFilePath = cacheFilePath;\n            return this;\n        }\n\n        public Builder cacheFile(File cacheFile) {\n            this.cacheFile = cacheFile;\n            return this;\n        }\n\n        public Builder lockFile(File lockFile) {\n            this.lockFile = lockFile;\n            return this;\n        }\n\n        public Builder directoryLock(FileLock directoryLock) {\n            this.directoryLock = directoryLock;\n            return this;\n        }\n\n        public FileCacheStore build() {\n            return new FileCacheStore(cacheFilePath, cacheFile, lockFile, directoryLock);\n        }\n    }\n\n    /**\n     * An empty (or fallback) implementation of FileCacheStore. Used when cache file creation failed.\n     */\n    protected static class Empty extends FileCacheStore {\n\n        private Empty(String cacheFilePath) {\n            super(cacheFilePath, null, null, null);\n        }\n\n        public static Empty getInstance(String cacheFilePath) {\n            return new Empty(cacheFilePath);\n        }\n\n        @Override\n        public synchronized Map<String, String> loadCache(int entrySize) throws IOException {\n            return Collections.emptyMap();\n        }\n\n        @Override\n        public synchronized void refreshCache(Map<String, String> properties, String comment, long maxFileSize) {\n            // No-op.\n        }\n    }\n\n    /**\n     * A BufferedWriter which limits the length (in bytes). When limit exceed, this writer stops writing.\n     */\n    private static class LimitedLengthBufferedWriter extends BufferedWriter {\n\n        private long remainSize;\n\n        public LimitedLengthBufferedWriter(Writer out, long maxSize) {\n            super(out);\n            this.remainSize = maxSize == 0 ? Long.MAX_VALUE : maxSize;\n        }\n\n        @Override\n        public void write(String str) throws IOException {\n            remainSize -= str.getBytes(StandardCharsets.UTF_8).length;\n            if (remainSize < 0) {\n                return;\n            }\n            super.write(str);\n        }\n\n        public long getRemainSize() {\n            return remainSize;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/cache/FileCacheStoreFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.cache;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileLock;\nimport java.nio.channels.OverlappingFileLockException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.USER_HOME;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CACHE_PATH_INACCESSIBLE;\n\n/**\n * ClassLoader Level static share.\n * Prevent FileCacheStore being operated in multi-application\n */\npublic final class FileCacheStoreFactory {\n\n    /**\n     * Forbids instantiation.\n     */\n    private FileCacheStoreFactory() {\n        throw new UnsupportedOperationException(\"No instance of 'FileCacheStoreFactory' for you! \");\n    }\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(FileCacheStoreFactory.class);\n    private static final ConcurrentMap<String, FileCacheStore> cacheMap = new ConcurrentHashMap<>();\n\n    private static final String SUFFIX = \".dubbo.cache\";\n    private static final char ESCAPE_MARK = '%';\n    private static final Set<Character> LEGAL_CHARACTERS = Collections.unmodifiableSet(new HashSet<Character>() {\n        {\n            // - $ . _ 0-9 a-z A-Z\n            add('-');\n            add('$');\n            add('.');\n            add('_');\n            for (char c = '0'; c <= '9'; c++) {\n                add(c);\n            }\n            for (char c = 'a'; c <= 'z'; c++) {\n                add(c);\n            }\n            for (char c = 'A'; c <= 'Z'; c++) {\n                add(c);\n            }\n        }\n    });\n\n    public static FileCacheStore getInstance(String basePath, String cacheName) {\n        return getInstance(basePath, cacheName, true);\n    }\n\n    public static FileCacheStore getInstance(String basePath, String cacheName, boolean enableFileCache) {\n        if (basePath == null) {\n            // default case: ~/.dubbo\n            basePath = SystemPropertyConfigUtils.getSystemProperty(USER_HOME) + File.separator + \".dubbo\";\n        }\n        if (basePath.endsWith(File.separator)) {\n            basePath = basePath.substring(0, basePath.length() - 1);\n        }\n\n        File candidate = new File(basePath);\n        Path path = candidate.toPath();\n\n        // ensure cache store path exists\n        if (!candidate.isDirectory()) {\n            try {\n                Files.createDirectories(path);\n            } catch (IOException e) {\n                // 0-3 - cache path inaccessible\n\n                logger.error(\n                        COMMON_CACHE_PATH_INACCESSIBLE,\n                        \"inaccessible of cache path\",\n                        \"\",\n                        \"Cache store path can't be created: \",\n                        e);\n\n                throw new RuntimeException(\"Cache store path can't be created: \" + candidate, e);\n            }\n        }\n\n        cacheName = safeName(cacheName);\n        if (!cacheName.endsWith(SUFFIX)) {\n            cacheName = cacheName + SUFFIX;\n        }\n\n        String cacheFilePath = basePath + File.separator + cacheName;\n\n        return ConcurrentHashMapUtils.computeIfAbsent(cacheMap, cacheFilePath, k -> getFile(k, enableFileCache));\n    }\n\n    /**\n     * sanitize a name for valid file or directory name\n     *\n     * @param name origin file name\n     * @return sanitized version of name\n     */\n    private static String safeName(String name) {\n        int len = name.length();\n        StringBuilder sb = new StringBuilder(len);\n        for (int i = 0; i < len; i++) {\n            char c = name.charAt(i);\n            if (LEGAL_CHARACTERS.contains(c)) {\n                sb.append(c);\n            } else {\n                sb.append(ESCAPE_MARK);\n                sb.append(String.format(\"%04x\", (int) c));\n            }\n        }\n        return sb.toString();\n    }\n\n    /**\n     * Get a file object for the given name\n     *\n     * @param name the file name\n     * @return a file object\n     */\n    private static FileCacheStore getFile(String name, boolean enableFileCache) {\n        if (!enableFileCache) {\n            return FileCacheStore.Empty.getInstance(name);\n        }\n\n        try {\n            FileCacheStore.Builder builder = FileCacheStore.newBuilder();\n            tryFileLock(builder, name);\n            File file = new File(name);\n\n            if (!file.exists()) {\n                Path pathObjectOfFile = file.toPath();\n                Files.createFile(pathObjectOfFile);\n            }\n\n            builder.cacheFilePath(name).cacheFile(file);\n\n            return builder.build();\n        } catch (Throwable t) {\n\n            logger.warn(\n                    COMMON_CACHE_PATH_INACCESSIBLE,\n                    \"inaccessible of cache path\",\n                    \"\",\n                    \"Failed to create file store cache. Local file cache will be disabled. Cache file name: \" + name,\n                    t);\n\n            return FileCacheStore.Empty.getInstance(name);\n        }\n    }\n\n    private static void tryFileLock(FileCacheStore.Builder builder, String fileName) throws PathNotExclusiveException {\n        File lockFile = new File(fileName + \".lock\");\n\n        FileLock dirLock;\n        try {\n            lockFile.createNewFile();\n            if (!lockFile.exists()) {\n                throw new AssertionError(\"Failed to create lock file \" + lockFile);\n            }\n            FileChannel lockFileChannel = new RandomAccessFile(lockFile, \"rw\").getChannel();\n            dirLock = lockFileChannel.tryLock();\n        } catch (OverlappingFileLockException ofle) {\n            dirLock = null;\n        } catch (IOException ioe) {\n            throw new RuntimeException(ioe);\n        }\n\n        if (dirLock == null) {\n            throw new PathNotExclusiveException(\n                    fileName + \" is not exclusive. Maybe multiple Dubbo instances are using the same folder.\");\n        }\n\n        lockFile.deleteOnExit();\n        builder.directoryLock(dirLock).lockFile(lockFile);\n    }\n\n    static void removeCache(String cacheFileName) {\n        cacheMap.remove(cacheFileName);\n    }\n\n    private static class PathNotExclusiveException extends Exception {\n        public PathNotExclusiveException(String msg) {\n            super(msg);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/compact/Dubbo2ActivateUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compact;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\n\npublic class Dubbo2ActivateUtils {\n    private static final Class<? extends Annotation> ACTIVATE_CLASS;\n    private static final Method GROUP_METHOD;\n    private static final Method VALUE_METHOD;\n    private static final Method BEFORE_METHOD;\n    private static final Method AFTER_METHOD;\n    private static final Method ORDER_METHOD;\n    private static final Method ON_CLASS_METHOD;\n\n    static {\n        ACTIVATE_CLASS = loadClass();\n        GROUP_METHOD = loadMethod(\"group\");\n        VALUE_METHOD = loadMethod(\"value\");\n        BEFORE_METHOD = loadMethod(\"before\");\n        AFTER_METHOD = loadMethod(\"after\");\n        ORDER_METHOD = loadMethod(\"order\");\n        ON_CLASS_METHOD = loadMethod(\"onClass\");\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static Class<? extends Annotation> loadClass() {\n        try {\n            Class<?> clazz = Class.forName(\"com.alibaba.dubbo.common.extension.Activate\");\n            if (clazz.isAnnotation()) {\n                return (Class<? extends Annotation>) clazz;\n            } else {\n                return null;\n            }\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static boolean isActivateLoaded() {\n        return ACTIVATE_CLASS != null;\n    }\n\n    public static Class<? extends Annotation> getActivateClass() {\n        return ACTIVATE_CLASS;\n    }\n\n    private static Method loadMethod(String name) {\n        if (ACTIVATE_CLASS == null) {\n            return null;\n        }\n        try {\n            return ACTIVATE_CLASS.getMethod(name);\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static String[] getGroup(Annotation annotation) {\n        if (GROUP_METHOD == null) {\n            return null;\n        }\n        try {\n            Object result = GROUP_METHOD.invoke(annotation);\n            if (result instanceof String[]) {\n                return (String[]) result;\n            } else {\n                return null;\n            }\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static String[] getValue(Annotation annotation) {\n        if (VALUE_METHOD == null) {\n            return null;\n        }\n        try {\n            Object result = VALUE_METHOD.invoke(annotation);\n            if (result instanceof String[]) {\n                return (String[]) result;\n            } else {\n                return null;\n            }\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static String[] getBefore(Annotation annotation) {\n        if (BEFORE_METHOD == null) {\n            return null;\n        }\n        try {\n            Object result = BEFORE_METHOD.invoke(annotation);\n            if (result instanceof String[]) {\n                return (String[]) result;\n            } else {\n                return null;\n            }\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static String[] getAfter(Annotation annotation) {\n        if (AFTER_METHOD == null) {\n            return null;\n        }\n        try {\n            Object result = AFTER_METHOD.invoke(annotation);\n            if (result instanceof String[]) {\n                return (String[]) result;\n            } else {\n                return null;\n            }\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static int getOrder(Annotation annotation) {\n        if (ORDER_METHOD == null) {\n            return 0;\n        }\n        try {\n            Object result = ORDER_METHOD.invoke(annotation);\n            if (result instanceof Integer) {\n                return (Integer) result;\n            } else {\n                return 0;\n            }\n        } catch (Throwable e) {\n            return 0;\n        }\n    }\n\n    public static String[] getOnClass(Annotation annotation) {\n        if (ON_CLASS_METHOD == null) {\n            return null;\n        }\n        try {\n            Object result = ON_CLASS_METHOD.invoke(annotation);\n            if (result instanceof String[]) {\n                return (String[]) result;\n            } else {\n                return null;\n            }\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/compact/Dubbo2CompactUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compact;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.lang.annotation.Annotation;\n\npublic class Dubbo2CompactUtils {\n    private static volatile boolean enabled = true;\n    private static final Class<? extends Annotation> REFERENCE_CLASS;\n    private static final Class<? extends Annotation> SERVICE_CLASS;\n    private static final Class<?> ECHO_SERVICE_CLASS;\n    private static final Class<?> GENERIC_SERVICE_CLASS;\n\n    static {\n        initEnabled();\n        REFERENCE_CLASS = loadAnnotation(\"com.alibaba.dubbo.config.annotation.Reference\");\n        SERVICE_CLASS = loadAnnotation(\"com.alibaba.dubbo.config.annotation.Service\");\n        ECHO_SERVICE_CLASS = loadClass(\"com.alibaba.dubbo.rpc.service.EchoService\");\n        GENERIC_SERVICE_CLASS = loadClass(\"com.alibaba.dubbo.rpc.service.GenericService\");\n    }\n\n    private static void initEnabled() {\n        try {\n            String fromProp =\n                    SystemPropertyConfigUtils.getSystemProperty(CommonConstants.DubboProperty.DUBBO2_COMPACT_ENABLE);\n            if (StringUtils.isNotEmpty(fromProp)) {\n                enabled = Boolean.parseBoolean(fromProp);\n                return;\n            }\n            String fromEnv = System.getenv(CommonConstants.DubboProperty.DUBBO2_COMPACT_ENABLE);\n            if (StringUtils.isNotEmpty(fromEnv)) {\n                enabled = Boolean.parseBoolean(fromEnv);\n                return;\n            }\n            fromEnv = System.getenv(StringUtils.toOSStyleKey(CommonConstants.DubboProperty.DUBBO2_COMPACT_ENABLE));\n            enabled = !StringUtils.isNotEmpty(fromEnv) || Boolean.parseBoolean(fromEnv);\n        } catch (Throwable t) {\n            enabled = true;\n        }\n    }\n\n    public static boolean isEnabled() {\n        return enabled;\n    }\n\n    public static void setEnabled(boolean enabled) {\n        Dubbo2CompactUtils.enabled = enabled;\n    }\n\n    private static Class<?> loadClass(String name) {\n        try {\n            return Class.forName(name);\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static Class<? extends Annotation> loadAnnotation(String name) {\n        try {\n            Class<?> clazz = Class.forName(name);\n            if (clazz.isAnnotation()) {\n                return (Class<? extends Annotation>) clazz;\n            } else {\n                return null;\n            }\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static boolean isReferenceClassLoaded() {\n        return REFERENCE_CLASS != null;\n    }\n\n    public static Class<? extends Annotation> getReferenceClass() {\n        return REFERENCE_CLASS;\n    }\n\n    public static boolean isServiceClassLoaded() {\n        return SERVICE_CLASS != null;\n    }\n\n    public static Class<? extends Annotation> getServiceClass() {\n        return SERVICE_CLASS;\n    }\n\n    public static boolean isEchoServiceClassLoaded() {\n        return ECHO_SERVICE_CLASS != null;\n    }\n\n    public static Class<?> getEchoServiceClass() {\n        return ECHO_SERVICE_CLASS;\n    }\n\n    public static boolean isGenericServiceClassLoaded() {\n        return GENERIC_SERVICE_CLASS != null;\n    }\n\n    public static Class<?> getGenericServiceClass() {\n        return GENERIC_SERVICE_CLASS;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/compact/Dubbo2GenericExceptionUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compact;\n\nimport org.apache.dubbo.rpc.service.GenericException;\n\nimport java.lang.reflect.Constructor;\n\npublic class Dubbo2GenericExceptionUtils {\n    private static final Class<? extends org.apache.dubbo.rpc.service.GenericException> GENERIC_EXCEPTION_CLASS;\n    private static final Constructor<? extends org.apache.dubbo.rpc.service.GenericException>\n            GENERIC_EXCEPTION_CONSTRUCTOR;\n    private static final Constructor<? extends org.apache.dubbo.rpc.service.GenericException>\n            GENERIC_EXCEPTION_CONSTRUCTOR_S;\n    private static final Constructor<? extends org.apache.dubbo.rpc.service.GenericException>\n            GENERIC_EXCEPTION_CONSTRUCTOR_S_S;\n    private static final Constructor<? extends org.apache.dubbo.rpc.service.GenericException>\n            GENERIC_EXCEPTION_CONSTRUCTOR_T;\n    private static final Constructor<? extends org.apache.dubbo.rpc.service.GenericException>\n            GENERIC_EXCEPTION_CONSTRUCTOR_S_T_S_S;\n\n    static {\n        GENERIC_EXCEPTION_CLASS = loadClass();\n        GENERIC_EXCEPTION_CONSTRUCTOR = loadConstructor();\n        GENERIC_EXCEPTION_CONSTRUCTOR_S = loadConstructor(String.class);\n        GENERIC_EXCEPTION_CONSTRUCTOR_S_S = loadConstructor(String.class, String.class);\n        GENERIC_EXCEPTION_CONSTRUCTOR_T = loadConstructor(Throwable.class);\n        GENERIC_EXCEPTION_CONSTRUCTOR_S_T_S_S =\n                loadConstructor(String.class, Throwable.class, String.class, String.class);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static Class<? extends org.apache.dubbo.rpc.service.GenericException> loadClass() {\n        try {\n            Class<?> clazz = Class.forName(\"com.alibaba.dubbo.rpc.service.GenericException\");\n            if (GenericException.class.isAssignableFrom(clazz)) {\n                return (Class<? extends org.apache.dubbo.rpc.service.GenericException>) clazz;\n            } else {\n                return null;\n            }\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    private static Constructor<? extends org.apache.dubbo.rpc.service.GenericException> loadConstructor(\n            Class<?>... parameterTypes) {\n        if (GENERIC_EXCEPTION_CLASS == null) {\n            return null;\n        }\n        try {\n            return GENERIC_EXCEPTION_CLASS.getConstructor(parameterTypes);\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static boolean isGenericExceptionClassLoaded() {\n        return GENERIC_EXCEPTION_CLASS != null\n                && GENERIC_EXCEPTION_CONSTRUCTOR != null\n                && GENERIC_EXCEPTION_CONSTRUCTOR_S != null\n                && GENERIC_EXCEPTION_CONSTRUCTOR_S_S != null\n                && GENERIC_EXCEPTION_CONSTRUCTOR_T != null\n                && GENERIC_EXCEPTION_CONSTRUCTOR_S_T_S_S != null;\n    }\n\n    public static Class<? extends org.apache.dubbo.rpc.service.GenericException> getGenericExceptionClass() {\n        return GENERIC_EXCEPTION_CLASS;\n    }\n\n    public static org.apache.dubbo.rpc.service.GenericException newGenericException() {\n        if (GENERIC_EXCEPTION_CONSTRUCTOR == null) {\n            return null;\n        }\n        try {\n            return GENERIC_EXCEPTION_CONSTRUCTOR.newInstance();\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static org.apache.dubbo.rpc.service.GenericException newGenericException(String exceptionMessage) {\n        if (GENERIC_EXCEPTION_CONSTRUCTOR_S == null) {\n            return null;\n        }\n        try {\n            return GENERIC_EXCEPTION_CONSTRUCTOR_S.newInstance(exceptionMessage);\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static org.apache.dubbo.rpc.service.GenericException newGenericException(\n            String exceptionClass, String exceptionMessage) {\n        if (GENERIC_EXCEPTION_CONSTRUCTOR_S_S == null) {\n            return null;\n        }\n        try {\n            return GENERIC_EXCEPTION_CONSTRUCTOR_S_S.newInstance(exceptionClass, exceptionMessage);\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static org.apache.dubbo.rpc.service.GenericException newGenericException(Throwable cause) {\n        if (GENERIC_EXCEPTION_CONSTRUCTOR_T == null) {\n            return null;\n        }\n        try {\n            return GENERIC_EXCEPTION_CONSTRUCTOR_T.newInstance(cause);\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static org.apache.dubbo.rpc.service.GenericException newGenericException(\n            String message, Throwable cause, String exceptionClass, String exceptionMessage) {\n        if (GENERIC_EXCEPTION_CONSTRUCTOR_S_T_S_S == null) {\n            return null;\n        }\n        try {\n            return GENERIC_EXCEPTION_CONSTRUCTOR_S_T_S_S.newInstance(message, cause, exceptionClass, exceptionMessage);\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/compiler/Compiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * Compiler. (SPI, Singleton, ThreadSafe)\n */\n@SPI(value = \"javassist\", scope = ExtensionScope.FRAMEWORK)\npublic interface Compiler {\n\n    /**\n     * Compile java source code.\n     *\n     * @param code        Java source code\n     * @param classLoader classloader\n     * @return Compiled class\n     * @deprecated use {@link Compiler#compile(Class, String, ClassLoader)} to support JDK 16\n     */\n    @Deprecated\n    default Class<?> compile(String code, ClassLoader classLoader) {\n        return compile(null, code, classLoader);\n    }\n\n    /**\n     * Compile java source code.\n     *\n     * @param neighbor    A class belonging to the same package that this\n     *                    class belongs to.  It is used to load the class. (For JDK 16 and above)\n     * @param code        Java source code\n     * @param classLoader classloader\n     * @return Compiled class\n     */\n    default Class<?> compile(Class<?> neighbor, String code, ClassLoader classLoader) {\n        return compile(code, classLoader);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/AbstractCompiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport org.apache.dubbo.common.compiler.Compiler;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Abstract compiler. (SPI, Prototype, ThreadSafe)\n */\npublic abstract class AbstractCompiler implements Compiler {\n\n    private static final Pattern PACKAGE_PATTERN = Pattern.compile(\"package\\\\s+([$_a-zA-Z][$_a-zA-Z0-9\\\\.]*);\");\n\n    private static final Pattern CLASS_PATTERN = Pattern.compile(\"class\\\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\\\s+\");\n\n    private static final Map<String, Lock> CLASS_IN_CREATION_MAP = new ConcurrentHashMap<>();\n\n    @Override\n    public Class<?> compile(Class<?> neighbor, String code, ClassLoader classLoader) {\n        code = code.trim();\n        Matcher matcher = PACKAGE_PATTERN.matcher(code);\n        String pkg;\n        if (matcher.find()) {\n            pkg = matcher.group(1);\n        } else {\n            pkg = \"\";\n        }\n        matcher = CLASS_PATTERN.matcher(code);\n        String cls;\n        if (matcher.find()) {\n            cls = matcher.group(1);\n        } else {\n            throw new IllegalArgumentException(\"No such class name in \" + code);\n        }\n        String className = pkg != null && pkg.length() > 0 ? pkg + \".\" + cls : cls;\n        Lock lock = CLASS_IN_CREATION_MAP.get(className);\n        if (lock == null) {\n            CLASS_IN_CREATION_MAP.putIfAbsent(className, new ReentrantLock());\n            lock = CLASS_IN_CREATION_MAP.get(className);\n        }\n        try {\n            lock.lock();\n            return Class.forName(className, true, classLoader);\n        } catch (ClassNotFoundException e) {\n            if (!code.endsWith(\"}\")) {\n                throw new IllegalStateException(\"The java code not endsWith \\\"}\\\", code: \\n\" + code + \"\\n\");\n            }\n            try {\n                return doCompile(neighbor, classLoader, className, code);\n            } catch (RuntimeException t) {\n                throw t;\n            } catch (Throwable t) {\n                throw new IllegalStateException(\"Failed to compile class, cause: \" + t.getMessage() + \", class: \"\n                        + className + \", code: \\n\" + code + \"\\n, stack: \" + ClassUtils.toString(t));\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    protected Class<?> doCompile(ClassLoader classLoader, String name, String source) throws Throwable {\n        return null;\n    }\n\n    protected Class<?> doCompile(Class<?> neighbor, ClassLoader classLoader, String name, String source)\n            throws Throwable {\n        return doCompile(classLoader, name, source);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/AdaptiveCompiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport org.apache.dubbo.common.compiler.Compiler;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\n/**\n * AdaptiveCompiler. (SPI, Singleton, ThreadSafe)\n */\n@Adaptive\npublic class AdaptiveCompiler implements Compiler, ScopeModelAware {\n    private FrameworkModel frameworkModel;\n\n    @Override\n    public void setFrameworkModel(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    private static volatile String DEFAULT_COMPILER;\n\n    public static void setDefaultCompiler(String compiler) {\n        DEFAULT_COMPILER = compiler;\n    }\n\n    @Override\n    public Class<?> compile(Class<?> neighbor, String code, ClassLoader classLoader) {\n        Compiler compiler;\n        ExtensionLoader<Compiler> loader = frameworkModel.getExtensionLoader(Compiler.class);\n        String name = DEFAULT_COMPILER; // copy reference\n        if (name != null && name.length() > 0) {\n            compiler = loader.getExtension(name);\n        } else {\n            compiler = loader.getDefaultExtension();\n        }\n        return compiler.compile(neighbor, code, classLoader);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * ClassUtils. (Tool, Static, ThreadSafe)\n */\npublic class ClassUtils {\n\n    public static final String CLASS_EXTENSION = \".class\";\n\n    public static final String JAVA_EXTENSION = \".java\";\n    private static final int JIT_LIMIT = 5 * 1024;\n\n    private ClassUtils() {}\n\n    public static Object newInstance(String name) {\n        try {\n            return forName(name).getDeclaredConstructor().newInstance();\n        } catch (InstantiationException\n                | IllegalAccessException\n                | InvocationTargetException\n                | NoSuchMethodException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    public static Class<?> forName(String[] packages, String className) {\n        try {\n            return classForName(className);\n        } catch (ClassNotFoundException e) {\n            if (packages != null && packages.length > 0) {\n                for (String pkg : packages) {\n                    try {\n                        return classForName(pkg + \".\" + className);\n                    } catch (ClassNotFoundException ignore) {\n                    }\n                }\n            }\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    public static Class<?> forName(String className) {\n        try {\n            return classForName(className);\n        } catch (ClassNotFoundException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    public static Class<?> classForName(String className) throws ClassNotFoundException {\n        switch (className) {\n            case \"boolean\":\n                return boolean.class;\n            case \"byte\":\n                return byte.class;\n            case \"char\":\n                return char.class;\n            case \"short\":\n                return short.class;\n            case \"int\":\n                return int.class;\n            case \"long\":\n                return long.class;\n            case \"float\":\n                return float.class;\n            case \"double\":\n                return double.class;\n            case \"boolean[]\":\n                return boolean[].class;\n            case \"byte[]\":\n                return byte[].class;\n            case \"char[]\":\n                return char[].class;\n            case \"short[]\":\n                return short[].class;\n            case \"int[]\":\n                return int[].class;\n            case \"long[]\":\n                return long[].class;\n            case \"float[]\":\n                return float[].class;\n            case \"double[]\":\n                return double[].class;\n            default:\n        }\n        try {\n            return arrayForName(className);\n        } catch (ClassNotFoundException e) {\n            // try to load from java.lang package\n            if (className.indexOf('.') == -1) {\n                try {\n                    return arrayForName(\"java.lang.\" + className);\n                } catch (ClassNotFoundException ignore) {\n                    // ignore, let the original exception be thrown\n                }\n            }\n            throw e;\n        }\n    }\n\n    private static Class<?> arrayForName(String className) throws ClassNotFoundException {\n        return Class.forName(\n                className.endsWith(\"[]\") ? \"[L\" + className.substring(0, className.length() - 2) + \";\" : className,\n                true,\n                Thread.currentThread().getContextClassLoader());\n    }\n\n    public static Class<?> getBoxedClass(Class<?> type) {\n        if (type == boolean.class) {\n            return Boolean.class;\n        } else if (type == char.class) {\n            return Character.class;\n        } else if (type == byte.class) {\n            return Byte.class;\n        } else if (type == short.class) {\n            return Short.class;\n        } else if (type == int.class) {\n            return Integer.class;\n        } else if (type == long.class) {\n            return Long.class;\n        } else if (type == float.class) {\n            return Float.class;\n        } else if (type == double.class) {\n            return Double.class;\n        } else {\n            return type;\n        }\n    }\n\n    public static Boolean boxed(boolean v) {\n        return Boolean.valueOf(v);\n    }\n\n    public static Character boxed(char v) {\n        return Character.valueOf(v);\n    }\n\n    public static Byte boxed(byte v) {\n        return Byte.valueOf(v);\n    }\n\n    public static Short boxed(short v) {\n        return Short.valueOf(v);\n    }\n\n    public static Integer boxed(int v) {\n        return Integer.valueOf(v);\n    }\n\n    public static Long boxed(long v) {\n        return Long.valueOf(v);\n    }\n\n    public static Float boxed(float v) {\n        return Float.valueOf(v);\n    }\n\n    public static Double boxed(double v) {\n        return Double.valueOf(v);\n    }\n\n    public static Object boxed(Object v) {\n        return v;\n    }\n\n    public static boolean unboxed(Boolean v) {\n        return v == null ? false : v.booleanValue();\n    }\n\n    public static char unboxed(Character v) {\n        return v == null ? '\\0' : v.charValue();\n    }\n\n    public static byte unboxed(Byte v) {\n        return v == null ? 0 : v.byteValue();\n    }\n\n    public static short unboxed(Short v) {\n        return v == null ? 0 : v.shortValue();\n    }\n\n    public static int unboxed(Integer v) {\n        return v == null ? 0 : v.intValue();\n    }\n\n    public static long unboxed(Long v) {\n        return v == null ? 0 : v.longValue();\n    }\n\n    public static float unboxed(Float v) {\n        return v == null ? 0 : v.floatValue();\n    }\n\n    public static double unboxed(Double v) {\n        return v == null ? 0 : v.doubleValue();\n    }\n\n    public static Object unboxed(Object v) {\n        return v;\n    }\n\n    public static boolean isNotEmpty(Object object) {\n        return getSize(object) > 0;\n    }\n\n    public static int getSize(Object object) {\n        if (object == null) {\n            return 0;\n        }\n        if (object instanceof Collection<?>) {\n            return ((Collection<?>) object).size();\n        } else if (object instanceof Map<?, ?>) {\n            return ((Map<?, ?>) object).size();\n        } else if (object.getClass().isArray()) {\n            return Array.getLength(object);\n        } else {\n            return -1;\n        }\n    }\n\n    public static URI toURI(String name) {\n        try {\n            return new URI(name);\n        } catch (URISyntaxException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static boolean isBeforeJava5(String javaVersion) {\n        return (StringUtils.isEmpty(javaVersion)\n                || \"1.0\".equals(javaVersion)\n                || \"1.1\".equals(javaVersion)\n                || \"1.2\".equals(javaVersion)\n                || \"1.3\".equals(javaVersion)\n                || \"1.4\".equals(javaVersion));\n    }\n\n    public static boolean isBeforeJava6(String javaVersion) {\n        return isBeforeJava5(javaVersion) || \"1.5\".equals(javaVersion);\n    }\n\n    public static String toString(Throwable e) {\n        StringWriter w = new StringWriter();\n        PrintWriter p = new PrintWriter(w);\n        p.print(e.getClass().getName() + \": \");\n        if (e.getMessage() != null) {\n            p.print(e.getMessage() + \"\\n\");\n        }\n        p.println();\n        try {\n            e.printStackTrace(p);\n            return w.toString();\n        } finally {\n            p.close();\n        }\n    }\n\n    public static void checkBytecode(String name, byte[] bytecode) {\n        if (bytecode.length > JIT_LIMIT) {\n            System.err.println(\n                    \"The template bytecode too long, may be affect the JIT compiler. template class: \" + name);\n        }\n    }\n\n    public static String getSizeMethod(Class<?> cls) {\n        try {\n            return cls.getMethod(\"size\", new Class<?>[0]).getName() + \"()\";\n        } catch (NoSuchMethodException e) {\n            try {\n                return cls.getMethod(\"length\", new Class<?>[0]).getName() + \"()\";\n            } catch (NoSuchMethodException e2) {\n                try {\n                    return cls.getMethod(\"getSize\", new Class<?>[0]).getName() + \"()\";\n                } catch (NoSuchMethodException e3) {\n                    try {\n                        return cls.getMethod(\"getLength\", new Class<?>[0]).getName() + \"()\";\n                    } catch (NoSuchMethodException e4) {\n                        return null;\n                    }\n                }\n            }\n        }\n    }\n\n    public static String getMethodName(Method method, Class<?>[] parameterClasses, String rightCode) {\n        StringBuilder buf = new StringBuilder(rightCode);\n        if (method.getParameterTypes().length > parameterClasses.length) {\n            Class<?>[] types = method.getParameterTypes();\n            for (int i = parameterClasses.length; i < types.length; i++) {\n                if (buf.length() > 0) {\n                    buf.append(',');\n                }\n                Class<?> type = types[i];\n                String def;\n                if (type == boolean.class) {\n                    def = \"false\";\n                } else if (type == char.class) {\n                    def = \"\\'\\\\0\\'\";\n                } else if (type == byte.class\n                        || type == short.class\n                        || type == int.class\n                        || type == long.class\n                        || type == float.class\n                        || type == double.class) {\n                    def = \"0\";\n                } else {\n                    def = \"null\";\n                }\n                buf.append(def);\n            }\n        }\n        return method.getName() + \"(\" + buf + \")\";\n    }\n\n    public static Method searchMethod(Class<?> currentClass, String name, Class<?>[] parameterTypes)\n            throws NoSuchMethodException {\n        if (currentClass == null) {\n            throw new NoSuchMethodException(\"class == null\");\n        }\n        try {\n            return currentClass.getMethod(name, parameterTypes);\n        } catch (NoSuchMethodException e) {\n            for (Method method : currentClass.getMethods()) {\n                if (method.getName().equals(name)\n                        && parameterTypes.length == method.getParameterTypes().length\n                        && Modifier.isPublic(method.getModifiers())) {\n                    if (parameterTypes.length > 0) {\n                        Class<?>[] types = method.getParameterTypes();\n                        boolean match = true;\n                        for (int i = 0; i < parameterTypes.length; i++) {\n                            if (!types[i].isAssignableFrom(parameterTypes[i])) {\n                                match = false;\n                                break;\n                            }\n                        }\n                        if (!match) {\n                            continue;\n                        }\n                    }\n                    return method;\n                }\n            }\n            throw e;\n        }\n    }\n\n    public static String getInitCode(Class<?> type) {\n        if (byte.class.equals(type)\n                || short.class.equals(type)\n                || int.class.equals(type)\n                || long.class.equals(type)\n                || float.class.equals(type)\n                || double.class.equals(type)) {\n            return \"0\";\n        } else if (char.class.equals(type)) {\n            return \"'\\\\0'\";\n        } else if (boolean.class.equals(type)) {\n            return \"false\";\n        } else {\n            return \"null\";\n        }\n    }\n\n    public static <K, V> Map<K, V> toMap(Map.Entry<K, V>[] entries) {\n        Map<K, V> map = new HashMap<>();\n        if (entries != null && entries.length > 0) {\n            for (Map.Entry<K, V> entry : entries) {\n                map.put(entry.getKey(), entry.getValue());\n            }\n        }\n        return map;\n    }\n\n    /**\n     * get simple class name from qualified class name\n     */\n    public static String getSimpleClassName(String qualifiedName) {\n        if (null == qualifiedName) {\n            return null;\n        }\n        int i = qualifiedName.lastIndexOf('.');\n        return i < 0 ? qualifiedName : qualifiedName.substring(i + 1);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/CtClassBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport org.apache.dubbo.common.bytecode.DubboLoaderClassPath;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport javassist.CannotCompileException;\nimport javassist.ClassPool;\nimport javassist.CtClass;\nimport javassist.CtField;\nimport javassist.CtNewConstructor;\nimport javassist.CtNewMethod;\nimport javassist.LoaderClassPath;\nimport javassist.NotFoundException;\n\n/**\n * CtClassBuilder is builder for CtClass\n * <p>\n * contains all the information, including:\n * <p>\n * class name, imported packages, super class name, implemented interfaces, constructors, fields, methods.\n */\npublic class CtClassBuilder {\n\n    private String className;\n\n    private String superClassName = \"java.lang.Object\";\n\n    private final List<String> imports = new ArrayList<>();\n\n    private final Map<String, String> fullNames = new HashMap<>();\n\n    private final List<String> ifaces = new ArrayList<>();\n\n    private final List<String> constructors = new ArrayList<>();\n\n    private final List<String> fields = new ArrayList<>();\n\n    private final List<String> methods = new ArrayList<>();\n\n    public String getClassName() {\n        return className;\n    }\n\n    public void setClassName(String className) {\n        this.className = className;\n    }\n\n    public String getSuperClassName() {\n        return superClassName;\n    }\n\n    public void setSuperClassName(String superClassName) {\n        this.superClassName = getQualifiedClassName(superClassName);\n    }\n\n    public List<String> getImports() {\n        return imports;\n    }\n\n    public void addImports(String pkg) {\n        int pi = pkg.lastIndexOf('.');\n        if (pi > 0) {\n            String pkgName = pkg.substring(0, pi);\n            this.imports.add(pkgName);\n            if (!pkg.endsWith(\".*\")) {\n                fullNames.put(pkg.substring(pi + 1), pkg);\n            }\n        }\n    }\n\n    public List<String> getInterfaces() {\n        return ifaces;\n    }\n\n    public void addInterface(String iface) {\n        this.ifaces.add(getQualifiedClassName(iface));\n    }\n\n    public List<String> getConstructors() {\n        return constructors;\n    }\n\n    public void addConstructor(String constructor) {\n        this.constructors.add(constructor);\n    }\n\n    public List<String> getFields() {\n        return fields;\n    }\n\n    public void addField(String field) {\n        this.fields.add(field);\n    }\n\n    public List<String> getMethods() {\n        return methods;\n    }\n\n    public void addMethod(String method) {\n        this.methods.add(method);\n    }\n\n    /**\n     * get full qualified class name\n     *\n     * @param className super class name, maybe qualified or not\n     */\n    protected String getQualifiedClassName(String className) {\n        if (className.contains(\".\")) {\n            return className;\n        }\n\n        if (fullNames.containsKey(className)) {\n            return fullNames.get(className);\n        }\n\n        return ClassUtils.forName(imports.toArray(new String[0]), className).getName();\n    }\n\n    /**\n     * build CtClass object\n     */\n    public CtClass build(ClassLoader classLoader) throws NotFoundException, CannotCompileException {\n        ClassPool pool = new ClassPool(true);\n        pool.insertClassPath(new LoaderClassPath(classLoader));\n        pool.insertClassPath(new DubboLoaderClassPath());\n\n        // create class\n        CtClass ctClass = pool.makeClass(className, pool.get(superClassName));\n\n        // add imported packages\n        imports.forEach(pool::importPackage);\n\n        // add implemented interfaces\n        for (String iface : ifaces) {\n            ctClass.addInterface(pool.get(iface));\n        }\n\n        // add constructors\n        for (String constructor : constructors) {\n            ctClass.addConstructor(CtNewConstructor.make(constructor, ctClass));\n        }\n\n        // add fields\n        for (String field : fields) {\n            ctClass.addField(CtField.make(field, ctClass));\n        }\n\n        // add methods\n        for (String method : methods) {\n            ctClass.addMethod(CtNewMethod.make(method, ctClass));\n        }\n\n        return ctClass;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JavassistCompiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport org.apache.dubbo.common.bytecode.DubboLoaderClassPath;\n\nimport java.util.Arrays;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport javassist.CannotCompileException;\nimport javassist.ClassPool;\nimport javassist.CtClass;\nimport javassist.LoaderClassPath;\n\n/**\n * JavassistCompiler. (SPI, Singleton, ThreadSafe)\n */\npublic class JavassistCompiler extends AbstractCompiler {\n\n    private static final Pattern IMPORT_PATTERN = Pattern.compile(\"import\\\\s+([\\\\w\\\\.\\\\*]+);\\n\");\n\n    private static final Pattern EXTENDS_PATTERN = Pattern.compile(\"\\\\s+extends\\\\s+([\\\\w\\\\.]+)[^\\\\{]*\\\\{\\n\");\n\n    private static final Pattern IMPLEMENTS_PATTERN = Pattern.compile(\"\\\\s+implements\\\\s+([\\\\w\\\\.]+)\\\\s*\\\\{\\n\");\n\n    private static final Pattern METHODS_PATTERN = Pattern.compile(\"\\n(private|public|protected)\\\\s+\");\n\n    private static final Pattern FIELD_PATTERN = Pattern.compile(\"[^\\n]+=[^\\n]+;\");\n\n    @Override\n    public Class<?> doCompile(Class<?> neighbor, ClassLoader classLoader, String name, String source) throws Throwable {\n        CtClassBuilder builder = new CtClassBuilder();\n        builder.setClassName(name);\n\n        // process imported classes\n        Matcher matcher = IMPORT_PATTERN.matcher(source);\n        while (matcher.find()) {\n            builder.addImports(matcher.group(1).trim());\n        }\n\n        // process extended super class\n        matcher = EXTENDS_PATTERN.matcher(source);\n        if (matcher.find()) {\n            builder.setSuperClassName(matcher.group(1).trim());\n        }\n\n        // process implemented interfaces\n        matcher = IMPLEMENTS_PATTERN.matcher(source);\n        if (matcher.find()) {\n            String[] ifaces = matcher.group(1).trim().split(\"\\\\,\");\n            Arrays.stream(ifaces).forEach(i -> builder.addInterface(i.trim()));\n        }\n\n        // process constructors, fields, methods\n        String body = source.substring(source.indexOf('{') + 1, source.length() - 1);\n        String[] methods = METHODS_PATTERN.split(body);\n        String className = ClassUtils.getSimpleClassName(name);\n        Arrays.stream(methods).map(String::trim).filter(m -> !m.isEmpty()).forEach(method -> {\n            if (method.startsWith(className)) {\n                builder.addConstructor(\"public \" + method);\n            } else if (FIELD_PATTERN.matcher(method).matches()) {\n                builder.addField(\"private \" + method);\n            } else {\n                builder.addMethod(\"public \" + method);\n            }\n        });\n\n        // compile\n        CtClass cls = builder.build(classLoader);\n\n        ClassPool cp = cls.getClassPool();\n        if (classLoader == null) {\n            classLoader = cp.getClassLoader();\n        }\n        cp.insertClassPath(new LoaderClassPath(classLoader));\n        cp.insertClassPath(new DubboLoaderClassPath());\n\n        try {\n            return cp.toClass(cls, neighbor, classLoader, JavassistCompiler.class.getProtectionDomain());\n        } catch (Throwable t) {\n            if (!(t instanceof CannotCompileException)) {\n                return cp.toClass(cls, classLoader, JavassistCompiler.class.getProtectionDomain());\n            }\n            throw t;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport javax.tools.DiagnosticCollector;\nimport javax.tools.FileObject;\nimport javax.tools.ForwardingJavaFileManager;\nimport javax.tools.JavaCompiler;\nimport javax.tools.JavaFileManager;\nimport javax.tools.JavaFileObject;\nimport javax.tools.JavaFileObject.Kind;\nimport javax.tools.SimpleJavaFileObject;\nimport javax.tools.StandardJavaFileManager;\nimport javax.tools.StandardLocation;\nimport javax.tools.ToolProvider;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URI;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.security.AccessController;\nimport java.security.PrivilegedAction;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * JdkCompiler. (SPI, Singleton, ThreadSafe)\n */\npublic class JdkCompiler extends AbstractCompiler {\n\n    private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();\n\n    private final DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>();\n\n    private final ClassLoaderImpl classLoader;\n\n    private final JavaFileManagerImpl javaFileManager;\n\n    private final List<String> options;\n\n    private static final String DEFAULT_JAVA_VERSION = \"1.8\";\n\n    private static List<String> buildDefaultOptions(String javaVersion) {\n        return Arrays.asList(\"-source\", javaVersion, \"-target\", javaVersion);\n    }\n\n    private static List<String> buildDefaultOptions() {\n        return buildDefaultOptions(DEFAULT_JAVA_VERSION);\n    }\n\n    public JdkCompiler(List<String> options) {\n        this.options = new ArrayList<>(options);\n        StandardJavaFileManager manager = compiler.getStandardFileManager(diagnosticCollector, null, null);\n        final ClassLoader loader = Thread.currentThread().getContextClassLoader();\n        if (loader instanceof URLClassLoader\n                && (!\"sun.misc.Launcher$AppClassLoader\".equals(loader.getClass().getName()))) {\n            try {\n                URLClassLoader urlClassLoader = (URLClassLoader) loader;\n                List<File> files = new ArrayList<>();\n                for (URL url : urlClassLoader.getURLs()) {\n                    files.add(new File(url.getFile()));\n                }\n                manager.setLocation(StandardLocation.CLASS_PATH, files);\n            } catch (IOException e) {\n                throw new IllegalStateException(e.getMessage(), e);\n            }\n        }\n        classLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoaderImpl>() {\n            @Override\n            public ClassLoaderImpl run() {\n                return new ClassLoaderImpl(loader);\n            }\n        });\n        javaFileManager = new JavaFileManagerImpl(manager, classLoader);\n    }\n\n    public JdkCompiler() {\n        this(buildDefaultOptions());\n    }\n\n    public JdkCompiler(String javaVersion) {\n        this(buildDefaultOptions(javaVersion));\n    }\n\n    @Override\n    public Class<?> doCompile(ClassLoader ignored, String name, String sourceCode) throws Throwable {\n        int i = name.lastIndexOf('.');\n        String packageName = i < 0 ? \"\" : name.substring(0, i);\n        String className = i < 0 ? name : name.substring(i + 1);\n        JavaFileObjectImpl javaFileObject = new JavaFileObjectImpl(className, sourceCode);\n        javaFileManager.putFileForInput(\n                StandardLocation.SOURCE_PATH, packageName, className + ClassUtils.JAVA_EXTENSION, javaFileObject);\n        Boolean result = compiler.getTask(\n                        null,\n                        javaFileManager,\n                        diagnosticCollector,\n                        options,\n                        null,\n                        Collections.singletonList(javaFileObject))\n                .call();\n        if (result == null || !result) {\n            throw new IllegalStateException(\n                    \"Compilation failed. class: \" + name + \", diagnostics: \" + diagnosticCollector.getDiagnostics());\n        }\n        return classLoader.loadClass(name);\n    }\n\n    private static final class JavaFileObjectImpl extends SimpleJavaFileObject {\n\n        private final CharSequence source;\n        private ByteArrayOutputStream bytecode;\n\n        public JavaFileObjectImpl(final String baseName, final CharSequence source) {\n            super(ClassUtils.toURI(baseName + ClassUtils.JAVA_EXTENSION), Kind.SOURCE);\n            this.source = source;\n        }\n\n        JavaFileObjectImpl(final String name, final Kind kind) {\n            super(ClassUtils.toURI(name), kind);\n            source = null;\n        }\n\n        public JavaFileObjectImpl(URI uri, Kind kind) {\n            super(uri, kind);\n            source = null;\n        }\n\n        @Override\n        public CharSequence getCharContent(final boolean ignoreEncodingErrors) throws UnsupportedOperationException {\n            if (source == null) {\n                throw new UnsupportedOperationException(\"source == null\");\n            }\n            return source;\n        }\n\n        @Override\n        public InputStream openInputStream() {\n            return new ByteArrayInputStream(getByteCode());\n        }\n\n        @Override\n        public OutputStream openOutputStream() {\n            return bytecode = new ByteArrayOutputStream();\n        }\n\n        public byte[] getByteCode() {\n            return bytecode.toByteArray();\n        }\n    }\n\n    private static final class JavaFileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {\n\n        private final ClassLoaderImpl classLoader;\n\n        private final Map<URI, JavaFileObject> fileObjects = new HashMap<>();\n\n        public JavaFileManagerImpl(JavaFileManager fileManager, ClassLoaderImpl classLoader) {\n            super(fileManager);\n            this.classLoader = classLoader;\n        }\n\n        @Override\n        public FileObject getFileForInput(Location location, String packageName, String relativeName)\n                throws IOException {\n            FileObject o = fileObjects.get(uri(location, packageName, relativeName));\n            if (o != null) {\n                return o;\n            }\n            return super.getFileForInput(location, packageName, relativeName);\n        }\n\n        public void putFileForInput(\n                StandardLocation location, String packageName, String relativeName, JavaFileObject file) {\n            fileObjects.put(uri(location, packageName, relativeName), file);\n        }\n\n        private URI uri(Location location, String packageName, String relativeName) {\n            return ClassUtils.toURI(location.getName() + '/' + packageName + '/' + relativeName);\n        }\n\n        @Override\n        public JavaFileObject getJavaFileForOutput(\n                Location location, String qualifiedName, Kind kind, FileObject outputFile) throws IOException {\n            JavaFileObject file = new JavaFileObjectImpl(qualifiedName, kind);\n            classLoader.add(qualifiedName, file);\n            return file;\n        }\n\n        @Override\n        public ClassLoader getClassLoader(JavaFileManager.Location location) {\n            return classLoader;\n        }\n\n        @Override\n        public String inferBinaryName(Location loc, JavaFileObject file) {\n            if (file instanceof JavaFileObjectImpl) {\n                return file.getName();\n            }\n            return super.inferBinaryName(loc, file);\n        }\n\n        @Override\n        public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse)\n                throws IOException {\n            Iterable<JavaFileObject> result = super.list(location, packageName, kinds, recurse);\n\n            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();\n\n            ArrayList<JavaFileObject> files = new ArrayList<>();\n\n            if (location == StandardLocation.CLASS_PATH && kinds.contains(JavaFileObject.Kind.CLASS)) {\n                for (JavaFileObject file : fileObjects.values()) {\n                    if (file.getKind() == Kind.CLASS && file.getName().startsWith(packageName)) {\n                        files.add(file);\n                    }\n                }\n\n                files.addAll(classLoader.files());\n            } else if (location == StandardLocation.SOURCE_PATH && kinds.contains(JavaFileObject.Kind.SOURCE)) {\n                for (JavaFileObject file : fileObjects.values()) {\n                    if (file.getKind() == Kind.SOURCE && file.getName().startsWith(packageName)) {\n                        files.add(file);\n                    }\n                }\n            }\n\n            for (JavaFileObject file : result) {\n                files.add(file);\n            }\n\n            return files;\n        }\n    }\n\n    private static final class ClassLoaderImpl extends ClassLoader {\n\n        private final Map<String, JavaFileObject> classes = new HashMap<>();\n\n        ClassLoaderImpl(final ClassLoader parentClassLoader) {\n            super(parentClassLoader);\n        }\n\n        Collection<JavaFileObject> files() {\n            return Collections.unmodifiableCollection(classes.values());\n        }\n\n        @Override\n        protected Class<?> findClass(final String qualifiedClassName) throws ClassNotFoundException {\n            JavaFileObject file = classes.get(qualifiedClassName);\n            if (file != null) {\n                byte[] bytes = ((JavaFileObjectImpl) file).getByteCode();\n                return defineClass(qualifiedClassName, bytes, 0, bytes.length);\n            }\n            try {\n                return org.apache.dubbo.common.utils.ClassUtils.forNameWithCallerClassLoader(\n                        qualifiedClassName, getClass());\n            } catch (ClassNotFoundException nf) {\n                return super.findClass(qualifiedClassName);\n            }\n        }\n\n        void add(final String qualifiedClassName, final JavaFileObject javaFile) {\n            classes.put(qualifiedClassName, javaFile);\n        }\n\n        @Override\n        protected synchronized Class<?> loadClass(final String name, final boolean resolve)\n                throws ClassNotFoundException {\n            return super.loadClass(name, resolve);\n        }\n\n        @Override\n        public InputStream getResourceAsStream(final String name) {\n            if (name.endsWith(ClassUtils.CLASS_EXTENSION)) {\n                String qualifiedClassName = name.substring(0, name.length() - ClassUtils.CLASS_EXTENSION.length())\n                        .replace('/', '.');\n                JavaFileObjectImpl file = (JavaFileObjectImpl) classes.get(qualifiedClassName);\n                if (file != null) {\n                    return new ByteArrayInputStream(file.getByteCode());\n                }\n            }\n            return super.getResourceAsStream(name);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/concurrent/AbortPolicy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.concurrent;\n\nimport java.util.Queue;\n\n/**\n * A handler for rejected element that throws a {@code RejectException}.\n */\npublic class AbortPolicy<E> implements Rejector<E> {\n\n    @Override\n    public void reject(final E e, final Queue<E> queue) {\n        throw new RejectException(\"no more memory can be used !\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/concurrent/CallableSafeInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.concurrent;\n\nimport org.apache.dubbo.common.resource.Disposable;\n\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Consumer;\n\n/**\n * <p>\n * A safe and lazy and removable initializer implementation that wraps a\n * {@code Callable} object.\n * </p>\n * @see org.apache.commons.lang3.concurrent.AtomicSafeInitializer\n */\npublic class CallableSafeInitializer<T> {\n    /** A guard which ensures that initialize() is called only once. */\n    private final AtomicReference<CallableSafeInitializer<T>> factory = new AtomicReference<>();\n\n    /** Holds the reference to the managed object. */\n    private final AtomicReference<T> reference = new AtomicReference<>();\n\n    /** The Callable to be executed. */\n    private final Callable<T> callable;\n\n    public CallableSafeInitializer(Callable<T> callable) {\n        this.callable = callable;\n    }\n\n    /**\n     * Get (and initialize, if not initialized yet) the required object\n     *\n     * @return lazily initialized object\n     * exception\n     */\n    // @Override\n    public final T get() {\n        T result;\n\n        while ((result = reference.get()) == null) {\n            if (factory.compareAndSet(null, this)) {\n                reference.set(initialize());\n            }\n        }\n\n        return result;\n    }\n\n    /**\n     * Creates and initializes the object managed by this\n     * {@code AtomicInitializer}. This method is called by {@link #get()} when\n     * the managed object is not available yet. An implementation can focus on\n     * the creation of the object. No synchronization is needed, as this is\n     * already handled by {@code get()}. This method is guaranteed to be called\n     * only once.\n     *\n     * @return the managed data object\n     */\n    protected T initialize() {\n        try {\n            return callable.call();\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n    }\n\n    public T remove() {\n        return this.remove(null);\n    }\n\n    public T remove(Consumer<? super T> action) {\n        // release\n        T value = reference.getAndSet(null);\n        if (value != null) {\n            if (action != null) {\n                action.accept(value);\n            }\n            if (value instanceof Disposable) {\n                ((Disposable) value).destroy();\n            }\n        }\n        factory.set(null);\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/concurrent/DiscardOldestPolicy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.concurrent;\n\nimport java.util.Queue;\n\n/**\n * A handler for rejected element that discards the oldest element.\n */\npublic class DiscardOldestPolicy<E> implements Rejector<E> {\n\n    @Override\n    public void reject(final E e, final Queue<E> queue) {\n        queue.poll();\n        queue.offer(e);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/concurrent/DiscardPolicy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.concurrent;\n\nimport java.util.Queue;\n\n/**\n * A handler for rejected element that silently discards the rejected element.\n */\npublic class DiscardPolicy<E> implements Rejector<E> {\n\n    @Override\n    public void reject(final E e, final Queue<E> queue) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/concurrent/RejectException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.concurrent;\n\nimport org.apache.dubbo.common.threadpool.MemorySafeLinkedBlockingQueue;\n\n/**\n * Exception thrown by an {@link MemorySafeLinkedBlockingQueue} when an element cannot be accepted.\n */\npublic class RejectException extends RuntimeException {\n\n    private static final long serialVersionUID = -3240015871717170195L;\n\n    /**\n     * Constructs a {@code RejectException} with no detail message. The cause is not initialized, and may subsequently be initialized by a\n     * call to {@link #initCause(Throwable) initCause}.\n     */\n    public RejectException() {}\n\n    /**\n     * Constructs a {@code RejectException} with the specified detail message. The cause is not initialized, and may subsequently be\n     * initialized by a call to {@link #initCause(Throwable) initCause}.\n     *\n     * @param message the detail message\n     */\n    public RejectException(final String message) {\n        super(message);\n    }\n\n    /**\n     * Constructs a {@code RejectException} with the specified detail message and cause.\n     *\n     * @param message the detail message\n     * @param cause   the cause (which is saved for later retrieval by the {@link #getCause()} method)\n     */\n    public RejectException(final String message, final Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Constructs a {@code RejectException} with the specified cause.  The detail message is set to {@code (cause == null ? null :\n     * cause.toString())} (which typically contains the class and detail message of {@code cause}).\n     *\n     * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method)\n     */\n    public RejectException(final Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/concurrent/Rejector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.concurrent;\n\nimport java.util.Queue;\n\n/**\n * RejectHandler, it works when you need to custom reject action.\n *\n * @see AbortPolicy\n * @see DiscardPolicy\n * @see DiscardOldestPolicy\n */\npublic interface Rejector<E> {\n\n    /**\n     * Method that may be invoked by a Queue when Queue has remained memory\n     * return true. This may occur when no more memory are available because their bounds would be exceeded.\n     *\n     * <p>In the absence of other alternatives, the method may throw an unchecked\n     * {@link RejectException}, which will be propagated to the caller.\n     *\n     * @param e     the element requested to be added\n     * @param queue the queue attempting to add this element\n     *\n     * @throws RejectException if there is no more memory\n     */\n    void reject(E e, Queue<E> queue);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ArrayUtils;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_LOAD_ENV_VARIABLE;\n\n/**\n * This is an abstraction specially customized for the sequence Dubbo retrieves properties.\n */\npublic class CompositeConfiguration implements Configuration {\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(CompositeConfiguration.class);\n\n    /**\n     * List holding all the configuration\n     */\n    private final List<Configuration> configList = new CopyOnWriteArrayList<>();\n\n    // FIXME, consider change configList to SortedMap to replace this boolean status.\n    private boolean dynamicIncluded;\n\n    public CompositeConfiguration() {}\n\n    public CompositeConfiguration(Configuration... configurations) {\n        if (ArrayUtils.isNotEmpty(configurations)) {\n            Arrays.stream(configurations)\n                    .filter(config -> !configList.contains(config))\n                    .forEach(configList::add);\n        }\n    }\n\n    // FIXME, consider changing configList to SortedMap to replace this boolean status.\n    public boolean isDynamicIncluded() {\n        return dynamicIncluded;\n    }\n\n    public void setDynamicIncluded(boolean dynamicIncluded) {\n        this.dynamicIncluded = dynamicIncluded;\n    }\n\n    public void addConfiguration(Configuration configuration) {\n        if (configList.contains(configuration)) {\n            return;\n        }\n        this.configList.add(configuration);\n    }\n\n    public void addConfigurationFirst(Configuration configuration) {\n        this.addConfiguration(0, configuration);\n    }\n\n    public void addConfiguration(int pos, Configuration configuration) {\n        this.configList.add(pos, configuration);\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        for (Configuration config : configList) {\n            try {\n                Object value = config.getProperty(key);\n                if (!ConfigurationUtils.isEmptyValue(value)) {\n                    return value;\n                }\n            } catch (Exception e) {\n                logger.error(\n                        CONFIG_FAILED_LOAD_ENV_VARIABLE,\n                        \"\",\n                        \"\",\n                        \"Error when trying to get value for key \" + key + \" from \" + config + \", \"\n                                + \"will continue to try the next one.\");\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/Configuration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.util.NoSuchElementException;\n\nimport static org.apache.dubbo.common.config.ConfigurationUtils.isEmptyValue;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_PROPERTY_TYPE_MISMATCH;\n\n/**\n * Configuration interface, to fetch the value for the specified key.\n */\npublic interface Configuration {\n\n    ErrorTypeAwareLogger interfaceLevelLogger = LoggerFactory.getErrorTypeAwareLogger(Configuration.class);\n\n    /**\n     * Get a string associated with the given configuration key.\n     *\n     * @param key The configuration key.\n     * @return The associated string.\n     */\n    default String getString(String key) {\n        return convert(String.class, key, null);\n    }\n\n    /**\n     * Get a string associated with the given configuration key.\n     * If the key doesn't map to an existing object, the default value\n     * is returned.\n     *\n     * @param key          The configuration key.\n     * @param defaultValue The default value.\n     * @return The associated string if key is found and has valid\n     * format, default value otherwise.\n     */\n    default String getString(String key, String defaultValue) {\n        return convert(String.class, key, defaultValue);\n    }\n\n    default int getInt(String key) {\n        Integer i = this.getInteger(key, null);\n        if (i != null) {\n            return i;\n        } else {\n            throw new NoSuchElementException('\\'' + key + \"' doesn't map to an existing object\");\n        }\n    }\n\n    default int getInt(String key, int defaultValue) {\n        Integer i = this.getInteger(key, null);\n        return i == null ? defaultValue : i;\n    }\n\n    default Integer getInteger(String key, Integer defaultValue) {\n        try {\n            return convert(Integer.class, key, defaultValue);\n        } catch (NumberFormatException e) {\n            // 0-2 Property type mismatch.\n            interfaceLevelLogger.error(\n                    COMMON_PROPERTY_TYPE_MISMATCH,\n                    \"typo in property value\",\n                    \"This property requires an integer value.\",\n                    \"Actual Class: \" + getClass().getName(),\n                    e);\n\n            throw new IllegalStateException('\\'' + key + \"' doesn't map to a Integer object\", e);\n        }\n    }\n\n    default boolean getBoolean(String key) {\n        Boolean b = this.getBoolean(key, null);\n        if (b != null) {\n            return b;\n        } else {\n            throw new NoSuchElementException('\\'' + key + \"' doesn't map to an existing object\");\n        }\n    }\n\n    default boolean getBoolean(String key, boolean defaultValue) {\n        return this.getBoolean(key, toBooleanObject(defaultValue));\n    }\n\n    default Boolean getBoolean(String key, Boolean defaultValue) {\n        try {\n            return convert(Boolean.class, key, defaultValue);\n        } catch (Exception e) {\n            throw new IllegalStateException(\n                    \"Try to get \" + '\\'' + key + \"' failed, maybe because this key doesn't map to a Boolean object\", e);\n        }\n    }\n\n    /**\n     * Gets a property from the configuration. This is the most basic get\n     * method for retrieving values of properties. In a typical implementation\n     * of the {@code Configuration} interface the other get methods (that\n     * return specific data types) will internally make use of this method. On\n     * this level variable substitution is not yet performed. The returned\n     * object is an internal representation of the property value for the passed\n     * in key. It is owned by the {@code Configuration} object. So a caller\n     * should not modify this object. It cannot be guaranteed that this object\n     * will stay constant over time (i.e. further update operations on the\n     * configuration may change its internal state).\n     *\n     * @param key property to retrieve\n     * @return the value to which this configuration maps the specified key, or\n     * null if the configuration contains no mapping for this key.\n     */\n    default Object getProperty(String key) {\n        return getProperty(key, null);\n    }\n\n    /**\n     * Gets a property from the configuration. The default value will return if the configuration doesn't contain\n     * the mapping for the specified key.\n     *\n     * @param key property to retrieve\n     * @param defaultValue default value\n     * @return the value to which this configuration maps the specified key, or default value if the configuration\n     * contains no mapping for this key.\n     */\n    default Object getProperty(String key, Object defaultValue) {\n        Object value = getInternalProperty(key);\n        return value != null ? value : defaultValue;\n    }\n\n    Object getInternalProperty(String key);\n\n    /**\n     * Check if the configuration contains the specified key.\n     *\n     * @param key the key whose presence in this configuration is to be tested\n     * @return {@code true} if the configuration contains a value for this\n     * key, {@code false} otherwise\n     */\n    default boolean containsKey(String key) {\n        return !isEmptyValue(getProperty(key));\n    }\n\n    default <T> T convert(Class<T> cls, String key, T defaultValue) {\n        // we only process String properties for now\n        String value = (String) getProperty(key);\n\n        if (value == null) {\n            return defaultValue;\n        }\n\n        Object obj = value;\n        if (cls.isInstance(value)) {\n            return cls.cast(value);\n        }\n\n        if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls)) {\n            obj = Boolean.valueOf(value);\n        } else if (Number.class.isAssignableFrom(cls) || cls.isPrimitive()) {\n            if (Integer.class.equals(cls) || Integer.TYPE.equals(cls)) {\n                obj = Integer.valueOf(value);\n            } else if (Long.class.equals(cls) || Long.TYPE.equals(cls)) {\n                obj = Long.valueOf(value);\n            } else if (Byte.class.equals(cls) || Byte.TYPE.equals(cls)) {\n                obj = Byte.valueOf(value);\n            } else if (Short.class.equals(cls) || Short.TYPE.equals(cls)) {\n                obj = Short.valueOf(value);\n            } else if (Float.class.equals(cls) || Float.TYPE.equals(cls)) {\n                obj = Float.valueOf(value);\n            } else if (Double.class.equals(cls) || Double.TYPE.equals(cls)) {\n                obj = Double.valueOf(value);\n            }\n        } else if (cls.isEnum()) {\n            obj = Enum.valueOf(cls.asSubclass(Enum.class), value);\n        }\n\n        return cls.cast(obj);\n    }\n\n    static Boolean toBooleanObject(boolean bool) {\n        return bool ? Boolean.TRUE : Boolean.FALSE;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Function;\n\n/**\n * Properties Cache of Configuration {@link ConfigurationUtils#getCachedDynamicProperty(ScopeModel, String, String)}\n */\npublic class ConfigurationCache {\n    private final Map<String, String> cache = new ConcurrentHashMap<>();\n\n    /**\n     * Get Cached Value\n     *\n     * @param key key\n     * @param function function to produce value, should not return `null`\n     * @return value\n     */\n    public String computeIfAbsent(String key, Function<String, String> function) {\n        String value = cache.get(key);\n        // value might be empty here!\n        // empty value from config center will be cached here\n        if (value == null) {\n            // lock free, tolerate repeat apply, will return previous value\n            cache.putIfAbsent(key, function.apply(key));\n            value = cache.get(key);\n        }\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory;\nimport org.apache.dubbo.common.extension.ExtensionAccessor;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVER_SHUTDOWN_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_PROPERTY_TYPE_MISMATCH;\n\n/**\n * Utilities for manipulating configurations from different sources\n */\npublic final class ConfigurationUtils {\n\n    /**\n     * Forbids instantiation.\n     */\n    private ConfigurationUtils() {\n        throw new UnsupportedOperationException(\"No instance of 'ConfigurationUtils' for you! \");\n    }\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConfigurationUtils.class);\n    private static final Set<String> securityKey;\n\n    private static volatile long expectedShutdownTime = Long.MAX_VALUE;\n\n    static {\n        Set<String> keys = new HashSet<>();\n        keys.add(\"accesslog\");\n        keys.add(\"router\");\n        keys.add(\"rule\");\n        keys.add(\"runtime\");\n        keys.add(\"type\");\n        securityKey = Collections.unmodifiableSet(keys);\n    }\n\n    /**\n     * Used to get properties from the jvm\n     *\n     * @return\n     */\n    public static Configuration getSystemConfiguration(ScopeModel scopeModel) {\n        return getScopeModelOrDefaultApplicationModel(scopeModel)\n                .modelEnvironment()\n                .getSystemConfiguration();\n    }\n\n    /**\n     * Used to get properties from the os environment\n     *\n     * @return\n     */\n    public static Configuration getEnvConfiguration(ScopeModel scopeModel) {\n        return getScopeModelOrDefaultApplicationModel(scopeModel)\n                .modelEnvironment()\n                .getEnvironmentConfiguration();\n    }\n\n    /**\n     * Used to get a composite property value.\n     * <p>\n     * Also see {@link Environment#getConfiguration()}\n     *\n     * @return\n     */\n    public static Configuration getGlobalConfiguration(ScopeModel scopeModel) {\n        return getScopeModelOrDefaultApplicationModel(scopeModel)\n                .modelEnvironment()\n                .getConfiguration();\n    }\n\n    public static Configuration getDynamicGlobalConfiguration(ScopeModel scopeModel) {\n        return scopeModel.modelEnvironment().getDynamicGlobalConfiguration();\n    }\n\n    // FIXME\n\n    /**\n     * Server shutdown wait timeout mills\n     *\n     * @return\n     */\n    @SuppressWarnings(\"deprecation\")\n    public static int getServerShutdownTimeout(ScopeModel scopeModel) {\n        if (expectedShutdownTime < System.currentTimeMillis()) {\n            return 1;\n        }\n        int timeout = DEFAULT_SERVER_SHUTDOWN_TIMEOUT;\n        Configuration configuration = getGlobalConfiguration(scopeModel);\n        String value = StringUtils.trim(configuration.getString(SHUTDOWN_WAIT_KEY));\n\n        if (StringUtils.isNotEmpty(value)) {\n            try {\n                timeout = Integer.parseInt(value);\n            } catch (Exception e) {\n                // ignore\n            }\n        } else {\n            value = StringUtils.trim(configuration.getString(SHUTDOWN_WAIT_SECONDS_KEY));\n            if (StringUtils.isNotEmpty(value)) {\n                try {\n                    timeout = Integer.parseInt(value) * 1000;\n                } catch (Exception e) {\n                    // ignore\n                }\n            }\n        }\n\n        if (expectedShutdownTime - System.currentTimeMillis() < timeout) {\n            return (int) Math.max(1, expectedShutdownTime - System.currentTimeMillis());\n        }\n\n        return timeout;\n    }\n\n    public static int reCalShutdownTime(int expected) {\n        // already timeout\n        if (expectedShutdownTime < System.currentTimeMillis()) {\n            return 1;\n        }\n\n        if (expectedShutdownTime - System.currentTimeMillis() < expected) {\n            // the shutdown time rest is less than expected\n            return (int) Math.max(1, expectedShutdownTime - System.currentTimeMillis());\n        }\n\n        // return the expected\n        return expected;\n    }\n\n    public static void setExpectedShutdownTime(long expectedShutdownTime) {\n        ConfigurationUtils.expectedShutdownTime = expectedShutdownTime;\n    }\n\n    public static String getCachedDynamicProperty(ScopeModel realScopeModel, String key, String defaultValue) {\n        ScopeModel scopeModel = getScopeModelOrDefaultApplicationModel(realScopeModel);\n        ConfigurationCache configurationCache = scopeModel.getBeanFactory().getBean(ConfigurationCache.class);\n        String value = configurationCache.computeIfAbsent(\n                key, _k -> ConfigurationUtils.getDynamicProperty(scopeModel, _k, \"\"));\n        return StringUtils.isEmpty(value) ? defaultValue : value;\n    }\n\n    private static ScopeModel getScopeModelOrDefaultApplicationModel(ScopeModel realScopeModel) {\n        if (realScopeModel == null) {\n            return ApplicationModel.defaultModel();\n        }\n        return realScopeModel;\n    }\n\n    public static String getDynamicProperty(ScopeModel scopeModel, String property) {\n        return getDynamicProperty(scopeModel, property, null);\n    }\n\n    public static String getDynamicProperty(ScopeModel scopeModel, String property, String defaultValue) {\n        return StringUtils.trim(getDynamicGlobalConfiguration(scopeModel).getString(property, defaultValue));\n    }\n\n    public static String getProperty(ScopeModel scopeModel, String property) {\n        return getProperty(scopeModel, property, null);\n    }\n\n    public static String getProperty(ScopeModel scopeModel, String property, String defaultValue) {\n        return StringUtils.trim(getGlobalConfiguration(scopeModel).getString(property, defaultValue));\n    }\n\n    public static int get(ScopeModel scopeModel, String property, int defaultValue) {\n        return getGlobalConfiguration(scopeModel).getInt(property, defaultValue);\n    }\n\n    public static Map<String, String> parseProperties(String content) throws IOException {\n        Map<String, String> map = new HashMap<>();\n        if (StringUtils.isEmpty(content)) {\n            logger.info(\"Config center was specified, but no config item found.\");\n        } else {\n            Properties properties = new Properties();\n            properties.load(new StringReader(content));\n            properties.stringPropertyNames().forEach(k -> {\n                boolean deny = false;\n                // check whether property name is safe or not based on the last fragment kebab-case comparison.\n                String[] fragments = k.split(\"\\\\.\");\n                if (securityKey.contains(StringUtils.convertToSplitName(fragments[fragments.length - 1], \"-\"))) {\n                    deny = true;\n                    logger.warn(\n                            COMMON_PROPERTY_TYPE_MISMATCH,\n                            \"security properties are not allowed to be set\",\n                            \"\",\n                            String.format(\"'%s' is not allowed to be set as it is on the security key list.\", k));\n                }\n                if (!deny) {\n                    map.put(k, properties.getProperty(k));\n                }\n            });\n        }\n        return map;\n    }\n\n    public static boolean isEmptyValue(Object value) {\n        return value == null || value instanceof String && StringUtils.isBlank((String) value);\n    }\n\n    /**\n     * Search props and extract sub properties.\n     * <pre>\n     * # properties\n     * dubbo.protocol.name=dubbo\n     * dubbo.protocol.port=1234\n     *\n     * # extract protocol props\n     * Map props = getSubProperties(\"dubbo.protocol.\");\n     *\n     * # result\n     * props: {\"name\": \"dubbo\", \"port\" : \"1234\"}\n     *\n     * </pre>\n     *\n     * @param configMaps\n     * @param prefix\n     * @param <V>\n     * @return\n     */\n    public static <V extends Object> Map<String, V> getSubProperties(\n            Collection<Map<String, V>> configMaps, String prefix) {\n        Map<String, V> map = new LinkedHashMap<>();\n        for (Map<String, V> configMap : configMaps) {\n            getSubProperties(configMap, prefix, map);\n        }\n        return map;\n    }\n\n    public static <V extends Object> Map<String, V> getSubProperties(Map<String, V> configMap, String prefix) {\n        return getSubProperties(configMap, prefix, null);\n    }\n\n    private static <V extends Object> Map<String, V> getSubProperties(\n            Map<String, V> configMap, String prefix, Map<String, V> resultMap) {\n        if (!prefix.endsWith(\".\")) {\n            prefix += \".\";\n        }\n\n        if (null == resultMap) {\n            resultMap = new LinkedHashMap<>();\n        }\n\n        if (CollectionUtils.isNotEmptyMap(configMap)) {\n            Map<String, V> copy;\n            synchronized (configMap) {\n                copy = new HashMap<>(configMap);\n            }\n            for (Map.Entry<String, V> entry : copy.entrySet()) {\n                String key = entry.getKey();\n                V val = entry.getValue();\n                if ((StringUtils.startsWithIgnoreCase(key, prefix)\n                                || StringUtils.startsWithIgnoreCase(key, StringUtils.toOSStyleKey(prefix)))\n                        && key.length() > prefix.length()\n                        && !ConfigurationUtils.isEmptyValue(val)) {\n\n                    String k = key.substring(prefix.length());\n                    // convert camelCase/snake_case to kebab-case\n                    String newK = StringUtils.convertToSplitName(k, \"-\");\n                    resultMap.putIfAbsent(newK, val);\n                    if (!Objects.equals(k, newK)) {\n                        resultMap.putIfAbsent(k, val);\n                    }\n                }\n            }\n        }\n\n        return resultMap;\n    }\n\n    public static <V extends Object> boolean hasSubProperties(Collection<Map<String, V>> configMaps, String prefix) {\n        if (!prefix.endsWith(\".\")) {\n            prefix += \".\";\n        }\n        for (Map<String, V> configMap : configMaps) {\n            if (hasSubProperties(configMap, prefix)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static <V extends Object> boolean hasSubProperties(Map<String, V> configMap, String prefix) {\n        if (!prefix.endsWith(\".\")) {\n            prefix += \".\";\n        }\n        Map<String, V> copy;\n        synchronized (configMap) {\n            copy = new HashMap<>(configMap);\n        }\n        for (Map.Entry<String, V> entry : copy.entrySet()) {\n            String key = entry.getKey();\n            if ((StringUtils.startsWithIgnoreCase(key, prefix)\n                            || StringUtils.startsWithIgnoreCase(key, StringUtils.toOSStyleKey(prefix)))\n                    && key.length() > prefix.length()\n                    && !ConfigurationUtils.isEmptyValue(entry.getValue())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Search props and extract config ids\n     * <pre>\n     * # properties\n     * dubbo.registries.registry1.address=xxx\n     * dubbo.registries.registry2.port=xxx\n     *\n     * # extract ids\n     * Set configIds = getSubIds(\"dubbo.registries.\")\n     *\n     * # result\n     * configIds: [\"registry1\", \"registry2\"]\n     * </pre>\n     *\n     * @param configMaps\n     * @param prefix\n     * @return\n     */\n    public static <V extends Object> Set<String> getSubIds(Collection<Map<String, V>> configMaps, String prefix) {\n        if (!prefix.endsWith(\".\")) {\n            prefix += \".\";\n        }\n        Set<String> ids = new LinkedHashSet<>();\n        for (Map<String, V> configMap : configMaps) {\n            Map<String, V> copy;\n            synchronized (configMap) {\n                copy = new HashMap<>(configMap);\n            }\n            for (Map.Entry<String, V> entry : copy.entrySet()) {\n                String key = entry.getKey();\n                V val = entry.getValue();\n                if (StringUtils.startsWithIgnoreCase(key, prefix)\n                        && key.length() > prefix.length()\n                        && !ConfigurationUtils.isEmptyValue(val)) {\n\n                    String k = key.substring(prefix.length());\n                    int endIndex = k.indexOf(\".\");\n                    if (endIndex > 0) {\n                        String id = k.substring(0, endIndex);\n                        ids.add(id);\n                    }\n                }\n            }\n        }\n        return ids;\n    }\n\n    /**\n     * Get an instance of {@link DynamicConfigurationFactory} by the specified name. If not found, take the default\n     * extension of {@link DynamicConfigurationFactory}\n     *\n     * @param name the name of extension of {@link DynamicConfigurationFactory}\n     * @return non-null\n     * @see 2.7.4\n     */\n    public static DynamicConfigurationFactory getDynamicConfigurationFactory(\n            ExtensionAccessor extensionAccessor, String name) {\n        ExtensionLoader<DynamicConfigurationFactory> loader =\n                extensionAccessor.getExtensionLoader(DynamicConfigurationFactory.class);\n        return loader.getOrDefaultExtension(name);\n    }\n\n    /**\n     * For compact single instance\n     *\n     * @deprecated Replaced to {@link ConfigurationUtils#getSystemConfiguration(ScopeModel)}\n     */\n    @Deprecated\n    public static Configuration getSystemConfiguration() {\n        return ApplicationModel.defaultModel().modelEnvironment().getSystemConfiguration();\n    }\n\n    /**\n     * For compact single instance\n     *\n     * @deprecated Replaced to {@link ConfigurationUtils#getEnvConfiguration(ScopeModel)}\n     */\n    @Deprecated\n    public static Configuration getEnvConfiguration() {\n        return ApplicationModel.defaultModel().modelEnvironment().getEnvironmentConfiguration();\n    }\n\n    /**\n     * For compact single instance\n     *\n     * @deprecated Replaced to {@link ConfigurationUtils#getGlobalConfiguration(ScopeModel)}\n     */\n    @Deprecated\n    public static Configuration getGlobalConfiguration() {\n        return ApplicationModel.defaultModel().modelEnvironment().getConfiguration();\n    }\n\n    /**\n     * For compact single instance\n     *\n     * @deprecated Replaced to {@link ConfigurationUtils#getDynamicGlobalConfiguration(ScopeModel)}\n     */\n    @Deprecated\n    public static Configuration getDynamicGlobalConfiguration() {\n        return ApplicationModel.defaultModel()\n                .getDefaultModule()\n                .modelEnvironment()\n                .getDynamicGlobalConfiguration();\n    }\n\n    /**\n     * For compact single instance\n     *\n     * @deprecated Replaced to {@link ConfigurationUtils#getCachedDynamicProperty(ScopeModel, String, String)}\n     */\n    @Deprecated\n    public static String getCachedDynamicProperty(String key, String defaultValue) {\n        return getCachedDynamicProperty(ApplicationModel.defaultModel(), key, defaultValue);\n    }\n\n    /**\n     * For compact single instance\n     *\n     * @deprecated Replaced to {@link ConfigurationUtils#getDynamicProperty(ScopeModel, String)}\n     */\n    @Deprecated\n    public static String getDynamicProperty(String property) {\n        return getDynamicProperty(ApplicationModel.defaultModel(), property);\n    }\n\n    /**\n     * For compact single instance\n     *\n     * @deprecated Replaced to {@link ConfigurationUtils#getDynamicProperty(ScopeModel, String, String)}\n     */\n    @Deprecated\n    public static String getDynamicProperty(String property, String defaultValue) {\n        return getDynamicProperty(ApplicationModel.defaultModel(), property, defaultValue);\n    }\n\n    /**\n     * For compact single instance\n     *\n     * @deprecated Replaced to {@link ConfigurationUtils#getProperty(ScopeModel, String)}\n     */\n    @Deprecated\n    public static String getProperty(String property) {\n        return getProperty(ApplicationModel.defaultModel(), property);\n    }\n\n    /**\n     * For compact single instance\n     *\n     * @deprecated Replaced to {@link ConfigurationUtils#getProperty(ScopeModel, String, String)}\n     */\n    @Deprecated\n    public static String getProperty(String property, String defaultValue) {\n        return getProperty(ApplicationModel.defaultModel(), property, defaultValue);\n    }\n\n    /**\n     * For compact single instance\n     *\n     * @deprecated Replaced to {@link ConfigurationUtils#get(ScopeModel, String, int)}\n     */\n    @Deprecated\n    public static int get(String property, int defaultValue) {\n        return get(ApplicationModel.defaultModel(), property, defaultValue);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.context.ApplicationExt;\nimport org.apache.dubbo.common.context.LifecycleAdapter;\nimport org.apache.dubbo.common.extension.DisableInject;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.context.ConfigConfigurationAdapter;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\npublic class Environment extends LifecycleAdapter implements ApplicationExt {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(Environment.class);\n\n    public static final String NAME = \"environment\";\n\n    // dubbo properties in classpath\n    private PropertiesConfiguration propertiesConfiguration;\n\n    // java system props (-D)\n    private SystemConfiguration systemConfiguration;\n\n    // java system environment\n    private EnvironmentConfiguration environmentConfiguration;\n\n    // external config, such as config-center global/default config\n    private InmemoryConfiguration externalConfiguration;\n\n    // external app config, such as config-center app config\n    private InmemoryConfiguration appExternalConfiguration;\n\n    // local app config , such as Spring Environment/PropertySources/application.properties\n    private InmemoryConfiguration appConfiguration;\n\n    protected CompositeConfiguration globalConfiguration;\n\n    protected List<Map<String, String>> globalConfigurationMaps;\n\n    private CompositeConfiguration defaultDynamicGlobalConfiguration;\n\n    private DynamicConfiguration defaultDynamicConfiguration;\n\n    private String localMigrationRule;\n\n    private final AtomicBoolean initialized = new AtomicBoolean(false);\n    private final ScopeModel scopeModel;\n\n    public Environment(ScopeModel scopeModel) {\n        this.scopeModel = scopeModel;\n    }\n\n    @Override\n    public void initialize() throws IllegalStateException {\n        if (initialized.compareAndSet(false, true)) {\n            this.propertiesConfiguration = new PropertiesConfiguration(scopeModel);\n            this.systemConfiguration = new SystemConfiguration();\n            this.environmentConfiguration = new EnvironmentConfiguration();\n            this.externalConfiguration = new InmemoryConfiguration(\"ExternalConfig\");\n            this.appExternalConfiguration = new InmemoryConfiguration(\"AppExternalConfig\");\n            this.appConfiguration = new InmemoryConfiguration(\"AppConfig\");\n\n            loadMigrationRule();\n        }\n    }\n\n    /**\n     * @deprecated MigrationRule will be removed in 3.1\n     */\n    @Deprecated\n    private void loadMigrationRule() {\n        if (Boolean.parseBoolean(SystemPropertyConfigUtils.getSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_MIGRATION_FILE_ENABLE, \"false\"))) {\n            String path =\n                    SystemPropertyConfigUtils.getSystemProperty(CommonConstants.DubboProperty.DUBBO_MIGRATION_KEY);\n            if (StringUtils.isEmpty(path)) {\n                path = System.getenv(CommonConstants.DubboProperty.DUBBO_MIGRATION_KEY);\n                if (StringUtils.isEmpty(path)) {\n                    path = CommonConstants.DEFAULT_DUBBO_MIGRATION_FILE;\n                }\n            }\n            this.localMigrationRule = ConfigUtils.loadMigrationRule(scopeModel.getClassLoaders(), path);\n        } else {\n            this.localMigrationRule = null;\n        }\n    }\n\n    /**\n     * @deprecated only for ut\n     */\n    @Deprecated\n    @DisableInject\n    public void setLocalMigrationRule(String localMigrationRule) {\n        this.localMigrationRule = localMigrationRule;\n    }\n\n    @DisableInject\n    public void setExternalConfigMap(Map<String, String> externalConfiguration) {\n        if (externalConfiguration != null) {\n            this.externalConfiguration.setProperties(externalConfiguration);\n        }\n    }\n\n    @DisableInject\n    public void setAppExternalConfigMap(Map<String, String> appExternalConfiguration) {\n        if (appExternalConfiguration != null) {\n            this.appExternalConfiguration.setProperties(appExternalConfiguration);\n        }\n    }\n\n    @DisableInject\n    public void setAppConfigMap(Map<String, String> appConfiguration) {\n        if (appConfiguration != null) {\n            this.appConfiguration.setProperties(appConfiguration);\n        }\n    }\n\n    public Map<String, String> getExternalConfigMap() {\n        return externalConfiguration.getProperties();\n    }\n\n    public Map<String, String> getAppExternalConfigMap() {\n        return appExternalConfiguration.getProperties();\n    }\n\n    public Map<String, String> getAppConfigMap() {\n        return appConfiguration.getProperties();\n    }\n\n    public void updateExternalConfigMap(Map<String, String> externalMap) {\n        this.externalConfiguration.addProperties(externalMap);\n    }\n\n    public void updateAppExternalConfigMap(Map<String, String> externalMap) {\n        this.appExternalConfiguration.addProperties(externalMap);\n    }\n\n    /**\n     * Merge target map properties into app configuration\n     *\n     * @param map\n     */\n    public void updateAppConfigMap(Map<String, String> map) {\n        this.appConfiguration.addProperties(map);\n    }\n\n    /**\n     * At start-up, Dubbo is driven by various configuration, such as Application, Registry, Protocol, etc.\n     * All configurations will be converged into a data bus - URL, and then drive the subsequent process.\n     * <p>\n     * At present, there are many configuration sources, including AbstractConfig (API, XML, annotation), - D, config center, etc.\n     * This method helps us t filter out the most priority values from various configuration sources.\n     *\n     * @param config\n     * @param prefix\n     * @return\n     */\n    public Configuration getPrefixedConfiguration(AbstractConfig config, String prefix) {\n\n        // The sequence would be: SystemConfiguration -> EnvironmentConfiguration -> AppExternalConfiguration ->\n        // ExternalConfiguration  -> AppConfiguration -> AbstractConfig -> PropertiesConfiguration\n        Configuration instanceConfiguration = new ConfigConfigurationAdapter(config, prefix);\n        CompositeConfiguration compositeConfiguration = new CompositeConfiguration();\n        compositeConfiguration.addConfiguration(systemConfiguration);\n        compositeConfiguration.addConfiguration(environmentConfiguration);\n        compositeConfiguration.addConfiguration(appExternalConfiguration);\n        compositeConfiguration.addConfiguration(externalConfiguration);\n        compositeConfiguration.addConfiguration(appConfiguration);\n        compositeConfiguration.addConfiguration(instanceConfiguration);\n        compositeConfiguration.addConfiguration(propertiesConfiguration);\n\n        return new PrefixedConfiguration(compositeConfiguration, prefix);\n    }\n\n    /**\n     * There are two ways to get configuration during exposure / reference or at runtime:\n     * 1. URL, The value in the URL is relatively fixed. we can get value directly.\n     * 2. The configuration exposed in this method is convenient for us to query the latest values from multiple\n     * prioritized sources, it also guarantees that configs changed dynamically can take effect on the fly.\n     */\n    public CompositeConfiguration getConfiguration() {\n        if (globalConfiguration == null) {\n            CompositeConfiguration configuration = new CompositeConfiguration();\n            configuration.addConfiguration(systemConfiguration);\n            configuration.addConfiguration(environmentConfiguration);\n            configuration.addConfiguration(appExternalConfiguration);\n            configuration.addConfiguration(externalConfiguration);\n            configuration.addConfiguration(appConfiguration);\n            configuration.addConfiguration(propertiesConfiguration);\n            globalConfiguration = configuration;\n        }\n        return globalConfiguration;\n    }\n\n    /**\n     * Get configuration map list for target instance\n     *\n     * @param config\n     * @param prefix\n     * @return\n     */\n    public List<Map<String, String>> getConfigurationMaps(AbstractConfig config, String prefix) {\n        // The sequence would be: SystemConfiguration -> EnvironmentConfiguration -> AppExternalConfiguration ->\n        // ExternalConfiguration  -> AppConfiguration -> AbstractConfig -> PropertiesConfiguration\n\n        List<Map<String, String>> maps = new ArrayList<>();\n        maps.add(systemConfiguration.getProperties());\n        maps.add(environmentConfiguration.getProperties());\n        maps.add(appExternalConfiguration.getProperties());\n        maps.add(externalConfiguration.getProperties());\n        maps.add(appConfiguration.getProperties());\n        if (config != null) {\n            ConfigConfigurationAdapter configurationAdapter = new ConfigConfigurationAdapter(config, prefix);\n            maps.add(configurationAdapter.getProperties());\n        }\n        maps.add(propertiesConfiguration.getProperties());\n        return maps;\n    }\n\n    /**\n     * Get global configuration as map list\n     *\n     * @return\n     */\n    public List<Map<String, String>> getConfigurationMaps() {\n        if (globalConfigurationMaps == null) {\n            globalConfigurationMaps = getConfigurationMaps(null, null);\n        }\n        return globalConfigurationMaps;\n    }\n\n    @Override\n    public void destroy() throws IllegalStateException {\n        initialized.set(false);\n        systemConfiguration = null;\n        propertiesConfiguration = null;\n        environmentConfiguration = null;\n        externalConfiguration = null;\n        appExternalConfiguration = null;\n        appConfiguration = null;\n        globalConfiguration = null;\n        globalConfigurationMaps = null;\n        defaultDynamicGlobalConfiguration = null;\n        if (defaultDynamicConfiguration != null) {\n            try {\n                defaultDynamicConfiguration.close();\n            } catch (Exception e) {\n                logger.warn(\n                        COMMON_UNEXPECTED_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"close dynamic configuration failed: \" + e.getMessage(),\n                        e);\n            }\n            defaultDynamicConfiguration = null;\n        }\n    }\n\n    /**\n     * Reset environment.\n     * For test only.\n     */\n    public void reset() {\n        destroy();\n        initialize();\n    }\n\n    public String resolvePlaceholders(String str) {\n        return ConfigUtils.replaceProperty(str, getConfiguration());\n    }\n\n    public PropertiesConfiguration getPropertiesConfiguration() {\n        return propertiesConfiguration;\n    }\n\n    public SystemConfiguration getSystemConfiguration() {\n        return systemConfiguration;\n    }\n\n    public EnvironmentConfiguration getEnvironmentConfiguration() {\n        return environmentConfiguration;\n    }\n\n    public InmemoryConfiguration getExternalConfiguration() {\n        return externalConfiguration;\n    }\n\n    public InmemoryConfiguration getAppExternalConfiguration() {\n        return appExternalConfiguration;\n    }\n\n    public InmemoryConfiguration getAppConfiguration() {\n        return appConfiguration;\n    }\n\n    public String getLocalMigrationRule() {\n        return localMigrationRule;\n    }\n\n    public synchronized void refreshClassLoaders() {\n        propertiesConfiguration.refresh();\n        loadMigrationRule();\n        this.globalConfiguration = null;\n        this.globalConfigurationMaps = null;\n        this.defaultDynamicGlobalConfiguration = null;\n    }\n\n    public Configuration getDynamicGlobalConfiguration() {\n        if (defaultDynamicGlobalConfiguration == null) {\n            if (defaultDynamicConfiguration == null) {\n                if (logger.isWarnEnabled()) {\n                    logger.warn(\n                            COMMON_UNEXPECTED_EXCEPTION,\n                            \"\",\n                            \"\",\n                            \"dynamicConfiguration is null , return globalConfiguration.\");\n                }\n                return getConfiguration();\n            }\n            defaultDynamicGlobalConfiguration = new CompositeConfiguration();\n            defaultDynamicGlobalConfiguration.addConfiguration(defaultDynamicConfiguration);\n            defaultDynamicGlobalConfiguration.addConfiguration(getConfiguration());\n        }\n        return defaultDynamicGlobalConfiguration;\n    }\n\n    public Optional<DynamicConfiguration> getDynamicConfiguration() {\n        return Optional.ofNullable(defaultDynamicConfiguration);\n    }\n\n    @DisableInject\n    public void setDynamicConfiguration(DynamicConfiguration defaultDynamicConfiguration) {\n        this.defaultDynamicConfiguration = defaultDynamicConfiguration;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/EnvironmentConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.LinkedHashSet;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Configuration from system environment\n */\npublic class EnvironmentConfiguration implements Configuration {\n\n    @Override\n    public Object getInternalProperty(String key) {\n        if (StringUtils.isEmpty(key)) {\n            return null;\n        }\n        String value = getenv().get(key);\n        if (value != null) {\n            return value;\n        }\n        for (String candidateKey : generateCandidateEnvironmentKeys(key)) {\n            value = getenv().get(candidateKey);\n            if (value != null) {\n                return value;\n            }\n        }\n\n        String osStyleKey = StringUtils.toOSStyleKey(key);\n        value = getenv().get(osStyleKey);\n        return value;\n    }\n\n    private Set<String> generateCandidateEnvironmentKeys(String originalKey) {\n        Set<String> candidates = new LinkedHashSet<>();\n\n        String dotsToUnderscores =\n                originalKey.replace(CommonConstants.DOT_SEPARATOR, CommonConstants.UNDERLINE_SEPARATOR);\n        String normalizedKey = dotsToUnderscores.replace(\n                CommonConstants.PROPERTIES_CHAR_SEPARATOR, CommonConstants.UNDERLINE_SEPARATOR);\n\n        candidates.add(normalizedKey.toUpperCase(Locale.ROOT));\n\n        String springLikeNoHyphens = dotsToUnderscores\n                .replace(CommonConstants.PROPERTIES_CHAR_SEPARATOR, \"\")\n                .toUpperCase(Locale.ROOT);\n        candidates.add(springLikeNoHyphens);\n\n        String dotsToUnderscoresUpper = dotsToUnderscores.toUpperCase(Locale.ROOT);\n        candidates.add(dotsToUnderscoresUpper);\n\n        candidates.add(normalizedKey);\n\n        return candidates;\n    }\n\n    public Map<String, String> getProperties() {\n        return getenv();\n    }\n\n    protected Map<String, String> getenv() {\n        return System.getenv();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/InmemoryConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * In-memory configuration\n */\npublic class InmemoryConfiguration implements Configuration {\n\n    private String name;\n\n    // stores the configuration key-value pairs\n    private Map<String, String> store = new LinkedHashMap<>();\n\n    public InmemoryConfiguration() {}\n\n    public InmemoryConfiguration(String name) {\n        this.name = name;\n    }\n\n    public InmemoryConfiguration(Map<String, String> properties) {\n        this.setProperties(properties);\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        return store.get(key);\n    }\n\n    /**\n     * Add one property into the store, the previous value will be replaced if the key exists\n     */\n    public void addProperty(String key, String value) {\n        store.put(key, value);\n    }\n\n    /**\n     * Add a set of properties into the store\n     */\n    public void addProperties(Map<String, String> properties) {\n        if (properties != null) {\n            this.store.putAll(properties);\n        }\n    }\n\n    /**\n     * set store\n     */\n    public void setProperties(Map<String, String> properties) {\n        if (properties != null) {\n            this.store = properties;\n        }\n    }\n\n    public Map<String, String> getProperties() {\n        return store;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/ModuleEnvironment.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.context.ModuleExt;\nimport org.apache.dubbo.common.extension.DisableInject;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class ModuleEnvironment extends Environment implements ModuleExt {\n\n    // delegate\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ModuleEnvironment.class);\n\n    public static final String NAME = \"moduleEnvironment\";\n\n    private final AtomicBoolean initialized = new AtomicBoolean(false);\n\n    private final ModuleModel moduleModel;\n\n    private final Environment applicationDelegate;\n\n    private OrderedPropertiesConfiguration orderedPropertiesConfiguration;\n\n    private CompositeConfiguration dynamicGlobalConfiguration;\n\n    private DynamicConfiguration dynamicConfiguration;\n\n    public ModuleEnvironment(ModuleModel moduleModel) {\n        super(moduleModel);\n        this.moduleModel = moduleModel;\n        this.applicationDelegate = moduleModel.getApplicationModel().modelEnvironment();\n    }\n\n    @Override\n    public void initialize() throws IllegalStateException {\n        if (initialized.compareAndSet(false, true)) {\n            this.orderedPropertiesConfiguration = new OrderedPropertiesConfiguration(moduleModel);\n        }\n    }\n\n    @Override\n    public Configuration getPrefixedConfiguration(AbstractConfig config, String prefix) {\n        CompositeConfiguration compositeConfiguration = new CompositeConfiguration();\n        compositeConfiguration.addConfiguration(applicationDelegate.getPrefixedConfiguration(config, prefix));\n        compositeConfiguration.addConfiguration(orderedPropertiesConfiguration);\n\n        return new PrefixedConfiguration(compositeConfiguration, prefix);\n    }\n\n    @Override\n    public CompositeConfiguration getConfiguration() {\n        if (globalConfiguration == null) {\n            CompositeConfiguration configuration = new CompositeConfiguration();\n            configuration.addConfiguration(applicationDelegate.getConfiguration());\n            configuration.addConfiguration(orderedPropertiesConfiguration);\n            globalConfiguration = configuration;\n        }\n        return globalConfiguration;\n    }\n\n    @Override\n    public List<Map<String, String>> getConfigurationMaps(AbstractConfig config, String prefix) {\n        List<Map<String, String>> maps = applicationDelegate.getConfigurationMaps(config, prefix);\n        maps.add(orderedPropertiesConfiguration.getProperties());\n        return maps;\n    }\n\n    @Override\n    public Configuration getDynamicGlobalConfiguration() {\n        if (dynamicConfiguration == null) {\n            CompositeConfiguration configuration = new CompositeConfiguration();\n            configuration.addConfiguration(applicationDelegate.getDynamicGlobalConfiguration());\n            configuration.addConfiguration(orderedPropertiesConfiguration);\n            return configuration;\n        }\n\n        if (dynamicGlobalConfiguration == null) {\n            dynamicGlobalConfiguration = new CompositeConfiguration();\n            dynamicGlobalConfiguration.addConfiguration(dynamicConfiguration);\n            dynamicGlobalConfiguration.addConfiguration(getConfiguration());\n        }\n        return dynamicGlobalConfiguration;\n    }\n\n    @Override\n    public Optional<DynamicConfiguration> getDynamicConfiguration() {\n        if (dynamicConfiguration == null) {\n            return applicationDelegate.getDynamicConfiguration();\n        }\n        return Optional.ofNullable(dynamicConfiguration);\n    }\n\n    @Override\n    @DisableInject\n    public void setDynamicConfiguration(DynamicConfiguration dynamicConfiguration) {\n        this.dynamicConfiguration = dynamicConfiguration;\n    }\n\n    @Override\n    public void destroy() throws IllegalStateException {\n        super.destroy();\n        this.orderedPropertiesConfiguration = null;\n    }\n\n    @Override\n    @DisableInject\n    public void setLocalMigrationRule(String localMigrationRule) {\n        applicationDelegate.setLocalMigrationRule(localMigrationRule);\n    }\n\n    @Override\n    @DisableInject\n    public void setExternalConfigMap(Map<String, String> externalConfiguration) {\n        applicationDelegate.setExternalConfigMap(externalConfiguration);\n    }\n\n    @Override\n    @DisableInject\n    public void setAppExternalConfigMap(Map<String, String> appExternalConfiguration) {\n        applicationDelegate.setAppExternalConfigMap(appExternalConfiguration);\n    }\n\n    @Override\n    @DisableInject\n    public void setAppConfigMap(Map<String, String> appConfiguration) {\n        applicationDelegate.setAppConfigMap(appConfiguration);\n    }\n\n    @Override\n    public Map<String, String> getExternalConfigMap() {\n        return applicationDelegate.getExternalConfigMap();\n    }\n\n    @Override\n    public Map<String, String> getAppExternalConfigMap() {\n        return applicationDelegate.getAppExternalConfigMap();\n    }\n\n    @Override\n    public Map<String, String> getAppConfigMap() {\n        return applicationDelegate.getAppConfigMap();\n    }\n\n    @Override\n    public void updateExternalConfigMap(Map<String, String> externalMap) {\n        applicationDelegate.updateExternalConfigMap(externalMap);\n    }\n\n    @Override\n    public void updateAppExternalConfigMap(Map<String, String> externalMap) {\n        applicationDelegate.updateAppExternalConfigMap(externalMap);\n    }\n\n    @Override\n    public void updateAppConfigMap(Map<String, String> map) {\n        applicationDelegate.updateAppConfigMap(map);\n    }\n\n    @Override\n    public PropertiesConfiguration getPropertiesConfiguration() {\n        return applicationDelegate.getPropertiesConfiguration();\n    }\n\n    @Override\n    public SystemConfiguration getSystemConfiguration() {\n        return applicationDelegate.getSystemConfiguration();\n    }\n\n    @Override\n    public EnvironmentConfiguration getEnvironmentConfiguration() {\n        return applicationDelegate.getEnvironmentConfiguration();\n    }\n\n    @Override\n    public InmemoryConfiguration getExternalConfiguration() {\n        return applicationDelegate.getExternalConfiguration();\n    }\n\n    @Override\n    public InmemoryConfiguration getAppExternalConfiguration() {\n        return applicationDelegate.getAppExternalConfiguration();\n    }\n\n    @Override\n    public InmemoryConfiguration getAppConfiguration() {\n        return applicationDelegate.getAppConfiguration();\n    }\n\n    @Override\n    public String getLocalMigrationRule() {\n        return applicationDelegate.getLocalMigrationRule();\n    }\n\n    @Override\n    public synchronized void refreshClassLoaders() {\n        orderedPropertiesConfiguration.refresh();\n        applicationDelegate.refreshClassLoaders();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/OrderedPropertiesConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\n\npublic class OrderedPropertiesConfiguration implements Configuration {\n    private Properties properties;\n    private final ModuleModel moduleModel;\n\n    public OrderedPropertiesConfiguration(ModuleModel moduleModel) {\n        this.moduleModel = moduleModel;\n        refresh();\n    }\n\n    public void refresh() {\n        properties = new Properties();\n        ExtensionLoader<OrderedPropertiesProvider> propertiesProviderExtensionLoader =\n                moduleModel.getExtensionLoader(OrderedPropertiesProvider.class);\n        Set<String> propertiesProviderNames = propertiesProviderExtensionLoader.getSupportedExtensions();\n        if (CollectionUtils.isEmpty(propertiesProviderNames)) {\n            return;\n        }\n        List<OrderedPropertiesProvider> orderedPropertiesProviders = new ArrayList<>();\n        for (String propertiesProviderName : propertiesProviderNames) {\n            orderedPropertiesProviders.add(propertiesProviderExtensionLoader.getExtension(propertiesProviderName));\n        }\n\n        // order the propertiesProvider according the priority descending\n        orderedPropertiesProviders.sort((a, b) -> b.priority() - a.priority());\n\n        // override the properties.\n        for (OrderedPropertiesProvider orderedPropertiesProvider : orderedPropertiesProviders) {\n            properties.putAll(orderedPropertiesProvider.initProperties());\n        }\n    }\n\n    @Override\n    public String getProperty(String key) {\n        return properties.getProperty(key);\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        return properties.getProperty(key);\n    }\n\n    public void setProperty(String key, String value) {\n        properties.setProperty(key, value);\n    }\n\n    public String remove(String key) {\n        return (String) properties.remove(key);\n    }\n\n    /**\n     * For ut only\n     */\n    @Deprecated\n    public void setProperties(Properties properties) {\n        this.properties = properties;\n    }\n\n    public Map<String, String> getProperties() {\n        return (Map) properties;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/OrderedPropertiesProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.Properties;\n\n/**\n *\n * The smaller value, the higher priority\n *\n */\n@SPI(scope = ExtensionScope.MODULE)\npublic interface OrderedPropertiesProvider {\n    /**\n     * order\n     *\n     * @return\n     */\n    int priority();\n\n    /**\n     * load the properties\n     *\n     * @return\n     */\n    Properties initProperties();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/PrefixedConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\npublic class PrefixedConfiguration implements Configuration {\n\n    private final String prefix;\n\n    private final Configuration origin;\n\n    public PrefixedConfiguration(Configuration origin, String prefix) {\n        this.origin = origin;\n        this.prefix = prefix;\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        if (StringUtils.isBlank(prefix)) {\n            return origin.getInternalProperty(key);\n        }\n\n        Object value = origin.getInternalProperty(prefix + \".\" + key);\n        if (!ConfigurationUtils.isEmptyValue(value)) {\n            return value;\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/PropertiesConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.Map;\nimport java.util.Properties;\n\n/**\n * Configuration from system properties and dubbo.properties\n */\npublic class PropertiesConfiguration implements Configuration {\n\n    private Properties properties;\n    private final ScopeModel scopeModel;\n\n    public PropertiesConfiguration(ScopeModel scopeModel) {\n        this.scopeModel = scopeModel;\n        refresh();\n    }\n\n    public void refresh() {\n        properties = ConfigUtils.getProperties(scopeModel.getClassLoaders());\n    }\n\n    @Override\n    public String getProperty(String key) {\n        return properties.getProperty(key);\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        return properties.getProperty(key);\n    }\n\n    public void setProperty(String key, String value) {\n        properties.setProperty(key, value);\n    }\n\n    public String remove(String key) {\n        return (String) properties.remove(key);\n    }\n\n    @Deprecated\n    public void setProperties(Properties properties) {\n        this.properties = properties;\n    }\n\n    public Map<String, String> getProperties() {\n        return (Map) properties;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/ReferenceCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.config.ReferenceConfigBase;\n\nimport java.util.List;\n\npublic interface ReferenceCache {\n    @SuppressWarnings(\"unchecked\")\n    default <T> T get(ReferenceConfigBase<T> referenceConfig) {\n        return get(referenceConfig, true);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    <T> T get(ReferenceConfigBase<T> referenceConfig, boolean check);\n\n    @SuppressWarnings(\"unchecked\")\n    <T> T get(String key, Class<T> type);\n\n    @SuppressWarnings(\"unchecked\")\n    <T> T get(String key);\n\n    @SuppressWarnings(\"unchecked\")\n    <T> List<T> getAll(Class<T> type);\n\n    @SuppressWarnings(\"unchecked\")\n    <T> T get(Class<T> type);\n\n    @SuppressWarnings(\"unchecked\")\n    <T> void check(ReferenceConfigBase<T> referenceConfig, long timeout);\n\n    void check(String key, Class<?> type, long timeout);\n\n    void destroy(String key, Class<?> type);\n\n    void destroy(Class<?> type);\n\n    <T> void destroy(ReferenceConfigBase<T> referenceConfig);\n\n    void destroyAll();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/SystemConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport java.util.Map;\n\n/**\n * Configuration from system properties\n */\npublic class SystemConfiguration implements Configuration {\n\n    @Override\n    public Object getInternalProperty(String key) {\n        return System.getProperty(key);\n    }\n\n    public Map<String, String> getProperties() {\n        return (Map) System.getProperties();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\n/**\n * The abstract implementation of {@link DynamicConfiguration}\n *\n * @since 2.7.5\n */\npublic abstract class AbstractDynamicConfiguration implements DynamicConfiguration {\n\n    public static final String PARAM_NAME_PREFIX = \"dubbo.config-center.\";\n\n    public static final String THREAD_POOL_PREFIX_PARAM_NAME = PARAM_NAME_PREFIX + \"thread-pool.prefix\";\n\n    public static final String DEFAULT_THREAD_POOL_PREFIX = PARAM_NAME_PREFIX + \"workers\";\n\n    public static final String THREAD_POOL_SIZE_PARAM_NAME = PARAM_NAME_PREFIX + \"thread-pool.size\";\n\n    /**\n     * The keep alive time in milliseconds for threads in {@link ThreadPoolExecutor}\n     */\n    public static final String THREAD_POOL_KEEP_ALIVE_TIME_PARAM_NAME =\n            PARAM_NAME_PREFIX + \"thread-pool.keep-alive-time\";\n\n    /**\n     * The parameter name of group for config-center\n     *\n     * @since 2.7.8\n     */\n    public static final String GROUP_PARAM_NAME = PARAM_NAME_PREFIX + GROUP_KEY;\n\n    /**\n     * The parameter name of timeout for config-center\n     *\n     * @since 2.7.8\n     */\n    public static final String TIMEOUT_PARAM_NAME = PARAM_NAME_PREFIX + TIMEOUT_KEY;\n\n    public static final int DEFAULT_THREAD_POOL_SIZE = 1;\n\n    /**\n     * Default keep alive time in milliseconds for threads in {@link ThreadPoolExecutor} is 1 minute( 60 * 1000 ms)\n     */\n    public static final long DEFAULT_THREAD_POOL_KEEP_ALIVE_TIME = TimeUnit.MINUTES.toMillis(1);\n\n    /**\n     * Logger\n     */\n    protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    /**\n     * The thread pool for workers who execute the tasks\n     */\n    private final ThreadPoolExecutor workersThreadPool;\n\n    private final String group;\n\n    private final long timeout;\n\n    protected AbstractDynamicConfiguration(URL url) {\n        this(\n                getThreadPoolPrefixName(url),\n                getThreadPoolSize(url),\n                getThreadPoolKeepAliveTime(url),\n                getGroup(url),\n                getTimeout(url));\n    }\n\n    protected AbstractDynamicConfiguration(\n            String threadPoolPrefixName, int threadPoolSize, long keepAliveTime, String group, long timeout) {\n        this.workersThreadPool = initWorkersThreadPool(threadPoolPrefixName, threadPoolSize, keepAliveTime);\n        this.group = group;\n        this.timeout = timeout;\n    }\n\n    @Override\n    public void addListener(String key, String group, ConfigurationListener listener) {}\n\n    @Override\n    public void removeListener(String key, String group, ConfigurationListener listener) {}\n\n    @Override\n    public final String getConfig(String key, String group, long timeout) throws IllegalStateException {\n        return execute(() -> doGetConfig(key, group), timeout);\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        return null;\n    }\n\n    @Override\n    public final void close() throws Exception {\n        try {\n            doClose();\n        } finally {\n            doFinally();\n        }\n    }\n\n    @Override\n    public boolean removeConfig(String key, String group) {\n        return Boolean.TRUE.equals(execute(() -> doRemoveConfig(key, group), -1L));\n    }\n\n    /**\n     * @return the default group\n     * @since 2.7.8\n     */\n    @Override\n    public String getDefaultGroup() {\n        return getGroup();\n    }\n\n    /**\n     * @return the default timeout\n     * @since 2.7.8\n     */\n    @Override\n    public long getDefaultTimeout() {\n        return getTimeout();\n    }\n\n    /**\n     * Get the content of configuration in the specified key and group\n     *\n     * @param key   the key\n     * @param group the group\n     * @return if found, return the content of configuration\n     * @throws Exception If met with some problems\n     */\n    protected abstract String doGetConfig(String key, String group) throws Exception;\n\n    /**\n     * Close the resources if necessary\n     *\n     * @throws Exception If met with some problems\n     */\n    protected abstract void doClose() throws Exception;\n\n    /**\n     * Remove the config in the specified key and group\n     *\n     * @param key   the key\n     * @param group the group\n     * @return If successful, return <code>true</code>, or <code>false</code>\n     * @throws Exception\n     * @since 2.7.8\n     */\n    protected abstract boolean doRemoveConfig(String key, String group) throws Exception;\n\n    /**\n     * Executes the {@link Runnable} with the specified timeout\n     *\n     * @param task    the {@link Runnable task}\n     * @param timeout timeout in milliseconds\n     */\n    protected final void execute(Runnable task, long timeout) {\n        execute(\n                () -> {\n                    task.run();\n                    return null;\n                },\n                timeout);\n    }\n\n    /**\n     * Executes the {@link Callable} with the specified timeout\n     *\n     * @param task    the {@link Callable task}\n     * @param timeout timeout in milliseconds\n     * @param <V>     the type of computing result\n     * @return the computing result\n     */\n    protected final <V> V execute(Callable<V> task, long timeout) {\n        V value = null;\n        try {\n\n            if (timeout < 1) { // less or equal 0\n                value = task.call();\n            } else {\n                Future<V> future = workersThreadPool.submit(task);\n                value = future.get(timeout, TimeUnit.MILLISECONDS);\n            }\n        } catch (Exception e) {\n            if (logger.isErrorEnabled()) {\n                logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", e.getMessage(), e);\n            }\n        }\n        return value;\n    }\n\n    protected ThreadPoolExecutor getWorkersThreadPool() {\n        return workersThreadPool;\n    }\n\n    private void doFinally() {\n        shutdownWorkersThreadPool();\n    }\n\n    private void shutdownWorkersThreadPool() {\n        if (!workersThreadPool.isShutdown()) {\n            workersThreadPool.shutdown();\n        }\n    }\n\n    protected ThreadPoolExecutor initWorkersThreadPool(\n            String threadPoolPrefixName, int threadPoolSize, long keepAliveTime) {\n        return new ThreadPoolExecutor(\n                threadPoolSize,\n                threadPoolSize,\n                keepAliveTime,\n                TimeUnit.MILLISECONDS,\n                new LinkedBlockingQueue<>(),\n                new NamedThreadFactory(threadPoolPrefixName, true));\n    }\n\n    protected static String getThreadPoolPrefixName(URL url) {\n        return getParameter(url, THREAD_POOL_PREFIX_PARAM_NAME, DEFAULT_THREAD_POOL_PREFIX);\n    }\n\n    protected static int getThreadPoolSize(URL url) {\n        return getParameter(url, THREAD_POOL_SIZE_PARAM_NAME, DEFAULT_THREAD_POOL_SIZE);\n    }\n\n    protected static long getThreadPoolKeepAliveTime(URL url) {\n        return getParameter(url, THREAD_POOL_KEEP_ALIVE_TIME_PARAM_NAME, DEFAULT_THREAD_POOL_KEEP_ALIVE_TIME);\n    }\n\n    protected static String getParameter(URL url, String name, String defaultValue) {\n        if (url != null) {\n            return url.getParameter(name, defaultValue);\n        }\n        return defaultValue;\n    }\n\n    protected static int getParameter(URL url, String name, int defaultValue) {\n        if (url != null) {\n            return url.getParameter(name, defaultValue);\n        }\n        return defaultValue;\n    }\n\n    protected static long getParameter(URL url, String name, long defaultValue) {\n        if (url != null) {\n            return url.getParameter(name, defaultValue);\n        }\n        return defaultValue;\n    }\n\n    protected String getGroup() {\n        return group;\n    }\n\n    protected long getTimeout() {\n        return timeout;\n    }\n\n    /**\n     * Get the group from {@link URL the specified connection URL}\n     *\n     * @param url {@link URL the specified connection URL}\n     * @return non-null\n     * @since 2.7.8\n     */\n    protected static String getGroup(URL url) {\n        String group = getParameter(url, GROUP_PARAM_NAME, null);\n        return StringUtils.isBlank(group) ? getParameter(url, GROUP_KEY, DEFAULT_GROUP) : group;\n    }\n\n    /**\n     * Get the timeout from {@link URL the specified connection URL}\n     *\n     * @param url {@link URL the specified connection URL}\n     * @return non-null\n     * @since 2.7.8\n     */\n    protected static long getTimeout(URL url) {\n        return getParameter(url, TIMEOUT_PARAM_NAME, -1L);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;\n\n/**\n * Abstract {@link DynamicConfigurationFactory} implementation with cache ability\n *\n * @see DynamicConfigurationFactory\n * @since 2.7.5\n */\npublic abstract class AbstractDynamicConfigurationFactory implements DynamicConfigurationFactory {\n\n    private volatile ConcurrentHashMap<String, DynamicConfiguration> dynamicConfigurations = new ConcurrentHashMap<>();\n\n    @Override\n    public final DynamicConfiguration getDynamicConfiguration(URL url) {\n        String key = url == null ? DEFAULT_KEY : url.toServiceString();\n        return ConcurrentHashMapUtils.computeIfAbsent(dynamicConfigurations, key, k -> createDynamicConfiguration(url));\n    }\n\n    protected abstract DynamicConfiguration createDynamicConfiguration(URL url);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangeType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\n/**\n * Config change event type\n */\npublic enum ConfigChangeType {\n    /**\n     * A config is created.\n     */\n    ADDED,\n\n    /**\n     * A config is updated.\n     */\n    MODIFIED,\n\n    /**\n     * A config is deleted.\n     */\n    DELETED\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangedEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport java.util.EventObject;\nimport java.util.Objects;\n\n/**\n * An event raised when the config changed, immutable.\n *\n * @see ConfigChangeType\n */\npublic class ConfigChangedEvent extends EventObject {\n\n    private final String key;\n\n    private final String group;\n\n    private final String content;\n\n    private final ConfigChangeType changeType;\n\n    public ConfigChangedEvent(String key, String group, String content) {\n        this(key, group, content, ConfigChangeType.MODIFIED);\n    }\n\n    public ConfigChangedEvent(String key, String group, String content, ConfigChangeType changeType) {\n        super(key + \",\" + group);\n        this.key = key;\n        this.group = group;\n        this.content = content;\n        this.changeType = changeType;\n    }\n\n    public String getKey() {\n        return key;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public ConfigChangeType getChangeType() {\n        return changeType;\n    }\n\n    @Override\n    public String toString() {\n        return \"ConfigChangedEvent{\" + \"key='\"\n                + key + '\\'' + \", group='\"\n                + group + '\\'' + \", content='\"\n                + content + '\\'' + \", changeType=\"\n                + changeType + \"} \"\n                + super.toString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (!(o instanceof ConfigChangedEvent)) {\n            return false;\n        }\n        ConfigChangedEvent that = (ConfigChangedEvent) o;\n        return Objects.equals(getKey(), that.getKey())\n                && Objects.equals(getGroup(), that.getGroup())\n                && Objects.equals(getContent(), that.getContent())\n                && getChangeType() == that.getChangeType();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(getKey(), getGroup(), getContent(), getChangeType());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigItem.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\n/**\n * Hold content and version information\n */\npublic class ConfigItem {\n\n    /**\n     * configure item content.\n     */\n    private String content;\n    /**\n     * version information corresponding to the current configure item.\n     */\n    private Object ticket;\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public Object getTicket() {\n        return ticket;\n    }\n\n    public void setTicket(Object ticket) {\n        this.ticket = ticket;\n    }\n\n    public ConfigItem(String content, Object ticket) {\n        this.content = content;\n        this.ticket = ticket;\n    }\n\n    public ConfigItem() {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigurationListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport java.util.EventListener;\n\n/**\n * Config listener, will get notified when the config it listens on changes.\n */\npublic interface ConfigurationListener extends EventListener {\n\n    /**\n     * Listener call back method. Listener gets notified by this method once there's any change happens on the config\n     * the listener listens on.\n     *\n     * @param event config change event\n     */\n    void process(ConfigChangedEvent event);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\n/**\n * @deprecated Replaced to {@link org.apache.dubbo.common.constants.CommonConstants}\n */\n@Deprecated\npublic interface Constants {\n    String CONFIG_CLUSTER_KEY = \"config.cluster\";\n    String CONFIG_NAMESPACE_KEY = \"config.namespace\";\n    String CONFIG_GROUP_KEY = \"config.group\";\n    String CONFIG_CHECK_KEY = \"config.check\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.Configuration;\n\n/**\n * Dynamic Configuration\n * <br/>\n * From the use scenario internally inside framework, there are mainly three kinds of methods:\n * <ol>\n * <li>{@link #getProperties(String, String, long)}, get configuration file from Config Center at start up.</li>\n * <li>{@link #addListener(String, String, ConfigurationListener)}/ {@link #removeListener(String, String, ConfigurationListener)}\n * , add or remove listeners for governance rules or config items that need to watch.</li>\n * <li>{@link #getProperty(String, Object)}, get a single config item.</li>\n * <li>{@link #getConfig(String, String, long)}, get the specified config</li>\n * </ol>\n *\n * @see AbstractDynamicConfiguration\n */\npublic interface DynamicConfiguration extends Configuration, AutoCloseable {\n\n    String DEFAULT_GROUP = \"dubbo\";\n\n    /**\n     * {@link #addListener(String, String, ConfigurationListener)}\n     *\n     * @param key      the key to represent a configuration\n     * @param listener configuration listener\n     */\n    default void addListener(String key, ConfigurationListener listener) {\n        addListener(key, getDefaultGroup(), listener);\n    }\n\n    /**\n     * {@link #removeListener(String, String, ConfigurationListener)}\n     *\n     * @param key      the key to represent a configuration\n     * @param listener configuration listener\n     */\n    default void removeListener(String key, ConfigurationListener listener) {\n        removeListener(key, getDefaultGroup(), listener);\n    }\n\n    /**\n     * Register a configuration listener for a specified key\n     * The listener only works for service governance purpose, so the target group would always be the value user\n     * specifies at startup or 'dubbo' by default. This method will only register listener, which means it will not\n     * trigger a notification that contains the current value.\n     *\n     * @param key      the key to represent a configuration\n     * @param group    the group where the key belongs to\n     * @param listener configuration listener\n     */\n    void addListener(String key, String group, ConfigurationListener listener);\n\n    /**\n     * Stops one listener from listening to value changes in the specified key.\n     *\n     * @param key      the key to represent a configuration\n     * @param group    the group where the key belongs to\n     * @param listener configuration listener\n     */\n    void removeListener(String key, String group, ConfigurationListener listener);\n\n    /**\n     * Get the configuration mapped to the given key and the given group with {@link #getDefaultTimeout() the default\n     * timeout}\n     *\n     * @param key   the key to represent a configuration\n     * @param group the group where the key belongs to\n     * @return target configuration mapped to the given key and the given group\n     */\n    default String getConfig(String key, String group) {\n        return getConfig(key, group, getDefaultTimeout());\n    }\n\n    /**\n     * get configItem which contains content and stat info.\n     *\n     * @param key\n     * @param group\n     * @return\n     */\n    default ConfigItem getConfigItem(String key, String group) {\n        String content = getConfig(key, group);\n        return new ConfigItem(content, null);\n    }\n\n    /**\n     * Get the configuration mapped to the given key and the given group. If the\n     * configuration fails to fetch after timeout exceeds, IllegalStateException will be thrown.\n     *\n     * @param key     the key to represent a configuration\n     * @param group   the group where the key belongs to\n     * @param timeout timeout value for fetching the target config\n     * @return target configuration mapped to the given key and the given group, IllegalStateException will be thrown\n     * if timeout exceeds.\n     */\n    String getConfig(String key, String group, long timeout) throws IllegalStateException;\n\n    /**\n     * This method are mostly used to get a compound config file with {@link #getDefaultTimeout() the default timeout},\n     * such as a complete dubbo.properties file.\n     */\n    default String getProperties(String key, String group) throws IllegalStateException {\n        return getProperties(key, group, getDefaultTimeout());\n    }\n\n    /**\n     * This method are mostly used to get a compound config file, such as a complete dubbo.properties file.\n     *\n     * @revision 2.7.4\n     */\n    default String getProperties(String key, String group, long timeout) throws IllegalStateException {\n        return getConfig(key, group, timeout);\n    }\n\n    /**\n     * Publish Config mapped to the given key under the {@link #getDefaultGroup() default group}\n     *\n     * @param key     the key to represent a configuration\n     * @param content the content of configuration\n     * @return <code>true</code> if success, or <code>false</code>\n     * @throws UnsupportedOperationException If the under layer does not support\n     * @since 2.7.5\n     */\n    default boolean publishConfig(String key, String content) throws UnsupportedOperationException {\n        return publishConfig(key, getDefaultGroup(), content);\n    }\n\n    /**\n     * Publish Config mapped to the given key and the given group.\n     *\n     * @param key     the key to represent a configuration\n     * @param group   the group where the key belongs to\n     * @param content the content of configuration\n     * @return <code>true</code> if success, or <code>false</code>\n     * @throws UnsupportedOperationException If the under layer does not support\n     * @since 2.7.5\n     */\n    default boolean publishConfig(String key, String group, String content) throws UnsupportedOperationException {\n        return false;\n    }\n\n    /**\n     * publish config mapped to this given key and given group with stat.\n     *\n     * @param key\n     * @param group\n     * @param content\n     * @param ticket\n     * @return\n     * @throws UnsupportedOperationException\n     */\n    default boolean publishConfigCas(String key, String group, String content, Object ticket)\n            throws UnsupportedOperationException {\n        return false;\n    }\n\n    /**\n     * Get the default group for the operations\n     *\n     * @return The default value is {@link #DEFAULT_GROUP \"dubbo\"}\n     * @since 2.7.5\n     */\n    default String getDefaultGroup() {\n        return DEFAULT_GROUP;\n    }\n\n    /**\n     * Get the default timeout for the operations in milliseconds\n     *\n     * @return The default value is <code>-1L</code>\n     * @since 2.7.5\n     */\n    default long getDefaultTimeout() {\n        return -1L;\n    }\n\n    /**\n     * Close the configuration\n     *\n     * @throws Exception\n     * @since 2.7.5\n     */\n    @Override\n    default void close() throws Exception {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * The format is '{interfaceName}:[version]:[group]'\n     *\n     * @return\n     */\n    static String getRuleKey(URL url) {\n        return url.getColonSeparatedKey();\n    }\n\n    /**\n     * @param key   the key to represent a configuration\n     * @param group the group where the key belongs to\n     * @return <code>true</code> if success, or <code>false</code>\n     * @since 2.7.8\n     */\n    default boolean removeConfig(String key, String group) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * The factory interface to create the instance of {@link DynamicConfiguration}\n */\n@SPI(value = \"nop\", scope = ExtensionScope.APPLICATION) // 2.7.5 change the default SPI implementation\npublic interface DynamicConfigurationFactory {\n\n    DynamicConfiguration getDynamicConfiguration(URL url);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/TreePathDynamicConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Collection;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONFIG_NAMESPACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;\nimport static org.apache.dubbo.common.utils.PathUtils.buildPath;\nimport static org.apache.dubbo.common.utils.PathUtils.normalize;\n\n/**\n * An abstract implementation of {@link DynamicConfiguration} is like \"tree-structure\" path :\n * <ul>\n *     <li>{@link org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration \"file\"}</li>\n *     <li>{@link org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfiguration \"zookeeper\"}</li>\n * </ul>\n *\n * @see DynamicConfiguration\n * @see AbstractDynamicConfiguration\n * @since 2.7.8\n */\npublic abstract class TreePathDynamicConfiguration extends AbstractDynamicConfiguration {\n\n    /**\n     * The parameter name of URL for the config root path\n     */\n    public static final String CONFIG_ROOT_PATH_PARAM_NAME = PARAM_NAME_PREFIX + \"root-path\";\n\n    /**\n     * The parameter name of URL for the config base path\n     */\n    public static final String CONFIG_BASE_PATH_PARAM_NAME = PARAM_NAME_PREFIX + \"base-path\";\n\n    /**\n     * The default value of parameter of URL for the config base path\n     */\n    public static final String DEFAULT_CONFIG_BASE_PATH = \"/config\";\n\n    protected final String rootPath;\n\n    public TreePathDynamicConfiguration(URL url) {\n        super(url);\n        this.rootPath = getRootPath(url);\n    }\n\n    public TreePathDynamicConfiguration(\n            String rootPath,\n            String threadPoolPrefixName,\n            int threadPoolSize,\n            long keepAliveTime,\n            String group,\n            long timeout) {\n        super(threadPoolPrefixName, threadPoolSize, keepAliveTime, group, timeout);\n        this.rootPath = rootPath;\n    }\n\n    @Override\n    protected final String doGetConfig(String key, String group) throws Exception {\n        String pathKey = buildPathKey(group, key);\n        return doGetConfig(pathKey);\n    }\n\n    @Override\n    public final boolean publishConfig(String key, String group, String content) {\n        String pathKey = buildPathKey(group, key);\n        return Boolean.TRUE.equals(execute(() -> doPublishConfig(pathKey, content), getDefaultTimeout()));\n    }\n\n    @Override\n    protected final boolean doRemoveConfig(String key, String group) throws Exception {\n        String pathKey = buildPathKey(group, key);\n        return doRemoveConfig(pathKey);\n    }\n\n    @Override\n    public final void addListener(String key, String group, ConfigurationListener listener) {\n        String pathKey = buildPathKey(group, key);\n        doAddListener(pathKey, listener, key, group);\n    }\n\n    @Override\n    public final void removeListener(String key, String group, ConfigurationListener listener) {\n        String pathKey = buildPathKey(group, key);\n        doRemoveListener(pathKey, listener);\n    }\n\n    protected abstract boolean doPublishConfig(String pathKey, String content) throws Exception;\n\n    protected abstract String doGetConfig(String pathKey) throws Exception;\n\n    protected abstract boolean doRemoveConfig(String pathKey) throws Exception;\n\n    protected abstract Collection<String> doGetConfigKeys(String groupPath);\n\n    protected abstract void doAddListener(String pathKey, ConfigurationListener listener, String key, String group);\n\n    protected abstract void doRemoveListener(String pathKey, ConfigurationListener listener);\n\n    protected String buildGroupPath(String group) {\n        return buildPath(rootPath, group);\n    }\n\n    protected String buildPathKey(String group, String key) {\n        return buildPath(buildGroupPath(group), key);\n    }\n\n    /**\n     * Get the root path from the specified {@link URL connection URl}\n     *\n     * @param url the specified {@link URL connection URl}\n     * @return non-null\n     */\n    protected String getRootPath(URL url) {\n\n        String rootPath = url.getParameter(CONFIG_ROOT_PATH_PARAM_NAME, buildRootPath(url));\n\n        rootPath = normalize(rootPath);\n\n        int rootPathLength = rootPath.length();\n\n        if (rootPathLength > 1 && rootPath.endsWith(PATH_SEPARATOR)) {\n            rootPath = rootPath.substring(0, rootPathLength - 1);\n        }\n\n        return rootPath;\n    }\n\n    private String buildRootPath(URL url) {\n        return PATH_SEPARATOR + getConfigNamespace(url) + getConfigBasePath(url);\n    }\n\n    /**\n     * Get the namespace from the specified {@link URL connection URl}\n     *\n     * @param url the specified {@link URL connection URl}\n     * @return non-null\n     */\n    protected String getConfigNamespace(URL url) {\n        return url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP);\n    }\n\n    /**\n     * Get the config base path from the specified {@link URL connection URl}\n     *\n     * @param url the specified {@link URL connection URl}\n     * @return non-null\n     */\n    protected String getConfigBasePath(URL url) {\n        String configBasePath = url.getParameter(CONFIG_BASE_PATH_PARAM_NAME, DEFAULT_CONFIG_BASE_PATH);\n        if (StringUtils.isNotEmpty(configBasePath) && !configBasePath.startsWith(PATH_SEPARATOR)) {\n            configBasePath = PATH_SEPARATOR + configBasePath;\n        }\n        return configBasePath;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter.nop;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\n\n/**\n * The default extension of {@link DynamicConfiguration}. If user does not specify a config center, or specifies one\n * that is not a valid extension, it will default to this one.\n */\n@Deprecated\npublic class NopDynamicConfiguration implements DynamicConfiguration {\n\n    public NopDynamicConfiguration(URL url) {\n        // no-op\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        return null;\n    }\n\n    @Override\n    public void addListener(String key, String group, ConfigurationListener listener) {\n        // no-op\n    }\n\n    @Override\n    public void removeListener(String key, String group, ConfigurationListener listener) {\n        // no-op\n    }\n\n    @Override\n    public String getConfig(String key, String group, long timeout) throws IllegalStateException {\n        // no-op\n        return null;\n    }\n\n    /**\n     * @since 2.7.5\n     */\n    @Override\n    public boolean publishConfig(String key, String group, String content) {\n        return true;\n    }\n\n    @Override\n    public void close() throws Exception {\n        // no-op\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfigurationFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter.nop;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\n\n@Deprecated\npublic class NopDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory {\n\n    @Override\n    protected DynamicConfiguration createDynamicConfiguration(URL url) {\n        return new NopDynamicConfiguration(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter.wrapper;\n\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\n\n/**\n * support multiple config center, simply iterating each concrete config center.\n */\npublic class CompositeDynamicConfiguration implements DynamicConfiguration {\n\n    public static final String NAME = \"COMPOSITE\";\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(CompositeDynamicConfiguration.class);\n\n    private final Set<DynamicConfiguration> configurations = new HashSet<>();\n\n    public void addConfiguration(DynamicConfiguration configuration) {\n        if (configuration != null) {\n            this.configurations.add(configuration);\n        }\n    }\n\n    public Set<DynamicConfiguration> getInnerConfigurations() {\n        return configurations;\n    }\n\n    @Override\n    public void addListener(String key, String group, ConfigurationListener listener) {\n        iterateListenerOperation(configuration -> configuration.addListener(key, group, listener));\n    }\n\n    @Override\n    public void removeListener(String key, String group, ConfigurationListener listener) {\n        iterateListenerOperation(configuration -> configuration.removeListener(key, group, listener));\n    }\n\n    @Override\n    public String getConfig(String key, String group, long timeout) throws IllegalStateException {\n        return (String) iterateConfigOperation(configuration -> configuration.getConfig(key, group, timeout));\n    }\n\n    @Override\n    public String getProperties(String key, String group, long timeout) throws IllegalStateException {\n        return (String) iterateConfigOperation(configuration -> configuration.getProperties(key, group, timeout));\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        return iterateConfigOperation(configuration -> configuration.getInternalProperty(key));\n    }\n\n    @Override\n    public boolean publishConfig(String key, String group, String content) throws UnsupportedOperationException {\n        boolean publishedAll = true;\n        for (DynamicConfiguration configuration : configurations) {\n            if (!configuration.publishConfig(key, group, content)) {\n                publishedAll = false;\n            }\n        }\n        return publishedAll;\n    }\n\n    @Override\n    public void close() throws Exception {\n        for (DynamicConfiguration configuration : configurations) {\n            try {\n                configuration.close();\n            } catch (Exception e) {\n                logger.warn(\n                        INTERNAL_ERROR,\n                        \"unknown error in configuration-center related code in common module\",\n                        \"\",\n                        \"close dynamic configuration \"\n                                + configuration.getClass().getName() + \"failed: \" + e.getMessage(),\n                        e);\n            }\n        }\n        configurations.clear();\n    }\n\n    private void iterateListenerOperation(Consumer<DynamicConfiguration> consumer) {\n        for (DynamicConfiguration configuration : configurations) {\n            consumer.accept(configuration);\n        }\n    }\n\n    private Object iterateConfigOperation(Function<DynamicConfiguration, Object> func) {\n        Object value = null;\n        for (DynamicConfiguration configuration : configurations) {\n            value = func.apply(configuration);\n            if (value != null) {\n                break;\n            }\n        }\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/constants/ClusterRules.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\n/**\n *  constant for Cluster fault-tolerant mode\n */\npublic interface ClusterRules {\n\n    /**\n     *  When invoke fails, log the initial error and retry other invokers\n     *  (retry n times, which means at most n different invokers will be invoked)\n     **/\n    String FAIL_OVER = \"failover\";\n\n    /**\n     *  Execute exactly once, which means this policy will throw an exception immediately in case of an invocation error.\n     **/\n    String FAIL_FAST = \"failfast\";\n\n    /**\n     *  When invoke fails, log the error message and ignore this error by returning an empty Result.\n     **/\n    String FAIL_SAFE = \"failsafe\";\n\n    /**\n     *  When fails, record failure requests and schedule for retry on a regular interval.\n     **/\n    String FAIL_BACK = \"failback\";\n\n    /**\n     *  Invoke a specific number of invokers concurrently, usually used for demanding real-time operations, but need to waste more service resources.\n     **/\n    String FORKING = \"forking\";\n\n    /**\n     *  Call all providers by broadcast, call them one by one, and report an error if any one reports an error\n     **/\n    String BROADCAST = \"broadcast\";\n\n    String AVAILABLE = \"available\";\n\n    String MERGEABLE = \"mergeable\";\n\n    String EMPTY = \"\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.net.NetworkInterface;\nimport java.util.Properties;\nimport java.util.concurrent.ExecutorService;\nimport java.util.regex.Pattern;\n\npublic interface CommonConstants {\n\n    String DUBBO = \"dubbo\";\n\n    String TRIPLE = \"tri\";\n\n    String PROVIDER = \"provider\";\n\n    String CONSUMER = \"consumer\";\n\n    String CALLBACK = \"callback\";\n\n    String APPLICATION_KEY = \"application\";\n\n    String APPLICATION_VERSION_KEY = \"application.version\";\n\n    String APPLICATION_PROTOCOL_KEY = \"application-protocol\";\n\n    String METADATA_SERVICE_PORT_KEY = \"metadata-service-port\";\n\n    String METADATA_SERVICE_PROTOCOL_KEY = \"metadata-service-protocol\";\n\n    String METRICS_SERVICE_PORT_KEY = \"metrics-service-port\";\n\n    String METRICS_SERVICE_PROTOCOL_KEY = \"metrics-service-protocol\";\n\n    String LIVENESS_PROBE_KEY = \"liveness-probe\";\n\n    String READINESS_PROBE_KEY = \"readiness-probe\";\n\n    String STARTUP_PROBE = \"startup-probe\";\n\n    String REMOTE_APPLICATION_KEY = \"remote.application\";\n\n    String ENABLED_KEY = \"enabled\";\n\n    String DISABLED_KEY = \"disabled\";\n\n    String DEFAULT_DUBBO_PROPERTIES = \"dubbo.properties\";\n\n    String DEFAULT_DUBBO_MIGRATION_FILE = \"dubbo-migration.yaml\";\n\n    String ANY_VALUE = \"*\";\n\n    /**\n     * @since 2.7.8\n     */\n    char COMMA_SEPARATOR_CHAR = ',';\n\n    String COMMA_SEPARATOR = \",\";\n\n    String DOT_SEPARATOR = \".\";\n\n    Pattern COMMA_SPLIT_PATTERN = Pattern.compile(\"\\\\s*[,]+\\\\s*\");\n\n    String PATH_SEPARATOR = \"/\";\n\n    String PROTOCOL_SEPARATOR = \"://\";\n\n    String PROTOCOL_SEPARATOR_ENCODED = URL.encode(PROTOCOL_SEPARATOR);\n\n    String REGISTRY_SEPARATOR = \"|\";\n\n    Pattern REGISTRY_SPLIT_PATTERN = Pattern.compile(\"\\\\s*[|;]+\\\\s*\");\n\n    Pattern D_REGISTRY_SPLIT_PATTERN = Pattern.compile(\"\\\\s*[|]+\\\\s*\");\n\n    String SEMICOLON_SEPARATOR = \";\";\n\n    Pattern SEMICOLON_SPLIT_PATTERN = Pattern.compile(\"\\\\s*[;]+\\\\s*\");\n\n    Pattern EQUAL_SPLIT_PATTERN = Pattern.compile(\"\\\\s*[=]+\\\\s*\");\n\n    String DEFAULT_PROXY = \"javassist\";\n\n    String DEFAULT_DIRECTORY = \"dubbo\";\n\n    String PROTOCOL_KEY = \"protocol\";\n\n    String DEFAULT_PROTOCOL = \"dubbo\";\n\n    String DEFAULT_THREAD_NAME = \"Dubbo\";\n\n    int DEFAULT_CORE_THREADS = 0;\n\n    int DEFAULT_THREADS = 200;\n\n    String EXECUTOR_SERVICE_COMPONENT_KEY = ExecutorService.class.getName();\n\n    String CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY = \"CONSUMER_SHARED_SERVICE_EXECUTOR\";\n\n    String THREADPOOL_KEY = \"threadpool\";\n\n    String THREAD_NAME_KEY = \"threadname\";\n\n    String CORE_THREADS_KEY = \"corethreads\";\n\n    String THREAD_POOL_EXHAUSTED_LISTENERS_KEY = \"thread-pool-exhausted-listeners\";\n\n    String JSON_CHECK_LEVEL_KEY = \"jsonCheckLevel\";\n\n    String THREADS_KEY = \"threads\";\n\n    String THREADS_VIRTUAL_CORE = \"threads.virtual.core\";\n\n    String QUEUES_KEY = \"queues\";\n\n    String ALIVE_KEY = \"alive\";\n\n    String DEFAULT_THREADPOOL = \"limited\";\n\n    String DEFAULT_CLIENT_THREADPOOL = \"cached\";\n\n    String IO_THREADS_KEY = \"iothreads\";\n\n    String KEEP_ALIVE_KEY = \"keep.alive\";\n\n    int DEFAULT_QUEUES = 0;\n\n    int DEFAULT_ALIVE = 60 * 1000;\n\n    String TIMEOUT_KEY = \"timeout\";\n\n    int DEFAULT_TIMEOUT = 1000;\n\n    String SESSION_KEY = \"session\";\n\n    // used by invocation attachments to transfer timeout from Consumer to Provider.\n    // works as a replacement of TIMEOUT_KEY on wire, which seems to be totally useless in previous releases).\n    String TIMEOUT_ATTACHMENT_KEY = \"_TO\";\n\n    String TIMEOUT_ATTACHMENT_KEY_LOWER = \"_to\";\n\n    String TIME_COUNTDOWN_KEY = \"timeout-countdown\";\n\n    String ENABLE_TIMEOUT_COUNTDOWN_KEY = \"enable-timeout-countdown\";\n\n    String REMOVE_VALUE_PREFIX = \"-\";\n\n    String PROPERTIES_CHAR_SEPARATOR = \"-\";\n\n    String UNDERLINE_SEPARATOR = \"_\";\n\n    String SEPARATOR_REGEX = \"_|-\";\n\n    String GROUP_CHAR_SEPARATOR = \":\";\n\n    String HIDE_KEY_PREFIX = \".\";\n\n    String DOT_REGEX = \"\\\\.\";\n\n    String DEFAULT_KEY_PREFIX = \"default.\";\n\n    String DEFAULT_KEY = \"default\";\n\n    String PREFERRED_KEY = \"preferred\";\n\n    /**\n     * Default timeout value in milliseconds for server shutdown\n     */\n    int DEFAULT_SERVER_SHUTDOWN_TIMEOUT = 10000;\n\n    String SIDE_KEY = \"side\";\n\n    String PROVIDER_SIDE = \"provider\";\n\n    String CONSUMER_SIDE = \"consumer\";\n\n    String ANYHOST_KEY = \"anyhost\";\n\n    String ANYHOST_VALUE = \"0.0.0.0\";\n\n    String LOCALHOST_KEY = \"localhost\";\n\n    String LOCALHOST_VALUE = \"127.0.0.1\";\n\n    String METHODS_KEY = \"methods\";\n\n    String METHOD_KEY = \"method\";\n\n    String PID_KEY = \"pid\";\n\n    String TIMESTAMP_KEY = \"timestamp\";\n\n    String GROUP_KEY = \"group\";\n\n    String PATH_KEY = \"path\";\n\n    String ADDRESS_KEY = \"address\";\n\n    String INTERFACE_KEY = \"interface\";\n\n    String FILE_KEY = \"file\";\n\n    String FILTER_KEY = \"filter\";\n\n    String DUMP_DIRECTORY = \"dump.directory\";\n\n    String DUMP_ENABLE = \"dump.enable\";\n\n    String CLASSIFIER_KEY = \"classifier\";\n\n    String VERSION_KEY = \"version\";\n\n    String REVISION_KEY = \"revision\";\n\n    String METADATA_KEY = \"metadata-type\";\n\n    String REPORT_METADATA_KEY = \"report-metadata\";\n\n    String REPORT_DEFINITION_KEY = \"report-definition\";\n\n    String DEFAULT_METADATA_STORAGE_TYPE = \"local\";\n\n    String REMOTE_METADATA_STORAGE_TYPE = \"remote\";\n\n    String INTERFACE_REGISTER_MODE = \"interface\";\n\n    String INSTANCE_REGISTER_MODE = \"instance\";\n\n    String DEFAULT_REGISTER_MODE = \"all\";\n\n    String GENERIC_KEY = \"generic\";\n\n    /**\n     * The composite metadata storage type includes {@link #DEFAULT_METADATA_STORAGE_TYPE \"local\"} and\n     * {@link #REMOTE_METADATA_STORAGE_TYPE \"remote\"}.\n     *\n     * @since 2.7.8\n     */\n    String COMPOSITE_METADATA_STORAGE_TYPE = \"composite\";\n\n    /**\n     * Consumer side 's proxy class\n     */\n    String PROXY_CLASS_REF = \"refClass\";\n\n    /**\n     * generic call\n     */\n    String $INVOKE = \"$invoke\";\n\n    String $INVOKE_ASYNC = \"$invokeAsync\";\n\n    String GENERIC_PARAMETER_DESC = \"Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/Object;\";\n\n    /**\n     * echo call\n     */\n    String $ECHO = \"$echo\";\n\n    /**\n     * package version in the manifest\n     */\n    String RELEASE_KEY = \"release\";\n\n    String PROTOBUF_MESSAGE_CLASS_NAME = \"com.google.protobuf.Message\";\n\n    int MAX_PROXY_COUNT = 65535;\n\n    String MONITOR_KEY = \"monitor\";\n\n    String BACKGROUND_KEY = \"background\";\n\n    String CLUSTER_KEY = \"cluster\";\n\n    String MERGEABLE_CLUSTER_NAME = \"mergeable\";\n\n    String USERNAME_KEY = \"username\";\n\n    String PASSWORD_KEY = \"password\";\n\n    String HOST_KEY = \"host\";\n\n    String PORT_KEY = \"port\";\n\n    String DUBBO_IP_TO_BIND = \"DUBBO_IP_TO_BIND\";\n\n    /**\n     * broadcast cluster.\n     */\n    String BROADCAST_CLUSTER = \"broadcast\";\n\n    @Deprecated\n    String SHUTDOWN_WAIT_SECONDS_KEY = \"dubbo.service.shutdown.wait.seconds\";\n\n    String SHUTDOWN_WAIT_KEY = \"dubbo.service.shutdown.wait\";\n\n    String DUBBO_PROTOCOL = \"dubbo\";\n\n    String DUBBO_LABELS = \"dubbo.labels\";\n\n    String DUBBO_ENV_KEYS = \"dubbo.env.keys\";\n\n    String CONFIG_CONFIGFILE_KEY = \"config-file\";\n\n    String CONFIG_ENABLE_KEY = \"highest-priority\";\n\n    String CONFIG_NAMESPACE_KEY = \"namespace\";\n\n    String CHECK_KEY = \"check\";\n\n    String BACKLOG_KEY = \"backlog\";\n\n    String HEARTBEAT_EVENT = null;\n\n    String MOCK_HEARTBEAT_EVENT = \"H\";\n\n    String READONLY_EVENT = \"R\";\n\n    String WRITEABLE_EVENT = \"W\";\n\n    String REFERENCE_FILTER_KEY = \"reference.filter\";\n\n    String HEADER_FILTER_KEY = \"header.filter\";\n\n    String INVOCATION_INTERCEPTOR_KEY = \"invocation.interceptor\";\n\n    String INVOKER_LISTENER_KEY = \"invoker.listener\";\n\n    String REGISTRY_PROTOCOL_LISTENER_KEY = \"registry.protocol.listener\";\n\n    String DUBBO_VERSION_KEY = \"dubbo\";\n\n    String TAG_KEY = \"dubbo.tag\";\n\n    /**\n     * To decide whether to make connection when the client is created\n     */\n    String LAZY_CONNECT_KEY = \"lazy\";\n\n    String STUB_EVENT_KEY = \"dubbo.stub.event\";\n\n    String REFERENCE_INTERCEPTOR_KEY = \"reference.interceptor\";\n\n    String SERVICE_FILTER_KEY = \"service.filter\";\n\n    String EXPORTER_LISTENER_KEY = \"exporter.listener\";\n\n    /**\n     * After simplify the registry, should add some parameter individually for provider.\n     *\n     * @since 2.7.0\n     */\n    String EXTRA_KEYS_KEY = \"extra-keys\";\n\n    String GENERIC_SERIALIZATION_NATIVE_JAVA = \"nativejava\";\n\n    String GENERIC_SERIALIZATION_GSON = \"gson\";\n\n    String GENERIC_SERIALIZATION_DEFAULT = \"true\";\n\n    String GENERIC_SERIALIZATION_BEAN = \"bean\";\n\n    String GENERIC_RAW_RETURN = \"raw.return\";\n\n    String GENERIC_SERIALIZATION_PROTOBUF = \"protobuf-json\";\n\n    String GENERIC_WITH_CLZ_KEY = \"generic.include.class\";\n\n    /**\n     * Whether to cache locally, default is true\n     */\n    String REGISTRY_LOCAL_FILE_CACHE_ENABLED = \"file-cache\";\n\n    String METADATA_INFO_CACHE_EXPIRE_KEY = \"metadata-info-cache.expire\";\n\n    int DEFAULT_METADATA_INFO_CACHE_EXPIRE = 10 * 60 * 1000;\n\n    String METADATA_INFO_CACHE_SIZE_KEY = \"metadata-info-cache.size\";\n\n    int DEFAULT_METADATA_INFO_CACHE_SIZE = 16;\n\n    /**\n     * The limit of callback service instances for one interface on every client\n     */\n    String CALLBACK_INSTANCES_LIMIT_KEY = \"callbacks\";\n\n    /**\n     * The default limit number for callback service instances\n     *\n     * @see #CALLBACK_INSTANCES_LIMIT_KEY\n     */\n    int DEFAULT_CALLBACK_INSTANCES = 1;\n\n    String LOADBALANCE_KEY = \"loadbalance\";\n\n    String DEFAULT_LOADBALANCE = \"random\";\n\n    String RETRIES_KEY = \"retries\";\n\n    String FORKS_KEY = \"forks\";\n\n    int DEFAULT_RETRIES = 2;\n\n    int DEFAULT_FAILBACK_TIMES = 3;\n\n    String INTERFACES = \"interfaces\";\n\n    String SSL_ENABLED_KEY = \"ssl-enabled\";\n\n    String SERVICE_PATH_PREFIX = \"service.path.prefix\";\n\n    String PROTOCOL_SERVER_SERVLET = \"servlet\";\n\n    String PROTOCOL_SERVER = \"server\";\n\n    String IPV6_KEY = \"ipv6\";\n\n    /**\n     * The parameter key for the class path of the ServiceNameMapping {@link Properties} file\n     *\n     * @since 2.7.8\n     */\n    String SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY = \"service-name-mapping.properties-path\";\n\n    /**\n     * The default class path of the ServiceNameMapping {@link Properties} file\n     *\n     * @since 2.7.8\n     */\n    String DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH = \"META-INF/dubbo/service-name-mapping.properties\";\n\n    String ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE = \"dubbo.security.serialize.generic.native-java-enable\";\n\n    String SERIALIZE_BLOCKED_LIST_FILE_PATH = \"security/serialize.blockedlist\";\n\n    String SERIALIZE_ALLOW_LIST_FILE_PATH = \"security/serialize.allowlist\";\n\n    String SERIALIZE_CHECK_STATUS_KEY = \"dubbo.application.serialize-check-status\";\n\n    String QOS_LIVE_PROBE_EXTENSION = \"dubbo.application.liveness-probe\";\n\n    String QOS_READY_PROBE_EXTENSION = \"dubbo.application.readiness-probe\";\n\n    String QOS_STARTUP_PROBE_EXTENSION = \"dubbo.application.startup-probe\";\n\n    String REGISTRY_DELAY_NOTIFICATION_KEY = \"delay-notification\";\n\n    String CACHE_CLEAR_TASK_INTERVAL = \"dubbo.application.url.cache.task.interval\";\n\n    String CACHE_CLEAR_WAITING_THRESHOLD = \"dubbo.application.url.cache.clear.waiting\";\n\n    String CLUSTER_INTERCEPTOR_COMPATIBLE_KEY = \"dubbo.application.cluster.interceptor.compatible\";\n\n    String UTF8ENCODE = \"UTF-8\";\n\n    /**\n     * Pseudo URL prefix for loading from the class path: \"classpath:\".\n     */\n    String CLASSPATH_URL_PREFIX = \"classpath:\";\n\n    String DEFAULT_VERSION = \"0.0.0\";\n\n    String ROUTER_KEY = \"router\";\n\n    String EXPORT_ASYNC_KEY = \"export-async\";\n\n    String REFER_ASYNC_KEY = \"refer-async\";\n\n    String EXPORT_BACKGROUND_KEY = \"export-background\";\n\n    String REFER_BACKGROUND_KEY = \"refer-background\";\n\n    String EXPORT_THREAD_NUM_KEY = \"export-thread-num\";\n\n    String REFER_THREAD_NUM_KEY = \"refer-thread-num\";\n\n    int DEFAULT_EXPORT_THREAD_NUM = 10;\n\n    int DEFAULT_REFER_THREAD_NUM = 10;\n\n    int DEFAULT_DELAY_NOTIFICATION_TIME = 5000;\n\n    int DEFAULT_DELAY_EXECUTE_TIMES = 10;\n\n    /**\n     * Url merge processor key\n     */\n    String URL_MERGE_PROCESSOR_KEY = \"url-merge-processor\";\n\n    String DUBBO_MONITOR_ADDRESS = \"dubbo.monitor.address\";\n\n    String SERVICE_NAME_MAPPING_KEY = \"service-name-mapping\";\n\n    String SCOPE_MODEL = \"scopeModel\";\n\n    String SERVICE_MODEL = \"serviceModel\";\n\n    String OS_LINUX_PREFIX = \"linux\";\n\n    String OS_WIN_PREFIX = \"win\";\n\n    String RECONNECT_TASK_TRY_COUNT = \"dubbo.reconnect.reconnectTaskTryCount\";\n\n    int DEFAULT_RECONNECT_TASK_TRY_COUNT = 10;\n\n    String RECONNECT_TASK_PERIOD = \"dubbo.reconnect.reconnectTaskPeriod\";\n\n    int DEFAULT_RECONNECT_TASK_PERIOD = 1000;\n\n    String RESELECT_COUNT = \"dubbo.reselect.count\";\n\n    int DEFAULT_RESELECT_COUNT = 10;\n\n    String ENABLE_CONNECTIVITY_VALIDATION = \"dubbo.connectivity.validation\";\n\n    String DUBBO_INTERNAL_APPLICATION = \"DUBBO_INTERNAL_APPLICATION\";\n\n    String RETRY_TIMES_KEY = \"retry-times\";\n\n    String RETRY_PERIOD_KEY = \"retry-period\";\n\n    String SYNC_REPORT_KEY = \"sync-report\";\n\n    String CYCLE_REPORT_KEY = \"cycle-report\";\n\n    String WORKING_CLASSLOADER_KEY = \"WORKING_CLASSLOADER\";\n\n    String STAGED_CLASSLOADER_KEY = \"STAGED_CLASSLOADER\";\n\n    String PROVIDER_ASYNC_KEY = \"PROVIDER_ASYNC\";\n\n    String REGISTER_IP_KEY = \"register.ip\";\n\n    String CURRENT_CLUSTER_INVOKER_KEY = \"currentClusterInvoker\";\n\n    String ENABLE_ROUTER_SNAPSHOT_PRINT_KEY = \"ENABLE_ROUTER_SNAPSHOT_PRINT\";\n\n    String INJVM_COPY_UTIL_KEY = \"injvm-copy-util\";\n\n    String INJVM_IGNORE_SAME_MODULE_KEY = \"injvm.ignore.same-module\";\n\n    String NATIVE_STUB = \"nativestub\";\n\n    String METADATA = \"metadata\";\n\n    String IGNORE_LISTEN_SHUTDOWN_HOOK = \"dubbo.shutdownHook.listenIgnore\";\n\n    String OPTIMIZER_KEY = \"optimizer\";\n\n    /**\n     * @since 3.1.0\n     */\n    String MESH_ENABLE = \"mesh-enable\";\n\n    /**\n     * @since 3.1.0\n     */\n    Integer DEFAULT_MESH_PORT = 80;\n\n    /**\n     * @since 3.1.0\n     */\n    String SVC = \".svc.\";\n\n    /**\n     * Domain name suffix used inside k8s.\n     *\n     * @since 3.1.0\n     */\n    String DEFAULT_CLUSTER_DOMAIN = \"cluster.local\";\n\n    /**\n     * @since 3.1.0\n     */\n    String UNLOAD_CLUSTER_RELATED = \"unloadClusterRelated\";\n\n    /**\n     * used for thread isolation between services\n     */\n    String SERVICE_EXECUTOR = \"service-executor\";\n\n    String EXECUTOR_MANAGEMENT_MODE = \"executor-management-mode\";\n\n    String EXECUTOR_MANAGEMENT_MODE_DEFAULT = \"default\";\n\n    String EXECUTOR_MANAGEMENT_MODE_ISOLATION = \"isolation\";\n\n    /**\n     * used in JVMUtil.java ,Control stack print lines, default is 32 lines\n     */\n    String DUBBO_JSTACK_MAXLINE = \"dubbo.jstack-dump.max-line\";\n\n    String ENCODE_IN_IO_THREAD_KEY = \"encode.in.io\";\n\n    boolean DEFAULT_ENCODE_IN_IO_THREAD = false;\n\n    String PAYLOAD = \"payload\";\n\n    String DUBBO_METRICS_CONFIGCENTER_ENABLE = \"dubbo.metrics.configcenter.enable\";\n\n    Integer TRI_EXCEPTION_CODE_NOT_EXISTS = 0;\n\n    String PACKABLE_METHOD_FACTORY_KEY = \"serialize.packable.factory\";\n\n    String DUBBO_PACKABLE_METHOD_FACTORY = \"dubbo.application.parameters.\" + PACKABLE_METHOD_FACTORY_KEY;\n\n    String DUBBO_TAG_HEADER = \"dubbo-tag\";\n\n    String REST_SERVICE_DEPLOYER_URL_ATTRIBUTE_KEY = \"restServiceDeployerAttributeKey\";\n\n    String POD_NAMESPACE = \"POD_NAMESPACE\";\n\n    String CLUSTER_DOMAIN = \"CLUSTER_DOMAIN\";\n\n    String EXT_PROTOCOL = \"ext.protocol\";\n\n    String PREFERRED_PROTOCOL = \"preferred.protocol\";\n\n    String IS_EXTRA = \"isExtra\";\n\n    String ZOOKEEPER_ENSEMBLE_TRACKER_KEY = \"zookeeper.ensemble.tracker\";\n\n    String DUBBO_VERSIONS_KEY = \"META-INF/dubbo-versions\";\n\n    String TRIPLE_PREFIX = \"triple.\";\n\n    /**\n     * System-related VM properties\n     */\n    interface SystemProperty {\n\n        String USER_HOME = \"user.home\";\n\n        String SYSTEM_JAVA_VERSION = \"java.version\";\n\n        String SYSTEM_JAVA_IO_TMPDIR = \"java.io.tmpdir\";\n\n        String SYSTEM_LINE_SEPARATOR = \"line.separator\";\n\n        String SERIALIZATION_SECURITY_CHECK_KEY = \"serialization.security.check\";\n\n        String SYSTEM_BYTE_ACCESSOR_KEY = \"byte.accessor\";\n\n        String SYSTEM_OS_NAME = \"os.name\";\n\n        String SYSTEM_OS_VERSION = \"os.version\";\n\n        String JAVA_RUNTIME_NAME = \"java.runtime.name\";\n\n        String JAVA_RUNTIME_VERSION = \"java.runtime.version\";\n\n        String JAVA_VM_NAME = \"java.vm.name\";\n\n        String JAVA_VM_VERSION = \"java.vm.version\";\n\n        String JAVA_VM_INFO = \"java.vm.info\";\n\n        String JAVA_HOME = \"java.home\";\n\n        String OS_ARCH = \"os.arch\";\n\n        String SYSTEM_FILE_ENCODING = \"file.encoding\";\n\n        String SYSTEM_TCP_RESPONSE_TIMEOUT = \"sun.rmi.transport.tcp.responseTimeout\";\n    }\n\n    /**\n     * Third-party-related VM properties\n     */\n    interface ThirdPartyProperty {\n        String NETTY_EPOLL_ENABLE_KEY = \"netty.epoll.enable\";\n\n        String SET_FUTURE_IN_SYNC_MODE = \"future.sync.set\";\n\n        String CLEAR_FUTURE_AFTER_GET = \"future.clear.once\";\n\n        String APOLLO_ADDR_KEY = \"apollo.meta\";\n\n        String APOLLO_CLUSTER_KEY = \"apollo.cluster\";\n\n        String APOLLO_ENV_KEY = \"env\";\n\n        String APOLLO_APPID_KEY = \"app.id\";\n\n        String NACOS_SERVICE_NAME_SEPARATOR = \"nacos.service.name.separator\";\n\n        String GRAALVM_NATIVEIMAGE_IMAGECODE = \"org.graalvm.nativeimage.imagecode\";\n\n        /**\n         * The JVM arguments to set if it can use embedded zookeeper, the default value is {@code true}.\n         */\n        String ZOOKEEPER_CONFIG_ENABLE_EMBEDDED = \"enableEmbeddedZookeeper\";\n    }\n\n    /**\n     * Dubbo custom VM properties\n     */\n    interface DubboProperty {\n        String DUBBO_MIGRATION_FILE_ENABLE = \"dubbo.migration-file.enable\";\n        String DUBBO_MIGRATION_KEY = \"dubbo.migration.file\";\n        String DUBBO_APPLICATION_LOGGER = \"dubbo.application.logger\";\n        String DUBBO_PROPERTIES_KEY = \"dubbo.properties.file\";\n        String DUBBO_PREFER_JSON_FRAMEWORK_NAME = \"dubbo.json-framework.prefer\";\n\n        /**\n         * used in JVMUtil.java ,Control stack print lines, default is 32 lines\n         */\n        String DUBBO_JSTACK_MAXLINE = \"dubbo.jstack-dump.max-line\";\n\n        /**\n         * The property name for {@link NetworkInterface#getDisplayName() the name of network interface} that the Dubbo\n         * application will be ignored\n         *\n         * @since 2.7.6\n         */\n        String DUBBO_NETWORK_IGNORED_INTERFACE = \"dubbo.network.interface.ignored\";\n\n        /**\n         * The property name for {@link NetworkInterface#getDisplayName() the name of network interface} that the Dubbo\n         * application prefers\n         *\n         * @since 2.7.6\n         */\n        String DUBBO_PREFERRED_NETWORK_INTERFACE = \"dubbo.network.interface.preferred\";\n\n        /**\n         * The property name for {@link NetworkInterface#isPointToPoint() return whether a network interface is a point\n         * to point interface} that the Dubbo application will determine whether to ignore the point-to-point network\n         * interface\n         *\n         * @since 3.3\n         */\n        String DUBBO_NETWORK_INTERFACE_POINT_TO_POINT_IGNORED = \"dubbo.network.interface.point-to-point.ignored\";\n\n        String DUBBO_CLASS_DESERIALIZE_ALLOWED_LIST = \"dubbo.security.serialize.allowedClassList\";\n        String DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST = \"dubbo.security.serialize.blockedClassList\";\n        String DUBBO_CLASS_DESERIALIZE_OPEN_CHECK = \"dubbo.security.serialize.openCheckClass\";\n        String DUBBO_CLASS_DESERIALIZE_BLOCK_ALL = \"dubbo.security.serialize.blockAllClassExceptAllow\";\n        String DUBBO_RESOLVE_FILE = \"dubbo.resolve.file\";\n        String DUBBO_IP_TO_REGISTRY = \"DUBBO_IP_TO_REGISTRY\";\n        String DUBBO_MONITOR_ADDRESS = \"dubbo.monitor.address\";\n        String DUBBO_CONTAINER_KEY = \"dubbo.container\";\n        String DUBBO_SHUTDOWN_HOOK_KEY = \"dubbo.shutdown.hook\";\n        String DUBBO_SPRING_CONFIG = \"dubbo.spring.config\";\n        String DUBBO_MAPPING_CACHE_FILEPATH = \"dubbo.mapping.cache.filePath\";\n\n        String DUBBO_MAPPING_CACHE_FILENAME = \"dubbo.mapping.cache.fileName\";\n\n        String DUBBO_MAPPING_CACHE_ENTRYSIZE = \"dubbo.mapping.cache.entrySize\";\n\n        String DUBBO_MAPPING_CACHE_MAXFILESIZE = \"dubbo.mapping.cache.maxFileSize\";\n\n        String DUBBO_META_CACHE_FILEPATH = \"dubbo.meta.cache.filePath\";\n\n        String DUBBO_META_CACHE_FILENAME = \"dubbo.meta.cache.fileName\";\n\n        String DUBBO_META_CACHE_ENTRYSIZE = \"dubbo.meta.cache.entrySize\";\n\n        String DUBBO_META_CACHE_MAXFILESIZE = \"dubbo.meta.cache.maxFileSize\";\n\n        String DUBBO_USE_SECURE_RANDOM_ID = \"dubbo.application.use-secure-random-request-id\";\n\n        String DUBBO_CLOSE_TIMEOUT_CONFIG_KEY = \"dubbo.protocol.default-close-timeout\";\n\n        String DUBBO_HEARTBEAT_CONFIG_KEY = \"dubbo.protocol.default-heartbeat\";\n\n        String DUBBO_DEFAULT_REMOTING_SERIALIZATION_PROPERTY = \"DUBBO_DEFAULT_SERIALIZATION\";\n\n        String DUBBO_HESSIAN_ALLOW_NON_SERIALIZABLE = \"dubbo.hessian.allowNonSerializable\";\n\n        String DUBBO_HESSIAN_WHITELIST = \"dubbo.application.hessian2.whitelist\";\n\n        String DUBBO_HESSIAN_ALLOW = \"dubbo.application.hessian2.allow\";\n\n        String DUBBO_HESSIAN_DENY = \"dubbo.application.hessian2.deny\";\n\n        String DUBBO_MANUAL_REGISTER_KEY = \"dubbo.application.manual-register\";\n\n        String DUBBO2_COMPACT_ENABLE = \"dubbo.compact.enable\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/constants/FilterConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\npublic interface FilterConstants {\n    String CACHE_KEY = \"cache\";\n\n    String VALIDATION_KEY = \"validation\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoadbalanceRules.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\n/**\n *  constant for Load-balance strategy\n */\npublic interface LoadbalanceRules {\n\n    /**\n     *  This class select one provider from multiple providers randomly.\n     **/\n    String RANDOM = \"random\";\n\n    /**\n     * Round-robin load balance.\n     **/\n    String ROUND_ROBIN = \"roundrobin\";\n\n    /**\n     *  Filter the number of invokers with the least number of active calls and count the weights and quantities of these invokers.\n     **/\n    String LEAST_ACTIVE = \"leastactive\";\n\n    /**\n     *  Consistent Hash, requests with the same parameters are always sent to the same provider.\n     **/\n    String CONSISTENT_HASH = \"consistenthash\";\n\n    /**\n     *  Filter the number of invokers with the shortest response time of success calls and count the weights and quantities of these invokers.\n     **/\n    String SHORTEST_RESPONSE = \"shortestresponse\";\n\n    /**\n     *  adaptive load balance.\n     **/\n    String ADAPTIVE = \"adaptive\";\n\n    String EMPTY = \"\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoggerCodeConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\n/**\n * <p>Constants of Error Codes used in logger.\n *\n * <p>Format: <i>[Category]-[Code]</i>, where:\n * <li>[Category] is the category code which identifies the module.\n * <li>[Code] is the detailed code.\n * <li>Every blanks should be filled with positive number.\n *\n * <br /><br />\n * <p>Hint:\n * <li>Synchronize this file across different branches. (Use merge and cherry-pick.)\n * <li>Double-check the usage in different branches before deleting any of the error code.\n * <li>If applicable, use error code that already appears in this file.\n * <li>If it's required to add an error code, find an error code that's marked by 'Absent', and rename it. (so that no code is wasted)\n * <li>Update the corresponding file in dubbo-website repository.\n */\npublic interface LoggerCodeConstants {\n\n    // Common module\n    String COMMON_THREAD_POOL_EXHAUSTED = \"0-1\";\n\n    String COMMON_PROPERTY_TYPE_MISMATCH = \"0-2\";\n\n    String COMMON_CACHE_PATH_INACCESSIBLE = \"0-3\";\n\n    String COMMON_CACHE_MAX_FILE_SIZE_LIMIT_EXCEED = \"0-4\";\n\n    String COMMON_CACHE_MAX_ENTRY_COUNT_LIMIT_EXCEED = \"0-5\";\n\n    String COMMON_THREAD_INTERRUPTED_EXCEPTION = \"0-6\";\n\n    String COMMON_CLASS_NOT_FOUND = \"0-7\";\n\n    String COMMON_REFLECTIVE_OPERATION_FAILED = \"0-8\";\n\n    String COMMON_FAILED_NOTIFY_EVENT = \"0-9\";\n\n    String COMMON_UNSUPPORTED_INVOKER = \"0-10\";\n\n    String COMMON_FAILED_STOP_HTTP_SERVER = \"0-11\";\n\n    String COMMON_UNEXPECTED_EXCEPTION = \"0-12\";\n\n    String COMMON_METRICS_COLLECTOR_EXCEPTION = \"0-13\";\n\n    String COMMON_MONITOR_EXCEPTION = \"0-14\";\n\n    String COMMON_ERROR_LOAD_EXTENSION = \"0-15\";\n\n    String COMMON_EXECUTORS_NO_FOUND = \"0-16\";\n\n    String COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN = \"0-17\";\n\n    String COMMON_ERROR_USE_THREAD_POOL = \"0-18\";\n\n    String COMMON_ERROR_RUN_THREAD_TASK = \"0-19\";\n\n    String COMMON_UNEXPECTED_CREATE_DUMP = \"0-20\";\n\n    String COMMON_ERROR_TOO_MANY_INSTANCES = \"0-21\";\n\n    String COMMON_IO_EXCEPTION = \"0-22\";\n\n    String COMMON_JSON_CONVERT_EXCEPTION = \"0-23\";\n\n    String COMMON_FAILED_OVERRIDE_FIELD = \"0-24\";\n\n    String COMMON_FAILED_LOAD_MAPPING_CACHE = \"0-25\";\n\n    String COMMON_METADATA_PROCESSOR = \"0-26\";\n\n    String COMMON_ISOLATED_EXECUTOR_CONFIGURATION_ERROR = \"0-27\";\n\n    String VULNERABILITY_WARNING = \"0-28\";\n\n    String COMMON_NOT_FOUND_TRACER_DEPENDENCY = \"0-29\";\n\n    // Registry module\n\n    String REGISTRY_ADDRESS_INVALID = \"1-1\";\n\n    /**\n     * Absent. Merged with 0-2.\n     */\n    String REGISTRY_ABSENCE = \"1-2\";\n\n    String REGISTRY_FAILED_URL_EVICTING = \"1-3\";\n\n    String REGISTRY_EMPTY_ADDRESS = \"1-4\";\n\n    String REGISTRY_NO_PARAMETERS_URL = \"1-5\";\n\n    String REGISTRY_FAILED_CLEAR_CACHED_URLS = \"1-6\";\n\n    String REGISTRY_FAILED_NOTIFY_EVENT = \"1-7\";\n\n    String REGISTRY_FAILED_DESTROY_UNREGISTER_URL = \"1-8\";\n\n    String REGISTRY_FAILED_READ_WRITE_CACHE_FILE = \"1-9\";\n\n    String REGISTRY_FAILED_DELETE_LOCKFILE = \"1-10\";\n\n    String REGISTRY_FAILED_CREATE_INSTANCE = \"1-11\";\n\n    String REGISTRY_FAILED_FETCH_INSTANCE = \"1-12\";\n\n    String REGISTRY_EXECUTE_RETRYING_TASK = \"1-13\";\n\n    String REGISTRY_FAILED_PARSE_DYNAMIC_CONFIG = \"1-14\";\n\n    String REGISTRY_FAILED_DESTROY_SERVICE = \"1-15\";\n\n    String REGISTRY_UNSUPPORTED_CATEGORY = \"1-16\";\n\n    String REGISTRY_FAILED_REFRESH_ADDRESS = \"1-17\";\n\n    String REGISTRY_MISSING_METADATA_CONFIG_PORT = \"1-18\";\n\n    String REGISTRY_ERROR_LISTEN_KUBERNETES = \"1-19\";\n\n    String REGISTRY_UNABLE_MATCH_KUBERNETES = \"1-20\";\n\n    String REGISTRY_UNABLE_FIND_SERVICE_KUBERNETES = \"1-21\";\n\n    String REGISTRY_UNABLE_ACCESS_KUBERNETES = \"1-22\";\n\n    /**\n     * Absent. Original '1-23' is changed to '81-3'.\n     */\n    String REGISTRY_FAILED_DOWNLOAD_FILE = \"1-23\";\n\n    /**\n     * Absent. Original '1-24' is changed to '81-1'.\n     */\n    String REGISTRY_FAILED_START_ZOOKEEPER = \"1-24\";\n\n    /**\n     * Absent. Original '1-25' is changed to '81-2'.\n     */\n    String REGISTRY_FAILED_STOP_ZOOKEEPER = \"1-25\";\n\n    String REGISTRY_FAILED_GENERATE_CERT_ISTIO = \"1-26\";\n\n    String REGISTRY_FAILED_GENERATE_KEY_ISTIO = \"1-27\";\n\n    String REGISTRY_RECEIVE_ERROR_MSG_ISTIO = \"1-28\";\n\n    String REGISTRY_ERROR_READ_FILE_ISTIO = \"1-29\";\n\n    String REGISTRY_ERROR_REQUEST_XDS = \"1-30\";\n\n    String REGISTRY_ERROR_RESPONSE_XDS = \"1-31\";\n\n    String REGISTRY_ERROR_CREATE_CHANNEL_XDS = \"1-32\";\n\n    String REGISTRY_ERROR_INITIALIZE_XDS = \"1-33\";\n\n    String REGISTRY_ERROR_PARSING_XDS = \"1-34\";\n\n    String REGISTRY_ZOOKEEPER_EXCEPTION = \"1-35\";\n\n    /**\n     * Absent. Merged with 99-0.\n     */\n    String REGISTRY_UNEXPECTED_EXCEPTION = \"1-36\";\n\n    String REGISTRY_NACOS_EXCEPTION = \"1-37\";\n\n    String REGISTRY_SOCKET_EXCEPTION = \"1-38\";\n\n    String REGISTRY_FAILED_LOAD_METADATA = \"1-39\";\n\n    String REGISTRY_ROUTER_WAIT_LONG = \"1-40\";\n\n    String REGISTRY_ISTIO_EXCEPTION = \"1-41\";\n\n    String REGISTRY_NACOS_SUB_LEGACY = \"1-42\";\n\n    // Cluster module 2-x\n    String CLUSTER_FAILED_SITE_SELECTION = \"2-1\";\n\n    String CLUSTER_NO_VALID_PROVIDER = \"2-2\";\n\n    String CLUSTER_FAILED_STOP = \"2-3\";\n\n    String CLUSTER_FAILED_LOAD_MERGER = \"2-4\";\n\n    String CLUSTER_FAILED_RESELECT_INVOKERS = \"2-5\";\n\n    String CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY = \"2-6\";\n\n    String CLUSTER_FAILED_EXEC_CONDITION_ROUTER = \"2-7\";\n\n    String CLUSTER_ERROR_RESPONSE = \"2-8\";\n\n    String CLUSTER_TIMER_RETRY_FAILED = \"2-9\";\n\n    String CLUSTER_FAILED_INVOKE_SERVICE = \"2-10\";\n\n    String CLUSTER_TAG_ROUTE_INVALID = \"2-11\";\n\n    String CLUSTER_TAG_ROUTE_EMPTY = \"2-12\";\n\n    String CLUSTER_FAILED_RECEIVE_RULE = \"2-13\";\n\n    String CLUSTER_SCRIPT_EXCEPTION = \"2-14\";\n\n    String CLUSTER_FAILED_RULE_PARSING = \"2-15\";\n\n    String CLUSTER_FAILED_MULTIPLE_RETRIES = \"2-16\";\n\n    String CLUSTER_FAILED_MOCK_REQUEST = \"2-17\";\n\n    String CLUSTER_NO_RULE_LISTENER = \"2-18\";\n\n    String CLUSTER_EXECUTE_FILTER_EXCEPTION = \"2-19\";\n\n    String CLUSTER_FAILED_GROUP_MERGE = \"2-20\";\n\n    // Proxy module. 3-1\n    String PROXY_FAILED_CONVERT_URL = \"3-1\";\n\n    String PROXY_FAILED_EXPORT_SERVICE = \"3-2\";\n\n    /**\n     * Absent. Merged with 3-8.\n     */\n    String PROXY_33 = \"3-3\";\n\n    String PROXY_TIMEOUT_REQUEST = \"3-4\";\n\n    String PROXY_ERROR_ASYNC_RESPONSE = \"3-5\";\n\n    String PROXY_UNSUPPORTED_INVOKER = \"3-6\";\n\n    String PROXY_TIMEOUT_RESPONSE = \"3-7\";\n\n    String PROXY_FAILED = \"3-8\";\n\n    // Protocol module.\n    String PROTOCOL_UNSUPPORTED = \"4-1\";\n\n    String PROTOCOL_FAILED_INIT_SERIALIZATION_OPTIMIZER = \"4-2\";\n\n    String PROTOCOL_FAILED_REFER_INVOKER = \"4-3\";\n\n    String PROTOCOL_UNSAFE_SERIALIZATION = \"4-4\";\n\n    String PROTOCOL_FAILED_CLOSE_STREAM = \"4-5\";\n\n    String PROTOCOL_ERROR_DESERIALIZE = \"4-6\";\n\n    String PROTOCOL_ERROR_CLOSE_CLIENT = \"4-7\";\n\n    String PROTOCOL_ERROR_CLOSE_SERVER = \"4-8\";\n\n    String PROTOCOL_FAILED_PARSE = \"4-9\";\n\n    String PROTOCOL_FAILED_SERIALIZE_TRIPLE = \"4-10\";\n\n    String PROTOCOL_FAILED_REQUEST = \"4-11\";\n\n    String PROTOCOL_FAILED_CREATE_STREAM_TRIPLE = \"4-12\";\n\n    String PROTOCOL_TIMEOUT_SERVER = \"4-13\";\n\n    String PROTOCOL_FAILED_RESPONSE = \"4-14\";\n\n    String PROTOCOL_STREAM_LISTENER = \"4-15\";\n\n    String PROTOCOL_CLOSED_SERVER = \"4-16\";\n\n    String PROTOCOL_FAILED_DESTROY_INVOKER = \"4-17\";\n\n    String PROTOCOL_FAILED_LOAD_MODEL = \"4-18\";\n\n    String PROTOCOL_INCORRECT_PARAMETER_VALUES = \"4-19\";\n\n    String PROTOCOL_FAILED_DECODE = \"4-20\";\n\n    String PROTOCOL_UNTRUSTED_SERIALIZE_CLASS = \"4-21\";\n\n    // Config module\n    String CONFIG_FAILED_CONNECT_REGISTRY = \"5-1\";\n\n    String CONFIG_FAILED_SHUTDOWN_HOOK = \"5-2\";\n\n    String CONFIG_FAILED_DESTROY_INVOKER = \"5-3\";\n\n    String CONFIG_NO_METHOD_FOUND = \"5-4\";\n\n    String CONFIG_FAILED_LOAD_ENV_VARIABLE = \"5-5\";\n\n    String CONFIG_PROPERTY_CONFLICT = \"5-6\";\n\n    String CONFIG_UNEXPORT_ERROR = \"5-7\";\n\n    String CONFIG_USE_RANDOM_PORT = \"5-8\";\n\n    String CONFIG_FAILED_EXPORT_SERVICE = \"5-9\";\n\n    String CONFIG_SERVER_DISCONNECTED = \"5-10\";\n\n    String CONFIG_REGISTER_INSTANCE_ERROR = \"5-11\";\n\n    String CONFIG_REFRESH_INSTANCE_ERROR = \"5-12\";\n\n    String CONFIG_UNABLE_DESTROY_MODEL = \"5-13\";\n\n    String CONFIG_FAILED_START_MODEL = \"5-14\";\n\n    String CONFIG_FAILED_REFERENCE_MODEL = \"5-15\";\n\n    String CONFIG_FAILED_FIND_PROTOCOL = \"5-16\";\n\n    String CONFIG_PARAMETER_FORMAT_ERROR = \"5-17\";\n\n    String CONFIG_FAILED_NOTIFY_EVENT = \"5-18\";\n\n    /**\n     * Absent. Changed to 81-4.\n     */\n    String CONFIG_ZOOKEEPER_SERVER_ERROR = \"5-19\";\n\n    String CONFIG_STOP_DUBBO_ERROR = \"5-20\";\n\n    String CONFIG_FAILED_EXECUTE_DESTROY = \"5-21\";\n\n    String CONFIG_FAILED_INIT_CONFIG_CENTER = \"5-22\";\n\n    String CONFIG_FAILED_WAIT_EXPORT_REFER = \"5-23\";\n\n    String CONFIG_FAILED_REFER_SERVICE = \"5-24\";\n\n    String CONFIG_UNDEFINED_PROTOCOL = \"5-25\";\n\n    String CONFIG_METADATA_SERVICE_EXPORTED = \"5-26\";\n\n    String CONFIG_API_WRONG_USE = \"5-27\";\n\n    String CONFIG_NO_ANNOTATIONS_FOUND = \"5-28\";\n\n    String CONFIG_NO_BEANS_SCANNED = \"5-29\";\n\n    String CONFIG_DUPLICATED_BEAN_DEFINITION = \"5-30\";\n\n    String CONFIG_WARN_STATUS_CHECKER = \"5-31\";\n\n    String CONFIG_FAILED_CLOSE_CONNECT_APOLLO = \"5-32\";\n\n    String CONFIG_NOT_EFFECT_EMPTY_RULE_APOLLO = \"5-33\";\n\n    String CONFIG_ERROR_NACOS = \"5-34\";\n\n    String CONFIG_START_DUBBO_ERROR = \"5-35\";\n\n    String CONFIG_FILTER_VALIDATION_EXCEPTION = \"5-36\";\n\n    String CONFIG_ERROR_PROCESS_LISTENER = \"5-37\";\n\n    String CONFIG_UNDEFINED_ARGUMENT = \"5-38\";\n\n    String CONFIG_DUBBO_BEAN_INITIALIZER = \"5-39\";\n\n    String CONFIG_DUBBO_BEAN_NOT_FOUND = \"5-40\";\n\n    String CONFIG_SSL_PATH_LOAD_FAILED = \"5-41\";\n\n    String CONFIG_SSL_CERT_GENERATE_FAILED = \"5-42\";\n\n    String CONFIG_SSL_CONNECT_INSECURE = \"5-43\";\n\n    // Transport module\n    String TRANSPORT_FAILED_CONNECT_PROVIDER = \"6-1\";\n\n    String TRANSPORT_CLIENT_CONNECT_TIMEOUT = \"6-2\";\n\n    String TRANSPORT_FAILED_CLOSE = \"6-3\";\n\n    /**\n     * Absent. Merged to 99-0.\n     */\n    String TRANSPORT_UNEXPECTED_EXCEPTION = \"6-4\";\n\n    String TRANSPORT_FAILED_DISCONNECT_PROVIDER = \"6-5\";\n\n    String TRANSPORT_UNSUPPORTED_MESSAGE = \"6-6\";\n\n    String TRANSPORT_CONNECTION_LIMIT_EXCEED = \"6-7\";\n\n    String TRANSPORT_FAILED_DECODE = \"6-8\";\n\n    String TRANSPORT_FAILED_SERIALIZATION = \"6-9\";\n\n    String TRANSPORT_EXCEED_PAYLOAD_LIMIT = \"6-10\";\n\n    String TRANSPORT_UNSUPPORTED_CHARSET = \"6-11\";\n\n    String TRANSPORT_FAILED_DESTROY_ZOOKEEPER = \"6-12\";\n\n    String TRANSPORT_FAILED_CLOSE_STREAM = \"6-13\";\n\n    String TRANSPORT_FAILED_RESPONSE = \"6-14\";\n\n    String TRANSPORT_SKIP_UNUSED_STREAM = \"6-15\";\n\n    String TRANSPORT_FAILED_RECONNECT = \"6-16\";\n\n    // qos plugin\n    String QOS_PROFILER_DISABLED = \"7-1\";\n\n    String QOS_PROFILER_ENABLED = \"7-2\";\n\n    String QOS_PROFILER_WARN_PERCENT = \"7-3\";\n\n    String QOS_FAILED_START_SERVER = \"7-4\";\n\n    String QOS_COMMAND_NOT_FOUND = \"7-5\";\n\n    String QOS_UNEXPECTED_EXCEPTION = \"7-6\";\n\n    String QOS_PERMISSION_DENY_EXCEPTION = \"7-7\";\n\n    // MCP plugin\n    String MCP_FAILED_START_SERVER = \"8-1\";\n\n    // Testing module (8[X], where [X] is number of the module to be tested.)\n    String TESTING_REGISTRY_FAILED_TO_START_ZOOKEEPER = \"81-1\";\n\n    String TESTING_REGISTRY_FAILED_TO_STOP_ZOOKEEPER = \"81-2\";\n\n    String TESTING_REGISTRY_FAILED_TO_DOWNLOAD_ZK_FILE = \"81-3\";\n\n    String TESTING_INIT_ZOOKEEPER_SERVER_ERROR = \"81-4\";\n\n    // Internal unknown error.\n\n    /**\n     * Unknown internal error. (99-0)\n     */\n    String INTERNAL_ERROR = \"99-0\";\n\n    String INTERNAL_INTERRUPTED = \"99-1\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\npublic interface MetricsConstants {\n\n    String PROTOCOL_PROMETHEUS = \"prometheus\";\n    String PROTOCOL_DEFAULT = \"default\";\n\n    String TAG_IP = \"ip\";\n\n    String TAG_PID = \"pid\";\n\n    String TAG_HOSTNAME = \"hostname\";\n\n    String TAG_APPLICATION_NAME = \"application.name\";\n\n    String TAG_APPLICATION_MODULE = \"application.module.id\";\n\n    String TAG_INTERFACE_KEY = \"interface\";\n\n    String TAG_METHOD_KEY = \"method\";\n\n    String TAG_GROUP_KEY = \"group\";\n\n    String TAG_VERSION_KEY = \"version\";\n\n    String TAG_APPLICATION_VERSION_KEY = \"application.version\";\n\n    String TAG_KEY_KEY = \"key\";\n\n    String TAG_CONFIG_CENTER = \"config.center\";\n\n    String TAG_CHANGE_TYPE = \"change.type\";\n\n    String TAG_ERROR_CODE = \"error\";\n\n    String ENABLE_JVM_METRICS_KEY = \"enable.jvm\";\n\n    String ENABLE_COLLECTOR_SYNC_KEY = \"enable.collector.sync\";\n\n    String COLLECTOR_SYNC_PERIOD_KEY = \"collector.sync.period\";\n\n    String AGGREGATION_COLLECTOR_KEY = \"aggregation\";\n\n    String AGGREGATION_ENABLED_KEY = \"aggregation.enabled\";\n\n    String AGGREGATION_BUCKET_NUM_KEY = \"aggregation.bucket.num\";\n\n    String AGGREGATION_TIME_WINDOW_SECONDS_KEY = \"aggregation.time.window.seconds\";\n\n    String HISTOGRAM_ENABLED_KEY = \"histogram.enabled\";\n\n    String PROMETHEUS_EXPORTER_ENABLED_KEY = \"prometheus.exporter.enabled\";\n\n    String PROMETHEUS_EXPORTER_ENABLE_HTTP_SERVICE_DISCOVERY_KEY = \"prometheus.exporter.enable.http.service.discovery\";\n\n    String PROMETHEUS_EXPORTER_HTTP_SERVICE_DISCOVERY_URL_KEY = \"prometheus.exporter.http.service.discovery.url\";\n\n    String PROMETHEUS_EXPORTER_METRICS_PORT_KEY = \"prometheus.exporter.metrics.port\";\n\n    String PROMETHEUS_EXPORTER_METRICS_PATH_KEY = \"prometheus.exporter.metrics.path\";\n\n    String PROMETHEUS_PUSHGATEWAY_ENABLED_KEY = \"prometheus.pushgateway.enabled\";\n\n    String PROMETHEUS_PUSHGATEWAY_BASE_URL_KEY = \"prometheus.pushgateway.base.url\";\n\n    String PROMETHEUS_PUSHGATEWAY_USERNAME_KEY = \"prometheus.pushgateway.username\";\n\n    String PROMETHEUS_PUSHGATEWAY_PASSWORD_KEY = \"prometheus.pushgateway.password\";\n\n    String PROMETHEUS_PUSHGATEWAY_PUSH_INTERVAL_KEY = \"prometheus.pushgateway.push.interval\";\n\n    String PROMETHEUS_PUSHGATEWAY_JOB_KEY = \"prometheus.pushgateway.job\";\n\n    int PROMETHEUS_DEFAULT_METRICS_PORT = 20888;\n\n    String PROMETHEUS_DEFAULT_METRICS_PATH = \"/metrics\";\n\n    int PROMETHEUS_DEFAULT_PUSH_INTERVAL = 30;\n\n    String PROMETHEUS_DEFAULT_JOB_NAME = \"default_dubbo_job\";\n\n    String METRIC_FILTER_START_TIME = \"metric_filter_start_time\";\n\n    String TAG_THREAD_NAME = \"thread.pool.name\";\n\n    String PROTOCOL_OTLP = \"otlp\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/constants/QosConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\npublic interface QosConstants {\n\n    String QOS_ENABLE = \"qos.enable\";\n\n    String QOS_CHECK = \"qos.check\";\n\n    String QOS_HOST = \"qos.host\";\n\n    String QOS_PORT = \"qos.port\";\n\n    String ACCEPT_FOREIGN_IP = \"qos.accept.foreign.ip\";\n\n    String ACCEPT_FOREIGN_IP_WHITELIST = \"qos.accept.foreign.ip.whitelist\";\n\n    String ANONYMOUS_ACCESS_PERMISSION_LEVEL = \"qos.anonymous.access.permission.level\";\n\n    String ANONYMOUS_ACCESS_ALLOW_COMMANDS = \"qos.anonymous.access.allow.commands\";\n\n    String QOS_ENABLE_COMPATIBLE = \"qos-enable\";\n\n    String QOS_HOST_COMPATIBLE = \"qos-host\";\n\n    String QOS_PORT_COMPATIBLE = \"qos-port\";\n\n    String ACCEPT_FOREIGN_IP_COMPATIBLE = \"qos-accept-foreign-ip\";\n\n    String ACCEPT_FOREIGN_IP_WHITELIST_COMPATIBLE = \"qos-accept-foreign-ip-whitelist\";\n\n    String ANONYMOUS_ACCESS_PERMISSION_LEVEL_COMPATIBLE = \"qos-anonymous-access-permission-level\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegisterTypeEnum.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\n/**\n * Indicate that a service need to be registered to registry or not\n */\npublic enum RegisterTypeEnum {\n\n    /**\n     * Never register. Cannot be registered by any command(like QoS-online).\n     */\n    NEVER_REGISTER,\n\n    /**\n     * Manual register. Can be registered by command(like QoS-online), but not register by default.\n     */\n    MANUAL_REGISTER,\n\n    /**\n     * (INTERNAL) Auto register by deployer. Will be registered after deployer started.\n     * (Delay publish when starting. Prevent service from being invoked before all services are started)\n     */\n    AUTO_REGISTER_BY_DEPLOYER,\n\n    /**\n     * Auto register. Will be registered when one service is exported.\n     */\n    AUTO_REGISTER;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\npublic interface RegistryConstants {\n\n    String REGISTRY_KEY = \"registry\";\n\n    String REGISTRY_CLUSTER_KEY = \"REGISTRY_CLUSTER\";\n\n    String REGISTRY_CLUSTER_TYPE_KEY = \"registry-cluster-type\";\n\n    String REGISTRY_PROTOCOL = \"registry\";\n\n    String DYNAMIC_KEY = \"dynamic\";\n\n    String CATEGORY_KEY = \"category\";\n\n    String PROVIDERS_CATEGORY = \"providers\";\n\n    String CONSUMERS_CATEGORY = \"consumers\";\n\n    String ROUTERS_CATEGORY = \"routers\";\n\n    String DYNAMIC_ROUTERS_CATEGORY = \"dynamicrouters\";\n\n    String DEFAULT_CATEGORY = PROVIDERS_CATEGORY;\n\n    String CONFIGURATORS_CATEGORY = \"configurators\";\n\n    String ALL_CATEGORIES = \"providers,configurators,routers\";\n\n    String DYNAMIC_CONFIGURATORS_CATEGORY = \"dynamicconfigurators\";\n\n    String APP_DYNAMIC_CONFIGURATORS_CATEGORY = \"appdynamicconfigurators\";\n\n    String ROUTERS_SUFFIX = \".routers\";\n\n    String EMPTY_PROTOCOL = \"empty\";\n\n    String ROUTE_PROTOCOL = \"route\";\n\n    String ROUTE_SCRIPT_PROTOCOL = \"script\";\n\n    String OVERRIDE_PROTOCOL = \"override\";\n\n    String COMPATIBLE_CONFIG_KEY = \"compatible_config\";\n\n    String REGISTER_MODE_KEY = \"register-mode\";\n\n    String DUBBO_REGISTER_MODE_DEFAULT_KEY = \"dubbo.application.register-mode\";\n\n    String DUBBO_PUBLISH_INTERFACE_DEFAULT_KEY = \"dubbo.application.publish-interface\";\n\n    String DUBBO_PUBLISH_INSTANCE_DEFAULT_KEY = \"dubbo.application.publish-instance\";\n\n    String DEFAULT_REGISTER_MODE_INTERFACE = \"interface\";\n\n    String DEFAULT_REGISTER_MODE_INSTANCE = \"instance\";\n\n    String DEFAULT_REGISTER_MODE_ALL = \"all\";\n    /**\n     * The parameter key of Dubbo Registry type\n     *\n     * @since 2.7.5\n     */\n    String REGISTRY_TYPE_KEY = \"registry-type\";\n\n    /**\n     * The parameter value of Service-Oriented Registry type\n     *\n     * @since 2.7.5\n     */\n    String SERVICE_REGISTRY_TYPE = \"service\";\n\n    /**\n     * The protocol for Service Discovery\n     *\n     * @since 2.7.5\n     */\n    String SERVICE_REGISTRY_PROTOCOL = \"service-discovery-registry\";\n\n    /**\n     * Specify registry level services consumer needs to subscribe to, multiple values should be separated using \",\".\n     */\n    String SUBSCRIBED_SERVICE_NAMES_KEY = \"subscribed-services\";\n\n    String PROVIDED_BY = \"provided-by\";\n\n    /**\n     * The provider tri port\n     *\n     * @since 3.1.0\n     */\n    String PROVIDER_PORT = \"provider-port\";\n\n    /**\n     * provider namespace\n     *\n     * @since 3.1.1\n     */\n    String PROVIDER_NAMESPACE = \"provider-namespace\";\n\n    /**\n     * The request size of service instances\n     *\n     * @since 2.7.5\n     */\n    String INSTANCES_REQUEST_SIZE_KEY = \"instances-request-size\";\n\n    /**\n     * The default request size of service instances\n     */\n    int DEFAULT_INSTANCES_REQUEST_SIZE = 100;\n\n    String ACCEPTS_KEY = \"accepts\";\n\n    String REGISTRY_ZONE = \"registry_zone\";\n    String REGISTRY_ZONE_FORCE = \"registry_zone_force\";\n    String ZONE_KEY = \"zone\";\n\n    String REGISTRY_SERVICE_REFERENCE_PATH = \"org.apache.dubbo.registry.RegistryService\";\n    String INIT = \"INIT\";\n\n    float DEFAULT_HASHMAP_LOAD_FACTOR = 0.75f;\n\n    String ENABLE_EMPTY_PROTECTION_KEY = \"enable-empty-protection\";\n    boolean DEFAULT_ENABLE_EMPTY_PROTECTION = false;\n    String REGISTER_CONSUMER_URL_KEY = \"register-consumer-url\";\n    String REGISTRY_PROTOCOL_TYPE = \"registry-protocol-type\";\n\n    /**\n     * export noting suffix servicename\n     * by default, dubbo export servicename is \"${interface}:${version}:\", this servicename with ':' suffix\n     * for compatible, we should export noting suffix servicename, eg: ${interface}:${version}\n     */\n    String NACOS_REGISTER_COMPATIBLE = \"nacos.register-compatible\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/constants/RemotingConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\npublic interface RemotingConstants {\n\n    String BACKUP_KEY = \"backup\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/context/ApplicationExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.context;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.APPLICATION)\npublic interface ApplicationExt extends Lifecycle {}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/context/Lifecycle.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.context;\n\nimport org.apache.dubbo.common.resource.Disposable;\n\n/**\n * The Lifecycle of Dubbo component\n *\n * @since 2.7.5\n */\npublic interface Lifecycle extends Disposable {\n\n    /**\n     * Initialize the component before {@link #start() start}\n     *\n     * @return current {@link Lifecycle}\n     * @throws IllegalStateException\n     */\n    void initialize() throws IllegalStateException;\n\n    /**\n     * Start the component\n     *\n     * @return current {@link Lifecycle}\n     * @throws IllegalStateException\n     */\n    void start() throws IllegalStateException;\n\n    /**\n     * Destroy the component\n     *\n     * @throws IllegalStateException\n     */\n    void destroy() throws IllegalStateException;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/context/LifecycleAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.context;\n\npublic abstract class LifecycleAdapter implements Lifecycle {\n\n    @Override\n    public void initialize() throws IllegalStateException {}\n\n    @Override\n    public void start() throws IllegalStateException {}\n\n    @Override\n    public void destroy() throws IllegalStateException {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/context/ModuleExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.context;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.MODULE)\npublic interface ModuleExt extends Lifecycle {}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.lang.Prioritized;\n\nimport static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom;\nimport static org.apache.dubbo.common.utils.TypeUtils.findActualTypeArgument;\n\n/**\n * A class to convert the source-typed value to the target-typed value\n *\n * @param <S> The source type\n * @param <T> The target type\n * @since 2.7.6\n */\n@SPI(scope = ExtensionScope.FRAMEWORK)\n@FunctionalInterface\npublic interface Converter<S, T> extends Prioritized {\n\n    /**\n     * Accept the source type and target type or not\n     *\n     * @param sourceType the source type\n     * @param targetType the target type\n     * @return if accepted, return <code>true</code>, or <code>false</code>\n     */\n    default boolean accept(Class<?> sourceType, Class<?> targetType) {\n        return isAssignableFrom(sourceType, getSourceType()) && isAssignableFrom(targetType, getTargetType());\n    }\n\n    /**\n     * Convert the source-typed value to the target-typed value\n     *\n     * @param source the source-typed value\n     * @return the target-typed value\n     */\n    T convert(S source);\n\n    /**\n     * Get the source type\n     *\n     * @return non-null\n     */\n    default Class<S> getSourceType() {\n        return findActualTypeArgument(getClass(), Converter.class, 0);\n    }\n\n    /**\n     * Get the target type\n     *\n     * @return non-null\n     */\n    default Class<T> getTargetType() {\n        return findActualTypeArgument(getClass(), Converter.class, 1);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/ConverterUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.stream.Collectors;\n\npublic class ConverterUtil {\n    private final FrameworkModel frameworkModel;\n    private final ConcurrentMap<Class<?>, ConcurrentMap<Class<?>, List<Converter>>> converterCache =\n            new ConcurrentHashMap<>();\n\n    public ConverterUtil(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    /**\n     * Get the Converter instance from {@link ExtensionLoader} with the specified source and target type\n     *\n     * @param sourceType the source type\n     * @param targetType the target type\n     * @return\n     * @see ExtensionLoader#getSupportedExtensionInstances()\n     */\n    public Converter<?, ?> getConverter(Class<?> sourceType, Class<?> targetType) {\n        ConcurrentMap<Class<?>, List<Converter>> toTargetMap =\n                ConcurrentHashMapUtils.computeIfAbsent(converterCache, sourceType, (k) -> new ConcurrentHashMap<>());\n        List<Converter> converters = ConcurrentHashMapUtils.computeIfAbsent(\n                toTargetMap,\n                targetType,\n                (k) -> frameworkModel.getExtensionLoader(Converter.class).getSupportedExtensionInstances().stream()\n                        .filter(converter -> converter.accept(sourceType, targetType))\n                        .collect(Collectors.toList()));\n\n        return converters.size() > 0 ? converters.get(0) : null;\n    }\n\n    /**\n     * Convert the value of source to target-type value if possible\n     *\n     * @param source     the value of source\n     * @param targetType the target type\n     * @param <T>        the target type\n     * @return <code>null</code> if can't be converted\n     * @since 2.7.8\n     */\n    public <T> T convertIfPossible(Object source, Class<T> targetType) {\n        Converter converter = getConverter(source.getClass(), targetType);\n        if (converter != null) {\n            return (T) converter.convert(source);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\n/**\n * A class to covert {@link String} to the target-typed value\n *\n * @see Converter\n * @since 2.7.6\n */\n@FunctionalInterface\npublic interface StringConverter<T> extends Converter<String, T> {}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToBooleanConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport static java.lang.Boolean.valueOf;\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\n\n/**\n * The class to convert {@link String} to {@link Boolean}\n *\n * @since 2.7.6\n */\npublic class StringToBooleanConverter implements StringConverter<Boolean> {\n\n    @Override\n    public Boolean convert(String source) {\n        return isNotEmpty(source) ? valueOf(source) : null;\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY + 5;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToByteConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\n/**\n * The class to convert {@link String} to {@link Byte}\n *\n * @since 3.0.4\n */\npublic class StringToByteConverter implements StringConverter<Byte> {\n    @Override\n    public Byte convert(String source) {\n        return StringUtils.isNotEmpty(source) ? Byte.valueOf(source) : null;\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY + 9;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToCharArrayConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\n\n/**\n * The class to convert {@link String} to <code>char[]</code>\n *\n * @since 2.7.6\n */\npublic class StringToCharArrayConverter implements StringConverter<char[]> {\n\n    @Override\n    public char[] convert(String source) {\n        return isNotEmpty(source) ? source.toCharArray() : null;\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY + 7;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToCharacterConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport static org.apache.dubbo.common.utils.StringUtils.length;\n\n/**\n * The class to convert {@link String} to {@link Character}\n *\n * @since 2.7.6\n */\npublic class StringToCharacterConverter implements StringConverter<Character> {\n\n    @Override\n    public Character convert(String source) {\n        int length = length(source);\n        if (length == 0) {\n            return null;\n        }\n        if (length > 1) {\n            throw new IllegalArgumentException(\"The source String is more than one character!\");\n        }\n        return source.charAt(0);\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY + 8;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToDoubleConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport static java.lang.Double.valueOf;\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\n\n/**\n * The class to convert {@link String} to {@link Double}\n *\n * @since 2.7.6\n */\npublic class StringToDoubleConverter implements StringConverter<Double> {\n\n    @Override\n    public Double convert(String source) {\n        return isNotEmpty(source) ? valueOf(source) : null;\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY + 3;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToDurationConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.function.Function;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\n\npublic class StringToDurationConverter implements StringConverter<Duration> {\n\n    @Override\n    public Duration convert(String source) {\n        return isNotEmpty(source) ? DurationStyle.detectAndParse(source) : null;\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY + 10;\n    }\n\n    enum DurationStyle {\n\n        /**\n         * Simple formatting, for example '1s'.\n         */\n        SIMPLE(\"^([+-]?\\\\d+)([a-zA-Z]{0,2})$\") {\n            @Override\n            public Duration parse(String value, ChronoUnit unit) {\n                try {\n                    Matcher matcher = matcher(value);\n                    Assert.assertTrue(matcher.matches(), \"Does not match simple duration pattern\");\n                    String suffix = matcher.group(2);\n                    return (StringUtils.isNotBlank(suffix)\n                                    ? TimeUnit.fromSuffix(suffix)\n                                    : TimeUnit.fromChronoUnit(unit))\n                            .parse(matcher.group(1));\n                } catch (Exception ex) {\n                    throw new IllegalArgumentException(\"'\" + value + \"' is not a valid simple duration\", ex);\n                }\n            }\n        },\n\n        /**\n         * ISO-8601 formatting.\n         */\n        ISO8601(\"^[+-]?[pP].*$\") {\n            @Override\n            public Duration parse(String value, ChronoUnit unit) {\n                try {\n                    return Duration.parse(value);\n                } catch (Exception ex) {\n                    throw new IllegalArgumentException(\"'\" + value + \"' is not a valid ISO-8601 duration\", ex);\n                }\n            }\n        };\n\n        private final Pattern pattern;\n\n        DurationStyle(String pattern) {\n            this.pattern = Pattern.compile(pattern);\n        }\n\n        protected final boolean matches(String value) {\n            return this.pattern.matcher(value).matches();\n        }\n\n        protected final Matcher matcher(String value) {\n            return this.pattern.matcher(value);\n        }\n\n        /**\n         * Parse the given value to a duration.\n         *\n         * @param value the value to parse\n         * @return a duration\n         */\n        public Duration parse(String value) {\n            return parse(value, null);\n        }\n\n        /**\n         * Parse the given value to a duration.\n         *\n         * @param value the value to parse\n         * @param unit  the duration unit to use if the value doesn't specify one ({@code null}\n         *              will default to ms)\n         * @return a duration\n         */\n        public abstract Duration parse(String value, ChronoUnit unit);\n\n        /**\n         * Detect the style then parse the value to return a duration.\n         *\n         * @param value the value to parse\n         * @return the parsed duration\n         * @throws IllegalArgumentException if the value is not a known style or cannot be\n         *                                  parsed\n         */\n        public static Duration detectAndParse(String value) {\n            return detectAndParse(value, null);\n        }\n\n        /**\n         * Detect the style then parse the value to return a duration.\n         *\n         * @param value the value to parse\n         * @param unit  the duration unit to use if the value doesn't specify one ({@code null}\n         *              will default to ms)\n         * @return the parsed duration\n         * @throws IllegalArgumentException if the value is not a known style or cannot be\n         *                                  parsed\n         */\n        public static Duration detectAndParse(String value, ChronoUnit unit) {\n            return detect(value).parse(value, unit);\n        }\n\n        /**\n         * Detect the style from the given source value.\n         *\n         * @param value the source value\n         * @return the duration style\n         * @throws IllegalArgumentException if the value is not a known style\n         */\n        public static DurationStyle detect(String value) {\n            Assert.notNull(value, \"Value must not be null\");\n            for (DurationStyle candidate : values()) {\n                if (candidate.matches(value)) {\n                    return candidate;\n                }\n            }\n            throw new IllegalArgumentException(\"'\" + value + \"' is not a valid duration\");\n        }\n\n        /**\n         * Time Unit that support.\n         */\n        enum TimeUnit {\n\n            /**\n             * Nanoseconds.\n             */\n            NANOS(ChronoUnit.NANOS, \"ns\", Duration::toNanos),\n\n            /**\n             * Microseconds.\n             */\n            MICROS(ChronoUnit.MICROS, \"us\", (duration) -> duration.toNanos() / 1000L),\n\n            /**\n             * Milliseconds.\n             */\n            MILLIS(ChronoUnit.MILLIS, \"ms\", Duration::toMillis),\n\n            /**\n             * Seconds.\n             */\n            SECONDS(ChronoUnit.SECONDS, \"s\", Duration::getSeconds),\n\n            /**\n             * Minutes.\n             */\n            MINUTES(ChronoUnit.MINUTES, \"m\", Duration::toMinutes),\n\n            /**\n             * Hours.\n             */\n            HOURS(ChronoUnit.HOURS, \"h\", Duration::toHours),\n\n            /**\n             * Days.\n             */\n            DAYS(ChronoUnit.DAYS, \"d\", Duration::toDays);\n\n            private final ChronoUnit chronoUnit;\n\n            private final String suffix;\n\n            private final Function<Duration, Long> longValue;\n\n            TimeUnit(ChronoUnit chronoUnit, String suffix, Function<Duration, Long> toUnit) {\n                this.chronoUnit = chronoUnit;\n                this.suffix = suffix;\n                this.longValue = toUnit;\n            }\n\n            public Duration parse(String value) {\n                return Duration.of(Long.parseLong(value), this.chronoUnit);\n            }\n\n            public long longValue(Duration value) {\n                return this.longValue.apply(value);\n            }\n\n            public static TimeUnit fromChronoUnit(ChronoUnit chronoUnit) {\n                if (chronoUnit == null) {\n                    return TimeUnit.MILLIS;\n                }\n                for (TimeUnit candidate : values()) {\n                    if (candidate.chronoUnit == chronoUnit) {\n                        return candidate;\n                    }\n                }\n                throw new IllegalArgumentException(\"Unknown unit \" + chronoUnit);\n            }\n\n            public static TimeUnit fromSuffix(String suffix) {\n                for (TimeUnit candidate : values()) {\n                    if (candidate.suffix.equalsIgnoreCase(suffix)) {\n                        return candidate;\n                    }\n                }\n                throw new IllegalArgumentException(\"Unknown unit '\" + suffix + \"'\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToFloatConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport static java.lang.Float.valueOf;\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\n\n/**\n * The class to convert {@link String} to {@link Float}\n *\n * @since 2.7.6\n */\npublic class StringToFloatConverter implements StringConverter<Float> {\n\n    @Override\n    public Float convert(String source) {\n        return isNotEmpty(source) ? valueOf(source) : null;\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY + 4;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToIntegerConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport static java.lang.Integer.valueOf;\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\n\n/**\n * The class to convert {@link String} to {@link Integer}\n *\n * @since 2.7.6\n */\npublic class StringToIntegerConverter implements StringConverter<Integer> {\n\n    @Override\n    public Integer convert(String source) {\n        return isNotEmpty(source) ? valueOf(source) : null;\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToLongConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport static java.lang.Long.valueOf;\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\n\n/**\n * The class to convert {@link String} to {@link Long}\n *\n * @since 2.7.6\n */\npublic class StringToLongConverter implements StringConverter<Long> {\n\n    @Override\n    public Long convert(String source) {\n        return isNotEmpty(source) ? valueOf(source) : null;\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY + 1;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToOptionalConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport java.util.Optional;\n\nimport static java.util.Optional.ofNullable;\n\n/**\n * The class to convert {@link String} to {@link Optional}\n *\n * @since 2.7.6\n */\npublic class StringToOptionalConverter implements StringConverter<Optional> {\n\n    @Override\n    public Optional convert(String source) {\n        return ofNullable(source);\n    }\n\n    @Override\n    public int getPriority() {\n        return MIN_PRIORITY;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToShortConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport static java.lang.Short.valueOf;\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\n\n/**\n * The class to convert {@link String} to {@link Short}\n *\n * @since 2.7.6\n */\npublic class StringToShortConverter implements StringConverter<Short> {\n\n    @Override\n    public Short convert(String source) {\n        return isNotEmpty(source) ? valueOf(source) : null;\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY + 2;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/StringToStringConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\n/**\n * A class to covert {@link String} to {@link String} value, just no-op\n *\n * @since 2.7.6\n */\npublic class StringToStringConverter implements StringConverter<String> {\n\n    @Override\n    public String convert(String source) {\n        return source;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/MultiValueConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Collection;\n\nimport static org.apache.dubbo.common.utils.TypeUtils.findActualTypeArgument;\n\n/**\n * An interface to convert the source-typed value to multiple value, e.g , Java array, {@link Collection} or\n * sub-interfaces\n *\n * @param <S> The source type\n * @since 2.7.6\n */\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface MultiValueConverter<S> extends Prioritized {\n\n    /**\n     * Accept the source type and target type or not\n     *\n     * @param sourceType     the source type\n     * @param multiValueType the multi-value type\n     * @return if accepted, return <code>true</code>, or <code>false</code>\n     */\n    boolean accept(Class<S> sourceType, Class<?> multiValueType);\n\n    /**\n     * Convert the source to be the multiple value\n     *\n     * @param source         the source-typed value\n     * @param multiValueType the multi-value type\n     * @param elementType    the element type\n     * @return\n     */\n    Object convert(S source, Class<?> multiValueType, Class<?> elementType);\n\n    /**\n     * Get the source type\n     *\n     * @return non-null\n     */\n    default Class<S> getSourceType() {\n        return findActualTypeArgument(getClass(), MultiValueConverter.class, 0);\n    }\n\n    /**\n     * Find the {@link MultiValueConverter} instance from {@link ExtensionLoader} with the specified source and target type\n     *\n     * @param sourceType the source type\n     * @param targetType the target type\n     * @return <code>null</code> if not found\n     * @see ExtensionLoader#getSupportedExtensionInstances()\n     * @since 2.7.8\n     * @deprecated will be removed in 3.3.0\n     */\n    @Deprecated\n    static MultiValueConverter<?> find(Class<?> sourceType, Class<?> targetType) {\n        return FrameworkModel.defaultModel()\n                .getExtensionLoader(MultiValueConverter.class)\n                .getSupportedExtensionInstances()\n                .stream()\n                .filter(converter -> converter.accept(sourceType, targetType))\n                .findFirst()\n                .orElse(null);\n    }\n\n    /**\n     * @deprecated will be removed in 3.3.0\n     */\n    @Deprecated\n    static <T> T convertIfPossible(Object source, Class<?> multiValueType, Class<?> elementType) {\n        Class<?> sourceType = source.getClass();\n        MultiValueConverter converter = find(sourceType, multiValueType);\n        if (converter != null) {\n            return (T) converter.convert(source, multiValueType, elementType);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToArrayConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.convert.Converter;\nimport org.apache.dubbo.common.convert.ConverterUtil;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.lang.reflect.Array;\n\nimport static java.lang.reflect.Array.newInstance;\n\n/**\n * The class to convert {@link String} to array-type object\n *\n * @since 2.7.6\n */\npublic class StringToArrayConverter implements StringToMultiValueConverter {\n    private ConverterUtil converterUtil;\n\n    public StringToArrayConverter(FrameworkModel frameworkModel) {\n        converterUtil = frameworkModel.getBeanFactory().getBean(ConverterUtil.class);\n    }\n\n    public boolean accept(Class<String> type, Class<?> multiValueType) {\n        if (multiValueType != null && multiValueType.isArray()) {\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public Object convert(String[] segments, int size, Class<?> targetType, Class<?> elementType) {\n\n        Class<?> componentType = targetType.getComponentType();\n\n        Converter converter = converterUtil.getConverter(String.class, componentType);\n\n        Object array = newInstance(componentType, size);\n\n        for (int i = 0; i < size; i++) {\n            Array.set(array, i, converter.convert(segments[i]));\n        }\n\n        return array;\n    }\n\n    @Override\n    public int getPriority() {\n        return MIN_PRIORITY;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToBlockingDequeConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.LinkedBlockingDeque;\n\n/**\n * The class to convert {@link String} to {@link BlockingDeque}-based value\n *\n * @since 2.7.6\n */\npublic class StringToBlockingDequeConverter extends StringToIterableConverter<BlockingDeque> {\n    public StringToBlockingDequeConverter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected BlockingDeque createMultiValue(int size, Class<?> multiValueType) {\n        return new LinkedBlockingDeque(size);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToBlockingQueueConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\n\n/**\n * The class to convert {@link String} to {@link BlockingDeque}-based value\n *\n * @since 2.7.6\n */\npublic class StringToBlockingQueueConverter extends StringToIterableConverter<BlockingQueue> {\n    public StringToBlockingQueueConverter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected BlockingQueue createMultiValue(int size, Class<?> multiValueType) {\n        return new ArrayBlockingQueue(size);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToCollectionConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\n\n/**\n * The class to convert {@link String} to {@link Collection}-based value\n *\n * @since 2.7.6\n */\npublic class StringToCollectionConverter extends StringToIterableConverter<Collection> {\n    public StringToCollectionConverter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected Collection createMultiValue(int size, Class<?> multiValueType) {\n        return new ArrayList(size);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToDequeConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayDeque;\nimport java.util.Deque;\n\n/**\n * The class to convert {@link String} to {@link Deque}-based value\n *\n * @since 2.7.6\n */\npublic class StringToDequeConverter extends StringToIterableConverter<Deque> {\n    public StringToDequeConverter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected Deque createMultiValue(int size, Class<?> multiValueType) {\n        return new ArrayDeque(size);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToIterableConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.convert.ConverterUtil;\nimport org.apache.dubbo.common.convert.StringConverter;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Collection;\nimport java.util.Optional;\n\nimport static org.apache.dubbo.common.utils.ClassUtils.getAllInterfaces;\nimport static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom;\nimport static org.apache.dubbo.common.utils.TypeUtils.findActualTypeArgument;\n\n/**\n * The class to convert {@link String} to {@link Iterable}-based value\n *\n * @since 2.7.6\n */\npublic abstract class StringToIterableConverter<T extends Iterable> implements StringToMultiValueConverter {\n    private ConverterUtil converterUtil;\n\n    public StringToIterableConverter(FrameworkModel frameworkModel) {\n        converterUtil = frameworkModel.getBeanFactory().getBean(ConverterUtil.class);\n    }\n\n    public boolean accept(Class<String> type, Class<?> multiValueType) {\n        return isAssignableFrom(getSupportedType(), multiValueType);\n    }\n\n    @Override\n    public final Object convert(String[] segments, int size, Class<?> multiValueType, Class<?> elementType) {\n\n        Optional<StringConverter> stringConverter = getStringConverter(elementType);\n\n        return stringConverter\n                .map(converter -> {\n                    T convertedObject = createMultiValue(size, multiValueType);\n\n                    if (convertedObject instanceof Collection) {\n                        Collection collection = (Collection) convertedObject;\n                        for (int i = 0; i < size; i++) {\n                            String segment = segments[i];\n                            Object element = converter.convert(segment);\n                            collection.add(element);\n                        }\n                        return collection;\n                    }\n\n                    return convertedObject;\n                })\n                .orElse(null);\n    }\n\n    protected abstract T createMultiValue(int size, Class<?> multiValueType);\n\n    protected Optional<StringConverter> getStringConverter(Class<?> elementType) {\n        StringConverter converter = (StringConverter) converterUtil.getConverter(String.class, elementType);\n        return Optional.ofNullable(converter);\n    }\n\n    protected final Class<T> getSupportedType() {\n        return findActualTypeArgument(getClass(), StringToIterableConverter.class, 0);\n    }\n\n    @Override\n    public final int getPriority() {\n        int level = getAllInterfaces(getSupportedType(), type -> isAssignableFrom(Iterable.class, type))\n                .size();\n        return MIN_PRIORITY - level;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToListConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * The class to convert {@link String} to {@link List}-based value\n *\n * @since 2.7.6\n */\npublic class StringToListConverter extends StringToIterableConverter<List> {\n    public StringToListConverter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected List createMultiValue(int size, Class<?> multiValueType) {\n        return new ArrayList(size);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToMultiValueConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\n\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\nimport static org.apache.dubbo.common.utils.StringUtils.split;\n\n/**\n * The class to convert {@link String} to multiple value object\n *\n * @see MultiValueConverter\n * @since 2.7.6\n */\npublic interface StringToMultiValueConverter extends MultiValueConverter<String> {\n\n    @Override\n    default Object convert(String source, Class<?> multiValueType, Class<?> elementType) {\n\n        if (isEmpty(source)) {\n            return null;\n        }\n\n        // split by the comma\n        String[] segments = split(source, ',');\n\n        if (ArrayUtils.isEmpty(segments)) { // If empty array, create an array with only one element\n            segments = new String[] {source};\n        }\n\n        int size = segments.length;\n\n        return convert(segments, size, multiValueType, elementType);\n    }\n\n    /**\n     * Convert the segments to multiple value object\n     *\n     * @param segments    the String array of content\n     * @param size        the size of multiple value object\n     * @param targetType  the target type\n     * @param elementType the element type\n     * @return multiple value object\n     */\n    Object convert(String[] segments, int size, Class<?> targetType, Class<?> elementType);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToNavigableSetConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.NavigableSet;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\n\n/**\n * The class to convert {@link String} to {@link SortedSet}-based value\n *\n * @since 2.7.6\n */\npublic class StringToNavigableSetConverter extends StringToIterableConverter<NavigableSet> {\n    public StringToNavigableSetConverter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected NavigableSet createMultiValue(int size, Class<?> multiValueType) {\n        return new TreeSet();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToQueueConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayDeque;\nimport java.util.Deque;\nimport java.util.Queue;\n\n/**\n * The class to convert {@link String} to {@link Deque}-based value\n *\n * @since 2.7.6\n */\npublic class StringToQueueConverter extends StringToIterableConverter<Queue> {\n    public StringToQueueConverter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected Queue createMultiValue(int size, Class<?> multiValueType) {\n        return new ArrayDeque(size);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToSetConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * The class to convert {@link String} to {@link Set}-based value\n *\n * @since 2.7.6\n */\npublic class StringToSetConverter extends StringToIterableConverter<Set> {\n    public StringToSetConverter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected Set createMultiValue(int size, Class<?> multiValueType) {\n        return new HashSet(size);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToSortedSetConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.SortedSet;\nimport java.util.TreeSet;\n\n/**\n * The class to convert {@link String} to {@link SortedSet}-based value\n *\n * @since 2.7.6\n */\npublic class StringToSortedSetConverter extends StringToIterableConverter<SortedSet> {\n    public StringToSortedSetConverter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected SortedSet createMultiValue(int size, Class<?> multiValueType) {\n        return new TreeSet();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/StringToTransferQueueConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.LinkedTransferQueue;\nimport java.util.concurrent.TransferQueue;\n\n/**\n * The class to convert {@link String} to {@link TransferQueue}-based value\n *\n * @since 2.7.6\n */\npublic class StringToTransferQueueConverter extends StringToIterableConverter<TransferQueue> {\n    public StringToTransferQueueConverter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected TransferQueue createMultiValue(int size, Class<?> multiValueType) {\n        return new LinkedTransferQueue();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/deploy/AbstractDeployer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.deploy;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_MONITOR_EXCEPTION;\nimport static org.apache.dubbo.common.deploy.DeployState.COMPLETION;\nimport static org.apache.dubbo.common.deploy.DeployState.FAILED;\nimport static org.apache.dubbo.common.deploy.DeployState.PENDING;\nimport static org.apache.dubbo.common.deploy.DeployState.STARTED;\nimport static org.apache.dubbo.common.deploy.DeployState.STARTING;\nimport static org.apache.dubbo.common.deploy.DeployState.STOPPED;\nimport static org.apache.dubbo.common.deploy.DeployState.STOPPING;\n\npublic abstract class AbstractDeployer<E extends ScopeModel> implements Deployer<E> {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractDeployer.class);\n\n    private volatile DeployState state = PENDING;\n\n    private volatile Throwable lastError;\n\n    protected volatile boolean initialized = false;\n\n    protected List<DeployListener<E>> listeners = new CopyOnWriteArrayList<>();\n\n    private E scopeModel;\n\n    public AbstractDeployer(E scopeModel) {\n        this.scopeModel = scopeModel;\n    }\n\n    @Override\n    public boolean isPending() {\n        return state == PENDING;\n    }\n\n    @Override\n    public boolean isRunning() {\n        return state == STARTING || state == STARTED || state == COMPLETION;\n    }\n\n    @Override\n    public boolean isStarted() {\n        return state == STARTED || state == COMPLETION;\n    }\n\n    @Override\n    public boolean isCompletion() {\n        return state == COMPLETION;\n    }\n\n    @Override\n    public boolean isStarting() {\n        return state == STARTING;\n    }\n\n    @Override\n    public boolean isStopping() {\n        return state == STOPPING;\n    }\n\n    @Override\n    public boolean isStopped() {\n        return state == STOPPED;\n    }\n\n    @Override\n    public boolean isFailed() {\n        return state == FAILED;\n    }\n\n    @Override\n    public DeployState getState() {\n        return state;\n    }\n\n    @Override\n    public void addDeployListener(DeployListener<E> listener) {\n        listeners.add(listener);\n    }\n\n    @Override\n    public void removeDeployListener(DeployListener<E> listener) {\n        listeners.remove(listener);\n    }\n\n    public void setPending() {\n        this.state = PENDING;\n    }\n\n    protected void setStarting() {\n        this.state = STARTING;\n        for (DeployListener<E> listener : listeners) {\n            try {\n                listener.onStarting(scopeModel);\n            } catch (Throwable e) {\n                logger.error(\n                        COMMON_MONITOR_EXCEPTION,\n                        \"\",\n                        \"\",\n                        getIdentifier() + \" an exception occurred when handle starting event\",\n                        e);\n            }\n        }\n    }\n\n    protected void setStarted() {\n        this.state = STARTED;\n        for (DeployListener<E> listener : listeners) {\n            try {\n                listener.onStarted(scopeModel);\n            } catch (Throwable e) {\n                logger.error(\n                        COMMON_MONITOR_EXCEPTION,\n                        \"\",\n                        \"\",\n                        getIdentifier() + \" an exception occurred when handle started event\",\n                        e);\n            }\n        }\n    }\n\n    protected void setCompletion() {\n        this.state = COMPLETION;\n        for (DeployListener<E> listener : listeners) {\n            try {\n                listener.onCompletion(scopeModel);\n            } catch (Throwable e) {\n                logger.error(\n                        COMMON_MONITOR_EXCEPTION,\n                        \"\",\n                        \"\",\n                        getIdentifier() + \" an exception occurred when handle completion event\",\n                        e);\n            }\n        }\n    }\n\n    protected void setStopping() {\n        this.state = STOPPING;\n        for (DeployListener<E> listener : listeners) {\n            try {\n                listener.onStopping(scopeModel);\n            } catch (Throwable e) {\n                logger.error(\n                        COMMON_MONITOR_EXCEPTION,\n                        \"\",\n                        \"\",\n                        getIdentifier() + \" an exception occurred when handle stopping event\",\n                        e);\n            }\n        }\n    }\n\n    protected void setStopped() {\n        this.state = STOPPED;\n        for (DeployListener<E> listener : listeners) {\n            try {\n                listener.onStopped(scopeModel);\n            } catch (Throwable e) {\n                logger.error(\n                        COMMON_MONITOR_EXCEPTION,\n                        \"\",\n                        \"\",\n                        getIdentifier() + \" an exception occurred when handle stopped event\",\n                        e);\n            }\n        }\n    }\n\n    protected void setFailed(Throwable error) {\n        this.state = FAILED;\n        this.lastError = error;\n        for (DeployListener<E> listener : listeners) {\n            try {\n                listener.onFailure(scopeModel, error);\n            } catch (Throwable e) {\n                logger.error(\n                        COMMON_MONITOR_EXCEPTION,\n                        \"\",\n                        \"\",\n                        getIdentifier() + \" an exception occurred when handle failed event\",\n                        e);\n            }\n        }\n    }\n\n    @Override\n    public Throwable getError() {\n        return lastError;\n    }\n\n    public boolean isInitialized() {\n        return initialized;\n    }\n\n    protected String getIdentifier() {\n        return scopeModel.getDesc();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ApplicationDeployListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.deploy;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\n/**\n * Listen for Dubbo application deployment events\n */\n@SPI(scope = ExtensionScope.APPLICATION)\npublic interface ApplicationDeployListener extends DeployListener<ApplicationModel> {\n\n    default void onModuleStarted(ApplicationModel applicationModel) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ApplicationDeployer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.deploy;\n\nimport org.apache.dubbo.common.config.ReferenceCache;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.concurrent.Future;\n\n/**\n * initialize and start application instance\n */\npublic interface ApplicationDeployer extends Deployer<ApplicationModel> {\n\n    /**\n     * Initialize the component\n     */\n    void initialize() throws IllegalStateException;\n\n    /**\n     * Starts the component.\n     * @return\n     */\n    Future start() throws IllegalStateException;\n\n    /**\n     * Stops the component.\n     */\n    void stop() throws IllegalStateException;\n\n    Future getStartFuture();\n\n    /**\n     * Register application instance and start internal services\n     */\n    void prepareApplicationInstance(ModuleModel moduleModel);\n\n    void exportMetadataService();\n\n    void registerServiceInstance();\n\n    /**\n     * Register application instance and start internal services\n     */\n    void prepareInternalModule();\n\n    /**\n     * Pre-processing before destroy model\n     */\n    void preDestroy();\n\n    /**\n     * Post-processing after destroy model\n     */\n    void postDestroy();\n\n    /**\n     * Indicates that the Application is initialized or not.\n     */\n    boolean isInitialized();\n\n    ApplicationModel getApplicationModel();\n\n    ReferenceCache getReferenceCache();\n\n    /**\n     * Whether start in background, do not await finish\n     */\n    boolean isBackground();\n\n    /**\n     * check all module state and update application state\n     */\n    void checkState(ModuleModel moduleModel, DeployState moduleState);\n\n    /**\n     * module state changed callbacks\n     */\n    void notifyModuleChanged(ModuleModel moduleModel, DeployState state);\n\n    /**\n     * refresh service instance\n     */\n    void refreshServiceInstance();\n\n    /**\n     * Increase the count of service update threads.\n     * NOTE: should call ${@link ApplicationDeployer#decreaseServiceRefreshCount()} after update finished\n     */\n    void increaseServiceRefreshCount();\n\n    /**\n     * Decrease the count of service update threads\n     */\n    void decreaseServiceRefreshCount();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.deploy;\n\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\npublic interface DeployListener<E extends ScopeModel> {\n    /**\n     * Useful to inject some configuration like MetricsConfig, RegistryConfig, etc.\n     */\n    void onInitialize(E scopeModel);\n\n    /**\n     * Triggered before starting module.\n     */\n    void onStarting(E scopeModel);\n\n    /**\n     * Triggered before registering and exposing the service.\n     */\n    void onStarted(E scopeModel);\n\n    /**\n     * Triggered after deployer startup is complete.\n     */\n    default void onCompletion(E scopeModel) {}\n\n    /**\n     * Triggered before the app is destroyed,\n     * can do some customized things before offline the service and destroy reference.\n     */\n    void onStopping(E scopeModel);\n\n    /**\n     * Triggered after the application is destroyed,\n     * can do some customized things after the service is offline and the reference is destroyed.\n     */\n    void onStopped(E scopeModel);\n\n    /**\n     * Useful to do something when deployer was failed.\n     */\n    void onFailure(E scopeModel, Throwable cause);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployListenerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.deploy;\n\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\npublic class DeployListenerAdapter<E extends ScopeModel> implements DeployListener<E> {\n    @Override\n    public void onInitialize(E scopeModel) {}\n\n    @Override\n    public void onStarting(E scopeModel) {}\n\n    @Override\n    public void onStarted(E scopeModel) {}\n\n    @Override\n    public void onCompletion(E scopeModel) {}\n\n    @Override\n    public void onStopping(E scopeModel) {}\n\n    @Override\n    public void onStopped(E scopeModel) {}\n\n    @Override\n    public void onFailure(E scopeModel, Throwable cause) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/deploy/DeployState.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.deploy;\n\n/**\n * Deploy state enum\n */\npublic enum DeployState {\n    /**\n     * Unknown state\n     */\n    UNKNOWN,\n\n    /**\n     * Pending, wait for start\n     */\n    PENDING,\n\n    /**\n     * Starting\n     */\n    STARTING,\n\n    /**\n     * Started\n     */\n    STARTED,\n\n    /**\n     * Completion\n     */\n    COMPLETION,\n\n    /**\n     * Stopping\n     */\n    STOPPING,\n\n    /**\n     * Stopped\n     */\n    STOPPED,\n\n    /**\n     * Failed\n     */\n    FAILED\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/deploy/Deployer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.deploy;\n\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.concurrent.Future;\n\npublic interface Deployer<E extends ScopeModel> {\n\n    /**\n     * Initialize the component\n     */\n    void initialize() throws IllegalStateException;\n\n    /**\n     * Starts the component.\n     * @return\n     */\n    Future start() throws IllegalStateException;\n\n    /**\n     * Stops the component.\n     */\n    void stop() throws IllegalStateException;\n\n    /**\n     * @return true if the component is added and waiting to start\n     */\n    boolean isPending();\n\n    /**\n     * @return true if the component is starting or has been started.\n     */\n    boolean isRunning();\n\n    /**\n     * @return true if the component has been started.\n     * @see #start()\n     * @see #isStarting()\n     */\n    boolean isStarted();\n\n    boolean isCompletion();\n\n    /**\n     * @return true if the component is starting.\n     * @see #isStarted()\n     */\n    boolean isStarting();\n\n    /**\n     * @return true if the component is stopping.\n     * @see #isStopped()\n     */\n    boolean isStopping();\n\n    /**\n     * @return true if the component is stopping.\n     * @see #isStopped()\n     */\n    boolean isStopped();\n\n    /**\n     * @return true if the component has failed to start or has failed to stop.\n     */\n    boolean isFailed();\n\n    /**\n     * @return current state\n     */\n    DeployState getState();\n\n    void addDeployListener(DeployListener<E> listener);\n\n    void removeDeployListener(DeployListener<E> listener);\n\n    Throwable getError();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ModuleDeployListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.deploy;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\n/**\n * Module deploy listener\n */\n@SPI(scope = ExtensionScope.MODULE)\npublic interface ModuleDeployListener extends DeployListener<ModuleModel> {}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ModuleDeployer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.deploy;\n\nimport org.apache.dubbo.common.config.ReferenceCache;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.concurrent.Future;\n\n/**\n * Export/refer services of module\n */\npublic interface ModuleDeployer extends Deployer<ModuleModel> {\n\n    void initialize() throws IllegalStateException;\n\n    Future start() throws IllegalStateException;\n\n    Future getStartFuture();\n\n    void stop() throws IllegalStateException;\n\n    void preDestroy() throws IllegalStateException;\n\n    void postDestroy() throws IllegalStateException;\n\n    boolean isInitialized();\n\n    ReferenceCache getReferenceCache();\n\n    void registerServiceInstance();\n\n    void prepare();\n\n    void setPending();\n\n    /**\n     * Whether start in background, do not await finish\n     */\n    boolean isBackground();\n\n    boolean hasRegistryInteraction();\n\n    ApplicationDeployer getApplicationDeployer();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/Activate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Activate. This annotation is useful for automatically activate certain extensions with the given criteria,\n * for examples: <code>@Activate</code> can be used to load certain <code>Filter</code> extension when there are\n * multiple implementations.\n * <ol>\n * <li>{@link Activate#group()} specifies group criteria. Framework SPI defines the valid group values.\n * <li>{@link Activate#value()} specifies parameter key in {@link URL} criteria.\n * </ol>\n * SPI provider can call {@link ExtensionLoader#getActivateExtension(URL, String, String)} to find out all activated\n * extensions with the given criteria.\n *\n * @see SPI\n * @see URL\n * @see ExtensionLoader\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE, ElementType.METHOD})\npublic @interface Activate {\n    /**\n     * Activate the current extension when one of the groups matches. The group passed into\n     * {@link ExtensionLoader#getActivateExtension(URL, String, String)} will be used for matching.\n     *\n     * @return group names to match\n     * @see ExtensionLoader#getActivateExtension(URL, String, String)\n     */\n    String[] group() default {};\n\n    /**\n     * Activate the current extension when the specified keys appear in the URL's parameters.\n     * <p>\n     * For example, given <code>@Activate(\"cache, validation\")</code>, the current extension will be return only when\n     * there's either <code>cache</code> or <code>validation</code> key appeared in the URL's parameters.\n     * </p>\n     *\n     * @return URL parameter keys\n     * @see ExtensionLoader#getActivateExtension(URL, String)\n     * @see ExtensionLoader#getActivateExtension(URL, String, String)\n     */\n    String[] value() default {};\n\n    /**\n     * Relative ordering info, optional\n     * Deprecated since 2.7.0\n     *\n     * @return extension list which should be put before the current one\n     */\n    @Deprecated\n    String[] before() default {};\n\n    /**\n     * Relative ordering info, optional\n     * Deprecated since 2.7.0\n     *\n     * @return extension list which should be put after the current one\n     */\n    @Deprecated\n    String[] after() default {};\n\n    /**\n     * Absolute ordering info, optional\n     *\n     * Ascending order, smaller values will be in the front of the list.\n     *\n     * @return absolute ordering info\n     */\n    int order() default 0;\n\n    /**\n     * Activate loadClass when the current extension when the specified className all match\n     * @return className names to all match\n     */\n    String[] onClass() default {};\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/Adaptive.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Provide helpful information for {@link ExtensionLoader} to inject dependency extension instance.\n *\n * @see ExtensionLoader\n * @see URL\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE, ElementType.METHOD})\npublic @interface Adaptive {\n    /**\n     * Decide which target extension to be injected. The name of the target extension is decided by the parameter passed\n     * in the URL, and the parameter names are given by this method.\n     * <p>\n     * If the specified parameters are not found from {@link URL}, then the default extension will be used for\n     * dependency injection (specified in its interface's {@link SPI}).\n     * <p>\n     * For example, given <code>String[] {\"key1\", \"key2\"}</code>:\n     * <ol>\n     * <li>find parameter 'key1' in URL, use its value as the extension's name</li>\n     * <li>try 'key2' for extension's name if 'key1' is not found (or its value is empty) in URL</li>\n     * <li>use default extension if 'key2' doesn't exist either</li>\n     * <li>otherwise, throw {@link IllegalStateException}</li>\n     * </ol>\n     * If the parameter names are empty, then a default parameter name is generated from interface's\n     * class name with the rule: divide classname from capital char into several parts, and separate the parts with\n     * dot '.', for example, for {@code org.apache.dubbo.xxx.YyyInvokerWrapper}, the generated name is\n     * <code>String[] {\"yyy.invoker.wrapper\"}</code>.\n     *\n     * @return parameter names in URL\n     */\n    String[] value() default {};\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGenerator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\n/**\n * Code generator for Adaptive class\n */\npublic class AdaptiveClassCodeGenerator {\n\n    private static final Logger logger = LoggerFactory.getLogger(AdaptiveClassCodeGenerator.class);\n\n    private static final String CLASS_NAME_INVOCATION = \"org.apache.dubbo.rpc.Invocation\";\n\n    private static final String CODE_PACKAGE = \"package %s;\\n\";\n\n    private static final String CODE_IMPORTS = \"import %s;\\n\";\n\n    private static final String CODE_CLASS_DECLARATION = \"public class %s$Adaptive implements %s {\\n\";\n\n    private static final String CODE_METHOD_DECLARATION = \"public %s %s(%s) %s {\\n%s}\\n\";\n\n    private static final String CODE_METHOD_ARGUMENT = \"%s arg%d\";\n\n    private static final String CODE_METHOD_THROWS = \"throws %s\";\n\n    private static final String CODE_UNSUPPORTED =\n            \"throw new UnsupportedOperationException(\\\"The method %s of interface %s is not adaptive method!\\\");\\n\";\n\n    private static final String CODE_URL_NULL_CHECK =\n            \"if (arg%d == null) throw new IllegalArgumentException(\\\"url == null\\\");\\n%s url = arg%d;\\n\";\n\n    private static final String CODE_EXT_NAME_ASSIGNMENT = \"String extName = %s;\\n\";\n\n    private static final String CODE_EXT_NAME_NULL_CHECK = \"if(extName == null) \"\n            + \"throw new IllegalStateException(\\\"Failed to get extension (%s) name from url (\\\" + url.toString() + \\\") use keys(%s)\\\");\\n\";\n\n    private static final String CODE_INVOCATION_ARGUMENT_NULL_CHECK =\n            \"if (arg%d == null) throw new IllegalArgumentException(\\\"invocation == null\\\"); \"\n                    + \"String methodName = arg%d.getMethodName();\\n\";\n\n    private static final String CODE_SCOPE_MODEL_ASSIGNMENT =\n            \"ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), %s.class);\\n\";\n    private static final String CODE_EXTENSION_ASSIGNMENT =\n            \"%s extension = (%<s)scopeModel.getExtensionLoader(%s.class).getExtension(extName);\\n\";\n\n    private static final String CODE_EXTENSION_METHOD_INVOKE_ARGUMENT = \"arg%d\";\n\n    private final Class<?> type;\n\n    private final String defaultExtName;\n\n    public AdaptiveClassCodeGenerator(Class<?> type, String defaultExtName) {\n        this.type = type;\n        this.defaultExtName = defaultExtName;\n    }\n\n    /**\n     * test if given type has at least one method annotated with <code>Adaptive</code>\n     */\n    private boolean hasAdaptiveMethod() {\n        return Arrays.stream(type.getMethods()).anyMatch(m -> m.isAnnotationPresent(Adaptive.class));\n    }\n\n    /**\n     * generate and return class code\n     */\n    public String generate() {\n        return this.generate(false);\n    }\n\n    /**\n     * generate and return class code\n     * @param sort - whether sort methods\n     */\n    public String generate(boolean sort) {\n        // no need to generate adaptive class since there's no adaptive method found.\n        if (!hasAdaptiveMethod()) {\n            throw new IllegalStateException(\"No adaptive method exist on extension \" + type.getName()\n                    + \", refuse to create the adaptive class!\");\n        }\n\n        StringBuilder code = new StringBuilder();\n        code.append(generatePackageInfo());\n        code.append(generateImports());\n        code.append(generateClassDeclaration());\n\n        Method[] methods = type.getMethods();\n        if (sort) {\n            Arrays.sort(methods, Comparator.comparing(Method::toString));\n        }\n        for (Method method : methods) {\n            code.append(generateMethod(method));\n        }\n        code.append('}');\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(code.toString());\n        }\n        return code.toString();\n    }\n\n    /**\n     * generate package info\n     */\n    private String generatePackageInfo() {\n        return String.format(CODE_PACKAGE, type.getPackage().getName());\n    }\n\n    /**\n     * generate imports\n     */\n    private String generateImports() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(String.format(CODE_IMPORTS, ScopeModel.class.getName()));\n        builder.append(String.format(CODE_IMPORTS, ScopeModelUtil.class.getName()));\n        return builder.toString();\n    }\n\n    /**\n     * generate class declaration\n     */\n    private String generateClassDeclaration() {\n        return String.format(CODE_CLASS_DECLARATION, type.getSimpleName(), type.getCanonicalName());\n    }\n\n    /**\n     * generate method not annotated with Adaptive with throwing unsupported exception\n     */\n    private String generateUnsupported(Method method) {\n        return String.format(CODE_UNSUPPORTED, method, type.getName());\n    }\n\n    /**\n     * get index of parameter with type URL\n     */\n    private int getUrlTypeIndex(Method method) {\n        int urlTypeIndex = -1;\n        Class<?>[] pts = method.getParameterTypes();\n        for (int i = 0; i < pts.length; ++i) {\n            if (pts[i].equals(URL.class)) {\n                urlTypeIndex = i;\n                break;\n            }\n        }\n        return urlTypeIndex;\n    }\n\n    /**\n     * generate method declaration\n     */\n    private String generateMethod(Method method) {\n        String methodReturnType = method.getReturnType().getCanonicalName();\n        String methodName = method.getName();\n        String methodContent = generateMethodContent(method);\n        String methodArgs = generateMethodArguments(method);\n        String methodThrows = generateMethodThrows(method);\n        return String.format(\n                CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent);\n    }\n\n    /**\n     * generate method arguments\n     */\n    private String generateMethodArguments(Method method) {\n        Class<?>[] pts = method.getParameterTypes();\n        return IntStream.range(0, pts.length)\n                .mapToObj(i -> String.format(CODE_METHOD_ARGUMENT, pts[i].getCanonicalName(), i))\n                .collect(Collectors.joining(\", \"));\n    }\n\n    /**\n     * generate method throws\n     */\n    private String generateMethodThrows(Method method) {\n        Class<?>[] ets = method.getExceptionTypes();\n        if (ets.length > 0) {\n            String list = Arrays.stream(ets).map(Class::getCanonicalName).collect(Collectors.joining(\", \"));\n            return String.format(CODE_METHOD_THROWS, list);\n        } else {\n            return \"\";\n        }\n    }\n\n    /**\n     * generate method URL argument null check\n     */\n    private String generateUrlNullCheck(int index) {\n        return String.format(CODE_URL_NULL_CHECK, index, URL.class.getName(), index);\n    }\n\n    /**\n     * generate method content\n     */\n    private String generateMethodContent(Method method) {\n        Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);\n        if (adaptiveAnnotation == null) {\n            return generateUnsupported(method);\n        }\n        StringBuilder code = new StringBuilder(512);\n        int urlTypeIndex = getUrlTypeIndex(method);\n\n        // found parameter in URL type\n        if (urlTypeIndex != -1) {\n            // Null Point check\n            code.append(generateUrlNullCheck(urlTypeIndex));\n        } else {\n            // did not find parameter in URL type\n            code.append(generateUrlAssignmentIndirectly(method));\n        }\n\n        String[] value = getMethodAdaptiveValue(adaptiveAnnotation);\n\n        boolean hasInvocation = hasInvocationArgument(method);\n\n        code.append(generateInvocationArgumentNullCheck(method));\n\n        code.append(generateExtNameAssignment(value, hasInvocation));\n        // check extName == null?\n        code.append(generateExtNameNullCheck(value));\n\n        code.append(generateScopeModelAssignment());\n        code.append(generateExtensionAssignment());\n\n        // return statement\n        code.append(generateReturnAndInvocation(method));\n\n        return code.toString();\n    }\n\n    /**\n     * generate code for variable extName null check\n     */\n    private String generateExtNameNullCheck(String[] value) {\n        return String.format(CODE_EXT_NAME_NULL_CHECK, type.getName(), Arrays.toString(value));\n    }\n\n    /**\n     * generate extName assignment code\n     */\n    private String generateExtNameAssignment(String[] value, boolean hasInvocation) {\n        // TODO: refactor it\n        String getNameCode = null;\n        for (int i = value.length - 1; i >= 0; --i) {\n            if (i == value.length - 1) {\n                if (null != defaultExtName) {\n                    if (!CommonConstants.PROTOCOL_KEY.equals(value[i])) {\n                        if (hasInvocation) {\n                            getNameCode = String.format(\n                                    \"url.getMethodParameter(methodName, \\\"%s\\\", \\\"%s\\\")\", value[i], defaultExtName);\n                        } else {\n                            getNameCode = String.format(\"url.getParameter(\\\"%s\\\", \\\"%s\\\")\", value[i], defaultExtName);\n                        }\n                    } else {\n                        getNameCode = String.format(\n                                \"( url.getProtocol() == null ? \\\"%s\\\" : url.getProtocol() )\", defaultExtName);\n                    }\n                } else {\n                    if (!CommonConstants.PROTOCOL_KEY.equals(value[i])) {\n                        if (hasInvocation) {\n                            getNameCode = String.format(\n                                    \"url.getMethodParameter(methodName, \\\"%s\\\", \\\"%s\\\")\", value[i], defaultExtName);\n                        } else {\n                            getNameCode = String.format(\"url.getParameter(\\\"%s\\\")\", value[i]);\n                        }\n                    } else {\n                        getNameCode = \"url.getProtocol()\";\n                    }\n                }\n            } else {\n                if (!CommonConstants.PROTOCOL_KEY.equals(value[i])) {\n                    if (hasInvocation) {\n                        getNameCode = String.format(\n                                \"url.getMethodParameter(methodName, \\\"%s\\\", \\\"%s\\\")\", value[i], defaultExtName);\n                    } else {\n                        getNameCode = String.format(\"url.getParameter(\\\"%s\\\", %s)\", value[i], getNameCode);\n                    }\n                } else {\n                    getNameCode = String.format(\"url.getProtocol() == null ? (%s) : url.getProtocol()\", getNameCode);\n                }\n            }\n        }\n\n        return String.format(CODE_EXT_NAME_ASSIGNMENT, getNameCode);\n    }\n\n    /**\n     * @return\n     */\n    private String generateScopeModelAssignment() {\n        return String.format(CODE_SCOPE_MODEL_ASSIGNMENT, type.getName());\n    }\n\n    private String generateExtensionAssignment() {\n        return String.format(CODE_EXTENSION_ASSIGNMENT, type.getName(), type.getName());\n    }\n\n    /**\n     * generate method invocation statement and return it if necessary\n     */\n    private String generateReturnAndInvocation(Method method) {\n        String returnStatement = method.getReturnType().equals(void.class) ? \"\" : \"return \";\n\n        String args = IntStream.range(0, method.getParameters().length)\n                .mapToObj(i -> String.format(CODE_EXTENSION_METHOD_INVOKE_ARGUMENT, i))\n                .collect(Collectors.joining(\", \"));\n\n        return returnStatement + String.format(\"extension.%s(%s);\\n\", method.getName(), args);\n    }\n\n    /**\n     * test if method has argument of type <code>Invocation</code>\n     */\n    private boolean hasInvocationArgument(Method method) {\n        Class<?>[] pts = method.getParameterTypes();\n        return Arrays.stream(pts).anyMatch(p -> CLASS_NAME_INVOCATION.equals(p.getName()));\n    }\n\n    /**\n     * generate code to test argument of type <code>Invocation</code> is null\n     */\n    private String generateInvocationArgumentNullCheck(Method method) {\n        Class<?>[] pts = method.getParameterTypes();\n        return IntStream.range(0, pts.length)\n                .filter(i -> CLASS_NAME_INVOCATION.equals(pts[i].getName()))\n                .mapToObj(i -> String.format(CODE_INVOCATION_ARGUMENT_NULL_CHECK, i, i))\n                .findFirst()\n                .orElse(\"\");\n    }\n\n    /**\n     * get value of adaptive annotation or if empty return splitted simple name\n     */\n    private String[] getMethodAdaptiveValue(Adaptive adaptiveAnnotation) {\n        String[] value = adaptiveAnnotation.value();\n        // value is not set, use the value generated from class name as the key\n        if (value.length == 0) {\n            String splitName = StringUtils.camelToSplitName(type.getSimpleName(), \".\");\n            value = new String[] {splitName};\n        }\n        return value;\n    }\n\n    /**\n     * get parameter with type <code>URL</code> from method parameter:\n     * <p>\n     * test if parameter has method which returns type <code>URL</code>\n     * <p>\n     * if not found, throws IllegalStateException\n     */\n    private String generateUrlAssignmentIndirectly(Method method) {\n        Class<?>[] pts = method.getParameterTypes();\n\n        Map<String, Integer> getterReturnUrl = new HashMap<>();\n        // find URL getter method\n        for (int i = 0; i < pts.length; ++i) {\n            for (Method m : pts[i].getMethods()) {\n                String name = m.getName();\n                if ((name.startsWith(\"get\") || name.length() > 3)\n                        && Modifier.isPublic(m.getModifiers())\n                        && !Modifier.isStatic(m.getModifiers())\n                        && m.getParameterTypes().length == 0\n                        && m.getReturnType() == URL.class) {\n                    getterReturnUrl.put(name, i);\n                }\n            }\n        }\n\n        if (getterReturnUrl.size() <= 0) {\n            // getter method not found, throw\n            throw new IllegalStateException(\"Failed to create adaptive class for interface \" + type.getName()\n                    + \": not found url parameter or url attribute in parameters of method \" + method.getName());\n        }\n\n        Integer index = getterReturnUrl.get(\"getUrl\");\n        if (index != null) {\n            return generateGetUrlNullCheck(index, pts[index], \"getUrl\");\n        } else {\n            Map.Entry<String, Integer> entry =\n                    getterReturnUrl.entrySet().iterator().next();\n            return generateGetUrlNullCheck(entry.getValue(), pts[entry.getValue()], entry.getKey());\n        }\n    }\n\n    /**\n     * 1, test if argi is null\n     * 2, test if argi.getXX() returns null\n     * 3, assign url with argi.getXX()\n     */\n    private String generateGetUrlNullCheck(int index, Class<?> type, String method) {\n        // Null point check\n        StringBuilder code = new StringBuilder();\n        code.append(String.format(\n                \"if (arg%d == null) throw new IllegalArgumentException(\\\"%s argument == null\\\");\\n\",\n                index, type.getName()));\n        code.append(String.format(\n                \"if (arg%d.%s() == null) throw new IllegalArgumentException(\\\"%s argument %s() == null\\\");\\n\",\n                index, method, type.getName(), method));\n\n        code.append(String.format(\"%s url = arg%d.%s();\\n\", URL.class.getName(), index, method));\n        return code.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/DisableInject.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE, ElementType.METHOD})\npublic @interface DisableInject {}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/DubboInternalLoadingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n/**\n * Dubbo internal {@link LoadingStrategy}\n *\n * @since 2.7.7\n */\npublic class DubboInternalLoadingStrategy implements LoadingStrategy {\n\n    @Override\n    public String directory() {\n        return \"META-INF/dubbo/internal/\";\n    }\n\n    @Override\n    public int getPriority() {\n        return MAX_PRIORITY;\n    }\n\n    @Override\n    public String getName() {\n        return \"DUBBO_INTERNAL\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/DubboLoadingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n/**\n * Dubbo {@link LoadingStrategy}\n *\n * @since 2.7.7\n */\npublic class DubboLoadingStrategy implements LoadingStrategy {\n\n    @Override\n    public String directory() {\n        return \"META-INF/dubbo/\";\n    }\n\n    @Override\n    public boolean overridden() {\n        return true;\n    }\n\n    @Override\n    public int getPriority() {\n        return NORMAL_PRIORITY;\n    }\n\n    @Override\n    public String getName() {\n        return \"DUBBO\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionAccessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Uniform accessor for extension\n */\npublic interface ExtensionAccessor {\n\n    ExtensionDirector getExtensionDirector();\n\n    default <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        return getExtensionDirector().getExtensionLoader(type);\n    }\n\n    default <T> T getExtension(Class<T> type, String name) {\n        ExtensionLoader<T> extensionLoader = getExtensionLoader(type);\n        return extensionLoader != null ? extensionLoader.getExtension(name) : null;\n    }\n\n    default <T> T getAdaptiveExtension(Class<T> type) {\n        ExtensionLoader<T> extensionLoader = getExtensionLoader(type);\n        return extensionLoader != null ? extensionLoader.getAdaptiveExtension() : null;\n    }\n\n    default <T> T getDefaultExtension(Class<T> type) {\n        ExtensionLoader<T> extensionLoader = getExtensionLoader(type);\n        return extensionLoader != null ? extensionLoader.getDefaultExtension() : null;\n    }\n\n    default <T> List<T> getActivateExtensions(Class<T> type) {\n        ExtensionLoader<T> extensionLoader = getExtensionLoader(type);\n        return extensionLoader != null ? extensionLoader.getActivateExtensions() : Collections.emptyList();\n    }\n\n    default <T> T getFirstActivateExtension(Class<T> type) {\n        ExtensionLoader<T> extensionLoader = getExtensionLoader(type);\n        if (extensionLoader == null) {\n            throw new IllegalArgumentException(\"ExtensionLoader for [\" + type + \"] is not found\");\n        }\n        List<T> extensions = extensionLoader.getActivateExtensions();\n        if (extensions.isEmpty()) {\n            throw new IllegalArgumentException(\"No activate extensions for [\" + type + \"] found\");\n        }\n        return extensions.get(0);\n    }\n\n    default Set<String> getSupportedExtensions(Class<?> type) {\n        ExtensionLoader<?> extensionLoader = getExtensionLoader(type);\n        return extensionLoader != null ? extensionLoader.getSupportedExtensions() : Collections.emptySet();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionAccessorAware.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n/**\n * SPI extension can implement this aware interface to obtain appropriate {@link ExtensionAccessor} instance.\n */\npublic interface ExtensionAccessorAware {\n\n    void setExtensionAccessor(final ExtensionAccessor extensionAccessor);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * ExtensionDirector is a scoped extension loader manager.\n *\n * <p></p>\n * <p>ExtensionDirector supports multiple levels, and the child can inherit the parent's extension instances. </p>\n * <p>The way to find and create an extension instance is similar to Java classloader.</p>\n */\npublic class ExtensionDirector implements ExtensionAccessor {\n\n    private final ConcurrentMap<Class<?>, ExtensionLoader<?>> extensionLoadersMap = new ConcurrentHashMap<>(64);\n    private final ConcurrentMap<Class<?>, ExtensionScope> extensionScopeMap = new ConcurrentHashMap<>(64);\n    private final ExtensionDirector parent;\n    private final ExtensionScope scope;\n    private final List<ExtensionPostProcessor> extensionPostProcessors = new ArrayList<>();\n    private final ScopeModel scopeModel;\n    private final AtomicBoolean destroyed = new AtomicBoolean();\n\n    public ExtensionDirector(ExtensionDirector parent, ExtensionScope scope, ScopeModel scopeModel) {\n        this.parent = parent;\n        this.scope = scope;\n        this.scopeModel = scopeModel;\n    }\n\n    public void addExtensionPostProcessor(ExtensionPostProcessor processor) {\n        if (!this.extensionPostProcessors.contains(processor)) {\n            this.extensionPostProcessors.add(processor);\n        }\n    }\n\n    public List<ExtensionPostProcessor> getExtensionPostProcessors() {\n        return extensionPostProcessors;\n    }\n\n    @Override\n    public ExtensionDirector getExtensionDirector() {\n        return this;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        checkDestroyed();\n        if (type == null) {\n            throw new IllegalArgumentException(\"Extension type == null\");\n        }\n        if (!type.isInterface()) {\n            throw new IllegalArgumentException(\"Extension type (\" + type + \") is not an interface!\");\n        }\n        if (!withExtensionAnnotation(type)) {\n            throw new IllegalArgumentException(\"Extension type (\" + type\n                    + \") is not an extension, because it is NOT annotated with @\" + SPI.class.getSimpleName() + \"!\");\n        }\n\n        // 1. find in local cache\n        ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);\n\n        ExtensionScope scope = extensionScopeMap.get(type);\n        if (scope == null) {\n            SPI annotation = type.getAnnotation(SPI.class);\n            scope = annotation.scope();\n            extensionScopeMap.put(type, scope);\n        }\n\n        if (loader == null && scope == ExtensionScope.SELF) {\n            // create an instance in self scope\n            loader = createExtensionLoader0(type);\n        }\n\n        // 2. find in parent\n        if (loader == null) {\n            if (this.parent != null) {\n                loader = this.parent.getExtensionLoader(type);\n            }\n        }\n\n        // 3. create it\n        if (loader == null) {\n            loader = createExtensionLoader(type);\n        }\n\n        return loader;\n    }\n\n    private <T> ExtensionLoader<T> createExtensionLoader(Class<T> type) {\n        ExtensionLoader<T> loader = null;\n        if (isScopeMatched(type)) {\n            // if scope is matched, just create it\n            loader = createExtensionLoader0(type);\n        }\n        return loader;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T> ExtensionLoader<T> createExtensionLoader0(Class<T> type) {\n        checkDestroyed();\n        ExtensionLoader<T> loader;\n        extensionLoadersMap.putIfAbsent(type, new ExtensionLoader<T>(type, this, scopeModel));\n        loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);\n        return loader;\n    }\n\n    private boolean isScopeMatched(Class<?> type) {\n        final SPI defaultAnnotation = type.getAnnotation(SPI.class);\n        return defaultAnnotation.scope().equals(scope);\n    }\n\n    private static boolean withExtensionAnnotation(Class<?> type) {\n        return type.isAnnotationPresent(SPI.class);\n    }\n\n    public ExtensionDirector getParent() {\n        return parent;\n    }\n\n    public void removeAllCachedLoader() {}\n\n    public void destroy() {\n        if (destroyed.compareAndSet(false, true)) {\n            for (ExtensionLoader<?> extensionLoader : extensionLoadersMap.values()) {\n                extensionLoader.destroy();\n            }\n            extensionLoadersMap.clear();\n            extensionScopeMap.clear();\n            extensionPostProcessors.clear();\n        }\n    }\n\n    private void checkDestroyed() {\n        if (destroyed.get()) {\n            throw new IllegalStateException(\"ExtensionDirector is destroyed\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n/**\n * ExtensionFactory\n * @deprecated use {@link ExtensionInjector} instead\n */\n@Deprecated\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface ExtensionFactory extends ExtensionInjector {\n\n    @Override\n    default <T> T getInstance(Class<T> type, String name) {\n        return getExtension(type, name);\n    }\n\n    /**\n     * Get extension.\n     *\n     * @param type object type.\n     * @param name object name.\n     * @return object instance.\n     */\n    <T> T getExtension(Class<T> type, String name);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionInjector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n/**\n * An injector to provide resources for SPI extension.\n */\n@SPI(scope = ExtensionScope.SELF)\npublic interface ExtensionInjector extends ExtensionAccessorAware {\n\n    /**\n     * Get instance of specify type and name.\n     *\n     * @param type object type.\n     * @param name object name.\n     * @return object instance.\n     */\n    <T> T getInstance(final Class<T> type, final String name);\n\n    @Override\n    default void setExtensionAccessor(final ExtensionAccessor extensionAccessor) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.Extension;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.aot.NativeDetector;\nimport org.apache.dubbo.common.beans.support.InstantiationStrategy;\nimport org.apache.dubbo.common.compact.Dubbo2ActivateUtils;\nimport org.apache.dubbo.common.compact.Dubbo2CompactUtils;\nimport org.apache.dubbo.common.context.Lifecycle;\nimport org.apache.dubbo.common.extension.support.ActivateComparator;\nimport org.apache.dubbo.common.extension.support.WrapperComparator;\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.ClassLoaderResourceLoader;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAccessor;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.lang.annotation.Annotation;\nimport java.lang.ref.SoftReference;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Properties;\nimport java.util.ServiceLoader;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.TreeSet;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport static java.util.Arrays.asList;\nimport static java.util.ServiceLoader.load;\nimport static java.util.stream.StreamSupport.stream;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_ERROR_LOAD_EXTENSION;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_LOAD_ENV_VARIABLE;\n\n/**\n * {@link org.apache.dubbo.rpc.model.ApplicationModel}, {@code DubboBootstrap} and this class are\n * at present designed to be singleton or static (by itself totally static or uses some static fields).\n * So the instances returned from them are of process or classloader scope. If you want to support\n * multiple dubbo servers in a single process, you may need to refactor these three classes.\n * <p>\n * Load dubbo extensions\n * <ul>\n * <li>auto inject dependency extension </li>\n * <li>auto wrap extension in wrapper </li>\n * <li>default extension is an adaptive instance</li>\n * </ul>\n *\n * @see <a href=\"http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider\">Service Provider in Java 5</a>\n * @see org.apache.dubbo.common.extension.SPI\n * @see org.apache.dubbo.common.extension.Adaptive\n * @see org.apache.dubbo.common.extension.Activate\n */\npublic class ExtensionLoader<T> {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ExtensionLoader.class);\n\n    private static final Pattern NAME_SEPARATOR = Pattern.compile(\"\\\\s*[,]+\\\\s*\");\n    private static final String SPECIAL_SPI_PROPERTIES = \"special_spi.properties\";\n\n    private final ConcurrentMap<Class<?>, Object> extensionInstances = new ConcurrentHashMap<>(64);\n\n    private final Class<?> type;\n\n    private final ExtensionInjector injector;\n\n    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();\n\n    private final ReentrantLock loadExtensionClassesLock = new ReentrantLock();\n    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();\n\n    private final Map<String, Object> cachedActivates = Collections.synchronizedMap(new LinkedHashMap<>());\n    private final Map<String, Set<String>> cachedActivateGroups = Collections.synchronizedMap(new LinkedHashMap<>());\n    private final Map<String, String[][]> cachedActivateValues = Collections.synchronizedMap(new LinkedHashMap<>());\n    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();\n    private final Holder<Object> cachedAdaptiveInstance = new Holder<>();\n    private volatile Class<?> cachedAdaptiveClass = null;\n    private String cachedDefaultName;\n    private volatile Throwable createAdaptiveInstanceError;\n\n    private Set<Class<?>> cachedWrapperClasses;\n\n    private final Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<>();\n\n    private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();\n\n    private static final Map<String, String> specialSPILoadingStrategyMap = getSpecialSPILoadingStrategyMap();\n\n    private static SoftReference<ConcurrentHashMap<java.net.URL, List<String>>> urlListMapCache =\n            new SoftReference<>(new ConcurrentHashMap<>());\n\n    private static final List<String> ignoredInjectMethodsDesc = getIgnoredInjectMethodsDesc();\n\n    /**\n     * Record all unacceptable exceptions when using SPI\n     */\n    private final Set<String> unacceptableExceptions = new ConcurrentHashSet<>();\n\n    private final ExtensionDirector extensionDirector;\n    private final List<ExtensionPostProcessor> extensionPostProcessors;\n    private InstantiationStrategy instantiationStrategy;\n    private final ActivateComparator activateComparator;\n    private final ScopeModel scopeModel;\n    private final AtomicBoolean destroyed = new AtomicBoolean();\n\n    public static void setLoadingStrategies(LoadingStrategy... strategies) {\n        if (ArrayUtils.isNotEmpty(strategies)) {\n            ExtensionLoader.strategies = strategies;\n        }\n    }\n\n    /**\n     * Load all {@link Prioritized prioritized} {@link LoadingStrategy Loading Strategies} via {@link ServiceLoader}\n     *\n     * @return non-null\n     * @since 2.7.7\n     */\n    private static LoadingStrategy[] loadLoadingStrategies() {\n        return stream(load(LoadingStrategy.class).spliterator(), false).sorted().toArray(LoadingStrategy[]::new);\n    }\n\n    /**\n     * some spi are implements by dubbo framework only and scan multi classloaders resources may cause\n     * application startup very slow\n     *\n     * @return\n     */\n    private static Map<String, String> getSpecialSPILoadingStrategyMap() {\n        Map map = new ConcurrentHashMap<>();\n        Properties properties = loadProperties(ExtensionLoader.class.getClassLoader(), SPECIAL_SPI_PROPERTIES);\n        map.putAll(properties);\n        return map;\n    }\n\n    /**\n     * Get all {@link LoadingStrategy Loading Strategies}\n     *\n     * @return non-null\n     * @see LoadingStrategy\n     * @see Prioritized\n     * @since 2.7.7\n     */\n    public static List<LoadingStrategy> getLoadingStrategies() {\n        return asList(strategies);\n    }\n\n    private static List<String> getIgnoredInjectMethodsDesc() {\n        List<String> ignoreInjectMethodsDesc = new ArrayList<>();\n        Arrays.stream(ScopeModelAware.class.getMethods())\n                .map(ReflectUtils::getDesc)\n                .forEach(ignoreInjectMethodsDesc::add);\n        Arrays.stream(ExtensionAccessorAware.class.getMethods())\n                .map(ReflectUtils::getDesc)\n                .forEach(ignoreInjectMethodsDesc::add);\n        return ignoreInjectMethodsDesc;\n    }\n\n    ExtensionLoader(Class<?> type, ExtensionDirector extensionDirector, ScopeModel scopeModel) {\n        this.type = type;\n        this.extensionDirector = extensionDirector;\n        this.extensionPostProcessors = extensionDirector.getExtensionPostProcessors();\n        initInstantiationStrategy();\n        this.injector = (type == ExtensionInjector.class\n                ? null\n                : extensionDirector.getExtensionLoader(ExtensionInjector.class).getAdaptiveExtension());\n        this.activateComparator = new ActivateComparator(extensionDirector);\n        this.scopeModel = scopeModel;\n    }\n\n    private void initInstantiationStrategy() {\n        instantiationStrategy = extensionPostProcessors.stream()\n                .filter(extensionPostProcessor -> extensionPostProcessor instanceof ScopeModelAccessor)\n                .map(extensionPostProcessor -> new InstantiationStrategy((ScopeModelAccessor) extensionPostProcessor))\n                .findFirst()\n                .orElse(new InstantiationStrategy());\n    }\n\n    /**\n     * @see ApplicationModel#getExtensionDirector()\n     * @see FrameworkModel#getExtensionDirector()\n     * @see ModuleModel#getExtensionDirector()\n     * @see ExtensionDirector#getExtensionLoader(java.lang.Class)\n     * @deprecated get extension loader from extension director of some module.\n     */\n    @Deprecated\n    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        return ApplicationModel.defaultModel().getDefaultModule().getExtensionLoader(type);\n    }\n\n    @Deprecated\n    public static void resetExtensionLoader(Class type) {}\n\n    public void destroy() {\n        if (!destroyed.compareAndSet(false, true)) {\n            return;\n        }\n        // destroy raw extension instance\n        extensionInstances.forEach((type, instance) -> {\n            if (instance instanceof Disposable) {\n                Disposable disposable = (Disposable) instance;\n                try {\n                    disposable.destroy();\n                } catch (Exception e) {\n                    logger.error(COMMON_ERROR_LOAD_EXTENSION, \"\", \"\", \"Error destroying extension \" + disposable, e);\n                }\n            }\n        });\n        extensionInstances.clear();\n\n        // destroy wrapped extension instance\n        for (Holder<Object> holder : cachedInstances.values()) {\n            Object wrappedInstance = holder.get();\n            if (wrappedInstance instanceof Disposable) {\n                Disposable disposable = (Disposable) wrappedInstance;\n                try {\n                    disposable.destroy();\n                } catch (Exception e) {\n                    logger.error(COMMON_ERROR_LOAD_EXTENSION, \"\", \"\", \"Error destroying extension \" + disposable, e);\n                }\n            }\n        }\n        cachedInstances.clear();\n    }\n\n    private void checkDestroyed() {\n        if (destroyed.get()) {\n            throw new IllegalStateException(\"ExtensionLoader is destroyed: \" + type);\n        }\n    }\n\n    public String getExtensionName(T extensionInstance) {\n        return getExtensionName(extensionInstance.getClass());\n    }\n\n    public String getExtensionName(Class<?> extensionClass) {\n        getExtensionClasses(); // load class\n        return cachedNames.get(extensionClass);\n    }\n\n    /**\n     * This is equivalent to {@code getActivateExtension(url, key, null)}\n     *\n     * @param url url\n     * @param key url parameter key which used to get extension point names\n     * @return extension list which are activated.\n     * @see #getActivateExtension(org.apache.dubbo.common.URL, String, String)\n     */\n    public List<T> getActivateExtension(URL url, String key) {\n        return getActivateExtension(url, key, null);\n    }\n\n    /**\n     * This is equivalent to {@code getActivateExtension(url, values, null)}\n     *\n     * @param url    url\n     * @param values extension point names\n     * @return extension list which are activated\n     * @see #getActivateExtension(org.apache.dubbo.common.URL, String[], String)\n     */\n    public List<T> getActivateExtension(URL url, String[] values) {\n        return getActivateExtension(url, values, null);\n    }\n\n    /**\n     * This is equivalent to {@code getActivateExtension(url, url.getParameter(key).split(\",\"), null)}\n     *\n     * @param url   url\n     * @param key   url parameter key which used to get extension point names\n     * @param group group\n     * @return extension list which are activated.\n     * @see #getActivateExtension(org.apache.dubbo.common.URL, String[], String)\n     */\n    public List<T> getActivateExtension(URL url, String key, String group) {\n        String value = url.getParameter(key);\n        return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);\n    }\n\n    /**\n     * Get activate extensions.\n     *\n     * @param url    url\n     * @param values extension point names\n     * @param group  group\n     * @return extension list which are activated\n     * @see org.apache.dubbo.common.extension.Activate\n     */\n    @SuppressWarnings(\"deprecation\")\n    public List<T> getActivateExtension(URL url, String[] values, String group) {\n        checkDestroyed();\n        // solve the bug of using @SPI's wrapper method to report a null pointer exception.\n        Map<Class<?>, T> activateExtensionsMap = new TreeMap<>(activateComparator);\n        List<String> names = values == null\n                ? new ArrayList<>(0)\n                : Arrays.stream(values).map(StringUtils::trim).collect(Collectors.toList());\n        Set<String> namesSet = new HashSet<>(names);\n        if (!namesSet.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {\n            if (cachedActivateGroups.size() == 0) {\n                synchronized (cachedActivateGroups) {\n                    // cache all extensions\n                    if (cachedActivateGroups.size() == 0) {\n                        getExtensionClasses();\n                        for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {\n                            String name = entry.getKey();\n                            Object activate = entry.getValue();\n\n                            String[] activateGroup, activateValue;\n\n                            if (activate instanceof Activate) {\n                                activateGroup = ((Activate) activate).group();\n                                activateValue = ((Activate) activate).value();\n                            } else if (Dubbo2CompactUtils.isEnabled()\n                                    && Dubbo2ActivateUtils.isActivateLoaded()\n                                    && Dubbo2ActivateUtils.getActivateClass().isAssignableFrom(activate.getClass())) {\n                                activateGroup = Dubbo2ActivateUtils.getGroup((Annotation) activate);\n                                activateValue = Dubbo2ActivateUtils.getValue((Annotation) activate);\n                            } else {\n                                continue;\n                            }\n                            cachedActivateGroups.put(name, new HashSet<>(Arrays.asList(activateGroup)));\n                            String[][] keyPairs = new String[activateValue.length][];\n                            for (int i = 0; i < activateValue.length; i++) {\n                                if (activateValue[i].contains(\":\")) {\n                                    keyPairs[i] = new String[2];\n                                    String[] arr = activateValue[i].split(\":\");\n                                    keyPairs[i][0] = arr[0];\n                                    keyPairs[i][1] = arr[1];\n                                } else {\n                                    keyPairs[i] = new String[1];\n                                    keyPairs[i][0] = activateValue[i];\n                                }\n                            }\n                            cachedActivateValues.put(name, keyPairs);\n                        }\n                    }\n                }\n            }\n\n            // traverse all cached extensions\n            cachedActivateGroups.forEach((name, activateGroup) -> {\n                if (isMatchGroup(group, activateGroup)\n                        && !namesSet.contains(name)\n                        && !namesSet.contains(REMOVE_VALUE_PREFIX + name)\n                        && isActive(cachedActivateValues.get(name), url)) {\n\n                    activateExtensionsMap.put(getExtensionClass(name), getExtension(name));\n                }\n            });\n        }\n\n        if (namesSet.contains(DEFAULT_KEY)) {\n            // will affect order\n            // `ext1,default,ext2` means ext1 will happens before all of the default extensions while ext2 will after\n            // them\n            ArrayList<T> extensionsResult = new ArrayList<>(activateExtensionsMap.size() + names.size());\n            for (String name : names) {\n                if (name.startsWith(REMOVE_VALUE_PREFIX) || namesSet.contains(REMOVE_VALUE_PREFIX + name)) {\n                    continue;\n                }\n                if (DEFAULT_KEY.equals(name)) {\n                    extensionsResult.addAll(activateExtensionsMap.values());\n                    continue;\n                }\n                if (containsExtension(name)) {\n                    extensionsResult.add(getExtension(name));\n                }\n            }\n            return extensionsResult;\n        } else {\n            // add extensions, will be sorted by its order\n            for (String name : names) {\n                if (name.startsWith(REMOVE_VALUE_PREFIX) || namesSet.contains(REMOVE_VALUE_PREFIX + name)) {\n                    continue;\n                }\n                if (DEFAULT_KEY.equals(name)) {\n                    continue;\n                }\n                if (containsExtension(name)) {\n                    activateExtensionsMap.put(getExtensionClass(name), getExtension(name));\n                }\n            }\n            return new ArrayList<>(activateExtensionsMap.values());\n        }\n    }\n\n    public List<T> getActivateExtensions() {\n        checkDestroyed();\n        List<T> activateExtensions = new ArrayList<>();\n        TreeMap<Class<?>, T> activateExtensionsMap = new TreeMap<>(activateComparator);\n        getExtensionClasses();\n        for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {\n            String name = entry.getKey();\n            Object activate = entry.getValue();\n            if (!(activate instanceof Activate)) {\n                continue;\n            }\n            activateExtensionsMap.put(getExtensionClass(name), getExtension(name));\n        }\n        if (!activateExtensionsMap.isEmpty()) {\n            activateExtensions.addAll(activateExtensionsMap.values());\n        }\n\n        return activateExtensions;\n    }\n\n    private boolean isMatchGroup(String group, Set<String> groups) {\n        if (StringUtils.isEmpty(group)) {\n            return true;\n        }\n        if (CollectionUtils.isNotEmpty(groups)) {\n            return groups.contains(group);\n        }\n        return false;\n    }\n\n    private boolean isActive(String[][] keyPairs, URL url) {\n        if (keyPairs.length == 0) {\n            return true;\n        }\n        for (String[] keyPair : keyPairs) {\n            // @Active(value=\"key1:value1, key2:value2\")\n            String key;\n            String keyValue = null;\n            if (keyPair.length > 1) {\n                key = keyPair[0];\n                keyValue = keyPair[1];\n            } else {\n                key = keyPair[0];\n            }\n\n            String realValue = url.getParameter(key);\n            if (StringUtils.isEmpty(realValue)) {\n                realValue = url.getAnyMethodParameter(key);\n            }\n            if ((keyValue != null && keyValue.equals(realValue))\n                    || (keyValue == null && ConfigUtils.isNotEmpty(realValue))) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Get extension's instance. Return <code>null</code> if extension is not found or is not initialized. Pls. note\n     * that this method will not trigger extension load.\n     * <p>\n     * In order to trigger extension load, call {@link #getExtension(String)} instead.\n     *\n     * @see #getExtension(String)\n     */\n    @SuppressWarnings(\"unchecked\")\n    public T getLoadedExtension(String name) {\n        checkDestroyed();\n        if (StringUtils.isEmpty(name)) {\n            throw new IllegalArgumentException(\"Extension name == null\");\n        }\n        Holder<Object> holder = getOrCreateHolder(name);\n        return (T) holder.get();\n    }\n\n    private Holder<Object> getOrCreateHolder(String name) {\n        Holder<Object> holder = cachedInstances.get(name);\n        if (holder == null) {\n            cachedInstances.putIfAbsent(name, new Holder<>());\n            holder = cachedInstances.get(name);\n        }\n        return holder;\n    }\n\n    /**\n     * Return the list of extensions which are already loaded.\n     * <p>\n     * Usually {@link #getSupportedExtensions()} should be called in order to get all extensions.\n     *\n     * @see #getSupportedExtensions()\n     */\n    public Set<String> getLoadedExtensions() {\n        return Collections.unmodifiableSet(new TreeSet<>(cachedInstances.keySet()));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public List<T> getLoadedExtensionInstances() {\n        checkDestroyed();\n        List<T> instances = new ArrayList<>();\n        cachedInstances.values().forEach(holder -> instances.add((T) holder.get()));\n        return instances;\n    }\n\n    /**\n     * Find the extension with the given name.\n     *\n     * @throws IllegalStateException If the specified extension is not found.\n     */\n    public T getExtension(String name) {\n        T extension = getExtension(name, true);\n        if (extension == null) {\n            throw new IllegalArgumentException(\"Not find extension: \" + name);\n        }\n        return extension;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T getExtension(String name, boolean wrap) {\n        checkDestroyed();\n        if (StringUtils.isEmpty(name)) {\n            throw new IllegalArgumentException(\"Extension name == null\");\n        }\n        if (\"true\".equals(name)) {\n            return getDefaultExtension();\n        }\n        String cacheKey = name;\n        if (!wrap) {\n            cacheKey += \"_origin\";\n        }\n        final Holder<Object> holder = getOrCreateHolder(cacheKey);\n        Object instance = holder.get();\n        if (instance == null) {\n            synchronized (holder) {\n                instance = holder.get();\n                if (instance == null) {\n                    instance = createExtension(name, wrap);\n                    holder.set(instance);\n                }\n            }\n        }\n        return (T) instance;\n    }\n\n    /**\n     * Get the extension by specified name if found, or {@link #getDefaultExtension() returns the default one}\n     *\n     * @param name the name of extension\n     * @return non-null\n     */\n    public T getOrDefaultExtension(String name) {\n        return containsExtension(name) ? getExtension(name) : getDefaultExtension();\n    }\n\n    /**\n     * Return default extension, return <code>null</code> if it's not configured.\n     */\n    public T getDefaultExtension() {\n        getExtensionClasses();\n        if (StringUtils.isBlank(cachedDefaultName) || \"true\".equals(cachedDefaultName)) {\n            return null;\n        }\n        return getExtension(cachedDefaultName);\n    }\n\n    public boolean hasExtension(String name) {\n        checkDestroyed();\n        if (StringUtils.isEmpty(name)) {\n            throw new IllegalArgumentException(\"Extension name == null\");\n        }\n        Class<?> c = this.getExtensionClass(name);\n        return c != null;\n    }\n\n    public Set<String> getSupportedExtensions() {\n        checkDestroyed();\n        Map<String, Class<?>> classes = getExtensionClasses();\n        return Collections.unmodifiableSet(new TreeSet<>(classes.keySet()));\n    }\n\n    public Set<T> getSupportedExtensionInstances() {\n        checkDestroyed();\n        List<T> instances = new LinkedList<>();\n        Set<String> supportedExtensions = getSupportedExtensions();\n        if (CollectionUtils.isNotEmpty(supportedExtensions)) {\n            for (String name : supportedExtensions) {\n                instances.add(getExtension(name));\n            }\n        }\n        // sort the Prioritized instances\n        instances.sort(Prioritized.COMPARATOR);\n        return new LinkedHashSet<>(instances);\n    }\n\n    /**\n     * Return default extension name, return <code>null</code> if not configured.\n     */\n    public String getDefaultExtensionName() {\n        getExtensionClasses();\n        return cachedDefaultName;\n    }\n\n    /**\n     * Register new extension via API\n     *\n     * @param name  extension name\n     * @param clazz extension class\n     * @throws IllegalStateException when extension with the same name has already been registered.\n     */\n    public void addExtension(String name, Class<?> clazz) {\n        checkDestroyed();\n        getExtensionClasses(); // load classes\n\n        if (!type.isAssignableFrom(clazz)) {\n            throw new IllegalStateException(\"Input type \" + clazz + \" doesn't implement the Extension \" + type);\n        }\n        if (clazz.isInterface()) {\n            throw new IllegalStateException(\"Input type \" + clazz + \" can't be interface!\");\n        }\n\n        if (!clazz.isAnnotationPresent(Adaptive.class)) {\n            if (StringUtils.isBlank(name)) {\n                throw new IllegalStateException(\"Extension name is blank (Extension \" + type + \")!\");\n            }\n            if (cachedClasses.get().containsKey(name)) {\n                throw new IllegalStateException(\"Extension name \" + name + \" already exists (Extension \" + type + \")!\");\n            }\n\n            cachedNames.put(clazz, name);\n            cachedClasses.get().put(name, clazz);\n        } else {\n            if (cachedAdaptiveClass != null) {\n                throw new IllegalStateException(\"Adaptive Extension already exists (Extension \" + type + \")!\");\n            }\n\n            cachedAdaptiveClass = clazz;\n        }\n    }\n\n    /**\n     * Replace the existing extension via API\n     *\n     * @param name  extension name\n     * @param clazz extension class\n     * @throws IllegalStateException when extension to be placed doesn't exist\n     * @deprecated not recommended any longer, and use only when test\n     */\n    @Deprecated\n    public void replaceExtension(String name, Class<?> clazz) {\n        checkDestroyed();\n        getExtensionClasses(); // load classes\n\n        if (!type.isAssignableFrom(clazz)) {\n            throw new IllegalStateException(\"Input type \" + clazz + \" doesn't implement Extension \" + type);\n        }\n        if (clazz.isInterface()) {\n            throw new IllegalStateException(\"Input type \" + clazz + \" can't be interface!\");\n        }\n\n        if (!clazz.isAnnotationPresent(Adaptive.class)) {\n            if (StringUtils.isBlank(name)) {\n                throw new IllegalStateException(\"Extension name is blank (Extension \" + type + \")!\");\n            }\n            if (!cachedClasses.get().containsKey(name)) {\n                throw new IllegalStateException(\"Extension name \" + name + \" doesn't exist (Extension \" + type + \")!\");\n            }\n\n            cachedNames.put(clazz, name);\n            cachedClasses.get().put(name, clazz);\n            cachedInstances.remove(name);\n        } else {\n            if (cachedAdaptiveClass == null) {\n                throw new IllegalStateException(\"Adaptive Extension doesn't exist (Extension \" + type + \")!\");\n            }\n\n            cachedAdaptiveClass = clazz;\n            cachedAdaptiveInstance.set(null);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T getAdaptiveExtension() {\n        checkDestroyed();\n        Object instance = cachedAdaptiveInstance.get();\n        if (instance == null) {\n            if (createAdaptiveInstanceError != null) {\n                throw new IllegalStateException(\n                        \"Failed to create adaptive instance: \" + createAdaptiveInstanceError.toString(),\n                        createAdaptiveInstanceError);\n            }\n\n            synchronized (cachedAdaptiveInstance) {\n                instance = cachedAdaptiveInstance.get();\n                if (instance == null) {\n                    try {\n                        instance = createAdaptiveExtension();\n                        cachedAdaptiveInstance.set(instance);\n                    } catch (Throwable t) {\n                        createAdaptiveInstanceError = t;\n                        throw new IllegalStateException(\"Failed to create adaptive instance: \" + t.toString(), t);\n                    }\n                }\n            }\n        }\n\n        return (T) instance;\n    }\n\n    private IllegalStateException findException(String name) {\n        StringBuilder buf = new StringBuilder(\"No such extension \" + type.getName() + \" by name \" + name);\n\n        int i = 1;\n        for (Map.Entry<String, IllegalStateException> entry : exceptions.entrySet()) {\n            if (entry.getKey().toLowerCase().startsWith(name.toLowerCase())) {\n                if (i == 1) {\n                    buf.append(\", possible causes: \");\n                }\n                buf.append(\"\\r\\n(\");\n                buf.append(i++);\n                buf.append(\") \");\n                buf.append(entry.getKey());\n                buf.append(\":\\r\\n\");\n                buf.append(StringUtils.toString(entry.getValue()));\n            }\n        }\n\n        if (i == 1) {\n            buf.append(\", no related exception was found, please check whether related SPI module is missing.\");\n        }\n        return new IllegalStateException(buf.toString());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private T createExtension(String name, boolean wrap) {\n        Class<?> clazz = getExtensionClasses().get(name);\n        if (clazz == null || unacceptableExceptions.contains(name)) {\n            throw findException(name);\n        }\n        try {\n            T instance = (T) extensionInstances.get(clazz);\n            if (instance == null) {\n                extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));\n                instance = (T) extensionInstances.get(clazz);\n                instance = postProcessBeforeInitialization(instance, name);\n                injectExtension(instance);\n                instance = postProcessAfterInitialization(instance, name);\n            }\n\n            if (wrap) {\n                List<Class<?>> wrapperClassesList = new ArrayList<>();\n                if (cachedWrapperClasses != null) {\n                    wrapperClassesList.addAll(cachedWrapperClasses);\n                    wrapperClassesList.sort(WrapperComparator.COMPARATOR);\n                    Collections.reverse(wrapperClassesList);\n                }\n\n                if (CollectionUtils.isNotEmpty(wrapperClassesList)) {\n                    for (Class<?> wrapperClass : wrapperClassesList) {\n                        Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);\n                        boolean match = (wrapper == null)\n                                || ((ArrayUtils.isEmpty(wrapper.matches())\n                                                || ArrayUtils.contains(wrapper.matches(), name))\n                                        && !ArrayUtils.contains(wrapper.mismatches(), name));\n                        if (match) {\n                            instance = (T) wrapperClass.getConstructor(type).newInstance(instance);\n                            instance = postProcessBeforeInitialization(instance, name);\n                            injectExtension(instance);\n                            instance = postProcessAfterInitialization(instance, name);\n                        }\n                    }\n                }\n            }\n\n            // Warning: After an instance of Lifecycle is wrapped by cachedWrapperClasses, it may not still be Lifecycle\n            // instance, this application may not invoke the lifecycle.initialize hook.\n            initExtension(instance);\n            return instance;\n        } catch (Throwable t) {\n            throw new IllegalStateException(\n                    \"Extension instance (name: \" + name + \", class: \" + type + \") couldn't be instantiated: \"\n                            + t.getMessage(),\n                    t);\n        }\n    }\n\n    private Object createExtensionInstance(Class<?> type) throws ReflectiveOperationException {\n        return instantiationStrategy.instantiate(type);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private T postProcessBeforeInitialization(T instance, String name) throws Exception {\n        if (extensionPostProcessors != null) {\n            for (ExtensionPostProcessor processor : extensionPostProcessors) {\n                instance = (T) processor.postProcessBeforeInitialization(instance, name);\n            }\n        }\n        return instance;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private T postProcessAfterInitialization(T instance, String name) throws Exception {\n        if (instance instanceof ExtensionAccessorAware) {\n            ((ExtensionAccessorAware) instance).setExtensionAccessor(extensionDirector);\n        }\n        if (extensionPostProcessors != null) {\n            for (ExtensionPostProcessor processor : extensionPostProcessors) {\n                instance = (T) processor.postProcessAfterInitialization(instance, name);\n            }\n        }\n        return instance;\n    }\n\n    private boolean containsExtension(String name) {\n        return getExtensionClasses().containsKey(name);\n    }\n\n    private T injectExtension(T instance) {\n        if (injector == null) {\n            return instance;\n        }\n\n        try {\n            for (Method method : instance.getClass().getMethods()) {\n                if (!isSetter(method)) {\n                    continue;\n                }\n                /**\n                 * Check {@link DisableInject} to see if we need auto-injection for this property\n                 */\n                if (method.isAnnotationPresent(DisableInject.class)) {\n                    continue;\n                }\n\n                // When spiXXX implements ScopeModelAware, ExtensionAccessorAware,\n                // the setXXX of ScopeModelAware and ExtensionAccessorAware does not need to be injected\n                if (method.getDeclaringClass() == ScopeModelAware.class) {\n                    continue;\n                }\n                if (instance instanceof ScopeModelAware || instance instanceof ExtensionAccessorAware) {\n                    if (ignoredInjectMethodsDesc.contains(ReflectUtils.getDesc(method))) {\n                        continue;\n                    }\n                }\n\n                Class<?> pt = method.getParameterTypes()[0];\n                if (ReflectUtils.isPrimitives(pt)) {\n                    continue;\n                }\n\n                try {\n                    String property = getSetterProperty(method);\n                    Object object = injector.getInstance(pt, property);\n                    if (object != null) {\n                        method.invoke(instance, object);\n                    }\n                } catch (Exception e) {\n                    logger.error(\n                            COMMON_ERROR_LOAD_EXTENSION,\n                            \"\",\n                            \"\",\n                            \"Failed to inject via method \" + method.getName() + \" of interface \" + type.getName() + \": \"\n                                    + e.getMessage(),\n                            e);\n                }\n            }\n        } catch (Exception e) {\n            logger.error(COMMON_ERROR_LOAD_EXTENSION, \"\", \"\", e.getMessage(), e);\n        }\n        return instance;\n    }\n\n    private void initExtension(T instance) {\n        if (instance instanceof Lifecycle) {\n            Lifecycle lifecycle = (Lifecycle) instance;\n            lifecycle.initialize();\n        }\n    }\n\n    /**\n     * get properties name for setter, for instance: setVersion, return \"version\"\n     * <p>\n     * return \"\", if setter name with length less than 3\n     */\n    private String getSetterProperty(Method method) {\n        return method.getName().length() > 3\n                ? method.getName().substring(3, 4).toLowerCase()\n                        + method.getName().substring(4)\n                : \"\";\n    }\n\n    /**\n     * return true if and only if:\n     * <p>\n     * 1, public\n     * <p>\n     * 2, name starts with \"set\"\n     * <p>\n     * 3, only has one parameter\n     */\n    private boolean isSetter(Method method) {\n        return method.getName().startsWith(\"set\")\n                && method.getParameterTypes().length == 1\n                && Modifier.isPublic(method.getModifiers());\n    }\n\n    private Class<?> getExtensionClass(String name) {\n        if (type == null) {\n            throw new IllegalArgumentException(\"Extension type == null\");\n        }\n        if (name == null) {\n            throw new IllegalArgumentException(\"Extension name == null\");\n        }\n        return getExtensionClasses().get(name);\n    }\n\n    private Map<String, Class<?>> getExtensionClasses() {\n        Map<String, Class<?>> classes = cachedClasses.get();\n        if (classes == null) {\n            loadExtensionClassesLock.lock();\n            try {\n                classes = cachedClasses.get();\n                if (classes == null) {\n                    try {\n                        classes = loadExtensionClasses();\n                    } catch (InterruptedException e) {\n                        logger.error(\n                                COMMON_ERROR_LOAD_EXTENSION,\n                                \"\",\n                                \"\",\n                                \"Exception occurred when loading extension class (interface: \" + type + \")\",\n                                e);\n                        throw new IllegalStateException(\n                                \"Exception occurred when loading extension class (interface: \" + type + \")\", e);\n                    }\n                    cachedClasses.set(classes);\n                }\n            } finally {\n                loadExtensionClassesLock.unlock();\n            }\n        }\n        return classes;\n    }\n\n    /**\n     * synchronized in getExtensionClasses\n     */\n    @SuppressWarnings(\"deprecation\")\n    private Map<String, Class<?>> loadExtensionClasses() throws InterruptedException {\n        checkDestroyed();\n        cacheDefaultExtensionName();\n\n        Map<String, Class<?>> extensionClasses = new HashMap<>();\n\n        for (LoadingStrategy strategy : strategies) {\n            loadDirectory(extensionClasses, strategy, type.getName());\n\n            // compatible with old ExtensionFactory\n            if (this.type == ExtensionInjector.class) {\n                loadDirectory(extensionClasses, strategy, ExtensionFactory.class.getName());\n            }\n        }\n\n        return extensionClasses;\n    }\n\n    private void loadDirectory(Map<String, Class<?>> extensionClasses, LoadingStrategy strategy, String type)\n            throws InterruptedException {\n        loadDirectoryInternal(extensionClasses, strategy, type);\n        if (Dubbo2CompactUtils.isEnabled()) {\n            try {\n                String oldType = type.replace(\"org.apache\", \"com.alibaba\");\n                if (oldType.equals(type)) {\n                    return;\n                }\n                // if class not found,skip try to load resources\n                ClassUtils.forName(oldType);\n                loadDirectoryInternal(extensionClasses, strategy, oldType);\n            } catch (ClassNotFoundException classNotFoundException) {\n\n            }\n        }\n    }\n\n    /**\n     * extract and cache default extension name if exists\n     */\n    private void cacheDefaultExtensionName() {\n        final SPI defaultAnnotation = type.getAnnotation(SPI.class);\n        if (defaultAnnotation == null) {\n            return;\n        }\n\n        String value = defaultAnnotation.value();\n        if ((value = value.trim()).length() > 0) {\n            String[] names = NAME_SEPARATOR.split(value);\n            if (names.length > 1) {\n                throw new IllegalStateException(\"More than 1 default extension name on extension \" + type.getName()\n                        + \": \" + Arrays.toString(names));\n            }\n            if (names.length == 1) {\n                cachedDefaultName = names[0];\n            }\n        }\n    }\n\n    private void loadDirectoryInternal(\n            Map<String, Class<?>> extensionClasses, LoadingStrategy loadingStrategy, String type)\n            throws InterruptedException {\n        String fileName = loadingStrategy.directory() + type;\n        try {\n            List<ClassLoader> classLoadersToLoad = new LinkedList<>();\n\n            // try to load from ExtensionLoader's ClassLoader first\n            if (loadingStrategy.preferExtensionClassLoader()) {\n                ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();\n                if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {\n                    classLoadersToLoad.add(extensionLoaderClassLoader);\n                }\n            }\n\n            if (specialSPILoadingStrategyMap.containsKey(type)) {\n                String internalDirectoryType = specialSPILoadingStrategyMap.get(type);\n                // skip to load spi when name don't match\n                if (!LoadingStrategy.ALL.equals(internalDirectoryType)\n                        && !internalDirectoryType.equals(loadingStrategy.getName())) {\n                    return;\n                }\n                classLoadersToLoad.clear();\n                classLoadersToLoad.add(ExtensionLoader.class.getClassLoader());\n            } else {\n                // load from scope model\n                Set<ClassLoader> classLoaders = scopeModel.getClassLoaders();\n\n                if (CollectionUtils.isEmpty(classLoaders)) {\n                    Enumeration<java.net.URL> resources = ClassLoader.getSystemResources(fileName);\n                    if (resources != null) {\n                        while (resources.hasMoreElements()) {\n                            loadResource(\n                                    extensionClasses,\n                                    null,\n                                    resources.nextElement(),\n                                    loadingStrategy.overridden(),\n                                    loadingStrategy.includedPackages(),\n                                    loadingStrategy.excludedPackages(),\n                                    loadingStrategy.onlyExtensionClassLoaderPackages());\n                        }\n                    }\n                } else {\n                    classLoadersToLoad.addAll(classLoaders);\n                }\n            }\n\n            Map<ClassLoader, Set<java.net.URL>> resources =\n                    ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad);\n            resources.forEach(((classLoader, urls) -> {\n                loadFromClass(\n                        extensionClasses,\n                        loadingStrategy.overridden(),\n                        urls,\n                        classLoader,\n                        loadingStrategy.includedPackages(),\n                        loadingStrategy.excludedPackages(),\n                        loadingStrategy.onlyExtensionClassLoaderPackages());\n            }));\n        } catch (InterruptedException e) {\n            throw e;\n        } catch (Throwable t) {\n            logger.error(\n                    COMMON_ERROR_LOAD_EXTENSION,\n                    \"\",\n                    \"\",\n                    \"Exception occurred when loading extension class (interface: \" + type + \", description file: \"\n                            + fileName + \").\",\n                    t);\n        }\n    }\n\n    private void loadFromClass(\n            Map<String, Class<?>> extensionClasses,\n            boolean overridden,\n            Set<java.net.URL> urls,\n            ClassLoader classLoader,\n            String[] includedPackages,\n            String[] excludedPackages,\n            String[] onlyExtensionClassLoaderPackages) {\n        if (CollectionUtils.isNotEmpty(urls)) {\n            for (java.net.URL url : urls) {\n                loadResource(\n                        extensionClasses,\n                        classLoader,\n                        url,\n                        overridden,\n                        includedPackages,\n                        excludedPackages,\n                        onlyExtensionClassLoaderPackages);\n            }\n        }\n    }\n\n    private void loadResource(\n            Map<String, Class<?>> extensionClasses,\n            ClassLoader classLoader,\n            java.net.URL resourceURL,\n            boolean overridden,\n            String[] includedPackages,\n            String[] excludedPackages,\n            String[] onlyExtensionClassLoaderPackages) {\n        try {\n            List<String> newContentList = getResourceContent(resourceURL);\n            String clazz;\n            for (String line : newContentList) {\n                try {\n                    String name = null;\n                    int i = line.indexOf('=');\n                    if (i > 0) {\n                        name = line.substring(0, i).trim();\n                        clazz = line.substring(i + 1).trim();\n                    } else {\n                        clazz = line;\n                    }\n                    if (StringUtils.isNotEmpty(clazz)\n                            && !isExcluded(clazz, excludedPackages)\n                            && isIncluded(clazz, includedPackages)\n                            && !isExcludedByClassLoader(clazz, classLoader, onlyExtensionClassLoaderPackages)) {\n\n                        loadClass(\n                                classLoader,\n                                extensionClasses,\n                                resourceURL,\n                                Class.forName(clazz, true, classLoader),\n                                name,\n                                overridden);\n                    }\n                } catch (Throwable t) {\n                    IllegalStateException e = new IllegalStateException(\n                            \"Failed to load extension class (interface: \" + type + \", class line: \" + line + \") in \"\n                                    + resourceURL + \", cause: \" + t.getMessage(),\n                            t);\n                    exceptions.put(line, e);\n                }\n            }\n        } catch (Throwable t) {\n            logger.error(\n                    COMMON_ERROR_LOAD_EXTENSION,\n                    \"\",\n                    \"\",\n                    \"Exception occurred when loading extension class (interface: \" + type + \", class file: \"\n                            + resourceURL + \") in \" + resourceURL,\n                    t);\n        }\n    }\n\n    private List<String> getResourceContent(java.net.URL resourceURL) throws IOException {\n        ConcurrentHashMap<java.net.URL, List<String>> urlListMap = urlListMapCache.get();\n        if (urlListMap == null) {\n            synchronized (ExtensionLoader.class) {\n                if ((urlListMap = urlListMapCache.get()) == null) {\n                    urlListMap = new ConcurrentHashMap<>();\n                    urlListMapCache = new SoftReference<>(urlListMap);\n                }\n            }\n        }\n\n        List<String> contentList = ConcurrentHashMapUtils.computeIfAbsent(urlListMap, resourceURL, key -> {\n            List<String> newContentList = new ArrayList<>();\n\n            try (BufferedReader reader =\n                    new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {\n                String line;\n                while ((line = reader.readLine()) != null) {\n                    final int ci = line.indexOf('#');\n                    if (ci >= 0) {\n                        line = line.substring(0, ci);\n                    }\n                    line = line.trim();\n                    if (line.length() > 0) {\n                        newContentList.add(line);\n                    }\n                }\n            } catch (IOException e) {\n                throw new RuntimeException(e.getMessage(), e);\n            }\n            return newContentList;\n        });\n        return contentList;\n    }\n\n    private boolean isIncluded(String className, String... includedPackages) {\n        if (includedPackages != null && includedPackages.length > 0) {\n            for (String includedPackage : includedPackages) {\n                if (className.startsWith(includedPackage + \".\")) {\n                    // one match, return true\n                    return true;\n                }\n            }\n            // none matcher match, return false\n            return false;\n        }\n        // matcher is empty, return true\n        return true;\n    }\n\n    private boolean isExcluded(String className, String... excludedPackages) {\n        if (excludedPackages != null) {\n            for (String excludePackage : excludedPackages) {\n                if (className.startsWith(excludePackage + \".\")) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    private boolean isExcludedByClassLoader(\n            String className, ClassLoader classLoader, String... onlyExtensionClassLoaderPackages) {\n        if (onlyExtensionClassLoaderPackages != null) {\n            for (String excludePackage : onlyExtensionClassLoaderPackages) {\n                if (className.startsWith(excludePackage + \".\")) {\n                    // if target classLoader is not ExtensionLoader's classLoader should be excluded\n                    return !Objects.equals(ExtensionLoader.class.getClassLoader(), classLoader);\n                }\n            }\n        }\n        return false;\n    }\n\n    private void loadClass(\n            ClassLoader classLoader,\n            Map<String, Class<?>> extensionClasses,\n            java.net.URL resourceURL,\n            Class<?> clazz,\n            String name,\n            boolean overridden) {\n        if (!type.isAssignableFrom(clazz)) {\n            throw new IllegalStateException(\n                    \"Error occurred when loading extension class (interface: \" + type + \", class line: \"\n                            + clazz.getName() + \"), class \" + clazz.getName() + \" is not subtype of interface.\");\n        }\n\n        boolean isActive = loadClassIfActive(classLoader, clazz);\n\n        if (!isActive) {\n            return;\n        }\n\n        if (clazz.isAnnotationPresent(Adaptive.class)) {\n            cacheAdaptiveClass(clazz, overridden);\n        } else if (isWrapperClass(clazz)) {\n            cacheWrapperClass(clazz);\n        } else {\n            if (StringUtils.isEmpty(name)) {\n                name = findAnnotationName(clazz);\n                if (name.length() == 0) {\n                    throw new IllegalStateException(\"No such extension name for the class \" + clazz.getName()\n                            + \" in the config \" + resourceURL);\n                }\n            }\n\n            String[] names = NAME_SEPARATOR.split(name);\n            if (ArrayUtils.isNotEmpty(names)) {\n                cacheActivateClass(clazz, names[0]);\n                for (String n : names) {\n                    cacheName(clazz, n);\n                    saveInExtensionClass(extensionClasses, clazz, n, overridden);\n                }\n            }\n        }\n    }\n\n    private boolean loadClassIfActive(ClassLoader classLoader, Class<?> clazz) {\n        Activate activate = clazz.getAnnotation(Activate.class);\n\n        if (activate == null) {\n            return true;\n        }\n        String[] onClass = null;\n\n        if (activate instanceof Activate) {\n            onClass = ((Activate) activate).onClass();\n        } else if (Dubbo2CompactUtils.isEnabled()\n                && Dubbo2ActivateUtils.isActivateLoaded()\n                && Dubbo2ActivateUtils.getActivateClass().isAssignableFrom(activate.getClass())) {\n            onClass = Dubbo2ActivateUtils.getOnClass(activate);\n        }\n\n        boolean isActive = true;\n\n        if (null != onClass && onClass.length > 0) {\n            isActive = Arrays.stream(onClass)\n                    .filter(StringUtils::isNotBlank)\n                    .allMatch(className -> ClassUtils.isPresent(className, classLoader));\n        }\n        return isActive;\n    }\n\n    /**\n     * cache name\n     */\n    private void cacheName(Class<?> clazz, String name) {\n        if (!cachedNames.containsKey(clazz)) {\n            cachedNames.put(clazz, name);\n        }\n    }\n\n    /**\n     * put clazz in extensionClasses\n     */\n    private void saveInExtensionClass(\n            Map<String, Class<?>> extensionClasses, Class<?> clazz, String name, boolean overridden) {\n        Class<?> c = extensionClasses.get(name);\n        if (c == null || overridden) {\n            extensionClasses.put(name, clazz);\n        } else if (c != clazz) {\n            // duplicate implementation is unacceptable\n            unacceptableExceptions.add(name);\n            String duplicateMsg = \"Duplicate extension \" + type.getName() + \" name \" + name + \" on \" + c.getName()\n                    + \" and \" + clazz.getName();\n            logger.error(COMMON_ERROR_LOAD_EXTENSION, \"\", \"\", duplicateMsg);\n            throw new IllegalStateException(duplicateMsg);\n        }\n    }\n\n    /**\n     * cache Activate class which is annotated with <code>Activate</code>\n     * <p>\n     * for compatibility, also cache class with old alibaba Activate annotation\n     */\n    @SuppressWarnings(\"deprecation\")\n    private void cacheActivateClass(Class<?> clazz, String name) {\n        Activate activate = clazz.getAnnotation(Activate.class);\n        if (activate != null) {\n            cachedActivates.put(name, activate);\n        } else if (Dubbo2CompactUtils.isEnabled() && Dubbo2ActivateUtils.isActivateLoaded()) {\n            // support com.alibaba.dubbo.common.extension.Activate\n            Annotation oldActivate = clazz.getAnnotation(Dubbo2ActivateUtils.getActivateClass());\n            if (oldActivate != null) {\n                cachedActivates.put(name, oldActivate);\n            }\n        }\n    }\n\n    /**\n     * cache Adaptive class which is annotated with <code>Adaptive</code>\n     */\n    private void cacheAdaptiveClass(Class<?> clazz, boolean overridden) {\n        if (cachedAdaptiveClass == null || overridden) {\n            cachedAdaptiveClass = clazz;\n        } else if (!cachedAdaptiveClass.equals(clazz)) {\n            throw new IllegalStateException(\n                    \"More than 1 adaptive class found: \" + cachedAdaptiveClass.getName() + \", \" + clazz.getName());\n        }\n    }\n\n    /**\n     * cache wrapper class\n     * <p>\n     * like: ProtocolFilterWrapper, ProtocolListenerWrapper\n     */\n    private void cacheWrapperClass(Class<?> clazz) {\n        if (cachedWrapperClasses == null) {\n            cachedWrapperClasses = new ConcurrentHashSet<>();\n        }\n        cachedWrapperClasses.add(clazz);\n    }\n\n    /**\n     * test if clazz is a wrapper class\n     * <p>\n     * which has Constructor with given class type as its only argument\n     */\n    protected boolean isWrapperClass(Class<?> clazz) {\n        Constructor<?>[] constructors = clazz.getConstructors();\n        for (Constructor<?> constructor : constructors) {\n            if (constructor.getParameterTypes().length == 1 && constructor.getParameterTypes()[0] == type) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private String findAnnotationName(Class<?> clazz) {\n        Extension extension = clazz.getAnnotation(Extension.class);\n        if (extension != null) {\n            return extension.value();\n        }\n\n        String name = clazz.getSimpleName();\n        if (name.endsWith(type.getSimpleName())) {\n            name = name.substring(0, name.length() - type.getSimpleName().length());\n        }\n        return name.toLowerCase();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private T createAdaptiveExtension() {\n        try {\n            T instance = (T) getAdaptiveExtensionClass().newInstance();\n            instance = postProcessBeforeInitialization(instance, null);\n            injectExtension(instance);\n            instance = postProcessAfterInitialization(instance, null);\n            initExtension(instance);\n            return instance;\n        } catch (Exception e) {\n            throw new IllegalStateException(\n                    \"Can't create adaptive extension \" + type + \", cause: \" + e.getMessage(), e);\n        }\n    }\n\n    private Class<?> getAdaptiveExtensionClass() {\n        getExtensionClasses();\n        if (cachedAdaptiveClass != null) {\n            return cachedAdaptiveClass;\n        }\n        return cachedAdaptiveClass = createAdaptiveExtensionClass();\n    }\n\n    private Class<?> createAdaptiveExtensionClass() {\n        // Adaptive Classes' ClassLoader should be the same with Real SPI interface classes' ClassLoader\n        ClassLoader classLoader = type.getClassLoader();\n        try {\n            if (NativeDetector.inNativeImage()) {\n                return classLoader.loadClass(type.getName() + \"$Adaptive\");\n            }\n        } catch (Throwable ignore) {\n\n        }\n        String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();\n        org.apache.dubbo.common.compiler.Compiler compiler = extensionDirector\n                .getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class)\n                .getAdaptiveExtension();\n        return compiler.compile(type, code, classLoader);\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \"[\" + type.getName() + \"]\";\n    }\n\n    private static Properties loadProperties(ClassLoader classLoader, String resourceName) {\n        Properties properties = new Properties();\n        if (classLoader != null) {\n            try {\n                Enumeration<java.net.URL> resources = classLoader.getResources(resourceName);\n                while (resources.hasMoreElements()) {\n                    java.net.URL url = resources.nextElement();\n                    Properties props = loadFromUrl(url);\n                    for (Map.Entry<Object, Object> entry : props.entrySet()) {\n                        String key = entry.getKey().toString();\n                        if (properties.containsKey(key)) {\n                            continue;\n                        }\n                        properties.put(key, entry.getValue().toString());\n                    }\n                }\n            } catch (IOException ex) {\n                logger.error(CONFIG_FAILED_LOAD_ENV_VARIABLE, \"\", \"\", \"load properties failed.\", ex);\n            }\n        }\n\n        return properties;\n    }\n\n    private static Properties loadFromUrl(java.net.URL url) {\n        Properties properties = new Properties();\n        InputStream is = null;\n        try {\n            is = url.openStream();\n            properties.load(is);\n        } catch (IOException e) {\n            // ignore\n        } finally {\n            if (is != null) {\n                try {\n                    is.close();\n                } catch (IOException e) {\n                    // ignore\n                }\n            }\n        }\n        return properties;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n/**\n * A Post-processor called before or after extension initialization.\n */\npublic interface ExtensionPostProcessor {\n\n    default Object postProcessBeforeInitialization(Object instance, String name) throws Exception {\n        return instance;\n    }\n\n    default Object postProcessAfterInitialization(Object instance, String name) throws Exception {\n        return instance;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionScope.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\n/**\n * Extension SPI Scope\n * @see SPI\n * @see ExtensionDirector\n */\npublic enum ExtensionScope {\n\n    /**\n     * The extension instance is used within framework, shared with all applications and modules.\n     *\n     * <p>Framework scope SPI extension can only obtain {@link FrameworkModel},\n     * cannot get the {@link ApplicationModel} and {@link ModuleModel}.</p>\n     *\n     * <p></p>\n     * Consideration:\n     * <ol>\n     * <li>Some SPI need share data between applications inside framework</li>\n     * <li>Stateless SPI is safe shared inside framework</li>\n     * </ol>\n     */\n    FRAMEWORK,\n\n    /**\n     * The extension instance is used within one application, shared with all modules of the application,\n     * and different applications create different extension instances.\n     *\n     * <p>Application scope SPI extension can obtain {@link FrameworkModel} and {@link ApplicationModel},\n     * cannot get the {@link ModuleModel}.</p>\n     *\n     * <p></p>\n     * Consideration:\n     * <ol>\n     * <li>Isolate extension data in different applications inside framework</li>\n     * <li>Share extension data between all modules inside application</li>\n     * </ol>\n     */\n    APPLICATION,\n\n    /**\n     * The extension instance is used within one module, and different modules create different extension instances.\n     *\n     * <p>Module scope SPI extension can obtain {@link FrameworkModel}, {@link ApplicationModel} and {@link ModuleModel}.</p>\n     *\n     * <p></p>\n     * Consideration:\n     * <ol>\n     * <li>Isolate extension data in different modules inside application</li>\n     * </ol>\n     */\n    MODULE,\n\n    /**\n     * self-sufficient, creates an instance for per scope, for special SPI extension, like {@link ExtensionInjector}\n     */\n    SELF\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/LoadingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.lang.Prioritized;\n\npublic interface LoadingStrategy extends Prioritized {\n\n    String directory();\n\n    default boolean preferExtensionClassLoader() {\n        return false;\n    }\n\n    default String[] excludedPackages() {\n        return null;\n    }\n\n    /**\n     * To restrict some class that should not be loaded from `org.apache.dubbo` package type SPI class.\n     * For example, we can restrict the implementation class which package is `org.xxx.xxx`\n     * can be loaded as SPI implementation.\n     *\n     * @return packages can be loaded in `org.apache.dubbo`'s SPI\n     */\n    default String[] includedPackages() {\n        // default match all\n        return null;\n    }\n\n    /**\n     * To restrict some class that should not be loaded from `org.alibaba.dubbo`(for compatible purpose)\n     * package type SPI class.\n     * For example, we can restrict the implementation class which package is `org.xxx.xxx`\n     * can be loaded as SPI implementation\n     *\n     * @return packages can be loaded in `org.alibaba.dubbo`'s SPI\n     */\n    default String[] includedPackagesInCompatibleType() {\n        // default match all\n        return null;\n    }\n\n    /**\n     * To restrict some class that should load from Dubbo's ClassLoader.\n     * For example, we can restrict the class declaration in `org.apache.dubbo` package should\n     * be loaded from Dubbo's ClassLoader and users cannot declare these classes.\n     *\n     * @return class packages should load\n     * @since 3.0.4\n     */\n    default String[] onlyExtensionClassLoaderPackages() {\n        return new String[] {};\n    }\n\n    /**\n     * Indicates current {@link LoadingStrategy} supports overriding other lower prioritized instances or not.\n     *\n     * @return if supports, return <code>true</code>, or <code>false</code>\n     * @since 2.7.7\n     */\n    default boolean overridden() {\n        return false;\n    }\n\n    default String getName() {\n        return this.getClass().getSimpleName();\n    }\n\n    /**\n     * when spi is loaded by dubbo framework classloader only, it indicates all LoadingStrategy should load this spi\n     */\n    String ALL = \"ALL\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/SPI.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Marker for extension interface\n * <p/>\n * Changes on extension configuration file <br/>\n * Use <code>Protocol</code> as an example, its configuration file 'META-INF/dubbo/com.xxx.Protocol' is changed from: <br/>\n * <pre>\n *     com.foo.XxxProtocol\n *     com.foo.YyyProtocol\n * </pre>\n * <p>\n * to key-value pair <br/>\n * <pre>\n *     xxx=com.foo.XxxProtocol\n *     yyy=com.foo.YyyProtocol\n * </pre>\n * <br/>\n * The reason for this change is:\n * <p>\n * If there's third party library referenced by static field or by method in extension implementation, its class will\n * fail to initialize if the third party library doesn't exist. In this case, dubbo cannot figure out extension's id\n * therefore cannot be able to map the exception information with the extension, if the previous format is used.\n * <p/>\n * For example:\n * <p>\n * Fails to load Extension(\"mina\"). When user configure to use mina, dubbo will complain the extension cannot be loaded,\n * instead of reporting which extract extension implementation fails and the extract reason.\n * </p>\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE})\npublic @interface SPI {\n\n    /**\n     * default extension name\n     */\n    String value() default \"\";\n\n    /**\n     * scope of SPI, default value is application scope.\n     */\n    ExtensionScope scope() default ExtensionScope.APPLICATION;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/ServicesLoadingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n/**\n * Services {@link LoadingStrategy}\n *\n * @since 2.7.7\n */\npublic class ServicesLoadingStrategy implements LoadingStrategy {\n\n    @Override\n    public String directory() {\n        return \"META-INF/services/\";\n    }\n\n    @Override\n    public boolean overridden() {\n        return true;\n    }\n\n    @Override\n    public int getPriority() {\n        return MIN_PRIORITY;\n    }\n\n    @Override\n    public String getName() {\n        return \"SERVICES\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/Wrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * The annotated class will only work as a wrapper when the condition matches.\n */\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Wrapper {\n\n    /**\n     * the extension names that need to be wrapped.\n     * default is matching when this array is empty.\n     */\n    String[] matches() default {};\n\n    /**\n     * the extension names that need to be excluded.\n     */\n    String[] mismatches() default {};\n\n    /**\n     * absolute ordering, optional\n     * ascending order, smaller values will be in the front of the list.\n     * @return\n     */\n    int order() default 0;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/inject/AdaptiveExtensionInjector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.inject;\n\nimport org.apache.dubbo.common.context.Lifecycle;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionAccessor;\nimport org.apache.dubbo.common.extension.ExtensionInjector;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\n@Adaptive\npublic class AdaptiveExtensionInjector implements ExtensionInjector, Lifecycle {\n\n    private Collection<ExtensionInjector> injectors = Collections.emptyList();\n    private ExtensionAccessor extensionAccessor;\n\n    public AdaptiveExtensionInjector() {}\n\n    @Override\n    public void setExtensionAccessor(final ExtensionAccessor extensionAccessor) {\n        this.extensionAccessor = extensionAccessor;\n    }\n\n    @Override\n    public void initialize() throws IllegalStateException {\n        ExtensionLoader<ExtensionInjector> loader = extensionAccessor.getExtensionLoader(ExtensionInjector.class);\n        injectors = loader.getSupportedExtensions().stream()\n                .map(loader::getExtension)\n                .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));\n    }\n\n    @Override\n    public <T> T getInstance(final Class<T> type, final String name) {\n        return injectors.stream()\n                .map(injector -> injector.getInstance(type, name))\n                .filter(Objects::nonNull)\n                .findFirst()\n                .orElse(null);\n    }\n\n    @Override\n    public void start() throws IllegalStateException {}\n\n    @Override\n    public void destroy() throws IllegalStateException {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/inject/SpiExtensionInjector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.inject;\n\nimport org.apache.dubbo.common.extension.ExtensionAccessor;\nimport org.apache.dubbo.common.extension.ExtensionInjector;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.SPI;\n\npublic class SpiExtensionInjector implements ExtensionInjector {\n\n    private ExtensionAccessor extensionAccessor;\n\n    @Override\n    public void setExtensionAccessor(final ExtensionAccessor extensionAccessor) {\n        this.extensionAccessor = extensionAccessor;\n    }\n\n    @Override\n    public <T> T getInstance(final Class<T> type, final String name) {\n        if (!type.isInterface() || !type.isAnnotationPresent(SPI.class)) {\n            return null;\n        }\n        ExtensionLoader<T> loader = extensionAccessor.getExtensionLoader(type);\n        if (loader == null) {\n            return null;\n        }\n        if (!loader.getSupportedExtensions().isEmpty()) {\n            return loader.getAdaptiveExtension();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/support/ActivateComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.compact.Dubbo2ActivateUtils;\nimport org.apache.dubbo.common.compact.Dubbo2CompactUtils;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.ExtensionDirector;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.utils.ArrayUtils;\n\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * OrderComparator\n */\npublic class ActivateComparator implements Comparator<Class<?>> {\n\n    private final List<ExtensionDirector> extensionDirectors;\n    private final Map<Class<?>, ActivateInfo> activateInfoMap = new ConcurrentHashMap<>();\n\n    public ActivateComparator(ExtensionDirector extensionDirector) {\n        extensionDirectors = new ArrayList<>();\n        extensionDirectors.add(extensionDirector);\n    }\n\n    public ActivateComparator(List<ExtensionDirector> extensionDirectors) {\n        this.extensionDirectors = extensionDirectors;\n    }\n\n    @Override\n    public int compare(Class o1, Class o2) {\n        if (o1 == null && o2 == null) {\n            return 0;\n        }\n        if (o1 == null) {\n            return -1;\n        }\n        if (o2 == null) {\n            return 1;\n        }\n        if (o1.equals(o2)) {\n            return 0;\n        }\n\n        Class<?> inf = findSpi(o1);\n\n        ActivateInfo a1 = parseActivate(o1);\n        ActivateInfo a2 = parseActivate(o2);\n\n        if ((a1.applicableToCompare() || a2.applicableToCompare()) && inf != null) {\n            if (a1.applicableToCompare()) {\n                String n2 = null;\n                for (ExtensionDirector director : extensionDirectors) {\n                    ExtensionLoader<?> extensionLoader = director.getExtensionLoader(inf);\n                    n2 = extensionLoader.getExtensionName(o2);\n                    if (n2 != null) {\n                        break;\n                    }\n                }\n\n                if (a1.isLess(n2)) {\n                    return -1;\n                }\n\n                if (a1.isMore(n2)) {\n                    return 1;\n                }\n            }\n\n            if (a2.applicableToCompare()) {\n                String n1 = null;\n                for (ExtensionDirector director : extensionDirectors) {\n                    ExtensionLoader<?> extensionLoader = director.getExtensionLoader(inf);\n                    n1 = extensionLoader.getExtensionName(o1);\n                    if (n1 != null) {\n                        break;\n                    }\n                }\n\n                if (a2.isLess(n1)) {\n                    return 1;\n                }\n\n                if (a2.isMore(n1)) {\n                    return -1;\n                }\n            }\n\n            return a1.order > a2.order ? 1 : -1;\n        }\n\n        // In order to avoid the problem of inconsistency between the loading order of two filters\n        // in different loading scenarios without specifying the order attribute of the filter,\n        // when the order is the same, compare its filterName\n        if (a1.order > a2.order) {\n            return 1;\n        } else if (a1.order == a2.order) {\n            return o1.getSimpleName().compareTo(o2.getSimpleName()) > 0 ? 1 : -1;\n        } else {\n            return -1;\n        }\n    }\n\n    private Class<?> findSpi(Class<?> clazz) {\n        if (clazz.getInterfaces().length == 0) {\n            return null;\n        }\n\n        for (Class<?> intf : clazz.getInterfaces()) {\n            if (intf.isAnnotationPresent(SPI.class)) {\n                return intf;\n            }\n            Class<?> result = findSpi(intf);\n            if (result != null) {\n                return result;\n            }\n        }\n\n        return null;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private ActivateInfo parseActivate(Class<?> clazz) {\n        ActivateInfo info = activateInfoMap.get(clazz);\n        if (info != null) {\n            return info;\n        }\n        info = new ActivateInfo();\n        if (clazz.isAnnotationPresent(Activate.class)) {\n            Activate activate = clazz.getAnnotation(Activate.class);\n            info.before = activate.before();\n            info.after = activate.after();\n            info.order = activate.order();\n        } else if (Dubbo2CompactUtils.isEnabled()\n                && Dubbo2ActivateUtils.isActivateLoaded()\n                && clazz.isAnnotationPresent(Dubbo2ActivateUtils.getActivateClass())) {\n            Annotation activate = clazz.getAnnotation(Dubbo2ActivateUtils.getActivateClass());\n            info.before = Dubbo2ActivateUtils.getBefore(activate);\n            info.after = Dubbo2ActivateUtils.getAfter(activate);\n            info.order = Dubbo2ActivateUtils.getOrder(activate);\n        } else {\n            info.order = 0;\n        }\n        activateInfoMap.put(clazz, info);\n        return info;\n    }\n\n    private static class ActivateInfo {\n        private String[] before;\n        private String[] after;\n        private int order;\n\n        private boolean applicableToCompare() {\n            return ArrayUtils.isNotEmpty(before) || ArrayUtils.isNotEmpty(after);\n        }\n\n        private boolean isLess(String name) {\n            return Arrays.asList(before).contains(name);\n        }\n\n        private boolean isMore(String name) {\n            return Arrays.asList(after).contains(name);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/extension/support/WrapperComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.compact.Dubbo2ActivateUtils;\nimport org.apache.dubbo.common.compact.Dubbo2CompactUtils;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.Wrapper;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Comparator;\n\n/**\n * OrderComparator\n * Derived from {@link ActivateComparator}\n */\npublic class WrapperComparator implements Comparator<Object> {\n\n    public static final Comparator<Object> COMPARATOR = new WrapperComparator();\n\n    @Override\n    public int compare(Object o1, Object o2) {\n        if (o1 == null && o2 == null) {\n            return 0;\n        }\n        if (o1 == null) {\n            return -1;\n        }\n        if (o2 == null) {\n            return 1;\n        }\n        if (o1.equals(o2)) {\n            return 0;\n        }\n\n        Class clazz1 = (Class) o1;\n        Class clazz2 = (Class) o2;\n\n        OrderInfo a1 = parseOrder(clazz1);\n        OrderInfo a2 = parseOrder(clazz2);\n\n        int n1 = a1.order;\n        int n2 = a2.order;\n        // never return 0 even if n1 equals n2, otherwise, o1 and o2 will override each other in collection like HashSet\n        return n1 > n2 ? 1 : -1;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private OrderInfo parseOrder(Class<?> clazz) {\n        OrderInfo info = new OrderInfo();\n        if (clazz.isAnnotationPresent(Activate.class)) {\n            // TODO: backward compatibility\n            Activate activate = clazz.getAnnotation(Activate.class);\n            info.order = activate.order();\n        } else if (Dubbo2CompactUtils.isEnabled()\n                && Dubbo2ActivateUtils.isActivateLoaded()\n                && clazz.isAnnotationPresent(Dubbo2ActivateUtils.getActivateClass())) {\n            // TODO: backward compatibility\n            Annotation activate = clazz.getAnnotation(Dubbo2ActivateUtils.getActivateClass());\n            info.order = Dubbo2ActivateUtils.getOrder(activate);\n        } else if (clazz.isAnnotationPresent(Wrapper.class)) {\n            Wrapper wrapper = clazz.getAnnotation(Wrapper.class);\n            info.order = wrapper.order();\n        }\n        return info;\n    }\n\n    private static class OrderInfo {\n        private int order;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/function/Predicates.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.function;\n\nimport java.util.function.Predicate;\n\nimport static java.util.stream.Stream.of;\n\n/**\n * The utilities class for Java {@link Predicate}\n *\n * @since 2.7.5\n */\npublic interface Predicates {\n\n    Predicate[] EMPTY_ARRAY = new Predicate[0];\n\n    /**\n     * {@link Predicate} always return <code>true</code>\n     *\n     * @param <T> the type to test\n     * @return <code>true</code>\n     */\n    static <T> Predicate<T> alwaysTrue() {\n        return e -> true;\n    }\n\n    /**\n     * {@link Predicate} always return <code>false</code>\n     *\n     * @param <T> the type to test\n     * @return <code>false</code>\n     */\n    static <T> Predicate<T> alwaysFalse() {\n        return e -> false;\n    }\n\n    /**\n     * a composed predicate that represents a short-circuiting logical AND of {@link Predicate predicates}\n     *\n     * @param predicates {@link Predicate predicates}\n     * @param <T>        the type to test\n     * @return non-null\n     */\n    static <T> Predicate<T> and(Predicate<T>... predicates) {\n        return of(predicates).reduce(Predicate::and).orElseGet(Predicates::alwaysTrue);\n    }\n\n    /**\n     * a composed predicate that represents a short-circuiting logical OR of {@link Predicate predicates}\n     *\n     * @param predicates {@link Predicate predicates}\n     * @param <T>        the detected type\n     * @return non-null\n     */\n    static <T> Predicate<T> or(Predicate<T>... predicates) {\n        return of(predicates).reduce(Predicate::or).orElse(e -> true);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/function/Streams.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.function;\n\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Predicate;\nimport java.util.stream.Stream;\n\nimport static java.util.stream.Collectors.toList;\nimport static java.util.stream.StreamSupport.stream;\nimport static org.apache.dubbo.common.function.Predicates.and;\nimport static org.apache.dubbo.common.function.Predicates.or;\n\n/**\n * The utilities class for {@link Stream}\n *\n * @since 2.7.5\n */\npublic interface Streams {\n\n    static <T, S extends Iterable<T>> Stream<T> filterStream(S values, Predicate<T> predicate) {\n        return stream(values.spliterator(), false).filter(predicate);\n    }\n\n    static <T, S extends Iterable<T>> List<T> filterList(S values, Predicate<T> predicate) {\n        return filterStream(values, predicate).collect(toList());\n    }\n\n    static <T, S extends Iterable<T>> Set<T> filterSet(S values, Predicate<T> predicate) {\n        // new Set with insertion order\n        return filterStream(values, predicate).collect(LinkedHashSet::new, Set::add, Set::addAll);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    static <T, S extends Iterable<T>> S filter(S values, Predicate<T> predicate) {\n        final boolean isSet = Set.class.isAssignableFrom(values.getClass());\n        return (S) (isSet ? filterSet(values, predicate) : filterList(values, predicate));\n    }\n\n    static <T, S extends Iterable<T>> S filterAll(S values, Predicate<T>... predicates) {\n        return filter(values, and(predicates));\n    }\n\n    static <T, S extends Iterable<T>> S filterAny(S values, Predicate<T>... predicates) {\n        return filter(values, or(predicates));\n    }\n\n    static <T> T filterFirst(Iterable<T> values, Predicate<T>... predicates) {\n        return stream(values.spliterator(), false)\n                .filter(and(predicates))\n                .findFirst()\n                .orElse(null);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableAction.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.function;\n\nimport java.util.function.Function;\n\n/**\n * A function interface for action with {@link Throwable}\n *\n * @see Function\n * @see Throwable\n * @since 2.7.5\n */\n@FunctionalInterface\npublic interface ThrowableAction {\n\n    /**\n     * Executes the action\n     *\n     * @throws Throwable if met with error\n     */\n    void execute() throws Throwable;\n\n    /**\n     * Executes {@link ThrowableAction}\n     *\n     * @param action {@link ThrowableAction}\n     * @throws RuntimeException wrap {@link Exception} to {@link RuntimeException}\n     */\n    static void execute(ThrowableAction action) throws RuntimeException {\n        try {\n            action.execute();\n        } catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableConsumer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.function;\n\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\n/**\n * {@link Consumer} with {@link Throwable}\n *\n * @param <T> the source type\n * @see Function\n * @see Throwable\n * @since 2.7.5\n */\n@FunctionalInterface\npublic interface ThrowableConsumer<T> {\n\n    /**\n     * Applies this function to the given argument.\n     *\n     * @param t the function argument\n     * @throws Throwable if met with any error\n     */\n    void accept(T t) throws Throwable;\n\n    /**\n     * Executes {@link ThrowableConsumer}\n     *\n     * @param t the function argument\n     * @throws RuntimeException wrappers {@link Throwable}\n     */\n    default void execute(T t) throws RuntimeException {\n        try {\n            accept(t);\n        } catch (Throwable e) {\n            throw new RuntimeException(e.getMessage(), e.getCause());\n        }\n    }\n\n    /**\n     * Executes {@link ThrowableConsumer}\n     *\n     * @param t        the function argument\n     * @param consumer {@link ThrowableConsumer}\n     * @param <T>      the source type\n     */\n    static <T> void execute(T t, ThrowableConsumer<T> consumer) {\n        consumer.execute(t);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableFunction.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.function;\n\nimport java.util.function.Function;\n\n/**\n * {@link Function} with {@link Throwable}\n *\n * @param <T> the source type\n * @param <R> the return type\n * @see Function\n * @see Throwable\n * @since 2.7.5\n */\n@FunctionalInterface\npublic interface ThrowableFunction<T, R> {\n\n    /**\n     * Applies this function to the given argument.\n     *\n     * @param t the function argument\n     * @return the function result\n     * @throws Throwable if met with any error\n     */\n    R apply(T t) throws Throwable;\n\n    /**\n     * Executes {@link ThrowableFunction}\n     *\n     * @param t the function argument\n     * @return the function result\n     * @throws RuntimeException wrappers {@link Throwable}\n     */\n    default R execute(T t) throws RuntimeException {\n        R result = null;\n        try {\n            result = apply(t);\n        } catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n        return result;\n    }\n\n    /**\n     * Executes {@link ThrowableFunction}\n     *\n     * @param t        the function argument\n     * @param function {@link ThrowableFunction}\n     * @param <T>      the source type\n     * @param <R>      the return type\n     * @return the result after execution\n     */\n    static <T, R> R execute(T t, ThrowableFunction<T, R> function) {\n        return function.execute(t);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/infra/InfraAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.infra;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.Map;\n\n/**\n * Used to interact with other systems. Typical use cases are:\n * 1. get extra attributes from underlying infrastructures related to the instance on which Dubbo is currently deploying.\n * 2. get configurations from third-party systems which maybe useful for a specific component.\n */\n@SPI(scope = ExtensionScope.APPLICATION)\npublic interface InfraAdapter {\n\n    /**\n     * get extra attributes\n     *\n     * @param params application name or hostname are most likely to be used as input params.\n     * @return\n     */\n    Map<String, String> getExtraAttributes(Map<String, String> params);\n\n    /**\n     * @param key\n     * @return\n     */\n    String getAttribute(String key);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/infra/support/EnvironmentAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.infra.support;\n\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.infra.InfraAdapter;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_ENV_KEYS;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_LABELS;\nimport static org.apache.dubbo.common.constants.CommonConstants.EQUAL_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.SEMICOLON_SPLIT_PATTERN;\n\n@Activate\npublic class EnvironmentAdapter implements InfraAdapter, ScopeModelAware {\n\n    private ApplicationModel applicationModel;\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    /**\n     * 1. OS Environment: DUBBO_LABELS=tag=pre;key=value\n     * 2. JVM Options: -Denv_keys = DUBBO_KEY1, DUBBO_KEY2\n     *\n     * @param params information of this Dubbo process, currently includes application name and host address.\n     */\n    @Override\n    public Map<String, String> getExtraAttributes(Map<String, String> params) {\n        Map<String, String> parameters = new HashMap<>();\n\n        String rawLabels = ConfigurationUtils.getProperty(applicationModel, DUBBO_LABELS);\n        if (StringUtils.isNotEmpty(rawLabels)) {\n            String[] labelPairs = SEMICOLON_SPLIT_PATTERN.split(rawLabels);\n            for (String pair : labelPairs) {\n                String[] label = EQUAL_SPLIT_PATTERN.split(pair);\n                if (label.length == 2) {\n                    parameters.put(label[0], label[1]);\n                }\n            }\n        }\n\n        String rawKeys = ConfigurationUtils.getProperty(applicationModel, DUBBO_ENV_KEYS);\n        if (StringUtils.isNotEmpty(rawKeys)) {\n            String[] keys = COMMA_SPLIT_PATTERN.split(rawKeys);\n            for (String key : keys) {\n                String value = ConfigurationUtils.getProperty(applicationModel, key);\n                if (value != null) {\n                    // since 3.2\n                    parameters.put(key.toLowerCase(), value);\n                    // upper-case key kept for compatibility\n                    parameters.put(key, value);\n                }\n            }\n        }\n        return parameters;\n    }\n\n    @Override\n    public String getAttribute(String key) {\n        return ConfigurationUtils.getProperty(applicationModel, key);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/io/Bytes.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport org.apache.dubbo.common.utils.IOUtils;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.zip.DeflaterOutputStream;\nimport java.util.zip.InflaterInputStream;\n\n/**\n * CodecUtils.\n */\npublic class Bytes {\n    private static final String C64 =\n            \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\"; // default base64.\n\n    private static final char[]\n            BASE16 = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'},\n            BASE64 = C64.toCharArray();\n    private static final int MASK4 = 0x0f, MASK6 = 0x3f, MASK8 = 0xff;\n\n    private static final Map<Integer, byte[]> DECODE_TABLE_MAP = new ConcurrentHashMap<>();\n\n    private static final ThreadLocal<MessageDigest> MD = new ThreadLocal<>();\n\n    private Bytes() {}\n\n    /**\n     * byte array copy.\n     *\n     * @param src    src.\n     * @param length new length.\n     * @return new byte array.\n     */\n    public static byte[] copyOf(byte[] src, int length) {\n        byte[] dest = new byte[length];\n        System.arraycopy(src, 0, dest, 0, Math.min(src.length, length));\n        return dest;\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @return byte[].\n     */\n    public static byte[] short2bytes(short v) {\n        byte[] ret = {0, 0};\n        short2bytes(v, ret);\n        return ret;\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @param b byte array.\n     */\n    public static void short2bytes(short v, byte[] b) {\n        short2bytes(v, b, 0);\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @param b byte array.\n     */\n    public static void short2bytes(short v, byte[] b, int off) {\n        b[off + 1] = (byte) v;\n        b[off + 0] = (byte) (v >>> 8);\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @return byte[].\n     */\n    public static byte[] int2bytes(int v) {\n        byte[] ret = {0, 0, 0, 0};\n        int2bytes(v, ret);\n        return ret;\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @param b byte array.\n     */\n    public static void int2bytes(int v, byte[] b) {\n        int2bytes(v, b, 0);\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v   value.\n     * @param b   byte array.\n     * @param off array offset.\n     */\n    public static void int2bytes(int v, byte[] b, int off) {\n        b[off + 3] = (byte) v;\n        b[off + 2] = (byte) (v >>> 8);\n        b[off + 1] = (byte) (v >>> 16);\n        b[off + 0] = (byte) (v >>> 24);\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @return byte[].\n     */\n    public static byte[] float2bytes(float v) {\n        byte[] ret = {0, 0, 0, 0};\n        float2bytes(v, ret);\n        return ret;\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @param b byte array.\n     */\n    public static void float2bytes(float v, byte[] b) {\n        float2bytes(v, b, 0);\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v   value.\n     * @param b   byte array.\n     * @param off array offset.\n     */\n    public static void float2bytes(float v, byte[] b, int off) {\n        int i = Float.floatToIntBits(v);\n        b[off + 3] = (byte) i;\n        b[off + 2] = (byte) (i >>> 8);\n        b[off + 1] = (byte) (i >>> 16);\n        b[off + 0] = (byte) (i >>> 24);\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @return byte[].\n     */\n    public static byte[] long2bytes(long v) {\n        byte[] ret = {0, 0, 0, 0, 0, 0, 0, 0};\n        long2bytes(v, ret);\n        return ret;\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @param b byte array.\n     */\n    public static void long2bytes(long v, byte[] b) {\n        long2bytes(v, b, 0);\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v   value.\n     * @param b   byte array.\n     * @param off array offset.\n     */\n    public static void long2bytes(long v, byte[] b, int off) {\n        b[off + 7] = (byte) v;\n        b[off + 6] = (byte) (v >>> 8);\n        b[off + 5] = (byte) (v >>> 16);\n        b[off + 4] = (byte) (v >>> 24);\n        b[off + 3] = (byte) (v >>> 32);\n        b[off + 2] = (byte) (v >>> 40);\n        b[off + 1] = (byte) (v >>> 48);\n        b[off + 0] = (byte) (v >>> 56);\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @return byte[].\n     */\n    public static byte[] double2bytes(double v) {\n        byte[] ret = {0, 0, 0, 0, 0, 0, 0, 0};\n        double2bytes(v, ret);\n        return ret;\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v value.\n     * @param b byte array.\n     */\n    public static void double2bytes(double v, byte[] b) {\n        double2bytes(v, b, 0);\n    }\n\n    /**\n     * to byte array.\n     *\n     * @param v   value.\n     * @param b   byte array.\n     * @param off array offset.\n     */\n    public static void double2bytes(double v, byte[] b, int off) {\n        long j = Double.doubleToLongBits(v);\n        b[off + 7] = (byte) j;\n        b[off + 6] = (byte) (j >>> 8);\n        b[off + 5] = (byte) (j >>> 16);\n        b[off + 4] = (byte) (j >>> 24);\n        b[off + 3] = (byte) (j >>> 32);\n        b[off + 2] = (byte) (j >>> 40);\n        b[off + 1] = (byte) (j >>> 48);\n        b[off + 0] = (byte) (j >>> 56);\n    }\n\n    /**\n     * to short.\n     *\n     * @param b byte array.\n     * @return short.\n     */\n    public static short bytes2short(byte[] b) {\n        return bytes2short(b, 0);\n    }\n\n    /**\n     * to short.\n     *\n     * @param b   byte array.\n     * @param off offset.\n     * @return short.\n     */\n    public static short bytes2short(byte[] b, int off) {\n        return (short) (((b[off + 1] & 0xFF) << 0) + ((b[off + 0]) << 8));\n    }\n\n    /**\n     * to int.\n     *\n     * @param b byte array.\n     * @return int.\n     */\n    public static int bytes2int(byte[] b) {\n        return bytes2int(b, 0);\n    }\n\n    /**\n     * to int.\n     *\n     * @param b   byte array.\n     * @param off offset.\n     * @return int.\n     */\n    public static int bytes2int(byte[] b, int off) {\n        return ((b[off + 3] & 0xFF) << 0)\n                + ((b[off + 2] & 0xFF) << 8)\n                + ((b[off + 1] & 0xFF) << 16)\n                + ((b[off + 0]) << 24);\n    }\n\n    /**\n     * to int.\n     *\n     * @param b byte array.\n     * @return int.\n     */\n    public static float bytes2float(byte[] b) {\n        return bytes2float(b, 0);\n    }\n\n    /**\n     * to int.\n     *\n     * @param b   byte array.\n     * @param off offset.\n     * @return int.\n     */\n    public static float bytes2float(byte[] b, int off) {\n        int i = ((b[off + 3] & 0xFF) << 0)\n                + ((b[off + 2] & 0xFF) << 8)\n                + ((b[off + 1] & 0xFF) << 16)\n                + ((b[off + 0]) << 24);\n        return Float.intBitsToFloat(i);\n    }\n\n    /**\n     * to long.\n     *\n     * @param b byte array.\n     * @return long.\n     */\n    public static long bytes2long(byte[] b) {\n        return bytes2long(b, 0);\n    }\n\n    /**\n     * to long.\n     *\n     * @param b   byte array.\n     * @param off offset.\n     * @return long.\n     */\n    public static long bytes2long(byte[] b, int off) {\n        return ((b[off + 7] & 0xFFL) << 0)\n                + ((b[off + 6] & 0xFFL) << 8)\n                + ((b[off + 5] & 0xFFL) << 16)\n                + ((b[off + 4] & 0xFFL) << 24)\n                + ((b[off + 3] & 0xFFL) << 32)\n                + ((b[off + 2] & 0xFFL) << 40)\n                + ((b[off + 1] & 0xFFL) << 48)\n                + (((long) b[off + 0]) << 56);\n    }\n\n    /**\n     * to long.\n     *\n     * @param b byte array.\n     * @return double.\n     */\n    public static double bytes2double(byte[] b) {\n        return bytes2double(b, 0);\n    }\n\n    /**\n     * to long.\n     *\n     * @param b   byte array.\n     * @param off offset.\n     * @return double.\n     */\n    public static double bytes2double(byte[] b, int off) {\n        long j = ((b[off + 7] & 0xFFL) << 0)\n                + ((b[off + 6] & 0xFFL) << 8)\n                + ((b[off + 5] & 0xFFL) << 16)\n                + ((b[off + 4] & 0xFFL) << 24)\n                + ((b[off + 3] & 0xFFL) << 32)\n                + ((b[off + 2] & 0xFFL) << 40)\n                + ((b[off + 1] & 0xFFL) << 48)\n                + (((long) b[off + 0]) << 56);\n        return Double.longBitsToDouble(j);\n    }\n\n    /**\n     * to hex string.\n     *\n     * @param bs byte array.\n     * @return hex string.\n     */\n    public static String bytes2hex(byte[] bs) {\n        return bytes2hex(bs, 0, bs.length);\n    }\n\n    /**\n     * to hex string.\n     *\n     * @param bs  byte array.\n     * @param off offset.\n     * @param len length.\n     * @return hex string.\n     */\n    public static String bytes2hex(byte[] bs, int off, int len) {\n        if (off < 0) {\n            throw new IndexOutOfBoundsException(\"bytes2hex: offset < 0, offset is \" + off);\n        }\n        if (len < 0) {\n            throw new IndexOutOfBoundsException(\"bytes2hex: length < 0, length is \" + len);\n        }\n        if (off + len > bs.length) {\n            throw new IndexOutOfBoundsException(\"bytes2hex: offset + length > array length.\");\n        }\n\n        byte b;\n        int r = off, w = 0;\n        char[] cs = new char[len * 2];\n        for (int i = 0; i < len; i++) {\n            b = bs[r++];\n            cs[w++] = BASE16[b >> 4 & MASK4];\n            cs[w++] = BASE16[b & MASK4];\n        }\n        return new String(cs);\n    }\n\n    /**\n     * from hex string.\n     *\n     * @param str hex string.\n     * @return byte array.\n     */\n    public static byte[] hex2bytes(String str) {\n        return hex2bytes(str, 0, str.length());\n    }\n\n    /**\n     * from hex string.\n     *\n     * @param str hex string.\n     * @param off offset.\n     * @param len length.\n     * @return byte array.\n     */\n    public static byte[] hex2bytes(final String str, final int off, int len) {\n        if ((len & 1) == 1) {\n            throw new IllegalArgumentException(\"hex2bytes: ( len & 1 ) == 1.\");\n        }\n\n        if (off < 0) {\n            throw new IndexOutOfBoundsException(\"hex2bytes: offset < 0, offset is \" + off);\n        }\n        if (len < 0) {\n            throw new IndexOutOfBoundsException(\"hex2bytes: length < 0, length is \" + len);\n        }\n        if (off + len > str.length()) {\n            throw new IndexOutOfBoundsException(\"hex2bytes: offset + length > array length.\");\n        }\n\n        int num = len / 2, r = off, w = 0;\n        byte[] b = new byte[num];\n        for (int i = 0; i < num; i++) {\n            b[w++] = (byte) (hex(str.charAt(r++)) << 4 | hex(str.charAt(r++)));\n        }\n        return b;\n    }\n\n    /**\n     * to base64 string.\n     *\n     * @param b byte array.\n     * @return base64 string.\n     */\n    public static String bytes2base64(byte[] b) {\n        return bytes2base64(b, 0, b.length, BASE64);\n    }\n\n    /**\n     * to base64 string.\n     *\n     * @param b byte array.\n     * @return base64 string.\n     */\n    public static String bytes2base64(byte[] b, int offset, int length) {\n        return bytes2base64(b, offset, length, BASE64);\n    }\n\n    /**\n     * to base64 string.\n     *\n     * @param b    byte array.\n     * @param code base64 code string(0-63 is base64 char,64 is pad char).\n     * @return base64 string.\n     */\n    public static String bytes2base64(byte[] b, String code) {\n        return bytes2base64(b, 0, b.length, code);\n    }\n\n    /**\n     * to base64 string.\n     *\n     * @param b    byte array.\n     * @param code base64 code string(0-63 is base64 char,64 is pad char).\n     * @return base64 string.\n     */\n    public static String bytes2base64(byte[] b, int offset, int length, String code) {\n        if (code.length() < 64) {\n            throw new IllegalArgumentException(\"Base64 code length < 64.\");\n        }\n\n        return bytes2base64(b, offset, length, code.toCharArray());\n    }\n\n    /**\n     * to base64 string.\n     *\n     * @param b    byte array.\n     * @param code base64 code(0-63 is base64 char,64 is pad char).\n     * @return base64 string.\n     */\n    public static String bytes2base64(byte[] b, char[] code) {\n        return bytes2base64(b, 0, b.length, code);\n    }\n\n    /**\n     * to base64 string.\n     *\n     * @param bs   byte array.\n     * @param off  offset.\n     * @param len  length.\n     * @param code base64 code(0-63 is base64 char,64 is pad char).\n     * @return base64 string.\n     */\n    public static String bytes2base64(final byte[] bs, final int off, final int len, final char[] code) {\n        if (off < 0) {\n            throw new IndexOutOfBoundsException(\"bytes2base64: offset < 0, offset is \" + off);\n        }\n        if (len < 0) {\n            throw new IndexOutOfBoundsException(\"bytes2base64: length < 0, length is \" + len);\n        }\n        if (off + len > bs.length) {\n            throw new IndexOutOfBoundsException(\"bytes2base64: offset + length > array length.\");\n        }\n\n        if (code.length < 64) {\n            throw new IllegalArgumentException(\"Base64 code length < 64.\");\n        }\n\n        boolean pad = code.length > 64; // has pad char.\n        int num = len / 3, rem = len % 3, r = off, w = 0;\n        char[] cs = new char[num * 4 + (rem == 0 ? 0 : pad ? 4 : rem + 1)];\n\n        for (int i = 0; i < num; i++) {\n            int b1 = bs[r++] & MASK8, b2 = bs[r++] & MASK8, b3 = bs[r++] & MASK8;\n\n            cs[w++] = code[b1 >> 2];\n            cs[w++] = code[(b1 << 4) & MASK6 | (b2 >> 4)];\n            cs[w++] = code[(b2 << 2) & MASK6 | (b3 >> 6)];\n            cs[w++] = code[b3 & MASK6];\n        }\n\n        if (rem == 1) {\n            int b1 = bs[r++] & MASK8;\n            cs[w++] = code[b1 >> 2];\n            cs[w++] = code[(b1 << 4) & MASK6];\n            if (pad) {\n                cs[w++] = code[64];\n                cs[w++] = code[64];\n            }\n        } else if (rem == 2) {\n            int b1 = bs[r++] & MASK8, b2 = bs[r++] & MASK8;\n            cs[w++] = code[b1 >> 2];\n            cs[w++] = code[(b1 << 4) & MASK6 | (b2 >> 4)];\n            cs[w++] = code[(b2 << 2) & MASK6];\n            if (pad) {\n                cs[w++] = code[64];\n            }\n        }\n        return new String(cs);\n    }\n\n    /**\n     * from base64 string.\n     *\n     * @param str base64 string.\n     * @return byte array.\n     */\n    public static byte[] base642bytes(String str) {\n        return base642bytes(str, 0, str.length());\n    }\n\n    /**\n     * from base64 string.\n     *\n     * @param str    base64 string.\n     * @param offset offset.\n     * @param length length.\n     * @return byte array.\n     */\n    public static byte[] base642bytes(String str, int offset, int length) {\n        return base642bytes(str, offset, length, C64);\n    }\n\n    /**\n     * from base64 string.\n     *\n     * @param str  base64 string.\n     * @param code base64 code(0-63 is base64 char,64 is pad char).\n     * @return byte array.\n     */\n    public static byte[] base642bytes(String str, String code) {\n        return base642bytes(str, 0, str.length(), code);\n    }\n\n    /**\n     * from base64 string.\n     *\n     * @param str  base64 string.\n     * @param off  offset.\n     * @param len  length.\n     * @param code base64 code(0-63 is base64 char,64 is pad char).\n     * @return byte array.\n     */\n    public static byte[] base642bytes(final String str, final int off, final int len, final String code) {\n        if (off < 0) {\n            throw new IndexOutOfBoundsException(\"base642bytes: offset < 0, offset is \" + off);\n        }\n        if (len < 0) {\n            throw new IndexOutOfBoundsException(\"base642bytes: length < 0, length is \" + len);\n        }\n        if (len == 0) {\n            return new byte[0];\n        }\n        if (off + len > str.length()) {\n            throw new IndexOutOfBoundsException(\"base642bytes: offset + length > string length.\");\n        }\n\n        if (code.length() < 64) {\n            throw new IllegalArgumentException(\"Base64 code length < 64.\");\n        }\n\n        int rem = len % 4;\n        if (rem == 1) {\n            throw new IllegalArgumentException(\"base642bytes: base64 string length % 4 == 1.\");\n        }\n\n        int num = len / 4, size = num * 3;\n        if (code.length() > 64) {\n            if (rem != 0) {\n                throw new IllegalArgumentException(\"base642bytes: base64 string length error.\");\n            }\n\n            char pc = code.charAt(64);\n            if (str.charAt(off + len - 2) == pc) {\n                size -= 2;\n                --num;\n                rem = 2;\n            } else if (str.charAt(off + len - 1) == pc) {\n                size--;\n                --num;\n                rem = 3;\n            }\n        } else {\n            if (rem == 2) {\n                size++;\n            } else if (rem == 3) {\n                size += 2;\n            }\n        }\n\n        int r = off, w = 0;\n        byte[] b = new byte[size], t = decodeTable(code);\n        for (int i = 0; i < num; i++) {\n            int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)];\n            int c3 = t[str.charAt(r++)], c4 = t[str.charAt(r++)];\n\n            b[w++] = (byte) ((c1 << 2) | (c2 >> 4));\n            b[w++] = (byte) ((c2 << 4) | (c3 >> 2));\n            b[w++] = (byte) ((c3 << 6) | c4);\n        }\n\n        if (rem == 2) {\n            int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)];\n\n            b[w++] = (byte) ((c1 << 2) | (c2 >> 4));\n        } else if (rem == 3) {\n            int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)], c3 = t[str.charAt(r++)];\n\n            b[w++] = (byte) ((c1 << 2) | (c2 >> 4));\n            b[w++] = (byte) ((c2 << 4) | (c3 >> 2));\n        }\n        return b;\n    }\n\n    /**\n     * from base64 string.\n     *\n     * @param str  base64 string.\n     * @param code base64 code(0-63 is base64 char,64 is pad char).\n     * @return byte array.\n     */\n    public static byte[] base642bytes(String str, char[] code) {\n        return base642bytes(str, 0, str.length(), code);\n    }\n\n    /**\n     * from base64 string.\n     *\n     * @param str  base64 string.\n     * @param off  offset.\n     * @param len  length.\n     * @param code base64 code(0-63 is base64 char,64 is pad char).\n     * @return byte array.\n     */\n    public static byte[] base642bytes(final String str, final int off, final int len, final char[] code) {\n        if (off < 0) {\n            throw new IndexOutOfBoundsException(\"base642bytes: offset < 0, offset is \" + off);\n        }\n        if (len < 0) {\n            throw new IndexOutOfBoundsException(\"base642bytes: length < 0, length is \" + len);\n        }\n        if (len == 0) {\n            return new byte[0];\n        }\n        if (off + len > str.length()) {\n            throw new IndexOutOfBoundsException(\"base642bytes: offset + length > string length.\");\n        }\n\n        if (code.length < 64) {\n            throw new IllegalArgumentException(\"Base64 code length < 64.\");\n        }\n\n        int rem = len % 4;\n        if (rem == 1) {\n            throw new IllegalArgumentException(\"base642bytes: base64 string length % 4 == 1.\");\n        }\n\n        int num = len / 4, size = num * 3;\n        if (code.length > 64) {\n            if (rem != 0) {\n                throw new IllegalArgumentException(\"base642bytes: base64 string length error.\");\n            }\n\n            char pc = code[64];\n            if (str.charAt(off + len - 2) == pc) {\n                size -= 2;\n                --num;\n                rem = 2;\n            } else if (str.charAt(off + len - 1) == pc) {\n                size--;\n                --num;\n                rem = 3;\n            }\n        } else {\n            if (rem == 2) {\n                size++;\n            } else if (rem == 3) {\n                size += 2;\n            }\n        }\n\n        int r = off, w = 0;\n        byte[] b = new byte[size];\n        for (int i = 0; i < num; i++) {\n            int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++));\n            int c3 = indexOf(code, str.charAt(r++)), c4 = indexOf(code, str.charAt(r++));\n\n            b[w++] = (byte) ((c1 << 2) | (c2 >> 4));\n            b[w++] = (byte) ((c2 << 4) | (c3 >> 2));\n            b[w++] = (byte) ((c3 << 6) | c4);\n        }\n\n        if (rem == 2) {\n            int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++));\n\n            b[w++] = (byte) ((c1 << 2) | (c2 >> 4));\n        } else if (rem == 3) {\n            int c1 = indexOf(code, str.charAt(r++)),\n                    c2 = indexOf(code, str.charAt(r++)),\n                    c3 = indexOf(code, str.charAt(r++));\n\n            b[w++] = (byte) ((c1 << 2) | (c2 >> 4));\n            b[w++] = (byte) ((c2 << 4) | (c3 >> 2));\n        }\n        return b;\n    }\n\n    /**\n     * zip.\n     *\n     * @param bytes source.\n     * @return compressed byte array.\n     * @throws IOException\n     */\n    public static byte[] zip(byte[] bytes) throws IOException {\n        UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream();\n        OutputStream os = new DeflaterOutputStream(bos);\n        try {\n            os.write(bytes);\n        } finally {\n            os.close();\n            bos.close();\n        }\n        return bos.toByteArray();\n    }\n\n    /**\n     * unzip.\n     *\n     * @param bytes compressed byte array.\n     * @return byte uncompressed array.\n     * @throws IOException\n     */\n    public static byte[] unzip(byte[] bytes) throws IOException {\n        UnsafeByteArrayInputStream bis = new UnsafeByteArrayInputStream(bytes);\n        UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream();\n        InputStream is = new InflaterInputStream(bis);\n        try {\n            IOUtils.write(is, bos);\n            return bos.toByteArray();\n        } finally {\n            is.close();\n            bis.close();\n            bos.close();\n        }\n    }\n\n    /**\n     * get md5.\n     *\n     * @param str input string.\n     * @return MD5 byte array.\n     */\n    public static byte[] getMD5(String str) {\n        return getMD5(str.getBytes(StandardCharsets.UTF_8));\n    }\n\n    /**\n     * get md5.\n     *\n     * @param source byte array source.\n     * @return MD5 byte array.\n     */\n    public static byte[] getMD5(byte[] source) {\n        MessageDigest md = getMessageDigest();\n        return md.digest(source);\n    }\n\n    /**\n     * get md5.\n     *\n     * @param file file source.\n     * @return MD5 byte array.\n     */\n    public static byte[] getMD5(File file) throws IOException {\n        InputStream is = new FileInputStream(file);\n        try {\n            return getMD5(is);\n        } finally {\n            is.close();\n        }\n    }\n\n    /**\n     * get md5.\n     *\n     * @param is input stream.\n     * @return MD5 byte array.\n     */\n    public static byte[] getMD5(InputStream is) throws IOException {\n        return getMD5(is, 1024 * 8);\n    }\n\n    private static byte hex(char c) {\n        if (c <= '9') {\n            return (byte) (c - '0');\n        }\n        if (c >= 'a' && c <= 'f') {\n            return (byte) (c - 'a' + 10);\n        }\n        if (c >= 'A' && c <= 'F') {\n            return (byte) (c - 'A' + 10);\n        }\n        throw new IllegalArgumentException(\"hex string format error [\" + c + \"].\");\n    }\n\n    private static int indexOf(char[] cs, char c) {\n        for (int i = 0, len = cs.length; i < len; i++) {\n            if (cs[i] == c) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    private static byte[] decodeTable(String code) {\n        int hash = code.hashCode();\n        byte[] ret = DECODE_TABLE_MAP.get(hash);\n        if (ret == null) {\n            if (code.length() < 64) {\n                throw new IllegalArgumentException(\"Base64 code length < 64.\");\n            }\n            // create new decode table.\n            ret = new byte[128];\n            for (int i = 0; i < 128; i++) // init table.\n            {\n                ret[i] = -1;\n            }\n            for (int i = 0; i < 64; i++) {\n                ret[code.charAt(i)] = (byte) i;\n            }\n            DECODE_TABLE_MAP.put(hash, ret);\n        }\n        return ret;\n    }\n\n    private static byte[] getMD5(InputStream is, int bs) throws IOException {\n        MessageDigest md = getMessageDigest();\n        byte[] buf = new byte[bs];\n        while (is.available() > 0) {\n            int read, total = 0;\n            do {\n                if ((read = is.read(buf, total, bs - total)) <= 0) {\n                    break;\n                }\n                total += read;\n            } while (total < bs);\n            md.update(buf);\n        }\n        return md.digest();\n    }\n\n    private static MessageDigest getMessageDigest() {\n        MessageDigest ret = MD.get();\n        if (ret == null) {\n            try {\n                ret = MessageDigest.getInstance(\"MD5\");\n                MD.set(ret);\n            } catch (NoSuchAlgorithmException e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return ret;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/io/StreamUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * Stream utils.\n */\npublic final class StreamUtils {\n\n    public static final ByteArrayInputStream EMPTY = new ByteArrayInputStream(new byte[0]);\n\n    private StreamUtils() {}\n\n    public static InputStream limitedInputStream(final InputStream is, final int limit) throws IOException {\n        return new InputStream() {\n            private int mPosition = 0;\n            private int mMark = 0;\n            private final int mLimit = Math.min(limit, is.available());\n\n            @Override\n            public int read() throws IOException {\n                if (mPosition < mLimit) {\n                    mPosition++;\n                    return is.read();\n                }\n                return -1;\n            }\n\n            @Override\n            public int read(byte[] b, int off, int len) throws IOException {\n                if (b == null) {\n                    throw new NullPointerException();\n                }\n\n                if (off < 0 || len < 0 || len > b.length - off) {\n                    throw new IndexOutOfBoundsException();\n                }\n\n                if (mPosition >= mLimit) {\n                    return -1;\n                }\n\n                if (mPosition + len > mLimit) {\n                    len = mLimit - mPosition;\n                }\n\n                if (len <= 0) {\n                    return 0;\n                }\n\n                is.read(b, off, len);\n                mPosition += len;\n                return len;\n            }\n\n            @Override\n            public long skip(long len) throws IOException {\n                if (mPosition + len > mLimit) {\n                    len = mLimit - mPosition;\n                }\n\n                if (len <= 0) {\n                    return 0;\n                }\n\n                is.skip(len);\n                mPosition += len;\n                return len;\n            }\n\n            @Override\n            public int available() {\n                return mLimit - mPosition;\n            }\n\n            @Override\n            public boolean markSupported() {\n                return is.markSupported();\n            }\n\n            @Override\n            public synchronized void mark(int readlimit) {\n                is.mark(readlimit);\n                mMark = mPosition;\n            }\n\n            @Override\n            public synchronized void reset() throws IOException {\n                is.reset();\n                mPosition = mMark;\n            }\n\n            @Override\n            public void close() throws IOException {\n                is.close();\n            }\n        };\n    }\n\n    public static InputStream markSupportedInputStream(final InputStream is, final int markBufferSize) {\n        if (is.markSupported()) {\n            return is;\n        }\n\n        return new InputStream() {\n            byte[] mMarkBuffer;\n\n            boolean mInMarked = false;\n            boolean mInReset = false;\n            boolean mDry = false;\n            private int mPosition = 0;\n            private int mCount = 0;\n\n            @Override\n            public int read() throws IOException {\n                if (!mInMarked) {\n                    return is.read();\n                } else {\n                    if (mPosition < mCount) {\n                        byte b = mMarkBuffer[mPosition++];\n                        return b & 0xFF;\n                    }\n\n                    if (!mInReset) {\n                        if (mDry) {\n                            return -1;\n                        }\n\n                        if (null == mMarkBuffer) {\n                            mMarkBuffer = new byte[markBufferSize];\n                        }\n                        if (mPosition >= markBufferSize) {\n                            throw new IOException(\"Mark buffer is full!\");\n                        }\n\n                        int read = is.read();\n                        if (-1 == read) {\n                            mDry = true;\n                            return -1;\n                        }\n\n                        mMarkBuffer[mPosition++] = (byte) read;\n                        mCount++;\n\n                        return read;\n                    } else {\n                        // mark buffer is used, exit mark status!\n                        mInMarked = false;\n                        mInReset = false;\n                        mPosition = 0;\n                        mCount = 0;\n\n                        return is.read();\n                    }\n                }\n            }\n\n            /**\n             * NOTE: the <code>readlimit</code> argument for this class\n             *  has no meaning.\n             */\n            @Override\n            public synchronized void mark(int readlimit) {\n                mInMarked = true;\n                mInReset = false;\n\n                // mark buffer is not empty\n                int count = mCount - mPosition;\n                if (count > 0) {\n                    System.arraycopy(mMarkBuffer, mPosition, mMarkBuffer, 0, count);\n                    mCount = count;\n                    mPosition = 0;\n                }\n            }\n\n            @Override\n            public synchronized void reset() throws IOException {\n                if (!mInMarked) {\n                    throw new IOException(\"should mark before reset!\");\n                }\n\n                mInReset = true;\n                mPosition = 0;\n            }\n\n            @Override\n            public boolean markSupported() {\n                return true;\n            }\n\n            @Override\n            public int available() throws IOException {\n                int available = is.available();\n\n                if (mInMarked && mInReset) {\n                    available += mCount - mPosition;\n                }\n\n                return available;\n            }\n\n            @Override\n            public void close() throws IOException {\n                is.close();\n            }\n        };\n    }\n\n    public static InputStream markSupportedInputStream(final InputStream is) {\n        return markSupportedInputStream(is, 1024);\n    }\n\n    public static void skipUnusedStream(InputStream is) throws IOException {\n        if (is.available() > 0) {\n            is.skip(is.available());\n        }\n    }\n\n    public static void copy(InputStream in, OutputStream out) throws IOException {\n        if (in.getClass() == ByteArrayInputStream.class) {\n            copy((ByteArrayInputStream) in, out);\n            return;\n        }\n        byte[] buffer = new byte[4096];\n        int bytesRead;\n        while ((bytesRead = in.read(buffer)) != -1) {\n            out.write(buffer, 0, bytesRead);\n        }\n    }\n\n    public static void copy(ByteArrayInputStream in, OutputStream out) throws IOException {\n        int len = in.available();\n        byte[] buffer = new byte[len];\n        in.read(buffer, 0, len);\n        out.write(buffer, 0, len);\n    }\n\n    public static byte[] readBytes(InputStream in) throws IOException {\n        if (in.getClass() == ByteArrayInputStream.class) {\n            return readBytes((ByteArrayInputStream) in);\n        }\n        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);\n        byte[] buffer = new byte[4096];\n        int bytesRead;\n        while ((bytesRead = in.read(buffer)) != -1) {\n            out.write(buffer, 0, bytesRead);\n        }\n        return out.toByteArray();\n    }\n\n    public static byte[] readBytes(ByteArrayInputStream in) throws IOException {\n        int len = in.available();\n        byte[] bytes = new byte[len];\n        in.read(bytes, 0, len);\n        return bytes;\n    }\n\n    public static String toString(InputStream in) throws IOException {\n        return new String(readBytes(in), StandardCharsets.UTF_8);\n    }\n\n    public static String toString(InputStream in, Charset charset) throws IOException {\n        return new String(readBytes(in), charset);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/io/UnsafeByteArrayInputStream.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * UnsafeByteArrayInputStream.\n */\npublic class UnsafeByteArrayInputStream extends InputStream {\n    protected byte[] mData;\n\n    protected int mPosition, mLimit, mMark = 0;\n\n    public UnsafeByteArrayInputStream(byte[] buf) {\n        this(buf, 0, buf.length);\n    }\n\n    public UnsafeByteArrayInputStream(byte[] buf, int offset) {\n        this(buf, offset, buf.length - offset);\n    }\n\n    public UnsafeByteArrayInputStream(byte[] buf, int offset, int length) {\n        mData = buf;\n        mPosition = mMark = offset;\n        mLimit = Math.min(offset + length, buf.length);\n    }\n\n    @Override\n    public int read() {\n        return (mPosition < mLimit) ? (mData[mPosition++] & 0xff) : -1;\n    }\n\n    @Override\n    public int read(byte[] b, int off, int len) {\n        if (b == null) {\n            throw new NullPointerException();\n        }\n        if (off < 0 || len < 0 || len > b.length - off) {\n            throw new IndexOutOfBoundsException();\n        }\n        if (mPosition >= mLimit) {\n            return -1;\n        }\n        if (mPosition + len > mLimit) {\n            len = mLimit - mPosition;\n        }\n        if (len <= 0) {\n            return 0;\n        }\n        System.arraycopy(mData, mPosition, b, off, len);\n        mPosition += len;\n        return len;\n    }\n\n    @Override\n    public long skip(long len) {\n        if (mPosition + len > mLimit) {\n            len = mLimit - mPosition;\n        }\n        if (len <= 0) {\n            return 0;\n        }\n        mPosition += len;\n        return len;\n    }\n\n    @Override\n    public int available() {\n        return mLimit - mPosition;\n    }\n\n    @Override\n    public boolean markSupported() {\n        return true;\n    }\n\n    @Override\n    public void mark(int readAheadLimit) {\n        mMark = mPosition;\n    }\n\n    @Override\n    public void reset() {\n        mPosition = mMark;\n    }\n\n    @Override\n    public void close() throws IOException {}\n\n    public int position() {\n        return mPosition;\n    }\n\n    public void position(int newPosition) {\n        mPosition = newPosition;\n    }\n\n    public int size() {\n        return mData == null ? 0 : mData.length;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/io/UnsafeByteArrayOutputStream.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.ByteBuffer;\n\n/**\n * UnsafeByteArrayOutputStream.\n */\npublic class UnsafeByteArrayOutputStream extends OutputStream {\n    protected byte[] mBuffer;\n\n    protected int mCount;\n\n    public UnsafeByteArrayOutputStream() {\n        this(32);\n    }\n\n    public UnsafeByteArrayOutputStream(int size) {\n        if (size < 0) {\n            throw new IllegalArgumentException(\"Negative initial size: \" + size);\n        }\n        mBuffer = new byte[size];\n    }\n\n    @Override\n    public void write(int b) {\n        int newCount = mCount + 1;\n        if (newCount > mBuffer.length) {\n            mBuffer = Bytes.copyOf(mBuffer, Math.max(mBuffer.length << 1, newCount));\n        }\n        mBuffer[mCount] = (byte) b;\n        mCount = newCount;\n    }\n\n    @Override\n    public void write(byte[] b, int off, int len) {\n        if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {\n            throw new IndexOutOfBoundsException();\n        }\n        if (len == 0) {\n            return;\n        }\n        int newCount = mCount + len;\n        if (newCount > mBuffer.length) {\n            mBuffer = Bytes.copyOf(mBuffer, Math.max(mBuffer.length << 1, newCount));\n        }\n        System.arraycopy(b, off, mBuffer, mCount, len);\n        mCount = newCount;\n    }\n\n    public int size() {\n        return mCount;\n    }\n\n    public void reset() {\n        mCount = 0;\n    }\n\n    public byte[] toByteArray() {\n        return Bytes.copyOf(mBuffer, mCount);\n    }\n\n    public ByteBuffer toByteBuffer() {\n        return ByteBuffer.wrap(mBuffer, 0, mCount);\n    }\n\n    public void writeTo(OutputStream out) throws IOException {\n        out.write(mBuffer, 0, mCount);\n    }\n\n    @Override\n    public String toString() {\n        return new String(mBuffer, 0, mCount);\n    }\n\n    public String toString(String charset) throws UnsupportedEncodingException {\n        return new String(mBuffer, 0, mCount, charset);\n    }\n\n    @Override\n    public void close() throws IOException {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/io/UnsafeStringReader.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.IOException;\nimport java.io.Reader;\n\n/**\n * Thread-unsafe StringReader.\n */\npublic class UnsafeStringReader extends Reader {\n    private String mString;\n\n    private int mPosition, mLimit, mMark;\n\n    public UnsafeStringReader(String str) {\n        mString = str;\n        mLimit = str.length();\n        mPosition = mMark = 0;\n    }\n\n    @Override\n    public int read() throws IOException {\n        ensureOpen();\n        if (mPosition >= mLimit) {\n            return -1;\n        }\n\n        return mString.charAt(mPosition++);\n    }\n\n    @Override\n    public int read(char[] cs, int off, int len) throws IOException {\n        ensureOpen();\n        if ((off < 0) || (off > cs.length) || (len < 0) || ((off + len) > cs.length) || ((off + len) < 0)) {\n            throw new IndexOutOfBoundsException();\n        }\n\n        if (len == 0) {\n            return 0;\n        }\n\n        if (mPosition >= mLimit) {\n            return -1;\n        }\n\n        int n = Math.min(mLimit - mPosition, len);\n        mString.getChars(mPosition, mPosition + n, cs, off);\n        mPosition += n;\n        return n;\n    }\n\n    @Override\n    public long skip(long ns) throws IOException {\n        ensureOpen();\n        if (mPosition >= mLimit) {\n            return 0;\n        }\n\n        long n = Math.min(mLimit - mPosition, ns);\n        n = Math.max(-mPosition, n);\n        mPosition += n;\n        return n;\n    }\n\n    @Override\n    public boolean ready() throws IOException {\n        ensureOpen();\n        return true;\n    }\n\n    @Override\n    public boolean markSupported() {\n        return true;\n    }\n\n    @Override\n    public void mark(int readAheadLimit) throws IOException {\n        if (readAheadLimit < 0) {\n            throw new IllegalArgumentException(\"Read-ahead limit < 0\");\n        }\n\n        ensureOpen();\n        mMark = mPosition;\n    }\n\n    @Override\n    public void reset() throws IOException {\n        ensureOpen();\n        mPosition = mMark;\n    }\n\n    @Override\n    public void close() throws IOException {\n        mString = null;\n    }\n\n    private void ensureOpen() throws IOException {\n        if (mString == null) {\n            throw new IOException(\"Stream closed\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/io/UnsafeStringWriter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.IOException;\nimport java.io.Writer;\n\n/**\n * Thread-unsafe StringWriter.\n */\npublic class UnsafeStringWriter extends Writer {\n    private final StringBuilder mBuffer;\n\n    public UnsafeStringWriter() {\n        lock = mBuffer = new StringBuilder();\n    }\n\n    public UnsafeStringWriter(int size) {\n        if (size < 0) {\n            throw new IllegalArgumentException(\"Negative buffer size\");\n        }\n\n        lock = mBuffer = new StringBuilder(size);\n    }\n\n    @Override\n    public void write(int c) {\n        mBuffer.append((char) c);\n    }\n\n    @Override\n    public void write(char[] cs) throws IOException {\n        mBuffer.append(cs, 0, cs.length);\n    }\n\n    @Override\n    public void write(char[] cs, int off, int len) throws IOException {\n        if ((off < 0) || (off > cs.length) || (len < 0) || ((off + len) > cs.length) || ((off + len) < 0)) {\n            throw new IndexOutOfBoundsException();\n        }\n\n        if (len > 0) {\n            mBuffer.append(cs, off, len);\n        }\n    }\n\n    @Override\n    public void write(String str) {\n        mBuffer.append(str);\n    }\n\n    @Override\n    public void write(String str, int off, int len) {\n        mBuffer.append(str, off, off + len);\n    }\n\n    @Override\n    public Writer append(CharSequence csq) {\n        if (csq == null) {\n            write(\"null\");\n        } else {\n            write(csq.toString());\n        }\n        return this;\n    }\n\n    @Override\n    public Writer append(CharSequence csq, int start, int end) {\n        CharSequence cs = (csq == null ? \"null\" : csq);\n        write(cs.subSequence(start, end).toString());\n        return this;\n    }\n\n    @Override\n    public Writer append(char c) {\n        mBuffer.append(c);\n        return this;\n    }\n\n    @Override\n    public void close() {}\n\n    @Override\n    public void flush() {}\n\n    @Override\n    public String toString() {\n        return mBuffer.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/json/GsonUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\n\nimport java.lang.reflect.Type;\n\nimport com.google.gson.Gson;\nimport com.google.gson.JsonSyntaxException;\nimport com.google.gson.reflect.TypeToken;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_GSON;\n\npublic class GsonUtils {\n    // weak reference of com.google.gson.Gson, prevent throw exception when init\n    private static volatile Object gsonCache = null;\n\n    private static volatile Boolean supportGson;\n\n    private static boolean isSupportGson() {\n        if (supportGson == null) {\n            synchronized (GsonUtils.class) {\n                if (supportGson == null) {\n                    try {\n                        Class<?> aClass = ClassUtils.forName(\"com.google.gson.Gson\");\n                        supportGson = aClass != null;\n                    } catch (Throwable t) {\n                        supportGson = false;\n                    }\n                }\n            }\n        }\n        return supportGson;\n    }\n\n    public static Object fromJson(String json, Type originType) throws RuntimeException {\n        if (!isSupportGson()) {\n            throw new RuntimeException(\"Gson is not supported. Please import Gson in JVM env.\");\n        }\n        Type type = TypeToken.get(originType).getType();\n        try {\n            return getGson().fromJson(json, type);\n        } catch (JsonSyntaxException ex) {\n            throw new RuntimeException(String.format(\n                    \"Generic serialization [%s] Json syntax exception thrown when parsing (message:%s type:%s) error:%s\",\n                    GENERIC_SERIALIZATION_GSON, json, type.toString(), ex.getMessage()));\n        }\n    }\n\n    public static String toJson(Object obj) throws RuntimeException {\n        if (!isSupportGson()) {\n            throw new RuntimeException(\"Gson is not supported. Please import Gson in JVM env.\");\n        }\n        try {\n            return getGson().toJson(obj);\n        } catch (JsonSyntaxException ex) {\n            throw new RuntimeException(String.format(\n                    \"Generic serialization [%s] Json syntax exception thrown when parsing (object:%s ) error:%s\",\n                    GENERIC_SERIALIZATION_GSON, obj, ex.getMessage()));\n        }\n    }\n\n    private static Gson getGson() {\n        if (gsonCache == null || !(gsonCache instanceof Gson)) {\n            synchronized (GsonUtils.class) {\n                if (gsonCache == null || !(gsonCache instanceof Gson)) {\n                    gsonCache = new Gson();\n                }\n            }\n        }\n        return (Gson) gsonCache;\n    }\n\n    /**\n     * @deprecated for uts only\n     */\n    @Deprecated\n    protected static void setSupportGson(Boolean supportGson) {\n        GsonUtils.supportGson = supportGson;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/json/JsonUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.lang.reflect.Type;\nimport java.util.List;\nimport java.util.Map;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface JsonUtil {\n\n    String getName();\n\n    boolean isSupport();\n\n    boolean isJson(String json);\n\n    <T> T toJavaObject(String json, Type type);\n\n    <T> List<T> toJavaList(String json, Class<T> clazz);\n\n    String toJson(Object obj);\n\n    String toPrettyJson(Object obj);\n\n    List<?> getList(Map<String, ?> obj, String key);\n\n    List<Map<String, ?>> getListOfObjects(Map<String, ?> obj, String key);\n\n    List<String> getListOfStrings(Map<String, ?> obj, String key);\n\n    Map<String, ?> getObject(Map<String, ?> obj, String key);\n\n    Object convertObject(Object obj, Type type);\n\n    Object convertObject(Object obj, Class<?> clazz);\n\n    Double getNumberAsDouble(Map<String, ?> obj, String key);\n\n    Integer getNumberAsInteger(Map<String, ?> obj, String key);\n\n    Long getNumberAsLong(Map<String, ?> obj, String key);\n\n    String getString(Map<String, ?> obj, String key);\n\n    List<Map<String, ?>> checkObjectList(List<?> rawList);\n\n    List<String> checkStringList(List<?> rawList);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/AbstractJsonUtilImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json.impl;\n\nimport org.apache.dubbo.common.json.JsonUtil;\nimport org.apache.dubbo.common.utils.CollectionUtils;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\npublic abstract class AbstractJsonUtilImpl implements JsonUtil {\n\n    @Override\n    public boolean isSupport() {\n        try {\n            Map<String, String> map = new HashMap<>();\n            map.put(\"json\", \"test\");\n            if (!CollectionUtils.mapEquals(map, toJavaObject(toJson(map), Map.class))) {\n                return false;\n            }\n\n            List<String> list = new LinkedList<>();\n            list.add(\"json\");\n            return CollectionUtils.equals(list, toJavaList(toJson(list), String.class));\n        } catch (Throwable t) {\n            return false;\n        }\n    }\n\n    @Override\n    public List<?> getList(Map<String, ?> obj, String key) {\n        assert obj != null;\n        assert key != null;\n        if (!obj.containsKey(key)) {\n            return null;\n        }\n        Object value = obj.get(key);\n        if (!(value instanceof List)) {\n            throw new ClassCastException(String.format(\"value '%s' for key '%s' in '%s' is not List\", value, key, obj));\n        }\n        return (List<?>) value;\n    }\n\n    /**\n     * Gets a list from an object for the given key, and verifies all entries are objects.  If the key\n     * is not present, this returns null.  If the value is not a List or an entry is not an object,\n     * throws an exception.\n     */\n    @Override\n    public List<Map<String, ?>> getListOfObjects(Map<String, ?> obj, String key) {\n        assert obj != null;\n        List<?> list = getList(obj, key);\n        if (list == null) {\n            return null;\n        }\n        return checkObjectList(list);\n    }\n\n    /**\n     * Gets a list from an object for the given key, and verifies all entries are strings.  If the key\n     * is not present, this returns null.  If the value is not a List or an entry is not a string,\n     * throws an exception.\n     */\n    @Override\n    public List<String> getListOfStrings(Map<String, ?> obj, String key) {\n        assert obj != null;\n        List<?> list = getList(obj, key);\n        if (list == null) {\n            return null;\n        }\n        return checkStringList(list);\n    }\n\n    /**\n     * Gets an object from an object for the given key.  If the key is not present, this returns null.\n     * If the value is not a Map, throws an exception.\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public Map<String, ?> getObject(Map<String, ?> obj, String key) {\n        assert obj != null;\n        assert key != null;\n        if (!obj.containsKey(key)) {\n            return null;\n        }\n        Object value = obj.get(key);\n        if (!(value instanceof Map)) {\n            throw new ClassCastException(\n                    String.format(\"value '%s' for key '%s' in '%s' is not object\", value, key, obj));\n        }\n        return (Map<String, ?>) value;\n    }\n\n    /**\n     * Gets a number from an object for the given key.  If the key is not present, this returns null.\n     * If the value does not represent a double, throws an exception.\n     */\n    @Override\n    public Double getNumberAsDouble(Map<String, ?> obj, String key) {\n        assert obj != null;\n        assert key != null;\n        if (!obj.containsKey(key)) {\n            return null;\n        }\n        Object value = obj.get(key);\n        if (value instanceof Double) {\n            return (Double) value;\n        }\n        if (value instanceof String) {\n            try {\n                return Double.parseDouble((String) value);\n            } catch (NumberFormatException e) {\n                throw new IllegalArgumentException(\n                        String.format(\"value '%s' for key '%s' is not a double\", value, key));\n            }\n        }\n        throw new IllegalArgumentException(\n                String.format(\"value '%s' for key '%s' in '%s' is not a number\", value, key, obj));\n    }\n\n    /**\n     * Gets a number from an object for the given key, casted to an integer.  If the key is not\n     * present, this returns null.  If the value does not represent an integer, throws an exception.\n     */\n    @Override\n    public Integer getNumberAsInteger(Map<String, ?> obj, String key) {\n        assert obj != null;\n        assert key != null;\n        if (!obj.containsKey(key)) {\n            return null;\n        }\n        Object value = obj.get(key);\n        if (value instanceof Double) {\n            Double d = (Double) value;\n            int i = d.intValue();\n            if (i != d) {\n                throw new ClassCastException(\"Number expected to be integer: \" + d);\n            }\n            return i;\n        }\n        if (value instanceof String) {\n            try {\n                return Integer.parseInt((String) value);\n            } catch (NumberFormatException e) {\n                throw new IllegalArgumentException(\n                        String.format(\"value '%s' for key '%s' is not an integer\", value, key));\n            }\n        }\n        throw new IllegalArgumentException(String.format(\"value '%s' for key '%s' is not an integer\", value, key));\n    }\n\n    /**\n     * Gets a number from an object for the given key, casted to an long.  If the key is not\n     * present, this returns null.  If the value does not represent a long integer, throws an\n     * exception.\n     */\n    @Override\n    public Long getNumberAsLong(Map<String, ?> obj, String key) {\n        assert obj != null;\n        assert key != null;\n        if (!obj.containsKey(key)) {\n            return null;\n        }\n        Object value = obj.get(key);\n        if (value instanceof Double) {\n            Double d = (Double) value;\n            long l = d.longValue();\n            if (l != d) {\n                throw new ClassCastException(\"Number expected to be long: \" + d);\n            }\n            return l;\n        }\n        if (value instanceof String) {\n            try {\n                return Long.parseLong((String) value);\n            } catch (NumberFormatException e) {\n                throw new IllegalArgumentException(\n                        String.format(\"value '%s' for key '%s' is not a long integer\", value, key));\n            }\n        }\n        throw new IllegalArgumentException(String.format(\"value '%s' for key '%s' is not a long integer\", value, key));\n    }\n\n    /**\n     * Gets a string from an object for the given key.  If the key is not present, this returns null.\n     * If the value is not a String, throws an exception.\n     */\n    @Override\n    public String getString(Map<String, ?> obj, String key) {\n        assert obj != null;\n        assert key != null;\n        if (!obj.containsKey(key)) {\n            return null;\n        }\n        Object value = obj.get(key);\n        if (!(value instanceof String)) {\n            throw new ClassCastException(\n                    String.format(\"value '%s' for key '%s' in '%s' is not String\", value, key, obj));\n        }\n        return (String) value;\n    }\n\n    /**\n     * Casts a list of unchecked JSON values to a list of checked objects in Java type.\n     * If the given list contains a value that is not a Map, throws an exception.\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public List<Map<String, ?>> checkObjectList(List<?> rawList) {\n        assert rawList != null;\n        for (int i = 0; i < rawList.size(); i++) {\n            if (!(rawList.get(i) instanceof Map)) {\n                throw new ClassCastException(\n                        String.format(\"value %s for idx %d in %s is not object\", rawList.get(i), i, rawList));\n            }\n        }\n        return (List<Map<String, ?>>) rawList;\n    }\n\n    /**\n     * Casts a list of unchecked JSON values to a list of String. If the given list\n     * contains a value that is not a String, throws an exception.\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public List<String> checkStringList(List<?> rawList) {\n        assert rawList != null;\n        for (int i = 0; i < rawList.size(); i++) {\n            if (!(rawList.get(i) instanceof String)) {\n                throw new ClassCastException(\n                        String.format(\"value '%s' for idx %d in '%s' is not string\", rawList.get(i), i, rawList));\n            }\n        }\n        return (List<String>) rawList;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/FastJson2Impl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\n\nimport java.lang.reflect.Type;\nimport java.util.List;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONValidator;\nimport com.alibaba.fastjson2.JSONWriter.Feature;\nimport com.alibaba.fastjson2.util.TypeUtils;\n\n@Activate(order = 100, onClass = \"com.alibaba.fastjson2.JSON\")\npublic class FastJson2Impl extends AbstractJsonUtilImpl {\n\n    @Override\n    public String getName() {\n        return \"fastjson2\";\n    }\n\n    @Override\n    public boolean isJson(String json) {\n        return JSONValidator.from(json).validate();\n    }\n\n    @Override\n    public <T> T toJavaObject(String json, Type type) {\n        return JSON.parseObject(json, type);\n    }\n\n    @Override\n    public <T> List<T> toJavaList(String json, Class<T> clazz) {\n        return JSON.parseArray(json, clazz);\n    }\n\n    @Override\n    public String toJson(Object obj) {\n        return JSON.toJSONString(obj, Feature.WriteEnumsUsingName);\n    }\n\n    @Override\n    public String toPrettyJson(Object obj) {\n        return JSON.toJSONString(obj, Feature.WriteEnumsUsingName, Feature.PrettyFormat);\n    }\n\n    @Override\n    public Object convertObject(Object obj, Type type) {\n        return TypeUtils.cast(obj, type);\n    }\n\n    @Override\n    public Object convertObject(Object obj, Class<?> clazz) {\n        return TypeUtils.cast(obj, clazz);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/FastJsonImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\n\nimport java.lang.reflect.Type;\nimport java.util.List;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONArray;\nimport com.alibaba.fastjson.JSONException;\nimport com.alibaba.fastjson.JSONObject;\nimport com.alibaba.fastjson.parser.ParserConfig;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport com.alibaba.fastjson.util.TypeUtils;\n\n@Activate(order = 200, onClass = \"com.alibaba.fastjson.JSON\")\npublic class FastJsonImpl extends AbstractJsonUtilImpl {\n\n    @Override\n    public String getName() {\n        return \"fastjson\";\n    }\n\n    @Override\n    public boolean isJson(String json) {\n        try {\n            Object obj = JSON.parse(json);\n            return obj instanceof JSONObject || obj instanceof JSONArray;\n        } catch (JSONException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public <T> T toJavaObject(String json, Type type) {\n        return JSON.parseObject(json, type);\n    }\n\n    @Override\n    public <T> List<T> toJavaList(String json, Class<T> clazz) {\n        return JSON.parseArray(json, clazz);\n    }\n\n    @Override\n    public String toJson(Object obj) {\n        return JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);\n    }\n\n    @Override\n    public String toPrettyJson(Object obj) {\n        return JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.PrettyFormat);\n    }\n\n    @Override\n    public Object convertObject(Object obj, Type type) {\n        return TypeUtils.cast(obj, type, ParserConfig.getGlobalInstance());\n    }\n\n    @Override\n    public Object convertObject(Object obj, Class<?> clazz) {\n        return TypeUtils.cast(obj, clazz, ParserConfig.getGlobalInstance());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/GsonImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\n\nimport java.lang.reflect.Type;\nimport java.util.List;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonParser;\nimport com.google.gson.JsonSyntaxException;\nimport com.google.gson.reflect.TypeToken;\n\n@Activate(order = 300, onClass = \"com.google.gson.Gson\")\npublic class GsonImpl extends AbstractJsonUtilImpl {\n\n    private volatile Gson gson;\n\n    @Override\n    public String getName() {\n        return \"gson\";\n    }\n\n    @Override\n    public boolean isJson(String json) {\n        try {\n            JsonElement jsonElement = JsonParser.parseString(json);\n            return jsonElement.isJsonObject() || jsonElement.isJsonArray();\n        } catch (JsonSyntaxException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public <T> T toJavaObject(String json, Type type) {\n        return getGson().fromJson(json, type);\n    }\n\n    @Override\n    public <T> List<T> toJavaList(String json, Class<T> clazz) {\n        Type type = TypeToken.getParameterized(List.class, clazz).getType();\n        return getGson().fromJson(json, type);\n    }\n\n    @Override\n    public String toJson(Object obj) {\n        return getGson().toJson(obj);\n    }\n\n    @Override\n    public String toPrettyJson(Object obj) {\n        return createBuilder().setPrettyPrinting().create().toJson(obj);\n    }\n\n    @Override\n    public Object convertObject(Object obj, Type type) {\n        Gson gson = getGson();\n        return gson.fromJson(gson.toJsonTree(obj), type);\n    }\n\n    @Override\n    public Object convertObject(Object obj, Class<?> clazz) {\n        Gson gson = getGson();\n        return gson.fromJson(gson.toJsonTree(obj), clazz);\n    }\n\n    protected Gson getGson() {\n        Gson gson = this.gson;\n        if (gson == null) {\n            synchronized (this) {\n                gson = this.gson;\n                if (gson == null) {\n                    this.gson = gson = createBuilder().create();\n                }\n            }\n        }\n        return gson;\n    }\n\n    protected GsonBuilder createBuilder() {\n        return new GsonBuilder();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/JacksonImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\n\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.DeserializationFeature;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.MapperFeature;\nimport com.fasterxml.jackson.databind.Module;\nimport com.fasterxml.jackson.databind.json.JsonMapper;\nimport com.fasterxml.jackson.databind.json.JsonMapper.Builder;\nimport com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;\n\n@Activate(order = 400, onClass = \"com.fasterxml.jackson.databind.json.JsonMapper\")\npublic class JacksonImpl extends AbstractJsonUtilImpl {\n\n    private volatile JsonMapper mapper;\n    private final List<Module> customModules = new ArrayList<>();\n\n    @Override\n    public String getName() {\n        return \"jackson\";\n    }\n\n    @Override\n    public boolean isJson(String json) {\n        try {\n            JsonNode node = getMapper().readTree(json);\n            return node.isObject() || node.isArray();\n        } catch (JsonProcessingException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public <T> T toJavaObject(String json, Type type) {\n        try {\n            JsonMapper mapper = getMapper();\n            return mapper.readValue(json, mapper.getTypeFactory().constructType(type));\n        } catch (com.fasterxml.jackson.core.JsonProcessingException e) {\n            throw new IllegalArgumentException(e);\n        }\n    }\n\n    @Override\n    public <T> List<T> toJavaList(String json, Class<T> clazz) {\n        try {\n            JsonMapper mapper = getMapper();\n            // Use ArrayList.class instead of List.class for JDK 21+ compatibility\n            // JDK 21+ introduced SequencedCollection interface which causes type inference issues with List.class\n            return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(ArrayList.class, clazz));\n        } catch (com.fasterxml.jackson.core.JsonProcessingException e) {\n            throw new IllegalArgumentException(e);\n        }\n    }\n\n    @Override\n    public String toJson(Object obj) {\n        try {\n            return getMapper().writeValueAsString(obj);\n        } catch (com.fasterxml.jackson.core.JsonProcessingException e) {\n            throw new IllegalArgumentException(e);\n        }\n    }\n\n    @Override\n    public String toPrettyJson(Object obj) {\n        try {\n            return getMapper().writerWithDefaultPrettyPrinter().writeValueAsString(obj);\n        } catch (JsonProcessingException e) {\n            throw new IllegalArgumentException(e);\n        }\n    }\n\n    @Override\n    public Object convertObject(Object obj, Type type) {\n        JsonMapper mapper = getMapper();\n        return mapper.convertValue(obj, mapper.constructType(type));\n    }\n\n    @Override\n    public Object convertObject(Object obj, Class<?> clazz) {\n        return getMapper().convertValue(obj, clazz);\n    }\n\n    protected JsonMapper getMapper() {\n        JsonMapper mapper = this.mapper;\n        if (mapper == null) {\n            synchronized (this) {\n                mapper = this.mapper;\n                if (mapper == null) {\n                    this.mapper = mapper = createBuilder().build();\n                }\n            }\n        }\n        return mapper;\n    }\n\n    protected Builder createBuilder() {\n        Builder builder = JsonMapper.builder()\n                .configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true)\n                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)\n                .serializationInclusion(Include.NON_NULL)\n                .addModule(new JavaTimeModule());\n\n        for (Module module : customModules) {\n            builder.addModule(module);\n        }\n\n        return builder;\n    }\n\n    public void addModule(Module module) {\n        synchronized (this) {\n            customModules.add(module);\n            // Invalidate the mapper to rebuild it\n            this.mapper = null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/lang/Nullable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.lang;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface Nullable {}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/lang/Prioritized.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.lang;\n\nimport java.util.Comparator;\n\nimport static java.lang.Integer.compare;\n\n/**\n * {@code Prioritized} interface can be implemented by objects that\n * should be sorted, for example the tasks in executable queue.\n *\n * @since 2.7.5\n */\npublic interface Prioritized extends Comparable<Prioritized> {\n\n    /**\n     * The {@link Comparator} of {@link Prioritized}\n     */\n    Comparator<Object> COMPARATOR = (one, two) -> {\n        boolean b1 = one instanceof Prioritized;\n        boolean b2 = two instanceof Prioritized;\n        if (b1 && !b2) { // one is Prioritized, two is not\n            return -1;\n        } else if (b2 && !b1) { // two is Prioritized, one is not\n            return 1;\n        } else if (b1 && b2) { //  one and two both are Prioritized\n            return ((Prioritized) one).compareTo((Prioritized) two);\n        } else { // no different\n            return 0;\n        }\n    };\n\n    /**\n     * The maximum priority\n     */\n    int MAX_PRIORITY = Integer.MIN_VALUE;\n\n    /**\n     * The minimum priority\n     */\n    int MIN_PRIORITY = Integer.MAX_VALUE;\n\n    /**\n     * Normal Priority\n     */\n    int NORMAL_PRIORITY = 0;\n\n    /**\n     * Get the priority\n     *\n     * @return the default is {@link #NORMAL_PRIORITY}\n     */\n    default int getPriority() {\n        return NORMAL_PRIORITY;\n    }\n\n    @Override\n    default int compareTo(Prioritized that) {\n        return compare(this.getPriority(), that.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallback.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.lang;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * A callback interface invoked when Dubbo application is stopped.\n * <p>Note: This class is not directly related to Java ShutdownHook.</p>\n * <p/>\n * <p>Call chains:</p>\n * <ol>\n *     <li>Java Shutdown Hook -> ApplicationDeployer.destroy() -> execute ShutdownHookCallback</li>\n *     <li>Stop dubbo application -> ApplicationDeployer.destroy() -> execute ShutdownHookCallback</li>\n * </ol>\n *\n * @since 2.7.5\n * @see org.apache.dubbo.common.deploy.ApplicationDeployListener\n * @see org.apache.dubbo.rpc.model.ScopeModelDestroyListener\n */\n@SPI(scope = ExtensionScope.APPLICATION)\npublic interface ShutdownHookCallback extends Prioritized {\n\n    /**\n     * Callback execution\n     *\n     * @throws Throwable if met with some errors\n     */\n    void callback() throws Throwable;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.lang;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport static java.util.Collections.sort;\nimport static org.apache.dubbo.common.function.ThrowableAction.execute;\n\n/**\n * The composed {@link ShutdownHookCallback} class to manipulate one and more {@link ShutdownHookCallback} instances\n *\n * @since 2.7.5\n */\npublic class ShutdownHookCallbacks implements Disposable {\n\n    private final List<ShutdownHookCallback> callbacks = new LinkedList<>();\n\n    private final ApplicationModel applicationModel;\n\n    public ShutdownHookCallbacks(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        loadCallbacks();\n    }\n\n    public ShutdownHookCallbacks addCallback(ShutdownHookCallback callback) {\n        synchronized (this) {\n            if (!callbacks.contains(callback)) {\n                this.callbacks.add(callback);\n            }\n        }\n        return this;\n    }\n\n    public Collection<ShutdownHookCallback> getCallbacks() {\n        synchronized (this) {\n            sort(this.callbacks);\n            return this.callbacks;\n        }\n    }\n\n    public void destroy() {\n        synchronized (this) {\n            callbacks.clear();\n        }\n    }\n\n    private void loadCallbacks() {\n        ExtensionLoader<ShutdownHookCallback> loader = applicationModel.getExtensionLoader(ShutdownHookCallback.class);\n        loader.getSupportedExtensionInstances().forEach(this::addCallback);\n    }\n\n    public void callback() {\n        getCallbacks().forEach(callback -> execute(callback::callback));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/ErrorTypeAwareLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\n\n/**\n * Logger interface with the ability of displaying solution of different types of error.\n *\n * <p>\n * This logger will log a message like this:\n *\n * <blockquote><pre>\n *     ... (original logging message) This may be caused by (... cause),\n *     go to https://dubbo.apache.org/faq/[Cat]/[X] to find instructions. (... extendedInformation)\n * </pre></blockquote>\n *\n * Where \"[Cat]/[X]\" is the error code (\"code\" in arguments). The link is clickable, leading user to\n * the \"Error code and its corresponding solutions\" page.\n *\n * @see LoggerCodeConstants Detailed Format of Error Code and Error Code Constants\n */\npublic interface ErrorTypeAwareLogger extends Logger {\n\n    /**\n     * Logs a message with warn log level.\n     *\n     * @param code error code\n     * @param cause error cause\n     * @param extendedInformation extended information\n     * @param msg log this message\n     */\n    void warn(String code, String cause, String extendedInformation, String msg);\n\n    /**\n     * Logs a message with warn log level.\n     *\n     * @param code error code\n     * @param cause error cause\n     * @param extendedInformation extended information\n     * @param msg log this message\n     * @param e log this cause\n     */\n    void warn(String code, String cause, String extendedInformation, String msg, Throwable e);\n\n    /**\n     * Logs a message with error log level.\n     *\n     * @param code error code\n     * @param cause error cause\n     * @param extendedInformation extended information\n     * @param msg log this message\n     */\n    void error(String code, String cause, String extendedInformation, String msg);\n\n    /**\n     * Logs a message with error log level.\n     *\n     * @param code error code\n     * @param cause error cause\n     * @param extendedInformation extended information\n     * @param msg log this message\n     * @param e log this cause\n     */\n    void error(String code, String cause, String extendedInformation, String msg, Throwable e);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/FluentLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\nimport java.util.function.Supplier;\n\npublic interface FluentLogger {\n\n    FluentLogger cause(String cause);\n\n    FluentLogger more(String extendedInformation);\n\n    FluentLogger msg(String msg);\n\n    FluentLogger msg(String msg, Object... args);\n\n    FluentLogger msg(Supplier<String> supplier);\n\n    void trace();\n\n    void trace(Throwable t);\n\n    void trace(String msg);\n\n    void trace(String msg, Object... args);\n\n    void trace(String msg, Throwable t);\n\n    void debug();\n\n    void debug(Throwable t);\n\n    void debug(String msg);\n\n    void debug(String msg, Object... args);\n\n    void debug(String msg, Throwable t);\n\n    void info();\n\n    void info(Throwable t);\n\n    void info(String msg, Object... args);\n\n    void info(String msg);\n\n    void info(String msg, Throwable t);\n\n    void internalWarn();\n\n    void internalWarn(Throwable t);\n\n    void internalWarn(String msg);\n\n    void internalWarn(String msg, Object... args);\n\n    void internalWarn(String msg, Throwable t);\n\n    void warn(String code);\n\n    void warn(String code, Throwable t);\n\n    void warn(String code, String msg, Object... args);\n\n    void warn(String code, String msg, Throwable t);\n\n    void internalError();\n\n    void internalError(Throwable t);\n\n    void internalError(String msg);\n\n    void internalError(String msg, Object... args);\n\n    void internalError(String msg, Throwable t);\n\n    void error(String code);\n\n    void error(String code, Throwable t);\n\n    void error(String code, String msg, Object... args);\n\n    void error(String code, String msg, Throwable t);\n\n    void log(Level level);\n\n    void log(Level level, Throwable t);\n\n    void log(Level level, String msg);\n\n    void log(Level level, String msg, Object... args);\n\n    void log(Level level, String msg, Throwable t);\n\n    void log(String code, Level level);\n\n    void log(String code, Level level, String msg, Object... args);\n\n    void log(String code, Level level, String msg, Throwable t);\n\n    boolean isTraceEnabled();\n\n    boolean isDebugEnabled();\n\n    boolean isInfoEnabled();\n\n    boolean isWarnEnabled();\n\n    boolean isErrorEnabled();\n\n    static FluentLogger of(Class<?> key) {\n        return new FluentLoggerImpl(key);\n    }\n\n    static FluentLogger of(String key) {\n        return new FluentLoggerImpl(key);\n    }\n\n    interface S extends Supplier<String> {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/FluentLoggerImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\nimport org.apache.dubbo.common.logger.helpers.FormattingTuple;\nimport org.apache.dubbo.common.logger.helpers.MessageFormatter;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.function.Supplier;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\n\nfinal class FluentLoggerImpl implements FluentLogger {\n\n    private final ErrorTypeAwareLogger delegate;\n    private final FluentLoggerImpl root;\n\n    private String cause = StringUtils.EMPTY_STRING;\n    private String extendedInformation = StringUtils.EMPTY_STRING;\n    private Supplier<String> messageSupplier;\n    private String message;\n    private Object[] args;\n\n    FluentLoggerImpl(Class<?> key) {\n        delegate = LoggerFactory.getErrorTypeAwareLogger(FluentLoggerImpl.class.getName(), key);\n        root = this;\n    }\n\n    FluentLoggerImpl(String key) {\n        delegate = LoggerFactory.getErrorTypeAwareLogger(FluentLoggerImpl.class.getName(), key);\n        root = this;\n    }\n\n    private FluentLoggerImpl(FluentLoggerImpl logger) {\n        delegate = logger.delegate;\n        root = logger;\n    }\n\n    @Override\n    public FluentLogger cause(String cause) {\n        if (cause == null) {\n            return this;\n        }\n        FluentLoggerImpl logger = getLogger();\n        logger.cause = cause;\n        return logger;\n    }\n\n    @Override\n    public FluentLogger more(String extendedInformation) {\n        if (extendedInformation == null) {\n            return this;\n        }\n        FluentLoggerImpl logger = getLogger();\n        logger.extendedInformation = extendedInformation;\n        return logger;\n    }\n\n    @Override\n    public FluentLogger msg(String message) {\n        FluentLoggerImpl logger = getLogger();\n        logger.message = message;\n        return logger;\n    }\n\n    @Override\n    public FluentLogger msg(String message, Object... args) {\n        FluentLoggerImpl logger = getLogger();\n        logger.message = message;\n        logger.args = args;\n        return logger;\n    }\n\n    @Override\n    public FluentLogger msg(Supplier<String> supplier) {\n        FluentLoggerImpl logger = getLogger();\n        logger.messageSupplier = supplier;\n        return logger;\n    }\n\n    @Override\n    public void trace() {\n        if (message != null) {\n            if (args != null && args.length > 0) {\n                if (delegate.isTraceEnabled()) {\n                    delegate.trace(message, formatArgs(args));\n                }\n            } else {\n                delegate.trace(message);\n            }\n        } else if (messageSupplier != null) {\n            if (delegate.isTraceEnabled()) {\n                delegate.trace(messageSupplier.get());\n            }\n        } else {\n            warnMessageMissing();\n        }\n    }\n\n    @Override\n    public void trace(Throwable t) {\n        if (message != null) {\n            int len = args == null ? 0 : args.length;\n            if (len > 0) {\n                if (delegate.isTraceEnabled()) {\n                    Object[] arr = new Object[len + 1];\n                    System.arraycopy(args, 0, arr, 0, len);\n                    arr[len] = t;\n                    delegate.trace(message, formatArgs(arr));\n                }\n            } else {\n                delegate.trace(message, t);\n            }\n        } else if (messageSupplier != null) {\n            if (delegate.isTraceEnabled()) {\n                delegate.trace(messageSupplier.get(), t);\n            }\n        } else {\n            warnMessageMissing();\n        }\n    }\n\n    @Override\n    public void trace(String message) {\n        delegate.trace(message);\n    }\n\n    @Override\n    public void trace(String message, Object... args) {\n        if (args == null || args.length == 0) {\n            delegate.trace(message);\n        } else if (delegate.isTraceEnabled()) {\n            delegate.trace(message, formatArgs(args));\n        }\n    }\n\n    @Override\n    public void trace(String message, Throwable t) {\n        delegate.trace(message, t);\n    }\n\n    @Override\n    public void debug() {\n        if (message != null) {\n            if (args != null && args.length > 0) {\n                if (delegate.isDebugEnabled()) {\n                    delegate.debug(message, formatArgs(args));\n                }\n            } else {\n                delegate.debug(message);\n            }\n        } else if (messageSupplier != null) {\n            if (delegate.isDebugEnabled()) {\n                delegate.debug(messageSupplier.get());\n            }\n        } else {\n            warnMessageMissing();\n        }\n    }\n\n    @Override\n    public void debug(Throwable t) {\n        if (message != null) {\n            int len = args == null ? 0 : args.length;\n            if (len > 0) {\n                if (delegate.isDebugEnabled()) {\n                    Object[] arr = new Object[len + 1];\n                    System.arraycopy(args, 0, arr, 0, len);\n                    arr[len] = t;\n                    delegate.debug(message, formatArgs(arr));\n                }\n            } else {\n                delegate.debug(message, t);\n            }\n        } else if (messageSupplier != null) {\n            if (delegate.isDebugEnabled()) {\n                delegate.debug(messageSupplier.get(), t);\n            }\n        } else {\n            warnMessageMissing();\n        }\n    }\n\n    @Override\n    public void debug(String message) {\n        delegate.debug(message);\n    }\n\n    @Override\n    public void debug(String message, Object... args) {\n        if (args == null || args.length == 0) {\n            delegate.debug(message);\n        } else if (delegate.isDebugEnabled()) {\n            delegate.debug(message, formatArgs(args));\n        }\n    }\n\n    @Override\n    public void debug(String message, Throwable t) {\n        delegate.debug(message, t);\n    }\n\n    @Override\n    public void info() {\n        if (message != null) {\n            if (args != null && args.length > 0) {\n                if (delegate.isInfoEnabled()) {\n                    delegate.info(message, formatArgs(args));\n                }\n            } else {\n                delegate.info(message);\n            }\n        } else if (messageSupplier != null) {\n            if (delegate.isInfoEnabled()) {\n                delegate.info(messageSupplier.get());\n            }\n        } else {\n            warnMessageMissing();\n        }\n    }\n\n    @Override\n    public void info(Throwable t) {\n        if (message != null) {\n            int len = args == null ? 0 : args.length;\n            if (len > 0) {\n                if (delegate.isInfoEnabled()) {\n                    Object[] arr = new Object[len + 1];\n                    System.arraycopy(args, 0, arr, 0, len);\n                    arr[len] = t;\n                    delegate.info(message, formatArgs(arr));\n                }\n            } else {\n                delegate.info(message, t);\n            }\n        } else if (messageSupplier != null) {\n            if (delegate.isInfoEnabled()) {\n                delegate.info(messageSupplier.get(), t);\n            }\n        } else {\n            warnMessageMissing();\n        }\n    }\n\n    @Override\n    public void info(String message, Object... args) {\n        if (args == null || args.length == 0) {\n            delegate.info(message);\n        } else if (delegate.isInfoEnabled()) {\n            delegate.info(message, formatArgs(args));\n        }\n    }\n\n    @Override\n    public void info(String message) {\n        delegate.info(message);\n    }\n\n    @Override\n    public void info(String message, Throwable t) {\n        delegate.info(message, t);\n    }\n\n    @Override\n    public void internalWarn() {\n        warn(INTERNAL_ERROR);\n    }\n\n    @Override\n    public void internalWarn(Throwable t) {\n        warn(INTERNAL_ERROR, t);\n    }\n\n    @Override\n    public void internalWarn(String message) {\n        warn(INTERNAL_ERROR, message);\n    }\n\n    @Override\n    public void internalWarn(String message, Object... args) {\n        warn(INTERNAL_ERROR, message, args);\n    }\n\n    @Override\n    public void internalWarn(String message, Throwable t) {\n        warn(INTERNAL_ERROR, message, t);\n    }\n\n    @Override\n    public void warn(String code) {\n        if (message != null) {\n            if (args != null && args.length > 0) {\n                formatAndWarn(code, message, args);\n            } else {\n                delegate.warn(code, cause, extendedInformation, message);\n            }\n        } else if (messageSupplier != null) {\n            if (delegate.isWarnEnabled()) {\n                delegate.warn(code, cause, extendedInformation, messageSupplier.get());\n            }\n        } else {\n            warnMessageMissing();\n        }\n    }\n\n    @Override\n    public void warn(String code, Throwable t) {\n        if (message != null) {\n            if (args != null && args.length > 0) {\n                if (delegate.isWarnEnabled()) {\n                    FormattingTuple tuple = MessageFormatter.arrayFormat(message, formatArgs(args));\n                    delegate.warn(code, cause, extendedInformation, tuple.getMessage(), t);\n                }\n            } else {\n                delegate.warn(code, cause, extendedInformation, message, t);\n            }\n        } else if (messageSupplier != null && delegate.isWarnEnabled()) {\n            delegate.warn(code, cause, extendedInformation, messageSupplier.get(), t);\n        }\n    }\n\n    @Override\n    public void warn(String code, String message, Object... args) {\n        if (args == null || args.length == 0) {\n            delegate.warn(code, cause, extendedInformation, message);\n            return;\n        }\n        formatAndWarn(code, message, args);\n    }\n\n    private void formatAndWarn(String code, String message, Object... args) {\n        if (!delegate.isWarnEnabled()) {\n            return;\n        }\n        FormattingTuple tuple = MessageFormatter.arrayFormat(message, formatArgs(args));\n        if (tuple.getThrowable() == null) {\n            delegate.warn(code, cause, extendedInformation, tuple.getMessage());\n        } else {\n            delegate.warn(code, cause, extendedInformation, tuple.getMessage(), tuple.getThrowable());\n        }\n    }\n\n    @Override\n    public void warn(String code, String message, Throwable t) {\n        delegate.warn(code, cause, extendedInformation, message, t);\n    }\n\n    @Override\n    public void internalError() {\n        error(INTERNAL_ERROR);\n    }\n\n    @Override\n    public void internalError(Throwable t) {\n        error(INTERNAL_ERROR, t);\n    }\n\n    @Override\n    public void internalError(String message) {\n        error(INTERNAL_ERROR, message);\n    }\n\n    @Override\n    public void internalError(String message, Object... args) {\n        error(INTERNAL_ERROR, message, args);\n    }\n\n    @Override\n    public void internalError(String message, Throwable t) {\n        error(INTERNAL_ERROR, message, t);\n    }\n\n    @Override\n    public void error(String code) {\n        if (message != null) {\n            if (args != null && args.length > 0) {\n                formatAndError(code, message, args);\n            } else {\n                delegate.error(code, cause, extendedInformation, message);\n            }\n        } else if (messageSupplier != null) {\n            if (delegate.isErrorEnabled()) {\n                delegate.error(code, cause, extendedInformation, messageSupplier.get());\n            }\n        } else {\n            warnMessageMissing();\n        }\n    }\n\n    @Override\n    public void error(String code, Throwable t) {\n        if (message != null) {\n            if (args != null && args.length > 0) {\n                if (delegate.isErrorEnabled()) {\n                    FormattingTuple tuple = MessageFormatter.arrayFormat(message, formatArgs(args));\n                    delegate.error(code, cause, extendedInformation, tuple.getMessage(), t);\n                }\n            } else {\n                delegate.error(code, cause, extendedInformation, message, t);\n            }\n        } else if (messageSupplier != null) {\n            if (delegate.isErrorEnabled()) {\n                delegate.error(code, cause, extendedInformation, messageSupplier.get(), t);\n            }\n        } else {\n            warnMessageMissing();\n        }\n    }\n\n    @Override\n    public void error(String code, String message, Object... args) {\n        if (args == null || args.length == 0) {\n            delegate.error(code, cause, extendedInformation, message);\n            return;\n        }\n        formatAndError(code, message, args);\n    }\n\n    private void formatAndError(String code, String message, Object... args) {\n        if (!delegate.isErrorEnabled()) {\n            return;\n        }\n        FormattingTuple tuple = MessageFormatter.arrayFormat(message, formatArgs(args));\n        if (tuple.getThrowable() == null) {\n            delegate.error(code, cause, extendedInformation, tuple.getMessage());\n        } else {\n            delegate.error(code, cause, extendedInformation, tuple.getMessage(), tuple.getThrowable());\n        }\n    }\n\n    @Override\n    public void error(String code, String message, Throwable t) {\n        delegate.error(code, cause, extendedInformation, message, t);\n    }\n\n    @Override\n    public void log(Level level) {\n        switch (level) {\n            case TRACE:\n                trace();\n                break;\n            case DEBUG:\n                debug();\n                break;\n            case INFO:\n                info();\n                break;\n            case WARN:\n                internalWarn();\n                break;\n            case ERROR:\n                internalError();\n                break;\n            default:\n        }\n    }\n\n    @Override\n    public void log(Level level, Throwable t) {\n        switch (level) {\n            case TRACE:\n                trace(t);\n                break;\n            case DEBUG:\n                debug(t);\n                break;\n            case INFO:\n                info(t);\n                break;\n            case WARN:\n                internalWarn(t);\n                break;\n            case ERROR:\n                internalError(t);\n                break;\n            default:\n        }\n    }\n\n    @Override\n    public void log(Level level, String msg) {\n        switch (level) {\n            case TRACE:\n                trace(msg);\n                break;\n            case DEBUG:\n                debug(msg);\n                break;\n            case INFO:\n                info(msg);\n                break;\n            case WARN:\n                internalWarn(msg);\n                break;\n            case ERROR:\n                internalError(msg);\n                break;\n            default:\n        }\n    }\n\n    @Override\n    public void log(Level level, String msg, Object... args) {\n        switch (level) {\n            case TRACE:\n                trace(msg, args);\n                break;\n            case DEBUG:\n                debug(msg, args);\n                break;\n            case INFO:\n                info(msg, args);\n                break;\n            case WARN:\n                internalWarn(msg, args);\n                break;\n            case ERROR:\n                internalError(msg, args);\n                break;\n            default:\n        }\n    }\n\n    @Override\n    public void log(Level level, String msg, Throwable t) {\n        switch (level) {\n            case TRACE:\n                trace(msg, t);\n                break;\n            case DEBUG:\n                debug(msg, t);\n                break;\n            case INFO:\n                info(msg, t);\n                break;\n            case WARN:\n                internalWarn(msg, t);\n                break;\n            case ERROR:\n                internalError(msg, t);\n                break;\n            default:\n        }\n    }\n\n    @Override\n    public void log(String code, Level level) {\n        switch (level) {\n            case TRACE:\n                trace();\n                break;\n            case DEBUG:\n                debug();\n                break;\n            case INFO:\n                info();\n                break;\n            case WARN:\n                warn(code);\n                break;\n            case ERROR:\n                error(code);\n                break;\n            default:\n        }\n    }\n\n    @Override\n    public void log(String code, Level level, String msg, Object... args) {\n        switch (level) {\n            case TRACE:\n                trace(msg, args);\n                break;\n            case DEBUG:\n                debug(msg, args);\n                break;\n            case INFO:\n                info(msg, args);\n                break;\n            case WARN:\n                warn(code, msg, args);\n                break;\n            case ERROR:\n                error(code, msg, args);\n                break;\n            default:\n        }\n    }\n\n    @Override\n    public void log(String code, Level level, String msg, Throwable t) {\n        switch (level) {\n            case TRACE:\n                trace(msg, t);\n                break;\n            case DEBUG:\n                debug(msg, t);\n                break;\n            case INFO:\n                info(msg, t);\n                break;\n            case WARN:\n                warn(code, msg, t);\n                break;\n            case ERROR:\n                error(code, msg, t);\n                break;\n            default:\n        }\n    }\n\n    @Override\n    public boolean isTraceEnabled() {\n        return delegate.isTraceEnabled();\n    }\n\n    @Override\n    public boolean isDebugEnabled() {\n        return delegate.isDebugEnabled();\n    }\n\n    @Override\n    public boolean isInfoEnabled() {\n        return delegate.isInfoEnabled();\n    }\n\n    @Override\n    public boolean isWarnEnabled() {\n        return delegate.isWarnEnabled();\n    }\n\n    @Override\n    public boolean isErrorEnabled() {\n        return delegate.isErrorEnabled();\n    }\n\n    private FluentLoggerImpl getLogger() {\n        return this == root ? new FluentLoggerImpl(this) : this;\n    }\n\n    private void warnMessageMissing() {\n        delegate.warn(INTERNAL_ERROR, cause, extendedInformation, \"Message must not be empty\");\n    }\n\n    private static Object[] formatArgs(Object[] args) {\n        for (int i = 0; i < args.length; i++) {\n            if (args[i] instanceof Supplier) {\n                args[i] = ((Supplier<?>) args[i]).get();\n            }\n        }\n        return args;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/Level.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\n/**\n * Level\n */\npublic enum Level {\n\n    /**\n     * ALL\n     */\n    ALL,\n\n    /**\n     * TRACE\n     */\n    TRACE,\n\n    /**\n     * DEBUG\n     */\n    DEBUG,\n\n    /**\n     * INFO\n     */\n    INFO,\n\n    /**\n     * WARN\n     */\n    WARN,\n\n    /**\n     * ERROR\n     */\n    ERROR,\n\n    /**\n     * OFF\n     */\n    OFF\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/ListenableLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\n/**\n *  Loggers that can register to listen to log messages.\n */\npublic interface ListenableLogger extends ErrorTypeAwareLogger {\n\n    /**\n     * Register a listener to this logger，and get notified when a log happens.\n     *\n     * @param listener log listener\n     */\n    void registerListen(LogListener listener);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/LogListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\n/**\n * Log Listener, can registered to an {@link ListenableLogger}.\n */\npublic interface LogListener {\n\n    void onMessage(String code, String msg);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/Logger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\n/**\n * Logger interface\n * <p>\n * This interface is referred from commons-logging\n */\npublic interface Logger {\n\n    /**\n     * Logs a message with trace log level.\n     *\n     * @param msg log this message\n     */\n    void trace(String msg);\n\n    /**\n     * Logs a message with trace log level.\n     *\n     * @param msg log this message\n     * @param arguments a list of arguments\n     */\n    void trace(String msg, Object... arguments);\n\n    /**\n     * Logs an error with trace log level.\n     *\n     * @param e log this cause\n     */\n    void trace(Throwable e);\n\n    /**\n     * Logs an error with trace log level.\n     *\n     * @param msg log this message\n     * @param e   log this cause\n     */\n    void trace(String msg, Throwable e);\n\n    /**\n     * Logs a message with debug log level.\n     *\n     * @param msg log this message\n     */\n    void debug(String msg);\n\n    /**\n     * Logs a message with debug log level.\n     *\n     * @param msg log this message\n     * @param arguments a list of arguments\n     */\n    void debug(String msg, Object... arguments);\n\n    /**\n     * Logs an error with debug log level.\n     *\n     * @param e log this cause\n     */\n    void debug(Throwable e);\n\n    /**\n     * Logs an error with debug log level.\n     *\n     * @param msg log this message\n     * @param e   log this cause\n     */\n    void debug(String msg, Throwable e);\n\n    /**\n     * Logs a message with info log level.\n     *\n     * @param msg log this message\n     */\n    void info(String msg);\n\n    /**\n     * Logs a message with info log level.\n     *\n     * @param msg log this message\n     * @param arguments a list of arguments\n     */\n    void info(String msg, Object... arguments);\n\n    /**\n     * Logs an error with info log level.\n     *\n     * @param e log this cause\n     */\n    void info(Throwable e);\n\n    /**\n     * Logs an error with info log level.\n     *\n     * @param msg log this message\n     * @param e   log this cause\n     */\n    void info(String msg, Throwable e);\n\n    /**\n     * Logs a message with warn log level.\n     *\n     * @param msg log this message\n     */\n    void warn(String msg);\n\n    /**\n     * Logs a message with warn log level.\n     *\n     * @param msg log this message\n     * @param arguments a list of arguments\n     */\n    void warn(String msg, Object... arguments);\n\n    /**\n     * Logs a message with warn log level.\n     *\n     * @param e log this message\n     */\n    void warn(Throwable e);\n\n    /**\n     * Logs a message with warn log level.\n     *\n     * @param msg log this message\n     * @param e   log this cause\n     */\n    void warn(String msg, Throwable e);\n\n    /**\n     * Logs a message with error log level.\n     *\n     * @param msg log this message\n     */\n    void error(String msg);\n\n    /**\n     * Logs a message with error log level.\n     *\n     * @param msg log this message\n     * @param arguments a list of arguments\n     */\n    void error(String msg, Object... arguments);\n\n    /**\n     * Logs an error with error log level.\n     *\n     * @param e log this cause\n     */\n    void error(Throwable e);\n\n    /**\n     * Logs an error with error log level.\n     *\n     * @param msg log this message\n     * @param e   log this cause\n     */\n    void error(String msg, Throwable e);\n\n    /**\n     * Is trace logging currently enabled?\n     *\n     * @return true if trace is enabled\n     */\n    boolean isTraceEnabled();\n\n    /**\n     * Is debug logging currently enabled?\n     *\n     * @return true if debug is enabled\n     */\n    boolean isDebugEnabled();\n\n    /**\n     * Is info logging currently enabled?\n     *\n     * @return true if info is enabled\n     */\n    boolean isInfoEnabled();\n\n    /**\n     * Is warn logging currently enabled?\n     *\n     * @return true if warn is enabled\n     */\n    boolean isWarnEnabled();\n\n    /**\n     * Is error logging currently enabled?\n     *\n     * @return true if error is enabled\n     */\n    boolean isErrorEnabled();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/LoggerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.io.File;\n\n/**\n * Logger provider\n */\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface LoggerAdapter {\n\n    /**\n     * Get a logger\n     *\n     * @param key the returned logger will be named after clazz\n     * @return logger\n     */\n    Logger getLogger(Class<?> key);\n\n    /**\n     * Get a logger\n     *\n     * @param key the returned logger will be named after key\n     * @return logger\n     */\n    Logger getLogger(String key);\n\n    /**\n     * Get a logger\n     *\n     * @param fqcn the full qualified class name of caller\n     * @param key the returned logger will be named after clazz\n     * @return logger\n     */\n    default Logger getLogger(String fqcn, Class<?> key) {\n        return getLogger(key);\n    }\n\n    /**\n     * Get a logger\n     *\n     * @param fqcn the full qualified class name of caller\n     * @param key the returned logger will be named after key\n     * @return logger\n     */\n    default Logger getLogger(String fqcn, String key) {\n        return getLogger(key);\n    }\n\n    /**\n     * Get the current logging level\n     *\n     * @return current logging level\n     */\n    Level getLevel();\n\n    /**\n     * Set the current logging level\n     *\n     * @param level logging level\n     */\n    void setLevel(Level level);\n\n    /**\n     * Get the current logging file\n     *\n     * @return current logging file\n     */\n    File getFile();\n\n    /**\n     * Set the current logging file\n     *\n     * @param file logging file\n     */\n    void setFile(File file);\n\n    /**\n     * Return is the current logger has been configured.\n     * Used to check if logger is available to use.\n     *\n     * @return true if the current logger has been configured\n     */\n    default boolean isConfigured() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/LoggerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.jcl.JclLoggerAdapter;\nimport org.apache.dubbo.common.logger.jdk.JdkLoggerAdapter;\nimport org.apache.dubbo.common.logger.log4j.Log4jLoggerAdapter;\nimport org.apache.dubbo.common.logger.log4j2.Log4j2LoggerAdapter;\nimport org.apache.dubbo.common.logger.slf4j.Slf4jLoggerAdapter;\nimport org.apache.dubbo.common.logger.support.FailsafeErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.support.FailsafeLogger;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.Pair;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Logger factory\n */\npublic class LoggerFactory {\n\n    private static final ConcurrentMap<String, FailsafeLogger> LOGGERS = new ConcurrentHashMap<>();\n    private static final ConcurrentMap<Object, FailsafeErrorTypeAwareLogger> ERROR_TYPE_AWARE_LOGGERS =\n            new ConcurrentHashMap<>();\n    private static volatile LoggerAdapter loggerAdapter;\n\n    // search common-used logging frameworks\n    static {\n        String logger =\n                SystemPropertyConfigUtils.getSystemProperty(CommonConstants.DubboProperty.DUBBO_APPLICATION_LOGGER, \"\");\n        switch (logger) {\n            case Slf4jLoggerAdapter.NAME:\n                setLoggerAdapter(new Slf4jLoggerAdapter());\n                break;\n            case JclLoggerAdapter.NAME:\n                setLoggerAdapter(new JclLoggerAdapter());\n                break;\n            case Log4jLoggerAdapter.NAME:\n                setLoggerAdapter(new Log4jLoggerAdapter());\n                break;\n            case JdkLoggerAdapter.NAME:\n                setLoggerAdapter(new JdkLoggerAdapter());\n                break;\n            case Log4j2LoggerAdapter.NAME:\n                setLoggerAdapter(new Log4j2LoggerAdapter());\n                break;\n            default:\n                List<Class<? extends LoggerAdapter>> candidates = Arrays.asList(\n                        Log4jLoggerAdapter.class,\n                        Slf4jLoggerAdapter.class,\n                        Log4j2LoggerAdapter.class,\n                        JclLoggerAdapter.class,\n                        JdkLoggerAdapter.class);\n                boolean found = false;\n                // try to use the first available adapter\n                for (Class<? extends LoggerAdapter> clazz : candidates) {\n                    try {\n                        LoggerAdapter loggerAdapter =\n                                clazz.getDeclaredConstructor().newInstance();\n                        loggerAdapter.getLogger(LoggerFactory.class);\n                        if (loggerAdapter.isConfigured()) {\n                            setLoggerAdapter(loggerAdapter);\n                            found = true;\n                            break;\n                        }\n                    } catch (Exception | LinkageError ignored) {\n                        // ignore\n                    }\n                }\n                if (found) {\n                    break;\n                }\n\n                System.err.println(\"Dubbo: Unable to find a proper configured logger to log out.\");\n                for (Class<? extends LoggerAdapter> clazz : candidates) {\n                    try {\n                        LoggerAdapter loggerAdapter =\n                                clazz.getDeclaredConstructor().newInstance();\n                        loggerAdapter.getLogger(LoggerFactory.class);\n                        setLoggerAdapter(loggerAdapter);\n                        found = true;\n                        break;\n                    } catch (Throwable ignored) {\n                        // ignore\n                    }\n                }\n                if (found) {\n                    System.err.println(\n                            \"Dubbo: Using default logger: \"\n                                    + loggerAdapter.getClass().getName() + \". \"\n                                    + \"If you cannot see any log, please configure -Ddubbo.application.logger property to your preferred logging framework.\");\n                } else {\n                    System.err.println(\n                            \"Dubbo: Unable to find any available logger adapter to log out. Dubbo logs will be ignored. \"\n                                    + \"Please configure -Ddubbo.application.logger property and add corresponding logging library to classpath.\");\n                }\n        }\n    }\n\n    private LoggerFactory() {}\n\n    public static void setLoggerAdapter(FrameworkModel frameworkModel, String loggerAdapter) {\n        if (loggerAdapter != null && loggerAdapter.length() > 0) {\n            setLoggerAdapter(\n                    frameworkModel.getExtensionLoader(LoggerAdapter.class).getExtension(loggerAdapter));\n        }\n    }\n\n    /**\n     * Set logger provider\n     *\n     * @param loggerAdapter logger provider\n     */\n    public static void setLoggerAdapter(LoggerAdapter loggerAdapter) {\n        if (loggerAdapter != null) {\n            if (loggerAdapter == LoggerFactory.loggerAdapter) {\n                return;\n            }\n            loggerAdapter.getLogger(LoggerFactory.class.getName());\n            LoggerFactory.loggerAdapter = loggerAdapter;\n            for (Map.Entry<String, FailsafeLogger> entry : LOGGERS.entrySet()) {\n                entry.getValue().setLogger(LoggerFactory.loggerAdapter.getLogger(entry.getKey()));\n            }\n        }\n    }\n\n    /**\n     * Get logger provider\n     *\n     * @param key the returned logger will be named after clazz\n     * @return logger\n     */\n    public static Logger getLogger(Class<?> key) {\n        return ConcurrentHashMapUtils.computeIfAbsent(\n                LOGGERS, key.getName(), name -> new FailsafeLogger(loggerAdapter.getLogger(name)));\n    }\n\n    /**\n     * Get logger provider\n     *\n     * @param key the returned logger will be named after key\n     * @return logger provider\n     */\n    public static Logger getLogger(String key) {\n        return ConcurrentHashMapUtils.computeIfAbsent(\n                LOGGERS, key, k -> new FailsafeLogger(loggerAdapter.getLogger(k)));\n    }\n\n    /**\n     * Get error type aware logger by Class object.\n     *\n     * @param key the returned logger will be named after clazz\n     * @return error type aware logger\n     */\n    public static ErrorTypeAwareLogger getErrorTypeAwareLogger(Class<?> key) {\n        final String name = key.getName();\n        return ConcurrentHashMapUtils.computeIfAbsent(\n                ERROR_TYPE_AWARE_LOGGERS, name, k -> new FailsafeErrorTypeAwareLogger(loggerAdapter.getLogger(name)));\n    }\n\n    /**\n     * Get error type aware logger by a String key.\n     *\n     * @param key the returned logger will be named after key\n     * @return error type aware logger\n     */\n    public static ErrorTypeAwareLogger getErrorTypeAwareLogger(String key) {\n        return ConcurrentHashMapUtils.computeIfAbsent(\n                ERROR_TYPE_AWARE_LOGGERS, key, k -> new FailsafeErrorTypeAwareLogger(loggerAdapter.getLogger(key)));\n    }\n\n    /**\n     * Get error type aware logger by FQCN and Class object.\n     *\n     * @param fqcn the full qualified class name of caller\n     * @param key the returned logger will be named after clazz\n     * @return error type aware logger\n     */\n    public static ErrorTypeAwareLogger getErrorTypeAwareLogger(String fqcn, Class<?> key) {\n        final String name = key.getName();\n        return ConcurrentHashMapUtils.computeIfAbsent(\n                ERROR_TYPE_AWARE_LOGGERS,\n                Pair.of(name, fqcn),\n                p -> new FailsafeErrorTypeAwareLogger(loggerAdapter.getLogger(fqcn, name)));\n    }\n\n    /**\n     * Get error type aware logger by FQCN and a String key.\n     *\n     * @param fqcn the full qualified class name of caller\n     * @param key the returned logger will be named after key\n     * @return error type aware logger\n     */\n    public static ErrorTypeAwareLogger getErrorTypeAwareLogger(String fqcn, String key) {\n        return ConcurrentHashMapUtils.computeIfAbsent(\n                ERROR_TYPE_AWARE_LOGGERS,\n                Pair.of(key, fqcn),\n                p -> new FailsafeErrorTypeAwareLogger(loggerAdapter.getLogger(fqcn, key)));\n    }\n\n    /**\n     * Get logging level\n     *\n     * @return logging level\n     */\n    public static Level getLevel() {\n        return loggerAdapter.getLevel();\n    }\n\n    /**\n     * Set the current logging level\n     *\n     * @param level logging level\n     */\n    public static void setLevel(Level level) {\n        loggerAdapter.setLevel(level);\n    }\n\n    /**\n     * Get the current logging file\n     *\n     * @return current logging file\n     */\n    public static File getFile() {\n        return loggerAdapter.getFile();\n    }\n\n    /**\n     * Get the available adapter names\n     *\n     * @return available adapter names\n     */\n    public static List<String> getAvailableAdapter() {\n        Map<Class<? extends LoggerAdapter>, String> candidates = new HashMap<>();\n        candidates.put(Log4jLoggerAdapter.class, \"log4j\");\n        candidates.put(Slf4jLoggerAdapter.class, \"slf4j\");\n        candidates.put(Log4j2LoggerAdapter.class, \"log4j2\");\n        candidates.put(JclLoggerAdapter.class, \"jcl\");\n        candidates.put(JdkLoggerAdapter.class, \"jdk\");\n        List<String> result = new LinkedList<>();\n        for (Map.Entry<Class<? extends LoggerAdapter>, String> entry : candidates.entrySet()) {\n            try {\n                LoggerAdapter loggerAdapter =\n                        entry.getKey().getDeclaredConstructor().newInstance();\n                loggerAdapter.getLogger(LoggerFactory.class);\n                result.add(entry.getValue());\n            } catch (Exception ignored) {\n                // ignored\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Get the current adapter name\n     *\n     * @return current adapter name\n     */\n    public static String getCurrentAdapter() {\n        Map<Class<? extends LoggerAdapter>, String> candidates = new HashMap<>();\n        candidates.put(Log4jLoggerAdapter.class, \"log4j\");\n        candidates.put(Slf4jLoggerAdapter.class, \"slf4j\");\n        candidates.put(Log4j2LoggerAdapter.class, \"log4j2\");\n        candidates.put(JclLoggerAdapter.class, \"jcl\");\n        candidates.put(JdkLoggerAdapter.class, \"jdk\");\n\n        String name = candidates.get(loggerAdapter.getClass());\n        if (name == null) {\n            name = loggerAdapter.getClass().getSimpleName();\n        }\n        return name;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/helpers/FormattingTuple.java",
    "content": "/*\n * Copyright (c) 2004-2011 QOS.ch\n * All rights reserved.\n *\n * Permission is hereby granted, free  of charge, to any person obtaining\n * a  copy  of this  software  and  associated  documentation files  (the\n * \"Software\"), to  deal in  the Software without  restriction, including\n * without limitation  the rights to  use, copy, modify,  merge, publish,\n * distribute,  sublicense, and/or sell  copies of  the Software,  and to\n * permit persons to whom the Software  is furnished to do so, subject to\n * the following conditions:\n *\n * The  above  copyright  notice  and  this permission  notice  shall  be\n * included in all copies or substantial portions of the Software.\n *\n * THE  SOFTWARE IS  PROVIDED  \"AS  IS\", WITHOUT  WARRANTY  OF ANY  KIND,\n * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF\n * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION\n * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\npackage org.apache.dubbo.common.logger.helpers;\n\n/**\n * Holds the results of formatting done by {@link MessageFormatter}.\n * This is a copy of org.slf4j.helpers.FormattingTuple from slf4j-api.\n */\npublic class FormattingTuple {\n\n    static public FormattingTuple NULL = new FormattingTuple(null);\n\n    private String message;\n    private Throwable throwable;\n    private Object[] argArray;\n\n    public FormattingTuple(String message) {\n        this(message, null, null);\n    }\n\n    public FormattingTuple(String message, Object[] argArray, Throwable throwable) {\n        this.message = message;\n        this.throwable = throwable;\n        this.argArray = argArray;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public Object[] getArgArray() {\n        return argArray;\n    }\n\n    public Throwable getThrowable() {\n        return throwable;\n    }\n\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/helpers/MessageFormatter.java",
    "content": "/*\n * Copyright (c) 2004-2011 QOS.ch\n * All rights reserved.\n *\n * Permission is hereby granted, free  of charge, to any person obtaining\n * a  copy  of this  software  and  associated  documentation files  (the\n * \"Software\"), to  deal in  the Software without  restriction, including\n * without limitation  the rights to  use, copy, modify,  merge, publish,\n * distribute,  sublicense, and/or sell  copies of  the Software,  and to\n * permit persons to whom the Software  is furnished to do so, subject to\n * the following conditions:\n *\n * The  above  copyright  notice  and  this permission  notice  shall  be\n * included in all copies or substantial portions of the Software.\n *\n * THE  SOFTWARE IS  PROVIDED  \"AS  IS\", WITHOUT  WARRANTY  OF ANY  KIND,\n * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF\n * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION\n * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\npackage org.apache.dubbo.common.logger.helpers;\n\nimport java.text.MessageFormat;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * This is a copy of org.slf4j.helpers.MessageFormatter from slf4j-api.\n * Formats messages according to very simple substitution rules. Substitutions\n * can be made 1, 2 or more arguments.\n *\n * <p>\n * For example,\n *\n * <pre>\n * MessageFormatter.format(&quot;Hi {}.&quot;, &quot;there&quot;)\n * </pre>\n * <p>\n * will return the string \"Hi there.\".\n * <p>\n * The {} pair is called the <em>formatting anchor</em>. It serves to designate\n * the location where arguments need to be substituted within the message\n * pattern.\n * <p>\n * In case your message contains the '{' or the '}' character, you do not have\n * to do anything special unless the '}' character immediately follows '{'. For\n * example,\n *\n * <pre>\n * MessageFormatter.format(&quot;Set {1,2,3} is not equal to {}.&quot;, &quot;1,2&quot;);\n * </pre>\n * <p>\n * will return the string \"Set {1,2,3} is not equal to 1,2.\".\n *\n * <p>\n * If for whatever reason you need to place the string \"{}\" in the message\n * without its <em>formatting anchor</em> meaning, then you need to escape the\n * '{' character with '\\', that is the backslash character. Only the '{'\n * character should be escaped. There is no need to escape the '}' character.\n * For example,\n *\n * <pre>\n * MessageFormatter.format(&quot;Set \\\\{} is not equal to {}.&quot;, &quot;1,2&quot;);\n * </pre>\n * <p>\n * will return the string \"Set {} is not equal to 1,2.\".\n *\n * <p>\n * The escaping behavior just described can be overridden by escaping the escape\n * character '\\'. Calling\n *\n * <pre>\n * MessageFormatter.format(&quot;File name is C:\\\\\\\\{}.&quot;, &quot;file.zip&quot;);\n * </pre>\n * <p>\n * will return the string \"File name is C:\\file.zip\".\n *\n * <p>\n * The formatting conventions are different than those of {@link MessageFormat}\n * which ships with the Java platform. This is justified by the fact that\n * SLF4J's implementation is 10 times faster than that of {@link MessageFormat}.\n * This local performance difference is both measurable and significant in the\n * larger context of the complete logging processing chain.\n *\n * <p>\n * See also {@link #format(String, Object)},\n * {@link #format(String, Object, Object)} and\n * {@link #arrayFormat(String, Object[])} methods for more details.\n *\n */\nfinal public class MessageFormatter {\n    static final char DELIM_START = '{';\n    static final char DELIM_STOP = '}';\n    static final String DELIM_STR = \"{}\";\n    private static final char ESCAPE_CHAR = '\\\\';\n\n    /**\n     * Performs single argument substitution for the 'messagePattern' passed as\n     * parameter.\n     * <p>\n     * For example,\n     *\n     * <pre>\n     * MessageFormatter.format(&quot;Hi {}.&quot;, &quot;there&quot;);\n     * </pre>\n     * <p>\n     * will return the string \"Hi there.\".\n     * <p>\n     *\n     * @param messagePattern The message pattern which will be parsed and formatted\n     * @param arg            The argument to be substituted in place of the formatting anchor\n     * @return The formatted message\n     */\n    final public static FormattingTuple format(String messagePattern, Object arg) {\n        return arrayFormat(messagePattern, new Object[]{arg});\n    }\n\n    /**\n     * Performs a two argument substitution for the 'messagePattern' passed as\n     * parameter.\n     * <p>\n     * For example,\n     *\n     * <pre>\n     * MessageFormatter.format(&quot;Hi {}. My name is {}.&quot;, &quot;Alice&quot;, &quot;Bob&quot;);\n     * </pre>\n     * <p>\n     * will return the string \"Hi Alice. My name is Bob.\".\n     *\n     * @param messagePattern The message pattern which will be parsed and formatted\n     * @param arg1           The argument to be substituted in place of the first formatting\n     *                       anchor\n     * @param arg2           The argument to be substituted in place of the second formatting\n     *                       anchor\n     * @return The formatted message\n     */\n    final public static FormattingTuple format(final String messagePattern, Object arg1, Object arg2) {\n        return arrayFormat(messagePattern, new Object[]{arg1, arg2});\n    }\n\n\n    final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray) {\n        Throwable throwableCandidate = MessageFormatter.getThrowableCandidate(argArray);\n        Object[] args = argArray;\n        if (throwableCandidate != null) {\n            args = MessageFormatter.trimmedCopy(argArray);\n        }\n        return arrayFormat(messagePattern, args, throwableCandidate);\n    }\n\n    final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray, Throwable throwable) {\n\n        if (messagePattern == null) {\n            return new FormattingTuple(null, argArray, throwable);\n        }\n\n        if (argArray == null) {\n            return new FormattingTuple(messagePattern);\n        }\n\n        int i = 0;\n        int j;\n        // use string builder for better multicore performance\n        StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);\n\n        int L;\n        for (L = 0; L < argArray.length; L++) {\n\n            j = messagePattern.indexOf(DELIM_STR, i);\n\n            if (j == -1) {\n                // no more variables\n                if (i == 0) { // this is a simple string\n                    return new FormattingTuple(messagePattern, argArray, throwable);\n                } else { // add the tail string which contains no variables and return\n                    // the result.\n                    sbuf.append(messagePattern, i, messagePattern.length());\n                    return new FormattingTuple(sbuf.toString(), argArray, throwable);\n                }\n            } else {\n                if (isEscapedDelimeter(messagePattern, j)) {\n                    if (!isDoubleEscaped(messagePattern, j)) {\n                        L--; // DELIM_START was escaped, thus should not be incremented\n                        sbuf.append(messagePattern, i, j - 1);\n                        sbuf.append(DELIM_START);\n                        i = j + 1;\n                    } else {\n                        // The escape character preceding the delimiter start is\n                        // itself escaped: \"abc x:\\\\{}\"\n                        // we have to consume one backward slash\n                        sbuf.append(messagePattern, i, j - 1);\n                        deeplyAppendParameter(sbuf, argArray[L], new HashMap<Object[], Object>());\n                        i = j + 2;\n                    }\n                } else {\n                    // normal case\n                    sbuf.append(messagePattern, i, j);\n                    deeplyAppendParameter(sbuf, argArray[L], new HashMap<Object[], Object>());\n                    i = j + 2;\n                }\n            }\n        }\n        // append the characters following the last {} pair.\n        sbuf.append(messagePattern, i, messagePattern.length());\n        return new FormattingTuple(sbuf.toString(), argArray, throwable);\n    }\n\n    final static boolean isEscapedDelimeter(String messagePattern, int delimeterStartIndex) {\n\n        if (delimeterStartIndex == 0) {\n            return false;\n        }\n        char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);\n        if (potentialEscape == ESCAPE_CHAR) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    final static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) {\n        if (delimeterStartIndex >= 2 && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    // special treatment of array values was suggested by 'lizongbo'\n    private static void deeplyAppendParameter(StringBuilder sbuf, Object o, Map<Object[], Object> seenMap) {\n        if (o == null) {\n            sbuf.append(\"null\");\n            return;\n        }\n        if (!o.getClass().isArray()) {\n            safeObjectAppend(sbuf, o);\n        } else {\n            // check for primitive array types because they\n            // unfortunately cannot be cast to Object[]\n            if (o instanceof boolean[]) {\n                booleanArrayAppend(sbuf, (boolean[]) o);\n            } else if (o instanceof byte[]) {\n                byteArrayAppend(sbuf, (byte[]) o);\n            } else if (o instanceof char[]) {\n                charArrayAppend(sbuf, (char[]) o);\n            } else if (o instanceof short[]) {\n                shortArrayAppend(sbuf, (short[]) o);\n            } else if (o instanceof int[]) {\n                intArrayAppend(sbuf, (int[]) o);\n            } else if (o instanceof long[]) {\n                longArrayAppend(sbuf, (long[]) o);\n            } else if (o instanceof float[]) {\n                floatArrayAppend(sbuf, (float[]) o);\n            } else if (o instanceof double[]) {\n                doubleArrayAppend(sbuf, (double[]) o);\n            } else {\n                objectArrayAppend(sbuf, (Object[]) o, seenMap);\n            }\n        }\n    }\n\n    private static void safeObjectAppend(StringBuilder sbuf, Object o) {\n        try {\n            String oAsString = o.toString();\n            sbuf.append(oAsString);\n        } catch (Throwable t) {\n            System.err.println(\"SLF4J: Failed toString() invocation on an object of type [\" + o.getClass().getName() + \"]\");\n            System.err.println(\"Reported exception:\");\n            StackTraceElement[] stackTrace = t.getStackTrace();\n            StringBuilder stackBuilder = new StringBuilder();\n            for (StackTraceElement traceElement : stackTrace) {\n                stackBuilder.append(\"\\tat \").append(traceElement).append(\"\\n\");\n            }\n            System.err.println(stackBuilder);\n            sbuf.append(\"[FAILED toString()]\");\n        }\n\n    }\n\n    private static void objectArrayAppend(StringBuilder sbuf, Object[] a, Map<Object[], Object> seenMap) {\n        sbuf.append('[');\n        if (!seenMap.containsKey(a)) {\n            seenMap.put(a, null);\n            final int len = a.length;\n            for (int i = 0; i < len; i++) {\n                deeplyAppendParameter(sbuf, a[i], seenMap);\n                if (i != len - 1)\n                    sbuf.append(\", \");\n            }\n            // allow repeats in siblings\n            seenMap.remove(a);\n        } else {\n            sbuf.append(\"...\");\n        }\n        sbuf.append(']');\n    }\n\n    private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) {\n        sbuf.append('[');\n        final int len = a.length;\n        for (int i = 0; i < len; i++) {\n            sbuf.append(a[i]);\n            if (i != len - 1)\n                sbuf.append(\", \");\n        }\n        sbuf.append(']');\n    }\n\n    private static void byteArrayAppend(StringBuilder sbuf, byte[] a) {\n        sbuf.append('[');\n        final int len = a.length;\n        for (int i = 0; i < len; i++) {\n            sbuf.append(a[i]);\n            if (i != len - 1)\n                sbuf.append(\", \");\n        }\n        sbuf.append(']');\n    }\n\n    private static void charArrayAppend(StringBuilder sbuf, char[] a) {\n        sbuf.append('[');\n        final int len = a.length;\n        for (int i = 0; i < len; i++) {\n            sbuf.append(a[i]);\n            if (i != len - 1)\n                sbuf.append(\", \");\n        }\n        sbuf.append(']');\n    }\n\n    private static void shortArrayAppend(StringBuilder sbuf, short[] a) {\n        sbuf.append('[');\n        final int len = a.length;\n        for (int i = 0; i < len; i++) {\n            sbuf.append(a[i]);\n            if (i != len - 1)\n                sbuf.append(\", \");\n        }\n        sbuf.append(']');\n    }\n\n    private static void intArrayAppend(StringBuilder sbuf, int[] a) {\n        sbuf.append('[');\n        final int len = a.length;\n        for (int i = 0; i < len; i++) {\n            sbuf.append(a[i]);\n            if (i != len - 1)\n                sbuf.append(\", \");\n        }\n        sbuf.append(']');\n    }\n\n    private static void longArrayAppend(StringBuilder sbuf, long[] a) {\n        sbuf.append('[');\n        final int len = a.length;\n        for (int i = 0; i < len; i++) {\n            sbuf.append(a[i]);\n            if (i != len - 1)\n                sbuf.append(\", \");\n        }\n        sbuf.append(']');\n    }\n\n    private static void floatArrayAppend(StringBuilder sbuf, float[] a) {\n        sbuf.append('[');\n        final int len = a.length;\n        for (int i = 0; i < len; i++) {\n            sbuf.append(a[i]);\n            if (i != len - 1)\n                sbuf.append(\", \");\n        }\n        sbuf.append(']');\n    }\n\n    private static void doubleArrayAppend(StringBuilder sbuf, double[] a) {\n        sbuf.append('[');\n        final int len = a.length;\n        for (int i = 0; i < len; i++) {\n            sbuf.append(a[i]);\n            if (i != len - 1)\n                sbuf.append(\", \");\n        }\n        sbuf.append(']');\n    }\n\n    /**\n     * Helper method to determine if an {@link Object} array contains a {@link Throwable} as last element\n     *\n     * @param argArray The arguments off which we want to know if it contains a {@link Throwable} as last element\n     * @return if the last {@link Object} in argArray is a {@link Throwable} this method will return it,\n     * otherwise it returns null\n     */\n    public static Throwable getThrowableCandidate(final Object[] argArray) {\n        if (argArray == null || argArray.length == 0) {\n            return null;\n        }\n\n        final Object lastEntry = argArray[argArray.length - 1];\n        if (lastEntry instanceof Throwable) {\n            return (Throwable) lastEntry;\n        }\n\n        return null;\n    }\n\n    /**\n     * Helper method to get all but the last element of an array\n     *\n     * @param argArray The arguments from which we want to remove the last element\n     * @return a copy of the array without the last element\n     */\n    public static Object[] trimmedCopy(final Object[] argArray) {\n        if (argArray == null || argArray.length == 0) {\n            throw new IllegalStateException(\"non-sensical empty or null argument array\");\n        }\n\n        final int trimmedLen = argArray.length - 1;\n\n        Object[] trimmed = new Object[trimmedLen];\n\n        if (trimmedLen > 0) {\n            System.arraycopy(argArray, 0, trimmed, 0, trimmedLen);\n        }\n\n        return trimmed;\n    }\n\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/jcl/JclLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.jcl;\n\nimport org.apache.dubbo.common.logger.Logger;\n\nimport org.apache.commons.logging.Log;\nimport org.slf4j.helpers.FormattingTuple;\nimport org.slf4j.helpers.MessageFormatter;\n\n/**\n * Adaptor to commons logging, depends on commons-logging.jar. For more information about commons logging, pls. refer to\n * <a target=\"_blank\" href=\"http://www.apache.org/\">http://www.apache.org/</a>\n */\npublic class JclLogger implements Logger {\n\n    private final Log logger;\n\n    public JclLogger(Log logger) {\n        this.logger = logger;\n    }\n\n    @Override\n    public void trace(String msg) {\n        logger.trace(msg);\n    }\n\n    @Override\n    public void trace(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.trace(ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void trace(Throwable e) {\n        logger.trace(e);\n    }\n\n    @Override\n    public void trace(String msg, Throwable e) {\n        logger.trace(msg, e);\n    }\n\n    @Override\n    public void debug(String msg) {\n        logger.debug(msg);\n    }\n\n    @Override\n    public void debug(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.debug(ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void debug(Throwable e) {\n        logger.debug(e);\n    }\n\n    @Override\n    public void debug(String msg, Throwable e) {\n        logger.debug(msg, e);\n    }\n\n    @Override\n    public void info(String msg) {\n        logger.info(msg);\n    }\n\n    @Override\n    public void info(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.info(ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void info(Throwable e) {\n        logger.info(e);\n    }\n\n    @Override\n    public void info(String msg, Throwable e) {\n        logger.info(msg, e);\n    }\n\n    @Override\n    public void warn(String msg) {\n        logger.warn(msg);\n    }\n\n    @Override\n    public void warn(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.warn(ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void warn(Throwable e) {\n        logger.warn(e);\n    }\n\n    @Override\n    public void warn(String msg, Throwable e) {\n        logger.warn(msg, e);\n    }\n\n    @Override\n    public void error(String msg) {\n        logger.error(msg);\n    }\n\n    @Override\n    public void error(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.error(ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void error(Throwable e) {\n        logger.error(e);\n    }\n\n    @Override\n    public void error(String msg, Throwable e) {\n        logger.error(msg, e);\n    }\n\n    @Override\n    public boolean isTraceEnabled() {\n        return logger.isTraceEnabled();\n    }\n\n    @Override\n    public boolean isDebugEnabled() {\n        return logger.isDebugEnabled();\n    }\n\n    @Override\n    public boolean isInfoEnabled() {\n        return logger.isInfoEnabled();\n    }\n\n    @Override\n    public boolean isWarnEnabled() {\n        return logger.isWarnEnabled();\n    }\n\n    @Override\n    public boolean isErrorEnabled() {\n        return logger.isErrorEnabled();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/jcl/JclLoggerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.jcl;\n\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerAdapter;\n\nimport java.io.File;\n\nimport org.apache.commons.logging.LogFactory;\n\npublic class JclLoggerAdapter implements LoggerAdapter {\n    public static final String NAME = \"jcl\";\n    private Level level;\n    private File file;\n\n    @Override\n    public Logger getLogger(String key) {\n        return new JclLogger(LogFactory.getLog(key));\n    }\n\n    @Override\n    public Logger getLogger(Class<?> key) {\n        return new JclLogger(LogFactory.getLog(key));\n    }\n\n    @Override\n    public Level getLevel() {\n        return level;\n    }\n\n    @Override\n    public void setLevel(Level level) {\n        this.level = level;\n    }\n\n    @Override\n    public File getFile() {\n        return file;\n    }\n\n    @Override\n    public void setFile(File file) {\n        this.file = file;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/jdk/JdkLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.jdk;\n\nimport org.apache.dubbo.common.logger.Logger;\n\nimport java.util.logging.Level;\n\nimport org.slf4j.helpers.FormattingTuple;\nimport org.slf4j.helpers.MessageFormatter;\n\npublic class JdkLogger implements Logger {\n\n    private final java.util.logging.Logger logger;\n\n    public JdkLogger(java.util.logging.Logger logger) {\n        this.logger = logger;\n    }\n\n    @Override\n    public void trace(String msg) {\n        logger.log(Level.FINER, msg);\n    }\n\n    @Override\n    public void trace(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.log(Level.FINER, ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void trace(Throwable e) {\n        logger.log(Level.FINER, e.getMessage(), e);\n    }\n\n    @Override\n    public void trace(String msg, Throwable e) {\n        logger.log(Level.FINER, msg, e);\n    }\n\n    @Override\n    public void debug(String msg) {\n        logger.log(Level.FINE, msg);\n    }\n\n    @Override\n    public void debug(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.log(Level.FINE, ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void debug(Throwable e) {\n        logger.log(Level.FINE, e.getMessage(), e);\n    }\n\n    @Override\n    public void debug(String msg, Throwable e) {\n        logger.log(Level.FINE, msg, e);\n    }\n\n    @Override\n    public void info(String msg) {\n        logger.log(Level.INFO, msg);\n    }\n\n    @Override\n    public void info(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.log(Level.INFO, ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void info(String msg, Throwable e) {\n        logger.log(Level.INFO, msg, e);\n    }\n\n    @Override\n    public void warn(String msg) {\n        logger.log(Level.WARNING, msg);\n    }\n\n    @Override\n    public void warn(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.log(Level.WARNING, ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void warn(String msg, Throwable e) {\n        logger.log(Level.WARNING, msg, e);\n    }\n\n    @Override\n    public void error(String msg) {\n        logger.log(Level.SEVERE, msg);\n    }\n\n    @Override\n    public void error(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.log(Level.SEVERE, ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void error(String msg, Throwable e) {\n        logger.log(Level.SEVERE, msg, e);\n    }\n\n    @Override\n    public void error(Throwable e) {\n        logger.log(Level.SEVERE, e.getMessage(), e);\n    }\n\n    @Override\n    public void info(Throwable e) {\n        logger.log(Level.INFO, e.getMessage(), e);\n    }\n\n    @Override\n    public void warn(Throwable e) {\n        logger.log(Level.WARNING, e.getMessage(), e);\n    }\n\n    @Override\n    public boolean isTraceEnabled() {\n        return logger.isLoggable(Level.FINER);\n    }\n\n    @Override\n    public boolean isDebugEnabled() {\n        return logger.isLoggable(Level.FINE);\n    }\n\n    @Override\n    public boolean isInfoEnabled() {\n        return logger.isLoggable(Level.INFO);\n    }\n\n    @Override\n    public boolean isWarnEnabled() {\n        return logger.isLoggable(Level.WARNING);\n    }\n\n    @Override\n    public boolean isErrorEnabled() {\n        return logger.isLoggable(Level.SEVERE);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/jdk/JdkLoggerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.jdk;\n\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerAdapter;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.lang.reflect.Field;\nimport java.util.logging.FileHandler;\nimport java.util.logging.Handler;\nimport java.util.logging.LogManager;\n\npublic class JdkLoggerAdapter implements LoggerAdapter {\n\n    public static final String NAME = \"jdk\";\n    private static final String GLOBAL_LOGGER_NAME = \"global\";\n\n    private File file;\n\n    private boolean propertiesLoaded = false;\n\n    public JdkLoggerAdapter() {\n        try {\n            InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(\"logging.properties\");\n            if (in != null) {\n                LogManager.getLogManager().readConfiguration(in);\n                propertiesLoaded = true;\n            } else {\n                System.err.println(\"No such logging.properties in classpath for jdk logging config!\");\n            }\n        } catch (Exception t) {\n            System.err.println(\n                    \"Failed to load logging.properties in classpath for jdk logging config, cause: \" + t.getMessage());\n        }\n        try {\n            Handler[] handlers =\n                    java.util.logging.Logger.getLogger(GLOBAL_LOGGER_NAME).getHandlers();\n            for (Handler handler : handlers) {\n                if (handler instanceof FileHandler) {\n                    FileHandler fileHandler = (FileHandler) handler;\n                    Field field = fileHandler.getClass().getField(\"files\");\n                    File[] files = (File[]) field.get(fileHandler);\n                    if (files != null && files.length > 0) {\n                        file = files[0];\n                    }\n                }\n            }\n        } catch (Exception ignored) {\n            // ignore\n        }\n    }\n\n    private static java.util.logging.Level toJdkLevel(Level level) {\n        if (level == Level.ALL) {\n            return java.util.logging.Level.ALL;\n        }\n        if (level == Level.TRACE) {\n            return java.util.logging.Level.FINER;\n        }\n        if (level == Level.DEBUG) {\n            return java.util.logging.Level.FINE;\n        }\n        if (level == Level.INFO) {\n            return java.util.logging.Level.INFO;\n        }\n        if (level == Level.WARN) {\n            return java.util.logging.Level.WARNING;\n        }\n        if (level == Level.ERROR) {\n            return java.util.logging.Level.SEVERE;\n        }\n        // if (level == Level.OFF)\n        return java.util.logging.Level.OFF;\n    }\n\n    private static Level fromJdkLevel(java.util.logging.Level level) {\n        if (level == java.util.logging.Level.ALL) {\n            return Level.ALL;\n        }\n        if (level == java.util.logging.Level.FINER) {\n            return Level.TRACE;\n        }\n        if (level == java.util.logging.Level.FINE) {\n            return Level.DEBUG;\n        }\n        if (level == java.util.logging.Level.INFO) {\n            return Level.INFO;\n        }\n        if (level == java.util.logging.Level.WARNING) {\n            return Level.WARN;\n        }\n        if (level == java.util.logging.Level.SEVERE) {\n            return Level.ERROR;\n        }\n        // if (level == java.util.logging.Level.OFF)\n        return Level.OFF;\n    }\n\n    @Override\n    public Logger getLogger(Class<?> key) {\n        return new JdkLogger(java.util.logging.Logger.getLogger(key == null ? \"\" : key.getName()));\n    }\n\n    @Override\n    public Logger getLogger(String key) {\n        return new JdkLogger(java.util.logging.Logger.getLogger(key));\n    }\n\n    @Override\n    public Level getLevel() {\n        return fromJdkLevel(\n                java.util.logging.Logger.getLogger(GLOBAL_LOGGER_NAME).getLevel());\n    }\n\n    @Override\n    public void setLevel(Level level) {\n        java.util.logging.Logger.getLogger(GLOBAL_LOGGER_NAME).setLevel(toJdkLevel(level));\n    }\n\n    @Override\n    public File getFile() {\n        return file;\n    }\n\n    @Override\n    public void setFile(File file) {\n        // ignore\n    }\n\n    @Override\n    public boolean isConfigured() {\n        return propertiesLoaded;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/log4j/Log4jLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.log4j;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.support.FailsafeLogger;\n\nimport org.apache.log4j.Level;\nimport org.slf4j.helpers.FormattingTuple;\nimport org.slf4j.helpers.MessageFormatter;\n\npublic class Log4jLogger implements Logger {\n\n    private final String fqcn;\n\n    private final org.apache.log4j.Logger logger;\n\n    public Log4jLogger(org.apache.log4j.Logger logger) {\n        this.fqcn = FailsafeLogger.class.getName();\n        this.logger = logger;\n    }\n\n    public Log4jLogger(String fqcn, org.apache.log4j.Logger logger) {\n        this.fqcn = fqcn;\n        this.logger = logger;\n    }\n\n    @Override\n    public void trace(String msg) {\n        logger.log(fqcn, Level.TRACE, msg, null);\n    }\n\n    @Override\n    public void trace(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.log(fqcn, Level.TRACE, ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void trace(Throwable e) {\n        logger.log(fqcn, Level.TRACE, e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void trace(String msg, Throwable e) {\n        logger.log(fqcn, Level.TRACE, msg, e);\n    }\n\n    @Override\n    public void debug(String msg) {\n        logger.log(fqcn, Level.DEBUG, msg, null);\n    }\n\n    @Override\n    public void debug(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.log(fqcn, Level.DEBUG, ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void debug(Throwable e) {\n        logger.log(fqcn, Level.DEBUG, e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void debug(String msg, Throwable e) {\n        logger.log(fqcn, Level.DEBUG, msg, e);\n    }\n\n    @Override\n    public void info(String msg) {\n        logger.log(fqcn, Level.INFO, msg, null);\n    }\n\n    @Override\n    public void info(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.log(fqcn, Level.INFO, ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void info(Throwable e) {\n        logger.log(fqcn, Level.INFO, e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void info(String msg, Throwable e) {\n        logger.log(fqcn, Level.INFO, msg, e);\n    }\n\n    @Override\n    public void warn(String msg) {\n        logger.log(fqcn, Level.WARN, msg, null);\n    }\n\n    @Override\n    public void warn(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.log(fqcn, Level.WARN, ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void warn(Throwable e) {\n        logger.log(fqcn, Level.WARN, e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void warn(String msg, Throwable e) {\n        logger.log(fqcn, Level.WARN, msg, e);\n    }\n\n    @Override\n    public void error(String msg) {\n        logger.log(fqcn, Level.ERROR, msg, null);\n    }\n\n    @Override\n    public void error(String msg, Object... arguments) {\n        FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n        logger.log(fqcn, Level.ERROR, ft.getMessage(), ft.getThrowable());\n    }\n\n    @Override\n    public void error(Throwable e) {\n        logger.log(fqcn, Level.ERROR, e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void error(String msg, Throwable e) {\n        logger.log(fqcn, Level.ERROR, msg, e);\n    }\n\n    @Override\n    public boolean isTraceEnabled() {\n        return logger.isTraceEnabled();\n    }\n\n    @Override\n    public boolean isDebugEnabled() {\n        return logger.isDebugEnabled();\n    }\n\n    @Override\n    public boolean isInfoEnabled() {\n        return logger.isInfoEnabled();\n    }\n\n    @Override\n    public boolean isWarnEnabled() {\n        return logger.isEnabledFor(Level.WARN);\n    }\n\n    @Override\n    public boolean isErrorEnabled() {\n        return logger.isEnabledFor(Level.ERROR);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/log4j/Log4jLoggerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.log4j;\n\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerAdapter;\n\nimport java.io.File;\nimport java.util.Enumeration;\n\nimport org.apache.log4j.Appender;\nimport org.apache.log4j.FileAppender;\nimport org.apache.log4j.LogManager;\n\npublic class Log4jLoggerAdapter implements LoggerAdapter {\n\n    public static final String NAME = \"log4j\";\n    private File file;\n\n    @SuppressWarnings(\"unchecked\")\n    public Log4jLoggerAdapter() {\n        try {\n            org.apache.log4j.Logger logger = LogManager.getRootLogger();\n            if (logger != null) {\n                Enumeration<Appender> appenders = logger.getAllAppenders();\n                if (appenders != null) {\n                    while (appenders.hasMoreElements()) {\n                        Appender appender = appenders.nextElement();\n                        if (appender instanceof FileAppender) {\n                            FileAppender fileAppender = (FileAppender) appender;\n                            String filename = fileAppender.getFile();\n                            file = new File(filename);\n                            break;\n                        }\n                    }\n                }\n            }\n        } catch (Exception t) {\n            // ignore\n        }\n    }\n\n    private static org.apache.log4j.Level toLog4jLevel(Level level) {\n        if (level == Level.ALL) {\n            return org.apache.log4j.Level.ALL;\n        }\n        if (level == Level.TRACE) {\n            return org.apache.log4j.Level.TRACE;\n        }\n        if (level == Level.DEBUG) {\n            return org.apache.log4j.Level.DEBUG;\n        }\n        if (level == Level.INFO) {\n            return org.apache.log4j.Level.INFO;\n        }\n        if (level == Level.WARN) {\n            return org.apache.log4j.Level.WARN;\n        }\n        if (level == Level.ERROR) {\n            return org.apache.log4j.Level.ERROR;\n        }\n        // if (level == Level.OFF)\n        return org.apache.log4j.Level.OFF;\n    }\n\n    private static Level fromLog4jLevel(org.apache.log4j.Level level) {\n        if (level == org.apache.log4j.Level.ALL) {\n            return Level.ALL;\n        }\n        if (level == org.apache.log4j.Level.TRACE) {\n            return Level.TRACE;\n        }\n        if (level == org.apache.log4j.Level.DEBUG) {\n            return Level.DEBUG;\n        }\n        if (level == org.apache.log4j.Level.INFO) {\n            return Level.INFO;\n        }\n        if (level == org.apache.log4j.Level.WARN) {\n            return Level.WARN;\n        }\n        if (level == org.apache.log4j.Level.ERROR) {\n            return Level.ERROR;\n        }\n        // if (level == org.apache.log4j.Level.OFF)\n        return Level.OFF;\n    }\n\n    @Override\n    public Logger getLogger(Class<?> key) {\n        return new Log4jLogger(LogManager.getLogger(key));\n    }\n\n    @Override\n    public Logger getLogger(String key) {\n        return new Log4jLogger(LogManager.getLogger(key));\n    }\n\n    @Override\n    public Logger getLogger(String fqcn, Class<?> key) {\n        return new Log4jLogger(fqcn, LogManager.getLogger(key));\n    }\n\n    @Override\n    public Logger getLogger(String fqcn, String key) {\n        return new Log4jLogger(fqcn, LogManager.getLogger(key));\n    }\n\n    @Override\n    public Level getLevel() {\n        return fromLog4jLevel(LogManager.getRootLogger().getLevel());\n    }\n\n    @Override\n    public void setLevel(Level level) {\n        LogManager.getRootLogger().setLevel(toLog4jLevel(level));\n    }\n\n    @Override\n    public File getFile() {\n        return file;\n    }\n\n    @Override\n    public void setFile(File file) {\n        // ignore\n    }\n\n    @Override\n    public boolean isConfigured() {\n        boolean hasAppender = false;\n        try {\n            org.apache.log4j.Logger logger = LogManager.getRootLogger();\n            if (logger != null) {\n                Enumeration<Appender> appenders = logger.getAllAppenders();\n                if (appenders != null) {\n                    while (appenders.hasMoreElements()) {\n                        hasAppender = true;\n                        Appender appender = appenders.nextElement();\n                        if (appender instanceof FileAppender) {\n                            FileAppender fileAppender = (FileAppender) appender;\n                            String filename = fileAppender.getFile();\n                            file = new File(filename);\n                            break;\n                        }\n                    }\n                }\n            }\n        } catch (Exception t) {\n            // ignore\n        }\n        return hasAppender;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/log4j2/Log4j2Logger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.log4j2;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.support.FailsafeLogger;\n\nimport org.apache.logging.log4j.Level;\n\npublic class Log4j2Logger implements Logger {\n\n    private final String fqcn;\n\n    private final org.apache.logging.log4j.spi.ExtendedLogger logger;\n\n    public Log4j2Logger(org.apache.logging.log4j.spi.ExtendedLogger logger) {\n        this.fqcn = FailsafeLogger.class.getName();\n        this.logger = logger;\n    }\n\n    public Log4j2Logger(String fqcn, org.apache.logging.log4j.spi.ExtendedLogger logger) {\n        this.fqcn = fqcn;\n        this.logger = logger;\n    }\n\n    @Override\n    public void trace(String msg) {\n        logger.logIfEnabled(fqcn, Level.TRACE, null, msg);\n    }\n\n    @Override\n    public void trace(String msg, Object... arguments) {\n        logger.logIfEnabled(fqcn, Level.TRACE, null, msg, arguments);\n    }\n\n    @Override\n    public void trace(Throwable e) {\n        logger.logIfEnabled(fqcn, Level.TRACE, null, e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void trace(String msg, Throwable e) {\n        logger.logIfEnabled(fqcn, Level.TRACE, null, msg, e);\n    }\n\n    @Override\n    public void debug(String msg) {\n        logger.logIfEnabled(fqcn, Level.DEBUG, null, msg);\n    }\n\n    @Override\n    public void debug(String msg, Object... arguments) {\n        logger.logIfEnabled(fqcn, Level.DEBUG, null, msg, arguments);\n    }\n\n    @Override\n    public void debug(Throwable e) {\n        logger.logIfEnabled(fqcn, Level.DEBUG, null, e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void debug(String msg, Throwable e) {\n        logger.logIfEnabled(fqcn, Level.DEBUG, null, msg, e);\n    }\n\n    @Override\n    public void info(String msg) {\n        logger.logIfEnabled(fqcn, Level.INFO, null, msg);\n    }\n\n    @Override\n    public void info(String msg, Object... arguments) {\n        logger.logIfEnabled(fqcn, Level.INFO, null, msg, arguments);\n    }\n\n    @Override\n    public void info(Throwable e) {\n        logger.logIfEnabled(fqcn, Level.INFO, null, e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void info(String msg, Throwable e) {\n        logger.logIfEnabled(fqcn, Level.INFO, null, msg, e);\n    }\n\n    @Override\n    public void warn(String msg) {\n        logger.logIfEnabled(fqcn, Level.WARN, null, msg);\n    }\n\n    @Override\n    public void warn(String msg, Object... arguments) {\n        logger.logIfEnabled(fqcn, Level.WARN, null, msg, arguments);\n    }\n\n    @Override\n    public void warn(Throwable e) {\n        logger.logIfEnabled(fqcn, Level.WARN, null, e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void warn(String msg, Throwable e) {\n        logger.logIfEnabled(fqcn, Level.WARN, null, msg, e);\n    }\n\n    @Override\n    public void error(String msg) {\n        logger.logIfEnabled(fqcn, Level.ERROR, null, msg);\n    }\n\n    @Override\n    public void error(String msg, Object... arguments) {\n        logger.logIfEnabled(fqcn, Level.ERROR, null, msg, arguments);\n    }\n\n    @Override\n    public void error(Throwable e) {\n        logger.logIfEnabled(fqcn, Level.ERROR, null, e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void error(String msg, Throwable e) {\n        logger.logIfEnabled(fqcn, Level.ERROR, null, msg, e);\n    }\n\n    @Override\n    public boolean isTraceEnabled() {\n        return logger.isTraceEnabled();\n    }\n\n    @Override\n    public boolean isDebugEnabled() {\n        return logger.isDebugEnabled();\n    }\n\n    @Override\n    public boolean isInfoEnabled() {\n        return logger.isInfoEnabled();\n    }\n\n    @Override\n    public boolean isWarnEnabled() {\n        return logger.isWarnEnabled();\n    }\n\n    @Override\n    public boolean isErrorEnabled() {\n        return logger.isErrorEnabled();\n    }\n\n    // test purpose only\n    public org.apache.logging.log4j.Logger getLogger() {\n        return logger;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/log4j2/Log4j2LoggerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.log4j2;\n\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerAdapter;\n\nimport java.io.File;\n\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.core.config.Configurator;\nimport org.apache.logging.log4j.spi.ExtendedLogger;\n\npublic class Log4j2LoggerAdapter implements LoggerAdapter {\n    public static final String NAME = \"log4j2\";\n\n    private Level level;\n\n    public Log4j2LoggerAdapter() {\n        try {\n            org.apache.logging.log4j.Logger logger = LogManager.getRootLogger();\n            this.level = fromLog4j2Level(logger.getLevel());\n        } catch (Exception t) {\n            // ignore\n        }\n    }\n\n    private static org.apache.logging.log4j.Level toLog4j2Level(Level level) {\n        if (level == Level.ALL) {\n            return org.apache.logging.log4j.Level.ALL;\n        }\n        if (level == Level.TRACE) {\n            return org.apache.logging.log4j.Level.TRACE;\n        }\n        if (level == Level.DEBUG) {\n            return org.apache.logging.log4j.Level.DEBUG;\n        }\n        if (level == Level.INFO) {\n            return org.apache.logging.log4j.Level.INFO;\n        }\n        if (level == Level.WARN) {\n            return org.apache.logging.log4j.Level.WARN;\n        }\n        if (level == Level.ERROR) {\n            return org.apache.logging.log4j.Level.ERROR;\n        }\n        return org.apache.logging.log4j.Level.OFF;\n    }\n\n    private static Level fromLog4j2Level(org.apache.logging.log4j.Level level) {\n        if (level == org.apache.logging.log4j.Level.ALL) {\n            return Level.ALL;\n        }\n        if (level == org.apache.logging.log4j.Level.TRACE) {\n            return Level.TRACE;\n        }\n        if (level == org.apache.logging.log4j.Level.DEBUG) {\n            return Level.DEBUG;\n        }\n        if (level == org.apache.logging.log4j.Level.INFO) {\n            return Level.INFO;\n        }\n        if (level == org.apache.logging.log4j.Level.WARN) {\n            return Level.WARN;\n        }\n        if (level == org.apache.logging.log4j.Level.ERROR) {\n            return Level.ERROR;\n        }\n        return Level.OFF;\n    }\n\n    @Override\n    public Logger getLogger(Class<?> key) {\n        return new Log4j2Logger((ExtendedLogger) LogManager.getLogger(key));\n    }\n\n    @Override\n    public Logger getLogger(String key) {\n        return new Log4j2Logger((ExtendedLogger) LogManager.getLogger(key));\n    }\n\n    @Override\n    public Logger getLogger(String fqcn, Class<?> key) {\n        return new Log4j2Logger(fqcn, (ExtendedLogger) LogManager.getLogger(key));\n    }\n\n    @Override\n    public Logger getLogger(String fqcn, String key) {\n        return new Log4j2Logger(fqcn, (ExtendedLogger) LogManager.getLogger(key));\n    }\n\n    @Override\n    public Level getLevel() {\n        return level;\n    }\n\n    @Override\n    public void setLevel(Level level) {\n        this.level = level;\n        Configurator.setLevel(LogManager.getRootLogger(), toLog4j2Level(level));\n    }\n\n    @Override\n    public File getFile() {\n        return null;\n    }\n\n    @Override\n    public void setFile(File file) {\n        // ignore\n    }\n\n    @Override\n    public boolean isConfigured() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/slf4j/Slf4jLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.slf4j;\n\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.support.FailsafeLogger;\n\nimport org.slf4j.helpers.FormattingTuple;\nimport org.slf4j.helpers.MessageFormatter;\nimport org.slf4j.spi.LocationAwareLogger;\n\npublic class Slf4jLogger implements Logger {\n\n    private final String fqcn;\n\n    private final org.slf4j.Logger logger;\n\n    private final LocationAwareLogger locationAwareLogger;\n\n    public Slf4jLogger(org.slf4j.Logger logger) {\n        if (logger instanceof LocationAwareLogger) {\n            locationAwareLogger = (LocationAwareLogger) logger;\n        } else {\n            locationAwareLogger = null;\n        }\n        this.fqcn = FailsafeLogger.class.getName();\n        this.logger = logger;\n    }\n\n    public Slf4jLogger(String fqcn, org.slf4j.Logger logger) {\n        if (logger instanceof LocationAwareLogger) {\n            locationAwareLogger = (LocationAwareLogger) logger;\n        } else {\n            locationAwareLogger = null;\n        }\n        this.fqcn = fqcn;\n        this.logger = logger;\n    }\n\n    @Override\n    public void trace(String msg) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.TRACE_INT, msg, null, null);\n            return;\n        }\n        logger.trace(msg);\n    }\n\n    @Override\n    public void trace(String msg, Object... arguments) {\n        if (locationAwareLogger != null && locationAwareLogger.isTraceEnabled()) {\n            FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n            locationAwareLogger.log(\n                    null, fqcn, LocationAwareLogger.TRACE_INT, msg, ft.getArgArray(), ft.getThrowable());\n            return;\n        }\n        logger.trace(msg, arguments);\n    }\n\n    @Override\n    public void trace(Throwable e) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(\n                    null, fqcn, LocationAwareLogger.TRACE_INT, e == null ? null : e.getMessage(), null, e);\n            return;\n        }\n        logger.trace(e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void trace(String msg, Throwable e) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.TRACE_INT, msg, null, e);\n            return;\n        }\n        logger.trace(msg, e);\n    }\n\n    @Override\n    public void debug(String msg) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, null);\n            return;\n        }\n        logger.debug(msg);\n    }\n\n    @Override\n    public void debug(String msg, Object... arguments) {\n        if (locationAwareLogger != null && locationAwareLogger.isDebugEnabled()) {\n            FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n            locationAwareLogger.log(\n                    null, fqcn, LocationAwareLogger.DEBUG_INT, msg, ft.getArgArray(), ft.getThrowable());\n            return;\n        }\n        logger.debug(msg, arguments);\n    }\n\n    @Override\n    public void debug(Throwable e) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(\n                    null, fqcn, LocationAwareLogger.DEBUG_INT, e == null ? null : e.getMessage(), null, e);\n            return;\n        }\n        logger.debug(e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void debug(String msg, Throwable e) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, e);\n            return;\n        }\n        logger.debug(msg, e);\n    }\n\n    @Override\n    public void info(String msg) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.INFO_INT, msg, null, null);\n            return;\n        }\n        logger.info(msg);\n    }\n\n    @Override\n    public void info(String msg, Object... arguments) {\n        if (locationAwareLogger != null && locationAwareLogger.isInfoEnabled()) {\n            FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.INFO_INT, msg, ft.getArgArray(), ft.getThrowable());\n            return;\n        }\n        logger.info(msg, arguments);\n    }\n\n    @Override\n    public void info(Throwable e) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(\n                    null, fqcn, LocationAwareLogger.INFO_INT, e == null ? null : e.getMessage(), null, e);\n            return;\n        }\n        logger.info(e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void info(String msg, Throwable e) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.INFO_INT, msg, null, e);\n            return;\n        }\n        logger.info(msg, e);\n    }\n\n    @Override\n    public void warn(String msg) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.WARN_INT, msg, null, null);\n            return;\n        }\n        logger.warn(msg);\n    }\n\n    @Override\n    public void warn(String msg, Object... arguments) {\n        if (locationAwareLogger != null && locationAwareLogger.isWarnEnabled()) {\n            FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.WARN_INT, msg, ft.getArgArray(), ft.getThrowable());\n            return;\n        }\n        logger.warn(msg, arguments);\n    }\n\n    @Override\n    public void warn(Throwable e) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(\n                    null, fqcn, LocationAwareLogger.WARN_INT, e == null ? null : e.getMessage(), null, e);\n            return;\n        }\n        logger.warn(e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void warn(String msg, Throwable e) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.WARN_INT, msg, null, e);\n            return;\n        }\n        logger.warn(msg, e);\n    }\n\n    @Override\n    public void error(String msg) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.ERROR_INT, msg, null, null);\n            return;\n        }\n        logger.error(msg);\n    }\n\n    @Override\n    public void error(String msg, Object... arguments) {\n        if (locationAwareLogger != null && locationAwareLogger.isErrorEnabled()) {\n            FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);\n            locationAwareLogger.log(\n                    null, fqcn, LocationAwareLogger.ERROR_INT, msg, ft.getArgArray(), ft.getThrowable());\n            return;\n        }\n        logger.error(msg, arguments);\n    }\n\n    @Override\n    public void error(Throwable e) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(\n                    null, fqcn, LocationAwareLogger.ERROR_INT, e == null ? null : e.getMessage(), null, e);\n            return;\n        }\n        logger.error(e == null ? null : e.getMessage(), e);\n    }\n\n    @Override\n    public void error(String msg, Throwable e) {\n        if (locationAwareLogger != null) {\n            locationAwareLogger.log(null, fqcn, LocationAwareLogger.ERROR_INT, msg, null, e);\n            return;\n        }\n        logger.error(msg, e);\n    }\n\n    @Override\n    public boolean isTraceEnabled() {\n        return logger.isTraceEnabled();\n    }\n\n    @Override\n    public boolean isDebugEnabled() {\n        return logger.isDebugEnabled();\n    }\n\n    @Override\n    public boolean isInfoEnabled() {\n        return logger.isInfoEnabled();\n    }\n\n    @Override\n    public boolean isWarnEnabled() {\n        return logger.isWarnEnabled();\n    }\n\n    @Override\n    public boolean isErrorEnabled() {\n        return logger.isErrorEnabled();\n    }\n\n    public static Level getLevel(org.slf4j.Logger logger) {\n        if (logger.isTraceEnabled()) {\n            return Level.TRACE;\n        }\n        if (logger.isDebugEnabled()) {\n            return Level.DEBUG;\n        }\n        if (logger.isInfoEnabled()) {\n            return Level.INFO;\n        }\n        if (logger.isWarnEnabled()) {\n            return Level.WARN;\n        }\n        if (logger.isErrorEnabled()) {\n            return Level.ERROR;\n        }\n        return Level.OFF;\n    }\n\n    public Level getLevel() {\n        return getLevel(logger);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/slf4j/Slf4jLoggerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.slf4j;\n\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerAdapter;\nimport org.apache.dubbo.common.utils.ClassUtils;\n\nimport java.io.File;\n\nimport org.slf4j.LoggerFactory;\n\npublic class Slf4jLoggerAdapter implements LoggerAdapter {\n    public static final String NAME = \"slf4j\";\n\n    private Level level;\n    private File file;\n\n    private static final org.slf4j.Logger ROOT_LOGGER = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);\n\n    public Slf4jLoggerAdapter() {\n        this.level = Slf4jLogger.getLevel(ROOT_LOGGER);\n    }\n\n    @Override\n    public Logger getLogger(String key) {\n        return new Slf4jLogger(org.slf4j.LoggerFactory.getLogger(key));\n    }\n\n    @Override\n    public Logger getLogger(Class<?> key) {\n        return new Slf4jLogger(org.slf4j.LoggerFactory.getLogger(key));\n    }\n\n    @Override\n    public Logger getLogger(String fqcn, Class<?> key) {\n        return new Slf4jLogger(fqcn, org.slf4j.LoggerFactory.getLogger(key));\n    }\n\n    @Override\n    public Logger getLogger(String fqcn, String key) {\n        return new Slf4jLogger(fqcn, org.slf4j.LoggerFactory.getLogger(key));\n    }\n\n    @Override\n    public Level getLevel() {\n        return level;\n    }\n\n    @Override\n    public void setLevel(Level level) {\n        System.err.printf(\n                \"The level of slf4j logger current can not be set, using the default level: %s \\n\",\n                Slf4jLogger.getLevel(ROOT_LOGGER));\n        this.level = level;\n    }\n\n    @Override\n    public File getFile() {\n        return file;\n    }\n\n    @Override\n    public void setFile(File file) {\n        this.file = file;\n    }\n\n    @Override\n    public boolean isConfigured() {\n        try {\n            ClassUtils.forName(\"org.slf4j.impl.StaticLoggerBinder\");\n            return true;\n        } catch (ClassNotFoundException ignore) {\n            // ignore\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.support;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.logger.ListenableLogger;\nimport org.apache.dubbo.common.logger.LogListener;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.utils.NetUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.regex.Pattern;\n\n/**\n * A fail-safe (ignoring exception thrown by logger) wrapper of error type aware logger.\n */\npublic class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements ListenableLogger {\n\n    /**\n     * Template address for formatting.\n     */\n    private static final String INSTRUCTIONS_URL = \"https://dubbo.apache.org/faq/%d/%d\";\n\n    private static final Pattern ERROR_CODE_PATTERN = Pattern.compile(\"\\\\d+-\\\\d+\");\n\n    /**\n     * Listeners that listened to all Loggers.\n     */\n    private static final List<LogListener> GLOBAL_LISTENERS = Collections.synchronizedList(new ArrayList<>());\n\n    /**\n     *  Listeners that listened to this listener.\n     */\n    private final AtomicReference<List<LogListener>> listeners = new AtomicReference<>();\n\n    public FailsafeErrorTypeAwareLogger(Logger logger) {\n        super(logger);\n    }\n\n    private String appendContextMessageWithInstructions(\n            String code, String cause, String extendedInformation, String msg) {\n        return \" [DUBBO] \" + msg + \", dubbo version: \" + Version.getVersion() + \", current host: \"\n                + NetUtils.getLocalHost() + \", error code: \" + code + \". This may be caused by \"\n                + cause + \", \" + \"go to \"\n                + getErrorUrl(code) + \" to find instructions. \" + extendedInformation;\n    }\n\n    private String getErrorUrl(String code) {\n\n        String trimmedString = code.trim();\n\n        if (!ERROR_CODE_PATTERN.matcher(trimmedString).matches()) {\n            error(\"Invalid error code: \" + code + \", the format of error code is: X-X (where X is a number).\");\n            return \"\";\n        }\n\n        String[] segments = trimmedString.split(\"[-]\");\n\n        int[] errorCodeSegments = new int[2];\n\n        try {\n            errorCodeSegments[0] = Integer.parseInt(segments[0]);\n            errorCodeSegments[1] = Integer.parseInt(segments[1]);\n        } catch (NumberFormatException numberFormatException) {\n            error(\n                    \"Invalid error code: \" + code + \", the format of error code is: X-X (where X is a number).\",\n                    numberFormatException);\n\n            return \"\";\n        }\n\n        return String.format(INSTRUCTIONS_URL, errorCodeSegments[0], errorCodeSegments[1]);\n    }\n\n    @Override\n    public void warn(String code, String cause, String extendedInformation, String msg) {\n        if (getDisabled()) {\n            return;\n        }\n\n        try {\n            onEvent(code, msg);\n            if (!getLogger().isWarnEnabled()) {\n                return;\n            }\n            getLogger().warn(appendContextMessageWithInstructions(code, cause, extendedInformation, msg));\n        } catch (Throwable t) {\n            // ignored.\n        }\n    }\n\n    @Override\n    public void warn(String code, String cause, String extendedInformation, String msg, Throwable e) {\n        if (getDisabled()) {\n            return;\n        }\n\n        try {\n            onEvent(code, msg);\n            if (!getLogger().isWarnEnabled()) {\n                return;\n            }\n            getLogger().warn(appendContextMessageWithInstructions(code, cause, extendedInformation, msg), e);\n        } catch (Throwable t) {\n            // ignored.\n        }\n    }\n\n    @Override\n    public void error(String code, String cause, String extendedInformation, String msg) {\n        if (getDisabled()) {\n            return;\n        }\n\n        try {\n            onEvent(code, msg);\n            if (!getLogger().isErrorEnabled()) {\n                return;\n            }\n            getLogger().error(appendContextMessageWithInstructions(code, cause, extendedInformation, msg));\n        } catch (Throwable t) {\n            // ignored.\n        }\n    }\n\n    @Override\n    public void error(String code, String cause, String extendedInformation, String msg, Throwable e) {\n        if (getDisabled()) {\n            return;\n        }\n\n        try {\n            onEvent(code, msg);\n            if (!getLogger().isErrorEnabled()) {\n                return;\n            }\n            getLogger().error(appendContextMessageWithInstructions(code, cause, extendedInformation, msg), e);\n        } catch (Throwable t) {\n            // ignored.\n        }\n    }\n\n    public static void registerGlobalListen(LogListener listener) {\n        GLOBAL_LISTENERS.add(listener);\n    }\n\n    @Override\n    public void registerListen(LogListener listener) {\n        listeners.getAndUpdate(logListeners -> {\n            if (logListeners == null) {\n                logListeners = Collections.synchronizedList(new ArrayList<>());\n            }\n            logListeners.add(listener);\n            return logListeners;\n        });\n    }\n\n    private void onEvent(String code, String msg) {\n        Optional.ofNullable(listeners.get())\n                .ifPresent(logListeners -> logListeners.forEach(logListener -> {\n                    try {\n                        logListener.onMessage(code, msg);\n                    } catch (Exception e) {\n                        // ignored.\n                    }\n                }));\n\n        GLOBAL_LISTENERS.forEach(logListener -> {\n            try {\n                logListener.onMessage(code, msg);\n            } catch (Exception e) {\n                // ignored.\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.support;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.utils.NetUtils;\n\npublic class FailsafeLogger implements Logger {\n\n    private Logger logger;\n\n    private static boolean disabled = false;\n\n    public FailsafeLogger(Logger logger) {\n        this.logger = logger;\n    }\n\n    public static void setDisabled(boolean disabled) {\n        FailsafeLogger.disabled = disabled;\n    }\n\n    static boolean getDisabled() {\n        return disabled;\n    }\n\n    public Logger getLogger() {\n        return logger;\n    }\n\n    public void setLogger(Logger logger) {\n        this.logger = logger;\n    }\n\n    private String appendContextMessage(String msg) {\n        return \" [DUBBO] \" + msg + \", dubbo version: \" + Version.getVersion() + \", current host: \"\n                + NetUtils.getLocalHost();\n    }\n\n    @Override\n    public void trace(String msg, Throwable e) {\n        if (disabled || !logger.isTraceEnabled()) {\n            return;\n        }\n        try {\n            logger.trace(appendContextMessage(msg), e);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void trace(Throwable e) {\n        if (disabled || !logger.isTraceEnabled()) {\n            return;\n        }\n        try {\n            logger.trace(e);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void trace(String msg) {\n        if (disabled || !logger.isTraceEnabled()) {\n            return;\n        }\n        try {\n            logger.trace(appendContextMessage(msg));\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void trace(String msg, Object... arguments) {\n        if (disabled || !logger.isTraceEnabled()) {\n            return;\n        }\n        try {\n            logger.trace(appendContextMessage(msg), arguments);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void debug(String msg, Throwable e) {\n        if (disabled || !logger.isDebugEnabled()) {\n            return;\n        }\n        try {\n            logger.debug(appendContextMessage(msg), e);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void debug(Throwable e) {\n        if (disabled || !logger.isDebugEnabled()) {\n            return;\n        }\n        try {\n            logger.debug(e);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void debug(String msg) {\n        if (disabled || !logger.isDebugEnabled()) {\n            return;\n        }\n        try {\n            logger.debug(appendContextMessage(msg));\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void debug(String msg, Object... arguments) {\n        if (disabled || !logger.isDebugEnabled()) {\n            return;\n        }\n        try {\n            logger.debug(appendContextMessage(msg), arguments);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void info(String msg, Throwable e) {\n        if (disabled || !logger.isInfoEnabled()) {\n            return;\n        }\n        try {\n            logger.info(appendContextMessage(msg), e);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void info(String msg) {\n        if (disabled || !logger.isInfoEnabled()) {\n            return;\n        }\n        try {\n            logger.info(appendContextMessage(msg));\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void info(String msg, Object... arguments) {\n        if (disabled || !logger.isInfoEnabled()) {\n            return;\n        }\n        try {\n            logger.info(appendContextMessage(msg), arguments);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void warn(String msg, Throwable e) {\n        if (disabled || !logger.isWarnEnabled()) {\n            return;\n        }\n        try {\n            logger.warn(appendContextMessage(msg), e);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void warn(String msg) {\n        if (disabled || !logger.isWarnEnabled()) {\n            return;\n        }\n        try {\n            logger.warn(appendContextMessage(msg));\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void warn(String msg, Object... arguments) {\n        if (disabled || !logger.isWarnEnabled()) {\n            return;\n        }\n        try {\n            logger.warn(appendContextMessage(msg), arguments);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void error(String msg, Throwable e) {\n        if (disabled || !logger.isErrorEnabled()) {\n            return;\n        }\n        try {\n            logger.error(appendContextMessage(msg), e);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void error(String msg) {\n        if (disabled || !logger.isErrorEnabled()) {\n            return;\n        }\n        try {\n            logger.error(appendContextMessage(msg));\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void error(String msg, Object... arguments) {\n        if (disabled || !logger.isErrorEnabled()) {\n            return;\n        }\n        try {\n            logger.error(appendContextMessage(msg), arguments);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void error(Throwable e) {\n        if (disabled || !logger.isErrorEnabled()) {\n            return;\n        }\n        try {\n            logger.error(e);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void info(Throwable e) {\n        if (disabled || !logger.isInfoEnabled()) {\n            return;\n        }\n        try {\n            logger.info(e);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public void warn(Throwable e) {\n        if (disabled || !logger.isWarnEnabled()) {\n            return;\n        }\n        try {\n            logger.warn(e);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    @Override\n    public boolean isTraceEnabled() {\n        if (disabled) {\n            return false;\n        }\n        try {\n            return logger.isTraceEnabled();\n        } catch (Throwable ignored) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isDebugEnabled() {\n        if (disabled) {\n            return false;\n        }\n        try {\n            return logger.isDebugEnabled();\n        } catch (Throwable ignored) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isInfoEnabled() {\n        if (disabled) {\n            return false;\n        }\n        try {\n            return logger.isInfoEnabled();\n        } catch (Throwable ignored) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isWarnEnabled() {\n        if (disabled) {\n            return false;\n        }\n        try {\n            return logger.isWarnEnabled();\n        } catch (Throwable ignored) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isErrorEnabled() {\n        if (disabled) {\n            return false;\n        }\n        try {\n            return logger.isErrorEnabled();\n        } catch (Throwable ignored) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/profiler/Profiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.profiler;\n\nimport org.apache.dubbo.common.threadlocal.InternalThreadLocal;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class Profiler {\n    public static final String PROFILER_KEY = \"DUBBO_INVOKE_PROFILER\";\n    public static final int MAX_ENTRY_SIZE = 1000;\n\n    private static final InternalThreadLocal<ProfilerEntry> bizProfiler = new InternalThreadLocal<>();\n\n    public static ProfilerEntry start(String message) {\n        return new ProfilerEntry(message);\n    }\n\n    public static ProfilerEntry enter(ProfilerEntry entry, String message) {\n        ProfilerEntry subEntry = new ProfilerEntry(message, entry, entry.getFirst());\n        if (subEntry.getRequestCount().incrementAndGet() < MAX_ENTRY_SIZE) {\n            entry.getSub().add(subEntry);\n        } // ignore if sub entry size is exceed\n        return subEntry;\n    }\n\n    public static ProfilerEntry release(ProfilerEntry entry) {\n        entry.setEndTime(System.nanoTime());\n        ProfilerEntry parent = entry.getParent();\n        if (parent != null) {\n            return parent;\n        } else {\n            return entry;\n        }\n    }\n\n    public static ProfilerEntry setToBizProfiler(ProfilerEntry entry) {\n        try {\n            return bizProfiler.get();\n        } finally {\n            bizProfiler.set(entry);\n        }\n    }\n\n    public static ProfilerEntry getBizProfiler() {\n        return bizProfiler.get();\n    }\n\n    public static void removeBizProfiler() {\n        bizProfiler.remove();\n    }\n\n    public static String buildDetail(ProfilerEntry entry) {\n        long totalUsageTime = entry.getEndTime() - entry.getStartTime();\n        return \"Start time: \" + entry.getStartTime() + \"\\n\"\n                + String.join(\"\\n\", buildDetail(entry, entry.getStartTime(), totalUsageTime, 0));\n    }\n\n    public static List<String> buildDetail(ProfilerEntry entry, long startTime, long totalUsageTime, int depth) {\n        StringBuilder stringBuilder = new StringBuilder();\n        long usage = entry.getEndTime() - entry.getStartTime();\n        int percent = (int) (((usage) * 100) / totalUsageTime);\n\n        long offset = entry.getStartTime() - startTime;\n        List<String> lines = new LinkedList<>();\n        stringBuilder\n                .append(\"+-[ Offset: \")\n                .append(offset / 1000_000)\n                .append('.')\n                .append(String.format(\"%06d\", offset % 1000_000))\n                .append(\"ms; Usage: \")\n                .append(usage / 1000_000)\n                .append('.')\n                .append(String.format(\"%06d\", usage % 1000_000))\n                .append(\"ms, \")\n                .append(percent)\n                .append(\"% ] \")\n                .append(entry.getMessage());\n        lines.add(stringBuilder.toString());\n        List<ProfilerEntry> entrySub = entry.getSub();\n        for (int i = 0, entrySubSize = entrySub.size(); i < entrySubSize; i++) {\n            ProfilerEntry sub = entrySub.get(i);\n            List<String> subLines = buildDetail(sub, startTime, totalUsageTime, depth + 1);\n            if (i < entrySubSize - 1) {\n                lines.add(\"  \" + subLines.get(0));\n                for (int j = 1, subLinesSize = subLines.size(); j < subLinesSize; j++) {\n                    String subLine = subLines.get(j);\n                    lines.add(\"  |\" + subLine);\n                }\n            } else {\n                lines.add(\"  \" + subLines.get(0));\n                for (int j = 1, subLinesSize = subLines.size(); j < subLinesSize; j++) {\n                    String subLine = subLines.get(j);\n                    lines.add(\"   \" + subLine);\n                }\n            }\n        }\n        return lines;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/profiler/ProfilerEntry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.profiler;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\n\npublic class ProfilerEntry {\n    private final List<ProfilerEntry> sub = new ArrayList<>(4);\n    private final String message;\n    private final ProfilerEntry parent;\n    private final ProfilerEntry first;\n    private final long startTime;\n    private final AtomicInteger requestCount;\n    private long endTime;\n\n    public ProfilerEntry(String message) {\n        this.message = message;\n        this.parent = null;\n        this.first = this;\n        this.startTime = System.nanoTime();\n        this.requestCount = new AtomicInteger(1);\n    }\n\n    public ProfilerEntry(String message, ProfilerEntry parentEntry, ProfilerEntry firstEntry) {\n        this.message = message;\n        this.parent = parentEntry;\n        this.first = firstEntry;\n        this.startTime = System.nanoTime();\n        this.requestCount = parentEntry.getRequestCount();\n    }\n\n    public List<ProfilerEntry> getSub() {\n        return sub;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public ProfilerEntry getParent() {\n        return parent;\n    }\n\n    public ProfilerEntry getFirst() {\n        return first;\n    }\n\n    public long getStartTime() {\n        return startTime;\n    }\n\n    public void setEndTime(long endTime) {\n        this.endTime = endTime;\n    }\n\n    public long getEndTime() {\n        return endTime;\n    }\n\n    public AtomicInteger getRequestCount() {\n        return requestCount;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/profiler/ProfilerSwitch.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.profiler;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * TODO\n */\npublic class ProfilerSwitch {\n    private static final AtomicBoolean enableDetailProfiler = new AtomicBoolean(false);\n\n    private static final AtomicBoolean enableSimpleProfiler = new AtomicBoolean(true);\n\n    private static final AtomicReference<Double> warnPercent = new AtomicReference<>(0.75);\n\n    public static void enableSimpleProfiler() {\n        enableSimpleProfiler.set(true);\n    }\n\n    public static void disableSimpleProfiler() {\n        enableSimpleProfiler.set(false);\n    }\n\n    public static void enableDetailProfiler() {\n        enableDetailProfiler.set(true);\n    }\n\n    public static void disableDetailProfiler() {\n        enableDetailProfiler.set(false);\n    }\n\n    public static boolean isEnableDetailProfiler() {\n        return enableDetailProfiler.get() && enableSimpleProfiler.get();\n    }\n\n    public static boolean isEnableSimpleProfiler() {\n        return enableSimpleProfiler.get();\n    }\n\n    public static double getWarnPercent() {\n        return warnPercent.get();\n    }\n\n    public static void setWarnPercent(double percent) {\n        warnPercent.set(percent);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/reference/ReferenceCountedResource.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.reference;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.util.concurrent.atomic.AtomicLongFieldUpdater;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_ERROR_CLOSE_CLIENT;\n\n/**\n * inspired by Netty\n */\npublic abstract class ReferenceCountedResource implements AutoCloseable {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ReferenceCountedResource.class);\n    private static final AtomicLongFieldUpdater<ReferenceCountedResource> COUNTER_UPDATER =\n            AtomicLongFieldUpdater.newUpdater(ReferenceCountedResource.class, \"counter\");\n\n    private volatile long counter = 1;\n\n    /**\n     * Increments the reference count by 1.\n     */\n    public final ReferenceCountedResource retain() {\n        long oldCount = COUNTER_UPDATER.getAndIncrement(this);\n        if (oldCount <= 0) {\n            COUNTER_UPDATER.getAndDecrement(this);\n            throw new AssertionError(\"This instance has been destroyed\");\n        }\n        return this;\n    }\n\n    /**\n     * Decreases the reference count by 1 and calls {@link this#destroy} if the reference count reaches 0.\n     */\n    public final boolean release() {\n        long remainingCount = COUNTER_UPDATER.decrementAndGet(this);\n\n        if (remainingCount == 0) {\n            destroy();\n            return true;\n        } else if (remainingCount <= -1) {\n            logger.warn(PROTOCOL_ERROR_CLOSE_CLIENT, \"\", \"\", \"This instance has been destroyed\");\n            return false;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * Useful when used together with try-with-resources pattern\n     */\n    @Override\n    public final void close() {\n        release();\n    }\n\n    /**\n     * This method will be invoked when counter reaches 0, override this method to destroy materials related to the specific resource.\n     */\n    protected abstract void destroy();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/resource/Disposable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.resource;\n\n/**\n * An interface for destroying resources\n */\npublic interface Disposable {\n\n    void destroy();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/resource/GlobalResourceInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.resource;\n\nimport org.apache.dubbo.common.concurrent.CallableSafeInitializer;\n\nimport java.util.concurrent.Callable;\nimport java.util.function.Consumer;\n\n/**\n * A initializer to release resource automatically on dubbo shutdown\n */\npublic class GlobalResourceInitializer<T> extends CallableSafeInitializer<T> {\n\n    /**\n     * The Dispose action to be executed on shutdown.\n     */\n    private Consumer<T> disposeAction;\n\n    private Disposable disposable;\n\n    public GlobalResourceInitializer(Callable<T> initializer) {\n        super(initializer);\n    }\n\n    public GlobalResourceInitializer(Callable<T> initializer, Consumer<T> disposeAction) {\n        super(initializer);\n        this.disposeAction = disposeAction;\n    }\n\n    public GlobalResourceInitializer(Callable<T> callable, Disposable disposable) {\n        super(callable);\n        this.disposable = disposable;\n    }\n\n    @Override\n    protected T initialize() {\n        T value = super.initialize();\n        // register disposable to release automatically\n        if (this.disposable != null) {\n            GlobalResourcesRepository.getInstance().registerDisposable(this.disposable);\n        } else {\n            GlobalResourcesRepository.getInstance().registerDisposable(() -> this.remove(disposeAction));\n        }\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/resource/GlobalResourcesRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.resource;\n\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVER_SHUTDOWN_TIMEOUT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\n/**\n * Global resource repository between all framework models.\n * It will be destroyed only after all framework model is destroyed.\n */\npublic class GlobalResourcesRepository {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(GlobalResourcesRepository.class);\n\n    private static volatile GlobalResourcesRepository instance;\n    private volatile ExecutorService executorService;\n    private final List<Disposable> oneoffDisposables = new CopyOnWriteArrayList<>();\n    private static final List<Disposable> globalReusedDisposables = new CopyOnWriteArrayList<>();\n\n    private GlobalResourcesRepository() {}\n\n    public static GlobalResourcesRepository getInstance() {\n        if (instance == null) {\n            synchronized (GlobalResourcesRepository.class) {\n                if (instance == null) {\n                    instance = new GlobalResourcesRepository();\n                }\n            }\n        }\n        return instance;\n    }\n\n    /**\n     * Register a global reused disposable. The disposable will be executed when all dubbo FrameworkModels are destroyed.\n     * Note: the global disposable should be registered in static code, it's reusable and will not be removed when dubbo shutdown.\n     *\n     * @param disposable\n     */\n    public static void registerGlobalDisposable(Disposable disposable) {\n        if (!globalReusedDisposables.contains(disposable)) {\n            synchronized (GlobalResourcesRepository.class) {\n                if (!globalReusedDisposables.contains(disposable)) {\n                    globalReusedDisposables.add(disposable);\n                }\n            }\n        }\n    }\n\n    public void removeGlobalDisposable(Disposable disposable) {\n        if (globalReusedDisposables.contains(disposable)) {\n            synchronized (GlobalResourcesRepository.class) {\n                if (globalReusedDisposables.contains(disposable)) {\n                    this.globalReusedDisposables.remove(disposable);\n                }\n            }\n        }\n    }\n\n    public static ExecutorService getGlobalExecutorService() {\n        return getInstance().getExecutorService();\n    }\n\n    public ExecutorService getExecutorService() {\n        if (executorService == null || executorService.isShutdown()) {\n            synchronized (this) {\n                if (executorService == null || executorService.isShutdown()) {\n                    if (logger.isInfoEnabled()) {\n                        logger.info(\"Creating global shared handler ...\");\n                    }\n                    executorService =\n                            Executors.newCachedThreadPool(new NamedThreadFactory(\"Dubbo-global-shared-handler\", true));\n                }\n            }\n        }\n        return executorService;\n    }\n\n    public synchronized void destroy() {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Destroying global resources ...\");\n        }\n        if (executorService != null) {\n            executorService.shutdownNow();\n            try {\n                if (!executorService.awaitTermination(\n                        ConfigurationUtils.reCalShutdownTime(DEFAULT_SERVER_SHUTDOWN_TIMEOUT), TimeUnit.MILLISECONDS)) {\n                    logger.warn(\n                            COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"Wait global executor service terminated timeout.\");\n                }\n            } catch (InterruptedException e) {\n                logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"destroy resources failed: \" + e.getMessage(), e);\n            }\n            executorService = null;\n        }\n\n        // call one-off disposables\n        for (Disposable disposable : new ArrayList<>(oneoffDisposables)) {\n            try {\n                disposable.destroy();\n            } catch (Exception e) {\n                logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"destroy resources failed: \" + e.getMessage(), e);\n            }\n        }\n        // clear one-off disposable\n        oneoffDisposables.clear();\n\n        // call global disposable, don't clear globalReusedDisposables for reuse purpose\n        for (Disposable disposable : new ArrayList<>(globalReusedDisposables)) {\n            try {\n                disposable.destroy();\n            } catch (Exception e) {\n                logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"destroy resources failed: \" + e.getMessage(), e);\n            }\n        }\n\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Dubbo is completely destroyed\");\n        }\n    }\n\n    /**\n     * Register a one-off disposable, the disposable is removed automatically on first shutdown.\n     *\n     * @param disposable\n     */\n    public void registerDisposable(Disposable disposable) {\n        if (!oneoffDisposables.contains(disposable)) {\n            synchronized (this) {\n                if (!oneoffDisposables.contains(disposable)) {\n                    oneoffDisposables.add(disposable);\n                }\n            }\n        }\n    }\n\n    public void removeDisposable(Disposable disposable) {\n        if (oneoffDisposables.contains(disposable)) {\n            synchronized (this) {\n                if (oneoffDisposables.contains(disposable)) {\n                    oneoffDisposables.remove(disposable);\n                }\n            }\n        }\n    }\n\n    // for test\n    public static List<Disposable> getGlobalReusedDisposables() {\n        return globalReusedDisposables;\n    }\n\n    // for test\n    public List<Disposable> getOneoffDisposables() {\n        return oneoffDisposables;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/resource/Initializable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.resource;\n\nimport org.apache.dubbo.common.extension.ExtensionAccessor;\n\n/**\n * An interface for Initializing resources\n */\npublic interface Initializable {\n\n    default void initialize(ExtensionAccessor accessor) {\n        initialize();\n    }\n\n    default void initialize() {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/serialization/ClassHolder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.serialization;\n\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\n\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class ClassHolder {\n    private final ConcurrentHashMap<String, Set<Class<?>>> classCache = new ConcurrentHashMap<>();\n\n    public void storeClass(Class<?> clazz) {\n        ConcurrentHashMapUtils.computeIfAbsent(classCache, clazz.getName(), k -> new ConcurrentHashSet<>())\n                .add(clazz);\n    }\n\n    public Class<?> loadClass(String className, ClassLoader classLoader) {\n        Set<Class<?>> classList = classCache.get(className);\n        if (classList == null) {\n            return null;\n        }\n        for (Class<?> clazz : classList) {\n            if (classLoader.equals(clazz.getClassLoader())) {\n                return clazz;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/serialization/PreferSerializationProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.serialization;\n\npublic interface PreferSerializationProvider {\n    String getPreferSerialization();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/ssl/AuthPolicy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.ssl;\n\npublic enum AuthPolicy {\n    NONE,\n    SERVER_AUTH,\n    CLIENT_AUTH\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/ssl/Cert.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.ssl;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.InputStream;\n\npublic class Cert {\n    private final byte[] keyCertChain;\n    private final byte[] privateKey;\n    private final byte[] trustCert;\n\n    private final String password;\n\n    public Cert(byte[] keyCertChain, byte[] privateKey, byte[] trustCert) {\n        this(keyCertChain, privateKey, trustCert, null);\n    }\n\n    public Cert(byte[] keyCertChain, byte[] privateKey, byte[] trustCert, String password) {\n        this.keyCertChain = keyCertChain;\n        this.privateKey = privateKey;\n        this.trustCert = trustCert;\n        this.password = password;\n    }\n\n    public byte[] getKeyCertChain() {\n        return keyCertChain;\n    }\n\n    public InputStream getKeyCertChainInputStream() {\n        return keyCertChain != null ? new ByteArrayInputStream(keyCertChain) : null;\n    }\n\n    public byte[] getPrivateKey() {\n        return privateKey;\n    }\n\n    public InputStream getPrivateKeyInputStream() {\n        return privateKey != null ? new ByteArrayInputStream(privateKey) : null;\n    }\n\n    public byte[] getTrustCert() {\n        return trustCert;\n    }\n\n    public InputStream getTrustCertInputStream() {\n        return trustCert != null ? new ByteArrayInputStream(trustCert) : null;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/ssl/CertManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.ssl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.net.SocketAddress;\nimport java.util.List;\n\npublic class CertManager {\n    private final List<CertProvider> certProviders;\n\n    public CertManager(FrameworkModel frameworkModel) {\n        this.certProviders =\n                frameworkModel.getExtensionLoader(CertProvider.class).getActivateExtensions();\n    }\n\n    public ProviderCert getProviderConnectionConfig(URL localAddress, SocketAddress remoteAddress) {\n        for (CertProvider certProvider : certProviders) {\n            if (certProvider.isSupport(localAddress, remoteAddress)) {\n                ProviderCert cert = certProvider.getProviderConnectionConfig(localAddress, remoteAddress);\n                if (cert != null) {\n                    return cert;\n                }\n            }\n        }\n        return null;\n    }\n\n    public Cert getConsumerConnectionConfig(URL remoteAddress) {\n        for (CertProvider certProvider : certProviders) {\n            if (certProvider.isSupport(remoteAddress)) {\n                Cert cert = certProvider.getConsumerConnectionConfig(remoteAddress);\n                if (cert != null) {\n                    return cert;\n                }\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/ssl/CertProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.ssl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.net.SocketAddress;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface CertProvider {\n    boolean isSupport(URL address);\n\n    default boolean isSupport(URL address, SocketAddress remoteAddress) {\n        return isSupport(address);\n    }\n\n    ProviderCert getProviderConnectionConfig(URL localAddress);\n\n    default ProviderCert getProviderConnectionConfig(URL localAddress, SocketAddress remoteAddress) {\n        return getProviderConnectionConfig(localAddress);\n    }\n\n    Cert getConsumerConnectionConfig(URL remoteAddress);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/ssl/ProviderCert.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.ssl;\n\npublic class ProviderCert extends Cert {\n    private final AuthPolicy authPolicy;\n\n    public ProviderCert(byte[] keyCertChain, byte[] privateKey, byte[] trustCert, AuthPolicy authPolicy) {\n        super(keyCertChain, privateKey, trustCert);\n        this.authPolicy = authPolicy;\n    }\n\n    public ProviderCert(\n            byte[] keyCertChain, byte[] privateKey, byte[] trustCert, String password, AuthPolicy authPolicy) {\n        super(keyCertChain, privateKey, trustCert, password);\n        this.authPolicy = authPolicy;\n    }\n\n    public AuthPolicy getAuthPolicy() {\n        return authPolicy;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/ssl/impl/SSLConfigCertProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.ssl.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.ssl.AuthPolicy;\nimport org.apache.dubbo.common.ssl.Cert;\nimport org.apache.dubbo.common.ssl.CertProvider;\nimport org.apache.dubbo.common.ssl.ProviderCert;\nimport org.apache.dubbo.common.utils.IOUtils;\n\nimport java.io.IOException;\nimport java.util.Objects;\n\n@Activate(order = Integer.MAX_VALUE - 10000)\npublic class SSLConfigCertProvider implements CertProvider {\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SSLConfigCertProvider.class);\n\n    @Override\n    public boolean isSupport(URL address) {\n        return address.getOrDefaultApplicationModel()\n                .getApplicationConfigManager()\n                .getSsl()\n                .isPresent();\n    }\n\n    @Override\n    public ProviderCert getProviderConnectionConfig(URL localAddress) {\n        return localAddress\n                .getOrDefaultApplicationModel()\n                .getApplicationConfigManager()\n                .getSsl()\n                .filter(sslConfig -> Objects.nonNull(sslConfig.getServerKeyCertChainPath()))\n                .filter(sslConfig -> Objects.nonNull(sslConfig.getServerPrivateKeyPath()))\n                .map(sslConfig -> {\n                    try {\n                        return new ProviderCert(\n                                IOUtils.toByteArray(sslConfig.getServerKeyCertChainPathStream()),\n                                IOUtils.toByteArray(sslConfig.getServerPrivateKeyPathStream()),\n                                sslConfig.getServerTrustCertCollectionPath() != null\n                                        ? IOUtils.toByteArray(sslConfig.getServerTrustCertCollectionPathStream())\n                                        : null,\n                                sslConfig.getServerKeyPassword(),\n                                AuthPolicy.CLIENT_AUTH);\n                    } catch (IOException e) {\n                        logger.warn(\n                                LoggerCodeConstants.CONFIG_SSL_PATH_LOAD_FAILED,\n                                \"\",\n                                \"\",\n                                \"Failed to load ssl config.\",\n                                e);\n                        return null;\n                    }\n                })\n                .orElse(null);\n    }\n\n    @Override\n    public Cert getConsumerConnectionConfig(URL remoteAddress) {\n        return remoteAddress\n                .getOrDefaultApplicationModel()\n                .getApplicationConfigManager()\n                .getSsl()\n                .filter(sslConfig -> Objects.nonNull(sslConfig.getClientKeyCertChainPath()))\n                .filter(sslConfig -> Objects.nonNull(sslConfig.getClientPrivateKeyPath()))\n                .map(sslConfig -> {\n                    try {\n                        return new Cert(\n                                IOUtils.toByteArray(sslConfig.getClientKeyCertChainPathStream()),\n                                IOUtils.toByteArray(sslConfig.getClientPrivateKeyPathStream()),\n                                sslConfig.getClientTrustCertCollectionPath() != null\n                                        ? IOUtils.toByteArray(sslConfig.getClientTrustCertCollectionPathStream())\n                                        : null,\n                                sslConfig.getClientKeyPassword());\n                    } catch (IOException e) {\n                        logger.warn(\n                                LoggerCodeConstants.CONFIG_SSL_PATH_LOAD_FAILED,\n                                \"\",\n                                \"\",\n                                \"Failed to load ssl config.\",\n                                e);\n                        return null;\n                    }\n                })\n                .orElse(null);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/status/Status.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status;\n\npublic class Status {\n\n    private final Level level;\n    private final String message;\n    private final String description;\n\n    public Status(Level level) {\n        this(level, null, null);\n    }\n\n    public Status(Level level, String message) {\n        this(level, message, null);\n    }\n\n    public Status(Level level, String message, String description) {\n        this.level = level;\n        this.message = message;\n        this.description = description;\n    }\n\n    public Level getLevel() {\n        return level;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    /**\n     * Level\n     */\n    public enum Level {\n        /**\n         * OK\n         */\n        OK,\n\n        /**\n         * WARN\n         */\n        WARN,\n\n        /**\n         * ERROR\n         */\n        ERROR,\n\n        /**\n         * UNKNOWN\n         */\n        UNKNOWN\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/status/StatusChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.APPLICATION)\npublic interface StatusChecker {\n\n    /**\n     * check status\n     *\n     * @return status\n     */\n    Status check();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/status/reporter/FrameworkStatusReportService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status.reporter;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport java.util.HashMap;\nimport java.util.Set;\n\npublic class FrameworkStatusReportService implements ScopeModelAware {\n\n    private static final Logger logger = LoggerFactory.getLogger(FrameworkStatusReporter.class);\n    public static final String REGISTRATION_STATUS = \"registration\";\n    public static final String ADDRESS_CONSUMPTION_STATUS = \"consumption\";\n    public static final String MIGRATION_STEP_STATUS = \"migrationStepStatus\";\n\n    private ApplicationModel applicationModel;\n    private Set<FrameworkStatusReporter> reporters;\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        reporters = applicationModel\n                .getExtensionLoader(FrameworkStatusReporter.class)\n                .getSupportedExtensionInstances();\n    }\n\n    public void reportRegistrationStatus(Object obj) {\n        doReport(REGISTRATION_STATUS, obj);\n    }\n\n    public void reportConsumptionStatus(Object obj) {\n        doReport(ADDRESS_CONSUMPTION_STATUS, obj);\n    }\n\n    public void reportMigrationStepStatus(Object obj) {\n        doReport(MIGRATION_STEP_STATUS, obj);\n    }\n\n    public boolean hasReporter() {\n        return reporters.size() > 0;\n    }\n\n    private void doReport(String type, Object obj) {\n        // TODO, report asynchronously\n        try {\n            if (CollectionUtils.isNotEmpty(reporters)) {\n                for (FrameworkStatusReporter reporter : reporters) {\n                    reporter.report(type, obj);\n                }\n            }\n        } catch (Exception e) {\n            logger.info(\"Report \" + type + \" status failed because of \" + e.getMessage());\n        }\n    }\n\n    public String createRegistrationReport(String status) {\n        HashMap<String, String> registration = new HashMap<>();\n        registration.put(\"application\", applicationModel.getApplicationName());\n        registration.put(\"status\", status);\n        return JsonUtils.toJson(registration);\n    }\n\n    public String createConsumptionReport(String interfaceName, String version, String group, String status) {\n        HashMap<String, String> migrationStatus = new HashMap<>();\n        migrationStatus.put(\"type\", \"consumption\");\n        migrationStatus.put(\"application\", applicationModel.getApplicationName());\n        migrationStatus.put(\"service\", interfaceName);\n        migrationStatus.put(\"version\", version);\n        migrationStatus.put(\"group\", group);\n        migrationStatus.put(\"status\", status);\n        return JsonUtils.toJson(migrationStatus);\n    }\n\n    public String createMigrationStepReport(\n            String interfaceName, String version, String group, String originStep, String newStep, String success) {\n        HashMap<String, String> migrationStatus = new HashMap<>();\n        migrationStatus.put(\"type\", \"migrationStepStatus\");\n        migrationStatus.put(\"application\", applicationModel.getApplicationName());\n        migrationStatus.put(\"service\", interfaceName);\n        migrationStatus.put(\"version\", version);\n        migrationStatus.put(\"group\", group);\n        migrationStatus.put(\"originStep\", originStep);\n        migrationStatus.put(\"newStep\", newStep);\n        migrationStatus.put(\"success\", success);\n        return JsonUtils.toJson(migrationStatus);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/status/reporter/FrameworkStatusReporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status.reporter;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\n@SPI(scope = ExtensionScope.APPLICATION)\npublic interface FrameworkStatusReporter extends ScopeModelAware {\n\n    void report(String type, Object obj);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/status/support/LoadStatusChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status.support;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.status.Status;\nimport org.apache.dubbo.common.status.StatusChecker;\nimport org.apache.dubbo.common.system.OperatingSystemBeanManager;\n\n/**\n * Load Status\n */\n@Activate\npublic class LoadStatusChecker implements StatusChecker {\n\n    @Override\n    public Status check() {\n        double load = OperatingSystemBeanManager.getOperatingSystemBean().getSystemLoadAverage();\n        if (load == -1) {\n            load = OperatingSystemBeanManager.getSystemCpuUsage();\n        }\n\n        int cpu = OperatingSystemBeanManager.getOperatingSystemBean().getAvailableProcessors();\n        Status.Level level;\n        if (load < 0) {\n            level = Status.Level.UNKNOWN;\n        } else if (load < cpu) {\n            level = Status.Level.OK;\n        } else {\n            level = Status.Level.WARN;\n        }\n\n        String message = (load < 0 ? \"\" : \"load:\" + load + \",\") + \"cpu:\" + cpu;\n        return new Status(level, message);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/status/support/MemoryStatusChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status.support;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.status.Status;\nimport org.apache.dubbo.common.status.StatusChecker;\n\n/**\n * MemoryStatus\n */\n@Activate\npublic class MemoryStatusChecker implements StatusChecker {\n\n    @Override\n    public Status check() {\n        Runtime runtime = Runtime.getRuntime();\n        long freeMemory = runtime.freeMemory();\n        long totalMemory = runtime.totalMemory();\n        long maxMemory = runtime.maxMemory();\n        boolean ok = (maxMemory - (totalMemory - freeMemory) > 2 * 1024 * 1024); // Alarm when spare memory < 2M\n        String msg = \"max:\" + (maxMemory / 1024 / 1024) + \"M,total:\" + (totalMemory / 1024 / 1024) + \"M,used:\"\n                + ((totalMemory / 1024 / 1024) - (freeMemory / 1024 / 1024)) + \"M,free:\" + (freeMemory / 1024 / 1024)\n                + \"M\";\n        return new Status(ok ? Status.Level.OK : Status.Level.WARN, msg);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/status/support/StatusUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status.support;\n\nimport org.apache.dubbo.common.status.Status;\nimport org.apache.dubbo.common.status.Status.Level;\n\nimport java.util.Map;\n\n/**\n * StatusManager\n */\npublic class StatusUtils {\n\n    public static Status getSummaryStatus(Map<String, Status> statuses) {\n        Level level = Level.OK;\n        StringBuilder msg = new StringBuilder();\n        for (Map.Entry<String, Status> entry : statuses.entrySet()) {\n            String key = entry.getKey();\n            Status status = entry.getValue();\n            Level l = status.getLevel();\n            if (Level.ERROR.equals(l)) {\n                level = Level.ERROR;\n                if (msg.length() > 0) {\n                    msg.append(',');\n                }\n                msg.append(key);\n            } else if (Level.WARN.equals(l)) {\n                if (!Level.ERROR.equals(level)) {\n                    level = Level.WARN;\n                }\n                if (msg.length() > 0) {\n                    msg.append(',');\n                }\n                msg.append(key);\n            }\n        }\n        return new Status(level, msg.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/store/DataStore.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.store;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.Map;\n\n@SPI(value = \"simple\", scope = ExtensionScope.APPLICATION)\npublic interface DataStore {\n\n    /**\n     * return a snapshot value of componentName\n     */\n    Map<String, Object> get(String componentName);\n\n    Object get(String componentName, String key);\n\n    void put(String componentName, String key, Object value);\n\n    void remove(String componentName, String key);\n\n    default void addListener(DataStoreUpdateListener dataStoreUpdateListener) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/store/DataStoreUpdateListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.store;\n\npublic interface DataStoreUpdateListener {\n    void onUpdate(String componentName, String key, Object value);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/store/support/SimpleDataStore.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.store.support;\n\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.store.DataStore;\nimport org.apache.dubbo.common.store.DataStoreUpdateListener;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\npublic class SimpleDataStore implements DataStore {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SimpleDataStore.class);\n\n    // <component name or id, <data-name, data-value>>\n    private final ConcurrentMap<String, ConcurrentMap<String, Object>> data = new ConcurrentHashMap<>();\n    private final ConcurrentHashSet<DataStoreUpdateListener> listeners = new ConcurrentHashSet<>();\n\n    @Override\n    public Map<String, Object> get(String componentName) {\n        ConcurrentMap<String, Object> value = data.get(componentName);\n        if (value == null) {\n            return new HashMap<>();\n        }\n\n        return new HashMap<>(value);\n    }\n\n    @Override\n    public Object get(String componentName, String key) {\n        if (!data.containsKey(componentName)) {\n            return null;\n        }\n        return data.get(componentName).get(key);\n    }\n\n    @Override\n    public void put(String componentName, String key, Object value) {\n        Map<String, Object> componentData =\n                ConcurrentHashMapUtils.computeIfAbsent(data, componentName, k -> new ConcurrentHashMap<>());\n        componentData.put(key, value);\n        notifyListeners(componentName, key, value);\n    }\n\n    @Override\n    public void remove(String componentName, String key) {\n        if (!data.containsKey(componentName)) {\n            return;\n        }\n        data.get(componentName).remove(key);\n        notifyListeners(componentName, key, null);\n    }\n\n    @Override\n    public void addListener(DataStoreUpdateListener dataStoreUpdateListener) {\n        listeners.add(dataStoreUpdateListener);\n    }\n\n    private void notifyListeners(String componentName, String key, Object value) {\n        for (DataStoreUpdateListener listener : listeners) {\n            try {\n                listener.onUpdate(componentName, key, value);\n            } catch (Throwable t) {\n                logger.warn(\n                        LoggerCodeConstants.INTERNAL_ERROR,\n                        \"\",\n                        \"\",\n                        \"Failed to notify data store update listener. \" + \"ComponentName: \" + componentName + \" Key: \"\n                                + key,\n                        t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/stream/CallStreamObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.stream;\n\n/**\n * An extension of {@link StreamObserver} that provides additional functionality for flow control\n * and backpressure. This interface mirrors gRPC's {@code io.grpc.stub.CallStreamObserver} for compatibility.\n *\n * <p>This is the base interface for both client-side ({@link ClientCallStreamObserver}) and\n * server-side ({@link ServerCallStreamObserver}) flow control observers. It provides two types\n * of flow control:\n *\n * <h3>Send-Side Backpressure (Outbound Flow Control)</h3>\n * <p>Controls the rate at which data is sent to avoid overwhelming the receiver:\n * <ul>\n *   <li>{@link #isReady()} - Check if the stream can accept more data without blocking</li>\n *   <li>{@link #setOnReadyHandler(Runnable)} - Register a callback for when the stream becomes writable</li>\n * </ul>\n *\n * <h3>Receive-Side Backpressure (Inbound Flow Control)</h3>\n * <p>Controls the rate at which data is received to avoid being overwhelmed:\n * <ul>\n *   <li>{@link #disableAutoFlowControl()} - Switch from automatic to manual message requesting</li>\n *   <li>{@link #request(int)} - Explicitly request a specific number of messages from the sender</li>\n * </ul>\n *\n * <h3>Typical Usage Pattern</h3>\n * <pre>{@code\n * // Send-side backpressure example\n * callStreamObserver.setOnReadyHandler(() -> {\n *     while (callStreamObserver.isReady() && hasMoreData()) {\n *         callStreamObserver.onNext(getNextData());\n *     }\n *     if (!hasMoreData()) {\n *         callStreamObserver.onCompleted();\n *     }\n * });\n *\n * // Receive-side backpressure example (in beforeStart or similar)\n * callStreamObserver.disableAutoFlowControl();\n * callStreamObserver.request(10); // Request initial batch\n *\n * // Then in onNext()\n * public void onNext(T value) {\n *     process(value);\n *     callStreamObserver.request(1); // Request next message after processing\n * }\n * }</pre>\n *\n * @param <T> the type of value passed to the stream\n * @see ClientCallStreamObserver\n * @see ServerCallStreamObserver\n * @see ClientResponseObserver\n */\npublic interface CallStreamObserver<T> extends StreamObserver<T> {\n\n    /**\n     * Returns {@code true} if the stream is ready to accept more messages.\n     *\n     * <p>If {@code false} is returned, the caller should avoid calling\n     * {@link StreamObserver#onNext(Object)} to prevent excessive buffering.\n     * Instead, the caller should wait for the {@link #setOnReadyHandler(Runnable) onReadyHandler}\n     * to be called before sending more messages.\n     *\n     * <p>This method is safe to call from multiple threads.\n     *\n     * @return {@code true} if the stream is ready for writing, {@code false} otherwise\n     */\n    boolean isReady();\n\n    /**\n     * Sets a callback to be invoked when the stream becomes ready for writing after\n     * previously returning {@code false} from {@link #isReady()}.\n     *\n     * <p>The handler will be called on the event loop thread, so any long-running\n     * operations should be offloaded to a separate executor.\n     *\n     * <p>Typical usage pattern:\n     * <pre>{@code\n     * observer.setOnReadyHandler(() -> {\n     *     while (observer.isReady() && hasMoreData()) {\n     *         observer.onNext(getNextData());\n     *     }\n     * });\n     * }</pre>\n     *\n     * @param onReadyHandler the handler to invoke when the stream becomes ready\n     */\n    void setOnReadyHandler(Runnable onReadyHandler);\n\n    /**\n     * Requests the peer to produce {@code count} more messages to be delivered to the 'inbound'\n     * {@link StreamObserver}.\n     *\n     * <p>This method is safe to call from multiple threads without external synchronization.\n     *\n     * @param count more messages\n     */\n    void request(int count);\n\n    /**\n     * Sets the compression algorithm to use for the call\n     * <p>\n     * For stream set compression needs to determine whether the metadata has been sent, and carry\n     * on corresponding processing\n     */\n    void setCompression(String compression);\n\n    /**\n     * Swaps to manual flow control where no message will be delivered to {@link\n     * StreamObserver#onNext(Object)} unless it is {@link #request request()}ed. Since {@code\n     * request()} may not be called before the call is started, a number of initial requests may be\n     * specified.\n     */\n    void disableAutoFlowControl();\n\n    /**\n     * Compatibility method to mirror gRPC Java\n     * {@code io.grpc.stub.CallStreamObserver#disableAutoInboundFlowControl()}.\n     * <p>\n     * This allows code written against gRPC's {@code CallStreamObserver} API to be\n     * more easily reused with Dubbo by providing an equivalent entry point that\n     * delegates to {@link #disableAutoFlowControl()}.\n     */\n    default void disableAutoInboundFlowControl() {\n        disableAutoFlowControl();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/stream/ClientCallStreamObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.stream;\n\n/**\n * A client-side extension of {@link CallStreamObserver} that provides additional functionality\n * for controlling the outbound request stream. This interface mirrors gRPC's\n * {@code io.grpc.stub.ClientCallStreamObserver} for compatibility.\n *\n * <p>This interface is typically obtained through {@link ClientResponseObserver#beforeStart(ClientCallStreamObserver)}\n * and provides methods for:\n * <ul>\n *   <li>Controlling send-side backpressure via {@link #isReady()} and {@link #setOnReadyHandler(Runnable)}</li>\n *   <li>Controlling receive-side backpressure via {@link #disableAutoRequestWithInitial(int)} and {@link #request(int)}</li>\n * </ul>\n *\n * <h3>Send-Side Backpressure (Controlling Outgoing Data Rate)</h3>\n * <pre>{@code\n * @Override\n * public void beforeStart(ClientCallStreamObserver<Request> requestStream) {\n *     requestStream.disableAutoFlowControl();\n *     requestStream.setOnReadyHandler(() -> {\n *         while (requestStream.isReady() && hasMoreData()) {\n *             requestStream.onNext(getNextRequest());\n *         }\n *     });\n * }\n * }</pre>\n *\n * <h3>Receive-Side Backpressure (Controlling Incoming Data Rate)</h3>\n * <pre>{@code\n * @Override\n * public void beforeStart(ClientCallStreamObserver<Request> requestStream) {\n *     // Request only 10 messages initially\n *     requestStream.disableAutoRequestWithInitial(10);\n * }\n *\n * @Override\n * public void onNext(Response response) {\n *     process(response);\n *     // Request more after processing\n *     requestStream.request(1);\n * }\n * }</pre>\n *\n * @param <ReqT> the type of messages sent to the server (request type)\n * @see CallStreamObserver\n * @see ClientResponseObserver\n */\npublic interface ClientCallStreamObserver<ReqT> extends CallStreamObserver<ReqT> {\n\n    /**\n     * Disables automatic inbound flow control and sets the initial number of messages\n     * to request from the server.\n     *\n     * <p>By default, the runtime automatically requests messages from the server as they\n     * are consumed. Calling this method switches to manual flow control mode, where the\n     * client must explicitly call {@link #request(int)} to receive more messages.\n     *\n     * <p>This method <strong>must</strong> be called within\n     * {@link ClientResponseObserver#beforeStart(ClientCallStreamObserver)} before the\n     * stream starts, otherwise it has no effect.\n     *\n     * <p><strong>Usage:</strong>\n     * <pre>{@code\n     * @Override\n     * public void beforeStart(ClientCallStreamObserver<Request> requestStream) {\n     *     // Start with 5 messages, then request more in onNext()\n     *     requestStream.disableAutoRequestWithInitial(5);\n     * }\n     *\n     * @Override\n     * public void onNext(Response response) {\n     *     process(response);\n     *     requestStream.request(1); // Request one more message\n     * }\n     * }</pre>\n     *\n     * @param request the initial number of messages to request from the server.\n     *                A value of 0 means no messages will be delivered until {@link #request(int)} is called.\n     * @see #request(int)\n     * @see #disableAutoFlowControl()\n     */\n    void disableAutoRequestWithInitial(int request);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/stream/ClientResponseObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.stream;\n\n/**\n * A client-side {@link StreamObserver} that provides a callback to receive a reference to the\n * outbound request stream observer before the call starts. This interface mirrors gRPC's\n * {@code io.grpc.stub.ClientResponseObserver} for compatibility.\n *\n * <p>This interface is used for advanced flow control scenarios where the client needs to:\n * <ul>\n *   <li>Configure flow control settings before the stream starts</li>\n *   <li>Set up an {@link CallStreamObserver#setOnReadyHandler(Runnable) onReadyHandler} for send-side backpressure</li>\n *   <li>Control the rate of receiving messages using {@link ClientCallStreamObserver#disableAutoRequestWithInitial(int)}</li>\n * </ul>\n *\n * <h3>Example Usage</h3>\n * <pre>{@code\n * // Client streaming with backpressure\n * ClientResponseObserver<DataChunk, Response> responseObserver =\n *         new ClientResponseObserver<DataChunk, Response>() {\n *     @Override\n *     public void beforeStart(ClientCallStreamObserver<DataChunk> requestStream) {\n *         // Disable auto flow control for manual send control\n *         requestStream.disableAutoFlowControl();\n *\n *         // Set up onReadyHandler for send-side backpressure\n *         requestStream.setOnReadyHandler(() -> {\n *             while (requestStream.isReady() && hasMoreData()) {\n *                 requestStream.onNext(getNextChunk());\n *             }\n *         });\n *     }\n *\n *     @Override\n *     public void onNext(Response response) { ... }\n *\n *     @Override\n *     public void onError(Throwable t) { ... }\n *\n *     @Override\n *     public void onCompleted() { ... }\n * };\n *\n * service.clientStream(responseObserver);\n * }</pre>\n *\n * @param <ReqT> the type of messages sent to the server (request type)\n * @param <RespT> the type of messages received from the server (response type)\n * @see ClientCallStreamObserver\n * @see CallStreamObserver\n */\npublic interface ClientResponseObserver<ReqT, RespT> extends StreamObserver<RespT> {\n\n    /**\n     * Called by the runtime prior to the start of a call to provide a reference to the\n     * {@link ClientCallStreamObserver} for the outbound request stream.\n     *\n     * <p>This callback is invoked <strong>before</strong> the underlying stream is created,\n     * allowing the client to configure flow control settings that take effect from the\n     * beginning of the call.\n     *\n     * <p><strong>Allowed operations in this callback:</strong>\n     * <ul>\n     *   <li>{@link ClientCallStreamObserver#setOnReadyHandler(Runnable)} - Set handler for send-side backpressure</li>\n     *   <li>{@link ClientCallStreamObserver#disableAutoRequestWithInitial(int)} - Configure receive-side backpressure</li>\n     *   <li>{@link CallStreamObserver#disableAutoFlowControl()} - Disable automatic flow control</li>\n     * </ul>\n     *\n     * <p><strong>Note:</strong> Do not call {@link StreamObserver#onNext(Object)} or\n     * {@link StreamObserver#onCompleted()} within this callback. Data should only be sent\n     * after the stream is ready (via the {@code onReadyHandler}).\n     *\n     * @param requestStream the {@link ClientCallStreamObserver} for sending requests to the server\n     */\n    void beforeStart(final ClientCallStreamObserver<ReqT> requestStream);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/stream/ServerCallStreamObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.stream;\n\n/**\n * A server-side extension of {@link CallStreamObserver} that provides flow control capabilities\n * for outbound response streams. This interface mirrors gRPC's\n * {@code io.grpc.stub.ServerCallStreamObserver} for compatibility.\n *\n * <p>On the server side, this interface is obtained by casting the {@link StreamObserver}\n * parameter passed to streaming RPC methods. It allows the server to:\n * <ul>\n *   <li>Check if the response stream is ready using {@link #isReady()}</li>\n *   <li>Set a callback for when the stream becomes ready using {@link #setOnReadyHandler(Runnable)}</li>\n *   <li>Control inbound flow from the client using {@link #request(int)} and {@link #disableAutoFlowControl()}</li>\n * </ul>\n *\n * <h3>Server-Side Send Backpressure Example</h3>\n * <pre>{@code\n * @Override\n * public void serverStream(Request request, StreamObserver<Response> responseObserver) {\n *     ServerCallStreamObserver<Response> serverObserver =\n *             (ServerCallStreamObserver<Response>) responseObserver;\n *\n *     AtomicInteger sent = new AtomicInteger(0);\n *     int totalCount = 100;\n *\n *     serverObserver.setOnReadyHandler(() -> {\n *         while (serverObserver.isReady() && sent.get() < totalCount) {\n *             int seq = sent.getAndIncrement();\n *             serverObserver.onNext(createResponse(seq));\n *         }\n *         if (sent.get() >= totalCount) {\n *             serverObserver.onCompleted();\n *         }\n *     });\n * }\n * }</pre>\n *\n * <h3>Server-Side Receive Backpressure Example (for Client/Bidi Streaming)</h3>\n * <pre>{@code\n * @Override\n * public StreamObserver<Request> clientStream(StreamObserver<Response> responseObserver) {\n *     ServerCallStreamObserver<Response> serverObserver =\n *             (ServerCallStreamObserver<Response>) responseObserver;\n *\n *     // Control how many messages we receive from the client\n *     serverObserver.disableAutoFlowControl();\n *     serverObserver.request(5); // Start with 5 messages\n *\n *     return new StreamObserver<Request>() {\n *         @Override\n *         public void onNext(Request request) {\n *             process(request);\n *             serverObserver.request(1); // Request one more\n *         }\n *         // ... onError, onCompleted\n *     };\n * }\n * }</pre>\n *\n * @param <RespT> the type of messages sent to the client (response type)\n * @see CallStreamObserver\n * @see StreamObserver\n */\npublic interface ServerCallStreamObserver<RespT> extends CallStreamObserver<RespT> {\n\n    default void disableAutoRequest() {\n        disableAutoFlowControl();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/stream/StreamObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.stream;\n\n/**\n * StreamObserver is a common streaming API. It is an observer for receiving messages.\n * Implementations are NOT required to be thread-safe.\n *\n * @param <T> type of message\n */\npublic interface StreamObserver<T> {\n\n    /**\n     * onNext\n     *\n     * @param data to process\n     */\n    void onNext(T data);\n\n    /**\n     * onError\n     *\n     * @param throwable error\n     */\n    void onError(Throwable throwable);\n\n    /**\n     * onCompleted\n     */\n    void onCompleted();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/system/OperatingSystemBeanManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.system;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.MethodUtils;\n\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.OperatingSystemMXBean;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CLASS_NOT_FOUND;\n\n/**\n * OperatingSystemBeanManager related.\n */\npublic class OperatingSystemBeanManager {\n\n    private static final ErrorTypeAwareLogger LOGGER =\n            LoggerFactory.getErrorTypeAwareLogger(OperatingSystemBeanManager.class);\n\n    /**\n     * com.ibm for J9\n     * com.sun for HotSpot\n     */\n    private static final List<String> OPERATING_SYSTEM_BEAN_CLASS_NAMES =\n            Arrays.asList(\"com.sun.management.OperatingSystemMXBean\", \"com.ibm.lang.management.OperatingSystemMXBean\");\n\n    private static final OperatingSystemMXBean OPERATING_SYSTEM_BEAN;\n\n    private static final Class<?> OPERATING_SYSTEM_BEAN_CLASS;\n\n    private static final Method SYSTEM_CPU_USAGE_METHOD;\n\n    private static final Method PROCESS_CPU_USAGE_METHOD;\n\n    static {\n        OPERATING_SYSTEM_BEAN = ManagementFactory.getOperatingSystemMXBean();\n        OPERATING_SYSTEM_BEAN_CLASS = loadOne(OPERATING_SYSTEM_BEAN_CLASS_NAMES);\n        SYSTEM_CPU_USAGE_METHOD = deduceMethod(\"getSystemCpuLoad\");\n        PROCESS_CPU_USAGE_METHOD = deduceMethod(\"getProcessCpuLoad\");\n    }\n\n    private OperatingSystemBeanManager() {}\n\n    public static OperatingSystemMXBean getOperatingSystemBean() {\n        return OPERATING_SYSTEM_BEAN;\n    }\n\n    public static double getSystemCpuUsage() {\n        return MethodUtils.invokeAndReturnDouble(SYSTEM_CPU_USAGE_METHOD, OPERATING_SYSTEM_BEAN);\n    }\n\n    public static double getProcessCpuUsage() {\n        return MethodUtils.invokeAndReturnDouble(PROCESS_CPU_USAGE_METHOD, OPERATING_SYSTEM_BEAN);\n    }\n\n    private static Class<?> loadOne(List<String> classNames) {\n        for (String className : classNames) {\n            try {\n                return Class.forName(className);\n            } catch (ClassNotFoundException e) {\n                LOGGER.warn(\n                        COMMON_CLASS_NOT_FOUND,\n                        \"\",\n                        \"\",\n                        \"[OperatingSystemBeanManager] Failed to load operating system bean class.\",\n                        e);\n            }\n        }\n        return null;\n    }\n\n    private static Method deduceMethod(String name) {\n        if (Objects.isNull(OPERATING_SYSTEM_BEAN_CLASS)) {\n            return null;\n        }\n        try {\n            OPERATING_SYSTEM_BEAN_CLASS.cast(OPERATING_SYSTEM_BEAN);\n            return OPERATING_SYSTEM_BEAN_CLASS.getDeclaredMethod(name);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalRunnable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadlocal;\n\n/**\n * InternalRunnable\n * There is a risk of memory leak when using {@link InternalThreadLocal} without calling\n * {@link InternalThreadLocal#removeAll()}.\n * This design is learning from {@see io.netty.util.concurrent.FastThreadLocalRunnable} which is in Netty.\n */\npublic class InternalRunnable implements Runnable {\n    private final Runnable runnable;\n\n    public InternalRunnable(Runnable runnable) {\n        this.runnable = runnable;\n    }\n\n    /**\n     * After the task execution is completed, it will call {@link InternalThreadLocal#removeAll()} to clear\n     * unnecessary variables in the thread.\n     */\n    @Override\n    public void run() {\n        try {\n            runnable.run();\n        } finally {\n            InternalThreadLocal.removeAll();\n        }\n    }\n\n    /**\n     * Wrap ordinary Runnable into {@link InternalThreadLocal}.\n     */\n    public static Runnable Wrap(Runnable runnable) {\n        return runnable instanceof InternalRunnable ? runnable : new InternalRunnable(runnable);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThread.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadlocal;\n\npublic class InternalThread extends Thread {\n\n    private InternalThreadLocalMap threadLocalMap;\n\n    public InternalThread() {}\n\n    public InternalThread(Runnable target) {\n        super(target);\n    }\n\n    public InternalThread(ThreadGroup group, Runnable target) {\n        super(group, target);\n    }\n\n    public InternalThread(String name) {\n        super(name);\n    }\n\n    public InternalThread(ThreadGroup group, String name) {\n        super(group, name);\n    }\n\n    public InternalThread(Runnable target, String name) {\n        super(target, name);\n    }\n\n    public InternalThread(ThreadGroup group, Runnable target, String name) {\n        super(group, target, name);\n    }\n\n    public InternalThread(ThreadGroup group, Runnable target, String name, long stackSize) {\n        super(group, target, name, stackSize);\n    }\n\n    /**\n     * Returns the internal data structure that keeps the threadLocal variables bound to this thread.\n     * Note that this method is for internal use only, and thus is subject to change at any time.\n     */\n    public final InternalThreadLocalMap threadLocalMap() {\n        return threadLocalMap;\n    }\n\n    /**\n     * Sets the internal data structure that keeps the threadLocal variables bound to this thread.\n     * Note that this method is for internal use only, and thus is subject to change at any time.\n     */\n    public final void setThreadLocalMap(InternalThreadLocalMap threadLocalMap) {\n        this.threadLocalMap = threadLocalMap;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"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, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage org.apache.dubbo.common.threadlocal;\n\nimport java.util.Collections;\nimport java.util.IdentityHashMap;\nimport java.util.Set;\n\n/**\n * InternalThreadLocal\n * A special variant of {@link ThreadLocal} that yields higher access performance when accessed from a\n * {@link InternalThread}.\n * <p></p>\n * Internally, a {@link InternalThread} uses a constant index in an array, instead of using hash code and hash table,\n * to look for a variable.  Although seemingly very subtle, it yields slight performance advantage over using a hash\n * table, and it is useful when accessed frequently.\n * <p></p>\n * This design is learning from {@see io.netty.util.concurrent.FastThreadLocal} which is in Netty.\n */\npublic class InternalThreadLocal<V> extends ThreadLocal<V> {\n\n    private static final int VARIABLES_TO_REMOVE_INDEX = InternalThreadLocalMap.nextVariableIndex();\n\n    private final int index;\n\n    public InternalThreadLocal() {\n        index = InternalThreadLocalMap.nextVariableIndex();\n    }\n\n    /**\n     * Removes all {@link InternalThreadLocal} variables bound to the current thread.  This operation is useful when you\n     * are in a container environment, and you don't want to leave the thread local variables in the threads you do not\n     * manage.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static void removeAll() {\n        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();\n        if (threadLocalMap == null) {\n            return;\n        }\n\n        try {\n            Object v = threadLocalMap.indexedVariable(VARIABLES_TO_REMOVE_INDEX);\n            if (v != null && v != InternalThreadLocalMap.UNSET) {\n                Set<InternalThreadLocal<?>> variablesToRemove = (Set<InternalThreadLocal<?>>) v;\n                InternalThreadLocal<?>[] variablesToRemoveArray =\n                        variablesToRemove.toArray(new InternalThreadLocal[0]);\n                for (InternalThreadLocal<?> tlv : variablesToRemoveArray) {\n                    tlv.remove(threadLocalMap);\n                }\n            }\n        } finally {\n            InternalThreadLocalMap.remove();\n        }\n    }\n\n    /**\n     * Returns the number of thread local variables bound to the current thread.\n     */\n    public static int size() {\n        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();\n        if (threadLocalMap == null) {\n            return 0;\n        } else {\n            return threadLocalMap.size();\n        }\n    }\n\n    public static void destroy() {\n        InternalThreadLocalMap.destroy();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, InternalThreadLocal<?> variable) {\n        Object v = threadLocalMap.indexedVariable(VARIABLES_TO_REMOVE_INDEX);\n        Set<InternalThreadLocal<?>> variablesToRemove;\n        if (v == InternalThreadLocalMap.UNSET || v == null) {\n            variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<InternalThreadLocal<?>, Boolean>());\n            threadLocalMap.setIndexedVariable(VARIABLES_TO_REMOVE_INDEX, variablesToRemove);\n        } else {\n            variablesToRemove = (Set<InternalThreadLocal<?>>) v;\n        }\n\n        variablesToRemove.add(variable);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static void removeFromVariablesToRemove(InternalThreadLocalMap threadLocalMap, InternalThreadLocal<?> variable) {\n\n        Object v = threadLocalMap.indexedVariable(VARIABLES_TO_REMOVE_INDEX);\n\n        if (v == InternalThreadLocalMap.UNSET || v == null) {\n            return;\n        }\n\n        Set<InternalThreadLocal<?>> variablesToRemove = (Set<InternalThreadLocal<?>>) v;\n        variablesToRemove.remove(variable);\n    }\n\n    /**\n     * Returns the current value for the current thread\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public final V get() {\n        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();\n        Object v = threadLocalMap.indexedVariable(index);\n        if (v != InternalThreadLocalMap.UNSET) {\n            return (V) v;\n        }\n\n        return initialize(threadLocalMap);\n    }\n\n    public final V getWithoutInitialize() {\n        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();\n        Object v = threadLocalMap.indexedVariable(index);\n        if (v != InternalThreadLocalMap.UNSET) {\n            return (V) v;\n        }\n\n        return null;\n    }\n\n    private V initialize(InternalThreadLocalMap threadLocalMap) {\n        V v = null;\n        try {\n            v = initialValue();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        threadLocalMap.setIndexedVariable(index, v);\n        addToVariablesToRemove(threadLocalMap, this);\n        return v;\n    }\n\n    /**\n     * Sets the value for the current thread.\n     */\n    @Override\n    public final void set(V value) {\n        if (value == null || value == InternalThreadLocalMap.UNSET) {\n            remove();\n        } else {\n            InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();\n            if (threadLocalMap.setIndexedVariable(index, value)) {\n                addToVariablesToRemove(threadLocalMap, this);\n            }\n        }\n    }\n\n    /**\n     * Sets the value to uninitialized; a proceeding call to get() will trigger a call to initialValue().\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public final void remove() {\n        remove(InternalThreadLocalMap.getIfSet());\n    }\n\n    /**\n     * Sets the value to uninitialized for the specified thread local map;\n     * a proceeding call to get() will trigger a call to initialValue().\n     * The specified thread local map must be for the current thread.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public final void remove(InternalThreadLocalMap threadLocalMap) {\n        if (threadLocalMap == null) {\n            return;\n        }\n\n        Object v = threadLocalMap.removeIndexedVariable(index);\n        removeFromVariablesToRemove(threadLocalMap, this);\n\n        if (v != InternalThreadLocalMap.UNSET) {\n            try {\n                onRemoval((V) v);\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    /**\n     * Returns the initial value for this thread-local variable.\n     */\n    @Override\n    protected V initialValue() {\n        return null;\n    }\n\n    /**\n     * Invoked when this thread local variable is removed by {@link #remove()}.\n     */\n    protected void onRemoval(@SuppressWarnings(\"unused\") V value) throws Exception {\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocalMap.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"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, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage org.apache.dubbo.common.threadlocal;\n\nimport java.util.Arrays;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * The internal data structure that stores the threadLocal variables for Netty and all {@link InternalThread}s.\n * Note that this class is for internal use only. Use {@link InternalThread}\n * unless you know what you are doing.\n */\npublic final class InternalThreadLocalMap {\n\n    private Object[] indexedVariables;\n\n    private static ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = new ThreadLocal<>();\n\n    private static final AtomicInteger NEXT_INDEX = new AtomicInteger();\n\n    static final Object UNSET = new Object();\n\n    /**\n     * should not be modified after initialization,\n     * do not set as final due to unit test\n     */\n    // Reference: https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/tip/src/share/classes/java/util/ArrayList.java#l229\n    static int ARRAY_LIST_CAPACITY_MAX_SIZE = Integer.MAX_VALUE - 8;\n\n    private static final int ARRAY_LIST_CAPACITY_EXPAND_THRESHOLD = 1 << 30;\n\n    public static InternalThreadLocalMap getIfSet() {\n        Thread thread = Thread.currentThread();\n        if (thread instanceof InternalThread) {\n            return ((InternalThread) thread).threadLocalMap();\n        }\n        return slowThreadLocalMap.get();\n    }\n\n    public static InternalThreadLocalMap get() {\n        Thread thread = Thread.currentThread();\n        if (thread instanceof InternalThread) {\n            return fastGet((InternalThread) thread);\n        }\n        return slowGet();\n    }\n\n    public static InternalThreadLocalMap getAndRemove() {\n        try {\n            Thread thread = Thread.currentThread();\n            if (thread instanceof InternalThread) {\n                return ((InternalThread) thread).threadLocalMap();\n            }\n            return slowThreadLocalMap.get();\n        } finally {\n            remove();\n        }\n    }\n\n    public static void set(InternalThreadLocalMap internalThreadLocalMap) {\n        Thread thread = Thread.currentThread();\n        if (thread instanceof InternalThread) {\n            ((InternalThread) thread).setThreadLocalMap(internalThreadLocalMap);\n        }\n        slowThreadLocalMap.set(internalThreadLocalMap);\n    }\n\n    public static void remove() {\n        Thread thread = Thread.currentThread();\n        if (thread instanceof InternalThread) {\n            ((InternalThread) thread).setThreadLocalMap(null);\n        } else {\n            slowThreadLocalMap.remove();\n        }\n    }\n\n    public static void destroy() {\n        slowThreadLocalMap = null;\n    }\n\n    public static int nextVariableIndex() {\n        int index = NEXT_INDEX.getAndIncrement();\n        if (index >= ARRAY_LIST_CAPACITY_MAX_SIZE || index < 0) {\n            NEXT_INDEX.set(ARRAY_LIST_CAPACITY_MAX_SIZE);\n            throw new IllegalStateException(\"Too many thread-local indexed variables\");\n        }\n        return index;\n    }\n\n    public static int lastVariableIndex() {\n        return NEXT_INDEX.get() - 1;\n    }\n\n    private InternalThreadLocalMap() {\n        indexedVariables = newIndexedVariableTable();\n    }\n\n    public Object indexedVariable(int index) {\n        Object[] lookup = indexedVariables;\n        return index < lookup.length ? lookup[index] : UNSET;\n    }\n\n    /**\n     * @return {@code true} if and only if a new thread-local variable has been created\n     */\n    public boolean setIndexedVariable(int index, Object value) {\n        Object[] lookup = indexedVariables;\n        if (index < lookup.length) {\n            Object oldValue = lookup[index];\n            lookup[index] = value;\n            return oldValue == UNSET;\n        } else {\n            expandIndexedVariableTableAndSet(index, value);\n            return true;\n        }\n    }\n\n    public Object removeIndexedVariable(int index) {\n        Object[] lookup = indexedVariables;\n        if (index < lookup.length) {\n            Object v = lookup[index];\n            lookup[index] = UNSET;\n            return v;\n        } else {\n            return UNSET;\n        }\n    }\n\n    public int size() {\n        int count = 0;\n        for (Object o : indexedVariables) {\n            if (o != UNSET) {\n                ++count;\n            }\n        }\n\n        //the fist element in `indexedVariables` is a set to keep all the InternalThreadLocal to remove\n        //look at method `addToVariablesToRemove`\n        return count - 1;\n    }\n\n    private static Object[] newIndexedVariableTable() {\n        int variableIndex = NEXT_INDEX.get();\n        int newCapacity = variableIndex < 32 ? 32 : newCapacity(variableIndex);\n        Object[] array = new Object[newCapacity];\n        Arrays.fill(array, UNSET);\n        return array;\n    }\n\n    private static int newCapacity(int index) {\n        int newCapacity;\n        if (index < ARRAY_LIST_CAPACITY_EXPAND_THRESHOLD) {\n            newCapacity = index;\n            newCapacity |= newCapacity >>>  1;\n            newCapacity |= newCapacity >>>  2;\n            newCapacity |= newCapacity >>>  4;\n            newCapacity |= newCapacity >>>  8;\n            newCapacity |= newCapacity >>> 16;\n            newCapacity ++;\n        } else {\n            newCapacity = ARRAY_LIST_CAPACITY_MAX_SIZE;\n        }\n        return newCapacity;\n    }\n\n    private static InternalThreadLocalMap fastGet(InternalThread thread) {\n        InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();\n        if (threadLocalMap == null) {\n            thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());\n        }\n        return threadLocalMap;\n    }\n\n    private static InternalThreadLocalMap slowGet() {\n        ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = InternalThreadLocalMap.slowThreadLocalMap;\n        InternalThreadLocalMap ret = slowThreadLocalMap.get();\n        if (ret == null) {\n            ret = new InternalThreadLocalMap();\n            slowThreadLocalMap.set(ret);\n        }\n        return ret;\n    }\n\n    private void expandIndexedVariableTableAndSet(int index, Object value) {\n        Object[] oldArray = indexedVariables;\n        final int oldCapacity = oldArray.length;\n        int newCapacity = newCapacity(index);\n        Object[] newArray = Arrays.copyOf(oldArray, newCapacity);\n        Arrays.fill(newArray, oldCapacity, newArray.length, UNSET);\n        newArray[index] = value;\n        indexedVariables = newArray;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/NamedInternalThreadFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadlocal;\n\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\n\n/**\n * NamedInternalThreadFactory\n * This is a threadFactory which produce {@link InternalThread}\n */\npublic class NamedInternalThreadFactory extends NamedThreadFactory {\n\n    public NamedInternalThreadFactory() {\n        super();\n    }\n\n    public NamedInternalThreadFactory(String prefix) {\n        super(prefix, false);\n    }\n\n    public NamedInternalThreadFactory(String prefix, boolean daemon) {\n        super(prefix, daemon);\n    }\n\n    @Override\n    public Thread newThread(Runnable runnable) {\n        String name = mPrefix + mThreadNum.getAndIncrement();\n        InternalThread ret = new InternalThread(InternalRunnable.Wrap(runnable), name);\n        ret.setDaemon(mDaemon);\n        return ret;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/MemoryLimitCalculator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool;\n\nimport org.apache.dubbo.common.resource.GlobalResourcesRepository;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * {@link java.lang.Runtime#freeMemory()} technology is used to calculate the\n * memory limit by using the percentage of the current maximum available memory,\n * which can be used with {@link MemoryLimiter}.\n *\n * @see MemoryLimiter\n * @see <a href=\"https://github.com/apache/incubator-shenyu/blob/master/shenyu-common/src/main/java/org/apache/shenyu/common/concurrent/MemoryLimitCalculator.java\">MemoryLimitCalculator</a>\n */\npublic class MemoryLimitCalculator {\n\n    private static volatile long maxAvailable;\n\n    private static final AtomicBoolean refreshStarted = new AtomicBoolean(false);\n\n    private static void refresh() {\n        maxAvailable = Runtime.getRuntime().freeMemory();\n    }\n\n    private static void checkAndScheduleRefresh() {\n        if (!refreshStarted.get()) {\n            // immediately refresh when first call to prevent maxAvailable from being 0\n            // to ensure that being refreshed before refreshStarted being set as true\n            // notice: refresh may be called for more than once because there is no lock\n            refresh();\n            if (refreshStarted.compareAndSet(false, true)) {\n                ScheduledExecutorService scheduledExecutorService =\n                        Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory(\"Dubbo-Memory-Calculator\"));\n                // check every 50 ms to improve performance\n                scheduledExecutorService.scheduleWithFixedDelay(\n                        MemoryLimitCalculator::refresh, 50, 50, TimeUnit.MILLISECONDS);\n                GlobalResourcesRepository.registerGlobalDisposable(() -> {\n                    refreshStarted.set(false);\n                    scheduledExecutorService.shutdown();\n                });\n            }\n        }\n    }\n\n    /**\n     * Get the maximum available memory of the current JVM.\n     *\n     * @return maximum available memory\n     */\n    public static long maxAvailable() {\n        checkAndScheduleRefresh();\n        return maxAvailable;\n    }\n\n    /**\n     * Take the current JVM's maximum available memory\n     * as a percentage of the result as the limit.\n     *\n     * @param percentage percentage\n     * @return available memory\n     */\n    public static long calculate(final float percentage) {\n        if (percentage <= 0 || percentage > 1) {\n            throw new IllegalArgumentException();\n        }\n        checkAndScheduleRefresh();\n        return (long) (maxAvailable() * percentage);\n    }\n\n    /**\n     * By default, it takes 80% of the maximum available memory of the current JVM.\n     *\n     * @return available memory\n     */\n    public static long defaultLimit() {\n        checkAndScheduleRefresh();\n        return (long) (maxAvailable() * 0.8);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/MemoryLimitedLinkedBlockingQueue.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool;\n\nimport java.lang.instrument.Instrumentation;\nimport java.util.Collection;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Can completely solve the OOM problem caused by {@link java.util.concurrent.LinkedBlockingQueue}.\n */\npublic class MemoryLimitedLinkedBlockingQueue<E> extends LinkedBlockingQueue<E> {\n\n    private static final long serialVersionUID = 1374792064759926198L;\n\n    private final MemoryLimiter memoryLimiter;\n\n    public MemoryLimitedLinkedBlockingQueue(Instrumentation inst) {\n        this(Integer.MAX_VALUE, inst);\n    }\n\n    public MemoryLimitedLinkedBlockingQueue(long memoryLimit, Instrumentation inst) {\n        super(Integer.MAX_VALUE);\n        this.memoryLimiter = new MemoryLimiter(memoryLimit, inst);\n    }\n\n    public MemoryLimitedLinkedBlockingQueue(Collection<? extends E> c, long memoryLimit, Instrumentation inst) {\n        super(c);\n        this.memoryLimiter = new MemoryLimiter(memoryLimit, inst);\n    }\n\n    public void setMemoryLimit(long memoryLimit) {\n        memoryLimiter.setMemoryLimit(memoryLimit);\n    }\n\n    public long getMemoryLimit() {\n        return memoryLimiter.getMemoryLimit();\n    }\n\n    public long getCurrentMemory() {\n        return memoryLimiter.getCurrentMemory();\n    }\n\n    public long getCurrentRemainMemory() {\n        return memoryLimiter.getCurrentRemainMemory();\n    }\n\n    @Override\n    public void put(E e) throws InterruptedException {\n        memoryLimiter.acquireInterruptibly(e);\n        super.put(e);\n    }\n\n    @Override\n    public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {\n        return memoryLimiter.acquire(e, timeout, unit) && super.offer(e, timeout, unit);\n    }\n\n    @Override\n    public boolean offer(E e) {\n        return memoryLimiter.acquire(e) && super.offer(e);\n    }\n\n    @Override\n    public E take() throws InterruptedException {\n        final E e = super.take();\n        memoryLimiter.releaseInterruptibly(e);\n        return e;\n    }\n\n    @Override\n    public E poll(long timeout, TimeUnit unit) throws InterruptedException {\n        final E e = super.poll(timeout, unit);\n        memoryLimiter.releaseInterruptibly(e, timeout, unit);\n        return e;\n    }\n\n    @Override\n    public E poll() {\n        final E e = super.poll();\n        memoryLimiter.release(e);\n        return e;\n    }\n\n    @Override\n    public boolean remove(Object o) {\n        final boolean success = super.remove(o);\n        if (success) {\n            memoryLimiter.release(o);\n        }\n        return success;\n    }\n\n    @Override\n    public void clear() {\n        super.clear();\n        memoryLimiter.clear();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/MemoryLimiter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool;\n\nimport java.lang.instrument.Instrumentation;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.LongAdder;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * memory limiter.\n */\npublic class MemoryLimiter {\n\n    private final Instrumentation inst;\n\n    private long memoryLimit;\n\n    private final LongAdder memory = new LongAdder();\n\n    private final ReentrantLock acquireLock = new ReentrantLock();\n\n    private final Condition notLimited = acquireLock.newCondition();\n\n    private final ReentrantLock releaseLock = new ReentrantLock();\n\n    private final Condition notEmpty = releaseLock.newCondition();\n\n    public MemoryLimiter(Instrumentation inst) {\n        this(Integer.MAX_VALUE, inst);\n    }\n\n    public MemoryLimiter(long memoryLimit, Instrumentation inst) {\n        if (memoryLimit <= 0) {\n            throw new IllegalArgumentException();\n        }\n        this.memoryLimit = memoryLimit;\n        this.inst = inst;\n    }\n\n    public void setMemoryLimit(long memoryLimit) {\n        if (memoryLimit <= 0) {\n            throw new IllegalArgumentException();\n        }\n        this.memoryLimit = memoryLimit;\n    }\n\n    public long getMemoryLimit() {\n        return memoryLimit;\n    }\n\n    public long getCurrentMemory() {\n        return memory.sum();\n    }\n\n    public long getCurrentRemainMemory() {\n        return getMemoryLimit() - getCurrentMemory();\n    }\n\n    private void signalNotEmpty() {\n        releaseLock.lock();\n        try {\n            notEmpty.signal();\n        } finally {\n            releaseLock.unlock();\n        }\n    }\n\n    private void signalNotLimited() {\n        acquireLock.lock();\n        try {\n            notLimited.signal();\n        } finally {\n            acquireLock.unlock();\n        }\n    }\n\n    /**\n     * Locks to prevent both acquires and releases.\n     */\n    private void fullyLock() {\n        acquireLock.lock();\n        releaseLock.lock();\n    }\n\n    /**\n     * Unlocks to allow both acquires and releases.\n     */\n    private void fullyUnlock() {\n        releaseLock.unlock();\n        acquireLock.unlock();\n    }\n\n    public boolean acquire(Object e) {\n        if (e == null) {\n            throw new NullPointerException();\n        }\n        if (memory.sum() >= memoryLimit) {\n            return false;\n        }\n        acquireLock.lock();\n        try {\n            final long sum = memory.sum();\n            final long objectSize = inst.getObjectSize(e);\n            if (sum + objectSize >= memoryLimit) {\n                return false;\n            }\n            memory.add(objectSize);\n            // see https://github.com/apache/incubator-shenyu/pull/3356\n            if (memory.sum() < memoryLimit) {\n                notLimited.signal();\n            }\n        } finally {\n            acquireLock.unlock();\n        }\n        if (memory.sum() > 0) {\n            signalNotEmpty();\n        }\n        return true;\n    }\n\n    public void acquireInterruptibly(Object e) throws InterruptedException {\n        if (e == null) {\n            throw new NullPointerException();\n        }\n        acquireLock.lockInterruptibly();\n        try {\n            final long objectSize = inst.getObjectSize(e);\n            // see https://github.com/apache/incubator-shenyu/pull/3335\n            while (memory.sum() + objectSize >= memoryLimit) {\n                notLimited.await();\n            }\n            memory.add(objectSize);\n            if (memory.sum() < memoryLimit) {\n                notLimited.signal();\n            }\n        } finally {\n            acquireLock.unlock();\n        }\n        if (memory.sum() > 0) {\n            signalNotEmpty();\n        }\n    }\n\n    public boolean acquire(Object e, long timeout, TimeUnit unit) throws InterruptedException {\n        if (e == null) {\n            throw new NullPointerException();\n        }\n        long nanos = unit.toNanos(timeout);\n        acquireLock.lockInterruptibly();\n        try {\n            final long objectSize = inst.getObjectSize(e);\n            while (memory.sum() + objectSize >= memoryLimit) {\n                if (nanos <= 0) {\n                    return false;\n                }\n                nanos = notLimited.awaitNanos(nanos);\n            }\n            memory.add(objectSize);\n            if (memory.sum() < memoryLimit) {\n                notLimited.signal();\n            }\n        } finally {\n            acquireLock.unlock();\n        }\n        if (memory.sum() > 0) {\n            signalNotEmpty();\n        }\n        return true;\n    }\n\n    public void release(Object e) {\n        if (null == e) {\n            return;\n        }\n        if (memory.sum() == 0) {\n            return;\n        }\n        releaseLock.lock();\n        try {\n            final long objectSize = inst.getObjectSize(e);\n            if (memory.sum() > 0) {\n                memory.add(-objectSize);\n                if (memory.sum() > 0) {\n                    notEmpty.signal();\n                }\n            }\n        } finally {\n            releaseLock.unlock();\n        }\n        if (memory.sum() < memoryLimit) {\n            signalNotLimited();\n        }\n    }\n\n    public void releaseInterruptibly(Object e) throws InterruptedException {\n        if (null == e) {\n            return;\n        }\n        releaseLock.lockInterruptibly();\n        try {\n            final long objectSize = inst.getObjectSize(e);\n            while (memory.sum() == 0) {\n                notEmpty.await();\n            }\n            memory.add(-objectSize);\n            if (memory.sum() > 0) {\n                notEmpty.signal();\n            }\n        } finally {\n            releaseLock.unlock();\n        }\n        if (memory.sum() < memoryLimit) {\n            signalNotLimited();\n        }\n    }\n\n    public void releaseInterruptibly(Object e, long timeout, TimeUnit unit) throws InterruptedException {\n        if (null == e) {\n            return;\n        }\n        long nanos = unit.toNanos(timeout);\n        releaseLock.lockInterruptibly();\n        try {\n            final long objectSize = inst.getObjectSize(e);\n            while (memory.sum() == 0) {\n                if (nanos <= 0) {\n                    return;\n                }\n                nanos = notEmpty.awaitNanos(nanos);\n            }\n            memory.add(-objectSize);\n            if (memory.sum() > 0) {\n                notEmpty.signal();\n            }\n        } finally {\n            releaseLock.unlock();\n        }\n        if (memory.sum() < memoryLimit) {\n            signalNotLimited();\n        }\n    }\n\n    public void clear() {\n        fullyLock();\n        try {\n            if (memory.sumThenReset() < memoryLimit) {\n                notLimited.signal();\n            }\n        } finally {\n            fullyUnlock();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/MemorySafeLinkedBlockingQueue.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool;\n\nimport org.apache.dubbo.common.concurrent.DiscardPolicy;\nimport org.apache.dubbo.common.concurrent.Rejector;\n\nimport java.util.Collection;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Can completely solve the OOM problem caused by {@link java.util.concurrent.LinkedBlockingQueue},\n * does not depend on {@link java.lang.instrument.Instrumentation} and is easier to use than\n * {@link MemoryLimitedLinkedBlockingQueue}.\n *\n * @see <a href=\"https://github.com/apache/incubator-shenyu/blob/master/shenyu-common/src/main/java/org/apache/shenyu/common/concurrent/MemorySafeLinkedBlockingQueue.java\">MemorySafeLinkedBlockingQueue</a>\n */\npublic class MemorySafeLinkedBlockingQueue<E> extends LinkedBlockingQueue<E> {\n\n    private static final long serialVersionUID = 8032578371739960142L;\n\n    public static int THE_256_MB = 256 * 1024 * 1024;\n\n    private long maxFreeMemory;\n\n    private Rejector<E> rejector;\n\n    public MemorySafeLinkedBlockingQueue() {\n        this(THE_256_MB);\n    }\n\n    public MemorySafeLinkedBlockingQueue(final long maxFreeMemory) {\n        super(Integer.MAX_VALUE);\n        this.maxFreeMemory = maxFreeMemory;\n        // default as DiscardPolicy to ensure compatibility with the old version\n        this.rejector = new DiscardPolicy<>();\n    }\n\n    public MemorySafeLinkedBlockingQueue(final Collection<? extends E> c, final int maxFreeMemory) {\n        super(c);\n        this.maxFreeMemory = maxFreeMemory;\n        // default as DiscardPolicy to ensure compatibility with the old version\n        this.rejector = new DiscardPolicy<>();\n    }\n\n    /**\n     * set the max free memory.\n     *\n     * @param maxFreeMemory the max free memory\n     */\n    public void setMaxFreeMemory(final int maxFreeMemory) {\n        this.maxFreeMemory = maxFreeMemory;\n    }\n\n    /**\n     * get the max free memory.\n     *\n     * @return the max free memory limit\n     */\n    public long getMaxFreeMemory() {\n        return maxFreeMemory;\n    }\n\n    /**\n     * set the rejector.\n     *\n     * @param rejector the rejector\n     */\n    public void setRejector(final Rejector<E> rejector) {\n        this.rejector = rejector;\n    }\n\n    /**\n     * determine if there is any remaining free memory.\n     *\n     * @return true if has free memory\n     */\n    public boolean hasRemainedMemory() {\n        return MemoryLimitCalculator.maxAvailable() > maxFreeMemory;\n    }\n\n    @Override\n    public void put(final E e) throws InterruptedException {\n        if (hasRemainedMemory()) {\n            super.put(e);\n        } else {\n            rejector.reject(e, this);\n        }\n    }\n\n    @Override\n    public boolean offer(final E e, final long timeout, final TimeUnit unit) throws InterruptedException {\n        if (!hasRemainedMemory()) {\n            rejector.reject(e, this);\n            return false;\n        }\n        return super.offer(e, timeout, unit);\n    }\n\n    @Override\n    public boolean offer(final E e) {\n        if (!hasRemainedMemory()) {\n            rejector.reject(e, this);\n            return false;\n        }\n        return super.offer(e);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/ThreadPool.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.concurrent.Executor;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;\n\n// TODO which scope for ThreadPool? APPLICATION or FRAMEWORK\n@SPI(value = \"fixed\", scope = ExtensionScope.FRAMEWORK)\npublic interface ThreadPool {\n\n    /**\n     * Thread pool\n     *\n     * @param url URL contains thread parameter\n     * @return thread pool\n     */\n    @Adaptive({THREADPOOL_KEY})\n    Executor getExecutor(URL url);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/ThreadlessExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Queue;\nimport java.util.concurrent.AbstractExecutorService;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.concurrent.locks.LockSupport;\n\n/**\n * The most important difference between this Executor and other normal Executor is that this one doesn't manage\n * any thread.\n * <p>\n * Tasks submitted to this executor through {@link #execute(Runnable)} will not get scheduled to a specific thread, though normal executors always do the schedule.\n * Those tasks are stored in a blocking queue and will only be executed when a thread calls {@link #waitAndDrain()}, the thread executing the task\n * is exactly the same as the one calling waitAndDrain.\n */\npublic class ThreadlessExecutor extends AbstractExecutorService {\n    private static final Logger logger = LoggerFactory.getLogger(ThreadlessExecutor.class.getName());\n\n    private static final Object SHUTDOWN = new Object();\n\n    private final Queue<Runnable> queue = new ConcurrentLinkedQueue<>();\n\n    /**\n     * Wait thread. It must be visible to other threads and does not need to be thread-safe\n     */\n    private final AtomicReference<Object> waiter = new AtomicReference<>();\n\n    /**\n     * Waits until there is a task, executes the task and all queued tasks (if there're any). The task is either a normal\n     * response or a timeout response.\n     */\n    public void waitAndDrain(long deadline) throws InterruptedException {\n        throwIfInterrupted();\n        Runnable runnable = queue.poll();\n        if (runnable == null) {\n            if (waiter.compareAndSet(null, Thread.currentThread())) {\n                try {\n                    while ((runnable = queue.poll()) == null && waiter.get() == Thread.currentThread()) {\n                        long restTime = deadline - System.nanoTime();\n                        if (restTime <= 0) {\n                            return;\n                        }\n                        LockSupport.parkNanos(this, restTime);\n                        throwIfInterrupted();\n                    }\n                } finally {\n                    waiter.compareAndSet(Thread.currentThread(), null);\n                }\n            }\n        }\n        do {\n            if (runnable != null) {\n                runnable.run();\n            }\n        } while ((runnable = queue.poll()) != null);\n    }\n\n    private static void throwIfInterrupted() throws InterruptedException {\n        if (Thread.interrupted()) {\n            throw new InterruptedException();\n        }\n    }\n\n    /**\n     * If the calling thread is still waiting for a callback task, add the task into the blocking queue to wait for schedule.\n     * Otherwise, submit to shared callback executor directly.\n     *\n     * @param runnable\n     */\n    @Override\n    public void execute(Runnable runnable) {\n        RunnableWrapper run = new RunnableWrapper(runnable);\n        queue.add(run);\n        Object waiter = this.waiter.get();\n        if (waiter != SHUTDOWN) {\n            LockSupport.unpark((Thread) waiter);\n        } else if (queue.remove(run)) {\n            throw new RejectedExecutionException();\n        }\n    }\n\n    /**\n     * The following methods are still not supported\n     */\n    @Override\n    public void shutdown() {\n        shutdownNow();\n    }\n\n    @Override\n    public List<Runnable> shutdownNow() {\n        if (waiter.get() != SHUTDOWN) {\n            LockSupport.unpark((Thread) waiter.get());\n        }\n        waiter.set(SHUTDOWN);\n        Runnable runnable;\n        while ((runnable = queue.poll()) != null) {\n            runnable.run();\n        }\n        return Collections.emptyList();\n    }\n\n    @Override\n    public boolean isShutdown() {\n        return waiter.get() == SHUTDOWN;\n    }\n\n    @Override\n    public boolean isTerminated() {\n        return isShutdown();\n    }\n\n    @Override\n    public boolean awaitTermination(long timeout, TimeUnit unit) {\n        return false;\n    }\n\n    private static class RunnableWrapper implements Runnable {\n        private final Runnable runnable;\n\n        public RunnableWrapper(Runnable runnable) {\n            this.runnable = runnable;\n        }\n\n        @Override\n        public void run() {\n            try {\n                runnable.run();\n            } catch (Throwable t) {\n                logger.info(t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/concurrent/ScheduledCompletableFuture.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.concurrent;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Supplier;\n\npublic class ScheduledCompletableFuture {\n\n    public static <T> CompletableFuture<T> schedule(\n            ScheduledExecutorService executor, Supplier<T> task, long delay, TimeUnit unit) {\n        CompletableFuture<T> completableFuture = new CompletableFuture<>();\n        executor.schedule(\n                () -> {\n                    try {\n                        return completableFuture.complete(task.get());\n                    } catch (Throwable t) {\n                        return completableFuture.completeExceptionally(t);\n                    }\n                },\n                delay,\n                unit);\n        return completableFuture;\n    }\n\n    public static <T> CompletableFuture<T> submit(ScheduledExecutorService executor, Supplier<T> task) {\n        CompletableFuture<T> completableFuture = new CompletableFuture<>();\n        executor.submit(() -> {\n            try {\n                return completableFuture.complete(task.get());\n            } catch (Throwable t) {\n                return completableFuture.completeExceptionally(t);\n            }\n        });\n        return completableFuture;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/event/ThreadPoolExhaustedEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.event;\n\n/**\n * An Event when the Dubbo thread pool is exhausted.\n */\npublic class ThreadPoolExhaustedEvent {\n\n    final String msg;\n\n    public ThreadPoolExhaustedEvent(String msg) {\n        this.msg = msg;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/event/ThreadPoolExhaustedListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.event;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface ThreadPoolExhaustedListener {\n\n    /**\n     * Notify when the thread pool is exhausted.\n     * {@link org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport}\n     */\n    void onEvent(ThreadPoolExhaustedEvent event);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/DefaultExecutorRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.manager;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionAccessor;\nimport org.apache.dubbo.common.extension.ExtensionAccessorAware;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.store.DataStore;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ExecutorUtil;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.rpc.executor.DefaultExecutorSupport;\nimport org.apache.dubbo.rpc.executor.ExecutorSupport;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_EXPORT_THREAD_NUM;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_REFER_THREAD_NUM;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_SERVICE_COMPONENT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_ERROR_USE_THREAD_POOL;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_EXECUTORS_NO_FOUND;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN;\n\n/**\n * Consider implementing {@code Lifecycle} to enable executors shutdown when the process stops.\n */\npublic class DefaultExecutorRepository implements ExecutorRepository, ExtensionAccessorAware {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DefaultExecutorRepository.class);\n\n    private static final String MAX_KEY = String.valueOf(Integer.MAX_VALUE);\n\n    private volatile ScheduledExecutorService serviceExportExecutor;\n\n    private volatile ExecutorService serviceReferExecutor;\n\n    private final ConcurrentMap<String, ConcurrentMap<String, ExecutorService>> data = new ConcurrentHashMap<>();\n\n    private final Object LOCK = new Object();\n    private ExtensionAccessor extensionAccessor;\n\n    private final ApplicationModel applicationModel;\n    private final FrameworkExecutorRepository frameworkExecutorRepository;\n    private ExecutorSupport executorSupport;\n\n    private final DataStore dataStore;\n\n    public DefaultExecutorRepository(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        this.frameworkExecutorRepository =\n                applicationModel.getFrameworkModel().getBeanFactory().getBean(FrameworkExecutorRepository.class);\n        this.dataStore = applicationModel.getExtensionLoader(DataStore.class).getDefaultExtension();\n    }\n\n    /**\n     * Get called when the server or client instance initiating.\n     *\n     * @param url\n     * @return\n     */\n    @Override\n    public synchronized ExecutorService createExecutorIfAbsent(URL url) {\n        String executorKey = getExecutorKey(url);\n        ConcurrentMap<String, ExecutorService> executors =\n                ConcurrentHashMapUtils.computeIfAbsent(data, executorKey, k -> new ConcurrentHashMap<>());\n\n        String executorCacheKey = getExecutorSecondKey(url);\n\n        url = setThreadNameIfAbsent(url, executorCacheKey);\n\n        URL finalUrl = url;\n        ExecutorService executor =\n                ConcurrentHashMapUtils.computeIfAbsent(executors, executorCacheKey, k -> createExecutor(finalUrl));\n        // If executor has been shut down, create a new one\n        if (executor.isShutdown() || executor.isTerminated()) {\n            executors.remove(executorCacheKey);\n            executor = createExecutor(url);\n            executors.put(executorCacheKey, executor);\n        }\n        dataStore.put(executorKey, executorCacheKey, executor);\n        return executor;\n    }\n\n    protected URL setThreadNameIfAbsent(URL url, String executorCacheKey) {\n        if (url.getParameter(THREAD_NAME_KEY) == null) {\n            String protocol = url.getProtocol();\n            if (StringUtils.isEmpty(protocol)) {\n                protocol = DEFAULT_PROTOCOL;\n            }\n            url = url.putAttribute(THREAD_NAME_KEY, protocol + \"-protocol-\" + executorCacheKey);\n        }\n        return url;\n    }\n\n    private String getExecutorSecondKey(URL url) {\n        if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {\n            return getConsumerKey(url);\n        } else {\n            return getProviderKey(url);\n        }\n    }\n\n    private String getExecutorSecondKey(ServiceModel serviceModel, URL url) {\n        if (serviceModel instanceof ConsumerModel) {\n            return getConsumerKey(serviceModel);\n        } else {\n            return getProviderKey((ProviderModel) serviceModel, url);\n        }\n    }\n\n    private String getConsumerKey(URL url) {\n        // Consumer's executor is sharing globally, key=Integer.MAX_VALUE\n        return String.valueOf(Integer.MAX_VALUE);\n    }\n\n    private String getConsumerKey(ServiceModel serviceModel) {\n        // Consumer's executor is sharing globally, key=Integer.MAX_VALUE\n        return MAX_KEY;\n    }\n\n    protected String getProviderKey(URL url) {\n        // Provider's executor is sharing by protocol.\n        return String.valueOf(url.getPort());\n    }\n\n    protected String getProviderKey(ProviderModel providerModel, URL url) {\n        // Provider's executor is sharing by protocol.\n        return String.valueOf(url.getPort());\n    }\n\n    /**\n     * Return the executor key based on the type (internal or biz) of the current service.\n     *\n     * @param url\n     * @return\n     */\n    private String getExecutorKey(URL url) {\n        if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {\n            return CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY;\n        }\n        return EXECUTOR_SERVICE_COMPONENT_KEY;\n    }\n\n    private String getExecutorKey(ServiceModel serviceModel) {\n        if (serviceModel instanceof ProviderModel) {\n            return EXECUTOR_SERVICE_COMPONENT_KEY;\n        } else {\n            return CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY;\n        }\n    }\n\n    protected ExecutorService createExecutor(URL url) {\n        return (ExecutorService) extensionAccessor\n                .getExtensionLoader(ThreadPool.class)\n                .getAdaptiveExtension()\n                .getExecutor(url);\n    }\n\n    @Override\n    public ExecutorService getExecutor(URL url) {\n        Map<String, ExecutorService> executors = data.get(getExecutorKey(url));\n\n        /*\n         * It's guaranteed that this method is called after {@link #createExecutorIfAbsent(URL)}, so data should already\n         * have Executor instances generated and stored.\n         */\n        if (executors == null) {\n            logger.warn(\n                    COMMON_EXECUTORS_NO_FOUND,\n                    \"\",\n                    \"\",\n                    \"No available executors, this is not expected, framework should call createExecutorIfAbsent first\"\n                            + \"before coming to here.\");\n\n            return null;\n        }\n\n        // Consumer's executor is sharing globally, key=Integer.MAX_VALUE. Provider's executor is sharing by protocol.\n        String executorCacheKey = getExecutorSecondKey(url);\n        ExecutorService executor = executors.get(executorCacheKey);\n        if (executor != null && (executor.isShutdown() || executor.isTerminated())) {\n            executors.remove(executorCacheKey);\n            // Does not re-create a shutdown executor, use SHARED_EXECUTOR for downgrade.\n            executor = null;\n            logger.info(\"Executor for \" + url + \" is shutdown.\");\n        }\n        if (executor == null) {\n            return frameworkExecutorRepository.getSharedExecutor();\n        } else {\n            return executor;\n        }\n    }\n\n    @Override\n    public ExecutorService getExecutor(ServiceModel serviceModel, URL url) {\n        Map<String, ExecutorService> executors = data.get(getExecutorKey(serviceModel));\n\n        /*\n         * It's guaranteed that this method is called after {@link #createExecutorIfAbsent(URL)}, so data should already\n         * have Executor instances generated and stored.\n         */\n        if (executors == null) {\n            logger.warn(\n                    COMMON_EXECUTORS_NO_FOUND,\n                    \"\",\n                    \"\",\n                    \"No available executors, this is not expected, framework should call createExecutorIfAbsent first\"\n                            + \"before coming to here.\");\n\n            return null;\n        }\n\n        // Consumer's executor is sharing globally, key=Integer.MAX_VALUE. Provider's executor is sharing by protocol.\n        String executorCacheKey = getExecutorSecondKey(serviceModel, url);\n        ExecutorService executor = executors.get(executorCacheKey);\n        if (executor != null && (executor.isShutdown() || executor.isTerminated())) {\n            executors.remove(executorCacheKey);\n            // Does not re-create a shutdown executor, use SHARED_EXECUTOR for downgrade.\n            executor = null;\n            logger.info(\"Executor for \" + url + \" is shutdown.\");\n        }\n        if (executor == null) {\n            return frameworkExecutorRepository.getSharedExecutor();\n        } else {\n            return executor;\n        }\n    }\n\n    @Override\n    public void updateThreadpool(URL url, ExecutorService executor) {\n        try {\n            if (url.hasParameter(THREADS_KEY) && executor instanceof ThreadPoolExecutor && !executor.isShutdown()) {\n                ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;\n                int threads = url.getParameter(THREADS_KEY, 0);\n                int max = threadPoolExecutor.getMaximumPoolSize();\n                int core = threadPoolExecutor.getCorePoolSize();\n                if (threads > 0 && (threads != max || threads != core)) {\n                    if (threads < core) {\n                        threadPoolExecutor.setCorePoolSize(threads);\n                        if (core == max) {\n                            threadPoolExecutor.setMaximumPoolSize(threads);\n                        }\n                    } else {\n                        threadPoolExecutor.setMaximumPoolSize(threads);\n                        if (core == max) {\n                            threadPoolExecutor.setCorePoolSize(threads);\n                        }\n                    }\n                }\n            }\n        } catch (Throwable t) {\n            logger.error(COMMON_ERROR_USE_THREAD_POOL, \"\", \"\", t.getMessage(), t);\n        }\n    }\n\n    @Override\n    public ScheduledExecutorService getServiceExportExecutor() {\n        synchronized (LOCK) {\n            if (serviceExportExecutor == null) {\n                int coreSize = getExportThreadNum();\n                String applicationName = applicationModel.tryGetApplicationName();\n                applicationName = StringUtils.isEmpty(applicationName) ? \"app\" : applicationName;\n                serviceExportExecutor = Executors.newScheduledThreadPool(\n                        coreSize, new NamedThreadFactory(\"Dubbo-\" + applicationName + \"-service-export\", true));\n            }\n        }\n        return serviceExportExecutor;\n    }\n\n    @Override\n    public void shutdownServiceExportExecutor() {\n        synchronized (LOCK) {\n            if (serviceExportExecutor != null && !serviceExportExecutor.isShutdown()) {\n                try {\n                    serviceExportExecutor.shutdown();\n                } catch (Throwable ignored) {\n                    // ignored\n                    logger.warn(COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN, \"\", \"\", ignored.getMessage(), ignored);\n                }\n            }\n            serviceExportExecutor = null;\n        }\n    }\n\n    @Override\n    public ExecutorService getServiceReferExecutor() {\n        synchronized (LOCK) {\n            if (serviceReferExecutor == null) {\n                int coreSize = getReferThreadNum();\n                String applicationName = applicationModel.tryGetApplicationName();\n                applicationName = StringUtils.isEmpty(applicationName) ? \"app\" : applicationName;\n                serviceReferExecutor = Executors.newFixedThreadPool(\n                        coreSize, new NamedThreadFactory(\"Dubbo-\" + applicationName + \"-service-refer\", true));\n            }\n        }\n        return serviceReferExecutor;\n    }\n\n    @Override\n    public void shutdownServiceReferExecutor() {\n        synchronized (LOCK) {\n            if (serviceReferExecutor != null && !serviceReferExecutor.isShutdown()) {\n                try {\n                    serviceReferExecutor.shutdown();\n                } catch (Throwable ignored) {\n                    logger.warn(COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN, \"\", \"\", ignored.getMessage(), ignored);\n                }\n            }\n            serviceReferExecutor = null;\n        }\n    }\n\n    private Integer getExportThreadNum() {\n        Integer threadNum = null;\n        ApplicationModel applicationModel = ApplicationModel.ofNullable(this.applicationModel);\n        for (ModuleModel moduleModel : applicationModel.getPubModuleModels()) {\n            threadNum = getExportThreadNum(moduleModel);\n            if (threadNum != null) {\n                break;\n            }\n        }\n        if (threadNum == null) {\n            logger.info(\"Cannot get config `export-thread-num` from module config, using default: \"\n                    + DEFAULT_EXPORT_THREAD_NUM);\n            return DEFAULT_EXPORT_THREAD_NUM;\n        }\n        return threadNum;\n    }\n\n    private Integer getExportThreadNum(ModuleModel moduleModel) {\n        ModuleConfig moduleConfig = moduleModel.getConfigManager().getModule().orElse(null);\n        if (moduleConfig == null) {\n            return null;\n        }\n        Integer threadNum = moduleConfig.getExportThreadNum();\n        if (threadNum == null) {\n            threadNum = moduleModel.getConfigManager().getProviders().stream()\n                    .map(ProviderConfig::getExportThreadNum)\n                    .filter(k -> k != null && k > 0)\n                    .findAny()\n                    .orElse(null);\n        }\n        return threadNum;\n    }\n\n    private Integer getReferThreadNum() {\n        Integer threadNum = null;\n        ApplicationModel applicationModel = ApplicationModel.ofNullable(this.applicationModel);\n        for (ModuleModel moduleModel : applicationModel.getPubModuleModels()) {\n            threadNum = getReferThreadNum(moduleModel);\n            if (threadNum != null) {\n                break;\n            }\n        }\n        if (threadNum == null) {\n            logger.info(\"Cannot get config `refer-thread-num` from module config, using default: \"\n                    + DEFAULT_REFER_THREAD_NUM);\n            return DEFAULT_REFER_THREAD_NUM;\n        }\n        return threadNum;\n    }\n\n    private Integer getReferThreadNum(ModuleModel moduleModel) {\n        ModuleConfig moduleConfig = moduleModel.getConfigManager().getModule().orElse(null);\n        if (moduleConfig == null) {\n            return null;\n        }\n        Integer threadNum = moduleConfig.getReferThreadNum();\n        if (threadNum == null) {\n            threadNum = moduleModel.getConfigManager().getConsumers().stream()\n                    .map(ConsumerConfig::getReferThreadNum)\n                    .filter(k -> k != null && k > 0)\n                    .findAny()\n                    .orElse(null);\n        }\n        return threadNum;\n    }\n\n    @Override\n    public void destroyAll() {\n        logger.info(\"destroying application executor repository ..\");\n        shutdownServiceExportExecutor();\n        shutdownServiceReferExecutor();\n\n        data.values().forEach(executors -> {\n            if (executors != null) {\n                executors.values().forEach(executor -> {\n                    if (executor != null && !executor.isShutdown()) {\n                        try {\n                            ExecutorUtil.shutdownNow(executor, 100);\n                        } catch (Throwable ignored) {\n                            // ignored\n                            logger.warn(COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN, \"\", \"\", ignored.getMessage(), ignored);\n                        }\n                    }\n                });\n            }\n        });\n        data.clear();\n    }\n\n    private void shutdownExecutorService(ExecutorService executorService, String name) {\n        try {\n            executorService.shutdownNow();\n        } catch (Exception e) {\n            String msg = \"shutdown executor service [\" + name + \"] failed: \";\n            logger.warn(COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN, \"\", \"\", msg + e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public void setExtensionAccessor(ExtensionAccessor extensionAccessor) {\n        this.extensionAccessor = extensionAccessor;\n    }\n\n    @Override\n    public ScheduledExecutorService nextScheduledExecutor() {\n        return frameworkExecutorRepository.nextScheduledExecutor();\n    }\n\n    @Override\n    public ExecutorService nextExecutorExecutor() {\n        return frameworkExecutorRepository.nextExecutorExecutor();\n    }\n\n    @Override\n    public ScheduledExecutorService getServiceDiscoveryAddressNotificationExecutor() {\n        return frameworkExecutorRepository.getServiceDiscoveryAddressNotificationExecutor();\n    }\n\n    @Override\n    public ScheduledExecutorService getMetadataRetryExecutor() {\n        return frameworkExecutorRepository.getMetadataRetryExecutor();\n    }\n\n    @Override\n    public ScheduledExecutorService getRegistryNotificationExecutor() {\n        return frameworkExecutorRepository.getRegistryNotificationExecutor();\n    }\n\n    @Override\n    public ExecutorService getSharedExecutor() {\n        return frameworkExecutorRepository.getSharedExecutor();\n    }\n\n    @Override\n    public ScheduledExecutorService getSharedScheduledExecutor() {\n        return frameworkExecutorRepository.getSharedScheduledExecutor();\n    }\n\n    @Override\n    public ExecutorService getPoolRouterExecutor() {\n        return frameworkExecutorRepository.getPoolRouterExecutor();\n    }\n\n    @Override\n    public ScheduledExecutorService getConnectivityScheduledExecutor() {\n        return frameworkExecutorRepository.getConnectivityScheduledExecutor();\n    }\n\n    @Override\n    public ScheduledExecutorService getCacheRefreshingScheduledExecutor() {\n        return frameworkExecutorRepository.getCacheRefreshingScheduledExecutor();\n    }\n\n    @Override\n    public ExecutorService getMappingRefreshingExecutor() {\n        return frameworkExecutorRepository.getMappingRefreshingExecutor();\n    }\n\n    @Override\n    public ExecutorSupport getExecutorSupport(URL url) {\n        if (executorSupport == null) {\n            executorSupport = new DefaultExecutorSupport(url);\n        }\n        return executorSupport;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.manager;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.rpc.executor.ExecutorSupport;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.Optional;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_ISOLATION;\n\n@SPI(value = \"isolation\", scope = ExtensionScope.APPLICATION)\npublic interface ExecutorRepository {\n\n    /**\n     * Called by both Client and Server. TODO, consider separate these two parts.\n     * When the Client or Server starts for the first time, generate a new threadpool according to the parameters specified.\n     *\n     * @param url\n     * @return\n     */\n    ExecutorService createExecutorIfAbsent(URL url);\n\n    /**\n     * Be careful,The semantics of this method are getOrDefaultExecutor\n     *\n     * @param url\n     * @return\n     */\n    ExecutorService getExecutor(URL url);\n\n    ExecutorService getExecutor(ServiceModel serviceModel, URL url);\n\n    /**\n     * Modify some of the threadpool's properties according to the url, for example, coreSize, maxSize, ...\n     *\n     * @param url\n     * @param executor\n     */\n    void updateThreadpool(URL url, ExecutorService executor);\n\n    ScheduledExecutorService getServiceExportExecutor();\n\n    /**\n     * The executor only used in bootstrap currently, we should call this method to release the resource\n     * after the async export is done.\n     */\n    void shutdownServiceExportExecutor();\n\n    ExecutorService getServiceReferExecutor();\n\n    /**\n     * The executor only used in bootstrap currently, we should call this method to release the resource\n     * after the async refer is done.\n     */\n    void shutdownServiceReferExecutor();\n\n    /**\n     * Destroy all executors that are not in shutdown state\n     */\n    void destroyAll();\n\n    /**\n     * Returns a scheduler from the scheduler list, call this method whenever you need a scheduler for a cron job.\n     * If your cron cannot burden the possible schedule delay caused by sharing the same scheduler, please consider define a dedicate one.\n     *\n     * @deprecated use {@link FrameworkExecutorRepository#nextScheduledExecutor()} instead\n     * @return ScheduledExecutorService\n     */\n    @Deprecated\n    ScheduledExecutorService nextScheduledExecutor();\n\n    /**\n     * @deprecated use {@link FrameworkExecutorRepository#nextExecutorExecutor()} instead\n     * @return ExecutorService\n     */\n    @Deprecated\n    ExecutorService nextExecutorExecutor();\n\n    /**\n     * @deprecated use {@link FrameworkExecutorRepository#getServiceDiscoveryAddressNotificationExecutor()} instead\n     * @return ScheduledExecutorService\n     */\n    @Deprecated\n    ScheduledExecutorService getServiceDiscoveryAddressNotificationExecutor();\n\n    /**\n     * @deprecated use {@link FrameworkExecutorRepository#getMetadataRetryExecutor()} instead\n     * @return ScheduledExecutorService\n     */\n    @Deprecated\n    ScheduledExecutorService getMetadataRetryExecutor();\n\n    /**\n     * Scheduled executor handle registry notification.\n     *\n     * @deprecated use {@link FrameworkExecutorRepository#getRegistryNotificationExecutor()} instead\n     * @return ScheduledExecutorService\n     */\n    @Deprecated\n    ScheduledExecutorService getRegistryNotificationExecutor();\n\n    /**\n     * Get the default shared threadpool.\n     *\n     * @deprecated use {@link FrameworkExecutorRepository#getSharedExecutor()} instead\n     * @return ScheduledExecutorService\n     */\n    @Deprecated\n    ExecutorService getSharedExecutor();\n\n    /**\n     * Get the shared schedule executor\n     *\n     * @deprecated use {@link FrameworkExecutorRepository#getSharedScheduledExecutor()} instead\n     * @return ScheduledExecutorService\n     */\n    @Deprecated\n    ScheduledExecutorService getSharedScheduledExecutor();\n\n    /**\n     * @deprecated use {@link FrameworkExecutorRepository#getPoolRouterExecutor()} instead\n     * @return ExecutorService\n     */\n    @Deprecated\n    ExecutorService getPoolRouterExecutor();\n\n    /**\n     * Scheduled executor handle connectivity check task\n     *\n     * @deprecated use {@link FrameworkExecutorRepository#getConnectivityScheduledExecutor()} instead\n     * @return ScheduledExecutorService\n     */\n    @Deprecated\n    ScheduledExecutorService getConnectivityScheduledExecutor();\n\n    /**\n     * Scheduler used to refresh file based caches from memory to disk.\n     *\n     * @deprecated use {@link FrameworkExecutorRepository#getCacheRefreshingScheduledExecutor()} instead\n     * @return ScheduledExecutorService\n     */\n    @Deprecated\n    ScheduledExecutorService getCacheRefreshingScheduledExecutor();\n\n    /**\n     * Executor used to run async mapping tasks\n     *\n     * @deprecated use {@link FrameworkExecutorRepository#getMappingRefreshingExecutor()} instead\n     * @return ExecutorService\n     */\n    @Deprecated\n    ExecutorService getMappingRefreshingExecutor();\n\n    ExecutorSupport getExecutorSupport(URL url);\n\n    static ExecutorRepository getInstance(ApplicationModel applicationModel) {\n        ExtensionLoader<ExecutorRepository> extensionLoader =\n                applicationModel.getExtensionLoader(ExecutorRepository.class);\n        String mode = getMode(applicationModel);\n        return StringUtils.isNotEmpty(mode)\n                ? extensionLoader.getExtension(mode)\n                : extensionLoader.getDefaultExtension();\n    }\n\n    static String getMode(ApplicationModel applicationModel) {\n        Optional<ApplicationConfig> optional =\n                applicationModel.getApplicationConfigManager().getApplication();\n        return optional.map(ApplicationConfig::getExecutorManagementMode).orElse(EXECUTOR_MANAGEMENT_MODE_ISOLATION);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/FrameworkExecutorRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.manager;\n\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\n\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVER_SHUTDOWN_TIMEOUT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN;\n\npublic class FrameworkExecutorRepository implements Disposable {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(FrameworkExecutorRepository.class);\n\n    private final ExecutorService sharedExecutor;\n    private final ScheduledExecutorService sharedScheduledExecutor;\n\n    private final Ring<ScheduledExecutorService> scheduledExecutors = new Ring<>();\n\n    private final ScheduledExecutorService connectivityScheduledExecutor;\n\n    private final ScheduledExecutorService cacheRefreshingScheduledExecutor;\n\n    private final ExecutorService mappingRefreshingExecutor;\n\n    public final Ring<ScheduledExecutorService> registryNotificationExecutorRing = new Ring<>();\n\n    private final Ring<ScheduledExecutorService> serviceDiscoveryAddressNotificationExecutorRing = new Ring<>();\n\n    private final ScheduledExecutorService metadataRetryExecutor;\n\n    private final ExecutorService poolRouterExecutor;\n\n    private final Ring<ExecutorService> executorServiceRing = new Ring<>();\n\n    private final ExecutorService internalServiceExecutor;\n\n    public FrameworkExecutorRepository() {\n        sharedExecutor = Executors.newCachedThreadPool(new NamedThreadFactory(\"Dubbo-framework-shared-handler\", true));\n        sharedScheduledExecutor =\n                Executors.newScheduledThreadPool(8, new NamedThreadFactory(\"Dubbo-framework-shared-scheduler\", true));\n\n        int availableProcessors = Runtime.getRuntime().availableProcessors();\n        for (int i = 0; i < availableProcessors; i++) {\n            ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(\n                    new NamedThreadFactory(\"Dubbo-framework-scheduler-\" + i, true));\n            scheduledExecutors.addItem(scheduler);\n\n            executorServiceRing.addItem(new ThreadPoolExecutor(\n                    1,\n                    1,\n                    0L,\n                    TimeUnit.MILLISECONDS,\n                    new LinkedBlockingQueue<>(1024),\n                    new NamedInternalThreadFactory(\"Dubbo-framework-state-router-loop-\" + i, true),\n                    new ThreadPoolExecutor.AbortPolicy()));\n        }\n\n        connectivityScheduledExecutor = Executors.newScheduledThreadPool(\n                availableProcessors, new NamedThreadFactory(\"Dubbo-framework-connectivity-scheduler\", true));\n        cacheRefreshingScheduledExecutor = Executors.newSingleThreadScheduledExecutor(\n                new NamedThreadFactory(\"Dubbo-framework-cache-refreshing-scheduler\", true));\n        mappingRefreshingExecutor = Executors.newFixedThreadPool(\n                availableProcessors, new NamedThreadFactory(\"Dubbo-framework-mapping-refreshing-scheduler\", true));\n        poolRouterExecutor = new ThreadPoolExecutor(\n                1,\n                10,\n                0L,\n                TimeUnit.MILLISECONDS,\n                new LinkedBlockingQueue<>(1024),\n                new NamedInternalThreadFactory(\"Dubbo-framework-state-router-pool-router\", true),\n                new ThreadPoolExecutor.AbortPolicy());\n\n        for (int i = 0; i < availableProcessors; i++) {\n            ScheduledExecutorService serviceDiscoveryAddressNotificationExecutor =\n                    Executors.newSingleThreadScheduledExecutor(\n                            new NamedThreadFactory(\"Dubbo-framework-SD-address-refresh-\" + i));\n            ScheduledExecutorService registryNotificationExecutor = Executors.newSingleThreadScheduledExecutor(\n                    new NamedThreadFactory(\"Dubbo-framework-registry-notification-\" + i));\n\n            serviceDiscoveryAddressNotificationExecutorRing.addItem(serviceDiscoveryAddressNotificationExecutor);\n            registryNotificationExecutorRing.addItem(registryNotificationExecutor);\n        }\n\n        metadataRetryExecutor =\n                Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory(\"Dubbo-framework-metadata-retry\"));\n        internalServiceExecutor = new ThreadPoolExecutor(\n                0,\n                100,\n                60L,\n                TimeUnit.SECONDS,\n                new SynchronousQueue<>(),\n                new NamedInternalThreadFactory(\"Dubbo-internal-service\", true),\n                new ThreadPoolExecutor.AbortPolicy());\n    }\n\n    /**\n     * Returns a scheduler from the scheduler list, call this method whenever you need a scheduler for a cron job.\n     * If your cron cannot burden the possible schedule delay caused by sharing the same scheduler, please consider define a dedicated one.\n     *\n     * @return ScheduledExecutorService\n     */\n    public ScheduledExecutorService nextScheduledExecutor() {\n        return scheduledExecutors.pollItem();\n    }\n\n    public ExecutorService nextExecutorExecutor() {\n        return executorServiceRing.pollItem();\n    }\n\n    /**\n     * Scheduled executor handle registry notification.\n     *\n     * @return ScheduledExecutorService\n     */\n    public ScheduledExecutorService getRegistryNotificationExecutor() {\n        return registryNotificationExecutorRing.pollItem();\n    }\n\n    public ScheduledExecutorService getServiceDiscoveryAddressNotificationExecutor() {\n        return serviceDiscoveryAddressNotificationExecutorRing.pollItem();\n    }\n\n    public ScheduledExecutorService getMetadataRetryExecutor() {\n        return metadataRetryExecutor;\n    }\n\n    public ExecutorService getInternalServiceExecutor() {\n        return internalServiceExecutor;\n    }\n\n    /**\n     * Get the default shared thread pool.\n     *\n     * @return ExecutorService\n     */\n    public ExecutorService getSharedExecutor() {\n        return sharedExecutor;\n    }\n\n    /**\n     * Get the shared schedule executor\n     *\n     * @return ScheduledExecutorService\n     */\n    public ScheduledExecutorService getSharedScheduledExecutor() {\n        return sharedScheduledExecutor;\n    }\n\n    public ExecutorService getPoolRouterExecutor() {\n        return poolRouterExecutor;\n    }\n\n    /**\n     * Scheduled executor handle connectivity check task\n     *\n     * @return ScheduledExecutorService\n     */\n    public ScheduledExecutorService getConnectivityScheduledExecutor() {\n        return connectivityScheduledExecutor;\n    }\n\n    /**\n     * Scheduler used to refresh file based caches from memory to disk.\n     *\n     * @return ScheduledExecutorService\n     */\n    public ScheduledExecutorService getCacheRefreshingScheduledExecutor() {\n        return cacheRefreshingScheduledExecutor;\n    }\n\n    /**\n     * Executor used to run async mapping tasks\n     *\n     * @return ExecutorService\n     */\n    public ExecutorService getMappingRefreshingExecutor() {\n        return mappingRefreshingExecutor;\n    }\n\n    @Override\n    public void destroy() {\n        logger.info(\"destroying framework executor repository ..\");\n        shutdownExecutorService(poolRouterExecutor, \"poolRouterExecutor\");\n        shutdownExecutorService(metadataRetryExecutor, \"metadataRetryExecutor\");\n        shutdownExecutorService(internalServiceExecutor, \"internalServiceExecutor\");\n\n        // scheduledExecutors\n        shutdownExecutorServices(scheduledExecutors.listItems(), \"scheduledExecutors\");\n\n        // executorServiceRing\n        shutdownExecutorServices(executorServiceRing.listItems(), \"executorServiceRing\");\n\n        // connectivityScheduledExecutor\n        shutdownExecutorService(connectivityScheduledExecutor, \"connectivityScheduledExecutor\");\n        shutdownExecutorService(cacheRefreshingScheduledExecutor, \"cacheRefreshingScheduledExecutor\");\n\n        // shutdown share executor\n        shutdownExecutorService(sharedExecutor, \"sharedExecutor\");\n        shutdownExecutorService(sharedScheduledExecutor, \"sharedScheduledExecutor\");\n\n        // serviceDiscoveryAddressNotificationExecutorRing\n        shutdownExecutorServices(\n                serviceDiscoveryAddressNotificationExecutorRing.listItems(),\n                \"serviceDiscoveryAddressNotificationExecutorRing\");\n\n        // registryNotificationExecutorRing\n        shutdownExecutorServices(registryNotificationExecutorRing.listItems(), \"registryNotificationExecutorRing\");\n\n        // mappingRefreshingExecutor\n        shutdownExecutorService(mappingRefreshingExecutor, \"mappingRefreshingExecutor\");\n    }\n\n    private void shutdownExecutorServices(List<? extends ExecutorService> executorServices, String msg) {\n        for (ExecutorService executorService : executorServices) {\n            shutdownExecutorService(executorService, msg);\n        }\n    }\n\n    private void shutdownExecutorService(ExecutorService executorService, String name) {\n        try {\n            executorService.shutdownNow();\n            if (!executorService.awaitTermination(\n                    ConfigurationUtils.reCalShutdownTime(DEFAULT_SERVER_SHUTDOWN_TIMEOUT), TimeUnit.MILLISECONDS)) {\n                logger.warn(\n                        COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN,\n                        \"\",\n                        \"\",\n                        \"Wait global executor service terminated timeout.\");\n            }\n        } catch (Exception e) {\n            String msg = \"shutdown executor service [\" + name + \"] failed: \";\n            logger.warn(COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN, \"\", \"\", msg + e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/IsolationExecutorRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.manager;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.executor.ExecutorSupport;\nimport org.apache.dubbo.rpc.executor.IsolationExecutorSupportFactory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\nimport java.util.concurrent.ExecutorService;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SERVICE_EXECUTOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\n\n/**\n * Thread pool isolation between services, that is, a service has its own thread pool and not interfere with each other\n */\npublic class IsolationExecutorRepository extends DefaultExecutorRepository {\n\n    public IsolationExecutorRepository(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    @Override\n    protected URL setThreadNameIfAbsent(URL url, String executorCacheKey) {\n        if (url.getParameter(THREAD_NAME_KEY) == null) {\n            url = url.putAttribute(THREAD_NAME_KEY, \"isolation-\" + executorCacheKey);\n        }\n        return url;\n    }\n\n    @Override\n    protected String getProviderKey(URL url) {\n        if (url.getAttributes().containsKey(SERVICE_EXECUTOR)) {\n            return url.getServiceKey();\n        } else {\n            return super.getProviderKey(url);\n        }\n    }\n\n    @Override\n    protected String getProviderKey(ProviderModel providerModel, URL url) {\n        if (url.getAttributes().containsKey(SERVICE_EXECUTOR)) {\n            return providerModel.getServiceKey();\n        } else {\n            return super.getProviderKey(url);\n        }\n    }\n\n    @Override\n    protected ExecutorService createExecutor(URL url) {\n        Object executor = url.getAttributes().get(SERVICE_EXECUTOR);\n        if (executor instanceof ExecutorService) {\n            return (ExecutorService) executor;\n        }\n        return super.createExecutor(url);\n    }\n\n    @Override\n    public ExecutorSupport getExecutorSupport(URL url) {\n        return IsolationExecutorSupportFactory.getIsolationExecutorSupport(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/Ring.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.manager;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.atomic.AtomicInteger;\n\npublic class Ring<T> {\n\n    AtomicInteger count = new AtomicInteger();\n\n    private final List<T> itemList = new CopyOnWriteArrayList<>();\n\n    public void addItem(T t) {\n        if (t != null) {\n            itemList.add(t);\n        }\n    }\n\n    public T pollItem() {\n        if (itemList.isEmpty()) {\n            return null;\n        }\n        if (itemList.size() == 1) {\n            return itemList.get(0);\n        }\n\n        if (count.intValue() > Integer.MAX_VALUE - 10000) {\n            count.set(count.get() % itemList.size());\n        }\n\n        int index = Math.abs(count.getAndIncrement()) % itemList.size();\n        return itemList.get(index);\n    }\n\n    public T peekItem() {\n        if (itemList.isEmpty()) {\n            return null;\n        }\n        if (itemList.size() == 1) {\n            return itemList.get(0);\n        }\n        int index = Math.abs(count.get()) % itemList.size();\n        return itemList.get(index);\n    }\n\n    public List<T> listItems() {\n        return Collections.unmodifiableList(itemList);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/serial/SerializingExecutor.java",
    "content": "/*\n * Copyright 2014 The gRPC Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.common.threadpool.serial;\n\nimport java.util.Queue;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadlocal.InternalThreadLocalMap;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_ERROR_RUN_THREAD_TASK;\nimport static org.apache.dubbo.common.utils.ExecutorUtil.isShutdown;\n\n/**\n * Executor ensuring that all {@link Runnable} tasks submitted are executed in order\n * using the provided {@link Executor}, and serially such that no two will ever be\n * running at the same time.\n */\npublic final class SerializingExecutor implements Executor, Runnable {\n\n    private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(SerializingExecutor.class);\n\n    /**\n     * Use false to stop and true to run\n     */\n    private final AtomicBoolean atomicBoolean = new AtomicBoolean();\n\n    private final Executor executor;\n\n    private final Queue<Runnable> runQueue = new ConcurrentLinkedQueue<>();\n\n    /**\n     * Creates a SerializingExecutor, running tasks using {@code executor}.\n     *\n     * @param executor Executor in which tasks should be run. Must not be null.\n     */\n    public SerializingExecutor(Executor executor) {\n        this.executor = executor;\n    }\n\n    /**\n     * Runs the given runnable strictly after all Runnables that were submitted\n     * before it, and using the {@code executor} passed to the constructor.     .\n     */\n    @Override\n    public void execute(Runnable r) {\n        runQueue.add(r);\n        schedule(r);\n    }\n\n    private void schedule(Runnable removable) {\n        if (atomicBoolean.compareAndSet(false, true)) {\n            boolean success = false;\n            try {\n                if (!isShutdown(executor)) {\n                    executor.execute(this);\n                    success = true;\n                }\n            } catch (RejectedExecutionException e) {\n                if (!isShutdown(executor)) {\n                    // ignore exception if the executor is shutdown\n                    throw e;\n                }\n            } finally {\n                // It is possible that at this point that there are still tasks in\n                // the queue, it would be nice to keep trying but the error may not\n                // be recoverable.  So we update our state and propagate so that if\n                // our caller deems it recoverable we won't be stuck.\n                if (!success) {\n                    if (removable != null) {\n                        // This case can only be reached if 'this' was not currently running, and we failed to\n                        // reschedule.  The item should still be in the queue for removal.\n                        // ConcurrentLinkedQueue claims that null elements are not allowed, but seems to not\n                        // throw if the item to remove is null.  If removable is present in the queue twice,\n                        // the wrong one may be removed.  It doesn't seem possible for this case to exist today.\n                        // This is important to run in case of RejectedExecutionException, so that future calls\n                        // to execute don't succeed and accidentally run a previous runnable.\n                        runQueue.remove(removable);\n                    }\n                    atomicBoolean.set(false);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void run() {\n        Runnable r;\n        try {\n            while ((r = runQueue.poll()) != null) {\n                InternalThreadLocalMap internalThreadLocalMap = InternalThreadLocalMap.getAndRemove();\n                try {\n                    r.run();\n                } catch (RuntimeException e) {\n                    LOGGER.error(COMMON_ERROR_RUN_THREAD_TASK, \"\", \"\", \"Exception while executing runnable \" + r, e);\n                } finally {\n                    InternalThreadLocalMap.set(internalThreadLocalMap);\n                }\n            }\n        } finally {\n            atomicBoolean.set(false);\n        }\n        if (!runQueue.isEmpty()) {\n            // we didn't enqueue anything but someone else did.\n            schedule(null);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedEvent;\nimport org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedListener;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.JVMUtil;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Set;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport static java.lang.String.format;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR_CHAR;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUMP_ENABLE;\nimport static org.apache.dubbo.common.constants.CommonConstants.OS_WIN_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_OS_NAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_POOL_EXHAUSTED_LISTENERS_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_THREAD_POOL_EXHAUSTED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_CREATE_DUMP;\n\n/**\n * Abort Policy.\n * Log warn info when abort.\n */\npublic class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {\n\n    protected static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(AbortPolicyWithReport.class);\n\n    private final String threadName;\n\n    private final URL url;\n\n    protected static volatile long lastPrintTime = 0;\n\n    private static final long TEN_MINUTES_MILLS = 10 * 60 * 1000;\n\n    private static final String WIN_DATETIME_FORMAT = \"yyyy-MM-dd_HH-mm-ss\";\n\n    private static final String DEFAULT_DATETIME_FORMAT = \"yyyy-MM-dd_HH:mm:ss\";\n\n    protected static Semaphore guard = new Semaphore(1);\n\n    private static final String USER_HOME =\n            SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.USER_HOME);\n\n    private final Set<ThreadPoolExhaustedListener> listeners = new ConcurrentHashSet<>();\n\n    public AbortPolicyWithReport(String threadName, URL url) {\n        this.threadName = threadName;\n        this.url = url;\n\n        String threadPoolExhaustedListeners = url.getParameter(\n                THREAD_POOL_EXHAUSTED_LISTENERS_KEY, (String) url.getAttribute(THREAD_POOL_EXHAUSTED_LISTENERS_KEY));\n\n        Set<String> listenerKeys = StringUtils.splitToSet(threadPoolExhaustedListeners, COMMA_SEPARATOR_CHAR, true);\n\n        FrameworkModel frameworkModel = url.getOrDefaultFrameworkModel();\n        ExtensionLoader<ThreadPoolExhaustedListener> extensionLoader =\n                frameworkModel.getExtensionLoader(ThreadPoolExhaustedListener.class);\n        listenerKeys.forEach(key -> {\n            if (extensionLoader.hasExtension(key)) {\n                addThreadPoolExhaustedEventListener(extensionLoader.getExtension(key));\n            }\n        });\n    }\n\n    @Override\n    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {\n        String msg = String.format(\n                \"Thread pool is EXHAUSTED!\"\n                        + \" Thread Name: %s, Pool Size: %d (active: %d, core: %d, max: %d, largest: %d),\"\n                        + \" Task: %d (completed: %d),\"\n                        + \" Executor status:(isShutdown:%s, isTerminated:%s, isTerminating:%s), in %s://%s:%d!\",\n                threadName,\n                e.getPoolSize(),\n                e.getActiveCount(),\n                e.getCorePoolSize(),\n                e.getMaximumPoolSize(),\n                e.getLargestPoolSize(),\n                e.getTaskCount(),\n                e.getCompletedTaskCount(),\n                e.isShutdown(),\n                e.isTerminated(),\n                e.isTerminating(),\n                url.getProtocol(),\n                url.getIp(),\n                url.getPort());\n\n        // 0-1 - Thread pool is EXHAUSTED!\n        logger.warn(COMMON_THREAD_POOL_EXHAUSTED, \"too much client requesting provider\", \"\", msg);\n\n        if (Boolean.parseBoolean(url.getParameter(DUMP_ENABLE, Boolean.TRUE.toString()))) {\n            dumpJStack();\n        }\n\n        dispatchThreadPoolExhaustedEvent(msg);\n\n        throw new RejectedExecutionException(msg);\n    }\n\n    public void addThreadPoolExhaustedEventListener(ThreadPoolExhaustedListener listener) {\n        listeners.add(listener);\n    }\n\n    public void removeThreadPoolExhaustedEventListener(ThreadPoolExhaustedListener listener) {\n        listeners.remove(listener);\n    }\n\n    /**\n     * dispatch ThreadPoolExhaustedEvent\n     *\n     * @param msg\n     */\n    public void dispatchThreadPoolExhaustedEvent(String msg) {\n        listeners.forEach(listener -> listener.onEvent(new ThreadPoolExhaustedEvent(msg)));\n    }\n\n    private void dumpJStack() {\n        long now = System.currentTimeMillis();\n\n        // dump every 10 minutes\n        if (now - lastPrintTime < TEN_MINUTES_MILLS) {\n            return;\n        }\n\n        if (!guard.tryAcquire()) {\n            return;\n        }\n        ExecutorService pool = null;\n        try {\n            // To avoid multiple dump, check again\n            if (System.currentTimeMillis() - lastPrintTime < TEN_MINUTES_MILLS) {\n                return;\n            }\n            pool = Executors.newSingleThreadExecutor();\n            pool.execute(() -> {\n                String dumpPath = getDumpPath();\n\n                SimpleDateFormat sdf;\n\n                String os = SystemPropertyConfigUtils.getSystemProperty(SYSTEM_OS_NAME)\n                        .toLowerCase();\n\n                // window system don't support \":\" in file name\n                if (os.contains(OS_WIN_PREFIX)) {\n                    sdf = new SimpleDateFormat(WIN_DATETIME_FORMAT);\n                } else {\n                    sdf = new SimpleDateFormat(DEFAULT_DATETIME_FORMAT);\n                }\n\n                String dateStr = sdf.format(new Date());\n                // try-with-resources\n                try (FileOutputStream jStackStream =\n                        new FileOutputStream(new File(dumpPath, \"Dubbo_JStack.log\" + \".\" + dateStr))) {\n                    jstack(jStackStream);\n                } catch (Exception t) {\n                    logger.error(COMMON_UNEXPECTED_CREATE_DUMP, \"\", \"\", \"dump jStack error\", t);\n                }\n            });\n            lastPrintTime = System.currentTimeMillis();\n        } finally {\n            guard.release();\n            // must shut down thread pool ,if not will lead to OOM\n            if (pool != null) {\n                pool.shutdown();\n            }\n        }\n    }\n\n    protected void jstack(FileOutputStream jStackStream) throws Exception {\n        JVMUtil.jstack(jStackStream);\n    }\n\n    protected String getDumpPath() {\n        final String dumpPath = url.getParameter(DUMP_DIRECTORY);\n        if (StringUtils.isEmpty(dumpPath)) {\n            return USER_HOME;\n        }\n        final File dumpDirectory = new File(dumpPath);\n        if (!dumpDirectory.exists()) {\n            if (dumpDirectory.mkdirs()) {\n                logger.info(format(\"Dubbo dump directory[%s] created\", dumpDirectory.getAbsolutePath()));\n            } else {\n                logger.warn(\n                        COMMON_UNEXPECTED_CREATE_DUMP,\n                        \"\",\n                        \"\",\n                        format(\n                                \"Dubbo dump directory[%s] can't be created, use the 'user.home'[%s]\",\n                                dumpDirectory.getAbsolutePath(), USER_HOME));\n                return USER_HOME;\n            }\n        }\n        return dumpPath;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/cached/CachedThreadPool.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.cached;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;\nimport org.apache.dubbo.common.threadpool.MemorySafeLinkedBlockingQueue;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_ALIVE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CORE_THREADS;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_QUEUES;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREAD_NAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\n\n/**\n * This thread pool is self-tuned. Thread will be recycled after idle for one minute, and new thread will be created for\n * the upcoming request.\n *\n * @see java.util.concurrent.Executors#newCachedThreadPool()\n */\npublic class CachedThreadPool implements ThreadPool {\n\n    @Override\n    public Executor getExecutor(URL url) {\n        String name =\n                url.getParameter(THREAD_NAME_KEY, (String) url.getAttribute(THREAD_NAME_KEY, DEFAULT_THREAD_NAME));\n        int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);\n        int threads = url.getParameter(THREADS_KEY, Integer.MAX_VALUE);\n        int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);\n        int alive = url.getParameter(ALIVE_KEY, DEFAULT_ALIVE);\n\n        BlockingQueue<Runnable> blockingQueue;\n\n        if (queues == 0) {\n            blockingQueue = new SynchronousQueue<>();\n        } else if (queues < 0) {\n            blockingQueue = new MemorySafeLinkedBlockingQueue<>();\n        } else {\n            blockingQueue = new LinkedBlockingQueue<>(queues);\n        }\n\n        return new ThreadPoolExecutor(\n                cores,\n                threads,\n                alive,\n                TimeUnit.MILLISECONDS,\n                blockingQueue,\n                new NamedInternalThreadFactory(name, true),\n                new AbortPolicyWithReport(name, url));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/eager/EagerThreadPool.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.eager;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\n\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_ALIVE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CORE_THREADS;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_QUEUES;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREAD_NAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\n\n/**\n * EagerThreadPool\n * When the core threads are all in busy,\n * create new thread instead of putting task into blocking queue.\n */\npublic class EagerThreadPool implements ThreadPool {\n\n    @Override\n    public Executor getExecutor(URL url) {\n        String name =\n                url.getParameter(THREAD_NAME_KEY, (String) url.getAttribute(THREAD_NAME_KEY, DEFAULT_THREAD_NAME));\n        int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);\n        int threads = url.getParameter(THREADS_KEY, Integer.MAX_VALUE);\n        int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);\n        int alive = url.getParameter(ALIVE_KEY, DEFAULT_ALIVE);\n\n        // init queue and executor\n        TaskQueue<Runnable> taskQueue = new TaskQueue<>(queues <= 0 ? 1 : queues);\n        EagerThreadPoolExecutor executor = new EagerThreadPoolExecutor(\n                cores,\n                threads,\n                alive,\n                TimeUnit.MILLISECONDS,\n                taskQueue,\n                new NamedInternalThreadFactory(name, true),\n                new AbortPolicyWithReport(name, url));\n        taskQueue.setExecutor(executor);\n        return executor;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/eager/EagerThreadPoolExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.eager;\n\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\npublic class EagerThreadPoolExecutor extends ThreadPoolExecutor {\n\n    public EagerThreadPoolExecutor(\n            int corePoolSize,\n            int maximumPoolSize,\n            long keepAliveTime,\n            TimeUnit unit,\n            TaskQueue<Runnable> workQueue,\n            ThreadFactory threadFactory,\n            RejectedExecutionHandler handler) {\n        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);\n    }\n\n    @Override\n    public void execute(Runnable command) {\n        if (command == null) {\n            throw new NullPointerException();\n        }\n\n        try {\n            super.execute(command);\n        } catch (RejectedExecutionException rx) {\n            // retry to offer the task into queue.\n            final TaskQueue queue = (TaskQueue) super.getQueue();\n            try {\n                if (!queue.retryOffer(command, 0, TimeUnit.MILLISECONDS)) {\n                    throw new RejectedExecutionException(\"Queue capacity is full.\", rx);\n                }\n            } catch (InterruptedException x) {\n                throw new RejectedExecutionException(x);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/eager/TaskQueue.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.eager;\n\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * TaskQueue in the EagerThreadPoolExecutor\n * It offer a task if the executor's submittedTaskCount less than currentPoolThreadSize\n * or the currentPoolThreadSize more than executor's maximumPoolSize.\n * That can make the executor create new worker\n * when the task num is bigger than corePoolSize but less than maximumPoolSize.\n */\npublic class TaskQueue<R extends Runnable> extends LinkedBlockingQueue<Runnable> {\n\n    private static final long serialVersionUID = -2635853580887179627L;\n\n    private EagerThreadPoolExecutor executor;\n\n    public TaskQueue(int capacity) {\n        super(capacity);\n    }\n\n    public void setExecutor(EagerThreadPoolExecutor exec) {\n        executor = exec;\n    }\n\n    @Override\n    public boolean offer(Runnable runnable) {\n        if (executor == null) {\n            throw new RejectedExecutionException(\"The task queue does not have executor!\");\n        }\n\n        int currentPoolThreadSize = executor.getPoolSize();\n        // have free worker. put task into queue to let the worker deal with task.\n        if (executor.getActiveCount() < currentPoolThreadSize) {\n            return super.offer(runnable);\n        }\n\n        // return false to let executor create new worker.\n        if (currentPoolThreadSize < executor.getMaximumPoolSize()) {\n            return false;\n        }\n\n        // currentPoolThreadSize >= max\n        return super.offer(runnable);\n    }\n\n    /**\n     * retry offer task\n     *\n     * @param o task\n     * @return offer success or not\n     * @throws RejectedExecutionException if executor is terminated.\n     */\n    public boolean retryOffer(Runnable o, long timeout, TimeUnit unit) throws InterruptedException {\n        if (executor.isShutdown()) {\n            throw new RejectedExecutionException(\"Executor is shutdown!\");\n        }\n        return super.offer(o, timeout, unit);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/fixed/FixedThreadPool.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.fixed;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;\nimport org.apache.dubbo.common.threadpool.MemorySafeLinkedBlockingQueue;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_QUEUES;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREADS;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREAD_NAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\n/**\n * Creates a thread pool that reuses a fixed number of threads\n *\n * @see java.util.concurrent.Executors#newFixedThreadPool(int)\n */\npublic class FixedThreadPool implements ThreadPool {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(FixedThreadPool.class);\n\n    @Override\n    public Executor getExecutor(URL url) {\n        String name =\n                url.getParameter(THREAD_NAME_KEY, (String) url.getAttribute(THREAD_NAME_KEY, DEFAULT_THREAD_NAME));\n        int threads = url.getParameter(THREADS_KEY, DEFAULT_THREADS);\n        int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);\n\n        BlockingQueue<Runnable> blockingQueue;\n\n        if (queues == 0) {\n            blockingQueue = new SynchronousQueue<>();\n        } else if (queues < 0) {\n            blockingQueue = new MemorySafeLinkedBlockingQueue<>();\n            logger.warn(\n                    COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"FixedThreadPool created with an unbounded queue (queues < 0). \"\n                            + \"This may lead to OutOfMemoryError under high load. \"\n                            + \"Consider configuring a positive integer for 'queues'.\");\n        } else {\n            blockingQueue = new LinkedBlockingQueue<>(queues);\n        }\n\n        return new ThreadPoolExecutor(\n                threads,\n                threads,\n                0,\n                TimeUnit.MILLISECONDS,\n                blockingQueue,\n                new NamedInternalThreadFactory(name, true),\n                new AbortPolicyWithReport(name, url));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/support/limited/LimitedThreadPool.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.limited;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;\nimport org.apache.dubbo.common.threadpool.MemorySafeLinkedBlockingQueue;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CORE_THREADS;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_QUEUES;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREADS;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREAD_NAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\n\n/**\n * Creates a thread pool that creates new threads as needed until limits reaches. This thread pool will not shrink\n * automatically.\n */\npublic class LimitedThreadPool implements ThreadPool {\n\n    @Override\n    public Executor getExecutor(URL url) {\n        String name =\n                url.getParameter(THREAD_NAME_KEY, (String) url.getAttribute(THREAD_NAME_KEY, DEFAULT_THREAD_NAME));\n        int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);\n        int threads = url.getParameter(THREADS_KEY, DEFAULT_THREADS);\n        int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);\n\n        BlockingQueue<Runnable> blockingQueue;\n\n        if (queues == 0) {\n            blockingQueue = new SynchronousQueue<>();\n        } else if (queues < 0) {\n            blockingQueue = new MemorySafeLinkedBlockingQueue<>();\n        } else {\n            blockingQueue = new LinkedBlockingQueue<>(queues);\n        }\n\n        return new ThreadPoolExecutor(\n                cores,\n                threads,\n                Long.MAX_VALUE,\n                TimeUnit.MILLISECONDS,\n                blockingQueue,\n                new NamedInternalThreadFactory(name, true),\n                new AbortPolicyWithReport(name, url));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java",
    "content": "/*\n * Copyright 2012 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"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, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage org.apache.dubbo.common.timer;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Locale;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicIntegerFieldUpdater;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_OS_NAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.OS_WIN_PREFIX;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_ERROR_RUN_THREAD_TASK;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_ERROR_TOO_MANY_INSTANCES;\n\n/**\n * A {@link Timer} optimized for approximated I/O timeout scheduling.\n *\n * <h3>Tick Duration</h3>\n * <p>\n * As described with 'approximated', this timer does not execute the scheduled\n * {@link TimerTask} on time.  {@link HashedWheelTimer}, on every tick, will\n * check if there are any {@link TimerTask}s behind the schedule and execute\n * them.\n * <p>\n * You can increase or decrease the accuracy of the execution timing by\n * specifying smaller or larger tick duration in the constructor.  In most\n * network applications, I/O timeout does not need to be accurate.  Therefore,\n * the default tick duration is 100 milliseconds, and you will not need to try\n * different configurations in most cases.\n *\n * <h3>Ticks per Wheel (Wheel Size)</h3>\n * <p>\n * {@link HashedWheelTimer} maintains a data structure called 'wheel'.\n * To put simply, a wheel is a hash table of {@link TimerTask}s whose hash\n * function is 'deadline of the task'.  The default number of ticks per wheel\n * (i.e. the size of the wheel) is 512.  You could specify a larger value\n * if you are going to schedule a lot of timeouts.\n *\n * <h3>Do not create many instances.</h3>\n * <p>\n * {@link HashedWheelTimer} creates a new thread whenever it is instantiated and\n * started.  Therefore, you should make sure to create only one instance and\n * share it across your application.  One of the common mistakes, that makes\n * your application unresponsive, is to create a new instance for every connection.\n *\n * <h3>Implementation Details</h3>\n * <p>\n * {@link HashedWheelTimer} is based on\n * <a href=\"http://cseweb.ucsd.edu/users/varghese/\">George Varghese</a> and\n * Tony Lauck's paper,\n * <a href=\"http://cseweb.ucsd.edu/users/varghese/PAPERS/twheel.ps.Z\">'Hashed\n * and Hierarchical Timing Wheels: data structures to efficiently implement a\n * timer facility'</a>.  More comprehensive slides are located\n * <a href=\"http://www.cse.wustl.edu/~cdgill/courses/cs6874/TimingWheels.ppt\">here</a>.\n */\npublic class HashedWheelTimer implements Timer {\n\n    /**\n     * may be in spi?\n     */\n    public static final String NAME = \"hashed\";\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(HashedWheelTimer.class);\n\n    private static final AtomicInteger INSTANCE_COUNTER = new AtomicInteger();\n    private static final AtomicBoolean WARNED_TOO_MANY_INSTANCES = new AtomicBoolean();\n    private static final int INSTANCE_COUNT_LIMIT = 64;\n    private static final AtomicIntegerFieldUpdater<HashedWheelTimer> WORKER_STATE_UPDATER =\n        AtomicIntegerFieldUpdater.newUpdater(HashedWheelTimer.class, \"workerState\");\n\n    private final Worker worker = new Worker();\n    private final Thread workerThread;\n\n    private static final int WORKER_STATE_INIT = 0;\n    private static final int WORKER_STATE_STARTED = 1;\n    private static final int WORKER_STATE_SHUTDOWN = 2;\n\n    /**\n     * 0 - init, 1 - started, 2 - shut down\n     */\n    @SuppressWarnings({\"unused\", \"FieldMayBeFinal\"})\n    private volatile int workerState;\n\n    private final long tickDuration;\n    private final HashedWheelBucket[] wheel;\n    private final int mask;\n    private final CountDownLatch startTimeInitialized = new CountDownLatch(1);\n    private final Queue<HashedWheelTimeout> timeouts = new LinkedBlockingQueue<>();\n    private final Queue<HashedWheelTimeout> cancelledTimeouts = new LinkedBlockingQueue<>();\n    private final AtomicLong pendingTimeouts = new AtomicLong(0);\n    private final long maxPendingTimeouts;\n\n    private volatile long startTime;\n\n    /**\n     * Creates a new timer with the default thread factory\n     * ({@link Executors#defaultThreadFactory()}), default tick duration, and\n     * default number of ticks per wheel.\n     */\n    public HashedWheelTimer() {\n        this(Executors.defaultThreadFactory());\n    }\n\n    /**\n     * Creates a new timer with the default thread factory\n     * ({@link Executors#defaultThreadFactory()}) and default number of ticks\n     * per wheel.\n     *\n     * @param tickDuration the duration between tick\n     * @param unit         the time unit of the {@code tickDuration}\n     * @throws NullPointerException     if {@code unit} is {@code null}\n     * @throws IllegalArgumentException if {@code tickDuration} is &lt;= 0\n     */\n    public HashedWheelTimer(long tickDuration, TimeUnit unit) {\n        this(Executors.defaultThreadFactory(), tickDuration, unit);\n    }\n\n    /**\n     * Creates a new timer with the default thread factory\n     * ({@link Executors#defaultThreadFactory()}).\n     *\n     * @param tickDuration  the duration between tick\n     * @param unit          the time unit of the {@code tickDuration}\n     * @param ticksPerWheel the size of the wheel\n     * @throws NullPointerException     if {@code unit} is {@code null}\n     * @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is &lt;= 0\n     */\n    public HashedWheelTimer(long tickDuration, TimeUnit unit, int ticksPerWheel) {\n        this(Executors.defaultThreadFactory(), tickDuration, unit, ticksPerWheel);\n    }\n\n    /**\n     * Creates a new timer with the default tick duration and default number of\n     * ticks per wheel.\n     *\n     * @param threadFactory a {@link ThreadFactory} that creates a\n     *                      background {@link Thread} which is dedicated to\n     *                      {@link TimerTask} execution.\n     * @throws NullPointerException if {@code threadFactory} is {@code null}\n     */\n    public HashedWheelTimer(ThreadFactory threadFactory) {\n        this(threadFactory, 100, TimeUnit.MILLISECONDS);\n    }\n\n    /**\n     * Creates a new timer with the default number of ticks per wheel.\n     *\n     * @param threadFactory a {@link ThreadFactory} that creates a\n     *                      background {@link Thread} which is dedicated to\n     *                      {@link TimerTask} execution.\n     * @param tickDuration  the duration between tick\n     * @param unit          the time unit of the {@code tickDuration}\n     * @throws NullPointerException     if either of {@code threadFactory} and {@code unit} is {@code null}\n     * @throws IllegalArgumentException if {@code tickDuration} is &lt;= 0\n     */\n    public HashedWheelTimer(\n        ThreadFactory threadFactory, long tickDuration, TimeUnit unit) {\n        this(threadFactory, tickDuration, unit, 512);\n    }\n\n    /**\n     * Creates a new timer.\n     *\n     * @param threadFactory a {@link ThreadFactory} that creates a\n     *                      background {@link Thread} which is dedicated to\n     *                      {@link TimerTask} execution.\n     * @param tickDuration  the duration between tick\n     * @param unit          the time unit of the {@code tickDuration}\n     * @param ticksPerWheel the size of the wheel\n     * @throws NullPointerException     if either of {@code threadFactory} and {@code unit} is {@code null}\n     * @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is &lt;= 0\n     */\n    public HashedWheelTimer(\n        ThreadFactory threadFactory,\n        long tickDuration, TimeUnit unit, int ticksPerWheel) {\n        this(threadFactory, tickDuration, unit, ticksPerWheel, -1);\n    }\n\n    /**\n     * Creates a new timer.\n     *\n     * @param threadFactory      a {@link ThreadFactory} that creates a\n     *                           background {@link Thread} which is dedicated to\n     *                           {@link TimerTask} execution.\n     * @param tickDuration       the duration between tick\n     * @param unit               the time unit of the {@code tickDuration}\n     * @param ticksPerWheel      the size of the wheel\n     * @param maxPendingTimeouts The maximum number of pending timeouts after which call to\n     *                           {@code newTimeout} will result in\n     *                           {@link java.util.concurrent.RejectedExecutionException}\n     *                           being thrown. No maximum pending timeouts limit is assumed if\n     *                           this value is 0 or negative.\n     * @throws NullPointerException     if either of {@code threadFactory} and {@code unit} is {@code null}\n     * @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is &lt;= 0\n     */\n    public HashedWheelTimer(\n        ThreadFactory threadFactory,\n        long tickDuration, TimeUnit unit, int ticksPerWheel,\n        long maxPendingTimeouts) {\n\n        if (threadFactory == null) {\n            throw new NullPointerException(\"threadFactory\");\n        }\n        if (unit == null) {\n            throw new NullPointerException(\"unit\");\n        }\n        if (tickDuration <= 0) {\n            throw new IllegalArgumentException(\"tickDuration must be greater than 0: \" + tickDuration);\n        }\n        if (ticksPerWheel <= 0) {\n            throw new IllegalArgumentException(\"ticksPerWheel must be greater than 0: \" + ticksPerWheel);\n        }\n\n        // Normalize ticksPerWheel to power of two and initialize the wheel.\n        wheel = createWheel(ticksPerWheel);\n        mask = wheel.length - 1;\n\n        // Convert tickDuration to nanos.\n        this.tickDuration = unit.toNanos(tickDuration);\n\n        // Prevent overflow.\n        if (this.tickDuration >= Long.MAX_VALUE / wheel.length) {\n            throw new IllegalArgumentException(String.format(\n                \"tickDuration: %d (expected: 0 < tickDuration in nanos < %d\",\n                tickDuration, Long.MAX_VALUE / wheel.length));\n        }\n        workerThread = threadFactory.newThread(worker);\n\n        this.maxPendingTimeouts = maxPendingTimeouts;\n\n        if (INSTANCE_COUNTER.incrementAndGet() > INSTANCE_COUNT_LIMIT &&\n            WARNED_TOO_MANY_INSTANCES.compareAndSet(false, true)) {\n            reportTooManyInstances();\n        }\n    }\n\n    @Override\n    protected void finalize() throws Throwable {\n        try {\n            super.finalize();\n        } finally {\n            // This object is going to be GCed and it is assumed the ship has sailed to do a proper shutdown. If\n            // we have not yet shutdown then we want to make sure we decrement the active instance count.\n            if (WORKER_STATE_UPDATER.getAndSet(this, WORKER_STATE_SHUTDOWN) != WORKER_STATE_SHUTDOWN) {\n                INSTANCE_COUNTER.decrementAndGet();\n            }\n        }\n    }\n\n    private static HashedWheelBucket[] createWheel(int ticksPerWheel) {\n        if (ticksPerWheel <= 0) {\n            throw new IllegalArgumentException(\n                \"ticksPerWheel must be greater than 0: \" + ticksPerWheel);\n        }\n        if (ticksPerWheel > 1073741824) {\n            throw new IllegalArgumentException(\n                \"ticksPerWheel may not be greater than 2^30: \" + ticksPerWheel);\n        }\n\n        ticksPerWheel = normalizeTicksPerWheel(ticksPerWheel);\n        HashedWheelBucket[] wheel = new HashedWheelBucket[ticksPerWheel];\n        for (int i = 0; i < wheel.length; i++) {\n            wheel[i] = new HashedWheelBucket();\n        }\n        return wheel;\n    }\n\n    private static int normalizeTicksPerWheel(int ticksPerWheel) {\n        int normalizedTicksPerWheel = ticksPerWheel - 1;\n        normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 1;\n        normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 2;\n        normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 4;\n        normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 8;\n        normalizedTicksPerWheel |= normalizedTicksPerWheel >>> 16;\n        return normalizedTicksPerWheel + 1;\n    }\n\n    /**\n     * Starts the background thread explicitly. The background thread will\n     * start automatically on demand even if you did not call this method.\n     *\n     * @throws IllegalStateException if this timer has been\n     * {@linkplain #stop() stopped} already\n     */\n    public void start() {\n        switch (WORKER_STATE_UPDATER.get(this)) {\n            case WORKER_STATE_INIT:\n                if (WORKER_STATE_UPDATER.compareAndSet(this, WORKER_STATE_INIT, WORKER_STATE_STARTED)) {\n                    workerThread.start();\n                }\n                break;\n            case WORKER_STATE_STARTED:\n                break;\n            case WORKER_STATE_SHUTDOWN:\n                throw new IllegalStateException(\"cannot be started once stopped\");\n            default:\n                throw new Error(\"Invalid WorkerState\");\n        }\n\n        // Wait until the startTime is initialized by the worker.\n        while (startTime == 0) {\n            try {\n                startTimeInitialized.await();\n            } catch (InterruptedException ignore) {\n                // Ignore - it will be ready very soon.\n            }\n        }\n    }\n\n    @Override\n    public Set<Timeout> stop() {\n        if (Thread.currentThread() == workerThread) {\n            throw new IllegalStateException(\n                HashedWheelTimer.class.getSimpleName() +\n                    \".stop() cannot be called from \" +\n                    TimerTask.class.getSimpleName());\n        }\n\n        if (!WORKER_STATE_UPDATER.compareAndSet(this, WORKER_STATE_STARTED, WORKER_STATE_SHUTDOWN)) {\n            // workerState can be 0 or 2 at this moment - let it always be 2.\n            if (WORKER_STATE_UPDATER.getAndSet(this, WORKER_STATE_SHUTDOWN) != WORKER_STATE_SHUTDOWN) {\n                INSTANCE_COUNTER.decrementAndGet();\n            }\n\n            return Collections.emptySet();\n        }\n\n        try {\n            boolean interrupted = false;\n            while (workerThread.isAlive()) {\n                workerThread.interrupt();\n                try {\n                    workerThread.join(100);\n                } catch (InterruptedException ignored) {\n                    interrupted = true;\n                }\n            }\n\n            if (interrupted) {\n                Thread.currentThread().interrupt();\n            }\n        } finally {\n            INSTANCE_COUNTER.decrementAndGet();\n        }\n        return worker.unprocessedTimeouts();\n    }\n\n    @Override\n    public boolean isStop() {\n        return WORKER_STATE_SHUTDOWN == WORKER_STATE_UPDATER.get(this);\n    }\n\n    @Override\n    public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {\n        if (task == null) {\n            throw new NullPointerException(\"task\");\n        }\n        if (unit == null) {\n            throw new NullPointerException(\"unit\");\n        }\n\n        long pendingTimeoutsCount = pendingTimeouts.incrementAndGet();\n\n        if (maxPendingTimeouts > 0 && pendingTimeoutsCount > maxPendingTimeouts) {\n            pendingTimeouts.decrementAndGet();\n            throw new RejectedExecutionException(\"Number of pending timeouts (\"\n                + pendingTimeoutsCount + \") is greater than or equal to maximum allowed pending \"\n                + \"timeouts (\" + maxPendingTimeouts + \")\");\n        }\n\n        start();\n\n        // Add the timeout to the timeout queue which will be processed on the next tick.\n        // During processing all the queued HashedWheelTimeouts will be added to the correct HashedWheelBucket.\n        long deadline = System.nanoTime() + unit.toNanos(delay) - startTime;\n\n        // Guard against overflow.\n        if (delay > 0 && deadline < 0) {\n            deadline = Long.MAX_VALUE;\n        }\n        HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline);\n        timeouts.add(timeout);\n        return timeout;\n    }\n\n    /**\n     * Returns the number of pending timeouts of this {@link Timer}.\n     */\n    public long pendingTimeouts() {\n        return pendingTimeouts.get();\n    }\n\n    private static void reportTooManyInstances() {\n        String resourceType = ClassUtils.simpleClassName(HashedWheelTimer.class);\n        logger.error(COMMON_ERROR_TOO_MANY_INSTANCES, \"\", \"\", \"You are creating too many \" + resourceType + \" instances. \" +\n            resourceType + \" is a shared resource that must be reused across the JVM, \" +\n            \"so that only a few instances are created.\");\n    }\n\n    private final class Worker implements Runnable {\n        private final Set<Timeout> unprocessedTimeouts = new HashSet<>();\n\n        private long tick;\n\n        @Override\n        public void run() {\n            // Initialize the startTime.\n            startTime = System.nanoTime();\n            if (startTime == 0) {\n                // We use 0 as an indicator for the uninitialized value here, so make sure it's not 0 when initialized.\n                startTime = 1;\n            }\n\n            // Notify the other threads waiting for the initialization at start().\n            startTimeInitialized.countDown();\n\n            do {\n                final long deadline = waitForNextTick();\n                if (deadline > 0) {\n                    int idx = (int) (tick & mask);\n                    processCancelledTasks();\n                    HashedWheelBucket bucket =\n                        wheel[idx];\n                    transferTimeoutsToBuckets();\n                    bucket.expireTimeouts(deadline);\n                    tick++;\n                }\n            } while (WORKER_STATE_UPDATER.get(HashedWheelTimer.this) == WORKER_STATE_STARTED);\n\n            // Fill the unprocessedTimeouts so we can return them from stop() method.\n            for (HashedWheelBucket bucket : wheel) {\n                bucket.clearTimeouts(unprocessedTimeouts);\n            }\n            for (; ; ) {\n                HashedWheelTimeout timeout = timeouts.poll();\n                if (timeout == null) {\n                    break;\n                }\n                if (!timeout.isCancelled()) {\n                    unprocessedTimeouts.add(timeout);\n                }\n            }\n            processCancelledTasks();\n        }\n\n        private void transferTimeoutsToBuckets() {\n            // transfer only max. 100000 timeouts per tick to prevent a thread to stale the workerThread when it just\n            // adds new timeouts in a loop.\n            for (int i = 0; i < 100000; i++) {\n                HashedWheelTimeout timeout = timeouts.poll();\n                if (timeout == null) {\n                    // all processed\n                    break;\n                }\n                if (timeout.state() == HashedWheelTimeout.ST_CANCELLED) {\n                    // Was cancelled in the meantime.\n                    continue;\n                }\n\n                long calculated = timeout.deadline / tickDuration;\n                timeout.remainingRounds = (calculated - tick) / wheel.length;\n\n                // Ensure we don't schedule for past.\n                final long ticks = Math.max(calculated, tick);\n                int stopIndex = (int) (ticks & mask);\n\n                HashedWheelBucket bucket = wheel[stopIndex];\n                bucket.addTimeout(timeout);\n            }\n        }\n\n        private void processCancelledTasks() {\n            for (; ; ) {\n                HashedWheelTimeout timeout = cancelledTimeouts.poll();\n                if (timeout == null) {\n                    // all processed\n                    break;\n                }\n                try {\n                    timeout.remove();\n                } catch (Throwable t) {\n                    if (logger.isWarnEnabled()) {\n                        logger.warn(COMMON_ERROR_RUN_THREAD_TASK, \"\", \"\", \"An exception was thrown while process a cancellation task\", t);\n                    }\n                }\n            }\n        }\n\n        /**\n         * calculate goal nanoTime from startTime and current tick number,\n         * then wait until that goal has been reached.\n         *\n         * @return Long.MIN_VALUE if received a shutdown request,\n         * current time otherwise (with Long.MIN_VALUE changed by +1)\n         */\n        private long waitForNextTick() {\n            long deadline = tickDuration * (tick + 1);\n\n            for (; ; ) {\n                final long currentTime = System.nanoTime() - startTime;\n                long sleepTimeMs = (deadline - currentTime + 999999) / 1000000;\n\n                if (sleepTimeMs <= 0) {\n                    if (currentTime == Long.MIN_VALUE) {\n                        return -Long.MAX_VALUE;\n                    } else {\n                        return currentTime;\n                    }\n                }\n                if (isWindows()) {\n                    sleepTimeMs = sleepTimeMs / 10 * 10;\n                }\n\n                try {\n                    Thread.sleep(sleepTimeMs);\n                } catch (InterruptedException ignored) {\n                    if (WORKER_STATE_UPDATER.get(HashedWheelTimer.this) == WORKER_STATE_SHUTDOWN) {\n                        return Long.MIN_VALUE;\n                    }\n                }\n            }\n        }\n\n        Set<Timeout> unprocessedTimeouts() {\n            return Collections.unmodifiableSet(unprocessedTimeouts);\n        }\n    }\n\n    private static final class HashedWheelTimeout implements Timeout {\n\n        private static final int ST_INIT = 0;\n        private static final int ST_CANCELLED = 1;\n        private static final int ST_EXPIRED = 2;\n        private static final AtomicIntegerFieldUpdater<HashedWheelTimeout> STATE_UPDATER =\n            AtomicIntegerFieldUpdater.newUpdater(HashedWheelTimeout.class, \"state\");\n\n        private final HashedWheelTimer timer;\n        private final TimerTask task;\n        private final long deadline;\n\n        @SuppressWarnings({\"unused\", \"FieldMayBeFinal\", \"RedundantFieldInitialization\"})\n        private volatile int state = ST_INIT;\n\n        /**\n         * RemainingRounds will be calculated and set by Worker.transferTimeoutsToBuckets() before the\n         * HashedWheelTimeout will be added to the correct HashedWheelBucket.\n         */\n        long remainingRounds;\n\n        /**\n         * This will be used to chain timeouts in HashedWheelTimerBucket via a double-linked-list.\n         * As only the workerThread will act on it there is no need for synchronization / volatile.\n         */\n        HashedWheelTimeout next;\n        HashedWheelTimeout prev;\n\n        /**\n         * The bucket to which the timeout was added\n         */\n        HashedWheelBucket bucket;\n\n        HashedWheelTimeout(HashedWheelTimer timer, TimerTask task, long deadline) {\n            this.timer = timer;\n            this.task = task;\n            this.deadline = deadline;\n        }\n\n        @Override\n        public Timer timer() {\n            return timer;\n        }\n\n        @Override\n        public TimerTask task() {\n            return task;\n        }\n\n        @Override\n        public boolean cancel() {\n            // only update the state it will be removed from HashedWheelBucket on next tick.\n            if (!compareAndSetState(ST_INIT, ST_CANCELLED)) {\n                return false;\n            }\n            // If a task should be canceled we put this to another queue which will be processed on each tick.\n            // So this means that we will have a GC latency of max. 1 tick duration which is good enough. This way we\n            // can make again use of our LinkedBlockingQueue and so minimize the locking / overhead as much as possible.\n            timer.cancelledTimeouts.add(this);\n            return true;\n        }\n\n        void remove() {\n            HashedWheelBucket bucket = this.bucket;\n            if (bucket != null) {\n                bucket.remove(this);\n            } else {\n                timer.pendingTimeouts.decrementAndGet();\n            }\n        }\n\n        public boolean compareAndSetState(int expected, int state) {\n            return STATE_UPDATER.compareAndSet(this, expected, state);\n        }\n\n        public int state() {\n            return state;\n        }\n\n        @Override\n        public boolean isCancelled() {\n            return state() == ST_CANCELLED;\n        }\n\n        @Override\n        public boolean isExpired() {\n            return state() == ST_EXPIRED;\n        }\n\n        public void expire() {\n            if (!compareAndSetState(ST_INIT, ST_EXPIRED)) {\n                return;\n            }\n\n            try {\n                task.run(this);\n            } catch (Throwable t) {\n                if (logger.isWarnEnabled()) {\n                    logger.warn(COMMON_ERROR_RUN_THREAD_TASK, \"\", \"\", \"An exception was thrown by \" + TimerTask.class.getSimpleName() + '.', t);\n                }\n            }\n        }\n\n        @Override\n        public String toString() {\n            final long currentTime = System.nanoTime();\n            long remaining = deadline - currentTime + timer.startTime;\n            String simpleClassName = ClassUtils.simpleClassName(this.getClass());\n\n            StringBuilder buf = new StringBuilder(192)\n                .append(simpleClassName)\n                .append('(')\n                .append(\"deadline: \");\n            if (remaining > 0) {\n                buf.append(remaining)\n                    .append(\" ns later\");\n            } else if (remaining < 0) {\n                buf.append(-remaining)\n                    .append(\" ns ago\");\n            } else {\n                buf.append(\"now\");\n            }\n\n            if (isCancelled()) {\n                buf.append(\", cancelled\");\n            }\n\n            return buf.append(\", task: \")\n                .append(task())\n                .append(')')\n                .toString();\n        }\n    }\n\n    /**\n     * Bucket that stores HashedWheelTimeouts. These are stored in a linked-list like datastructure to allow easy\n     * removal of HashedWheelTimeouts in the middle. Also the HashedWheelTimeout act as nodes themself and so no\n     * extra object creation is needed.\n     */\n    private static final class HashedWheelBucket {\n\n        /**\n         * Used for the linked-list data structure\n         */\n        private HashedWheelTimeout head;\n        private HashedWheelTimeout tail;\n\n        /**\n         * Add {@link HashedWheelTimeout} to this bucket.\n         */\n        void addTimeout(HashedWheelTimeout timeout) {\n            assert timeout.bucket == null;\n            timeout.bucket = this;\n            if (head == null) {\n                head = tail = timeout;\n            } else {\n                tail.next = timeout;\n                timeout.prev = tail;\n                tail = timeout;\n            }\n        }\n\n        /**\n         * Expire all {@link HashedWheelTimeout}s for the given {@code deadline}.\n         */\n        void expireTimeouts(long deadline) {\n            HashedWheelTimeout timeout = head;\n\n            // process all timeouts\n            while (timeout != null) {\n                HashedWheelTimeout next = timeout.next;\n                if (timeout.remainingRounds <= 0) {\n                    next = remove(timeout);\n                    if (timeout.deadline <= deadline) {\n                        timeout.expire();\n                    } else {\n                        // The timeout was placed into a wrong slot. This should never happen.\n                        throw new IllegalStateException(String.format(\n                            \"timeout.deadline (%d) > deadline (%d)\", timeout.deadline, deadline));\n                    }\n                } else if (timeout.isCancelled()) {\n                    next = remove(timeout);\n                } else {\n                    timeout.remainingRounds--;\n                }\n                timeout = next;\n            }\n        }\n\n        public HashedWheelTimeout remove(HashedWheelTimeout timeout) {\n            HashedWheelTimeout next = timeout.next;\n            // remove timeout that was either processed or cancelled by updating the linked-list\n            if (timeout.prev != null) {\n                timeout.prev.next = next;\n            }\n            if (timeout.next != null) {\n                timeout.next.prev = timeout.prev;\n            }\n\n            if (timeout == head) {\n                // if timeout is also the tail we need to adjust the entry too\n                if (timeout == tail) {\n                    tail = null;\n                    head = null;\n                } else {\n                    head = next;\n                }\n            } else if (timeout == tail) {\n                // if the timeout is the tail modify the tail to be the prev node.\n                tail = timeout.prev;\n            }\n            // null out prev, next and bucket to allow for GC.\n            timeout.prev = null;\n            timeout.next = null;\n            timeout.bucket = null;\n            timeout.timer.pendingTimeouts.decrementAndGet();\n            return next;\n        }\n\n        /**\n         * Clear this bucket and return all not expired / cancelled {@link Timeout}s.\n         */\n        void clearTimeouts(Set<Timeout> set) {\n            for (; ; ) {\n                HashedWheelTimeout timeout = pollTimeout();\n                if (timeout == null) {\n                    return;\n                }\n                if (timeout.isExpired() || timeout.isCancelled()) {\n                    continue;\n                }\n                set.add(timeout);\n            }\n        }\n\n        private HashedWheelTimeout pollTimeout() {\n            HashedWheelTimeout head = this.head;\n            if (head == null) {\n                return null;\n            }\n            HashedWheelTimeout next = head.next;\n            if (next == null) {\n                tail = this.head = null;\n            } else {\n                this.head = next;\n                next.prev = null;\n            }\n\n            // null out prev and next to allow for GC.\n            head.next = null;\n            head.prev = null;\n            head.bucket = null;\n            return head;\n        }\n    }\n\n    private static final boolean IS_OS_WINDOWS = SystemPropertyConfigUtils.getSystemProperty(SYSTEM_OS_NAME, \"\").toLowerCase(Locale.US).contains(OS_WIN_PREFIX);\n\n    private boolean isWindows() {\n        return IS_OS_WINDOWS;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/timer/Timeout.java",
    "content": "/*\n * Copyright 2012 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"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, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage org.apache.dubbo.common.timer;\n\n/**\n * A handle associated with a {@link TimerTask} that is returned by a\n * {@link Timer}.\n */\npublic interface Timeout {\n\n    /**\n     * Returns the {@link Timer} that created this handle.\n     */\n    Timer timer();\n\n    /**\n     * Returns the {@link TimerTask} which is associated with this handle.\n     */\n    TimerTask task();\n\n    /**\n     * Returns {@code true} if and only if the {@link TimerTask} associated\n     * with this handle has been expired.\n     */\n    boolean isExpired();\n\n    /**\n     * Returns {@code true} if and only if the {@link TimerTask} associated\n     * with this handle has been cancelled.\n     */\n    boolean isCancelled();\n\n    /**\n     * Attempts to cancel the {@link TimerTask} associated with this handle.\n     * If the task has been executed or cancelled already, it will return with\n     * no side effect.\n     *\n     * @return True if the cancellation completed successfully, otherwise false\n     */\n    boolean cancel();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/timer/Timer.java",
    "content": "/*\n * Copyright 2012 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"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, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage org.apache.dubbo.common.timer;\n\nimport java.util.Set;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Schedules {@link TimerTask}s for one-time future execution in a background\n * thread.\n */\npublic interface Timer {\n\n    /**\n     * Schedules the specified {@link TimerTask} for one-time execution after\n     * the specified delay.\n     *\n     * @return a handle which is associated with the specified task\n     * @throws IllegalStateException      if this timer has been {@linkplain #stop() stopped} already\n     * @throws RejectedExecutionException if the pending timeouts are too many and creating new timeout\n     *                                    can cause instability in the system.\n     */\n    Timeout newTimeout(TimerTask task, long delay, TimeUnit unit);\n\n    /**\n     * Releases all resources acquired by this {@link Timer} and cancels all\n     * tasks which were scheduled but not executed yet.\n     *\n     * @return the handles associated with the tasks which were canceled by\n     * this method\n     */\n    Set<Timeout> stop();\n\n    /**\n     * the timer is stop\n     *\n     * @return true for stop\n     */\n    boolean isStop();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/timer/TimerTask.java",
    "content": "/*\n * Copyright 2012 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"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, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage org.apache.dubbo.common.timer;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * A task which is executed after the delay specified with\n * {@link Timer#newTimeout(TimerTask, long, TimeUnit)} (TimerTask, long, TimeUnit)}.\n */\npublic interface TimerTask {\n\n    /**\n     * Executed after the delay specified with\n     * {@link Timer#newTimeout(TimerTask, long, TimeUnit)}.\n     *\n     * @param timeout a handle which is associated with this task\n     */\n    void run(Timeout timeout) throws Exception;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/DubboServiceAddressURL.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\n\npublic class DubboServiceAddressURL extends ServiceAddressURL {\n\n    public static DubboServiceAddressURL valueOf(String rawURL, URL consumerURL) {\n        return valueOf(rawURL, consumerURL, null);\n    }\n\n    public static DubboServiceAddressURL valueOf(String rawURL, URL consumerURL, ServiceConfigURL overriddenURL) {\n        URL url = valueOf(rawURL, true);\n        return new DubboServiceAddressURL(url.getUrlAddress(), url.getUrlParam(), consumerURL, overriddenURL);\n    }\n\n    private ServiceConfigURL overrideURL;\n\n    public DubboServiceAddressURL(\n            URLAddress urlAddress, URLParam urlParam, URL consumerURL, ServiceConfigURL overrideURL) {\n        super(urlAddress, urlParam, consumerURL);\n        this.overrideURL = overrideURL;\n    }\n\n    @Override\n    protected <T extends URL> T newURL(URLAddress urlAddress, URLParam urlParam) {\n        return (T) new DubboServiceAddressURL(urlAddress, urlParam, this.consumerURL, this.overrideURL);\n    }\n\n    @Override\n    public String getSide() {\n        return consumerURL.getParameter(SIDE_KEY);\n    }\n\n    @Override\n    public String getParameter(String key) {\n        String value = null;\n        if (overrideURL != null) {\n            value = overrideURL.getParameter(key);\n        }\n        if (StringUtils.isEmpty(value)) {\n            value = super.getParameter(key);\n        }\n        return value;\n    }\n\n    @Override\n    public String getMethodParameter(String method, String key) {\n        String value = null;\n        if (overrideURL != null) {\n            value = overrideURL.getMethodParameterStrict(method, key);\n        }\n        if (StringUtils.isEmpty(value)) {\n            value = super.getMethodParameter(method, key);\n        }\n        return value;\n    }\n\n    @Override\n    public String getAnyMethodParameter(String key) {\n        String value = null;\n        if (overrideURL != null) {\n            value = overrideURL.getAnyMethodParameter(key);\n        }\n        if (StringUtils.isEmpty(value)) {\n            value = super.getAnyMethodParameter(key);\n        }\n        return value;\n    }\n\n    /**\n     * The returned parameters is imprecise regarding override priorities of consumer url and provider url.\n     * This method is only used to pass the configuration in the 'client'.\n     */\n    @Override\n    public Map<String, String> getAllParameters() {\n        Map<String, String> allParameters =\n                new HashMap<>((int) (super.getParameters().size() / .75 + 1));\n        allParameters.putAll(super.getParameters());\n        if (consumerURL != null) {\n            allParameters.putAll(consumerURL.getParameters());\n        }\n        if (overrideURL != null) {\n            allParameters.putAll(overrideURL.getParameters());\n        }\n        return Collections.unmodifiableMap(allParameters);\n    }\n\n    public ServiceConfigURL getOverrideURL() {\n        return overrideURL;\n    }\n\n    public void setOverrideURL(ServiceConfigURL overrideURL) {\n        this.overrideURL = overrideURL;\n    }\n\n    @Override\n    public ScopeModel getScopeModel() {\n        return consumerURL.getScopeModel();\n    }\n\n    @Override\n    public ServiceModel getServiceModel() {\n        return consumerURL.getServiceModel();\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        return prime * super.hashCode() + (overrideURL == null ? 0 : overrideURL.hashCode());\n    }\n\n    /**\n     * ignore consumer url compare.\n     * It's only meaningful for comparing two AddressURLs related to the same consumerURL.\n     *\n     * @param obj\n     * @return\n     */\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof DubboServiceAddressURL)) {\n            return false;\n        }\n        if (overrideURL == null) {\n            return super.equals(obj);\n        } else {\n            DubboServiceAddressURL other = (DubboServiceAddressURL) obj;\n            boolean overrideEquals = Objects.equals(\n                    overrideURL.getParameters(), other.getOverrideURL().getParameters());\n            if (!overrideEquals) {\n                return false;\n            }\n\n            Map<String, String> params = this.getParameters();\n            for (Map.Entry<String, String> entry : params.entrySet()) {\n                String key = entry.getKey();\n                if (overrideURL.getParameters().containsKey(key)) {\n                    continue;\n                }\n                if (!entry.getValue().equals(other.getUrlParam().getParameter(key))) {\n                    return false;\n                }\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/PathURLAddress.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component;\n\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Objects;\n\npublic class PathURLAddress extends URLAddress {\n    private String protocol;\n    private String username;\n    private String password;\n    private String path;\n\n    private transient String address;\n    private transient String ip;\n\n    public PathURLAddress(String protocol, String username, String password, String path, String host, int port) {\n        this(protocol, username, password, path, host, port, null);\n    }\n\n    public PathURLAddress(\n            String protocol, String username, String password, String path, String host, int port, String rawAddress) {\n        super(host, port, rawAddress);\n\n        this.protocol = protocol;\n        this.username = username;\n        this.password = password;\n\n        // trim the beginning \"/\"\n        while (path != null && path.startsWith(\"/\")) {\n            path = path.substring(1);\n        }\n        if (path != null) {\n            path = path.intern();\n        }\n        this.path = path;\n    }\n\n    public String getProtocol() {\n        return protocol;\n    }\n\n    public URLAddress setProtocol(String protocol) {\n        return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public URLAddress setUsername(String username) {\n        return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public PathURLAddress setPassword(String password) {\n        return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);\n    }\n\n    public String getPath() {\n        return path;\n    }\n\n    public PathURLAddress setPath(String path) {\n        return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);\n    }\n\n    @Override\n    public URLAddress setHost(String host) {\n        return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);\n    }\n\n    @Override\n    public URLAddress setPort(int port) {\n        return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);\n    }\n\n    @Override\n    public URLAddress setAddress(String host, int port) {\n        return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);\n    }\n\n    public String getAddress() {\n        if (address == null) {\n            address = getAddress(getHost(), getPort());\n        }\n        return address;\n    }\n\n    /**\n     * Fetch IP address for this URL.\n     * <p>\n     * Pls. note that IP should be used instead of Host when to compare with socket's address or to search in a map\n     * which use address as its key.\n     *\n     * @return ip in string format\n     */\n    public String getIp() {\n        if (ip == null) {\n            ip = NetUtils.getIpByHost(getHost());\n        }\n        return ip;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(protocol, username, password, path, host, port);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (!(obj instanceof URLAddress)) return false;\n        URLAddress that = (URLAddress) obj;\n        return Objects.equals(this.getProtocol(), that.getProtocol())\n                && Objects.equals(this.getUsername(), that.getUsername())\n                && Objects.equals(this.getPassword(), that.getPassword())\n                && Objects.equals(this.getPath(), that.getPath())\n                && Objects.equals(this.getHost(), that.getHost())\n                && Objects.equals(this.getPort(), that.getPort());\n    }\n\n    @Override\n    public String toString() {\n        if (rawAddress != null) {\n            return rawAddress;\n        }\n\n        StringBuilder buf = new StringBuilder();\n        if (StringUtils.isNotEmpty(protocol)) {\n            buf.append(protocol);\n            buf.append(\"://\");\n        }\n        //\n        //        if (StringUtils.isNotEmpty(username)) {\n        //            buf.append(username);\n        //            if (StringUtils.isNotEmpty(password)) {\n        //                buf.append(\":\");\n        //                buf.append(password);\n        //            }\n        //            buf.append(\"@\");\n        //        }\n\n        if (StringUtils.isNotEmpty(host)) {\n            buf.append(host);\n            if (port > 0) {\n                buf.append(':');\n                buf.append(port);\n            }\n        }\n\n        if (StringUtils.isNotEmpty(path)) {\n            buf.append('/');\n            buf.append(path);\n        }\n\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceAddressURL.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;\n\npublic abstract class ServiceAddressURL extends URL {\n    protected final transient URL consumerURL;\n\n    // cache\n    private transient Map<String, String> concatenatedPrams;\n    //    private transient Map<String, String> allParameters;\n\n    public ServiceAddressURL(\n            String protocol,\n            String username,\n            String password,\n            String host,\n            int port,\n            String path,\n            Map<String, String> parameters,\n            URL consumerURL) {\n        super(protocol, username, password, host, port, path, parameters);\n        this.consumerURL = consumerURL;\n    }\n\n    public ServiceAddressURL(URLAddress urlAddress, URLParam urlParam, URL consumerURL) {\n        super(urlAddress, urlParam);\n        this.consumerURL = consumerURL;\n    }\n\n    @Override\n    public String getPath() {\n        String path = super.getPath();\n        if (StringUtils.isNotEmpty(path)) {\n            return path;\n        }\n        return consumerURL.getPath();\n    }\n\n    @Override\n    public String getServiceInterface() {\n        return consumerURL.getServiceInterface();\n    }\n\n    @Override\n    public String getApplication() {\n        return consumerURL.getApplication();\n    }\n\n    @Override\n    public String getRemoteApplication() {\n        return super.getParameter(APPLICATION_KEY);\n    }\n\n    @Override\n    public String getGroup() {\n        return super.getParameter(GROUP_KEY);\n    }\n\n    @Override\n    public String getVersion() {\n        return super.getParameter(VERSION_KEY);\n    }\n\n    @Override\n    public String getOriginalParameter(String key) {\n        // call corresponding methods directly, then we can remove the following if branches.\n        if (GROUP_KEY.equals(key)) {\n            return getGroup();\n        } else if (VERSION_KEY.equals(key)) {\n            return getVersion();\n        } else if (APPLICATION_KEY.equals(key)) {\n            return getRemoteApplication();\n        } else if (SIDE_KEY.equals(key)) {\n            return getSide();\n        } else if (CATEGORY_KEY.equals(key)) {\n            return getCategory();\n        }\n        return super.getParameter(key);\n    }\n\n    @Override\n    public String getParameter(String key) {\n        // call corresponding methods directly, then we can remove the following if branches.\n        if (GROUP_KEY.equals(key)) {\n            return getGroup();\n        } else if (VERSION_KEY.equals(key)) {\n            return getVersion();\n        } else if (APPLICATION_KEY.equals(key)) {\n            return getRemoteApplication();\n        } else if (SIDE_KEY.equals(key)) {\n            return getSide();\n        } else if (CATEGORY_KEY.equals(key)) {\n            return getCategory();\n        }\n        String value = null;\n        if (consumerURL != null) {\n            value = consumerURL.getParameter(key);\n        }\n        if (StringUtils.isEmpty(value)) {\n            value = super.getParameter(key);\n        }\n        return value;\n    }\n\n    @Override\n    public String getMethodParameter(String method, String key) {\n        String value = null;\n        if (consumerURL != null) {\n            value = consumerURL.getMethodParameterStrict(method, key);\n        }\n        if (StringUtils.isEmpty(value)) {\n            value = super.getMethodParameterStrict(method, key);\n        }\n        if (StringUtils.isEmpty(value)) {\n            value = getParameter(key);\n        }\n        return value;\n    }\n\n    @Override\n    public String getAnyMethodParameter(String key) {\n        String value = null;\n        if (consumerURL != null) {\n            value = consumerURL.getAnyMethodParameter(key);\n        }\n        if (StringUtils.isEmpty(value)) {\n            value = super.getAnyMethodParameter(key);\n        }\n        return value;\n    }\n\n    @Override\n    public String getConcatenatedParameter(String key) {\n        if (concatenatedPrams == null) {\n            concatenatedPrams = new HashMap<>(1);\n        }\n        String value = concatenatedPrams.get(key);\n        if (StringUtils.isNotEmpty(value)) {\n            return value;\n        }\n\n        // Combine filters and listeners on Provider and Consumer\n        String remoteValue = super.getParameter(key);\n        String localValue = consumerURL.getParameter(key);\n        if (remoteValue != null && remoteValue.length() > 0 && localValue != null && localValue.length() > 0) {\n            value = remoteValue + \",\" + localValue;\n            concatenatedPrams.put(key, value);\n            return value;\n        }\n        if (localValue != null && localValue.length() > 0) {\n            value = localValue;\n        } else if (remoteValue != null && remoteValue.length() > 0) {\n            value = remoteValue;\n        }\n        concatenatedPrams.put(key, value);\n        return value;\n    }\n\n    @Override\n    public String getCategory() {\n        return PROVIDERS_CATEGORY;\n    }\n\n    @Override\n    public String getSide() {\n        return CONSUMER_SIDE;\n    }\n\n    public URL getConsumerURL() {\n        return consumerURL;\n    }\n\n    @Override\n    public int hashCode() {\n        return super.hashCode();\n    }\n\n    @Override\n    public ScopeModel getScopeModel() {\n        return consumerURL.getScopeModel();\n    }\n\n    @Override\n    public ServiceModel getServiceModel() {\n        return consumerURL.getServiceModel();\n    }\n\n    @Override\n    public URL setScopeModel(ScopeModel scopeModel) {\n        throw new UnsupportedOperationException(\"setScopeModel is forbidden for ServiceAddressURL\");\n    }\n\n    @Override\n    public URL setServiceModel(ServiceModel serviceModel) {\n        throw new UnsupportedOperationException(\"setServiceModel is forbidden for ServiceAddressURL\");\n    }\n\n    /**\n     * ignore consumer url compare.\n     * It's only meaningful for comparing two address urls related to the same consumerURL.\n     *\n     * @param obj\n     * @return\n     */\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof ServiceAddressURL)) {\n            return false;\n        }\n        return super.equals(obj);\n    }\n\n    @Override\n    public String toString() {\n        URLParam totalParam = getUrlParam().addParametersIfAbsent(consumerURL.getParameters());\n        return new ServiceConfigURL(getUrlAddress(), totalParam, null).toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceConfigURL.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\npublic class ServiceConfigURL extends URL {\n\n    private transient volatile ConcurrentMap<String, URL> urls;\n    private transient volatile ConcurrentMap<String, Number> numbers;\n    private transient volatile ConcurrentMap<String, Map<String, Number>> methodNumbers;\n    private transient volatile String full;\n    private transient volatile String string;\n    private transient volatile String identity;\n    private transient volatile String parameter;\n\n    public ServiceConfigURL() {\n        super();\n    }\n\n    public ServiceConfigURL(URLAddress urlAddress, URLParam urlParam, Map<String, Object> attributes) {\n        super(urlAddress, urlParam, attributes);\n    }\n\n    public ServiceConfigURL(String protocol, String host, int port) {\n        this(protocol, null, null, host, port, null, (Map<String, String>) null);\n    }\n\n    public ServiceConfigURL(\n            String protocol,\n            String host,\n            int port,\n            String[] pairs) { // varargs ... conflict with the following path argument, use array instead.\n        this(protocol, null, null, host, port, null, CollectionUtils.toStringMap(pairs));\n    }\n\n    public ServiceConfigURL(String protocol, String host, int port, Map<String, String> parameters) {\n        this(protocol, null, null, host, port, null, parameters);\n    }\n\n    public ServiceConfigURL(String protocol, String host, int port, String path) {\n        this(protocol, null, null, host, port, path, (Map<String, String>) null);\n    }\n\n    public ServiceConfigURL(String protocol, String host, int port, String path, String... pairs) {\n        this(protocol, null, null, host, port, path, CollectionUtils.toStringMap(pairs));\n    }\n\n    public ServiceConfigURL(String protocol, String host, int port, String path, Map<String, String> parameters) {\n        this(protocol, null, null, host, port, path, parameters);\n    }\n\n    public ServiceConfigURL(String protocol, String username, String password, String host, int port, String path) {\n        this(protocol, username, password, host, port, path, (Map<String, String>) null);\n    }\n\n    public ServiceConfigURL(\n            String protocol, String username, String password, String host, int port, String path, String... pairs) {\n        this(protocol, username, password, host, port, path, CollectionUtils.toStringMap(pairs));\n    }\n\n    public ServiceConfigURL(\n            String protocol,\n            String username,\n            String password,\n            String host,\n            int port,\n            String path,\n            Map<String, String> parameters) {\n        this(new PathURLAddress(protocol, username, password, path, host, port), URLParam.parse(parameters), null);\n    }\n\n    public ServiceConfigURL(\n            String protocol,\n            String username,\n            String password,\n            String host,\n            int port,\n            String path,\n            Map<String, String> parameters,\n            Map<String, Object> attributes) {\n        this(\n                new PathURLAddress(protocol, username, password, path, host, port),\n                URLParam.parse(parameters),\n                attributes);\n    }\n\n    @Override\n    protected <T extends URL> T newURL(URLAddress urlAddress, URLParam urlParam) {\n        return (T) new ServiceConfigURL(urlAddress, urlParam, attributes);\n    }\n\n    @Override\n    public URL addAttributes(Map<String, Object> attributeMap) {\n        Map<String, Object> newAttributes = new HashMap<>();\n        if (this.attributes != null) {\n            newAttributes.putAll(this.attributes);\n        }\n        newAttributes.putAll(attributeMap);\n        return new ServiceConfigURL(getUrlAddress(), getUrlParam(), newAttributes);\n    }\n\n    @Override\n    public ServiceConfigURL putAttribute(String key, Object obj) {\n        Map<String, Object> newAttributes = new HashMap<>();\n        if (attributes != null) {\n            newAttributes.putAll(attributes);\n        }\n        newAttributes.put(key, obj);\n        return new ServiceConfigURL(getUrlAddress(), getUrlParam(), newAttributes);\n    }\n\n    @Override\n    public URL removeAttribute(String key) {\n        Map<String, Object> newAttributes = new HashMap<>();\n        if (attributes != null) {\n            newAttributes.putAll(attributes);\n        }\n        newAttributes.remove(key);\n        return new ServiceConfigURL(getUrlAddress(), getUrlParam(), newAttributes);\n    }\n\n    @Override\n    public String toString() {\n        if (string != null) {\n            return string;\n        }\n        return string = super.toString();\n    }\n\n    @Override\n    public String toFullString() {\n        if (full != null) {\n            return full;\n        }\n        return full = super.toFullString();\n    }\n\n    @Override\n    public String toIdentityString() {\n        if (identity != null) {\n            return identity;\n        }\n        return identity = super.toIdentityString();\n    }\n\n    @Override\n    public String toParameterString() {\n        if (parameter != null) {\n            return parameter;\n        }\n        return parameter = super.toParameterString();\n    }\n\n    @Override\n    public URL getUrlParameter(String key) {\n        URL u = getUrls().get(key);\n        if (u != null) {\n            return u;\n        }\n        String value = getParameterAndDecoded(key);\n        if (StringUtils.isEmpty(value)) {\n            return null;\n        }\n        u = URL.valueOf(value);\n        getUrls().put(key, u);\n        return u;\n    }\n\n    @Override\n    public double getParameter(String key, double defaultValue) {\n        Number n = getNumbers().get(key);\n        if (n != null) {\n            return n.doubleValue();\n        }\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        double d = Double.parseDouble(value);\n        getNumbers().put(key, d);\n        return d;\n    }\n\n    @Override\n    public float getParameter(String key, float defaultValue) {\n        Number n = getNumbers().get(key);\n        if (n != null) {\n            return n.floatValue();\n        }\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        float f = Float.parseFloat(value);\n        getNumbers().put(key, f);\n        return f;\n    }\n\n    @Override\n    public long getParameter(String key, long defaultValue) {\n        Number n = getNumbers().get(key);\n        if (n != null) {\n            return n.longValue();\n        }\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        long l = Long.parseLong(value);\n        getNumbers().put(key, l);\n        return l;\n    }\n\n    @Override\n    public int getParameter(String key, int defaultValue) {\n        Number n = getNumbers().get(key);\n        if (n != null) {\n            return n.intValue();\n        }\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        int i = Integer.parseInt(value);\n        getNumbers().put(key, i);\n        return i;\n    }\n\n    @Override\n    public short getParameter(String key, short defaultValue) {\n        Number n = getNumbers().get(key);\n        if (n != null) {\n            return n.shortValue();\n        }\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        short s = Short.parseShort(value);\n        getNumbers().put(key, s);\n        return s;\n    }\n\n    @Override\n    public byte getParameter(String key, byte defaultValue) {\n        Number n = getNumbers().get(key);\n        if (n != null) {\n            return n.byteValue();\n        }\n        String value = getParameter(key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        byte b = Byte.parseByte(value);\n        getNumbers().put(key, b);\n        return b;\n    }\n\n    @Override\n    public double getMethodParameter(String method, String key, double defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.doubleValue();\n        }\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        double d = Double.parseDouble(value);\n        updateCachedNumber(method, key, d);\n        return d;\n    }\n\n    @Override\n    public float getMethodParameter(String method, String key, float defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.floatValue();\n        }\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        float f = Float.parseFloat(value);\n        updateCachedNumber(method, key, f);\n        return f;\n    }\n\n    @Override\n    public long getMethodParameter(String method, String key, long defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.longValue();\n        }\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        long l = Long.parseLong(value);\n        updateCachedNumber(method, key, l);\n        return l;\n    }\n\n    @Override\n    public int getMethodParameter(String method, String key, int defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.intValue();\n        }\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        int i = Integer.parseInt(value);\n        updateCachedNumber(method, key, i);\n        return i;\n    }\n\n    @Override\n    public short getMethodParameter(String method, String key, short defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.shortValue();\n        }\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        short s = Short.parseShort(value);\n        updateCachedNumber(method, key, s);\n        return s;\n    }\n\n    @Override\n    public byte getMethodParameter(String method, String key, byte defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.byteValue();\n        }\n        String value = getMethodParameter(method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        byte b = Byte.parseByte(value);\n        updateCachedNumber(method, key, b);\n        return b;\n    }\n\n    @Override\n    public double getServiceParameter(String service, String key, double defaultValue) {\n        Number n = getServiceNumbers(service).get(key);\n        if (n != null) {\n            return n.doubleValue();\n        }\n        String value = getServiceParameter(service, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        double d = Double.parseDouble(value);\n        getNumbers().put(key, d);\n        return d;\n    }\n\n    @Override\n    public float getServiceParameter(String service, String key, float defaultValue) {\n        Number n = getServiceNumbers(service).get(key);\n        if (n != null) {\n            return n.floatValue();\n        }\n        String value = getServiceParameter(service, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        float f = Float.parseFloat(value);\n        getNumbers().put(key, f);\n        return f;\n    }\n\n    @Override\n    public long getServiceParameter(String service, String key, long defaultValue) {\n        Number n = getServiceNumbers(service).get(key);\n        if (n != null) {\n            return n.longValue();\n        }\n        String value = getServiceParameter(service, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        long l = Long.parseLong(value);\n        getNumbers().put(key, l);\n        return l;\n    }\n\n    @Override\n    public short getServiceParameter(String service, String key, short defaultValue) {\n        Number n = getServiceNumbers(service).get(key);\n        if (n != null) {\n            return n.shortValue();\n        }\n        String value = getServiceParameter(service, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        short s = Short.parseShort(value);\n        getNumbers().put(key, s);\n        return s;\n    }\n\n    @Override\n    public byte getServiceParameter(String service, String key, byte defaultValue) {\n        Number n = getServiceNumbers(service).get(key);\n        if (n != null) {\n            return n.byteValue();\n        }\n        String value = getServiceParameter(service, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        byte b = Byte.parseByte(value);\n        getNumbers().put(key, b);\n        return b;\n    }\n\n    @Override\n    public double getServiceMethodParameter(String service, String method, String key, double defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.doubleValue();\n        }\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        double d = Double.parseDouble(value);\n        updateCachedNumber(method, key, d);\n        return d;\n    }\n\n    @Override\n    public float getServiceMethodParameter(String service, String method, String key, float defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.floatValue();\n        }\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        float f = Float.parseFloat(value);\n        updateCachedNumber(method, key, f);\n        return f;\n    }\n\n    @Override\n    public long getServiceMethodParameter(String service, String method, String key, long defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.longValue();\n        }\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        long l = Long.parseLong(value);\n        updateCachedNumber(method, key, l);\n        return l;\n    }\n\n    @Override\n    public int getServiceMethodParameter(String service, String method, String key, int defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.intValue();\n        }\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        int i = Integer.parseInt(value);\n        updateCachedNumber(method, key, i);\n        return i;\n    }\n\n    @Override\n    public short getServiceMethodParameter(String service, String method, String key, short defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.shortValue();\n        }\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        short s = Short.parseShort(value);\n        updateCachedNumber(method, key, s);\n        return s;\n    }\n\n    @Override\n    public byte getServiceMethodParameter(String service, String method, String key, byte defaultValue) {\n        Number n = getCachedNumber(method, key);\n        if (n != null) {\n            return n.byteValue();\n        }\n        String value = getServiceMethodParameter(service, method, key);\n        if (StringUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        byte b = Byte.parseByte(value);\n        updateCachedNumber(method, key, b);\n        return b;\n    }\n\n    private Map<String, URL> getUrls() {\n        // concurrent initialization is tolerant\n        if (urls == null) {\n            urls = new ConcurrentHashMap<>();\n        }\n        return urls;\n    }\n\n    protected Map<String, Number> getNumbers() {\n        // concurrent initialization is tolerant\n        if (numbers == null) {\n            numbers = new ConcurrentHashMap<>();\n        }\n        return numbers;\n    }\n\n    private Number getCachedNumber(String method, String key) {\n        Map<String, Number> keyNumber = getMethodNumbers().get(method);\n        if (keyNumber != null) {\n            return keyNumber.get(key);\n        }\n        return null;\n    }\n\n    private void updateCachedNumber(String method, String key, Number n) {\n        Map<String, Number> keyNumber =\n                ConcurrentHashMapUtils.computeIfAbsent(getMethodNumbers(), method, m -> new HashMap<>());\n        keyNumber.put(key, n);\n    }\n\n    protected ConcurrentMap<String, Map<String, Number>> getMethodNumbers() {\n        if (methodNumbers == null) { // concurrent initialization is tolerant\n            methodNumbers = new ConcurrentHashMap<>();\n        }\n        return methodNumbers;\n    }\n\n    protected Map<String, Number> getServiceNumbers(String service) {\n        return getNumbers();\n    }\n\n    protected Map<String, Map<String, Number>> getServiceMethodNumbers(String service) {\n        return getMethodNumbers();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLAddress.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component;\n\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.io.Serializable;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLDecoder;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;\n\npublic class URLAddress implements Serializable {\n    private static final long serialVersionUID = -1985165475234910535L;\n\n    protected String host;\n    protected int port;\n\n    // cache\n    protected transient String rawAddress;\n    protected transient long timestamp;\n\n    public URLAddress(String host, int port) {\n        this(host, port, null);\n    }\n\n    public URLAddress(String host, int port, String rawAddress) {\n        this.host = host;\n        port = Math.max(port, 0);\n        this.port = port;\n\n        this.rawAddress = rawAddress;\n        this.timestamp = System.currentTimeMillis();\n    }\n\n    public String getProtocol() {\n        return \"\";\n    }\n\n    public URLAddress setProtocol(String protocol) {\n        return this;\n    }\n\n    public String getUsername() {\n        return \"\";\n    }\n\n    public URLAddress setUsername(String username) {\n        return this;\n    }\n\n    public String getPassword() {\n        return \"\";\n    }\n\n    public URLAddress setPassword(String password) {\n        return this;\n    }\n\n    public String getPath() {\n        return \"\";\n    }\n\n    public URLAddress setPath(String path) {\n        return this;\n    }\n\n    public String getHost() {\n        return host;\n    }\n\n    public URLAddress setHost(String host) {\n        return new URLAddress(host, port, null);\n    }\n\n    public int getPort() {\n        return port;\n    }\n\n    public URLAddress setPort(int port) {\n        return new URLAddress(host, port, null);\n    }\n\n    public String getAddress() {\n        if (rawAddress == null) {\n            rawAddress = getAddress(getHost(), getPort());\n        }\n        return rawAddress;\n    }\n\n    public URLAddress setAddress(String host, int port) {\n        return new URLAddress(host, port, rawAddress);\n    }\n\n    public String getIp() {\n        return NetUtils.getIpByHost(getHost());\n    }\n\n    public String getRawAddress() {\n        return rawAddress;\n    }\n\n    protected String getAddress(String host, int port) {\n        return port <= 0 ? host : host + ':' + port;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    @Override\n    public int hashCode() {\n        return host.hashCode() * 31 + port;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (!(obj instanceof URLAddress)) return false;\n        URLAddress that = (URLAddress) obj;\n        return Objects.equals(this.getProtocol(), that.getProtocol())\n                && Objects.equals(this.getUsername(), that.getUsername())\n                && Objects.equals(this.getPassword(), that.getPassword())\n                && Objects.equals(this.getPath(), that.getPath())\n                && Objects.equals(this.getHost(), that.getHost())\n                && Objects.equals(this.getPort(), that.getPort());\n    }\n\n    @Override\n    public String toString() {\n        if (rawAddress != null) {\n            return rawAddress;\n        }\n\n        StringBuilder buf = new StringBuilder();\n        if (StringUtils.isNotEmpty(host)) {\n            buf.append(host);\n            if (port > 0) {\n                buf.append(':');\n                buf.append(port);\n            }\n        }\n        return buf.toString();\n    }\n\n    public static URLAddress parse(String rawAddress, String defaultProtocol, boolean encoded) {\n        try {\n            String decodeStr = rawAddress;\n            if (encoded) {\n                decodeStr = URLDecoder.decode(rawAddress, \"UTF-8\");\n            }\n\n            boolean isPathAddress = decodeStr.contains(PATH_SEPARATOR);\n            if (isPathAddress) {\n                return createPathURLAddress(decodeStr, rawAddress, defaultProtocol);\n            }\n            return createURLAddress(decodeStr, rawAddress, defaultProtocol);\n        } catch (UnsupportedEncodingException e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n    }\n\n    private static URLAddress createURLAddress(String decodeStr, String rawAddress, String defaultProtocol) {\n        String host = null;\n        int port = 0;\n\n        int i = decodeStr.lastIndexOf(':');\n        if (i >= 0 && i < decodeStr.length() - 1) {\n            if (decodeStr.lastIndexOf('%') > i) {\n                // ipv6 address with scope id\n                // e.g. fe80:0:0:0:894:aeec:f37d:23e1%en0\n                // see https://howdoesinternetwork.com/2013/ipv6-zone-id\n                // ignore\n            } else {\n                port = Integer.parseInt(decodeStr.substring(i + 1));\n                host = decodeStr.substring(0, i);\n            }\n        } else {\n            host = decodeStr;\n        }\n\n        return new URLAddress(host, port, rawAddress);\n    }\n\n    private static PathURLAddress createPathURLAddress(String decodeStr, String rawAddress, String defaultProtocol) {\n        String protocol = defaultProtocol;\n        String path = null, username = null, password = null, host = null;\n        int port = 0;\n        int i = decodeStr.indexOf(\"://\");\n        if (i >= 0) {\n            if (i == 0) {\n                throw new IllegalStateException(\"url missing protocol: \\\"\" + decodeStr + \"\\\"\");\n            }\n            protocol = decodeStr.substring(0, i);\n            decodeStr = decodeStr.substring(i + 3);\n        } else {\n            // case: file:/path/to/file.txt\n            i = decodeStr.indexOf(\":/\");\n            if (i >= 0) {\n                if (i == 0) {\n                    throw new IllegalStateException(\"url missing protocol: \\\"\" + decodeStr + \"\\\"\");\n                }\n                protocol = decodeStr.substring(0, i);\n                decodeStr = decodeStr.substring(i + 1);\n            }\n        }\n\n        i = decodeStr.indexOf('/');\n        if (i >= 0) {\n            path = decodeStr.substring(i + 1);\n            decodeStr = decodeStr.substring(0, i);\n        }\n        i = decodeStr.lastIndexOf('@');\n        if (i >= 0) {\n            username = decodeStr.substring(0, i);\n            int j = username.indexOf(':');\n            if (j >= 0) {\n                password = username.substring(j + 1);\n                username = username.substring(0, j);\n            }\n            decodeStr = decodeStr.substring(i + 1);\n        }\n        i = decodeStr.lastIndexOf(':');\n        if (i >= 0 && i < decodeStr.length() - 1) {\n            if (decodeStr.lastIndexOf('%') > i) {\n                // ipv6 address with scope id\n                // e.g. fe80:0:0:0:894:aeec:f37d:23e1%en0\n                // see https://howdoesinternetwork.com/2013/ipv6-zone-id\n                // ignore\n            } else {\n                port = Integer.parseInt(decodeStr.substring(i + 1));\n                host = decodeStr.substring(0, i);\n            }\n        }\n\n        // check cache\n        protocol = URLItemCache.intern(protocol);\n        path = URLItemCache.checkPath(path);\n\n        return new PathURLAddress(protocol, username, password, path, host, port, rawAddress);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLItemCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component;\n\nimport org.apache.dubbo.common.utils.LRUCache;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Map;\n\npublic class URLItemCache {\n    // thread safe with limited size, by default 1000\n    private static final Map<String, String> PARAM_KEY_CACHE = new LRUCache<>(10000);\n    private static final Map<String, String> PARAM_VALUE_CACHE = new LRUCache<>(50000);\n    private static final Map<String, String> PATH_CACHE = new LRUCache<>(10000);\n    private static final Map<String, String> REVISION_CACHE = new LRUCache<>(10000);\n\n    public static void putParams(Map<String, String> params, String key, String value) {\n        String cachedKey = PARAM_KEY_CACHE.get(key);\n        if (StringUtils.isBlank(cachedKey)) {\n            cachedKey = key;\n            PARAM_KEY_CACHE.put(key, key);\n        }\n        String cachedValue = PARAM_VALUE_CACHE.get(value);\n        if (StringUtils.isBlank(cachedValue)) {\n            cachedValue = value;\n            PARAM_VALUE_CACHE.put(value, value);\n        }\n\n        params.put(cachedKey, cachedValue);\n    }\n\n    public static String checkPath(String path) {\n        if (StringUtils.isBlank(path)) {\n            return path;\n        }\n        String cachedPath = PATH_CACHE.putIfAbsent(path, path);\n        if (StringUtils.isNotBlank(cachedPath)) {\n            return cachedPath;\n        }\n        return path;\n    }\n\n    public static String checkRevision(String revision) {\n        if (StringUtils.isBlank(revision)) {\n            return revision;\n        }\n        String cachedRevision = REVISION_CACHE.putIfAbsent(revision, revision);\n        if (StringUtils.isNotBlank(cachedRevision)) {\n            return cachedRevision;\n        }\n        return revision;\n    }\n\n    public static String intern(String protocol) {\n        if (StringUtils.isBlank(protocol)) {\n            return protocol;\n        }\n        return protocol.intern();\n    }\n\n    public static void putParamsIntern(Map<String, String> params, String key, String value) {\n        if (StringUtils.isBlank(key) || StringUtils.isBlank(value)) {\n            params.put(key, value);\n            return;\n        }\n        key = key.intern();\n        value = value.intern();\n        params.put(key, value);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLStrParser;\nimport org.apache.dubbo.common.url.component.param.DynamicParamTable;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.AbstractMap;\nimport java.util.Arrays;\nimport java.util.BitSet;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.StringJoiner;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\n\n/**\n * A class which store parameters for {@link URL}\n * <br/>\n * Using {@link DynamicParamTable} to compress common keys (i.e. side, version)\n * <br/>\n * {@link DynamicParamTable} allow to use only two integer value named `key` and\n * `value-offset` to find a unique string to string key-pair. Also, `value-offset`\n * is not required if the real value is the default value.\n * <br/>\n * URLParam should operate as Copy-On-Write, each modify actions will return a new Object\n * <br/>\n * <p>\n * NOTE: URLParam is not support serialization! {@link DynamicParamTable} is related with\n * current running environment. If you want to make URL as a parameter, please call\n * {@link URL#toSerializableURL()} to create {@link URLPlainParam} instead.\n *\n * @since 3.0\n */\npublic class URLParam {\n\n    /**\n     * Maximum size of key-pairs requested using array moving to add into URLParam.\n     * If user request like addParameter for only one key-pair, adding value into a array\n     * on moving is more efficient. However when add more than ADD_PARAMETER_ON_MOVE_THRESHOLD\n     * size of key-pairs, recover compressed array back to map can reduce operation count\n     * when putting objects.\n     */\n    private static final int ADD_PARAMETER_ON_MOVE_THRESHOLD = 1;\n\n    /**\n     * the original parameters string, empty if parameters have been modified or init by {@link Map}\n     */\n    private final String rawParam;\n\n    /**\n     * using bit to save if index exist even if value is default value\n     */\n    private final BitSet KEY;\n\n    /**\n     * an array which contains value-offset\n     */\n    private final int[] VALUE;\n\n    /**\n     * store extra parameters which key not match in {@link DynamicParamTable}\n     */\n    private final Map<String, String> EXTRA_PARAMS;\n\n    /**\n     * store method related parameters\n     * <p>\n     * K - key\n     * V -\n     * K - method\n     * V - value\n     * <p>\n     * e.g. method1.mock=true => ( mock, (method1, true) )\n     */\n    private final Map<String, Map<String, String>> METHOD_PARAMETERS;\n\n    private transient long timestamp;\n\n    /**\n     * Whether to enable DynamicParamTable compression\n     */\n    protected boolean enableCompressed;\n\n    private static final URLParam EMPTY_PARAM =\n            new URLParam(new BitSet(0), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), \"\");\n\n    protected URLParam() {\n        this.rawParam = null;\n        this.KEY = null;\n        this.VALUE = null;\n        this.EXTRA_PARAMS = null;\n        this.METHOD_PARAMETERS = null;\n        this.enableCompressed = true;\n    }\n\n    protected URLParam(\n            BitSet key,\n            Map<Integer, Integer> value,\n            Map<String, String> extraParams,\n            Map<String, Map<String, String>> methodParameters,\n            String rawParam) {\n        this.KEY = key;\n        this.VALUE = new int[value.size()];\n        for (int i = key.nextSetBit(0), offset = 0; i >= 0; i = key.nextSetBit(i + 1)) {\n            if (value.containsKey(i)) {\n                VALUE[offset++] = value.get(i);\n            } else {\n                throw new IllegalArgumentException();\n            }\n        }\n        this.EXTRA_PARAMS =\n                Collections.unmodifiableMap((extraParams == null ? new HashMap<>() : new HashMap<>(extraParams)));\n        this.METHOD_PARAMETERS = Collections.unmodifiableMap(\n                (methodParameters == null) ? Collections.emptyMap() : new LinkedHashMap<>(methodParameters));\n        this.rawParam = rawParam;\n\n        this.timestamp = System.currentTimeMillis();\n        this.enableCompressed = true;\n    }\n\n    protected URLParam(\n            BitSet key,\n            int[] value,\n            Map<String, String> extraParams,\n            Map<String, Map<String, String>> methodParameters,\n            String rawParam) {\n        this.KEY = key;\n        this.VALUE = value;\n        this.EXTRA_PARAMS =\n                Collections.unmodifiableMap((extraParams == null ? new HashMap<>() : new HashMap<>(extraParams)));\n        this.METHOD_PARAMETERS = Collections.unmodifiableMap(\n                (methodParameters == null) ? Collections.emptyMap() : new LinkedHashMap<>(methodParameters));\n        this.rawParam = rawParam;\n        this.timestamp = System.currentTimeMillis();\n        this.enableCompressed = true;\n    }\n\n    /**\n     * Weather there contains some parameter match method\n     *\n     * @param method method name\n     * @return contains or not\n     */\n    public boolean hasMethodParameter(String method) {\n        if (method == null) {\n            return false;\n        }\n\n        String methodsString = getParameter(METHODS_KEY);\n        if (StringUtils.isNotEmpty(methodsString)) {\n            if (!methodsString.contains(method)) {\n                return false;\n            }\n        }\n\n        for (Map.Entry<String, Map<String, String>> methods : METHOD_PARAMETERS.entrySet()) {\n            if (methods.getValue().containsKey(method)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Get method related parameter. If not contains, use getParameter(key) instead.\n     * Specially, in some situation like `method1.1.callback=true`, key is `1.callback`.\n     *\n     * @param method method name\n     * @param key    key\n     * @return value\n     */\n    public String getMethodParameter(String method, String key) {\n        String strictResult = getMethodParameterStrict(method, key);\n        return StringUtils.isNotEmpty(strictResult) ? strictResult : getParameter(key);\n    }\n\n    /**\n     * Get method related parameter. If not contains, return null.\n     * Specially, in some situation like `method1.1.callback=true`, key is `1.callback`.\n     *\n     * @param method method name\n     * @param key    key\n     * @return value\n     */\n    public String getMethodParameterStrict(String method, String key) {\n        String methodsString = getParameter(METHODS_KEY);\n        if (StringUtils.isNotEmpty(methodsString)) {\n            if (!methodsString.contains(method)) {\n                return null;\n            }\n        }\n\n        Map<String, String> methodMap = METHOD_PARAMETERS.get(key);\n        if (CollectionUtils.isNotEmptyMap(methodMap)) {\n            return methodMap.get(method);\n        } else {\n            return null;\n        }\n    }\n\n    public static Map<String, Map<String, String>> initMethodParameters(Map<String, String> parameters) {\n        Map<String, Map<String, String>> methodParameters = new HashMap<>();\n        if (parameters == null) {\n            return methodParameters;\n        }\n\n        String methodsString = parameters.get(METHODS_KEY);\n        if (StringUtils.isNotEmpty(methodsString)) {\n            String[] methods = methodsString.split(\",\");\n            for (Map.Entry<String, String> entry : parameters.entrySet()) {\n                String key = entry.getKey();\n                for (String method : methods) {\n                    String methodPrefix = method + '.';\n                    if (key.startsWith(methodPrefix)) {\n                        String realKey = key.substring(methodPrefix.length());\n                        URL.putMethodParameter(method, realKey, entry.getValue(), methodParameters);\n                    }\n                }\n            }\n        } else {\n            for (Map.Entry<String, String> entry : parameters.entrySet()) {\n                String key = entry.getKey();\n                int methodSeparator = key.indexOf('.');\n                if (methodSeparator > 0) {\n                    String method = key.substring(0, methodSeparator);\n                    String realKey = key.substring(methodSeparator + 1);\n                    URL.putMethodParameter(method, realKey, entry.getValue(), methodParameters);\n                }\n            }\n        }\n        return methodParameters;\n    }\n\n    /**\n     * An embedded Map adapt to URLParam\n     * <br/>\n     * copy-on-write mode, urlParam reference will be changed after modify actions.\n     * If wishes to get the result after modify, please use {@link URLParamMap#getUrlParam()}\n     */\n    public static class URLParamMap extends AbstractMap<String, String> {\n        private URLParam urlParam;\n\n        public URLParamMap(URLParam urlParam) {\n            this.urlParam = urlParam;\n        }\n\n        public static class Node implements Map.Entry<String, String> {\n            private final String key;\n            private String value;\n\n            public Node(String key, String value) {\n                this.key = key;\n                this.value = value;\n            }\n\n            @Override\n            public String getKey() {\n                return key;\n            }\n\n            @Override\n            public String getValue() {\n                return value;\n            }\n\n            @Override\n            public String setValue(String value) {\n                throw new UnsupportedOperationException();\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                Node node = (Node) o;\n                return Objects.equals(key, node.key) && Objects.equals(value, node.value);\n            }\n\n            @Override\n            public int hashCode() {\n                return Objects.hash(key, value);\n            }\n        }\n\n        @Override\n        public int size() {\n            return urlParam.KEY.cardinality() + urlParam.EXTRA_PARAMS.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return size() == 0;\n        }\n\n        @Override\n        public boolean containsKey(Object key) {\n            if (key instanceof String) {\n                return urlParam.hasParameter((String) key);\n            } else {\n                return false;\n            }\n        }\n\n        @Override\n        public boolean containsValue(Object value) {\n            return values().contains(value);\n        }\n\n        @Override\n        public String get(Object key) {\n            if (key instanceof String) {\n                return urlParam.getParameter((String) key);\n            } else {\n                return null;\n            }\n        }\n\n        @Override\n        public String put(String key, String value) {\n            String previous = urlParam.getParameter(key);\n            urlParam = urlParam.addParameter(key, value);\n            return previous;\n        }\n\n        @Override\n        public String remove(Object key) {\n            if (key instanceof String) {\n                String previous = urlParam.getParameter((String) key);\n                urlParam = urlParam.removeParameters((String) key);\n                return previous;\n            } else {\n                return null;\n            }\n        }\n\n        @Override\n        public void putAll(Map<? extends String, ? extends String> m) {\n            urlParam = urlParam.addParameters((Map<String, String>) m);\n        }\n\n        @Override\n        public void clear() {\n            urlParam = urlParam.clearParameters();\n        }\n\n        @Override\n        public Set<String> keySet() {\n            Set<String> set =\n                    new LinkedHashSet<>((int) ((urlParam.VALUE.length + urlParam.EXTRA_PARAMS.size()) / 0.75) + 1);\n            for (int i = urlParam.KEY.nextSetBit(0); i >= 0; i = urlParam.KEY.nextSetBit(i + 1)) {\n                set.add(DynamicParamTable.getKey(i));\n            }\n            for (Entry<String, String> entry : urlParam.EXTRA_PARAMS.entrySet()) {\n                set.add(entry.getKey());\n            }\n            return Collections.unmodifiableSet(set);\n        }\n\n        @Override\n        public Collection<String> values() {\n            Set<String> set =\n                    new LinkedHashSet<>((int) ((urlParam.VALUE.length + urlParam.EXTRA_PARAMS.size()) / 0.75) + 1);\n            for (int i = urlParam.KEY.nextSetBit(0); i >= 0; i = urlParam.KEY.nextSetBit(i + 1)) {\n                String value;\n                int offset = urlParam.keyIndexToOffset(i);\n                value = DynamicParamTable.getValue(i, offset);\n                set.add(value);\n            }\n\n            for (Entry<String, String> entry : urlParam.EXTRA_PARAMS.entrySet()) {\n                set.add(entry.getValue());\n            }\n            return Collections.unmodifiableSet(set);\n        }\n\n        @Override\n        public Set<Entry<String, String>> entrySet() {\n            Set<Entry<String, String>> set =\n                    new LinkedHashSet<>((int) ((urlParam.KEY.cardinality() + urlParam.EXTRA_PARAMS.size()) / 0.75) + 1);\n            for (int i = urlParam.KEY.nextSetBit(0); i >= 0; i = urlParam.KEY.nextSetBit(i + 1)) {\n                String value;\n                int offset = urlParam.keyIndexToOffset(i);\n                value = DynamicParamTable.getValue(i, offset);\n                set.add(new Node(DynamicParamTable.getKey(i), value));\n            }\n\n            for (Entry<String, String> entry : urlParam.EXTRA_PARAMS.entrySet()) {\n                set.add(new Node(entry.getKey(), entry.getValue()));\n            }\n            return Collections.unmodifiableSet(set);\n        }\n\n        public URLParam getUrlParam() {\n            return urlParam;\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            URLParamMap that = (URLParamMap) o;\n            return Objects.equals(urlParam, that.urlParam);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(urlParam);\n        }\n    }\n\n    /**\n     * Get a Map like URLParam\n     *\n     * @return a {@link URLParamMap} adapt to URLParam\n     */\n    public Map<String, String> getParameters() {\n        return new URLParamMap(this);\n    }\n\n    /**\n     * Get any method related parameter which match key\n     *\n     * @param key key\n     * @return result ( if any, random choose one )\n     */\n    public String getAnyMethodParameter(String key) {\n        Map<String, String> methodMap = METHOD_PARAMETERS.get(key);\n        if (CollectionUtils.isNotEmptyMap(methodMap)) {\n            String methods = getParameter(METHODS_KEY);\n            if (StringUtils.isNotEmpty(methods)) {\n                for (String method : methods.split(\",\")) {\n                    String value = methodMap.get(method);\n                    if (StringUtils.isNotEmpty(value)) {\n                        return value;\n                    }\n                }\n            } else {\n                return methodMap.values().iterator().next();\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Add parameters to a new URLParam.\n     *\n     * @param key   key\n     * @param value value\n     * @return A new URLParam\n     */\n    public URLParam addParameter(String key, String value) {\n        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {\n            return this;\n        }\n        return addParameters(Collections.singletonMap(key, value));\n    }\n\n    /**\n     * Add absent parameters to a new URLParam.\n     *\n     * @param key   key\n     * @param value value\n     * @return A new URLParam\n     */\n    public URLParam addParameterIfAbsent(String key, String value) {\n        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {\n            return this;\n        }\n        if (hasParameter(key)) {\n            return this;\n        }\n        return addParametersIfAbsent(Collections.singletonMap(key, value));\n    }\n\n    /**\n     * Add parameters to a new URLParam.\n     * If key-pair is present, this will cover it.\n     *\n     * @param parameters parameters in key-value pairs\n     * @return A new URLParam\n     */\n    public URLParam addParameters(Map<String, String> parameters) {\n        if (CollectionUtils.isEmptyMap(parameters)) {\n            return this;\n        }\n\n        boolean hasAndEqual = true;\n        Map<String, String> urlParamMap = getParameters();\n        for (Map.Entry<String, String> entry : parameters.entrySet()) {\n            String value = urlParamMap.get(entry.getKey());\n            if (value == null) {\n                if (entry.getValue() != null) {\n                    hasAndEqual = false;\n                    break;\n                }\n            } else {\n                if (!value.equals(entry.getValue())) {\n                    hasAndEqual = false;\n                    break;\n                }\n            }\n        }\n        // return immediately if there's no change\n        if (hasAndEqual) {\n            return this;\n        }\n\n        return doAddParameters(parameters, false);\n    }\n\n    /**\n     * Add absent parameters to a new URLParam.\n     *\n     * @param parameters parameters in key-value pairs\n     * @return A new URL\n     */\n    public URLParam addParametersIfAbsent(Map<String, String> parameters) {\n        if (CollectionUtils.isEmptyMap(parameters)) {\n            return this;\n        }\n\n        return doAddParameters(parameters, true);\n    }\n\n    private URLParam doAddParameters(Map<String, String> parameters, boolean skipIfPresent) {\n        // lazy init, null if no modify\n        BitSet newKey = null;\n        int[] newValueArray = null;\n        Map<Integer, Integer> newValueMap = null;\n        Map<String, String> newExtraParams = null;\n        Map<String, Map<String, String>> newMethodParams = null;\n        for (Map.Entry<String, String> entry : parameters.entrySet()) {\n            if (skipIfPresent && hasParameter(entry.getKey())) {\n                continue;\n            }\n            if (entry.getKey() == null || entry.getValue() == null) {\n                continue;\n            }\n            int keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, entry.getKey());\n            if (keyIndex < 0) {\n                // entry key is not present in DynamicParamTable, add it to EXTRA_PARAMS\n                if (newExtraParams == null) {\n                    newExtraParams = new HashMap<>(EXTRA_PARAMS);\n                }\n                newExtraParams.put(entry.getKey(), entry.getValue());\n                String[] methodSplit = entry.getKey().split(\"\\\\.\");\n                if (methodSplit.length == 2) {\n                    if (newMethodParams == null) {\n                        newMethodParams = new HashMap<>(METHOD_PARAMETERS);\n                    }\n                    Map<String, String> methodMap =\n                            newMethodParams.computeIfAbsent(methodSplit[1], (k) -> new HashMap<>());\n                    methodMap.put(methodSplit[0], entry.getValue());\n                }\n            } else {\n                if (KEY.get(keyIndex)) {\n                    // contains key, replace value\n                    if (parameters.size() > ADD_PARAMETER_ON_MOVE_THRESHOLD) {\n                        // recover VALUE back to Map, use map to replace key pair\n                        if (newValueMap == null) {\n                            newValueMap = recoverValue();\n                        }\n                        newValueMap.put(keyIndex, DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));\n                    } else {\n                        newValueArray = replaceOffset(\n                                VALUE,\n                                keyIndexToIndex(KEY, keyIndex),\n                                DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));\n                    }\n                } else {\n                    // key is absent, add it\n                    if (newKey == null) {\n                        newKey = (BitSet) KEY.clone();\n                    }\n                    newKey.set(keyIndex);\n\n                    if (parameters.size() > ADD_PARAMETER_ON_MOVE_THRESHOLD) {\n                        // recover VALUE back to Map\n                        if (newValueMap == null) {\n                            newValueMap = recoverValue();\n                        }\n                        newValueMap.put(keyIndex, DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));\n                    } else {\n                        // add parameter by moving array, only support for adding once\n                        newValueArray = addByMove(\n                                VALUE,\n                                keyIndexToIndex(newKey, keyIndex),\n                                DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));\n                    }\n                }\n            }\n        }\n        if (newKey == null) {\n            newKey = KEY;\n        }\n        if (newValueArray == null && newValueMap == null) {\n            newValueArray = VALUE;\n        }\n        if (newExtraParams == null) {\n            newExtraParams = EXTRA_PARAMS;\n        }\n        if (newMethodParams == null) {\n            newMethodParams = METHOD_PARAMETERS;\n        }\n        if (newValueMap == null) {\n            return new URLParam(newKey, newValueArray, newExtraParams, newMethodParams, null);\n        } else {\n            return new URLParam(newKey, newValueMap, newExtraParams, newMethodParams, null);\n        }\n    }\n\n    private Map<Integer, Integer> recoverValue() {\n        Map<Integer, Integer> map = new HashMap<>((int) (KEY.size() / 0.75) + 1);\n        for (int i = KEY.nextSetBit(0), offset = 0; i >= 0; i = KEY.nextSetBit(i + 1)) {\n            map.put(i, VALUE[offset++]);\n        }\n        return map;\n    }\n\n    private int[] addByMove(int[] array, int index, Integer value) {\n        if (index < 0 || index > array.length) {\n            throw new IllegalArgumentException();\n        }\n        // copy-on-write\n        int[] result = new int[array.length + 1];\n\n        System.arraycopy(array, 0, result, 0, index);\n        result[index] = value;\n        System.arraycopy(array, index, result, index + 1, array.length - index);\n\n        return result;\n    }\n\n    private int[] replaceOffset(int[] array, int index, Integer value) {\n        if (index < 0 || index > array.length) {\n            throw new IllegalArgumentException();\n        }\n        // copy-on-write\n        int[] result = new int[array.length];\n\n        System.arraycopy(array, 0, result, 0, array.length);\n        result[index] = value;\n\n        return result;\n    }\n\n    /**\n     * remove specified parameters in URLParam\n     *\n     * @param keys keys to being removed\n     * @return A new URLParam\n     */\n    public URLParam removeParameters(String... keys) {\n        if (keys == null || keys.length == 0) {\n            return this;\n        }\n        // lazy init, null if no modify\n        BitSet newKey = null;\n        int[] newValueArray = null;\n        Map<String, String> newExtraParams = null;\n        Map<String, Map<String, String>> newMethodParams = null;\n        for (String key : keys) {\n            int keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, key);\n            if (keyIndex >= 0 && KEY.get(keyIndex)) {\n                if (newKey == null) {\n                    newKey = (BitSet) KEY.clone();\n                }\n                newKey.clear(keyIndex);\n                // which offset is in VALUE array, set value as -1, compress in the end\n                if (newValueArray == null) {\n                    newValueArray = new int[VALUE.length];\n                    System.arraycopy(VALUE, 0, newValueArray, 0, VALUE.length);\n                }\n                // KEY is immutable\n                newValueArray[keyIndexToIndex(KEY, keyIndex)] = -1;\n            }\n            if (EXTRA_PARAMS.containsKey(key)) {\n                if (newExtraParams == null) {\n                    newExtraParams = new HashMap<>(EXTRA_PARAMS);\n                }\n                newExtraParams.remove(key);\n\n                String[] methodSplit = key.split(\"\\\\.\");\n                if (methodSplit.length == 2) {\n                    if (newMethodParams == null) {\n                        newMethodParams = new HashMap<>(METHOD_PARAMETERS);\n                    }\n                    Map<String, String> methodMap = newMethodParams.get(methodSplit[1]);\n                    if (CollectionUtils.isNotEmptyMap(methodMap)) {\n                        methodMap.remove(methodSplit[0]);\n                    }\n                }\n            }\n            // ignore if key is absent\n        }\n        if (newKey == null) {\n            newKey = KEY;\n        }\n        if (newValueArray == null) {\n            newValueArray = VALUE;\n        } else {\n            // remove -1 value\n            newValueArray = compressArray(newValueArray);\n        }\n        if (newExtraParams == null) {\n            newExtraParams = EXTRA_PARAMS;\n        }\n        if (newMethodParams == null) {\n            newMethodParams = METHOD_PARAMETERS;\n        }\n        if (newKey.cardinality() + newExtraParams.size() == 0) {\n            // empty, directly return cache\n            return EMPTY_PARAM;\n        } else {\n            return new URLParam(newKey, newValueArray, newExtraParams, newMethodParams, null);\n        }\n    }\n\n    private int[] compressArray(int[] array) {\n        int total = 0;\n        for (int i : array) {\n            if (i > -1) {\n                total++;\n            }\n        }\n        if (total == 0) {\n            return new int[0];\n        }\n\n        int[] result = new int[total];\n        for (int i = 0, offset = 0; i < array.length; i++) {\n            // skip if value if less than 0\n            if (array[i] > -1) {\n                result[offset++] = array[i];\n            }\n        }\n        return result;\n    }\n\n    /**\n     * remove all of the parameters in URLParam\n     *\n     * @return An empty URLParam\n     */\n    public URLParam clearParameters() {\n        return EMPTY_PARAM;\n    }\n\n    /**\n     * check if specified key is present in URLParam\n     *\n     * @param key specified key\n     * @return present or not\n     */\n    public boolean hasParameter(String key) {\n        int keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, key);\n        if (keyIndex < 0) {\n            return EXTRA_PARAMS.containsKey(key);\n        }\n        return KEY.get(keyIndex);\n    }\n\n    /**\n     * get value of specified key in URLParam\n     *\n     * @param key specified key\n     * @return value, null if key is absent\n     */\n    public String getParameter(String key) {\n        int keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, key);\n        if (keyIndex < 0) {\n            return EXTRA_PARAMS.get(key);\n        }\n        if (KEY.get(keyIndex)) {\n            String value;\n            int offset = keyIndexToOffset(keyIndex);\n            value = DynamicParamTable.getValue(keyIndex, offset);\n\n            return value;\n            //            if (StringUtils.isEmpty(value)) {\n            //                // Forward compatible, make sure key dynamic increment can work.\n            //                // In that case, some values which are proceed before increment will set in EXTRA_PARAMS.\n            //                return EXTRA_PARAMS.get(key);\n            //            } else {\n            //                return value;\n            //            }\n        }\n        return null;\n    }\n\n    private int keyIndexToIndex(BitSet key, int keyIndex) {\n        return key.get(0, keyIndex).cardinality();\n    }\n\n    private int keyIndexToOffset(int keyIndex) {\n        int arrayOffset = keyIndexToIndex(KEY, keyIndex);\n        return VALUE[arrayOffset];\n    }\n\n    /**\n     * get raw string like parameters\n     *\n     * @return raw string like parameters\n     */\n    public String getRawParam() {\n        // If rawParam is not null, return it directly\n        // If rawParam is null, it means that the parameters have been modified\n        return toString();\n    }\n\n    protected Map<String, Map<String, String>> getMethodParameters() {\n        return METHOD_PARAMETERS;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long timestamp) {\n        this.timestamp = timestamp;\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        URLParam urlParam = (URLParam) o;\n\n        if (Objects.equals(KEY, urlParam.KEY) && Arrays.equals(VALUE, urlParam.VALUE)) {\n            if (CollectionUtils.isNotEmptyMap(EXTRA_PARAMS)) {\n                if (CollectionUtils.isEmptyMap(urlParam.EXTRA_PARAMS)\n                        || EXTRA_PARAMS.size() != urlParam.EXTRA_PARAMS.size()) {\n                    return false;\n                }\n                for (Map.Entry<String, String> entry : EXTRA_PARAMS.entrySet()) {\n                    if (TIMESTAMP_KEY.equals(entry.getKey())) {\n                        continue;\n                    }\n                    if (!entry.getValue().equals(urlParam.EXTRA_PARAMS.get(entry.getKey()))) {\n                        return false;\n                    }\n                }\n                return true;\n            }\n            return CollectionUtils.isEmptyMap(urlParam.EXTRA_PARAMS);\n        }\n        return false;\n    }\n\n    private int hashCodeCache = -1;\n\n    @Override\n    public int hashCode() {\n        if (hashCodeCache == -1) {\n            int result = 1;\n            for (Map.Entry<String, String> entry : EXTRA_PARAMS.entrySet()) {\n                if (!TIMESTAMP_KEY.equals(entry.getKey())) {\n                    result += entry.hashCode();\n                }\n            }\n\n            result = 31 * result + Arrays.hashCode(VALUE);\n            result = 31 * result + ((KEY == null) ? 0 : KEY.hashCode());\n\n            hashCodeCache = result;\n        }\n        return hashCodeCache;\n    }\n\n    @Override\n    public String toString() {\n        if (StringUtils.isNotEmpty(rawParam)) {\n            return rawParam;\n        }\n        if ((KEY.cardinality() + EXTRA_PARAMS.size()) == 0) {\n            return \"\";\n        }\n\n        StringJoiner stringJoiner = new StringJoiner(\"&\");\n        for (int i = KEY.nextSetBit(0); i >= 0; i = KEY.nextSetBit(i + 1)) {\n            String key = DynamicParamTable.getKey(i);\n            String value = DynamicParamTable.getValue(i, keyIndexToOffset(i));\n            value = value == null ? \"\" : value.trim();\n            stringJoiner.add(String.format(\"%s=%s\", key, value));\n        }\n        for (Map.Entry<String, String> entry : EXTRA_PARAMS.entrySet()) {\n            String key = entry.getKey();\n            String value = entry.getValue();\n            value = value == null ? \"\" : value.trim();\n            stringJoiner.add(String.format(\"%s=%s\", key, value));\n        }\n\n        return stringJoiner.toString();\n    }\n\n    /**\n     * Parse URLParam\n     * Init URLParam by constructor is not allowed\n     * rawParam field in result will be null while {@link URLParam#getRawParam()} will automatically create it\n     *\n     * @param params params map added into URLParam\n     * @return a new URLParam\n     */\n    public static URLParam parse(Map<String, String> params) {\n        return parse(params, null);\n    }\n\n    /**\n     * Parse URLParam\n     * Init URLParam by constructor is not allowed\n     *\n     * @param rawParam        original rawParam string\n     * @param encoded         if parameters are URL encoded\n     * @param extraParameters extra parameters to add into URLParam\n     * @return a new URLParam\n     */\n    public static URLParam parse(String rawParam, boolean encoded, Map<String, String> extraParameters) {\n        Map<String, String> parameters = URLStrParser.parseParams(rawParam, encoded);\n        if (CollectionUtils.isNotEmptyMap(extraParameters)) {\n            parameters.putAll(extraParameters);\n        }\n        return parse(parameters, rawParam);\n    }\n\n    /**\n     * Parse URLParam\n     * Init URLParam by constructor is not allowed\n     *\n     * @param rawParam original rawParam string\n     * @return a new URLParam\n     */\n    public static URLParam parse(String rawParam) {\n        String[] parts = rawParam.split(\"&\");\n\n        int capacity = (int) (parts.length / .75f) + 1;\n        BitSet keyBit = new BitSet(capacity);\n        Map<Integer, Integer> valueMap = new HashMap<>(capacity);\n        Map<String, String> extraParam = new HashMap<>(capacity);\n        Map<String, Map<String, String>> methodParameters = new HashMap<>(capacity);\n\n        for (String part : parts) {\n            part = part.trim();\n            if (part.length() > 0) {\n                int j = part.indexOf('=');\n                if (j >= 0) {\n                    String key = part.substring(0, j);\n                    String value = part.substring(j + 1);\n                    addParameter(keyBit, valueMap, extraParam, methodParameters, key, value, false);\n                    // compatible with lower versions registering \"default.\" keys\n                    if (key.startsWith(DEFAULT_KEY_PREFIX)) {\n                        addParameter(\n                                keyBit,\n                                valueMap,\n                                extraParam,\n                                methodParameters,\n                                key.substring(DEFAULT_KEY_PREFIX.length()),\n                                value,\n                                true);\n                    }\n                } else {\n                    addParameter(keyBit, valueMap, extraParam, methodParameters, part, part, false);\n                }\n            }\n        }\n        return new URLParam(keyBit, valueMap, extraParam, methodParameters, rawParam);\n    }\n\n    /**\n     * Parse URLParam\n     * Init URLParam by constructor is not allowed\n     *\n     * @param params   params map added into URLParam\n     * @param rawParam original rawParam string, directly add to rawParam field,\n     *                 will not affect real key-pairs store in URLParam.\n     *                 Please make sure it can correspond with params or will\n     *                 cause unexpected result when calling {@link URLParam#getRawParam()}\n     *                 and {@link URLParam#toString()} ()}. If you not sure, you can call\n     *                 {@link URLParam#parse(String)} to init.\n     * @return a new URLParam\n     */\n    public static URLParam parse(Map<String, String> params, String rawParam) {\n        if (CollectionUtils.isNotEmptyMap(params)) {\n            int capacity = (int) (params.size() / .75f) + 1;\n            BitSet keyBit = new BitSet(capacity);\n            Map<Integer, Integer> valueMap = new HashMap<>(capacity);\n            Map<String, String> extraParam = new HashMap<>(capacity);\n            Map<String, Map<String, String>> methodParameters = new HashMap<>(capacity);\n\n            for (Map.Entry<String, String> entry : params.entrySet()) {\n                String key = entry.getKey();\n                String value = entry.getValue();\n                addParameter(keyBit, valueMap, extraParam, methodParameters, key, value, false);\n                // compatible with lower versions registering \"default.\" keys\n                if (key.startsWith(DEFAULT_KEY_PREFIX)) {\n                    addParameter(\n                            keyBit,\n                            valueMap,\n                            extraParam,\n                            methodParameters,\n                            key.substring(DEFAULT_KEY_PREFIX.length()),\n                            value,\n                            true);\n                }\n            }\n            return new URLParam(keyBit, valueMap, extraParam, methodParameters, rawParam);\n        } else {\n            return EMPTY_PARAM;\n        }\n    }\n\n    private static void addParameter(\n            BitSet keyBit,\n            Map<Integer, Integer> valueMap,\n            Map<String, String> extraParam,\n            Map<String, Map<String, String>> methodParameters,\n            String key,\n            String value,\n            boolean skipIfPresent) {\n        int keyIndex = DynamicParamTable.getKeyIndex(true, key);\n        if (skipIfPresent) {\n            if (keyIndex < 0) {\n                if (extraParam.containsKey(key)) {\n                    return;\n                }\n            } else {\n                if (keyBit.get(keyIndex)) {\n                    return;\n                }\n            }\n        }\n\n        if (keyIndex < 0) {\n            extraParam.put(key, value);\n            String[] methodSplit = key.split(\"\\\\.\", 2);\n            if (methodSplit.length == 2) {\n                Map<String, String> methodMap =\n                        methodParameters.computeIfAbsent(methodSplit[1], (k) -> new HashMap<>());\n                methodMap.put(methodSplit[0], value);\n            }\n        } else {\n            valueMap.put(keyIndex, DynamicParamTable.getValueIndex(key, value));\n            keyBit.set(keyIndex);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLPlainParam.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component;\n\nimport java.io.Serializable;\nimport java.util.BitSet;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Act like URLParam, will not use DynamicParamTable to compress parameters,\n * which can support serializer serialization and deserialization.\n * DynamicParamTable is environment hard related.\n */\npublic class URLPlainParam extends URLParam implements Serializable {\n\n    private static final long serialVersionUID = 4722019979665434393L;\n\n    protected URLPlainParam(\n            BitSet key,\n            int[] value,\n            Map<String, String> extraParams,\n            Map<String, Map<String, String>> methodParameters,\n            String rawParam) {\n        super(key, value, extraParams, methodParameters, rawParam);\n        this.enableCompressed = false;\n    }\n\n    public static URLPlainParam toURLPlainParam(URLParam urlParam) {\n        Map<String, String> params = Collections.unmodifiableMap(new HashMap<>(urlParam.getParameters()));\n        return new URLPlainParam(\n                new BitSet(), new int[0], params, urlParam.getMethodParameters(), urlParam.getRawParam());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DefaultDynamicParamSource.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component.param;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\n\nimport java.util.List;\n\npublic class DefaultDynamicParamSource implements DynamicParamSource {\n    @Override\n    public void init(List<String> keys, List<ParamValue> values) {\n        keys.add(CommonConstants.VERSION_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.SIDE_KEY);\n        values.add(new FixedParamValue(CommonConstants.CONSUMER_SIDE, CommonConstants.PROVIDER_SIDE));\n\n        keys.add(CommonConstants.INTERFACE_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.PID_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.THREADPOOL_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.GROUP_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.VERSION_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.METADATA_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.APPLICATION_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.DUBBO_VERSION_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.RELEASE_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.PATH_KEY);\n        values.add(new DynamicValues(null));\n\n        keys.add(CommonConstants.ANYHOST_KEY);\n        values.add(new DynamicValues(null));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicParamSource.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component.param;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.List;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface DynamicParamSource {\n\n    void init(List<String> keys, List<ParamValue> values);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicParamTable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component.param;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\n\n/**\n * Global Param Cache Table\n * Not support method parameters\n */\npublic final class DynamicParamTable {\n    /**\n     * Keys array, value is string\n     */\n    private static String[] ORIGIN_KEYS;\n\n    private static ParamValue[] VALUES;\n    private static final Map<String, Integer> KEY2INDEX = new HashMap<>(64);\n\n    private DynamicParamTable() {\n        throw new IllegalStateException();\n    }\n\n    static {\n        init();\n    }\n\n    public static int getKeyIndex(boolean enabled, String key) {\n        if (!enabled) {\n            return -1;\n        }\n        Integer indexFromMap = KEY2INDEX.get(key);\n        return indexFromMap == null ? -1 : indexFromMap;\n    }\n\n    public static int getValueIndex(String key, String value) {\n        int idx = getKeyIndex(true, key);\n        if (idx < 0) {\n            throw new IllegalArgumentException(\"Cannot found key in url param:\" + key);\n        }\n        ParamValue paramValue = VALUES[idx];\n        return paramValue.getIndex(value);\n    }\n\n    public static String getKey(int offset) {\n        return ORIGIN_KEYS[offset];\n    }\n\n    public static String getValue(int vi, int offset) {\n        return VALUES[vi].getN(offset);\n    }\n\n    private static void init() {\n        List<String> keys = new LinkedList<>();\n        List<ParamValue> values = new LinkedList<>();\n        Map<String, Integer> key2Index = new HashMap<>(64);\n        keys.add(\"\");\n        values.add(new DynamicValues(null));\n\n        FrameworkModel.defaultModel()\n                .getExtensionLoader(DynamicParamSource.class)\n                .getSupportedExtensionInstances()\n                .forEach(source -> source.init(keys, values));\n\n        TreeMap<String, ParamValue> resultMap = new TreeMap<>(Comparator.comparingInt(System::identityHashCode));\n        for (int i = 0; i < keys.size(); i++) {\n            resultMap.put(keys.get(i), values.get(i));\n        }\n\n        ORIGIN_KEYS = resultMap.keySet().toArray(new String[0]);\n\n        VALUES = resultMap.values().toArray(new ParamValue[0]);\n\n        for (int i = 0; i < ORIGIN_KEYS.length; i++) {\n            key2Index.put(ORIGIN_KEYS[i], i);\n        }\n        KEY2INDEX.putAll(key2Index);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicValues.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component.param;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class DynamicValues implements ParamValue {\n    private volatile String[] index2Value = new String[1];\n    private final Map<String, Integer> value2Index = new ConcurrentHashMap<>();\n    private int indexSeq = 0;\n\n    public DynamicValues(String defaultVal) {\n        if (defaultVal == null) {\n            indexSeq += 1;\n        } else {\n            add(defaultVal);\n        }\n    }\n\n    public int add(String value) {\n        Integer index = value2Index.get(value);\n        if (index != null) {\n            return index;\n        } else {\n            synchronized (this) {\n                // thread safe\n                if (!value2Index.containsKey(value)) {\n                    if (indexSeq == Integer.MAX_VALUE) {\n                        throw new IllegalStateException(\"URL Param Cache is full.\");\n                    }\n                    // copy on write, only support append now\n                    String[] newValues = new String[indexSeq + 1];\n                    System.arraycopy(index2Value, 0, newValues, 0, indexSeq);\n                    newValues[indexSeq] = value;\n                    index2Value = newValues;\n                    value2Index.put(value, indexSeq);\n                    indexSeq += 1;\n                }\n            }\n        }\n        return value2Index.get(value);\n    }\n\n    @Override\n    public String getN(int n) {\n        if (n == -1) {\n            return null;\n        }\n        return index2Value[n];\n    }\n\n    @Override\n    public int getIndex(String value) {\n        if (value == null) {\n            return -1;\n        }\n        Integer index = value2Index.get(value);\n        if (index == null) {\n            return add(value);\n        }\n        return index;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/FixedParamValue.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component.param;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\n/**\n * In lower case\n */\npublic class FixedParamValue implements ParamValue {\n    private final String[] values;\n    private final Map<String, Integer> val2Index;\n\n    public FixedParamValue(String... values) {\n        if (values.length == 0) {\n            throw new IllegalArgumentException(\"the array size of values should be larger than 0\");\n        }\n        this.values = values;\n        Map<String, Integer> valueMap = new HashMap<>(values.length);\n        for (int i = 0; i < values.length; i++) {\n            if (values[i] != null) {\n                valueMap.put(values[i].toLowerCase(Locale.ROOT), i);\n            }\n        }\n        val2Index = Collections.unmodifiableMap(valueMap);\n    }\n\n    /**\n     * DEFAULT value will be returned if n = 0\n     * @param n\n     */\n    @Override\n    public String getN(int n) {\n        return values[n];\n    }\n\n    @Override\n    public int getIndex(String value) {\n        Integer offset = val2Index.get(value.toLowerCase(Locale.ROOT));\n        if (offset == null) {\n            throw new IllegalArgumentException(\"unrecognized value \" + value\n                    + \" , please check if value is illegal. \" + \"Permitted values: \"\n                    + Arrays.asList(values));\n        }\n        return offset;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/IgnoredParam.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component.param;\n\nimport java.util.HashSet;\n\npublic class IgnoredParam {\n    private static final HashSet<String> IGNORED = new HashSet<>();\n\n    static {\n        IGNORED.add(\"timestamp\");\n    }\n\n    static boolean ignore(String key) {\n        return IGNORED.contains(key);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/ParamValue.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url.component.param;\n\npublic interface ParamValue {\n    /**\n     * get value at the specified index.\n     *\n     * @param n the nth value\n     * @return the value stored at index = n\n     */\n    String getN(int n);\n\n    /**\n     * max index is 2^31 - 1\n     *\n     * @param value the stored value\n     * @return the index of value\n     */\n    int getIndex(String value);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/AllowClassNotifyListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.Set;\n\npublic interface AllowClassNotifyListener {\n\n    SerializeCheckStatus DEFAULT_STATUS = SerializeCheckStatus.STRICT;\n\n    void notifyPrefix(Set<String> allowedList, Set<String> disAllowedList);\n\n    void notifyCheckStatus(SerializeCheckStatus status);\n\n    void notifyCheckSerializable(boolean checkSerializable);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\nimport java.lang.reflect.AnnotatedElement;\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\nimport static java.util.Arrays.asList;\nimport static java.util.Collections.emptyList;\nimport static java.util.Collections.unmodifiableList;\nimport static org.apache.dubbo.common.function.Predicates.and;\nimport static org.apache.dubbo.common.function.Streams.filterAll;\nimport static org.apache.dubbo.common.function.Streams.filterFirst;\nimport static org.apache.dubbo.common.utils.ClassUtils.getAllInheritedTypes;\nimport static org.apache.dubbo.common.utils.ClassUtils.resolveClass;\nimport static org.apache.dubbo.common.utils.CollectionUtils.first;\nimport static org.apache.dubbo.common.utils.MethodUtils.findMethod;\nimport static org.apache.dubbo.common.utils.MethodUtils.invokeMethod;\n\n/**\n * Commons Annotation Utilities class\n *\n * @since 2.7.6\n */\npublic interface AnnotationUtils {\n\n    /**\n     * Resolve the annotation type by the annotated element and resolved class name\n     *\n     * @param annotatedElement    the annotated element\n     * @param annotationClassName the class name of annotation\n     * @param <A>                 the type of annotation\n     * @return If resolved, return the type of annotation, or <code>null</code>\n     */\n    @SuppressWarnings(\"unchecked\")\n    static <A extends Annotation> Class<A> resolveAnnotationType(\n            AnnotatedElement annotatedElement, String annotationClassName) {\n        ClassLoader classLoader = annotatedElement.getClass().getClassLoader();\n        Class<?> annotationType = resolveClass(annotationClassName, classLoader);\n        if (annotationType == null || !Annotation.class.isAssignableFrom(annotationType)) {\n            return null;\n        }\n        return (Class<A>) annotationType;\n    }\n\n    /**\n     * Is the specified type a generic {@link Class type}\n     *\n     * @param annotatedElement the annotated element\n     * @return if <code>annotatedElement</code> is the {@link Class}, return <code>true</code>, or <code>false</code>\n     * @see ElementType#TYPE\n     */\n    static boolean isType(AnnotatedElement annotatedElement) {\n        return annotatedElement instanceof Class;\n    }\n\n    /**\n     * Is the type of specified annotation same to the expected type?\n     *\n     * @param annotation     the specified {@link Annotation}\n     * @param annotationType the expected annotation type\n     * @return if same, return <code>true</code>, or <code>false</code>\n     */\n    static boolean isSameType(Annotation annotation, Class<? extends Annotation> annotationType) {\n        if (annotation == null || annotationType == null) {\n            return false;\n        }\n        return Objects.equals(annotation.annotationType(), annotationType);\n    }\n\n    /**\n     * Build an instance of {@link Predicate} to excluded annotation type\n     *\n     * @param excludedAnnotationType excluded annotation type\n     * @return non-null\n     */\n    static Predicate<Annotation> excludedType(Class<? extends Annotation> excludedAnnotationType) {\n        return annotation -> !isSameType(annotation, excludedAnnotationType);\n    }\n\n    /**\n     * Get the attribute from the specified {@link Annotation annotation}\n     *\n     * @param annotation    the specified {@link Annotation annotation}\n     * @param attributeName the attribute name\n     * @param <T>           the type of attribute\n     * @return the attribute value\n     * @throws IllegalArgumentException If the attribute name can't be found\n     */\n    static <T> T getAttribute(Annotation annotation, String attributeName) throws IllegalArgumentException {\n        return annotation == null ? null : invokeMethod(annotation, attributeName);\n    }\n\n    /**\n     * Get the \"value\" attribute from the specified {@link Annotation annotation}\n     *\n     * @param annotation the specified {@link Annotation annotation}\n     * @param <T>        the type of attribute\n     * @return the value of \"value\" attribute\n     * @throws IllegalArgumentException If the attribute name can't be found\n     */\n    static <T> T getValue(Annotation annotation) throws IllegalArgumentException {\n        return getAttribute(annotation, \"value\");\n    }\n\n    /**\n     * Get the attribute from the specified {@link Annotation annotation}\n     *\n     * @param annotation     the specified {@link Annotation annotation}\n     * @param attributeNames the multiply attribute name arrays\n     * @param <T>            the type of attribute\n     * @return the attribute value\n     * @throws IllegalArgumentException If the attribute name can't be found\n     */\n    static <T> T getAttribute(Annotation annotation, String... attributeNames) throws IllegalArgumentException {\n        if (attributeNames == null || attributeNames.length == 0) {\n            return null;\n        }\n\n        for (String attributeName : attributeNames) {\n            T attribute = getAttribute(annotation, attributeName);\n\n            if (attribute == null) {\n                continue;\n            }\n\n            //  exclude string attribute  default is empty\n            if ((attribute instanceof String) && ((String) attribute).length() == 0) {\n                continue;\n            }\n\n            return attribute;\n        }\n\n        return null;\n    }\n\n    /**\n     * Get the {@link Annotation} from the specified {@link AnnotatedElement the annotated element} and\n     * {@link Annotation annotation} class name\n     *\n     * @param annotatedElement    {@link AnnotatedElement}\n     * @param annotationClassName the class name of annotation\n     * @param <A>                 The type of {@link Annotation}\n     * @return the {@link Annotation} if found\n     * @throws ClassCastException If the {@link Annotation annotation} type that client requires can't match actual type\n     */\n    static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, String annotationClassName)\n            throws ClassCastException {\n        Class<? extends Annotation> annotationType = resolveAnnotationType(annotatedElement, annotationClassName);\n        if (annotationType == null) {\n            return null;\n        }\n        return (A) annotatedElement.getAnnotation(annotationType);\n    }\n\n    /**\n     * Get annotations that are <em>directly present</em> on this element.\n     * This method ignores inherited annotations.\n     *\n     * @param annotatedElement    the annotated element\n     * @param annotationsToFilter the annotations to filter\n     * @return non-null read-only {@link List}\n     */\n    static List<Annotation> getDeclaredAnnotations(\n            AnnotatedElement annotatedElement, Predicate<Annotation>... annotationsToFilter) {\n        if (annotatedElement == null) {\n            return emptyList();\n        }\n\n        return unmodifiableList(filterAll(asList(annotatedElement.getDeclaredAnnotations()), annotationsToFilter));\n    }\n\n    /**\n     * Get all directly declared annotations of the the annotated element, not including\n     * meta annotations.\n     *\n     * @param annotatedElement    the annotated element\n     * @param annotationsToFilter the annotations to filter\n     * @return non-null read-only {@link List}\n     */\n    static List<Annotation> getAllDeclaredAnnotations(\n            AnnotatedElement annotatedElement, Predicate<Annotation>... annotationsToFilter) {\n        if (isType(annotatedElement)) {\n            return getAllDeclaredAnnotations((Class) annotatedElement, annotationsToFilter);\n        } else {\n            return getDeclaredAnnotations(annotatedElement, annotationsToFilter);\n        }\n    }\n\n    /**\n     * Get all directly declared annotations of the specified type and its' all hierarchical types, not including\n     * meta annotations.\n     *\n     * @param type                the specified type\n     * @param annotationsToFilter the annotations to filter\n     * @return non-null read-only {@link List}\n     */\n    @SuppressWarnings(\"unchecked\")\n    static List<Annotation> getAllDeclaredAnnotations(Class<?> type, Predicate<Annotation>... annotationsToFilter) {\n\n        if (type == null) {\n            return emptyList();\n        }\n\n        List<Annotation> allAnnotations = new LinkedList<>();\n\n        // All types\n        Set<Class<?>> allTypes = new LinkedHashSet<>();\n        // Add current type\n        allTypes.add(type);\n        // Add all inherited types\n        allTypes.addAll(getAllInheritedTypes(type, t -> !Object.class.equals(t)));\n\n        for (Class<?> t : allTypes) {\n            allAnnotations.addAll(getDeclaredAnnotations(t, annotationsToFilter));\n        }\n\n        return unmodifiableList(allAnnotations);\n    }\n\n    /**\n     * Get the meta-annotated {@link Annotation annotations} directly, excluding {@link Target}, {@link Retention}\n     * and {@link Documented}\n     *\n     * @param annotationType          the {@link Annotation annotation} type\n     * @param metaAnnotationsToFilter the meta annotations to filter\n     * @return non-null read-only {@link List}\n     */\n    @SuppressWarnings(\"unchecked\")\n    static List<Annotation> getMetaAnnotations(\n            Class<? extends Annotation> annotationType, Predicate<Annotation>... metaAnnotationsToFilter) {\n        return getDeclaredAnnotations(\n                annotationType,\n                // Excludes the Java native annotation types or it causes the stack overflow, e.g,\n                // @Target annotates itself\n                excludedType(Target.class),\n                excludedType(Retention.class),\n                excludedType(Documented.class),\n                // Add other predicates\n                and(metaAnnotationsToFilter));\n    }\n\n    /**\n     * Get all meta annotations from the specified {@link Annotation annotation} type\n     *\n     * @param annotationType      the {@link Annotation annotation} type\n     * @param annotationsToFilter the annotations to filter\n     * @return non-null read-only {@link List}\n     */\n    @SuppressWarnings(\"unchecked\")\n    static List<Annotation> getAllMetaAnnotations(\n            Class<? extends Annotation> annotationType, Predicate<Annotation>... annotationsToFilter) {\n\n        List<Annotation> allMetaAnnotations = new LinkedList<>();\n\n        List<Annotation> metaAnnotations = getMetaAnnotations(annotationType);\n\n        allMetaAnnotations.addAll(metaAnnotations);\n\n        for (Annotation metaAnnotation : metaAnnotations) {\n            // Get the nested meta annotations recursively\n            allMetaAnnotations.addAll(getAllMetaAnnotations(metaAnnotation.annotationType()));\n        }\n\n        return unmodifiableList(filterAll(allMetaAnnotations, annotationsToFilter));\n    }\n\n    /**\n     * Find the annotation that is annotated on the specified element may be a meta-annotation\n     *\n     * @param annotatedElement    the annotated element\n     * @param annotationClassName the class name of annotation\n     * @param <A>                 the required type of annotation\n     * @return If found, return first matched-type {@link Annotation annotation}, or <code>null</code>\n     */\n    static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, String annotationClassName) {\n        return findAnnotation(annotatedElement, resolveAnnotationType(annotatedElement, annotationClassName));\n    }\n\n    /**\n     * Find the annotation that is annotated on the specified element may be a meta-annotation\n     *\n     * @param annotatedElement the annotated element\n     * @param annotationType   the type of annotation\n     * @param <A>              the required type of annotation\n     * @return If found, return first matched-type {@link Annotation annotation}, or <code>null</code>\n     */\n    @SuppressWarnings(\"unchecked\")\n    static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {\n        return (A) filterFirst(getAllDeclaredAnnotations(annotatedElement), a -> isSameType(a, annotationType));\n    }\n\n    /**\n     * Find the meta annotations from the the {@link Annotation annotation} type by meta annotation type\n     *\n     * @param annotationType     the {@link Annotation annotation} type\n     * @param metaAnnotationType the meta annotation type\n     * @param <A>                the type of required annotation\n     * @return if found, return all matched results, or get an {@link Collections#emptyList() empty list}\n     */\n    @SuppressWarnings(\"unchecked\")\n    static <A extends Annotation> List<A> findMetaAnnotations(\n            Class<? extends Annotation> annotationType, Class<A> metaAnnotationType) {\n        return (List<A>) getAllMetaAnnotations(annotationType, a -> isSameType(a, metaAnnotationType));\n    }\n\n    /**\n     * Find the meta annotations from the the the annotated element by meta annotation type\n     *\n     * @param annotatedElement   the annotated element\n     * @param metaAnnotationType the meta annotation type\n     * @param <A>                the type of required annotation\n     * @return if found, return all matched results, or get an {@link Collections#emptyList() empty list}\n     */\n    @SuppressWarnings(\"unchecked\")\n    static <A extends Annotation> List<A> findMetaAnnotations(\n            AnnotatedElement annotatedElement, Class<A> metaAnnotationType) {\n        List<A> metaAnnotations = new LinkedList<>();\n\n        for (Annotation annotation : getAllDeclaredAnnotations(annotatedElement)) {\n            metaAnnotations.addAll(findMetaAnnotations(annotation.annotationType(), metaAnnotationType));\n        }\n\n        return unmodifiableList(metaAnnotations);\n    }\n\n    /**\n     * Find the meta annotation from the annotated element by meta annotation type\n     *\n     * @param annotatedElement        the annotated element\n     * @param metaAnnotationClassName the class name of meta annotation\n     * @param <A>                     the type of required annotation\n     * @return {@link #findMetaAnnotation(Class, Class)}\n     */\n    static <A extends Annotation> A findMetaAnnotation(\n            AnnotatedElement annotatedElement, String metaAnnotationClassName) {\n        return findMetaAnnotation(annotatedElement, resolveAnnotationType(annotatedElement, metaAnnotationClassName));\n    }\n\n    /**\n     * Find the meta annotation from the annotation type by meta annotation type\n     *\n     * @param annotationType     the {@link Annotation annotation} type\n     * @param metaAnnotationType the meta annotation type\n     * @param <A>                the type of required annotation\n     * @return If found, return the {@link CollectionUtils#first(Collection)} matched result, return <code>null</code>.\n     * If it requires more result, please consider to use {@link #findMetaAnnotations(Class, Class)}\n     * @see #findMetaAnnotations(Class, Class)\n     */\n    static <A extends Annotation> A findMetaAnnotation(\n            Class<? extends Annotation> annotationType, Class<A> metaAnnotationType) {\n        return first(findMetaAnnotations(annotationType, metaAnnotationType));\n    }\n\n    /**\n     * Find the meta annotation from the annotated element by meta annotation type\n     *\n     * @param annotatedElement   the annotated element\n     * @param metaAnnotationType the meta annotation type\n     * @param <A>                the type of required annotation\n     * @return If found, return the {@link CollectionUtils#first(Collection)} matched result, return <code>null</code>.\n     * If it requires more result, please consider to use {@link #findMetaAnnotations(AnnotatedElement, Class)}\n     * @see #findMetaAnnotations(AnnotatedElement, Class)\n     */\n    static <A extends Annotation> A findMetaAnnotation(AnnotatedElement annotatedElement, Class<A> metaAnnotationType) {\n        return first(findMetaAnnotations(annotatedElement, metaAnnotationType));\n    }\n\n    /**\n     * Tests the annotated element is annotated the specified annotations or not\n     *\n     * @param type            the annotated type\n     * @param matchAll        If <code>true</code>, checking all annotation types are present or not, or match any\n     * @param annotationTypes the specified annotation types\n     * @return If the specified annotation types are present, return <code>true</code>, or <code>false</code>\n     */\n    static boolean isAnnotationPresent(\n            Class<?> type, boolean matchAll, Class<? extends Annotation>... annotationTypes) {\n\n        int size = annotationTypes == null ? 0 : annotationTypes.length;\n\n        if (size < 1) {\n            return false;\n        }\n\n        int presentCount = 0;\n\n        for (int i = 0; i < size; i++) {\n            Class<? extends Annotation> annotationType = annotationTypes[i];\n            if (findAnnotation(type, annotationType) != null || findMetaAnnotation(type, annotationType) != null) {\n                presentCount++;\n            }\n        }\n\n        return matchAll ? presentCount == size : presentCount > 0;\n    }\n\n    /**\n     * Tests the annotated element is annotated the specified annotation or not\n     *\n     * @param type           the annotated type\n     * @param annotationType the class of annotation\n     * @return If the specified annotation type is present, return <code>true</code>, or <code>false</code>\n     */\n    @SuppressWarnings(\"unchecked\")\n    static boolean isAnnotationPresent(Class<?> type, Class<? extends Annotation> annotationType) {\n        return isAnnotationPresent(type, true, annotationType);\n    }\n\n    /**\n     * Tests the annotated element is present any specified annotation types\n     *\n     * @param annotatedElement    the annotated element\n     * @param annotationClassName the class name of annotation\n     * @return If any specified annotation types are present, return <code>true</code>\n     */\n    @SuppressWarnings(\"unchecked\")\n    static boolean isAnnotationPresent(AnnotatedElement annotatedElement, String annotationClassName) {\n        ClassLoader classLoader = annotatedElement.getClass().getClassLoader();\n        Class<?> resolvedType = resolveClass(annotationClassName, classLoader);\n        if (resolvedType == null || !Annotation.class.isAssignableFrom(resolvedType)) {\n            return false;\n        }\n        return isAnnotationPresent(annotatedElement, (Class<? extends Annotation>) resolvedType);\n    }\n\n    /**\n     * Tests the annotated element is present any specified annotation types\n     *\n     * @param annotatedElement the annotated element\n     * @param annotationType   the class of annotation\n     * @return If any specified annotation types are present, return <code>true</code>\n     */\n    static boolean isAnnotationPresent(AnnotatedElement annotatedElement, Class<? extends Annotation> annotationType) {\n        if (isType(annotatedElement)) {\n            return isAnnotationPresent((Class) annotatedElement, annotationType);\n        } else {\n            return annotatedElement.isAnnotationPresent(annotationType)\n                    || findMetaAnnotation(annotatedElement, annotationType) != null; // to find meta-annotation\n        }\n    }\n\n    /**\n     * Tests the annotated element is annotated all specified annotations or not\n     *\n     * @param type            the annotated type\n     * @param annotationTypes the specified annotation types\n     * @return If the specified annotation types are present, return <code>true</code>, or <code>false</code>\n     */\n    static boolean isAllAnnotationPresent(Class<?> type, Class<? extends Annotation>... annotationTypes) {\n        return isAnnotationPresent(type, true, annotationTypes);\n    }\n\n    /**\n     * Tests the annotated element is present any specified annotation types\n     *\n     * @param type            the annotated type\n     * @param annotationTypes the specified annotation types\n     * @return If any specified annotation types are present, return <code>true</code>\n     */\n    static boolean isAnyAnnotationPresent(Class<?> type, Class<? extends Annotation>... annotationTypes) {\n        return isAnnotationPresent(type, false, annotationTypes);\n    }\n\n    /**\n     * Get the default value of attribute on the specified annotation\n     *\n     * @param annotation    {@link Annotation} object\n     * @param attributeName the name of attribute\n     * @param <T>           the type of value\n     * @return <code>null</code> if not found\n     * @since 2.7.9\n     */\n    static <T> T getDefaultValue(Annotation annotation, String attributeName) {\n        return getDefaultValue(annotation.annotationType(), attributeName);\n    }\n\n    /**\n     * Get the default value of attribute on the specified annotation\n     *\n     * @param annotationType the type of {@link Annotation}\n     * @param attributeName  the name of attribute\n     * @param <T>            the type of value\n     * @return <code>null</code> if not found\n     * @since 2.7.9\n     */\n    @SuppressWarnings(\"unchecked\")\n    static <T> T getDefaultValue(Class<? extends Annotation> annotationType, String attributeName) {\n        Method method = findMethod(annotationType, attributeName);\n        return (T) (method == null ? null : method.getDefaultValue());\n    }\n\n    /**\n     * Filter default value of Annotation type\n     * @param annotationType annotation type from {@link Annotation#annotationType()}\n     * @param attributes\n     * @return\n     */\n    static Map<String, Object> filterDefaultValues(\n            Class<? extends Annotation> annotationType, Map<String, Object> attributes) {\n        Map<String, Object> filteredAttributes = new LinkedHashMap<>(attributes.size());\n        attributes.forEach((key, val) -> {\n            if (!Objects.deepEquals(val, getDefaultValue(annotationType, key))) {\n                filteredAttributes.put(key, val);\n            }\n        });\n        // remove void class, compatible with spring 3.x\n        Object interfaceClassValue = filteredAttributes.get(\"interfaceClass\");\n        if (interfaceClassValue instanceof String && StringUtils.isEquals((String) interfaceClassValue, \"void\")) {\n            filteredAttributes.remove(\"interfaceClass\");\n        }\n        return filteredAttributes;\n    }\n\n    /**\n     * Filter default value of Annotation type\n     * @param annotation\n     * @param attributes\n     * @return\n     */\n    static Map<String, Object> filterDefaultValues(Annotation annotation, Map<String, Object> attributes) {\n        return filterDefaultValues(annotation.annotationType(), attributes);\n    }\n\n    /**\n     * Get attributes of annotation\n     * @param annotation\n     * @return\n     */\n    static Map<String, Object> getAttributes(Annotation annotation, boolean filterDefaultValue) {\n        Class<?> annotationType = annotation.annotationType();\n        Method[] methods = annotationType.getMethods();\n        Map<String, Object> attributes = new LinkedHashMap<>(methods.length);\n        for (Method method : methods) {\n            try {\n                if (method.getDeclaringClass() == Annotation.class) {\n                    continue;\n                }\n                String name = method.getName();\n                Object value = method.invoke(annotation);\n                if (!filterDefaultValue || !Objects.deepEquals(value, method.getDefaultValue())) {\n                    attributes.put(name, value);\n                }\n            } catch (Exception e) {\n                throw new IllegalStateException(\"get attribute value of annotation failed: \" + method, e);\n            }\n        }\n        return attributes;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ArrayUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\n/**\n * Contains some methods to check array.\n */\npublic final class ArrayUtils {\n\n    private ArrayUtils() {}\n\n    /**\n     * <p>Checks if the array is null or empty. <p/>\n     *\n     * @param array th array to check\n     * @return {@code true} if the array is null or empty.\n     */\n    public static boolean isEmpty(final Object[] array) {\n        return array == null || array.length == 0;\n    }\n\n    /**\n     * <p>Checks if the array is not null or empty. <p/>\n     *\n     * @param array th array to check\n     * @return {@code true} if the array is not null or empty.\n     */\n    public static boolean isNotEmpty(final Object[] array) {\n        return !isEmpty(array);\n    }\n\n    public static boolean contains(final String[] array, String valueToFind) {\n        return indexOf(array, valueToFind, 0) != -1;\n    }\n\n    public static int indexOf(String[] array, String valueToFind, int startIndex) {\n        if (isEmpty(array) || valueToFind == null) {\n            return -1;\n        } else {\n            if (startIndex < 0) {\n                startIndex = 0;\n            }\n\n            for (int i = startIndex; i < array.length; ++i) {\n                if (valueToFind.equals(array[i])) {\n                    return i;\n                }\n            }\n\n            return -1;\n        }\n    }\n\n    /**\n     * Convert from variable arguments to array\n     *\n     * @param values variable arguments\n     * @param <T>    The class\n     * @return array\n     * @since 2.7.9\n     */\n    public static <T> T[] of(T... values) {\n        return values;\n    }\n\n    public static <T> T first(T[] data) {\n        return isEmpty(data) ? null : data[0];\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/Assert.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.function.Supplier;\n\npublic abstract class Assert {\n\n    protected Assert() {}\n\n    public static void notNull(Object obj, String message) {\n        if (obj == null) {\n            throw new IllegalArgumentException(message);\n        }\n    }\n\n    public static void notNull(Object obj, String format, Object... args) {\n        if (obj == null) {\n            throw new IllegalArgumentException(String.format(format, args));\n        }\n    }\n\n    public static void notEmptyString(String str, String message) {\n        if (StringUtils.isEmpty(str)) {\n            throw new IllegalArgumentException(message);\n        }\n    }\n\n    public static void notNull(Object obj, RuntimeException exception) {\n        if (obj == null) {\n            throw exception;\n        }\n    }\n\n    public static void assertTrue(boolean condition, String message) {\n        if (!condition) {\n            throw new IllegalArgumentException(message);\n        }\n    }\n\n    public static void assertTrue(boolean expression, Supplier<String> messageSupplier) {\n        if (!expression) {\n            throw new IllegalStateException(nullSafeGet(messageSupplier));\n        }\n    }\n\n    private static String nullSafeGet(Supplier<String> messageSupplier) {\n        return (messageSupplier != null ? messageSupplier.get() : null);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/AtomicPositiveInteger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.concurrent.atomic.AtomicIntegerFieldUpdater;\n\npublic class AtomicPositiveInteger extends Number {\n\n    private static final long serialVersionUID = -3038533876489105940L;\n\n    private static final AtomicIntegerFieldUpdater<AtomicPositiveInteger> INDEX_UPDATER =\n            AtomicIntegerFieldUpdater.newUpdater(AtomicPositiveInteger.class, \"index\");\n\n    @SuppressWarnings(\"unused\")\n    private volatile int index = 0;\n\n    public AtomicPositiveInteger() {}\n\n    public AtomicPositiveInteger(int initialValue) {\n        INDEX_UPDATER.set(this, initialValue);\n    }\n\n    public final int getAndIncrement() {\n        return INDEX_UPDATER.getAndIncrement(this) & Integer.MAX_VALUE;\n    }\n\n    public final int getAndDecrement() {\n        return INDEX_UPDATER.getAndDecrement(this) & Integer.MAX_VALUE;\n    }\n\n    public final int incrementAndGet() {\n        return INDEX_UPDATER.incrementAndGet(this) & Integer.MAX_VALUE;\n    }\n\n    public final int decrementAndGet() {\n        return INDEX_UPDATER.decrementAndGet(this) & Integer.MAX_VALUE;\n    }\n\n    public final int get() {\n        return INDEX_UPDATER.get(this) & Integer.MAX_VALUE;\n    }\n\n    public final void set(int newValue) {\n        if (newValue < 0) {\n            throw new IllegalArgumentException(\"new value \" + newValue + \" < 0\");\n        }\n        INDEX_UPDATER.set(this, newValue);\n    }\n\n    public final int getAndSet(int newValue) {\n        if (newValue < 0) {\n            throw new IllegalArgumentException(\"new value \" + newValue + \" < 0\");\n        }\n        return INDEX_UPDATER.getAndSet(this, newValue) & Integer.MAX_VALUE;\n    }\n\n    public final int getAndAdd(int delta) {\n        if (delta < 0) {\n            throw new IllegalArgumentException(\"delta \" + delta + \" < 0\");\n        }\n        return INDEX_UPDATER.getAndAdd(this, delta) & Integer.MAX_VALUE;\n    }\n\n    public final int addAndGet(int delta) {\n        if (delta < 0) {\n            throw new IllegalArgumentException(\"delta \" + delta + \" < 0\");\n        }\n        return INDEX_UPDATER.addAndGet(this, delta) & Integer.MAX_VALUE;\n    }\n\n    public final boolean compareAndSet(int expect, int update) {\n        if (update < 0) {\n            throw new IllegalArgumentException(\"update value \" + update + \" < 0\");\n        }\n        return INDEX_UPDATER.compareAndSet(this, expect, update);\n    }\n\n    public final boolean weakCompareAndSet(int expect, int update) {\n        if (update < 0) {\n            throw new IllegalArgumentException(\"update value \" + update + \" < 0\");\n        }\n        return INDEX_UPDATER.weakCompareAndSet(this, expect, update);\n    }\n\n    @Override\n    public byte byteValue() {\n        return (byte) get();\n    }\n\n    @Override\n    public short shortValue() {\n        return (short) get();\n    }\n\n    @Override\n    public int intValue() {\n        return get();\n    }\n\n    @Override\n    public long longValue() {\n        return (long) get();\n    }\n\n    @Override\n    public float floatValue() {\n        return (float) get();\n    }\n\n    @Override\n    public double doubleValue() {\n        return (double) get();\n    }\n\n    @Override\n    public String toString() {\n        return Integer.toString(get());\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + get();\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof AtomicPositiveInteger)) {\n            return false;\n        }\n        AtomicPositiveInteger other = (AtomicPositiveInteger) obj;\n        return intValue() == other.intValue();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/CIDRUtils.java",
    "content": "/*\n * The MIT License\n *\n * Copyright (c) 2013 Edin Dazdarevic (edin.dazdarevic@gmail.com)\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n **/\npackage org.apache.dubbo.common.utils;\n\nimport java.math.BigInteger;\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * A class that enables to get an IP range from CIDR specification. It supports\n * both IPv4 and IPv6.\n * <p>\n * From https://github.com/edazdarevic/CIDRUtils/blob/master/CIDRUtils.java\n */\npublic class CIDRUtils {\n    private final String cidr;\n\n    private InetAddress inetAddress;\n    private InetAddress startAddress;\n    private InetAddress endAddress;\n    private final int prefixLength;\n\n\n    public CIDRUtils(String cidr) throws UnknownHostException {\n\n        this.cidr = cidr;\n\n        /* split CIDR to address and prefix part */\n        if (this.cidr.contains(\"/\")) {\n            int index = this.cidr.indexOf(\"/\");\n            String addressPart = this.cidr.substring(0, index);\n            String networkPart = this.cidr.substring(index + 1);\n\n            inetAddress = InetAddress.getByName(addressPart);\n            prefixLength = Integer.parseInt(networkPart);\n\n            calculate();\n        } else {\n            throw new IllegalArgumentException(\"not an valid CIDR format!\");\n        }\n    }\n\n\n    private void calculate() throws UnknownHostException {\n\n        ByteBuffer maskBuffer;\n        int targetSize;\n        if (inetAddress.getAddress().length == 4) {\n            maskBuffer =\n                    ByteBuffer\n                            .allocate(4)\n                            .putInt(-1);\n            targetSize = 4;\n        } else {\n            maskBuffer = ByteBuffer.allocate(16)\n                    .putLong(-1L)\n                    .putLong(-1L);\n            targetSize = 16;\n        }\n\n        BigInteger mask = (new BigInteger(1, maskBuffer.array())).not().shiftRight(prefixLength);\n\n        ByteBuffer buffer = ByteBuffer.wrap(inetAddress.getAddress());\n        BigInteger ipVal = new BigInteger(1, buffer.array());\n\n        BigInteger startIp = ipVal.and(mask);\n        BigInteger endIp = startIp.add(mask.not());\n\n        byte[] startIpArr = toBytes(startIp.toByteArray(), targetSize);\n        byte[] endIpArr = toBytes(endIp.toByteArray(), targetSize);\n\n        this.startAddress = InetAddress.getByAddress(startIpArr);\n        this.endAddress = InetAddress.getByAddress(endIpArr);\n\n    }\n\n    private byte[] toBytes(byte[] array, int targetSize) {\n        int counter = 0;\n        List<Byte> newArr = new ArrayList<>();\n        while (counter < targetSize && (array.length - 1 - counter >= 0)) {\n            newArr.add(0, array[array.length - 1 - counter]);\n            counter++;\n        }\n\n        int size = newArr.size();\n        for (int i = 0; i < (targetSize - size); i++) {\n\n            newArr.add(0, (byte) 0);\n        }\n\n        byte[] ret = new byte[newArr.size()];\n        for (int i = 0; i < newArr.size(); i++) {\n            ret[i] = newArr.get(i);\n        }\n        return ret;\n    }\n\n    public String getNetworkAddress() {\n\n        return this.startAddress.getHostAddress();\n    }\n\n    public String getBroadcastAddress() {\n        return this.endAddress.getHostAddress();\n    }\n\n    public boolean isInRange(String ipAddress) throws UnknownHostException {\n        InetAddress address = InetAddress.getByName(ipAddress);\n        BigInteger start = new BigInteger(1, this.startAddress.getAddress());\n        BigInteger end = new BigInteger(1, this.endAddress.getAddress());\n        BigInteger target = new BigInteger(1, address.getAddress());\n\n        int st = start.compareTo(target);\n        int te = target.compareTo(end);\n\n        return (st == -1 || st == 0) && (te == -1 || te == 0);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/CacheableSupplier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.function.Supplier;\n\npublic class CacheableSupplier<T> implements Supplier<T> {\n\n    private volatile T object;\n\n    private final Supplier<T> supplier;\n\n    public CacheableSupplier(Supplier<T> supplier) {\n        this.supplier = supplier;\n    }\n\n    public static <T> CacheableSupplier<T> newSupplier(Supplier<T> supplier) {\n        return new CacheableSupplier<>(supplier);\n    }\n\n    @Override\n    public T get() {\n        if (this.object == null) {\n            this.object = supplier.get();\n        }\n        return object;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/CharSequenceComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.Comparator;\n\n/**\n * The {@link Comparator} for {@link CharSequence}\n *\n * @since 2.7.6\n */\npublic class CharSequenceComparator implements Comparator<CharSequence> {\n\n    public static final CharSequenceComparator INSTANCE = new CharSequenceComparator();\n\n    private CharSequenceComparator() {}\n\n    @Override\n    public int compare(CharSequence c1, CharSequence c2) {\n        return c1.toString().compareTo(c2.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassHelper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Method;\n\n/**\n * @see org.apache.dubbo.common.utils.ClassUtils\n * @deprecated Replace to <code>ClassUtils</code>\n */\npublic class ClassHelper {\n    public static Class<?> forNameWithThreadContextClassLoader(String name) throws ClassNotFoundException {\n        return ClassUtils.forName(name, Thread.currentThread().getContextClassLoader());\n    }\n\n    public static Class<?> forNameWithCallerClassLoader(String name, Class<?> caller) throws ClassNotFoundException {\n        return ClassUtils.forName(name, caller.getClassLoader());\n    }\n\n    public static ClassLoader getCallerClassLoader(Class<?> caller) {\n        return caller.getClassLoader();\n    }\n\n    /**\n     * get class loader\n     *\n     * @param clazz\n     * @return class loader\n     */\n    public static ClassLoader getClassLoader(Class<?> clazz) {\n        return ClassUtils.getClassLoader(clazz);\n    }\n\n    /**\n     * Return the default ClassLoader to use: typically the thread context\n     * ClassLoader, if available; the ClassLoader that loaded the ClassUtils\n     * class will be used as fallback.\n     * <p>\n     * Call this method if you intend to use the thread context ClassLoader in a\n     * scenario where you absolutely need a non-null ClassLoader reference: for\n     * example, for class path resource loading (but not necessarily for\n     * <code>Class.forName</code>, which accepts a <code>null</code> ClassLoader\n     * reference as well).\n     *\n     * @return the default ClassLoader (never <code>null</code>)\n     * @see java.lang.Thread#getContextClassLoader()\n     */\n    public static ClassLoader getClassLoader() {\n        return getClassLoader(ClassHelper.class);\n    }\n\n    /**\n     * Same as <code>Class.forName()</code>, except that it works for primitive\n     * types.\n     */\n    public static Class<?> forName(String name) throws ClassNotFoundException {\n        return forName(name, getClassLoader());\n    }\n\n    /**\n     * Replacement for <code>Class.forName()</code> that also returns Class\n     * instances for primitives (like \"int\") and array class names (like\n     * \"String[]\").\n     *\n     * @param name        the name of the Class\n     * @param classLoader the class loader to use (may be <code>null</code>,\n     *                    which indicates the default class loader)\n     * @return Class instance for the supplied name\n     * @throws ClassNotFoundException if the class was not found\n     * @throws LinkageError           if the class file could not be loaded\n     * @see Class#forName(String, boolean, ClassLoader)\n     */\n    public static Class<?> forName(String name, ClassLoader classLoader) throws ClassNotFoundException, LinkageError {\n        return ClassUtils.forName(name, classLoader);\n    }\n\n    /**\n     * Resolve the given class name as primitive class, if appropriate,\n     * according to the JVM's naming rules for primitive classes.\n     * <p>\n     * Also supports the JVM's internal class names for primitive arrays. Does\n     * <i>not</i> support the \"[]\" suffix notation for primitive arrays; this is\n     * only supported by {@link #forName}.\n     *\n     * @param name the name of the potentially primitive class\n     * @return the primitive class, or <code>null</code> if the name does not\n     * denote a primitive class or primitive array class\n     */\n    public static Class<?> resolvePrimitiveClassName(String name) {\n        return ClassUtils.resolvePrimitiveClassName(name);\n    }\n\n    public static String toShortString(Object obj) {\n        return ClassUtils.toShortString(obj);\n    }\n\n    public static String simpleClassName(Class<?> clazz) {\n        return ClassUtils.simpleClassName(clazz);\n    }\n\n    /**\n     * @see org.apache.dubbo.common.utils.MethodUtils#isSetter(Method)\n     * @deprecated Replace to <code>MethodUtils#isSetter(Method)</code>\n     */\n    public static boolean isSetter(Method method) {\n        return MethodUtils.isSetter(method);\n    }\n\n    /**\n     * @see org.apache.dubbo.common.utils.MethodUtils#isGetter(Method) (Method)\n     * @deprecated Replace to <code>MethodUtils#isGetter(Method)</code>\n     */\n    public static boolean isGetter(Method method) {\n        return MethodUtils.isGetter(method);\n    }\n\n    public static boolean isPrimitive(Class<?> type) {\n        return ClassUtils.isPrimitive(type);\n    }\n\n    public static Object convertPrimitive(Class<?> type, String value) {\n        return ClassUtils.convertPrimitive(type, value);\n    }\n\n    /**\n     * We only check boolean value at this moment.\n     *\n     * @param type\n     * @param value\n     * @return\n     */\n    public static boolean isTypeMatch(Class<?> type, String value) {\n        return ClassUtils.isTypeMatch(type, value);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassLoaderResourceLoader.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.resource.GlobalResourcesRepository;\n\nimport java.io.IOException;\nimport java.lang.ref.SoftReference;\nimport java.net.URL;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CountDownLatch;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_IO_EXCEPTION;\n\npublic class ClassLoaderResourceLoader {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ClassLoaderResourceLoader.class);\n    private static SoftReference<Map<ClassLoader, Map<String, Set<URL>>>> classLoaderResourcesCache = null;\n\n    static {\n        // register resources destroy listener\n        GlobalResourcesRepository.registerGlobalDisposable(ClassLoaderResourceLoader::destroy);\n    }\n\n    public static Map<ClassLoader, Set<URL>> loadResources(String fileName, Collection<ClassLoader> classLoaders)\n            throws InterruptedException {\n        Map<ClassLoader, Set<URL>> resources = new ConcurrentHashMap<>();\n        CountDownLatch countDownLatch = new CountDownLatch(classLoaders.size());\n        for (ClassLoader classLoader : classLoaders) {\n            GlobalResourcesRepository.getGlobalExecutorService().submit(() -> {\n                resources.put(classLoader, loadResources(fileName, classLoader));\n                countDownLatch.countDown();\n            });\n        }\n        countDownLatch.await();\n        return Collections.unmodifiableMap(new LinkedHashMap<>(resources));\n    }\n\n    public static Set<URL> loadResources(String fileName, ClassLoader currentClassLoader) {\n        Map<ClassLoader, Map<String, Set<URL>>> classLoaderCache;\n        if (classLoaderResourcesCache == null || (classLoaderCache = classLoaderResourcesCache.get()) == null) {\n            synchronized (ClassLoaderResourceLoader.class) {\n                if (classLoaderResourcesCache == null || (classLoaderCache = classLoaderResourcesCache.get()) == null) {\n                    classLoaderCache = new ConcurrentHashMap<>();\n                    classLoaderResourcesCache = new SoftReference<>(classLoaderCache);\n                }\n            }\n        }\n        if (!classLoaderCache.containsKey(currentClassLoader)) {\n            classLoaderCache.putIfAbsent(currentClassLoader, new ConcurrentHashMap<>());\n        }\n        Map<String, Set<URL>> urlCache = classLoaderCache.get(currentClassLoader);\n        if (!urlCache.containsKey(fileName)) {\n            Set<URL> set = new LinkedHashSet<>();\n            Enumeration<URL> urls;\n            try {\n                urls = currentClassLoader.getResources(fileName);\n                if (urls != null) {\n                    while (urls.hasMoreElements()) {\n                        URL url = urls.nextElement();\n                        set.add(url);\n                    }\n                }\n            } catch (IOException e) {\n                logger.error(\n                        COMMON_IO_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Exception occurred when reading SPI definitions. SPI path: \" + fileName + \" ClassLoader name: \"\n                                + currentClassLoader,\n                        e);\n            }\n            urlCache.put(fileName, set);\n        }\n        return urlCache.get(fileName);\n    }\n\n    public static void destroy() {\n        synchronized (ClassLoaderResourceLoader.class) {\n            classLoaderResourcesCache = null;\n        }\n    }\n\n    // for test\n    protected static SoftReference<Map<ClassLoader, Map<String, Set<URL>>>> getClassLoaderResourcesCache() {\n        return classLoaderResourcesCache;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.convert.ConverterUtil;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Method;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport static java.util.Collections.emptySet;\nimport static java.util.Collections.unmodifiableSet;\nimport static org.apache.dubbo.common.function.Streams.filterAll;\nimport static org.apache.dubbo.common.utils.ArrayUtils.isNotEmpty;\nimport static org.apache.dubbo.common.utils.CollectionUtils.flip;\nimport static org.apache.dubbo.common.utils.CollectionUtils.ofSet;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\n\npublic class ClassUtils {\n    /**\n     * Suffix for array class names: \"[]\"\n     */\n    public static final String ARRAY_SUFFIX = \"[]\";\n    /**\n     * Simple Types including:\n     * <ul>\n     *     <li>{@link Void}</li>\n     *     <li>{@link Boolean}</li>\n     *     <li>{@link Character}</li>\n     *     <li>{@link Byte}</li>\n     *     <li>{@link Integer}</li>\n     *     <li>{@link Float}</li>\n     *     <li>{@link Double}</li>\n     *     <li>{@link String}</li>\n     *     <li>{@link BigDecimal}</li>\n     *     <li>{@link BigInteger}</li>\n     *     <li>{@link Date}</li>\n     *     <li>{@link Object}</li>\n     * </ul>\n     *\n     * @see javax.management.openmbean.SimpleType\n     * @since 2.7.6\n     */\n    public static final Set<Class<?>> SIMPLE_TYPES = ofSet(\n            Void.class,\n            Boolean.class,\n            Character.class,\n            Byte.class,\n            Short.class,\n            Integer.class,\n            Long.class,\n            Float.class,\n            Double.class,\n            String.class,\n            BigDecimal.class,\n            BigInteger.class,\n            Date.class,\n            Object.class,\n            Duration.class);\n    /**\n     * Prefix for internal array class names: \"[L\"\n     */\n    private static final String INTERNAL_ARRAY_PREFIX = \"[L\";\n    /**\n     * Map with primitive type name as key and corresponding primitive type as\n     * value, for example: \"int\" -> \"int.class\".\n     */\n    private static final Map<String, Class<?>> PRIMITIVE_TYPE_NAME_MAP = new HashMap<>(32);\n    /**\n     * Map with primitive wrapper type as key and corresponding primitive type\n     * as value, for example: Integer.class -> int.class.\n     */\n    private static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_TYPE_MAP = new HashMap<>(16);\n\n    static {\n        PRIMITIVE_WRAPPER_TYPE_MAP.put(Boolean.class, boolean.class);\n        PRIMITIVE_WRAPPER_TYPE_MAP.put(Byte.class, byte.class);\n        PRIMITIVE_WRAPPER_TYPE_MAP.put(Character.class, char.class);\n        PRIMITIVE_WRAPPER_TYPE_MAP.put(Double.class, double.class);\n        PRIMITIVE_WRAPPER_TYPE_MAP.put(Float.class, float.class);\n        PRIMITIVE_WRAPPER_TYPE_MAP.put(Integer.class, int.class);\n        PRIMITIVE_WRAPPER_TYPE_MAP.put(Long.class, long.class);\n        PRIMITIVE_WRAPPER_TYPE_MAP.put(Short.class, short.class);\n        PRIMITIVE_WRAPPER_TYPE_MAP.put(Void.class, void.class);\n\n        Set<Class<?>> primitiveTypeNames = new HashSet<>(32);\n        primitiveTypeNames.addAll(PRIMITIVE_WRAPPER_TYPE_MAP.values());\n        primitiveTypeNames.addAll(Arrays.asList(\n                boolean[].class,\n                byte[].class,\n                char[].class,\n                double[].class,\n                float[].class,\n                int[].class,\n                long[].class,\n                short[].class));\n        for (Class<?> primitiveTypeName : primitiveTypeNames) {\n            PRIMITIVE_TYPE_NAME_MAP.put(primitiveTypeName.getName(), primitiveTypeName);\n        }\n    }\n\n    /**\n     * Map with primitive type as key and corresponding primitive wrapper type\n     * as value, for example: int.class -> Integer.class.\n     */\n    private static final Map<Class<?>, Class<?>> WRAPPER_PRIMITIVE_TYPE_MAP = flip(PRIMITIVE_WRAPPER_TYPE_MAP);\n\n    /**\n     * Separator char for package\n     */\n    private static final char PACKAGE_SEPARATOR_CHAR = '.';\n\n    public static Class<?> forNameWithThreadContextClassLoader(String name) throws ClassNotFoundException {\n        return forName(name, Thread.currentThread().getContextClassLoader());\n    }\n\n    public static Class<?> forNameWithCallerClassLoader(String name, Class<?> caller) throws ClassNotFoundException {\n        return forName(name, caller.getClassLoader());\n    }\n\n    public static ClassLoader getCallerClassLoader(Class<?> caller) {\n        return caller.getClassLoader();\n    }\n\n    /**\n     * get class loader\n     *\n     * @param clazz\n     * @return class loader\n     */\n    public static ClassLoader getClassLoader(Class<?> clazz) {\n        ClassLoader cl = null;\n        if (!clazz.getName().startsWith(\"org.apache.dubbo\")) {\n            cl = clazz.getClassLoader();\n        }\n        if (cl == null) {\n            try {\n                cl = Thread.currentThread().getContextClassLoader();\n            } catch (Exception ignored) {\n                // Cannot access thread context ClassLoader - falling back to system class loader...\n            }\n            if (cl == null) {\n                // No thread context class loader -> use class loader of this class.\n                cl = clazz.getClassLoader();\n                if (cl == null) {\n                    // getClassLoader() returning null indicates the bootstrap ClassLoader\n                    try {\n                        cl = ClassLoader.getSystemClassLoader();\n                    } catch (Exception ignored) {\n                        // Cannot access system ClassLoader - oh well, maybe the caller can live with null...\n                    }\n                }\n            }\n        }\n\n        return cl;\n    }\n\n    /**\n     * Return the default ClassLoader to use: typically the thread context\n     * ClassLoader, if available; the ClassLoader that loaded the ClassUtils\n     * class will be used as fallback.\n     * <p>\n     * Call this method if you intend to use the thread context ClassLoader in a\n     * scenario where you absolutely need a non-null ClassLoader reference: for\n     * example, for class path resource loading (but not necessarily for\n     * <code>Class.forName</code>, which accepts a <code>null</code> ClassLoader\n     * reference as well).\n     *\n     * @return the default ClassLoader (never <code>null</code>)\n     * @see java.lang.Thread#getContextClassLoader()\n     */\n    public static ClassLoader getClassLoader() {\n        return getClassLoader(ClassUtils.class);\n    }\n\n    /**\n     * Same as <code>Class.forName()</code>, except that it works for primitive\n     * types.\n     */\n    public static Class<?> forName(String name) throws ClassNotFoundException {\n        return forName(name, getClassLoader());\n    }\n\n    /**\n     *  find class and don`t expect to throw exception\n     * @param name\n     * @return\n     */\n    public static Class<?> forNameAndTryCatch(String name) {\n        try {\n            return forName(name, getClassLoader());\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    /**\n     * Replacement for <code>Class.forName()</code> that also returns Class\n     * instances for primitives (like \"int\") and array class names (like\n     * \"String[]\").\n     *\n     * @param name        the name of the Class\n     * @param classLoader the class loader to use (may be <code>null</code>,\n     *                    which indicates the default class loader)\n     * @return Class instance for the supplied name\n     * @throws ClassNotFoundException if the class was not found\n     * @throws LinkageError           if the class file could not be loaded\n     * @see Class#forName(String, boolean, ClassLoader)\n     */\n    public static Class<?> forName(String name, ClassLoader classLoader) throws ClassNotFoundException, LinkageError {\n\n        Class<?> clazz = resolvePrimitiveClassName(name);\n        if (clazz != null) {\n            return clazz;\n        }\n\n        // \"java.lang.String[]\" style arrays\n        if (name.endsWith(ARRAY_SUFFIX)) {\n            String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());\n            Class<?> elementClass = forName(elementClassName, classLoader);\n            return Array.newInstance(elementClass, 0).getClass();\n        }\n\n        // \"[Ljava.lang.String;\" style arrays\n        int internalArrayMarker = name.indexOf(INTERNAL_ARRAY_PREFIX);\n        if (internalArrayMarker != -1 && name.endsWith(\";\")) {\n            String elementClassName = null;\n            if (internalArrayMarker == 0) {\n                elementClassName = name.substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1);\n            } else if (name.startsWith(\"[\")) {\n                elementClassName = name.substring(1);\n            }\n            Class<?> elementClass = forName(elementClassName, classLoader);\n            return Array.newInstance(elementClass, 0).getClass();\n        }\n\n        ClassLoader classLoaderToUse = classLoader;\n        if (classLoaderToUse == null) {\n            classLoaderToUse = getClassLoader();\n        }\n        return classLoaderToUse.loadClass(name);\n    }\n\n    /**\n     * Resolve the given class name as primitive class, if appropriate,\n     * according to the JVM's naming rules for primitive classes.\n     * <p>\n     * Also supports the JVM's internal class names for primitive arrays. Does\n     * <i>not</i> support the \"[]\" suffix notation for primitive arrays; this is\n     * only supported by {@link #forName}.\n     *\n     * @param name the name of the potentially primitive class\n     * @return the primitive class, or <code>null</code> if the name does not\n     * denote a primitive class or primitive array class\n     */\n    public static Class<?> resolvePrimitiveClassName(String name) {\n        Class<?> result = null;\n        // Most class names will be quite long, considering that they\n        // SHOULD sit in a package, so a length check is worthwhile.\n        if (name != null && name.length() <= 8) {\n            // Could be a primitive - likely.\n            result = (Class<?>) PRIMITIVE_TYPE_NAME_MAP.get(name);\n        }\n        return result;\n    }\n\n    public static String toShortString(Object obj) {\n        if (obj == null) {\n            return \"null\";\n        }\n        return obj.getClass().getSimpleName() + \"@\" + System.identityHashCode(obj);\n    }\n\n    public static String simpleClassName(Class<?> clazz) {\n        if (clazz == null) {\n            throw new NullPointerException(\"clazz\");\n        }\n        String className = clazz.getName();\n        final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);\n        if (lastDotIdx > -1) {\n            return className.substring(lastDotIdx + 1);\n        }\n        return className;\n    }\n\n    /**\n     * The specified type is primitive type or simple type\n     *\n     * @param type the type to test\n     * @return\n     * @deprecated as 2.7.6, use {@link Class#isPrimitive()} plus {@link #isSimpleType(Class)} instead\n     */\n    public static boolean isPrimitive(Class<?> type) {\n        return type != null && (type.isPrimitive() || isSimpleType(type));\n    }\n\n    public static boolean isPrimitiveWrapper(Class<?> type) {\n        return PRIMITIVE_WRAPPER_TYPE_MAP.containsKey(type);\n    }\n\n    /**\n     * The specified type is simple type or not\n     *\n     * @param type the type to test\n     * @return if <code>type</code> is one element of {@link #SIMPLE_TYPES}, return <code>true</code>, or <code>false</code>\n     * @see #SIMPLE_TYPES\n     * @since 2.7.6\n     */\n    public static boolean isSimpleType(Class<?> type) {\n        return SIMPLE_TYPES.contains(type);\n    }\n\n    public static Object convertPrimitive(Class<?> type, String value) {\n        return convertPrimitive(FrameworkModel.defaultModel(), type, value);\n    }\n\n    public static Object convertPrimitive(FrameworkModel frameworkModel, Class<?> type, String value) {\n        if (isEmpty(value)) {\n            return null;\n        }\n        Class<?> wrapperType = WRAPPER_PRIMITIVE_TYPE_MAP.getOrDefault(type, type);\n        Object result = null;\n        try {\n            result =\n                    frameworkModel.getBeanFactory().getBean(ConverterUtil.class).convertIfPossible(value, wrapperType);\n        } catch (Exception e) {\n            // ignore exception\n        }\n        return result;\n    }\n\n    /**\n     * We only check boolean value at this moment.\n     *\n     * @param type\n     * @param value\n     * @return\n     */\n    public static boolean isTypeMatch(Class<?> type, String value) {\n        if ((type == boolean.class || type == Boolean.class) && !(\"true\".equals(value) || \"false\".equals(value))) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Get all super classes from the specified type\n     *\n     * @param type         the specified type\n     * @param classFilters the filters for classes\n     * @return non-null read-only {@link Set}\n     * @since 2.7.6\n     */\n    public static Set<Class<?>> getAllSuperClasses(Class<?> type, Predicate<Class<?>>... classFilters) {\n\n        Set<Class<?>> allSuperClasses = new LinkedHashSet<>();\n\n        Class<?> superClass = type.getSuperclass();\n        while (superClass != null) {\n            // add current super class\n            allSuperClasses.add(superClass);\n            superClass = superClass.getSuperclass();\n        }\n\n        return unmodifiableSet(filterAll(allSuperClasses, classFilters));\n    }\n\n    /**\n     * Get all interfaces from the specified type\n     *\n     * @param type             the specified type\n     * @param interfaceFilters the filters for interfaces\n     * @return non-null read-only {@link Set}\n     * @since 2.7.6\n     */\n    public static Set<Class<?>> getAllInterfaces(Class<?> type, Predicate<Class<?>>... interfaceFilters) {\n        if (type == null || type.isPrimitive()) {\n            return emptySet();\n        }\n\n        Set<Class<?>> allInterfaces = new LinkedHashSet<>();\n        Set<Class<?>> resolved = new LinkedHashSet<>();\n        Queue<Class<?>> waitResolve = new LinkedList<>();\n\n        resolved.add(type);\n        Class<?> clazz = type;\n        while (clazz != null) {\n\n            Class<?>[] interfaces = clazz.getInterfaces();\n\n            if (isNotEmpty(interfaces)) {\n                // add current interfaces\n                Arrays.stream(interfaces).filter(resolved::add).forEach(cls -> {\n                    allInterfaces.add(cls);\n                    waitResolve.add(cls);\n                });\n            }\n\n            // add all super classes to waitResolve\n            getAllSuperClasses(clazz).stream().filter(resolved::add).forEach(waitResolve::add);\n\n            clazz = waitResolve.poll();\n        }\n\n        return filterAll(allInterfaces, interfaceFilters);\n    }\n\n    /**\n     * Get all inherited types from the specified type\n     *\n     * @param type        the specified type\n     * @param typeFilters the filters for types\n     * @return non-null read-only {@link Set}\n     * @since 2.7.6\n     */\n    public static Set<Class<?>> getAllInheritedTypes(Class<?> type, Predicate<Class<?>>... typeFilters) {\n        // Add all super classes\n        Set<Class<?>> types = new LinkedHashSet<>(getAllSuperClasses(type, typeFilters));\n        // Add all interface classes\n        types.addAll(getAllInterfaces(type, typeFilters));\n        return unmodifiableSet(types);\n    }\n\n    /**\n     * the semantics is same as {@link Class#isAssignableFrom(Class)}\n     *\n     * @param superType  the super type\n     * @param targetType the target type\n     * @return see {@link Class#isAssignableFrom(Class)}\n     * @since 2.7.6\n     */\n    public static boolean isAssignableFrom(Class<?> superType, Class<?> targetType) {\n        // any argument is null\n        if (superType == null || targetType == null) {\n            return false;\n        }\n        // equals\n        if (Objects.equals(superType, targetType)) {\n            return true;\n        }\n        // isAssignableFrom\n        return superType.isAssignableFrom(targetType);\n    }\n\n    /**\n     * Test the specified class name is present in the {@link ClassLoader}\n     *\n     * @param className   the name of {@link Class}\n     * @param classLoader {@link ClassLoader}\n     * @return If found, return <code>true</code>\n     * @since 2.7.6\n     */\n    public static boolean isPresent(String className, ClassLoader classLoader) {\n        try {\n            forName(className, classLoader);\n        } catch (Exception ignored) { // Ignored\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Test the specified class name is present, array class is not supported\n     */\n    public static boolean isPresent(String className) {\n        try {\n            loadClass(className);\n            return true;\n        } catch (Throwable ignored) {\n            return false;\n        }\n    }\n\n    /**\n     * Load the {@link Class} by the specified name, array class is not supported\n     */\n    public static Class<?> loadClass(String className) throws ClassNotFoundException {\n        ClassLoader cl = null;\n        if (!className.startsWith(\"org.apache.dubbo\")) {\n            try {\n                cl = Thread.currentThread().getContextClassLoader();\n            } catch (Throwable ignored) {\n            }\n        }\n        if (cl == null) {\n            cl = ClassUtils.class.getClassLoader();\n        }\n        return cl.loadClass(className);\n    }\n\n    public static void runWith(ClassLoader classLoader, Runnable runnable) {\n        Thread thread = Thread.currentThread();\n        ClassLoader tccl = thread.getContextClassLoader();\n        if (classLoader == null || classLoader.equals(tccl)) {\n            runnable.run();\n            return;\n        }\n        thread.setContextClassLoader(classLoader);\n        try {\n            runnable.run();\n        } finally {\n            thread.setContextClassLoader(tccl);\n        }\n    }\n\n    /**\n     * Resolve the {@link Class} by the specified name and {@link ClassLoader}\n     *\n     * @param className   the name of {@link Class}\n     * @param classLoader {@link ClassLoader}\n     * @return If can't be resolved , return <code>null</code>\n     * @since 2.7.6\n     */\n    public static Class<?> resolveClass(String className, ClassLoader classLoader) {\n        Class<?> targetClass = null;\n        try {\n            targetClass = forName(className, classLoader);\n        } catch (Exception ignored) { // Ignored\n        }\n        return targetClass;\n    }\n\n    /**\n     * Is generic class or not?\n     *\n     * @param type the target type\n     * @return if the target type is not null or <code>void</code> or Void.class, return <code>true</code>, or false\n     * @since 2.7.6\n     */\n    public static boolean isGenericClass(Class<?> type) {\n        return type != null && !void.class.equals(type) && !Void.class.equals(type);\n    }\n\n    public static boolean hasMethods(Method[] methods) {\n        if (methods == null || methods.length == 0) {\n            return false;\n        }\n        for (Method m : methods) {\n            if (m.getDeclaringClass() != Object.class) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private static final String[] OBJECT_METHODS = new String[] {\"getClass\", \"hashCode\", \"toString\", \"equals\"};\n\n    /**\n     * get method name array.\n     *\n     * @return method name array.\n     */\n    public static String[] getMethodNames(Class<?> tClass) {\n        if (tClass == Object.class) {\n            return OBJECT_METHODS;\n        }\n        Method[] methods =\n                Arrays.stream(tClass.getMethods()).collect(Collectors.toList()).toArray(new Method[] {});\n        List<String> mns = new ArrayList<>(); // method names.\n        boolean hasMethod = hasMethods(methods);\n        if (hasMethod) {\n            for (Method m : methods) {\n                // ignore Object's method.\n                if (m.getDeclaringClass() == Object.class) {\n                    continue;\n                }\n                String mn = m.getName();\n                mns.add(mn);\n            }\n        }\n        return mns.toArray(new String[0]);\n    }\n\n    public static boolean isMatch(Class<?> from, Class<?> to) {\n        if (from == to) {\n            return true;\n        }\n        boolean isMatch;\n        if (from.isPrimitive()) {\n            isMatch = matchPrimitive(from, to);\n        } else if (to.isPrimitive()) {\n            isMatch = matchPrimitive(to, from);\n        } else {\n            isMatch = to.isAssignableFrom(from);\n        }\n        return isMatch;\n    }\n\n    private static boolean matchPrimitive(Class<?> from, Class<?> to) {\n        if (from == boolean.class) {\n            return to == Boolean.class;\n        } else if (from == byte.class) {\n            return to == Byte.class;\n        } else if (from == char.class) {\n            return to == Character.class;\n        } else if (from == short.class) {\n            return to == Short.class;\n        } else if (from == int.class) {\n            return to == Integer.class;\n        } else if (from == long.class) {\n            return to == Long.class;\n        } else if (from == float.class) {\n            return to == Float.class;\n        } else if (from == double.class) {\n            return to == Double.class;\n        } else if (from == void.class) {\n            return to == Void.class;\n        }\n        return false;\n    }\n\n    /**\n     * get method name array.\n     *\n     * @return method name array.\n     */\n    public static String[] getDeclaredMethodNames(Class<?> tClass) {\n        if (tClass == Object.class) {\n            return OBJECT_METHODS;\n        }\n        Method[] methods =\n                Arrays.stream(tClass.getMethods()).collect(Collectors.toList()).toArray(new Method[] {});\n        List<String> dmns = new ArrayList<>(); // method names.\n        boolean hasMethod = hasMethods(methods);\n        if (hasMethod) {\n            for (Method m : methods) {\n                // ignore Object's method.\n                if (m.getDeclaringClass() == Object.class) {\n                    continue;\n                }\n                String mn = m.getName();\n                if (m.getDeclaringClass() == tClass) {\n                    dmns.add(mn);\n                }\n            }\n        }\n        dmns.sort(Comparator.naturalOrder());\n        return dmns.toArray(new String[0]);\n    }\n\n    public static boolean hasProtobuf() {\n        return isPresent(CommonConstants.PROTOBUF_MESSAGE_CLASS_NAME);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/CollectionUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Field;\nimport java.util.AbstractSet;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport static java.util.Collections.emptySet;\nimport static java.util.Collections.unmodifiableSet;\n\n/**\n * Miscellaneous collection utility methods.\n * Mainly for internal use within the framework.\n *\n * @since 2.0.7\n */\npublic class CollectionUtils {\n\n    private static final Comparator<String> SIMPLE_NAME_COMPARATOR = (s1, s2) -> {\n        if (s1 == null && s2 == null) {\n            return 0;\n        }\n        if (s1 == null) {\n            return -1;\n        }\n        if (s2 == null) {\n            return 1;\n        }\n        int i1 = s1.lastIndexOf('.');\n        if (i1 >= 0) {\n            s1 = s1.substring(i1 + 1);\n        }\n        int i2 = s2.lastIndexOf('.');\n        if (i2 >= 0) {\n            s2 = s2.substring(i2 + 1);\n        }\n        return s1.compareToIgnoreCase(s2);\n    };\n\n    private CollectionUtils() {}\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public static <T> List<T> sort(List<T> list) {\n        if (isNotEmpty(list)) {\n            Collections.sort((List) list);\n        }\n        return list;\n    }\n\n    public static List<String> sortSimpleName(List<String> list) {\n        if (list != null && list.size() > 0) {\n            Collections.sort(list, SIMPLE_NAME_COMPARATOR);\n        }\n        return list;\n    }\n\n    /**\n     * Flip the specified {@link Map}\n     *\n     * @param map The specified {@link Map},Its value must be unique\n     * @param <K> The key type of specified {@link Map}\n     * @param <V> The value type of specified {@link Map}\n     * @return {@link Map}\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <K, V> Map<V, K> flip(Map<K, V> map) {\n        if (isEmptyMap(map)) {\n            return (Map<V, K>) map;\n        }\n        Set<V> set = new HashSet<>(map.values());\n        if (set.size() != map.size()) {\n            throw new IllegalArgumentException(\"The map value must be unique.\");\n        }\n        return map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));\n    }\n\n    public static Map<String, Map<String, String>> splitAll(Map<String, List<String>> list, String separator) {\n        if (list == null) {\n            return null;\n        }\n        Map<String, Map<String, String>> result = new HashMap<>();\n        for (Map.Entry<String, List<String>> entry : list.entrySet()) {\n            result.put(entry.getKey(), split(entry.getValue(), separator));\n        }\n        return result;\n    }\n\n    public static Map<String, List<String>> joinAll(Map<String, Map<String, String>> map, String separator) {\n        if (map == null) {\n            return null;\n        }\n        Map<String, List<String>> result = new HashMap<>();\n        for (Map.Entry<String, Map<String, String>> entry : map.entrySet()) {\n            result.put(entry.getKey(), join(entry.getValue(), separator));\n        }\n        return result;\n    }\n\n    public static Map<String, String> split(List<String> list, String separator) {\n        if (list == null) {\n            return null;\n        }\n        Map<String, String> map = new HashMap<>();\n        if (list.isEmpty()) {\n            return map;\n        }\n        for (String item : list) {\n            int index = item.indexOf(separator);\n            if (index == -1) {\n                map.put(item, \"\");\n            } else {\n                map.put(item.substring(0, index), item.substring(index + 1));\n            }\n        }\n        return map;\n    }\n\n    public static List<String> join(Map<String, String> map, String separator) {\n        if (map == null) {\n            return null;\n        }\n        List<String> list = new ArrayList<>();\n        if (map.size() == 0) {\n            return list;\n        }\n        for (Map.Entry<String, String> entry : map.entrySet()) {\n            String key = entry.getKey();\n            String value = entry.getValue();\n            if (StringUtils.isEmpty(value)) {\n                list.add(key);\n            } else {\n                list.add(key + separator + value);\n            }\n        }\n        return list;\n    }\n\n    public static String join(List<String> list, String separator) {\n        StringBuilder sb = new StringBuilder();\n        for (String ele : list) {\n            if (sb.length() > 0) {\n                sb.append(separator);\n            }\n            sb.append(ele);\n        }\n        return sb.toString();\n    }\n\n    public static boolean mapEquals(Map<?, ?> map1, Map<?, ?> map2) {\n        if (map1 == null && map2 == null) {\n            return true;\n        }\n        if (map1 == null || map2 == null) {\n            return false;\n        }\n        if (map1.size() != map2.size()) {\n            return false;\n        }\n        for (Map.Entry<?, ?> entry : map1.entrySet()) {\n            Object key = entry.getKey();\n            Object value1 = entry.getValue();\n            Object value2 = map2.get(key);\n            if (!objectEquals(value1, value2)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private static boolean objectEquals(Object obj1, Object obj2) {\n        if (obj1 == null && obj2 == null) {\n            return true;\n        }\n        if (obj1 == null || obj2 == null) {\n            return false;\n        }\n        return obj1.equals(obj2);\n    }\n\n    public static Map<String, String> toStringMap(String... pairs) {\n        Map<String, String> parameters = new HashMap<>();\n        if (ArrayUtils.isEmpty(pairs)) {\n            return parameters;\n        }\n\n        if (pairs.length > 0) {\n            if (pairs.length % 2 != 0) {\n                throw new IllegalArgumentException(\"pairs must be even.\");\n            }\n            for (int i = 0; i < pairs.length; i = i + 2) {\n                parameters.put(pairs[i], pairs[i + 1]);\n            }\n        }\n        return parameters;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <K, V> Map<K, V> toMap(Object... pairs) {\n        Map<K, V> ret = new HashMap<>();\n        if (pairs == null || pairs.length == 0) {\n            return ret;\n        }\n\n        if (pairs.length % 2 != 0) {\n            throw new IllegalArgumentException(\"Map pairs can not be odd number.\");\n        }\n        int len = pairs.length / 2;\n        for (int i = 0; i < len; i++) {\n            ret.put((K) pairs[2 * i], (V) pairs[2 * i + 1]);\n        }\n        return ret;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <K, V> Map<K, V> objToMap(Object object) throws IllegalAccessException {\n        Map<K, V> ret = new HashMap<>();\n        if (object != null) {\n            Field[] fields = object.getClass().getDeclaredFields();\n            for (Field field : fields) {\n                field.setAccessible(true);\n                Object value = field.get(object);\n                if (value != null) {\n                    ret.put((K) field.getName(), (V) value);\n                }\n            }\n        }\n        return ret;\n    }\n\n    /**\n     * Return {@code true} if the supplied Collection is {@code null} or empty.\n     * Otherwise, return {@code false}.\n     *\n     * @param collection the Collection to check\n     * @return whether the given Collection is empty\n     */\n    public static boolean isEmpty(Collection<?> collection) {\n        return collection == null || collection.isEmpty();\n    }\n\n    /**\n     * Return {@code true} if the supplied Collection is {@code not null} or not empty.\n     * Otherwise, return {@code false}.\n     *\n     * @param collection the Collection to check\n     * @return whether the given Collection is not empty\n     */\n    public static boolean isNotEmpty(Collection<?> collection) {\n        return !isEmpty(collection);\n    }\n\n    /**\n     * Return {@code true} if the supplied Map is {@code null} or empty.\n     * Otherwise, return {@code false}.\n     *\n     * @param map the Map to check\n     * @return whether the given Map is empty\n     */\n    public static boolean isEmptyMap(Map map) {\n        return map == null || map.isEmpty();\n    }\n\n    /**\n     * Return {@code true} if the supplied Map is {@code not null} or not empty.\n     * Otherwise, return {@code false}.\n     *\n     * @param map the Map to check\n     * @return whether the given Map is not empty\n     */\n    public static boolean isNotEmptyMap(Map map) {\n        return !isEmptyMap(map);\n    }\n\n    /**\n     * Convert to multiple values to be {@link LinkedHashSet}\n     *\n     * @param values one or more values\n     * @param <T>    the type of <code>values</code>\n     * @return read-only {@link Set}\n     */\n    public static <T> Set<T> ofSet(T... values) {\n        int size = values == null ? 0 : values.length;\n        if (size < 1) {\n            return emptySet();\n        }\n\n        float loadFactor = 1f / ((size + 1) * 1.0f);\n\n        if (loadFactor > 0.75f) {\n            loadFactor = 0.75f;\n        }\n\n        Set<T> elements = new LinkedHashSet<>(size, loadFactor);\n        for (int i = 0; i < size; i++) {\n            elements.add(values[i]);\n        }\n        return unmodifiableSet(elements);\n    }\n\n    /**\n     * Get the size of the specified {@link Collection}\n     *\n     * @param collection the specified {@link Collection}\n     * @return must be positive number\n     * @since 2.7.6\n     */\n    public static int size(Collection<?> collection) {\n        return collection == null ? 0 : collection.size();\n    }\n\n    /**\n     * Compares the specified collection with another, the main implementation references\n     * {@link AbstractSet}\n     *\n     * @param one     {@link Collection}\n     * @param another {@link Collection}\n     * @return if equals, return <code>true</code>, or <code>false</code>\n     * @since 2.7.6\n     */\n    public static boolean equals(Collection<?> one, Collection<?> another) {\n\n        if (one == another) {\n            return true;\n        }\n\n        if (isEmpty(one) && isEmpty(another)) {\n            return true;\n        }\n\n        if (size(one) != size(another)) {\n            return false;\n        }\n\n        try {\n            return one.containsAll(another);\n        } catch (ClassCastException | NullPointerException unused) {\n            return false;\n        }\n    }\n\n    /**\n     * Add the multiple values into {@link Collection the specified collection}\n     *\n     * @param collection {@link Collection the specified collection}\n     * @param values     the multiple values\n     * @param <T>        the type of values\n     * @return the effected count after added\n     * @since 2.7.6\n     */\n    public static <T> int addAll(Collection<T> collection, T... values) {\n\n        int size = values == null ? 0 : values.length;\n\n        if (collection == null || size < 1) {\n            return 0;\n        }\n\n        int effectedCount = 0;\n        for (int i = 0; i < size; i++) {\n            if (collection.add(values[i])) {\n                effectedCount++;\n            }\n        }\n\n        return effectedCount;\n    }\n\n    /**\n     * Take the first element from the specified collection\n     *\n     * @param values the collection object\n     * @param <T>    the type of element of collection\n     * @return if found, return the first one, or <code>null</code>\n     * @since 2.7.6\n     */\n    public static <T> T first(Collection<T> values) {\n        if (isEmpty(values)) {\n            return null;\n        }\n        if (values instanceof List) {\n            return ((List<T>) values).get(0);\n        } else {\n            return values.iterator().next();\n        }\n    }\n\n    public static <T> T first(List<T> values) {\n        if (isEmpty(values)) {\n            return null;\n        }\n        return values.get(0);\n    }\n\n    public static <T> Set<T> toTreeSet(Set<T> set) {\n        if (isEmpty(set)) {\n            return set;\n        }\n        if (!(set instanceof TreeSet)) {\n            set = new TreeSet<>(set);\n        }\n        return set;\n    }\n\n    public static <T> Set<T> newHashSet(int expectedSize) {\n        return new HashSet<>(capacity(expectedSize));\n    }\n\n    public static <T> Set<T> newLinkedHashSet(int expectedSize) {\n        return new LinkedHashSet<>(capacity(expectedSize));\n    }\n\n    public static <K, T> Map<K, T> newHashMap(int expectedSize) {\n        return new HashMap<>(capacity(expectedSize));\n    }\n\n    public static <K, T> Map<K, T> newLinkedHashMap(int expectedSize) {\n        return new LinkedHashMap<>(capacity(expectedSize));\n    }\n\n    public static <K, T> Map<K, T> newConcurrentHashMap(int expectedSize) {\n        if (JRE.JAVA_8.isCurrentVersion()) {\n            return new SafeConcurrentHashMap<>(capacity(expectedSize));\n        }\n        return new ConcurrentHashMap<>(capacity(expectedSize));\n    }\n\n    public static <K, T> Map<K, T> newConcurrentHashMap() {\n        if (JRE.JAVA_8.isCurrentVersion()) {\n            return new SafeConcurrentHashMap<>();\n        }\n        return new ConcurrentHashMap<>();\n    }\n\n    public static int capacity(int expectedSize) {\n        if (expectedSize < 3) {\n            if (expectedSize < 0) {\n                throw new IllegalArgumentException(\"expectedSize cannot be negative but was: \" + expectedSize);\n            }\n            return expectedSize + 1;\n        }\n        if (expectedSize < 1 << (Integer.SIZE - 2)) {\n            return (int) (expectedSize / 0.75F + 1.0F);\n        }\n        return Integer.MAX_VALUE;\n    }\n\n    public static class SafeConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {\n        private static final long serialVersionUID = 1L;\n\n        public SafeConcurrentHashMap() {}\n\n        public SafeConcurrentHashMap(int initialCapacity) {\n            super(initialCapacity);\n        }\n\n        public SafeConcurrentHashMap(Map<? extends K, ? extends V> m) {\n            super(m);\n        }\n\n        @Override\n        public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {\n            V value = get(key);\n            if (value != null) {\n                return value;\n            }\n            value = mappingFunction.apply(key);\n            if (value == null) {\n                return null;\n            }\n            V exists = putIfAbsent(key, value);\n            if (exists != null) {\n                return exists;\n            }\n            return value;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/CompatibleTypeUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Array;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class CompatibleTypeUtils {\n\n    private static final String DATE_FORMAT = \"yyyy-MM-dd HH:mm:ss\";\n\n    /**\n     * the text to parse such as \"2007-12-03T10:15:30\"\n     */\n    private static final int ISO_LOCAL_DATE_TIME_MIN_LEN = 19;\n\n    private CompatibleTypeUtils() {}\n\n    /**\n     * Compatible type convert. Null value is allowed to pass in. If no conversion is needed, then the original value\n     * will be returned.\n     * <p>\n     * Supported compatible type conversions include (primary types and corresponding wrappers are not listed):\n     * <ul>\n     * <li> String -> char, enum, Date\n     * <li> byte, short, int, long -> byte, short, int, long\n     * <li> float, double -> float, double\n     * </ul>\n     */\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public static Object compatibleTypeConvert(Object value, Class<?> type) {\n        if (value == null || type == null || type.isAssignableFrom(value.getClass())) {\n            return value;\n        }\n\n        if (value instanceof String) {\n            String string = (String) value;\n            if (char.class.equals(type) || Character.class.equals(type)) {\n                if (string.length() != 1) {\n                    throw new IllegalArgumentException(String.format(\n                            \"CAN NOT convert String(%s) to char!\"\n                                    + \" when convert String to char, the String MUST only 1 char.\",\n                            string));\n                }\n                return string.charAt(0);\n            }\n            if (type.isEnum()) {\n                return Enum.valueOf((Class<Enum>) type, string);\n            }\n            if (type == BigInteger.class) {\n                return new BigInteger(string);\n            }\n            if (type == BigDecimal.class) {\n                return new BigDecimal(string);\n            }\n            if (type == Short.class || type == short.class) {\n                return new Short(string);\n            }\n            if (type == Integer.class || type == int.class) {\n                return new Integer(string);\n            }\n            if (type == Long.class || type == long.class) {\n                return new Long(string);\n            }\n            if (type == Double.class || type == double.class) {\n                return new Double(string);\n            }\n            if (type == Float.class || type == float.class) {\n                return new Float(string);\n            }\n            if (type == Byte.class || type == byte.class) {\n                return new Byte(string);\n            }\n            if (type == Boolean.class || type == boolean.class) {\n                return Boolean.valueOf(string);\n            }\n            if (type == Date.class\n                    || type == java.sql.Date.class\n                    || type == java.sql.Timestamp.class\n                    || type == java.sql.Time.class) {\n                try {\n                    Date date = new SimpleDateFormat(DATE_FORMAT).parse(string);\n                    if (type == java.sql.Date.class) {\n                        return new java.sql.Date(date.getTime());\n                    }\n                    if (type == java.sql.Timestamp.class) {\n                        return new java.sql.Timestamp(date.getTime());\n                    }\n                    if (type == java.sql.Time.class) {\n                        return new java.sql.Time(date.getTime());\n                    }\n                    return date;\n                } catch (ParseException e) {\n                    throw new IllegalStateException(\n                            \"Failed to parse date \" + value + \" by format \" + DATE_FORMAT + \", cause: \"\n                                    + e.getMessage(),\n                            e);\n                }\n            }\n            if (type == java.time.LocalDateTime.class) {\n                if (StringUtils.isEmpty(string)) {\n                    return null;\n                }\n                return LocalDateTime.parse(string);\n            }\n            if (type == java.time.LocalDate.class) {\n                if (StringUtils.isEmpty(string)) {\n                    return null;\n                }\n                return LocalDate.parse(string);\n            }\n            if (type == java.time.LocalTime.class) {\n                if (StringUtils.isEmpty(string)) {\n                    return null;\n                }\n\n                if (string.length() >= ISO_LOCAL_DATE_TIME_MIN_LEN) {\n                    return LocalDateTime.parse(string).toLocalTime();\n                } else {\n                    return LocalTime.parse(string);\n                }\n            }\n            if (type == Class.class) {\n                try {\n                    return ReflectUtils.name2class(string);\n                } catch (ClassNotFoundException e) {\n                    throw new RuntimeException(e.getMessage(), e);\n                }\n            }\n            if (char[].class.equals(type)) {\n                // Process string to char array for generic invoke\n                // See\n                // - https://github.com/apache/dubbo/issues/2003\n                int len = string.length();\n                char[] chars = new char[len];\n                string.getChars(0, len, chars, 0);\n                return chars;\n            }\n        }\n        if (value instanceof Number) {\n            Number number = (Number) value;\n            if (type == byte.class || type == Byte.class) {\n                return number.byteValue();\n            }\n            if (type == short.class || type == Short.class) {\n                return number.shortValue();\n            }\n            if (type == int.class || type == Integer.class) {\n                return number.intValue();\n            }\n            if (type == long.class || type == Long.class) {\n                return number.longValue();\n            }\n            if (type == float.class || type == Float.class) {\n                return number.floatValue();\n            }\n            if (type == double.class || type == Double.class) {\n                return number.doubleValue();\n            }\n            if (type == BigInteger.class) {\n                return BigInteger.valueOf(number.longValue());\n            }\n            if (type == BigDecimal.class) {\n                return new BigDecimal(number.toString());\n            }\n            if (type == Date.class) {\n                return new Date(number.longValue());\n            }\n            if (type == boolean.class || type == Boolean.class) {\n                return 0 != number.intValue();\n            }\n        }\n        if (value instanceof Collection) {\n            Collection collection = (Collection) value;\n            if (type.isArray()) {\n                int length = collection.size();\n                Object array = Array.newInstance(type.getComponentType(), length);\n                int i = 0;\n                for (Object item : collection) {\n                    Array.set(array, i++, item);\n                }\n                return array;\n            }\n            if (!type.isInterface()) {\n                try {\n                    Collection result =\n                            (Collection) type.getDeclaredConstructor().newInstance();\n                    result.addAll(collection);\n                    return result;\n                } catch (Throwable ignored) {\n                }\n            }\n            if (type == List.class) {\n                return new ArrayList<Object>(collection);\n            }\n            if (type == Set.class) {\n                return new HashSet<Object>(collection);\n            }\n        }\n        if (value.getClass().isArray() && Collection.class.isAssignableFrom(type)) {\n            int length = Array.getLength(value);\n            Collection collection;\n            if (!type.isInterface()) {\n                try {\n                    collection = (Collection) type.getDeclaredConstructor().newInstance();\n                } catch (Exception e) {\n                    collection = new ArrayList<Object>(length);\n                }\n            } else if (type == Set.class) {\n                collection = new HashSet<Object>(Math.max((int) (length / .75f) + 1, 16));\n            } else {\n                collection = new ArrayList<Object>(length);\n            }\n            for (int i = 0; i < length; i++) {\n                collection.add(Array.get(value, i));\n            }\n            return collection;\n        }\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.Objects;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.function.Function;\n\n/**\n * ConcurrentHashMap util\n */\npublic class ConcurrentHashMapUtils {\n\n    /**\n     * A temporary workaround for Java 8 ConcurrentHashMap#computeIfAbsent specific performance issue: JDK-8161372.</br>\n     * @see <a href=\"https://bugs.openjdk.java.net/browse/JDK-8161372\">https://bugs.openjdk.java.net/browse/JDK-8161372</a>\n     *\n     */\n    public static <K, V> V computeIfAbsent(ConcurrentMap<K, V> map, K key, Function<? super K, ? extends V> func) {\n        Objects.requireNonNull(func);\n        if (JRE.JAVA_8.isCurrentVersion()) {\n            V v = map.get(key);\n            if (null == v) {\n                // issue#11986 lock bug\n                // v = map.computeIfAbsent(key, func);\n\n                // this bug fix methods maybe cause `func.apply` multiple calls.\n                v = func.apply(key);\n                if (null == v) {\n                    return null;\n                }\n                final V res = map.putIfAbsent(key, v);\n                if (null != res) {\n                    // if pre value present, means other thread put value already, and putIfAbsent not effect\n                    // return exist value\n                    return res;\n                }\n                // if pre value is null, means putIfAbsent effected, return current value\n            }\n            return v;\n        } else {\n            return map.computeIfAbsent(key, func);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ConcurrentHashSet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.AbstractSet;\nimport java.util.ConcurrentModificationException;\nimport java.util.Iterator;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\npublic class ConcurrentHashSet<E> extends AbstractSet<E> implements Set<E>, java.io.Serializable {\n\n    private static final long serialVersionUID = -8672117787651310382L;\n\n    private static final Object PRESENT = new Object();\n\n    private final ConcurrentMap<E, Object> map;\n\n    public ConcurrentHashSet() {\n        map = new ConcurrentHashMap<>();\n    }\n\n    public ConcurrentHashSet(int initialCapacity) {\n        map = new ConcurrentHashMap<>(initialCapacity);\n    }\n\n    /**\n     * Returns an iterator over the elements in this set. The elements are\n     * returned in no particular order.\n     *\n     * @return an Iterator over the elements in this set\n     * @see ConcurrentModificationException\n     */\n    @Override\n    public Iterator<E> iterator() {\n        return map.keySet().iterator();\n    }\n\n    /**\n     * Returns the number of elements in this set (its cardinality).\n     *\n     * @return the number of elements in this set (its cardinality)\n     */\n    @Override\n    public int size() {\n        return map.size();\n    }\n\n    /**\n     * Returns <tt>true</tt> if this set contains no elements.\n     *\n     * @return <tt>true</tt> if this set contains no elements\n     */\n    @Override\n    public boolean isEmpty() {\n        return map.isEmpty();\n    }\n\n    /**\n     * Returns <tt>true</tt> if this set contains the specified element. More\n     * formally, returns <tt>true</tt> if and only if this set contains an\n     * element <tt>e</tt> such that\n     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.\n     *\n     * @param o element whose presence in this set is to be tested\n     * @return <tt>true</tt> if this set contains the specified element\n     */\n    @Override\n    public boolean contains(Object o) {\n        return map.containsKey(o);\n    }\n\n    /**\n     * Adds the specified element to this set if it is not already present. More\n     * formally, adds the specified element <tt>e</tt> to this set if this set\n     * contains no element <tt>e2</tt> such that\n     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>. If this\n     * set already contains the element, the call leaves the set unchanged and\n     * returns <tt>false</tt>.\n     *\n     * @param e element to be added to this set\n     * @return <tt>true</tt> if this set did not already contain the specified\n     * element\n     */\n    @Override\n    public boolean add(E e) {\n        return map.put(e, PRESENT) == null;\n    }\n\n    /**\n     * Removes the specified element from this set if it is present. More\n     * formally, removes an element <tt>e</tt> such that\n     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>, if this\n     * set contains such an element. Returns <tt>true</tt> if this set contained\n     * the element (or equivalently, if this set changed as a result of the\n     * call). (This set will not contain the element once the call returns.)\n     *\n     * @param o object to be removed from this set, if present\n     * @return <tt>true</tt> if the set contained the specified element\n     */\n    @Override\n    public boolean remove(Object o) {\n        return map.remove(o) == PRESENT;\n    }\n\n    /**\n     * Removes all of the elements from this set. The set will be empty after\n     * this call returns.\n     */\n    @Override\n    public void clear() {\n        map.clear();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ConfigUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.InmemoryConfiguration;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.ExtensionDirector;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.RuntimeMXBean;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_IO_EXCEPTION;\n\npublic class ConfigUtils {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConfigUtils.class);\n    private static final Pattern VARIABLE_PATTERN = Pattern.compile(\"\\\\$\\\\s*\\\\{?\\\\s*([\\\\._0-9a-zA-Z]+)\\\\s*\\\\}?\");\n    private static int PID = -1;\n\n    private ConfigUtils() {}\n\n    public static boolean isNotEmpty(String value) {\n        return !isEmpty(value);\n    }\n\n    public static boolean isEmpty(String value) {\n        return StringUtils.isEmpty(value)\n                || \"false\".equalsIgnoreCase(value)\n                || \"0\".equalsIgnoreCase(value)\n                || \"null\".equalsIgnoreCase(value)\n                || \"N/A\".equalsIgnoreCase(value);\n    }\n\n    public static boolean isDefault(String value) {\n        return \"true\".equalsIgnoreCase(value) || \"default\".equalsIgnoreCase(value);\n    }\n\n    /**\n     * Insert default extension into extension list.\n     * <p>\n     * Extension list support<ul>\n     * <li>Special value <code><strong>default</strong></code>, means the location for default extensions.\n     * <li>Special symbol<code><strong>-</strong></code>, means remove. <code>-foo1</code> will remove default extension 'foo'; <code>-default</code> will remove all default extensions.\n     * </ul>\n     *\n     * @param type Extension type\n     * @param cfg  Extension name list\n     * @param def  Default extension list\n     * @return result extension list\n     */\n    public static List<String> mergeValues(\n            ExtensionDirector extensionDirector, Class<?> type, String cfg, List<String> def) {\n        List<String> defaults = new ArrayList<>();\n        if (def != null) {\n            for (String name : def) {\n                if (extensionDirector.getExtensionLoader(type).hasExtension(name)) {\n                    defaults.add(name);\n                }\n            }\n        }\n\n        List<String> names = new ArrayList<>();\n\n        // add initial values\n        String[] configs = (cfg == null || cfg.trim().length() == 0) ? new String[0] : COMMA_SPLIT_PATTERN.split(cfg);\n        for (String config : configs) {\n            if (config != null && config.trim().length() > 0) {\n                names.add(config);\n            }\n        }\n\n        // -default is not included\n        if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {\n            // add default extension\n            int i = names.indexOf(DEFAULT_KEY);\n            if (i > 0) {\n                names.addAll(i, defaults);\n            } else {\n                names.addAll(0, defaults);\n            }\n            names.remove(DEFAULT_KEY);\n        } else {\n            names.remove(DEFAULT_KEY);\n        }\n\n        // merge - configuration\n        for (String name : new ArrayList<String>(names)) {\n            if (name.startsWith(REMOVE_VALUE_PREFIX)) {\n                names.remove(name);\n                names.remove(name.substring(1));\n            }\n        }\n        return names;\n    }\n\n    public static String replaceProperty(String expression, Map<String, String> params) {\n        return replaceProperty(expression, new InmemoryConfiguration(params));\n    }\n\n    public static String replaceProperty(String expression, Configuration configuration) {\n        if (StringUtils.isEmpty(expression) || expression.indexOf('$') < 0) {\n            return expression;\n        }\n        Matcher matcher = VARIABLE_PATTERN.matcher(expression);\n        StringBuffer sb = new StringBuffer();\n        while (matcher.find()) {\n            String key = matcher.group(1);\n            String value = System.getProperty(key);\n            if (value == null && configuration != null) {\n                Object val = configuration.getProperty(key);\n                value = (val != null) ? val.toString() : null;\n            }\n            if (value == null) {\n                // maybe not placeholders, use origin express\n                value = matcher.group();\n            }\n            matcher.appendReplacement(sb, Matcher.quoteReplacement(value));\n        }\n        matcher.appendTail(sb);\n        return sb.toString();\n    }\n\n    /**\n     * Get dubbo properties.\n     * It is not recommended using this method to modify dubbo properties.\n     *\n     * @return\n     */\n    public static Properties getProperties(Set<ClassLoader> classLoaders) {\n        String path = SystemPropertyConfigUtils.getSystemProperty(CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY);\n        if (StringUtils.isEmpty(path)) {\n            path = System.getenv(CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY);\n            if (StringUtils.isEmpty(path)) {\n                path = CommonConstants.DEFAULT_DUBBO_PROPERTIES;\n            }\n        }\n        return ConfigUtils.loadProperties(classLoaders, path, false, true);\n    }\n\n    /**\n     * System environment -> System properties\n     *\n     * @param key key\n     * @return value\n     */\n    public static String getSystemProperty(String key) {\n        String value = System.getenv(key);\n        if (StringUtils.isEmpty(value)) {\n            value = System.getProperty(key);\n        }\n        return value;\n    }\n\n    public static Properties loadProperties(Set<ClassLoader> classLoaders, String fileName) {\n        return loadProperties(classLoaders, fileName, false, false);\n    }\n\n    public static Properties loadProperties(Set<ClassLoader> classLoaders, String fileName, boolean allowMultiFile) {\n        return loadProperties(classLoaders, fileName, allowMultiFile, false);\n    }\n\n    /**\n     * Load properties file to {@link Properties} from class path.\n     *\n     * @param fileName       properties file name. for example: <code>dubbo.properties</code>, <code>METE-INF/conf/foo.properties</code>\n     * @param allowMultiFile if <code>false</code>, throw {@link IllegalStateException} when found multi file on the class path.\n     * @param optional       is optional. if <code>false</code>, log warn when properties config file not found!s\n     * @return loaded {@link Properties} content. <ul>\n     * <li>return empty Properties if no file found.\n     * <li>merge multi properties file if found multi file\n     * </ul>\n     * @throws IllegalStateException not allow multi-file, but multi-file exist on class path.\n     */\n    public static Properties loadProperties(\n            Set<ClassLoader> classLoaders, String fileName, boolean allowMultiFile, boolean optional) {\n        Properties properties = new Properties();\n        // add scene judgement in windows environment Fix 2557\n        if (checkFileNameExist(fileName)) {\n            try (FileInputStream input = new FileInputStream(fileName)) {\n                properties.load(input);\n            } catch (Throwable e) {\n                logger.warn(\n                        COMMON_IO_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Failed to load \" + fileName + \" file from \" + fileName + \"(ignore this file): \"\n                                + e.getMessage(),\n                        e);\n            }\n            return properties;\n        }\n\n        Set<java.net.URL> set = null;\n        try {\n            List<ClassLoader> classLoadersToLoad = new LinkedList<>();\n            classLoadersToLoad.add(ClassUtils.getClassLoader());\n            classLoadersToLoad.addAll(classLoaders);\n            set = ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad).values().stream()\n                    .reduce(new LinkedHashSet<>(), (a, i) -> {\n                        a.addAll(i);\n                        return a;\n                    });\n        } catch (Throwable t) {\n            logger.warn(COMMON_IO_EXCEPTION, \"\", \"\", \"Fail to load \" + fileName + \" file: \" + t.getMessage(), t);\n        }\n\n        if (CollectionUtils.isEmpty(set)) {\n            if (!optional) {\n                logger.warn(COMMON_IO_EXCEPTION, \"\", \"\", \"No \" + fileName + \" found on the class path.\");\n            }\n            return properties;\n        }\n\n        if (!allowMultiFile) {\n            if (set.size() > 1) {\n                String errMsg = String.format(\n                        \"only 1 %s file is expected, but %d dubbo.properties files found on class path: %s\",\n                        fileName, set.size(), set);\n                logger.warn(COMMON_IO_EXCEPTION, \"\", \"\", errMsg);\n            }\n\n            // fall back to use method getResourceAsStream\n            try {\n                properties.load(ClassUtils.getClassLoader().getResourceAsStream(fileName));\n            } catch (Throwable e) {\n                logger.warn(\n                        COMMON_IO_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Failed to load \" + fileName + \" file from \" + fileName + \"(ignore this file): \"\n                                + e.getMessage(),\n                        e);\n            }\n            return properties;\n        }\n\n        logger.info(\"load \" + fileName + \" properties file from \" + set);\n\n        for (java.net.URL url : set) {\n            try (InputStream input = url.openStream()) {\n                if (input != null) {\n                    Properties p = new Properties();\n                    p.load(input);\n                    properties.putAll(p);\n                }\n            } catch (Throwable e) {\n                logger.warn(\n                        COMMON_IO_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Fail to load \" + fileName + \" file from \" + url + \"(ignore this file): \" + e.getMessage(),\n                        e);\n            }\n        }\n\n        return properties;\n    }\n\n    public static String loadMigrationRule(Set<ClassLoader> classLoaders, String fileName) {\n        String rawRule = \"\";\n        if (checkFileNameExist(fileName)) {\n            try {\n                try (FileInputStream input = new FileInputStream(fileName)) {\n                    return readString(input);\n                }\n            } catch (Throwable e) {\n                logger.warn(\n                        COMMON_IO_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Failed to load \" + fileName + \" file from \" + fileName + \"(ignore this file): \"\n                                + e.getMessage(),\n                        e);\n            }\n        }\n\n        try {\n            List<ClassLoader> classLoadersToLoad = new LinkedList<>();\n            classLoadersToLoad.add(ClassUtils.getClassLoader());\n            classLoadersToLoad.addAll(classLoaders);\n            for (Set<URL> urls : ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad)\n                    .values()) {\n                for (URL url : urls) {\n                    try (InputStream is = url.openStream()) {\n                        if (is != null) {\n                            return readString(is);\n                        }\n                    }\n                }\n            }\n        } catch (Throwable e) {\n            logger.warn(\n                    COMMON_IO_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to load \" + fileName + \" file from \" + fileName + \"(ignore this file): \" + e.getMessage(),\n                    e);\n        }\n        return rawRule;\n    }\n\n    private static String readString(InputStream is) {\n        StringBuilder stringBuilder = new StringBuilder();\n        char[] buffer = new char[10];\n        try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {\n            int n;\n            while ((n = reader.read(buffer)) != -1) {\n                if (n < 10) {\n                    buffer = Arrays.copyOf(buffer, n);\n                }\n                stringBuilder.append(String.valueOf(buffer));\n                buffer = new char[10];\n            }\n        } catch (IOException e) {\n            logger.error(COMMON_IO_EXCEPTION, \"\", \"\", \"Read migration file error.\", e);\n        }\n\n        return stringBuilder.toString();\n    }\n\n    /**\n     * check if the fileName can be found in filesystem\n     *\n     * @param fileName\n     * @return\n     */\n    private static boolean checkFileNameExist(String fileName) {\n        File file = new File(fileName);\n        return file.exists();\n    }\n\n    public static int getPid() {\n        if (PID < 0) {\n            try {\n                RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();\n                // format: \"pid@hostname\"\n                String name = runtime.getName();\n                PID = Integer.parseInt(name.substring(0, name.indexOf('@')));\n            } catch (Throwable e) {\n                PID = 0;\n            }\n        }\n        return PID;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/DateUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.time.Instant;\nimport java.time.LocalDate;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.time.temporal.ChronoField;\nimport java.time.temporal.TemporalAccessor;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.TimeZone;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\npublic final class DateUtils {\n\n    public static final ZoneId GMT = ZoneId.of(\"GMT\");\n    public static final ZoneId UTC = ZoneId.of(\"UTC\");\n\n    public static final String DATE = \"yyyy-MM-dd\";\n    public static final String DATE_MIN = \"yyyy-MM-dd HH:mm\";\n    public static final String DATE_TIME = \"yyyy-MM-dd HH:mm:ss\";\n    public static final String JDK_TIME = \"EEE MMM dd HH:mm:ss zzz yyyy\";\n    public static final String ASC_TIME = \"EEE MMM d HH:mm:ss yyyy\";\n    public static final String RFC1036 = \"EEE, dd-MMM-yy HH:mm:ss zzz\";\n\n    public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern(DATE);\n    public static final DateTimeFormatter DATE_MIN_FORMAT = DateTimeFormatter.ofPattern(DATE_MIN);\n    public static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern(DATE_TIME);\n    public static final DateTimeFormatter JDK_TIME_FORMAT = DateTimeFormatter.ofPattern(JDK_TIME, Locale.US);\n    public static final DateTimeFormatter ASC_TIME_FORMAT = DateTimeFormatter.ofPattern(ASC_TIME, Locale.US);\n    public static final DateTimeFormatter RFC1036_FORMAT = DateTimeFormatter.ofPattern(RFC1036, Locale.US);\n\n    private static final Map<String, DateTimeFormatter> CACHE = new LRUCache<>(64);\n    private static final List<DateTimeFormatter> CUSTOM_FORMATTERS = new CopyOnWriteArrayList<>();\n\n    private DateUtils() {}\n\n    public static void registerFormatter(String pattern) {\n        CUSTOM_FORMATTERS.add(DateTimeFormatter.ofPattern(pattern));\n    }\n\n    public static void registerFormatter(DateTimeFormatter formatter) {\n        CUSTOM_FORMATTERS.add(formatter);\n    }\n\n    public static Date parse(String str, String pattern) {\n        if (DATE_TIME.equals(pattern)) {\n            return parse(str, DATE_TIME_FORMAT);\n        }\n        DateTimeFormatter formatter = getFormatter(pattern);\n        return parse(str, formatter);\n    }\n\n    public static Date parse(String str, DateTimeFormatter formatter) {\n        return toDate(formatter.parse(str));\n    }\n\n    public static String format(Date date) {\n        return format(date, DATE_TIME_FORMAT);\n    }\n\n    public static String format(Date date, String pattern) {\n        if (DATE_TIME.equals(pattern)) {\n            return format(date, DATE_TIME_FORMAT);\n        }\n        DateTimeFormatter formatter = getFormatter(pattern);\n        return format(date, formatter);\n    }\n\n    public static String format(Date date, DateTimeFormatter formatter) {\n        return formatter.format(ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()));\n    }\n\n    public static String format(Date date, DateTimeFormatter formatter, ZoneId zone) {\n        return formatter.format(ZonedDateTime.ofInstant(date.toInstant(), zone));\n    }\n\n    public static String formatGMT(Date date, DateTimeFormatter formatter) {\n        return formatter.format(ZonedDateTime.ofInstant(date.toInstant(), GMT));\n    }\n\n    public static String formatUTC(Date date, DateTimeFormatter formatter) {\n        return formatter.format(ZonedDateTime.ofInstant(date.toInstant(), UTC));\n    }\n\n    public static String formatHeader(Date date) {\n        return DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.ofInstant(date.toInstant(), GMT));\n    }\n\n    private static DateTimeFormatter getFormatter(String pattern) {\n        return CACHE.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);\n    }\n\n    public static Date parse(Object value) {\n        if (value == null) {\n            return null;\n        }\n        if (value instanceof Date) {\n            return (Date) value;\n        }\n        if (value instanceof Calendar) {\n            return ((Calendar) value).getTime();\n        }\n        if (value.getClass() == Instant.class) {\n            return Date.from((Instant) value);\n        }\n        if (value instanceof TemporalAccessor) {\n            return Date.from(Instant.from((TemporalAccessor) value));\n        }\n        if (value instanceof Number) {\n            return new Date(((Number) value).longValue());\n        }\n        if (value instanceof CharSequence) {\n            return parse(value.toString());\n        }\n        throw new IllegalArgumentException(\"Can not cast to Date, value : '\" + value + \"'\");\n    }\n\n    public static Date parse(String value) {\n        if (value == null) {\n            return null;\n        }\n        String str = value.trim();\n        int len = str.length();\n        if (len == 0) {\n            return null;\n        }\n\n        boolean isIso = true;\n        boolean isNumeric = true;\n        boolean hasDate = false;\n        boolean hasTime = false;\n        for (int i = 0; i < len; i++) {\n            char c = str.charAt(i);\n            switch (c) {\n                case ' ':\n                    isIso = false;\n                    break;\n                case '-':\n                    hasDate = true;\n                    break;\n                case 'T':\n                case ':':\n                    hasTime = true;\n                    break;\n                case '0':\n                case '1':\n                case '2':\n                case '3':\n                case '4':\n                case '5':\n                case '6':\n                case '7':\n                case '8':\n                case '9':\n                    continue;\n                default:\n            }\n            if (isNumeric) {\n                isNumeric = false;\n            }\n        }\n        DateTimeFormatter formatter = null;\n        if (isIso) {\n            if (hasDate) {\n                formatter = hasTime ? DateTimeFormatter.ISO_DATE_TIME : DateTimeFormatter.ISO_DATE;\n            } else if (hasTime) {\n                formatter = DateTimeFormatter.ISO_TIME;\n            }\n        }\n        if (isNumeric) {\n            long num = Long.parseLong(str);\n            if (num > 21000101 || num < 19700101) {\n                return new Date(num);\n            }\n            formatter = DateTimeFormatter.BASIC_ISO_DATE;\n        }\n        switch (len) {\n            case 10:\n                formatter = DATE_FORMAT;\n                break;\n            case 16:\n                formatter = DATE_MIN_FORMAT;\n                break;\n            case 19:\n                formatter = DATE_TIME_FORMAT;\n                break;\n            case 23:\n            case 24:\n                formatter = ASC_TIME_FORMAT;\n                break;\n            case 27:\n                formatter = RFC1036_FORMAT;\n                break;\n            case 28:\n                formatter = JDK_TIME_FORMAT;\n                break;\n            case 29:\n                formatter = DateTimeFormatter.RFC_1123_DATE_TIME;\n                break;\n            default:\n        }\n\n        if (formatter != null) {\n            try {\n                return toDate(formatter.parse(str));\n            } catch (Exception ignored) {\n            }\n        }\n        for (DateTimeFormatter dtf : CUSTOM_FORMATTERS) {\n            try {\n                return parse(str, dtf);\n            } catch (Exception ignored) {\n            }\n        }\n        throw new IllegalArgumentException(\"Can not cast to Date, value : '\" + value + \"'\");\n    }\n\n    public static Date toDate(TemporalAccessor temporal) {\n        if (temporal instanceof Instant) {\n            return Date.from((Instant) temporal);\n        }\n        long timestamp;\n        if (temporal.isSupported(ChronoField.EPOCH_DAY)) {\n            timestamp = temporal.getLong(ChronoField.EPOCH_DAY) * 86400000;\n        } else {\n            timestamp = LocalDate.now().toEpochDay() * 86400000;\n        }\n        if (temporal.isSupported(ChronoField.MILLI_OF_DAY)) {\n            timestamp += temporal.getLong(ChronoField.MILLI_OF_DAY);\n        }\n        if (temporal.isSupported(ChronoField.OFFSET_SECONDS)) {\n            timestamp -= temporal.getLong(ChronoField.OFFSET_SECONDS) * 1000;\n        } else {\n            timestamp -= TimeZone.getDefault().getRawOffset();\n        }\n        return new Date(timestamp);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultPage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * The default implementation of {@link Page}\n *\n * @since 2.7.5\n */\npublic class DefaultPage<T> implements Page<T>, Serializable {\n\n    private static final long serialVersionUID = 1099331838954070419L;\n\n    private final int requestOffset;\n\n    private final int pageSize;\n\n    private final int totalSize;\n\n    private final List<T> data;\n\n    private final int totalPages;\n\n    private final boolean hasNext;\n\n    public DefaultPage(int requestOffset, int pageSize, List<T> data, int totalSize) {\n        this.requestOffset = requestOffset;\n        this.pageSize = pageSize;\n        this.data = data;\n        this.totalSize = totalSize;\n        int remain = totalSize % pageSize;\n        this.totalPages = remain > 0 ? (totalSize / pageSize) + 1 : totalSize / pageSize;\n        this.hasNext = totalSize - requestOffset - pageSize > 0;\n    }\n\n    @Override\n    public int getOffset() {\n        return requestOffset;\n    }\n\n    @Override\n    public int getPageSize() {\n        return pageSize;\n    }\n\n    @Override\n    public int getTotalSize() {\n        return totalSize;\n    }\n\n    @Override\n    public int getTotalPages() {\n        return totalPages;\n    }\n\n    @Override\n    public List<T> getData() {\n        return data;\n    }\n\n    @Override\n    public boolean hasNext() {\n        return hasNext;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultParameterNameReader.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Parameter;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\npublic final class DefaultParameterNameReader implements ParameterNameReader {\n\n    private final Map<Object, Optional<String[]>> cache = CollectionUtils.newConcurrentHashMap();\n    private final List<ParameterNameReader> readers;\n\n    public DefaultParameterNameReader(FrameworkModel frameworkModel) {\n        readers = frameworkModel.getActivateExtensions(ParameterNameReader.class);\n    }\n\n    @Override\n    public String[] readParameterNames(Method method) {\n        return cache.computeIfAbsent(method, k -> {\n                    String[] names = readByReflection(method.getParameters());\n                    if (names == null) {\n                        for (ParameterNameReader reader : readers) {\n                            names = reader.readParameterNames(method);\n                            if (names != null) {\n                                break;\n                            }\n                        }\n                    }\n                    return Optional.ofNullable(names);\n                })\n                .orElse(null);\n    }\n\n    @Override\n    public String[] readParameterNames(Constructor<?> ctor) {\n        return cache.computeIfAbsent(ctor, k -> {\n                    String[] names = readByReflection(ctor.getParameters());\n                    if (names == null) {\n                        for (ParameterNameReader reader : readers) {\n                            names = reader.readParameterNames(ctor);\n                            if (names != null) {\n                                break;\n                            }\n                        }\n                    }\n                    return Optional.ofNullable(names);\n                })\n                .orElse(null);\n    }\n\n    private static String[] readByReflection(Parameter[] parameters) {\n        int len = parameters.length;\n        if (len == 0) {\n            return StringUtils.EMPTY_STRING_ARRAY;\n        }\n        String[] names = new String[len];\n        for (int i = 0; i < len; i++) {\n            Parameter param = parameters[i];\n            if (!param.isNamePresent()) {\n                return null;\n            }\n            names[i] = param.getName();\n        }\n        return names;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.aot.NativeDetector;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialization.ClassHolder;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.Serializable;\nimport java.util.Arrays;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNTRUSTED_SERIALIZE_CLASS;\n\n/**\n * Inspired by Fastjson2\n * see com.alibaba.fastjson2.filter.ContextAutoTypeBeforeHandler#apply(java.lang.String, java.lang.Class, long)\n */\npublic class DefaultSerializeClassChecker implements AllowClassNotifyListener {\n\n    private static final long MAGIC_HASH_CODE = 0xcbf29ce484222325L;\n    private static final long MAGIC_PRIME = 0x100000001b3L;\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DefaultSerializeClassChecker.class);\n    private volatile SerializeCheckStatus checkStatus = AllowClassNotifyListener.DEFAULT_STATUS;\n    private volatile boolean checkSerializable = true;\n\n    private final SerializeSecurityManager serializeSecurityManager;\n    private final ClassHolder classHolder;\n    private volatile long[] allowPrefixes = new long[0];\n\n    private volatile long[] disAllowPrefixes = new long[0];\n\n    public DefaultSerializeClassChecker(FrameworkModel frameworkModel) {\n        serializeSecurityManager = frameworkModel.getBeanFactory().getOrRegisterBean(SerializeSecurityManager.class);\n        serializeSecurityManager.registerListener(this);\n        classHolder =\n                NativeDetector.inNativeImage() ? frameworkModel.getBeanFactory().getBean(ClassHolder.class) : null;\n    }\n\n    @Override\n    public synchronized void notifyPrefix(Set<String> allowedList, Set<String> disAllowedList) {\n        this.allowPrefixes = loadPrefix(allowedList);\n        this.disAllowPrefixes = loadPrefix(disAllowedList);\n    }\n\n    @Override\n    public synchronized void notifyCheckStatus(SerializeCheckStatus status) {\n        this.checkStatus = status;\n    }\n\n    @Override\n    public synchronized void notifyCheckSerializable(boolean checkSerializable) {\n        this.checkSerializable = checkSerializable;\n    }\n\n    private static long[] loadPrefix(Set<String> allowedList) {\n        long[] array = new long[allowedList.size()];\n\n        int index = 0;\n        for (String name : allowedList) {\n            if (name == null || name.isEmpty()) {\n                continue;\n            }\n\n            long hashCode = MAGIC_HASH_CODE;\n            for (int j = 0; j < name.length(); ++j) {\n                char ch = name.charAt(j);\n                if (ch == '$') {\n                    ch = '.';\n                }\n                hashCode ^= ch;\n                hashCode *= MAGIC_PRIME;\n            }\n\n            array[index++] = hashCode;\n        }\n\n        if (index != array.length) {\n            array = Arrays.copyOf(array, index);\n        }\n        Arrays.sort(array);\n        return array;\n    }\n\n    /**\n     * Try load class\n     *\n     * @param className class name\n     * @throws IllegalArgumentException if class is blocked\n     */\n    public Class<?> loadClass(ClassLoader classLoader, String className) throws ClassNotFoundException {\n        Class<?> aClass = loadClass0(classLoader, className);\n        if (!aClass.isPrimitive() && !Serializable.class.isAssignableFrom(aClass)) {\n            String msg = \"[Serialization Security] Serialized class \" + className\n                    + \" has not implement Serializable interface. \"\n                    + \"Current mode is strict check, will disallow to deserialize it by default. \";\n            if (serializeSecurityManager.getWarnedClasses().add(className)) {\n                logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, \"\", \"\", msg);\n            }\n\n            if (checkSerializable) {\n                throw new IllegalArgumentException(msg);\n            }\n        }\n\n        return aClass;\n    }\n\n    private Class<?> loadClass0(ClassLoader classLoader, String className) throws ClassNotFoundException {\n        if (checkStatus == SerializeCheckStatus.DISABLE) {\n            return classForName(classLoader, className);\n        }\n\n        long hash = MAGIC_HASH_CODE;\n        for (int i = 0, typeNameLength = className.length(); i < typeNameLength; ++i) {\n            char ch = className.charAt(i);\n            if (ch == '$') {\n                ch = '.';\n            }\n            hash ^= ch;\n            hash *= MAGIC_PRIME;\n\n            if (Arrays.binarySearch(allowPrefixes, hash) >= 0) {\n                return classForName(classLoader, className);\n            }\n        }\n\n        if (checkStatus == SerializeCheckStatus.STRICT) {\n            String msg = \"[Serialization Security] Serialized class \" + className + \" is not in allow list. \"\n                    + \"Current mode is `STRICT`, will disallow to deserialize it by default. \"\n                    + \"Please add it into security/serialize.allowlist or follow FAQ to configure it.\";\n            if (serializeSecurityManager.getWarnedClasses().add(className)) {\n                logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, \"\", \"\", msg);\n            }\n\n            throw new IllegalArgumentException(msg);\n        }\n\n        hash = MAGIC_HASH_CODE;\n        for (int i = 0, typeNameLength = className.length(); i < typeNameLength; ++i) {\n            char ch = className.charAt(i);\n            if (ch == '$') {\n                ch = '.';\n            }\n            hash ^= ch;\n            hash *= MAGIC_PRIME;\n\n            if (Arrays.binarySearch(disAllowPrefixes, hash) >= 0) {\n                String msg = \"[Serialization Security] Serialized class \" + className + \" is in disallow list. \"\n                        + \"Current mode is `WARN`, will disallow to deserialize it by default. \"\n                        + \"Please add it into security/serialize.allowlist or follow FAQ to configure it.\";\n                if (serializeSecurityManager.getWarnedClasses().add(className)) {\n                    logger.warn(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, \"\", \"\", msg);\n                }\n\n                throw new IllegalArgumentException(msg);\n            }\n        }\n\n        hash = MAGIC_HASH_CODE;\n        for (int i = 0, typeNameLength = className.length(); i < typeNameLength; ++i) {\n            char ch = Character.toLowerCase(className.charAt(i));\n            if (ch == '$') {\n                ch = '.';\n            }\n            hash ^= ch;\n            hash *= MAGIC_PRIME;\n\n            if (Arrays.binarySearch(disAllowPrefixes, hash) >= 0) {\n                String msg = \"[Serialization Security] Serialized class \" + className + \" is in disallow list. \"\n                        + \"Current mode is `WARN`, will disallow to deserialize it by default. \"\n                        + \"Please add it into security/serialize.allowlist or follow FAQ to configure it.\";\n                if (serializeSecurityManager.getWarnedClasses().add(className)) {\n                    logger.warn(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, \"\", \"\", msg);\n                }\n\n                throw new IllegalArgumentException(msg);\n            }\n        }\n\n        Class<?> clazz = classForName(classLoader, className);\n        if (serializeSecurityManager.getWarnedClasses().add(className)) {\n            logger.warn(\n                    PROTOCOL_UNTRUSTED_SERIALIZE_CLASS,\n                    \"\",\n                    \"\",\n                    \"[Serialization Security] Serialized class \" + className + \" is not in allow list. \"\n                            + \"Current mode is `WARN`, will allow to deserialize it by default. \"\n                            + \"Dubbo will set to `STRICT` mode by default in the future. \"\n                            + \"Please add it into security/serialize.allowlist or follow FAQ to configure it.\");\n        }\n        return clazz;\n    }\n\n    private Class<?> classForName(ClassLoader classLoader, String className) throws ClassNotFoundException {\n        if (classHolder != null) {\n            Class<?> aClass = classHolder.loadClass(className, classLoader);\n            if (aClass != null) {\n                return aClass;\n            }\n        }\n        return ClassUtils.forName(className, classLoader);\n    }\n\n    public static DefaultSerializeClassChecker getInstance() {\n        return FrameworkModel.defaultModel().getBeanFactory().getBean(DefaultSerializeClassChecker.class);\n    }\n\n    public boolean isCheckSerializable() {\n        return checkSerializable;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/DubboAppender.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.Level;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.appender.AbstractAppender;\nimport org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;\nimport org.apache.logging.log4j.core.appender.FileAppender;\nimport org.apache.logging.log4j.core.config.Property;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;\nimport org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;\n\n@Plugin(name = \"Dubbo\", category = \"Core\", elementType = \"appender\")\npublic class DubboAppender extends AbstractAppender {\n\n    public static class Builder extends AbstractOutputStreamAppender.Builder<Builder>\n            implements org.apache.logging.log4j.core.util.Builder<DubboAppender> {\n\n        @PluginBuilderAttribute\n        private String fileName;\n\n        @PluginBuilderAttribute\n        private boolean append = true;\n\n        @PluginBuilderAttribute\n        private boolean locking;\n\n        public Builder setFileName(String fileName) {\n            this.fileName = fileName;\n            return this;\n        }\n\n        public Builder setAppend(boolean append) {\n            this.append = append;\n            return this;\n        }\n\n        public Builder setLocking(boolean locking) {\n            this.locking = locking;\n            return this;\n        }\n\n        @Override\n        public DubboAppender build() {\n            return new DubboAppender(getName(), buildFileAppender());\n        }\n\n        private <B extends FileAppender.Builder<B>> FileAppender buildFileAppender() {\n            FileAppender.Builder<B> builder = FileAppender.newBuilder();\n            builder.setIgnoreExceptions(isIgnoreExceptions());\n            builder.setLayout(getLayout());\n            builder.setName(getName() + \"-File\");\n            builder.setConfiguration(getConfiguration());\n            builder.setBufferedIo(isBufferedIo());\n            builder.setBufferSize(getBufferSize());\n            builder.setImmediateFlush(isImmediateFlush());\n            builder.withFileName(fileName == null || fileName.isEmpty() ? DEFAULT_FILE_NAME : fileName);\n            builder.withAppend(append);\n            builder.withLocking(locking);\n            return builder.build();\n        }\n    }\n\n    private static final String DEFAULT_FILE_NAME = \"dubbo.log\";\n\n    public static boolean available = false;\n    public static List<Log> logList = new ArrayList<>();\n\n    private final FileAppender fileAppender;\n\n    public DubboAppender() {\n        this(\"Dubbo\", null);\n    }\n\n    private DubboAppender(String name, FileAppender fileAppender) {\n        super(name, null, null, true, Property.EMPTY_ARRAY);\n        this.fileAppender = fileAppender;\n    }\n\n    @PluginBuilderFactory\n    public static Builder newBuilder() {\n        return new Builder().asBuilder();\n    }\n\n    public static void doStart() {\n        available = true;\n    }\n\n    public static void doStop() {\n        available = false;\n    }\n\n    public static void clear() {\n        logList.clear();\n    }\n\n    @Override\n    public void append(LogEvent event) {\n        if (fileAppender != null) {\n            fileAppender.append(event);\n        }\n        if (available) {\n            logList.add(parseLog(event));\n        }\n    }\n\n    @Override\n    public void initialize() {\n        fileAppender.initialize();\n        super.initialize();\n    }\n\n    @Override\n    public void start() {\n        fileAppender.start();\n        super.start();\n    }\n\n    @Override\n    public void stop() {\n        super.stop();\n        fileAppender.stop();\n    }\n\n    private Log parseLog(LogEvent event) {\n        Log log = new Log();\n        log.setLogName(event.getLoggerName());\n        log.setLogLevel(Level.valueOf(event.getLevel().name()));\n        log.setLogThread(event.getThreadName());\n        log.setLogMessage(event.getMessage().getFormattedMessage());\n        return log;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ExecutorUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN;\n\npublic class ExecutorUtil {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ExecutorUtil.class);\n    private static final ThreadPoolExecutor SHUTDOWN_EXECUTOR = new ThreadPoolExecutor(\n            0,\n            1,\n            0L,\n            TimeUnit.MILLISECONDS,\n            new LinkedBlockingQueue<Runnable>(100),\n            new NamedThreadFactory(\"Close-ExecutorService-Timer\", true));\n\n    public static boolean isTerminated(Executor executor) {\n        if (!(executor instanceof ExecutorService)) {\n            return false;\n        }\n        return ((ExecutorService) executor).isTerminated();\n    }\n\n    public static boolean isShutdown(Executor executor) {\n        if (!(executor instanceof ExecutorService)) {\n            return false;\n        }\n        return ((ExecutorService) executor).isShutdown();\n    }\n\n    /**\n     * Use the shutdown pattern from:\n     * https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html\n     *\n     * @param executor the Executor to shutdown\n     * @param timeout  the timeout in milliseconds before termination\n     */\n    public static void gracefulShutdown(Executor executor, int timeout) {\n        if (!(executor instanceof ExecutorService) || isTerminated(executor)) {\n            return;\n        }\n        final ExecutorService es = (ExecutorService) executor;\n        try {\n            // Disable new tasks from being submitted\n            es.shutdown();\n        } catch (SecurityException | NullPointerException ex2) {\n            return;\n        }\n        try {\n            // Wait a while for existing tasks to terminate\n            if (!es.awaitTermination(timeout, TimeUnit.MILLISECONDS)) {\n                es.shutdownNow();\n            }\n        } catch (InterruptedException ex) {\n            es.shutdownNow();\n            Thread.currentThread().interrupt();\n        }\n        if (!isTerminated(es)) {\n            newThreadToCloseExecutor(es);\n        }\n    }\n\n    public static void shutdownNow(Executor executor, final int timeout) {\n        if (!(executor instanceof ExecutorService) || isTerminated(executor)) {\n            return;\n        }\n        final ExecutorService es = (ExecutorService) executor;\n        try {\n            es.shutdownNow();\n        } catch (SecurityException | NullPointerException ex2) {\n            return;\n        }\n        try {\n            es.awaitTermination(timeout, TimeUnit.MILLISECONDS);\n        } catch (InterruptedException ex) {\n            Thread.currentThread().interrupt();\n        }\n        if (!isTerminated(es)) {\n            newThreadToCloseExecutor(es);\n        }\n    }\n\n    private static void newThreadToCloseExecutor(final ExecutorService es) {\n        if (!isTerminated(es)) {\n            SHUTDOWN_EXECUTOR.execute(() -> {\n                try {\n                    for (int i = 0; i < 1000; i++) {\n                        es.shutdownNow();\n                        if (es.awaitTermination(10, TimeUnit.MILLISECONDS)) {\n                            break;\n                        }\n                    }\n                } catch (InterruptedException ex) {\n                    Thread.currentThread().interrupt();\n                } catch (Throwable e) {\n                    logger.warn(COMMON_UNEXPECTED_EXECUTORS_SHUTDOWN, \"\", \"\", e.getMessage(), e);\n                }\n            });\n        }\n    }\n\n    /**\n     * append thread name with url address\n     *\n     * @return new url with updated thread name\n     */\n    public static URL setThreadName(URL url, String defaultName) {\n        String name = url.getParameter(THREAD_NAME_KEY, defaultName);\n        name = name + \"-\" + url.getAddress();\n        url = url.addParameter(THREAD_NAME_KEY, name);\n        return url;\n    }\n\n    public static void cancelScheduledFuture(ScheduledFuture<?> scheduledFuture) {\n        ScheduledFuture<?> future = scheduledFuture;\n        if (future != null && !future.isCancelled()) {\n            future.cancel(true);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/FieldUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Field;\n\nimport static org.apache.dubbo.common.utils.ClassUtils.getAllInheritedTypes;\n\n/**\n * The utilities class for Java Reflection {@link Field}\n *\n * @since 2.7.6\n */\npublic interface FieldUtils {\n\n    /**\n     * Like the {@link Class#getDeclaredField(String)} method without throwing any {@link Exception}\n     *\n     * @param declaredClass the declared class\n     * @param fieldName     the name of {@link Field}\n     * @return if field can't be found, return <code>null</code>\n     */\n    static Field getDeclaredField(Class<?> declaredClass, String fieldName) {\n        try {\n            Field[] fields = declaredClass.getDeclaredFields();\n            for (int i = 0; i < fields.length; i++) {\n                if (fields[i].getName().equals(fieldName)) {\n                    return fields[i];\n                }\n            }\n            return null;\n        } catch (Exception exception) {\n            throw new RuntimeException(exception);\n        }\n    }\n\n    /**\n     * Find the {@link Field} by the name in the specified class and its inherited types\n     *\n     * @param declaredClass the declared class\n     * @param fieldName     the name of {@link Field}\n     * @return if can't be found, return <code>null</code>\n     */\n    static Field findField(Class<?> declaredClass, String fieldName) {\n        Field field = getDeclaredField(declaredClass, fieldName);\n        if (field != null) {\n            return field;\n        }\n        for (Class superType : getAllInheritedTypes(declaredClass)) {\n            field = getDeclaredField(superType, fieldName);\n            if (field != null) {\n                break;\n            }\n        }\n\n        if (field == null) {\n            throw new IllegalStateException(String.format(\"cannot find field %s,field is null\", fieldName));\n        }\n\n        return field;\n    }\n\n    /**\n     * Find the {@link Field} by the name in the specified class and its inherited types\n     *\n     * @param object    the object whose field should be modified\n     * @param fieldName the name of {@link Field}\n     * @return if can't be found, return <code>null</code>\n     */\n    static Field findField(Object object, String fieldName) {\n        return findField(object.getClass(), fieldName);\n    }\n\n    /**\n     * Get the value of the specified {@link Field}\n     *\n     * @param object    the object whose field should be modified\n     * @param fieldName the name of {@link Field}\n     * @return the value of  the specified {@link Field}\n     */\n    static Object getFieldValue(Object object, String fieldName) {\n        return getFieldValue(object, findField(object, fieldName));\n    }\n\n    /**\n     * Get the value of the specified {@link Field}\n     *\n     * @param object the object whose field should be modified\n     * @param field  {@link Field}\n     * @return the value of  the specified {@link Field}\n     */\n    static <T> T getFieldValue(Object object, Field field) {\n        boolean accessible = field.isAccessible();\n        Object value = null;\n        try {\n            if (!accessible) {\n                field.setAccessible(true);\n            }\n            value = field.get(object);\n        } catch (IllegalAccessException ignored) {\n        } finally {\n            field.setAccessible(accessible);\n        }\n        return (T) value;\n    }\n\n    /**\n     * Set the value for the specified {@link Field}\n     *\n     * @param object    the object whose field should be modified\n     * @param fieldName the name of {@link Field}\n     * @param value     the value of field to be set\n     * @return the previous value of the specified {@link Field}\n     */\n    static <T> T setFieldValue(Object object, String fieldName, T value) {\n        return setFieldValue(object, findField(object, fieldName), value);\n    }\n\n    /**\n     * Set the value for the specified {@link Field}\n     *\n     * @param object the object whose field should be modified\n     * @param field  {@link Field}\n     * @param value  the value of field to be set\n     * @return the previous value of the specified {@link Field}\n     */\n    static <T> T setFieldValue(Object object, Field field, T value) {\n        boolean accessible = field.isAccessible();\n        Object previousValue = null;\n        try {\n            if (!accessible) {\n                field.setAccessible(true);\n            }\n            previousValue = field.get(object);\n            field.set(object, value);\n        } catch (IllegalAccessException ignored) {\n        } finally {\n            field.setAccessible(accessible);\n        }\n        return (T) previousValue;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/Holder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\n/**\n * Helper Class for hold a value.\n */\npublic class Holder<T> {\n\n    private volatile T value;\n\n    public void set(T value) {\n        this.value = value;\n    }\n\n    public T get() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/IOUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\n\nimport java.io.BufferedReader;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.PrintWriter;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Miscellaneous io utility methods.\n * Mainly for internal use within the framework.\n *\n * @since 2.0.7\n */\npublic class IOUtils {\n    private static final int BUFFER_SIZE = 1024 * 8;\n    public static final int EOF = -1;\n\n    private IOUtils() {}\n\n    /**\n     * write.\n     *\n     * @param is InputStream instance.\n     * @param os OutputStream instance.\n     * @return count.\n     * @throws IOException If an I/O error occurs\n     */\n    public static long write(InputStream is, OutputStream os) throws IOException {\n        return write(is, os, BUFFER_SIZE);\n    }\n\n    /**\n     * write.\n     *\n     * @param is         InputStream instance.\n     * @param os         OutputStream instance.\n     * @param bufferSize buffer size.\n     * @return count.\n     * @throws IOException If an I/O error occurs\n     */\n    public static long write(InputStream is, OutputStream os, int bufferSize) throws IOException {\n        byte[] buff = new byte[bufferSize];\n        return write(is, os, buff);\n    }\n\n    /**\n     * write.\n     *\n     * @param input  InputStream instance.\n     * @param output OutputStream instance.\n     * @param buffer buffer byte array\n     * @return count.\n     * @throws IOException If an I/O error occurs\n     */\n    public static long write(final InputStream input, final OutputStream output, final byte[] buffer)\n            throws IOException {\n        long count = 0;\n        int n;\n        while (EOF != (n = input.read(buffer))) {\n            output.write(buffer, 0, n);\n            count += n;\n        }\n        return count;\n    }\n\n    /**\n     * read string.\n     *\n     * @param reader Reader instance.\n     * @return String.\n     * @throws IOException If an I/O error occurs\n     */\n    public static String read(Reader reader) throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            write(reader, writer);\n            return writer.getBuffer().toString();\n        }\n    }\n\n    /**\n     * write string.\n     *\n     * @param writer Writer instance.\n     * @param string String.\n     * @throws IOException If an I/O error occurs\n     */\n    public static long write(Writer writer, String string) throws IOException {\n        try (Reader reader = new StringReader(string)) {\n            return write(reader, writer);\n        }\n    }\n\n    /**\n     * write.\n     *\n     * @param reader Reader.\n     * @param writer Writer.\n     * @return count.\n     * @throws IOException If an I/O error occurs\n     */\n    public static long write(Reader reader, Writer writer) throws IOException {\n        return write(reader, writer, BUFFER_SIZE);\n    }\n\n    /**\n     * write.\n     *\n     * @param reader     Reader.\n     * @param writer     Writer.\n     * @param bufferSize buffer size.\n     * @return count.\n     * @throws IOException If an I/O error occurs\n     */\n    public static long write(Reader reader, Writer writer, int bufferSize) throws IOException {\n        int read;\n        long total = 0;\n        char[] buf = new char[bufferSize];\n        while ((read = reader.read(buf)) != -1) {\n            writer.write(buf, 0, read);\n            total += read;\n        }\n        return total;\n    }\n\n    /**\n     * read lines.\n     *\n     * @param file file.\n     * @return lines.\n     * @throws IOException If an I/O error occurs\n     */\n    public static String[] readLines(File file) throws IOException {\n        if (file == null || !file.exists() || !file.canRead()) {\n            return new String[0];\n        }\n\n        return readLines(new FileInputStream(file));\n    }\n\n    /**\n     * read lines.\n     *\n     * @param is input stream.\n     * @return lines.\n     * @throws IOException If an I/O error occurs\n     */\n    public static String[] readLines(InputStream is) throws IOException {\n        List<String> lines = new ArrayList<>();\n        try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {\n            String line;\n            while ((line = reader.readLine()) != null) {\n                lines.add(line);\n            }\n            return lines.toArray(new String[0]);\n        }\n    }\n\n    public static String read(InputStream is, String encoding) throws IOException {\n        StringBuilder stringBuilder = new StringBuilder();\n        InputStreamReader inputStreamReader = new InputStreamReader(is, encoding);\n        char[] buf = new char[1024];\n        int len;\n        while ((len = inputStreamReader.read(buf)) != -1) {\n            stringBuilder.append(buf, 0, len);\n        }\n        inputStreamReader.close();\n        return stringBuilder.toString();\n    }\n\n    /**\n     * write lines.\n     *\n     * @param os    output stream.\n     * @param lines lines.\n     * @throws IOException If an I/O error occurs\n     */\n    public static void writeLines(OutputStream os, String[] lines) throws IOException {\n        try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(os))) {\n            for (String line : lines) {\n                writer.println(line);\n            }\n            writer.flush();\n        }\n    }\n\n    /**\n     * write lines.\n     *\n     * @param file  file.\n     * @param lines lines.\n     * @throws IOException If an I/O error occurs\n     */\n    public static void writeLines(File file, String[] lines) throws IOException {\n        if (file == null) {\n            throw new IOException(\"File is null.\");\n        }\n        writeLines(new FileOutputStream(file), lines);\n    }\n\n    /**\n     * append lines.\n     *\n     * @param file  file.\n     * @param lines lines.\n     * @throws IOException If an I/O error occurs\n     */\n    public static void appendLines(File file, String[] lines) throws IOException {\n        if (file == null) {\n            throw new IOException(\"File is null.\");\n        }\n        writeLines(new FileOutputStream(file, true), lines);\n    }\n\n    /**\n     * use like spring code\n     *\n     * @param resourceLocation\n     * @return\n     */\n    public static URL getURL(String resourceLocation) throws FileNotFoundException {\n        Assert.notNull(resourceLocation, \"Resource location must not be null\");\n        if (resourceLocation.startsWith(CommonConstants.CLASSPATH_URL_PREFIX)) {\n            String path = resourceLocation.substring(CommonConstants.CLASSPATH_URL_PREFIX.length());\n            ClassLoader cl = ClassUtils.getClassLoader();\n            URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));\n            if (url == null) {\n                String description = \"class path resource [\" + path + \"]\";\n                throw new FileNotFoundException(description + \" cannot be resolved to URL because it does not exist\");\n            }\n            return url;\n        }\n        try {\n            // try URL\n            return new URL(resourceLocation);\n        } catch (MalformedURLException ex) {\n            // no URL -> treat as file path\n            try {\n                return new File(resourceLocation).toURI().toURL();\n            } catch (MalformedURLException ex2) {\n                throw new FileNotFoundException(\n                        \"Resource location [\" + resourceLocation + \"] is neither a URL not a well-formed file path\");\n            }\n        }\n    }\n\n    public static byte[] toByteArray(final InputStream inputStream) throws IOException {\n        try (final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {\n            byte[] buffer = new byte[1024];\n            int n;\n            while (-1 != (n = inputStream.read(buffer))) {\n                byteArrayOutputStream.write(buffer, 0, n);\n            }\n            return byteArrayOutputStream.toByteArray();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/JRE.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_JAVA_VERSION;\n\n/**\n * JRE version\n */\npublic enum JRE {\n    JAVA_8,\n\n    JAVA_9,\n\n    JAVA_10,\n\n    JAVA_11,\n\n    JAVA_12,\n\n    JAVA_13,\n\n    JAVA_14,\n\n    JAVA_15,\n\n    JAVA_16,\n\n    JAVA_17,\n\n    JAVA_18,\n\n    JAVA_19,\n\n    JAVA_20,\n\n    JAVA_21,\n\n    JAVA_22,\n\n    JAVA_23,\n\n    JAVA_24,\n\n    JAVA_25,\n\n    OTHER;\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(JRE.class);\n\n    private static final JRE VERSION = getJre();\n\n    /**\n     * get current JRE version\n     *\n     * @return JRE version\n     */\n    public static JRE currentVersion() {\n        return VERSION;\n    }\n\n    /**\n     * is current version\n     *\n     * @return true if current version\n     */\n    public boolean isCurrentVersion() {\n        return this == VERSION;\n    }\n\n    private static JRE getJre() {\n        // get java version from system property\n        String version = SystemPropertyConfigUtils.getSystemProperty(SYSTEM_JAVA_VERSION);\n        boolean isBlank = StringUtils.isBlank(version);\n        if (isBlank) {\n            logger.debug(\"java.version is blank\");\n        }\n        // if start with 1.8 return java 8\n        if (!isBlank && version.startsWith(\"1.8\")) {\n            return JAVA_8;\n        }\n        // if JRE version is 9 or above, we can get version from java.lang.Runtime.version()\n        try {\n            Object javaRunTimeVersion = MethodUtils.invokeMethod(Runtime.getRuntime(), \"version\");\n            int majorVersion = MethodUtils.invokeMethod(javaRunTimeVersion, \"major\");\n            switch (majorVersion) {\n                case 9:\n                    return JAVA_9;\n                case 10:\n                    return JAVA_10;\n                case 11:\n                    return JAVA_11;\n                case 12:\n                    return JAVA_12;\n                case 13:\n                    return JAVA_13;\n                case 14:\n                    return JAVA_14;\n                case 15:\n                    return JAVA_15;\n                case 16:\n                    return JAVA_16;\n                case 17:\n                    return JAVA_17;\n                case 18:\n                    return JAVA_18;\n                case 19:\n                    return JAVA_19;\n                case 20:\n                    return JAVA_20;\n                case 21:\n                    return JAVA_21;\n                case 22:\n                    return JAVA_22;\n                case 23:\n                    return JAVA_23;\n                case 24:\n                    return JAVA_24;\n                case 25:\n                    return JAVA_25;\n                default:\n                    return OTHER;\n            }\n        } catch (Exception e) {\n            logger.debug(\n                    \"Can't determine current JRE version (maybe java.version is null), assuming that JRE version is 8.\",\n                    e);\n        }\n        // default java 8\n        return JAVA_8;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/JVMUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\n\nimport java.io.OutputStream;\nimport java.lang.management.LockInfo;\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.MonitorInfo;\nimport java.lang.management.ThreadInfo;\nimport java.lang.management.ThreadMXBean;\nimport java.nio.charset.StandardCharsets;\n\nimport static java.lang.Thread.State.BLOCKED;\nimport static java.lang.Thread.State.TIMED_WAITING;\nimport static java.lang.Thread.State.WAITING;\n\npublic class JVMUtil {\n    public static void jstack(OutputStream stream) throws Exception {\n        ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();\n        for (ThreadInfo threadInfo : threadMxBean.dumpAllThreads(true, true)) {\n            stream.write(getThreadDumpString(threadInfo).getBytes(StandardCharsets.UTF_8));\n        }\n    }\n\n    private static String getThreadDumpString(ThreadInfo threadInfo) {\n        StringBuilder sb = new StringBuilder(\"\\\"\" + threadInfo.getThreadName() + \"\\\"\" + \" Id=\"\n                + threadInfo.getThreadId() + \" \" + threadInfo.getThreadState());\n        if (threadInfo.getLockName() != null) {\n            sb.append(\" on \" + threadInfo.getLockName());\n        }\n        if (threadInfo.getLockOwnerName() != null) {\n            sb.append(\" owned by \\\"\" + threadInfo.getLockOwnerName() + \"\\\" Id=\" + threadInfo.getLockOwnerId());\n        }\n        if (threadInfo.isSuspended()) {\n            sb.append(\" (suspended)\");\n        }\n        if (threadInfo.isInNative()) {\n            sb.append(\" (in native)\");\n        }\n        sb.append('\\n');\n        int i = 0;\n        // default is 32, means only print up to 32 lines\n        int jstackMaxLine = 32;\n        String jstackMaxLineStr =\n                SystemPropertyConfigUtils.getSystemProperty(CommonConstants.DubboProperty.DUBBO_JSTACK_MAXLINE);\n        if (StringUtils.isNotEmpty(jstackMaxLineStr)) {\n            try {\n                jstackMaxLine = Integer.parseInt(jstackMaxLineStr);\n            } catch (Exception ignore) {\n            }\n        }\n        StackTraceElement[] stackTrace = threadInfo.getStackTrace();\n        MonitorInfo[] lockedMonitors = threadInfo.getLockedMonitors();\n        for (; i < stackTrace.length && i < jstackMaxLine; i++) {\n            StackTraceElement ste = stackTrace[i];\n            sb.append(\"\\tat \").append(ste.toString());\n            sb.append('\\n');\n            if (i == 0 && threadInfo.getLockInfo() != null) {\n                Thread.State ts = threadInfo.getThreadState();\n                if (BLOCKED.equals(ts)) {\n                    sb.append(\"\\t-  blocked on \").append(threadInfo.getLockInfo());\n                    sb.append('\\n');\n                } else if (WAITING.equals(ts) || TIMED_WAITING.equals(ts)) {\n                    sb.append(\"\\t-  waiting on \").append(threadInfo.getLockInfo());\n                    sb.append('\\n');\n                }\n            }\n\n            for (MonitorInfo mi : lockedMonitors) {\n                if (mi.getLockedStackDepth() == i) {\n                    sb.append(\"\\t-  locked \").append(mi);\n                    sb.append('\\n');\n                }\n            }\n        }\n        if (i < stackTrace.length) {\n            sb.append(\"\\t...\");\n            sb.append('\\n');\n        }\n\n        LockInfo[] locks = threadInfo.getLockedSynchronizers();\n        if (locks.length > 0) {\n            sb.append(\"\\n\\tNumber of locked synchronizers = \" + locks.length);\n            sb.append('\\n');\n            for (LockInfo li : locks) {\n                sb.append(\"\\t- \" + li);\n                sb.append('\\n');\n            }\n        }\n        sb.append('\\n');\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/JavassistParameterNameReader.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.Map;\nimport javassist.ClassPool;\nimport javassist.CtBehavior;\nimport javassist.CtConstructor;\nimport javassist.CtMethod;\nimport javassist.LoaderClassPath;\nimport javassist.bytecode.CodeAttribute;\nimport javassist.bytecode.Descriptor;\nimport javassist.bytecode.LocalVariableAttribute;\n\nimport static org.apache.dubbo.common.logger.LoggerFactory.getErrorTypeAwareLogger;\n\n@Activate(order = 100, onClass = \"javassist.ClassPool\")\npublic class JavassistParameterNameReader implements ParameterNameReader {\n\n    private static final ErrorTypeAwareLogger LOG = getErrorTypeAwareLogger(JavassistParameterNameReader.class);\n\n    private final Map<Integer, ClassPool> classPoolMap = CollectionUtils.newConcurrentHashMap();\n\n    @Override\n    public String[] readParameterNames(Method method) {\n        try {\n            Class<?>[] paramTypes = method.getParameterTypes();\n            if (paramTypes.length == 0) {\n                return StringUtils.EMPTY_STRING_ARRAY;\n            }\n            String descriptor = getDescriptor(paramTypes, method.getReturnType());\n            Class<?> clazz = method.getDeclaringClass();\n            CtMethod ctMethod = getClassPool(clazz).get(clazz.getName()).getMethod(method.getName(), descriptor);\n            return read(ctMethod, Modifier.isStatic(method.getModifiers()) ? 0 : 1, paramTypes.length);\n        } catch (Throwable t) {\n            LOG.warn(LoggerCodeConstants.INTERNAL_ERROR, \"\", \"\", \"Read parameter names error\", t);\n            return null;\n        }\n    }\n\n    @Override\n    public String[] readParameterNames(Constructor<?> ctor) {\n        try {\n            Class<?>[] paramTypes = ctor.getParameterTypes();\n            if (paramTypes.length == 0) {\n                return StringUtils.EMPTY_STRING_ARRAY;\n            }\n            String descriptor = getDescriptor(paramTypes, void.class);\n            Class<?> clazz = ctor.getDeclaringClass();\n            CtConstructor ctCtor = getClassPool(clazz).get(clazz.getName()).getConstructor(descriptor);\n            return read(ctCtor, 1, paramTypes.length);\n        } catch (Throwable t) {\n            LOG.warn(LoggerCodeConstants.INTERNAL_ERROR, \"\", \"\", \"Read parameter names error\", t);\n            return null;\n        }\n    }\n\n    private static String getDescriptor(Class<?>[] parameterTypes, Class<?> returnType) {\n        StringBuilder descriptor = new StringBuilder(32);\n        descriptor.append('(');\n        for (Class<?> type : parameterTypes) {\n            descriptor.append(toJvmName(type));\n        }\n        descriptor.append(')');\n        descriptor.append(toJvmName(returnType));\n        return descriptor.toString();\n    }\n\n    private static String toJvmName(Class<?> clazz) {\n        return clazz.isArray() ? Descriptor.toJvmName(clazz.getName()) : Descriptor.of(clazz.getName());\n    }\n\n    private ClassPool getClassPool(Class<?> clazz) {\n        ClassLoader classLoader = ClassUtils.getClassLoader(clazz);\n        return classPoolMap.computeIfAbsent(System.identityHashCode(classLoader), k -> {\n            ClassPool pool = new ClassPool();\n            pool.appendClassPath(new LoaderClassPath(classLoader));\n            return pool;\n        });\n    }\n\n    private static String[] read(CtBehavior behavior, int start, int len) {\n        if (behavior == null) {\n            return null;\n        }\n        CodeAttribute codeAttr = behavior.getMethodInfo().getCodeAttribute();\n        if (codeAttr == null) {\n            return null;\n        }\n        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttr.getAttribute(LocalVariableAttribute.tag);\n        if (attr == null) {\n            return null;\n        }\n        String[] names = new String[len];\n        for (int i = 0, tLen = attr.tableLength(); i < tLen; i++) {\n            int j = attr.index(i) - start;\n            if (j >= 0 && j < len) {\n                names[j] = attr.variableName(i);\n            }\n        }\n\n        return names;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/JsonCompatibilityUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.GenericArrayType;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class JsonCompatibilityUtil {\n\n    private static final Logger logger = LoggerFactory.getLogger(JsonCompatibilityUtil.class);\n\n    private static final Set<String> unsupportedClasses = new HashSet<>(Arrays.asList(\n            \"java.util.Optional\",\n            \"java.util.Calendar\",\n            \"java.util.Iterator\",\n            \"java.io.InputStream\",\n            \"java.io.OutputStream\"));\n\n    /**\n     * Determine whether a Class can be serialized by JSON.\n     * @param clazz Incoming Class.\n     * @return If a Class can be serialized by JSON, return true;\n     * else return false.\n     */\n    public static boolean checkClassCompatibility(Class<?> clazz) {\n        Method[] methods = clazz.getDeclaredMethods();\n\n        boolean result;\n\n        for (Method method : methods) {\n            result = checkMethodCompatibility(method);\n            if (!result) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Determine whether a Method can be serialized by JSON.\n     * @param method Incoming Method.\n     * @return If a Method can be serialized by JSON, return true;\n     * else return false.\n     */\n    public static boolean checkMethodCompatibility(Method method) {\n\n        boolean result;\n\n        Type[] types = method.getGenericParameterTypes();\n        List<Type> typeList = new ArrayList<>(Arrays.asList(types));\n        Type returnType = method.getGenericReturnType();\n        typeList.add(returnType);\n        for (Type type : typeList) {\n            result = checkType(type);\n            if (!result) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Get unsupported methods.\n     * @param clazz\n     * @return If there are unsupported methods, return them by List;\n     * else return null.\n     */\n    public static List<String> getUnsupportedMethods(Class<?> clazz) {\n        ArrayList<String> unsupportedMethods = new ArrayList<>();\n\n        Method[] methods = clazz.getDeclaredMethods();\n\n        for (Method method : methods) {\n            if (!checkMethodCompatibility(method)) {\n                unsupportedMethods.add(method.getName());\n            }\n        }\n\n        return unsupportedMethods.size() > 0 ? unsupportedMethods : null;\n    }\n\n    /**\n     * Determine whether a Type can be serialized by JSON.\n     * @param classType Incoming Type.\n     * @return If a Type can be serialized by JSON, return true;\n     * else return false.\n     */\n    private static boolean checkType(Type classType) {\n\n        boolean result;\n\n        if (classType instanceof TypeVariable) {\n            return true;\n        }\n\n        if (classType instanceof ParameterizedType) {\n\n            Type[] types = ((ParameterizedType) classType).getActualTypeArguments();\n            List<Type> typeList = new ArrayList<>(Arrays.asList(types));\n            classType = ((ParameterizedType) classType).getRawType();\n            typeList.add(classType);\n            for (Type type : typeList) {\n                result = checkType(type);\n                if (!result) {\n                    return false;\n                }\n            }\n        } else if (classType instanceof GenericArrayType) {\n            Type componentType = ((GenericArrayType) classType).getGenericComponentType();\n            result = checkType(componentType);\n            return result;\n        } else if (classType instanceof Class<?>) {\n            Class<?> clazz = (Class<?>) classType;\n\n            String className = clazz.getName();\n\n            if (clazz.isArray()) {\n                Type componentType = clazz.getComponentType();\n                result = checkType(componentType);\n                return result;\n            } else if (clazz.isPrimitive()) {\n                // deal with case of basic byte\n                return !unsupportedClasses.contains(className);\n            } else if (className.startsWith(\"java\") || className.startsWith(\"javax\")) {\n                return !unsupportedClasses.contains(className);\n            } else {\n                // deal with case of interface\n                if (clazz.isInterface()) {\n                    return false;\n                }\n                // deal with case of abstract\n                if (Modifier.isAbstract(clazz.getModifiers())) {\n                    return false;\n                }\n                if (clazz.isEnum()) {\n                    return true;\n                }\n                // deal with case of record\n                //                if (clazz.isRecord()) {\n                //                    return false;\n                //                }\n                // deal with field one by one\n                for (Field field : clazz.getDeclaredFields()) {\n                    Type type = field.getGenericType();\n                    Class<?> fieldClass = field.getType();\n                    result = checkType(type);\n                    if (!result) {\n                        return false;\n                    }\n                }\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/JsonUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.json.JsonUtil;\n\nimport java.lang.reflect.Type;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.ServiceLoader;\nimport java.util.TreeMap;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME;\n\npublic class JsonUtils {\n\n    private static volatile JsonUtil jsonUtil;\n\n    public static JsonUtil getJson() {\n        if (jsonUtil == null) {\n            synchronized (JsonUtils.class) {\n                if (jsonUtil == null) {\n                    jsonUtil = createJsonUtil();\n                }\n            }\n        }\n        return jsonUtil;\n    }\n\n    private static JsonUtil createJsonUtil() {\n        Map<String, JsonUtil> extensions = new HashMap<>();\n        String preferName = SystemPropertyConfigUtils.getSystemProperty(DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n        ClassLoader classLoader = JsonUtil.class.getClassLoader();\n        JsonUtil jsonUtil = loadExtensions(preferName, classLoader, extensions);\n        if (jsonUtil != null) {\n            return jsonUtil;\n        }\n\n        ClassLoader tccl = Thread.currentThread().getContextClassLoader();\n        if (tccl != null && tccl != classLoader) {\n            jsonUtil = loadExtensions(preferName, classLoader, extensions);\n            if (jsonUtil != null) {\n                return jsonUtil;\n            }\n        }\n\n        TreeMap<Integer, JsonUtil> sortedExtensions = new TreeMap<>();\n        for (JsonUtil extension : extensions.values()) {\n            Activate activate = extension.getClass().getAnnotation(Activate.class);\n            sortedExtensions.put(activate == null ? 0 : activate.order(), extension);\n        }\n\n        if (sortedExtensions.isEmpty()) {\n            throw new IllegalStateException(\"Dubbo unable to find out any json framework (e.g. fastjson2, \"\n                    + \"fastjson, gson, jackson) from jvm env. Please import at least one json framework.\");\n        }\n\n        return sortedExtensions.firstEntry().getValue();\n    }\n\n    private static JsonUtil loadExtensions(String name, ClassLoader classLoader, Map<String, JsonUtil> extensions) {\n        ServiceLoader<JsonUtil> loader = ServiceLoader.load(JsonUtil.class, classLoader);\n        Iterator<JsonUtil> it = loader.iterator();\n        // In JDK 21+, ServiceLoader.hasNext() may throw NoClassDefFoundError\n        // when checking class dependencies, so we need to catch it here\n        while (true) {\n            try {\n                if (!it.hasNext()) {\n                    break;\n                }\n                JsonUtil extension = it.next();\n                if (extension.isSupport()) {\n                    if (name != null && name.equals(extension.getName())) {\n                        return extension;\n                    }\n                    extensions.put(extension.getName(), extension);\n                }\n            } catch (Throwable ignored) {\n                // Ignore loading failures (e.g., NoClassDefFoundError in JDK 25)\n                // and continue with the next extension\n            }\n        }\n        return null;\n    }\n\n    /**\n     * @deprecated for unit test only\n     */\n    @Deprecated\n    @SuppressWarnings(\"DeprecatedIsStillUsed\")\n    protected static void setJson(JsonUtil json) {\n        jsonUtil = json;\n    }\n\n    public static <T> T toJavaObject(String json, Type type) {\n        return getJson().toJavaObject(json, type);\n    }\n\n    public static <T> List<T> toJavaList(String json, Class<T> clazz) {\n        return getJson().toJavaList(json, clazz);\n    }\n\n    public static String toJson(Object obj) {\n        return getJson().toJson(obj);\n    }\n\n    public static String toPrettyJson(Object obj) {\n        return getJson().toPrettyJson(obj);\n    }\n\n    public static List<?> getList(Map<String, ?> obj, String key) {\n        return getJson().getList(obj, key);\n    }\n\n    public static List<Map<String, ?>> getListOfObjects(Map<String, ?> obj, String key) {\n        return getJson().getListOfObjects(obj, key);\n    }\n\n    public static List<String> getListOfStrings(Map<String, ?> obj, String key) {\n        return getJson().getListOfStrings(obj, key);\n    }\n\n    public static Map<String, ?> getObject(Map<String, ?> obj, String key) {\n        return getJson().getObject(obj, key);\n    }\n\n    public static Object convertObject(Object obj, Type targetType) {\n        return getJson().convertObject(obj, targetType);\n    }\n\n    public static Object convertObject(Object obj, Class<?> targetType) {\n        return getJson().convertObject(obj, targetType);\n    }\n\n    public static Double getNumberAsDouble(Map<String, ?> obj, String key) {\n        return getJson().getNumberAsDouble(obj, key);\n    }\n\n    public static Integer getNumberAsInteger(Map<String, ?> obj, String key) {\n        return getJson().getNumberAsInteger(obj, key);\n    }\n\n    public static Long getNumberAsLong(Map<String, ?> obj, String key) {\n        return getJson().getNumberAsLong(obj, key);\n    }\n\n    public static String getString(Map<String, ?> obj, String key) {\n        return getJson().getString(obj, key);\n    }\n\n    public static List<Map<String, ?>> checkObjectList(List<?> rawList) {\n        return getJson().checkObjectList(rawList);\n    }\n\n    public static List<String> checkStringList(List<?> rawList) {\n        return getJson().checkStringList(rawList);\n    }\n\n    public static boolean checkJson(String json) {\n        return getJson().isJson(json);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/LFUCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.locks.ReentrantLock;\n\npublic class LFUCache<K, V> {\n\n    private final Map<K, CacheNode<K, V>> map;\n    private final CacheDeque<K, V>[] freqTable;\n\n    private final int capacity;\n    private final int evictionCount;\n    private int curSize = 0;\n\n    private final ReentrantLock lock = new ReentrantLock();\n    private static final int DEFAULT_INITIAL_CAPACITY = 1000;\n\n    private static final float DEFAULT_EVICTION_FACTOR = 0.75f;\n\n    public LFUCache() {\n        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_EVICTION_FACTOR);\n    }\n\n    /**\n     * Constructs and initializes cache with specified capacity and eviction\n     * factor. Unacceptable parameter values followed with\n     * {@link IllegalArgumentException}.\n     *\n     * @param maxCapacity    cache max capacity\n     * @param evictionFactor cache proceedEviction factor\n     */\n    @SuppressWarnings(\"unchecked\")\n    public LFUCache(final int maxCapacity, final float evictionFactor) {\n        if (maxCapacity <= 0) {\n            throw new IllegalArgumentException(\"Illegal initial capacity: \" + maxCapacity);\n        }\n        boolean factorInRange = evictionFactor <= 1 && evictionFactor > 0;\n        if (!factorInRange || Float.isNaN(evictionFactor)) {\n            throw new IllegalArgumentException(\"Illegal eviction factor value:\" + evictionFactor);\n        }\n        this.capacity = maxCapacity;\n        this.evictionCount = (int) (capacity * evictionFactor);\n        this.map = new HashMap<>();\n        this.freqTable = new CacheDeque[capacity + 1];\n        for (int i = 0; i <= capacity; i++) {\n            freqTable[i] = new CacheDeque<>();\n        }\n        for (int i = 0; i < capacity; i++) {\n            freqTable[i].nextDeque = freqTable[i + 1];\n        }\n        freqTable[capacity].nextDeque = freqTable[capacity];\n    }\n\n    public int getCapacity() {\n        return capacity;\n    }\n\n    public V put(final K key, final V value) {\n        CacheNode<K, V> node;\n        lock.lock();\n        try {\n            node = map.get(key);\n            if (node != null) {\n                CacheNode.withdrawNode(node);\n                node.value = value;\n                freqTable[0].addLastNode(node);\n                map.put(key, node);\n            } else {\n                curSize++;\n                if (curSize > capacity) {\n                    proceedEviction();\n                }\n                node = freqTable[0].addLast(key, value);\n                map.put(key, node);\n            }\n        } finally {\n            lock.unlock();\n        }\n        return node.value;\n    }\n\n    public V remove(final K key) {\n        CacheNode<K, V> node = null;\n        lock.lock();\n        try {\n            if (map.containsKey(key)) {\n                node = map.remove(key);\n                if (node != null) {\n                    CacheNode.withdrawNode(node);\n                }\n                curSize--;\n            }\n        } finally {\n            lock.unlock();\n        }\n        return (node != null) ? node.value : null;\n    }\n\n    public V get(final K key) {\n        CacheNode<K, V> node = null;\n        lock.lock();\n        try {\n            if (map.containsKey(key)) {\n                node = map.get(key);\n                CacheNode.withdrawNode(node);\n                node.owner.nextDeque.addLastNode(node);\n            }\n        } finally {\n            lock.unlock();\n        }\n        return (node != null) ? node.value : null;\n    }\n\n    /**\n     * Evicts less frequently used elements corresponding to eviction factor,\n     * specified at instantiation step.\n     *\n     * @return number of evicted elements\n     */\n    private int proceedEviction() {\n        int targetSize = capacity - evictionCount;\n        int evictedElements = 0;\n\n        FREQ_TABLE_ITER_LOOP:\n        for (int i = 0; i <= capacity; i++) {\n            CacheNode<K, V> node;\n            while (!freqTable[i].isEmpty()) {\n                node = freqTable[i].pollFirst();\n                remove(node.key);\n                if (targetSize >= curSize) {\n                    break FREQ_TABLE_ITER_LOOP;\n                }\n                evictedElements++;\n            }\n        }\n        return evictedElements;\n    }\n\n    /**\n     * Returns cache current size.\n     *\n     * @return cache size\n     */\n    public int getSize() {\n        return curSize;\n    }\n\n    static class CacheNode<K, V> {\n\n        CacheNode<K, V> prev;\n        CacheNode<K, V> next;\n        K key;\n        V value;\n        CacheDeque<K, V> owner;\n\n        CacheNode() {}\n\n        CacheNode(final K key, final V value) {\n            this.key = key;\n            this.value = value;\n        }\n\n        /**\n         * This method takes specified node and reattaches it neighbors nodes\n         * links to each other, so specified node will no longer tied with them.\n         * Returns united node, returns null if argument is null.\n         *\n         * @param node note to retrieve\n         * @param <K>  key\n         * @param <V>  value\n         * @return retrieved node\n         */\n        static <K, V> CacheNode<K, V> withdrawNode(final CacheNode<K, V> node) {\n            if (node != null && node.prev != null) {\n                node.prev.next = node.next;\n                if (node.next != null) {\n                    node.next.prev = node.prev;\n                }\n            }\n            return node;\n        }\n    }\n\n    /**\n     * Custom deque implementation of LIFO type. Allows to place element at top\n     * of deque and poll very last added elements. An arbitrary node from the\n     * deque can be removed with {@link CacheNode#withdrawNode(CacheNode)}\n     * method.\n     *\n     * @param <K> key\n     * @param <V> value\n     */\n    static class CacheDeque<K, V> {\n\n        CacheNode<K, V> last;\n        CacheNode<K, V> first;\n        CacheDeque<K, V> nextDeque;\n\n        /**\n         * Constructs list and initializes last and first pointers.\n         */\n        CacheDeque() {\n            last = new CacheNode<>();\n            first = new CacheNode<>();\n            last.next = first;\n            first.prev = last;\n        }\n\n        /**\n         * Puts the node with specified key and value at the end of the deque\n         * and returns node.\n         *\n         * @param key   key\n         * @param value value\n         * @return added node\n         */\n        CacheNode<K, V> addLast(final K key, final V value) {\n            CacheNode<K, V> node = new CacheNode<>(key, value);\n            node.owner = this;\n            node.next = last.next;\n            node.prev = last;\n            node.next.prev = node;\n            last.next = node;\n            return node;\n        }\n\n        CacheNode<K, V> addLastNode(final CacheNode<K, V> node) {\n            node.owner = this;\n            node.next = last.next;\n            node.prev = last;\n            node.next.prev = node;\n            last.next = node;\n            return node;\n        }\n\n        /**\n         * Retrieves and removes the first node of this deque.\n         *\n         * @return removed node\n         */\n        CacheNode<K, V> pollFirst() {\n            CacheNode<K, V> node = null;\n            if (first.prev != last) {\n                node = first.prev;\n                first.prev = node.prev;\n                first.prev.next = first;\n                node.prev = null;\n                node.next = null;\n            }\n            return node;\n        }\n\n        /**\n         * Checks if link to the last node points to link to the first node.\n         *\n         * @return is deque empty\n         */\n        boolean isEmpty() {\n            return last.next == first;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRU2Cache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.function.Function;\n\n/**\n * LRU-2\n * <p>\n * When the data accessed for the first time, add it to history list. If the size of history list reaches max capacity, eliminate the earliest data (first in first out).\n * When the data already exists in the history list, and be accessed for the second time, then it will be put into cache.\n * </p>\n * TODO, consider replacing with ConcurrentHashMap to improve performance under concurrency\n */\npublic class LRU2Cache<K, V> extends LinkedHashMap<K, V> {\n\n    private static final long serialVersionUID = -5167631809472116969L;\n\n    private static final float DEFAULT_LOAD_FACTOR = 0.75f;\n    private static final int DEFAULT_MAX_CAPACITY = 1000;\n\n    private final Lock lock = new ReentrantLock();\n    private volatile int maxCapacity;\n\n    // as history list\n    private final PreCache<K, Boolean> preCache;\n\n    public LRU2Cache() {\n        this(DEFAULT_MAX_CAPACITY);\n    }\n\n    public LRU2Cache(int maxCapacity) {\n        super(16, DEFAULT_LOAD_FACTOR, true);\n        this.maxCapacity = maxCapacity;\n        this.preCache = new PreCache<>(maxCapacity);\n    }\n\n    @Override\n    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {\n        return size() > maxCapacity;\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        lock.lock();\n        try {\n            return super.containsKey(key);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public V get(Object key) {\n        lock.lock();\n        try {\n            return super.get(key);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public V put(K key, V value) {\n        lock.lock();\n        try {\n            if (preCache.containsKey(key)) {\n                // add it to cache\n                preCache.remove(key);\n                return super.put(key, value);\n            } else {\n                // add it to history list\n                preCache.put(key, true);\n                return value;\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public V computeIfAbsent(K key, Function<? super K, ? extends V> fn) {\n        V value = get(key);\n        if (value == null) {\n            value = fn.apply(key);\n            put(key, value);\n        }\n        return value;\n    }\n\n    @Override\n    public V remove(Object key) {\n        lock.lock();\n        try {\n            preCache.remove(key);\n            return super.remove(key);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public int size() {\n        lock.lock();\n        try {\n            return super.size();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public void clear() {\n        lock.lock();\n        try {\n            preCache.clear();\n            super.clear();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public int getMaxCapacity() {\n        return maxCapacity;\n    }\n\n    public void setMaxCapacity(int maxCapacity) {\n        lock.lock();\n        try {\n            this.maxCapacity = maxCapacity;\n            preCache.setMaxCapacity(maxCapacity);\n            trimMainCache();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    private void trimMainCache() {\n        while (super.size() > maxCapacity) {\n            Iterator<Map.Entry<K, V>> it = super.entrySet().iterator();\n            if (it.hasNext()) {\n                it.next();\n                it.remove();\n            }\n        }\n    }\n\n    static class PreCache<K, V> extends LinkedHashMap<K, V> {\n\n        private volatile int maxCapacity;\n\n        public PreCache() {\n            this(DEFAULT_MAX_CAPACITY);\n        }\n\n        public PreCache(int maxCapacity) {\n            super(16, DEFAULT_LOAD_FACTOR, true);\n            this.maxCapacity = maxCapacity;\n        }\n\n        @Override\n        protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {\n            return size() > maxCapacity;\n        }\n\n        public void setMaxCapacity(int maxCapacity) {\n            this.maxCapacity = maxCapacity;\n            trimToSize();\n        }\n\n        private void trimToSize() {\n            while (super.size() > maxCapacity) {\n                Iterator<Map.Entry<K, V>> it = super.entrySet().iterator();\n                if (it.hasNext()) {\n                    it.next();\n                    it.remove();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRUCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.function.Function;\n\n/**\n * A 'least recently used' cache based on LinkedHashMap.\n *\n * @param <K> key\n * @param <V> value\n */\npublic class LRUCache<K, V> extends LinkedHashMap<K, V> {\n\n    private static final long serialVersionUID = -5167631809472116969L;\n\n    private static final float DEFAULT_LOAD_FACTOR = 0.75f;\n    private static final int DEFAULT_MAX_CAPACITY = 1000;\n\n    private final Lock lock = new ReentrantLock();\n    private volatile int maxCapacity;\n\n    public LRUCache() {\n        this(DEFAULT_MAX_CAPACITY);\n    }\n\n    public LRUCache(int maxCapacity) {\n        super(16, DEFAULT_LOAD_FACTOR, true);\n        this.maxCapacity = maxCapacity;\n    }\n\n    @Override\n    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {\n        return size() > maxCapacity;\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        lock.lock();\n        try {\n            return super.containsKey(key);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public V get(Object key) {\n        lock.lock();\n        try {\n            return super.get(key);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public V put(K key, V value) {\n        lock.lock();\n        try {\n            return super.put(key, value);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public V remove(Object key) {\n        lock.lock();\n        try {\n            return super.remove(key);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public int size() {\n        lock.lock();\n        try {\n            return super.size();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public void clear() {\n        lock.lock();\n        try {\n            super.clear();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public V putIfAbsent(K key, V value) {\n        lock.lock();\n        try {\n            return super.putIfAbsent(key, value);\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public V computeIfAbsent(K key, Function<? super K, ? extends V> fn) {\n        V value = get(key);\n        if (value == null) {\n            lock.lock();\n            try {\n                return super.computeIfAbsent(key, fn);\n            } finally {\n                lock.unlock();\n            }\n        }\n        return value;\n    }\n\n    public void lock() {\n        lock.lock();\n    }\n\n    public void releaseLock() {\n        lock.unlock();\n    }\n\n    public int getMaxCapacity() {\n        return maxCapacity;\n    }\n\n    public void setMaxCapacity(int maxCapacity) {\n        lock.lock();\n        try {\n            this.maxCapacity = maxCapacity;\n            trimToSize();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    private void trimToSize() {\n        while (super.size() > maxCapacity) {\n            Iterator<Map.Entry<K, V>> it = super.entrySet().iterator();\n            if (it.hasNext()) {\n                it.next();\n                it.remove();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/LockUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.locks.Lock;\n\npublic class LockUtils {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(LockUtils.class);\n\n    public static final int DEFAULT_TIMEOUT = 60_000;\n\n    public static void safeLock(Lock lock, int timeout, Runnable runnable) {\n        try {\n            boolean interrupted = false;\n            try {\n                if (!lock.tryLock(timeout, TimeUnit.MILLISECONDS)) {\n                    logger.error(\n                            LoggerCodeConstants.INTERNAL_ERROR,\n                            \"\",\n                            \"\",\n                            \"Try to lock failed, timeout: \" + timeout,\n                            new TimeoutException());\n                }\n            } catch (InterruptedException e) {\n                logger.warn(LoggerCodeConstants.INTERNAL_ERROR, \"\", \"\", \"Try to lock failed\", e);\n                interrupted = true;\n            }\n            runnable.run();\n            if (interrupted) {\n                Thread.currentThread().interrupt();\n            }\n        } finally {\n            try {\n                lock.unlock();\n            } catch (Exception e) {\n                // ignore\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/Log.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.Level;\n\nimport java.io.Serializable;\n\npublic class Log implements Serializable {\n    private static final long serialVersionUID = -534113138054377073L;\n    private String logName;\n    private Level logLevel;\n    private String logMessage;\n    private String logThread;\n\n    public String getLogName() {\n        return logName;\n    }\n\n    public void setLogName(String logName) {\n        this.logName = logName;\n    }\n\n    public Level getLogLevel() {\n        return logLevel;\n    }\n\n    public void setLogLevel(Level logLevel) {\n        this.logLevel = logLevel;\n    }\n\n    public String getLogMessage() {\n        return logMessage;\n    }\n\n    public void setLogMessage(String logMessage) {\n        this.logMessage = logMessage;\n    }\n\n    public String getLogThread() {\n        return logThread;\n    }\n\n    public void setLogThread(String logThread) {\n        this.logThread = logThread;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((logLevel == null) ? 0 : logLevel.hashCode());\n        result = prime * result + ((logMessage == null) ? 0 : logMessage.hashCode());\n        result = prime * result + ((logName == null) ? 0 : logName.hashCode());\n        result = prime * result + ((logThread == null) ? 0 : logThread.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        Log other = (Log) obj;\n        if (logLevel == null) {\n            if (other.logLevel != null) {\n                return false;\n            }\n        } else if (!logLevel.equals(other.logLevel)) {\n            return false;\n        }\n        if (logMessage == null) {\n            if (other.logMessage != null) {\n                return false;\n            }\n        } else if (!logMessage.equals(other.logMessage)) {\n            return false;\n        }\n        if (logName == null) {\n            if (other.logName != null) {\n                return false;\n            }\n        } else if (!logName.equals(other.logName)) {\n            return false;\n        }\n        if (logThread == null) {\n            if (other.logThread != null) {\n                return false;\n            }\n        } else if (!logThread.equals(other.logThread)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/LogHelper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.Logger;\n\npublic class LogHelper {\n\n    private LogHelper() {}\n\n    public static void trace(Logger logger, String msg) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isTraceEnabled()) {\n            logger.trace(msg);\n        }\n    }\n\n    public static void trace(Logger logger, Throwable throwable) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isTraceEnabled()) {\n            logger.trace(throwable);\n        }\n    }\n\n    public static void trace(Logger logger, String msg, Throwable e) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isTraceEnabled()) {\n            logger.trace(msg, e);\n        }\n    }\n\n    public static void debug(Logger logger, String msg) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(msg);\n        }\n    }\n\n    public static void debug(Logger logger, Throwable e) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(e);\n        }\n    }\n\n    public static void debug(Logger logger, String msg, Throwable e) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(msg, e);\n        }\n    }\n\n    public static void info(Logger logger, String msg) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isInfoEnabled()) {\n            logger.info(msg);\n        }\n    }\n\n    public static void info(Logger logger, Throwable e) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isInfoEnabled()) {\n            logger.info(e);\n        }\n    }\n\n    public static void info(Logger logger, String msg, Throwable e) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isInfoEnabled()) {\n            logger.info(msg, e);\n        }\n    }\n\n    public static void warn(Logger logger, String msg, Throwable e) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isWarnEnabled()) {\n            logger.warn(msg, e);\n        }\n    }\n\n    public static void warn(Logger logger, String msg) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isWarnEnabled()) {\n            logger.warn(msg);\n        }\n    }\n\n    public static void warn(Logger logger, Throwable e) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isWarnEnabled()) {\n            logger.warn(e);\n        }\n    }\n\n    public static void error(Logger logger, Throwable e) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isErrorEnabled()) {\n            logger.error(e);\n        }\n    }\n\n    public static void error(Logger logger, String msg) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isErrorEnabled()) {\n            logger.error(msg);\n        }\n    }\n\n    public static void error(Logger logger, String msg, Throwable e) {\n        if (logger == null) {\n            return;\n        }\n\n        if (logger.isErrorEnabled()) {\n            logger.error(msg, e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/LogUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.util.Iterator;\nimport java.util.List;\n\npublic class LogUtil {\n\n    private static final Logger Log = LoggerFactory.getLogger(LogUtil.class);\n\n    public static void start() {\n        DubboAppender.doStart();\n    }\n\n    public static void stop() {\n        DubboAppender.doStop();\n    }\n\n    public static boolean checkNoError() {\n        if (findLevel(Level.ERROR) == 0) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public static int findName(String expectedLogName) {\n        int count = 0;\n        List<Log> logList = DubboAppender.logList;\n        for (int i = 0; i < logList.size(); i++) {\n            String logName = logList.get(i).getLogName();\n            if (logName.contains(expectedLogName)) {\n                count++;\n            }\n        }\n        return count;\n    }\n\n    public static int findLevel(Level expectedLevel) {\n        int count = 0;\n        List<Log> logList = DubboAppender.logList;\n        for (int i = 0; i < logList.size(); i++) {\n            Level logLevel = logList.get(i).getLogLevel();\n            if (logLevel.equals(expectedLevel)) {\n                count++;\n            }\n        }\n        return count;\n    }\n\n    public static int findLevelWithThreadName(Level expectedLevel, String threadName) {\n        int count = 0;\n        List<Log> logList = DubboAppender.logList;\n        for (int i = 0; i < logList.size(); i++) {\n            Log log = logList.get(i);\n            if (log.getLogLevel().equals(expectedLevel) && log.getLogThread().equals(threadName)) {\n                count++;\n            }\n        }\n        return count;\n    }\n\n    public static int findThread(String expectedThread) {\n        int count = 0;\n        List<Log> logList = DubboAppender.logList;\n        for (int i = 0; i < logList.size(); i++) {\n            String logThread = logList.get(i).getLogThread();\n            if (logThread.contains(expectedThread)) {\n                count++;\n            }\n        }\n        return count;\n    }\n\n    public static int findMessage(String expectedMessage) {\n        int count = 0;\n        List<Log> logList = DubboAppender.logList;\n        for (int i = 0; i < logList.size(); i++) {\n            String logMessage = logList.get(i).getLogMessage();\n            if (logMessage.contains(expectedMessage)) {\n                count++;\n            }\n        }\n        return count;\n    }\n\n    public static int findMessage(Level expectedLevel, String expectedMessage) {\n        int count = 0;\n        List<Log> logList = DubboAppender.logList;\n        for (int i = 0; i < logList.size(); i++) {\n            Level logLevel = logList.get(i).getLogLevel();\n            if (logLevel.equals(expectedLevel)) {\n                String logMessage = logList.get(i).getLogMessage();\n                if (logMessage.contains(expectedMessage)) {\n                    count++;\n                }\n            }\n        }\n        return count;\n    }\n\n    public static <T> void printList(List<T> list) {\n        Log.info(\"PrintList:\");\n        Iterator<T> it = list.iterator();\n        while (it.hasNext()) {\n            Log.info(it.next().toString());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/MD5Utils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\n/**\n * MD5 util.\n */\npublic class MD5Utils {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MD5Utils.class);\n\n    private static final char[] hexDigits = {\n        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'\n    };\n\n    private MessageDigest mdInst;\n\n    public MD5Utils() {\n        try {\n            mdInst = MessageDigest.getInstance(\"MD5\");\n        } catch (NoSuchAlgorithmException e) {\n            logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"Failed to obtain md5\", e);\n        }\n    }\n\n    /**\n     * Calculation md5 value of specify string\n     *\n     * @param input\n     */\n    public String getMd5(String input) {\n        byte[] md5;\n        // MessageDigest instance is NOT thread-safe\n        synchronized (mdInst) {\n            mdInst.update(input.getBytes(UTF_8));\n            md5 = mdInst.digest();\n        }\n\n        int j = md5.length;\n        char str[] = new char[j * 2];\n        int k = 0;\n        for (int i = 0; i < j; i++) {\n            byte byte0 = md5[i];\n            str[k++] = hexDigits[byte0 >>> 4 & 0xf];\n            str[k++] = hexDigits[byte0 & 0xf];\n        }\n        return new String(str);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/MemberUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Member;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\n\n/**\n * Java Reflection {@link Member} Utilities class\n *\n * @since 2.7.6\n */\npublic interface MemberUtils {\n\n    /**\n     * check the specified {@link Member member} is static or not ?\n     *\n     * @param member {@link Member} instance, e.g, {@link Constructor}, {@link Method} or {@link Field}\n     * @return Iff <code>member</code> is static one, return <code>true</code>, or <code>false</code>\n     */\n    static boolean isStatic(Member member) {\n        return member != null && Modifier.isStatic(member.getModifiers());\n    }\n\n    /**\n     * check the specified {@link Member member} is private or not ?\n     *\n     * @param member {@link Member} instance, e.g, {@link Constructor}, {@link Method} or {@link Field}\n     * @return Iff <code>member</code> is private one, return <code>true</code>, or <code>false</code>\n     */\n    static boolean isPrivate(Member member) {\n        return member != null && Modifier.isPrivate(member.getModifiers());\n    }\n\n    /**\n     * check the specified {@link Member member} is public or not ?\n     *\n     * @param member {@link Member} instance, e.g, {@link Constructor}, {@link Method} or {@link Field}\n     * @return Iff <code>member</code> is public one, return <code>true</code>, or <code>false</code>\n     */\n    static boolean isPublic(Member member) {\n        return member != null && Modifier.isPublic(member.getModifiers());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Method;\nimport java.util.Comparator;\n\n/**\n * The Comparator class for {@link Method}, the comparison rule :\n * <ol>\n *     <li>Comparing to two {@link Method#getName() method names} {@link String#compareTo(String) lexicographically}.\n *     If equals, go to step 2</li>\n *     <li>Comparing to the count of two method parameters. If equals, go to step 3</li>\n *     <li>Comparing to the type names of methods parameter {@link String#compareTo(String) lexicographically}</li>\n * </ol>\n *\n * @since 2.7.6\n */\npublic class MethodComparator implements Comparator<Method> {\n\n    public static final MethodComparator INSTANCE = new MethodComparator();\n\n    private MethodComparator() {}\n\n    @Override\n    public int compare(Method m1, Method m2) {\n\n        if (m1.equals(m2)) {\n            return 0;\n        }\n\n        // Step 1\n        String n1 = m1.getName();\n        String n2 = m2.getName();\n        int value = n1.compareTo(n2);\n\n        if (value == 0) { // Step 2\n\n            Class[] types1 = m1.getParameterTypes();\n            Class[] types2 = m2.getParameterTypes();\n\n            value = types1.length - types2.length;\n\n            if (value == 0) { // Step 3\n                for (int i = 0; i < types1.length; i++) {\n                    value = types1[i].getName().compareTo(types2[i].getName());\n                    if (value != 0) {\n                        break;\n                    }\n                }\n            }\n        }\n\n        return Integer.compare(value, 0);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/MethodUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.rpc.model.MethodDescriptor;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.util.Elements;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.Arrays;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.function.Predicate;\n\nimport static java.util.Collections.emptyList;\nimport static java.util.Collections.unmodifiableList;\nimport static org.apache.dubbo.common.function.Streams.filterAll;\nimport static org.apache.dubbo.common.utils.ClassUtils.getAllInheritedTypes;\nimport static org.apache.dubbo.common.utils.MemberUtils.isPrivate;\nimport static org.apache.dubbo.common.utils.MemberUtils.isStatic;\nimport static org.apache.dubbo.common.utils.ReflectUtils.EMPTY_CLASS_ARRAY;\nimport static org.apache.dubbo.common.utils.ReflectUtils.resolveTypes;\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\n\n/**\n * Miscellaneous method utility methods.\n * Mainly for internal use within the framework.\n *\n * @since 2.7.2\n */\npublic interface MethodUtils {\n\n    /**\n     * Return {@code true} if the provided method is a set method.\n     * Otherwise, return {@code false}.\n     *\n     * @param method the method to check\n     * @return whether the given method is setter method\n     */\n    static boolean isSetter(Method method) {\n        return method.getName().startsWith(\"set\")\n                && !\"set\".equals(method.getName())\n                && Modifier.isPublic(method.getModifiers())\n                && method.getParameterCount() == 1\n                && ClassUtils.isPrimitive(method.getParameterTypes()[0]);\n    }\n\n    /**\n     * Return {@code true} if the provided method is a get method.\n     * Otherwise, return {@code false}.\n     *\n     * @param method the method to check\n     * @return whether the given method is getter method\n     */\n    static boolean isGetter(Method method) {\n        String name = method.getName();\n        return (name.startsWith(\"get\") || name.startsWith(\"is\"))\n                && !\"get\".equals(name)\n                && !\"is\".equals(name)\n                && !\"getClass\".equals(name)\n                && !\"getObject\".equals(name)\n                && Modifier.isPublic(method.getModifiers())\n                && method.getParameterTypes().length == 0\n                && ClassUtils.isPrimitive(method.getReturnType());\n    }\n\n    /**\n     * Return {@code true} If this method is a meta method.\n     * Otherwise, return {@code false}.\n     *\n     * @param method the method to check\n     * @return whether the given method is meta method\n     */\n    static boolean isMetaMethod(Method method) {\n        String name = method.getName();\n        if (!(name.startsWith(\"get\") || name.startsWith(\"is\"))) {\n            return false;\n        }\n        if (\"get\".equals(name)) {\n            return false;\n        }\n        if (\"getClass\".equals(name)) {\n            return false;\n        }\n        if (!Modifier.isPublic(method.getModifiers())) {\n            return false;\n        }\n        if (method.getParameterTypes().length != 0) {\n            return false;\n        }\n        if (!ClassUtils.isPrimitive(method.getReturnType())) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Check if the method is a deprecated method. The standard is whether the {@link java.lang.Deprecated} annotation is declared on the class.\n     * Return {@code true} if this annotation is present.\n     * Otherwise, return {@code false}.\n     *\n     * @param method the method to check\n     * @return whether the given method is deprecated method\n     */\n    static boolean isDeprecated(Method method) {\n        return method.getAnnotation(Deprecated.class) != null;\n    }\n\n    /**\n     * Create an instance of {@link Predicate} for {@link Method} to exclude the specified declared class\n     *\n     * @param declaredClass the declared class to exclude\n     * @return non-null\n     * @since 2.7.6\n     */\n    static Predicate<Method> excludedDeclaredClass(Class<?> declaredClass) {\n        return method -> !Objects.equals(declaredClass, method.getDeclaringClass());\n    }\n\n    /**\n     * Get all {@link Method methods} of the declared class\n     *\n     * @param declaringClass        the declared class\n     * @param includeInheritedTypes include the inherited types, e,g. super classes or interfaces\n     * @param publicOnly            only public method\n     * @param methodsToFilter       (optional) the methods to be filtered\n     * @return non-null read-only {@link List}\n     * @since 2.7.6\n     */\n    static List<Method> getMethods(\n            Class<?> declaringClass,\n            boolean includeInheritedTypes,\n            boolean publicOnly,\n            Predicate<Method>... methodsToFilter) {\n\n        if (declaringClass == null || declaringClass.isPrimitive()) {\n            return emptyList();\n        }\n\n        // All declared classes\n        List<Class<?>> declaredClasses = new LinkedList<>();\n        // Add the top declaring class\n        declaredClasses.add(declaringClass);\n        // If the super classes are resolved, all them into declaredClasses\n        if (includeInheritedTypes) {\n            declaredClasses.addAll(getAllInheritedTypes(declaringClass));\n        }\n\n        // All methods\n        List<Method> allMethods = new LinkedList<>();\n\n        for (Class<?> classToSearch : declaredClasses) {\n            Method[] methods = publicOnly ? classToSearch.getMethods() : classToSearch.getDeclaredMethods();\n            // Add the declared methods or public methods\n            for (Method method : methods) {\n                allMethods.add(method);\n            }\n        }\n\n        return unmodifiableList(filterAll(allMethods, methodsToFilter));\n    }\n\n    /**\n     * Get all declared {@link Method methods} of the declared class, excluding the inherited methods\n     *\n     * @param declaringClass  the declared class\n     * @param methodsToFilter (optional) the methods to be filtered\n     * @return non-null read-only {@link List}\n     * @see #getMethods(Class, boolean, boolean, Predicate[])\n     * @since 2.7.6\n     */\n    static List<Method> getDeclaredMethods(Class<?> declaringClass, Predicate<Method>... methodsToFilter) {\n        return getMethods(declaringClass, false, false, methodsToFilter);\n    }\n\n    /**\n     * Get all public {@link Method methods} of the declared class, including the inherited methods.\n     *\n     * @param declaringClass  the declared class\n     * @param methodsToFilter (optional) the methods to be filtered\n     * @return non-null read-only {@link List}\n     * @see #getMethods(Class, boolean, boolean, Predicate[])\n     * @since 2.7.6\n     */\n    static List<Method> getMethods(Class<?> declaringClass, Predicate<Method>... methodsToFilter) {\n        return getMethods(declaringClass, false, true, methodsToFilter);\n    }\n\n    /**\n     * Get all declared {@link Method methods} of the declared class, including the inherited methods.\n     *\n     * @param declaringClass  the declared class\n     * @param methodsToFilter (optional) the methods to be filtered\n     * @return non-null read-only {@link List}\n     * @see #getMethods(Class, boolean, boolean, Predicate[])\n     * @since 2.7.6\n     */\n    static List<Method> getAllDeclaredMethods(Class<?> declaringClass, Predicate<Method>... methodsToFilter) {\n        return getMethods(declaringClass, true, false, methodsToFilter);\n    }\n\n    /**\n     * Get all public {@link Method methods} of the declared class, including the inherited methods.\n     *\n     * @param declaringClass  the declared class\n     * @param methodsToFilter (optional) the methods to be filtered\n     * @return non-null read-only {@link List}\n     * @see #getMethods(Class, boolean, boolean, Predicate[])\n     * @since 2.7.6\n     */\n    static List<Method> getAllMethods(Class<?> declaringClass, Predicate<Method>... methodsToFilter) {\n        return getMethods(declaringClass, true, true, methodsToFilter);\n    }\n\n    //    static List<Method> getOverriderMethods(Class<?> implementationClass, Class<?>... superTypes) {\n\n    //\n\n    //    }\n\n    /**\n     * Find the {@link Method} by the the specified type and method name without the parameter types\n     *\n     * @param type       the target type\n     * @param methodName the specified method name\n     * @return if not found, return <code>null</code>\n     * @since 2.7.6\n     */\n    static Method findMethod(Class type, String methodName) {\n        return findMethod(type, methodName, EMPTY_CLASS_ARRAY);\n    }\n\n    /**\n     * Find the {@link Method} by the the specified type, method name and parameter types\n     *\n     * @param type           the target type\n     * @param methodName     the method name\n     * @param parameterTypes the parameter types\n     * @return if not found, return <code>null</code>\n     * @since 2.7.6\n     */\n    static Method findMethod(Class type, String methodName, Class<?>... parameterTypes) {\n        Method method = null;\n        try {\n            if (type != null && isNotEmpty(methodName)) {\n                method = type.getDeclaredMethod(methodName, parameterTypes);\n            }\n        } catch (NoSuchMethodException e) {\n        }\n        return method;\n    }\n\n    /**\n     * Invoke the target object and method\n     *\n     * @param object           the target object\n     * @param methodName       the method name\n     * @param methodParameters the method parameters\n     * @param <T>              the return type\n     * @return the target method's execution result\n     * @since 2.7.6\n     */\n    static <T> T invokeMethod(Object object, String methodName, Object... methodParameters) {\n        Class type = object.getClass();\n        Class[] parameterTypes = resolveTypes(methodParameters);\n        Method method = findMethod(type, methodName, parameterTypes);\n        T value = null;\n\n        if (method == null) {\n            throw new IllegalStateException(\n                    String.format(\"cannot find method %s,class: %s\", methodName, type.getName()));\n        }\n\n        try {\n            final boolean isAccessible = method.isAccessible();\n\n            if (!isAccessible) {\n                method.setAccessible(true);\n            }\n            value = (T) method.invoke(object, methodParameters);\n            method.setAccessible(isAccessible);\n        } catch (Exception e) {\n            throw new IllegalArgumentException(e);\n        }\n\n        return value;\n    }\n\n    /**\n     * Tests whether one method, as a member of a given type,\n     * overrides another method.\n     *\n     * @param overrider  the first method, possible overrider\n     * @param overridden the second method, possibly being overridden\n     * @return {@code true} if and only if the first method overrides\n     * the second\n     * @jls 8.4.8 Inheritance, Overriding, and Hiding\n     * @jls 9.4.1 Inheritance and Overriding\n     * @see Elements#overrides(ExecutableElement, ExecutableElement, TypeElement)\n     */\n    static boolean overrides(Method overrider, Method overridden) {\n\n        if (overrider == null || overridden == null) {\n            return false;\n        }\n\n        // equality comparison: If two methods are same\n        if (Objects.equals(overrider, overridden)) {\n            return false;\n        }\n\n        // Modifiers comparison: Any method must be non-static method\n        if (isStatic(overrider) || isStatic(overridden)) { //\n            return false;\n        }\n\n        // Modifiers comparison: the accessibility of any method must not be private\n        if (isPrivate(overrider) || isPrivate(overridden)) {\n            return false;\n        }\n\n        // Inheritance comparison: The declaring class of overrider must be inherit from the overridden's\n        if (!overridden.getDeclaringClass().isAssignableFrom(overrider.getDeclaringClass())) {\n            return false;\n        }\n\n        // Method comparison: must not be \"default\" method\n        if (overrider.isDefault()) {\n            return false;\n        }\n\n        // Method comparison: The method name must be equal\n        if (!Objects.equals(overrider.getName(), overridden.getName())) {\n            return false;\n        }\n\n        // Method comparison: The count of method parameters must be equal\n        if (!Objects.equals(overrider.getParameterCount(), overridden.getParameterCount())) {\n            return false;\n        }\n\n        // Method comparison: Any parameter type of overrider must equal the overridden's\n        for (int i = 0; i < overrider.getParameterCount(); i++) {\n            if (!Objects.equals(overridden.getParameterTypes()[i], overrider.getParameterTypes()[i])) {\n                return false;\n            }\n        }\n\n        // Method comparison: The return type of overrider must be inherit from the overridden's\n        if (!overridden.getReturnType().isAssignableFrom(overrider.getReturnType())) {\n            return false;\n        }\n\n        // Throwable comparison: \"throws\" Throwable list will be ignored, trust the compiler verify\n\n        return true;\n    }\n\n    /**\n     * Find the nearest overridden {@link Method method} from the inherited class\n     *\n     * @param overrider the overrider {@link Method method}\n     * @return if found, the overrider <code>method</code>, or <code>null</code>\n     */\n    static Method findNearestOverriddenMethod(Method overrider) {\n        Class<?> declaringClass = overrider.getDeclaringClass();\n        Method overriddenMethod = null;\n        for (Class<?> inheritedType : getAllInheritedTypes(declaringClass)) {\n            overriddenMethod = findOverriddenMethod(overrider, inheritedType);\n            if (overriddenMethod != null) {\n                break;\n            }\n        }\n        return overriddenMethod;\n    }\n\n    /**\n     * Find the overridden {@link Method method} from the declaring class\n     *\n     * @param overrider      the overrider {@link Method method}\n     * @param declaringClass the class that is declaring the overridden {@link Method method}\n     * @return if found, the overrider <code>method</code>, or <code>null</code>\n     */\n    static Method findOverriddenMethod(Method overrider, Class<?> declaringClass) {\n        List<Method> matchedMethods = getAllMethods(declaringClass, method -> overrides(overrider, method));\n        return matchedMethods.isEmpty() ? null : matchedMethods.get(0);\n    }\n\n    /**\n     * Extract fieldName from set/get/is method. if it's not a set/get/is method, return empty string.\n     * If method equals get/is/getClass/getObject, also return empty string.\n     *\n     * @param method method\n     * @return fieldName\n     */\n    static String extractFieldName(Method method) {\n        List<String> emptyFieldMethod = Arrays.asList(\"is\", \"get\", \"getObject\", \"getClass\");\n        String methodName = method.getName();\n        String fieldName = \"\";\n\n        if (emptyFieldMethod.contains(methodName)) {\n            return fieldName;\n        } else if (methodName.startsWith(\"get\")) {\n            fieldName = methodName.substring(\"get\".length());\n        } else if (methodName.startsWith(\"set\")) {\n            fieldName = methodName.substring(\"set\".length());\n        } else if (methodName.startsWith(\"is\")) {\n            fieldName = methodName.substring(\"is\".length());\n        } else {\n            return fieldName;\n        }\n\n        if (StringUtils.isNotEmpty(fieldName)) {\n            fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);\n        }\n\n        return fieldName;\n    }\n\n    /**\n     * Invoke and return double value.\n     *\n     * @param method method\n     * @param targetObj the object the method is invoked from\n     * @return double value\n     */\n    static double invokeAndReturnDouble(Method method, Object targetObj) {\n        try {\n            return method != null ? (double) method.invoke(targetObj) : Double.NaN;\n        } catch (Exception e) {\n            return Double.NaN;\n        }\n    }\n\n    /**\n     * Invoke and return long value.\n     *\n     * @param method method\n     * @param targetObj the object the method is invoked from\n     * @return long value\n     */\n    static long invokeAndReturnLong(Method method, Object targetObj) {\n        try {\n            return method != null ? (long) method.invoke(targetObj) : -1;\n        } catch (Exception e) {\n            return -1;\n        }\n    }\n\n    static String toShortString(Method method) {\n        StringBuilder sb = new StringBuilder(64);\n        sb.append(method.getDeclaringClass().getName());\n        sb.append('.').append(method.getName()).append('(');\n        Class<?>[] parameterTypes = method.getParameterTypes();\n        for (int i = 0, len = parameterTypes.length; i < len; i++) {\n            if (i > 0) {\n                sb.append(\", \");\n            }\n            sb.append(parameterTypes[i].getSimpleName());\n        }\n        sb.append(')');\n        return sb.toString();\n    }\n\n    static String toShortString(MethodDescriptor md) {\n        Method method = md.getMethod();\n        if (method == null) {\n            StringBuilder sb = new StringBuilder(64);\n            sb.append(md.getMethodName()).append('(');\n            Class<?>[] parameterTypes = md.getParameterClasses();\n            for (int i = 0, len = parameterTypes.length; i < len; i++) {\n                if (i > 0) {\n                    sb.append(\", \");\n                }\n                sb.append(parameterTypes[i].getSimpleName());\n            }\n            sb.append(')');\n            return sb.toString();\n        }\n        return toShortString(method);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/NamedThreadFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * InternalThreadFactory.\n */\npublic class NamedThreadFactory implements ThreadFactory {\n\n    protected static final AtomicInteger POOL_SEQ = new AtomicInteger(1);\n\n    protected final AtomicInteger mThreadNum = new AtomicInteger(1);\n\n    protected final String mPrefix;\n\n    protected final boolean mDaemon;\n\n    public NamedThreadFactory() {\n        this(\"pool-\" + POOL_SEQ.getAndIncrement(), false);\n    }\n\n    public NamedThreadFactory(String prefix) {\n        this(prefix, false);\n    }\n\n    public NamedThreadFactory(String prefix, boolean daemon) {\n        mPrefix = prefix + \"-thread-\";\n        mDaemon = daemon;\n    }\n\n    @Override\n    public Thread newThread(Runnable runnable) {\n        String name = mPrefix + mThreadNum.getAndIncrement();\n        Thread ret = new Thread(runnable, name);\n        ret.setDaemon(mDaemon);\n        return ret;\n    }\n\n    // for test\n    public AtomicInteger getThreadNum() {\n        return mThreadNum;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.logger.support.FailsafeLogger;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.io.IOException;\nimport java.net.Inet4Address;\nimport java.net.Inet6Address;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.MulticastSocket;\nimport java.net.NetworkInterface;\nimport java.net.ServerSocket;\nimport java.net.SocketException;\nimport java.net.UnknownHostException;\nimport java.util.BitSet;\nimport java.util.Enumeration;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.regex.Pattern;\nimport java.util.regex.PatternSyntaxException;\n\nimport static java.util.Collections.emptyList;\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;\nimport static org.apache.dubbo.common.utils.CollectionUtils.first;\n\n/**\n * IP and Port Helper for RPC\n */\npublic final class NetUtils {\n\n    /**\n     * Forbids instantiation.\n     */\n    private NetUtils() {\n        throw new UnsupportedOperationException(\"No instance of 'NetUtils' for you! \");\n    }\n\n    private static Logger logger;\n\n    static {\n        /*\n            DO NOT replace this logger to error type aware logger (or fail-safe logger), since its\n            logging method calls NetUtils.getLocalHost().\n\n            According to issue #4992, getLocalHost() method will be endless recursively invoked when network disconnected.\n        */\n\n        logger = LoggerFactory.getLogger(NetUtils.class);\n        if (logger instanceof FailsafeLogger) {\n            logger = ((FailsafeLogger) logger).getLogger();\n        }\n    }\n\n    // returned port range is [30000, 39999]\n    private static final int RND_PORT_START = 30000;\n    private static final int RND_PORT_RANGE = 10000;\n\n    // valid port range is (0, 65535]\n    private static final int MIN_PORT = 1;\n    private static final int MAX_PORT = 65535;\n\n    private static final Pattern ADDRESS_PATTERN = Pattern.compile(\"^\\\\d{1,3}(\\\\.\\\\d{1,3}){3}\\\\:\\\\d{1,5}$\");\n    private static final Pattern LOCAL_IP_PATTERN = Pattern.compile(\"127(\\\\.\\\\d{1,3}){3}$\");\n    private static final Pattern IP_PATTERN = Pattern.compile(\"\\\\d{1,3}(\\\\.\\\\d{1,3}){3,5}$\");\n\n    private static final Map<String, String> HOST_NAME_CACHE = new LRUCache<>(1000);\n    private static volatile InetAddress LOCAL_ADDRESS = null;\n    private static volatile Inet6Address LOCAL_ADDRESS_V6 = null;\n\n    private static final String SPLIT_IPV4_CHARACTER = \"\\\\.\";\n    private static final String SPLIT_IPV6_CHARACTER = \":\";\n\n    /**\n     * store the used port.\n     * the set used only on the synchronized method.\n     */\n    private static BitSet USED_PORT = new BitSet(65536);\n\n    private static boolean reuseAddressSupported;\n\n    static {\n        try (ServerSocket serverSocket = new ServerSocket()) {\n            serverSocket.setReuseAddress(true);\n            reuseAddressSupported = true;\n        } catch (Throwable ignored) {\n            // ignore.\n        }\n    }\n\n    public static boolean isReuseAddressSupported() {\n        return reuseAddressSupported;\n    }\n\n    public static int getRandomPort() {\n        return RND_PORT_START + ThreadLocalRandom.current().nextInt(RND_PORT_RANGE);\n    }\n\n    public static synchronized int getAvailablePort() {\n        int randomPort = getRandomPort();\n        return getAvailablePort(randomPort);\n    }\n\n    public static synchronized int getAvailablePort(int port) {\n        if (port < MIN_PORT) {\n            return MIN_PORT;\n        }\n\n        for (int i = port; i < MAX_PORT; i++) {\n            if (USED_PORT.get(i)) {\n                continue;\n            }\n            try (ServerSocket serverSocket = new ServerSocket()) {\n                if (reuseAddressSupported) {\n                    // SO_REUSEADDR should be enabled before bind.\n                    serverSocket.setReuseAddress(true);\n                }\n                serverSocket.bind(new InetSocketAddress(i));\n                USED_PORT.set(i);\n                port = i;\n                break;\n            } catch (IOException e) {\n                // continue\n            }\n        }\n        return port;\n    }\n\n    /**\n     * Check the port whether is in use in os\n     *\n     * @param port port to check\n     * @return true if it's occupied\n     */\n    public static boolean isPortInUsed(int port) {\n        try (ServerSocket serverSocket = new ServerSocket()) {\n            if (reuseAddressSupported) {\n                // SO_REUSEADDR should be enabled before bind.\n                serverSocket.setReuseAddress(true);\n            }\n            serverSocket.bind(new InetSocketAddress(port));\n            return false;\n        } catch (IOException e) {\n            // continue\n        }\n        return true;\n    }\n\n    /**\n     * Tells whether the port to test is an invalid port.\n     *\n     * @param port port to test\n     * @return true if invalid\n     * @implNote Numeric comparison only.\n     */\n    public static boolean isInvalidPort(int port) {\n        return port < MIN_PORT || port > MAX_PORT;\n    }\n\n    /**\n     * Tells whether the address to test is an invalid address.\n     *\n     * @param address address to test\n     * @return true if invalid\n     * @implNote Pattern matching only.\n     */\n    public static boolean isValidAddress(String address) {\n        return ADDRESS_PATTERN.matcher(address).matches();\n    }\n\n    public static boolean isLocalHost(String host) {\n        return host != null && (LOCAL_IP_PATTERN.matcher(host).matches() || host.equalsIgnoreCase(LOCALHOST_KEY));\n    }\n\n    public static boolean isAnyHost(String host) {\n        return ANYHOST_VALUE.equals(host);\n    }\n\n    public static boolean isInvalidLocalHost(String host) {\n        return host == null\n                || host.length() == 0\n                || host.equalsIgnoreCase(LOCALHOST_KEY)\n                || host.equals(ANYHOST_VALUE)\n                || host.startsWith(\"127.\");\n    }\n\n    public static boolean isValidLocalHost(String host) {\n        return !isInvalidLocalHost(host);\n    }\n\n    public static InetSocketAddress getLocalSocketAddress(String host, int port) {\n        return isInvalidLocalHost(host) ? new InetSocketAddress(port) : new InetSocketAddress(host, port);\n    }\n\n    static boolean isValidV4Address(InetAddress address) {\n        if (address == null || address.isLoopbackAddress() || address.isLinkLocalAddress()) {\n            return false;\n        }\n\n        String name = address.getHostAddress();\n        return (name != null\n                && IP_PATTERN.matcher(name).matches()\n                && !ANYHOST_VALUE.equals(name)\n                && !LOCALHOST_VALUE.equals(name));\n    }\n\n    /**\n     * Check if an ipv6 address\n     *\n     * @return true if it is reachable\n     */\n    static boolean isPreferIPV6Address() {\n        return Boolean.getBoolean(\"java.net.preferIPv6Addresses\");\n    }\n\n    /**\n     * normalize the ipv6 Address, convert scope name to scope id.\n     * e.g.\n     * convert\n     * fe80:0:0:0:894:aeec:f37d:23e1%en0\n     * to\n     * fe80:0:0:0:894:aeec:f37d:23e1%5\n     * <p>\n     * The %5 after ipv6 address is called scope id.\n     * see java doc of {@link Inet6Address} for more details.\n     *\n     * @param address the input address\n     * @return the normalized address, with scope id converted to int\n     */\n    static InetAddress normalizeV6Address(Inet6Address address) {\n        String addr = address.getHostAddress();\n        int i = addr.lastIndexOf('%');\n        if (i > 0) {\n            try {\n                return InetAddress.getByName(addr.substring(0, i) + '%' + address.getScopeId());\n            } catch (UnknownHostException e) {\n                // ignore\n                logger.debug(\"Unknown IPV6 address: \", e);\n            }\n        }\n        return address;\n    }\n\n    private static volatile String HOST_ADDRESS;\n\n    private static volatile String HOST_NAME;\n\n    private static volatile String HOST_ADDRESS_V6;\n\n    public static String getLocalHost() {\n        if (HOST_ADDRESS != null) {\n            return HOST_ADDRESS;\n        }\n\n        InetAddress address = getLocalAddress();\n        if (address != null) {\n            if (address instanceof Inet6Address) {\n                String ipv6AddressString = address.getHostAddress();\n                if (ipv6AddressString.contains(\"%\")) {\n                    ipv6AddressString = ipv6AddressString.substring(0, ipv6AddressString.indexOf(\"%\"));\n                }\n                HOST_ADDRESS = ipv6AddressString;\n                return HOST_ADDRESS;\n            }\n\n            HOST_ADDRESS = address.getHostAddress();\n            return HOST_ADDRESS;\n        }\n\n        return LOCALHOST_VALUE;\n    }\n\n    public static String getLocalHostV6() {\n        if (StringUtils.isNotEmpty(HOST_ADDRESS_V6)) {\n            return HOST_ADDRESS_V6;\n        }\n        // avoid to search network interface card many times\n        if (\"\".equals(HOST_ADDRESS_V6)) {\n            return null;\n        }\n\n        Inet6Address address = getLocalAddressV6();\n        if (address != null) {\n            String ipv6AddressString = address.getHostAddress();\n            if (ipv6AddressString.contains(\"%\")) {\n                ipv6AddressString = ipv6AddressString.substring(0, ipv6AddressString.indexOf(\"%\"));\n            }\n\n            HOST_ADDRESS_V6 = ipv6AddressString;\n            return HOST_ADDRESS_V6;\n        }\n        HOST_ADDRESS_V6 = \"\";\n        return null;\n    }\n\n    public static String filterLocalHost(String host) {\n        if (host == null || host.length() == 0) {\n            return host;\n        }\n        if (host.contains(\"://\")) {\n            URL u = URL.valueOf(host);\n            if (NetUtils.isInvalidLocalHost(u.getHost())) {\n                return u.setHost(NetUtils.getLocalHost()).toFullString();\n            }\n        } else if (host.contains(\":\")) {\n            int i = host.lastIndexOf(':');\n            if (NetUtils.isInvalidLocalHost(host.substring(0, i))) {\n                return NetUtils.getLocalHost() + host.substring(i);\n            }\n        } else {\n            if (NetUtils.isInvalidLocalHost(host)) {\n                return NetUtils.getLocalHost();\n            }\n        }\n        return host;\n    }\n\n    public static String getIpByConfig(ScopeModel scopeModel) {\n        String configIp = ConfigurationUtils.getProperty(scopeModel, DUBBO_IP_TO_BIND);\n        if (configIp != null) {\n            return configIp;\n        }\n\n        return getLocalHost();\n    }\n\n    /**\n     * Find first valid IP from local network card\n     *\n     * @return first valid local IP\n     */\n    public static InetAddress getLocalAddress() {\n        if (LOCAL_ADDRESS != null) {\n            return LOCAL_ADDRESS;\n        }\n        InetAddress localAddress = getLocalAddress0();\n        LOCAL_ADDRESS = localAddress;\n        return localAddress;\n    }\n\n    public static Inet6Address getLocalAddressV6() {\n        if (LOCAL_ADDRESS_V6 != null) {\n            return LOCAL_ADDRESS_V6;\n        }\n        Inet6Address localAddress = getLocalAddress0V6();\n        LOCAL_ADDRESS_V6 = localAddress;\n        return localAddress;\n    }\n\n    private static Optional<InetAddress> toValidAddress(InetAddress address) {\n        if (address instanceof Inet6Address) {\n            Inet6Address v6Address = (Inet6Address) address;\n            if (isPreferIPV6Address()) {\n                return Optional.ofNullable(normalizeV6Address(v6Address));\n            }\n        }\n        if (isValidV4Address(address)) {\n            return Optional.of(address);\n        }\n        return Optional.empty();\n    }\n\n    private static InetAddress getLocalAddress0() {\n        InetAddress localAddress = null;\n\n        // @since 2.7.6, choose the {@link NetworkInterface} first\n        try {\n            NetworkInterface networkInterface = findNetworkInterface();\n            Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();\n            while (addresses.hasMoreElements()) {\n                Optional<InetAddress> addressOp = toValidAddress(addresses.nextElement());\n                if (addressOp.isPresent()) {\n                    try {\n                        if (addressOp.get().isReachable(100)) {\n                            return addressOp.get();\n                        }\n                    } catch (IOException e) {\n                        // ignore\n                    }\n                }\n            }\n        } catch (Throwable e) {\n            logger.warn(e);\n        }\n\n        try {\n            localAddress = InetAddress.getLocalHost();\n            Optional<InetAddress> addressOp = toValidAddress(localAddress);\n            if (addressOp.isPresent()) {\n                return addressOp.get();\n            }\n        } catch (Throwable e) {\n            logger.warn(e);\n        }\n\n        localAddress = getLocalAddressV6();\n\n        return localAddress;\n    }\n\n    private static Inet6Address getLocalAddress0V6() {\n        // @since 2.7.6, choose the {@link NetworkInterface} first\n        try {\n            NetworkInterface networkInterface = findNetworkInterface();\n            Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();\n            while (addresses.hasMoreElements()) {\n                InetAddress address = addresses.nextElement();\n                if (address instanceof Inet6Address) {\n                    if (!address.isLoopbackAddress() // filter ::1\n                            && !address.isAnyLocalAddress() // filter ::/128\n                            && !address.isLinkLocalAddress() // filter fe80::/10\n                            && !address.isSiteLocalAddress() // filter fec0::/10\n                            && !isUniqueLocalAddress(address) // filter fd00::/8\n                            && address.getHostAddress().contains(\":\")) { // filter IPv6\n                        return (Inet6Address) address;\n                    }\n                }\n            }\n        } catch (Throwable e) {\n            logger.warn(e);\n        }\n\n        return null;\n    }\n\n    /**\n     * If the address is Unique Local Address.\n     *\n     * @param address {@link InetAddress}\n     * @return {@code true} if the address is Unique Local Address,otherwise {@code false}\n     */\n    private static boolean isUniqueLocalAddress(InetAddress address) {\n        byte[] ip = address.getAddress();\n        return (ip[0] & 0xff) == 0xfd;\n    }\n\n    /**\n     * Returns {@code true} if the specified {@link NetworkInterface} should be ignored with the given conditions.\n     *\n     * @param networkInterface the {@link NetworkInterface} to check\n     * @return {@code true} if the specified {@link NetworkInterface} should be ignored, otherwise {@code false}\n     * @throws SocketException SocketException if an I/O error occurs.\n     */\n    private static boolean ignoreNetworkInterface(NetworkInterface networkInterface) throws SocketException {\n        if (networkInterface == null\n                || networkInterface.isLoopback()\n                || networkInterface.isVirtual()\n                || !networkInterface.isUp()) {\n            return true;\n        }\n        if (Boolean.parseBoolean(SystemPropertyConfigUtils.getSystemProperty(\n                        CommonConstants.DubboProperty.DUBBO_NETWORK_INTERFACE_POINT_TO_POINT_IGNORED, \"false\"))\n                && networkInterface.isPointToPoint()) {\n            return true;\n        }\n        String ignoredInterfaces = SystemPropertyConfigUtils.getSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_NETWORK_IGNORED_INTERFACE);\n        String networkInterfaceDisplayName;\n        if (StringUtils.isNotEmpty(ignoredInterfaces)\n                && StringUtils.isNotEmpty(networkInterfaceDisplayName = networkInterface.getDisplayName())) {\n            for (String ignoredInterface : ignoredInterfaces.split(\",\")) {\n                String trimIgnoredInterface = ignoredInterface.trim();\n                boolean matched = false;\n                try {\n                    matched = networkInterfaceDisplayName.matches(trimIgnoredInterface);\n                } catch (PatternSyntaxException e) {\n                    // if trimIgnoredInterface is an invalid regular expression, a PatternSyntaxException will be thrown\n                    // out\n                    logger.warn(\n                            \"exception occurred: \" + networkInterfaceDisplayName + \" matches \" + trimIgnoredInterface,\n                            e);\n                } finally {\n                    if (matched) {\n                        return true;\n                    }\n                    if (networkInterfaceDisplayName.equals(trimIgnoredInterface)) {\n                        return true;\n                    }\n                }\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Get the valid {@link NetworkInterface network interfaces}\n     *\n     * @return the valid {@link NetworkInterface}s\n     * @throws SocketException SocketException if an I/O error occurs.\n     * @since 2.7.6\n     */\n    private static List<NetworkInterface> getValidNetworkInterfaces() throws SocketException {\n        List<NetworkInterface> validNetworkInterfaces = new LinkedList<>();\n        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();\n        while (interfaces.hasMoreElements()) {\n            NetworkInterface networkInterface = interfaces.nextElement();\n            if (ignoreNetworkInterface(networkInterface)) { // ignore\n                continue;\n            }\n            validNetworkInterfaces.add(networkInterface);\n        }\n        return validNetworkInterfaces;\n    }\n\n    /**\n     * Is preferred {@link NetworkInterface} or not\n     *\n     * @param networkInterface {@link NetworkInterface}\n     * @return if the name of the specified {@link NetworkInterface} matches\n     * the property value from {@link CommonConstants.DubboProperty#DUBBO_PREFERRED_NETWORK_INTERFACE}, return <code>true</code>,\n     * or <code>false</code>\n     */\n    public static boolean isPreferredNetworkInterface(NetworkInterface networkInterface) {\n        String preferredNetworkInterface = SystemPropertyConfigUtils.getSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFERRED_NETWORK_INTERFACE);\n        return Objects.equals(networkInterface.getDisplayName(), preferredNetworkInterface);\n    }\n\n    /**\n     * Get the suitable {@link NetworkInterface}\n     *\n     * @return If no {@link NetworkInterface} is available , return <code>null</code>\n     * @since 2.7.6\n     */\n    public static NetworkInterface findNetworkInterface() {\n\n        List<NetworkInterface> validNetworkInterfaces = emptyList();\n        try {\n            validNetworkInterfaces = getValidNetworkInterfaces();\n        } catch (Throwable e) {\n            logger.warn(e);\n        }\n\n        NetworkInterface result = null;\n\n        // Try to find the preferred one\n        for (NetworkInterface networkInterface : validNetworkInterfaces) {\n            if (isPreferredNetworkInterface(networkInterface)) {\n                result = networkInterface;\n                break;\n            }\n        }\n\n        if (result == null) { // If not found, try to get the first one\n            for (NetworkInterface networkInterface : validNetworkInterfaces) {\n                Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();\n                while (addresses.hasMoreElements()) {\n                    Optional<InetAddress> addressOp = toValidAddress(addresses.nextElement());\n                    if (addressOp.isPresent()) {\n                        try {\n                            if (addressOp.get().isReachable(100)) {\n                                if (addressOp.get().isSiteLocalAddress()) {\n                                    return networkInterface;\n                                } else {\n                                    result = networkInterface;\n                                }\n                            }\n                        } catch (IOException e) {\n                            // ignore\n                        }\n                    }\n                }\n            }\n        }\n\n        if (result == null) {\n            result = first(validNetworkInterfaces);\n        }\n\n        return result;\n    }\n\n    public static String getHostName(String address) {\n        try {\n            int i = address.indexOf(':');\n            if (i > -1) {\n                address = address.substring(0, i);\n            }\n            String hostname = HOST_NAME_CACHE.get(address);\n            if (hostname != null && hostname.length() > 0) {\n                return hostname;\n            }\n            InetAddress inetAddress = InetAddress.getByName(address);\n            if (inetAddress != null) {\n                hostname = inetAddress.getHostName();\n                HOST_NAME_CACHE.put(address, hostname);\n                return hostname;\n            }\n        } catch (Throwable e) {\n            // ignore\n        }\n        return address;\n    }\n\n    public static String getLocalHostName() {\n        if (HOST_NAME != null) {\n            return HOST_NAME;\n        }\n        try {\n            HOST_NAME = InetAddress.getLocalHost().getHostName();\n        } catch (UnknownHostException e) {\n            HOST_NAME = Optional.ofNullable(getLocalAddress())\n                    .map(k -> k.getHostName())\n                    .orElse(null);\n        }\n        return HOST_NAME;\n    }\n\n    /**\n     * @param hostName\n     * @return ip address or hostName if UnknownHostException\n     */\n    public static String getIpByHost(String hostName) {\n        try {\n            return InetAddress.getByName(hostName).getHostAddress();\n        } catch (UnknownHostException e) {\n            return hostName;\n        }\n    }\n\n    public static String toAddressString(InetSocketAddress address) {\n        return address.getAddress().getHostAddress() + \":\" + address.getPort();\n    }\n\n    public static InetSocketAddress toAddress(String address) {\n        int i = address.indexOf(':');\n        String host;\n        int port;\n        if (i > -1) {\n            host = address.substring(0, i);\n            port = Integer.parseInt(address.substring(i + 1));\n        } else {\n            host = address;\n            port = 0;\n        }\n        return new InetSocketAddress(host, port);\n    }\n\n    public static String toURL(String protocol, String host, int port, String path) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(protocol).append(\"://\");\n        sb.append(host).append(':').append(port);\n        if (path.charAt(0) != '/') {\n            sb.append('/');\n        }\n        sb.append(path);\n        return sb.toString();\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static void joinMulticastGroup(MulticastSocket multicastSocket, InetAddress multicastAddress)\n            throws IOException {\n        setInterface(multicastSocket, multicastAddress instanceof Inet6Address);\n\n        // For the deprecation notice: the equivalent only appears in JDK 9+.\n        multicastSocket.setLoopbackMode(false);\n        multicastSocket.joinGroup(multicastAddress);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static void setInterface(MulticastSocket multicastSocket, boolean preferIpv6) throws IOException {\n        boolean interfaceSet = false;\n        for (NetworkInterface networkInterface : getValidNetworkInterfaces()) {\n            Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();\n\n            while (addresses.hasMoreElements()) {\n                InetAddress address = addresses.nextElement();\n                if (preferIpv6 && address instanceof Inet6Address) {\n                    try {\n                        if (address.isReachable(100)) {\n                            multicastSocket.setInterface(address);\n                            interfaceSet = true;\n                            break;\n                        }\n                    } catch (IOException e) {\n                        // ignore\n                    }\n                } else if (!preferIpv6 && address instanceof Inet4Address) {\n                    try {\n                        if (address.isReachable(100)) {\n                            multicastSocket.setInterface(address);\n                            interfaceSet = true;\n                            break;\n                        }\n                    } catch (IOException e) {\n                        // ignore\n                    }\n                }\n            }\n            if (interfaceSet) {\n                break;\n            }\n        }\n    }\n\n    /**\n     * Check if address matches with specified pattern, currently only supports ipv4, use {@link this#matchIpExpression(String, String, int)} for ipv6 addresses.\n     *\n     * @param pattern cird pattern\n     * @param address 'ip:port'\n     * @return true if address matches with the pattern\n     */\n    public static boolean matchIpExpression(String pattern, String address) throws UnknownHostException {\n        if (address == null) {\n            return false;\n        }\n\n        String host = address;\n        int port = 0;\n        // only works for ipv4 address with 'ip:port' format\n        if (address.endsWith(\":\")) {\n            String[] hostPort = address.split(\":\");\n            host = hostPort[0];\n            port = StringUtils.parseInteger(hostPort[1]);\n        }\n\n        // if the pattern is subnet format, it will not be allowed to config port param in pattern.\n        if (pattern.contains(\"/\")) {\n            CIDRUtils utils = new CIDRUtils(pattern);\n            return utils.isInRange(host);\n        }\n\n        return matchIpRange(pattern, host, port);\n    }\n\n    public static boolean matchIpExpression(String pattern, String host, int port) throws UnknownHostException {\n\n        // if the pattern is subnet format, it will not be allowed to config port param in pattern.\n        if (pattern.contains(\"/\")) {\n            CIDRUtils utils = new CIDRUtils(pattern);\n            return utils.isInRange(host);\n        }\n\n        return matchIpRange(pattern, host, port);\n    }\n\n    /**\n     * @param pattern\n     * @param host\n     * @param port\n     * @return\n     * @throws UnknownHostException\n     */\n    public static boolean matchIpRange(String pattern, String host, int port) throws UnknownHostException {\n        if (pattern == null || host == null) {\n            throw new IllegalArgumentException(\n                    \"Illegal Argument pattern or hostName. Pattern:\" + pattern + \", Host:\" + host);\n        }\n        pattern = pattern.trim();\n        if (\"*.*.*.*\".equals(pattern) || \"*\".equals(pattern)) {\n            return true;\n        }\n\n        InetAddress inetAddress = InetAddress.getByName(host);\n        boolean isIpv4 = isValidV4Address(inetAddress);\n        String[] hostAndPort = getPatternHostAndPort(pattern, isIpv4);\n        if (hostAndPort[1] != null && !hostAndPort[1].equals(String.valueOf(port))) {\n            return false;\n        }\n        pattern = hostAndPort[0];\n\n        String splitCharacter = SPLIT_IPV4_CHARACTER;\n        if (!isIpv4) {\n            splitCharacter = SPLIT_IPV6_CHARACTER;\n        }\n        String[] mask = pattern.split(splitCharacter);\n        // check format of pattern\n        checkHostPattern(pattern, mask, isIpv4);\n\n        host = inetAddress.getHostAddress();\n        if (pattern.equals(host)) {\n            return true;\n        }\n\n        // short name condition\n        if (!ipPatternContainExpression(pattern)) {\n            InetAddress patternAddress = InetAddress.getByName(pattern);\n            return patternAddress.getHostAddress().equals(host);\n        }\n\n        String[] ipAddress = host.split(splitCharacter);\n\n        for (int i = 0; i < mask.length; i++) {\n            if (\"*\".equals(mask[i]) || mask[i].equals(ipAddress[i])) {\n                continue;\n            } else if (mask[i].contains(\"-\")) {\n                String[] rangeNumStrs = StringUtils.split(mask[i], '-');\n                if (rangeNumStrs.length != 2) {\n                    throw new IllegalArgumentException(\"There is wrong format of ip Address: \" + mask[i]);\n                }\n                Integer min = getNumOfIpSegment(rangeNumStrs[0], isIpv4);\n                Integer max = getNumOfIpSegment(rangeNumStrs[1], isIpv4);\n                Integer ip = getNumOfIpSegment(ipAddress[i], isIpv4);\n                if (ip < min || ip > max) {\n                    return false;\n                }\n            } else if (\"0\".equals(ipAddress[i])\n                    && (\"0\".equals(mask[i])\n                            || \"00\".equals(mask[i])\n                            || \"000\".equals(mask[i])\n                            || \"0000\".equals(mask[i]))) {\n                continue;\n            } else if (!mask[i].equals(ipAddress[i])) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * is multicast address or not\n     *\n     * @param host ipv4 address\n     * @return {@code true} if is multicast address\n     */\n    public static boolean isMulticastAddress(String host) {\n        int i = host.indexOf('.');\n        if (i > 0) {\n            String prefix = host.substring(0, i);\n            if (StringUtils.isNumber(prefix)) {\n                int p = Integer.parseInt(prefix);\n                return p >= 224 && p <= 239;\n            }\n        }\n        return false;\n    }\n\n    private static boolean ipPatternContainExpression(String pattern) {\n        return pattern.contains(\"*\") || pattern.contains(\"-\");\n    }\n\n    private static void checkHostPattern(String pattern, String[] mask, boolean isIpv4) {\n        if (!isIpv4) {\n            if (mask.length != 8 && ipPatternContainExpression(pattern)) {\n                throw new IllegalArgumentException(\n                        \"If you config ip expression that contains '*' or '-', please fill qualified ip pattern like 234e:0:4567:0:0:0:3d:*. \");\n            }\n            if (mask.length != 8 && !pattern.contains(\"::\")) {\n                throw new IllegalArgumentException(\n                        \"The host is ipv6, but the pattern is not ipv6 pattern : \" + pattern);\n            }\n        } else {\n            if (mask.length != 4) {\n                throw new IllegalArgumentException(\n                        \"The host is ipv4, but the pattern is not ipv4 pattern : \" + pattern);\n            }\n        }\n    }\n\n    private static String[] getPatternHostAndPort(String pattern, boolean isIpv4) {\n        String[] result = new String[2];\n        if (pattern.startsWith(\"[\") && pattern.contains(\"]:\")) {\n            int end = pattern.indexOf(\"]:\");\n            result[0] = pattern.substring(1, end);\n            result[1] = pattern.substring(end + 2);\n            return result;\n        } else if (pattern.startsWith(\"[\") && pattern.endsWith(\"]\")) {\n            result[0] = pattern.substring(1, pattern.length() - 1);\n            result[1] = null;\n            return result;\n        } else if (isIpv4 && pattern.contains(\":\")) {\n            int end = pattern.indexOf(\":\");\n            result[0] = pattern.substring(0, end);\n            result[1] = pattern.substring(end + 1);\n            return result;\n        } else {\n            result[0] = pattern;\n            return result;\n        }\n    }\n\n    private static Integer getNumOfIpSegment(String ipSegment, boolean isIpv4) {\n        if (isIpv4) {\n            return Integer.parseInt(ipSegment);\n        }\n        return Integer.parseInt(ipSegment, 16);\n    }\n\n    public static boolean isIPV6URLStdFormat(String ip) {\n        if ((ip.charAt(0) == '[' && ip.indexOf(']') > 2)) {\n            return true;\n        } else if (ip.indexOf(\":\") != ip.lastIndexOf(\":\")) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public static String getLegalIP(String ip) {\n        // ipv6 [::FFFF:129.144.52.38]:80\n        int ind;\n        if ((ip.charAt(0) == '[' && (ind = ip.indexOf(']')) > 2)) {\n            String nhost = ip;\n            ip = nhost.substring(0, ind + 1);\n            ip = ip.substring(1, ind);\n            return ip;\n        } else {\n            return ip;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/Page.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.List;\n\n/**\n * The model class of pagination\n *\n * @since 2.7.5\n */\npublic interface Page<T> {\n\n    /**\n     * Gets the offset of request\n     *\n     * @return positive integer\n     */\n    int getOffset();\n\n    /**\n     * Gets the size of request for pagination query\n     *\n     * @return positive integer\n     */\n    int getPageSize();\n\n    /**\n     * Gets the total amount of elements.\n     *\n     * @return the total amount of elements\n     */\n    int getTotalSize();\n\n    /**\n     * Get the number of total pages.\n     *\n     * @return the number of total pages.\n     */\n    int getTotalPages();\n\n    /**\n     * The data of current page\n     *\n     * @return non-null {@link List}\n     */\n    List<T> getData();\n\n    /**\n     * The size of {@link #getData() data}\n     *\n     * @return positive integer\n     */\n    default int getDataSize() {\n        return getData().size();\n    }\n\n    /**\n     * It indicates has next page or not\n     *\n     * @return if has , return <code>true</code>, or <code>false</code>\n     */\n    boolean hasNext();\n\n    /**\n     * Returns whether the page has data at all.\n     *\n     * @return\n     */\n    default boolean hasData() {\n        return getDataSize() > 0;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/Pair.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\npublic final class Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @SuppressWarnings(\"rawtypes\")\n    private static final Pair NULL = new Pair<>(null, null);\n\n    private final L left;\n    private final R right;\n\n    public static <L, R> Pair<L, R> of(L left, R right) {\n        return left == null && right == null ? nullPair() : new Pair<>(left, right);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <L, R> Pair<L, R> nullPair() {\n        return NULL;\n    }\n\n    @SafeVarargs\n    public static <L, R> Map<L, R> toMap(Pair<L, R>... pairs) {\n        if (pairs == null) {\n            return Collections.emptyMap();\n        }\n        return toMap(Arrays.asList(pairs));\n    }\n\n    public static <L, R> Map<L, R> toMap(Collection<Pair<L, R>> pairs) {\n        if (pairs == null) {\n            return Collections.emptyMap();\n        }\n        Map<L, R> map = CollectionUtils.newLinkedHashMap(pairs.size());\n        for (Pair<L, R> pair : pairs) {\n            map.put(pair.getLeft(), pair.getRight());\n        }\n        return map;\n    }\n\n    public static <L, R> List<Pair<L, R>> toPairs(Map<L, R> map) {\n        if (map == null) {\n            return Collections.emptyList();\n        }\n        List<Pair<L, R>> pairs = new ArrayList<>(map.size());\n        for (Map.Entry<L, R> entry : map.entrySet()) {\n            pairs.add(of(entry.getKey(), entry.getValue()));\n        }\n        return pairs;\n    }\n\n    public Pair(L left, R right) {\n        this.left = left;\n        this.right = right;\n    }\n\n    public L getLeft() {\n        return left;\n    }\n\n    public R getRight() {\n        return right;\n    }\n\n    public boolean isNull() {\n        return this == NULL || left == null && right == null;\n    }\n\n    @Override\n    public L getKey() {\n        return left;\n    }\n\n    @Override\n    public R getValue() {\n        return right;\n    }\n\n    @Override\n    public R setValue(R value) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public int compareTo(Pair<L, R> other) {\n        return left.equals(other.left)\n                ? ((Comparable<R>) right).compareTo(other.right)\n                : ((Comparable<L>) left).compareTo(other.left);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(left) ^ Objects.hashCode(right);\n    }\n\n    @Override\n    public boolean equals(Object other) {\n        if (this == other) {\n            return true;\n        }\n        if (other instanceof Map.Entry) {\n            Map.Entry<?, ?> that = (Map.Entry<?, ?>) other;\n            return Objects.equals(left, that.getKey()) && Objects.equals(right, that.getValue());\n        }\n        return false;\n    }\n\n    @Override\n    public String toString() {\n        return \"(\" + left + \", \" + right + ')';\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ParameterNameReader.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface ParameterNameReader {\n\n    String[] readParameterNames(Method method);\n\n    String[] readParameterNames(Constructor<?> ctor);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/PathUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.utils.StringUtils.QUESTION_MASK;\nimport static org.apache.dubbo.common.utils.StringUtils.SLASH;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\nimport static org.apache.dubbo.common.utils.StringUtils.replace;\n\n/**\n * Path Utilities class\n *\n * @since 2.7.6\n */\npublic interface PathUtils {\n\n    static String buildPath(String rootPath, String... subPaths) {\n\n        Set<String> paths = new LinkedHashSet<>();\n        paths.add(rootPath);\n        paths.addAll(asList(subPaths));\n\n        return normalize(paths.stream().filter(StringUtils::isNotEmpty).collect(Collectors.joining(SLASH)));\n    }\n\n    /**\n     * Normalize path:\n     * <ol>\n     * <li>To remove query string if presents</li>\n     * <li>To remove duplicated slash(\"/\") if exists</li>\n     * </ol>\n     *\n     * @param path path to be normalized\n     * @return a normalized path if required\n     */\n    static String normalize(String path) {\n        if (isEmpty(path)) {\n            return SLASH;\n        }\n        String normalizedPath = path;\n        int index = normalizedPath.indexOf(QUESTION_MASK);\n        if (index > -1) {\n            normalizedPath = normalizedPath.substring(0, index);\n        }\n\n        while (normalizedPath.contains(\"//\")) {\n            normalizedPath = replace(normalizedPath, \"//\", \"/\");\n        }\n        return normalizedPath;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.GenericArrayType;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Proxy;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.lang.reflect.WildcardType;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.IdentityHashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Properties;\nimport java.util.TreeMap;\nimport java.util.WeakHashMap;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ConcurrentSkipListMap;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_REFLECTIVE_OPERATION_FAILED;\nimport static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom;\n\n/**\n * PojoUtils. Travel object deeply, and convert complex type to simple type.\n * <p/>\n * Simple type below will be remained:\n * <ul>\n * <li> Primitive Type, also include <b>String</b>, <b>Number</b>(Integer, Long), <b>Date</b>\n * <li> Array of Primitive Type\n * <li> Collection, eg: List, Map, Set etc.\n * </ul>\n * <p/>\n * Other type will be covert to a map which contains the attributes and value pair of object.\n * <p>\n * TODO: exact PojoUtils to scope bean\n */\npublic class PojoUtils {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(PojoUtils.class);\n    private static final ConcurrentMap<String, Method> NAME_METHODS_CACHE = new ConcurrentHashMap<>();\n    private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Field>> CLASS_FIELD_CACHE =\n            new ConcurrentHashMap<>();\n\n    private static final ConcurrentMap<String, Object> CLASS_NOT_FOUND_CACHE = new ConcurrentHashMap<>();\n\n    private static final Object NOT_FOUND_VALUE = new Object();\n    private static final boolean GENERIC_WITH_CLZ = Boolean.parseBoolean(ConfigurationUtils.getProperty(\n            ApplicationModel.defaultModel(), CommonConstants.GENERIC_WITH_CLZ_KEY, \"true\"));\n\n    private static final List<Class<?>> CLASS_CAN_BE_STRING = Arrays.asList(\n            Byte.class,\n            Short.class,\n            Integer.class,\n            Long.class,\n            Float.class,\n            Double.class,\n            Boolean.class,\n            Character.class);\n\n    public static Object[] generalize(Object[] objs) {\n        Object[] dests = new Object[objs.length];\n        for (int i = 0; i < objs.length; i++) {\n            dests[i] = generalize(objs[i]);\n        }\n        return dests;\n    }\n\n    public static Object[] realize(Object[] objs, Class<?>[] types) {\n        if (objs.length != types.length) {\n            throw new IllegalArgumentException(\"args.length != types.length\");\n        }\n\n        Object[] dests = new Object[objs.length];\n        for (int i = 0; i < objs.length; i++) {\n            dests[i] = realize(objs[i], types[i]);\n        }\n\n        return dests;\n    }\n\n    public static Object[] realize(Object[] objs, Class<?>[] types, Type[] gtypes) {\n        if (objs.length != types.length || objs.length != gtypes.length) {\n            throw new IllegalArgumentException(\"args.length != types.length\");\n        }\n        Object[] dests = new Object[objs.length];\n        for (int i = 0; i < objs.length; i++) {\n            dests[i] = realize(objs[i], types[i], gtypes[i]);\n        }\n        return dests;\n    }\n\n    public static Object generalize(Object pojo) {\n        return generalize(pojo, new IdentityHashMap<>());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static Object generalize(Object pojo, Map<Object, Object> history) {\n        if (pojo == null) {\n            return null;\n        }\n\n        if (pojo instanceof Enum<?>) {\n            return ((Enum<?>) pojo).name();\n        }\n        if (pojo.getClass().isArray()\n                && Enum.class.isAssignableFrom(pojo.getClass().getComponentType())) {\n            int len = Array.getLength(pojo);\n            String[] values = new String[len];\n            for (int i = 0; i < len; i++) {\n                values[i] = ((Enum<?>) Array.get(pojo, i)).name();\n            }\n            return values;\n        }\n\n        if (ReflectUtils.isPrimitives(pojo.getClass())) {\n            return pojo;\n        }\n\n        if (pojo instanceof LocalDate || pojo instanceof LocalDateTime || pojo instanceof LocalTime) {\n            return pojo.toString();\n        }\n\n        if (pojo instanceof Class) {\n            return ((Class) pojo).getName();\n        }\n\n        Object o = history.get(pojo);\n        if (o != null) {\n            return o;\n        }\n        history.put(pojo, pojo);\n\n        if (pojo.getClass().isArray()) {\n            int len = Array.getLength(pojo);\n            Object[] dest = new Object[len];\n            history.put(pojo, dest);\n            for (int i = 0; i < len; i++) {\n                Object obj = Array.get(pojo, i);\n                dest[i] = generalize(obj, history);\n            }\n            return dest;\n        }\n        if (pojo instanceof Collection<?>) {\n            Collection<Object> src = (Collection<Object>) pojo;\n            int len = src.size();\n            Collection<Object> dest = (pojo instanceof List<?>) ? new ArrayList<>(len) : new HashSet<>(len);\n            history.put(pojo, dest);\n            for (Object obj : src) {\n                dest.add(generalize(obj, history));\n            }\n            return dest;\n        }\n        if (pojo instanceof Map<?, ?>) {\n            Map<Object, Object> src = (Map<Object, Object>) pojo;\n            Map<Object, Object> dest = createMap(src);\n            history.put(pojo, dest);\n            for (Map.Entry<Object, Object> obj : src.entrySet()) {\n                dest.put(generalize(obj.getKey(), history), generalize(obj.getValue(), history));\n            }\n            return dest;\n        }\n        Map<String, Object> map = new HashMap<>();\n        history.put(pojo, map);\n        if (GENERIC_WITH_CLZ) {\n            map.put(\"class\", pojo.getClass().getName());\n        }\n        for (Method method : pojo.getClass().getMethods()) {\n            if (ReflectUtils.isBeanPropertyReadMethod(method)) {\n                ReflectUtils.makeAccessible(method);\n                try {\n                    map.put(\n                            ReflectUtils.getPropertyNameFromBeanReadMethod(method),\n                            generalize(method.invoke(pojo), history));\n                } catch (Exception e) {\n                    throw new RuntimeException(e.getMessage(), e);\n                }\n            }\n        }\n        // public field\n        for (Field field : pojo.getClass().getFields()) {\n            if (ReflectUtils.isPublicInstanceField(field)) {\n                try {\n                    Object fieldValue = field.get(pojo);\n                    if (history.containsKey(pojo)) {\n                        Object pojoGeneralizedValue = history.get(pojo);\n                        if (pojoGeneralizedValue instanceof Map\n                                && ((Map) pojoGeneralizedValue).containsKey(field.getName())) {\n                            continue;\n                        }\n                    }\n                    if (fieldValue != null) {\n                        map.put(field.getName(), generalize(fieldValue, history));\n                    }\n                } catch (Exception e) {\n                    throw new RuntimeException(e.getMessage(), e);\n                }\n            }\n        }\n        return map;\n    }\n\n    public static Object realize(Object pojo, Class<?> type) {\n        return realize0(pojo, type, null, new IdentityHashMap<>());\n    }\n\n    public static Object realize(Object pojo, Class<?> type, Type genericType) {\n        return realize0(pojo, type, genericType, new IdentityHashMap<>());\n    }\n\n    private static class PojoInvocationHandler implements InvocationHandler {\n\n        private final Map<Object, Object> map;\n\n        public PojoInvocationHandler(Map<Object, Object> map) {\n            this.map = map;\n        }\n\n        @Override\n        @SuppressWarnings(\"unchecked\")\n        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n            if (method.getDeclaringClass() == Object.class) {\n                return method.invoke(map, args);\n            }\n            String methodName = method.getName();\n            Object value = null;\n            if (methodName.length() > 3 && methodName.startsWith(\"get\")) {\n                value = map.get(methodName.substring(3, 4).toLowerCase() + methodName.substring(4));\n            } else if (methodName.length() > 2 && methodName.startsWith(\"is\")) {\n                value = map.get(methodName.substring(2, 3).toLowerCase() + methodName.substring(3));\n            } else {\n                value = map.get(methodName.substring(0, 1).toLowerCase() + methodName.substring(1));\n            }\n            if (value instanceof Map<?, ?> && !Map.class.isAssignableFrom(method.getReturnType())) {\n                value = realize0(value, method.getReturnType(), null, new IdentityHashMap<>());\n            }\n            return value;\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static Collection<Object> createCollection(Class<?> type, int len) {\n        if (type.isAssignableFrom(ArrayList.class)) {\n            return new ArrayList<>(len);\n        }\n        if (type.isAssignableFrom(HashSet.class)) {\n            return new HashSet<>(len);\n        }\n        if (!type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {\n            try {\n                return (Collection<Object>) type.getDeclaredConstructor().newInstance();\n            } catch (Exception e) {\n                // ignore\n            }\n        }\n        return new ArrayList<>();\n    }\n\n    private static Map createMap(Map src) {\n        Class<? extends Map> cl = src.getClass();\n        Map result = null;\n        if (HashMap.class == cl) {\n            result = new HashMap();\n        } else if (Hashtable.class == cl) {\n            result = new Hashtable();\n        } else if (IdentityHashMap.class == cl) {\n            result = new IdentityHashMap();\n        } else if (LinkedHashMap.class == cl) {\n            result = new LinkedHashMap();\n        } else if (Properties.class == cl) {\n            result = new Properties();\n        } else if (TreeMap.class == cl) {\n            result = new TreeMap();\n        } else if (WeakHashMap.class == cl) {\n            return new WeakHashMap();\n        } else if (ConcurrentHashMap.class == cl) {\n            result = new ConcurrentHashMap();\n        } else if (ConcurrentSkipListMap.class == cl) {\n            result = new ConcurrentSkipListMap();\n        } else {\n            try {\n                result = cl.getDeclaredConstructor().newInstance();\n            } catch (Exception e) {\n                /* ignore */\n            }\n\n            if (result == null) {\n                try {\n                    Constructor<?> constructor = cl.getConstructor(Map.class);\n                    result = (Map) constructor.newInstance(Collections.EMPTY_MAP);\n                } catch (Exception e) {\n                    /* ignore */\n                }\n            }\n        }\n\n        if (result == null) {\n            result = new HashMap<>();\n        }\n\n        return result;\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private static Object realize0(Object pojo, Class<?> type, Type genericType, final Map<Object, Object> history) {\n        return realize1(pojo, type, genericType, new HashMap<>(8), history);\n    }\n\n    private static Object realize1(\n            Object pojo,\n            Class<?> type,\n            Type genericType,\n            final Map<String, Type> mapParent,\n            final Map<Object, Object> history) {\n        if (pojo == null) {\n            return null;\n        }\n\n        if (type != null && type.isEnum() && pojo.getClass() == String.class) {\n            return Enum.valueOf((Class<Enum>) type, (String) pojo);\n        }\n\n        if (ReflectUtils.isPrimitives(pojo.getClass())\n                && !(type != null\n                        && type.isArray()\n                        && type.getComponentType().isEnum()\n                        && pojo.getClass() == String[].class)) {\n            return CompatibleTypeUtils.compatibleTypeConvert(pojo, type);\n        }\n\n        Object o = history.get(pojo);\n\n        if (o != null) {\n            return o;\n        }\n\n        history.put(pojo, pojo);\n\n        Map<String, Type> mapGeneric = new HashMap<>(8);\n        mapGeneric.putAll(mapParent);\n        TypeVariable<? extends Class<?>>[] typeParameters = type.getTypeParameters();\n        if (genericType instanceof ParameterizedType && typeParameters.length > 0) {\n            ParameterizedType parameterizedType = (ParameterizedType) genericType;\n            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();\n            for (int i = 0; i < typeParameters.length; i++) {\n                if (!(actualTypeArguments[i] instanceof TypeVariable)) {\n                    mapGeneric.put(typeParameters[i].getTypeName(), actualTypeArguments[i]);\n                }\n            }\n        }\n\n        if (pojo.getClass().isArray()) {\n            if (Collection.class.isAssignableFrom(type)) {\n                Class<?> ctype = pojo.getClass().getComponentType();\n                int len = Array.getLength(pojo);\n                Collection dest = createCollection(type, len);\n                history.put(pojo, dest);\n                for (int i = 0; i < len; i++) {\n                    Object obj = Array.get(pojo, i);\n                    Object value = realize1(obj, ctype, null, mapGeneric, history);\n                    dest.add(value);\n                }\n                return dest;\n            } else {\n                Class<?> ctype = (type != null && type.isArray()\n                        ? type.getComponentType()\n                        : pojo.getClass().getComponentType());\n                int len = Array.getLength(pojo);\n                Object dest = Array.newInstance(ctype, len);\n                history.put(pojo, dest);\n                for (int i = 0; i < len; i++) {\n                    Object obj = Array.get(pojo, i);\n                    Object value = realize1(obj, ctype, null, mapGeneric, history);\n                    Array.set(dest, i, value);\n                }\n                return dest;\n            }\n        }\n\n        if (pojo instanceof Collection<?>) {\n            if (type.isArray()) {\n                Class<?> ctype = type.getComponentType();\n                Collection<Object> src = (Collection<Object>) pojo;\n                int len = src.size();\n                Object dest = Array.newInstance(ctype, len);\n                history.put(pojo, dest);\n                int i = 0;\n                for (Object obj : src) {\n                    Object value = realize1(obj, ctype, null, mapGeneric, history);\n                    Array.set(dest, i, value);\n                    i++;\n                }\n                return dest;\n            } else {\n                Collection<Object> src = (Collection<Object>) pojo;\n                int len = src.size();\n                Collection<Object> dest = createCollection(type, len);\n                history.put(pojo, dest);\n                for (Object obj : src) {\n                    Type keyType = getGenericClassByIndex(genericType, 0);\n                    Class<?> keyClazz = obj == null ? null : obj.getClass();\n                    if (keyType instanceof Class) {\n                        keyClazz = (Class<?>) keyType;\n                    }\n                    Object value = realize1(obj, keyClazz, keyType, mapGeneric, history);\n                    dest.add(value);\n                }\n                return dest;\n            }\n        }\n\n        if (pojo instanceof Map<?, ?> && type != null) {\n            Object className = ((Map<Object, Object>) pojo).get(\"class\");\n            if (className instanceof String) {\n                if (!CLASS_NOT_FOUND_CACHE.containsKey(className)) {\n                    try {\n                        type = DefaultSerializeClassChecker.getInstance()\n                                .loadClass(ClassUtils.getClassLoader(), (String) className);\n                    } catch (ClassNotFoundException e) {\n                        CLASS_NOT_FOUND_CACHE.put((String) className, NOT_FOUND_VALUE);\n                    }\n                }\n            }\n\n            // special logic for enum\n            if (type.isEnum()) {\n                Object name = ((Map<Object, Object>) pojo).get(\"name\");\n                if (name != null) {\n                    if (!(name instanceof String)) {\n                        throw new IllegalArgumentException(\"`name` filed should be string!\");\n                    } else {\n                        return Enum.valueOf((Class<Enum>) type, (String) name);\n                    }\n                }\n            }\n            Map<Object, Object> map;\n            // when return type is not the subclass of return type from the signature and not an interface\n            if (!type.isInterface() && !type.isAssignableFrom(pojo.getClass())) {\n                try {\n                    map = (Map<Object, Object>) type.getDeclaredConstructor().newInstance();\n                    Map<Object, Object> mapPojo = (Map<Object, Object>) pojo;\n                    map.putAll(mapPojo);\n                    if (GENERIC_WITH_CLZ) {\n                        map.remove(\"class\");\n                    }\n                } catch (Exception e) {\n                    // ignore error\n                    map = (Map<Object, Object>) pojo;\n                }\n            } else {\n                map = (Map<Object, Object>) pojo;\n            }\n\n            if (Map.class.isAssignableFrom(type) || type == Object.class) {\n                final Map<Object, Object> result;\n                // fix issue#5939\n                Type mapKeyType = getKeyTypeForMap(map.getClass());\n                Type typeKeyType = getGenericClassByIndex(genericType, 0);\n                boolean typeMismatch = mapKeyType instanceof Class\n                        && typeKeyType instanceof Class\n                        && !typeKeyType.getTypeName().equals(mapKeyType.getTypeName());\n                if (typeMismatch) {\n                    result = createMap(new HashMap(0));\n                } else {\n                    result = createMap(map);\n                }\n\n                history.put(pojo, result);\n                for (Map.Entry<Object, Object> entry : map.entrySet()) {\n                    Type keyType = getGenericClassByIndex(genericType, 0);\n                    Type valueType = getGenericClassByIndex(genericType, 1);\n                    Class<?> keyClazz;\n                    if (keyType instanceof Class) {\n                        keyClazz = (Class<?>) keyType;\n                    } else if (keyType instanceof ParameterizedType) {\n                        keyClazz = (Class<?>) ((ParameterizedType) keyType).getRawType();\n                    } else {\n                        keyClazz =\n                                entry.getKey() == null ? null : entry.getKey().getClass();\n                    }\n                    Class<?> valueClazz;\n                    if (valueType instanceof Class) {\n                        valueClazz = (Class<?>) valueType;\n                    } else if (valueType instanceof ParameterizedType) {\n                        valueClazz = (Class<?>) ((ParameterizedType) valueType).getRawType();\n                    } else {\n                        valueClazz = entry.getValue() == null\n                                ? null\n                                : entry.getValue().getClass();\n                    }\n\n                    Object key = keyClazz == null\n                            ? entry.getKey()\n                            : realize1(entry.getKey(), keyClazz, keyType, mapGeneric, history);\n                    Object value = valueClazz == null\n                            ? entry.getValue()\n                            : realize1(entry.getValue(), valueClazz, valueType, mapGeneric, history);\n                    result.put(key, value);\n                }\n                return result;\n            } else if (type.isInterface()) {\n                Object dest = Proxy.newProxyInstance(\n                        Thread.currentThread().getContextClassLoader(),\n                        new Class<?>[] {type},\n                        new PojoInvocationHandler(map));\n                history.put(pojo, dest);\n                return dest;\n            } else {\n                Object dest;\n                if (Throwable.class.isAssignableFrom(type)) {\n                    Object message = map.get(\"message\");\n                    if (message instanceof String) {\n                        dest = newThrowableInstance(type, (String) message);\n                    } else {\n                        dest = newInstance(type);\n                    }\n                } else {\n                    dest = newInstance(type);\n                }\n\n                history.put(pojo, dest);\n\n                for (Map.Entry<Object, Object> entry : map.entrySet()) {\n                    Object key = entry.getKey();\n                    if (key instanceof String) {\n                        String name = (String) key;\n                        Object value = entry.getValue();\n                        if (value != null) {\n                            Method method = getSetterMethod(dest.getClass(), name, value.getClass());\n                            Field field = getAndCacheField(dest.getClass(), name);\n                            if (method != null) {\n                                if (!method.isAccessible()) {\n                                    method.setAccessible(true);\n                                }\n                                Type containType = Optional.ofNullable(field)\n                                        .map(Field::getGenericType)\n                                        .map(Type::getTypeName)\n                                        .map(mapGeneric::get)\n                                        .orElse(null);\n                                if (containType != null) {\n                                    // is generic\n                                    if (containType instanceof ParameterizedType) {\n                                        value = realize1(\n                                                value,\n                                                (Class<?>) ((ParameterizedType) containType).getRawType(),\n                                                containType,\n                                                mapGeneric,\n                                                history);\n                                    } else if (containType instanceof Class) {\n                                        value = realize1(\n                                                value, (Class<?>) containType, containType, mapGeneric, history);\n                                    } else {\n                                        Type ptype = method.getGenericParameterTypes()[0];\n                                        value = realize1(\n                                                value, method.getParameterTypes()[0], ptype, mapGeneric, history);\n                                    }\n                                } else {\n                                    Type ptype = method.getGenericParameterTypes()[0];\n                                    value = realize1(value, method.getParameterTypes()[0], ptype, mapGeneric, history);\n                                }\n                                try {\n                                    method.invoke(dest, value);\n                                } catch (Exception e) {\n                                    String exceptionDescription = \"Failed to set pojo \"\n                                            + dest.getClass().getSimpleName() + \" property \" + name + \" value \"\n                                            + value.getClass() + \", cause: \" + e.getMessage();\n                                    logger.error(COMMON_REFLECTIVE_OPERATION_FAILED, \"\", \"\", exceptionDescription, e);\n                                    throw new RuntimeException(exceptionDescription, e);\n                                }\n                            } else if (field != null) {\n                                value = realize1(value, field.getType(), field.getGenericType(), mapGeneric, history);\n                                try {\n                                    field.set(dest, value);\n                                } catch (IllegalAccessException e) {\n                                    throw new RuntimeException(\n                                            \"Failed to set field \" + name + \" of pojo \"\n                                                    + dest.getClass().getName() + \" : \" + e.getMessage(),\n                                            e);\n                                }\n                            }\n                        }\n                    }\n                }\n                return dest;\n            }\n        }\n        return pojo;\n    }\n\n    /**\n     * Get key type for {@link Map} directly implemented by {@code clazz}.\n     * If {@code clazz} does not implement {@link Map} directly, return {@code null}.\n     *\n     * @param clazz {@link Class}\n     * @return Return String.class for {@link com.alibaba.fastjson.JSONObject}\n     */\n    private static Type getKeyTypeForMap(Class<?> clazz) {\n        Type[] interfaces = clazz.getGenericInterfaces();\n        if (!ArrayUtils.isEmpty(interfaces)) {\n            for (Type type : interfaces) {\n                if (type instanceof ParameterizedType) {\n                    ParameterizedType t = (ParameterizedType) type;\n                    if (\"java.util.Map\".equals(t.getRawType().getTypeName())) {\n                        return t.getActualTypeArguments()[0];\n                    }\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Get parameterized type\n     *\n     * @param genericType generic type\n     * @param index       index of the target parameterized type\n     * @return Return Person.class for List<Person>, return Person.class for Map<String, Person> when index=0\n     */\n    private static Type getGenericClassByIndex(Type genericType, int index) {\n        Type clazz = null;\n        // find parameterized type\n        if (genericType instanceof ParameterizedType) {\n            ParameterizedType t = (ParameterizedType) genericType;\n            Type[] types = t.getActualTypeArguments();\n            clazz = types[index];\n        }\n        return clazz;\n    }\n\n    private static Object newThrowableInstance(Class<?> cls, String message) {\n        try {\n            Constructor<?> messagedConstructor = cls.getDeclaredConstructor(String.class);\n            return messagedConstructor.newInstance(message);\n        } catch (Exception t) {\n            return newInstance(cls);\n        }\n    }\n\n    private static Object newInstance(Class<?> cls) {\n        try {\n            return cls.getDeclaredConstructor().newInstance();\n        } catch (Exception t) {\n            Constructor<?>[] constructors = cls.getDeclaredConstructors();\n            /*\n             From Javadoc java.lang.Class#getDeclaredConstructors\n             This method returns an array of Constructor objects reflecting all the constructors\n             declared by the class represented by this Class object.\n             This method returns an array of length 0,\n             if this Class object represents an interface, a primitive type, an array class, or void.\n            */\n            if (constructors.length == 0) {\n                throw new RuntimeException(\"Illegal constructor: \" + cls.getName());\n            }\n            Throwable lastError = null;\n            Arrays.sort(constructors, Comparator.comparingInt(a -> a.getParameterTypes().length));\n            for (Constructor<?> constructor : constructors) {\n                try {\n                    constructor.setAccessible(true);\n                    Object[] parameters = Arrays.stream(constructor.getParameterTypes())\n                            .map(PojoUtils::getDefaultValue)\n                            .toArray();\n                    return constructor.newInstance(parameters);\n                } catch (Exception e) {\n                    lastError = e;\n                }\n            }\n            throw new RuntimeException(lastError.getMessage(), lastError);\n        }\n    }\n\n    /**\n     * return init value\n     *\n     * @param parameterType\n     * @return\n     */\n    private static Object getDefaultValue(Class<?> parameterType) {\n        if (\"char\".equals(parameterType.getName())) {\n            return Character.MIN_VALUE;\n        }\n        if (\"boolean\".equals(parameterType.getName())) {\n            return false;\n        }\n        if (\"byte\".equals(parameterType.getName())) {\n            return (byte) 0;\n        }\n        if (\"short\".equals(parameterType.getName())) {\n            return (short) 0;\n        }\n        return parameterType.isPrimitive() ? 0 : null;\n    }\n\n    private static Method getSetterMethod(Class<?> cls, String property, Class<?> valueCls) {\n        String name = \"set\" + property.substring(0, 1).toUpperCase() + property.substring(1);\n        Method method = NAME_METHODS_CACHE.get(cls.getName() + \".\" + name + \"(\" + valueCls.getName() + \")\");\n        if (method == null) {\n            try {\n                method = cls.getMethod(name, valueCls);\n            } catch (NoSuchMethodException e) {\n                for (Method m : cls.getMethods()) {\n                    if (ReflectUtils.isBeanPropertyWriteMethod(m) && m.getName().equals(name)) {\n                        method = m;\n                        break;\n                    }\n                }\n            }\n            if (method != null) {\n                NAME_METHODS_CACHE.put(cls.getName() + \".\" + name + \"(\" + valueCls.getName() + \")\", method);\n            }\n        }\n        return method;\n    }\n\n    private static Field getAndCacheField(Class<?> cls, String fieldName) {\n        Field result;\n        if (CLASS_FIELD_CACHE.containsKey(cls) && CLASS_FIELD_CACHE.get(cls).containsKey(fieldName)) {\n            return CLASS_FIELD_CACHE.get(cls).get(fieldName);\n        }\n\n        result = getField(cls, fieldName);\n\n        if (result != null) {\n            ConcurrentMap<String, Field> fields =\n                    ConcurrentHashMapUtils.computeIfAbsent(CLASS_FIELD_CACHE, cls, k -> new ConcurrentHashMap<>());\n            fields.putIfAbsent(fieldName, result);\n        }\n        return result;\n    }\n\n    private static Field getField(Class<?> cls, String fieldName) {\n        Field result = null;\n        for (Class<?> acls = cls; acls != null; acls = acls.getSuperclass()) {\n            try {\n                result = acls.getDeclaredField(fieldName);\n                if (!Modifier.isPublic(result.getModifiers())) {\n                    result.setAccessible(true);\n                }\n            } catch (NoSuchFieldException e) {\n            }\n        }\n        if (result == null && cls != null) {\n            for (Field field : cls.getFields()) {\n                if (fieldName.equals(field.getName()) && ReflectUtils.isPublicInstanceField(field)) {\n                    result = field;\n                    break;\n                }\n            }\n        }\n        return result;\n    }\n\n    public static boolean isPojo(Class<?> cls) {\n        return !ReflectUtils.isPrimitives(cls)\n                && !Collection.class.isAssignableFrom(cls)\n                && !Map.class.isAssignableFrom(cls);\n    }\n\n    /**\n     * Update the property if absent\n     *\n     * @param getterMethod the getter method\n     * @param setterMethod the setter method\n     * @param newValue     the new value\n     * @param <T>          the value type\n     * @since 2.7.8\n     */\n    public static <T> void updatePropertyIfAbsent(Supplier<T> getterMethod, Consumer<T> setterMethod, T newValue) {\n        if (newValue != null && getterMethod.get() == null) {\n            setterMethod.accept(newValue);\n        }\n    }\n\n    /**\n     * convert map to a specific class instance\n     *\n     * @param map map wait for convert\n     * @param cls the specified class\n     * @param <T> the type of {@code cls}\n     * @return class instance declare in param {@code cls}\n     * @throws ReflectiveOperationException if the instance creation is failed\n     * @since 2.7.10\n     */\n    public static <T> T mapToPojo(Map<String, Object> map, Class<T> cls) throws ReflectiveOperationException {\n        T instance = cls.getDeclaredConstructor().newInstance();\n        Map<String, Field> beanPropertyFields = ReflectUtils.getBeanPropertyFields(cls);\n        for (Map.Entry<String, Field> entry : beanPropertyFields.entrySet()) {\n            String name = entry.getKey();\n            Field field = entry.getValue();\n            Object mapObject = map.get(name);\n            if (mapObject == null) {\n                continue;\n            }\n\n            Type type = field.getGenericType();\n            Object fieldObject = getFieldObject(mapObject, type);\n            field.set(instance, fieldObject);\n        }\n\n        return instance;\n    }\n\n    private static Object getFieldObject(Object mapObject, Type fieldType) throws ReflectiveOperationException {\n        if (fieldType instanceof Class<?>) {\n            return convertClassType(mapObject, (Class<?>) fieldType);\n        } else if (fieldType instanceof ParameterizedType) {\n            return convertParameterizedType(mapObject, (ParameterizedType) fieldType);\n        } else if (fieldType instanceof GenericArrayType\n                || fieldType instanceof TypeVariable<?>\n                || fieldType instanceof WildcardType) {\n            // ignore these type currently\n            return null;\n        } else {\n            throw new IllegalArgumentException(\"Unrecognized Type: \" + fieldType.toString());\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static Object convertClassType(Object mapObject, Class<?> type) throws ReflectiveOperationException {\n        if (type.isPrimitive() || isAssignableFrom(type, mapObject.getClass())) {\n            return mapObject;\n        } else if (Objects.equals(type, String.class) && CLASS_CAN_BE_STRING.contains(mapObject.getClass())) {\n            // auto convert specified type to string\n            return mapObject.toString();\n        } else if (mapObject instanceof Map) {\n            return mapToPojo((Map<String, Object>) mapObject, type);\n        } else {\n            // type didn't match and mapObject is not another Map struct.\n            // we just ignore this situation.\n            return null;\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static Object convertParameterizedType(Object mapObject, ParameterizedType type)\n            throws ReflectiveOperationException {\n        Type rawType = type.getRawType();\n        if (!isAssignableFrom((Class<?>) rawType, mapObject.getClass())) {\n            return null;\n        }\n\n        Type[] actualTypeArguments = type.getActualTypeArguments();\n        if (isAssignableFrom(Map.class, (Class<?>) rawType)) {\n            Map<Object, Object> map = (Map<Object, Object>)\n                    mapObject.getClass().getDeclaredConstructor().newInstance();\n            for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) mapObject).entrySet()) {\n                Object key = getFieldObject(entry.getKey(), actualTypeArguments[0]);\n                Object value = getFieldObject(entry.getValue(), actualTypeArguments[1]);\n                map.put(key, value);\n            }\n\n            return map;\n        } else if (isAssignableFrom(Collection.class, (Class<?>) rawType)) {\n            Collection<Object> collection = (Collection<Object>)\n                    mapObject.getClass().getDeclaredConstructor().newInstance();\n            for (Object m : (Iterable<?>) mapObject) {\n                Object ele = getFieldObject(m, actualTypeArguments[0]);\n                collection.add(ele);\n            }\n\n            return collection;\n        } else {\n            // ignore other type currently\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ProtobufUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOBUF_MESSAGE_CLASS_NAME;\n\npublic class ProtobufUtils {\n\n    private static final Logger logger = LoggerFactory.getLogger(ProtobufUtils.class);\n\n    private static Class<?> protobufClss;\n\n    private ProtobufUtils() {}\n\n    static {\n        try {\n            protobufClss = ClassUtils.forName(PROTOBUF_MESSAGE_CLASS_NAME, ProtobufUtils.class.getClassLoader());\n        } catch (Throwable t) {\n            logger.info(\"protobuf's dependency is absent\");\n        }\n    }\n\n    public static boolean isProtobufClass(Class<?> pojoClazz) {\n        if (protobufClss != null) {\n            return protobufClss.isAssignableFrom(pojoClazz);\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.beans.BeanInfo;\nimport java.beans.Introspector;\nimport java.beans.MethodDescriptor;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.GenericArrayType;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.net.URL;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.Future;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\nimport javassist.CtClass;\nimport javassist.CtConstructor;\nimport javassist.CtMethod;\nimport javassist.NotFoundException;\n\nimport static java.util.Arrays.asList;\nimport static java.util.Collections.unmodifiableSet;\nimport static org.apache.dubbo.common.utils.ArrayUtils.isEmpty;\n\npublic final class ReflectUtils {\n\n    /**\n     * void(V).\n     */\n    public static final char JVM_VOID = 'V';\n\n    /**\n     * boolean(Z).\n     */\n    public static final char JVM_BOOLEAN = 'Z';\n\n    /**\n     * byte(B).\n     */\n    public static final char JVM_BYTE = 'B';\n\n    /**\n     * char(C).\n     */\n    public static final char JVM_CHAR = 'C';\n\n    /**\n     * double(D).\n     */\n    public static final char JVM_DOUBLE = 'D';\n\n    /**\n     * float(F).\n     */\n    public static final char JVM_FLOAT = 'F';\n\n    /**\n     * int(I).\n     */\n    public static final char JVM_INT = 'I';\n\n    /**\n     * long(J).\n     */\n    public static final char JVM_LONG = 'J';\n\n    /**\n     * short(S).\n     */\n    public static final char JVM_SHORT = 'S';\n\n    public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];\n\n    public static final String JAVA_IDENT_REGEX = \"(?:[_$a-zA-Z][_$a-zA-Z0-9]*)\";\n\n    public static final String JAVA_NAME_REGEX = \"(?:\" + JAVA_IDENT_REGEX + \"(?:\\\\.\" + JAVA_IDENT_REGEX + \")*)\";\n\n    public static final String CLASS_DESC = \"(?:L\" + JAVA_IDENT_REGEX + \"(?:\\\\/\" + JAVA_IDENT_REGEX + \")*;)\";\n\n    public static final String ARRAY_DESC = \"(?:\\\\[+(?:(?:[VZBCDFIJS])|\" + CLASS_DESC + \"))\";\n\n    public static final String DESC_REGEX = \"(?:(?:[VZBCDFIJS])|\" + CLASS_DESC + \"|\" + ARRAY_DESC + \")\";\n\n    public static final Pattern DESC_PATTERN = Pattern.compile(DESC_REGEX);\n\n    public static final String METHOD_DESC_REGEX =\n            \"(?:(\" + JAVA_IDENT_REGEX + \")?\\\\((\" + DESC_REGEX + \"*)\\\\)(\" + DESC_REGEX + \")?)\";\n\n    public static final Pattern METHOD_DESC_PATTERN = Pattern.compile(METHOD_DESC_REGEX);\n\n    public static final Pattern GETTER_METHOD_DESC_PATTERN =\n            Pattern.compile(\"get([A-Z][_a-zA-Z0-9]*)\\\\(\\\\)(\" + DESC_REGEX + \")\");\n\n    public static final Pattern SETTER_METHOD_DESC_PATTERN =\n            Pattern.compile(\"set([A-Z][_a-zA-Z0-9]*)\\\\((\" + DESC_REGEX + \")\\\\)V\");\n\n    public static final Pattern IS_HAS_CAN_METHOD_DESC_PATTERN =\n            Pattern.compile(\"(?:is|has|can)([A-Z][_a-zA-Z0-9]*)\\\\(\\\\)Z\");\n\n    private static Map<Class<?>, Object> primitiveDefaults = new HashMap<>();\n\n    static {\n        primitiveDefaults.put(int.class, 0);\n        primitiveDefaults.put(long.class, 0L);\n        primitiveDefaults.put(byte.class, (byte) 0);\n        primitiveDefaults.put(char.class, (char) 0);\n        primitiveDefaults.put(short.class, (short) 0);\n        primitiveDefaults.put(float.class, (float) 0);\n        primitiveDefaults.put(double.class, (double) 0);\n        primitiveDefaults.put(boolean.class, false);\n        primitiveDefaults.put(void.class, null);\n    }\n\n    private ReflectUtils() {}\n\n    public static boolean isPrimitives(Class<?> cls) {\n        while (cls.isArray()) {\n            cls = cls.getComponentType();\n        }\n        return isPrimitive(cls);\n    }\n\n    public static boolean isPrimitive(Class<?> cls) {\n        return cls.isPrimitive()\n                || cls == String.class\n                || cls == Boolean.class\n                || cls == Character.class\n                || Number.class.isAssignableFrom(cls)\n                || Date.class.isAssignableFrom(cls);\n    }\n\n    public static Class<?> getBoxedClass(Class<?> c) {\n        if (c == int.class) {\n            c = Integer.class;\n        } else if (c == boolean.class) {\n            c = Boolean.class;\n        } else if (c == long.class) {\n            c = Long.class;\n        } else if (c == float.class) {\n            c = Float.class;\n        } else if (c == double.class) {\n            c = Double.class;\n        } else if (c == char.class) {\n            c = Character.class;\n        } else if (c == byte.class) {\n            c = Byte.class;\n        } else if (c == short.class) {\n            c = Short.class;\n        }\n        return c;\n    }\n\n    /**\n     * is compatible.\n     *\n     * @param c class.\n     * @param o instance.\n     * @return compatible or not.\n     */\n    public static boolean isCompatible(Class<?> c, Object o) {\n        boolean pt = c.isPrimitive();\n        if (o == null) {\n            return !pt;\n        }\n\n        if (pt) {\n            c = getBoxedClass(c);\n        }\n\n        return c == o.getClass() || c.isInstance(o);\n    }\n\n    /**\n     * is compatible.\n     *\n     * @param cs class array.\n     * @param os object array.\n     * @return compatible or not.\n     */\n    public static boolean isCompatible(Class<?>[] cs, Object[] os) {\n        int len = cs.length;\n        if (len != os.length) {\n            return false;\n        }\n        if (len == 0) {\n            return true;\n        }\n        for (int i = 0; i < len; i++) {\n            if (!isCompatible(cs[i], os[i])) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public static String getCodeBase(Class<?> cls) {\n        if (cls == null) {\n            return null;\n        }\n        ProtectionDomain domain = cls.getProtectionDomain();\n        if (domain == null) {\n            return null;\n        }\n        CodeSource source = domain.getCodeSource();\n        if (source == null) {\n            return null;\n        }\n        URL location = source.getLocation();\n        if (location == null) {\n            return null;\n        }\n        return location.getFile();\n    }\n\n    /**\n     * get name.\n     * java.lang.Object[][].class => \"java.lang.Object[][]\"\n     *\n     * @param c class.\n     * @return name.\n     */\n    public static String getName(Class<?> c) {\n        if (c.isArray()) {\n            StringBuilder sb = new StringBuilder();\n            do {\n                sb.append(\"[]\");\n                c = c.getComponentType();\n            } while (c.isArray());\n\n            return c.getName() + sb.toString();\n        }\n        return c.getName();\n    }\n\n    public static Class<?> getGenericClass(Class<?> cls) {\n        return getGenericClass(cls, 0);\n    }\n\n    public static Class<?> getGenericClass(Class<?> cls, int i) {\n        try {\n            ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);\n            Object genericClass = parameterizedType.getActualTypeArguments()[i];\n\n            // handle nested generic type\n            if (genericClass instanceof ParameterizedType) {\n                return (Class<?>) ((ParameterizedType) genericClass).getRawType();\n            }\n\n            // handle array generic type\n            if (genericClass instanceof GenericArrayType) {\n                return (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType();\n            }\n\n            // Requires JDK 7 or higher, Foo<int[]> is no longer GenericArrayType\n            if (((Class) genericClass).isArray()) {\n                return ((Class) genericClass).getComponentType();\n            }\n            return (Class<?>) genericClass;\n        } catch (Throwable e) {\n            throw new IllegalArgumentException(cls.getName() + \" generic type undefined!\", e);\n        }\n    }\n\n    /**\n     * get method name.\n     * \"void do(int)\", \"void do()\", \"int do(java.lang.String,boolean)\"\n     *\n     * @param m method.\n     * @return name.\n     */\n    public static String getName(final Method m) {\n        StringBuilder ret = new StringBuilder();\n        ret.append(getName(m.getReturnType())).append(' ');\n        ret.append(m.getName()).append('(');\n        Class<?>[] parameterTypes = m.getParameterTypes();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            if (i > 0) {\n                ret.append(',');\n            }\n            ret.append(getName(parameterTypes[i]));\n        }\n        ret.append(')');\n        return ret.toString();\n    }\n\n    public static String getSignature(String methodName, Class<?>[] parameterTypes) {\n        StringBuilder sb = new StringBuilder(methodName);\n        sb.append('(');\n        if (parameterTypes != null && parameterTypes.length > 0) {\n            boolean first = true;\n            for (Class<?> type : parameterTypes) {\n                if (first) {\n                    first = false;\n                } else {\n                    sb.append(',');\n                }\n                sb.append(type.getName());\n            }\n        }\n        sb.append(')');\n        return sb.toString();\n    }\n\n    /**\n     * get constructor name.\n     * \"()\", \"(java.lang.String,int)\"\n     *\n     * @param c constructor.\n     * @return name.\n     */\n    public static String getName(final Constructor<?> c) {\n        StringBuilder ret = new StringBuilder(\"(\");\n        Class<?>[] parameterTypes = c.getParameterTypes();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            if (i > 0) {\n                ret.append(',');\n            }\n            ret.append(getName(parameterTypes[i]));\n        }\n        ret.append(')');\n        return ret.toString();\n    }\n\n    /**\n     * get class desc.\n     * boolean[].class => \"[Z\"\n     * Object.class => \"Ljava/lang/Object;\"\n     *\n     * @param c class.\n     * @return desc.\n     * @throws NotFoundException\n     */\n    public static String getDesc(Class<?> c) {\n        StringBuilder ret = new StringBuilder();\n\n        while (c.isArray()) {\n            ret.append('[');\n            c = c.getComponentType();\n        }\n\n        if (c.isPrimitive()) {\n            String t = c.getName();\n            if (\"void\".equals(t)) {\n                ret.append(JVM_VOID);\n            } else if (\"boolean\".equals(t)) {\n                ret.append(JVM_BOOLEAN);\n            } else if (\"byte\".equals(t)) {\n                ret.append(JVM_BYTE);\n            } else if (\"char\".equals(t)) {\n                ret.append(JVM_CHAR);\n            } else if (\"double\".equals(t)) {\n                ret.append(JVM_DOUBLE);\n            } else if (\"float\".equals(t)) {\n                ret.append(JVM_FLOAT);\n            } else if (\"int\".equals(t)) {\n                ret.append(JVM_INT);\n            } else if (\"long\".equals(t)) {\n                ret.append(JVM_LONG);\n            } else if (\"short\".equals(t)) {\n                ret.append(JVM_SHORT);\n            }\n        } else {\n            ret.append('L');\n            ret.append(c.getName().replace('.', '/'));\n            ret.append(';');\n        }\n        return ret.toString();\n    }\n\n    /**\n     * get class array desc.\n     * [int.class, boolean[].class, Object.class] => \"I[ZLjava/lang/Object;\"\n     *\n     * @param cs class array.\n     * @return desc.\n     * @throws NotFoundException\n     */\n    public static String getDesc(final Class<?>[] cs) {\n        if (cs.length == 0) {\n            return \"\";\n        }\n\n        StringBuilder sb = new StringBuilder(64);\n        for (Class<?> c : cs) {\n            sb.append(getDesc(c));\n        }\n        return sb.toString();\n    }\n\n    /**\n     * get method desc.\n     * int do(int arg1) => \"do(I)I\"\n     * void do(String arg1,boolean arg2) => \"do(Ljava/lang/String;Z)V\"\n     *\n     * @param m method.\n     * @return desc.\n     */\n    public static String getDesc(final Method m) {\n        StringBuilder ret = new StringBuilder(m.getName()).append('(');\n        Class<?>[] parameterTypes = m.getParameterTypes();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            ret.append(getDesc(parameterTypes[i]));\n        }\n        ret.append(')').append(getDesc(m.getReturnType()));\n        return ret.toString();\n    }\n\n    public static String[] getDescArray(final Method m) {\n        Class<?>[] parameterTypes = m.getParameterTypes();\n        String[] arr = new String[parameterTypes.length];\n\n        for (int i = 0; i < parameterTypes.length; i++) {\n            arr[i] = getDesc(parameterTypes[i]);\n        }\n        return arr;\n    }\n\n    /**\n     * get constructor desc.\n     * \"()V\", \"(Ljava/lang/String;I)V\"\n     *\n     * @param c constructor.\n     * @return desc\n     */\n    public static String getDesc(final Constructor<?> c) {\n        StringBuilder ret = new StringBuilder(\"(\");\n        Class<?>[] parameterTypes = c.getParameterTypes();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            ret.append(getDesc(parameterTypes[i]));\n        }\n        ret.append(')').append('V');\n        return ret.toString();\n    }\n\n    /**\n     * get method desc.\n     * \"(I)I\", \"()V\", \"(Ljava/lang/String;Z)V\"\n     *\n     * @param m method.\n     * @return desc.\n     */\n    public static String getDescWithoutMethodName(Method m) {\n        StringBuilder ret = new StringBuilder();\n        ret.append('(');\n        Class<?>[] parameterTypes = m.getParameterTypes();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            ret.append(getDesc(parameterTypes[i]));\n        }\n        ret.append(')').append(getDesc(m.getReturnType()));\n        return ret.toString();\n    }\n\n    /**\n     * get class desc.\n     * Object.class => \"Ljava/lang/Object;\"\n     * boolean[].class => \"[Z\"\n     *\n     * @param c class.\n     * @return desc.\n     * @throws NotFoundException\n     */\n    public static String getDesc(final CtClass c) throws NotFoundException {\n        StringBuilder ret = new StringBuilder();\n        if (c.isArray()) {\n            ret.append('[');\n            ret.append(getDesc(c.getComponentType()));\n        } else if (c.isPrimitive()) {\n            String t = c.getName();\n            if (\"void\".equals(t)) {\n                ret.append(JVM_VOID);\n            } else if (\"boolean\".equals(t)) {\n                ret.append(JVM_BOOLEAN);\n            } else if (\"byte\".equals(t)) {\n                ret.append(JVM_BYTE);\n            } else if (\"char\".equals(t)) {\n                ret.append(JVM_CHAR);\n            } else if (\"double\".equals(t)) {\n                ret.append(JVM_DOUBLE);\n            } else if (\"float\".equals(t)) {\n                ret.append(JVM_FLOAT);\n            } else if (\"int\".equals(t)) {\n                ret.append(JVM_INT);\n            } else if (\"long\".equals(t)) {\n                ret.append(JVM_LONG);\n            } else if (\"short\".equals(t)) {\n                ret.append(JVM_SHORT);\n            }\n        } else {\n            ret.append('L');\n            ret.append(c.getName().replace('.', '/'));\n            ret.append(';');\n        }\n        return ret.toString();\n    }\n\n    /**\n     * get method desc.\n     * \"do(I)I\", \"do()V\", \"do(Ljava/lang/String;Z)V\"\n     *\n     * @param m method.\n     * @return desc.\n     */\n    public static String getDesc(final CtMethod m) throws NotFoundException {\n        StringBuilder ret = new StringBuilder(m.getName()).append('(');\n        CtClass[] parameterTypes = m.getParameterTypes();\n        for (CtClass parameterType : parameterTypes) {\n            ret.append(getDesc(parameterType));\n        }\n        ret.append(')').append(getDesc(m.getReturnType()));\n        return ret.toString();\n    }\n\n    /**\n     * get constructor desc.\n     * \"()V\", \"(Ljava/lang/String;I)V\"\n     *\n     * @param c constructor.\n     * @return desc\n     */\n    public static String getDesc(final CtConstructor c) throws NotFoundException {\n        StringBuilder ret = new StringBuilder(\"(\");\n        CtClass[] parameterTypes = c.getParameterTypes();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            ret.append(getDesc(parameterTypes[i]));\n        }\n        ret.append(')').append('V');\n        return ret.toString();\n    }\n\n    /**\n     * get method desc.\n     * \"(I)I\", \"()V\", \"(Ljava/lang/String;Z)V\".\n     *\n     * @param m method.\n     * @return desc.\n     */\n    public static String getDescWithoutMethodName(final CtMethod m) throws NotFoundException {\n        StringBuilder ret = new StringBuilder();\n        ret.append('(');\n        CtClass[] parameterTypes = m.getParameterTypes();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            ret.append(getDesc(parameterTypes[i]));\n        }\n        ret.append(')').append(getDesc(m.getReturnType()));\n        return ret.toString();\n    }\n\n    /**\n     * name to desc.\n     * java.util.Map[][] => \"[[Ljava/util/Map;\"\n     *\n     * @param name name.\n     * @return desc.\n     */\n    public static String name2desc(String name) {\n        StringBuilder sb = new StringBuilder();\n        int c = 0, index = name.indexOf('[');\n        if (index > 0) {\n            c = (name.length() - index) / 2;\n            name = name.substring(0, index);\n        }\n        while (c-- > 0) {\n            sb.append('[');\n        }\n        if (\"void\".equals(name)) {\n            sb.append(JVM_VOID);\n        } else if (\"boolean\".equals(name)) {\n            sb.append(JVM_BOOLEAN);\n        } else if (\"byte\".equals(name)) {\n            sb.append(JVM_BYTE);\n        } else if (\"char\".equals(name)) {\n            sb.append(JVM_CHAR);\n        } else if (\"double\".equals(name)) {\n            sb.append(JVM_DOUBLE);\n        } else if (\"float\".equals(name)) {\n            sb.append(JVM_FLOAT);\n        } else if (\"int\".equals(name)) {\n            sb.append(JVM_INT);\n        } else if (\"long\".equals(name)) {\n            sb.append(JVM_LONG);\n        } else if (\"short\".equals(name)) {\n            sb.append(JVM_SHORT);\n        } else {\n            sb.append('L').append(name.replace('.', '/')).append(';');\n        }\n        return sb.toString();\n    }\n\n    /**\n     * desc to name.\n     * \"[[I\" => \"int[][]\"\n     *\n     * @param desc desc.\n     * @return name.\n     */\n    public static String desc2name(String desc) {\n        StringBuilder sb = new StringBuilder();\n        int c = desc.lastIndexOf('[') + 1;\n        if (desc.length() == c + 1) {\n            switch (desc.charAt(c)) {\n                case JVM_VOID: {\n                    sb.append(\"void\");\n                    break;\n                }\n                case JVM_BOOLEAN: {\n                    sb.append(\"boolean\");\n                    break;\n                }\n                case JVM_BYTE: {\n                    sb.append(\"byte\");\n                    break;\n                }\n                case JVM_CHAR: {\n                    sb.append(\"char\");\n                    break;\n                }\n                case JVM_DOUBLE: {\n                    sb.append(\"double\");\n                    break;\n                }\n                case JVM_FLOAT: {\n                    sb.append(\"float\");\n                    break;\n                }\n                case JVM_INT: {\n                    sb.append(\"int\");\n                    break;\n                }\n                case JVM_LONG: {\n                    sb.append(\"long\");\n                    break;\n                }\n                case JVM_SHORT: {\n                    sb.append(\"short\");\n                    break;\n                }\n                default:\n                    throw new RuntimeException();\n            }\n        } else {\n            sb.append(desc.substring(c + 1, desc.length() - 1).replace('/', '.'));\n        }\n        while (c-- > 0) {\n            sb.append(\"[]\");\n        }\n        return sb.toString();\n    }\n\n    public static Class<?> forName(String name) {\n        try {\n            return name2class(name);\n        } catch (ClassNotFoundException e) {\n            throw new IllegalStateException(\"Not found class \" + name + \", cause: \" + e.getMessage(), e);\n        }\n    }\n\n    public static Class<?> forName(ClassLoader cl, String name) {\n        try {\n            return name2class(cl, name);\n        } catch (ClassNotFoundException e) {\n            throw new IllegalStateException(\"Not found class \" + name + \", cause: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * name to class.\n     * \"boolean\" => boolean.class\n     * \"java.util.Map[][]\" => java.util.Map[][].class\n     *\n     * @param name name.\n     * @return Class instance.\n     */\n    public static Class<?> name2class(String name) throws ClassNotFoundException {\n        return name2class(ClassUtils.getClassLoader(), name);\n    }\n\n    /**\n     * name to class.\n     * \"boolean\" => boolean.class\n     * \"java.util.Map[][]\" => java.util.Map[][].class\n     *\n     * @param cl   ClassLoader instance.\n     * @param name name.\n     * @return Class instance.\n     */\n    private static Class<?> name2class(ClassLoader cl, String name) throws ClassNotFoundException {\n        int c = 0, index = name.indexOf('[');\n        if (index > 0) {\n            c = (name.length() - index) / 2;\n            name = name.substring(0, index);\n        }\n        if (c > 0) {\n            StringBuilder sb = new StringBuilder();\n            while (c-- > 0) {\n                sb.append('[');\n            }\n\n            if (\"void\".equals(name)) {\n                sb.append(JVM_VOID);\n            } else if (\"boolean\".equals(name)) {\n                sb.append(JVM_BOOLEAN);\n            } else if (\"byte\".equals(name)) {\n                sb.append(JVM_BYTE);\n            } else if (\"char\".equals(name)) {\n                sb.append(JVM_CHAR);\n            } else if (\"double\".equals(name)) {\n                sb.append(JVM_DOUBLE);\n            } else if (\"float\".equals(name)) {\n                sb.append(JVM_FLOAT);\n            } else if (\"int\".equals(name)) {\n                sb.append(JVM_INT);\n            } else if (\"long\".equals(name)) {\n                sb.append(JVM_LONG);\n            } else if (\"short\".equals(name)) {\n                sb.append(JVM_SHORT);\n            } else {\n                // \"java.lang.Object\" ==> \"Ljava.lang.Object;\"\n                sb.append('L').append(name).append(';');\n            }\n            name = sb.toString();\n        } else {\n            if (\"void\".equals(name)) {\n                return void.class;\n            }\n            if (\"boolean\".equals(name)) {\n                return boolean.class;\n            }\n            if (\"byte\".equals(name)) {\n                return byte.class;\n            }\n            if (\"char\".equals(name)) {\n                return char.class;\n            }\n            if (\"double\".equals(name)) {\n                return double.class;\n            }\n            if (\"float\".equals(name)) {\n                return float.class;\n            }\n            if (\"int\".equals(name)) {\n                return int.class;\n            }\n            if (\"long\".equals(name)) {\n                return long.class;\n            }\n            if (\"short\".equals(name)) {\n                return short.class;\n            }\n        }\n\n        if (cl == null) {\n            cl = ClassUtils.getClassLoader();\n        }\n        return Class.forName(name, true, cl);\n    }\n\n    /**\n     * desc to class.\n     * \"[Z\" => boolean[].class\n     * \"[[Ljava/util/Map;\" => java.util.Map[][].class\n     *\n     * @param desc desc.\n     * @return Class instance.\n     * @throws ClassNotFoundException\n     */\n    public static Class<?> desc2class(String desc) throws ClassNotFoundException {\n        return desc2class(ClassUtils.getClassLoader(), desc);\n    }\n\n    /**\n     * desc to class.\n     * \"[Z\" => boolean[].class\n     * \"[[Ljava/util/Map;\" => java.util.Map[][].class\n     *\n     * @param cl   ClassLoader instance.\n     * @param desc desc.\n     * @return Class instance.\n     * @throws ClassNotFoundException\n     */\n    private static Class<?> desc2class(ClassLoader cl, String desc) throws ClassNotFoundException {\n        switch (desc.charAt(0)) {\n            case JVM_VOID:\n                return void.class;\n            case JVM_BOOLEAN:\n                return boolean.class;\n            case JVM_BYTE:\n                return byte.class;\n            case JVM_CHAR:\n                return char.class;\n            case JVM_DOUBLE:\n                return double.class;\n            case JVM_FLOAT:\n                return float.class;\n            case JVM_INT:\n                return int.class;\n            case JVM_LONG:\n                return long.class;\n            case JVM_SHORT:\n                return short.class;\n            case 'L':\n                // \"Ljava/lang/Object;\" ==> \"java.lang.Object\"\n                desc = desc.substring(1, desc.length() - 1).replace('/', '.');\n                break;\n            case '[':\n                // \"[[Ljava/lang/Object;\" ==> \"[[Ljava.lang.Object;\"\n                desc = desc.replace('/', '.');\n                break;\n            default:\n                throw new ClassNotFoundException(\"Class not found: \" + desc);\n        }\n\n        if (cl == null) {\n            cl = ClassUtils.getClassLoader();\n        }\n        return Class.forName(desc, true, cl);\n    }\n\n    /**\n     * get class array instance.\n     *\n     * @param desc desc.\n     * @return Class class array.\n     * @throws ClassNotFoundException\n     */\n    public static Class<?>[] desc2classArray(String desc) throws ClassNotFoundException {\n        Class<?>[] ret = desc2classArray(ClassUtils.getClassLoader(), desc);\n        return ret;\n    }\n\n    /**\n     * get class array instance.\n     *\n     * @param cl   ClassLoader instance.\n     * @param desc desc.\n     * @return Class[] class array.\n     * @throws ClassNotFoundException\n     */\n    private static Class<?>[] desc2classArray(ClassLoader cl, String desc) throws ClassNotFoundException {\n        if (desc.length() == 0) {\n            return EMPTY_CLASS_ARRAY;\n        }\n\n        List<Class<?>> cs = new ArrayList<>();\n        Matcher m = DESC_PATTERN.matcher(desc);\n        while (m.find()) {\n            cs.add(desc2class(cl, m.group()));\n        }\n        return cs.toArray(EMPTY_CLASS_ARRAY);\n    }\n\n    /**\n     * Find method from method signature\n     *\n     * @param clazz      Target class to find method\n     * @param methodName Method signature, e.g.: method1(int, String). It is allowed to provide method name only, e.g.: method2\n     * @return target method\n     * @throws NoSuchMethodException\n     * @throws ClassNotFoundException\n     * @throws IllegalStateException  when multiple methods are found (overridden method when parameter info is not provided)\n     * @deprecated Recommend {@link MethodUtils#findMethod(Class, String, Class[])}\n     */\n    @Deprecated\n    public static Method findMethodByMethodSignature(Class<?> clazz, String methodName, String[] parameterTypes)\n            throws NoSuchMethodException, ClassNotFoundException {\n        Method method;\n        if (parameterTypes == null) {\n            List<Method> found = new ArrayList<>();\n            for (Method m : clazz.getMethods()) {\n                if (m.getName().equals(methodName)) {\n                    found.add(m);\n                }\n            }\n            if (found.isEmpty()) {\n                throw new NoSuchMethodException(\"No such method \" + methodName + \" in class \" + clazz);\n            }\n            if (found.size() > 1) {\n                String msg = String.format(\n                        \"Not unique method for method name(%s) in class(%s), find %d methods.\",\n                        methodName, clazz.getName(), found.size());\n                throw new IllegalStateException(msg);\n            }\n            method = found.get(0);\n        } else {\n            Class<?>[] types = new Class<?>[parameterTypes.length];\n            for (int i = 0; i < parameterTypes.length; i++) {\n                types[i] = ReflectUtils.name2class(parameterTypes[i]);\n            }\n            method = clazz.getMethod(methodName, types);\n        }\n        return method;\n    }\n\n    /**\n     * @param clazz      Target class to find method\n     * @param methodName Method signature, e.g.: method1(int, String). It is allowed to provide method name only, e.g.: method2\n     * @return target method\n     * @throws NoSuchMethodException\n     * @throws ClassNotFoundException\n     * @throws IllegalStateException  when multiple methods are found (overridden method when parameter info is not provided)\n     * @deprecated Recommend {@link MethodUtils#findMethod(Class, String, Class[])}\n     */\n    @Deprecated\n    public static Method findMethodByMethodName(Class<?> clazz, String methodName)\n            throws NoSuchMethodException, ClassNotFoundException {\n        return findMethodByMethodSignature(clazz, methodName, null);\n    }\n\n    public static Constructor<?> findConstructor(Class<?> clazz, Class<?> paramType) throws NoSuchMethodException {\n        Constructor<?> targetConstructor;\n        try {\n            targetConstructor = clazz.getConstructor(new Class<?>[] {paramType});\n        } catch (NoSuchMethodException e) {\n            targetConstructor = null;\n            Constructor<?>[] constructors = clazz.getConstructors();\n            for (Constructor<?> constructor : constructors) {\n                if (Modifier.isPublic(constructor.getModifiers())\n                        && constructor.getParameterTypes().length == 1\n                        && constructor.getParameterTypes()[0].isAssignableFrom(paramType)) {\n                    targetConstructor = constructor;\n                    break;\n                }\n            }\n            if (targetConstructor == null) {\n                throw e;\n            }\n        }\n        return targetConstructor;\n    }\n\n    /**\n     * Check if one object is the implementation for a given interface.\n     * <p>\n     * This method will not trigger classloading for the given interface, therefore it will not lead to error when\n     * the given interface is not visible by the classloader\n     *\n     * @param obj                Object to examine\n     * @param interfaceClazzName The given interface\n     * @return true if the object implements the given interface, otherwise return false\n     */\n    public static boolean isInstance(Object obj, String interfaceClazzName) {\n        for (Class<?> clazz = obj.getClass();\n                clazz != null && !clazz.equals(Object.class);\n                clazz = clazz.getSuperclass()) {\n            Class<?>[] interfaces = clazz.getInterfaces();\n            for (Class<?> itf : interfaces) {\n                if (itf.getName().equals(interfaceClazzName)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    public static Object getEmptyObject(Class<?> returnType) {\n        return getEmptyObject(returnType, new HashMap<>(), 0);\n    }\n\n    private static Object getEmptyObject(Class<?> returnType, Map<Class<?>, Object> emptyInstances, int level) {\n        if (level > 2) {\n            return null;\n        }\n        if (returnType == null) {\n            return null;\n        }\n        if (returnType == boolean.class || returnType == Boolean.class) {\n            return false;\n        }\n        if (returnType == char.class || returnType == Character.class) {\n            return '\\0';\n        }\n        if (returnType == byte.class || returnType == Byte.class) {\n            return (byte) 0;\n        }\n        if (returnType == short.class || returnType == Short.class) {\n            return (short) 0;\n        }\n        if (returnType == int.class || returnType == Integer.class) {\n            return 0;\n        }\n        if (returnType == long.class || returnType == Long.class) {\n            return 0L;\n        }\n        if (returnType == float.class || returnType == Float.class) {\n            return 0F;\n        }\n        if (returnType == double.class || returnType == Double.class) {\n            return 0D;\n        }\n        if (returnType.isArray()) {\n            return Array.newInstance(returnType.getComponentType(), 0);\n        }\n        if (returnType.isAssignableFrom(ArrayList.class)) {\n            return new ArrayList<>(0);\n        }\n        if (returnType.isAssignableFrom(HashSet.class)) {\n            return new HashSet<>(0);\n        }\n        if (returnType.isAssignableFrom(HashMap.class)) {\n            return new HashMap<>(0);\n        }\n        if (String.class.equals(returnType)) {\n            return \"\";\n        }\n        if (returnType.isInterface()) {\n            return null;\n        }\n\n        try {\n            Object value = emptyInstances.get(returnType);\n            if (value == null) {\n                value = returnType.getDeclaredConstructor().newInstance();\n                emptyInstances.put(returnType, value);\n            }\n            Class<?> cls = value.getClass();\n            while (cls != null && cls != Object.class) {\n                Field[] fields = cls.getDeclaredFields();\n                for (Field field : fields) {\n                    if (field.isSynthetic()) {\n                        continue;\n                    }\n                    Object property = getEmptyObject(field.getType(), emptyInstances, level + 1);\n                    if (property != null) {\n                        try {\n                            if (!field.isAccessible()) {\n                                field.setAccessible(true);\n                            }\n                            field.set(value, property);\n                        } catch (Throwable ignored) {\n                        }\n                    }\n                }\n                cls = cls.getSuperclass();\n            }\n            return value;\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n\n    public static Object defaultReturn(Method m) {\n        if (m.getReturnType().isPrimitive()) {\n            return primitiveDefaults.get(m.getReturnType());\n        } else {\n            return null;\n        }\n    }\n\n    public static Object defaultReturn(Class<?> classType) {\n        if (classType != null && classType.isPrimitive()) {\n            return primitiveDefaults.get(classType);\n        } else {\n            return null;\n        }\n    }\n\n    public static boolean isBeanPropertyReadMethod(Method method) {\n        return method != null\n                && Modifier.isPublic(method.getModifiers())\n                && !Modifier.isStatic(method.getModifiers())\n                && method.getReturnType() != void.class\n                && method.getDeclaringClass() != Object.class\n                && method.getParameterTypes().length == 0\n                && ((method.getName().startsWith(\"get\") && method.getName().length() > 3)\n                        || (method.getName().startsWith(\"is\")\n                                && method.getName().length() > 2));\n    }\n\n    public static String getPropertyNameFromBeanReadMethod(Method method) {\n        if (isBeanPropertyReadMethod(method)) {\n            if (method.getName().startsWith(\"get\")) {\n                return method.getName().substring(3, 4).toLowerCase()\n                        + method.getName().substring(4);\n            }\n            if (method.getName().startsWith(\"is\")) {\n                return method.getName().substring(2, 3).toLowerCase()\n                        + method.getName().substring(3);\n            }\n        }\n        return null;\n    }\n\n    public static boolean isBeanPropertyWriteMethod(Method method) {\n        return method != null\n                && Modifier.isPublic(method.getModifiers())\n                && !Modifier.isStatic(method.getModifiers())\n                && method.getDeclaringClass() != Object.class\n                && method.getParameterTypes().length == 1\n                && method.getName().startsWith(\"set\")\n                && method.getName().length() > 3;\n    }\n\n    public static String getPropertyNameFromBeanWriteMethod(Method method) {\n        if (isBeanPropertyWriteMethod(method)) {\n            return method.getName().substring(3, 4).toLowerCase()\n                    + method.getName().substring(4);\n        }\n        return null;\n    }\n\n    public static boolean isPublicInstanceField(Field field) {\n        return Modifier.isPublic(field.getModifiers())\n                && !Modifier.isStatic(field.getModifiers())\n                && !Modifier.isFinal(field.getModifiers())\n                && !field.isSynthetic();\n    }\n\n    public static Map<String, Field> getBeanPropertyFields(Class cl) {\n        Map<String, Field> properties = new HashMap<>();\n        for (; cl != null; cl = cl.getSuperclass()) {\n            Field[] fields = cl.getDeclaredFields();\n            for (Field field : fields) {\n                if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {\n                    continue;\n                }\n\n                field.setAccessible(true);\n\n                properties.put(field.getName(), field);\n            }\n        }\n\n        return properties;\n    }\n\n    public static Map<String, Method> getBeanPropertyReadMethods(Class cl) {\n        Map<String, Method> properties = new HashMap<>();\n        for (; cl != null; cl = cl.getSuperclass()) {\n            Method[] methods = cl.getDeclaredMethods();\n            for (Method method : methods) {\n                if (isBeanPropertyReadMethod(method)) {\n                    method.setAccessible(true);\n                    String property = getPropertyNameFromBeanReadMethod(method);\n                    properties.put(property, method);\n                }\n            }\n        }\n\n        return properties;\n    }\n\n    public static Type[] getReturnTypes(Method method) {\n        Class<?> returnType = method.getReturnType();\n        Type genericReturnType = method.getGenericReturnType();\n        if (Future.class.isAssignableFrom(returnType)) {\n            if (genericReturnType instanceof ParameterizedType) {\n                Type actualArgType = ((ParameterizedType) genericReturnType).getActualTypeArguments()[0];\n                if (actualArgType instanceof ParameterizedType) {\n                    returnType = (Class<?>) ((ParameterizedType) actualArgType).getRawType();\n                    genericReturnType = actualArgType;\n                } else if (actualArgType instanceof TypeVariable) {\n                    returnType = (Class<?>) ((TypeVariable<?>) actualArgType).getBounds()[0];\n                    genericReturnType = actualArgType;\n                } else {\n                    returnType = (Class<?>) actualArgType;\n                    genericReturnType = returnType;\n                }\n            } else {\n                returnType = null;\n                genericReturnType = null;\n            }\n        }\n        return new Type[] {returnType, genericReturnType};\n    }\n\n    /**\n     * Find the {@link Set} of {@link ParameterizedType}\n     *\n     * @param sourceClass the source {@link Class class}\n     * @return non-null read-only {@link Set}\n     * @since 2.7.5\n     */\n    public static Set<ParameterizedType> findParameterizedTypes(Class<?> sourceClass) {\n        // Add Generic Interfaces\n        List<Type> genericTypes = new LinkedList<>(asList(sourceClass.getGenericInterfaces()));\n        // Add Generic Super Class\n        genericTypes.add(sourceClass.getGenericSuperclass());\n\n        Set<ParameterizedType> parameterizedTypes = genericTypes.stream()\n                .filter(type -> type instanceof ParameterizedType) // filter ParameterizedType\n                .map(ParameterizedType.class::cast) // cast to ParameterizedType\n                .collect(Collectors.toSet());\n\n        if (parameterizedTypes.isEmpty()) { // If not found, try to search super types recursively\n            genericTypes.stream()\n                    .filter(type -> type instanceof Class)\n                    .map(Class.class::cast)\n                    .forEach(superClass -> parameterizedTypes.addAll(findParameterizedTypes(superClass)));\n        }\n\n        return unmodifiableSet(parameterizedTypes); // build as a Set\n    }\n\n    /**\n     * Find the hierarchical types from the source {@link Class class} by specified {@link Class type}.\n     *\n     * @param sourceClass the source {@link Class class}\n     * @param matchType   the type to match\n     * @param <T>         the type to match\n     * @return non-null read-only {@link Set}\n     * @since 2.7.5\n     */\n    public static <T> Set<Class<T>> findHierarchicalTypes(Class<?> sourceClass, Class<T> matchType) {\n        if (sourceClass == null) {\n            return Collections.emptySet();\n        }\n\n        Set<Class<T>> hierarchicalTypes = new LinkedHashSet<>();\n\n        if (matchType.isAssignableFrom(sourceClass)) {\n            hierarchicalTypes.add((Class<T>) sourceClass);\n        }\n\n        // Find all super classes\n        hierarchicalTypes.addAll(findHierarchicalTypes(sourceClass.getSuperclass(), matchType));\n\n        return unmodifiableSet(hierarchicalTypes);\n    }\n\n    /**\n     * Get the value from the specified bean and its getter method.\n     *\n     * @param bean       the bean instance\n     * @param methodName the name of getter\n     * @param <T>        the type of property value\n     * @return\n     * @since 2.7.5\n     */\n    public static <T> T getProperty(Object bean, String methodName) {\n        Class<?> beanClass = bean.getClass();\n        BeanInfo beanInfo = null;\n        T propertyValue = null;\n\n        try {\n            beanInfo = Introspector.getBeanInfo(beanClass);\n            propertyValue = (T) Stream.of(beanInfo.getMethodDescriptors())\n                    .filter(methodDescriptor -> methodName.equals(methodDescriptor.getName()))\n                    .findFirst()\n                    .map(method -> {\n                        try {\n                            return method.getMethod().invoke(bean);\n                        } catch (Exception e) {\n                            // ignore\n                        }\n                        return null;\n                    })\n                    .get();\n        } catch (Exception e) {\n\n        }\n        return propertyValue;\n    }\n\n    /**\n     * Check target bean class whether has specify method\n     * @param beanClass\n     * @param methodName\n     * @return\n     */\n    public static boolean hasMethod(Class<?> beanClass, String methodName) {\n        try {\n            BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);\n            Optional<MethodDescriptor> descriptor = Stream.of(beanInfo.getMethodDescriptors())\n                    .filter(methodDescriptor -> methodName.equals(methodDescriptor.getName()))\n                    .findFirst();\n            return descriptor.isPresent();\n        } catch (Exception e) {\n\n        }\n        return false;\n    }\n\n    /**\n     * Resolve the types of the specified values\n     *\n     * @param values the values\n     * @return If can't be resolved, return {@link ReflectUtils#EMPTY_CLASS_ARRAY empty class array}\n     * @since 2.7.6\n     */\n    public static Class[] resolveTypes(Object... values) {\n\n        if (isEmpty(values)) {\n            return EMPTY_CLASS_ARRAY;\n        }\n\n        int size = values.length;\n\n        Class[] types = new Class[size];\n\n        for (int i = 0; i < size; i++) {\n            Object value = values[i];\n            types[i] = value == null ? null : value.getClass();\n        }\n\n        return types;\n    }\n\n    public static boolean checkZeroArgConstructor(Class clazz) {\n        try {\n            clazz.getDeclaredConstructor();\n            return true;\n        } catch (NoSuchMethodException e) {\n            return false;\n        }\n    }\n\n    public static boolean isJdk(Class clazz) {\n        return clazz.getName().startsWith(\"java.\") || clazz.getName().startsWith(\"javax.\");\n    }\n\n    /**\n     * Copy from org.springframework.util.ReflectionUtils.\n     * Make the given method accessible, explicitly setting it accessible if\n     * necessary. The {@code setAccessible(true)} method is only called\n     * when actually necessary, to avoid unnecessary conflicts with a JVM\n     * SecurityManager (if active).\n     * @param method the method to make accessible\n     * @see java.lang.reflect.Method#setAccessible\n     */\n    @SuppressWarnings(\"deprecation\") // on JDK 9\n    public static void makeAccessible(Method method) {\n        if ((!Modifier.isPublic(method.getModifiers())\n                        || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))\n                && !method.isAccessible()) {\n            method.setAccessible(true);\n        }\n    }\n\n    /**\n     * Get all field names of target type\n     * @param type\n     * @return\n     */\n    public static Set<String> getAllFieldNames(Class<?> type) {\n\n        Set<String> fieldNames = new HashSet<>();\n        for (Field field : type.getDeclaredFields()) {\n            fieldNames.add(field.getName());\n        }\n\n        Set<Class<?>> allSuperClasses = ClassUtils.getAllSuperClasses(type);\n        for (Class<?> aClass : allSuperClasses) {\n            for (Field field : aClass.getDeclaredFields()) {\n                fieldNames.add(field.getName());\n            }\n        }\n        return fieldNames;\n    }\n\n    public static <T> T getFieldValue(Object obj, String fieldName) throws RuntimeException {\n        if (obj == null) {\n            throw new IllegalArgumentException(\"object is null\");\n        }\n        try {\n            Field field = obj.getClass().getDeclaredField(fieldName);\n            field.setAccessible(true);\n            return (T) field.get(obj);\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectionUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * A utility class that provides methods for accessing and manipulating private fields and methods of an object.\n * This is useful for white-box testing, where the internal workings of a class need to be tested directly.\n * <p>\n * Note: Usage of this class should be limited to testing purposes only, as it violates the encapsulation principle.\n */\npublic class ReflectionUtils {\n\n    private ReflectionUtils() {}\n\n    /**\n     * Retrieves the value of the specified field from the given object.\n     *\n     * @param source    The object from which to retrieve the field value.\n     * @param fieldName The name of the field to retrieve.\n     * @return The value of the specified field in the given object.\n     * @throws RuntimeException If the specified field does not exist.\n     */\n    public static Object getField(Object source, String fieldName) {\n        try {\n            Field f = source.getClass().getDeclaredField(fieldName);\n            f.setAccessible(true);\n            return f.get(source);\n        } catch (Exception e) {\n            throw new ReflectionException(e);\n        }\n    }\n\n    /**\n     * Invokes the specified method on the given object with the provided parameters.\n     *\n     * @param source     The object on which to invoke the method.\n     * @param methodName The name of the method to invoke.\n     * @param params     The parameters to pass to the method.\n     * @return The result of invoking the specified method on the given object.\n     */\n    public static Object invoke(Object source, String methodName, Object... params) {\n        try {\n            Class<?>[] classes = Arrays.stream(params)\n                    .map(param -> param != null ? param.getClass() : null)\n                    .toArray(Class<?>[]::new);\n\n            for (Method method : source.getClass().getDeclaredMethods()) {\n                if (method.getName().equals(methodName) && matchParameters(method.getParameterTypes(), classes)) {\n                    method.setAccessible(true);\n                    return method.invoke(source, params);\n                }\n            }\n            throw new NoSuchMethodException(\"No method found with the specified name and parameter types\");\n        } catch (Exception e) {\n            throw new ReflectionException(e);\n        }\n    }\n\n    private static boolean matchParameters(Class<?>[] methodParamTypes, Class<?>[] givenParamTypes) {\n        if (methodParamTypes.length != givenParamTypes.length) {\n            return false;\n        }\n\n        for (int i = 0; i < methodParamTypes.length; i++) {\n            if (givenParamTypes[i] == null) {\n                if (methodParamTypes[i].isPrimitive()) {\n                    return false;\n                }\n            } else if (!methodParamTypes[i].isAssignableFrom(givenParamTypes[i])) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Returns a list of distinct {@link Class} objects representing the generics of the given class that implement the\n     * given interface.\n     *\n     * @param clazz          the class to retrieve the generics for\n     * @param interfaceClass the interface to retrieve the generics for\n     * @return a list of distinct {@link Class} objects representing the generics of the given class that implement the\n     * given interface\n     */\n    public static List<Class<?>> getClassGenerics(Class<?> clazz, Class<?> interfaceClass) {\n        List<Class<?>> generics = new ArrayList<>();\n        Type[] genericInterfaces = clazz.getGenericInterfaces();\n        for (Type genericInterface : genericInterfaces) {\n            if (genericInterface instanceof ParameterizedType) {\n                ParameterizedType parameterizedType = (ParameterizedType) genericInterface;\n                Type rawType = parameterizedType.getRawType();\n                if (rawType instanceof Class && interfaceClass.isAssignableFrom((Class<?>) rawType)) {\n                    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();\n                    for (Type actualTypeArgument : actualTypeArguments) {\n                        if (actualTypeArgument instanceof Class) {\n                            generics.add((Class<?>) actualTypeArgument);\n                        }\n                    }\n                }\n            }\n        }\n        Type genericSuperclass = clazz.getGenericSuperclass();\n        if (genericSuperclass instanceof ParameterizedType) {\n            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;\n            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();\n            for (Type actualTypeArgument : actualTypeArguments) {\n                if (actualTypeArgument instanceof Class) {\n                    generics.add((Class<?>) actualTypeArgument);\n                }\n            }\n        }\n        Class<?> superclass = clazz.getSuperclass();\n        if (superclass != null) {\n            generics.addAll(getClassGenerics(superclass, interfaceClass));\n        }\n        return generics.stream().distinct().collect(Collectors.toList());\n    }\n\n    public static class ReflectionException extends RuntimeException {\n        public ReflectionException(Throwable cause) {\n            super(cause);\n        }\n    }\n\n    public static boolean match(Class<?> clazz, Class<?> interfaceClass, Object event) {\n        List<Class<?>> eventTypes = ReflectionUtils.getClassGenerics(clazz, interfaceClass);\n        return eventTypes.stream().allMatch(eventType -> eventType.isInstance(event));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/RegexProperties.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\n\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\n/**\n * Regex matching of keys is supported.\n */\npublic class RegexProperties extends Properties {\n\n    @Override\n    public String getProperty(String key) {\n        String value = super.getProperty(key);\n        if (value != null) {\n            return value;\n        }\n\n        // Sort the keys to solve the problem of matching priority.\n        List<String> sortedKeyList = keySet().stream()\n                .map(k -> (String) k)\n                .sorted(Comparator.reverseOrder())\n                .collect(Collectors.toList());\n\n        String keyPattern = sortedKeyList.stream()\n                .filter(k -> {\n                    String matchingKey = k;\n                    if (matchingKey.startsWith(CommonConstants.ANY_VALUE)) {\n                        matchingKey = CommonConstants.HIDE_KEY_PREFIX + matchingKey;\n                    }\n                    return Pattern.matches(matchingKey, key);\n                })\n                .findFirst()\n                .orElse(null);\n\n        return keyPattern == null ? null : super.getProperty(keyPattern);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeCheckStatus.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\npublic enum SerializeCheckStatus {\n    /**\n     * Disable serialize check for all classes\n     */\n    DISABLE(0),\n\n    /**\n     * Only deny danger classes, warn if other classes are not in allow list\n     */\n    WARN(1),\n\n    /**\n     * Only allow classes in allow list, deny if other classes are not in allow list\n     */\n    STRICT(2);\n\n    private final int level;\n\n    SerializeCheckStatus(int level) {\n        this.level = level;\n    }\n\n    public int level() {\n        return level;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityConfigurator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.aot.NativeDetector;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialization.ClassHolder;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeClassLoaderListener;\n\nimport java.io.IOException;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.GenericArrayType;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.lang.reflect.WildcardType;\nimport java.net.URL;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SERIALIZE_ALLOW_LIST_FILE_PATH;\nimport static org.apache.dubbo.common.constants.CommonConstants.SERIALIZE_BLOCKED_LIST_FILE_PATH;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_IO_EXCEPTION;\n\npublic class SerializeSecurityConfigurator implements ScopeClassLoaderListener<ModuleModel> {\n    private static final ErrorTypeAwareLogger LOGGER =\n            LoggerFactory.getErrorTypeAwareLogger(SerializeSecurityConfigurator.class);\n\n    private final Set<Type> markedTypeCache = new HashSet<>();\n\n    private final SerializeSecurityManager serializeSecurityManager;\n\n    private final ModuleModel moduleModel;\n\n    private final ClassHolder classHolder;\n\n    private volatile boolean autoTrustSerializeClass = true;\n\n    private volatile int trustSerializeClassLevel = Integer.MAX_VALUE;\n\n    public SerializeSecurityConfigurator(ModuleModel moduleModel) {\n        this.moduleModel = moduleModel;\n        moduleModel.addClassLoaderListener(this);\n\n        FrameworkModel frameworkModel = moduleModel.getApplicationModel().getFrameworkModel();\n        serializeSecurityManager = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n        classHolder =\n                NativeDetector.inNativeImage() ? frameworkModel.getBeanFactory().getBean(ClassHolder.class) : null;\n\n        refreshStatus();\n        refreshCheck();\n        refreshConfig();\n\n        onAddClassLoader(moduleModel, Thread.currentThread().getContextClassLoader());\n    }\n\n    public void refreshCheck() {\n        Optional<ApplicationConfig> applicationConfig =\n                moduleModel.getApplicationModel().getApplicationConfigManager().getApplication();\n        autoTrustSerializeClass = applicationConfig\n                .map(ApplicationConfig::getAutoTrustSerializeClass)\n                .orElse(true);\n        trustSerializeClassLevel = applicationConfig\n                .map(ApplicationConfig::getTrustSerializeClassLevel)\n                .orElse(Integer.MAX_VALUE);\n        serializeSecurityManager.setCheckSerializable(\n                applicationConfig.map(ApplicationConfig::getCheckSerializable).orElse(true));\n    }\n\n    @Override\n    public void onAddClassLoader(ModuleModel scopeModel, ClassLoader classLoader) {\n        refreshClassLoader(classLoader);\n    }\n\n    @Override\n    public void onRemoveClassLoader(ModuleModel scopeModel, ClassLoader classLoader) {\n        // ignore\n    }\n\n    private void refreshClassLoader(ClassLoader classLoader) {\n        loadAllow(classLoader);\n        loadBlocked(classLoader);\n    }\n\n    private void refreshConfig() {\n        String allowedClassList = SystemPropertyConfigUtils.getSystemProperty(\n                        CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_ALLOWED_LIST, \"\")\n                .trim();\n        String blockedClassList = SystemPropertyConfigUtils.getSystemProperty(\n                        CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST, \"\")\n                .trim();\n\n        if (StringUtils.isNotEmpty(allowedClassList)) {\n            String[] classStrings = allowedClassList.trim().split(\",\");\n            for (String className : classStrings) {\n                className = className.trim();\n                if (StringUtils.isNotEmpty(className)) {\n                    serializeSecurityManager.addToAlwaysAllowed(className);\n                }\n            }\n        }\n\n        if (StringUtils.isNotEmpty(blockedClassList)) {\n            String[] classStrings = blockedClassList.trim().split(\",\");\n            for (String className : classStrings) {\n                className = className.trim();\n                if (StringUtils.isNotEmpty(className)) {\n                    serializeSecurityManager.addToDisAllowed(className);\n                }\n            }\n        }\n    }\n\n    private void loadAllow(ClassLoader classLoader) {\n        Set<URL> urls = ClassLoaderResourceLoader.loadResources(SERIALIZE_ALLOW_LIST_FILE_PATH, classLoader);\n        for (URL u : urls) {\n            try {\n                LOGGER.info(\"Read serialize allow list from \" + u);\n                String[] lines = IOUtils.readLines(u.openStream());\n                for (String line : lines) {\n                    line = line.trim();\n                    if (StringUtils.isEmpty(line) || line.startsWith(\"#\")) {\n                        continue;\n                    }\n                    serializeSecurityManager.addToAlwaysAllowed(line);\n                }\n            } catch (IOException e) {\n                LOGGER.error(\n                        COMMON_IO_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Failed to load allow class list! Will ignore allow lis from \" + u,\n                        e);\n            }\n        }\n    }\n\n    private void loadBlocked(ClassLoader classLoader) {\n        Set<URL> urls = ClassLoaderResourceLoader.loadResources(SERIALIZE_BLOCKED_LIST_FILE_PATH, classLoader);\n        for (URL u : urls) {\n            try {\n                LOGGER.info(\"Read serialize blocked list from \" + u);\n                String[] lines = IOUtils.readLines(u.openStream());\n                for (String line : lines) {\n                    line = line.trim();\n                    if (StringUtils.isEmpty(line) || line.startsWith(\"#\")) {\n                        continue;\n                    }\n                    serializeSecurityManager.addToDisAllowed(line);\n                }\n            } catch (IOException e) {\n                LOGGER.error(\n                        COMMON_IO_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Failed to load blocked class list! Will ignore blocked lis from \" + u,\n                        e);\n            }\n        }\n    }\n\n    public void refreshStatus() {\n        Optional<ApplicationConfig> application =\n                moduleModel.getApplicationModel().getApplicationConfigManager().getApplication();\n        String statusString =\n                application.map(ApplicationConfig::getSerializeCheckStatus).orElse(null);\n        SerializeCheckStatus checkStatus = null;\n\n        if (StringUtils.isEmpty(statusString)) {\n            String openCheckClass = SystemPropertyConfigUtils.getSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_OPEN_CHECK, \"true\");\n            if (!Boolean.parseBoolean(openCheckClass)) {\n                checkStatus = SerializeCheckStatus.DISABLE;\n            }\n            String blockAllClassExceptAllow = SystemPropertyConfigUtils.getSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCK_ALL, \"false\");\n            if (Boolean.parseBoolean(blockAllClassExceptAllow)) {\n                checkStatus = SerializeCheckStatus.STRICT;\n            }\n        } else {\n            checkStatus = SerializeCheckStatus.valueOf(statusString);\n        }\n\n        if (checkStatus != null) {\n            serializeSecurityManager.setCheckStatus(checkStatus);\n        }\n    }\n\n    public synchronized void registerInterface(Class<?> clazz) {\n        if (!autoTrustSerializeClass) {\n            return;\n        }\n\n        if (!checkClass(clazz)) {\n            return;\n        }\n\n        addToAllow(clazz);\n\n        Method[] methodsToExport = clazz.getMethods();\n\n        for (Method method : methodsToExport) {\n            Class<?>[] parameterTypes = method.getParameterTypes();\n            for (Class<?> parameterType : parameterTypes) {\n                checkClass(parameterType);\n            }\n\n            Type[] genericParameterTypes = method.getGenericParameterTypes();\n            for (Type genericParameterType : genericParameterTypes) {\n                checkType(genericParameterType);\n            }\n\n            Class<?> returnType = method.getReturnType();\n            checkClass(returnType);\n\n            Type genericReturnType = method.getGenericReturnType();\n            checkType(genericReturnType);\n\n            Class<?>[] exceptionTypes = method.getExceptionTypes();\n            for (Class<?> exceptionType : exceptionTypes) {\n                checkClass(exceptionType);\n            }\n\n            Type[] genericExceptionTypes = method.getGenericExceptionTypes();\n            for (Type genericExceptionType : genericExceptionTypes) {\n                checkType(genericExceptionType);\n            }\n        }\n    }\n\n    private void checkType(Type type) {\n        if (type == null) {\n            return;\n        }\n\n        if (type instanceof Class) {\n            checkClass((Class<?>) type);\n            return;\n        }\n\n        if (!markedTypeCache.add(type)) {\n            return;\n        }\n\n        if (type instanceof ParameterizedType) {\n            ParameterizedType parameterizedType = (ParameterizedType) type;\n            checkClass((Class<?>) parameterizedType.getRawType());\n            for (Type actualTypeArgument : parameterizedType.getActualTypeArguments()) {\n                checkType(actualTypeArgument);\n            }\n        } else if (type instanceof GenericArrayType) {\n            GenericArrayType genericArrayType = (GenericArrayType) type;\n            checkType(genericArrayType.getGenericComponentType());\n        } else if (type instanceof TypeVariable) {\n            TypeVariable typeVariable = (TypeVariable) type;\n            for (Type bound : typeVariable.getBounds()) {\n                checkType(bound);\n            }\n        } else if (type instanceof WildcardType) {\n            WildcardType wildcardType = (WildcardType) type;\n            for (Type bound : wildcardType.getUpperBounds()) {\n                checkType(bound);\n            }\n            for (Type bound : wildcardType.getLowerBounds()) {\n                checkType(bound);\n            }\n        }\n    }\n\n    private boolean checkClass(Class<?> clazz) {\n        if (clazz == null) {\n            return false;\n        }\n\n        if (!markedTypeCache.add(clazz)) {\n            return false;\n        }\n\n        addToAllow(clazz);\n\n        if (ClassUtils.isSimpleType(clazz) || clazz.isPrimitive() || clazz.isArray()) {\n            return true;\n        }\n        String className = clazz.getName();\n        if (className.startsWith(\"java.\")\n                || className.startsWith(\"javax.\")\n                || className.startsWith(\"com.sun.\")\n                || className.startsWith(\"sun.\")\n                || className.startsWith(\"jdk.\")) {\n            return true;\n        }\n\n        Class<?>[] interfaces = clazz.getInterfaces();\n        for (Class<?> interfaceClass : interfaces) {\n            checkClass(interfaceClass);\n        }\n\n        for (Type genericInterface : clazz.getGenericInterfaces()) {\n            checkType(genericInterface);\n        }\n\n        Class<?> superclass = clazz.getSuperclass();\n        if (superclass != null) {\n            checkClass(superclass);\n        }\n\n        Type genericSuperclass = clazz.getGenericSuperclass();\n        if (genericSuperclass != null) {\n            checkType(genericSuperclass);\n        }\n\n        Field[] fields = clazz.getDeclaredFields();\n\n        for (Field field : fields) {\n            if (Modifier.isTransient(field.getModifiers())) {\n                continue;\n            }\n\n            Class<?> fieldClass = field.getType();\n            checkClass(fieldClass);\n            checkType(field.getGenericType());\n        }\n\n        return true;\n    }\n\n    private void addToAllow(Class<?> clazz) {\n        if (classHolder != null) {\n            classHolder.storeClass(clazz);\n        }\n\n        String className = clazz.getName();\n        // ignore jdk\n        if (className.startsWith(\"java.\")\n                || className.startsWith(\"javax.\")\n                || className.startsWith(\"com.sun.\")\n                || className.startsWith(\"jakarta.\")\n                || className.startsWith(\"sun.\")\n                || className.startsWith(\"jdk.\")) {\n            serializeSecurityManager.addToAllowed(className);\n            return;\n        }\n\n        // add group package\n        String[] subs = className.split(\"\\\\.\");\n        if (subs.length > trustSerializeClassLevel) {\n            serializeSecurityManager.addToAllowed(\n                    Arrays.stream(subs).limit(trustSerializeClassLevel).collect(Collectors.joining(\".\")) + \".\");\n        } else {\n            serializeSecurityManager.addToAllowed(className);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.Set;\n\npublic class SerializeSecurityManager {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(SerializeSecurityManager.class);\n\n    private final Set<String> allowedPrefix = new ConcurrentHashSet<>();\n\n    private final Set<String> alwaysAllowedPrefix = new ConcurrentHashSet<>();\n\n    private final Set<String> disAllowedPrefix = new ConcurrentHashSet<>();\n\n    private final Set<AllowClassNotifyListener> listeners = new ConcurrentHashSet<>();\n\n    private final Set<String> warnedClasses = new ConcurrentHashSet<>(1);\n\n    private volatile SerializeCheckStatus checkStatus = null;\n\n    private volatile SerializeCheckStatus defaultCheckStatus = AllowClassNotifyListener.DEFAULT_STATUS;\n\n    private volatile Boolean checkSerializable = null;\n\n    public void addToAlwaysAllowed(String className) {\n        boolean modified = alwaysAllowedPrefix.add(className);\n\n        if (modified) {\n            notifyPrefix();\n        }\n    }\n\n    public void addToAllowed(String className) {\n        if (disAllowedPrefix.stream().anyMatch(className::startsWith)) {\n            return;\n        }\n\n        boolean modified = allowedPrefix.add(className);\n\n        if (modified) {\n            notifyPrefix();\n        }\n    }\n\n    public void addToDisAllowed(String className) {\n        boolean modified = disAllowedPrefix.add(className);\n        modified = allowedPrefix.removeIf(allow -> allow.startsWith(className)) || modified;\n\n        if (modified) {\n            notifyPrefix();\n        }\n\n        String lowerCase = className.toLowerCase(Locale.ROOT);\n        if (!Objects.equals(lowerCase, className)) {\n            addToDisAllowed(lowerCase);\n        }\n    }\n\n    public void setCheckStatus(SerializeCheckStatus checkStatus) {\n        if (this.checkStatus == null) {\n            this.checkStatus = checkStatus;\n            logger.info(\"Serialize check level: \" + checkStatus.name());\n            notifyCheckStatus();\n            return;\n        }\n\n        // If has been set to WARN, ignore STRICT\n        if (this.checkStatus.level() <= checkStatus.level()) {\n            return;\n        }\n\n        this.checkStatus = checkStatus;\n        logger.info(\"Serialize check level: \" + checkStatus.name());\n        notifyCheckStatus();\n    }\n\n    public void setDefaultCheckStatus(SerializeCheckStatus checkStatus) {\n        this.defaultCheckStatus = checkStatus;\n        logger.info(\"Serialize check default level: \" + checkStatus.name());\n        notifyCheckStatus();\n    }\n\n    public void setCheckSerializable(boolean checkSerializable) {\n        if (this.checkSerializable == null || (Boolean.TRUE.equals(this.checkSerializable) && !checkSerializable)) {\n            this.checkSerializable = checkSerializable;\n            logger.info(\"Serialize check serializable: \" + checkSerializable);\n            notifyCheckSerializable();\n        }\n    }\n\n    public void registerListener(AllowClassNotifyListener listener) {\n        listeners.add(listener);\n        listener.notifyPrefix(getAllowedPrefix(), getDisAllowedPrefix());\n        listener.notifyCheckSerializable(isCheckSerializable());\n        listener.notifyCheckStatus(getCheckStatus());\n    }\n\n    private void notifyPrefix() {\n        for (AllowClassNotifyListener listener : listeners) {\n            listener.notifyPrefix(getAllowedPrefix(), getDisAllowedPrefix());\n        }\n    }\n\n    private void notifyCheckStatus() {\n        for (AllowClassNotifyListener listener : listeners) {\n            listener.notifyCheckStatus(getCheckStatus());\n        }\n    }\n\n    private void notifyCheckSerializable() {\n        for (AllowClassNotifyListener listener : listeners) {\n            listener.notifyCheckSerializable(isCheckSerializable());\n        }\n    }\n\n    protected SerializeCheckStatus getCheckStatus() {\n        return checkStatus == null ? defaultCheckStatus : checkStatus;\n    }\n\n    protected Set<String> getAllowedPrefix() {\n        Set<String> set = new ConcurrentHashSet<>();\n        set.addAll(allowedPrefix);\n        set.addAll(alwaysAllowedPrefix);\n        return set;\n    }\n\n    protected Set<String> getDisAllowedPrefix() {\n        Set<String> set = new ConcurrentHashSet<>();\n        set.addAll(disAllowedPrefix);\n        return set;\n    }\n\n    protected boolean isCheckSerializable() {\n        return checkSerializable == null || checkSerializable;\n    }\n\n    public Set<String> getWarnedClasses() {\n        return warnedClasses;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ServiceAnnotationResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.compact.Dubbo2CompactUtils;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.annotation.Service;\n\nimport java.lang.annotation.Annotation;\nimport java.util.List;\n\nimport static java.lang.String.format;\nimport static java.util.Arrays.asList;\nimport static java.util.Collections.unmodifiableList;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAttribute;\nimport static org.apache.dubbo.common.utils.ArrayUtils.isNotEmpty;\nimport static org.apache.dubbo.common.utils.ClassUtils.isGenericClass;\nimport static org.apache.dubbo.common.utils.ClassUtils.resolveClass;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\n\n/**\n * The resolver class for {@link Service @Service}\n *\n * @see Service\n * @see com.alibaba.dubbo.config.annotation.Service\n * @since 2.7.6\n */\npublic class ServiceAnnotationResolver {\n\n    /**\n     * The annotation {@link Class classes} of Dubbo Service (read-only)\n     *\n     * @since 2.7.9\n     */\n    public static List<Class<? extends Annotation>> SERVICE_ANNOTATION_CLASSES = loadServiceAnnotationClasses();\n\n    private static List<Class<? extends Annotation>> loadServiceAnnotationClasses() {\n        if (Dubbo2CompactUtils.isEnabled() && Dubbo2CompactUtils.isServiceClassLoaded()) {\n            return unmodifiableList(asList(DubboService.class, Service.class, Dubbo2CompactUtils.getServiceClass()));\n        } else {\n            return unmodifiableList(asList(DubboService.class, Service.class));\n        }\n    }\n\n    private final Annotation serviceAnnotation;\n\n    private final Class<?> serviceType;\n\n    public ServiceAnnotationResolver(Class<?> serviceType) throws IllegalArgumentException {\n        this.serviceType = serviceType;\n        this.serviceAnnotation = getServiceAnnotation(serviceType);\n    }\n\n    private Annotation getServiceAnnotation(Class<?> serviceType) {\n\n        Annotation serviceAnnotation = null;\n\n        for (Class<? extends Annotation> serviceAnnotationClass : SERVICE_ANNOTATION_CLASSES) {\n            serviceAnnotation = serviceType.getAnnotation(serviceAnnotationClass);\n            if (serviceAnnotation != null) {\n                break;\n            }\n        }\n\n        if (serviceAnnotation == null) {\n            throw new IllegalArgumentException(format(\n                    \"Any annotation of [%s] can't be annotated in the service type[%s].\",\n                    SERVICE_ANNOTATION_CLASSES, serviceType.getName()));\n        }\n\n        return serviceAnnotation;\n    }\n\n    /**\n     * Resolve the class name of interface\n     *\n     * @return if not found, return <code>null</code>\n     */\n    public String resolveInterfaceClassName() {\n\n        Class interfaceClass;\n        // first, try to get the value from \"interfaceName\" attribute\n        String interfaceName = resolveAttribute(\"interfaceName\");\n\n        if (isEmpty(interfaceName)) { // If not found, try \"interfaceClass\"\n            interfaceClass = resolveAttribute(\"interfaceClass\");\n        } else {\n            interfaceClass = resolveClass(interfaceName, getClass().getClassLoader());\n        }\n\n        if (isGenericClass(interfaceClass)) {\n            interfaceName = interfaceClass.getName();\n        } else {\n            interfaceName = null;\n        }\n\n        if (isEmpty(interfaceName)) { // If not fund, try to get the first interface from the service type\n            Class[] interfaces = serviceType.getInterfaces();\n            if (isNotEmpty(interfaces)) {\n                interfaceName = interfaces[0].getName();\n            }\n        }\n\n        return interfaceName;\n    }\n\n    public String resolveVersion() {\n        return resolveAttribute(\"version\");\n    }\n\n    public String resolveGroup() {\n        return resolveAttribute(\"group\");\n    }\n\n    private <T> T resolveAttribute(String attributeName) {\n        return getAttribute(serviceAnnotation, attributeName);\n    }\n\n    public Annotation getServiceAnnotation() {\n        return serviceAnnotation;\n    }\n\n    public Class<?> getServiceType() {\n        return serviceType;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/Stack.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.ArrayList;\nimport java.util.EmptyStackException;\nimport java.util.List;\n\n/**\n * Stack.\n */\npublic class Stack<E> {\n    private int mSize = 0;\n\n    private final List<E> mElements = new ArrayList<>();\n\n    public Stack() {}\n\n    /**\n     * push.\n     *\n     * @param ele\n     */\n    public void push(E ele) {\n        if (mElements.size() > mSize) {\n            mElements.set(mSize, ele);\n        } else {\n            mElements.add(ele);\n        }\n        mSize++;\n    }\n\n    /**\n     * pop.\n     *\n     * @return the last element.\n     */\n    public E pop() {\n        if (mSize == 0) {\n            throw new EmptyStackException();\n        }\n        return mElements.set(--mSize, null);\n    }\n\n    /**\n     * peek.\n     *\n     * @return the last element.\n     */\n    public E peek() {\n        if (mSize == 0) {\n            throw new EmptyStackException();\n        }\n        return mElements.get(mSize - 1);\n    }\n\n    /**\n     * get.\n     *\n     * @param index index.\n     * @return element.\n     */\n    public E get(int index) {\n        if (index >= mSize || index + mSize < 0) {\n            throw new IndexOutOfBoundsException(\"Index: \" + index + \", Size: \" + mSize);\n        }\n\n        return index < 0 ? mElements.get(index + mSize) : mElements.get(index);\n    }\n\n    /**\n     * set.\n     *\n     * @param index index.\n     * @param value element.\n     * @return old element.\n     */\n    public E set(int index, E value) {\n        if (index >= mSize || index + mSize < 0) {\n            throw new IndexOutOfBoundsException(\"Index: \" + index + \", Size: \" + mSize);\n        }\n\n        return mElements.set(index < 0 ? index + mSize : index, value);\n    }\n\n    /**\n     * remove.\n     *\n     * @param index\n     * @return element\n     */\n    public E remove(int index) {\n        if (index >= mSize || index + mSize < 0) {\n            throw new IndexOutOfBoundsException(\"Index: \" + index + \", Size: \" + mSize);\n        }\n\n        E ret = mElements.remove(index < 0 ? index + mSize : index);\n        mSize--;\n        return ret;\n    }\n\n    /**\n     * get stack size.\n     *\n     * @return size.\n     */\n    public int size() {\n        return mSize;\n    }\n\n    /**\n     * is empty.\n     *\n     * @return empty or not.\n     */\n    public boolean isEmpty() {\n        return mSize == 0;\n    }\n\n    /**\n     * clear stack.\n     */\n    public void clear() {\n        mSize = 0;\n        mElements.clear();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringConstantFieldValuePredicate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Field;\nimport java.util.Set;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport static java.lang.reflect.Modifier.isFinal;\nimport static java.lang.reflect.Modifier.isPublic;\nimport static java.lang.reflect.Modifier.isStatic;\nimport static org.apache.dubbo.common.utils.FieldUtils.getFieldValue;\n\n/**\n * The constant field value {@link Predicate} for the specified {@link Class}\n *\n * @see Predicate\n * @since 2.7.8\n */\npublic class StringConstantFieldValuePredicate implements Predicate<String> {\n\n    private final Set<String> constantFieldValues;\n\n    public StringConstantFieldValuePredicate(Class<?> targetClass) {\n        this.constantFieldValues = getConstantFieldValues(targetClass);\n    }\n\n    public static Predicate<String> of(Class<?> targetClass) {\n        return new StringConstantFieldValuePredicate(targetClass);\n    }\n\n    private Set<String> getConstantFieldValues(Class<?> targetClass) {\n        return Stream.of(targetClass.getFields())\n                .filter(f -> isStatic(f.getModifiers())) // static\n                .filter(f -> isPublic(f.getModifiers())) // public\n                .filter(f -> isFinal(f.getModifiers())) // final\n                .map(this::getConstantValue)\n                .filter(v -> v instanceof String) // filters String type\n                .map(String.class::cast) // Casts String type\n                .collect(Collectors.toSet());\n    }\n\n    @Override\n    public boolean test(String s) {\n        return constantFieldValues.contains(s);\n    }\n\n    private Object getConstantValue(Field field) {\n        return getFieldValue(null, field);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.io.UnsafeStringWriter;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport static java.lang.String.valueOf;\nimport static java.util.Collections.emptySet;\nimport static java.util.Collections.unmodifiableSet;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.DOT_REGEX;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.HIDE_KEY_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SEPARATOR_REGEX;\nimport static org.apache.dubbo.common.constants.CommonConstants.UNDERLINE_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_JSON_CONVERT_EXCEPTION;\n\npublic final class StringUtils {\n\n    public static final String EMPTY_STRING = \"\";\n    public static final int INDEX_NOT_FOUND = -1;\n    public static final String[] EMPTY_STRING_ARRAY = new String[0];\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(StringUtils.class);\n    private static final Pattern KVP_PATTERN =\n            Pattern.compile(\"([_.a-zA-Z0-9][-_.a-zA-Z0-9]*)[=](.*)\"); // key value pair pattern.\n    private static final Pattern NUM_PATTERN = Pattern.compile(\"^\\\\d+$\");\n    private static final Pattern PARAMETERS_PATTERN =\n            Pattern.compile(\"^\\\\[((\\\\s*\\\\{\\\\s*[\\\\w_\\\\-\\\\.]+\\\\s*:\\\\s*.+?\\\\s*\\\\}\\\\s*,?\\\\s*)+)\\\\s*\\\\]$\");\n    private static final Pattern PAIR_PARAMETERS_PATTERN =\n            Pattern.compile(\"^\\\\{\\\\s*([\\\\w-_\\\\.]+)\\\\s*:\\\\s*(.+)\\\\s*\\\\}$\");\n    private static final int PAD_LIMIT = 8192;\n    private static final byte[] HEX2B;\n\n    /**\n     * @since 2.7.5\n     */\n    public static final char EQUAL_CHAR = '=';\n\n    public static final String EQUAL = valueOf(EQUAL_CHAR);\n\n    public static final char AND_CHAR = '&';\n\n    public static final String AND = valueOf(AND_CHAR);\n\n    public static final char SEMICOLON_CHAR = ';';\n\n    public static final String SEMICOLON = valueOf(SEMICOLON_CHAR);\n\n    public static final char QUESTION_MASK_CHAR = '?';\n\n    public static final String QUESTION_MASK = valueOf(QUESTION_MASK_CHAR);\n\n    public static final char SLASH_CHAR = '/';\n\n    public static final String SLASH = valueOf(SLASH_CHAR);\n\n    public static final char HYPHEN_CHAR = '-';\n\n    public static final String HYPHEN = valueOf(HYPHEN_CHAR);\n\n    static {\n        HEX2B = new byte[128];\n        Arrays.fill(HEX2B, (byte) -1);\n        HEX2B['0'] = (byte) 0;\n        HEX2B['1'] = (byte) 1;\n        HEX2B['2'] = (byte) 2;\n        HEX2B['3'] = (byte) 3;\n        HEX2B['4'] = (byte) 4;\n        HEX2B['5'] = (byte) 5;\n        HEX2B['6'] = (byte) 6;\n        HEX2B['7'] = (byte) 7;\n        HEX2B['8'] = (byte) 8;\n        HEX2B['9'] = (byte) 9;\n        HEX2B['A'] = (byte) 10;\n        HEX2B['B'] = (byte) 11;\n        HEX2B['C'] = (byte) 12;\n        HEX2B['D'] = (byte) 13;\n        HEX2B['E'] = (byte) 14;\n        HEX2B['F'] = (byte) 15;\n        HEX2B['a'] = (byte) 10;\n        HEX2B['b'] = (byte) 11;\n        HEX2B['c'] = (byte) 12;\n        HEX2B['d'] = (byte) 13;\n        HEX2B['e'] = (byte) 14;\n        HEX2B['f'] = (byte) 15;\n    }\n\n    private StringUtils() {}\n\n    /**\n     * Gets a CharSequence length or {@code 0} if the CharSequence is\n     * {@code null}.\n     *\n     * @param cs a CharSequence or {@code null}\n     * @return CharSequence length or {@code 0} if the CharSequence is\n     * {@code null}.\n     */\n    public static int length(final CharSequence cs) {\n        return cs == null ? 0 : cs.length();\n    }\n\n    /**\n     * <p>Repeat a String {@code repeat} times to form a\n     * new String.</p>\n     *\n     * <pre>\n     * StringUtils.repeat(null, 2) = null\n     * StringUtils.repeat(\"\", 0)   = \"\"\n     * StringUtils.repeat(\"\", 2)   = \"\"\n     * StringUtils.repeat(\"a\", 3)  = \"aaa\"\n     * StringUtils.repeat(\"ab\", 2) = \"abab\"\n     * StringUtils.repeat(\"a\", -2) = \"\"\n     * </pre>\n     *\n     * @param str    the String to repeat, may be null\n     * @param repeat number of times to repeat str, negative treated as zero\n     * @return a new String consisting of the original String repeated,\n     * {@code null} if null String input\n     */\n    public static String repeat(final String str, final int repeat) {\n        // Performance tuned for 2.0 (JDK1.4)\n\n        if (str == null) {\n            return null;\n        }\n        if (repeat <= 0) {\n            return EMPTY_STRING;\n        }\n        final int inputLength = str.length();\n        if (repeat == 1 || inputLength == 0) {\n            return str;\n        }\n        if (inputLength == 1 && repeat <= PAD_LIMIT) {\n            return repeat(str.charAt(0), repeat);\n        }\n\n        final int outputLength = inputLength * repeat;\n        switch (inputLength) {\n            case 1:\n                return repeat(str.charAt(0), repeat);\n            case 2:\n                final char ch0 = str.charAt(0);\n                final char ch1 = str.charAt(1);\n                final char[] output2 = new char[outputLength];\n                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {\n                    output2[i] = ch0;\n                    output2[i + 1] = ch1;\n                }\n                return new String(output2);\n            default:\n                final StringBuilder buf = new StringBuilder(outputLength);\n                for (int i = 0; i < repeat; i++) {\n                    buf.append(str);\n                }\n                return buf.toString();\n        }\n    }\n\n    /**\n     * <p>Repeat a String {@code repeat} times to form a\n     * new String, with a String separator injected each time. </p>\n     *\n     * <pre>\n     * StringUtils.repeat(null, null, 2) = null\n     * StringUtils.repeat(null, \"x\", 2)  = null\n     * StringUtils.repeat(\"\", null, 0)   = \"\"\n     * StringUtils.repeat(\"\", \"\", 2)     = \"\"\n     * StringUtils.repeat(\"\", \"x\", 3)    = \"xxx\"\n     * StringUtils.repeat(\"?\", \", \", 3)  = \"?, ?, ?\"\n     * </pre>\n     *\n     * @param str       the String to repeat, may be null\n     * @param separator the String to inject, may be null\n     * @param repeat    number of times to repeat str, negative treated as zero\n     * @return a new String consisting of the original String repeated,\n     * {@code null} if null String input\n     * @since 2.5\n     */\n    public static String repeat(final String str, final String separator, final int repeat) {\n        if (str == null || separator == null) {\n            return repeat(str, repeat);\n        }\n        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it\n        final String result = repeat(str + separator, repeat);\n        return removeEnd(result, separator);\n    }\n\n    /**\n     * <p>Removes a substring only if it is at the end of a source string,\n     * otherwise returns the source string.</p>\n     *\n     * <p>A {@code null} source string will return {@code null}.\n     * An empty (\"\") source string will return the empty string.\n     * A {@code null} search string will return the source string.</p>\n     *\n     * <pre>\n     * StringUtils.removeEnd(null, *)      = null\n     * StringUtils.removeEnd(\"\", *)        = \"\"\n     * StringUtils.removeEnd(*, null)      = *\n     * StringUtils.removeEnd(\"www.domain.com\", \".com.\")  = \"www.domain.com\"\n     * StringUtils.removeEnd(\"www.domain.com\", \".com\")   = \"www.domain\"\n     * StringUtils.removeEnd(\"www.domain.com\", \"domain\") = \"www.domain.com\"\n     * StringUtils.removeEnd(\"abc\", \"\")    = \"abc\"\n     * </pre>\n     *\n     * @param str    the source String to search, may be null\n     * @param remove the String to search for and remove, may be null\n     * @return the substring with the string removed if found,\n     * {@code null} if null String input\n     */\n    public static String removeEnd(final String str, final String remove) {\n        if (isAnyEmpty(str, remove)) {\n            return str;\n        }\n        if (str.endsWith(remove)) {\n            return str.substring(0, str.length() - remove.length());\n        }\n        return str;\n    }\n\n    /**\n     * <p>Returns padding using the specified delimiter repeated\n     * to a given length.</p>\n     *\n     * <pre>\n     * StringUtils.repeat('e', 0)  = \"\"\n     * StringUtils.repeat('e', 3)  = \"eee\"\n     * StringUtils.repeat('e', -2) = \"\"\n     * </pre>\n     *\n     * <p>Note: this method doesn't not support padding with\n     * <a href=\"http://www.unicode.org/glossary/#supplementary_character\">Unicode Supplementary Characters</a>\n     * as they require a pair of {@code char}s to be represented.\n     * If you are needing to support full I18N of your applications\n     * consider using {@link #repeat(String, int)} instead.\n     * </p>\n     *\n     * @param ch     character to repeat\n     * @param repeat number of times to repeat char, negative treated as zero\n     * @return String with repeated character\n     * @see #repeat(String, int)\n     */\n    public static String repeat(final char ch, final int repeat) {\n        final char[] buf = new char[repeat];\n        for (int i = repeat - 1; i >= 0; i--) {\n            buf[i] = ch;\n        }\n        return new String(buf);\n    }\n\n    /**\n     * <p>Strips any of a set of characters from the end of a String.</p>\n     *\n     * <p>A {@code null} input String returns {@code null}.\n     * An empty string (\"\") input returns the empty string.</p>\n     *\n     * <p>If the stripChars String is {@code null}, whitespace is\n     * stripped as defined by {@link Character#isWhitespace(char)}.</p>\n     *\n     * <pre>\n     * StringUtils.stripEnd(null, *)          = null\n     * StringUtils.stripEnd(\"\", *)            = \"\"\n     * StringUtils.stripEnd(\"abc\", \"\")        = \"abc\"\n     * StringUtils.stripEnd(\"abc\", null)      = \"abc\"\n     * StringUtils.stripEnd(\"  abc\", null)    = \"  abc\"\n     * StringUtils.stripEnd(\"abc  \", null)    = \"abc\"\n     * StringUtils.stripEnd(\" abc \", null)    = \" abc\"\n     * StringUtils.stripEnd(\"  abcyx\", \"xyz\") = \"  abc\"\n     * StringUtils.stripEnd(\"120.00\", \".0\")   = \"12\"\n     * </pre>\n     *\n     * @param str        the String to remove characters from, may be null\n     * @param stripChars the set of characters to remove, null treated as whitespace\n     * @return the stripped String, {@code null} if null String input\n     */\n    public static String stripEnd(final String str, final String stripChars) {\n        int end;\n        if (str == null || (end = str.length()) == 0) {\n            return str;\n        }\n\n        if (stripChars == null) {\n            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {\n                end--;\n            }\n        } else if (stripChars.isEmpty()) {\n            return str;\n        } else {\n            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {\n                end--;\n            }\n        }\n        return str.substring(0, end);\n    }\n\n    /**\n     * <p>Replaces all occurrences of a String within another String.</p>\n     *\n     * <p>A {@code null} reference passed to this method is a no-op.</p>\n     *\n     * <pre>\n     * StringUtils.replace(null, *, *)        = null\n     * StringUtils.replace(\"\", *, *)          = \"\"\n     * StringUtils.replace(\"any\", null, *)    = \"any\"\n     * StringUtils.replace(\"any\", *, null)    = \"any\"\n     * StringUtils.replace(\"any\", \"\", *)      = \"any\"\n     * StringUtils.replace(\"aba\", \"a\", null)  = \"aba\"\n     * StringUtils.replace(\"aba\", \"a\", \"\")    = \"b\"\n     * StringUtils.replace(\"aba\", \"a\", \"z\")   = \"zbz\"\n     * </pre>\n     *\n     * @param text         text to search and replace in, may be null\n     * @param searchString the String to search for, may be null\n     * @param replacement  the String to replace it with, may be null\n     * @return the text with any replacements processed,\n     * {@code null} if null String input\n     * @see #replace(String text, String searchString, String replacement, int max)\n     */\n    public static String replace(final String text, final String searchString, final String replacement) {\n        return replace(text, searchString, replacement, -1);\n    }\n\n    /**\n     * <p>Replaces a String with another String inside a larger String,\n     * for the first {@code max} values of the search String.</p>\n     *\n     * <p>A {@code null} reference passed to this method is a no-op.</p>\n     *\n     * <pre>\n     * StringUtils.replace(null, *, *, *)         = null\n     * StringUtils.replace(\"\", *, *, *)           = \"\"\n     * StringUtils.replace(\"any\", null, *, *)     = \"any\"\n     * StringUtils.replace(\"any\", *, null, *)     = \"any\"\n     * StringUtils.replace(\"any\", \"\", *, *)       = \"any\"\n     * StringUtils.replace(\"any\", *, *, 0)        = \"any\"\n     * StringUtils.replace(\"abaa\", \"a\", null, -1) = \"abaa\"\n     * StringUtils.replace(\"abaa\", \"a\", \"\", -1)   = \"b\"\n     * StringUtils.replace(\"abaa\", \"a\", \"z\", 0)   = \"abaa\"\n     * StringUtils.replace(\"abaa\", \"a\", \"z\", 1)   = \"zbaa\"\n     * StringUtils.replace(\"abaa\", \"a\", \"z\", 2)   = \"zbza\"\n     * StringUtils.replace(\"abaa\", \"a\", \"z\", -1)  = \"zbzz\"\n     * </pre>\n     *\n     * @param text         text to search and replace in, may be null\n     * @param searchString the String to search for, may be null\n     * @param replacement  the String to replace it with, may be null\n     * @param max          maximum number of values to replace, or {@code -1} if no maximum\n     * @return the text with any replacements processed,\n     * {@code null} if null String input\n     */\n    public static String replace(final String text, final String searchString, final String replacement, int max) {\n        if (isAnyEmpty(text, searchString) || replacement == null || max == 0) {\n            return text;\n        }\n        int start = 0;\n        int end = text.indexOf(searchString, start);\n        if (end == INDEX_NOT_FOUND) {\n            return text;\n        }\n        final int replLength = searchString.length();\n        int increase = replacement.length() - replLength;\n        increase = increase < 0 ? 0 : increase;\n        increase *= max < 0 ? 16 : max > 64 ? 64 : max;\n        final StringBuilder buf = new StringBuilder(text.length() + increase);\n        while (end != INDEX_NOT_FOUND) {\n            buf.append(text, start, end).append(replacement);\n            start = end + replLength;\n            if (--max == 0) {\n                break;\n            }\n            end = text.indexOf(searchString, start);\n        }\n        buf.append(text.substring(start));\n        return buf.toString();\n    }\n\n    public static boolean isBlank(CharSequence cs) {\n        int strLen;\n        if (cs == null || (strLen = cs.length()) == 0) {\n            return true;\n        }\n        for (int i = 0; i < strLen; i++) {\n            if (!Character.isWhitespace(cs.charAt(i))) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * is not blank string.\n     *\n     * @param cs source string.\n     * @return is not blank.\n     */\n    public static boolean isNotBlank(CharSequence cs) {\n        return !isBlank(cs);\n    }\n\n    /**\n     * Check the cs String whether contains non whitespace characters.\n     *\n     * @param cs\n     * @return\n     */\n    public static boolean hasText(CharSequence cs) {\n        return !isBlank(cs);\n    }\n\n    /**\n     * is empty string.\n     *\n     * @param str source string.\n     * @return is empty.\n     */\n    public static boolean isEmpty(String str) {\n        return str == null || str.isEmpty();\n    }\n\n    /**\n     * <p>Checks if the strings contain empty or null elements. <p/>\n     *\n     * <pre>\n     * StringUtils.isNoneEmpty(null)            = false\n     * StringUtils.isNoneEmpty(\"\")              = false\n     * StringUtils.isNoneEmpty(\" \")             = true\n     * StringUtils.isNoneEmpty(\"abc\")           = true\n     * StringUtils.isNoneEmpty(\"abc\", \"def\")    = true\n     * StringUtils.isNoneEmpty(\"abc\", null)     = false\n     * StringUtils.isNoneEmpty(\"abc\", \"\")       = false\n     * StringUtils.isNoneEmpty(\"abc\", \" \")      = true\n     * </pre>\n     *\n     * @param ss the strings to check\n     * @return {@code true} if all strings are not empty or null\n     */\n    public static boolean isNoneEmpty(final String... ss) {\n        if (ArrayUtils.isEmpty(ss)) {\n            return false;\n        }\n        for (final String s : ss) {\n            if (isEmpty(s)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * <p>Checks if the strings contain at least on empty or null element. <p/>\n     *\n     * <pre>\n     * StringUtils.isAnyEmpty(null)            = true\n     * StringUtils.isAnyEmpty(\"\")              = true\n     * StringUtils.isAnyEmpty(\" \")             = false\n     * StringUtils.isAnyEmpty(\"abc\")           = false\n     * StringUtils.isAnyEmpty(\"abc\", \"def\")    = false\n     * StringUtils.isAnyEmpty(\"abc\", null)     = true\n     * StringUtils.isAnyEmpty(\"abc\", \"\")       = true\n     * StringUtils.isAnyEmpty(\"abc\", \" \")      = false\n     * </pre>\n     *\n     * @param ss the strings to check\n     * @return {@code true} if at least one in the strings is empty or null\n     */\n    public static boolean isAnyEmpty(final String... ss) {\n        return !isNoneEmpty(ss);\n    }\n\n    /**\n     * is not empty string.\n     *\n     * @param str source string.\n     * @return is not empty.\n     */\n    public static boolean isNotEmpty(String str) {\n        return !isEmpty(str);\n    }\n\n    /**\n     * if s1 is null and s2 is null, then return true\n     *\n     * @param s1 str1\n     * @param s2 str2\n     * @return equals\n     */\n    public static boolean isEquals(String s1, String s2) {\n        if (s1 == null && s2 == null) {\n            return true;\n        }\n        if (s1 == null || s2 == null) {\n            return false;\n        }\n        return s1.equals(s2);\n    }\n\n    /**\n     * is positive integer or zero string.\n     *\n     * @param str a string\n     * @return is positive integer or zero\n     */\n    public static boolean isNumber(String str) {\n        return isNotEmpty(str) && NUM_PATTERN.matcher(str).matches();\n    }\n\n    /**\n     * parse str to Integer(if str is not number or n < 0, then return 0)\n     *\n     * @param str a number str\n     * @return positive integer or zero\n     */\n    public static int parseInteger(String str) {\n        return isNumber(str) ? Integer.parseInt(str) : 0;\n    }\n\n    /**\n     * parse str to Long(if str is not number or n < 0, then return 0)\n     *\n     * @param str a number str\n     * @return positive long or zero\n     */\n    public static long parseLong(String str) {\n        return isNumber(str) ? Long.parseLong(str) : 0;\n    }\n\n    /**\n     * Returns true if s is a legal Java identifier.<p>\n     * <a href=\"http://www.exampledepot.com/egs/java.lang/IsJavaId.html\">more info.</a>\n     */\n    public static boolean isJavaIdentifier(String s) {\n        if (isEmpty(s) || !Character.isJavaIdentifierStart(s.charAt(0))) {\n            return false;\n        }\n        for (int i = 1; i < s.length(); i++) {\n            if (!Character.isJavaIdentifierPart(s.charAt(i))) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public static boolean isContains(String values, String value) {\n        return isNotEmpty(values) && isContains(COMMA_SPLIT_PATTERN.split(values), value);\n    }\n\n    public static boolean isContains(String str, char ch) {\n        return isNotEmpty(str) && str.indexOf(ch) >= 0;\n    }\n\n    public static boolean isNotContains(String str, char ch) {\n        return !isContains(str, ch);\n    }\n\n    /**\n     * @param values\n     * @param value\n     * @return contains\n     */\n    public static boolean isContains(String[] values, String value) {\n        if (isNotEmpty(value) && ArrayUtils.isNotEmpty(values)) {\n            for (String v : values) {\n                if (value.equals(v)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    public static boolean isNumeric(String str, boolean allowDot) {\n        if (str == null || str.isEmpty()) {\n            return false;\n        }\n        boolean hasDot = false;\n        int sz = str.length();\n        for (int i = 0; i < sz; i++) {\n            if (str.charAt(i) == '.') {\n                if (hasDot || !allowDot) {\n                    return false;\n                }\n                hasDot = true;\n                continue;\n            }\n            if (!Character.isDigit(str.charAt(i))) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * @param e\n     * @return string\n     */\n    public static String toString(Throwable e) {\n        UnsafeStringWriter w = new UnsafeStringWriter();\n        PrintWriter p = new PrintWriter(w);\n        p.print(e.getClass().getName());\n        if (e.getMessage() != null) {\n            p.print(\": \" + e.getMessage());\n        }\n        p.println();\n        try {\n            e.printStackTrace(p);\n            return w.toString();\n        } finally {\n            p.close();\n        }\n    }\n\n    /**\n     * @param msg\n     * @param e\n     * @return string\n     */\n    public static String toString(String msg, Throwable e) {\n        UnsafeStringWriter w = new UnsafeStringWriter();\n        w.write(msg + \"\\n\");\n        PrintWriter p = new PrintWriter(w);\n        try {\n            e.printStackTrace(p);\n            return w.toString();\n        } finally {\n            p.close();\n        }\n    }\n\n    /**\n     * translate.\n     *\n     * @param src  source string.\n     * @param from src char table.\n     * @param to   target char table.\n     * @return String.\n     */\n    public static String translate(String src, String from, String to) {\n        if (isEmpty(src)) {\n            return src;\n        }\n        StringBuilder sb = null;\n        int ix;\n        char c;\n        for (int i = 0, len = src.length(); i < len; i++) {\n            c = src.charAt(i);\n            ix = from.indexOf(c);\n            if (ix == -1) {\n                if (sb != null) {\n                    sb.append(c);\n                }\n            } else {\n                if (sb == null) {\n                    sb = new StringBuilder(len);\n                    sb.append(src, 0, i);\n                }\n                if (ix < to.length()) {\n                    sb.append(to.charAt(ix));\n                }\n            }\n        }\n        return sb == null ? src : sb.toString();\n    }\n\n    /**\n     * split.\n     *\n     * @param ch char.\n     * @return string array.\n     */\n    public static String[] split(String str, char ch) {\n        if (isEmpty(str)) {\n            return EMPTY_STRING_ARRAY;\n        }\n        return splitToList0(str, ch).toArray(EMPTY_STRING_ARRAY);\n    }\n\n    private static List<String> splitToList0(String str, char ch) {\n        List<String> result = new ArrayList<>();\n        int ix = 0, len = str.length();\n        for (int i = 0; i < len; i++) {\n            if (str.charAt(i) == ch) {\n                result.add(str.substring(ix, i));\n                ix = i + 1;\n            }\n        }\n\n        if (ix >= 0) {\n            result.add(str.substring(ix));\n        }\n        return result;\n    }\n\n    /**\n     * Splits String around matches of the given character.\n     * <p>\n     * Note: Compare with {@link StringUtils#split(String, char)}, this method reduce memory copy.\n     */\n    public static List<String> splitToList(String str, char ch) {\n        if (isEmpty(str)) {\n            return Collections.emptyList();\n        }\n        return splitToList0(str, ch);\n    }\n\n    /**\n     * Split the specified value to be a {@link Set}\n     *\n     * @param value         the content to be split\n     * @param separatorChar a char to separate\n     * @return non-null read-only {@link Set}\n     * @since 2.7.8\n     */\n    public static Set<String> splitToSet(String value, char separatorChar) {\n        return splitToSet(value, separatorChar, false);\n    }\n\n    /**\n     * Split the specified value to be a {@link Set}\n     *\n     * @param value         the content to be split\n     * @param separatorChar a char to separate\n     * @param trimElements  require to trim the elements or not\n     * @return non-null read-only {@link Set}\n     * @since 2.7.8\n     */\n    public static Set<String> splitToSet(String value, char separatorChar, boolean trimElements) {\n        List<String> values = splitToList(value, separatorChar);\n        int size = values.size();\n\n        if (size < 1) { // empty condition\n            return emptySet();\n        }\n\n        if (!trimElements) { // Do not require to trim the elements\n            return new LinkedHashSet(values);\n        }\n\n        return unmodifiableSet(values.stream().map(String::trim).collect(LinkedHashSet::new, Set::add, Set::addAll));\n    }\n\n    /**\n     * join string.\n     *\n     * @param array String array.\n     * @return String.\n     */\n    public static String join(String[] array) {\n        if (ArrayUtils.isEmpty(array)) {\n            return EMPTY_STRING;\n        }\n        StringBuilder sb = new StringBuilder();\n        for (String s : array) {\n            sb.append(s);\n        }\n        return sb.toString();\n    }\n\n    /**\n     * join string like javascript.\n     *\n     * @param array String array.\n     * @param split split\n     * @return String.\n     */\n    public static String join(String[] array, char split) {\n        if (ArrayUtils.isEmpty(array)) {\n            return EMPTY_STRING;\n        }\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < array.length; i++) {\n            if (i > 0) {\n                sb.append(split);\n            }\n            sb.append(array[i]);\n        }\n        return sb.toString();\n    }\n\n    /**\n     * join string like javascript.\n     *\n     * @param array String array.\n     * @param split split\n     * @return String.\n     */\n    public static String join(String[] array, String split) {\n        if (ArrayUtils.isEmpty(array)) {\n            return EMPTY_STRING;\n        }\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < array.length; i++) {\n            if (i > 0) {\n                sb.append(split);\n            }\n            sb.append(array[i]);\n        }\n        return sb.toString();\n    }\n\n    public static String join(Collection<String> coll, String split) {\n        if (CollectionUtils.isEmpty(coll)) {\n            return EMPTY_STRING;\n        }\n\n        StringBuilder sb = new StringBuilder();\n        boolean isFirst = true;\n        for (String s : coll) {\n            if (isFirst) {\n                isFirst = false;\n            } else {\n                sb.append(split);\n            }\n            sb.append(s);\n        }\n        return sb.toString();\n    }\n\n    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {\n        if (ArrayUtils.isEmpty(array)) {\n            return EMPTY_STRING;\n        }\n        if (endIndex - startIndex <= 0) {\n            return EMPTY_STRING;\n        }\n        StringBuilder sb = new StringBuilder();\n        for (int i = startIndex; i < endIndex; i++) {\n            if (i > 0) {\n                sb.append(delimiter);\n            }\n            sb.append(array[i]);\n        }\n        return sb.toString();\n    }\n\n    /**\n     * parse key-value pair.\n     *\n     * @param str           string.\n     * @param itemSeparator item separator.\n     * @return key-value map;\n     */\n    private static Map<String, String> parseKeyValuePair(String str, String itemSeparator) {\n        String[] tmp = str.split(itemSeparator);\n        Map<String, String> map = new HashMap<>(tmp.length);\n        for (int i = 0; i < tmp.length; i++) {\n            Matcher matcher = KVP_PATTERN.matcher(tmp[i]);\n            if (!matcher.matches()) {\n                continue;\n            }\n            map.put(matcher.group(1), matcher.group(2));\n        }\n        return map;\n    }\n\n    public static String getQueryStringValue(String qs, String key) {\n        Map<String, String> map = parseQueryString(qs);\n        return map.get(key);\n    }\n\n    /**\n     * parse query string to Parameters.\n     *\n     * @param qs query string.\n     * @return Parameters instance.\n     */\n    public static Map<String, String> parseQueryString(String qs) {\n        if (isEmpty(qs)) {\n            return new HashMap<>();\n        }\n        return parseKeyValuePair(qs, \"\\\\&\");\n    }\n\n    public static String getServiceKey(Map<String, String> ps) {\n        StringBuilder buf = new StringBuilder();\n        String group = ps.get(GROUP_KEY);\n        if (isNotEmpty(group)) {\n            buf.append(group).append('/');\n        }\n        buf.append(ps.get(INTERFACE_KEY));\n        String version = ps.get(VERSION_KEY);\n        if (isNotEmpty(group)) {\n            buf.append(':').append(version);\n        }\n        return buf.toString();\n    }\n\n    public static String toQueryString(Map<String, String> ps) {\n        StringBuilder buf = new StringBuilder();\n        if (ps != null && ps.size() > 0) {\n            for (Map.Entry<String, String> entry : new TreeMap<String, String>(ps).entrySet()) {\n                String key = entry.getKey();\n                String value = entry.getValue();\n                if (isNoneEmpty(key, value)) {\n                    if (buf.length() > 0) {\n                        buf.append('&');\n                    }\n                    buf.append(key);\n                    buf.append('=');\n                    buf.append(value);\n                }\n            }\n        }\n        return buf.toString();\n    }\n\n    public static String camelToSplitName(String camelName, String split) {\n        if (isEmpty(camelName)) {\n            return camelName;\n        }\n        if (!isWord(camelName)) {\n            // convert Ab-Cd-Ef to ab-cd-ef\n            if (isSplitCase(camelName, split.charAt(0))) {\n                return camelName.toLowerCase();\n            }\n            // not camel case\n            return camelName;\n        }\n\n        StringBuilder buf = null;\n        for (int i = 0; i < camelName.length(); i++) {\n            char ch = camelName.charAt(i);\n            if (ch >= 'A' && ch <= 'Z') {\n                if (buf == null) {\n                    buf = new StringBuilder();\n                    if (i > 0) {\n                        buf.append(camelName, 0, i);\n                    }\n                }\n                if (i > 0) {\n                    buf.append(split);\n                }\n                buf.append(Character.toLowerCase(ch));\n            } else if (buf != null) {\n                buf.append(ch);\n            }\n        }\n        return buf == null ? camelName.toLowerCase() : buf.toString().toLowerCase();\n    }\n\n    private static boolean isSplitCase(String str, char separator) {\n        if (str == null) {\n            return false;\n        }\n        return str.chars().allMatch(ch -> (ch == separator) || isWord((char) ch));\n    }\n\n    private static boolean isWord(String str) {\n        if (str == null) {\n            return false;\n        }\n        return str.chars().allMatch(ch -> isWord((char) ch));\n    }\n\n    private static boolean isWord(char ch) {\n        if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Convert snake_case or SNAKE_CASE to kebab-case.\n     * <p>\n     * NOTE: Return itself if it's not a snake case.\n     *\n     * @param snakeName\n     * @param split\n     * @return\n     */\n    public static String snakeToSplitName(String snakeName, String split) {\n        String lowerCase = snakeName.toLowerCase();\n        if (isSnakeCase(snakeName)) {\n            return replace(lowerCase, \"_\", split);\n        }\n        return snakeName;\n    }\n\n    protected static boolean isSnakeCase(String str) {\n        return str.contains(\"_\") || str.equals(str.toLowerCase()) || str.equals(str.toUpperCase());\n    }\n\n    /**\n     * Convert camelCase or snake_case/SNAKE_CASE to kebab-case\n     *\n     * @param str\n     * @param split\n     * @return\n     */\n    public static String convertToSplitName(String str, String split) {\n        if (isSnakeCase(str)) {\n            return snakeToSplitName(str, split);\n        } else {\n            return camelToSplitName(str, split);\n        }\n    }\n\n    public static String toArgumentString(Object[] args) {\n        StringBuilder buf = new StringBuilder();\n        for (Object arg : args) {\n            if (buf.length() > 0) {\n                buf.append(COMMA_SEPARATOR);\n            }\n            if (arg == null || ReflectUtils.isPrimitives(arg.getClass())) {\n                buf.append(arg);\n            } else {\n                try {\n                    buf.append(JsonUtils.toJson(arg));\n                } catch (Exception e) {\n                    logger.warn(COMMON_JSON_CONVERT_EXCEPTION, \"\", \"\", e.getMessage(), e);\n                    buf.append(arg);\n                }\n            }\n        }\n        return buf.toString();\n    }\n\n    public static String trim(String str) {\n        return str == null ? null : str.trim();\n    }\n\n    public static String toURLKey(String key) {\n        return key.toLowerCase().replaceAll(SEPARATOR_REGEX, HIDE_KEY_PREFIX);\n    }\n\n    public static String toOSStyleKey(String key) {\n        key = key.toUpperCase().replaceAll(DOT_REGEX, UNDERLINE_SEPARATOR);\n        if (!key.startsWith(\"DUBBO_\")) {\n            key = \"DUBBO_\" + key;\n        }\n        return key;\n    }\n\n    public static boolean isAllUpperCase(String str) {\n        if (str != null && !isEmpty(str)) {\n            int sz = str.length();\n\n            for (int i = 0; i < sz; ++i) {\n                if (!Character.isUpperCase(str.charAt(i))) {\n                    return false;\n                }\n            }\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public static String[] delimitedListToStringArray(String str, String delimiter) {\n        return delimitedListToStringArray(str, delimiter, (String) null);\n    }\n\n    public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) {\n        if (str == null) {\n            return new String[0];\n        } else if (delimiter == null) {\n            return new String[] {str};\n        } else {\n            List<String> result = new ArrayList();\n            int pos;\n            if (\"\".equals(delimiter)) {\n                for (pos = 0; pos < str.length(); ++pos) {\n                    result.add(deleteAny(str.substring(pos, pos + 1), charsToDelete));\n                }\n            } else {\n                int delPos;\n                for (pos = 0; (delPos = str.indexOf(delimiter, pos)) != -1; pos = delPos + delimiter.length()) {\n                    result.add(deleteAny(str.substring(pos, delPos), charsToDelete));\n                }\n\n                if (str.length() > 0 && pos <= str.length()) {\n                    result.add(deleteAny(str.substring(pos), charsToDelete));\n                }\n            }\n\n            return toStringArray((Collection) result);\n        }\n    }\n\n    public static String arrayToDelimitedString(Object[] arr, String delim) {\n        if (ArrayUtils.isEmpty(arr)) {\n            return \"\";\n        } else if (arr.length == 1) {\n            return nullSafeToString(arr[0]);\n        } else {\n            StringBuilder sb = new StringBuilder();\n\n            for (int i = 0; i < arr.length; ++i) {\n                if (i > 0) {\n                    sb.append(delim);\n                }\n\n                sb.append(arr[i]);\n            }\n\n            return sb.toString();\n        }\n    }\n\n    public static String deleteAny(String inString, String charsToDelete) {\n        if (isNotEmpty(inString) && isNotEmpty(charsToDelete)) {\n            StringBuilder sb = new StringBuilder(inString.length());\n\n            for (int i = 0; i < inString.length(); ++i) {\n                char c = inString.charAt(i);\n                if (charsToDelete.indexOf(c) == -1) {\n                    sb.append(c);\n                }\n            }\n\n            return sb.toString();\n        } else {\n            return inString;\n        }\n    }\n\n    public static String[] toStringArray(Collection<String> collection) {\n        return (String[]) collection.toArray(new String[0]);\n    }\n\n    public static String nullSafeToString(Object obj) {\n        if (obj == null) {\n            return \"null\";\n        } else if (obj instanceof String) {\n            return (String) obj;\n        } else {\n            String str = obj.toString();\n            return str != null ? str : \"\";\n        }\n    }\n\n    /**\n     * Decode parameters string to map\n     *\n     * @param rawParameters format like '[{a:b},{c:d}]'\n     * @return\n     */\n    public static Map<String, String> parseParameters(String rawParameters) {\n        if (StringUtils.isBlank(rawParameters)) {\n            return Collections.emptyMap();\n        }\n        Matcher matcher = PARAMETERS_PATTERN.matcher(rawParameters);\n        if (!matcher.matches()) {\n            return Collections.emptyMap();\n        }\n\n        String pairs = matcher.group(1);\n        String[] pairArr = pairs.split(\"\\\\s*,\\\\s*\");\n\n        Map<String, String> parameters = new HashMap<>();\n        for (String pair : pairArr) {\n            Matcher pairMatcher = PAIR_PARAMETERS_PATTERN.matcher(pair);\n            if (pairMatcher.matches()) {\n                parameters.put(pairMatcher.group(1), pairMatcher.group(2));\n            }\n        }\n        return parameters;\n    }\n\n    /**\n     * Encode parameters map to string, like '[{a:b},{c:d}]'\n     *\n     * @param params\n     * @return\n     */\n    public static String encodeParameters(Map<String, String> params) {\n        if (params == null || params.isEmpty()) {\n            return null;\n        }\n\n        StringBuilder sb = new StringBuilder();\n        sb.append('[');\n        params.forEach((key, value) -> {\n            // {key:value},\n            if (hasText(value)) {\n                sb.append('{').append(key).append(':').append(value).append(\"},\");\n            }\n        });\n        // delete last separator ','\n        if (sb.charAt(sb.length() - 1) == ',') {\n            sb.deleteCharAt(sb.length() - 1);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    public static int decodeHexNibble(final char c) {\n        // Character.digit() is not used here, as it addresses a larger\n        // set of characters (both ASCII and full-width latin letters).\n        byte[] hex2b = HEX2B;\n        return c < hex2b.length ? hex2b[c] : -1;\n    }\n\n    /**\n     * Decode a 2-digit hex byte from within a string.\n     */\n    public static byte decodeHexByte(CharSequence s, int pos) {\n        int hi = decodeHexNibble(s.charAt(pos));\n        int lo = decodeHexNibble(s.charAt(pos + 1));\n        if (hi == -1 || lo == -1) {\n            throw new IllegalArgumentException(\n                    String.format(\"invalid hex byte '%s' at index %d of '%s'\", s.subSequence(pos, pos + 2), pos, s));\n        }\n        return (byte) ((hi << 4) + lo);\n    }\n\n    /**\n     * Creates a comma-delimited string from one or more string values.\n     *\n     * @param one    the first string value\n     * @param others additional string values\n     * @return the combined string, or null if the first value is null\n     * @since 2.7.8\n     */\n    public static String toCommaDelimitedString(String one, String... others) {\n        if (one == null) {\n            return null;\n        }\n        if (others == null) {\n            return one;\n        }\n        String another = arrayToDelimitedString(others, COMMA_SEPARATOR);\n        return isEmpty(another) ? one : one + COMMA_SEPARATOR + another;\n    }\n\n    /**\n     * Test str whether starts with the prefix ignore case.\n     */\n    public static boolean startsWithIgnoreCase(String str, String prefix) {\n        if (str == null || prefix == null || str.length() < prefix.length()) {\n            return false;\n        }\n        // return str.substring(0, prefix.length()).equalsIgnoreCase(prefix);\n        return str.regionMatches(true, 0, prefix, 0, prefix.length());\n    }\n\n    /**\n     * Returns the default string if the input string is empty, otherwise returns\n     * the input string itself\n     */\n    public static String defaultIf(String str, String defaultStr) {\n        return isEmpty(str) ? defaultStr : str;\n    }\n\n    /**\n     * Gets a substring from the specified String avoiding exceptions. If end index\n     * is not found, returns substring from start to the end\n     */\n    public static String substring(String str, int start, int end) {\n        if (str == null) {\n            return null;\n        }\n        return end == INDEX_NOT_FOUND ? str.substring(start) : str.substring(start, end);\n    }\n\n    /**\n     * Gets the substring before the first occurrence of a separator.\n     * <p>If nothing is found, returns the original string</p>\n     */\n    public static String substringBefore(String str, int separator) {\n        if (isEmpty(str)) {\n            return str;\n        }\n        int index = str.indexOf(separator);\n        return index == INDEX_NOT_FOUND ? str : str.substring(0, index);\n    }\n\n    /**\n     * Gets the substring after the first occurrence of a separator.\n     * <p>If nothing is found, the empty string is returned.</p>\n     */\n    public static String substringAfter(String str, int separator) {\n        if (isEmpty(str)) {\n            return str;\n        }\n        int index = str.indexOf(separator);\n        return index == INDEX_NOT_FOUND ? str : str.substring(index + 1);\n    }\n\n    /**\n     * Gets the substring before the last occurrence of a separator.\n     * <p>If nothing is found, returns the original string</p>\n     */\n    public static String substringBeforeLast(String str, int separator) {\n        if (isEmpty(str)) {\n            return str;\n        }\n        int index = str.lastIndexOf(separator);\n        return index == INDEX_NOT_FOUND ? str : str.substring(0, index);\n    }\n\n    /**\n     * Gets the substring after the last occurrence of a separator.\n     * <p>If nothing is found, the empty string is returned.</p>\n     */\n    public static String substringAfterLast(String str, int separator) {\n        if (isEmpty(str)) {\n            return str;\n        }\n        int index = str.lastIndexOf(separator);\n        return index == INDEX_NOT_FOUND || index == str.length() - 1 ? EMPTY_STRING : str.substring(index + 1);\n    }\n\n    /**\n     * Tokenize the given String into a String array.\n     * Trims tokens and omits empty tokens.\n     */\n    public static String[] tokenize(String str, char... separators) {\n        if (isEmpty(str)) {\n            return EMPTY_STRING_ARRAY;\n        }\n        return tokenizeToList(str, separators).toArray(EMPTY_STRING_ARRAY);\n    }\n\n    /**\n     * Splits a string into a list of tokens using specified separators, trimming whitespace\n     * and ignoring empty tokens. Uses comma as default separator if none provided.\n     */\n    public static List<String> tokenizeToList(String str, char... separators) {\n        if (isEmpty(str)) {\n            return Collections.emptyList();\n        }\n        if (separators == null || separators.length == 0) {\n            separators = new char[] {','};\n        }\n        List<String> tokens = new ArrayList<>();\n        int start = -1, end = 0;\n        int i = 0;\n        out:\n        for (int len = str.length(), sLen = separators.length; i < len; i++) {\n            char c = str.charAt(i);\n            for (int j = 0; j < sLen; j++) {\n                if (c == separators[j]) {\n                    if (start > -1) {\n                        tokens.add(str.substring(start, end + 1));\n                        start = -1;\n                    }\n                    continue out;\n                }\n            }\n            switch (c) {\n                case ' ':\n                case '\\t':\n                case '\\n':\n                case '\\r':\n                    break;\n                default:\n                    if (start == -1) {\n                        start = i;\n                    }\n                    end = i;\n                    break;\n            }\n        }\n        if (start > -1) {\n            String part = str.substring(start, end + 1);\n            if (tokens.isEmpty()) {\n                return Collections.singletonList(part);\n            }\n            tokens.add(part);\n        }\n        return tokens;\n    }\n\n    /**\n     * Converts string to Boolean based on common boolean representations.\n     * Supports values like 'true'/'false', 'yes'/'no', 'on'/'off', '1'/'0', etc.\n     * Returns null if the input cannot be parsed.\n     */\n    public static Boolean toBoolean(String value) {\n        if (isEmpty(value)) {\n            return null;\n        }\n        switch (value.length()) {\n            case 1:\n                char c = value.charAt(0);\n                if (c == '0' || c == 'n' || c == 'N') {\n                    return Boolean.FALSE;\n                }\n                if (c == '1' || c == 'y' || c == 'Y') {\n                    return Boolean.TRUE;\n                }\n                break;\n            case 2:\n                if (\"on\".equalsIgnoreCase(value)) {\n                    return Boolean.TRUE;\n                }\n                if (\"no\".equalsIgnoreCase(value)) {\n                    return Boolean.FALSE;\n                }\n                break;\n            case 3:\n                if (\"yes\".equalsIgnoreCase(value)) {\n                    return Boolean.TRUE;\n                }\n                if (\"off\".equalsIgnoreCase(value)) {\n                    return Boolean.TRUE;\n                }\n                break;\n            case 4:\n                if (\"true\".equalsIgnoreCase(value)) {\n                    return Boolean.TRUE;\n                }\n                break;\n            case 5:\n                if (\"false\".equalsIgnoreCase(value)) {\n                    return Boolean.FALSE;\n                }\n                break;\n            default:\n        }\n        return null;\n    }\n\n    public static boolean toBoolean(String value, boolean defaultValue) {\n        Boolean result = toBoolean(value);\n        return result == null ? defaultValue : result;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/SystemPropertyConfigUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\n\nimport java.lang.reflect.Field;\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class SystemPropertyConfigUtils {\n\n    private static Set<String> systemProperties = new HashSet<>();\n\n    static {\n        Class<?>[] classes = new Class[] {\n            CommonConstants.SystemProperty.class,\n            CommonConstants.ThirdPartyProperty.class,\n            CommonConstants.DubboProperty.class\n        };\n        for (Class<?> clazz : classes) {\n            Field[] fields = clazz.getDeclaredFields();\n            for (Field field : fields) {\n                try {\n                    assert systemProperties != null;\n                    Object value = field.get(null);\n                    if (value instanceof String) {\n                        systemProperties.add((String) value);\n                    }\n                } catch (IllegalAccessException e) {\n                    throw new IllegalStateException(\n                            String.format(\"%s does not have field of %s\", clazz.getName(), field.getName()));\n                }\n            }\n        }\n    }\n\n    /**\n     * Return property of VM.\n     *\n     * @param key\n     * @return\n     */\n    public static String getSystemProperty(String key) {\n        if (containsKey(key)) {\n            return System.getProperty(key);\n        } else {\n            throw new IllegalStateException(String.format(\n                    \"System property [%s] does not define in org.apache.dubbo.common.constants.CommonConstants\", key));\n        }\n    }\n\n    /**\n     * Return property of VM. If not exist, the default value is returned.\n     *\n     * @param key\n     * @param defaultValue\n     * @return\n     */\n    public static String getSystemProperty(String key, String defaultValue) {\n        if (containsKey(key)) {\n            return System.getProperty(key, defaultValue);\n        } else {\n            throw new IllegalStateException(String.format(\n                    \"System property [%s] does not define in org.apache.dubbo.common.constants.CommonConstants\", key));\n        }\n    }\n\n    /**\n     * Set property of VM.\n     *\n     * @param key\n     * @param value\n     * @return\n     */\n    public static String setSystemProperty(String key, String value) {\n        if (containsKey(key)) {\n            return System.setProperty(key, value);\n        } else {\n            throw new IllegalStateException(String.format(\n                    \"System property [%s] does not define in org.apache.dubbo.common.constants.CommonConstants\", key));\n        }\n    }\n\n    /**\n     * Clear property of VM.\n     *\n     * @param key\n     * @return\n     */\n    public static String clearSystemProperty(String key) {\n        if (containsKey(key)) {\n            return System.clearProperty(key);\n        } else {\n            throw new IllegalStateException(String.format(\n                    \"System property [%s] does not define in org.apache.dubbo.common.constants.CommonConstants\", key));\n        }\n    }\n\n    /**\n     * Check whether the key is valid.\n     *\n     * @param key\n     * @return\n     */\n    private static boolean containsKey(String key) {\n        return systemProperties.contains(key);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/TimeUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Provide currentTimeMillis acquisition for high-frequency access scenarios.\n */\npublic final class TimeUtils {\n\n    private static volatile long currentTimeMillis;\n\n    private static volatile boolean isTickerAlive = false;\n\n    private static volatile boolean isFallback = false;\n\n    private TimeUtils() {}\n\n    public static long currentTimeMillis() {\n        // When an exception occurs in the Ticker mechanism, fall back.\n        if (isFallback) {\n            return System.currentTimeMillis();\n        }\n\n        if (!isTickerAlive) {\n            try {\n                startTicker();\n            } catch (Exception e) {\n                isFallback = true;\n            }\n        }\n        return currentTimeMillis;\n    }\n\n    private static synchronized void startTicker() {\n        if (!isTickerAlive) {\n            currentTimeMillis = System.currentTimeMillis();\n            Thread ticker = new Thread(() -> {\n                while (isTickerAlive) {\n                    currentTimeMillis = System.currentTimeMillis();\n                    try {\n                        TimeUnit.MILLISECONDS.sleep(1);\n                    } catch (InterruptedException e) {\n                        isTickerAlive = false;\n                        Thread.currentThread().interrupt();\n                    } catch (Exception ignored) {\n                        //\n                    }\n                }\n            });\n            ticker.setDaemon(true);\n            ticker.setName(\"time-millis-ticker-thread\");\n            ticker.start();\n            Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n                isFallback = true;\n                ticker.interrupt();\n            }));\n            isTickerAlive = true;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/ToStringUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.config.AbstractConfig;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ToStringUtils {\n\n    private ToStringUtils() {}\n\n    public static String printToString(Object obj) {\n        if (obj == null) {\n            return \"null\";\n        }\n        try {\n            return JsonUtils.toJson(obj);\n        } catch (Throwable throwable) {\n            if (obj instanceof Object[]) {\n                return Arrays.toString((Object[]) obj);\n            }\n            return obj.toString();\n        }\n    }\n\n    public static String toString(Object obj) {\n        if (obj == null) {\n            return \"null\";\n        }\n        if (ClassUtils.isSimpleType(obj.getClass())) {\n            return obj.toString();\n        }\n        if (obj.getClass().isPrimitive()) {\n            return obj.toString();\n        }\n        if (obj instanceof Object[]) {\n            StringBuilder stringBuilder = new StringBuilder();\n            stringBuilder.append(\"[\");\n            Object[] objects = (Object[]) obj;\n            for (int i = 0; i < objects.length; i++) {\n                stringBuilder.append(toString(objects[i]));\n                if (i != objects.length - 1) {\n                    stringBuilder.append(\", \");\n                }\n            }\n            stringBuilder.append(\"]\");\n            return stringBuilder.toString();\n        }\n        if (obj instanceof List) {\n            StringBuilder stringBuilder = new StringBuilder();\n            stringBuilder.append(\"[\");\n            List list = (List) obj;\n            for (int i = 0; i < list.size(); i++) {\n                stringBuilder.append(toString(list.get(i)));\n                if (i != list.size() - 1) {\n                    stringBuilder.append(\", \");\n                }\n            }\n            stringBuilder.append(\"]\");\n            return stringBuilder.toString();\n        }\n        if (obj instanceof Map) {\n            StringBuilder stringBuilder = new StringBuilder();\n            stringBuilder.append(\"{\");\n            Map map = (Map) obj;\n            int i = 0;\n            for (Object key : map.keySet()) {\n                stringBuilder.append(toString(key));\n                stringBuilder.append(\"=\");\n                stringBuilder.append(toString(map.get(key)));\n                if (i != map.size() - 1) {\n                    stringBuilder.append(\", \");\n                }\n                i++;\n            }\n            stringBuilder.append(\"}\");\n            return stringBuilder.toString();\n        }\n        if (obj instanceof AbstractConfig) {\n            return obj.toString();\n        }\n        return obj.getClass() + \"@\" + Integer.toHexString(System.identityHashCode(obj));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/TypeUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport static java.util.Arrays.asList;\nimport static java.util.Collections.emptyList;\nimport static java.util.Collections.unmodifiableList;\nimport static java.util.stream.Collectors.toList;\nimport static java.util.stream.Collectors.toSet;\nimport static java.util.stream.StreamSupport.stream;\nimport static org.apache.dubbo.common.function.Predicates.and;\nimport static org.apache.dubbo.common.function.Streams.filterAll;\nimport static org.apache.dubbo.common.function.Streams.filterList;\nimport static org.apache.dubbo.common.utils.ClassUtils.getAllInterfaces;\nimport static org.apache.dubbo.common.utils.ClassUtils.getAllSuperClasses;\nimport static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom;\n\n/**\n * The utilities class for {@link Type}\n *\n * @since 2.7.6\n */\npublic interface TypeUtils {\n\n    Predicate<Class<?>> NON_OBJECT_TYPE_FILTER = t -> !Objects.equals(Object.class, t);\n\n    static boolean isParameterizedType(Type type) {\n        return type instanceof ParameterizedType;\n    }\n\n    static Type getRawType(Type type) {\n        if (isParameterizedType(type)) {\n            return ((ParameterizedType) type).getRawType();\n        } else {\n            return type;\n        }\n    }\n\n    static Class<?> getRawClass(Type type) {\n        Type rawType = getRawType(type);\n        if (isClass(rawType)) {\n            return (Class) rawType;\n        }\n        return null;\n    }\n\n    static boolean isClass(Type type) {\n        return type instanceof Class;\n    }\n\n    static <T> Class<T> findActualTypeArgument(Type type, Class<?> interfaceClass, int index) {\n        return (Class<T>) findActualTypeArguments(type, interfaceClass).get(index);\n    }\n\n    static List<Class<?>> findActualTypeArguments(Type type, Class<?> interfaceClass) {\n\n        List<Class<?>> actualTypeArguments = new ArrayList<>();\n\n        getAllGenericTypes(type, t -> isAssignableFrom(interfaceClass, getRawClass(t)))\n                .forEach(parameterizedType -> {\n                    Class<?> rawClass = getRawClass(parameterizedType);\n                    Type[] typeArguments = parameterizedType.getActualTypeArguments();\n                    for (int i = 0; i < typeArguments.length; i++) {\n                        Type typeArgument = typeArguments[i];\n                        if (typeArgument instanceof Class) {\n                            actualTypeArguments.add(i, (Class) typeArgument);\n                        }\n                    }\n                    Class<?> superClass = rawClass.getSuperclass();\n                    if (superClass != null) {\n                        actualTypeArguments.addAll(findActualTypeArguments(superClass, interfaceClass));\n                    }\n                });\n\n        return unmodifiableList(actualTypeArguments);\n    }\n\n    /**\n     * Get the specified types' generic types(including super classes and interfaces) that are assignable from {@link ParameterizedType} interface\n     *\n     * @param type        the specified type\n     * @param typeFilters one or more {@link Predicate}s to filter the {@link ParameterizedType} instance\n     * @return non-null read-only {@link List}\n     */\n    static List<ParameterizedType> getGenericTypes(Type type, Predicate<ParameterizedType>... typeFilters) {\n\n        Class<?> rawClass = getRawClass(type);\n\n        if (rawClass == null) {\n            return emptyList();\n        }\n\n        List<Type> genericTypes = new LinkedList<>();\n\n        genericTypes.add(rawClass.getGenericSuperclass());\n        genericTypes.addAll(asList(rawClass.getGenericInterfaces()));\n\n        return unmodifiableList(filterList(genericTypes, TypeUtils::isParameterizedType).stream()\n                .map(ParameterizedType.class::cast)\n                .filter(and(typeFilters))\n                .collect(toList()));\n    }\n\n    /**\n     * Get all generic types(including super classes and interfaces) that are assignable from {@link ParameterizedType} interface\n     *\n     * @param type        the specified type\n     * @param typeFilters one or more {@link Predicate}s to filter the {@link ParameterizedType} instance\n     * @return non-null read-only {@link List}\n     */\n    static List<ParameterizedType> getAllGenericTypes(Type type, Predicate<ParameterizedType>... typeFilters) {\n        List<ParameterizedType> allGenericTypes = new LinkedList<>();\n        // Add generic super classes\n        allGenericTypes.addAll(getAllGenericSuperClasses(type, typeFilters));\n        // Add generic super interfaces\n        allGenericTypes.addAll(getAllGenericInterfaces(type, typeFilters));\n        // wrap unmodifiable object\n        return unmodifiableList(allGenericTypes);\n    }\n\n    /**\n     * Get all generic super classes that are assignable from {@link ParameterizedType} interface\n     *\n     * @param type        the specified type\n     * @param typeFilters one or more {@link Predicate}s to filter the {@link ParameterizedType} instance\n     * @return non-null read-only {@link List}\n     */\n    static List<ParameterizedType> getAllGenericSuperClasses(Type type, Predicate<ParameterizedType>... typeFilters) {\n\n        Class<?> rawClass = getRawClass(type);\n\n        if (rawClass == null || rawClass.isInterface()) {\n            return emptyList();\n        }\n\n        List<Class<?>> allTypes = new LinkedList<>();\n        // Add current class\n        allTypes.add(rawClass);\n        // Add all super classes\n        allTypes.addAll(getAllSuperClasses(rawClass, NON_OBJECT_TYPE_FILTER));\n\n        List<ParameterizedType> allGenericSuperClasses = allTypes.stream()\n                .map(Class::getGenericSuperclass)\n                .filter(TypeUtils::isParameterizedType)\n                .map(ParameterizedType.class::cast)\n                .collect(Collectors.toList());\n\n        return unmodifiableList(filterAll(allGenericSuperClasses, typeFilters));\n    }\n\n    /**\n     * Get all generic interfaces that are assignable from {@link ParameterizedType} interface\n     *\n     * @param type        the specified type\n     * @param typeFilters one or more {@link Predicate}s to filter the {@link ParameterizedType} instance\n     * @return non-null read-only {@link List}\n     */\n    static List<ParameterizedType> getAllGenericInterfaces(Type type, Predicate<ParameterizedType>... typeFilters) {\n\n        Class<?> rawClass = getRawClass(type);\n\n        if (rawClass == null) {\n            return emptyList();\n        }\n\n        List<Class<?>> allTypes = new LinkedList<>();\n        // Add current class\n        allTypes.add(rawClass);\n        // Add all super classes\n        allTypes.addAll(getAllSuperClasses(rawClass, NON_OBJECT_TYPE_FILTER));\n        // Add all super interfaces\n        allTypes.addAll(getAllInterfaces(rawClass));\n\n        List<ParameterizedType> allGenericInterfaces = allTypes.stream()\n                .map(Class::getGenericInterfaces)\n                .map(Arrays::asList)\n                .flatMap(Collection::stream)\n                .filter(TypeUtils::isParameterizedType)\n                .map(ParameterizedType.class::cast)\n                .collect(toList());\n\n        return unmodifiableList(filterAll(allGenericInterfaces, typeFilters));\n    }\n\n    static String getClassName(Type type) {\n        return getRawType(type).getTypeName();\n    }\n\n    static Set<String> getClassNames(Iterable<? extends Type> types) {\n        return stream(types.spliterator(), false).map(TypeUtils::getClassName).collect(toSet());\n    }\n\n    static Class<?> getSuperGenericType(Class<?> clazz, int index) {\n        Class<?> result = getArgumentClass(clazz.getGenericSuperclass(), index);\n        return result == null ? getArgumentClass(ArrayUtils.first(clazz.getGenericInterfaces()), index) : result;\n    }\n\n    static Class<?> getArgumentClass(Type type, int index) {\n        if (type instanceof ParameterizedType) {\n            Type[] typeArgs = ((ParameterizedType) type).getActualTypeArguments();\n            if (index < typeArgs.length) {\n                Type typeArg = typeArgs[index];\n                if (typeArg instanceof Class) {\n                    return (Class<?>) typeArg;\n                } else if (typeArg instanceof ParameterizedType) {\n                    return (Class<?>) ((ParameterizedType) typeArg).getRawType();\n                }\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLStrParser;\nimport org.apache.dubbo.common.constants.RemotingConstants;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport static java.util.Collections.emptyMap;\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CLASSIFIER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.OVERRIDE_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ROUTE_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE;\n\npublic class UrlUtils {\n\n    /**\n     * Forbids the instantiation.\n     */\n    private UrlUtils() {\n        throw new UnsupportedOperationException(\"No instance of 'UrlUtils' for you! \");\n    }\n\n    /**\n     * in the url string,mark the param begin\n     */\n    private static final String URL_PARAM_STARTING_SYMBOL = \"?\";\n\n    public static URL parseURL(String address, Map<String, String> defaults) {\n        if (StringUtils.isEmpty(address)) {\n            throw new IllegalArgumentException(\"Address is not allowed to be empty, please re-enter.\");\n        }\n        String url;\n        if (address.contains(\"://\") || address.contains(URL_PARAM_STARTING_SYMBOL)) {\n            url = address;\n        } else {\n            String[] addresses = COMMA_SPLIT_PATTERN.split(address);\n            url = addresses[0];\n            if (addresses.length > 1) {\n                StringBuilder backup = new StringBuilder();\n                for (int i = 1; i < addresses.length; i++) {\n                    if (i > 1) {\n                        backup.append(',');\n                    }\n                    backup.append(addresses[i]);\n                }\n                url += URL_PARAM_STARTING_SYMBOL + RemotingConstants.BACKUP_KEY + \"=\" + backup.toString();\n            }\n        }\n        String defaultProtocol = defaults == null ? null : defaults.get(PROTOCOL_KEY);\n        if (StringUtils.isEmpty(defaultProtocol)) {\n            defaultProtocol = DUBBO_PROTOCOL;\n        }\n        String defaultUsername = defaults == null ? null : defaults.get(USERNAME_KEY);\n        String defaultPassword = defaults == null ? null : defaults.get(PASSWORD_KEY);\n        int defaultPort = StringUtils.parseInteger(defaults == null ? null : defaults.get(PORT_KEY));\n        String defaultPath = defaults == null ? null : defaults.get(PATH_KEY);\n        Map<String, String> defaultParameters = defaults == null ? null : new HashMap<>(defaults);\n        if (defaultParameters != null) {\n            defaultParameters.remove(PROTOCOL_KEY);\n            defaultParameters.remove(USERNAME_KEY);\n            defaultParameters.remove(PASSWORD_KEY);\n            defaultParameters.remove(HOST_KEY);\n            defaultParameters.remove(PORT_KEY);\n            defaultParameters.remove(PATH_KEY);\n        }\n        URL u = URL.cacheableValueOf(url);\n        boolean changed = false;\n        String protocol = u.getProtocol();\n        String username = u.getUsername();\n        String password = u.getPassword();\n        String host = u.getHost();\n        int port = u.getPort();\n        String path = u.getPath();\n        Map<String, String> parameters = new HashMap<>(u.getParameters());\n        if (StringUtils.isEmpty(protocol)) {\n            changed = true;\n            protocol = defaultProtocol;\n        }\n        if (StringUtils.isEmpty(username) && StringUtils.isNotEmpty(defaultUsername)) {\n            changed = true;\n            username = defaultUsername;\n        }\n        if (StringUtils.isEmpty(password) && StringUtils.isNotEmpty(defaultPassword)) {\n            changed = true;\n            password = defaultPassword;\n        }\n        /*if (u.isAnyHost() || u.isLocalHost()) {\n            changed = true;\n            host = NetUtils.getLocalHost();\n        }*/\n        if (port <= 0) {\n            if (defaultPort > 0) {\n                changed = true;\n                port = defaultPort;\n            } else {\n                changed = true;\n                port = 9090;\n            }\n        }\n        if (StringUtils.isEmpty(path)) {\n            if (StringUtils.isNotEmpty(defaultPath)) {\n                changed = true;\n                path = defaultPath;\n            }\n        }\n        if (defaultParameters != null && defaultParameters.size() > 0) {\n            for (Map.Entry<String, String> entry : defaultParameters.entrySet()) {\n                String key = entry.getKey();\n                String defaultValue = entry.getValue();\n                if (StringUtils.isNotEmpty(defaultValue)) {\n                    String value = parameters.get(key);\n                    if (StringUtils.isEmpty(value)) {\n                        changed = true;\n                        parameters.put(key, defaultValue);\n                    }\n                }\n            }\n        }\n        if (changed) {\n            u = new ServiceConfigURL(protocol, username, password, host, port, path, parameters);\n        }\n        return u;\n    }\n\n    public static List<URL> parseURLs(String address, Map<String, String> defaults) {\n        if (StringUtils.isEmpty(address)) {\n            throw new IllegalArgumentException(\"Address is not allowed to be empty, please re-enter.\");\n        }\n        String[] addresses = REGISTRY_SPLIT_PATTERN.split(address);\n        if (addresses == null || addresses.length == 0) {\n            throw new IllegalArgumentException(\n                    \"Addresses is not allowed to be empty, please re-enter.\"); // here won't be empty\n        }\n        List<URL> registries = new ArrayList<>();\n        for (String addr : addresses) {\n            registries.add(parseURL(addr, defaults));\n        }\n        return registries;\n    }\n\n    public static Map<String, Map<String, String>> convertRegister(Map<String, Map<String, String>> register) {\n        Map<String, Map<String, String>> newRegister = new HashMap<>();\n        for (Map.Entry<String, Map<String, String>> entry : register.entrySet()) {\n            String serviceName = entry.getKey();\n            Map<String, String> serviceUrls = entry.getValue();\n            if (StringUtils.isNotContains(serviceName, ':') && StringUtils.isNotContains(serviceName, '/')) {\n                for (Map.Entry<String, String> entry2 : serviceUrls.entrySet()) {\n                    String serviceUrl = entry2.getKey();\n                    String serviceQuery = entry2.getValue();\n                    Map<String, String> params = StringUtils.parseQueryString(serviceQuery);\n                    String group = params.get(GROUP_KEY);\n                    String version = params.get(VERSION_KEY);\n                    // params.remove(\"group\");\n                    // params.remove(\"version\");\n                    String name = serviceName;\n                    if (StringUtils.isNotEmpty(group)) {\n                        name = group + \"/\" + name;\n                    }\n                    if (StringUtils.isNotEmpty(version)) {\n                        name = name + \":\" + version;\n                    }\n                    Map<String, String> newUrls = newRegister.computeIfAbsent(name, k -> new HashMap<>());\n                    newUrls.put(serviceUrl, StringUtils.toQueryString(params));\n                }\n            } else {\n                newRegister.put(serviceName, serviceUrls);\n            }\n        }\n        return newRegister;\n    }\n\n    public static Map<String, String> convertSubscribe(Map<String, String> subscribe) {\n        Map<String, String> newSubscribe = new HashMap<>();\n\n        for (Map.Entry<String, String> entry : subscribe.entrySet()) {\n            String serviceName = entry.getKey();\n            String serviceQuery = entry.getValue();\n            if (StringUtils.isNotContains(serviceName, ':') && StringUtils.isNotContains(serviceName, '/')) {\n                Map<String, String> params = StringUtils.parseQueryString(serviceQuery);\n                String group = params.get(GROUP_KEY);\n                String version = params.get(VERSION_KEY);\n                // params.remove(\"group\");\n                // params.remove(\"version\");\n                String name = serviceName;\n                if (StringUtils.isNotEmpty(group)) {\n                    name = group + \"/\" + name;\n                }\n                if (StringUtils.isNotEmpty(version)) {\n                    name = name + \":\" + version;\n                }\n                newSubscribe.put(name, StringUtils.toQueryString(params));\n            } else {\n                newSubscribe.put(serviceName, serviceQuery);\n            }\n        }\n\n        return newSubscribe;\n    }\n\n    public static Map<String, Map<String, String>> revertRegister(Map<String, Map<String, String>> register) {\n        Map<String, Map<String, String>> newRegister = new HashMap<>();\n\n        for (Map.Entry<String, Map<String, String>> entry : register.entrySet()) {\n            String serviceName = entry.getKey();\n            Map<String, String> serviceUrls = entry.getValue();\n            if (StringUtils.isContains(serviceName, ':') && StringUtils.isContains(serviceName, '/')) {\n                for (Map.Entry<String, String> entry2 : serviceUrls.entrySet()) {\n                    String serviceUrl = entry2.getKey();\n                    String serviceQuery = entry2.getValue();\n                    Map<String, String> params = StringUtils.parseQueryString(serviceQuery);\n                    String name = serviceName;\n                    int i = name.indexOf('/');\n                    if (i >= 0) {\n                        params.put(GROUP_KEY, name.substring(0, i));\n                        name = name.substring(i + 1);\n                    }\n                    i = name.lastIndexOf(':');\n                    if (i >= 0) {\n                        params.put(VERSION_KEY, name.substring(i + 1));\n                        name = name.substring(0, i);\n                    }\n                    Map<String, String> newUrls = newRegister.computeIfAbsent(name, k -> new HashMap<String, String>());\n                    newUrls.put(serviceUrl, StringUtils.toQueryString(params));\n                }\n            } else {\n                newRegister.put(serviceName, serviceUrls);\n            }\n        }\n\n        return newRegister;\n    }\n\n    public static Map<String, String> revertSubscribe(Map<String, String> subscribe) {\n\n        Map<String, String> newSubscribe = new HashMap<>();\n\n        for (Map.Entry<String, String> entry : subscribe.entrySet()) {\n            String serviceName = entry.getKey();\n            String serviceQuery = entry.getValue();\n            if (StringUtils.isContains(serviceName, ':') && StringUtils.isContains(serviceName, '/')) {\n                Map<String, String> params = StringUtils.parseQueryString(serviceQuery);\n                String name = serviceName;\n                int i = name.indexOf('/');\n                if (i >= 0) {\n                    params.put(GROUP_KEY, name.substring(0, i));\n                    name = name.substring(i + 1);\n                }\n                i = name.lastIndexOf(':');\n                if (i >= 0) {\n                    params.put(VERSION_KEY, name.substring(i + 1));\n                    name = name.substring(0, i);\n                }\n                newSubscribe.put(name, StringUtils.toQueryString(params));\n            } else {\n                newSubscribe.put(serviceName, serviceQuery);\n            }\n        }\n        return newSubscribe;\n    }\n\n    public static Map<String, Map<String, String>> revertNotify(Map<String, Map<String, String>> notify) {\n        if (notify != null && notify.size() > 0) {\n            Map<String, Map<String, String>> newNotify = new HashMap<>();\n            for (Map.Entry<String, Map<String, String>> entry : notify.entrySet()) {\n                String serviceName = entry.getKey();\n                Map<String, String> serviceUrls = entry.getValue();\n                if (StringUtils.isNotContains(serviceName, ':') && StringUtils.isNotContains(serviceName, '/')) {\n                    if (CollectionUtils.isNotEmptyMap(serviceUrls)) {\n                        for (Map.Entry<String, String> entry2 : serviceUrls.entrySet()) {\n                            String url = entry2.getKey();\n                            String query = entry2.getValue();\n                            Map<String, String> params = StringUtils.parseQueryString(query);\n                            String group = params.get(GROUP_KEY);\n                            String version = params.get(VERSION_KEY);\n                            // params.remove(\"group\");\n                            // params.remove(\"version\");\n                            String name = serviceName;\n                            if (StringUtils.isNotEmpty(group)) {\n                                name = group + \"/\" + name;\n                            }\n                            if (StringUtils.isNotEmpty(version)) {\n                                name = name + \":\" + version;\n                            }\n                            Map<String, String> newUrls = newNotify.computeIfAbsent(name, k -> new HashMap<>());\n                            newUrls.put(url, StringUtils.toQueryString(params));\n                        }\n                    }\n                } else {\n                    newNotify.put(serviceName, serviceUrls);\n                }\n            }\n            return newNotify;\n        }\n        return notify;\n    }\n\n    // compatible for dubbo-2.0.0\n    public static List<String> revertForbid(List<String> forbid, Set<URL> subscribed) {\n        if (CollectionUtils.isNotEmpty(forbid)) {\n            List<String> newForbid = new ArrayList<>();\n            for (String serviceName : forbid) {\n                if (StringUtils.isNotContains(serviceName, ':') && StringUtils.isNotContains(serviceName, '/')) {\n                    for (URL url : subscribed) {\n                        if (serviceName.equals(url.getServiceInterface())) {\n                            newForbid.add(url.getServiceKey());\n                            break;\n                        }\n                    }\n                } else {\n                    newForbid.add(serviceName);\n                }\n            }\n            return newForbid;\n        }\n        return forbid;\n    }\n\n    public static URL getEmptyUrl(String service, String category) {\n        String group = null;\n        String version = null;\n        int i = service.indexOf('/');\n        if (i > 0) {\n            group = service.substring(0, i);\n            service = service.substring(i + 1);\n        }\n        i = service.lastIndexOf(':');\n        if (i > 0) {\n            version = service.substring(i + 1);\n            service = service.substring(0, i);\n        }\n        return URL.valueOf(EMPTY_PROTOCOL + \"://0.0.0.0/\" + service + URL_PARAM_STARTING_SYMBOL\n                + CATEGORY_KEY + \"=\" + category\n                + (group == null ? \"\" : \"&\" + GROUP_KEY + \"=\" + group)\n                + (version == null ? \"\" : \"&\" + VERSION_KEY + \"=\" + version));\n    }\n\n    public static boolean isMatchCategory(String category, String categories) {\n        if (categories == null || categories.length() == 0) {\n            return DEFAULT_CATEGORY.equals(category);\n        } else if (categories.contains(ANY_VALUE)) {\n            return true;\n        } else if (categories.contains(REMOVE_VALUE_PREFIX)) {\n            return !categories.contains(REMOVE_VALUE_PREFIX + category);\n        } else {\n            return categories.contains(category);\n        }\n    }\n\n    public static boolean isMatch(URL consumerUrl, URL providerUrl) {\n        String consumerInterface = consumerUrl.getServiceInterface();\n        String providerInterface = providerUrl.getServiceInterface();\n\n        // FIXME accept providerUrl with '*' as interface name, after carefully thought about all possible scenarios I\n        // think it's ok to add this condition.\n\n        // Return false if the consumer interface is not equals the provider interface,\n        // except one of the interface configurations is equals '*' (i.e. any value).\n        if (!(ANY_VALUE.equals(consumerInterface)\n                || ANY_VALUE.equals(providerInterface)\n                || StringUtils.isEquals(consumerInterface, providerInterface))) {\n            return false;\n        }\n\n        // If the category of provider URL does not match the category of consumer URL.\n        // Usually, the provider URL's category is empty, and the default category ('providers') is present.\n        // Hence, the category of the provider URL is 'providers'.\n        // Through observing of debugging process, I found that the category of the consumer URL is\n        // 'providers,configurators,routers'.\n        if (!isMatchCategory(providerUrl.getCategory(DEFAULT_CATEGORY), consumerUrl.getCategory(DEFAULT_CATEGORY))) {\n            return false;\n        }\n\n        // If the provider is not enabled, return false.\n        if (!providerUrl.getParameter(ENABLED_KEY, true) && !ANY_VALUE.equals(consumerUrl.getParameter(ENABLED_KEY))) {\n            return false;\n        }\n\n        // Obtain consumer's group, version and classifier.\n        String consumerGroup = consumerUrl.getGroup();\n        String consumerVersion = consumerUrl.getVersion();\n        String consumerClassifier = consumerUrl.getParameter(CLASSIFIER_KEY, ANY_VALUE);\n\n        // Obtain provider's group, version and classifier.\n        String providerGroup = providerUrl.getGroup();\n        String providerVersion = providerUrl.getVersion();\n        String providerClassifier = providerUrl.getParameter(CLASSIFIER_KEY, ANY_VALUE);\n\n        // If Group, Version, Classifier all matches, return true.\n        boolean groupMatches = ANY_VALUE.equals(consumerGroup)\n                || StringUtils.isEquals(consumerGroup, providerGroup)\n                || StringUtils.isContains(consumerGroup, providerGroup);\n        boolean versionMatches =\n                ANY_VALUE.equals(consumerVersion) || StringUtils.isEquals(consumerVersion, providerVersion);\n        boolean classifierMatches = consumerClassifier == null\n                || ANY_VALUE.equals(consumerClassifier)\n                || StringUtils.isEquals(consumerClassifier, providerClassifier);\n\n        return groupMatches && versionMatches && classifierMatches;\n    }\n\n    public static boolean isMatchGlobPattern(String pattern, String value, URL param) {\n        if (param != null && pattern.startsWith(\"$\")) {\n            pattern = param.getRawParameter(pattern.substring(1));\n        }\n        return isMatchGlobPattern(pattern, value);\n    }\n\n    public static boolean isMatchGlobPattern(String pattern, String value) {\n        if (\"*\".equals(pattern)) {\n            return true;\n        }\n        if (StringUtils.isEmpty(pattern) && StringUtils.isEmpty(value)) {\n            return true;\n        }\n        if (StringUtils.isEmpty(pattern) || StringUtils.isEmpty(value)) {\n            return false;\n        }\n\n        int i = pattern.lastIndexOf('*');\n        // doesn't find \"*\"\n        if (i == -1) {\n            return value.equals(pattern);\n        }\n        // \"*\" is at the end\n        else if (i == pattern.length() - 1) {\n            return value.startsWith(pattern.substring(0, i));\n        }\n        // \"*\" is at the beginning\n        else if (i == 0) {\n            return value.endsWith(pattern.substring(i + 1));\n        }\n        // \"*\" is in the middle\n        else {\n            String prefix = pattern.substring(0, i);\n            String suffix = pattern.substring(i + 1);\n            return value.startsWith(prefix) && value.endsWith(suffix);\n        }\n    }\n\n    public static boolean isServiceKeyMatch(URL pattern, URL value) {\n        return pattern.getParameter(INTERFACE_KEY).equals(value.getParameter(INTERFACE_KEY))\n                && isItemMatch(pattern.getGroup(), value.getGroup())\n                && isItemMatch(pattern.getVersion(), value.getVersion());\n    }\n\n    public static List<URL> classifyUrls(List<URL> urls, Predicate<URL> predicate) {\n        return urls.stream().filter(predicate).collect(Collectors.toList());\n    }\n\n    public static boolean isConfigurator(URL url) {\n        return OVERRIDE_PROTOCOL.equals(url.getProtocol())\n                || CONFIGURATORS_CATEGORY.equals(url.getCategory(DEFAULT_CATEGORY));\n    }\n\n    public static boolean isRoute(URL url) {\n        return ROUTE_PROTOCOL.equals(url.getProtocol()) || ROUTERS_CATEGORY.equals(url.getCategory(DEFAULT_CATEGORY));\n    }\n\n    public static boolean isProvider(URL url) {\n        return !OVERRIDE_PROTOCOL.equals(url.getProtocol())\n                && !ROUTE_PROTOCOL.equals(url.getProtocol())\n                && PROVIDERS_CATEGORY.equals(url.getCategory(PROVIDERS_CATEGORY));\n    }\n\n    public static boolean isRegistry(URL url) {\n        return REGISTRY_PROTOCOL.equals(url.getProtocol())\n                || SERVICE_REGISTRY_PROTOCOL.equalsIgnoreCase(url.getProtocol())\n                || (url.getProtocol() != null && url.getProtocol().endsWith(\"-registry-protocol\"));\n    }\n\n    public static boolean isCheck(URL url) {\n        return url.getParameter(CHECK_KEY, true) && url.getPort() != 0;\n    }\n\n    /**\n     * The specified {@link URL} is service discovery registry type or not\n     *\n     * @param url the {@link URL} connects to the registry\n     * @return If it is, return <code>true</code>, or <code>false</code>\n     * @since 2.7.5\n     */\n    public static boolean hasServiceDiscoveryRegistryTypeKey(URL url) {\n        return hasServiceDiscoveryRegistryTypeKey(url == null ? emptyMap() : url.getParameters());\n    }\n\n    public static boolean hasServiceDiscoveryRegistryProtocol(URL url) {\n        return SERVICE_REGISTRY_PROTOCOL.equalsIgnoreCase(url.getProtocol());\n    }\n\n    public static boolean isServiceDiscoveryURL(URL url) {\n        return hasServiceDiscoveryRegistryProtocol(url) || hasServiceDiscoveryRegistryTypeKey(url);\n    }\n\n    /**\n     * The specified parameters of {@link URL} is service discovery registry type or not\n     *\n     * @param parameters the parameters of {@link URL} that connects to the registry\n     * @return If it is, return <code>true</code>, or <code>false</code>\n     * @since 2.7.5\n     */\n    public static boolean hasServiceDiscoveryRegistryTypeKey(Map<String, String> parameters) {\n        if (CollectionUtils.isEmptyMap(parameters)) {\n            return false;\n        }\n        return SERVICE_REGISTRY_TYPE.equals(parameters.get(REGISTRY_TYPE_KEY));\n    }\n\n    /**\n     * Check if the given value matches the given pattern. The pattern supports wildcard \"*\".\n     *\n     * @param pattern pattern\n     * @param value   value\n     * @return true if match otherwise false\n     */\n    static boolean isItemMatch(String pattern, String value) {\n        if (StringUtils.isEmpty(pattern)) {\n            return value == null;\n        } else {\n            return \"*\".equals(pattern) || pattern.equals(value);\n        }\n    }\n\n    /**\n     * @param serviceKey, {group}/{interfaceName}:{version}\n     * @return [group, interfaceName, version]\n     */\n    public static String[] parseServiceKey(String serviceKey) {\n        String[] arr = new String[3];\n        int i = serviceKey.indexOf('/');\n        if (i > 0) {\n            arr[0] = serviceKey.substring(0, i);\n            serviceKey = serviceKey.substring(i + 1);\n        }\n\n        int j = serviceKey.indexOf(':');\n        if (j > 0) {\n            arr[2] = serviceKey.substring(j + 1);\n            serviceKey = serviceKey.substring(0, j);\n        }\n        arr[1] = serviceKey;\n        return arr;\n    }\n\n    /**\n     * NOTICE: This method allocate too much objects, we can use {@link URLStrParser#parseDecodedStr(String)} instead.\n     * <p>\n     * Parse url string\n     *\n     * @param url URL string\n     * @return URL instance\n     * @see URL\n     */\n    public static URL valueOf(String url) {\n        if (url == null || (url = url.trim()).length() == 0) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n        String protocol = null;\n        String username = null;\n        String password = null;\n        String host = null;\n        int port = 0;\n        String path = null;\n        Map<String, String> parameters = null;\n        int i = url.indexOf('?'); // separator between body and parameters\n        if (i >= 0) {\n            String[] parts = url.substring(i + 1).split(\"&\");\n            parameters = new HashMap<>();\n            for (String part : parts) {\n                part = part.trim();\n                if (part.length() > 0) {\n                    int j = part.indexOf('=');\n                    if (j >= 0) {\n                        String key = part.substring(0, j);\n                        String value = part.substring(j + 1);\n                        parameters.put(key, value);\n                        // compatible with lower versions registering \"default.\" keys\n                        if (key.startsWith(DEFAULT_KEY_PREFIX)) {\n                            parameters.putIfAbsent(key.substring(DEFAULT_KEY_PREFIX.length()), value);\n                        }\n                    } else {\n                        parameters.put(part, part);\n                    }\n                }\n            }\n            url = url.substring(0, i);\n        }\n        i = url.indexOf(\"://\");\n        if (i >= 0) {\n            if (i == 0) {\n                throw new IllegalStateException(\"url missing protocol: \\\"\" + url + \"\\\"\");\n            }\n            protocol = url.substring(0, i);\n            url = url.substring(i + 3);\n        } else {\n            // case: file:/path/to/file.txt\n            i = url.indexOf(\":/\");\n            if (i >= 0) {\n                if (i == 0) {\n                    throw new IllegalStateException(\"url missing protocol: \\\"\" + url + \"\\\"\");\n                }\n                protocol = url.substring(0, i);\n                url = url.substring(i + 1);\n            }\n        }\n\n        i = url.indexOf('/');\n        if (i >= 0) {\n            path = url.substring(i + 1);\n            url = url.substring(0, i);\n        }\n        i = url.lastIndexOf('@');\n        if (i >= 0) {\n            username = url.substring(0, i);\n            int j = username.indexOf(':');\n            if (j >= 0) {\n                password = username.substring(j + 1);\n                username = username.substring(0, j);\n            }\n            url = url.substring(i + 1);\n        }\n        i = url.lastIndexOf(':');\n        if (i >= 0 && i < url.length() - 1) {\n            if (url.lastIndexOf('%') > i) {\n                // ipv6 address with scope id\n                // e.g. fe80:0:0:0:894:aeec:f37d:23e1%en0\n                // see https://howdoesinternetwork.com/2013/ipv6-zone-id\n                // ignore\n            } else {\n                port = Integer.parseInt(url.substring(i + 1));\n                url = url.substring(0, i);\n            }\n        }\n        if (url.length() > 0) {\n            host = url;\n        }\n\n        return new ServiceConfigURL(protocol, username, password, host, port, path, parameters);\n    }\n\n    public static boolean isConsumer(URL url) {\n        return url.getProtocol().equalsIgnoreCase(CONSUMER) || url.getPort() == 0;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T computeServiceAttribute(URL url, String key, Function<URL, T> fn) {\n        return Optional.ofNullable(url.getServiceModel())\n                .map(ServiceModel::getServiceMetadata)\n                .map(ServiceMetadata::getAttributeMap)\n                .map(stringObjectMap ->\n                        (T) ConcurrentHashMapUtils.computeIfAbsent(stringObjectMap, key, k -> fn.apply(url)))\n                .orElse(null);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/common/utils/Utf8Utils.java",
    "content": "// Protocol Buffers - Google's data interchange format\n// Copyright 2008 Google Inc.  All rights reserved.\n// https://developers.google.com/protocol-buffers/\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\npackage org.apache.dubbo.common.utils;\n\nimport static java.lang.Character.MIN_HIGH_SURROGATE;\nimport static java.lang.Character.MIN_LOW_SURROGATE;\nimport static java.lang.Character.MIN_SUPPLEMENTARY_CODE_POINT;\n\n/**\n * See original <a href=\n * \"https://github.com/protocolbuffers/protobuf/blob/master/java/core/src/main/java/com/google/protobuf/Utf8.java\"\n * >Utf8.java</a>\n */\npublic final class Utf8Utils {\n\n    private Utf8Utils() {\n        //empty\n    }\n\n    public static int decodeUtf8(byte[] srcBytes, int srcIdx, int srcSize, char[] destChars, int destIdx) {\n        // Bitwise OR combines the sign bits so any negative value fails the check.\n        if ((srcIdx | srcSize | srcBytes.length - srcIdx - srcSize) < 0\n                || (destIdx | destChars.length - destIdx - srcSize) < 0) {\n            String exMsg = String.format(\"buffer srcBytes.length=%d, srcIdx=%d, srcSize=%d, destChars.length=%d, \" +\n                    \"destIdx=%d\", srcBytes.length, srcIdx, srcSize, destChars.length, destIdx);\n            throw new ArrayIndexOutOfBoundsException(\n                    exMsg);\n        }\n\n        int offset = srcIdx;\n        final int limit = offset + srcSize;\n        final int destIdx0 = destIdx;\n\n        // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).\n        // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).\n        while (offset < limit) {\n            byte b = srcBytes[offset];\n            if (!DecodeUtil.isOneByte(b)) {\n                break;\n            }\n            offset++;\n            DecodeUtil.handleOneByteSafe(b, destChars, destIdx++);\n        }\n\n        while (offset < limit) {\n            byte byte1 = srcBytes[offset++];\n            if (DecodeUtil.isOneByte(byte1)) {\n                DecodeUtil.handleOneByteSafe(byte1, destChars, destIdx++);\n                // It's common for there to be multiple ASCII characters in a run mixed in, so add an\n                // extra optimized loop to take care of these runs.\n                while (offset < limit) {\n                    byte b = srcBytes[offset];\n                    if (!DecodeUtil.isOneByte(b)) {\n                        break;\n                    }\n                    offset++;\n                    DecodeUtil.handleOneByteSafe(b, destChars, destIdx++);\n                }\n            } else if (DecodeUtil.isTwoBytes(byte1)) {\n                if (offset >= limit) {\n                    throw new IllegalArgumentException(\"invalid UTF-8.\");\n                }\n                DecodeUtil.handleTwoBytesSafe(byte1, /* byte2 */ srcBytes[offset++], destChars, destIdx++);\n            } else if (DecodeUtil.isThreeBytes(byte1)) {\n                if (offset >= limit - 1) {\n                    throw new IllegalArgumentException(\"invalid UTF-8.\");\n                }\n                DecodeUtil.handleThreeBytesSafe(\n                        byte1,\n                        /* byte2 */ srcBytes[offset++],\n                        /* byte3 */ srcBytes[offset++],\n                        destChars,\n                        destIdx++);\n            } else {\n                if (offset >= limit - 2) {\n                    throw new IllegalArgumentException(\"invalid UTF-8.\");\n                }\n                DecodeUtil.handleFourBytesSafe(\n                        byte1,\n                        /* byte2 */ srcBytes[offset++],\n                        /* byte3 */ srcBytes[offset++],\n                        /* byte4 */ srcBytes[offset++],\n                        destChars,\n                        destIdx);\n                destIdx += 2;\n            }\n        }\n        return destIdx - destIdx0;\n    }\n\n\n    private static class DecodeUtil {\n\n        /**\n         * Returns whether this is a single-byte codepoint (i.e., ASCII) with the form '0XXXXXXX'.\n         */\n        private static boolean isOneByte(byte b) {\n            return b >= 0;\n        }\n\n        /**\n         * Returns whether this is a two-byte codepoint with the form '10XXXXXX'.\n         */\n        private static boolean isTwoBytes(byte b) {\n            return b < (byte) 0xE0;\n        }\n\n        /**\n         * Returns whether this is a three-byte codepoint with the form '110XXXXX'.\n         */\n        private static boolean isThreeBytes(byte b) {\n            return b < (byte) 0xF0;\n        }\n\n        private static void handleOneByteSafe(byte byte1, char[] resultArr, int resultPos) {\n            resultArr[resultPos] = (char) byte1;\n        }\n\n        private static void handleTwoBytesSafe(byte byte1, byte byte2, char[] resultArr, int resultPos) {\n            checkUtf8(byte1, byte2);\n            resultArr[resultPos] = (char) (((byte1 & 0x1F) << 6) | trailingByteValue(byte2));\n        }\n\n        private static void checkUtf8(byte byte1, byte byte2) {\n            // Simultaneously checks for illegal trailing-byte in leading position (<= '11000000') and\n            // overlong 2-byte, '11000001'.\n            if (byte1 < (byte) 0xC2 || isNotTrailingByte(byte2)) {\n                throw new IllegalArgumentException(\"invalid UTF-8.\");\n            }\n        }\n\n        private static void handleThreeBytesSafe(byte byte1, byte byte2, byte byte3, char[] resultArr, int resultPos) {\n            checkUtf8(byte1, byte2, byte3);\n            resultArr[resultPos] =\n                    (char) (((byte1 & 0x0F) << 12) | (trailingByteValue(byte2) << 6) | trailingByteValue(byte3));\n        }\n\n        private static void checkUtf8(byte byte1, byte byte2, byte byte3) {\n            if (isNotTrailingByte(byte2)\n                    // overlong? 5 most significant bits must not all be zero\n                    || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)\n                    // check for illegal surrogate codepoints\n                    || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)\n                    || isNotTrailingByte(byte3)) {\n                throw new IllegalArgumentException(\"invalid UTF-8.\");\n            }\n        }\n\n        private static void handleFourBytesSafe(byte byte1, byte byte2, byte byte3, byte byte4, char[] resultArr,\n                                                int resultPos) {\n            checkUtf8(byte1, byte2, byte3, byte4);\n            int codepoint =\n                    ((byte1 & 0x07) << 18)\n                            | (trailingByteValue(byte2) << 12)\n                            | (trailingByteValue(byte3) << 6)\n                            | trailingByteValue(byte4);\n\n            resultArr[resultPos] = DecodeUtil.highSurrogate(codepoint);\n            resultArr[resultPos + 1] = DecodeUtil.lowSurrogate(codepoint);\n        }\n\n        private static void checkUtf8(byte byte1, byte byte2, byte byte3, byte byte4) {\n            if (isNotTrailingByte(byte2)\n                    // Check that 1 <= plane <= 16.  Tricky optimized form of:\n                    //   valid 4-byte leading byte?\n                    // if (byte1 > (byte) 0xF4 ||\n                    //   overlong? 4 most significant bits must not all be zero\n                    //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||\n                    //   codepoint larger than the highest code point (U+10FFFF)?\n                    //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)\n                    || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0\n                    || isNotTrailingByte(byte3)\n                    || isNotTrailingByte(byte4)) {\n                throw new IllegalArgumentException(\"invalid UTF-8.\");\n            }\n        }\n\n        /**\n         * Returns whether the byte is not a valid continuation of the form '10XXXXXX'.\n         */\n        private static boolean isNotTrailingByte(byte b) {\n            return b > (byte) 0xBF;\n        }\n\n        /**\n         * Returns the actual value of the trailing byte (removes the prefix '10') for composition.\n         */\n        private static int trailingByteValue(byte b) {\n            return b & 0x3F;\n        }\n\n        private static char highSurrogate(int codePoint) {\n            return (char)\n                    ((MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10)) + (codePoint >>> 10));\n        }\n\n        private static char lowSurrogate(int codePoint) {\n            return (char) (MIN_LOW_SURROGATE + (codePoint & 0x3ff));\n        }\n    }\n\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.config.InmemoryConfiguration;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.FieldUtils;\nimport org.apache.dubbo.common.utils.MethodUtils;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.ToStringUtils;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.context.ConfigMode;\nimport org.apache.dubbo.config.support.Nested;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.beans.BeanInfo;\nimport java.beans.IntrospectionException;\nimport java.beans.Introspector;\nimport java.beans.MethodDescriptor;\nimport java.beans.PropertyDescriptor;\nimport java.beans.Transient;\nimport java.io.Serializable;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_FAILED_OVERRIDE_FIELD;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_REFLECTIVE_OPERATION_FAILED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\nimport static org.apache.dubbo.common.utils.ClassUtils.isSimpleType;\nimport static org.apache.dubbo.config.Constants.PARAMETERS;\n\n/**\n * Utility methods and public methods for parsing configuration\n *\n * @export\n */\n@SuppressWarnings({\"unchecked\", \"rawtypes\"})\npublic abstract class AbstractConfig implements Serializable {\n\n    private static final long serialVersionUID = 4267533505537413570L;\n\n    protected static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractConfig.class);\n\n    /**\n     * tag name cache, speed up get tag name frequently\n     */\n    private static final ConcurrentMap<Class, String> tagNameCache = new ConcurrentHashMap<>();\n\n    /**\n     * attributed getter method cache for equals(), hashCode() and toString()\n     */\n    private static final ConcurrentMap<Class, List<Method>> attributedMethodCache = new ConcurrentHashMap<>();\n\n    /**\n     * The suffix container\n     */\n    private static final String[] SUFFIXES = new String[] {\"Config\", \"Bean\", \"ConfigBase\"};\n\n    /**\n     * Identifier for this configuration.\n     */\n    private String id;\n\n    /**\n     * Indicates whether the configuration has been refreshed (true if refreshed).\n     */\n    protected final AtomicBoolean refreshed = new AtomicBoolean(false);\n\n    /**\n     * Specifies if this configuration should be refreshed (true for refreshing).\n     */\n    protected transient volatile boolean needRefresh = true;\n\n    /**\n     * Indicates if this is the default configuration (true for default).\n     */\n    protected Boolean isDefault;\n\n    /**\n     * The scope model of this config instance.\n     * <p>\n     * <b>NOTE:</b> the model maybe changed during config processing,\n     * the extension spi instance needs to be reinitialized after changing the model!\n     */\n    private transient volatile ScopeModel scopeModel;\n\n    public AbstractConfig() {\n        this(null);\n    }\n\n    public AbstractConfig(ScopeModel scopeModel) {\n        this.setScopeModel(scopeModel);\n    }\n\n    public static String getTagName(Class<?> cls) {\n        return ConcurrentHashMapUtils.computeIfAbsent(tagNameCache, cls, (key) -> {\n            String tag = cls.getSimpleName();\n            for (String suffix : SUFFIXES) {\n                if (tag.endsWith(suffix)) {\n                    tag = tag.substring(0, tag.length() - suffix.length());\n                    break;\n                }\n            }\n            return StringUtils.camelToSplitName(tag, \"-\");\n        });\n    }\n\n    public static String getPluralTagName(Class<?> cls) {\n        String tagName = getTagName(cls);\n        if (tagName.endsWith(\"y\")) {\n            // e.g. registry -> registries\n            return tagName.substring(0, tagName.length() - 1) + \"ies\";\n        } else if (tagName.endsWith(\"s\")) {\n            // e.g. metrics -> metricses\n            return tagName + \"es\";\n        }\n        return tagName + \"s\";\n    }\n\n    public static void appendParameters(Map<String, String> parameters, Object config) {\n        appendParameters(parameters, config, null);\n    }\n\n    public static void appendParameters(Map<String, String> parameters, Object config, String prefix) {\n        appendParameters0(parameters, config, prefix, true);\n    }\n\n    /**\n     * Put attributes of specify 'config' into 'parameters' argument\n     */\n    public static void appendAttributes(Map<String, String> parameters, Object config) {\n        appendParameters0(parameters, config, null, false);\n    }\n\n    public static void appendAttributes(Map<String, String> parameters, Object config, String prefix) {\n        appendParameters0(parameters, config, prefix, false);\n    }\n\n    private static void appendParameters0(\n            Map<String, String> parameters, Object config, String prefix, boolean asParameters) {\n        if (config == null) {\n            return;\n        }\n        // If asParameters=false, it means append attributes, ignore @Parameter annotation's attributes except 'append'\n        // and 'attribute'\n\n        // How to select the appropriate one from multiple getter methods of the property?\n        // e.g. Using String getGeneric() or Boolean isGeneric()? Judge by field type ?\n        // Currently, use @Parameter.attribute() to determine whether it is an attribute.\n\n        BeanInfo beanInfo = getBeanInfo(config.getClass());\n        for (MethodDescriptor methodDescriptor : beanInfo.getMethodDescriptors()) {\n            Method method = methodDescriptor.getMethod();\n            try {\n                String name = method.getName();\n                if (MethodUtils.isGetter(method)) {\n                    if (method.getReturnType() == Object.class) {\n                        continue;\n                    }\n                    String key;\n                    Parameter parameter = method.getAnnotation(Parameter.class);\n                    if (asParameters) {\n                        if (parameter != null && parameter.excluded()) {\n                            continue;\n                        }\n                        // get parameter key\n                        if (parameter != null && parameter.key().length() > 0) {\n                            key = parameter.key();\n                        } else {\n                            key = calculatePropertyFromGetter(name);\n                        }\n                    } else { // as attributes\n                        // filter non attribute\n                        if (parameter != null && !parameter.attribute()) {\n                            continue;\n                        }\n                        // get attribute name\n                        String propertyName = calculateAttributeFromGetter(name);\n                        // convert camelCase/snake_case to kebab-case\n                        key = StringUtils.convertToSplitName(propertyName, \"-\");\n                    }\n                    Object value = method.invoke(config);\n                    String str = String.valueOf(value).trim();\n                    if (value != null && str.length() > 0) {\n                        if (asParameters && parameter != null && parameter.escaped()) {\n                            str = URL.encode(str);\n                        }\n                        if (parameter != null && parameter.append()) {\n                            String pre = parameters.get(key);\n                            if (pre != null && pre.length() > 0) {\n                                str = pre + \",\" + str;\n                                // Remove duplicate values\n                                Set<String> set = StringUtils.splitToSet(str, ',');\n                                str = StringUtils.join(set, \",\");\n                            }\n                        }\n                        if (prefix != null && prefix.length() > 0) {\n                            key = prefix + \".\" + key;\n                        }\n                        parameters.put(key, str);\n                    } else if (asParameters && parameter != null && parameter.required()) {\n                        throw new IllegalStateException(config.getClass().getSimpleName() + \".\" + key + \" == null\");\n                    }\n                } else if (isParametersGetter(method)) {\n                    Map<String, String> map = (Map<String, String>) method.invoke(config);\n                    map = convert(map, prefix);\n                    if (asParameters) {\n                        // put all parameters to url\n                        parameters.putAll(map);\n                    } else {\n                        // encode parameters to string for config overriding, see AbstractConfig#refresh()\n                        String key = calculatePropertyFromGetter(name);\n                        String encodeParameters = StringUtils.encodeParameters(map);\n                        if (encodeParameters != null) {\n                            parameters.put(key, encodeParameters);\n                        }\n                    }\n                } else if (isNestedGetter(config, method)) {\n                    Object inner = method.invoke(config);\n                    String fieldName = MethodUtils.extractFieldName(method);\n                    String nestedPrefix = prefix == null ? fieldName : prefix + \".\" + fieldName;\n                    appendParameters0(parameters, inner, nestedPrefix, asParameters);\n                }\n            } catch (Exception e) {\n                throw new IllegalStateException(\"Append parameters failed: \" + e.getMessage(), e);\n            }\n        }\n    }\n\n    protected static String extractPropertyName(String setter) {\n        String propertyName = setter.substring(\"set\".length());\n        propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1);\n        return propertyName;\n    }\n\n    private static String calculatePropertyToGetter(String name) {\n        return \"get\" + name.substring(0, 1).toUpperCase() + name.substring(1);\n    }\n\n    private static String calculatePropertyToSetter(String name) {\n        return \"set\" + name.substring(0, 1).toUpperCase() + name.substring(1);\n    }\n\n    private static String calculatePropertyFromGetter(String name) {\n        int i = name.startsWith(\"get\") ? 3 : 2;\n        return StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), \".\");\n    }\n\n    private static String calculateAttributeFromGetter(String getter) {\n        int i = getter.startsWith(\"get\") ? 3 : 2;\n        return getter.substring(i, i + 1).toLowerCase() + getter.substring(i + 1);\n    }\n\n    private static void invokeSetParameters(Class c, Object o, Map map) {\n        try {\n            Method method =\n                    ReflectUtils.findMethodByMethodSignature(c, \"setParameters\", new String[] {Map.class.getName()});\n            if (method != null && isParametersSetter(method)) {\n                method.invoke(o, map);\n            }\n        } catch (Throwable t) {\n            // ignore\n        }\n    }\n\n    private static Map<String, String> invokeGetParameters(Class c, Object o) {\n        try {\n\n            Method method = ReflectUtils.findMethodByMethodSignature(c, \"getParameters\", null);\n            if (method != null && isParametersGetter(method)) {\n                return (Map<String, String>) method.invoke(o);\n            }\n        } catch (Throwable t) {\n            // ignore\n        }\n        return null;\n    }\n\n    private static boolean isParametersGetter(Method method) {\n        String name = method.getName();\n        return (\"getParameters\".equals(name)\n                && Modifier.isPublic(method.getModifiers())\n                && method.getParameterTypes().length == 0\n                && method.getReturnType() == Map.class);\n    }\n\n    private static boolean isPropertySetter(Method method) {\n        String name = method.getName();\n        if (name.startsWith(\"set\")\n                && name.length() > 3\n                && Modifier.isPublic(method.getModifiers())\n                && method.getParameterCount() == 1) {\n            Class<?> paramType = method.getParameterTypes()[0];\n            if (paramType.isArray()) {\n                Class<?> componentType = paramType.getComponentType();\n                return componentType.isPrimitive() || isSimpleType(componentType);\n            } else {\n                return paramType.isPrimitive() || isSimpleType(paramType);\n            }\n        }\n        return false;\n    }\n\n    private static boolean isParametersSetter(Method method) {\n        return (\"setParameters\".equals(method.getName())\n                && Modifier.isPublic(method.getModifiers())\n                && method.getParameterCount() == 1\n                && Map.class == method.getParameterTypes()[0]\n                && method.getReturnType() == void.class);\n    }\n\n    private static boolean isNestedGetter(Object obj, Method method) {\n        String name = method.getName();\n        boolean isGetter = (name.startsWith(\"get\") || name.startsWith(\"is\"))\n                && !\"get\".equals(name)\n                && !\"is\".equals(name)\n                && !\"getClass\".equals(name)\n                && !\"getObject\".equals(name)\n                && Modifier.isPublic(method.getModifiers())\n                && method.getParameterTypes().length == 0\n                && (!method.getReturnType().isPrimitive() && !isSimpleType(method.getReturnType()));\n\n        if (!isGetter) {\n            return false;\n        } else {\n            // Extract fieldName only when necessary.\n            String fieldName = MethodUtils.extractFieldName(method);\n            Field field = FieldUtils.getDeclaredField(obj.getClass(), fieldName);\n            return field != null && field.isAnnotationPresent(Nested.class);\n        }\n    }\n\n    private static boolean isNestedSetter(Object obj, Method method) {\n        boolean isSetter = method.getName().startsWith(\"set\")\n                && !\"set\".equals(method.getName())\n                && Modifier.isPublic(method.getModifiers())\n                && method.getParameterCount() == 1\n                && method.getParameterTypes()[0] != null\n                && (!method.getParameterTypes()[0].isPrimitive() && !isSimpleType(method.getParameterTypes()[0]));\n\n        if (!isSetter) {\n            return false;\n        } else {\n            // Extract fieldName only when necessary.\n            String fieldName = MethodUtils.extractFieldName(method);\n            Field field = FieldUtils.getDeclaredField(obj.getClass(), fieldName);\n            return field != null && field.isAnnotationPresent(Nested.class);\n        }\n    }\n\n    /**\n     * @param parameters the raw parameters\n     * @param prefix     the prefix\n     * @return the parameters whose raw key will replace \"-\" to \".\"\n     * @revised 2.7.8 \"private\" to be \"protected\"\n     */\n    protected static Map<String, String> convert(Map<String, String> parameters, String prefix) {\n        if (parameters == null || parameters.isEmpty()) {\n            return new HashMap<>();\n        }\n\n        Map<String, String> result = new HashMap<>();\n        String pre = (StringUtils.isNotEmpty(prefix) ? prefix + \".\" : \"\");\n        for (Map.Entry<String, String> entry : parameters.entrySet()) {\n            String key = entry.getKey();\n            String value = entry.getValue();\n            result.put(pre + key, value);\n            // For compatibility, key like \"registry-type\" will have a duplicate key \"registry.type\"\n            if (Arrays.binarySearch(Constants.DOT_COMPATIBLE_KEYS, key) >= 0) {\n                result.put(pre + key.replace('-', '.'), value);\n            }\n        }\n        return result;\n    }\n\n    @Transient\n    public ApplicationModel getApplicationModel() {\n        if (scopeModel == null) {\n            setScopeModel(getDefaultModel());\n        }\n        if (scopeModel instanceof ApplicationModel) {\n            return (ApplicationModel) scopeModel;\n        } else if (scopeModel instanceof ModuleModel) {\n            return ((ModuleModel) scopeModel).getApplicationModel();\n        } else {\n            throw new IllegalStateException(\"scope model is invalid: \" + scopeModel);\n        }\n    }\n\n    @Transient\n    public ScopeModel getScopeModel() {\n        if (scopeModel == null) {\n            setScopeModel(getDefaultModel());\n        }\n        return scopeModel;\n    }\n\n    @Transient\n    protected ScopeModel getDefaultModel() {\n        return ApplicationModel.defaultModel();\n    }\n\n    public final void setScopeModel(ScopeModel scopeModel) {\n        if (scopeModel != null && this.scopeModel != scopeModel) {\n            checkScopeModel(scopeModel);\n            ScopeModel oldScopeModel = this.scopeModel;\n            this.scopeModel = scopeModel;\n            // reinitialize spi extension and change referenced config's scope model\n            this.postProcessAfterScopeModelChanged(oldScopeModel, this.scopeModel);\n        }\n    }\n\n    protected void checkScopeModel(ScopeModel scopeModel) {\n        if (!(scopeModel instanceof ApplicationModel)) {\n            throw new IllegalArgumentException(\n                    \"Invalid scope model, expect to be a ApplicationModel but got: \" + scopeModel);\n        }\n    }\n\n    /**\n     * Subclass should override this method to initialize its SPI extensions and change referenced config's scope model.\n     * <p>\n     * For example:\n     * <pre>\n     * protected void postProcessAfterScopeModelChanged() {\n     *   super.postProcessAfterScopeModelChanged();\n     *   // re-initialize spi extension\n     *   this.protocol = this.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n     *   // change referenced config's scope model\n     *   if (this.providerConfig != null && this.providerConfig.getScopeModel() != scopeModel) {\n     *     this.providerConfig.setScopeModel(scopeModel);\n     *   }\n     * }\n     * </pre>\n     *\n     * @param oldScopeModel\n     * @param newScopeModel\n     */\n    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {\n        // remove this config from old ConfigManager\n        //        if (oldScopeModel != null && oldScopeModel instanceof ApplicationModel) {\n        //           ((ApplicationModel)oldScopeModel).getApplicationConfigManager().removeConfig(this);\n        //        }\n    }\n\n    protected <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        if (scopeModel == null) {\n            setScopeModel(getScopeModel());\n        }\n        return scopeModel.getExtensionLoader(type);\n    }\n\n    @Parameter(excluded = true)\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    /**\n     * Copy attributes from annotation\n     *\n     * @param annotationClass\n     * @param annotation\n     */\n    protected void appendAnnotation(Class<?> annotationClass, Object annotation) {\n        Method[] methods = annotationClass.getMethods();\n        for (Method method : methods) {\n            if (method.getDeclaringClass() != Object.class\n                    && method.getDeclaringClass() != Annotation.class\n                    && method.getReturnType() != void.class\n                    && method.getParameterTypes().length == 0\n                    && Modifier.isPublic(method.getModifiers())\n                    && !Modifier.isStatic(method.getModifiers())) {\n                try {\n                    String property = method.getName();\n                    if (\"interfaceClass\".equals(property) || \"interfaceName\".equals(property)) {\n                        property = \"interface\";\n                    }\n                    String setter = calculatePropertyToSetter(property);\n                    Object value = method.invoke(annotation);\n                    if (value != null && !value.equals(method.getDefaultValue())) {\n                        Class<?> parameterType = ReflectUtils.getBoxedClass(method.getReturnType());\n                        if (\"filter\".equals(property) || \"listener\".equals(property)) {\n                            parameterType = String.class;\n                            value = StringUtils.join((String[]) value, \",\");\n                        } else if (\"parameters\".equals(property)) {\n                            parameterType = Map.class;\n                            value = CollectionUtils.toStringMap((String[]) value);\n                        }\n                        try {\n                            Method setterMethod = getClass().getMethod(setter, parameterType);\n                            setterMethod.invoke(this, value);\n                        } catch (NoSuchMethodException e) {\n                            // ignore\n                        }\n                    }\n                } catch (Throwable e) {\n                    logger.error(COMMON_REFLECTIVE_OPERATION_FAILED, \"\", \"\", e.getMessage(), e);\n                }\n            }\n        }\n    }\n\n    /**\n     * <p>\n     * <b>The new instance of the AbstractConfig subclass should return empty metadata.</b>\n     * The purpose is to get the attributes set by the user instead of the default value when the {@link #refresh()} method handles attribute overrides.\n     * </p>\n     *\n     * <p><b>The default value of the field should be set in the {@link #checkDefault()} method</b>,\n     * which will be called at the end of {@link #refresh()}, so that it will not affect the behavior of attribute overrides.</p>\n     *\n     * <p></p>\n     * Should be called after Config was fully initialized.\n     * <p>\n     * Notice! This method should include all properties in the returning map, treat @Parameter differently compared to appendParameters?\n     * </p>\n     * // FIXME: this method should be completely replaced by appendParameters?\n     * // -- Url parameter may use key, but props override only use property name. So replace it with appendAttributes().\n     *\n     * @see AbstractConfig#checkDefault()\n     * @see AbstractConfig#appendParameters(Map, Object, String)\n     */\n    @Transient\n    public Map<String, String> getMetaData() {\n        return getMetaData(null);\n    }\n\n    @Transient\n    public Map<String, String> getMetaData(String prefix) {\n        Map<String, String> metaData = new HashMap<>();\n        appendAttributes(metaData, this, prefix);\n        return metaData;\n    }\n\n    private static BeanInfo getBeanInfo(Class cls) {\n        BeanInfo beanInfo;\n        try {\n            beanInfo = Introspector.getBeanInfo(cls);\n        } catch (IntrospectionException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n        return beanInfo;\n    }\n\n    private static boolean isWritableProperty(BeanInfo beanInfo, String key) {\n        for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) {\n            if (key.equals(propertyDescriptor.getName())) {\n                return propertyDescriptor.getWriteMethod() != null;\n            }\n        }\n        return false;\n    }\n\n    @Parameter(excluded = true, attribute = false)\n    @Transient\n    public List<String> getPrefixes() {\n        List<String> prefixes = new ArrayList<>();\n        if (StringUtils.hasText(this.getId())) {\n            // dubbo.{tag-name}s.{id}\n            prefixes.add(CommonConstants.DUBBO + \".\" + getPluralTagName(this.getClass()) + \".\" + this.getId());\n        }\n\n        // check name\n        String name = ReflectUtils.getProperty(this, \"getName\");\n        if (StringUtils.hasText(name)) {\n            // dubbo.{tag-name}s.{name}\n            String prefix = CommonConstants.DUBBO + \".\" + getPluralTagName(this.getClass()) + \".\" + name;\n            if (!prefixes.contains(prefix)) {\n                prefixes.add(prefix);\n            }\n        }\n\n        // dubbo.{tag-name}\n        prefixes.add(getTypePrefix(this.getClass()));\n        return prefixes;\n    }\n\n    public static String getTypePrefix(Class<? extends AbstractConfig> cls) {\n        return CommonConstants.DUBBO + \".\" + getTagName(cls);\n    }\n\n    @Transient\n    public ConfigMode getConfigMode() {\n        return getApplicationModel().getApplicationConfigManager().getConfigMode();\n    }\n\n    public void overrideWithConfig(AbstractConfig newOne, boolean overrideAll) {\n        if (!Objects.equals(this.getClass(), newOne.getClass())) {\n            // ignore if two config is not the same class\n            return;\n        }\n\n        List<Method> methods =\n                MethodUtils.getMethods(this.getClass(), method -> method.getDeclaringClass() != Object.class);\n        for (Method method : methods) {\n            try {\n                Method getterMethod;\n                try {\n                    String propertyName = extractPropertyName(method.getName());\n                    String getterName = calculatePropertyToGetter(propertyName);\n                    getterMethod = this.getClass().getMethod(getterName);\n                } catch (Exception ignore) {\n                    continue;\n                }\n\n                if (MethodUtils.isSetter(method)) {\n                    Object oldOne = getterMethod.invoke(this);\n\n                    // if old one is null or need to override\n                    if (overrideAll || oldOne == null) {\n                        Object newResult = getterMethod.invoke(newOne);\n                        // if new one is non-null and new one is not equals old one\n                        if (newResult != null && !Objects.equals(newResult, oldOne)) {\n                            method.invoke(this, newResult);\n                        }\n                    }\n                } else if (isParametersSetter(method)) {\n                    Object oldOne = getterMethod.invoke(this);\n                    Object newResult = getterMethod.invoke(newOne);\n\n                    Map<String, String> oldMap = null;\n                    if (oldOne instanceof Map) {\n                        oldMap = (Map) oldOne;\n                    }\n\n                    Map<String, String> newMap = null;\n                    if (newResult instanceof Map) {\n                        newMap = (Map) newResult;\n                    }\n\n                    // if new map is null, skip\n                    if (newMap == null) {\n                        continue;\n                    }\n\n                    // if old map is null, override with new map\n                    if (oldMap == null) {\n                        invokeSetParameters(newMap, this);\n                        continue;\n                    }\n\n                    // if mode is OVERRIDE_IF_ABSENT, put all old map entries to new map, will override the same key\n                    // if mode is OVERRIDE_ALL, put all keyed entries not in new map from old map to new map (ignore the\n                    // same key appeared in old map)\n                    if (overrideAll) {\n                        oldMap.forEach(newMap::putIfAbsent);\n                    } else {\n                        newMap.putAll(oldMap);\n                    }\n\n                    invokeSetParameters(newMap, this);\n                } else if (isNestedSetter(this, method)) {\n                    // not support\n                }\n\n            } catch (Throwable t) {\n                logger.error(\n                        COMMON_FAILED_OVERRIDE_FIELD,\n                        \"\",\n                        \"\",\n                        \"Failed to override field value of config bean: \" + this,\n                        t);\n                throw new IllegalStateException(\"Failed to override field value of config bean: \" + this, t);\n            }\n        }\n    }\n\n    /**\n     * Dubbo config property override\n     */\n    public void refresh() {\n        if (needRefresh) {\n            try {\n                // check and init before do refresh\n                preProcessRefresh();\n                refreshWithPrefixes(getPrefixes(), getConfigMode());\n            } catch (Exception e) {\n                logger.error(\n                        COMMON_FAILED_OVERRIDE_FIELD,\n                        \"\",\n                        \"\",\n                        \"Failed to override field value of config bean: \" + this,\n                        e);\n                throw new IllegalStateException(\"Failed to override field value of config bean: \" + this, e);\n            }\n\n            postProcessRefresh();\n        }\n        refreshed.set(true);\n    }\n\n    protected void refreshWithPrefixes(List<String> prefixes, ConfigMode configMode) {\n        Environment environment = getScopeModel().modelEnvironment();\n        List<Map<String, String>> configurationMaps = environment.getConfigurationMaps();\n\n        // Search props starts with PREFIX in order\n        String preferredPrefix = null;\n        for (String prefix : prefixes) {\n            if (ConfigurationUtils.hasSubProperties(configurationMaps, prefix)) {\n                preferredPrefix = prefix;\n                break;\n            }\n        }\n        if (preferredPrefix == null) {\n            preferredPrefix = prefixes.get(0);\n        }\n        // Extract sub props (which key was starts with preferredPrefix)\n        Collection<Map<String, String>> instanceConfigMaps = environment.getConfigurationMaps(this, preferredPrefix);\n        Map<String, String> subProperties = ConfigurationUtils.getSubProperties(instanceConfigMaps, preferredPrefix);\n        InmemoryConfiguration subPropsConfiguration = new InmemoryConfiguration(subProperties);\n\n        if (logger.isDebugEnabled()) {\n            String idOrName = \"\";\n            if (StringUtils.hasText(this.getId())) {\n                idOrName = \"[id=\" + this.getId() + \"]\";\n            } else {\n                String name = ReflectUtils.getProperty(this, \"getName\");\n                if (StringUtils.hasText(name)) {\n                    idOrName = \"[name=\" + name + \"]\";\n                }\n            }\n            logger.debug(\"Refreshing \" + this.getClass().getSimpleName() + idOrName + \" with prefix [\"\n                    + preferredPrefix + \"], extracted props: \"\n                    + subProperties);\n        }\n\n        assignProperties(this, environment, subProperties, subPropsConfiguration, configMode);\n\n        // process extra refresh of subclass, e.g. refresh method configs\n        processExtraRefresh(preferredPrefix, subPropsConfiguration);\n    }\n\n    private void assignProperties(\n            Object obj,\n            Environment environment,\n            Map<String, String> properties,\n            InmemoryConfiguration configuration,\n            ConfigMode configMode) {\n        // if old one (this) contains non-null value, do not override\n        boolean overrideIfAbsent = configMode == ConfigMode.OVERRIDE_IF_ABSENT;\n\n        // even if old one (this) contains non-null value, do override\n        boolean overrideAll = configMode == ConfigMode.OVERRIDE_ALL;\n\n        FrameworkModel frameworkModel = ScopeModelUtil.getFrameworkModel(getScopeModel());\n\n        // loop methods, get override value and set the new value back to method\n        List<Method> methods =\n                MethodUtils.getMethods(obj.getClass(), method -> method.getDeclaringClass() != Object.class);\n        for (Method method : methods) {\n            // filter non attribute\n            Parameter parameter = method.getAnnotation(Parameter.class);\n            if (parameter != null && !parameter.attribute()) {\n                continue;\n            }\n\n            if (isPropertySetter(method)) {\n                String propertyName = extractPropertyName(method.getName());\n\n                // if config mode is OVERRIDE_IF_ABSENT and property has set, skip\n                if (overrideIfAbsent && isPropertySet(methods, propertyName)) {\n                    continue;\n                }\n\n                // convert camelCase/snake_case to kebab-case\n                String kebabPropertyName = StringUtils.convertToSplitName(propertyName, \"-\");\n\n                try {\n                    String value = StringUtils.trim(configuration.getString(kebabPropertyName));\n\n                    Class<?> paramType = method.getParameterTypes()[0];\n                    if (paramType.isArray()) {\n                        if (isIgnoredAttribute(obj.getClass(), propertyName)) {\n                            continue;\n                        }\n\n                        Class<?> itemType = paramType.getComponentType();\n                        List<Object> items = new ArrayList<>();\n                        if (StringUtils.hasText(value)) {\n                            value = environment.resolvePlaceholders(value);\n                            if (StringUtils.hasText(value)) {\n                                for (String item : StringUtils.tokenize(value, ',')) {\n                                    items.add(ClassUtils.convertPrimitive(frameworkModel, itemType, item));\n                                }\n                            }\n                        } else {\n                            for (int i = 0; ; i++) {\n                                value = StringUtils.trim(configuration.getString(kebabPropertyName + '[' + i + ']'));\n                                if (value == null) {\n                                    break;\n                                }\n                                if (StringUtils.hasText(value)) {\n                                    value = environment.resolvePlaceholders(value);\n                                    if (StringUtils.hasText(value)) {\n                                        items.add(ClassUtils.convertPrimitive(frameworkModel, itemType, value));\n                                    }\n                                }\n                            }\n                        }\n                        int len = items.size();\n                        if (len > 0) {\n                            Object array = Array.newInstance(itemType, len);\n                            for (int i = 0; i < len; i++) {\n                                Array.set(array, i, items.get(i));\n                            }\n                            method.invoke(obj, array);\n                        }\n                        continue;\n                    }\n\n                    // isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two\n                    // 'setGeneric' methods in ReferenceConfig.\n                    if (StringUtils.hasText(value)\n                            && ClassUtils.isTypeMatch(paramType, value)\n                            && !isIgnoredAttribute(obj.getClass(), propertyName)) {\n                        value = environment.resolvePlaceholders(value);\n                        if (StringUtils.hasText(value)) {\n                            Object arg = ClassUtils.convertPrimitive(frameworkModel, paramType, value);\n                            if (arg != null) {\n                                method.invoke(obj, arg);\n                            }\n                        }\n                    }\n                } catch (Exception e) {\n                    logger.info(\"Failed to override the property \" + method.getName() + \" in \"\n                            + obj.getClass().getSimpleName()\n                            + \", please make sure every property has getter/setter method provided.\");\n                }\n            } else if (isParametersSetter(method)) {\n                String propertyName = extractPropertyName(method.getName());\n\n                String value = StringUtils.trim(configuration.getString(propertyName));\n                Map<String, String> parameterMap;\n                if (StringUtils.hasText(value)) {\n                    parameterMap = StringUtils.parseParameters(value);\n                } else {\n                    // in this case, maybe parameters.item3=value3.\n                    parameterMap = ConfigurationUtils.getSubProperties(properties, PARAMETERS);\n                }\n                Map<String, String> newMap = convert(parameterMap, \"\");\n                if (CollectionUtils.isEmptyMap(newMap)) {\n                    continue;\n                }\n\n                // get old map from original obj\n                Map<String, String> oldMap = null;\n                try {\n                    String getterName = calculatePropertyToGetter(propertyName);\n                    Method getterMethod = this.getClass().getMethod(getterName);\n                    Object oldOne = getterMethod.invoke(this);\n                    if (oldOne instanceof Map) {\n                        oldMap = (Map) oldOne;\n                    }\n                } catch (Exception ignore) {\n\n                }\n\n                // if old map is null, directly set params\n                if (oldMap == null) {\n                    invokeSetParameters(newMap, obj);\n                    continue;\n                }\n\n                // if mode is OVERRIDE_IF_ABSENT, put all old map entries to new map, will override the same key\n                // if mode is OVERRIDE_ALL, put all keyed entries not in new map from old map to new map (ignore the\n                // same key appeared in old map)\n                // if mode is others, override with new map\n                if (overrideIfAbsent) {\n                    newMap.putAll(oldMap);\n                } else if (overrideAll) {\n                    oldMap.forEach(newMap::putIfAbsent);\n                }\n\n                invokeSetParameters(newMap, obj);\n            } else if (isNestedSetter(obj, method)) {\n                try {\n                    Class<?> clazz = method.getParameterTypes()[0];\n                    Object inner = clazz.getDeclaredConstructor().newInstance();\n                    String fieldName = MethodUtils.extractFieldName(method);\n                    Map<String, String> subProperties = ConfigurationUtils.getSubProperties(properties, fieldName);\n                    InmemoryConfiguration subPropsConfiguration = new InmemoryConfiguration(subProperties);\n                    assignProperties(inner, environment, subProperties, subPropsConfiguration, configMode);\n                    method.invoke(obj, inner);\n                } catch (ReflectiveOperationException e) {\n                    throw new IllegalStateException(\n                            \"Cannot assign nested class when refreshing config: \"\n                                    + obj.getClass().getName(),\n                            e);\n                }\n            }\n        }\n    }\n\n    private boolean isPropertySet(List<Method> methods, String propertyName) {\n        try {\n            String getterName = calculatePropertyToGetter(propertyName);\n            Method getterMethod = findGetMethod(methods, getterName);\n            if (getterMethod == null) {\n                return false;\n            }\n            Object oldOne = getterMethod.invoke(this);\n            if (oldOne != null) {\n                return true;\n            }\n        } catch (Exception ignore) {\n\n        }\n        return false;\n    }\n\n    private Method findGetMethod(List<Method> methods, String methodName) {\n        for (Method method : methods) {\n            if (method.getName().equals(methodName) && method.getParameterCount() == 0) {\n                return method;\n            }\n        }\n        return null;\n    }\n\n    private void invokeSetParameters(Map<String, String> values, Object obj) {\n        if (CollectionUtils.isEmptyMap(values)) {\n            return;\n        }\n        Map<String, String> map = new HashMap<>();\n        Map<String, String> getParametersMap = invokeGetParameters(obj.getClass(), obj);\n        if (getParametersMap != null && !getParametersMap.isEmpty()) {\n            map.putAll(getParametersMap);\n        }\n        map.putAll(values);\n        invokeSetParameters(obj.getClass(), obj, map);\n    }\n\n    private boolean isIgnoredAttribute(Class<?> clazz, String propertyName) {\n        Method getter = null;\n        String capitalizePropertyName = propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);\n        try {\n            getter = clazz.getMethod(\"get\" + capitalizePropertyName);\n        } catch (NoSuchMethodException e) {\n            try {\n                getter = clazz.getMethod(\"is\" + capitalizePropertyName);\n            } catch (NoSuchMethodException ex) {\n                // ignore\n            }\n        }\n\n        if (getter == null) {\n            // no getter method\n            return true;\n        }\n\n        Parameter parameter = getter.getAnnotation(Parameter.class);\n        // not an attribute\n        return parameter != null && !parameter.attribute();\n    }\n\n    protected void processExtraRefresh(String preferredPrefix, InmemoryConfiguration subPropsConfiguration) {\n        // process extra refresh\n    }\n\n    protected void preProcessRefresh() {\n        // pre-process refresh\n    }\n\n    protected void postProcessRefresh() {\n        // post-process refresh\n        checkDefault();\n    }\n\n    /**\n     * Check and set default value for some fields.\n     * <p>\n     * This method will be called at the end of {@link #refresh()}, as a post-initializer.\n     * </p>\n     * <p>NOTE: </p>\n     * <p>\n     * To distinguish between user-set property values and default property values,\n     * do not initialize default value at field declare statement. <b>If the field has a default value,\n     * it should be set in the checkDefault() method</b>, which will be called at the end of {@link #refresh()},\n     * so that it will not affect the behavior of attribute overrides.</p>\n     *\n     * @see AbstractConfig#getMetaData()\n     * @see AbstractConfig#appendAttributes(Map, Object)\n     */\n    protected void checkDefault() {}\n\n    @Parameter(excluded = true, attribute = false)\n    public boolean isRefreshed() {\n        return refreshed.get();\n    }\n\n    /**\n     * FIXME check @Parameter(required=true) and any conditions that need to match.\n     */\n    @Parameter(excluded = true, attribute = false)\n    public boolean isValid() {\n        return true;\n    }\n\n    @Parameter(excluded = true, attribute = false)\n    public Boolean isDefault() {\n        return isDefault;\n    }\n\n    public void setDefault(Boolean isDefault) {\n        this.isDefault = isDefault;\n    }\n\n    @Transient\n    @Parameter(excluded = true, attribute = false)\n    public boolean isNeedRefresh() {\n        return needRefresh;\n    }\n\n    @Transient\n    public void setNeedRefresh(boolean needRefresh) {\n        this.needRefresh = needRefresh;\n    }\n\n    @Override\n    public String toString() {\n        try {\n\n            StringBuilder buf = new StringBuilder();\n            buf.append(\"<dubbo:\");\n            buf.append(getTagName(getClass()));\n            for (Method method : getAttributedMethods()) {\n                try {\n                    String name = method.getName();\n                    String key = calculateAttributeFromGetter(name);\n                    Object value = method.invoke(this);\n                    if (value != null) {\n                        buf.append(' ');\n                        buf.append(key);\n                        buf.append(\"=\\\"\");\n                        buf.append(key.equals(\"password\") ? \"******\" : ToStringUtils.toString(value));\n                        buf.append('\\\"');\n                    }\n                } catch (Exception e) {\n                    logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", e.getMessage(), e);\n                }\n            }\n            buf.append(\" />\");\n            return buf.toString();\n        } catch (Throwable t) {\n            logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", t.getMessage(), t);\n            return super.toString();\n        }\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj == null || obj.getClass() != this.getClass()) {\n            return false;\n        }\n        if (obj == this) {\n            return true;\n        }\n\n        for (Method method : getAttributedMethods()) {\n            // ignore compare 'id' value\n            if (\"getId\".equals(method.getName())) {\n                continue;\n            }\n            try {\n                Object value1 = method.invoke(this);\n                Object value2 = method.invoke(obj);\n                if (!Objects.equals(value1, value2)) {\n                    return false;\n                }\n            } catch (Exception e) {\n                throw new IllegalStateException(\"compare config instances failed\", e);\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        int hashCode = 1;\n\n        for (Method method : getAttributedMethods()) {\n            // ignore compare 'id' value\n            if (\"getId\".equals(method.getName())) {\n                continue;\n            }\n            try {\n                Object value = method.invoke(this);\n                if (value != null) {\n                    hashCode = 31 * hashCode + value.hashCode();\n                }\n            } catch (Exception ignored) {\n                // ignored\n            }\n        }\n\n        if (hashCode == 0) {\n            hashCode = 1;\n        }\n        return hashCode;\n    }\n\n    @Transient\n    private List<Method> getAttributedMethods() {\n        Class<? extends AbstractConfig> cls = this.getClass();\n        return ConcurrentHashMapUtils.computeIfAbsent(attributedMethodCache, cls, (key) -> computeAttributedMethods());\n    }\n\n    /**\n     * compute attributed getter methods, subclass can override this method to add/remove attributed methods\n     *\n     * @return\n     */\n    protected List<Method> computeAttributedMethods() {\n        Class<? extends AbstractConfig> cls = this.getClass();\n        BeanInfo beanInfo = getBeanInfo(cls);\n        List<Method> methods = new ArrayList<>(beanInfo.getMethodDescriptors().length);\n        for (MethodDescriptor methodDescriptor : beanInfo.getMethodDescriptors()) {\n            Method method = methodDescriptor.getMethod();\n            if (MethodUtils.isGetter(method) || isParametersGetter(method)) {\n                // filter non attribute\n                Parameter parameter = method.getAnnotation(Parameter.class);\n                if (parameter != null && !parameter.attribute()) {\n                    continue;\n                }\n                String propertyName = calculateAttributeFromGetter(method.getName());\n                // filter non-writable property, exclude non property methods, fix #4225\n                if (!isWritableProperty(beanInfo, propertyName)) {\n                    continue;\n                }\n                methods.add(method);\n            }\n        }\n        return methods;\n    }\n\n    @Transient\n    protected ConfigManager getConfigManager() {\n        return getApplicationModel().getApplicationConfigManager();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.aot.NativeDetector;\nimport org.apache.dubbo.common.compiler.support.AdaptiveCompiler;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.config.InmemoryConfiguration;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\n\nimport java.beans.Transient;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INVOKER_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_NO_METHOD_FOUND;\nimport static org.apache.dubbo.config.Constants.DEFAULT_NATIVE_PROXY;\n\n/**\n * Abstract configuration for the interface.\n *\n * @export\n */\npublic abstract class AbstractInterfaceConfig extends AbstractMethodConfig {\n\n    private static final long serialVersionUID = -1559314110797223229L;\n\n    /**\n     * Interface name of the exported service.\n     */\n    protected String interfaceName;\n\n    /**\n     * ClassLoader associated with the interface.\n     */\n    protected transient ClassLoader interfaceClassLoader;\n\n    /**\n     * Version of the remote service referenced by the consumer/provider.\n     */\n    protected String version;\n\n    /**\n     * Group of the remote service referenced by the consumer/provider.\n     */\n    protected String group;\n\n    /**\n     * Service metadata configuration.\n     */\n    protected ServiceMetadata serviceMetadata;\n\n    /**\n     * Local implementation class name for the service interface.\n     */\n    protected String local;\n\n    /**\n     * Local stub class name for the service interface.\n     */\n    protected String stub;\n\n    /**\n     * Service monitoring configuration.\n     */\n    protected MonitorConfig monitor;\n\n    /**\n     * Strategy for generating dynamic agents (options: \"jdk\" or \"javassist\").\n     */\n    protected String proxy;\n\n    /**\n     * Cluster type for service.\n     */\n    protected String cluster;\n\n    /**\n     * Filters for service exposure or reference (multiple filters can be separated by commas).\n     */\n    protected String filter;\n\n    /**\n     * Listeners for service exposure or reference (multiple listeners can be separated by commas).\n     */\n    protected String listener;\n\n    /**\n     * Owner of the service providers.\n     */\n    protected String owner;\n\n    /**\n     * Connection limits: 0 for shared connection, otherwise specifying connections for the service.\n     */\n    protected Integer connections;\n\n    /**\n     * Layer of service providers.\n     */\n    protected String layer;\n\n    /**\n     * Application configuration for the service.\n     */\n    protected ApplicationConfig application;\n\n    /**\n     * Module configuration for the service.\n     */\n    protected ModuleConfig module;\n\n    /**\n     * Registries where the service will be registered (use this or registryIds, not both).\n     */\n    protected List<RegistryConfig> registries;\n\n    /**\n     * Method-specific configuration.\n     */\n    private List<MethodConfig> methods;\n\n    /**\n     * Registry IDs for service registration (use this or registries, not both).\n     */\n    protected String registryIds;\n\n    /**\n     * Event handler for connection establishment.\n     */\n    protected String onconnect;\n\n    /**\n     * Event handler for disconnection.\n     */\n    protected String ondisconnect;\n\n    /**\n     * Metadata report configuration.\n     */\n    protected MetadataReportConfig metadataReportConfig;\n\n    /**\n     * Configuration center settings.\n     */\n    protected ConfigCenterConfig configCenter;\n\n    /**\n     * Callback limits for the service.\n     */\n    private Integer callbacks;\n\n    /**\n     * Service scope (\"local\" implies searching in the current JVM only).\n     */\n    private String scope;\n\n    /**\n     * Custom tag for the service configuration.\n     */\n    protected String tag;\n\n    /**\n     * Enable service authentication.\n     */\n    private Boolean auth;\n\n    /**\n     * Authenticator for authentication\n     */\n    private String authenticator;\n\n    /**\n     * Username for basic authenticator\n     */\n    private String username;\n\n    /**\n     * Password for basic authenticator\n     */\n    private String password;\n\n    /**\n     * Use separate instances for services with the same serviceKey (applies when using ReferenceConfig and SimpleReferenceCache together).\n     * Directly calling ReferenceConfig.get() will not check this attribute.\n     */\n    private Boolean singleton;\n\n    public AbstractInterfaceConfig() {}\n\n    public AbstractInterfaceConfig(ModuleModel moduleModel) {\n        super(moduleModel);\n    }\n\n    /**\n     * The url of the reference service\n     */\n    protected final transient List<URL> urls = new ArrayList<>();\n\n    @Transient\n    public List<URL> getExportedUrls() {\n        return urls;\n    }\n\n    public URL toUrl() {\n        return urls.isEmpty() ? null : urls.iterator().next();\n    }\n\n    public List<URL> toUrls() {\n        return urls;\n    }\n\n    @Override\n    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {\n        super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);\n        // change referenced config's scope model\n        ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(getScopeModel());\n        if (this.configCenter != null && this.configCenter.getScopeModel() != applicationModel) {\n            this.configCenter.setScopeModel(applicationModel);\n        }\n        if (this.metadataReportConfig != null && this.metadataReportConfig.getScopeModel() != applicationModel) {\n            this.metadataReportConfig.setScopeModel(applicationModel);\n        }\n        if (this.monitor != null && this.monitor.getScopeModel() != applicationModel) {\n            this.monitor.setScopeModel(applicationModel);\n        }\n        if (CollectionUtils.isNotEmpty(this.registries)) {\n            this.registries.forEach(registryConfig -> {\n                if (registryConfig.getScopeModel() != applicationModel) {\n                    registryConfig.setScopeModel(applicationModel);\n                }\n            });\n        }\n    }\n\n    /**\n     * Check whether the registry config is exists, and then conversion it to {@link RegistryConfig}\n     */\n    protected void checkRegistry() {\n        convertRegistryIdsToRegistries();\n\n        for (RegistryConfig registryConfig : registries) {\n            if (!registryConfig.isValid()) {\n                throw new IllegalStateException(\"No registry config found or it's not a valid config! \"\n                        + \"The registry config is: \" + registryConfig);\n            }\n        }\n    }\n\n    public static void appendRuntimeParameters(Map<String, String> map) {\n        map.put(DUBBO_VERSION_KEY, Version.getProtocolVersion());\n        map.put(RELEASE_KEY, Version.getVersion());\n        map.put(TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));\n        if (ConfigUtils.getPid() > 0) {\n            map.put(PID_KEY, String.valueOf(ConfigUtils.getPid()));\n        }\n    }\n\n    /**\n     * To obtain the method list in the port, use reflection when in native mode and javassist otherwise.\n     *\n     * @param interfaceClass\n     * @return\n     */\n    protected String[] methods(Class<?> interfaceClass) {\n        if (NativeDetector.inNativeImage()) {\n            return Arrays.stream(interfaceClass.getMethods())\n                    .map(Method::getName)\n                    .toArray(String[]::new);\n        } else {\n            return ClassUtils.getMethodNames(interfaceClass);\n        }\n    }\n\n    protected Environment getEnvironment() {\n        return getScopeModel().modelEnvironment();\n    }\n\n    @Override\n    protected void processExtraRefresh(String preferredPrefix, InmemoryConfiguration subPropsConfiguration) {\n        if (StringUtils.hasText(interfaceName)) {\n            Class<?> interfaceClass;\n            try {\n                interfaceClass = ClassUtils.forName(interfaceName);\n            } catch (ClassNotFoundException e) {\n                // There may be no interface class when generic call\n                return;\n            }\n\n            checkInterface();\n\n            // Auto create MethodConfig/ArgumentConfig according to config props\n            Map<String, String> configProperties = subPropsConfiguration.getProperties();\n            Method[] methods;\n            try {\n                methods = interfaceClass.getMethods();\n            } catch (Throwable e) {\n                // NoClassDefFoundError may be thrown if interface class's dependency jar is missing\n                return;\n            }\n\n            for (Method method : methods) {\n                if (ConfigurationUtils.hasSubProperties(configProperties, method.getName())) {\n                    MethodConfig methodConfig = getMethodByName(method.getName());\n                    // Add method config if not found\n                    if (methodConfig == null) {\n                        methodConfig = new MethodConfig();\n                        methodConfig.setName(method.getName());\n                        this.addMethod(methodConfig);\n                    }\n                    // Add argument config\n                    // dubbo.service.{interfaceName}.{methodName}.{arg-index}.xxx=xxx\n                    java.lang.reflect.Parameter[] arguments = method.getParameters();\n                    for (int i = 0; i < arguments.length; i++) {\n                        if (getArgumentByIndex(methodConfig, i) == null\n                                && hasArgumentConfigProps(configProperties, methodConfig.getName(), i)) {\n\n                            ArgumentConfig argumentConfig = new ArgumentConfig();\n                            argumentConfig.setIndex(i);\n                            methodConfig.addArgument(argumentConfig);\n                        }\n                    }\n                }\n            }\n\n            // refresh MethodConfigs\n            List<MethodConfig> methodConfigs = this.getMethods();\n            if (methodConfigs != null && methodConfigs.size() > 0) {\n                // whether ignore invalid method config\n                Object ignoreInvalidMethodConfigVal = getEnvironment()\n                        .getConfiguration()\n                        .getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_INVALID_METHOD_CONFIG, \"false\");\n                boolean ignoreInvalidMethodConfig = Boolean.parseBoolean(ignoreInvalidMethodConfigVal.toString());\n\n                Class<?> finalInterfaceClass = interfaceClass;\n                List<MethodConfig> validMethodConfigs = methodConfigs.stream()\n                        .filter(methodConfig -> {\n                            methodConfig.setParentPrefix(preferredPrefix);\n                            methodConfig.setScopeModel(getScopeModel());\n                            methodConfig.refresh();\n                            // verify method config\n                            return verifyMethodConfig(methodConfig, finalInterfaceClass, ignoreInvalidMethodConfig);\n                        })\n                        .collect(Collectors.toList());\n                this.setMethods(validMethodConfigs);\n            }\n        }\n    }\n\n    /**\n     * it is used for skipping the check of interface since dubbo 3.2\n     * rest and triple protocol allow the service is implement class\n     */\n    protected void checkInterface() {}\n\n    protected boolean verifyMethodConfig(\n            MethodConfig methodConfig, Class<?> interfaceClass, boolean ignoreInvalidMethodConfig) {\n        String methodName = methodConfig.getName();\n        if (StringUtils.isEmpty(methodName)) {\n            String msg = \"<dubbo:method> name attribute is required! Please check: \" + \"<dubbo:service interface=\\\"\"\n                    + interfaceName + \"\\\" ... >\" + \"<dubbo:method name=\\\"\\\" ... /></<dubbo:reference>\";\n            if (ignoreInvalidMethodConfig) {\n                logger.warn(CONFIG_NO_METHOD_FOUND, \"\", \"\", msg);\n                return false;\n            } else {\n                throw new IllegalStateException(msg);\n            }\n        }\n\n        boolean hasMethod = Arrays.stream(interfaceClass.getMethods())\n                .anyMatch(method -> method.getName().equals(methodName));\n        if (!hasMethod) {\n            String msg = \"Found invalid method config, the interface \" + interfaceClass.getName()\n                    + \" not found method \\\"\" + methodName + \"\\\" : [\" + methodConfig + \"]\";\n            if (ignoreInvalidMethodConfig) {\n                logger.warn(CONFIG_NO_METHOD_FOUND, \"\", \"\", msg);\n                return false;\n            } else {\n                if (!isNeedCheckMethod()) {\n                    msg = \"Generic call: \" + msg;\n                    logger.warn(CONFIG_NO_METHOD_FOUND, \"\", \"\", msg);\n                } else {\n                    throw new IllegalStateException(msg);\n                }\n            }\n        }\n        return true;\n    }\n\n    private ArgumentConfig getArgumentByIndex(MethodConfig methodConfig, int argIndex) {\n        if (methodConfig.getArguments() != null && methodConfig.getArguments().size() > 0) {\n            for (ArgumentConfig argument : methodConfig.getArguments()) {\n                if (argument.getIndex() != null && argument.getIndex() == argIndex) {\n                    return argument;\n                }\n            }\n        }\n        return null;\n    }\n\n    @Transient\n    protected boolean isNeedCheckMethod() {\n        return true;\n    }\n\n    private boolean hasArgumentConfigProps(Map<String, String> configProperties, String methodName, int argIndex) {\n        String argPrefix = methodName + \".\" + argIndex + \".\";\n        return ConfigurationUtils.hasSubProperties(configProperties, argPrefix);\n    }\n\n    protected MethodConfig getMethodByName(String name) {\n        if (methods != null && methods.size() > 0) {\n            for (MethodConfig methodConfig : methods) {\n                if (StringUtils.isEquals(methodConfig.getName(), name)) {\n                    return methodConfig;\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Legitimacy check of stub, note that: the local will deprecated, and replace with <code>stub</code>\n     *\n     * @param interfaceClass for provider side, it is the {@link Class} of the service that will be exported; for consumer\n     *                       side, it is the {@link Class} of the remote service interface\n     */\n    protected void checkStubAndLocal(Class<?> interfaceClass) {\n        verifyStubAndLocal(local, \"Local\", interfaceClass);\n        verifyStubAndLocal(stub, \"Stub\", interfaceClass);\n    }\n\n    private void verifyStubAndLocal(String className, String label, Class<?> interfaceClass) {\n        if (ConfigUtils.isNotEmpty(className)) {\n            Class<?> localClass = ConfigUtils.isDefault(className)\n                    ? ReflectUtils.forName(interfaceClass.getName() + label)\n                    : ReflectUtils.forName(className);\n            verify(interfaceClass, localClass);\n        }\n    }\n\n    private void verify(Class<?> interfaceClass, Class<?> localClass) {\n        if (!interfaceClass.isAssignableFrom(localClass)) {\n            throw new IllegalStateException(\"The local implementation class \" + localClass.getName()\n                    + \" not implement interface \" + interfaceClass.getName());\n        }\n\n        try {\n            // Check if the localClass a constructor with parameter whose type is interfaceClass\n            ReflectUtils.findConstructor(localClass, interfaceClass);\n        } catch (NoSuchMethodException e) {\n            throw new IllegalStateException(\"No such constructor \\\"public \" + localClass.getSimpleName() + \"(\"\n                    + interfaceClass.getName() + \")\\\" in local implementation class \" + localClass.getName());\n        }\n    }\n\n    private void convertRegistryIdsToRegistries() {\n        computeValidRegistryIds();\n        if (StringUtils.isEmpty(registryIds)) {\n            if (CollectionUtils.isEmpty(registries)) {\n                List<RegistryConfig> registryConfigs = getConfigManager().getDefaultRegistries();\n                registryConfigs = new ArrayList<>(registryConfigs);\n                setRegistries(registryConfigs);\n            }\n        } else {\n            String[] ids = COMMA_SPLIT_PATTERN.split(registryIds);\n            List<RegistryConfig> tmpRegistries = new ArrayList<>();\n            Arrays.stream(ids).forEach(id -> {\n                if (tmpRegistries.stream().noneMatch(reg -> reg.getId().equals(id))) {\n                    Optional<RegistryConfig> globalRegistry = getConfigManager().getRegistry(id);\n                    if (globalRegistry.isPresent()) {\n                        tmpRegistries.add(globalRegistry.get());\n                    } else {\n                        throw new IllegalStateException(\"Registry not found: \" + id);\n                    }\n                }\n            });\n            setRegistries(tmpRegistries);\n        }\n    }\n\n    protected boolean notHasSelfRegistryProperty() {\n        return CollectionUtils.isEmpty(registries) && StringUtils.isEmpty(registryIds);\n    }\n\n    protected void completeCompoundConfigs(AbstractInterfaceConfig interfaceConfig) {\n        if (interfaceConfig != null) {\n            if (application == null) {\n                setApplication(interfaceConfig.getApplication());\n            }\n            if (module == null) {\n                setModule(interfaceConfig.getModule());\n            }\n            if (notHasSelfRegistryProperty()) {\n                setRegistries(interfaceConfig.getRegistries());\n                setRegistryIds(interfaceConfig.getRegistryIds());\n            }\n            if (monitor == null) {\n                setMonitor(interfaceConfig.getMonitor());\n            }\n        }\n        if (module != null) {\n            if (notHasSelfRegistryProperty()) {\n                setRegistries(module.getRegistries());\n            }\n            if (monitor == null) {\n                setMonitor(module.getMonitor());\n            }\n        }\n        if (application != null) {\n            if (notHasSelfRegistryProperty()) {\n                setRegistries(application.getRegistries());\n                setRegistryIds(application.getRegistryIds());\n            }\n            if (monitor == null) {\n                setMonitor(application.getMonitor());\n            }\n        }\n    }\n\n    protected void computeValidRegistryIds() {\n        if (application != null && notHasSelfRegistryProperty()) {\n            setRegistries(application.getRegistries());\n            setRegistryIds(application.getRegistryIds());\n        }\n    }\n\n    /**\n     * @return local\n     * @deprecated Replace to <code>getStub()</code>\n     */\n    @Deprecated\n    public String getLocal() {\n        return local;\n    }\n\n    /**\n     * @param local\n     * @deprecated Replace to <code>setStub(Boolean)</code>\n     */\n    @Deprecated\n    public void setLocal(Boolean local) {\n        if (local == null) {\n            setLocal((String) null);\n        } else {\n            setLocal(local.toString());\n        }\n    }\n\n    /**\n     * @param local\n     * @deprecated Replace to <code>setStub(String)</code>\n     */\n    @Deprecated\n    public void setLocal(String local) {\n        this.local = local;\n    }\n\n    public String getStub() {\n        return stub;\n    }\n\n    public void setStub(Boolean stub) {\n        if (stub == null) {\n            setStub((String) null);\n        } else {\n            setStub(stub.toString());\n        }\n    }\n\n    public void setStub(String stub) {\n        this.stub = stub;\n    }\n\n    public String getCluster() {\n        return cluster;\n    }\n\n    public void setCluster(String cluster) {\n        this.cluster = cluster;\n    }\n\n    public String getProxy() {\n        if (NativeDetector.inNativeImage()) {\n            return DEFAULT_NATIVE_PROXY;\n        } else {\n            return this.proxy;\n        }\n    }\n\n    public void setProxy(String proxy) {\n        if (NativeDetector.inNativeImage()) {\n            this.proxy = DEFAULT_NATIVE_PROXY;\n            AdaptiveCompiler.setDefaultCompiler(DEFAULT_NATIVE_PROXY);\n        } else {\n            this.proxy = proxy;\n        }\n    }\n\n    public Integer getConnections() {\n        return connections;\n    }\n\n    public void setConnections(Integer connections) {\n        this.connections = connections;\n    }\n\n    @Parameter(key = REFERENCE_FILTER_KEY, append = true)\n    public String getFilter() {\n        return filter;\n    }\n\n    public void setFilter(String filter) {\n        this.filter = filter;\n    }\n\n    @Parameter(key = INVOKER_LISTENER_KEY, append = true)\n    public String getListener() {\n        return listener;\n    }\n\n    public void setListener(String listener) {\n        this.listener = listener;\n    }\n\n    public String getLayer() {\n        return layer;\n    }\n\n    public void setLayer(String layer) {\n        this.layer = layer;\n    }\n\n    /**\n     * Always use the global ApplicationConfig\n     */\n    public ApplicationConfig getApplication() {\n        if (application != null) {\n            return application;\n        }\n        return getConfigManager().getApplicationOrElseThrow();\n    }\n\n    /**\n     * @param application\n     * @deprecated Use {@link org.apache.dubbo.config.AbstractConfig#setScopeModel(ScopeModel)}\n     */\n    @Deprecated\n    public void setApplication(ApplicationConfig application) {\n        this.application = application;\n        if (application != null) {\n            getConfigManager().setApplication(application);\n        }\n    }\n\n    public ModuleConfig getModule() {\n        if (module != null) {\n            return module;\n        }\n        return getModuleConfigManager().getModule().orElse(null);\n    }\n\n    /**\n     * @param module\n     * @deprecated Use {@link org.apache.dubbo.config.AbstractConfig#setScopeModel(ScopeModel)}\n     */\n    @Deprecated\n    public void setModule(ModuleConfig module) {\n        this.module = module;\n        if (module != null) {\n            getModuleConfigManager().setModule(module);\n        }\n    }\n\n    public RegistryConfig getRegistry() {\n        return CollectionUtils.isEmpty(registries) ? null : registries.get(0);\n    }\n\n    public void setRegistry(RegistryConfig registry) {\n        if (registry != null) {\n            List<RegistryConfig> registries = new ArrayList<>(1);\n            registries.add(registry);\n            setRegistries(registries);\n        } else {\n            this.registries = null;\n        }\n    }\n\n    public List<RegistryConfig> getRegistries() {\n        return registries;\n    }\n\n    @SuppressWarnings({\"unchecked\"})\n    public void setRegistries(List<? extends RegistryConfig> registries) {\n        this.registries = (List<RegistryConfig>) registries;\n    }\n\n    @Parameter(excluded = true)\n    public String getRegistryIds() {\n        return registryIds;\n    }\n\n    public void setRegistryIds(String registryIds) {\n        this.registryIds = registryIds;\n    }\n\n    public List<MethodConfig> getMethods() {\n        return methods;\n    }\n\n    public void setMethods(List<? extends MethodConfig> methods) {\n        this.methods = (methods != null) ? new ArrayList<>(methods) : null;\n    }\n\n    /**\n     * It is only used in native scenarios to get methodConfigs.\n     * @param methodsJson\n     */\n    public void setMethodsJson(List<String> methodsJson) {\n        if (methodsJson != null) {\n            this.methods = new ArrayList<>();\n            methodsJson.forEach(\n                    (methodConfigJson) -> methods.add(JsonUtils.toJavaObject(methodConfigJson, MethodConfig.class)));\n        } else {\n            this.methods = null;\n        }\n    }\n\n    public void addMethod(MethodConfig methodConfig) {\n        if (this.methods == null) {\n            this.methods = new ArrayList<>();\n        }\n        this.methods.add(methodConfig);\n    }\n\n    public MonitorConfig getMonitor() {\n        if (monitor != null) {\n            return monitor;\n        }\n        // FIXME: instead of return null, we should set default monitor when getMonitor() return null in ConfigManager\n        return getConfigManager().getMonitor().orElse(null);\n    }\n\n    /**\n     * @deprecated Use {@link org.apache.dubbo.config.context.ConfigManager#setMonitor(MonitorConfig)}\n     */\n    @Deprecated\n    public void setMonitor(String monitor) {\n        setMonitor(new MonitorConfig(monitor));\n    }\n\n    /**\n     * @deprecated Use {@link org.apache.dubbo.config.context.ConfigManager#setMonitor(MonitorConfig)}\n     */\n    @Deprecated\n    public void setMonitor(MonitorConfig monitor) {\n        this.monitor = monitor;\n        if (monitor != null) {\n            getConfigManager().setMonitor(monitor);\n        }\n    }\n\n    public String getOwner() {\n        return owner;\n    }\n\n    public void setOwner(String owner) {\n        this.owner = owner;\n    }\n\n    /**\n     * @deprecated Use {@link org.apache.dubbo.config.context.ConfigManager#getConfigCenter(String)}\n     */\n    @Deprecated\n    public ConfigCenterConfig getConfigCenter() {\n        if (configCenter != null) {\n            return configCenter;\n        }\n        Collection<ConfigCenterConfig> configCenterConfigs = getConfigManager().getConfigCenters();\n        if (CollectionUtils.isNotEmpty(configCenterConfigs)) {\n            return configCenterConfigs.iterator().next();\n        }\n        return null;\n    }\n\n    /**\n     * @deprecated Use {@link org.apache.dubbo.config.context.ConfigManager#addConfigCenter(ConfigCenterConfig)}\n     */\n    @Deprecated\n    public void setConfigCenter(ConfigCenterConfig configCenter) {\n        this.configCenter = configCenter;\n        if (configCenter != null) {\n            getConfigManager().addConfigCenter(configCenter);\n        }\n    }\n\n    public Integer getCallbacks() {\n        return callbacks;\n    }\n\n    public void setCallbacks(Integer callbacks) {\n        this.callbacks = callbacks;\n    }\n\n    public String getOnconnect() {\n        return onconnect;\n    }\n\n    public void setOnconnect(String onconnect) {\n        this.onconnect = onconnect;\n    }\n\n    public String getOndisconnect() {\n        return ondisconnect;\n    }\n\n    public void setOndisconnect(String ondisconnect) {\n        this.ondisconnect = ondisconnect;\n    }\n\n    public String getScope() {\n        return scope;\n    }\n\n    public void setScope(String scope) {\n        this.scope = scope;\n    }\n\n    /**\n     * @deprecated Use {@link org.apache.dubbo.config.context.ConfigManager#getMetadataConfigs()}\n     */\n    @Deprecated\n    public MetadataReportConfig getMetadataReportConfig() {\n        if (metadataReportConfig != null) {\n            return metadataReportConfig;\n        }\n        Collection<MetadataReportConfig> metadataReportConfigs =\n                getConfigManager().getMetadataConfigs();\n        if (CollectionUtils.isNotEmpty(metadataReportConfigs)) {\n            return metadataReportConfigs.iterator().next();\n        }\n        return null;\n    }\n\n    /**\n     * @deprecated Use {@link org.apache.dubbo.config.context.ConfigManager#addMetadataReport(MetadataReportConfig)}\n     */\n    @Deprecated\n    public void setMetadataReportConfig(MetadataReportConfig metadataReportConfig) {\n        this.metadataReportConfig = metadataReportConfig;\n        if (metadataReportConfig != null) {\n            getConfigManager().addMetadataReport(metadataReportConfig);\n        }\n    }\n\n    @Parameter(key = TAG_KEY)\n    public String getTag() {\n        return tag;\n    }\n\n    public void setTag(String tag) {\n        this.tag = tag;\n    }\n\n    public Boolean getAuth() {\n        return auth;\n    }\n\n    public void setAuth(Boolean auth) {\n        this.auth = auth;\n    }\n\n    public String getAuthenticator() {\n        return authenticator;\n    }\n\n    public AbstractInterfaceConfig setAuthenticator(String authenticator) {\n        this.authenticator = authenticator;\n        return this;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public AbstractInterfaceConfig setUsername(String username) {\n        this.username = username;\n        return this;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public AbstractInterfaceConfig setPassword(String password) {\n        this.password = password;\n        return this;\n    }\n\n    public SslConfig getSslConfig() {\n        return getConfigManager().getSsl().orElse(null);\n    }\n\n    public Boolean getSingleton() {\n        return singleton;\n    }\n\n    public void setSingleton(Boolean singleton) {\n        this.singleton = singleton;\n    }\n\n    protected void initServiceMetadata(AbstractInterfaceConfig interfaceConfig) {\n        serviceMetadata.setVersion(getVersion(interfaceConfig));\n        serviceMetadata.setGroup(getGroup(interfaceConfig));\n        serviceMetadata.setDefaultGroup(getGroup(interfaceConfig));\n        serviceMetadata.setServiceInterfaceName(getInterface());\n    }\n\n    public String getGroup(AbstractInterfaceConfig interfaceConfig) {\n        return StringUtils.isEmpty(getGroup())\n                ? (interfaceConfig != null ? interfaceConfig.getGroup() : getGroup())\n                : getGroup();\n    }\n\n    public String getVersion(AbstractInterfaceConfig interfaceConfig) {\n        return StringUtils.isEmpty(getVersion())\n                ? (interfaceConfig != null ? interfaceConfig.getVersion() : getVersion())\n                : getVersion();\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public String getInterface() {\n        return interfaceName;\n    }\n\n    public void setInterface(String interfaceName) {\n        this.interfaceName = interfaceName;\n    }\n\n    @Transient\n    public ClassLoader getInterfaceClassLoader() {\n        return interfaceClassLoader;\n    }\n\n    public void setInterfaceClassLoader(ClassLoader interfaceClassLoader) {\n        this.interfaceClassLoader = interfaceClassLoader;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/AbstractMethodConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.beans.Transient;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\n\n/**\n * Abstract configuration for the method.\n *\n * @export\n */\npublic abstract class AbstractMethodConfig extends AbstractConfig {\n\n    private static final long serialVersionUID = 5809761483000878437L;\n\n    /**\n     * Timeout for remote invocation in milliseconds.\n     */\n    protected Integer timeout;\n\n    /**\n     * Retry times for failed invocations.\n     */\n    protected Integer retries;\n\n    /**\n     * Maximum concurrent invocations allowed.\n     */\n    protected Integer actives;\n\n    /**\n     * Load balancing strategy for service invocation.\n     */\n    protected String loadbalance;\n\n    /**\n     * Enable asynchronous invocation. Note that it is unreliable asynchronous, ignoring return values and not blocking threads.\n     */\n    protected Boolean async;\n\n    /**\n     * Acknowledge asynchronous-sent invocations.\n     */\n    protected Boolean sent;\n\n    /**\n     * Mock class name to be called when a service fails to execute. The mock doesn't support on the provider side,\n     * and it is executed when a non-business exception occurs after a remote service call.\n     */\n    protected String mock;\n\n    /**\n     * Merger for result data.\n     */\n    protected String merger;\n\n    /**\n     * Cache provider for caching return results. available options: lru, threadlocal, jcache etc.\n     */\n    protected String cache;\n\n    /**\n     * Enable JSR303 standard annotation validation for method parameters.\n     */\n    protected String validation;\n\n    /**\n     * Customized parameters for configuration.\n     */\n    protected Map<String, String> parameters;\n\n    /**\n     * Forks for forking cluster.\n     */\n    protected Integer forks;\n\n    public AbstractMethodConfig() {}\n\n    public AbstractMethodConfig(ModuleModel moduleModel) {\n        super(moduleModel);\n    }\n\n    @Override\n    @Transient\n    public ModuleModel getScopeModel() {\n        return (ModuleModel) super.getScopeModel();\n    }\n\n    @Override\n    @Transient\n    protected ScopeModel getDefaultModel() {\n        return ApplicationModel.defaultModel().getDefaultModule();\n    }\n\n    @Override\n    protected void checkScopeModel(ScopeModel scopeModel) {\n        if (!(scopeModel instanceof ModuleModel)) {\n            throw new IllegalArgumentException(\n                    \"Invalid scope model, expect to be a ModuleModel but got: \" + scopeModel);\n        }\n    }\n\n    @Transient\n    protected ModuleConfigManager getModuleConfigManager() {\n        return getScopeModel().getConfigManager();\n    }\n\n    public Integer getForks() {\n        return forks;\n    }\n\n    public void setForks(Integer forks) {\n        this.forks = forks;\n    }\n\n    public Integer getTimeout() {\n        return timeout;\n    }\n\n    public void setTimeout(Integer timeout) {\n        this.timeout = timeout;\n    }\n\n    public Integer getRetries() {\n        return retries;\n    }\n\n    public void setRetries(Integer retries) {\n        this.retries = retries;\n    }\n\n    public String getLoadbalance() {\n        return loadbalance;\n    }\n\n    public void setLoadbalance(String loadbalance) {\n        this.loadbalance = loadbalance;\n    }\n\n    public Boolean isAsync() {\n        return async;\n    }\n\n    public void setAsync(Boolean async) {\n        this.async = async;\n    }\n\n    public Integer getActives() {\n        return actives;\n    }\n\n    public void setActives(Integer actives) {\n        this.actives = actives;\n    }\n\n    public Boolean getSent() {\n        return sent;\n    }\n\n    public void setSent(Boolean sent) {\n        this.sent = sent;\n    }\n\n    @Parameter(escaped = true)\n    public String getMock() {\n        return mock;\n    }\n\n    public void setMock(String mock) {\n        this.mock = mock;\n    }\n\n    /**\n     * Set the property \"mock\"\n     *\n     * @param mock the value of mock\n     * @since 2.7.6\n     * @deprecated use {@link #setMock(String)} instead\n     */\n    @Deprecated\n    public void setMock(Object mock) {\n        if (mock == null) {\n            return;\n        }\n        this.setMock(String.valueOf(mock));\n    }\n\n    public String getMerger() {\n        return merger;\n    }\n\n    public void setMerger(String merger) {\n        this.merger = merger;\n    }\n\n    public String getCache() {\n        return cache;\n    }\n\n    public void setCache(String cache) {\n        this.cache = cache;\n    }\n\n    public String getValidation() {\n        return validation;\n    }\n\n    public void setValidation(String validation) {\n        this.validation = validation;\n    }\n\n    public Map<String, String> getParameters() {\n        this.parameters = Optional.ofNullable(this.parameters).orElseGet(HashMap::new);\n        return this.parameters;\n    }\n\n    public void setParameters(Map<String, String> parameters) {\n        this.parameters = parameters;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/AbstractReferenceConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.support.ProtocolUtils;\n\nimport java.beans.Transient;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.INVOKER_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFER_ASYNC_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ROUTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.STUB_EVENT_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDED_BY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDER_NAMESPACE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDER_PORT;\n\n/**\n * AbstractConsumerConfig\n *\n * @export\n * @see ReferenceConfigBase\n */\npublic abstract class AbstractReferenceConfig extends AbstractInterfaceConfig {\n\n    private static final long serialVersionUID = -2786526984373031126L;\n\n    // ======== Reference config default values, will take effect if reference's attribute is not set  ========\n\n    /**\n     * Check if service provider exists, if not exists, it will be fast fail\n     */\n    protected Boolean check;\n\n    /**\n     * Whether to eagle-init\n     */\n    protected Boolean init;\n\n    /**\n     * Whether to use generic interface\n     */\n    protected String generic;\n\n    /**\n     * Whether to find reference's instance from the current JVM\n     */\n    protected Boolean injvm;\n\n    /**\n     * Lazy create connection\n     */\n    protected Boolean lazy;\n\n    protected String reconnect;\n\n    protected Boolean sticky;\n\n    /**\n     * Whether to support event in stub.\n     */\n    // TODO solve merge problem\n    protected Boolean stubevent; // = Constants.DEFAULT_STUB_EVENT;\n\n    /**\n     * declares which app or service this interface belongs to\n     */\n    protected String providedBy;\n\n    /**\n     * By VirtualService and DestinationRule, envoy will generate a new route rule,such as 'demo.default.svc.cluster.local:80',the default port is 80.\n     * When you want to specify the provider port,you can use this config.\n     *\n     * @since 3.1.0\n     */\n    protected Integer providerPort;\n\n    /**\n     * assign the namespace that provider belong to\n     * @since 3.1.1\n     */\n    protected String providerNamespace;\n\n    protected String router;\n\n    /**\n     * Weather the reference is referred asynchronously\n     *\n     * @see ModuleConfig#referAsync\n     * @deprecated\n     */\n    @Deprecated\n    private Boolean referAsync;\n\n    /**\n     * client type\n     */\n    protected String client;\n\n    /**\n     * Only the service provider of the specified protocol is invoked, and other protocols are ignored.\n     */\n    protected String protocol;\n\n    public AbstractReferenceConfig() {}\n\n    public AbstractReferenceConfig(ModuleModel moduleModel) {\n        super(moduleModel);\n    }\n\n    @Override\n    protected void checkDefault() {\n        super.checkDefault();\n        if (sticky == null) {\n            sticky = false;\n        }\n    }\n\n    public Boolean isCheck() {\n        return check;\n    }\n\n    public void setCheck(Boolean check) {\n        this.check = check;\n    }\n\n    public Boolean isInit() {\n        return init;\n    }\n\n    public void setInit(Boolean init) {\n        this.init = init;\n    }\n\n    /**\n     * @deprecated Replace to {@link AbstractReferenceConfig#getGeneric()}\n     */\n    @Deprecated\n    @Parameter(excluded = true, attribute = false)\n    public Boolean isGeneric() {\n        return this.generic != null ? ProtocolUtils.isGeneric(generic) : null;\n    }\n\n    /**\n     * @deprecated Replace to {@link AbstractReferenceConfig#setGeneric(String)}\n     */\n    @Deprecated\n    public void setGeneric(Boolean generic) {\n        if (generic != null) {\n            this.generic = generic.toString();\n        }\n    }\n\n    public String getGeneric() {\n        return generic;\n    }\n\n    public void setGeneric(String generic) {\n        if (StringUtils.isEmpty(generic)) {\n            return;\n        }\n        if (ProtocolUtils.isValidGenericValue(generic)) {\n            this.generic = generic;\n        } else {\n            throw new IllegalArgumentException(\"Unsupported generic type \" + generic);\n        }\n    }\n\n    @Override\n    @Transient\n    protected boolean isNeedCheckMethod() {\n        return StringUtils.isEmpty(getGeneric());\n    }\n\n    /**\n     * @return\n     * @deprecated instead, use the parameter <b>scope</> to judge if it's in jvm, scope=local\n     */\n    @Deprecated\n    public Boolean isInjvm() {\n        return injvm;\n    }\n\n    /**\n     * @param injvm\n     * @deprecated instead, use the parameter <b>scope</b> to judge if it's in jvm, scope=local\n     */\n    @Deprecated\n    public void setInjvm(Boolean injvm) {\n        this.injvm = injvm;\n    }\n\n    @Override\n    @Parameter(key = REFERENCE_FILTER_KEY, append = true)\n    public String getFilter() {\n        return super.getFilter();\n    }\n\n    @Override\n    @Parameter(key = INVOKER_LISTENER_KEY, append = true)\n    public String getListener() {\n        return super.getListener();\n    }\n\n    @Override\n    public void setListener(String listener) {\n        super.setListener(listener);\n    }\n\n    public Boolean getLazy() {\n        return lazy;\n    }\n\n    public void setLazy(Boolean lazy) {\n        this.lazy = lazy;\n    }\n\n    @Override\n    public void setOnconnect(String onconnect) {\n        if (onconnect != null && onconnect.length() > 0) {\n            this.stubevent = true;\n        }\n        super.setOnconnect(onconnect);\n    }\n\n    @Override\n    public void setOndisconnect(String ondisconnect) {\n        if (ondisconnect != null && ondisconnect.length() > 0) {\n            this.stubevent = true;\n        }\n        super.setOndisconnect(ondisconnect);\n    }\n\n    @Parameter(key = STUB_EVENT_KEY)\n    public Boolean getStubevent() {\n        return stubevent;\n    }\n\n    public String getReconnect() {\n        return reconnect;\n    }\n\n    public void setReconnect(String reconnect) {\n        this.reconnect = reconnect;\n    }\n\n    public Boolean getSticky() {\n        return sticky;\n    }\n\n    public void setSticky(Boolean sticky) {\n        this.sticky = sticky;\n    }\n\n    @Parameter(key = PROVIDED_BY)\n    public String getProvidedBy() {\n        return providedBy;\n    }\n\n    public void setProvidedBy(String providedBy) {\n        this.providedBy = providedBy;\n    }\n\n    @Parameter(key = PROVIDER_PORT)\n    public Integer getProviderPort() {\n        return providerPort;\n    }\n\n    public void setProviderPort(Integer providerPort) {\n        this.providerPort = providerPort;\n    }\n\n    @Parameter(key = PROVIDER_NAMESPACE)\n    public String getProviderNamespace() {\n        return providerNamespace;\n    }\n\n    public void setProviderNamespace(String providerNamespace) {\n        this.providerNamespace = providerNamespace;\n    }\n\n    @Parameter(key = ROUTER_KEY, append = true)\n    public String getRouter() {\n        return router;\n    }\n\n    public void setRouter(String router) {\n        this.router = router;\n    }\n\n    @Deprecated\n    @Parameter(key = REFER_ASYNC_KEY)\n    public Boolean getReferAsync() {\n        return referAsync;\n    }\n\n    @Deprecated\n    public void setReferAsync(Boolean referAsync) {\n        this.referAsync = referAsync;\n    }\n\n    public String getClient() {\n        return client;\n    }\n\n    public void setClient(String client) {\n        this.client = client;\n    }\n\n    public String getProtocol() {\n        return protocol;\n    }\n\n    public void setProtocol(String protocol) {\n        this.protocol = protocol;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/AbstractServiceConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.beans.Transient;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Executor;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.EXPORTER_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXPORT_ASYNC_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SERVICE_EXECUTOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.SERVICE_FILTER_KEY;\n\n/**\n * Abstract configuration for the service.\n *\n * @export\n */\npublic abstract class AbstractServiceConfig extends AbstractInterfaceConfig {\n\n    private static final long serialVersionUID = -9026290350363878309L;\n\n    /**\n     * The service version.\n     */\n    protected String version;\n\n    /**\n     * The service group.\n     */\n    protected String group;\n\n    /**\n     * Whether the service is deprecated.\n     */\n    protected Boolean deprecated;\n\n    /**\n     * The time delay to register the service (in milliseconds).\n     */\n    protected Integer delay;\n\n    /**\n     * Whether to export the service.\n     */\n    protected Boolean export;\n\n    /**\n     * The service weight.\n     */\n    protected Integer weight;\n\n    /**\n     * Document center for the service.\n     */\n    protected String document;\n\n    /**\n     * Whether to register the service as a dynamic service on the registry. If true, the service\n     * will be enabled automatically after registration, and manual disabling is required to stop it.\n     */\n    protected Boolean dynamic;\n\n    /**\n     * Whether to use a token for authentication.\n     */\n    protected String token;\n\n    /**\n     * Whether to export access logs to logs.\n     */\n    protected String accesslog;\n\n    /**\n     * List of protocols the service will export with (use this or protocolIds, not both).\n     */\n    protected List<ProtocolConfig> protocols;\n\n    /**\n     * Id list of protocols the service will export with (use this or protocols, not both).\n     */\n    protected String protocolIds;\n\n    /**\n     * Max allowed executing times.\n     */\n    private Integer executes;\n\n    /**\n     * Whether to register the service.\n     */\n    private Boolean register;\n\n    /**\n     * Warm-up period for the service.\n     */\n    private Integer warmup;\n\n    /**\n     * Serialization type for service communication.\n     */\n    private String serialization;\n\n    /**\n     * Specifies the preferred serialization method for the consumer.\n     *  If specified, the consumer will use this parameter first.\n     * If the Dubbo Sdk you are using contains the serialization type, the serialization method specified by the argument is used.\n     * <p>\n     * When this parameter is null or the serialization type specified by this parameter does not exist in the Dubbo SDK, the serialization type specified by serialization is used.\n     * If the Dubbo SDK if still does not exist, the default type of the Dubbo SDK is used.\n     * For Dubbo SDK >= 3.2, <code>preferSerialization</code> takes precedence over <code>serialization</code>\n     * <p>\n     * Supports multiple values separated by commas, e.g., \"fastjson2,fastjson,hessian2\".\n     */\n    private String preferSerialization; // Default: fastjson2, hessian2\n\n    /**\n     * Weather the service is export asynchronously\n     * @deprecated\n     * @see ModuleConfig#exportAsync\n     */\n    @Deprecated\n    private Boolean exportAsync;\n\n    /**\n     * used for thread pool isolation between services\n     */\n    private Executor executor;\n\n    /**\n     * Payload max length.\n     */\n    private Integer payload;\n\n    /**\n     * Whether to use java_package in IDL as path. Default use package.\n     * This param only available when service using native stub.\n     */\n    private Boolean useJavaPackageAsPath;\n\n    public AbstractServiceConfig() {}\n\n    public AbstractServiceConfig(ModuleModel moduleModel) {\n        super(moduleModel);\n    }\n\n    @Override\n    protected void checkDefault() {\n        super.checkDefault();\n        if (deprecated == null) {\n            deprecated = false;\n        }\n        if (dynamic == null) {\n            dynamic = true;\n        }\n        if (useJavaPackageAsPath == null) {\n            useJavaPackageAsPath = false;\n        }\n        if (StringUtils.isBlank(preferSerialization)) {\n            preferSerialization = serialization;\n        }\n    }\n\n    @Override\n    public String getVersion() {\n        return version;\n    }\n\n    @Override\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    @Override\n    public String getGroup() {\n        return group;\n    }\n\n    @Override\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public Integer getDelay() {\n        return delay;\n    }\n\n    public void setDelay(Integer delay) {\n        this.delay = delay;\n    }\n\n    public Boolean getExport() {\n        return export;\n    }\n\n    public void setExport(Boolean export) {\n        this.export = export;\n    }\n\n    public Integer getWeight() {\n        return weight;\n    }\n\n    public void setWeight(Integer weight) {\n        this.weight = weight;\n    }\n\n    @Parameter(escaped = true)\n    public String getDocument() {\n        return document;\n    }\n\n    public void setDocument(String document) {\n        this.document = document;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public void setToken(Boolean token) {\n        if (token == null) {\n            setToken((String) null);\n        } else {\n            setToken(String.valueOf(token));\n        }\n    }\n\n    public void setToken(String token) {\n        this.token = token;\n    }\n\n    public Boolean isDeprecated() {\n        return deprecated;\n    }\n\n    public void setDeprecated(Boolean deprecated) {\n        this.deprecated = deprecated;\n    }\n\n    public Boolean isDynamic() {\n        return dynamic;\n    }\n\n    public void setDynamic(Boolean dynamic) {\n        this.dynamic = dynamic;\n    }\n\n    public List<ProtocolConfig> getProtocols() {\n        return protocols;\n    }\n\n    @SuppressWarnings({\"unchecked\"})\n    public void setProtocols(List<? extends ProtocolConfig> protocols) {\n        this.protocols = (List<ProtocolConfig>) protocols;\n    }\n\n    public ProtocolConfig getProtocol() {\n        return CollectionUtils.isEmpty(protocols) ? null : protocols.get(0);\n    }\n\n    public void setProtocol(ProtocolConfig protocol) {\n        setProtocols(new ArrayList<>(Collections.singletonList(protocol)));\n    }\n\n    @Parameter(excluded = true)\n    public String getProtocolIds() {\n        return protocolIds;\n    }\n\n    public void setProtocolIds(String protocolIds) {\n        this.protocolIds = protocolIds;\n    }\n\n    public String getAccesslog() {\n        return accesslog;\n    }\n\n    public void setAccesslog(Boolean accesslog) {\n        if (accesslog == null) {\n            setAccesslog((String) null);\n        } else {\n            setAccesslog(String.valueOf(accesslog));\n        }\n    }\n\n    public void setAccesslog(String accesslog) {\n        this.accesslog = accesslog;\n    }\n\n    public Integer getExecutes() {\n        return executes;\n    }\n\n    public void setExecutes(Integer executes) {\n        this.executes = executes;\n    }\n\n    @Override\n    @Parameter(key = SERVICE_FILTER_KEY, append = true)\n    public String getFilter() {\n        return super.getFilter();\n    }\n\n    @Override\n    @Parameter(key = EXPORTER_LISTENER_KEY, append = true)\n    public String getListener() {\n        return listener;\n    }\n\n    @Override\n    public void setListener(String listener) {\n        this.listener = listener;\n    }\n\n    public Boolean isRegister() {\n        return register;\n    }\n\n    public void setRegister(Boolean register) {\n        this.register = register;\n    }\n\n    public Integer getWarmup() {\n        return warmup;\n    }\n\n    public void setWarmup(Integer warmup) {\n        this.warmup = warmup;\n    }\n\n    public String getSerialization() {\n        return serialization;\n    }\n\n    public void setSerialization(String serialization) {\n        this.serialization = serialization;\n    }\n\n    public String getPreferSerialization() {\n        return preferSerialization;\n    }\n\n    public void setPreferSerialization(String preferSerialization) {\n        this.preferSerialization = preferSerialization;\n    }\n\n    @Deprecated\n    @Parameter(key = EXPORT_ASYNC_KEY)\n    public Boolean getExportAsync() {\n        return exportAsync;\n    }\n\n    @Deprecated\n    public void setExportAsync(Boolean exportAsync) {\n        this.exportAsync = exportAsync;\n    }\n\n    public void setExecutor(Executor executor) {\n        this.executor = executor;\n    }\n\n    @Parameter(key = SERVICE_EXECUTOR)\n    @Transient\n    public Executor getExecutor() {\n        return executor;\n    }\n\n    public Integer getPayload() {\n        return payload;\n    }\n\n    public void setPayload(Integer payload) {\n        this.payload = payload;\n    }\n\n    @Parameter(excluded = true, attribute = false)\n    public Boolean getUseJavaPackageAsPath() {\n        return useJavaPackageAsPath;\n    }\n\n    public void setUseJavaPackageAsPath(Boolean useJavaPackageAsPath) {\n        this.useJavaPackageAsPath = useJavaPackageAsPath;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/ApplicationConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.aot.NativeDetector;\nimport org.apache.dubbo.common.compiler.support.AdaptiveCompiler;\nimport org.apache.dubbo.common.infra.InfraAdapter;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUMP_ENABLE;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_ISOLATION;\nimport static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.LIVENESS_PROBE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_SERVICE_PORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_SERVICE_PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.READINESS_PROBE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED;\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.STARTUP_PROBE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_WHITELIST;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_WHITELIST_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_ALLOW_COMMANDS;\nimport static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_PERMISSION_LEVEL;\nimport static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_PERMISSION_LEVEL_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_CHECK;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_HOST_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_PORT_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;\nimport static org.apache.dubbo.config.Constants.DEFAULT_APP_NAME;\nimport static org.apache.dubbo.config.Constants.DEFAULT_NATIVE_COMPILER;\nimport static org.apache.dubbo.config.Constants.DEVELOPMENT_ENVIRONMENT;\nimport static org.apache.dubbo.config.Constants.PRODUCTION_ENVIRONMENT;\nimport static org.apache.dubbo.config.Constants.TEST_ENVIRONMENT;\n\n/**\n * Configuration for the dubbo application.\n *\n * @export\n */\npublic class ApplicationConfig extends AbstractConfig {\n\n    private static final long serialVersionUID = 5508512956753757169L;\n\n    private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(ApplicationConfig.class);\n\n    /**\n     * The Application name.\n     */\n    private String name;\n\n    /**\n     * The application version.\n     */\n    private String version;\n\n    /**\n     * The application owner.\n     */\n    private String owner;\n\n    /**\n     * The application's organization (BU).\n     */\n    private String organization;\n\n    /**\n     * Architecture layer.\n     */\n    private String architecture;\n\n    /**\n     * Environment, e.g., dev, test, or production.\n     */\n    private String environment;\n\n    /**\n     * Java compiler.\n     */\n    private String compiler;\n\n    /**\n     * The type of log access.\n     */\n    private String logger;\n\n    /**\n     * Registry centers.\n     */\n    private List<RegistryConfig> registries;\n\n    /**\n     * The comma-separated list of registry IDs to which the service will be registered.\n     */\n    private String registryIds;\n\n    /**\n     * Monitor center.\n     */\n    private MonitorConfig monitor;\n\n    /**\n     * Directory for saving thread dump.\n     */\n    private String dumpDirectory;\n\n    /**\n     * Whether to enable saving thread dump or not.\n     */\n    private Boolean dumpEnable;\n\n    /**\n     * Whether to enable Quality of Service (QoS) or not.\n     */\n    private Boolean qosEnable;\n\n    /**\n     * Whether QoS should start successfully or not, will check qosEnable first.\n     */\n    private Boolean qosCheck;\n\n    /**\n     * The QoS host to listen.\n     */\n    private String qosHost;\n\n    /**\n     * The QoS port to listen.\n     */\n    private Integer qosPort;\n\n    /**\n     * Should we accept foreign IP or not?\n     */\n    private Boolean qosAcceptForeignIp;\n\n    /**\n     * When we disable accepting foreign IP, support specifying foreign IPs in the whitelist.\n     */\n    private String qosAcceptForeignIpWhitelist;\n\n    /**\n     * The anonymous (any foreign IP) access permission level, default is NONE, which means no access to any command.\n     */\n    private String qosAnonymousAccessPermissionLevel;\n\n    /**\n     * The anonymous (any foreign IP) allowed commands, default is empty, which means no access to any command.\n     */\n    private String qosAnonymousAllowCommands;\n\n    /**\n     * Customized parameters.\n     */\n    private Map<String, String> parameters;\n\n    /**\n     * Config the shutdown wait.\n     */\n    private String shutwait;\n\n    /**\n     * Hostname.\n     */\n    private String hostname;\n\n    /**\n     * Metadata type, local or remote. If 'remote' is chosen, you need to specify a metadata center further.\n     */\n    private String metadataType;\n\n    /**\n     * Used to control whether to register the instance with the registry or not. Set to 'false' only when the instance is a pure consumer.\n     */\n    private Boolean registerConsumer;\n\n    /**\n     * Repository.\n     */\n    private String repository;\n\n    /**\n     * Whether to enable file caching.\n     */\n    private Boolean enableFileCache;\n\n    /**\n     * The preferred protocol (name) of this application, convenient for places where it's hard to determine the preferred protocol.\n     */\n    private String protocol;\n\n    /**\n     * The protocol used for peer-to-peer metadata transmission.\n     */\n    private String metadataServiceProtocol;\n\n    /**\n     * Metadata Service, used in Service Discovery.\n     */\n    private Integer metadataServicePort;\n\n    /**\n     * The retry interval of service name mapping.\n     */\n    private Integer mappingRetryInterval;\n\n    /**\n     * Used to set extensions of the probe in QoS.\n     */\n    private String livenessProbe;\n\n    /**\n     * The probe for checking the readiness of the application.\n     */\n    private String readinessProbe;\n\n    /**\n     * The probe for checking the startup of the application.\n     */\n    private String startupProbe;\n\n    /**\n     * Register mode.\n     */\n    private String registerMode;\n\n    /**\n     * Whether to enable protection against empty objects.\n     */\n    private Boolean enableEmptyProtection;\n\n    /**\n     * The status of class serialization checking.\n     */\n    private String serializeCheckStatus;\n\n    /**\n     * Whether to automatically trust serialized classes.\n     */\n    private Boolean autoTrustSerializeClass;\n\n    /**\n     * The trust level for serialized classes.\n     */\n    private Integer trustSerializeClassLevel;\n\n    /**\n     * Whether to check serializable.\n     */\n    private Boolean checkSerializable;\n\n    /**\n     * Thread pool management mode: 'default' or 'isolation'.\n     */\n    private String executorManagementMode;\n\n    /**\n     * Only use the new version of metadataService (MetadataServiceV2).\n     * <br> MetadataServiceV2 have better compatibility with other language's dubbo implement (dubbo-go).\n     * <br> If set to false (default):\n     * <br>  1. If your services are using triple protocol and {@link #metadataServiceProtocol} is not set\n     * <br>     - Dubbo will export both MetadataService and MetadataServiceV2 with triple\n     * <br>  2. Set {@link #metadataServiceProtocol} = tri\n     * <br>     - Dubbo will export both MetadataService and MetadataServiceV2 with triple\n     * <br>  3. Set {@link #metadataServiceProtocol} != tri\n     * <br>     - Dubbo will only export MetadataService\n     * <br>  4. Your services are not using triple protocol, and {@link #metadataServiceProtocol} is not set\n     * <br>     - Dubbo will only export MetadataService\n     * <br>\n     * <br>  If set to true, dubbo will try to only use MetadataServiceV2.\n     * <br>  It only activates when meet at least one of the following cases:\n     * <br>     1. Manually set {@link #metadataServiceProtocol} = tri\n     * <br>     2. Your services are using triple protocol\n     * <br>\n     */\n    private Boolean onlyUseMetadataV2;\n\n    public ApplicationConfig() {}\n\n    public ApplicationConfig(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    public ApplicationConfig(String name) {\n        setName(name);\n    }\n\n    public ApplicationConfig(ApplicationModel applicationModel, String name) {\n        super(applicationModel);\n        setName(name);\n    }\n\n    @Override\n    protected void checkDefault() {\n        super.checkDefault();\n        if (protocol == null) {\n            protocol = DUBBO;\n        }\n        if (hostname == null) {\n            try {\n                hostname = InetAddress.getLocalHost().getHostName();\n            } catch (UnknownHostException e) {\n                LOGGER.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"Failed to get the hostname of current instance.\", e);\n                hostname = \"UNKNOWN\";\n            }\n        }\n        if (executorManagementMode == null) {\n            executorManagementMode = EXECUTOR_MANAGEMENT_MODE_ISOLATION;\n        }\n        if (enableFileCache == null) {\n            enableFileCache = Boolean.TRUE;\n        }\n    }\n\n    @Parameter(key = APPLICATION_KEY, required = true)\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Parameter(key = APPLICATION_VERSION_KEY)\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    public String getOwner() {\n        return owner;\n    }\n\n    public void setOwner(String owner) {\n        this.owner = owner;\n    }\n\n    public String getOrganization() {\n        return organization;\n    }\n\n    public void setOrganization(String organization) {\n        this.organization = organization;\n    }\n\n    public String getArchitecture() {\n        return architecture;\n    }\n\n    public void setArchitecture(String architecture) {\n        this.architecture = architecture;\n    }\n\n    public String getEnvironment() {\n        return environment;\n    }\n\n    public void setEnvironment(String environment) {\n        if (environment != null\n                && !(DEVELOPMENT_ENVIRONMENT.equals(environment)\n                        || TEST_ENVIRONMENT.equals(environment)\n                        || PRODUCTION_ENVIRONMENT.equals(environment))) {\n\n            throw new IllegalStateException(String.format(\n                    \"Unsupported environment: %s, only support %s/%s/%s, default is %s.\",\n                    environment,\n                    DEVELOPMENT_ENVIRONMENT,\n                    TEST_ENVIRONMENT,\n                    PRODUCTION_ENVIRONMENT,\n                    PRODUCTION_ENVIRONMENT));\n        }\n        this.environment = environment;\n    }\n\n    public RegistryConfig getRegistry() {\n        return CollectionUtils.isEmpty(registries) ? null : registries.get(0);\n    }\n\n    public void setRegistry(RegistryConfig registry) {\n        List<RegistryConfig> registries = new ArrayList<>(1);\n        registries.add(registry);\n        this.registries = registries;\n    }\n\n    public List<RegistryConfig> getRegistries() {\n        return registries;\n    }\n\n    @SuppressWarnings({\"unchecked\"})\n    public void setRegistries(List<? extends RegistryConfig> registries) {\n        this.registries = (List<RegistryConfig>) registries;\n    }\n\n    @Parameter(excluded = true)\n    public String getRegistryIds() {\n        return registryIds;\n    }\n\n    public void setRegistryIds(String registryIds) {\n        this.registryIds = registryIds;\n    }\n\n    public MonitorConfig getMonitor() {\n        return monitor;\n    }\n\n    public void setMonitor(String monitor) {\n        this.monitor = new MonitorConfig(monitor);\n    }\n\n    public void setMonitor(MonitorConfig monitor) {\n        this.monitor = monitor;\n    }\n\n    public String getCompiler() {\n        if (NativeDetector.inNativeImage()) {\n            return DEFAULT_NATIVE_COMPILER;\n        } else {\n            return compiler;\n        }\n    }\n\n    public void setCompiler(String compiler) {\n\n        if (NativeDetector.inNativeImage()) {\n            this.compiler = DEFAULT_NATIVE_COMPILER;\n            AdaptiveCompiler.setDefaultCompiler(DEFAULT_NATIVE_COMPILER);\n        } else {\n            this.compiler = compiler;\n            AdaptiveCompiler.setDefaultCompiler(compiler);\n        }\n    }\n\n    public String getLogger() {\n        return logger;\n    }\n\n    public void setLogger(String logger) {\n        this.logger = logger;\n        LoggerFactory.setLoggerAdapter(getApplicationModel().getFrameworkModel(), logger);\n    }\n\n    @Parameter(key = DUMP_DIRECTORY)\n    public String getDumpDirectory() {\n        return dumpDirectory;\n    }\n\n    public void setDumpDirectory(String dumpDirectory) {\n        this.dumpDirectory = dumpDirectory;\n    }\n\n    @Parameter(key = DUMP_ENABLE)\n    public Boolean getDumpEnable() {\n        return dumpEnable;\n    }\n\n    public void setDumpEnable(Boolean dumpEnable) {\n        this.dumpEnable = dumpEnable;\n    }\n\n    @Parameter(key = QOS_ENABLE)\n    public Boolean getQosEnable() {\n        return qosEnable;\n    }\n\n    public void setQosEnable(Boolean qosEnable) {\n        this.qosEnable = qosEnable;\n    }\n\n    @Parameter(key = QOS_CHECK)\n    public Boolean getQosCheck() {\n        return qosCheck;\n    }\n\n    public void setQosCheck(Boolean qosCheck) {\n        this.qosCheck = qosCheck;\n    }\n\n    @Parameter(key = QOS_HOST)\n    public String getQosHost() {\n        return qosHost;\n    }\n\n    public void setQosHost(String qosHost) {\n        this.qosHost = qosHost;\n    }\n\n    @Parameter(key = QOS_PORT)\n    public Integer getQosPort() {\n        return qosPort;\n    }\n\n    public void setQosPort(Integer qosPort) {\n        this.qosPort = qosPort;\n    }\n\n    @Parameter(key = ACCEPT_FOREIGN_IP)\n    public Boolean getQosAcceptForeignIp() {\n        return qosAcceptForeignIp;\n    }\n\n    public void setQosAcceptForeignIp(Boolean qosAcceptForeignIp) {\n        this.qosAcceptForeignIp = qosAcceptForeignIp;\n    }\n\n    @Parameter(key = ACCEPT_FOREIGN_IP_WHITELIST)\n    public String getQosAcceptForeignIpWhitelist() {\n        return qosAcceptForeignIpWhitelist;\n    }\n\n    public void setQosAcceptForeignIpWhitelist(String qosAcceptForeignIpWhitelist) {\n        this.qosAcceptForeignIpWhitelist = qosAcceptForeignIpWhitelist;\n    }\n\n    @Parameter(key = ANONYMOUS_ACCESS_PERMISSION_LEVEL)\n    public String getQosAnonymousAccessPermissionLevel() {\n        return qosAnonymousAccessPermissionLevel;\n    }\n\n    public void setQosAnonymousAccessPermissionLevel(String qosAnonymousAccessPermissionLevel) {\n        this.qosAnonymousAccessPermissionLevel = qosAnonymousAccessPermissionLevel;\n    }\n\n    @Parameter(key = ANONYMOUS_ACCESS_ALLOW_COMMANDS)\n    public String getQosAnonymousAllowCommands() {\n        return qosAnonymousAllowCommands;\n    }\n\n    public void setQosAnonymousAllowCommands(String qosAnonymousAllowCommands) {\n        this.qosAnonymousAllowCommands = qosAnonymousAllowCommands;\n    }\n\n    /**\n     * The format is the same as the springboot, including: getQosEnableCompatible(), getQosPortCompatible(), getQosAcceptForeignIpCompatible().\n     *\n     */\n    @Parameter(key = QOS_ENABLE_COMPATIBLE, excluded = true, attribute = false)\n    public Boolean getQosEnableCompatible() {\n        return getQosEnable();\n    }\n\n    public void setQosEnableCompatible(Boolean qosEnable) {\n        setQosEnable(qosEnable);\n    }\n\n    @Parameter(key = QOS_HOST_COMPATIBLE, excluded = true, attribute = false)\n    public String getQosHostCompatible() {\n        return getQosHost();\n    }\n\n    public void setQosHostCompatible(String qosHost) {\n        this.setQosHost(qosHost);\n    }\n\n    @Parameter(key = QOS_PORT_COMPATIBLE, excluded = true, attribute = false)\n    public Integer getQosPortCompatible() {\n        return getQosPort();\n    }\n\n    public void setQosPortCompatible(Integer qosPort) {\n        this.setQosPort(qosPort);\n    }\n\n    @Parameter(key = ACCEPT_FOREIGN_IP_COMPATIBLE, excluded = true, attribute = false)\n    public Boolean getQosAcceptForeignIpCompatible() {\n        return this.getQosAcceptForeignIp();\n    }\n\n    public void setQosAcceptForeignIpCompatible(Boolean qosAcceptForeignIp) {\n        this.setQosAcceptForeignIp(qosAcceptForeignIp);\n    }\n\n    @Parameter(key = ACCEPT_FOREIGN_IP_WHITELIST_COMPATIBLE, excluded = true, attribute = false)\n    public String getQosAcceptForeignIpWhitelistCompatible() {\n        return this.getQosAcceptForeignIpWhitelist();\n    }\n\n    public void setQosAcceptForeignIpWhitelistCompatible(String qosAcceptForeignIpWhitelist) {\n        this.setQosAcceptForeignIpWhitelist(qosAcceptForeignIpWhitelist);\n    }\n\n    @Parameter(key = ANONYMOUS_ACCESS_PERMISSION_LEVEL_COMPATIBLE, excluded = true, attribute = false)\n    public String getQosAnonymousAccessPermissionLevelCompatible() {\n        return this.getQosAnonymousAccessPermissionLevel();\n    }\n\n    public void setQosAnonymousAccessPermissionLevelCompatible(String qosAnonymousAccessPermissionLevel) {\n        this.setQosAnonymousAccessPermissionLevel(qosAnonymousAccessPermissionLevel);\n    }\n\n    public Map<String, String> getParameters() {\n        return parameters;\n    }\n\n    public void setParameters(Map<String, String> parameters) {\n        this.parameters = parameters;\n    }\n\n    public String getShutwait() {\n        return shutwait;\n    }\n\n    public void setShutwait(String shutwait) {\n        System.setProperty(SHUTDOWN_WAIT_KEY, shutwait);\n        this.shutwait = shutwait;\n    }\n\n    @Parameter(excluded = true)\n    public String getHostname() {\n        return hostname;\n    }\n\n    @Override\n    @Parameter(excluded = true, attribute = false)\n    public boolean isValid() {\n        return !StringUtils.isEmpty(name);\n    }\n\n    @Parameter(key = METADATA_KEY)\n    public String getMetadataType() {\n        return metadataType;\n    }\n\n    public void setMetadataType(String metadataType) {\n        this.metadataType = metadataType;\n    }\n\n    public Boolean getRegisterConsumer() {\n        return registerConsumer;\n    }\n\n    public void setRegisterConsumer(Boolean registerConsumer) {\n        this.registerConsumer = registerConsumer;\n    }\n\n    public String getRepository() {\n        return repository;\n    }\n\n    public void setRepository(String repository) {\n        this.repository = repository;\n    }\n\n    @Parameter(key = REGISTRY_LOCAL_FILE_CACHE_ENABLED)\n    public Boolean getEnableFileCache() {\n        return enableFileCache;\n    }\n\n    public void setEnableFileCache(Boolean enableFileCache) {\n        this.enableFileCache = enableFileCache;\n    }\n\n    @Parameter(key = REGISTER_MODE_KEY)\n    public String getRegisterMode() {\n        return registerMode;\n    }\n\n    public void setRegisterMode(String registerMode) {\n        this.registerMode = registerMode;\n    }\n\n    @Parameter(key = ENABLE_EMPTY_PROTECTION_KEY)\n    public Boolean getEnableEmptyProtection() {\n        return enableEmptyProtection;\n    }\n\n    public void setEnableEmptyProtection(Boolean enableEmptyProtection) {\n        this.enableEmptyProtection = enableEmptyProtection;\n    }\n\n    @Parameter(excluded = true, key = APPLICATION_PROTOCOL_KEY)\n    public String getProtocol() {\n        return protocol;\n    }\n\n    public void setProtocol(String protocol) {\n        this.protocol = protocol;\n    }\n\n    @Parameter(key = METADATA_SERVICE_PORT_KEY)\n    public Integer getMetadataServicePort() {\n        return metadataServicePort;\n    }\n\n    public void setMetadataServicePort(Integer metadataServicePort) {\n        this.metadataServicePort = metadataServicePort;\n    }\n\n    public Integer getMappingRetryInterval() {\n        return mappingRetryInterval;\n    }\n\n    public void setMappingRetryInterval(Integer mappingRetryInterval) {\n        this.mappingRetryInterval = mappingRetryInterval;\n    }\n\n    @Parameter(key = METADATA_SERVICE_PROTOCOL_KEY)\n    public String getMetadataServiceProtocol() {\n        return metadataServiceProtocol;\n    }\n\n    public void setMetadataServiceProtocol(String metadataServiceProtocol) {\n        this.metadataServiceProtocol = metadataServiceProtocol;\n    }\n\n    @Parameter(key = LIVENESS_PROBE_KEY)\n    public String getLivenessProbe() {\n        return livenessProbe;\n    }\n\n    public void setLivenessProbe(String livenessProbe) {\n        this.livenessProbe = livenessProbe;\n    }\n\n    @Parameter(key = READINESS_PROBE_KEY)\n    public String getReadinessProbe() {\n        return readinessProbe;\n    }\n\n    public void setReadinessProbe(String readinessProbe) {\n        this.readinessProbe = readinessProbe;\n    }\n\n    @Parameter(key = STARTUP_PROBE)\n    public String getStartupProbe() {\n        return startupProbe;\n    }\n\n    public void setStartupProbe(String startupProbe) {\n        this.startupProbe = startupProbe;\n    }\n\n    public String getSerializeCheckStatus() {\n        return serializeCheckStatus;\n    }\n\n    public void setSerializeCheckStatus(String serializeCheckStatus) {\n        this.serializeCheckStatus = serializeCheckStatus;\n    }\n\n    public Boolean getAutoTrustSerializeClass() {\n        return autoTrustSerializeClass;\n    }\n\n    public void setAutoTrustSerializeClass(Boolean autoTrustSerializeClass) {\n        this.autoTrustSerializeClass = autoTrustSerializeClass;\n    }\n\n    public Integer getTrustSerializeClassLevel() {\n        return trustSerializeClassLevel;\n    }\n\n    public void setTrustSerializeClassLevel(Integer trustSerializeClassLevel) {\n        this.trustSerializeClassLevel = trustSerializeClassLevel;\n    }\n\n    public Boolean getCheckSerializable() {\n        return checkSerializable;\n    }\n\n    public void setCheckSerializable(Boolean checkSerializable) {\n        this.checkSerializable = checkSerializable;\n    }\n\n    public void setExecutorManagementMode(String executorManagementMode) {\n        this.executorManagementMode = executorManagementMode;\n    }\n\n    @Parameter(key = EXECUTOR_MANAGEMENT_MODE)\n    public String getExecutorManagementMode() {\n        return executorManagementMode;\n    }\n\n    @Parameter(excluded = true)\n    public Boolean getOnlyUseMetadataV2() {\n        return onlyUseMetadataV2;\n    }\n\n    public void setOnlyUseMetadataV2(Boolean onlyUseMetadataV2) {\n        this.onlyUseMetadataV2 = onlyUseMetadataV2;\n    }\n\n    @Override\n    public void refresh() {\n        super.refresh();\n        appendEnvironmentProperties();\n        if (StringUtils.isEmpty(getName())) {\n            this.setName(DEFAULT_APP_NAME);\n            LOGGER.warn(\n                    COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"No application name was set, '\" + DEFAULT_APP_NAME\n                            + \"' will be used as the default application name,\"\n                            + \" it's highly recommended to set a unique and customized name for it can be critical for some service governance features.\");\n        }\n    }\n\n    private void appendEnvironmentProperties() {\n        if (parameters == null) {\n            parameters = new HashMap<>();\n        }\n\n        Set<InfraAdapter> adapters = this.getExtensionLoader(InfraAdapter.class).getSupportedExtensionInstances();\n        if (CollectionUtils.isNotEmpty(adapters)) {\n            Map<String, String> inputParameters = new HashMap<>();\n            inputParameters.put(APPLICATION_KEY, getName());\n            inputParameters.put(HOST_KEY, getHostname());\n            for (InfraAdapter adapter : adapters) {\n                Map<String, String> extraParameters = adapter.getExtraAttributes(inputParameters);\n                if (CollectionUtils.isNotEmptyMap(extraParameters)) {\n                    extraParameters.forEach((key, value) -> {\n                        for (String prefix : this.getPrefixes()) {\n                            prefix += \".\";\n                            if (key.startsWith(prefix)) {\n                                key = key.substring(prefix.length());\n                            }\n                            parameters.put(key, value);\n                            break;\n                        }\n                    });\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/ArgumentConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.config.annotation.Argument;\nimport org.apache.dubbo.config.support.Parameter;\n\nimport java.io.Serializable;\n\n/**\n * The method arguments configuration\n *\n * @export\n */\npublic class ArgumentConfig implements Serializable {\n\n    private static final long serialVersionUID = -2165482463925213595L;\n\n    /**\n     * The argument index: index -1 represents not set\n     */\n    private Integer index = -1;\n\n    /**\n     * Argument type\n     */\n    private String type;\n\n    /**\n     * Whether the argument is the callback interface\n     */\n    private Boolean callback;\n\n    public ArgumentConfig() {}\n\n    public ArgumentConfig(Argument argument) {\n        this.index = argument.index();\n        this.type = argument.type();\n        this.callback = argument.callback();\n    }\n\n    @Parameter(excluded = true)\n    public Integer getIndex() {\n        return index;\n    }\n\n    public void setIndex(Integer index) {\n        this.index = index;\n    }\n\n    @Parameter(excluded = true)\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public void setCallback(Boolean callback) {\n        this.callback = callback;\n    }\n\n    public Boolean isCallback() {\n        return callback;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/ConfigCenterConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONFIG_CONFIGFILE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONFIG_ENABLE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;\nimport static org.apache.dubbo.common.utils.PojoUtils.updatePropertyIfAbsent;\nimport static org.apache.dubbo.config.Constants.CONFIG_APP_CONFIGFILE_KEY;\nimport static org.apache.dubbo.config.Constants.ZOOKEEPER_PROTOCOL;\n\n/**\n * Configuration for the config center.\n */\npublic class ConfigCenterConfig extends AbstractConfig {\n\n    private final AtomicBoolean initialized = new AtomicBoolean(false);\n\n    /**\n     * The protocol used for accessing the config center.\n     */\n    private String protocol;\n\n    /**\n     * The address (URL or hostname) of the config center server.\n     */\n    private String address;\n\n    /**\n     * The port number for the config center server.\n     */\n    private Integer port;\n\n    /**\n     * The config center cluster, its actual meaning may vary depending on the specific config center product.\n     */\n    private String cluster;\n\n    /**\n     * The namespace of the config center, generally used for multi-tenancy.\n     * Its actual meaning depends on the specific config center you use. Default value is CommonConstants.DUBBO.\n     */\n    private String namespace;\n\n    /**\n     * The group of the config center, often used to identify an isolated space for a batch of config items.\n     * Its actual meaning depends on the specific config center you use. Default value is CommonConstants.DUBBO.\n     */\n    private String group;\n\n    /**\n     * Username for authentication with the config center.\n     */\n    private String username;\n\n    /**\n     * Password for authentication with the config center.\n     */\n    private String password;\n\n    /**\n     * The timeout for accessing the config center. Default value is 30000L.\n     */\n    private Long timeout;\n\n    /**\n     * If the config center should have the highest priority and override all other configurations.\n     * Deprecated and no longer used. Default value is true.\n     */\n    private Boolean highestPriority;\n\n    /**\n     * Behavior when the initial connection attempt to the config center fails.\n     * 'true' means interrupt the whole process once a failure occurs. Default value is true.\n     */\n    private Boolean check;\n\n    /**\n     * Key mapping for properties files. Most of the time, you do not need to change this parameter.\n     * Default value is CommonConstants.DEFAULT_DUBBO_PROPERTIES.\n     */\n    private String configFile;\n\n    /**\n     * The properties file under 'configFile' is global shared, while '.properties' under this one is limited only to this application.\n     */\n    private String appConfigFile;\n\n    /**\n     * Additional parameters specific to your config center product can be added here.\n     * For example, with XML:\n     * <dubbo:config-center>\n     * <dubbo:parameter key=\"{your key}\" value=\"{your value}\" />\n     * </dubbo:config-center>\n     */\n    private Map<String, String> parameters;\n\n    /**\n     * External configuration for the config center.\n     */\n    private Map<String, String> externalConfiguration;\n\n    /**\n     * Application-specific external configuration for the config center.\n     */\n    private Map<String, String> appExternalConfiguration;\n\n    public ConfigCenterConfig() {}\n\n    public ConfigCenterConfig(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    @Override\n    protected void checkDefault() {\n        super.checkDefault();\n\n        if (namespace == null) {\n            namespace = CommonConstants.DUBBO;\n        }\n        if (group == null) {\n            group = CommonConstants.DUBBO;\n        }\n        if (timeout == null) {\n            timeout = 30000L;\n        }\n        if (check == null) {\n            check = true;\n        }\n        if (configFile == null) {\n            configFile = CommonConstants.DEFAULT_DUBBO_PROPERTIES;\n        }\n    }\n\n    public URL toUrl() {\n        Map<String, String> map = new HashMap<>();\n        appendParameters(map, this);\n        if (StringUtils.isEmpty(address)) {\n            address = ANYHOST_VALUE;\n        }\n        map.put(PATH_KEY, ConfigCenterConfig.class.getName());\n        // use 'zookeeper' as the default config center.\n        if (StringUtils.isEmpty(map.get(PROTOCOL_KEY))) {\n            map.put(PROTOCOL_KEY, ZOOKEEPER_PROTOCOL);\n        }\n        return UrlUtils.parseURL(address, map).setScopeModel(getScopeModel());\n    }\n\n    public boolean checkOrUpdateInitialized(boolean update) {\n        return initialized.compareAndSet(false, update);\n    }\n\n    public void setInitialized(boolean val) {\n        initialized.set(val);\n    }\n\n    public Map<String, String> getExternalConfiguration() {\n        return externalConfiguration;\n    }\n\n    public Map<String, String> getAppExternalConfiguration() {\n        return appExternalConfiguration;\n    }\n\n    public void setExternalConfig(Map<String, String> externalConfiguration) {\n        this.externalConfiguration = externalConfiguration;\n    }\n\n    public void setAppExternalConfig(Map<String, String> appExternalConfiguration) {\n        this.appExternalConfiguration = appExternalConfiguration;\n    }\n\n    public String getProtocol() {\n        return protocol;\n    }\n\n    public void setProtocol(String protocol) {\n        this.protocol = protocol;\n    }\n\n    @Parameter(excluded = true)\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n        if (address != null) {\n            try {\n                URL url = URL.valueOf(address);\n                updatePropertyIfAbsent(this::getUsername, this::setUsername, url.getUsername());\n                updatePropertyIfAbsent(this::getPassword, this::setPassword, url.getPassword());\n                updatePropertyIfAbsent(this::getProtocol, this::setProtocol, url.getProtocol());\n                updatePropertyIfAbsent(this::getPort, this::setPort, url.getPort());\n\n                Map<String, String> params = url.getParameters();\n                if (CollectionUtils.isNotEmptyMap(params)) {\n                    params.remove(BACKUP_KEY);\n                }\n                updateParameters(params);\n            } catch (Exception ignored) {\n            }\n        }\n    }\n\n    public Integer getPort() {\n        return port;\n    }\n\n    public void setPort(Integer port) {\n        this.port = port;\n    }\n\n    public String getCluster() {\n        return cluster;\n    }\n\n    public void setCluster(String cluster) {\n        this.cluster = cluster;\n    }\n\n    public String getNamespace() {\n        return namespace;\n    }\n\n    public void setNamespace(String namespace) {\n        this.namespace = namespace;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public Boolean isCheck() {\n        return check;\n    }\n\n    public void setCheck(Boolean check) {\n        this.check = check;\n    }\n\n    @Deprecated\n    @Parameter(key = CONFIG_ENABLE_KEY)\n    public Boolean isHighestPriority() {\n        return highestPriority;\n    }\n\n    @Deprecated\n    public void setHighestPriority(Boolean highestPriority) {\n        this.highestPriority = highestPriority;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public Long getTimeout() {\n        return timeout;\n    }\n\n    public void setTimeout(Long timeout) {\n        this.timeout = timeout;\n    }\n\n    @Parameter(key = CONFIG_CONFIGFILE_KEY)\n    public String getConfigFile() {\n        return configFile;\n    }\n\n    public void setConfigFile(String configFile) {\n        this.configFile = configFile;\n    }\n\n    @Parameter(excluded = true, key = CONFIG_APP_CONFIGFILE_KEY)\n    public String getAppConfigFile() {\n        return appConfigFile;\n    }\n\n    public void setAppConfigFile(String appConfigFile) {\n        this.appConfigFile = appConfigFile;\n    }\n\n    public Map<String, String> getParameters() {\n        return parameters;\n    }\n\n    public void setParameters(Map<String, String> parameters) {\n        this.parameters = parameters;\n    }\n\n    @Override\n    @Parameter(excluded = true, attribute = false)\n    public boolean isValid() {\n        if (StringUtils.isEmpty(address)) {\n            return false;\n        }\n\n        return address.contains(\"://\") || StringUtils.isNotEmpty(protocol);\n    }\n\n    public void updateParameters(Map<String, String> parameters) {\n        if (CollectionUtils.isEmptyMap(parameters)) {\n            return;\n        }\n        if (this.parameters == null) {\n            this.parameters = parameters;\n        } else {\n            this.parameters.putAll(parameters);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/ConfigKeys.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.context.ConfigMode;\n\n/**\n * External config keys list\n * @see org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties\n */\npublic interface ConfigKeys {\n\n    /**\n     * The basePackages to scan , the multiple-value is delimited by comma\n     * @see org.apache.dubbo.config.spring.context.annotation.EnableDubbo#scanBasePackages()\n     */\n    String DUBBO_SCAN_BASE_PACKAGES = \"dubbo.scan.base-packages\";\n\n    /**\n     * Change dubbo config mode, available values from {@link ConfigMode}. Default value is {@link ConfigMode#STRICT}.\n     * @see ConfigMode\n     * @see ConfigManager#configMode\n     */\n    String DUBBO_CONFIG_MODE = \"dubbo.config.mode\";\n\n    /**\n     * Ignore invalid method config. Default value is false.\n     */\n    String DUBBO_CONFIG_IGNORE_INVALID_METHOD_CONFIG = \"dubbo.config.ignore-invalid-method-config\";\n\n    /**\n     * Ignore duplicated interface (service/reference) config. Default value is false.\n     */\n    String DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE = \"dubbo.config.ignore-duplicated-interface\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_WHITELIST_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_HOST_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_PORT_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;\n\npublic interface Constants {\n\n    String STATUS_KEY = \"status\";\n\n    String CONTEXTPATH_KEY = \"contextpath\";\n\n    String LISTENER_KEY = \"listener\";\n\n    String LAYER_KEY = \"layer\";\n\n    // General\n\n    /**\n     * Config id\n     */\n    String ID = \"id\";\n\n    /**\n     * Application name;\n     */\n    String NAME = \"name\";\n\n    /**\n     * Application owner name;\n     */\n    String OWNER = \"owner\";\n\n    /**\n     * Running application organization name.\n     */\n    String ORGANIZATION = \"organization\";\n\n    /**\n     * Application architecture name.\n     */\n    String ARCHITECTURE = \"architecture\";\n\n    /**\n     * Environment name\n     */\n    String ENVIRONMENT = \"environment\";\n\n    /**\n     * Test environment key.\n     */\n    String TEST_ENVIRONMENT = \"test\";\n\n    /**\n     * Development environment key.\n     */\n    String DEVELOPMENT_ENVIRONMENT = \"develop\";\n\n    /**\n     * Production environment key.\n     */\n    String PRODUCTION_ENVIRONMENT = \"product\";\n\n    String CONFIG_CONFIGFILE_KEY = \"config-file\";\n    String CONFIG_ENABLE_KEY = \"highest-priority\";\n    String CONFIG_APP_CONFIGFILE_KEY = \"app-config-file\";\n\n    String MULTICAST = \"multicast\";\n\n    String DUBBO_PORT_TO_REGISTRY = \"DUBBO_PORT_TO_REGISTRY\";\n\n    String DUBBO_PORT_TO_BIND = \"DUBBO_PORT_TO_BIND\";\n\n    String SCOPE_NONE = \"none\";\n\n    String ON_INVOKE_METHOD_PARAMETER_KEY = \"oninvoke.method\";\n\n    String ON_RETURN_METHOD_PARAMETER_KEY = \"onreturn.method\";\n\n    String ON_THROW_METHOD_PARAMETER_KEY = \"onthrow.method\";\n\n    String ON_INVOKE_INSTANCE_PARAMETER_KEY = \"oninvoke.instance\";\n\n    String ON_RETURN_INSTANCE_PARAMETER_KEY = \"onreturn.instance\";\n\n    String ON_THROW_INSTANCE_PARAMETER_KEY = \"onthrow.instance\";\n\n    String ON_INVOKE_METHOD_ATTRIBUTE_KEY = \"oninvoke-method\";\n\n    String ON_RETURN_METHOD_ATTRIBUTE_KEY = \"onreturn-method\";\n\n    String ON_THROW_METHOD_ATTRIBUTE_KEY = \"onthrow-method\";\n\n    String ON_INVOKE_INSTANCE_ATTRIBUTE_KEY = \"oninvoke-instance\";\n\n    String ON_RETURN_INSTANCE_ATTRIBUTE_KEY = \"onreturn-instance\";\n\n    String ON_THROW_INSTANCE_ATTRIBUTE_KEY = \"onthrow-instance\";\n\n    // FIXME: is this still useful?\n    String SHUTDOWN_TIMEOUT_KEY = \"shutdown.timeout\";\n\n    String PROTOCOLS_SUFFIX = \"dubbo.protocols.\";\n\n    String REGISTRIES_SUFFIX = \"dubbo.registries.\";\n\n    String ZOOKEEPER_PROTOCOL = \"zookeeper\";\n\n    String REGISTER_KEY = \"register\";\n\n    String MULTI_SERIALIZATION_KEY = \"serialize.multiple\";\n\n    String[] DOT_COMPATIBLE_KEYS = new String[] {\n        QOS_ENABLE_COMPATIBLE,\n        QOS_HOST_COMPATIBLE,\n        QOS_PORT_COMPATIBLE,\n        ACCEPT_FOREIGN_IP_COMPATIBLE,\n        ACCEPT_FOREIGN_IP_WHITELIST_COMPATIBLE,\n        REGISTRY_TYPE_KEY\n    };\n\n    String IGNORE_CHECK_KEYS = \"ignoreCheckKeys\";\n\n    String PARAMETERS = \"parameters\";\n\n    String SERVER_THREAD_POOL_NAME = \"DubboServerHandler\";\n\n    String SERVER_THREAD_POOL_PREFIX = SERVER_THREAD_POOL_NAME + \"-\";\n\n    String CLIENT_THREAD_POOL_NAME = \"DubboClientHandler\";\n\n    String CLIENT_THREAD_POOL_PREFIX = CLIENT_THREAD_POOL_NAME + \"-\";\n\n    String REST_PROTOCOL = \"rest\";\n\n    String DEFAULT_NATIVE_COMPILER = \"jdk\";\n\n    String DEFAULT_NATIVE_PROXY = \"jdk\";\n\n    String DEFAULT_APP_NAME = \"DEFAULT_DUBBO_APP\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/ConsumerConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.MESH_ENABLE;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFER_BACKGROUND_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFER_THREAD_NUM_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_TCP_RESPONSE_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.URL_MERGE_PROCESSOR_KEY;\n\n/**\n * The service consumer default configuration\n *\n * @export\n */\npublic class ConsumerConfig extends AbstractReferenceConfig {\n\n    private static final long serialVersionUID = 2827274711143680600L;\n\n    /**\n     * Consumer thread pool type: cached, fixed, limit, eager\n     */\n    private String threadpool;\n\n    /**\n     * Consumer threadpool core thread size\n     */\n    private Integer corethreads;\n\n    /**\n     * Consumer threadpool thread size\n     */\n    private Integer threads;\n\n    /**\n     * Consumer threadpool queue size\n     */\n    private Integer queues;\n\n    /**\n     * By default, a TCP long-connection communication is shared between the consumer process and the provider process.\n     * This property can be set to share multiple TCP long-connection communications. Note that only the dubbo protocol takes effect.\n     */\n    private Integer shareconnections;\n\n    /**\n     * Url Merge Processor\n     * Used to customize the URL merge of consumer and provider\n     */\n    private String urlMergeProcessor;\n\n    /**\n     * Thread num for asynchronous refer pool size\n     */\n    private Integer referThreadNum;\n\n    /**\n     * Whether refer should run in background or not.\n     *\n     * @see ModuleConfig#setBackground(Boolean)\n     * @deprecated replace with {@link ModuleConfig#setBackground(Boolean)}\n     */\n    private Boolean referBackground;\n\n    /**\n     * enable mesh mode\n     *\n     * @since 3.1.0\n     */\n    private Boolean meshEnable;\n\n    public ConsumerConfig() {}\n\n    public ConsumerConfig(ModuleModel moduleModel) {\n        super(moduleModel);\n    }\n\n    @Override\n    public void setTimeout(Integer timeout) {\n        super.setTimeout(timeout);\n        String rmiTimeout = SystemPropertyConfigUtils.getSystemProperty(SYSTEM_TCP_RESPONSE_TIMEOUT);\n        if (timeout != null && timeout > 0 && (StringUtils.isEmpty(rmiTimeout))) {\n            SystemPropertyConfigUtils.setSystemProperty(SYSTEM_TCP_RESPONSE_TIMEOUT, String.valueOf(timeout));\n        }\n    }\n\n    public String getThreadpool() {\n        return threadpool;\n    }\n\n    public void setThreadpool(String threadpool) {\n        this.threadpool = threadpool;\n    }\n\n    public Integer getCorethreads() {\n        return corethreads;\n    }\n\n    public void setCorethreads(Integer corethreads) {\n        this.corethreads = corethreads;\n    }\n\n    public Integer getThreads() {\n        return threads;\n    }\n\n    public void setThreads(Integer threads) {\n        this.threads = threads;\n    }\n\n    public Integer getQueues() {\n        return queues;\n    }\n\n    public void setQueues(Integer queues) {\n        this.queues = queues;\n    }\n\n    public Integer getShareconnections() {\n        return shareconnections;\n    }\n\n    public void setShareconnections(Integer shareconnections) {\n        this.shareconnections = shareconnections;\n    }\n\n    @Parameter(key = URL_MERGE_PROCESSOR_KEY)\n    public String getUrlMergeProcessor() {\n        return urlMergeProcessor;\n    }\n\n    public void setUrlMergeProcessor(String urlMergeProcessor) {\n        this.urlMergeProcessor = urlMergeProcessor;\n    }\n\n    @Parameter(key = REFER_THREAD_NUM_KEY, excluded = true)\n    public Integer getReferThreadNum() {\n        return referThreadNum;\n    }\n\n    public void setReferThreadNum(Integer referThreadNum) {\n        this.referThreadNum = referThreadNum;\n    }\n\n    @Deprecated\n    @Parameter(key = REFER_BACKGROUND_KEY, excluded = true)\n    public Boolean getReferBackground() {\n        return referBackground;\n    }\n\n    /**\n     * Whether refer should run in background or not.\n     *\n     * @see ModuleConfig#setBackground(Boolean)\n     * @deprecated replace with {@link ModuleConfig#setBackground(Boolean)}\n     */\n    @Deprecated\n    public void setReferBackground(Boolean referBackground) {\n        this.referBackground = referBackground;\n    }\n\n    @Parameter(key = MESH_ENABLE)\n    public Boolean getMeshEnable() {\n        return meshEnable;\n    }\n\n    public void setMeshEnable(Boolean meshEnable) {\n        this.meshEnable = meshEnable;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/MetadataReportConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CYCLE_REPORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REPORT_DEFINITION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REPORT_METADATA_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RETRY_PERIOD_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RETRY_TIMES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SYNC_REPORT_KEY;\nimport static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;\nimport static org.apache.dubbo.common.utils.PojoUtils.updatePropertyIfAbsent;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\n\n/**\n * Configuration for the metadata report.\n *\n * @export\n */\npublic class MetadataReportConfig extends AbstractConfig {\n\n    private static final long serialVersionUID = 55233L;\n\n    /**\n     * The protocol for the metadata center.\n     */\n    private String protocol;\n\n    /**\n     * The address of the metadata center.\n     */\n    private String address;\n\n    /**\n     * The default port for the metadata center.\n     */\n    private Integer port;\n\n    /**\n     * The username used to log in to the metadata center.\n     */\n    private String username;\n\n    /**\n     * The password used to log in to the metadata center.\n     */\n    private String password;\n\n    /**\n     * The request timeout in milliseconds for the metadata center.\n     */\n    private Integer timeout;\n\n    /**\n     * The group for the metadata center, which is similar to the registry group.\n     */\n    private String group;\n\n    /**\n     * Customized parameters for the metadata center.\n     */\n    private Map<String, String> parameters;\n\n    /**\n     * The number of retry times when connecting to the metadata center.\n     */\n    private Integer retryTimes;\n\n    /**\n     * The retry period in milliseconds when connecting to the metadata center.\n     */\n    private Integer retryPeriod;\n\n    /**\n     * By default, the metadata store will store full metadata repeatedly every day.\n     */\n    private Boolean cycleReport;\n\n    /**\n     * Synchronization report, with the default value as asynchronous.\n     */\n    private Boolean syncReport;\n\n    /**\n     * Whether to use a cluster configuration for the metadata center.\n     */\n    private Boolean cluster;\n\n    /**\n     * The registry ID for the metadata center.\n     */\n    private String registry;\n\n    /**\n     * The file path for saving the metadata center's dynamic list.\n     */\n    private String file;\n\n    /**\n     * Decide the behavior when the initial connection attempt fails, where 'true' means interrupt the whole process once it fails.\n     * The default value is true.\n     */\n    private Boolean check;\n\n    /**\n     * Whether to report metadata.\n     */\n    private Boolean reportMetadata;\n\n    /**\n     * Whether to report definition.\n     */\n    private Boolean reportDefinition;\n\n    public MetadataReportConfig() {}\n\n    public MetadataReportConfig(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    public MetadataReportConfig(String address) {\n        setAddress(address);\n    }\n\n    public MetadataReportConfig(ApplicationModel applicationModel, String address) {\n        super(applicationModel);\n        setAddress(address);\n    }\n\n    public URL toUrl() throws IllegalArgumentException {\n        String address = this.getAddress();\n        if (isEmpty(address)) {\n            throw new IllegalArgumentException(\"The address of metadata report is invalid.\");\n        }\n        Map<String, String> map = new HashMap<>();\n        URL url = URL.valueOf(address, getScopeModel());\n        // Issue : https://github.com/apache/dubbo/issues/6491\n        // Append the parameters from address\n        map.putAll(url.getParameters());\n        // Append or overrides the properties as parameters\n        appendParameters(map, this);\n        // Normalize the parameters\n        map.putAll(convert(map, null));\n        // put the protocol of URL as the \"metadata\"\n        map.put(METADATA, isEmpty(url.getProtocol()) ? map.get(PROTOCOL_KEY) : url.getProtocol());\n        return new ServiceConfigURL(\n                        METADATA,\n                        StringUtils.isBlank(url.getUsername()) ? this.getUsername() : url.getUsername(),\n                        StringUtils.isBlank(url.getPassword()) ? this.getPassword() : url.getPassword(),\n                        url.getHost(),\n                        url.getPort(),\n                        url.getPath(),\n                        map)\n                .setScopeModel(getScopeModel());\n    }\n\n    public String getProtocol() {\n        return protocol;\n    }\n\n    public void setProtocol(String protocol) {\n        this.protocol = protocol;\n    }\n\n    @Parameter(excluded = true)\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n        if (address != null) {\n            try {\n                URL url = URL.valueOf(address);\n\n                // Refactor since 2.7.8\n                updatePropertyIfAbsent(this::getUsername, this::setUsername, url.getUsername());\n                updatePropertyIfAbsent(this::getPassword, this::setPassword, url.getPassword());\n                updatePropertyIfAbsent(this::getProtocol, this::setProtocol, url.getProtocol());\n                updatePropertyIfAbsent(this::getPort, this::setPort, url.getPort());\n\n                Map<String, String> params = url.getParameters();\n                if (CollectionUtils.isNotEmptyMap(params)) {\n                    params.remove(BACKUP_KEY);\n                }\n                updateParameters(params);\n            } catch (Exception ignored) {\n            }\n        }\n    }\n\n    public Integer getPort() {\n        return port;\n    }\n\n    public void setPort(Integer port) {\n        this.port = port;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public Integer getTimeout() {\n        return timeout;\n    }\n\n    public void setTimeout(Integer timeout) {\n        this.timeout = timeout;\n    }\n\n    public Map<String, String> getParameters() {\n        return parameters;\n    }\n\n    public void setParameters(Map<String, String> parameters) {\n        this.parameters = parameters;\n    }\n\n    @Parameter(key = RETRY_TIMES_KEY)\n    public Integer getRetryTimes() {\n        return retryTimes;\n    }\n\n    public void setRetryTimes(Integer retryTimes) {\n        this.retryTimes = retryTimes;\n    }\n\n    @Parameter(key = RETRY_PERIOD_KEY)\n    public Integer getRetryPeriod() {\n        return retryPeriod;\n    }\n\n    public void setRetryPeriod(Integer retryPeriod) {\n        this.retryPeriod = retryPeriod;\n    }\n\n    @Parameter(key = CYCLE_REPORT_KEY)\n    public Boolean getCycleReport() {\n        return cycleReport;\n    }\n\n    public void setCycleReport(Boolean cycleReport) {\n        this.cycleReport = cycleReport;\n    }\n\n    @Parameter(key = SYNC_REPORT_KEY)\n    public Boolean getSyncReport() {\n        return syncReport;\n    }\n\n    public void setSyncReport(Boolean syncReport) {\n        this.syncReport = syncReport;\n    }\n\n    @Override\n    @Parameter(excluded = true, attribute = false)\n    public boolean isValid() {\n        return StringUtils.isNotEmpty(address);\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public Boolean getCluster() {\n        return cluster;\n    }\n\n    public void setCluster(Boolean cluster) {\n        this.cluster = cluster;\n    }\n\n    public String getRegistry() {\n        return registry;\n    }\n\n    public void setRegistry(String registry) {\n        this.registry = registry;\n    }\n\n    public String getFile() {\n        return file;\n    }\n\n    public void setFile(String file) {\n        this.file = file;\n    }\n\n    public void updateParameters(Map<String, String> parameters) {\n        if (CollectionUtils.isEmptyMap(parameters)) {\n            return;\n        }\n        if (this.parameters == null) {\n            this.parameters = parameters;\n        } else {\n            this.parameters.putAll(parameters);\n        }\n    }\n\n    public Boolean isCheck() {\n        return check;\n    }\n\n    public void setCheck(Boolean check) {\n        this.check = check;\n    }\n\n    @Parameter(key = REPORT_METADATA_KEY)\n    public Boolean getReportMetadata() {\n        return reportMetadata;\n    }\n\n    public void setReportMetadata(Boolean reportMetadata) {\n        this.reportMetadata = reportMetadata;\n    }\n\n    @Parameter(key = REPORT_DEFINITION_KEY)\n    public Boolean getReportDefinition() {\n        return reportDefinition;\n    }\n\n    public void setReportDefinition(Boolean reportDefinition) {\n        this.reportDefinition = reportDefinition;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/MethodConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.config.InmemoryConfiguration;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.MethodUtils;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.AsyncMethodInfo;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport static org.apache.dubbo.config.Constants.ON_INVOKE_INSTANCE_PARAMETER_KEY;\nimport static org.apache.dubbo.config.Constants.ON_INVOKE_METHOD_PARAMETER_KEY;\nimport static org.apache.dubbo.config.Constants.ON_RETURN_INSTANCE_PARAMETER_KEY;\nimport static org.apache.dubbo.config.Constants.ON_RETURN_METHOD_PARAMETER_KEY;\nimport static org.apache.dubbo.config.Constants.ON_THROW_INSTANCE_PARAMETER_KEY;\nimport static org.apache.dubbo.config.Constants.ON_THROW_METHOD_PARAMETER_KEY;\n\n/**\n * The method configuration\n *\n * @export\n */\npublic class MethodConfig extends AbstractMethodConfig {\n\n    private static final long serialVersionUID = 884908855422675941L;\n\n    /**\n     * The method name\n     */\n    private String name;\n\n    /**\n     * Stat\n     */\n    private Integer stat;\n\n    /**\n     * Whether to retry\n     */\n    private Boolean retry;\n\n    /**\n     * If it's reliable\n     */\n    private Boolean reliable;\n\n    /**\n     * Thread limits for method invocations\n     */\n    private Integer executes;\n\n    /**\n     * If it's deprecated\n     */\n    private Boolean deprecated;\n\n    /**\n     * Whether to enable sticky\n     */\n    private Boolean sticky;\n\n    /**\n     * Whether you need to return\n     */\n    private Boolean isReturn;\n\n    /**\n     * Callback instance when async-call is invoked\n     */\n    private Object oninvoke;\n\n    /**\n     * Callback method when async-call is invoked\n     */\n    private String oninvokeMethod;\n\n    /**\n     * Callback instance when async-call is returned\n     */\n    private Object onreturn;\n\n    /**\n     * Callback method when async-call is returned\n     */\n    private String onreturnMethod;\n\n    /**\n     * Callback instance when async-call has exception thrown\n     */\n    private Object onthrow;\n\n    /**\n     * Callback method when async-call has exception thrown\n     */\n    private String onthrowMethod;\n\n    /**\n     * The method arguments\n     */\n    private List<ArgumentConfig> arguments;\n\n    /**\n     * TODO remove service and serviceId\n     * These properties come from MethodConfig's parent Config module, they will neither be collected directly from xml or API nor be delivered to url\n     */\n    private String service;\n\n    private String serviceId;\n\n    /**\n     * The preferred prefix of parent\n     */\n    private String parentPrefix;\n\n    public MethodConfig() {}\n\n    public MethodConfig(ModuleModel moduleModel) {\n        super(moduleModel);\n    }\n\n    /**\n     * TODO remove this construct, the callback method processing logic needs to rely on Spring context\n     */\n    @Deprecated\n    public MethodConfig(Method method) {\n        appendAnnotation(Method.class, method);\n\n        this.setReturn(method.isReturn());\n\n        String split = \".\";\n\n        if (!\"\".equals(method.oninvoke()) && method.oninvoke().lastIndexOf(split) > 0) {\n            int index = method.oninvoke().lastIndexOf(split);\n            String ref = method.oninvoke().substring(0, index);\n            String methodName = method.oninvoke().substring(index + 1);\n            this.setOninvoke(ref);\n            this.setOninvokeMethod(methodName);\n        }\n        if (!\"\".equals(method.onreturn()) && method.onreturn().lastIndexOf(split) > 0) {\n            int index = method.onreturn().lastIndexOf(split);\n            String ref = method.onreturn().substring(0, index);\n            String methodName = method.onreturn().substring(index + 1);\n            this.setOnreturn(ref);\n            this.setOnreturnMethod(methodName);\n        }\n        if (!\"\".equals(method.onthrow()) && method.onthrow().lastIndexOf(split) > 0) {\n            int index = method.onthrow().lastIndexOf(split);\n            String ref = method.onthrow().substring(0, index);\n            String methodName = method.onthrow().substring(index + 1);\n            this.setOnthrow(ref);\n            this.setOnthrowMethod(methodName);\n        }\n\n        if (method.arguments() != null && method.arguments().length != 0) {\n            List<ArgumentConfig> argumentConfigs = new ArrayList<>(method.arguments().length);\n            this.setArguments(argumentConfigs);\n            for (int i = 0; i < method.arguments().length; i++) {\n                ArgumentConfig argumentConfig = new ArgumentConfig(method.arguments()[i]);\n                argumentConfigs.add(argumentConfig);\n            }\n        }\n    }\n\n    /**\n     * TODO remove constructMethodConfig\n     *\n     * @param methods\n     * @return\n     */\n    @Deprecated\n    public static List<MethodConfig> constructMethodConfig(Method[] methods) {\n        if (methods != null && methods.length != 0) {\n            List<MethodConfig> methodConfigs = new ArrayList<>(methods.length);\n            for (int i = 0; i < methods.length; i++) {\n                MethodConfig methodConfig = new MethodConfig(methods[i]);\n                methodConfigs.add(methodConfig);\n            }\n            return methodConfigs;\n        }\n        return Collections.emptyList();\n    }\n\n    /**\n     * Get method prefixes\n     *\n     * @return\n     */\n    @Override\n    @Parameter(excluded = true, attribute = false)\n    public List<String> getPrefixes() {\n        // parent prefix + method name\n        if (parentPrefix != null) {\n            List<String> prefixes = new ArrayList<>();\n            prefixes.add(parentPrefix + \".\" + this.getName());\n            return prefixes;\n        }\n        return null;\n    }\n\n    @Override\n    protected void processExtraRefresh(String preferredPrefix, InmemoryConfiguration subPropsConfiguration) {\n        // refresh ArgumentConfigs\n        if (this.getArguments() != null && this.getArguments().size() > 0) {\n            for (ArgumentConfig argument : this.getArguments()) {\n                refreshArgument(argument, subPropsConfiguration);\n            }\n        }\n    }\n\n    private void refreshArgument(ArgumentConfig argument, InmemoryConfiguration subPropsConfiguration) {\n        if (argument.getIndex() != null && argument.getIndex() >= 0) {\n            String prefix = argument.getIndex() + \".\";\n            Environment environment = getScopeModel().modelEnvironment();\n            List<java.lang.reflect.Method> methods =\n                    MethodUtils.getMethods(argument.getClass(), method -> method.getDeclaringClass() != Object.class);\n            for (java.lang.reflect.Method method : methods) {\n                if (MethodUtils.isSetter(method)) {\n                    String propertyName = extractPropertyName(method.getName());\n                    // ignore attributes: 'index' / 'type'\n                    if (StringUtils.isEquals(propertyName, \"index\") || StringUtils.isEquals(propertyName, \"type\")) {\n                        continue;\n                    }\n                    // convert camelCase/snake_case to kebab-case\n                    String kebabPropertyName = prefix + StringUtils.convertToSplitName(propertyName, \"-\");\n\n                    try {\n                        String value = StringUtils.trim(subPropsConfiguration.getString(kebabPropertyName));\n                        if (StringUtils.hasText(value)\n                                && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value)) {\n                            value = environment.resolvePlaceholders(value);\n                            method.invoke(\n                                    argument,\n                                    ClassUtils.convertPrimitive(\n                                            ScopeModelUtil.getFrameworkModel(getScopeModel()),\n                                            method.getParameterTypes()[0],\n                                            value));\n                        }\n                    } catch (Exception e) {\n                        logger.info(\"Failed to override the property \" + method.getName() + \" in \"\n                                + this.getClass().getSimpleName()\n                                + \", please make sure every property has getter/setter method provided.\");\n                    }\n                }\n            }\n        }\n    }\n\n    public AsyncMethodInfo convertMethodConfig2AsyncInfo() {\n        if ((getOninvoke() == null && getOnreturn() == null && getOnthrow() == null)) {\n            return null;\n        }\n\n        // check config conflict\n        if (Boolean.FALSE.equals(isReturn()) && (getOnreturn() != null || getOnthrow() != null)) {\n            throw new IllegalStateException(\n                    \"method config error : return attribute must be set true when on-return or on-throw has been set.\");\n        }\n\n        AsyncMethodInfo asyncMethodInfo = new AsyncMethodInfo();\n\n        asyncMethodInfo.setOninvokeInstance(getOninvoke());\n        asyncMethodInfo.setOnreturnInstance(getOnreturn());\n        asyncMethodInfo.setOnthrowInstance(getOnthrow());\n\n        try {\n            if (StringUtils.isNotEmpty(oninvokeMethod)) {\n                asyncMethodInfo.setOninvokeMethod(getMethodByName(getOninvoke().getClass(), oninvokeMethod));\n            }\n\n            if (StringUtils.isNotEmpty(onreturnMethod)) {\n                asyncMethodInfo.setOnreturnMethod(getMethodByName(getOnreturn().getClass(), onreturnMethod));\n            }\n\n            if (StringUtils.isNotEmpty(onthrowMethod)) {\n                asyncMethodInfo.setOnthrowMethod(getMethodByName(getOnthrow().getClass(), onthrowMethod));\n            }\n        } catch (Exception e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n\n        return asyncMethodInfo;\n    }\n\n    private java.lang.reflect.Method getMethodByName(Class<?> clazz, String methodName) {\n        try {\n            return ReflectUtils.findMethodByMethodName(clazz, methodName);\n        } catch (Exception e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    /**\n     * Set default field values of MethodConfig.\n     *\n     * @see org.apache.dubbo.config.annotation.Method\n     */\n    @Override\n    protected void checkDefault() {\n        super.checkDefault();\n\n        // set default field values\n        // org.apache.dubbo.config.annotation.Method.isReturn() default true;\n        if (isReturn() == null) {\n            setReturn(true);\n        }\n\n        // org.apache.dubbo.config.annotation.Method.sent() default true;\n        if (getSent() == null) {\n            setSent(true);\n        }\n    }\n\n    @Parameter(excluded = true)\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n        // FIXME, add id strategy in ConfigManager\n        //        if (StringUtils.isEmpty(id)) {\n        //            id = name;\n        //        }\n    }\n\n    public Integer getStat() {\n        return stat;\n    }\n\n    @Deprecated\n    public void setStat(Integer stat) {\n        this.stat = stat;\n    }\n\n    @Deprecated\n    public Boolean isRetry() {\n        return retry;\n    }\n\n    @Deprecated\n    public void setRetry(Boolean retry) {\n        this.retry = retry;\n    }\n\n    @Deprecated\n    public Boolean isReliable() {\n        return reliable;\n    }\n\n    @Deprecated\n    public void setReliable(Boolean reliable) {\n        this.reliable = reliable;\n    }\n\n    public Integer getExecutes() {\n        return executes;\n    }\n\n    public void setExecutes(Integer executes) {\n        this.executes = executes;\n    }\n\n    public Boolean getDeprecated() {\n        return deprecated;\n    }\n\n    public void setDeprecated(Boolean deprecated) {\n        this.deprecated = deprecated;\n    }\n\n    public List<ArgumentConfig> getArguments() {\n        return arguments;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void setArguments(List<? extends ArgumentConfig> arguments) {\n        this.arguments = (List<ArgumentConfig>) arguments;\n    }\n\n    public Boolean getSticky() {\n        return sticky;\n    }\n\n    public void setSticky(Boolean sticky) {\n        this.sticky = sticky;\n    }\n\n    @Parameter(key = ON_RETURN_INSTANCE_PARAMETER_KEY, excluded = true, attribute = true)\n    public Object getOnreturn() {\n        return onreturn;\n    }\n\n    public void setOnreturn(Object onreturn) {\n        this.onreturn = onreturn;\n    }\n\n    @Parameter(key = ON_RETURN_METHOD_PARAMETER_KEY, excluded = true, attribute = true)\n    public String getOnreturnMethod() {\n        return onreturnMethod;\n    }\n\n    public void setOnreturnMethod(String onreturnMethod) {\n        this.onreturnMethod = onreturnMethod;\n    }\n\n    @Parameter(key = ON_THROW_INSTANCE_PARAMETER_KEY, excluded = true, attribute = true)\n    public Object getOnthrow() {\n        return onthrow;\n    }\n\n    public void setOnthrow(Object onthrow) {\n        this.onthrow = onthrow;\n    }\n\n    @Parameter(key = ON_THROW_METHOD_PARAMETER_KEY, excluded = true, attribute = true)\n    public String getOnthrowMethod() {\n        return onthrowMethod;\n    }\n\n    public void setOnthrowMethod(String onthrowMethod) {\n        this.onthrowMethod = onthrowMethod;\n    }\n\n    @Parameter(key = ON_INVOKE_INSTANCE_PARAMETER_KEY, excluded = true, attribute = true)\n    public Object getOninvoke() {\n        return oninvoke;\n    }\n\n    public void setOninvoke(Object oninvoke) {\n        this.oninvoke = oninvoke;\n    }\n\n    @Parameter(key = ON_INVOKE_METHOD_PARAMETER_KEY, excluded = true, attribute = true)\n    public String getOninvokeMethod() {\n        return oninvokeMethod;\n    }\n\n    public void setOninvokeMethod(String oninvokeMethod) {\n        this.oninvokeMethod = oninvokeMethod;\n    }\n\n    public Boolean isReturn() {\n        return isReturn;\n    }\n\n    public void setReturn(Boolean isReturn) {\n        this.isReturn = isReturn;\n    }\n\n    @Parameter(excluded = true, attribute = false)\n    public String getService() {\n        return service;\n    }\n\n    public void setService(String service) {\n        this.service = service;\n    }\n\n    @Parameter(excluded = true, attribute = false)\n    public String getServiceId() {\n        return serviceId;\n    }\n\n    public void setServiceId(String serviceId) {\n        this.serviceId = serviceId;\n    }\n\n    public void setParentPrefix(String parentPrefix) {\n        this.parentPrefix = parentPrefix;\n    }\n\n    @Parameter(excluded = true, attribute = false)\n    public String getParentPrefix() {\n        return parentPrefix;\n    }\n\n    public void addArgument(ArgumentConfig argumentConfig) {\n        if (arguments == null) {\n            arguments = new ArrayList<>();\n        }\n        arguments.add(argumentConfig);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.config.nested.AggregationConfig;\nimport org.apache.dubbo.config.nested.HistogramConfig;\nimport org.apache.dubbo.config.nested.OtlpMetricConfig;\nimport org.apache.dubbo.config.nested.PrometheusConfig;\nimport org.apache.dubbo.config.support.Nested;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Configuration for the metrics.\n */\npublic class MetricsConfig extends AbstractConfig {\n\n    private static final long serialVersionUID = -9089919311611546383L;\n\n    /**\n     * Protocol used for metrics.\n     */\n    private String protocol;\n\n    /**\n     * Whether to enable JVM metrics collection.\n     */\n    private Boolean enableJvm;\n\n    /**\n     * Whether to enable thread pool metrics collection.\n     */\n    private Boolean enableThreadpool;\n\n    /**\n     * Whether to enable registry metrics collection.\n     */\n    private Boolean enableRegistry;\n\n    /**\n     * Whether to enable metadata metrics collection.\n     */\n    private Boolean enableMetadata;\n\n    /**\n     * Whether to export metrics service.\n     */\n    private Boolean exportMetricsService;\n\n    /**\n     * Whether to enable Netty metrics collection.\n     */\n    private Boolean enableNetty;\n\n    /**\n     * Whether to enable metrics initialization.\n     */\n    private Boolean enableMetricsInit;\n\n    /**\n     * Whether to enable collector synchronization.\n     */\n    private Boolean enableCollectorSync;\n\n    /**\n     * Collector synchronization period.\n     */\n    private Integer collectorSyncPeriod;\n\n    /**\n     * Configuration for Prometheus metrics collection.\n     */\n    @Nested\n    private PrometheusConfig prometheus;\n\n    /**\n     * Configuration for metrics aggregation.\n     */\n    @Nested\n    private AggregationConfig aggregation;\n\n    /**\n     * Configuration for metrics histogram.\n     */\n    @Nested\n    private HistogramConfig histogram;\n\n    /**\n     * Protocol used for metrics collection and export.\n     */\n    private String exportServiceProtocol;\n\n    /**\n     * Port used for exporting metrics services.\n     */\n    private Integer exportServicePort;\n\n    /**\n     * Decide whether to use the global registry of Micrometer.\n     */\n    private Boolean useGlobalRegistry;\n\n    /**\n     * Whether to enable RPC (Remote Procedure Call) metrics collection.\n     */\n    private Boolean enableRpc;\n\n    /**\n     * The level of metrics collection, which can be \"SERVICE\" or \"METHOD\". The default is \"METHOD\".\n     */\n    private String rpcLevel;\n\n    /**\n     * Configuration for the metrics exporter.\n     */\n    @Nested\n    private OtlpMetricConfig otlp;\n\n    public MetricsConfig() {}\n\n    public MetricsConfig(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    public URL toUrl() {\n        Map<String, String> map = new HashMap<>();\n        appendParameters(map, this);\n\n        // ignore address parameter, use specified url in each metrics server config\n        // the address \"localhost\" here is meaningless\n        URL url = UrlUtils.parseURL(\"localhost\", map);\n        url = url.setScopeModel(getScopeModel());\n        return url;\n    }\n\n    public String getProtocol() {\n        return protocol;\n    }\n\n    public void setProtocol(String protocol) {\n        this.protocol = protocol;\n    }\n\n    public Boolean getEnableJvm() {\n        return enableJvm;\n    }\n\n    public String getRpcLevel() {\n        return rpcLevel;\n    }\n\n    public void setRpcLevel(String rpcLevel) {\n        this.rpcLevel = rpcLevel;\n    }\n\n    public void setEnableJvm(Boolean enableJvm) {\n        this.enableJvm = enableJvm;\n    }\n\n    public Boolean getEnableRegistry() {\n        return enableRegistry;\n    }\n\n    public void setEnableRegistry(Boolean enableRegistry) {\n        this.enableRegistry = enableRegistry;\n    }\n\n    public PrometheusConfig getPrometheus() {\n        return prometheus;\n    }\n\n    public void setPrometheus(PrometheusConfig prometheus) {\n        this.prometheus = prometheus;\n    }\n\n    public AggregationConfig getAggregation() {\n        return aggregation;\n    }\n\n    public void setAggregation(AggregationConfig aggregation) {\n        this.aggregation = aggregation;\n    }\n\n    public HistogramConfig getHistogram() {\n        return histogram;\n    }\n\n    public void setHistogram(HistogramConfig histogram) {\n        this.histogram = histogram;\n    }\n\n    public String getExportServiceProtocol() {\n        return exportServiceProtocol;\n    }\n\n    public void setExportServiceProtocol(String exportServiceProtocol) {\n        this.exportServiceProtocol = exportServiceProtocol;\n    }\n\n    public Integer getExportServicePort() {\n        return exportServicePort;\n    }\n\n    public void setExportServicePort(Integer exportServicePort) {\n        this.exportServicePort = exportServicePort;\n    }\n\n    public Boolean getEnableMetadata() {\n        return enableMetadata;\n    }\n\n    public void setEnableMetadata(Boolean enableMetadata) {\n        this.enableMetadata = enableMetadata;\n    }\n\n    public Boolean getExportMetricsService() {\n        return exportMetricsService;\n    }\n\n    public void setExportMetricsService(Boolean exportMetricsService) {\n        this.exportMetricsService = exportMetricsService;\n    }\n\n    public Boolean getEnableThreadpool() {\n        return enableThreadpool;\n    }\n\n    public void setEnableThreadpool(Boolean enableThreadpool) {\n        this.enableThreadpool = enableThreadpool;\n    }\n\n    public Boolean getEnableMetricsInit() {\n        return enableMetricsInit;\n    }\n\n    public void setEnableMetricsInit(Boolean enableMetricsInit) {\n        this.enableMetricsInit = enableMetricsInit;\n    }\n\n    public Boolean getEnableCollectorSync() {\n        return enableCollectorSync;\n    }\n\n    public void setEnableCollectorSync(Boolean enableCollectorSync) {\n        this.enableCollectorSync = enableCollectorSync;\n    }\n\n    public Integer getCollectorSyncPeriod() {\n        return collectorSyncPeriod;\n    }\n\n    public void setCollectorSyncPeriod(Integer collectorSyncPeriod) {\n        this.collectorSyncPeriod = collectorSyncPeriod;\n    }\n\n    public Boolean getUseGlobalRegistry() {\n        return useGlobalRegistry;\n    }\n\n    public void setUseGlobalRegistry(Boolean useGlobalRegistry) {\n        this.useGlobalRegistry = useGlobalRegistry;\n    }\n\n    public Boolean getEnableRpc() {\n        return enableRpc;\n    }\n\n    public void setEnableRpc(Boolean enableRpc) {\n        this.enableRpc = enableRpc;\n    }\n\n    public Boolean getEnableNetty() {\n        return enableNetty;\n    }\n\n    public void setEnableNetty(Boolean enableNetty) {\n        this.enableNetty = enableNetty;\n    }\n\n    public OtlpMetricConfig getOtlp() {\n        return otlp;\n    }\n\n    public void setOtlp(OtlpMetricConfig otlp) {\n        this.otlp = otlp;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/ModuleConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.beans.Transient;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Configuration for the module.\n *\n * @export\n */\npublic class ModuleConfig extends AbstractConfig {\n\n    private static final long serialVersionUID = 5508512956753757169L;\n\n    /**\n     * The module name\n     */\n    private String name;\n\n    /**\n     * The module version\n     */\n    private String version;\n\n    /**\n     * The module owner\n     */\n    private String owner;\n\n    /**\n     * The module's organization\n     */\n    private String organization;\n\n    /**\n     * Registry centers\n     */\n    private List<RegistryConfig> registries;\n\n    /**\n     * Monitor center\n     */\n    private MonitorConfig monitor;\n\n    /**\n     * Whether to start the module in the background.\n     * If started in the background, it does not await finish on Spring ContextRefreshedEvent.\n     *\n     * @see org.apache.dubbo.config.spring.context.DubboDeployApplicationListener\n     */\n    private Boolean background;\n\n    /**\n     * Whether the reference is referred asynchronously.\n     */\n    private Boolean referAsync;\n\n    /**\n     * The thread number for asynchronous reference pool size.\n     */\n    private Integer referThreadNum;\n\n    /**\n     * Whether the service is exported asynchronously.\n     */\n    private Boolean exportAsync;\n\n    /**\n     * The thread number for asynchronous export pool size.\n     */\n    private Integer exportThreadNum;\n\n    /**\n     * The timeout to check references.\n     */\n    private Long checkReferenceTimeout;\n\n    public ModuleConfig() {\n        super();\n    }\n\n    public ModuleConfig(ModuleModel moduleModel) {\n        super(moduleModel);\n    }\n\n    public ModuleConfig(String name) {\n        this();\n        setName(name);\n    }\n\n    public ModuleConfig(ModuleModel moduleModel, String name) {\n        this(moduleModel);\n        setName(name);\n    }\n\n    @Override\n    protected void checkDefault() {\n        super.checkDefault();\n        // default is false\n        if (background == null) {\n            background = false;\n        }\n    }\n\n    @Override\n    protected void checkScopeModel(ScopeModel scopeModel) {\n        if (!(scopeModel instanceof ModuleModel)) {\n            throw new IllegalArgumentException(\n                    \"Invalid scope model, expect to be a ModuleModel but got: \" + scopeModel);\n        }\n    }\n\n    @Override\n    @Transient\n    public ModuleModel getScopeModel() {\n        return (ModuleModel) super.getScopeModel();\n    }\n\n    @Override\n    @Transient\n    protected ScopeModel getDefaultModel() {\n        return ApplicationModel.defaultModel().getDefaultModule();\n    }\n\n    @Parameter(key = \"module\")\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Parameter(key = \"module.version\")\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    @Parameter(key = \"module.owner\")\n    public String getOwner() {\n        return owner;\n    }\n\n    public void setOwner(String owner) {\n        this.owner = owner;\n    }\n\n    @Parameter(key = \"module.organization\")\n    public String getOrganization() {\n        return organization;\n    }\n\n    public void setOrganization(String organization) {\n        this.organization = organization;\n    }\n\n    public RegistryConfig getRegistry() {\n        return CollectionUtils.isEmpty(registries) ? null : registries.get(0);\n    }\n\n    public void setRegistry(RegistryConfig registry) {\n        List<RegistryConfig> registries = new ArrayList<>(1);\n        registries.add(registry);\n        this.registries = registries;\n    }\n\n    public List<RegistryConfig> getRegistries() {\n        return registries;\n    }\n\n    @SuppressWarnings({\"unchecked\"})\n    public void setRegistries(List<? extends RegistryConfig> registries) {\n        this.registries = (List<RegistryConfig>) registries;\n    }\n\n    public MonitorConfig getMonitor() {\n        return monitor;\n    }\n\n    public void setMonitor(MonitorConfig monitor) {\n        this.monitor = monitor;\n    }\n\n    public void setMonitor(String monitor) {\n        this.monitor = new MonitorConfig(monitor);\n    }\n\n    public Boolean getBackground() {\n        return background;\n    }\n\n    /**\n     * Whether start module in background.\n     * If start in background, do not await finish on Spring ContextRefreshedEvent.\n     *\n     * @see org.apache.dubbo.config.spring.context.DubboDeployApplicationListener\n     */\n    public void setBackground(Boolean background) {\n        this.background = background;\n    }\n\n    public Integer getReferThreadNum() {\n        return referThreadNum;\n    }\n\n    public void setReferThreadNum(Integer referThreadNum) {\n        this.referThreadNum = referThreadNum;\n    }\n\n    public Integer getExportThreadNum() {\n        return exportThreadNum;\n    }\n\n    public void setExportThreadNum(Integer exportThreadNum) {\n        this.exportThreadNum = exportThreadNum;\n    }\n\n    public Boolean getReferAsync() {\n        return referAsync;\n    }\n\n    public void setReferAsync(Boolean referAsync) {\n        this.referAsync = referAsync;\n    }\n\n    public Boolean getExportAsync() {\n        return exportAsync;\n    }\n\n    public void setExportAsync(Boolean exportAsync) {\n        this.exportAsync = exportAsync;\n    }\n\n    public Long getCheckReferenceTimeout() {\n        return checkReferenceTimeout;\n    }\n\n    public void setCheckReferenceTimeout(Long checkReferenceTimeout) {\n        this.checkReferenceTimeout = checkReferenceTimeout;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/MonitorConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\n\n/**\n * Configuration for the monitor.\n *\n * @export\n */\npublic class MonitorConfig extends AbstractConfig {\n\n    private static final long serialVersionUID = -1184681514659198203L;\n\n    /**\n     * The protocol of the monitor. If the value is \"registry\" it will search the monitor address from the registry center.\n     * Otherwise, it will directly connect to the monitor center.\n     */\n    private String protocol;\n\n    /**\n     * The monitor address\n     */\n    private String address;\n\n    /**\n     * The monitor username\n     */\n    private String username;\n\n    /**\n     * The monitor password\n     */\n    private String password;\n\n    /**\n     * The monitor group\n     */\n    private String group;\n\n    /**\n     * The monitor version\n     */\n    private String version;\n\n    /**\n     * The monitor reporting interval\n     */\n    private String interval;\n\n    /**\n     * Customized parameters\n     */\n    private Map<String, String> parameters;\n\n    public MonitorConfig() {}\n\n    public MonitorConfig(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    public MonitorConfig(String address) {\n        this.address = address;\n    }\n\n    public MonitorConfig(ApplicationModel applicationModel, String address) {\n        super(applicationModel);\n        this.address = address;\n    }\n\n    @Parameter(excluded = true)\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    @Parameter(excluded = true)\n    public String getProtocol() {\n        return protocol;\n    }\n\n    public void setProtocol(String protocol) {\n        this.protocol = protocol;\n    }\n\n    @Parameter(excluded = true)\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    @Parameter(excluded = true)\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    public Map<String, String> getParameters() {\n        return parameters;\n    }\n\n    public void setParameters(Map<String, String> parameters) {\n        this.parameters = parameters;\n    }\n\n    public String getInterval() {\n        return interval;\n    }\n\n    public void setInterval(String interval) {\n        this.interval = interval;\n    }\n\n    @Override\n    @Parameter(excluded = true, attribute = false)\n    public boolean isValid() {\n        return StringUtils.isNotEmpty(address) || RegistryConstants.REGISTRY_PROTOCOL.equals(protocol);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/ProtocolConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.serialization.PreferSerializationProvider;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.nested.TripleConfig;\nimport org.apache.dubbo.config.support.Nested;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Field;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.JSON_CHECK_LEVEL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SSL_ENABLED_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_POOL_EXHAUSTED_LISTENERS_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\n/**\n * Configuration for the protocol.\n */\npublic class ProtocolConfig extends AbstractConfig {\n\n    private static final long serialVersionUID = 6913423882496634749L;\n\n    /**\n     * The name of the protocol.\n     */\n    private String name;\n\n    /**\n     * The service's IP address (useful when there are multiple network cards available).\n     */\n    private String host;\n\n    /**\n     * The service's port number.\n     */\n    private Integer port;\n\n    /**\n     * The context path for the service.\n     */\n    private String contextpath;\n\n    /**\n     * The name of the thread pool.\n     */\n    private String threadpool;\n\n    /**\n     * The core thread size of the thread pool.\n     */\n    private Integer corethreads;\n\n    /**\n     * The fixed size of the thread pool.\n     */\n    private Integer threads;\n\n    /**\n     * The fixed size of the IO thread pool.\n     */\n    private Integer iothreads;\n\n    /**\n     * The keep-alive time for threads in the thread pool (default unit is TimeUnit.MILLISECONDS).\n     */\n    private Integer alive;\n\n    /**\n     * The length of the thread pool's queue.\n     */\n    private Integer queues;\n\n    /**\n     * Listeners for exhausted thread pool.\n     */\n    private String threadPoolExhaustedListeners;\n\n    /**\n     * The maximum acceptable connections.\n     */\n    private Integer accepts;\n\n    /**\n     * The protocol codec.\n     */\n    private String codec;\n\n    /**\n     * The serialization method.\n     */\n    private String serialization;\n\n    /**\n     * Specifies the preferred serialization method for the consumer.\n     *  If specified, the consumer will use this parameter first.\n     * If the Dubbo Sdk you are using contains the serialization type, the serialization method specified by the argument is used.\n     * <p>\n     * When this parameter is null or the serialization type specified by this parameter does not exist in the Dubbo SDK, the serialization type specified by serialization is used.\n     * If the Dubbo SDK if still does not exist, the default type of the Dubbo SDK is used.\n     * For Dubbo SDK >= 3.2, <code>preferSerialization</code> takes precedence over <code>serialization</code>\n     * <p>\n     * Supports multiple values separated by commas, e.g., \"fastjson2,fastjson,hessian2\".\n     */\n    private String preferSerialization; // default:fastjson2,hessian2\n\n    /**\n     * The character set used for communication.\n     */\n    private String charset;\n\n    /**\n     * The maximum payload length.\n     */\n    private Integer payload;\n\n    /**\n     * The buffer size.\n     */\n    private Integer buffer;\n\n    /**\n     * The interval for sending heartbeats.\n     */\n    private Integer heartbeat;\n\n    /**\n     * The access log configuration.\n     */\n    private String accesslog;\n\n    /**\n     * The transporter used for communication.\n     */\n    private String transporter;\n\n    /**\n     * The method of information exchange.\n     */\n    private String exchanger;\n\n    /**\n     * The thread dispatch mode.\n     */\n    private String dispatcher;\n\n    /**\n     * The networker implementation.\n     */\n    private String networker;\n\n    /**\n     * The server implementation.\n     */\n    private String server;\n\n    /**\n     * The client implementation.\n     */\n    private String client;\n\n    /**\n     * Supported Telnet commands, separated by commas.\n     */\n    private String telnet;\n\n    /**\n     * The command line prompt.\n     */\n    private String prompt;\n\n    /**\n     * The status check configuration.\n     */\n    private String status;\n\n    /**\n     * Indicates whether the service should be registered.\n     */\n    private Boolean register;\n\n    // TODO: Move this property to the provider configuration.\n    /**\n     * Indicates whether it is a persistent connection.\n     */\n    private Boolean keepAlive;\n\n    // TODO: Move this property to the provider configuration.\n    /**\n     * The optimizer used for dubbo protocol.\n     */\n    private String optimizer;\n\n    /**\n     * Additional extensions.\n     */\n    private String extension;\n\n    /**\n     * Custom parameters.\n     */\n    private Map<String, String> parameters;\n\n    /**\n     * Indicates whether SSL is enabled.\n     */\n    private Boolean sslEnabled;\n\n    /**\n     * Extra protocol for this service, using Port Unification Server.\n     */\n    private String extProtocol;\n\n    private String preferredProtocol;\n\n    /**\n     * JSON check level for serialization.\n     */\n    private String jsonCheckLevel;\n\n    /**\n     * Indicates whether to support no interface.\n     */\n    private Boolean noInterfaceSupport;\n\n    @Nested\n    private TripleConfig triple;\n\n    public ProtocolConfig() {}\n\n    public ProtocolConfig(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    public ProtocolConfig(String name) {\n        setName(name);\n    }\n\n    public ProtocolConfig(ApplicationModel applicationModel, String name) {\n        super(applicationModel);\n        setName(name);\n    }\n\n    public ProtocolConfig(String name, int port) {\n        setName(name);\n        setPort(port);\n    }\n\n    public ProtocolConfig(ApplicationModel applicationModel, String name, int port) {\n        super(applicationModel);\n        setName(name);\n        setPort(port);\n    }\n\n    @Override\n    protected void checkDefault() {\n        super.checkDefault();\n        if (name == null) {\n            name = DUBBO_PROTOCOL;\n        }\n\n        if (StringUtils.isBlank(preferSerialization)) {\n            preferSerialization = serialization != null\n                    ? serialization\n                    : getScopeModel()\n                            .getBeanFactory()\n                            .getBean(PreferSerializationProvider.class)\n                            .getPreferSerialization();\n        }\n    }\n\n    @Parameter(excluded = true)\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Parameter(excluded = true)\n    public String getHost() {\n        return host;\n    }\n\n    public void setHost(String host) {\n        this.host = host;\n    }\n\n    @Parameter(excluded = true)\n    public Integer getPort() {\n        return port;\n    }\n\n    public void setPort(Integer port) {\n        this.port = port;\n    }\n\n    @Deprecated\n    @Parameter(excluded = true, attribute = false)\n    public String getPath() {\n        return getContextpath();\n    }\n\n    @Deprecated\n    public void setPath(String path) {\n        setContextpath(path);\n    }\n\n    @Parameter(excluded = true)\n    public String getContextpath() {\n        return contextpath;\n    }\n\n    public void setContextpath(String contextpath) {\n        this.contextpath = contextpath;\n    }\n\n    public String getThreadpool() {\n        return threadpool;\n    }\n\n    public void setThreadpool(String threadpool) {\n        this.threadpool = threadpool;\n    }\n\n    @Parameter(key = JSON_CHECK_LEVEL_KEY)\n    public String getJsonCheckLevel() {\n        return jsonCheckLevel;\n    }\n\n    public void setJsonCheckLevel(String jsonCheckLevel) {\n        this.jsonCheckLevel = jsonCheckLevel;\n    }\n\n    @Parameter(key = THREAD_POOL_EXHAUSTED_LISTENERS_KEY)\n    public String getThreadPoolExhaustedListeners() {\n        return threadPoolExhaustedListeners;\n    }\n\n    public void setThreadPoolExhaustedListeners(String threadPoolExhaustedListeners) {\n        this.threadPoolExhaustedListeners = threadPoolExhaustedListeners;\n    }\n\n    public Integer getCorethreads() {\n        return corethreads;\n    }\n\n    public void setCorethreads(Integer corethreads) {\n        this.corethreads = corethreads;\n    }\n\n    public Integer getThreads() {\n        return threads;\n    }\n\n    public void setThreads(Integer threads) {\n        this.threads = threads;\n    }\n\n    public Integer getIothreads() {\n        return iothreads;\n    }\n\n    public void setIothreads(Integer iothreads) {\n        this.iothreads = iothreads;\n    }\n\n    public Integer getAlive() {\n        return alive;\n    }\n\n    public void setAlive(Integer alive) {\n        this.alive = alive;\n    }\n\n    public Integer getQueues() {\n        return queues;\n    }\n\n    public void setQueues(Integer queues) {\n        this.queues = queues;\n    }\n\n    public Integer getAccepts() {\n        return accepts;\n    }\n\n    public void setAccepts(Integer accepts) {\n        this.accepts = accepts;\n    }\n\n    public String getCodec() {\n        return codec;\n    }\n\n    public void setCodec(String codec) {\n        this.codec = codec;\n    }\n\n    public String getSerialization() {\n        return serialization;\n    }\n\n    public void setSerialization(String serialization) {\n        this.serialization = serialization;\n    }\n\n    public String getPreferSerialization() {\n        return preferSerialization;\n    }\n\n    public void setPreferSerialization(String preferSerialization) {\n        this.preferSerialization = preferSerialization;\n    }\n\n    public String getCharset() {\n        return charset;\n    }\n\n    public void setCharset(String charset) {\n        this.charset = charset;\n    }\n\n    public Integer getPayload() {\n        return payload;\n    }\n\n    public void setPayload(Integer payload) {\n        this.payload = payload;\n    }\n\n    public Integer getBuffer() {\n        return buffer;\n    }\n\n    public void setBuffer(Integer buffer) {\n        this.buffer = buffer;\n    }\n\n    public Integer getHeartbeat() {\n        return heartbeat;\n    }\n\n    public void setHeartbeat(Integer heartbeat) {\n        this.heartbeat = heartbeat;\n    }\n\n    public String getServer() {\n        return server;\n    }\n\n    public void setServer(String server) {\n        this.server = server;\n    }\n\n    public String getClient() {\n        return client;\n    }\n\n    public void setClient(String client) {\n        this.client = client;\n    }\n\n    public String getAccesslog() {\n        return accesslog;\n    }\n\n    public void setAccesslog(String accesslog) {\n        this.accesslog = accesslog;\n    }\n\n    public String getTelnet() {\n        return telnet;\n    }\n\n    public void setTelnet(String telnet) {\n        this.telnet = telnet;\n    }\n\n    @Parameter(escaped = true)\n    public String getPrompt() {\n        return prompt;\n    }\n\n    public void setPrompt(String prompt) {\n        this.prompt = prompt;\n    }\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n\n    public Boolean isRegister() {\n        return register;\n    }\n\n    public void setRegister(Boolean register) {\n        this.register = register;\n    }\n\n    public String getTransporter() {\n        return transporter;\n    }\n\n    public void setTransporter(String transporter) {\n        this.transporter = transporter;\n    }\n\n    public String getExchanger() {\n        return exchanger;\n    }\n\n    public void setExchanger(String exchanger) {\n        this.exchanger = exchanger;\n    }\n\n    /**\n     * typo, switch to use {@link #getDispatcher()}\n     *\n     * @deprecated {@link #getDispatcher()}\n     */\n    @Deprecated\n    @Parameter(excluded = true, attribute = false)\n    public String getDispather() {\n        return getDispatcher();\n    }\n\n    /**\n     * typo, switch to use {@link #getDispatcher()}\n     *\n     * @deprecated {@link #setDispatcher(String)}\n     */\n    @Deprecated\n    public void setDispather(String dispather) {\n        setDispatcher(dispather);\n    }\n\n    public String getDispatcher() {\n        return dispatcher;\n    }\n\n    public void setDispatcher(String dispatcher) {\n        this.dispatcher = dispatcher;\n    }\n\n    public String getNetworker() {\n        return networker;\n    }\n\n    public void setNetworker(String networker) {\n        this.networker = networker;\n    }\n\n    public Map<String, String> getParameters() {\n        return parameters;\n    }\n\n    public void setParameters(Map<String, String> parameters) {\n        this.parameters = parameters;\n    }\n\n    @Parameter(key = SSL_ENABLED_KEY)\n    public Boolean getSslEnabled() {\n        return sslEnabled;\n    }\n\n    public void setSslEnabled(Boolean sslEnabled) {\n        this.sslEnabled = sslEnabled;\n    }\n\n    public Boolean getKeepAlive() {\n        return keepAlive;\n    }\n\n    public void setKeepAlive(Boolean keepAlive) {\n        this.keepAlive = keepAlive;\n    }\n\n    public String getOptimizer() {\n        return optimizer;\n    }\n\n    public void setOptimizer(String optimizer) {\n        this.optimizer = optimizer;\n    }\n\n    public String getExtension() {\n        return extension;\n    }\n\n    public void setExtension(String extension) {\n        this.extension = extension;\n    }\n\n    @Override\n    @Parameter(excluded = true, attribute = false)\n    public boolean isValid() {\n        return StringUtils.isNotEmpty(name);\n    }\n\n    public String getExtProtocol() {\n        return extProtocol;\n    }\n\n    public void setExtProtocol(String extProtocol) {\n        this.extProtocol = extProtocol;\n    }\n\n    public String getPreferredProtocol() {\n        return preferredProtocol;\n    }\n\n    public void setPreferredProtocol(String preferredProtocol) {\n        this.preferredProtocol = preferredProtocol;\n    }\n\n    public Boolean isNoInterfaceSupport() {\n        return noInterfaceSupport;\n    }\n\n    public void setNoInterfaceSupport(Boolean noInterfaceSupport) {\n        this.noInterfaceSupport = noInterfaceSupport;\n    }\n\n    public TripleConfig getTriple() {\n        return triple;\n    }\n\n    @Parameter(excluded = true)\n    public TripleConfig getTripleOrDefault() {\n        if (triple == null) {\n            triple = new TripleConfig();\n        }\n        return triple;\n    }\n\n    public void setTriple(TripleConfig triple) {\n        this.triple = triple;\n    }\n\n    public void mergeProtocol(ProtocolConfig sourceConfig) {\n        if (sourceConfig == null) {\n            return;\n        }\n        Field[] targetFields = getClass().getDeclaredFields();\n        try {\n            Map<String, Object> protocolConfigMap = CollectionUtils.objToMap(sourceConfig);\n            for (Field targetField : targetFields) {\n                Optional.ofNullable(protocolConfigMap.get(targetField.getName()))\n                        .ifPresent(value -> {\n                            try {\n                                targetField.setAccessible(true);\n                                if (targetField.get(this) == null) {\n                                    targetField.set(this, value);\n                                }\n                            } catch (IllegalAccessException e) {\n                                throw new RuntimeException(e);\n                            }\n                        });\n            }\n        } catch (Exception e) {\n            logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"merge protocol config fail, error: \", e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/ProviderConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.EXPORT_BACKGROUND_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXPORT_THREAD_NUM_KEY;\n\n/**\n * Configuration for the service provider.\n *\n * @export\n * @see org.apache.dubbo.config.ProtocolConfig\n * @see ServiceConfigBase\n */\npublic class ProviderConfig extends AbstractServiceConfig {\n\n    private static final long serialVersionUID = 6913423882496634749L;\n\n    /* ======== Default values for protocols, which take effect when protocol attributes are not set ======== */\n\n    /**\n     * The IP addresses of the service (used when there are multiple network cards available).\n     */\n    private String host;\n\n    /**\n     * The port of the service.\n     */\n    private Integer port;\n\n    /**\n     * The context path of the service.\n     */\n    private String contextpath;\n\n    /**\n     * The thread pool configuration.\n     */\n    private String threadpool;\n\n    /**\n     * The name of the thread pool.\n     */\n    private String threadname;\n\n    /**\n     * The size of the thread pool (fixed size).\n     */\n    private Integer threads;\n\n    /**\n     * The size of the I/O thread pool (fixed size).\n     */\n    private Integer iothreads;\n\n    /**\n     * The keep-alive time of the thread pool, default unit: TimeUnit.MILLISECONDS.\n     */\n    private Integer alive;\n\n    /**\n     * The length of the thread pool queue.\n     */\n    private Integer queues;\n\n    /**\n     * The maximum number of acceptable connections.\n     */\n    private Integer accepts;\n\n    /**\n     * The codec used by the protocol.\n     */\n    private String codec;\n\n    /**\n     * The charset used for serialization.\n     */\n    private String charset;\n\n    /**\n     * The maximum payload length.\n     */\n    private Integer payload;\n\n    /**\n     * The size of the network I/O buffer.\n     */\n    private Integer buffer;\n\n    /**\n     * The transporter used by the protocol.\n     */\n    private String transporter;\n\n    /**\n     * The method of information exchange.\n     */\n    private String exchanger;\n\n    /**\n     * The mode of thread dispatching.\n     */\n    private String dispatcher;\n\n    /**\n     * The networker used by the protocol.\n     */\n    private String networker;\n\n    /**\n     * The server-side implementation model of the protocol.\n     */\n    private String server;\n\n    /**\n     * The client-side implementation model of the protocol.\n     */\n    private String client;\n\n    /**\n     * Supported telnet commands, separated by commas.\n     */\n    private String telnet;\n\n    /**\n     * The command line prompt.\n     */\n    private String prompt;\n\n    /**\n     * The status check configuration.\n     */\n    private String status;\n\n    /**\n     * The wait time when stopping the service.\n     */\n    private Integer wait;\n\n    /**\n     * The number of threads for the asynchronous export pool.\n     */\n    private Integer exportThreadNum;\n\n    /**\n     * Whether the export should run in the background or not.\n     *\n     * @deprecated Replace with {@link ModuleConfig#setBackground(Boolean)}\n     * @see ModuleConfig#setBackground(Boolean)\n     */\n    private Boolean exportBackground;\n\n    public ProviderConfig() {}\n\n    public ProviderConfig(ModuleModel moduleModel) {\n        super(moduleModel);\n    }\n\n    @Deprecated\n    public void setProtocol(String protocol) {\n        this.protocols = new ArrayList<>(Arrays.asList(new ProtocolConfig(protocol)));\n    }\n\n    @Parameter(excluded = true)\n    public String getHost() {\n        return host;\n    }\n\n    public void setHost(String host) {\n        this.host = host;\n    }\n\n    @Parameter(excluded = true)\n    public Integer getPort() {\n        return port;\n    }\n\n    @Deprecated\n    public void setPort(Integer port) {\n        this.port = port;\n    }\n\n    @Deprecated\n    @Parameter(excluded = true, attribute = false)\n    public String getPath() {\n        return getContextpath();\n    }\n\n    @Deprecated\n    public void setPath(String path) {\n        setContextpath(path);\n    }\n\n    @Parameter(excluded = true)\n    public String getContextpath() {\n        return contextpath;\n    }\n\n    public void setContextpath(String contextpath) {\n        this.contextpath = contextpath;\n    }\n\n    public String getThreadpool() {\n        return threadpool;\n    }\n\n    public void setThreadpool(String threadpool) {\n        this.threadpool = threadpool;\n    }\n\n    public String getThreadname() {\n        return threadname;\n    }\n\n    public void setThreadname(String threadname) {\n        this.threadname = threadname;\n    }\n\n    public Integer getThreads() {\n        return threads;\n    }\n\n    public void setThreads(Integer threads) {\n        this.threads = threads;\n    }\n\n    public Integer getIothreads() {\n        return iothreads;\n    }\n\n    public void setIothreads(Integer iothreads) {\n        this.iothreads = iothreads;\n    }\n\n    public Integer getAlive() {\n        return alive;\n    }\n\n    public void setAlive(Integer alive) {\n        this.alive = alive;\n    }\n\n    public Integer getQueues() {\n        return queues;\n    }\n\n    public void setQueues(Integer queues) {\n        this.queues = queues;\n    }\n\n    public Integer getAccepts() {\n        return accepts;\n    }\n\n    public void setAccepts(Integer accepts) {\n        this.accepts = accepts;\n    }\n\n    public String getCodec() {\n        return codec;\n    }\n\n    public void setCodec(String codec) {\n        this.codec = codec;\n    }\n\n    public String getCharset() {\n        return charset;\n    }\n\n    public void setCharset(String charset) {\n        this.charset = charset;\n    }\n\n    public Integer getPayload() {\n        return payload;\n    }\n\n    public void setPayload(Integer payload) {\n        this.payload = payload;\n    }\n\n    public Integer getBuffer() {\n        return buffer;\n    }\n\n    public void setBuffer(Integer buffer) {\n        this.buffer = buffer;\n    }\n\n    public String getServer() {\n        return server;\n    }\n\n    public void setServer(String server) {\n        this.server = server;\n    }\n\n    public String getClient() {\n        return client;\n    }\n\n    public void setClient(String client) {\n        this.client = client;\n    }\n\n    public String getTelnet() {\n        return telnet;\n    }\n\n    public void setTelnet(String telnet) {\n        this.telnet = telnet;\n    }\n\n    @Parameter(escaped = true)\n    public String getPrompt() {\n        return prompt;\n    }\n\n    public void setPrompt(String prompt) {\n        this.prompt = prompt;\n    }\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n\n    public String getTransporter() {\n        return transporter;\n    }\n\n    public void setTransporter(String transporter) {\n        this.transporter = transporter;\n    }\n\n    public String getExchanger() {\n        return exchanger;\n    }\n\n    public void setExchanger(String exchanger) {\n        this.exchanger = exchanger;\n    }\n\n    /**\n     * typo, switch to use {@link #getDispatcher()}\n     *\n     * @deprecated {@link #getDispatcher()}\n     */\n    @Deprecated\n    @Parameter(excluded = true, attribute = false)\n    public String getDispather() {\n        return getDispatcher();\n    }\n\n    /**\n     * typo, switch to use {@link #getDispatcher()}\n     *\n     * @deprecated {@link #setDispatcher(String)}\n     */\n    @Deprecated\n    public void setDispather(String dispather) {\n        setDispatcher(dispather);\n    }\n\n    public String getDispatcher() {\n        return dispatcher;\n    }\n\n    public void setDispatcher(String dispatcher) {\n        this.dispatcher = dispatcher;\n    }\n\n    public String getNetworker() {\n        return networker;\n    }\n\n    public void setNetworker(String networker) {\n        this.networker = networker;\n    }\n\n    public Integer getWait() {\n        return wait;\n    }\n\n    public void setWait(Integer wait) {\n        this.wait = wait;\n    }\n\n    @Deprecated\n    @Parameter(key = EXPORT_THREAD_NUM_KEY, excluded = true)\n    public Integer getExportThreadNum() {\n        return exportThreadNum;\n    }\n\n    @Deprecated\n    public void setExportThreadNum(Integer exportThreadNum) {\n        this.exportThreadNum = exportThreadNum;\n    }\n\n    /**\n     * @deprecated replace with {@link ModuleConfig#getBackground()}\n     * @see ModuleConfig#getBackground()\n     */\n    @Deprecated\n    @Parameter(key = EXPORT_BACKGROUND_KEY, excluded = true)\n    public Boolean getExportBackground() {\n        return exportBackground;\n    }\n\n    /**\n     * Whether export should run in background or not.\n     *\n     * @deprecated replace with {@link ModuleConfig#setBackground(Boolean)}\n     * @see ModuleConfig#setBackground(Boolean)\n     */\n    @Deprecated\n    public void setExportBackground(Boolean exportBackground) {\n        this.exportBackground = exportBackground;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.compact.Dubbo2CompactUtils;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.RegexProperties;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.context.ConfigMode;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\nimport org.apache.dubbo.rpc.service.GenericService;\nimport org.apache.dubbo.rpc.support.ProtocolUtils;\n\nimport java.beans.Transient;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO;\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.USER_HOME;\nimport static org.apache.dubbo.common.constants.CommonConstants.UNLOAD_CLUSTER_RELATED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\n/**\n * Base configuration for the service reference.\n *\n * @export\n */\npublic abstract class ReferenceConfigBase<T> extends AbstractReferenceConfig {\n\n    private static final long serialVersionUID = -5864351140409987595L;\n\n    private static final String ORIGIN_CONFIG = \"ORIGIN_CONFIG\";\n\n    /**\n     * The interface class of the reference service.\n     */\n    protected Class<?> interfaceClass;\n\n    /**\n     * The URL for peer-to-peer invocation.\n     */\n    protected String url;\n\n    /**\n     * The default consumer configuration.\n     */\n    protected ConsumerConfig consumer;\n\n    /**\n     * In mesh mode, this flag uninstalls the directory, router, and load balancing configurations related to the cluster in the currently invoked invoker.\n     * It delegates retry, load balancing, timeout, and other traffic management capabilities to Sidecar.\n     */\n    protected Boolean unloadClusterRelated;\n\n    public ReferenceConfigBase() {\n        serviceMetadata = new ServiceMetadata();\n        serviceMetadata.addAttribute(ORIGIN_CONFIG, this);\n    }\n\n    public ReferenceConfigBase(ModuleModel moduleModel) {\n        super(moduleModel);\n        serviceMetadata = new ServiceMetadata();\n        serviceMetadata.addAttribute(ORIGIN_CONFIG, this);\n    }\n\n    public ReferenceConfigBase(Reference reference) {\n        serviceMetadata = new ServiceMetadata();\n        serviceMetadata.addAttribute(ORIGIN_CONFIG, this);\n        appendAnnotation(Reference.class, reference);\n        setMethods(MethodConfig.constructMethodConfig(reference.methods()));\n    }\n\n    public ReferenceConfigBase(ModuleModel moduleModel, Reference reference) {\n        super(moduleModel);\n        serviceMetadata = new ServiceMetadata();\n        serviceMetadata.addAttribute(ORIGIN_CONFIG, this);\n        appendAnnotation(Reference.class, reference);\n        setMethods(MethodConfig.constructMethodConfig(reference.methods()));\n    }\n\n    public boolean shouldCheck() {\n        checkDefault();\n        Boolean shouldCheck = isCheck();\n        if (shouldCheck == null && getConsumer() != null) {\n            shouldCheck = getConsumer().isCheck();\n        }\n        if (shouldCheck == null) {\n            // default true\n            shouldCheck = true;\n        }\n        return shouldCheck;\n    }\n\n    public boolean shouldInit() {\n        checkDefault();\n        Boolean shouldInit = isInit();\n        if (shouldInit == null && getConsumer() != null) {\n            shouldInit = getConsumer().isInit();\n        }\n        if (shouldInit == null) {\n            // default is true\n            return true;\n        }\n        return shouldInit;\n    }\n\n    @Override\n    protected void preProcessRefresh() {\n        super.preProcessRefresh();\n        if (consumer == null) {\n            consumer = getModuleConfigManager()\n                    .getDefaultConsumer()\n                    .orElseThrow(() -> new IllegalStateException(\"Default consumer is not initialized\"));\n        }\n        // try set properties from `dubbo.reference` if not set in current config\n        refreshWithPrefixes(super.getPrefixes(), ConfigMode.OVERRIDE_IF_ABSENT);\n    }\n\n    @Override\n    @Parameter(excluded = true, attribute = false)\n    public List<String> getPrefixes() {\n        List<String> prefixes = new ArrayList<>();\n        // dubbo.reference.{interface-name}\n        prefixes.add(DUBBO + \".reference.\" + interfaceName);\n        return prefixes;\n    }\n\n    @Override\n    @Transient\n    public Map<String, String> getMetaData() {\n        return getMetaData(null);\n    }\n\n    @Override\n    public Map<String, String> getMetaData(String prefix) {\n        Map<String, String> metaData = new HashMap<>();\n        ConsumerConfig consumer = this.getConsumer();\n        // consumer should be initialized at preProcessRefresh()\n        if (isRefreshed() && consumer == null) {\n            throw new IllegalStateException(\"Consumer is not initialized\");\n        }\n        // use consumer attributes as default value\n        appendAttributes(metaData, consumer, prefix);\n        appendAttributes(metaData, this, prefix);\n        return metaData;\n    }\n\n    /**\n     * Get service interface class of this reference.\n     * The actual service type of remote provider.\n     *\n     * @return\n     */\n    public Class<?> getServiceInterfaceClass() {\n        Class<?> actualInterface = interfaceClass;\n        if (interfaceClass == GenericService.class) {\n            try {\n                if (getInterfaceClassLoader() != null) {\n                    actualInterface = Class.forName(interfaceName, false, getInterfaceClassLoader());\n                } else {\n                    actualInterface = Class.forName(interfaceName);\n                }\n            } catch (ClassNotFoundException e) {\n                return null;\n            }\n        }\n        return actualInterface;\n    }\n\n    /**\n     * Get proxy interface class of this reference.\n     * The proxy interface class is used to create proxy instance.\n     *\n     * @return\n     */\n    public Class<?> getInterfaceClass() {\n        if (interfaceClass != null) {\n            return interfaceClass;\n        }\n\n        String generic = getGeneric();\n        if (StringUtils.isBlank(generic) && getConsumer() != null) {\n            generic = getConsumer().getGeneric();\n        }\n        if (getInterfaceClassLoader() != null) {\n            interfaceClass = determineInterfaceClass(generic, interfaceName, getInterfaceClassLoader());\n        } else {\n            interfaceClass = determineInterfaceClass(generic, interfaceName);\n        }\n        return interfaceClass;\n    }\n\n    /**\n     * Determine the interface of the proxy class\n     *\n     * @param generic\n     * @param interfaceName\n     * @return\n     */\n    public static Class<?> determineInterfaceClass(String generic, String interfaceName) {\n        return determineInterfaceClass(generic, interfaceName, ClassUtils.getClassLoader());\n    }\n\n    public static Class<?> determineInterfaceClass(String generic, String interfaceName, ClassLoader classLoader) {\n        if (ProtocolUtils.isGeneric(generic)) {\n            return Dubbo2CompactUtils.isEnabled() && Dubbo2CompactUtils.isGenericServiceClassLoaded()\n                    ? Dubbo2CompactUtils.getGenericServiceClass()\n                    : GenericService.class;\n        }\n        try {\n            if (StringUtils.isNotEmpty(interfaceName)) {\n                return Class.forName(interfaceName, true, classLoader);\n            }\n        } catch (ClassNotFoundException t) {\n            throw new IllegalStateException(t.getMessage(), t);\n        }\n        return null;\n    }\n\n    @Override\n    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {\n        super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);\n        if (this.consumer != null && this.consumer.getScopeModel() != getScopeModel()) {\n            this.consumer.setScopeModel(getScopeModel());\n        }\n    }\n\n    public void setInterface(Class<?> interfaceClass) {\n        if (interfaceClass != null && !interfaceClass.isInterface()) {\n            throw new IllegalStateException(\"The interface class \" + interfaceClass + \" is not a interface!\");\n        }\n        setInterface(interfaceClass == null ? null : interfaceClass.getName());\n        this.interfaceClass = interfaceClass;\n        if (getInterfaceClassLoader() == null) {\n            setInterfaceClassLoader(interfaceClass == null ? null : interfaceClass.getClassLoader());\n        } else {\n            if (interfaceClass != null) {\n                try {\n                    if (!interfaceClass.equals(\n                            Class.forName(interfaceClass.getName(), false, getInterfaceClassLoader()))) {\n                        // interfaceClass is not visible from origin classloader, override the classloader from\n                        // interfaceClass into referenceConfig\n                        setInterfaceClassLoader(interfaceClass.getClassLoader());\n                    }\n                } catch (ClassNotFoundException e) {\n                    // class not found from origin classloader, override the classloader from interfaceClass into\n                    // referenceConfig\n                    setInterfaceClassLoader(interfaceClass.getClassLoader());\n                }\n            }\n        }\n    }\n\n    @Parameter(excluded = true)\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public ConsumerConfig getConsumer() {\n        return consumer;\n    }\n\n    public void setConsumer(ConsumerConfig consumer) {\n        this.consumer = consumer;\n    }\n\n    @Parameter(key = UNLOAD_CLUSTER_RELATED)\n    public Boolean getUnloadClusterRelated() {\n        return unloadClusterRelated;\n    }\n\n    public void setUnloadClusterRelated(Boolean unloadClusterRelated) {\n        this.unloadClusterRelated = unloadClusterRelated;\n    }\n\n    @Transient\n    public ServiceMetadata getServiceMetadata() {\n        return serviceMetadata;\n    }\n\n    protected void resolveFile() {\n        String resolve = System.getProperty(interfaceName);\n        String resolveFile = null;\n        if (StringUtils.isEmpty(resolve)) {\n            resolveFile = SystemPropertyConfigUtils.getSystemProperty(CommonConstants.DubboProperty.DUBBO_RESOLVE_FILE);\n            if (StringUtils.isEmpty(resolveFile)) {\n                File userResolveFile = new File(\n                        new File(SystemPropertyConfigUtils.getSystemProperty(USER_HOME)), \"dubbo-resolve.properties\");\n                if (userResolveFile.exists()) {\n                    resolveFile = userResolveFile.getAbsolutePath();\n                }\n            }\n            if (resolveFile != null && resolveFile.length() > 0) {\n                Properties properties = new RegexProperties();\n                try (FileInputStream fis = new FileInputStream(resolveFile)) {\n                    properties.load(fis);\n                } catch (IOException e) {\n                    throw new IllegalStateException(\"Failed to load \" + resolveFile + \", cause: \" + e.getMessage(), e);\n                }\n\n                resolve = properties.getProperty(interfaceName);\n            }\n        }\n        if (StringUtils.isNotEmpty(resolve)) {\n            url = resolve;\n            if (logger.isWarnEnabled()) {\n                if (resolveFile != null) {\n                    logger.warn(\n                            COMMON_UNEXPECTED_EXCEPTION,\n                            \"\",\n                            \"\",\n                            \"Using default dubbo resolve file \" + resolveFile + \" replace \" + interfaceName + \"\"\n                                    + resolve + \" to p2p invoke remote service.\");\n                } else {\n                    logger.warn(\n                            COMMON_UNEXPECTED_EXCEPTION,\n                            \"\",\n                            \"\",\n                            \"Using -D\" + interfaceName + \"=\" + resolve + \" to p2p invoke remote service.\");\n                }\n            }\n        }\n    }\n\n    @Override\n    protected void computeValidRegistryIds() {\n        if (consumer != null && notHasSelfRegistryProperty()) {\n            setRegistries(consumer.getRegistries());\n            setRegistryIds(consumer.getRegistryIds());\n        }\n        super.computeValidRegistryIds();\n    }\n\n    @Parameter(excluded = true, attribute = false)\n    public String getUniqueServiceName() {\n        return interfaceName != null ? URL.buildKey(interfaceName, getGroup(), getVersion()) : null;\n    }\n\n    @Override\n    public String getVersion() {\n        return StringUtils.isEmpty(this.version)\n                ? (consumer != null ? consumer.getVersion() : this.version)\n                : this.version;\n    }\n\n    @Override\n    public String getGroup() {\n        return StringUtils.isEmpty(this.group) ? (consumer != null ? consumer.getGroup() : this.group) : this.group;\n    }\n\n    public Boolean shouldReferAsync() {\n        Boolean shouldReferAsync = getReferAsync();\n        if (shouldReferAsync == null) {\n            shouldReferAsync = consumer != null && consumer.getReferAsync() != null && consumer.getReferAsync();\n        }\n\n        return shouldReferAsync;\n    }\n\n    @Transient\n    public abstract T get(boolean check);\n\n    @Transient\n    public abstract void checkOrDestroy(long timeout);\n\n    @Transient\n    public final T get() {\n        return get(true);\n    }\n\n    public void destroy() {\n        getModuleConfigManager().removeConfig(this);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/RegistryConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.EXTRA_KEYS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;\nimport static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;\nimport static org.apache.dubbo.common.utils.PojoUtils.updatePropertyIfAbsent;\n\n/**\n * Configuration for service registration and discovery.\n *\n * @export\n */\npublic class RegistryConfig extends AbstractConfig {\n\n    private static final long serialVersionUID = 5508512956753757169L;\n\n    public static final String NO_AVAILABLE = \"N/A\";\n\n    /**\n     * Register center address.\n     */\n    private String address;\n\n    /**\n     * Username to login the register center.\n     */\n    private String username;\n\n    /**\n     * Password to login the register center.\n     */\n    private String password;\n\n    /**\n     * Default port for the register center.\n     */\n    private Integer port;\n\n    /**\n     * Protocol used for the register center.\n     */\n    private String protocol;\n\n    /**\n     * Network transmission type.\n     */\n    private String transporter;\n\n    /**\n     * Server implementation.\n     */\n    private String server;\n\n    /**\n     * Client implementation.\n     */\n    private String client;\n\n    /**\n     * Affects how traffic distributes among registries, useful when subscribing to multiple registries.\n     * Available options:\n     * - \"zone-aware\": A certain type of traffic always goes to one Registry according to where the traffic is originated.\n     */\n    private String cluster;\n\n    /**\n     * The region where the registry belongs, usually used to isolate traffics.\n     */\n    private String zone;\n\n    /**\n     * The group that services registry belongs to.\n     */\n    private String group;\n\n    /**\n     * Version of the registry.\n     */\n    private String version;\n\n    /**\n     * Connect timeout in milliseconds for the register center.\n     */\n    private Integer timeout;\n\n    /**\n     * Session timeout in milliseconds for the register center.\n     */\n    private Integer session;\n\n    /**\n     * File for saving the register center dynamic list.\n     */\n    private String file;\n\n    /**\n     * Wait time before stopping.\n     */\n    private Integer wait;\n\n    /**\n     * Whether to check if the register center is available when booting up.\n     */\n    private Boolean check;\n\n    /**\n     * Whether to allow dynamic service registration on the register center.\n     */\n    private Boolean dynamic;\n\n    /**\n     * Whether to allow exporting service on the register center.\n     */\n    private Boolean register;\n\n    /**\n     * Whether to allow subscribing to services on the register center.\n     */\n    private Boolean subscribe;\n\n    /**\n     * Customized parameters.\n     */\n    private Map<String, String> parameters;\n\n    /**\n     * Simplify the registry, useful for both providers and consumers.\n     *\n     * @since 2.7.0\n     */\n    private Boolean simplified;\n\n    /**\n     * After simplifying the registry, add some parameters individually, useful for providers.\n     * Example: extra-keys = \"A, b, c, d\".\n     *\n     * @since 2.7.0\n     */\n    private String extraKeys;\n\n    /**\n     * Indicates whether the address works as a configuration center or not.\n     */\n    private Boolean useAsConfigCenter;\n\n    /**\n     * Indicates whether the address works as a remote metadata center or not.\n     */\n    private Boolean useAsMetadataCenter;\n\n    /**\n     * List of RPC protocols accepted by this registry, e.g., \"dubbo,rest\".\n     */\n    private String accepts;\n\n    /**\n     * Always use this registry first if set to true, useful when subscribing to multiple registries.\n     */\n    private Boolean preferred;\n\n    /**\n     * Affects traffic distribution among registries, useful when subscribing to multiple registries.\n     * Takes effect only when no preferred registry is specified.\n     */\n    private Integer weight;\n\n    /**\n     * Register mode.\n     */\n    private String registerMode;\n\n    /**\n     * Enable empty protection.\n     */\n    private Boolean enableEmptyProtection;\n\n    /**\n     * Security settings.\n     */\n    private String secure;\n\n    public String getSecure() {\n        return secure;\n    }\n\n    public void setSecure(String secure) {\n        this.secure = secure;\n    }\n\n    public RegistryConfig() {}\n\n    public RegistryConfig(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    public RegistryConfig(String address) {\n        setAddress(address);\n    }\n\n    public RegistryConfig(ApplicationModel applicationModel, String address) {\n        super(applicationModel);\n        setAddress(address);\n    }\n\n    public RegistryConfig(String address, String protocol) {\n        setAddress(address);\n        setProtocol(protocol);\n    }\n\n    public RegistryConfig(ApplicationModel applicationModel, String address, String protocol) {\n        super(applicationModel);\n        setAddress(address);\n        setProtocol(protocol);\n    }\n\n    @Override\n    public String getId() {\n        return super.getId();\n    }\n\n    public String getProtocol() {\n        return protocol;\n    }\n\n    public void setProtocol(String protocol) {\n        this.protocol = protocol;\n    }\n\n    @Parameter(excluded = true)\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n        if (address != null) {\n            try {\n                URL url = URL.valueOf(address);\n\n                // Refactor since 2.7.8\n                updatePropertyIfAbsent(this::getUsername, this::setUsername, url.getUsername());\n                updatePropertyIfAbsent(this::getPassword, this::setPassword, url.getPassword());\n                updatePropertyIfAbsent(this::getProtocol, this::setProtocol, url.getProtocol());\n                updatePropertyIfAbsent(this::getPort, this::setPort, url.getPort());\n\n                Map<String, String> params = url.getParameters();\n                if (CollectionUtils.isNotEmptyMap(params)) {\n                    params.remove(BACKUP_KEY);\n                }\n                updateParameters(params);\n            } catch (Exception ignored) {\n            }\n        }\n    }\n\n    public Integer getPort() {\n        return port;\n    }\n\n    public void setPort(Integer port) {\n        this.port = port;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    /**\n     * @return wait\n     * @see org.apache.dubbo.config.ProviderConfig#getWait()\n     * @deprecated\n     */\n    @Deprecated\n    public Integer getWait() {\n        return wait;\n    }\n\n    /**\n     * @param wait\n     * @see org.apache.dubbo.config.ProviderConfig#setWait(Integer)\n     * @deprecated\n     */\n    @Deprecated\n    public void setWait(Integer wait) {\n        this.wait = wait;\n        if (wait != null && wait > 0) {\n            System.setProperty(SHUTDOWN_WAIT_KEY, String.valueOf(wait));\n        }\n    }\n\n    public Boolean isCheck() {\n        return check;\n    }\n\n    public void setCheck(Boolean check) {\n        this.check = check;\n    }\n\n    public String getFile() {\n        return file;\n    }\n\n    public void setFile(String file) {\n        this.file = file;\n    }\n\n    /**\n     * @return transport\n     * @see #getTransporter()\n     * @deprecated\n     */\n    @Deprecated\n    @Parameter(excluded = true, attribute = false)\n    public String getTransport() {\n        return getTransporter();\n    }\n\n    /**\n     * @param transport\n     * @see #setTransporter(String)\n     * @deprecated\n     */\n    @Deprecated\n    public void setTransport(String transport) {\n        setTransporter(transport);\n    }\n\n    public String getTransporter() {\n        return transporter;\n    }\n\n    public void setTransporter(String transporter) {\n        /*if(transporter != null && transporter.length() > 0 && ! this.getExtensionLoader(Transporter.class).hasExtension(transporter)){\n            throw new IllegalStateException(\"No such transporter type : \" + transporter);\n        }*/\n        this.transporter = transporter;\n    }\n\n    public String getServer() {\n        return server;\n    }\n\n    public void setServer(String server) {\n        /*if(server != null && server.length() > 0 && ! this.getExtensionLoader(Transporter.class).hasExtension(server)){\n            throw new IllegalStateException(\"No such server type : \" + server);\n        }*/\n        this.server = server;\n    }\n\n    public String getClient() {\n        return client;\n    }\n\n    public void setClient(String client) {\n        /*if(client != null && client.length() > 0 && ! this.getExtensionLoader(Transporter.class).hasExtension(client)){\n            throw new IllegalStateException(\"No such client type : \" + client);\n        }*/\n        this.client = client;\n    }\n\n    public Integer getTimeout() {\n        return timeout;\n    }\n\n    public void setTimeout(Integer timeout) {\n        this.timeout = timeout;\n    }\n\n    public Integer getSession() {\n        return session;\n    }\n\n    public void setSession(Integer session) {\n        this.session = session;\n    }\n\n    public Boolean isDynamic() {\n        return dynamic;\n    }\n\n    public void setDynamic(Boolean dynamic) {\n        this.dynamic = dynamic;\n    }\n\n    public Boolean isRegister() {\n        return register;\n    }\n\n    public void setRegister(Boolean register) {\n        this.register = register;\n    }\n\n    public Boolean isSubscribe() {\n        return subscribe;\n    }\n\n    public void setSubscribe(Boolean subscribe) {\n        this.subscribe = subscribe;\n    }\n\n    public String getCluster() {\n        return cluster;\n    }\n\n    public void setCluster(String cluster) {\n        this.cluster = cluster;\n    }\n\n    public String getZone() {\n        return zone;\n    }\n\n    public void setZone(String zone) {\n        this.zone = zone;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    public Map<String, String> getParameters() {\n        return parameters;\n    }\n\n    public void setParameters(Map<String, String> parameters) {\n        this.parameters = parameters;\n    }\n\n    public void updateParameters(Map<String, String> parameters) {\n        if (CollectionUtils.isEmptyMap(parameters)) {\n            return;\n        }\n        if (this.parameters == null) {\n            this.parameters = parameters;\n        } else {\n            this.parameters.putAll(parameters);\n        }\n    }\n\n    public Boolean getSimplified() {\n        return simplified;\n    }\n\n    public void setSimplified(Boolean simplified) {\n        this.simplified = simplified;\n    }\n\n    @Parameter(key = EXTRA_KEYS_KEY)\n    public String getExtraKeys() {\n        return extraKeys;\n    }\n\n    public void setExtraKeys(String extraKeys) {\n        this.extraKeys = extraKeys;\n    }\n\n    @Parameter(excluded = true)\n    public Boolean getUseAsConfigCenter() {\n        return useAsConfigCenter;\n    }\n\n    public void setUseAsConfigCenter(Boolean useAsConfigCenter) {\n        this.useAsConfigCenter = useAsConfigCenter;\n    }\n\n    @Parameter(excluded = true)\n    public Boolean getUseAsMetadataCenter() {\n        return useAsMetadataCenter;\n    }\n\n    public void setUseAsMetadataCenter(Boolean useAsMetadataCenter) {\n        this.useAsMetadataCenter = useAsMetadataCenter;\n    }\n\n    public String getAccepts() {\n        return accepts;\n    }\n\n    public void setAccepts(String accepts) {\n        this.accepts = accepts;\n    }\n\n    public Boolean getPreferred() {\n        return preferred;\n    }\n\n    public void setPreferred(Boolean preferred) {\n        this.preferred = preferred;\n    }\n\n    public Integer getWeight() {\n        return weight;\n    }\n\n    public void setWeight(Integer weight) {\n        this.weight = weight;\n    }\n\n    @Parameter(key = REGISTER_MODE_KEY)\n    public String getRegisterMode() {\n        return registerMode;\n    }\n\n    public void setRegisterMode(String registerMode) {\n        this.registerMode = registerMode;\n    }\n\n    @Parameter(key = ENABLE_EMPTY_PROTECTION_KEY)\n    public Boolean getEnableEmptyProtection() {\n        return enableEmptyProtection;\n    }\n\n    public void setEnableEmptyProtection(Boolean enableEmptyProtection) {\n        this.enableEmptyProtection = enableEmptyProtection;\n    }\n\n    @Override\n    @Parameter(excluded = true, attribute = false)\n    public boolean isValid() {\n        // empty protocol will default to 'dubbo'\n        return !StringUtils.isEmpty(address) || !StringUtils.isEmpty(protocol);\n    }\n\n    @Override\n    @Parameter(excluded = true)\n    public Boolean isDefault() {\n        return isDefault;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.constants.RegisterTypeEnum;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.context.ConfigMode;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\nimport org.apache.dubbo.rpc.service.GenericService;\nimport org.apache.dubbo.rpc.support.ProtocolUtils;\n\nimport java.beans.Transient;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO;\n\n/**\n * Base configuration for service.\n *\n * @export\n */\n@SuppressWarnings({\"rawtypes\", \"deprecation\"})\npublic abstract class ServiceConfigBase<T> extends AbstractServiceConfig {\n\n    private static final long serialVersionUID = 3033787999037024738L;\n\n    /**\n     * The interface class of the exported service.\n     */\n    protected Class<?> interfaceClass;\n\n    /**\n     * The reference to the interface implementation.\n     */\n    protected transient T ref;\n\n    /**\n     * The service name, which is used to uniquely identify the service.\n     */\n    protected String path;\n\n    /**\n     * The provider configuration for this service.\n     */\n    protected ProviderConfig provider;\n\n    /**\n     * A comma-separated list of provider IDs.\n     */\n    protected String providerIds;\n\n    /**\n     * Indicates whether the service is a GenericService.\n     * If set, this means that the service is a generic service that can handle multiple types.\n     */\n    protected volatile String generic;\n\n    public ServiceConfigBase() {\n        serviceMetadata = new ServiceMetadata();\n        serviceMetadata.addAttribute(\"ORIGIN_CONFIG\", this);\n    }\n\n    public ServiceConfigBase(ModuleModel moduleModel) {\n        super(moduleModel);\n        serviceMetadata = new ServiceMetadata();\n        serviceMetadata.addAttribute(\"ORIGIN_CONFIG\", this);\n    }\n\n    public ServiceConfigBase(Service service) {\n        serviceMetadata = new ServiceMetadata();\n        serviceMetadata.addAttribute(\"ORIGIN_CONFIG\", this);\n        appendAnnotation(Service.class, service);\n        setMethods(MethodConfig.constructMethodConfig(service.methods()));\n    }\n\n    public ServiceConfigBase(ModuleModel moduleModel, Service service) {\n        super(moduleModel);\n        serviceMetadata = new ServiceMetadata();\n        serviceMetadata.addAttribute(\"ORIGIN_CONFIG\", this);\n        appendAnnotation(Service.class, service);\n        setMethods(MethodConfig.constructMethodConfig(service.methods()));\n    }\n\n    @Override\n    public void setProtocols(List<? extends ProtocolConfig> protocols) {\n        super.setProtocols(protocols);\n        checkInterface();\n    }\n\n    @Override\n    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {\n        super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);\n        if (this.provider != null && this.provider.getScopeModel() != getScopeModel()) {\n            this.provider.setScopeModel(getScopeModel());\n        }\n    }\n\n    public boolean shouldExport() {\n        Boolean export = getExport();\n        // default value is true\n        return export == null || export;\n    }\n\n    @Override\n    public Boolean getExport() {\n        return (export == null && provider != null) ? provider.getExport() : export;\n    }\n\n    public boolean shouldDelay() {\n        Integer delay = getDelay();\n        return delay != null && delay > 0;\n    }\n\n    @Override\n    public Integer getDelay() {\n        return (delay == null && provider != null) ? provider.getDelay() : delay;\n    }\n\n    protected void checkRef() {\n        // reference should not be null, and is the implementation of the given interface\n        if (ref == null) {\n            throw new IllegalStateException(\"ref not allow null!\");\n        }\n        if (!interfaceClass.isInstance(ref)) {\n            throw new IllegalStateException(\"The class \"\n                    + getClassDesc(ref.getClass()) + \" unimplemented interface \"\n                    + getClassDesc(interfaceClass) + \"!\");\n        }\n    }\n\n    private String getClassDesc(Class clazz) {\n        ClassLoader classLoader = clazz.getClassLoader();\n        return clazz.getName() + \"[classloader=\" + classLoader.getClass().getName() + \"@\" + classLoader.hashCode()\n                + \"]\";\n    }\n\n    public Optional<String> getContextPath(ProtocolConfig protocolConfig) {\n        String contextPath = protocolConfig.getContextpath();\n        if (StringUtils.isEmpty(contextPath) && provider != null) {\n            contextPath = provider.getContextpath();\n        }\n        return Optional.ofNullable(contextPath);\n    }\n\n    protected Class getServiceClass(T ref) {\n        return ref.getClass();\n    }\n\n    @Override\n    protected void preProcessRefresh() {\n        super.preProcessRefresh();\n        convertProviderIdToProvider();\n        if (provider == null) {\n            provider = getModuleConfigManager()\n                    .getDefaultProvider()\n                    .orElseThrow(() -> new IllegalStateException(\"Default provider is not initialized\"));\n        }\n        // try set properties from `dubbo.service` if not set in current config\n        refreshWithPrefixes(super.getPrefixes(), ConfigMode.OVERRIDE_IF_ABSENT);\n    }\n\n    @Override\n    @Transient\n    public Map<String, String> getMetaData() {\n        return getMetaData(null);\n    }\n\n    @Override\n    public Map<String, String> getMetaData(String prefix) {\n        Map<String, String> metaData = new HashMap<>();\n        ProviderConfig provider = this.getProvider();\n        // provider should be initialized at preProcessRefresh()\n        if (isRefreshed() && provider == null) {\n            throw new IllegalStateException(\"Provider is not initialized\");\n        }\n        // use provider attributes as default value\n        appendAttributes(metaData, provider, prefix);\n        // Finally, put the service's attributes, overriding previous attributes\n        appendAttributes(metaData, this, prefix);\n        return metaData;\n    }\n\n    protected void checkProtocol() {\n        if (provider != null && notHasSelfProtocolProperty()) {\n            setProtocols(provider.getProtocols());\n            setProtocolIds(provider.getProtocolIds());\n        }\n        convertProtocolIdsToProtocols();\n    }\n\n    private boolean notHasSelfProtocolProperty() {\n        return CollectionUtils.isEmpty(protocols) && StringUtils.isEmpty(protocolIds);\n    }\n\n    protected void completeCompoundConfigs() {\n        completeCompoundConfigs(provider);\n        if (provider != null) {\n            if (notHasSelfProtocolProperty()) {\n                setProtocols(provider.getProtocols());\n                setProtocolIds(provider.getProtocolIds());\n            }\n            if (configCenter == null) {\n                setConfigCenter(provider.getConfigCenter());\n            }\n        }\n    }\n\n    protected void convertProviderIdToProvider() {\n        if (provider == null && StringUtils.hasText(providerIds)) {\n            provider = getModuleConfigManager()\n                    .getProvider(providerIds)\n                    .orElseThrow(() -> new IllegalStateException(\"Provider config not found: \" + providerIds));\n        }\n    }\n\n    protected void convertProtocolIdsToProtocols() {\n        if (StringUtils.isEmpty(protocolIds)) {\n            if (CollectionUtils.isEmpty(protocols)) {\n                List<ProtocolConfig> protocolConfigs = getConfigManager().getDefaultProtocols();\n                if (CollectionUtils.isEmpty(protocolConfigs)) {\n                    throw new IllegalStateException(\"The default protocol has not been initialized.\");\n                }\n                setProtocols(protocolConfigs);\n            }\n        } else {\n            String[] idsArray = COMMA_SPLIT_PATTERN.split(protocolIds);\n            Set<String> idsSet = new LinkedHashSet<>(Arrays.asList(idsArray));\n            List<ProtocolConfig> tmpProtocols = new ArrayList<>();\n            for (String id : idsSet) {\n                Optional<ProtocolConfig> globalProtocol = getConfigManager().getProtocol(id);\n                if (globalProtocol.isPresent()) {\n                    tmpProtocols.add(globalProtocol.get());\n                } else {\n                    throw new IllegalStateException(\"Protocol not found: \" + id);\n                }\n            }\n            setProtocols(tmpProtocols);\n        }\n    }\n\n    public Class<?> getInterfaceClass() {\n        if (interfaceClass != null) {\n            return interfaceClass;\n        }\n        if (ref instanceof GenericService) {\n            return GenericService.class;\n        }\n        try {\n            if (StringUtils.isNotEmpty(interfaceName)) {\n                interfaceClass = Class.forName(\n                        interfaceName, true, Thread.currentThread().getContextClassLoader());\n            }\n        } catch (ClassNotFoundException t) {\n            throw new IllegalStateException(t.getMessage(), t);\n        }\n        return interfaceClass;\n    }\n\n    /**\n     * @see #setInterface(Class)\n     * @deprecated\n     */\n    public void setInterfaceClass(Class<?> interfaceClass) {\n        setInterface(interfaceClass);\n    }\n\n    public void setInterface(Class<?> interfaceClass) {\n        this.interfaceClass = interfaceClass;\n        checkInterface();\n        setInterface(interfaceClass == null ? null : interfaceClass.getName());\n        if (getInterfaceClassLoader() == null) {\n            setInterfaceClassLoader(interfaceClass == null ? null : interfaceClass.getClassLoader());\n        }\n    }\n\n    @Override\n    public void checkInterface() {\n        if (interfaceClass == null || interfaceClass.isInterface()) {\n            return;\n        }\n        List<ProtocolConfig> protocols = getProtocols();\n        if (CollectionUtils.isEmpty(protocols)) {\n            return;\n        }\n        for (ProtocolConfig protocol : protocols) {\n            String name = protocol.getName();\n            if (CommonConstants.TRIPLE.equals(name) && Boolean.TRUE.equals(protocol.isNoInterfaceSupport())) {\n                return;\n            }\n            if (Constants.REST_PROTOCOL.equals(name)) {\n                return;\n            }\n        }\n        throw new IllegalStateException(\"The interface class \" + interfaceClass + \" is not a interface!\");\n    }\n\n    @Transient\n    public T getRef() {\n        return ref;\n    }\n\n    public void setRef(T ref) {\n        this.ref = ref;\n    }\n\n    @Parameter(excluded = true)\n    public String getPath() {\n        return path;\n    }\n\n    public void setPath(String path) {\n        this.path = path;\n    }\n\n    public ProviderConfig getProvider() {\n        return provider;\n    }\n\n    public void setProvider(ProviderConfig provider) {\n        getModuleConfigManager().addProvider(provider);\n        this.provider = provider;\n    }\n\n    @Parameter(excluded = true)\n    public String getProviderIds() {\n        return providerIds;\n    }\n\n    public void setProviderIds(String providerIds) {\n        this.providerIds = providerIds;\n    }\n\n    public String getGeneric() {\n        return generic;\n    }\n\n    public void setGeneric(String generic) {\n        if (StringUtils.isEmpty(generic)) {\n            return;\n        }\n        if (ProtocolUtils.isValidGenericValue(generic)) {\n            this.generic = generic;\n        } else {\n            throw new IllegalArgumentException(\"Unsupported generic type \" + generic);\n        }\n    }\n\n    @Transient\n    public ServiceMetadata getServiceMetadata() {\n        return serviceMetadata;\n    }\n\n    @Override\n    @Transient\n    @Parameter(excluded = true, attribute = false)\n    public List<String> getPrefixes() {\n        List<String> prefixes = new ArrayList<>();\n        // dubbo.service.{interface-name}\n        prefixes.add(DUBBO + \".service.\" + interfaceName);\n        return prefixes;\n    }\n\n    @Parameter(excluded = true, attribute = false)\n    public String getUniqueServiceName() {\n        return interfaceName != null ? URL.buildKey(interfaceName, getGroup(), getVersion()) : null;\n    }\n\n    @Override\n    public String getGroup() {\n        return StringUtils.isEmpty(this.group) ? (provider != null ? provider.getGroup() : this.group) : this.group;\n    }\n\n    @Override\n    public String getVersion() {\n        return StringUtils.isEmpty(this.version)\n                ? (provider != null ? provider.getVersion() : this.version)\n                : this.version;\n    }\n\n    @Override\n    protected void computeValidRegistryIds() {\n        if (provider != null && notHasSelfRegistryProperty()) {\n            setRegistries(provider.getRegistries());\n            setRegistryIds(provider.getRegistryIds());\n        }\n        super.computeValidRegistryIds();\n    }\n\n    public Boolean shouldExportAsync() {\n        Boolean shouldExportAsync = getExportAsync();\n        if (shouldExportAsync == null) {\n            shouldExportAsync = provider != null && provider.getExportAsync() != null && provider.getExportAsync();\n        }\n\n        return shouldExportAsync;\n    }\n\n    /**\n     * export service and auto start application instance\n     */\n    public final void export() {\n        export(RegisterTypeEnum.AUTO_REGISTER);\n    }\n\n    public abstract void unexport();\n\n    public abstract boolean isExported();\n\n    public abstract boolean isUnexported();\n\n    /**\n     * Export service to network\n     *\n     * @param registerType register type of current export action.\n     */\n    public abstract void export(RegisterTypeEnum registerType);\n\n    /**\n     * Register delay published service to registry.\n     */\n    public final void register() {\n        register(false);\n    }\n\n    /**\n     * Register delay published service to registry.\n     *\n     * @param byDeployer register by deployer or not.\n     */\n    public abstract void register(boolean byDeployer);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/SslConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.IOUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.beans.Transient;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Configuration for ssl.\n *\n * @export\n */\npublic class SslConfig extends AbstractConfig {\n\n    private static final long serialVersionUID = 4072725016922915851L;\n\n    public static final String SERVER_KEY_CERT_CHAIN_PATH = \"server-key-cert-chain-path\";\n\n    public static final String SERVER_PRIVATE_KEY_PATH = \"server-private-key-path\";\n\n    public static final String SERVER_KEY_PASSWORD = \"server-key-password\";\n\n    public static final String SERVER_TRUST_CERT_COLLECTION_PATH = \"server-trust-cert-collection-path\";\n\n    public static final String CLIENT_KEY_CERT_CHAIN_PATH = \"client-key-cert-chain-path\";\n\n    public static final String CLIENT_PRIVATE_KEY_PATH = \"client-private-key-path\";\n\n    public static final String CLIENT_KEY_PASSWORD = \"client-key-password\";\n\n    public static final String CLIENT_TRUST_CERT_COLLECTION_PATH = \"client-trust-cert-collection-path\";\n\n    /**\n     * Path to the server's key certificate chain file.\n     */\n    private String serverKeyCertChainPath;\n\n    /**\n     * Path to the server's private key file.\n     */\n    private String serverPrivateKeyPath;\n\n    /**\n     * Password for the server's private key (if applicable).\n     */\n    private String serverKeyPassword;\n\n    /**\n     * Path to the server's trust certificate collection file.\n     */\n    private String serverTrustCertCollectionPath;\n\n    /**\n     * Path to the client's key certificate chain file.\n     */\n    private String clientKeyCertChainPath;\n\n    /**\n     * Path to the client's private key file.\n     */\n    private String clientPrivateKeyPath;\n\n    /**\n     * Password for the client's private key (if applicable).\n     */\n    private String clientKeyPassword;\n\n    /**\n     * Path to the client's trust certificate collection file.\n     */\n    private String clientTrustCertCollectionPath;\n\n    /**\n     * Input stream for the server's key certificate chain (if provided).\n     */\n    private InputStream serverKeyCertChainPathStream;\n\n    /**\n     * Input stream for the server's private key (if provided).\n     */\n    private InputStream serverPrivateKeyPathStream;\n\n    /**\n     * Input stream for the server's trust certificate collection (if provided).\n     */\n    private InputStream serverTrustCertCollectionPathStream;\n\n    /**\n     * Input stream for the client's key certificate chain (if provided).\n     */\n    private InputStream clientKeyCertChainPathStream;\n\n    /**\n     * Input stream for the client's private key (if provided).\n     */\n    private InputStream clientPrivateKeyPathStream;\n\n    /**\n     * Input stream for the client's trust certificate collection (if provided).\n     */\n    private InputStream clientTrustCertCollectionPathStream;\n\n    /**\n     * Address for Certificate Authority (CA).\n     */\n    private String caAddress;\n\n    /**\n     * Environment type for SSL configuration.\n     */\n    private String envType;\n\n    /**\n     * Path to the CA certificate file.\n     */\n    private String caCertPath;\n\n    /**\n     * Path to the OIDC (OpenID Connect) token file.\n     */\n    private String oidcTokenPath;\n\n    public SslConfig() {}\n\n    public SslConfig(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    @Parameter(key = SERVER_KEY_CERT_CHAIN_PATH)\n    public String getServerKeyCertChainPath() {\n        return serverKeyCertChainPath;\n    }\n\n    public void setServerKeyCertChainPath(String serverKeyCertChainPath) {\n        this.serverKeyCertChainPath = serverKeyCertChainPath;\n    }\n\n    @Parameter(key = SERVER_PRIVATE_KEY_PATH)\n    public String getServerPrivateKeyPath() {\n        return serverPrivateKeyPath;\n    }\n\n    public void setServerPrivateKeyPath(String serverPrivateKeyPath) {\n        this.serverPrivateKeyPath = serverPrivateKeyPath;\n    }\n\n    @Parameter(key = SERVER_KEY_PASSWORD)\n    public String getServerKeyPassword() {\n        return serverKeyPassword;\n    }\n\n    public void setServerKeyPassword(String serverKeyPassword) {\n        this.serverKeyPassword = serverKeyPassword;\n    }\n\n    @Parameter(key = SERVER_TRUST_CERT_COLLECTION_PATH)\n    public String getServerTrustCertCollectionPath() {\n        return serverTrustCertCollectionPath;\n    }\n\n    public void setServerTrustCertCollectionPath(String serverTrustCertCollectionPath) {\n        this.serverTrustCertCollectionPath = serverTrustCertCollectionPath;\n    }\n\n    @Parameter(key = CLIENT_KEY_CERT_CHAIN_PATH)\n    public String getClientKeyCertChainPath() {\n        return clientKeyCertChainPath;\n    }\n\n    public void setClientKeyCertChainPath(String clientKeyCertChainPath) {\n        this.clientKeyCertChainPath = clientKeyCertChainPath;\n    }\n\n    @Parameter(key = CLIENT_PRIVATE_KEY_PATH)\n    public String getClientPrivateKeyPath() {\n        return clientPrivateKeyPath;\n    }\n\n    public void setClientPrivateKeyPath(String clientPrivateKeyPath) {\n        this.clientPrivateKeyPath = clientPrivateKeyPath;\n    }\n\n    @Parameter(key = CLIENT_KEY_PASSWORD)\n    public String getClientKeyPassword() {\n        return clientKeyPassword;\n    }\n\n    public void setClientKeyPassword(String clientKeyPassword) {\n        this.clientKeyPassword = clientKeyPassword;\n    }\n\n    @Parameter(key = CLIENT_TRUST_CERT_COLLECTION_PATH)\n    public String getClientTrustCertCollectionPath() {\n        return clientTrustCertCollectionPath;\n    }\n\n    public void setClientTrustCertCollectionPath(String clientTrustCertCollectionPath) {\n        this.clientTrustCertCollectionPath = clientTrustCertCollectionPath;\n    }\n\n    public String getCaAddress() {\n        return caAddress;\n    }\n\n    public void setCaAddress(String caAddress) {\n        this.caAddress = caAddress;\n    }\n\n    public String getEnvType() {\n        return envType;\n    }\n\n    public void setEnvType(String envType) {\n        this.envType = envType;\n    }\n\n    public String getCaCertPath() {\n        return caCertPath;\n    }\n\n    public void setCaCertPath(String caCertPath) {\n        this.caCertPath = caCertPath;\n    }\n\n    public String getOidcTokenPath() {\n        return oidcTokenPath;\n    }\n\n    public void setOidcTokenPath(String oidcTokenPath) {\n        this.oidcTokenPath = oidcTokenPath;\n    }\n\n    @Transient\n    public InputStream getServerKeyCertChainPathStream() throws IOException {\n        if (serverKeyCertChainPath != null) {\n            serverKeyCertChainPathStream =\n                    IOUtils.getURL(serverKeyCertChainPath).openStream();\n        }\n        return serverKeyCertChainPathStream;\n    }\n\n    public void setServerKeyCertChainPathStream(InputStream serverKeyCertChainPathStream) {\n        this.serverKeyCertChainPathStream = serverKeyCertChainPathStream;\n    }\n\n    @Transient\n    public InputStream getServerPrivateKeyPathStream() throws IOException {\n        if (serverPrivateKeyPath != null) {\n            serverPrivateKeyPathStream = IOUtils.getURL(serverPrivateKeyPath).openStream();\n        }\n        return serverPrivateKeyPathStream;\n    }\n\n    public void setServerPrivateKeyPathStream(InputStream serverPrivateKeyPathStream) {\n        this.serverPrivateKeyPathStream = serverPrivateKeyPathStream;\n    }\n\n    @Transient\n    public InputStream getServerTrustCertCollectionPathStream() throws IOException {\n        if (serverTrustCertCollectionPath != null) {\n            serverTrustCertCollectionPathStream =\n                    IOUtils.getURL(serverTrustCertCollectionPath).openStream();\n        }\n        return serverTrustCertCollectionPathStream;\n    }\n\n    public void setServerTrustCertCollectionPathStream(InputStream serverTrustCertCollectionPathStream) {\n        this.serverTrustCertCollectionPathStream = serverTrustCertCollectionPathStream;\n    }\n\n    @Transient\n    public InputStream getClientKeyCertChainPathStream() throws IOException {\n        if (clientKeyCertChainPath != null) {\n            clientKeyCertChainPathStream =\n                    IOUtils.getURL(clientKeyCertChainPath).openStream();\n        }\n        return clientKeyCertChainPathStream;\n    }\n\n    public void setClientKeyCertChainPathStream(InputStream clientKeyCertChainPathStream) {\n        this.clientKeyCertChainPathStream = clientKeyCertChainPathStream;\n    }\n\n    @Transient\n    public InputStream getClientPrivateKeyPathStream() throws IOException {\n        if (clientPrivateKeyPath != null) {\n            clientPrivateKeyPathStream = IOUtils.getURL(clientPrivateKeyPath).openStream();\n        }\n        return clientPrivateKeyPathStream;\n    }\n\n    public void setClientPrivateKeyPathStream(InputStream clientPrivateKeyPathStream) {\n        this.clientPrivateKeyPathStream = clientPrivateKeyPathStream;\n    }\n\n    @Transient\n    public InputStream getClientTrustCertCollectionPathStream() throws IOException {\n        if (clientTrustCertCollectionPath != null) {\n            clientTrustCertCollectionPathStream =\n                    IOUtils.getURL(clientTrustCertCollectionPath).openStream();\n        }\n        return clientTrustCertCollectionPathStream;\n    }\n\n    public void setClientTrustCertCollectionPathStream(InputStream clientTrustCertCollectionPathStream) {\n        this.clientTrustCertCollectionPathStream = clientTrustCertCollectionPathStream;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/TracingConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.config.nested.BaggageConfig;\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.config.nested.PropagationConfig;\nimport org.apache.dubbo.config.nested.SamplingConfig;\nimport org.apache.dubbo.config.support.Nested;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\n/**\n * Configuration for tracing.\n */\npublic class TracingConfig extends AbstractConfig {\n\n    private static final long serialVersionUID = -9089919311611546383L;\n\n    /**\n     * Indicates whether the feature is enabled (default is false).\n     */\n    private Boolean enabled = false;\n\n    /**\n     * Configuration for sampling.\n     */\n    @Nested\n    private SamplingConfig sampling = new SamplingConfig();\n\n    /**\n     * Configuration for baggage.\n     */\n    @Nested\n    private BaggageConfig baggage = new BaggageConfig();\n\n    /**\n     * Configuration for propagation.\n     */\n    @Nested\n    private PropagationConfig propagation = new PropagationConfig();\n\n    /**\n     * Configuration for the tracing exporter.\n     */\n    @Nested\n    private ExporterConfig tracingExporter = new ExporterConfig();\n\n    public TracingConfig() {}\n\n    public TracingConfig(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public SamplingConfig getSampling() {\n        return sampling;\n    }\n\n    public void setSampling(SamplingConfig sampling) {\n        this.sampling = sampling;\n    }\n\n    public BaggageConfig getBaggage() {\n        return baggage;\n    }\n\n    public void setBaggage(BaggageConfig baggage) {\n        this.baggage = baggage;\n    }\n\n    public PropagationConfig getPropagation() {\n        return propagation;\n    }\n\n    public void setPropagation(PropagationConfig propagation) {\n        this.propagation = propagation;\n    }\n\n    public ExporterConfig getTracingExporter() {\n        return tracingExporter;\n    }\n\n    public void setTracingExporter(ExporterConfig tracingExporter) {\n        this.tracingExporter = tracingExporter;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/annotation/Argument.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @since 2.6.5\n *\n * 2018/9/29\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.ANNOTATION_TYPE})\n@Inherited\npublic @interface Argument {\n    // argument: index -1 represents not set\n    int index() default -1;\n\n    // argument type\n    String type() default \"\";\n\n    // callback interface\n    boolean callback() default false;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/annotation/DubboReference.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.annotation;\n\nimport org.apache.dubbo.common.constants.ClusterRules;\nimport org.apache.dubbo.common.constants.LoadbalanceRules;\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.config.AbstractReferenceConfig;\nimport org.apache.dubbo.config.ReferenceConfigBase;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * An annotation used for referencing a Dubbo service.\n * <p>\n * <b>It is recommended to use @DubboReference on the @Bean method in the Java-config class, but not on the fields or setter methods to be injected.</b>\n * </p>\n * <p>\n * Step 1: Register ReferenceBean in Java-config class:\n * <pre class=\"code\">\n * &#64;Configuration\n * public class ReferenceConfiguration {\n *     &#64;Bean\n *     &#64;DubboReference(group = \"demo\")\n *     public ReferenceBean&lt;HelloService&gt; helloService() {\n *         return new ReferenceBean();\n *     }\n *\n *     &#64;Bean\n *     &#64;DubboReference(group = \"demo\", interfaceClass = HelloService.class)\n *     public ReferenceBean&lt;GenericService&gt; genericHelloService() {\n *         return new ReferenceBean();\n *     }\n * }\n * </pre>\n * <p>\n * Step 2: Inject ReferenceBean by @Autowired\n * <pre class=\"code\">\n * public class FooController {\n *     &#64;Autowired\n *     private HelloService helloService;\n *\n *     &#64;Autowired\n *     private GenericService genericHelloService;\n * }\n * </pre>\n *\n * @see org.apache.dubbo.config.spring.reference.ReferenceBeanBuilder\n * @see org.apache.dubbo.config.spring.ReferenceBean\n * @since 2.7.7\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})\npublic @interface DubboReference {\n\n    /**\n     * Interface class, default value is void.class\n     */\n    Class<?> interfaceClass() default void.class;\n\n    /**\n     * Interface class name, default value is empty string\n     */\n    String interfaceName() default \"\";\n\n    /**\n     * Service version, default value is empty string\n     */\n    String version() default \"\";\n\n    /**\n     * Service group, default value is empty string\n     */\n    String group() default \"\";\n\n    /**\n     * Service target URL for direct invocation, if this is specified, then registry center takes no effect.\n     */\n    String url() default \"\";\n\n    /**\n     * Client transport type, default value is \"netty\"\n     */\n    String client() default \"\";\n\n    /**\n     * Whether to enable generic invocation, default value is false\n     *\n     * @deprecated Do not need specify generic value, judge by injection type and interface class\n     */\n    @Deprecated\n    boolean generic() default false;\n\n    /**\n     * When enable, prefer to call local service in the same JVM if it's present, default value is true\n     *\n     * @deprecated using scope=\"local\" or scope=\"remote\" instead\n     */\n    @Deprecated\n    boolean injvm() default true;\n\n    /**\n     * Check if service provider is available during boot up, default value is true\n     */\n    boolean check() default true;\n\n    /**\n     * Whether eager initialize the reference bean when all properties are set, default value is true ( null as true)\n     *\n     * @see ReferenceConfigBase#shouldInit()\n     */\n    boolean init() default true;\n\n    /**\n     * Whether to make connection when the client is created, the default value is false\n     */\n    boolean lazy() default false;\n\n    /**\n     * Export an stub service for event dispatch, default value is false.\n     * <p>\n     * see org.apache.dubbo.rpc.Constants#STUB_EVENT_METHODS_KEY\n     */\n    boolean stubevent() default false;\n\n    /**\n     * Whether to reconnect if connection is lost, if not specify, reconnect is enabled by default, and the interval\n     * for retry connecting is 2000 ms\n     * <p>\n     * see org.apache.dubbo.remoting.Constants#DEFAULT_RECONNECT_PERIOD\n     */\n    String reconnect() default \"\";\n\n    /**\n     * Whether to stick to the same node in the cluster, the default value is false\n     * <p>\n     * see Constants#DEFAULT_CLUSTER_STICKY\n     */\n    boolean sticky() default false;\n\n    /**\n     * How the proxy is generated, legal values include: jdk, javassist\n     */\n    String proxy() default \"\";\n\n    /**\n     * Service stub name, use interface name + Stub if not set\n     */\n    String stub() default \"\";\n\n    /**\n     * Cluster strategy, legal values include: failover, failfast, failsafe, failback, forking\n     * you can use {@link org.apache.dubbo.common.constants.ClusterRules#FAIL_FAST} ……\n     */\n    String cluster() default ClusterRules.EMPTY;\n\n    /**\n     * Maximum connections service provider can accept, default value is 0 - connection is shared\n     */\n    int connections() default -1;\n\n    /**\n     * The callback instance limit peer connection\n     * <p>\n     * see org.apache.dubbo.rpc.Constants#DEFAULT_CALLBACK_INSTANCES\n     */\n    int callbacks() default -1;\n\n    /**\n     * Callback method name when connected, default value is empty string\n     */\n    String onconnect() default \"\";\n\n    /**\n     * Callback method name when disconnected, default value is empty string\n     */\n    String ondisconnect() default \"\";\n\n    /**\n     * Service owner, default value is empty string\n     */\n    String owner() default \"\";\n\n    /**\n     * Service layer, default value is empty string\n     */\n    String layer() default \"\";\n\n    /**\n     * Service invocation retry times\n     * <p>\n     * see Constants#DEFAULT_RETRIES\n     */\n    int retries() default -1;\n\n    /**\n     * Load balance strategy, legal values include: random, roundrobin, leastactive\n     * you can use {@link org.apache.dubbo.common.constants.LoadbalanceRules#RANDOM} ……\n     */\n    String loadbalance() default LoadbalanceRules.EMPTY;\n\n    /**\n     * Whether to enable async invocation, default value is false\n     */\n    boolean async() default false;\n\n    /**\n     * Maximum active requests allowed, default value is 0\n     */\n    int actives() default -1;\n\n    /**\n     * Whether the async request has already been sent, the default value is false\n     */\n    boolean sent() default false;\n\n    /**\n     * Service mock name, use interface name + Mock if not set\n     */\n    String mock() default \"\";\n\n    /**\n     * Whether to use JSR303 validation, legal values are: true, false\n     */\n    String validation() default \"\";\n\n    /**\n     * Timeout value for service invocation, default value is 0\n     */\n    int timeout() default -1;\n\n    /**\n     * Specify cache implementation for service invocation, legal values include: lru, threadlocal, jcache\n     */\n    String cache() default \"\";\n\n    /**\n     * Filters for service invocation\n     * <p>\n     * see Filter\n     */\n    String[] filter() default {};\n\n    /**\n     * Listeners for service exporting and unexporting\n     * <p>\n     * see ExporterListener\n     */\n    String[] listener() default {};\n\n    /**\n     * Customized parameter key-value pair, for example: {key1, value1, key2, value2} or {\"key1=value1\", \"key2=value2\"}\n     */\n    String[] parameters() default {};\n\n    /**\n     * Application name\n     *\n     * @deprecated This attribute was deprecated, use bind application/module of spring ApplicationContext\n     */\n    @Deprecated\n    String application() default \"\";\n\n    /**\n     * Module associated name\n     */\n    String module() default \"\";\n\n    /**\n     * Consumer associated name\n     */\n    String consumer() default \"\";\n\n    /**\n     * Monitor associated name\n     */\n    String monitor() default \"\";\n\n    /**\n     * Registry associated name\n     */\n    String[] registry() default {};\n\n    /**\n     * The communication protocol of Dubbo Service\n     *\n     * @return the default value is \"\"\n     * @since 2.6.6\n     */\n    String protocol() default \"\";\n\n    /**\n     * Service tag name\n     */\n    String tag() default \"\";\n\n    /**\n     * Service merger\n     */\n    String merger() default \"\";\n\n    /**\n     * methods support\n     */\n    Method[] methods() default {};\n\n    /**\n     * The id\n     * NOTE: The id attribute is ignored when using @DubboReference on @Bean method\n     *\n     * @return default value is empty\n     * @since 2.7.3\n     */\n    String id() default \"\";\n\n    /**\n     * @return The service names that the Dubbo interface subscribed\n     * @see RegistryConstants#SUBSCRIBED_SERVICE_NAMES_KEY\n     * @since 2.7.8\n     * @deprecated using {@link DubboReference#providedBy()}\n     */\n    @Deprecated\n    String[] services() default {};\n\n    /**\n     * declares which app or service this interface belongs to\n     *\n     * @see RegistryConstants#PROVIDED_BY\n     */\n    String[] providedBy() default {};\n\n    /**\n     * The service port of the provider\n     *\n     * @see AbstractReferenceConfig#providerPort\n     * @since 3.1.0\n     */\n    int providerPort() default -1;\n\n    /**\n     * assign the namespace that provider belong to\n     * @see AbstractReferenceConfig#providerNamespace\n     * @since 3.1.1\n     */\n    String providerNamespace() default \"\";\n\n    /**\n     * the scope for referring/exporting a service, if it's local, it means searching in current JVM only.\n     *\n     * @see org.apache.dubbo.rpc.Constants#SCOPE_LOCAL\n     * @see org.apache.dubbo.rpc.Constants#SCOPE_REMOTE\n     */\n    String scope() default \"\";\n\n    /**\n     * Weather the reference is refer asynchronously\n     */\n    boolean referAsync() default false;\n\n    /**\n     * unload Cluster related in mesh mode\n     *\n     * @see ReferenceConfigBase#unloadClusterRelated\n     * @since 3.1.0\n     */\n    boolean unloadClusterRelated() default false;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/annotation/DubboService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.annotation;\n\nimport org.apache.dubbo.common.constants.ClusterRules;\nimport org.apache.dubbo.common.constants.LoadbalanceRules;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Class-level annotation used for declaring Dubbo service.\n * <p/>\n * <b>1. Using with java config bean:</b>\n * <p/>\n * <b>This usage is recommended</b>.<br/>\n * It is more flexible on bean methods than on implementation classes, and is more compatible with Spring.\n * <pre>\n * &#64;Configuration\n * class ProviderConfiguration {\n *\n *     &#64;Bean\n *     &#64;DubboService(group=\"demo\")\n *     public DemoService demoServiceImpl() {\n *         return new DemoServiceImpl();\n *     }\n * }\n * </pre>\n *\n * <b>2. Using on implementation class of service:  </b>\n * <pre>\n * &#64;DubboService(group=\"demo\")\n * public class DemoServiceImpl implements DemoService {\n *     ...\n * }\n * </pre>\n *\n * This usage causes the implementation class to rely on the Dubbo module.\n *\n *\n * @since 2.7.7\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE, ElementType.METHOD})\n@Inherited\npublic @interface DubboService {\n\n    /**\n     * Interface class, default value is void.class\n     */\n    Class<?> interfaceClass() default void.class;\n\n    /**\n     * Interface class name, default value is empty string\n     */\n    String interfaceName() default \"\";\n\n    /**\n     * Service version, default value is empty string\n     */\n    String version() default \"\";\n\n    /**\n     * Service group, default value is empty string\n     */\n    String group() default \"\";\n\n    /**\n     * Service path, default value is empty string\n     */\n    String path() default \"\";\n\n    /**\n     * Whether to export service, default value is true\n     */\n    boolean export() default true;\n\n    /**\n     * Service token, default value is empty string\n     */\n    String token() default \"\";\n\n    /**\n     * Whether the service is deprecated, default value is false\n     */\n    boolean deprecated() default false;\n\n    /**\n     * Whether the service is dynamic, default value is true\n     */\n    boolean dynamic() default true;\n\n    /**\n     * Access log for the service, default value is empty string\n     */\n    String accesslog() default \"\";\n\n    /**\n     * Maximum concurrent executes for the service, default value is -1 - no limits\n     */\n    int executes() default -1;\n\n    /**\n     * Whether to register the service to register center, default value is true\n     */\n    boolean register() default true;\n\n    /**\n     * Service weight value, default value is -1\n     */\n    int weight() default -1;\n\n    /**\n     * Service doc, default value is empty string\n     */\n    String document() default \"\";\n\n    /**\n     * Delay time for service registration, default value is -1\n     */\n    int delay() default -1;\n\n    /**\n     * @see DubboService#stub()\n     * @deprecated\n     */\n    String local() default \"\";\n\n    /**\n     * Service stub name, use interface name + Local if not set\n     */\n    String stub() default \"\";\n\n    /**\n     * Cluster strategy, legal values include: failover, failfast, failsafe, failback, forking\n     * you can use {@link org.apache.dubbo.common.constants.ClusterRules#FAIL_FAST} ……\n     */\n    String cluster() default ClusterRules.EMPTY;\n\n    /**\n     * How the proxy is generated, legal values include: jdk, javassist\n     */\n    String proxy() default \"\";\n\n    /**\n     * Maximum connections service provider can accept, default value is -1 - connection is shared\n     */\n    int connections() default -1;\n\n    /**\n     * The callback instance limit peer connection\n     * <p>\n     * see org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CALLBACK_INSTANCES\n     */\n    int callbacks() default -1;\n\n    /**\n     * Callback method name when connected, default value is empty string\n     */\n    String onconnect() default \"\";\n\n    /**\n     * Callback method name when disconnected, default value is empty string\n     */\n    String ondisconnect() default \"\";\n\n    /**\n     * Service owner, default value is empty string\n     */\n    String owner() default \"\";\n\n    /**\n     * Service layer, default value is empty string\n     */\n    String layer() default \"\";\n\n    /**\n     * Service invocation retry times\n     *\n     * @see org.apache.dubbo.common.constants.CommonConstants#DEFAULT_RETRIES\n     */\n    int retries() default -1;\n\n    /**\n     * Load balance strategy, legal values include: random, roundrobin, leastactive\n     *\n     * you can use {@link org.apache.dubbo.common.constants.LoadbalanceRules#RANDOM} ……\n     */\n    String loadbalance() default LoadbalanceRules.EMPTY;\n\n    /**\n     * Whether to enable async invocation, default value is false\n     */\n    boolean async() default false;\n\n    /**\n     * Maximum active requests allowed, default value is -1\n     */\n    int actives() default -1;\n\n    /**\n     * Whether the async request has already been sent, the default value is false\n     */\n    boolean sent() default false;\n\n    /**\n     * Service mock name, use interface name + Mock if not set\n     */\n    String mock() default \"\";\n\n    /**\n     * Whether to use JSR303 validation, legal values are: true, false\n     */\n    String validation() default \"\";\n\n    /**\n     * Timeout value for service invocation, default value is -1\n     */\n    int timeout() default -1;\n\n    /**\n     * Specify cache implementation for service invocation, legal values include: lru, threadlocal, jcache\n     */\n    String cache() default \"\";\n\n    /**\n     * Filters for service invocation\n     *\n     * @see Filter\n     */\n    String[] filter() default {};\n\n    /**\n     * Listeners for service exporting and unexporting\n     *\n     * @see ExporterListener\n     */\n    String[] listener() default {};\n\n    /**\n     * Customized parameter key-value pair, for example:\n     * <pre>\n     *  [\"a\",\"b\"] ==> {a=b}\n     *  [\" a \",\" b \"] ==> {a=b}\n     *  [\"a=b\"] ==>{a=b}\n     *  [\"a:b\"] ==>{a=b}\n     *  [\"a=b\",\"c\",\"d\"] ==>{a=b,c=d}\n     *  [\"a\",\"a:b\"] ==>{a=\"a:b\"}\n     *  [\"a\",\"a,b\"] ==>{a=\"a,b\"}\n     * </pre>\n     * @see org.apache.dubbo.config.spring.util.DubboAnnotationUtils#convertParameters(java.lang.String[])\n     */\n    String[] parameters() default {};\n\n    /**\n     * Application spring bean name\n     * @deprecated This attribute was deprecated, use bind application/module of spring ApplicationContext\n     */\n    @Deprecated\n    String application() default \"\";\n\n    /**\n     * Module spring bean name\n     */\n    String module() default \"\";\n\n    /**\n     * Provider spring bean name\n     */\n    String provider() default \"\";\n\n    /**\n     * Protocol spring bean names\n     */\n    String[] protocol() default {};\n\n    /**\n     * Monitor spring bean name\n     */\n    String monitor() default \"\";\n\n    /**\n     * Registry spring bean name\n     */\n    String[] registry() default {};\n\n    /**\n     * Service tag name\n     */\n    String tag() default \"\";\n\n    /**\n     * methods support\n     *\n     * @return\n     */\n    Method[] methods() default {};\n\n    /**\n     * the scope for referring/exporting a service, if it's local, it means searching in current JVM only.\n     * @see org.apache.dubbo.rpc.Constants#SCOPE_LOCAL\n     * @see org.apache.dubbo.rpc.Constants#SCOPE_REMOTE\n     */\n    String scope() default \"\";\n\n    /**\n     * Weather the service is export asynchronously\n     */\n    boolean exportAsync() default false;\n\n    /**\n     * bean name of service executor(thread pool), used for thread pool isolation between services\n     * @return\n     */\n    String executor() default \"\";\n\n    /**\n     * Payload max length.\n     */\n    String payload() default \"\";\n\n    /**\n     * The serialization type\n     */\n    String serialization() default \"\";\n\n    /**\n     * If the parameter has a value, the consumer will read the parameter first.\n     * If the Dubbo Sdk you are using contains the serialization type, the serialization method specified by the argument is used.\n     * <p>\n     * When this parameter is null or the serialization type specified by this parameter does not exist in the Dubbo SDK, the serialization type specified by serialization is used.\n     * If the Dubbo SDK if still does not exist, the default type of the Dubbo SDK is used.\n     * For Dubbo SDK >= 3.2, <code>preferSerialization</code> takes precedence over <code>serialization</code>\n     * <p>\n     * The configuration supports multiple, which are separated by commas.Such as:<code>fastjson2,fastjson,hessian2</code>\n     */\n    String preferSerialization() default \"\";\n\n    /**\n     * Whether to expose methods in this service as MCP tools, default value is false\n     * This controls whether methods in this service class can be exposed as MCP tools.\n     * Specific method-level configuration should be done via method annotations.\n     */\n    boolean mcpEnabled() default false;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/annotation/Method.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @since 2.6.5\n *  *\n *  * 2018/9/29\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.ANNOTATION_TYPE})\n@Inherited\npublic @interface Method {\n    String name();\n\n    int timeout() default -1;\n\n    int retries() default -1;\n\n    String loadbalance() default \"\";\n\n    boolean async() default false;\n\n    boolean sent() default true;\n\n    int actives() default -1;\n\n    int executes() default -1;\n\n    boolean deprecated() default false;\n\n    boolean sticky() default false;\n\n    boolean isReturn() default true;\n\n    String oninvoke() default \"\";\n\n    String onreturn() default \"\";\n\n    String onthrow() default \"\";\n\n    String cache() default \"\";\n\n    String validation() default \"\";\n\n    String merger() default \"\";\n\n    Argument[] arguments() default {};\n\n    /**\n     * Customized parameter key-value pair, for example: {key1, value1, key2, value2} or {\"key1=value1\", \"key2=value2\"}\n     */\n    String[] parameters() default {};\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/annotation/ProvidedBy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Class-level annotation used for declaring Dubbo interface.\n * Example:\n * @ProvidedBy(\"dubbo-samples-xds-provider\")\n * public interface GreetingService {\n *     String sayHello(String name);\n * }\n *\n * @Component(\"annotatedConsumer\")\n * public class GreetingServiceConsumer {\n *     @DubboReference(version = \"1.0.0\")\n *     private GreetingService greetingService;\n * }\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE})\n@Inherited\npublic @interface ProvidedBy {\n\n    /**\n     * Interface app name, default value is empty string\n     */\n    String[] name() default {};\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/annotation/Reference.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.annotation;\n\nimport org.apache.dubbo.config.ReferenceConfigBase;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Reference\n * <p>\n *\n * @see DubboReference\n * @since 2.7.0\n * @deprecated Recommend {@link DubboReference} as the substitute\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})\n@Deprecated\npublic @interface Reference {\n    /**\n     * Interface class, default value is void.class\n     */\n    Class<?> interfaceClass() default void.class;\n\n    /**\n     * Interface class name, default value is empty string\n     */\n    String interfaceName() default \"\";\n\n    /**\n     * Service version, default value is empty string\n     */\n    String version() default \"\";\n\n    /**\n     * Service group, default value is empty string\n     */\n    String group() default \"\";\n\n    /**\n     * Service target URL for direct invocation, if this is specified, then registry center takes no effect.\n     */\n    String url() default \"\";\n\n    /**\n     * Client transport type, default value is \"netty\"\n     */\n    String client() default \"\";\n\n    /**\n     * Whether to enable generic invocation, default value is false\n     * @deprecated Do not need specify generic value, judge by injection type and interface class\n     */\n    @Deprecated\n    boolean generic() default false;\n\n    /**\n     * When enable, prefer to call local service in the same JVM if it's present, default value is true\n     */\n    boolean injvm() default true;\n\n    /**\n     * Check if service provider is available during boot up, default value is true\n     */\n    boolean check() default true;\n\n    /**\n     * Whether eager initialize the reference bean when all properties are set, default value is true ( null as true)\n     * @see ReferenceConfigBase#shouldInit()\n     */\n    boolean init() default true;\n\n    /**\n     * Whether to make connection when the client is created, the default value is false\n     */\n    boolean lazy() default false;\n\n    /**\n     * Export an stub service for event dispatch, default value is false.\n     * <p>\n     * see org.apache.dubbo.rpc.Constants#STUB_EVENT_METHODS_KEY\n     */\n    boolean stubevent() default false;\n\n    /**\n     * Whether to reconnect if connection is lost, if not specify, reconnect is enabled by default, and the interval\n     * for retry connecting is 2000 ms\n     * <p>\n     * see org.apache.dubbo.remoting.Constants#DEFAULT_RECONNECT_PERIOD\n     */\n    String reconnect() default \"\";\n\n    /**\n     * Whether to stick to the same node in the cluster, the default value is false\n     * <p>\n     * see Constants#DEFAULT_CLUSTER_STICKY\n     */\n    boolean sticky() default false;\n\n    /**\n     * How the proxy is generated, legal values include: jdk, javassist\n     */\n    String proxy() default \"\";\n\n    /**\n     * Service stub name, use interface name + Local if not set\n     */\n    String stub() default \"\";\n\n    /**\n     * Cluster strategy, legal values include: failover, failfast, failsafe, failback, forking\n     */\n    String cluster() default \"\";\n\n    /**\n     * Maximum connections service provider can accept, default value is 0 - connection is shared\n     */\n    int connections() default -1;\n\n    /**\n     * The callback instance limit peer connection\n     * <p>\n     * see org.apache.dubbo.rpc.Constants#DEFAULT_CALLBACK_INSTANCES\n     */\n    int callbacks() default -1;\n\n    /**\n     * Callback method name when connected, default value is empty string\n     */\n    String onconnect() default \"\";\n\n    /**\n     * Callback method name when disconnected, default value is empty string\n     */\n    String ondisconnect() default \"\";\n\n    /**\n     * Service owner, default value is empty string\n     */\n    String owner() default \"\";\n\n    /**\n     * Service layer, default value is empty string\n     */\n    String layer() default \"\";\n\n    /**\n     * Service invocation retry times\n     * <p>\n     * see Constants#DEFAULT_RETRIES\n     */\n    int retries() default -1;\n\n    /**\n     * Load balance strategy, legal values include: random, roundrobin, leastactive\n     * <p>\n     * see Constants#DEFAULT_LOADBALANCE\n     */\n    String loadbalance() default \"\";\n\n    /**\n     * Whether to enable async invocation, default value is false\n     */\n    boolean async() default false;\n\n    /**\n     * Maximum active requests allowed, default value is 0\n     */\n    int actives() default -1;\n\n    /**\n     * Whether the async request has already been sent, the default value is false\n     */\n    boolean sent() default false;\n\n    /**\n     * Service mock name, use interface name + Mock if not set\n     */\n    String mock() default \"\";\n\n    /**\n     * Whether to use JSR303 validation, legal values are: true, false\n     */\n    String validation() default \"\";\n\n    /**\n     * Timeout value for service invocation, default value is 0\n     */\n    int timeout() default -1;\n\n    /**\n     * Specify cache implementation for service invocation, legal values include: lru, threadlocal, jcache\n     */\n    String cache() default \"\";\n\n    /**\n     * Filters for service invocation\n     * <p>\n     * see Filter\n     */\n    String[] filter() default {};\n\n    /**\n     * Listeners for service exporting and unexporting\n     * <p>\n     * see ExporterListener\n     */\n    String[] listener() default {};\n\n    /**\n     * Customized parameter key-value pair, for example: {key1, value1, key2, value2}\n     */\n    String[] parameters() default {};\n\n    /**\n     * Application associated name\n     * @deprecated Do not set it and use the global Application Config\n     */\n    @Deprecated\n    String application() default \"\";\n\n    /**\n     * Module associated name\n     */\n    String module() default \"\";\n\n    /**\n     * Consumer associated name\n     */\n    String consumer() default \"\";\n\n    /**\n     * Monitor associated name\n     */\n    String monitor() default \"\";\n\n    /**\n     * Registry associated name\n     */\n    String[] registry() default {};\n\n    /**\n     * The communication protocol of Dubbo Service\n     *\n     * @return the default value is \"\"\n     * @since 2.6.6\n     */\n    String protocol() default \"\";\n\n    /**\n     * Service tag name\n     */\n    String tag() default \"\";\n\n    /**\n     * methods support\n     *\n     * @return\n     */\n    Method[] methods() default {};\n\n    /**\n     * The id\n     *\n     * @return default value is empty\n     * @since 2.7.3\n     */\n    String id() default \"\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/annotation/Service.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Service annotation\n *\n * @see DubboService\n * @since 2.7.0\n * @deprecated Recommend {@link DubboService} as the substitute\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE, ElementType.METHOD})\n@Inherited\n@Deprecated\npublic @interface Service {\n\n    /**\n     * Interface class, default value is void.class\n     */\n    Class<?> interfaceClass() default void.class;\n\n    /**\n     * Interface class name, default value is empty string\n     */\n    String interfaceName() default \"\";\n\n    /**\n     * Service version, default value is empty string\n     */\n    String version() default \"\";\n\n    /**\n     * Service group, default value is empty string\n     */\n    String group() default \"\";\n\n    /**\n     * Service path, default value is empty string\n     */\n    String path() default \"\";\n\n    /**\n     * Whether to export service, default value is true\n     */\n    boolean export() default true;\n\n    /**\n     * Service token, default value is false\n     */\n    String token() default \"\";\n\n    /**\n     * Whether the service is deprecated, default value is false\n     */\n    boolean deprecated() default false;\n\n    /**\n     * Whether the service is dynamic, default value is true\n     */\n    boolean dynamic() default true;\n\n    /**\n     * Access log for the service, default value is \"\"\n     */\n    String accesslog() default \"\";\n\n    /**\n     * Maximum concurrent executes for the service, default value is 0 - no limits\n     */\n    int executes() default -1;\n\n    /**\n     * Whether to register the service to register center, default value is true\n     */\n    boolean register() default true;\n\n    /**\n     * Service weight value, default value is 0\n     */\n    int weight() default -1;\n\n    /**\n     * Service doc, default value is \"\"\n     */\n    String document() default \"\";\n\n    /**\n     * Delay time for service registration, default value is 0\n     */\n    int delay() default -1;\n\n    /**\n     * @see Service#stub()\n     * @deprecated\n     */\n    String local() default \"\";\n\n    /**\n     * Service stub name, use interface name + Local if not set\n     */\n    String stub() default \"\";\n\n    /**\n     * Cluster strategy, legal values include: failover, failfast, failsafe, failback, forking\n     */\n    String cluster() default \"\";\n\n    /**\n     * How the proxy is generated, legal values include: jdk, javassist\n     */\n    String proxy() default \"\";\n\n    /**\n     * Maximum connections service provider can accept, default value is 0 - connection is shared\n     */\n    int connections() default -1;\n\n    /**\n     * The callback instance limit peer connection\n     * <p>\n     * see org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CALLBACK_INSTANCES\n     */\n    int callbacks() default -1;\n\n    /**\n     * Callback method name when connected, default value is empty string\n     */\n    String onconnect() default \"\";\n\n    /**\n     * Callback method name when disconnected, default value is empty string\n     */\n    String ondisconnect() default \"\";\n\n    /**\n     * Service owner, default value is empty string\n     */\n    String owner() default \"\";\n\n    /**\n     * Service layer, default value is empty string\n     */\n    String layer() default \"\";\n\n    /**\n     * Service invocation retry times\n     *\n     * @see org.apache.dubbo.common.constants.CommonConstants#DEFAULT_RETRIES\n     */\n    int retries() default -1;\n\n    /**\n     * Load balance strategy, legal values include: random, roundrobin, leastactive\n     *\n     * @see org.apache.dubbo.common.constants.CommonConstants#DEFAULT_LOADBALANCE\n     */\n    String loadbalance() default \"\";\n\n    /**\n     * Whether to enable async invocation, default value is false\n     */\n    boolean async() default false;\n\n    /**\n     * Maximum active requests allowed, default value is 0\n     */\n    int actives() default -1;\n\n    /**\n     * Whether the async request has already been sent, the default value is false\n     */\n    boolean sent() default false;\n\n    /**\n     * Service mock name, use interface name + Mock if not set\n     */\n    String mock() default \"\";\n\n    /**\n     * Whether to use JSR303 validation, legal values are: true, false\n     */\n    String validation() default \"\";\n\n    /**\n     * Timeout value for service invocation, default value is 0\n     */\n    int timeout() default -1;\n\n    /**\n     * Specify cache implementation for service invocation, legal values include: lru, threadlocal, jcache\n     */\n    String cache() default \"\";\n\n    /**\n     * Filters for service invocation\n     *\n     * @see Filter\n     */\n    String[] filter() default {};\n\n    /**\n     * Listeners for service exporting and unexporting\n     *\n     * @see ExporterListener\n     */\n    String[] listener() default {};\n\n    /**\n     * Customized parameter key-value pair, for example: {key1, value1, key2, value2}\n     */\n    String[] parameters() default {};\n\n    /**\n     * Application spring bean name\n     * @deprecated Do not set it and use the global Application Config\n     */\n    @Deprecated\n    String application() default \"\";\n\n    /**\n     * Module spring bean name\n     */\n    String module() default \"\";\n\n    /**\n     * Provider spring bean name\n     */\n    String provider() default \"\";\n\n    /**\n     * Protocol spring bean names\n     */\n    String[] protocol() default {};\n\n    /**\n     * Monitor spring bean name\n     */\n    String monitor() default \"\";\n\n    /**\n     * Registry spring bean name\n     */\n    String[] registry() default {};\n\n    /**\n     * Service tag name\n     */\n    String tag() default \"\";\n\n    /**\n     * methods support\n     *\n     * @return\n     */\n    Method[] methods() default {};\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.context;\n\nimport org.apache.dubbo.common.config.CompositeConfiguration;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.config.PropertiesConfiguration;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.context.LifecycleAdapter;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigKeys;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfigBase;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.stream.Collectors;\n\nimport static java.lang.Boolean.TRUE;\nimport static java.util.Collections.emptyMap;\nimport static java.util.Optional.ofNullable;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_PROPERTY_TYPE_MISMATCH;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\nimport static org.apache.dubbo.config.AbstractConfig.getTagName;\n\npublic abstract class AbstractConfigManager extends LifecycleAdapter {\n\n    private static final String CONFIG_NAME_READ_METHOD = \"getName\";\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(AbstractConfigManager.class);\n    private static final Set<Class<? extends AbstractConfig>> uniqueConfigTypes = new ConcurrentHashSet<>();\n\n    final ConcurrentHashMap<String, Map<String, AbstractConfig>> configsCache = new ConcurrentHashMap<>();\n\n    private final ConcurrentHashMap<String, AtomicInteger> configIdIndexes = new ConcurrentHashMap<>();\n\n    protected Set<AbstractConfig> duplicatedConfigs = new ConcurrentHashSet<>();\n\n    protected final ScopeModel scopeModel;\n    protected final ApplicationModel applicationModel;\n    private final Collection<Class<? extends AbstractConfig>> supportedConfigTypes;\n    private final Environment environment;\n    private ConfigValidator configValidator;\n    private final AtomicBoolean initialized = new AtomicBoolean(false);\n    protected ConfigMode configMode = ConfigMode.STRICT;\n    protected boolean ignoreDuplicatedInterface = false;\n\n    static {\n        // init unique config types\n        // unique config in application\n        uniqueConfigTypes.add(ApplicationConfig.class);\n        uniqueConfigTypes.add(MonitorConfig.class);\n        uniqueConfigTypes.add(MetricsConfig.class);\n        uniqueConfigTypes.add(TracingConfig.class);\n        uniqueConfigTypes.add(SslConfig.class);\n\n        // unique config in each module\n        uniqueConfigTypes.add(ModuleConfig.class);\n    }\n\n    public AbstractConfigManager(\n            ScopeModel scopeModel, Collection<Class<? extends AbstractConfig>> supportedConfigTypes) {\n        this.scopeModel = scopeModel;\n        this.applicationModel = ScopeModelUtil.getApplicationModel(scopeModel);\n        this.supportedConfigTypes = supportedConfigTypes;\n        environment = scopeModel.modelEnvironment();\n    }\n\n    @Override\n    public void initialize() throws IllegalStateException {\n        if (!initialized.compareAndSet(false, true)) {\n            return;\n        }\n        CompositeConfiguration configuration = scopeModel.modelEnvironment().getConfiguration();\n\n        // dubbo.config.mode\n        String configModeStr = (String) configuration.getProperty(ConfigKeys.DUBBO_CONFIG_MODE);\n        try {\n            if (StringUtils.hasText(configModeStr)) {\n                this.configMode = ConfigMode.valueOf(configModeStr.toUpperCase());\n            }\n        } catch (Exception e) {\n            String msg = \"Illegal '\" + ConfigKeys.DUBBO_CONFIG_MODE + \"' config value [\" + configModeStr\n                    + \"], available values \" + Arrays.toString(ConfigMode.values());\n            logger.error(COMMON_PROPERTY_TYPE_MISMATCH, \"\", \"\", msg, e);\n            throw new IllegalArgumentException(msg, e);\n        }\n\n        // dubbo.config.ignore-duplicated-interface\n        String ignoreDuplicatedInterfaceStr =\n                (String) configuration.getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE);\n        if (ignoreDuplicatedInterfaceStr != null) {\n            this.ignoreDuplicatedInterface = Boolean.parseBoolean(ignoreDuplicatedInterfaceStr);\n        }\n\n        // print\n        Map<String, Object> map = new LinkedHashMap<>();\n        map.put(ConfigKeys.DUBBO_CONFIG_MODE, configMode);\n        map.put(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE, this.ignoreDuplicatedInterface);\n        logger.info(\"Config settings: \" + map);\n    }\n\n    /**\n     * Add the dubbo {@link AbstractConfig config}\n     *\n     * @param config the dubbo {@link AbstractConfig config}\n     */\n    public final <T extends AbstractConfig> T addConfig(AbstractConfig config) {\n        if (config == null) {\n            return null;\n        }\n        // ignore MethodConfig\n        if (!isSupportConfigType(config.getClass())) {\n            throw new IllegalArgumentException(\"Unsupported config type: \" + config);\n        }\n\n        if (config.getScopeModel() != scopeModel) {\n            config.setScopeModel(scopeModel);\n        }\n\n        Class<? extends AbstractConfig> targetConfigType = getTargetConfigType(config.getClass());\n\n        Map<String, AbstractConfig> configsMap = ConcurrentHashMapUtils.computeIfAbsent(\n                configsCache, getTagName(targetConfigType), type -> new ConcurrentHashMap<>());\n\n        // fast check duplicated equivalent config before write lock\n        if (!(config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase)) {\n            for (AbstractConfig value : configsMap.values()) {\n                if (value.equals(config)) {\n                    return (T) value;\n                }\n            }\n        }\n\n        // lock by config type\n        synchronized (configsMap) {\n            return (T) addIfAbsent(config, configsMap, targetConfigType);\n        }\n    }\n\n    protected boolean isSupportConfigType(Class<? extends AbstractConfig> type) {\n        return getTargetConfigType(type) != null;\n    }\n\n    protected Class<? extends AbstractConfig> getTargetConfigType(Class<? extends AbstractConfig> type) {\n        for (Class<? extends AbstractConfig> supportedConfigType : supportedConfigTypes) {\n            if (supportedConfigType.isAssignableFrom(type)) {\n                return supportedConfigType;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Add config\n     *\n     * @param config\n     * @param configsMap\n     * @return the existing equivalent config or the new adding config\n     * @throws IllegalStateException\n     */\n    private <C extends AbstractConfig> C addIfAbsent(\n            C config, Map<String, C> configsMap, Class<? extends AbstractConfig> targetConfigType)\n            throws IllegalStateException {\n\n        if (config == null || configsMap == null) {\n            return config;\n        }\n\n        // find by value\n        Optional<C> prevConfig = findDuplicatedConfig(configsMap, config);\n        if (prevConfig.isPresent()) {\n            return prevConfig.get();\n        }\n\n        String key = config.getId();\n        if (key == null) {\n            do {\n                // generate key if id is not set\n                key = generateConfigId(config);\n            } while (configsMap.containsKey(key));\n        }\n\n        C existedConfig = configsMap.get(key);\n        if (existedConfig != null && !isEquals(existedConfig, config)) {\n            String type = targetConfigType.getSimpleName();\n            logger.warn(\n                    COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    String.format(\n                            \"Duplicate %s found, there already has one default %s or more than two %ss have the same id, \"\n                                    + \"you can try to give each %s a different id, override previous config with later config. id: %s, prev: %s, later: %s\",\n                            type, type, type, type, key, existedConfig, config));\n        }\n\n        // override existed config if any\n        configsMap.put(key, config);\n        return config;\n    }\n\n    protected <C extends AbstractConfig> boolean removeIfAbsent(C config, Map<String, C> configsMap) {\n        if (config.getId() != null) {\n            return configsMap.remove(config.getId(), config);\n        }\n        return configsMap.values().removeIf(c -> config == c);\n    }\n\n    protected boolean isUniqueConfig(AbstractConfig config) {\n        if (uniqueConfigTypes.contains(config.getClass())) {\n            return true;\n        }\n        for (Class<? extends AbstractConfig> uniqueConfigType : uniqueConfigTypes) {\n            if (uniqueConfigType.isAssignableFrom(config.getClass())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    protected <C extends AbstractConfig> C getSingleConfig(String configType) throws IllegalStateException {\n        Map<String, AbstractConfig> configsMap = getConfigsMap(configType);\n        int size = configsMap.size();\n        if (size < 1) {\n            //                throw new IllegalStateException(\"No such \" + configType.getName() + \" is found\");\n            return null;\n        } else if (size > 1) {\n            throw new IllegalStateException(\"Expected single instance of \" + configType + \", but found \" + size\n                    + \" instances, please remove redundant configs. instances: \" + configsMap.values());\n        }\n        return (C) configsMap.values().iterator().next();\n    }\n\n    protected <C extends AbstractConfig> Optional<C> findDuplicatedConfig(Map<String, C> configsMap, C config) {\n\n        // find by value\n        Optional<C> prevConfig = findConfigByValue(configsMap.values(), config);\n        if (prevConfig.isPresent()) {\n            if (prevConfig.get() == config) {\n                // the new one is same as existing one\n                return prevConfig;\n            }\n\n            // ignore duplicated equivalent config\n            if (logger.isInfoEnabled() && duplicatedConfigs.add(config)) {\n                logger.info(\"Ignore duplicated config: \" + config);\n            }\n            return prevConfig;\n        }\n\n        // check unique config\n        return checkUniqueConfig(configsMap, config);\n    }\n\n    public <C extends AbstractConfig> Map<String, C> getConfigsMap(Class<C> cls) {\n        return getConfigsMap(getTagName(cls));\n    }\n\n    protected <C extends AbstractConfig> Map<String, C> getConfigsMap(String configType) {\n        return (Map<String, C>) configsCache.getOrDefault(configType, emptyMap());\n    }\n\n    protected <C extends AbstractConfig> Collection<C> getConfigs(String configType) {\n        return (Collection<C>) getConfigsMap(configType).values();\n    }\n\n    public <C extends AbstractConfig> Collection<C> getConfigs(Class<C> configType) {\n        return (Collection<C>) getConfigsMap(getTagName(configType)).values();\n    }\n\n    /**\n     * Get config by id\n     *\n     * @param configType\n     * @param id\n     * @return\n     */\n    protected <C extends AbstractConfig> C getConfigById(String configType, String id) {\n        return (C) getConfigsMap(configType).get(id);\n    }\n\n    /**\n     * Get config instance by id or by name\n     *\n     * @param cls      Config type\n     * @param idOrName the id or name of the config\n     * @return\n     */\n    public <T extends AbstractConfig> Optional<T> getConfig(Class<T> cls, String idOrName) {\n        T config = getConfigById(getTagName(cls), idOrName);\n        if (config == null) {\n            config = getConfigByName(cls, idOrName);\n        }\n        return ofNullable(config);\n    }\n\n    /**\n     * Get config by name if existed\n     *\n     * @param cls\n     * @param name\n     * @return\n     */\n    protected <C extends AbstractConfig> C getConfigByName(Class<? extends C> cls, String name) {\n        Map<String, ? extends C> configsMap = getConfigsMap(cls);\n        if (configsMap.isEmpty()) {\n            return null;\n        }\n        // try to find config by name\n        if (ReflectUtils.hasMethod(cls, CONFIG_NAME_READ_METHOD)) {\n            List<C> list = configsMap.values().stream()\n                    .filter(cfg -> name.equals(getConfigName(cfg)))\n                    .collect(Collectors.toList());\n            if (list.size() > 1) {\n                throw new IllegalStateException(\"Found more than one config by name: \" + name + \", instances: \" + list\n                        + \". Please remove redundant configs or get config by id.\");\n            } else if (list.size() == 1) {\n                return list.get(0);\n            }\n        }\n        return null;\n    }\n\n    private <C extends AbstractConfig> String getConfigName(C config) {\n        try {\n            return ReflectUtils.getProperty(config, CONFIG_NAME_READ_METHOD);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    protected <C extends AbstractConfig> Optional<C> findConfigByValue(Collection<C> values, C config) {\n        // 1. find same config instance (speed up raw api usage)\n        Optional<C> prevConfig = values.stream().filter(val -> val == config).findFirst();\n        if (prevConfig.isPresent()) {\n            return prevConfig;\n        }\n\n        // 2. find equal config\n        prevConfig = values.stream().filter(val -> isEquals(val, config)).findFirst();\n        return prevConfig;\n    }\n\n    protected boolean isEquals(AbstractConfig oldOne, AbstractConfig newOne) {\n        if (oldOne == newOne) {\n            return true;\n        }\n        if (oldOne == null || newOne == null) {\n            return false;\n        }\n        if (oldOne.getClass() != newOne.getClass()) {\n            return false;\n        }\n        // make both are refreshed or none is refreshed\n        if (oldOne.isRefreshed() || newOne.isRefreshed()) {\n            if (!oldOne.isRefreshed()) {\n                oldOne.refresh();\n            }\n            if (!newOne.isRefreshed()) {\n                newOne.refresh();\n            }\n        }\n        return oldOne.equals(newOne);\n    }\n\n    protected <C extends AbstractConfig> String generateConfigId(C config) {\n        String tagName = getTagName(config.getClass());\n        int idx = ConcurrentHashMapUtils.computeIfAbsent(configIdIndexes, tagName, clazz -> new AtomicInteger(0))\n                .incrementAndGet();\n        return tagName + \"#\" + idx;\n    }\n\n    public <C extends AbstractConfig> List<C> getDefaultConfigs(Class<C> cls) {\n        return getDefaultConfigs(getConfigsMap(getTagName(cls)));\n    }\n\n    static <C extends AbstractConfig> Boolean isDefaultConfig(C config) {\n        return config.isDefault();\n    }\n\n    static <C extends AbstractConfig> List<C> getDefaultConfigs(Map<String, C> configsMap) {\n        // find isDefault() == true\n        List<C> list = configsMap.values().stream()\n                .filter(c -> TRUE.equals(AbstractConfigManager.isDefaultConfig(c)))\n                .collect(Collectors.toList());\n        if (!list.isEmpty()) {\n            return list;\n        }\n\n        // find isDefault() == null\n        list = configsMap.values().stream()\n                .filter(c -> AbstractConfigManager.isDefaultConfig(c) == null)\n                .collect(Collectors.toList());\n        return list;\n\n        // exclude isDefault() == false\n    }\n\n    protected <C extends AbstractConfig> Optional<C> checkUniqueConfig(Map<String, C> configsMap, C config) {\n        if (configsMap.size() > 0 && isUniqueConfig(config)) {\n            C oldOne = configsMap.values().iterator().next();\n            String configName = oldOne.getClass().getSimpleName();\n            String msgPrefix = \"Duplicate Configs found for \" + configName + \", only one unique \" + configName\n                    + \" is allowed for one application. previous: \" + oldOne + \", later: \" + config\n                    + \". According to config mode [\" + configMode + \"], \";\n            switch (configMode) {\n                case STRICT: {\n                    if (!isEquals(oldOne, config)) {\n                        throw new IllegalStateException(\n                                msgPrefix + \"please remove redundant configs and keep only one.\");\n                    }\n                    break;\n                }\n                case IGNORE: {\n                    // ignore later config\n                    if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {\n                        logger.warn(\n                                COMMON_UNEXPECTED_EXCEPTION,\n                                \"\",\n                                \"\",\n                                msgPrefix + \"keep previous config and ignore later config\");\n                    }\n                    return Optional.of(oldOne);\n                }\n                case OVERRIDE: {\n                    // clear previous config, add new config\n                    configsMap.clear();\n                    if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {\n                        logger.warn(\n                                COMMON_UNEXPECTED_EXCEPTION,\n                                \"\",\n                                \"\",\n                                msgPrefix + \"override previous config with later config\");\n                    }\n                    break;\n                }\n                case OVERRIDE_ALL: {\n                    // override old one's properties with the new one\n                    oldOne.overrideWithConfig(config, true);\n                    if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {\n                        logger.warn(\n                                COMMON_UNEXPECTED_EXCEPTION,\n                                \"\",\n                                \"\",\n                                msgPrefix + \"override previous config with later config\");\n                    }\n                    return Optional.of(oldOne);\n                }\n                case OVERRIDE_IF_ABSENT: {\n                    // override old one's properties with the new one\n                    oldOne.overrideWithConfig(config, false);\n                    if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {\n                        logger.warn(\n                                COMMON_UNEXPECTED_EXCEPTION,\n                                \"\",\n                                \"\",\n                                msgPrefix + \"override previous config with later config\");\n                    }\n                    return Optional.of(oldOne);\n                }\n            }\n        }\n        return Optional.empty();\n    }\n\n    public abstract void loadConfigs();\n\n    public <T extends AbstractConfig> List<T> loadConfigsOfTypeFromProps(Class<T> cls) {\n        List<T> tmpConfigs = new ArrayList<>();\n        PropertiesConfiguration properties = environment.getPropertiesConfiguration();\n\n        // load multiple configs with id\n        Set<String> configIds = this.getConfigIdsFromProps(cls);\n        configIds.forEach(id -> {\n            if (!this.getConfig(cls, id).isPresent()) {\n                T config;\n                try {\n                    config = createConfig(cls, scopeModel);\n                    config.setId(id);\n                } catch (Exception e) {\n                    throw new IllegalStateException(\n                            \"create config instance failed, id: \" + id + \", type:\" + cls.getSimpleName());\n                }\n\n                String key = null;\n                boolean addDefaultNameConfig = false;\n                try {\n                    // add default name config (same as id), e.g. dubbo.protocols.rest.port=1234\n                    key = DUBBO + \".\" + AbstractConfig.getPluralTagName(cls) + \".\" + id + \".name\";\n                    if (properties.getProperty(key) == null) {\n                        properties.setProperty(key, id);\n                        addDefaultNameConfig = true;\n                    }\n\n                    config.refresh();\n                    this.addConfig(config);\n                    tmpConfigs.add(config);\n                } catch (Exception e) {\n                    logger.error(\n                            COMMON_PROPERTY_TYPE_MISMATCH,\n                            \"\",\n                            \"\",\n                            \"load config failed, id: \" + id + \", type:\" + cls.getSimpleName(),\n                            e);\n                    throw new IllegalStateException(\"load config failed, id: \" + id + \", type:\" + cls.getSimpleName());\n                } finally {\n                    if (addDefaultNameConfig && key != null) {\n                        properties.remove(key);\n                    }\n                }\n            }\n        });\n\n        // If none config of the type, try load single config\n        if (this.getConfigs(cls).isEmpty()) {\n            // load single config\n            List<Map<String, String>> configurationMaps = environment.getConfigurationMaps();\n            if (ConfigurationUtils.hasSubProperties(configurationMaps, AbstractConfig.getTypePrefix(cls))) {\n                T config;\n                try {\n                    config = createConfig(cls, scopeModel);\n                    config.refresh();\n                } catch (Exception e) {\n                    throw new IllegalStateException(\n                            \"create default config instance failed, type:\" + cls.getSimpleName(), e);\n                }\n\n                this.addConfig(config);\n                tmpConfigs.add(config);\n            }\n        }\n\n        return tmpConfigs;\n    }\n\n    private <T extends AbstractConfig> T createConfig(Class<T> cls, ScopeModel scopeModel)\n            throws ReflectiveOperationException {\n        T config = cls.getDeclaredConstructor().newInstance();\n        config.setScopeModel(scopeModel);\n        return config;\n    }\n\n    /**\n     * Search props and extract config ids of specify type.\n     * <pre>\n     * # properties\n     * dubbo.registries.registry1.address=xxx\n     * dubbo.registries.registry2.port=xxx\n     *\n     * # extract\n     * Set configIds = getConfigIds(RegistryConfig.class)\n     *\n     * # result\n     * configIds: [\"registry1\", \"registry2\"]\n     * </pre>\n     *\n     * @param clazz config type\n     * @return ids of specify config type\n     */\n    private Set<String> getConfigIdsFromProps(Class<? extends AbstractConfig> clazz) {\n        String prefix = CommonConstants.DUBBO + \".\" + AbstractConfig.getPluralTagName(clazz) + \".\";\n        return ConfigurationUtils.getSubIds(environment.getConfigurationMaps(), prefix);\n    }\n\n    protected <T extends AbstractConfig> void checkDefaultAndValidateConfigs(Class<T> configType) {\n        try {\n            if (shouldAddDefaultConfig(configType)) {\n                T config = createConfig(configType, scopeModel);\n                config.refresh();\n                if (!isNeedValidation(config) || config.isValid()) {\n                    this.addConfig(config);\n                } else {\n                    logger.info(\"Ignore invalid config: \" + config);\n                }\n            }\n        } catch (Exception e) {\n            throw new IllegalStateException(\"Add default config failed: \" + configType.getSimpleName(), e);\n        }\n\n        // validate configs\n        Collection<T> configs = this.getConfigs(configType);\n        if (getConfigValidator() != null) {\n            for (T config : configs) {\n                getConfigValidator().validate(config);\n            }\n        }\n\n        // check required default\n        if (isRequired(configType) && configs.isEmpty()) {\n            throw new IllegalStateException(\"Default config not found for \" + configType.getSimpleName());\n        }\n    }\n\n    /**\n     * The component configuration that does not affect the main process does not need to be verified.\n     *\n     * @param config\n     * @param <T>\n     * @return\n     */\n    protected <T extends AbstractConfig> boolean isNeedValidation(T config) {\n        return !(config instanceof MetadataReportConfig);\n    }\n\n    private ConfigValidator getConfigValidator() {\n        if (configValidator == null) {\n            configValidator = applicationModel.getBeanFactory().getBean(ConfigValidator.class);\n        }\n        return configValidator;\n    }\n\n    /**\n     * The configuration that does not affect the main process is not necessary.\n     *\n     * @param clazz\n     * @param <T>\n     * @return\n     */\n    protected <T extends AbstractConfig> boolean isRequired(Class<T> clazz) {\n        return clazz != RegistryConfig.class\n                && clazz != MetadataReportConfig.class\n                && clazz != MonitorConfig.class\n                && clazz != MetricsConfig.class\n                && clazz != TracingConfig.class;\n    }\n\n    private <T extends AbstractConfig> boolean shouldAddDefaultConfig(Class<T> clazz) {\n        // Configurations that are not required will not be automatically added to the default configuration\n        if (!isRequired(clazz)) {\n            return false;\n        }\n        return this.getDefaultConfigs(clazz).isEmpty();\n    }\n\n    public void refreshAll() {}\n\n    /**\n     * In some scenario,  we may need to add and remove ServiceConfig or ReferenceConfig dynamically.\n     *\n     * @param config the config instance to remove.\n     * @return\n     */\n    public boolean removeConfig(AbstractConfig config) {\n        if (config == null) {\n            return false;\n        }\n\n        Map<String, AbstractConfig> configs = configsCache.get(getTagName(config.getClass()));\n        if (CollectionUtils.isNotEmptyMap(configs)) {\n            // lock by config type\n            synchronized (configs) {\n                return removeIfAbsent(config, configs);\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public void destroy() throws IllegalStateException {\n        clear();\n    }\n\n    public void clear() {\n        this.configsCache.clear();\n        this.configIdIndexes.clear();\n        this.duplicatedConfigs.clear();\n    }\n\n    public boolean isInitialized() {\n        return initialized.get();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigConfigurationAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.context;\n\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.AbstractConfig;\n\nimport java.util.Map;\n\n/**\n * This class receives an {@link AbstractConfig} and exposes its attributes through {@link Configuration}\n */\npublic class ConfigConfigurationAdapter implements Configuration {\n\n    private final Map<String, String> metaData;\n\n    public ConfigConfigurationAdapter(AbstractConfig config, String prefix) {\n        if (StringUtils.hasText(prefix)) {\n            metaData = config.getMetaData(prefix);\n        } else {\n            metaData = config.getMetaData();\n        }\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        return metaData.get(key);\n    }\n\n    public Map<String, String> getProperties() {\n        return metaData;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.context;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.context.ApplicationExt;\nimport org.apache.dubbo.common.extension.DisableInject;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.ConfigKeys;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport static java.util.Optional.ofNullable;\nimport static org.apache.dubbo.config.AbstractConfig.getTagName;\n\n/**\n * A lock-free config manager (through ConcurrentHashMap), for fast read operation.\n * The Write operation lock with sub configs map of config type, for safely check and add new config.\n */\npublic class ConfigManager extends AbstractConfigManager implements ApplicationExt {\n\n    private static final Logger logger = LoggerFactory.getLogger(ConfigManager.class);\n\n    public static final String NAME = \"config\";\n    public static final String BEAN_NAME = \"dubboConfigManager\";\n    public static final String DUBBO_CONFIG_MODE = ConfigKeys.DUBBO_CONFIG_MODE;\n\n    public ConfigManager(ApplicationModel applicationModel) {\n        super(\n                applicationModel,\n                Arrays.asList(\n                        ApplicationConfig.class,\n                        MonitorConfig.class,\n                        MetricsConfig.class,\n                        SslConfig.class,\n                        ProtocolConfig.class,\n                        RegistryConfig.class,\n                        ConfigCenterConfig.class,\n                        MetadataReportConfig.class,\n                        TracingConfig.class));\n    }\n\n    public static ProtocolConfig getProtocolOrDefault(URL url) {\n        return getProtocolOrDefault(url.getOrDefaultApplicationModel(), url.getProtocol());\n    }\n\n    public static ProtocolConfig getProtocolOrDefault(String idOrName) {\n        return getProtocolOrDefault(ApplicationModel.defaultModel(), idOrName);\n    }\n\n    private static ProtocolConfig getProtocolOrDefault(ApplicationModel applicationModel, String idOrName) {\n        return applicationModel.getApplicationConfigManager().getOrAddProtocol(idOrName);\n    }\n\n    // ApplicationConfig correlative methods\n\n    /**\n     * Set application config\n     */\n    @DisableInject\n    public void setApplication(ApplicationConfig application) {\n        addConfig(application);\n    }\n\n    public Optional<ApplicationConfig> getApplication() {\n        return ofNullable(getSingleConfig(getTagName(ApplicationConfig.class)));\n    }\n\n    public ApplicationConfig getApplicationOrElseThrow() {\n        return getApplication().orElseThrow(() -> new IllegalStateException(\"There's no ApplicationConfig specified.\"));\n    }\n\n    // MonitorConfig correlative methods\n\n    @DisableInject\n    public void setMonitor(MonitorConfig monitor) {\n        addConfig(monitor);\n    }\n\n    public Optional<MonitorConfig> getMonitor() {\n        return ofNullable(getSingleConfig(getTagName(MonitorConfig.class)));\n    }\n\n    @DisableInject\n    public void setMetrics(MetricsConfig metrics) {\n        addConfig(metrics);\n    }\n\n    public Optional<MetricsConfig> getMetrics() {\n        return ofNullable(getSingleConfig(getTagName(MetricsConfig.class)));\n    }\n\n    @DisableInject\n    public void setTracing(TracingConfig tracing) {\n        addConfig(tracing);\n    }\n\n    public Optional<TracingConfig> getTracing() {\n        return ofNullable(getSingleConfig(getTagName(TracingConfig.class)));\n    }\n\n    @DisableInject\n    public void setSsl(SslConfig sslConfig) {\n        addConfig(sslConfig);\n    }\n\n    public Optional<SslConfig> getSsl() {\n        return ofNullable(getSingleConfig(getTagName(SslConfig.class)));\n    }\n\n    // ConfigCenterConfig correlative methods\n\n    public void addConfigCenter(ConfigCenterConfig configCenter) {\n        addConfig(configCenter);\n    }\n\n    public void addConfigCenters(Iterable<ConfigCenterConfig> configCenters) {\n        configCenters.forEach(this::addConfigCenter);\n    }\n\n    public Optional<Collection<ConfigCenterConfig>> getDefaultConfigCenter() {\n        Collection<ConfigCenterConfig> defaults =\n                getDefaultConfigs(getConfigsMap(getTagName(ConfigCenterConfig.class)));\n        if (CollectionUtils.isEmpty(defaults)) {\n            defaults = getConfigCenters();\n        }\n        return ofNullable(defaults);\n    }\n\n    public Optional<ConfigCenterConfig> getConfigCenter(String id) {\n        return getConfig(ConfigCenterConfig.class, id);\n    }\n\n    public Collection<ConfigCenterConfig> getConfigCenters() {\n        return getConfigs(getTagName(ConfigCenterConfig.class));\n    }\n\n    // MetadataReportConfig correlative methods\n\n    public void addMetadataReport(MetadataReportConfig metadataReportConfig) {\n        addConfig(metadataReportConfig);\n    }\n\n    public void addMetadataReports(Iterable<MetadataReportConfig> metadataReportConfigs) {\n        metadataReportConfigs.forEach(this::addMetadataReport);\n    }\n\n    public Collection<MetadataReportConfig> getMetadataConfigs() {\n        return getConfigs(getTagName(MetadataReportConfig.class));\n    }\n\n    public Collection<MetadataReportConfig> getDefaultMetadataConfigs() {\n        Collection<MetadataReportConfig> defaults =\n                getDefaultConfigs(getConfigsMap(getTagName(MetadataReportConfig.class)));\n        if (CollectionUtils.isEmpty(defaults)) {\n            return getMetadataConfigs();\n        }\n        return defaults;\n    }\n\n    // ProtocolConfig correlative methods\n\n    public void addProtocol(ProtocolConfig protocolConfig) {\n        addConfig(protocolConfig);\n    }\n\n    public void addProtocols(Iterable<ProtocolConfig> protocolConfigs) {\n        if (protocolConfigs != null) {\n            protocolConfigs.forEach(this::addProtocol);\n        }\n    }\n\n    public Optional<ProtocolConfig> getProtocol(String idOrName) {\n        return getConfig(ProtocolConfig.class, idOrName);\n    }\n\n    public ProtocolConfig getOrAddProtocol(String idOrName) {\n        Optional<ProtocolConfig> protocol = getProtocol(idOrName);\n        if (protocol.isPresent()) {\n            return protocol.get();\n        }\n\n        // Avoiding default protocol configuration overriding custom protocol configuration\n        // due to `getOrAddProtocol` being called when they are not loaded\n        idOrName = idOrName + \".default\";\n        protocol = getProtocol(idOrName);\n        if (protocol.isPresent()) {\n            return protocol.get();\n        }\n\n        ProtocolConfig protocolConfig = addConfig(new ProtocolConfig(idOrName));\n\n        // addProtocol triggers refresh when other protocols exist in the ConfigManager.\n        // so refresh is only done when ProtocolConfig is not refreshed.\n        if (!protocolConfig.isRefreshed()) {\n            protocolConfig.refresh();\n        }\n        return protocolConfig;\n    }\n\n    public List<ProtocolConfig> getDefaultProtocols() {\n        return getDefaultConfigs(ProtocolConfig.class);\n    }\n\n    @Override\n    @SuppressWarnings(\"RedundantMethodOverride\")\n    public <C extends AbstractConfig> List<C> getDefaultConfigs(Class<C> cls) {\n        return getDefaultConfigs(getConfigsMap(getTagName(cls)));\n    }\n\n    public Collection<ProtocolConfig> getProtocols() {\n        return getConfigs(getTagName(ProtocolConfig.class));\n    }\n\n    // RegistryConfig correlative methods\n\n    public void addRegistry(RegistryConfig registryConfig) {\n        addConfig(registryConfig);\n    }\n\n    public void addRegistries(Iterable<RegistryConfig> registryConfigs) {\n        if (registryConfigs != null) {\n            registryConfigs.forEach(this::addRegistry);\n        }\n    }\n\n    public Optional<RegistryConfig> getRegistry(String id) {\n        return getConfig(RegistryConfig.class, id);\n    }\n\n    public List<RegistryConfig> getDefaultRegistries() {\n        return getDefaultConfigs(getConfigsMap(getTagName(RegistryConfig.class)));\n    }\n\n    public Collection<RegistryConfig> getRegistries() {\n        return getConfigs(getTagName(RegistryConfig.class));\n    }\n\n    @Override\n    public void refreshAll() {\n        // refresh all configs here\n        getApplication().ifPresent(ApplicationConfig::refresh);\n        getMonitor().ifPresent(MonitorConfig::refresh);\n        getMetrics().ifPresent(MetricsConfig::refresh);\n        getTracing().ifPresent(TracingConfig::refresh);\n        getSsl().ifPresent(SslConfig::refresh);\n\n        getProtocols().forEach(ProtocolConfig::refresh);\n        getRegistries().forEach(RegistryConfig::refresh);\n        getConfigCenters().forEach(ConfigCenterConfig::refresh);\n        getMetadataConfigs().forEach(MetadataReportConfig::refresh);\n    }\n\n    @Override\n    public void loadConfigs() {\n        // application config has load before starting config center\n        // load dubbo.applications.xxx\n        loadConfigsOfTypeFromProps(ApplicationConfig.class);\n\n        // load dubbo.monitors.xxx\n        loadConfigsOfTypeFromProps(MonitorConfig.class);\n\n        // load dubbo.metrics.xxx\n        loadConfigsOfTypeFromProps(MetricsConfig.class);\n\n        // load dubbo.tracing.xxx\n        loadConfigsOfTypeFromProps(TracingConfig.class);\n\n        // load multiple config types:\n        // load dubbo.protocols.xxx\n        loadConfigsOfTypeFromProps(ProtocolConfig.class);\n\n        // load dubbo.registries.xxx\n        loadConfigsOfTypeFromProps(RegistryConfig.class);\n\n        // load dubbo.metadata-report.xxx\n        loadConfigsOfTypeFromProps(MetadataReportConfig.class);\n\n        // config centers has been loaded before starting config center\n        // loadConfigsOfTypeFromProps(ConfigCenterConfig.class);\n\n        refreshAll();\n\n        checkConfigs();\n\n        // set model name\n        if (StringUtils.isBlank(applicationModel.getModelName())) {\n            applicationModel.setModelName(applicationModel.getApplicationName());\n        }\n    }\n\n    private void checkConfigs() {\n        // check config types (ignore metadata-center)\n        List<Class<? extends AbstractConfig>> multipleConfigTypes = Arrays.asList(\n                ApplicationConfig.class,\n                ProtocolConfig.class,\n                RegistryConfig.class,\n                MonitorConfig.class,\n                MetricsConfig.class,\n                TracingConfig.class,\n                SslConfig.class);\n\n        for (Class<? extends AbstractConfig> configType : multipleConfigTypes) {\n            checkDefaultAndValidateConfigs(configType);\n        }\n\n        // check port conflicts\n        Map<Integer, ProtocolConfig> protocolPortMap = new LinkedHashMap<>();\n        for (ProtocolConfig protocol : getProtocols()) {\n            Integer port = protocol.getPort();\n            if (port == null || port == -1) {\n                continue;\n            }\n            ProtocolConfig prevProtocol = protocolPortMap.get(port);\n            if (prevProtocol != null) {\n                throw new IllegalStateException(\"Duplicated port used by protocol configs, port: \" + port\n                        + \", configs: \" + Arrays.asList(prevProtocol, protocol));\n            }\n            protocolPortMap.put(port, protocol);\n        }\n\n        // Log the current configurations.\n        logger.info(\"The current configurations or effective configurations are as follows:\");\n        for (Class<? extends AbstractConfig> configType : multipleConfigTypes) {\n            getConfigs(configType).forEach((config) -> logger.info(config.toString()));\n        }\n    }\n\n    public ConfigMode getConfigMode() {\n        return configMode;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigMode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.context;\n\n/**\n * Config processing mode for unique config type, e.g. ApplicationConfig, ModuleConfig, MonitorConfig, SslConfig, MetricsConfig\n * @see ConfigManager#uniqueConfigTypes\n */\npublic enum ConfigMode {\n    /**\n     * Strict mode: accept only one config for unique config type, throw exceptions if found more than one config for a unique config type.\n     */\n    STRICT,\n\n    /**\n     * Override mode: accept last config, override previous config\n     */\n    OVERRIDE,\n\n    /**\n     * Override mode: accept last config, override previous config regardless of whether the attribute of previous config is absent or not\n     */\n    OVERRIDE_ALL,\n\n    /**\n     * Override mode: accept last config, override previous config only when the attribute of previous config is absent\n     */\n    OVERRIDE_IF_ABSENT,\n\n    /**\n     * Ignore mode: accept first config, ignore later configs\n     */\n    IGNORE\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.context;\n\nimport org.apache.dubbo.config.AbstractConfig;\n\npublic interface ConfigValidator {\n\n    void validate(AbstractConfig config);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/context/ModuleConfigManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.context;\n\nimport org.apache.dubbo.common.context.ModuleExt;\nimport org.apache.dubbo.common.extension.DisableInject;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.AbstractInterfaceConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfigBase;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport static java.util.Optional.ofNullable;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\nimport static org.apache.dubbo.config.AbstractConfig.getTagName;\n\n/**\n * Manage configs of module\n */\npublic class ModuleConfigManager extends AbstractConfigManager implements ModuleExt {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ModuleConfigManager.class);\n\n    public static final String NAME = \"moduleConfig\";\n\n    private final Map<String, AbstractInterfaceConfig> serviceConfigCache = new ConcurrentHashMap<>();\n    private final ConfigManager applicationConfigManager;\n\n    public ModuleConfigManager(ModuleModel moduleModel) {\n        super(\n                moduleModel,\n                Arrays.asList(\n                        ModuleConfig.class,\n                        ServiceConfigBase.class,\n                        ReferenceConfigBase.class,\n                        ProviderConfig.class,\n                        ConsumerConfig.class));\n        applicationConfigManager = moduleModel.getApplicationModel().getApplicationConfigManager();\n    }\n\n    // ModuleConfig correlative methods\n\n    @DisableInject\n    public void setModule(ModuleConfig module) {\n        addConfig(module);\n    }\n\n    public Optional<ModuleConfig> getModule() {\n        return ofNullable(getSingleConfig(getTagName(ModuleConfig.class)));\n    }\n\n    // ServiceConfig correlative methods\n\n    public void addService(ServiceConfigBase<?> serviceConfig) {\n        addConfig(serviceConfig);\n    }\n\n    public void addServices(Iterable<ServiceConfigBase<?>> serviceConfigs) {\n        serviceConfigs.forEach(this::addService);\n    }\n\n    public Collection<ServiceConfigBase> getServices() {\n        return getConfigs(getTagName(ServiceConfigBase.class));\n    }\n\n    public <T> ServiceConfigBase<T> getService(String id) {\n        return getConfig(ServiceConfigBase.class, id).orElse(null);\n    }\n\n    // ReferenceConfig correlative methods\n\n    public void addReference(ReferenceConfigBase<?> referenceConfig) {\n        addConfig(referenceConfig);\n    }\n\n    public void addReferences(Iterable<ReferenceConfigBase<?>> referenceConfigs) {\n        referenceConfigs.forEach(this::addReference);\n    }\n\n    public Collection<ReferenceConfigBase<?>> getReferences() {\n        return getConfigs(getTagName(ReferenceConfigBase.class));\n    }\n\n    public <T> ReferenceConfigBase<T> getReference(String id) {\n        return getConfig(ReferenceConfigBase.class, id).orElse(null);\n    }\n\n    public void addProvider(ProviderConfig providerConfig) {\n        addConfig(providerConfig);\n    }\n\n    public void addProviders(Iterable<ProviderConfig> providerConfigs) {\n        providerConfigs.forEach(this::addProvider);\n    }\n\n    public Optional<ProviderConfig> getProvider(String id) {\n        return getConfig(ProviderConfig.class, id);\n    }\n\n    /**\n     * Only allows one default ProviderConfig\n     */\n    public Optional<ProviderConfig> getDefaultProvider() {\n        List<ProviderConfig> providerConfigs = getDefaultConfigs(getConfigsMap(getTagName(ProviderConfig.class)));\n        if (CollectionUtils.isNotEmpty(providerConfigs)) {\n            return Optional.of(providerConfigs.get(0));\n        }\n        return Optional.empty();\n    }\n\n    public Collection<ProviderConfig> getProviders() {\n        return getConfigs(getTagName(ProviderConfig.class));\n    }\n\n    // ConsumerConfig correlative methods\n\n    public void addConsumer(ConsumerConfig consumerConfig) {\n        addConfig(consumerConfig);\n    }\n\n    public void addConsumers(Iterable<ConsumerConfig> consumerConfigs) {\n        consumerConfigs.forEach(this::addConsumer);\n    }\n\n    public Optional<ConsumerConfig> getConsumer(String id) {\n        return getConfig(ConsumerConfig.class, id);\n    }\n\n    /**\n     * Only allows one default ConsumerConfig\n     */\n    public Optional<ConsumerConfig> getDefaultConsumer() {\n        List<ConsumerConfig> consumerConfigs = getDefaultConfigs(getConfigsMap(getTagName(ConsumerConfig.class)));\n        if (CollectionUtils.isNotEmpty(consumerConfigs)) {\n            return Optional.of(consumerConfigs.get(0));\n        }\n        return Optional.empty();\n    }\n\n    public Collection<ConsumerConfig> getConsumers() {\n        return getConfigs(getTagName(ConsumerConfig.class));\n    }\n\n    @Override\n    public void refreshAll() {\n        // refresh all configs here\n        getModule().ifPresent(ModuleConfig::refresh);\n        getProviders().forEach(ProviderConfig::refresh);\n        getConsumers().forEach(ConsumerConfig::refresh);\n\n        getReferences().forEach(ReferenceConfigBase::refresh);\n        getServices().forEach(ServiceConfigBase::refresh);\n    }\n\n    @Override\n    public void clear() {\n        super.clear();\n        this.serviceConfigCache.clear();\n    }\n\n    @Override\n    protected <C extends AbstractConfig> Optional<C> findDuplicatedConfig(Map<String, C> configsMap, C config) {\n        // check duplicated configs\n        // special check service and reference config by unique service name, speed up the processing of large number of\n        // instances\n        if (config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase) {\n            C existedConfig = (C) findDuplicatedInterfaceConfig((AbstractInterfaceConfig) config);\n            if (existedConfig != null) {\n                return Optional.of(existedConfig);\n            }\n        } else {\n            return super.findDuplicatedConfig(configsMap, config);\n        }\n        return Optional.empty();\n    }\n\n    @Override\n    protected <C extends AbstractConfig> boolean removeIfAbsent(C config, Map<String, C> configsMap) {\n        if (super.removeIfAbsent(config, configsMap)) {\n            if (config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase) {\n                removeInterfaceConfig((AbstractInterfaceConfig) config);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * check duplicated ReferenceConfig/ServiceConfig\n     *\n     * @param config\n     */\n    private AbstractInterfaceConfig findDuplicatedInterfaceConfig(AbstractInterfaceConfig config) {\n        String uniqueServiceName;\n        Map<String, AbstractInterfaceConfig> configCache;\n        if (config instanceof ReferenceConfigBase) {\n            return null;\n        } else if (config instanceof ServiceConfigBase) {\n            ServiceConfigBase serviceConfig = (ServiceConfigBase) config;\n            uniqueServiceName = serviceConfig.getUniqueServiceName();\n            configCache = serviceConfigCache;\n        } else {\n            throw new IllegalArgumentException(\n                    \"Illegal type of parameter 'config' : \" + config.getClass().getName());\n        }\n\n        AbstractInterfaceConfig prevConfig = configCache.putIfAbsent(uniqueServiceName, config);\n        if (prevConfig != null) {\n            if (prevConfig == config) {\n                return prevConfig;\n            }\n\n            if (prevConfig.equals(config)) {\n                // Is there any problem with ignoring duplicate and equivalent but different ReferenceConfig instances?\n                if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {\n                    logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"Ignore duplicated and equal config: \" + config);\n                }\n                return prevConfig;\n            }\n\n            String configType = config.getClass().getSimpleName();\n            String msg = \"Found multiple \" + configType + \"s with unique service name [\" + uniqueServiceName\n                    + \"], previous: \" + prevConfig + \", later: \" + config + \". \" + \"There can only be one instance of \"\n                    + configType + \" with the same triple (group, interface, version). \"\n                    + \"If multiple instances are required for the same interface, please use a different group or version.\";\n\n            if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {\n                logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", msg);\n            }\n            if (!this.ignoreDuplicatedInterface) {\n                throw new IllegalStateException(msg);\n            }\n        }\n        return prevConfig;\n    }\n\n    private void removeInterfaceConfig(AbstractInterfaceConfig config) {\n        String uniqueServiceName;\n        Map<String, AbstractInterfaceConfig> configCache;\n        if (config instanceof ReferenceConfigBase) {\n            return;\n        } else if (config instanceof ServiceConfigBase) {\n            ServiceConfigBase serviceConfig = (ServiceConfigBase) config;\n            uniqueServiceName = serviceConfig.getUniqueServiceName();\n            configCache = serviceConfigCache;\n        } else {\n            throw new IllegalArgumentException(\n                    \"Illegal type of parameter 'config' : \" + config.getClass().getName());\n        }\n        configCache.remove(uniqueServiceName, config);\n    }\n\n    @Override\n    public void loadConfigs() {\n        // load dubbo.providers.xxx\n        loadConfigsOfTypeFromProps(ProviderConfig.class);\n\n        // load dubbo.consumers.xxx\n        loadConfigsOfTypeFromProps(ConsumerConfig.class);\n\n        // load dubbo.modules.xxx\n        loadConfigsOfTypeFromProps(ModuleConfig.class);\n\n        // check configs\n        checkDefaultAndValidateConfigs(ProviderConfig.class);\n        checkDefaultAndValidateConfigs(ConsumerConfig.class);\n        checkDefaultAndValidateConfigs(ModuleConfig.class);\n    }\n\n    //\n    // Delegate read application configs\n    //\n\n    public ConfigManager getApplicationConfigManager() {\n        return applicationConfigManager;\n    }\n\n    @Override\n    public <C extends AbstractConfig> Map<String, C> getConfigsMap(Class<C> cls) {\n        if (isSupportConfigType(cls)) {\n            return super.getConfigsMap(cls);\n        } else {\n            // redirect to application ConfigManager\n            return applicationConfigManager.getConfigsMap(cls);\n        }\n    }\n\n    @Override\n    public <C extends AbstractConfig> Collection<C> getConfigs(Class<C> configType) {\n        if (isSupportConfigType(configType)) {\n            return super.getConfigs(configType);\n        } else {\n            return applicationConfigManager.getConfigs(configType);\n        }\n    }\n\n    @Override\n    public <T extends AbstractConfig> Optional<T> getConfig(Class<T> cls, String idOrName) {\n        if (isSupportConfigType(cls)) {\n            return super.getConfig(cls, idOrName);\n        } else {\n            return applicationConfigManager.getConfig(cls, idOrName);\n        }\n    }\n\n    @Override\n    public <C extends AbstractConfig> List<C> getDefaultConfigs(Class<C> cls) {\n        if (isSupportConfigType(cls)) {\n            return super.getDefaultConfigs(cls);\n        } else {\n            return applicationConfigManager.getDefaultConfigs(cls);\n        }\n    }\n\n    public Optional<ApplicationConfig> getApplication() {\n        return applicationConfigManager.getApplication();\n    }\n\n    public Optional<MonitorConfig> getMonitor() {\n        return applicationConfigManager.getMonitor();\n    }\n\n    public Optional<MetricsConfig> getMetrics() {\n        return applicationConfigManager.getMetrics();\n    }\n\n    public Optional<TracingConfig> getTracing() {\n        return applicationConfigManager.getTracing();\n    }\n\n    public Optional<SslConfig> getSsl() {\n        return applicationConfigManager.getSsl();\n    }\n\n    public Optional<Collection<ConfigCenterConfig>> getDefaultConfigCenter() {\n        return applicationConfigManager.getDefaultConfigCenter();\n    }\n\n    public Optional<ConfigCenterConfig> getConfigCenter(String id) {\n        return applicationConfigManager.getConfigCenter(id);\n    }\n\n    public Collection<ConfigCenterConfig> getConfigCenters() {\n        return applicationConfigManager.getConfigCenters();\n    }\n\n    public Collection<MetadataReportConfig> getMetadataConfigs() {\n        return applicationConfigManager.getMetadataConfigs();\n    }\n\n    public Collection<MetadataReportConfig> getDefaultMetadataConfigs() {\n        return applicationConfigManager.getDefaultMetadataConfigs();\n    }\n\n    public Optional<ProtocolConfig> getProtocol(String idOrName) {\n        return applicationConfigManager.getProtocol(idOrName);\n    }\n\n    public List<ProtocolConfig> getDefaultProtocols() {\n        return applicationConfigManager.getDefaultProtocols();\n    }\n\n    public Collection<ProtocolConfig> getProtocols() {\n        return applicationConfigManager.getProtocols();\n    }\n\n    public Optional<RegistryConfig> getRegistry(String id) {\n        return applicationConfigManager.getRegistry(id);\n    }\n\n    public List<RegistryConfig> getDefaultRegistries() {\n        return applicationConfigManager.getDefaultRegistries();\n    }\n\n    public Collection<RegistryConfig> getRegistries() {\n        return applicationConfigManager.getRegistries();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/AggregationConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport java.io.Serializable;\n\n/**\n * Configuration for the metric aggregation.\n */\npublic class AggregationConfig implements Serializable {\n\n    private static final long serialVersionUID = 4878693820314125085L;\n\n    /**\n     * Enable aggregation or not.\n     */\n    private Boolean enabled;\n\n    /**\n     * Enable QPS (Queries Per Second) aggregation or not.\n     */\n    private Boolean enableQps;\n\n    /**\n     * Enable Response Time Percentile (Pxx) aggregation or not.\n     */\n    private Boolean enableRtPxx;\n\n    /**\n     * Enable Response Time aggregation or not.\n     */\n    private Boolean enableRt;\n\n    /**\n     * Enable Request aggregation or not.\n     */\n    private Boolean enableRequest;\n\n    /**\n     * The number of buckets for time window quantile.\n     */\n    private Integer bucketNum;\n\n    /**\n     * The time window in seconds for time window quantile.\n     */\n    private Integer timeWindowSeconds;\n\n    /**\n     * The time window in milliseconds for QPS (Queries Per Second) aggregation.\n     */\n    private Integer qpsTimeWindowMillSeconds;\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public Integer getBucketNum() {\n        return bucketNum;\n    }\n\n    public void setBucketNum(Integer bucketNum) {\n        this.bucketNum = bucketNum;\n    }\n\n    public Integer getTimeWindowSeconds() {\n        return timeWindowSeconds;\n    }\n\n    public void setTimeWindowSeconds(Integer timeWindowSeconds) {\n        this.timeWindowSeconds = timeWindowSeconds;\n    }\n\n    public Boolean getEnableQps() {\n        return enableQps;\n    }\n\n    public void setEnableQps(Boolean enableQps) {\n        this.enableQps = enableQps;\n    }\n\n    public Boolean getEnableRtPxx() {\n        return enableRtPxx;\n    }\n\n    public void setEnableRtPxx(Boolean enableRtPxx) {\n        this.enableRtPxx = enableRtPxx;\n    }\n\n    public Boolean getEnableRt() {\n        return enableRt;\n    }\n\n    public void setEnableRt(Boolean enableRt) {\n        this.enableRt = enableRt;\n    }\n\n    public Boolean getEnableRequest() {\n        return enableRequest;\n    }\n\n    public void setEnableRequest(Boolean enableRequest) {\n        this.enableRequest = enableRequest;\n    }\n\n    public Integer getQpsTimeWindowMillSeconds() {\n        return qpsTimeWindowMillSeconds;\n    }\n\n    public void setQpsTimeWindowMillSeconds(Integer qpsTimeWindowMillSeconds) {\n        this.qpsTimeWindowMillSeconds = qpsTimeWindowMillSeconds;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/BaggageConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport org.apache.dubbo.config.support.Nested;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Configuration for the baggage.\n */\npublic class BaggageConfig implements Serializable {\n\n    private static final long serialVersionUID = -4750259290735346439L;\n\n    /**\n     * Whether baggage is enabled or not.\n     */\n    private Boolean enabled = true;\n\n    /**\n     * Correlation configuration.\n     */\n    @Nested\n    private Correlation correlation = new Correlation();\n\n    /**\n     * List of fields that are referenced the same in-process as it is on the wire.\n     * For example, the field \"x-vcap-request-id\" would be set as-is including the\n     * prefix.\n     */\n    private List<String> remoteFields = new ArrayList<>();\n\n    public BaggageConfig() {}\n\n    public BaggageConfig(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public BaggageConfig(Boolean enabled, Correlation correlation, List<String> remoteFields) {\n        this.enabled = enabled;\n        this.correlation = correlation;\n        this.remoteFields = remoteFields;\n    }\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public Correlation getCorrelation() {\n        return correlation;\n    }\n\n    public void setCorrelation(Correlation correlation) {\n        this.correlation = correlation;\n    }\n\n    public List<String> getRemoteFields() {\n        return remoteFields;\n    }\n\n    public void setRemoteFields(List<String> remoteFields) {\n        this.remoteFields = remoteFields;\n    }\n\n    public static class Correlation implements Serializable {\n\n        /**\n         * Whether to enable correlation of the baggage context with logging contexts.\n         */\n        private boolean enabled = true;\n\n        /**\n         * List of fields that should be correlated with the logging context. That\n         * means that these fields would end up as key-value pairs in e.g. MDC.\n         */\n        private List<String> fields = new ArrayList<>();\n\n        public Correlation() {}\n\n        public Correlation(boolean enabled) {\n            this.enabled = enabled;\n        }\n\n        public Correlation(boolean enabled, List<String> fields) {\n            this.enabled = enabled;\n            this.fields = fields;\n        }\n\n        public boolean isEnabled() {\n            return this.enabled;\n        }\n\n        public void setEnabled(boolean enabled) {\n            this.enabled = enabled;\n        }\n\n        public List<String> getFields() {\n            return this.fields;\n        }\n\n        public void setFields(List<String> fields) {\n            this.fields = fields;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/CorsConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport java.io.Serializable;\n\npublic class CorsConfig implements Serializable {\n\n    private static final long serialVersionUID = -7106481576053641726L;\n\n    /**\n     * A list of origins for which cross-origin requests are allowed. Values may be a specific domain, e.g.\n     * {@code \"https://domain1.com\"}, or the CORS defined special value {@code \"*\"} for all origins.\n     * <p>By default this is not set which means that no origins are allowed.\n     * However, an instance of this class is often initialized further, e.g. for {@code @CrossOrigin}, via\n     * {@code org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.CorsMeta.Builder#applyDefault()}.\n     */\n    private String[] allowedOrigins;\n\n    /**\n     * Set the HTTP methods to allow, e.g. {@code \"GET\"}, {@code \"POST\"},\n     * {@code \"PUT\"}, etc. The special value {@code \"*\"} allows all methods.\n     * <p>If not set, only {@code \"GET\"} and {@code \"HEAD\"} are allowed.\n     * <p>By default this is not set.\n     */\n    private String[] allowedMethods;\n\n    /**\n     * /**\n     * Set the list of headers that a pre-flight request can list as allowed\n     * for use during an actual request. The special value {@code \"*\"} allows\n     * actual requests to send any header.\n     * <p>By default this is not set.\n     */\n    private String[] allowedHeaders;\n\n    /**\n     * Set the list of response headers that an actual response might have\n     * and can be exposed to the client. The special value {@code \"*\"}\n     * allows all headers to be exposed.\n     * <p>By default this is not set.\n     */\n    private String[] exposedHeaders;\n\n    /**\n     * Whether user credentials are supported.\n     * <p>By default this is not set (i.e. user credentials are not supported).\n     */\n    private Boolean allowCredentials;\n\n    /**\n     * Configure how long, as a duration, the response from a pre-flight request\n     * can be cached by clients.\n     */\n    private Long maxAge;\n\n    public String[] getAllowedOrigins() {\n        return allowedOrigins;\n    }\n\n    public void setAllowedOrigins(String[] allowedOrigins) {\n        this.allowedOrigins = allowedOrigins;\n    }\n\n    public String[] getAllowedMethods() {\n        return allowedMethods;\n    }\n\n    public void setAllowedMethods(String[] allowedMethods) {\n        this.allowedMethods = allowedMethods;\n    }\n\n    public String[] getAllowedHeaders() {\n        return allowedHeaders;\n    }\n\n    public void setAllowedHeaders(String[] allowedHeaders) {\n        this.allowedHeaders = allowedHeaders;\n    }\n\n    public String[] getExposedHeaders() {\n        return exposedHeaders;\n    }\n\n    public void setExposedHeaders(String[] exposedHeaders) {\n        this.exposedHeaders = exposedHeaders;\n    }\n\n    public Boolean getAllowCredentials() {\n        return allowCredentials;\n    }\n\n    public void setAllowCredentials(Boolean allowCredentials) {\n        this.allowCredentials = allowCredentials;\n    }\n\n    public Long getMaxAge() {\n        return maxAge;\n    }\n\n    public void setMaxAge(Long maxAge) {\n        this.maxAge = maxAge;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/ExporterConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport org.apache.dubbo.config.support.Nested;\n\nimport java.io.Serializable;\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Configuration for the exporter.\n */\npublic class ExporterConfig implements Serializable {\n\n    private static final long serialVersionUID = -559392305178067845L;\n\n    /**\n     * Configuration for the Zipkin.\n     */\n    @Nested\n    private ZipkinConfig zipkinConfig;\n\n    /**\n     * Configuration for the OTLP.\n     */\n    @Nested\n    private OtlpConfig otlpConfig;\n\n    public ZipkinConfig getZipkinConfig() {\n        return zipkinConfig;\n    }\n\n    public void setZipkinConfig(ZipkinConfig zipkinConfig) {\n        this.zipkinConfig = zipkinConfig;\n    }\n\n    public OtlpConfig getOtlpConfig() {\n        return otlpConfig;\n    }\n\n    public void setOtlpConfig(OtlpConfig otlpConfig) {\n        this.otlpConfig = otlpConfig;\n    }\n\n    public static class ZipkinConfig implements Serializable {\n\n        /**\n         * URL to the Zipkin API.\n         */\n        private String endpoint;\n\n        /**\n         * Connection timeout for requests to Zipkin. (seconds)\n         */\n        private Duration connectTimeout = Duration.ofSeconds(1);\n\n        /**\n         * Read timeout for requests to Zipkin. (seconds)\n         */\n        private Duration readTimeout = Duration.ofSeconds(10);\n\n        public ZipkinConfig() {}\n\n        public ZipkinConfig(String endpoint) {\n            this.endpoint = endpoint;\n        }\n\n        public ZipkinConfig(String endpoint, Duration connectTimeout, Duration readTimeout) {\n            this.endpoint = endpoint;\n            this.connectTimeout = connectTimeout;\n            this.readTimeout = readTimeout;\n        }\n\n        public String getEndpoint() {\n            return endpoint;\n        }\n\n        public void setEndpoint(String endpoint) {\n            this.endpoint = endpoint;\n        }\n\n        public Duration getConnectTimeout() {\n            return connectTimeout;\n        }\n\n        public void setConnectTimeout(Duration connectTimeout) {\n            this.connectTimeout = connectTimeout;\n        }\n\n        public Duration getReadTimeout() {\n            return readTimeout;\n        }\n\n        public void setReadTimeout(Duration readTimeout) {\n            this.readTimeout = readTimeout;\n        }\n    }\n\n    public static class OtlpConfig implements Serializable {\n\n        /**\n         * URL to the Otlp API.\n         */\n        private String endpoint;\n\n        /**\n         * The maximum time to wait for the collector to process an exported batch of spans. (seconds)\n         */\n        private Duration timeout = Duration.ofSeconds(10);\n\n        /**\n         * The method used to compress payloads. If unset, compression is disabled. Currently\n         * supported compression methods include \"gzip\" and \"none\".\n         */\n        private String compressionMethod = \"none\";\n\n        private Map<String, String> headers = new HashMap<>();\n\n        public OtlpConfig() {}\n\n        public OtlpConfig(String endpoint) {\n            this.endpoint = endpoint;\n        }\n\n        public OtlpConfig(String endpoint, Duration timeout) {\n            this.endpoint = endpoint;\n            this.timeout = timeout;\n        }\n\n        public OtlpConfig(String endpoint, Duration timeout, String compressionMethod) {\n            this.endpoint = endpoint;\n            this.timeout = timeout;\n            this.compressionMethod = compressionMethod;\n        }\n\n        public String getEndpoint() {\n            return endpoint;\n        }\n\n        public void setEndpoint(String endpoint) {\n            this.endpoint = endpoint;\n        }\n\n        public Duration getTimeout() {\n            return timeout;\n        }\n\n        public void setTimeout(Duration timeout) {\n            this.timeout = timeout;\n        }\n\n        public String getCompressionMethod() {\n            return compressionMethod;\n        }\n\n        public void setCompressionMethod(String compressionMethod) {\n            this.compressionMethod = compressionMethod;\n        }\n\n        public Map<String, String> getHeaders() {\n            return headers;\n        }\n\n        public void setHeaders(Map<String, String> headers) {\n            this.headers = headers;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/HistogramConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport java.io.Serializable;\n\n/**\n * Configuration for the histogram.\n */\npublic class HistogramConfig implements Serializable {\n\n    private static final long serialVersionUID = 8152538916051803031L;\n\n    /**\n     * Whether histograms are enabled or not. Default is not enabled (false).\n     */\n    private Boolean enabled;\n\n    /**\n     * Buckets in milliseconds for the histograms. Defines the histogram bucket boundaries.\n     */\n    private Integer[] bucketsMs;\n\n    /**\n     * Minimum expected value in milliseconds for the histograms. Values lower than this will be considered outliers.\n     */\n    private Integer minExpectedMs;\n\n    /**\n     * Maximum expected value in milliseconds for the histograms. Values higher than this will be considered outliers.\n     */\n    private Integer maxExpectedMs;\n\n    /**\n     * Whether enabledPercentiles are enabled or not. Default is not enabled (false).\n     */\n    private Boolean enabledPercentiles;\n\n    /**\n     * Array of percentiles to be calculated for the histograms. Each percentile is a double value.\n     */\n    private double[] percentiles;\n\n    /**\n     * Expiry time in minutes for distribution statistics. After this time, the statistics are expired.\n     */\n    private Integer distributionStatisticExpiryMin;\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public Integer[] getBucketsMs() {\n        return bucketsMs;\n    }\n\n    public void setBucketsMs(Integer[] bucketsMs) {\n        this.bucketsMs = bucketsMs;\n    }\n\n    public Integer getMinExpectedMs() {\n        return minExpectedMs;\n    }\n\n    public void setMinExpectedMs(Integer minExpectedMs) {\n        this.minExpectedMs = minExpectedMs;\n    }\n\n    public Integer getMaxExpectedMs() {\n        return maxExpectedMs;\n    }\n\n    public void setMaxExpectedMs(Integer maxExpectedMs) {\n        this.maxExpectedMs = maxExpectedMs;\n    }\n\n    public Boolean getEnabledPercentiles() {\n        return enabledPercentiles;\n    }\n\n    public void setEnabledPercentiles(Boolean enabledPercentiles) {\n        this.enabledPercentiles = enabledPercentiles;\n    }\n\n    public double[] getPercentiles() {\n        return percentiles;\n    }\n\n    public void setPercentiles(double[] percentiles) {\n        this.percentiles = percentiles;\n    }\n\n    public Integer getDistributionStatisticExpiryMin() {\n        return distributionStatisticExpiryMin;\n    }\n\n    public void setDistributionStatisticExpiryMin(Integer distributionStatisticExpiryMin) {\n        this.distributionStatisticExpiryMin = distributionStatisticExpiryMin;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/Http3Config.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport org.apache.dubbo.config.support.Parameter;\n\nimport java.io.Serializable;\n\npublic class Http3Config implements Serializable {\n\n    private static final long serialVersionUID = -4443828713331129834L;\n\n    public static final int DEFAULT_INITIAL_MAX_DATA = 8_388_608;\n    public static final int DEFAULT_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = 1_048_576;\n    public static final int DEFAULT_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE = 1_048_576;\n    public static final int DEFAULT_INITIAL_MAX_STREAM_DATA_UNI = 1_048_576;\n    public static final long DEFAULT_INITIAL_MAX_STREAMS_BIDI = 1_073_741_824;\n    public static final long DEFAULT_INITIAL_MAX_STREAMS_UNI = 1_073_741_824;\n\n    /**\n     * Whether to enable HTTP/3 support\n     * <p>The default value is false.\n     */\n    private Boolean enabled;\n\n    /**\n     * Whether to enable HTTP/3 negotiation\n     * If set to false, HTTP/2 alt-svc negotiation will be skipped, enabling HTTP/3 but disabling HTTP/2 on the consumer side.\n     * <p>The default value is true.\n     */\n    private Boolean negotiation;\n\n    /**\n     * See <a href=\"https://docs.rs/quiche/0.6.0/quiche/struct.Config.html#method.set_initial_max_data\">set_initial_max_data</a>.\n     * <p>The default value is 8MiB.\n     */\n    private Integer initialMaxData;\n\n    /**\n     * If configured this will enable <a href=\"https://tools.ietf.org/html/draft-ietf-quic-datagram-01\">Datagram support.</a>\n     */\n    private Integer recvQueueLen;\n\n    /**\n     * If configured this will enable <a href=\"https://tools.ietf.org/html/draft-ietf-quic-datagram-01\">Datagram support.</a>\n     */\n    private Integer sendQueueLen;\n\n    /**\n     * See\n     * <a href=\"https://docs.rs/quiche/0.6.0/quiche/struct.Config.html#method.set_initial_max_stream_data_bidi_local\">set_initial_max_stream_data_bidi_local</a>.\n     * <p>The default value is 1MiB.\n     */\n    private Integer initialMaxStreamDataBidiLocal;\n\n    /**\n     * See\n     * <a href=\"https://docs.rs/quiche/0.6.0/quiche/struct.Config.html#method.set_initial_max_stream_data_bidi_remote\">set_initial_max_stream_data_bidi_remote</a>.\n     * <p>The default value is 1MiB.\n     */\n    private Integer initialMaxStreamDataBidiRemote;\n\n    /**\n     * See\n     * <a href=\"https://docs.rs/quiche/0.6.0/quiche/struct.Config.html#method.set_initial_max_stream_data_uni\">set_initial_max_stream_data_uni</a>.\n     * <p>The default value is 0.\n     */\n    private Integer initialMaxStreamDataUni;\n\n    /**\n     * See\n     * <a href=\"https://docs.rs/quiche/0.6.0/quiche/struct.Config.html#method.set_initial_max_streams_bidi\">set_initial_max_streams_bidi</a>.\n     * <p>The default value is 1B(2^30).\n     */\n    private Long initialMaxStreamsBidi;\n\n    /**\n     * See\n     * <a href=\"https://docs.rs/quiche/0.6.0/quiche/struct.Config.html#method.set_initial_max_streams_uni\">set_initial_max_streams_uni</a>.\n     * <p>\n     * <p>The default value is 1B(2^30).\n     */\n    private Long initialMaxStreamsUni;\n\n    /**\n     * See\n     * <a href=\"https://docs.rs/quiche/0.6.0/quiche/struct.Config.html#method.set_ack_delay_exponent\">set_ack_delay_exponent</a>.\n     * <p>The default value is 3.\n     */\n    private Integer maxAckDelayExponent;\n\n    /**\n     * See\n     * <a href=\"https://docs.rs/quiche/0.6.0/quiche/struct.Config.html#method.set_max_ack_delay\">set_max_ack_delay</a>.\n     * <p>The default value is 25 milliseconds.\n     */\n    private Integer maxAckDelay;\n\n    /**\n     * See\n     * <a href=\"https://docs.rs/quiche/0.6.0/quiche/struct.Config.html#method.set_disable_active_migration\">set_disable_active_migration</a>.\n     * <p>The default value is {@code false}.\n     */\n    private Boolean disableActiveMigration;\n\n    /**\n     * See\n     * <a href=\"https://docs.rs/quiche/0.6.0/quiche/struct.Config.html#method.enable_hystart\">enable_hystart</a>.\n     * <p>The default value is {@code true}.\n     */\n    private Boolean enableHystart;\n\n    /**\n     * Sets the congestion control algorithm to use.\n     * <p>Supported algorithms are {@code \"RENO\"} or {@code \"CUBIC\"} or {@code \"BBR\"}.\n     * <p>The default value is {@code \"CUBIC\"}.\n     */\n    private String ccAlgorithm;\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public Boolean getNegotiation() {\n        return negotiation;\n    }\n\n    public void setNegotiation(Boolean negotiation) {\n        this.negotiation = negotiation;\n    }\n\n    public Integer getInitialMaxData() {\n        return initialMaxData;\n    }\n\n    @Parameter(excluded = true)\n    public int getInitialMaxDataOrDefault() {\n        return initialMaxData == null ? DEFAULT_INITIAL_MAX_DATA : initialMaxData;\n    }\n\n    public void setInitialMaxData(Integer initialMaxData) {\n        this.initialMaxData = initialMaxData;\n    }\n\n    public Integer getRecvQueueLen() {\n        return recvQueueLen;\n    }\n\n    public void setRecvQueueLen(Integer recvQueueLen) {\n        this.recvQueueLen = recvQueueLen;\n    }\n\n    public Integer getSendQueueLen() {\n        return sendQueueLen;\n    }\n\n    public void setSendQueueLen(Integer sendQueueLen) {\n        this.sendQueueLen = sendQueueLen;\n    }\n\n    public Integer getInitialMaxStreamDataBidiLocal() {\n        return initialMaxStreamDataBidiLocal;\n    }\n\n    @Parameter(excluded = true)\n    public int getInitialMaxStreamDataBidiLocalOrDefault() {\n        return initialMaxStreamDataBidiLocal == null\n                ? DEFAULT_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL\n                : initialMaxStreamDataBidiLocal;\n    }\n\n    public void setInitialMaxStreamDataBidiLocal(Integer initialMaxStreamDataBidiLocal) {\n        this.initialMaxStreamDataBidiLocal = initialMaxStreamDataBidiLocal;\n    }\n\n    public Integer getInitialMaxStreamDataBidiRemote() {\n        return initialMaxStreamDataBidiRemote;\n    }\n\n    @Parameter(excluded = true)\n    public int getInitialMaxStreamDataBidiRemoteOrDefault() {\n        return initialMaxStreamDataBidiRemote == null\n                ? DEFAULT_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE\n                : initialMaxStreamDataBidiRemote;\n    }\n\n    public void setInitialMaxStreamDataBidiRemote(Integer initialMaxStreamDataBidiRemote) {\n        this.initialMaxStreamDataBidiRemote = initialMaxStreamDataBidiRemote;\n    }\n\n    public Integer getInitialMaxStreamDataUni() {\n        return initialMaxStreamDataUni;\n    }\n\n    @Parameter(excluded = true)\n    public int getInitialMaxStreamDataUniOrDefault() {\n        return initialMaxStreamDataUni == null ? DEFAULT_INITIAL_MAX_STREAM_DATA_UNI : initialMaxStreamDataUni;\n    }\n\n    public void setInitialMaxStreamDataUni(Integer initialMaxStreamDataUni) {\n        this.initialMaxStreamDataUni = initialMaxStreamDataUni;\n    }\n\n    public Long getInitialMaxStreamsBidi() {\n        return initialMaxStreamsBidi;\n    }\n\n    @Parameter(excluded = true)\n    public long getInitialMaxStreamsBidiOrDefault() {\n        return initialMaxStreamsBidi == null ? DEFAULT_INITIAL_MAX_STREAMS_BIDI : initialMaxStreamsBidi;\n    }\n\n    public void setInitialMaxStreamsBidi(Long initialMaxStreamsBidi) {\n        this.initialMaxStreamsBidi = initialMaxStreamsBidi;\n    }\n\n    public Long getInitialMaxStreamsUni() {\n        return initialMaxStreamsUni;\n    }\n\n    @Parameter(excluded = true)\n    public long getInitialMaxStreamsUniOrDefault() {\n        return initialMaxStreamsUni == null ? DEFAULT_INITIAL_MAX_STREAMS_UNI : initialMaxStreamsUni;\n    }\n\n    public void setInitialMaxStreamsUni(Long initialMaxStreamsUni) {\n        this.initialMaxStreamsUni = initialMaxStreamsUni;\n    }\n\n    public Integer getMaxAckDelayExponent() {\n        return maxAckDelayExponent;\n    }\n\n    public void setMaxAckDelayExponent(Integer maxAckDelayExponent) {\n        this.maxAckDelayExponent = maxAckDelayExponent;\n    }\n\n    public Integer getMaxAckDelay() {\n        return maxAckDelay;\n    }\n\n    public void setMaxAckDelay(Integer maxAckDelay) {\n        this.maxAckDelay = maxAckDelay;\n    }\n\n    public Boolean getDisableActiveMigration() {\n        return disableActiveMigration;\n    }\n\n    public void setDisableActiveMigration(Boolean disableActiveMigration) {\n        this.disableActiveMigration = disableActiveMigration;\n    }\n\n    public Boolean getEnableHystart() {\n        return enableHystart;\n    }\n\n    public void setEnableHystart(Boolean enableHystart) {\n        this.enableHystart = enableHystart;\n    }\n\n    public String getCcAlgorithm() {\n        return ccAlgorithm;\n    }\n\n    public void setCcAlgorithm(String ccAlgorithm) {\n        this.ccAlgorithm = ccAlgorithm;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/McpConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport org.apache.dubbo.config.support.Nested;\n\nimport java.io.Serializable;\n\npublic class McpConfig implements Serializable {\n\n    private static final long serialVersionUID = 6943417856234001947L;\n\n    /**\n     * Whether to enable MCP Server support\n     * <p>The default value is 'true'.\n     */\n    private Boolean enabled;\n\n    /**\n     * The port of MCP Server\n     * <p>The default value is '0'.\n     */\n    private Integer port;\n\n    /**\n     * the path of mcp\n     */\n    @Nested\n    private MCPPath path;\n\n    /**\n     * streamable or sse\n     */\n    private String protocol;\n\n    /**\n     * Session timeout in milliseconds for long connection\n     * unit: seconds\n     */\n    private Integer sessionTimeout;\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public Integer getPort() {\n        return port;\n    }\n\n    public void setPort(Integer port) {\n        this.port = port;\n    }\n\n    public MCPPath getPath() {\n        return path;\n    }\n\n    public void setPath(MCPPath path) {\n        this.path = path;\n    }\n\n    public String getProtocol() {\n        return protocol;\n    }\n\n    public void setProtocol(String protocol) {\n        this.protocol = protocol;\n    }\n\n    public Integer getSessionTimeout() {\n        return sessionTimeout;\n    }\n\n    public void setSessionTimeout(Integer sessionTimeout) {\n        this.sessionTimeout = sessionTimeout;\n    }\n\n    public static class MCPPath implements Serializable {\n\n        private static final long serialVersionUID = 6943417856234837947L;\n\n        /**\n         * The path of mcp message\n         * <p>The default value is '/mcp/message'.\n         */\n        private String message;\n\n        /**\n         * The path of mcp sse\n         * <p>The default value is '/mcp/sse'.\n         */\n        private String sse;\n\n        public String getMessage() {\n            return message;\n        }\n\n        public void setMessage(String message) {\n            this.message = message;\n        }\n\n        public String getSse() {\n            return sse;\n        }\n\n        public void setSse(String sse) {\n            this.sse = sse;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport java.io.Serializable;\nimport java.util.Map;\n\npublic class OpenAPIConfig implements Serializable {\n\n    private static final long serialVersionUID = 6943417456345001947L;\n\n    /**\n     * Whether to enable OpenAPI support\n     * <p>The default value is 'true'.\n     */\n    private Boolean enabled;\n\n    /**\n     * Whether to cache the OpenAPI document.\n     * <p>The default value is 'true'.\n     */\n    private Boolean cache;\n\n    /**\n     * The HTTP path where OpenAPI will be registered.\n     * <p>The default value is '/dubbo/openapi'.\n     */\n    private String path;\n\n    /**\n     * The title of the OpenAPI information.\n     */\n    private String infoTitle;\n\n    /**\n     * A brief description of the OpenAPI information.\n     */\n    private String infoDescription;\n\n    /**\n     * The version number of the OpenAPI information.\n     */\n    private String infoVersion;\n\n    /**\n     * The name of the contact.\n     */\n    private String infoContactName;\n\n    /**\n     * The url of the contact.\n     */\n    private String infoContactUrl;\n\n    /**\n     * The email address of the contact.\n     */\n    private String infoContactEmail;\n\n    /**\n     * A description of the external documentation.\n     */\n    private String externalDocsDescription;\n\n    /**\n     * The URL of the external documentation.\n     */\n    private String externalDocsUrl;\n\n    /**\n     * A list of servers.\n     */\n    private String[] servers;\n\n    /**\n     * The security scheme.\n     */\n    private String securityScheme;\n\n    /**\n     * The security.\n     */\n    private String security;\n\n    /**\n     * The strategy used to generate operation id and schema name.\n     */\n    private String nameStrategy;\n\n    /**\n     * The default media types that are consumed.\n     */\n    private String[] defaultConsumesMediaTypes;\n\n    /**\n     * The default media types that are produced.\n     */\n    private String[] defaultProducesMediaTypes;\n\n    /**\n     * The default HTTP methods are used.\n     */\n    private String[] defaultHttpMethods;\n\n    /**\n     * The default HTTP status codes are returned.\n     */\n    private String[] defaultHttpStatusCodes;\n\n    /**\n     * Whether to flatten the inherited fields from the parent class into the schema.\n     * <p>The default value is {@code false}.\n     */\n    private Boolean schemaFlatten;\n\n    /**\n     * Specifies the classes to be excluded from schema generation.\n     * <p>For example:\n     * <ul>\n     *     <li>com.example.MyClass - Exclude the MyClass class.</li>\n     *     <li>com.example. - Exclude all classes in the com.example package.</li>\n     *     <li>!com.example.exclude. - Exclude all classes except those in the com.example.exclude package.</li>\n     * </ul>\n     * Note that the package name should end with a dot (.) or an exclamation mark (!) to indicate the exclusion scope.\n     * <p>Multiple classes or package names can be separated by commas, for\n     * example: com.example.MyClass,com.example.,!com.example.exclude\n     */\n    private String[] schemaClassExcludes;\n\n    /**\n     * The custom settings.\n     */\n    private Map<String, String> settings;\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public Boolean getCache() {\n        return cache;\n    }\n\n    public void setCache(Boolean cache) {\n        this.cache = cache;\n    }\n\n    public String getPath() {\n        return path;\n    }\n\n    public void setPath(String path) {\n        this.path = path;\n    }\n\n    public String getInfoTitle() {\n        return infoTitle;\n    }\n\n    public void setInfoTitle(String infoTitle) {\n        this.infoTitle = infoTitle;\n    }\n\n    public String getInfoDescription() {\n        return infoDescription;\n    }\n\n    public void setInfoDescription(String infoDescription) {\n        this.infoDescription = infoDescription;\n    }\n\n    public String getInfoVersion() {\n        return infoVersion;\n    }\n\n    public void setInfoVersion(String infoVersion) {\n        this.infoVersion = infoVersion;\n    }\n\n    public String getInfoContactName() {\n        return infoContactName;\n    }\n\n    public void setInfoContactName(String infoContactName) {\n        this.infoContactName = infoContactName;\n    }\n\n    public String getInfoContactUrl() {\n        return infoContactUrl;\n    }\n\n    public void setInfoContactUrl(String infoContactUrl) {\n        this.infoContactUrl = infoContactUrl;\n    }\n\n    public String getInfoContactEmail() {\n        return infoContactEmail;\n    }\n\n    public void setInfoContactEmail(String infoContactEmail) {\n        this.infoContactEmail = infoContactEmail;\n    }\n\n    public String getExternalDocsDescription() {\n        return externalDocsDescription;\n    }\n\n    public void setExternalDocsDescription(String externalDocsDescription) {\n        this.externalDocsDescription = externalDocsDescription;\n    }\n\n    public String getExternalDocsUrl() {\n        return externalDocsUrl;\n    }\n\n    public void setExternalDocsUrl(String externalDocsUrl) {\n        this.externalDocsUrl = externalDocsUrl;\n    }\n\n    public String[] getServers() {\n        return servers;\n    }\n\n    public void setServers(String[] servers) {\n        this.servers = servers;\n    }\n\n    public String getSecurityScheme() {\n        return securityScheme;\n    }\n\n    public void setSecurityScheme(String securityScheme) {\n        this.securityScheme = securityScheme;\n    }\n\n    public String getSecurity() {\n        return security;\n    }\n\n    public void setSecurity(String security) {\n        this.security = security;\n    }\n\n    public String getNameStrategy() {\n        return nameStrategy;\n    }\n\n    public void setNameStrategy(String nameStrategy) {\n        this.nameStrategy = nameStrategy;\n    }\n\n    public String[] getDefaultConsumesMediaTypes() {\n        return defaultConsumesMediaTypes;\n    }\n\n    public void setDefaultConsumesMediaTypes(String[] defaultConsumesMediaTypes) {\n        this.defaultConsumesMediaTypes = defaultConsumesMediaTypes;\n    }\n\n    public String[] getDefaultProducesMediaTypes() {\n        return defaultProducesMediaTypes;\n    }\n\n    public void setDefaultProducesMediaTypes(String[] defaultProducesMediaTypes) {\n        this.defaultProducesMediaTypes = defaultProducesMediaTypes;\n    }\n\n    public String[] getDefaultHttpMethods() {\n        return defaultHttpMethods;\n    }\n\n    public void setDefaultHttpMethods(String[] defaultHttpMethods) {\n        this.defaultHttpMethods = defaultHttpMethods;\n    }\n\n    public String[] getDefaultHttpStatusCodes() {\n        return defaultHttpStatusCodes;\n    }\n\n    public void setDefaultHttpStatusCodes(String[] defaultHttpStatusCodes) {\n        this.defaultHttpStatusCodes = defaultHttpStatusCodes;\n    }\n\n    public Boolean getSchemaFlatten() {\n        return schemaFlatten;\n    }\n\n    public void setSchemaFlatten(Boolean schemaFlatten) {\n        this.schemaFlatten = schemaFlatten;\n    }\n\n    public String[] getSchemaClassExcludes() {\n        return schemaClassExcludes;\n    }\n\n    public void setSchemaClassExcludes(String[] schemaClassExcludes) {\n        this.schemaClassExcludes = schemaClassExcludes;\n    }\n\n    public Map<String, String> getSettings() {\n        return settings;\n    }\n\n    public void setSettings(Map<String, String> settings) {\n        this.settings = settings;\n    }\n\n    public String getSetting(String key) {\n        return settings == null ? null : settings.get(key);\n    }\n\n    public String getSetting(String key, String defaultValue) {\n        return settings == null ? defaultValue : settings.getOrDefault(key, defaultValue);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/OtlpMetricConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport java.io.Serializable;\nimport java.time.Duration;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\npublic class OtlpMetricConfig implements Serializable {\n\n    /**\n     * URI of the OLTP server.\n     */\n    private String endpoint;\n\n    /**\n     * Monitored resource's attributes.\n     */\n    private Map<String, String> resourceAttributes;\n\n    /**\n     * Headers for the exported metrics.\n     */\n    private Map<String, String> headers;\n\n    /**\n     * Time unit for exported metrics.\n     */\n    private TimeUnit baseTimeUnit = TimeUnit.MILLISECONDS;\n\n    /**\n     * Intervals for pushing metrics\n     */\n    private Duration step;\n\n    public String getEndpoint() {\n        return this.endpoint;\n    }\n\n    public void setUrl(String endpoint) {\n        this.endpoint = endpoint;\n    }\n\n    public Map<String, String> getResourceAttributes() {\n        return this.resourceAttributes;\n    }\n\n    public void setResourceAttributes(Map<String, String> resourceAttributes) {\n        this.resourceAttributes = resourceAttributes;\n    }\n\n    public Map<String, String> getHeaders() {\n        return this.headers;\n    }\n\n    public void setHeaders(Map<String, String> headers) {\n        this.headers = headers;\n    }\n\n    public TimeUnit getBaseTimeUnit() {\n        return this.baseTimeUnit;\n    }\n\n    public void setBaseTimeUnit(TimeUnit baseTimeUnit) {\n        this.baseTimeUnit = baseTimeUnit;\n    }\n\n    public Duration getStep() {\n        return this.step;\n    }\n\n    public void setStep(Duration step) {\n        this.step = step;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/PrometheusConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport org.apache.dubbo.config.support.Nested;\n\nimport java.io.Serializable;\n\n/**\n * Configuration for the prometheus.\n */\npublic class PrometheusConfig implements Serializable {\n\n    private static final long serialVersionUID = 2238807632335823129L;\n\n    /**\n     * Prometheus exporter configuration\n     */\n    @Nested\n    private Exporter exporter;\n\n    /**\n     * Prometheus push gateway configuration\n     */\n    @Nested\n    private Pushgateway pushgateway;\n\n    public Exporter getExporter() {\n        return exporter;\n    }\n\n    public void setExporter(Exporter exporter) {\n        this.exporter = exporter;\n    }\n\n    public Pushgateway getPushgateway() {\n        return pushgateway;\n    }\n\n    public void setPushgateway(Pushgateway pushgateway) {\n        this.pushgateway = pushgateway;\n    }\n\n    public static class Exporter implements Serializable {\n\n        /**\n         * Enable prometheus exporter\n         */\n        private Boolean enabled;\n\n        /**\n         * Enable http service discovery for prometheus\n         */\n        private Boolean enableHttpServiceDiscovery;\n\n        /**\n         * Http service discovery url\n         */\n        private String httpServiceDiscoveryUrl;\n\n        public Boolean getEnabled() {\n            return enabled;\n        }\n\n        public void setEnabled(Boolean enabled) {\n            this.enabled = enabled;\n        }\n\n        public Boolean getEnableHttpServiceDiscovery() {\n            return enableHttpServiceDiscovery;\n        }\n\n        public void setEnableHttpServiceDiscovery(Boolean enableHttpServiceDiscovery) {\n            this.enableHttpServiceDiscovery = enableHttpServiceDiscovery;\n        }\n\n        public String getHttpServiceDiscoveryUrl() {\n            return httpServiceDiscoveryUrl;\n        }\n\n        public void setHttpServiceDiscoveryUrl(String httpServiceDiscoveryUrl) {\n            this.httpServiceDiscoveryUrl = httpServiceDiscoveryUrl;\n        }\n    }\n\n    public static class Pushgateway implements Serializable {\n\n        /**\n         * Enable publishing via a Prometheus Pushgateway\n         */\n        private Boolean enabled;\n\n        /**\n         * Base URL for the Pushgateway\n         */\n        private String baseUrl;\n\n        /**\n         * Login user of the Prometheus Pushgateway\n         */\n        private String username;\n\n        /**\n         * Login password of the Prometheus Pushgateway\n         */\n        private String password;\n\n        /**\n         * Frequency with which to push metrics\n         */\n        private Integer pushInterval;\n\n        /**\n         * Job identifier for this application instance\n         */\n        private String job;\n\n        public Boolean getEnabled() {\n            return enabled;\n        }\n\n        public void setEnabled(Boolean enabled) {\n            this.enabled = enabled;\n        }\n\n        public String getBaseUrl() {\n            return baseUrl;\n        }\n\n        public void setBaseUrl(String baseUrl) {\n            this.baseUrl = baseUrl;\n        }\n\n        public String getUsername() {\n            return username;\n        }\n\n        public void setUsername(String username) {\n            this.username = username;\n        }\n\n        public String getPassword() {\n            return password;\n        }\n\n        public void setPassword(String password) {\n            this.password = password;\n        }\n\n        public Integer getPushInterval() {\n            return pushInterval;\n        }\n\n        public void setPushInterval(Integer pushInterval) {\n            this.pushInterval = pushInterval;\n        }\n\n        public String getJob() {\n            return job;\n        }\n\n        public void setJob(String job) {\n            this.job = job;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/PropagationConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport java.io.Serializable;\n\n/**\n * Configuration for the propagation.\n */\npublic class PropagationConfig implements Serializable {\n\n    private static final long serialVersionUID = -2570106396211532046L;\n\n    public static final String B3 = \"B3\";\n\n    public static final String W3C = \"W3C\";\n\n    /**\n     * Tracing context propagation type.\n     */\n    private String type = W3C;\n\n    public PropagationConfig() {}\n\n    public PropagationConfig(String type) {\n        this.type = type;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport org.apache.dubbo.config.support.Nested;\nimport org.apache.dubbo.config.support.Parameter;\n\nimport java.io.Serializable;\nimport java.util.Map;\n\n/**\n * Configuration for triple rest protocol.\n */\npublic class RestConfig implements Serializable {\n\n    private static final long serialVersionUID = -8068568976367034755L;\n\n    public static final boolean DEFAULT_TRAILING_SLASH_MATCH = true;\n    public static final boolean DEFAULT_SUFFIX_PATTERN_MATCH = true;\n    public static final boolean DEFAULT_CASE_SENSITIVE_MATCH = true;\n    public static final String DEFAULT_FORMAT_PARAMETER_NAME = \"format\";\n\n    /**\n     * Whether to enable rest support\n     * <p>The default value is 'true'.\n     */\n    private Boolean enabled;\n\n    /**\n     *  Whether to enable the default mapping '/{interfaceName}/{methodName}'.\n     * <p>The default value is 'true'.\n     */\n    private Boolean enableDefaultMapping;\n\n    /**\n     * Whether path matching should be match paths with a trailing slash.\n     * If enabled, a method mapped to \"/users\" also matches to \"/users/\".\n     * <p>The default value is {@code true}.\n     */\n    private Boolean trailingSlashMatch;\n\n    /**\n     * Whether path matching uses suffix pattern matching (\".*\").\n     * If enabled, a method mapped to \"/users\" also matches to \"/users.*\".\n     * <p>This also enables suffix content negotiation, with the media-type\n     * inferred from the URL suffix, e.g., \".json\" for \"application/json\".\n     * <p>The default value is {@code true}.\n     */\n    private Boolean suffixPatternMatch;\n\n    /**\n     * Whether path matching should be case-sensitive.\n     * If enabled, a method mapped to \"/users\" won't match to \"/Users/\".\n     * <p>The default value is {@code true}.\n     */\n    private Boolean caseSensitiveMatch;\n\n    /**\n     * The parameter name that can be used to specify the response format.\n     * <p>The default value is 'format'.\n     */\n    private String formatParameterName;\n\n    /**\n     * The json framework to use, make sure that dependencies are imported.\n     */\n    private String jsonFramework;\n\n    /**\n     * The disallowed content-types.\n     */\n    private String[] disallowedContentTypes;\n\n    /**\n     *  The cors configuration.\n     */\n    @Nested\n    private CorsConfig cors;\n\n    /**\n     * The openapi configuration.\n     */\n    @Nested\n    private OpenAPIConfig openapi;\n\n    /**\n     * The Mcp configuration.\n     */\n    @Nested\n    private McpConfig mcp;\n\n    /**\n     * Multiple configurations for openapi.\n     */\n    private Map<String, OpenAPIConfig> openapis;\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public Boolean getEnableDefaultMapping() {\n        return enableDefaultMapping;\n    }\n\n    public void setEnableDefaultMapping(Boolean enableDefaultMapping) {\n        this.enableDefaultMapping = enableDefaultMapping;\n    }\n\n    public Boolean getTrailingSlashMatch() {\n        return trailingSlashMatch;\n    }\n\n    @Parameter(excluded = true)\n    public boolean getTrailingSlashMatchOrDefault() {\n        return trailingSlashMatch == null ? DEFAULT_TRAILING_SLASH_MATCH : trailingSlashMatch;\n    }\n\n    public void setTrailingSlashMatch(Boolean trailingSlashMatch) {\n        this.trailingSlashMatch = trailingSlashMatch;\n    }\n\n    public Boolean getSuffixPatternMatch() {\n        return suffixPatternMatch;\n    }\n\n    @Parameter(excluded = true)\n    public boolean getSuffixPatternMatchOrDefault() {\n        return suffixPatternMatch == null ? DEFAULT_SUFFIX_PATTERN_MATCH : suffixPatternMatch;\n    }\n\n    public void setSuffixPatternMatch(Boolean suffixPatternMatch) {\n        this.suffixPatternMatch = suffixPatternMatch;\n    }\n\n    public Boolean getCaseSensitiveMatch() {\n        return caseSensitiveMatch;\n    }\n\n    @Parameter(excluded = true)\n    public boolean getCaseSensitiveMatchOrDefault() {\n        return caseSensitiveMatch == null ? DEFAULT_CASE_SENSITIVE_MATCH : caseSensitiveMatch;\n    }\n\n    public void setCaseSensitiveMatch(Boolean caseSensitiveMatch) {\n        this.caseSensitiveMatch = caseSensitiveMatch;\n    }\n\n    public String getFormatParameterName() {\n        return formatParameterName;\n    }\n\n    @Parameter(excluded = true)\n    public String getFormatParameterNameOrDefault() {\n        return formatParameterName == null ? DEFAULT_FORMAT_PARAMETER_NAME : formatParameterName;\n    }\n\n    public void setFormatParameterName(String formatParameterName) {\n        this.formatParameterName = formatParameterName;\n    }\n\n    public String getJsonFramework() {\n        return jsonFramework;\n    }\n\n    public void setJsonFramework(String jsonFramework) {\n        this.jsonFramework = jsonFramework;\n    }\n\n    public String[] getDisallowedContentTypes() {\n        return disallowedContentTypes;\n    }\n\n    public void setDisallowedContentTypes(String[] disallowedContentTypes) {\n        this.disallowedContentTypes = disallowedContentTypes;\n    }\n\n    public CorsConfig getCors() {\n        return cors;\n    }\n\n    @Parameter(excluded = true)\n    public CorsConfig getCorsOrDefault() {\n        if (cors == null) {\n            cors = new CorsConfig();\n        }\n        return cors;\n    }\n\n    public void setCors(CorsConfig cors) {\n        this.cors = cors;\n    }\n\n    @Parameter(excluded = true)\n    public OpenAPIConfig getOpenapi() {\n        return openapi;\n    }\n\n    @Parameter(attribute = false)\n    public void setOpenapi(OpenAPIConfig openapi) {\n        this.openapi = openapi;\n    }\n\n    @Parameter(excluded = true)\n    public McpConfig getMcp() {\n        return mcp;\n    }\n\n    @Parameter(attribute = false)\n    public void setMcp(McpConfig mcp) {\n        this.mcp = mcp;\n    }\n\n    @Parameter(excluded = true)\n    public Map<String, OpenAPIConfig> getOpenapis() {\n        return openapis;\n    }\n\n    @Parameter(attribute = false)\n    public void setOpenapis(Map<String, OpenAPIConfig> openapis) {\n        this.openapis = openapis;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/SamplingConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport java.io.Serializable;\n\n/**\n * Configuration for the sampling.\n */\npublic class SamplingConfig implements Serializable {\n\n    private static final long serialVersionUID = -7456034528275916549L;\n\n    /**\n     * Probability in the range from 0.0 to 1.0 that a trace will be sampled.\n     */\n    private float probability = 0.10f;\n\n    public SamplingConfig() {}\n\n    public SamplingConfig(float probability) {\n        this.probability = probability;\n    }\n\n    public float getProbability() {\n        return this.probability;\n    }\n\n    public void setProbability(float probability) {\n        this.probability = probability;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/ServletConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport java.io.Serializable;\n\npublic class ServletConfig implements Serializable {\n\n    private static final long serialVersionUID = 1091478303358670173L;\n\n    /**\n     * Whether to enable servlet support, requests are transport through the servlet container\n     * <p>The default value is false.\n     */\n    private Boolean enabled;\n\n    /**\n     * Maximum concurrent streams.\n     * <p>For HTTP/2\n     * <p>Note that the default value for tomcat is 20. Highly recommended to change it to {@link Integer#MAX_VALUE}\n     * <p>If set to zero or a negative number, the actual value will be set to {@link Integer#MAX_VALUE}.\n     */\n    private Integer maxConcurrentStreams;\n\n    /**\n     * The URL patterns that the servlet filter will be registered for.\n     * <p>The default value is '/*'.\n     */\n    private String[] filterUrlPatterns;\n\n    /**\n     * The order of the servlet filter.\n     * <p>The default value is -1000000.\n     */\n    private Integer filterOrder;\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public Integer getMaxConcurrentStreams() {\n        return maxConcurrentStreams;\n    }\n\n    public void setMaxConcurrentStreams(Integer maxConcurrentStreams) {\n        this.maxConcurrentStreams = maxConcurrentStreams;\n    }\n\n    public String[] getFilterUrlPatterns() {\n        return filterUrlPatterns;\n    }\n\n    public void setFilterUrlPatterns(String[] filterUrlPatterns) {\n        this.filterUrlPatterns = filterUrlPatterns;\n    }\n\n    public Integer getFilterOrder() {\n        return filterOrder;\n    }\n\n    public void setFilterOrder(Integer filterOrder) {\n        this.filterOrder = filterOrder;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/TripleConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport org.apache.dubbo.config.support.Nested;\nimport org.apache.dubbo.config.support.Parameter;\n\nimport java.io.Serializable;\n\n/**\n * Configuration for triple protocol.\n */\npublic class TripleConfig implements Serializable {\n\n    private static final long serialVersionUID = -3682252713701362155L;\n\n    public static final int DEFAULT_MAX_BODY_SIZE = 8_388_608;\n    public static final int DEFAULT_MAX_RESPONSE_BODY_SIZE = 8_388_608;\n    public static final int DEFAULT_MAX_CHUNK_SIZE = 8_388_608;\n    public static final int DEFAULT_MAX_HEADER_SIZE = 8_192;\n    public static final int DEFAULT_MAX_INITIAL_LINE_LENGTH = 4_096;\n    public static final int DEFAULT_INITIAL_BUFFER_SIZE = 16_384;\n    public static final int DEFAULT_HEADER_TABLE_SIZE = 4_096;\n    public static final boolean DEFAULT_ENABLE_PUSH = false;\n    public static final int DEFAULT_MAX_CONCURRENT_STREAMS = Integer.MAX_VALUE;\n    public static final int DEFAULT_INITIAL_WINDOW_SIZE = 8_388_608;\n    public static final int DEFAULT_CONNECTION_INITIAL_WINDOW_SIZE_KEY = 65_536;\n    public static final int DEFAULT_MAX_FRAME_SIZE = 8_388_608;\n    public static final int DEFAULT_MAX_HEADER_LIST_SIZE = 32_768;\n    public static final int DEFAULT_MAX_MESSAGE_SIZE = 50 * 1024 * 1024;\n    public static final float DEFAULT_WINDOW_UPDATE_RATIO = 0.5f;\n\n    public static final String H2_SETTINGS_MAX_MESSAGE_SIZE_KEY = \"dubbo.protocol.triple.max-message-size\";\n\n    /**\n     * Whether enable verbose mode.\n     * When true, the application will produce detailed logging output\n     * to help with debugging and monitoring. This is useful for\n     * troubleshooting and understanding the application's behavior in detail.\n     * <p>The default value is false.\n     */\n    private Boolean verbose;\n\n    /**\n     * Maximum allowed size for HTTP request bodies.\n     * Limits the size of request to prevent excessively large request.\n     * <p>The default value is 8MiB.\n     */\n    private Integer maxBodySize;\n\n    /**\n     * Maximum allowed size for HTTP response bodies.\n     * Limits the size of responses to prevent excessively large response.\n     * <p>The default value is 8MiB.\n     */\n    private Integer maxResponseBodySize;\n\n    /**\n     * Set the maximum chunk size.\n     * HTTP requests and responses can be quite large,\n     * in which case it's better to process the data as a stream of chunks.\n     * This sets the limit, in bytes, at which Netty will send a chunk down the pipeline.\n     * <p>The default value is 8MiB.\n     * <p>For HTTP/1\n     */\n    private Integer maxChunkSize;\n\n    /**\n     * Set the maximum line length of header lines.\n     * This limits how much memory Netty will use when parsing HTTP header key-value pairs.\n     * You would typically set this to the same value as {@link #setMaxInitialLineLength(Integer)}.\n     * <p>The default value is 8KiB.\n     * <p>For HTTP/1\n     */\n    private Integer maxHeaderSize;\n\n    /**\n     * Set the maximum length of the first line of the HTTP header.\n     * This limits how much memory Netty will use when parsed the initial HTTP header line.\n     * You would typically set this to the same value as {@link #setMaxHeaderSize(Integer)}.\n     * <p>The default value is 4096.\n     * <p>For HTTP/1\n     */\n    private Integer maxInitialLineLength;\n\n    /**\n     * Set the initial size of the temporary buffer used when parsing the lines of the HTTP headers.\n     * <p>The default value is 16384 octets.\n     * <p>For HTTP/1\n     */\n    private Integer initialBufferSize;\n\n    /**\n     * The header table size.\n     * <p>For HTTP/1\n     */\n    private Integer headerTableSize;\n\n    /**\n     * Whether to enable push\n     * <p>The default value is false.\n     * <p>For HTTP/2\n     */\n    private Boolean enablePush;\n\n    /**\n     * Maximum concurrent streams.\n     * <p>For HTTP/2\n     */\n    private Integer maxConcurrentStreams;\n\n    /**\n     * Initial window size.\n     * <p>For HTTP/2\n     */\n    private Integer initialWindowSize;\n\n    /**\n     * Connection initial window size.\n     * <p>For HTTP/2\n     */\n    private Integer connectionInitialWindowSize;\n\n    /**\n     * Maximum frame size.\n     * <p>For HTTP/2\n     */\n    private Integer maxFrameSize;\n\n    /**\n     * Maximum header list size.\n     * <p>For HTTP/2\n     */\n    private Integer maxHeaderListSize;\n\n    /**\n     * Maximum message size.\n     */\n    private Integer maxMessageSize;\n\n    /**\n     * Window update ratio for HTTP/2 flow control.\n     * Determines when to send WINDOW_UPDATE frames based on the ratio of consumed bytes\n     * to the initial window size. For example, 0.5 means WINDOW_UPDATE is sent when\n     * 50% of the initial window has been consumed.\n     * <p>Valid range: 0.0 to 1.0 (exclusive of 0, as 0 would disable window updates)\n     * <p>The default value is 0.5.\n     * <p>For HTTP/2\n     */\n    private Float windowUpdateRatio;\n\n    @Nested\n    private RestConfig rest;\n\n    @Nested\n    private Http3Config http3;\n\n    @Nested\n    private ServletConfig servlet;\n\n    @Nested\n    private WebSocketConfig websocket;\n\n    public Boolean getVerbose() {\n        return verbose;\n    }\n\n    public void setVerbose(Boolean verbose) {\n        this.verbose = verbose;\n    }\n\n    public Integer getMaxBodySize() {\n        return maxBodySize;\n    }\n\n    @Parameter(excluded = true)\n    public int getMaxBodySizeOrDefault() {\n        return maxBodySize == null ? DEFAULT_MAX_BODY_SIZE : maxBodySize;\n    }\n\n    public void setMaxBodySize(Integer maxBodySize) {\n        this.maxBodySize = maxBodySize;\n    }\n\n    public Integer getMaxResponseBodySize() {\n        return maxResponseBodySize;\n    }\n\n    @Parameter(excluded = true)\n    public int getMaxResponseBodySizeOrDefault() {\n        return maxResponseBodySize == null ? DEFAULT_MAX_RESPONSE_BODY_SIZE : maxResponseBodySize;\n    }\n\n    public void setMaxResponseBodySize(Integer maxResponseBodySize) {\n        this.maxResponseBodySize = maxResponseBodySize;\n    }\n\n    public Integer getMaxChunkSize() {\n        return maxChunkSize;\n    }\n\n    @Parameter(excluded = true)\n    public int getMaxChunkSizeOrDefault() {\n        return maxChunkSize == null ? DEFAULT_MAX_CHUNK_SIZE : maxChunkSize;\n    }\n\n    public void setMaxChunkSize(Integer maxChunkSize) {\n        this.maxChunkSize = maxChunkSize;\n    }\n\n    public Integer getMaxHeaderSize() {\n        return maxHeaderSize;\n    }\n\n    @Parameter(excluded = true)\n    public int getMaxHeaderSizeOrDefault() {\n        return maxHeaderSize == null ? DEFAULT_MAX_HEADER_SIZE : maxHeaderSize;\n    }\n\n    public void setMaxHeaderSize(Integer maxHeaderSize) {\n        this.maxHeaderSize = maxHeaderSize;\n    }\n\n    public Integer getMaxInitialLineLength() {\n        return maxInitialLineLength;\n    }\n\n    @Parameter(excluded = true)\n    public int getMaxInitialLineLengthOrDefault() {\n        return maxInitialLineLength == null ? DEFAULT_MAX_INITIAL_LINE_LENGTH : maxInitialLineLength;\n    }\n\n    public void setMaxInitialLineLength(Integer maxInitialLineLength) {\n        this.maxInitialLineLength = maxInitialLineLength;\n    }\n\n    public Integer getInitialBufferSize() {\n        return initialBufferSize;\n    }\n\n    @Parameter(excluded = true)\n    public int getInitialBufferSizeOrDefault() {\n        return initialBufferSize == null ? DEFAULT_INITIAL_BUFFER_SIZE : initialBufferSize;\n    }\n\n    public void setInitialBufferSize(Integer initialBufferSize) {\n        this.initialBufferSize = initialBufferSize;\n    }\n\n    public Integer getHeaderTableSize() {\n        return headerTableSize;\n    }\n\n    @Parameter(excluded = true)\n    public int getHeaderTableSizeOrDefault() {\n        return headerTableSize == null ? DEFAULT_HEADER_TABLE_SIZE : headerTableSize;\n    }\n\n    public void setHeaderTableSize(Integer headerTableSize) {\n        this.headerTableSize = headerTableSize;\n    }\n\n    public Boolean getEnablePush() {\n        return enablePush;\n    }\n\n    @Parameter(excluded = true)\n    public boolean getEnablePushOrDefault() {\n        return enablePush == null ? DEFAULT_ENABLE_PUSH : enablePush;\n    }\n\n    public void setEnablePush(Boolean enablePush) {\n        this.enablePush = enablePush;\n    }\n\n    public Integer getMaxConcurrentStreams() {\n        return maxConcurrentStreams;\n    }\n\n    @Parameter(excluded = true)\n    public int getMaxConcurrentStreamsOrDefault() {\n        return maxConcurrentStreams == null ? DEFAULT_MAX_CONCURRENT_STREAMS : maxConcurrentStreams;\n    }\n\n    public void setMaxConcurrentStreams(Integer maxConcurrentStreams) {\n        this.maxConcurrentStreams = maxConcurrentStreams;\n    }\n\n    public Integer getInitialWindowSize() {\n        return initialWindowSize;\n    }\n\n    @Parameter(excluded = true)\n    public int getInitialWindowSizeOrDefault() {\n        return initialWindowSize == null ? DEFAULT_INITIAL_WINDOW_SIZE : initialWindowSize;\n    }\n\n    public void setInitialWindowSize(Integer initialWindowSize) {\n        this.initialWindowSize = initialWindowSize;\n    }\n\n    public Integer getConnectionInitialWindowSize() {\n        return connectionInitialWindowSize;\n    }\n\n    @Parameter(excluded = true)\n    public Integer getConnectionInitialWindowSizeOrDefault() {\n        return connectionInitialWindowSize == null\n                ? DEFAULT_CONNECTION_INITIAL_WINDOW_SIZE_KEY\n                : connectionInitialWindowSize;\n    }\n\n    public void setConnectionInitialWindowSize(Integer connectionInitialWindowSize) {\n        this.connectionInitialWindowSize = connectionInitialWindowSize;\n    }\n\n    public Integer getMaxFrameSize() {\n        return maxFrameSize;\n    }\n\n    @Parameter(excluded = true)\n    public int getMaxFrameSizeOrDefault() {\n        return maxFrameSize == null ? DEFAULT_MAX_FRAME_SIZE : maxFrameSize;\n    }\n\n    public void setMaxFrameSize(Integer maxFrameSize) {\n        this.maxFrameSize = maxFrameSize;\n    }\n\n    public Integer getMaxHeaderListSize() {\n        return maxHeaderListSize;\n    }\n\n    @Parameter(excluded = true)\n    public int getMaxHeaderListSizeOrDefault() {\n        return maxHeaderListSize == null ? DEFAULT_MAX_HEADER_LIST_SIZE : maxHeaderListSize;\n    }\n\n    public void setMaxHeaderListSize(Integer maxHeaderListSize) {\n        this.maxHeaderListSize = maxHeaderListSize;\n    }\n\n    public Integer getMaxMessageSize() {\n        return maxMessageSize;\n    }\n\n    @Parameter(excluded = true, key = H2_SETTINGS_MAX_MESSAGE_SIZE_KEY)\n    public int getMaxMessageSizeOrDefault() {\n        return maxMessageSize == null ? DEFAULT_MAX_MESSAGE_SIZE : maxMessageSize;\n    }\n\n    public void setMaxMessageSize(Integer maxMessageSize) {\n        this.maxMessageSize = maxMessageSize;\n    }\n\n    public Float getWindowUpdateRatio() {\n        return windowUpdateRatio;\n    }\n\n    @Parameter(excluded = true)\n    public float getWindowUpdateRatioOrDefault() {\n        return windowUpdateRatio == null ? DEFAULT_WINDOW_UPDATE_RATIO : windowUpdateRatio;\n    }\n\n    public void setWindowUpdateRatio(Float windowUpdateRatio) {\n        if (windowUpdateRatio != null && (windowUpdateRatio <= 0.0f || windowUpdateRatio > 1.0f)) {\n            throw new IllegalArgumentException(\"windowUpdateRatio must be > 0 and <= 1, but was: \" + windowUpdateRatio);\n        }\n        this.windowUpdateRatio = windowUpdateRatio;\n    }\n\n    public RestConfig getRest() {\n        return rest;\n    }\n\n    @Parameter(excluded = true)\n    public RestConfig getRestOrDefault() {\n        if (rest == null) {\n            rest = new RestConfig();\n        }\n        return rest;\n    }\n\n    public void setRest(RestConfig rest) {\n        this.rest = rest;\n    }\n\n    public Http3Config getHttp3() {\n        return http3;\n    }\n\n    @Parameter(excluded = true)\n    public Http3Config getHttp3OrDefault() {\n        if (http3 == null) {\n            http3 = new Http3Config();\n        }\n        return http3;\n    }\n\n    public void setHttp3(Http3Config http3) {\n        this.http3 = http3;\n    }\n\n    public ServletConfig getServlet() {\n        return servlet;\n    }\n\n    public void setServlet(ServletConfig servlet) {\n        this.servlet = servlet;\n    }\n\n    public WebSocketConfig getWebsocket() {\n        return websocket;\n    }\n\n    public void setWebsocket(WebSocketConfig websocket) {\n        this.websocket = websocket;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/nested/WebSocketConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport java.io.Serializable;\n\npublic class WebSocketConfig implements Serializable {\n\n    private static final long serialVersionUID = -2504271061733141988L;\n\n    /**\n     * Whether to enable websocket support, requests are transport through the websocket container\n     * <p>The default value is false.\n     */\n    private Boolean enabled;\n\n    /**\n     * The URL patterns that the websocket filter will be registered for.\n     * <p>The default value is '/*'.\n     */\n    private String[] filterUrlPatterns;\n\n    /**\n     * The order of the websocket filter.\n     * <p>The default value is -1000000.\n     */\n    private Integer filterOrder;\n\n    public Boolean getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public String[] getFilterUrlPatterns() {\n        return filterUrlPatterns;\n    }\n\n    public void setFilterUrlPatterns(String[] filterUrlPatterns) {\n        this.filterUrlPatterns = filterUrlPatterns;\n    }\n\n    public Integer getFilterOrder() {\n        return filterOrder;\n    }\n\n    public void setFilterOrder(Integer filterOrder) {\n        this.filterOrder = filterOrder;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/support/Nested.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.support;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Nested Class Parameter\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.FIELD})\npublic @interface Nested {}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/config/support/Parameter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.support;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Parameter\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.METHOD})\npublic @interface Parameter {\n\n    /**\n     * Specify the parameter key when append parameters to url\n     */\n    String key() default \"\";\n\n    /**\n     * If required=true, the value must not be empty when append to url\n     */\n    boolean required() default false;\n\n    /**\n     * If excluded=true, ignore it when append parameters to url\n     */\n    boolean excluded() default false;\n\n    /**\n     * if escaped=true, escape it when append parameters to url\n     */\n    boolean escaped() default false;\n\n    /**\n     * If attribute=false, ignore it when processing refresh()/getMetadata()/equals()/toString()\n     */\n    boolean attribute() default true;\n\n    /**\n     * If append=true, append new value to exist value instead of overriding it.\n     */\n    boolean append() default false;\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/MethodDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition;\n\nimport org.apache.dubbo.metadata.definition.model.MethodDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * {@link MethodDefinition} Builder based on Java Reflection\n *\n * @since 2.7.6\n */\npublic class MethodDefinitionBuilder {\n\n    private final TypeDefinitionBuilder builder;\n\n    public MethodDefinitionBuilder(TypeDefinitionBuilder builder) {\n        this.builder = builder;\n    }\n\n    public MethodDefinitionBuilder() {\n        this.builder = new TypeDefinitionBuilder();\n    }\n\n    /**\n     * Build the instance of {@link MethodDefinition}\n     *\n     * @param method {@link Method}\n     * @return non-null\n     */\n    public MethodDefinition build(Method method) {\n\n        MethodDefinition md = new MethodDefinition();\n        md.setName(method.getName());\n\n        // Process the parameters\n        Class<?>[] paramTypes = method.getParameterTypes();\n        Type[] genericParamTypes = method.getGenericParameterTypes();\n\n        int paramSize = paramTypes.length;\n        String[] parameterTypes = new String[paramSize];\n        List<TypeDefinition> parameters = new ArrayList<>(paramSize);\n        for (int i = 0; i < paramSize; i++) {\n            TypeDefinition parameter = builder.build(genericParamTypes[i], paramTypes[i]);\n            parameterTypes[i] = parameter.getType();\n            parameters.add(parameter);\n        }\n\n        md.setParameterTypes(parameterTypes);\n        md.setParameters(parameters);\n\n        // Process return type.\n        TypeDefinition td = builder.build(method.getGenericReturnType(), method.getReturnType());\n        md.setReturnType(td.getType());\n\n        return md;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.MethodDefinition;\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.metadata.definition.util.ClassUtils;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 2015/1/27.\n */\npublic final class ServiceDefinitionBuilder {\n\n    /**\n     * Describe a Java interface in {@link ServiceDefinition}.\n     *\n     * @return Service description\n     */\n    public static ServiceDefinition build(final Class<?> interfaceClass) {\n        ServiceDefinition sd = new ServiceDefinition();\n        build(sd, interfaceClass);\n        return sd;\n    }\n\n    public static FullServiceDefinition buildFullDefinition(final Class<?> interfaceClass) {\n        FullServiceDefinition sd = new FullServiceDefinition();\n        build(sd, interfaceClass);\n        return sd;\n    }\n\n    public static FullServiceDefinition buildFullDefinition(final Class<?> interfaceClass, Map<String, String> params) {\n        FullServiceDefinition sd = new FullServiceDefinition();\n        build(sd, interfaceClass);\n        sd.setParameters(params);\n        return sd;\n    }\n\n    public static <T extends ServiceDefinition> void build(T sd, final Class<?> interfaceClass) {\n        sd.setCanonicalName(interfaceClass.getCanonicalName());\n        sd.setCodeSource(ClassUtils.getCodeSource(interfaceClass));\n        Annotation[] classAnnotations = interfaceClass.getAnnotations();\n        sd.setAnnotations(annotationToStringList(classAnnotations));\n\n        TypeDefinitionBuilder builder = new TypeDefinitionBuilder();\n        List<Method> methods = ClassUtils.getPublicNonStaticMethods(interfaceClass);\n        for (Method method : methods) {\n            MethodDefinition md = new MethodDefinition();\n            md.setName(method.getName());\n\n            Annotation[] methodAnnotations = method.getAnnotations();\n            md.setAnnotations(annotationToStringList(methodAnnotations));\n\n            // Process parameter types.\n            Class<?>[] paramTypes = method.getParameterTypes();\n            Type[] genericParamTypes = method.getGenericParameterTypes();\n\n            String[] parameterTypes = new String[paramTypes.length];\n            for (int i = 0; i < paramTypes.length; i++) {\n                TypeDefinition td = builder.build(genericParamTypes[i], paramTypes[i]);\n                parameterTypes[i] = td.getType();\n            }\n            md.setParameterTypes(parameterTypes);\n\n            // Process return type.\n            TypeDefinition td = builder.build(method.getGenericReturnType(), method.getReturnType());\n            md.setReturnType(td.getType());\n\n            sd.getMethods().add(md);\n        }\n\n        sd.setTypes(builder.getTypeDefinitions());\n    }\n\n    private static List<String> annotationToStringList(Annotation[] annotations) {\n        if (annotations == null) {\n            return Collections.emptyList();\n        }\n        List<String> list = new ArrayList<>();\n        for (Annotation annotation : annotations) {\n            list.add(annotation.toString());\n        }\n        return list;\n    }\n\n    /**\n     * Describe a Java interface in Json schema.\n     *\n     * @return Service description\n     */\n    public static String schema(final Class<?> clazz) {\n        ServiceDefinition sd = build(clazz);\n        return JsonUtils.toJson(sd);\n    }\n\n    private ServiceDefinitionBuilder() {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.metadata.definition.builder.DefaultTypeBuilder;\nimport org.apache.dubbo.metadata.definition.builder.TypeBuilder;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * 2015/1/27.\n */\npublic class TypeDefinitionBuilder {\n    private static final Logger logger = LoggerFactory.getLogger(TypeDefinitionBuilder.class);\n    public static List<TypeBuilder> BUILDERS;\n\n    public static void initBuilders(FrameworkModel model) {\n        Set<TypeBuilder> tbs = model.getExtensionLoader(TypeBuilder.class).getSupportedExtensionInstances();\n        BUILDERS = new ArrayList<>(tbs);\n    }\n\n    public static TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) {\n        TypeBuilder builder = getGenericTypeBuilder(clazz);\n        TypeDefinition td;\n\n        if (clazz.isPrimitive() || ClassUtils.isSimpleType(clazz)) { // changed since 2.7.6\n            td = new TypeDefinition(clazz.getCanonicalName());\n            typeCache.put(clazz.getCanonicalName(), td);\n        } else if (builder != null) {\n            td = builder.build(type, clazz, typeCache);\n        } else {\n            td = DefaultTypeBuilder.build(clazz, typeCache);\n        }\n        return td;\n    }\n\n    private static TypeBuilder getGenericTypeBuilder(Class<?> clazz) {\n        for (TypeBuilder builder : BUILDERS) {\n            try {\n                if (builder.accept(clazz)) {\n                    return builder;\n                }\n            } catch (NoClassDefFoundError cnfe) {\n                // ignore\n                logger.info(\"Throw classNotFound (\" + cnfe.getMessage() + \") in \" + builder.getClass());\n            }\n        }\n        return null;\n    }\n\n    private final Map<String, TypeDefinition> typeCache = new HashMap<>();\n\n    public TypeDefinition build(Type type, Class<?> clazz) {\n        return build(type, clazz, typeCache);\n    }\n\n    public List<TypeDefinition> getTypeDefinitions() {\n        return new ArrayList<>(typeCache.values());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/ArrayTypeBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.builder;\n\nimport org.apache.dubbo.metadata.definition.TypeDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport java.lang.reflect.Type;\nimport java.util.Map;\n\n/**\n * 2015/1/27.\n */\npublic class ArrayTypeBuilder implements TypeBuilder {\n\n    @Override\n    public boolean accept(Class<?> clazz) {\n        if (clazz == null) {\n            return false;\n        }\n        return clazz.isArray();\n    }\n\n    @Override\n    public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) {\n        final String canonicalName = clazz.getCanonicalName();\n        TypeDefinition td = typeCache.get(canonicalName);\n        if (td != null) {\n            return td;\n        }\n        td = new TypeDefinition(canonicalName);\n        typeCache.put(canonicalName, td);\n        // Process the component type of array.\n        Class<?> componentType = clazz.getComponentType();\n        TypeDefinition itemTd = TypeDefinitionBuilder.build(componentType, componentType, typeCache);\n        if (itemTd != null) {\n            td.getItems().add(itemTd.getType());\n        }\n        return td;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/CollectionTypeBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.builder;\n\nimport org.apache.dubbo.metadata.definition.TypeDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.metadata.definition.util.ClassUtils;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.text.MessageFormat;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Map;\n\n/**\n * 2015/1/27.\n */\npublic class CollectionTypeBuilder implements TypeBuilder {\n\n    @Override\n    public boolean accept(Class<?> clazz) {\n        if (clazz == null) {\n            return false;\n        }\n        return Collection.class.isAssignableFrom(clazz);\n    }\n\n    @Override\n    public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) {\n        if (!(type instanceof ParameterizedType)) {\n            return new TypeDefinition(clazz.getCanonicalName());\n        }\n\n        ParameterizedType parameterizedType = (ParameterizedType) type;\n        Type[] actualTypeArgs = parameterizedType.getActualTypeArguments();\n        if (actualTypeArgs == null || actualTypeArgs.length != 1) {\n            throw new IllegalArgumentException(MessageFormat.format(\n                    \"[ServiceDefinitionBuilder] Collection type [{0}] with unexpected amount of arguments [{1}].\"\n                            + Arrays.toString(actualTypeArgs),\n                    type,\n                    actualTypeArgs));\n        }\n\n        String colType = ClassUtils.getCanonicalNameForParameterizedType(parameterizedType);\n        TypeDefinition td = typeCache.get(colType);\n        if (td != null) {\n            return td;\n        }\n        td = new TypeDefinition(colType);\n        typeCache.put(colType, td);\n\n        Type actualType = actualTypeArgs[0];\n        TypeDefinition itemTd = null;\n        if (actualType instanceof ParameterizedType) {\n            // Nested collection or map.\n            Class<?> rawType = (Class<?>) ((ParameterizedType) actualType).getRawType();\n            itemTd = TypeDefinitionBuilder.build(actualType, rawType, typeCache);\n        } else if (actualType instanceof Class<?>) {\n            Class<?> actualClass = (Class<?>) actualType;\n            itemTd = TypeDefinitionBuilder.build(null, actualClass, typeCache);\n        }\n        if (itemTd != null) {\n            td.getItems().add(itemTd.getType());\n        }\n\n        return td;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/DefaultTypeBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.builder;\n\nimport org.apache.dubbo.metadata.definition.TypeDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.metadata.definition.util.ClassUtils;\nimport org.apache.dubbo.metadata.definition.util.JaketConfigurationUtils;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Type;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 2015/1/27.\n */\npublic final class DefaultTypeBuilder {\n\n    public static TypeDefinition build(Class<?> clazz, Map<String, TypeDefinition> typeCache) {\n        String className = clazz.getCanonicalName();\n        if (className == null) {\n            className = clazz.getName();\n        }\n\n        // Try to get a cached definition\n        TypeDefinition td = typeCache.get(className);\n        if (td != null) {\n            return td;\n        }\n        td = new TypeDefinition(className);\n        typeCache.put(className, td);\n\n        // Primitive type\n        if (!JaketConfigurationUtils.needAnalyzing(clazz)) {\n            return td;\n        }\n\n        // Custom type\n        List<Field> fields = ClassUtils.getNonStaticFields(clazz);\n        for (Field field : fields) {\n            String fieldName = field.getName();\n            Class<?> fieldClass = field.getType();\n            Type fieldType = field.getGenericType();\n            TypeDefinition fieldTd = TypeDefinitionBuilder.build(fieldType, fieldClass, typeCache);\n            td.getProperties().put(fieldName, fieldTd.getType());\n        }\n\n        return td;\n    }\n\n    private DefaultTypeBuilder() {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/EnumTypeBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.builder;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.metadata.definition.TypeDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\n/**\n * 2015/1/27.\n */\npublic class EnumTypeBuilder implements TypeBuilder {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(TypeDefinitionBuilder.class);\n\n    @Override\n    public boolean accept(Class<?> clazz) {\n        if (clazz == null) {\n            return false;\n        }\n        return clazz.isEnum();\n    }\n\n    @Override\n    public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) {\n        String canonicalName = clazz.getCanonicalName();\n\n        TypeDefinition td = typeCache.get(canonicalName);\n        if (td != null) {\n            return td;\n        }\n        td = new TypeDefinition(canonicalName);\n        typeCache.put(canonicalName, td);\n\n        try {\n            Method methodValues = clazz.getDeclaredMethod(\"values\");\n            methodValues.setAccessible(true);\n            Object[] values = (Object[]) methodValues.invoke(clazz, new Object[0]);\n            int length = values.length;\n            for (int i = 0; i < length; i++) {\n                Object value = values[i];\n                td.getEnums().add(value.toString());\n            }\n            return td;\n        } catch (Throwable t) {\n            logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"There is an error while process class \" + clazz, t);\n        }\n        return td;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.builder;\n\nimport org.apache.dubbo.metadata.definition.TypeDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.metadata.definition.util.ClassUtils;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.utils.TypeUtils.getRawClass;\nimport static org.apache.dubbo.common.utils.TypeUtils.isClass;\nimport static org.apache.dubbo.common.utils.TypeUtils.isParameterizedType;\n\n/**\n * 2015/1/27.\n */\npublic class MapTypeBuilder implements TypeBuilder {\n\n    @Override\n    public boolean accept(Class<?> clazz) {\n        if (clazz == null) {\n            return false;\n        }\n        return Map.class.isAssignableFrom(clazz);\n    }\n\n    @Override\n    public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) {\n        if (!(type instanceof ParameterizedType)) {\n            return new TypeDefinition(clazz.getCanonicalName());\n        }\n\n        ParameterizedType parameterizedType = (ParameterizedType) type;\n        Type[] actualTypeArgs = parameterizedType.getActualTypeArguments();\n        int actualTypeArgsLength = actualTypeArgs == null ? 0 : actualTypeArgs.length;\n\n        String mapType = ClassUtils.getCanonicalNameForParameterizedType(parameterizedType);\n\n        TypeDefinition td = typeCache.get(mapType);\n        if (td != null) {\n            return td;\n        }\n        td = new TypeDefinition(mapType);\n        typeCache.put(mapType, td);\n\n        for (int i = 0; i < actualTypeArgsLength; i++) {\n            Type actualType = actualTypeArgs[i];\n            TypeDefinition item = null;\n            Class<?> rawType = getRawClass(actualType);\n            if (isParameterizedType(actualType)) {\n                // Nested collection or map.\n                item = TypeDefinitionBuilder.build(actualType, rawType, typeCache);\n            } else if (isClass(actualType)) {\n                item = TypeDefinitionBuilder.build(null, rawType, typeCache);\n            }\n            if (item != null) {\n                td.getItems().add(item.getType());\n            }\n        }\n        return td;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/builder/TypeBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.builder;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport java.lang.reflect.Type;\nimport java.util.Map;\n\n/**\n * 2015/1/27.\n */\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface TypeBuilder extends Prioritized {\n\n    /**\n     * Whether the build accept the class passed in.\n     */\n    boolean accept(Class<?> clazz);\n\n    /**\n     * Build type definition with the type or class.\n     */\n    TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/FullServiceDefinition.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.model;\n\nimport java.util.Map;\n\n/**\n * 2018/10/25\n */\npublic class FullServiceDefinition extends ServiceDefinition {\n\n    private Map<String, String> parameters;\n\n    public Map<String, String> getParameters() {\n        return parameters;\n    }\n\n    public void setParameters(Map<String, String> parameters) {\n        this.parameters = parameters;\n    }\n\n    @Override\n    public String toString() {\n        return \"FullServiceDefinition{\" + \"parameters=\" + parameters + \"} \" + super.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/MethodDefinition.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.model;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.metadata.definition.model.TypeDefinition.formatType;\nimport static org.apache.dubbo.metadata.definition.model.TypeDefinition.formatTypes;\n\n/**\n * 2015/1/27.\n */\npublic class MethodDefinition implements Serializable {\n\n    private String name;\n    private String[] parameterTypes;\n    private String returnType;\n\n    /**\n     * @deprecated please use parameterTypes,\n     * and find TypeDefinition in org.apache.dubbo.metadata.definition.model.ServiceDefinition#types\n     */\n    @Deprecated\n    private List<TypeDefinition> parameters;\n\n    private List<String> annotations;\n\n    public String getName() {\n        return name;\n    }\n\n    public List<TypeDefinition> getParameters() {\n        if (parameters == null) {\n            parameters = new ArrayList<>();\n        }\n        return parameters;\n    }\n\n    public String[] getParameterTypes() {\n        return parameterTypes;\n    }\n\n    public String getReturnType() {\n        return returnType;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public void setParameters(List<TypeDefinition> parameters) {\n        this.parameters = parameters;\n    }\n\n    public void setParameterTypes(String[] parameterTypes) {\n        this.parameterTypes = formatTypes(parameterTypes);\n    }\n\n    public void setReturnType(String returnType) {\n        this.returnType = formatType(returnType);\n    }\n\n    public List<String> getAnnotations() {\n        if (annotations == null) {\n            annotations = Collections.emptyList();\n        }\n        return annotations;\n    }\n\n    public void setAnnotations(List<String> annotations) {\n        this.annotations = annotations;\n    }\n\n    @Override\n    public String toString() {\n        return \"MethodDefinition [name=\" + name + \", parameterTypes=\" + Arrays.toString(parameterTypes)\n                + \", returnType=\" + returnType + \"]\";\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (!(o instanceof MethodDefinition)) {\n            return false;\n        }\n        MethodDefinition that = (MethodDefinition) o;\n        return Objects.equals(getName(), that.getName())\n                && Arrays.equals(getParameterTypes(), that.getParameterTypes())\n                && Objects.equals(getReturnType(), that.getReturnType());\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(getName(), getReturnType(), Arrays.toString(getParameterTypes()));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/ServiceDefinition.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.model;\n\nimport org.apache.dubbo.metadata.definition.util.ClassUtils;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * 2015/1/27.\n */\npublic class ServiceDefinition implements Serializable {\n\n    /**\n     * the canonical name of interface\n     *\n     * @see Class#getCanonicalName()\n     */\n    private String canonicalName;\n\n    /**\n     * the location of class file\n     *\n     * @see ClassUtils#getCodeSource(Class)\n     */\n    private String codeSource;\n\n    private List<MethodDefinition> methods;\n\n    /**\n     * the definitions of type\n     */\n    private List<TypeDefinition> types;\n\n    /**\n     * the definitions of annotations\n     */\n    private List<String> annotations;\n\n    public String getCanonicalName() {\n        return canonicalName;\n    }\n\n    public String getCodeSource() {\n        return codeSource;\n    }\n\n    public List<MethodDefinition> getMethods() {\n        if (methods == null) {\n            methods = new ArrayList<>();\n        }\n        return methods;\n    }\n\n    public List<TypeDefinition> getTypes() {\n        if (types == null) {\n            types = new ArrayList<>();\n        }\n        return types;\n    }\n\n    public String getUniqueId() {\n        return canonicalName + \"@\" + codeSource;\n    }\n\n    public void setCanonicalName(String canonicalName) {\n        this.canonicalName = canonicalName;\n    }\n\n    public void setCodeSource(String codeSource) {\n        this.codeSource = codeSource;\n    }\n\n    public void setMethods(List<MethodDefinition> methods) {\n        this.methods = methods;\n    }\n\n    public void setTypes(List<TypeDefinition> types) {\n        this.types = types;\n    }\n\n    public List<String> getAnnotations() {\n        if (annotations == null) {\n            annotations = Collections.emptyList();\n        }\n        return annotations;\n    }\n\n    public void setAnnotations(List<String> annotations) {\n        this.annotations = annotations;\n    }\n\n    @Override\n    public String toString() {\n        return \"ServiceDefinition [canonicalName=\" + canonicalName + \", codeSource=\" + codeSource + \", methods=\"\n                + methods + \"]\";\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (!(o instanceof ServiceDefinition)) {\n            return false;\n        }\n        ServiceDefinition that = (ServiceDefinition) o;\n        return Objects.equals(getCanonicalName(), that.getCanonicalName())\n                && Objects.equals(getCodeSource(), that.getCodeSource())\n                && Objects.equals(getMethods(), that.getMethods())\n                && Objects.equals(getTypes(), that.getTypes());\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(getCanonicalName(), getCodeSource(), getMethods(), getTypes());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/model/TypeDefinition.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.model;\n\nimport java.io.Serializable;\nimport java.lang.reflect.ParameterizedType;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.common.utils.StringUtils.replace;\n\n/**\n * 2015/1/27.\n */\npublic class TypeDefinition implements Serializable {\n\n    /**\n     * the name of type\n     *\n     * @see Class#getCanonicalName()\n     * @see org.apache.dubbo.metadata.definition.util.ClassUtils#getCanonicalNameForParameterizedType(ParameterizedType)\n     */\n    private String type;\n\n    /**\n     * the items(generic parameter) of Map/List(ParameterizedType)\n     * <p>\n     * if this type is not ParameterizedType, the items is null or empty\n     */\n    private List<String> items;\n\n    /**\n     * the enum's value\n     * <p>\n     * If this type is not enum, enums is null or empty\n     */\n    private List<String> enums;\n\n    /**\n     * the key is property name,\n     * the value is property's type name\n     */\n    private Map<String, String> properties;\n\n    public TypeDefinition() {}\n\n    public TypeDefinition(String type) {\n        this.setType(type);\n    }\n\n    /**\n     * Format the {@link String} array presenting Java types\n     *\n     * @param types the strings presenting Java types\n     * @return new String array of Java types after be formatted\n     * @since 2.7.9\n     */\n    public static String[] formatTypes(String[] types) {\n        String[] newTypes = new String[types.length];\n        for (int i = 0; i < types.length; i++) {\n            newTypes[i] = formatType(types[i]);\n        }\n        return newTypes;\n    }\n\n    /**\n     * Format the {@link String} presenting Java type\n     *\n     * @param type the String presenting type\n     * @return new String presenting Java type after be formatted\n     * @since 2.7.9\n     */\n    public static String formatType(String type) {\n        if (isGenericType(type)) {\n            return formatGenericType(type);\n        }\n        return type;\n    }\n\n    /**\n     * Replacing <code>\", \"</code> to <code>\",\"</code> will not change the semantic of\n     * {@link ParameterizedType#toString()}\n     *\n     * @param type\n     * @return formatted type\n     * @see sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl\n     */\n    private static String formatGenericType(String type) {\n        return replace(type, \", \", \",\");\n    }\n\n    private static boolean isGenericType(String type) {\n        return type.contains(\"<\") && type.contains(\">\");\n    }\n\n    public List<String> getEnums() {\n        if (enums == null) {\n            enums = new ArrayList<>();\n        }\n        return enums;\n    }\n\n    public List<String> getItems() {\n        if (items == null) {\n            items = new ArrayList<>();\n        }\n        return items;\n    }\n\n    public Map<String, String> getProperties() {\n        if (properties == null) {\n            properties = new HashMap<>();\n        }\n        return properties;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setEnums(List<String> enums) {\n        this.enums = enums;\n    }\n\n    public void setItems(List<String> items) {\n        this.items = items;\n    }\n\n    public void setProperties(Map<String, String> properties) {\n        this.properties = properties;\n    }\n\n    public void setType(String type) {\n        this.type = formatType(type);\n    }\n\n    @Override\n    public String toString() {\n        return \"TypeDefinition [type=\" + type + \", properties=\" + properties + \"]\";\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (!(o instanceof TypeDefinition)) {\n            return false;\n        }\n        TypeDefinition that = (TypeDefinition) o;\n        return Objects.equals(getType(), that.getType())\n                && Objects.equals(getItems(), that.getItems())\n                && Objects.equals(getEnums(), that.getEnums())\n                && Objects.equals(getProperties(), that.getProperties());\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(getType(), getItems(), getEnums(), getProperties());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/util/ClassUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.util;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.net.URL;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 2015/1/27.\n */\npublic final class ClassUtils {\n\n    /**\n     * Get the code source file or class path of the Class passed in.\n     *\n     * @param clazz\n     * @return Jar file name or class path.\n     */\n    public static String getCodeSource(Class<?> clazz) {\n        ProtectionDomain protectionDomain = clazz.getProtectionDomain();\n        if (protectionDomain == null || protectionDomain.getCodeSource() == null) {\n            return null;\n        }\n\n        CodeSource codeSource = clazz.getProtectionDomain().getCodeSource();\n        URL location = codeSource.getLocation();\n        if (location == null) {\n            return null;\n        }\n\n        String path = location.toExternalForm();\n\n        if (path.endsWith(\".jar\") && path.contains(\"/\")) {\n            return path.substring(path.lastIndexOf('/') + 1);\n        }\n        return path;\n    }\n\n    /**\n     * Get all non-static fields of the Class passed in or its super classes.\n     * <p>\n     *\n     * @param clazz Class to parse.\n     * @return field list\n     */\n    public static List<Field> getNonStaticFields(final Class<?> clazz) {\n        List<Field> result = new ArrayList<>();\n        Class<?> target = clazz;\n        while (target != null) {\n            if (JaketConfigurationUtils.isExcludedType(target)) {\n                break;\n            }\n\n            Field[] fields = target.getDeclaredFields();\n            for (Field field : fields) {\n                int modifiers = field.getModifiers();\n                if (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) {\n                    continue;\n                }\n\n                result.add(field);\n            }\n            target = target.getSuperclass();\n        }\n\n        return result;\n    }\n\n    /**\n     * Get all public, non-static methods of the Class passed in.\n     * <p>\n     *\n     * @param clazz Class to parse.\n     * @return methods list\n     */\n    public static List<Method> getPublicNonStaticMethods(final Class<?> clazz) {\n        List<Method> result = new ArrayList<>();\n\n        Method[] methods = clazz.getMethods();\n        for (Method method : methods) {\n            int mod = method.getModifiers();\n            if (Modifier.isPublic(mod) && !Modifier.isStatic(mod)) {\n                result.add(method);\n            }\n        }\n        return result;\n    }\n\n    public static String getCanonicalNameForParameterizedType(ParameterizedType parameterizedType) {\n        StringBuilder sb = new StringBuilder();\n        Type ownerType = parameterizedType.getOwnerType();\n        Class<?> rawType = (Class) parameterizedType.getRawType();\n        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();\n\n        if (ownerType != null) {\n            if (ownerType instanceof Class) {\n                sb.append(((Class) ownerType).getName());\n            } else {\n                sb.append(ownerType);\n            }\n\n            sb.append('.');\n\n            if (ownerType instanceof ParameterizedType) {\n                // Find simple name of nested type by removing the\n                // shared prefix with owner.\n                sb.append(rawType.getName()\n                        .replace(((Class) ((ParameterizedType) ownerType).getRawType()).getName() + \"$\", \"\"));\n            } else {\n                sb.append(rawType.getSimpleName());\n            }\n        } else {\n            sb.append(rawType.getCanonicalName());\n        }\n\n        if (actualTypeArguments != null && actualTypeArguments.length > 0) {\n            sb.append('<');\n            boolean first = true;\n            for (Type t : actualTypeArguments) {\n                if (!first) {\n                    sb.append(\", \");\n                }\n                if (t instanceof Class) {\n                    Class c = (Class) t;\n                    sb.append(c.getCanonicalName());\n                } else if (t instanceof ParameterizedType) {\n                    sb.append(getCanonicalNameForParameterizedType((ParameterizedType) t));\n                } else {\n                    sb.append(t.toString());\n                }\n                first = false;\n            }\n            sb.append('>');\n        }\n\n        return sb.toString();\n    }\n\n    private ClassUtils() {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/metadata/definition/util/JaketConfigurationUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.util;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.io.InputStream;\nimport java.util.Properties;\n\n/**\n * 2015/1/27.\n */\npublic class JaketConfigurationUtils {\n\n    private static final String CONFIGURATION_FILE = \"jaket.properties\";\n\n    private static String[] includedInterfacePackages;\n    private static String[] includedTypePackages;\n    private static String[] closedTypes;\n\n    static {\n        Properties props = new Properties();\n        InputStream inStream = JaketConfigurationUtils.class.getClassLoader().getResourceAsStream(CONFIGURATION_FILE);\n        try {\n            props.load(inStream);\n            String value = (String) props.get(\"included_interface_packages\");\n            if (StringUtils.isNotEmpty(value)) {\n                includedInterfacePackages = value.split(\",\");\n            }\n\n            value = props.getProperty(\"included_type_packages\");\n            if (StringUtils.isNotEmpty(value)) {\n                includedTypePackages = value.split(\",\");\n            }\n\n            value = props.getProperty(\"closed_types\");\n            if (StringUtils.isNotEmpty(value)) {\n                closedTypes = value.split(\",\");\n            }\n\n        } catch (Throwable e) {\n            // Ignore it.\n        }\n    }\n\n    public static boolean isExcludedInterface(Class<?> clazz) {\n        if (includedInterfacePackages == null || includedInterfacePackages.length == 0) {\n            return false;\n        }\n\n        for (String packagePrefix : includedInterfacePackages) {\n            if (clazz.getCanonicalName().startsWith(packagePrefix)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public static boolean isExcludedType(Class<?> clazz) {\n        if (includedTypePackages == null || includedTypePackages.length == 0) {\n            return false;\n        }\n\n        for (String packagePrefix : includedTypePackages) {\n            if (clazz.getCanonicalName().startsWith(packagePrefix)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public static boolean needAnalyzing(Class<?> clazz) {\n        String canonicalName = clazz.getCanonicalName();\n\n        if (closedTypes != null && closedTypes.length > 0) {\n            for (String type : closedTypes) {\n                if (canonicalName.startsWith(type)) {\n                    return false;\n                }\n            }\n        }\n\n        return !isExcludedType(clazz);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/executor/AbstractIsolationExecutorSupport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.executor;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.rpc.model.FrameworkServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\nimport java.util.List;\nimport java.util.concurrent.Executor;\n\npublic abstract class AbstractIsolationExecutorSupport implements ExecutorSupport {\n    private final URL url;\n    private final ExecutorRepository executorRepository;\n    private final FrameworkServiceRepository frameworkServiceRepository;\n\n    public AbstractIsolationExecutorSupport(URL url) {\n        this.url = url;\n        this.executorRepository = ExecutorRepository.getInstance(url.getOrDefaultApplicationModel());\n        this.frameworkServiceRepository = url.getOrDefaultFrameworkModel().getServiceRepository();\n    }\n\n    @Override\n    public Executor getExecutor(Object data) {\n\n        ProviderModel providerModel = getProviderModel(data);\n        if (providerModel == null) {\n            return executorRepository.getExecutor(url);\n        }\n\n        List<URL> serviceUrls = providerModel.getServiceUrls();\n        if (serviceUrls == null || serviceUrls.isEmpty()) {\n            return executorRepository.getExecutor(url);\n        }\n\n        for (URL serviceUrl : serviceUrls) {\n            if (serviceUrl.getProtocol().equals(url.getProtocol()) && serviceUrl.getPort() == url.getPort()) {\n                return executorRepository.getExecutor(providerModel, serviceUrl);\n            }\n        }\n        return executorRepository.getExecutor(providerModel, serviceUrls.get(0));\n    }\n\n    protected String getServiceKey(Object data) {\n        return null;\n    }\n\n    protected ProviderModel getProviderModel(Object data) {\n        String serviceKey = getServiceKey(data);\n        return serviceKey == null ? null : frameworkServiceRepository.lookupExportedService(serviceKey);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/executor/DefaultExecutorSupport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.executor;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\n\nimport java.util.concurrent.Executor;\n\npublic class DefaultExecutorSupport implements ExecutorSupport {\n    private final ExecutorRepository executorRepository;\n    private final URL url;\n\n    public DefaultExecutorSupport(URL url) {\n        this.url = url;\n        this.executorRepository = ExecutorRepository.getInstance(url.getOrDefaultApplicationModel());\n    }\n\n    @Override\n    public Executor getExecutor(Object data) {\n        return executorRepository.getExecutor(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/executor/DefaultIsolationExecutorSupportFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.executor;\n\nimport org.apache.dubbo.common.URL;\n\npublic class DefaultIsolationExecutorSupportFactory implements IsolationExecutorSupportFactory {\n    @Override\n    public ExecutorSupport createIsolationExecutorSupport(URL url) {\n        return new DefaultExecutorSupport(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/executor/ExecutorSupport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.executor;\n\nimport java.util.concurrent.Executor;\n\npublic interface ExecutorSupport {\n    Executor getExecutor(Object data);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/executor/IsolationExecutorSupportFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.executor;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\n@SPI(\"default\")\npublic interface IsolationExecutorSupportFactory {\n\n    ExecutorSupport createIsolationExecutorSupport(URL url);\n\n    static ExecutorSupport getIsolationExecutorSupport(URL url) {\n        ApplicationModel applicationModel = url.getOrDefaultApplicationModel();\n        ExtensionLoader<IsolationExecutorSupportFactory> extensionLoader =\n                applicationModel.getExtensionLoader(IsolationExecutorSupportFactory.class);\n        IsolationExecutorSupportFactory factory = extensionLoader.getOrDefaultExtension(url.getProtocol());\n        return factory.createIsolationExecutorSupport(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationInitListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.APPLICATION)\npublic interface ApplicationInitListener {\n    /**\n     * init the application\n     */\n    void init();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.context.ApplicationExt;\nimport org.apache.dubbo.common.deploy.ApplicationDeployer;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.locks.Lock;\n\n/**\n * {@link ExtensionLoader}, {@code DubboBootstrap} and this class are at present designed to be\n * singleton or static (by itself totally static or uses some static fields). So the instances\n * returned from them are of process scope. If you want to support multiple dubbo servers in one\n * single process, you may need to refactor those three classes.\n * <p>\n * Represent an application which is using Dubbo and store basic metadata info for using\n * during the processing of RPC invoking.\n * <p>\n * ApplicationModel includes many ProviderModel which is about published services\n * and many Consumer Model which is about subscribed services.\n * <p>\n */\npublic class ApplicationModel extends ScopeModel {\n    protected static final Logger LOGGER = LoggerFactory.getLogger(ApplicationModel.class);\n    public static final String NAME = \"ApplicationModel\";\n    private final List<ModuleModel> moduleModels = new CopyOnWriteArrayList<>();\n    private final List<ModuleModel> pubModuleModels = new CopyOnWriteArrayList<>();\n    private volatile Environment environment;\n    private volatile ConfigManager configManager;\n    private volatile ServiceRepository serviceRepository;\n    private volatile ApplicationDeployer deployer;\n\n    private final FrameworkModel frameworkModel;\n\n    private final ModuleModel internalModule;\n\n    private volatile ModuleModel defaultModule;\n\n    // internal module index is 0, default module index is 1\n    private final AtomicInteger moduleIndex = new AtomicInteger(0);\n\n    // --------- static methods ----------//\n\n    public static ApplicationModel ofNullable(ApplicationModel applicationModel) {\n        if (applicationModel != null) {\n            return applicationModel;\n        } else {\n            return defaultModel();\n        }\n    }\n\n    /**\n     * During destroying the default FrameworkModel, the FrameworkModel.defaultModel() or ApplicationModel.defaultModel()\n     * will return a broken model, maybe cause unpredictable problem.\n     * Recommendation: Avoid using the default model as much as possible.\n     *\n     * @return the global default ApplicationModel\n     */\n    public static ApplicationModel defaultModel() {\n        // should get from default FrameworkModel, avoid out of sync\n        return FrameworkModel.defaultModel().defaultApplication();\n    }\n\n    // ------------- instance methods ---------------//\n\n    protected ApplicationModel(FrameworkModel frameworkModel) {\n        this(frameworkModel, false);\n    }\n\n    protected ApplicationModel(FrameworkModel frameworkModel, boolean isInternal) {\n        super(frameworkModel, ExtensionScope.APPLICATION, isInternal);\n        synchronized (instLock) {\n            Assert.notNull(frameworkModel, \"FrameworkModel can not be null\");\n            this.frameworkModel = frameworkModel;\n            frameworkModel.addApplication(this);\n            if (LOGGER.isInfoEnabled()) {\n                LOGGER.info(getDesc() + \" is created\");\n            }\n            initialize();\n\n            this.internalModule = new ModuleModel(this, true);\n            this.serviceRepository = new ServiceRepository(this);\n\n            ExtensionLoader<ApplicationInitListener> extensionLoader =\n                    this.getExtensionLoader(ApplicationInitListener.class);\n            Set<String> listenerNames = extensionLoader.getSupportedExtensions();\n            for (String listenerName : listenerNames) {\n                extensionLoader.getExtension(listenerName).init();\n            }\n\n            initApplicationExts();\n\n            ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader =\n                    this.getExtensionLoader(ScopeModelInitializer.class);\n            Set<ScopeModelInitializer> initializers = initializerExtensionLoader.getSupportedExtensionInstances();\n            for (ScopeModelInitializer initializer : initializers) {\n                initializer.initializeApplicationModel(this);\n            }\n\n            Assert.notNull(getApplicationServiceRepository(), \"ApplicationServiceRepository can not be null\");\n            Assert.notNull(getApplicationConfigManager(), \"ApplicationConfigManager can not be null\");\n            Assert.assertTrue(\n                    getApplicationConfigManager().isInitialized(), \"ApplicationConfigManager can not be initialized\");\n        }\n    }\n\n    // already synchronized in constructor\n    private void initApplicationExts() {\n        Set<ApplicationExt> exts = this.getExtensionLoader(ApplicationExt.class).getSupportedExtensionInstances();\n        for (ApplicationExt ext : exts) {\n            ext.initialize();\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        synchronized (instLock) {\n            // 1. remove from frameworkModel\n            frameworkModel.removeApplication(this);\n\n            // 2. pre-destroy, set stopping\n            if (deployer != null) {\n                // destroy registries and unregister services from registries first to notify consumers to stop\n                // consuming this instance.\n                deployer.preDestroy();\n            }\n\n            // 3. Try to destroy protocols to stop this instance from receiving new requests from connections\n            frameworkModel.tryDestroyProtocols();\n\n            // 4. destroy application resources\n            for (ModuleModel moduleModel : moduleModels) {\n                if (moduleModel != internalModule) {\n                    moduleModel.destroy();\n                }\n            }\n            // 5. destroy internal module later\n            internalModule.destroy();\n\n            // 6. post-destroy, release registry resources\n            if (deployer != null) {\n                deployer.postDestroy();\n            }\n\n            // 7. destroy other resources (e.g. ZookeeperTransporter )\n            notifyDestroy();\n\n            if (environment != null) {\n                environment.destroy();\n                environment = null;\n            }\n            if (configManager != null) {\n                configManager.destroy();\n                configManager = null;\n            }\n            if (serviceRepository != null) {\n                serviceRepository.destroy();\n                serviceRepository = null;\n            }\n\n            // 8. destroy framework if none application\n            frameworkModel.tryDestroy();\n        }\n    }\n\n    public FrameworkModel getFrameworkModel() {\n        return frameworkModel;\n    }\n\n    public ModuleModel newModule() {\n        synchronized (instLock) {\n            return new ModuleModel(this);\n        }\n    }\n\n    @Override\n    public Environment modelEnvironment() {\n        if (environment == null) {\n            environment =\n                    (Environment) this.getExtensionLoader(ApplicationExt.class).getExtension(Environment.NAME);\n        }\n        return environment;\n    }\n\n    public ConfigManager getApplicationConfigManager() {\n        if (configManager == null) {\n            configManager = (ConfigManager)\n                    this.getExtensionLoader(ApplicationExt.class).getExtension(ConfigManager.NAME);\n        }\n        return configManager;\n    }\n\n    public ServiceRepository getApplicationServiceRepository() {\n        return serviceRepository;\n    }\n\n    public ExecutorRepository getApplicationExecutorRepository() {\n        return ExecutorRepository.getInstance(this);\n    }\n\n    public boolean NotExistApplicationConfig() {\n        return !getApplicationConfigManager().getApplication().isPresent();\n    }\n\n    public ApplicationConfig getCurrentConfig() {\n        return getApplicationConfigManager().getApplicationOrElseThrow();\n    }\n\n    public String getApplicationName() {\n        return getCurrentConfig().getName();\n    }\n\n    public String tryGetApplicationName() {\n        Optional<ApplicationConfig> appCfgOptional =\n                getApplicationConfigManager().getApplication();\n        return appCfgOptional.isPresent() ? appCfgOptional.get().getName() : null;\n    }\n\n    void addModule(ModuleModel moduleModel, boolean isInternal) {\n        synchronized (instLock) {\n            if (!this.moduleModels.contains(moduleModel)) {\n                checkDestroyed();\n                this.moduleModels.add(moduleModel);\n                moduleModel.setInternalId(buildInternalId(getInternalId(), moduleIndex.getAndIncrement()));\n                if (!isInternal) {\n                    pubModuleModels.add(moduleModel);\n                }\n            }\n        }\n    }\n\n    public void removeModule(ModuleModel moduleModel) {\n        synchronized (instLock) {\n            this.moduleModels.remove(moduleModel);\n            this.pubModuleModels.remove(moduleModel);\n            if (moduleModel == defaultModule) {\n                defaultModule = findDefaultModule();\n            }\n        }\n    }\n\n    void tryDestroy() {\n        synchronized (instLock) {\n            if (this.moduleModels.isEmpty()\n                    || (this.moduleModels.size() == 1 && this.moduleModels.get(0) == internalModule)) {\n                destroy();\n            }\n        }\n    }\n\n    private void checkDestroyed() {\n        if (isDestroyed()) {\n            throw new IllegalStateException(\"ApplicationModel is destroyed\");\n        }\n    }\n\n    public List<ModuleModel> getModuleModels() {\n        return Collections.unmodifiableList(moduleModels);\n    }\n\n    public List<ModuleModel> getPubModuleModels() {\n        return Collections.unmodifiableList(pubModuleModels);\n    }\n\n    public ModuleModel getDefaultModule() {\n        if (defaultModule == null) {\n            synchronized (instLock) {\n                if (defaultModule == null) {\n                    defaultModule = findDefaultModule();\n                    if (defaultModule == null) {\n                        defaultModule = this.newModule();\n                    }\n                }\n            }\n        }\n        return defaultModule;\n    }\n\n    private ModuleModel findDefaultModule() {\n        synchronized (instLock) {\n            for (ModuleModel moduleModel : moduleModels) {\n                if (moduleModel != internalModule) {\n                    return moduleModel;\n                }\n            }\n            return null;\n        }\n    }\n\n    public ModuleModel getInternalModule() {\n        return internalModule;\n    }\n\n    @Override\n    public void addClassLoader(ClassLoader classLoader) {\n        super.addClassLoader(classLoader);\n        if (environment != null) {\n            environment.refreshClassLoaders();\n        }\n    }\n\n    @Override\n    public void removeClassLoader(ClassLoader classLoader) {\n        super.removeClassLoader(classLoader);\n        if (environment != null) {\n            environment.refreshClassLoaders();\n        }\n    }\n\n    @Override\n    protected boolean checkIfClassLoaderCanRemoved(ClassLoader classLoader) {\n        return super.checkIfClassLoaderCanRemoved(classLoader) && !containsClassLoader(classLoader);\n    }\n\n    protected boolean containsClassLoader(ClassLoader classLoader) {\n        return moduleModels.stream()\n                .anyMatch(moduleModel -> moduleModel.getClassLoaders().contains(classLoader));\n    }\n\n    public ApplicationDeployer getDeployer() {\n        return deployer;\n    }\n\n    public void setDeployer(ApplicationDeployer deployer) {\n        this.deployer = deployer;\n    }\n\n    @Override\n    protected Lock acquireDestroyLock() {\n        return frameworkModel.acquireDestroyLock();\n    }\n\n    // =============================== Deprecated Methods Start =======================================\n\n    /**\n     * @deprecated use {@link ServiceRepository#allConsumerModels()}\n     */\n    @Deprecated\n    public static Collection<ConsumerModel> allConsumerModels() {\n        return defaultModel().getApplicationServiceRepository().allConsumerModels();\n    }\n\n    /**\n     * @deprecated use {@link ServiceRepository#allProviderModels()}\n     */\n    @Deprecated\n    public static Collection<ProviderModel> allProviderModels() {\n        return defaultModel().getApplicationServiceRepository().allProviderModels();\n    }\n\n    /**\n     * @deprecated use {@link FrameworkServiceRepository#lookupExportedService(String)}\n     */\n    @Deprecated\n    public static ProviderModel getProviderModel(String serviceKey) {\n        return defaultModel().getDefaultModule().getServiceRepository().lookupExportedService(serviceKey);\n    }\n\n    /**\n     * @deprecated ConsumerModel should fetch from context\n     */\n    @Deprecated\n    public static ConsumerModel getConsumerModel(String serviceKey) {\n        return defaultModel().getDefaultModule().getServiceRepository().lookupReferredService(serviceKey);\n    }\n\n    /**\n     * @deprecated Replace to {@link ScopeModel#modelEnvironment()}\n     */\n    @Deprecated\n    public static Environment getEnvironment() {\n        return defaultModel().modelEnvironment();\n    }\n\n    /**\n     * @deprecated Replace to {@link ApplicationModel#getApplicationConfigManager()}\n     */\n    @Deprecated\n    public static ConfigManager getConfigManager() {\n        return defaultModel().getApplicationConfigManager();\n    }\n\n    /**\n     * @deprecated Replace to {@link ApplicationModel#getApplicationServiceRepository()}\n     */\n    @Deprecated\n    public static ServiceRepository getServiceRepository() {\n        return defaultModel().getApplicationServiceRepository();\n    }\n\n    /**\n     * @deprecated Replace to {@link ApplicationModel#getApplicationExecutorRepository()}\n     */\n    @Deprecated\n    public static ExecutorRepository getExecutorRepository() {\n        return defaultModel().getApplicationExecutorRepository();\n    }\n\n    /**\n     * @deprecated Replace to {@link ApplicationModel#getCurrentConfig()}\n     */\n    @Deprecated\n    public static ApplicationConfig getApplicationConfig() {\n        return defaultModel().getCurrentConfig();\n    }\n\n    /**\n     * @deprecated Replace to {@link ApplicationModel#getApplicationName()}\n     */\n    @Deprecated\n    public static String getName() {\n        return defaultModel().getCurrentConfig().getName();\n    }\n\n    /**\n     * @deprecated Replace to {@link ApplicationModel#getApplicationName()}\n     */\n    @Deprecated\n    public static String getApplication() {\n        return getName();\n    }\n\n    // only for unit test\n    @Deprecated\n    public static void reset() {\n        if (FrameworkModel.defaultModel().getDefaultAppModel() != null) {\n            FrameworkModel.defaultModel().getDefaultAppModel().destroy();\n        }\n    }\n\n    /**\n     * @deprecated only for ut\n     */\n    @Deprecated\n    public void setEnvironment(Environment environment) {\n        this.environment = environment;\n    }\n\n    /**\n     * @deprecated only for ut\n     */\n    @Deprecated\n    public void setConfigManager(ConfigManager configManager) {\n        this.configManager = configManager;\n    }\n\n    /**\n     * @deprecated only for ut\n     */\n    @Deprecated\n    public void setServiceRepository(ServiceRepository serviceRepository) {\n        this.serviceRepository = serviceRepository;\n    }\n\n    // =============================== Deprecated Methods End =======================================\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/AsyncMethodInfo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.lang.reflect.Method;\n\npublic class AsyncMethodInfo {\n    // callback instance when async-call is invoked\n    private Object oninvokeInstance;\n\n    // callback method when async-call is invoked\n    private Method oninvokeMethod;\n\n    // callback instance when async-call is returned\n    private Object onreturnInstance;\n\n    // callback method when async-call is returned\n    private Method onreturnMethod;\n\n    // callback instance when async-call has exception thrown\n    private Object onthrowInstance;\n\n    // callback method when async-call has exception thrown\n    private Method onthrowMethod;\n\n    public Object getOninvokeInstance() {\n        return oninvokeInstance;\n    }\n\n    public void setOninvokeInstance(Object oninvokeInstance) {\n        this.oninvokeInstance = oninvokeInstance;\n    }\n\n    public Method getOninvokeMethod() {\n        return oninvokeMethod;\n    }\n\n    public void setOninvokeMethod(Method oninvokeMethod) {\n        this.oninvokeMethod = oninvokeMethod;\n    }\n\n    public Object getOnreturnInstance() {\n        return onreturnInstance;\n    }\n\n    public void setOnreturnInstance(Object onreturnInstance) {\n        this.onreturnInstance = onreturnInstance;\n    }\n\n    public Method getOnreturnMethod() {\n        return onreturnMethod;\n    }\n\n    public void setOnreturnMethod(Method onreturnMethod) {\n        this.onreturnMethod = onreturnMethod;\n    }\n\n    public Object getOnthrowInstance() {\n        return onthrowInstance;\n    }\n\n    public void setOnthrowInstance(Object onthrowInstance) {\n        this.onthrowInstance = onthrowInstance;\n    }\n\n    public Method getOnthrowMethod() {\n        return onthrowMethod;\n    }\n\n    public void setOnthrowMethod(Method onthrowMethod) {\n        this.onthrowMethod = onthrowMethod;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/BuiltinServiceDetector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface BuiltinServiceDetector {\n\n    Class<?> getService();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ConsumerMethodModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.lang.reflect.Method;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.$INVOKE;\n\n/**\n * Replaced with {@link MethodDescriptor}\n */\n@Deprecated\npublic class ConsumerMethodModel {\n    private final Method method;\n    //    private final boolean isCallBack;\n    //    private final boolean isFuture;\n    private final String[] parameterTypes;\n    private final Class<?>[] parameterClasses;\n    private final Class<?> returnClass;\n    private final String methodName;\n    private final boolean generic;\n\n    private final ConcurrentMap<String, Object> attributeMap = new ConcurrentHashMap<>();\n\n    public ConsumerMethodModel(Method method) {\n        this.method = method;\n        this.parameterClasses = method.getParameterTypes();\n        this.returnClass = method.getReturnType();\n        this.parameterTypes = this.createParamSignature(parameterClasses);\n        this.methodName = method.getName();\n        this.generic = methodName.equals($INVOKE) && parameterTypes != null && parameterTypes.length == 3;\n    }\n\n    public Method getMethod() {\n        return method;\n    }\n\n    //    public ConcurrentMap<String, Object> getAttributeMap() {\n    //        return attributeMap;\n    //    }\n\n    public void addAttribute(String key, Object value) {\n        this.attributeMap.put(key, value);\n    }\n\n    public Object getAttribute(String key) {\n        return this.attributeMap.get(key);\n    }\n\n    public Class<?> getReturnClass() {\n        return returnClass;\n    }\n\n    public String getMethodName() {\n        return methodName;\n    }\n\n    public String[] getParameterTypes() {\n        return parameterTypes;\n    }\n\n    private String[] createParamSignature(Class<?>[] args) {\n        if (args == null || args.length == 0) {\n            return new String[] {};\n        }\n        String[] paramSig = new String[args.length];\n        for (int x = 0; x < args.length; x++) {\n            paramSig[x] = args[x].getName();\n        }\n        return paramSig;\n    }\n\n    public boolean isGeneric() {\n        return generic;\n    }\n\n    public Class<?>[] getParameterClasses() {\n        return parameterClasses;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ConsumerModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.Assert;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeSet;\n\n/**\n * This model is bound to your reference's configuration, for example, group, version or method level configuration.\n */\npublic class ConsumerModel extends ServiceModel {\n    private final Set<String> apps = new TreeSet<>();\n\n    private final Map<String, AsyncMethodInfo> methodConfigs;\n    private Map<Method, ConsumerMethodModel> methodModels = new HashMap<>();\n\n    /**\n     * This constructor creates an instance of ConsumerModel and passed objects should not be null.\n     * If service name, service instance, proxy object,methods should not be null. If these are null\n     * then this constructor will throw {@link IllegalArgumentException}\n     *\n     * @param serviceKey  Name of the service.\n     * @param proxyObject Proxy object.\n     */\n    public ConsumerModel(\n            String serviceKey,\n            Object proxyObject,\n            ServiceDescriptor serviceDescriptor,\n            Map<String, AsyncMethodInfo> methodConfigs,\n            ClassLoader interfaceClassLoader) {\n\n        super(proxyObject, serviceKey, serviceDescriptor, null, interfaceClassLoader);\n        Assert.notEmptyString(serviceKey, \"Service name can't be null or blank\");\n\n        this.methodConfigs = methodConfigs == null ? new HashMap<>() : methodConfigs;\n    }\n\n    public ConsumerModel(\n            String serviceKey,\n            Object proxyObject,\n            ServiceDescriptor serviceDescriptor,\n            ServiceMetadata metadata,\n            Map<String, AsyncMethodInfo> methodConfigs,\n            ClassLoader interfaceClassLoader) {\n\n        super(proxyObject, serviceKey, serviceDescriptor, null, metadata, interfaceClassLoader);\n        Assert.notEmptyString(serviceKey, \"Service name can't be null or blank\");\n\n        this.methodConfigs = methodConfigs == null ? new HashMap<>() : methodConfigs;\n    }\n\n    public ConsumerModel(\n            String serviceKey,\n            Object proxyObject,\n            ServiceDescriptor serviceDescriptor,\n            ModuleModel moduleModel,\n            ServiceMetadata metadata,\n            Map<String, AsyncMethodInfo> methodConfigs,\n            ClassLoader interfaceClassLoader) {\n        super(proxyObject, serviceKey, serviceDescriptor, moduleModel, metadata, interfaceClassLoader);\n\n        Assert.notEmptyString(serviceKey, \"Service name can't be null or blank\");\n\n        this.methodConfigs = methodConfigs == null ? new HashMap<>() : methodConfigs;\n    }\n\n    public AsyncMethodInfo getMethodConfig(String methodName) {\n        return methodConfigs.get(methodName);\n    }\n\n    public Set<String> getApps() {\n        return apps;\n    }\n\n    public AsyncMethodInfo getAsyncInfo(String methodName) {\n        return methodConfigs.get(methodName);\n    }\n\n    public void initMethodModels() {\n        Class<?>[] interfaceList;\n        if (getProxyObject() == null) {\n            Class<?> serviceInterfaceClass = getServiceInterfaceClass();\n            if (serviceInterfaceClass != null) {\n                interfaceList = new Class[] {serviceInterfaceClass};\n            } else {\n                interfaceList = new Class[0];\n            }\n        } else {\n            interfaceList = getProxyObject().getClass().getInterfaces();\n        }\n        for (Class<?> interfaceClass : interfaceList) {\n            for (Method method : interfaceClass.getMethods()) {\n                methodModels.put(method, new ConsumerMethodModel(method));\n            }\n        }\n    }\n\n    /**\n     * Return method model for the given method on consumer side\n     *\n     * @param method method object\n     * @return method model\n     */\n    public ConsumerMethodModel getMethodModel(Method method) {\n        return methodModels.get(method);\n    }\n\n    /**\n     * Return method model for the given method on consumer side\n     *\n     * @param method method object\n     * @return method model\n     */\n    public ConsumerMethodModel getMethodModel(String method) {\n        Optional<Map.Entry<Method, ConsumerMethodModel>> consumerMethodModelEntry = methodModels.entrySet().stream()\n                .filter(entry -> entry.getKey().getName().equals(method))\n                .findFirst();\n        return consumerMethodModelEntry.map(Map.Entry::getValue).orElse(null);\n    }\n\n    /**\n     * @param method   methodName\n     * @param argsType method arguments type\n     * @return\n     */\n    public ConsumerMethodModel getMethodModel(String method, String[] argsType) {\n        Optional<ConsumerMethodModel> consumerMethodModel = methodModels.entrySet().stream()\n                .filter(entry -> entry.getKey().getName().equals(method))\n                .map(Map.Entry::getValue)\n                .filter(methodModel -> Arrays.equals(argsType, methodModel.getParameterTypes()))\n                .findFirst();\n        return consumerMethodModel.orElse(null);\n    }\n\n    /**\n     * Return all method models for the current service\n     *\n     * @return method model list\n     */\n    public List<ConsumerMethodModel> getAllMethodModels() {\n        return new ArrayList<>(methodModels.values());\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        if (!super.equals(o)) {\n            return false;\n        }\n        ConsumerModel that = (ConsumerModel) o;\n        return Objects.equals(apps, that.apps)\n                && Objects.equals(methodConfigs, that.methodConfigs)\n                && Objects.equals(methodModels, that.methodModels);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), apps, methodConfigs, methodModels);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/DubboStub.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\n/**\n * Marker interface implemented by all stub. Used to detect\n * whether objects are Dubbo-generated stub.\n */\npublic interface DubboStub {}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/FrameworkModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.resource.GlobalResourcesRepository;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metadata.definition.TypeDefinitionBuilder;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.stream.Collectors;\n\n/**\n * Model of dubbo framework, it can be shared with multiple applications.\n */\npublic class FrameworkModel extends ScopeModel {\n\n    // ========================= Static Fields Start ===================================\n\n    protected static final Logger LOGGER = LoggerFactory.getLogger(FrameworkModel.class);\n\n    public static final String NAME = \"FrameworkModel\";\n    private static final AtomicLong index = new AtomicLong(1);\n\n    private static final Object globalLock = new Object();\n\n    private static volatile FrameworkModel defaultInstance;\n\n    private static final List<FrameworkModel> allInstances = new CopyOnWriteArrayList<>();\n\n    // ========================= Static Fields End ===================================\n\n    // internal app index is 0, default app index is 1\n    private final AtomicLong appIndex = new AtomicLong(0);\n\n    private volatile ApplicationModel defaultAppModel;\n\n    private final List<ApplicationModel> applicationModels = new CopyOnWriteArrayList<>();\n\n    private final List<ApplicationModel> pubApplicationModels = new CopyOnWriteArrayList<>();\n\n    private final FrameworkServiceRepository serviceRepository;\n\n    private final ApplicationModel internalApplicationModel;\n\n    private final ReentrantLock destroyLock = new ReentrantLock();\n\n    /**\n     * Use {@link FrameworkModel#newModel()} to create a new model\n     */\n    public FrameworkModel() {\n        super(null, ExtensionScope.FRAMEWORK, false);\n        synchronized (globalLock) {\n            synchronized (instLock) {\n                this.setInternalId(String.valueOf(index.getAndIncrement()));\n                // register FrameworkModel instance early\n                allInstances.add(this);\n                if (LOGGER.isInfoEnabled()) {\n                    LOGGER.info(getDesc() + \" is created\");\n                }\n                initialize();\n\n                TypeDefinitionBuilder.initBuilders(this);\n\n                serviceRepository = new FrameworkServiceRepository(this);\n\n                ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader =\n                        this.getExtensionLoader(ScopeModelInitializer.class);\n                Set<ScopeModelInitializer> initializers = initializerExtensionLoader.getSupportedExtensionInstances();\n                for (ScopeModelInitializer initializer : initializers) {\n                    initializer.initializeFrameworkModel(this);\n                }\n\n                internalApplicationModel = new ApplicationModel(this, true);\n                internalApplicationModel\n                        .getApplicationConfigManager()\n                        .setApplication(new ApplicationConfig(\n                                internalApplicationModel, CommonConstants.DUBBO_INTERNAL_APPLICATION));\n                internalApplicationModel.setModelName(CommonConstants.DUBBO_INTERNAL_APPLICATION);\n            }\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        synchronized (instLock) {\n            if (defaultInstance == this) {\n                // NOTE: During destroying the default FrameworkModel, the FrameworkModel.defaultModel() or\n                // ApplicationModel.defaultModel()\n                // will return a broken model, maybe cause unpredictable problem.\n                if (LOGGER.isInfoEnabled()) {\n                    LOGGER.info(\"Destroying default framework model: \" + getDesc());\n                }\n            }\n\n            if (LOGGER.isInfoEnabled()) {\n                LOGGER.info(getDesc() + \" is destroying ...\");\n            }\n\n            // destroy all application model\n            for (ApplicationModel applicationModel : new ArrayList<>(applicationModels)) {\n                applicationModel.destroy();\n            }\n            // check whether all application models are destroyed\n            checkApplicationDestroy();\n\n            // notify destroy and clean framework resources\n            // see org.apache.dubbo.config.deploy.FrameworkModelCleaner\n            notifyDestroy();\n\n            if (LOGGER.isInfoEnabled()) {\n                LOGGER.info(getDesc() + \" is destroyed\");\n            }\n\n            // remove from allInstances and reset default FrameworkModel\n            synchronized (globalLock) {\n                allInstances.remove(this);\n                resetDefaultFrameworkModel();\n            }\n\n            // if all FrameworkModels are destroyed, clean global static resources, shutdown dubbo completely\n            destroyGlobalResources();\n        }\n    }\n\n    private void checkApplicationDestroy() {\n        synchronized (instLock) {\n            if (applicationModels.size() > 0) {\n                List<String> remainApplications =\n                        applicationModels.stream().map(ScopeModel::getDesc).collect(Collectors.toList());\n                throw new IllegalStateException(\n                        \"Not all application models are completely destroyed, remaining \" + remainApplications.size()\n                                + \" application models may be created during destruction: \" + remainApplications);\n            }\n        }\n    }\n\n    private void destroyGlobalResources() {\n        synchronized (globalLock) {\n            if (allInstances.isEmpty()) {\n                GlobalResourcesRepository.getInstance().destroy();\n            }\n        }\n    }\n\n    /**\n     * During destroying the default FrameworkModel, the FrameworkModel.defaultModel() or ApplicationModel.defaultModel()\n     * will return a broken model, maybe cause unpredictable problem.\n     * Recommendation: Avoid using the default model as much as possible.\n     * @return the global default FrameworkModel\n     */\n    public static FrameworkModel defaultModel() {\n        FrameworkModel instance = defaultInstance;\n        if (instance == null) {\n            synchronized (globalLock) {\n                resetDefaultFrameworkModel();\n                if (defaultInstance == null) {\n                    defaultInstance = new FrameworkModel();\n                }\n                instance = defaultInstance;\n            }\n        }\n        Assert.notNull(instance, \"Default FrameworkModel is null\");\n        return instance;\n    }\n\n    /**\n     * Get all framework model instances\n     * @return\n     */\n    public static List<FrameworkModel> getAllInstances() {\n        synchronized (globalLock) {\n            return Collections.unmodifiableList(new ArrayList<>(allInstances));\n        }\n    }\n\n    /**\n     * Destroy all framework model instances, shutdown dubbo engine completely.\n     */\n    public static void destroyAll() {\n        synchronized (globalLock) {\n            for (FrameworkModel frameworkModel : new ArrayList<>(allInstances)) {\n                frameworkModel.destroy();\n            }\n        }\n    }\n\n    public ApplicationModel newApplication() {\n        synchronized (instLock) {\n            return new ApplicationModel(this);\n        }\n    }\n\n    /**\n     * Get or create default application model\n     * @return\n     */\n    public ApplicationModel defaultApplication() {\n        ApplicationModel appModel = this.defaultAppModel;\n        if (appModel == null) {\n            // check destroyed before acquire inst lock, avoid blocking during destroying\n            checkDestroyed();\n            resetDefaultAppModel();\n            if ((appModel = this.defaultAppModel) == null) {\n                synchronized (instLock) {\n                    if (this.defaultAppModel == null) {\n                        this.defaultAppModel = newApplication();\n                    }\n                    appModel = this.defaultAppModel;\n                }\n            }\n        }\n        Assert.notNull(appModel, \"Default ApplicationModel is null\");\n        return appModel;\n    }\n\n    ApplicationModel getDefaultAppModel() {\n        return defaultAppModel;\n    }\n\n    void addApplication(ApplicationModel applicationModel) {\n        // can not add new application if it's destroying\n        checkDestroyed();\n        synchronized (instLock) {\n            if (!this.applicationModels.contains(applicationModel)) {\n                applicationModel.setInternalId(buildInternalId(getInternalId(), appIndex.getAndIncrement()));\n                this.applicationModels.add(applicationModel);\n                if (!applicationModel.isInternal()) {\n                    this.pubApplicationModels.add(applicationModel);\n                }\n            }\n        }\n    }\n\n    void removeApplication(ApplicationModel model) {\n        synchronized (instLock) {\n            this.applicationModels.remove(model);\n            if (!model.isInternal()) {\n                this.pubApplicationModels.remove(model);\n            }\n            resetDefaultAppModel();\n        }\n    }\n\n    /**\n     * Protocols are special resources that need to be destroyed as soon as possible.\n     *\n     * Since connections inside protocol are not classified by applications, trying to destroy protocols in advance might only work for singleton application scenario.\n     */\n    void tryDestroyProtocols() {\n        synchronized (instLock) {\n            if (pubApplicationModels.size() == 0) {\n                notifyProtocolDestroy();\n            }\n        }\n    }\n\n    void tryDestroy() {\n        synchronized (instLock) {\n            if (pubApplicationModels.size() == 0) {\n                destroy();\n            }\n        }\n    }\n\n    private void checkDestroyed() {\n        if (isDestroyed()) {\n            throw new IllegalStateException(\"FrameworkModel is destroyed\");\n        }\n    }\n\n    private void resetDefaultAppModel() {\n        synchronized (instLock) {\n            if (this.defaultAppModel != null && !this.defaultAppModel.isDestroyed()) {\n                return;\n            }\n            ApplicationModel oldDefaultAppModel = this.defaultAppModel;\n            if (pubApplicationModels.size() > 0) {\n                this.defaultAppModel = pubApplicationModels.get(0);\n            } else {\n                this.defaultAppModel = null;\n            }\n            if (defaultInstance == this && oldDefaultAppModel != this.defaultAppModel) {\n                if (LOGGER.isInfoEnabled()) {\n                    LOGGER.info(\"Reset global default application from \" + safeGetModelDesc(oldDefaultAppModel) + \" to \"\n                            + safeGetModelDesc(this.defaultAppModel));\n                }\n            }\n        }\n    }\n\n    private static void resetDefaultFrameworkModel() {\n        synchronized (globalLock) {\n            if (defaultInstance != null && !defaultInstance.isDestroyed()) {\n                return;\n            }\n            FrameworkModel oldDefaultFrameworkModel = defaultInstance;\n            if (allInstances.size() > 0) {\n                defaultInstance = allInstances.get(0);\n            } else {\n                defaultInstance = null;\n            }\n            if (oldDefaultFrameworkModel != defaultInstance) {\n                if (LOGGER.isInfoEnabled()) {\n                    LOGGER.info(\"Reset global default framework from \" + safeGetModelDesc(oldDefaultFrameworkModel)\n                            + \" to \" + safeGetModelDesc(defaultInstance));\n                }\n            }\n        }\n    }\n\n    private static String safeGetModelDesc(ScopeModel scopeModel) {\n        return scopeModel != null ? scopeModel.getDesc() : null;\n    }\n\n    /**\n     * Get all application models except for the internal application model.\n     */\n    public List<ApplicationModel> getApplicationModels() {\n        synchronized (globalLock) {\n            return Collections.unmodifiableList(pubApplicationModels);\n        }\n    }\n\n    /**\n     * Get all application models including the internal application model.\n     */\n    public List<ApplicationModel> getAllApplicationModels() {\n        synchronized (globalLock) {\n            return Collections.unmodifiableList(applicationModels);\n        }\n    }\n\n    public ApplicationModel getInternalApplicationModel() {\n        return internalApplicationModel;\n    }\n\n    public FrameworkServiceRepository getServiceRepository() {\n        return serviceRepository;\n    }\n\n    @Override\n    protected Lock acquireDestroyLock() {\n        return destroyLock;\n    }\n\n    @Override\n    public Environment modelEnvironment() {\n        throw new UnsupportedOperationException(\"Environment is inaccessible for FrameworkModel\");\n    }\n\n    @Override\n    protected boolean checkIfClassLoaderCanRemoved(ClassLoader classLoader) {\n        return super.checkIfClassLoaderCanRemoved(classLoader)\n                && applicationModels.stream()\n                        .noneMatch(applicationModel -> applicationModel.containsClassLoader(classLoader));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/FrameworkServiceRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport static org.apache.dubbo.common.BaseServiceMetadata.interfaceFromServiceKey;\nimport static org.apache.dubbo.common.BaseServiceMetadata.versionFromServiceKey;\n\n/**\n * Service repository for framework\n */\npublic class FrameworkServiceRepository {\n\n    private final FrameworkModel frameworkModel;\n\n    // useful to find a provider model quickly with group/serviceInterfaceName:version\n    private final ConcurrentMap<String, ProviderModel> providers = new ConcurrentHashMap<>();\n\n    // useful to find a provider model quickly with serviceInterfaceName:version\n    private final ConcurrentMap<String, List<ProviderModel>> providersWithoutGroup = new ConcurrentHashMap<>();\n\n    public FrameworkServiceRepository(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    public void registerProvider(ProviderModel providerModel) {\n        String key = providerModel.getServiceKey();\n        ProviderModel previous = providers.putIfAbsent(key, providerModel);\n        if (previous != null && previous != providerModel) {\n            // TODO callback service multi instances\n            // throw new IllegalStateException(\"Register duplicate provider for key: \" + key);\n        }\n        String keyWithoutGroup = keyWithoutGroup(key);\n        ConcurrentHashMapUtils.computeIfAbsent(\n                        providersWithoutGroup, keyWithoutGroup, (k) -> new CopyOnWriteArrayList<>())\n                .add(providerModel);\n    }\n\n    public void unregisterProvider(ProviderModel providerModel) {\n        providers.remove(providerModel.getServiceKey());\n        String keyWithoutGroup = keyWithoutGroup(providerModel.getServiceKey());\n        providersWithoutGroup.remove(keyWithoutGroup);\n    }\n\n    public ProviderModel lookupExportedServiceWithoutGroup(String key) {\n        if (providersWithoutGroup.containsKey(key)) {\n            List<ProviderModel> providerModels = providersWithoutGroup.get(key);\n            return providerModels.size() > 0 ? providerModels.get(0) : null;\n        } else {\n            return null;\n        }\n    }\n\n    public List<ProviderModel> lookupExportedServicesWithoutGroup(String key) {\n        return providersWithoutGroup.get(key);\n    }\n\n    public ProviderModel lookupExportedService(String serviceKey) {\n        return providers.get(serviceKey);\n    }\n\n    public List<ProviderModel> allProviderModels() {\n        return Collections.unmodifiableList(new ArrayList<>(providers.values()));\n    }\n\n    public List<ConsumerModel> allConsumerModels() {\n        List<ConsumerModel> consumerModels = new LinkedList<>();\n        frameworkModel\n                .getApplicationModels()\n                .forEach(applicationModel -> consumerModels.addAll(\n                        applicationModel.getApplicationServiceRepository().allConsumerModels()));\n        return Collections.unmodifiableList(consumerModels);\n    }\n\n    private static String keyWithoutGroup(String serviceKey) {\n        String interfaceName = interfaceFromServiceKey(serviceKey);\n        String version = versionFromServiceKey(serviceKey);\n        if (StringUtils.isEmpty(version)) {\n            return interfaceName;\n        }\n        return interfaceName + CommonConstants.GROUP_CHAR_SEPARATOR + version;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/MethodDescriptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\n\npublic interface MethodDescriptor {\n\n    /**\n     * Retrieves the method name.\n     * <p>\n     * In Protobuf scenarios, this name may start with an uppercase letter.\n     *\n     * @return the method name\n     */\n    String getMethodName();\n\n    /**\n     * Retrieves the Java method name.\n     * <p>\n     * In Protobuf scenarios, This name is typically converted to start with a lowercase letter for Java naming conventions.\n     *\n     * @return the Java method name as a String\n     */\n    String getJavaMethodName();\n\n    String getParamDesc();\n\n    /**\n     * duplicate filed as paramDesc, but with different format.\n     */\n    String[] getCompatibleParamSignatures();\n\n    Class<?>[] getParameterClasses();\n\n    Class<?> getReturnClass();\n\n    Type[] getReturnTypes();\n\n    RpcType getRpcType();\n\n    boolean isGeneric();\n\n    /**\n     * Only available for ReflectionMethod\n     *\n     * @return method\n     */\n    Method getMethod();\n\n    void addAttribute(String key, Object value);\n\n    Object getAttribute(String key);\n\n    Class<?>[] getActualRequestTypes();\n\n    Class<?> getActualResponseType();\n\n    enum RpcType {\n        UNARY,\n        CLIENT_STREAM,\n        SERVER_STREAM,\n        BI_STREAM\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\npublic interface ModelConstants {\n\n    String DEPLOYER = \"deployer\";\n\n    /**\n     * Keep Dubbo running when spring is stopped\n     */\n    String KEEP_RUNNING_ON_SPRING_CLOSED = \"keepRunningOnSpringClosed\";\n\n    String KEEP_RUNNING_ON_SPRING_CLOSED_KEY = \"dubbo.module.keepRunningOnSpringClosed\";\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ModuleEnvironment;\nimport org.apache.dubbo.common.context.ModuleExt;\nimport org.apache.dubbo.common.deploy.ApplicationDeployer;\nimport org.apache.dubbo.common.deploy.DeployState;\nimport org.apache.dubbo.common.deploy.ModuleDeployer;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\n\nimport java.util.HashMap;\nimport java.util.Set;\nimport java.util.concurrent.locks.Lock;\n\n/**\n * Model of a service module\n */\npublic class ModuleModel extends ScopeModel {\n    private static final Logger logger = LoggerFactory.getLogger(ModuleModel.class);\n\n    public static final String NAME = \"ModuleModel\";\n\n    private final ApplicationModel applicationModel;\n    private volatile ModuleServiceRepository serviceRepository;\n    private volatile ModuleEnvironment moduleEnvironment;\n    private volatile ModuleConfigManager moduleConfigManager;\n    private volatile ModuleDeployer deployer;\n    private boolean lifeCycleManagedExternally = false;\n\n    protected ModuleModel(ApplicationModel applicationModel) {\n        this(applicationModel, false);\n    }\n\n    protected ModuleModel(ApplicationModel applicationModel, boolean isInternal) {\n        super(applicationModel, ExtensionScope.MODULE, isInternal);\n        synchronized (instLock) {\n            Assert.notNull(applicationModel, \"ApplicationModel can not be null\");\n            this.applicationModel = applicationModel;\n            applicationModel.addModule(this, isInternal);\n            if (LOGGER.isInfoEnabled()) {\n                LOGGER.info(getDesc() + \" is created\");\n            }\n\n            initialize();\n\n            this.serviceRepository = new ModuleServiceRepository(this);\n\n            initModuleExt();\n\n            ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader =\n                    this.getExtensionLoader(ScopeModelInitializer.class);\n            Set<ScopeModelInitializer> initializers = initializerExtensionLoader.getSupportedExtensionInstances();\n            for (ScopeModelInitializer initializer : initializers) {\n                initializer.initializeModuleModel(this);\n            }\n            Assert.notNull(getServiceRepository(), \"ModuleServiceRepository can not be null\");\n            Assert.notNull(getConfigManager(), \"ModuleConfigManager can not be null\");\n            Assert.assertTrue(getConfigManager().isInitialized(), \"ModuleConfigManager can not be initialized\");\n\n            // notify application check state\n            ApplicationDeployer applicationDeployer = applicationModel.getDeployer();\n            if (applicationDeployer != null) {\n                applicationDeployer.notifyModuleChanged(this, DeployState.PENDING);\n            }\n        }\n    }\n\n    // already synchronized in constructor\n    private void initModuleExt() {\n        Set<ModuleExt> exts = this.getExtensionLoader(ModuleExt.class).getSupportedExtensionInstances();\n        for (ModuleExt ext : exts) {\n            ext.initialize();\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        synchronized (instLock) {\n            // 1. remove from applicationModel\n            applicationModel.removeModule(this);\n\n            // 2. set stopping\n            if (deployer != null) {\n                deployer.preDestroy();\n            }\n\n            // 3. release services\n            if (deployer != null) {\n                deployer.postDestroy();\n            }\n\n            // destroy other resources\n            notifyDestroy();\n\n            if (serviceRepository != null) {\n                serviceRepository.destroy();\n                serviceRepository = null;\n            }\n\n            if (moduleEnvironment != null) {\n                moduleEnvironment.destroy();\n                moduleEnvironment = null;\n            }\n\n            if (moduleConfigManager != null) {\n                moduleConfigManager.destroy();\n                moduleConfigManager = null;\n            }\n\n            // destroy application if none pub module\n            applicationModel.tryDestroy();\n        }\n    }\n\n    public ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    public ModuleServiceRepository getServiceRepository() {\n        return serviceRepository;\n    }\n\n    @Override\n    public void addClassLoader(ClassLoader classLoader) {\n        super.addClassLoader(classLoader);\n        if (moduleEnvironment != null) {\n            moduleEnvironment.refreshClassLoaders();\n        }\n    }\n\n    @Override\n    public ModuleEnvironment modelEnvironment() {\n        if (moduleEnvironment == null) {\n            moduleEnvironment =\n                    (ModuleEnvironment) this.getExtensionLoader(ModuleExt.class).getExtension(ModuleEnvironment.NAME);\n        }\n        return moduleEnvironment;\n    }\n\n    public ModuleConfigManager getConfigManager() {\n        if (moduleConfigManager == null) {\n            moduleConfigManager = (ModuleConfigManager)\n                    this.getExtensionLoader(ModuleExt.class).getExtension(ModuleConfigManager.NAME);\n        }\n        return moduleConfigManager;\n    }\n\n    public ModuleDeployer getDeployer() {\n        return deployer;\n    }\n\n    public void setDeployer(ModuleDeployer deployer) {\n        this.deployer = deployer;\n    }\n\n    @Override\n    protected Lock acquireDestroyLock() {\n        return getApplicationModel().getFrameworkModel().acquireDestroyLock();\n    }\n\n    /**\n     * for ut only\n     */\n    @Deprecated\n    public void setModuleEnvironment(ModuleEnvironment moduleEnvironment) {\n        this.moduleEnvironment = moduleEnvironment;\n    }\n\n    public ConsumerModel registerInternalConsumer(\n            Class<?> internalService, URL url, ServiceDescriptor serviceDescriptor, Object proxyObject) {\n        ServiceMetadata serviceMetadata = new ServiceMetadata();\n        serviceMetadata.setVersion(url.getVersion());\n        serviceMetadata.setGroup(url.getGroup());\n        serviceMetadata.setDefaultGroup(url.getGroup());\n        serviceMetadata.setServiceInterfaceName(internalService.getName());\n        serviceMetadata.setServiceType(internalService);\n        String serviceKey = URL.buildKey(internalService.getName(), url.getGroup(), url.getVersion());\n        serviceMetadata.setServiceKey(serviceKey);\n        ConsumerModel consumerModel = new ConsumerModel(\n                serviceMetadata.getServiceKey(),\n                proxyObject,\n                serviceDescriptor == null\n                        ? serviceRepository.lookupService(serviceMetadata.getServiceInterfaceName())\n                        : serviceDescriptor,\n                this,\n                serviceMetadata,\n                new HashMap<>(0),\n                ClassUtils.getClassLoader(internalService));\n\n        logger.info(\"[INSTANCE_REGISTER] Dynamically registering consumer model \" + serviceKey + \" into model \"\n                + this.getDesc());\n        serviceRepository.registerConsumer(consumerModel);\n        return consumerModel;\n    }\n\n    public ConsumerModel registerInternalConsumer(\n            Class<?> internalService, URL url, ServiceDescriptor serviceDescriptor) {\n        return registerInternalConsumer(internalService, url, serviceDescriptor, null);\n    }\n\n    public ConsumerModel registerInternalConsumer(Class<?> internalService, URL url) {\n        return registerInternalConsumer(internalService, url, null, null);\n    }\n\n    public boolean isLifeCycleManagedExternally() {\n        return lifeCycleManagedExternally;\n    }\n\n    public void setLifeCycleManagedExternally(boolean lifeCycleManagedExternally) {\n        this.lifeCycleManagedExternally = lifeCycleManagedExternally;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleServiceRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.config.ServiceConfigBase;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.stream.Collectors;\n\n/**\n * Service repository for module\n */\npublic class ModuleServiceRepository {\n\n    private final ModuleModel moduleModel;\n\n    /**\n     * services\n     */\n    private final ConcurrentMap<String, List<ServiceDescriptor>> services = new ConcurrentHashMap<>();\n\n    /**\n     * consumers ( key - group/interface:version value - consumerModel list)\n     */\n    private final ConcurrentMap<String, List<ConsumerModel>> consumers = new ConcurrentHashMap<>();\n\n    /**\n     * providers\n     */\n    private final ConcurrentMap<String, ProviderModel> providers = new ConcurrentHashMap<>();\n\n    private final FrameworkServiceRepository frameworkServiceRepository;\n\n    public ModuleServiceRepository(ModuleModel moduleModel) {\n        this.moduleModel = moduleModel;\n        frameworkServiceRepository =\n                ScopeModelUtil.getFrameworkModel(moduleModel).getServiceRepository();\n    }\n\n    public ModuleModel getModuleModel() {\n        return moduleModel;\n    }\n\n    /**\n     * @deprecated Replaced to {@link ModuleServiceRepository#registerConsumer(ConsumerModel)}\n     */\n    @Deprecated\n    public void registerConsumer(\n            String serviceKey,\n            ServiceDescriptor serviceDescriptor,\n            ReferenceConfigBase<?> rc,\n            Object proxy,\n            ServiceMetadata serviceMetadata) {\n        ClassLoader classLoader = null;\n        if (rc != null) {\n            classLoader = rc.getInterfaceClassLoader();\n        }\n        ConsumerModel consumerModel = new ConsumerModel(\n                serviceMetadata.getServiceKey(), proxy, serviceDescriptor, serviceMetadata, null, classLoader);\n        this.registerConsumer(consumerModel);\n    }\n\n    public void registerConsumer(ConsumerModel consumerModel) {\n        ConcurrentHashMapUtils.computeIfAbsent(\n                        consumers, consumerModel.getServiceKey(), (serviceKey) -> new CopyOnWriteArrayList<>())\n                .add(consumerModel);\n    }\n\n    /**\n     * @deprecated Replaced to {@link ModuleServiceRepository#registerProvider(ProviderModel)}\n     */\n    @Deprecated\n    public void registerProvider(\n            String serviceKey,\n            Object serviceInstance,\n            ServiceDescriptor serviceModel,\n            ServiceConfigBase<?> serviceConfig,\n            ServiceMetadata serviceMetadata) {\n        ClassLoader classLoader = null;\n        Class<?> cla = null;\n        if (serviceConfig != null) {\n            classLoader = serviceConfig.getInterfaceClassLoader();\n            cla = serviceConfig.getInterfaceClass();\n        }\n        ProviderModel providerModel =\n                new ProviderModel(serviceKey, serviceInstance, serviceModel, serviceMetadata, classLoader);\n        this.registerProvider(providerModel);\n    }\n\n    public void registerProvider(ProviderModel providerModel) {\n        providers.putIfAbsent(providerModel.getServiceKey(), providerModel);\n        frameworkServiceRepository.registerProvider(providerModel);\n    }\n\n    public ServiceDescriptor registerService(ServiceDescriptor serviceDescriptor) {\n        return registerService(serviceDescriptor.getServiceInterfaceClass(), serviceDescriptor);\n    }\n\n    public ServiceDescriptor registerService(Class<?> interfaceClazz) {\n        ServiceDescriptor serviceDescriptor = new ReflectionServiceDescriptor(interfaceClazz);\n        return registerService(interfaceClazz, serviceDescriptor);\n    }\n\n    public ServiceDescriptor registerService(Class<?> interfaceClazz, ServiceDescriptor serviceDescriptor) {\n        List<ServiceDescriptor> serviceDescriptors = ConcurrentHashMapUtils.computeIfAbsent(\n                services, interfaceClazz.getName(), k -> new CopyOnWriteArrayList<>());\n        synchronized (serviceDescriptors) {\n            Optional<ServiceDescriptor> previous = serviceDescriptors.stream()\n                    .filter(s -> s.getServiceInterfaceClass().equals(interfaceClazz))\n                    .findFirst();\n            if (previous.isPresent()) {\n                return previous.get();\n            } else {\n                serviceDescriptors.add(serviceDescriptor);\n                return serviceDescriptor;\n            }\n        }\n    }\n\n    /**\n     * See {@link #registerService(Class)}\n     * <p>\n     * we assume:\n     * 1. services with different interfaces are not allowed to have the same path.\n     * 2. services share the same interface but has different group/version can share the same path.\n     * 3. path's default value is the name of the interface.\n     *\n     * @param path\n     * @param interfaceClass\n     * @return\n     */\n    public ServiceDescriptor registerService(String path, Class<?> interfaceClass) {\n        ServiceDescriptor serviceDescriptor = registerService(interfaceClass);\n        // if path is different with interface name, add extra path mapping\n        if (!interfaceClass.getName().equals(path)) {\n            List<ServiceDescriptor> serviceDescriptors =\n                    ConcurrentHashMapUtils.computeIfAbsent(services, path, _k -> new CopyOnWriteArrayList<>());\n            synchronized (serviceDescriptors) {\n                Optional<ServiceDescriptor> previous = serviceDescriptors.stream()\n                        .filter(s -> s.getServiceInterfaceClass().equals(serviceDescriptor.getServiceInterfaceClass()))\n                        .findFirst();\n                if (previous.isPresent()) {\n                    return previous.get();\n                } else {\n                    serviceDescriptors.add(serviceDescriptor);\n                    return serviceDescriptor;\n                }\n            }\n        }\n        return serviceDescriptor;\n    }\n\n    @Deprecated\n    public void reRegisterProvider(String newServiceKey, String serviceKey) {\n        ProviderModel providerModel = this.providers.get(serviceKey);\n        frameworkServiceRepository.unregisterProvider(providerModel);\n        providerModel.setServiceKey(newServiceKey);\n        this.providers.putIfAbsent(newServiceKey, providerModel);\n        frameworkServiceRepository.registerProvider(providerModel);\n        this.providers.remove(serviceKey);\n    }\n\n    @Deprecated\n    public void reRegisterConsumer(String newServiceKey, String serviceKey) {\n        List<ConsumerModel> consumerModel = this.consumers.get(serviceKey);\n        consumerModel.forEach(c -> c.setServiceKey(newServiceKey));\n        ConcurrentHashMapUtils.computeIfAbsent(this.consumers, newServiceKey, (k) -> new CopyOnWriteArrayList<>())\n                .addAll(consumerModel);\n        this.consumers.remove(serviceKey);\n    }\n\n    public void unregisterService(Class<?> interfaceClazz) {\n        // TODO remove\n        unregisterService(interfaceClazz.getName());\n    }\n\n    public void unregisterService(String path) {\n        services.remove(path);\n    }\n\n    public void unregisterProvider(ProviderModel providerModel) {\n        frameworkServiceRepository.unregisterProvider(providerModel);\n        providers.remove(providerModel.getServiceKey());\n    }\n\n    public void unregisterConsumer(ConsumerModel consumerModel) {\n        consumers.get(consumerModel.getServiceKey()).remove(consumerModel);\n    }\n\n    public List<ServiceDescriptor> getAllServices() {\n        List<ServiceDescriptor> serviceDescriptors =\n                services.values().stream().flatMap(Collection::stream).collect(Collectors.toList());\n        return Collections.unmodifiableList(serviceDescriptors);\n    }\n\n    public ServiceDescriptor getService(String serviceName) {\n        // TODO, may need to distinguish service by class loader.\n        List<ServiceDescriptor> serviceDescriptors = services.get(serviceName);\n        if (CollectionUtils.isEmpty(serviceDescriptors)) {\n            return null;\n        }\n        return serviceDescriptors.get(0);\n    }\n\n    public ServiceDescriptor lookupService(String interfaceName) {\n        if (interfaceName != null && services.containsKey(interfaceName)) {\n            List<ServiceDescriptor> serviceDescriptors = services.get(interfaceName);\n            return serviceDescriptors.size() > 0 ? serviceDescriptors.get(0) : null;\n        } else {\n            return null;\n        }\n    }\n\n    public MethodDescriptor lookupMethod(String interfaceName, String methodName) {\n        ServiceDescriptor serviceDescriptor = lookupService(interfaceName);\n        if (serviceDescriptor == null) {\n            return null;\n        }\n\n        List<MethodDescriptor> methods = serviceDescriptor.getMethods(methodName);\n        if (CollectionUtils.isEmpty(methods)) {\n            return null;\n        }\n        return methods.iterator().next();\n    }\n\n    public List<ProviderModel> getExportedServices() {\n        return Collections.unmodifiableList(new ArrayList<>(providers.values()));\n    }\n\n    public ProviderModel lookupExportedService(String serviceKey) {\n        return providers.get(serviceKey);\n    }\n\n    public List<ConsumerModel> getReferredServices() {\n        List<ConsumerModel> consumerModels =\n                consumers.values().stream().flatMap(Collection::stream).collect(Collectors.toList());\n        return Collections.unmodifiableList(consumerModels);\n    }\n\n    /**\n     * @deprecated Replaced to {@link ModuleServiceRepository#lookupReferredServices(String)}\n     */\n    @Deprecated\n    public ConsumerModel lookupReferredService(String serviceKey) {\n        if (consumers.containsKey(serviceKey)) {\n            List<ConsumerModel> consumerModels = consumers.get(serviceKey);\n            return consumerModels.size() > 0 ? consumerModels.get(0) : null;\n        } else {\n            return null;\n        }\n    }\n\n    public List<ConsumerModel> lookupReferredServices(String serviceKey) {\n        return consumers.get(serviceKey);\n    }\n\n    public void destroy() {\n        for (ProviderModel providerModel : providers.values()) {\n            frameworkServiceRepository.unregisterProvider(providerModel);\n        }\n        providers.clear();\n        consumers.clear();\n        services.clear();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/Pack.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.io.OutputStream;\n\npublic interface Pack {\n\n    /**\n     * @deprecated use {@link #pack(Object, OutputStream)} instead\n     */\n    @Deprecated\n    byte[] pack(Object obj) throws Exception;\n\n    default void pack(Object obj, OutputStream out) throws Exception {\n        out.write(pack(obj));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/PackableMethod.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * A packable method is used to customize serialization for methods. It can provide a common wrapper\n * for RESP / Protobuf.\n */\npublic interface PackableMethod {\n\n    /**\n     * @deprecated use {@link #parseRequest(InputStream)} instead\n     */\n    @Deprecated\n    default Object parseRequest(byte[] data) throws Exception {\n        return getRequestUnpack().unpack(data);\n    }\n\n    /**\n     * @deprecated use {@link #parseResponse(InputStream)} instead\n     */\n    @Deprecated\n    default Object parseResponse(byte[] data) throws Exception {\n        return parseResponse(data, false);\n    }\n\n    /**\n     * @deprecated use {@link #parseResponse(InputStream, boolean)} instead\n     */\n    @Deprecated\n    default Object parseResponse(byte[] data, boolean isReturnTriException) throws Exception {\n        UnPack unPack = getResponseUnpack();\n        if (unPack instanceof WrapperUnPack) {\n            return ((WrapperUnPack) unPack).unpack(data, isReturnTriException);\n        }\n        return unPack.unpack(data);\n    }\n\n    /**\n     * @deprecated use {@link #packRequest(Object, OutputStream)} instead\n     */\n    @Deprecated\n    default byte[] packRequest(Object request) throws Exception {\n        return getRequestPack().pack(request);\n    }\n\n    /**\n     * @deprecated use {@link #packResponse(Object, OutputStream)} instead\n     */\n    @Deprecated\n    default byte[] packResponse(Object response) throws Exception {\n        return getResponsePack().pack(response);\n    }\n\n    default Object parseRequest(InputStream inputStream) throws Exception {\n        return getRequestUnpack().unpack(inputStream);\n    }\n\n    default Object parseResponse(InputStream inputStream) throws Exception {\n        return parseResponse(inputStream, false);\n    }\n\n    default Object parseResponse(InputStream inputStream, boolean isReturnTriException) throws Exception {\n        UnPack unPack = getResponseUnpack();\n        if (unPack instanceof WrapperUnPack) {\n            return ((WrapperUnPack) unPack).unpack(inputStream, isReturnTriException);\n        }\n        return unPack.unpack(inputStream);\n    }\n\n    default void packRequest(Object request, OutputStream outputStream) throws Exception {\n        getRequestPack().pack(request, outputStream);\n    }\n\n    default void packResponse(Object response, OutputStream outputStream) throws Exception {\n        getResponsePack().pack(response, outputStream);\n    }\n\n    default boolean needWrapper() {\n        return false;\n    }\n\n    Pack getRequestPack();\n\n    Pack getResponsePack();\n\n    UnPack getResponseUnpack();\n\n    UnPack getRequestUnpack();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/PackableMethodFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface PackableMethodFactory {\n\n    PackableMethod create(MethodDescriptor methodDescriptor, URL url, String contentType);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ProviderMethodModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Replaced with {@link MethodDescriptor}\n */\n@Deprecated\npublic class ProviderMethodModel {\n    private final Method method;\n    private final String methodName;\n    private final Class<?>[] parameterClasses;\n    private final String[] methodArgTypes;\n    private final Type[] genericParameterTypes;\n    private final ConcurrentMap<String, Object> attributeMap = new ConcurrentHashMap<>();\n\n    public ProviderMethodModel(Method method) {\n        this.method = method;\n        this.methodName = method.getName();\n        this.parameterClasses = method.getParameterTypes();\n        this.methodArgTypes = getArgTypes(method);\n        this.genericParameterTypes = method.getGenericParameterTypes();\n    }\n\n    public Method getMethod() {\n        return method;\n    }\n\n    public String getMethodName() {\n        return methodName;\n    }\n\n    public String[] getMethodArgTypes() {\n        return methodArgTypes;\n    }\n\n    public ConcurrentMap<String, Object> getAttributeMap() {\n        return attributeMap;\n    }\n\n    private static String[] getArgTypes(Method method) {\n        String[] methodArgTypes = new String[0];\n        Class<?>[] parameterTypes = method.getParameterTypes();\n        if (parameterTypes.length > 0) {\n            methodArgTypes = new String[parameterTypes.length];\n            int index = 0;\n            for (Class<?> paramType : parameterTypes) {\n                methodArgTypes[index++] = paramType.getName();\n            }\n        }\n        return methodArgTypes;\n    }\n\n    public Class<?>[] getParameterClasses() {\n        return parameterClasses;\n    }\n\n    public Type[] getGenericParameterTypes() {\n        return genericParameterTypes;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ProviderModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\n/**\n * ProviderModel is about published services\n */\npublic class ProviderModel extends ServiceModel {\n    private final List<RegisterStatedURL> urls;\n    private final Map<String, List<ProviderMethodModel>> methods = new HashMap<>();\n\n    /**\n     * The url of the reference service\n     */\n    private List<URL> serviceUrls = new ArrayList<>();\n\n    private volatile long lastInvokeTime = 0;\n\n    public ProviderModel(\n            String serviceKey,\n            Object serviceInstance,\n            ServiceDescriptor serviceDescriptor,\n            ClassLoader interfaceClassLoader) {\n        super(serviceInstance, serviceKey, serviceDescriptor, null, interfaceClassLoader);\n        if (null == serviceInstance) {\n            throw new IllegalArgumentException(\"Service[\" + serviceKey + \"]Target is NULL.\");\n        }\n\n        this.urls = new CopyOnWriteArrayList<>();\n    }\n\n    public ProviderModel(\n            String serviceKey,\n            Object serviceInstance,\n            ServiceDescriptor serviceDescriptor,\n            ServiceMetadata serviceMetadata,\n            ClassLoader interfaceClassLoader) {\n        super(serviceInstance, serviceKey, serviceDescriptor, null, serviceMetadata, interfaceClassLoader);\n        if (null == serviceInstance) {\n            throw new IllegalArgumentException(\"Service[\" + serviceKey + \"]Target is NULL.\");\n        }\n\n        initMethod(serviceDescriptor.getServiceInterfaceClass());\n        this.urls = new ArrayList<>(1);\n    }\n\n    public ProviderModel(\n            String serviceKey,\n            Object serviceInstance,\n            ServiceDescriptor serviceModel,\n            ModuleModel moduleModel,\n            ServiceMetadata serviceMetadata,\n            ClassLoader interfaceClassLoader) {\n        super(serviceInstance, serviceKey, serviceModel, moduleModel, serviceMetadata, interfaceClassLoader);\n        if (null == serviceInstance) {\n            throw new IllegalArgumentException(\"Service[\" + serviceKey + \"]Target is NULL.\");\n        }\n\n        initMethod(serviceModel.getServiceInterfaceClass());\n        this.urls = new ArrayList<>(1);\n    }\n\n    public Object getServiceInstance() {\n        return getProxyObject();\n    }\n\n    public List<RegisterStatedURL> getStatedUrl() {\n        return urls;\n    }\n\n    public void addStatedUrl(RegisterStatedURL url) {\n        this.urls.add(url);\n    }\n\n    public static class RegisterStatedURL {\n        private volatile URL registryUrl;\n        private volatile URL providerUrl;\n        private volatile boolean registered;\n\n        public RegisterStatedURL(URL providerUrl, URL registryUrl, boolean registered) {\n            this.providerUrl = providerUrl;\n            this.registered = registered;\n            this.registryUrl = registryUrl;\n        }\n\n        public URL getProviderUrl() {\n            return providerUrl;\n        }\n\n        public void setProviderUrl(URL providerUrl) {\n            this.providerUrl = providerUrl;\n        }\n\n        public boolean isRegistered() {\n            return registered;\n        }\n\n        public void setRegistered(boolean registered) {\n            this.registered = registered;\n        }\n\n        public URL getRegistryUrl() {\n            return registryUrl;\n        }\n\n        public void setRegistryUrl(URL registryUrl) {\n            this.registryUrl = registryUrl;\n        }\n    }\n\n    public List<ProviderMethodModel> getAllMethodModels() {\n        List<ProviderMethodModel> result = new ArrayList<>();\n        for (List<ProviderMethodModel> models : methods.values()) {\n            result.addAll(models);\n        }\n        return result;\n    }\n\n    public ProviderMethodModel getMethodModel(String methodName, String[] argTypes) {\n        List<ProviderMethodModel> methodModels = methods.get(methodName);\n        if (methodModels != null) {\n            for (ProviderMethodModel methodModel : methodModels) {\n                if (Arrays.equals(argTypes, methodModel.getMethodArgTypes())) {\n                    return methodModel;\n                }\n            }\n        }\n        return null;\n    }\n\n    public List<ProviderMethodModel> getMethodModelList(String methodName) {\n        List<ProviderMethodModel> resultList = methods.get(methodName);\n        return resultList == null ? Collections.emptyList() : resultList;\n    }\n\n    private void initMethod(Class<?> serviceInterfaceClass) {\n        Method[] methodsToExport = serviceInterfaceClass.getMethods();\n\n        for (Method method : methodsToExport) {\n            method.setAccessible(true);\n\n            List<ProviderMethodModel> methodModels = methods.computeIfAbsent(method.getName(), k -> new ArrayList<>());\n            methodModels.add(new ProviderMethodModel(method));\n        }\n    }\n\n    public List<URL> getServiceUrls() {\n        return serviceUrls;\n    }\n\n    public void setServiceUrls(List<URL> urls) {\n        this.serviceUrls = urls;\n    }\n\n    public long getLastInvokeTime() {\n        return lastInvokeTime;\n    }\n\n    public void updateLastInvokeTime() {\n        this.lastInvokeTime = System.currentTimeMillis();\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        if (!super.equals(o)) {\n            return false;\n        }\n        ProviderModel that = (ProviderModel) o;\n        return Objects.equals(urls, that.urls) && Objects.equals(methods, that.methods);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), urls, methods);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ReflectionMethodDescriptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.common.utils.ReflectUtils;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Objects;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.stream.Stream;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.$INVOKE;\nimport static org.apache.dubbo.common.constants.CommonConstants.$INVOKE_ASYNC;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_REFLECTIVE_OPERATION_FAILED;\nimport static org.apache.dubbo.common.utils.MethodUtils.toShortString;\n\npublic class ReflectionMethodDescriptor implements MethodDescriptor {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ReflectionMethodDescriptor.class);\n\n    private final ConcurrentMap<String, Object> attributeMap = new ConcurrentHashMap<>();\n    public final String methodName;\n    private final String[] compatibleParamSignatures;\n    private final Class<?>[] parameterClasses;\n    private final Class<?> returnClass;\n    private final Type[] returnTypes;\n    private final String paramDesc;\n    private final Method method;\n    private final boolean generic;\n    private final RpcType rpcType;\n    private Class<?>[] actualRequestTypes;\n    private Class<?> actualResponseType;\n\n    public ReflectionMethodDescriptor(Method method) {\n        this.method = method;\n        this.methodName = method.getName();\n        this.parameterClasses = method.getParameterTypes();\n        this.returnClass = method.getReturnType();\n        Type[] returnTypesResult;\n        try {\n            returnTypesResult = ReflectUtils.getReturnTypes(method);\n        } catch (Throwable throwable) {\n            logger.error(\n                    COMMON_REFLECTIVE_OPERATION_FAILED,\n                    \"\",\n                    \"\",\n                    \"fail to get return types. Method name: \" + methodName + \" Declaring class:\"\n                            + method.getDeclaringClass().getName(),\n                    throwable);\n            returnTypesResult = new Type[] {returnClass, returnClass};\n        }\n        this.returnTypes = returnTypesResult;\n        this.paramDesc = ReflectUtils.getDesc(parameterClasses);\n        this.compatibleParamSignatures =\n                Stream.of(parameterClasses).map(Class::getName).toArray(String[]::new);\n        this.generic = (methodName.equals($INVOKE) || methodName.equals($INVOKE_ASYNC)) && parameterClasses.length == 3;\n        this.rpcType = determineRpcType();\n    }\n\n    private RpcType determineRpcType() {\n        if (generic) {\n            return RpcType.UNARY;\n        }\n        if (parameterClasses.length > 2) {\n            return RpcType.UNARY;\n        }\n        Type[] genericParameterTypes = method.getGenericParameterTypes();\n        if (parameterClasses.length == 1 && isStreamType(parameterClasses[0]) && isStreamType(returnClass)) {\n            this.actualRequestTypes = new Class<?>[] {\n                obtainActualTypeInStreamObserver(\n                        ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0])\n            };\n            actualResponseType = obtainActualTypeInStreamObserver(\n                    ((ParameterizedType) genericParameterTypes[0]).getActualTypeArguments()[0]);\n            return RpcType.BI_STREAM;\n        }\n        boolean returnIsVoid = returnClass.getName().equals(void.class.getName());\n        if (returnIsVoid && parameterClasses.length == 1 && isStreamType(parameterClasses[0])) {\n            actualRequestTypes = Collections.emptyList().toArray(new Class<?>[0]);\n            actualResponseType = obtainActualTypeInStreamObserver(\n                    ((ParameterizedType) method.getGenericParameterTypes()[0]).getActualTypeArguments()[0]);\n            return RpcType.SERVER_STREAM;\n        }\n        if (returnIsVoid\n                && parameterClasses.length == 2\n                && !isStreamType(parameterClasses[0])\n                && isStreamType(parameterClasses[1])) {\n            actualRequestTypes = parameterClasses;\n            actualResponseType = obtainActualTypeInStreamObserver(\n                    ((ParameterizedType) method.getGenericParameterTypes()[1]).getActualTypeArguments()[0]);\n            return RpcType.SERVER_STREAM;\n        }\n        if (Arrays.stream(parameterClasses).anyMatch(this::isStreamType) || isStreamType(returnClass)) {\n            throw new IllegalStateException(\n                    \"Bad stream method signature. method(\" + methodName + \":\" + paramDesc + \")\");\n        }\n        // Can not determine client stream because it has same signature with bi_stream\n        return RpcType.UNARY;\n    }\n\n    private boolean isStreamType(Class<?> classType) {\n        return StreamObserver.class.isAssignableFrom(classType);\n    }\n\n    @Override\n    public String getMethodName() {\n        return methodName;\n    }\n\n    @Override\n    public String getJavaMethodName() {\n        return method.getName();\n    }\n\n    @Override\n    public Method getMethod() {\n        return method;\n    }\n\n    @Override\n    public String[] getCompatibleParamSignatures() {\n        return compatibleParamSignatures;\n    }\n\n    @Override\n    public Class<?>[] getParameterClasses() {\n        return parameterClasses;\n    }\n\n    @Override\n    public String getParamDesc() {\n        return paramDesc;\n    }\n\n    @Override\n    public Class<?> getReturnClass() {\n        return returnClass;\n    }\n\n    @Override\n    public Type[] getReturnTypes() {\n        return returnTypes;\n    }\n\n    @Override\n    public RpcType getRpcType() {\n        return rpcType;\n    }\n\n    @Override\n    public boolean isGeneric() {\n        return generic;\n    }\n\n    public void addAttribute(String key, Object value) {\n        this.attributeMap.put(key, value);\n    }\n\n    public Object getAttribute(String key) {\n        return this.attributeMap.get(key);\n    }\n\n    @Override\n    public Class<?>[] getActualRequestTypes() {\n        return actualRequestTypes;\n    }\n\n    @Override\n    public Class<?> getActualResponseType() {\n        return actualResponseType;\n    }\n\n    private Class<?> obtainActualTypeInStreamObserver(Type typeInStreamObserver) {\n        return (Class<?>)\n                (typeInStreamObserver instanceof ParameterizedType\n                        ? ((ParameterizedType) typeInStreamObserver).getRawType()\n                        : typeInStreamObserver);\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        ReflectionMethodDescriptor that = (ReflectionMethodDescriptor) o;\n        return generic == that.generic\n                && Objects.equals(method, that.method)\n                && Objects.equals(paramDesc, that.paramDesc)\n                && Arrays.equals(compatibleParamSignatures, that.compatibleParamSignatures)\n                && Arrays.equals(parameterClasses, that.parameterClasses)\n                && Objects.equals(returnClass, that.returnClass)\n                && Arrays.equals(returnTypes, that.returnTypes)\n                && Objects.equals(methodName, that.methodName)\n                && Objects.equals(attributeMap, that.attributeMap);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = Objects.hash(method, paramDesc, returnClass, methodName, generic, attributeMap);\n        result = 31 * result + Arrays.hashCode(compatibleParamSignatures);\n        result = 31 * result + Arrays.hashCode(parameterClasses);\n        result = 31 * result + Arrays.hashCode(returnTypes);\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return \"ReflectionMethodDescriptor{method='\" + toShortString(method) + \"', rpcType=\" + rpcType + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ReflectionServiceDescriptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentNavigableMap;\nimport java.util.concurrent.ConcurrentSkipListMap;\n\npublic class ReflectionServiceDescriptor implements ServiceDescriptor {\n    private final String interfaceName;\n    private final Class<?> serviceInterfaceClass;\n    // to accelerate search\n    private final Map<String, List<MethodDescriptor>> methods = new HashMap<>();\n    private final Map<String, Map<String, MethodDescriptor>> descToMethods = new HashMap<>();\n    private final ConcurrentNavigableMap<String, FullServiceDefinition> serviceDefinitions =\n            new ConcurrentSkipListMap<>();\n\n    public ReflectionServiceDescriptor(String interfaceName, Class<?> interfaceClass) {\n        this.interfaceName = interfaceName;\n        this.serviceInterfaceClass = interfaceClass;\n    }\n\n    public void addMethod(MethodDescriptor methodDescriptor) {\n        methods.computeIfAbsent(methodDescriptor.getMethodName(), k -> new ArrayList<>(1))\n                .add(methodDescriptor);\n    }\n\n    public ReflectionServiceDescriptor(Class<?> interfaceClass) {\n        this.serviceInterfaceClass = interfaceClass;\n        this.interfaceName = interfaceClass.getName();\n        initMethods();\n    }\n\n    public FullServiceDefinition getFullServiceDefinition(String serviceKey) {\n        return serviceDefinitions.computeIfAbsent(\n                serviceKey,\n                (k) -> ServiceDefinitionBuilder.buildFullDefinition(serviceInterfaceClass, Collections.emptyMap()));\n    }\n\n    private void initMethods() {\n        Method[] methodsToExport = this.serviceInterfaceClass.getMethods();\n        for (Method method : methodsToExport) {\n            method.setAccessible(true);\n\n            MethodDescriptor methodDescriptor = new ReflectionMethodDescriptor(method);\n\n            List<MethodDescriptor> methodModels = methods.computeIfAbsent(method.getName(), (k) -> new ArrayList<>(1));\n            methodModels.add(methodDescriptor);\n        }\n\n        methods.forEach((methodName, methodList) -> {\n            Map<String, MethodDescriptor> descMap = descToMethods.computeIfAbsent(methodName, k -> new HashMap<>());\n            // not support BI_STREAM and SERVER_STREAM at the same time, for example,\n            // void foo(Request, StreamObserver<Response>)  ---> SERVER_STREAM\n            // StreamObserver<Response> foo(StreamObserver<Request>)   ---> BI_STREAM\n            long streamMethodCount = methodList.stream()\n                    .peek(methodModel -> descMap.put(methodModel.getParamDesc(), methodModel))\n                    .map(MethodDescriptor::getRpcType)\n                    .filter(rpcType -> rpcType == MethodDescriptor.RpcType.SERVER_STREAM\n                            || rpcType == MethodDescriptor.RpcType.BI_STREAM)\n                    .count();\n            if (streamMethodCount > 1L)\n                throw new IllegalStateException(\"Stream method could not be overloaded.There are \" + streamMethodCount\n                        + \" stream method signatures. method(\" + methodName + \")\");\n        });\n    }\n\n    public String getInterfaceName() {\n        return interfaceName;\n    }\n\n    public Class<?> getServiceInterfaceClass() {\n        return serviceInterfaceClass;\n    }\n\n    public Set<MethodDescriptor> getAllMethods() {\n        Set<MethodDescriptor> methodModels = new HashSet<>();\n        methods.forEach((k, v) -> methodModels.addAll(v));\n        return methodModels;\n    }\n\n    /**\n     * Does not use Optional as return type to avoid potential performance decrease.\n     *\n     * @param methodName\n     * @param params\n     * @return\n     */\n    public MethodDescriptor getMethod(String methodName, String params) {\n        Map<String, MethodDescriptor> methods = descToMethods.get(methodName);\n        if (CollectionUtils.isNotEmptyMap(methods)) {\n            return methods.get(params);\n        }\n        return null;\n    }\n\n    /**\n     * Does not use Optional as return type to avoid potential performance decrease.\n     *\n     * @param methodName\n     * @param paramTypes\n     * @return\n     */\n    public MethodDescriptor getMethod(String methodName, Class<?>[] paramTypes) {\n        List<MethodDescriptor> methodModels = methods.get(methodName);\n        if (CollectionUtils.isNotEmpty(methodModels)) {\n            for (MethodDescriptor descriptor : methodModels) {\n                if (Arrays.equals(paramTypes, descriptor.getParameterClasses())) {\n                    return descriptor;\n                }\n            }\n        }\n        return null;\n    }\n\n    public List<MethodDescriptor> getMethods(String methodName) {\n        return methods.get(methodName);\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        ReflectionServiceDescriptor that = (ReflectionServiceDescriptor) o;\n        return Objects.equals(interfaceName, that.interfaceName)\n                && Objects.equals(serviceInterfaceClass, that.serviceInterfaceClass)\n                && Objects.equals(methods, that.methods)\n                && Objects.equals(descToMethods, that.descToMethods);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(interfaceName, serviceInterfaceClass, methods, descToMethods);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeClassLoaderListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\npublic interface ScopeClassLoaderListener<T extends ScopeModel> {\n\n    void onAddClassLoader(T scopeModel, ClassLoader classLoader);\n\n    void onRemoveClassLoader(T scopeModel, ClassLoader classLoader);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.extension.ExtensionAccessor;\nimport org.apache.dubbo.common.extension.ExtensionDirector;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.Lock;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNABLE_DESTROY_MODEL;\n\n@SuppressWarnings({\"unchecked\", \"rawtypes\"})\npublic abstract class ScopeModel implements ExtensionAccessor {\n    protected static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(ScopeModel.class);\n\n    /**\n     * The internal id is used to represent the hierarchy of the model tree, such as:\n     * <ol>\n     *     <li>1</li>\n     *     FrameworkModel (index=1)\n     *     <li>1.2</li>\n     *     FrameworkModel (index=1) -> ApplicationModel (index=2)\n     *     <li>1.2.0</li>\n     *     FrameworkModel (index=1) -> ApplicationModel (index=2) -> ModuleModel (index=0, internal module)\n     *     <li>1.2.1</li>\n     *     FrameworkModel (index=1) -> ApplicationModel (index=2) -> ModuleModel (index=1, first user module)\n     * </ol>\n     */\n    private String internalId;\n\n    /**\n     * Public Model Name, can be set from user\n     */\n    private String modelName;\n\n    private String desc;\n\n    private final Set<ClassLoader> classLoaders = new ConcurrentHashSet<>();\n\n    private final ScopeModel parent;\n    private final ExtensionScope scope;\n\n    private volatile ExtensionDirector extensionDirector;\n\n    private volatile ScopeBeanFactory beanFactory;\n    private final List<ScopeModelDestroyListener> destroyListeners = new CopyOnWriteArrayList<>();\n\n    private final List<ScopeClassLoaderListener> classLoaderListeners = new CopyOnWriteArrayList<>();\n\n    private final Map<String, Object> attributes = new ConcurrentHashMap<>();\n    private final AtomicBoolean destroyed = new AtomicBoolean(false);\n    private final boolean internalScope;\n\n    protected final Object instLock = new Object();\n\n    protected ScopeModel(ScopeModel parent, ExtensionScope scope, boolean isInternal) {\n        this.parent = parent;\n        this.scope = scope;\n        this.internalScope = isInternal;\n    }\n\n    /**\n     * NOTE:\n     * <ol>\n     *  <li>The initialize method only be called in subclass.</li>\n     * <li>\n     * In subclass, the extensionDirector and beanFactory are available in initialize but not available in constructor.\n     * </li>\n     * </ol>\n     */\n    protected void initialize() {\n        synchronized (instLock) {\n            this.extensionDirector =\n                    new ExtensionDirector(parent != null ? parent.getExtensionDirector() : null, scope, this);\n            this.extensionDirector.addExtensionPostProcessor(new ScopeModelAwareExtensionProcessor(this));\n            this.beanFactory = new ScopeBeanFactory(parent != null ? parent.getBeanFactory() : null, extensionDirector);\n\n            // Add Framework's ClassLoader by default\n            ClassLoader dubboClassLoader = ScopeModel.class.getClassLoader();\n            if (dubboClassLoader != null) {\n                this.addClassLoader(dubboClassLoader);\n            }\n        }\n    }\n\n    protected abstract Lock acquireDestroyLock();\n\n    public void destroy() {\n        Lock lock = acquireDestroyLock();\n        try {\n            lock.lock();\n            if (destroyed.compareAndSet(false, true)) {\n                try {\n                    onDestroy();\n                    HashSet<ClassLoader> copyOfClassLoaders = new HashSet<>(classLoaders);\n                    for (ClassLoader classLoader : copyOfClassLoaders) {\n                        removeClassLoader(classLoader);\n                    }\n                    if (beanFactory != null) {\n                        beanFactory.destroy();\n                    }\n                    if (extensionDirector != null) {\n                        extensionDirector.destroy();\n                    }\n                } catch (Throwable t) {\n                    LOGGER.error(CONFIG_UNABLE_DESTROY_MODEL, \"\", \"\", \"Error happened when destroying ScopeModel.\", t);\n                }\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public boolean isDestroyed() {\n        return destroyed.get();\n    }\n\n    protected void notifyDestroy() {\n        for (ScopeModelDestroyListener destroyListener : destroyListeners) {\n            destroyListener.onDestroy(this);\n        }\n    }\n\n    protected void notifyProtocolDestroy() {\n        for (ScopeModelDestroyListener destroyListener : destroyListeners) {\n            if (destroyListener.isProtocol()) {\n                destroyListener.onDestroy(this);\n            }\n        }\n    }\n\n    protected void notifyClassLoaderAdd(ClassLoader classLoader) {\n        for (ScopeClassLoaderListener classLoaderListener : classLoaderListeners) {\n            classLoaderListener.onAddClassLoader(this, classLoader);\n        }\n    }\n\n    protected void notifyClassLoaderDestroy(ClassLoader classLoader) {\n        for (ScopeClassLoaderListener classLoaderListener : classLoaderListeners) {\n            classLoaderListener.onRemoveClassLoader(this, classLoader);\n        }\n    }\n\n    protected abstract void onDestroy();\n\n    public final void addDestroyListener(ScopeModelDestroyListener listener) {\n        destroyListeners.add(listener);\n    }\n\n    public final void addClassLoaderListener(ScopeClassLoaderListener listener) {\n        classLoaderListeners.add(listener);\n    }\n\n    public Map<String, Object> getAttributes() {\n        return attributes;\n    }\n\n    public <T> T getAttribute(String key, Class<T> type) {\n        return (T) attributes.get(key);\n    }\n\n    public Object getAttribute(String key) {\n        return attributes.get(key);\n    }\n\n    public void setAttribute(String key, Object value) {\n        attributes.put(key, value);\n    }\n\n    @Override\n    public ExtensionDirector getExtensionDirector() {\n        return extensionDirector;\n    }\n\n    public final ScopeBeanFactory getBeanFactory() {\n        return beanFactory;\n    }\n\n    public final <T> T getOrRegisterBean(Class<T> type) {\n        return beanFactory.getOrRegisterBean(type);\n    }\n\n    public final <T> T getBean(Class<T> type) {\n        return beanFactory.getBean(type);\n    }\n\n    public ScopeModel getParent() {\n        return parent;\n    }\n\n    public ExtensionScope getScope() {\n        return scope;\n    }\n\n    public void addClassLoader(ClassLoader classLoader) {\n        synchronized (instLock) {\n            this.classLoaders.add(classLoader);\n            if (parent != null) {\n                parent.addClassLoader(classLoader);\n            }\n            extensionDirector.removeAllCachedLoader();\n            notifyClassLoaderAdd(classLoader);\n        }\n    }\n\n    public void removeClassLoader(ClassLoader classLoader) {\n        synchronized (instLock) {\n            if (checkIfClassLoaderCanRemoved(classLoader)) {\n                this.classLoaders.remove(classLoader);\n                if (parent != null) {\n                    parent.removeClassLoader(classLoader);\n                }\n                extensionDirector.removeAllCachedLoader();\n                notifyClassLoaderDestroy(classLoader);\n            }\n        }\n    }\n\n    protected boolean checkIfClassLoaderCanRemoved(ClassLoader classLoader) {\n        return classLoader != null && !classLoader.equals(ScopeModel.class.getClassLoader());\n    }\n\n    public Set<ClassLoader> getClassLoaders() {\n        return Collections.unmodifiableSet(classLoaders);\n    }\n\n    /**\n     * Get current model's environment.\n     * </br>\n     * Note: This method should not start with `get` or it would be invoked due to Spring boot refresh.\n     * @see <a href=\"https://github.com/apache/dubbo/issues/12542\">Configuration refresh issue</a>\n     */\n    public abstract Environment modelEnvironment();\n\n    /**\n     * Get current model's environment.\n     *\n     * @see <a href=\"https://github.com/apache/dubbo/issues/12542\">Configuration refresh issue</a>\n     * @deprecated use modelEnvironment() instead\n     */\n    @Deprecated\n    @SuppressWarnings(\"DeprecatedIsStillUsed\")\n    public final Environment getModelEnvironment() {\n        try {\n            return modelEnvironment();\n        } catch (Exception ex) {\n            return null;\n        }\n    }\n\n    public String getInternalId() {\n        return this.internalId;\n    }\n\n    void setInternalId(String internalId) {\n        this.internalId = internalId;\n    }\n\n    protected String buildInternalId(String parentInternalId, long childIndex) {\n        // FrameworkModel    1\n        // ApplicationModel  1.1\n        // ModuleModel       1.1.1\n        if (StringUtils.hasText(parentInternalId)) {\n            return parentInternalId + \".\" + childIndex;\n        } else {\n            return \"\" + childIndex;\n        }\n    }\n\n    public String getModelName() {\n        return modelName;\n    }\n\n    public void setModelName(String modelName) {\n        this.modelName = modelName;\n        this.desc = buildDesc();\n    }\n\n    public boolean isInternal() {\n        return internalScope;\n    }\n\n    /**\n     * @return to describe string of this scope model\n     */\n    public String getDesc() {\n        if (this.desc == null) {\n            this.desc = buildDesc();\n        }\n        return this.desc;\n    }\n\n    private String buildDesc() {\n        // Dubbo Framework[1]\n        // Dubbo Application[1.1](appName)\n        // Dubbo Module[1.1.1](appName/moduleName)\n        String type = this.getClass().getSimpleName().replace(\"Model\", \"\");\n        String desc = \"Dubbo \" + type + \"[\" + this.getInternalId() + \"]\";\n\n        // append model name path\n        String modelNamePath = this.getModelNamePath();\n        if (StringUtils.hasText(modelNamePath)) {\n            desc += \"(\" + modelNamePath + \")\";\n        }\n        return desc;\n    }\n\n    private String getModelNamePath() {\n        if (this instanceof ApplicationModel) {\n            return safeGetAppName((ApplicationModel) this);\n        } else if (this instanceof ModuleModel) {\n            String modelName = this.getModelName();\n            if (StringUtils.hasText(modelName)) {\n                // appName/moduleName\n                return safeGetAppName(((ModuleModel) this).getApplicationModel()) + \"/\" + modelName;\n            }\n        }\n        return null;\n    }\n\n    private static String safeGetAppName(ApplicationModel applicationModel) {\n        String modelName = applicationModel.getModelName();\n        if (StringUtils.isBlank(modelName)) {\n            modelName = \"unknown\"; // unknown application\n        }\n        return modelName;\n    }\n\n    @Override\n    public String toString() {\n        return getDesc();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelAccessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\n/**\n * An accessor for scope model, it can be use in interface default methods to get scope model.\n */\npublic interface ScopeModelAccessor {\n\n    ScopeModel getScopeModel();\n\n    default FrameworkModel getFrameworkModel() {\n        return ScopeModelUtil.getFrameworkModel(getScopeModel());\n    }\n\n    default ApplicationModel getApplicationModel() {\n        return ScopeModelUtil.getApplicationModel(getScopeModel());\n    }\n\n    default ModuleModel getModuleModel() {\n        return ScopeModelUtil.getModuleModel(getScopeModel());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelAware.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\n/**\n * An interface to inject FrameworkModel/ApplicationModel/ModuleModel for SPI extensions and internal beans.\n */\npublic interface ScopeModelAware {\n\n    /**\n     * Override this method if you need get the scope model (maybe one of FrameworkModel/ApplicationModel/ModuleModel).\n     * @param scopeModel\n     */\n    default void setScopeModel(ScopeModel scopeModel) {}\n\n    /**\n     * Override this method if you just need framework model\n     * @param frameworkModel\n     */\n    default void setFrameworkModel(FrameworkModel frameworkModel) {}\n\n    /**\n     * Override this method if you just need application model\n     * @param applicationModel\n     */\n    default void setApplicationModel(ApplicationModel applicationModel) {}\n\n    /**\n     * Override this method if you just need module model\n     * @param moduleModel\n     */\n    default void setModuleModel(ModuleModel moduleModel) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelAwareExtensionProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.extension.ExtensionPostProcessor;\n\npublic class ScopeModelAwareExtensionProcessor implements ExtensionPostProcessor, ScopeModelAccessor {\n    private ScopeModel scopeModel;\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n\n    public ScopeModelAwareExtensionProcessor(ScopeModel scopeModel) {\n        this.scopeModel = scopeModel;\n        initialize();\n    }\n\n    private void initialize() {\n\n        // NOTE: Do not create a new model or use the default application/module model here!\n        // Only the visible and only matching scope model can be injected, that is, module -> application -> framework.\n        // The converse is a one-to-many relationship and cannot be injected.\n        // One framework may have multiple applications, and one application may have multiple modules.\n        // So, the spi extension/bean of application scope can be injected its application model and framework model,\n        // but the spi extension/bean of framework scope cannot be injected an application or module model.\n\n        if (scopeModel instanceof FrameworkModel) {\n            frameworkModel = (FrameworkModel) scopeModel;\n        } else if (scopeModel instanceof ApplicationModel) {\n            applicationModel = (ApplicationModel) scopeModel;\n            frameworkModel = applicationModel.getFrameworkModel();\n        } else if (scopeModel instanceof ModuleModel) {\n            moduleModel = (ModuleModel) scopeModel;\n            applicationModel = moduleModel.getApplicationModel();\n            frameworkModel = applicationModel.getFrameworkModel();\n        }\n    }\n\n    @Override\n    public Object postProcessAfterInitialization(Object instance, String name) throws Exception {\n        if (instance instanceof ScopeModelAware) {\n            ScopeModelAware modelAware = (ScopeModelAware) instance;\n            modelAware.setScopeModel(scopeModel);\n            if (this.moduleModel != null) {\n                modelAware.setModuleModel(this.moduleModel);\n            }\n            if (this.applicationModel != null) {\n                modelAware.setApplicationModel(this.applicationModel);\n            }\n            if (this.frameworkModel != null) {\n                modelAware.setFrameworkModel(this.frameworkModel);\n            }\n        }\n        return instance;\n    }\n\n    @Override\n    public ScopeModel getScopeModel() {\n        return scopeModel;\n    }\n\n    @Override\n    public FrameworkModel getFrameworkModel() {\n        return frameworkModel;\n    }\n\n    @Override\n    public ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    @Override\n    public ModuleModel getModuleModel() {\n        return moduleModel;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelDestroyListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\npublic interface ScopeModelDestroyListener<T extends ScopeModel> {\n    void onDestroy(T scopeModel);\n\n    default boolean isProtocol() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.SELF)\npublic interface ScopeModelInitializer {\n\n    default void initializeFrameworkModel(FrameworkModel frameworkModel) {}\n\n    default void initializeApplicationModel(ApplicationModel applicationModel) {}\n\n    default void initializeModuleModel(ModuleModel moduleModel) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.SPI;\n\npublic class ScopeModelUtil {\n\n    public static <T> ScopeModel getOrDefault(ScopeModel scopeModel, Class<T> type) {\n        if (scopeModel != null) {\n            return scopeModel;\n        }\n        return getDefaultScopeModel(type);\n    }\n\n    private static <T> ScopeModel getDefaultScopeModel(Class<T> type) {\n        SPI spi = type.getAnnotation(SPI.class);\n        if (spi == null) {\n            throw new IllegalArgumentException(\"SPI annotation not found for class: \" + type.getName());\n        }\n        switch (spi.scope()) {\n            case FRAMEWORK:\n                return FrameworkModel.defaultModel();\n            case APPLICATION:\n                return ApplicationModel.defaultModel();\n            case MODULE:\n                return ApplicationModel.defaultModel().getDefaultModule();\n            default:\n                throw new IllegalStateException(\"Unable to get default scope model for type: \" + type.getName());\n        }\n    }\n\n    public static ModuleModel getModuleModel(ScopeModel scopeModel) {\n        if (scopeModel == null) {\n            return ApplicationModel.defaultModel().getDefaultModule();\n        }\n        if (scopeModel instanceof ModuleModel) {\n            return (ModuleModel) scopeModel;\n        } else {\n            throw new IllegalArgumentException(\"Unable to get ModuleModel from \" + scopeModel);\n        }\n    }\n\n    public static ApplicationModel getApplicationModel(ScopeModel scopeModel) {\n        return getOrDefaultApplicationModel(scopeModel);\n    }\n\n    public static ApplicationModel getOrDefaultApplicationModel(ScopeModel scopeModel) {\n        if (scopeModel == null) {\n            return ApplicationModel.defaultModel();\n        }\n        return getOrNullApplicationModel(scopeModel);\n    }\n\n    public static ApplicationModel getOrNullApplicationModel(ScopeModel scopeModel) {\n        if (scopeModel == null) {\n            return null;\n        }\n        if (scopeModel instanceof ApplicationModel) {\n            return (ApplicationModel) scopeModel;\n        } else if (scopeModel instanceof ModuleModel) {\n            ModuleModel moduleModel = (ModuleModel) scopeModel;\n            return moduleModel.getApplicationModel();\n        } else {\n            throw new IllegalArgumentException(\"Unable to get ApplicationModel from \" + scopeModel);\n        }\n    }\n\n    public static FrameworkModel getFrameworkModel(ScopeModel scopeModel) {\n        if (scopeModel == null) {\n            return FrameworkModel.defaultModel();\n        }\n        if (scopeModel instanceof ApplicationModel) {\n            return ((ApplicationModel) scopeModel).getFrameworkModel();\n        } else if (scopeModel instanceof ModuleModel) {\n            ModuleModel moduleModel = (ModuleModel) scopeModel;\n            return moduleModel.getApplicationModel().getFrameworkModel();\n        } else if (scopeModel instanceof FrameworkModel) {\n            return (FrameworkModel) scopeModel;\n        } else {\n            throw new IllegalArgumentException(\"Unable to get FrameworkModel from \" + scopeModel);\n        }\n    }\n\n    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type, ScopeModel scopeModel) {\n        if (scopeModel != null) {\n            return scopeModel.getExtensionLoader(type);\n        } else {\n            SPI spi = type.getAnnotation(SPI.class);\n            if (spi == null) {\n                throw new IllegalArgumentException(\"SPI annotation not found for class: \" + type.getName());\n            }\n            switch (spi.scope()) {\n                case FRAMEWORK:\n                    return FrameworkModel.defaultModel().getExtensionLoader(type);\n                case APPLICATION:\n                    return ApplicationModel.defaultModel().getExtensionLoader(type);\n                case MODULE:\n                    return ApplicationModel.defaultModel().getDefaultModule().getExtensionLoader(type);\n                default:\n                    throw new IllegalArgumentException(\"Unable to get ExtensionLoader for type: \" + type.getName());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ServiceDescriptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * ServiceModel and ServiceMetadata are to some extent duplicated with each other. We should merge them in the future.\n */\npublic interface ServiceDescriptor {\n\n    FullServiceDefinition getFullServiceDefinition(String serviceKey);\n\n    String getInterfaceName();\n\n    Class<?> getServiceInterfaceClass();\n\n    Set<MethodDescriptor> getAllMethods();\n\n    /**\n     * Does not use Optional as return type to avoid potential performance decrease.\n     *\n     */\n    MethodDescriptor getMethod(String methodName, String params);\n\n    /**\n     * Does not use Optional as return type to avoid potential performance decrease.\n     *\n     */\n    MethodDescriptor getMethod(String methodName, Class<?>[] paramTypes);\n\n    List<MethodDescriptor> getMethods(String methodName);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ServiceMetadata.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.BaseServiceMetadata;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Notice, this class currently has no usage inside Dubbo.\n *\n * data related to service level such as name, version, classloader of business service,\n * security info, etc. Also, with a AttributeMap for extension.\n */\npublic class ServiceMetadata extends BaseServiceMetadata {\n\n    private String defaultGroup;\n    private Class<?> serviceType;\n\n    private Object target;\n\n    /**\n     * will be transferred to remote side\n     */\n    private final Map<String, Object> attachments = new ConcurrentHashMap<>();\n    /**\n     * used locally\n     */\n    private final ConcurrentHashMap<String, Object> attributeMap = new ConcurrentHashMap<>();\n\n    public ServiceMetadata(String serviceInterfaceName, String group, String version, Class<?> serviceType) {\n        this.serviceInterfaceName = serviceInterfaceName;\n        this.defaultGroup = group;\n        this.group = group;\n        this.version = version;\n        this.serviceKey = buildServiceKey(serviceInterfaceName, group, version);\n        this.serviceType = serviceType;\n    }\n\n    public ServiceMetadata() {}\n\n    @Override\n    public String getServiceKey() {\n        return serviceKey;\n    }\n\n    public Map<String, Object> getAttachments() {\n        return attachments;\n    }\n\n    public ConcurrentHashMap<String, Object> getAttributeMap() {\n        return attributeMap;\n    }\n\n    public Object getAttribute(String key) {\n        return attributeMap.get(key);\n    }\n\n    public void addAttribute(String key, Object value) {\n        this.attributeMap.put(key, value);\n    }\n\n    public void addAttachment(String key, Object value) {\n        this.attachments.put(key, value);\n    }\n\n    public Class<?> getServiceType() {\n        return serviceType;\n    }\n\n    public String getDefaultGroup() {\n        return defaultGroup;\n    }\n\n    public void setDefaultGroup(String defaultGroup) {\n        this.defaultGroup = defaultGroup;\n    }\n\n    public void setServiceType(Class<?> serviceType) {\n        this.serviceType = serviceType;\n    }\n\n    public Object getTarget() {\n        return target;\n    }\n\n    public void setTarget(Object target) {\n        this.target = target;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ServiceModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.BaseServiceMetadata;\nimport org.apache.dubbo.config.AbstractInterfaceConfig;\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.config.ServiceConfigBase;\n\nimport java.util.Objects;\nimport java.util.Set;\n\npublic class ServiceModel {\n    private String serviceKey;\n    private Object proxyObject;\n    private Runnable destroyRunner;\n    private ClassLoader classLoader;\n\n    private final ClassLoader interfaceClassLoader;\n\n    private final ModuleModel moduleModel;\n    private final ServiceDescriptor serviceModel;\n\n    private AbstractInterfaceConfig config;\n\n    private final ServiceMetadata serviceMetadata;\n\n    public ServiceModel(\n            Object proxyObject,\n            String serviceKey,\n            ServiceDescriptor serviceModel,\n            ModuleModel moduleModel,\n            ClassLoader interfaceClassLoader) {\n        this(proxyObject, serviceKey, serviceModel, moduleModel, null, interfaceClassLoader);\n    }\n\n    public ServiceModel(\n            Object proxyObject,\n            String serviceKey,\n            ServiceDescriptor serviceModel,\n            ModuleModel moduleModel,\n            ServiceMetadata serviceMetadata,\n            ClassLoader interfaceClassLoader) {\n        this.proxyObject = proxyObject;\n        this.serviceKey = serviceKey;\n        this.serviceModel = serviceModel;\n        this.moduleModel = ScopeModelUtil.getModuleModel(moduleModel);\n        this.serviceMetadata = serviceMetadata;\n        this.interfaceClassLoader = interfaceClassLoader;\n        if (serviceMetadata != null) {\n            serviceMetadata.setServiceModel(this);\n        }\n        if (interfaceClassLoader != null) {\n            this.classLoader = interfaceClassLoader;\n        }\n        if (this.classLoader == null) {\n            this.classLoader = Thread.currentThread().getContextClassLoader();\n        }\n    }\n\n    @Deprecated\n    public AbstractInterfaceConfig getConfig() {\n        return config;\n    }\n\n    @Deprecated\n    public void setConfig(AbstractInterfaceConfig config) {\n        this.config = config;\n    }\n\n    /**\n     * ServiceModel should be decoupled from AbstractInterfaceConfig and removed in a future version\n     * @return\n     */\n    @Deprecated\n    public ReferenceConfigBase<?> getReferenceConfig() {\n        if (config == null) {\n            return null;\n        }\n        if (config instanceof ReferenceConfigBase) {\n            return (ReferenceConfigBase<?>) config;\n        } else {\n            throw new IllegalArgumentException(\"Current ServiceModel is not a ConsumerModel\");\n        }\n    }\n\n    /**\n     * ServiceModel should be decoupled from AbstractInterfaceConfig and removed in a future version\n     * @return\n     */\n    @Deprecated\n    public ServiceConfigBase<?> getServiceConfig() {\n        if (config == null) {\n            return null;\n        }\n        if (config instanceof ServiceConfigBase) {\n            return (ServiceConfigBase<?>) config;\n        } else {\n            throw new IllegalArgumentException(\"Current ServiceModel is not a ProviderModel\");\n        }\n    }\n\n    public String getServiceKey() {\n        return serviceKey;\n    }\n\n    public void setProxyObject(Object proxyObject) {\n        this.proxyObject = proxyObject;\n    }\n\n    public Object getProxyObject() {\n        return proxyObject;\n    }\n\n    public ServiceDescriptor getServiceModel() {\n        return serviceModel;\n    }\n\n    public void setClassLoader(ClassLoader classLoader) {\n        this.classLoader = classLoader;\n    }\n\n    public ClassLoader getClassLoader() {\n        return classLoader;\n    }\n\n    /**\n     * Return all method models for the current service\n     *\n     * @return method model list\n     */\n    public Set<MethodDescriptor> getAllMethods() {\n        return serviceModel.getAllMethods();\n    }\n\n    public Class<?> getServiceInterfaceClass() {\n        return serviceModel.getServiceInterfaceClass();\n    }\n\n    public void setServiceKey(String serviceKey) {\n        this.serviceKey = serviceKey;\n        if (serviceMetadata != null) {\n            serviceMetadata.setServiceKey(serviceKey);\n            serviceMetadata.setGroup(BaseServiceMetadata.groupFromServiceKey(serviceKey));\n        }\n    }\n\n    public String getServiceName() {\n        return this.serviceMetadata.getServiceKey();\n    }\n\n    /**\n     * @return serviceMetadata\n     */\n    public ServiceMetadata getServiceMetadata() {\n        return serviceMetadata;\n    }\n\n    public ModuleModel getModuleModel() {\n        return moduleModel;\n    }\n\n    public Runnable getDestroyRunner() {\n        return destroyRunner;\n    }\n\n    public void setDestroyRunner(Runnable destroyRunner) {\n        this.destroyRunner = destroyRunner;\n    }\n\n    public ClassLoader getInterfaceClassLoader() {\n        return interfaceClassLoader;\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        ServiceModel that = (ServiceModel) o;\n        return Objects.equals(serviceKey, that.serviceKey)\n                && Objects.equals(proxyObject, that.proxyObject)\n                && Objects.equals(destroyRunner, that.destroyRunner)\n                && Objects.equals(classLoader, that.classLoader)\n                && Objects.equals(interfaceClassLoader, that.interfaceClassLoader)\n                && Objects.equals(moduleModel, that.moduleModel)\n                && Objects.equals(serviceModel, that.serviceModel)\n                && Objects.equals(serviceMetadata, that.serviceMetadata);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(\n                serviceKey,\n                proxyObject,\n                destroyRunner,\n                classLoader,\n                interfaceClassLoader,\n                moduleModel,\n                serviceModel,\n                serviceMetadata);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ServiceRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class ServiceRepository {\n\n    public static final String NAME = \"repository\";\n\n    private final AtomicBoolean initialized = new AtomicBoolean(false);\n    private final ApplicationModel applicationModel;\n\n    public ServiceRepository(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        initialize();\n    }\n\n    private void initialize() {\n        if (initialized.compareAndSet(false, true)) {\n            Set<BuiltinServiceDetector> builtinServices = applicationModel\n                    .getExtensionLoader(BuiltinServiceDetector.class)\n                    .getSupportedExtensionInstances();\n            if (CollectionUtils.isNotEmpty(builtinServices)) {\n                for (BuiltinServiceDetector service : builtinServices) {\n                    Class<?> serviceClass = service.getService();\n                    if (serviceClass == null) {\n                        continue;\n                    }\n                    applicationModel.getInternalModule().getServiceRepository().registerService(serviceClass);\n                }\n            }\n        }\n    }\n\n    public void destroy() {\n        // TODO destroy application service repository\n    }\n\n    public Collection<ConsumerModel> allConsumerModels() {\n        // aggregate from sub modules\n        List<ConsumerModel> allConsumerModels = new ArrayList<>();\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            allConsumerModels.addAll(moduleModel.getServiceRepository().getReferredServices());\n        }\n        return allConsumerModels;\n    }\n\n    public Collection<ProviderModel> allProviderModels() {\n        // aggregate from sub modules\n        List<ProviderModel> allProviderModels = new ArrayList<>();\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            allProviderModels.addAll(moduleModel.getServiceRepository().getExportedServices());\n        }\n        return allProviderModels;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/StubMethodDescriptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.ReflectUtils;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.stream.Stream;\n\npublic class StubMethodDescriptor implements MethodDescriptor, PackableMethod {\n    private final ConcurrentMap<String, Object> attributeMap = new ConcurrentHashMap<>();\n    private final String methodName;\n    private final String javaMethodName;\n    private final String[] compatibleParamSignatures;\n    private final Class<?>[] parameterClasses;\n    private final Class<?> returnClass;\n    private final Type[] returnTypes;\n    private final String paramDesc;\n    private final RpcType rpcType;\n    private final Pack requestPack;\n    private final Pack responsePack;\n    private final UnPack requestUnpack;\n    private final UnPack responseUnpack;\n\n    public StubMethodDescriptor(\n            String methodName,\n            Class<?> requestClass,\n            Class<?> responseClass,\n            RpcType rpcType,\n            Pack requestPack,\n            Pack responsePack,\n            UnPack requestUnpack,\n            UnPack responseUnpack) {\n        this.methodName = methodName;\n        this.javaMethodName = toJavaMethodName(methodName);\n        this.rpcType = rpcType;\n        this.requestPack = requestPack;\n        this.responsePack = responsePack;\n        this.responseUnpack = responseUnpack;\n        this.requestUnpack = requestUnpack;\n        this.parameterClasses = new Class<?>[] {requestClass};\n        this.returnClass = responseClass;\n        this.paramDesc = ReflectUtils.getDesc(parameterClasses);\n        this.compatibleParamSignatures =\n                Stream.of(parameterClasses).map(Class::getName).toArray(String[]::new);\n        this.returnTypes = new Type[] {responseClass, responseClass};\n    }\n\n    @Override\n    public String getMethodName() {\n        return methodName;\n    }\n\n    @Override\n    public String getJavaMethodName() {\n        return javaMethodName;\n    }\n\n    @Override\n    public String getParamDesc() {\n        return paramDesc;\n    }\n\n    @Override\n    public String[] getCompatibleParamSignatures() {\n        return compatibleParamSignatures;\n    }\n\n    @Override\n    public Class<?>[] getParameterClasses() {\n        return parameterClasses;\n    }\n\n    @Override\n    public Class<?> getReturnClass() {\n        return returnClass;\n    }\n\n    @Override\n    public Type[] getReturnTypes() {\n        return returnTypes;\n    }\n\n    @Override\n    public RpcType getRpcType() {\n        return rpcType;\n    }\n\n    @Override\n    public boolean isGeneric() {\n        return false;\n    }\n\n    @Override\n    public Method getMethod() {\n        return null;\n    }\n\n    @Override\n    public void addAttribute(String key, Object value) {\n        this.attributeMap.put(key, value);\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        return this.attributeMap.get(key);\n    }\n\n    @Override\n    public Class<?>[] getActualRequestTypes() {\n        return this.parameterClasses;\n    }\n\n    @Override\n    public Class<?> getActualResponseType() {\n        return this.returnClass;\n    }\n\n    @Override\n    public Pack getRequestPack() {\n        return requestPack;\n    }\n\n    @Override\n    public Pack getResponsePack() {\n        return responsePack;\n    }\n\n    @Override\n    public UnPack getResponseUnpack() {\n        return responseUnpack;\n    }\n\n    @Override\n    public UnPack getRequestUnpack() {\n        return requestUnpack;\n    }\n\n    @Override\n    public String toString() {\n        return \"StubMethodDescriptor{\" + \"method=\" + methodName + '('\n                + (parameterClasses.length > 0 ? parameterClasses[0].getSimpleName() : \"\") + \"), rpcType='\" + rpcType\n                + \"'}\";\n    }\n\n    private static String toJavaMethodName(String methodName) {\n        char ch = methodName.charAt(0);\n        return Character.isUpperCase(ch) ? Character.toLowerCase(ch) + methodName.substring(1) : methodName;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/StubServiceDescriptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentNavigableMap;\nimport java.util.concurrent.ConcurrentSkipListMap;\n\npublic class StubServiceDescriptor implements ServiceDescriptor {\n    private final String interfaceName;\n    private final Class<?> serviceInterfaceClass;\n    // to accelerate search\n    private final Map<String, List<MethodDescriptor>> methods = new HashMap<>();\n    private final Map<String, Map<String, MethodDescriptor>> descToMethods = new HashMap<>();\n    private final ConcurrentNavigableMap<String, FullServiceDefinition> serviceDefinitions =\n            new ConcurrentSkipListMap<>();\n\n    public StubServiceDescriptor(String interfaceName, Class<?> interfaceClass) {\n        this.interfaceName = interfaceName;\n        this.serviceInterfaceClass = interfaceClass;\n    }\n\n    public void addMethod(MethodDescriptor methodDescriptor) {\n        doAddMethod(methodDescriptor.getMethodName(), methodDescriptor);\n        if (methods.containsKey(methodDescriptor.getJavaMethodName())) {\n            return;\n        }\n        doAddMethod(methodDescriptor.getJavaMethodName(), methodDescriptor);\n    }\n\n    private void doAddMethod(String methodName, MethodDescriptor methodDescriptor) {\n        methods.put(methodName, Collections.singletonList(methodDescriptor));\n        descToMethods\n                .computeIfAbsent(methodName, k -> new HashMap<>())\n                .put(methodDescriptor.getParamDesc(), methodDescriptor);\n    }\n\n    public FullServiceDefinition getFullServiceDefinition(String serviceKey) {\n        return serviceDefinitions.computeIfAbsent(\n                serviceKey,\n                (k) -> ServiceDefinitionBuilder.buildFullDefinition(serviceInterfaceClass, Collections.emptyMap()));\n    }\n\n    public String getInterfaceName() {\n        return interfaceName;\n    }\n\n    public Class<?> getServiceInterfaceClass() {\n        return serviceInterfaceClass;\n    }\n\n    public Set<MethodDescriptor> getAllMethods() {\n        Set<MethodDescriptor> methodModels = new HashSet<>();\n        methods.forEach((k, v) -> methodModels.addAll(v));\n        return methodModels;\n    }\n\n    /**\n     * Does not use Optional as return type to avoid potential performance decrease.\n     *\n     */\n    public MethodDescriptor getMethod(String methodName, String params) {\n        Map<String, MethodDescriptor> methods = descToMethods.get(methodName);\n        if (CollectionUtils.isNotEmptyMap(methods)) {\n            return methods.get(params);\n        }\n        return null;\n    }\n\n    /**\n     * Does not use Optional as return type to avoid potential performance decrease.\n     *\n     */\n    public MethodDescriptor getMethod(String methodName, Class<?>[] paramTypes) {\n        List<MethodDescriptor> methodModels = methods.get(methodName);\n        if (CollectionUtils.isNotEmpty(methodModels)) {\n            for (MethodDescriptor descriptor : methodModels) {\n                if (Arrays.equals(paramTypes, descriptor.getParameterClasses())) {\n                    return descriptor;\n                }\n            }\n        }\n        return null;\n    }\n\n    public List<MethodDescriptor> getMethods(String methodName) {\n        return methods.get(methodName);\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        StubServiceDescriptor that = (StubServiceDescriptor) o;\n        return Objects.equals(interfaceName, that.interfaceName)\n                && Objects.equals(serviceInterfaceClass, that.serviceInterfaceClass)\n                && Objects.equals(methods, that.methods)\n                && Objects.equals(descToMethods, that.descToMethods);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(interfaceName, serviceInterfaceClass, methods, descToMethods);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/UnPack.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.InputStream;\n\npublic interface UnPack {\n\n    /**\n     * @deprecated use {@link #unpack(InputStream)} instead\n     */\n    @Deprecated\n    Object unpack(byte[] data) throws Exception;\n\n    default Object unpack(InputStream inputStream) throws Exception {\n        ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n        byte[] tmp = new byte[4096];\n        int len;\n        while ((len = inputStream.read(tmp)) != -1) {\n            buffer.write(tmp, 0, len);\n        }\n        return unpack(buffer.toByteArray());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/model/WrapperUnPack.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.InputStream;\n\npublic interface WrapperUnPack extends UnPack {\n\n    @Override\n    default Object unpack(byte[] data) throws Exception {\n        return unpack(data, false);\n    }\n\n    /**\n     * @deprecated use {@link #unpack(InputStream, boolean)} instead\n     */\n    @Deprecated\n    Object unpack(byte[] data, boolean isReturnTriException) throws Exception;\n\n    @Override\n    default Object unpack(InputStream inputStream) throws Exception {\n        return unpack(inputStream, false);\n    }\n\n    default Object unpack(InputStream inputStream, boolean isReturnTriException) throws Exception {\n        ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n        byte[] tmp = new byte[4096];\n        int len;\n        while ((len = inputStream.read(tmp)) != -1) {\n            buffer.write(tmp, 0, len);\n        }\n        return unpack(buffer.toByteArray(), isReturnTriException);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/service/Destroyable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.service;\n\npublic interface Destroyable {\n\n    void $destroy();\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/service/EchoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.service;\n\n/**\n * Echo service.\n * @export\n */\npublic interface EchoService {\n\n    /**\n     * echo test.\n     *\n     * @param message message.\n     * @return message.\n     */\n    Object $echo(Object message);\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/service/EchoServiceDetector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.service;\n\nimport org.apache.dubbo.rpc.model.BuiltinServiceDetector;\n\npublic class EchoServiceDetector implements BuiltinServiceDetector {\n\n    @Override\n    public Class<?> getService() {\n        return EchoService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/service/GenericException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.service;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\n/**\n * GenericException\n *\n * @export\n */\npublic class GenericException extends RuntimeException {\n\n    private static final long serialVersionUID = -1182299763306599962L;\n\n    private String exceptionClass;\n\n    private String exceptionMessage;\n\n    public GenericException() {}\n\n    public GenericException(String exceptionMessage) {\n        super(exceptionMessage);\n        this.exceptionMessage = exceptionMessage;\n    }\n\n    public GenericException(String exceptionClass, String exceptionMessage) {\n        super(exceptionMessage);\n        this.exceptionClass = exceptionClass;\n        this.exceptionMessage = exceptionMessage;\n    }\n\n    public GenericException(Throwable cause) {\n        super(StringUtils.toString(cause));\n        this.exceptionClass = cause.getClass().getName();\n        this.exceptionMessage = cause.getMessage();\n    }\n\n    public GenericException(String message, Throwable cause, String exceptionClass, String exceptionMessage) {\n        super(message, cause);\n        this.exceptionClass = exceptionClass;\n        this.exceptionMessage = exceptionMessage;\n    }\n\n    public String getExceptionClass() {\n        return exceptionClass;\n    }\n\n    public void setExceptionClass(String exceptionClass) {\n        this.exceptionClass = exceptionClass;\n    }\n\n    public String getExceptionMessage() {\n        return exceptionMessage;\n    }\n\n    public void setExceptionMessage(String exceptionMessage) {\n        this.exceptionMessage = exceptionMessage;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/service/GenericService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.service;\n\nimport java.util.concurrent.CompletableFuture;\n\n/**\n * Generic service interface\n *\n * @export\n */\npublic interface GenericService {\n\n    /**\n     * Generic invocation\n     *\n     * @param method         Method name, e.g. findPerson. If there are overridden methods, parameter info is\n     *                       required, e.g. findPerson(java.lang.String)\n     * @param parameterTypes Parameter types\n     * @param args           Arguments\n     * @return invocation return value\n     * @throws GenericException potential exception thrown from the invocation\n     */\n    Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException;\n\n    default CompletableFuture<Object> $invokeAsync(String method, String[] parameterTypes, Object[] args)\n            throws GenericException {\n        Object object = $invoke(method, parameterTypes, args);\n        if (object instanceof CompletableFuture) {\n            return (CompletableFuture<Object>) object;\n        }\n        return CompletableFuture.completedFuture(object);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/service/GenericServiceDetector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.service;\n\nimport org.apache.dubbo.rpc.model.BuiltinServiceDetector;\n\npublic class GenericServiceDetector implements BuiltinServiceDetector {\n\n    @Override\n    public Class<?> getService() {\n        return GenericService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/service/ServiceDescriptorInternalCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.service;\n\nimport org.apache.dubbo.rpc.model.ReflectionServiceDescriptor;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\n\npublic class ServiceDescriptorInternalCache {\n    private static final ServiceDescriptor genericServiceDescriptor =\n            new ReflectionServiceDescriptor(GenericService.class);\n    private static final ServiceDescriptor echoServiceDescriptor = new ReflectionServiceDescriptor(EchoService.class);\n\n    public static ServiceDescriptor genericService() {\n        return genericServiceDescriptor;\n    }\n\n    public static ServiceDescriptor echoService() {\n        return echoServiceDescriptor;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/support/GroupServiceKeyCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\npublic class GroupServiceKeyCache {\n\n    private final String serviceGroup;\n\n    // ConcurrentMap<serviceName, ConcurrentMap<serviceVersion, ConcurrentMap<port, String>>>\n    private final ConcurrentMap<String, ConcurrentMap<String, ConcurrentMap<Integer, String>>> serviceKeyMap;\n\n    public GroupServiceKeyCache(String serviceGroup) {\n        this.serviceGroup = serviceGroup;\n        this.serviceKeyMap = new ConcurrentHashMap<>(512);\n    }\n\n    public String getServiceKey(String serviceName, String serviceVersion, int port) {\n        ConcurrentMap<String, ConcurrentMap<Integer, String>> versionMap = serviceKeyMap.get(serviceName);\n        if (versionMap == null) {\n            serviceKeyMap.putIfAbsent(serviceName, new ConcurrentHashMap<>());\n            versionMap = serviceKeyMap.get(serviceName);\n        }\n\n        serviceVersion = serviceVersion == null ? \"\" : serviceVersion;\n        ConcurrentMap<Integer, String> portMap = versionMap.get(serviceVersion);\n        if (portMap == null) {\n            versionMap.putIfAbsent(serviceVersion, new ConcurrentHashMap<>());\n            portMap = versionMap.get(serviceVersion);\n        }\n\n        String serviceKey = portMap.get(port);\n        if (serviceKey == null) {\n            serviceKey = createServiceKey(serviceName, serviceVersion, port);\n            portMap.put(port, serviceKey);\n        }\n        return serviceKey;\n    }\n\n    private String createServiceKey(String serviceName, String serviceVersion, int port) {\n        StringBuilder buf = new StringBuilder();\n        if (StringUtils.isNotEmpty(serviceGroup)) {\n            buf.append(serviceGroup).append('/');\n        }\n\n        buf.append(serviceName);\n        if (StringUtils.isNotEmpty(serviceVersion) && !\"0.0.0\".equals(serviceVersion) && !\"*\".equals(serviceVersion)) {\n            buf.append(':').append(serviceVersion);\n        }\n        buf.append(':').append(port);\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/java/org/apache/dubbo/rpc/support/ProtocolUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_RAW_RETURN;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_BEAN;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_DEFAULT;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_GSON;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_PROTOBUF;\n\npublic class ProtocolUtils {\n\n    private static final ConcurrentMap<String, GroupServiceKeyCache> groupServiceKeyCacheMap =\n            new ConcurrentHashMap<>();\n\n    private ProtocolUtils() {}\n\n    public static String serviceKey(URL url) {\n        return serviceKey(url.getPort(), url.getPath(), url.getVersion(), url.getGroup());\n    }\n\n    public static String serviceKey(int port, String serviceName, String serviceVersion, String serviceGroup) {\n        serviceGroup = serviceGroup == null ? \"\" : serviceGroup;\n        GroupServiceKeyCache groupServiceKeyCache = groupServiceKeyCacheMap.get(serviceGroup);\n        if (groupServiceKeyCache == null) {\n            groupServiceKeyCacheMap.putIfAbsent(serviceGroup, new GroupServiceKeyCache(serviceGroup));\n            groupServiceKeyCache = groupServiceKeyCacheMap.get(serviceGroup);\n        }\n        return groupServiceKeyCache.getServiceKey(serviceName, serviceVersion, port);\n    }\n\n    public static boolean isGeneric(String generic) {\n        return StringUtils.isNotEmpty(generic)\n                && (GENERIC_SERIALIZATION_DEFAULT.equalsIgnoreCase(generic) /* Normal generalization cal */\n                        || GENERIC_SERIALIZATION_NATIVE_JAVA.equalsIgnoreCase(\n                                generic) /* Streaming generalization call supporting jdk serialization */\n                        || GENERIC_SERIALIZATION_BEAN.equalsIgnoreCase(generic)\n                        || GENERIC_SERIALIZATION_PROTOBUF.equalsIgnoreCase(generic)\n                        || GENERIC_SERIALIZATION_GSON.equalsIgnoreCase(generic)\n                        || GENERIC_RAW_RETURN.equalsIgnoreCase(generic));\n    }\n\n    public static boolean isValidGenericValue(String generic) {\n        return isGeneric(generic) || Boolean.FALSE.toString().equalsIgnoreCase(generic);\n    }\n\n    public static boolean isDefaultGenericSerialization(String generic) {\n        return isGeneric(generic) && GENERIC_SERIALIZATION_DEFAULT.equalsIgnoreCase(generic);\n    }\n\n    public static boolean isJavaGenericSerialization(String generic) {\n        return isGeneric(generic) && GENERIC_SERIALIZATION_NATIVE_JAVA.equalsIgnoreCase(generic);\n    }\n\n    public static boolean isGsonGenericSerialization(String generic) {\n        return isGeneric(generic) && GENERIC_SERIALIZATION_GSON.equalsIgnoreCase(generic);\n    }\n\n    public static boolean isBeanGenericSerialization(String generic) {\n        return isGeneric(generic) && GENERIC_SERIALIZATION_BEAN.equals(generic);\n    }\n\n    public static boolean isProtobufGenericSerialization(String generic) {\n        return isGeneric(generic) && GENERIC_SERIALIZATION_PROTOBUF.equals(generic);\n    }\n\n    public static boolean isGenericReturnRawResult(String generic) {\n        return GENERIC_RAW_RETURN.equals(generic);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.compiler.Compiler",
    "content": "adaptive=org.apache.dubbo.common.compiler.support.AdaptiveCompiler\njdk=org.apache.dubbo.common.compiler.support.JdkCompiler\njavassist=org.apache.dubbo.common.compiler.support.JavassistCompiler"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory",
    "content": "nop=org.apache.dubbo.common.config.configcenter.nop.NopDynamicConfigurationFactory\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.context.ApplicationExt",
    "content": "config=org.apache.dubbo.config.context.ConfigManager\nenvironment=org.apache.dubbo.common.config.Environment\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.context.ModuleExt",
    "content": "moduleEnvironment=org.apache.dubbo.common.config.ModuleEnvironment\nmoduleConfig=org.apache.dubbo.config.context.ModuleConfigManager\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.convert.Converter",
    "content": "# org.apache.dubbo.common.convert.Converter\nstring-to-boolean=org.apache.dubbo.common.convert.StringToBooleanConverter\nstring-to-character=org.apache.dubbo.common.convert.StringToCharacterConverter\nstring-to-char-array=org.apache.dubbo.common.convert.StringToCharArrayConverter\nstring-to-double=org.apache.dubbo.common.convert.StringToDoubleConverter\nstring-to-float=org.apache.dubbo.common.convert.StringToFloatConverter\nstring-to-integer=org.apache.dubbo.common.convert.StringToIntegerConverter\nstring-to-long=org.apache.dubbo.common.convert.StringToLongConverter\nstring-to-optional=org.apache.dubbo.common.convert.StringToOptionalConverter\nstring-to-short=org.apache.dubbo.common.convert.StringToShortConverter\nstring-to-string=org.apache.dubbo.common.convert.StringToStringConverter\nstring-to-byte=org.apache.dubbo.common.convert.StringToByteConverter\nstring-to-duration=org.apache.dubbo.common.convert.StringToDurationConverter"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.convert.multiple.MultiValueConverter",
    "content": "# org.apache.dubbo.common.convert.multiple.MultiValueConverter\nstring-to-array=org.apache.dubbo.common.convert.multiple.StringToArrayConverter\nstring-to-blocking-deque=org.apache.dubbo.common.convert.multiple.StringToBlockingDequeConverter\nstring-to-blocking-queue=org.apache.dubbo.common.convert.multiple.StringToBlockingQueueConverter\nstring-to-collection=org.apache.dubbo.common.convert.multiple.StringToCollectionConverter\nstring-to-deque=org.apache.dubbo.common.convert.multiple.StringToDequeConverter\nstring-to-list=org.apache.dubbo.common.convert.multiple.StringToListConverter\nstring-to-navigable-set=org.apache.dubbo.common.convert.multiple.StringToNavigableSetConverter\nstring-to-queue=org.apache.dubbo.common.convert.multiple.StringToQueueConverter\nstring-to-set=org.apache.dubbo.common.convert.multiple.StringToSetConverter\nstring-to-sorted-set=org.apache.dubbo.common.convert.multiple.StringToSortedSetConverter\nstring-to-transfer-queue=org.apache.dubbo.common.convert.multiple.StringToTransferQueueConverter\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector",
    "content": "adaptive=org.apache.dubbo.common.extension.inject.AdaptiveExtensionInjector\nspi=org.apache.dubbo.common.extension.inject.SpiExtensionInjector\nscopeBean=org.apache.dubbo.common.beans.ScopeBeanExtensionInjector\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.infra.InfraAdapter",
    "content": "environment=org.apache.dubbo.common.infra.support.EnvironmentAdapter"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.json.JsonUtil",
    "content": "fastjson2=org.apache.dubbo.common.json.impl.FastJson2Impl\nfastjson=org.apache.dubbo.common.json.impl.FastJsonImpl\ngson=org.apache.dubbo.common.json.impl.GsonImpl\njackson=org.apache.dubbo.common.json.impl.JacksonImpl\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.logger.LoggerAdapter",
    "content": "slf4j=org.apache.dubbo.common.logger.slf4j.Slf4jLoggerAdapter\njcl=org.apache.dubbo.common.logger.jcl.JclLoggerAdapter\nlog4j=org.apache.dubbo.common.logger.log4j.Log4jLoggerAdapter\njdk=org.apache.dubbo.common.logger.jdk.JdkLoggerAdapter\nlog4j2=org.apache.dubbo.common.logger.log4j2.Log4j2LoggerAdapter\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.ssl.CertProvider",
    "content": "ssl-config=org.apache.dubbo.common.ssl.impl.SSLConfigCertProvider\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.status.StatusChecker",
    "content": "memory=org.apache.dubbo.common.status.support.MemoryStatusChecker\nload=org.apache.dubbo.common.status.support.LoadStatusChecker"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.store.DataStore",
    "content": "simple=org.apache.dubbo.common.store.support.SimpleDataStore"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.ThreadPool",
    "content": "fixed=org.apache.dubbo.common.threadpool.support.fixed.FixedThreadPool\ncached=org.apache.dubbo.common.threadpool.support.cached.CachedThreadPool\nlimited=org.apache.dubbo.common.threadpool.support.limited.LimitedThreadPool\neager=org.apache.dubbo.common.threadpool.support.eager.EagerThreadPool\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.manager.ExecutorRepository",
    "content": "default=org.apache.dubbo.common.threadpool.manager.DefaultExecutorRepository\nisolation=org.apache.dubbo.common.threadpool.manager.IsolationExecutorRepository\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.url.component.param.DynamicParamSource",
    "content": "default=org.apache.dubbo.common.url.component.param.DefaultDynamicParamSource"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader",
    "content": "javassist=org.apache.dubbo.common.utils.JavassistParameterNameReader\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder",
    "content": "array=org.apache.dubbo.metadata.definition.builder.ArrayTypeBuilder\ncollection=org.apache.dubbo.metadata.definition.builder.CollectionTypeBuilder\nmap=org.apache.dubbo.metadata.definition.builder.MapTypeBuilder\nenum=org.apache.dubbo.metadata.definition.builder.EnumTypeBuilder"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.executor.IsolationExecutorSupportFactory",
    "content": "default=org.apache.dubbo.rpc.executor.DefaultIsolationExecutorSupportFactory\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.BuiltinServiceDetector",
    "content": "echo=org.apache.dubbo.rpc.service.EchoServiceDetector\ngeneric=org.apache.dubbo.rpc.service.GenericServiceDetector"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "dubbo-common=org.apache.dubbo.common.CommonScopeModelInitializer\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/services/org.apache.dubbo.common.extension.LoadingStrategy",
    "content": "org.apache.dubbo.common.extension.DubboInternalLoadingStrategy\norg.apache.dubbo.common.extension.DubboLoadingStrategy\norg.apache.dubbo.common.extension.ServicesLoadingStrategy"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/services/org.apache.dubbo.common.json.JsonUtil",
    "content": "org.apache.dubbo.common.json.impl.FastJson2Impl\norg.apache.dubbo.common.json.impl.FastJsonImpl\norg.apache.dubbo.common.json.impl.GsonImpl\norg.apache.dubbo.common.json.impl.JacksonImpl\n"
  },
  {
    "path": "dubbo-common/src/main/resources/META-INF/version",
    "content": "# This is a placeholder file, the real file will be output when the project compiles\n"
  },
  {
    "path": "dubbo-common/src/main/resources/security/serialize.allowlist",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\nboolean\nbyte\nchar\ndouble\nfloat\nint\nlong\nshort\njava.lang.AutoCloseable\njava.lang.Boolean\njava.lang.Byte\njava.lang.Character\njava.lang.Class\njava.lang.Cloneable\njava.lang.Double\njava.lang.Exception\njava.lang.Float\njava.lang.IllegalAccessError\njava.lang.IllegalAccessException\njava.lang.IllegalArgumentException\njava.lang.IllegalMonitorStateException\njava.lang.IllegalStateException\njava.lang.IllegalThreadStateException\njava.lang.IndexOutOfBoundsException\njava.lang.InstantiationError\njava.lang.InstantiationException\njava.lang.Integer\njava.lang.InternalError\njava.lang.InterruptedException\njava.lang.LinkageError\njava.lang.Long\njava.lang.NegativeArraySizeException\njava.lang.NoClassDefFoundError\njava.lang.NoSuchFieldError\njava.lang.NoSuchFieldException\njava.lang.NoSuchMethodError\njava.lang.NoSuchMethodException\njava.lang.NullPointerException\njava.lang.Number\njava.lang.NumberFormatException\njava.lang.Object\njava.lang.OutOfMemoryError\njava.lang.RuntimeException\njava.lang.SecurityException\njava.lang.Short\njava.lang.StackOverflowError\njava.lang.StackTraceElement\njava.lang.String\njava.lang.StringIndexOutOfBoundsException\njava.lang.TypeNotPresentException\njava.lang.VerifyError\njava.math.BigDecimal\njava.math.BigInteger\njava.text.SimpleDateFormat\njava.time.format.DateTimeFormatter\njava.time.Instant\njava.time.LocalDate\njava.time.LocalDateTime\njava.time.LocalTime\njava.util.ArrayList\njava.util.Arrays$ArrayList\njava.util.BitSet\njava.util.Calendar\njava.util.Collections$EmptyList\njava.util.Collections$EmptyMap\njava.util.Collections$SingletonSet\njava.util.Collections$SingletonList\njava.util.Collections$SingletonMap\njava.util.Collections$UnmodifiableCollection\njava.util.Collections$UnmodifiableList\njava.util.Collections$UnmodifiableMap\njava.util.Collections$UnmodifiableNavigableMap\njava.util.Collections$UnmodifiableNavigableSet\njava.util.Collections$UnmodifiableRandomAccessList\njava.util.Collections$UnmodifiableSet\njava.util.Collections$UnmodifiableSortedMap\njava.util.Collections$UnmodifiableSortedSet\njava.util.concurrent.atomic.AtomicBoolean\njava.util.concurrent.atomic.AtomicInteger\njava.util.concurrent.atomic.AtomicIntegerArray\njava.util.concurrent.atomic.AtomicLong\njava.util.concurrent.atomic.AtomicLongArray\njava.util.concurrent.atomic.AtomicReference\njava.util.concurrent.ConcurrentHashMap\njava.util.concurrent.ConcurrentLinkedQueue\njava.util.concurrent.ConcurrentMap\njava.util.concurrent.ConcurrentSkipListMap\njava.util.concurrent.ConcurrentSkipListSet\njava.util.concurrent.CopyOnWriteArrayList\njava.util.concurrent.TimeUnit\njava.util.Currency\njava.util.Date\njava.util.EnumSet\njava.util.RegularEnumSet\njava.util.JumboEnumSet\njava.util.HashMap\njava.util.HashSet\njava.util.Hashtable\njava.util.IdentityHashMap\njava.util.LinkedHashMap\njava.util.LinkedHashSet\njava.util.LinkedList\njava.util.List\njava.util.Locale\njava.util.Map\njava.util.Set\njava.util.TreeMap\njava.util.TreeSet\njava.util.UUID\njava.util.WeakHashMap\norg.apache.dubbo.metadata.MetadataInfo\ncom.alibaba.com.caucho.hessian.io\ncom.alibaba.dubbo.rpc.service.GenericException\norg.apache.dubbo.rpc.service.GenericException\norg.apache.dubbo.rpc.RpcException\norg.apache.dubbo.remoting.http12.ErrorResponse\norg.apache.dubbo.remoting.http12.message.DefaultHttpResult\norg.apache.dubbo.remoting.http12.exception.HttpResultPayloadException\norg.apache.dubbo.common.url.component.ServiceConfigURL\norg.apache.dubbo.common.URL\norg.apache.dubbo.common.url.component.URLAddress\norg.apache.dubbo.common.url.component.URLPlainParam\norg.apache.dubbo.common.url.component.PathURLAddress\norg.apache.dubbo.remoting.http12.exception.DecodeException\norg.apache.dubbo.remoting.http12.exception.EncodeException\norg.apache.dubbo.remoting.http12.exception.HttpOverPayloadException\norg.apache.dubbo.remoting.http12.exception.HttpRequestTimeout\norg.apache.dubbo.remoting.http12.exception.HttpResultPayloadException\norg.apache.dubbo.remoting.http12.exception.HttpStatusException\norg.apache.dubbo.remoting.http12.exception.UnimplementedException\norg.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException\norg.apache.dubbo.rpc.protocol.tri.rest.PathParserException\norg.apache.dubbo.rpc.protocol.tri.rest.RestBadRequestException\norg.apache.dubbo.rpc.protocol.tri.rest.RestException\norg.apache.dubbo.rpc.protocol.tri.rest.RestInitializeException\norg.apache.dubbo.rpc.protocol.tri.rest.RestMappingException\norg.apache.dubbo.rpc.protocol.tri.rest.RestParameterException\norg.apache.dubbo.remoting.http12.h2.CancelStreamException\norg.apache.dubbo.rpc.protocol.tri.ThrowableWrapper\norg.apache.dubbo.rpc.StatusRpcException\n"
  },
  {
    "path": "dubbo-common/src/main/resources/security/serialize.blockedlist",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\naj.org.objectweb.asm.\nbr.com.anteros.\nbsh.\nch.qos.logback.\nclojure.\ncom.alibaba.citrus.springext.support.parser.\ncom.alibaba.citrus.springext.util.SpringExtUtil.\ncom.alibaba.druid.pool.\ncom.alibaba.druid.stat.jdbcdatasourcestat\ncom.alibaba.fastjson.annotation\ncom.alibaba.hotcode.internal.org.apache.commons.collections.functors.\ncom.alipay.custrelation.service.model.redress.\ncom.alipay.oceanbase.obproxy.druid.pool.\ncom.caucho.\ncom.ibatis.\ncom.ibm.jtc.jax.xml.bind.v2.runtime.unmarshaller.\ncom.ibm.xltxe.rnm1.xtq.bcel.util.\ncom.mchange\ncom.mysql.cj.jdbc.admin.\ncom.mysql.cj.jdbc.mysqlconnectionpooldatasource\ncom.mysql.cj.jdbc.mysqldatasource\ncom.mysql.cj.jdbc.mysqlxadatasource\ncom.mysql.cj.log.\ncom.mysql.jdbc.util.\ncom.p6spy.engine.\ncom.rometools.rome.feed.\ncom.sun.\ncom.taobao.eagleeye.wrapper\ncom.taobao.vipserver.commons.collections.functors.\ncom.zaxxer.hikari.\nflex.messaging.util.concurrent.\ngroovy.lang.\njava.awt.\njava.beans.\njava.io.closeable\njava.io.serializable\njava.lang.autocloseable\njava.lang.class\njava.lang.cloneable\njava.lang.iterable\njava.lang.object\njava.lang.ProcessBuilder\njava.lang.readable\njava.lang.runnable\njava.lang.Runtime\njava.lang.thread\njava.lang.unixprocess\njava.net.inetaddress\njava.net.socket\njava.net.url\njava.rmi\njava.security.\njava.util.collection\njava.util.eventlistener\njava.util.jar.\njava.util.logging.\njava.util.prefs.\njava.util.ServiceLoader\njava.util.serviceloader$lazyiterator\njava.util.StringTokenizer\njavassist.\njavax.activation.\njavax.imageio.\njavax.management.\njavax.media.jai.remote.\njavax.naming.\njavax.net.\njavax.print.\njavax.script.\njavax.sound.\njavax.swing.\njavax.tools.\njavax.xml\njdk.internal.\njodd.db.connection.\njunit.\nnet.bytebuddy.dynamic.loading.\nnet.sf.cglib.\nnet.sf.ehcache.hibernate.\nnet.sf.ehcache.transaction.manager.\nognl.\noracle.jdbc.\noracle.jms.aq\noracle.net\norg.aoju.bus.proxy.provider.\norg.apache.activemq.activemqconnectionfactory\norg.apache.activemq.activemqxaconnectionfactory\norg.apache.activemq.jms.pool.\norg.apache.activemq.pool.\norg.apache.activemq.spring.\norg.apache.aries.transaction.\norg.apache.axis2.jaxws.spi.handler.\norg.apache.axis2.transport.jms.\norg.apache.bcel\norg.apache.carbondata.core.scan.expression.\norg.apache.carbondata.core.scan.expression.expressionresult\norg.apache.catalina.\norg.apache.cocoon.\norg.apache.commons.beanutils\norg.apache.commons.codec.\norg.apache.commons.collections.comparators.\norg.apache.commons.collections.functors\norg.apache.commons.collections.functors.\norg.apache.commons.collections.transformer\norg.apache.commons.collections4.comparators\norg.apache.commons.collections4.functors\norg.apache.commons.collections4.transformer\norg.apache.commons.configuration\norg.apache.commons.configuration2.\norg.apache.commons.dbcp\norg.apache.commons.fileupload\norg.apache.commons.jelly.\norg.apache.commons.logging.\norg.apache.commons.proxy.\norg.apache.hadoop.shaded.com.zaxxer.hikari.\norg.apache.http.auth.\norg.apache.http.conn.\norg.apache.http.cookie.\norg.apache.http.impl.\norg.apache.ibatis.datasource\norg.apache.ibatis.executor.\norg.apache.ibatis.javassist.\norg.apache.ibatis.ognl.\norg.apache.ibatis.parsing.\norg.apache.ibatis.reflection.\norg.apache.ibatis.scripting.\norg.apache.ignite.cache.\norg.apache.ignite.cache.jta.\norg.apache.log.output.db.\norg.apache.log4j.\norg.apache.logging.\norg.apache.myfaces.context.servlet\norg.apache.myfaces.view.facelets.el.\norg.apache.openjpa.ee.\norg.apache.shiro.\norg.apache.tomcat\norg.apache.velocity.\norg.apache.wicket.util\norg.apache.xalan\norg.apache.xbean.\norg.apache.xpath.\norg.apache.zookeeper.\norg.aspectj.\norg.codehaus.groovy.runtime\norg.codehaus.jackson.\norg.datanucleus.store.rdbms.datasource.dbcp.datasources.\norg.dom4j.\norg.eclipse.jetty.\norg.geotools.filter.\norg.h2.jdbcx.\norg.h2.server.\norg.h2.value.\norg.hibernate\norg.javasimon.\norg.jaxen.\norg.jboss\norg.jdom.\norg.jdom2.transform.\norg.junit.\norg.logicalcobwebs.\norg.mockito.\norg.mortbay.jetty.\norg.mortbay.log.\norg.mozilla.javascript\norg.objectweb.asm.\norg.osjava.sj.\norg.python.core\norg.quartz.\norg.slf4j.\norg.springframework.\norg.thymeleaf.\norg.yaml.snakeyaml.tokens.\npstore.shaded.org.apache.commons.collections.\nsun.print.\nsun.rmi.\nweblogic.ejb20.internal.\nweblogic.jms.common.\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/Demo1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class Demo1 {\n    private Simple simple;\n\n    public Simple getSimple() {\n        return simple;\n    }\n\n    public void setSimple(Simple simple) {\n        this.simple = simple;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/Demo2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class Demo2 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/Demo3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class Demo3 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/Demo4.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class Demo4 extends Demo3 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/Demo5.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class Demo5 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/Demo6.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class Demo6 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/Demo7.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class Demo7 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/Demo8.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class Demo8 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/DemoException1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class DemoException1 extends Exception {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/DemoException2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class DemoException2 extends Exception {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/DemoException3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class DemoException3 extends DemoException2 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/pojo/Simple.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.pojo;\n\npublic class Simple {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/service/DemoService1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.service;\n\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.Vector;\n\nimport com.pojo.Demo1;\nimport com.pojo.Demo2;\nimport com.pojo.Demo4;\nimport com.pojo.Demo5;\nimport com.pojo.Demo6;\nimport com.pojo.Demo7;\nimport com.pojo.Demo8;\nimport com.pojo.DemoException1;\nimport com.pojo.DemoException3;\n\npublic interface DemoService1<T extends Demo8> {\n    Demo1 getDemo1();\n\n    void setDemo2(Demo2 demo2);\n\n    List<Demo4> getDemo4s();\n\n    List<HashSet<LinkedList<Set<Vector<Map<? extends Demo5, ? super Demo6>>>>>> getDemo5s();\n\n    List<Demo7>[] getDemo7s();\n\n    List<T> getTs();\n\n    void echo1() throws DemoException1;\n\n    void echo2() throws DemoException3;\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/service/DemoService2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.service;\n\npublic interface DemoService2 extends DemoService1 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/service/DemoService4.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.service;\n\npublic abstract class DemoService4<T, R, Param extends DemoService5<T, R, Param>> {\n    public DemoService4() {}\n\n    public DemoService5<T, R, Param> getWrapper() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/service/DemoService5.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.service;\n\npublic abstract class DemoService5<T, R, Children extends DemoService5<T, R, Children>> {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/service/Params.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.service;\n\nimport java.io.Serializable;\nimport java.util.Map;\n\npublic class Params implements Serializable {\n    private static final long serialVersionUID = 1L;\n    private Map<String, String> params;\n\n    public Params(Map<String, String> params) {\n        this.params = params;\n    }\n\n    public String get(String key) {\n        return params.get(key);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/service/Service.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.service;\n\npublic interface Service<P, V> {\n    V get(P params);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/service/User.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.service;\n\nimport java.io.Serializable;\n\npublic class User implements Serializable {\n    private static final long serialVersionUID = 1L;\n    private int id;\n    private String name;\n\n    public User(int id, String name) {\n        super();\n        this.id = id;\n        this.name = name;\n    }\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public String toString() {\n        return \"User [id=\" + id + \", name=\" + name + \"]\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/service/UserService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.service;\n\npublic interface UserService extends Service<Params, User> {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/com/service/deep1/deep2/deep3/DemoService3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.service.deep1.deep2.deep3;\n\npublic interface DemoService3 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/BaseServiceMetadataTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_VERSION;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass BaseServiceMetadataTest {\n\n    @Test\n    void test() {\n        BaseServiceMetadata baseServiceMetadata = new BaseServiceMetadata();\n        baseServiceMetadata.setGroup(\"group1\");\n        baseServiceMetadata.setServiceInterfaceName(\"org.apache.dubbo.common.TestInterface\");\n        baseServiceMetadata.setVersion(\"1.0.0\");\n        baseServiceMetadata.setServiceKey(\n                BaseServiceMetadata.buildServiceKey(\"org.apache.dubbo.common.TestInterface\", \"group1\", \"1.0.0\"));\n\n        assertEquals(baseServiceMetadata.getGroup(), \"group1\");\n        assertEquals(baseServiceMetadata.getServiceInterfaceName(), \"org.apache.dubbo.common.TestInterface\");\n        assertEquals(baseServiceMetadata.getVersion(), \"1.0.0\");\n        assertEquals(baseServiceMetadata.getServiceKey(), \"group1/org.apache.dubbo.common.TestInterface:1.0.0\");\n        assertEquals(baseServiceMetadata.getDisplayServiceKey(), \"org.apache.dubbo.common.TestInterface:1.0.0\");\n\n        baseServiceMetadata.setServiceKey(\n                BaseServiceMetadata.buildServiceKey(\"org.apache.dubbo.common.TestInterface\", null, null));\n        assertEquals(baseServiceMetadata.getServiceKey(), \"org.apache.dubbo.common.TestInterface\");\n        baseServiceMetadata.setServiceKey(\n                BaseServiceMetadata.buildServiceKey(\"org.apache.dubbo.common.TestInterface\", \"\", \"\"));\n        assertEquals(baseServiceMetadata.getServiceKey(), \"org.apache.dubbo.common.TestInterface\");\n\n        baseServiceMetadata.setVersion(\"2.0.0\");\n        baseServiceMetadata.generateServiceKey();\n        assertEquals(baseServiceMetadata.getServiceKey(), \"group1/org.apache.dubbo.common.TestInterface:2.0.0\");\n\n        assertEquals(\n                BaseServiceMetadata.versionFromServiceKey(\"group1/org.apache.dubbo.common.TestInterface:1.0.0\"),\n                \"1.0.0\");\n        assertEquals(\n                BaseServiceMetadata.groupFromServiceKey(\"group1/org.apache.dubbo.common.TestInterface:1.0.0\"),\n                \"group1\");\n        assertEquals(\n                BaseServiceMetadata.interfaceFromServiceKey(\"group1/org.apache.dubbo.common.TestInterface:1.0.0\"),\n                \"org.apache.dubbo.common.TestInterface\");\n\n        assertEquals(DEFAULT_VERSION, BaseServiceMetadata.versionFromServiceKey(\"\"));\n        assertNull(BaseServiceMetadata.groupFromServiceKey(\"\"));\n        assertEquals(BaseServiceMetadata.interfaceFromServiceKey(\"\"), \"\");\n\n        assertEquals(\n                BaseServiceMetadata.revertDisplayServiceKey(\"org.apache.dubbo.common.TestInterface:1.0.0\")\n                        .getDisplayServiceKey(),\n                \"org.apache.dubbo.common.TestInterface:1.0.0\");\n        assertEquals(\n                BaseServiceMetadata.revertDisplayServiceKey(\"org.apache.dubbo.common.TestInterface\")\n                        .getDisplayServiceKey(),\n                \"org.apache.dubbo.common.TestInterface:null\");\n        assertEquals(BaseServiceMetadata.revertDisplayServiceKey(null).getDisplayServiceKey(), \"null:null\");\n        assertEquals(\n                BaseServiceMetadata.revertDisplayServiceKey(\"org.apache.dubbo.common.TestInterface:1.0.0:1\")\n                        .getDisplayServiceKey(),\n                \"null:null\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/CommonScopeModelInitializerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.config.ConfigurationCache;\nimport org.apache.dubbo.common.lang.ShutdownHookCallbacks;\nimport org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link CommonScopeModelInitializer}\n */\nclass CommonScopeModelInitializerTest {\n\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n        applicationModel = frameworkModel.newApplication();\n        moduleModel = applicationModel.newModule();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void test() {\n        ScopeBeanFactory applicationModelBeanFactory = applicationModel.getBeanFactory();\n        Assertions.assertNotNull(applicationModelBeanFactory.getBean(ShutdownHookCallbacks.class));\n        Assertions.assertNotNull(applicationModelBeanFactory.getBean(FrameworkStatusReportService.class));\n        Assertions.assertNotNull(applicationModelBeanFactory.getBean(ConfigurationCache.class));\n\n        ScopeBeanFactory moduleModelBeanFactory = moduleModel.getBeanFactory();\n        Assertions.assertNotNull(moduleModelBeanFactory.getBean(ConfigurationCache.class));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/InterfaceAddressURLTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.url.component.DubboServiceAddressURL;\nimport org.apache.dubbo.common.url.component.ServiceAddressURL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNotSame;\n\nclass InterfaceAddressURLTest {\n    private static final String rawURL =\n            \"dubbo://10.20.130.230:20880/context/path?version=1.0.0&group=g1&application=provider&timeout=1000&category=provider&side=provider&sayHello.weight=222\";\n    private static final URL overrideURL = URL.valueOf(\n            \"override://10.20.130.230:20880/context/path?version=1.0.0&application=morgan&timeout=2000&category=configurators&sayHello.overrideKey=override\");\n    private static final URL consumerURL = URL.valueOf(\n            \"consumer://10.20.130.230/context/path?version=2.0.0,1.0.0&group=g2&application=morgan&timeout=3000&side=consumer&sayHello.timeout=5000\");\n\n    @Test\n    void testMergeOverriden() {\n        URL url = URL.valueOf(rawURL);\n        ServiceAddressURL interfaceAddressURL =\n                new DubboServiceAddressURL(url.getUrlAddress(), url.getUrlParam(), null, null);\n        assertEquals(\"1000\", interfaceAddressURL.getParameter(TIMEOUT_KEY));\n\n        ServiceAddressURL withConsumer = DubboServiceAddressURL.valueOf(rawURL, consumerURL);\n        assertEquals(\"3000\", withConsumer.getParameter(TIMEOUT_KEY));\n\n        ServiceAddressURL withOverriden =\n                DubboServiceAddressURL.valueOf(rawURL, consumerURL, (ServiceConfigURL) overrideURL);\n        assertEquals(\"2000\", withOverriden.getParameter(TIMEOUT_KEY));\n    }\n\n    @Test\n    void testGetParameter() {\n        URL url = URL.valueOf(rawURL);\n        ServiceAddressURL interfaceAddressURL =\n                new DubboServiceAddressURL(url.getUrlAddress(), url.getUrlParam(), consumerURL, null);\n\n        assertEquals(\"3000\", interfaceAddressURL.getParameter(TIMEOUT_KEY));\n\n        assertEquals(\"morgan\", interfaceAddressURL.getApplication());\n        assertEquals(\"provider\", interfaceAddressURL.getRemoteApplication());\n\n        assertEquals(\"dubbo\", interfaceAddressURL.getProtocol());\n        assertEquals(\"context/path\", interfaceAddressURL.getPath());\n\n        assertEquals(\"consumer\", interfaceAddressURL.getSide());\n        assertEquals(\"1.0.0\", interfaceAddressURL.getVersion());\n        assertEquals(\"g1\", interfaceAddressURL.getGroup());\n    }\n\n    @Test\n    void testGetMethodParameter() {\n        URL url = URL.valueOf(rawURL);\n        ServiceAddressURL interfaceAddressURL = new DubboServiceAddressURL(\n                url.getUrlAddress(), url.getUrlParam(), consumerURL, (ServiceConfigURL) overrideURL);\n\n        assertEquals(\"5000\", interfaceAddressURL.getMethodParameter(\"sayHello\", TIMEOUT_KEY));\n        assertEquals(\"2000\", interfaceAddressURL.getMethodParameter(\"non-exist-methods\", TIMEOUT_KEY));\n        assertEquals(\"222\", interfaceAddressURL.getMethodParameter(\"sayHello\", \"weight\"));\n        assertEquals(\"222\", interfaceAddressURL.getMethodParameter(\"sayHello\", \"weight\"));\n        assertEquals(\"override\", interfaceAddressURL.getMethodParameter(\"sayHello\", \"overrideKey\"));\n    }\n\n    @Test\n    void testURLEquals() {\n        URL url1 = URL.valueOf(rawURL);\n        URL url2 = URL.valueOf(rawURL);\n        assertNotSame(url1, url2);\n        assertEquals(url1, url2);\n\n        // with consumer\n        ServiceAddressURL withConsumer =\n                new DubboServiceAddressURL(url1.getUrlAddress(), url1.getUrlParam(), consumerURL, null);\n        ServiceAddressURL withConsumer2 =\n                new DubboServiceAddressURL(url1.getUrlAddress(), url1.getUrlParam(), consumerURL, null);\n        assertEquals(withConsumer, withConsumer2);\n\n        ServiceAddressURL withOverride = new DubboServiceAddressURL(\n                url1.getUrlAddress(), url1.getUrlParam(), consumerURL, (ServiceConfigURL) overrideURL);\n        url2 = url2.addParameter(\"timeout\", \"4444\");\n        ServiceAddressURL withOverride2 = new DubboServiceAddressURL(\n                url2.getUrlAddress(), url2.getUrlParam(), consumerURL, (ServiceConfigURL) overrideURL);\n        assertNotEquals(url1, url2);\n        assertEquals(withOverride, withOverride2);\n    }\n\n    @Test\n    void testToString() {\n        URL url1 = URL.valueOf(rawURL);\n        assertNotNull(url1.toString());\n        ServiceAddressURL withConsumer =\n                new DubboServiceAddressURL(url1.getUrlAddress(), url1.getUrlParam(), consumerURL, null);\n        assertNotNull(withConsumer.toString());\n        ServiceAddressURL withOverride2 = new DubboServiceAddressURL(\n                url1.getUrlAddress(), url1.getUrlParam(), consumerURL, (ServiceConfigURL) overrideURL);\n        assertNotNull(withOverride2.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/PojoUtilsForNonPublicStaticTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.utils.PojoUtils;\n\nimport org.junit.jupiter.api.Test;\n\nclass PojoUtilsForNonPublicStaticTest {\n\n    @Test\n    void testNonPublicStaticClass() {\n        NonPublicStaticData nonPublicStaticData = new NonPublicStaticData(\"horizon\");\n        PojoUtils.generalize(nonPublicStaticData);\n    }\n\n    /**\n     * the static class need is not same package with PojoUtils, so define it here.\n     */\n    static class NonPublicStaticData {\n\n        private String name;\n\n        public NonPublicStaticData(String name) {\n            this.name = name;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/ProtocolServiceKeyMatcherTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ProtocolServiceKeyMatcherTest {\n\n    @Test\n    void testProtocol() {\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo\"), new ProtocolServiceKey(null, null, null, \"dubbo\")));\n\n        Assertions.assertFalse(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo\"), new ProtocolServiceKey(null, null, null, null)));\n\n        Assertions.assertFalse(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo\"),\n                new ProtocolServiceKey(\"DemoService\", null, null, \"dubbo\")));\n\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, null), new ProtocolServiceKey(null, null, null, \"dubbo\")));\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"\"), new ProtocolServiceKey(null, null, null, \"dubbo\")));\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"*\"), new ProtocolServiceKey(null, null, null, \"dubbo\")));\n\n        Assertions.assertFalse(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo1,dubbo2\"),\n                new ProtocolServiceKey(null, null, null, \"dubbo\")));\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo1,dubbo2\"),\n                new ProtocolServiceKey(null, null, null, \"dubbo1\")));\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo1,dubbo2\"),\n                new ProtocolServiceKey(null, null, null, \"dubbo2\")));\n\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo1,,dubbo2\"),\n                new ProtocolServiceKey(null, null, null, null)));\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo1,,dubbo2\"),\n                new ProtocolServiceKey(null, null, null, \"\")));\n\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \",dubbo1,dubbo2\"),\n                new ProtocolServiceKey(null, null, null, null)));\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \",dubbo1,dubbo2\"),\n                new ProtocolServiceKey(null, null, null, \"\")));\n\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo1,dubbo2,\"),\n                new ProtocolServiceKey(null, null, null, null)));\n        Assertions.assertTrue(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo1,dubbo2,\"),\n                new ProtocolServiceKey(null, null, null, \"\")));\n\n        Assertions.assertFalse(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo1,,dubbo2\"),\n                new ProtocolServiceKey(null, null, null, \"dubbo\")));\n        Assertions.assertFalse(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \",dubbo1,dubbo2\"),\n                new ProtocolServiceKey(null, null, null, \"dubbo\")));\n        Assertions.assertFalse(ProtocolServiceKey.Matcher.isMatch(\n                new ProtocolServiceKey(null, null, null, \"dubbo1,dubbo2,\"),\n                new ProtocolServiceKey(null, null, null, \"dubbo\")));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/ProtocolServiceKeyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ProtocolServiceKeyTest {\n    @Test\n    void test() {\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"protocol1\");\n        Assertions.assertEquals(\"DemoService\", protocolServiceKey.getInterfaceName());\n        Assertions.assertEquals(\"1.0.0\", protocolServiceKey.getVersion());\n        Assertions.assertEquals(\"group1\", protocolServiceKey.getGroup());\n        Assertions.assertEquals(\"protocol1\", protocolServiceKey.getProtocol());\n\n        Assertions.assertEquals(\"group1/DemoService:1.0.0:protocol1\", protocolServiceKey.toString());\n        Assertions.assertEquals(\"group1/DemoService:1.0.0\", protocolServiceKey.getServiceKeyString());\n\n        Assertions.assertEquals(protocolServiceKey, protocolServiceKey);\n\n        ProtocolServiceKey protocolServiceKey1 = new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"protocol1\");\n        Assertions.assertEquals(protocolServiceKey, protocolServiceKey1);\n        Assertions.assertEquals(protocolServiceKey.hashCode(), protocolServiceKey1.hashCode());\n\n        ProtocolServiceKey protocolServiceKey2 = new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"protocol2\");\n        Assertions.assertNotEquals(protocolServiceKey, protocolServiceKey2);\n\n        ProtocolServiceKey protocolServiceKey3 = new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group2\", \"protocol1\");\n        Assertions.assertNotEquals(protocolServiceKey, protocolServiceKey3);\n\n        ProtocolServiceKey protocolServiceKey4 = new ProtocolServiceKey(\"DemoService\", \"1.0.1\", \"group1\", \"protocol1\");\n        Assertions.assertNotEquals(protocolServiceKey, protocolServiceKey4);\n\n        ProtocolServiceKey protocolServiceKey5 =\n                new ProtocolServiceKey(\"DemoInterface\", \"1.0.0\", \"group1\", \"protocol1\");\n        Assertions.assertNotEquals(protocolServiceKey, protocolServiceKey5);\n\n        ServiceKey serviceKey = new ServiceKey(\"DemoService\", \"1.0.0\", \"group1\");\n        Assertions.assertNotEquals(protocolServiceKey, serviceKey);\n\n        Assertions.assertTrue(protocolServiceKey.isSameWith(protocolServiceKey));\n        Assertions.assertTrue(\n                protocolServiceKey.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"\")));\n        Assertions.assertTrue(\n                protocolServiceKey.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", null)));\n\n        Assertions.assertFalse(\n                protocolServiceKey.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group2\", \"protocol1\")));\n        Assertions.assertFalse(\n                protocolServiceKey.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group2\", \"\")));\n        Assertions.assertFalse(\n                protocolServiceKey.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group2\", null)));\n\n        ProtocolServiceKey protocolServiceKey6 = new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", null);\n        Assertions.assertTrue(protocolServiceKey6.isSameWith(protocolServiceKey6));\n        Assertions.assertTrue(\n                protocolServiceKey6.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"\")));\n        Assertions.assertTrue(\n                protocolServiceKey6.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"protocol1\")));\n        Assertions.assertTrue(\n                protocolServiceKey6.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"protocol2\")));\n\n        ProtocolServiceKey protocolServiceKey7 = new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"*\");\n        Assertions.assertFalse(\n                protocolServiceKey7.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", null)));\n        Assertions.assertFalse(\n                protocolServiceKey7.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"\")));\n        Assertions.assertFalse(\n                protocolServiceKey7.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"protocol1\")));\n        Assertions.assertFalse(\n                protocolServiceKey7.isSameWith(new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"protocol2\")));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/ServiceKeyMatcherTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ServiceKeyMatcherTest {\n\n    @Test\n    void testInterface() {\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, null), new ServiceKey(null, null, null)));\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(\"DemoService\", null, null), new ServiceKey(null, null, null)));\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, null, null), new ServiceKey(\"DemoService\", null, null)));\n\n        Assertions.assertFalse(\n                ServiceKey.Matcher.isMatch(new ServiceKey(\"*\", null, null), new ServiceKey(\"DemoService\", null, null)));\n        Assertions.assertFalse(\n                ServiceKey.Matcher.isMatch(new ServiceKey(\"*\", null, null), new ServiceKey(null, null, null)));\n    }\n\n    @Test\n    void testVersion() {\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, \"1.0.0\", null), new ServiceKey(null, \"1.0.0\", null)));\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, null), new ServiceKey(null, null, null)));\n        Assertions.assertFalse(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, \"1.0.0\", null), new ServiceKey(null, null, null)));\n        Assertions.assertFalse(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, null), new ServiceKey(null, \"1.0.0\", null)));\n\n        Assertions.assertTrue(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, \"1.0.0,1.0.1\", null), new ServiceKey(null, \"1.0.0\", null)));\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, \"1.0.0,1.0.1\", null), new ServiceKey(null, \"1.0.2\", null)));\n\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, \"1.0.0,1.0.1\", null), new ServiceKey(null, null, null)));\n\n        Assertions.assertTrue(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, \",1.0.0,1.0.1\", null), new ServiceKey(null, null, null)));\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, \",1.0.0,1.0.1\", null), new ServiceKey(null, \"\", null)));\n\n        Assertions.assertTrue(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, \"1.0.0,,1.0.1\", null), new ServiceKey(null, null, null)));\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, \"1.0.0,,1.0.1\", null), new ServiceKey(null, \"\", null)));\n\n        Assertions.assertTrue(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, \"1.0.0,1.0.1,\", null), new ServiceKey(null, null, null)));\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, \"1.0.0,1.0.1,\", null), new ServiceKey(null, \"\", null)));\n\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, \"1.0.0,1.0.1\", null), new ServiceKey(null, null, null)));\n        Assertions.assertFalse(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, \"1.0.0,1.0.1\", null), new ServiceKey(null, \"\", null)));\n\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, \",1.0.0,1.0.1\", null), new ServiceKey(null, \"1.0.2\", null)));\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, \",1.0.0,1.0.1\", null), new ServiceKey(null, \"1.0.2\", null)));\n\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, \"*\", null), new ServiceKey(null, null, null)));\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, \"*\", null), new ServiceKey(null, \"\", null)));\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, \"*\", null), new ServiceKey(null, \"1.0.0\", null)));\n    }\n\n    @Test\n    void testGroup() {\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, \"group1\"), new ServiceKey(null, null, \"group1\")));\n        Assertions.assertFalse(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, \"group1\"), new ServiceKey(null, null, null)));\n        Assertions.assertFalse(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, null), new ServiceKey(null, null, \"group1\")));\n\n        Assertions.assertTrue(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, null, \"group1, group2\"), new ServiceKey(null, null, \"group1\")));\n\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, null, \"group2, group3\"), new ServiceKey(null, null, \"group1\")));\n\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, null, \"group2, group3\"), new ServiceKey(null, null, null)));\n\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, null, \"group2, group3\"), new ServiceKey(null, null, \"\")));\n\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, \",group2\"), new ServiceKey(null, null, \"\")));\n\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, \"group2,\"), new ServiceKey(null, null, \"\")));\n\n        Assertions.assertTrue(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, null, \"group2, ,group3\"), new ServiceKey(null, null, \"\")));\n\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, null, \",group2\"), new ServiceKey(null, null, \"group1\")));\n\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, null, \"group2,\"), new ServiceKey(null, null, \"group1\")));\n\n        Assertions.assertFalse(ServiceKey.Matcher.isMatch(\n                new ServiceKey(null, null, \"group2, ,group3\"), new ServiceKey(null, null, \"group1\")));\n\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, \"*\"), new ServiceKey(null, null, \"\")));\n\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, \"*\"), new ServiceKey(null, null, null)));\n\n        Assertions.assertTrue(\n                ServiceKey.Matcher.isMatch(new ServiceKey(null, null, \"*\"), new ServiceKey(null, null, \"group1\")));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/ServiceKeyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ServiceKeyTest {\n    @Test\n    void test() {\n        ServiceKey serviceKey = new ServiceKey(\"DemoService\", \"1.0.0\", \"group1\");\n\n        Assertions.assertEquals(\"DemoService\", serviceKey.getInterfaceName());\n        Assertions.assertEquals(\"1.0.0\", serviceKey.getVersion());\n        Assertions.assertEquals(\"group1\", serviceKey.getGroup());\n\n        Assertions.assertEquals(\"group1/DemoService:1.0.0\", serviceKey.toString());\n        Assertions.assertEquals(\"DemoService\", new ServiceKey(\"DemoService\", null, null).toString());\n        Assertions.assertEquals(\"DemoService:1.0.0\", new ServiceKey(\"DemoService\", \"1.0.0\", null).toString());\n        Assertions.assertEquals(\"group1/DemoService\", new ServiceKey(\"DemoService\", null, \"group1\").toString());\n\n        Assertions.assertEquals(serviceKey, serviceKey);\n\n        ServiceKey serviceKey1 = new ServiceKey(\"DemoService\", \"1.0.0\", \"group1\");\n        Assertions.assertEquals(serviceKey, serviceKey1);\n        Assertions.assertEquals(serviceKey.hashCode(), serviceKey1.hashCode());\n\n        ServiceKey serviceKey2 = new ServiceKey(\"DemoService\", \"1.0.0\", \"group2\");\n        Assertions.assertNotEquals(serviceKey, serviceKey2);\n\n        ServiceKey serviceKey3 = new ServiceKey(\"DemoService\", \"1.0.1\", \"group1\");\n        Assertions.assertNotEquals(serviceKey, serviceKey3);\n\n        ServiceKey serviceKey4 = new ServiceKey(\"DemoInterface\", \"1.0.0\", \"group1\");\n        Assertions.assertNotEquals(serviceKey, serviceKey4);\n\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(\"DemoService\", \"1.0.0\", \"group1\", \"protocol1\");\n        Assertions.assertNotEquals(serviceKey, protocolServiceKey);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/URLBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.NetUtils;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass URLBuilderTest {\n    @Test\n    void testNoArgConstructor() {\n        URL url = new URLBuilder().build();\n        assertThat(url.toString(), equalTo(\"\"));\n    }\n\n    @Test\n    void shouldAddParameter() {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        URL url2 = URLBuilder.from(url1)\n                .addParameter(\"newKey1\", \"newValue1\") // string\n                .addParameter(\"newKey2\", 2) // int\n                .addParameter(\"version\", 1) // override\n                .build();\n        assertThat(url2.getParameter(\"newKey1\"), equalTo(\"newValue1\"));\n        assertThat(url2.getParameter(\"newKey2\"), equalTo(\"2\"));\n        assertThat(url2.getVersion(), equalTo(\"1\"));\n    }\n\n    @Test\n    void testDefault() {\n        ServiceConfigURL url1 = URLBuilder.from(URL.valueOf(\"\"))\n                .addParameter(\"timeout\", \"1234\")\n                .addParameter(\"default.timeout\", \"5678\")\n                .build();\n\n        assertThat(url1.getParameter(\"timeout\"), equalTo(\"1234\"));\n        assertThat(url1.getParameter(\"default.timeout\"), equalTo(\"5678\"));\n\n        ServiceConfigURL url2 = URLBuilder.from(URL.valueOf(\"\"))\n                .addParameter(\"default.timeout\", \"5678\")\n                .build();\n\n        assertThat(url2.getParameter(\"timeout\"), equalTo(\"5678\"));\n        assertThat(url2.getParameter(\"default.timeout\"), equalTo(\"5678\"));\n    }\n\n    @Test\n    void shouldSet() {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        int port = NetUtils.getAvailablePort();\n        URL url2 = URLBuilder.from(url1)\n                .setProtocol(\"rest\")\n                .setUsername(\"newUsername\")\n                .setPassword(\"newPassword\")\n                .setHost(\"newHost\")\n                .setPath(\"newContext\")\n                .setPort(port)\n                .build();\n        assertThat(url2.getProtocol(), equalTo(\"rest\"));\n        assertThat(url2.getUsername(), equalTo(\"newUsername\"));\n        assertThat(url2.getPassword(), equalTo(\"newPassword\"));\n        assertThat(url2.getHost(), equalTo(\"newHost\"));\n        assertThat(url2.getPort(), equalTo(port));\n        assertThat(url2.getPath(), equalTo(\"newContext\"));\n\n        int port2 = NetUtils.getAvailablePort();\n        url2 = URLBuilder.from(url1).setAddress(\"newHost2:\" + port2).build();\n        assertThat(url2.getHost(), equalTo(\"newHost2\"));\n        assertThat(url2.getPort(), equalTo(port2));\n    }\n\n    @Test\n    void shouldClearParameters() {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        URL url2 = URLBuilder.from(url1).clearParameters().build();\n        assertThat(url2.getParameters().size(), equalTo(0));\n    }\n\n    @Test\n    void shouldRemoveParameters() {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&key2=v2\");\n        URL url2 = URLBuilder.from(url1)\n                .removeParameters(Arrays.asList(\"key2\", \"application\"))\n                .build();\n        assertThat(url2.getParameters().size(), equalTo(1));\n        assertThat(url2.getVersion(), equalTo(\"1.0.0\"));\n    }\n\n    @Test\n    void shouldAddIfAbsent() {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&key2=v2\");\n        URL url2 = URLBuilder.from(url1)\n                .addParameterIfAbsent(\"absentKey\", \"absentValue\")\n                .addParameterIfAbsent(\"version\", \"2.0.0\") // should not override\n                .build();\n        assertThat(url2.getVersion(), equalTo(\"1.0.0\"));\n        assertThat(url2.getParameter(\"absentKey\"), equalTo(\"absentValue\"));\n    }\n\n    @Test\n    void shouldAddParameters() {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&key2=v2\");\n\n        // string pairs test\n        URL url2 = URLBuilder.from(url1)\n                .addParameters(\"version\", \"1.0.0\", \"absentKey1\", \"absentValue1\")\n                .build();\n        assertThat(url2.getParameter(\"version\"), equalTo(\"1.0.0\"));\n        assertThat(url2.getParameter(\"absentKey1\"), equalTo(\"absentValue1\"));\n\n        // map test\n        Map<String, String> parameters = new HashMap<String, String>() {\n            {\n                this.put(\"version\", \"2.0.0\");\n                this.put(\"absentKey2\", \"absentValue2\");\n            }\n        };\n        url2 = URLBuilder.from(url1).addParameters(parameters).build();\n        assertThat(url2.getParameter(\"version\"), equalTo(\"2.0.0\"));\n        assertThat(url2.getParameter(\"absentKey2\"), equalTo(\"absentValue2\"));\n    }\n\n    @Test\n    void shouldAddParametersIfAbsent() {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&key2=v2\");\n\n        Map<String, String> parameters = new HashMap<String, String>() {\n            {\n                this.put(\"version\", \"2.0.0\");\n                this.put(\"absentKey\", \"absentValue\");\n            }\n        };\n        URL url2 = URLBuilder.from(url1).addParametersIfAbsent(parameters).build();\n        assertThat(url2.getParameter(\"version\"), equalTo(\"1.0.0\"));\n        assertThat(url2.getParameter(\"absentKey\"), equalTo(\"absentValue\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/URLStrParserTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport net.bytebuddy.utility.RandomString;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n/**\n * Created by LinShunkang on 2020/03/12\n */\nclass URLStrParserTest {\n    private static Set<String> testCases = new HashSet<>(16);\n    private static Set<String> errorDecodedCases = new HashSet<>(8);\n    private static Set<String> errorEncodedCases = new HashSet<>(8);\n\n    static {\n        testCases.add(\"dubbo://192.168.1.1\");\n        testCases.add(\"dubbo://192.168.1.1?\");\n        testCases.add(\"dubbo://127.0.0.1?test=中文测试\");\n        testCases.add(\"dubbo://admin:admin123@192.168.1.41:28113/org.test.api\"\n                + \".DemoService$Iface?anyhost=true&application=demo-service&dubbo=2.6.1&generic=false&interface=org\"\n                + \".test.api.DemoService$Iface&methods=orbCompare,checkText,checkPicture&pid=65557&revision=1.4\"\n                + \".17&service.filter=bootMetrics&side=provider&status=server&threads=200&timestamp=1583136298859\"\n                + \"&version=1.0.0\");\n        // super long text test\n        testCases.add(\"dubbo://192.168.1.1/\" + RandomString.make(10240));\n        testCases.add(\"file:/path/to/file.txt\");\n        testCases.add(\"dubbo://fe80:0:0:0:894:aeec:f37d:23e1%en0/path?abc=abc\");\n        testCases.add(\"dubbo://[fe80:0:0:0:894:aeec:f37d:23e1]:20880/path?abc=abc\");\n        testCases.add(\"nacos://192.168.1.1:8848?username=&password=\");\n        testCases.add(\"dubbo://127.0.0.1?timeout=1234&default.timeout=5678\");\n        testCases.add(\"dubbo://127.0.0.1?default.timeout=5678\");\n\n        errorDecodedCases.add(\"dubbo:192.168.1.1\");\n        errorDecodedCases.add(\"://192.168.1.1\");\n        errorDecodedCases.add(\":/192.168.1.1\");\n\n        errorEncodedCases.add(\"dubbo%3a%2f%2f192.168.1.41%3fabc%3\");\n        errorEncodedCases.add(\"dubbo%3a192.168.1.1%3fabc%3dabc\");\n        errorEncodedCases.add(\"%3a%2f%2f192.168.1.1%3fabc%3dabc\");\n        errorEncodedCases.add(\"%3a%2f192.168.1.1%3fabc%3dabc\");\n        errorEncodedCases.add(\"dubbo%3a%2f%2f127.0.0.1%3ftest%3d%e2%96%b2%e2%96%bc%e2%97%80%e2%96%b6%e2%86%90%e2%86\"\n                + \"%91%e2%86%92%e2%86%93%e2%86%94%e2%86%95%e2%88%9e%c2%b1%e9%be%98%e9%9d%90%e9%bd%89%9%d%b\");\n    }\n\n    @Test\n    void testEncoded() {\n        testCases.forEach(testCase -> {\n            assertThat(URLStrParser.parseEncodedStr(URL.encode(testCase)), equalTo(URL.valueOf(testCase)));\n        });\n\n        errorEncodedCases.forEach(errorCase -> {\n            Assertions.assertThrows(RuntimeException.class, () -> URLStrParser.parseEncodedStr(errorCase));\n        });\n    }\n\n    @Test\n    void testDecoded() {\n        testCases.forEach(testCase -> {\n            assertThat(URLStrParser.parseDecodedStr(testCase), equalTo(URL.valueOf(testCase)));\n        });\n\n        errorDecodedCases.forEach(errorCase -> {\n            Assertions.assertThrows(RuntimeException.class, () -> URLStrParser.parseDecodedStr(errorCase));\n        });\n    }\n\n    @Test\n    void testDefault() {\n        URL url1 = URLStrParser.parseEncodedStr(URL.encode(\"dubbo://127.0.0.1?timeout=1234&default.timeout=5678\"));\n        assertThat(url1.getParameter(\"timeout\"), equalTo(\"1234\"));\n        assertThat(url1.getParameter(\"default.timeout\"), equalTo(\"5678\"));\n\n        URL url2 = URLStrParser.parseEncodedStr(URL.encode(\"dubbo://127.0.0.1?default.timeout=5678\"));\n        assertThat(url2.getParameter(\"timeout\"), equalTo(\"5678\"));\n        assertThat(url2.getParameter(\"default.timeout\"), equalTo(\"5678\"));\n    }\n\n    @Test\n    void testPond() {\n        String str = \"https://a#@b\";\n\n        URL url1 = URL.valueOf(str);\n        URL url2 = URLStrParser.parseDecodedStr(str);\n\n        Assertions.assertEquals(\"https\", url1.getProtocol());\n        Assertions.assertEquals(\"https\", url2.getProtocol());\n        Assertions.assertEquals(\"a\", url1.getHost());\n        Assertions.assertEquals(\"a\", url2.getHost());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common;\n\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.Predicate;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.OS_WIN_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_OS_NAME;\nimport static org.hamcrest.CoreMatchers.anyOf;\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass URLTest {\n\n    @Test\n    void test_ignore_pond() {\n        URL url = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path#index?version=1.0.0&id=org.apache.dubbo.config.RegistryConfig#0\");\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"org.apache.dubbo.config.RegistryConfig#0\", url.getParameter(\"id\"));\n    }\n\n    @Test\n    void testDefault() {\n        URL url1 = URL.valueOf(\"dubbo://127.0.0.1:12345?timeout=1234&default.timeout=5678\");\n        assertEquals(1234, url1.getParameter(\"timeout\", 0));\n        assertEquals(5678, url1.getParameter(\"default.timeout\", 0));\n\n        URL url2 = URL.valueOf(\"dubbo://127.0.0.1:12345?default.timeout=5678\");\n        assertEquals(5678, url2.getParameter(\"timeout\", 0));\n        assertEquals(5678, url2.getParameter(\"default.timeout\", 0));\n    }\n\n    @Test\n    void test_valueOf_noProtocolAndHost() throws Exception {\n        URL url = URL.valueOf(\"/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url);\n        assertNull(url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertNull(url.getHost());\n        assertNull(url.getAddress());\n        assertEquals(0, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n\n        url = URL.valueOf(\"context/path?version=1.0.0&application=morgan\");\n        //                 ^^^^^^^ Caution , parse as host\n        assertURLStrDecoder(url);\n        assertNull(url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertEquals(\"context\", url.getHost());\n        assertEquals(0, url.getPort());\n        assertEquals(\"path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n    }\n\n    private void assertURLStrDecoder(URL url) {\n        String fullURLStr = url.toFullString();\n        URL newUrl = URLStrParser.parseEncodedStr(URL.encode(fullURLStr));\n        assertEquals(URL.valueOf(fullURLStr), newUrl);\n\n        URL newUrl2 = URLStrParser.parseDecodedStr(fullURLStr);\n        assertEquals(URL.valueOf(fullURLStr), newUrl2);\n    }\n\n    @Test\n    void test_valueOf_noProtocol() throws Exception {\n        URL url = URL.valueOf(\"10.20.130.230\");\n        assertURLStrDecoder(url);\n        assertNull(url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230\", url.getAddress());\n        assertEquals(0, url.getPort());\n        assertNull(url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        url = URL.valueOf(\"10.20.130.230:20880\");\n        assertURLStrDecoder(url);\n        assertNull(url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertNull(url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        url = URL.valueOf(\"10.20.130.230/context/path\");\n        assertURLStrDecoder(url);\n        assertNull(url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230\", url.getAddress());\n        assertEquals(0, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        url = URL.valueOf(\"10.20.130.230:20880/context/path\");\n        assertURLStrDecoder(url);\n        assertNull(url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        url = URL.valueOf(\"admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url);\n        assertNull(url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n    }\n\n    @Test\n    void test_valueOf_noHost() throws Exception {\n        URL url = URL.valueOf(\"file:///home/user1/router.js\");\n        assertURLStrDecoder(url);\n        assertEquals(\"file\", url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertNull(url.getHost());\n        assertNull(url.getAddress());\n        assertEquals(0, url.getPort());\n        assertEquals(\"home/user1/router.js\", url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        // Caution!!\n        url = URL.valueOf(\"file://home/user1/router.js\");\n        //                      ^^ only tow slash!\n        assertURLStrDecoder(url);\n        assertEquals(\"file\", url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertEquals(\"home\", url.getHost());\n        assertEquals(0, url.getPort());\n        assertEquals(\"user1/router.js\", url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        url = URL.valueOf(\"file:/home/user1/router.js\");\n        assertURLStrDecoder(url);\n        assertEquals(\"file\", url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertNull(url.getHost());\n        assertNull(url.getAddress());\n        assertEquals(0, url.getPort());\n        assertEquals(\"home/user1/router.js\", url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        url = URL.valueOf(\"file:///d:/home/user1/router.js\");\n        assertURLStrDecoder(url);\n        assertEquals(\"file\", url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertNull(url.getHost());\n        assertNull(url.getAddress());\n        assertEquals(0, url.getPort());\n        assertEquals(\"d:/home/user1/router.js\", url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        url = URL.valueOf(\"file:///home/user1/router.js?p1=v1&p2=v2\");\n        assertURLStrDecoder(url);\n        assertEquals(\"file\", url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertNull(url.getHost());\n        assertNull(url.getAddress());\n        assertEquals(0, url.getPort());\n        assertEquals(\"home/user1/router.js\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        Map<String, String> params = new HashMap<String, String>();\n        params.put(\"p1\", \"v1\");\n        params.put(\"p2\", \"v2\");\n        assertEquals(params, url.getParameters());\n\n        url = URL.valueOf(\"file:/home/user1/router.js?p1=v1&p2=v2\");\n        assertURLStrDecoder(url);\n        assertEquals(\"file\", url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertNull(url.getHost());\n        assertNull(url.getAddress());\n        assertEquals(0, url.getPort());\n        assertEquals(\"home/user1/router.js\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        params = new HashMap<String, String>();\n        params.put(\"p1\", \"v1\");\n        params.put(\"p2\", \"v2\");\n        assertEquals(params, url.getParameters());\n    }\n\n    @Test\n    void test_valueOf_WithProtocolHost() throws Exception {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230\");\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230\", url.getAddress());\n        assertEquals(0, url.getPort());\n        assertNull(url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path\");\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880\");\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertNull(url.getPath());\n        assertEquals(0, url.getParameters().size());\n\n        url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880?version=1.0.0\");\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertNull(url.getPath());\n        assertEquals(1, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n\n        url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n\n        url = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&noValue=\");\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(3, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n        assertEquals(\"\", url.getParameter(\"noValue\"));\n    }\n\n    // TODO Do not want to use spaces? See: DUBBO-502, URL class handles special conventions for special characters.\n    @Test\n    void test_valueOf_spaceSafe() throws Exception {\n        URL url = URL.valueOf(\"http://1.2.3.4:8080/path?key=value1 value2\");\n        assertURLStrDecoder(url);\n        assertEquals(\"http://1.2.3.4:8080/path?key=value1 value2\", url.toString());\n        assertEquals(\"value1 value2\", url.getParameter(\"key\"));\n    }\n\n    @Test\n    void test_noValueKey() throws Exception {\n        URL url = URL.valueOf(\"http://1.2.3.4:8080/path?k0=&k1=v1\");\n\n        assertURLStrDecoder(url);\n        assertFalse(url.hasParameter(\"k0\"));\n\n        // If a Key has no corresponding Value, then empty string used as the Value.\n        assertEquals(\"\", url.getParameter(\"k0\"));\n    }\n\n    @Test\n    void test_valueOf_Exception_noProtocol() throws Exception {\n        try {\n            URL.valueOf(\"://1.2.3.4:8080/path\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertEquals(\"url missing protocol: \\\"://1.2.3.4:8080/path\\\"\", expected.getMessage());\n        }\n\n        try {\n            String encodedURLStr = URL.encode(\"://1.2.3.4:8080/path\");\n            URLStrParser.parseEncodedStr(encodedURLStr);\n            fail();\n        } catch (IllegalStateException expected) {\n            assertEquals(\"url missing protocol: \\\"://1.2.3.4:8080/path\\\"\", URL.decode(expected.getMessage()));\n        }\n\n        try {\n            URLStrParser.parseDecodedStr(\"://1.2.3.4:8080/path\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertEquals(\"url missing protocol: \\\"://1.2.3.4:8080/path\\\"\", expected.getMessage());\n        }\n    }\n\n    @Test\n    void test_getAddress() throws Exception {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url1);\n        assertEquals(\"10.20.130.230:20880\", url1.getAddress());\n    }\n\n    @Test\n    void test_getAbsolutePath() throws Exception {\n        URL url = new ServiceConfigURL(\"p1\", \"1.2.2.2\", 33);\n        assertURLStrDecoder(url);\n        assertNull(url.getAbsolutePath());\n\n        url = new ServiceConfigURL(\"file\", null, 90, \"/home/user1/route.js\");\n        assertURLStrDecoder(url);\n        assertEquals(\"/home/user1/route.js\", url.getAbsolutePath());\n    }\n\n    @Test\n    void test_equals() throws Exception {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url1);\n\n        Map<String, String> params = new HashMap<String, String>();\n        params.put(\"version\", \"1.0.0\");\n        params.put(\"application\", \"morgan\");\n        URL url2 = new ServiceConfigURL(\"dubbo\", \"admin\", \"hello1234\", \"10.20.130.230\", 20880, \"context/path\", params);\n\n        assertURLStrDecoder(url2);\n        assertEquals(url1, url2);\n    }\n\n    @Test\n    void test_toString() throws Exception {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url1);\n        assertThat(\n                url1.toString(),\n                anyOf(\n                        equalTo(\"dubbo://10.20.130.230:20880/context/path?version=1.0.0&application=morgan\"),\n                        equalTo(\"dubbo://10.20.130.230:20880/context/path?application=morgan&version=1.0.0\")));\n    }\n\n    @Test\n    void test_toFullString() throws Exception {\n        URL url1 = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url1);\n        assertThat(\n                url1.toFullString(),\n                anyOf(\n                        equalTo(\n                                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\"),\n                        equalTo(\n                                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&version=1.0.0\")));\n    }\n\n    @Test\n    void test_set_methods() throws Exception {\n        URL url = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url);\n\n        url = url.setHost(\"host\");\n\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"host\", url.getHost());\n        assertEquals(\"host:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n\n        url = url.setPort(1);\n\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"host\", url.getHost());\n        assertEquals(\"host:1\", url.getAddress());\n        assertEquals(1, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n\n        url = url.setPath(\"path\");\n\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"host\", url.getHost());\n        assertEquals(\"host:1\", url.getAddress());\n        assertEquals(1, url.getPort());\n        assertEquals(\"path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n\n        url = url.setProtocol(\"protocol\");\n\n        assertURLStrDecoder(url);\n        assertEquals(\"protocol\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"host\", url.getHost());\n        assertEquals(\"host:1\", url.getAddress());\n        assertEquals(1, url.getPort());\n        assertEquals(\"path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n\n        url = url.setUsername(\"username\");\n\n        assertURLStrDecoder(url);\n        assertEquals(\"protocol\", url.getProtocol());\n        assertEquals(\"username\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"host\", url.getHost());\n        assertEquals(\"host:1\", url.getAddress());\n        assertEquals(1, url.getPort());\n        assertEquals(\"path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n\n        url = url.setPassword(\"password\");\n\n        assertURLStrDecoder(url);\n        assertEquals(\"protocol\", url.getProtocol());\n        assertEquals(\"username\", url.getUsername());\n        assertEquals(\"password\", url.getPassword());\n        assertEquals(\"host\", url.getHost());\n        assertEquals(\"host:1\", url.getAddress());\n        assertEquals(1, url.getPort());\n        assertEquals(\"path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n    }\n\n    @Test\n    void test_removeParameters() throws Exception {\n        URL url = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2\");\n        assertURLStrDecoder(url);\n\n        url = url.removeParameter(\"version\");\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(3, url.getParameters().size());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n        assertEquals(\"v1\", url.getParameter(\"k1\"));\n        assertEquals(\"v2\", url.getParameter(\"k2\"));\n        assertNull(url.getVersion());\n\n        url = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2\");\n        url = url.removeParameters(\"version\", \"application\", \"NotExistedKey\");\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"v1\", url.getParameter(\"k1\"));\n        assertEquals(\"v2\", url.getParameter(\"k2\"));\n        assertNull(url.getVersion());\n        assertNull(url.getParameter(\"application\"));\n\n        url = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2\");\n        url = url.removeParameters(Arrays.asList(\"version\", \"application\"));\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"v1\", url.getParameter(\"k1\"));\n        assertEquals(\"v2\", url.getParameter(\"k2\"));\n        assertNull(url.getVersion());\n        assertNull(url.getParameter(\"application\"));\n    }\n\n    @Test\n    void test_addParameter() throws Exception {\n        URL url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan\");\n        url = url.addParameter(\"k1\", \"v1\");\n\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n        assertEquals(\"v1\", url.getParameter(\"k1\"));\n    }\n\n    @Test\n    void test_addParameter_sameKv() throws Exception {\n        URL url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&k1=v1\");\n        URL newUrl = url.addParameter(\"k1\", \"v1\");\n\n        assertURLStrDecoder(url);\n        assertSame(newUrl, url);\n    }\n\n    @Test\n    void test_addParameters() throws Exception {\n        URL url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan\");\n        url = url.addParameters(CollectionUtils.toStringMap(\"k1\", \"v1\", \"k2\", \"v2\"));\n\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(3, url.getParameters().size());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n        assertEquals(\"v1\", url.getParameter(\"k1\"));\n        assertEquals(\"v2\", url.getParameter(\"k2\"));\n\n        url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan\");\n        url = url.addParameters(\"k1\", \"v1\", \"k2\", \"v2\", \"application\", \"xxx\");\n\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(3, url.getParameters().size());\n        assertEquals(\"xxx\", url.getParameter(\"application\"));\n        assertEquals(\"v1\", url.getParameter(\"k1\"));\n        assertEquals(\"v2\", url.getParameter(\"k2\"));\n\n        url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan\");\n        url = url.addParametersIfAbsent(CollectionUtils.toStringMap(\"k1\", \"v1\", \"k2\", \"v2\", \"application\", \"xxx\"));\n\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(3, url.getParameters().size());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n        assertEquals(\"v1\", url.getParameter(\"k1\"));\n        assertEquals(\"v2\", url.getParameter(\"k2\"));\n\n        url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan\");\n        url = url.addParameter(\"k1\", \"v1\");\n\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n        assertEquals(\"v1\", url.getParameter(\"k1\"));\n\n        url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan\");\n        url = url.addParameter(\"application\", \"xxx\");\n\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(1, url.getParameters().size());\n        assertEquals(\"xxx\", url.getParameter(\"application\"));\n    }\n\n    @Test\n    void test_addParameters_SameKv() throws Exception {\n        {\n            URL url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&k1=v1\");\n            URL newUrl = url.addParameters(CollectionUtils.toStringMap(\"k1\", \"v1\"));\n\n            assertURLStrDecoder(url);\n            assertSame(url, newUrl);\n        }\n        {\n            URL url = URL.valueOf(\n                    \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&k1=v1&k2=v2\");\n            URL newUrl = url.addParameters(CollectionUtils.toStringMap(\"k1\", \"v1\", \"k2\", \"v2\"));\n\n            assertURLStrDecoder(url);\n            assertSame(newUrl, url);\n        }\n    }\n\n    @Test\n    void test_addParameterIfAbsent() throws Exception {\n        URL url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan\");\n        url = url.addParameterIfAbsent(\"application\", \"xxx\");\n\n        assertURLStrDecoder(url);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"admin\", url.getUsername());\n        assertEquals(\"hello1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(1, url.getParameters().size());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n    }\n\n    @Test\n    void test_windowAbsolutePathBeginWithSlashIsValid() throws Exception {\n        final String osProperty = SystemPropertyConfigUtils.getSystemProperty(SYSTEM_OS_NAME);\n        if (!osProperty.toLowerCase().contains(OS_WIN_PREFIX)) return;\n\n        File f0 = new File(\"C:/Windows\");\n        File f1 = new File(\"/C:/Windows\");\n\n        File f2 = new File(\"C:\\\\Windows\");\n        File f3 = new File(\"/C:\\\\Windows\");\n        File f4 = new File(\"\\\\C:\\\\Windows\");\n\n        assertEquals(f0, f1);\n        assertEquals(f0, f2);\n        assertEquals(f0, f3);\n        assertEquals(f0, f4);\n    }\n\n    @Test\n    void test_javaNetUrl() throws Exception {\n        java.net.URL url = new java.net.URL(\n                \"http://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan#anchor1\");\n\n        assertEquals(\"http\", url.getProtocol());\n        assertEquals(\"admin:hello1234\", url.getUserInfo());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"/context/path\", url.getPath());\n        assertEquals(\"version=1.0.0&application=morgan\", url.getQuery());\n        assertEquals(\"anchor1\", url.getRef());\n\n        assertEquals(\"admin:hello1234@10.20.130.230:20880\", url.getAuthority());\n        assertEquals(\"/context/path?version=1.0.0&application=morgan\", url.getFile());\n    }\n\n    @Test\n    void test_Anyhost() throws Exception {\n        URL url = URL.valueOf(\"dubbo://0.0.0.0:20880\");\n        assertURLStrDecoder(url);\n        assertEquals(\"0.0.0.0\", url.getHost());\n        assertTrue(url.isAnyHost());\n    }\n\n    @Test\n    void test_Localhost() throws Exception {\n        URL url = URL.valueOf(\"dubbo://127.0.0.1:20880\");\n        assertURLStrDecoder(url);\n        assertEquals(\"127.0.0.1\", url.getHost());\n        assertEquals(\"127.0.0.1:20880\", url.getAddress());\n        assertTrue(url.isLocalHost());\n\n        url = URL.valueOf(\"dubbo://127.0.1.1:20880\");\n        assertURLStrDecoder(url);\n        assertEquals(\"127.0.1.1\", url.getHost());\n        assertEquals(\"127.0.1.1:20880\", url.getAddress());\n        assertTrue(url.isLocalHost());\n\n        url = URL.valueOf(\"dubbo://localhost:20880\");\n        assertURLStrDecoder(url);\n        assertEquals(\"localhost\", url.getHost());\n        assertEquals(\"localhost:20880\", url.getAddress());\n        assertTrue(url.isLocalHost());\n    }\n\n    @Test\n    void test_Path() throws Exception {\n        URL url = new ServiceConfigURL(\"dubbo\", \"localhost\", 20880, \"////path\");\n        assertURLStrDecoder(url);\n        assertEquals(\"path\", url.getPath());\n    }\n\n    @Test\n    void testAddParameters() throws Exception {\n        URL url = URL.valueOf(\"dubbo://127.0.0.1:20880\");\n        assertURLStrDecoder(url);\n\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(\"version\", null);\n        url.addParameters(parameters);\n        assertURLStrDecoder(url);\n    }\n\n    @Test\n    void testUserNamePasswordContainsAt() {\n        // Test username or password contains \"@\"\n        URL url = URL.valueOf(\"ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url);\n        assertNull(url.getProtocol());\n        assertEquals(\"ad@min\", url.getUsername());\n        assertEquals(\"hello@1234\", url.getPassword());\n        assertEquals(\"10.20.130.230\", url.getHost());\n        assertEquals(\"10.20.130.230:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n    }\n\n    @Test\n    void testIpV6Address() {\n        // Test username or password contains \"@\"\n        URL url = URL.valueOf(\n                \"ad@min111:haha@1234@2001:0db8:85a3:08d3:1319:8a2e:0370:7344:20880/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url);\n        assertNull(url.getProtocol());\n        assertEquals(\"ad@min111\", url.getUsername());\n        assertEquals(\"haha@1234\", url.getPassword());\n        assertEquals(\"2001:0db8:85a3:08d3:1319:8a2e:0370:7344\", url.getHost());\n        assertEquals(\"2001:0db8:85a3:08d3:1319:8a2e:0370:7344:20880\", url.getAddress());\n        assertEquals(20880, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n    }\n\n    @Test\n    void testIpV6AddressWithScopeId() {\n        URL url =\n                URL.valueOf(\"2001:0db8:85a3:08d3:1319:8a2e:0370:7344%5/context/path?version=1.0.0&application=morgan\");\n        assertURLStrDecoder(url);\n        assertNull(url.getProtocol());\n        assertEquals(\"2001:0db8:85a3:08d3:1319:8a2e:0370:7344%5\", url.getHost());\n        assertEquals(\"2001:0db8:85a3:08d3:1319:8a2e:0370:7344%5\", url.getAddress());\n        assertEquals(0, url.getPort());\n        assertEquals(\"context/path\", url.getPath());\n        assertEquals(2, url.getParameters().size());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"morgan\", url.getParameter(\"application\"));\n    }\n\n    @Test\n    void testDefaultPort() {\n        Assertions.assertEquals(\"10.20.153.10:2181\", URL.appendDefaultPort(\"10.20.153.10:0\", 2181));\n        Assertions.assertEquals(\"10.20.153.10:2181\", URL.appendDefaultPort(\"10.20.153.10\", 2181));\n    }\n\n    @Test\n    void testGetServiceKey() {\n        URL url1 = URL.valueOf(\"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName\");\n        assertURLStrDecoder(url1);\n        Assertions.assertEquals(\"org.apache.dubbo.test.interfaceName\", url1.getServiceKey());\n\n        URL url2 = URL.valueOf(\n                \"10.20.130.230:20880/org.apache.dubbo.test.interfaceName?interface=org.apache.dubbo.test.interfaceName\");\n        assertURLStrDecoder(url2);\n        Assertions.assertEquals(\"org.apache.dubbo.test.interfaceName\", url2.getServiceKey());\n\n        URL url3 = URL.valueOf(\n                \"10.20.130.230:20880/org.apache.dubbo.test.interfaceName?interface=org.apache.dubbo.test.interfaceName&group=group1&version=1.0.0\");\n        assertURLStrDecoder(url3);\n        Assertions.assertEquals(\"group1/org.apache.dubbo.test.interfaceName:1.0.0\", url3.getServiceKey());\n\n        URL url4 = URL.valueOf(\"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName\");\n        assertURLStrDecoder(url4);\n        Assertions.assertEquals(\"context/path\", url4.getPathKey());\n\n        URL url5 = URL.valueOf(\n                \"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group1&version=1.0.0\");\n        assertURLStrDecoder(url5);\n        Assertions.assertEquals(\"group1/context/path:1.0.0\", url5.getPathKey());\n    }\n\n    @Test\n    void testGetColonSeparatedKey() {\n        URL url1 = URL.valueOf(\n                \"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0\");\n        assertURLStrDecoder(url1);\n        Assertions.assertEquals(\"org.apache.dubbo.test.interfaceName:1.0.0:group\", url1.getColonSeparatedKey());\n\n        URL url2 = URL.valueOf(\n                \"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&version=1.0.0\");\n        assertURLStrDecoder(url2);\n        Assertions.assertEquals(\"org.apache.dubbo.test.interfaceName:1.0.0:\", url2.getColonSeparatedKey());\n\n        URL url3 = URL.valueOf(\n                \"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group\");\n        assertURLStrDecoder(url3);\n        Assertions.assertEquals(\"org.apache.dubbo.test.interfaceName::group\", url3.getColonSeparatedKey());\n\n        URL url4 = URL.valueOf(\"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName\");\n        assertURLStrDecoder(url4);\n        Assertions.assertEquals(\"org.apache.dubbo.test.interfaceName::\", url4.getColonSeparatedKey());\n\n        URL url5 = URL.valueOf(\"10.20.130.230:20880/org.apache.dubbo.test.interfaceName\");\n        assertURLStrDecoder(url5);\n        Assertions.assertEquals(\"org.apache.dubbo.test.interfaceName::\", url5.getColonSeparatedKey());\n\n        URL url6 = URL.valueOf(\n                \"10.20.130.230:20880/org.apache.dubbo.test.interfaceName?interface=org.apache.dubbo.test.interfaceName1\");\n        assertURLStrDecoder(url6);\n        Assertions.assertEquals(\"org.apache.dubbo.test.interfaceName1::\", url6.getColonSeparatedKey());\n    }\n\n    @Test\n    void testValueOf() {\n        URL url = URL.valueOf(\"10.20.130.230\");\n        assertURLStrDecoder(url);\n\n        url = URL.valueOf(\"10.20.130.230:20880\");\n        assertURLStrDecoder(url);\n\n        url = URL.valueOf(\"dubbo://10.20.130.230:20880\");\n        assertURLStrDecoder(url);\n\n        url = URL.valueOf(\"dubbo://10.20.130.230:20880/path\");\n        assertURLStrDecoder(url);\n    }\n\n    /**\n     * Test {@link URL#getParameters(Predicate)} method\n     *\n     * @since 2.7.8\n     */\n    @Test\n    void testGetParameters() {\n        URL url = URL.valueOf(\n                \"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0\");\n        Map<String, String> parameters = url.getParameters(i -> \"version\".equals(i));\n        String version = parameters.get(\"version\");\n        assertEquals(1, parameters.size());\n        assertEquals(\"1.0.0\", version);\n    }\n\n    @Test\n    void testGetParameter() {\n        URL url = URL.valueOf(\"http://127.0.0.1:8080/path?i=1&b=false\");\n        assertEquals(Integer.valueOf(1), url.getParameter(\"i\", Integer.class));\n        assertEquals(Boolean.FALSE, url.getParameter(\"b\", Boolean.class));\n    }\n\n    @Test\n    void testEquals() {\n        URL url1 = URL.valueOf(\n                \"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0\");\n        URL url2 = URL.valueOf(\n                \"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0\");\n        Assertions.assertEquals(url1, url2);\n\n        URL url3 = URL.valueOf(\n                \"10.20.130.230:20881/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0\");\n        Assertions.assertNotEquals(url1, url3);\n\n        URL url4 = URL.valueOf(\n                \"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&weight=10&group=group&version=1.0.0\");\n        Assertions.assertNotEquals(url1, url4);\n\n        URL url5 = URL.valueOf(\n                \"10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&weight=10&group=group&version=1.0.0\");\n        Assertions.assertEquals(url4, url5);\n\n        URL url6 = URL.valueOf(\"consumer://30.225.20.150/org.apache.dubbo.rpc.service.GenericService?application=\"\n                + \"dubbo-demo-api-consumer&category=consumers&check=false&dubbo=2.0.2&generic=true&interface=\"\n                + \"org.apache.dubbo.demo.DemoService&pid=7375&side=consumer&sticky=false&timestamp=1599556506417\");\n        URL url7 = URL.valueOf(\"consumer://30.225.20.150/org.apache.dubbo.rpc.service.GenericService?application=\"\n                + \"dubbo-demo-api-consumer&category=consumers&check=false&dubbo=2.0.2&generic=true&interface=\"\n                + \"org.apache.dubbo.demo.DemoService&pid=7375&side=consumer&sticky=false&timestamp=2299556506417\");\n        assertEquals(url6, url7);\n\n        URL url8 = URL.valueOf(\"consumer://30.225.20.150/org.apache.dubbo.rpc.service.GenericService?application=\"\n                + \"dubbo-demo-api-consumer&category=consumers&check=false&dubbo=2.0.2&interface=\"\n                + \"org.apache.dubbo.demo.DemoService&pid=7375&side=consumer&sticky=false&timestamp=2299556506417\");\n        assertNotEquals(url7, url8);\n\n        URL url9 = URL.valueOf(\"consumer://30.225.20.150/org.apache.dubbo.rpc.service.GenericService?application=\"\n                + \"dubbo-demo-api-consumer&category=consumers&check=true&dubbo=2.0.2&interface=\"\n                + \"org.apache.dubbo.demo.DemoService&pid=7375&side=consumer&sticky=false&timestamp=2299556506417\");\n        assertNotEquals(url8, url9);\n    }\n\n    @Test\n    void testEqualsWithPassword() {\n        URL url1 = URL.valueOf(\"ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        URL url2 = URL.valueOf(\"ad@min:hello@4321@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        URL url3 = URL.valueOf(\"ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n\n        boolean actual1 = url1.equals(url2);\n        boolean actual2 = url1.equals(url3);\n        assertFalse(actual1);\n        assertTrue(actual2);\n    }\n\n    @Test\n    void testEqualsWithPath() {\n        URL url1 = URL.valueOf(\"ad@min:hello@1234@10.20.130.230:20880/context/path1?version=1.0.0&application=morgan\");\n        URL url2 = URL.valueOf(\"ad@min:hello@1234@10.20.130.230:20880/context/path2?version=1.0.0&application=morgan\");\n        URL url3 = URL.valueOf(\"ad@min:hello@1234@10.20.130.230:20880/context/path1?version=1.0.0&application=morgan\");\n\n        boolean actual1 = url1.equals(url2);\n        boolean actual2 = url1.equals(url3);\n        assertFalse(actual1);\n        assertTrue(actual2);\n    }\n\n    @Test\n    void testEqualsWithPort() {\n        URL url1 = URL.valueOf(\"ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        URL url2 = URL.valueOf(\"ad@min:hello@1234@10.20.130.230:20881/context/path?version=1.0.0&application=morgan\");\n        URL url3 = URL.valueOf(\"ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n\n        boolean actual1 = url1.equals(url2);\n        boolean actual2 = url1.equals(url3);\n        assertFalse(actual1);\n        assertTrue(actual2);\n    }\n\n    @Test\n    void testEqualsWithProtocol() {\n        URL url1 = URL.valueOf(\n                \"dubbo://ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        URL url2 = URL.valueOf(\n                \"file://ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        URL url3 = URL.valueOf(\n                \"dubbo://ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n\n        boolean actual1 = url1.equals(url2);\n        boolean actual2 = url1.equals(url3);\n        assertFalse(actual1);\n        assertTrue(actual2);\n    }\n\n    @Test\n    void testEqualsWithUser() {\n        URL url1 = URL.valueOf(\"ad@min1:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        URL url2 = URL.valueOf(\"ad@min2:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n        URL url3 = URL.valueOf(\"ad@min1:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan\");\n\n        boolean actual1 = url1.equals(url2);\n        boolean actual2 = url1.equals(url3);\n        assertFalse(actual1);\n        assertTrue(actual2);\n    }\n\n    @Test\n    void testHashcode() {\n        URL url1 = URL.valueOf(\"consumer://30.225.20.150/org.apache.dubbo.rpc.service.GenericService?application=\"\n                + \"dubbo-demo-api-consumer&category=consumers&check=false&dubbo=2.0.2&generic=true&interface=\"\n                + \"org.apache.dubbo.demo.DemoService&pid=7375&side=consumer&sticky=false&timestamp=1599556506417\");\n        URL url2 = URL.valueOf(\"consumer://30.225.20.150/org.apache.dubbo.rpc.service.GenericService?application=\"\n                + \"dubbo-demo-api-consumer&category=consumers&check=false&dubbo=2.0.2&generic=true&interface=\"\n                + \"org.apache.dubbo.demo.DemoService&pid=7375&side=consumer&sticky=false&timestamp=2299556506417\");\n        assertEquals(url1.hashCode(), url2.hashCode());\n\n        URL url3 = URL.valueOf(\"consumer://30.225.20.150/org.apache.dubbo.rpc.service.GenericService?application=\"\n                + \"dubbo-demo-api-consumer&category=consumers&check=false&dubbo=2.0.2&interface=\"\n                + \"org.apache.dubbo.demo.DemoService&pid=7375&side=consumer&sticky=false&timestamp=2299556506417\");\n        assertNotEquals(url2.hashCode(), url3.hashCode());\n\n        URL url4 = URL.valueOf(\"consumer://30.225.20.150/org.apache.dubbo.rpc.service.GenericService?application=\"\n                + \"dubbo-demo-api-consumer&category=consumers&check=true&dubbo=2.0.2&interface=\"\n                + \"org.apache.dubbo.demo.DemoService&pid=7375&side=consumer&sticky=false&timestamp=2299556506417\");\n        assertNotEquals(url3.hashCode(), url4.hashCode());\n    }\n\n    @Test\n    void testParameterContainPound() {\n        URL url = URL.valueOf(\n                \"dubbo://ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&pound=abcd#efg&protocol=registry\");\n        Assertions.assertEquals(\"abcd#efg\", url.getParameter(\"pound\"));\n        Assertions.assertEquals(\"registry\", url.getParameter(\"protocol\"));\n    }\n\n    @Test\n    void test_valueOfHasNameWithoutValue() throws Exception {\n        URL url = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&noValue\");\n        Assertions.assertEquals(\"\", url.getParameter(\"noValue\"));\n    }\n\n    @Test\n    void testGetAuthority() {\n        URL url = URL.valueOf(\"admin1:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=app1\");\n        assertEquals(\"admin1:hello1234@10.20.130.230:20880\", url.getAuthority());\n\n        URL urlWithoutUsername =\n                URL.valueOf(\":hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=app1\");\n        assertEquals(\":hello1234@10.20.130.230:20880\", urlWithoutUsername.getAuthority());\n\n        URL urlWithoutPassword = URL.valueOf(\"admin1:@10.20.130.230:20880/context/path?version=1.0.0&application=app1\");\n        assertEquals(\"admin1:@10.20.130.230:20880\", urlWithoutPassword.getAuthority());\n\n        URL urlWithoutUserInformation = URL.valueOf(\"10.20.130.230:20880/context/path?version=1.0.0&application=app1\");\n        assertEquals(\"10.20.130.230:20880\", urlWithoutUserInformation.getAuthority());\n\n        URL urlWithoutPort = URL.valueOf(\"admin1:hello1234@10.20.130.230/context/path?version=1.0.0&application=app1\");\n        assertEquals(\"admin1:hello1234@10.20.130.230\", urlWithoutPort.getAuthority());\n    }\n\n    @Test\n    void testGetUserInformation() {\n        URL url = URL.valueOf(\"admin1:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=app1\");\n        assertEquals(\"admin1:hello1234\", url.getUserInformation());\n\n        URL urlWithoutUsername =\n                URL.valueOf(\":hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=app1\");\n        assertEquals(\":hello1234@10.20.130.230:20880\", urlWithoutUsername.getAuthority());\n\n        URL urlWithoutPassword = URL.valueOf(\"admin1:@10.20.130.230:20880/context/path?version=1.0.0&application=app1\");\n        assertEquals(\"admin1:@10.20.130.230:20880\", urlWithoutPassword.getAuthority());\n\n        URL urlWithoutUserInformation = URL.valueOf(\"10.20.130.230:20880/context/path?version=1.0.0&application=app1\");\n        assertEquals(\"10.20.130.230:20880\", urlWithoutUserInformation.getAuthority());\n    }\n\n    @Test\n    void testIPV6() {\n        URL url = URL.valueOf(\"dubbo://[2408:4004:194:8896:3e8a:82ae:814a:398]:20881?name=apache\");\n        assertEquals(\"[2408:4004:194:8896:3e8a:82ae:814a:398]\", url.getHost());\n        assertEquals(20881, url.getPort());\n        assertEquals(\"apache\", url.getParameter(\"name\"));\n    }\n\n    @Test\n    void testToServiceString() {\n        URL url = URL.valueOf(\n                \"zookeeper://10.20.130.230:4444/org.apache.dubbo.metadata.report.MetadataReport?version=1.0.0&application=vic&group=aaa\");\n        assertEquals(\n                \"zookeeper://10.20.130.230:4444/aaa/org.apache.dubbo.metadata.report.MetadataReport:1.0.0\",\n                url.toServiceString());\n    }\n\n    @Test\n    void testToServiceStringWithParameters() {\n        URL url = URL.valueOf(\n                \"zookeeper://10.20.130.230:4444/org.apache.dubbo.metadata.report.MetadataReport?version=1.0.0&application=vic&group=aaa&namespace=test\");\n        assertEquals(\n                \"zookeeper://10.20.130.230:4444/aaa/org.apache.dubbo.metadata.report.MetadataReport:1.0.0?namespace=test\",\n                url.toServiceString(\"namespace\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/beans/InstantiationStrategyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans;\n\nimport org.apache.dubbo.common.beans.model.FooBeanWithApplicationModel;\nimport org.apache.dubbo.common.beans.model.FooBeanWithFrameworkModel;\nimport org.apache.dubbo.common.beans.model.FooBeanWithModuleModel;\nimport org.apache.dubbo.common.beans.model.FooBeanWithScopeModel;\nimport org.apache.dubbo.common.beans.model.FooBeanWithoutUniqueConstructors;\nimport org.apache.dubbo.common.beans.support.InstantiationStrategy;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAccessor;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass InstantiationStrategyTest {\n\n    private ScopeModelAccessor scopeModelAccessor = new ScopeModelAccessor() {\n        @Override\n        public ScopeModel getScopeModel() {\n            return ApplicationModel.defaultModel().getDefaultModule();\n        }\n    };\n\n    @Test\n    void testCreateBeanWithScopeModelArgument() throws ReflectiveOperationException {\n        InstantiationStrategy instantiationStrategy = new InstantiationStrategy(scopeModelAccessor);\n\n        FooBeanWithFrameworkModel beanWithFrameworkModel =\n                instantiationStrategy.instantiate(FooBeanWithFrameworkModel.class);\n        Assertions.assertSame(scopeModelAccessor.getFrameworkModel(), beanWithFrameworkModel.getFrameworkModel());\n\n        FooBeanWithApplicationModel beanWithApplicationModel =\n                instantiationStrategy.instantiate(FooBeanWithApplicationModel.class);\n        Assertions.assertSame(scopeModelAccessor.getApplicationModel(), beanWithApplicationModel.getApplicationModel());\n\n        FooBeanWithModuleModel beanWithModuleModel = instantiationStrategy.instantiate(FooBeanWithModuleModel.class);\n        Assertions.assertSame(scopeModelAccessor.getModuleModel(), beanWithModuleModel.getModuleModel());\n\n        FooBeanWithScopeModel beanWithScopeModel = instantiationStrategy.instantiate(FooBeanWithScopeModel.class);\n        Assertions.assertSame(scopeModelAccessor.getScopeModel(), beanWithScopeModel.getScopeModel());\n\n        // test not unique matched constructors\n        try {\n            instantiationStrategy.instantiate(FooBeanWithoutUniqueConstructors.class);\n            Assertions.fail(\"Expect throwing exception\");\n        } catch (Exception e) {\n            Assertions.assertTrue(\n                    e.getMessage().contains(\"Expect only one but found 2 matched constructors\"),\n                    StringUtils.toString(e));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/beans/ScopeBeanFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.beans.model.FooBeanWithApplicationModel;\nimport org.apache.dubbo.common.beans.model.FooBeanWithFrameworkModel;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ScopeBeanFactoryTest {\n\n    @Test\n    void testInjection() {\n\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        FooBeanWithApplicationModel beanWithApplicationModel =\n                beanFactory.registerBean(FooBeanWithApplicationModel.class);\n        Assertions.assertSame(applicationModel, beanWithApplicationModel.getApplicationModel());\n\n        FrameworkModel frameworkModel = applicationModel.getFrameworkModel();\n        FooBeanWithFrameworkModel beanWithFrameworkModel =\n                frameworkModel.getBeanFactory().registerBean(FooBeanWithFrameworkModel.class);\n        Assertions.assertSame(frameworkModel, beanWithFrameworkModel.getFrameworkModel());\n\n        // child bean factory can obtain bean from parent bean factory\n        FooBeanWithFrameworkModel beanWithFrameworkModelFromApp =\n                applicationModel.getBeanFactory().getBean(FooBeanWithFrameworkModel.class);\n        Assertions.assertSame(beanWithFrameworkModel, beanWithFrameworkModelFromApp);\n\n        Object objectBean = applicationModel.getBeanFactory().getBean(Object.class);\n        Assertions.assertNull(objectBean);\n\n        // child bean factory can obtain bean from parent bean factory by classType\n        frameworkModel.getBeanFactory().registerBean(new TestBean());\n        applicationModel.getBeanFactory().registerBean(new TestBean());\n        List<TestBean> testBeans = applicationModel.getBeanFactory().getBeansOfType(TestBean.class);\n        Assertions.assertEquals(testBeans.size(), 2);\n\n        // father can't get son's\n        List<TestBean> testBeans_1 = frameworkModel.getBeanFactory().getBeansOfType(TestBean.class);\n        Assertions.assertEquals(testBeans_1.size(), 1);\n\n        Assertions.assertFalse(beanWithApplicationModel.isDestroyed());\n        Assertions.assertFalse(beanWithFrameworkModel.isDestroyed());\n\n        // destroy\n        frameworkModel.destroy();\n        Assertions.assertTrue(beanWithApplicationModel.isDestroyed());\n        Assertions.assertTrue(beanWithFrameworkModel.isDestroyed());\n    }\n\n    static class TestBean {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithApplicationModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans.model;\n\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\npublic class FooBeanWithApplicationModel implements Disposable {\n    private ApplicationModel applicationModel;\n    private boolean destroyed;\n\n    public FooBeanWithApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    public ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    @Override\n    public void destroy() {\n        this.destroyed = true;\n    }\n\n    public boolean isDestroyed() {\n        return destroyed;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithFrameworkModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans.model;\n\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\npublic class FooBeanWithFrameworkModel implements Disposable {\n    private FrameworkModel frameworkModel;\n    private boolean destroyed;\n\n    public FooBeanWithFrameworkModel(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    public FrameworkModel getFrameworkModel() {\n        return frameworkModel;\n    }\n\n    @Override\n    public void destroy() {\n        this.destroyed = true;\n    }\n\n    public boolean isDestroyed() {\n        return destroyed;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithModuleModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans.model;\n\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\npublic class FooBeanWithModuleModel {\n    private ModuleModel moduleModel;\n\n    public FooBeanWithModuleModel(ModuleModel moduleModel) {\n        this.moduleModel = moduleModel;\n    }\n\n    public ModuleModel getModuleModel() {\n        return moduleModel;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithScopeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans.model;\n\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\npublic class FooBeanWithScopeModel {\n    private ScopeModel scopeModel;\n\n    public FooBeanWithScopeModel(ScopeModel scopeModel) {\n        this.scopeModel = scopeModel;\n    }\n\n    public ScopeModel getScopeModel() {\n        return scopeModel;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithoutUniqueConstructors.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beans.model;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\npublic class FooBeanWithoutUniqueConstructors {\n    private ModuleModel moduleModel;\n    private ApplicationModel applicationModel;\n\n    public FooBeanWithoutUniqueConstructors(ModuleModel moduleModel) {\n        this.moduleModel = moduleModel;\n    }\n\n    public FooBeanWithoutUniqueConstructors(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/beanutil/Bean.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beanutil;\n\nimport org.apache.dubbo.rpc.model.person.FullAddress;\nimport org.apache.dubbo.rpc.model.person.PersonStatus;\nimport org.apache.dubbo.rpc.model.person.Phone;\n\nimport java.io.Serializable;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.Map;\n\npublic class Bean implements Serializable {\n\n    private Class<?> type;\n\n    private PersonStatus status;\n\n    private Date date;\n\n    private Phone[] array;\n\n    private Collection<Phone> collection;\n\n    private Map<String, FullAddress> addresses;\n\n    public Class<?> getType() {\n        return type;\n    }\n\n    public void setType(Class<?> type) {\n        this.type = type;\n    }\n\n    public PersonStatus getStatus() {\n        return status;\n    }\n\n    public void setStatus(PersonStatus status) {\n        this.status = status;\n    }\n\n    public Date getDate() {\n        return date;\n    }\n\n    public void setDate(Date date) {\n        this.date = date;\n    }\n\n    public Phone[] getArray() {\n        return array;\n    }\n\n    public void setArray(Phone[] array) {\n        this.array = array;\n    }\n\n    public Collection<Phone> getCollection() {\n        return collection;\n    }\n\n    public void setCollection(Collection<Phone> collection) {\n        this.collection = collection;\n    }\n\n    public Map<String, FullAddress> getAddresses() {\n        return addresses;\n    }\n\n    public void setAddresses(Map<String, FullAddress> addresses) {\n        this.addresses = addresses;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/beanutil/JavaBeanAccessorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beanutil;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass JavaBeanAccessorTest {\n\n    @Test\n    void testIsAccessByMethod() {\n        Assertions.assertTrue(JavaBeanAccessor.isAccessByMethod(JavaBeanAccessor.METHOD));\n        Assertions.assertTrue(JavaBeanAccessor.isAccessByMethod(JavaBeanAccessor.ALL));\n        Assertions.assertFalse(JavaBeanAccessor.isAccessByMethod(JavaBeanAccessor.FIELD));\n    }\n\n    @Test\n    void testIsAccessByField() {\n        Assertions.assertTrue(JavaBeanAccessor.isAccessByField(JavaBeanAccessor.FIELD));\n        Assertions.assertTrue(JavaBeanAccessor.isAccessByField(JavaBeanAccessor.ALL));\n        Assertions.assertFalse(JavaBeanAccessor.isAccessByField(JavaBeanAccessor.METHOD));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtilTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.beanutil;\n\nimport org.apache.dubbo.rpc.model.person.BigPerson;\nimport org.apache.dubbo.rpc.model.person.FullAddress;\nimport org.apache.dubbo.rpc.model.person.PersonInfo;\nimport org.apache.dubbo.rpc.model.person.PersonStatus;\nimport org.apache.dubbo.rpc.model.person.Phone;\n\nimport java.lang.reflect.Array;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass JavaBeanSerializeUtilTest {\n\n    @Test\n    void testSerialize_Primitive() {\n        JavaBeanDescriptor descriptor;\n        descriptor = JavaBeanSerializeUtil.serialize(Integer.MAX_VALUE);\n        Assertions.assertTrue(descriptor.isPrimitiveType());\n        Assertions.assertEquals(Integer.MAX_VALUE, descriptor.getPrimitiveProperty());\n\n        Date now = new Date();\n        descriptor = JavaBeanSerializeUtil.serialize(now);\n        Assertions.assertTrue(descriptor.isPrimitiveType());\n        Assertions.assertEquals(now, descriptor.getPrimitiveProperty());\n    }\n\n    @Test\n    void testSerialize_Primitive_NUll() {\n        JavaBeanDescriptor descriptor;\n        descriptor = JavaBeanSerializeUtil.serialize(null);\n        Assertions.assertNull(descriptor);\n    }\n\n    @Test\n    void testDeserialize_Primitive() {\n        JavaBeanDescriptor descriptor = new JavaBeanDescriptor(long.class.getName(), JavaBeanDescriptor.TYPE_PRIMITIVE);\n        descriptor.setPrimitiveProperty(Long.MAX_VALUE);\n        Assertions.assertEquals(Long.MAX_VALUE, JavaBeanSerializeUtil.deserialize(descriptor));\n\n        BigDecimal decimal = BigDecimal.TEN;\n        Assertions.assertEquals(Long.MAX_VALUE, descriptor.setPrimitiveProperty(decimal));\n        Assertions.assertEquals(decimal, JavaBeanSerializeUtil.deserialize(descriptor));\n\n        String string = UUID.randomUUID().toString();\n        Assertions.assertEquals(decimal, descriptor.setPrimitiveProperty(string));\n        Assertions.assertEquals(string, JavaBeanSerializeUtil.deserialize(descriptor));\n    }\n\n    @Test\n    void testDeserialize_Primitive0() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            JavaBeanDescriptor descriptor =\n                    new JavaBeanDescriptor(long.class.getName(), JavaBeanDescriptor.TYPE_BEAN + 1);\n        });\n    }\n\n    @Test\n    void testDeserialize_Null() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            JavaBeanDescriptor descriptor = new JavaBeanDescriptor(null, JavaBeanDescriptor.TYPE_BEAN);\n        });\n    }\n\n    @Test\n    void testDeserialize_containsProperty() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            JavaBeanDescriptor descriptor =\n                    new JavaBeanDescriptor(long.class.getName(), JavaBeanDescriptor.TYPE_PRIMITIVE);\n            descriptor.containsProperty(null);\n        });\n    }\n\n    @Test\n    void testSetEnumNameProperty() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JavaBeanDescriptor descriptor =\n                    new JavaBeanDescriptor(long.class.getName(), JavaBeanDescriptor.TYPE_PRIMITIVE);\n            descriptor.setEnumNameProperty(JavaBeanDescriptor.class.getName());\n        });\n\n        JavaBeanDescriptor descriptor =\n                new JavaBeanDescriptor(JavaBeanDescriptor.class.getName(), JavaBeanDescriptor.TYPE_ENUM);\n\n        String oldValueOrigin = descriptor.setEnumNameProperty(JavaBeanDescriptor.class.getName());\n        Assertions.assertNull(oldValueOrigin);\n\n        String oldValueNext = descriptor.setEnumNameProperty(JavaBeanDescriptor.class.getName());\n        Assertions.assertEquals(oldValueNext, descriptor.getEnumPropertyName());\n    }\n\n    @Test\n    void testGetEnumNameProperty() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JavaBeanDescriptor descriptor =\n                    new JavaBeanDescriptor(long.class.getName(), JavaBeanDescriptor.TYPE_PRIMITIVE);\n            descriptor.getEnumPropertyName();\n        });\n    }\n\n    @Test\n    void testSetClassNameProperty() {\n\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JavaBeanDescriptor descriptor =\n                    new JavaBeanDescriptor(long.class.getName(), JavaBeanDescriptor.TYPE_PRIMITIVE);\n            descriptor.setClassNameProperty(JavaBeanDescriptor.class.getName());\n        });\n\n        JavaBeanDescriptor descriptor =\n                new JavaBeanDescriptor(JavaBeanDescriptor.class.getName(), JavaBeanDescriptor.TYPE_CLASS);\n\n        String oldValue1 = descriptor.setClassNameProperty(JavaBeanDescriptor.class.getName());\n        Assertions.assertNull(oldValue1);\n\n        String oldValue2 = descriptor.setClassNameProperty(JavaBeanDescriptor.class.getName());\n        Assertions.assertEquals(oldValue2, descriptor.getClassNameProperty());\n    }\n\n    @Test\n    void testGetClassNameProperty() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JavaBeanDescriptor descriptor =\n                    new JavaBeanDescriptor(long.class.getName(), JavaBeanDescriptor.TYPE_PRIMITIVE);\n            descriptor.getClassNameProperty();\n        });\n    }\n\n    @Test\n    void testSetPrimitiveProperty() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JavaBeanDescriptor descriptor =\n                    new JavaBeanDescriptor(JavaBeanDescriptor.class.getName(), JavaBeanDescriptor.TYPE_BEAN);\n            descriptor.setPrimitiveProperty(JavaBeanDescriptor.class.getName());\n        });\n    }\n\n    @Test\n    void testGetPrimitiveProperty() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JavaBeanDescriptor descriptor =\n                    new JavaBeanDescriptor(JavaBeanDescriptor.class.getName(), JavaBeanDescriptor.TYPE_BEAN);\n            descriptor.getPrimitiveProperty();\n        });\n    }\n\n    @Test\n    void testDeserialize_get_and_set() {\n        JavaBeanDescriptor descriptor = new JavaBeanDescriptor(long.class.getName(), JavaBeanDescriptor.TYPE_BEAN);\n        descriptor.setType(JavaBeanDescriptor.TYPE_PRIMITIVE);\n        Assertions.assertEquals(descriptor.getType(), JavaBeanDescriptor.TYPE_PRIMITIVE);\n        descriptor.setClassName(JavaBeanDescriptor.class.getName());\n        Assertions.assertEquals(JavaBeanDescriptor.class.getName(), descriptor.getClassName());\n    }\n\n    @Test\n    void testSerialize_Array() {\n        int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9};\n        JavaBeanDescriptor descriptor = JavaBeanSerializeUtil.serialize(array, JavaBeanAccessor.METHOD);\n        Assertions.assertTrue(descriptor.isArrayType());\n        Assertions.assertEquals(int.class.getName(), descriptor.getClassName());\n        for (int i = 0; i < array.length; i++) {\n            Assertions.assertEquals(array[i], ((JavaBeanDescriptor) descriptor.getProperty(i)).getPrimitiveProperty());\n        }\n\n        Integer[] integers = new Integer[] {1, 2, 3, 4, null, null, null};\n        descriptor = JavaBeanSerializeUtil.serialize(integers, JavaBeanAccessor.METHOD);\n        Assertions.assertTrue(descriptor.isArrayType());\n        Assertions.assertEquals(Integer.class.getName(), descriptor.getClassName());\n        Assertions.assertEquals(integers.length, descriptor.propertySize());\n        for (int i = 0; i < integers.length; i++) {\n            if (integers[i] == null) {\n                Assertions.assertSame(integers[i], descriptor.getProperty(i));\n            } else {\n                Assertions.assertEquals(\n                        integers[i], ((JavaBeanDescriptor) descriptor.getProperty(i)).getPrimitiveProperty());\n            }\n        }\n\n        int[][] second = {{1, 2}, {3, 4}};\n        descriptor = JavaBeanSerializeUtil.serialize(second, JavaBeanAccessor.METHOD);\n        Assertions.assertTrue(descriptor.isArrayType());\n        Assertions.assertEquals(int[].class.getName(), descriptor.getClassName());\n        for (int i = 0; i < second.length; i++) {\n            for (int j = 0; j < second[i].length; j++) {\n                JavaBeanDescriptor item = (((JavaBeanDescriptor) descriptor.getProperty(i)));\n                Assertions.assertTrue(item.isArrayType());\n                Assertions.assertEquals(int.class.getName(), item.getClassName());\n                Assertions.assertEquals(\n                        second[i][j], ((JavaBeanDescriptor) item.getProperty(j)).getPrimitiveProperty());\n            }\n        }\n\n        BigPerson[] persons = new BigPerson[] {createBigPerson(), createBigPerson()};\n        descriptor = JavaBeanSerializeUtil.serialize(persons);\n        Assertions.assertTrue(descriptor.isArrayType());\n        Assertions.assertEquals(BigPerson.class.getName(), descriptor.getClassName());\n        for (int i = 0; i < persons.length; i++) {\n            assertEqualsBigPerson(persons[i], descriptor.getProperty(i));\n        }\n    }\n\n    @Test\n    void testConstructorArg() {\n        Assertions.assertFalse((boolean) JavaBeanSerializeUtil.getConstructorArg(boolean.class));\n        Assertions.assertFalse((boolean) JavaBeanSerializeUtil.getConstructorArg(Boolean.class));\n        Assertions.assertEquals((byte) 0, JavaBeanSerializeUtil.getConstructorArg(byte.class));\n        Assertions.assertEquals((byte) 0, JavaBeanSerializeUtil.getConstructorArg(Byte.class));\n        Assertions.assertEquals((short) 0, JavaBeanSerializeUtil.getConstructorArg(short.class));\n        Assertions.assertEquals((short) 0, JavaBeanSerializeUtil.getConstructorArg(Short.class));\n        Assertions.assertEquals(0, JavaBeanSerializeUtil.getConstructorArg(int.class));\n        Assertions.assertEquals(0, JavaBeanSerializeUtil.getConstructorArg(Integer.class));\n        Assertions.assertEquals((long) 0, JavaBeanSerializeUtil.getConstructorArg(long.class));\n        Assertions.assertEquals((long) 0, JavaBeanSerializeUtil.getConstructorArg(Long.class));\n        Assertions.assertEquals((float) 0, JavaBeanSerializeUtil.getConstructorArg(float.class));\n        Assertions.assertEquals((float) 0, JavaBeanSerializeUtil.getConstructorArg(Float.class));\n        Assertions.assertEquals((double) 0, JavaBeanSerializeUtil.getConstructorArg(double.class));\n        Assertions.assertEquals((double) 0, JavaBeanSerializeUtil.getConstructorArg(Double.class));\n        Assertions.assertEquals((char) 0, JavaBeanSerializeUtil.getConstructorArg(char.class));\n        Assertions.assertEquals(new Character((char) 0), JavaBeanSerializeUtil.getConstructorArg(Character.class));\n        Assertions.assertNull(JavaBeanSerializeUtil.getConstructorArg(JavaBeanSerializeUtil.class));\n    }\n\n    @Test\n    void testDeserialize_Array() {\n        final int len = 10;\n        JavaBeanDescriptor descriptor = new JavaBeanDescriptor(int.class.getName(), JavaBeanDescriptor.TYPE_ARRAY);\n        for (int i = 0; i < len; i++) {\n            descriptor.setProperty(i, i);\n        }\n\n        Object obj = JavaBeanSerializeUtil.deserialize(descriptor);\n        Assertions.assertTrue(obj.getClass().isArray());\n        Assertions.assertSame(int.class, obj.getClass().getComponentType());\n        for (int i = 0; i < len; i++) {\n            Assertions.assertEquals(i, Array.get(obj, i));\n        }\n\n        descriptor = new JavaBeanDescriptor(int[].class.getName(), JavaBeanDescriptor.TYPE_ARRAY);\n        for (int i = 0; i < len; i++) {\n            JavaBeanDescriptor innerItem = new JavaBeanDescriptor(int.class.getName(), JavaBeanDescriptor.TYPE_ARRAY);\n            for (int j = 0; j < len; j++) {\n                innerItem.setProperty(j, j);\n            }\n            descriptor.setProperty(i, innerItem);\n        }\n        obj = JavaBeanSerializeUtil.deserialize(descriptor);\n        Assertions.assertTrue(obj.getClass().isArray());\n        Assertions.assertEquals(int[].class, obj.getClass().getComponentType());\n        for (int i = 0; i < len; i++) {\n            Object innerItem = Array.get(obj, i);\n            Assertions.assertTrue(innerItem.getClass().isArray());\n            Assertions.assertEquals(int.class, innerItem.getClass().getComponentType());\n            for (int j = 0; j < len; j++) {\n                Assertions.assertEquals(j, Array.get(innerItem, j));\n            }\n        }\n\n        descriptor = new JavaBeanDescriptor(BigPerson[].class.getName(), JavaBeanDescriptor.TYPE_ARRAY);\n        JavaBeanDescriptor innerDescriptor =\n                new JavaBeanDescriptor(BigPerson.class.getName(), JavaBeanDescriptor.TYPE_ARRAY);\n        innerDescriptor.setProperty(0, JavaBeanSerializeUtil.serialize(createBigPerson(), JavaBeanAccessor.METHOD));\n        descriptor.setProperty(0, innerDescriptor);\n\n        obj = JavaBeanSerializeUtil.deserialize(descriptor);\n        Assertions.assertTrue(obj.getClass().isArray());\n        Assertions.assertEquals(BigPerson[].class, obj.getClass().getComponentType());\n        Assertions.assertEquals(1, Array.getLength(obj));\n        obj = Array.get(obj, 0);\n        Assertions.assertTrue(obj.getClass().isArray());\n        Assertions.assertEquals(BigPerson.class, obj.getClass().getComponentType());\n        Assertions.assertEquals(1, Array.getLength(obj));\n        Assertions.assertEquals(createBigPerson(), Array.get(obj, 0));\n    }\n\n    @Test\n    void test_Circular_Reference() {\n        Parent parent = new Parent();\n        parent.setAge(Integer.MAX_VALUE);\n        parent.setEmail(\"a@b\");\n        parent.setName(\"zhangsan\");\n\n        Child child = new Child();\n        child.setAge(100);\n        child.setName(\"lisi\");\n        child.setParent(parent);\n\n        parent.setChild(child);\n\n        JavaBeanDescriptor descriptor = JavaBeanSerializeUtil.serialize(parent, JavaBeanAccessor.METHOD);\n        Assertions.assertTrue(descriptor.isBeanType());\n        assertEqualsPrimitive(parent.getAge(), descriptor.getProperty(\"age\"));\n        assertEqualsPrimitive(parent.getName(), descriptor.getProperty(\"name\"));\n        assertEqualsPrimitive(parent.getEmail(), descriptor.getProperty(\"email\"));\n\n        JavaBeanDescriptor childDescriptor = (JavaBeanDescriptor) descriptor.getProperty(\"child\");\n        Assertions.assertSame(descriptor, childDescriptor.getProperty(\"parent\"));\n        assertEqualsPrimitive(child.getName(), childDescriptor.getProperty(\"name\"));\n        assertEqualsPrimitive(child.getAge(), childDescriptor.getProperty(\"age\"));\n    }\n\n    public static class Parent {\n        public String gender;\n        public String email;\n        String name;\n        int age;\n        Child child;\n        private String securityEmail;\n\n        public static Parent getNewParent() {\n            return new Parent();\n        }\n\n        public String getEmail() {\n            return this.securityEmail;\n        }\n\n        public void setEmail(String email) {\n            this.securityEmail = email;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public int getAge() {\n            return age;\n        }\n\n        public void setAge(int age) {\n            this.age = age;\n        }\n\n        public Child getChild() {\n            return child;\n        }\n\n        public void setChild(Child child) {\n            this.child = child;\n        }\n    }\n\n    public static class Child {\n        public String gender;\n        public int age;\n        String toy;\n        Parent parent;\n        private String name;\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public int getAge() {\n            return age;\n        }\n\n        public void setAge(int age) {\n            this.age = age;\n        }\n\n        public String getToy() {\n            return toy;\n        }\n\n        public void setToy(String toy) {\n            this.toy = toy;\n        }\n\n        public Parent getParent() {\n            return parent;\n        }\n\n        public void setParent(Parent parent) {\n            this.parent = parent;\n        }\n    }\n\n    @Test\n    void testBeanSerialize() {\n        Bean bean = new Bean();\n        bean.setDate(new Date());\n        bean.setStatus(PersonStatus.ENABLED);\n        bean.setType(Bean.class);\n        bean.setArray(new Phone[] {});\n\n        Collection<Phone> collection = new ArrayList<Phone>();\n        bean.setCollection(collection);\n        Phone phone = new Phone();\n        collection.add(phone);\n\n        Map<String, FullAddress> map = new HashMap<String, FullAddress>();\n        FullAddress address = new FullAddress();\n        map.put(\"first\", address);\n        bean.setAddresses(map);\n\n        JavaBeanDescriptor descriptor = JavaBeanSerializeUtil.serialize(bean, JavaBeanAccessor.METHOD);\n        Assertions.assertTrue(descriptor.isBeanType());\n        assertEqualsPrimitive(bean.getDate(), descriptor.getProperty(\"date\"));\n        assertEqualsEnum(bean.getStatus(), descriptor.getProperty(\"status\"));\n        Assertions.assertTrue(((JavaBeanDescriptor) descriptor.getProperty(\"type\")).isClassType());\n        Assertions.assertEquals(\n                Bean.class.getName(), ((JavaBeanDescriptor) descriptor.getProperty(\"type\")).getClassNameProperty());\n        Assertions.assertTrue(((JavaBeanDescriptor) descriptor.getProperty(\"array\")).isArrayType());\n        Assertions.assertEquals(0, ((JavaBeanDescriptor) descriptor.getProperty(\"array\")).propertySize());\n\n        JavaBeanDescriptor property = (JavaBeanDescriptor) descriptor.getProperty(\"collection\");\n        Assertions.assertTrue(property.isCollectionType());\n        Assertions.assertEquals(1, property.propertySize());\n        property = (JavaBeanDescriptor) property.getProperty(0);\n        Assertions.assertTrue(property.isBeanType());\n        Assertions.assertEquals(Phone.class.getName(), property.getClassName());\n        Assertions.assertEquals(0, property.propertySize());\n\n        property = (JavaBeanDescriptor) descriptor.getProperty(\"addresses\");\n        Assertions.assertTrue(property.isMapType());\n        Assertions.assertEquals(bean.getAddresses().getClass().getName(), property.getClassName());\n        Assertions.assertEquals(1, property.propertySize());\n\n        Map.Entry<Object, Object> entry = property.iterator().next();\n        Assertions.assertTrue(((JavaBeanDescriptor) entry.getKey()).isPrimitiveType());\n        Assertions.assertEquals(\"first\", ((JavaBeanDescriptor) entry.getKey()).getPrimitiveProperty());\n\n        Assertions.assertTrue(((JavaBeanDescriptor) entry.getValue()).isBeanType());\n        Assertions.assertEquals(FullAddress.class.getName(), ((JavaBeanDescriptor) entry.getValue()).getClassName());\n        Assertions.assertEquals(0, ((JavaBeanDescriptor) entry.getValue()).propertySize());\n    }\n\n    @Test\n    void testDeserializeBean() {\n        Bean bean = new Bean();\n        bean.setDate(new Date());\n        bean.setStatus(PersonStatus.ENABLED);\n        bean.setType(Bean.class);\n        bean.setArray(new Phone[] {});\n\n        Collection<Phone> collection = new ArrayList<Phone>();\n        bean.setCollection(collection);\n        Phone phone = new Phone();\n        collection.add(phone);\n\n        Map<String, FullAddress> map = new HashMap<String, FullAddress>();\n        FullAddress address = new FullAddress();\n        map.put(\"first\", address);\n        bean.setAddresses(map);\n\n        JavaBeanDescriptor beanDescriptor = JavaBeanSerializeUtil.serialize(bean, JavaBeanAccessor.METHOD);\n        Object deser = JavaBeanSerializeUtil.deserialize(beanDescriptor);\n        Assertions.assertTrue(deser instanceof Bean);\n        Bean deserBean = (Bean) deser;\n        Assertions.assertEquals(bean.getDate(), deserBean.getDate());\n        Assertions.assertEquals(bean.getStatus(), deserBean.getStatus());\n        Assertions.assertEquals(bean.getType(), deserBean.getType());\n        Assertions.assertEquals(\n                bean.getCollection().size(), deserBean.getCollection().size());\n        Assertions.assertEquals(\n                bean.getCollection().iterator().next().getClass(),\n                deserBean.getCollection().iterator().next().getClass());\n        Assertions.assertEquals(\n                bean.getAddresses().size(), deserBean.getAddresses().size());\n        Assertions.assertEquals(\n                bean.getAddresses().entrySet().iterator().next().getKey(),\n                deserBean.getAddresses().entrySet().iterator().next().getKey());\n        Assertions.assertEquals(\n                bean.getAddresses().entrySet().iterator().next().getValue().getClass(),\n                deserBean.getAddresses().entrySet().iterator().next().getValue().getClass());\n    }\n\n    @Test\n    @SuppressWarnings(\"unchecked\")\n    public void testSerializeJavaBeanDescriptor() {\n        JavaBeanDescriptor descriptor = new JavaBeanDescriptor();\n        JavaBeanDescriptor result = JavaBeanSerializeUtil.serialize(descriptor);\n        Assertions.assertSame(descriptor, result);\n\n        Map map = new HashMap();\n        map.put(\"first\", descriptor);\n        result = JavaBeanSerializeUtil.serialize(map);\n        Assertions.assertTrue(result.isMapType());\n        Assertions.assertEquals(HashMap.class.getName(), result.getClassName());\n        Assertions.assertEquals(map.size(), result.propertySize());\n        Object object = result.iterator().next().getValue();\n        Assertions.assertTrue(object instanceof JavaBeanDescriptor);\n        JavaBeanDescriptor actual = (JavaBeanDescriptor) object;\n        Assertions.assertEquals(map.get(\"first\"), actual);\n    }\n\n    static void assertEqualsEnum(Enum<?> expected, Object obj) {\n        JavaBeanDescriptor descriptor = (JavaBeanDescriptor) obj;\n        Assertions.assertTrue(descriptor.isEnumType());\n        Assertions.assertEquals(expected.getClass().getName(), descriptor.getClassName());\n        Assertions.assertEquals(expected.name(), descriptor.getEnumPropertyName());\n    }\n\n    static void assertEqualsPrimitive(Object expected, Object obj) {\n        if (expected == null) {\n            return;\n        }\n        JavaBeanDescriptor descriptor = (JavaBeanDescriptor) obj;\n        Assertions.assertTrue(descriptor.isPrimitiveType());\n        Assertions.assertEquals(expected, descriptor.getPrimitiveProperty());\n    }\n\n    static void assertEqualsBigPerson(BigPerson person, Object obj) {\n        JavaBeanDescriptor descriptor = (JavaBeanDescriptor) obj;\n        Assertions.assertTrue(descriptor.isBeanType());\n        assertEqualsPrimitive(person.getPersonId(), descriptor.getProperty(\"personId\"));\n        assertEqualsPrimitive(person.getLoginName(), descriptor.getProperty(\"loginName\"));\n        assertEqualsEnum(person.getStatus(), descriptor.getProperty(\"status\"));\n        assertEqualsPrimitive(person.getEmail(), descriptor.getProperty(\"email\"));\n        assertEqualsPrimitive(person.getPersonName(), descriptor.getProperty(\"personName\"));\n\n        JavaBeanDescriptor infoProfile = (JavaBeanDescriptor) descriptor.getProperty(\"infoProfile\");\n        Assertions.assertTrue(infoProfile.isBeanType());\n        JavaBeanDescriptor phones = (JavaBeanDescriptor) infoProfile.getProperty(\"phones\");\n        Assertions.assertTrue(phones.isCollectionType());\n        assertEqualsPhone(person.getInfoProfile().getPhones().get(0), phones.getProperty(0));\n        assertEqualsPhone(person.getInfoProfile().getPhones().get(1), phones.getProperty(1));\n        assertEqualsPhone(person.getInfoProfile().getFax(), infoProfile.getProperty(\"fax\"));\n        assertEqualsFullAddress(person.getInfoProfile().getFullAddress(), infoProfile.getProperty(\"fullAddress\"));\n        assertEqualsPrimitive(person.getInfoProfile().getMobileNo(), infoProfile.getProperty(\"mobileNo\"));\n        assertEqualsPrimitive(person.getInfoProfile().getName(), infoProfile.getProperty(\"name\"));\n        assertEqualsPrimitive(person.getInfoProfile().getDepartment(), infoProfile.getProperty(\"department\"));\n        assertEqualsPrimitive(person.getInfoProfile().getJobTitle(), infoProfile.getProperty(\"jobTitle\"));\n        assertEqualsPrimitive(person.getInfoProfile().getHomepageUrl(), infoProfile.getProperty(\"homepageUrl\"));\n        assertEqualsPrimitive(person.getInfoProfile().isFemale(), infoProfile.getProperty(\"female\"));\n        assertEqualsPrimitive(person.getInfoProfile().isMale(), infoProfile.getProperty(\"male\"));\n    }\n\n    static void assertEqualsPhone(Phone expected, Object obj) {\n        JavaBeanDescriptor descriptor = (JavaBeanDescriptor) obj;\n        Assertions.assertTrue(descriptor.isBeanType());\n        if (expected.getArea() != null) {\n            assertEqualsPrimitive(expected.getArea(), descriptor.getProperty(\"area\"));\n        }\n        if (expected.getCountry() != null) {\n            assertEqualsPrimitive(expected.getCountry(), descriptor.getProperty(\"country\"));\n        }\n        if (expected.getExtensionNumber() != null) {\n            assertEqualsPrimitive(expected.getExtensionNumber(), descriptor.getProperty(\"extensionNumber\"));\n        }\n        if (expected.getNumber() != null) {\n            assertEqualsPrimitive(expected.getNumber(), descriptor.getProperty(\"number\"));\n        }\n    }\n\n    static void assertEqualsFullAddress(FullAddress expected, Object obj) {\n        JavaBeanDescriptor descriptor = (JavaBeanDescriptor) obj;\n        Assertions.assertTrue(descriptor.isBeanType());\n        if (expected.getCityId() != null) {\n            assertEqualsPrimitive(expected.getCityId(), descriptor.getProperty(\"cityId\"));\n        }\n        if (expected.getCityName() != null) {\n            assertEqualsPrimitive(expected.getCityName(), descriptor.getProperty(\"cityName\"));\n        }\n        if (expected.getCountryId() != null) {\n            assertEqualsPrimitive(expected.getCountryId(), descriptor.getProperty(\"countryId\"));\n        }\n        if (expected.getCountryName() != null) {\n            assertEqualsPrimitive(expected.getCountryName(), descriptor.getProperty(\"countryName\"));\n        }\n        if (expected.getProvinceName() != null) {\n            assertEqualsPrimitive(expected.getProvinceName(), descriptor.getProperty(\"provinceName\"));\n        }\n        if (expected.getStreetAddress() != null) {\n            assertEqualsPrimitive(expected.getStreetAddress(), descriptor.getProperty(\"streetAddress\"));\n        }\n        if (expected.getZipCode() != null) {\n            assertEqualsPrimitive(expected.getZipCode(), descriptor.getProperty(\"zipCode\"));\n        }\n    }\n\n    static BigPerson createBigPerson() {\n        BigPerson bigPerson;\n        bigPerson = new BigPerson();\n        bigPerson.setPersonId(\"superman111\");\n        bigPerson.setLoginName(\"superman\");\n        bigPerson.setStatus(PersonStatus.ENABLED);\n        bigPerson.setEmail(\"sm@1.com\");\n        bigPerson.setPersonName(\"pname\");\n\n        ArrayList<Phone> phones = new ArrayList<Phone>();\n        Phone phone1 = new Phone(\"86\", \"0571\", \"87654321\", \"001\");\n        Phone phone2 = new Phone(\"86\", \"0571\", \"87654322\", \"002\");\n        phones.add(phone1);\n        phones.add(phone2);\n\n        PersonInfo pi = new PersonInfo();\n        pi.setPhones(phones);\n        Phone fax = new Phone(\"86\", \"0571\", \"87654321\", null);\n        pi.setFax(fax);\n        FullAddress addr = new FullAddress(\"CN\", \"zj\", \"3480\", \"wensanlu\", \"315000\");\n        pi.setFullAddress(addr);\n        pi.setMobileNo(\"13584652131\");\n        pi.setMale(true);\n        pi.setDepartment(\"b2b\");\n        pi.setHomepageUrl(\"www.capcom.com\");\n        pi.setJobTitle(\"qa\");\n        pi.setName(\"superman\");\n\n        bigPerson.setInfoProfile(pi);\n        return bigPerson;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/bytecode/ClassGeneratorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.CountDownLatch;\nimport javassist.ClassPool;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\ninterface Builder<T> {\n    T getName(Bean bean);\n\n    void setName(Bean bean, T name);\n}\n\nclass BaseClass {\n\n    public BaseClass() {}\n\n    public BaseClass(StringBuilder sb) {\n        sb.append(\"constructor comes from BaseClass\");\n    }\n\n    public String baseClassMethod() {\n        return \"method comes from BaseClass\";\n    }\n}\n\ninterface BaseInterface {}\n\nclass ClassGeneratorTest {\n\n    @Test\n    void test() throws Exception {\n        ClassGenerator cg = ClassGenerator.newInstance();\n\n        // add className, interface, superClass\n        String className = BaseClass.class.getPackage().getName() + \".TestClass\"\n                + UUID.randomUUID().toString().replace(\"-\", \"\");\n        cg.setClassName(className);\n        cg.addInterface(BaseInterface.class);\n        cg.setSuperClass(BaseClass.class);\n\n        // add constructor\n        cg.addDefaultConstructor();\n        cg.addConstructor(\n                Modifier.PUBLIC,\n                new Class[] {String.class, int.class},\n                new Class[] {Throwable.class, RuntimeException.class},\n                \"this.strAttr = arg0;this.intAttr = arg1;\");\n        cg.addConstructor(BaseClass.class.getConstructor(StringBuilder.class));\n\n        // add field\n        cg.addField(\n                \"staticAttr\", Modifier.PUBLIC | Modifier.STATIC | Modifier.VOLATILE, String.class, \"\\\"defaultVal\\\"\");\n        cg.addField(\"strAttr\", Modifier.PROTECTED | Modifier.VOLATILE, String.class);\n        cg.addField(\"intAttr\", Modifier.PRIVATE | Modifier.VOLATILE, int.class);\n\n        // add method\n        cg.addMethod(\n                \"setStrAttr\",\n                Modifier.PUBLIC,\n                void.class,\n                new Class[] {String.class, int.class},\n                new Class[] {Throwable.class, RuntimeException.class},\n                \"this.strAttr = arg0;\");\n        cg.addMethod(\n                \"setIntAttr\",\n                Modifier.PUBLIC,\n                void.class,\n                new Class[] {String.class, int.class},\n                new Class[] {Throwable.class, RuntimeException.class},\n                \"this.intAttr = arg1;\");\n        cg.addMethod(\n                \"getStrAttr\",\n                Modifier.PUBLIC,\n                String.class,\n                new Class[] {},\n                new Class[] {Throwable.class, RuntimeException.class},\n                \"return this.strAttr;\");\n        cg.addMethod(\n                \"getIntAttr\",\n                Modifier.PUBLIC,\n                int.class,\n                new Class[] {},\n                new Class[] {Throwable.class, RuntimeException.class},\n                \"return this.intAttr;\");\n        cg.addMethod(BaseClass.class.getMethod(\"baseClassMethod\"));\n\n        // cg.toClass\n        Class<?> clz = cg.toClass(Bean.class);\n        // after cg.toClass, the TestClass.class generated by javassist is like the following file content\n        getClass().getResource(\"/org/apache/dubbo/common/bytecode/TestClass\");\n\n        // verify class, superClass, interfaces\n        Assertions.assertTrue(ClassGenerator.isDynamicClass(clz));\n        Assertions.assertEquals(clz.getName(), className);\n        Assertions.assertEquals(clz.getSuperclass(), BaseClass.class);\n        Assertions.assertArrayEquals(clz.getInterfaces(), new Class[] {ClassGenerator.DC.class, BaseInterface.class});\n\n        // get constructors\n        Constructor<?>[] constructors = clz.getConstructors();\n        Assertions.assertEquals(constructors.length, 3);\n        Constructor<?> constructor0 = clz.getConstructor();\n        Constructor<?> constructor1 = clz.getConstructor(new Class[] {String.class, int.class});\n        Constructor<?> constructor2 = clz.getConstructor(new Class[] {StringBuilder.class});\n        Assertions.assertEquals(constructor1.getModifiers(), Modifier.PUBLIC);\n        Assertions.assertArrayEquals(\n                constructor1.getExceptionTypes(), new Class[] {Throwable.class, RuntimeException.class});\n\n        // get fields\n        Field staticAttrField = clz.getDeclaredField(\"staticAttr\");\n        Field strAttrField = clz.getDeclaredField(\"strAttr\");\n        Field intAttrField = clz.getDeclaredField(\"intAttr\");\n        Assertions.assertNotNull(staticAttrField);\n        Assertions.assertNotNull(strAttrField);\n        Assertions.assertNotNull(intAttrField);\n        Assertions.assertEquals(staticAttrField.get(null), \"defaultVal\");\n\n        // get methods\n        Method setStrAttrMethod = clz.getMethod(\"setStrAttr\", new Class[] {String.class, int.class});\n        Method setIntAttrMethod = clz.getMethod(\"setIntAttr\", new Class[] {String.class, int.class});\n        Method getStrAttrMethod = clz.getMethod(\"getStrAttr\");\n        Method getIntAttrMethod = clz.getMethod(\"getIntAttr\");\n        Method baseClassMethod = clz.getMethod(\"baseClassMethod\");\n        Assertions.assertNotNull(setStrAttrMethod);\n        Assertions.assertNotNull(setIntAttrMethod);\n        Assertions.assertNotNull(getStrAttrMethod);\n        Assertions.assertNotNull(getIntAttrMethod);\n        Assertions.assertNotNull(baseClassMethod);\n\n        // verify constructor0\n        Object objByConstructor0 = constructor0.newInstance();\n        Assertions.assertEquals(getStrAttrMethod.invoke(objByConstructor0), null);\n        Assertions.assertEquals(getIntAttrMethod.invoke(objByConstructor0), 0);\n\n        // verify constructor1\n        Object objByConstructor1 = constructor1.newInstance(\"v1\", 1);\n        Assertions.assertEquals(getStrAttrMethod.invoke(objByConstructor1), \"v1\");\n        Assertions.assertEquals(getIntAttrMethod.invoke(objByConstructor1), 1);\n\n        // verify getter setter method\n        setStrAttrMethod.invoke(objByConstructor0, \"v2\", 2);\n        setIntAttrMethod.invoke(objByConstructor0, \"v3\", 3);\n        Assertions.assertEquals(getStrAttrMethod.invoke(objByConstructor0), \"v2\");\n        Assertions.assertEquals(getIntAttrMethod.invoke(objByConstructor0), 3);\n\n        // verify constructor and method witch comes from baseClass\n        StringBuilder sb = new StringBuilder();\n        Object objByConstructor2 = constructor2.newInstance(sb);\n        Assertions.assertEquals(sb.toString(), \"constructor comes from BaseClass\");\n\n        Object res = baseClassMethod.invoke(objByConstructor2);\n        Assertions.assertEquals(res, \"method comes from BaseClass\");\n\n        cg.release();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void testMain() throws Exception {\n        Bean b = new Bean();\n        Field fname = Bean.class.getDeclaredField(\"name\");\n        fname.setAccessible(true);\n\n        ClassGenerator cg = ClassGenerator.newInstance();\n        cg.setClassName(Bean.class.getName() + \"$Builder\" + UUID.randomUUID().toString());\n        cg.addInterface(Builder.class);\n\n        cg.addField(\"public static java.lang.reflect.Field FNAME;\");\n\n        cg.addMethod(\"public Object getName(\" + Bean.class.getName()\n                + \" o){ boolean[][][] bs = new boolean[0][][]; return (String)FNAME.get($1); }\");\n        cg.addMethod(\"public void setName(\" + Bean.class.getName() + \" o, Object name){ FNAME.set($1, $2); }\");\n\n        cg.addDefaultConstructor();\n        Class<?> cl = cg.toClass(Bean.class);\n        cl.getField(\"FNAME\").set(null, fname);\n\n        Assertions.assertTrue(cl.getName().startsWith(Bean.class.getName() + \"$Builder\"));\n        Builder<String> builder = (Builder<String>) cl.getDeclaredConstructor().newInstance();\n        Assertions.assertEquals(\"qianlei\", b.getName());\n        builder.setName(b, \"ok\");\n        Assertions.assertEquals(\"ok\", b.getName());\n    }\n\n    @Test\n    void testMain0() throws Exception {\n        Bean b = new Bean();\n        Field fname = Bean.class.getDeclaredField(\"name\");\n        fname.setAccessible(true);\n\n        ClassGenerator cg = ClassGenerator.newInstance();\n        cg.setClassName(Bean.class.getName() + \"$Builder2\" + UUID.randomUUID().toString());\n        cg.addInterface(Builder.class);\n\n        cg.addField(\"FNAME\", Modifier.PUBLIC | Modifier.STATIC, java.lang.reflect.Field.class);\n\n        cg.addMethod(\"public Object getName(\" + Bean.class.getName()\n                + \" o){ boolean[][][] bs = new boolean[0][][]; return (String)FNAME.get($1); }\");\n        cg.addMethod(\"public void setName(\" + Bean.class.getName() + \" o, Object name){ FNAME.set($1, $2); }\");\n\n        cg.addDefaultConstructor();\n        Class<?> cl = cg.toClass(Bean.class);\n        cl.getField(\"FNAME\").set(null, fname);\n\n        Assertions.assertTrue(cl.getName().startsWith(Bean.class.getName() + \"$Builder2\"));\n        Builder<String> builder = (Builder<String>) cl.getDeclaredConstructor().newInstance();\n        Assertions.assertEquals(\"qianlei\", b.getName());\n        builder.setName(b, \"ok\");\n        Assertions.assertEquals(\"ok\", b.getName());\n    }\n\n    @Test\n    public void test_getClassPool() throws InterruptedException {\n        int threadCount = 5;\n        CountDownLatch LATCH = new CountDownLatch(threadCount);\n        ClassLoader loader = Thread.currentThread().getContextClassLoader();\n        List<Integer> hashCodeList = new CopyOnWriteArrayList<>();\n        for (int i = 0; i < threadCount; i++) {\n            new Thread(new Runnable() {\n                        @Override\n                        public void run() {\n                            ClassPool classPool = ClassGenerator.getClassPool(loader);\n                            int currentHashCode = classPool.hashCode();\n                            hashCodeList.add(currentHashCode);\n                            LATCH.countDown();\n                        }\n                    })\n                    .start();\n        }\n        LATCH.await();\n        Integer firstHashCode = null;\n        for (Integer currentHashCode : hashCodeList) {\n            if (firstHashCode == null) {\n                firstHashCode = currentHashCode;\n                continue;\n            }\n            Assertions.assertTrue(firstHashCode.intValue() == currentHashCode.intValue());\n        }\n    }\n}\n\nclass Bean {\n    int age = 30;\n\n    private String name = \"qianlei\";\n\n    public int getAge() {\n        return age;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public static volatile String abc = \"df\";\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/bytecode/MixinTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass MixinTest {\n    private static final Logger logger = LoggerFactory.getLogger(MixinTest.class);\n\n    @Test\n    void testMain() {\n        Mixin mixin = Mixin.mixin(new Class[] {I1.class, I2.class, I3.class}, new Class[] {C1.class, C2.class});\n        Object o = mixin.newInstance(new Object[] {new C1(), new C2()});\n        assertTrue(o instanceof I1);\n        assertTrue(o instanceof I2);\n        assertTrue(o instanceof I3);\n        ((I1) o).m1();\n        ((I2) o).m2();\n        ((I3) o).m3();\n    }\n\n    public interface I1 {\n        void m1();\n    }\n\n    public interface I2 {\n        void m2();\n    }\n\n    public interface I3 {\n        void m3();\n    }\n\n    public class C1 implements Mixin.MixinAware {\n        public void m1() {\n            logger.info(\"c1.m1();\");\n        }\n\n        public void m2() {\n            logger.info(\"c1.m2();\");\n        }\n\n        public void setMixinInstance(Object mi) {\n            logger.info(\"c1.setMixinInstance:{}\", mi);\n        }\n    }\n\n    public class C2 implements Mixin.MixinAware {\n        public void m3() {\n            logger.info(\"c2.m3();\");\n        }\n\n        public void setMixinInstance(Object mi) {\n            logger.info(\"c2.setMixinInstance:{}\", mi);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/bytecode/ProxyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\nimport net.sf.cglib.proxy.Enhancer;\nimport net.sf.cglib.proxy.MethodInterceptor;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\n@DisabledForJreRange(min = JRE.JAVA_16)\nclass ProxyTest {\n\n    @Test\n    void testMain() throws Exception {\n        Proxy proxy = Proxy.getProxy(ITest.class, ITest.class);\n        ITest instance = (ITest) proxy.newInstance((proxy1, method, args) -> {\n            if (\"getName\".equals(method.getName())) {\n                assertEquals(args.length, 0);\n            } else if (\"setName\".equals(method.getName())) {\n                assertEquals(args.length, 2);\n                assertEquals(args[0], \"qianlei\");\n                assertEquals(args[1], \"hello\");\n            }\n            return null;\n        });\n\n        assertNull(instance.getName());\n        instance.setName(\"qianlei\", \"hello\");\n    }\n\n    @Test\n    void testCglibProxy() throws Exception {\n        ITest test = (ITest) Proxy.getProxy(ITest.class).newInstance((proxy, method, args) -> {\n            return null;\n        });\n\n        Enhancer enhancer = new Enhancer();\n        enhancer.setSuperclass(test.getClass());\n        enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> null);\n        try {\n            enhancer.create();\n        } catch (IllegalArgumentException e) {\n            e.printStackTrace();\n            Assertions.fail();\n        }\n    }\n\n    public interface ITest {\n        String getName();\n\n        void setName(String name, String name2);\n\n        static String sayBye() {\n            return \"Bye!\";\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/bytecode/WrapperTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.bytecode;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass WrapperTest {\n    private static final Logger logger = LoggerFactory.getLogger(WrapperTest.class);\n\n    @Test\n    void testMain() throws Exception {\n        Wrapper w = Wrapper.getWrapper(I1.class);\n        String[] ns = w.getDeclaredMethodNames();\n        assertEquals(ns.length, 5);\n        ns = w.getMethodNames();\n        assertEquals(ns.length, 6);\n\n        Object obj = new Impl1();\n        assertEquals(w.getPropertyValue(obj, \"name\"), \"you name\");\n\n        w.setPropertyValue(obj, \"name\", \"changed\");\n        assertEquals(w.getPropertyValue(obj, \"name\"), \"changed\");\n\n        w.invokeMethod(obj, \"hello\", new Class<?>[] {String.class}, new Object[] {\"qianlei\"});\n\n        w.setPropertyValues(obj, new String[] {\"name\", \"float\"}, new Object[] {\"mrh\", 1.0f});\n        Object[] propertyValues = w.getPropertyValues(obj, new String[] {\"name\", \"float\"});\n        Assertions.assertEquals(propertyValues.length, 2);\n        Assertions.assertEquals(propertyValues[0], \"mrh\");\n        Assertions.assertEquals(propertyValues[1], 1.0f);\n    }\n\n    // bug: DUBBO-132\n    @Test\n    void test_unwantedArgument() throws Exception {\n        Wrapper w = Wrapper.getWrapper(I1.class);\n        Object obj = new Impl1();\n        try {\n            w.invokeMethod(\n                    obj, \"hello\", new Class<?>[] {String.class, String.class}, new Object[] {\"qianlei\", \"badboy\"});\n            fail();\n        } catch (NoSuchMethodException expected) {\n        }\n    }\n\n    // bug: DUBBO-425\n    @Test\n    void test_makeEmptyClass() throws Exception {\n        Wrapper.getWrapper(EmptyServiceImpl.class);\n    }\n\n    @Test\n    void testHasMethod() throws Exception {\n        Wrapper w = Wrapper.getWrapper(I1.class);\n        Assertions.assertTrue(w.hasMethod(\"setName\"));\n        Assertions.assertTrue(w.hasMethod(\"hello\"));\n        Assertions.assertTrue(w.hasMethod(\"showInt\"));\n        Assertions.assertTrue(w.hasMethod(\"getFloat\"));\n        Assertions.assertTrue(w.hasMethod(\"setFloat\"));\n        Assertions.assertFalse(w.hasMethod(\"setFloatXXX\"));\n    }\n\n    @Test\n    void testWrapperObject() throws Exception {\n        Wrapper w = Wrapper.getWrapper(Object.class);\n        Assertions.assertEquals(4, w.getMethodNames().length);\n        Assertions.assertEquals(4, w.getDeclaredMethodNames().length);\n        Assertions.assertEquals(0, w.getPropertyNames().length);\n        Assertions.assertNull(w.getPropertyType(null));\n        Assertions.assertFalse(w.hasProperty(null));\n    }\n\n    @Test\n    void testGetPropertyValue() throws Exception {\n        Assertions.assertThrows(NoSuchPropertyException.class, () -> {\n            Wrapper w = Wrapper.getWrapper(Object.class);\n            w.getPropertyValue(null, null);\n        });\n    }\n\n    @Test\n    void testSetPropertyValue() throws Exception {\n        Assertions.assertThrows(NoSuchPropertyException.class, () -> {\n            Wrapper w = Wrapper.getWrapper(Object.class);\n            w.setPropertyValue(null, null, null);\n        });\n    }\n\n    @Test\n    void testWrapPrimitive() throws Exception {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            Wrapper.getWrapper(Byte.TYPE);\n        });\n    }\n\n    @Test\n    void testInvokeWrapperObject() throws Exception {\n        Wrapper w = Wrapper.getWrapper(Object.class);\n        Object instance = new Object();\n        Assertions.assertEquals(instance.getClass(), w.invokeMethod(instance, \"getClass\", null, null));\n        Assertions.assertEquals(instance.hashCode(), (int) w.invokeMethod(instance, \"hashCode\", null, null));\n        Assertions.assertEquals(instance.toString(), w.invokeMethod(instance, \"toString\", null, null));\n        Assertions.assertTrue((boolean)\n                w.invokeMethod(instance, \"equals\", new Class[] {instance.getClass()}, new Object[] {instance}));\n        Assertions.assertThrows(\n                IllegalArgumentException.class,\n                () -> w.invokeMethod(\n                        instance, \"equals\", new Class[] {instance.getClass()}, new Object[] {instance, instance}));\n    }\n\n    @Test\n    void testNoSuchMethod() throws Exception {\n        Assertions.assertThrows(NoSuchMethodException.class, () -> {\n            Wrapper w = Wrapper.getWrapper(Object.class);\n            w.invokeMethod(new Object(), \"__XX__\", null, null);\n        });\n    }\n\n    @Test\n    void testOverloadMethod() throws Exception {\n        Wrapper w = Wrapper.getWrapper(I2.class);\n        assertEquals(2, w.getMethodNames().length);\n\n        Impl2 impl = new Impl2();\n\n        w.invokeMethod(impl, \"setFloat\", new Class[] {float.class}, new Object[] {1F});\n        assertEquals(1F, impl.getFloat1());\n        assertNull(impl.getFloat2());\n\n        w.invokeMethod(impl, \"setFloat\", new Class[] {Float.class}, new Object[] {2f});\n        assertEquals(1F, impl.getFloat1());\n        assertEquals(2F, impl.getFloat2());\n\n        w.invokeMethod(impl, \"setFloat\", new Class[] {Float.class}, new Object[] {null});\n        assertEquals(1F, impl.getFloat1());\n        assertNull(impl.getFloat2());\n    }\n\n    @Test\n    void test_getDeclaredMethodNames_ContainExtendsParentMethods() throws Exception {\n        assertArrayEquals(\n                new String[] {\n                    \"hello\",\n                },\n                Wrapper.getWrapper(Parent1.class).getMethodNames());\n        assertArrayEquals(\n                new String[] {\n                    \"hello\",\n                },\n                ClassUtils.getMethodNames(Parent1.class));\n\n        assertArrayEquals(new String[] {}, Wrapper.getWrapper(Son.class).getDeclaredMethodNames());\n        assertArrayEquals(new String[] {}, ClassUtils.getDeclaredMethodNames(Son.class));\n    }\n\n    @Test\n    void test_getMethodNames_ContainExtendsParentMethods() throws Exception {\n        String[] methodNamesFromWrapepr = Wrapper.getWrapper(Son.class).getMethodNames();\n        String[] methodNamesFromClassUtils = ClassUtils.getMethodNames(Son.class);\n\n        Arrays.sort(methodNamesFromWrapepr);\n        Arrays.sort(methodNamesFromClassUtils);\n\n        assertArrayEquals(new String[] {\"hello\", \"world\"}, methodNamesFromWrapepr);\n        assertArrayEquals(new String[] {\"hello\", \"world\"}, methodNamesFromClassUtils);\n    }\n\n    @Test\n    void testWrapImplClass() {\n        Wrapper w = Wrapper.getWrapper(Impl0.class);\n\n        String[] propertyNames = w.getPropertyNames();\n        Assertions.assertArrayEquals(propertyNames, new String[] {\"a\", \"b\", \"c\"});\n        // fields that do not contain the static|final|transient modifier\n        Assertions.assertFalse(w.hasProperty(\"f\"));\n        Assertions.assertFalse(w.hasProperty(\"l\"));\n        Assertions.assertFalse(w.hasProperty(\"ch\"));\n\n        // only has public methods, do not contain the private or comes from object methods\n        Assertions.assertTrue(w.hasMethod(\"publicMethod\"));\n        Assertions.assertFalse(w.hasMethod(\"privateMethod\"));\n        Assertions.assertFalse(w.hasMethod(\"hashcode\"));\n    }\n\n    public interface I0 {\n        String getName();\n    }\n\n    public interface I1 extends I0 {\n        void setName(String name);\n\n        void hello(String name);\n\n        int showInt(int v);\n\n        float getFloat();\n\n        void setFloat(float f);\n    }\n\n    public interface I2 {\n        void setFloat(float f);\n\n        void setFloat(Float f);\n    }\n\n    public interface EmptyService {}\n\n    public interface Parent1 {\n        void hello();\n    }\n\n    public interface Parent2 {\n        void world();\n    }\n\n    public interface Son extends Parent1, Parent2 {}\n\n    public static class Impl0 {\n        public float a, b, c;\n        public transient boolean f;\n        public static long l = 1;\n        public final char ch = 'c';\n\n        private void privateMethod() {}\n\n        public void publicMethod() {}\n    }\n\n    public static class Impl1 implements I1 {\n        private String name = \"you name\";\n\n        private float fv = 0;\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public void hello(String name) {\n            logger.info(\"hello {}\", name);\n        }\n\n        public int showInt(int v) {\n            return v;\n        }\n\n        public float getFloat() {\n            return fv;\n        }\n\n        public void setFloat(float f) {\n            fv = f;\n        }\n    }\n\n    public static class Impl2 implements I2 {\n        private float float1;\n        private Float float2;\n\n        @Override\n        public void setFloat(float f) {\n            this.float1 = f;\n        }\n\n        @Override\n        public void setFloat(Float f) {\n            this.float2 = f;\n        }\n\n        public float getFloat1() {\n            return float1;\n        }\n\n        public Float getFloat2() {\n            return float2;\n        }\n    }\n\n    public static class EmptyServiceImpl implements EmptyService {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/cache/FileCacheStoreFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.cache;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.reflect.Field;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.file.Paths;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass FileCacheStoreFactoryTest {\n\n    @Test\n    void testSafeName() throws URISyntaxException {\n        FileCacheStore store1 = FileCacheStoreFactory.getInstance(getDirectoryOfClassPath(), \"../../../dubbo\");\n        Assertions.assertEquals(\n                getDirectoryOfClassPath() + \"..%002f..%002f..%002fdubbo.dubbo.cache\", getCacheFilePath(store1));\n        store1.destroy();\n\n        FileCacheStore store2 = FileCacheStoreFactory.getInstance(getDirectoryOfClassPath(), \"../../../中文\");\n        Assertions.assertEquals(\n                getDirectoryOfClassPath() + \"..%002f..%002f..%002f%4e2d%6587.dubbo.cache\", getCacheFilePath(store2));\n        store2.destroy();\n    }\n\n    @Test\n    void testPathIsFile() throws URISyntaxException, IOException {\n        String basePath = getDirectoryOfClassPath();\n        String filePath = basePath + File.separator + \"isFile\";\n        new File(filePath).createNewFile();\n\n        Assertions.assertThrows(RuntimeException.class, () -> FileCacheStoreFactory.getInstance(filePath, \"dubbo\"));\n    }\n\n    @Test\n    void testCacheContains() throws URISyntaxException {\n        String classPath = getDirectoryOfClassPath();\n\n        FileCacheStore store1 = FileCacheStoreFactory.getInstance(classPath, \"testCacheContains\");\n        Assertions.assertNotNull(getCacheFilePath(store1));\n\n        getCacheMap().remove(getCacheFilePath(store1));\n        FileCacheStore store2 = FileCacheStoreFactory.getInstance(classPath, \"testCacheContains\");\n        Assertions.assertEquals(FileCacheStore.Empty.class, store2.getClass());\n\n        store1.destroy();\n        store2.destroy();\n\n        FileCacheStore store3 = FileCacheStoreFactory.getInstance(classPath, \"testCacheContains\");\n        Assertions.assertNotNull(getCacheFilePath(store3));\n        store3.destroy();\n    }\n\n    private String getDirectoryOfClassPath() throws URISyntaxException {\n        URL resource = this.getClass().getResource(\"/log4j2-test.xml\");\n        String path = Paths.get(resource.toURI()).toFile().getAbsolutePath();\n        int index = path.indexOf(\"log4j2-test.xml\");\n        String directoryPath = path.substring(0, index);\n        return directoryPath;\n    }\n\n    private static class ReflectFieldCache {\n        Field cacheMapField;\n\n        Field cacheFilePathField;\n    }\n\n    private static final ReflectFieldCache REFLECT_FIELD_CACHE = new ReflectFieldCache();\n\n    private Map<String, FileCacheStore> getCacheMap() {\n\n        try {\n            if (REFLECT_FIELD_CACHE.cacheMapField == null) {\n                REFLECT_FIELD_CACHE.cacheMapField = FileCacheStoreFactory.class.getDeclaredField(\"cacheMap\");\n                REFLECT_FIELD_CACHE.cacheMapField.setAccessible(true);\n            }\n\n            return (Map<String, FileCacheStore>) REFLECT_FIELD_CACHE.cacheMapField.get(null);\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n    }\n\n    private String getCacheFilePath(FileCacheStore cacheStore) {\n        try {\n            if (REFLECT_FIELD_CACHE.cacheFilePathField == null) {\n                REFLECT_FIELD_CACHE.cacheFilePathField = FileCacheStore.class.getDeclaredField(\"cacheFilePath\");\n                REFLECT_FIELD_CACHE.cacheFilePathField.setAccessible(true);\n            }\n\n            return (String) REFLECT_FIELD_CACHE.cacheFilePathField.get(cacheStore);\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/cache/FileCacheStoreTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.cache;\n\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.file.Paths;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass FileCacheStoreTest {\n    private FileCacheStore cacheStore;\n\n    @Test\n    void testCache() throws Exception {\n        String directoryPath = getDirectoryOfClassPath();\n        String filePath = \"test-cache.dubbo.cache\";\n        cacheStore = FileCacheStoreFactory.getInstance(directoryPath, filePath);\n        Map<String, String> properties = cacheStore.loadCache(10);\n        assertEquals(2, properties.size());\n\n        Map<String, String> newProperties = new HashMap<>();\n        newProperties.put(\"newKey1\", \"newValue1\");\n        newProperties.put(\"newKey2\", \"newValue2\");\n        newProperties.put(\"newKey3\", \"newValue3\");\n        newProperties.put(\"newKey4\", \"newValue4\");\n        cacheStore = FileCacheStoreFactory.getInstance(directoryPath, \"non-exit.dubbo.cache\");\n        cacheStore.refreshCache(newProperties, \"test refresh cache\", 0);\n        Map<String, String> propertiesLimitTo2 = cacheStore.loadCache(2);\n        assertEquals(2, propertiesLimitTo2.size());\n\n        Map<String, String> propertiesLimitTo10 = cacheStore.loadCache(10);\n        assertEquals(4, propertiesLimitTo10.size());\n\n        cacheStore.destroy();\n    }\n\n    @Test\n    void testFileSizeExceed() throws Exception {\n        String directoryPath = getDirectoryOfClassPath();\n        Map<String, String> newProperties = new HashMap<>();\n        newProperties.put(\"newKey1\", \"newValue1\");\n        newProperties.put(\"newKey2\", \"newValue2\");\n        newProperties.put(\"newKey3\", \"newValue3\");\n        newProperties.put(\"newKey4\", \"newValue4\");\n        cacheStore = FileCacheStoreFactory.getInstance(directoryPath, \"non-exit.dubbo.cache\");\n        cacheStore.refreshCache(newProperties, \"test refresh cache\", 2);\n        Map<String, String> propertiesLimitTo1 = cacheStore.loadCache(2);\n        assertEquals(0, propertiesLimitTo1.size());\n    }\n\n    private String getDirectoryOfClassPath() throws URISyntaxException {\n        URL resource = this.getClass().getResource(\"/log4j2-test.xml\");\n        String path = Paths.get(resource.toURI()).toFile().getAbsolutePath();\n        int index = path.indexOf(\"log4j2-test.xml\");\n        String directoryPath = path.substring(0, index);\n        return directoryPath;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/AdaptiveCompilerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass AdaptiveCompilerTest extends JavaCodeTest {\n\n    @Test\n    void testAvailableCompiler() throws Exception {\n        AdaptiveCompiler.setDefaultCompiler(\"jdk\");\n        AdaptiveCompiler compiler = new AdaptiveCompiler();\n        compiler.setFrameworkModel(FrameworkModel.defaultModel());\n        Class<?> clazz = compiler.compile(JavaCodeTest.class, getSimpleCode(), AdaptiveCompiler.class.getClassLoader());\n        HelloService helloService =\n                (HelloService) clazz.getDeclaredConstructor().newInstance();\n        Assertions.assertEquals(\"Hello world!\", helloService.sayHello());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/ClassUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ClassUtilsTest {\n\n    @Test\n    void testNewInstance() {\n        HelloServiceImpl0 instance = (HelloServiceImpl0) ClassUtils.newInstance(HelloServiceImpl0.class.getName());\n        Assertions.assertEquals(\"Hello world!\", instance.sayHello());\n    }\n\n    @Test\n    void testNewInstance0() {\n        Assertions.assertThrows(\n                IllegalStateException.class, () -> ClassUtils.newInstance(PrivateHelloServiceImpl.class.getName()));\n    }\n\n    @Test\n    void testNewInstance1() {\n        Assertions.assertThrows(\n                IllegalStateException.class,\n                () -> ClassUtils.newInstance(\n                        \"org.apache.dubbo.common.compiler.support.internal.HelloServiceInternalImpl\"));\n    }\n\n    @Test\n    void testNewInstance2() {\n        Assertions.assertThrows(\n                IllegalStateException.class,\n                () -> ClassUtils.newInstance(\"org.apache.dubbo.common.compiler.support.internal.NotExistsImpl\"));\n    }\n\n    @Test\n    void testForName() {\n        ClassUtils.forName(new String[] {\"org.apache.dubbo.common.compiler.support\"}, \"HelloServiceImpl0\");\n    }\n\n    @Test\n    void testForName1() {\n        Assertions.assertThrows(\n                IllegalStateException.class,\n                () -> ClassUtils.forName(\n                        new String[] {\"org.apache.dubbo.common.compiler.support\"}, \"HelloServiceImplXX\"));\n    }\n\n    @Test\n    void testForName2() {\n        Assertions.assertEquals(boolean.class, ClassUtils.forName(\"boolean\"));\n        Assertions.assertEquals(byte.class, ClassUtils.forName(\"byte\"));\n        Assertions.assertEquals(char.class, ClassUtils.forName(\"char\"));\n        Assertions.assertEquals(short.class, ClassUtils.forName(\"short\"));\n        Assertions.assertEquals(int.class, ClassUtils.forName(\"int\"));\n        Assertions.assertEquals(long.class, ClassUtils.forName(\"long\"));\n        Assertions.assertEquals(float.class, ClassUtils.forName(\"float\"));\n        Assertions.assertEquals(double.class, ClassUtils.forName(\"double\"));\n        Assertions.assertEquals(boolean[].class, ClassUtils.forName(\"boolean[]\"));\n        Assertions.assertEquals(byte[].class, ClassUtils.forName(\"byte[]\"));\n        Assertions.assertEquals(char[].class, ClassUtils.forName(\"char[]\"));\n        Assertions.assertEquals(short[].class, ClassUtils.forName(\"short[]\"));\n        Assertions.assertEquals(int[].class, ClassUtils.forName(\"int[]\"));\n        Assertions.assertEquals(long[].class, ClassUtils.forName(\"long[]\"));\n        Assertions.assertEquals(float[].class, ClassUtils.forName(\"float[]\"));\n        Assertions.assertEquals(double[].class, ClassUtils.forName(\"double[]\"));\n    }\n\n    @Test\n    void testGetBoxedClass() {\n        Assertions.assertEquals(Boolean.class, ClassUtils.getBoxedClass(boolean.class));\n        Assertions.assertEquals(Character.class, ClassUtils.getBoxedClass(char.class));\n        Assertions.assertEquals(Byte.class, ClassUtils.getBoxedClass(byte.class));\n        Assertions.assertEquals(Short.class, ClassUtils.getBoxedClass(short.class));\n        Assertions.assertEquals(Integer.class, ClassUtils.getBoxedClass(int.class));\n        Assertions.assertEquals(Long.class, ClassUtils.getBoxedClass(long.class));\n        Assertions.assertEquals(Float.class, ClassUtils.getBoxedClass(float.class));\n        Assertions.assertEquals(Double.class, ClassUtils.getBoxedClass(double.class));\n        Assertions.assertEquals(ClassUtilsTest.class, ClassUtils.getBoxedClass(ClassUtilsTest.class));\n    }\n\n    @Test\n    void testBoxedAndUnboxed() {\n        Assertions.assertEquals(Boolean.valueOf(true), ClassUtils.boxed(true));\n        Assertions.assertEquals(Character.valueOf('0'), ClassUtils.boxed('0'));\n        Assertions.assertEquals(Byte.valueOf((byte) 0), ClassUtils.boxed((byte) 0));\n        Assertions.assertEquals(Short.valueOf((short) 0), ClassUtils.boxed((short) 0));\n        Assertions.assertEquals(Integer.valueOf((int) 0), ClassUtils.boxed((int) 0));\n        Assertions.assertEquals(Long.valueOf((long) 0), ClassUtils.boxed((long) 0));\n        Assertions.assertEquals(Float.valueOf((float) 0), ClassUtils.boxed((float) 0));\n        Assertions.assertEquals(Double.valueOf((double) 0), ClassUtils.boxed((double) 0));\n\n        Assertions.assertTrue(ClassUtils.unboxed(Boolean.valueOf(true)));\n        Assertions.assertEquals('0', ClassUtils.unboxed(Character.valueOf('0')));\n        Assertions.assertEquals((byte) 0, ClassUtils.unboxed(Byte.valueOf((byte) 0)));\n        Assertions.assertEquals((short) 0, ClassUtils.unboxed(Short.valueOf((short) 0)));\n        Assertions.assertEquals(0, ClassUtils.unboxed(Integer.valueOf((int) 0)));\n        Assertions.assertEquals((long) 0, ClassUtils.unboxed(Long.valueOf((long) 0)));\n        //        Assertions.assertEquals((float) 0, ClassUtils.unboxed(Float.valueOf((float) 0)), ((float) 0));\n        //        Assertions.assertEquals((double) 0, ClassUtils.unboxed(Double.valueOf((double) 0)), ((double) 0));\n    }\n\n    @Test\n    void testGetSize() {\n        Assertions.assertEquals(0, ClassUtils.getSize(null));\n        List<Integer> list = new ArrayList<>();\n        list.add(1);\n        Assertions.assertEquals(1, ClassUtils.getSize(list));\n        Map map = new HashMap();\n        map.put(1, 1);\n        Assertions.assertEquals(1, ClassUtils.getSize(map));\n        int[] array = new int[1];\n        Assertions.assertEquals(1, ClassUtils.getSize(array));\n        Assertions.assertEquals(-1, ClassUtils.getSize(new Object()));\n    }\n\n    @Test\n    void testToUri() {\n        Assertions.assertThrows(RuntimeException.class, () -> ClassUtils.toURI(\"#xx_abc#hello\"));\n    }\n\n    @Test\n    void testGetSizeMethod() {\n        Assertions.assertEquals(\"getLength()\", ClassUtils.getSizeMethod(GenericClass3.class));\n    }\n\n    @Test\n    void testGetSimpleClassName() {\n        Assertions.assertNull(ClassUtils.getSimpleClassName(null));\n        Assertions.assertEquals(\"Map\", ClassUtils.getSimpleClassName(Map.class.getName()));\n        Assertions.assertEquals(\"Map\", ClassUtils.getSimpleClassName(Map.class.getSimpleName()));\n    }\n\n    private interface GenericInterface<T> {}\n\n    private class GenericClass<T> implements GenericInterface<T> {}\n\n    private class GenericClass0 implements GenericInterface<String> {}\n\n    private class GenericClass1 implements GenericInterface<Collection<String>> {}\n\n    private class GenericClass2<T> implements GenericInterface<T[]> {}\n\n    private class GenericClass3<T> implements GenericInterface<T[][]> {\n        public int getLength() {\n            return -1;\n        }\n    }\n\n    private class PrivateHelloServiceImpl implements HelloService {\n        private PrivateHelloServiceImpl() {}\n\n        @Override\n        public String sayHello() {\n            return \"Hello world!\";\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/HelloService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\npublic interface HelloService {\n\n    String sayHello();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/HelloServiceImpl0.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\npublic class HelloServiceImpl0 implements HelloService {\n    @Override\n    public String sayHello() {\n        return \"Hello world!\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/JavaCodeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nclass JavaCodeTest {\n\n    public static final AtomicInteger SUBFIX = new AtomicInteger(8);\n\n    boolean shouldIgnoreWithoutPackage() {\n        String jdkVersion = System.getProperty(\"java.specification.version\");\n        try {\n            return Integer.parseInt(jdkVersion) > 15;\n        } catch (Throwable t) {\n            return false;\n        }\n    }\n\n    String getSimpleCode() {\n        StringBuilder code = new StringBuilder();\n        code.append(\"package org.apache.dubbo.common.compiler.support;\");\n\n        code.append(\"public class HelloServiceImpl\" + SUBFIX.getAndIncrement() + \" implements HelloService {\");\n        code.append(\"   public String sayHello() { \");\n        code.append(\"       return \\\"Hello world!\\\"; \");\n        code.append(\"   }\");\n        code.append('}');\n        return code.toString();\n    }\n\n    String getSimpleCodeWithoutPackage() {\n        StringBuilder code = new StringBuilder();\n        code.append(\"public class HelloServiceImpl\" + SUBFIX.getAndIncrement()\n                + \"implements org.apache.dubbo.common.compiler.support.HelloService.HelloService {\");\n        code.append(\"   public String sayHello() { \");\n        code.append(\"       return \\\"Hello world!\\\"; \");\n        code.append(\"   }\");\n        code.append('}');\n        return code.toString();\n    }\n\n    String getSimpleCodeWithSyntax() {\n        StringBuilder code = new StringBuilder();\n        code.append(\"package org.apache.dubbo.common.compiler.support;\");\n\n        code.append(\"public class HelloServiceImpl\" + SUBFIX.getAndIncrement() + \" implements HelloService {\");\n        code.append(\"   public String sayHello() { \");\n        code.append(\"       return \\\"Hello world!\\\"; \");\n        // code.append(\"   }\");\n        // }\n        return code.toString();\n    }\n\n    // only used for javassist\n    String getSimpleCodeWithSyntax0() {\n        StringBuilder code = new StringBuilder();\n        code.append(\"package org.apache.dubbo.common.compiler.support;\");\n\n        code.append(\"public class HelloServiceImpl_0 implements HelloService {\");\n        code.append(\"   public String sayHello() { \");\n        code.append(\"       return \\\"Hello world!\\\"; \");\n        // code.append(\"   }\");\n        // }\n        return code.toString();\n    }\n\n    String getSimpleCodeWithImports() {\n        StringBuilder code = new StringBuilder();\n        code.append(\"package org.apache.dubbo.common.compiler.support;\");\n\n        code.append(\"import java.lang.*;\\n\");\n        code.append(\"import org.apache.dubbo.common.compiler.support;\\n\");\n\n        code.append(\"public class HelloServiceImpl2\" + SUBFIX.getAndIncrement() + \" implements HelloService {\");\n        code.append(\"   public String sayHello() { \");\n        code.append(\"       return \\\"Hello world!\\\"; \");\n        code.append(\"   }\");\n        code.append('}');\n        return code.toString();\n    }\n\n    String getSimpleCodeWithWithExtends() {\n        StringBuilder code = new StringBuilder();\n        code.append(\"package org.apache.dubbo.common.compiler.support;\");\n\n        code.append(\"import java.lang.*;\\n\");\n        code.append(\"import org.apache.dubbo.common.compiler.support;\\n\");\n\n        code.append(\"public class HelloServiceImpl\" + SUBFIX.getAndIncrement()\n                + \" extends org.apache.dubbo.common.compiler.support.HelloServiceImpl0 {\\n\");\n        code.append(\"   public String sayHello() { \");\n        code.append(\"       return \\\"Hello world3!\\\"; \");\n        code.append(\"   }\");\n        code.append('}');\n        return code.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/JavassistCompilerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nclass JavassistCompilerTest extends JavaCodeTest {\n    @Test\n    void testCompileJavaClass() throws Exception {\n        JavassistCompiler compiler = new JavassistCompiler();\n        Class<?> clazz =\n                compiler.compile(JavaCodeTest.class, getSimpleCode(), JavassistCompiler.class.getClassLoader());\n\n        // Because javassist compiles using the caller class loader, we shouldn't use HelloService directly\n        Object instance = clazz.getDeclaredConstructor().newInstance();\n        Method sayHello = instance.getClass().getMethod(\"sayHello\");\n        Assertions.assertEquals(\"Hello world!\", sayHello.invoke(instance));\n    }\n\n    /**\n     * javassist compile will find HelloService in classpath\n     */\n    @Test\n    @DisabledForJreRange(min = JRE.JAVA_16)\n    public void testCompileJavaClass0() throws Exception {\n        boolean ignoreWithoutPackage = shouldIgnoreWithoutPackage();\n        JavassistCompiler compiler = new JavassistCompiler();\n\n        if (ignoreWithoutPackage) {\n            Assertions.assertThrows(\n                    RuntimeException.class,\n                    () -> compiler.compile(\n                            null, getSimpleCodeWithoutPackage(), JavassistCompiler.class.getClassLoader()));\n        } else {\n            Class<?> clazz =\n                    compiler.compile(null, getSimpleCodeWithoutPackage(), JavassistCompiler.class.getClassLoader());\n            Object instance = clazz.getDeclaredConstructor().newInstance();\n            Method sayHello = instance.getClass().getMethod(\"sayHello\");\n            Assertions.assertEquals(\"Hello world!\", sayHello.invoke(instance));\n        }\n    }\n\n    @Test\n    void testCompileJavaClass1() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JavassistCompiler compiler = new JavassistCompiler();\n            Class<?> clazz = compiler.compile(\n                    JavaCodeTest.class, getSimpleCodeWithSyntax0(), JavassistCompiler.class.getClassLoader());\n            Object instance = clazz.getDeclaredConstructor().newInstance();\n            Method sayHello = instance.getClass().getMethod(\"sayHello\");\n            Assertions.assertEquals(\"Hello world!\", sayHello.invoke(instance));\n        });\n    }\n\n    @Test\n    void testCompileJavaClassWithImport() throws Exception {\n        JavassistCompiler compiler = new JavassistCompiler();\n        Class<?> clazz = compiler.compile(\n                JavaCodeTest.class, getSimpleCodeWithImports(), JavassistCompiler.class.getClassLoader());\n        Object instance = clazz.getDeclaredConstructor().newInstance();\n        Method sayHello = instance.getClass().getMethod(\"sayHello\");\n        Assertions.assertEquals(\"Hello world!\", sayHello.invoke(instance));\n    }\n\n    @Test\n    void testCompileJavaClassWithExtends() throws Exception {\n        JavassistCompiler compiler = new JavassistCompiler();\n        Class<?> clazz = compiler.compile(\n                JavaCodeTest.class, getSimpleCodeWithWithExtends(), JavassistCompiler.class.getClassLoader());\n        Object instance = clazz.getDeclaredConstructor().newInstance();\n        Method sayHello = instance.getClass().getMethod(\"sayHello\");\n        Assertions.assertEquals(\"Hello world3!\", sayHello.invoke(instance));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/JdkCompilerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support;\n\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass JdkCompilerTest extends JavaCodeTest {\n\n    @Test\n    void test_compileJavaClass() throws Exception {\n        JdkCompiler compiler = new JdkCompiler();\n        Class<?> clazz = compiler.compile(JavaCodeTest.class, getSimpleCode(), JdkCompiler.class.getClassLoader());\n        Object instance = clazz.getDeclaredConstructor().newInstance();\n        Method sayHello = instance.getClass().getMethod(\"sayHello\");\n        Assertions.assertEquals(\"Hello world!\", sayHello.invoke(instance));\n    }\n\n    @Test\n    void test_compileJavaClass0() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JdkCompiler compiler = new JdkCompiler();\n            Class<?> clazz = compiler.compile(\n                    JavaCodeTest.class, getSimpleCodeWithoutPackage(), JdkCompiler.class.getClassLoader());\n            Object instance = clazz.getDeclaredConstructor().newInstance();\n            Method sayHello = instance.getClass().getMethod(\"sayHello\");\n            Assertions.assertEquals(\"Hello world!\", sayHello.invoke(instance));\n        });\n    }\n\n    @Test\n    void test_compileJavaClass1() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JdkCompiler compiler = new JdkCompiler();\n            Class<?> clazz =\n                    compiler.compile(JavaCodeTest.class, getSimpleCodeWithSyntax(), JdkCompiler.class.getClassLoader());\n            Object instance = clazz.getDeclaredConstructor().newInstance();\n            Method sayHello = instance.getClass().getMethod(\"sayHello\");\n            Assertions.assertEquals(\"Hello world!\", sayHello.invoke(instance));\n        });\n    }\n\n    @Test\n    void test_compileJavaClass_java8() throws Exception {\n        JdkCompiler compiler = new JdkCompiler(\"1.8\");\n        Class<?> clazz = compiler.compile(JavaCodeTest.class, getSimpleCode(), JdkCompiler.class.getClassLoader());\n        Object instance = clazz.getDeclaredConstructor().newInstance();\n        Method sayHello = instance.getClass().getMethod(\"sayHello\");\n        Assertions.assertEquals(\"Hello world!\", sayHello.invoke(instance));\n    }\n\n    @Test\n    void test_compileJavaClass0_java8() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JdkCompiler compiler = new JdkCompiler(\"1.8\");\n            Class<?> clazz = compiler.compile(\n                    JavaCodeTest.class, getSimpleCodeWithoutPackage(), JdkCompiler.class.getClassLoader());\n            Object instance = clazz.getDeclaredConstructor().newInstance();\n            Method sayHello = instance.getClass().getMethod(\"sayHello\");\n            Assertions.assertEquals(\"Hello world!\", sayHello.invoke(instance));\n        });\n    }\n\n    @Test\n    void test_compileJavaClass1_java8() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            JdkCompiler compiler = new JdkCompiler(\"1.8\");\n            Class<?> clazz =\n                    compiler.compile(JavaCodeTest.class, getSimpleCodeWithSyntax(), JdkCompiler.class.getClassLoader());\n            Object instance = clazz.getDeclaredConstructor().newInstance();\n            Method sayHello = instance.getClass().getMethod(\"sayHello\");\n            Assertions.assertEquals(\"Hello world!\", sayHello.invoke(instance));\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/internal/HelloServiceInternalImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.compiler.support.internal;\n\nfinal class HelloServiceInternalImpl {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/concurrent/CompletableFutureTaskTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.concurrent;\n\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nclass CompletableFutureTaskTest {\n\n    private static final ExecutorService executor = new ThreadPoolExecutor(\n            0,\n            10,\n            60L,\n            TimeUnit.SECONDS,\n            new SynchronousQueue<Runnable>(),\n            new NamedThreadFactory(\"DubboMonitorCreator\", true));\n\n    @Test\n    void testCreate() throws InterruptedException {\n\n        final CountDownLatch countDownLatch = new CountDownLatch(1);\n        CompletableFuture<Boolean> completableFuture = CompletableFuture.supplyAsync(\n                () -> {\n                    countDownLatch.countDown();\n                    return true;\n                },\n                executor);\n        countDownLatch.await();\n    }\n\n    @Test\n    void testRunnableResponse() throws ExecutionException, InterruptedException {\n        CountDownLatch latch = new CountDownLatch(1);\n        CompletableFuture<Boolean> completableFuture = CompletableFuture.supplyAsync(\n                () -> {\n                    try {\n                        latch.await();\n                    } catch (InterruptedException e) {\n                        throw new RuntimeException(e);\n                    }\n                    return true;\n                },\n                executor);\n        Assertions.assertNull(completableFuture.getNow(null));\n        latch.countDown();\n        Boolean result = completableFuture.get();\n        assertThat(result, is(true));\n    }\n\n    @Test\n    void testListener() throws InterruptedException {\n        AtomicBoolean run = new AtomicBoolean(false);\n        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(\n                () -> {\n                    run.set(true);\n                    return \"hello\";\n                },\n                executor);\n        final CountDownLatch countDownLatch = new CountDownLatch(1);\n        completableFuture.thenRunAsync(countDownLatch::countDown);\n        countDownLatch.await();\n        Assertions.assertTrue(run.get());\n    }\n\n    @Test\n    void testCustomExecutor() {\n        Executor mockedExecutor = mock(Executor.class);\n        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {\n            return 0;\n        });\n        completableFuture\n                .thenRunAsync(mock(Runnable.class), mockedExecutor)\n                .whenComplete((s, e) -> verify(mockedExecutor, times(1)).execute(any(Runnable.class)));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/CompositeConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link CompositeConfiguration}\n */\nclass CompositeConfigurationTest {\n\n    @Test\n    void test() {\n        InmemoryConfiguration inmemoryConfiguration1 = new InmemoryConfiguration();\n        InmemoryConfiguration inmemoryConfiguration2 = new InmemoryConfiguration();\n        InmemoryConfiguration inmemoryConfiguration3 = new InmemoryConfiguration();\n        CompositeConfiguration configuration = new CompositeConfiguration(new Configuration[] {inmemoryConfiguration1});\n        configuration.addConfiguration(inmemoryConfiguration2);\n        configuration.addConfigurationFirst(inmemoryConfiguration3);\n\n        inmemoryConfiguration1.addProperty(\"k\", \"v1\");\n        inmemoryConfiguration2.addProperty(\"k\", \"v2\");\n        inmemoryConfiguration3.addProperty(\"k\", \"v3\");\n\n        Assertions.assertEquals(configuration.getInternalProperty(\"k\"), \"v3\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/ConfigurationCacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link ConfigurationCache}\n */\nclass ConfigurationCacheTest {\n\n    @Test\n    void test() {\n        ConfigurationCache configurationCache = new ConfigurationCache();\n        String value = configurationCache.computeIfAbsent(\"k1\", k -> \"v1\");\n        Assertions.assertEquals(value, \"v1\");\n        value = configurationCache.computeIfAbsent(\"k1\", k -> \"v2\");\n        Assertions.assertEquals(value, \"v1\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/ConfigurationUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;\n\nclass ConfigurationUtilsTest {\n    @Test\n    void testCachedProperties() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        Environment originApplicationEnvironment = applicationModel.modelEnvironment();\n        Environment applicationEnvironment = Mockito.spy(originApplicationEnvironment);\n        applicationModel.setEnvironment(applicationEnvironment);\n\n        Configuration configuration = Mockito.mock(Configuration.class);\n        Mockito.when(applicationEnvironment.getDynamicGlobalConfiguration()).thenReturn(configuration);\n        Mockito.when(configuration.getString(\"TestKey\", \"\")).thenReturn(\"a\");\n\n        Assertions.assertEquals(\"a\", ConfigurationUtils.getCachedDynamicProperty(applicationModel, \"TestKey\", \"xxx\"));\n\n        Mockito.when(configuration.getString(\"TestKey\", \"\")).thenReturn(\"b\");\n        // cached key\n        Assertions.assertEquals(\"a\", ConfigurationUtils.getCachedDynamicProperty(applicationModel, \"TestKey\", \"xxx\"));\n\n        ModuleModel moduleModel = applicationModel.newModule();\n        ModuleEnvironment originModuleEnvironment = moduleModel.modelEnvironment();\n        ModuleEnvironment moduleEnvironment = Mockito.spy(originModuleEnvironment);\n        moduleModel.setModuleEnvironment(moduleEnvironment);\n\n        Mockito.when(moduleEnvironment.getDynamicGlobalConfiguration()).thenReturn(configuration);\n\n        // ApplicationModel should not affect ModuleModel\n        Assertions.assertEquals(\"b\", ConfigurationUtils.getCachedDynamicProperty(moduleModel, \"TestKey\", \"xxx\"));\n\n        Mockito.when(configuration.getString(\"TestKey\", \"\")).thenReturn(\"c\");\n        // cached key\n        Assertions.assertEquals(\"b\", ConfigurationUtils.getCachedDynamicProperty(moduleModel, \"TestKey\", \"xxx\"));\n\n        moduleModel.setModuleEnvironment(originModuleEnvironment);\n        applicationModel.setEnvironment(originApplicationEnvironment);\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testGetServerShutdownTimeout() {\n        System.setProperty(SHUTDOWN_WAIT_KEY, \" 10000\");\n        Assertions.assertEquals(10000, ConfigurationUtils.getServerShutdownTimeout(ApplicationModel.defaultModel()));\n        System.clearProperty(SHUTDOWN_WAIT_KEY);\n    }\n\n    @Test\n    void testGetProperty() {\n        System.setProperty(SHUTDOWN_WAIT_KEY, \" 10000\");\n        Assertions.assertEquals(\n                \"10000\", ConfigurationUtils.getProperty(ApplicationModel.defaultModel(), SHUTDOWN_WAIT_KEY));\n        System.clearProperty(SHUTDOWN_WAIT_KEY);\n    }\n\n    @Test\n    void testParseSingleProperties() throws Exception {\n        String p1 = \"aaa=bbb\";\n        Map<String, String> result = ConfigurationUtils.parseProperties(p1);\n        Assertions.assertEquals(1, result.size());\n        Assertions.assertEquals(\"bbb\", result.get(\"aaa\"));\n    }\n\n    @Test\n    void testParseMultipleProperties() throws Exception {\n        String p1 = \"aaa=bbb\\nccc=ddd\";\n        Map<String, String> result = ConfigurationUtils.parseProperties(p1);\n        Assertions.assertEquals(2, result.size());\n        Assertions.assertEquals(\"bbb\", result.get(\"aaa\"));\n        Assertions.assertEquals(\"ddd\", result.get(\"ccc\"));\n    }\n\n    @Test\n    void testEscapedNewLine() throws Exception {\n        String p1 = \"dubbo.registry.address=zookeeper://127.0.0.1:2181\\\\\\\\ndubbo.protocol.port=20880\";\n        Map<String, String> result = ConfigurationUtils.parseProperties(p1);\n        Assertions.assertEquals(1, result.size());\n        Assertions.assertEquals(\n                \"zookeeper://127.0.0.1:2181\\\\ndubbo.protocol.port=20880\", result.get(\"dubbo.registry.address\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/EnvironmentConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * The type Environment configuration test.\n */\nclass EnvironmentConfigurationTest {\n\n    private static final String MOCK_KEY = \"DUBBO_KEY\";\n    private static final String MOCK_VALUE = \"mockValue\";\n\n    private EnvironmentConfiguration envConfig(Map<String, String> map) {\n        return new EnvironmentConfiguration() {\n            @Override\n            protected Map<String, String> getenv() {\n                return map;\n            }\n        };\n    }\n\n    @Test\n    void testGetInternalProperty() {\n        Map<String, String> map = new HashMap<>();\n        map.put(MOCK_KEY, MOCK_VALUE);\n        EnvironmentConfiguration configuration = envConfig(map);\n        Assertions.assertEquals(MOCK_VALUE, configuration.getInternalProperty(\"dubbo.key\"));\n        Assertions.assertEquals(MOCK_VALUE, configuration.getInternalProperty(\"key\"));\n        Assertions.assertEquals(MOCK_VALUE, configuration.getInternalProperty(\"dubbo_key\"));\n        Assertions.assertEquals(MOCK_VALUE, configuration.getInternalProperty(MOCK_KEY));\n    }\n\n    @Test\n    void testGetProperties() {\n        Map<String, String> map = new HashMap<>();\n        map.put(MOCK_KEY, MOCK_VALUE);\n        EnvironmentConfiguration configuration = new EnvironmentConfiguration() {\n            @Override\n            protected Map<String, String> getenv() {\n                return map;\n            }\n        };\n        Assertions.assertEquals(map, configuration.getProperties());\n    }\n\n    @Test\n    void testHyphenAndDotKeyResolveFromEnv() {\n        Map<String, String> envMap = new HashMap<>();\n        envMap.put(\"DUBBO_ABC_DEF_GHI\", \"v1\");\n        envMap.put(\"DUBBO_ABCDEF_GHI\", \"v2\");\n        envMap.put(\"DUBBO_ABC-DEF_GHI\", \"v3\");\n        envMap.put(\"dubbo_abc_def_ghi\", \"v4\");\n\n        EnvironmentConfiguration configuration = envConfig(envMap);\n\n        String dubboKey = \"dubbo.abc-def.ghi\";\n\n        Assertions.assertEquals(\"v1\", configuration.getProperty(dubboKey));\n\n        envMap.remove(\"DUBBO_ABC_DEF_GHI\");\n        configuration = envConfig(envMap);\n        Assertions.assertEquals(\"v2\", configuration.getProperty(dubboKey));\n\n        envMap.remove(\"DUBBO_ABCDEF_GHI\");\n        configuration = envConfig(envMap);\n        Assertions.assertEquals(\"v3\", configuration.getProperty(dubboKey));\n\n        envMap.remove(\"DUBBO_ABC-DEF_GHI\");\n        configuration = envConfig(envMap);\n        Assertions.assertEquals(\"v4\", configuration.getProperty(dubboKey));\n\n        envMap.remove(\"dubbo_abc_def_ghi\");\n        configuration = envConfig(envMap);\n        Assertions.assertNull(configuration.getProperty(dubboKey));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/EnvironmentTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.config.configcenter.wrapper.CompositeDynamicConfiguration;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link Environment}\n */\nclass EnvironmentTest {\n\n    @Test\n    void testResolvePlaceholders() {\n        Environment environment = ApplicationModel.defaultModel().modelEnvironment();\n\n        Map<String, String> externalMap = new LinkedHashMap<>();\n        externalMap.put(\"zookeeper.address\", \"127.0.0.1\");\n        externalMap.put(\"zookeeper.port\", \"2181\");\n        environment.updateAppExternalConfigMap(externalMap);\n\n        Map<String, String> sysprops = new LinkedHashMap<>();\n        sysprops.put(\"zookeeper.address\", \"192.168.10.1\");\n        System.getProperties().putAll(sysprops);\n\n        try {\n            String s = environment.resolvePlaceholders(\"zookeeper://${zookeeper.address}:${zookeeper.port}\");\n            assertEquals(\"zookeeper://192.168.10.1:2181\", s);\n        } finally {\n            for (String key : sysprops.keySet()) {\n                System.clearProperty(key);\n            }\n        }\n    }\n\n    @Test\n    void test() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        Environment environment = applicationModel.modelEnvironment();\n\n        // test getPrefixedConfiguration\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setAddress(\"127.0.0.1\");\n        registryConfig.setPort(2181);\n        String prefix = \"dubbo.registry\";\n        Configuration prefixedConfiguration = environment.getPrefixedConfiguration(registryConfig, prefix);\n        Assertions.assertTrue(prefixedConfiguration instanceof PrefixedConfiguration);\n\n        // test getConfigurationMaps(AbstractConfig config, String prefix)\n        List<Map<String, String>> configurationMaps = environment.getConfigurationMaps(registryConfig, prefix);\n        Assertions.assertEquals(7, configurationMaps.size());\n\n        // test getConfigurationMaps()\n        configurationMaps = environment.getConfigurationMaps();\n        Assertions.assertEquals(6, configurationMaps.size());\n\n        CompositeConfiguration configuration1 = environment.getConfiguration();\n        CompositeConfiguration configuration2 = environment.getConfiguration();\n        Assertions.assertEquals(configuration1, configuration2);\n\n        // test getDynamicConfiguration\n        Optional<DynamicConfiguration> dynamicConfiguration = environment.getDynamicConfiguration();\n        Assertions.assertFalse(dynamicConfiguration.isPresent());\n        // test getDynamicGlobalConfiguration\n        Configuration dynamicGlobalConfiguration = environment.getDynamicGlobalConfiguration();\n        Assertions.assertEquals(dynamicGlobalConfiguration, configuration1);\n\n        CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();\n        environment.setDynamicConfiguration(compositeDynamicConfiguration);\n        dynamicConfiguration = environment.getDynamicConfiguration();\n        Assertions.assertEquals(dynamicConfiguration.get(), compositeDynamicConfiguration);\n\n        dynamicGlobalConfiguration = environment.getDynamicGlobalConfiguration();\n        Assertions.assertNotEquals(dynamicGlobalConfiguration, configuration1);\n\n        // test destroy\n        environment.destroy();\n        Assertions.assertNull(environment.getSystemConfiguration());\n        Assertions.assertNull(environment.getEnvironmentConfiguration());\n        Assertions.assertNull(environment.getAppExternalConfiguration());\n        Assertions.assertNull(environment.getExternalConfiguration());\n        Assertions.assertNull(environment.getAppConfiguration());\n\n        frameworkModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/InmemoryConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.common.beanutil.JavaBeanAccessor;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * Unit test of class InmemoryConfiguration, and interface Configuration.\n */\nclass InmemoryConfigurationTest {\n\n    private InmemoryConfiguration memConfig;\n    private static final String MOCK_KEY = \"mockKey\";\n    private static final String MOCK_VALUE = \"mockValue\";\n    private static final String MOCK_ONE_KEY = \"one\";\n    private static final String MOCK_TWO_KEY = \"two\";\n    private static final String MOCK_THREE_KEY = \"three\";\n\n    /**\n     * Init.\n     */\n    @BeforeEach\n    public void init() {\n        memConfig = new InmemoryConfiguration();\n    }\n\n    /**\n     * Test get mem property.\n     */\n    @Test\n    void testGetMemProperty() {\n        Assertions.assertNull(memConfig.getInternalProperty(MOCK_KEY));\n        Assertions.assertFalse(memConfig.containsKey(MOCK_KEY));\n        Assertions.assertNull(memConfig.getString(MOCK_KEY));\n        Assertions.assertNull(memConfig.getProperty(MOCK_KEY));\n        memConfig.addProperty(MOCK_KEY, MOCK_VALUE);\n        Assertions.assertTrue(memConfig.containsKey(MOCK_KEY));\n        Assertions.assertEquals(MOCK_VALUE, memConfig.getInternalProperty(MOCK_KEY));\n        Assertions.assertEquals(MOCK_VALUE, memConfig.getString(MOCK_KEY, MOCK_VALUE));\n        Assertions.assertEquals(MOCK_VALUE, memConfig.getProperty(MOCK_KEY, MOCK_VALUE));\n    }\n\n    /**\n     * Test get properties.\n     */\n    @Test\n    void testGetProperties() {\n        Assertions.assertNull(memConfig.getInternalProperty(MOCK_ONE_KEY));\n        Assertions.assertNull(memConfig.getInternalProperty(MOCK_TWO_KEY));\n        Map<String, String> proMap = new HashMap<>();\n        proMap.put(MOCK_ONE_KEY, MOCK_VALUE);\n        proMap.put(MOCK_TWO_KEY, MOCK_VALUE);\n        memConfig.addProperties(proMap);\n        Assertions.assertNotNull(memConfig.getInternalProperty(MOCK_ONE_KEY));\n        Assertions.assertNotNull(memConfig.getInternalProperty(MOCK_TWO_KEY));\n        Map<String, String> anotherProMap = new HashMap<>();\n        anotherProMap.put(MOCK_THREE_KEY, MOCK_VALUE);\n        memConfig.setProperties(anotherProMap);\n        Assertions.assertNotNull(memConfig.getInternalProperty(MOCK_THREE_KEY));\n        Assertions.assertNull(memConfig.getInternalProperty(MOCK_ONE_KEY));\n        Assertions.assertNull(memConfig.getInternalProperty(MOCK_TWO_KEY));\n    }\n\n    @Test\n    void testGetInt() {\n        memConfig.addProperty(\"a\", \"1\");\n        Assertions.assertEquals(1, memConfig.getInt(\"a\"));\n        Assertions.assertEquals(Integer.valueOf(1), memConfig.getInteger(\"a\", 2));\n        Assertions.assertEquals(2, memConfig.getInt(\"b\", 2));\n    }\n\n    @Test\n    void getBoolean() {\n        memConfig.addProperty(\"a\", Boolean.TRUE.toString());\n        Assertions.assertTrue(memConfig.getBoolean(\"a\"));\n        Assertions.assertFalse(memConfig.getBoolean(\"b\", false));\n        Assertions.assertTrue(memConfig.getBoolean(\"b\", Boolean.TRUE));\n    }\n\n    @Test\n    void testIllegalType() {\n        memConfig.addProperty(\"it\", \"aaa\");\n\n        Assertions.assertThrows(IllegalStateException.class, () -> memConfig.getInteger(\"it\", 1));\n        Assertions.assertThrows(IllegalStateException.class, () -> memConfig.getInt(\"it\", 1));\n        Assertions.assertThrows(IllegalStateException.class, () -> memConfig.getInt(\"it\"));\n    }\n\n    @Test\n    void testDoesNotExist() {\n        Assertions.assertThrows(NoSuchElementException.class, () -> memConfig.getInt(\"ne\"));\n        Assertions.assertThrows(NoSuchElementException.class, () -> memConfig.getBoolean(\"ne\"));\n    }\n\n    @Test\n    void testConversions() {\n        memConfig.addProperty(\"long\", \"2147483648\");\n        memConfig.addProperty(\"byte\", \"127\");\n        memConfig.addProperty(\"short\", \"32767\");\n        memConfig.addProperty(\"float\", \"3.14\");\n        memConfig.addProperty(\"double\", \"3.14159265358979323846264338327950\");\n        memConfig.addProperty(\"enum\", \"FIELD\");\n\n        Object longObject = memConfig.convert(Long.class, \"long\", 1L);\n        Object byteObject = memConfig.convert(Byte.class, \"byte\", (byte) 1);\n        Object shortObject = memConfig.convert(Short.class, \"short\", (short) 1);\n        Object floatObject = memConfig.convert(Float.class, \"float\", 3.14F);\n        Object doubleObject = memConfig.convert(Double.class, \"double\", 3.14159265358979323846264338327950);\n        JavaBeanAccessor javaBeanAccessor = memConfig.convert(JavaBeanAccessor.class, \"enum\", JavaBeanAccessor.ALL);\n\n        Assertions.assertEquals(Long.class, longObject.getClass());\n        Assertions.assertEquals(2147483648L, longObject);\n\n        Assertions.assertEquals(Byte.class, byteObject.getClass());\n        Assertions.assertEquals((byte) 127, byteObject);\n\n        Assertions.assertEquals(Short.class, shortObject.getClass());\n        Assertions.assertEquals((short) 32767, shortObject);\n\n        Assertions.assertEquals(Float.class, floatObject.getClass());\n        Assertions.assertEquals(3.14F, floatObject);\n\n        Assertions.assertEquals(Double.class, doubleObject.getClass());\n        Assertions.assertEquals(3.14159265358979323846264338327950, doubleObject);\n\n        Assertions.assertEquals(JavaBeanAccessor.class, javaBeanAccessor.getClass());\n        Assertions.assertEquals(JavaBeanAccessor.FIELD, javaBeanAccessor);\n    }\n\n    /**\n     * Clean.\n     */\n    @AfterEach\n    public void clean() {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/MockOrderedPropertiesProvider1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport java.util.Properties;\n\npublic class MockOrderedPropertiesProvider1 implements OrderedPropertiesProvider {\n    @Override\n    public int priority() {\n        return 3;\n    }\n\n    @Override\n    public Properties initProperties() {\n        Properties properties = new Properties();\n        properties.put(\"testKey\", \"333\");\n        return properties;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/MockOrderedPropertiesProvider2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport java.util.Properties;\n\npublic class MockOrderedPropertiesProvider2 implements OrderedPropertiesProvider {\n    @Override\n    public int priority() {\n        return 1;\n    }\n\n    @Override\n    public Properties initProperties() {\n        Properties properties = new Properties();\n        properties.put(\"testKey\", \"999\");\n        return properties;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/OrderedPropertiesConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link OrderedPropertiesConfiguration}\n */\nclass OrderedPropertiesConfigurationTest {\n\n    @Test\n    void testOrderPropertiesProviders() {\n        OrderedPropertiesConfiguration configuration = new OrderedPropertiesConfiguration(\n                ApplicationModel.defaultModel().getDefaultModule());\n        Assertions.assertEquals(\"999\", configuration.getInternalProperty(\"testKey\"));\n    }\n\n    @Test\n    void testGetPropertyFromOrderedPropertiesConfiguration() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n\n        ModuleModel moduleModel = applicationModel.newModule();\n        ModuleEnvironment moduleEnvironment = moduleModel.modelEnvironment();\n\n        Configuration configuration = moduleEnvironment.getDynamicGlobalConfiguration();\n        // MockOrderedPropertiesProvider2  initProperties\n        Assertions.assertEquals(\"999\", configuration.getString(\"testKey\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/PrefixedConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass PrefixedConfigurationTest {\n\n    @Test\n    void testPrefixedConfiguration() {\n        Map<String, String> props = new LinkedHashMap<>();\n        props.put(\"dubbo.protocol.name\", \"dubbo\");\n        props.put(\"dubbo.protocol.port\", \"1234\");\n        props.put(\"dubbo.protocols.rest.port\", \"2345\");\n        InmemoryConfiguration inmemoryConfiguration = new InmemoryConfiguration();\n        inmemoryConfiguration.addProperties(props);\n\n        // prefixed over InmemoryConfiguration\n        PrefixedConfiguration prefixedConfiguration =\n                new PrefixedConfiguration(inmemoryConfiguration, \"dubbo.protocol\");\n        Assertions.assertEquals(\"dubbo\", prefixedConfiguration.getProperty(\"name\"));\n        Assertions.assertEquals(\"1234\", prefixedConfiguration.getProperty(\"port\"));\n\n        prefixedConfiguration = new PrefixedConfiguration(inmemoryConfiguration, \"dubbo.protocols.rest\");\n        Assertions.assertEquals(\"2345\", prefixedConfiguration.getProperty(\"port\"));\n\n        // prefixed over composite configuration\n        CompositeConfiguration compositeConfiguration = new CompositeConfiguration();\n        compositeConfiguration.addConfiguration(inmemoryConfiguration);\n        prefixedConfiguration = new PrefixedConfiguration(compositeConfiguration, \"dubbo.protocols.rest\");\n        Assertions.assertEquals(\"2345\", prefixedConfiguration.getProperty(\"port\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/PropertiesConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link PropertiesConfiguration}\n */\nclass PropertiesConfigurationTest {\n\n    @Test\n    void test() {\n        PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration(ApplicationModel.defaultModel());\n\n        Map<String, String> properties = propertiesConfiguration.getProperties();\n        Assertions.assertEquals(properties.get(\"dubbo\"), \"properties\");\n        Assertions.assertEquals(properties.get(\"dubbo.application.enable-file-cache\"), \"false\");\n        Assertions.assertEquals(properties.get(\"dubbo.service.shutdown.wait\"), \"200\");\n\n        Assertions.assertEquals(propertiesConfiguration.getProperty(\"dubbo\"), \"properties\");\n        Assertions.assertEquals(propertiesConfiguration.getInternalProperty(\"dubbo\"), \"properties\");\n\n        propertiesConfiguration.setProperty(\"k1\", \"v1\");\n        Assertions.assertEquals(propertiesConfiguration.getProperty(\"k1\"), \"v1\");\n        propertiesConfiguration.remove(\"k1\");\n        Assertions.assertNull(propertiesConfiguration.getProperty(\"k1\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/SystemConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * The type System configuration test.\n */\nclass SystemConfigurationTest {\n\n    private static SystemConfiguration sysConfig;\n    private static final String MOCK_KEY = \"mockKey\";\n    private static final String MOCK_STRING_VALUE = \"mockValue\";\n    private static final Boolean MOCK_BOOL_VALUE = Boolean.FALSE;\n    private static final Integer MOCK_INT_VALUE = Integer.MAX_VALUE;\n    private static final Long MOCK_LONG_VALUE = Long.MIN_VALUE;\n    private static final Short MOCK_SHORT_VALUE = Short.MIN_VALUE;\n    private static final Float MOCK_FLOAT_VALUE = Float.MIN_VALUE;\n    private static final Double MOCK_DOUBLE_VALUE = Double.MIN_VALUE;\n    private static final Byte MOCK_BYTE_VALUE = Byte.MIN_VALUE;\n    private static final String NOT_EXIST_KEY = \"NOTEXIST\";\n\n    /**\n     * Init.\n     */\n    @BeforeEach\n    public void init() {\n\n        sysConfig = new SystemConfiguration();\n    }\n\n    /**\n     * Test get sys property.\n     */\n    @Test\n    void testGetSysProperty() {\n        Assertions.assertNull(sysConfig.getInternalProperty(MOCK_KEY));\n        Assertions.assertFalse(sysConfig.containsKey(MOCK_KEY));\n        Assertions.assertNull(sysConfig.getString(MOCK_KEY));\n        Assertions.assertNull(sysConfig.getProperty(MOCK_KEY));\n        System.setProperty(MOCK_KEY, MOCK_STRING_VALUE);\n        Assertions.assertTrue(sysConfig.containsKey(MOCK_KEY));\n        Assertions.assertEquals(MOCK_STRING_VALUE, sysConfig.getInternalProperty(MOCK_KEY));\n        Assertions.assertEquals(MOCK_STRING_VALUE, sysConfig.getString(MOCK_KEY, MOCK_STRING_VALUE));\n        Assertions.assertEquals(MOCK_STRING_VALUE, sysConfig.getProperty(MOCK_KEY, MOCK_STRING_VALUE));\n    }\n\n    /**\n     * Test convert.\n     */\n    @Test\n    void testConvert() {\n        Assertions.assertEquals(MOCK_STRING_VALUE, sysConfig.convert(String.class, NOT_EXIST_KEY, MOCK_STRING_VALUE));\n        System.setProperty(MOCK_KEY, String.valueOf(MOCK_BOOL_VALUE));\n        Assertions.assertEquals(MOCK_BOOL_VALUE, sysConfig.convert(Boolean.class, MOCK_KEY, null));\n        System.setProperty(MOCK_KEY, String.valueOf(MOCK_STRING_VALUE));\n        Assertions.assertEquals(MOCK_STRING_VALUE, sysConfig.convert(String.class, MOCK_KEY, null));\n        System.setProperty(MOCK_KEY, String.valueOf(MOCK_INT_VALUE));\n        Assertions.assertEquals(MOCK_INT_VALUE, sysConfig.convert(Integer.class, MOCK_KEY, null));\n        System.setProperty(MOCK_KEY, String.valueOf(MOCK_LONG_VALUE));\n        Assertions.assertEquals(MOCK_LONG_VALUE, sysConfig.convert(Long.class, MOCK_KEY, null));\n        System.setProperty(MOCK_KEY, String.valueOf(MOCK_SHORT_VALUE));\n        Assertions.assertEquals(MOCK_SHORT_VALUE, sysConfig.convert(Short.class, MOCK_KEY, null));\n        System.setProperty(MOCK_KEY, String.valueOf(MOCK_FLOAT_VALUE));\n        Assertions.assertEquals(MOCK_FLOAT_VALUE, sysConfig.convert(Float.class, MOCK_KEY, null));\n        System.setProperty(MOCK_KEY, String.valueOf(MOCK_DOUBLE_VALUE));\n        Assertions.assertEquals(MOCK_DOUBLE_VALUE, sysConfig.convert(Double.class, MOCK_KEY, null));\n        System.setProperty(MOCK_KEY, String.valueOf(MOCK_BYTE_VALUE));\n        Assertions.assertEquals(MOCK_BYTE_VALUE, sysConfig.convert(Byte.class, MOCK_KEY, null));\n        System.setProperty(MOCK_KEY, String.valueOf(ConfigMock.MockOne));\n        Assertions.assertEquals(ConfigMock.MockOne, sysConfig.convert(ConfigMock.class, MOCK_KEY, null));\n    }\n\n    /**\n     * Clean.\n     */\n    @AfterEach\n    public void clean() {\n        if (null != System.getProperty(MOCK_KEY)) {\n            System.clearProperty(MOCK_KEY);\n        }\n    }\n\n    /**\n     * The enum Config mock.\n     */\n    enum ConfigMock {\n        /**\n         * Mock one config mock.\n         */\n        MockOne,\n        /**\n         * Mock two config mock.\n         */\n        MockTwo\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.nop.NopDynamicConfiguration;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link AbstractDynamicConfigurationFactory} Test\n *\n * @see AbstractDynamicConfigurationFactory\n * @since 2.7.5\n */\nclass AbstractDynamicConfigurationFactoryTest {\n\n    private AbstractDynamicConfigurationFactory factory;\n\n    @BeforeEach\n    public void init() {\n        factory = new AbstractDynamicConfigurationFactory() {\n            @Override\n            protected DynamicConfiguration createDynamicConfiguration(URL url) {\n                return new NopDynamicConfiguration(url);\n            }\n        };\n    }\n\n    @Test\n    void testGetDynamicConfiguration() {\n        URL url = URL.valueOf(\"nop://127.0.0.1\");\n        assertEquals(factory.getDynamicConfiguration(url), factory.getDynamicConfiguration(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.DEFAULT_THREAD_POOL_KEEP_ALIVE_TIME;\nimport static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.DEFAULT_THREAD_POOL_PREFIX;\nimport static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.DEFAULT_THREAD_POOL_SIZE;\nimport static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.GROUP_PARAM_NAME;\nimport static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.PARAM_NAME_PREFIX;\nimport static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.THREAD_POOL_KEEP_ALIVE_TIME_PARAM_NAME;\nimport static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.THREAD_POOL_PREFIX_PARAM_NAME;\nimport static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.THREAD_POOL_SIZE_PARAM_NAME;\nimport static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.TIMEOUT_PARAM_NAME;\nimport static org.apache.dubbo.common.config.configcenter.DynamicConfiguration.DEFAULT_GROUP;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\n/**\n * {@link AbstractDynamicConfiguration} Test\n *\n * @since 2.7.5\n */\nclass AbstractDynamicConfigurationTest {\n\n    private AbstractDynamicConfiguration configuration;\n\n    @BeforeEach\n    public void init() {\n        configuration = new AbstractDynamicConfiguration(null) {\n            @Override\n            protected String doGetConfig(String key, String group) {\n                return null;\n            }\n\n            @Override\n            protected void doClose() {}\n\n            @Override\n            protected boolean doRemoveConfig(String key, String group) {\n                return false;\n            }\n        };\n    }\n\n    @Test\n    void testConstants() {\n        assertEquals(\"dubbo.config-center.\", PARAM_NAME_PREFIX);\n        assertEquals(\"dubbo.config-center.workers\", DEFAULT_THREAD_POOL_PREFIX);\n        assertEquals(\"dubbo.config-center.thread-pool.prefix\", THREAD_POOL_PREFIX_PARAM_NAME);\n        assertEquals(\"dubbo.config-center.thread-pool.size\", THREAD_POOL_SIZE_PARAM_NAME);\n        assertEquals(\"dubbo.config-center.thread-pool.keep-alive-time\", THREAD_POOL_KEEP_ALIVE_TIME_PARAM_NAME);\n        assertEquals(1, DEFAULT_THREAD_POOL_SIZE);\n        assertEquals(60 * 1000, DEFAULT_THREAD_POOL_KEEP_ALIVE_TIME);\n\n        // @since 2.7.8\n        assertEquals(\"dubbo.config-center.group\", GROUP_PARAM_NAME);\n        assertEquals(\"dubbo.config-center.timeout\", TIMEOUT_PARAM_NAME);\n    }\n\n    @Test\n    void testConstructor() {\n        URL url = URL.valueOf(\"default://\")\n                .addParameter(THREAD_POOL_PREFIX_PARAM_NAME, \"test\")\n                .addParameter(THREAD_POOL_SIZE_PARAM_NAME, 10)\n                .addParameter(THREAD_POOL_KEEP_ALIVE_TIME_PARAM_NAME, 100);\n\n        AbstractDynamicConfiguration configuration = new AbstractDynamicConfiguration(url) {\n\n            @Override\n            protected String doGetConfig(String key, String group) {\n                return null;\n            }\n\n            @Override\n            protected void doClose() {}\n\n            @Override\n            protected boolean doRemoveConfig(String key, String group) {\n                return false;\n            }\n        };\n\n        ThreadPoolExecutor threadPoolExecutor = configuration.getWorkersThreadPool();\n        ThreadFactory threadFactory = threadPoolExecutor.getThreadFactory();\n\n        Thread thread = threadFactory.newThread(() -> {});\n\n        assertEquals(10, threadPoolExecutor.getCorePoolSize());\n        assertEquals(10, threadPoolExecutor.getMaximumPoolSize());\n        assertEquals(100, threadPoolExecutor.getKeepAliveTime(TimeUnit.MILLISECONDS));\n        assertEquals(\"test-thread-1\", thread.getName());\n    }\n\n    @Test\n    void testPublishConfig() {\n        assertFalse(configuration.publishConfig(null, null));\n        assertFalse(configuration.publishConfig(null, null, null));\n    }\n    //\n    //    @Test\n    //    public void testGetConfigKeys() {\n    //        assertTrue(configuration.getConfigKeys(null).isEmpty());\n    //    }\n\n    @Test\n    void testGetConfig() {\n        assertNull(configuration.getConfig(null, null));\n        assertNull(configuration.getConfig(null, null, 200));\n    }\n\n    @Test\n    void testGetInternalProperty() {\n        assertNull(configuration.getInternalProperty(null));\n    }\n\n    @Test\n    void testGetProperties() {\n        assertNull(configuration.getProperties(null, null));\n        assertNull(configuration.getProperties(null, null, 100L));\n    }\n\n    @Test\n    void testAddListener() {\n        configuration.addListener(null, null);\n        configuration.addListener(null, null, null);\n    }\n\n    @Test\n    void testRemoveListener() {\n        configuration.removeListener(null, null);\n        configuration.removeListener(null, null, null);\n    }\n\n    @Test\n    void testClose() throws Exception {\n        configuration.close();\n    }\n\n    /**\n     * Test {@link AbstractDynamicConfiguration#getGroup()} and\n     * {@link AbstractDynamicConfiguration#getDefaultGroup()} methods\n     *\n     * @since 2.7.8\n     */\n    @Test\n    void testGetGroupAndGetDefaultGroup() {\n        assertEquals(configuration.getGroup(), configuration.getDefaultGroup());\n        assertEquals(DEFAULT_GROUP, configuration.getDefaultGroup());\n    }\n\n    /**\n     * Test {@link AbstractDynamicConfiguration#getTimeout()} and\n     * {@link AbstractDynamicConfiguration#getDefaultTimeout()} methods\n     *\n     * @since 2.7.8\n     */\n    @Test\n    void testGetTimeoutAndGetDefaultTimeout() {\n        assertEquals(configuration.getTimeout(), configuration.getDefaultTimeout());\n        assertEquals(-1L, configuration.getDefaultTimeout());\n    }\n\n    /**\n     * Test {@link AbstractDynamicConfiguration#removeConfig(String, String)} and\n     * {@link AbstractDynamicConfiguration#doRemoveConfig(String, String)} methods\n     *\n     * @since 2.7.8\n     */\n    @Test\n    void testRemoveConfigAndDoRemoveConfig() throws Exception {\n        String key = null;\n        String group = null;\n        assertEquals(configuration.removeConfig(key, group), configuration.doRemoveConfig(key, group));\n        assertFalse(configuration.removeConfig(key, group));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/ConfigChangeTypeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.config.configcenter.ConfigChangeType.ADDED;\nimport static org.apache.dubbo.common.config.configcenter.ConfigChangeType.DELETED;\nimport static org.apache.dubbo.common.config.configcenter.ConfigChangeType.MODIFIED;\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\n\n/**\n * {@link ConfigChangeType} Test\n *\n * @see ConfigChangeType\n * @since 2.7.5\n */\nclass ConfigChangeTypeTest {\n\n    @Test\n    void testMembers() {\n        assertArrayEquals(new ConfigChangeType[] {ADDED, MODIFIED, DELETED}, ConfigChangeType.values());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/ConfigChangedEventTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\n\n/**\n * {@link ConfigChangedEvent} Test\n *\n * @since 2.7.5\n */\nclass ConfigChangedEventTest {\n\n    private static final String KEY = \"k\";\n\n    private static final String GROUP = \"g\";\n\n    private static final String CONTENT = \"c\";\n\n    @Test\n    void testGetter() {\n\n        ConfigChangedEvent event = new ConfigChangedEvent(KEY, GROUP, CONTENT);\n\n        assertEquals(KEY, event.getKey());\n        assertEquals(GROUP, event.getGroup());\n        assertEquals(CONTENT, event.getContent());\n        assertEquals(ConfigChangeType.MODIFIED, event.getChangeType());\n        assertEquals(\"k,g\", event.getSource());\n\n        event = new ConfigChangedEvent(KEY, GROUP, CONTENT, ConfigChangeType.ADDED);\n\n        assertEquals(KEY, event.getKey());\n        assertEquals(GROUP, event.getGroup());\n        assertEquals(CONTENT, event.getContent());\n        assertEquals(ConfigChangeType.ADDED, event.getChangeType());\n        assertEquals(\"k,g\", event.getSource());\n    }\n\n    @Test\n    void testEqualsAndHashCode() {\n        for (ConfigChangeType type : ConfigChangeType.values()) {\n            assertEquals(\n                    new ConfigChangedEvent(KEY, GROUP, CONTENT, type),\n                    new ConfigChangedEvent(KEY, GROUP, CONTENT, type));\n            assertEquals(\n                    new ConfigChangedEvent(KEY, GROUP, CONTENT, type).hashCode(),\n                    new ConfigChangedEvent(KEY, GROUP, CONTENT, type).hashCode());\n            assertEquals(\n                    new ConfigChangedEvent(KEY, GROUP, CONTENT, type).toString(),\n                    new ConfigChangedEvent(KEY, GROUP, CONTENT, type).toString());\n        }\n    }\n\n    @Test\n    void testToString() {\n        ConfigChangedEvent event = new ConfigChangedEvent(KEY, GROUP, CONTENT);\n        assertNotNull(event.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter;\n\nimport org.apache.dubbo.common.config.configcenter.nop.NopDynamicConfigurationFactory;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link DynamicConfigurationFactory} Test\n *\n * @since 2.7.5\n */\nclass DynamicConfigurationFactoryTest {\n\n    @Test\n    void testDefaultExtension() {\n        DynamicConfigurationFactory factory =\n                getExtensionLoader(DynamicConfigurationFactory.class).getDefaultExtension();\n        assertEquals(NopDynamicConfigurationFactory.class, factory.getClass());\n        assertEquals(\n                NopDynamicConfigurationFactory.class,\n                getExtensionLoader(DynamicConfigurationFactory.class)\n                        .getExtension(\"nop\")\n                        .getClass());\n    }\n\n    private <T> ExtensionLoader<T> getExtensionLoader(Class<T> extClass) {\n        return ApplicationModel.defaultModel().getDefaultModule().getExtensionLoader(extClass);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/constants/CommonConstantsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.constants;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR_CHAR;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH;\nimport static org.apache.dubbo.common.constants.CommonConstants.SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link CommonConstants} Test-Cases\n *\n * @since 2.7.8\n */\nclass CommonConstantsTest {\n\n    @Test\n    void test() {\n        assertEquals(',', COMMA_SEPARATOR_CHAR);\n        assertEquals(\"composite\", COMPOSITE_METADATA_STORAGE_TYPE);\n        assertEquals(\"service-name-mapping.properties-path\", SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY);\n        assertEquals(\"META-INF/dubbo/service-name-mapping.properties\", DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/ConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertSame;\n\n/**\n * {@link Converter} Test-Cases\n *\n * @since 2.7.8\n */\nclass ConverterTest {\n\n    private ConverterUtil converterUtil;\n\n    @BeforeEach\n    public void setup() {\n        converterUtil = FrameworkModel.defaultModel().getBeanFactory().getBean(ConverterUtil.class);\n    }\n\n    @AfterEach\n    public void tearDown() {\n        FrameworkModel.destroyAll();\n    }\n\n    @Test\n    void testGetConverter() {\n        getExtensionLoader(Converter.class).getSupportedExtensionInstances().forEach(converter -> {\n            assertSame(converter, converterUtil.getConverter(converter.getSourceType(), converter.getTargetType()));\n        });\n    }\n\n    @Test\n    void testConvertIfPossible() {\n        assertEquals(Integer.valueOf(2), converterUtil.convertIfPossible(\"2\", Integer.class));\n        assertEquals(Boolean.FALSE, converterUtil.convertIfPossible(\"false\", Boolean.class));\n        assertEquals(Double.valueOf(1), converterUtil.convertIfPossible(\"1\", Double.class));\n    }\n\n    private <T> ExtensionLoader<T> getExtensionLoader(Class<T> extClass) {\n        return ApplicationModel.defaultModel().getDefaultModule().getExtensionLoader(extClass);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToBooleanConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToBooleanConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToBooleanConverterTest {\n\n    private StringToBooleanConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter =\n                (StringToBooleanConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-boolean\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, Boolean.class));\n    }\n\n    @Test\n    void testConvert() {\n        assertTrue(converter.convert(\"true\"));\n        assertTrue(converter.convert(\"true\"));\n        assertTrue(converter.convert(\"True\"));\n        assertFalse(converter.convert(\"a\"));\n        assertNull(converter.convert(\"\"));\n        assertNull(converter.convert(null));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToCharArrayConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToCharArrayConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToCharArrayConverterTest {\n\n    private StringToCharArrayConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter =\n                (StringToCharArrayConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-char-array\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, char[].class));\n    }\n\n    @Test\n    void testConvert() {\n        assertArrayEquals(new char[] {'1', '2', '3'}, converter.convert(\"123\"));\n        assertNull(converter.convert(null));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToCharacterConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToCharacterConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToCharacterConverterTest {\n\n    private StringToCharacterConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter =\n                (StringToCharacterConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-character\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, Character.class));\n    }\n\n    @Test\n    void testConvert() {\n        assertEquals('t', converter.convert(\"t\"));\n        assertNull(converter.convert(null));\n        assertThrows(IllegalArgumentException.class, () -> {\n            converter.convert(\"ttt\");\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToDoubleConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToDoubleConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToDoubleConverterTest {\n\n    private StringToDoubleConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter =\n                (StringToDoubleConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-double\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, Double.class));\n    }\n\n    @Test\n    void testConvert() {\n        assertEquals(Double.valueOf(\"1.0\"), converter.convert(\"1.0\"));\n        assertNull(converter.convert(null));\n        assertThrows(NumberFormatException.class, () -> {\n            converter.convert(\"ttt\");\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToDurationConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToDurationConverter} Test\n *\n * @since 3.2.3\n */\nclass StringToDurationConverterTest {\n\n    private StringToDurationConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter =\n                (StringToDurationConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-duration\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, Duration.class));\n    }\n\n    @Test\n    void testConvert() {\n        assertEquals(Duration.ofMillis(1000), converter.convert(\"1000ms\"));\n        assertEquals(Duration.ofSeconds(1), converter.convert(\"1s\"));\n        assertEquals(Duration.ofMinutes(1), converter.convert(\"1m\"));\n        assertEquals(Duration.ofHours(1), converter.convert(\"1h\"));\n        assertEquals(Duration.ofDays(1), converter.convert(\"1d\"));\n\n        assertNull(converter.convert(null));\n        assertThrows(IllegalArgumentException.class, () -> {\n            converter.convert(\"ttt\");\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToFloatConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToFloatConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToFloatConverterTest {\n\n    private StringToFloatConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = (StringToFloatConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-float\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, Float.class));\n    }\n\n    @Test\n    void testConvert() {\n        assertEquals(Float.valueOf(\"1.0\"), converter.convert(\"1.0\"));\n        assertNull(converter.convert(null));\n        assertThrows(NumberFormatException.class, () -> {\n            converter.convert(\"ttt\");\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToIntegerConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToIntegerConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToIntegerConverterTest {\n\n    private StringToIntegerConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter =\n                (StringToIntegerConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-integer\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, Integer.class));\n    }\n\n    @Test\n    void testConvert() {\n        assertEquals(Integer.valueOf(\"1\"), converter.convert(\"1\"));\n        assertNull(converter.convert(null));\n        assertThrows(NumberFormatException.class, () -> {\n            converter.convert(\"ttt\");\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToLongConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToLongConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToLongConverterTest {\n\n    private StringToLongConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = (StringToLongConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-long\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, Long.class));\n    }\n\n    @Test\n    void testConvert() {\n        assertEquals(Long.valueOf(\"1\"), converter.convert(\"1\"));\n        assertNull(converter.convert(null));\n        assertThrows(NumberFormatException.class, () -> {\n            converter.convert(\"ttt\");\n        });\n    }\n\n    private <T> ExtensionLoader<T> getExtensionLoader(Class<T> extClass) {\n        return ApplicationModel.defaultModel().getDefaultModule().getExtensionLoader(extClass);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToOptionalConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport java.util.Optional;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToOptionalConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToOptionalConverterTest {\n\n    private StringToOptionalConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter =\n                (StringToOptionalConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-optional\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, Optional.class));\n    }\n\n    @Test\n    void testConvert() {\n        assertEquals(Optional.of(\"1\"), converter.convert(\"1\"));\n        assertEquals(Optional.empty(), converter.convert(null));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToShortConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToShortConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToShortConverterTest {\n\n    private StringToShortConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = (StringToShortConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-short\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, Short.class));\n    }\n\n    @Test\n    void testConvert() {\n        assertEquals(Short.valueOf(\"1\"), converter.convert(\"1\"));\n        assertNull(converter.convert(null));\n        assertThrows(NumberFormatException.class, () -> {\n            converter.convert(\"ttt\");\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToStringConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToStringConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToStringConverterTest {\n\n    private StringToStringConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter =\n                (StringToStringConverter) getExtensionLoader(Converter.class).getExtension(\"string-to-string\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, String.class));\n    }\n\n    @Test\n    void testConvert() {\n        assertEquals(\"1\", converter.convert(\"1\"));\n        assertNull(converter.convert(null));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/MultiValueConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link MultiValueConverter} Test\n *\n * @since 2.7.8\n */\nclass MultiValueConverterTest {\n\n    @Test\n    void testFind() {\n        MultiValueConverter converter = MultiValueConverter.find(String.class, String[].class);\n        assertEquals(StringToArrayConverter.class, converter.getClass());\n\n        converter = MultiValueConverter.find(String.class, BlockingDeque.class);\n        assertEquals(StringToBlockingDequeConverter.class, converter.getClass());\n\n        converter = MultiValueConverter.find(String.class, BlockingQueue.class);\n        assertEquals(StringToBlockingQueueConverter.class, converter.getClass());\n\n        converter = MultiValueConverter.find(String.class, Collection.class);\n        assertEquals(StringToCollectionConverter.class, converter.getClass());\n\n        converter = MultiValueConverter.find(String.class, Deque.class);\n        assertEquals(StringToDequeConverter.class, converter.getClass());\n\n        converter = MultiValueConverter.find(String.class, List.class);\n        assertEquals(StringToListConverter.class, converter.getClass());\n\n        converter = MultiValueConverter.find(String.class, NavigableSet.class);\n        assertEquals(StringToNavigableSetConverter.class, converter.getClass());\n\n        converter = MultiValueConverter.find(String.class, Queue.class);\n        assertEquals(StringToQueueConverter.class, converter.getClass());\n\n        converter = MultiValueConverter.find(String.class, Set.class);\n        assertEquals(StringToSetConverter.class, converter.getClass());\n\n        converter = MultiValueConverter.find(String.class, TransferQueue.class);\n        assertEquals(StringToTransferQueueConverter.class, converter.getClass());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToArrayConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Objects.deepEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToArrayConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToArrayConverterTest {\n\n    private StringToArrayConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = new StringToArrayConverter(FrameworkModel.defaultModel());\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(converter.accept(String.class, char[].class));\n        assertTrue(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() {\n        assertTrue(deepEquals(new Integer[] {123}, converter.convert(\"123\", Integer[].class, Integer.class)));\n        assertTrue(deepEquals(new Integer[] {1, 2, 3}, converter.convert(\"1,2,3\", Integer[].class, null)));\n        assertNull(converter.convert(\"\", Integer[].class, null));\n        assertNull(converter.convert(null, Integer[].class, null));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        assertEquals(Integer.MAX_VALUE, converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToBlockingDequeConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JRE;\n\nimport java.util.AbstractList;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.LinkedBlockingDeque;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToBlockingDequeConverter} Test\n *\n * @see BlockingDeque\n * @since 2.7.6\n */\nclass StringToBlockingDequeConverterTest {\n\n    private MultiValueConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = getExtensionLoader(MultiValueConverter.class).getExtension(\"string-to-blocking-deque\");\n    }\n\n    @Test\n    void testAccept() {\n\n        assertFalse(converter.accept(String.class, Collection.class));\n\n        assertFalse(converter.accept(String.class, List.class));\n        assertFalse(converter.accept(String.class, AbstractList.class));\n        assertFalse(converter.accept(String.class, ArrayList.class));\n        assertFalse(converter.accept(String.class, LinkedList.class));\n\n        assertFalse(converter.accept(String.class, Set.class));\n        assertFalse(converter.accept(String.class, SortedSet.class));\n        assertFalse(converter.accept(String.class, NavigableSet.class));\n        assertFalse(converter.accept(String.class, TreeSet.class));\n        assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class));\n\n        assertFalse(converter.accept(String.class, Queue.class));\n        assertFalse(converter.accept(String.class, BlockingQueue.class));\n        assertFalse(converter.accept(String.class, TransferQueue.class));\n        assertFalse(converter.accept(String.class, Deque.class));\n        assertTrue(converter.accept(String.class, BlockingDeque.class));\n\n        assertFalse(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() throws NoSuchFieldException {\n\n        BlockingQueue<Integer> values = new LinkedBlockingDeque(asList(1, 2, 3));\n\n        BlockingDeque<Integer> result =\n                (BlockingDeque<Integer>) converter.convert(\"1,2,3\", BlockingDeque.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        values = new LinkedBlockingDeque(asList(123));\n\n        result = (BlockingDeque<Integer>) converter.convert(\"123\", BlockingDeque.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        assertNull(converter.convert(null, Collection.class, null));\n        assertNull(converter.convert(\"\", Collection.class, null));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        // Since JDK21, add SequencedCollection\n        assertEquals(\n                Integer.MAX_VALUE - (JRE.currentVersion().compareTo(JRE.JAVA_21) >= 0 ? 6 : 5),\n                converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToBlockingQueueConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\n\nimport java.util.AbstractList;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToBlockingQueueConverter} Test\n *\n * @see BlockingDeque\n * @since 2.7.6\n */\nclass StringToBlockingQueueConverterTest {\n\n    private MultiValueConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = getExtensionLoader(MultiValueConverter.class).getExtension(\"string-to-blocking-queue\");\n    }\n\n    @Test\n    void testAccept() {\n\n        assertFalse(converter.accept(String.class, Collection.class));\n\n        assertFalse(converter.accept(String.class, List.class));\n        assertFalse(converter.accept(String.class, AbstractList.class));\n        assertFalse(converter.accept(String.class, ArrayList.class));\n        assertFalse(converter.accept(String.class, LinkedList.class));\n\n        assertFalse(converter.accept(String.class, Set.class));\n        assertFalse(converter.accept(String.class, SortedSet.class));\n        assertFalse(converter.accept(String.class, NavigableSet.class));\n        assertFalse(converter.accept(String.class, TreeSet.class));\n        assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class));\n\n        assertFalse(converter.accept(String.class, Queue.class));\n        assertTrue(converter.accept(String.class, BlockingQueue.class));\n        assertTrue(converter.accept(String.class, TransferQueue.class));\n        assertFalse(converter.accept(String.class, Deque.class));\n        assertTrue(converter.accept(String.class, BlockingDeque.class));\n\n        assertFalse(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() {\n\n        BlockingQueue values = new ArrayBlockingQueue(3);\n        values.offer(1);\n        values.offer(2);\n        values.offer(3);\n\n        BlockingQueue<Integer> result =\n                (BlockingQueue<Integer>) converter.convert(\"1,2,3\", BlockingDeque.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        values.clear();\n        values.offer(123);\n\n        result = (BlockingQueue<Integer>) converter.convert(\"123\", BlockingDeque.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        assertNull(converter.convert(null, Collection.class, null));\n        assertNull(converter.convert(\"\", Collection.class, null));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        assertEquals(Integer.MAX_VALUE - 3, converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToCollectionConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport java.util.AbstractList;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToCollectionConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToCollectionConverterTest {\n\n    private MultiValueConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = getExtensionLoader(MultiValueConverter.class).getExtension(\"string-to-collection\");\n    }\n\n    @Test\n    void testAccept() {\n\n        assertTrue(converter.accept(String.class, Collection.class));\n\n        assertTrue(converter.accept(String.class, List.class));\n        assertTrue(converter.accept(String.class, AbstractList.class));\n        assertTrue(converter.accept(String.class, ArrayList.class));\n        assertTrue(converter.accept(String.class, LinkedList.class));\n\n        assertTrue(converter.accept(String.class, Set.class));\n        assertTrue(converter.accept(String.class, SortedSet.class));\n        assertTrue(converter.accept(String.class, NavigableSet.class));\n        assertTrue(converter.accept(String.class, TreeSet.class));\n        assertTrue(converter.accept(String.class, ConcurrentSkipListSet.class));\n\n        assertTrue(converter.accept(String.class, Queue.class));\n        assertTrue(converter.accept(String.class, BlockingQueue.class));\n        assertTrue(converter.accept(String.class, TransferQueue.class));\n        assertTrue(converter.accept(String.class, Deque.class));\n        assertTrue(converter.accept(String.class, BlockingDeque.class));\n\n        assertFalse(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() {\n\n        List values = asList(1L, 2L, 3L);\n\n        Collection result = (Collection<Long>) converter.convert(\"1,2,3\", Collection.class, Long.class);\n\n        assertEquals(values, result);\n\n        values = asList(123);\n\n        result = (Collection<Integer>) converter.convert(\"123\", Collection.class, Integer.class);\n\n        assertEquals(values, result);\n\n        assertNull(converter.convert(null, Collection.class, Integer.class));\n        assertNull(converter.convert(\"\", Collection.class, Integer.class));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        assertEquals(Integer.MAX_VALUE - 1, converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToDequeConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JRE;\n\nimport java.util.AbstractList;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToDequeConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToDequeConverterTest {\n\n    private MultiValueConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = getExtensionLoader(MultiValueConverter.class).getExtension(\"string-to-deque\");\n    }\n\n    @Test\n    void testAccept() {\n\n        assertFalse(converter.accept(String.class, Collection.class));\n\n        assertFalse(converter.accept(String.class, List.class));\n        assertFalse(converter.accept(String.class, AbstractList.class));\n        assertTrue(converter.accept(String.class, LinkedList.class));\n        assertFalse(converter.accept(String.class, ArrayList.class));\n\n        assertFalse(converter.accept(String.class, Queue.class));\n        assertFalse(converter.accept(String.class, BlockingQueue.class));\n        assertFalse(converter.accept(String.class, TransferQueue.class));\n        assertTrue(converter.accept(String.class, Deque.class));\n        assertTrue(converter.accept(String.class, BlockingDeque.class));\n\n        assertFalse(converter.accept(String.class, Set.class));\n        assertFalse(converter.accept(String.class, SortedSet.class));\n        assertFalse(converter.accept(String.class, NavigableSet.class));\n        assertFalse(converter.accept(String.class, TreeSet.class));\n        assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class));\n\n        assertFalse(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() {\n\n        Deque values = new ArrayDeque(asList(1, 2, 3));\n\n        Deque result = (Deque) converter.convert(\"1,2,3\", Deque.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        values = new ArrayDeque(asList(\"123\"));\n\n        result = (Deque) converter.convert(\"123\", Deque.class, String.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        assertNull(converter.convert(null, Collection.class, Integer.class));\n        assertNull(converter.convert(\"\", Collection.class, null));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        // Since JDK21, add SequencedCollection\n        assertEquals(\n                Integer.MAX_VALUE - (JRE.currentVersion().compareTo(JRE.JAVA_21) >= 0 ? 4 : 3),\n                converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToListConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JRE;\n\nimport java.util.AbstractList;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToListConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToListConverterTest {\n\n    private MultiValueConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = getExtensionLoader(MultiValueConverter.class).getExtension(\"string-to-list\");\n    }\n\n    @Test\n    void testAccept() {\n\n        assertFalse(converter.accept(String.class, Collection.class));\n\n        assertTrue(converter.accept(String.class, List.class));\n        assertTrue(converter.accept(String.class, AbstractList.class));\n        assertTrue(converter.accept(String.class, LinkedList.class));\n        assertTrue(converter.accept(String.class, ArrayList.class));\n\n        assertFalse(converter.accept(String.class, Set.class));\n        assertFalse(converter.accept(String.class, SortedSet.class));\n        assertFalse(converter.accept(String.class, NavigableSet.class));\n        assertFalse(converter.accept(String.class, TreeSet.class));\n        assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class));\n\n        assertFalse(converter.accept(String.class, Queue.class));\n        assertFalse(converter.accept(String.class, BlockingQueue.class));\n        assertFalse(converter.accept(String.class, TransferQueue.class));\n        assertFalse(converter.accept(String.class, Deque.class));\n        assertFalse(converter.accept(String.class, BlockingDeque.class));\n\n        assertFalse(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() {\n\n        List values = asList(1, 2, 3);\n\n        List result = (List<Integer>) converter.convert(\"1,2,3\", List.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        values = asList(\"123\");\n\n        result = (List<String>) converter.convert(\"123\", List.class, String.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        assertNull(converter.convert(null, Collection.class, Integer.class));\n        assertNull(converter.convert(\"\", Collection.class, null));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        // Since JDK21, add SequencedCollection\n        assertEquals(\n                Integer.MAX_VALUE - (JRE.currentVersion().compareTo(JRE.JAVA_21) >= 0 ? 3 : 2),\n                converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToNavigableSetConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JRE;\n\nimport java.util.AbstractList;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToNavigableSetConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToNavigableSetConverterTest {\n\n    private MultiValueConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = getExtensionLoader(MultiValueConverter.class).getExtension(\"string-to-navigable-set\");\n    }\n\n    @Test\n    void testAccept() {\n\n        assertFalse(converter.accept(String.class, Collection.class));\n\n        assertFalse(converter.accept(String.class, List.class));\n        assertFalse(converter.accept(String.class, AbstractList.class));\n        assertFalse(converter.accept(String.class, LinkedList.class));\n        assertFalse(converter.accept(String.class, ArrayList.class));\n\n        assertFalse(converter.accept(String.class, Set.class));\n        assertFalse(converter.accept(String.class, SortedSet.class));\n        assertTrue(converter.accept(String.class, NavigableSet.class));\n        assertTrue(converter.accept(String.class, TreeSet.class));\n        assertTrue(converter.accept(String.class, ConcurrentSkipListSet.class));\n\n        assertFalse(converter.accept(String.class, Queue.class));\n        assertFalse(converter.accept(String.class, BlockingQueue.class));\n        assertFalse(converter.accept(String.class, TransferQueue.class));\n        assertFalse(converter.accept(String.class, Deque.class));\n        assertFalse(converter.accept(String.class, BlockingDeque.class));\n\n        assertFalse(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() {\n\n        Set values = new TreeSet(asList(1, 2, 3));\n\n        NavigableSet result = (NavigableSet) converter.convert(\"1,2,3\", List.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        values = new TreeSet(asList(\"123\"));\n\n        result = (NavigableSet) converter.convert(\"123\", NavigableSet.class, String.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        assertNull(converter.convert(null, Collection.class, Integer.class));\n        assertNull(converter.convert(\"\", Collection.class, null));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        // Since JDK21, add SequencedCollection, SequencedSet\n        assertEquals(\n                Integer.MAX_VALUE - (JRE.currentVersion().compareTo(JRE.JAVA_21) >= 0 ? 6 : 4),\n                converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToQueueConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.AbstractList;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToQueueConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToQueueConverterTest {\n\n    private StringToQueueConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = new StringToQueueConverter(FrameworkModel.defaultModel());\n    }\n\n    @Test\n    void testAccept() {\n\n        assertFalse(converter.accept(String.class, Collection.class));\n\n        assertFalse(converter.accept(String.class, List.class));\n        assertFalse(converter.accept(String.class, AbstractList.class));\n        assertTrue(converter.accept(String.class, LinkedList.class));\n        assertFalse(converter.accept(String.class, ArrayList.class));\n\n        assertTrue(converter.accept(String.class, Queue.class));\n        assertTrue(converter.accept(String.class, BlockingQueue.class));\n        assertTrue(converter.accept(String.class, TransferQueue.class));\n        assertTrue(converter.accept(String.class, Deque.class));\n        assertTrue(converter.accept(String.class, BlockingDeque.class));\n\n        assertFalse(converter.accept(String.class, Set.class));\n        assertFalse(converter.accept(String.class, SortedSet.class));\n        assertFalse(converter.accept(String.class, NavigableSet.class));\n        assertFalse(converter.accept(String.class, TreeSet.class));\n        assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class));\n\n        assertFalse(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() {\n\n        Queue values = new ArrayDeque(asList(1.0, 2.0, 3.0));\n\n        Queue result = (Queue<Double>) converter.convert(\"1.0,2.0,3.0\", Queue.class, Double.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        values.clear();\n        values.add(123);\n\n        result = (Queue) converter.convert(\"123\", Queue.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        assertNull(converter.convert(null, Collection.class, Integer.class));\n        assertNull(converter.convert(\"\", Collection.class, null));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        assertEquals(Integer.MAX_VALUE - 2, converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToSetConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.AbstractList;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToSetConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToSetConverterTest {\n\n    private StringToSetConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = new StringToSetConverter(FrameworkModel.defaultModel());\n    }\n\n    @Test\n    void testAccept() {\n\n        assertFalse(converter.accept(String.class, Collection.class));\n\n        assertFalse(converter.accept(String.class, List.class));\n        assertFalse(converter.accept(String.class, AbstractList.class));\n        assertFalse(converter.accept(String.class, LinkedList.class));\n        assertFalse(converter.accept(String.class, ArrayList.class));\n\n        assertTrue(converter.accept(String.class, Set.class));\n        assertTrue(converter.accept(String.class, SortedSet.class));\n        assertTrue(converter.accept(String.class, NavigableSet.class));\n        assertTrue(converter.accept(String.class, TreeSet.class));\n        assertTrue(converter.accept(String.class, ConcurrentSkipListSet.class));\n\n        assertFalse(converter.accept(String.class, Queue.class));\n        assertFalse(converter.accept(String.class, BlockingQueue.class));\n        assertFalse(converter.accept(String.class, TransferQueue.class));\n        assertFalse(converter.accept(String.class, Deque.class));\n        assertFalse(converter.accept(String.class, BlockingDeque.class));\n\n        assertFalse(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() {\n        Set values = new HashSet(asList(1.0, 2.0, 3.0));\n\n        Set result = (Set<Double>) converter.convert(\"1.0,2.0,3.0\", Queue.class, Double.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        values.clear();\n        values.add(123);\n\n        result = (Set) converter.convert(\"123\", Queue.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        assertNull(converter.convert(null, Collection.class, Integer.class));\n        assertNull(converter.convert(\"\", Collection.class, null));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        assertEquals(Integer.MAX_VALUE - 2, converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToSortedSetConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JRE;\n\nimport java.util.AbstractList;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToSortedSetConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToSortedSetConverterTest {\n\n    private MultiValueConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = getExtensionLoader(MultiValueConverter.class).getExtension(\"string-to-sorted-set\");\n    }\n\n    @Test\n    void testAccept() {\n\n        assertFalse(converter.accept(String.class, Collection.class));\n\n        assertFalse(converter.accept(String.class, List.class));\n        assertFalse(converter.accept(String.class, AbstractList.class));\n        assertFalse(converter.accept(String.class, LinkedList.class));\n        assertFalse(converter.accept(String.class, ArrayList.class));\n\n        assertFalse(converter.accept(String.class, Set.class));\n        assertTrue(converter.accept(String.class, SortedSet.class));\n        assertTrue(converter.accept(String.class, NavigableSet.class));\n        assertTrue(converter.accept(String.class, TreeSet.class));\n        assertTrue(converter.accept(String.class, ConcurrentSkipListSet.class));\n\n        assertFalse(converter.accept(String.class, Queue.class));\n        assertFalse(converter.accept(String.class, BlockingQueue.class));\n        assertFalse(converter.accept(String.class, TransferQueue.class));\n        assertFalse(converter.accept(String.class, Deque.class));\n        assertFalse(converter.accept(String.class, BlockingDeque.class));\n\n        assertFalse(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() {\n\n        Set values = new TreeSet(asList(1, 2, 3));\n\n        SortedSet result = (SortedSet) converter.convert(\"1,2,3\", List.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        values = new TreeSet(asList(\"123\"));\n\n        result = (SortedSet) converter.convert(\"123\", NavigableSet.class, String.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        assertNull(converter.convert(null, Collection.class, Integer.class));\n        assertNull(converter.convert(\"\", Collection.class, null));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        // Since JDK21, add SequencedCollection, SequencedSet\n        assertEquals(\n                Integer.MAX_VALUE - (JRE.currentVersion().compareTo(JRE.JAVA_21) >= 0 ? 5 : 3),\n                converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToTransferQueueConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.convert.multiple;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\n\nimport java.util.AbstractList;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.NavigableSet;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.LinkedTransferQueue;\nimport java.util.concurrent.TransferQueue;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringToTransferQueueConverter} Test\n *\n * @since 2.7.6\n */\nclass StringToTransferQueueConverterTest {\n\n    private MultiValueConverter converter;\n\n    @BeforeEach\n    public void init() {\n        converter = getExtensionLoader(MultiValueConverter.class).getExtension(\"string-to-transfer-queue\");\n    }\n\n    @Test\n    void testAccept() {\n\n        assertFalse(converter.accept(String.class, Collection.class));\n\n        assertFalse(converter.accept(String.class, List.class));\n        assertFalse(converter.accept(String.class, AbstractList.class));\n        assertFalse(converter.accept(String.class, LinkedList.class));\n        assertFalse(converter.accept(String.class, ArrayList.class));\n\n        assertFalse(converter.accept(String.class, Set.class));\n        assertFalse(converter.accept(String.class, SortedSet.class));\n        assertFalse(converter.accept(String.class, NavigableSet.class));\n        assertFalse(converter.accept(String.class, TreeSet.class));\n        assertFalse(converter.accept(String.class, ConcurrentSkipListSet.class));\n\n        assertFalse(converter.accept(String.class, Queue.class));\n        assertFalse(converter.accept(String.class, BlockingQueue.class));\n        assertFalse(converter.accept(String.class, Deque.class));\n        assertFalse(converter.accept(String.class, BlockingDeque.class));\n        assertTrue(converter.accept(String.class, TransferQueue.class));\n\n        assertFalse(converter.accept(null, char[].class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, String.class));\n        assertFalse(converter.accept(null, null));\n    }\n\n    @Test\n    void testConvert() {\n\n        TransferQueue values = new LinkedTransferQueue(asList(1, 2, 3));\n\n        TransferQueue result = (TransferQueue) converter.convert(\"1,2,3\", List.class, Integer.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        values.clear();\n\n        values.addAll(asList(\"123\"));\n\n        result = (TransferQueue) converter.convert(\"123\", NavigableSet.class, String.class);\n\n        assertTrue(CollectionUtils.equals(values, result));\n\n        assertNull(converter.convert(null, Collection.class, Integer.class));\n        assertNull(converter.convert(\"\", Collection.class, null));\n    }\n\n    @Test\n    void testGetSourceType() {\n        assertEquals(String.class, converter.getSourceType());\n    }\n\n    @Test\n    void testGetPriority() {\n        assertEquals(Integer.MAX_VALUE - 4, converter.getPriority());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGeneratorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt;\nimport org.apache.dubbo.common.utils.IOUtils;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link AdaptiveClassCodeGenerator} Test\n *\n * @since 2.7.5\n */\nclass AdaptiveClassCodeGeneratorTest {\n\n    @Test\n    void testGenerate() throws IOException {\n        AdaptiveClassCodeGenerator generator = new AdaptiveClassCodeGenerator(HasAdaptiveExt.class, \"adaptive\");\n        String value = generator.generate();\n        URL url = getClass().getResource(\"/org/apache/dubbo/common/extension/adaptive/HasAdaptiveExt$Adaptive\");\n        try (InputStream inputStream = url.openStream()) {\n            String content = IOUtils.read(new InputStreamReader(inputStream, StandardCharsets.UTF_8));\n            // in Windows platform content get from resource contains \\r delimiter\n            content = content.replaceAll(\"\\r\", \"\");\n            assertTrue(content.contains(value));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/DubboExternalLoadingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n/**\n * Dubbo external {@link LoadingStrategy} for testing\n *\n * @since 2.7.7\n */\npublic class DubboExternalLoadingStrategy implements LoadingStrategy {\n\n    @Override\n    public String directory() {\n        return \"META-INF/dubbo/external/\";\n    }\n\n    @Override\n    public boolean overridden() {\n        return true;\n    }\n\n    @Override\n    public int getPriority() {\n        return MAX_PRIORITY + 1;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionDirectorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.extension.director.FooAppService;\nimport org.apache.dubbo.common.extension.director.FooFrameworkService;\nimport org.apache.dubbo.common.extension.director.FooModuleService;\nimport org.apache.dubbo.common.extension.director.impl.TestAppService;\nimport org.apache.dubbo.common.extension.director.impl.TestFrameworkService;\nimport org.apache.dubbo.common.extension.director.impl.TestModuleService;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Collection;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ExtensionDirectorTest {\n\n    String testFwSrvName = \"testFwSrv\";\n    String testAppSrvName = \"testAppSrv\";\n    String testMdSrvName = \"testMdSrv\";\n\n    @Test\n    void testInheritanceAndScope() {\n\n        // Expecting:\n        // 1. SPI extension only be created in ExtensionDirector which matched scope\n        // 2. Child ExtensionDirector can get extension instance from parent\n        // 3. Parent ExtensionDirector can't get extension instance from child\n\n        ExtensionDirector fwExtensionDirector = FrameworkModel.defaultModel().getExtensionDirector();\n        ExtensionDirector appExtensionDirector =\n                new ExtensionDirector(fwExtensionDirector, ExtensionScope.APPLICATION, ApplicationModel.defaultModel());\n        ExtensionDirector moduleExtensionDirector = new ExtensionDirector(\n                appExtensionDirector,\n                ExtensionScope.MODULE,\n                ApplicationModel.defaultModel().getDefaultModule());\n\n        // test module extension loader\n        FooFrameworkService testFwSrvFromModule =\n                moduleExtensionDirector.getExtension(FooFrameworkService.class, testFwSrvName);\n        FooAppService testAppSrvFromModule = moduleExtensionDirector.getExtension(FooAppService.class, testAppSrvName);\n        FooModuleService testMdSrvFromModule =\n                moduleExtensionDirector.getExtension(FooModuleService.class, testMdSrvName);\n\n        Assertions.assertNotNull(testFwSrvFromModule);\n        Assertions.assertNotNull(testAppSrvFromModule);\n        Assertions.assertNotNull(testMdSrvFromModule);\n\n        // test app extension loader\n        FooFrameworkService testFwSrvFromApp =\n                appExtensionDirector.getExtension(FooFrameworkService.class, testFwSrvName);\n        FooAppService testAppSrvFromApp = appExtensionDirector.getExtension(FooAppService.class, testAppSrvName);\n        FooModuleService testMdSrvFromApp = appExtensionDirector.getExtension(FooModuleService.class, testMdSrvName);\n\n        Assertions.assertSame(testFwSrvFromApp, testFwSrvFromModule);\n        Assertions.assertSame(testAppSrvFromApp, testAppSrvFromModule);\n        Assertions.assertNull(testMdSrvFromApp);\n\n        // test framework extension loader\n        FooFrameworkService testFwSrvFromFw =\n                fwExtensionDirector.getExtension(FooFrameworkService.class, testFwSrvName);\n        FooAppService testAppSrvFromFw = fwExtensionDirector.getExtension(FooAppService.class, testAppSrvName);\n        FooModuleService testMdSrvFromFw = fwExtensionDirector.getExtension(FooModuleService.class, testMdSrvName);\n\n        Assertions.assertSame(testFwSrvFromFw, testFwSrvFromApp);\n        Assertions.assertNull(testAppSrvFromFw);\n        Assertions.assertNull(testMdSrvFromFw);\n    }\n\n    @Test\n    void testPostProcessor() {}\n\n    @Test\n    void testModelAware() {\n        // Expecting:\n        // 1. Module scope SPI can be injected ModuleModel, ApplicationModel, FrameworkModel\n        // 2. Application scope SPI can be injected ApplicationModel, FrameworkModel, but not ModuleModel\n        // 3. Framework scope SPI can be injected FrameworkModel, but not ModuleModel, ApplicationModel\n\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        ExtensionDirector moduleExtensionDirector = moduleModel.getExtensionDirector();\n        ExtensionDirector appExtensionDirector = applicationModel.getExtensionDirector();\n        ExtensionDirector fwExtensionDirector = frameworkModel.getExtensionDirector();\n\n        // check extension director inheritance\n        Assertions.assertSame(appExtensionDirector, moduleExtensionDirector.getParent());\n        Assertions.assertSame(fwExtensionDirector, appExtensionDirector.getParent());\n        Assertions.assertSame(null, fwExtensionDirector.getParent());\n\n        // check module extension aware\n        TestFrameworkService testFwSrvFromModule =\n                (TestFrameworkService) moduleExtensionDirector.getExtension(FooFrameworkService.class, testFwSrvName);\n        TestAppService testAppSrvFromModule =\n                (TestAppService) moduleExtensionDirector.getExtension(FooAppService.class, testAppSrvName);\n        TestModuleService testMdSrvFromModule =\n                (TestModuleService) moduleExtensionDirector.getExtension(FooModuleService.class, testMdSrvName);\n\n        Assertions.assertSame(frameworkModel, testFwSrvFromModule.getFrameworkModel());\n        Assertions.assertSame(null, testFwSrvFromModule.getApplicationModel());\n        Assertions.assertSame(null, testFwSrvFromModule.getModuleModel());\n\n        Assertions.assertSame(frameworkModel, testAppSrvFromModule.getFrameworkModel());\n        Assertions.assertSame(applicationModel, testAppSrvFromModule.getApplicationModel());\n        Assertions.assertSame(null, testAppSrvFromModule.getModuleModel());\n\n        Assertions.assertSame(frameworkModel, testMdSrvFromModule.getFrameworkModel());\n        Assertions.assertSame(applicationModel, testMdSrvFromModule.getApplicationModel());\n        Assertions.assertSame(moduleModel, testMdSrvFromModule.getModuleModel());\n\n        // check app extension aware\n        TestFrameworkService testFwSrvFromApp =\n                (TestFrameworkService) appExtensionDirector.getExtension(FooFrameworkService.class, testFwSrvName);\n        TestAppService testAppSrvFromApp =\n                (TestAppService) appExtensionDirector.getExtension(FooAppService.class, testAppSrvName);\n        TestModuleService testMdSrvFromApp =\n                (TestModuleService) appExtensionDirector.getExtension(FooModuleService.class, testMdSrvName);\n\n        Assertions.assertSame(testFwSrvFromApp, testFwSrvFromModule);\n        Assertions.assertSame(testAppSrvFromApp, testAppSrvFromModule);\n        Assertions.assertNull(testMdSrvFromApp);\n\n        // check framework extension aware\n        FooFrameworkService testFwSrvFromFw =\n                fwExtensionDirector.getExtension(FooFrameworkService.class, testFwSrvName);\n        FooAppService testAppSrvFromFw = fwExtensionDirector.getExtension(FooAppService.class, testAppSrvName);\n        FooModuleService testMdSrvFromFw = fwExtensionDirector.getExtension(FooModuleService.class, testMdSrvName);\n\n        Assertions.assertSame(testFwSrvFromFw, testFwSrvFromApp);\n        Assertions.assertNull(testAppSrvFromFw);\n        Assertions.assertNull(testMdSrvFromFw);\n    }\n\n    @Test\n    void testModelDataIsolation() {\n        // Model Tree\n        // ├─frameworkModel1\n        // │  ├─applicationModel11\n        // │  │  ├─moduleModel111\n        // │  │  └─moduleModel112\n        // │  └─applicationModel12\n        // │     └─moduleModel121\n        // └─frameworkModel2\n        //   └─applicationModel21\n        //      └─moduleModel211\n\n        FrameworkModel frameworkModel1 = new FrameworkModel();\n        ApplicationModel applicationModel11 = frameworkModel1.newApplication();\n        ModuleModel moduleModel111 = applicationModel11.newModule();\n        ModuleModel moduleModel112 = applicationModel11.newModule();\n\n        ApplicationModel applicationModel12 = frameworkModel1.newApplication();\n        ModuleModel moduleModel121 = applicationModel12.newModule();\n\n        FrameworkModel frameworkModel2 = new FrameworkModel();\n        ApplicationModel applicationModel21 = frameworkModel2.newApplication();\n        ModuleModel moduleModel211 = applicationModel21.newModule();\n\n        // test model references\n        Collection<ApplicationModel> applicationsOfFw1 = frameworkModel1.getApplicationModels();\n        Assertions.assertEquals(2, applicationsOfFw1.size());\n        Assertions.assertTrue(applicationsOfFw1.contains(applicationModel11));\n        Assertions.assertTrue(applicationsOfFw1.contains(applicationModel12));\n        Assertions.assertFalse(applicationsOfFw1.contains(applicationModel21));\n\n        Collection<ModuleModel> modulesOfApp11 = applicationModel11.getModuleModels();\n        Assertions.assertTrue(modulesOfApp11.contains(moduleModel111));\n        Assertions.assertTrue(modulesOfApp11.contains(moduleModel112));\n\n        // test isolation of FrameworkModel\n        FooFrameworkService frameworkService1 =\n                frameworkModel1.getExtensionDirector().getExtension(FooFrameworkService.class, testFwSrvName);\n        FooFrameworkService frameworkService2 =\n                frameworkModel2.getExtensionDirector().getExtension(FooFrameworkService.class, testFwSrvName);\n        Assertions.assertNotSame(frameworkService1, frameworkService2);\n\n        // test isolation of ApplicationModel\n        // applicationModel11 and applicationModel12 are shared frameworkModel1\n        FooFrameworkService frameworkService11 =\n                applicationModel11.getExtensionDirector().getExtension(FooFrameworkService.class, testFwSrvName);\n        FooFrameworkService frameworkService12 =\n                applicationModel12.getExtensionDirector().getExtension(FooFrameworkService.class, testFwSrvName);\n        Assertions.assertSame(frameworkService1, frameworkService11);\n        Assertions.assertSame(frameworkService1, frameworkService12);\n\n        // applicationModel11 and applicationModel12 are isolated in application scope\n        FooAppService applicationService11 =\n                applicationModel11.getExtensionDirector().getExtension(FooAppService.class, testAppSrvName);\n        FooAppService applicationService12 =\n                applicationModel12.getExtensionDirector().getExtension(FooAppService.class, testAppSrvName);\n        Assertions.assertNotSame(applicationService11, applicationService12);\n\n        // applicationModel11 and applicationModel21 are isolated in both framework and application scope\n        FooFrameworkService frameworkService21 =\n                applicationModel21.getExtensionDirector().getExtension(FooFrameworkService.class, testFwSrvName);\n        FooAppService applicationService21 =\n                applicationModel21.getExtensionDirector().getExtension(FooAppService.class, testAppSrvName);\n        Assertions.assertNotSame(frameworkService11, frameworkService21);\n        Assertions.assertNotSame(applicationService11, applicationService21);\n\n        // test isolation of ModuleModel\n        FooModuleService moduleService111 =\n                moduleModel111.getExtensionDirector().getExtension(FooModuleService.class, testMdSrvName);\n        FooModuleService moduleService112 =\n                moduleModel112.getExtensionDirector().getExtension(FooModuleService.class, testMdSrvName);\n\n        // moduleModel111 and moduleModel112 are isolated in module scope\n        Assertions.assertNotSame(moduleService111, moduleService112);\n\n        // moduleModel111 and moduleModel112 are shared applicationModel11\n        FooAppService applicationService111 =\n                moduleModel111.getExtensionDirector().getExtension(FooAppService.class, testAppSrvName);\n        FooAppService applicationService112 =\n                moduleModel112.getExtensionDirector().getExtension(FooAppService.class, testAppSrvName);\n        Assertions.assertSame(applicationService111, applicationService112);\n\n        // moduleModel111 and moduleModel121 are isolated in application scope, but shared frameworkModel1\n        FooAppService applicationService121 =\n                moduleModel121.getExtensionDirector().getExtension(FooAppService.class, testAppSrvName);\n        Assertions.assertNotSame(applicationService111, applicationService121);\n\n        FooFrameworkService frameworkService111 =\n                moduleModel111.getExtensionDirector().getExtension(FooFrameworkService.class, testFwSrvName);\n        FooFrameworkService frameworkService121 =\n                moduleModel121.getExtensionDirector().getExtension(FooFrameworkService.class, testFwSrvName);\n        Assertions.assertSame(frameworkService111, frameworkService121);\n\n        // moduleModel111 and moduleModel211 are isolated in both framework and application scope\n        FooModuleService moduleService211 =\n                moduleModel211.getExtensionDirector().getExtension(FooModuleService.class, testMdSrvName);\n        FooAppService applicationService211 =\n                moduleModel211.getExtensionDirector().getExtension(FooAppService.class, testAppSrvName);\n        FooFrameworkService frameworkService211 =\n                moduleModel211.getExtensionDirector().getExtension(FooFrameworkService.class, testFwSrvName);\n        Assertions.assertNotSame(moduleService111, moduleService211);\n        Assertions.assertNotSame(applicationService111, applicationService211);\n        Assertions.assertNotSame(frameworkService111, frameworkService211);\n    }\n\n    @Test\n    void testInjection() {\n\n        // Expect:\n        // 1. Framework scope extension can be injected to extensions of Framework/Application/Module scope\n        // 2. Application scope extension can be injected to extensions of Application/Module scope, but not Framework\n        // scope\n        // 3. Module scope extension can be injected to extensions of Module scope, but not Framework/Application scope\n\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        // check module service\n        TestModuleService moduleService = (TestModuleService)\n                moduleModel.getExtensionDirector().getExtension(FooModuleService.class, testMdSrvName);\n        Assertions.assertNotNull(moduleService.getFrameworkService());\n        Assertions.assertNotNull(moduleService.getFrameworkProvider());\n        Assertions.assertNotNull(moduleService.getAppService());\n        Assertions.assertNotNull(moduleService.getAppProvider());\n        Assertions.assertNotNull(moduleService.getModuleProvider());\n\n        // check app service\n        TestAppService appService = (TestAppService)\n                applicationModel.getExtensionDirector().getExtension(FooAppService.class, testAppSrvName);\n        Assertions.assertNotNull(appService.getFrameworkService());\n        Assertions.assertNotNull(appService.getFrameworkProvider());\n        Assertions.assertNotNull(appService.getAppProvider());\n        Assertions.assertNull(appService.getModuleProvider());\n\n        // check framework service\n        TestFrameworkService frameworkService = (TestFrameworkService)\n                frameworkModel.getExtensionDirector().getExtension(FooFrameworkService.class, testFwSrvName);\n        Assertions.assertNotNull(frameworkService.getFrameworkProvider());\n        Assertions.assertNull(frameworkService.getAppProvider());\n        Assertions.assertNull(frameworkService.getModuleProvider());\n\n        Assertions.assertFalse(moduleService.isDestroyed());\n        Assertions.assertFalse(appService.isDestroyed());\n        Assertions.assertFalse(frameworkService.isDestroyed());\n\n        // destroy\n        frameworkModel.destroy();\n        Assertions.assertTrue(moduleService.isDestroyed());\n        Assertions.assertTrue(appService.isDestroyed());\n        Assertions.assertTrue(frameworkService.isDestroyed());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.convert.Converter;\nimport org.apache.dubbo.common.convert.StringToBooleanConverter;\nimport org.apache.dubbo.common.convert.StringToDoubleConverter;\nimport org.apache.dubbo.common.convert.StringToIntegerConverter;\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\nimport org.apache.dubbo.common.extension.activate.impl.ActivateExt1Impl1;\nimport org.apache.dubbo.common.extension.activate.impl.GroupActivateExtImpl;\nimport org.apache.dubbo.common.extension.activate.impl.OrderActivateExtImpl1;\nimport org.apache.dubbo.common.extension.activate.impl.OrderActivateExtImpl2;\nimport org.apache.dubbo.common.extension.activate.impl.ValueActivateExtImpl;\nimport org.apache.dubbo.common.extension.convert.String2BooleanConverter;\nimport org.apache.dubbo.common.extension.convert.String2DoubleConverter;\nimport org.apache.dubbo.common.extension.convert.String2IntegerConverter;\nimport org.apache.dubbo.common.extension.duplicated.DuplicatedOverriddenExt;\nimport org.apache.dubbo.common.extension.duplicated.DuplicatedWithoutOverriddenExt;\nimport org.apache.dubbo.common.extension.ext1.SimpleExt;\nimport org.apache.dubbo.common.extension.ext1.impl.SimpleExtImpl1;\nimport org.apache.dubbo.common.extension.ext1.impl.SimpleExtImpl2;\nimport org.apache.dubbo.common.extension.ext10_multi_names.Ext10MultiNames;\nimport org.apache.dubbo.common.extension.ext11_no_adaptive.NoAdaptiveExt;\nimport org.apache.dubbo.common.extension.ext11_no_adaptive.NoAdaptiveExtImpl;\nimport org.apache.dubbo.common.extension.ext2.Ext2;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExt;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExtWrapper;\nimport org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Impl1;\nimport org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Impl3;\nimport org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Wrapper1;\nimport org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Wrapper2;\nimport org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Wrapper3;\nimport org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Wrapper4;\nimport org.apache.dubbo.common.extension.ext7.InitErrorExt;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt1;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt2;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt3;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt4;\nimport org.apache.dubbo.common.extension.ext8_add.impl.AddExt1Impl1;\nimport org.apache.dubbo.common.extension.ext8_add.impl.AddExt1_ManualAdaptive;\nimport org.apache.dubbo.common.extension.ext8_add.impl.AddExt1_ManualAdd1;\nimport org.apache.dubbo.common.extension.ext8_add.impl.AddExt1_ManualAdd2;\nimport org.apache.dubbo.common.extension.ext8_add.impl.AddExt2_ManualAdaptive;\nimport org.apache.dubbo.common.extension.ext8_add.impl.AddExt3_ManualAdaptive;\nimport org.apache.dubbo.common.extension.ext8_add.impl.AddExt4_ManualAdaptive;\nimport org.apache.dubbo.common.extension.ext9_empty.Ext9Empty;\nimport org.apache.dubbo.common.extension.ext9_empty.impl.Ext9EmptyImpl;\nimport org.apache.dubbo.common.extension.injection.InjectExt;\nimport org.apache.dubbo.common.extension.injection.impl.InjectExtImpl;\nimport org.apache.dubbo.common.extension.wrapper.Demo;\nimport org.apache.dubbo.common.extension.wrapper.impl.DemoImpl;\nimport org.apache.dubbo.common.extension.wrapper.impl.DemoWrapper;\nimport org.apache.dubbo.common.extension.wrapper.impl.DemoWrapper2;\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.extension.ExtensionLoader.getLoadingStrategies;\nimport static org.hamcrest.CoreMatchers.allOf;\nimport static org.hamcrest.CoreMatchers.anyOf;\nimport static org.hamcrest.CoreMatchers.instanceOf;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNotSame;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass ExtensionLoaderTest {\n\n    private <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        return ApplicationModel.defaultModel().getExtensionDirector().getExtensionLoader(type);\n    }\n\n    @Test\n    void test_getExtensionLoader_Null() {\n        try {\n            getExtensionLoader(null);\n            fail();\n        } catch (IllegalArgumentException expected) {\n            assertThat(expected.getMessage(), containsString(\"Extension type == null\"));\n        }\n    }\n\n    @Test\n    void test_getExtensionLoader_NotInterface() {\n        try {\n            getExtensionLoader(ExtensionLoaderTest.class);\n            fail();\n        } catch (IllegalArgumentException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Extension type (class org.apache.dubbo.common.extension.ExtensionLoaderTest) is not an interface\"));\n        }\n    }\n\n    @Test\n    void test_getExtensionLoader_NotSpiAnnotation() {\n        try {\n            getExtensionLoader(NoSpiExt.class);\n            fail();\n        } catch (IllegalArgumentException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    allOf(\n                            containsString(\"org.apache.dubbo.common.extension.NoSpiExt\"),\n                            containsString(\"is not an extension\"),\n                            containsString(\"NOT annotated with @SPI\")));\n        }\n    }\n\n    @Test\n    void test_getDefaultExtension() {\n        SimpleExt ext = getExtensionLoader(SimpleExt.class).getDefaultExtension();\n        assertThat(ext, instanceOf(SimpleExtImpl1.class));\n\n        String name = getExtensionLoader(SimpleExt.class).getDefaultExtensionName();\n        assertEquals(\"impl1\", name);\n    }\n\n    @Test\n    void test_getDefaultExtension_NULL() {\n        Ext2 ext = getExtensionLoader(Ext2.class).getDefaultExtension();\n        assertNull(ext);\n\n        String name = getExtensionLoader(Ext2.class).getDefaultExtensionName();\n        assertNull(name);\n    }\n\n    @Test\n    void test_getExtension() {\n        assertTrue(getExtensionLoader(SimpleExt.class).getExtension(\"impl1\") instanceof SimpleExtImpl1);\n        assertTrue(getExtensionLoader(SimpleExt.class).getExtension(\"impl2\") instanceof SimpleExtImpl2);\n    }\n\n    @Test\n    void test_getExtension_WithWrapper() {\n        WrappedExt impl1 = getExtensionLoader(WrappedExt.class).getExtension(\"impl1\");\n        assertThat(impl1, anyOf(instanceOf(Ext6Wrapper1.class), instanceOf(Ext6Wrapper2.class)));\n        assertThat(impl1, instanceOf(WrappedExtWrapper.class));\n        // get origin instance from wrapper\n        WrappedExt originImpl1 = impl1;\n        while (originImpl1 instanceof WrappedExtWrapper) {\n            originImpl1 = ((WrappedExtWrapper) originImpl1).getOrigin();\n        }\n\n        // test unwrapped instance\n        WrappedExt unwrappedImpl1 = getExtensionLoader(WrappedExt.class).getExtension(\"impl1\", false);\n        assertThat(unwrappedImpl1, instanceOf(Ext6Impl1.class));\n        assertNotSame(unwrappedImpl1, impl1);\n        assertSame(unwrappedImpl1, originImpl1);\n\n        WrappedExt impl2 = getExtensionLoader(WrappedExt.class).getExtension(\"impl2\");\n        assertThat(impl2, anyOf(instanceOf(Ext6Wrapper1.class), instanceOf(Ext6Wrapper2.class)));\n\n        URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\");\n        int echoCount1 = Ext6Wrapper1.echoCount.get();\n        int echoCount2 = Ext6Wrapper2.echoCount.get();\n\n        assertEquals(\"Ext6Impl1-echo\", impl1.echo(url, \"ha\"));\n        assertEquals(echoCount1 + 1, Ext6Wrapper1.echoCount.get());\n        assertEquals(echoCount2 + 1, Ext6Wrapper2.echoCount.get());\n    }\n\n    @Test\n    void test_getExtension_withWrapperAnnotation() {\n        WrappedExt impl3 = getExtensionLoader(WrappedExt.class).getExtension(\"impl3\");\n        assertThat(impl3, instanceOf(Ext6Wrapper3.class));\n        WrappedExt originImpl3 = impl3;\n        while (originImpl3 instanceof WrappedExtWrapper) {\n            originImpl3 = ((WrappedExtWrapper) originImpl3).getOrigin();\n        }\n\n        // test unwrapped instance\n        WrappedExt unwrappedImpl3 = getExtensionLoader(WrappedExt.class).getExtension(\"impl3\", false);\n        assertThat(unwrappedImpl3, instanceOf(Ext6Impl3.class));\n        assertNotSame(unwrappedImpl3, impl3);\n        assertSame(unwrappedImpl3, originImpl3);\n\n        WrappedExt impl4 = getExtensionLoader(WrappedExt.class).getExtension(\"impl4\");\n        assertThat(impl4, instanceOf(Ext6Wrapper4.class));\n\n        URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\");\n        int echoCount3 = Ext6Wrapper3.echoCount.get();\n        int echoCount4 = Ext6Wrapper4.echoCount.get();\n\n        assertEquals(\"Ext6Impl4-echo\", impl4.echo(url, \"haha\"));\n        assertEquals(echoCount3, Ext6Wrapper3.echoCount.get());\n        assertEquals(echoCount4 + 1, Ext6Wrapper4.echoCount.get());\n    }\n\n    @Test\n    void test_getActivateExtension_WithWrapper1() {\n        URL url = URL.valueOf(\"test://localhost/test\");\n        List<ActivateExt1> list =\n                getExtensionLoader(ActivateExt1.class).getActivateExtension(url, new String[] {}, \"order\");\n        assertEquals(2, list.size());\n    }\n\n    @Test\n    void test_getExtension_ExceptionNoExtension() {\n        try {\n            getExtensionLoader(SimpleExt.class).getExtension(\"XXX\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\"No such extension org.apache.dubbo.common.extension.ext1.SimpleExt by name XXX\"));\n        }\n    }\n\n    @Test\n    void test_getExtension_ExceptionNoExtension_WrapperNotAffactName() {\n        try {\n            getExtensionLoader(WrappedExt.class).getExtension(\"XXX\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"No such extension org.apache.dubbo.common.extension.ext6_wrap.WrappedExt by name XXX\"));\n        }\n    }\n\n    @Test\n    void test_getExtension_ExceptionNullArg() {\n        try {\n            getExtensionLoader(SimpleExt.class).getExtension(null);\n            fail();\n        } catch (IllegalArgumentException expected) {\n            assertThat(expected.getMessage(), containsString(\"Extension name == null\"));\n        }\n    }\n\n    @Test\n    void test_hasExtension() {\n        assertTrue(getExtensionLoader(SimpleExt.class).hasExtension(\"impl1\"));\n        assertFalse(getExtensionLoader(SimpleExt.class).hasExtension(\"impl1,impl2\"));\n        assertFalse(getExtensionLoader(SimpleExt.class).hasExtension(\"xxx\"));\n\n        try {\n            getExtensionLoader(SimpleExt.class).hasExtension(null);\n            fail();\n        } catch (IllegalArgumentException expected) {\n            assertThat(expected.getMessage(), containsString(\"Extension name == null\"));\n        }\n    }\n\n    @Test\n    void test_hasExtension_wrapperIsNotExt() {\n        assertTrue(getExtensionLoader(WrappedExt.class).hasExtension(\"impl1\"));\n        assertFalse(getExtensionLoader(WrappedExt.class).hasExtension(\"impl1,impl2\"));\n        assertFalse(getExtensionLoader(WrappedExt.class).hasExtension(\"xxx\"));\n\n        assertFalse(getExtensionLoader(WrappedExt.class).hasExtension(\"wrapper1\"));\n\n        try {\n            getExtensionLoader(WrappedExt.class).hasExtension(null);\n            fail();\n        } catch (IllegalArgumentException expected) {\n            assertThat(expected.getMessage(), containsString(\"Extension name == null\"));\n        }\n    }\n\n    @Test\n    void test_getSupportedExtensions() {\n        Set<String> exts = getExtensionLoader(SimpleExt.class).getSupportedExtensions();\n\n        Set<String> expected = new HashSet<>();\n        expected.add(\"impl1\");\n        expected.add(\"impl2\");\n        expected.add(\"impl3\");\n\n        assertEquals(expected, exts);\n    }\n\n    @Test\n    void test_getSupportedExtensions_wrapperIsNotExt() {\n        Set<String> exts = getExtensionLoader(WrappedExt.class).getSupportedExtensions();\n\n        Set<String> expected = new HashSet<>();\n        expected.add(\"impl1\");\n        expected.add(\"impl2\");\n        expected.add(\"impl3\");\n        expected.add(\"impl4\");\n\n        assertEquals(expected, exts);\n    }\n\n    @Test\n    void test_AddExtension() {\n        try {\n            getExtensionLoader(AddExt1.class).getExtension(\"Manual1\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"No such extension org.apache.dubbo.common.extension.ext8_add.AddExt1 by name Manual\"));\n        }\n\n        getExtensionLoader(AddExt1.class).addExtension(\"Manual1\", AddExt1_ManualAdd1.class);\n        AddExt1 ext = getExtensionLoader(AddExt1.class).getExtension(\"Manual1\");\n\n        assertThat(ext, instanceOf(AddExt1_ManualAdd1.class));\n        assertEquals(\"Manual1\", getExtensionLoader(AddExt1.class).getExtensionName(AddExt1_ManualAdd1.class));\n    }\n\n    @Test\n    void test_AddExtension_NoExtend() {\n        getExtensionLoader(Ext9Empty.class).addExtension(\"ext9\", Ext9EmptyImpl.class);\n        Ext9Empty ext = getExtensionLoader(Ext9Empty.class).getExtension(\"ext9\");\n\n        assertThat(ext, instanceOf(Ext9Empty.class));\n        assertEquals(\"ext9\", getExtensionLoader(Ext9Empty.class).getExtensionName(Ext9EmptyImpl.class));\n    }\n\n    @Test\n    void test_AddExtension_ExceptionWhenExistedExtension() {\n        SimpleExt ext = getExtensionLoader(SimpleExt.class).getExtension(\"impl1\");\n\n        try {\n            getExtensionLoader(AddExt1.class).addExtension(\"impl1\", AddExt1_ManualAdd1.class);\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Extension name impl1 already exists (Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt1)!\"));\n        }\n    }\n\n    @Test\n    void test_AddExtension_Adaptive() {\n        ExtensionLoader<AddExt2> loader = getExtensionLoader(AddExt2.class);\n        loader.addExtension(null, AddExt2_ManualAdaptive.class);\n\n        AddExt2 adaptive = loader.getAdaptiveExtension();\n        assertTrue(adaptive instanceof AddExt2_ManualAdaptive);\n    }\n\n    @Test\n    void test_AddExtension_Adaptive_ExceptionWhenExistedAdaptive() {\n        ExtensionLoader<AddExt1> loader = getExtensionLoader(AddExt1.class);\n\n        loader.getAdaptiveExtension();\n\n        try {\n            loader.addExtension(null, AddExt1_ManualAdaptive.class);\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Adaptive Extension already exists (Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt1)!\"));\n        }\n    }\n\n    @Test\n    void test_addExtension_with_error_class() {\n        try {\n            getExtensionLoader(SimpleExt.class).addExtension(\"impl1\", ExtensionLoaderTest.class);\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Input type class org.apache.dubbo.common.extension.ExtensionLoaderTest \"\n                                    + \"doesn't implement the Extension interface org.apache.dubbo.common.extension.ext1.SimpleExt\"));\n        }\n    }\n\n    @Test\n    void test_addExtension_with_interface() {\n        try {\n            getExtensionLoader(SimpleExt.class).addExtension(\"impl1\", SimpleExt.class);\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\"Input type interface org.apache.dubbo.common.extension.ext1.SimpleExt \"\n                            + \"can't be interface!\"));\n        }\n    }\n\n    @Test\n    void test_addExtension_without_adaptive_annotation() {\n        try {\n            getExtensionLoader(NoAdaptiveExt.class).addExtension(null, NoAdaptiveExtImpl.class);\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Extension name is blank \"\n                                    + \"(Extension interface org.apache.dubbo.common.extension.ext11_no_adaptive.NoAdaptiveExt)!\"));\n        }\n    }\n\n    @Test\n    void test_getLoadedExtension_name_with_null() {\n        try {\n            getExtensionLoader(SimpleExt.class).getLoadedExtension(null);\n        } catch (IllegalArgumentException expected) {\n            assertThat(expected.getMessage(), containsString(\"Extension name == null\"));\n        }\n    }\n\n    @Test\n    void test_getLoadedExtension_null() {\n        SimpleExt impl1 = getExtensionLoader(SimpleExt.class).getLoadedExtension(\"XXX\");\n        assertNull(impl1);\n    }\n\n    @Test\n    void test_getLoadedExtension() {\n        SimpleExt simpleExt = getExtensionLoader(SimpleExt.class).getExtension(\"impl1\");\n        assertThat(simpleExt, instanceOf(SimpleExtImpl1.class));\n\n        SimpleExt simpleExt1 = getExtensionLoader(SimpleExt.class).getLoadedExtension(\"impl1\");\n        assertThat(simpleExt1, instanceOf(SimpleExtImpl1.class));\n    }\n\n    @Test\n    void test_getLoadedExtensions() {\n        SimpleExt simpleExt1 = getExtensionLoader(SimpleExt.class).getExtension(\"impl1\");\n        assertThat(simpleExt1, instanceOf(SimpleExtImpl1.class));\n\n        SimpleExt simpleExt2 = getExtensionLoader(SimpleExt.class).getExtension(\"impl2\");\n        assertThat(simpleExt2, instanceOf(SimpleExtImpl2.class));\n\n        Set<String> loadedExtensions = getExtensionLoader(SimpleExt.class).getLoadedExtensions();\n        Assertions.assertNotNull(loadedExtensions);\n    }\n\n    @Test\n    void test_getLoadedExtensionInstances() {\n        SimpleExt simpleExt1 = getExtensionLoader(SimpleExt.class).getExtension(\"impl1\");\n        assertThat(simpleExt1, instanceOf(SimpleExtImpl1.class));\n\n        SimpleExt simpleExt2 = getExtensionLoader(SimpleExt.class).getExtension(\"impl2\");\n        assertThat(simpleExt2, instanceOf(SimpleExtImpl2.class));\n\n        List<SimpleExt> loadedExtensionInstances =\n                getExtensionLoader(SimpleExt.class).getLoadedExtensionInstances();\n        Assertions.assertNotNull(loadedExtensionInstances);\n    }\n\n    @Test\n    void test_replaceExtension_with_error_class() {\n        try {\n            getExtensionLoader(SimpleExt.class).replaceExtension(\"impl1\", ExtensionLoaderTest.class);\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Input type class org.apache.dubbo.common.extension.ExtensionLoaderTest \"\n                                    + \"doesn't implement Extension interface org.apache.dubbo.common.extension.ext1.SimpleExt\"));\n        }\n    }\n\n    @Test\n    void test_replaceExtension_with_interface() {\n        try {\n            getExtensionLoader(SimpleExt.class).replaceExtension(\"impl1\", SimpleExt.class);\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\"Input type interface org.apache.dubbo.common.extension.ext1.SimpleExt \"\n                            + \"can't be interface!\"));\n        }\n    }\n\n    @Test\n    void test_replaceExtension() {\n        try {\n            getExtensionLoader(AddExt1.class).getExtension(\"Manual2\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"No such extension org.apache.dubbo.common.extension.ext8_add.AddExt1 by name Manual\"));\n        }\n\n        {\n            AddExt1 ext = getExtensionLoader(AddExt1.class).getExtension(\"impl1\");\n\n            assertThat(ext, instanceOf(AddExt1Impl1.class));\n            assertEquals(\"impl1\", getExtensionLoader(AddExt1.class).getExtensionName(AddExt1Impl1.class));\n        }\n        {\n            getExtensionLoader(AddExt1.class).replaceExtension(\"impl1\", AddExt1_ManualAdd2.class);\n            AddExt1 ext = getExtensionLoader(AddExt1.class).getExtension(\"impl1\");\n\n            assertThat(ext, instanceOf(AddExt1_ManualAdd2.class));\n            assertEquals(\"impl1\", getExtensionLoader(AddExt1.class).getExtensionName(AddExt1_ManualAdd2.class));\n        }\n    }\n\n    @Test\n    void test_replaceExtension_Adaptive() {\n        ExtensionLoader<AddExt3> loader = getExtensionLoader(AddExt3.class);\n\n        AddExt3 adaptive = loader.getAdaptiveExtension();\n        assertFalse(adaptive instanceof AddExt3_ManualAdaptive);\n\n        loader.replaceExtension(null, AddExt3_ManualAdaptive.class);\n\n        adaptive = loader.getAdaptiveExtension();\n        assertTrue(adaptive instanceof AddExt3_ManualAdaptive);\n    }\n\n    @Test\n    void test_replaceExtension_ExceptionWhenNotExistedExtension() {\n        AddExt1 ext = getExtensionLoader(AddExt1.class).getExtension(\"impl1\");\n\n        try {\n            getExtensionLoader(AddExt1.class).replaceExtension(\"NotExistedExtension\", AddExt1_ManualAdd1.class);\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Extension name NotExistedExtension doesn't exist (Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt1)\"));\n        }\n    }\n\n    @Test\n    void test_replaceExtension_Adaptive_ExceptionWhenNotExistedExtension() {\n        ExtensionLoader<AddExt4> loader = getExtensionLoader(AddExt4.class);\n\n        try {\n            loader.replaceExtension(null, AddExt4_ManualAdaptive.class);\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Adaptive Extension doesn't exist (Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt4)\"));\n        }\n    }\n\n    @Test\n    void test_InitError() {\n        ExtensionLoader<InitErrorExt> loader = getExtensionLoader(InitErrorExt.class);\n\n        loader.getExtension(\"ok\");\n\n        try {\n            loader.getExtension(\"error\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Failed to load extension class (interface: interface org.apache.dubbo.common.extension.ext7.InitErrorExt\"));\n            assertThat(expected.getMessage(), containsString(\"java.lang.ExceptionInInitializerError\"));\n        }\n    }\n\n    @Test\n    void testLoadActivateExtension() {\n        // test default\n        URL url = URL.valueOf(\"test://localhost/test\");\n        List<ActivateExt1> list =\n                getExtensionLoader(ActivateExt1.class).getActivateExtension(url, new String[] {}, \"default_group\");\n        Assertions.assertEquals(1, list.size());\n        assertSame(list.get(0).getClass(), ActivateExt1Impl1.class);\n\n        // test group\n        url = url.addParameter(GROUP_KEY, \"group1\");\n        list = getExtensionLoader(ActivateExt1.class).getActivateExtension(url, new String[] {}, \"group1\");\n        Assertions.assertEquals(1, list.size());\n        assertSame(list.get(0).getClass(), GroupActivateExtImpl.class);\n\n        // test value\n        url = url.removeParameter(GROUP_KEY);\n        url = url.addParameter(GROUP_KEY, \"value\");\n        url = url.addParameter(\"value\", \"value\");\n        list = getExtensionLoader(ActivateExt1.class).getActivateExtension(url, new String[] {}, \"value\");\n        Assertions.assertEquals(1, list.size());\n        assertSame(list.get(0).getClass(), ValueActivateExtImpl.class);\n\n        // test order\n        url = URL.valueOf(\"test://localhost/test\");\n        url = url.addParameter(GROUP_KEY, \"order\");\n        list = getExtensionLoader(ActivateExt1.class).getActivateExtension(url, new String[] {}, \"order\");\n        Assertions.assertEquals(2, list.size());\n        assertSame(list.get(0).getClass(), OrderActivateExtImpl1.class);\n        assertSame(list.get(1).getClass(), OrderActivateExtImpl2.class);\n    }\n\n    @Test\n    void testLoadDefaultActivateExtension1() {\n        // test default\n        URL url = URL.valueOf(\"test://localhost/test?ext=order1,default\");\n        List<ActivateExt1> list =\n                getExtensionLoader(ActivateExt1.class).getActivateExtension(url, \"ext\", \"default_group\");\n        Assertions.assertEquals(2, list.size());\n        assertSame(list.get(0).getClass(), OrderActivateExtImpl1.class);\n        assertSame(list.get(1).getClass(), ActivateExt1Impl1.class);\n\n        url = URL.valueOf(\"test://localhost/test?ext=default,order1\");\n        list = getExtensionLoader(ActivateExt1.class).getActivateExtension(url, \"ext\", \"default_group\");\n        Assertions.assertEquals(2, list.size());\n        assertSame(list.get(0).getClass(), ActivateExt1Impl1.class);\n        assertSame(list.get(1).getClass(), OrderActivateExtImpl1.class);\n\n        url = URL.valueOf(\"test://localhost/test?ext=order1\");\n        list = getExtensionLoader(ActivateExt1.class).getActivateExtension(url, \"ext\", \"default_group\");\n        Assertions.assertEquals(2, list.size());\n        assertSame(list.get(0).getClass(), ActivateExt1Impl1.class);\n        assertSame(list.get(1).getClass(), OrderActivateExtImpl1.class);\n    }\n\n    @Test\n    void testLoadDefaultActivateExtension2() {\n        // test default\n        URL url = URL.valueOf(\"test://localhost/test?ext=order1  , default\");\n        List<ActivateExt1> list =\n                getExtensionLoader(ActivateExt1.class).getActivateExtension(url, \"ext\", \"default_group\");\n        Assertions.assertEquals(2, list.size());\n        assertSame(list.get(0).getClass(), OrderActivateExtImpl1.class);\n        assertSame(list.get(1).getClass(), ActivateExt1Impl1.class);\n\n        url = URL.valueOf(\"test://localhost/test?ext=default, order1\");\n        list = getExtensionLoader(ActivateExt1.class).getActivateExtension(url, \"ext\", \"default_group\");\n        Assertions.assertEquals(2, list.size());\n        assertSame(list.get(0).getClass(), ActivateExt1Impl1.class);\n        assertSame(list.get(1).getClass(), OrderActivateExtImpl1.class);\n\n        url = URL.valueOf(\"test://localhost/test?ext=order1\");\n        list = getExtensionLoader(ActivateExt1.class).getActivateExtension(url, \"ext\", \"default_group\");\n        Assertions.assertEquals(2, list.size());\n        assertSame(list.get(0).getClass(), ActivateExt1Impl1.class);\n        assertSame(list.get(1).getClass(), OrderActivateExtImpl1.class);\n    }\n\n    @Test\n    void testInjectExtension() {\n        // register bean for test ScopeBeanExtensionInjector\n        DemoImpl demoBean = new DemoImpl();\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(demoBean);\n        // test default\n        InjectExt injectExt = getExtensionLoader(InjectExt.class).getExtension(\"injection\");\n        InjectExtImpl injectExtImpl = (InjectExtImpl) injectExt;\n        Assertions.assertNotNull(injectExtImpl.getSimpleExt());\n        Assertions.assertNull(injectExtImpl.getSimpleExt1());\n        Assertions.assertNull(injectExtImpl.getGenericType());\n        Assertions.assertSame(demoBean, injectExtImpl.getDemo());\n    }\n\n    @Test\n    void testMultiNames() {\n        Ext10MultiNames ext10MultiNames =\n                getExtensionLoader(Ext10MultiNames.class).getExtension(\"impl\");\n        Assertions.assertNotNull(ext10MultiNames);\n        ext10MultiNames = getExtensionLoader(Ext10MultiNames.class).getExtension(\"implMultiName\");\n        Assertions.assertNotNull(ext10MultiNames);\n        Assertions.assertThrows(IllegalStateException.class, () -> getExtensionLoader(Ext10MultiNames.class)\n                .getExtension(\"impl,implMultiName\"));\n    }\n\n    @Test\n    void testGetOrDefaultExtension() {\n        ExtensionLoader<InjectExt> loader = getExtensionLoader(InjectExt.class);\n        InjectExt injectExt = loader.getOrDefaultExtension(\"non-exists\");\n        assertEquals(InjectExtImpl.class, injectExt.getClass());\n        assertEquals(\n                InjectExtImpl.class, loader.getOrDefaultExtension(\"injection\").getClass());\n    }\n\n    @Test\n    void testGetSupported() {\n        ExtensionLoader<InjectExt> loader = getExtensionLoader(InjectExt.class);\n        assertEquals(1, loader.getSupportedExtensions().size());\n        assertEquals(Collections.singleton(\"injection\"), loader.getSupportedExtensions());\n    }\n\n    /**\n     * @since 2.7.7\n     */\n    @Test\n    void testOverridden() {\n        ExtensionLoader<Converter> loader = getExtensionLoader(Converter.class);\n\n        Converter converter = loader.getExtension(\"string-to-boolean\");\n        assertEquals(String2BooleanConverter.class, converter.getClass());\n\n        converter = loader.getExtension(\"string-to-double\");\n        assertEquals(String2DoubleConverter.class, converter.getClass());\n\n        converter = loader.getExtension(\"string-to-integer\");\n        assertEquals(String2IntegerConverter.class, converter.getClass());\n\n        assertEquals(\"string-to-boolean\", loader.getExtensionName(String2BooleanConverter.class));\n        assertEquals(\"string-to-boolean\", loader.getExtensionName(StringToBooleanConverter.class));\n\n        assertEquals(\"string-to-double\", loader.getExtensionName(String2DoubleConverter.class));\n        assertEquals(\"string-to-double\", loader.getExtensionName(StringToDoubleConverter.class));\n\n        assertEquals(\"string-to-integer\", loader.getExtensionName(String2IntegerConverter.class));\n        assertEquals(\"string-to-integer\", loader.getExtensionName(StringToIntegerConverter.class));\n    }\n\n    /**\n     * @since 2.7.7\n     */\n    @Test\n    void testGetLoadingStrategies() {\n        List<LoadingStrategy> strategies = getLoadingStrategies();\n\n        assertEquals(4, strategies.size());\n\n        int i = 0;\n\n        LoadingStrategy loadingStrategy = strategies.get(i++);\n        assertEquals(DubboInternalLoadingStrategy.class, loadingStrategy.getClass());\n        assertEquals(Prioritized.MAX_PRIORITY, loadingStrategy.getPriority());\n\n        loadingStrategy = strategies.get(i++);\n        assertEquals(DubboExternalLoadingStrategy.class, loadingStrategy.getClass());\n        assertEquals(Prioritized.MAX_PRIORITY + 1, loadingStrategy.getPriority());\n\n        loadingStrategy = strategies.get(i++);\n        assertEquals(DubboLoadingStrategy.class, loadingStrategy.getClass());\n        assertEquals(Prioritized.NORMAL_PRIORITY, loadingStrategy.getPriority());\n\n        loadingStrategy = strategies.get(i++);\n        assertEquals(ServicesLoadingStrategy.class, loadingStrategy.getClass());\n        assertEquals(Prioritized.MIN_PRIORITY, loadingStrategy.getPriority());\n    }\n\n    @Test\n    void testDuplicatedImplWithoutOverriddenStrategy() {\n        List<LoadingStrategy> loadingStrategies = ExtensionLoader.getLoadingStrategies();\n        ExtensionLoader.setLoadingStrategies(\n                new DubboExternalLoadingStrategyTest(false), new DubboInternalLoadingStrategyTest(false));\n        ExtensionLoader<DuplicatedWithoutOverriddenExt> extensionLoader =\n                getExtensionLoader(DuplicatedWithoutOverriddenExt.class);\n        try {\n            extensionLoader.getExtension(\"duplicated\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Failed to load extension class (interface: interface org.apache.dubbo.common.extension.duplicated.DuplicatedWithoutOverriddenExt\"));\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"cause: Duplicate extension org.apache.dubbo.common.extension.duplicated.DuplicatedWithoutOverriddenExt name duplicated\"));\n        } finally {\n            // recover the loading strategies\n            ExtensionLoader.setLoadingStrategies(\n                    loadingStrategies.toArray(new LoadingStrategy[loadingStrategies.size()]));\n        }\n    }\n\n    @Test\n    void testDuplicatedImplWithOverriddenStrategy() {\n        List<LoadingStrategy> loadingStrategies = ExtensionLoader.getLoadingStrategies();\n        ExtensionLoader.setLoadingStrategies(\n                new DubboExternalLoadingStrategyTest(true), new DubboInternalLoadingStrategyTest(true));\n        ExtensionLoader<DuplicatedOverriddenExt> extensionLoader = getExtensionLoader(DuplicatedOverriddenExt.class);\n        DuplicatedOverriddenExt duplicatedOverriddenExt = extensionLoader.getExtension(\"duplicated\");\n        assertEquals(\"DuplicatedOverriddenExt1\", duplicatedOverriddenExt.echo());\n        // recover the loading strategies\n        ExtensionLoader.setLoadingStrategies(loadingStrategies.toArray(new LoadingStrategy[loadingStrategies.size()]));\n    }\n\n    @Test\n    void testLoadByDubboInternalSPI() {\n        ExtensionLoader<SPI1> extensionLoader = getExtensionLoader(SPI1.class);\n        SPI1 spi1 = extensionLoader.getExtension(\"1\", true);\n        assertNotNull(spi1);\n\n        ExtensionLoader<SPI2> extensionLoader2 = getExtensionLoader(SPI2.class);\n        SPI2 spi2 = extensionLoader2.getExtension(\"2\", true);\n        assertNotNull(spi2);\n\n        try {\n            ExtensionLoader<SPI3> extensionLoader3 = getExtensionLoader(SPI3.class);\n            SPI3 spi3 = extensionLoader3.getExtension(\"3\", true);\n            assertNotNull(spi3);\n        } catch (IllegalStateException illegalStateException) {\n            if (!illegalStateException.getMessage().contains(\"No such extension\")) {\n                fail();\n            }\n        }\n\n        ExtensionLoader<SPI4> extensionLoader4 = getExtensionLoader(SPI4.class);\n        SPI4 spi4 = extensionLoader4.getExtension(\"4\", true);\n        assertNotNull(spi4);\n    }\n\n    @Test\n    void isWrapperClass() {\n        assertFalse(getExtensionLoader(Demo.class).isWrapperClass(DemoImpl.class));\n        assertTrue(getExtensionLoader(Demo.class).isWrapperClass(DemoWrapper.class));\n        assertTrue(getExtensionLoader(Demo.class).isWrapperClass(DemoWrapper2.class));\n    }\n\n    /**\n     * The external {@link LoadingStrategy}, which can set if it supports overriding.\n     */\n    private static class DubboExternalLoadingStrategyTest implements LoadingStrategy {\n\n        public DubboExternalLoadingStrategyTest(boolean overridden) {\n            this.overridden = overridden;\n        }\n\n        private boolean overridden;\n\n        @Override\n        public String directory() {\n            return \"META-INF/dubbo/external/\";\n        }\n\n        @Override\n        public boolean overridden() {\n            return this.overridden;\n        }\n\n        @Override\n        public int getPriority() {\n            return MAX_PRIORITY + 1;\n        }\n    }\n\n    /**\n     * The internal {@link LoadingStrategy}, which can set if it support overridden\n     */\n    private static class DubboInternalLoadingStrategyTest implements LoadingStrategy {\n\n        public DubboInternalLoadingStrategyTest(boolean overridden) {\n            this.overridden = overridden;\n        }\n\n        private boolean overridden;\n\n        @Override\n        public String directory() {\n            return \"META-INF/dubbo/internal/\";\n        }\n\n        @Override\n        public boolean overridden() {\n            return this.overridden;\n        }\n\n        @Override\n        public int getPriority() {\n            return MAX_PRIORITY;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoader_Activate_Test.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\npublic class ExtensionLoader_Activate_Test {\n\n    @Test\n    void test_onClass() throws Exception {\n        URL url = URL.valueOf(\"test://localhost/test\");\n        ExtensionLoader<ActivateExt1> loader = ExtensionLoader.getExtensionLoader(ActivateExt1.class);\n        List<ActivateExt1> list = loader.getActivateExtension(url, new String[] {}, \"onClass\");\n\n        assertTrue(list == null || list.size() == 0);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoader_Adaptive_Test.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt;\nimport org.apache.dubbo.common.extension.adaptive.impl.HasAdaptiveExt_ManualAdaptive;\nimport org.apache.dubbo.common.extension.ext1.SimpleExt;\nimport org.apache.dubbo.common.extension.ext2.Ext2;\nimport org.apache.dubbo.common.extension.ext2.UrlHolder;\nimport org.apache.dubbo.common.extension.ext3.UseProtocolKeyExt;\nimport org.apache.dubbo.common.extension.ext4.NoUrlParamExt;\nimport org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt;\nimport org.apache.dubbo.common.extension.ext6_inject.Ext6;\nimport org.apache.dubbo.common.extension.ext6_inject.impl.Ext6Impl2;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.LogUtil;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.allOf;\nimport static org.hamcrest.CoreMatchers.containsString;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass ExtensionLoader_Adaptive_Test {\n\n    @Test\n    void test_useAdaptiveClass() throws Exception {\n        ExtensionLoader<HasAdaptiveExt> loader = ExtensionLoader.getExtensionLoader(HasAdaptiveExt.class);\n        HasAdaptiveExt ext = loader.getAdaptiveExtension();\n        assertTrue(ext instanceof HasAdaptiveExt_ManualAdaptive);\n    }\n\n    @Test\n    void test_getAdaptiveExtension_defaultAdaptiveKey() throws Exception {\n        {\n            SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();\n\n            Map<String, String> map = new HashMap<String, String>();\n            URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\", map);\n\n            String echo = ext.echo(url, \"haha\");\n            assertEquals(\"Ext1Impl1-echo\", echo);\n        }\n\n        {\n            SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();\n\n            Map<String, String> map = new HashMap<String, String>();\n            map.put(\"simple.ext\", \"impl2\");\n            URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\", map);\n\n            String echo = ext.echo(url, \"haha\");\n            assertEquals(\"Ext1Impl2-echo\", echo);\n        }\n    }\n\n    @Test\n    void test_getAdaptiveExtension_customizeAdaptiveKey() throws Exception {\n        SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();\n\n        Map<String, String> map = new HashMap<String, String>();\n        map.put(\"key2\", \"impl2\");\n        URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\", map);\n\n        String echo = ext.yell(url, \"haha\");\n        assertEquals(\"Ext1Impl2-yell\", echo);\n\n        url = url.addParameter(\"key1\", \"impl3\"); // note: URL is value's type\n        echo = ext.yell(url, \"haha\");\n        assertEquals(\"Ext1Impl3-yell\", echo);\n    }\n\n    @Test\n    void test_getAdaptiveExtension_protocolKey() throws Exception {\n        UseProtocolKeyExt ext =\n                ExtensionLoader.getExtensionLoader(UseProtocolKeyExt.class).getAdaptiveExtension();\n\n        {\n            String echo = ext.echo(URL.valueOf(\"1.2.3.4:20880\"), \"s\");\n            assertEquals(\"Ext3Impl1-echo\", echo); // default value\n\n            Map<String, String> map = new HashMap<String, String>();\n            URL url = new ServiceConfigURL(\"impl3\", \"1.2.3.4\", 1010, \"path1\", map);\n\n            echo = ext.echo(url, \"s\");\n            assertEquals(\"Ext3Impl3-echo\", echo); // use 2nd key, protocol\n\n            url = url.addParameter(\"key1\", \"impl2\");\n            echo = ext.echo(url, \"s\");\n            assertEquals(\"Ext3Impl2-echo\", echo); // use 1st key, key1\n        }\n\n        {\n            Map<String, String> map = new HashMap<String, String>();\n            URL url = new ServiceConfigURL(null, \"1.2.3.4\", 1010, \"path1\", map);\n            String yell = ext.yell(url, \"s\");\n            assertEquals(\"Ext3Impl1-yell\", yell); // default value\n\n            url = url.addParameter(\"key2\", \"impl2\"); // use 2nd key, key2\n            yell = ext.yell(url, \"s\");\n            assertEquals(\"Ext3Impl2-yell\", yell);\n\n            url = url.setProtocol(\"impl3\"); // use 1st key, protocol\n            yell = ext.yell(url, \"d\");\n            assertEquals(\"Ext3Impl3-yell\", yell);\n        }\n    }\n\n    @Test\n    void test_getAdaptiveExtension_UrlNpe() throws Exception {\n        SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();\n\n        try {\n            ext.echo(null, \"haha\");\n            fail();\n        } catch (IllegalArgumentException e) {\n            assertEquals(\"url == null\", e.getMessage());\n        }\n    }\n\n    @Test\n    void test_getAdaptiveExtension_ExceptionWhenNoAdaptiveMethodOnInterface() throws Exception {\n        try {\n            ExtensionLoader.getExtensionLoader(NoAdaptiveMethodExt.class).getAdaptiveExtension();\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    allOf(\n                            containsString(\n                                    \"Can't create adaptive extension interface org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt\"),\n                            containsString(\n                                    \"No adaptive method exist on extension org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt, refuse to create the adaptive class\")));\n        }\n        // report same error when get is invoked for multiple times\n        try {\n            ExtensionLoader.getExtensionLoader(NoAdaptiveMethodExt.class).getAdaptiveExtension();\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    allOf(\n                            containsString(\n                                    \"Can't create adaptive extension interface org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt\"),\n                            containsString(\n                                    \"No adaptive method exist on extension org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt, refuse to create the adaptive class\")));\n        }\n    }\n\n    @Test\n    void test_getAdaptiveExtension_ExceptionWhenNotAdaptiveMethod() throws Exception {\n        SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();\n\n        Map<String, String> map = new HashMap<String, String>();\n        URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\", map);\n\n        try {\n            ext.bang(url, 33);\n            fail();\n        } catch (UnsupportedOperationException expected) {\n            assertThat(expected.getMessage(), containsString(\"method \"));\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"of interface org.apache.dubbo.common.extension.ext1.SimpleExt is not adaptive method!\"));\n        }\n    }\n\n    @Test\n    void test_getAdaptiveExtension_ExceptionWhenNoUrlAttribute() throws Exception {\n        try {\n            ExtensionLoader.getExtensionLoader(NoUrlParamExt.class).getAdaptiveExtension();\n            fail();\n        } catch (Exception expected) {\n            assertThat(expected.getMessage(), containsString(\"Failed to create adaptive class for interface \"));\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\": not found url parameter or url attribute in parameters of method \"));\n        }\n    }\n\n    @Test\n    void test_urlHolder_getAdaptiveExtension() throws Exception {\n        Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension();\n\n        Map<String, String> map = new HashMap<String, String>();\n        map.put(\"ext2\", \"impl1\");\n        URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\", map);\n\n        UrlHolder holder = new UrlHolder();\n        holder.setUrl(url);\n\n        String echo = ext.echo(holder, \"haha\");\n        assertEquals(\"Ext2Impl1-echo\", echo);\n    }\n\n    @Test\n    void test_urlHolder_getAdaptiveExtension_noExtension() throws Exception {\n        Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension();\n\n        URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\");\n\n        UrlHolder holder = new UrlHolder();\n        holder.setUrl(url);\n\n        try {\n            ext.echo(holder, \"haha\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(expected.getMessage(), containsString(\"Failed to get extension\"));\n        }\n\n        url = url.addParameter(\"ext2\", \"XXX\");\n        holder.setUrl(url);\n        try {\n            ext.echo(holder, \"haha\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(expected.getMessage(), containsString(\"No such extension\"));\n        }\n    }\n\n    @Test\n    void test_urlHolder_getAdaptiveExtension_UrlNpe() throws Exception {\n        Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension();\n\n        try {\n            ext.echo(null, \"haha\");\n            fail();\n        } catch (IllegalArgumentException e) {\n            assertEquals(\"org.apache.dubbo.common.extension.ext2.UrlHolder argument == null\", e.getMessage());\n        }\n\n        try {\n            ext.echo(new UrlHolder(), \"haha\");\n            fail();\n        } catch (IllegalArgumentException e) {\n            assertEquals(\"org.apache.dubbo.common.extension.ext2.UrlHolder argument getUrl() == null\", e.getMessage());\n        }\n    }\n\n    @Test\n    void test_urlHolder_getAdaptiveExtension_ExceptionWhenNotAdativeMethod() throws Exception {\n        Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension();\n\n        Map<String, String> map = new HashMap<String, String>();\n        URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\", map);\n\n        try {\n            ext.bang(url, 33);\n            fail();\n        } catch (UnsupportedOperationException expected) {\n            assertThat(expected.getMessage(), containsString(\"method \"));\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\"of interface org.apache.dubbo.common.extension.ext2.Ext2 is not adaptive method!\"));\n        }\n    }\n\n    @Test\n    void test_urlHolder_getAdaptiveExtension_ExceptionWhenNameNotProvided() throws Exception {\n        Ext2 ext = ExtensionLoader.getExtensionLoader(Ext2.class).getAdaptiveExtension();\n\n        URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\");\n\n        UrlHolder holder = new UrlHolder();\n        holder.setUrl(url);\n\n        try {\n            ext.echo(holder, \"impl1\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(expected.getMessage(), containsString(\"Failed to get extension\"));\n        }\n\n        url = url.addParameter(\"key1\", \"impl1\");\n        holder.setUrl(url);\n        try {\n            ext.echo(holder, \"haha\");\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"Failed to get extension (org.apache.dubbo.common.extension.ext2.Ext2) name from url\"));\n        }\n    }\n\n    @Test\n    void test_getAdaptiveExtension_inject() throws Exception {\n        LogUtil.start();\n        Ext6 ext = ExtensionLoader.getExtensionLoader(Ext6.class).getAdaptiveExtension();\n\n        URL url = new ServiceConfigURL(\"p1\", \"1.2.3.4\", 1010, \"path1\");\n        url = url.addParameters(\"ext6\", \"impl1\");\n\n        assertEquals(\"Ext6Impl1-echo-Ext1Impl1-echo\", ext.echo(url, \"ha\"));\n\n        Assertions.assertTrue(LogUtil.checkNoError(), \"can not find error.\");\n        LogUtil.stop();\n\n        url = url.addParameters(\"simple.ext\", \"impl2\");\n        assertEquals(\"Ext6Impl1-echo-Ext1Impl2-echo\", ext.echo(url, \"ha\"));\n    }\n\n    @Test\n    void test_getAdaptiveExtension_InjectNotExtFail() throws Exception {\n        Ext6 ext = ExtensionLoader.getExtensionLoader(Ext6.class).getExtension(\"impl2\");\n\n        Ext6Impl2 impl = (Ext6Impl2) ext;\n        assertNull(impl.getList());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoader_Adaptive_UseJdkCompiler_Test.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.compiler.support.AdaptiveCompiler;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\n\nclass ExtensionLoader_Adaptive_UseJdkCompiler_Test extends ExtensionLoader_Adaptive_Test {\n    @BeforeAll\n    public static void setUp() throws Exception {\n        AdaptiveCompiler.setDefaultCompiler(\"jdk\");\n    }\n\n    @AfterAll\n    public static void tearDown() throws Exception {\n        AdaptiveCompiler.setDefaultCompiler(\"javassist\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoader_Compatible_Test.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.extension.compatible.CompatibleExt;\nimport org.apache.dubbo.common.extension.compatible.impl.CompatibleExtImpl1;\nimport org.apache.dubbo.common.extension.compatible.impl.CompatibleExtImpl2;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ExtensionLoader_Compatible_Test {\n\n    @Test\n    void test_getExtension() {\n\n        ModuleModel moduleModel = ApplicationModel.defaultModel().getDefaultModule();\n\n        assertTrue(\n                moduleModel.getExtensionLoader(CompatibleExt.class).getExtension(\"impl1\")\n                        instanceof CompatibleExtImpl1);\n        assertTrue(\n                moduleModel.getExtensionLoader(CompatibleExt.class).getExtension(\"impl2\")\n                        instanceof CompatibleExtImpl2);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/NoSpiExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.URL;\n\n/**\n * Has no SPI annotation\n */\npublic interface NoSpiExt {\n    @Adaptive\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/SPI1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n@SPI\npublic interface SPI1 {\n    String sayHello();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/SPI1Impl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n@Activate\npublic class SPI1Impl implements SPI1 {\n    @Override\n    public String sayHello() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/SPI2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n@SPI\npublic interface SPI2 {\n    String sayHello();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/SPI2Impl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n@Activate\npublic class SPI2Impl implements SPI2 {\n    @Override\n    public String sayHello() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/SPI3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n@SPI\npublic interface SPI3 {\n    String sayHello();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/SPI3Impl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n@Activate\npublic class SPI3Impl implements SPI3 {\n    @Override\n    public String sayHello() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/SPI4.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n@SPI\npublic interface SPI4 {\n    String sayHello();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/SPI4Impl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\n@Activate\npublic class SPI4Impl implements SPI4 {\n    @Override\n    public String sayHello() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/ActivateExt1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(\"impl1\")\npublic interface ActivateExt1 {\n    String echo(String msg);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/ActivateWrapperExt1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(\"extImp1\")\npublic interface ActivateWrapperExt1 {\n    String echo(String msg);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/impl/ActivateExt1Impl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\n\n@Activate(\n        order = 1,\n        group = {\"default_group\"})\npublic class ActivateExt1Impl1 implements ActivateExt1 {\n    public String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/impl/ActivateOnClassExt1Impl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\n\n@Activate(\n        group = {\"onClass\"},\n        onClass = \"org.springframework.security.core.context.SecurityContextHolder\")\npublic class ActivateOnClassExt1Impl implements ActivateExt1 {\n    @Override\n    public String echo(String msg) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/impl/ActivateWrapperExt1Impl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.activate.ActivateWrapperExt1;\n\n@Activate(\n        order = 1,\n        group = {\"order\"})\npublic class ActivateWrapperExt1Impl1 implements ActivateWrapperExt1 {\n    public String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/impl/ActivateWrapperExt1Impl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.activate.ActivateWrapperExt1;\n\n@Activate(\n        order = 2,\n        group = {\"order\"})\npublic class ActivateWrapperExt1Impl2 implements ActivateWrapperExt1 {\n    public String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/impl/ActivateWrapperExt1Wrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.activate.ActivateWrapperExt1;\n\npublic class ActivateWrapperExt1Wrapper implements ActivateWrapperExt1 {\n    private ActivateWrapperExt1 activateWrapperExt1;\n\n    public ActivateWrapperExt1Wrapper(ActivateWrapperExt1 activateWrapperExt1) {\n        this.activateWrapperExt1 = activateWrapperExt1;\n    }\n\n    @Override\n    public String echo(String msg) {\n        return activateWrapperExt1.echo(msg);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/impl/GroupActivateExtImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\n\n@Activate(group = {\"group1\", \"group2\"})\npublic class GroupActivateExtImpl implements ActivateExt1 {\n\n    public String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/impl/OrderActivateExtImpl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\n\n@Activate(\n        order = 2,\n        group = {\"order\"})\npublic class OrderActivateExtImpl1 implements ActivateExt1 {\n\n    public String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/impl/OrderActivateExtImpl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\n\n@Activate(\n        order = 100,\n        group = {\"order\"})\npublic class OrderActivateExtImpl2 implements ActivateExt1 {\n\n    public String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/activate/impl/ValueActivateExtImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\n\n@Activate(\n        value = {\"value\"},\n        group = {\"value\"})\npublic class ValueActivateExtImpl implements ActivateExt1 {\n\n    public String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/adaptive/HasAdaptiveExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.adaptive;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface HasAdaptiveExt {\n    @Adaptive\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/adaptive/impl/HasAdaptiveExtImpl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.adaptive.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt;\n\npublic class HasAdaptiveExtImpl1 implements HasAdaptiveExt {\n    public String echo(URL url, String s) {\n        return this.getClass().getSimpleName();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/adaptive/impl/HasAdaptiveExt_ManualAdaptive.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.adaptive.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt;\n\n@Adaptive\npublic class HasAdaptiveExt_ManualAdaptive implements HasAdaptiveExt {\n    public String echo(URL url, String s) {\n        HasAdaptiveExt addExt1 =\n                ExtensionLoader.getExtensionLoader(HasAdaptiveExt.class).getExtension(url.getParameter(\"key\"));\n        return addExt1.echo(url, s);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/compatible/CompatibleExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.compatible;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(\"impl1\")\npublic interface CompatibleExt {\n    @Adaptive\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/compatible/impl/CompatibleExtImpl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.compatible.impl;\n\nimport org.apache.dubbo.common.Extension;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.compatible.CompatibleExt;\n\n@Extension(\"impl1\")\npublic class CompatibleExtImpl1 implements CompatibleExt {\n    public String echo(URL url, String s) {\n        return \"Ext1Impl1-echo\";\n    }\n\n    public String yell(URL url, String s) {\n        return \"Ext1Impl1-yell\";\n    }\n\n    public String bang(URL url, int i) {\n        return \"bang1\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/compatible/impl/CompatibleExtImpl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.compatible.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.compatible.CompatibleExt;\n\npublic class CompatibleExtImpl2 implements CompatibleExt {\n    public String echo(URL url, String s) {\n        return \"Ext1Impl2-echo\";\n    }\n\n    public String yell(URL url, String s) {\n        return \"Ext1Impl2-yell\";\n    }\n\n    public String bang(URL url, int i) {\n        return \"bang2\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/convert/String2BooleanConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.convert;\n\nimport org.apache.dubbo.common.convert.Converter;\nimport org.apache.dubbo.common.convert.StringToBooleanConverter;\n\n/**\n * A {@link Converter} implementation of {@link String} to {@link Boolean}\n *\n * @since 2.7.7\n */\npublic class String2BooleanConverter extends StringToBooleanConverter {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/convert/String2DoubleConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.convert;\n\nimport org.apache.dubbo.common.convert.Converter;\nimport org.apache.dubbo.common.convert.StringToDoubleConverter;\n\n/**\n * A {@link Converter} implementation of {@link String} to {@link Double}\n *\n * @since 2.7.7\n */\npublic class String2DoubleConverter extends StringToDoubleConverter {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/convert/String2IntegerConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.convert;\n\nimport org.apache.dubbo.common.convert.Converter;\nimport org.apache.dubbo.common.convert.StringToIntegerConverter;\n\n/**\n * A {@link Converter} implementation of {@link String} to {@link Integer}\n *\n * @since 2.7.7\n */\npublic class String2IntegerConverter extends StringToIntegerConverter {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/FooAppProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.APPLICATION)\npublic interface FooAppProvider {\n\n    @Adaptive\n    void process(URL url);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/FooAppService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.APPLICATION)\npublic interface FooAppService {\n    @Adaptive\n    void process(URL url);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/FooFrameworkProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface FooFrameworkProvider {\n\n    @Adaptive\n    void process(URL url);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/FooFrameworkService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface FooFrameworkService {\n    @Adaptive\n    void process(URL url);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/FooModuleProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.MODULE)\npublic interface FooModuleProvider {\n\n    @Adaptive\n    void process(URL url);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/FooModuleService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.MODULE)\npublic interface FooModuleService {\n\n    @Adaptive\n    void process(URL url);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/BaseTestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director.impl;\n\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\npublic class BaseTestService implements ScopeModelAware, Disposable {\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n    private volatile boolean destroyed;\n\n    @Override\n    public void setFrameworkModel(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    @Override\n    public void setModuleModel(ModuleModel moduleModel) {\n        this.moduleModel = moduleModel;\n    }\n\n    public FrameworkModel getFrameworkModel() {\n        return frameworkModel;\n    }\n\n    public ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    public ModuleModel getModuleModel() {\n        return moduleModel;\n    }\n\n    @Override\n    public void destroy() {\n        this.destroyed = true;\n    }\n\n    public boolean isDestroyed() {\n        return destroyed;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestAppProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.director.FooAppProvider;\n\npublic class TestAppProvider implements FooAppProvider {\n    @Override\n    public void process(URL url) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestAppService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.director.FooAppProvider;\nimport org.apache.dubbo.common.extension.director.FooAppService;\nimport org.apache.dubbo.common.extension.director.FooFrameworkProvider;\nimport org.apache.dubbo.common.extension.director.FooFrameworkService;\nimport org.apache.dubbo.common.extension.director.FooModuleProvider;\n\npublic class TestAppService extends BaseTestService implements FooAppService {\n\n    private FooFrameworkService frameworkService;\n\n    private FooFrameworkProvider frameworkProvider;\n\n    private FooAppProvider appProvider;\n\n    private FooModuleProvider moduleProvider;\n\n    public FooFrameworkService getFrameworkService() {\n        return frameworkService;\n    }\n\n    public void setFrameworkService(FooFrameworkService frameworkService) {\n        this.frameworkService = frameworkService;\n    }\n\n    public FooAppProvider getAppProvider() {\n        return appProvider;\n    }\n\n    public void setAppProvider(FooAppProvider appProvider) {\n        this.appProvider = appProvider;\n    }\n\n    public FooModuleProvider getModuleProvider() {\n        return moduleProvider;\n    }\n\n    public void setModuleProvider(FooModuleProvider moduleProvider) {\n        this.moduleProvider = moduleProvider;\n    }\n\n    public FooFrameworkProvider getFrameworkProvider() {\n        return frameworkProvider;\n    }\n\n    public void setFrameworkProvider(FooFrameworkProvider frameworkProvider) {\n        this.frameworkProvider = frameworkProvider;\n    }\n\n    @Override\n    public void process(URL url) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestFrameworkProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.director.FooFrameworkProvider;\n\npublic class TestFrameworkProvider implements FooFrameworkProvider {\n    @Override\n    public void process(URL url) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestFrameworkService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.director.FooAppProvider;\nimport org.apache.dubbo.common.extension.director.FooFrameworkProvider;\nimport org.apache.dubbo.common.extension.director.FooFrameworkService;\nimport org.apache.dubbo.common.extension.director.FooModuleProvider;\n\npublic class TestFrameworkService extends BaseTestService implements FooFrameworkService {\n\n    private FooFrameworkProvider frameworkProvider;\n\n    private FooAppProvider appProvider;\n\n    private FooModuleProvider moduleProvider;\n\n    public FooFrameworkProvider getFrameworkProvider() {\n        return frameworkProvider;\n    }\n\n    public void setFrameworkProvider(FooFrameworkProvider frameworkProvider) {\n        this.frameworkProvider = frameworkProvider;\n    }\n\n    public FooAppProvider getAppProvider() {\n        return appProvider;\n    }\n\n    public void setAppProvider(FooAppProvider appProvider) {\n        this.appProvider = appProvider;\n    }\n\n    public FooModuleProvider getModuleProvider() {\n        return moduleProvider;\n    }\n\n    public void setModuleProvider(FooModuleProvider moduleProvider) {\n        this.moduleProvider = moduleProvider;\n    }\n\n    @Override\n    public void process(URL url) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestModuleProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.director.FooModuleProvider;\n\npublic class TestModuleProvider implements FooModuleProvider {\n\n    public void process(URL url) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestModuleService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.director.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.director.FooAppProvider;\nimport org.apache.dubbo.common.extension.director.FooAppService;\nimport org.apache.dubbo.common.extension.director.FooFrameworkProvider;\nimport org.apache.dubbo.common.extension.director.FooFrameworkService;\nimport org.apache.dubbo.common.extension.director.FooModuleProvider;\nimport org.apache.dubbo.common.extension.director.FooModuleService;\n\npublic class TestModuleService extends BaseTestService implements FooModuleService {\n\n    private FooFrameworkService frameworkService;\n\n    private FooFrameworkProvider frameworkProvider;\n\n    private FooAppService appService;\n\n    private FooAppProvider appProvider;\n\n    private FooModuleProvider moduleProvider;\n\n    public FooFrameworkService getFrameworkService() {\n        return frameworkService;\n    }\n\n    public void setFrameworkService(FooFrameworkService frameworkService) {\n        this.frameworkService = frameworkService;\n    }\n\n    public FooAppProvider getAppProvider() {\n        return appProvider;\n    }\n\n    public void setAppProvider(FooAppProvider appProvider) {\n        this.appProvider = appProvider;\n    }\n\n    public FooModuleProvider getModuleProvider() {\n        return moduleProvider;\n    }\n\n    public void setModuleProvider(FooModuleProvider moduleProvider) {\n        this.moduleProvider = moduleProvider;\n    }\n\n    public FooFrameworkProvider getFrameworkProvider() {\n        return frameworkProvider;\n    }\n\n    public void setFrameworkProvider(FooFrameworkProvider frameworkProvider) {\n        this.frameworkProvider = frameworkProvider;\n    }\n\n    public FooAppService getAppService() {\n        return appService;\n    }\n\n    public void setAppService(FooAppService appService) {\n        this.appService = appService;\n    }\n\n    @Override\n    public void process(URL url) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/duplicated/DuplicatedOverriddenExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.duplicated;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * This is an interface for testing duplicated extension\n */\n@SPI\npublic interface DuplicatedOverriddenExt {\n\n    String echo();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/duplicated/DuplicatedWithoutOverriddenExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.duplicated;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * This is an interface for testing duplicated extension\n * see issue: https://github.com/apache/dubbo/issues/3575\n */\n@SPI\npublic interface DuplicatedWithoutOverriddenExt {\n\n    String echo();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/duplicated/impl/DuplicatedOverriddenExt1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.duplicated.impl;\n\nimport org.apache.dubbo.common.extension.duplicated.DuplicatedOverriddenExt;\n\npublic class DuplicatedOverriddenExt1 implements DuplicatedOverriddenExt {\n\n    @Override\n    public String echo() {\n        return \"DuplicatedOverriddenExt1\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/duplicated/impl/DuplicatedOverriddenExt2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.duplicated.impl;\n\nimport org.apache.dubbo.common.extension.duplicated.DuplicatedOverriddenExt;\n\npublic class DuplicatedOverriddenExt2 implements DuplicatedOverriddenExt {\n\n    @Override\n    public String echo() {\n        return \"DuplicatedOverriddenExt2\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/duplicated/impl/DuplicatedWithoutOverriddenExt1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.duplicated.impl;\n\nimport org.apache.dubbo.common.extension.duplicated.DuplicatedWithoutOverriddenExt;\n\npublic class DuplicatedWithoutOverriddenExt1 implements DuplicatedWithoutOverriddenExt {\n\n    @Override\n    public String echo() {\n        return \"DuplicatedWithoutOverriddenExt1\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/duplicated/impl/DuplicatedWithoutOverriddenExt2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.duplicated.impl;\n\nimport org.apache.dubbo.common.extension.duplicated.DuplicatedWithoutOverriddenExt;\n\npublic class DuplicatedWithoutOverriddenExt2 implements DuplicatedWithoutOverriddenExt {\n\n    @Override\n    public String echo() {\n        return \"DuplicatedWithoutOverriddenExt2\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext1/SimpleExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext1;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * Simple extension, has no wrapper\n */\n@SPI(\"impl1\")\npublic interface SimpleExt {\n    // @Adaptive example, do not specify a explicit key.\n    @Adaptive\n    String echo(URL url, String s);\n\n    @Adaptive({\"key1\", \"key2\"})\n    String yell(URL url, String s);\n\n    // no @Adaptive\n    String bang(URL url, int i);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext1/impl/SimpleExtImpl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext1.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext1.SimpleExt;\n\npublic class SimpleExtImpl1 implements SimpleExt {\n    public String echo(URL url, String s) {\n        return \"Ext1Impl1-echo\";\n    }\n\n    public String yell(URL url, String s) {\n        return \"Ext1Impl1-yell\";\n    }\n\n    public String bang(URL url, int i) {\n        return \"bang1\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext1/impl/SimpleExtImpl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext1.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext1.SimpleExt;\n\npublic class SimpleExtImpl2 implements SimpleExt {\n    public String echo(URL url, String s) {\n        return \"Ext1Impl2-echo\";\n    }\n\n    public String yell(URL url, String s) {\n        return \"Ext1Impl2-yell\";\n    }\n\n    public String bang(URL url, int i) {\n        return \"bang2\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext1/impl/SimpleExtImpl3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext1.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext1.SimpleExt;\n\npublic class SimpleExtImpl3 implements SimpleExt {\n    public String echo(URL url, String s) {\n        return \"Ext1Impl3-echo\";\n    }\n\n    public String yell(URL url, String s) {\n        return \"Ext1Impl3-yell\";\n    }\n\n    public String bang(URL url, int i) {\n        return \"bang3\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext10_multi_names/Ext10MultiNames.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext10_multi_names;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface Ext10MultiNames {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext10_multi_names/impl/Ext10MultiNamesImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext10_multi_names.impl;\n\nimport org.apache.dubbo.common.extension.ext10_multi_names.Ext10MultiNames;\n\npublic class Ext10MultiNamesImpl implements Ext10MultiNames {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext11_no_adaptive/NoAdaptiveExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext11_no_adaptive;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * Has no Adaptive annotation\n */\n@SPI\npublic interface NoAdaptiveExt {\n\n    String echo(String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext11_no_adaptive/NoAdaptiveExtImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext11_no_adaptive;\n\npublic class NoAdaptiveExtImpl implements NoAdaptiveExt {\n\n    public String echo(String s) {\n        return \"NoAdaptiveExtImpl-echo\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext2/Ext2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext2;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * Has no default\n */\n@SPI\npublic interface Ext2 {\n    // one of the properties of an argument is an instance of URL.\n    @Adaptive\n    String echo(UrlHolder holder, String s);\n\n    String bang(URL url, int i);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext2/UrlHolder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext2;\n\nimport org.apache.dubbo.common.URL;\n\npublic class UrlHolder {\n    private Double Num;\n\n    private URL url;\n\n    private String name;\n\n    private int age;\n\n    public Double getNum() {\n        return Num;\n    }\n\n    public void setNum(Double num) {\n        Num = num;\n    }\n\n    public URL getUrl() {\n        return url;\n    }\n\n    public void setUrl(URL url) {\n        this.url = url;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext2/impl/Ext2Impl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext2.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext2.Ext2;\nimport org.apache.dubbo.common.extension.ext2.UrlHolder;\n\npublic class Ext2Impl1 implements Ext2 {\n    public String echo(UrlHolder holder, String s) {\n        return \"Ext2Impl1-echo\";\n    }\n\n    public String bang(URL url, int i) {\n        return \"bang1\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext2/impl/Ext2Impl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext2.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext2.Ext2;\nimport org.apache.dubbo.common.extension.ext2.UrlHolder;\n\npublic class Ext2Impl2 implements Ext2 {\n    public String echo(UrlHolder holder, String s) {\n        return \"Ext2Impl2-echo\";\n    }\n\n    public String bang(URL url, int i) {\n        return \"bang2\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext2/impl/Ext2Impl3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext2.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext2.Ext2;\nimport org.apache.dubbo.common.extension.ext2.UrlHolder;\n\npublic class Ext2Impl3 implements Ext2 {\n    public String echo(UrlHolder holder, String s) {\n        return \"Ext2Impl3-echo\";\n    }\n\n    public String bang(URL url, int i) {\n        return \"bang3\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext3/UseProtocolKeyExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext3;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(\"impl1\")\npublic interface UseProtocolKeyExt {\n    // protocol key is the second\n    @Adaptive({\"key1\", \"protocol\"})\n    String echo(URL url, String s);\n\n    // protocol key is the first\n    @Adaptive({\"protocol\", \"key2\"})\n    String yell(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext3/impl/UseProtocolKeyExtImpl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext3.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext3.UseProtocolKeyExt;\n\npublic class UseProtocolKeyExtImpl1 implements UseProtocolKeyExt {\n    public String echo(URL url, String s) {\n        return \"Ext3Impl1-echo\";\n    }\n\n    public String yell(URL url, String s) {\n        return \"Ext3Impl1-yell\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext3/impl/UseProtocolKeyExtImpl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext3.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext3.UseProtocolKeyExt;\n\npublic class UseProtocolKeyExtImpl2 implements UseProtocolKeyExt {\n    public String echo(URL url, String s) {\n        return \"Ext3Impl2-echo\";\n    }\n\n    public String yell(URL url, String s) {\n        return \"Ext3Impl2-yell\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext3/impl/UseProtocolKeyExtImpl3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext3.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext3.UseProtocolKeyExt;\n\npublic class UseProtocolKeyExtImpl3 implements UseProtocolKeyExt {\n    public String echo(URL url, String s) {\n        return \"Ext3Impl3-echo\";\n    }\n\n    public String yell(URL url, String s) {\n        return \"Ext3Impl3-yell\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext4/NoUrlParamExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext4;\n\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.List;\n\n@SPI(\"impl1\")\npublic interface NoUrlParamExt {\n    // method has no URL parameter\n    @Adaptive\n    String bark(String name, List<Object> list);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext4/impl/Ext4Impl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext4.impl;\n\nimport org.apache.dubbo.common.extension.ext4.NoUrlParamExt;\n\nimport java.util.List;\n\npublic class Ext4Impl1 implements NoUrlParamExt {\n    public String bark(String name, List<Object> list) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext4/impl/Ext4Impl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext4.impl;\n\nimport org.apache.dubbo.common.extension.ext4.NoUrlParamExt;\n\nimport java.util.List;\n\npublic class Ext4Impl2 implements NoUrlParamExt {\n    public String bark(String name, List<Object> list) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext5/NoAdaptiveMethodExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext5;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * No Adaptive Method!!\n */\n@SPI(\"impl1\")\npublic interface NoAdaptiveMethodExt {\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext5/impl/Ext5Impl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext5.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt;\n\npublic class Ext5Impl1 implements NoAdaptiveMethodExt {\n    public String echo(URL url, String s) {\n        return \"Ext5Impl1-echo\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext5/impl/Ext5Impl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext5.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt;\n\npublic class Ext5Impl2 implements NoAdaptiveMethodExt {\n    public String echo(URL url, String s) {\n        return \"Ext5Impl2-echo\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_inject/Dao.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_inject;\n\npublic interface Dao {\n    void update();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_inject/Ext6.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_inject;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * No default\n */\n@SPI\npublic interface Ext6 {\n    @Adaptive\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_inject/impl/DaoImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_inject.impl;\n\nimport org.apache.dubbo.common.extension.ext6_inject.Dao;\n\npublic class DaoImpl implements Dao {\n    public void update() {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_inject/impl/Ext6Impl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_inject.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext1.SimpleExt;\nimport org.apache.dubbo.common.extension.ext6_inject.Dao;\nimport org.apache.dubbo.common.extension.ext6_inject.Ext6;\n\nimport org.junit.jupiter.api.Assertions;\n\npublic class Ext6Impl1 implements Ext6 {\n    public Dao obj;\n    SimpleExt ext1;\n\n    public void setDao(Dao obj) {\n        Assertions.assertNotNull(obj, \"inject extension instance can not be null\");\n        Assertions.fail();\n    }\n\n    public void setExt1(SimpleExt ext1) {\n        this.ext1 = ext1;\n    }\n\n    public String echo(URL url, String s) {\n        return \"Ext6Impl1-echo-\" + ext1.echo(url, s);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_inject/impl/Ext6Impl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_inject.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext6_inject.Ext6;\n\nimport java.util.List;\n\npublic class Ext6Impl2 implements Ext6 {\n    List<String> list;\n\n    public List<String> getList() {\n        return list;\n    }\n\n    public void setList(List<String> list) {\n        this.list = list;\n    }\n\n    public String echo(URL url, String s) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_wrap/WrappedExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_wrap;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * No Adaptive Method!!\n */\n@SPI(\"impl1\")\npublic interface WrappedExt {\n\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_wrap/WrappedExtWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_wrap;\n\npublic interface WrappedExtWrapper {\n\n    WrappedExt getOrigin();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_wrap/impl/Ext6Impl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_wrap.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExt;\n\npublic class Ext6Impl1 implements WrappedExt {\n    public String echo(URL url, String s) {\n        return \"Ext6Impl1-echo\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_wrap/impl/Ext6Impl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_wrap.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExt;\n\npublic class Ext6Impl2 implements WrappedExt {\n    public String echo(URL url, String s) {\n        return \"Ext6Impl2-echo\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_wrap/impl/Ext6Impl3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_wrap.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExt;\n\npublic class Ext6Impl3 implements WrappedExt {\n\n    @Override\n    public String echo(URL url, String s) {\n        return \"Ext6Impl3-echo\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_wrap/impl/Ext6Impl4.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_wrap.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExt;\n\npublic class Ext6Impl4 implements WrappedExt {\n\n    @Override\n    public String echo(URL url, String s) {\n        return \"Ext6Impl4-echo\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_wrap/impl/Ext6Wrapper1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_wrap.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Wrapper;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExt;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExtWrapper;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\n@Wrapper(matches = {\"impl1\", \"impl2\"})\npublic class Ext6Wrapper1 implements WrappedExt, WrappedExtWrapper {\n    public static AtomicInteger echoCount = new AtomicInteger();\n    WrappedExt origin;\n\n    public Ext6Wrapper1(WrappedExt origin) {\n        this.origin = origin;\n    }\n\n    public String echo(URL url, String s) {\n        echoCount.incrementAndGet();\n        return origin.echo(url, s);\n    }\n\n    @Override\n    public WrappedExt getOrigin() {\n        return origin;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_wrap/impl/Ext6Wrapper2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_wrap.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Wrapper;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExt;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExtWrapper;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\n@Wrapper(mismatches = {\"impl3\", \"impl4\"})\npublic class Ext6Wrapper2 implements WrappedExt, WrappedExtWrapper {\n    public static AtomicInteger echoCount = new AtomicInteger();\n    WrappedExt origin;\n\n    public Ext6Wrapper2(WrappedExt origin) {\n        this.origin = origin;\n    }\n\n    public String echo(URL url, String s) {\n        echoCount.incrementAndGet();\n        return origin.echo(url, s);\n    }\n\n    public WrappedExt getOrigin() {\n        return origin;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_wrap/impl/Ext6Wrapper3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_wrap.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Wrapper;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExt;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExtWrapper;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\n@Wrapper(\n        matches = {\"impl3\"},\n        order = 3)\npublic class Ext6Wrapper3 implements WrappedExt, WrappedExtWrapper {\n    public static AtomicInteger echoCount = new AtomicInteger();\n    WrappedExt origin;\n\n    public Ext6Wrapper3(WrappedExt origin) {\n        this.origin = origin;\n    }\n\n    public String echo(URL url, String s) {\n        echoCount.incrementAndGet();\n        return origin.echo(url, s);\n    }\n\n    public WrappedExt getOrigin() {\n        return origin;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext6_wrap/impl/Ext6Wrapper4.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext6_wrap.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Wrapper;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExt;\nimport org.apache.dubbo.common.extension.ext6_wrap.WrappedExtWrapper;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\n@Wrapper(\n        mismatches = {\"impl1\", \"impl2\"},\n        order = 4)\npublic class Ext6Wrapper4 implements WrappedExt, WrappedExtWrapper {\n    public static AtomicInteger echoCount = new AtomicInteger();\n    WrappedExt origin;\n\n    public Ext6Wrapper4(WrappedExt origin) {\n        this.origin = origin;\n    }\n\n    public String echo(URL url, String s) {\n        echoCount.incrementAndGet();\n        return origin.echo(url, s);\n    }\n\n    public WrappedExt getOrigin() {\n        return origin;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext7/InitErrorExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext7;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * Test scenario for DUBBO-144: extension load failure when third-party dependency doesn't exist. If extension is not\n * referenced/used, do not report error in load time (instead, report issue when it gets used)\n */\n@SPI\npublic interface InitErrorExt {\n    @Adaptive\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext7/impl/Ext7Impl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext7.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext7.InitErrorExt;\n\npublic class Ext7Impl implements InitErrorExt {\n    public String echo(URL url, String s) {\n        return \"\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext7/impl/Ext7InitErrorImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext7.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext7.InitErrorExt;\n\npublic class Ext7InitErrorImpl implements InitErrorExt {\n\n    static {\n        if (true) {\n            throw new RuntimeException(\"intended!\");\n        }\n    }\n\n    public String echo(URL url, String s) {\n        return \"\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/AddExt1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * show add extension pragmatically\n */\n@SPI(\"impl1\")\npublic interface AddExt1 {\n    @Adaptive\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/AddExt2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * show add extension pragmatically. use for test addAdaptive successful\n */\n@SPI(\"impl1\")\npublic interface AddExt2 {\n    @Adaptive\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/AddExt3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * show add extension pragmatically. use for test replaceAdaptive success\n */\n@SPI(\"impl1\")\npublic interface AddExt3 {\n    @Adaptive\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/AddExt4.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * show add extension pragmatically. use for test replaceAdaptive fail\n */\n@SPI(\"impl1\")\npublic interface AddExt4 {\n    @Adaptive\n    String echo(URL url, String s);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/impl/AddExt1Impl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt1;\n\npublic class AddExt1Impl1 implements AddExt1 {\n    public String echo(URL url, String s) {\n        return this.getClass().getSimpleName();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/impl/AddExt1_ManualAdaptive.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt1;\n\n@Adaptive\npublic class AddExt1_ManualAdaptive implements AddExt1 {\n    public String echo(URL url, String s) {\n        AddExt1 addExt1 = ExtensionLoader.getExtensionLoader(AddExt1.class).getExtension(url.getParameter(\"add.ext1\"));\n        return addExt1.echo(url, s);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/impl/AddExt1_ManualAdd1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt1;\n\npublic class AddExt1_ManualAdd1 implements AddExt1 {\n    public String echo(URL url, String s) {\n        return this.getClass().getSimpleName();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/impl/AddExt1_ManualAdd2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt1;\n\npublic class AddExt1_ManualAdd2 implements AddExt1 {\n    public String echo(URL url, String s) {\n        return this.getClass().getSimpleName();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/impl/AddExt2Impl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt2;\n\npublic class AddExt2Impl1 implements AddExt2 {\n    public String echo(URL url, String s) {\n        return this.getClass().getSimpleName();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/impl/AddExt2_ManualAdaptive.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt2;\n\n@Adaptive\npublic class AddExt2_ManualAdaptive implements AddExt2 {\n    public String echo(URL url, String s) {\n        AddExt2 addExt1 = ExtensionLoader.getExtensionLoader(AddExt2.class).getExtension(url.getParameter(\"add.ext2\"));\n        return addExt1.echo(url, s);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/impl/AddExt3_ManualAdaptive.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt3;\n\n@Adaptive\npublic class AddExt3_ManualAdaptive implements AddExt3 {\n    public String echo(URL url, String s) {\n        AddExt3 addExt1 = ExtensionLoader.getExtensionLoader(AddExt3.class).getExtension(url.getParameter(\"add.ext3\"));\n        return addExt1.echo(url, s);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext8_add/impl/AddExt4_ManualAdaptive.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext8_add.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.ext8_add.AddExt4;\n\n@Adaptive\npublic class AddExt4_ManualAdaptive implements AddExt4 {\n    public String echo(URL url, String s) {\n        AddExt4 addExt1 = ExtensionLoader.getExtensionLoader(AddExt4.class).getExtension(url.getParameter(\"add.ext4\"));\n        return addExt1.echo(url, s);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext9_empty/Ext9Empty.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext9_empty;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface Ext9Empty {\n    void empty();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/ext9_empty/impl/Ext9EmptyImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.ext9_empty.impl;\n\nimport org.apache.dubbo.common.extension.ext9_empty.Ext9Empty;\n\npublic class Ext9EmptyImpl implements Ext9Empty {\n    @Override\n    public void empty() {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/inject/AdaptiveExtensionInjectorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.inject;\n\nimport org.apache.dubbo.common.beans.ScopeBeanExtensionInjector;\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.extension.ExtensionInjector;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.director.FooFrameworkProvider;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link AdaptiveExtensionInjector}\n * {@link ScopeBeanExtensionInjector}\n * {@link SpiExtensionInjector}\n */\nclass AdaptiveExtensionInjectorTest {\n\n    @Test\n    void test() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ExtensionLoader<ExtensionInjector> extensionLoader = frameworkModel.getExtensionLoader(ExtensionInjector.class);\n\n        ExtensionInjector adaptiveExtensionInjector = extensionLoader.getAdaptiveExtension();\n        ExtensionInjector scopeExtensionInjector = extensionLoader.getExtension(\"scopeBean\");\n        ExtensionInjector spiExtensionInjector = extensionLoader.getExtension(\"spi\");\n\n        FooFrameworkProvider testFrameworkProvider =\n                adaptiveExtensionInjector.getInstance(FooFrameworkProvider.class, \"testFrameworkProvider\");\n        Assertions.assertNotNull(testFrameworkProvider);\n        Assertions.assertTrue(testFrameworkProvider.getClass().getName().endsWith(\"$Adaptive\"));\n        Assertions.assertEquals(\n                spiExtensionInjector.getInstance(FooFrameworkProvider.class, \"testFrameworkProvider\"),\n                testFrameworkProvider);\n\n        ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();\n        AdaptiveExtensionInjectorTest obj = new AdaptiveExtensionInjectorTest();\n        beanFactory.registerBean(\"bean\", obj);\n        AdaptiveExtensionInjectorTest bean =\n                adaptiveExtensionInjector.getInstance(AdaptiveExtensionInjectorTest.class, \"bean\");\n        Assertions.assertEquals(bean, obj);\n        Assertions.assertEquals(scopeExtensionInjector.getInstance(AdaptiveExtensionInjectorTest.class, \"bean\"), bean);\n\n        frameworkModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/injection/InjectExt.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.injection;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(\"injection\")\npublic interface InjectExt {\n    String echo(String msg);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/injection/impl/InjectExtImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.injection.impl;\n\nimport org.apache.dubbo.common.extension.DisableInject;\nimport org.apache.dubbo.common.extension.ext1.SimpleExt;\nimport org.apache.dubbo.common.extension.injection.InjectExt;\nimport org.apache.dubbo.common.extension.wrapper.Demo;\n\npublic class InjectExtImpl implements InjectExt {\n\n    private SimpleExt simpleExt;\n\n    private SimpleExt simpleExt1;\n\n    private Object genericType;\n\n    private Demo demo;\n\n    public void setSimpleExt(SimpleExt simpleExt) {\n        this.simpleExt = simpleExt;\n    }\n\n    @DisableInject\n    public void setSimpleExt1(SimpleExt simpleExt1) {\n        this.simpleExt1 = simpleExt1;\n    }\n\n    public void setGenericType(Object genericType) {\n        this.genericType = genericType;\n    }\n\n    @Override\n    public String echo(String msg) {\n        return null;\n    }\n\n    public SimpleExt getSimpleExt() {\n        return simpleExt;\n    }\n\n    public SimpleExt getSimpleExt1() {\n        return simpleExt1;\n    }\n\n    public Object getGenericType() {\n        return genericType;\n    }\n\n    public Demo getDemo() {\n        return demo;\n    }\n\n    public void setDemo(Demo demo) {\n        this.demo = demo;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/ActivateComparatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass ActivateComparatorTest {\n\n    private ActivateComparator activateComparator;\n\n    @BeforeEach\n    public void setup() {\n        activateComparator =\n                new ActivateComparator(ApplicationModel.defaultModel().getExtensionDirector());\n    }\n\n    @Test\n    void testActivateComparator() {\n        Filter1 f1 = new Filter1();\n        Filter2 f2 = new Filter2();\n        Filter3 f3 = new Filter3();\n        Filter4 f4 = new Filter4();\n        List<Class<?>> filters = new ArrayList<>();\n        filters.add(f1.getClass());\n        filters.add(f2.getClass());\n        filters.add(f3.getClass());\n        filters.add(f4.getClass());\n\n        Collections.sort(filters, activateComparator);\n\n        Assertions.assertEquals(f4.getClass(), filters.get(0));\n        Assertions.assertEquals(f3.getClass(), filters.get(1));\n        Assertions.assertEquals(f2.getClass(), filters.get(2));\n        Assertions.assertEquals(f1.getClass(), filters.get(3));\n    }\n\n    @Test\n    void testFilterOrder() {\n        Order0Filter1 order0Filter1 = new Order0Filter1();\n        Order0Filter2 order0Filter2 = new Order0Filter2();\n\n        List<Class<?>> filters = null;\n\n        {\n            filters = new ArrayList<>();\n            filters.add(order0Filter1.getClass());\n            filters.add(order0Filter2.getClass());\n            filters.sort(activateComparator);\n            Assertions.assertEquals(order0Filter1.getClass(), filters.get(0));\n            Assertions.assertEquals(order0Filter2.getClass(), filters.get(1));\n        }\n\n        {\n            filters = new ArrayList<>();\n            filters.add(order0Filter2.getClass());\n            filters.add(order0Filter1.getClass());\n            filters.sort(activateComparator);\n            Assertions.assertEquals(order0Filter1.getClass(), filters.get(0));\n            Assertions.assertEquals(order0Filter2.getClass(), filters.get(1));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/Filter0.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface Filter0 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/Filter1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate\npublic class Filter1 implements Filter0 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/Filter2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate(before = \"_1\")\npublic class Filter2 implements Filter0 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/Filter3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate(after = \"_4\")\npublic class Filter3 implements Filter0 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/Filter4.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate(before = \"_2\")\npublic class Filter4 implements Filter0 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/Order0Filter0.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface Order0Filter0 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/Order0Filter1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate\npublic class Order0Filter1 implements Order0Filter0 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/Order0Filter2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate\npublic class Order0Filter2 implements Order0Filter0 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/wrapper/Demo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.wrapper;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(\"demo\")\npublic interface Demo {\n    String echo(String msg);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/wrapper/WrapperTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.wrapper;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.wrapper.impl.DemoWrapper;\nimport org.apache.dubbo.common.extension.wrapper.impl.DemoWrapper2;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link org.apache.dubbo.common.extension.Wrapper} Test\n *\n * @since 2.7.5\n */\nclass WrapperTest {\n\n    @Test\n    void testWrapper() {\n        Demo demoWrapper = ExtensionLoader.getExtensionLoader(Demo.class).getExtension(\"demo\");\n        assertTrue(demoWrapper instanceof DemoWrapper);\n        Demo demoWrapper2 = ExtensionLoader.getExtensionLoader(Demo.class).getExtension(\"demo2\");\n        assertTrue(demoWrapper2 instanceof DemoWrapper2);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/wrapper/impl/DemoImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.wrapper.impl;\n\nimport org.apache.dubbo.common.extension.wrapper.Demo;\n\npublic class DemoImpl implements Demo {\n    @Override\n    public String echo(String msg) {\n        return msg;\n    }\n\n    public DemoImpl() {}\n\n    public DemoImpl(String test) {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/wrapper/impl/DemoWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.wrapper.impl;\n\nimport org.apache.dubbo.common.extension.Wrapper;\nimport org.apache.dubbo.common.extension.wrapper.Demo;\n\n@Wrapper(\n        matches = {\"demo\"},\n        mismatches = \"demo2\")\npublic class DemoWrapper implements Demo {\n    private Demo demo;\n\n    public DemoWrapper(Demo demo) {\n        this.demo = demo;\n    }\n\n    public String echo(String msg) {\n        return demo.echo(msg);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/extension/wrapper/impl/DemoWrapper2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.wrapper.impl;\n\nimport org.apache.dubbo.common.extension.Wrapper;\nimport org.apache.dubbo.common.extension.wrapper.Demo;\n\n@Wrapper(\n        matches = {\"demo2\"},\n        mismatches = {\"demo\"})\npublic class DemoWrapper2 implements Demo {\n    private Demo demo;\n\n    public DemoWrapper2(Demo demo) {\n        this.demo = demo;\n    }\n\n    public String echo(String msg) {\n        return demo.echo(msg);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/function/PredicatesTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.function;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.function.Predicates.alwaysFalse;\nimport static org.apache.dubbo.common.function.Predicates.alwaysTrue;\nimport static org.apache.dubbo.common.function.Predicates.and;\nimport static org.apache.dubbo.common.function.Predicates.or;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link Predicates} Test\n *\n * @since 2.7.5\n */\nclass PredicatesTest {\n\n    @Test\n    void testAlwaysTrue() {\n        assertTrue(alwaysTrue().test(null));\n    }\n\n    @Test\n    void testAlwaysFalse() {\n        assertFalse(alwaysFalse().test(null));\n    }\n\n    @Test\n    void testAnd() {\n        assertTrue(and(alwaysTrue(), alwaysTrue(), alwaysTrue()).test(null));\n        assertFalse(and(alwaysFalse(), alwaysFalse(), alwaysFalse()).test(null));\n        assertFalse(and(alwaysTrue(), alwaysFalse(), alwaysFalse()).test(null));\n        assertFalse(and(alwaysTrue(), alwaysTrue(), alwaysFalse()).test(null));\n    }\n\n    @Test\n    void testOr() {\n        assertTrue(or(alwaysTrue(), alwaysTrue(), alwaysTrue()).test(null));\n        assertTrue(or(alwaysTrue(), alwaysTrue(), alwaysFalse()).test(null));\n        assertTrue(or(alwaysTrue(), alwaysFalse(), alwaysFalse()).test(null));\n        assertFalse(or(alwaysFalse(), alwaysFalse(), alwaysFalse()).test(null));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/function/StreamsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.function;\n\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static java.util.stream.Collectors.toList;\nimport static org.apache.dubbo.common.function.Streams.filterList;\nimport static org.apache.dubbo.common.function.Streams.filterSet;\nimport static org.apache.dubbo.common.function.Streams.filterStream;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link Streams} Test\n *\n * @since 2.7.5\n */\nclass StreamsTest {\n\n    @Test\n    void testFilterStream() {\n        Stream<Integer> stream = filterStream(asList(1, 2, 3, 4, 5), i -> i % 2 == 0);\n        assertEquals(asList(2, 4), stream.collect(toList()));\n    }\n\n    @Test\n    void testFilterList() {\n        List<Integer> list = filterList(asList(1, 2, 3, 4, 5), i -> i % 2 == 0);\n        assertEquals(asList(2, 4), list);\n    }\n\n    @Test\n    void testFilterSet() {\n        Set<Integer> set = filterSet(asList(1, 2, 3, 4, 5), i -> i % 2 == 0);\n        assertEquals(new LinkedHashSet<>(asList(2, 4)), set);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/function/ThrowableActionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.function;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.function.ThrowableAction.execute;\n\n/**\n * {@link ThrowableAction} Test\n *\n * @since 2.7.5\n */\nclass ThrowableActionTest {\n\n    @Test\n    void testExecute() {\n        Assertions.assertThrows(\n                RuntimeException.class,\n                () -> execute(() -> {\n                    throw new Exception(\"Test\");\n                }),\n                \"Test\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/function/ThrowableConsumerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.function;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.function.ThrowableConsumer.execute;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\n/**\n * {@link ThrowableConsumer} Test\n *\n * @since 2.7.5\n */\nclass ThrowableConsumerTest {\n\n    @Test\n    void testExecute() {\n        assertThrows(\n                RuntimeException.class,\n                () -> execute(\"Hello,World\", m -> {\n                    throw new Exception(m);\n                }),\n                \"Hello,World\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/function/ThrowableFunctionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.function;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.function.ThrowableConsumer.execute;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\n/**\n * {@link ThrowableFunction} Test\n *\n * @since 2.7.5\n */\nclass ThrowableFunctionTest {\n\n    @Test\n    void testExecute() {\n        assertThrows(\n                RuntimeException.class,\n                () -> execute(\"Hello,World\", m -> {\n                    throw new Exception(m);\n                }),\n                \"Hello,World\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/io/BytesTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass BytesTest {\n    private final byte[] b1 =\n            \"adpfioha;eoh;aldfadl;kfadslkfdajfio123431241235123davas;odvwe;lmzcoqpwoewqogineopwqihwqetup\\n\\tejqf;lajsfd中文字符0da0gsaofdsf==adfasdfs\"\n                    .getBytes();\n    private final String C64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\"; // default base64.\n    private byte[] bytes1 = {3, 12, 14, 41, 12, 2, 3, 12, 4, 67, 23};\n    private byte[] bytes2 = {3, 12, 14, 41, 12, 2, 3, 12, 4, 67};\n\n    @Test\n    void testMain() {\n        short s = (short) 0xabcd;\n        assertThat(s, is(Bytes.bytes2short(Bytes.short2bytes(s))));\n\n        int i = 198284;\n        assertThat(i, is(Bytes.bytes2int(Bytes.int2bytes(i))));\n\n        long l = 13841747174L;\n        assertThat(l, is(Bytes.bytes2long(Bytes.long2bytes(l))));\n\n        float f = 1.3f;\n        assertThat(f, is(Bytes.bytes2float(Bytes.float2bytes(f))));\n\n        double d = 11213.3;\n        assertThat(d, is(Bytes.bytes2double(Bytes.double2bytes(d))));\n\n        assertThat(Bytes.int2bytes(i), is(int2bytes(i)));\n        assertThat(Bytes.long2bytes(l), is(long2bytes(l)));\n\n        String str = Bytes.bytes2base64(\"dubbo\".getBytes());\n        byte[] bytes = Bytes.base642bytes(str, 0, str.length());\n        assertThat(bytes, is(\"dubbo\".getBytes()));\n\n        byte[] bytesWithC64 = Bytes.base642bytes(str, C64);\n        assertThat(bytesWithC64, is(bytes));\n\n        byte[] emptyBytes = Bytes.base642bytes(\"dubbo\", 0, 0);\n        assertThat(emptyBytes, is(\"\".getBytes()));\n\n        assertThat(Bytes.base642bytes(\"dubbo\", 0, 0, \"\"), is(\"\".getBytes()));\n        assertThat(Bytes.base642bytes(\"dubbo\", 0, 0, new char[0]), is(\"\".getBytes()));\n    }\n\n    @Test\n    void testWrongBase64Code() {\n        Assertions.assertThrows(\n                IllegalArgumentException.class, () -> Bytes.bytes2base64(\"dubbo\".getBytes(), 0, 1, new char[] {'a'}));\n    }\n\n    @Test\n    void testWrongOffSet() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> Bytes.bytes2base64(\"dubbo\".getBytes(), -1, 1));\n    }\n\n    @Test\n    void testLargeLength() {\n        Assertions.assertThrows(\n                IndexOutOfBoundsException.class, () -> Bytes.bytes2base64(\"dubbo\".getBytes(), 0, 100000));\n    }\n\n    @Test\n    void testSmallLength() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> Bytes.bytes2base64(\"dubbo\".getBytes(), 0, -1));\n    }\n\n    @Test\n    void testBase64S2b2sFailCaseLog() {\n        String s1 = Bytes.bytes2base64(bytes1);\n        byte[] out1 = Bytes.base642bytes(s1);\n        assertThat(bytes1, is(out1));\n\n        String s2 = Bytes.bytes2base64(bytes2);\n        byte[] out2 = Bytes.base642bytes(s2);\n        assertThat(bytes2, is(out2));\n    }\n\n    @Test\n    void testBase642bCharArrCall() {\n        byte[] stringCall = Bytes.base642bytes(\"ZHViYm8=\", C64);\n        byte[] charArrCall = Bytes.base642bytes(\"ZHViYm8=\", C64.toCharArray());\n\n        assertThat(stringCall, is(charArrCall));\n    }\n\n    @Test\n    void testHex() {\n        String str = Bytes.bytes2hex(b1);\n        assertThat(b1, is(Bytes.hex2bytes(str)));\n    }\n\n    @Test\n    void testMD5ForString() {\n        byte[] md5 = Bytes.getMD5(\"dubbo\");\n        assertThat(md5, is(Bytes.base642bytes(\"qk4bjCzJ3u2W/gEu8uB1Kg==\")));\n    }\n\n    @Test\n    void testMD5ForFile() throws IOException {\n        byte[] md5 = Bytes.getMD5(new File(\n                getClass().getClassLoader().getResource(\"md5.testfile.txt\").getFile()));\n        assertThat(md5, is(Bytes.base642bytes(\"iNZ+5qHafVNPLJxHwLKJ3w==\")));\n    }\n\n    @Test\n    void testZip() throws IOException {\n        String s = \"hello world\";\n        byte[] zip = Bytes.zip(s.getBytes());\n        byte[] unzip = Bytes.unzip(zip);\n        assertThat(unzip, is(s.getBytes()));\n    }\n\n    @Test\n    void testBytes2HexWithWrongOffset() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> Bytes.bytes2hex(\"hello\".getBytes(), -1, 1));\n    }\n\n    @Test\n    void testBytes2HexWithWrongLength() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> Bytes.bytes2hex(\"hello\".getBytes(), 0, 6));\n    }\n\n    private byte[] int2bytes(int x) {\n        byte[] bb = new byte[4];\n        bb[0] = (byte) (x >> 24);\n        bb[1] = (byte) (x >> 16);\n        bb[2] = (byte) (x >> 8);\n        bb[3] = (byte) (x >> 0);\n        return bb;\n    }\n\n    private byte[] long2bytes(long x) {\n        byte[] bb = new byte[8];\n        bb[0] = (byte) (x >> 56);\n        bb[1] = (byte) (x >> 48);\n        bb[2] = (byte) (x >> 40);\n        bb[3] = (byte) (x >> 32);\n        bb[4] = (byte) (x >> 24);\n        bb[5] = (byte) (x >> 16);\n        bb[6] = (byte) (x >> 8);\n        bb[7] = (byte) (x >> 0);\n        return bb;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/io/StreamUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PushbackInputStream;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\n\nclass StreamUtilsTest {\n\n    @Test\n    void testMarkSupportedInputStream() throws Exception {\n        InputStream is = StreamUtilsTest.class.getResourceAsStream(\"/StreamUtilsTest.txt\");\n        assertEquals(10, is.available());\n\n        is = new PushbackInputStream(is);\n        assertEquals(10, is.available());\n        assertFalse(is.markSupported());\n\n        is = StreamUtils.markSupportedInputStream(is);\n        assertEquals(10, is.available());\n\n        is.mark(0);\n        assertEquals((int) '0', is.read());\n        assertEquals((int) '1', is.read());\n\n        is.reset();\n        assertEquals((int) '0', is.read());\n        assertEquals((int) '1', is.read());\n        assertEquals((int) '2', is.read());\n\n        is.mark(0);\n        assertEquals((int) '3', is.read());\n        assertEquals((int) '4', is.read());\n        assertEquals((int) '5', is.read());\n\n        is.reset();\n        assertEquals((int) '3', is.read());\n        assertEquals((int) '4', is.read());\n\n        is.mark(0);\n        assertEquals((int) '5', is.read());\n        assertEquals((int) '6', is.read());\n\n        is.reset();\n        assertEquals((int) '5', is.read());\n        assertEquals((int) '6', is.read());\n        assertEquals((int) '7', is.read());\n        assertEquals((int) '8', is.read());\n        assertEquals((int) '9', is.read());\n        assertEquals(-1, is.read());\n        assertEquals(-1, is.read());\n\n        is.mark(0);\n        assertEquals(-1, is.read());\n        assertEquals(-1, is.read());\n\n        is.reset();\n        assertEquals(-1, is.read());\n        assertEquals(-1, is.read());\n\n        is.close();\n    }\n\n    @Test\n    void testLimitedInputStream() throws Exception {\n        InputStream is = StreamUtilsTest.class.getResourceAsStream(\"/StreamUtilsTest.txt\");\n        assertThat(10, is(is.available()));\n\n        is = StreamUtils.limitedInputStream(is, 2);\n        assertThat(2, is(is.available()));\n        assertThat(is.markSupported(), is(true));\n\n        is.mark(0);\n        assertEquals((int) '0', is.read());\n        assertEquals((int) '1', is.read());\n        assertEquals(-1, is.read());\n\n        is.reset();\n        is.skip(1);\n        assertEquals((int) '1', is.read());\n\n        is.reset();\n        is.skip(-1);\n        assertEquals((int) '0', is.read());\n\n        is.reset();\n        byte[] bytes = new byte[2];\n        int read = is.read(bytes, 1, 1);\n        assertThat(read, is(1));\n\n        is.reset();\n        StreamUtils.skipUnusedStream(is);\n        assertEquals(-1, is.read());\n\n        is.close();\n    }\n\n    @Test\n    void testMarkInputSupport() {\n        Assertions.assertThrows(IOException.class, () -> {\n            InputStream is = StreamUtilsTest.class.getResourceAsStream(\"/StreamUtilsTest.txt\");\n            try {\n                is = StreamUtils.markSupportedInputStream(new PushbackInputStream(is), 1);\n\n                is.mark(1);\n                int read = is.read();\n                assertThat(read, is((int) '0'));\n\n                is.skip(1);\n                is.read();\n            } finally {\n                if (is != null) {\n                    is.close();\n                }\n            }\n        });\n    }\n\n    @Test\n    void testSkipForOriginMarkSupportInput() throws IOException {\n        InputStream is = StreamUtilsTest.class.getResourceAsStream(\"/StreamUtilsTest.txt\");\n        InputStream newIs = StreamUtils.markSupportedInputStream(is, 1);\n\n        assertThat(newIs, is(is));\n        is.close();\n    }\n\n    @Test\n    void testReadEmptyByteArray() {\n        Assertions.assertThrows(NullPointerException.class, () -> {\n            InputStream is = StreamUtilsTest.class.getResourceAsStream(\"/StreamUtilsTest.txt\");\n            try {\n                is = StreamUtils.limitedInputStream(is, 2);\n                is.read(null, 0, 1);\n            } finally {\n                if (is != null) {\n                    is.close();\n                }\n            }\n        });\n    }\n\n    @Test\n    void testReadWithWrongOffset() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            InputStream is = StreamUtilsTest.class.getResourceAsStream(\"/StreamUtilsTest.txt\");\n            try {\n                is = StreamUtils.limitedInputStream(is, 2);\n                is.read(new byte[1], -1, 1);\n            } finally {\n                if (is != null) {\n                    is.close();\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/io/UnsafeByteArrayInputStreamTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass UnsafeByteArrayInputStreamTest {\n    @Test\n    void testMark() {\n        UnsafeByteArrayInputStream stream = new UnsafeByteArrayInputStream(\"abc\".getBytes(), 1);\n        assertThat(stream.markSupported(), is(true));\n\n        stream.mark(2);\n        stream.read();\n        assertThat(stream.position(), is(2));\n        stream.reset();\n        assertThat(stream.position(), is(1));\n    }\n\n    @Test\n    void testRead() throws IOException {\n        UnsafeByteArrayInputStream stream = new UnsafeByteArrayInputStream(\"abc\".getBytes());\n        assertThat(stream.read(), is((int) 'a'));\n        assertThat(stream.available(), is(2));\n\n        stream.skip(1);\n        assertThat(stream.available(), is(1));\n\n        byte[] bytes = new byte[1];\n        int read = stream.read(bytes);\n        assertThat(read, is(1));\n        assertThat(bytes, is(\"c\".getBytes()));\n\n        stream.reset();\n        assertThat(stream.position(), is(0));\n        assertThat(stream.size(), is(3));\n\n        stream.position(1);\n        assertThat(stream.read(), is((int) 'b'));\n    }\n\n    @Test\n    void testWrongLength() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            UnsafeByteArrayInputStream stream = new UnsafeByteArrayInputStream(\"abc\".getBytes());\n            stream.read(new byte[1], 0, 100);\n        });\n    }\n\n    @Test\n    void testWrongOffset() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            UnsafeByteArrayInputStream stream = new UnsafeByteArrayInputStream(\"abc\".getBytes());\n            stream.read(new byte[1], -1, 1);\n        });\n    }\n\n    @Test\n    void testReadEmptyByteArray() {\n        Assertions.assertThrows(NullPointerException.class, () -> {\n            UnsafeByteArrayInputStream stream = new UnsafeByteArrayInputStream(\"abc\".getBytes());\n            stream.read(null, 0, 1);\n        });\n    }\n\n    @Test\n    void testSkipZero() {\n        UnsafeByteArrayInputStream stream = new UnsafeByteArrayInputStream(\"abc\".getBytes());\n        long skip = stream.skip(-1);\n\n        assertThat(skip, is(0L));\n        assertThat(stream.position(), is(0));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/io/UnsafeByteArrayOutputStreamTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyInt;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.mock;\n\nclass UnsafeByteArrayOutputStreamTest {\n    @Test\n    void testWrongSize() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> new UnsafeByteArrayOutputStream(-1));\n    }\n\n    @Test\n    void testWrite() {\n        UnsafeByteArrayOutputStream outputStream = new UnsafeByteArrayOutputStream(1);\n        outputStream.write((int) 'a');\n        outputStream.write(\"bc\".getBytes(), 0, 2);\n\n        assertThat(outputStream.size(), is(3));\n        assertThat(outputStream.toString(), is(\"abc\"));\n    }\n\n    @Test\n    void testToByteBuffer() {\n        UnsafeByteArrayOutputStream outputStream = new UnsafeByteArrayOutputStream(1);\n        outputStream.write((int) 'a');\n\n        ByteBuffer byteBuffer = outputStream.toByteBuffer();\n        assertThat(byteBuffer.get(), is(\"a\".getBytes()[0]));\n    }\n\n    @Test\n    void testExtendLengthForBuffer() throws IOException {\n        UnsafeByteArrayOutputStream outputStream = new UnsafeByteArrayOutputStream(1);\n        for (int i = 0; i < 10; i++) {\n            outputStream.write(i);\n        }\n        assertThat(outputStream.size(), is(10));\n\n        OutputStream stream = mock(OutputStream.class);\n        outputStream.writeTo(stream);\n        Mockito.verify(stream).write(any(byte[].class), anyInt(), eq(10));\n    }\n\n    @Test\n    void testToStringWithCharset() throws IOException {\n        UnsafeByteArrayOutputStream outputStream = new UnsafeByteArrayOutputStream();\n        outputStream.write(\"Hòa Bình\".getBytes(StandardCharsets.UTF_8));\n\n        assertThat(outputStream.toString(\"UTF-8\"), is(\"Hòa Bình\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/io/UnsafeStringReaderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass UnsafeStringReaderTest {\n    @Test\n    void testRead() throws IOException {\n        UnsafeStringReader reader = new UnsafeStringReader(\"abc\");\n        assertThat(reader.markSupported(), is(true));\n        assertThat(reader.read(), is((int) 'a'));\n        assertThat(reader.read(), is((int) 'b'));\n        assertThat(reader.read(), is((int) 'c'));\n        assertThat(reader.read(), is(-1));\n\n        reader.reset();\n        reader.mark(0);\n        assertThat(reader.read(), is((int) 'a'));\n\n        char[] chars = new char[2];\n        reader.read(chars);\n        reader.close();\n\n        assertThat(chars[0], is('b'));\n        assertThat(chars[1], is('c'));\n    }\n\n    @Test\n    void testSkip() throws IOException {\n        UnsafeStringReader reader = new UnsafeStringReader(\"abc\");\n        assertThat(reader.ready(), is(true));\n        reader.skip(1);\n        assertThat(reader.read(), is((int) 'b'));\n    }\n\n    @Test\n    void testSkipTooLong() throws IOException {\n        UnsafeStringReader reader = new UnsafeStringReader(\"abc\");\n\n        reader.skip(10);\n        long skip = reader.skip(10);\n\n        assertThat(skip, is(0L));\n    }\n\n    @Test\n    void testWrongLength() throws IOException {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            UnsafeStringReader reader = new UnsafeStringReader(\"abc\");\n            char[] chars = new char[1];\n            reader.read(chars, 0, 2);\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/io/UnsafeStringWriterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.io;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass UnsafeStringWriterTest {\n    @Test\n    void testWrite() {\n        UnsafeStringWriter writer = new UnsafeStringWriter();\n        writer.write(\"a\");\n        writer.write(\"abc\", 1, 1);\n        writer.write(99);\n        writer.flush();\n        writer.close();\n\n        assertThat(writer.toString(), is(\"abc\"));\n    }\n\n    @Test\n    void testNegativeSize() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> new UnsafeStringWriter(-1));\n    }\n\n    @Test\n    void testAppend() {\n        UnsafeStringWriter writer = new UnsafeStringWriter();\n        writer.append('a');\n        writer.append(\"abc\", 1, 2);\n        writer.append('c');\n        writer.flush();\n        writer.close();\n\n        assertThat(writer.toString(), is(\"abc\"));\n    }\n\n    @Test\n    void testAppendNull() {\n        UnsafeStringWriter writer = new UnsafeStringWriter();\n        writer.append(null);\n        writer.append(null, 0, 4);\n        writer.flush();\n        writer.close();\n\n        assertThat(writer.toString(), is(\"nullnull\"));\n    }\n\n    @Test\n    void testWriteNull() throws IOException {\n        UnsafeStringWriter writer = new UnsafeStringWriter(3);\n        char[] chars = new char[2];\n        chars[0] = 'a';\n        chars[1] = 'b';\n        writer.write(chars);\n        writer.write(chars, 0, 1);\n        writer.flush();\n        writer.close();\n\n        assertThat(writer.toString(), is(\"aba\"));\n    }\n\n    @Test\n    void testWriteCharWithWrongLength() throws IOException {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            UnsafeStringWriter writer = new UnsafeStringWriter();\n            char[] chars = new char[0];\n            writer.write(chars, 0, 1);\n        });\n    }\n\n    @Test\n    void testWriteCharWithWrongCombineLength() throws IOException {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            UnsafeStringWriter writer = new UnsafeStringWriter();\n            char[] chars = new char[1];\n            writer.write(chars, 1, 1);\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/json/GsonUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass GsonUtilsTest {\n    @Test\n    void test1() {\n        Object user = GsonUtils.fromJson(\"{'name':'Tom','age':24}\", User.class);\n        Assertions.assertInstanceOf(User.class, user);\n        Assertions.assertEquals(\"Tom\", ((User) user).getName());\n        Assertions.assertEquals(24, ((User) user).getAge());\n\n        try {\n            GsonUtils.fromJson(\"{'name':'Tom','age':}\", User.class);\n            Assertions.fail();\n        } catch (RuntimeException ex) {\n            Assertions.assertEquals(\n                    \"Generic serialization [gson] Json syntax exception thrown when parsing (message:{'name':'Tom','age':} type:class org.apache.dubbo.common.json.GsonUtilsTest$User) error:com.google.gson.stream.MalformedJsonException: Expected value at line 1 column 21 path $.age\\n\"\n                            + \"See https://github.com/google/gson/blob/main/Troubleshooting.md#malformed-json\",\n                    ex.getMessage());\n        }\n    }\n\n    @Test\n    void test2() {\n        ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();\n        AtomicReference<List<String>> removedPackages = new AtomicReference<>(Collections.emptyList());\n        ClassLoader newClassLoader = new ClassLoader(originClassLoader) {\n            @Override\n            public Class<?> loadClass(String name) throws ClassNotFoundException {\n                for (String removedPackage : removedPackages.get()) {\n                    if (name.startsWith(removedPackage)) {\n                        throw new ClassNotFoundException(\"Test\");\n                    }\n                }\n                return super.loadClass(name);\n            }\n        };\n        Thread.currentThread().setContextClassLoader(newClassLoader);\n\n        // TCCL not found gson\n        removedPackages.set(Collections.singletonList(\"com.google.gson\"));\n        GsonUtils.setSupportGson(null);\n        try {\n            GsonUtils.fromJson(\"{'name':'Tom','age':24}\", User.class);\n            Assertions.fail();\n        } catch (RuntimeException ex) {\n            Assertions.assertEquals(\"Gson is not supported. Please import Gson in JVM env.\", ex.getMessage());\n        }\n\n        Thread.currentThread().setContextClassLoader(originClassLoader);\n        GsonUtils.setSupportGson(null);\n    }\n\n    private static class User {\n        String name;\n        int age;\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public int getAge() {\n            return age;\n        }\n\n        public void setAge(int age) {\n            this.age = age;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/json/impl/FastJson2ImplTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json.impl;\n\nimport java.lang.reflect.Type;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONWriter;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\nimport static org.mockito.Answers.CALLS_REAL_METHODS;\n\nclass FastJson2ImplTest {\n    private static MockedStatic<JSON> fastjson2Mock;\n\n    @BeforeAll\n    static void setup() {\n        fastjson2Mock = Mockito.mockStatic(JSON.class, CALLS_REAL_METHODS);\n    }\n\n    @AfterAll\n    static void teardown() {\n        fastjson2Mock.close();\n    }\n\n    @Test\n    void testSupported() {\n        Assertions.assertTrue(new FastJson2Impl().isSupport());\n\n        fastjson2Mock\n                .when(() -> JSON.toJSONString(Mockito.any(), (JSONWriter.Feature) Mockito.any()))\n                .thenThrow(new RuntimeException());\n        Assertions.assertFalse(new FastJson2Impl().isSupport());\n        fastjson2Mock.reset();\n\n        fastjson2Mock\n                .when(() -> JSON.toJSONString(Mockito.any(), (JSONWriter.Feature) Mockito.any()))\n                .thenReturn(null);\n        Assertions.assertFalse(new FastJson2Impl().isSupport());\n        fastjson2Mock.reset();\n\n        fastjson2Mock\n                .when(() -> JSON.parseObject((String) Mockito.any(), (Type) Mockito.any()))\n                .thenReturn(null);\n        Assertions.assertFalse(new FastJson2Impl().isSupport());\n        fastjson2Mock.reset();\n\n        fastjson2Mock\n                .when(() -> JSON.parseArray(Mockito.any(), (Class) Mockito.any()))\n                .thenReturn(null);\n        Assertions.assertFalse(new FastJson2Impl().isSupport());\n        fastjson2Mock.reset();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/json/impl/FastJsonImplTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json.impl;\n\nimport java.lang.reflect.Type;\n\nimport com.alibaba.fastjson.JSON;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\nimport static org.mockito.Answers.CALLS_REAL_METHODS;\n\nclass FastJsonImplTest {\n    private static MockedStatic<JSON> fastjsonMock;\n\n    @BeforeAll\n    static void setup() {\n        fastjsonMock = Mockito.mockStatic(JSON.class, CALLS_REAL_METHODS);\n    }\n\n    @AfterAll\n    static void teardown() {\n        fastjsonMock.close();\n    }\n\n    @Test\n    void testSupported() {\n        Assertions.assertTrue(new FastJsonImpl().isSupport());\n\n        fastjsonMock.when(() -> JSON.toJSONString(Mockito.any(), Mockito.any())).thenThrow(new RuntimeException());\n        Assertions.assertFalse(new FastJsonImpl().isSupport());\n        fastjsonMock.reset();\n\n        fastjsonMock.when(() -> JSON.toJSONString(Mockito.any(), Mockito.any())).thenReturn(null);\n        Assertions.assertFalse(new FastJsonImpl().isSupport());\n        fastjsonMock.reset();\n\n        fastjsonMock\n                .when(() -> JSON.parseObject((String) Mockito.any(), (Type) Mockito.any()))\n                .thenReturn(null);\n        Assertions.assertFalse(new FastJsonImpl().isSupport());\n        fastjsonMock.reset();\n\n        fastjsonMock\n                .when(() -> JSON.parseArray(Mockito.any(), (Class) Mockito.any()))\n                .thenReturn(null);\n        Assertions.assertFalse(new FastJsonImpl().isSupport());\n        fastjsonMock.reset();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/json/impl/GsonImplTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.json.impl;\n\nimport java.lang.reflect.Type;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Consumer;\n\nimport com.google.gson.Gson;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedConstruction;\nimport org.mockito.Mockito;\n\npublic class GsonImplTest {\n\n    private static Gson gson = new Gson();\n    private static AtomicReference<Gson> gsonReference = new AtomicReference<>();\n    private static MockedConstruction<Gson> gsonMock;\n    private static AtomicReference<Consumer<Gson>> gsonInit = new AtomicReference<>();\n\n    @BeforeAll\n    static void setup() {\n        gsonMock = Mockito.mockConstruction(Gson.class, (mock, context) -> {\n            gsonReference.set(mock);\n            Mockito.when(mock.toJson((Object) Mockito.any()))\n                    .thenAnswer(invocation -> gson.toJson((Object) invocation.getArgument(0)));\n            Mockito.when(mock.fromJson(Mockito.anyString(), (Type) Mockito.any()))\n                    .thenAnswer(invocation ->\n                            gson.fromJson((String) invocation.getArgument(0), (Type) invocation.getArgument(1)));\n            Consumer<Gson> gsonConsumer = gsonInit.get();\n            if (gsonConsumer != null) {\n                gsonConsumer.accept(mock);\n            }\n        });\n    }\n\n    @AfterAll\n    static void teardown() {\n        gsonMock.close();\n    }\n\n    @Test\n    void testSupported() {\n        Assertions.assertTrue(new GsonImpl().isSupport());\n\n        gsonInit.set(g -> Mockito.when(g.toJson((Object) Mockito.any())).thenThrow(new RuntimeException()));\n        Assertions.assertFalse(new GsonImpl().isSupport());\n        gsonInit.set(null);\n\n        gsonInit.set(g -> Mockito.when(g.fromJson(Mockito.anyString(), (Type) Mockito.any()))\n                .thenThrow(new RuntimeException()));\n        Assertions.assertFalse(new GsonImpl().isSupport());\n        gsonInit.set(null);\n\n        gsonInit.set(g -> Mockito.when(g.toJson((Object) Mockito.any())).thenReturn(null));\n        Assertions.assertFalse(new GsonImpl().isSupport());\n        gsonInit.set(null);\n\n        gsonInit.set(g -> Mockito.when(g.fromJson(Mockito.anyString(), (Type) Mockito.any()))\n                .thenReturn(null));\n        Assertions.assertFalse(new GsonImpl().isSupport());\n        gsonInit.set(null);\n\n        gsonInit.set(g -> Mockito.when(g.fromJson(Mockito.eq(\"[\\\"json\\\"]\"), (Type) Mockito.any()))\n                .thenReturn(null));\n        Assertions.assertFalse(new GsonImpl().isSupport());\n        gsonInit.set(null);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/lang/DefaultShutdownHookCallback.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.lang;\n\n/**\n * Default {@link ShutdownHookCallback}\n *\n * @since 2.7.5\n */\npublic class DefaultShutdownHookCallback implements ShutdownHookCallback {\n\n    private boolean executed = false;\n\n    @Override\n    public void callback() throws Throwable {\n        executed = true;\n    }\n\n    public boolean isExecuted() {\n        return executed;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/lang/PrioritizedTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.lang;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static java.util.Collections.sort;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link Prioritized} Test\n *\n * @since 2.7.5\n */\nclass PrioritizedTest {\n\n    @Test\n    void testConstants() {\n        assertEquals(Integer.MAX_VALUE, Prioritized.MIN_PRIORITY);\n        assertEquals(Integer.MIN_VALUE, Prioritized.MAX_PRIORITY);\n    }\n\n    @Test\n    void testGetPriority() {\n        assertEquals(Prioritized.NORMAL_PRIORITY, new Prioritized() {}.getPriority());\n    }\n\n    @Test\n    void testComparator() {\n\n        List<Object> list = new LinkedList<>();\n\n        // All Prioritized\n        list.add(of(1));\n        list.add(of(2));\n        list.add(of(3));\n\n        List<Object> copy = new LinkedList<>(list);\n\n        sort(list, Prioritized.COMPARATOR);\n\n        assertEquals(copy, list);\n\n        // MIX non-Prioritized and Prioritized\n        list.clear();\n\n        list.add(1);\n        list.add(of(2));\n        list.add(of(1));\n\n        sort(list, Prioritized.COMPARATOR);\n\n        copy = asList(of(1), of(2), 1);\n\n        assertEquals(copy, list);\n\n        // All non-Prioritized\n        list.clear();\n        list.add(1);\n        list.add(2);\n        list.add(3);\n\n        sort(list, Prioritized.COMPARATOR);\n\n        copy = asList(1, 2, 3);\n\n        assertEquals(copy, list);\n    }\n\n    public static PrioritizedValue of(int value) {\n        return new PrioritizedValue(value);\n    }\n\n    static class PrioritizedValue implements Prioritized {\n\n        private final int value;\n\n        private PrioritizedValue(int value) {\n            this.value = value;\n        }\n\n        @Override\n        public int getPriority() {\n            return value;\n        }\n\n        @Override\n        public String toString() {\n            return String.valueOf(value);\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof PrioritizedValue)) return false;\n            PrioritizedValue that = (PrioritizedValue) o;\n            return value == that.value;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(value);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/lang/ShutdownHookCallbacksTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.lang;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link ShutdownHookCallbacks}\n *\n * @since 2.7.5\n */\nclass ShutdownHookCallbacksTest {\n\n    private ShutdownHookCallbacks callbacks;\n\n    @BeforeEach\n    public void init() {\n        callbacks = new ShutdownHookCallbacks(ApplicationModel.defaultModel());\n    }\n\n    @Test\n    void testSingleton() {\n        assertNotNull(callbacks);\n    }\n\n    @Test\n    void testCallback() {\n        callbacks.callback();\n        DefaultShutdownHookCallback callback = (DefaultShutdownHookCallback)\n                callbacks.getCallbacks().iterator().next();\n        assertTrue(callback.isExecuted());\n    }\n\n    @AfterEach\n    public void destroy() {\n        callbacks.destroy();\n        assertTrue(callbacks.getCallbacks().isEmpty());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerAdapterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\nimport org.apache.dubbo.common.logger.jcl.JclLogger;\nimport org.apache.dubbo.common.logger.jcl.JclLoggerAdapter;\nimport org.apache.dubbo.common.logger.jdk.JdkLogger;\nimport org.apache.dubbo.common.logger.jdk.JdkLoggerAdapter;\nimport org.apache.dubbo.common.logger.log4j.Log4jLogger;\nimport org.apache.dubbo.common.logger.log4j.Log4jLoggerAdapter;\nimport org.apache.dubbo.common.logger.log4j2.Log4j2Logger;\nimport org.apache.dubbo.common.logger.log4j2.Log4j2LoggerAdapter;\nimport org.apache.dubbo.common.logger.slf4j.Slf4jLogger;\nimport org.apache.dubbo.common.logger.slf4j.Slf4jLoggerAdapter;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass LoggerAdapterTest {\n    static Stream<Arguments> data() {\n        return Stream.of(\n                Arguments.of(JclLoggerAdapter.class, JclLogger.class),\n                Arguments.of(JdkLoggerAdapter.class, JdkLogger.class),\n                Arguments.of(Log4jLoggerAdapter.class, Log4jLogger.class),\n                Arguments.of(Slf4jLoggerAdapter.class, Slf4jLogger.class),\n                Arguments.of(Log4j2LoggerAdapter.class, Log4j2Logger.class));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"data\")\n    void testGetLogger(Class<? extends LoggerAdapter> loggerAdapterClass, Class<? extends Logger> loggerClass)\n            throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {\n        LoggerAdapter loggerAdapter =\n                loggerAdapterClass.getDeclaredConstructor().newInstance();\n        Logger logger = loggerAdapter.getLogger(this.getClass());\n        assertThat(logger.getClass().isAssignableFrom(loggerClass), is(true));\n\n        logger = loggerAdapter.getLogger(this.getClass().getSimpleName());\n        assertThat(logger.getClass().isAssignableFrom(loggerClass), is(true));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"data\")\n    void testLevel(Class<? extends LoggerAdapter> loggerAdapterClass)\n            throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {\n        LoggerAdapter loggerAdapter =\n                loggerAdapterClass.getDeclaredConstructor().newInstance();\n        for (Level targetLevel : Level.values()) {\n            loggerAdapter.setLevel(targetLevel);\n            assertThat(loggerAdapter.getLevel(), is(targetLevel));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.nullValue;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass LoggerFactoryTest {\n    @Test\n    void testLoggerLevel() {\n        LoggerFactory.setLevel(Level.INFO);\n        Level level = LoggerFactory.getLevel();\n\n        assertThat(level, is(Level.INFO));\n    }\n\n    @Test\n    void testGetLogFile() {\n        LoggerFactory.setLoggerAdapter(FrameworkModel.defaultModel(), \"slf4j\");\n        File file = LoggerFactory.getFile();\n\n        assertThat(file, is(nullValue()));\n    }\n\n    @Test\n    void testAllLogLevel() {\n        for (Level targetLevel : Level.values()) {\n            LoggerFactory.setLevel(targetLevel);\n            Level level = LoggerFactory.getLevel();\n\n            assertThat(level, is(targetLevel));\n        }\n    }\n\n    @Test\n    void testGetLogger() {\n        Logger logger1 = LoggerFactory.getLogger(this.getClass());\n        Logger logger2 = LoggerFactory.getLogger(this.getClass());\n\n        assertThat(logger1, is(logger2));\n    }\n\n    @Test\n    void shouldReturnSameLogger() {\n        Logger logger1 = LoggerFactory.getLogger(this.getClass().getName());\n        Logger logger2 = LoggerFactory.getLogger(this.getClass().getName());\n\n        assertThat(logger1, is(logger2));\n    }\n\n    @Test\n    void shouldReturnSameErrorTypeAwareLogger() {\n        ErrorTypeAwareLogger logger1 =\n                LoggerFactory.getErrorTypeAwareLogger(this.getClass().getName());\n        ErrorTypeAwareLogger logger2 =\n                LoggerFactory.getErrorTypeAwareLogger(this.getClass().getName());\n\n        assertThat(logger1, is(logger2));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger;\n\nimport org.apache.dubbo.common.logger.jcl.JclLoggerAdapter;\nimport org.apache.dubbo.common.logger.jdk.JdkLoggerAdapter;\nimport org.apache.dubbo.common.logger.log4j.Log4jLoggerAdapter;\nimport org.apache.dubbo.common.logger.log4j2.Log4j2LoggerAdapter;\nimport org.apache.dubbo.common.logger.slf4j.Slf4jLoggerAdapter;\nimport org.apache.dubbo.common.logger.support.FailsafeErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.support.FailsafeLogger;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport static org.hamcrest.CoreMatchers.not;\nimport static org.hamcrest.CoreMatchers.nullValue;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass LoggerTest {\n\n    static Stream<Arguments> data() {\n        return Stream.of(\n                Arguments.of(JclLoggerAdapter.class),\n                Arguments.of(JdkLoggerAdapter.class),\n                Arguments.of(Log4jLoggerAdapter.class),\n                Arguments.of(Slf4jLoggerAdapter.class),\n                Arguments.of(Log4j2LoggerAdapter.class));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"data\")\n    void testAllLogMethod(Class<? extends LoggerAdapter> loggerAdapter) throws Exception {\n        LoggerAdapter adapter = loggerAdapter.getDeclaredConstructor().newInstance();\n        adapter.setLevel(Level.ALL);\n        Logger logger =\n                new FailsafeErrorTypeAwareLogger(adapter.getLogger(FailsafeLogger.class.getName(), this.getClass()));\n        logger.error(\"error\");\n        logger.warn(\"warn\");\n        logger.info(\"info\");\n        logger.debug(\"debug\");\n        logger.trace(\"trace\");\n\n        logger.error(\"error:{}\", \"arg1\");\n        logger.warn(\"warn:{}\", \"arg1\");\n        logger.info(\"info:{}\", \"arg1\");\n        logger.debug(\"debug:{}\", \"arg1\");\n        logger.trace(\"trace:{}\", \"arg1\");\n\n        logger.error(new Exception(\"error\"));\n        logger.warn(new Exception(\"warn\"));\n        logger.info(new Exception(\"info\"));\n        logger.debug(new Exception(\"debug\"));\n        logger.trace(new Exception(\"trace\"));\n\n        logger.error(\"error\", new Exception(\"error\"));\n        logger.warn(\"warn\", new Exception(\"warn\"));\n        logger.info(\"info\", new Exception(\"info\"));\n        logger.debug(\"debug\", new Exception(\"debug\"));\n        logger.trace(\"trace\", new Exception(\"trace\"));\n\n        logger.error(\"error:{}\", \"arg1\", new Exception(\"error\"));\n        logger.warn(\"warn:{}\", \"arg1\", new Exception(\"warn\"));\n        logger.info(\"info:{}\", \"arg1\", new Exception(\"info\"));\n        logger.debug(\"debug:{}\", \"arg1\", new Exception(\"debug\"));\n        logger.trace(\"trace:{}\", \"arg1\", new Exception(\"trace\"));\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"data\")\n    void testLevelEnable(Class<? extends LoggerAdapter> loggerAdapter)\n            throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {\n        LoggerAdapter adapter = loggerAdapter.getDeclaredConstructor().newInstance();\n        adapter.setLevel(Level.ALL);\n        Logger logger = adapter.getLogger(this.getClass());\n        assertThat(logger.isWarnEnabled(), not(nullValue()));\n        assertThat(logger.isTraceEnabled(), not(nullValue()));\n        assertThat(logger.isErrorEnabled(), not(nullValue()));\n        assertThat(logger.isInfoEnabled(), not(nullValue()));\n        assertThat(logger.isDebugEnabled(), not(nullValue()));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/logger/slf4j/Slf4jLoggerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.slf4j;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\nimport org.slf4j.spi.LocationAwareLogger;\n\nimport static org.mockito.ArgumentMatchers.*;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.internal.verification.VerificationModeFactory.times;\n\nclass Slf4jLoggerTest {\n    @Test\n    void testLocationAwareLogger() {\n        LocationAwareLogger locationAwareLogger = mock(LocationAwareLogger.class);\n\n        Slf4jLogger logger = new Slf4jLogger(locationAwareLogger);\n\n        logger.error(\"error\");\n        logger.warn(\"warn\");\n        logger.info(\"info\");\n        logger.debug(\"debug\");\n        logger.trace(\"info\");\n\n        verify(locationAwareLogger, times(5)).log(isNull(), anyString(), anyInt(), anyString(), isNull(), isNull());\n\n        logger.error(\"error:{}\", \"arg1\");\n        logger.warn(\"warn:{}\", \"arg1\");\n        logger.info(\"info:{}\", \"arg1\");\n        logger.debug(\"debug:{}\", \"arg1\");\n        logger.trace(\"info:{}\", \"arg1\");\n\n        verify(locationAwareLogger, never())\n                .log(isNull(), anyString(), anyInt(), anyString(), eq(new String[] {\"arg1\"}), isNull());\n\n        Mockito.when(locationAwareLogger.isErrorEnabled()).thenReturn(true);\n        Mockito.when(locationAwareLogger.isWarnEnabled()).thenReturn(true);\n        Mockito.when(locationAwareLogger.isInfoEnabled()).thenReturn(true);\n        Mockito.when(locationAwareLogger.isDebugEnabled()).thenReturn(true);\n        Mockito.when(locationAwareLogger.isTraceEnabled()).thenReturn(true);\n\n        logger.error(\"error:{}\", \"arg1\");\n        logger.warn(\"warn:{}\", \"arg1\");\n        logger.info(\"info:{}\", \"arg1\");\n        logger.debug(\"debug:{}\", \"arg1\");\n        logger.trace(\"info:{}\", \"arg1\");\n\n        verify(locationAwareLogger, times(5))\n                .log(isNull(), anyString(), anyInt(), anyString(), eq(new String[] {\"arg1\"}), isNull());\n\n        logger.error(new Exception(\"error\"));\n        logger.warn(new Exception(\"warn\"));\n        logger.info(new Exception(\"info\"));\n        logger.debug(new Exception(\"debug\"));\n        logger.trace(new Exception(\"trace\"));\n\n        logger.error(\"error\", new Exception(\"error\"));\n        logger.warn(\"warn\", new Exception(\"warn\"));\n        logger.info(\"info\", new Exception(\"info\"));\n        logger.debug(\"debug\", new Exception(\"debug\"));\n        logger.trace(\"trace\", new Exception(\"trace\"));\n\n        verify(locationAwareLogger, times(10))\n                .log(isNull(), anyString(), anyInt(), anyString(), isNull(), any(Throwable.class));\n\n        logger.error(\"error:{}\", \"arg1\", new Exception(\"error\"));\n        logger.warn(\"warn:{}\", \"arg1\", new Exception(\"warn\"));\n        logger.info(\"info:{}\", \"arg1\", new Exception(\"info\"));\n        logger.debug(\"debug:{}\", \"arg1\", new Exception(\"debug\"));\n        logger.trace(\"trace:{}\", \"arg1\", new Exception(\"trace\"));\n\n        verify(locationAwareLogger, times(5))\n                .log(isNull(), anyString(), anyInt(), anyString(), eq(new String[] {\"arg1\"}), any(Throwable.class));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLoggerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.support;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_ADDRESS_INVALID;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n/**\n * Tests for FailsafeErrorTypeAwareLogger to test whether it 'ignores' exceptions thrown by logger or not.\n */\nclass FailsafeErrorTypeAwareLoggerTest {\n    @Test\n    void testFailsafeErrorTypeAwareForLoggingMethod() {\n        Logger failLogger = mock(Logger.class);\n        FailsafeErrorTypeAwareLogger failsafeLogger = new FailsafeErrorTypeAwareLogger(failLogger);\n\n        doThrow(new RuntimeException()).when(failLogger).error(anyString());\n        doThrow(new RuntimeException()).when(failLogger).warn(anyString());\n        doThrow(new RuntimeException()).when(failLogger).info(anyString());\n        doThrow(new RuntimeException()).when(failLogger).debug(anyString());\n        doThrow(new RuntimeException()).when(failLogger).trace(anyString());\n\n        failsafeLogger.error(REGISTRY_ADDRESS_INVALID, \"Registry center\", \"May be it's offline.\", \"error\");\n        failsafeLogger.warn(REGISTRY_ADDRESS_INVALID, \"Registry center\", \"May be it's offline.\", \"warn\");\n\n        doThrow(new RuntimeException()).when(failLogger).error(any(Throwable.class));\n        doThrow(new RuntimeException()).when(failLogger).warn(any(Throwable.class));\n        doThrow(new RuntimeException()).when(failLogger).info(any(Throwable.class));\n        doThrow(new RuntimeException()).when(failLogger).debug(any(Throwable.class));\n        doThrow(new RuntimeException()).when(failLogger).trace(any(Throwable.class));\n\n        failsafeLogger.error(\n                REGISTRY_ADDRESS_INVALID, \"Registry center\", \"May be it's offline.\", \"error\", new Exception(\"error\"));\n        failsafeLogger.warn(\n                REGISTRY_ADDRESS_INVALID, \"Registry center\", \"May be it's offline.\", \"warn\", new Exception(\"warn\"));\n    }\n\n    @Test\n    void testSuccessLogger() {\n        Logger successLogger = mock(Logger.class);\n        when(successLogger.isErrorEnabled()).thenReturn(true);\n        when(successLogger.isWarnEnabled()).thenReturn(true);\n        FailsafeErrorTypeAwareLogger failsafeLogger = new FailsafeErrorTypeAwareLogger(successLogger);\n\n        failsafeLogger.error(REGISTRY_ADDRESS_INVALID, \"Registry center\", \"May be it's offline.\", \"error\");\n        failsafeLogger.warn(REGISTRY_ADDRESS_INVALID, \"Registry center\", \"May be it's offline.\", \"warn\");\n\n        verify(successLogger).error(anyString());\n        verify(successLogger).warn(anyString());\n\n        failsafeLogger.error(\n                REGISTRY_ADDRESS_INVALID, \"Registry center\", \"May be it's offline.\", \"error\", new Exception(\"error\"));\n        failsafeLogger.warn(\n                REGISTRY_ADDRESS_INVALID, \"Registry center\", \"May be it's offline.\", \"warn\", new Exception(\"warn\"));\n    }\n\n    @Test\n    void testGetLogger() {\n        Assertions.assertThrows(RuntimeException.class, () -> {\n            Logger failLogger = mock(Logger.class);\n            FailsafeErrorTypeAwareLogger failsafeLogger = new FailsafeErrorTypeAwareLogger(failLogger);\n\n            doThrow(new RuntimeException()).when(failLogger).error(anyString());\n            failsafeLogger.getLogger().error(\"should get error\");\n        });\n    }\n\n    @Test\n    void testInstructionShownOrNot() {\n        LoggerFactory.setLoggerAdapter(FrameworkModel.defaultModel(), \"jdk\");\n\n        ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(FailsafeErrorTypeAwareLoggerTest.class);\n\n        logger.error(\n                REGISTRY_ADDRESS_INVALID,\n                \"Registry center\",\n                \"May be it's offline.\",\n                \"error message\",\n                new Exception(\"error\"));\n\n        logger.error(\n                REGISTRY_ADDRESS_INVALID,\n                \"Registry center\",\n                \"May be it's offline.\",\n                \"error message\",\n                new Exception(\"error\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/logger/support/FailsafeLoggerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.logger.support;\n\nimport org.apache.dubbo.common.logger.Logger;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\n\nclass FailsafeLoggerTest {\n    @Test\n    void testFailSafeForLoggingMethod() {\n        Logger failLogger = mock(Logger.class);\n        FailsafeLogger failsafeLogger = new FailsafeLogger(failLogger);\n\n        doThrow(new RuntimeException()).when(failLogger).error(anyString());\n        doThrow(new RuntimeException()).when(failLogger).warn(anyString());\n        doThrow(new RuntimeException()).when(failLogger).info(anyString());\n        doThrow(new RuntimeException()).when(failLogger).debug(anyString());\n        doThrow(new RuntimeException()).when(failLogger).trace(anyString());\n\n        failsafeLogger.error(\"error\");\n        failsafeLogger.warn(\"warn\");\n        failsafeLogger.info(\"info\");\n        failsafeLogger.debug(\"debug\");\n        failsafeLogger.trace(\"info\");\n\n        doThrow(new RuntimeException()).when(failLogger).error(any(Throwable.class));\n        doThrow(new RuntimeException()).when(failLogger).warn(any(Throwable.class));\n        doThrow(new RuntimeException()).when(failLogger).info(any(Throwable.class));\n        doThrow(new RuntimeException()).when(failLogger).debug(any(Throwable.class));\n        doThrow(new RuntimeException()).when(failLogger).trace(any(Throwable.class));\n\n        failsafeLogger.error(new Exception(\"error\"));\n        failsafeLogger.warn(new Exception(\"warn\"));\n        failsafeLogger.info(new Exception(\"info\"));\n        failsafeLogger.debug(new Exception(\"debug\"));\n        failsafeLogger.trace(new Exception(\"trace\"));\n\n        failsafeLogger.error(\"error\", new Exception(\"error\"));\n        failsafeLogger.warn(\"warn\", new Exception(\"warn\"));\n        failsafeLogger.info(\"info\", new Exception(\"info\"));\n        failsafeLogger.debug(\"debug\", new Exception(\"debug\"));\n        failsafeLogger.trace(\"trace\", new Exception(\"trace\"));\n    }\n\n    @Test\n    void testSuccessLogger() {\n        Logger successLogger = mock(Logger.class);\n        Mockito.when(successLogger.isErrorEnabled()).thenReturn(true);\n        Mockito.when(successLogger.isWarnEnabled()).thenReturn(true);\n        Mockito.when(successLogger.isInfoEnabled()).thenReturn(true);\n        Mockito.when(successLogger.isDebugEnabled()).thenReturn(true);\n        Mockito.when(successLogger.isTraceEnabled()).thenReturn(true);\n\n        FailsafeLogger failsafeLogger = new FailsafeLogger(successLogger);\n        failsafeLogger.error(\"error\");\n        failsafeLogger.warn(\"warn\");\n        failsafeLogger.info(\"info\");\n        failsafeLogger.debug(\"debug\");\n        failsafeLogger.trace(\"info\");\n\n        verify(successLogger).error(anyString());\n        verify(successLogger).warn(anyString());\n        verify(successLogger).info(anyString());\n        verify(successLogger).debug(anyString());\n        verify(successLogger).trace(anyString());\n\n        failsafeLogger.error(new Exception(\"error\"));\n        failsafeLogger.warn(new Exception(\"warn\"));\n        failsafeLogger.info(new Exception(\"info\"));\n        failsafeLogger.debug(new Exception(\"debug\"));\n        failsafeLogger.trace(new Exception(\"trace\"));\n\n        failsafeLogger.error(\"error\", new Exception(\"error\"));\n        failsafeLogger.warn(\"warn\", new Exception(\"warn\"));\n        failsafeLogger.info(\"info\", new Exception(\"info\"));\n        failsafeLogger.debug(\"debug\", new Exception(\"debug\"));\n        failsafeLogger.trace(\"trace\", new Exception(\"trace\"));\n    }\n\n    @Test\n    void testGetLogger() {\n        Assertions.assertThrows(RuntimeException.class, () -> {\n            Logger failLogger = mock(Logger.class);\n            FailsafeLogger failsafeLogger = new FailsafeLogger(failLogger);\n\n            doThrow(new RuntimeException()).when(failLogger).error(anyString());\n            failsafeLogger.getLogger().error(\"should get error\");\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/Person.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model;\n\nimport java.io.Serializable;\nimport java.util.Arrays;\n\npublic class Person implements Serializable {\n    byte oneByte = 123;\n    private String name = \"name1\";\n    private int age = 11;\n\n    private String[] value = {\"value1\", \"value2\"};\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public byte getOneByte() {\n        return oneByte;\n    }\n\n    public void setOneByte(byte b) {\n        this.oneByte = b;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public String[] getValue() {\n        return value;\n    }\n\n    public void setValue(String[] value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"Person name(%s) age(%d) byte(%s) [value=%s]\", name, age, oneByte, Arrays.toString(value));\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + age;\n        result = prime * result + ((name == null) ? 0 : name.hashCode());\n        result = prime * result + Arrays.hashCode(value);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        Person other = (Person) obj;\n        if (age != other.age) return false;\n        if (name == null) {\n            if (other.name != null) return false;\n        } else if (!name.equals(other.name)) return false;\n        if (!Arrays.equals(value, other.value)) return false;\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/SerializablePerson.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model;\n\nimport java.io.Serializable;\nimport java.util.Arrays;\n\npublic class SerializablePerson implements Serializable {\n    private static final long serialVersionUID = 1L;\n    byte oneByte = 123;\n    private String name = \"name1\";\n    private int age = 11;\n\n    private String[] value = {\"value1\", \"value2\"};\n\n    public SerializablePerson(char description, boolean adult) {}\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public byte getOneByte() {\n        return oneByte;\n    }\n\n    public void setOneByte(byte b) {\n        this.oneByte = b;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public String[] getValue() {\n        return value;\n    }\n\n    public void setValue(String[] value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"Person name(%s) age(%d) byte(%s) [value=%s]\", name, age, oneByte, Arrays.toString(value));\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + age;\n        result = prime * result + ((name == null) ? 0 : name.hashCode());\n        result = prime * result + Arrays.hashCode(value);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        SerializablePerson other = (SerializablePerson) obj;\n        if (age != other.age) return false;\n        if (name == null) {\n            if (other.name != null) return false;\n        } else if (!name.equals(other.name)) return false;\n        if (!Arrays.equals(value, other.value)) return false;\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/User.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model;\n\nimport java.io.Serializable;\nimport java.util.Objects;\n\n/**\n * this class has no nullary constructor and some field is primitive\n */\npublic class User implements Serializable {\n    private int age;\n\n    private String name;\n\n    public User(int age, String name) {\n        this.age = age;\n        this.name = name;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"User name(%s) age(%d) \", name, age);\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        User user = (User) o;\n        if (name == null) {\n            if (user.name != null) {\n                return false;\n            }\n        } else if (!name.equals(user.name)) {\n            return false;\n        }\n        return Objects.equals(age, user.age);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(age, name);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/media/Image.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.media;\n\npublic class Image implements java.io.Serializable {\n    private static final long serialVersionUID = 1L;\n    public String uri;\n    public String title; // Can be null\n    public int width;\n    public int height;\n    public Size size;\n\n    public Image() {}\n\n    public Image(String uri, String title, int width, int height, Size size) {\n        this.height = height;\n        this.title = title;\n        this.uri = uri;\n        this.width = width;\n        this.size = size;\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        Image image = (Image) o;\n\n        if (height != image.height) return false;\n        if (width != image.width) return false;\n        if (size != image.size) return false;\n        if (title != null ? !title.equals(image.title) : image.title != null) return false;\n        if (uri != null ? !uri.equals(image.uri) : image.uri != null) return false;\n\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = uri != null ? uri.hashCode() : 0;\n        result = 31 * result + (title != null ? title.hashCode() : 0);\n        result = 31 * result + width;\n        result = 31 * result + height;\n        result = 31 * result + (size != null ? size.hashCode() : 0);\n        return result;\n    }\n\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"[Image \");\n        sb.append(\"uri=\").append(uri);\n        sb.append(\", title=\").append(title);\n        sb.append(\", width=\").append(width);\n        sb.append(\", height=\").append(height);\n        sb.append(\", size=\").append(size);\n        sb.append(']');\n        return sb.toString();\n    }\n\n    public String getUri() {\n        return uri;\n    }\n\n    public void setUri(String uri) {\n        this.uri = uri;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public int getWidth() {\n        return width;\n    }\n\n    public void setWidth(int width) {\n        this.width = width;\n    }\n\n    public int getHeight() {\n        return height;\n    }\n\n    public void setHeight(int height) {\n        this.height = height;\n    }\n\n    public Size getSize() {\n        return size;\n    }\n\n    public void setSize(Size size) {\n        this.size = size;\n    }\n\n    public enum Size {\n        SMALL,\n        LARGE\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/media/Media.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.media;\n\nimport java.util.List;\n\n@SuppressWarnings(\"serial\")\npublic class Media implements java.io.Serializable {\n    public String uri;\n    public String title; // Can be unset.\n    public int width;\n    public int height;\n    public String format;\n    public long duration;\n    public long size;\n    public int bitrate; // Can be unset.\n    public boolean hasBitrate;\n    public List<String> persons;\n    public Player player;\n    public String copyright; // Can be unset.\n\n    public Media() {}\n\n    public Media(\n            String uri,\n            String title,\n            int width,\n            int height,\n            String format,\n            long duration,\n            long size,\n            int bitrate,\n            boolean hasBitrate,\n            List<String> persons,\n            Player player,\n            String copyright) {\n        this.uri = uri;\n        this.title = title;\n        this.width = width;\n        this.height = height;\n        this.format = format;\n        this.duration = duration;\n        this.size = size;\n        this.bitrate = bitrate;\n        this.hasBitrate = hasBitrate;\n        this.persons = persons;\n        this.player = player;\n        this.copyright = copyright;\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        Media media = (Media) o;\n\n        if (bitrate != media.bitrate) return false;\n        if (duration != media.duration) return false;\n        if (hasBitrate != media.hasBitrate) return false;\n        if (height != media.height) return false;\n        if (size != media.size) return false;\n        if (width != media.width) return false;\n        if (copyright != null ? !copyright.equals(media.copyright) : media.copyright != null) return false;\n        if (format != null ? !format.equals(media.format) : media.format != null) return false;\n        if (persons != null ? !persons.equals(media.persons) : media.persons != null) return false;\n        if (player != media.player) return false;\n        if (title != null ? !title.equals(media.title) : media.title != null) return false;\n        if (uri != null ? !uri.equals(media.uri) : media.uri != null) return false;\n\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = uri != null ? uri.hashCode() : 0;\n        result = 31 * result + (title != null ? title.hashCode() : 0);\n        result = 31 * result + width;\n        result = 31 * result + height;\n        result = 31 * result + (format != null ? format.hashCode() : 0);\n        result = 31 * result + (int) (duration ^ (duration >>> 32));\n        result = 31 * result + (int) (size ^ (size >>> 32));\n        result = 31 * result + bitrate;\n        result = 31 * result + (hasBitrate ? 1 : 0);\n        result = 31 * result + (persons != null ? persons.hashCode() : 0);\n        result = 31 * result + (player != null ? player.hashCode() : 0);\n        result = 31 * result + (copyright != null ? copyright.hashCode() : 0);\n        return result;\n    }\n\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"[Media \");\n        sb.append(\"uri=\").append(uri);\n        sb.append(\", title=\").append(title);\n        sb.append(\", width=\").append(width);\n        sb.append(\", height=\").append(height);\n        sb.append(\", format=\").append(format);\n        sb.append(\", duration=\").append(duration);\n        sb.append(\", size=\").append(size);\n        sb.append(\", hasBitrate=\").append(hasBitrate);\n        sb.append(\", bitrate=\").append(String.valueOf(bitrate));\n        sb.append(\", persons=\").append(persons);\n        sb.append(\", player=\").append(player);\n        sb.append(\", copyright=\").append(copyright);\n        sb.append(']');\n        return sb.toString();\n    }\n\n    public String getUri() {\n        return uri;\n    }\n\n    public void setUri(String uri) {\n        this.uri = uri;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public int getWidth() {\n        return width;\n    }\n\n    public void setWidth(int width) {\n        this.width = width;\n    }\n\n    public int getHeight() {\n        return height;\n    }\n\n    public void setHeight(int height) {\n        this.height = height;\n    }\n\n    public String getFormat() {\n        return format;\n    }\n\n    public void setFormat(String format) {\n        this.format = format;\n    }\n\n    public long getDuration() {\n        return duration;\n    }\n\n    public void setDuration(long duration) {\n        this.duration = duration;\n    }\n\n    public long getSize() {\n        return size;\n    }\n\n    public void setSize(long size) {\n        this.size = size;\n    }\n\n    public int getBitrate() {\n        return bitrate;\n    }\n\n    public void setBitrate(int bitrate) {\n        this.bitrate = bitrate;\n        this.hasBitrate = true;\n    }\n\n    public List<String> getPersons() {\n        return persons;\n    }\n\n    public void setPersons(List<String> persons) {\n        this.persons = persons;\n    }\n\n    public Player getPlayer() {\n        return player;\n    }\n\n    public void setPlayer(Player player) {\n        this.player = player;\n    }\n\n    public String getCopyright() {\n        return copyright;\n    }\n\n    public void setCopyright(String copyright) {\n        this.copyright = copyright;\n    }\n\n    public enum Player {\n        JAVA,\n        FLASH\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/person/Ageneric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.person;\n\nimport java.io.Serializable;\n\npublic class Ageneric<T> implements Serializable {\n    public static String NAME = \"A\";\n\n    private String name = NAME;\n    private T data;\n\n    public T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\n    }\n\n    public String getName() {\n        return name;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/person/Bgeneric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.person;\n\nimport java.io.Serializable;\n\npublic class Bgeneric<T> implements Serializable {\n    public static String NAME = \"B\";\n\n    private String name = NAME;\n    private T data;\n\n    public T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\n    }\n\n    public String getName() {\n        return name;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/person/BigPerson.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.person;\n\nimport java.io.Serializable;\n\npublic class BigPerson implements Serializable {\n    private static final long serialVersionUID = 1L;\n\n    String personId;\n\n    String loginName;\n\n    PersonStatus status;\n\n    String email;\n\n    String personName;\n\n    PersonInfo infoProfile;\n\n    public BigPerson() {}\n\n    public BigPerson(String id) {\n        this.personId = id;\n    }\n\n    public String getPersonId() {\n        return personId;\n    }\n\n    public void setPersonId(String personId) {\n        this.personId = personId;\n    }\n\n    public PersonInfo getInfoProfile() {\n        return infoProfile;\n    }\n\n    public void setInfoProfile(PersonInfo infoProfile) {\n        this.infoProfile = infoProfile;\n    }\n\n    public String getEmail() {\n        return this.email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public String getLoginName() {\n        return this.loginName;\n    }\n\n    public void setLoginName(String loginName) {\n        this.loginName = loginName;\n    }\n\n    public PersonStatus getStatus() {\n        return this.status;\n    }\n\n    public void setStatus(PersonStatus status) {\n        this.status = status;\n    }\n\n    public String getPersonName() {\n        return personName;\n    }\n\n    public void setPersonName(String personName) {\n        this.personName = personName;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((email == null) ? 0 : email.hashCode());\n        result = prime * result + ((infoProfile == null) ? 0 : infoProfile.hashCode());\n        result = prime * result + ((loginName == null) ? 0 : loginName.hashCode());\n        result = prime * result + ((personName == null) ? 0 : personName.hashCode());\n        result = prime * result + ((personId == null) ? 0 : personId.hashCode());\n        result = prime * result + ((status == null) ? 0 : status.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        BigPerson other = (BigPerson) obj;\n        if (email == null) {\n            if (other.email != null) return false;\n        } else if (!email.equals(other.email)) return false;\n        if (infoProfile == null) {\n            if (other.infoProfile != null) return false;\n        } else if (!infoProfile.equals(other.infoProfile)) return false;\n        if (loginName == null) {\n            if (other.loginName != null) return false;\n        } else if (!loginName.equals(other.loginName)) return false;\n        if (personName == null) {\n            if (other.personName != null) return false;\n        } else if (!personName.equals(other.personName)) return false;\n        if (personId == null) {\n            if (other.personId != null) return false;\n        } else if (!personId.equals(other.personId)) return false;\n        if (status != other.status) return false;\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        return \"BigPerson [personId=\" + personId + \", loginName=\" + loginName + \", status=\"\n                + status + \", email=\" + email + \", personName=\" + personName + \", infoProfile=\"\n                + infoProfile + \"]\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/person/Cgeneric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.person;\n\nimport java.io.Serializable;\n\npublic class Cgeneric<T> implements Serializable {\n    public static String NAME = \"C\";\n\n    private String name = NAME;\n    private T data;\n    private Ageneric<T> a;\n    private Bgeneric<PersonInfo> b;\n\n    public T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public Ageneric<T> getA() {\n        return a;\n    }\n\n    public void setA(Ageneric<T> a) {\n        this.a = a;\n    }\n\n    public Bgeneric<PersonInfo> getB() {\n        return b;\n    }\n\n    public void setB(Bgeneric<PersonInfo> b) {\n        this.b = b;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/person/Dgeneric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.person;\n\nimport java.io.Serializable;\n\npublic class Dgeneric<T, Y, Z> implements Serializable {\n    public static String NAME = \"D\";\n\n    private String name = NAME;\n    private T t;\n    private Y y;\n    private Z z;\n\n    public T getT() {\n        return t;\n    }\n\n    public void setT(T t) {\n        this.t = t;\n    }\n\n    public Y getY() {\n        return y;\n    }\n\n    public void setY(Y y) {\n        this.y = y;\n    }\n\n    public Z getZ() {\n        return z;\n    }\n\n    public void setZ(Z z) {\n        this.z = z;\n    }\n\n    public String getName() {\n        return name;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/person/FullAddress.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.person;\n\nimport java.io.Serializable;\n\npublic class FullAddress implements Serializable {\n\n    private static final long serialVersionUID = 5163979984269419831L;\n\n    private String countryId;\n\n    private String countryName;\n\n    private String provinceName;\n\n    private String cityId;\n\n    private String cityName;\n\n    private String streetAddress;\n\n    private String zipCode;\n\n    public FullAddress() {}\n\n    public FullAddress(String countryId, String provinceName, String cityId, String streetAddress, String zipCode) {\n        this.countryId = countryId;\n        this.countryName = countryId;\n        this.provinceName = provinceName;\n        this.cityId = cityId;\n        this.cityName = cityId;\n        this.streetAddress = streetAddress;\n        this.zipCode = zipCode;\n    }\n\n    public FullAddress(\n            String countryId,\n            String countryName,\n            String provinceName,\n            String cityId,\n            String cityName,\n            String streetAddress,\n            String zipCode) {\n        this.countryId = countryId;\n        this.countryName = countryName;\n        this.provinceName = provinceName;\n        this.cityId = cityId;\n        this.cityName = cityName;\n        this.streetAddress = streetAddress;\n        this.zipCode = zipCode;\n    }\n\n    public String getCountryId() {\n        return countryId;\n    }\n\n    public void setCountryId(String countryId) {\n        this.countryId = countryId;\n    }\n\n    public String getCountryName() {\n        return countryName;\n    }\n\n    public void setCountryName(String countryName) {\n        this.countryName = countryName;\n    }\n\n    public String getProvinceName() {\n        return provinceName;\n    }\n\n    public void setProvinceName(String provinceName) {\n        this.provinceName = provinceName;\n    }\n\n    public String getCityId() {\n        return cityId;\n    }\n\n    public void setCityId(String cityId) {\n        this.cityId = cityId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getStreetAddress() {\n        return streetAddress;\n    }\n\n    public void setStreetAddress(String streetAddress) {\n        this.streetAddress = streetAddress;\n    }\n\n    public String getZipCode() {\n        return zipCode;\n    }\n\n    public void setZipCode(String zipCode) {\n        this.zipCode = zipCode;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((cityId == null) ? 0 : cityId.hashCode());\n        result = prime * result + ((cityName == null) ? 0 : cityName.hashCode());\n        result = prime * result + ((countryId == null) ? 0 : countryId.hashCode());\n        result = prime * result + ((countryName == null) ? 0 : countryName.hashCode());\n        result = prime * result + ((provinceName == null) ? 0 : provinceName.hashCode());\n        result = prime * result + ((streetAddress == null) ? 0 : streetAddress.hashCode());\n        result = prime * result + ((zipCode == null) ? 0 : zipCode.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        FullAddress other = (FullAddress) obj;\n        if (cityId == null) {\n            if (other.cityId != null) return false;\n        } else if (!cityId.equals(other.cityId)) return false;\n        if (cityName == null) {\n            if (other.cityName != null) return false;\n        } else if (!cityName.equals(other.cityName)) return false;\n        if (countryId == null) {\n            if (other.countryId != null) return false;\n        } else if (!countryId.equals(other.countryId)) return false;\n        if (countryName == null) {\n            if (other.countryName != null) return false;\n        } else if (!countryName.equals(other.countryName)) return false;\n        if (provinceName == null) {\n            if (other.provinceName != null) return false;\n        } else if (!provinceName.equals(other.provinceName)) return false;\n        if (streetAddress == null) {\n            if (other.streetAddress != null) return false;\n        } else if (!streetAddress.equals(other.streetAddress)) return false;\n        if (zipCode == null) {\n            if (other.zipCode != null) return false;\n        } else if (!zipCode.equals(other.zipCode)) return false;\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        if (countryName != null && countryName.length() > 0) {\n            sb.append(countryName);\n        }\n        if (provinceName != null && provinceName.length() > 0) {\n            sb.append(' ');\n            sb.append(provinceName);\n        }\n        if (cityName != null && cityName.length() > 0) {\n            sb.append(' ');\n            sb.append(cityName);\n        }\n        if (streetAddress != null && streetAddress.length() > 0) {\n            sb.append(' ');\n            sb.append(streetAddress);\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/person/PersonInfo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.person;\n\nimport java.io.Serializable;\nimport java.util.List;\n\npublic class PersonInfo implements Serializable {\n    private static final long serialVersionUID = 7443011149612231882L;\n\n    List<Phone> phones;\n\n    Phone fax;\n\n    FullAddress fullAddress;\n\n    String mobileNo;\n\n    String name;\n\n    boolean male;\n\n    boolean female;\n\n    String department;\n\n    String jobTitle;\n\n    String homepageUrl;\n\n    public List<Phone> getPhones() {\n        return phones;\n    }\n\n    public void setPhones(List<Phone> phones) {\n        this.phones = phones;\n    }\n\n    public boolean isMale() {\n        return male;\n    }\n\n    public void setMale(boolean male) {\n        this.male = male;\n    }\n\n    public boolean isFemale() {\n        return female;\n    }\n\n    public void setFemale(boolean female) {\n        this.female = female;\n    }\n\n    public String getDepartment() {\n        return department;\n    }\n\n    public void setDepartment(String department) {\n        this.department = department;\n    }\n\n    public Phone getFax() {\n        return fax;\n    }\n\n    public void setFax(Phone fax) {\n        this.fax = fax;\n    }\n\n    public FullAddress getFullAddress() {\n        return fullAddress;\n    }\n\n    public void setFullAddress(FullAddress fullAddress) {\n        this.fullAddress = fullAddress;\n    }\n\n    public String getHomepageUrl() {\n        return homepageUrl;\n    }\n\n    public void setHomepageUrl(String homepageUrl) {\n        this.homepageUrl = homepageUrl;\n    }\n\n    public String getJobTitle() {\n        return jobTitle;\n    }\n\n    public void setJobTitle(String jobTitle) {\n        this.jobTitle = jobTitle;\n    }\n\n    public String getMobileNo() {\n        return mobileNo;\n    }\n\n    public void setMobileNo(String mobileNo) {\n        this.mobileNo = mobileNo;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((department == null) ? 0 : department.hashCode());\n        result = prime * result + ((fax == null) ? 0 : fax.hashCode());\n        result = prime * result + (female ? 1231 : 1237);\n        result = prime * result + ((fullAddress == null) ? 0 : fullAddress.hashCode());\n        result = prime * result + ((homepageUrl == null) ? 0 : homepageUrl.hashCode());\n        result = prime * result + ((jobTitle == null) ? 0 : jobTitle.hashCode());\n        result = prime * result + (male ? 1231 : 1237);\n        result = prime * result + ((mobileNo == null) ? 0 : mobileNo.hashCode());\n        result = prime * result + ((name == null) ? 0 : name.hashCode());\n        result = prime * result + ((phones == null) ? 0 : phones.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        PersonInfo other = (PersonInfo) obj;\n        if (department == null) {\n            if (other.department != null) return false;\n        } else if (!department.equals(other.department)) return false;\n        if (fax == null) {\n            if (other.fax != null) return false;\n        } else if (!fax.equals(other.fax)) return false;\n        if (female != other.female) return false;\n        if (fullAddress == null) {\n            if (other.fullAddress != null) return false;\n        } else if (!fullAddress.equals(other.fullAddress)) return false;\n        if (homepageUrl == null) {\n            if (other.homepageUrl != null) return false;\n        } else if (!homepageUrl.equals(other.homepageUrl)) return false;\n        if (jobTitle == null) {\n            if (other.jobTitle != null) return false;\n        } else if (!jobTitle.equals(other.jobTitle)) return false;\n        if (male != other.male) return false;\n        if (mobileNo == null) {\n            if (other.mobileNo != null) return false;\n        } else if (!mobileNo.equals(other.mobileNo)) return false;\n        if (name == null) {\n            if (other.name != null) return false;\n        } else if (!name.equals(other.name)) return false;\n        if (phones == null) {\n            if (other.phones != null) return false;\n        } else if (!phones.equals(other.phones)) return false;\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        return \"PersonInfo [phones=\" + phones + \", fax=\" + fax + \", fullAddress=\" + fullAddress\n                + \", mobileNo=\" + mobileNo + \", name=\" + name + \", male=\" + male + \", female=\"\n                + female + \", department=\" + department + \", jobTitle=\" + jobTitle\n                + \", homepageUrl=\" + homepageUrl + \"]\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/person/PersonMap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.person;\n\nimport java.util.HashMap;\n\npublic class PersonMap extends HashMap<String, String> {\n\n    private static final String ID = \"1\";\n    private static final String NAME = \"hand\";\n\n    String personId;\n    String personName;\n\n    public String getPersonId() {\n        return get(ID);\n    }\n\n    public void setPersonId(String personId) {\n        this.personId = personId;\n    }\n\n    public String getPersonName() {\n        return get(NAME);\n    }\n\n    public void setPersonName(String personName) {\n        this.personName = personName;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/person/PersonStatus.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.person;\n\npublic enum PersonStatus {\n    ENABLED,\n    DISABLED\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/model/person/Phone.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.model.person;\n\nimport java.io.Serializable;\n\npublic class Phone implements Serializable {\n\n    private static final long serialVersionUID = 4399060521859707703L;\n\n    private String country;\n\n    private String area;\n\n    private String number;\n\n    private String extensionNumber;\n\n    public Phone() {}\n\n    public Phone(String country, String area, String number, String extensionNumber) {\n        this.country = country;\n        this.area = area;\n        this.number = number;\n        this.extensionNumber = extensionNumber;\n    }\n\n    public String getCountry() {\n        return country;\n    }\n\n    public void setCountry(String country) {\n        this.country = country;\n    }\n\n    public String getArea() {\n        return area;\n    }\n\n    public void setArea(String area) {\n        this.area = area;\n    }\n\n    public String getNumber() {\n        return number;\n    }\n\n    public void setNumber(String number) {\n        this.number = number;\n    }\n\n    public String getExtensionNumber() {\n        return extensionNumber;\n    }\n\n    public void setExtensionNumber(String extensionNumber) {\n        this.extensionNumber = extensionNumber;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((area == null) ? 0 : area.hashCode());\n        result = prime * result + ((country == null) ? 0 : country.hashCode());\n        result = prime * result + ((extensionNumber == null) ? 0 : extensionNumber.hashCode());\n        result = prime * result + ((number == null) ? 0 : number.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        Phone other = (Phone) obj;\n        if (area == null) {\n            if (other.area != null) return false;\n        } else if (!area.equals(other.area)) return false;\n        if (country == null) {\n            if (other.country != null) return false;\n        } else if (!country.equals(other.country)) return false;\n        if (extensionNumber == null) {\n            if (other.extensionNumber != null) return false;\n        } else if (!extensionNumber.equals(other.extensionNumber)) return false;\n        if (number == null) {\n            if (other.number != null) return false;\n        } else if (!number.equals(other.number)) return false;\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        if (country != null && country.length() > 0) {\n            sb.append(country);\n            sb.append('-');\n        }\n        if (area != null && area.length() > 0) {\n            sb.append(area);\n            sb.append('-');\n        }\n        if (number != null && number.length() > 0) {\n            sb.append(number);\n        }\n        if (extensionNumber != null && extensionNumber.length() > 0) {\n            sb.append('-');\n            sb.append(extensionNumber);\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/profiler/ProfilerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.profiler;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ProfilerTest {\n\n    @Test\n    void testProfiler() {\n        ProfilerEntry one = Profiler.start(\"1\");\n        ProfilerEntry two = Profiler.enter(one, \"1-2\");\n\n        ProfilerEntry three = Profiler.enter(two, \"1-2-3\");\n\n        ProfilerEntry four = Profiler.enter(three, \"1-2-3-4\");\n        Assertions.assertEquals(three, Profiler.release(four));\n\n        ProfilerEntry five = Profiler.enter(three, \"1-2-3-5\");\n        Assertions.assertEquals(three, Profiler.release(five));\n\n        Assertions.assertEquals(two, Profiler.release(three));\n\n        ProfilerEntry six = Profiler.enter(two, \"1-2-6\");\n        Assertions.assertEquals(two, Profiler.release(six));\n\n        ProfilerEntry seven = Profiler.enter(six, \"1-2-6-7\");\n        Assertions.assertEquals(six, Profiler.release(seven));\n\n        ProfilerEntry eight = Profiler.enter(six, \"1-2-6-8\");\n        Assertions.assertEquals(six, Profiler.release(eight));\n\n        Assertions.assertEquals(2, two.getSub().size());\n        Assertions.assertEquals(three, two.getSub().get(0));\n        Assertions.assertEquals(six, two.getSub().get(1));\n\n        Profiler.release(two);\n\n        ProfilerEntry nine = Profiler.enter(one, \"1-9\");\n        Profiler.release(nine);\n\n        Profiler.release(one);\n\n        /*\n         * Start time: 287395734500659\n         * +-[ Offset: 0.000000ms; Usage: 4.721583ms, 100% ] 1\n         *   +-[ Offset: 0.013136ms; Usage: 4.706288ms, 99% ] 1-2\n         *   |  +-[ Offset: 0.027903ms; Usage: 4.662918ms, 98% ] 1-2-3\n         *   |  |  +-[ Offset: 0.029742ms; Usage: 0.003785ms, 0% ] 1-2-3-4\n         *   |  |  +-[ Offset: 4.688477ms; Usage: 0.001398ms, 0% ] 1-2-3-5\n         *   |  +-[ Offset: 4.693346ms; Usage: 0.000316ms, 0% ] 1-2-6\n         *   |     +-[ Offset: 4.695191ms; Usage: 0.000212ms, 0% ] 1-2-6-7\n         *   |     +-[ Offset: 4.696655ms; Usage: 0.000195ms, 0% ] 1-2-6-8\n         *   +-[ Offset: 4.721044ms; Usage: 0.000270ms, 0% ] 1-9\n         */\n        Assertions.assertNotEquals(Profiler.buildDetail(one), Profiler.buildDetail(two));\n        Assertions.assertNotEquals(Profiler.buildDetail(one), Profiler.buildDetail(three));\n        Assertions.assertNotEquals(Profiler.buildDetail(one), Profiler.buildDetail(four));\n        Assertions.assertNotEquals(Profiler.buildDetail(one), Profiler.buildDetail(five));\n        Assertions.assertNotEquals(Profiler.buildDetail(one), Profiler.buildDetail(six));\n        Assertions.assertNotEquals(Profiler.buildDetail(one), Profiler.buildDetail(seven));\n        Assertions.assertNotEquals(Profiler.buildDetail(one), Profiler.buildDetail(eight));\n        Assertions.assertNotEquals(Profiler.buildDetail(one), Profiler.buildDetail(nine));\n    }\n\n    @Test\n    void testBizProfiler() {\n        Assertions.assertNull(Profiler.getBizProfiler());\n\n        ProfilerEntry one = Profiler.start(\"1\");\n\n        Profiler.setToBizProfiler(one);\n\n        Profiler.release(Profiler.enter(Profiler.getBizProfiler(), \"1-2\"));\n\n        Assertions.assertEquals(one, Profiler.getBizProfiler());\n        Assertions.assertEquals(1, one.getSub().size());\n\n        Profiler.removeBizProfiler();\n        Assertions.assertNull(Profiler.getBizProfiler());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/resource/GlobalResourcesRepositoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.resource;\n\nimport java.util.concurrent.ExecutorService;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link GlobalResourcesRepository}\n */\nclass GlobalResourcesRepositoryTest {\n\n    @Test\n    void test() {\n        GlobalResourcesRepository repository = GlobalResourcesRepository.getInstance();\n\n        ExecutorService globalExecutorService = GlobalResourcesRepository.getGlobalExecutorService();\n        Assertions.assertNotNull(globalExecutorService);\n\n        GlobalDisposable globalDisposable = new GlobalDisposable();\n        GlobalResourcesRepository.registerGlobalDisposable(globalDisposable);\n\n        OneOffDisposable oneOffDisposable = new OneOffDisposable();\n        repository.registerDisposable(oneOffDisposable);\n\n        repository.destroy();\n        Assertions.assertTrue(globalExecutorService.isShutdown());\n        Assertions.assertTrue(globalDisposable.isDestroyed());\n        Assertions.assertTrue(oneOffDisposable.isDestroyed());\n        Assertions.assertTrue(\n                !GlobalResourcesRepository.getGlobalReusedDisposables().isEmpty());\n        Assertions.assertTrue(\n                GlobalResourcesRepository.getGlobalReusedDisposables().contains(globalDisposable));\n        Assertions.assertTrue(repository.getOneoffDisposables().isEmpty());\n    }\n\n    class GlobalDisposable implements Disposable {\n\n        boolean destroyed = false;\n\n        @Override\n        public void destroy() {\n            destroyed = true;\n        }\n\n        public boolean isDestroyed() {\n            return destroyed;\n        }\n    }\n\n    class OneOffDisposable implements Disposable {\n        boolean destroyed = false;\n\n        @Override\n        public void destroy() {\n            destroyed = true;\n        }\n\n        public boolean isDestroyed() {\n            return destroyed;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/ssl/CertManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.ssl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass CertManagerTest {\n    private FrameworkModel frameworkModel;\n    private URL url;\n\n    @BeforeEach\n    void setup() {\n        FirstCertProvider.setProviderCert(null);\n        FirstCertProvider.setCert(null);\n        FirstCertProvider.setSupport(false);\n\n        SecondCertProvider.setProviderCert(null);\n        SecondCertProvider.setCert(null);\n        SecondCertProvider.setSupport(false);\n\n        frameworkModel = new FrameworkModel();\n        url = URL.valueOf(\"dubbo://\").setScopeModel(frameworkModel.newApplication());\n    }\n\n    @AfterEach\n    void teardown() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testGetConsumerConnectionConfig() {\n        CertManager certManager = new CertManager(frameworkModel);\n\n        Assertions.assertNull(certManager.getConsumerConnectionConfig(url));\n\n        Cert cert1 = Mockito.mock(Cert.class);\n        FirstCertProvider.setCert(cert1);\n        Assertions.assertNull(certManager.getConsumerConnectionConfig(url));\n\n        FirstCertProvider.setSupport(true);\n        Assertions.assertEquals(cert1, certManager.getConsumerConnectionConfig(url));\n\n        Cert cert2 = Mockito.mock(Cert.class);\n        SecondCertProvider.setCert(cert2);\n        Assertions.assertEquals(cert1, certManager.getConsumerConnectionConfig(url));\n\n        SecondCertProvider.setSupport(true);\n        Assertions.assertEquals(cert1, certManager.getConsumerConnectionConfig(url));\n\n        FirstCertProvider.setSupport(false);\n        Assertions.assertEquals(cert2, certManager.getConsumerConnectionConfig(url));\n\n        FirstCertProvider.setSupport(true);\n        FirstCertProvider.setCert(null);\n        Assertions.assertEquals(cert2, certManager.getConsumerConnectionConfig(url));\n    }\n\n    @Test\n    void testGetProviderConnectionConfig() {\n        CertManager certManager = new CertManager(frameworkModel);\n\n        Assertions.assertNull(certManager.getProviderConnectionConfig(url, null));\n\n        ProviderCert providerCert1 = Mockito.mock(ProviderCert.class);\n        FirstCertProvider.setProviderCert(providerCert1);\n        Assertions.assertNull(certManager.getProviderConnectionConfig(url, null));\n\n        FirstCertProvider.setSupport(true);\n        Assertions.assertEquals(providerCert1, certManager.getProviderConnectionConfig(url, null));\n\n        ProviderCert providerCert2 = Mockito.mock(ProviderCert.class);\n        SecondCertProvider.setProviderCert(providerCert2);\n        Assertions.assertEquals(providerCert1, certManager.getProviderConnectionConfig(url, null));\n\n        SecondCertProvider.setSupport(true);\n        Assertions.assertEquals(providerCert1, certManager.getProviderConnectionConfig(url, null));\n\n        FirstCertProvider.setSupport(false);\n        Assertions.assertEquals(providerCert2, certManager.getProviderConnectionConfig(url, null));\n\n        FirstCertProvider.setSupport(true);\n        FirstCertProvider.setProviderCert(null);\n        Assertions.assertEquals(providerCert2, certManager.getProviderConnectionConfig(url, null));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/ssl/FirstCertProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.ssl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\n\n@Activate(order = -10000)\npublic class FirstCertProvider implements CertProvider {\n    private static final AtomicBoolean isSupport = new AtomicBoolean(false);\n    private static final AtomicReference<ProviderCert> providerCert = new AtomicReference<>();\n    private static final AtomicReference<Cert> cert = new AtomicReference<>();\n\n    @Override\n    public boolean isSupport(URL address) {\n        return isSupport.get();\n    }\n\n    @Override\n    public ProviderCert getProviderConnectionConfig(URL localAddress) {\n        return providerCert.get();\n    }\n\n    @Override\n    public Cert getConsumerConnectionConfig(URL remoteAddress) {\n        return cert.get();\n    }\n\n    public static void setSupport(boolean support) {\n        isSupport.set(support);\n    }\n\n    public static void setProviderCert(ProviderCert providerCert) {\n        FirstCertProvider.providerCert.set(providerCert);\n    }\n\n    public static void setCert(Cert cert) {\n        FirstCertProvider.cert.set(cert);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/ssl/SSLConfigCertProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.ssl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.ssl.impl.SSLConfigCertProvider;\nimport org.apache.dubbo.common.utils.IOUtils;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass SSLConfigCertProviderTest {\n    @Test\n    void testSupported() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        SSLConfigCertProvider sslConfigCertProvider = new SSLConfigCertProvider();\n\n        URL url = URL.valueOf(\"\").setScopeModel(applicationModel);\n        Assertions.assertFalse(sslConfigCertProvider.isSupport(url));\n\n        SslConfig sslConfig = new SslConfig();\n        applicationModel.getApplicationConfigManager().setSsl(sslConfig);\n        Assertions.assertTrue(sslConfigCertProvider.isSupport(url));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testGetProviderConnectionConfig() throws IOException {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        SSLConfigCertProvider sslConfigCertProvider = new SSLConfigCertProvider();\n\n        URL url = URL.valueOf(\"\").setScopeModel(applicationModel);\n        Assertions.assertNull(sslConfigCertProvider.getProviderConnectionConfig(url));\n\n        SslConfig sslConfig = new SslConfig();\n        sslConfig.setServerKeyCertChainPath(\"keyCert\");\n        sslConfig.setServerPrivateKeyPath(\"private\");\n        applicationModel.getApplicationConfigManager().setSsl(sslConfig);\n        ProviderCert providerCert = sslConfigCertProvider.getProviderConnectionConfig(url);\n        Assertions.assertNull(providerCert);\n\n        sslConfig.setServerKeyCertChainPath(\n                this.getClass().getClassLoader().getResource(\"certs/cert.pem\").getFile());\n        sslConfig.setServerPrivateKeyPath(\n                this.getClass().getClassLoader().getResource(\"certs/key.pem\").getFile());\n        providerCert = sslConfigCertProvider.getProviderConnectionConfig(url);\n        Assertions.assertNotNull(providerCert);\n        Assertions.assertArrayEquals(\n                IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(\"certs/cert.pem\")),\n                providerCert.getKeyCertChain());\n        Assertions.assertArrayEquals(\n                IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(\"certs/key.pem\")),\n                providerCert.getPrivateKey());\n        Assertions.assertNull(providerCert.getTrustCert());\n\n        sslConfig.setServerTrustCertCollectionPath(\n                this.getClass().getClassLoader().getResource(\"certs/ca.pem\").getFile());\n        providerCert = sslConfigCertProvider.getProviderConnectionConfig(url);\n        Assertions.assertNotNull(providerCert);\n        Assertions.assertArrayEquals(\n                IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(\"certs/cert.pem\")),\n                providerCert.getKeyCertChain());\n        Assertions.assertArrayEquals(\n                IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(\"certs/key.pem\")),\n                providerCert.getPrivateKey());\n        Assertions.assertArrayEquals(\n                IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(\"certs/ca.pem\")),\n                providerCert.getTrustCert());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testGetConsumerConnectionConfig() throws IOException {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        SSLConfigCertProvider sslConfigCertProvider = new SSLConfigCertProvider();\n\n        URL url = URL.valueOf(\"\").setScopeModel(applicationModel);\n        Assertions.assertNull(sslConfigCertProvider.getConsumerConnectionConfig(url));\n\n        SslConfig sslConfig = new SslConfig();\n        sslConfig.setClientKeyCertChainPath(\"keyCert\");\n        sslConfig.setClientPrivateKeyPath(\"private\");\n        applicationModel.getApplicationConfigManager().setSsl(sslConfig);\n        Cert cert = sslConfigCertProvider.getConsumerConnectionConfig(url);\n        Assertions.assertNull(cert);\n\n        sslConfig.setClientKeyCertChainPath(\n                this.getClass().getClassLoader().getResource(\"certs/cert.pem\").getFile());\n        sslConfig.setClientPrivateKeyPath(\n                this.getClass().getClassLoader().getResource(\"certs/key.pem\").getFile());\n        cert = sslConfigCertProvider.getConsumerConnectionConfig(url);\n        Assertions.assertNotNull(cert);\n        Assertions.assertArrayEquals(\n                IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(\"certs/cert.pem\")),\n                cert.getKeyCertChain());\n        Assertions.assertArrayEquals(\n                IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(\"certs/key.pem\")),\n                cert.getPrivateKey());\n\n        sslConfig.setClientTrustCertCollectionPath(\n                this.getClass().getClassLoader().getResource(\"certs/ca.pem\").getFile());\n        cert = sslConfigCertProvider.getConsumerConnectionConfig(url);\n        Assertions.assertNotNull(cert);\n        Assertions.assertArrayEquals(\n                IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(\"certs/cert.pem\")),\n                cert.getKeyCertChain());\n        Assertions.assertArrayEquals(\n                IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(\"certs/key.pem\")),\n                cert.getPrivateKey());\n        Assertions.assertArrayEquals(\n                IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(\"certs/ca.pem\")),\n                cert.getTrustCert());\n\n        frameworkModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/ssl/SecondCertProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.ssl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\n\n@Activate(order = 10000)\npublic class SecondCertProvider implements CertProvider {\n    private static final AtomicBoolean isSupport = new AtomicBoolean(false);\n    private static final AtomicReference<ProviderCert> providerCert = new AtomicReference<>();\n    private static final AtomicReference<Cert> cert = new AtomicReference<>();\n\n    @Override\n    public boolean isSupport(URL address) {\n        return isSupport.get();\n    }\n\n    @Override\n    public ProviderCert getProviderConnectionConfig(URL localAddress) {\n        return providerCert.get();\n    }\n\n    @Override\n    public Cert getConsumerConnectionConfig(URL remoteAddress) {\n        return cert.get();\n    }\n\n    public static void setSupport(boolean support) {\n        isSupport.set(support);\n    }\n\n    public static void setProviderCert(ProviderCert providerCert) {\n        SecondCertProvider.providerCert.set(providerCert);\n    }\n\n    public static void setCert(Cert cert) {\n        SecondCertProvider.cert.set(cert);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/status/StatusTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.status.Status.Level.OK;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.isEmptyOrNullString;\n\nclass StatusTest {\n    @Test\n    void testConstructor1() throws Exception {\n        Status status = new Status(OK, \"message\", \"description\");\n        assertThat(status.getLevel(), is(OK));\n        assertThat(status.getMessage(), equalTo(\"message\"));\n        assertThat(status.getDescription(), equalTo(\"description\"));\n    }\n\n    @Test\n    void testConstructor2() throws Exception {\n        Status status = new Status(OK, \"message\");\n        assertThat(status.getLevel(), is(OK));\n        assertThat(status.getMessage(), equalTo(\"message\"));\n        assertThat(status.getDescription(), isEmptyOrNullString());\n    }\n\n    @Test\n    void testConstructor3() throws Exception {\n        Status status = new Status(OK);\n        assertThat(status.getLevel(), is(OK));\n        assertThat(status.getMessage(), isEmptyOrNullString());\n        assertThat(status.getDescription(), isEmptyOrNullString());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/status/reporter/FrameworkStatusReportServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status.reporter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INSTANCE;\nimport static org.apache.dubbo.common.status.reporter.FrameworkStatusReportService.ADDRESS_CONSUMPTION_STATUS;\nimport static org.apache.dubbo.common.status.reporter.FrameworkStatusReportService.MIGRATION_STEP_STATUS;\nimport static org.apache.dubbo.common.status.reporter.FrameworkStatusReportService.REGISTRATION_STATUS;\n\n/**\n * {@link FrameworkStatusReportService}\n */\nclass FrameworkStatusReportServiceTest {\n\n    @Test\n    void test() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ApplicationConfig app = new ApplicationConfig(\"APP\");\n        applicationModel.getApplicationConfigManager().setApplication(app);\n        FrameworkStatusReportService reportService =\n                applicationModel.getBeanFactory().getBean(FrameworkStatusReportService.class);\n\n        // 1. reportRegistrationStatus\n        reportService.reportRegistrationStatus(reportService.createRegistrationReport(DEFAULT_REGISTER_MODE_INSTANCE));\n\n        // 2. createConsumptionReport\n        URL consumerURL = Mockito.mock(URL.class);\n        Mockito.when(consumerURL.getServiceInterface()).thenReturn(\"Test\");\n        Mockito.when(consumerURL.getGroup()).thenReturn(\"Group\");\n        Mockito.when(consumerURL.getVersion()).thenReturn(\"0.0.0\");\n        Mockito.when(consumerURL.getServiceKey()).thenReturn(\"Group/Test:0.0.0\");\n        Mockito.when(consumerURL.getDisplayServiceKey()).thenReturn(\"Test:0.0.0\");\n        reportService.reportConsumptionStatus(reportService.createConsumptionReport(\n                consumerURL.getServiceInterface(), consumerURL.getVersion(), consumerURL.getGroup(), \"status\"));\n\n        // 3. reportMigrationStepStatus\n        reportService.reportMigrationStepStatus(reportService.createMigrationStepReport(\n                consumerURL.getServiceInterface(),\n                consumerURL.getVersion(),\n                consumerURL.getGroup(),\n                \"FORCE_INTERFACE\",\n                \"FORCE_APPLICATION\",\n                \"true\"));\n\n        MockFrameworkStatusReporter statusReporter =\n                (MockFrameworkStatusReporter) applicationModel.getExtension(FrameworkStatusReporter.class, \"mock\");\n\n        // \"migrationStepStatus\" ->\n        // \"{\"originStep\":\"FORCE_INTERFACE\",\"application\":\"APP\",\"service\":\"Test\",\"success\":\"true\",\"newStep\":\"FORCE_APPLICATION\",\"type\":\"migrationStepStatus\",\"version\":\"0.0.0\",\"group\":\"Group\"}\"\n        // \"registration\" -> \"{\"application\":\"APP\",\"status\":\"instance\"}\"\n        // \"consumption\" ->\n        // \"{\"application\":\"APP\",\"service\":\"Test\",\"type\":\"consumption\",\"version\":\"0.0.0\",\"group\":\"Group\",\"status\":\"status\"}\"\n        Map<String, Object> reportContent = statusReporter.getReportContent();\n        Assertions.assertEquals(reportContent.size(), 3);\n\n        // verify registrationStatus\n        Object registrationStatus = reportContent.get(REGISTRATION_STATUS);\n        Map<String, String> registrationMap = JsonUtils.toJavaObject(String.valueOf(registrationStatus), Map.class);\n        Assertions.assertEquals(registrationMap.get(\"application\"), \"APP\");\n        Assertions.assertEquals(registrationMap.get(\"status\"), \"instance\");\n\n        // verify addressConsumptionStatus\n        Object addressConsumptionStatus = reportContent.get(ADDRESS_CONSUMPTION_STATUS);\n        Map<String, String> consumptionMap =\n                JsonUtils.toJavaObject(String.valueOf(addressConsumptionStatus), Map.class);\n        Assertions.assertEquals(consumptionMap.get(\"application\"), \"APP\");\n        Assertions.assertEquals(consumptionMap.get(\"service\"), \"Test\");\n        Assertions.assertEquals(consumptionMap.get(\"status\"), \"status\");\n        Assertions.assertEquals(consumptionMap.get(\"type\"), \"consumption\");\n        Assertions.assertEquals(consumptionMap.get(\"version\"), \"0.0.0\");\n        Assertions.assertEquals(consumptionMap.get(\"group\"), \"Group\");\n\n        // verify migrationStepStatus\n        Object migrationStepStatus = reportContent.get(MIGRATION_STEP_STATUS);\n        Map<String, String> migrationStepStatusMap =\n                JsonUtils.toJavaObject(String.valueOf(migrationStepStatus), Map.class);\n        Assertions.assertEquals(migrationStepStatusMap.get(\"originStep\"), \"FORCE_INTERFACE\");\n        Assertions.assertEquals(migrationStepStatusMap.get(\"application\"), \"APP\");\n        Assertions.assertEquals(migrationStepStatusMap.get(\"service\"), \"Test\");\n        Assertions.assertEquals(migrationStepStatusMap.get(\"success\"), \"true\");\n        Assertions.assertEquals(migrationStepStatusMap.get(\"newStep\"), \"FORCE_APPLICATION\");\n        Assertions.assertEquals(migrationStepStatusMap.get(\"type\"), \"migrationStepStatus\");\n        Assertions.assertEquals(migrationStepStatusMap.get(\"version\"), \"0.0.0\");\n        Assertions.assertEquals(migrationStepStatusMap.get(\"group\"), \"Group\");\n\n        frameworkModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/status/reporter/MockFrameworkStatusReporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status.reporter;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class MockFrameworkStatusReporter implements FrameworkStatusReporter {\n    Map<String, Object> reportContent = new HashMap<>();\n\n    @Override\n    public void report(String type, Object obj) {\n        reportContent.put(type, obj);\n    }\n\n    public Map<String, Object> getReportContent() {\n        return reportContent;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/status/support/LoadStatusCheckerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status.support;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.status.Status;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.notNullValue;\n\nclass LoadStatusCheckerTest {\n    private static Logger logger = LoggerFactory.getLogger(LoadStatusCheckerTest.class);\n\n    @Test\n    void test() {\n        LoadStatusChecker statusChecker = new LoadStatusChecker();\n        Status status = statusChecker.check();\n        assertThat(status, notNullValue());\n        logger.info(\"load status level: \" + status.getLevel());\n        logger.info(\"load status message: \" + status.getMessage());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/status/support/MemoryStatusCheckerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status.support;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.status.Status;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.status.Status.Level.OK;\nimport static org.apache.dubbo.common.status.Status.Level.WARN;\nimport static org.hamcrest.CoreMatchers.anyOf;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\n\nclass MemoryStatusCheckerTest {\n    private static final Logger logger = LoggerFactory.getLogger(MemoryStatusCheckerTest.class);\n\n    @Test\n    void test() {\n        MemoryStatusChecker statusChecker = new MemoryStatusChecker();\n        Status status = statusChecker.check();\n        assertThat(status.getLevel(), anyOf(is(OK), is(WARN)));\n        logger.info(\"memory status level: \" + status.getLevel());\n        logger.info(\"memory status message: \" + status.getMessage());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/status/support/StatusUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.status.support;\n\nimport org.apache.dubbo.common.status.Status;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.isEmptyOrNullString;\nimport static org.hamcrest.Matchers.not;\n\nclass StatusUtilsTest {\n    @Test\n    void testGetSummaryStatus1() throws Exception {\n        Status status1 = new Status(Status.Level.ERROR);\n        Status status2 = new Status(Status.Level.WARN);\n        Status status3 = new Status(Status.Level.OK);\n        Map<String, Status> statuses = new HashMap<String, Status>();\n        statuses.put(\"status1\", status1);\n        statuses.put(\"status2\", status2);\n        statuses.put(\"status3\", status3);\n        Status status = StatusUtils.getSummaryStatus(statuses);\n        assertThat(status.getLevel(), is(Status.Level.ERROR));\n        assertThat(status.getMessage(), containsString(\"status1\"));\n        assertThat(status.getMessage(), containsString(\"status2\"));\n        assertThat(status.getMessage(), not(containsString(\"status3\")));\n    }\n\n    @Test\n    void testGetSummaryStatus2() throws Exception {\n        Status status1 = new Status(Status.Level.WARN);\n        Status status2 = new Status(Status.Level.OK);\n        Map<String, Status> statuses = new HashMap<String, Status>();\n        statuses.put(\"status1\", status1);\n        statuses.put(\"status2\", status2);\n        Status status = StatusUtils.getSummaryStatus(statuses);\n        assertThat(status.getLevel(), is(Status.Level.WARN));\n        assertThat(status.getMessage(), containsString(\"status1\"));\n        assertThat(status.getMessage(), not(containsString(\"status2\")));\n    }\n\n    @Test\n    void testGetSummaryStatus3() throws Exception {\n        Status status1 = new Status(Status.Level.OK);\n        Map<String, Status> statuses = new HashMap<String, Status>();\n        statuses.put(\"status1\", status1);\n        Status status = StatusUtils.getSummaryStatus(statuses);\n        assertThat(status.getLevel(), is(Status.Level.OK));\n        assertThat(status.getMessage(), isEmptyOrNullString());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/store/support/SimpleDataStoreTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.store.support;\n\nimport org.apache.dubbo.common.store.DataStoreUpdateListener;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass SimpleDataStoreTest {\n    private SimpleDataStore dataStore = new SimpleDataStore();\n\n    @Test\n    void testPutGet() throws Exception {\n        assertNull(dataStore.get(\"xxx\", \"yyy\"));\n\n        dataStore.put(\"name\", \"key\", \"1\");\n        assertEquals(\"1\", dataStore.get(\"name\", \"key\"));\n\n        assertNull(dataStore.get(\"xxx\", \"yyy\"));\n    }\n\n    @Test\n    void testRemove() throws Exception {\n        dataStore.remove(\"xxx\", \"yyy\");\n\n        dataStore.put(\"name\", \"key\", \"1\");\n        dataStore.remove(\"name\", \"key\");\n        assertNull(dataStore.get(\"name\", \"key\"));\n    }\n\n    @Test\n    void testGetComponent() throws Exception {\n        Map<String, Object> map = dataStore.get(\"component\");\n        assertTrue(map != null && map.isEmpty());\n        dataStore.put(\"component\", \"key\", \"value\");\n        map = dataStore.get(\"component\");\n        assertTrue(map != null && map.size() == 1);\n        dataStore.remove(\"component\", \"key\");\n        assertNotEquals(map, dataStore.get(\"component\"));\n    }\n\n    @Test\n    void testNotify() {\n        DataStoreUpdateListener listener = Mockito.mock(DataStoreUpdateListener.class);\n        dataStore.addListener(listener);\n\n        ArgumentCaptor<String> componentNameCaptor = ArgumentCaptor.forClass(String.class);\n        ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class);\n        ArgumentCaptor<Object> valueCaptor = ArgumentCaptor.forClass(Object.class);\n\n        dataStore.put(\"name\", \"key\", \"1\");\n        Mockito.verify(listener).onUpdate(componentNameCaptor.capture(), keyCaptor.capture(), valueCaptor.capture());\n        assertEquals(\"name\", componentNameCaptor.getValue());\n        assertEquals(\"key\", keyCaptor.getValue());\n        assertEquals(\"1\", valueCaptor.getValue());\n\n        dataStore.remove(\"name\", \"key\");\n        Mockito.verify(listener, Mockito.times(2))\n                .onUpdate(componentNameCaptor.capture(), keyCaptor.capture(), valueCaptor.capture());\n        assertEquals(\"name\", componentNameCaptor.getValue());\n        assertEquals(\"key\", keyCaptor.getValue());\n        assertNull(valueCaptor.getValue());\n\n        dataStore.remove(\"name2\", \"key\");\n        Mockito.verify(listener, Mockito.times(0)).onUpdate(\"name2\", \"key\", null);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadlocal/InternalThreadLocalTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadlocal;\n\nimport java.lang.reflect.Field;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.concurrent.locks.LockSupport;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.awaitility.Awaitility.await;\nimport static org.hamcrest.CoreMatchers.instanceOf;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.not;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass InternalThreadLocalTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(InternalThreadLocalTest.class);\n    private static final int THREADS = 10;\n\n    private static final int PERFORMANCE_THREAD_COUNT = 1000;\n\n    private static final int GET_COUNT = 1000000;\n\n    @AfterEach\n    public void setup() {\n        InternalThreadLocalMap.remove();\n    }\n\n    @Test\n    void testInternalThreadLocal() {\n        final AtomicInteger index = new AtomicInteger(0);\n\n        final InternalThreadLocal<Integer> internalThreadLocal = new InternalThreadLocal<Integer>() {\n\n            @Override\n            protected Integer initialValue() {\n                Integer v = index.getAndIncrement();\n                return v;\n            }\n        };\n\n        for (int i = 0; i < THREADS; i++) {\n            Thread t = new Thread(internalThreadLocal::get);\n            t.start();\n        }\n\n        await().until(index::get, is(THREADS));\n    }\n\n    @Test\n    void testRemoveAll() {\n        final InternalThreadLocal<Integer> internalThreadLocal = new InternalThreadLocal<Integer>();\n        internalThreadLocal.set(1);\n        Assertions.assertEquals(1, (int) internalThreadLocal.get(), \"set failed\");\n\n        final InternalThreadLocal<String> internalThreadLocalString = new InternalThreadLocal<String>();\n        internalThreadLocalString.set(\"value\");\n        Assertions.assertEquals(\"value\", internalThreadLocalString.get(), \"set failed\");\n\n        InternalThreadLocal.removeAll();\n        Assertions.assertNull(internalThreadLocal.get(), \"removeAll failed!\");\n        Assertions.assertNull(internalThreadLocalString.get(), \"removeAll failed!\");\n    }\n\n    @Test\n    void testSize() {\n        final InternalThreadLocal<Integer> internalThreadLocal = new InternalThreadLocal<Integer>();\n        internalThreadLocal.set(1);\n        Assertions.assertEquals(1, InternalThreadLocal.size(), \"size method is wrong!\");\n\n        final InternalThreadLocal<String> internalThreadLocalString = new InternalThreadLocal<String>();\n        internalThreadLocalString.set(\"value\");\n        Assertions.assertEquals(2, InternalThreadLocal.size(), \"size method is wrong!\");\n        InternalThreadLocal.removeAll();\n    }\n\n    @Test\n    void testSetAndGet() {\n        final Integer testVal = 10;\n        final InternalThreadLocal<Integer> internalThreadLocal = new InternalThreadLocal<Integer>();\n        internalThreadLocal.set(testVal);\n        Assertions.assertEquals(testVal, internalThreadLocal.get(), \"set is not equals get\");\n    }\n\n    @Test\n    void testRemove() {\n        final InternalThreadLocal<Integer> internalThreadLocal = new InternalThreadLocal<Integer>();\n        internalThreadLocal.set(1);\n        Assertions.assertEquals(1, (int) internalThreadLocal.get(), \"get method false!\");\n\n        internalThreadLocal.remove();\n        Assertions.assertNull(internalThreadLocal.get(), \"remove failed!\");\n    }\n\n    @Test\n    void testOnRemove() {\n        final Integer[] valueToRemove = {null};\n        final InternalThreadLocal<Integer> internalThreadLocal = new InternalThreadLocal<Integer>() {\n            @Override\n            protected void onRemoval(Integer value) {\n                // value calculate\n                valueToRemove[0] = value + 1;\n            }\n        };\n        internalThreadLocal.set(1);\n        Assertions.assertEquals(1, (int) internalThreadLocal.get(), \"get method false!\");\n\n        internalThreadLocal.remove();\n        Assertions.assertEquals(2, (int) valueToRemove[0], \"onRemove method failed!\");\n    }\n\n    @Test\n    void testMultiThreadSetAndGet() throws InterruptedException {\n        final Integer testVal1 = 10;\n        final Integer testVal2 = 20;\n        final InternalThreadLocal<Integer> internalThreadLocal = new InternalThreadLocal<Integer>();\n        final CountDownLatch countDownLatch = new CountDownLatch(2);\n        Thread t1 = new Thread(new Runnable() {\n            @Override\n            public void run() {\n\n                internalThreadLocal.set(testVal1);\n                Assertions.assertEquals(testVal1, internalThreadLocal.get(), \"set is not equals get\");\n                countDownLatch.countDown();\n            }\n        });\n        t1.start();\n\n        Thread t2 = new Thread(new Runnable() {\n            @Override\n            public void run() {\n                internalThreadLocal.set(testVal2);\n                Assertions.assertEquals(testVal2, internalThreadLocal.get(), \"set is not equals get\");\n                countDownLatch.countDown();\n            }\n        });\n        t2.start();\n        countDownLatch.await();\n    }\n\n    /**\n     * print\n     * take[2689]ms\n     * <p></p>\n     * This test is based on a Machine with 4 core and 16g memory.\n     */\n    @Test\n    void testPerformanceTradition() {\n        final ThreadLocal<String>[] caches1 = new ThreadLocal[PERFORMANCE_THREAD_COUNT];\n        final Thread mainThread = Thread.currentThread();\n        for (int i = 0; i < PERFORMANCE_THREAD_COUNT; i++) {\n            caches1[i] = new ThreadLocal<String>();\n        }\n        Thread t1 = new Thread(new Runnable() {\n            @Override\n            public void run() {\n                for (int i = 0; i < PERFORMANCE_THREAD_COUNT; i++) {\n                    caches1[i].set(\"float.lu\");\n                }\n                long start = System.nanoTime();\n                for (int i = 0; i < PERFORMANCE_THREAD_COUNT; i++) {\n                    for (int j = 0; j < GET_COUNT; j++) {\n                        caches1[i].get();\n                    }\n                }\n                long end = System.nanoTime();\n                logger.info(\"take[{}]ms\", TimeUnit.NANOSECONDS.toMillis(end - start));\n                LockSupport.unpark(mainThread);\n            }\n        });\n        t1.start();\n        LockSupport.park(mainThread);\n    }\n\n    /**\n     * print\n     * take[14]ms\n     * <p></p>\n     * This test is based on a Machine with 4 core and 16g memory.\n     */\n    @Test\n    void testPerformance() {\n        final InternalThreadLocal<String>[] caches = new InternalThreadLocal[PERFORMANCE_THREAD_COUNT];\n        final Thread mainThread = Thread.currentThread();\n        for (int i = 0; i < PERFORMANCE_THREAD_COUNT; i++) {\n            caches[i] = new InternalThreadLocal<String>();\n        }\n        Thread t = new InternalThread(new Runnable() {\n            @Override\n            public void run() {\n                for (int i = 0; i < PERFORMANCE_THREAD_COUNT; i++) {\n                    caches[i].set(\"float.lu\");\n                }\n                long start = System.nanoTime();\n                for (int i = 0; i < PERFORMANCE_THREAD_COUNT; i++) {\n                    for (int j = 0; j < GET_COUNT; j++) {\n                        caches[i].get();\n                    }\n                }\n                long end = System.nanoTime();\n                logger.info(\"take[{}]ms\", TimeUnit.NANOSECONDS.toMillis(end - start));\n                LockSupport.unpark(mainThread);\n            }\n        });\n        t.start();\n        LockSupport.park(mainThread);\n    }\n\n    @Test\n    void testConstructionWithIndex() throws Exception {\n        // reset ARRAY_LIST_CAPACITY_MAX_SIZE to speed up\n        int NEW_ARRAY_LIST_CAPACITY_MAX_SIZE = 8;\n        Field nextIndexField = InternalThreadLocalMap.class.getDeclaredField(\"NEXT_INDEX\");\n\n        nextIndexField.setAccessible(true);\n        AtomicInteger nextIndex = (AtomicInteger) nextIndexField.get(AtomicInteger.class);\n        int arrayListCapacityMaxSize = InternalThreadLocalMap.ARRAY_LIST_CAPACITY_MAX_SIZE;\n        int nextIndex_before = nextIndex.incrementAndGet();\n        nextIndex.set(0);\n        final AtomicReference<Throwable> throwable = new AtomicReference<Throwable>();\n        try {\n            InternalThreadLocalMap.ARRAY_LIST_CAPACITY_MAX_SIZE = NEW_ARRAY_LIST_CAPACITY_MAX_SIZE;\n            while (nextIndex.get() < NEW_ARRAY_LIST_CAPACITY_MAX_SIZE) {\n                new InternalThreadLocal<Boolean>();\n            }\n            assertEquals(NEW_ARRAY_LIST_CAPACITY_MAX_SIZE - 1, InternalThreadLocalMap.lastVariableIndex());\n            try {\n                new InternalThreadLocal<Boolean>();\n            } catch (Throwable t) {\n                throwable.set(t);\n            }\n            // Assert the max index cannot greater than (ARRAY_LIST_CAPACITY_MAX_SIZE - 1)\n            assertThat(throwable.get(), is(instanceOf(IllegalStateException.class)));\n            // Assert the index was reset to ARRAY_LIST_CAPACITY_MAX_SIZE after it reaches ARRAY_LIST_CAPACITY_MAX_SIZE\n            assertEquals(NEW_ARRAY_LIST_CAPACITY_MAX_SIZE - 1, InternalThreadLocalMap.lastVariableIndex());\n        } finally {\n            // Restore the index\n            nextIndex.set(nextIndex_before);\n            InternalThreadLocalMap.ARRAY_LIST_CAPACITY_MAX_SIZE = arrayListCapacityMaxSize;\n        }\n    }\n\n    @Test\n    void testInternalThreadLocalMapExpand() throws Exception {\n        final AtomicReference<Throwable> throwable = new AtomicReference<Throwable>();\n        Runnable runnable = new Runnable() {\n            @Override\n            public void run() {\n                int expand_threshold = 1 << 30;\n                try {\n                    InternalThreadLocalMap.get().setIndexedVariable(expand_threshold, null);\n                } catch (Throwable t) {\n                    throwable.set(t);\n                }\n            }\n        };\n        InternalThread internalThread = new InternalThread(runnable);\n        internalThread.start();\n        internalThread.join();\n        // Assert the expanded size is not overflowed to negative value\n        assertThat(throwable.get(), is(not(instanceOf(NegativeArraySizeException.class))));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadlocal/NamedInternalThreadFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadlocal;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass NamedInternalThreadFactoryTest {\n\n    @Test\n    void newThread() throws Exception {\n        NamedInternalThreadFactory namedInternalThreadFactory = new NamedInternalThreadFactory();\n        Thread t = namedInternalThreadFactory.newThread(() -> {});\n\n        Assertions.assertEquals(t.getClass(), InternalThread.class, \"thread is not InternalThread\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/MemoryLimitedLinkedBlockingQueueTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool;\n\nimport java.lang.instrument.Instrumentation;\n\nimport net.bytebuddy.agent.ByteBuddyAgent;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\n\nclass MemoryLimitedLinkedBlockingQueueTest {\n    private static final Logger logger = LoggerFactory.getLogger(MemoryLimitedLinkedBlockingQueueTest.class);\n\n    @Test\n    void test() {\n        ByteBuddyAgent.install();\n        final Instrumentation instrumentation = ByteBuddyAgent.getInstrumentation();\n        MemoryLimitedLinkedBlockingQueue<Runnable> queue = new MemoryLimitedLinkedBlockingQueue<>(1, instrumentation);\n        // an object needs more than 1 byte of space, so it will fail here\n        assertThat(queue.offer(() -> logger.info(\"add fail\")), is(false));\n\n        // will success\n        queue.setMemoryLimit(Integer.MAX_VALUE);\n        assertThat(queue.offer(() -> logger.info(\"add success\")), is(true));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/MemorySafeLinkedBlockingQueueTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool;\n\nimport org.apache.dubbo.common.concurrent.AbortPolicy;\nimport org.apache.dubbo.common.concurrent.RejectException;\n\nimport java.lang.instrument.Instrumentation;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nimport net.bytebuddy.agent.ByteBuddyAgent;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass MemorySafeLinkedBlockingQueueTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(MemorySafeLinkedBlockingQueueTest.class);\n\n    @Test\n    void test() {\n        ByteBuddyAgent.install();\n        final Instrumentation instrumentation = ByteBuddyAgent.getInstrumentation();\n        final long objectSize = instrumentation.getObjectSize((Runnable) () -> {});\n        long maxFreeMemory = (long) MemoryLimitCalculator.maxAvailable();\n        MemorySafeLinkedBlockingQueue<Runnable> queue = new MemorySafeLinkedBlockingQueue<>(maxFreeMemory);\n        // all memory is reserved for JVM, so it will fail here\n        assertThat(queue.offer(() -> {}), is(false));\n\n        // maxFreeMemory-objectSize Byte memory is reserved for the JVM, so this will succeed\n        queue.setMaxFreeMemory((int) (MemoryLimitCalculator.maxAvailable() - objectSize));\n        assertThat(queue.offer(() -> {}), is(true));\n    }\n\n    @Test\n    void testCustomReject() {\n        MemorySafeLinkedBlockingQueue<Runnable> queue = new MemorySafeLinkedBlockingQueue<>(Long.MAX_VALUE);\n        queue.setRejector(new AbortPolicy<>());\n        assertThrows(RejectException.class, () -> queue.offer(() -> {}));\n    }\n\n    @Test\n    @Disabled(\"This test is not stable, it may fail due to performance (C1, C2)\")\n    void testEfficiency() throws InterruptedException {\n        // if length is vert large(unit test may runs for a long time), so you may need to modify JVM param such as :\n        // -Xms=1024m -Xmx=2048m\n        // if you want to test efficiency of MemorySafeLinkedBlockingQueue, you may modify following param: length and\n        // times\n        int length = 1000, times = 1;\n\n        // LinkedBlockingQueue insert Integer: 500W * 20 times\n        long spent1 = spend(new LinkedBlockingQueue<>(), length, times);\n\n        // MemorySafeLinkedBlockingQueue insert Integer: 500W * 20 times\n        long spent2 = spend(newMemorySafeLinkedBlockingQueue(), length, times);\n        System.gc();\n\n        logger.info(\n                \"LinkedBlockingQueue spent {} millis, MemorySafeLinkedBlockingQueue spent {} millis\", spent1, spent2);\n        // efficiency between LinkedBlockingQueue and MemorySafeLinkedBlockingQueue is very nearly the same\n        Assertions.assertTrue(spent1 - spent2 <= 1);\n    }\n\n    private static long spend(LinkedBlockingQueue<Integer> lbq, int length, int times) throws InterruptedException {\n        // new Queue\n        if (lbq instanceof MemorySafeLinkedBlockingQueue) {\n            lbq = newMemorySafeLinkedBlockingQueue();\n        } else {\n            lbq = new LinkedBlockingQueue<>();\n        }\n\n        long total = 0L;\n        for (int i = 0; i < times; i++) {\n            long start = System.currentTimeMillis();\n            for (int j = 0; j < length; j++) {\n                lbq.offer(j);\n            }\n            long end = System.currentTimeMillis();\n            long spent = end - start;\n            total += spent;\n        }\n        long result = total / times;\n\n        // gc\n        System.gc();\n\n        return result;\n    }\n\n    private static MemorySafeLinkedBlockingQueue<Integer> newMemorySafeLinkedBlockingQueue() {\n        ByteBuddyAgent.install();\n        final Instrumentation instrumentation = ByteBuddyAgent.getInstrumentation();\n        final long objectSize = instrumentation.getObjectSize((Runnable) () -> {});\n        int maxFreeMemory = (int) MemoryLimitCalculator.maxAvailable();\n        MemorySafeLinkedBlockingQueue<Integer> queue = new MemorySafeLinkedBlockingQueue<>(maxFreeMemory);\n        queue.setMaxFreeMemory((int) (MemoryLimitCalculator.maxAvailable() - objectSize));\n        queue.setRejector(new AbortPolicy<>());\n        return queue;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/ThreadlessExecutorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ThreadlessExecutorTest {\n    private static final ThreadlessExecutor executor;\n\n    static {\n        executor = new ThreadlessExecutor();\n    }\n\n    @Test\n    void test() throws InterruptedException {\n        for (int i = 0; i < 10; i++) {\n            executor.execute(() -> {\n                throw new RuntimeException(\"test\");\n            });\n        }\n\n        executor.waitAndDrain(123);\n\n        AtomicBoolean invoked = new AtomicBoolean(false);\n        executor.execute(() -> {\n            invoked.set(true);\n        });\n\n        executor.waitAndDrain(123);\n        Assertions.assertTrue(invoked.get());\n\n        executor.shutdown();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/event/ThreadPoolExhaustedEventListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.event;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link ThreadPoolExhaustedEvent} Test\n */\nclass ThreadPoolExhaustedEventListenerTest {\n\n    private MyListener listener;\n\n    @BeforeEach\n    public void init() {\n        this.listener = new MyListener();\n    }\n\n    @Test\n    void testOnEvent() {\n        String msg =\n                \"Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-127.0.0.1:12345, Pool Size: 1 (active: 0, core: 1, max: 1, largest: 1), Task: 6 (completed: 6), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://127.0.0.1:12345!, dubbo version: 2.7.3, current host: 127.0.0.1\";\n        ThreadPoolExhaustedEvent exhaustedEvent = new ThreadPoolExhaustedEvent(msg);\n        listener.onEvent(exhaustedEvent);\n        assertEquals(exhaustedEvent, listener.getThreadPoolExhaustedEvent());\n    }\n\n    static class MyListener implements ThreadPoolExhaustedListener {\n\n        private ThreadPoolExhaustedEvent threadPoolExhaustedEvent;\n\n        @Override\n        public void onEvent(ThreadPoolExhaustedEvent event) {\n            this.threadPoolExhaustedEvent = event;\n        }\n\n        public ThreadPoolExhaustedEvent getThreadPoolExhaustedEvent() {\n            return threadPoolExhaustedEvent;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/event/ThreadPoolExhaustedEventTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.event;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n *  {@link ThreadPoolExhaustedEvent} Test\n */\nclass ThreadPoolExhaustedEventTest {\n\n    @Test\n    void test() {\n        String msg =\n                \"Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-127.0.0.1:12345, Pool Size: 1 (active: 0, core: 1, max: 1, largest: 1), Task: 6 (completed: 6), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://127.0.0.1:12345!, dubbo version: 2.7.3, current host: 127.0.0.1\";\n        ThreadPoolExhaustedEvent event = new ThreadPoolExhaustedEvent(msg);\n\n        assertEquals(msg, event.getMsg());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/manager/ExecutorRepositoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.manager;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.awaitility.Awaitility.await;\n\nclass ExecutorRepositoryTest {\n    private ApplicationModel applicationModel;\n    private ExecutorRepository executorRepository;\n\n    @BeforeEach\n    public void setup() {\n        applicationModel = FrameworkModel.defaultModel().newApplication();\n        executorRepository = ExecutorRepository.getInstance(applicationModel);\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    @Test\n    void testGetExecutor() {\n        testGet(URL.valueOf(\"dubbo://127.0.0.1:23456/TestService\"));\n        testGet(URL.valueOf(\"dubbo://127.0.0.1:23456/TestService?side=consumer\"));\n\n        Assertions.assertNotNull(executorRepository.getSharedExecutor());\n        Assertions.assertNotNull(executorRepository.getServiceExportExecutor());\n        Assertions.assertNotNull(executorRepository.getServiceReferExecutor());\n        executorRepository.nextScheduledExecutor();\n    }\n\n    private void testGet(URL url) {\n        ExecutorService executorService = executorRepository.createExecutorIfAbsent(url);\n        executorService.shutdown();\n        executorService = executorRepository.createExecutorIfAbsent(url);\n        Assertions.assertFalse(executorService.isShutdown());\n\n        Assertions.assertEquals(executorService, executorRepository.getExecutor(url));\n        executorService.shutdown();\n        Assertions.assertNotEquals(executorService, executorRepository.getExecutor(url));\n    }\n\n    @Test\n    void testUpdateExecutor() {\n        URL url = URL.valueOf(\"dubbo://127.0.0.1:23456/TestService?threads=5\");\n        ThreadPoolExecutor executorService = (ThreadPoolExecutor) executorRepository.createExecutorIfAbsent(url);\n\n        executorService.setCorePoolSize(3);\n        executorRepository.updateThreadpool(url, executorService);\n\n        executorService.setCorePoolSize(3);\n        executorService.setMaximumPoolSize(3);\n        executorRepository.updateThreadpool(url, executorService);\n\n        executorService.setMaximumPoolSize(20);\n        executorService.setCorePoolSize(10);\n        executorRepository.updateThreadpool(url, executorService);\n\n        executorService.setCorePoolSize(10);\n        executorService.setMaximumPoolSize(10);\n        executorRepository.updateThreadpool(url, executorService);\n\n        executorService.setCorePoolSize(5);\n        executorRepository.updateThreadpool(url, executorService);\n    }\n\n    @Test\n    void testSharedExecutor() throws Exception {\n        ExecutorService sharedExecutor = executorRepository.getSharedExecutor();\n        CountDownLatch latch = new CountDownLatch(3);\n        CountDownLatch latch1 = new CountDownLatch(1);\n        sharedExecutor.execute(() -> {\n            latch.countDown();\n            try {\n                latch1.await();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        });\n        sharedExecutor.execute(() -> {\n            latch.countDown();\n            try {\n                latch1.await();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        });\n        sharedExecutor.submit(() -> {\n            latch.countDown();\n            try {\n                latch1.await();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        });\n\n        await().until(() -> latch.getCount() == 0);\n        Assertions.assertEquals(3, ((ThreadPoolExecutor) sharedExecutor).getActiveCount());\n        latch1.countDown();\n        await().until(() -> ((ThreadPoolExecutor) sharedExecutor).getActiveCount() == 0);\n        Assertions.assertEquals(3, ((ThreadPoolExecutor) sharedExecutor).getCompletedTaskCount());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/manager/FrameworkExecutorRepositoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.manager;\n\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.awaitility.Awaitility.await;\n\nclass FrameworkExecutorRepositoryTest {\n    private FrameworkModel frameworkModel;\n    private FrameworkExecutorRepository frameworkExecutorRepository;\n\n    @BeforeEach\n    public void setup() {\n        frameworkModel = new FrameworkModel();\n        frameworkExecutorRepository = frameworkModel.getBeanFactory().getBean(FrameworkExecutorRepository.class);\n    }\n\n    @AfterEach\n    public void teardown() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testGetExecutor() {\n\n        Assertions.assertNotNull(frameworkExecutorRepository.getSharedExecutor());\n        frameworkExecutorRepository.nextScheduledExecutor();\n    }\n\n    @Test\n    void testSharedExecutor() throws Exception {\n        ExecutorService sharedExecutor = frameworkExecutorRepository.getSharedExecutor();\n        CountDownLatch latch = new CountDownLatch(3);\n        CountDownLatch latch1 = new CountDownLatch(1);\n        sharedExecutor.execute(() -> {\n            latch.countDown();\n            try {\n                latch1.await();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        });\n        sharedExecutor.execute(() -> {\n            latch.countDown();\n            try {\n                latch1.await();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        });\n        sharedExecutor.submit(() -> {\n            latch.countDown();\n            try {\n                latch1.await();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        });\n\n        await().until(() -> latch.getCount() == 0);\n        Assertions.assertEquals(3, ((ThreadPoolExecutor) sharedExecutor).getActiveCount());\n        latch1.countDown();\n        await().until(() -> ((ThreadPoolExecutor) sharedExecutor).getActiveCount() == 0);\n        Assertions.assertEquals(3, ((ThreadPoolExecutor) sharedExecutor).getCompletedTaskCount());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/serial/SerializingExecutorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.serial;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.awaitility.Awaitility.await;\n\nclass SerializingExecutorTest {\n\n    private ExecutorService service;\n    private SerializingExecutor serializingExecutor;\n\n    @BeforeEach\n    public void before() {\n        service = Executors.newFixedThreadPool(4);\n        serializingExecutor = new SerializingExecutor(service);\n    }\n\n    @Test\n    void testSerial() throws InterruptedException {\n        int total = 10000;\n\n        Map<String, Integer> map = new HashMap<>();\n        map.put(\"val\", 0);\n\n        Semaphore semaphore = new Semaphore(1);\n        CountDownLatch startLatch = new CountDownLatch(1);\n        AtomicBoolean failed = new AtomicBoolean(false);\n\n        for (int i = 0; i < total; i++) {\n            final int index = i;\n            serializingExecutor.execute(() -> {\n                if (!semaphore.tryAcquire()) {\n                    failed.set(true);\n                }\n                try {\n                    startLatch.await();\n                } catch (InterruptedException e) {\n                    throw new RuntimeException(e);\n                }\n                int num = map.get(\"val\");\n                map.put(\"val\", num + 1);\n                if (num != index) {\n                    failed.set(true);\n                }\n                semaphore.release();\n            });\n        }\n\n        startLatch.countDown();\n        await().until(() -> map.get(\"val\") == total);\n        Assertions.assertFalse(failed.get());\n    }\n\n    @Test\n    void testNonSerial() {\n        int total = 10;\n\n        Map<String, Integer> map = new HashMap<>();\n        map.put(\"val\", 0);\n\n        Semaphore semaphore = new Semaphore(1);\n        CountDownLatch startLatch = new CountDownLatch(1);\n        AtomicBoolean failed = new AtomicBoolean(false);\n\n        for (int i = 0; i < total; i++) {\n            final int index = i;\n            service.execute(() -> {\n                if (!semaphore.tryAcquire()) {\n                    failed.set(true);\n                }\n                try {\n                    startLatch.await();\n                } catch (InterruptedException e) {\n                    throw new RuntimeException(e);\n                }\n                int num = map.get(\"val\");\n                map.put(\"val\", num + 1);\n                if (num != index) {\n                    failed.set(true);\n                }\n                semaphore.release();\n            });\n        }\n\n        await().until(() -> ((ThreadPoolExecutor) service).getActiveCount() == 4);\n        startLatch.countDown();\n        await().until(() -> ((ThreadPoolExecutor) service).getCompletedTaskCount() == total);\n        Assertions.assertTrue(failed.get());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/AbortPolicyWithReportTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;\nimport org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedEvent;\nimport org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedListener;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.io.FileOutputStream;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.OS_WIN_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_OS_NAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.USER_HOME;\nimport static org.awaitility.Awaitility.await;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass AbortPolicyWithReportTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(AbortPolicyWithReportTest.class);\n\n    @BeforeEach\n    public void setUp() {\n        AbortPolicyWithReport.lastPrintTime = 0;\n    }\n\n    @Test\n    void jStackDumpTest() {\n        URL url = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?dump.directory=/tmp&version=1.0.0&application=morgan&noValue=\");\n        AtomicReference<FileOutputStream> fileOutputStream = new AtomicReference<>();\n\n        AbortPolicyWithReport abortPolicyWithReport = new AbortPolicyWithReport(\"Test\", url) {\n            @Override\n            protected void jstack(FileOutputStream jStackStream) {\n                fileOutputStream.set(jStackStream);\n            }\n        };\n        ExecutorService executorService = Executors.newFixedThreadPool(1);\n        AbortPolicyWithReport.lastPrintTime = 0;\n        Assertions.assertThrows(RejectedExecutionException.class, () -> {\n            abortPolicyWithReport.rejectedExecution(() -> logger.debug(\"hello\"), (ThreadPoolExecutor) executorService);\n        });\n\n        await().until(() -> AbortPolicyWithReport.guard.availablePermits() == 1);\n        Assertions.assertNotNull(fileOutputStream.get());\n        executorService.shutdown();\n    }\n\n    @Test\n    void jStack_ConcurrencyDump_Silence_10Min() {\n        URL url = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?dump.directory=/tmp&version=1.0.0&application=morgan&noValue=\");\n        AtomicInteger jStackCount = new AtomicInteger(0);\n        AtomicInteger failureCount = new AtomicInteger(0);\n        AtomicInteger finishedCount = new AtomicInteger(0);\n        AtomicInteger timeoutCount = new AtomicInteger(0);\n        AbortPolicyWithReport abortPolicyWithReport = new AbortPolicyWithReport(\"Test\", url) {\n            @Override\n            protected void jstack(FileOutputStream jStackStream) {\n                jStackCount.incrementAndGet();\n                // try to simulate the jstack cost long time, so that AbortPolicyWithReport may jstack repeatedly.\n                long startTime = System.currentTimeMillis();\n                await().atLeast(200, TimeUnit.MILLISECONDS).until(() -> System.currentTimeMillis() - startTime >= 300);\n            }\n        };\n        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(\n                4,\n                4,\n                0,\n                TimeUnit.MILLISECONDS,\n                new SynchronousQueue<>(),\n                new NamedInternalThreadFactory(\"jStack_ConcurrencyDump_Silence_10Min\", false),\n                abortPolicyWithReport);\n        int runTimes = 100;\n        List<Future<?>> futureList = new LinkedList<>();\n        for (int i = 0; i < runTimes; i++) {\n            try {\n                futureList.add(threadPoolExecutor.submit(() -> {\n                    finishedCount.incrementAndGet();\n                    long start = System.currentTimeMillis();\n                    // try to await 1s to make sure jstack dump thread scheduled\n                    await().atLeast(300, TimeUnit.MILLISECONDS).until(() -> System.currentTimeMillis() - start >= 300);\n                }));\n            } catch (Exception ignored) {\n                failureCount.incrementAndGet();\n            }\n        }\n        futureList.forEach(f -> {\n            try {\n                f.get(500, TimeUnit.MILLISECONDS);\n            } catch (Exception ignored) {\n                timeoutCount.incrementAndGet();\n            }\n        });\n\n        logger.info(\n                \"jStackCount: {}, finishedCount: {}, failureCount: {}, timeoutCount: {}\",\n                jStackCount.get(),\n                finishedCount.get(),\n                failureCount.get(),\n                timeoutCount.get());\n        Assertions.assertEquals(\n                runTimes, finishedCount.get() + failureCount.get(), \"all the test thread should be run completely\");\n        Assertions.assertEquals(1, jStackCount.get(), \"'jstack' should be called only once in 10 minutes\");\n        threadPoolExecutor.shutdown();\n    }\n\n    @Test\n    void jStackDumpTest_dumpDirectoryNotExists_cannotBeCreatedTakeUserHome() {\n        final String dumpDirectory = dumpDirectoryCannotBeCreated();\n\n        URL url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?dump.directory=\"\n                + dumpDirectory\n                + \"&version=1.0.0&application=morgan&noValue=true\");\n        AbortPolicyWithReport abortPolicyWithReport = new AbortPolicyWithReport(\"Test\", url);\n\n        Assertions.assertEquals(\n                SystemPropertyConfigUtils.getSystemProperty(USER_HOME), abortPolicyWithReport.getDumpPath());\n    }\n\n    private String dumpDirectoryCannotBeCreated() {\n        final String os =\n                SystemPropertyConfigUtils.getSystemProperty(SYSTEM_OS_NAME).toLowerCase();\n        if (os.contains(OS_WIN_PREFIX)) {\n            // colon is a reserved character which could not be used in a file or directory name,\n            // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file\n            return \"c:o:n\";\n        } else {\n            return \"/dev/full/\" + UUID.randomUUID().toString();\n        }\n    }\n\n    @Test\n    void jStackDumpTest_dumpDirectoryNotExists_canBeCreated() {\n        final String dumpDirectory = UUID.randomUUID().toString();\n\n        URL url = URL.valueOf(\"dubbo://admin:hello1234@10.20.130.230:20880/context/path?dump.directory=\"\n                + dumpDirectory\n                + \"&version=1.0.0&application=morgan&noValue=true\");\n        AbortPolicyWithReport abortPolicyWithReport = new AbortPolicyWithReport(\"Test\", url);\n\n        Assertions.assertNotEquals(\n                SystemPropertyConfigUtils.getSystemProperty(USER_HOME), abortPolicyWithReport.getDumpPath());\n    }\n\n    @Test\n    void test_dispatchThreadPoolExhaustedEvent() {\n        URL url = URL.valueOf(\n                \"dubbo://admin:hello1234@10.20.130.230:20880/context/path?dump.directory=/tmp&version=1.0.0&application=morgan&noValue=\");\n        AbortPolicyWithReport abortPolicyWithReport = new AbortPolicyWithReport(\"Test\", url);\n        String msg =\n                \"Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-127.0.0.1:12345, Pool Size: 1 (active: 0, core: 1, max: 1, largest: 1), Task: 6 (completed: 6), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://127.0.0.1:12345!, dubbo version: 2.7.3, current host: 127.0.0.1\";\n        MyListener listener = new MyListener();\n        abortPolicyWithReport.addThreadPoolExhaustedEventListener(listener);\n        abortPolicyWithReport.dispatchThreadPoolExhaustedEvent(msg);\n\n        assertEquals(listener.getThreadPoolExhaustedEvent().getMsg(), msg);\n    }\n\n    static class MyListener implements ThreadPoolExhaustedListener {\n\n        private ThreadPoolExhaustedEvent threadPoolExhaustedEvent;\n\n        @Override\n        public void onEvent(ThreadPoolExhaustedEvent event) {\n            this.threadPoolExhaustedEvent = event;\n        }\n\n        public ThreadPoolExhaustedEvent getThreadPoolExhaustedEvent() {\n            return threadPoolExhaustedEvent;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/cached/CachedThreadPoolTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.cached;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadlocal.InternalThread;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.instanceOf;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.startsWith;\n\nclass CachedThreadPoolTest {\n    @Test\n    void getExecutor1() throws Exception {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + THREAD_NAME_KEY\n                + \"=demo&\" + CORE_THREADS_KEY\n                + \"=1&\" + THREADS_KEY\n                + \"=2&\" + ALIVE_KEY\n                + \"=1000&\" + QUEUES_KEY\n                + \"=0\");\n        ThreadPool threadPool = new CachedThreadPool();\n        ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor(url);\n        assertThat(executor.getCorePoolSize(), is(1));\n        assertThat(executor.getMaximumPoolSize(), is(2));\n        assertThat(executor.getQueue(), Matchers.<BlockingQueue<Runnable>>instanceOf(SynchronousQueue.class));\n        assertThat(\n                executor.getRejectedExecutionHandler(),\n                Matchers.<RejectedExecutionHandler>instanceOf(AbortPolicyWithReport.class));\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        executor.execute(() -> {\n            Thread thread = Thread.currentThread();\n            assertThat(thread, instanceOf(InternalThread.class));\n            assertThat(thread.getName(), startsWith(\"demo\"));\n            latch.countDown();\n        });\n\n        latch.await();\n        assertThat(latch.getCount(), is(0L));\n    }\n\n    @Test\n    void getExecutor2() {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + QUEUES_KEY + \"=1\");\n        ThreadPool threadPool = new CachedThreadPool();\n        ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor(url);\n        assertThat(executor.getQueue(), Matchers.<BlockingQueue<Runnable>>instanceOf(LinkedBlockingQueue.class));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/eager/EagerThreadPoolExecutorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.eager;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.awaitility.Awaitility.await;\n\nclass EagerThreadPoolExecutorTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(EagerThreadPoolExecutorTest.class);\n    private static final URL URL = new ServiceConfigURL(\"dubbo\", \"localhost\", 8080);\n\n    /**\n     * It print like this:\n     * thread number in current pool：1,  task number in task queue：0 executor size: 1\n     * thread number in current pool：2,  task number in task queue：0 executor size: 2\n     * thread number in current pool：3,  task number in task queue：0 executor size: 3\n     * thread number in current pool：4,  task number in task queue：0 executor size: 4\n     * thread number in current pool：5,  task number in task queue：0 executor size: 5\n     * thread number in current pool：6,  task number in task queue：0 executor size: 6\n     * thread number in current pool：7,  task number in task queue：0 executor size: 7\n     * thread number in current pool：8,  task number in task queue：0 executor size: 8\n     * thread number in current pool：9,  task number in task queue：0 executor size: 9\n     * thread number in current pool：10,  task number in task queue：0 executor size: 10\n     * thread number in current pool：10,  task number in task queue：4 executor size: 10\n     * thread number in current pool：10,  task number in task queue：3 executor size: 10\n     * thread number in current pool：10,  task number in task queue：2 executor size: 10\n     * thread number in current pool：10,  task number in task queue：1 executor size: 10\n     * thread number in current pool：10,  task number in task queue：0 executor size: 10\n     * <p>\n     * We can see , when the core threads are in busy,\n     * the thread pool create thread (but thread nums always less than max) instead of put task into queue.\n     */\n    @Disabled(\"replaced to testEagerThreadPoolFast for performance\")\n    @Test\n    void testEagerThreadPool() throws Exception {\n        String name = \"eager-tf\";\n        int queues = 5;\n        int cores = 5;\n        int threads = 10;\n        // alive 1 second\n        long alive = 1000;\n\n        // init queue and executor\n        TaskQueue<Runnable> taskQueue = new TaskQueue<Runnable>(queues);\n        final EagerThreadPoolExecutor executor = new EagerThreadPoolExecutor(\n                cores,\n                threads,\n                alive,\n                TimeUnit.MILLISECONDS,\n                taskQueue,\n                new NamedThreadFactory(name, true),\n                new AbortPolicyWithReport(name, URL));\n        taskQueue.setExecutor(executor);\n\n        for (int i = 0; i < 15; i++) {\n            Thread.sleep(50);\n            executor.execute(() -> {\n                logger.info(\n                        \"thread number in current pool：{},  task number in task queue：{} executor size: {}\",\n                        executor.getPoolSize(),\n                        executor.getQueue().size(),\n                        executor.getPoolSize());\n                try {\n                    Thread.sleep(1000);\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            });\n        }\n        Thread.sleep(5000);\n        // cores theads are all alive.\n        Assertions.assertEquals(executor.getPoolSize(), cores, \"more than cores threads alive!\");\n\n        executor.shutdown();\n    }\n\n    @Test\n    void testEagerThreadPoolFast() {\n        String name = \"eager-tf\";\n        int queues = 5;\n        int cores = 5;\n        // github actions usually run on 4 cores which could be determined by LoadStatusCheckerTest\n        int threads = 5;\n        // alive 1 second\n        long alive = 1000;\n\n        // init queue and executor\n        TaskQueue<Runnable> taskQueue = new TaskQueue<>(queues);\n        final EagerThreadPoolExecutor executor = new EagerThreadPoolExecutor(\n                cores,\n                threads,\n                alive,\n                TimeUnit.MILLISECONDS,\n                taskQueue,\n                new NamedThreadFactory(name, true),\n                new AbortPolicyWithReport(name, URL));\n        taskQueue.setExecutor(executor);\n\n        CountDownLatch countDownLatch1 = new CountDownLatch(1);\n        for (int i = 0; i < 5; i++) {\n            executor.execute(() -> {\n                try {\n                    countDownLatch1.await();\n                } catch (InterruptedException e) {\n                    throw new RuntimeException(e);\n                }\n            });\n        }\n        await().until(() -> executor.getPoolSize() == 5);\n        Assertions.assertEquals(5, executor.getActiveCount());\n\n        CountDownLatch countDownLatch2 = new CountDownLatch(1);\n        AtomicBoolean started = new AtomicBoolean(false);\n        for (int i = 0; i < 5; i++) {\n            executor.execute(() -> {\n                started.set(true);\n                try {\n                    countDownLatch2.await();\n                } catch (InterruptedException e) {\n                    throw new RuntimeException(e);\n                }\n            });\n        }\n\n        await().until(() -> executor.getQueue().size() == 5);\n        Assertions.assertEquals(5, executor.getActiveCount());\n        Assertions.assertEquals(5, executor.getPoolSize());\n        Assertions.assertFalse(started.get());\n        countDownLatch1.countDown();\n\n        await().until(() -> executor.getActiveCount() == 5);\n        Assertions.assertTrue(started.get());\n\n        countDownLatch2.countDown();\n        await().until(() -> executor.getActiveCount() == 0);\n\n        await().until(() -> executor.getPoolSize() == cores);\n\n        executor.shutdown();\n    }\n\n    @Test\n    void testSPI() {\n        ExtensionLoader<ThreadPool> extensionLoader =\n                ApplicationModel.defaultModel().getDefaultModule().getExtensionLoader(ThreadPool.class);\n\n        ExecutorService executorService =\n                (ExecutorService) extensionLoader.getExtension(\"eager\").getExecutor(URL);\n\n        Assertions.assertEquals(\n                \"EagerThreadPoolExecutor\", executorService.getClass().getSimpleName(), \"test spi fail!\");\n    }\n\n    @Test\n    void testEagerThreadPool_rejectExecution1() {\n        String name = \"eager-tf\";\n        int cores = 1;\n        int threads = 3;\n        int queues = 2;\n        long alive = 1000;\n\n        // init queue and executor\n        TaskQueue<Runnable> taskQueue = new TaskQueue<>(queues);\n        final EagerThreadPoolExecutor executor = new EagerThreadPoolExecutor(\n                cores,\n                threads,\n                alive,\n                TimeUnit.MILLISECONDS,\n                taskQueue,\n                new NamedThreadFactory(name, true),\n                new AbortPolicyWithReport(name, URL));\n        taskQueue.setExecutor(executor);\n\n        CountDownLatch countDownLatch = new CountDownLatch(1);\n        Runnable runnable = () -> {\n            try {\n                countDownLatch.await();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        };\n        for (int i = 0; i < 5; i++) {\n            executor.execute(runnable);\n        }\n\n        await().until(() -> executor.getPoolSize() == threads);\n        await().until(() -> executor.getQueue().size() == queues);\n\n        Assertions.assertThrows(RejectedExecutionException.class, () -> executor.execute(runnable));\n\n        countDownLatch.countDown();\n        await().until(() -> executor.getActiveCount() == 0);\n\n        executor.execute(runnable);\n\n        executor.shutdown();\n    }\n\n    @Test\n    void testEagerThreadPool_rejectExecution2() {\n        String name = \"eager-tf\";\n        int cores = 1;\n        int threads = 3;\n        int queues = 2;\n        long alive = 1000;\n\n        // init queue and executor\n        AtomicReference<Runnable> runnableWhenRetryOffer = new AtomicReference<>();\n        TaskQueue<Runnable> taskQueue = new TaskQueue<Runnable>(queues) {\n            @Override\n            public boolean retryOffer(Runnable o, long timeout, TimeUnit unit) throws InterruptedException {\n                if (runnableWhenRetryOffer.get() != null) {\n                    runnableWhenRetryOffer.get().run();\n                }\n                return super.retryOffer(o, timeout, unit);\n            }\n        };\n        final EagerThreadPoolExecutor executor = new EagerThreadPoolExecutor(\n                cores,\n                threads,\n                alive,\n                TimeUnit.MILLISECONDS,\n                taskQueue,\n                new NamedThreadFactory(name, true),\n                new AbortPolicyWithReport(name, URL));\n        taskQueue.setExecutor(executor);\n\n        Semaphore semaphore = new Semaphore(0);\n        Runnable runnable = () -> {\n            try {\n                semaphore.acquire();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        };\n        for (int i = 0; i < 5; i++) {\n            executor.execute(runnable);\n        }\n\n        await().until(() -> executor.getPoolSize() == threads);\n        await().until(() -> executor.getQueue().size() == queues);\n\n        Assertions.assertThrows(RejectedExecutionException.class, () -> executor.execute(runnable));\n\n        runnableWhenRetryOffer.set(() -> {\n            semaphore.release();\n            await().until(() -> executor.getCompletedTaskCount() == 1);\n        });\n        executor.execute(runnable);\n        semaphore.release(5);\n        await().until(() -> executor.getActiveCount() == 0);\n\n        executor.shutdown();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/eager/EagerThreadPoolTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.eager;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadlocal.InternalThread;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.instanceOf;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.startsWith;\n\nclass EagerThreadPoolTest {\n    @Test\n    void getExecutor1() throws Exception {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + THREAD_NAME_KEY\n                + \"=demo&\" + CORE_THREADS_KEY\n                + \"=1&\" + THREADS_KEY\n                + \"=2&\" + ALIVE_KEY\n                + \"=1000&\" + QUEUES_KEY\n                + \"=0\");\n        ThreadPool threadPool = new EagerThreadPool();\n        ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor(url);\n        assertThat(executor, instanceOf(EagerThreadPoolExecutor.class));\n        assertThat(executor.getCorePoolSize(), is(1));\n        assertThat(executor.getMaximumPoolSize(), is(2));\n        assertThat(executor.getKeepAliveTime(TimeUnit.MILLISECONDS), is(1000L));\n        assertThat(executor.getQueue().remainingCapacity(), is(1));\n        assertThat(executor.getQueue(), Matchers.<BlockingQueue<Runnable>>instanceOf(TaskQueue.class));\n        assertThat(\n                executor.getRejectedExecutionHandler(),\n                Matchers.<RejectedExecutionHandler>instanceOf(AbortPolicyWithReport.class));\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        executor.execute(() -> {\n            Thread thread = Thread.currentThread();\n            assertThat(thread, instanceOf(InternalThread.class));\n            assertThat(thread.getName(), startsWith(\"demo\"));\n            latch.countDown();\n        });\n\n        latch.await();\n        assertThat(latch.getCount(), is(0L));\n    }\n\n    @Test\n    void getExecutor2() {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + QUEUES_KEY + \"=2\");\n        ThreadPool threadPool = new EagerThreadPool();\n        ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor(url);\n        assertThat(executor.getQueue().remainingCapacity(), is(2));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/eager/TaskQueueTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.eager;\n\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\nimport static org.mockito.Mockito.mock;\n\nclass TaskQueueTest {\n\n    private TaskQueue<Runnable> queue;\n    private EagerThreadPoolExecutor executor;\n\n    @BeforeEach\n    void setup() {\n        queue = new TaskQueue<Runnable>(1);\n        executor = mock(EagerThreadPoolExecutor.class);\n        queue.setExecutor(executor);\n    }\n\n    @Test\n    void testOffer1() throws Exception {\n        Assertions.assertThrows(RejectedExecutionException.class, () -> {\n            TaskQueue<Runnable> queue = new TaskQueue<Runnable>(1);\n            queue.offer(mock(Runnable.class));\n        });\n    }\n\n    @Test\n    void testOffer2() throws Exception {\n        Mockito.when(executor.getPoolSize()).thenReturn(2);\n        Mockito.when(executor.getActiveCount()).thenReturn(1);\n        assertThat(queue.offer(mock(Runnable.class)), is(true));\n    }\n\n    @Test\n    void testOffer3() throws Exception {\n        Mockito.when(executor.getPoolSize()).thenReturn(2);\n        Mockito.when(executor.getActiveCount()).thenReturn(2);\n        Mockito.when(executor.getMaximumPoolSize()).thenReturn(4);\n        assertThat(queue.offer(mock(Runnable.class)), is(false));\n    }\n\n    @Test\n    void testOffer4() throws Exception {\n        Mockito.when(executor.getPoolSize()).thenReturn(4);\n        Mockito.when(executor.getActiveCount()).thenReturn(4);\n        Mockito.when(executor.getMaximumPoolSize()).thenReturn(4);\n        assertThat(queue.offer(mock(Runnable.class)), is(true));\n    }\n\n    @Test\n    void testRetryOffer1() throws Exception {\n        Assertions.assertThrows(RejectedExecutionException.class, () -> {\n            Mockito.when(executor.isShutdown()).thenReturn(true);\n            queue.retryOffer(mock(Runnable.class), 1000, TimeUnit.MILLISECONDS);\n        });\n    }\n\n    @Test\n    void testRetryOffer2() throws Exception {\n        Mockito.when(executor.isShutdown()).thenReturn(false);\n        assertThat(queue.retryOffer(mock(Runnable.class), 1000, TimeUnit.MILLISECONDS), is(true));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/fixed/FixedThreadPoolTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.fixed;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadlocal.InternalThread;\nimport org.apache.dubbo.common.threadpool.MemorySafeLinkedBlockingQueue;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.instanceOf;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.startsWith;\n\nclass FixedThreadPoolTest {\n    @Test\n    void getExecutor1() throws Exception {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + THREAD_NAME_KEY\n                + \"=demo&\" + CORE_THREADS_KEY\n                + \"=1&\" + THREADS_KEY\n                + \"=2&\" + QUEUES_KEY\n                + \"=0\");\n        ThreadPool threadPool = new FixedThreadPool();\n        ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor(url);\n        assertThat(executor.getCorePoolSize(), is(2));\n        assertThat(executor.getMaximumPoolSize(), is(2));\n        assertThat(executor.getKeepAliveTime(TimeUnit.MILLISECONDS), is(0L));\n        assertThat(executor.getQueue(), Matchers.<BlockingQueue<Runnable>>instanceOf(SynchronousQueue.class));\n        assertThat(\n                executor.getRejectedExecutionHandler(),\n                Matchers.<RejectedExecutionHandler>instanceOf(AbortPolicyWithReport.class));\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        executor.execute(new Runnable() {\n            @Override\n            public void run() {\n                Thread thread = Thread.currentThread();\n                assertThat(thread, instanceOf(InternalThread.class));\n                assertThat(thread.getName(), startsWith(\"demo\"));\n                latch.countDown();\n            }\n        });\n\n        latch.await();\n        assertThat(latch.getCount(), is(0L));\n    }\n\n    @Test\n    void getExecutor2() throws Exception {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + QUEUES_KEY + \"=1\");\n        ThreadPool threadPool = new FixedThreadPool();\n        ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor(url);\n        assertThat(executor.getQueue(), Matchers.<BlockingQueue<Runnable>>instanceOf(LinkedBlockingQueue.class));\n    }\n\n    @Test\n    void testNegativeQueuesCreateUnboundedQueue() {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + QUEUES_KEY + \"=-1\");\n        ThreadPool threadPool = new FixedThreadPool();\n        ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor(url);\n        assertThat(\n                executor.getQueue(), Matchers.<BlockingQueue<Runnable>>instanceOf(MemorySafeLinkedBlockingQueue.class));\n        assertThat(executor.getQueue().remainingCapacity(), is(Integer.MAX_VALUE));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/limited/LimitedThreadPoolTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.limited;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadlocal.InternalThread;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.instanceOf;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.startsWith;\n\nclass LimitedThreadPoolTest {\n    @Test\n    void getExecutor1() throws Exception {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + THREAD_NAME_KEY\n                + \"=demo&\" + CORE_THREADS_KEY\n                + \"=1&\" + THREADS_KEY\n                + \"=2&\" + QUEUES_KEY\n                + \"=0\");\n        ThreadPool threadPool = new LimitedThreadPool();\n        ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor(url);\n        assertThat(executor.getCorePoolSize(), is(1));\n        assertThat(executor.getMaximumPoolSize(), is(2));\n        assertThat(executor.getQueue(), Matchers.<BlockingQueue<Runnable>>instanceOf(SynchronousQueue.class));\n        assertThat(\n                executor.getRejectedExecutionHandler(),\n                Matchers.<RejectedExecutionHandler>instanceOf(AbortPolicyWithReport.class));\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        executor.execute(new Runnable() {\n            @Override\n            public void run() {\n                Thread thread = Thread.currentThread();\n                assertThat(thread, instanceOf(InternalThread.class));\n                assertThat(thread.getName(), startsWith(\"demo\"));\n                latch.countDown();\n            }\n        });\n\n        latch.await();\n        assertThat(latch.getCount(), is(0L));\n    }\n\n    @Test\n    void getExecutor2() {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + QUEUES_KEY + \"=1\");\n        ThreadPool threadPool = new LimitedThreadPool();\n        ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor(url);\n        assertThat(executor.getQueue(), Matchers.<BlockingQueue<Runnable>>instanceOf(LinkedBlockingQueue.class));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/timer/HashedWheelTimerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.timer;\n\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\n\nimport java.lang.ref.WeakReference;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.awaitility.Awaitility.await;\n\nclass HashedWheelTimerTest {\n    private CountDownLatch tryStopTaskCountDownLatch = new CountDownLatch(1);\n    private CountDownLatch errorTaskCountDownLatch = new CountDownLatch(1);\n\n    private static class EmptyTask implements TimerTask {\n        @Override\n        public void run(Timeout timeout) {}\n    }\n\n    private static class BlockTask implements TimerTask {\n        @Override\n        public void run(Timeout timeout) throws InterruptedException {\n            this.wait();\n        }\n    }\n\n    private class ErrorTask implements TimerTask {\n        @Override\n        public void run(Timeout timeout) {\n            errorTaskCountDownLatch.countDown();\n            throw new RuntimeException(\"Test\");\n        }\n    }\n\n    private class TryStopTask implements TimerTask {\n        private Timer timer;\n\n        public TryStopTask(Timer timer) {\n            this.timer = timer;\n        }\n\n        @Override\n        public void run(Timeout timeout) {\n            Assertions.assertThrows(RuntimeException.class, () -> timer.stop());\n            tryStopTaskCountDownLatch.countDown();\n        }\n    }\n\n    @Test\n    void constructorTest() {\n        // use weak reference to let gc work every time\n        // which can check finalize method and reduce memory usage in time\n        WeakReference<Timer> timer = new WeakReference<>(new HashedWheelTimer());\n        timer = new WeakReference<>(new HashedWheelTimer(100, TimeUnit.MILLISECONDS));\n        timer = new WeakReference<>(new HashedWheelTimer(100, TimeUnit.MILLISECONDS, 8));\n\n        // to cover arg check branches\n        Assertions.assertThrows(RuntimeException.class, () -> {\n            new HashedWheelTimer(null, 100, TimeUnit.MILLISECONDS, 8, -1);\n        });\n\n        Assertions.assertThrows(RuntimeException.class, () -> {\n            new HashedWheelTimer(new NamedThreadFactory(\"dubbo-future-timeout\", true), 0, TimeUnit.MILLISECONDS, 8, -1);\n        });\n\n        Assertions.assertThrows(RuntimeException.class, () -> {\n            new HashedWheelTimer(new NamedThreadFactory(\"dubbo-future-timeout\", true), 100, null, 8, -1);\n        });\n\n        Assertions.assertThrows(RuntimeException.class, () -> {\n            new HashedWheelTimer(\n                    new NamedThreadFactory(\"dubbo-future-timeout\", true), 100, TimeUnit.MILLISECONDS, 0, -1);\n        });\n\n        Assertions.assertThrows(RuntimeException.class, () -> {\n            new HashedWheelTimer(\n                    new NamedThreadFactory(\"dubbo-future-timeout\", true), Long.MAX_VALUE, TimeUnit.MILLISECONDS, 8, -1);\n        });\n\n        Assertions.assertThrows(RuntimeException.class, () -> {\n            new HashedWheelTimer(\n                    new NamedThreadFactory(\"dubbo-future-timeout\", true),\n                    100,\n                    TimeUnit.MILLISECONDS,\n                    Integer.MAX_VALUE,\n                    -1);\n        });\n\n        for (int i = 0; i < 128; i++) {\n            // to trigger INSTANCE_COUNT_LIMIT\n            timer = new WeakReference<>(new HashedWheelTimer());\n        }\n\n        System.gc();\n    }\n\n    @Test\n    void createTaskTest() throws InterruptedException {\n        HashedWheelTimer timer = new HashedWheelTimer(\n                new NamedThreadFactory(\"dubbo-future-timeout\", true), 10, TimeUnit.MILLISECONDS, 8, 8);\n\n        EmptyTask emptyTask = new EmptyTask();\n        Assertions.assertThrows(RuntimeException.class, () -> timer.newTimeout(null, 5, TimeUnit.SECONDS));\n        Assertions.assertThrows(RuntimeException.class, () -> timer.newTimeout(emptyTask, 5, null));\n\n        Timeout timeout = timer.newTimeout(new ErrorTask(), 10, TimeUnit.MILLISECONDS);\n        errorTaskCountDownLatch.await();\n        Assertions.assertFalse(timeout.cancel());\n        Assertions.assertFalse(timeout.isCancelled());\n        Assertions.assertNotNull(timeout.toString());\n        Assertions.assertEquals(timeout.timer(), timer);\n\n        timeout = timer.newTimeout(emptyTask, 1000, TimeUnit.SECONDS);\n        timeout.cancel();\n        Assertions.assertTrue(timeout.isCancelled());\n\n        List<Timeout> timeouts = new LinkedList<>();\n        BlockTask blockTask = new BlockTask();\n        while (timer.pendingTimeouts() < 8) {\n            // to trigger maxPendingTimeouts\n            timeout = timer.newTimeout(blockTask, -1, TimeUnit.MILLISECONDS);\n            timeouts.add(timeout);\n            Assertions.assertNotNull(timeout.toString());\n        }\n        Assertions.assertEquals(8, timer.pendingTimeouts());\n\n        // this will throw an exception because of maxPendingTimeouts\n        Assertions.assertThrows(RuntimeException.class, () -> timer.newTimeout(blockTask, 1, TimeUnit.MILLISECONDS));\n\n        Timeout secondTimeout = timeouts.get(2);\n        // wait until the task expired\n        await().until(secondTimeout::isExpired);\n\n        timer.stop();\n    }\n\n    @Test\n    void stopTaskTest() throws InterruptedException {\n        Timer timer = new HashedWheelTimer(new NamedThreadFactory(\"dubbo-future-timeout\", true));\n        timer.newTimeout(new TryStopTask(timer), 10, TimeUnit.MILLISECONDS);\n        tryStopTaskCountDownLatch.await();\n\n        for (int i = 0; i < 8; i++) {\n            timer.newTimeout(new EmptyTask(), 0, TimeUnit.SECONDS);\n        }\n        // stop timer\n        timer.stop();\n        Assertions.assertTrue(timer.isStop());\n\n        // this will throw an exception\n        Assertions.assertThrows(RuntimeException.class, () -> timer.newTimeout(new EmptyTask(), 5, TimeUnit.SECONDS));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/url/URLParamTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.url;\n\nimport org.apache.dubbo.common.url.component.URLParam;\nimport org.apache.dubbo.common.utils.CollectionUtils;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass URLParamTest {\n    @Test\n    void testParseWithRawParam() {\n        URLParam urlParam1 = URLParam.parse(\"aaa=aaa&bbb&version=1.0&default.ccc=123\");\n        Assertions.assertEquals(\"aaa\", urlParam1.getParameter(\"aaa\"));\n        Assertions.assertEquals(\"bbb\", urlParam1.getParameter(\"bbb\"));\n        Assertions.assertEquals(\"1.0\", urlParam1.getParameter(\"version\"));\n        Assertions.assertEquals(\"123\", urlParam1.getParameter(\"default.ccc\"));\n        Assertions.assertEquals(\"123\", urlParam1.getParameter(\"ccc\"));\n        Assertions.assertEquals(urlParam1, URLParam.parse(urlParam1.getRawParam()));\n        Assertions.assertEquals(urlParam1, URLParam.parse(urlParam1.toString()));\n\n        URLParam urlParam2 = URLParam.parse(\"aaa%3dtest\", true, null);\n        Assertions.assertEquals(\"test\", urlParam2.getParameter(\"aaa\"));\n\n        Map<String, String> overrideMap = Collections.singletonMap(\"aaa\", \"bbb\");\n        URLParam urlParam3 = URLParam.parse(\"aaa%3dtest\", true, overrideMap);\n        Assertions.assertEquals(\"bbb\", urlParam3.getParameter(\"aaa\"));\n\n        URLParam urlParam4 = URLParam.parse(\"ccc=456&&default.ccc=123\");\n        Assertions.assertEquals(\"456\", urlParam4.getParameter(\"ccc\"));\n\n        URLParam urlParam5 = URLParam.parse(\"version=2.0&&default.version=1.0\");\n        Assertions.assertEquals(\"2.0\", urlParam5.getParameter(\"version\"));\n    }\n\n    @Test\n    void testParseWithMap() {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"aaa\", \"aaa\");\n        map.put(\"bbb\", \"bbb\");\n        map.put(\"version\", \"2.0\");\n        map.put(\"side\", \"consumer\");\n\n        URLParam urlParam1 = URLParam.parse(map);\n        Assertions.assertEquals(\"aaa\", urlParam1.getParameter(\"aaa\"));\n        Assertions.assertEquals(\"bbb\", urlParam1.getParameter(\"bbb\"));\n        Assertions.assertEquals(\"2.0\", urlParam1.getParameter(\"version\"));\n        Assertions.assertEquals(\"consumer\", urlParam1.getParameter(\"side\"));\n        Assertions.assertEquals(urlParam1, URLParam.parse(urlParam1.getRawParam()));\n\n        map.put(\"bbb\", \"ccc\");\n\n        Assertions.assertEquals(\"bbb\", urlParam1.getParameter(\"bbb\"));\n\n        URLParam urlParam2 = URLParam.parse(map);\n        Assertions.assertEquals(\"ccc\", urlParam2.getParameter(\"bbb\"));\n\n        URLParam urlParam3 = URLParam.parse(null, null);\n        Assertions.assertFalse(urlParam3.hasParameter(\"aaa\"));\n        Assertions.assertEquals(urlParam3, URLParam.parse(urlParam3.getRawParam()));\n    }\n\n    @Test\n    void testDefault() {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"aaa\", \"aaa\");\n        map.put(\"bbb\", \"bbb\");\n        map.put(\"version\", \"2.0\");\n        map.put(\"timeout\", \"1234\");\n        map.put(\"default.timeout\", \"5678\");\n\n        URLParam urlParam1 = URLParam.parse(map);\n        Assertions.assertEquals(\"1234\", urlParam1.getParameter(\"timeout\"));\n        Assertions.assertEquals(\"5678\", urlParam1.getParameter(\"default.timeout\"));\n\n        map.remove(\"timeout\");\n        URLParam urlParam2 = URLParam.parse(map);\n        Assertions.assertEquals(\"5678\", urlParam2.getParameter(\"timeout\"));\n        Assertions.assertEquals(\"5678\", urlParam2.getParameter(\"default.timeout\"));\n\n        URLParam urlParam3 = URLParam.parse(\"timeout=1234&default.timeout=5678\");\n        Assertions.assertEquals(\"1234\", urlParam3.getParameter(\"timeout\"));\n        Assertions.assertEquals(\"5678\", urlParam3.getParameter(\"default.timeout\"));\n\n        URLParam urlParam4 = URLParam.parse(\"default.timeout=5678\");\n        Assertions.assertEquals(\"5678\", urlParam4.getParameter(\"timeout\"));\n        Assertions.assertEquals(\"5678\", urlParam4.getParameter(\"default.timeout\"));\n    }\n\n    @Test\n    void testGetParameter() {\n        URLParam urlParam1 = URLParam.parse(\"aaa=aaa&bbb&version=1.0&default.ccc=123\");\n        Assertions.assertNull(urlParam1.getParameter(\"abcde\"));\n\n        URLParam urlParam2 = URLParam.parse(\"aaa=aaa&bbb&default.ccc=123\");\n        Assertions.assertNull(urlParam2.getParameter(\"version\"));\n\n        URLParam urlParam3 = URLParam.parse(\"aaa=aaa&side=consumer\");\n        Assertions.assertEquals(\"consumer\", urlParam3.getParameter(\"side\"));\n\n        URLParam urlParam4 = URLParam.parse(\"aaa=aaa&side=provider\");\n        Assertions.assertEquals(\"provider\", urlParam4.getParameter(\"side\"));\n    }\n\n    @Test\n    void testHasParameter() {\n        URLParam urlParam1 = URLParam.parse(\"aaa=aaa&side=provider\");\n        Assertions.assertTrue(urlParam1.hasParameter(\"aaa\"));\n        Assertions.assertFalse(urlParam1.hasParameter(\"bbb\"));\n        Assertions.assertTrue(urlParam1.hasParameter(\"side\"));\n        Assertions.assertFalse(urlParam1.hasParameter(\"version\"));\n    }\n\n    @Test\n    void testRemoveParameters() {\n        URLParam urlParam1 = URLParam.parse(\"aaa=aaa&side=provider&version=1.0\");\n        Assertions.assertTrue(urlParam1.hasParameter(\"aaa\"));\n        Assertions.assertTrue(urlParam1.hasParameter(\"side\"));\n        Assertions.assertTrue(urlParam1.hasParameter(\"version\"));\n\n        URLParam urlParam2 = urlParam1.removeParameters(\"side\");\n        Assertions.assertFalse(urlParam2.hasParameter(\"side\"));\n\n        URLParam urlParam3 = urlParam1.removeParameters(\"aaa\", \"version\");\n        Assertions.assertFalse(urlParam3.hasParameter(\"aaa\"));\n        Assertions.assertFalse(urlParam3.hasParameter(\"version\"));\n\n        URLParam urlParam4 = urlParam1.removeParameters();\n        Assertions.assertTrue(urlParam4.hasParameter(\"aaa\"));\n        Assertions.assertTrue(urlParam4.hasParameter(\"side\"));\n        Assertions.assertTrue(urlParam4.hasParameter(\"version\"));\n\n        URLParam urlParam5 = urlParam1.clearParameters();\n        Assertions.assertFalse(urlParam5.hasParameter(\"aaa\"));\n        Assertions.assertFalse(urlParam5.hasParameter(\"side\"));\n        Assertions.assertFalse(urlParam5.hasParameter(\"version\"));\n\n        URLParam urlParam6 = urlParam1.removeParameters(\"aaa\");\n        Assertions.assertFalse(urlParam6.hasParameter(\"aaa\"));\n\n        URLParam urlParam7 = URLParam.parse(\"side=consumer\").removeParameters(\"side\");\n        Assertions.assertFalse(urlParam7.hasParameter(\"side\"));\n    }\n\n    @Test\n    void testAddParameters() {\n        URLParam urlParam1 = URLParam.parse(\"aaa=aaa&side=provider\");\n        Assertions.assertTrue(urlParam1.hasParameter(\"aaa\"));\n        Assertions.assertTrue(urlParam1.hasParameter(\"side\"));\n\n        URLParam urlParam2 = urlParam1.addParameter(\"bbb\", \"bbb\");\n        Assertions.assertEquals(\"aaa\", urlParam2.getParameter(\"aaa\"));\n        Assertions.assertEquals(\"bbb\", urlParam2.getParameter(\"bbb\"));\n\n        URLParam urlParam3 = urlParam1.addParameter(\"aaa\", \"ccc\");\n        Assertions.assertEquals(\"aaa\", urlParam1.getParameter(\"aaa\"));\n        Assertions.assertEquals(\"ccc\", urlParam3.getParameter(\"aaa\"));\n\n        URLParam urlParam4 = urlParam1.addParameter(\"aaa\", \"aaa\");\n        Assertions.assertEquals(\"aaa\", urlParam4.getParameter(\"aaa\"));\n\n        URLParam urlParam5 = urlParam1.addParameter(\"version\", \"0.1\");\n        Assertions.assertEquals(\"0.1\", urlParam5.getParameter(\"version\"));\n\n        URLParam urlParam6 = urlParam5.addParameterIfAbsent(\"version\", \"0.2\");\n        Assertions.assertEquals(\"0.1\", urlParam6.getParameter(\"version\"));\n\n        URLParam urlParam7 = urlParam1.addParameterIfAbsent(\"version\", \"0.2\");\n        Assertions.assertEquals(\"0.2\", urlParam7.getParameter(\"version\"));\n\n        Map<String, String> map = new HashMap<>();\n        map.put(\"version\", \"1.0\");\n        map.put(\"side\", \"provider\");\n\n        URLParam urlParam8 = urlParam1.addParameters(map);\n        Assertions.assertEquals(\"1.0\", urlParam8.getParameter(\"version\"));\n        Assertions.assertEquals(\"provider\", urlParam8.getParameter(\"side\"));\n\n        map.put(\"side\", \"consumer\");\n\n        Assertions.assertEquals(\"provider\", urlParam8.getParameter(\"side\"));\n\n        URLParam urlParam9 = urlParam8.addParameters(map);\n        Assertions.assertEquals(\"consumer\", urlParam9.getParameter(\"side\"));\n\n        URLParam urlParam10 = urlParam8.addParametersIfAbsent(map);\n        Assertions.assertEquals(\"provider\", urlParam10.getParameter(\"side\"));\n\n        Assertions.assertThrows(IllegalArgumentException.class, () -> urlParam1.addParameter(\"side\", \"unrecognized\"));\n    }\n\n    @Test\n    void testURLParamMap() {\n        URLParam urlParam1 = URLParam.parse(\"\");\n        Assertions.assertTrue(urlParam1.getParameters().isEmpty());\n        Assertions.assertEquals(0, urlParam1.getParameters().size());\n        Assertions.assertFalse(urlParam1.getParameters().containsKey(\"aaa\"));\n        Assertions.assertFalse(urlParam1.getParameters().containsKey(\"version\"));\n        Assertions.assertFalse(urlParam1.getParameters().containsKey(new Object()));\n        Assertions.assertEquals(\n                new HashMap<>(urlParam1.getParameters()).toString(),\n                urlParam1.getParameters().toString());\n\n        URLParam urlParam2 = URLParam.parse(\"aaa=aaa&version=1.0\");\n        URLParam.URLParamMap urlParam2Map = (URLParam.URLParamMap) urlParam2.getParameters();\n        Assertions.assertTrue(urlParam2Map.containsKey(\"version\"));\n        Assertions.assertFalse(urlParam2Map.containsKey(\"side\"));\n\n        Assertions.assertTrue(urlParam2Map.containsValue(\"1.0\"));\n        Assertions.assertFalse(urlParam2Map.containsValue(\"2.0\"));\n\n        Assertions.assertEquals(\"1.0\", urlParam2Map.get(\"version\"));\n        Assertions.assertEquals(\"aaa\", urlParam2Map.get(\"aaa\"));\n        Assertions.assertNull(urlParam2Map.get(new Object()));\n\n        Assertions.assertEquals(urlParam2, urlParam2Map.getUrlParam());\n\n        urlParam2Map.put(\"version\", \"1.0\");\n        Assertions.assertEquals(urlParam2, urlParam2Map.getUrlParam());\n\n        urlParam2Map.putAll(Collections.singletonMap(\"version\", \"1.0\"));\n        Assertions.assertEquals(urlParam2, urlParam2Map.getUrlParam());\n\n        urlParam2Map.put(\"side\", \"consumer\");\n        Assertions.assertNotEquals(urlParam2, urlParam2Map.getUrlParam());\n\n        urlParam2Map = (URLParam.URLParamMap) urlParam2.getParameters();\n        Assertions.assertEquals(urlParam2, urlParam2Map.getUrlParam());\n\n        urlParam2Map.remove(\"version\");\n        Assertions.assertNotEquals(urlParam2, urlParam2Map.getUrlParam());\n        Assertions.assertFalse(urlParam2Map.containsValue(\"version\"));\n        Assertions.assertNull(urlParam2Map.getUrlParam().getParameter(\"version\"));\n\n        urlParam2Map = (URLParam.URLParamMap) urlParam2.getParameters();\n        Assertions.assertEquals(urlParam2, urlParam2Map.getUrlParam());\n\n        urlParam2Map.clear();\n        Assertions.assertTrue(urlParam2Map.isEmpty());\n        Assertions.assertEquals(0, urlParam2Map.size());\n        Assertions.assertNull(urlParam2Map.getUrlParam().getParameter(\"aaa\"));\n        Assertions.assertNull(urlParam2Map.getUrlParam().getParameter(\"version\"));\n\n        urlParam2Map = (URLParam.URLParamMap) urlParam2.getParameters();\n        Assertions.assertEquals(urlParam2, urlParam2Map.getUrlParam());\n\n        URLParam urlParam3 = URLParam.parse(\"aaa=aaa&version=1.0\");\n        Assertions.assertTrue(CollectionUtils.mapEquals(urlParam2Map, urlParam3.getParameters()));\n        Assertions.assertTrue(CollectionUtils.equals(\n                urlParam2Map.entrySet(), urlParam3.getParameters().entrySet()));\n        Assertions.assertTrue(CollectionUtils.equals(\n                urlParam2Map.keySet(), urlParam3.getParameters().keySet()));\n        Assertions.assertTrue(CollectionUtils.equals(\n                urlParam2Map.values(), urlParam3.getParameters().values()));\n\n        URLParam urlParam4 = URLParam.parse(\"aaa=aaa&version=1.0&side=consumer\");\n        Assertions.assertFalse(CollectionUtils.mapEquals(urlParam2Map, urlParam4.getParameters()));\n        Assertions.assertFalse(CollectionUtils.equals(\n                urlParam2Map.entrySet(), urlParam4.getParameters().entrySet()));\n        Assertions.assertFalse(CollectionUtils.equals(\n                urlParam2Map.keySet(), urlParam4.getParameters().keySet()));\n        Assertions.assertFalse(CollectionUtils.equals(\n                urlParam2Map.values(), urlParam4.getParameters().values()));\n\n        Set<Map<String, String>> set = new HashSet<>();\n\n        set.add(urlParam2Map);\n        set.add(urlParam3.getParameters());\n        Assertions.assertEquals(1, set.size());\n\n        set.add(urlParam4.getParameters());\n        Assertions.assertEquals(2, set.size());\n\n        URLParam urlParam5 = URLParam.parse(\"version=1.0\");\n        Assertions.assertEquals(\n                new HashMap<>(urlParam5.getParameters()).toString(),\n                urlParam5.getParameters().toString());\n    }\n\n    @Test\n    void testMethodParameters() {\n        URLParam urlParam1 = URLParam.parse(\"aaa.method1=aaa&bbb.method2=bbb\");\n        Assertions.assertEquals(\"aaa\", urlParam1.getAnyMethodParameter(\"method1\"));\n        Assertions.assertEquals(\"bbb\", urlParam1.getAnyMethodParameter(\"method2\"));\n\n        URLParam urlParam2 = URLParam.parse(\"methods=aaa&aaa.method1=aaa&bbb.method2=bbb\");\n        Assertions.assertEquals(\"aaa\", urlParam2.getAnyMethodParameter(\"method1\"));\n        Assertions.assertNull(urlParam2.getAnyMethodParameter(\"method2\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/AnnotationUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.annotation.Service;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.excludedType;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.findAnnotation;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotation;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotations;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAllDeclaredAnnotations;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAllMetaAnnotations;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAnnotation;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAttribute;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAttributes;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getDeclaredAnnotations;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getDefaultValue;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getMetaAnnotations;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getValue;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.isAnnotationPresent;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.isAnyAnnotationPresent;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.isSameType;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.isType;\nimport static org.apache.dubbo.common.utils.MethodUtils.findMethod;\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link AnnotationUtils} Test\n *\n * @since 2.7.6\n */\nclass AnnotationUtilsTest {\n\n    @Test\n    void testIsType() {\n        // null checking\n        assertFalse(isType(null));\n        // Method checking\n        assertFalse(isType(findMethod(A.class, \"execute\")));\n        // Class checking\n        assertTrue(isType(A.class));\n    }\n\n    @Test\n    void testIsSameType() {\n        assertTrue(isSameType(A.class.getAnnotation(Service.class), Service.class));\n        assertFalse(isSameType(A.class.getAnnotation(Service.class), Deprecated.class));\n        assertFalse(isSameType(A.class.getAnnotation(Service.class), null));\n        assertFalse(isSameType(null, Deprecated.class));\n        assertFalse(isSameType(null, null));\n    }\n\n    @Test\n    void testExcludedType() {\n        assertFalse(excludedType(Service.class).test(A.class.getAnnotation(Service.class)));\n        assertTrue(excludedType(Service.class).test(A.class.getAnnotation(Deprecated.class)));\n    }\n\n    @Test\n    void testGetAttribute() {\n        Annotation annotation = A.class.getAnnotation(Service.class);\n        assertEquals(\"java.lang.CharSequence\", getAttribute(annotation, \"interfaceName\"));\n        assertEquals(CharSequence.class, getAttribute(annotation, \"interfaceClass\"));\n        assertEquals(\"\", getAttribute(annotation, \"version\"));\n        assertEquals(\"\", getAttribute(annotation, \"group\"));\n        assertEquals(\"\", getAttribute(annotation, \"path\"));\n        assertEquals(true, getAttribute(annotation, \"export\"));\n        assertEquals(false, getAttribute(annotation, \"deprecated\"));\n    }\n\n    @Test\n    void testGetAttributesMap() {\n        Annotation annotation = A.class.getAnnotation(Service.class);\n        Map<String, Object> attributes = getAttributes(annotation, false);\n        assertEquals(\"java.lang.CharSequence\", attributes.get(\"interfaceName\"));\n        assertEquals(CharSequence.class, attributes.get(\"interfaceClass\"));\n        assertEquals(\"\", attributes.get(\"group\"));\n        assertEquals(getDefaultValue(annotation, \"export\"), attributes.get(\"export\"));\n\n        Map<String, Object> filteredAttributes = filterDefaultValues(annotation, attributes);\n        assertEquals(2, filteredAttributes.size());\n        assertEquals(\"java.lang.CharSequence\", filteredAttributes.get(\"interfaceName\"));\n        assertEquals(CharSequence.class, filteredAttributes.get(\"interfaceClass\"));\n        assertFalse(filteredAttributes.containsKey(\"group\"));\n        assertFalse(filteredAttributes.containsKey(\"export\"));\n\n        Map<String, Object> nonDefaultAttributes = getAttributes(annotation, true);\n        assertEquals(nonDefaultAttributes, filteredAttributes);\n    }\n\n    @Test\n    void testGetValue() {\n        Adaptive adaptive = A.class.getAnnotation(Adaptive.class);\n        String[] value = getValue(adaptive);\n        assertEquals(asList(\"a\", \"b\", \"c\"), asList(value));\n    }\n\n    @Test\n    void testGetDeclaredAnnotations() {\n        List<Annotation> annotations = getDeclaredAnnotations(A.class);\n        assertADeclaredAnnotations(annotations, 0);\n\n        annotations = getDeclaredAnnotations(A.class, a -> isSameType(a, Service.class));\n        assertEquals(1, annotations.size());\n        Service service = (Service) annotations.get(0);\n        assertEquals(\"java.lang.CharSequence\", service.interfaceName());\n        assertEquals(CharSequence.class, service.interfaceClass());\n    }\n\n    @Test\n    void testGetAllDeclaredAnnotations() {\n        List<Annotation> annotations = getAllDeclaredAnnotations(A.class);\n        assertADeclaredAnnotations(annotations, 0);\n\n        annotations = getAllDeclaredAnnotations(B.class);\n        assertTrue(isSameType(annotations.get(0), Service5.class));\n        assertADeclaredAnnotations(annotations, 1);\n\n        annotations = new LinkedList<>(getAllDeclaredAnnotations(C.class));\n        assertTrue(isSameType(annotations.get(0), MyAdaptive.class));\n        assertTrue(isSameType(annotations.get(1), Service5.class));\n        assertADeclaredAnnotations(annotations, 2);\n\n        annotations = getAllDeclaredAnnotations(findMethod(A.class, \"execute\"));\n        MyAdaptive myAdaptive = (MyAdaptive) annotations.get(0);\n        assertArrayEquals(new String[] {\"e\"}, myAdaptive.value());\n\n        annotations = getAllDeclaredAnnotations(findMethod(B.class, \"execute\"));\n        Adaptive adaptive = (Adaptive) annotations.get(0);\n        assertArrayEquals(new String[] {\"f\"}, adaptive.value());\n    }\n\n    @Test\n    void testGetMetaAnnotations() {\n        List<Annotation> metaAnnotations = getMetaAnnotations(Service.class, a -> isSameType(a, Inherited.class));\n        assertEquals(1, metaAnnotations.size());\n        assertEquals(Inherited.class, metaAnnotations.get(0).annotationType());\n\n        metaAnnotations = getMetaAnnotations(Service.class);\n        HashSet<Object> set1 = new HashSet<>();\n        metaAnnotations.forEach(t -> set1.add(t.annotationType()));\n        HashSet<Object> set2 = new HashSet<>();\n        set2.add(Inherited.class);\n        set2.add(Deprecated.class);\n        assertEquals(2, metaAnnotations.size());\n        assertEquals(set1, set2);\n    }\n\n    @Test\n    void testGetAllMetaAnnotations() {\n        List<Annotation> metaAnnotations = getAllMetaAnnotations(Service5.class);\n        int offset = 0;\n\n        HashSet<Object> set1 = new HashSet<>();\n        metaAnnotations.forEach(t -> set1.add(t.annotationType()));\n        HashSet<Object> set2 = new HashSet<>();\n        set2.add(Inherited.class);\n        set2.add(DubboService.class);\n        set2.add(Service4.class);\n        set2.add(Service3.class);\n        set2.add(Service2.class);\n        assertEquals(9, metaAnnotations.size());\n        assertEquals(set1, set2);\n\n        metaAnnotations = getAllMetaAnnotations(MyAdaptive.class);\n        HashSet<Object> set3 = new HashSet<>();\n        metaAnnotations.forEach(t -> set3.add(t.annotationType()));\n        HashSet<Object> set4 = new HashSet<>();\n        metaAnnotations.forEach(t -> set3.add(t.annotationType()));\n        set4.add(Inherited.class);\n        set4.add(Adaptive.class);\n        assertEquals(2, metaAnnotations.size());\n        assertEquals(set3, set4);\n    }\n\n    @Test\n    void testIsAnnotationPresent() {\n        assertTrue(isAnnotationPresent(A.class, true, Service.class));\n        //        assertTrue(isAnnotationPresent(A.class, true, Service.class,\n        // com.alibaba.dubbo.config.annotation.Service.class));\n        assertTrue(isAnnotationPresent(A.class, Service.class));\n        assertTrue(isAnnotationPresent(A.class, \"org.apache.dubbo.config.annotation.Service\"));\n        //        assertTrue(AnnotationUtils.isAllAnnotationPresent(A.class, Service.class, Service.class,\n        // com.alibaba.dubbo.config.annotation.Service.class));\n        assertTrue(AnnotationUtils.isAllAnnotationPresent(A.class, Service.class, Service.class));\n        assertTrue(isAnnotationPresent(A.class, Deprecated.class));\n    }\n\n    @Test\n    void testIsAnyAnnotationPresent() {\n        //        assertTrue(isAnyAnnotationPresent(A.class, Service.class,\n        // com.alibaba.dubbo.config.annotation.Service.class, Deprecated.class));\n        //        assertTrue(isAnyAnnotationPresent(A.class, Service.class,\n        // com.alibaba.dubbo.config.annotation.Service.class));\n        assertTrue(isAnyAnnotationPresent(A.class, Service.class, Deprecated.class));\n        //        assertTrue(isAnyAnnotationPresent(A.class, com.alibaba.dubbo.config.annotation.Service.class,\n        // Deprecated.class));\n        assertTrue(isAnyAnnotationPresent(A.class, Deprecated.class));\n        assertTrue(isAnyAnnotationPresent(A.class, Service.class));\n        //        assertTrue(isAnyAnnotationPresent(A.class, com.alibaba.dubbo.config.annotation.Service.class));\n        assertTrue(isAnyAnnotationPresent(A.class, Deprecated.class));\n    }\n\n    @Test\n    void testGetAnnotation() {\n        assertNotNull(getAnnotation(A.class, \"org.apache.dubbo.config.annotation.Service\"));\n        //        assertNotNull(getAnnotation(A.class, \"com.alibaba.dubbo.config.annotation.Service\"));\n        assertNotNull(getAnnotation(A.class, \"org.apache.dubbo.common.extension.Adaptive\"));\n        assertNull(getAnnotation(A.class, \"java.lang.Deprecated\"));\n        assertNull(getAnnotation(A.class, \"java.lang.String\"));\n        assertNull(getAnnotation(A.class, \"NotExistedClass\"));\n    }\n\n    @Test\n    void testFindAnnotation() {\n        Service service = findAnnotation(A.class, Service.class);\n        assertEquals(\"java.lang.CharSequence\", service.interfaceName());\n        assertEquals(CharSequence.class, service.interfaceClass());\n\n        service = findAnnotation(B.class, Service.class);\n        assertEquals(CharSequence.class, service.interfaceClass());\n    }\n\n    @Test\n    void testFindMetaAnnotations() {\n        List<DubboService> services = findMetaAnnotations(B.class, DubboService.class);\n        assertEquals(1, services.size());\n\n        DubboService service = services.get(0);\n        assertEquals(\"\", service.interfaceName());\n        assertEquals(Cloneable.class, service.interfaceClass());\n\n        services = findMetaAnnotations(Service5.class, DubboService.class);\n        assertEquals(1, services.size());\n\n        service = services.get(0);\n        assertEquals(\"\", service.interfaceName());\n        assertEquals(Cloneable.class, service.interfaceClass());\n    }\n\n    @Test\n    void testFindMetaAnnotation() {\n        DubboService service = findMetaAnnotation(B.class, DubboService.class);\n        assertEquals(Cloneable.class, service.interfaceClass());\n\n        service = findMetaAnnotation(B.class, \"org.apache.dubbo.config.annotation.DubboService\");\n        assertEquals(Cloneable.class, service.interfaceClass());\n\n        service = findMetaAnnotation(Service5.class, DubboService.class);\n        assertEquals(Cloneable.class, service.interfaceClass());\n    }\n\n    @Service(interfaceName = \"java.lang.CharSequence\", interfaceClass = CharSequence.class)\n    @Adaptive(value = {\"a\", \"b\", \"c\"})\n    static class A {\n\n        @MyAdaptive(\"e\")\n        public void execute() {}\n    }\n\n    @Documented\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.TYPE})\n    @Inherited\n    @DubboService(interfaceClass = Cloneable.class)\n    @interface Service2 {}\n\n    @Documented\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.TYPE})\n    @Inherited\n    @Service2\n    @interface Service3 {}\n\n    @Documented\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.TYPE})\n    @Inherited\n    @Service3\n    @interface Service4 {}\n\n    @Documented\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.TYPE})\n    @Inherited\n    @Service4\n    @interface Service5 {}\n\n    @Documented\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.TYPE, ElementType.METHOD})\n    @Inherited\n    @Adaptive\n    @interface MyAdaptive {\n\n        String[] value() default {};\n    }\n\n    @Service5\n    static class B extends A {\n\n        @Adaptive(\"f\")\n        @Override\n        public void execute() {}\n    }\n\n    @MyAdaptive\n    static class C extends B {}\n\n    private void assertADeclaredAnnotations(List<Annotation> annotations, int offset) {\n        int size = 2 + offset;\n        assertEquals(size, annotations.size());\n        boolean apacheServiceFound = false;\n        boolean adaptiveFound = false;\n\n        for (Annotation annotation : annotations) {\n            if (!apacheServiceFound && (annotation instanceof Service)) {\n                assertEquals(\"java.lang.CharSequence\", ((Service) annotation).interfaceName());\n                assertEquals(CharSequence.class, ((Service) annotation).interfaceClass());\n                apacheServiceFound = true;\n                continue;\n            }\n            if (!adaptiveFound && (annotation instanceof Adaptive)) {\n                assertArrayEquals(new String[] {\"a\", \"b\", \"c\"}, ((Adaptive) annotation).value());\n                adaptiveFound = true;\n                continue;\n            }\n        }\n        assertTrue(apacheServiceFound && adaptiveFound);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/ArrayUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ArrayUtilsTest {\n\n    @Test\n    void isEmpty() {\n        assertTrue(ArrayUtils.isEmpty(null));\n        assertTrue(ArrayUtils.isEmpty(new Object[0]));\n        assertFalse(ArrayUtils.isEmpty(new Object[] {\"abc\"}));\n    }\n\n    @Test\n    void isNotEmpty() {\n        assertFalse(ArrayUtils.isNotEmpty(null));\n        assertFalse(ArrayUtils.isNotEmpty(new Object[0]));\n        assertTrue(ArrayUtils.isNotEmpty(new Object[] {\"abc\"}));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/AssertTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.utils.Assert.notEmptyString;\nimport static org.apache.dubbo.common.utils.Assert.notNull;\n\nclass AssertTest {\n    @Test\n    void testNotNull1() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> notNull(null, \"null object\"));\n    }\n\n    @Test\n    void testNotNull2() {\n        Assertions.assertThrows(\n                IllegalStateException.class, () -> notNull(null, new IllegalStateException(\"null object\")));\n    }\n\n    @Test\n    void testNotNullWhenInputNotNull1() {\n        notNull(new Object(), \"null object\");\n    }\n\n    @Test\n    void testNotNullWhenInputNotNull2() {\n        notNull(new Object(), new IllegalStateException(\"null object\"));\n    }\n\n    @Test\n    void testNotNullString() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> notEmptyString(null, \"Message can't be null\"));\n    }\n\n    @Test\n    void testNotEmptyString() {\n        Assertions.assertThrows(\n                IllegalArgumentException.class, () -> notEmptyString(\"\", \"Message can't be null or empty\"));\n    }\n\n    @Test\n    void testNotNullNotEmptyString() {\n        notEmptyString(\"abcd\", \"Message can'be null or empty\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/AtomicPositiveIntegerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.allOf;\nimport static org.hamcrest.CoreMatchers.containsString;\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass AtomicPositiveIntegerTest {\n    private AtomicPositiveInteger i1 = new AtomicPositiveInteger();\n\n    private AtomicPositiveInteger i2 = new AtomicPositiveInteger(127);\n\n    private AtomicPositiveInteger i3 = new AtomicPositiveInteger(Integer.MAX_VALUE);\n\n    @Test\n    void testGet() {\n        assertEquals(0, i1.get());\n        assertEquals(127, i2.get());\n        assertEquals(Integer.MAX_VALUE, i3.get());\n    }\n\n    @Test\n    void testSet() {\n        i1.set(100);\n        assertEquals(100, i1.get());\n\n        try {\n            i1.set(-1);\n            fail();\n        } catch (IllegalArgumentException expected) {\n            assertThat(expected.getMessage(), allOf(containsString(\"new value\"), containsString(\"< 0\")));\n        }\n    }\n\n    @Test\n    void testGetAndIncrement() {\n        int get = i1.getAndIncrement();\n        assertEquals(0, get);\n        assertEquals(1, i1.get());\n\n        get = i2.getAndIncrement();\n        assertEquals(127, get);\n        assertEquals(128, i2.get());\n\n        get = i3.getAndIncrement();\n        assertEquals(Integer.MAX_VALUE, get);\n        assertEquals(0, i3.get());\n    }\n\n    @Test\n    void testGetAndDecrement() {\n        int get = i1.getAndDecrement();\n        assertEquals(0, get);\n        assertEquals(Integer.MAX_VALUE, i1.get());\n\n        get = i2.getAndDecrement();\n        assertEquals(127, get);\n        assertEquals(126, i2.get());\n\n        get = i3.getAndDecrement();\n        assertEquals(Integer.MAX_VALUE, get);\n        assertEquals(Integer.MAX_VALUE - 1, i3.get());\n    }\n\n    @Test\n    void testIncrementAndGet() {\n        int get = i1.incrementAndGet();\n        assertEquals(1, get);\n        assertEquals(1, i1.get());\n\n        get = i2.incrementAndGet();\n        assertEquals(128, get);\n        assertEquals(128, i2.get());\n\n        get = i3.incrementAndGet();\n        assertEquals(0, get);\n        assertEquals(0, i3.get());\n    }\n\n    @Test\n    void testDecrementAndGet() {\n        int get = i1.decrementAndGet();\n        assertEquals(Integer.MAX_VALUE, get);\n        assertEquals(Integer.MAX_VALUE, i1.get());\n\n        get = i2.decrementAndGet();\n        assertEquals(126, get);\n        assertEquals(126, i2.get());\n\n        get = i3.decrementAndGet();\n        assertEquals(Integer.MAX_VALUE - 1, get);\n        assertEquals(Integer.MAX_VALUE - 1, i3.get());\n    }\n\n    @Test\n    void testGetAndSet() {\n        int get = i1.getAndSet(100);\n        assertEquals(0, get);\n        assertEquals(100, i1.get());\n\n        try {\n            i1.getAndSet(-1);\n        } catch (IllegalArgumentException expected) {\n            assertThat(expected.getMessage(), allOf(containsString(\"new value\"), containsString(\"< 0\")));\n        }\n    }\n\n    @Test\n    void testGetAndAnd() {\n        int get = i1.getAndAdd(3);\n        assertEquals(0, get);\n        assertEquals(3, i1.get());\n\n        get = i2.getAndAdd(3);\n        assertEquals(127, get);\n        assertEquals(127 + 3, i2.get());\n\n        get = i3.getAndAdd(3);\n        assertEquals(Integer.MAX_VALUE, get);\n        assertEquals(2, i3.get());\n    }\n\n    @Test\n    void testAddAndGet() {\n        int get = i1.addAndGet(3);\n        assertEquals(3, get);\n        assertEquals(3, i1.get());\n\n        get = i2.addAndGet(3);\n        assertEquals(127 + 3, get);\n        assertEquals(127 + 3, i2.get());\n\n        get = i3.addAndGet(3);\n        assertEquals(2, get);\n        assertEquals(2, i3.get());\n    }\n\n    @Test\n    void testCompareAndSet1() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            i1.compareAndSet(i1.get(), -1);\n        });\n    }\n\n    @Test\n    void testCompareAndSet2() {\n        assertThat(i1.compareAndSet(i1.get(), 2), is(true));\n        assertThat(i1.get(), is(2));\n    }\n\n    @Test\n    void testWeakCompareAndSet1() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            i1.weakCompareAndSet(i1.get(), -1);\n        });\n    }\n\n    @Test\n    void testWeakCompareAndSet2() {\n        assertThat(i1.weakCompareAndSet(i1.get(), 2), is(true));\n        assertThat(i1.get(), is(2));\n    }\n\n    @Test\n    void testValues() {\n        Integer i = i1.get();\n        assertThat(i1.byteValue(), equalTo(i.byteValue()));\n        assertThat(i1.shortValue(), equalTo(i.shortValue()));\n        assertThat(i1.intValue(), equalTo(i.intValue()));\n        assertThat(i1.longValue(), equalTo(i.longValue()));\n        assertThat(i1.floatValue(), equalTo(i.floatValue()));\n        assertThat(i1.doubleValue(), equalTo(i.doubleValue()));\n        assertThat(i1.toString(), equalTo(i.toString()));\n    }\n\n    @Test\n    void testEquals() {\n        assertEquals(new AtomicPositiveInteger(), new AtomicPositiveInteger());\n        assertEquals(new AtomicPositiveInteger(1), new AtomicPositiveInteger(1));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/CIDRUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.net.UnknownHostException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass CIDRUtilsTest {\n\n    @Test\n    void testIpv4() throws UnknownHostException {\n        CIDRUtils cidrUtils = new CIDRUtils(\"192.168.1.0/26\");\n        Assertions.assertTrue(cidrUtils.isInRange(\"192.168.1.63\"));\n        Assertions.assertFalse(cidrUtils.isInRange(\"192.168.1.65\"));\n\n        cidrUtils = new CIDRUtils(\"192.168.1.192/26\");\n        Assertions.assertTrue(cidrUtils.isInRange(\"192.168.1.199\"));\n        Assertions.assertFalse(cidrUtils.isInRange(\"192.168.1.190\"));\n    }\n\n    @Test\n    void testIpv6() throws UnknownHostException {\n        CIDRUtils cidrUtils = new CIDRUtils(\"234e:0:4567::3d/64\");\n        Assertions.assertTrue(cidrUtils.isInRange(\"234e:0:4567::3e\"));\n        Assertions.assertTrue(cidrUtils.isInRange(\"234e:0:4567::ffff:3e\"));\n        Assertions.assertFalse(cidrUtils.isInRange(\"234e:1:4567::3d\"));\n        Assertions.assertFalse(cidrUtils.isInRange(\"234e:0:4567:1::3d\"));\n\n        cidrUtils = new CIDRUtils(\"3FFE:FFFF:0:CC00::/54\");\n        Assertions.assertTrue(cidrUtils.isInRange(\"3FFE:FFFF:0:CC00::dd\"));\n        Assertions.assertTrue(cidrUtils.isInRange(\"3FFE:FFFF:0:CC00:0000:eeee:0909:dd\"));\n        Assertions.assertTrue(cidrUtils.isInRange(\"3FFE:FFFF:0:CC0F:0000:eeee:0909:dd\"));\n\n        Assertions.assertFalse(cidrUtils.isInRange(\"3EFE:FFFE:0:C107::dd\"));\n        Assertions.assertFalse(cidrUtils.isInRange(\"1FFE:FFFE:0:CC00::dd\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/ClassLoaderResourceLoaderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.extension.DubboInternalLoadingStrategy;\nimport org.apache.dubbo.common.extension.director.FooAppProvider;\nimport org.apache.dubbo.common.resource.GlobalResourcesRepository;\n\nimport java.net.URL;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link ClassLoaderResourceLoader}\n */\nclass ClassLoaderResourceLoaderTest {\n\n    @Test\n    void test() throws InterruptedException {\n        DubboInternalLoadingStrategy dubboInternalLoadingStrategy = new DubboInternalLoadingStrategy();\n        String directory = dubboInternalLoadingStrategy.directory();\n        String type = FooAppProvider.class.getName();\n        String fileName = directory + type;\n\n        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();\n        Map<ClassLoader, Set<URL>> loadResources =\n                ClassLoaderResourceLoader.loadResources(fileName, Arrays.asList(contextClassLoader));\n        Assertions.assertTrue(loadResources.containsKey(contextClassLoader));\n        Assertions.assertTrue(!loadResources.get(contextClassLoader).isEmpty());\n\n        // cache\n        Assertions.assertNotNull(ClassLoaderResourceLoader.getClassLoaderResourcesCache());\n        loadResources = ClassLoaderResourceLoader.loadResources(fileName, Arrays.asList(contextClassLoader));\n        Assertions.assertTrue(loadResources.containsKey(contextClassLoader));\n        Assertions.assertTrue(!loadResources.get(contextClassLoader).isEmpty());\n\n        Assertions.assertNotNull(GlobalResourcesRepository.getGlobalReusedDisposables());\n\n        ClassLoaderResourceLoader.destroy();\n        Assertions.assertNull(ClassLoaderResourceLoader.getClassLoaderResourcesCache());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/ClassUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.sameInstance;\nimport static org.hamcrest.Matchers.startsWith;\nimport static org.mockito.Mockito.verify;\n\nclass ClassUtilsTest {\n    @Test\n    void testForNameWithThreadContextClassLoader() throws Exception {\n        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();\n        try {\n            ClassLoader classLoader = Mockito.mock(ClassLoader.class);\n            Thread.currentThread().setContextClassLoader(classLoader);\n            ClassUtils.forNameWithThreadContextClassLoader(\"a.b.c.D\");\n            verify(classLoader).loadClass(\"a.b.c.D\");\n        } finally {\n            Thread.currentThread().setContextClassLoader(oldClassLoader);\n        }\n    }\n\n    @Test\n    void tetForNameWithCallerClassLoader() throws Exception {\n        Class c = ClassUtils.forNameWithCallerClassLoader(ClassUtils.class.getName(), ClassUtilsTest.class);\n        assertThat(c == ClassUtils.class, is(true));\n    }\n\n    @Test\n    void testGetCallerClassLoader() {\n        assertThat(\n                ClassUtils.getCallerClassLoader(ClassUtilsTest.class),\n                sameInstance(ClassUtilsTest.class.getClassLoader()));\n    }\n\n    @Test\n    void testGetClassLoader1() {\n        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();\n        try {\n            assertThat(ClassUtils.getClassLoader(ClassUtilsTest.class), sameInstance(oldClassLoader));\n            Thread.currentThread().setContextClassLoader(null);\n            assertThat(\n                    ClassUtils.getClassLoader(ClassUtilsTest.class),\n                    sameInstance(ClassUtilsTest.class.getClassLoader()));\n        } finally {\n            Thread.currentThread().setContextClassLoader(oldClassLoader);\n        }\n    }\n\n    @Test\n    void testGetClassLoader2() {\n        assertThat(ClassUtils.getClassLoader(), sameInstance(ClassUtils.class.getClassLoader()));\n    }\n\n    @Test\n    void testForName1() throws Exception {\n        assertThat(ClassUtils.forName(ClassUtilsTest.class.getName()) == ClassUtilsTest.class, is(true));\n    }\n\n    @Test\n    void testForName2() throws Exception {\n        assertThat(ClassUtils.forName(\"byte\") == byte.class, is(true));\n        assertThat(ClassUtils.forName(\"java.lang.String[]\") == String[].class, is(true));\n        assertThat(ClassUtils.forName(\"[Ljava.lang.String;\") == String[].class, is(true));\n    }\n\n    @Test\n    void testForName3() throws Exception {\n        ClassLoader classLoader = Mockito.mock(ClassLoader.class);\n        ClassUtils.forName(\"a.b.c.D\", classLoader);\n        verify(classLoader).loadClass(\"a.b.c.D\");\n    }\n\n    @Test\n    void testResolvePrimitiveClassName() {\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"boolean\") == boolean.class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"byte\") == byte.class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"char\") == char.class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"double\") == double.class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"float\") == float.class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"int\") == int.class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"long\") == long.class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"short\") == short.class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"[Z\") == boolean[].class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"[B\") == byte[].class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"[C\") == char[].class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"[D\") == double[].class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"[F\") == float[].class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"[I\") == int[].class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"[J\") == long[].class, is(true));\n        assertThat(ClassUtils.resolvePrimitiveClassName(\"[S\") == short[].class, is(true));\n    }\n\n    @Test\n    void testToShortString() {\n        assertThat(ClassUtils.toShortString(null), equalTo(\"null\"));\n        assertThat(ClassUtils.toShortString(new ClassUtilsTest()), startsWith(\"ClassUtilsTest@\"));\n    }\n\n    @Test\n    void testConvertPrimitive() {\n\n        assertThat(ClassUtils.convertPrimitive(char.class, \"\"), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(char.class, null), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(char.class, \"6\"), equalTo(Character.valueOf('6')));\n\n        assertThat(ClassUtils.convertPrimitive(boolean.class, \"\"), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(boolean.class, null), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(boolean.class, \"true\"), equalTo(Boolean.TRUE));\n\n        assertThat(ClassUtils.convertPrimitive(byte.class, \"\"), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(byte.class, null), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(byte.class, \"127\"), equalTo(Byte.MAX_VALUE));\n\n        assertThat(ClassUtils.convertPrimitive(short.class, \"\"), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(short.class, null), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(short.class, \"32767\"), equalTo(Short.MAX_VALUE));\n\n        assertThat(ClassUtils.convertPrimitive(int.class, \"\"), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(int.class, null), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(int.class, \"6\"), equalTo(6));\n\n        assertThat(ClassUtils.convertPrimitive(long.class, \"\"), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(long.class, null), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(long.class, \"6\"), equalTo(Long.valueOf(6)));\n\n        assertThat(ClassUtils.convertPrimitive(float.class, \"\"), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(float.class, null), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(float.class, \"1.1\"), equalTo(Float.valueOf(1.1F)));\n\n        assertThat(ClassUtils.convertPrimitive(double.class, \"\"), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(double.class, null), equalTo(null));\n        assertThat(ClassUtils.convertPrimitive(double.class, \"10.1\"), equalTo(Double.valueOf(10.1)));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/CollectionUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.config.ProtocolConfig;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Collections.emptyList;\nimport static java.util.Collections.emptySet;\nimport static java.util.Collections.singleton;\nimport static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;\nimport static org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty;\nimport static org.apache.dubbo.common.utils.CollectionUtils.ofSet;\nimport static org.apache.dubbo.common.utils.CollectionUtils.toMap;\nimport static org.apache.dubbo.common.utils.CollectionUtils.toStringMap;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass CollectionUtilsTest {\n    @Test\n    void testSort() {\n        List<Integer> list = new ArrayList<Integer>();\n        list.add(100);\n        list.add(10);\n        list.add(20);\n\n        List<Integer> expected = new ArrayList<Integer>();\n        expected.add(10);\n        expected.add(20);\n        expected.add(100);\n\n        assertEquals(expected, CollectionUtils.sort(list));\n    }\n\n    @Test\n    void testSortNull() {\n        assertNull(CollectionUtils.sort(null));\n\n        assertTrue(CollectionUtils.sort(new ArrayList<Integer>()).isEmpty());\n    }\n\n    @Test\n    void testSortSimpleName() {\n        List<String> list = new ArrayList<String>();\n        list.add(\"aaa.z\");\n        list.add(\"b\");\n        list.add(null);\n        list.add(\"zzz.a\");\n        list.add(\"c\");\n        list.add(null);\n\n        List<String> sorted = CollectionUtils.sortSimpleName(list);\n        assertNull(sorted.get(0));\n        assertNull(sorted.get(1));\n    }\n\n    @Test\n    void testSortSimpleNameNull() {\n        assertNull(CollectionUtils.sortSimpleName(null));\n\n        assertTrue(CollectionUtils.sortSimpleName(new ArrayList<String>()).isEmpty());\n    }\n\n    @Test\n    void testFlip() {\n        assertEquals(CollectionUtils.flip(null), null);\n        Map<String, String> input1 = new HashMap<>();\n        input1.put(\"k1\", null);\n        input1.put(\"k2\", \"v2\");\n        Map<String, String> output1 = new HashMap<>();\n        output1.put(null, \"k1\");\n        output1.put(\"v2\", \"k2\");\n        assertEquals(CollectionUtils.flip(input1), output1);\n        Map<String, String> input2 = new HashMap<>();\n        input2.put(\"k1\", null);\n        input2.put(\"k2\", null);\n        assertThrows(IllegalArgumentException.class, () -> CollectionUtils.flip(input2));\n    }\n\n    @Test\n    void testSplitAll() {\n        assertNull(CollectionUtils.splitAll(null, null));\n        assertNull(CollectionUtils.splitAll(null, \"-\"));\n\n        assertTrue(CollectionUtils.splitAll(new HashMap<String, List<String>>(), \"-\")\n                .isEmpty());\n\n        Map<String, List<String>> input = new HashMap<String, List<String>>();\n        input.put(\"key1\", Arrays.asList(\"1:a\", \"2:b\", \"3:c\"));\n        input.put(\"key2\", Arrays.asList(\"1:a\", \"2:b\"));\n        input.put(\"key3\", null);\n        input.put(\"key4\", new ArrayList<String>());\n\n        Map<String, Map<String, String>> expected = new HashMap<String, Map<String, String>>();\n        expected.put(\"key1\", CollectionUtils.toStringMap(\"1\", \"a\", \"2\", \"b\", \"3\", \"c\"));\n        expected.put(\"key2\", CollectionUtils.toStringMap(\"1\", \"a\", \"2\", \"b\"));\n        expected.put(\"key3\", null);\n        expected.put(\"key4\", new HashMap<String, String>());\n\n        assertEquals(expected, CollectionUtils.splitAll(input, \":\"));\n    }\n\n    @Test\n    void testJoinAll() {\n        assertNull(CollectionUtils.joinAll(null, null));\n        assertNull(CollectionUtils.joinAll(null, \"-\"));\n\n        Map<String, List<String>> expected = new HashMap<String, List<String>>();\n        expected.put(\"key1\", Arrays.asList(\"1:a\", \"2:b\", \"3:c\"));\n        expected.put(\"key2\", Arrays.asList(\"1:a\", \"2:b\"));\n        expected.put(\"key3\", null);\n        expected.put(\"key4\", new ArrayList<String>());\n\n        Map<String, Map<String, String>> input = new HashMap<String, Map<String, String>>();\n        input.put(\"key1\", CollectionUtils.toStringMap(\"1\", \"a\", \"2\", \"b\", \"3\", \"c\"));\n        input.put(\"key2\", CollectionUtils.toStringMap(\"1\", \"a\", \"2\", \"b\"));\n        input.put(\"key3\", null);\n        input.put(\"key4\", new HashMap<String, String>());\n\n        Map<String, List<String>> output = CollectionUtils.joinAll(input, \":\");\n        for (Map.Entry<String, List<String>> entry : output.entrySet()) {\n            if (entry.getValue() == null) continue;\n            Collections.sort(entry.getValue());\n        }\n\n        assertEquals(expected, output);\n    }\n\n    @Test\n    void testJoinList() {\n        List<String> list = emptyList();\n        assertEquals(\"\", CollectionUtils.join(list, \"/\"));\n\n        list = Arrays.asList(\"x\");\n        assertEquals(\"x\", CollectionUtils.join(list, \"-\"));\n\n        list = Arrays.asList(\"a\", \"b\");\n        assertEquals(\"a/b\", CollectionUtils.join(list, \"/\"));\n    }\n\n    @Test\n    void testMapEquals() {\n        assertTrue(CollectionUtils.mapEquals(null, null));\n        assertFalse(CollectionUtils.mapEquals(null, new HashMap<String, String>()));\n        assertFalse(CollectionUtils.mapEquals(new HashMap<String, String>(), null));\n\n        assertTrue(CollectionUtils.mapEquals(\n                CollectionUtils.toStringMap(\"1\", \"a\", \"2\", \"b\"), CollectionUtils.toStringMap(\"1\", \"a\", \"2\", \"b\")));\n        assertFalse(CollectionUtils.mapEquals(\n                CollectionUtils.toStringMap(\"1\", \"a\"), CollectionUtils.toStringMap(\"1\", \"a\", \"2\", \"b\")));\n    }\n\n    @Test\n    void testStringMap1() {\n        assertThat(toStringMap(\"key\", \"value\"), equalTo(Collections.singletonMap(\"key\", \"value\")));\n    }\n\n    @Test\n    void testStringMap2() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> toStringMap(\"key\", \"value\", \"odd\"));\n    }\n\n    @Test\n    void testToMap1() {\n        assertTrue(CollectionUtils.toMap().isEmpty());\n\n        Map<String, Integer> expected = new HashMap<String, Integer>();\n        expected.put(\"a\", 1);\n        expected.put(\"b\", 2);\n        expected.put(\"c\", 3);\n\n        assertEquals(expected, CollectionUtils.toMap(\"a\", 1, \"b\", 2, \"c\", 3));\n    }\n\n    @Test\n    void testObjectToMap() throws Exception {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        protocolConfig.setSerialization(\"fastjson2\");\n\n        assertFalse(CollectionUtils.objToMap(protocolConfig).isEmpty());\n    }\n\n    @Test\n    void testToMap2() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> toMap(\"a\", \"b\", \"c\"));\n    }\n\n    @Test\n    void testIsEmpty() {\n        assertThat(isEmpty(null), is(true));\n        assertThat(isEmpty(new HashSet()), is(true));\n        assertThat(isEmpty(emptyList()), is(true));\n    }\n\n    @Test\n    void testIsNotEmpty() {\n        assertThat(isNotEmpty(singleton(\"a\")), is(true));\n    }\n\n    @Test\n    void testOfSet() {\n        Set<String> set = ofSet();\n        assertEquals(emptySet(), set);\n\n        set = ofSet(((String[]) null));\n        assertEquals(emptySet(), set);\n\n        set = ofSet(\"A\", \"B\", \"C\");\n        Set<String> expectedSet = new LinkedHashSet<>();\n        expectedSet.add(\"A\");\n        expectedSet.add(\"B\");\n        expectedSet.add(\"C\");\n        assertEquals(expectedSet, set);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/CompatibleTypeUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.text.SimpleDateFormat;\nimport java.time.format.DateTimeFormatter;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass CompatibleTypeUtilsTest {\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void testCompatibleTypeConvert() throws Exception {\n        Object result;\n\n        {\n            Object input = new Object();\n            result = CompatibleTypeUtils.compatibleTypeConvert(input, Date.class);\n            assertSame(input, result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(input, null);\n            assertSame(input, result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(null, Date.class);\n            assertNull(result);\n        }\n\n        {\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"a\", char.class);\n            assertEquals(Character.valueOf('a'), (Character) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"A\", MyEnum.class);\n            assertEquals(MyEnum.A, (MyEnum) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"3\", BigInteger.class);\n            assertEquals(new BigInteger(\"3\"), (BigInteger) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"3\", BigDecimal.class);\n            assertEquals(new BigDecimal(\"3\"), (BigDecimal) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"2011-12-11 12:24:12\", Date.class);\n            assertEquals(new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\").parse(\"2011-12-11 12:24:12\"), (Date) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"2011-12-11 12:24:12\", java.sql.Date.class);\n            assertEquals(new SimpleDateFormat(\"yyyy-MM-dd\").format((java.sql.Date) result), \"2011-12-11\");\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"2011-12-11 12:24:12\", java.sql.Time.class);\n            assertEquals(new SimpleDateFormat(\"HH:mm:ss\").format((java.sql.Time) result), \"12:24:12\");\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"2011-12-11 12:24:12\", java.sql.Timestamp.class);\n            assertEquals(\n                    new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\").format((java.sql.Timestamp) result),\n                    \"2011-12-11 12:24:12\");\n\n            result =\n                    CompatibleTypeUtils.compatibleTypeConvert(\"2011-12-11T12:24:12.047\", java.time.LocalDateTime.class);\n            assertEquals(\n                    DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\").format((java.time.LocalDateTime) result),\n                    \"2011-12-11 12:24:12\");\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"2011-12-11T12:24:12.047\", java.time.LocalTime.class);\n            assertEquals(DateTimeFormatter.ofPattern(\"HH:mm:ss\").format((java.time.LocalTime) result), \"12:24:12\");\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"2011-12-11\", java.time.LocalDate.class);\n            assertEquals(DateTimeFormatter.ofPattern(\"yyyy-MM-dd\").format((java.time.LocalDate) result), \"2011-12-11\");\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"ab\", char[].class);\n            assertEquals(2, ((char[]) result).length);\n            assertEquals('a', ((char[]) result)[0]);\n            assertEquals('b', ((char[]) result)[1]);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(\"\", char[].class);\n            assertEquals(0, ((char[]) result).length);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(null, char[].class);\n            assertNull(result);\n        }\n\n        {\n            result = CompatibleTypeUtils.compatibleTypeConvert(3, byte.class);\n            assertEquals(Byte.valueOf((byte) 3), (Byte) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert((byte) 3, int.class);\n            assertEquals(Integer.valueOf(3), (Integer) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(3, short.class);\n            assertEquals(Short.valueOf((short) 3), (Short) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert((short) 3, int.class);\n            assertEquals(Integer.valueOf(3), (Integer) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(3, int.class);\n            assertEquals(Integer.valueOf(3), (Integer) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(3, long.class);\n            assertEquals(Long.valueOf(3), (Long) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(3L, int.class);\n            assertEquals(Integer.valueOf(3), (Integer) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(3L, BigInteger.class);\n            assertEquals(BigInteger.valueOf(3L), (BigInteger) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(BigInteger.valueOf(3L), int.class);\n            assertEquals(Integer.valueOf(3), (Integer) result);\n        }\n\n        {\n            result = CompatibleTypeUtils.compatibleTypeConvert(3D, float.class);\n            assertEquals(Float.valueOf(3), (Float) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(3F, double.class);\n            assertEquals(Double.valueOf(3), (Double) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(3D, double.class);\n            assertEquals(Double.valueOf(3), (Double) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(3D, BigDecimal.class);\n            assertEquals(BigDecimal.valueOf(3D), (BigDecimal) result);\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(BigDecimal.valueOf(3D), double.class);\n            assertEquals(Double.valueOf(3), (Double) result);\n        }\n\n        {\n            List<String> list = new ArrayList<String>();\n            list.add(\"a\");\n            list.add(\"b\");\n\n            Set<String> set = new HashSet<String>();\n            set.add(\"a\");\n            set.add(\"b\");\n\n            String[] array = new String[] {\"a\", \"b\"};\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(array, List.class);\n            assertEquals(ArrayList.class, result.getClass());\n            assertEquals(2, ((List<String>) result).size());\n            assertTrue(((List<String>) result).contains(\"a\"));\n            assertTrue(((List<String>) result).contains(\"b\"));\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(set, List.class);\n            assertEquals(ArrayList.class, result.getClass());\n            assertEquals(2, ((List<String>) result).size());\n            assertTrue(((List<String>) result).contains(\"a\"));\n            assertTrue(((List<String>) result).contains(\"b\"));\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(array, CopyOnWriteArrayList.class);\n            assertEquals(CopyOnWriteArrayList.class, result.getClass());\n            assertEquals(2, ((List<String>) result).size());\n            assertTrue(((List<String>) result).contains(\"a\"));\n            assertTrue(((List<String>) result).contains(\"b\"));\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(set, CopyOnWriteArrayList.class);\n            assertEquals(CopyOnWriteArrayList.class, result.getClass());\n            assertEquals(2, ((List<String>) result).size());\n            assertTrue(((List<String>) result).contains(\"a\"));\n            assertTrue(((List<String>) result).contains(\"b\"));\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(set, String[].class);\n            assertEquals(String[].class, result.getClass());\n            assertEquals(2, ((String[]) result).length);\n            assertTrue(((String[]) result)[0].equals(\"a\") || ((String[]) result)[0].equals(\"b\"));\n            assertTrue(((String[]) result)[1].equals(\"a\") || ((String[]) result)[1].equals(\"b\"));\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(array, Set.class);\n            assertEquals(HashSet.class, result.getClass());\n            assertEquals(2, ((Set<String>) result).size());\n            assertTrue(((Set<String>) result).contains(\"a\"));\n            assertTrue(((Set<String>) result).contains(\"b\"));\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(list, Set.class);\n            assertEquals(HashSet.class, result.getClass());\n            assertEquals(2, ((Set<String>) result).size());\n            assertTrue(((Set<String>) result).contains(\"a\"));\n            assertTrue(((Set<String>) result).contains(\"b\"));\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(array, ConcurrentHashSet.class);\n            assertEquals(ConcurrentHashSet.class, result.getClass());\n            assertEquals(2, ((Set<String>) result).size());\n            assertTrue(((Set<String>) result).contains(\"a\"));\n            assertTrue(((Set<String>) result).contains(\"b\"));\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(list, ConcurrentHashSet.class);\n            assertEquals(ConcurrentHashSet.class, result.getClass());\n            assertEquals(2, ((Set<String>) result).size());\n            assertTrue(((Set<String>) result).contains(\"a\"));\n            assertTrue(((Set<String>) result).contains(\"b\"));\n\n            result = CompatibleTypeUtils.compatibleTypeConvert(list, String[].class);\n            assertEquals(String[].class, result.getClass());\n            assertEquals(2, ((String[]) result).length);\n            assertTrue(((String[]) result)[0].equals(\"a\"));\n            assertTrue(((String[]) result)[1].equals(\"b\"));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass ConcurrentHashMapUtilsTest {\n\n    @Test\n    public void testComputeIfAbsent() {\n        ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();\n        String ifAbsent = ConcurrentHashMapUtils.computeIfAbsent(map, \"mxsm\", k -> \"mxsm\");\n        assertEquals(\"mxsm\", ifAbsent);\n        ifAbsent = ConcurrentHashMapUtils.computeIfAbsent(map, \"mxsm\", k -> \"mxsm1\");\n        assertEquals(\"mxsm\", ifAbsent);\n        map.remove(\"mxsm\");\n        ifAbsent = ConcurrentHashMapUtils.computeIfAbsent(map, \"mxsm\", k -> \"mxsm1\");\n        assertEquals(\"mxsm1\", ifAbsent);\n    }\n\n    @Test\n    @EnabledForJreRange(max = org.junit.jupiter.api.condition.JRE.JAVA_8)\n    public void issue11986ForJava8Test() {\n        // https://github.com/apache/dubbo/issues/11986\n        final ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();\n        // // map.computeIfAbsent(\"AaAa\", key->map.computeIfAbsent(\"BBBB\",key2->42));\n\n        // In JDK8，for the bug of JDK-8161372，may cause dead cycle when use computeIfAbsent\n        // ConcurrentHashMapUtils.computeIfAbsent method to resolve this bug\n        ConcurrentHashMapUtils.computeIfAbsent(map, \"AaAa\", key -> map.computeIfAbsent(\"BBBB\", key2 -> 42));\n        assertEquals(2, map.size());\n        assertEquals(Integer.valueOf(42), map.get(\"AaAa\"));\n        assertEquals(Integer.valueOf(42), map.get(\"BBBB\"));\n    }\n\n    @Test\n    @EnabledForJreRange(min = org.junit.jupiter.api.condition.JRE.JAVA_9)\n    public void issue11986ForJava17Test() {\n        // https://github.com/apache/dubbo/issues/11986\n        final ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();\n\n        // JDK9+ has been resolved JDK-8161372 bug, when cause dead then throw IllegalStateException\n        assertThrows(IllegalStateException.class, () -> {\n            ConcurrentHashMapUtils.computeIfAbsent(map, \"AaAa\", key -> map.computeIfAbsent(\"BBBB\", key2 -> 42));\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/ConfigUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.config.CompositeConfiguration;\nimport org.apache.dubbo.common.config.InmemoryConfiguration;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.greaterThan;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass ConfigUtilsTest {\n    private Properties properties;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        properties = ConfigUtils.getProperties(Collections.emptySet());\n    }\n\n    @AfterEach\n    public void tearDown() throws Exception {}\n\n    @Test\n    void testIsNotEmpty() throws Exception {\n        assertThat(ConfigUtils.isNotEmpty(\"abc\"), is(true));\n    }\n\n    @Test\n    void testIsEmpty() throws Exception {\n        assertThat(ConfigUtils.isEmpty(null), is(true));\n        assertThat(ConfigUtils.isEmpty(\"\"), is(true));\n        assertThat(ConfigUtils.isEmpty(\"false\"), is(true));\n        assertThat(ConfigUtils.isEmpty(\"FALSE\"), is(true));\n        assertThat(ConfigUtils.isEmpty(\"0\"), is(true));\n        assertThat(ConfigUtils.isEmpty(\"null\"), is(true));\n        assertThat(ConfigUtils.isEmpty(\"NULL\"), is(true));\n        assertThat(ConfigUtils.isEmpty(\"n/a\"), is(true));\n        assertThat(ConfigUtils.isEmpty(\"N/A\"), is(true));\n    }\n\n    @Test\n    void testIsDefault() throws Exception {\n        assertThat(ConfigUtils.isDefault(\"true\"), is(true));\n        assertThat(ConfigUtils.isDefault(\"TRUE\"), is(true));\n        assertThat(ConfigUtils.isDefault(\"default\"), is(true));\n        assertThat(ConfigUtils.isDefault(\"DEFAULT\"), is(true));\n    }\n\n    @Test\n    void testMergeValues() {\n        List<String> merged = ConfigUtils.mergeValues(\n                ApplicationModel.defaultModel().getExtensionDirector(),\n                ThreadPool.class,\n                \"aaa,bbb,default.custom\",\n                asList(\"fixed\", \"default.limited\", \"cached\"));\n        assertEquals(asList(\"fixed\", \"cached\", \"aaa\", \"bbb\", \"default.custom\"), merged);\n    }\n\n    @Test\n    void testMergeValuesAddDefault() {\n        List<String> merged = ConfigUtils.mergeValues(\n                ApplicationModel.defaultModel().getExtensionDirector(),\n                ThreadPool.class,\n                \"aaa,bbb,default,zzz\",\n                asList(\"fixed\", \"default.limited\", \"cached\"));\n        assertEquals(asList(\"aaa\", \"bbb\", \"fixed\", \"cached\", \"zzz\"), merged);\n    }\n\n    @Test\n    void testMergeValuesDeleteDefault() {\n        List<String> merged = ConfigUtils.mergeValues(\n                ApplicationModel.defaultModel().getExtensionDirector(),\n                ThreadPool.class,\n                \"-default\",\n                asList(\"fixed\", \"default.limited\", \"cached\"));\n        assertEquals(Collections.emptyList(), merged);\n    }\n\n    @Test\n    void testMergeValuesDeleteDefault_2() {\n        List<String> merged = ConfigUtils.mergeValues(\n                ApplicationModel.defaultModel().getExtensionDirector(),\n                ThreadPool.class,\n                \"-default,aaa\",\n                asList(\"fixed\", \"default.limited\", \"cached\"));\n        assertEquals(asList(\"aaa\"), merged);\n    }\n\n    /**\n     * The user configures -default, which will delete all the default parameters\n     */\n    @Test\n    void testMergeValuesDelete() {\n        List<String> merged = ConfigUtils.mergeValues(\n                ApplicationModel.defaultModel().getExtensionDirector(),\n                ThreadPool.class,\n                \"-fixed,aaa\",\n                asList(\"fixed\", \"default.limited\", \"cached\"));\n        assertEquals(asList(\"cached\", \"aaa\"), merged);\n    }\n\n    @Test\n    void testReplaceProperty() throws Exception {\n        String s = ConfigUtils.replaceProperty(\"1${a.b.c}2${a.b.c}3\", Collections.singletonMap(\"a.b.c\", \"ABC\"));\n        assertEquals(\"1ABC2ABC3\", s);\n        s = ConfigUtils.replaceProperty(\"1${a.b.c}2${a.b.c}3\", Collections.<String, String>emptyMap());\n        assertEquals(\"1${a.b.c}2${a.b.c}3\", s);\n    }\n\n    @Test\n    void testReplaceProperty2() {\n\n        InmemoryConfiguration configuration1 = new InmemoryConfiguration();\n        configuration1.getProperties().put(\"zookeeper.address\", \"127.0.0.1\");\n\n        InmemoryConfiguration configuration2 = new InmemoryConfiguration();\n        configuration2.getProperties().put(\"zookeeper.port\", \"2181\");\n\n        CompositeConfiguration compositeConfiguration = new CompositeConfiguration();\n        compositeConfiguration.addConfiguration(configuration1);\n        compositeConfiguration.addConfiguration(configuration2);\n\n        String s = ConfigUtils.replaceProperty(\n                \"zookeeper://${zookeeper.address}:${zookeeper.port}\", compositeConfiguration);\n        assertEquals(\"zookeeper://127.0.0.1:2181\", s);\n\n        // should not replace inner class name\n        String interfaceName = \"dubbo.service.io.grpc.examples.helloworld.DubboGreeterGrpc$IGreeter\";\n        s = ConfigUtils.replaceProperty(interfaceName, compositeConfiguration);\n        Assertions.assertEquals(interfaceName, s);\n    }\n\n    @Test\n    void testGetProperties1() throws Exception {\n        try {\n            SystemPropertyConfigUtils.getSystemProperty(CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY);\n            SystemPropertyConfigUtils.setSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY, \"properties.load\");\n            Properties p = ConfigUtils.getProperties(Collections.emptySet());\n            assertThat((String) p.get(\"a\"), equalTo(\"12\"));\n            assertThat((String) p.get(\"b\"), equalTo(\"34\"));\n            assertThat((String) p.get(\"c\"), equalTo(\"56\"));\n        } finally {\n            SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY);\n        }\n    }\n\n    @Test\n    void testGetProperties2() throws Exception {\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY);\n        Properties p = ConfigUtils.getProperties(Collections.emptySet());\n        assertThat((String) p.get(\"dubbo\"), equalTo(\"properties\"));\n    }\n\n    @Test\n    void testLoadPropertiesNoFile() throws Exception {\n        Properties p = ConfigUtils.loadProperties(Collections.emptySet(), \"notExisted\", true);\n        Properties expected = new Properties();\n        assertEquals(expected, p);\n\n        p = ConfigUtils.loadProperties(Collections.emptySet(), \"notExisted\", false);\n        assertEquals(expected, p);\n    }\n\n    @Test\n    void testGetProperty() throws Exception {\n        assertThat(properties.getProperty(\"dubbo\"), equalTo(\"properties\"));\n    }\n\n    @Test\n    void testGetPropertyDefaultValue() throws Exception {\n        assertThat(properties.getProperty(\"not-exist\", \"default\"), equalTo(\"default\"));\n    }\n\n    @Test\n    void testGetSystemProperty() throws Exception {\n        try {\n            System.setProperty(\"dubbo\", \"system-only\");\n            assertThat(ConfigUtils.getSystemProperty(\"dubbo\"), equalTo(\"system-only\"));\n        } finally {\n            System.clearProperty(\"dubbo\");\n        }\n    }\n\n    @Test\n    void testLoadProperties() throws Exception {\n        Properties p = ConfigUtils.loadProperties(Collections.emptySet(), \"dubbo.properties\");\n        assertThat((String) p.get(\"dubbo\"), equalTo(\"properties\"));\n    }\n\n    @Test\n    void testLoadPropertiesOneFile() throws Exception {\n        Properties p = ConfigUtils.loadProperties(Collections.emptySet(), \"properties.load\", false);\n\n        Properties expected = new Properties();\n        expected.put(\"a\", \"12\");\n        expected.put(\"b\", \"34\");\n        expected.put(\"c\", \"56\");\n\n        assertEquals(expected, p);\n    }\n\n    @Test\n    void testLoadPropertiesOneFileAllowMulti() throws Exception {\n        Properties p = ConfigUtils.loadProperties(Collections.emptySet(), \"properties.load\", true);\n\n        Properties expected = new Properties();\n        expected.put(\"a\", \"12\");\n        expected.put(\"b\", \"34\");\n        expected.put(\"c\", \"56\");\n\n        assertEquals(expected, p);\n    }\n\n    @Test\n    void testLoadPropertiesOneFileNotRootPath() throws Exception {\n        Properties p = ConfigUtils.loadProperties(\n                Collections.emptySet(), \"META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.ThreadPool\", false);\n\n        Properties expected = new Properties();\n        expected.put(\"fixed\", \"org.apache.dubbo.common.threadpool.support.fixed.FixedThreadPool\");\n        expected.put(\"cached\", \"org.apache.dubbo.common.threadpool.support.cached.CachedThreadPool\");\n        expected.put(\"limited\", \"org.apache.dubbo.common.threadpool.support.limited.LimitedThreadPool\");\n        expected.put(\"eager\", \"org.apache.dubbo.common.threadpool.support.eager.EagerThreadPool\");\n\n        assertEquals(expected, p);\n    }\n\n    @Disabled(\"Not know why disabled, the original link explaining this was reachable.\")\n    @Test\n    void testLoadPropertiesMultiFileNotRootPathException() throws Exception {\n        try {\n            ConfigUtils.loadProperties(\n                    Collections.emptySet(), \"META-INF/services/org.apache.dubbo.common.status.StatusChecker\", false);\n            Assertions.fail();\n        } catch (IllegalStateException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    containsString(\n                            \"only 1 META-INF/services/org.apache.dubbo.common.status.StatusChecker file is expected, but 2 dubbo.properties files found on class path:\"));\n        }\n    }\n\n    @Test\n    void testLoadPropertiesMultiFileNotRootPath() throws Exception {\n\n        Properties p = ConfigUtils.loadProperties(\n                Collections.emptySet(), \"META-INF/dubbo/internal/org.apache.dubbo.common.status.StatusChecker\", true);\n\n        Properties expected = new Properties();\n        expected.put(\"memory\", \"org.apache.dubbo.common.status.support.MemoryStatusChecker\");\n        expected.put(\"load\", \"org.apache.dubbo.common.status.support.LoadStatusChecker\");\n        expected.put(\"aa\", \"12\");\n\n        assertEquals(expected, p);\n    }\n\n    @Test\n    void testGetPid() throws Exception {\n        assertThat(ConfigUtils.getPid(), greaterThan(0));\n    }\n\n    @Test\n    void testPropertiesWithStructedValue() throws Exception {\n        Properties p = ConfigUtils.loadProperties(Collections.emptySet(), \"parameters.properties\", false);\n\n        Properties expected = new Properties();\n        expected.put(\"dubbo.parameters\", \"[{a:b},{c_.d: r*}]\");\n\n        assertEquals(expected, p);\n    }\n\n    @Test\n    void testLoadMigrationRule() {\n        Set<ClassLoader> classLoaderSet = new HashSet<>();\n        classLoaderSet.add(ClassUtils.getClassLoader());\n        String rule = ConfigUtils.loadMigrationRule(classLoaderSet, \"dubbo-migration.yaml\");\n        Assertions.assertNotNull(rule);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultCharSequence.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.lang.Prioritized;\n\n/**\n * Default {@link CharSequence}\n *\n * @since 2.7.5\n */\npublic class DefaultCharSequence implements CharSequence, Prioritized {\n    @Override\n    public int length() {\n        return 0;\n    }\n\n    @Override\n    public char charAt(int index) {\n        return 0;\n    }\n\n    @Override\n    public CharSequence subSequence(int start, int end) {\n        return null;\n    }\n\n    @Override\n    public int getPriority() {\n        return MAX_PRIORITY;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\n\n/**\n * {@link DefaultPage}\n *\n * @since 2.7.5\n */\nclass DefaultPageTest {\n\n    @Test\n    void test() {\n        List<Integer> data = asList(1, 2, 3, 4, 5);\n        DefaultPage<Integer> page = new DefaultPage<>(0, 1, data.subList(0, 1), data.size());\n        Assertions.assertEquals(page.getOffset(), 0);\n        Assertions.assertEquals(page.getPageSize(), 1);\n        Assertions.assertEquals(page.getTotalSize(), data.size());\n        Assertions.assertEquals(page.getData(), data.subList(0, 1));\n        Assertions.assertEquals(page.getTotalPages(), 5);\n        Assertions.assertTrue(page.hasNext());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultSerializeClassCheckerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.net.Socket;\nimport java.util.LinkedList;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass DefaultSerializeClassCheckerTest {\n\n    @BeforeEach\n    void setUp() {\n        FrameworkModel.destroyAll();\n    }\n\n    @AfterEach\n    void tearDown() {\n        FrameworkModel.destroyAll();\n    }\n\n    @Test\n    void testCommon() throws ClassNotFoundException {\n        FrameworkModel.defaultModel()\n                .getBeanFactory()\n                .getBean(SerializeSecurityManager.class)\n                .setCheckStatus(SerializeCheckStatus.WARN);\n        DefaultSerializeClassChecker defaultSerializeClassChecker = DefaultSerializeClassChecker.getInstance();\n\n        for (int i = 0; i < 10; i++) {\n            defaultSerializeClassChecker.loadClass(\n                    Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.ReadLock.class.getName());\n            defaultSerializeClassChecker.loadClass(\n                    Thread.currentThread().getContextClassLoader(), LinkedList.class.getName());\n            defaultSerializeClassChecker.loadClass(\n                    Thread.currentThread().getContextClassLoader(), Integer.class.getName());\n            defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), int.class.getName());\n        }\n\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            defaultSerializeClassChecker.loadClass(\n                    Thread.currentThread().getContextClassLoader(), Socket.class.getName());\n        });\n        Assertions.assertTrue(FrameworkModel.defaultModel()\n                .getBeanFactory()\n                .getBean(SerializeSecurityManager.class)\n                .getWarnedClasses()\n                .contains(Socket.class.getName()));\n    }\n\n    @Test\n    void testAddAllow() throws ClassNotFoundException {\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_ALLOWED_LIST,\n                ReentrantReadWriteLock.WriteLock.class.getName() + \",\"\n                        + ReentrantReadWriteLock.ReadLock.class.getName());\n\n        DefaultSerializeClassChecker defaultSerializeClassChecker = DefaultSerializeClassChecker.getInstance();\n        for (int i = 0; i < 10; i++) {\n            defaultSerializeClassChecker.loadClass(\n                    Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.WriteLock.class.getName());\n            defaultSerializeClassChecker.loadClass(\n                    Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.ReadLock.class.getName());\n        }\n\n        SystemPropertyConfigUtils.clearSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_ALLOWED_LIST);\n    }\n\n    @Test\n    void testAddBlock() {\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST,\n                Runtime.class.getName() + \",\" + Thread.class.getName());\n\n        DefaultSerializeClassChecker defaultSerializeClassChecker = DefaultSerializeClassChecker.getInstance();\n        for (int i = 0; i < 10; i++) {\n            Assertions.assertThrows(IllegalArgumentException.class, () -> {\n                defaultSerializeClassChecker.loadClass(\n                        Thread.currentThread().getContextClassLoader(), Runtime.class.getName());\n            });\n            Assertions.assertTrue(FrameworkModel.defaultModel()\n                    .getBeanFactory()\n                    .getBean(SerializeSecurityManager.class)\n                    .getWarnedClasses()\n                    .contains(Runtime.class.getName()));\n            Assertions.assertThrows(IllegalArgumentException.class, () -> {\n                defaultSerializeClassChecker.loadClass(\n                        Thread.currentThread().getContextClassLoader(), Thread.class.getName());\n            });\n            Assertions.assertTrue(FrameworkModel.defaultModel()\n                    .getBeanFactory()\n                    .getBean(SerializeSecurityManager.class)\n                    .getWarnedClasses()\n                    .contains(Thread.class.getName()));\n        }\n\n        SystemPropertyConfigUtils.clearSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST);\n    }\n\n    @Test\n    void testBlockAll() throws ClassNotFoundException {\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCK_ALL, \"true\");\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_ALLOWED_LIST,\n                ReentrantReadWriteLock.WriteLock.class.getName());\n\n        DefaultSerializeClassChecker defaultSerializeClassChecker = DefaultSerializeClassChecker.getInstance();\n        for (int i = 0; i < 10; i++) {\n            defaultSerializeClassChecker.loadClass(\n                    Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.WriteLock.class.getName());\n            Assertions.assertThrows(IllegalArgumentException.class, () -> {\n                defaultSerializeClassChecker.loadClass(\n                        Thread.currentThread().getContextClassLoader(),\n                        ReentrantReadWriteLock.ReadLock.class.getName());\n            });\n            Assertions.assertTrue(FrameworkModel.defaultModel()\n                    .getBeanFactory()\n                    .getBean(SerializeSecurityManager.class)\n                    .getWarnedClasses()\n                    .contains(ReentrantReadWriteLock.ReadLock.class.getName()));\n        }\n\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCK_ALL);\n        SystemPropertyConfigUtils.clearSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_ALLOWED_LIST);\n    }\n\n    @Test\n    void testStatus() throws ClassNotFoundException {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n        ssm.setCheckStatus(SerializeCheckStatus.STRICT);\n\n        DefaultSerializeClassChecker defaultSerializeClassChecker = DefaultSerializeClassChecker.getInstance();\n        Assertions.assertEquals(\n                Integer.class,\n                defaultSerializeClassChecker.loadClass(\n                        Thread.currentThread().getContextClassLoader(), Integer.class.getName()));\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            defaultSerializeClassChecker.loadClass(\n                    Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.class.getName());\n        });\n        Assertions.assertTrue(FrameworkModel.defaultModel()\n                .getBeanFactory()\n                .getBean(SerializeSecurityManager.class)\n                .getWarnedClasses()\n                .contains(ReentrantReadWriteLock.class.getName()));\n\n        ssm.setCheckStatus(SerializeCheckStatus.WARN);\n        Assertions.assertEquals(\n                ReentrantReadWriteLock.class,\n                defaultSerializeClassChecker.loadClass(\n                        Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.class.getName()));\n\n        ssm.setCheckStatus(SerializeCheckStatus.DISABLE);\n        Assertions.assertEquals(\n                ReentrantReadWriteLock.class,\n                defaultSerializeClassChecker.loadClass(\n                        Thread.currentThread().getContextClassLoader(), ReentrantReadWriteLock.class.getName()));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/DubboAppenderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.logging.log4j.Level;\nimport org.apache.logging.log4j.core.impl.Log4jLogEvent;\nimport org.apache.logging.log4j.message.SimpleMessage;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasSize;\nimport static org.hamcrest.Matchers.is;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass DubboAppenderTest {\n    private Log4jLogEvent event;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        event = mock(Log4jLogEvent.class);\n        when(event.getLoggerName()).thenReturn(\"logger-name\");\n        when(event.getLevel()).thenReturn(Level.INFO);\n        when(event.getThreadName()).thenReturn(\"thread-name\");\n        when(event.getMessage()).thenReturn(new SimpleMessage(\"message\"));\n\n        DubboAppender.clear();\n        DubboAppender.doStop();\n    }\n\n    @AfterEach\n    public void tearDown() throws Exception {\n        DubboAppender.clear();\n        DubboAppender.doStop();\n    }\n\n    @Test\n    void testAvailable() {\n        assertThat(DubboAppender.available, is(false));\n        DubboAppender.doStart();\n        assertThat(DubboAppender.available, is(true));\n        DubboAppender.doStop();\n        assertThat(DubboAppender.available, is(false));\n    }\n\n    @Test\n    void testAppend() {\n        DubboAppender appender = new DubboAppender();\n        assertThat(DubboAppender.logList, hasSize(0));\n        appender.append(event);\n        assertThat(DubboAppender.logList, hasSize(0));\n        DubboAppender.doStart();\n        appender.append(event);\n        assertThat(DubboAppender.logList, hasSize(1));\n        assertThat(DubboAppender.logList.get(0).getLogThread(), equalTo(\"thread-name\"));\n    }\n\n    @Test\n    void testClear() {\n        DubboAppender.doStart();\n        DubboAppender appender = new DubboAppender();\n        appender.append(event);\n        assertThat(DubboAppender.logList, hasSize(1));\n        DubboAppender.clear();\n        assertThat(DubboAppender.logList, hasSize(0));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/ExecutorUtilTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\n\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.awaitility.Awaitility.await;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass ExecutorUtilTest {\n    @Test\n    void testIsTerminated() throws Exception {\n        ExecutorService executor = Mockito.mock(ExecutorService.class);\n        when(executor.isTerminated()).thenReturn(true);\n        assertThat(ExecutorUtil.isTerminated(executor), is(true));\n        Executor executor2 = Mockito.mock(Executor.class);\n        assertThat(ExecutorUtil.isTerminated(executor2), is(false));\n    }\n\n    @Test\n    void testGracefulShutdown1() throws Exception {\n        ExecutorService executor = Mockito.mock(ExecutorService.class);\n        when(executor.isTerminated()).thenReturn(false, true);\n        when(executor.awaitTermination(20, TimeUnit.MILLISECONDS)).thenReturn(false);\n        ExecutorUtil.gracefulShutdown(executor, 20);\n        verify(executor).shutdown();\n        verify(executor).shutdownNow();\n    }\n\n    @Test\n    void testGracefulShutdown2() throws Exception {\n        ExecutorService executor = Mockito.mock(ExecutorService.class);\n        when(executor.isTerminated()).thenReturn(false, false, false);\n        when(executor.awaitTermination(20, TimeUnit.MILLISECONDS)).thenReturn(false);\n        when(executor.awaitTermination(10, TimeUnit.MILLISECONDS)).thenReturn(false, true);\n        ExecutorUtil.gracefulShutdown(executor, 20);\n\n        await().untilAsserted(() -> verify(executor, times(2)).awaitTermination(10, TimeUnit.MILLISECONDS));\n\n        verify(executor, times(1)).shutdown();\n        verify(executor, times(3)).shutdownNow();\n    }\n\n    @Test\n    void testShutdownNow() throws Exception {\n        ExecutorService executor = Mockito.mock(ExecutorService.class);\n        when(executor.isTerminated()).thenReturn(false, true);\n        ExecutorUtil.shutdownNow(executor, 20);\n        verify(executor).shutdownNow();\n        verify(executor).awaitTermination(20, TimeUnit.MILLISECONDS);\n    }\n\n    @Test\n    void testSetThreadName() throws Exception {\n        URL url = new ServiceConfigURL(\"dubbo\", \"localhost\", 1234).addParameter(THREAD_NAME_KEY, \"custom-thread\");\n        url = ExecutorUtil.setThreadName(url, \"default-name\");\n        assertThat(url.getParameter(THREAD_NAME_KEY), equalTo(\"custom-thread-localhost:1234\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/FieldUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.utils.FieldUtils.findField;\nimport static org.apache.dubbo.common.utils.FieldUtils.getDeclaredField;\nimport static org.apache.dubbo.common.utils.FieldUtils.getFieldValue;\nimport static org.apache.dubbo.common.utils.FieldUtils.setFieldValue;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\n/**\n * {@link FieldUtils} Test-cases\n *\n * @since 2.7.6\n */\nclass FieldUtilsTest {\n\n    @Test\n    void testGetDeclaredField() {\n        assertEquals(\"a\", getDeclaredField(A.class, \"a\").getName());\n        assertEquals(\"b\", getDeclaredField(B.class, \"b\").getName());\n        assertEquals(\"c\", getDeclaredField(C.class, \"c\").getName());\n        assertNull(getDeclaredField(B.class, \"a\"));\n        assertNull(getDeclaredField(C.class, \"a\"));\n    }\n\n    @Test\n    void testFindField() {\n        assertEquals(\"a\", findField(A.class, \"a\").getName());\n        assertEquals(\"a\", findField(new A(), \"a\").getName());\n        assertEquals(\"a\", findField(B.class, \"a\").getName());\n        assertEquals(\"b\", findField(B.class, \"b\").getName());\n        assertEquals(\"a\", findField(C.class, \"a\").getName());\n        assertEquals(\"b\", findField(C.class, \"b\").getName());\n        assertEquals(\"c\", findField(C.class, \"c\").getName());\n    }\n\n    @Test\n    void testGetFieldValue() {\n        assertEquals(\"a\", getFieldValue(new A(), \"a\"));\n        assertEquals(\"a\", getFieldValue(new B(), \"a\"));\n        assertEquals(\"b\", getFieldValue(new B(), \"b\"));\n        assertEquals(\"a\", getFieldValue(new C(), \"a\"));\n        assertEquals(\"b\", getFieldValue(new C(), \"b\"));\n        assertEquals(\"c\", getFieldValue(new C(), \"c\"));\n    }\n\n    @Test\n    void setSetFieldValue() {\n        A a = new A();\n        assertEquals(\"a\", setFieldValue(a, \"a\", \"x\"));\n        assertEquals(\"x\", getFieldValue(a, \"a\"));\n    }\n}\n\nclass A {\n\n    private String a = \"a\";\n}\n\nclass B extends A {\n\n    private String b = \"b\";\n}\n\nclass C extends B {\n\n    private String c = \"c\";\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/HolderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\n\nclass HolderTest {\n    @Test\n    void testSetAndGet() throws Exception {\n        Holder<String> holder = new Holder<String>();\n        String message = \"hello\";\n        holder.set(message);\n        assertThat(holder.get(), is(message));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/IOUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass IOUtilsTest {\n\n    private static String TEXT = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\";\n    private InputStream is;\n    private OutputStream os;\n    private Reader reader;\n    private Writer writer;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        is = new ByteArrayInputStream(TEXT.getBytes(StandardCharsets.UTF_8));\n        os = new ByteArrayOutputStream();\n        reader = new StringReader(TEXT);\n        writer = new StringWriter();\n    }\n\n    @AfterEach\n    public void tearDown() throws Exception {\n        is.close();\n        os.close();\n        reader.close();\n        writer.close();\n    }\n\n    @Test\n    void testWrite1() throws Exception {\n        assertThat((int) IOUtils.write(is, os, 16), equalTo(TEXT.length()));\n    }\n\n    @Test\n    void testWrite2() throws Exception {\n        assertThat((int) IOUtils.write(reader, writer, 16), equalTo(TEXT.length()));\n    }\n\n    @Test\n    void testWrite3() throws Exception {\n        assertThat((int) IOUtils.write(writer, TEXT), equalTo(TEXT.length()));\n    }\n\n    @Test\n    void testWrite4() throws Exception {\n        assertThat((int) IOUtils.write(is, os), equalTo(TEXT.length()));\n    }\n\n    @Test\n    void testWrite5() throws Exception {\n        assertThat((int) IOUtils.write(reader, writer), equalTo(TEXT.length()));\n    }\n\n    @Test\n    void testLines(@TempDir Path tmpDir) throws Exception {\n        File file = tmpDir.getFileName().toAbsolutePath().toFile();\n        IOUtils.writeLines(file, new String[] {TEXT});\n        String[] lines = IOUtils.readLines(file);\n        assertThat(lines.length, equalTo(1));\n        assertThat(lines[0], equalTo(TEXT));\n        tmpDir.getFileName().toAbsolutePath().toFile().delete();\n    }\n\n    @Test\n    void testReadLines() throws Exception {\n        String[] lines = IOUtils.readLines(is);\n        assertThat(lines.length, equalTo(1));\n        assertThat(lines[0], equalTo(TEXT));\n    }\n\n    @Test\n    void testWriteLines() throws Exception {\n        IOUtils.writeLines(os, new String[] {TEXT});\n        ByteArrayOutputStream bos = (ByteArrayOutputStream) os;\n        assertThat(new String(bos.toByteArray()), equalTo(TEXT + System.lineSeparator()));\n    }\n\n    @Test\n    void testRead() throws Exception {\n        assertThat(IOUtils.read(reader), equalTo(TEXT));\n    }\n\n    @Test\n    void testAppendLines(@TempDir Path tmpDir) throws Exception {\n        File file = tmpDir.getFileName().toAbsolutePath().toFile();\n        IOUtils.appendLines(file, new String[] {\"a\", \"b\", \"c\"});\n        String[] lines = IOUtils.readLines(file);\n        assertThat(lines.length, equalTo(3));\n        assertThat(lines[0], equalTo(\"a\"));\n        assertThat(lines[1], equalTo(\"b\"));\n        assertThat(lines[2], equalTo(\"c\"));\n        tmpDir.getFileName().toAbsolutePath().toFile().delete();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/JRETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport javax.lang.model.SourceVersion;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_JAVA_VERSION;\n\nclass JRETest {\n\n    @Test\n    @Disabled\n    void blankSystemVersion() {\n        SystemPropertyConfigUtils.setSystemProperty(SYSTEM_JAVA_VERSION, \"\");\n        JRE jre = JRE.currentVersion();\n        Assertions.assertEquals(JRE.JAVA_8, jre);\n    }\n\n    @Test\n    void testCurrentVersion() {\n        // SourceVersion is an enum, which member name is RELEASE_XX.\n        // e.g., \"RELEASE_25\"\n        String sourceVersionName = SourceVersion.latest().name();\n        String expectedVersion = \"UNKNOWN\";\n        if (sourceVersionName.contains(\"_\")) {\n            expectedVersion = sourceVersionName.split(\"_\")[1];\n        }\n\n        String jreEnumName = JRE.currentVersion().name();\n        String actualVersion = \"UNKNOWN\";\n        if (jreEnumName.contains(\"_\")) {\n            actualVersion = jreEnumName.split(\"_\")[1];\n        } else {\n            actualVersion = jreEnumName;\n        }\n\n        Assertions.assertEquals(expectedVersion, actualVersion);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/JVMUtilTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nclass JVMUtilTest {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/JavassistParameterNameReaderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.emptyArray;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass JavassistParameterNameReaderTest {\n\n    private final ParameterNameReader reader = new JavassistParameterNameReader();\n\n    @Test\n    void readFromConstructor() {\n        Class<?> clazz = URL.class;\n        for (Constructor<?> ctor : clazz.getConstructors()) {\n            String[] names = reader.readParameterNames(ctor);\n            if (names.length == 7) {\n                assertThat(names[0], equalTo(\"protocol\"));\n            }\n        }\n    }\n\n    @Test\n    void readFromMethod() {\n        Class<?> clazz = URL.class;\n        for (Method method : clazz.getMethods()) {\n            String[] names = reader.readParameterNames(method);\n            switch (method.getName()) {\n                case \"getAddress\":\n                    assertThat(names, emptyArray());\n                    break;\n                case \"setAddress\":\n                    assertThat(names[0], equalTo(\"address\"));\n                    break;\n                case \"buildKey\":\n                    assertThat(names[0], equalTo(\"path\"));\n                    break;\n                default:\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/JsonCompatibilityUtilTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.utils.json.Service;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\npublic class JsonCompatibilityUtilTest {\n\n    private static Class<?> service = Service.class;\n\n    private static final Logger logger = LoggerFactory.getLogger(JsonCompatibilityUtil.class);\n\n    @Test\n    public void testCheckClassCompatibility() {\n        boolean res = JsonCompatibilityUtil.checkClassCompatibility(service);\n        assertFalse(res);\n    }\n\n    @Test\n    public void testGetUnsupportedMethods() {\n        List<String> res = JsonCompatibilityUtil.getUnsupportedMethods(service);\n        assert res != null;\n        logger.info(res.toString());\n        assert (res.size() != 0);\n    }\n\n    @Test\n    public void testInt() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testInt\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testIntArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testIntArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testInteger() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testInteger\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testIntegerArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testIntegerArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testIntegerList() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testIntegerList\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testShort() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testShort\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testShortArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testShortArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testSShort() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testSShort\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testSShortArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testSShortArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testShortList() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testShortList\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testByte() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testByte\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testByteArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testByteArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testBByte() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testBByte\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testBByteArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testBByteArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testByteList() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testByteList\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testFloat() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testFloat\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testFloatArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testFloatArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testFFloat() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testFFloat\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testFloatArray() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testFloatArray\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testFloatList() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testFloatList\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testBoolean() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testBoolean\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testBooleanArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testBooleanArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testBBoolean() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testBBoolean\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testBooleanArray() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testBooleanArray\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testBooleanList() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testBooleanList\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testChar() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testChar\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testCharArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testCharArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testCharacter() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testCharacter\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testCharacterArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testCharacterArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testCharacterList() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testCharacterList\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testCharacterListArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testCharacterListArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testString() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testString\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testStringArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testStringArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testStringList() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testStringList\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testStringListArr() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testStringListArr\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testDate() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testDate\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testCalendar() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testCalendar\"));\n        assertFalse(res);\n    }\n\n    @Test\n    public void testLocalTime() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testLocalTime\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testLocalDate() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testLocalDate\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testLocalDateTime() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testLocalDateTime\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testZoneDateTime() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testZoneDateTime\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testMap() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testMap\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testSet() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testSet\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testOptionalEmpty() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testOptionalEmpty\"));\n        assertFalse(res);\n    }\n\n    @Test\n    public void testOptionalInteger() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testOptionalInteger\"));\n        assertFalse(res);\n    }\n\n    @Test\n    public void testOptionalString() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testOptionalString\"));\n        assertFalse(res);\n    }\n\n    @Test\n    public void testEnum() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testEnum\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testRecord() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testRecord\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testInterface() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testInterface\"));\n        assertFalse(res);\n    }\n\n    @Test\n    public void testObject() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testObject\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testObjectList() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testObjectList\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testTemplate() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testTemplate\"));\n        assertTrue(res);\n    }\n\n    @Test\n    public void testStream() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testStream\"));\n        assertFalse(res);\n    }\n\n    @Test\n    public void testIterator() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testIterator\"));\n        assertFalse(res);\n    }\n\n    @Test\n    public void testAbstract() throws NoSuchMethodException {\n        boolean res = JsonCompatibilityUtil.checkMethodCompatibility(service.getDeclaredMethod(\"testAbstract\"));\n        assertFalse(res);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/JsonUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.json.JsonUtil;\nimport org.apache.dubbo.common.json.impl.FastJson2Impl;\nimport org.apache.dubbo.common.json.impl.FastJsonImpl;\nimport org.apache.dubbo.common.json.impl.GsonImpl;\nimport org.apache.dubbo.common.json.impl.JacksonImpl;\nimport org.apache.dubbo.common.utils.json.TestEnum;\nimport org.apache.dubbo.common.utils.json.TestObjectA;\nimport org.apache.dubbo.common.utils.json.TestObjectB;\n\nimport java.lang.reflect.Field;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedConstruction;\nimport org.mockito.Mockito;\n\nclass JsonUtilsTest {\n    private AtomicBoolean allowFastjson2 = new AtomicBoolean(true);\n    private AtomicBoolean allowFastjson = new AtomicBoolean(true);\n    private AtomicBoolean allowGson = new AtomicBoolean(true);\n    private AtomicBoolean allowJackson = new AtomicBoolean(true);\n    private MockedConstruction<FastJson2Impl> fastjson2Mock;\n    private MockedConstruction<FastJsonImpl> fastjsonMock;\n    private MockedConstruction<GsonImpl> gsonMock;\n    private MockedConstruction<JacksonImpl> jacksonMock;\n\n    @AfterEach\n    void teardown() {\n        if (fastjsonMock != null) {\n            fastjsonMock.close();\n        }\n        if (fastjson2Mock != null) {\n            fastjson2Mock.close();\n        }\n        if (gsonMock != null) {\n            gsonMock.close();\n        }\n        if (jacksonMock != null) {\n            jacksonMock.close();\n        }\n    }\n\n    @Test\n    void testIsJson() {\n        JsonUtils.setJson(null);\n        // prefer use fastjson2\n        System.setProperty(\"dubbo.json-framework.prefer\", \"fastjson2\");\n        Assertions.assertTrue(\n                JsonUtils.getJson().isJson(\"{\\\"title\\\":\\\"Java Programming\\\",\\\"author\\\":\\\"John Doe\\\",\\\"pages\\\":300}\"));\n        Assertions.assertFalse(JsonUtils.getJson().isJson(\"This is not a JSON string\"));\n        Assertions.assertTrue(\n                JsonUtils.getJson().isJson(\"[{\\\"title\\\":\\\"Java Programming\\\"}, {\\\"title\\\":\\\"Python Programming\\\"}]\"));\n        System.clearProperty(\"dubbo.json-framework.prefer\");\n\n        // prefer use fastjson\n        JsonUtils.setJson(null);\n        System.setProperty(\"dubbo.json-framework.prefer\", \"fastjson\");\n        Assertions.assertTrue(\n                JsonUtils.getJson().isJson(\"{\\\"title\\\":\\\"Java Programming\\\",\\\"author\\\":\\\"John Doe\\\",\\\"pages\\\":300}\"));\n        Assertions.assertFalse(JsonUtils.getJson().isJson(\"This is not a JSON string\"));\n        Assertions.assertTrue(\n                JsonUtils.getJson().isJson(\"[{\\\"title\\\":\\\"Java Programming\\\"}, {\\\"title\\\":\\\"Python Programming\\\"}]\"));\n        System.clearProperty(\"dubbo.json-framework.prefer\");\n\n        // prefer use gson\n        JsonUtils.setJson(null);\n        System.setProperty(\"dubbo.json-framework.prefer\", \"gson\");\n        Assertions.assertTrue(\n                JsonUtils.getJson().isJson(\"{\\\"title\\\":\\\"Java Programming\\\",\\\"author\\\":\\\"John Doe\\\",\\\"pages\\\":300}\"));\n        Assertions.assertFalse(JsonUtils.getJson().isJson(\"This is not a JSON string\"));\n        Assertions.assertTrue(\n                JsonUtils.getJson().isJson(\"[{\\\"title\\\":\\\"Java Programming\\\"}, {\\\"title\\\":\\\"Python Programming\\\"}]\"));\n        System.clearProperty(\"dubbo.json-framework.prefer\");\n\n        // prefer use jackson\n        JsonUtils.setJson(null);\n        System.setProperty(\"dubbo.json-framework.prefer\", \"jackson\");\n        Assertions.assertTrue(\n                JsonUtils.getJson().isJson(\"{\\\"title\\\":\\\"Java Programming\\\",\\\"author\\\":\\\"John Doe\\\",\\\"pages\\\":300}\"));\n        Assertions.assertFalse(JsonUtils.getJson().isJson(\"This is not a JSON string\"));\n        Assertions.assertTrue(\n                JsonUtils.getJson().isJson(\"[{\\\"title\\\":\\\"Java Programming\\\"}, {\\\"title\\\":\\\"Python Programming\\\"}]\"));\n        System.clearProperty(\"dubbo.json-framework.prefer\");\n    }\n\n    @Test\n    void testGetJson1() {\n        Assertions.assertNotNull(JsonUtils.getJson());\n        Assertions.assertEquals(JsonUtils.getJson(), JsonUtils.getJson());\n\n        Map<String, String> map = new HashMap<>();\n        map.put(\"a\", \"a\");\n        Assertions.assertEquals(\"{\\\"a\\\":\\\"a\\\"}\", JsonUtils.getJson().toJson(map));\n        Assertions.assertEquals(map, JsonUtils.getJson().toJavaObject(\"{\\\"a\\\":\\\"a\\\"}\", Map.class));\n        Assertions.assertEquals(\n                Collections.singletonList(map), JsonUtils.getJson().toJavaList(\"[{\\\"a\\\":\\\"a\\\"}]\", Map.class));\n\n        // prefer use fastjson2\n        setJson(null);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"fastjson2\");\n        Assertions.assertEquals(\"{\\\"a\\\":\\\"a\\\"}\", JsonUtils.getJson().toJson(map));\n        Assertions.assertEquals(map, JsonUtils.getJson().toJavaObject(\"{\\\"a\\\":\\\"a\\\"}\", Map.class));\n        Assertions.assertEquals(\n                Collections.singletonList(map), JsonUtils.getJson().toJavaList(\"[{\\\"a\\\":\\\"a\\\"}]\", Map.class));\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n        // prefer use fastjson\n        setJson(null);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"fastjson\");\n        Assertions.assertEquals(\"{\\\"a\\\":\\\"a\\\"}\", JsonUtils.getJson().toJson(map));\n        Assertions.assertEquals(map, JsonUtils.getJson().toJavaObject(\"{\\\"a\\\":\\\"a\\\"}\", Map.class));\n        Assertions.assertEquals(\n                Collections.singletonList(map), JsonUtils.getJson().toJavaList(\"[{\\\"a\\\":\\\"a\\\"}]\", Map.class));\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n        // prefer use gson\n        setJson(null);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"gson\");\n        Assertions.assertEquals(\"{\\\"a\\\":\\\"a\\\"}\", JsonUtils.getJson().toJson(map));\n        Assertions.assertEquals(map, JsonUtils.getJson().toJavaObject(\"{\\\"a\\\":\\\"a\\\"}\", Map.class));\n        Assertions.assertEquals(\n                Collections.singletonList(map), JsonUtils.getJson().toJavaList(\"[{\\\"a\\\":\\\"a\\\"}]\", Map.class));\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n        // prefer use jackson\n        setJson(null);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"jackson\");\n        Assertions.assertEquals(\"{\\\"a\\\":\\\"a\\\"}\", JsonUtils.getJson().toJson(map));\n        Assertions.assertEquals(map, JsonUtils.getJson().toJavaObject(\"{\\\"a\\\":\\\"a\\\"}\", Map.class));\n        Assertions.assertEquals(\n                Collections.singletonList(map), JsonUtils.getJson().toJavaList(\"[{\\\"a\\\":\\\"a\\\"}]\", Map.class));\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n        setJson(null);\n    }\n\n    @Test\n    void consistentTest() throws Exception {\n        ObjectMapper om = new ObjectMapper();\n        List<Object> objs = new LinkedList<>();\n\n        {\n            objs.add(null);\n        }\n\n        {\n            Map<String, String> map = new HashMap<>();\n            map.put(\"a\", \"a\");\n            objs.add(map);\n        }\n\n        {\n            TestObjectA a = new TestObjectA();\n            objs.add(a);\n        }\n\n        {\n            TestObjectA a = new TestObjectA();\n            a.setTestEnum(TestEnum.TYPE_A);\n            objs.add(a);\n        }\n\n        {\n            TestObjectB b = new TestObjectB();\n            objs.add(b);\n        }\n\n        {\n            TestObjectB b = new TestObjectB();\n            b.setInnerA(new TestObjectB.Inner());\n            b.setInnerB(new TestObjectB.Inner());\n            objs.add(b);\n        }\n\n        {\n            TestObjectB b = new TestObjectB();\n            TestObjectB.Inner inner1 = new TestObjectB.Inner();\n            TestObjectB.Inner inner2 = new TestObjectB.Inner();\n            inner1.setName(\"Test\");\n            inner2.setName(\"Test\");\n            b.setInnerA(inner1);\n            b.setInnerB(inner2);\n            objs.add(b);\n        }\n\n        {\n            TestObjectB b = new TestObjectB();\n            TestObjectB.Inner inner1 = new TestObjectB.Inner();\n            inner1.setName(\"Test\");\n            b.setInnerA(inner1);\n            b.setInnerB(inner1);\n            objs.add(b);\n        }\n\n        for (Object obj : objs) {\n\n            // prefer use fastjson2\n            setJson(null);\n            SystemPropertyConfigUtils.setSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"fastjson2\");\n            Assertions.assertInstanceOf(FastJson2Impl.class, JsonUtils.getJson());\n            String fromFastjson2 = JsonUtils.getJson().toJson(obj);\n            SystemPropertyConfigUtils.clearSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n            // prefer use fastjson\n            setJson(null);\n            SystemPropertyConfigUtils.setSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"fastjson\");\n            Assertions.assertInstanceOf(FastJsonImpl.class, JsonUtils.getJson());\n            String fromFastjson1 = JsonUtils.getJson().toJson(obj);\n            SystemPropertyConfigUtils.clearSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n            // prefer use gson\n            setJson(null);\n            SystemPropertyConfigUtils.setSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"gson\");\n            Assertions.assertInstanceOf(GsonImpl.class, JsonUtils.getJson());\n            String fromGson = JsonUtils.getJson().toJson(obj);\n            SystemPropertyConfigUtils.clearSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n            // prefer use jackson\n            setJson(null);\n            SystemPropertyConfigUtils.setSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"jackson\");\n            Assertions.assertInstanceOf(JacksonImpl.class, JsonUtils.getJson());\n            String fromJackson = JsonUtils.getJson().toJson(obj);\n            SystemPropertyConfigUtils.clearSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n            setJson(null);\n\n            Assertions.assertEquals(om.readTree(fromFastjson1), om.readTree(fromFastjson2));\n            Assertions.assertEquals(om.readTree(fromFastjson1), om.readTree(fromGson));\n            Assertions.assertEquals(om.readTree(fromFastjson2), om.readTree(fromGson));\n            Assertions.assertEquals(om.readTree(fromFastjson1), om.readTree(fromJackson));\n            Assertions.assertEquals(om.readTree(fromFastjson2), om.readTree(fromJackson));\n        }\n    }\n\n    @Test\n    void testGetJson2() {\n        fastjson2Mock = Mockito.mockConstruction(FastJson2Impl.class, (mock, context) -> {\n            Mockito.when(mock.isSupport()).thenAnswer(invocation -> allowFastjson2.get());\n            Mockito.when(mock.getName()).thenAnswer(invocation -> \"fastjson2\");\n        });\n        fastjsonMock = Mockito.mockConstruction(FastJsonImpl.class, (mock, context) -> {\n            Mockito.when(mock.isSupport()).thenAnswer(invocation -> allowFastjson.get());\n            Mockito.when(mock.getName()).thenAnswer(invocation -> \"fastjson\");\n        });\n        gsonMock = Mockito.mockConstruction(GsonImpl.class, (mock, context) -> {\n            Mockito.when(mock.isSupport()).thenAnswer(invocation -> allowGson.get());\n            Mockito.when(mock.getName()).thenAnswer(invocation -> \"gson\");\n        });\n        jacksonMock = Mockito.mockConstruction(JacksonImpl.class, (mock, context) -> {\n            Mockito.when(mock.isSupport()).thenAnswer(invocation -> allowJackson.get());\n            Mockito.when(mock.getName()).thenAnswer(invocation -> \"jackson\");\n        });\n\n        // default use fastjson2\n        setJson(null);\n        Assertions.assertInstanceOf(FastJson2Impl.class, JsonUtils.getJson());\n\n        // prefer use fastjson2\n        setJson(null);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"fastjson2\");\n        Assertions.assertInstanceOf(FastJson2Impl.class, JsonUtils.getJson());\n\n        // prefer use fastjson\n        setJson(null);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"fastjson\");\n        Assertions.assertInstanceOf(FastJsonImpl.class, JsonUtils.getJson());\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n        // prefer use gson\n        setJson(null);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"gson\");\n        Assertions.assertInstanceOf(GsonImpl.class, JsonUtils.getJson());\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n        // prefer use not found\n        setJson(null);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"notfound\");\n        Assertions.assertInstanceOf(FastJson2Impl.class, JsonUtils.getJson());\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n\n        setJson(null);\n        // TCCL not found fastjson2\n        allowFastjson2.set(false);\n        Assertions.assertInstanceOf(FastJsonImpl.class, JsonUtils.getJson());\n        allowFastjson2.set(true);\n\n        setJson(null);\n        // TCCL not found fastjson2, fastjson\n        allowFastjson2.set(false);\n        allowFastjson.set(false);\n        Assertions.assertInstanceOf(GsonImpl.class, JsonUtils.getJson());\n        allowFastjson.set(true);\n        allowFastjson2.set(true);\n\n        setJson(null);\n        // TCCL not found fastjson2, fastjson, gson\n        allowFastjson2.set(false);\n        allowFastjson.set(false);\n        allowGson.set(false);\n        Assertions.assertInstanceOf(JacksonImpl.class, JsonUtils.getJson());\n        allowGson.set(true);\n        allowFastjson.set(true);\n        allowFastjson2.set(true);\n\n        setJson(null);\n        // TCCL not found fastjson2, prefer use fastjson2\n        allowFastjson2.set(false);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"fastjson2\");\n        Assertions.assertInstanceOf(FastJsonImpl.class, JsonUtils.getJson());\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n        allowFastjson2.set(true);\n\n        setJson(null);\n        // TCCL not found fastjson, prefer use fastjson\n        allowFastjson.set(false);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"fastjson\");\n        Assertions.assertInstanceOf(FastJson2Impl.class, JsonUtils.getJson());\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n        allowFastjson.set(true);\n\n        setJson(null);\n        // TCCL not found gson, prefer use gson\n        allowGson.set(false);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"gson\");\n        Assertions.assertInstanceOf(FastJson2Impl.class, JsonUtils.getJson());\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n        allowGson.set(true);\n\n        setJson(null);\n        // TCCL not found jackson, prefer use jackson\n        allowJackson.set(false);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"jackson\");\n        Assertions.assertInstanceOf(FastJson2Impl.class, JsonUtils.getJson());\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n        allowJackson.set(true);\n\n        setJson(null);\n        // TCCL not found fastjson, gson\n        allowFastjson2.set(false);\n        allowFastjson.set(false);\n        allowGson.set(false);\n        allowJackson.set(false);\n        Assertions.assertThrows(IllegalStateException.class, JsonUtils::getJson);\n        allowGson.set(true);\n        allowFastjson.set(true);\n        allowFastjson2.set(true);\n        allowJackson.set(true);\n\n        setJson(null);\n    }\n\n    private static Field jsonFieldCache;\n\n    /**\n     * Test for JDK 21+ compatibility with SequencedCollection.\n     * Verifies that toJavaList() works correctly with Jackson on JDK 25.\n     * This test ensures that the fix using ArrayList.class instead of List.class\n     * resolves the type inference issue introduced in JDK 21+.\n     *\n     * @date 2025-11-04\n     */\n    @Test\n    void testToJavaListJDKCompatibility() {\n        // Test with Jackson specifically, as it's most affected by SequencedCollection changes\n        setJson(null);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, \"jackson\");\n\n        // Test parsing JSON array of strings (the original failing case from ConfiguratorTest)\n        String jsonArray = \"[\\\"override://0.0.0.0/com.xx.Service?timeout=6666\\\", \"\n                + \"\\\"absent://0.0.0.0/com.xx.Service?timeout=8888\\\"]\";\n        List<String> result = JsonUtils.toJavaList(jsonArray, String.class);\n\n        Assertions.assertNotNull(result, \"Result should not be null\");\n        Assertions.assertEquals(2, result.size(), \"Should parse 2 elements\");\n        Assertions.assertTrue(result.get(0).startsWith(\"override://\"), \"First element should start with 'override://'\");\n        Assertions.assertTrue(result.get(1).startsWith(\"absent://\"), \"Second element should start with 'absent://'\");\n\n        // Test parsing JSON array of objects\n        String jsonObjectArray = \"[{\\\"a\\\":\\\"value1\\\"}, {\\\"b\\\":\\\"value2\\\"}]\";\n        List<Map> mapResult = JsonUtils.toJavaList(jsonObjectArray, Map.class);\n\n        Assertions.assertNotNull(mapResult, \"Map result should not be null\");\n        Assertions.assertEquals(2, mapResult.size(), \"Should parse 2 map elements\");\n        Assertions.assertTrue(mapResult.get(0).containsKey(\"a\"), \"First map should contain key 'a'\");\n        Assertions.assertTrue(mapResult.get(1).containsKey(\"b\"), \"Second map should contain key 'b'\");\n\n        // Test with other JSON implementations to ensure consistency\n        String[] implementations = {\"fastjson2\", \"fastjson\", \"gson\"};\n        for (String impl : implementations) {\n            setJson(null);\n            SystemPropertyConfigUtils.setSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, impl);\n\n            List<String> implResult = JsonUtils.toJavaList(jsonArray, String.class);\n            Assertions.assertNotNull(implResult, impl + \" should parse the array\");\n            Assertions.assertEquals(2, implResult.size(), impl + \" should parse 2 elements\");\n\n            SystemPropertyConfigUtils.clearSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n        }\n\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME);\n        setJson(null);\n    }\n\n    private static void setJson(JsonUtil json) {\n        try {\n            if (jsonFieldCache == null) {\n                jsonFieldCache = JsonUtils.class.getDeclaredField(\"jsonUtil\");\n                jsonFieldCache.setAccessible(true);\n            }\n\n            jsonFieldCache.set(null, json);\n\n        } catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/LFUCacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass LFUCacheTest {\n\n    @Test\n    void testCacheEviction() {\n        LFUCache<String, Integer> cache = new LFUCache<>(8, 0.8f);\n        cache.put(\"one\", 1);\n        cache.put(\"two\", 2);\n        cache.put(\"three\", 3);\n        assertThat(cache.get(\"one\"), equalTo(1));\n        assertThat(cache.get(\"two\"), equalTo(2));\n        assertThat(cache.get(\"three\"), equalTo(3));\n        assertThat(cache.getSize(), equalTo(3));\n        cache.put(\"four\", 4);\n        assertThat(cache.getSize(), equalTo(4));\n        cache.put(\"five\", 5);\n        cache.put(\"six\", 6);\n        assertThat(cache.getSize(), equalTo(6));\n        cache.put(\"seven\", 7);\n        cache.put(\"eight\", 8);\n        cache.put(\"nine\", 9);\n        assertThat(cache.getSize(), equalTo(2));\n    }\n\n    @Test\n    void testCacheRemove() {\n        LFUCache<String, Integer> cache = new LFUCache<>(8, 0.8f);\n        cache.put(\"one\", 1);\n        cache.put(\"two\", 2);\n        cache.put(\"three\", 3);\n        assertThat(cache.get(\"one\"), equalTo(1));\n        assertThat(cache.get(\"two\"), equalTo(2));\n        assertThat(cache.get(\"three\"), equalTo(3));\n        assertThat(cache.getSize(), equalTo(3));\n        cache.put(\"four\", 4);\n        assertThat(cache.getSize(), equalTo(4));\n        cache.remove(\"four\");\n        assertThat(cache.getSize(), equalTo(3));\n        cache.put(\"five\", 5);\n        assertThat(cache.getSize(), equalTo(4));\n        cache.put(\"six\", 6);\n        assertThat(cache.getSize(), equalTo(5));\n    }\n\n    @Test\n    void testDefaultCapacity() {\n        LFUCache<String, Integer> cache = new LFUCache<>();\n        assertThat(cache.getCapacity(), equalTo(1000));\n    }\n\n    @Test\n    void testErrorConstructArguments() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> new LFUCache<>(0, 0.8f));\n        Assertions.assertThrows(IllegalArgumentException.class, () -> new LFUCache<>(-1, 0.8f));\n        Assertions.assertThrows(IllegalArgumentException.class, () -> new LFUCache<>(100, 0.0f));\n        Assertions.assertThrows(IllegalArgumentException.class, () -> new LFUCache<>(100, -0.1f));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/LRU2CacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass LRU2CacheTest {\n    @Test\n    void testCache() {\n        LRU2Cache<String, Integer> cache = new LRU2Cache<String, Integer>(3);\n        cache.put(\"one\", 1);\n        cache.put(\"two\", 2);\n        cache.put(\"three\", 3);\n        assertFalse(cache.containsKey(\"one\"));\n        assertFalse(cache.containsKey(\"two\"));\n        assertFalse(cache.containsKey(\"three\"));\n        cache.put(\"one\", 1);\n        cache.put(\"two\", 2);\n        cache.put(\"three\", 3);\n        assertThat(cache.get(\"one\"), equalTo(1));\n        assertThat(cache.get(\"two\"), equalTo(2));\n        assertThat(cache.get(\"three\"), equalTo(3));\n        assertThat(cache.size(), equalTo(3));\n        cache.put(\"four\", 4);\n        cache.put(\"four\", 4);\n        assertThat(cache.size(), equalTo(3));\n        assertFalse(cache.containsKey(\"one\"));\n        assertTrue(cache.containsKey(\"two\"));\n        assertTrue(cache.containsKey(\"three\"));\n        assertTrue(cache.containsKey(\"four\"));\n        cache.remove(\"four\");\n        assertThat(cache.size(), equalTo(2));\n        cache.put(\"five\", 5);\n        cache.put(\"five\", 5);\n        assertFalse(cache.containsKey(\"four\"));\n        assertTrue(cache.containsKey(\"five\"));\n        assertTrue(cache.containsKey(\"two\"));\n        assertTrue(cache.containsKey(\"three\"));\n        assertThat(cache.size(), equalTo(3));\n        cache.put(\"six\", 6);\n        assertFalse(cache.containsKey(\"six\"));\n    }\n\n    @Test\n    void testCapacity() {\n        LRU2Cache<String, Integer> cache = new LRU2Cache<String, Integer>();\n        assertThat(cache.getMaxCapacity(), equalTo(1000));\n        cache.setMaxCapacity(10);\n        assertThat(cache.getMaxCapacity(), equalTo(10));\n    }\n\n    @Test\n    void testTrimWhenCapacityReduced() {\n        LRU2Cache<String, Integer> cache = new LRU2Cache<>(5);\n\n        cache.put(\"1\", 1);\n        cache.put(\"2\", 2);\n        cache.put(\"3\", 3);\n        cache.put(\"4\", 4);\n        cache.put(\"5\", 5);\n\n        // trigger LRU2 flow (do not assume size)\n        cache.get(\"1\");\n        cache.get(\"1\");\n        cache.get(\"2\");\n        cache.get(\"2\");\n        cache.get(\"3\");\n        cache.get(\"3\");\n        cache.get(\"4\");\n        cache.get(\"4\");\n        cache.get(\"5\");\n        cache.get(\"5\");\n\n        // Reduce capacity\n        cache.setMaxCapacity(3);\n\n        // Only guarantee we care about:\n        assertTrue(cache.size() <= 3);\n\n        // Old entries should be gone\n        assertFalse(cache.containsKey(\"1\"));\n        assertFalse(cache.containsKey(\"2\"));\n    }\n\n    @Test\n    void testPreCacheTrimWhenCapacityReduced() {\n        LRU2Cache<String, Integer> cache = new LRU2Cache<>(5);\n\n        cache.put(\"1\", 1);\n        cache.put(\"2\", 2);\n        cache.put(\"3\", 3);\n        cache.put(\"4\", 4);\n        cache.put(\"5\", 5);\n\n        cache.setMaxCapacity(2);\n\n        // Access entries to promote them through LRU2 flow\n        cache.get(\"1\");\n        cache.get(\"2\");\n        cache.get(\"3\");\n        cache.get(\"4\");\n        cache.get(\"5\");\n\n        assertTrue(cache.size() <= 2);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/LRUCacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\n\nclass LRUCacheTest {\n\n    @Test\n    void testTrimWhenCapacityReduced() {\n        LRUCache<String, Integer> cache = new LRUCache<>(5);\n\n        cache.put(\"1\", 1);\n        cache.put(\"2\", 2);\n        cache.put(\"3\", 3);\n        cache.put(\"4\", 4);\n        cache.put(\"5\", 5);\n\n        assertThat(cache.size(), equalTo(5));\n\n        // Reduce capacity and verify immediate trimming\n        cache.setMaxCapacity(3);\n\n        assertThat(cache.size(), equalTo(3));\n\n        // Oldest entries should be evicted\n        assertFalse(cache.containsKey(\"1\"));\n        assertFalse(cache.containsKey(\"2\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/LockUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.Thread.State;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.RepeatedTest;\n\nimport static org.awaitility.Awaitility.await;\n\npublic class LockUtilsTest {\n    @RepeatedTest(5)\n    void testLockFailed() {\n        ReentrantLock reentrantLock = new ReentrantLock();\n        AtomicBoolean releaseLock = new AtomicBoolean(false);\n        new Thread(() -> {\n                    reentrantLock.lock();\n                    while (!releaseLock.get()) {\n                        try {\n                            Thread.sleep(5);\n                        } catch (InterruptedException e) {\n                            throw new RuntimeException(e);\n                        }\n                    }\n                    reentrantLock.unlock();\n                })\n                .start();\n\n        await().until(reentrantLock::isLocked);\n\n        AtomicLong lockTime = new AtomicLong(0);\n        long startTime = System.currentTimeMillis();\n        LockUtils.safeLock(reentrantLock, 1000, () -> {\n            lockTime.set(System.currentTimeMillis());\n        });\n        Assertions.assertTrue(lockTime.get() - startTime >= 1000);\n        releaseLock.set(true);\n\n        while (reentrantLock.isLocked()) {\n            try {\n                Thread.sleep(5);\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        lockTime.set(0);\n        startTime = System.currentTimeMillis();\n        LockUtils.safeLock(reentrantLock, 1000, () -> {\n            lockTime.set(System.currentTimeMillis());\n        });\n        Assertions.assertTrue(lockTime.get() - startTime < 1000);\n    }\n\n    @RepeatedTest(5)\n    void testReentrant() {\n        ReentrantLock reentrantLock = new ReentrantLock();\n        reentrantLock.lock();\n\n        AtomicLong lockTime = new AtomicLong(0);\n        long startTime = System.currentTimeMillis();\n        LockUtils.safeLock(reentrantLock, 1000, () -> {\n            lockTime.set(System.currentTimeMillis());\n        });\n        Assertions.assertTrue(lockTime.get() - startTime < 1000);\n\n        reentrantLock.lock();\n        lockTime.set(0);\n        startTime = System.currentTimeMillis();\n        LockUtils.safeLock(reentrantLock, 1000, () -> {\n            lockTime.set(System.currentTimeMillis());\n        });\n        Assertions.assertTrue(lockTime.get() - startTime < 1000);\n\n        Assertions.assertTrue(reentrantLock.isLocked());\n        reentrantLock.unlock();\n        Assertions.assertTrue(reentrantLock.isLocked());\n        reentrantLock.unlock();\n        Assertions.assertFalse(reentrantLock.isLocked());\n    }\n\n    @RepeatedTest(5)\n    void testInterrupt() {\n        ReentrantLock reentrantLock = new ReentrantLock();\n        reentrantLock.lock();\n\n        AtomicBoolean locked = new AtomicBoolean(false);\n        Thread thread = new Thread(() -> {\n            LockUtils.safeLock(reentrantLock, 10000, () -> {\n                locked.set(true);\n            });\n        });\n        thread.start();\n\n        await().until(() -> thread.getState() == State.TIMED_WAITING);\n        thread.interrupt();\n        await().until(() -> thread.getState() == State.TERMINATED);\n\n        Assertions.assertTrue(locked.get());\n\n        reentrantLock.unlock();\n    }\n\n    @RepeatedTest(5)\n    void testHoldLock() throws InterruptedException {\n        ReentrantLock reentrantLock = new ReentrantLock();\n        reentrantLock.lock();\n\n        AtomicLong lockTime = new AtomicLong(0);\n        long startTime = System.currentTimeMillis();\n        Thread thread = new Thread(() -> {\n            LockUtils.safeLock(reentrantLock, 10000, () -> {\n                lockTime.set(System.currentTimeMillis());\n            });\n        });\n        thread.start();\n\n        await().until(() -> thread.getState() == State.TIMED_WAITING);\n        Thread.sleep(1000);\n        reentrantLock.unlock();\n\n        await().until(() -> thread.getState() == State.TERMINATED);\n        Assertions.assertTrue(lockTime.get() - startTime > 1000);\n        Assertions.assertTrue(lockTime.get() - startTime < 10000);\n    }\n\n    @RepeatedTest(5)\n    void testInterrupted() throws InterruptedException {\n        ReentrantLock reentrantLock = new ReentrantLock();\n        reentrantLock.lock();\n\n        AtomicLong lockTime = new AtomicLong(0);\n        long startTime = System.currentTimeMillis();\n        Thread thread = new Thread(() -> {\n            Thread.currentThread().interrupt();\n            LockUtils.safeLock(reentrantLock, 10000, () -> {\n                lockTime.set(System.currentTimeMillis());\n            });\n        });\n        thread.start();\n\n        await().until(() -> thread.getState() == State.TERMINATED);\n        Assertions.assertTrue(lockTime.get() >= startTime);\n        Assertions.assertTrue(lockTime.get() - startTime < 10000);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/LogHelperTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.Logger;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass LogHelperTest {\n\n    @Test\n    void testTrace() {\n        Logger logger = Mockito.mock(Logger.class);\n        when(logger.isTraceEnabled()).thenReturn(true);\n        LogHelper.trace(logger, \"trace\");\n        verify(logger).trace(\"trace\");\n        Throwable t = new RuntimeException();\n        LogHelper.trace(logger, t);\n        verify(logger).trace(t);\n        LogHelper.trace(logger, \"trace\", t);\n        verify(logger).trace(\"trace\", t);\n    }\n\n    @Test\n    void testDebug() {\n        Logger logger = Mockito.mock(Logger.class);\n        when(logger.isDebugEnabled()).thenReturn(true);\n        LogHelper.debug(logger, \"debug\");\n        verify(logger).debug(\"debug\");\n        Throwable t = new RuntimeException();\n        LogHelper.debug(logger, t);\n        verify(logger).debug(t);\n        LogHelper.debug(logger, \"debug\", t);\n        verify(logger).debug(\"debug\", t);\n    }\n\n    @Test\n    void testInfo() {\n        Logger logger = Mockito.mock(Logger.class);\n        when(logger.isInfoEnabled()).thenReturn(true);\n        LogHelper.info(logger, \"info\");\n        verify(logger).info(\"info\");\n        Throwable t = new RuntimeException();\n        LogHelper.info(logger, t);\n        verify(logger).info(t);\n        LogHelper.info(logger, \"info\", t);\n        verify(logger).info(\"info\", t);\n    }\n\n    @Test\n    void testWarn() {\n        Logger logger = Mockito.mock(Logger.class);\n        when(logger.isWarnEnabled()).thenReturn(true);\n        LogHelper.warn(logger, \"warn\");\n        verify(logger).warn(\"warn\");\n        Throwable t = new RuntimeException();\n        LogHelper.warn(logger, t);\n        verify(logger).warn(t);\n        LogHelper.warn(logger, \"warn\", t);\n        verify(logger).warn(\"warn\", t);\n    }\n\n    @Test\n    void testError() {\n        Logger logger = Mockito.mock(Logger.class);\n        when(logger.isErrorEnabled()).thenReturn(true);\n        LogHelper.error(logger, \"error\");\n        verify(logger).error(\"error\");\n        Throwable t = new RuntimeException();\n        LogHelper.error(logger, t);\n        verify(logger).error(t);\n        LogHelper.error(logger, \"error\", t);\n        verify(logger).error(\"error\", t);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/LogTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.Level;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\n\nclass LogTest {\n    @Test\n    void testLogName() {\n        Log log1 = new Log();\n        Log log2 = new Log();\n        Log log3 = new Log();\n        log1.setLogName(\"log-name\");\n        log2.setLogName(\"log-name\");\n        log3.setLogName(\"log-name-other\");\n        assertThat(log1.getLogName(), equalTo(\"log-name\"));\n        Assertions.assertEquals(log1, log2);\n        Assertions.assertEquals(log1.hashCode(), log2.hashCode());\n        Assertions.assertNotEquals(log1, log3);\n    }\n\n    @Test\n    void testLogLevel() {\n        Log log1 = new Log();\n        Log log2 = new Log();\n        Log log3 = new Log();\n        log1.setLogLevel(Level.ALL);\n        log2.setLogLevel(Level.ALL);\n        log3.setLogLevel(Level.DEBUG);\n        assertThat(log1.getLogLevel(), is(Level.ALL));\n        Assertions.assertEquals(log1, log2);\n        Assertions.assertEquals(log1.hashCode(), log2.hashCode());\n        Assertions.assertNotEquals(log1, log3);\n    }\n\n    @Test\n    void testLogMessage() {\n        Log log1 = new Log();\n        Log log2 = new Log();\n        Log log3 = new Log();\n        log1.setLogMessage(\"log-message\");\n        log2.setLogMessage(\"log-message\");\n        log3.setLogMessage(\"log-message-other\");\n        assertThat(log1.getLogMessage(), equalTo(\"log-message\"));\n        Assertions.assertEquals(log1, log2);\n        Assertions.assertEquals(log1.hashCode(), log2.hashCode());\n        Assertions.assertNotEquals(log1, log3);\n    }\n\n    @Test\n    void testLogThread() {\n        Log log1 = new Log();\n        Log log2 = new Log();\n        Log log3 = new Log();\n        log1.setLogThread(\"log-thread\");\n        log2.setLogThread(\"log-thread\");\n        log3.setLogThread(\"log-thread-other\");\n        assertThat(log1.getLogThread(), equalTo(\"log-thread\"));\n        Assertions.assertEquals(log1, log2);\n        Assertions.assertEquals(log1.hashCode(), log2.hashCode());\n        Assertions.assertNotEquals(log1, log3);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/LogUtilTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.logger.Level;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass LogUtilTest {\n    @AfterEach\n    public void tearDown() throws Exception {\n        DubboAppender.logList.clear();\n    }\n\n    @Test\n    void testStartStop() {\n        LogUtil.start();\n        assertThat(DubboAppender.available, is(true));\n        LogUtil.stop();\n        assertThat(DubboAppender.available, is(false));\n    }\n\n    @Test\n    void testCheckNoError() {\n        Log log = mock(Log.class);\n        DubboAppender.logList.add(log);\n        when(log.getLogLevel()).thenReturn(Level.ERROR);\n        assertThat(LogUtil.checkNoError(), is(false));\n        when(log.getLogLevel()).thenReturn(Level.INFO);\n        assertThat(LogUtil.checkNoError(), is(true));\n    }\n\n    @Test\n    void testFindName() {\n        Log log = mock(Log.class);\n        DubboAppender.logList.add(log);\n        when(log.getLogName()).thenReturn(\"a\");\n        assertThat(LogUtil.findName(\"a\"), equalTo(1));\n    }\n\n    @Test\n    void testFindLevel() {\n        Log log = mock(Log.class);\n        DubboAppender.logList.add(log);\n        when(log.getLogLevel()).thenReturn(Level.ERROR);\n        assertThat(LogUtil.findLevel(Level.ERROR), equalTo(1));\n        assertThat(LogUtil.findLevel(Level.INFO), equalTo(0));\n    }\n\n    @Test\n    void testFindLevelWithThreadName() {\n        Log log = mock(Log.class);\n        DubboAppender.logList.add(log);\n        when(log.getLogLevel()).thenReturn(Level.ERROR);\n        when(log.getLogThread()).thenReturn(\"thread-1\");\n        log = mock(Log.class);\n        DubboAppender.logList.add(log);\n        when(log.getLogLevel()).thenReturn(Level.ERROR);\n        when(log.getLogThread()).thenReturn(\"thread-2\");\n        assertThat(LogUtil.findLevelWithThreadName(Level.ERROR, \"thread-2\"), equalTo(1));\n    }\n\n    @Test\n    void testFindThread() {\n        Log log = mock(Log.class);\n        DubboAppender.logList.add(log);\n        when(log.getLogThread()).thenReturn(\"thread-1\");\n        assertThat(LogUtil.findThread(\"thread-1\"), equalTo(1));\n    }\n\n    @Test\n    void testFindMessage1() {\n        Log log = mock(Log.class);\n        DubboAppender.logList.add(log);\n        when(log.getLogMessage()).thenReturn(\"message\");\n        assertThat(LogUtil.findMessage(\"message\"), equalTo(1));\n    }\n\n    @Test\n    void testFindMessage2() {\n        Log log = mock(Log.class);\n        DubboAppender.logList.add(log);\n        when(log.getLogMessage()).thenReturn(\"message\");\n        when(log.getLogLevel()).thenReturn(Level.ERROR);\n        log = mock(Log.class);\n        DubboAppender.logList.add(log);\n        when(log.getLogMessage()).thenReturn(\"message\");\n        when(log.getLogLevel()).thenReturn(Level.INFO);\n        assertThat(LogUtil.findMessage(Level.ERROR, \"message\"), equalTo(1));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/MD5UtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nclass MD5UtilsTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(MD5UtilsTest.class);\n\n    @Test\n    void test() {\n        MD5Utils sharedMd5Utils = new MD5Utils();\n        final String[] input = {\n            \"provider-appgroup-one/org.apache.dubbo.config.spring.api.HelloService:dubboorg.apache.dubbo.config.spring.api.HelloService{REGISTRY_CLUSTER=registry-one, anyhost=true, application=provider-app, background=false, compiler=javassist, deprecated=false, dubbo=2.0.2, dynamic=true, file.cache=false, generic=false, group=group-one, interface=org.apache.dubbo.config.spring.api.HelloService, logger=slf4j, metadata-type=remote, methods=sayHello, organization=test, owner=com.test, release=, service-name-mapping=true, side=provider}\",\n            \"provider-appgroup-two/org.apache.dubbo.config.spring.api.DemoService:dubboorg.apache.dubbo.config.spring.api.DemoService{REGISTRY_CLUSTER=registry-two, anyhost=true, application=provider-app, background=false, compiler=javassist, deprecated=false, dubbo=2.0.2, dynamic=true, file.cache=false, generic=false, group=group-two, interface=org.apache.dubbo.config.spring.api.DemoService, logger=slf4j, metadata-type=remote, methods=sayName,getBox, organization=test, owner=com.test, release=, service-name-mapping=true, side=provider}\"\n        };\n        final String[] result = {sharedMd5Utils.getMd5(input[0]), new MD5Utils().getMd5(input[1])};\n\n        logger.info(\"Expected result: {}\", Arrays.asList(result));\n        int nThreads = 8;\n        CountDownLatch latch = new CountDownLatch(nThreads);\n        List<Throwable> errors = Collections.synchronizedList(new ArrayList<>());\n        ExecutorService executorService = Executors.newFixedThreadPool(nThreads);\n        try {\n\n            for (int i = 0; i < nThreads; i++) {\n                MD5Utils md5Utils = i < nThreads / 2 ? sharedMd5Utils : new MD5Utils();\n                executorService.submit(new Md5Task(input[i % 2], result[i % 2], md5Utils, latch, errors));\n            }\n            latch.await();\n            Assertions.assertEquals(Collections.EMPTY_LIST, errors);\n            Assertions.assertEquals(0, latch.getCount());\n        } catch (Throwable e) {\n            Assertions.fail(StringUtils.toString(e));\n        } finally {\n            executorService.shutdown();\n        }\n    }\n\n    static class Md5Task implements Runnable {\n\n        private final String input;\n        private final String expected;\n        private final MD5Utils md5Utils;\n        private final CountDownLatch latch;\n        private final List<Throwable> errorCollector;\n\n        public Md5Task(\n                String input,\n                String expected,\n                MD5Utils md5Utils,\n                CountDownLatch latch,\n                List<Throwable> errorCollector) {\n            this.input = input;\n            this.expected = expected;\n            this.md5Utils = md5Utils;\n            this.latch = latch;\n            this.errorCollector = errorCollector;\n        }\n\n        @Override\n        public void run() {\n            int i = 0;\n            long start = System.currentTimeMillis();\n            try {\n                for (; i < 200; i++) {\n                    Assertions.assertEquals(expected, md5Utils.getMd5(input));\n                    md5Utils.getMd5(\"test#\" + i);\n                }\n            } catch (Throwable e) {\n                errorCollector.add(e);\n                e.printStackTrace();\n            } finally {\n                long cost = System.currentTimeMillis() - start;\n                logger.info(\n                        \"[{}] progress: {}, cost: {}\", Thread.currentThread().getName(), i, cost);\n                latch.countDown();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/MemberUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.utils.MemberUtils.isPrivate;\nimport static org.apache.dubbo.common.utils.MemberUtils.isPublic;\nimport static org.apache.dubbo.common.utils.MemberUtils.isStatic;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link MemberUtils} Test\n *\n * @since 2.7.6\n */\nclass MemberUtilsTest {\n\n    @Test\n    void test() throws NoSuchMethodException {\n\n        assertFalse(isStatic(getClass().getMethod(\"noStatic\")));\n        assertTrue(isStatic(getClass().getMethod(\"staticMethod\")));\n        assertTrue(isPrivate(getClass().getDeclaredMethod(\"privateMethod\")));\n        assertTrue(isPublic(getClass().getMethod(\"publicMethod\")));\n    }\n\n    public void noStatic() {}\n\n    public static void staticMethod() {}\n\n    private void privateMethod() {}\n\n    public void publicMethod() {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/MethodComparatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass MethodComparatorTest {\n\n    // The test methods: we use interface since\n    // It is the fastest way compared to class\n    // which will need the curly braces\n    interface TestInterface {\n        void a();\n\n        void b();\n\n        void c(int i);\n\n        void c(int i, int j);\n\n        void d(Integer i);\n\n        void d(String s);\n    }\n\n    @Test\n    void testCompare() throws Exception {\n        MethodComparator comparator = MethodComparator.INSTANCE;\n\n        // Grab the Methods usind the Reflection\n        Method a = TestInterface.class.getMethod(\"a\");\n        Method b = TestInterface.class.getMethod(\"b\");\n        Method c1 = TestInterface.class.getMethod(\"c\", int.class);\n        Method c2 = TestInterface.class.getMethod(\"c\", int.class, int.class);\n        Method dInt = TestInterface.class.getMethod(\"d\", Integer.class);\n        Method dStr = TestInterface.class.getMethod(\"d\", String.class);\n\n        // 1: Test Equals(The \"Safety\")\n        assertEquals(0, comparator.compare(a, a));\n\n        // 2:Names (a comes b4 b)\n        assertTrue(comparator.compare(a, b) < 0);\n        assertTrue(comparator.compare(b, a) > 0);\n\n        // 3: Parameter count example for c1 and c2 method names are similar\n        // so we check number of parameters\n        assertTrue(comparator.compare(c1, c2) < 0);\n\n        // 4: Parameter types eg Integer vs String\n        // this is when they have same number of parameters\n        assertTrue(comparator.compare(dInt, dStr) < 0);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/MethodUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.utils.MethodUtils.excludedDeclaredClass;\nimport static org.apache.dubbo.common.utils.MethodUtils.findMethod;\nimport static org.apache.dubbo.common.utils.MethodUtils.findNearestOverriddenMethod;\nimport static org.apache.dubbo.common.utils.MethodUtils.findOverriddenMethod;\nimport static org.apache.dubbo.common.utils.MethodUtils.getAllDeclaredMethods;\nimport static org.apache.dubbo.common.utils.MethodUtils.getAllMethods;\nimport static org.apache.dubbo.common.utils.MethodUtils.getDeclaredMethods;\nimport static org.apache.dubbo.common.utils.MethodUtils.getMethods;\nimport static org.apache.dubbo.common.utils.MethodUtils.invokeMethod;\nimport static org.apache.dubbo.common.utils.MethodUtils.overrides;\n\nclass MethodUtilsTest {\n\n    @Test\n    void testGetMethod() {\n        Method getMethod = null;\n        for (Method method : MethodTestClazz.class.getMethods()) {\n            if (MethodUtils.isGetter(method)) {\n                getMethod = method;\n            }\n        }\n        Assertions.assertNotNull(getMethod);\n        Assertions.assertEquals(\"getValue\", getMethod.getName());\n    }\n\n    @Test\n    void testSetMethod() {\n        Method setMethod = null;\n        for (Method method : MethodTestClazz.class.getMethods()) {\n            if (MethodUtils.isSetter(method)) {\n                setMethod = method;\n            }\n        }\n        Assertions.assertNotNull(setMethod);\n        Assertions.assertEquals(\"setValue\", setMethod.getName());\n    }\n\n    @Test\n    void testIsDeprecated() throws Exception {\n        Assertions.assertTrue(MethodUtils.isDeprecated(MethodTestClazz.class.getMethod(\"deprecatedMethod\")));\n        Assertions.assertFalse(MethodUtils.isDeprecated(MethodTestClazz.class.getMethod(\"getValue\")));\n    }\n\n    @Test\n    void testIsMetaMethod() {\n        boolean containMetaMethod = false;\n        for (Method method : MethodTestClazz.class.getMethods()) {\n            if (MethodUtils.isMetaMethod(method)) {\n                containMetaMethod = true;\n            }\n        }\n        Assertions.assertTrue(containMetaMethod);\n    }\n\n    @Test\n    void testGetMethods() throws NoSuchMethodException {\n        Assertions.assertTrue(getDeclaredMethods(MethodTestClazz.class, excludedDeclaredClass(String.class))\n                        .size()\n                > 0);\n        Assertions.assertTrue(getMethods(MethodTestClazz.class).size() > 0);\n        Assertions.assertTrue(getAllDeclaredMethods(MethodTestClazz.class).size() > 0);\n        Assertions.assertTrue(getAllMethods(MethodTestClazz.class).size() > 0);\n        Assertions.assertNotNull(findMethod(MethodTestClazz.class, \"getValue\"));\n\n        MethodTestClazz methodTestClazz = new MethodTestClazz();\n        invokeMethod(methodTestClazz, \"setValue\", \"Test\");\n        Assertions.assertEquals(methodTestClazz.getValue(), \"Test\");\n\n        Assertions.assertTrue(\n                overrides(MethodOverrideClazz.class.getMethod(\"get\"), MethodTestClazz.class.getMethod(\"get\")));\n        Assertions.assertEquals(\n                findNearestOverriddenMethod(MethodOverrideClazz.class.getMethod(\"get\")),\n                MethodTestClazz.class.getMethod(\"get\"));\n        Assertions.assertEquals(\n                findOverriddenMethod(MethodOverrideClazz.class.getMethod(\"get\"), MethodOverrideClazz.class),\n                MethodTestClazz.class.getMethod(\"get\"));\n    }\n\n    @Test\n    void testExtractFieldName() throws Exception {\n        Method m1 = MethodFieldTestClazz.class.getMethod(\"is\");\n        Method m2 = MethodFieldTestClazz.class.getMethod(\"get\");\n        Method m3 = MethodFieldTestClazz.class.getMethod(\"getClass\");\n        Method m4 = MethodFieldTestClazz.class.getMethod(\"getObject\");\n        Method m5 = MethodFieldTestClazz.class.getMethod(\"getFieldName1\");\n        Method m6 = MethodFieldTestClazz.class.getMethod(\"setFieldName2\");\n        Method m7 = MethodFieldTestClazz.class.getMethod(\"isFieldName3\");\n\n        Assertions.assertEquals(\"\", MethodUtils.extractFieldName(m1));\n        Assertions.assertEquals(\"\", MethodUtils.extractFieldName(m2));\n        Assertions.assertEquals(\"\", MethodUtils.extractFieldName(m3));\n        Assertions.assertEquals(\"\", MethodUtils.extractFieldName(m4));\n        Assertions.assertEquals(\"fieldName1\", MethodUtils.extractFieldName(m5));\n        Assertions.assertEquals(\"fieldName2\", MethodUtils.extractFieldName(m6));\n        Assertions.assertEquals(\"fieldName3\", MethodUtils.extractFieldName(m7));\n    }\n\n    public class MethodFieldTestClazz {\n        public String is() {\n            return \"\";\n        }\n\n        public String get() {\n            return \"\";\n        }\n\n        public String getObject() {\n            return \"\";\n        }\n\n        public String getFieldName1() {\n            return \"\";\n        }\n\n        public String setFieldName2() {\n            return \"\";\n        }\n\n        public String isFieldName3() {\n            return \"\";\n        }\n    }\n\n    public class MethodTestClazz {\n        private String value;\n\n        public String getValue() {\n            return value;\n        }\n\n        public void setValue(String value) {\n            this.value = value;\n        }\n\n        public MethodTestClazz get() {\n            return this;\n        }\n\n        @Deprecated\n        public Boolean deprecatedMethod() {\n            return true;\n        }\n    }\n\n    public class MethodOverrideClazz extends MethodTestClazz {\n        @Override\n        public MethodTestClazz get() {\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/MyEnum.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\n/**\n * MyEnum\n */\npublic enum MyEnum {\n    A,\n    B\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/NamedThreadFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.allOf;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass NamedThreadFactoryTest {\n\n    private static final int INITIAL_THREAD_NUM = 1;\n\n    @Test\n    void testNewThread() {\n        NamedThreadFactory factory = new NamedThreadFactory();\n        Thread t = factory.newThread(Mockito.mock(Runnable.class));\n        assertThat(t.getName(), allOf(containsString(\"pool-\"), containsString(\"-thread-\")));\n        assertFalse(t.isDaemon());\n        // since security manager is not installed.\n        assertSame(t.getThreadGroup(), Thread.currentThread().getThreadGroup());\n    }\n\n    @Test\n    void testPrefixAndDaemon() {\n        NamedThreadFactory factory = new NamedThreadFactory(\"prefix\", true);\n        Thread t = factory.newThread(Mockito.mock(Runnable.class));\n        assertThat(t.getName(), allOf(containsString(\"prefix-\"), containsString(\"-thread-\")));\n        assertTrue(t.isDaemon());\n    }\n\n    @Test\n    public void testGetThreadNum() {\n        NamedThreadFactory threadFactory = new NamedThreadFactory();\n        AtomicInteger threadNum = threadFactory.getThreadNum();\n        assertNotNull(threadNum);\n        assertEquals(INITIAL_THREAD_NUM, threadNum.get());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/NetUtilsInterfaceDisplayNameHasMetaCharactersTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\n\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.util.Enumeration;\nimport java.util.NoSuchElementException;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass NetUtilsInterfaceDisplayNameHasMetaCharactersTest {\n    private static final String IGNORED_DISPLAY_NAME_HAS_METACHARACTERS = \"Mock(R) ^$*+[?].|-[0-9] Adapter\";\n    private static final String SELECTED_DISPLAY_NAME = \"Selected Adapter\";\n    private static final String SELECTED_HOST_ADDR = \"192.168.0.1\";\n\n    @Test\n    void testIgnoreGivenInterfaceNameWithMetaCharacters() throws Exception {\n        String originIgnoredInterfaces = this.getIgnoredInterfaces();\n        // mock static methods of final class NetworkInterface\n        try (MockedStatic<NetworkInterface> mockedStaticNetif = Mockito.mockStatic(NetworkInterface.class)) {\n            NetworkInterface mockIgnoredNetif = Mockito.mock(NetworkInterface.class);\n            NetworkInterface mockSelectedNetif = Mockito.mock(NetworkInterface.class);\n            NetworkInterface[] mockNetifs = {mockIgnoredNetif, mockSelectedNetif};\n            Enumeration<NetworkInterface> mockEnumIfs = new Enumeration<NetworkInterface>() {\n                private int i = 0;\n\n                public NetworkInterface nextElement() {\n                    if (mockNetifs != null && i < mockNetifs.length) {\n                        NetworkInterface netif = mockNetifs[i++];\n                        return netif;\n                    } else {\n                        throw new NoSuchElementException();\n                    }\n                }\n\n                public boolean hasMoreElements() {\n                    return (mockNetifs != null && i < mockNetifs.length);\n                }\n            };\n\n            InetAddress mockSelectedAddr = Mockito.mock(InetAddress.class);\n            InetAddress[] mockAddrs = {mockSelectedAddr};\n            Enumeration<InetAddress> mockEnumAddrs = new Enumeration<InetAddress>() {\n                private int i = 0;\n\n                public InetAddress nextElement() {\n                    if (mockAddrs != null && i < mockAddrs.length) {\n                        InetAddress addr = mockAddrs[i++];\n                        return addr;\n                    } else {\n                        throw new NoSuchElementException();\n                    }\n                }\n\n                public boolean hasMoreElements() {\n                    return (mockAddrs != null && i < mockAddrs.length);\n                }\n            };\n\n            // mock static method getNetworkInterfaces\n            mockedStaticNetif\n                    .when(() -> {\n                        NetworkInterface.getNetworkInterfaces();\n                    })\n                    .thenReturn(mockEnumIfs);\n\n            Mockito.when(mockIgnoredNetif.isUp()).thenReturn(true);\n            Mockito.when(mockIgnoredNetif.getDisplayName()).thenReturn(IGNORED_DISPLAY_NAME_HAS_METACHARACTERS);\n\n            Mockito.when(mockSelectedNetif.isUp()).thenReturn(true);\n            Mockito.when(mockSelectedNetif.getDisplayName()).thenReturn(SELECTED_DISPLAY_NAME);\n            Mockito.when(mockSelectedNetif.getInetAddresses()).thenReturn(mockEnumAddrs);\n\n            Mockito.when(mockSelectedAddr.isLoopbackAddress()).thenReturn(false);\n            Mockito.when(mockSelectedAddr.getHostAddress()).thenReturn(SELECTED_HOST_ADDR);\n            Mockito.when(mockSelectedAddr.isReachable(Mockito.anyInt())).thenReturn(true);\n\n            this.setIgnoredInterfaces(IGNORED_DISPLAY_NAME_HAS_METACHARACTERS);\n            NetworkInterface newNetworkInterface = NetUtils.findNetworkInterface();\n            assertTrue(!IGNORED_DISPLAY_NAME_HAS_METACHARACTERS.equals(newNetworkInterface.getDisplayName()));\n        } finally {\n            // recover the origin ignored interfaces\n            this.setIgnoredInterfaces(originIgnoredInterfaces);\n        }\n    }\n\n    private String getIgnoredInterfaces() {\n        return SystemPropertyConfigUtils.getSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_NETWORK_IGNORED_INTERFACE);\n    }\n\n    private void setIgnoredInterfaces(String ignoredInterfaces) {\n        if (ignoredInterfaces != null) {\n            SystemPropertyConfigUtils.setSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_NETWORK_IGNORED_INTERFACE, ignoredInterfaces);\n        } else {\n            SystemPropertyConfigUtils.setSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_NETWORK_IGNORED_INTERFACE, \"\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/NetUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\n\nimport java.io.IOException;\nimport java.net.Inet6Address;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.NetworkInterface;\nimport java.net.ServerSocket;\nimport java.net.UnknownHostException;\nimport java.util.regex.Pattern;\n\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.greaterThan;\nimport static org.hamcrest.Matchers.greaterThanOrEqualTo;\nimport static org.junit.jupiter.api.Assertions.assertDoesNotThrow;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assumptions.assumeTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass NetUtilsTest {\n\n    @Test\n    void testGetRandomPort() {\n        assertThat(NetUtils.getRandomPort(), greaterThanOrEqualTo(30000));\n        assertThat(NetUtils.getRandomPort(), greaterThanOrEqualTo(30000));\n        assertThat(NetUtils.getRandomPort(), greaterThanOrEqualTo(30000));\n    }\n\n    @Test\n    void testGetAvailablePort() {\n        assertThat(NetUtils.getAvailablePort(), greaterThan(0));\n        assertThat(NetUtils.getAvailablePort(12345), greaterThanOrEqualTo(12345));\n        assertThat(NetUtils.getAvailablePort(-1), greaterThanOrEqualTo(0));\n    }\n\n    @Test\n    void testValidAddress() {\n        assertTrue(NetUtils.isValidAddress(\"10.20.130.230:20880\"));\n        assertFalse(NetUtils.isValidAddress(\"10.20.130.230\"));\n        assertFalse(NetUtils.isValidAddress(\"10.20.130.230:666666\"));\n        assertFalse(NetUtils.isValidAddress(\"127.0.1:8080\"));\n        assertFalse(NetUtils.isValidAddress(\"127.0.0.0.1:8080\"));\n        assertFalse(NetUtils.isValidAddress(\"127.a.0.1:8080\"));\n        assertFalse(NetUtils.isValidAddress(\"127.0.0.1:80a\"));\n        assertFalse(NetUtils.isValidAddress(\"127.0.0.-1:8080\"));\n    }\n\n    @Test\n    void testIsInvalidPort() {\n        assertTrue(NetUtils.isInvalidPort(0));\n        assertTrue(NetUtils.isInvalidPort(65536));\n        assertFalse(NetUtils.isInvalidPort(1024));\n    }\n\n    @Test\n    void testIsLocalHost() {\n        assertTrue(NetUtils.isLocalHost(\"localhost\"));\n        assertTrue(NetUtils.isLocalHost(\"127.1.2.3\"));\n        assertFalse(NetUtils.isLocalHost(\"128.1.2.3\"));\n    }\n\n    @Test\n    void testIsAnyHost() {\n        assertTrue(NetUtils.isAnyHost(\"0.0.0.0\"));\n        assertFalse(NetUtils.isAnyHost(\"1.1.1.1\"));\n    }\n\n    @Test\n    void testIsInvalidLocalHost() {\n        assertTrue(NetUtils.isInvalidLocalHost(null));\n        assertTrue(NetUtils.isInvalidLocalHost(\"\"));\n        assertTrue(NetUtils.isInvalidLocalHost(\"localhost\"));\n        assertTrue(NetUtils.isInvalidLocalHost(\"0.0.0.0\"));\n        assertTrue(NetUtils.isInvalidLocalHost(\"127.1.2.3\"));\n        assertTrue(NetUtils.isInvalidLocalHost(\"127.0.0.1\"));\n        assertFalse(NetUtils.isInvalidLocalHost(\"128.0.0.1\"));\n    }\n\n    @Test\n    void testIsValidLocalHost() {\n        assertTrue(NetUtils.isValidLocalHost(\"1.2.3.4\"));\n        assertTrue(NetUtils.isValidLocalHost(\"128.0.0.1\"));\n    }\n\n    @Test\n    void testGetLocalSocketAddress() {\n        InetSocketAddress address = NetUtils.getLocalSocketAddress(\"localhost\", 12345);\n        assertTrue(address.getAddress().isAnyLocalAddress());\n        assertEquals(address.getPort(), 12345);\n        address = NetUtils.getLocalSocketAddress(\"dubbo-addr\", 12345);\n        assertEquals(address.getHostName(), \"dubbo-addr\");\n        assertEquals(address.getPort(), 12345);\n    }\n\n    @Test\n    void testIsValidAddress() {\n        assertFalse(NetUtils.isValidV4Address((InetAddress) null));\n        InetAddress address = mock(InetAddress.class);\n        when(address.isLoopbackAddress()).thenReturn(true);\n        assertFalse(NetUtils.isValidV4Address(address));\n        address = mock(InetAddress.class);\n        when(address.isLinkLocalAddress()).thenReturn(true);\n        assertFalse(NetUtils.isValidV4Address(address));\n        address = mock(InetAddress.class);\n        when(address.getHostAddress()).thenReturn(\"localhost\");\n        assertFalse(NetUtils.isValidV4Address(address));\n        address = mock(InetAddress.class);\n        when(address.getHostAddress()).thenReturn(\"0.0.0.0\");\n        assertFalse(NetUtils.isValidV4Address(address));\n        address = mock(InetAddress.class);\n        when(address.getHostAddress()).thenReturn(\"127.0.0.1\");\n        assertFalse(NetUtils.isValidV4Address(address));\n        address = mock(InetAddress.class);\n        when(address.getHostAddress()).thenReturn(\"1.2.3.4\");\n        assertTrue(NetUtils.isValidV4Address(address));\n    }\n\n    @Test\n    void testGetLocalHost() {\n        assertNotNull(NetUtils.getLocalHost());\n    }\n\n    @Test\n    void testGetLocalAddress() {\n        InetAddress address = NetUtils.getLocalAddress();\n        assertNotNull(address);\n        assertTrue(NetUtils.isValidLocalHost(address.getHostAddress()));\n    }\n\n    @Test\n    void testFilterLocalHost() {\n        assertNull(NetUtils.filterLocalHost(null));\n        assertEquals(NetUtils.filterLocalHost(\"\"), \"\");\n        String host = NetUtils.filterLocalHost(\"dubbo://127.0.0.1:8080/foo\");\n        assertThat(host, equalTo(\"dubbo://\" + NetUtils.getLocalHost() + \":8080/foo\"));\n        host = NetUtils.filterLocalHost(\"127.0.0.1:8080\");\n        assertThat(host, equalTo(NetUtils.getLocalHost() + \":8080\"));\n        host = NetUtils.filterLocalHost(\"0.0.0.0\");\n        assertThat(host, equalTo(NetUtils.getLocalHost()));\n        host = NetUtils.filterLocalHost(\"88.88.88.88\");\n        assertThat(host, equalTo(host));\n    }\n\n    @Test\n    void testGetHostName() {\n        assertNotNull(NetUtils.getHostName(\"127.0.0.1\"));\n    }\n\n    @Test\n    void testGetIpByHost() {\n        assertThat(NetUtils.getIpByHost(\"localhost\"), equalTo(\"127.0.0.1\"));\n        assertThat(NetUtils.getIpByHost(\"dubbo.local\"), equalTo(\"dubbo.local\"));\n    }\n\n    @Test\n    void testToAddressString() {\n        InetAddress address = mock(InetAddress.class);\n        when(address.getHostAddress()).thenReturn(\"dubbo\");\n        InetSocketAddress socketAddress = new InetSocketAddress(address, 1234);\n        assertThat(NetUtils.toAddressString(socketAddress), equalTo(\"dubbo:1234\"));\n    }\n\n    @Test\n    void testToAddress() {\n        InetSocketAddress address = NetUtils.toAddress(\"localhost:1234\");\n        assertThat(address.getHostName(), equalTo(\"localhost\"));\n        assertThat(address.getPort(), equalTo(1234));\n        address = NetUtils.toAddress(\"localhost\");\n        assertThat(address.getHostName(), equalTo(\"localhost\"));\n        assertThat(address.getPort(), equalTo(0));\n        assertThrows(NumberFormatException.class, () -> {\n            NetUtils.toAddress(\"127.0.0.1:abc\");\n        });\n    }\n\n    @Test\n    void testToURL() {\n        String url = NetUtils.toURL(\"dubbo\", \"host\", 1234, \"foo\");\n        assertThat(url, equalTo(\"dubbo://host:1234/foo\"));\n    }\n\n    @Test\n    void testIsValidV6Address() {\n        String saved = System.getProperty(\"java.net.preferIPv6Addresses\", \"false\");\n        System.setProperty(\"java.net.preferIPv6Addresses\", \"true\");\n\n        InetAddress address = NetUtils.getLocalAddress();\n        boolean isPreferIPV6Address = NetUtils.isPreferIPV6Address();\n\n        // Restore system property to previous value before executing test\n        System.setProperty(\"java.net.preferIPv6Addresses\", saved);\n\n        assumeTrue(address instanceof Inet6Address);\n        assertThat(isPreferIPV6Address, equalTo(true));\n    }\n\n    /**\n     * Mockito starts to support mocking final classes since 2.1.0\n     * see https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#unmockable\n     * But enable it will cause other UT to fail.\n     * Therefore, currently disabling this UT.\n     */\n    @Disabled\n    @Test\n    void testNormalizeV6Address() {\n        Inet6Address address = mock(Inet6Address.class);\n        when(address.getHostAddress()).thenReturn(\"fe80:0:0:0:894:aeec:f37d:23e1%en0\");\n        when(address.getScopeId()).thenReturn(5);\n        InetAddress normalized = NetUtils.normalizeV6Address(address);\n        assertThat(normalized.getHostAddress(), equalTo(\"fe80:0:0:0:894:aeec:f37d:23e1%5\"));\n    }\n\n    // ================================\n    // IPv6 normalization and testcases\n    // ================================\n\n    @Test\n    void testNormalizeIpv6WithoutScope() throws UnknownHostException {\n        Inet6Address input = (Inet6Address) InetAddress.getByName(\"2001:db8::1\");\n\n        InetAddress result = NetUtils.normalizeV6Address(input);\n\n        assertEquals(input.getHostAddress(), result.getHostAddress());\n    }\n    // NOTE:\n    // Scope-name normalization logic is covered by testNormalizeV6Address,\n    // which is currently @Disabled due to Mockito final-class limitations.\n    // These tests focus on CI-safe behavior over hacky way around.\n\n    @Test\n    void testMatchIpExpressionWithIpv6Pattern() throws UnknownHostException {\n        String pattern = \"2001:db8::/64\";\n        String host = \"2001:db8::1\";\n        assertTrue(NetUtils.matchIpExpression(pattern, host, 90));\n    }\n\n    @Test\n    void testMatchIPv6WildcardUnsupported() throws UnknownHostException {\n        String pattern = \"2001:db8::*\";\n        String host = \"2001:db8::1\";\n        assertThrows(IllegalArgumentException.class, () -> NetUtils.matchIpExpression(pattern, host, 90));\n    }\n\n    @Test\n    void testMatchIPv4PatternIPv6Host() throws IllegalArgumentException {\n        String pattern = \"127.0.0.1\";\n        String host = \"::1\";\n\n        assertThrows(IllegalArgumentException.class, () -> NetUtils.matchIpExpression(pattern, host, 90));\n    }\n\n    @Test\n    void testValidIpv6EdgeCases() {\n        assertDoesNotThrow(() -> InetAddress.getByName(\"::\"));\n        assertDoesNotThrow(() -> InetAddress.getByName(\"::1\"));\n        assertDoesNotThrow(() -> InetAddress.getByName(\"2001:db8::\"));\n    }\n\n    @Test\n    void testInvalidIpv6EdgeCases() {\n        assertThrows(UnknownHostException.class, () -> InetAddress.getByName(\"1:2:3:4:5:6:7:8:9\"));\n\n        assertThrows(UnknownHostException.class, () -> InetAddress.getByName(\"2001:db8::zzzz\"));\n\n        assertThrows(UnknownHostException.class, () -> InetAddress.getByName(\"2001:db8::192.168.1\"));\n    }\n\n    @Test\n    void testMatchIpRangeMatchWhenIpv4() throws UnknownHostException {\n        assertTrue(NetUtils.matchIpRange(\"*.*.*.*\", \"192.168.1.63\", 90));\n        assertTrue(NetUtils.matchIpRange(\"192.168.1.*\", \"192.168.1.63\", 90));\n        assertTrue(NetUtils.matchIpRange(\"192.168.1.63\", \"192.168.1.63\", 90));\n        assertTrue(NetUtils.matchIpRange(\"192.168.1.1-65\", \"192.168.1.63\", 90));\n        assertFalse(NetUtils.matchIpRange(\"192.168.1.1-61\", \"192.168.1.63\", 90));\n        assertFalse(NetUtils.matchIpRange(\"192.168.1.62\", \"192.168.1.63\", 90));\n    }\n\n    @Test\n    void testMatchIpRangeMatchWhenIpv6() throws UnknownHostException {\n        assertTrue(NetUtils.matchIpRange(\"*.*.*.*\", \"192.168.1.63\", 90));\n        assertTrue(NetUtils.matchIpRange(\"234e:0:4567:0:0:0:3d:*\", \"234e:0:4567::3d:ff\", 90));\n        assertTrue(NetUtils.matchIpRange(\"234e:0:4567:0:0:0:3d:ee\", \"234e:0:4567::3d:ee\", 90));\n        assertTrue(NetUtils.matchIpRange(\"234e:0:4567::3d:ee\", \"234e:0:4567::3d:ee\", 90));\n        assertTrue(NetUtils.matchIpRange(\"234e:0:4567:0:0:0:3d:0-ff\", \"234e:0:4567::3d:ee\", 90));\n        assertTrue(NetUtils.matchIpRange(\"234e:0:4567:0:0:0:3d:0-ee\", \"234e:0:4567::3d:ee\", 90));\n\n        assertFalse(NetUtils.matchIpRange(\"234e:0:4567:0:0:0:3d:ff\", \"234e:0:4567::3d:ee\", 90));\n        assertFalse(NetUtils.matchIpRange(\"234e:0:4567:0:0:0:3d:0-ea\", \"234e:0:4567::3d:ee\", 90));\n    }\n\n    @Test\n    void testMatchIpRangeMatchWhenIpv6Exception() {\n        IllegalArgumentException thrown = assertThrows(\n                IllegalArgumentException.class,\n                () -> NetUtils.matchIpRange(\"234e:0:4567::3d:*\", \"234e:0:4567::3d:ff\", 90));\n        assertTrue(thrown.getMessage().contains(\"If you config ip expression that contains '*'\"));\n\n        thrown = assertThrows(\n                IllegalArgumentException.class,\n                () -> NetUtils.matchIpRange(\"234e:0:4567:3d\", \"234e:0:4567::3d:ff\", 90));\n        assertTrue(thrown.getMessage().contains(\"The host is ipv6, but the pattern is not ipv6 pattern\"));\n\n        thrown = assertThrows(\n                IllegalArgumentException.class, () -> NetUtils.matchIpRange(\"192.168.1.1-65-3\", \"192.168.1.63\", 90));\n        assertTrue(thrown.getMessage().contains(\"There is wrong format of ip Address\"));\n    }\n\n    @Test\n    void testMatchIpRangeMatchWhenIpWrongException() {\n        UnknownHostException thrown = assertThrows(\n                UnknownHostException.class, () -> NetUtils.matchIpRange(\"192.168.1.63\", \"192.168.1.ff\", 90));\n        assertTrue(thrown.getMessage().contains(\"192.168.1.ff\"));\n    }\n\n    @Test\n    void testMatchIpMatch() throws UnknownHostException {\n        assertTrue(NetUtils.matchIpExpression(\"192.168.1.*\", \"192.168.1.63\", 90));\n        assertTrue(NetUtils.matchIpExpression(\"192.168.1.192/26\", \"192.168.1.199\", 90));\n    }\n\n    @Test\n    void testMatchIpv6WithIpPort() throws UnknownHostException {\n        assertTrue(NetUtils.matchIpRange(\"[234e:0:4567::3d:ee]\", \"234e:0:4567::3d:ee\", 8090));\n        assertTrue(NetUtils.matchIpRange(\"[234e:0:4567:0:0:0:3d:ee]\", \"234e:0:4567::3d:ee\", 8090));\n        assertTrue(NetUtils.matchIpRange(\"[234e:0:4567:0:0:0:3d:ee]:8090\", \"234e:0:4567::3d:ee\", 8090));\n        assertTrue(NetUtils.matchIpRange(\"[234e:0:4567:0:0:0:3d:0-ee]:8090\", \"234e:0:4567::3d:ee\", 8090));\n        assertTrue(NetUtils.matchIpRange(\"[234e:0:4567:0:0:0:3d:ee-ff]:8090\", \"234e:0:4567::3d:ee\", 8090));\n        assertTrue(NetUtils.matchIpRange(\"[234e:0:4567:0:0:0:3d:*]:90\", \"234e:0:4567::3d:ff\", 90));\n\n        assertFalse(NetUtils.matchIpRange(\"[234e:0:4567:0:0:0:3d:ee]:7289\", \"234e:0:4567::3d:ee\", 8090));\n        assertFalse(NetUtils.matchIpRange(\"[234e:0:4567:0:0:0:3d:ee-ff]:8090\", \"234e:0:4567::3d:ee\", 9090));\n    }\n\n    @Test\n    void testMatchIpv4WithIpPort() throws UnknownHostException {\n        NumberFormatException thrown = assertThrows(\n                NumberFormatException.class,\n                () -> NetUtils.matchIpExpression(\"192.168.1.192/26:90\", \"192.168.1.199\", 90));\n        assertTrue(thrown instanceof NumberFormatException);\n\n        assertTrue(NetUtils.matchIpRange(\"*.*.*.*:90\", \"192.168.1.63\", 90));\n        assertTrue(NetUtils.matchIpRange(\"192.168.1.*:90\", \"192.168.1.63\", 90));\n        assertTrue(NetUtils.matchIpRange(\"192.168.1.63:90\", \"192.168.1.63\", 90));\n        assertTrue(NetUtils.matchIpRange(\"192.168.1.63-65:90\", \"192.168.1.63\", 90));\n        assertTrue(NetUtils.matchIpRange(\"192.168.1.1-63:90\", \"192.168.1.63\", 90));\n\n        assertFalse(NetUtils.matchIpRange(\"*.*.*.*:80\", \"192.168.1.63\", 90));\n        assertFalse(NetUtils.matchIpRange(\"192.168.1.*:80\", \"192.168.1.63\", 90));\n        assertFalse(NetUtils.matchIpRange(\"192.168.1.63:80\", \"192.168.1.63\", 90));\n        assertFalse(NetUtils.matchIpRange(\"192.168.1.63-65:80\", \"192.168.1.63\", 90));\n        assertFalse(NetUtils.matchIpRange(\"192.168.1.1-63:80\", \"192.168.1.63\", 90));\n\n        assertFalse(NetUtils.matchIpRange(\"192.168.1.1-61:90\", \"192.168.1.62\", 90));\n        assertFalse(NetUtils.matchIpRange(\"192.168.1.62:90\", \"192.168.1.63\", 90));\n    }\n\n    @Test\n    void testLocalHost() {\n        assertEquals(NetUtils.getLocalHost(), NetUtils.getLocalAddress().getHostAddress());\n        assertTrue(NetUtils.isValidLocalHost(NetUtils.getLocalHost()));\n        assertFalse(NetUtils.isInvalidLocalHost(NetUtils.getLocalHost()));\n    }\n\n    @Test\n    void testIsMulticastAddress() {\n        assertTrue(NetUtils.isMulticastAddress(\"224.0.0.1\"));\n        assertTrue(NetUtils.isMulticastAddress(\"224.0.0.0\"));\n        assertTrue(NetUtils.isMulticastAddress(\"239.255.255.255\"));\n        assertFalse(NetUtils.isMulticastAddress(\"223.255.255.255\"));\n        assertFalse(NetUtils.isMulticastAddress(\"240.0.0.0\"));\n        assertFalse(NetUtils.isMulticastAddress(\"127.0.0.1\"));\n        assertFalse(NetUtils.isMulticastAddress(\"abc.0.0.1\"));\n        assertFalse(NetUtils.isMulticastAddress(\"localhost\"));\n    }\n\n    @Test\n    void testFindNetworkInterface() {\n        assertNotNull(NetUtils.findNetworkInterface());\n    }\n\n    @Test\n    void testIgnoreAllInterfaces() {\n        // store the origin ignored interfaces\n        String originIgnoredInterfaces = this.getIgnoredInterfaces();\n        try {\n            // ignore all interfaces\n            this.setIgnoredInterfaces(\".*\");\n            assertNull(NetUtils.findNetworkInterface());\n        } finally {\n            // recover the origin ignored interfaces\n            this.setIgnoredInterfaces(originIgnoredInterfaces);\n        }\n    }\n\n    @Test\n    void testIgnoreGivenInterface() {\n        // store the origin ignored interfaces\n        String originIgnoredInterfaces = this.getIgnoredInterfaces();\n        try {\n            NetworkInterface networkInterface = NetUtils.findNetworkInterface();\n            assertNotNull(networkInterface);\n            // ignore the given network interface's display name\n            this.setIgnoredInterfaces(Pattern.quote(networkInterface.getDisplayName()));\n            NetworkInterface newNetworkInterface = NetUtils.findNetworkInterface();\n            if (newNetworkInterface != null) {\n                assertTrue(!networkInterface.getDisplayName().equals(newNetworkInterface.getDisplayName()));\n            }\n        } finally {\n            // recover the origin ignored interfaces\n            this.setIgnoredInterfaces(originIgnoredInterfaces);\n        }\n    }\n\n    @Test\n    void testIgnoreGivenPrefixInterfaceName() {\n        // store the origin ignored interfaces\n        String originIgnoredInterfaces = this.getIgnoredInterfaces();\n        try {\n            NetworkInterface networkInterface = NetUtils.findNetworkInterface();\n            assertNotNull(networkInterface);\n            // ignore the given prefix network interface's display name\n            String displayName = networkInterface.getDisplayName();\n            if (StringUtils.isNotEmpty(displayName) && displayName.length() > 2) {\n                String ignoredInterfaces = Pattern.quote(displayName.substring(0, 1)) + \".*\";\n                this.setIgnoredInterfaces(ignoredInterfaces);\n                NetworkInterface newNetworkInterface = NetUtils.findNetworkInterface();\n                if (newNetworkInterface != null) {\n                    assertTrue(!newNetworkInterface.getDisplayName().startsWith(displayName.substring(0, 1)));\n                }\n            }\n        } finally {\n            // recover the origin ignored interfaces\n            this.setIgnoredInterfaces(originIgnoredInterfaces);\n        }\n    }\n\n    @Test\n    void testRepeatedStatusChecking() {\n        int port = NetUtils.getAvailablePort();\n        for (int i = 0; i < 10000; i++) {\n            assertFalse(NetUtils.isPortInUsed(port));\n        }\n    }\n\n    private String getIgnoredInterfaces() {\n        return SystemPropertyConfigUtils.getSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_NETWORK_IGNORED_INTERFACE);\n    }\n\n    private void setIgnoredInterfaces(String ignoredInterfaces) {\n        if (ignoredInterfaces != null) {\n            SystemPropertyConfigUtils.setSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_NETWORK_IGNORED_INTERFACE, ignoredInterfaces);\n        } else {\n            SystemPropertyConfigUtils.setSystemProperty(\n                    CommonConstants.DubboProperty.DUBBO_NETWORK_IGNORED_INTERFACE, \"\");\n        }\n    }\n\n    @Test\n    void testIsIPV6URLStdFormat() {\n        assertTrue(NetUtils.isIPV6URLStdFormat(\"2001:0db8:85a3:0000:0000:8a2e:0370:7334\"));\n        assertTrue(NetUtils.isIPV6URLStdFormat(\"2001:db8::1\"));\n        assertTrue(NetUtils.isIPV6URLStdFormat(\"[2001:db8::1]\"));\n        assertTrue(NetUtils.isIPV6URLStdFormat(\"[2001:db8::1]:8080\"));\n        assertFalse(NetUtils.isIPV6URLStdFormat(\"192.168.1.1\"));\n        assertFalse(NetUtils.isIPV6URLStdFormat(\"localhost\"));\n        assertFalse(NetUtils.isIPV6URLStdFormat(\"[]\"));\n        assertFalse(NetUtils.isIPV6URLStdFormat(\"127.0.0.1:8080\"));\n    }\n\n    @Test\n    void testGetLegalIP() {\n        assertThat(NetUtils.getLegalIP(\"[2001:db8::1]\"), equalTo(\"2001:db8::1\"));\n        assertThat(NetUtils.getLegalIP(\"[2001:db8::1]:8080\"), equalTo(\"2001:db8::1\"));\n        assertThat(NetUtils.getLegalIP(\"2001:db8::1\"), equalTo(\"2001:db8::1\"));\n        assertThat(NetUtils.getLegalIP(\"192.168.1.1\"), equalTo(\"192.168.1.1\"));\n        assertThat(NetUtils.getLegalIP(\"[::]\"), equalTo(\"::\"));\n        assertThat(NetUtils.getLegalIP(\"[]\"), equalTo(\"[]\"));\n    }\n\n    @Test\n    void testGetLocalHostName() {\n        assertNotNull(NetUtils.getLocalHostName());\n    }\n\n    @Test\n    void testGetLocalHostV6() {\n        String v6 = NetUtils.getLocalHostV6();\n        if (v6 != null) {\n            assertTrue(v6.contains(\":\"));\n        }\n    }\n\n    @Test\n    void testIsReuseAddressSupported() {\n        boolean supported = NetUtils.isReuseAddressSupported();\n        assertTrue(supported || !supported);\n    }\n\n    @Test\n    void testMatchIpRange_NullInputs() {\n        assertThrows(IllegalArgumentException.class, () -> {\n            NetUtils.matchIpRange(null, \"127.0.0.1\", 80);\n        });\n        assertThrows(IllegalArgumentException.class, () -> {\n            NetUtils.matchIpRange(\"127.0.0.1\", null, 80);\n        });\n    }\n\n    @Test\n    void testMatchIpRange_ZeroPadding() throws UnknownHostException {\n        assertTrue(NetUtils.matchIpRange(\"10.00.1.1\", \"10.0.1.1\", 0));\n        assertTrue(NetUtils.matchIpRange(\"10.000.1.1\", \"10.0.1.1\", 0));\n    }\n\n    @Test\n    void testIsPortInUsed_True() throws IOException {\n        int port = NetUtils.getAvailablePort();\n        try (ServerSocket socket = new ServerSocket(port)) {\n            assertTrue(NetUtils.isPortInUsed(port));\n        }\n        assertFalse(NetUtils.isPortInUsed(port));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/ParametersTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass ParametersTest {\n    final String ServiceName = \"org.apache.dubbo.rpc.service.GenericService\";\n    final String ServiceVersion = \"1.0.15\";\n    final String LoadBalance = \"lcr\";\n\n    public void testMap2Parameters() {\n        Map<String, String> map = new HashMap<String, String>();\n        map.put(\"name\", \"org.apache.dubbo.rpc.service.GenericService\");\n        map.put(\"version\", \"1.0.15\");\n        map.put(\"lb\", \"lcr\");\n        map.put(\"max.active\", \"500\");\n        assertEquals(map.get(\"name\"), ServiceName);\n        assertEquals(map.get(\"version\"), ServiceVersion);\n        assertEquals(map.get(\"lb\"), LoadBalance);\n    }\n\n    public void testString2Parameters() throws Exception {\n        String qs = \"name=org.apache.dubbo.rpc.service.GenericService&version=1.0.15&lb=lcr\";\n        Map<String, String> map = StringUtils.parseQueryString(qs);\n        assertEquals(map.get(\"name\"), ServiceName);\n        assertEquals(map.get(\"version\"), ServiceVersion);\n        assertEquals(map.get(\"lb\"), LoadBalance);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/PathUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass PathUtilsTest {\n    @Test\n    void testBuildPath() {\n        Assertions.assertEquals(\"a/b/c\", PathUtils.buildPath(\"a\", \"b\", \"c\"));\n        Assertions.assertEquals(\"root/sub\", PathUtils.buildPath(\"root\", \"sub\"));\n    }\n\n    @Test\n    void testNormalize() {\n        Assertions.assertEquals(\"/path\", PathUtils.normalize(\"//path\"));\n        Assertions.assertEquals(\"/api/v1\", PathUtils.normalize(\"/api/v1?name=dubbo\"));\n        // Empty and Null handling (The \"Edge Cases\")\n        Assertions.assertEquals(\"/\", PathUtils.normalize(\"\"));\n        Assertions.assertEquals(\"/\", PathUtils.normalize(null));\n        // Multiple slashes\n        Assertions.assertEquals(\"/a/b/c\", PathUtils.normalize(\"/a//b///c\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.model.Person;\nimport org.apache.dubbo.common.model.SerializablePerson;\nimport org.apache.dubbo.common.model.User;\nimport org.apache.dubbo.common.model.person.Ageneric;\nimport org.apache.dubbo.common.model.person.Bgeneric;\nimport org.apache.dubbo.common.model.person.BigPerson;\nimport org.apache.dubbo.common.model.person.Cgeneric;\nimport org.apache.dubbo.common.model.person.Dgeneric;\nimport org.apache.dubbo.common.model.person.FullAddress;\nimport org.apache.dubbo.common.model.person.PersonInfo;\nimport org.apache.dubbo.common.model.person.PersonMap;\nimport org.apache.dubbo.common.model.person.PersonStatus;\nimport org.apache.dubbo.common.model.person.Phone;\n\nimport java.io.Serializable;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\nimport java.text.SimpleDateFormat;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.UUID;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass PojoUtilsTest {\n\n    BigPerson bigPerson;\n\n    {\n        bigPerson = new BigPerson();\n        bigPerson.setPersonId(\"id1\");\n        bigPerson.setLoginName(\"name1\");\n        bigPerson.setStatus(PersonStatus.ENABLED);\n        bigPerson.setEmail(\"abc@123.com\");\n        bigPerson.setPersonName(\"pname\");\n\n        ArrayList<Phone> phones = new ArrayList<Phone>();\n        Phone phone1 = new Phone(\"86\", \"0571\", \"11223344\", \"001\");\n        Phone phone2 = new Phone(\"86\", \"0571\", \"11223344\", \"002\");\n        phones.add(phone1);\n        phones.add(phone2);\n\n        PersonInfo pi = new PersonInfo();\n        pi.setPhones(phones);\n        Phone fax = new Phone(\"86\", \"0571\", \"11223344\", null);\n        pi.setFax(fax);\n        FullAddress addr = new FullAddress(\"CN\", \"zj\", \"1234\", \"Road1\", \"333444\");\n        pi.setFullAddress(addr);\n        pi.setMobileNo(\"1122334455\");\n        pi.setMale(true);\n        pi.setDepartment(\"b2b\");\n        pi.setHomepageUrl(\"www.abc.com\");\n        pi.setJobTitle(\"dev\");\n        pi.setName(\"name2\");\n\n        bigPerson.setInfoProfile(pi);\n    }\n\n    private static Child newChild(String name, int age) {\n        Child result = new Child();\n        result.setName(name);\n        result.setAge(age);\n        return result;\n    }\n\n    public void assertObject(Object data) {\n        assertObject(data, null);\n    }\n\n    public void assertObject(Object data, Type type) {\n        Object generalize = PojoUtils.generalize(data);\n        Object realize = PojoUtils.realize(generalize, data.getClass(), type);\n        assertEquals(data, realize);\n    }\n\n    public <T> void assertArrayObject(T[] data) {\n        Object generalize = PojoUtils.generalize(data);\n        @SuppressWarnings(\"unchecked\")\n        T[] realize = (T[]) PojoUtils.realize(generalize, data.getClass());\n        assertArrayEquals(data, realize);\n    }\n\n    @Test\n    void test_primitive() throws Exception {\n        assertObject(Boolean.TRUE);\n        assertObject(Boolean.FALSE);\n\n        assertObject(Byte.valueOf((byte) 78));\n\n        assertObject('a');\n        assertObject('中');\n\n        assertObject(Short.valueOf((short) 37));\n\n        assertObject(78);\n\n        assertObject(123456789L);\n\n        assertObject(3.14F);\n        assertObject(3.14D);\n    }\n\n    @Test\n    void test_pojo() throws Exception {\n        assertObject(new Person());\n        assertObject(new BasicTestData(false, '\\0', (byte) 0, (short) 0, 0, 0L, 0F, 0D));\n        assertObject(new SerializablePerson(Character.MIN_VALUE, false));\n    }\n\n    @Test\n    void test_has_no_nullary_constructor_pojo() {\n        assertObject(new User(1, \"fibbery\"));\n    }\n\n    @Test\n    void test_Map_List_pojo() throws Exception {\n        Map<String, List<Object>> map = new HashMap<String, List<Object>>();\n\n        List<Object> list = new ArrayList<Object>();\n        list.add(new Person());\n        list.add(new SerializablePerson(Character.MIN_VALUE, false));\n\n        map.put(\"k\", list);\n\n        Object generalize = PojoUtils.generalize(map);\n        Object realize = PojoUtils.realize(generalize, Map.class);\n        assertEquals(map, realize);\n    }\n\n    @Test\n    void test_PrimitiveArray() throws Exception {\n        assertObject(new boolean[] {true, false});\n        assertObject(new Boolean[] {true, false, true});\n\n        assertObject(new byte[] {1, 12, 28, 78});\n        assertObject(new Byte[] {1, 12, 28, 78});\n\n        assertObject(new char[] {'a', '中', '无'});\n        assertObject(new Character[] {'a', '中', '无'});\n\n        assertObject(new short[] {37, 39, 12});\n        assertObject(new Short[] {37, 39, 12});\n\n        assertObject(new int[] {37, -39, 12456});\n        assertObject(new Integer[] {37, -39, 12456});\n\n        assertObject(new long[] {37L, -39L, 123456789L});\n        assertObject(new Long[] {37L, -39L, 123456789L});\n\n        assertObject(new float[] {37F, -3.14F, 123456.7F});\n        assertObject(new Float[] {37F, -39F, 123456.7F});\n\n        assertObject(new double[] {37D, -3.14D, 123456.7D});\n        assertObject(new Double[] {37D, -39D, 123456.7D});\n\n        assertArrayObject(new Boolean[] {true, false, true});\n\n        assertArrayObject(new Byte[] {1, 12, 28, 78});\n\n        assertArrayObject(new Character[] {'a', '中', '无'});\n\n        assertArrayObject(new Short[] {37, 39, 12});\n\n        assertArrayObject(new Integer[] {37, -39, 12456});\n\n        assertArrayObject(new Long[] {37L, -39L, 123456789L});\n\n        assertArrayObject(new Float[] {37F, -39F, 123456.7F});\n\n        assertArrayObject(new Double[] {37D, -39D, 123456.7D});\n\n        assertObject(new int[][] {{37, -39, 12456}});\n        assertObject(new Integer[][][] {{{37, -39, 12456}}});\n\n        assertArrayObject(new Integer[] {37, -39, 12456});\n    }\n\n    @Test\n    void test_PojoArray() throws Exception {\n        Person[] array = new Person[2];\n        array[0] = new Person();\n        {\n            Person person = new Person();\n            person.setName(\"xxxx\");\n            array[1] = person;\n        }\n        assertArrayObject(array);\n    }\n\n    @Test\n    void testArrayToCollection() throws Exception {\n        Person[] array = new Person[2];\n        Person person1 = new Person();\n        person1.setName(\"person1\");\n        Person person2 = new Person();\n        person2.setName(\"person2\");\n        array[0] = person1;\n        array[1] = person2;\n        Object o = PojoUtils.realize(PojoUtils.generalize(array), LinkedList.class);\n        assertTrue(o instanceof LinkedList);\n        assertEquals(((List) o).get(0), person1);\n        assertEquals(((List) o).get(1), person2);\n    }\n\n    @Test\n    void testCollectionToArray() throws Exception {\n        Person person1 = new Person();\n        person1.setName(\"person1\");\n        Person person2 = new Person();\n        person2.setName(\"person2\");\n        List<Person> list = new LinkedList<Person>();\n        list.add(person1);\n        list.add(person2);\n        Object o = PojoUtils.realize(PojoUtils.generalize(list), Person[].class);\n        assertTrue(o instanceof Person[]);\n        assertEquals(((Person[]) o)[0], person1);\n        assertEquals(((Person[]) o)[1], person2);\n    }\n\n    @Test\n    void testMapToEnum() throws Exception {\n        Map map = new HashMap();\n        map.put(\"name\", \"MONDAY\");\n        Object o = PojoUtils.realize(map, Day.class);\n        assertEquals(o, Day.MONDAY);\n    }\n\n    @Test\n    void testGeneralizeEnumArray() throws Exception {\n        Object days = new Enum[] {Day.FRIDAY, Day.SATURDAY};\n        Object o = PojoUtils.generalize(days);\n        assertTrue(o instanceof String[]);\n        assertEquals(((String[]) o)[0], \"FRIDAY\");\n        assertEquals(((String[]) o)[1], \"SATURDAY\");\n    }\n\n    @Test\n    void testGeneralizePersons() throws Exception {\n        Object persons = new Person[] {new Person(), new Person()};\n        Object o = PojoUtils.generalize(persons);\n        assertTrue(o instanceof Object[]);\n        assertEquals(((Object[]) o).length, 2);\n    }\n\n    @Test\n    void testMapToInterface() throws Exception {\n        Map map = new HashMap();\n        map.put(\"content\", \"greeting\");\n        map.put(\"from\", \"dubbo\");\n        map.put(\"urgent\", true);\n        Object o = PojoUtils.realize(map, Message.class);\n        Message message = (Message) o;\n        assertThat(message.getContent(), equalTo(\"greeting\"));\n        assertThat(message.getFrom(), equalTo(\"dubbo\"));\n        assertTrue(message.isUrgent());\n    }\n\n    @Test\n    void testJsonObjectToMap() throws Exception {\n        Method method = PojoUtilsTest.class.getMethod(\"setMap\", Map.class);\n        assertNotNull(method);\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"1\", \"test\");\n        @SuppressWarnings(\"unchecked\")\n        Map<Integer, Object> value = (Map<Integer, Object>)\n                PojoUtils.realize(jsonObject, method.getParameterTypes()[0], method.getGenericParameterTypes()[0]);\n        method.invoke(new PojoUtilsTest(), value);\n        assertEquals(\"test\", value.get(1));\n    }\n\n    @Test\n    void testListJsonObjectToListMap() throws Exception {\n        Method method = PojoUtilsTest.class.getMethod(\"setListMap\", List.class);\n        assertNotNull(method);\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"1\", \"test\");\n        List<JSONObject> list = new ArrayList<>(1);\n        list.add(jsonObject);\n        @SuppressWarnings(\"unchecked\")\n        List<Map<Integer, Object>> result = (List<Map<Integer, Object>>)\n                PojoUtils.realize(list, method.getParameterTypes()[0], method.getGenericParameterTypes()[0]);\n        method.invoke(new PojoUtilsTest(), result);\n        assertEquals(\"test\", result.get(0).get(1));\n    }\n\n    public void setMap(Map<Integer, Object> map) {}\n\n    public void setListMap(List<Map<Integer, Object>> list) {}\n\n    @Test\n    void testException() throws Exception {\n        Map map = new HashMap();\n        map.put(\"message\", \"dubbo exception\");\n        Object o = PojoUtils.realize(map, RuntimeException.class);\n        assertEquals(((Throwable) o).getMessage(), \"dubbo exception\");\n    }\n\n    @Test\n    void testIsPojo() throws Exception {\n        assertFalse(PojoUtils.isPojo(boolean.class));\n        assertFalse(PojoUtils.isPojo(Map.class));\n        assertFalse(PojoUtils.isPojo(List.class));\n        assertTrue(PojoUtils.isPojo(Person.class));\n    }\n\n    public List<Person> returnListPersonMethod() {\n        return null;\n    }\n\n    public BigPerson returnBigPersonMethod() {\n        return null;\n    }\n\n    public Type getType(String methodName) {\n        Method method;\n        try {\n            method = getClass().getDeclaredMethod(methodName, new Class<?>[] {});\n        } catch (Exception e) {\n            throw new IllegalStateException(e);\n        }\n        Type gtype = method.getGenericReturnType();\n        return gtype;\n    }\n\n    @Test\n    void test_simpleCollection() throws Exception {\n        Type gtype = getType(\"returnListPersonMethod\");\n        List<Person> list = new ArrayList<Person>();\n        list.add(new Person());\n        {\n            Person person = new Person();\n            person.setName(\"xxxx\");\n            list.add(person);\n        }\n        assertObject(list, gtype);\n    }\n\n    @Test\n    void test_total() throws Exception {\n        Object generalize = PojoUtils.generalize(bigPerson);\n        Type gtype = getType(\"returnBigPersonMethod\");\n        Object realize = PojoUtils.realize(generalize, BigPerson.class, gtype);\n        assertEquals(bigPerson, realize);\n    }\n\n    @Test\n    void test_total_Array() throws Exception {\n        Object[] persons = new Object[] {bigPerson, bigPerson, bigPerson};\n\n        Object generalize = PojoUtils.generalize(persons);\n        Object[] realize = (Object[]) PojoUtils.realize(generalize, Object[].class);\n        assertArrayEquals(persons, realize);\n    }\n\n    @Test\n    void test_Loop_pojo() throws Exception {\n        Parent p = new Parent();\n        p.setAge(10);\n        p.setName(\"jerry\");\n\n        Child c = new Child();\n        c.setToy(\"haha\");\n\n        p.setChild(c);\n        c.setParent(p);\n\n        Object generalize = PojoUtils.generalize(p);\n        Parent parent = (Parent) PojoUtils.realize(generalize, Parent.class);\n\n        assertEquals(10, parent.getAge());\n        assertEquals(\"jerry\", parent.getName());\n\n        assertEquals(\"haha\", parent.getChild().getToy());\n        assertSame(parent, parent.getChild().getParent());\n    }\n\n    @Test\n    void test_Loop_Map() throws Exception {\n        Map<String, Object> map = new HashMap<String, Object>();\n\n        map.put(\"k\", \"v\");\n        map.put(\"m\", map);\n        assertSame(map, map.get(\"m\"));\n        Object generalize = PojoUtils.generalize(map);\n        @SuppressWarnings(\"unchecked\")\n        Map<String, Object> ret = (Map<String, Object>) PojoUtils.realize(generalize, Map.class);\n\n        assertEquals(\"v\", ret.get(\"k\"));\n        assertSame(ret, ret.get(\"m\"));\n    }\n\n    @Test\n    void test_LoopPojoInMap() throws Exception {\n        Parent p = new Parent();\n        p.setAge(10);\n        p.setName(\"jerry\");\n\n        Child c = new Child();\n        c.setToy(\"haha\");\n\n        p.setChild(c);\n        c.setParent(p);\n\n        Map<String, Object> map = new HashMap<String, Object>();\n        map.put(\"k\", p);\n\n        Object generalize = PojoUtils.generalize(map);\n        @SuppressWarnings(\"unchecked\")\n        Map<String, Object> realize =\n                (Map<String, Object>) PojoUtils.realize(generalize, Map.class, getType(\"getMapGenericType\"));\n\n        Parent parent = (Parent) realize.get(\"k\");\n\n        assertEquals(10, parent.getAge());\n        assertEquals(\"jerry\", parent.getName());\n\n        assertEquals(\"haha\", parent.getChild().getToy());\n        assertSame(parent, parent.getChild().getParent());\n    }\n\n    @Test\n    void test_LoopPojoInList() throws Exception {\n        Parent p = new Parent();\n        p.setAge(10);\n        p.setName(\"jerry\");\n\n        Child c = new Child();\n        c.setToy(\"haha\");\n\n        p.setChild(c);\n        c.setParent(p);\n\n        List<Object> list = new ArrayList<Object>();\n        list.add(p);\n\n        Object generalize = PojoUtils.generalize(list);\n        @SuppressWarnings(\"unchecked\")\n        List<Object> realize = (List<Object>) PojoUtils.realize(generalize, List.class, getType(\"getListGenericType\"));\n\n        Parent parent = (Parent) realize.get(0);\n\n        assertEquals(10, parent.getAge());\n        assertEquals(\"jerry\", parent.getName());\n\n        assertEquals(\"haha\", parent.getChild().getToy());\n        assertSame(parent, parent.getChild().getParent());\n\n        Object[] objects = PojoUtils.realize(\n                new Object[] {generalize}, new Class[] {List.class}, new Type[] {getType(\"getListGenericType\")});\n        assertTrue(((List) objects[0]).get(0) instanceof Parent);\n    }\n\n    @Test\n    void test_PojoInList() throws Exception {\n        Parent p = new Parent();\n        p.setAge(10);\n        p.setName(\"jerry\");\n\n        List<Object> list = new ArrayList<Object>();\n        list.add(p);\n\n        Object generalize = PojoUtils.generalize(list);\n        @SuppressWarnings(\"unchecked\")\n        List<Object> realize = (List<Object>) PojoUtils.realize(generalize, List.class, getType(\"getListGenericType\"));\n\n        Parent parent = (Parent) realize.get(0);\n\n        assertEquals(10, parent.getAge());\n        assertEquals(\"jerry\", parent.getName());\n    }\n\n    public void setLong(long l) {}\n\n    public void setInt(int l) {}\n\n    public List<Parent> getListGenericType() {\n        return null;\n    }\n\n    public Map<String, Parent> getMapGenericType() {\n        return null;\n    }\n\n    // java.lang.IllegalArgumentException: argument type mismatch\n    @Test\n    void test_realize_LongPararmter_IllegalArgumentException() throws Exception {\n        Method method = PojoUtilsTest.class.getMethod(\"setLong\", long.class);\n        assertNotNull(method);\n\n        Object value = PojoUtils.realize(\n                \"563439743927993\", method.getParameterTypes()[0], method.getGenericParameterTypes()[0]);\n\n        method.invoke(new PojoUtilsTest(), value);\n    }\n\n    // java.lang.IllegalArgumentException: argument type mismatch\n    @Test\n    void test_realize_IntPararmter_IllegalArgumentException() throws Exception {\n        Method method = PojoUtilsTest.class.getMethod(\"setInt\", int.class);\n        assertNotNull(method);\n\n        Object value = PojoUtils.realize(\"123\", method.getParameterTypes()[0], method.getGenericParameterTypes()[0]);\n\n        method.invoke(new PojoUtilsTest(), value);\n    }\n\n    @Test\n    void testStackOverflow() throws Exception {\n        Parent parent = Parent.getNewParent();\n        parent.setAge(Integer.MAX_VALUE);\n        String name = UUID.randomUUID().toString();\n        parent.setName(name);\n        Object generalize = PojoUtils.generalize(parent);\n        assertTrue(generalize instanceof Map);\n        Map map = (Map) generalize;\n        assertEquals(Integer.MAX_VALUE, map.get(\"age\"));\n        assertEquals(name, map.get(\"name\"));\n\n        Parent realize = (Parent) PojoUtils.realize(generalize, Parent.class);\n        assertEquals(Integer.MAX_VALUE, realize.getAge());\n        assertEquals(name, realize.getName());\n    }\n\n    @Test\n    void testGenerializeAndRealizeClass() throws Exception {\n        Object generalize = PojoUtils.generalize(Integer.class);\n        assertEquals(Integer.class.getName(), generalize);\n        Object real = PojoUtils.realize(generalize, Integer.class.getClass());\n        assertEquals(Integer.class, real);\n\n        generalize = PojoUtils.generalize(int[].class);\n        assertEquals(int[].class.getName(), generalize);\n        real = PojoUtils.realize(generalize, int[].class.getClass());\n        assertEquals(int[].class, real);\n    }\n\n    @Test\n    void testPublicField() throws Exception {\n        Parent parent = new Parent();\n        parent.gender = \"female\";\n        parent.email = \"email@host.com\";\n        parent.setEmail(\"securityemail@host.com\");\n        Child child = new Child();\n        parent.setChild(child);\n        child.gender = \"male\";\n        child.setAge(20);\n        child.setParent(parent);\n        Object obj = PojoUtils.generalize(parent);\n        Parent realizedParent = (Parent) PojoUtils.realize(obj, Parent.class);\n        Assertions.assertEquals(parent.gender, realizedParent.gender);\n        Assertions.assertEquals(child.gender, parent.getChild().gender);\n        Assertions.assertEquals(child.age, realizedParent.getChild().getAge());\n        Assertions.assertEquals(parent.getEmail(), realizedParent.getEmail());\n        Assertions.assertNull(realizedParent.email);\n    }\n\n    @Test\n    void testMapField() throws Exception {\n        TestData data = new TestData();\n        Child child = newChild(\"first\", 1);\n        data.addChild(child);\n        child = newChild(\"second\", 2);\n        data.addChild(child);\n        child = newChild(\"third\", 3);\n        data.addChild(child);\n\n        data.setList(Arrays.asList(newChild(\"forth\", 4)));\n\n        Object obj = PojoUtils.generalize(data);\n        Assertions.assertEquals(3, data.getChildren().size());\n        assertSame(data.getChildren().get(\"first\").getClass(), Child.class);\n        Assertions.assertEquals(1, data.getList().size());\n        assertSame(data.getList().get(0).getClass(), Child.class);\n\n        TestData realizadData = (TestData) PojoUtils.realize(obj, TestData.class);\n        Assertions.assertEquals(\n                data.getChildren().size(), realizadData.getChildren().size());\n        Assertions.assertEquals(\n                data.getChildren().keySet(), realizadData.getChildren().keySet());\n        for (Map.Entry<String, Child> entry : data.getChildren().entrySet()) {\n            Child c = realizadData.getChildren().get(entry.getKey());\n            Assertions.assertNotNull(c);\n            Assertions.assertEquals(entry.getValue().getName(), c.getName());\n            Assertions.assertEquals(entry.getValue().getAge(), c.getAge());\n        }\n\n        Assertions.assertEquals(1, realizadData.getList().size());\n        Assertions.assertEquals(\n                data.getList().get(0).getName(), realizadData.getList().get(0).getName());\n        Assertions.assertEquals(\n                data.getList().get(0).getAge(), realizadData.getList().get(0).getAge());\n    }\n\n    @Test\n    void testRealize() throws Exception {\n        Map<String, String> map = new LinkedHashMap<String, String>();\n        map.put(\"key\", \"value\");\n        Object obj = PojoUtils.generalize(map);\n        assertTrue(obj instanceof LinkedHashMap);\n        Object outputObject = PojoUtils.realize(map, LinkedHashMap.class);\n        assertTrue(outputObject instanceof LinkedHashMap);\n        Object[] objects = PojoUtils.realize(new Object[] {map}, new Class[] {LinkedHashMap.class});\n        assertTrue(objects[0] instanceof LinkedHashMap);\n        assertEquals(objects[0], outputObject);\n    }\n\n    @Test\n    void testRealizeLinkedList() throws Exception {\n        LinkedList<Person> input = new LinkedList<Person>();\n        Person person = new Person();\n        person.setAge(37);\n        input.add(person);\n        Object obj = PojoUtils.generalize(input);\n        assertTrue(obj instanceof List);\n        assertTrue(input.get(0) instanceof Person);\n        Object output = PojoUtils.realize(obj, LinkedList.class);\n        assertTrue(output instanceof LinkedList);\n    }\n\n    @Test\n    void testPojoList() throws Exception {\n        ListResult<Parent> result = new ListResult<Parent>();\n        List<Parent> list = new ArrayList<Parent>();\n        Parent parent = new Parent();\n        parent.setAge(Integer.MAX_VALUE);\n        parent.setName(\"zhangsan\");\n        list.add(parent);\n        result.setResult(list);\n\n        Object generializeObject = PojoUtils.generalize(result);\n        Object realizeObject = PojoUtils.realize(generializeObject, ListResult.class);\n        assertTrue(realizeObject instanceof ListResult);\n        ListResult listResult = (ListResult) realizeObject;\n        List l = listResult.getResult();\n        assertEquals(1, l.size());\n        assertTrue(l.get(0) instanceof Parent);\n        Parent realizeParent = (Parent) l.get(0);\n        Assertions.assertEquals(parent.getName(), realizeParent.getName());\n        Assertions.assertEquals(parent.getAge(), realizeParent.getAge());\n    }\n\n    @Test\n    void testListPojoListPojo() throws Exception {\n        InnerPojo<Parent> parentList = new InnerPojo<Parent>();\n        Parent parent = new Parent();\n        parent.setName(\"zhangsan\");\n        parent.setAge(Integer.MAX_VALUE);\n        parentList.setList(Arrays.asList(parent));\n\n        ListResult<InnerPojo<Parent>> list = new ListResult<InnerPojo<Parent>>();\n        list.setResult(Arrays.asList(parentList));\n\n        Object generializeObject = PojoUtils.generalize(list);\n        Object realizeObject = PojoUtils.realize(generializeObject, ListResult.class);\n\n        assertTrue(realizeObject instanceof ListResult);\n        ListResult realizeList = (ListResult) realizeObject;\n        List realizeInnerList = realizeList.getResult();\n        Assertions.assertEquals(1, realizeInnerList.size());\n        assertTrue(realizeInnerList.get(0) instanceof InnerPojo);\n        InnerPojo realizeParentList = (InnerPojo) realizeInnerList.get(0);\n        Assertions.assertEquals(1, realizeParentList.getList().size());\n        assertTrue(realizeParentList.getList().get(0) instanceof Parent);\n        Parent realizeParent = (Parent) realizeParentList.getList().get(0);\n        Assertions.assertEquals(parent.getName(), realizeParent.getName());\n        Assertions.assertEquals(parent.getAge(), realizeParent.getAge());\n    }\n\n    @Test\n    void testDateTimeTimestamp() throws Exception {\n        String dateStr = \"2018-09-12\";\n        String timeStr = \"10:12:33\";\n        String dateTimeStr = \"2018-09-12 10:12:33\";\n        String[] dateFormat = new String[] {\"yyyy-MM-dd HH:mm:ss\", \"yyyy-MM-dd\", \"HH:mm:ss\"};\n\n        // java.util.Date\n        Object date = PojoUtils.realize(dateTimeStr, Date.class, (Type) Date.class);\n        assertEquals(Date.class, date.getClass());\n        assertEquals(dateTimeStr, new SimpleDateFormat(dateFormat[0]).format(date));\n\n        // java.sql.Time\n        Object time = PojoUtils.realize(dateTimeStr, java.sql.Time.class, (Type) java.sql.Time.class);\n        assertEquals(java.sql.Time.class, time.getClass());\n        assertEquals(timeStr, new SimpleDateFormat(dateFormat[2]).format(time));\n\n        // java.sql.Date\n        Object sqlDate = PojoUtils.realize(dateTimeStr, java.sql.Date.class, (Type) java.sql.Date.class);\n        assertEquals(java.sql.Date.class, sqlDate.getClass());\n        assertEquals(dateStr, new SimpleDateFormat(dateFormat[1]).format(sqlDate));\n\n        // java.sql.Timestamp\n        Object timestamp = PojoUtils.realize(dateTimeStr, java.sql.Timestamp.class, (Type) java.sql.Timestamp.class);\n        assertEquals(java.sql.Timestamp.class, timestamp.getClass());\n        assertEquals(dateTimeStr, new SimpleDateFormat(dateFormat[0]).format(timestamp));\n    }\n\n    @Test\n    void testIntToBoolean() throws Exception {\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"name\", \"myname\");\n        map.put(\"male\", 1);\n        map.put(\"female\", 0);\n\n        PersonInfo personInfo = (PersonInfo) PojoUtils.realize(map, PersonInfo.class);\n\n        assertEquals(\"myname\", personInfo.getName());\n        assertTrue(personInfo.isMale());\n        assertFalse(personInfo.isFemale());\n    }\n\n    @Test\n    void testRealizeCollectionWithNullElement() {\n        LinkedList<String> listStr = new LinkedList<>();\n        listStr.add(\"arrayValue\");\n        listStr.add(null);\n        HashSet<String> setStr = new HashSet<>();\n        setStr.add(\"setValue\");\n        setStr.add(null);\n\n        Object listResult = PojoUtils.realize(listStr, LinkedList.class);\n        assertEquals(LinkedList.class, listResult.getClass());\n        assertEquals(listResult, listStr);\n\n        Object setResult = PojoUtils.realize(setStr, HashSet.class);\n        assertEquals(HashSet.class, setResult.getClass());\n        assertEquals(setResult, setStr);\n    }\n\n    @Test\n    void testJava8Time() {\n\n        Object localDateTimeGen = PojoUtils.generalize(LocalDateTime.now());\n        Object localDateTime = PojoUtils.realize(localDateTimeGen, LocalDateTime.class);\n        assertEquals(localDateTimeGen, localDateTime.toString());\n\n        Object localDateGen = PojoUtils.generalize(LocalDate.now());\n        Object localDate = PojoUtils.realize(localDateGen, LocalDate.class);\n        assertEquals(localDateGen, localDate.toString());\n\n        Object localTimeGen = PojoUtils.generalize(LocalTime.now());\n        Object localTime = PojoUtils.realize(localTimeGen, LocalTime.class);\n        assertEquals(localTimeGen, localTime.toString());\n    }\n\n    @Test\n    public void testJSONObjectToPersonMapPojo() {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"personId\", \"1\");\n        jsonObject.put(\"personName\", \"hand\");\n        Object result = PojoUtils.realize(jsonObject, PersonMap.class);\n        assertEquals(PersonMap.class, result.getClass());\n    }\n\n    protected PersonInfo createPersonInfoByName(String name) {\n        PersonInfo dataPerson = new PersonInfo();\n        dataPerson.setName(name);\n        return dataPerson;\n    }\n\n    protected Ageneric<PersonInfo> createAGenericPersonInfo(String name) {\n        Ageneric<PersonInfo> ret = new Ageneric();\n        ret.setData(createPersonInfoByName(name));\n        return ret;\n    }\n\n    protected Bgeneric<PersonInfo> createBGenericPersonInfo(String name) {\n        Bgeneric<PersonInfo> ret = new Bgeneric();\n        ret.setData(createPersonInfoByName(name));\n        return ret;\n    }\n\n    @Test\n    public void testPojoGeneric1() throws NoSuchMethodException {\n        String personName = \"testName\";\n\n        {\n            Ageneric<PersonInfo> genericPersonInfo = createAGenericPersonInfo(personName);\n\n            Object o = JSON.toJSON(genericPersonInfo);\n            {\n                Ageneric personInfo = (Ageneric) PojoUtils.realize(o, Ageneric.class);\n\n                assertEquals(Ageneric.NAME, personInfo.getName());\n                assertTrue(personInfo.getData() instanceof Map);\n            }\n            {\n                Type[] createGenericPersonInfos = ReflectUtils.getReturnTypes(\n                        PojoUtilsTest.class.getDeclaredMethod(\"createAGenericPersonInfo\", String.class));\n                Ageneric personInfo = (Ageneric)\n                        PojoUtils.realize(o, (Class) createGenericPersonInfos[0], createGenericPersonInfos[1]);\n\n                assertEquals(Ageneric.NAME, personInfo.getName());\n                assertEquals(personInfo.getData().getClass(), PersonInfo.class);\n                assertEquals(personName, ((PersonInfo) personInfo.getData()).getName());\n            }\n        }\n        {\n            Bgeneric<PersonInfo> genericPersonInfo = createBGenericPersonInfo(personName);\n\n            Object o = JSON.toJSON(genericPersonInfo);\n            {\n                Bgeneric personInfo = (Bgeneric) PojoUtils.realize(o, Bgeneric.class);\n\n                assertEquals(Bgeneric.NAME, personInfo.getName());\n                assertTrue(personInfo.getData() instanceof Map);\n            }\n            {\n                Type[] createGenericPersonInfos = ReflectUtils.getReturnTypes(\n                        PojoUtilsTest.class.getDeclaredMethod(\"createBGenericPersonInfo\", String.class));\n                Bgeneric personInfo = (Bgeneric)\n                        PojoUtils.realize(o, (Class) createGenericPersonInfos[0], createGenericPersonInfos[1]);\n\n                assertEquals(Bgeneric.NAME, personInfo.getName());\n                assertEquals(personInfo.getData().getClass(), PersonInfo.class);\n                assertEquals(personName, ((PersonInfo) personInfo.getData()).getName());\n            }\n        }\n    }\n\n    protected Ageneric<Ageneric<PersonInfo>> createAGenericLoop(String name) {\n        Ageneric<Ageneric<PersonInfo>> ret = new Ageneric();\n        ret.setData(createAGenericPersonInfo(name));\n        return ret;\n    }\n\n    protected Bgeneric<Ageneric<PersonInfo>> createBGenericWithAgeneric(String name) {\n        Bgeneric<Ageneric<PersonInfo>> ret = new Bgeneric();\n        ret.setData(createAGenericPersonInfo(name));\n        return ret;\n    }\n\n    @Test\n    public void testPojoGeneric2() throws NoSuchMethodException {\n        String personName = \"testName\";\n\n        {\n            Ageneric<Ageneric<PersonInfo>> generic2PersonInfo = createAGenericLoop(personName);\n            Object o = JSON.toJSON(generic2PersonInfo);\n            {\n                Ageneric personInfo = (Ageneric) PojoUtils.realize(o, Ageneric.class);\n\n                assertEquals(Ageneric.NAME, personInfo.getName());\n                assertTrue(personInfo.getData() instanceof Map);\n            }\n            {\n                Type[] createGenericPersonInfos = ReflectUtils.getReturnTypes(\n                        PojoUtilsTest.class.getDeclaredMethod(\"createAGenericLoop\", String.class));\n                Ageneric personInfo = (Ageneric)\n                        PojoUtils.realize(o, (Class) createGenericPersonInfos[0], createGenericPersonInfos[1]);\n\n                assertEquals(Ageneric.NAME, personInfo.getName());\n                assertEquals(personInfo.getData().getClass(), Ageneric.class);\n                assertEquals(Ageneric.NAME, ((Ageneric) personInfo.getData()).getName());\n                assertEquals(((Ageneric) personInfo.getData()).getData().getClass(), PersonInfo.class);\n                assertEquals(personName, ((PersonInfo) ((Ageneric) personInfo.getData()).getData()).getName());\n            }\n        }\n        {\n            Bgeneric<Ageneric<PersonInfo>> generic = createBGenericWithAgeneric(personName);\n            Object o = JSON.toJSON(generic);\n            {\n                Ageneric personInfo = (Ageneric) PojoUtils.realize(o, Ageneric.class);\n\n                assertEquals(Bgeneric.NAME, personInfo.getName());\n                assertTrue(personInfo.getData() instanceof Map);\n            }\n            {\n                Type[] createGenericPersonInfos = ReflectUtils.getReturnTypes(\n                        PojoUtilsTest.class.getDeclaredMethod(\"createBGenericWithAgeneric\", String.class));\n                Bgeneric personInfo = (Bgeneric)\n                        PojoUtils.realize(o, (Class) createGenericPersonInfos[0], createGenericPersonInfos[1]);\n\n                assertEquals(Bgeneric.NAME, personInfo.getName());\n                assertEquals(personInfo.getData().getClass(), Ageneric.class);\n                assertEquals(Ageneric.NAME, ((Ageneric) personInfo.getData()).getName());\n                assertEquals(((Ageneric) personInfo.getData()).getData().getClass(), PersonInfo.class);\n                assertEquals(personName, ((PersonInfo) ((Ageneric) personInfo.getData()).getData()).getName());\n            }\n        }\n    }\n\n    protected Cgeneric<PersonInfo> createCGenericPersonInfo(String name) {\n        Cgeneric<PersonInfo> ret = new Cgeneric();\n        ret.setData(createPersonInfoByName(name));\n        ret.setA(createAGenericPersonInfo(name));\n        ret.setB(createBGenericPersonInfo(name));\n        return ret;\n    }\n\n    @Test\n    public void testPojoGeneric3() throws NoSuchMethodException {\n        String personName = \"testName\";\n\n        Cgeneric<PersonInfo> generic = createCGenericPersonInfo(personName);\n        Object o = JSON.toJSON(generic);\n        {\n            Cgeneric personInfo = (Cgeneric) PojoUtils.realize(o, Cgeneric.class);\n\n            assertEquals(Cgeneric.NAME, personInfo.getName());\n            assertTrue(personInfo.getData() instanceof Map);\n            assertTrue(personInfo.getA().getData() instanceof Map);\n            assertTrue(personInfo.getB().getData() instanceof PersonInfo);\n        }\n        {\n            Type[] createGenericPersonInfos = ReflectUtils.getReturnTypes(\n                    PojoUtilsTest.class.getDeclaredMethod(\"createCGenericPersonInfo\", String.class));\n            Cgeneric personInfo =\n                    (Cgeneric) PojoUtils.realize(o, (Class) createGenericPersonInfos[0], createGenericPersonInfos[1]);\n\n            assertEquals(Cgeneric.NAME, personInfo.getName());\n            assertEquals(personInfo.getData().getClass(), PersonInfo.class);\n            assertEquals(personName, ((PersonInfo) personInfo.getData()).getName());\n\n            assertEquals(personInfo.getA().getClass(), Ageneric.class);\n            assertEquals(personInfo.getA().getData().getClass(), PersonInfo.class);\n            assertEquals(personInfo.getB().getClass(), Bgeneric.class);\n            assertEquals(personInfo.getB().getData().getClass(), PersonInfo.class);\n        }\n    }\n\n    protected Dgeneric<Ageneric<PersonInfo>, Bgeneric<PersonInfo>, Cgeneric<PersonInfo>> createDGenericPersonInfo(\n            String name) {\n        Dgeneric<Ageneric<PersonInfo>, Bgeneric<PersonInfo>, Cgeneric<PersonInfo>> ret = new Dgeneric();\n        ret.setT(createAGenericPersonInfo(name));\n        ret.setY(createBGenericPersonInfo(name));\n        ret.setZ(createCGenericPersonInfo(name));\n        return ret;\n    }\n\n    @Test\n    public void testPojoGeneric4() throws NoSuchMethodException {\n        String personName = \"testName\";\n\n        Dgeneric generic = createDGenericPersonInfo(personName);\n        Object o = JSON.toJSON(generic);\n        {\n            Dgeneric personInfo = (Dgeneric) PojoUtils.realize(o, Dgeneric.class);\n\n            assertEquals(Dgeneric.NAME, personInfo.getName());\n            assertTrue(personInfo.getT() instanceof Map);\n            assertTrue(personInfo.getY() instanceof Map);\n            assertTrue(personInfo.getZ() instanceof Map);\n        }\n        {\n            Type[] createGenericPersonInfos = ReflectUtils.getReturnTypes(\n                    PojoUtilsTest.class.getDeclaredMethod(\"createDGenericPersonInfo\", String.class));\n            Dgeneric personInfo =\n                    (Dgeneric) PojoUtils.realize(o, (Class) createGenericPersonInfos[0], createGenericPersonInfos[1]);\n\n            assertEquals(Dgeneric.NAME, personInfo.getName());\n\n            assertEquals(personInfo.getT().getClass(), Ageneric.class);\n            assertEquals(((Ageneric) personInfo.getT()).getData().getClass(), PersonInfo.class);\n            assertEquals(personInfo.getY().getClass(), Bgeneric.class);\n            assertEquals(((Bgeneric) personInfo.getY()).getData().getClass(), PersonInfo.class);\n            assertEquals(personInfo.getZ().getClass(), Cgeneric.class);\n            assertEquals(((Cgeneric) personInfo.getZ()).getData().getClass(), PersonInfo.class);\n\n            assertEquals(personInfo.getZ().getClass(), Cgeneric.class);\n            assertEquals(((Cgeneric) personInfo.getZ()).getA().getClass(), Ageneric.class);\n            assertEquals(((Cgeneric) personInfo.getZ()).getA().getData().getClass(), PersonInfo.class);\n            assertEquals(((Cgeneric) personInfo.getZ()).getB().getClass(), Bgeneric.class);\n            assertEquals(((Cgeneric) personInfo.getZ()).getB().getData().getClass(), PersonInfo.class);\n        }\n    }\n\n    @Test\n    void testNameNotMatch() {\n        NameNotMatch origin = new NameNotMatch();\n        origin.setNameA(\"test123\");\n        origin.setNameB(\"test234\");\n\n        Object generalized = PojoUtils.generalize(origin);\n\n        Assertions.assertInstanceOf(Map.class, generalized);\n        Assertions.assertEquals(\"test123\", ((Map) generalized).get(\"nameA\"));\n        Assertions.assertEquals(\"test234\", ((Map) generalized).get(\"nameB\"));\n\n        NameNotMatch target1 =\n                (NameNotMatch) PojoUtils.realize(PojoUtils.generalize(origin), NameNotMatch.class, NameNotMatch.class);\n        Assertions.assertEquals(origin, target1);\n\n        Map<String, String> map = new HashMap<>();\n        map.put(\"nameA\", \"test123\");\n        map.put(\"nameB\", \"test234\");\n\n        NameNotMatch target2 = (NameNotMatch) PojoUtils.realize(map, NameNotMatch.class, NameNotMatch.class);\n        Assertions.assertEquals(origin, target2);\n    }\n\n    class NameNotMatch implements Serializable {\n        private String NameA;\n        private String NameAbsent;\n\n        public void setNameA(String nameA) {\n            this.NameA = nameA;\n        }\n\n        public String getNameA() {\n            return NameA;\n        }\n\n        public void setNameB(String nameB) {\n            this.NameAbsent = nameB;\n        }\n\n        public String getNameB() {\n            return NameAbsent;\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            NameNotMatch that = (NameNotMatch) o;\n            return Objects.equals(NameA, that.NameA) && Objects.equals(NameAbsent, that.NameAbsent);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(NameA, NameAbsent);\n        }\n    }\n\n    public enum Day {\n        SUNDAY,\n        MONDAY,\n        TUESDAY,\n        WEDNESDAY,\n        THURSDAY,\n        FRIDAY,\n        SATURDAY\n    }\n\n    public static class BasicTestData implements Serializable {\n\n        public boolean a;\n        public char b;\n        public byte c;\n        public short d;\n        public int e;\n        public long f;\n        public float g;\n        public double h;\n\n        public BasicTestData(boolean a, char b, byte c, short d, int e, long f, float g, double h) {\n            this.a = a;\n            this.b = b;\n            this.c = c;\n            this.d = d;\n            this.e = e;\n            this.f = f;\n            this.g = g;\n            this.h = h;\n        }\n\n        @Override\n        public int hashCode() {\n            final int prime = 31;\n            int result = 1;\n            result = prime * result + (a ? 1 : 2);\n            result = prime * result + b;\n            result = prime * result + c;\n            result = prime * result + c;\n            result = prime * result + e;\n            result = (int) (prime * result + f);\n            result = (int) (prime * result + g);\n            result = (int) (prime * result + h);\n            return result;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) return true;\n            if (obj == null) return false;\n            if (getClass() != obj.getClass()) return false;\n            BasicTestData other = (BasicTestData) obj;\n            if (a != other.a) {\n                return false;\n            }\n            if (b != other.b) {\n                return false;\n            }\n            if (c != other.c) {\n                return false;\n            }\n            if (e != other.e) {\n                return false;\n            }\n            if (f != other.f) {\n                return false;\n            }\n            if (g != other.g) {\n                return false;\n            }\n            if (h != other.h) {\n                return false;\n            }\n            return true;\n        }\n    }\n\n    public static class Parent implements Serializable {\n        public String gender;\n        public String email;\n        String name;\n        int age;\n        Child child;\n        private String securityEmail;\n\n        public static Parent getNewParent() {\n            return new Parent();\n        }\n\n        public String getEmail() {\n            return this.securityEmail;\n        }\n\n        public void setEmail(String email) {\n            this.securityEmail = email;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public int getAge() {\n            return age;\n        }\n\n        public void setAge(int age) {\n            this.age = age;\n        }\n\n        public Child getChild() {\n            return child;\n        }\n\n        public void setChild(Child child) {\n            this.child = child;\n        }\n    }\n\n    public static class Child implements Serializable {\n        public String gender;\n        public int age;\n        String toy;\n        Parent parent;\n        private String name;\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public int getAge() {\n            return age;\n        }\n\n        public void setAge(int age) {\n            this.age = age;\n        }\n\n        public String getToy() {\n            return toy;\n        }\n\n        public void setToy(String toy) {\n            this.toy = toy;\n        }\n\n        public Parent getParent() {\n            return parent;\n        }\n\n        public void setParent(Parent parent) {\n            this.parent = parent;\n        }\n    }\n\n    public static class TestData implements Serializable {\n        private Map<String, Child> children = new HashMap<String, Child>();\n        private List<Child> list = new ArrayList<Child>();\n\n        public List<Child> getList() {\n            return list;\n        }\n\n        public void setList(List<Child> list) {\n            if (CollectionUtils.isNotEmpty(list)) {\n                this.list.addAll(list);\n            }\n        }\n\n        public Map<String, Child> getChildren() {\n            return children;\n        }\n\n        public void setChildren(Map<String, Child> children) {\n            if (CollectionUtils.isNotEmptyMap(children)) {\n                this.children.putAll(children);\n            }\n        }\n\n        public void addChild(Child child) {\n            this.children.put(child.getName(), child);\n        }\n    }\n\n    public static class InnerPojo<T> implements Serializable {\n        private List<T> list;\n\n        public List<T> getList() {\n            return list;\n        }\n\n        public void setList(List<T> list) {\n            this.list = list;\n        }\n    }\n\n    public static class ListResult<T> implements Serializable {\n        List<T> result;\n\n        public List<T> getResult() {\n            return result;\n        }\n\n        public void setResult(List<T> result) {\n            this.result = result;\n        }\n    }\n\n    interface Message {\n        String getContent();\n\n        String getFrom();\n\n        boolean isUrgent();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/ProtobufUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.vo.UserVo;\nimport org.apache.dubbo.rpc.model.HelloReply;\nimport org.apache.dubbo.rpc.model.HelloRequest;\nimport org.apache.dubbo.rpc.model.Person;\nimport org.apache.dubbo.rpc.model.SerializablePerson;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ProtobufUtilsTest {\n\n    @Test\n    void testIsProtobufClass() {\n        Assertions.assertTrue(ProtobufUtils.isProtobufClass(HelloRequest.class));\n        Assertions.assertTrue(ProtobufUtils.isProtobufClass(HelloReply.class));\n        Assertions.assertFalse(ProtobufUtils.isProtobufClass(Person.class));\n        Assertions.assertFalse(ProtobufUtils.isProtobufClass(SerializablePerson.class));\n        Assertions.assertFalse(ProtobufUtils.isProtobufClass(UserVo.class));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/ReflectUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasKey;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.sameInstance;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass ReflectUtilsTest {\n    @Test\n    void testIsPrimitives() {\n        assertTrue(ReflectUtils.isPrimitives(boolean[].class));\n        assertTrue(ReflectUtils.isPrimitives(byte.class));\n        assertFalse(ReflectUtils.isPrimitive(Map[].class));\n    }\n\n    @Test\n    void testIsPrimitive() {\n        assertTrue(ReflectUtils.isPrimitive(boolean.class));\n        assertTrue(ReflectUtils.isPrimitive(String.class));\n        assertTrue(ReflectUtils.isPrimitive(Boolean.class));\n        assertTrue(ReflectUtils.isPrimitive(Character.class));\n        assertTrue(ReflectUtils.isPrimitive(Number.class));\n        assertTrue(ReflectUtils.isPrimitive(Date.class));\n        assertFalse(ReflectUtils.isPrimitive(Map.class));\n    }\n\n    @Test\n    void testGetBoxedClass() {\n        assertThat(ReflectUtils.getBoxedClass(int.class), sameInstance(Integer.class));\n        assertThat(ReflectUtils.getBoxedClass(boolean.class), sameInstance(Boolean.class));\n        assertThat(ReflectUtils.getBoxedClass(long.class), sameInstance(Long.class));\n        assertThat(ReflectUtils.getBoxedClass(float.class), sameInstance(Float.class));\n        assertThat(ReflectUtils.getBoxedClass(double.class), sameInstance(Double.class));\n        assertThat(ReflectUtils.getBoxedClass(char.class), sameInstance(Character.class));\n        assertThat(ReflectUtils.getBoxedClass(byte.class), sameInstance(Byte.class));\n        assertThat(ReflectUtils.getBoxedClass(short.class), sameInstance(Short.class));\n        assertThat(ReflectUtils.getBoxedClass(String.class), sameInstance(String.class));\n    }\n\n    @Test\n    void testIsCompatible() {\n        assertTrue(ReflectUtils.isCompatible(short.class, (short) 1));\n        assertTrue(ReflectUtils.isCompatible(int.class, 1));\n        assertTrue(ReflectUtils.isCompatible(double.class, 1.2));\n        assertTrue(ReflectUtils.isCompatible(Object.class, 1.2));\n        assertTrue(ReflectUtils.isCompatible(List.class, new ArrayList<String>()));\n    }\n\n    @Test\n    void testIsCompatibleWithArray() {\n        assertFalse(ReflectUtils.isCompatible(new Class[] {short.class, int.class}, new Object[] {(short) 1}));\n        assertFalse(ReflectUtils.isCompatible(new Class[] {double.class}, new Object[] {\"hello\"}));\n        assertTrue(ReflectUtils.isCompatible(new Class[] {double.class}, new Object[] {1.2}));\n    }\n\n    @Test\n    void testGetCodeBase() {\n        assertNull(ReflectUtils.getCodeBase(null));\n        assertNull(ReflectUtils.getCodeBase(String.class));\n        assertNotNull(ReflectUtils.getCodeBase(ReflectUtils.class));\n    }\n\n    @Test\n    void testGetName() {\n        // getName\n        assertEquals(\"boolean\", ReflectUtils.getName(boolean.class));\n        assertEquals(\"int[][][]\", ReflectUtils.getName(int[][][].class));\n        assertEquals(\"java.lang.Object[][]\", ReflectUtils.getName(Object[][].class));\n    }\n\n    @Test\n    void testGetDesc() {\n        // getDesc\n        assertEquals(\"Z\", ReflectUtils.getDesc(boolean.class));\n        assertEquals(\"[[[I\", ReflectUtils.getDesc(int[][][].class));\n        assertEquals(\"[[Ljava/lang/Object;\", ReflectUtils.getDesc(Object[][].class));\n    }\n\n    @Test\n    void testName2desc() {\n        // name2desc\n        assertEquals(\"Z\", ReflectUtils.name2desc(ReflectUtils.getName(boolean.class)));\n        assertEquals(\"[[[I\", ReflectUtils.name2desc(ReflectUtils.getName(int[][][].class)));\n        assertEquals(\"[[Ljava/lang/Object;\", ReflectUtils.name2desc(ReflectUtils.getName(Object[][].class)));\n    }\n\n    @Test\n    void testDesc2name() {\n        // desc2name\n        assertEquals(\"short[]\", ReflectUtils.desc2name(ReflectUtils.getDesc(short[].class)));\n        assertEquals(\"boolean[]\", ReflectUtils.desc2name(ReflectUtils.getDesc(boolean[].class)));\n        assertEquals(\"byte[]\", ReflectUtils.desc2name(ReflectUtils.getDesc(byte[].class)));\n        assertEquals(\"char[]\", ReflectUtils.desc2name(ReflectUtils.getDesc(char[].class)));\n        assertEquals(\"double[]\", ReflectUtils.desc2name(ReflectUtils.getDesc(double[].class)));\n        assertEquals(\"float[]\", ReflectUtils.desc2name(ReflectUtils.getDesc(float[].class)));\n        assertEquals(\"int[]\", ReflectUtils.desc2name(ReflectUtils.getDesc(int[].class)));\n        assertEquals(\"long[]\", ReflectUtils.desc2name(ReflectUtils.getDesc(long[].class)));\n        assertEquals(\"int\", ReflectUtils.desc2name(ReflectUtils.getDesc(int.class)));\n        assertEquals(\"void\", ReflectUtils.desc2name(ReflectUtils.getDesc(void.class)));\n        assertEquals(\"java.lang.Object[][]\", ReflectUtils.desc2name(ReflectUtils.getDesc(Object[][].class)));\n    }\n\n    @Test\n    void testGetGenericClass() {\n        assertThat(ReflectUtils.getGenericClass(Foo1.class), sameInstance(String.class));\n    }\n\n    @Test\n    void testGetGenericClassWithIndex() {\n        assertThat(ReflectUtils.getGenericClass(Foo1.class, 0), sameInstance(String.class));\n        assertThat(ReflectUtils.getGenericClass(Foo1.class, 1), sameInstance(Integer.class));\n        assertThat(ReflectUtils.getGenericClass(Foo2.class, 0), sameInstance(List.class));\n        assertThat(ReflectUtils.getGenericClass(Foo2.class, 1), sameInstance(int.class));\n        assertThat(ReflectUtils.getGenericClass(Foo3.class, 0), sameInstance(Foo1.class));\n        assertThat(ReflectUtils.getGenericClass(Foo3.class, 1), sameInstance(Foo2.class));\n    }\n\n    @Test\n    void testGetMethodName() throws Exception {\n        assertThat(\n                ReflectUtils.getName(Foo2.class.getDeclaredMethod(\"hello\", int[].class)),\n                equalTo(\"java.util.List hello(int[])\"));\n    }\n\n    @Test\n    void testGetSignature() throws Exception {\n        Method m = Foo2.class.getDeclaredMethod(\"hello\", int[].class);\n        assertThat(ReflectUtils.getSignature(\"greeting\", m.getParameterTypes()), equalTo(\"greeting([I)\"));\n    }\n\n    @Test\n    void testGetConstructorName() {\n        Constructor c = Foo2.class.getConstructors()[0];\n        assertThat(ReflectUtils.getName(c), equalTo(\"(java.util.List,int[])\"));\n    }\n\n    @Test\n    void testName2Class() throws Exception {\n        assertEquals(boolean.class, ReflectUtils.name2class(\"boolean\"));\n        assertEquals(boolean[].class, ReflectUtils.name2class(\"boolean[]\"));\n        assertEquals(int[][].class, ReflectUtils.name2class(ReflectUtils.getName(int[][].class)));\n        assertEquals(ReflectUtilsTest[].class, ReflectUtils.name2class(ReflectUtils.getName(ReflectUtilsTest[].class)));\n    }\n\n    @Test\n    void testGetDescMethod() throws Exception {\n        assertThat(\n                ReflectUtils.getDesc(Foo2.class.getDeclaredMethod(\"hello\", int[].class)),\n                equalTo(\"hello([I)Ljava/util/List;\"));\n    }\n\n    @Test\n    void testGetDescConstructor() {\n        assertThat(ReflectUtils.getDesc(Foo2.class.getConstructors()[0]), equalTo(\"(Ljava/util/List;[I)V\"));\n    }\n\n    @Test\n    void testGetDescWithoutMethodName() throws Exception {\n        assertThat(\n                ReflectUtils.getDescWithoutMethodName(Foo2.class.getDeclaredMethod(\"hello\", int[].class)),\n                equalTo(\"([I)Ljava/util/List;\"));\n    }\n\n    @Test\n    void testFindMethodByMethodName1() throws Exception {\n        assertNotNull(ReflectUtils.findMethodByMethodName(Foo.class, \"hello\"));\n    }\n\n    @Test\n    void testFindMethodByMethodName2() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            ReflectUtils.findMethodByMethodName(Foo2.class, \"hello\");\n        });\n    }\n\n    @Test\n    void testFindConstructor() throws Exception {\n        Constructor constructor = ReflectUtils.findConstructor(Foo3.class, Foo2.class);\n        assertNotNull(constructor);\n    }\n\n    @Test\n    void testIsInstance() {\n        assertTrue(ReflectUtils.isInstance(new Foo1(), Foo.class.getName()));\n    }\n\n    @Test\n    void testIsBeanPropertyReadMethod() throws Exception {\n        Method method = EmptyClass.class.getMethod(\"getProperty\");\n        assertTrue(ReflectUtils.isBeanPropertyReadMethod(method));\n        method = EmptyClass.class.getMethod(\"getProperties\");\n        assertFalse(ReflectUtils.isBeanPropertyReadMethod(method));\n        method = EmptyClass.class.getMethod(\"isProperty\");\n        assertFalse(ReflectUtils.isBeanPropertyReadMethod(method));\n        method = EmptyClass.class.getMethod(\"getPropertyIndex\", int.class);\n        assertFalse(ReflectUtils.isBeanPropertyReadMethod(method));\n    }\n\n    @Test\n    void testGetPropertyNameFromBeanReadMethod() throws Exception {\n        Method method = EmptyClass.class.getMethod(\"getProperty\");\n        assertEquals(\"property\", ReflectUtils.getPropertyNameFromBeanReadMethod(method));\n        method = EmptyClass.class.getMethod(\"isSet\");\n        assertEquals(\"set\", ReflectUtils.getPropertyNameFromBeanReadMethod(method));\n    }\n\n    @Test\n    void testIsBeanPropertyWriteMethod() throws Exception {\n        Method method = EmptyClass.class.getMethod(\"setProperty\", EmptyProperty.class);\n        assertTrue(ReflectUtils.isBeanPropertyWriteMethod(method));\n        method = EmptyClass.class.getMethod(\"setSet\", boolean.class);\n        assertTrue(ReflectUtils.isBeanPropertyWriteMethod(method));\n    }\n\n    @Test\n    void testGetPropertyNameFromBeanWriteMethod() throws Exception {\n        Method method = EmptyClass.class.getMethod(\"setProperty\", EmptyProperty.class);\n        assertEquals(\"property\", ReflectUtils.getPropertyNameFromBeanWriteMethod(method));\n    }\n\n    @Test\n    void testIsPublicInstanceField() throws Exception {\n        Field field = EmptyClass.class.getDeclaredField(\"set\");\n        assertTrue(ReflectUtils.isPublicInstanceField(field));\n        field = EmptyClass.class.getDeclaredField(\"property\");\n        assertFalse(ReflectUtils.isPublicInstanceField(field));\n    }\n\n    @Test\n    void testGetBeanPropertyFields() {\n        Map<String, Field> map = ReflectUtils.getBeanPropertyFields(EmptyClass.class);\n        assertThat(map.size(), is(2));\n        assertThat(map, hasKey(\"set\"));\n        assertThat(map, hasKey(\"property\"));\n        for (Field f : map.values()) {\n            if (!f.isAccessible()) {\n                fail();\n            }\n        }\n    }\n\n    @Test\n    void testGetBeanPropertyReadMethods() {\n        Map<String, Method> map = ReflectUtils.getBeanPropertyReadMethods(EmptyClass.class);\n        assertThat(map.size(), is(2));\n        assertThat(map, hasKey(\"set\"));\n        assertThat(map, hasKey(\"property\"));\n        for (Method m : map.values()) {\n            if (!m.isAccessible()) {\n                fail();\n            }\n        }\n    }\n\n    @Test\n    void testDesc2Class() throws Exception {\n        assertEquals(void.class, ReflectUtils.desc2class(\"V\"));\n        assertEquals(boolean.class, ReflectUtils.desc2class(\"Z\"));\n        assertEquals(boolean[].class, ReflectUtils.desc2class(\"[Z\"));\n        assertEquals(byte.class, ReflectUtils.desc2class(\"B\"));\n        assertEquals(char.class, ReflectUtils.desc2class(\"C\"));\n        assertEquals(double.class, ReflectUtils.desc2class(\"D\"));\n        assertEquals(float.class, ReflectUtils.desc2class(\"F\"));\n        assertEquals(int.class, ReflectUtils.desc2class(\"I\"));\n        assertEquals(long.class, ReflectUtils.desc2class(\"J\"));\n        assertEquals(short.class, ReflectUtils.desc2class(\"S\"));\n        assertEquals(String.class, ReflectUtils.desc2class(\"Ljava.lang.String;\"));\n        assertEquals(int[][].class, ReflectUtils.desc2class(ReflectUtils.getDesc(int[][].class)));\n        assertEquals(ReflectUtilsTest[].class, ReflectUtils.desc2class(ReflectUtils.getDesc(ReflectUtilsTest[].class)));\n\n        String desc;\n        Class<?>[] cs;\n\n        cs = new Class<?>[] {int.class, getClass(), String.class, int[][].class, boolean[].class};\n        desc = ReflectUtils.getDesc(cs);\n        assertSame(cs, ReflectUtils.desc2classArray(desc));\n\n        cs = new Class<?>[] {};\n        desc = ReflectUtils.getDesc(cs);\n        assertSame(cs, ReflectUtils.desc2classArray(desc));\n\n        cs = new Class<?>[] {void.class, String[].class, int[][].class, ReflectUtilsTest[][].class};\n        desc = ReflectUtils.getDesc(cs);\n        assertSame(cs, ReflectUtils.desc2classArray(desc));\n    }\n\n    protected void assertSame(Class<?>[] cs1, Class<?>[] cs2) throws Exception {\n        assertEquals(cs1.length, cs2.length);\n        for (int i = 0; i < cs1.length; i++) assertEquals(cs1[i], cs2[i]);\n    }\n\n    @Test\n    void testFindMethodByMethodSignature() throws Exception {\n        Method m = ReflectUtils.findMethodByMethodSignature(TestedClass.class, \"method1\", null);\n\n        assertEquals(\"method1\", m.getName());\n        Class<?>[] parameterTypes = m.getParameterTypes();\n        assertEquals(1, parameterTypes.length);\n        assertEquals(int.class, parameterTypes[0]);\n    }\n\n    @Test\n    void testFindMethodByMethodSignature_override() throws Exception {\n        {\n            Method m =\n                    ReflectUtils.findMethodByMethodSignature(TestedClass.class, \"overrideMethod\", new String[] {\"int\"});\n\n            assertEquals(\"overrideMethod\", m.getName());\n            Class<?>[] parameterTypes = m.getParameterTypes();\n            assertEquals(1, parameterTypes.length);\n            assertEquals(int.class, parameterTypes[0]);\n        }\n        {\n            Method m = ReflectUtils.findMethodByMethodSignature(\n                    TestedClass.class, \"overrideMethod\", new String[] {\"java.lang.Integer\"});\n\n            assertEquals(\"overrideMethod\", m.getName());\n            Class<?>[] parameterTypes = m.getParameterTypes();\n            assertEquals(1, parameterTypes.length);\n            assertEquals(Integer.class, parameterTypes[0]);\n        }\n    }\n\n    @Test\n    void testFindMethodByMethodSignatureOverrideMoreThan1() throws Exception {\n        try {\n            ReflectUtils.findMethodByMethodSignature(TestedClass.class, \"overrideMethod\", null);\n            fail();\n        } catch (IllegalStateException expected) {\n            assertThat(expected.getMessage(), containsString(\"Not unique method for method name(\"));\n        }\n    }\n\n    @Test\n    void testFindMethodByMethodSignatureNotFound() throws Exception {\n        try {\n            ReflectUtils.findMethodByMethodSignature(TestedClass.class, \"doesNotExist\", null);\n            fail();\n        } catch (NoSuchMethodException expected) {\n            assertThat(expected.getMessage(), containsString(\"No such method \"));\n            assertThat(expected.getMessage(), containsString(\"in class\"));\n        }\n    }\n\n    @Test\n    void testGetEmptyObject() {\n        assertTrue(ReflectUtils.getEmptyObject(Collection.class) instanceof Collection);\n        assertTrue(ReflectUtils.getEmptyObject(List.class) instanceof List);\n        assertTrue(ReflectUtils.getEmptyObject(Set.class) instanceof Set);\n        assertTrue(ReflectUtils.getEmptyObject(Map.class) instanceof Map);\n        assertTrue(ReflectUtils.getEmptyObject(Object[].class) instanceof Object[]);\n\n        assertEquals(\"\", ReflectUtils.getEmptyObject(String.class));\n        assertEquals((short) 0, ReflectUtils.getEmptyObject(short.class));\n        assertEquals((byte) 0, ReflectUtils.getEmptyObject(byte.class));\n        assertEquals(0, ReflectUtils.getEmptyObject(int.class));\n        assertEquals(0L, ReflectUtils.getEmptyObject(long.class));\n        assertEquals((float) 0, ReflectUtils.getEmptyObject(float.class));\n        assertEquals((double) 0, ReflectUtils.getEmptyObject(double.class));\n        assertEquals('\\0', ReflectUtils.getEmptyObject(char.class));\n        assertEquals(Boolean.FALSE, ReflectUtils.getEmptyObject(boolean.class));\n\n        EmptyClass object = (EmptyClass) ReflectUtils.getEmptyObject(EmptyClass.class);\n        assertNotNull(object);\n        assertNotNull(object.getProperty());\n    }\n\n    @Test\n    void testForName1() {\n        assertThat(ReflectUtils.forName(ReflectUtils.class.getName()), sameInstance(ReflectUtils.class));\n    }\n\n    @Test\n    void testForName2() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            ReflectUtils.forName(\"a.c.d.e.F\");\n        });\n    }\n\n    @Test\n    void testGetReturnTypes() throws Exception {\n        Class<TypeClass> clazz = TypeClass.class;\n\n        Type[] types = ReflectUtils.getReturnTypes(clazz.getMethod(\"getFuture\"));\n        Assertions.assertEquals(\"java.lang.String\", types[0].getTypeName());\n        Assertions.assertEquals(\"java.lang.String\", types[1].getTypeName());\n\n        Type[] types1 = ReflectUtils.getReturnTypes(clazz.getMethod(\"getString\"));\n        Assertions.assertEquals(\"java.lang.String\", types1[0].getTypeName());\n        Assertions.assertEquals(\"java.lang.String\", types1[1].getTypeName());\n\n        Type[] types2 = ReflectUtils.getReturnTypes(clazz.getMethod(\"getT\"));\n        Assertions.assertEquals(\"java.lang.String\", types2[0].getTypeName());\n        Assertions.assertEquals(\"T\", types2[1].getTypeName());\n\n        Type[] types3 = ReflectUtils.getReturnTypes(clazz.getMethod(\"getS\"));\n        Assertions.assertEquals(\"java.lang.Object\", types3[0].getTypeName());\n        Assertions.assertEquals(\"S\", types3[1].getTypeName());\n\n        Type[] types4 = ReflectUtils.getReturnTypes(clazz.getMethod(\"getListFuture\"));\n        Assertions.assertEquals(\"java.util.List\", types4[0].getTypeName());\n        Assertions.assertEquals(\"java.util.List<java.lang.String>\", types4[1].getTypeName());\n\n        Type[] types5 = ReflectUtils.getReturnTypes(clazz.getMethod(\"getGenericWithUpperFuture\"));\n        // T extends String, the first arg should be the upper bound of param\n        Assertions.assertEquals(\"java.lang.String\", types5[0].getTypeName());\n        Assertions.assertEquals(\"T\", types5[1].getTypeName());\n\n        Type[] types6 = ReflectUtils.getReturnTypes(clazz.getMethod(\"getGenericFuture\"));\n        // default upper bound is Object\n        Assertions.assertEquals(\"java.lang.Object\", types6[0].getTypeName());\n        Assertions.assertEquals(\"S\", types6[1].getTypeName());\n    }\n\n    public interface TypeClass<T extends String, S> {\n\n        CompletableFuture<String> getFuture();\n\n        String getString();\n\n        T getT();\n\n        S getS();\n\n        CompletableFuture<List<String>> getListFuture();\n\n        CompletableFuture<T> getGenericWithUpperFuture();\n\n        CompletableFuture<S> getGenericFuture();\n    }\n\n    public static class EmptyClass {\n        private EmptyProperty property;\n        public boolean set;\n        public static String s;\n        private transient int i;\n\n        public EmptyProperty getProperty() {\n            return property;\n        }\n\n        public EmptyProperty getPropertyIndex(int i) {\n            return property;\n        }\n\n        public static EmptyProperty getProperties() {\n            return null;\n        }\n\n        public void isProperty() {}\n\n        public boolean isSet() {\n            return set;\n        }\n\n        public void setProperty(EmptyProperty property) {\n            this.property = property;\n        }\n\n        public void setSet(boolean set) {\n            this.set = set;\n        }\n    }\n\n    public static class EmptyProperty {}\n\n    static class TestedClass {\n        public void method1(int x) {}\n\n        public void overrideMethod(int x) {}\n\n        public void overrideMethod(Integer x) {}\n\n        public void overrideMethod(String s) {}\n\n        public void overrideMethod(String s1, String s2) {}\n    }\n\n    interface Foo<A, B> {\n        A hello(B b);\n    }\n\n    static class Foo1 implements Foo<String, Integer> {\n        @Override\n        public String hello(Integer integer) {\n            return null;\n        }\n    }\n\n    static class Foo2 implements Foo<List<String>, int[]> {\n        public Foo2(List<String> list, int[] ints) {}\n\n        @Override\n        public List<String> hello(int[] ints) {\n            return null;\n        }\n    }\n\n    static class Foo3 implements Foo<Foo1, Foo2> {\n        public Foo3(Foo foo) {}\n\n        @Override\n        public Foo1 hello(Foo2 foo2) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/RegexPropertiesTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass RegexPropertiesTest {\n    @Test\n    void testGetProperty() {\n        RegexProperties regexProperties = new RegexProperties();\n        regexProperties.setProperty(\"org.apache.dubbo.provider.*\", \"http://localhost:20880\");\n        regexProperties.setProperty(\"org.apache.dubbo.provider.config.*\", \"http://localhost:30880\");\n        regexProperties.setProperty(\"org.apache.dubbo.provider.config.demo\", \"http://localhost:40880\");\n        regexProperties.setProperty(\"org.apache.dubbo.consumer.*.demo\", \"http://localhost:50880\");\n        regexProperties.setProperty(\"*.service\", \"http://localhost:60880\");\n\n        Assertions.assertEquals(\n                \"http://localhost:20880\", regexProperties.getProperty(\"org.apache.dubbo.provider.cluster\"));\n        Assertions.assertEquals(\n                \"http://localhost:30880\", regexProperties.getProperty(\"org.apache.dubbo.provider.config.cluster\"));\n        Assertions.assertEquals(\n                \"http://localhost:40880\", regexProperties.getProperty(\"org.apache.dubbo.provider.config.demo\"));\n        Assertions.assertEquals(\n                \"http://localhost:50880\", regexProperties.getProperty(\"org.apache.dubbo.consumer.service.demo\"));\n        Assertions.assertEquals(\"http://localhost:60880\", regexProperties.getProperty(\"org.apache.dubbo.service\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeSecurityConfiguratorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.Vector;\n\nimport com.service.DemoService1;\nimport com.service.DemoService2;\nimport com.service.DemoService4;\nimport com.service.Params;\nimport com.service.Service;\nimport com.service.User;\nimport com.service.UserService;\nimport com.service.deep1.deep2.deep3.DemoService3;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass SerializeSecurityConfiguratorTest {\n\n    @Test\n    void test() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"java.util.HashMap\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.example.DemoInterface\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.sun.Interface1\"));\n        Assertions.assertTrue(ssm.getDisAllowedPrefix().contains(\"com.exampletest.DemoInterface\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.sun.Interface2\"));\n        Assertions.assertEquals(AllowClassNotifyListener.DEFAULT_STATUS, ssm.getCheckStatus());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testStatus1() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"Test\");\n        applicationConfig.setSerializeCheckStatus(SerializeCheckStatus.DISABLE.name());\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertEquals(SerializeCheckStatus.DISABLE, ssm.getCheckStatus());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testStatus2() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"Test\");\n        applicationConfig.setSerializeCheckStatus(SerializeCheckStatus.WARN.name());\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertEquals(SerializeCheckStatus.WARN, ssm.getCheckStatus());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testStatus3() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"Test\");\n        applicationConfig.setSerializeCheckStatus(SerializeCheckStatus.STRICT.name());\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertEquals(SerializeCheckStatus.STRICT, ssm.getCheckStatus());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testStatus4() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_OPEN_CHECK, \"false\");\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertEquals(SerializeCheckStatus.DISABLE, ssm.getCheckStatus());\n\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_OPEN_CHECK);\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testStatus5() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCK_ALL, \"true\");\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertEquals(SerializeCheckStatus.STRICT, ssm.getCheckStatus());\n\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCK_ALL);\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testConfig1() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_ALLOWED_LIST, \"test.package1, test.package2, ,\");\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"test.package1\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"test.package2\"));\n\n        SystemPropertyConfigUtils.clearSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_ALLOWED_LIST);\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testConfig2() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST, \"test.package1, test.package2, ,\");\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertTrue(ssm.getDisAllowedPrefix().contains(\"test.package1\"));\n        Assertions.assertTrue(ssm.getDisAllowedPrefix().contains(\"test.package2\"));\n\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCK_ALL);\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testConfig3() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_ALLOWED_LIST, \"test.package1, test.package2, ,\");\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST, \"test.package1, test.package2, ,\");\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"test.package1\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"test.package2\"));\n\n        SystemPropertyConfigUtils.clearSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_ALLOWED_LIST);\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCK_ALL);\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testSerializable1() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"Test\");\n        applicationConfig.setCheckSerializable(false);\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertFalse(ssm.isCheckSerializable());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testSerializable2() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        Assertions.assertTrue(ssm.isCheckSerializable());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testGeneric() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        serializeSecurityConfigurator.registerInterface(DemoService4.class);\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.service.DemoService4\"));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testGenericClass() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        serializeSecurityConfigurator.registerInterface(UserService.class);\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(UserService.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(Service.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(Params.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(User.class.getName()));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testRegister1() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        serializeSecurityConfigurator.registerInterface(DemoService1.class);\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.service.DemoService1\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo1\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo2\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo3\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo4\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo5\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo6\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo7\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo8\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Simple\"));\n\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(List.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(Set.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(Map.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(LinkedList.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(Vector.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(HashSet.class.getName()));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testRegister2() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        serializeSecurityConfigurator.registerInterface(DemoService2.class);\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.service.DemoService2\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo1\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo2\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo3\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo4\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo5\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo6\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo7\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Demo8\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.pojo.Simple\"));\n\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(List.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(Set.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(Map.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(LinkedList.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(Vector.class.getName()));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(HashSet.class.getName()));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testRegister3() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"Test\");\n        applicationConfig.setAutoTrustSerializeClass(false);\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        serializeSecurityConfigurator.registerInterface(DemoService1.class);\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.service.DemoService1\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.pojo.Demo1\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.pojo.Demo2\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.pojo.Demo3\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.pojo.Demo4\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.pojo.Demo5\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.pojo.Demo6\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.pojo.Demo7\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.pojo.Demo8\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.pojo.Simple\"));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testRegister4() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"Test\");\n        applicationConfig.setTrustSerializeClassLevel(4);\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        serializeSecurityConfigurator.registerInterface(DemoService3.class);\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.service.deep1.deep2.\"));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testRegister5() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"Test\");\n        applicationConfig.setTrustSerializeClassLevel(10);\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeSecurityConfigurator serializeSecurityConfigurator = new SerializeSecurityConfigurator(moduleModel);\n        serializeSecurityConfigurator.onAddClassLoader(\n                moduleModel, Thread.currentThread().getContextClassLoader());\n\n        serializeSecurityConfigurator.registerInterface(DemoService3.class);\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.service.deep1.deep2.deep3.DemoService3\"));\n\n        frameworkModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeSecurityManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass SerializeSecurityManagerTest {\n    @Test\n    void testPrefix() {\n        TestAllowClassNotifyListener.setCount(0);\n        SerializeSecurityManager ssm = new SerializeSecurityManager();\n        ssm.registerListener(new TestAllowClassNotifyListener());\n\n        ssm.addToAllowed(\"java.util.HashMap\");\n        ssm.addToAllowed(\"com.example.DemoInterface\");\n        ssm.addToAllowed(\"com.sun.Interface1\");\n        ssm.addToAllowed(\"com.sun.Interface2\");\n\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"java.util.HashMap\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.example.DemoInterface\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.sun.Interface1\"));\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.sun.Interface2\"));\n\n        Assertions.assertEquals(ssm.getAllowedPrefix(), TestAllowClassNotifyListener.getAllowedList());\n        Assertions.assertEquals(7, TestAllowClassNotifyListener.getCount());\n\n        ssm.addToDisAllowed(\"com.sun.Interface\");\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.sun.Interface1\"));\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.sun.Interface2\"));\n        Assertions.assertEquals(ssm.getDisAllowedPrefix(), TestAllowClassNotifyListener.getDisAllowedList());\n        Assertions.assertEquals(9, TestAllowClassNotifyListener.getCount());\n\n        ssm.addToAllowed(\"com.sun.Interface3\");\n        Assertions.assertFalse(ssm.getAllowedPrefix().contains(\"com.sun.Interface3\"));\n        Assertions.assertEquals(9, TestAllowClassNotifyListener.getCount());\n\n        ssm.addToAllowed(\"java.util.HashMap\");\n        Assertions.assertEquals(9, TestAllowClassNotifyListener.getCount());\n\n        ssm.addToDisAllowed(\"com.sun.Interface\");\n        Assertions.assertEquals(9, TestAllowClassNotifyListener.getCount());\n\n        ssm.addToAlwaysAllowed(\"com.sun.Interface3\");\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.sun.Interface3\"));\n        Assertions.assertEquals(10, TestAllowClassNotifyListener.getCount());\n\n        ssm.addToAlwaysAllowed(\"com.sun.Interface3\");\n        Assertions.assertTrue(ssm.getAllowedPrefix().contains(\"com.sun.Interface3\"));\n        Assertions.assertEquals(10, TestAllowClassNotifyListener.getCount());\n    }\n\n    @Test\n    void testStatus1() {\n        SerializeSecurityManager ssm = new SerializeSecurityManager();\n        ssm.registerListener(new TestAllowClassNotifyListener());\n\n        Assertions.assertEquals(AllowClassNotifyListener.DEFAULT_STATUS, ssm.getCheckStatus());\n        Assertions.assertEquals(AllowClassNotifyListener.DEFAULT_STATUS, TestAllowClassNotifyListener.getStatus());\n\n        ssm.setCheckStatus(SerializeCheckStatus.STRICT);\n        Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus());\n        Assertions.assertEquals(SerializeCheckStatus.STRICT, TestAllowClassNotifyListener.getStatus());\n\n        ssm.setCheckStatus(SerializeCheckStatus.WARN);\n        Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus());\n        Assertions.assertEquals(SerializeCheckStatus.WARN, TestAllowClassNotifyListener.getStatus());\n\n        ssm.setCheckStatus(SerializeCheckStatus.STRICT);\n        Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus());\n        Assertions.assertEquals(SerializeCheckStatus.WARN, TestAllowClassNotifyListener.getStatus());\n\n        ssm.setCheckStatus(SerializeCheckStatus.DISABLE);\n        Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus());\n        Assertions.assertEquals(SerializeCheckStatus.DISABLE, TestAllowClassNotifyListener.getStatus());\n\n        ssm.setCheckStatus(SerializeCheckStatus.STRICT);\n        Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus());\n        Assertions.assertEquals(SerializeCheckStatus.DISABLE, TestAllowClassNotifyListener.getStatus());\n\n        ssm.setCheckStatus(SerializeCheckStatus.WARN);\n        Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus());\n        Assertions.assertEquals(SerializeCheckStatus.DISABLE, TestAllowClassNotifyListener.getStatus());\n    }\n\n    @Test\n    void testStatus2() {\n        SerializeSecurityManager ssm = new SerializeSecurityManager();\n\n        ssm.setCheckStatus(SerializeCheckStatus.STRICT);\n        ssm.registerListener(new TestAllowClassNotifyListener());\n        Assertions.assertEquals(ssm.getCheckStatus(), TestAllowClassNotifyListener.getStatus());\n        Assertions.assertEquals(SerializeCheckStatus.STRICT, TestAllowClassNotifyListener.getStatus());\n    }\n\n    @Test\n    void testSerializable() {\n        SerializeSecurityManager ssm = new SerializeSecurityManager();\n        ssm.registerListener(new TestAllowClassNotifyListener());\n\n        Assertions.assertTrue(ssm.isCheckSerializable());\n        Assertions.assertTrue(TestAllowClassNotifyListener.isCheckSerializable());\n\n        ssm.setCheckSerializable(true);\n        Assertions.assertTrue(ssm.isCheckSerializable());\n        Assertions.assertTrue(TestAllowClassNotifyListener.isCheckSerializable());\n\n        ssm.setCheckSerializable(false);\n        Assertions.assertFalse(ssm.isCheckSerializable());\n        Assertions.assertFalse(TestAllowClassNotifyListener.isCheckSerializable());\n\n        ssm.setCheckSerializable(true);\n        Assertions.assertFalse(ssm.isCheckSerializable());\n        Assertions.assertFalse(TestAllowClassNotifyListener.isCheckSerializable());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/StackTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.EmptyStackException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\n\nclass StackTest {\n    @Test\n    void testOps() throws Exception {\n        Stack<String> stack = new Stack<String>();\n        stack.push(\"one\");\n        assertThat(stack.get(0), equalTo(\"one\"));\n        assertThat(stack.peek(), equalTo(\"one\"));\n        assertThat(stack.size(), equalTo(1));\n        stack.push(\"two\");\n        assertThat(stack.get(0), equalTo(\"one\"));\n        assertThat(stack.peek(), equalTo(\"two\"));\n        assertThat(stack.size(), equalTo(2));\n        assertThat(stack.set(0, \"three\"), equalTo(\"one\"));\n        assertThat(stack.remove(0), equalTo(\"three\"));\n        assertThat(stack.size(), equalTo(1));\n        assertThat(stack.isEmpty(), is(false));\n        assertThat(stack.get(0), equalTo(\"two\"));\n        assertThat(stack.peek(), equalTo(\"two\"));\n        assertThat(stack.pop(), equalTo(\"two\"));\n        assertThat(stack.isEmpty(), is(true));\n    }\n\n    @Test\n    void testClear() throws Exception {\n        Stack<String> stack = new Stack<String>();\n        stack.push(\"one\");\n        stack.push(\"two\");\n        assertThat(stack.isEmpty(), is(false));\n        stack.clear();\n        assertThat(stack.isEmpty(), is(true));\n    }\n\n    @Test\n    void testIllegalPop() throws Exception {\n        Assertions.assertThrows(EmptyStackException.class, () -> {\n            Stack<String> stack = new Stack<String>();\n            stack.pop();\n        });\n    }\n\n    @Test\n    void testIllegalPeek() throws Exception {\n        Assertions.assertThrows(EmptyStackException.class, () -> {\n            Stack<String> stack = new Stack<String>();\n            stack.peek();\n        });\n    }\n\n    @Test\n    void testIllegalGet() throws Exception {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            Stack<String> stack = new Stack<String>();\n            stack.get(1);\n        });\n    }\n\n    @Test\n    void testIllegalGetNegative() throws Exception {\n        Stack<String> stack = new Stack<String>();\n        stack.push(\"one\");\n        stack.get(-1);\n\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            stack.get(-10);\n        });\n    }\n\n    @Test\n    void testIllegalSet() throws Exception {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            Stack<String> stack = new Stack<String>();\n            stack.set(1, \"illegal\");\n        });\n    }\n\n    @Test\n    void testIllegalSetNegative() throws Exception {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            Stack<String> stack = new Stack<String>();\n            stack.set(-1, \"illegal\");\n        });\n    }\n\n    @Test\n    void testIllegalRemove() throws Exception {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            Stack<String> stack = new Stack<String>();\n            stack.remove(1);\n        });\n    }\n\n    @Test\n    void testIllegalRemoveNegative() throws Exception {\n        Stack<String> stack = new Stack<String>();\n        stack.push(\"one\");\n\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            stack.remove(-2);\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringConstantFieldValuePredicateTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.function.Predicate;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link StringConstantFieldValuePredicate} Test\n *\n * @since 2.7.8\n */\nclass StringConstantFieldValuePredicateTest {\n\n    public static final String S1 = \"1\";\n\n    public static final Object O1 = \"2\";\n\n    public static final Object O2 = 3;\n\n    @Test\n    void test() {\n        Predicate<String> predicate = of(getClass());\n        assertTrue(predicate.test(\"1\"));\n        assertTrue(predicate.test(\"2\"));\n        assertFalse(predicate.test(\"3\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.utils.CollectionUtils.ofSet;\nimport static org.apache.dubbo.common.utils.StringUtils.splitToList;\nimport static org.apache.dubbo.common.utils.StringUtils.splitToSet;\nimport static org.apache.dubbo.common.utils.StringUtils.startsWithIgnoreCase;\nimport static org.apache.dubbo.common.utils.StringUtils.toCommaDelimitedString;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.isEmptyOrNullString;\nimport static org.hamcrest.Matchers.nullValue;\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass StringUtilsTest {\n    @Test\n    void testLength() throws Exception {\n        assertThat(StringUtils.length(null), equalTo(0));\n        assertThat(StringUtils.length(\"abc\"), equalTo(3));\n    }\n\n    @Test\n    void testRepeat() throws Exception {\n        assertThat(StringUtils.repeat(null, 2), nullValue());\n        assertThat(StringUtils.repeat(\"\", 0), equalTo(\"\"));\n        assertThat(StringUtils.repeat(\"\", 2), equalTo(\"\"));\n        assertThat(StringUtils.repeat(\"a\", 3), equalTo(\"aaa\"));\n        assertThat(StringUtils.repeat(\"ab\", 2), equalTo(\"abab\"));\n        assertThat(StringUtils.repeat(\"a\", -2), equalTo(\"\"));\n        assertThat(StringUtils.repeat(null, null, 2), nullValue());\n        assertThat(StringUtils.repeat(null, \"x\", 2), nullValue());\n        assertThat(StringUtils.repeat(\"\", null, 0), equalTo(\"\"));\n        assertThat(StringUtils.repeat(\"\", \"\", 2), equalTo(\"\"));\n        assertThat(StringUtils.repeat(\"\", \"x\", 3), equalTo(\"xx\"));\n        assertThat(StringUtils.repeat(\"?\", \", \", 3), equalTo(\"?, ?, ?\"));\n        assertThat(StringUtils.repeat('e', 0), equalTo(\"\"));\n        assertThat(StringUtils.repeat('e', 3), equalTo(\"eee\"));\n    }\n\n    @Test\n    void testStripEnd() throws Exception {\n        assertThat(StringUtils.stripEnd(null, \"*\"), nullValue());\n        assertThat(StringUtils.stripEnd(\"\", null), equalTo(\"\"));\n        assertThat(StringUtils.stripEnd(\"abc\", \"\"), equalTo(\"abc\"));\n        assertThat(StringUtils.stripEnd(\"abc\", null), equalTo(\"abc\"));\n        assertThat(StringUtils.stripEnd(\"  abc\", null), equalTo(\"  abc\"));\n        assertThat(StringUtils.stripEnd(\"abc  \", null), equalTo(\"abc\"));\n        assertThat(StringUtils.stripEnd(\" abc \", null), equalTo(\" abc\"));\n        assertThat(StringUtils.stripEnd(\"  abcyx\", \"xyz\"), equalTo(\"  abc\"));\n        assertThat(StringUtils.stripEnd(\"120.00\", \".0\"), equalTo(\"12\"));\n    }\n\n    @Test\n    void testReplace() throws Exception {\n        assertThat(StringUtils.replace(null, \"*\", \"*\"), nullValue());\n        assertThat(StringUtils.replace(\"\", \"*\", \"*\"), equalTo(\"\"));\n        assertThat(StringUtils.replace(\"any\", null, \"*\"), equalTo(\"any\"));\n        assertThat(StringUtils.replace(\"any\", \"*\", null), equalTo(\"any\"));\n        assertThat(StringUtils.replace(\"any\", \"\", \"*\"), equalTo(\"any\"));\n        assertThat(StringUtils.replace(\"aba\", \"a\", null), equalTo(\"aba\"));\n        assertThat(StringUtils.replace(\"aba\", \"a\", \"\"), equalTo(\"b\"));\n        assertThat(StringUtils.replace(\"aba\", \"a\", \"z\"), equalTo(\"zbz\"));\n        assertThat(StringUtils.replace(null, \"*\", \"*\", 64), nullValue());\n        assertThat(StringUtils.replace(\"\", \"*\", \"*\", 64), equalTo(\"\"));\n        assertThat(StringUtils.replace(\"any\", null, \"*\", 64), equalTo(\"any\"));\n        assertThat(StringUtils.replace(\"any\", \"*\", null, 64), equalTo(\"any\"));\n        assertThat(StringUtils.replace(\"any\", \"\", \"*\", 64), equalTo(\"any\"));\n        assertThat(StringUtils.replace(\"any\", \"*\", \"*\", 0), equalTo(\"any\"));\n        assertThat(StringUtils.replace(\"abaa\", \"a\", null, -1), equalTo(\"abaa\"));\n        assertThat(StringUtils.replace(\"abaa\", \"a\", \"\", -1), equalTo(\"b\"));\n        assertThat(StringUtils.replace(\"abaa\", \"a\", \"z\", 0), equalTo(\"abaa\"));\n        assertThat(StringUtils.replace(\"abaa\", \"a\", \"z\", 1), equalTo(\"zbaa\"));\n        assertThat(StringUtils.replace(\"abaa\", \"a\", \"z\", 2), equalTo(\"zbza\"));\n    }\n\n    @Test\n    void testIsBlank() throws Exception {\n        assertTrue(StringUtils.isBlank(null));\n        assertTrue(StringUtils.isBlank(\"\"));\n        assertFalse(StringUtils.isBlank(\"abc\"));\n    }\n\n    @Test\n    void testIsEmpty() throws Exception {\n        assertTrue(StringUtils.isEmpty(null));\n        assertTrue(StringUtils.isEmpty(\"\"));\n        assertFalse(StringUtils.isEmpty(\"abc\"));\n    }\n\n    @Test\n    void testIsNoneEmpty() throws Exception {\n        assertFalse(StringUtils.isNoneEmpty(null));\n        assertFalse(StringUtils.isNoneEmpty(\"\"));\n        assertTrue(StringUtils.isNoneEmpty(\" \"));\n        assertTrue(StringUtils.isNoneEmpty(\"abc\"));\n        assertTrue(StringUtils.isNoneEmpty(\"abc\", \"def\"));\n        assertFalse(StringUtils.isNoneEmpty(\"abc\", null));\n        assertFalse(StringUtils.isNoneEmpty(\"abc\", \"\"));\n        assertTrue(StringUtils.isNoneEmpty(\"abc\", \" \"));\n    }\n\n    @Test\n    void testIsAnyEmpty() throws Exception {\n        assertTrue(StringUtils.isAnyEmpty(null));\n        assertTrue(StringUtils.isAnyEmpty(\"\"));\n        assertFalse(StringUtils.isAnyEmpty(\" \"));\n        assertFalse(StringUtils.isAnyEmpty(\"abc\"));\n        assertFalse(StringUtils.isAnyEmpty(\"abc\", \"def\"));\n        assertTrue(StringUtils.isAnyEmpty(\"abc\", null));\n        assertTrue(StringUtils.isAnyEmpty(\"abc\", \"\"));\n        assertFalse(StringUtils.isAnyEmpty(\"abc\", \" \"));\n    }\n\n    @Test\n    void testIsNotEmpty() throws Exception {\n        assertFalse(StringUtils.isNotEmpty(null));\n        assertFalse(StringUtils.isNotEmpty(\"\"));\n        assertTrue(StringUtils.isNotEmpty(\"abc\"));\n    }\n\n    @Test\n    void testIsEquals() throws Exception {\n        assertTrue(StringUtils.isEquals(null, null));\n        assertFalse(StringUtils.isEquals(null, \"\"));\n        assertTrue(StringUtils.isEquals(\"abc\", \"abc\"));\n        assertFalse(StringUtils.isEquals(\"abc\", \"ABC\"));\n    }\n\n    @Test\n    void testIsInteger() throws Exception {\n        assertFalse(StringUtils.isNumber(null));\n        assertFalse(StringUtils.isNumber(\"\"));\n        assertTrue(StringUtils.isNumber(\"123\"));\n    }\n\n    @Test\n    void testParseInteger() throws Exception {\n        assertThat(StringUtils.parseInteger(null), equalTo(0));\n        assertThat(StringUtils.parseInteger(\"123\"), equalTo(123));\n    }\n\n    @Test\n    void testIsJavaIdentifier() throws Exception {\n        assertThat(StringUtils.isJavaIdentifier(\"\"), is(false));\n        assertThat(StringUtils.isJavaIdentifier(\"1\"), is(false));\n        assertThat(StringUtils.isJavaIdentifier(\"abc123\"), is(true));\n        assertThat(StringUtils.isJavaIdentifier(\"abc(23)\"), is(false));\n    }\n\n    @Test\n    void testExceptionToString() throws Exception {\n        assertThat(\n                StringUtils.toString(new RuntimeException(\"abc\")), containsString(\"java.lang.RuntimeException: abc\"));\n    }\n\n    @Test\n    void testExceptionToStringWithMessage() throws Exception {\n        String s = StringUtils.toString(\"greeting\", new RuntimeException(\"abc\"));\n        assertThat(s, containsString(\"greeting\"));\n        assertThat(s, containsString(\"java.lang.RuntimeException: abc\"));\n    }\n\n    @Test\n    void testParseQueryString() throws Exception {\n        assertThat(StringUtils.getQueryStringValue(\"key1=value1&key2=value2\", \"key1\"), equalTo(\"value1\"));\n        assertThat(StringUtils.getQueryStringValue(\"key1=value1&key2=value2\", \"key2\"), equalTo(\"value2\"));\n        assertThat(StringUtils.getQueryStringValue(\"\", \"key1\"), isEmptyOrNullString());\n    }\n\n    @Test\n    void testGetServiceKey() throws Exception {\n        Map<String, String> map = new HashMap<String, String>();\n        map.put(GROUP_KEY, \"dubbo\");\n        map.put(INTERFACE_KEY, \"a.b.c.Foo\");\n        map.put(VERSION_KEY, \"1.0.0\");\n        assertThat(StringUtils.getServiceKey(map), equalTo(\"dubbo/a.b.c.Foo:1.0.0\"));\n    }\n\n    @Test\n    void testToQueryString() throws Exception {\n        Map<String, String> map = new HashMap<String, String>();\n        map.put(\"key1\", \"value1\");\n        map.put(\"key2\", \"value2\");\n        String queryString = StringUtils.toQueryString(map);\n        assertThat(queryString, containsString(\"key1=value1\"));\n        assertThat(queryString, containsString(\"key2=value2\"));\n    }\n\n    @Test\n    void testJoin() throws Exception {\n        String[] s = {\"1\", \"2\", \"3\"};\n        assertEquals(StringUtils.join(s), \"123\");\n        assertEquals(StringUtils.join(s, ','), \"1,2,3\");\n        assertEquals(StringUtils.join(s, \",\"), \"1,2,3\");\n        assertEquals(StringUtils.join(s, ',', 0, 1), \"1\");\n        assertEquals(StringUtils.join(s, ',', 0, 2), \"1,2\");\n        assertEquals(StringUtils.join(s, ',', 0, 3), \"1,2,3\");\n        assertEquals(\"\", StringUtils.join(s, ',', 2, 0), \"1,2\");\n    }\n\n    @Test\n    void testSplit() throws Exception {\n        String str = \"d,1,2,4\";\n\n        assertEquals(4, StringUtils.split(str, ',').length);\n        assertArrayEquals(str.split(\",\"), StringUtils.split(str, ','));\n\n        assertEquals(1, StringUtils.split(str, 'a').length);\n        assertArrayEquals(str.split(\"a\"), StringUtils.split(str, 'a'));\n\n        assertEquals(0, StringUtils.split(\"\", 'a').length);\n        assertEquals(0, StringUtils.split(null, 'a').length);\n    }\n\n    @Test\n    void testSplitToList() throws Exception {\n        String str = \"d,1,2,4\";\n\n        assertEquals(4, splitToList(str, ',').size());\n        assertEquals(asList(str.split(\",\")), splitToList(str, ','));\n\n        assertEquals(1, splitToList(str, 'a').size());\n        assertEquals(asList(str.split(\"a\")), splitToList(str, 'a'));\n\n        assertEquals(0, splitToList(\"\", 'a').size());\n        assertEquals(0, splitToList(null, 'a').size());\n    }\n\n    /**\n     * Test {@link StringUtils#splitToSet(String, char, boolean)}\n     *\n     * @since 2.7.8\n     */\n    @Test\n    void testSplitToSet() {\n        String value = \"1# 2#3 #4#3\";\n        Set<String> values = splitToSet(value, '#', false);\n        assertEquals(ofSet(\"1\", \" 2\", \"3 \", \"4\", \"3\"), values);\n\n        values = splitToSet(value, '#', true);\n        assertEquals(ofSet(\"1\", \"2\", \"3\", \"4\"), values);\n    }\n\n    @Test\n    void testTranslate() throws Exception {\n        String s = \"16314\";\n        assertEquals(StringUtils.translate(s, \"123456\", \"abcdef\"), \"afcad\");\n        assertEquals(StringUtils.translate(s, \"123456\", \"abcd\"), \"acad\");\n    }\n\n    @Test\n    void testIsContains() throws Exception {\n        assertThat(StringUtils.isContains(\"a,b, c\", \"b\"), is(true));\n        assertThat(StringUtils.isContains(\"\", \"b\"), is(false));\n        assertThat(StringUtils.isContains(new String[] {\"a\", \"b\", \"c\"}, \"b\"), is(true));\n        assertThat(StringUtils.isContains((String[]) null, null), is(false));\n\n        assertTrue(StringUtils.isContains(\"abc\", 'a'));\n        assertFalse(StringUtils.isContains(\"abc\", 'd'));\n        assertFalse(StringUtils.isContains(\"\", 'a'));\n        assertFalse(StringUtils.isContains(null, 'a'));\n\n        assertTrue(StringUtils.isNotContains(\"abc\", 'd'));\n        assertFalse(StringUtils.isNotContains(\"abc\", 'a'));\n        assertTrue(StringUtils.isNotContains(\"\", 'a'));\n        assertTrue(StringUtils.isNotContains(null, 'a'));\n    }\n\n    @Test\n    void testIsNumeric() throws Exception {\n        assertThat(StringUtils.isNumeric(\"123\", false), is(true));\n        assertThat(StringUtils.isNumeric(\"1a3\", false), is(false));\n        assertThat(StringUtils.isNumeric(null, false), is(false));\n\n        assertThat(StringUtils.isNumeric(\"0\", true), is(true));\n        assertThat(StringUtils.isNumeric(\"0.1\", true), is(true));\n        assertThat(StringUtils.isNumeric(\"DUBBO\", true), is(false));\n        assertThat(StringUtils.isNumeric(\"\", true), is(false));\n        assertThat(StringUtils.isNumeric(\" \", true), is(false));\n        assertThat(StringUtils.isNumeric(\"   \", true), is(false));\n\n        assertThat(StringUtils.isNumeric(\"123.3.3\", true), is(false));\n        assertThat(StringUtils.isNumeric(\"123.\", true), is(true));\n        assertThat(StringUtils.isNumeric(\".123\", true), is(true));\n        assertThat(StringUtils.isNumeric(\"..123\", true), is(false));\n    }\n\n    @Test\n    void testJoinCollectionString() throws Exception {\n        List<String> list = new ArrayList<String>();\n        assertEquals(\"\", StringUtils.join(list, \",\"));\n\n        list.add(\"v1\");\n        assertEquals(\"v1\", StringUtils.join(list, \"-\"));\n\n        list.add(\"v2\");\n        list.add(\"v3\");\n        String out = StringUtils.join(list, \":\");\n        assertEquals(\"v1:v2:v3\", out);\n    }\n\n    @Test\n    void testCamelToSplitName() throws Exception {\n        assertEquals(\"ab-cd-ef\", StringUtils.camelToSplitName(\"abCdEf\", \"-\"));\n        assertEquals(\"ab-cd-ef\", StringUtils.camelToSplitName(\"AbCdEf\", \"-\"));\n        assertEquals(\"abcdef\", StringUtils.camelToSplitName(\"abcdef\", \"-\"));\n        // assertEquals(\"name\", StringUtils.camelToSplitName(\"NAME\", \"-\"));\n\n        assertEquals(\"ab-cd-ef\", StringUtils.camelToSplitName(\"ab-cd-ef\", \"-\"));\n        assertEquals(\"ab-cd-ef\", StringUtils.camelToSplitName(\"Ab-Cd-Ef\", \"-\"));\n        assertEquals(\"Ab_Cd_Ef\", StringUtils.camelToSplitName(\"Ab_Cd_Ef\", \"-\"));\n        assertEquals(\"AB_CD_EF\", StringUtils.camelToSplitName(\"AB_CD_EF\", \"-\"));\n\n        assertEquals(\"ab.cd.ef\", StringUtils.camelToSplitName(\"AbCdEf\", \".\"));\n        // assertEquals(\"ab.cd.ef\", StringUtils.camelToSplitName(\"ab-cd-ef\", \".\"));\n    }\n\n    @Test\n    void testSnakeCaseToSplitName() throws Exception {\n        assertEquals(\"ab-cd-ef\", StringUtils.snakeToSplitName(\"ab_Cd_Ef\", \"-\"));\n        assertEquals(\"ab-cd-ef\", StringUtils.snakeToSplitName(\"Ab_Cd_Ef\", \"-\"));\n        assertEquals(\"ab-cd-ef\", StringUtils.snakeToSplitName(\"ab_cd_ef\", \"-\"));\n        assertEquals(\"ab-cd-ef\", StringUtils.snakeToSplitName(\"AB_CD_EF\", \"-\"));\n        assertEquals(\"abcdef\", StringUtils.snakeToSplitName(\"abcdef\", \"-\"));\n        assertEquals(\"qosEnable\", StringUtils.snakeToSplitName(\"qosEnable\", \"-\"));\n        assertEquals(\"name\", StringUtils.snakeToSplitName(\"NAME\", \"-\"));\n    }\n\n    @Test\n    void testConvertToSplitName() {\n        assertEquals(\"ab-cd-ef\", StringUtils.convertToSplitName(\"ab_Cd_Ef\", \"-\"));\n        assertEquals(\"ab-cd-ef\", StringUtils.convertToSplitName(\"Ab_Cd_Ef\", \"-\"));\n        assertEquals(\"ab-cd-ef\", StringUtils.convertToSplitName(\"ab_cd_ef\", \"-\"));\n        assertEquals(\"ab-cd-ef\", StringUtils.convertToSplitName(\"AB_CD_EF\", \"-\"));\n        assertEquals(\"abcdef\", StringUtils.convertToSplitName(\"abcdef\", \"-\"));\n        assertEquals(\"qos-enable\", StringUtils.convertToSplitName(\"qosEnable\", \"-\"));\n        assertEquals(\"name\", StringUtils.convertToSplitName(\"NAME\", \"-\"));\n\n        assertEquals(\"ab-cd-ef\", StringUtils.convertToSplitName(\"abCdEf\", \"-\"));\n        assertEquals(\"ab-cd-ef\", StringUtils.convertToSplitName(\"AbCdEf\", \"-\"));\n\n        assertEquals(\"ab-cd-ef\", StringUtils.convertToSplitName(\"ab-cd-ef\", \"-\"));\n        assertEquals(\"ab-cd-ef\", StringUtils.convertToSplitName(\"Ab-Cd-Ef\", \"-\"));\n    }\n\n    @Test\n    void testToArgumentString() throws Exception {\n        String s = StringUtils.toArgumentString(new Object[] {\"a\", 0, Collections.singletonMap(\"enabled\", true)});\n        assertThat(s, containsString(\"a,\"));\n        assertThat(s, containsString(\"0,\"));\n        assertThat(s, containsString(\"{\\\"enabled\\\":true}\"));\n    }\n\n    @Test\n    void testTrim() {\n        assertEquals(\"left blank\", StringUtils.trim(\" left blank\"));\n        assertEquals(\"right blank\", StringUtils.trim(\"right blank \"));\n        assertEquals(\"bi-side blank\", StringUtils.trim(\" bi-side blank \"));\n    }\n\n    @Test\n    void testToURLKey() {\n        assertEquals(\"dubbo.tag1\", StringUtils.toURLKey(\"dubbo_tag1\"));\n        assertEquals(\"dubbo.tag1.tag11\", StringUtils.toURLKey(\"dubbo-tag1_tag11\"));\n    }\n\n    @Test\n    void testToOSStyleKey() {\n        assertEquals(\"DUBBO_TAG1\", StringUtils.toOSStyleKey(\"dubbo_tag1\"));\n        assertEquals(\"DUBBO_TAG1\", StringUtils.toOSStyleKey(\"dubbo.tag1\"));\n        assertEquals(\"DUBBO_TAG1_TAG11\", StringUtils.toOSStyleKey(\"dubbo.tag1.tag11\"));\n        assertEquals(\"DUBBO_TAG1\", StringUtils.toOSStyleKey(\"tag1\"));\n    }\n\n    @Test\n    void testParseParameters() {\n        String legalStr = \"[{key1:value1},{key2:value2}]\";\n        Map<String, String> legalMap = StringUtils.parseParameters(legalStr);\n        assertEquals(2, legalMap.size());\n        assertEquals(\"value2\", legalMap.get(\"key2\"));\n\n        String str = StringUtils.encodeParameters(legalMap);\n        assertEqualsWithoutSpaces(legalStr, str);\n\n        String legalSpaceStr = \"[{key1: value1}, {key2 :value2}]\";\n        Map<String, String> legalSpaceMap = StringUtils.parseParameters(legalSpaceStr);\n        assertEquals(2, legalSpaceMap.size());\n        assertEquals(\"value2\", legalSpaceMap.get(\"key2\"));\n\n        str = StringUtils.encodeParameters(legalSpaceMap);\n        assertEqualsWithoutSpaces(legalSpaceStr, str);\n\n        String legalSpecialStr = \"[{key-1: value*.1}, {key.2 :value*.-_2}]\";\n        Map<String, String> legalSpecialMap = StringUtils.parseParameters(legalSpecialStr);\n        assertEquals(2, legalSpecialMap.size());\n        assertEquals(\"value*.1\", legalSpecialMap.get(\"key-1\"));\n        assertEquals(\"value*.-_2\", legalSpecialMap.get(\"key.2\"));\n\n        str = StringUtils.encodeParameters(legalSpecialMap);\n        assertEqualsWithoutSpaces(legalSpecialStr, str);\n\n        String illegalStr = \"[{key=value},{aa:bb}]\";\n        Map<String, String> illegalMap = StringUtils.parseParameters(illegalStr);\n        assertEquals(0, illegalMap.size());\n\n        str = StringUtils.encodeParameters(illegalMap);\n        assertEquals(null, str);\n\n        String emptyMapStr = \"[]\";\n        Map<String, String> emptyMap = StringUtils.parseParameters(emptyMapStr);\n        assertEquals(0, emptyMap.size());\n    }\n\n    @Test\n    void testEncodeParameters() {\n        Map<String, String> nullValueMap = new LinkedHashMap<>();\n        nullValueMap.put(\"client\", null);\n        String str = StringUtils.encodeParameters(nullValueMap);\n        assertEquals(\"[]\", str);\n\n        Map<String, String> blankValueMap = new LinkedHashMap<>();\n        blankValueMap.put(\"client\", \" \");\n        str = StringUtils.encodeParameters(nullValueMap);\n        assertEquals(\"[]\", str);\n\n        blankValueMap = new LinkedHashMap<>();\n        blankValueMap.put(\"client\", \"\");\n        str = StringUtils.encodeParameters(nullValueMap);\n        assertEquals(\"[]\", str);\n    }\n\n    private void assertEqualsWithoutSpaces(String expect, String actual) {\n        assertEquals(expect.replaceAll(\" \", \"\"), actual.replaceAll(\" \", \"\"));\n    }\n\n    /**\n     * Test {@link StringUtils#toCommaDelimitedString(String, String...)}\n     *\n     * @since 2.7.8\n     */\n    @Test\n    void testToCommaDelimitedString() {\n        String value = toCommaDelimitedString(null);\n        assertNull(value);\n\n        value = toCommaDelimitedString(null, null);\n        assertNull(value);\n\n        value = toCommaDelimitedString(\"one\", null);\n        assertEquals(\"one\", value);\n\n        value = toCommaDelimitedString(\"\");\n        assertEquals(\"\", value);\n\n        value = toCommaDelimitedString(\"one\");\n        assertEquals(\"one\", value);\n\n        value = toCommaDelimitedString(\"one\", \"two\");\n        assertEquals(\"one,two\", value);\n\n        value = toCommaDelimitedString(\"one\", \"two\", \"three\");\n        assertEquals(\"one,two,three\", value);\n    }\n\n    @Test\n    void testStartsWithIgnoreCase() {\n        assertTrue(startsWithIgnoreCase(\"dubbo.application.name\", \"dubbo.application.\"));\n        assertTrue(startsWithIgnoreCase(\"dubbo.Application.name\", \"dubbo.application.\"));\n        assertTrue(startsWithIgnoreCase(\"Dubbo.application.name\", \"dubbo.application.\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/SystemPropertyConfigUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrowsExactly;\n\npublic class SystemPropertyConfigUtilsTest {\n\n    @Test\n    public void testGetSystemProperty() {\n        SystemPropertyConfigUtils.setSystemProperty(\"dubbo.migration.file\", \"migration.xml\");\n        String value = SystemPropertyConfigUtils.getSystemProperty(\"dubbo.migration.file\");\n        assertEquals(value, \"migration.xml\");\n        SystemPropertyConfigUtils.clearSystemProperty(\"dubbo.migration.file\");\n    }\n\n    @Test\n    public void testGetSystemPropertyNotExist() {\n        assertThrowsExactly(\n                IllegalStateException.class, () -> SystemPropertyConfigUtils.getSystemProperty(\"dubbo.not.exist\"));\n    }\n\n    @Test\n    public void testGetSystemPropertyWithDefaultValue() {\n        String value = SystemPropertyConfigUtils.getSystemProperty(\"dubbo.migration.file\", \"migration.xml\");\n        assertEquals(value, \"migration.xml\");\n    }\n\n    @Test\n    public void testSetSystemProperty() {\n        SystemPropertyConfigUtils.setSystemProperty(\"dubbo.migration.file\", \"migration.xml\");\n        String expectValue = SystemPropertyConfigUtils.getSystemProperty(\"dubbo.migration.file\");\n        assertEquals(expectValue, \"migration.xml\");\n        SystemPropertyConfigUtils.clearSystemProperty(\"dubbo.migration.file\");\n    }\n\n    @Test\n    public void testClearSystemProperty() {\n        SystemPropertyConfigUtils.setSystemProperty(\"dubbo.migration.file\", \"migration33.xml\");\n        SystemPropertyConfigUtils.clearSystemProperty(\"dubbo.migration.file\");\n        String expectValue = SystemPropertyConfigUtils.getSystemProperty(\"dubbo.migration.file\");\n        assertNull(expectValue);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/TestAllowClassNotifyListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\npublic class TestAllowClassNotifyListener implements AllowClassNotifyListener {\n    private static final AtomicReference<SerializeCheckStatus> status = new AtomicReference<>();\n    private static final AtomicReference<Set<String>> allowedList = new AtomicReference<>();\n    private static final AtomicReference<Set<String>> disAllowedList = new AtomicReference<>();\n    private static final AtomicBoolean checkSerializable = new AtomicBoolean();\n\n    private static final AtomicInteger count = new AtomicInteger(0);\n\n    @Override\n    public void notifyPrefix(Set<String> allowedList, Set<String> disAllowedList) {\n        TestAllowClassNotifyListener.allowedList.set(allowedList);\n        TestAllowClassNotifyListener.disAllowedList.set(disAllowedList);\n        count.incrementAndGet();\n    }\n\n    @Override\n    public void notifyCheckStatus(SerializeCheckStatus status) {\n        TestAllowClassNotifyListener.status.set(status);\n        count.incrementAndGet();\n    }\n\n    @Override\n    public void notifyCheckSerializable(boolean checkSerializable) {\n        TestAllowClassNotifyListener.checkSerializable.set(checkSerializable);\n        count.incrementAndGet();\n    }\n\n    public static SerializeCheckStatus getStatus() {\n        return status.get();\n    }\n\n    public static Set<String> getAllowedList() {\n        return allowedList.get();\n    }\n\n    public static Set<String> getDisAllowedList() {\n        return disAllowedList.get();\n    }\n\n    public static boolean isCheckSerializable() {\n        return checkSerializable.get();\n    }\n\n    public static int getCount() {\n        return count.get();\n    }\n\n    public static void setCount(int count) {\n        TestAllowClassNotifyListener.count.set(count);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/TimeUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass TimeUtilsTest {\n\n    @Test\n    void testCurrentTimeMillis() {\n        assertTrue(0 < TimeUtils.currentTimeMillis());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/UrlUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass UrlUtilsTest {\n\n    String localAddress = \"127.0.0.1\";\n\n    @Test\n    void testAddressNull() {\n        String exceptionMessage = \"Address is not allowed to be empty, please re-enter.\";\n        try {\n            UrlUtils.parseURL(null, null);\n        } catch (IllegalArgumentException illegalArgumentException) {\n            assertEquals(exceptionMessage, illegalArgumentException.getMessage());\n        }\n    }\n\n    @Test\n    void testParseUrl() {\n        String address = \"remote://root:alibaba@127.0.0.1:9090/dubbo.test.api\";\n        URL url = UrlUtils.parseURL(address, null);\n        assertEquals(localAddress + \":9090\", url.getAddress());\n        assertEquals(\"root\", url.getUsername());\n        assertEquals(\"alibaba\", url.getPassword());\n        assertEquals(\"dubbo.test.api\", url.getPath());\n        assertEquals(9090, url.getPort());\n        assertEquals(\"remote\", url.getProtocol());\n    }\n\n    @Test\n    void testParseURLWithSpecial() {\n        String address = \"127.0.0.1:2181?backup=127.0.0.1:2182,127.0.0.1:2183\";\n        assertEquals(\"dubbo://\" + address, UrlUtils.parseURL(address, null).toString());\n    }\n\n    @Test\n    void testDefaultUrl() {\n        String address = \"127.0.0.1\";\n        URL url = UrlUtils.parseURL(address, null);\n        assertEquals(localAddress + \":9090\", url.getAddress());\n        assertEquals(9090, url.getPort());\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertNull(url.getUsername());\n        assertNull(url.getPassword());\n        assertNull(url.getPath());\n    }\n\n    @Test\n    void testParseFromParameter() {\n        String address = \"127.0.0.1\";\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(\"username\", \"root\");\n        parameters.put(\"password\", \"alibaba\");\n        parameters.put(\"port\", \"10000\");\n        parameters.put(\"protocol\", \"dubbo\");\n        parameters.put(\"path\", \"dubbo.test.api\");\n        parameters.put(\"aaa\", \"bbb\");\n        parameters.put(\"ccc\", \"ddd\");\n        URL url = UrlUtils.parseURL(address, parameters);\n        assertEquals(localAddress + \":10000\", url.getAddress());\n        assertEquals(\"root\", url.getUsername());\n        assertEquals(\"alibaba\", url.getPassword());\n        assertEquals(10000, url.getPort());\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"dubbo.test.api\", url.getPath());\n        assertEquals(\"bbb\", url.getParameter(\"aaa\"));\n        assertEquals(\"ddd\", url.getParameter(\"ccc\"));\n    }\n\n    @Test\n    void testParseUrl2() {\n        String address = \"192.168.0.1\";\n        String backupAddress1 = \"192.168.0.2\";\n        String backupAddress2 = \"192.168.0.3\";\n\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(\"username\", \"root\");\n        parameters.put(\"password\", \"alibaba\");\n        parameters.put(\"port\", \"10000\");\n        parameters.put(\"protocol\", \"dubbo\");\n        URL url = UrlUtils.parseURL(address + \",\" + backupAddress1 + \",\" + backupAddress2, parameters);\n        assertEquals(\"192.168.0.1:10000\", url.getAddress());\n        assertEquals(\"root\", url.getUsername());\n        assertEquals(\"alibaba\", url.getPassword());\n        assertEquals(10000, url.getPort());\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"192.168.0.2\" + \",\" + \"192.168.0.3\", url.getParameter(\"backup\"));\n    }\n\n    @Test\n    void testParseUrls() {\n        String addresses = \"192.168.0.1|192.168.0.2|192.168.0.3\";\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(\"username\", \"root\");\n        parameters.put(\"password\", \"alibaba\");\n        parameters.put(\"port\", \"10000\");\n        parameters.put(\"protocol\", \"dubbo\");\n        List<URL> urls = UrlUtils.parseURLs(addresses, parameters);\n        assertEquals(\"192.168.0.1\" + \":10000\", urls.get(0).getAddress());\n        assertEquals(\"192.168.0.2\" + \":10000\", urls.get(1).getAddress());\n    }\n\n    @Test\n    void testParseUrlsAddressNull() {\n        String exceptionMessage = \"Address is not allowed to be empty, please re-enter.\";\n        try {\n            UrlUtils.parseURLs(null, null);\n        } catch (IllegalArgumentException illegalArgumentException) {\n            assertEquals(exceptionMessage, illegalArgumentException.getMessage());\n        }\n    }\n\n    @Test\n    void testConvertRegister() {\n        String key = \"perf/dubbo.test.api.HelloService:1.0.0\";\n        Map<String, Map<String, String>> register = new HashMap<String, Map<String, String>>();\n        register.put(key, null);\n        Map<String, Map<String, String>> newRegister = UrlUtils.convertRegister(register);\n        assertEquals(register, newRegister);\n    }\n\n    @Test\n    void testConvertRegister2() {\n        String key = \"dubbo.test.api.HelloService\";\n        Map<String, Map<String, String>> register = new HashMap<String, Map<String, String>>();\n        Map<String, String> service = new HashMap<String, String>();\n        service.put(\"dubbo://127.0.0.1:20880/com.xxx.XxxService\", \"version=1.0.0&group=test&dubbo.version=2.0.0\");\n        register.put(key, service);\n        Map<String, Map<String, String>> newRegister = UrlUtils.convertRegister(register);\n        Map<String, String> newService = new HashMap<String, String>();\n        newService.put(\"dubbo://127.0.0.1:20880/com.xxx.XxxService\", \"dubbo.version=2.0.0&group=test&version=1.0.0\");\n        assertEquals(newService, newRegister.get(\"test/dubbo.test.api.HelloService:1.0.0\"));\n    }\n\n    @Test\n    void testSubscribe() {\n        String key = \"perf/dubbo.test.api.HelloService:1.0.0\";\n        Map<String, String> subscribe = new HashMap<String, String>();\n        subscribe.put(key, null);\n        Map<String, String> newSubscribe = UrlUtils.convertSubscribe(subscribe);\n        assertEquals(subscribe, newSubscribe);\n    }\n\n    @Test\n    void testSubscribe2() {\n        String key = \"dubbo.test.api.HelloService\";\n        Map<String, String> subscribe = new HashMap<String, String>();\n        subscribe.put(key, \"version=1.0.0&group=test&dubbo.version=2.0.0\");\n        Map<String, String> newSubscribe = UrlUtils.convertSubscribe(subscribe);\n        assertEquals(\n                \"dubbo.version=2.0.0&group=test&version=1.0.0\",\n                newSubscribe.get(\"test/dubbo.test.api.HelloService:1.0.0\"));\n    }\n\n    @Test\n    void testRevertRegister() {\n        String key = \"perf/dubbo.test.api.HelloService:1.0.0\";\n        Map<String, Map<String, String>> register = new HashMap<String, Map<String, String>>();\n        Map<String, String> service = new HashMap<String, String>();\n        service.put(\"dubbo://127.0.0.1:20880/com.xxx.XxxService\", null);\n        register.put(key, service);\n        Map<String, Map<String, String>> newRegister = UrlUtils.revertRegister(register);\n        Map<String, Map<String, String>> expectedRegister = new HashMap<String, Map<String, String>>();\n        service.put(\"dubbo://127.0.0.1:20880/com.xxx.XxxService\", \"group=perf&version=1.0.0\");\n        expectedRegister.put(\"dubbo.test.api.HelloService\", service);\n        assertEquals(expectedRegister, newRegister);\n    }\n\n    @Test\n    void testRevertRegister2() {\n        String key = \"dubbo.test.api.HelloService\";\n        Map<String, Map<String, String>> register = new HashMap<String, Map<String, String>>();\n        Map<String, String> service = new HashMap<String, String>();\n        service.put(\"dubbo://127.0.0.1:20880/com.xxx.XxxService\", null);\n        register.put(key, service);\n        Map<String, Map<String, String>> newRegister = UrlUtils.revertRegister(register);\n        Map<String, Map<String, String>> expectedRegister = new HashMap<String, Map<String, String>>();\n        service.put(\"dubbo://127.0.0.1:20880/com.xxx.XxxService\", null);\n        expectedRegister.put(\"dubbo.test.api.HelloService\", service);\n        assertEquals(expectedRegister, newRegister);\n    }\n\n    @Test\n    void testRevertSubscribe() {\n        String key = \"perf/dubbo.test.api.HelloService:1.0.0\";\n        Map<String, String> subscribe = new HashMap<String, String>();\n        subscribe.put(key, null);\n        Map<String, String> newSubscribe = UrlUtils.revertSubscribe(subscribe);\n        Map<String, String> expectSubscribe = new HashMap<String, String>();\n        expectSubscribe.put(\"dubbo.test.api.HelloService\", \"group=perf&version=1.0.0\");\n        assertEquals(expectSubscribe, newSubscribe);\n    }\n\n    @Test\n    void testRevertSubscribe2() {\n        String key = \"dubbo.test.api.HelloService\";\n        Map<String, String> subscribe = new HashMap<String, String>();\n        subscribe.put(key, null);\n        Map<String, String> newSubscribe = UrlUtils.revertSubscribe(subscribe);\n        assertEquals(subscribe, newSubscribe);\n    }\n\n    @Test\n    void testRevertNotify() {\n        String key = \"dubbo.test.api.HelloService\";\n        Map<String, Map<String, String>> notify = new HashMap<String, Map<String, String>>();\n        Map<String, String> service = new HashMap<String, String>();\n        service.put(\"dubbo://127.0.0.1:20880/com.xxx.XxxService\", \"group=perf&version=1.0.0\");\n        notify.put(key, service);\n        Map<String, Map<String, String>> newRegister = UrlUtils.revertNotify(notify);\n        Map<String, Map<String, String>> expectedRegister = new HashMap<String, Map<String, String>>();\n        service.put(\"dubbo://127.0.0.1:20880/com.xxx.XxxService\", \"group=perf&version=1.0.0\");\n        expectedRegister.put(\"perf/dubbo.test.api.HelloService:1.0.0\", service);\n        assertEquals(expectedRegister, newRegister);\n    }\n\n    @Test\n    void testRevertNotify2() {\n        String key = \"perf/dubbo.test.api.HelloService:1.0.0\";\n        Map<String, Map<String, String>> notify = new HashMap<String, Map<String, String>>();\n        Map<String, String> service = new HashMap<String, String>();\n        service.put(\"dubbo://127.0.0.1:20880/com.xxx.XxxService\", \"group=perf&version=1.0.0\");\n        notify.put(key, service);\n        Map<String, Map<String, String>> newRegister = UrlUtils.revertNotify(notify);\n        Map<String, Map<String, String>> expectedRegister = new HashMap<String, Map<String, String>>();\n        service.put(\"dubbo://127.0.0.1:20880/com.xxx.XxxService\", \"group=perf&version=1.0.0\");\n        expectedRegister.put(\"perf/dubbo.test.api.HelloService:1.0.0\", service);\n        assertEquals(expectedRegister, newRegister);\n    }\n\n    // backward compatibility for version 2.0.0\n    @Test\n    void testRevertForbid() {\n        String service = \"dubbo.test.api.HelloService\";\n        List<String> forbid = new ArrayList<String>();\n        forbid.add(service);\n        Set<URL> subscribed = new HashSet<URL>();\n        subscribed.add(URL.valueOf(\"dubbo://127.0.0.1:20880/\" + service + \"?group=perf&version=1.0.0\"));\n        List<String> newForbid = UrlUtils.revertForbid(forbid, subscribed);\n        List<String> expectForbid = new ArrayList<String>();\n        expectForbid.add(\"perf/\" + service + \":1.0.0\");\n        assertEquals(expectForbid, newForbid);\n    }\n\n    @Test\n    void testRevertForbid2() {\n        List<String> newForbid = UrlUtils.revertForbid(null, null);\n        assertNull(newForbid);\n    }\n\n    @Test\n    void testRevertForbid3() {\n        String service1 = \"dubbo.test.api.HelloService:1.0.0\";\n        String service2 = \"dubbo.test.api.HelloService:2.0.0\";\n        List<String> forbid = new ArrayList<String>();\n        forbid.add(service1);\n        forbid.add(service2);\n        List<String> newForbid = UrlUtils.revertForbid(forbid, null);\n        assertEquals(forbid, newForbid);\n    }\n\n    @Test\n    void testIsMatch() {\n        URL consumerUrl = URL.valueOf(\"dubbo://127.0.0.1:20880/com.xxx.XxxService?version=1.0.0&group=test\");\n        URL providerUrl = URL.valueOf(\"http://127.0.0.1:8080/com.xxx.XxxService?version=1.0.0&group=test\");\n        assertTrue(UrlUtils.isMatch(consumerUrl, providerUrl));\n    }\n\n    @Test\n    void testIsMatch2() {\n        URL consumerUrl = URL.valueOf(\"dubbo://127.0.0.1:20880/com.xxx.XxxService?version=2.0.0&group=test\");\n        URL providerUrl = URL.valueOf(\"http://127.0.0.1:8080/com.xxx.XxxService?version=1.0.0&group=test\");\n        assertFalse(UrlUtils.isMatch(consumerUrl, providerUrl));\n    }\n\n    @Test\n    void testIsMatch3() {\n        URL consumerUrl = URL.valueOf(\"dubbo://127.0.0.1:20880/com.xxx.XxxService?version=1.0.0&group=aa\");\n        URL providerUrl = URL.valueOf(\"http://127.0.0.1:8080/com.xxx.XxxService?version=1.0.0&group=test\");\n        assertFalse(UrlUtils.isMatch(consumerUrl, providerUrl));\n    }\n\n    @Test\n    void testIsMatch4() {\n        URL consumerUrl = URL.valueOf(\"dubbo://127.0.0.1:20880/com.xxx.XxxService?version=1.0.0&group=*\");\n        URL providerUrl = URL.valueOf(\"http://127.0.0.1:8080/com.xxx.XxxService?version=1.0.0&group=test\");\n        assertTrue(UrlUtils.isMatch(consumerUrl, providerUrl));\n    }\n\n    @Test\n    void testIsMatch5() {\n        URL consumerUrl = URL.valueOf(\"dubbo://127.0.0.1:20880/com.xxx.XxxService?version=*&group=test\");\n        URL providerUrl = URL.valueOf(\"http://127.0.0.1:8080/com.xxx.XxxService?version=1.0.0&group=test\");\n        assertTrue(UrlUtils.isMatch(consumerUrl, providerUrl));\n    }\n\n    @Test\n    void testIsItemMatch() throws Exception {\n        assertTrue(UrlUtils.isItemMatch(null, null));\n        assertTrue(!UrlUtils.isItemMatch(\"1\", null));\n        assertTrue(!UrlUtils.isItemMatch(null, \"1\"));\n        assertTrue(UrlUtils.isItemMatch(\"1\", \"1\"));\n        assertTrue(UrlUtils.isItemMatch(\"*\", null));\n        assertTrue(UrlUtils.isItemMatch(\"*\", \"*\"));\n        assertTrue(UrlUtils.isItemMatch(\"*\", \"1234\"));\n        assertTrue(!UrlUtils.isItemMatch(null, \"*\"));\n    }\n\n    @Test\n    void testIsServiceKeyMatch() throws Exception {\n        URL url = URL.valueOf(\"test://127.0.0.1\");\n        URL pattern = url.addParameter(GROUP_KEY, \"test\")\n                .addParameter(INTERFACE_KEY, \"test\")\n                .addParameter(VERSION_KEY, \"test\");\n        URL value = pattern;\n        assertTrue(UrlUtils.isServiceKeyMatch(pattern, value));\n\n        pattern = pattern.addParameter(GROUP_KEY, \"*\");\n        assertTrue(UrlUtils.isServiceKeyMatch(pattern, value));\n\n        pattern = pattern.addParameter(VERSION_KEY, \"*\");\n        assertTrue(UrlUtils.isServiceKeyMatch(pattern, value));\n    }\n\n    @Test\n    void testGetEmptyUrl() throws Exception {\n        URL url = UrlUtils.getEmptyUrl(\"dubbo/a.b.c.Foo:1.0.0\", \"test\");\n        assertThat(url.toFullString(), equalTo(\"empty://0.0.0.0/a.b.c.Foo?category=test&group=dubbo&version=1.0.0\"));\n    }\n\n    @Test\n    void testIsMatchGlobPattern() throws Exception {\n        assertTrue(UrlUtils.isMatchGlobPattern(\"*\", \"value\"));\n        assertTrue(UrlUtils.isMatchGlobPattern(\"\", null));\n        assertFalse(UrlUtils.isMatchGlobPattern(\"\", \"value\"));\n        assertTrue(UrlUtils.isMatchGlobPattern(\"value\", \"value\"));\n        assertTrue(UrlUtils.isMatchGlobPattern(\"v*\", \"value\"));\n        assertTrue(UrlUtils.isMatchGlobPattern(\"*e\", \"value\"));\n        assertTrue(UrlUtils.isMatchGlobPattern(\"v*e\", \"value\"));\n        assertTrue(UrlUtils.isMatchGlobPattern(\"$key\", \"value\", URL.valueOf(\"dubbo://localhost:8080/Foo?key=v*e\")));\n    }\n\n    @Test\n    void testIsMatchUrlWithDefaultPrefix() {\n        URL url = URL.valueOf(\"dubbo://127.0.0.1:20880/com.xxx.XxxService?default.version=1.0.0&default.group=test\");\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"1.0.0\", url.getParameter(\"default.version\"));\n\n        URL consumerUrl = URL.valueOf(\"consumer://127.0.0.1/com.xxx.XxxService?version=1.0.0&group=test\");\n        assertTrue(UrlUtils.isMatch(consumerUrl, url));\n\n        URL consumerUrl1 =\n                URL.valueOf(\"consumer://127.0.0.1/com.xxx.XxxService?default.version=1.0.0&default.group=test\");\n        assertTrue(UrlUtils.isMatch(consumerUrl1, url));\n    }\n\n    @Test\n    public void testIsConsumer() {\n        String address1 = \"remote://root:alibaba@127.0.0.1:9090\";\n        URL url1 = UrlUtils.parseURL(address1, null);\n        String address2 = \"consumer://root:alibaba@127.0.0.1:9090\";\n        URL url2 = UrlUtils.parseURL(address2, null);\n        String address3 = \"consumer://root:alibaba@127.0.0.1\";\n        URL url3 = UrlUtils.parseURL(address3, null);\n\n        assertFalse(UrlUtils.isConsumer(url1));\n        assertTrue(UrlUtils.isConsumer(url2));\n        assertTrue(UrlUtils.isConsumer(url3));\n    }\n\n    @Test\n    public void testPrivateConstructor() throws Exception {\n        Constructor<UrlUtils> constructor = UrlUtils.class.getDeclaredConstructor();\n        assertTrue(Modifier.isPrivate(constructor.getModifiers()));\n        constructor.setAccessible(true);\n        assertThrows(InvocationTargetException.class, () -> {\n            constructor.newInstance();\n        });\n    }\n\n    @Test\n    public void testClassifyUrls() {\n\n        String address1 = \"remote://root:alibaba@127.0.0.1:9090\";\n        URL url1 = UrlUtils.parseURL(address1, null);\n        String address2 = \"consumer://root:alibaba@127.0.0.1:9090\";\n        URL url2 = UrlUtils.parseURL(address2, null);\n        String address3 = \"remote://root:alibaba@127.0.0.1\";\n        URL url3 = UrlUtils.parseURL(address3, null);\n        String address4 = \"consumer://root:alibaba@127.0.0.1\";\n        URL url4 = UrlUtils.parseURL(address4, null);\n\n        List<URL> urls = new ArrayList<>();\n        urls.add(url1);\n        urls.add(url2);\n        urls.add(url3);\n        urls.add(url4);\n\n        List<URL> consumerUrls = UrlUtils.classifyUrls(urls, UrlUtils::isConsumer);\n        assertEquals(2, consumerUrls.size());\n        assertTrue(consumerUrls.contains(url2));\n        assertTrue(consumerUrls.contains(url4));\n\n        List<URL> nonConsumerUrls = UrlUtils.classifyUrls(urls, url -> !UrlUtils.isConsumer(url));\n        assertEquals(2, nonConsumerUrls.size());\n        assertTrue(nonConsumerUrls.contains(url1));\n        assertTrue(nonConsumerUrls.contains(url3));\n    }\n\n    @Test\n    public void testHasServiceDiscoveryRegistryProtocol() {\n        String address1 = \"http://root:alibaba@127.0.0.1:9090/dubbo.test.api\";\n        URL url1 = UrlUtils.parseURL(address1, null);\n        String address2 = \"service-discovery-registry://root:alibaba@127.0.0.1:9090/dubbo.test.api\";\n        URL url2 = UrlUtils.parseURL(address2, null);\n\n        assertFalse(UrlUtils.hasServiceDiscoveryRegistryProtocol(url1));\n        assertTrue(UrlUtils.hasServiceDiscoveryRegistryProtocol(url2));\n    }\n\n    private static final String SERVICE_REGISTRY_TYPE = \"service\";\n    private static final String REGISTRY_TYPE_KEY = \"registry-type\";\n\n    @Test\n    public void testHasServiceDiscoveryRegistryTypeKey() {\n        Map<String, String> parameters1 = new HashMap<>();\n        parameters1.put(REGISTRY_TYPE_KEY, \"value2\");\n        assertFalse(UrlUtils.hasServiceDiscoveryRegistryTypeKey(parameters1));\n\n        Map<String, String> parameters2 = new HashMap<>();\n        parameters2.put(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE);\n\n        assertTrue(UrlUtils.hasServiceDiscoveryRegistryTypeKey(parameters2));\n    }\n\n    @Test\n    public void testIsConfigurator() {\n        String address1 = \"http://example.com\";\n        URL url1 = UrlUtils.parseURL(address1, null);\n        String address2 = \"override://example.com\";\n        URL url2 = UrlUtils.parseURL(address2, null);\n        String address3 = \"http://example.com?category=configurators\";\n        URL url3 = UrlUtils.parseURL(address3, null);\n\n        assertFalse(UrlUtils.isConfigurator(url1));\n        assertTrue(UrlUtils.isConfigurator(url2));\n        assertTrue(UrlUtils.isConfigurator(url3));\n    }\n\n    @Test\n    public void testIsRoute() {\n        String address1 = \"http://example.com\";\n        URL url1 = UrlUtils.parseURL(address1, null);\n        String address2 = \"route://example.com\";\n        URL url2 = UrlUtils.parseURL(address2, null);\n        String address3 = \"http://example.com?category=routers\";\n        URL url3 = UrlUtils.parseURL(address3, null);\n\n        assertFalse(UrlUtils.isRoute(url1));\n        assertTrue(UrlUtils.isRoute(url2));\n        assertTrue(UrlUtils.isRoute(url3));\n    }\n\n    @Test\n    public void testIsProvider() {\n        String address1 = \"http://example.com\";\n        URL url1 = UrlUtils.parseURL(address1, null);\n        String address2 = \"override://example.com\";\n        URL url2 = UrlUtils.parseURL(address2, null);\n        String address3 = \"route://example.com\";\n        URL url3 = UrlUtils.parseURL(address3, null);\n        String address4 = \"http://example.com?category=providers\";\n        URL url4 = UrlUtils.parseURL(address4, null);\n        String address5 = \"http://example.com?category=something-else\";\n        URL url5 = UrlUtils.parseURL(address5, null);\n\n        assertTrue(UrlUtils.isProvider(url1));\n        assertFalse(UrlUtils.isProvider(url2));\n        assertFalse(UrlUtils.isProvider(url3));\n        assertTrue(UrlUtils.isProvider(url4));\n        assertFalse(UrlUtils.isProvider(url5));\n    }\n\n    @Test\n    public void testIsRegistry() {\n        String address1 = \"http://example.com\";\n        URL url1 = UrlUtils.parseURL(address1, null);\n        String address2 = \"registry://example.com\";\n        URL url2 = UrlUtils.parseURL(address2, null);\n        String address3 = \"sr://example.com\";\n        URL url3 = UrlUtils.parseURL(address3, null);\n        String address4 = \"custom-registry-protocol://example.com\";\n        URL url4 = UrlUtils.parseURL(address4, null);\n\n        assertFalse(UrlUtils.isRegistry(url1));\n        assertTrue(UrlUtils.isRegistry(url2));\n        assertFalse(UrlUtils.isRegistry(url3));\n        assertTrue(UrlUtils.isRegistry(url4));\n    }\n\n    @Test\n    public void testIsServiceDiscoveryURL() {\n        String address1 = \"http://example.com\";\n        URL url1 = UrlUtils.parseURL(address1, null);\n        String address2 = \"service-discovery-registry://example.com\";\n        URL url2 = UrlUtils.parseURL(address2, null);\n        String address3 = \"SERVICE-DISCOVERY-REGISTRY://example.com\";\n        URL url3 = UrlUtils.parseURL(address3, null);\n        String address4 = \"http://example.com?registry-type=service\";\n        URL url4 = UrlUtils.parseURL(address4, null);\n        url4.addParameter(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE);\n\n        assertFalse(UrlUtils.isServiceDiscoveryURL(url1));\n        assertTrue(UrlUtils.isServiceDiscoveryURL(url2));\n        assertTrue(UrlUtils.isServiceDiscoveryURL(url3));\n        assertTrue(UrlUtils.isServiceDiscoveryURL(url4));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/json/AbstractObject.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils.json;\n\npublic abstract class AbstractObject {\n\n    public abstract String sayHello();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/json/Color.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils.json;\n\npublic enum Color {\n    RED(\"红色\", 1),\n    GREEN(\"绿色\", 2),\n    BLANK(\"白色\", 3),\n    YELLOW(\"黄色\", 4);\n\n    private String name;\n    private int index;\n\n    private Color(String name, int index) {\n        this.name = name;\n        this.index = index;\n    }\n\n    public static String getName(int index) {\n        for (Color c : Color.values()) {\n            if (c.getIndex() == index) {\n                return c.name;\n            }\n        }\n        return null;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public int getIndex() {\n        return index;\n    }\n\n    public void setIndex(int index) {\n        this.index = index;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/json/Printer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils.json;\n\npublic interface Printer {\n    String print();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/json/Range.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils.json;\n\n// public record Range(Integer left, Integer right) {\n//    public Integer sum() {\n//        return left + right;\n//    }\n// }\n\npublic class Range {\n    private Integer left;\n    private Integer right;\n\n    public Range(Integer left, Integer right) {\n        this.left = left;\n        this.right = right;\n    }\n\n    public Integer sum() {\n        return left + right;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/json/Service.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils.json;\n\nimport java.io.FileNotFoundException;\nimport java.io.InputStream;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.time.ZonedDateTime;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\n\npublic interface Service {\n    String sayHi(String name);\n\n    List<String> testList();\n\n    int testInt();\n\n    int[] testIntArr();\n\n    Integer testInteger();\n\n    Integer[] testIntegerArr();\n\n    List<Integer> testIntegerList();\n\n    short testShort();\n\n    short[] testShortArr();\n\n    Short testSShort();\n\n    Short[] testSShortArr();\n\n    List<Short> testShortList();\n\n    byte testByte();\n\n    byte[] testByteArr();\n\n    Byte testBByte();\n\n    Byte[] testBByteArr();\n\n    ArrayList<Byte> testByteList();\n\n    float testFloat();\n\n    float[] testFloatArr();\n\n    Float testFFloat();\n\n    Float[] testFloatArray();\n\n    List<Float> testFloatList();\n\n    boolean testBoolean();\n\n    boolean[] testBooleanArr();\n\n    Boolean testBBoolean();\n\n    Boolean[] testBooleanArray();\n\n    List<Boolean> testBooleanList();\n\n    char testChar();\n\n    char[] testCharArr();\n\n    Character testCharacter();\n\n    Character[] testCharacterArr();\n\n    List<Character> testCharacterList();\n\n    List<Character[]> testCharacterListArr();\n\n    String testString();\n\n    String[] testStringArr();\n\n    List<String> testStringList();\n\n    List<String[]> testStringListArr();\n\n    String testNull();\n\n    Date testDate();\n\n    Calendar testCalendar();\n\n    LocalTime testLocalTime();\n\n    LocalDate testLocalDate();\n\n    LocalDateTime testLocalDateTime();\n\n    ZonedDateTime testZoneDateTime();\n\n    Map<Integer, String> testMap();\n\n    Set<Integer> testSet();\n\n    Optional<Integer> testOptionalEmpty();\n\n    Optional<Integer> testOptionalInteger();\n\n    Optional<String> testOptionalString();\n\n    Color testEnum();\n\n    Range testRecord();\n\n    Printer testInterface();\n\n    Teacher testObject();\n\n    List<Teacher> testObjectList();\n\n    Student<Integer> testTemplate();\n\n    InputStream testStream() throws FileNotFoundException;\n\n    Iterator<String> testIterator();\n\n    AbstractObject testAbstract();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/json/Student.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils.json;\n\nimport java.io.Serializable;\nimport java.util.List;\n\npublic class Student<W> implements Serializable {\n    private Integer type;\n\n    private List<String> names;\n\n    private List<W> namesT;\n\n    private W age;\n\n    private String name;\n\n    public Student(Integer type, String name) {\n        this.type = type;\n        this.name = name;\n    }\n\n    @Override\n    public String toString() {\n        return \"Student{\" + \"type=\" + type + \", name='\" + name + '\\'' + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/json/Teacher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils.json;\n\nimport java.io.Serializable;\n\npublic class Teacher implements Serializable {\n    private String name;\n    private Integer age;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n\n    public Teacher(String name, Integer age) {\n        this.name = name;\n        this.age = age;\n    }\n\n    @Override\n    public String toString() {\n        return \"Teacher{\" + \"name='\" + name + '\\'' + \", age=\" + age + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/json/TestEnum.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils.json;\n\npublic enum TestEnum {\n    TYPE_A,\n    TYPE_B,\n    TYPE_C\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/json/TestObjectA.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils.json;\n\npublic class TestObjectA {\n    private String name;\n    private int age;\n    private TestEnum testEnum;\n\n    public TestObjectA() {}\n\n    public TestObjectA(String name, int age, TestEnum testEnum) {\n        this.name = name;\n        this.age = age;\n        this.testEnum = testEnum;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public TestEnum getTestEnum() {\n        return testEnum;\n    }\n\n    public void setTestEnum(TestEnum testEnum) {\n        this.testEnum = testEnum;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/utils/json/TestObjectB.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils.json;\n\npublic class TestObjectB {\n    private Inner innerA;\n    private Inner innerB;\n\n    public Inner getInnerA() {\n        return innerA;\n    }\n\n    public void setInnerA(Inner innerA) {\n        this.innerA = innerA;\n    }\n\n    public Inner getInnerB() {\n        return innerB;\n    }\n\n    public void setInnerB(Inner innerB) {\n        this.innerB = innerB;\n    }\n\n    public static class Inner {\n        private String name;\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/version/VersionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.version;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.constants.CommonConstants;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.lang.reflect.InvocationTargetException;\nimport java.net.URL;\nimport java.util.Enumeration;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass VersionTest {\n\n    @Test\n    void testGetProtocolVersion() {\n        Assertions.assertEquals(Version.getProtocolVersion(), Version.DEFAULT_DUBBO_PROTOCOL_VERSION);\n    }\n\n    @Test\n    void testSupportResponseAttachment() {\n        Assertions.assertTrue(Version.isSupportResponseAttachment(\"2.0.2\"));\n        Assertions.assertTrue(Version.isSupportResponseAttachment(\"2.0.3\"));\n        Assertions.assertTrue(Version.isSupportResponseAttachment(\"2.0.99\"));\n\n        Assertions.assertFalse(Version.isSupportResponseAttachment(\"2.1.0\"));\n        Assertions.assertFalse(Version.isSupportResponseAttachment(\"2.0.0\"));\n        Assertions.assertFalse(Version.isSupportResponseAttachment(\"1.0.0\"));\n        Assertions.assertFalse(Version.isSupportResponseAttachment(\"3.0.0\"));\n        Assertions.assertFalse(Version.isSupportResponseAttachment(\"2.6.6-stable\"));\n        Assertions.assertFalse(Version.isSupportResponseAttachment(\"2.6.6.RC1\"));\n        Assertions.assertFalse(Version.isSupportResponseAttachment(\"2.0.contains\"));\n        Assertions.assertFalse(Version.isSupportResponseAttachment(\"version.string\"));\n        Assertions.assertFalse(Version.isSupportResponseAttachment(\"prefix2.0\"));\n    }\n\n    @Test\n    void testGetIntVersion() {\n        Assertions.assertEquals(2060100, Version.getIntVersion(\"2.6.1\"));\n        Assertions.assertEquals(2060101, Version.getIntVersion(\"2.6.1.1\"));\n        Assertions.assertEquals(2070001, Version.getIntVersion(\"2.7.0.1\"));\n        Assertions.assertEquals(2070000, Version.getIntVersion(\"2.7.0\"));\n        Assertions.assertEquals(Version.HIGHEST_PROTOCOL_VERSION, Version.getIntVersion(\"2.0.99\"));\n        Assertions.assertEquals(2070000, Version.getIntVersion(\"2.7.0.RC1\"));\n        Assertions.assertEquals(2070000, Version.getIntVersion(\"2.7.0-SNAPSHOT\"));\n        Assertions.assertEquals(3000000, Version.getIntVersion(\"3.0.0-SNAPSHOT\"));\n        Assertions.assertEquals(3010000, Version.getIntVersion(\"3.1.0\"));\n    }\n\n    @Test\n    void testCompare() {\n        Assertions.assertEquals(0, Version.compare(\"3.0.0\", \"3.0.0\"));\n        Assertions.assertEquals(0, Version.compare(\"3.0.0-SNAPSHOT\", \"3.0.0\"));\n        Assertions.assertEquals(1, Version.compare(\"3.0.0.1\", \"3.0.0\"));\n        Assertions.assertEquals(1, Version.compare(\"3.1.0\", \"3.0.0\"));\n        Assertions.assertEquals(1, Version.compare(\"3.1.2.3\", \"3.0.0\"));\n        Assertions.assertEquals(-1, Version.compare(\"2.9.9.9\", \"3.0.0\"));\n        Assertions.assertEquals(-1, Version.compare(\"2.6.3.1\", \"3.0.0\"));\n    }\n\n    @Test\n    void testIsFramework270OrHigher() {\n        Assertions.assertTrue(Version.isRelease270OrHigher(\"2.7.0\"));\n        Assertions.assertTrue(Version.isRelease270OrHigher(\"2.7.0.1\"));\n        Assertions.assertTrue(Version.isRelease270OrHigher(\"2.7.0.2\"));\n        Assertions.assertTrue(Version.isRelease270OrHigher(\"2.8.0\"));\n        Assertions.assertFalse(Version.isRelease270OrHigher(\"2.6.3\"));\n        Assertions.assertFalse(Version.isRelease270OrHigher(\"2.6.3.1\"));\n    }\n\n    @Test\n    void testIsFramework263OrHigher() {\n        Assertions.assertTrue(Version.isRelease263OrHigher(\"2.7.0\"));\n        Assertions.assertTrue(Version.isRelease263OrHigher(\"2.7.0.1\"));\n        Assertions.assertTrue(Version.isRelease263OrHigher(\"2.6.4\"));\n        Assertions.assertFalse(Version.isRelease263OrHigher(\"2.6.2\"));\n        Assertions.assertFalse(Version.isRelease263OrHigher(\"2.6.2.1\"));\n        Assertions.assertFalse(Version.isRelease263OrHigher(\"2.6.1.1\"));\n        Assertions.assertTrue(Version.isRelease263OrHigher(\"2.6.3\"));\n        Assertions.assertTrue(Version.isRelease263OrHigher(\"2.6.3.0\"));\n    }\n\n    @Test\n    void testGetVersion()\n            throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {\n        Class<?> versionClass = reloadVersionClass();\n        Assertions.assertEquals(\n                \"1.0.0\", versionClass.getDeclaredMethod(\"getVersion\").invoke(null));\n    }\n\n    private static Class<?> reloadVersionClass() throws ClassNotFoundException {\n        ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();\n        ClassLoader classLoader = new ClassLoader(originClassLoader) {\n            @Override\n            public Class<?> loadClass(String name) throws ClassNotFoundException {\n                if (\"org.apache.dubbo.common.Version\".equals(name)) {\n                    return findClass(name);\n                }\n                return super.loadClass(name);\n            }\n\n            @Override\n            protected Class<?> findClass(String name) throws ClassNotFoundException {\n                try {\n                    byte[] bytes = loadClassData(name);\n                    return defineClass(name, bytes, 0, bytes.length);\n                } catch (Exception e) {\n                    return getParent().loadClass(name);\n                }\n            }\n\n            public byte[] loadClassData(String className) throws IOException {\n                className = className.replaceAll(\"\\\\.\", \"/\");\n                String path = Version.class\n                                .getProtectionDomain()\n                                .getCodeSource()\n                                .getLocation()\n                                .getPath() + className + \".class\";\n                FileInputStream fileInputStream;\n                byte[] classBytes;\n                fileInputStream = new FileInputStream(path);\n                int length = fileInputStream.available();\n                classBytes = new byte[length];\n                fileInputStream.read(classBytes);\n                fileInputStream.close();\n                return classBytes;\n            }\n\n            @Override\n            public Enumeration<URL> getResources(String name) throws IOException {\n                if (name.equals(CommonConstants.DUBBO_VERSIONS_KEY + \"/dubbo-common\")) {\n                    return super.getResources(\"META-INF/test-versions/dubbo-common\");\n                }\n                return super.getResources(name);\n            }\n        };\n        return classLoader.loadClass(\"org.apache.dubbo.common.Version\");\n    }\n\n    @Test\n    void testGetLastCommitId()\n            throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException {\n        Class<?> versionClass = reloadVersionClass();\n        Assertions.assertEquals(\n                \"82a29fcd674216fe9bea10b6efef3196929dd7ca\",\n                versionClass.getDeclaredMethod(\"getLastCommitId\").invoke(null));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/common/vo/UserVo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.vo;\n\nimport java.util.Objects;\n\npublic class UserVo {\n    private String name;\n    private String addr;\n    private int age;\n\n    public UserVo(String name, String addr, int age) {\n        this.name = name;\n        this.addr = addr;\n        this.age = age;\n    }\n\n    public UserVo() {}\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getAddr() {\n        return addr;\n    }\n\n    public void setAddr(String addr) {\n        this.addr = addr;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public static UserVo getInstance() {\n        return new UserVo(\"dubbo\", \"hangzhou\", 10);\n    }\n\n    @Override\n    public String toString() {\n        return \"UserVo{\" + \"name='\" + name + '\\'' + \", addr='\" + addr + '\\'' + \", age=\" + age + '}';\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        UserVo userVo = (UserVo) o;\n        return age == userVo.age && Objects.equals(name, userVo.name) && Objects.equals(addr, userVo.addr);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name, addr, age);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.io.File;\nimport java.nio.file.Path;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nclass AbstractInterfaceConfigTest {\n\n    @BeforeAll\n    public static void setUp(@TempDir Path folder) {\n        File dubboProperties = folder.resolve(CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY)\n                .toFile();\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY, dubboProperties.getAbsolutePath());\n    }\n\n    @AfterAll\n    public static void tearDown() {\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY);\n    }\n\n    @Test\n    void checkStub1() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            InterfaceConfig interfaceConfig = new InterfaceConfig();\n            interfaceConfig.setLocal(GreetingLocal1.class.getName());\n            interfaceConfig.checkStubAndLocal(Greeting.class);\n        });\n    }\n\n    @Test\n    void checkStub2() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            InterfaceConfig interfaceConfig = new InterfaceConfig();\n            interfaceConfig.setLocal(GreetingLocal2.class.getName());\n            interfaceConfig.checkStubAndLocal(Greeting.class);\n        });\n    }\n\n    @Test\n    void checkStub3() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setLocal(GreetingLocal3.class.getName());\n        interfaceConfig.checkStubAndLocal(Greeting.class);\n    }\n\n    @Test\n    void checkStub4() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            InterfaceConfig interfaceConfig = new InterfaceConfig();\n            interfaceConfig.setStub(GreetingLocal1.class.getName());\n            interfaceConfig.checkStubAndLocal(Greeting.class);\n        });\n    }\n\n    @Test\n    void checkStub5() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            InterfaceConfig interfaceConfig = new InterfaceConfig();\n            interfaceConfig.setStub(GreetingLocal2.class.getName());\n            interfaceConfig.checkStubAndLocal(Greeting.class);\n        });\n    }\n\n    @Test\n    void checkStub6() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setStub(GreetingLocal3.class.getName());\n        interfaceConfig.checkStubAndLocal(Greeting.class);\n    }\n\n    @Test\n    void testLocal() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setLocal((Boolean) null);\n        Assertions.assertNull(interfaceConfig.getLocal());\n        interfaceConfig.setLocal(true);\n        Assertions.assertEquals(\"true\", interfaceConfig.getLocal());\n        interfaceConfig.setLocal(\"GreetingMock\");\n        Assertions.assertEquals(\"GreetingMock\", interfaceConfig.getLocal());\n    }\n\n    @Test\n    void testStub() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setStub((Boolean) null);\n        Assertions.assertNull(interfaceConfig.getStub());\n        interfaceConfig.setStub(true);\n        Assertions.assertEquals(\"true\", interfaceConfig.getStub());\n        interfaceConfig.setStub(\"GreetingMock\");\n        Assertions.assertEquals(\"GreetingMock\", interfaceConfig.getStub());\n    }\n\n    @Test\n    void testCluster() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setCluster(\"mockcluster\");\n        Assertions.assertEquals(\"mockcluster\", interfaceConfig.getCluster());\n    }\n\n    @Test\n    void testProxy() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setProxy(\"mockproxyfactory\");\n        Assertions.assertEquals(\"mockproxyfactory\", interfaceConfig.getProxy());\n    }\n\n    @Test\n    void testConnections() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setConnections(1);\n        Assertions.assertEquals(1, interfaceConfig.getConnections().intValue());\n    }\n\n    @Test\n    void testFilter() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setFilter(\"mockfilter\");\n        Assertions.assertEquals(\"mockfilter\", interfaceConfig.getFilter());\n    }\n\n    @Test\n    void testListener() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setListener(\"mockinvokerlistener\");\n        Assertions.assertEquals(\"mockinvokerlistener\", interfaceConfig.getListener());\n    }\n\n    @Test\n    void testLayer() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setLayer(\"layer\");\n        Assertions.assertEquals(\"layer\", interfaceConfig.getLayer());\n    }\n\n    @Test\n    void testApplication() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"AbstractInterfaceConfigTest\");\n        interfaceConfig.setApplication(applicationConfig);\n        Assertions.assertSame(applicationConfig, interfaceConfig.getApplication());\n    }\n\n    @Test\n    void testModule() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        ModuleConfig moduleConfig = new ModuleConfig();\n        interfaceConfig.setModule(moduleConfig);\n        Assertions.assertSame(moduleConfig, interfaceConfig.getModule());\n    }\n\n    @Test\n    void testRegistry() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        RegistryConfig registryConfig = new RegistryConfig();\n        interfaceConfig.setRegistry(registryConfig);\n        Assertions.assertSame(registryConfig, interfaceConfig.getRegistry());\n    }\n\n    @Test\n    void testRegistries() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        RegistryConfig registryConfig = new RegistryConfig();\n        interfaceConfig.setRegistries(Collections.singletonList(registryConfig));\n        Assertions.assertEquals(1, interfaceConfig.getRegistries().size());\n        Assertions.assertSame(registryConfig, interfaceConfig.getRegistries().get(0));\n    }\n\n    @Test\n    void testMonitor() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setMonitor(\"monitor-addr\");\n        Assertions.assertEquals(\"monitor-addr\", interfaceConfig.getMonitor().getAddress());\n        MonitorConfig monitorConfig = new MonitorConfig();\n        monitorConfig.setAddress(\"monitor-addr\");\n        interfaceConfig.setMonitor(monitorConfig);\n        Assertions.assertSame(monitorConfig, interfaceConfig.getMonitor());\n    }\n\n    @Test\n    void testOwner() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setOwner(\"owner\");\n        Assertions.assertEquals(\"owner\", interfaceConfig.getOwner());\n    }\n\n    @Test\n    void testCallbacks() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setCallbacks(2);\n        Assertions.assertEquals(2, interfaceConfig.getCallbacks().intValue());\n    }\n\n    @Test\n    void testOnconnect() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setOnconnect(\"onConnect\");\n        Assertions.assertEquals(\"onConnect\", interfaceConfig.getOnconnect());\n    }\n\n    @Test\n    void testOndisconnect() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setOndisconnect(\"onDisconnect\");\n        Assertions.assertEquals(\"onDisconnect\", interfaceConfig.getOndisconnect());\n    }\n\n    @Test\n    void testScope() {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setScope(\"scope\");\n        Assertions.assertEquals(\"scope\", interfaceConfig.getScope());\n    }\n\n    @Test\n    void testVerifyMethod() {\n        InterfaceConfig2 interfaceConfig2 = new InterfaceConfig2();\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setTimeout(5000);\n        methodConfig.setName(\"sayHello\");\n        Class<?> clazz = Greeting.class;\n        boolean verifyResult = interfaceConfig2.verifyMethodConfig(methodConfig, clazz, false);\n        Assertions.assertTrue(verifyResult);\n\n        boolean verifyResult2 = interfaceConfig2.verifyMethodConfig(methodConfig, clazz, true);\n        Assertions.assertFalse(verifyResult2);\n    }\n\n    public static class InterfaceConfig2 extends AbstractInterfaceConfig {\n        @Override\n        protected boolean isNeedCheckMethod() {\n            return false;\n        }\n    }\n\n    public static class InterfaceConfig extends AbstractInterfaceConfig {}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/config/Greeting.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface Greeting {\n    String hello();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/config/GreetingLocal1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\npublic class GreetingLocal1 {}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/config/GreetingLocal2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\npublic class GreetingLocal2 implements Greeting {\n    @Override\n    public String hello() {\n        return \"local\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/config/GreetingLocal3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\npublic class GreetingLocal3 implements Greeting {\n    private Greeting greeting;\n\n    public GreetingLocal3(Greeting greeting) {\n        this.greeting = greeting;\n    }\n\n    @Override\n    public String hello() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigConfigurationAdapterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.context;\n\nimport org.apache.dubbo.config.RegistryConfig;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link ConfigConfigurationAdapter}\n */\nclass ConfigConfigurationAdapterTest {\n\n    @Test\n    void test() {\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setAddress(\"127.0.0.1\");\n        registryConfig.setPort(2181);\n\n        String prefix = \"dubbo.registry\";\n        ConfigConfigurationAdapter configConfigurationAdapter = new ConfigConfigurationAdapter(registryConfig, prefix);\n\n        Assertions.assertEquals(configConfigurationAdapter.getInternalProperty(prefix + \".\" + \"address\"), \"127.0.0.1\");\n        Assertions.assertEquals(configConfigurationAdapter.getInternalProperty(prefix + \".\" + \"port\"), \"2181\");\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.context;\n\nimport org.apache.dubbo.common.serialization.PreferSerializationProvider;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Collection;\nimport java.util.Optional;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\nimport static org.apache.dubbo.config.context.ConfigManager.DUBBO_CONFIG_MODE;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\n\n/**\n * {@link AbstractConfigManager} Test\n * {@link ConfigManager} Test\n * {@link ModuleConfigManager} Test\n *\n * @since 2.7.5\n */\nclass ConfigManagerTest {\n\n    private ConfigManager configManager;\n    private ModuleConfigManager moduleConfigManager;\n\n    @BeforeEach\n    public void init() {\n        ApplicationModel.defaultModel().destroy();\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        configManager = applicationModel.getApplicationConfigManager();\n        moduleConfigManager = applicationModel.getDefaultModule().getConfigManager();\n        FrameworkModel.defaultModel().getBeanFactory().registerBean(TestPreferSerializationProvider.class);\n    }\n\n    @Test\n    void testDestroy() {\n        assertTrue(configManager.configsCache.isEmpty());\n    }\n\n    @Test\n    void testDefaultValues() {\n        // assert single\n        assertFalse(configManager.getApplication().isPresent());\n        assertFalse(configManager.getMonitor().isPresent());\n        assertFalse(configManager.getMetrics().isPresent());\n\n        // protocols\n        assertTrue(configManager.getProtocols().isEmpty());\n        assertTrue(configManager.getDefaultProtocols().isEmpty());\n\n        // registries\n        assertTrue(configManager.getRegistries().isEmpty());\n        assertTrue(configManager.getDefaultRegistries().isEmpty());\n\n        // config centers\n        assertTrue(configManager.getConfigCenters().isEmpty());\n\n        // metadata\n        assertTrue(configManager.getMetadataConfigs().isEmpty());\n\n        // services and references\n        assertTrue(moduleConfigManager.getServices().isEmpty());\n        assertTrue(moduleConfigManager.getReferences().isEmpty());\n\n        // providers and consumers\n        assertFalse(moduleConfigManager.getModule().isPresent());\n        assertFalse(moduleConfigManager.getDefaultProvider().isPresent());\n        assertFalse(moduleConfigManager.getDefaultConsumer().isPresent());\n        assertTrue(moduleConfigManager.getProviders().isEmpty());\n        assertTrue(moduleConfigManager.getConsumers().isEmpty());\n    }\n\n    // Test ApplicationConfig correlative methods\n    @Test\n    void testApplicationConfig() {\n        ApplicationConfig config = new ApplicationConfig(\"ConfigManagerTest\");\n        configManager.setApplication(config);\n        assertTrue(configManager.getApplication().isPresent());\n        assertEquals(config, configManager.getApplication().get());\n        assertEquals(config, moduleConfigManager.getApplication().get());\n    }\n\n    // Test MonitorConfig correlative methods\n    @Test\n    void testMonitorConfig() {\n        MonitorConfig monitorConfig = new MonitorConfig();\n        monitorConfig.setGroup(\"test\");\n        configManager.setMonitor(monitorConfig);\n        assertTrue(configManager.getMonitor().isPresent());\n        assertEquals(monitorConfig, configManager.getMonitor().get());\n        assertEquals(monitorConfig, moduleConfigManager.getMonitor().get());\n    }\n\n    // Test ModuleConfig correlative methods\n    @Test\n    void testModuleConfig() {\n        ModuleConfig config = new ModuleConfig();\n        moduleConfigManager.setModule(config);\n        assertTrue(moduleConfigManager.getModule().isPresent());\n        assertEquals(config, moduleConfigManager.getModule().get());\n    }\n\n    // Test MetricsConfig correlative methods\n    @Test\n    void testMetricsConfig() {\n        MetricsConfig config = new MetricsConfig();\n        config.setProtocol(PROTOCOL_PROMETHEUS);\n        configManager.setMetrics(config);\n        assertTrue(configManager.getMetrics().isPresent());\n        assertEquals(config, configManager.getMetrics().get());\n        assertEquals(config, moduleConfigManager.getMetrics().get());\n    }\n\n    // Test ProviderConfig correlative methods\n    @Test\n    void testProviderConfig() {\n        ProviderConfig config = new ProviderConfig();\n        moduleConfigManager.addProviders(asList(config, null));\n        Collection<ProviderConfig> configs = moduleConfigManager.getProviders();\n        assertEquals(1, configs.size());\n        assertEquals(config, configs.iterator().next());\n        assertTrue(moduleConfigManager.getDefaultProvider().isPresent());\n\n        config = new ProviderConfig();\n        config.setId(DEFAULT_KEY);\n        config.setQueues(10);\n        moduleConfigManager.addProvider(config);\n        assertTrue(moduleConfigManager.getDefaultProvider().isPresent());\n        configs = moduleConfigManager.getProviders();\n        assertEquals(2, configs.size());\n    }\n\n    // Test ConsumerConfig correlative methods\n    @Test\n    void testConsumerConfig() {\n        ConsumerConfig config = new ConsumerConfig();\n        moduleConfigManager.addConsumers(asList(config, null));\n        Collection<ConsumerConfig> configs = moduleConfigManager.getConsumers();\n        assertEquals(1, configs.size());\n        assertEquals(config, configs.iterator().next());\n        assertTrue(moduleConfigManager.getDefaultConsumer().isPresent());\n\n        config = new ConsumerConfig();\n        config.setId(DEFAULT_KEY);\n        config.setThreads(10);\n        moduleConfigManager.addConsumer(config);\n        assertTrue(moduleConfigManager.getDefaultConsumer().isPresent());\n        configs = moduleConfigManager.getConsumers();\n        assertEquals(2, configs.size());\n    }\n\n    // Test ProtocolConfig correlative methods\n    @Test\n    void testProtocolConfig() {\n        ProtocolConfig config = new ProtocolConfig();\n        configManager.addProtocols(asList(config, null));\n        Collection<ProtocolConfig> configs = configManager.getProtocols();\n        assertEquals(1, configs.size());\n        assertEquals(config, configs.iterator().next());\n        assertFalse(configManager.getDefaultProtocols().isEmpty());\n        assertEquals(configs, moduleConfigManager.getProtocols());\n        assertNotEquals(20881, config.getPort());\n        assertNotEquals(config.getSerialization(), \"fastjson2\");\n        ProtocolConfig defaultConfig = new ProtocolConfig();\n        defaultConfig.setPort(20881);\n        defaultConfig.setSerialization(\"fastjson2\");\n        config.mergeProtocol(defaultConfig);\n        assertEquals(config.getPort(), 20881);\n        assertEquals(config.getSerialization(), \"fastjson2\");\n    }\n\n    // Test RegistryConfig correlative methods\n    @Test\n    void testRegistryConfig() {\n        RegistryConfig config = new RegistryConfig();\n        configManager.addRegistries(asList(config, null));\n        Collection<RegistryConfig> configs = configManager.getRegistries();\n        assertEquals(1, configs.size());\n        assertEquals(config, configs.iterator().next());\n        assertFalse(configManager.getDefaultRegistries().isEmpty());\n        assertEquals(configs, moduleConfigManager.getRegistries());\n    }\n\n    // Test ConfigCenterConfig correlative methods\n    @Test\n    void testConfigCenterConfig() {\n        String address = \"zookeeper://127.0.0.1:2181\";\n        ConfigCenterConfig config = new ConfigCenterConfig();\n        config.setAddress(address);\n        configManager.addConfigCenters(asList(config, null));\n        Collection<ConfigCenterConfig> configs = configManager.getConfigCenters();\n        assertEquals(1, configs.size());\n        assertEquals(config, configs.iterator().next());\n\n        // add duplicated config, expecting ignore equivalent configs\n        ConfigCenterConfig config2 = new ConfigCenterConfig();\n        config2.setAddress(address);\n        configManager.addConfigCenter(config2);\n\n        configs = configManager.getConfigCenters();\n        assertEquals(1, configs.size());\n        assertEquals(config, configs.iterator().next());\n        assertEquals(configs, moduleConfigManager.getConfigCenters());\n    }\n\n    @Test\n    void testAddConfig() {\n        configManager.addConfig(new ApplicationConfig(\"ConfigManagerTest\"));\n        configManager.addConfig(new ProtocolConfig());\n        moduleConfigManager.addConfig(new ProviderConfig());\n\n        assertTrue(configManager.getApplication().isPresent());\n        assertFalse(configManager.getProtocols().isEmpty());\n        assertFalse(moduleConfigManager.getProviders().isEmpty());\n    }\n\n    @Test\n    void testAddCustomConfig() {\n        configManager.addConfig(new CustomRegistryConfig(\"CustomConfigManagerTest\"));\n\n        assertTrue(configManager.getRegistry(\"CustomConfigManagerTest\").isPresent());\n    }\n\n    static class CustomRegistryConfig extends RegistryConfig {\n\n        CustomRegistryConfig(String id) {\n            super();\n            this.setId(id);\n        }\n    }\n\n    @Test\n    void testRefreshAll() {\n        configManager.refreshAll();\n        moduleConfigManager.refreshAll();\n    }\n\n    @Test\n    void testDefaultConfig() {\n        ProviderConfig providerConfig = new ProviderConfig();\n        providerConfig.setDefault(false);\n        assertFalse(ConfigManager.isDefaultConfig(providerConfig));\n\n        ProviderConfig providerConfig1 = new ProviderConfig();\n        assertNull(ConfigManager.isDefaultConfig(providerConfig1));\n\n        ProviderConfig providerConfig3 = new ProviderConfig();\n        providerConfig3.setDefault(true);\n        assertTrue(ConfigManager.isDefaultConfig(providerConfig3));\n\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        protocolConfig.setDefault(false);\n        assertFalse(ConfigManager.isDefaultConfig(protocolConfig));\n    }\n\n    @Test\n    void testConfigMode() {\n        ApplicationConfig applicationConfig1 = new ApplicationConfig(\"app1\");\n        ApplicationConfig applicationConfig2 = new ApplicationConfig(\"app2\");\n\n        try {\n            // test strict mode\n            ApplicationModel.reset();\n            ConfigManager configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n            Assertions.assertEquals(ConfigMode.STRICT, configManager.getConfigMode());\n\n            System.setProperty(DUBBO_CONFIG_MODE, ConfigMode.STRICT.name());\n            ApplicationModel.reset();\n            Assertions.assertEquals(ConfigMode.STRICT, configManager.getConfigMode());\n\n            configManager.addConfig(applicationConfig1);\n            try {\n                configManager.addConfig(applicationConfig2);\n                fail(\"strict mode cannot add two application configs\");\n            } catch (Exception e) {\n                assertEquals(IllegalStateException.class, e.getClass());\n                assertTrue(e.getMessage().contains(\"please remove redundant configs and keep only one\"));\n            }\n\n            // test override mode\n            System.setProperty(DUBBO_CONFIG_MODE, ConfigMode.OVERRIDE.name());\n            ApplicationModel.reset();\n            configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n            Assertions.assertEquals(ConfigMode.OVERRIDE, configManager.getConfigMode());\n\n            configManager.addConfig(applicationConfig1);\n            configManager.addConfig(applicationConfig2);\n            assertEquals(applicationConfig2, configManager.getApplicationOrElseThrow());\n\n            // test ignore mode\n            System.setProperty(DUBBO_CONFIG_MODE, ConfigMode.IGNORE.name());\n            ApplicationModel.reset();\n            configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n            Assertions.assertEquals(ConfigMode.IGNORE, configManager.getConfigMode());\n\n            configManager.addConfig(applicationConfig1);\n            configManager.addConfig(applicationConfig2);\n            assertEquals(applicationConfig1, configManager.getApplicationOrElseThrow());\n\n            // test OVERRIDE_ALL mode\n            System.setProperty(DUBBO_CONFIG_MODE, ConfigMode.OVERRIDE_ALL.name());\n            ApplicationModel.reset();\n            configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n            Assertions.assertEquals(ConfigMode.OVERRIDE_ALL, configManager.getConfigMode());\n\n            ApplicationConfig applicationConfig11 = new ApplicationConfig(\"app11\");\n            ApplicationConfig applicationConfig22 = new ApplicationConfig(\"app22\");\n            applicationConfig11.setParameters(CollectionUtils.toStringMap(\"k1\", \"v1\", \"k2\", \"v2\"));\n            applicationConfig22.setParameters(CollectionUtils.toStringMap(\"k1\", \"v11\", \"k2\", \"v22\", \"k3\", \"v3\"));\n            configManager.addConfig(applicationConfig11);\n            configManager.addConfig(applicationConfig22);\n\n            assertEquals(applicationConfig11, configManager.getApplicationOrElseThrow());\n            assertEquals(applicationConfig11.getName(), \"app22\");\n            assertEquals(\n                    applicationConfig11.getParameters(),\n                    CollectionUtils.toStringMap(\"k1\", \"v11\", \"k2\", \"v22\", \"k3\", \"v3\"));\n\n            // test OVERRIDE_IF_ABSENT mode\n            System.setProperty(DUBBO_CONFIG_MODE, ConfigMode.OVERRIDE_IF_ABSENT.name());\n            ApplicationModel.reset();\n            configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n            Assertions.assertEquals(ConfigMode.OVERRIDE_IF_ABSENT, configManager.getConfigMode());\n\n            ApplicationConfig applicationConfig33 = new ApplicationConfig(\"app33\");\n            ApplicationConfig applicationConfig44 = new ApplicationConfig(\"app44\");\n            applicationConfig33.setParameters(CollectionUtils.toStringMap(\"k1\", \"v1\", \"k2\", \"v2\"));\n            applicationConfig44.setParameters(CollectionUtils.toStringMap(\"k1\", \"v11\", \"k2\", \"v22\", \"k3\", \"v3\"));\n            configManager.addConfig(applicationConfig33);\n            configManager.addConfig(applicationConfig44);\n\n            assertEquals(applicationConfig33, configManager.getApplicationOrElseThrow());\n            assertEquals(\"app33\", applicationConfig33.getName());\n            assertEquals(\n                    CollectionUtils.toStringMap(\"k1\", \"v1\", \"k2\", \"v2\", \"k3\", \"v3\"),\n                    applicationConfig33.getParameters());\n        } finally {\n            System.clearProperty(DUBBO_CONFIG_MODE);\n        }\n    }\n\n    @Test\n    void testGetConfigByIdOrName() {\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setId(\"registryID_1\");\n        configManager.addRegistry(registryConfig);\n        Optional<RegistryConfig> registryConfigOptional =\n                configManager.getConfig(RegistryConfig.class, registryConfig.getId());\n\n        if (registryConfigOptional.isPresent()) {\n            Assertions.assertEquals(registryConfigOptional.get(), registryConfig);\n        } else {\n            fail(\"registryConfigOptional is empty! \");\n        }\n\n        ProtocolConfig protocolConfig = new ProtocolConfig(\"dubbo\");\n        configManager.addProtocol(protocolConfig);\n        Optional<ProtocolConfig> protocolConfigOptional =\n                configManager.getConfig(ProtocolConfig.class, protocolConfig.getName());\n\n        if (protocolConfigOptional.isPresent()) {\n            Assertions.assertEquals(protocolConfigOptional.get(), protocolConfig);\n        } else {\n            fail(\"protocolConfigOptional is empty! \");\n        }\n\n        // test multi config has same name(dubbo)\n        ProtocolConfig protocolConfig2 = new ProtocolConfig(\"dubbo\");\n        protocolConfig2.setPort(9103);\n        configManager.addProtocol(protocolConfig2);\n        try {\n            configManager.getConfig(ProtocolConfig.class, protocolConfig.getName());\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof IllegalStateException);\n            String msg = e.getMessage();\n\n            Assertions.assertTrue(\n                    msg.startsWith(\"Found more than one config by name: dubbo, instances: \"),\n                    \"Unexpected message prefix: \" + msg);\n            Assertions.assertTrue(\n                    msg.contains(\"<dubbo:protocol port=\\\"9103\\\" name=\\\"dubbo\\\" />\"),\n                    \"Message should mention protocol with port 9103: \" + msg);\n            Assertions.assertTrue(\n                    msg.contains(\"<dubbo:protocol name=\\\"dubbo\\\" />\"),\n                    \"Message should mention protocol with default port: \" + msg);\n            Assertions.assertTrue(\n                    msg.endsWith(\"Please remove redundant configs or get config by id.\"),\n                    \"Unexpected message suffix: \" + msg);\n        }\n\n        ModuleConfig moduleConfig = new ModuleConfig();\n        moduleConfig.setId(\"moduleID_1\");\n        moduleConfigManager.setModule(moduleConfig);\n        Optional<ModuleConfig> moduleConfigOptional =\n                moduleConfigManager.getConfig(ModuleConfig.class, moduleConfig.getId());\n        Assertions.assertEquals(moduleConfig, moduleConfigOptional.get());\n\n        Optional<RegistryConfig> config = moduleConfigManager.getConfig(RegistryConfig.class, registryConfig.getId());\n        Assertions.assertEquals(config.get(), registryConfig);\n    }\n\n    @Test\n    void testLoadConfigsOfTypeFromProps() {\n        try {\n            // dubbo.application.enable-file-cache = false\n            configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);\n            Optional<ApplicationConfig> application = configManager.getApplication();\n            Assertions.assertTrue(application.isPresent());\n            configManager.removeConfig(application.get());\n\n            System.setProperty(\"dubbo.protocols.dubbo1.port\", \"20880\");\n            System.setProperty(\"dubbo.protocols.dubbo2.port\", \"20881\");\n            System.setProperty(\"dubbo.protocols.rest1.port\", \"8080\");\n            System.setProperty(\"dubbo.protocols.rest2.port\", \"8081\");\n            configManager.loadConfigsOfTypeFromProps(ProtocolConfig.class);\n            Collection<ProtocolConfig> protocols = configManager.getProtocols();\n            Assertions.assertEquals(4, protocols.size());\n\n            System.setProperty(\"dubbo.applications.app1.name\", \"app-demo1\");\n            System.setProperty(\"dubbo.applications.app2.name\", \"app-demo2\");\n            try {\n                configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);\n                Assertions.fail();\n            } catch (Exception e) {\n                Assertions.assertTrue(e.getMessage().contains(\"load config failed\"));\n            }\n        } finally {\n            System.clearProperty(\"dubbo.protocols.dubbo1.port\");\n            System.clearProperty(\"dubbo.protocols.dubbo2.port\");\n            System.clearProperty(\"dubbo.protocols.rest1.port\");\n            System.clearProperty(\"dubbo.protocols.rest2.port\");\n            System.clearProperty(\"dubbo.applications.app1.name\");\n            System.clearProperty(\"dubbo.applications.app2.name\");\n        }\n    }\n\n    @Test\n    void testLoadConfig() {\n        configManager.loadConfigs();\n        Assertions.assertTrue(configManager.getApplication().isPresent());\n        Assertions.assertTrue(configManager.getSsl().isPresent());\n        Assertions.assertFalse(configManager.getProtocols().isEmpty());\n\n        int port = 20880;\n        ProtocolConfig config1 = new ProtocolConfig();\n        config1.setName(\"dubbo\");\n        config1.setPort(port);\n\n        ProtocolConfig config2 = new ProtocolConfig();\n        config2.setName(\"rest\");\n        config2.setPort(port);\n        configManager.addProtocols(asList(config1, config2));\n        try {\n            configManager.loadConfigs();\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof IllegalStateException);\n            Assertions.assertTrue(e.getMessage().contains(\"Duplicated port used by protocol configs, port: \" + port));\n        }\n\n        moduleConfigManager.loadConfigs();\n        Assertions.assertTrue(moduleConfigManager.getModule().isPresent());\n        Assertions.assertFalse(moduleConfigManager.getProviders().isEmpty());\n        Assertions.assertFalse(moduleConfigManager.getConsumers().isEmpty());\n    }\n\n    public static class TestPreferSerializationProvider implements PreferSerializationProvider {\n        @Override\n        public String getPreferSerialization() {\n            return \"hessian2\";\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/DefaultTypeBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition;\n\nimport org.apache.dubbo.metadata.definition.builder.DefaultTypeBuilder;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.HashMap;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\npublic class DefaultTypeBuilderTest {\n    @Test\n    void testInnerClass() {\n        TypeDefinitionBuilder.initBuilders(FrameworkModel.defaultModel());\n\n        Assertions.assertEquals(\n                String.class.getName(),\n                DefaultTypeBuilder.build(String.class, new HashMap<>()).getType());\n\n        DefaultTypeBuilderTest innerObject = new DefaultTypeBuilderTest() {};\n        Assertions.assertEquals(\n                DefaultTypeBuilderTest.class.getName() + \"$1\",\n                DefaultTypeBuilder.build(innerObject.getClass(), new HashMap<>())\n                        .getType());\n\n        TypeDefinitionBuilder.BUILDERS = null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/MetadataTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition;\n\nimport org.apache.dubbo.metadata.definition.common.ClassExtendsMap;\nimport org.apache.dubbo.metadata.definition.common.ColorEnum;\nimport org.apache.dubbo.metadata.definition.common.OuterClass;\nimport org.apache.dubbo.metadata.definition.common.ResultWithRawCollections;\nimport org.apache.dubbo.metadata.definition.common.TestService;\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\n/**\n * TypeDefinitionBuilder\n * <p>\n * 16/9/22.\n */\nclass MetadataTest {\n\n    @BeforeAll\n    public static void setup() {\n        TypeDefinitionBuilder.initBuilders(FrameworkModel.defaultModel());\n    }\n\n    /**\n     *\n     */\n    @Test\n    void testInnerClassType() {\n        TypeDefinitionBuilder builder = new TypeDefinitionBuilder();\n        TypeDefinition td = builder.build(OuterClass.InnerClass.class, OuterClass.InnerClass.class);\n\n        Assertions.assertEquals(\"org.apache.dubbo.metadata.definition.common.OuterClass.InnerClass\", td.getType());\n        Assertions.assertEquals(1, td.getProperties().size());\n        Assertions.assertNotNull(td.getProperties().get(\"name\"));\n        ServiceDefinition sd = MetadataUtils.generateMetadata(TestService.class);\n\n        Assertions.assertEquals(TestService.class.getName(), sd.getCanonicalName());\n        Assertions.assertEquals(\n                TestService.class.getMethods().length, sd.getMethods().size());\n        boolean containsType = false;\n        for (TypeDefinition type : sd.getTypes()) {\n            if (type.getType().equals(\"org.apache.dubbo.metadata.definition.common.OuterClass.InnerClass\")) {\n                containsType = true;\n                break;\n            }\n        }\n        Assertions.assertTrue(containsType);\n    }\n\n    /**\n     *\n     */\n    @Test\n    void testRawMap() {\n        TypeDefinitionBuilder builder = new TypeDefinitionBuilder();\n        TypeDefinition td = builder.build(ResultWithRawCollections.class, ResultWithRawCollections.class);\n\n        Assertions.assertEquals(\"org.apache.dubbo.metadata.definition.common.ResultWithRawCollections\", td.getType());\n        Assertions.assertEquals(2, td.getProperties().size());\n        Assertions.assertEquals(\"java.util.Map\", td.getProperties().get(\"map\"));\n        Assertions.assertEquals(\"java.util.List\", td.getProperties().get(\"list\"));\n\n        ServiceDefinition sd = MetadataUtils.generateMetadata(TestService.class);\n\n        Assertions.assertEquals(TestService.class.getName(), sd.getCanonicalName());\n        Assertions.assertEquals(\n                TestService.class.getMethods().length, sd.getMethods().size());\n        boolean containsType = false;\n        for (TypeDefinition type : sd.getTypes()) {\n            if (type.getType().equals(\"org.apache.dubbo.metadata.definition.common.ResultWithRawCollections\")) {\n                containsType = true;\n                break;\n            }\n        }\n        Assertions.assertTrue(containsType);\n    }\n\n    @Test\n    void testEnum() {\n        TypeDefinitionBuilder builder = new TypeDefinitionBuilder();\n        TypeDefinition td = builder.build(ColorEnum.class, ColorEnum.class);\n\n        Assertions.assertEquals(\"org.apache.dubbo.metadata.definition.common.ColorEnum\", td.getType());\n        Assertions.assertEquals(3, td.getEnums().size());\n        Assertions.assertTrue(td.getEnums().contains(\"RED\"));\n        Assertions.assertTrue(td.getEnums().contains(\"YELLOW\"));\n        Assertions.assertTrue(td.getEnums().contains(\"BLUE\"));\n\n        ServiceDefinition sd = MetadataUtils.generateMetadata(TestService.class);\n\n        Assertions.assertEquals(TestService.class.getName(), sd.getCanonicalName());\n        Assertions.assertEquals(\n                TestService.class.getMethods().length, sd.getMethods().size());\n        boolean containsType = false;\n        for (TypeDefinition type : sd.getTypes()) {\n            if (type.getType().equals(\"org.apache.dubbo.metadata.definition.common.ColorEnum\")) {\n                containsType = true;\n                break;\n            }\n        }\n        Assertions.assertTrue(containsType);\n    }\n\n    @Test\n    void testExtendsMap() {\n        TypeDefinitionBuilder builder = new TypeDefinitionBuilder();\n        TypeDefinition td = builder.build(ClassExtendsMap.class, ClassExtendsMap.class);\n\n        Assertions.assertEquals(\"org.apache.dubbo.metadata.definition.common.ClassExtendsMap\", td.getType());\n        Assertions.assertEquals(0, td.getProperties().size());\n\n        ServiceDefinition sd = MetadataUtils.generateMetadata(TestService.class);\n\n        Assertions.assertEquals(TestService.class.getName(), sd.getCanonicalName());\n        Assertions.assertEquals(\n                TestService.class.getMethods().length, sd.getMethods().size());\n        boolean containsType = false;\n        for (TypeDefinition type : sd.getTypes()) {\n            if (type.getType().equals(\"org.apache.dubbo.metadata.definition.common.ClassExtendsMap\")) {\n                containsType = true;\n                break;\n            }\n        }\n        Assertions.assertFalse(containsType);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/MetadataUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition;\n\nimport org.apache.dubbo.metadata.definition.model.MethodDefinition;\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.metadata.definition.util.ClassUtils;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\nimport java.util.List;\n\n/**\n * generate metadata\n * <p>\n * 2017-4-17 14:33:24\n */\npublic class MetadataUtils {\n\n    /**\n     * com.taobao.hsf.metadata.store.MetadataInfoStoreServiceRedis.publishClassInfo(ServiceMetadata) 生成元数据的代码\n     */\n    public static ServiceDefinition generateMetadata(Class<?> interfaceClass) {\n        ServiceDefinition sd = new ServiceDefinition();\n        sd.setCanonicalName(interfaceClass.getCanonicalName());\n        sd.setCodeSource(ClassUtils.getCodeSource(interfaceClass));\n\n        TypeDefinitionBuilder builder = new TypeDefinitionBuilder();\n        List<Method> methods = ClassUtils.getPublicNonStaticMethods(interfaceClass);\n        for (Method method : methods) {\n            MethodDefinition md = new MethodDefinition();\n            md.setName(method.getName());\n\n            Class<?>[] paramTypes = method.getParameterTypes();\n            Type[] genericParamTypes = method.getGenericParameterTypes();\n\n            String[] parameterTypes = new String[paramTypes.length];\n            for (int i = 0; i < paramTypes.length; i++) {\n                try {\n                    TypeDefinition td = builder.build(genericParamTypes[i], paramTypes[i]);\n                    parameterTypes[i] = td.getType();\n                } catch (Exception e) {\n                    parameterTypes[i] = paramTypes[i].getName();\n                }\n            }\n            md.setParameterTypes(parameterTypes);\n            try {\n                TypeDefinition td = builder.build(method.getGenericReturnType(), method.getReturnType());\n                md.setReturnType(td.getType());\n            } catch (Exception e) {\n                md.setReturnType(method.getReturnType().getName());\n            }\n\n            sd.getMethods().add(md);\n        }\n\n        sd.setTypes(builder.getTypeDefinitions());\n        return sd;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/ServiceDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition;\n\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.MethodDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.metadata.definition.service.ComplexObject;\nimport org.apache.dubbo.metadata.definition.service.DemoService;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\n/**\n * 2018/11/6\n */\nclass ServiceDefinitionBuilderTest {\n\n    private static FrameworkModel frameworkModel;\n\n    @BeforeAll\n    public static void setup() {\n        frameworkModel = new FrameworkModel();\n        TypeDefinitionBuilder.initBuilders(frameworkModel);\n    }\n\n    @AfterAll\n    public static void clear() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testBuilderComplexObject() {\n        TypeDefinitionBuilder.initBuilders(FrameworkModel.defaultModel());\n        FullServiceDefinition fullServiceDefinition = ServiceDefinitionBuilder.buildFullDefinition(DemoService.class);\n        checkComplexObjectAsParam(fullServiceDefinition);\n    }\n\n    void checkComplexObjectAsParam(FullServiceDefinition fullServiceDefinition) {\n        Assertions.assertTrue(fullServiceDefinition\n                        .getAnnotations()\n                        .contains(\n                                \"@org.apache.dubbo.metadata.definition.service.annotation.MockTypeAnnotation(value=666)\")\n                // JDK 17 style\n                || fullServiceDefinition\n                        .getAnnotations()\n                        .contains(\"@org.apache.dubbo.metadata.definition.service.annotation.MockTypeAnnotation(666)\"));\n\n        List<MethodDefinition> methodDefinitions = fullServiceDefinition.getMethods();\n        MethodDefinition complexCompute = null;\n        MethodDefinition findComplexObject = null;\n        MethodDefinition testAnnotation = null;\n        for (MethodDefinition methodDefinition : methodDefinitions) {\n            if (\"complexCompute\".equals(methodDefinition.getName())) {\n                complexCompute = methodDefinition;\n            } else if (\"findComplexObject\".equals(methodDefinition.getName())) {\n                findComplexObject = methodDefinition;\n            } else if (\"testAnnotation\".equals(methodDefinition.getName())) {\n                testAnnotation = methodDefinition;\n            }\n        }\n        Assertions.assertTrue(Arrays.equals(\n                complexCompute.getParameterTypes(),\n                new String[] {String.class.getName(), ComplexObject.class.getName()}));\n        Assertions.assertEquals(complexCompute.getReturnType(), String.class.getName());\n\n        Assertions.assertTrue(Arrays.equals(findComplexObject.getParameterTypes(), new String[] {\n            String.class.getName(),\n            \"int\",\n            \"long\",\n            String[].class.getCanonicalName(),\n            \"java.util.List<java.lang.Integer>\",\n            ComplexObject.TestEnum.class.getCanonicalName()\n        }));\n        Assertions.assertEquals(findComplexObject.getReturnType(), ComplexObject.class.getCanonicalName());\n\n        Assertions.assertTrue(\n                (testAnnotation\n                                        .getAnnotations()\n                                        .contains(\n                                                \"@org.apache.dubbo.metadata.definition.service.annotation.MockMethodAnnotation(value=777)\")\n                                && testAnnotation\n                                        .getAnnotations()\n                                        .contains(\n                                                \"@org.apache.dubbo.metadata.definition.service.annotation.MockMethodAnnotation2(value=888)\"))\n                        // JDK 17 style\n                        || (testAnnotation\n                                        .getAnnotations()\n                                        .contains(\n                                                \"@org.apache.dubbo.metadata.definition.service.annotation.MockMethodAnnotation(777)\")\n                                && testAnnotation\n                                        .getAnnotations()\n                                        .contains(\n                                                \"@org.apache.dubbo.metadata.definition.service.annotation.MockMethodAnnotation2(888)\")));\n        Assertions.assertEquals(testAnnotation.getReturnType(), \"void\");\n\n        List<TypeDefinition> typeDefinitions = fullServiceDefinition.getTypes();\n\n        TypeDefinition topTypeDefinition = null;\n        TypeDefinition innerTypeDefinition = null;\n        TypeDefinition inner2TypeDefinition = null;\n        TypeDefinition inner3TypeDefinition = null;\n        TypeDefinition listTypeDefinition = null;\n        for (TypeDefinition typeDefinition : typeDefinitions) {\n            if (typeDefinition.getType().equals(ComplexObject.class.getCanonicalName())) {\n                topTypeDefinition = typeDefinition;\n            } else if (typeDefinition.getType().equals(ComplexObject.InnerObject.class.getCanonicalName())) {\n                innerTypeDefinition = typeDefinition;\n            } else if (typeDefinition.getType().equals(ComplexObject.InnerObject2.class.getCanonicalName())) {\n                inner2TypeDefinition = typeDefinition;\n            } else if (typeDefinition.getType().equals(ComplexObject.InnerObject3.class.getCanonicalName())) {\n                inner3TypeDefinition = typeDefinition;\n            } else if (typeDefinition.getType().equals(\"java.util.List<java.lang.Integer>\")) {\n                listTypeDefinition = typeDefinition;\n            }\n        }\n        Assertions.assertEquals(\"long\", topTypeDefinition.getProperties().get(\"v\"));\n        Assertions.assertEquals(\n                \"java.util.Map<java.lang.String,java.lang.String>\",\n                topTypeDefinition.getProperties().get(\"maps\"));\n        Assertions.assertEquals(\n                ComplexObject.InnerObject.class.getCanonicalName(),\n                topTypeDefinition.getProperties().get(\"innerObject\"));\n        Assertions.assertEquals(\n                \"java.util.List<java.lang.Integer>\",\n                topTypeDefinition.getProperties().get(\"intList\"));\n        Assertions.assertEquals(\n                \"java.lang.String[]\", topTypeDefinition.getProperties().get(\"strArrays\"));\n        Assertions.assertEquals(\n                \"org.apache.dubbo.metadata.definition.service.ComplexObject.InnerObject3[]\",\n                topTypeDefinition.getProperties().get(\"innerObject3\"));\n        Assertions.assertEquals(\n                \"org.apache.dubbo.metadata.definition.service.ComplexObject.TestEnum\",\n                topTypeDefinition.getProperties().get(\"testEnum\"));\n        Assertions.assertEquals(\n                \"java.util.Set<org.apache.dubbo.metadata.definition.service.ComplexObject.InnerObject2>\",\n                topTypeDefinition.getProperties().get(\"innerObject2\"));\n\n        Assertions.assertSame(\n                \"java.lang.String\", innerTypeDefinition.getProperties().get(\"innerA\"));\n        Assertions.assertSame(\"int\", innerTypeDefinition.getProperties().get(\"innerB\"));\n\n        Assertions.assertSame(\n                \"java.lang.String\", inner2TypeDefinition.getProperties().get(\"innerA2\"));\n        Assertions.assertSame(\"int\", inner2TypeDefinition.getProperties().get(\"innerB2\"));\n\n        Assertions.assertSame(\n                \"java.lang.String\", inner3TypeDefinition.getProperties().get(\"innerA3\"));\n\n        Assertions.assertEquals(\n                Integer.class.getCanonicalName(), listTypeDefinition.getItems().get(0));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/Test3TypeBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition;\n\nimport org.apache.dubbo.metadata.definition.builder.TypeBuilder;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport java.lang.reflect.Type;\nimport java.util.Map;\n\n/**\n * test for sort\n */\npublic class Test3TypeBuilder implements TypeBuilder {\n    // it is smaller than the implements of TypeBuilder\n    @Override\n    public int getPriority() {\n        return 10;\n    }\n\n    @Override\n    public boolean accept(Class<?> clazz) {\n        return false;\n    }\n\n    @Override\n    public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/TestTypeBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition;\n\nimport org.apache.dubbo.metadata.definition.builder.TypeBuilder;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport java.lang.reflect.Type;\nimport java.util.Map;\n\n/**\n * test for sort\n */\npublic class TestTypeBuilder implements TypeBuilder {\n    // it is smaller than the implements of TypeBuilder\n    @Override\n    public int getPriority() {\n        return -3;\n    }\n\n    @Override\n    public boolean accept(Class<?> clazz) {\n        return false;\n    }\n\n    @Override\n    public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition;\n\nimport org.apache.dubbo.metadata.definition.builder.TypeBuilder;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass TypeDefinitionBuilderTest {\n\n    @Test\n    void testSortTypeBuilder() {\n        TypeDefinitionBuilder.initBuilders(FrameworkModel.defaultModel());\n\n        TypeBuilder tb = TypeDefinitionBuilder.BUILDERS.get(0);\n        Assertions.assertTrue(tb instanceof TestTypeBuilder);\n\n        tb = TypeDefinitionBuilder.BUILDERS.get(TypeDefinitionBuilder.BUILDERS.size() - 1);\n        Assertions.assertTrue(tb instanceof Test3TypeBuilder);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/common/ClassExtendsMap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.common;\n\nimport java.util.HashMap;\n\npublic class ClassExtendsMap extends HashMap<String, Object> {\n\n    private static final long serialVersionUID = 5108356684263812575L;\n    private ClassExtendsMap resultMap;\n\n    public ClassExtendsMap() {}\n\n    public ClassExtendsMap getResultMap() {\n        return resultMap;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/common/ColorEnum.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.common;\n\npublic enum ColorEnum {\n    RED,\n    YELLOW,\n    BLUE\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/common/OuterClass.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.common;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 16/9/22.\n */\npublic class OuterClass {\n    private static final Logger logger = LoggerFactory.getLogger(OuterClass.class);\n\n    public static class InnerClass {\n\n        private String name;\n\n        public InnerClass() {\n            logger.debug(\"I am inner class\");\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/common/ResultWithRawCollections.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.common;\n\nimport java.util.List;\nimport java.util.Map;\n\n@SuppressWarnings(\"rawtypes\")\npublic class ResultWithRawCollections {\n\n    private Map map;\n    private List list;\n\n    public ResultWithRawCollections() {}\n\n    public ResultWithRawCollections(Map map, List list) {\n        this.map = map;\n        this.list = list;\n    }\n\n    public List getList() {\n        return list;\n    }\n\n    public void setList(List list) {\n        this.list = list;\n    }\n\n    public Map getMap() {\n        return map;\n    }\n\n    public void setMap(Map map) {\n        this.map = map;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/common/TestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.common;\n\n/**\n * 16/9/22.\n */\npublic interface TestService {\n    /**\n     *\n     * @param innerClass\n     * @return\n     */\n    void m1(OuterClass.InnerClass innerClass);\n\n    /**\n     *\n     * @param a\n     */\n    void m2(int[] a);\n\n    /**\n     *\n     * @param s1\n     * @return\n     */\n    ResultWithRawCollections m3(String s1);\n\n    /**\n     *\n     * @param color\n     */\n    void m4(ColorEnum color);\n\n    /**\n     *\n     * @param s1\n     * @return\n     */\n    ClassExtendsMap m5(String s1);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/service/ComplexObject.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.service;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\n/**\n * for test\n */\npublic class ComplexObject {\n\n    public ComplexObject() {}\n\n    public ComplexObject(String var1, int var2, long l, String[] var3, List<Integer> var4, TestEnum testEnum) {\n        this.setInnerObject(new InnerObject());\n        this.getInnerObject().setInnerA(var1);\n        this.getInnerObject().setInnerB(var2);\n        this.setIntList(var4);\n        this.setStrArrays(var3);\n        this.setTestEnum(testEnum);\n        this.setV(l);\n        InnerObject2 io21 = new InnerObject2();\n        io21.setInnerA2(var1 + \"_21\");\n        io21.setInnerB2(var2 + 100000);\n        InnerObject2 io22 = new InnerObject2();\n        io22.setInnerA2(var1 + \"_22\");\n        io22.setInnerB2(var2 + 200000);\n        this.setInnerObject2(new HashSet<InnerObject2>(Arrays.asList(io21, io22)));\n\n        InnerObject3 io31 = new InnerObject3();\n        io31.setInnerA3(var1 + \"_31\");\n        InnerObject3 io32 = new InnerObject3();\n        io32.setInnerA3(var1 + \"_32\");\n        InnerObject3 io33 = new InnerObject3();\n        io33.setInnerA3(var1 + \"_33\");\n        this.setInnerObject3(new InnerObject3[] {io31, io32, io33});\n        this.maps = new HashMap<>(4);\n        this.maps.put(var1 + \"_k1\", var1 + \"_v1\");\n        this.maps.put(var1 + \"_k2\", var1 + \"_v2\");\n    }\n\n    private InnerObject innerObject;\n    private Set<InnerObject2> innerObject2;\n    private InnerObject3[] innerObject3;\n    private String[] strArrays;\n    private List<Integer> intList;\n    private long v;\n    private TestEnum testEnum;\n    private Map<String, String> maps;\n\n    public InnerObject getInnerObject() {\n        return innerObject;\n    }\n\n    public void setInnerObject(InnerObject innerObject) {\n        this.innerObject = innerObject;\n    }\n\n    public String[] getStrArrays() {\n        return strArrays;\n    }\n\n    public void setStrArrays(String[] strArrays) {\n        this.strArrays = strArrays;\n    }\n\n    public List<Integer> getIntList() {\n        return intList;\n    }\n\n    public void setIntList(List<Integer> intList) {\n        this.intList = intList;\n    }\n\n    public long getV() {\n        return v;\n    }\n\n    public void setV(long v) {\n        this.v = v;\n    }\n\n    public TestEnum getTestEnum() {\n        return testEnum;\n    }\n\n    public void setTestEnum(TestEnum testEnum) {\n        this.testEnum = testEnum;\n    }\n\n    public Set<InnerObject2> getInnerObject2() {\n        return innerObject2;\n    }\n\n    public void setInnerObject2(Set<InnerObject2> innerObject2) {\n        this.innerObject2 = innerObject2;\n    }\n\n    public InnerObject3[] getInnerObject3() {\n        return innerObject3;\n    }\n\n    public void setInnerObject3(InnerObject3[] innerObject3) {\n        this.innerObject3 = innerObject3;\n    }\n\n    public Map<String, String> getMaps() {\n        return maps;\n    }\n\n    public void setMaps(Map<String, String> maps) {\n        this.maps = maps;\n    }\n\n    @Override\n    public String toString() {\n        return \"ComplexObject{\" + \"innerObject=\"\n                + innerObject + \", innerObject2=\"\n                + innerObject2 + \", innerObject3=\"\n                + Arrays.toString(innerObject3) + \", strArrays=\"\n                + Arrays.toString(strArrays) + \", intList=\"\n                + intList + \", v=\"\n                + v + \", testEnum=\"\n                + testEnum + \", maps=\"\n                + maps + '}';\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof ComplexObject)) return false;\n        ComplexObject that = (ComplexObject) o;\n        return getV() == that.getV()\n                && Objects.equals(getInnerObject(), that.getInnerObject())\n                && Objects.equals(getInnerObject2(), that.getInnerObject2())\n                && Arrays.equals(getInnerObject3(), that.getInnerObject3())\n                && Arrays.equals(getStrArrays(), that.getStrArrays())\n                && Objects.equals(getIntList(), that.getIntList())\n                && getTestEnum() == that.getTestEnum()\n                && Objects.equals(getMaps(), that.getMaps());\n    }\n\n    @Override\n    public int hashCode() {\n        int result = Objects.hash(getInnerObject(), getInnerObject2(), getIntList(), getV(), getTestEnum(), getMaps());\n        result = 31 * result + Arrays.hashCode(getInnerObject3());\n        result = 31 * result + Arrays.hashCode(getStrArrays());\n        return result;\n    }\n\n    public enum TestEnum {\n        VALUE1,\n        VALUE2\n    }\n\n    public static class InnerObject {\n        String innerA;\n        int innerB;\n\n        public String getInnerA() {\n            return innerA;\n        }\n\n        public void setInnerA(String innerA) {\n            this.innerA = innerA;\n        }\n\n        public int getInnerB() {\n            return innerB;\n        }\n\n        public void setInnerB(int innerB) {\n            this.innerB = innerB;\n        }\n\n        @Override\n        public String toString() {\n            return \"InnerObject{\" + \"innerA='\" + innerA + '\\'' + \", innerB=\" + innerB + '}';\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof InnerObject)) return false;\n            InnerObject that = (InnerObject) o;\n            return getInnerB() == that.getInnerB() && Objects.equals(getInnerA(), that.getInnerA());\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(getInnerA(), getInnerB());\n        }\n    }\n\n    public static class InnerObject2 {\n        String innerA2;\n        int innerB2;\n\n        public String getInnerA2() {\n            return innerA2;\n        }\n\n        public void setInnerA2(String innerA2) {\n            this.innerA2 = innerA2;\n        }\n\n        public int getInnerB2() {\n            return innerB2;\n        }\n\n        public void setInnerB2(int innerB2) {\n            this.innerB2 = innerB2;\n        }\n\n        @Override\n        public String toString() {\n            return \"InnerObject{\" + \"innerA='\" + innerA2 + '\\'' + \", innerB=\" + innerB2 + '}';\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof InnerObject2)) return false;\n            InnerObject2 that = (InnerObject2) o;\n            return getInnerB2() == that.getInnerB2() && Objects.equals(getInnerA2(), that.getInnerA2());\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(getInnerA2(), getInnerB2());\n        }\n    }\n\n    public static class InnerObject3 {\n        String innerA3;\n\n        public String getInnerA3() {\n            return innerA3;\n        }\n\n        public void setInnerA3(String innerA3) {\n            this.innerA3 = innerA3;\n        }\n\n        @Override\n        public String toString() {\n            return \"InnerObject3{\" + \"innerA3='\" + innerA3 + '\\'' + '}';\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof InnerObject3)) return false;\n            InnerObject3 that = (InnerObject3) o;\n            return Objects.equals(getInnerA3(), that.getInnerA3());\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(getInnerA3());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/service/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.service;\n\nimport org.apache.dubbo.metadata.definition.service.annotation.MockMethodAnnotation;\nimport org.apache.dubbo.metadata.definition.service.annotation.MockMethodAnnotation2;\nimport org.apache.dubbo.metadata.definition.service.annotation.MockTypeAnnotation;\n\nimport java.util.List;\n\n/**\n * for test\n */\n@MockTypeAnnotation(666)\npublic interface DemoService {\n\n    String complexCompute(String input, ComplexObject co);\n\n    ComplexObject findComplexObject(\n            String var1, int var2, long l, String[] var3, List<Integer> var4, ComplexObject.TestEnum testEnum);\n\n    @MockMethodAnnotation(777)\n    @MockMethodAnnotation2(888)\n    void testAnnotation(boolean flag);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/service/annotation/MockMethodAnnotation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.service.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface MockMethodAnnotation {\n    int value();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/service/annotation/MockMethodAnnotation2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.service.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface MockMethodAnnotation2 {\n    int value();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/metadata/definition/service/annotation/MockTypeAnnotation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.service.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface MockTypeAnnotation {\n    int value();\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/executor/IsolationExecutorSupportFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.executor;\n\nimport org.apache.dubbo.common.URL;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass IsolationExecutorSupportFactoryTest {\n    @Test\n    void test() {\n        Assertions.assertInstanceOf(\n                DefaultExecutorSupport.class,\n                IsolationExecutorSupportFactory.getIsolationExecutorSupport(URL.valueOf(\"dubbo://\")));\n        Assertions.assertInstanceOf(\n                DefaultExecutorSupport.class,\n                IsolationExecutorSupportFactory.getIsolationExecutorSupport(URL.valueOf(\"empty://\")));\n        Assertions.assertInstanceOf(\n                DefaultExecutorSupport.class,\n                IsolationExecutorSupportFactory.getIsolationExecutorSupport(URL.valueOf(\"exchange://\")));\n        Assertions.assertInstanceOf(\n                Mock1ExecutorSupport.class,\n                IsolationExecutorSupportFactory.getIsolationExecutorSupport(URL.valueOf(\"mock1://\")));\n        Assertions.assertInstanceOf(\n                Mock2ExecutorSupport.class,\n                IsolationExecutorSupportFactory.getIsolationExecutorSupport(URL.valueOf(\"mock2://\")));\n        Assertions.assertInstanceOf(\n                DefaultExecutorSupport.class,\n                IsolationExecutorSupportFactory.getIsolationExecutorSupport(URL.valueOf(\"mock3://\")));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/executor/Mock1ExecutorSupport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.executor;\n\nimport java.util.concurrent.Executor;\n\npublic class Mock1ExecutorSupport implements ExecutorSupport {\n    @Override\n    public Executor getExecutor(Object data) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/executor/Mock1IsolationExecutorSupportFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.executor;\n\nimport org.apache.dubbo.common.URL;\n\npublic class Mock1IsolationExecutorSupportFactory implements IsolationExecutorSupportFactory {\n    @Override\n    public ExecutorSupport createIsolationExecutorSupport(URL url) {\n        return new Mock1ExecutorSupport();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/executor/Mock2ExecutorSupport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.executor;\n\nimport java.util.concurrent.Executor;\n\npublic class Mock2ExecutorSupport implements ExecutorSupport {\n    @Override\n    public Executor getExecutor(Object data) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/executor/Mock2IsolationExecutorSupportFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.executor;\n\nimport org.apache.dubbo.common.URL;\n\npublic class Mock2IsolationExecutorSupportFactory implements IsolationExecutorSupportFactory {\n    @Override\n    public ExecutorSupport createIsolationExecutorSupport(URL url) {\n        return new Mock2ExecutorSupport();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ApplicationModelTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.config.ConfigurationCache;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.lang.ShutdownHookCallbacks;\nimport org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.support.MockScopeModelDestroyListener;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link ApplicationModel}\n */\nclass ApplicationModelTest {\n\n    @Test\n    void testInitialize() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n\n        Assertions.assertEquals(applicationModel.getParent(), frameworkModel);\n        Assertions.assertEquals(applicationModel.getScope(), ExtensionScope.APPLICATION);\n        Assertions.assertEquals(applicationModel.getFrameworkModel(), frameworkModel);\n        Assertions.assertFalse(applicationModel.isInternal());\n        Assertions.assertTrue(frameworkModel.getApplicationModels().contains(applicationModel));\n        Assertions.assertNotNull(applicationModel.getInternalId());\n\n        Assertions.assertNotNull(applicationModel.getExtensionDirector());\n        Assertions.assertNotNull(applicationModel.getBeanFactory());\n        Assertions.assertTrue(applicationModel.getClassLoaders().contains(ScopeModel.class.getClassLoader()));\n\n        Assertions.assertNotNull(applicationModel.getInternalModule());\n        Assertions.assertNotNull(applicationModel.getApplicationServiceRepository());\n\n        ScopeBeanFactory applicationModelBeanFactory = applicationModel.getBeanFactory();\n        Assertions.assertNotNull(applicationModelBeanFactory.getBean(ShutdownHookCallbacks.class));\n        Assertions.assertNotNull(applicationModelBeanFactory.getBean(FrameworkStatusReportService.class));\n        Assertions.assertNotNull(applicationModelBeanFactory.getBean(ConfigurationCache.class));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testDefaultApplication() {\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        FrameworkModel frameworkModel = applicationModel.getFrameworkModel();\n\n        Assertions.assertFalse(applicationModel.isInternal());\n        Assertions.assertEquals(frameworkModel.defaultApplication(), applicationModel);\n        Assertions.assertTrue(frameworkModel.getApplicationModels().contains(applicationModel));\n\n        String desc = applicationModel.getDesc();\n        Assertions.assertEquals(desc, \"Dubbo Application[\" + applicationModel.getInternalId() + \"](unknown)\");\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testModule() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n\n        ModuleModel defaultModule = applicationModel.getDefaultModule();\n        ModuleModel internalModule = applicationModel.getInternalModule();\n\n        Assertions.assertTrue(applicationModel.getModuleModels().contains(defaultModule));\n        Assertions.assertTrue(applicationModel.getModuleModels().contains(internalModule));\n        Assertions.assertTrue(applicationModel.getPubModuleModels().contains(defaultModule));\n        Assertions.assertFalse(applicationModel.getPubModuleModels().contains(internalModule));\n\n        applicationModel.removeModule(defaultModule);\n        Assertions.assertFalse(applicationModel.getModuleModels().contains(defaultModule));\n        Assertions.assertFalse(applicationModel.getPubModuleModels().contains(defaultModule));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testOfNullable() {\n        ApplicationModel applicationModel = ApplicationModel.ofNullable(null);\n        Assertions.assertEquals(ApplicationModel.defaultModel(), applicationModel);\n        applicationModel.getFrameworkModel().destroy();\n\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel1 = frameworkModel.newApplication();\n        ApplicationModel applicationModel2 = ApplicationModel.ofNullable(applicationModel1);\n        Assertions.assertEquals(applicationModel1, applicationModel2);\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testDestroy() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n\n        applicationModel.getDefaultModule();\n        applicationModel.newModule();\n\n        MockScopeModelDestroyListener destroyListener = new MockScopeModelDestroyListener();\n        applicationModel.addDestroyListener(destroyListener);\n        applicationModel.destroy();\n\n        Assertions.assertFalse(frameworkModel.getApplicationModels().contains(applicationModel));\n        Assertions.assertTrue(applicationModel.getModuleModels().isEmpty());\n        Assertions.assertTrue(destroyListener.isDestroyed());\n        Assertions.assertEquals(destroyListener.getScopeModel(), applicationModel);\n        Assertions.assertNull(applicationModel.getApplicationServiceRepository());\n        Assertions.assertTrue(applicationModel.isDestroyed());\n        // trigger frameworkModel.tryDestroy()\n        Assertions.assertTrue(frameworkModel.isDestroyed());\n\n        try {\n            applicationModel.getDefaultModule();\n            Assertions.fail(\"Cannot create new module after application model destroyed\");\n        } catch (Exception e) {\n            Assertions.assertEquals(\"ApplicationModel is destroyed\", e.getMessage(), StringUtils.toString(e));\n        }\n\n        try {\n            applicationModel.newModule();\n            Assertions.fail(\"Cannot create new module after application model destroyed\");\n        } catch (Exception e) {\n            Assertions.assertEquals(\"ApplicationModel is destroyed\", e.getMessage(), StringUtils.toString(e));\n        }\n    }\n\n    @Test\n    void testCopyOnWriteArrayListIteratorAndRemove() throws InterruptedException {\n        List<Integer> cur = new ArrayList<>();\n        for (int i = 0; i < 10000; i++) {\n            cur.add(i);\n        }\n        List<Integer> myList = new CopyOnWriteArrayList<>(cur);\n        List<Thread> threads = new ArrayList<>();\n        int threadNum = 20;\n        CountDownLatch endLatch = new CountDownLatch(threadNum);\n        for (int i = 0; i < 20; i++) {\n            threads.add(new Thread(() -> {\n                for (Integer number : myList) {\n                    if (number % 2 == 0) {\n                        myList.remove(number);\n                    }\n                }\n                endLatch.countDown();\n            }));\n        }\n        threads.forEach(Thread::start);\n        endLatch.await();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/FrameworkModelTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link FrameworkModel}\n */\nclass FrameworkModelTest {\n    @Test\n    void testInitialize() {\n        FrameworkModel.destroyAll();\n        FrameworkModel frameworkModel = new FrameworkModel();\n\n        Assertions.assertNull(frameworkModel.getParent());\n        Assertions.assertEquals(frameworkModel.getScope(), ExtensionScope.FRAMEWORK);\n\n        Assertions.assertNotNull(frameworkModel.getInternalId());\n        Assertions.assertTrue(FrameworkModel.getAllInstances().contains(frameworkModel));\n        Assertions.assertEquals(FrameworkModel.defaultModel(), frameworkModel);\n\n        Assertions.assertNotNull(frameworkModel.getExtensionDirector());\n        Assertions.assertNotNull(frameworkModel.getBeanFactory());\n        Assertions.assertTrue(frameworkModel.getClassLoaders().contains(ScopeModel.class.getClassLoader()));\n\n        Assertions.assertNotNull(frameworkModel.getServiceRepository());\n        ApplicationModel applicationModel = frameworkModel.getInternalApplicationModel();\n        Assertions.assertNotNull(applicationModel);\n        Assertions.assertTrue(frameworkModel.getAllApplicationModels().contains(applicationModel));\n        Assertions.assertFalse(frameworkModel.getApplicationModels().contains(applicationModel));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testDefaultModel() {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        Assertions.assertTrue(FrameworkModel.getAllInstances().contains(frameworkModel));\n        String desc = frameworkModel.getDesc();\n        Assertions.assertEquals(desc, \"Dubbo Framework[\" + frameworkModel.getInternalId() + \"]\");\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testApplicationModel() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n\n        ApplicationModel applicationModel = frameworkModel.defaultApplication();\n        ApplicationModel internalApplicationModel = frameworkModel.getInternalApplicationModel();\n\n        Assertions.assertEquals(frameworkModel.getDefaultAppModel(), applicationModel);\n        Assertions.assertTrue(frameworkModel.getAllApplicationModels().contains(applicationModel));\n        Assertions.assertTrue(frameworkModel.getAllApplicationModels().contains(internalApplicationModel));\n        Assertions.assertTrue(frameworkModel.getApplicationModels().contains(applicationModel));\n        Assertions.assertFalse(frameworkModel.getApplicationModels().contains(internalApplicationModel));\n\n        frameworkModel.removeApplication(applicationModel);\n        Assertions.assertFalse(frameworkModel.getAllApplicationModels().contains(applicationModel));\n        Assertions.assertFalse(frameworkModel.getApplicationModels().contains(applicationModel));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void destroyAll() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        frameworkModel.defaultApplication();\n        frameworkModel.newApplication();\n\n        FrameworkModel.destroyAll();\n        Assertions.assertTrue(FrameworkModel.getAllInstances().isEmpty());\n        Assertions.assertTrue(frameworkModel.isDestroyed());\n\n        try {\n            frameworkModel.defaultApplication();\n            Assertions.fail(\"Cannot create new application after framework model destroyed\");\n        } catch (Exception e) {\n            Assertions.assertEquals(\"FrameworkModel is destroyed\", e.getMessage(), StringUtils.toString(e));\n        }\n\n        try {\n            frameworkModel.newApplication();\n            Assertions.fail(\"Cannot create new application after framework model destroyed\");\n        } catch (Exception e) {\n            Assertions.assertEquals(\"FrameworkModel is destroyed\", e.getMessage(), StringUtils.toString(e));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/FrameworkServiceRepositoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.support.DemoService;\nimport org.apache.dubbo.rpc.support.DemoServiceImpl;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.BaseServiceMetadata.interfaceFromServiceKey;\nimport static org.apache.dubbo.common.BaseServiceMetadata.versionFromServiceKey;\n\n/**\n * {@link FrameworkServiceRepository}\n */\nclass FrameworkServiceRepositoryTest {\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n        applicationModel = frameworkModel.newApplication();\n        moduleModel = applicationModel.newModule();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void test() {\n        FrameworkServiceRepository frameworkServiceRepository = frameworkModel.getServiceRepository();\n        ModuleServiceRepository moduleServiceRepository = moduleModel.getServiceRepository();\n\n        ServiceMetadata serviceMetadata =\n                new ServiceMetadata(DemoService.class.getName(), \"GROUP\", \"1.0.0\", DemoService.class);\n        ServiceDescriptor serviceDescriptor = moduleServiceRepository.registerService(DemoService.class);\n        String serviceKey = serviceMetadata.getServiceKey();\n        ProviderModel providerModel = new ProviderModel(\n                serviceKey,\n                new DemoServiceImpl(),\n                serviceDescriptor,\n                moduleModel,\n                serviceMetadata,\n                ClassUtils.getClassLoader(DemoService.class));\n        frameworkServiceRepository.registerProvider(providerModel);\n\n        ProviderModel lookupExportedService = frameworkServiceRepository.lookupExportedService(serviceKey);\n        Assertions.assertEquals(lookupExportedService, providerModel);\n\n        List<ProviderModel> allProviderModels = frameworkServiceRepository.allProviderModels();\n        Assertions.assertEquals(allProviderModels.size(), 1);\n        Assertions.assertEquals(allProviderModels.get(0), providerModel);\n\n        String keyWithoutGroup = keyWithoutGroup(serviceKey);\n        ProviderModel exportedServiceWithoutGroup =\n                frameworkServiceRepository.lookupExportedServiceWithoutGroup(keyWithoutGroup);\n        Assertions.assertEquals(exportedServiceWithoutGroup, providerModel);\n\n        List<ProviderModel> providerModels =\n                frameworkServiceRepository.lookupExportedServicesWithoutGroup(keyWithoutGroup);\n        Assertions.assertEquals(providerModels.size(), 1);\n        Assertions.assertEquals(providerModels.get(0), providerModel);\n\n        ConsumerModel consumerModel = new ConsumerModel(\n                serviceMetadata.getServiceKey(),\n                new DemoServiceImpl(),\n                serviceDescriptor,\n                moduleModel,\n                serviceMetadata,\n                null,\n                ClassUtils.getClassLoader(DemoService.class));\n        moduleServiceRepository.registerConsumer(consumerModel);\n        List<ConsumerModel> consumerModels = frameworkServiceRepository.allConsumerModels();\n        Assertions.assertEquals(consumerModels.size(), 1);\n        Assertions.assertEquals(consumerModels.get(0), consumerModel);\n\n        frameworkServiceRepository.unregisterProvider(providerModel);\n        Assertions.assertNull(frameworkServiceRepository.lookupExportedService(serviceKey));\n        Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(keyWithoutGroup));\n    }\n\n    private static String keyWithoutGroup(String serviceKey) {\n        String interfaceName = interfaceFromServiceKey(serviceKey);\n        String version = versionFromServiceKey(serviceKey);\n        if (StringUtils.isEmpty(version)) {\n            return interfaceName;\n        }\n        return interfaceName + \":\" + version;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/HelloReply.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport com.google.protobuf.Message;\n\npublic final class HelloReply extends com.google.protobuf.GeneratedMessageV3 {\n\n    @Override\n    protected FieldAccessorTable internalGetFieldAccessorTable() {\n        return null;\n    }\n\n    @Override\n    protected Message.Builder newBuilderForType(BuilderParent builderParent) {\n        return null;\n    }\n\n    @Override\n    public Message.Builder newBuilderForType() {\n        return null;\n    }\n\n    @Override\n    public Message.Builder toBuilder() {\n        return null;\n    }\n\n    @Override\n    public Message getDefaultInstanceForType() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/HelloRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport com.google.protobuf.Message;\n\npublic final class HelloRequest extends com.google.protobuf.GeneratedMessageV3 {\n\n    @Override\n    protected FieldAccessorTable internalGetFieldAccessorTable() {\n        return null;\n    }\n\n    @Override\n    protected Message.Builder newBuilderForType(BuilderParent builderParent) {\n        return null;\n    }\n\n    @Override\n    public Message.Builder newBuilderForType() {\n        return null;\n    }\n\n    @Override\n    public Message.Builder toBuilder() {\n        return null;\n    }\n\n    @Override\n    public Message getDefaultInstanceForType() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ModuleModelTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.config.ConfigurationCache;\nimport org.apache.dubbo.common.config.ModuleEnvironment;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.rpc.support.MockScopeModelDestroyListener;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link ModuleModel}\n */\nclass ModuleModelTest {\n\n    @Test\n    void testInitialize() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        Assertions.assertEquals(moduleModel.getParent(), applicationModel);\n        Assertions.assertEquals(moduleModel.getScope(), ExtensionScope.MODULE);\n        Assertions.assertEquals(moduleModel.getApplicationModel(), applicationModel);\n        Assertions.assertTrue(applicationModel.getPubModuleModels().contains(moduleModel));\n        Assertions.assertNotNull(moduleModel.getInternalId());\n        Assertions.assertFalse(moduleModel.isLifeCycleManagedExternally());\n\n        Assertions.assertNotNull(moduleModel.getExtensionDirector());\n        Assertions.assertNotNull(moduleModel.getBeanFactory());\n        Assertions.assertTrue(moduleModel.getClassLoaders().contains(ScopeModel.class.getClassLoader()));\n\n        Assertions.assertNotNull(moduleModel.getServiceRepository());\n        Assertions.assertNotNull(moduleModel.getConfigManager());\n\n        ScopeBeanFactory moduleModelBeanFactory = moduleModel.getBeanFactory();\n        Assertions.assertNotNull(moduleModelBeanFactory.getBean(ConfigurationCache.class));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testModelEnvironment() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        ModuleEnvironment modelEnvironment = moduleModel.modelEnvironment();\n        Assertions.assertNotNull(modelEnvironment);\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testDestroy() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        MockScopeModelDestroyListener destroyListener = new MockScopeModelDestroyListener();\n        moduleModel.addDestroyListener(destroyListener);\n\n        moduleModel.destroy();\n        Assertions.assertTrue(destroyListener.isDestroyed());\n        Assertions.assertEquals(destroyListener.getScopeModel(), moduleModel);\n        Assertions.assertFalse(applicationModel.getPubModuleModels().contains(moduleModel));\n        Assertions.assertNull(moduleModel.getServiceRepository());\n        Assertions.assertTrue(moduleModel.isDestroyed());\n\n        // trigger tryDestroy\n        Assertions.assertTrue(applicationModel.isDestroyed());\n        Assertions.assertTrue(frameworkModel.isDestroyed());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ModuleServiceRepositoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.rpc.support.DemoService;\nimport org.apache.dubbo.rpc.support.DemoServiceImpl;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link ModuleServiceRepository}\n */\nclass ModuleServiceRepositoryTest {\n\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n        applicationModel = frameworkModel.newApplication();\n        moduleModel = applicationModel.newModule();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void test() {\n        ModuleServiceRepository moduleServiceRepository = new ModuleServiceRepository(moduleModel);\n        Assertions.assertEquals(moduleServiceRepository.getModuleModel(), moduleModel);\n        ModuleServiceRepository repository = moduleModel.getServiceRepository();\n\n        // 1.test service\n        ServiceMetadata serviceMetadata =\n                new ServiceMetadata(DemoService.class.getName(), null, null, DemoService.class);\n        ServiceDescriptor serviceDescriptor = repository.registerService(DemoService.class);\n\n        ServiceDescriptor lookupServiceResult = repository.lookupService(DemoService.class.getName());\n        Assertions.assertEquals(lookupServiceResult, serviceDescriptor);\n\n        List<ServiceDescriptor> allServices = repository.getAllServices();\n        Assertions.assertEquals(1, allServices.size());\n        Assertions.assertEquals(allServices.get(0), serviceDescriptor);\n\n        ServiceDescriptor serviceDescriptor1 =\n                repository.registerService(DemoService.class.getSimpleName(), DemoService.class);\n        Assertions.assertEquals(serviceDescriptor1, serviceDescriptor);\n\n        // 2.test consumerModule\n        ConsumerModel consumerModel = new ConsumerModel(\n                serviceMetadata.getServiceKey(),\n                new DemoServiceImpl(),\n                serviceDescriptor,\n                moduleModel,\n                serviceMetadata,\n                null,\n                ClassUtils.getClassLoader(DemoService.class));\n        repository.registerConsumer(consumerModel);\n\n        List<ConsumerModel> allReferredServices = repository.getReferredServices();\n        Assertions.assertEquals(1, allReferredServices.size());\n        Assertions.assertEquals(allReferredServices.get(0), consumerModel);\n\n        List<ConsumerModel> referredServices = repository.lookupReferredServices(DemoService.class.getName());\n        Assertions.assertEquals(1, referredServices.size());\n        Assertions.assertEquals(referredServices.get(0), consumerModel);\n\n        ConsumerModel referredService =\n                repository.lookupReferredServices(DemoService.class.getName()).get(0);\n        Assertions.assertEquals(referredService, consumerModel);\n\n        // 3.test providerModel\n        ProviderModel providerModel = new ProviderModel(\n                DemoService.class.getName(),\n                new DemoServiceImpl(),\n                serviceDescriptor,\n                moduleModel,\n                serviceMetadata,\n                ClassUtils.getClassLoader(DemoService.class));\n        repository.registerProvider(providerModel);\n        List<ProviderModel> allExportedServices = repository.getExportedServices();\n        Assertions.assertEquals(1, allExportedServices.size());\n        Assertions.assertEquals(allExportedServices.get(0), providerModel);\n\n        ProviderModel exportedService = repository.lookupExportedService(DemoService.class.getName());\n        Assertions.assertEquals(exportedService, providerModel);\n\n        List<ProviderModel> providerModels =\n                frameworkModel.getServiceRepository().allProviderModels();\n        Assertions.assertEquals(1, providerModels.size());\n        Assertions.assertEquals(providerModels.get(0), providerModel);\n\n        // 4.test destroy\n        repository.destroy();\n        Assertions.assertTrue(repository.getAllServices().isEmpty());\n        Assertions.assertTrue(repository.getReferredServices().isEmpty());\n        Assertions.assertTrue(repository.getExportedServices().isEmpty());\n        Assertions.assertTrue(\n                frameworkModel.getServiceRepository().allProviderModels().isEmpty());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/Person.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.util.Arrays;\n\npublic class Person {\n    byte oneByte = 123;\n    private String name = \"name1\";\n    private int age = 11;\n\n    private String[] value = {\"value1\", \"value2\"};\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public byte getOneByte() {\n        return oneByte;\n    }\n\n    public void setOneByte(byte b) {\n        this.oneByte = b;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public String[] getValue() {\n        return value;\n    }\n\n    public void setValue(String[] value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"Person name(%s) age(%d) byte(%s) [value=%s]\", name, age, oneByte, Arrays.toString(value));\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + age;\n        result = prime * result + ((name == null) ? 0 : name.hashCode());\n        result = prime * result + Arrays.hashCode(value);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        Person other = (Person) obj;\n        if (age != other.age) return false;\n        if (name == null) {\n            if (other.name != null) return false;\n        } else if (!name.equals(other.name)) return false;\n        if (!Arrays.equals(value, other.value)) return false;\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ReflectionMethodDescriptorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.rpc.model.MethodDescriptor.RpcType;\nimport org.apache.dubbo.rpc.support.DemoService;\n\nimport java.lang.reflect.Type;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ReflectionMethodDescriptorTest {\n\n    private final ReflectionMethodDescriptor method;\n\n    {\n        try {\n            method = new ReflectionMethodDescriptor(DemoService.class.getDeclaredMethod(\"sayHello\", String.class));\n        } catch (NoSuchMethodException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    @Test\n    void getMethodName() {\n        Assertions.assertEquals(\"sayHello\", method.getMethodName());\n    }\n\n    @Test\n    void getMethod() {\n        Assertions.assertEquals(\"sayHello\", method.getMethod().getName());\n    }\n\n    @Test\n    void getCompatibleParamSignatures() {\n        Assertions.assertArrayEquals(new String[] {String.class.getName()}, method.getCompatibleParamSignatures());\n    }\n\n    @Test\n    void getParameterClasses() {\n        Assertions.assertArrayEquals(new Class[] {String.class}, method.getParameterClasses());\n    }\n\n    @Test\n    void getParamDesc() {\n        Assertions.assertEquals(ReflectUtils.getDesc(String.class), method.getParamDesc());\n    }\n\n    @Test\n    void getReturnClass() {\n        Assertions.assertEquals(String.class, method.getReturnClass());\n    }\n\n    @Test\n    void getReturnTypes() {\n        Assertions.assertArrayEquals(new Type[] {String.class, String.class}, method.getReturnTypes());\n    }\n\n    @Test\n    void getRpcType() {\n        Assertions.assertEquals(RpcType.UNARY, method.getRpcType());\n    }\n\n    @Test\n    void isGeneric() {\n        Assertions.assertFalse(method.isGeneric());\n    }\n\n    @Test\n    void addAttribute() {\n        String attr = \"attr\";\n        method.addAttribute(attr, attr);\n        Assertions.assertEquals(attr, method.getAttribute(attr));\n    }\n\n    @Test\n    void testEquals() {\n        try {\n            MethodDescriptor method2 =\n                    new ReflectionMethodDescriptor(DemoService.class.getDeclaredMethod(\"sayHello\", String.class));\n            method.addAttribute(\"attr\", \"attr\");\n            method2.addAttribute(\"attr\", \"attr\");\n            Assertions.assertEquals(method, method2);\n        } catch (NoSuchMethodException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    @Test\n    void testHashCode() {\n        try {\n            MethodDescriptor method2 =\n                    new ReflectionMethodDescriptor(DemoService.class.getDeclaredMethod(\"sayHello\", String.class));\n            method.addAttribute(\"attr\", \"attr\");\n            method2.addAttribute(\"attr\", \"attr\");\n            Assertions.assertEquals(method.hashCode(), method2.hashCode());\n        } catch (NoSuchMethodException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ReflectionServiceDescriptorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.metadata.definition.TypeDefinitionBuilder;\nimport org.apache.dubbo.rpc.support.DemoService;\nimport org.apache.dubbo.rpc.support.DemoService1;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.mockito.Mockito.when;\n\nclass ReflectionServiceDescriptorTest {\n\n    private final ReflectionServiceDescriptor service = new ReflectionServiceDescriptor(DemoService.class);\n\n    @Test\n    void addMethod() {\n        ReflectionServiceDescriptor service2 = new ReflectionServiceDescriptor(DemoService.class);\n        MethodDescriptor method = Mockito.mock(MethodDescriptor.class);\n        when(method.getMethodName()).thenReturn(\"sayHello2\");\n        service2.addMethod(method);\n        Assertions.assertEquals(1, service2.getMethods(\"sayHello2\").size());\n    }\n\n    @Test\n    void testStreamRpcTypeException() {\n        try {\n            new ReflectionServiceDescriptor(DemoService1.class);\n        } catch (IllegalStateException e) {\n            Assertions.assertTrue(e.getMessage().contains(\"Stream method could not be overloaded.\"));\n        }\n    }\n\n    @Test\n    void getFullServiceDefinition() {\n        TypeDefinitionBuilder.initBuilders(new FrameworkModel());\n        Assertions.assertNotNull(service.getFullServiceDefinition(\"demoService\"));\n    }\n\n    @Test\n    void getInterfaceName() {\n        Assertions.assertEquals(DemoService.class.getName(), service.getInterfaceName());\n    }\n\n    @Test\n    void getServiceInterfaceClass() {\n        Assertions.assertEquals(DemoService.class, service.getServiceInterfaceClass());\n    }\n\n    @Test\n    void getAllMethods() {\n        Assertions.assertFalse(service.getAllMethods().isEmpty());\n    }\n\n    @Test\n    void getMethod() {\n        String desc = ReflectUtils.getDesc(String.class);\n        Assertions.assertNotNull(service.getMethod(\"sayHello\", desc));\n    }\n\n    @Test\n    void testGetMethod() {\n        Assertions.assertNotNull(service.getMethod(\"sayHello\", new Class[] {String.class}));\n    }\n\n    @Test\n    void getMethods() {\n        Assertions.assertEquals(1, service.getMethods(\"sayHello\").size());\n    }\n\n    @Test\n    void testEquals() {\n        ReflectionServiceDescriptor service2 = new ReflectionServiceDescriptor(DemoService.class);\n        ReflectionServiceDescriptor service3 = new ReflectionServiceDescriptor(DemoService.class);\n        Assertions.assertEquals(service2, service3);\n    }\n\n    @Test\n    void testHashCode() {\n        ReflectionServiceDescriptor service2 = new ReflectionServiceDescriptor(DemoService.class);\n        ReflectionServiceDescriptor service3 = new ReflectionServiceDescriptor(DemoService.class);\n        Assertions.assertEquals(service2.hashCode(), service3.hashCode());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ScopeModelAwareExtensionProcessorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.rpc.support.MockScopeModelAware;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link ScopeModelAwareExtensionProcessor}\n */\nclass ScopeModelAwareExtensionProcessorTest {\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n        applicationModel = frameworkModel.newApplication();\n        moduleModel = applicationModel.newModule();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testInitialize() {\n        ScopeModelAwareExtensionProcessor processor1 = new ScopeModelAwareExtensionProcessor(frameworkModel);\n        Assertions.assertEquals(processor1.getFrameworkModel(), frameworkModel);\n        Assertions.assertEquals(processor1.getScopeModel(), frameworkModel);\n        Assertions.assertNull(processor1.getApplicationModel());\n        Assertions.assertNull(processor1.getModuleModel());\n\n        ScopeModelAwareExtensionProcessor processor2 = new ScopeModelAwareExtensionProcessor(applicationModel);\n        Assertions.assertEquals(processor2.getApplicationModel(), applicationModel);\n        Assertions.assertEquals(processor2.getScopeModel(), applicationModel);\n        Assertions.assertEquals(processor2.getFrameworkModel(), frameworkModel);\n        Assertions.assertNull(processor2.getModuleModel());\n\n        ScopeModelAwareExtensionProcessor processor3 = new ScopeModelAwareExtensionProcessor(moduleModel);\n        Assertions.assertEquals(processor3.getModuleModel(), moduleModel);\n        Assertions.assertEquals(processor3.getScopeModel(), moduleModel);\n        Assertions.assertEquals(processor2.getApplicationModel(), applicationModel);\n        Assertions.assertEquals(processor2.getFrameworkModel(), frameworkModel);\n    }\n\n    @Test\n    void testPostProcessAfterInitialization() throws Exception {\n        ScopeModelAwareExtensionProcessor processor = new ScopeModelAwareExtensionProcessor(moduleModel);\n        MockScopeModelAware mockScopeModelAware = new MockScopeModelAware();\n        Object object = processor.postProcessAfterInitialization(\n                mockScopeModelAware, mockScopeModelAware.getClass().getName());\n        Assertions.assertEquals(object, mockScopeModelAware);\n\n        Assertions.assertEquals(mockScopeModelAware.getScopeModel(), moduleModel);\n        Assertions.assertEquals(mockScopeModelAware.getFrameworkModel(), frameworkModel);\n        Assertions.assertEquals(mockScopeModelAware.getApplicationModel(), applicationModel);\n        Assertions.assertEquals(mockScopeModelAware.getModuleModel(), moduleModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ScopeModelTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ScopeModelTest {\n\n    @Test\n    void testCreateOnDestroy() throws InterruptedException {\n        FrameworkModel.destroyAll();\n\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n\n        List<Throwable> errors = new ArrayList<>();\n        applicationModel.addDestroyListener(scopeModel -> {\n            try {\n                try {\n                    applicationModel.getDefaultModule();\n                    Assertions.fail(\"Cannot create new module after application model destroyed\");\n                } catch (Exception e) {\n                    Assertions.assertEquals(\"ApplicationModel is destroyed\", e.getMessage(), StringUtils.toString(e));\n                }\n\n                try {\n                    applicationModel.newModule();\n                    Assertions.fail(\"Cannot create new module after application model destroyed\");\n                } catch (Exception e) {\n                    Assertions.assertEquals(\"ApplicationModel is destroyed\", e.getMessage(), StringUtils.toString(e));\n                }\n            } catch (Throwable e) {\n                errors.add(e);\n            }\n        });\n\n        CountDownLatch latch = new CountDownLatch(1);\n        frameworkModel.addDestroyListener(scopeModel -> {\n            try {\n                try {\n                    frameworkModel.defaultApplication();\n                    Assertions.fail(\"Cannot create new application after framework model destroyed\");\n                } catch (Exception e) {\n                    Assertions.assertEquals(\"FrameworkModel is destroyed\", e.getMessage(), StringUtils.toString(e));\n                }\n\n                try {\n                    frameworkModel.newApplication();\n                    Assertions.fail(\"Cannot create new application after framework model destroyed\");\n                } catch (Exception e) {\n                    Assertions.assertEquals(\"FrameworkModel is destroyed\", e.getMessage(), StringUtils.toString(e));\n                }\n\n                try {\n                    ApplicationModel.defaultModel();\n                    Assertions.fail(\"Cannot create new application after framework model destroyed\");\n                } catch (Exception e) {\n                    Assertions.assertEquals(\"FrameworkModel is destroyed\", e.getMessage(), StringUtils.toString(e));\n                }\n\n                try {\n                    FrameworkModel.defaultModel().defaultApplication();\n                    Assertions.fail(\"Cannot create new application after framework model destroyed\");\n                } catch (Exception e) {\n                    Assertions.assertEquals(\"FrameworkModel is destroyed\", e.getMessage(), StringUtils.toString(e));\n                }\n            } catch (Throwable ex) {\n                errors.add(ex);\n            } finally {\n                latch.countDown();\n            }\n        });\n\n        // destroy frameworkModel\n        frameworkModel.destroy();\n        latch.await();\n\n        String errorMsg = null;\n        for (Throwable throwable : errors) {\n            errorMsg = StringUtils.toString(throwable);\n            errorMsg += \"\\n\";\n        }\n        Assertions.assertEquals(0, errors.size(), \"Error occurred while destroy FrameworkModel: \" + errorMsg);\n\n        // destroy all FrameworkModel\n        FrameworkModel.destroyAll();\n        List<String> remainFrameworks =\n                FrameworkModel.getAllInstances().stream().map(m -> m.getDesc()).collect(Collectors.toList());\n        Assertions.assertEquals(\n                0,\n                FrameworkModel.getAllInstances().size(),\n                \"FrameworkModel is not completely destroyed: \" + remainFrameworks);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ScopeModelUtilTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.concurrent.locks.Lock;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link ScopeModelUtil}\n */\nclass ScopeModelUtilTest {\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n        applicationModel = frameworkModel.newApplication();\n        moduleModel = applicationModel.newModule();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void test() {\n\n        Assertions.assertEquals(ScopeModelUtil.getFrameworkModel(null), FrameworkModel.defaultModel());\n        Assertions.assertEquals(ScopeModelUtil.getFrameworkModel(frameworkModel), frameworkModel);\n        Assertions.assertEquals(ScopeModelUtil.getFrameworkModel(applicationModel), frameworkModel);\n        Assertions.assertEquals(ScopeModelUtil.getFrameworkModel(moduleModel), frameworkModel);\n        Assertions.assertThrows(\n                IllegalArgumentException.class, () -> ScopeModelUtil.getFrameworkModel(new MockScopeModel(null, null)));\n\n        Assertions.assertEquals(ScopeModelUtil.getApplicationModel(null), ApplicationModel.defaultModel());\n        Assertions.assertEquals(ScopeModelUtil.getApplicationModel(applicationModel), applicationModel);\n        Assertions.assertEquals(ScopeModelUtil.getApplicationModel(moduleModel), applicationModel);\n        Assertions.assertThrows(\n                IllegalArgumentException.class, () -> ScopeModelUtil.getApplicationModel(frameworkModel));\n\n        Assertions.assertEquals(\n                ScopeModelUtil.getModuleModel(null),\n                ApplicationModel.defaultModel().getDefaultModule());\n        Assertions.assertEquals(ScopeModelUtil.getModuleModel(moduleModel), moduleModel);\n        Assertions.assertThrows(IllegalArgumentException.class, () -> ScopeModelUtil.getModuleModel(frameworkModel));\n        Assertions.assertThrows(IllegalArgumentException.class, () -> ScopeModelUtil.getModuleModel(applicationModel));\n\n        Assertions.assertEquals(ScopeModelUtil.getOrDefault(null, SPIDemo1.class), FrameworkModel.defaultModel());\n        Assertions.assertEquals(ScopeModelUtil.getOrDefault(null, SPIDemo2.class), ApplicationModel.defaultModel());\n        Assertions.assertEquals(\n                ScopeModelUtil.getOrDefault(null, SPIDemo3.class),\n                ApplicationModel.defaultModel().getDefaultModule());\n        Assertions.assertThrows(\n                IllegalArgumentException.class, () -> ScopeModelUtil.getOrDefault(null, SPIDemo4.class));\n\n        Assertions.assertEquals(\n                ScopeModelUtil.getExtensionLoader(SPIDemo1.class, null),\n                FrameworkModel.defaultModel().getExtensionLoader(SPIDemo1.class));\n        Assertions.assertEquals(\n                ScopeModelUtil.getExtensionLoader(SPIDemo2.class, null),\n                ApplicationModel.defaultModel().getExtensionLoader(SPIDemo2.class));\n        Assertions.assertEquals(\n                ScopeModelUtil.getExtensionLoader(SPIDemo3.class, null),\n                ApplicationModel.defaultModel().getDefaultModule().getExtensionLoader(SPIDemo3.class));\n        Assertions.assertThrows(\n                IllegalArgumentException.class, () -> ScopeModelUtil.getExtensionLoader(SPIDemo4.class, null));\n    }\n\n    @SPI(scope = ExtensionScope.FRAMEWORK)\n    interface SPIDemo1 {}\n\n    @SPI(scope = ExtensionScope.APPLICATION)\n    interface SPIDemo2 {}\n\n    @SPI(scope = ExtensionScope.MODULE)\n    interface SPIDemo3 {}\n\n    interface SPIDemo4 {}\n\n    class MockScopeModel extends ScopeModel {\n        public MockScopeModel(ScopeModel parent, ExtensionScope scope) {\n            super(parent, scope, false);\n        }\n\n        @Override\n        protected void onDestroy() {}\n\n        @Override\n        public Environment modelEnvironment() {\n            return null;\n        }\n\n        @Override\n        protected Lock acquireDestroyLock() {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/SerializablePerson.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.io.Serializable;\nimport java.util.Arrays;\n\npublic class SerializablePerson implements Serializable {\n    private static final long serialVersionUID = 1L;\n    byte oneByte = 123;\n    private String name = \"name1\";\n    private int age = 11;\n\n    private String[] value = {\"value1\", \"value2\"};\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public byte getOneByte() {\n        return oneByte;\n    }\n\n    public void setOneByte(byte b) {\n        this.oneByte = b;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public String[] getValue() {\n        return value;\n    }\n\n    public void setValue(String[] value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"Person name(%s) age(%d) byte(%s) [value=%s]\", name, age, oneByte, Arrays.toString(value));\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + age;\n        result = prime * result + ((name == null) ? 0 : name.hashCode());\n        result = prime * result + Arrays.hashCode(value);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        SerializablePerson other = (SerializablePerson) obj;\n        if (age != other.age) return false;\n        if (name == null) {\n            if (other.name != null) return false;\n        } else if (!name.equals(other.name)) return false;\n        if (!Arrays.equals(value, other.value)) return false;\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/ServiceRepositoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.rpc.support.DemoService;\nimport org.apache.dubbo.rpc.support.DemoServiceImpl;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link ServiceRepository}\n */\nclass ServiceRepositoryTest {\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n        applicationModel = frameworkModel.newApplication();\n        moduleModel = applicationModel.newModule();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void test() {\n        // verify BuiltinService\n        Set<BuiltinServiceDetector> builtinServices = applicationModel\n                .getExtensionLoader(BuiltinServiceDetector.class)\n                .getSupportedExtensionInstances();\n        ModuleServiceRepository moduleServiceRepository =\n                applicationModel.getInternalModule().getServiceRepository();\n        List<ServiceDescriptor> allServices = moduleServiceRepository.getAllServices();\n        Assertions.assertEquals(allServices.size(), builtinServices.size());\n\n        ModuleServiceRepository repository = moduleModel.getServiceRepository();\n        ServiceMetadata serviceMetadata =\n                new ServiceMetadata(DemoService.class.getName(), null, null, DemoService.class);\n        ServiceDescriptor serviceDescriptor = repository.registerService(DemoService.class);\n\n        // registerConsumer\n        ConsumerModel consumerModel = new ConsumerModel(\n                serviceMetadata.getServiceKey(),\n                new DemoServiceImpl(),\n                serviceDescriptor,\n                moduleModel,\n                serviceMetadata,\n                null,\n                ClassUtils.getClassLoader(DemoService.class));\n        repository.registerConsumer(consumerModel);\n\n        // registerProvider\n        ProviderModel providerModel = new ProviderModel(\n                DemoService.class.getName(),\n                new DemoServiceImpl(),\n                serviceDescriptor,\n                moduleModel,\n                serviceMetadata,\n                ClassUtils.getClassLoader(DemoService.class));\n        repository.registerProvider(providerModel);\n\n        // verify allProviderModels, allConsumerModels\n        ServiceRepository serviceRepository = applicationModel.getApplicationServiceRepository();\n        Collection<ProviderModel> providerModels = serviceRepository.allProviderModels();\n        Assertions.assertEquals(providerModels.size(), 1);\n        Assertions.assertTrue(providerModels.contains(providerModel));\n\n        Collection<ConsumerModel> consumerModels = serviceRepository.allConsumerModels();\n        Assertions.assertEquals(consumerModels.size(), 1);\n        Assertions.assertTrue(consumerModels.contains(consumerModel));\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/User.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model;\n\nimport java.util.Objects;\n\n/**\n * this class has no nullary constructor and some field is primitive\n */\npublic class User {\n    private int age;\n\n    private String name;\n\n    public User(int age, String name) {\n        this.age = age;\n        this.name = name;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"User name(%s) age(%d) \", name, age);\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        User user = (User) o;\n        if (name == null) {\n            if (user.name != null) {\n                return false;\n            }\n        } else if (!name.equals(user.name)) {\n            return false;\n        }\n        return Objects.equals(age, user.age);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(age, name);\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/media/Image.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model.media;\n\npublic class Image implements java.io.Serializable {\n    private static final long serialVersionUID = 1L;\n    public String uri;\n    public String title; // Can be null\n    public int width;\n    public int height;\n    public Size size;\n\n    public Image() {}\n\n    public Image(String uri, String title, int width, int height, Size size) {\n        this.height = height;\n        this.title = title;\n        this.uri = uri;\n        this.width = width;\n        this.size = size;\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        Image image = (Image) o;\n\n        if (height != image.height) return false;\n        if (width != image.width) return false;\n        if (size != image.size) return false;\n        if (title != null ? !title.equals(image.title) : image.title != null) return false;\n        if (uri != null ? !uri.equals(image.uri) : image.uri != null) return false;\n\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = uri != null ? uri.hashCode() : 0;\n        result = 31 * result + (title != null ? title.hashCode() : 0);\n        result = 31 * result + width;\n        result = 31 * result + height;\n        result = 31 * result + (size != null ? size.hashCode() : 0);\n        return result;\n    }\n\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"[Image \");\n        sb.append(\"uri=\").append(uri);\n        sb.append(\", title=\").append(title);\n        sb.append(\", width=\").append(width);\n        sb.append(\", height=\").append(height);\n        sb.append(\", size=\").append(size);\n        sb.append(']');\n        return sb.toString();\n    }\n\n    public String getUri() {\n        return uri;\n    }\n\n    public void setUri(String uri) {\n        this.uri = uri;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public int getWidth() {\n        return width;\n    }\n\n    public void setWidth(int width) {\n        this.width = width;\n    }\n\n    public int getHeight() {\n        return height;\n    }\n\n    public void setHeight(int height) {\n        this.height = height;\n    }\n\n    public Size getSize() {\n        return size;\n    }\n\n    public void setSize(Size size) {\n        this.size = size;\n    }\n\n    public enum Size {\n        SMALL,\n        LARGE\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/media/Media.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model.media;\n\nimport java.util.List;\n\n@SuppressWarnings(\"serial\")\npublic class Media implements java.io.Serializable {\n    public String uri;\n    public String title; // Can be unset.\n    public int width;\n    public int height;\n    public String format;\n    public long duration;\n    public long size;\n    public int bitrate; // Can be unset.\n    public boolean hasBitrate;\n    public List<String> persons;\n    public Player player;\n    public String copyright; // Can be unset.\n\n    public Media() {}\n\n    public Media(\n            String uri,\n            String title,\n            int width,\n            int height,\n            String format,\n            long duration,\n            long size,\n            int bitrate,\n            boolean hasBitrate,\n            List<String> persons,\n            Player player,\n            String copyright) {\n        this.uri = uri;\n        this.title = title;\n        this.width = width;\n        this.height = height;\n        this.format = format;\n        this.duration = duration;\n        this.size = size;\n        this.bitrate = bitrate;\n        this.hasBitrate = hasBitrate;\n        this.persons = persons;\n        this.player = player;\n        this.copyright = copyright;\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        Media media = (Media) o;\n\n        if (bitrate != media.bitrate) return false;\n        if (duration != media.duration) return false;\n        if (hasBitrate != media.hasBitrate) return false;\n        if (height != media.height) return false;\n        if (size != media.size) return false;\n        if (width != media.width) return false;\n        if (copyright != null ? !copyright.equals(media.copyright) : media.copyright != null) return false;\n        if (format != null ? !format.equals(media.format) : media.format != null) return false;\n        if (persons != null ? !persons.equals(media.persons) : media.persons != null) return false;\n        if (player != media.player) return false;\n        if (title != null ? !title.equals(media.title) : media.title != null) return false;\n        if (uri != null ? !uri.equals(media.uri) : media.uri != null) return false;\n\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = uri != null ? uri.hashCode() : 0;\n        result = 31 * result + (title != null ? title.hashCode() : 0);\n        result = 31 * result + width;\n        result = 31 * result + height;\n        result = 31 * result + (format != null ? format.hashCode() : 0);\n        result = 31 * result + (int) (duration ^ (duration >>> 32));\n        result = 31 * result + (int) (size ^ (size >>> 32));\n        result = 31 * result + bitrate;\n        result = 31 * result + (hasBitrate ? 1 : 0);\n        result = 31 * result + (persons != null ? persons.hashCode() : 0);\n        result = 31 * result + (player != null ? player.hashCode() : 0);\n        result = 31 * result + (copyright != null ? copyright.hashCode() : 0);\n        return result;\n    }\n\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"[Media \");\n        sb.append(\"uri=\").append(uri);\n        sb.append(\", title=\").append(title);\n        sb.append(\", width=\").append(width);\n        sb.append(\", height=\").append(height);\n        sb.append(\", format=\").append(format);\n        sb.append(\", duration=\").append(duration);\n        sb.append(\", size=\").append(size);\n        sb.append(\", hasBitrate=\").append(hasBitrate);\n        sb.append(\", bitrate=\").append(String.valueOf(bitrate));\n        sb.append(\", persons=\").append(persons);\n        sb.append(\", player=\").append(player);\n        sb.append(\", copyright=\").append(copyright);\n        sb.append(']');\n        return sb.toString();\n    }\n\n    public String getUri() {\n        return uri;\n    }\n\n    public void setUri(String uri) {\n        this.uri = uri;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public int getWidth() {\n        return width;\n    }\n\n    public void setWidth(int width) {\n        this.width = width;\n    }\n\n    public int getHeight() {\n        return height;\n    }\n\n    public void setHeight(int height) {\n        this.height = height;\n    }\n\n    public String getFormat() {\n        return format;\n    }\n\n    public void setFormat(String format) {\n        this.format = format;\n    }\n\n    public long getDuration() {\n        return duration;\n    }\n\n    public void setDuration(long duration) {\n        this.duration = duration;\n    }\n\n    public long getSize() {\n        return size;\n    }\n\n    public void setSize(long size) {\n        this.size = size;\n    }\n\n    public int getBitrate() {\n        return bitrate;\n    }\n\n    public void setBitrate(int bitrate) {\n        this.bitrate = bitrate;\n        this.hasBitrate = true;\n    }\n\n    public List<String> getPersons() {\n        return persons;\n    }\n\n    public void setPersons(List<String> persons) {\n        this.persons = persons;\n    }\n\n    public Player getPlayer() {\n        return player;\n    }\n\n    public void setPlayer(Player player) {\n        this.player = player;\n    }\n\n    public String getCopyright() {\n        return copyright;\n    }\n\n    public void setCopyright(String copyright) {\n        this.copyright = copyright;\n    }\n\n    public enum Player {\n        JAVA,\n        FLASH\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/person/BigPerson.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model.person;\n\nimport java.io.Serializable;\n\npublic class BigPerson implements Serializable {\n    private static final long serialVersionUID = 1L;\n\n    String personId;\n\n    String loginName;\n\n    PersonStatus status;\n\n    String email;\n\n    String personName;\n\n    PersonInfo infoProfile;\n\n    public BigPerson() {}\n\n    public BigPerson(String id) {\n        this.personId = id;\n    }\n\n    public String getPersonId() {\n        return personId;\n    }\n\n    public void setPersonId(String personId) {\n        this.personId = personId;\n    }\n\n    public PersonInfo getInfoProfile() {\n        return infoProfile;\n    }\n\n    public void setInfoProfile(PersonInfo infoProfile) {\n        this.infoProfile = infoProfile;\n    }\n\n    public String getEmail() {\n        return this.email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public String getLoginName() {\n        return this.loginName;\n    }\n\n    public void setLoginName(String loginName) {\n        this.loginName = loginName;\n    }\n\n    public PersonStatus getStatus() {\n        return this.status;\n    }\n\n    public void setStatus(PersonStatus status) {\n        this.status = status;\n    }\n\n    public String getPersonName() {\n        return personName;\n    }\n\n    public void setPersonName(String personName) {\n        this.personName = personName;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((email == null) ? 0 : email.hashCode());\n        result = prime * result + ((infoProfile == null) ? 0 : infoProfile.hashCode());\n        result = prime * result + ((loginName == null) ? 0 : loginName.hashCode());\n        result = prime * result + ((personName == null) ? 0 : personName.hashCode());\n        result = prime * result + ((personId == null) ? 0 : personId.hashCode());\n        result = prime * result + ((status == null) ? 0 : status.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        BigPerson other = (BigPerson) obj;\n        if (email == null) {\n            if (other.email != null) return false;\n        } else if (!email.equals(other.email)) return false;\n        if (infoProfile == null) {\n            if (other.infoProfile != null) return false;\n        } else if (!infoProfile.equals(other.infoProfile)) return false;\n        if (loginName == null) {\n            if (other.loginName != null) return false;\n        } else if (!loginName.equals(other.loginName)) return false;\n        if (personName == null) {\n            if (other.personName != null) return false;\n        } else if (!personName.equals(other.personName)) return false;\n        if (personId == null) {\n            if (other.personId != null) return false;\n        } else if (!personId.equals(other.personId)) return false;\n        if (status != other.status) return false;\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        return \"BigPerson [personId=\" + personId + \", loginName=\" + loginName + \", status=\"\n                + status + \", email=\" + email + \", personName=\" + personName + \", infoProfile=\"\n                + infoProfile + \"]\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/person/FullAddress.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model.person;\n\nimport java.io.Serializable;\n\npublic class FullAddress implements Serializable {\n\n    private static final long serialVersionUID = 5163979984269419831L;\n\n    private String countryId;\n\n    private String countryName;\n\n    private String provinceName;\n\n    private String cityId;\n\n    private String cityName;\n\n    private String streetAddress;\n\n    private String zipCode;\n\n    public FullAddress() {}\n\n    public FullAddress(String countryId, String provinceName, String cityId, String streetAddress, String zipCode) {\n        this.countryId = countryId;\n        this.countryName = countryId;\n        this.provinceName = provinceName;\n        this.cityId = cityId;\n        this.cityName = cityId;\n        this.streetAddress = streetAddress;\n        this.zipCode = zipCode;\n    }\n\n    public FullAddress(\n            String countryId,\n            String countryName,\n            String provinceName,\n            String cityId,\n            String cityName,\n            String streetAddress,\n            String zipCode) {\n        this.countryId = countryId;\n        this.countryName = countryName;\n        this.provinceName = provinceName;\n        this.cityId = cityId;\n        this.cityName = cityName;\n        this.streetAddress = streetAddress;\n        this.zipCode = zipCode;\n    }\n\n    public String getCountryId() {\n        return countryId;\n    }\n\n    public void setCountryId(String countryId) {\n        this.countryId = countryId;\n    }\n\n    public String getCountryName() {\n        return countryName;\n    }\n\n    public void setCountryName(String countryName) {\n        this.countryName = countryName;\n    }\n\n    public String getProvinceName() {\n        return provinceName;\n    }\n\n    public void setProvinceName(String provinceName) {\n        this.provinceName = provinceName;\n    }\n\n    public String getCityId() {\n        return cityId;\n    }\n\n    public void setCityId(String cityId) {\n        this.cityId = cityId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getStreetAddress() {\n        return streetAddress;\n    }\n\n    public void setStreetAddress(String streetAddress) {\n        this.streetAddress = streetAddress;\n    }\n\n    public String getZipCode() {\n        return zipCode;\n    }\n\n    public void setZipCode(String zipCode) {\n        this.zipCode = zipCode;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((cityId == null) ? 0 : cityId.hashCode());\n        result = prime * result + ((cityName == null) ? 0 : cityName.hashCode());\n        result = prime * result + ((countryId == null) ? 0 : countryId.hashCode());\n        result = prime * result + ((countryName == null) ? 0 : countryName.hashCode());\n        result = prime * result + ((provinceName == null) ? 0 : provinceName.hashCode());\n        result = prime * result + ((streetAddress == null) ? 0 : streetAddress.hashCode());\n        result = prime * result + ((zipCode == null) ? 0 : zipCode.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        FullAddress other = (FullAddress) obj;\n        if (cityId == null) {\n            if (other.cityId != null) return false;\n        } else if (!cityId.equals(other.cityId)) return false;\n        if (cityName == null) {\n            if (other.cityName != null) return false;\n        } else if (!cityName.equals(other.cityName)) return false;\n        if (countryId == null) {\n            if (other.countryId != null) return false;\n        } else if (!countryId.equals(other.countryId)) return false;\n        if (countryName == null) {\n            if (other.countryName != null) return false;\n        } else if (!countryName.equals(other.countryName)) return false;\n        if (provinceName == null) {\n            if (other.provinceName != null) return false;\n        } else if (!provinceName.equals(other.provinceName)) return false;\n        if (streetAddress == null) {\n            if (other.streetAddress != null) return false;\n        } else if (!streetAddress.equals(other.streetAddress)) return false;\n        if (zipCode == null) {\n            if (other.zipCode != null) return false;\n        } else if (!zipCode.equals(other.zipCode)) return false;\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        if (countryName != null && countryName.length() > 0) {\n            sb.append(countryName);\n        }\n        if (provinceName != null && provinceName.length() > 0) {\n            sb.append(' ');\n            sb.append(provinceName);\n        }\n        if (cityName != null && cityName.length() > 0) {\n            sb.append(' ');\n            sb.append(cityName);\n        }\n        if (streetAddress != null && streetAddress.length() > 0) {\n            sb.append(' ');\n            sb.append(streetAddress);\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/person/PersonInfo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model.person;\n\nimport java.io.Serializable;\nimport java.util.List;\n\npublic class PersonInfo implements Serializable {\n    private static final long serialVersionUID = 7443011149612231882L;\n\n    List<Phone> phones;\n\n    Phone fax;\n\n    FullAddress fullAddress;\n\n    String mobileNo;\n\n    String name;\n\n    boolean male;\n\n    boolean female;\n\n    String department;\n\n    String jobTitle;\n\n    String homepageUrl;\n\n    public List<Phone> getPhones() {\n        return phones;\n    }\n\n    public void setPhones(List<Phone> phones) {\n        this.phones = phones;\n    }\n\n    public boolean isMale() {\n        return male;\n    }\n\n    public void setMale(boolean male) {\n        this.male = male;\n    }\n\n    public boolean isFemale() {\n        return female;\n    }\n\n    public void setFemale(boolean female) {\n        this.female = female;\n    }\n\n    public String getDepartment() {\n        return department;\n    }\n\n    public void setDepartment(String department) {\n        this.department = department;\n    }\n\n    public Phone getFax() {\n        return fax;\n    }\n\n    public void setFax(Phone fax) {\n        this.fax = fax;\n    }\n\n    public FullAddress getFullAddress() {\n        return fullAddress;\n    }\n\n    public void setFullAddress(FullAddress fullAddress) {\n        this.fullAddress = fullAddress;\n    }\n\n    public String getHomepageUrl() {\n        return homepageUrl;\n    }\n\n    public void setHomepageUrl(String homepageUrl) {\n        this.homepageUrl = homepageUrl;\n    }\n\n    public String getJobTitle() {\n        return jobTitle;\n    }\n\n    public void setJobTitle(String jobTitle) {\n        this.jobTitle = jobTitle;\n    }\n\n    public String getMobileNo() {\n        return mobileNo;\n    }\n\n    public void setMobileNo(String mobileNo) {\n        this.mobileNo = mobileNo;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((department == null) ? 0 : department.hashCode());\n        result = prime * result + ((fax == null) ? 0 : fax.hashCode());\n        result = prime * result + (female ? 1231 : 1237);\n        result = prime * result + ((fullAddress == null) ? 0 : fullAddress.hashCode());\n        result = prime * result + ((homepageUrl == null) ? 0 : homepageUrl.hashCode());\n        result = prime * result + ((jobTitle == null) ? 0 : jobTitle.hashCode());\n        result = prime * result + (male ? 1231 : 1237);\n        result = prime * result + ((mobileNo == null) ? 0 : mobileNo.hashCode());\n        result = prime * result + ((name == null) ? 0 : name.hashCode());\n        result = prime * result + ((phones == null) ? 0 : phones.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        PersonInfo other = (PersonInfo) obj;\n        if (department == null) {\n            if (other.department != null) return false;\n        } else if (!department.equals(other.department)) return false;\n        if (fax == null) {\n            if (other.fax != null) return false;\n        } else if (!fax.equals(other.fax)) return false;\n        if (female != other.female) return false;\n        if (fullAddress == null) {\n            if (other.fullAddress != null) return false;\n        } else if (!fullAddress.equals(other.fullAddress)) return false;\n        if (homepageUrl == null) {\n            if (other.homepageUrl != null) return false;\n        } else if (!homepageUrl.equals(other.homepageUrl)) return false;\n        if (jobTitle == null) {\n            if (other.jobTitle != null) return false;\n        } else if (!jobTitle.equals(other.jobTitle)) return false;\n        if (male != other.male) return false;\n        if (mobileNo == null) {\n            if (other.mobileNo != null) return false;\n        } else if (!mobileNo.equals(other.mobileNo)) return false;\n        if (name == null) {\n            if (other.name != null) return false;\n        } else if (!name.equals(other.name)) return false;\n        if (phones == null) {\n            if (other.phones != null) return false;\n        } else if (!phones.equals(other.phones)) return false;\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        return \"PersonInfo [phones=\" + phones + \", fax=\" + fax + \", fullAddress=\" + fullAddress\n                + \", mobileNo=\" + mobileNo + \", name=\" + name + \", male=\" + male + \", female=\"\n                + female + \", department=\" + department + \", jobTitle=\" + jobTitle\n                + \", homepageUrl=\" + homepageUrl + \"]\";\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/person/PersonStatus.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model.person;\n\npublic enum PersonStatus {\n    ENABLED,\n    DISABLED\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/model/person/Phone.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.model.person;\n\nimport java.io.Serializable;\n\npublic class Phone implements Serializable {\n\n    private static final long serialVersionUID = 4399060521859707703L;\n\n    private String country;\n\n    private String area;\n\n    private String number;\n\n    private String extensionNumber;\n\n    public Phone() {}\n\n    public Phone(String country, String area, String number, String extensionNumber) {\n        this.country = country;\n        this.area = area;\n        this.number = number;\n        this.extensionNumber = extensionNumber;\n    }\n\n    public String getCountry() {\n        return country;\n    }\n\n    public void setCountry(String country) {\n        this.country = country;\n    }\n\n    public String getArea() {\n        return area;\n    }\n\n    public void setArea(String area) {\n        this.area = area;\n    }\n\n    public String getNumber() {\n        return number;\n    }\n\n    public void setNumber(String number) {\n        this.number = number;\n    }\n\n    public String getExtensionNumber() {\n        return extensionNumber;\n    }\n\n    public void setExtensionNumber(String extensionNumber) {\n        this.extensionNumber = extensionNumber;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((area == null) ? 0 : area.hashCode());\n        result = prime * result + ((country == null) ? 0 : country.hashCode());\n        result = prime * result + ((extensionNumber == null) ? 0 : extensionNumber.hashCode());\n        result = prime * result + ((number == null) ? 0 : number.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) return true;\n        if (obj == null) return false;\n        if (getClass() != obj.getClass()) return false;\n        Phone other = (Phone) obj;\n        if (area == null) {\n            if (other.area != null) return false;\n        } else if (!area.equals(other.area)) return false;\n        if (country == null) {\n            if (other.country != null) return false;\n        } else if (!country.equals(other.country)) return false;\n        if (extensionNumber == null) {\n            if (other.extensionNumber != null) return false;\n        } else if (!extensionNumber.equals(other.extensionNumber)) return false;\n        if (number == null) {\n            if (other.number != null) return false;\n        } else if (!number.equals(other.number)) return false;\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        if (country != null && country.length() > 0) {\n            sb.append(country);\n            sb.append('-');\n        }\n        if (area != null && area.length() > 0) {\n            sb.append(area);\n            sb.append('-');\n        }\n        if (number != null && number.length() > 0) {\n            sb.append(number);\n        }\n        if (extensionNumber != null && extensionNumber.length() > 0) {\n            sb.append('-');\n            sb.append(extensionNumber);\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/service/GenericExceptionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.service;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass GenericExceptionTest {\n\n    @Test\n    void jsonSupport() throws IOException {\n        {\n            GenericException src = new GenericException();\n            String s = JsonUtils.toJson(src);\n            GenericException dst = JsonUtils.toJavaObject(s, GenericException.class);\n            Assertions.assertEquals(src.getExceptionClass(), dst.getExceptionClass());\n            Assertions.assertEquals(src.getExceptionMessage(), dst.getExceptionMessage());\n            Assertions.assertEquals(src.getMessage(), dst.getMessage());\n            Assertions.assertEquals(src.getExceptionMessage(), dst.getExceptionMessage());\n        }\n        {\n            GenericException src = new GenericException(this.getClass().getSimpleName(), \"test\");\n            String s = JsonUtils.toJson(src);\n            GenericException dst = JsonUtils.toJavaObject(s, GenericException.class);\n            Assertions.assertEquals(src.getExceptionClass(), dst.getExceptionClass());\n            Assertions.assertEquals(src.getExceptionMessage(), dst.getExceptionMessage());\n            Assertions.assertEquals(src.getMessage(), dst.getMessage());\n            Assertions.assertEquals(src.getExceptionMessage(), dst.getExceptionMessage());\n        }\n        {\n            Throwable throwable = new Throwable(\"throwable\");\n            GenericException src = new GenericException(throwable);\n            String s = JsonUtils.toJson(src);\n            GenericException dst = JsonUtils.toJavaObject(s, GenericException.class);\n            Assertions.assertEquals(src.getExceptionClass(), dst.getExceptionClass());\n            Assertions.assertEquals(src.getExceptionMessage(), dst.getExceptionMessage());\n            Assertions.assertEquals(src.getMessage(), dst.getMessage());\n            Assertions.assertEquals(src.getExceptionMessage(), dst.getExceptionMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/service/ServiceDescriptorInternalCacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.service;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ServiceDescriptorInternalCacheTest {\n\n    @Test\n    void genericService() {\n        Assertions.assertNotNull(ServiceDescriptorInternalCache.genericService());\n        Assertions.assertEquals(\n                GenericService.class,\n                ServiceDescriptorInternalCache.genericService().getServiceInterfaceClass());\n    }\n\n    @Test\n    void echoService() {\n        Assertions.assertNotNull(ServiceDescriptorInternalCache.echoService());\n        Assertions.assertEquals(\n                EchoService.class, ServiceDescriptorInternalCache.echoService().getServiceInterfaceClass());\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/support/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\npublic interface DemoService {\n    String sayHello(String name);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/support/DemoService1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\n\npublic interface DemoService1 {\n    StreamObserver<String> sayHello(StreamObserver<String> request);\n\n    void sayHello(String msg, StreamObserver<String> request);\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/support/DemoService1Impl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\n\npublic class DemoService1Impl implements DemoService1 {\n    @Override\n    public StreamObserver<String> sayHello(StreamObserver<String> request) {\n        request.onNext(\"BI_STREAM\");\n        return request;\n    }\n\n    @Override\n    public void sayHello(String msg, StreamObserver<String> request) {\n        request.onNext(msg);\n        request.onNext(\"SERVER_STREAM\");\n        request.onCompleted();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/support/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\npublic class DemoServiceImpl implements DemoService {\n    @Override\n    public String sayHello(String name) {\n        return \"hello \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/support/MockScopeModelAware.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAccessor;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\npublic class MockScopeModelAware implements ScopeModelAware, ScopeModelAccessor {\n\n    private ScopeModel scopeModel;\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n\n    @Override\n    public ScopeModel getScopeModel() {\n        return scopeModel;\n    }\n\n    @Override\n    public FrameworkModel getFrameworkModel() {\n        return frameworkModel;\n    }\n\n    @Override\n    public ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    @Override\n    public ModuleModel getModuleModel() {\n        return moduleModel;\n    }\n\n    @Override\n    public void setScopeModel(ScopeModel scopeModel) {\n        this.scopeModel = scopeModel;\n    }\n\n    @Override\n    public void setFrameworkModel(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    @Override\n    public void setModuleModel(ModuleModel moduleModel) {\n        this.moduleModel = moduleModel;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/support/MockScopeModelDestroyListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelDestroyListener;\n\npublic class MockScopeModelDestroyListener implements ScopeModelDestroyListener {\n    private boolean destroyed = false;\n    private ScopeModel scopeModel;\n\n    @Override\n    public void onDestroy(ScopeModel scopeModel) {\n        this.destroyed = true;\n        this.scopeModel = scopeModel;\n    }\n\n    public boolean isDestroyed() {\n        return destroyed;\n    }\n\n    public ScopeModel getScopeModel() {\n        return scopeModel;\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/java/org/apache/dubbo/rpc/support/ProtocolUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ProtocolUtilsTest {\n\n    @Test\n    void testGetServiceKey() {\n        final String serviceName = \"com.abc.demoService\";\n        final int port = 1001;\n\n        assertServiceKey(port, serviceName, \"1.0.0\", \"group\");\n        assertServiceKey(port, serviceName, \"1.0.0\", \"\");\n        assertServiceKey(port, serviceName, \"1.0.0\", null);\n\n        assertServiceKey(port, serviceName, \"0.0\", \"group\");\n        assertServiceKey(port, serviceName, \"0_0_0\", \"group\");\n        assertServiceKey(port, serviceName, \"0.0.0\", \"group\");\n        assertServiceKey(port, serviceName, \"\", \"group\");\n        assertServiceKey(port, serviceName, null, \"group\");\n\n        assertServiceKey(port, serviceName, \"\", \"\");\n        assertServiceKey(port, serviceName, \"\", null);\n        assertServiceKey(port, serviceName, null, \"\");\n        assertServiceKey(port, serviceName, null, null);\n\n        assertServiceKey(port, serviceName, \"\", \" \");\n        assertServiceKey(port, serviceName, \" \", \"\");\n        assertServiceKey(port, serviceName, \" \", \" \");\n    }\n\n    private void assertServiceKey(int port, String serviceName, String serviceVersion, String serviceGroup) {\n        Assertions.assertEquals(\n                serviceKeyOldImpl(port, serviceName, serviceVersion, serviceGroup),\n                ProtocolUtils.serviceKey(port, serviceName, serviceVersion, serviceGroup));\n    }\n\n    /**\n     * 来自 ProtocolUtils.serviceKey(int, String, String, String) 老版本的实现，用于对比测试！\n     */\n    private static String serviceKeyOldImpl(int port, String serviceName, String serviceVersion, String serviceGroup) {\n        StringBuilder buf = new StringBuilder();\n        if (serviceGroup != null && serviceGroup.length() > 0) {\n            buf.append(serviceGroup);\n            buf.append('/');\n        }\n        buf.append(serviceName);\n        if (serviceVersion != null && serviceVersion.length() > 0 && !\"0.0.0\".equals(serviceVersion)) {\n            buf.append(':');\n            buf.append(serviceVersion);\n        }\n        buf.append(':');\n        buf.append(port);\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/external/org.apache.dubbo.common.convert.Converter",
    "content": "# org.apache.dubbo.common.convert.Converter\nstring-to-boolean=org.apache.dubbo.common.extension.convert.String2BooleanConverter"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/external/org.apache.dubbo.common.extension.duplicated.DuplicatedOverriddenExt",
    "content": "duplicated=org.apache.dubbo.common.extension.duplicated.impl.DuplicatedOverriddenExt2"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/external/org.apache.dubbo.common.extension.duplicated.DuplicatedWithoutOverriddenExt",
    "content": "duplicated=org.apache.dubbo.common.extension.duplicated.impl.DuplicatedWithoutOverriddenExt2"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.OrderedPropertiesProvider",
    "content": "mock1=org.apache.dubbo.common.config.MockOrderedPropertiesProvider1\nmock2=org.apache.dubbo.common.config.MockOrderedPropertiesProvider2\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.SPI2",
    "content": "2=org.apache.dubbo.common.extension.SPI2Impl\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.activate.ActivateExt1",
    "content": "group=org.apache.dubbo.common.extension.activate.impl.GroupActivateExtImpl\nvalue=org.apache.dubbo.common.extension.activate.impl.ValueActivateExtImpl\norder1=org.apache.dubbo.common.extension.activate.impl.OrderActivateExtImpl1\norder2=org.apache.dubbo.common.extension.activate.impl.OrderActivateExtImpl2\nonClassExt=org.apache.dubbo.common.extension.activate.impl.ActivateOnClassExt1Impl\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.activate.ActivateWrapperExt1",
    "content": "wrapper1=org.apache.dubbo.common.extension.activate.impl.ActivateWrapperExt1Wrapper\nextImp1=org.apache.dubbo.common.extension.activate.impl.ActivateWrapperExt1Impl1\nextImp2=org.apache.dubbo.common.extension.activate.impl.ActivateWrapperExt1Impl2"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt",
    "content": "adaptive=org.apache.dubbo.common.extension.adaptive.impl.HasAdaptiveExt_ManualAdaptive\nimpl1=org.apache.dubbo.common.extension.adaptive.impl.HasAdaptiveExtImpl1"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.compatible.CompatibleExt",
    "content": "org.apache.dubbo.common.extension.compatible.impl.CompatibleExtImpl1\nimpl2=org.apache.dubbo.common.extension.compatible.impl.CompatibleExtImpl2"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.FooAppProvider",
    "content": "testAppProvider=org.apache.dubbo.common.extension.director.impl.TestAppProvider\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.FooAppService",
    "content": "testAppSrv=org.apache.dubbo.common.extension.director.impl.TestAppService\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.FooFrameworkProvider",
    "content": "testFrameworkProvider=org.apache.dubbo.common.extension.director.impl.TestFrameworkProvider\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.FooFrameworkService",
    "content": "testFwSrv=org.apache.dubbo.common.extension.director.impl.TestFrameworkService\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.FooModuleProvider",
    "content": "testModuleProvider=org.apache.dubbo.common.extension.director.impl.TestModuleProvider\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.FooModuleService",
    "content": "testMdSrv=org.apache.dubbo.common.extension.director.impl.TestModuleService\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.duplicated.DuplicatedOverriddenExt",
    "content": "duplicated=org.apache.dubbo.common.extension.duplicated.impl.DuplicatedOverriddenExt1"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.duplicated.DuplicatedWithoutOverriddenExt",
    "content": "duplicated=org.apache.dubbo.common.extension.duplicated.impl.DuplicatedWithoutOverriddenExt1"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext1.SimpleExt",
    "content": "# Comment 1\nimpl1=org.apache.dubbo.common.extension.ext1.impl.SimpleExtImpl1#Hello World\nimpl2=org.apache.dubbo.common.extension.ext1.impl.SimpleExtImpl2  # Comment 2\n   impl3=org.apache.dubbo.common.extension.ext1.impl.SimpleExtImpl3 # with head space"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext10_multi_names.Ext10MultiNames",
    "content": "impl,implMultiName=org.apache.dubbo.common.extension.ext10_multi_names.impl.Ext10MultiNamesImpl"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext11_no_adaptive.NoAdaptiveExt",
    "content": "noAdaptive=org.apache.dubbo.common.extension.ext11_no_adaptive.NoAdaptiveExtImpl\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext2.Ext2",
    "content": "impl1=org.apache.dubbo.common.extension.ext2.impl.Ext2Impl1\nimpl2=org.apache.dubbo.common.extension.ext2.impl.Ext2Impl2\nimpl3=org.apache.dubbo.common.extension.ext2.impl.Ext2Impl3"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext3.UseProtocolKeyExt",
    "content": "impl1=org.apache.dubbo.common.extension.ext3.impl.UseProtocolKeyExtImpl1\nimpl2=org.apache.dubbo.common.extension.ext3.impl.UseProtocolKeyExtImpl2\nimpl3=org.apache.dubbo.common.extension.ext3.impl.UseProtocolKeyExtImpl3"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext4.NoUrlParamExt",
    "content": "impl1=org.apache.dubbo.common.extension.ext4.impl.Ext4Impl1\nimpl2=org.apache.dubbo.common.extension.ext4.impl.Ext4Impl2"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt",
    "content": "impl1=org.apache.dubbo.common.extension.ext5.impl.Ext5Impl1\nimpl2=org.apache.dubbo.common.extension.ext5.impl.Ext5Impl2\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext6_inject.Ext6",
    "content": "impl1=org.apache.dubbo.common.extension.ext6_inject.impl.Ext6Impl1\nimpl2=org.apache.dubbo.common.extension.ext6_inject.impl.Ext6Impl2"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext6_wrap.WrappedExt",
    "content": "impl1=org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Impl1\nimpl2=org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Impl2\nimpl3=org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Impl3\nimpl4=org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Impl4\nwrapper1=org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Wrapper1\nwrapper2=org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Wrapper2\nwrapper3=org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Wrapper3\nwrapper4=org.apache.dubbo.common.extension.ext6_wrap.impl.Ext6Wrapper4\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext7.InitErrorExt",
    "content": "error=org.apache.dubbo.common.extension.ext7.impl.Ext7InitErrorImpl\nok=org.apache.dubbo.common.extension.ext7.impl.Ext7Impl\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext8_add.AddExt1",
    "content": "impl1=org.apache.dubbo.common.extension.ext8_add.impl.AddExt1Impl1"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ext9_empty.Ext9Empty",
    "content": ""
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.injection.InjectExt",
    "content": "injection=org.apache.dubbo.common.extension.injection.impl.InjectExtImpl"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.support.Filter0",
    "content": "_1=org.apache.dubbo.common.extension.support.Filter1\n_2=org.apache.dubbo.common.extension.support.Filter2\n_3=org.apache.dubbo.common.extension.support.Filter3\n_4=org.apache.dubbo.common.extension.support.Filter4\n_5=org.apache.dubbo.common.extension.support.OldFilter5"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.wrapper.Demo",
    "content": "demo=org.apache.dubbo.common.extension.wrapper.impl.DemoImpl\nwrapper=org.apache.dubbo.common.extension.wrapper.impl.DemoWrapper\nwrapper2=org.apache.dubbo.common.extension.wrapper.impl.DemoWrapper2\ndemo2=org.apache.dubbo.common.extension.wrapper.impl.DemoImpl"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.lang.ShutdownHookCallback",
    "content": "default=org.apache.dubbo.common.lang.DefaultShutdownHookCallback"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.logger.LoggerAdapter",
    "content": "slf4j=org.apache.dubbo.common.logger.slf4j.Slf4jLoggerAdapter"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.ssl.CertProvider",
    "content": "first=org.apache.dubbo.common.ssl.FirstCertProvider\nsecond=org.apache.dubbo.common.ssl.SecondCertProvider\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.status.StatusChecker",
    "content": "aa=12"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.status.reporter.FrameworkStatusReporter",
    "content": "mock=org.apache.dubbo.common.status.reporter.MockFrameworkStatusReporter\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener",
    "content": "#echo2=org.apache.dubbo.event.EchoEventListener2"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder",
    "content": "test=org.apache.dubbo.metadata.definition.TestTypeBuilder\ntest3=org.apache.dubbo.metadata.definition.Test3TypeBuilder\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.executor.IsolationExecutorSupportFactory",
    "content": "mock1=org.apache.dubbo.rpc.executor.Mock1IsolationExecutorSupportFactory\nmock2=org.apache.dubbo.rpc.executor.Mock2IsolationExecutorSupportFactory\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/org.apache.dubbo.common.convert.Converter",
    "content": "# org.apache.dubbo.common.convert.Converter\nstring-to-double=org.apache.dubbo.common.extension.convert.String2DoubleConverter\nstring-to-integer=org.apache.dubbo.common.extension.convert.String2IntegerConverter"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/dubbo/org.apache.dubbo.common.extension.SPI1",
    "content": "1=org.apache.dubbo.common.extension.SPI1Impl\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/services/java.lang.CharSequence",
    "content": "java.lang.String\njava.lang.StringBuilder\norg.apache.dubbo.common.utils.DefaultCharSequence"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/services/org.apache.dubbo.common.extension.LoadingStrategy",
    "content": "org.apache.dubbo.common.extension.DubboExternalLoadingStrategy"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/services/org.apache.dubbo.common.extension.SPI3",
    "content": "3=org.apache.dubbo.common.extension.SPI3Impl\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/services/org.apache.dubbo.common.extension.SPI4",
    "content": "4=org.apache.dubbo.common.extension.SPI4Impl\n"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/services/org.apache.dubbo.common.extension.activate.ActivateExt1",
    "content": "org.apache.dubbo.common.extension.activate.impl.ActivateExt1Impl1"
  },
  {
    "path": "dubbo-common/src/test/resources/META-INF/test-versions/dubbo-common",
    "content": "# This is a test file\nrevision=1.0.0\ngit.commit.id=82a29fcd674216fe9bea10b6efef3196929dd7ca\n"
  },
  {
    "path": "dubbo-common/src/test/resources/StreamUtilsTest.txt",
    "content": "0123456789"
  },
  {
    "path": "dubbo-common/src/test/resources/certs/ca.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla\nFw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0\nYXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT\nBnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7\n+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu\ng1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd\nQah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV\nHQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau\nsPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m\noIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG\nDfcog5wrJytaQ6UA0wE=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "dubbo-common/src/test/resources/certs/cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIC6TCCAlKgAwIBAgIBCjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET\nMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ\ndHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTEwMDEwOTU4WhcNMjUxMTA3\nMDEwOTU4WjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8G\nA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYDVQQDDAp0ZXN0Y2xp\nZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsVEfbob4W3lVCDLOVmx9K\ncdJnoZdvurGaTY87xNiopmaR8zCR7pFR9BX5L4bNG/PkuVLfVTVAKndyDCQggBBr\nUTaEITNbfWK9swHJEr20WnKfhS/wo/Xg5sqNNCrFRmnnnwOA4eDlvmYZEzSnJXV6\npEro9bBH9uOCWWLqmaev7QIDAQABo4HCMIG/MAkGA1UdEwQCMAAwCwYDVR0PBAQD\nAgXgMB0GA1UdDgQWBBQAdbW5Vml/CnYwqdP3mOHDARU+8zBwBgNVHSMEaTBnoVqk\nWDBWMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMY\nSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2GCCQCRxhke\nHRoqBzAJBgNVHREEAjAAMAkGA1UdEgQCMAAwDQYJKoZIhvcNAQELBQADgYEAf4MM\nk+sdzd720DfrQ0PF2gDauR3M9uBubozDuMuF6ufAuQBJSKGQEGibXbUelrwHmnql\nUjTyfolVcxEBVaF4VFHmn7u6vP7S1NexIDdNUHcULqxIb7Tzl8JYq8OOHD2rQy4H\ns8BXaVIzw4YcaCGAMS0iDX052Sy7e2JhP8Noxvo=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "dubbo-common/src/test/resources/certs/key.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOxUR9uhvhbeVUIM\ns5WbH0px0mehl2+6sZpNjzvE2KimZpHzMJHukVH0Ffkvhs0b8+S5Ut9VNUAqd3IM\nJCCAEGtRNoQhM1t9Yr2zAckSvbRacp+FL/Cj9eDmyo00KsVGaeefA4Dh4OW+ZhkT\nNKcldXqkSuj1sEf244JZYuqZp6/tAgMBAAECgYEAi2NSVqpZMafE5YYUTcMGe6QS\nk2jtpsqYgggI2RnLJ/2tNZwYI5pwP8QVSbnMaiF4gokD5hGdrNDfTnb2v+yIwYEH\n0w8+oG7Z81KodsiZSIDJfTGsAZhVNwOz9y0VD8BBZZ1/274Zh52AUKLjZS/ZwIbS\nW2ywya855dPnH/wj+0ECQQD9X8D920kByTNHhBG18biAEZ4pxs9f0OAG8333eVcI\nw2lJDLsYDZrCB2ocgA3lUdozlzPC7YDYw8reg0tkiRY5AkEA7sdNzOeQsQRn7++5\n0bP9DtT/iON1gbfxRzCfCfXdoOtfQWIzTePWtURt9X/5D9NofI0Rg5W2oGy/MLe5\n/sXHVQJBAIup5XrJDkQywNZyAUU2ecn2bCWBFjwtqd+LBmuMciI9fOKsZtEKZrz/\nU0lkeMRoSwvXE8wmGLjjrAbdfohrXFkCQQDZEx/LtIl6JINJQiswVe0tWr6k+ASP\n1WXoTm+HYpoF/XUvv9LccNF1IazFj34hwRQwhx7w/V52Ieb+p0jUMYGxAkEAjDhd\n9pBO1fKXWiXzi9ZKfoyTNcUq3eBSVKwPG2nItg5ycXengjT5sgcWDnciIzW7BIVI\nJiqOszq9GWESErAatg==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "dubbo-common/src/test/resources/dubbo-migration.yaml",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\nkey: demo-consumer\nstep: APPLICATION_FIRST\nthreshold: 0.1\n"
  },
  {
    "path": "dubbo-common/src/test/resources/dubbo.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ndubbo=properties\ndubbo.application.enable-file-cache=false\ndubbo.service.shutdown.wait=200\n"
  },
  {
    "path": "dubbo-common/src/test/resources/json.flex",
    "content": "package org.apache.dubbo.common.json;\n%%\n\n%{\nprivate StringBuffer sb;\n%}\n\n%table\n%unicode\n%state STR1,STR2\n\n%yylexthrow ParseException\n\nHEX = [a-fA-F0-9]\nHEX4 = {HEX}{HEX}{HEX}{HEX}\n\nIDENT = [a-zA-Z_$] [a-zA-Z0-9_$]*\nINT_LITERAL = [-]? [0-9]+\nFLOAT_LITERAL = {INT_LITERAL} ( ( \\.[0-9]+ ) ? ( [eE][-+]? [0-9]+ )? )\n\nESC1 = [^\\\"\\\\]\nESC2 = [^\\'\\\\]\n\nSKIP = [ \\t\\r\\n]\nOTHERS = .\n%%\n\n<STR1>{\n\t\\\"\t\t\t\t{ yybegin(YYINITIAL); return new JSONToken(JSONToken.STRING, sb.toString()); }\n\t{ESC1}+\t\t\t{ sb.append(yytext()); }\n\t\\\\\\\"\t\t\t{ sb.append('\"'); }\n}\n\n<STR2>{\n\t\\'\t\t\t\t{ yybegin(YYINITIAL); return new JSONToken(JSONToken.STRING, sb.toString()); }\n\t{ESC2}+\t\t\t{ sb.append(yytext()); }\n\t\\\\\\'\t\t\t{ sb.append('\\''); }\n}\n\n<STR1,STR2>{\n\t\\\\\\\\\t\t\t{ sb.append('\\\\'); }\n\t\\\\\\/\t\t\t{ sb.append('/'); }\n\t\\\\b\t\t\t\t{ sb.append('\\b'); }\n\t\\\\f\t\t\t\t{ sb.append('\\f'); }\n\t\\\\n\t\t\t\t{ sb.append('\\n'); }\n\t\\\\r\t\t\t\t{ sb.append('\\r'); }\n\t\\\\t\t\t\t\t{ sb.append('\\t'); }\n\t\\\\u{HEX4}\t\t{ try{ sb.append((char)Integer.parseInt(yytext().substring(2),16)); }catch(Exception e){ throw new ParseException(e.getMessage()); } }\n}\n\n<YYINITIAL>{\n\t\\\"\t\t\t\t\t{ sb = new StringBuffer(); yybegin(STR1); }\n\t\\'\t\t\t\t\t{ sb = new StringBuffer(); yybegin(STR2); }\n\t{INT_LITERAL}\t\t{ Long val = Long.valueOf(yytext()); return new JSONToken(JSONToken.INT, val); }\n\t{FLOAT_LITERAL}\t\t{ Double val = Double.valueOf(yytext()); return new JSONToken(JSONToken.FLOAT, val); }\n\t\"true\"|\"TRUE\"\t\t{ return new JSONToken(JSONToken.BOOL, Boolean.TRUE); }\n\t\"false\"|\"FALSE\"\t\t{ return new JSONToken(JSONToken.BOOL, Boolean.FALSE); }\n\t\"null\"|\"NULL\"\t\t{ return new JSONToken(JSONToken.NULL, null); }\n\t{IDENT}\t\t\t\t{ return new JSONToken(JSONToken.IDENT, yytext()); }\n\t\"{\"\t\t\t\t\t{ return new JSONToken(JSONToken.LBRACE); }\n\t\"}\"\t\t\t\t\t{ return new JSONToken(JSONToken.RBRACE); }\n\t\"[\"\t\t\t\t\t{ return new JSONToken(JSONToken.LSQUARE); }\n\t\"]\"\t\t\t\t\t{ return new JSONToken(JSONToken.RSQUARE); }\n\t\",\"\t\t\t\t\t{ return new JSONToken(JSONToken.COMMA); }\n\t\":\"\t\t\t\t\t{ return new JSONToken(JSONToken.COLON); }\n\t{SKIP}+ \t\t\t{}\n\t{OTHERS} \t\t\t{ throw new ParseException(\"Unexpected char [\" + yytext() +\"]\"); }\n}\n"
  },
  {
    "path": "dubbo-common/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-common/src/test/resources/md5.testfile.txt",
    "content": "hello world!"
  },
  {
    "path": "dubbo-common/src/test/resources/org/apache/dubbo/common/bytecode/TestClass",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.common.bytecode;\n\nimport org.apache.dubbo.common.bytecode.ClassGenerator.DC;\n\npublic class TestClass extends BaseClass implements DC, BaseInterface {\n    public static volatile String staticAttr = \"defaultVal\";\n    protected volatile String strAttr;\n    private volatile int intAttr;\n\n    public void setStrAttr(String var1, int var2) throws Throwable, RuntimeException {\n        this.strAttr = var1;\n    }\n\n    public void setIntAttr(String var1, int var2) throws Throwable, RuntimeException {\n        this.intAttr = var2;\n    }\n\n    public String getStrAttr() throws Throwable, RuntimeException {\n        return this.strAttr;\n    }\n\n    public int getIntAttr() throws Throwable, RuntimeException {\n        return this.intAttr;\n    }\n\n    public String baseClassMethod() {\n        return \"method comes from BaseClass\";\n    }\n\n    public TestClass() {\n    }\n\n    public TestClass(String var1, int var2) throws Throwable, RuntimeException {\n        this.strAttr = var1;\n        this.intAttr = var2;\n    }\n\n    public TestClass(StringBuilder sb) {\n        sb.append(\"constructor comes from BaseClass\");\n    }\n}\n\n"
  },
  {
    "path": "dubbo-common/src/test/resources/org/apache/dubbo/common/extension/adaptive/HasAdaptiveExt$Adaptive",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.adaptive;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\npublic class HasAdaptiveExt$Adaptive implements org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt {\npublic java.lang.String echo(org.apache.dubbo.common.URL arg0, java.lang.String arg1)  {\nif (arg0 == null) throw new IllegalArgumentException(\"url == null\");\norg.apache.dubbo.common.URL url = arg0;\nString extName = url.getParameter(\"has.adaptive.ext\", \"adaptive\");\nif(extName == null) throw new IllegalStateException(\"Failed to get extension (org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt) name from url (\" + url.toString() + \") use keys([has.adaptive.ext])\");\nScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt.class);\norg.apache.dubbo.common.extension.adaptive.HasAdaptiveExt extension = (org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt)scopeModel.getExtensionLoader(org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt.class).getExtension(extName);\nreturn extension.echo(arg0, arg1);\n}\n}\n"
  },
  {
    "path": "dubbo-common/src/test/resources/org/apache/dubbo/common/serialize/dubbo/SimpleDO.fc",
    "content": "a,d,e,b,c\nstr3,str2"
  },
  {
    "path": "dubbo-common/src/test/resources/parameters.properties",
    "content": "dubbo.parameters=[{a:b},{c_.d: r*}]\n"
  },
  {
    "path": "dubbo-common/src/test/resources/properties.load",
    "content": "a=12\nb=34\nc=56"
  },
  {
    "path": "dubbo-common/src/test/resources/security/serialize.allowlist",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\ncom.example.DemoInterface\ncom.sun.Interface1\n\norg.apache.dubbo\n"
  },
  {
    "path": "dubbo-common/src/test/resources/security/serialize.blockedlist",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\ncom.exampletest.DemoInterface\n"
  },
  {
    "path": "dubbo-common/src/test/resources/special_spi.properties",
    "content": "org.apache.dubbo.common.extension.SPI1=ALL\norg.apache.dubbo.common.extension.SPI2=DUBBO_INTERNAL\norg.apache.dubbo.common.extension.SPI3=DUBBO_INTERNAL\norg.apache.dubbo.common.extension.SPI4=SERVICES\n"
  },
  {
    "path": "dubbo-compatible/README.md",
    "content": "### dubbo-compatible\n\nHi, all\n\nFrom 2.7.x, `Dubbo` has renamed package to `org.apache.dubbo`, so `dubbo-compatible` module is provided.\n\nFor compatibility with older versions, we provider the following most popular APIs(classes/interfaces):\n\n* com.alibaba.dubbo.rpc.Filter / Invocation / Invoker / Result / RpcContext / RpcException\n* com.alibaba.dubbo.config.annotation.Reference / Service\n* com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo\n* com.alibaba.dubbo.common.Constants / URL\n* com.alibaba.dubbo.common.extension.ExtensionFactory\n* com.alibaba.dubbo.common.serialize.Serialization / ObjectInput / ObjectOutput\n* com.alibaba.dubbo.cache.CacheFactory / Cache\n* com.alibaba.dubbo.rpc.service.EchoService / GenericService\n\nThe above APIs work fine with some unit tests in the test root. \n\nExcept these APIs, others provided in `dubbo-compatible` are just bridge APIs without any unit tests, they may work with wrong. If you have any demand for them, you could: \n\n* Implement your own extensions with new APIs. (RECOMMENDED) \n* Follow `com.alibaba.dubbo.rpc.Filter` to implement bridge APIs, and then contribute to community. \n* Open issue on github.\n\nBy the way, We will remove this module some day, so it's recommended that implementing your extensions with new APIs at the right time. \n\nNow we need your help: Any other popular APIs are missing?\n\nFor compatible module, any suggestions are welcome. Thanks."
  },
  {
    "path": "dubbo-compatible/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-compatible</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The compatible module of dubbo project</description>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-tx</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-zookeeper-curator5</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-filter-cache</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-filter-validation</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>javax.servlet</groupId>\n      <artifactId>javax.servlet-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <!-- JAX-RS API -->\n    <dependency>\n      <groupId>javax.ws.rs</groupId>\n      <artifactId>javax.ws.rs-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>log4j</groupId>\n      <artifactId>log4j</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-fastjson2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-multicast</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-processor</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.alibaba</groupId>\n      <artifactId>fastjson</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-test-check</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/cache/Cache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.cache;\n\n@Deprecated\npublic interface Cache extends org.apache.dubbo.cache.Cache {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/cache/CacheFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.cache;\n\nimport com.alibaba.dubbo.common.DelegateURL;\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.rpc.Invocation;\n\n@Deprecated\npublic interface CacheFactory extends org.apache.dubbo.cache.CacheFactory {\n\n    Cache getCache(URL url, Invocation invocation);\n\n    default org.apache.dubbo.cache.Cache getCache(\n            org.apache.dubbo.common.URL url, org.apache.dubbo.rpc.Invocation invocation) {\n        return this.getCache(new DelegateURL(url), new Invocation.CompatibleInvocation(invocation));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/cache/support/AbstractCacheFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.cache.support;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport com.alibaba.dubbo.cache.Cache;\nimport com.alibaba.dubbo.cache.CacheFactory;\nimport com.alibaba.dubbo.common.DelegateURL;\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.rpc.Invocation;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;\n\n@Deprecated\npublic abstract class AbstractCacheFactory implements CacheFactory {\n\n    private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<>();\n\n    @Override\n    public Cache getCache(URL url, Invocation invocation) {\n        url = url.addParameter(METHOD_KEY, invocation.getMethodName());\n        String key = url.toFullString();\n        Cache cache = caches.get(key);\n        if (cache == null) {\n            caches.put(key, createCache(url));\n            cache = caches.get(key);\n        }\n        return cache;\n    }\n\n    protected abstract Cache createCache(URL url);\n\n    @Override\n    public org.apache.dubbo.cache.Cache getCache(\n            org.apache.dubbo.common.URL url, org.apache.dubbo.rpc.Invocation invocation) {\n        return getCache(new DelegateURL(url), new Invocation.CompatibleInvocation(invocation));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.constants.FilterConstants;\nimport org.apache.dubbo.common.constants.QosConstants;\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.constants.RemotingConstants;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.regex.Pattern;\n\n@Deprecated\npublic class Constants\n        implements CommonConstants,\n                QosConstants,\n                FilterConstants,\n                RegistryConstants,\n                RemotingConstants,\n                org.apache.dubbo.config.Constants,\n                org.apache.dubbo.remoting.Constants,\n                org.apache.dubbo.rpc.cluster.Constants,\n                org.apache.dubbo.monitor.Constants,\n                org.apache.dubbo.rpc.Constants,\n                org.apache.dubbo.rpc.protocol.dubbo.Constants,\n                org.apache.dubbo.common.serialize.Constants,\n                org.apache.dubbo.common.config.configcenter.Constants,\n                org.apache.dubbo.metadata.report.support.Constants,\n                org.apache.dubbo.registry.Constants {\n    public static final String PROVIDER = \"provider\";\n\n    public static final String CONSUMER = \"consumer\";\n\n    public static final String REGISTER = \"register\";\n\n    public static final String UNREGISTER = \"unregister\";\n\n    public static final String SUBSCRIBE = \"subscribe\";\n\n    public static final String UNSUBSCRIBE = \"unsubscribe\";\n\n    public static final String CATEGORY_KEY = \"category\";\n\n    public static final String PROVIDERS_CATEGORY = \"providers\";\n\n    public static final String CONSUMERS_CATEGORY = \"consumers\";\n\n    public static final String ROUTERS_CATEGORY = \"routers\";\n\n    public static final String CONFIGURATORS_CATEGORY = \"configurators\";\n\n    public static final String DEFAULT_CATEGORY = PROVIDERS_CATEGORY;\n\n    public static final String ENABLED_KEY = \"enabled\";\n\n    public static final String DISABLED_KEY = \"disabled\";\n\n    public static final String VALIDATION_KEY = \"validation\";\n\n    public static final String CACHE_KEY = \"cache\";\n\n    public static final String DYNAMIC_KEY = \"dynamic\";\n\n    public static final String DUBBO_PROPERTIES_KEY = \"dubbo.properties.file\";\n\n    public static final String DEFAULT_DUBBO_PROPERTIES = \"dubbo.properties\";\n\n    public static final String SENT_KEY = \"sent\";\n\n    public static final boolean DEFAULT_SENT = false;\n\n    public static final String REGISTRY_PROTOCOL = \"registry\";\n\n    public static final String $INVOKE = \"$invoke\";\n\n    public static final String $ECHO = \"$echo\";\n\n    public static final int DEFAULT_IO_THREADS = Runtime.getRuntime().availableProcessors() + 1;\n\n    public static final String DEFAULT_PROXY = \"javassist\";\n\n    public static final int DEFAULT_PAYLOAD = 8 * 1024 * 1024;\n\n    public static final String DEFAULT_CLUSTER = \"failover\";\n\n    public static final String DEFAULT_DIRECTORY = \"dubbo\";\n\n    public static final String DEFAULT_LOADBALANCE = \"random\";\n\n    public static final String DEFAULT_PROTOCOL = \"dubbo\";\n\n    public static final String DEFAULT_EXCHANGER = \"header\";\n\n    public static final String DEFAULT_TRANSPORTER = \"netty\";\n\n    public static final String DEFAULT_REMOTING_SERVER = \"netty\";\n\n    public static final String DEFAULT_REMOTING_CLIENT = \"netty\";\n\n    public static final String DEFAULT_REMOTING_CODEC = \"dubbo\";\n\n    public static final String DEFAULT_REMOTING_SERIALIZATION = \"hessian2\";\n\n    public static final String DEFAULT_HTTP_SERVER = \"servlet\";\n\n    public static final String DEFAULT_HTTP_CLIENT = \"jdk\";\n\n    public static final String DEFAULT_HTTP_SERIALIZATION = \"json\";\n\n    public static final String DEFAULT_CHARSET = \"UTF-8\";\n\n    public static final int DEFAULT_WEIGHT = 100;\n\n    public static final int DEFAULT_FORKS = 2;\n\n    public static final String DEFAULT_THREAD_NAME = \"Dubbo\";\n\n    public static final int DEFAULT_CORE_THREADS = 0;\n\n    public static final int DEFAULT_THREADS = 200;\n\n    public static final int DEFAULT_QUEUES = 0;\n\n    public static final int DEFAULT_ALIVE = 60 * 1000;\n\n    public static final int DEFAULT_CONNECTIONS = 0;\n\n    public static final int DEFAULT_ACCEPTS = 0;\n\n    public static final int DEFAULT_IDLE_TIMEOUT = 600 * 1000;\n\n    public static final int DEFAULT_HEARTBEAT = 60 * 1000;\n\n    public static final int DEFAULT_TIMEOUT = 1000;\n\n    public static final int DEFAULT_CONNECT_TIMEOUT = 3000;\n\n    public static final int DEFAULT_RETRIES = 2;\n\n    public static final int DEFAULT_BUFFER_SIZE = 8 * 1024;\n\n    public static final int MAX_BUFFER_SIZE = 16 * 1024;\n\n    public static final int MIN_BUFFER_SIZE = 1 * 1024;\n\n    public static final String REMOVE_VALUE_PREFIX = \"-\";\n\n    public static final String HIDE_KEY_PREFIX = \".\";\n\n    public static final String DEFAULT_KEY_PREFIX = \"default.\";\n\n    public static final String DEFAULT_KEY = \"default\";\n\n    public static final String LOADBALANCE_KEY = \"loadbalance\";\n\n    public static final String ROUTER_KEY = \"router\";\n\n    public static final String CLUSTER_KEY = \"cluster\";\n\n    public static final String REGISTRY_KEY = \"registry\";\n\n    public static final String MONITOR_KEY = \"monitor\";\n\n    public static final String SIDE_KEY = \"side\";\n\n    public static final String PROVIDER_SIDE = \"provider\";\n\n    public static final String CONSUMER_SIDE = \"consumer\";\n\n    public static final String DEFAULT_REGISTRY = \"dubbo\";\n\n    public static final String BACKUP_KEY = \"backup\";\n\n    public static final String DIRECTORY_KEY = \"directory\";\n\n    public static final String DEPRECATED_KEY = \"deprecated\";\n\n    public static final String ANYHOST_KEY = \"anyhost\";\n\n    public static final String ANYHOST_VALUE = \"0.0.0.0\";\n\n    public static final String LOCALHOST_KEY = \"localhost\";\n\n    public static final String LOCALHOST_VALUE = \"127.0.0.1\";\n\n    public static final String APPLICATION_KEY = \"application\";\n\n    public static final String LOCAL_KEY = \"local\";\n\n    public static final String STUB_KEY = \"stub\";\n\n    public static final String MOCK_KEY = \"mock\";\n\n    public static final String PROTOCOL_KEY = \"protocol\";\n\n    public static final String PROXY_KEY = \"proxy\";\n\n    public static final String WEIGHT_KEY = \"weight\";\n\n    public static final String FORKS_KEY = \"forks\";\n\n    public static final String DEFAULT_THREADPOOL = \"limited\";\n\n    public static final String DEFAULT_CLIENT_THREADPOOL = \"cached\";\n\n    public static final String THREADPOOL_KEY = \"threadpool\";\n\n    public static final String THREAD_NAME_KEY = \"threadname\";\n\n    public static final String IO_THREADS_KEY = \"iothreads\";\n\n    public static final String CORE_THREADS_KEY = \"corethreads\";\n\n    public static final String THREADS_KEY = \"threads\";\n\n    public static final String QUEUES_KEY = \"queues\";\n\n    public static final String ALIVE_KEY = \"alive\";\n\n    public static final String EXECUTES_KEY = \"executes\";\n\n    public static final String BUFFER_KEY = \"buffer\";\n\n    public static final String PAYLOAD_KEY = \"payload\";\n\n    public static final String REFERENCE_FILTER_KEY = \"reference.filter\";\n\n    public static final String INVOKER_LISTENER_KEY = \"invoker.listener\";\n\n    public static final String SERVICE_FILTER_KEY = \"service.filter\";\n\n    public static final String EXPORTER_LISTENER_KEY = \"exporter.listener\";\n\n    public static final String ACCESS_LOG_KEY = \"accesslog\";\n\n    public static final String ACTIVES_KEY = \"actives\";\n\n    public static final String CONNECTIONS_KEY = \"connections\";\n\n    public static final String ACCEPTS_KEY = \"accepts\";\n\n    public static final String IDLE_TIMEOUT_KEY = \"idle.timeout\";\n\n    public static final String HEARTBEAT_KEY = \"heartbeat\";\n\n    public static final String HEARTBEAT_TIMEOUT_KEY = \"heartbeat.timeout\";\n\n    public static final String CONNECT_TIMEOUT_KEY = \"connect.timeout\";\n\n    public static final String TIMEOUT_KEY = \"timeout\";\n\n    public static final String RETRIES_KEY = \"retries\";\n\n    public static final String PROMPT_KEY = \"prompt\";\n\n    public static final String DEFAULT_PROMPT = \"dubbo>\";\n\n    public static final String CODEC_KEY = \"codec\";\n\n    public static final String SERIALIZATION_KEY = \"serialization\";\n\n    public static final String EXCHANGER_KEY = \"exchanger\";\n\n    public static final String TRANSPORTER_KEY = \"transporter\";\n\n    public static final String SERVER_KEY = \"server\";\n\n    public static final String CLIENT_KEY = \"client\";\n\n    public static final String ID_KEY = \"id\";\n\n    public static final String ASYNC_KEY = \"async\";\n\n    public static final String RETURN_KEY = \"return\";\n\n    public static final String TOKEN_KEY = \"token\";\n\n    public static final String METHOD_KEY = \"method\";\n\n    public static final String METHODS_KEY = \"methods\";\n\n    public static final String CHARSET_KEY = \"charset\";\n\n    public static final String RECONNECT_KEY = \"reconnect\";\n\n    public static final String SEND_RECONNECT_KEY = \"send.reconnect\";\n\n    public static final int DEFAULT_RECONNECT_PERIOD = 2000;\n\n    public static final String SHUTDOWN_TIMEOUT_KEY = \"shutdown.timeout\";\n\n    public static final int DEFAULT_SHUTDOWN_TIMEOUT = 1000 * 60 * 15;\n\n    public static final String PID_KEY = \"pid\";\n\n    public static final String TIMESTAMP_KEY = \"timestamp\";\n\n    public static final String WARMUP_KEY = \"warmup\";\n\n    public static final int DEFAULT_WARMUP = 10 * 60 * 1000;\n\n    public static final String CHECK_KEY = \"check\";\n\n    public static final String REGISTER_KEY = \"register\";\n\n    public static final String SUBSCRIBE_KEY = \"subscribe\";\n\n    public static final String GROUP_KEY = \"group\";\n\n    public static final String PATH_KEY = \"path\";\n\n    public static final String INTERFACE_KEY = \"interface\";\n\n    public static final String GENERIC_KEY = \"generic\";\n\n    public static final String FILE_KEY = \"file\";\n\n    public static final String WAIT_KEY = \"wait\";\n\n    public static final String CLASSIFIER_KEY = \"classifier\";\n\n    public static final String VERSION_KEY = \"version\";\n\n    public static final String REVISION_KEY = \"revision\";\n\n    public static final String DUBBO_VERSION_KEY = \"dubbo\";\n\n    public static final String HESSIAN_VERSION_KEY = \"hessian.version\";\n\n    public static final String DISPATCHER_KEY = \"dispatcher\";\n\n    public static final String CHANNEL_HANDLER_KEY = \"channel.handler\";\n\n    public static final String DEFAULT_CHANNEL_HANDLER = \"default\";\n\n    public static final String ANY_VALUE = \"*\";\n\n    public static final String COMMA_SEPARATOR = \",\";\n\n    public static final Pattern COMMA_SPLIT_PATTERN = Pattern.compile(\"\\\\s*[,]+\\\\s*\");\n\n    public static final String PATH_SEPARATOR = \"/\";\n\n    public static final String REGISTRY_SEPARATOR = \"|\";\n\n    public static final Pattern REGISTRY_SPLIT_PATTERN = Pattern.compile(\"\\\\s*[|;]+\\\\s*\");\n\n    public static final String SEMICOLON_SEPARATOR = \";\";\n\n    public static final Pattern SEMICOLON_SPLIT_PATTERN = Pattern.compile(\"\\\\s*[;]+\\\\s*\");\n\n    public static final String CONNECT_QUEUE_CAPACITY = \"connect.queue.capacity\";\n\n    public static final String CONNECT_QUEUE_WARNING_SIZE = \"connect.queue.warning.size\";\n\n    public static final int DEFAULT_CONNECT_QUEUE_WARNING_SIZE = 1000;\n\n    public static final String CHANNEL_ATTRIBUTE_READONLY_KEY = \"channel.readonly\";\n\n    public static final String CHANNEL_READONLYEVENT_SENT_KEY = \"channel.readonly.sent\";\n\n    public static final String CHANNEL_SEND_READONLYEVENT_KEY = \"channel.readonly.send\";\n\n    public static final String COUNT_PROTOCOL = \"count\";\n\n    public static final String TRACE_PROTOCOL = \"trace\";\n\n    public static final String EMPTY_PROTOCOL = \"empty\";\n\n    public static final String ADMIN_PROTOCOL = \"admin\";\n\n    public static final String PROVIDER_PROTOCOL = \"provider\";\n\n    public static final String CONSUMER_PROTOCOL = \"consumer\";\n\n    public static final String ROUTE_PROTOCOL = \"route\";\n\n    public static final String SCRIPT_PROTOCOL = \"script\";\n\n    public static final String CONDITION_PROTOCOL = \"condition\";\n\n    public static final String MOCK_PROTOCOL = \"mock\";\n\n    public static final String RETURN_PREFIX = \"return \";\n\n    public static final String THROW_PREFIX = \"throw\";\n\n    public static final String FAIL_PREFIX = \"fail:\";\n\n    public static final String FORCE_PREFIX = \"force:\";\n\n    public static final String FORCE_KEY = \"force\";\n\n    public static final String MERGER_KEY = \"merger\";\n\n    public static final String CLUSTER_AVAILABLE_CHECK_KEY = \"cluster.availablecheck\";\n\n    public static final boolean DEFAULT_CLUSTER_AVAILABLE_CHECK = true;\n\n    public static final String CLUSTER_STICKY_KEY = \"sticky\";\n\n    public static final boolean DEFAULT_CLUSTER_STICKY = false;\n\n    public static final String LAZY_CONNECT_KEY = \"lazy\";\n\n    public static final String LAZY_CONNECT_INITIAL_STATE_KEY = \"connect.lazy.initial.state\";\n\n    public static final boolean DEFAULT_LAZY_CONNECT_INITIAL_STATE = true;\n\n    public static final String REGISTRY_FILESAVE_SYNC_KEY = \"save.file\";\n\n    public static final String REGISTRY_RETRY_PERIOD_KEY = \"retry.period\";\n\n    public static final int DEFAULT_REGISTRY_RETRY_PERIOD = 5 * 1000;\n\n    public static final String REGISTRY_RECONNECT_PERIOD_KEY = \"reconnect.period\";\n\n    public static final int DEFAULT_REGISTRY_RECONNECT_PERIOD = 3 * 1000;\n\n    public static final String SESSION_TIMEOUT_KEY = \"session\";\n\n    public static final int DEFAULT_SESSION_TIMEOUT = 60 * 1000;\n\n    public static final String EXPORT_KEY = \"export\";\n\n    public static final String REFER_KEY = \"refer\";\n\n    public static final String CALLBACK_SERVICE_KEY = \"callback.service.instid\";\n\n    public static final String CALLBACK_INSTANCES_LIMIT_KEY = \"callbacks\";\n\n    public static final int DEFAULT_CALLBACK_INSTANCES = 1;\n\n    public static final String CALLBACK_SERVICE_PROXY_KEY = \"callback.service.proxy\";\n\n    public static final String IS_CALLBACK_SERVICE = \"is_callback_service\";\n\n    public static final String CHANNEL_CALLBACK_KEY = \"channel.callback.invokers.key\";\n\n    @Deprecated\n    public static final String SHUTDOWN_WAIT_SECONDS_KEY = \"dubbo.service.shutdown.wait.seconds\";\n\n    public static final String SHUTDOWN_WAIT_KEY = \"dubbo.service.shutdown.wait\";\n\n    public static final String IS_SERVER_KEY = \"isserver\";\n\n    public static final int DEFAULT_SERVER_SHUTDOWN_TIMEOUT = 10000;\n\n    public static final String ON_CONNECT_KEY = \"onconnect\";\n\n    public static final String ON_DISCONNECT_KEY = \"ondisconnect\";\n\n    public static final String ON_INVOKE_METHOD_KEY = \"oninvoke.method\";\n\n    public static final String ON_RETURN_METHOD_KEY = \"onreturn.method\";\n\n    public static final String ON_THROW_METHOD_KEY = \"onthrow.method\";\n\n    public static final String ON_INVOKE_INSTANCE_KEY = \"oninvoke.instance\";\n\n    public static final String ON_RETURN_INSTANCE_KEY = \"onreturn.instance\";\n\n    public static final String ON_THROW_INSTANCE_KEY = \"onthrow.instance\";\n\n    public static final String OVERRIDE_PROTOCOL = \"override\";\n\n    public static final String PRIORITY_KEY = \"priority\";\n\n    public static final String RULE_KEY = \"rule\";\n\n    public static final String TYPE_KEY = \"type\";\n\n    public static final String RUNTIME_KEY = \"runtime\";\n\n    public static final String ROUTER_TYPE_CLEAR = \"clean\";\n\n    public static final String DEFAULT_SCRIPT_TYPE_KEY = \"javascript\";\n\n    public static final String STUB_EVENT_KEY = \"dubbo.stub.event\";\n\n    public static final boolean DEFAULT_STUB_EVENT = false;\n\n    public static final String STUB_EVENT_METHODS_KEY = \"dubbo.stub.event.methods\";\n\n    public static final String INVOCATION_NEED_MOCK = \"invocation.need.mock\";\n\n    public static final String LOCAL_PROTOCOL = \"injvm\";\n\n    public static final String AUTO_ATTACH_INVOCATIONID_KEY = \"invocationid.autoattach\";\n\n    public static final String SCOPE_KEY = \"scope\";\n\n    public static final String SCOPE_LOCAL = \"local\";\n\n    public static final String SCOPE_REMOTE = \"remote\";\n\n    public static final String SCOPE_NONE = \"none\";\n\n    public static final String RELIABLE_PROTOCOL = \"napoli\";\n\n    public static final String TPS_LIMIT_RATE_KEY = \"tps\";\n\n    public static final String TPS_LIMIT_INTERVAL_KEY = \"tps.interval\";\n\n    public static final long DEFAULT_TPS_LIMIT_INTERVAL = 60 * 1000;\n\n    public static final String DECODE_IN_IO_THREAD_KEY = \"decode.in.io\";\n\n    public static final boolean DEFAULT_DECODE_IN_IO_THREAD = true;\n\n    public static final String INPUT_KEY = \"input\";\n\n    public static final String OUTPUT_KEY = \"output\";\n\n    public static final String EXECUTOR_SERVICE_COMPONENT_KEY = ExecutorService.class.getName();\n\n    public static final String GENERIC_SERIALIZATION_NATIVE_JAVA = \"nativejava\";\n\n    public static final String GENERIC_SERIALIZATION_DEFAULT = \"true\";\n\n    public static final String INVOKER_CONNECTED_KEY = \"connected\";\n\n    public static final String INVOKER_INSIDE_INVOKERS_KEY = \"inside.invokers\";\n\n    public static final String INVOKER_INSIDE_INVOKER_COUNT_KEY = \"inside.invoker.count\";\n\n    public static final String CLUSTER_SWITCH_FACTOR = \"cluster.switch.factor\";\n\n    public static final String CLUSTER_SWITCH_LOG_ERROR = \"cluster.switch.log.error\";\n\n    public static final double DEFAULT_CLUSTER_SWITCH_FACTOR = 2;\n\n    public static final String DISPATHER_KEY = \"dispather\";\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/DelegateURL.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common;\n\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.url.component.URLAddress;\nimport org.apache.dubbo.common.url.component.URLParam;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.net.InetSocketAddress;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Predicate;\n\n@Deprecated\npublic class DelegateURL extends com.alibaba.dubbo.common.URL {\n    protected final org.apache.dubbo.common.URL apacheUrl;\n\n    public DelegateURL(org.apache.dubbo.common.URL apacheUrl) {\n        this.apacheUrl = apacheUrl;\n    }\n\n    public static com.alibaba.dubbo.common.URL valueOf(String url) {\n        return new DelegateURL(org.apache.dubbo.common.URL.valueOf(url));\n    }\n\n    @Override\n    public String getProtocol() {\n        return apacheUrl.getProtocol();\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL setProtocol(String protocol) {\n        return new DelegateURL(apacheUrl.setProtocol(protocol));\n    }\n\n    @Override\n    public String getUsername() {\n        return apacheUrl.getUsername();\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL setUsername(String username) {\n        return new DelegateURL(apacheUrl.setUsername(username));\n    }\n\n    @Override\n    public String getPassword() {\n        return apacheUrl.getPassword();\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL setPassword(String password) {\n        return new DelegateURL(apacheUrl.setPassword(password));\n    }\n\n    @Override\n    public String getAuthority() {\n        return apacheUrl.getAuthority();\n    }\n\n    @Override\n    public String getHost() {\n        return apacheUrl.getHost();\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL setHost(String host) {\n        return new DelegateURL(apacheUrl.setHost(host));\n    }\n\n    @Override\n    public String getIp() {\n        return apacheUrl.getIp();\n    }\n\n    @Override\n    public int getPort() {\n        return apacheUrl.getPort();\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL setPort(int port) {\n        return new DelegateURL(apacheUrl.setPort(port));\n    }\n\n    @Override\n    public int getPort(int defaultPort) {\n        return apacheUrl.getPort(defaultPort);\n    }\n\n    @Override\n    public String getAddress() {\n        return apacheUrl.getAddress();\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL setAddress(String address) {\n        return new DelegateURL(apacheUrl.setAddress(address));\n    }\n\n    @Override\n    public String getBackupAddress() {\n        return apacheUrl.getBackupAddress();\n    }\n\n    @Override\n    public String getBackupAddress(int defaultPort) {\n        return apacheUrl.getBackupAddress(defaultPort);\n    }\n\n    @Override\n    public String getPath() {\n        return apacheUrl.getPath();\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL setPath(String path) {\n        return new DelegateURL(apacheUrl.setPath(path));\n    }\n\n    @Override\n    public String getAbsolutePath() {\n        return apacheUrl.getAbsolutePath();\n    }\n\n    @Override\n    public Map<String, String> getParameters() {\n        return apacheUrl.getParameters();\n    }\n\n    @Override\n    public String getParameterAndDecoded(String key) {\n        return apacheUrl.getParameterAndDecoded(key);\n    }\n\n    @Override\n    public String getParameterAndDecoded(String key, String defaultValue) {\n        return apacheUrl.getParameterAndDecoded(key, defaultValue);\n    }\n\n    @Override\n    public String getParameter(String key) {\n        return apacheUrl.getParameter(key);\n    }\n\n    @Override\n    public String getParameter(String key, String defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public String[] getParameter(String key, String[] defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL getUrlParameter(String key) {\n        return new DelegateURL(apacheUrl.getUrlParameter(key));\n    }\n\n    @Override\n    public double getParameter(String key, double defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public float getParameter(String key, float defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public long getParameter(String key, long defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public int getParameter(String key, int defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public short getParameter(String key, short defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public byte getParameter(String key, byte defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public float getPositiveParameter(String key, float defaultValue) {\n        return apacheUrl.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public double getPositiveParameter(String key, double defaultValue) {\n        return apacheUrl.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public long getPositiveParameter(String key, long defaultValue) {\n        return apacheUrl.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public int getPositiveParameter(String key, int defaultValue) {\n        return apacheUrl.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public short getPositiveParameter(String key, short defaultValue) {\n        return apacheUrl.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public byte getPositiveParameter(String key, byte defaultValue) {\n        return apacheUrl.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public char getParameter(String key, char defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public boolean getParameter(String key, boolean defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public boolean hasParameter(String key) {\n        return apacheUrl.hasParameter(key);\n    }\n\n    @Override\n    public String getMethodParameterAndDecoded(String method, String key) {\n        return apacheUrl.getMethodParameterAndDecoded(method, key);\n    }\n\n    @Override\n    public String getMethodParameterAndDecoded(String method, String key, String defaultValue) {\n        return apacheUrl.getMethodParameterAndDecoded(method, key, defaultValue);\n    }\n\n    @Override\n    public String getMethodParameter(String method, String key) {\n        return apacheUrl.getMethodParameter(method, key);\n    }\n\n    @Override\n    public String getMethodParameter(String method, String key, String defaultValue) {\n        return apacheUrl.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public double getMethodParameter(String method, String key, double defaultValue) {\n        return apacheUrl.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public float getMethodParameter(String method, String key, float defaultValue) {\n        return apacheUrl.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public long getMethodParameter(String method, String key, long defaultValue) {\n        return apacheUrl.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public int getMethodParameter(String method, String key, int defaultValue) {\n        return apacheUrl.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public short getMethodParameter(String method, String key, short defaultValue) {\n        return apacheUrl.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public byte getMethodParameter(String method, String key, byte defaultValue) {\n        return apacheUrl.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public double getMethodPositiveParameter(String method, String key, double defaultValue) {\n        return apacheUrl.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public float getMethodPositiveParameter(String method, String key, float defaultValue) {\n        return apacheUrl.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public long getMethodPositiveParameter(String method, String key, long defaultValue) {\n        return apacheUrl.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public int getMethodPositiveParameter(String method, String key, int defaultValue) {\n        return apacheUrl.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public short getMethodPositiveParameter(String method, String key, short defaultValue) {\n        return apacheUrl.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public byte getMethodPositiveParameter(String method, String key, byte defaultValue) {\n        return apacheUrl.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public char getMethodParameter(String method, String key, char defaultValue) {\n        return apacheUrl.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public boolean getMethodParameter(String method, String key, boolean defaultValue) {\n        return apacheUrl.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public boolean hasMethodParameter(String method, String key) {\n        return apacheUrl.hasMethodParameter(method, key);\n    }\n\n    @Override\n    public boolean isLocalHost() {\n        return apacheUrl.isLocalHost();\n    }\n\n    @Override\n    public boolean isAnyHost() {\n        return apacheUrl.isAnyHost();\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameterAndEncoded(String key, String value) {\n        return new DelegateURL(apacheUrl.addParameterAndEncoded(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, boolean value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, char value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, byte value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, short value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, int value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, long value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, float value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, double value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, Enum<?> value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, Number value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, CharSequence value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameter(String key, String value) {\n        return new DelegateURL(apacheUrl.addParameter(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameterIfAbsent(String key, String value) {\n        return new DelegateURL(apacheUrl.addParameterIfAbsent(key, value));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameters(Map<String, String> parameters) {\n        return new DelegateURL(apacheUrl.addParameters(parameters));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParametersIfAbsent(Map<String, String> parameters) {\n        return new DelegateURL(apacheUrl.addParametersIfAbsent(parameters));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameters(String... pairs) {\n        return new DelegateURL(apacheUrl.addParameters(pairs));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL addParameterString(String query) {\n        return new DelegateURL(apacheUrl.addParameterString(query));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL removeParameter(String key) {\n        return new DelegateURL(apacheUrl.removeParameter(key));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL removeParameters(Collection<String> keys) {\n        return new DelegateURL(apacheUrl.removeParameters(keys));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL removeParameters(String... keys) {\n        return new DelegateURL(apacheUrl.removeParameters(keys));\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL clearParameters() {\n        return new DelegateURL(apacheUrl.clearParameters());\n    }\n\n    @Override\n    public String getRawParameter(String key) {\n        return apacheUrl.getRawParameter(key);\n    }\n\n    @Override\n    public Map<String, String> toMap() {\n        return apacheUrl.toMap();\n    }\n\n    @Override\n    public String toString() {\n        return apacheUrl.toString();\n    }\n\n    @Override\n    public String toString(String... parameters) {\n        return apacheUrl.toString(parameters);\n    }\n\n    @Override\n    public String toIdentityString() {\n        return apacheUrl.toIdentityString();\n    }\n\n    @Override\n    public String toIdentityString(String... parameters) {\n        return apacheUrl.toIdentityString(parameters);\n    }\n\n    @Override\n    public String toFullString() {\n        return apacheUrl.toFullString();\n    }\n\n    @Override\n    public String toFullString(String... parameters) {\n        return apacheUrl.toFullString(parameters);\n    }\n\n    @Override\n    public String toParameterString() {\n        return apacheUrl.toParameterString();\n    }\n\n    @Override\n    public String toParameterString(String... parameters) {\n        return apacheUrl.toParameterString(parameters);\n    }\n\n    @Override\n    public java.net.URL toJavaURL() {\n        return apacheUrl.toJavaURL();\n    }\n\n    @Override\n    public InetSocketAddress toInetSocketAddress() {\n        return apacheUrl.toInetSocketAddress();\n    }\n\n    @Override\n    public String getServiceKey() {\n        return apacheUrl.getServiceKey();\n    }\n\n    @Override\n    public String toServiceStringWithoutResolving() {\n        return apacheUrl.toServiceStringWithoutResolving();\n    }\n\n    @Override\n    public String toServiceString() {\n        return apacheUrl.toServiceString();\n    }\n\n    @Override\n    public String getServiceInterface() {\n        return apacheUrl.getServiceInterface();\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL setServiceInterface(String service) {\n        return new DelegateURL(apacheUrl.setServiceInterface(service));\n    }\n\n    @Override\n    public org.apache.dubbo.common.URL getOriginalURL() {\n        return apacheUrl;\n    }\n\n    @Override\n    public URLAddress getUrlAddress() {\n        return apacheUrl.getUrlAddress();\n    }\n\n    @Override\n    public URLParam getUrlParam() {\n        return apacheUrl.getUrlParam();\n    }\n\n    @Override\n    public String getUserInformation() {\n        return apacheUrl.getUserInformation();\n    }\n\n    @Override\n    public List<org.apache.dubbo.common.URL> getBackupUrls() {\n        return apacheUrl.getBackupUrls();\n    }\n\n    @Override\n    public Map<String, String> getOriginalParameters() {\n        return apacheUrl.getOriginalParameters();\n    }\n\n    @Override\n    public Map<String, String> getAllParameters() {\n        return apacheUrl.getAllParameters();\n    }\n\n    @Override\n    public Map<String, String> getParameters(Predicate<String> nameToSelect) {\n        return apacheUrl.getParameters(nameToSelect);\n    }\n\n    @Override\n    public String getOriginalParameter(String key) {\n        return apacheUrl.getOriginalParameter(key);\n    }\n\n    @Override\n    public List<String> getParameter(String key, List<String> defaultValue) {\n        return apacheUrl.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public <T> T getParameter(String key, Class<T> valueType) {\n        return apacheUrl.getParameter(key, valueType);\n    }\n\n    @Override\n    public <T> T getParameter(String key, Class<T> valueType, T defaultValue) {\n        return apacheUrl.getParameter(key, valueType, defaultValue);\n    }\n\n    @Override\n    public org.apache.dubbo.common.URL setScopeModel(ScopeModel scopeModel) {\n        return apacheUrl.setScopeModel(scopeModel);\n    }\n\n    @Override\n    public ScopeModel getScopeModel() {\n        return apacheUrl.getScopeModel();\n    }\n\n    @Override\n    public FrameworkModel getOrDefaultFrameworkModel() {\n        return apacheUrl.getOrDefaultFrameworkModel();\n    }\n\n    @Override\n    public ApplicationModel getOrDefaultApplicationModel() {\n        return apacheUrl.getOrDefaultApplicationModel();\n    }\n\n    @Override\n    public ApplicationModel getApplicationModel() {\n        return apacheUrl.getApplicationModel();\n    }\n\n    @Override\n    public ModuleModel getOrDefaultModuleModel() {\n        return apacheUrl.getOrDefaultModuleModel();\n    }\n\n    @Override\n    public org.apache.dubbo.common.URL setServiceModel(ServiceModel serviceModel) {\n        return apacheUrl.setServiceModel(serviceModel);\n    }\n\n    @Override\n    public ServiceModel getServiceModel() {\n        return apacheUrl.getServiceModel();\n    }\n\n    @Override\n    public String getMethodParameterStrict(String method, String key) {\n        return apacheUrl.getMethodParameterStrict(method, key);\n    }\n\n    @Override\n    public String getAnyMethodParameter(String key) {\n        return apacheUrl.getAnyMethodParameter(key);\n    }\n\n    @Override\n    public boolean hasMethodParameter(String method) {\n        return apacheUrl.hasMethodParameter(method);\n    }\n\n    @Override\n    public Map<String, String> toOriginalMap() {\n        return apacheUrl.toOriginalMap();\n    }\n\n    @Override\n    public String getColonSeparatedKey() {\n        return apacheUrl.getColonSeparatedKey();\n    }\n\n    @Override\n    public String getDisplayServiceKey() {\n        return apacheUrl.getDisplayServiceKey();\n    }\n\n    @Override\n    public String getPathKey() {\n        return apacheUrl.getPathKey();\n    }\n\n    public static String buildKey(String path, String group, String version) {\n        return org.apache.dubbo.common.URL.buildKey(path, group, version);\n    }\n\n    @Override\n    public String getProtocolServiceKey() {\n        return apacheUrl.getProtocolServiceKey();\n    }\n\n    @Override\n    @Deprecated\n    public String getServiceName() {\n        return apacheUrl.getServiceName();\n    }\n\n    @Override\n    @Deprecated\n    public int getIntParameter(String key) {\n        return apacheUrl.getIntParameter(key);\n    }\n\n    @Override\n    @Deprecated\n    public int getIntParameter(String key, int defaultValue) {\n        return apacheUrl.getIntParameter(key, defaultValue);\n    }\n\n    @Override\n    @Deprecated\n    public int getPositiveIntParameter(String key, int defaultValue) {\n        return apacheUrl.getPositiveIntParameter(key, defaultValue);\n    }\n\n    @Override\n    @Deprecated\n    public boolean getBooleanParameter(String key) {\n        return apacheUrl.getBooleanParameter(key);\n    }\n\n    @Override\n    @Deprecated\n    public boolean getBooleanParameter(String key, boolean defaultValue) {\n        return apacheUrl.getBooleanParameter(key, defaultValue);\n    }\n\n    @Override\n    @Deprecated\n    public int getMethodIntParameter(String method, String key) {\n        return apacheUrl.getMethodIntParameter(method, key);\n    }\n\n    @Override\n    @Deprecated\n    public int getMethodIntParameter(String method, String key, int defaultValue) {\n        return apacheUrl.getMethodIntParameter(method, key, defaultValue);\n    }\n\n    @Override\n    @Deprecated\n    public int getMethodPositiveIntParameter(String method, String key, int defaultValue) {\n        return apacheUrl.getMethodPositiveIntParameter(method, key, defaultValue);\n    }\n\n    @Override\n    @Deprecated\n    public boolean getMethodBooleanParameter(String method, String key) {\n        return apacheUrl.getMethodBooleanParameter(method, key);\n    }\n\n    @Override\n    @Deprecated\n    public boolean getMethodBooleanParameter(String method, String key, boolean defaultValue) {\n        return apacheUrl.getMethodBooleanParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public Configuration toConfiguration() {\n        return apacheUrl.toConfiguration();\n    }\n\n    @Override\n    public int hashCode() {\n        return apacheUrl.hashCode();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        return apacheUrl.equals(obj);\n    }\n\n    public static void putMethodParameter(\n            String method, String key, String value, Map<String, Map<String, String>> methodParameters) {\n        org.apache.dubbo.common.URL.putMethodParameter(method, key, value, methodParameters);\n    }\n\n    @Override\n    public String getApplication(String defaultValue) {\n        return apacheUrl.getApplication(defaultValue);\n    }\n\n    @Override\n    public String getApplication() {\n        return apacheUrl.getApplication();\n    }\n\n    @Override\n    public String getRemoteApplication() {\n        return apacheUrl.getRemoteApplication();\n    }\n\n    @Override\n    public String getGroup() {\n        return apacheUrl.getGroup();\n    }\n\n    @Override\n    public String getGroup(String defaultValue) {\n        return apacheUrl.getGroup(defaultValue);\n    }\n\n    @Override\n    public String getVersion() {\n        return apacheUrl.getVersion();\n    }\n\n    @Override\n    public String getVersion(String defaultValue) {\n        return apacheUrl.getVersion(defaultValue);\n    }\n\n    @Override\n    public String getConcatenatedParameter(String key) {\n        return apacheUrl.getConcatenatedParameter(key);\n    }\n\n    @Override\n    public String getCategory(String defaultValue) {\n        return apacheUrl.getCategory(defaultValue);\n    }\n\n    @Override\n    public String[] getCategory(String[] defaultValue) {\n        return apacheUrl.getCategory(defaultValue);\n    }\n\n    @Override\n    public String getCategory() {\n        return apacheUrl.getCategory();\n    }\n\n    @Override\n    public String getSide(String defaultValue) {\n        return apacheUrl.getSide(defaultValue);\n    }\n\n    @Override\n    public String getSide() {\n        return apacheUrl.getSide();\n    }\n\n    @Override\n    public Map<String, Object> getAttributes() {\n        return apacheUrl.getAttributes();\n    }\n\n    @Override\n    public org.apache.dubbo.common.URL addAttributes(Map<String, Object> attributeMap) {\n        return apacheUrl.addAttributes(attributeMap);\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        return apacheUrl.getAttribute(key);\n    }\n\n    @Override\n    public Object getAttribute(String key, Object defaultValue) {\n        return apacheUrl.getAttribute(key, defaultValue);\n    }\n\n    @Override\n    public org.apache.dubbo.common.URL putAttribute(String key, Object obj) {\n        return apacheUrl.putAttribute(key, obj);\n    }\n\n    @Override\n    public org.apache.dubbo.common.URL removeAttribute(String key) {\n        return apacheUrl.removeAttribute(key);\n    }\n\n    @Override\n    public boolean hasAttribute(String key) {\n        return apacheUrl.hasAttribute(key);\n    }\n\n    @Override\n    public Map<String, String> getOriginalServiceParameters(String service) {\n        return apacheUrl.getOriginalServiceParameters(service);\n    }\n\n    @Override\n    public Map<String, String> getServiceParameters(String service) {\n        return apacheUrl.getServiceParameters(service);\n    }\n\n    @Override\n    public String getOriginalServiceParameter(String service, String key) {\n        return apacheUrl.getOriginalServiceParameter(service, key);\n    }\n\n    @Override\n    public String getServiceParameter(String service, String key) {\n        return apacheUrl.getServiceParameter(service, key);\n    }\n\n    @Override\n    public String getServiceParameter(String service, String key, String defaultValue) {\n        return apacheUrl.getServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public int getServiceParameter(String service, String key, int defaultValue) {\n        return apacheUrl.getServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public double getServiceParameter(String service, String key, double defaultValue) {\n        return apacheUrl.getServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public float getServiceParameter(String service, String key, float defaultValue) {\n        return apacheUrl.getServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public long getServiceParameter(String service, String key, long defaultValue) {\n        return apacheUrl.getServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public short getServiceParameter(String service, String key, short defaultValue) {\n        return apacheUrl.getServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public byte getServiceParameter(String service, String key, byte defaultValue) {\n        return apacheUrl.getServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public char getServiceParameter(String service, String key, char defaultValue) {\n        return apacheUrl.getServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public boolean getServiceParameter(String service, String key, boolean defaultValue) {\n        return apacheUrl.getServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public boolean hasServiceParameter(String service, String key) {\n        return apacheUrl.hasServiceParameter(service, key);\n    }\n\n    @Override\n    public float getPositiveServiceParameter(String service, String key, float defaultValue) {\n        return apacheUrl.getPositiveServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public double getPositiveServiceParameter(String service, String key, double defaultValue) {\n        return apacheUrl.getPositiveServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public long getPositiveServiceParameter(String service, String key, long defaultValue) {\n        return apacheUrl.getPositiveServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public int getPositiveServiceParameter(String service, String key, int defaultValue) {\n        return apacheUrl.getPositiveServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public short getPositiveServiceParameter(String service, String key, short defaultValue) {\n        return apacheUrl.getPositiveServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public byte getPositiveServiceParameter(String service, String key, byte defaultValue) {\n        return apacheUrl.getPositiveServiceParameter(service, key, defaultValue);\n    }\n\n    @Override\n    public String getServiceMethodParameterAndDecoded(String service, String method, String key) {\n        return apacheUrl.getServiceMethodParameterAndDecoded(service, method, key);\n    }\n\n    @Override\n    public String getServiceMethodParameterAndDecoded(String service, String method, String key, String defaultValue) {\n        return apacheUrl.getServiceMethodParameterAndDecoded(service, method, key, defaultValue);\n    }\n\n    @Override\n    public String getServiceMethodParameterStrict(String service, String method, String key) {\n        return apacheUrl.getServiceMethodParameterStrict(service, method, key);\n    }\n\n    @Override\n    public String getServiceMethodParameter(String service, String method, String key) {\n        return apacheUrl.getServiceMethodParameter(service, method, key);\n    }\n\n    @Override\n    public String getServiceMethodParameter(String service, String method, String key, String defaultValue) {\n        return apacheUrl.getServiceMethodParameter(service, method, key, defaultValue);\n    }\n\n    @Override\n    public double getServiceMethodParameter(String service, String method, String key, double defaultValue) {\n        return apacheUrl.getServiceMethodParameter(service, method, key, defaultValue);\n    }\n\n    @Override\n    public float getServiceMethodParameter(String service, String method, String key, float defaultValue) {\n        return apacheUrl.getServiceMethodParameter(service, method, key, defaultValue);\n    }\n\n    @Override\n    public long getServiceMethodParameter(String service, String method, String key, long defaultValue) {\n        return apacheUrl.getServiceMethodParameter(service, method, key, defaultValue);\n    }\n\n    @Override\n    public int getServiceMethodParameter(String service, String method, String key, int defaultValue) {\n        return apacheUrl.getServiceMethodParameter(service, method, key, defaultValue);\n    }\n\n    @Override\n    public short getServiceMethodParameter(String service, String method, String key, short defaultValue) {\n        return apacheUrl.getServiceMethodParameter(service, method, key, defaultValue);\n    }\n\n    @Override\n    public byte getServiceMethodParameter(String service, String method, String key, byte defaultValue) {\n        return apacheUrl.getServiceMethodParameter(service, method, key, defaultValue);\n    }\n\n    @Override\n    public boolean hasServiceMethodParameter(String service, String method, String key) {\n        return apacheUrl.hasServiceMethodParameter(service, method, key);\n    }\n\n    @Override\n    public boolean hasServiceMethodParameter(String service, String method) {\n        return apacheUrl.hasServiceMethodParameter(service, method);\n    }\n\n    @Override\n    public org.apache.dubbo.common.URL toSerializableURL() {\n        return apacheUrl.toSerializableURL();\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/URL.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.net.InetSocketAddress;\nimport java.util.Collection;\nimport java.util.Map;\n\n@Deprecated\npublic class URL extends org.apache.dubbo.common.URL {\n\n    protected URL() {\n        super();\n    }\n\n    public URL(org.apache.dubbo.common.URL url) {\n        super(\n                url.getProtocol(),\n                url.getUsername(),\n                url.getPassword(),\n                url.getHost(),\n                url.getPort(),\n                url.getPath(),\n                url.getParameters());\n    }\n\n    public URL(String protocol, String host, int port) {\n        super(protocol, null, null, host, port, null, (Map<String, String>) null);\n    }\n\n    public URL(String protocol, String host, int port, String[] pairs) {\n        super(protocol, null, null, host, port, null, CollectionUtils.toStringMap(pairs));\n    }\n\n    public URL(String protocol, String host, int port, Map<String, String> parameters) {\n        super(protocol, null, null, host, port, null, parameters);\n    }\n\n    public URL(String protocol, String host, int port, String path) {\n        super(protocol, null, null, host, port, path, (Map<String, String>) null);\n    }\n\n    public URL(String protocol, String host, int port, String path, String... pairs) {\n        super(protocol, null, null, host, port, path, CollectionUtils.toStringMap(pairs));\n    }\n\n    public URL(String protocol, String host, int port, String path, Map<String, String> parameters) {\n        super(protocol, null, null, host, port, path, parameters);\n    }\n\n    public URL(String protocol, String username, String password, String host, int port, String path) {\n        super(protocol, username, password, host, port, path, (Map<String, String>) null);\n    }\n\n    public URL(String protocol, String username, String password, String host, int port, String path, String... pairs) {\n        super(protocol, username, password, host, port, path, CollectionUtils.toStringMap(pairs));\n    }\n\n    public URL(\n            String protocol,\n            String username,\n            String password,\n            String host,\n            int port,\n            String path,\n            Map<String, String> parameters) {\n        super(protocol, username, password, host, port, path, parameters);\n    }\n\n    public static URL valueOf(String url) {\n        org.apache.dubbo.common.URL result = org.apache.dubbo.common.URL.valueOf(url);\n        return new DelegateURL(result);\n    }\n\n    public static String encode(String value) {\n        return org.apache.dubbo.common.URL.encode(value);\n    }\n\n    public static String decode(String value) {\n        return org.apache.dubbo.common.URL.decode(value);\n    }\n\n    @Override\n    public String getProtocol() {\n        return super.getProtocol();\n    }\n\n    @Override\n    public URL setProtocol(String protocol) {\n        return new URL(\n                protocol,\n                super.getUsername(),\n                super.getPassword(),\n                super.getHost(),\n                super.getPort(),\n                super.getPath(),\n                super.getParameters());\n    }\n\n    @Override\n    public String getUsername() {\n        return super.getUsername();\n    }\n\n    @Override\n    public URL setUsername(String username) {\n        return new URL(\n                super.getProtocol(),\n                username,\n                super.getPassword(),\n                super.getHost(),\n                super.getPort(),\n                super.getPath(),\n                super.getParameters());\n    }\n\n    @Override\n    public String getPassword() {\n        return super.getPassword();\n    }\n\n    @Override\n    public URL setPassword(String password) {\n        return new URL(\n                super.getProtocol(),\n                super.getUsername(),\n                password,\n                super.getHost(),\n                super.getPort(),\n                super.getPath(),\n                super.getParameters());\n    }\n\n    @Override\n    public String getAuthority() {\n        // Compatible with old version logic：The previous Authority only contained username and password information.\n        return super.getUserInformation();\n    }\n\n    @Override\n    public String getHost() {\n        return super.getHost();\n    }\n\n    @Override\n    public URL setHost(String host) {\n        return new URL(\n                super.getProtocol(),\n                super.getUsername(),\n                super.getPassword(),\n                host,\n                super.getPort(),\n                super.getPath(),\n                super.getParameters());\n    }\n\n    @Override\n    public String getIp() {\n        return super.getIp();\n    }\n\n    @Override\n    public int getPort() {\n        return super.getPort();\n    }\n\n    @Override\n    public URL setPort(int port) {\n        return new URL(\n                super.getProtocol(),\n                super.getUsername(),\n                super.getPassword(),\n                super.getHost(),\n                port,\n                super.getPath(),\n                super.getParameters());\n    }\n\n    @Override\n    public int getPort(int defaultPort) {\n        return super.getPort();\n    }\n\n    @Override\n    public String getAddress() {\n        return super.getAddress();\n    }\n\n    @Override\n    public URL setAddress(String address) {\n        org.apache.dubbo.common.URL result = super.setAddress(address);\n        return new URL(result);\n    }\n\n    @Override\n    public String getBackupAddress() {\n        return super.getBackupAddress();\n    }\n\n    @Override\n    public String getBackupAddress(int defaultPort) {\n        return super.getBackupAddress(defaultPort);\n    }\n\n    //    public List<URL> getBackupUrls() {\n    //        List<org.apache.dubbo.common.URL> res = super.getBackupUrls();\n    //        return res.stream().map(url -> new URL(url)).collect(Collectors.toList());\n    //    }\n\n    @Override\n    public String getPath() {\n        return super.getPath();\n    }\n\n    @Override\n    public URL setPath(String path) {\n        return new URL(\n                super.getProtocol(),\n                super.getUsername(),\n                super.getPassword(),\n                super.getHost(),\n                super.getPort(),\n                path,\n                super.getParameters());\n    }\n\n    @Override\n    public String getAbsolutePath() {\n        return super.getAbsolutePath();\n    }\n\n    @Override\n    public Map<String, String> getParameters() {\n        return super.getParameters();\n    }\n\n    @Override\n    public String getParameterAndDecoded(String key) {\n        return super.getParameterAndDecoded(key);\n    }\n\n    @Override\n    public String getParameterAndDecoded(String key, String defaultValue) {\n        return org.apache.dubbo.common.URL.decode(getParameter(key, defaultValue));\n    }\n\n    @Override\n    public String getParameter(String key) {\n        return super.getParameter(key);\n    }\n\n    @Override\n    public String getParameter(String key, String defaultValue) {\n        return super.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public String[] getParameter(String key, String[] defaultValue) {\n        return super.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public URL getUrlParameter(String key) {\n        org.apache.dubbo.common.URL result = super.getUrlParameter(key);\n        return new URL(result);\n    }\n\n    @Override\n    public double getParameter(String key, double defaultValue) {\n        return super.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public float getParameter(String key, float defaultValue) {\n        return super.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public long getParameter(String key, long defaultValue) {\n        return super.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public int getParameter(String key, int defaultValue) {\n        return super.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public short getParameter(String key, short defaultValue) {\n        return super.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public byte getParameter(String key, byte defaultValue) {\n        return super.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public float getPositiveParameter(String key, float defaultValue) {\n        return super.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public double getPositiveParameter(String key, double defaultValue) {\n        return super.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public long getPositiveParameter(String key, long defaultValue) {\n        return super.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public int getPositiveParameter(String key, int defaultValue) {\n        return super.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public short getPositiveParameter(String key, short defaultValue) {\n        return super.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public byte getPositiveParameter(String key, byte defaultValue) {\n        return super.getPositiveParameter(key, defaultValue);\n    }\n\n    @Override\n    public char getParameter(String key, char defaultValue) {\n        return super.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public boolean getParameter(String key, boolean defaultValue) {\n        return super.getParameter(key, defaultValue);\n    }\n\n    @Override\n    public boolean hasParameter(String key) {\n        return super.hasParameter(key);\n    }\n\n    @Override\n    public String getMethodParameterAndDecoded(String method, String key) {\n        return super.getMethodParameterAndDecoded(method, key);\n    }\n\n    @Override\n    public String getMethodParameterAndDecoded(String method, String key, String defaultValue) {\n        return super.getMethodParameterAndDecoded(method, key, defaultValue);\n    }\n\n    @Override\n    public String getMethodParameter(String method, String key) {\n        return super.getMethodParameter(method, key);\n    }\n\n    @Override\n    public String getMethodParameter(String method, String key, String defaultValue) {\n        return super.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public double getMethodParameter(String method, String key, double defaultValue) {\n        return super.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public float getMethodParameter(String method, String key, float defaultValue) {\n        return super.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public long getMethodParameter(String method, String key, long defaultValue) {\n        return super.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public int getMethodParameter(String method, String key, int defaultValue) {\n        return super.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public short getMethodParameter(String method, String key, short defaultValue) {\n        return super.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public byte getMethodParameter(String method, String key, byte defaultValue) {\n        return super.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public double getMethodPositiveParameter(String method, String key, double defaultValue) {\n        return super.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public float getMethodPositiveParameter(String method, String key, float defaultValue) {\n        return super.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public long getMethodPositiveParameter(String method, String key, long defaultValue) {\n        return super.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public int getMethodPositiveParameter(String method, String key, int defaultValue) {\n        return super.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public short getMethodPositiveParameter(String method, String key, short defaultValue) {\n        return super.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public byte getMethodPositiveParameter(String method, String key, byte defaultValue) {\n        return super.getMethodPositiveParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public char getMethodParameter(String method, String key, char defaultValue) {\n        return super.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public boolean getMethodParameter(String method, String key, boolean defaultValue) {\n        return super.getMethodParameter(method, key, defaultValue);\n    }\n\n    @Override\n    public boolean hasMethodParameter(String method, String key) {\n        return super.hasMethodParameter(method, key);\n    }\n\n    @Override\n    public boolean isLocalHost() {\n        return super.isLocalHost();\n    }\n\n    @Override\n    public boolean isAnyHost() {\n        return super.isAnyHost();\n    }\n\n    @Override\n    public URL addParameterAndEncoded(String key, String value) {\n        if (StringUtils.isEmpty(value)) {\n            return this;\n        }\n        return addParameter(key, encode(value));\n    }\n\n    @Override\n    public URL addParameter(String key, boolean value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, char value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, byte value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, short value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, int value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, long value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, float value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, double value) {\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, Enum<?> value) {\n        if (value == null) {\n            return this;\n        }\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, Number value) {\n        if (value == null) {\n            return this;\n        }\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, CharSequence value) {\n        if (value == null || value.length() == 0) {\n            return this;\n        }\n        return addParameter(key, String.valueOf(value));\n    }\n\n    @Override\n    public URL addParameter(String key, String value) {\n        org.apache.dubbo.common.URL result = super.addParameter(key, value);\n        return new URL(result);\n    }\n\n    @Override\n    public URL addParameterIfAbsent(String key, String value) {\n        org.apache.dubbo.common.URL result = super.addParameterIfAbsent(key, value);\n        return new URL(result);\n    }\n\n    @Override\n    public URL addParameters(Map<String, String> parameters) {\n        org.apache.dubbo.common.URL result = super.addParameters(parameters);\n        return new URL(result);\n    }\n\n    @Override\n    public URL addParametersIfAbsent(Map<String, String> parameters) {\n        org.apache.dubbo.common.URL result = super.addParametersIfAbsent(parameters);\n        return new URL(result);\n    }\n\n    @Override\n    public URL addParameters(String... pairs) {\n        org.apache.dubbo.common.URL result = super.addParameters(pairs);\n        return new URL(result);\n    }\n\n    @Override\n    public URL addParameterString(String query) {\n        org.apache.dubbo.common.URL result = super.addParameterString(query);\n        return new URL(result);\n    }\n\n    @Override\n    public URL removeParameter(String key) {\n        org.apache.dubbo.common.URL result = super.removeParameter(key);\n        return new URL(result);\n    }\n\n    @Override\n    public URL removeParameters(Collection<String> keys) {\n        org.apache.dubbo.common.URL result = super.removeParameters(keys);\n        return new URL(result);\n    }\n\n    @Override\n    public URL removeParameters(String... keys) {\n        org.apache.dubbo.common.URL result = super.removeParameters(keys);\n        return new URL(result);\n    }\n\n    @Override\n    public URL clearParameters() {\n        org.apache.dubbo.common.URL result = super.clearParameters();\n        return new URL(result);\n    }\n\n    @Override\n    public String getRawParameter(String key) {\n        return super.getRawParameter(key);\n    }\n\n    @Override\n    public Map<String, String> toMap() {\n        return super.toMap();\n    }\n\n    @Override\n    public String toString() {\n        return super.toString();\n    }\n\n    @Override\n    public String toString(String... parameters) {\n        return super.toString(parameters);\n    }\n\n    @Override\n    public String toIdentityString() {\n        return super.toIdentityString();\n    }\n\n    @Override\n    public String toIdentityString(String... parameters) {\n        return super.toIdentityString(parameters);\n    }\n\n    @Override\n    public String toFullString() {\n        return super.toFullString();\n    }\n\n    @Override\n    public String toFullString(String... parameters) {\n        return super.toFullString(parameters);\n    }\n\n    @Override\n    public String toParameterString() {\n        return super.toParameterString();\n    }\n\n    @Override\n    public String toParameterString(String... parameters) {\n        return super.toParameterString(parameters);\n    }\n\n    @Override\n    public java.net.URL toJavaURL() {\n        return super.toJavaURL();\n    }\n\n    @Override\n    public InetSocketAddress toInetSocketAddress() {\n        return super.toInetSocketAddress();\n    }\n\n    @Override\n    public String getServiceKey() {\n        return super.getServiceKey();\n    }\n\n    @Override\n    public String toServiceStringWithoutResolving() {\n        return super.toServiceStringWithoutResolving();\n    }\n\n    @Override\n    public String toServiceString() {\n        return super.toServiceString();\n    }\n\n    @Override\n    public String getServiceInterface() {\n        return super.getServiceInterface();\n    }\n\n    @Override\n    public URL setServiceInterface(String service) {\n        org.apache.dubbo.common.URL result = super.setServiceInterface(service);\n        return new URL(result);\n    }\n\n    public org.apache.dubbo.common.URL getOriginalURL() {\n        return new org.apache.dubbo.common.URL(\n                super.getProtocol(),\n                super.getUsername(),\n                super.getPassword(),\n                super.getHost(),\n                super.getPort(),\n                super.getPath(),\n                super.getParameters());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/compiler/Compiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.compiler;\n\n@Deprecated\npublic interface Compiler extends org.apache.dubbo.common.compiler.Compiler {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/extension/Activate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.extension;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * See @org.apache.dubbo.common.extension.Activate\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE, ElementType.METHOD})\n@Deprecated\npublic @interface Activate {\n\n    String[] group() default {};\n\n    String[] value() default {};\n\n    @Deprecated\n    String[] before() default {};\n\n    @Deprecated\n    String[] after() default {};\n\n    int order() default 0;\n\n    /**\n     * Activate loadClass when the current extension when the specified className all match\n     * @return className names to all match\n     */\n    String[] onClass() default {};\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/extension/ExtensionFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.extension;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@Deprecated\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface ExtensionFactory extends org.apache.dubbo.common.extension.ExtensionFactory {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/logger/LoggerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.logger;\n\n@Deprecated\npublic interface LoggerAdapter extends org.apache.dubbo.common.logger.LoggerAdapter {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/serialize/ObjectInput.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.serialize;\n\n@Deprecated\npublic interface ObjectInput extends org.apache.dubbo.common.serialize.ObjectInput {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/serialize/ObjectOutput.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.serialize;\n\n@Deprecated\npublic interface ObjectOutput extends org.apache.dubbo.common.serialize.ObjectOutput {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/serialize/Serialization.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.serialize;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport com.alibaba.dubbo.common.DelegateURL;\nimport com.alibaba.dubbo.common.URL;\n\n@Deprecated\npublic interface Serialization extends org.apache.dubbo.common.serialize.Serialization {\n\n    ObjectOutput serialize(URL url, OutputStream output) throws IOException;\n\n    ObjectInput deserialize(URL url, InputStream input) throws IOException;\n\n    @Override\n    default org.apache.dubbo.common.serialize.ObjectOutput serialize(\n            org.apache.dubbo.common.URL url, OutputStream output) throws IOException {\n        return this.serialize(new DelegateURL(url), output);\n    }\n\n    @Override\n    default org.apache.dubbo.common.serialize.ObjectInput deserialize(\n            org.apache.dubbo.common.URL url, InputStream input) throws IOException {\n        return this.deserialize(new DelegateURL(url), input);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/status/Status.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.status;\n\n@Deprecated\npublic class Status extends org.apache.dubbo.common.status.Status {\n\n    public Status(Level level) {\n        super(level);\n    }\n\n    public Status(Level level, String message) {\n        super(level, message);\n    }\n\n    public Status(Level level, String message, String description) {\n        super(level, message, description);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/status/StatusChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.status;\n\n@Deprecated\npublic interface StatusChecker extends org.apache.dubbo.common.status.StatusChecker {\n\n    @Override\n    Status check();\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/store/DataStore.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.store;\n\n@Deprecated\npublic interface DataStore extends org.apache.dubbo.common.store.DataStore {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/threadpool/ThreadPool.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.threadpool;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.concurrent.Executor;\n\n@Deprecated\npublic interface ThreadPool extends org.apache.dubbo.common.threadpool.ThreadPool {\n\n    Executor getExecutor(com.alibaba.dubbo.common.URL url);\n\n    @Override\n    default Executor getExecutor(URL url) {\n        return getExecutor(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/common/utils/UrlUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.common.utils;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.dubbo.common.DelegateURL;\nimport com.alibaba.dubbo.common.URL;\n\n/**\n * 2019-04-17\n */\n@Deprecated\npublic class UrlUtils {\n\n    public static URL parseURL(String address, Map<String, String> defaults) {\n        return new DelegateURL(org.apache.dubbo.common.utils.UrlUtils.parseURL(address, defaults));\n    }\n\n    public static List<URL> parseURLs(String address, Map<String, String> defaults) {\n        return org.apache.dubbo.common.utils.UrlUtils.parseURLs(address, defaults).stream()\n                .map(e -> new DelegateURL(e))\n                .collect(Collectors.toList());\n    }\n\n    public static Map<String, Map<String, String>> convertRegister(Map<String, Map<String, String>> register) {\n        return org.apache.dubbo.common.utils.UrlUtils.convertRegister(register);\n    }\n\n    public static Map<String, String> convertSubscribe(Map<String, String> subscribe) {\n        return org.apache.dubbo.common.utils.UrlUtils.convertSubscribe(subscribe);\n    }\n\n    public static Map<String, Map<String, String>> revertRegister(Map<String, Map<String, String>> register) {\n        return org.apache.dubbo.common.utils.UrlUtils.revertRegister(register);\n    }\n\n    public static Map<String, String> revertSubscribe(Map<String, String> subscribe) {\n        return org.apache.dubbo.common.utils.UrlUtils.revertSubscribe(subscribe);\n    }\n\n    public static Map<String, Map<String, String>> revertNotify(Map<String, Map<String, String>> notify) {\n        return org.apache.dubbo.common.utils.UrlUtils.revertNotify(notify);\n    }\n\n    // compatible for dubbo-2.0.0\n    public static List<String> revertForbid(List<String> forbid, Set<URL> subscribed) {\n        Set<org.apache.dubbo.common.URL> urls =\n                subscribed.stream().map(e -> e.getOriginalURL()).collect(Collectors.toSet());\n        return org.apache.dubbo.common.utils.UrlUtils.revertForbid(forbid, urls);\n    }\n\n    public static URL getEmptyUrl(String service, String category) {\n        return new DelegateURL(org.apache.dubbo.common.utils.UrlUtils.getEmptyUrl(service, category));\n    }\n\n    public static boolean isMatchCategory(String category, String categories) {\n        return org.apache.dubbo.common.utils.UrlUtils.isMatchCategory(category, categories);\n    }\n\n    public static boolean isMatch(URL consumerUrl, URL providerUrl) {\n        return org.apache.dubbo.common.utils.UrlUtils.isMatch(\n                consumerUrl.getOriginalURL(), providerUrl.getOriginalURL());\n    }\n\n    public static boolean isMatchGlobPattern(String pattern, String value, URL param) {\n        return org.apache.dubbo.common.utils.UrlUtils.isMatchGlobPattern(pattern, value, param.getOriginalURL());\n    }\n\n    public static boolean isMatchGlobPattern(String pattern, String value) {\n        return org.apache.dubbo.common.utils.UrlUtils.isMatchGlobPattern(pattern, value);\n    }\n\n    public static boolean isServiceKeyMatch(URL pattern, URL value) {\n        return org.apache.dubbo.common.utils.UrlUtils.isServiceKeyMatch(\n                pattern.getOriginalURL(), value.getOriginalURL());\n    }\n\n    public static boolean isConfigurator(URL url) {\n        return org.apache.dubbo.common.utils.UrlUtils.isConfigurator(url.getOriginalURL());\n    }\n\n    public static boolean isRoute(URL url) {\n        return org.apache.dubbo.common.utils.UrlUtils.isRoute(url.getOriginalURL());\n    }\n\n    public static boolean isProvider(URL url) {\n        return org.apache.dubbo.common.utils.UrlUtils.isProvider(url.getOriginalURL());\n    }\n\n    public static int getHeartbeat(URL url) {\n        return org.apache.dubbo.remoting.utils.UrlUtils.getHeartbeat(url.getOriginalURL());\n    }\n\n    public static int getIdleTimeout(URL url) {\n        return org.apache.dubbo.remoting.utils.UrlUtils.getIdleTimeout(url.getOriginalURL());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/ApplicationConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\n@Deprecated\npublic class ApplicationConfig extends org.apache.dubbo.config.ApplicationConfig {\n\n    public ApplicationConfig() {\n        super();\n    }\n\n    public ApplicationConfig(String name) {\n        super(name);\n    }\n\n    public void setRegistry(com.alibaba.dubbo.config.RegistryConfig registry) {\n        super.setRegistry(registry);\n    }\n\n    public void setMonitor(com.alibaba.dubbo.config.MonitorConfig monitor) {\n        super.setMonitor(monitor);\n    }\n\n    @Override\n    public void setMonitor(String monitor) {\n        setMonitor(new com.alibaba.dubbo.config.MonitorConfig(monitor));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/ArgumentConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\n@Deprecated\npublic class ArgumentConfig extends org.apache.dubbo.config.ArgumentConfig {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/ConsumerConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\n@Deprecated\npublic class ConsumerConfig extends org.apache.dubbo.config.ConsumerConfig {\n\n    public void setApplication(com.alibaba.dubbo.config.ApplicationConfig application) {\n        super.setApplication(application);\n    }\n\n    public void setModule(com.alibaba.dubbo.config.ModuleConfig module) {\n        super.setModule(module);\n    }\n\n    public void setRegistry(com.alibaba.dubbo.config.RegistryConfig registry) {\n        super.setRegistry(registry);\n    }\n\n    public void addMethod(com.alibaba.dubbo.config.MethodConfig methodConfig) {\n        super.addMethod(methodConfig);\n    }\n\n    public void setMonitor(com.alibaba.dubbo.config.MonitorConfig monitor) {\n        super.setMonitor(monitor);\n    }\n\n    public void setMock(Boolean mock) {\n        if (mock == null) {\n            setMock((String) null);\n        } else {\n            setMock(String.valueOf(mock));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/MethodConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\n@Deprecated\npublic class MethodConfig extends org.apache.dubbo.config.MethodConfig {\n    public void addArgument(com.alibaba.dubbo.config.ArgumentConfig argumentConfig) {\n        super.addArgument(argumentConfig);\n    }\n\n    public void setMock(Boolean mock) {\n        if (mock == null) {\n            setMock((String) null);\n        } else {\n            setMock(String.valueOf(mock));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/ModuleConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\n@Deprecated\npublic class ModuleConfig extends org.apache.dubbo.config.ModuleConfig {\n\n    public ModuleConfig() {}\n\n    public ModuleConfig(String name) {\n        super(name);\n    }\n\n    public void setRegistry(com.alibaba.dubbo.config.RegistryConfig registry) {\n        super.setRegistry(registry);\n    }\n\n    public void setMonitor(com.alibaba.dubbo.config.MonitorConfig monitor) {\n        super.setMonitor(monitor);\n    }\n\n    @Override\n    public void setMonitor(String monitor) {\n        setMonitor(new com.alibaba.dubbo.config.MonitorConfig(monitor));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/MonitorConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\n@Deprecated\npublic class MonitorConfig extends org.apache.dubbo.config.MonitorConfig {\n    public MonitorConfig() {}\n\n    public MonitorConfig(String address) {\n        super(address);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/ProtocolConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\n@Deprecated\npublic class ProtocolConfig extends org.apache.dubbo.config.ProtocolConfig {\n\n    public ProtocolConfig() {}\n\n    public ProtocolConfig(String name) {\n        super(name);\n    }\n\n    public ProtocolConfig(String name, int port) {\n        super(name, port);\n    }\n\n    public void mergeProtocol(ProtocolConfig sourceConfig) {\n        super.mergeProtocol(sourceConfig);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/ProviderConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\n@Deprecated\npublic class ProviderConfig extends org.apache.dubbo.config.ProviderConfig {\n    public void setApplication(com.alibaba.dubbo.config.ApplicationConfig application) {\n        super.setApplication(application);\n    }\n\n    public void setModule(com.alibaba.dubbo.config.ModuleConfig module) {\n        super.setModule(module);\n    }\n\n    public void setRegistry(com.alibaba.dubbo.config.RegistryConfig registry) {\n        super.setRegistry(registry);\n    }\n\n    public void addMethod(com.alibaba.dubbo.config.MethodConfig methodConfig) {\n        super.addMethod(methodConfig);\n    }\n\n    public void setMonitor(com.alibaba.dubbo.config.MonitorConfig monitor) {\n        super.setMonitor(monitor);\n    }\n\n    public void setProtocol(com.alibaba.dubbo.config.ProtocolConfig protocol) {\n        super.setProtocol(protocol);\n    }\n\n    @Override\n    public void setProtocol(String protocol) {\n        setProtocol(new com.alibaba.dubbo.config.ProtocolConfig(protocol));\n    }\n\n    public void setMock(Boolean mock) {\n        if (mock == null) {\n            setMock((String) null);\n        } else {\n            setMock(String.valueOf(mock));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\nimport org.apache.dubbo.config.annotation.Reference;\n\n@Deprecated\npublic class ReferenceConfig<T> extends org.apache.dubbo.config.ReferenceConfig<T> {\n\n    public ReferenceConfig() {}\n\n    public ReferenceConfig(Reference reference) {\n        super(reference);\n    }\n\n    public void setConsumer(com.alibaba.dubbo.config.ConsumerConfig consumer) {\n        super.setConsumer(consumer);\n    }\n\n    public void setApplication(com.alibaba.dubbo.config.ApplicationConfig application) {\n        super.setApplication(application);\n    }\n\n    public void setModule(com.alibaba.dubbo.config.ModuleConfig module) {\n        super.setModule(module);\n    }\n\n    public void setRegistry(com.alibaba.dubbo.config.RegistryConfig registry) {\n        super.setRegistry(registry);\n    }\n\n    public void addMethod(com.alibaba.dubbo.config.MethodConfig methodConfig) {\n        super.addMethod(methodConfig);\n    }\n\n    public void setMonitor(com.alibaba.dubbo.config.MonitorConfig monitor) {\n        super.setMonitor(monitor);\n    }\n\n    public void setMock(Boolean mock) {\n        if (mock == null) {\n            setMock((String) null);\n        } else {\n            setMock(String.valueOf(mock));\n        }\n    }\n\n    public void setInterfaceClass(Class<?> interfaceClass) {\n        setInterface(interfaceClass);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/RegistryConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\n@Deprecated\npublic class RegistryConfig extends org.apache.dubbo.config.RegistryConfig {\n\n    public RegistryConfig() {}\n\n    public RegistryConfig(String address) {\n        super(address);\n    }\n\n    public RegistryConfig(String address, String protocol) {\n        super(address, protocol);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config;\n\nimport org.apache.dubbo.config.annotation.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Deprecated\npublic class ServiceConfig<T> extends org.apache.dubbo.config.ServiceConfig<T> {\n\n    public ServiceConfig() {}\n\n    public ServiceConfig(Service service) {\n        super(service);\n    }\n\n    public void setProvider(com.alibaba.dubbo.config.ProviderConfig provider) {\n        super.setProvider(provider);\n    }\n\n    public void setApplication(com.alibaba.dubbo.config.ApplicationConfig application) {\n        super.setApplication(application);\n    }\n\n    public void setModule(com.alibaba.dubbo.config.ModuleConfig module) {\n        super.setModule(module);\n    }\n\n    public void setRegistry(com.alibaba.dubbo.config.RegistryConfig registry) {\n        super.setRegistry(registry);\n    }\n\n    public void addMethod(com.alibaba.dubbo.config.MethodConfig methodConfig) {\n        super.addMethod(methodConfig);\n    }\n\n    public com.alibaba.dubbo.config.MonitorConfig getMonitor() {\n        org.apache.dubbo.config.MonitorConfig monitorConfig = super.getMonitor();\n        if (monitorConfig == null) {\n            return null;\n        }\n        if (monitorConfig instanceof com.alibaba.dubbo.config.MonitorConfig) {\n            return (com.alibaba.dubbo.config.MonitorConfig) monitorConfig;\n        }\n        throw new IllegalArgumentException(\"Monitor has not been set with type com.alibaba.dubbo.config.MonitorConfig. \"\n                + \"Found \" + monitorConfig.getClass().getName() + \" instead.\");\n    }\n\n    public void setMonitor(com.alibaba.dubbo.config.MonitorConfig monitor) {\n        super.setMonitor(monitor);\n    }\n\n    public void setProtocol(com.alibaba.dubbo.config.ProtocolConfig protocol) {\n        super.setProtocol(protocol);\n    }\n\n    public void setMock(Boolean mock) {\n        if (mock == null) {\n            setMock((String) null);\n        } else {\n            setMock(String.valueOf(mock));\n        }\n    }\n\n    public void setProviders(List<ProviderConfig> providers) {\n        setProtocols(convertProviderToProtocol(providers));\n    }\n\n    private static List<ProtocolConfig> convertProviderToProtocol(List<ProviderConfig> providers) {\n        if (providers == null || providers.isEmpty()) {\n            return null;\n        }\n        List<ProtocolConfig> protocols = new ArrayList<>(providers.size());\n        for (ProviderConfig provider : providers) {\n            protocols.add(convertProviderToProtocol(provider));\n        }\n        return protocols;\n    }\n\n    private static ProtocolConfig convertProviderToProtocol(ProviderConfig provider) {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setName(provider.getProtocol().getName());\n        protocol.setServer(provider.getServer());\n        protocol.setClient(provider.getClient());\n        protocol.setCodec(provider.getCodec());\n        protocol.setHost(provider.getHost());\n        protocol.setPort(provider.getPort());\n        protocol.setPath(provider.getPath());\n        protocol.setPayload(provider.getPayload());\n        protocol.setThreads(provider.getThreads());\n        protocol.setParameters(provider.getParameters());\n        return protocol;\n    }\n\n    private static ProviderConfig convertProtocolToProvider(ProtocolConfig protocol) {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setProtocol(protocol);\n        provider.setServer(protocol.getServer());\n        provider.setClient(protocol.getClient());\n        provider.setCodec(protocol.getCodec());\n        provider.setHost(protocol.getHost());\n        provider.setPort(protocol.getPort());\n        provider.setPath(protocol.getPath());\n        provider.setPayload(protocol.getPayload());\n        provider.setThreads(protocol.getThreads());\n        provider.setParameters(protocol.getParameters());\n        return provider;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config.annotation;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Reference\n * <p>\n *\n * @see DubboReference\n * @deprecated Recommend {@link DubboReference} as the substitute\n */\n@Deprecated\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})\npublic @interface Reference {\n\n    Class<?> interfaceClass() default void.class;\n\n    String interfaceName() default \"\";\n\n    String version() default \"\";\n\n    String group() default \"\";\n\n    String url() default \"\";\n\n    String client() default \"\";\n\n    /**\n     * Whether to enable generic invocation, default value is false\n     * @deprecated Do not need specify generic value, judge by injection type and interface class\n     */\n    @Deprecated\n    boolean generic() default false;\n\n    boolean injvm() default true;\n\n    boolean check() default true;\n\n    boolean init() default true;\n\n    boolean lazy() default false;\n\n    boolean stubevent() default false;\n\n    String reconnect() default \"\";\n\n    boolean sticky() default false;\n\n    String proxy() default \"\";\n\n    String stub() default \"\";\n\n    String cluster() default \"\";\n\n    int connections() default -1;\n\n    int callbacks() default -1;\n\n    String onconnect() default \"\";\n\n    String ondisconnect() default \"\";\n\n    String owner() default \"\";\n\n    String layer() default \"\";\n\n    int retries() default -1;\n\n    String loadbalance() default \"\";\n\n    boolean async() default false;\n\n    int actives() default -1;\n\n    boolean sent() default false;\n\n    String mock() default \"\";\n\n    String validation() default \"\";\n\n    int timeout() default -1;\n\n    String cache() default \"\";\n\n    String[] filter() default {};\n\n    String[] listener() default {};\n\n    String[] parameters() default {};\n\n    /**\n     * Application associated name\n     * @deprecated Do not set it and use the global Application Config\n     */\n    @Deprecated\n    String application() default \"\";\n\n    String module() default \"\";\n\n    String consumer() default \"\";\n\n    String monitor() default \"\";\n\n    String[] registry() default {};\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/annotation/Service.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config.annotation;\n\nimport org.apache.dubbo.config.annotation.DubboService;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Service annotation\n *\n * @see DubboService\n * @deprecated Recommend {@link DubboService} as the substitute\n */\n@Deprecated\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE, ElementType.METHOD})\n@Inherited\npublic @interface Service {\n\n    Class<?> interfaceClass() default void.class;\n\n    String interfaceName() default \"\";\n\n    String version() default \"\";\n\n    String group() default \"\";\n\n    String path() default \"\";\n\n    boolean export() default false;\n\n    String token() default \"\";\n\n    boolean deprecated() default false;\n\n    boolean dynamic() default true;\n\n    String accesslog() default \"\";\n\n    int executes() default -1;\n\n    boolean register() default false;\n\n    int weight() default -1;\n\n    String document() default \"\";\n\n    int delay() default -1;\n\n    String local() default \"\";\n\n    String stub() default \"\";\n\n    String cluster() default \"\";\n\n    String proxy() default \"\";\n\n    int connections() default -1;\n\n    int callbacks() default -1;\n\n    String onconnect() default \"\";\n\n    String ondisconnect() default \"\";\n\n    String owner() default \"\";\n\n    String layer() default \"\";\n\n    int retries() default -1;\n\n    String loadbalance() default \"\";\n\n    boolean async() default false;\n\n    int actives() default -1;\n\n    boolean sent() default false;\n\n    String mock() default \"\";\n\n    String validation() default \"\";\n\n    int timeout() default -1;\n\n    String cache() default \"\";\n\n    String[] filter() default {};\n\n    String[] listener() default {};\n\n    String[] parameters() default {};\n\n    /**\n     * Application associated name\n     * @deprecated Do not set it and use the global Application Config\n     */\n    @Deprecated\n    String application() default \"\";\n\n    String module() default \"\";\n\n    String provider() default \"\";\n\n    String[] protocol() default {};\n\n    String monitor() default \"\";\n\n    String[] registry() default {};\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubbo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.core.annotation.AliasFor;\n\n@Deprecated\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\n@Documented\n@EnableDubboConfig\n@DubboComponentScan\npublic @interface EnableDubbo {\n\n    /**\n     * Base packages to scan for annotated @Service classes.\n     * <p>\n     * Use {@link #scanBasePackageClasses()} for a type-safe alternative to String-based\n     * package names.\n     *\n     * @return the base packages to scan\n     * @see DubboComponentScan#basePackages()\n     */\n    @AliasFor(annotation = DubboComponentScan.class, attribute = \"basePackages\")\n    String[] scanBasePackages() default {};\n\n    /**\n     * Type-safe alternative to {@link #scanBasePackages()} for specifying the packages to\n     * scan for annotated @Service classes. The package of each class specified will be\n     * scanned.\n     *\n     * @return classes from the base packages to scan\n     * @see DubboComponentScan#basePackageClasses\n     */\n    @AliasFor(annotation = DubboComponentScan.class, attribute = \"basePackageClasses\")\n    Class<?>[] scanBasePackageClasses() default {};\n\n    /**\n     * It indicates whether {@link AbstractConfig} binding to multiple Spring Beans.\n     *\n     * @return the default value is <code>false</code>\n     * @see EnableDubboConfig#multiple()\n     */\n    @AliasFor(annotation = EnableDubboConfig.class, attribute = \"multiple\")\n    boolean multipleConfig() default false;\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/container/page/Menu.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.container.page;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Menu\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE})\npublic @interface Menu {\n\n    String name();\n\n    String desc() default \"\";\n\n    int order() default 0;\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/container/page/MenuComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.container.page;\n\nimport java.io.Serializable;\nimport java.util.Comparator;\n\npublic class MenuComparator implements Comparator<PageHandler>, Serializable {\n\n    private static final long serialVersionUID = -3161526932904414029L;\n\n    @Override\n    public int compare(PageHandler o1, PageHandler o2) {\n        if (o1 == null && o2 == null) {\n            return 0;\n        }\n        if (o1 == null) {\n            return -1;\n        }\n        if (o2 == null) {\n            return 1;\n        }\n        return o1.equals(o2)\n                ? 0\n                : (o1.getClass().getAnnotation(Menu.class).order()\n                                > o2.getClass().getAnnotation(Menu.class).order()\n                        ? 1\n                        : -1);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/container/page/Page.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.container.page;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class Page {\n\n    private final String navigation;\n\n    private final String title;\n\n    private final List<String> columns;\n\n    private final List<List<String>> rows;\n\n    public Page(String navigation) {\n        this(navigation, (String) null, (String[]) null, (List<List<String>>) null);\n    }\n\n    public Page(String navigation, String title, String column, String row) {\n        this(\n                navigation,\n                title,\n                column == null ? null : Arrays.asList(new String[] {column}),\n                row == null ? null : stringToList(row));\n    }\n\n    public Page(String navigation, String title, String[] columns, List<List<String>> rows) {\n        this(navigation, title, columns == null ? null : Arrays.asList(columns), rows);\n    }\n\n    public Page(String navigation, String title, List<String> columns, List<List<String>> rows) {\n        this.navigation = navigation;\n        this.title = title;\n        this.columns = columns;\n        this.rows = rows;\n    }\n\n    private static List<List<String>> stringToList(String str) {\n        List<List<String>> rows = new ArrayList<>();\n        List<String> row = new ArrayList<>();\n        row.add(str);\n        rows.add(row);\n        return rows;\n    }\n\n    public String getNavigation() {\n        return navigation;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public List<String> getColumns() {\n        return columns;\n    }\n\n    public List<List<String>> getRows() {\n        return rows;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/container/page/PageHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.container.page;\n\nimport org.apache.dubbo.common.extension.SPI;\n\nimport com.alibaba.dubbo.common.URL;\n\n@SPI\npublic interface PageHandler {\n\n    /**\n     * Handle the page.\n     *\n     * @param url\n     * @return the page.\n     */\n    Page handle(URL url);\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/container/page/PageServlet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.container.page;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.alibaba.dubbo.common.Constants;\nimport com.alibaba.dubbo.common.URL;\n\npublic class PageServlet extends HttpServlet {\n\n    protected static final Logger logger = LoggerFactory.getLogger(PageServlet.class);\n    private static final long serialVersionUID = -8370312705453328501L;\n    private static PageServlet INSTANCE;\n    protected final Random random = new Random();\n    protected final Map<String, PageHandler> pages = new ConcurrentHashMap<>();\n    protected final List<PageHandler> menus = new ArrayList<>();\n\n    public static PageServlet getInstance() {\n        return INSTANCE;\n    }\n\n    public List<PageHandler> getMenus() {\n        return Collections.unmodifiableList(menus);\n    }\n\n    @Override\n    public void init() throws ServletException {\n        super.init();\n        INSTANCE = this;\n        String config = getServletConfig().getInitParameter(\"pages\");\n        Collection<String> names;\n        if (config != null && config.length() > 0) {\n            names = Arrays.asList(Constants.COMMA_SPLIT_PATTERN.split(config));\n        } else {\n            names = ExtensionLoader.getExtensionLoader(PageHandler.class).getSupportedExtensions();\n        }\n        for (String name : names) {\n            PageHandler handler =\n                    ExtensionLoader.getExtensionLoader(PageHandler.class).getExtension(name);\n            pages.put(ExtensionLoader.getExtensionLoader(PageHandler.class).getExtensionName(handler), handler);\n            Menu menu = handler.getClass().getAnnotation(Menu.class);\n            if (menu != null) {\n                menus.add(handler);\n            }\n        }\n        Collections.sort(menus, new MenuComparator());\n    }\n\n    @Override\n    protected final void doGet(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n        doPost(request, response);\n    }\n\n    @Override\n    protected final void doPost(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n        if (!response.isCommitted()) {\n            PrintWriter writer = response.getWriter();\n            String uri = request.getRequestURI();\n            boolean isHtml = false;\n            if (uri == null || uri.length() == 0 || \"/\".equals(uri)) {\n                uri = \"index\";\n                isHtml = true;\n            } else {\n                if (uri.startsWith(\"/\")) {\n                    uri = uri.substring(1);\n                }\n                if (uri.endsWith(\".html\")) {\n                    uri = uri.substring(0, uri.length() - \".html\".length());\n                    isHtml = true;\n                }\n            }\n            if (uri.endsWith(\"favicon.ico\")) {\n                response.sendError(HttpServletResponse.SC_NOT_FOUND);\n                return;\n            }\n            ExtensionLoader<PageHandler> pageHandlerLoader = ExtensionLoader.getExtensionLoader(PageHandler.class);\n            PageHandler pageHandler = pageHandlerLoader.hasExtension(uri) ? pageHandlerLoader.getExtension(uri) : null;\n            if (isHtml) {\n                writer.println(\"<html><head><title>Dubbo</title>\");\n                writer.println(\n                        \"<style type=\\\"text/css\\\">html, body {margin: 10;padding: 0;background-color: #6D838C;font-family: Arial, Verdana;font-size: 12px;color: #FFFFFF;text-align: center;vertical-align: middle;word-break: break-all; } table {width: 90%; margin: 0px auto;border-collapse: collapse;border: 8px solid #FFFFFF; } thead tr {background-color: #253c46; } tbody tr {background-color: #8da5af; } th {padding-top: 4px;padding-bottom: 4px;font-size: 14px;height: 20px; } td {margin: 3px;padding: 3px;border: 2px solid #FFFFFF;font-size: 14px;height: 25px; } a {color: #FFFFFF;cursor: pointer;text-decoration: underline; } a:hover {text-decoration: none; }</style>\");\n                writer.println(\"</head><body>\");\n            }\n            if (pageHandler != null) {\n                Page page = null;\n                try {\n                    String query = request.getQueryString();\n                    page = pageHandler.handle(\n                            URL.valueOf(request.getRequestURL().toString()\n                                    + (query == null || query.length() == 0 ? \"\" : \"?\" + query)));\n                } catch (Throwable t) {\n                    logger.warn(t.getMessage(), t);\n                    String msg = t.getMessage();\n                    if (msg == null) {\n                        msg = StringUtils.toString(t);\n                    }\n                    if (isHtml) {\n                        writer.println(\"<table>\");\n                        writer.println(\"<thead>\");\n                        writer.println(\"    <tr>\");\n                        writer.println(\"        <th>Error</th>\");\n                        writer.println(\"    </tr>\");\n                        writer.println(\"</thead>\");\n                        writer.println(\"<tbody>\");\n                        writer.println(\"    <tr>\");\n                        writer.println(\"        <td>\");\n                        writer.println(\"            \"\n                                + msg.replace(\"<\", \"&lt;\").replace(\">\", \"&lt;\").replace(\"\\n\", \"<br/>\"));\n                        writer.println(\"        </td>\");\n                        writer.println(\"    </tr>\");\n                        writer.println(\"</tbody>\");\n                        writer.println(\"</table>\");\n                        writer.println(\"<br/>\");\n                    } else {\n                        writer.println(msg);\n                    }\n                }\n                if (page != null) {\n                    if (isHtml) {\n                        String nav = page.getNavigation();\n                        if (nav == null || nav.length() == 0) {\n                            nav = ExtensionLoader.getExtensionLoader(PageHandler.class)\n                                    .getExtensionName(pageHandler);\n                            nav = nav.substring(0, 1).toUpperCase() + nav.substring(1);\n                        }\n                        if (!\"index\".equals(uri)) {\n                            nav = \"<a href=\\\"/\\\">Home</a> &gt; \" + nav;\n                        }\n                        writeMenu(request, writer, nav);\n                        writeTable(writer, page.getTitle(), page.getColumns(), page.getRows());\n                    } else {\n                        if (page.getRows().size() > 0 && page.getRows().get(0).size() > 0) {\n                            writer.println(page.getRows().get(0).get(0));\n                        }\n                    }\n                }\n            } else {\n                if (isHtml) {\n                    writer.println(\"<table>\");\n                    writer.println(\"<thead>\");\n                    writer.println(\"    <tr>\");\n                    writer.println(\"        <th>Error</th>\");\n                    writer.println(\"    </tr>\");\n                    writer.println(\"</thead>\");\n                    writer.println(\"<tbody>\");\n                    writer.println(\"    <tr>\");\n                    writer.println(\"        <td>\");\n                    writer.println(\"            Not found \" + uri + \" page. Please goto <a href=\\\"/\\\">Home</a> page.\");\n                    writer.println(\"        </td>\");\n                    writer.println(\"    </tr>\");\n                    writer.println(\"</tbody>\");\n                    writer.println(\"</table>\");\n                    writer.println(\"<br/>\");\n                } else {\n                    writer.println(\"Not found \" + uri + \" page.\");\n                }\n            }\n            if (isHtml) {\n                writer.println(\"</body></html>\");\n            }\n            writer.flush();\n        }\n    }\n\n    protected final void writeMenu(HttpServletRequest request, PrintWriter writer, String nav) {\n        writer.println(\"<table>\");\n        writer.println(\"<thead>\");\n        writer.println(\"    <tr>\");\n        for (PageHandler handler : menus) {\n            String uri = ExtensionLoader.getExtensionLoader(PageHandler.class).getExtensionName(handler);\n            Menu menu = handler.getClass().getAnnotation(Menu.class);\n            writer.println(\"        <th><a href=\\\"\" + uri + \".html\\\">\" + menu.name() + \"</a></th>\");\n        }\n        writer.println(\"    </tr>\");\n        writer.println(\"</thead>\");\n        writer.println(\"<tbody>\");\n        writer.println(\"    <tr>\");\n        writer.println(\"        <td style=\\\"text-align: left\\\" colspan=\\\"\" + menus.size() + \"\\\">\");\n        writer.println(nav);\n        writer.println(\"        </td>\");\n        writer.println(\"    </tr>\");\n        writer.println(\"</tbody>\");\n        writer.println(\"</table>\");\n        writer.println(\"<br/>\");\n    }\n\n    protected final void writeTable(PrintWriter writer, String title, List<String> columns, List<List<String>> rows) {\n        int n = random.nextInt();\n        int c = (columns == null\n                ? (rows == null || rows.size() == 0 ? 0 : rows.get(0).size())\n                : columns.size());\n        int r = (rows == null ? 0 : rows.size());\n        writer.println(\"<table>\");\n        writer.println(\"<thead>\");\n        writer.println(\"    <tr>\");\n        writer.println(\"        <th colspan=\\\"\" + c + \"\\\">\" + title + \"</th>\");\n        writer.println(\"    </tr>\");\n        if (columns != null && columns.size() > 0) {\n            writer.println(\"    <tr>\");\n            for (int i = 0; i < columns.size(); i++) {\n                String col = columns.get(i);\n                if (col.endsWith(\":\")) {\n                    col += \" <input type=\\\"text\\\" id=\\\"in_\"\n                            + n\n                            + \"_\"\n                            + i\n                            + \"\\\" onkeyup=\\\"for (var i = 0; i < \"\n                            + r\n                            + \"; i ++) { var m = true; for (var j = 0; j < \"\n                            + columns.size()\n                            + \"; j ++) { if (document.getElementById('in_\"\n                            + n\n                            + \"_' + j)) { var iv = document.getElementById('in_\"\n                            + n\n                            + \"_' + j).value; var tv = document.getElementById('td_\"\n                            + n\n                            + \"_' + i + '_' + j).innerHTML; if (iv.length > 0 && (tv.length < iv.length || tv.indexOf(iv) == -1)) { m = false; break; } } } document.getElementById('tr_\"\n                            + n\n                            + \"_' + i).style.display = (m ? '' : 'none');}\\\" style=\\\"width: 100%\\\" />\";\n                }\n                writer.println(\"        <td>\" + col + \"</td>\");\n            }\n            writer.println(\"    </tr>\");\n        }\n        writer.println(\"</thead>\");\n        if (rows != null && rows.size() > 0) {\n            writer.println(\"<tbody>\");\n            int i = 0;\n            for (Collection<String> row : rows) {\n                writer.println(\"    <tr id=\\\"tr_\" + n + \"_\" + i + \"\\\">\");\n                int j = 0;\n                for (String col : row) {\n                    writer.println(\"        <td id=\\\"td_\" + n + \"_\" + i + \"_\" + j + \"\\\" style=\\\"display: ;\\\">\" + col\n                            + \"</td>\");\n                    j++;\n                }\n                writer.println(\"    </tr>\");\n                i++;\n            }\n            writer.println(\"</tbody>\");\n        }\n        writer.println(\"</table>\");\n        writer.println(\"<br/>\");\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/container/page/ResourceFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.container.page;\n\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.alibaba.dubbo.common.Constants;\n\npublic class ResourceFilter implements Filter {\n\n    private static final String CLASSPATH_PREFIX = \"classpath:\";\n\n    private final long start = System.currentTimeMillis();\n\n    private final List<String> resources = new ArrayList<>();\n\n    public void init(FilterConfig filterConfig) throws ServletException {\n        String config = filterConfig.getInitParameter(\"resources\");\n        if (config != null && config.length() > 0) {\n            String[] configs = Constants.COMMA_SPLIT_PATTERN.split(config);\n            for (String c : configs) {\n                if (c != null && c.length() > 0) {\n                    c = c.replace('\\\\', '/');\n                    if (c.endsWith(\"/\")) {\n                        c = c.substring(0, c.length() - 1);\n                    }\n                    resources.add(c);\n                }\n            }\n        }\n    }\n\n    public void destroy() {}\n\n    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)\n            throws IOException, ServletException {\n        HttpServletRequest request = (HttpServletRequest) req;\n        HttpServletResponse response = (HttpServletResponse) res;\n        if (response.isCommitted()) {\n            return;\n        }\n        String uri = request.getRequestURI();\n        String context = request.getContextPath();\n        if (uri.endsWith(\"/favicon.ico\")) {\n            uri = \"/favicon.ico\";\n        } else if (context != null && !\"/\".equals(context)) {\n            uri = uri.substring(context.length());\n        }\n        if (!uri.startsWith(\"/\")) {\n            uri = \"/\" + uri;\n        }\n        long lastModified = getLastModified(uri);\n        long since = request.getDateHeader(\"If-Modified-Since\");\n        if (since >= lastModified) {\n            response.sendError(HttpServletResponse.SC_NOT_MODIFIED);\n            return;\n        }\n        byte[] data;\n        InputStream input = getInputStream(uri);\n        if (input == null) {\n            chain.doFilter(req, res);\n            return;\n        }\n        try {\n            ByteArrayOutputStream output = new ByteArrayOutputStream();\n            byte[] buffer = new byte[8192];\n            int n = 0;\n            while (-1 != (n = input.read(buffer))) {\n                output.write(buffer, 0, n);\n            }\n            data = output.toByteArray();\n        } finally {\n            input.close();\n        }\n        response.setDateHeader(\"Last-Modified\", lastModified);\n        OutputStream output = response.getOutputStream();\n        output.write(data);\n        output.flush();\n    }\n\n    private boolean isFile(String path) {\n        return path.startsWith(\"/\") || path.indexOf(\":\") <= 1;\n    }\n\n    private long getLastModified(String uri) {\n        for (String resource : resources) {\n            if (resource != null && resource.length() > 0) {\n                String path = resource + uri;\n                if (isFile(path)) {\n                    File file = new File(path);\n                    if (file.exists()) {\n                        return file.lastModified();\n                    }\n                }\n            }\n        }\n        return start;\n    }\n\n    private InputStream getInputStream(String uri) {\n        for (String resource : resources) {\n            String path = resource + uri;\n            try {\n                if (isFile(path)) {\n                    return new FileInputStream(path);\n                } else if (path.startsWith(CLASSPATH_PREFIX)) {\n                    return Thread.currentThread()\n                            .getContextClassLoader()\n                            .getResourceAsStream(path.substring(CLASSPATH_PREFIX.length()));\n                } else {\n                    return new URL(path).openStream();\n                }\n            } catch (IOException e) {\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/container/page/pages/HomePageHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.container.page.pages;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.container.page.Menu;\nimport com.alibaba.dubbo.container.page.Page;\nimport com.alibaba.dubbo.container.page.PageHandler;\nimport com.alibaba.dubbo.container.page.PageServlet;\n\n@Menu(name = \"Home\", desc = \"Home page.\", order = Integer.MIN_VALUE)\npublic class HomePageHandler implements PageHandler {\n\n    @Override\n    public Page handle(URL url) {\n        List<List<String>> rows = new ArrayList<>();\n        for (PageHandler handler : PageServlet.getInstance().getMenus()) {\n            String uri = ExtensionLoader.getExtensionLoader(PageHandler.class).getExtensionName(handler);\n            Menu menu = handler.getClass().getAnnotation(Menu.class);\n            List<String> row = new ArrayList<>();\n            row.add(\"<a href=\\\"\" + uri + \".html\\\">\" + menu.name() + \"</a>\");\n            row.add(menu.desc());\n            rows.add(row);\n        }\n        return new Page(\"Home\", \"Menus\", new String[] {\"Menu Name\", \"Menu Desc\"}, rows);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/container/page/pages/LogPageHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.container.page.pages;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.Enumeration;\nimport java.util.List;\n\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.container.page.Menu;\nimport com.alibaba.dubbo.container.page.Page;\nimport com.alibaba.dubbo.container.page.PageHandler;\nimport org.apache.log4j.Appender;\nimport org.apache.log4j.FileAppender;\nimport org.apache.log4j.Level;\nimport org.apache.log4j.LogManager;\n\n@Menu(name = \"Log\", desc = \"Show system log.\", order = Integer.MAX_VALUE - 11000)\npublic class LogPageHandler implements PageHandler {\n\n    private static final int SHOW_LOG_LENGTH = 30000;\n\n    private File file;\n\n    @SuppressWarnings(\"unchecked\")\n    public LogPageHandler() {\n        try {\n            org.apache.log4j.Logger logger = LogManager.getRootLogger();\n            if (logger != null) {\n                Enumeration<Appender> appenders = logger.getAllAppenders();\n                if (appenders != null) {\n                    while (appenders.hasMoreElements()) {\n                        Appender appender = appenders.nextElement();\n                        if (appender instanceof FileAppender) {\n                            FileAppender fileAppender = (FileAppender) appender;\n                            String filename = fileAppender.getFile();\n                            file = new File(filename);\n                            break;\n                        }\n                    }\n                }\n            }\n        } catch (Throwable t) {\n        }\n    }\n\n    @Override\n    public Page handle(URL url) {\n        long size = 0;\n        String content = \"\";\n        String modified = \"Not exist\";\n        if (file != null && file.exists()) {\n            try {\n                FileInputStream fis = new FileInputStream(file);\n                FileChannel channel = fis.getChannel();\n                size = channel.size();\n                ByteBuffer bb;\n                if (size <= SHOW_LOG_LENGTH) {\n                    bb = ByteBuffer.allocate((int) size);\n                    channel.read(bb, 0);\n                } else {\n                    int pos = (int) (size - SHOW_LOG_LENGTH);\n                    bb = ByteBuffer.allocate(SHOW_LOG_LENGTH);\n                    channel.read(bb, pos);\n                }\n                bb.flip();\n                content = new String(bb.array())\n                        .replace(\"<\", \"&lt;\")\n                        .replace(\">\", \"&gt;\")\n                        .replace(\"\\n\", \"<br/><br/>\");\n                modified = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\").format(new Date(file.lastModified()));\n            } catch (IOException e) {\n            }\n        }\n        Level level = LogManager.getRootLogger().getLevel();\n        List<List<String>> rows = new ArrayList<>();\n        List<String> row = new ArrayList<>();\n        row.add(content);\n        rows.add(row);\n        return new Page(\n                \"Log\",\n                \"Log\",\n                new String[] {(file == null ? \"\" : file.getName()) + \", \" + size + \" bytes, \" + modified + \", \" + level\n                },\n                rows);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/container/page/pages/StatusPageHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.container.page.pages;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.status.Status;\nimport org.apache.dubbo.common.status.support.StatusUtils;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.common.status.StatusChecker;\nimport com.alibaba.dubbo.container.page.Menu;\nimport com.alibaba.dubbo.container.page.Page;\nimport com.alibaba.dubbo.container.page.PageHandler;\n\n@Menu(name = \"Status\", desc = \"Show system status.\", order = Integer.MAX_VALUE - 12000)\npublic class StatusPageHandler implements PageHandler {\n\n    @Override\n    public Page handle(URL url) {\n        List<List<String>> rows = new ArrayList<>();\n        Set<String> names =\n                ExtensionLoader.getExtensionLoader(StatusChecker.class).getSupportedExtensions();\n        Map<String, Status> statuses = new HashMap<>();\n        for (String name : names) {\n            StatusChecker checker =\n                    ExtensionLoader.getExtensionLoader(StatusChecker.class).getExtension(name);\n            List<String> row = new ArrayList<>();\n            row.add(name);\n            Status status = checker.check();\n            if (status != null && !Status.Level.UNKNOWN.equals(status.getLevel())) {\n                statuses.put(name, status);\n                row.add(getLevelHtml(status.getLevel()));\n                row.add(status.getMessage());\n                rows.add(row);\n            }\n        }\n        Status status = StatusUtils.getSummaryStatus(statuses);\n        if (\"status\".equals(url.getPath())) {\n            return new Page(\"\", \"\", \"\", status.getLevel().toString());\n        } else {\n            List<String> row = new ArrayList<>();\n            row.add(\"summary\");\n            row.add(getLevelHtml(status.getLevel()));\n            row.add(\"<a href=\\\"/status\\\" target=\\\"_blank\\\">summary</a>\");\n            rows.add(row);\n            return new Page(\n                    \"Status (<a href=\\\"/status\\\" target=\\\"_blank\\\">summary</a>)\",\n                    \"Status\",\n                    new String[] {\"Name\", \"Status\", \"Description\"},\n                    rows);\n        }\n    }\n\n    private String getLevelHtml(Status.Level level) {\n        return \"<font color=\\\"\" + getLevelColor(level) + \"\\\">\" + level.name() + \"</font>\";\n    }\n\n    private String getLevelColor(Status.Level level) {\n        if (level == Status.Level.OK) {\n            return \"green\";\n        } else if (level == Status.Level.ERROR) {\n            return \"red\";\n        } else if (level == Status.Level.WARN) {\n            return \"yellow\";\n        }\n        return \"gray\";\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/container/page/pages/SystemPageHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.container.page.pages;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.lang.management.ManagementFactory;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\n\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.container.page.Menu;\nimport com.alibaba.dubbo.container.page.Page;\nimport com.alibaba.dubbo.container.page.PageHandler;\n\n@Menu(name = \"System\", desc = \"Show system environment information.\", order = Integer.MAX_VALUE - 10000)\npublic class SystemPageHandler implements PageHandler {\n\n    private static final long SECOND = 1000;\n    private static final long MINUTE = 60 * SECOND;\n    private static final long HOUR = 60 * MINUTE;\n    private static final long DAY = 24 * HOUR;\n\n    @Override\n    public Page handle(URL url) {\n        List<List<String>> rows = new ArrayList<>();\n        List<String> row;\n\n        row = new ArrayList<>();\n        row.add(\"Version\");\n        row.add(Version.getVersion(SystemPageHandler.class, \"2.0.0\"));\n        rows.add(row);\n\n        row = new ArrayList<>();\n        row.add(\"Host\");\n        String address = NetUtils.getLocalHost();\n        row.add(NetUtils.getHostName(address) + \"/\" + address);\n        rows.add(row);\n\n        row = new ArrayList<>();\n        row.add(\"OS\");\n        row.add(SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.SYSTEM_OS_NAME) + \" \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.SYSTEM_OS_VERSION));\n        rows.add(row);\n\n        row = new ArrayList<>();\n        row.add(\"JVM\");\n        row.add(SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_RUNTIME_NAME) + \" \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_RUNTIME_VERSION)\n                + \",<br/>\"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_VM_NAME) + \" \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_VM_VERSION) + \" \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_VM_INFO, \"\"));\n        rows.add(row);\n\n        row = new ArrayList<>();\n        row.add(\"CPU\");\n        row.add(SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.OS_ARCH, \"\") + \", \"\n                + String.valueOf(Runtime.getRuntime().availableProcessors()) + \" cores\");\n        rows.add(row);\n\n        row = new ArrayList<>();\n        row.add(\"Locale\");\n        row.add(Locale.getDefault().toString() + \"/\"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.SYSTEM_FILE_ENCODING));\n        rows.add(row);\n\n        row = new ArrayList<>();\n        row.add(\"Uptime\");\n        row.add(formatUptime(ManagementFactory.getRuntimeMXBean().getUptime()));\n        rows.add(row);\n\n        row = new ArrayList<>();\n        row.add(\"Time\");\n        row.add(new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS Z\").format(new Date()));\n        rows.add(row);\n\n        return new Page(\"System\", \"System\", new String[] {\"Property\", \"Value\"}, rows);\n    }\n\n    private String formatUptime(long uptime) {\n        StringBuilder buf = new StringBuilder();\n        if (uptime > DAY) {\n            long days = (uptime - uptime % DAY) / DAY;\n            buf.append(days);\n            buf.append(\" Days\");\n            uptime = uptime % DAY;\n        }\n        if (uptime > HOUR) {\n            long hours = (uptime - uptime % HOUR) / HOUR;\n            if (buf.length() > 0) {\n                buf.append(\", \");\n            }\n            buf.append(hours);\n            buf.append(\" Hours\");\n            uptime = uptime % HOUR;\n        }\n        if (uptime > MINUTE) {\n            long minutes = (uptime - uptime % MINUTE) / MINUTE;\n            if (buf.length() > 0) {\n                buf.append(\", \");\n            }\n            buf.append(minutes);\n            buf.append(\" Minutes\");\n            uptime = uptime % MINUTE;\n        }\n        if (uptime > SECOND) {\n            long seconds = (uptime - uptime % SECOND) / SECOND;\n            if (buf.length() > 0) {\n                buf.append(\", \");\n            }\n            buf.append(seconds);\n            buf.append(\" Seconds\");\n            uptime = uptime % SECOND;\n        }\n        if (uptime > 0) {\n            if (buf.length() > 0) {\n                buf.append(\", \");\n            }\n            buf.append(uptime);\n            buf.append(\" Milliseconds\");\n        }\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/monitor/Monitor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.monitor;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n@Deprecated\npublic interface Monitor extends org.apache.dubbo.monitor.Monitor {\n\n    @Override\n    com.alibaba.dubbo.common.URL getUrl();\n\n    void collect(com.alibaba.dubbo.common.URL statistics);\n\n    List<com.alibaba.dubbo.common.URL> lookup(com.alibaba.dubbo.common.URL query);\n\n    @Override\n    default void collect(URL statistics) {\n        this.collect(new com.alibaba.dubbo.common.DelegateURL(statistics));\n    }\n\n    @Override\n    default List<URL> lookup(URL query) {\n        return this.lookup(new com.alibaba.dubbo.common.DelegateURL(query)).stream()\n                .map(url -> url.getOriginalURL())\n                .collect(Collectors.toList());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/monitor/MonitorFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.monitor;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.monitor.Monitor;\n\n@Deprecated\npublic interface MonitorFactory extends org.apache.dubbo.monitor.MonitorFactory {\n\n    com.alibaba.dubbo.monitor.Monitor getMonitor(com.alibaba.dubbo.common.URL url);\n\n    @Override\n    default Monitor getMonitor(URL url) {\n        return this.getMonitor(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/qos/command/BaseCommand.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.qos.command;\n\nimport org.apache.dubbo.qos.api.CommandContext;\n\n@Deprecated\npublic interface BaseCommand extends org.apache.dubbo.qos.api.BaseCommand {\n\n    String execute(com.alibaba.dubbo.qos.command.CommandContext commandContext, String[] args);\n\n    @Override\n    default String execute(CommandContext commandContext, String[] args) {\n        return this.execute(new com.alibaba.dubbo.qos.command.CommandContext(commandContext), args);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/qos/command/CommandContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.qos.command;\n\n@Deprecated\npublic class CommandContext extends org.apache.dubbo.qos.api.CommandContext {\n\n    public CommandContext(org.apache.dubbo.qos.api.CommandContext context) {\n        super(context.getCommandName(), context.getArgs(), context.isHttp());\n        setRemote(context.getRemote());\n        setOriginRequest(context.getOriginRequest());\n    }\n\n    public CommandContext(String commandName) {\n        super(commandName);\n    }\n\n    public CommandContext(String commandName, String[] args, boolean isHttp) {\n        super(commandName, args, isHttp);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/registry/NotifyListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.registry;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.dubbo.common.DelegateURL;\nimport com.alibaba.dubbo.common.URL;\n\n@Deprecated\npublic interface NotifyListener {\n\n    void notify(List<URL> urls);\n\n    class CompatibleNotifyListener implements NotifyListener {\n\n        private org.apache.dubbo.registry.NotifyListener listener;\n\n        public CompatibleNotifyListener(org.apache.dubbo.registry.NotifyListener listener) {\n            this.listener = listener;\n        }\n\n        @Override\n        public void notify(List<URL> urls) {\n            if (listener != null) {\n                listener.notify(urls.stream().map(url -> url.getOriginalURL()).collect(Collectors.toList()));\n            }\n        }\n    }\n\n    class ReverseCompatibleNotifyListener implements org.apache.dubbo.registry.NotifyListener {\n\n        private NotifyListener listener;\n\n        public ReverseCompatibleNotifyListener(NotifyListener listener) {\n            this.listener = listener;\n        }\n\n        @Override\n        public void notify(List<org.apache.dubbo.common.URL> urls) {\n            if (listener != null) {\n                listener.notify(urls.stream().map(url -> new DelegateURL(url)).collect(Collectors.toList()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/registry/Registry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.NotifyListener;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n@Deprecated\npublic interface Registry extends org.apache.dubbo.registry.Registry {\n\n    @Override\n    com.alibaba.dubbo.common.URL getUrl();\n\n    void register(com.alibaba.dubbo.common.URL url);\n\n    void unregister(com.alibaba.dubbo.common.URL url);\n\n    void subscribe(com.alibaba.dubbo.common.URL url, com.alibaba.dubbo.registry.NotifyListener listener);\n\n    void unsubscribe(com.alibaba.dubbo.common.URL url, com.alibaba.dubbo.registry.NotifyListener listener);\n\n    List<com.alibaba.dubbo.common.URL> lookup(com.alibaba.dubbo.common.URL url);\n\n    @Override\n    default void register(URL url) {\n        this.register(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n\n    @Override\n    default void unregister(URL url) {\n        this.unregister(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n\n    @Override\n    default void subscribe(URL url, NotifyListener listener) {\n        this.subscribe(\n                new com.alibaba.dubbo.common.DelegateURL(url),\n                new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener));\n    }\n\n    @Override\n    default void unsubscribe(URL url, NotifyListener listener) {\n        this.unsubscribe(\n                new com.alibaba.dubbo.common.DelegateURL(url),\n                new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener));\n    }\n\n    @Override\n    default List<URL> lookup(URL url) {\n        return this.lookup(new com.alibaba.dubbo.common.DelegateURL(url)).stream()\n                .map(u -> u.getOriginalURL())\n                .collect(Collectors.toList());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/registry/RegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.Registry;\n\n@Deprecated\npublic interface RegistryFactory extends org.apache.dubbo.registry.RegistryFactory {\n\n    com.alibaba.dubbo.registry.Registry getRegistry(com.alibaba.dubbo.common.URL url);\n\n    @Override\n    default Registry getRegistry(URL url) {\n        return this.getRegistry(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n * 2019-04-16\n */\n@Deprecated\npublic abstract class AbstractRegistry implements Registry {\n\n    private CompatibleAbstractRegistry abstractRegistry;\n\n    public AbstractRegistry(com.alibaba.dubbo.common.URL url) {\n        abstractRegistry = new CompatibleAbstractRegistry(url.getOriginalURL());\n    }\n\n    @Override\n    public com.alibaba.dubbo.common.URL getUrl() {\n        return new com.alibaba.dubbo.common.DelegateURL(abstractRegistry.getUrl());\n    }\n\n    protected void setUrl(com.alibaba.dubbo.common.URL url) {\n        abstractRegistry.setUrl(url.getOriginalURL());\n    }\n\n    public Set<com.alibaba.dubbo.common.URL> getRegistered() {\n        return abstractRegistry.getRegistered().stream()\n                .map(url -> new com.alibaba.dubbo.common.DelegateURL(url))\n                .collect(Collectors.toSet());\n    }\n\n    public Map<com.alibaba.dubbo.common.URL, Set<com.alibaba.dubbo.registry.NotifyListener>> getSubscribed() {\n        return abstractRegistry.getSubscribed().entrySet().stream()\n                .collect(Collectors.toMap(\n                        entry -> new com.alibaba.dubbo.common.DelegateURL(entry.getKey()),\n                        entry -> convertToNotifyListeners(entry.getValue())));\n    }\n\n    public Map<com.alibaba.dubbo.common.URL, Map<String, List<com.alibaba.dubbo.common.URL>>> getNotified() {\n        return abstractRegistry.getNotified().entrySet().stream()\n                .collect(Collectors.toMap(entry -> new com.alibaba.dubbo.common.DelegateURL(entry.getKey()), entry -> {\n                    return entry.getValue().entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> {\n                        return e.getValue().stream()\n                                .map(url -> new com.alibaba.dubbo.common.DelegateURL(url))\n                                .collect(Collectors.toList());\n                    }));\n                }));\n    }\n\n    public List<com.alibaba.dubbo.common.URL> getCacheUrls(com.alibaba.dubbo.common.URL url) {\n        return abstractRegistry.lookup(url.getOriginalURL()).stream()\n                .map(tmpUrl -> new com.alibaba.dubbo.common.DelegateURL(tmpUrl))\n                .collect(Collectors.toList());\n    }\n\n    public List<com.alibaba.dubbo.common.URL> lookup(com.alibaba.dubbo.common.URL url) {\n        return abstractRegistry.lookup(url.getOriginalURL()).stream()\n                .map(tmpUrl -> new com.alibaba.dubbo.common.DelegateURL(tmpUrl))\n                .collect(Collectors.toList());\n    }\n\n    protected void notify(\n            com.alibaba.dubbo.common.URL url,\n            com.alibaba.dubbo.registry.NotifyListener listener,\n            List<com.alibaba.dubbo.common.URL> urls) {\n        abstractRegistry.notify(\n                url.getOriginalURL(),\n                new com.alibaba.dubbo.registry.NotifyListener.ReverseCompatibleNotifyListener(listener),\n                urls.stream().map(tmpUrl -> tmpUrl.getOriginalURL()).collect(Collectors.toList()));\n    }\n\n    public void register(com.alibaba.dubbo.common.URL url) {\n        abstractRegistry.register(url.getOriginalURL());\n    }\n\n    public void unregister(com.alibaba.dubbo.common.URL url) {\n        abstractRegistry.unregister(url.getOriginalURL());\n    }\n\n    public void subscribe(com.alibaba.dubbo.common.URL url, com.alibaba.dubbo.registry.NotifyListener listener) {\n        abstractRegistry.subscribe(\n                url.getOriginalURL(),\n                new com.alibaba.dubbo.registry.NotifyListener.ReverseCompatibleNotifyListener(listener));\n    }\n\n    public void unsubscribe(com.alibaba.dubbo.common.URL url, com.alibaba.dubbo.registry.NotifyListener listener) {\n        abstractRegistry.unsubscribe(\n                url.getOriginalURL(),\n                new com.alibaba.dubbo.registry.NotifyListener.ReverseCompatibleNotifyListener(listener));\n    }\n\n    @Override\n    public void register(URL url) {\n        this.register(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n\n    @Override\n    public void unregister(URL url) {\n        this.unregister(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        this.subscribe(\n                new com.alibaba.dubbo.common.DelegateURL(url),\n                new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener));\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        this.unsubscribe(\n                new com.alibaba.dubbo.common.DelegateURL(url),\n                new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener));\n    }\n\n    final Set<com.alibaba.dubbo.registry.NotifyListener> convertToNotifyListeners(Set<NotifyListener> notifyListeners) {\n        return notifyListeners.stream()\n                .map(listener -> new com.alibaba.dubbo.registry.NotifyListener.CompatibleNotifyListener(listener))\n                .collect(Collectors.toSet());\n    }\n\n    static class CompatibleAbstractRegistry extends org.apache.dubbo.registry.support.AbstractRegistry {\n        public CompatibleAbstractRegistry(URL url) {\n            super(url);\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return false;\n        }\n\n        @Override\n        public void notify(URL url, NotifyListener listener, List<URL> urls) {\n            super.notify(url, listener, urls);\n        }\n\n        @Override\n        public void setUrl(URL url) {\n            super.setUrl(url);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/registry/support/AbstractRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.Registry;\n\nimport com.alibaba.dubbo.registry.RegistryFactory;\n\n/**\n * 2019-04-16\n */\n@Deprecated\npublic abstract class AbstractRegistryFactory extends org.apache.dubbo.registry.support.AbstractRegistryFactory\n        implements RegistryFactory {\n\n    @Override\n    public com.alibaba.dubbo.registry.Registry getRegistry(com.alibaba.dubbo.common.URL url) {\n        return (com.alibaba.dubbo.registry.Registry) super.getRegistry(url.getOriginalURL());\n    }\n\n    protected abstract com.alibaba.dubbo.registry.Registry createRegistry(com.alibaba.dubbo.common.URL url);\n\n    @Override\n    protected Registry createRegistry(URL url) {\n        return createRegistry(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/registry/support/FailbackRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.registry.support;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.dubbo.common.DelegateURL;\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.registry.NotifyListener;\nimport com.alibaba.dubbo.registry.Registry;\n\n/**\n * 2019-04-17\n */\n@Deprecated\npublic abstract class FailbackRegistry implements org.apache.dubbo.registry.Registry, Registry {\n\n    private CompatibleFailbackRegistry failbackRegistry;\n\n    public FailbackRegistry(URL url) {\n        failbackRegistry = new CompatibleFailbackRegistry(url.getOriginalURL(), this);\n    }\n\n    public void removeFailedRegisteredTask(URL url) {\n        failbackRegistry.removeFailedRegisteredTask(url.getOriginalURL());\n    }\n\n    public void removeFailedUnregisteredTask(URL url) {\n        failbackRegistry.removeFailedUnregisteredTask(url.getOriginalURL());\n    }\n\n    public void removeFailedSubscribedTask(URL url, NotifyListener listener) {\n        failbackRegistry.removeFailedSubscribedTask(\n                url.getOriginalURL(), new NotifyListener.ReverseCompatibleNotifyListener(listener));\n    }\n\n    public void removeFailedUnsubscribedTask(URL url, NotifyListener listener) {\n        failbackRegistry.removeFailedUnsubscribedTask(\n                url.getOriginalURL(), new NotifyListener.ReverseCompatibleNotifyListener(listener));\n    }\n\n    @Override\n    public void register(URL url) {\n        failbackRegistry.register(url.getOriginalURL());\n    }\n\n    @Override\n    public void unregister(URL url) {\n        failbackRegistry.unregister(url.getOriginalURL());\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        failbackRegistry.subscribe(\n                url.getOriginalURL(),\n                new com.alibaba.dubbo.registry.NotifyListener.ReverseCompatibleNotifyListener(listener));\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        failbackRegistry.unsubscribe(\n                url.getOriginalURL(),\n                new com.alibaba.dubbo.registry.NotifyListener.ReverseCompatibleNotifyListener(listener));\n    }\n\n    protected void notify(URL url, NotifyListener listener, List<URL> urls) {\n        List<org.apache.dubbo.common.URL> urlResult =\n                urls.stream().map(URL::getOriginalURL).collect(Collectors.toList());\n        failbackRegistry.notify(\n                url.getOriginalURL(),\n                new com.alibaba.dubbo.registry.NotifyListener.ReverseCompatibleNotifyListener(listener),\n                urlResult);\n    }\n\n    protected void doNotify(URL url, NotifyListener listener, List<URL> urls) {\n        List<org.apache.dubbo.common.URL> urlResult =\n                urls.stream().map(URL::getOriginalURL).collect(Collectors.toList());\n        failbackRegistry.doNotify(\n                url.getOriginalURL(),\n                new com.alibaba.dubbo.registry.NotifyListener.ReverseCompatibleNotifyListener(listener),\n                urlResult);\n    }\n\n    protected void recover() throws Exception {\n        failbackRegistry.recover();\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        return failbackRegistry.lookup(url.getOriginalURL()).stream()\n                .map(e -> new DelegateURL(e))\n                .collect(Collectors.toList());\n    }\n\n    @Override\n    public URL getUrl() {\n        return new DelegateURL(failbackRegistry.getUrl());\n    }\n\n    @Override\n    public void destroy() {\n        failbackRegistry.destroy();\n    }\n\n    // ==== Template method ====\n\n    public abstract void doRegister(URL url);\n\n    public abstract void doUnregister(URL url);\n\n    public abstract void doSubscribe(URL url, NotifyListener listener);\n\n    public abstract void doUnsubscribe(URL url, NotifyListener listener);\n\n    @Override\n    public void register(org.apache.dubbo.common.URL url) {\n        this.register(new DelegateURL(url));\n    }\n\n    @Override\n    public void unregister(org.apache.dubbo.common.URL url) {\n        this.unregister(new DelegateURL(url));\n    }\n\n    @Override\n    public void subscribe(org.apache.dubbo.common.URL url, org.apache.dubbo.registry.NotifyListener listener) {\n        this.subscribe(new DelegateURL(url), new NotifyListener.CompatibleNotifyListener(listener));\n    }\n\n    @Override\n    public void unsubscribe(org.apache.dubbo.common.URL url, org.apache.dubbo.registry.NotifyListener listener) {\n        this.unsubscribe(new DelegateURL(url), new NotifyListener.CompatibleNotifyListener(listener));\n    }\n\n    @Override\n    public List<org.apache.dubbo.common.URL> lookup(org.apache.dubbo.common.URL url) {\n        return failbackRegistry.lookup(url);\n    }\n\n    static class CompatibleFailbackRegistry extends org.apache.dubbo.registry.support.FailbackRegistry {\n\n        private FailbackRegistry compatibleFailbackRegistry;\n\n        public CompatibleFailbackRegistry(\n                org.apache.dubbo.common.URL url, FailbackRegistry compatibleFailbackRegistry) {\n            super(url);\n            this.compatibleFailbackRegistry = compatibleFailbackRegistry;\n        }\n\n        @Override\n        public void doRegister(org.apache.dubbo.common.URL url) {\n            this.compatibleFailbackRegistry.doRegister(new DelegateURL(url));\n        }\n\n        @Override\n        public void doUnregister(org.apache.dubbo.common.URL url) {\n            this.compatibleFailbackRegistry.doUnregister(new DelegateURL(url));\n        }\n\n        @Override\n        public void doSubscribe(org.apache.dubbo.common.URL url, org.apache.dubbo.registry.NotifyListener listener) {\n            this.compatibleFailbackRegistry.doSubscribe(\n                    new DelegateURL(url), new NotifyListener.CompatibleNotifyListener(listener));\n        }\n\n        @Override\n        public void doUnsubscribe(org.apache.dubbo.common.URL url, org.apache.dubbo.registry.NotifyListener listener) {\n            this.compatibleFailbackRegistry.doUnsubscribe(\n                    new DelegateURL(url), new NotifyListener.CompatibleNotifyListener(listener));\n        }\n\n        @Override\n        public void notify(\n                org.apache.dubbo.common.URL url,\n                org.apache.dubbo.registry.NotifyListener listener,\n                List<org.apache.dubbo.common.URL> urls) {\n            super.notify(url, listener, urls);\n        }\n\n        @Override\n        public void doNotify(\n                org.apache.dubbo.common.URL url,\n                org.apache.dubbo.registry.NotifyListener listener,\n                List<org.apache.dubbo.common.URL> urls) {\n            super.doNotify(url, listener, urls);\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return false;\n        }\n\n        @Override\n        public void recover() throws Exception {\n            super.recover();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/Channel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting;\n\n@Deprecated\npublic interface Channel extends org.apache.dubbo.remoting.Channel {\n\n    @Override\n    com.alibaba.dubbo.common.URL getUrl();\n\n    @Override\n    com.alibaba.dubbo.remoting.ChannelHandler getChannelHandler();\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/ChannelHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\n\n@Deprecated\npublic interface ChannelHandler extends org.apache.dubbo.remoting.ChannelHandler {\n\n    void connected(com.alibaba.dubbo.remoting.Channel channel) throws com.alibaba.dubbo.remoting.RemotingException;\n\n    void disconnected(com.alibaba.dubbo.remoting.Channel channel) throws com.alibaba.dubbo.remoting.RemotingException;\n\n    void sent(com.alibaba.dubbo.remoting.Channel channel, Object message)\n            throws com.alibaba.dubbo.remoting.RemotingException;\n\n    void received(com.alibaba.dubbo.remoting.Channel channel, Object message)\n            throws com.alibaba.dubbo.remoting.RemotingException;\n\n    void caught(com.alibaba.dubbo.remoting.Channel channel, Throwable exception)\n            throws com.alibaba.dubbo.remoting.RemotingException;\n\n    @Override\n    default void connected(Channel channel) throws RemotingException {}\n\n    @Override\n    default void disconnected(Channel channel) throws RemotingException {}\n\n    @Override\n    default void sent(Channel channel, Object message) throws RemotingException {}\n\n    @Override\n    default void received(Channel channel, Object message) throws RemotingException {}\n\n    @Override\n    default void caught(Channel channel, Throwable exception) throws RemotingException {}\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/Codec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting;\n\n@Deprecated\npublic interface Codec extends org.apache.dubbo.remoting.Codec {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/Codec2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting;\n\n@Deprecated\npublic interface Codec2 extends org.apache.dubbo.remoting.Codec2 {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/Dispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\n\n@Deprecated\npublic interface Dispatcher extends org.apache.dubbo.remoting.Dispatcher {\n\n    com.alibaba.dubbo.remoting.ChannelHandler dispatch(\n            com.alibaba.dubbo.remoting.ChannelHandler handler, com.alibaba.dubbo.common.URL url);\n\n    @Override\n    default ChannelHandler dispatch(ChannelHandler handler, URL url) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/RemotingException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting;\n\nimport org.apache.dubbo.remoting.Channel;\n\nimport java.net.InetSocketAddress;\n\n@Deprecated\npublic class RemotingException extends org.apache.dubbo.remoting.RemotingException {\n\n    public RemotingException(Channel channel, String msg) {\n        super(channel, msg);\n    }\n\n    public RemotingException(InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message) {\n        super(localAddress, remoteAddress, message);\n    }\n\n    public RemotingException(Channel channel, Throwable cause) {\n        super(channel, cause);\n    }\n\n    public RemotingException(InetSocketAddress localAddress, InetSocketAddress remoteAddress, Throwable cause) {\n        super(localAddress, remoteAddress, cause);\n    }\n\n    public RemotingException(Channel channel, String message, Throwable cause) {\n        super(channel, message, cause);\n    }\n\n    public RemotingException(\n            InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message, Throwable cause) {\n        super(localAddress, remoteAddress, message, cause);\n    }\n\n    public RemotingException(Exception e) {\n        super(null, e.getMessage());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/Server.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting;\n\nimport org.apache.dubbo.remoting.RemotingServer;\n\n@Deprecated\npublic interface Server extends RemotingServer {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/Transporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting;\n\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingServer;\n\nimport com.alibaba.dubbo.common.DelegateURL;\nimport com.alibaba.dubbo.common.URL;\n\n@Deprecated\npublic interface Transporter extends org.apache.dubbo.remoting.Transporter {\n\n    @Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})\n    Server bind(URL url, ChannelHandler handler) throws RemotingException;\n\n    @Override\n    default RemotingServer bind(org.apache.dubbo.common.URL url, org.apache.dubbo.remoting.ChannelHandler handler)\n            throws org.apache.dubbo.remoting.RemotingException {\n        return bind(new DelegateURL(url), new ChannelHandler() {\n            @Override\n            public void connected(Channel channel) throws RemotingException {\n                try {\n                    handler.connected(channel);\n                } catch (org.apache.dubbo.remoting.RemotingException e) {\n                    throw new RemotingException(e);\n                }\n            }\n\n            @Override\n            public void disconnected(Channel channel) throws RemotingException {\n                try {\n                    handler.disconnected(channel);\n                } catch (org.apache.dubbo.remoting.RemotingException e) {\n                    throw new RemotingException(e);\n                }\n            }\n\n            @Override\n            public void sent(Channel channel, Object message) throws RemotingException {\n                try {\n                    handler.sent(channel, message);\n                } catch (org.apache.dubbo.remoting.RemotingException e) {\n                    throw new RemotingException(e);\n                }\n            }\n\n            @Override\n            public void received(Channel channel, Object message) throws RemotingException {\n                try {\n                    handler.received(channel, message);\n                } catch (org.apache.dubbo.remoting.RemotingException e) {\n                    throw new RemotingException(e);\n                }\n            }\n\n            @Override\n            public void caught(Channel channel, Throwable exception) throws RemotingException {\n                try {\n                    handler.caught(channel, exception);\n                } catch (org.apache.dubbo.remoting.RemotingException e) {\n                    throw new RemotingException(e);\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/exchange/Exchanger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting.exchange;\n\n@Deprecated\npublic interface Exchanger extends org.apache.dubbo.remoting.exchange.Exchanger {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/exchange/ResponseCallback.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting.exchange;\n\n/**\n * 2019-06-20\n */\n@Deprecated\npublic interface ResponseCallback {\n    /**\n     * done.\n     *\n     * @param response\n     */\n    void done(Object response);\n\n    /**\n     * caught exception.\n     *\n     * @param exception\n     */\n    void caught(Throwable exception);\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/exchange/ResponseFuture.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting.exchange;\n\nimport com.alibaba.dubbo.remoting.RemotingException;\n\n/**\n * 2019-06-20\n */\n@Deprecated\npublic interface ResponseFuture {\n    /**\n     * get result.\n     *\n     * @return result.\n     */\n    Object get() throws RemotingException;\n\n    /**\n     * get result with the specified timeout.\n     *\n     * @param timeoutInMillis timeout.\n     * @return result.\n     */\n    Object get(int timeoutInMillis) throws RemotingException;\n\n    /**\n     * set callback.\n     *\n     * @param callback\n     */\n    void setCallback(ResponseCallback callback);\n\n    /**\n     * check is done.\n     *\n     * @return done or not.\n     */\n    boolean isDone();\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/remoting/telnet/TelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.remoting.telnet;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\n\n@Deprecated\npublic interface TelnetHandler extends org.apache.dubbo.remoting.telnet.TelnetHandler {\n\n    String telnet(com.alibaba.dubbo.remoting.Channel channel, String message)\n            throws com.alibaba.dubbo.remoting.RemotingException;\n\n    @Override\n    default String telnet(Channel channel, String message) throws RemotingException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Exporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\n@Deprecated\npublic interface Exporter<T> extends org.apache.dubbo.rpc.Exporter<T> {\n\n    @Override\n    Invoker<T> getInvoker();\n\n    default void register() {}\n\n    default void unregister() {}\n\n    class CompatibleExporter<T> implements Exporter<T> {\n\n        private org.apache.dubbo.rpc.Exporter<T> delegate;\n\n        public CompatibleExporter(org.apache.dubbo.rpc.Exporter<T> delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public Invoker<T> getInvoker() {\n            return new Invoker.CompatibleInvoker<>(delegate.getInvoker());\n        }\n\n        @Override\n        public void unexport() {\n            delegate.unexport();\n        }\n\n        @Override\n        public void register() {\n            delegate.register();\n        }\n\n        @Override\n        public void unregister() {\n            delegate.unregister();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Filter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.dubbo.rpc;\n\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.AttachmentsAdapter;\n\nimport java.util.Map;\n\n@Deprecated\npublic interface Filter extends org.apache.dubbo.rpc.Filter {\n\n    Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;\n\n    @Override\n    default org.apache.dubbo.rpc.Result invoke(\n            org.apache.dubbo.rpc.Invoker<?> invoker, org.apache.dubbo.rpc.Invocation invocation)\n            throws org.apache.dubbo.rpc.RpcException {\n        Result invokeResult =\n                invoke(new Invoker.CompatibleInvoker<>(invoker), new Invocation.CompatibleInvocation(invocation));\n\n        if (invokeResult instanceof Result.CompatibleResult) {\n            return ((Result.CompatibleResult) invokeResult).getDelegate();\n        }\n\n        AsyncRpcResult asyncRpcResult = AsyncRpcResult.newDefaultAsyncResult(invocation);\n        asyncRpcResult.setValue(invokeResult.getValue());\n        asyncRpcResult.setException(invokeResult.getException());\n        Map<String, String> attachments = invokeResult.getAttachments();\n        if (!(attachments instanceof AttachmentsAdapter.ObjectToStringMap)) {\n            asyncRpcResult.setAttachments(attachments);\n        }\n        asyncRpcResult.setObjectAttachments(invokeResult.getObjectAttachments());\n\n        return asyncRpcResult;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Invocation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.beans.Transient;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\n@Deprecated\npublic interface Invocation extends org.apache.dubbo.rpc.Invocation {\n\n    @Override\n    Invoker<?> getInvoker();\n\n    default org.apache.dubbo.rpc.Invocation getOriginal() {\n        return null;\n    }\n\n    @Override\n    default void setAttachment(String key, String value) {\n        setObjectAttachment(key, value);\n    }\n\n    @Override\n    default void setAttachmentIfAbsent(String key, String value) {\n        setObjectAttachmentIfAbsent(key, value);\n    }\n\n    @Override\n    default void setObjectAttachmentIfAbsent(String key, Object value) {}\n\n    @Override\n    default void setObjectAttachment(String key, Object value) {}\n\n    @Override\n    default void setAttachment(String key, Object value) {\n        setObjectAttachment(key, value);\n    }\n\n    @Override\n    default void setAttachmentIfAbsent(String key, Object value) {\n        setObjectAttachmentIfAbsent(key, value);\n    }\n\n    @Override\n    default String getServiceName() {\n        return null;\n    }\n\n    @Override\n    default String getTargetServiceUniqueName() {\n        return null;\n    }\n\n    @Override\n    default String getAttachment(String key, String defaultValue) {\n        return null;\n    }\n\n    @Override\n    default void setServiceModel(ServiceModel serviceModel) {}\n\n    @Override\n    default ServiceModel getServiceModel() {\n        return null;\n    }\n\n    @Override\n    default Object put(Object key, Object value) {\n        return null;\n    }\n\n    @Override\n    default Object get(Object key) {\n        return null;\n    }\n\n    @Override\n    default Map<Object, Object> getAttributes() {\n        return null;\n    }\n\n    @Override\n    default Map<String, Object> getObjectAttachments() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    default Map<String, Object> copyObjectAttachments() {\n        return new HashMap<>(getObjectAttachments());\n    }\n\n    @Override\n    default void foreachAttachment(Consumer<Map.Entry<String, Object>> consumer) {\n        getObjectAttachments().entrySet().forEach(consumer);\n    }\n\n    @Override\n    default Object getObjectAttachment(String key) {\n        return null;\n    }\n\n    @Override\n    default Object getObjectAttachment(String key, Object defaultValue) {\n        return null;\n    }\n\n    class CompatibleInvocation implements Invocation {\n\n        private org.apache.dubbo.rpc.Invocation delegate;\n\n        public CompatibleInvocation(org.apache.dubbo.rpc.Invocation invocation) {\n            this.delegate = invocation;\n        }\n\n        @Override\n        public String getTargetServiceUniqueName() {\n            return delegate.getTargetServiceUniqueName();\n        }\n\n        @Override\n        public String getProtocolServiceKey() {\n            return delegate.getProtocolServiceKey();\n        }\n\n        @Override\n        public String getMethodName() {\n            return delegate.getMethodName();\n        }\n\n        @Override\n        public String getServiceName() {\n            return null;\n        }\n\n        @Override\n        public Class<?>[] getParameterTypes() {\n            return delegate.getParameterTypes();\n        }\n\n        @Override\n        public Object[] getArguments() {\n            return delegate.getArguments();\n        }\n\n        @Override\n        public Map<String, String> getAttachments() {\n            return delegate.getAttachments();\n        }\n\n        @Override\n        public String getAttachment(String key) {\n            return delegate.getAttachment(key);\n        }\n\n        @Override\n        public String getAttachment(String key, String defaultValue) {\n            return delegate.getAttachment(key, defaultValue);\n        }\n\n        @Override\n        @Transient\n        public Invoker<?> getInvoker() {\n            return new Invoker.CompatibleInvoker(delegate.getInvoker());\n        }\n\n        @Override\n        public void setServiceModel(ServiceModel serviceModel) {\n            delegate.setServiceModel(serviceModel);\n        }\n\n        @Override\n        public ServiceModel getServiceModel() {\n            return delegate.getServiceModel();\n        }\n\n        @Override\n        public Object put(Object key, Object value) {\n            return delegate.put(key, value);\n        }\n\n        @Override\n        public Object get(Object key) {\n            return delegate.get(key);\n        }\n\n        @Override\n        public Map<Object, Object> getAttributes() {\n            return delegate.getAttributes();\n        }\n\n        @Override\n        public org.apache.dubbo.rpc.Invocation getOriginal() {\n            return delegate;\n        }\n\n        @Override\n        public void addInvokedInvoker(org.apache.dubbo.rpc.Invoker<?> invoker) {\n            delegate.addInvokedInvoker(invoker);\n        }\n\n        @Override\n        public List<org.apache.dubbo.rpc.Invoker<?>> getInvokedInvokers() {\n            return delegate.getInvokedInvokers();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Invoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\nimport org.apache.dubbo.rpc.AsyncRpcResult;\n\nimport com.alibaba.dubbo.common.DelegateURL;\nimport com.alibaba.dubbo.common.URL;\n\n@Deprecated\npublic interface Invoker<T> extends org.apache.dubbo.rpc.Invoker<T> {\n\n    Result invoke(Invocation invocation) throws RpcException;\n\n    @Override\n    URL getUrl();\n\n    default org.apache.dubbo.rpc.Invoker<T> getOriginal() {\n        return null;\n    }\n\n    // This method will never be called for a legacy invoker.\n    @Override\n    default org.apache.dubbo.rpc.Result invoke(org.apache.dubbo.rpc.Invocation invocation)\n            throws org.apache.dubbo.rpc.RpcException {\n        return null;\n    }\n\n    class CompatibleInvoker<T> implements Invoker<T> {\n\n        private org.apache.dubbo.rpc.Invoker<T> invoker;\n\n        public CompatibleInvoker(org.apache.dubbo.rpc.Invoker<T> invoker) {\n            this.invoker = invoker;\n        }\n\n        @Override\n        public Class<T> getInterface() {\n            return invoker.getInterface();\n        }\n\n        @Override\n        public org.apache.dubbo.rpc.Result invoke(org.apache.dubbo.rpc.Invocation invocation)\n                throws org.apache.dubbo.rpc.RpcException {\n            return new Result.CompatibleResult(invoker.invoke(invocation));\n        }\n\n        @Override\n        public Result invoke(Invocation invocation) throws RpcException {\n            if (invoker instanceof Invoker) {\n                Result result = ((Invoker) invoker).invoke(invocation);\n                if (result instanceof Result.CompatibleResult) {\n                    return result;\n                } else {\n                    AsyncRpcResult asyncRpcResult = AsyncRpcResult.newDefaultAsyncResult(invocation.getOriginal());\n                    asyncRpcResult.setValue(result.getValue());\n                    asyncRpcResult.setException(result.getException());\n                    asyncRpcResult.setObjectAttachments(result.getObjectAttachments());\n\n                    return new Result.CompatibleResult(asyncRpcResult);\n                }\n            }\n            return new Result.CompatibleResult(invoker.invoke(invocation.getOriginal()));\n        }\n\n        @Override\n        public URL getUrl() {\n            return new DelegateURL(invoker.getUrl());\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return invoker.isAvailable();\n        }\n\n        @Override\n        public void destroy() {\n            invoker.destroy();\n        }\n\n        @Override\n        public org.apache.dubbo.rpc.Invoker<T> getOriginal() {\n            return invoker;\n        }\n\n        @Override\n        public int hashCode() {\n            return invoker.hashCode();\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) {\n                return true;\n            }\n            if (!(o instanceof CompatibleInvoker)) {\n                return false;\n            }\n            return invoker.equals(o);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/InvokerListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\n\n@Deprecated\npublic interface InvokerListener extends org.apache.dubbo.rpc.InvokerListener {\n\n    void referred(com.alibaba.dubbo.rpc.Invoker<?> invoker) throws com.alibaba.dubbo.rpc.RpcException;\n\n    void destroyed(com.alibaba.dubbo.rpc.Invoker<?> invoker);\n\n    @Override\n    default void referred(Invoker<?> invoker) throws RpcException {\n        this.referred(new com.alibaba.dubbo.rpc.Invoker.CompatibleInvoker<>(invoker));\n    }\n\n    @Override\n    default void destroyed(Invoker<?> invoker) {\n        this.destroyed(new com.alibaba.dubbo.rpc.Invoker.CompatibleInvoker<>(invoker));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Protocol.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\nimport org.apache.dubbo.rpc.ProtocolServer;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport com.alibaba.dubbo.common.DelegateURL;\nimport com.alibaba.dubbo.common.URL;\n\n@Deprecated\npublic interface Protocol extends org.apache.dubbo.rpc.Protocol {\n\n    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;\n\n    <T> Invoker<T> refer(Class<T> aClass, URL url) throws RpcException;\n\n    @Override\n    default <T> org.apache.dubbo.rpc.Exporter<T> export(org.apache.dubbo.rpc.Invoker<T> invoker) throws RpcException {\n        return this.export(new Invoker.CompatibleInvoker<>(invoker));\n    }\n\n    @Override\n    default <T> org.apache.dubbo.rpc.Invoker<T> refer(Class<T> aClass, org.apache.dubbo.common.URL url)\n            throws RpcException {\n        return this.refer(aClass, new DelegateURL(url));\n    }\n\n    @Override\n    default List<ProtocolServer> getServers() {\n        return Collections.emptyList();\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/ProxyFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\n\n@Deprecated\npublic interface ProxyFactory extends org.apache.dubbo.rpc.ProxyFactory {\n\n    <T> T getProxy(com.alibaba.dubbo.rpc.Invoker<T> invoker) throws com.alibaba.dubbo.rpc.RpcException;\n\n    <T> T getProxy(com.alibaba.dubbo.rpc.Invoker<T> invoker, boolean generic) throws com.alibaba.dubbo.rpc.RpcException;\n\n    <T> com.alibaba.dubbo.rpc.Invoker<T> getInvoker(T proxy, Class<T> type, com.alibaba.dubbo.common.URL url)\n            throws com.alibaba.dubbo.rpc.RpcException;\n\n    @Override\n    default <T> T getProxy(Invoker<T> invoker) throws RpcException {\n        return getProxy(new com.alibaba.dubbo.rpc.Invoker.CompatibleInvoker<>(invoker));\n    }\n\n    @Override\n    default <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {\n        return getProxy(new com.alibaba.dubbo.rpc.Invoker.CompatibleInvoker<>(invoker), generic);\n    }\n\n    @Override\n    default <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {\n        return getInvoker(proxy, type, new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Result.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\n\n@Deprecated\npublic interface Result extends org.apache.dubbo.rpc.Result {\n\n    @Override\n    default void setValue(Object value) {}\n\n    @Override\n    default void setException(Throwable t) {}\n\n    @Override\n    default Map<String, Object> getObjectAttachments() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    default void addObjectAttachments(Map<String, Object> map) {}\n\n    @Override\n    default void setObjectAttachments(Map<String, Object> map) {}\n\n    @Override\n    default Object getObjectAttachment(String key) {\n        return null;\n    }\n\n    @Override\n    default Object getObjectAttachment(String key, Object defaultValue) {\n        return null;\n    }\n\n    /**\n     * @see com.alibaba.dubbo.rpc.Result#getValue()\n     * @deprecated Replace to getValue()\n     */\n    @Deprecated\n    default Object getResult() {\n        return getValue();\n    }\n\n    class CompatibleResult implements Result {\n        private org.apache.dubbo.rpc.Result delegate;\n\n        public CompatibleResult(org.apache.dubbo.rpc.Result result) {\n            this.delegate = result;\n        }\n\n        public org.apache.dubbo.rpc.Result getDelegate() {\n            return delegate;\n        }\n\n        @Override\n        public org.apache.dubbo.rpc.Result whenCompleteWithContext(\n                BiConsumer<org.apache.dubbo.rpc.Result, Throwable> fn) {\n            return delegate.whenCompleteWithContext(fn);\n        }\n\n        @Override\n        public Object getValue() {\n            return delegate.getValue();\n        }\n\n        @Override\n        public void setValue(Object value) {\n            delegate.setValue(value);\n        }\n\n        @Override\n        public Throwable getException() {\n            return delegate.getException();\n        }\n\n        @Override\n        public void setException(Throwable t) {\n            delegate.setException(t);\n        }\n\n        @Override\n        public boolean hasException() {\n            return delegate.hasException();\n        }\n\n        @Override\n        public Object recreate() throws Throwable {\n            return delegate.recreate();\n        }\n\n        @Override\n        public Map<String, String> getAttachments() {\n            return delegate.getAttachments();\n        }\n\n        @Override\n        public void addAttachments(Map<String, String> map) {\n            delegate.addAttachments(map);\n        }\n\n        @Override\n        public void setAttachments(Map<String, String> map) {\n            delegate.setAttachments(map);\n        }\n\n        @Override\n        public String getAttachment(String key) {\n            return delegate.getAttachment(key);\n        }\n\n        @Override\n        public String getAttachment(String key, String defaultValue) {\n            return delegate.getAttachment(key, defaultValue);\n        }\n\n        @Override\n        public void setAttachment(String key, String value) {\n            delegate.setAttachment(key, value);\n        }\n\n        @Override\n        public void setAttachment(String key, Object value) {\n            delegate.setAttachment(key, value);\n        }\n\n        @Override\n        public void setObjectAttachment(String key, Object value) {\n            delegate.setObjectAttachment(key, value);\n        }\n\n        @Override\n        public <U> CompletableFuture<U> thenApply(Function<org.apache.dubbo.rpc.Result, ? extends U> fn) {\n            return delegate.thenApply(fn);\n        }\n\n        @Override\n        public org.apache.dubbo.rpc.Result get() throws InterruptedException, ExecutionException {\n            return delegate.get();\n        }\n\n        @Override\n        public org.apache.dubbo.rpc.Result get(long timeout, TimeUnit unit)\n                throws InterruptedException, ExecutionException, TimeoutException {\n            return delegate.get(timeout, unit);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/RpcContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.FutureContext;\n\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.FutureTask;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.dubbo.common.Constants;\nimport com.alibaba.dubbo.common.DelegateURL;\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.rpc.protocol.dubbo.FutureAdapter;\n\n@Deprecated\npublic class RpcContext {\n\n    public static RpcContext getContext() {\n        return new RpcContext(org.apache.dubbo.rpc.RpcContext.getContext());\n    }\n\n    public static RpcContext getServerContext() {\n        return new RpcContext(org.apache.dubbo.rpc.RpcContext.getServerContext());\n    }\n\n    public static RpcContext getClientResponseContext() {\n        return new RpcContext(org.apache.dubbo.rpc.RpcContext.getClientResponseContext());\n    }\n\n    public static RpcContext getServerResponseContext() {\n        return new RpcContext(org.apache.dubbo.rpc.RpcContext.getServerResponseContext());\n    }\n\n    public static void removeClientResponseContext() {\n        org.apache.dubbo.rpc.RpcContext.removeClientResponseContext();\n    }\n\n    public static void removeServerResponseContext() {\n        org.apache.dubbo.rpc.RpcContext.removeServerResponseContext();\n    }\n\n    public static void removeServerContext() {\n        org.apache.dubbo.rpc.RpcContext.removeServerContext();\n    }\n\n    public static void removeContext() {\n        org.apache.dubbo.rpc.RpcContext.removeContext();\n    }\n\n    private org.apache.dubbo.rpc.RpcContext newRpcContext;\n\n    public RpcContext(org.apache.dubbo.rpc.RpcContext newRpcContext) {\n        this.newRpcContext = newRpcContext;\n    }\n\n    public Object getRequest() {\n        return newRpcContext.getRequest();\n    }\n\n    public <T> T getRequest(Class<T> clazz) {\n        return newRpcContext.getRequest(clazz);\n    }\n\n    public void setRequest(Object request) {\n        newRpcContext.setRequest(request);\n    }\n\n    /**\n     * Get the response object of the underlying RPC protocol, e.g. HttpServletResponse\n     *\n     * @return null if the underlying protocol doesn't provide support for getting response\n     */\n    public Object getResponse() {\n        return newRpcContext.getResponse();\n    }\n\n    /**\n     * Get the response object of the underlying RPC protocol, e.g. HttpServletResponse\n     *\n     * @return null if the underlying protocol doesn't provide support for getting response or the response is not of the specified type\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <T> T getResponse(Class<T> clazz) {\n        return newRpcContext.getResponse(clazz);\n    }\n\n    public void setResponse(Object response) {\n        newRpcContext.setResponse(response);\n    }\n\n    /**\n     * is provider side.\n     *\n     * @return provider side.\n     */\n    public boolean isProviderSide() {\n        return newRpcContext.isProviderSide();\n    }\n\n    /**\n     * is consumer side.\n     *\n     * @return consumer side.\n     */\n    public boolean isConsumerSide() {\n        return newRpcContext.isConsumerSide();\n    }\n\n    public List<URL> getUrls() {\n        List<org.apache.dubbo.common.URL> newUrls = newRpcContext.getUrls();\n        if (CollectionUtils.isNotEmpty(newUrls)) {\n            List<URL> urls = new ArrayList<>(newUrls.size());\n            for (org.apache.dubbo.common.URL newUrl : newUrls) {\n                urls.add(new DelegateURL(newUrl));\n            }\n            return urls;\n        }\n        return Collections.emptyList();\n    }\n\n    public void setUrls(List<URL> urls) {\n        if (CollectionUtils.isNotEmpty(urls)) {\n            List<org.apache.dubbo.common.URL> newUrls = new ArrayList<>(urls.size());\n            for (URL url : urls) {\n                newUrls.add(url.getOriginalURL());\n            }\n            newRpcContext.setUrls(newUrls);\n        }\n    }\n\n    public URL getUrl() {\n        return new DelegateURL(newRpcContext.getUrl());\n    }\n\n    public void setUrl(URL url) {\n        newRpcContext.setUrl(url.getOriginalURL());\n    }\n\n    public String getMethodName() {\n        return newRpcContext.getMethodName();\n    }\n\n    public void setMethodName(String methodName) {\n        newRpcContext.setMethodName(methodName);\n    }\n\n    public Class<?>[] getParameterTypes() {\n        return newRpcContext.getParameterTypes();\n    }\n\n    public void setParameterTypes(Class<?>[] parameterTypes) {\n        newRpcContext.setParameterTypes(parameterTypes);\n    }\n\n    public Object[] getArguments() {\n        return newRpcContext.getArguments();\n    }\n\n    public void setArguments(Object[] arguments) {\n        newRpcContext.setArguments(arguments);\n    }\n\n    public RpcContext setLocalAddress(String host, int port) {\n        newRpcContext.setLocalAddress(host, port);\n        return this;\n    }\n\n    /**\n     * get local address.\n     *\n     * @return local address\n     */\n    public InetSocketAddress getLocalAddress() {\n        return newRpcContext.getLocalAddress();\n    }\n\n    public RpcContext setLocalAddress(InetSocketAddress address) {\n        newRpcContext.setLocalAddress(address);\n        return this;\n    }\n\n    public String getLocalAddressString() {\n        return newRpcContext.getLocalAddressString();\n    }\n\n    public String getLocalHostName() {\n        return newRpcContext.getLocalHostName();\n    }\n\n    public RpcContext setRemoteAddress(String host, int port) {\n        newRpcContext.setRemoteAddress(host, port);\n        return this;\n    }\n\n    public InetSocketAddress getRemoteAddress() {\n        return newRpcContext.getRemoteAddress();\n    }\n\n    public RpcContext setRemoteAddress(InetSocketAddress address) {\n        newRpcContext.setRemoteAddress(address);\n        return this;\n    }\n\n    public String getRemoteAddressString() {\n        return newRpcContext.getRemoteAddressString();\n    }\n\n    public String getRemoteHostName() {\n        return newRpcContext.getRemoteHostName();\n    }\n\n    public String getLocalHost() {\n        return newRpcContext.getLocalHost();\n    }\n\n    public int getLocalPort() {\n        return newRpcContext.getLocalPort();\n    }\n\n    public String getRemoteHost() {\n        return newRpcContext.getRemoteHost();\n    }\n\n    public int getRemotePort() {\n        return newRpcContext.getRemotePort();\n    }\n\n    public String getAttachment(String key) {\n        return newRpcContext.getAttachment(key);\n    }\n\n    public RpcContext setAttachment(String key, String value) {\n        newRpcContext.setAttachment(key, value);\n        return this;\n    }\n\n    public RpcContext removeAttachment(String key) {\n        newRpcContext.removeAttachment(key);\n        return this;\n    }\n\n    public Map<String, String> getAttachments() {\n        return newRpcContext.getAttachments();\n    }\n\n    public RpcContext setAttachments(Map<String, String> attachment) {\n        newRpcContext.setAttachments(attachment);\n        return this;\n    }\n\n    public void clearAttachments() {\n        newRpcContext.clearAttachments();\n    }\n\n    /**\n     * get values.\n     *\n     * @return values\n     */\n    public Map<String, Object> get() {\n        return newRpcContext.get();\n    }\n\n    /**\n     * set value.\n     *\n     * @param key\n     * @param value\n     * @return context\n     */\n    public RpcContext set(String key, Object value) {\n        newRpcContext.set(key, value);\n        return this;\n    }\n\n    public RpcContext remove(String key) {\n        newRpcContext.remove(key);\n        return this;\n    }\n\n    public Object get(String key) {\n        return newRpcContext.get(key);\n    }\n\n    public Invocation getInvocation() {\n        return new Invocation.CompatibleInvocation(newRpcContext.getInvocation());\n    }\n\n    @Deprecated\n    public boolean isServerSide() {\n        return isProviderSide();\n    }\n\n    @Deprecated\n    public boolean isClientSide() {\n        return isConsumerSide();\n    }\n\n    @Deprecated\n    public Invoker<?> getInvoker() {\n        org.apache.dubbo.rpc.Invoker<?> invoker = newRpcContext.getInvoker();\n        if (invoker == null) {\n            return null;\n        }\n        return new Invoker.CompatibleInvoker<>(invoker);\n    }\n\n    @Deprecated\n    public List<Invoker<?>> getInvokers() {\n        List<org.apache.dubbo.rpc.Invoker<?>> invokers = newRpcContext.getInvokers();\n        if (CollectionUtils.isEmpty(invokers)) {\n            return Collections.emptyList();\n        }\n        return invokers.stream().map(Invoker.CompatibleInvoker::new).collect(Collectors.toList());\n    }\n    /**\n     * Async invocation. Timeout will be handled even if <code>Future.get()</code> is not called.\n     *\n     * @param callable\n     * @return get the return result from <code>future.get()</code>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <T> Future<T> asyncCall(Callable<T> callable) {\n        try {\n            try {\n                setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());\n                final T o = callable.call();\n                // local invoke will return directly\n                if (o != null) {\n                    FutureTask<T> f = new FutureTask<>(new Callable<T>() {\n                        @Override\n                        public T call() throws Exception {\n                            return o;\n                        }\n                    });\n                    f.run();\n                    return f;\n                } else {\n\n                }\n            } catch (Exception e) {\n                throw new RpcException(e);\n            } finally {\n                removeAttachment(Constants.ASYNC_KEY);\n            }\n        } catch (final RpcException e) {\n            return new Future<T>() {\n                @Override\n                public boolean cancel(boolean mayInterruptIfRunning) {\n                    return false;\n                }\n\n                @Override\n                public boolean isCancelled() {\n                    return false;\n                }\n\n                @Override\n                public boolean isDone() {\n                    return true;\n                }\n\n                @Override\n                public T get() throws InterruptedException, ExecutionException {\n                    throw new ExecutionException(e.getCause());\n                }\n\n                @Override\n                public T get(long timeout, TimeUnit unit)\n                        throws InterruptedException, ExecutionException, TimeoutException {\n                    return get();\n                }\n            };\n        }\n        return ((Future<T>) getContext().getFuture());\n    }\n\n    /**\n     * one way async call, send request only, and result is not required\n     *\n     * @param runnable\n     */\n    public void asyncCall(Runnable runnable) {\n        try {\n            setAttachment(Constants.RETURN_KEY, Boolean.FALSE.toString());\n            runnable.run();\n        } catch (Throwable e) {\n            // FIXME should put exception in future?\n            throw new RpcException(\"oneway call error .\" + e.getMessage(), e);\n        } finally {\n            removeAttachment(Constants.RETURN_KEY);\n        }\n    }\n\n    public <T> Future<T> getFuture() {\n        CompletableFuture completableFuture = FutureContext.getContext().getCompatibleCompletableFuture();\n        if (completableFuture == null) {\n            return null;\n        }\n        return new FutureAdapter(completableFuture);\n    }\n\n    public void setFuture(CompletableFuture<?> future) {\n        FutureContext.getContext().setCompatibleFuture(future);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/RpcException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\n@Deprecated\npublic class RpcException extends org.apache.dubbo.rpc.RpcException {\n\n    public RpcException() {\n        super();\n    }\n\n    public RpcException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public RpcException(String message) {\n        super(message);\n    }\n\n    public RpcException(Throwable cause) {\n        super(cause);\n    }\n\n    public RpcException(int code) {\n        super(code);\n    }\n\n    public RpcException(int code, String message, Throwable cause) {\n        super(code, message, cause);\n    }\n\n    public RpcException(int code, String message) {\n        super(code, message);\n    }\n\n    public RpcException(int code, Throwable cause) {\n        super(code, cause);\n    }\n\n    public boolean isForbidded() {\n        return isForbidden();\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\nimport java.beans.Transient;\nimport java.io.Serializable;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.common.Constants;\nimport com.alibaba.dubbo.common.URL;\n\n@Deprecated\npublic class RpcInvocation implements Invocation, Serializable {\n\n    private static final long serialVersionUID = -4355285085441097045L;\n\n    private String methodName;\n\n    private Class<?>[] parameterTypes;\n\n    private Object[] arguments;\n\n    private Map<String, String> attachments;\n\n    private transient Invoker<?> invoker;\n\n    public RpcInvocation() {}\n\n    public RpcInvocation(Invocation invocation, Invoker<?> invoker) {\n        this(\n                invocation.getMethodName(),\n                invocation.getParameterTypes(),\n                invocation.getArguments(),\n                new HashMap<String, String>(invocation.getAttachments()),\n                invocation.getInvoker());\n        if (invoker != null) {\n            URL url = invoker.getUrl();\n            setAttachment(Constants.PATH_KEY, url.getPath());\n            if (url.hasParameter(Constants.INTERFACE_KEY)) {\n                setAttachment(Constants.INTERFACE_KEY, url.getParameter(Constants.INTERFACE_KEY));\n            }\n            if (url.hasParameter(Constants.GROUP_KEY)) {\n                setAttachment(Constants.GROUP_KEY, url.getParameter(Constants.GROUP_KEY));\n            }\n            if (url.hasParameter(Constants.VERSION_KEY)) {\n                setAttachment(Constants.VERSION_KEY, url.getParameter(Constants.VERSION_KEY, \"0.0.0\"));\n            }\n            if (url.hasParameter(Constants.TIMEOUT_KEY)) {\n                setAttachment(Constants.TIMEOUT_KEY, url.getParameter(Constants.TIMEOUT_KEY));\n            }\n            if (url.hasParameter(Constants.TOKEN_KEY)) {\n                setAttachment(Constants.TOKEN_KEY, url.getParameter(Constants.TOKEN_KEY));\n            }\n            if (url.hasParameter(Constants.APPLICATION_KEY)) {\n                setAttachment(Constants.APPLICATION_KEY, url.getParameter(Constants.APPLICATION_KEY));\n            }\n        }\n    }\n\n    public RpcInvocation(Invocation invocation) {\n        this(\n                invocation.getMethodName(),\n                invocation.getParameterTypes(),\n                invocation.getArguments(),\n                invocation.getAttachments(),\n                invocation.getInvoker());\n    }\n\n    public RpcInvocation(Method method, Object[] arguments) {\n        this(method.getName(), method.getParameterTypes(), arguments, null, null);\n    }\n\n    public RpcInvocation(Method method, Object[] arguments, Map<String, String> attachment) {\n        this(method.getName(), method.getParameterTypes(), arguments, attachment, null);\n    }\n\n    public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments) {\n        this(methodName, parameterTypes, arguments, null, null);\n    }\n\n    public RpcInvocation(\n            String methodName, Class<?>[] parameterTypes, Object[] arguments, Map<String, String> attachments) {\n        this(methodName, parameterTypes, arguments, attachments, null);\n    }\n\n    public RpcInvocation(\n            String methodName,\n            Class<?>[] parameterTypes,\n            Object[] arguments,\n            Map<String, String> attachments,\n            Invoker<?> invoker) {\n        this.methodName = methodName;\n        this.parameterTypes = parameterTypes == null ? new Class<?>[0] : parameterTypes;\n        this.arguments = arguments == null ? new Object[0] : arguments;\n        this.attachments = attachments == null ? new HashMap<String, String>() : attachments;\n        this.invoker = invoker;\n    }\n\n    @Transient\n    public Invoker<?> getInvoker() {\n        return invoker;\n    }\n\n    public void setInvoker(Invoker<?> invoker) {\n        this.invoker = invoker;\n    }\n\n    @Override\n    public String getProtocolServiceKey() {\n        return null;\n    }\n\n    public String getMethodName() {\n        return methodName;\n    }\n\n    public void setMethodName(String methodName) {\n        this.methodName = methodName;\n    }\n\n    public Class<?>[] getParameterTypes() {\n        return parameterTypes;\n    }\n\n    public void setParameterTypes(Class<?>[] parameterTypes) {\n        this.parameterTypes = parameterTypes == null ? new Class<?>[0] : parameterTypes;\n    }\n\n    public Object[] getArguments() {\n        return arguments;\n    }\n\n    public void setArguments(Object[] arguments) {\n        this.arguments = arguments == null ? new Object[0] : arguments;\n    }\n\n    public Map<String, String> getAttachments() {\n        return attachments;\n    }\n\n    public void setAttachments(Map<String, String> attachments) {\n        this.attachments = attachments == null ? new HashMap<String, String>() : attachments;\n    }\n\n    public void setAttachment(String key, String value) {\n        if (attachments == null) {\n            attachments = new HashMap<>();\n        }\n        attachments.put(key, value);\n    }\n\n    public void setAttachmentIfAbsent(String key, String value) {\n        if (attachments == null) {\n            attachments = new HashMap<>();\n        }\n        if (!attachments.containsKey(key)) {\n            attachments.put(key, value);\n        }\n    }\n\n    public void addAttachments(Map<String, String> attachments) {\n        if (attachments == null) {\n            return;\n        }\n        if (this.attachments == null) {\n            this.attachments = new HashMap<>();\n        }\n        this.attachments.putAll(attachments);\n    }\n\n    public void addAttachmentsIfAbsent(Map<String, String> attachments) {\n        if (attachments == null) {\n            return;\n        }\n        for (Map.Entry<String, String> entry : attachments.entrySet()) {\n            setAttachmentIfAbsent(entry.getKey(), entry.getValue());\n        }\n    }\n\n    public String getAttachment(String key) {\n        if (attachments == null) {\n            return null;\n        }\n        return (String) attachments.get(key);\n    }\n\n    public String getAttachment(String key, String defaultValue) {\n        if (attachments == null) {\n            return defaultValue;\n        }\n        String value = (String) attachments.get(key);\n        if (value == null || value.length() == 0) {\n            return defaultValue;\n        }\n        return value;\n    }\n\n    @Override\n    public void addInvokedInvoker(org.apache.dubbo.rpc.Invoker<?> invoker) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public List<org.apache.dubbo.rpc.Invoker<?>> getInvokedInvokers() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String toString() {\n        return \"RpcInvocation [methodName=\" + methodName + \", parameterTypes=\"\n                + Arrays.toString(parameterTypes) + \", arguments=\" + Arrays.toString(arguments)\n                + \", attachments=\" + attachments + \"]\";\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/RpcResult.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc;\n\nimport org.apache.dubbo.rpc.AppResponse;\n\n@Deprecated\npublic class RpcResult extends AppResponse implements com.alibaba.dubbo.rpc.Result {\n\n    public RpcResult() {}\n\n    public RpcResult(Object result) {\n        super(result);\n    }\n\n    public RpcResult(Throwable exception) {\n        super(exception);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Cluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\n@Deprecated\npublic interface Cluster extends org.apache.dubbo.rpc.cluster.Cluster {\n\n    <T> com.alibaba.dubbo.rpc.Invoker<T> join(com.alibaba.dubbo.rpc.cluster.Directory<T> directory)\n            throws com.alibaba.dubbo.rpc.RpcException;\n\n    @Override\n    default <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Configurator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\n\n@Deprecated\npublic interface Configurator extends org.apache.dubbo.rpc.cluster.Configurator {\n    /**\n     * Get the configurator url.\n     *\n     * @return configurator url.\n     */\n    com.alibaba.dubbo.common.URL getUrl();\n\n    /**\n     * Configure the provider url.\n     *\n     * @param url - old provider url.\n     * @return new provider url.\n     */\n    com.alibaba.dubbo.common.URL configure(com.alibaba.dubbo.common.URL url);\n\n    @Override\n    default URL configure(URL url) {\n        return this.configure(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/ConfiguratorFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.rpc.cluster.Configurator;\n\n@Deprecated\npublic interface ConfiguratorFactory extends org.apache.dubbo.rpc.cluster.ConfiguratorFactory {\n    @Adaptive(CommonConstants.PROTOCOL_KEY)\n    com.alibaba.dubbo.rpc.cluster.Configurator getConfigurator(com.alibaba.dubbo.common.URL url);\n\n    @Override\n    default Configurator getConfigurator(URL url) {\n        return this.getConfigurator(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Directory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.dubbo.common.URL;\n\n@Deprecated\npublic interface Directory<T> extends org.apache.dubbo.rpc.cluster.Directory<T> {\n\n    @Override\n    URL getUrl();\n\n    List<com.alibaba.dubbo.rpc.Invoker<T>> list(com.alibaba.dubbo.rpc.Invocation invocation)\n            throws com.alibaba.dubbo.rpc.RpcException;\n\n    @Override\n    default List<Invoker<T>> list(Invocation invocation) throws RpcException {\n        List<com.alibaba.dubbo.rpc.Invoker<T>> res =\n                this.list(new com.alibaba.dubbo.rpc.Invocation.CompatibleInvocation(invocation));\n        return res.stream().map(com.alibaba.dubbo.rpc.Invoker::getOriginal).collect(Collectors.toList());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/LoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.dubbo.common.DelegateURL;\n\n@Deprecated\npublic interface LoadBalance extends org.apache.dubbo.rpc.cluster.LoadBalance {\n\n    <T> com.alibaba.dubbo.rpc.Invoker<T> select(\n            List<com.alibaba.dubbo.rpc.Invoker<T>> invokers,\n            com.alibaba.dubbo.common.URL url,\n            com.alibaba.dubbo.rpc.Invocation invocation)\n            throws RpcException;\n\n    @Override\n    default <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {\n        List<com.alibaba.dubbo.rpc.Invoker<T>> invs = invokers.stream()\n                .map(invoker -> new com.alibaba.dubbo.rpc.Invoker.CompatibleInvoker<T>(invoker))\n                .collect(Collectors.toList());\n\n        com.alibaba.dubbo.rpc.Invoker<T> selected = select(\n                invs, new DelegateURL(url), new com.alibaba.dubbo.rpc.Invocation.CompatibleInvocation(invocation));\n\n        return selected == null ? null : selected.getOriginal();\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Merger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.cluster;\n\n@Deprecated\npublic interface Merger extends org.apache.dubbo.rpc.cluster.Merger {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Router.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\n@Deprecated\npublic interface Router extends org.apache.dubbo.rpc.cluster.Router {\n\n    @Override\n    com.alibaba.dubbo.common.URL getUrl();\n\n    <T> List<com.alibaba.dubbo.rpc.Invoker<T>> route(\n            List<com.alibaba.dubbo.rpc.Invoker<T>> invokers,\n            com.alibaba.dubbo.common.URL url,\n            com.alibaba.dubbo.rpc.Invocation invocation)\n            throws com.alibaba.dubbo.rpc.RpcException;\n\n    int compareTo(Router o);\n\n    // Add since 2.7.0\n    @Override\n    default <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {\n        List<com.alibaba.dubbo.rpc.Invoker<T>> invs = invokers.stream()\n                .map(invoker -> new com.alibaba.dubbo.rpc.Invoker.CompatibleInvoker<T>(invoker))\n                .collect(Collectors.toList());\n\n        List<com.alibaba.dubbo.rpc.Invoker<T>> res = this.route(\n                invs,\n                new com.alibaba.dubbo.common.DelegateURL(url),\n                new com.alibaba.dubbo.rpc.Invocation.CompatibleInvocation(invocation));\n\n        return res.stream()\n                .map(inv -> inv.getOriginal())\n                .filter(Objects::nonNull)\n                .collect(Collectors.toList());\n    }\n\n    @Override\n    default boolean isRuntime() {\n        return true;\n    }\n\n    @Override\n    default boolean isForce() {\n        return false;\n    }\n\n    @Override\n    default int getPriority() {\n        return 1;\n    }\n\n    @Override\n    default int compareTo(org.apache.dubbo.rpc.cluster.Router o) {\n        if (!(o instanceof Router)) {\n            return 1;\n        }\n\n        return this.compareTo((Router) o);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/RouterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.cluster.Router;\n\n@Deprecated\npublic interface RouterFactory extends org.apache.dubbo.rpc.cluster.RouterFactory {\n\n    com.alibaba.dubbo.rpc.cluster.Router getRouter(com.alibaba.dubbo.common.URL url);\n\n    @Override\n    default Router getRouter(URL url) {\n        return this.getRouter(new com.alibaba.dubbo.common.DelegateURL(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/RuleConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n@Deprecated\npublic interface RuleConverter extends org.apache.dubbo.rpc.cluster.RuleConverter {\n\n    List<com.alibaba.dubbo.common.URL> convert(com.alibaba.dubbo.common.URL subscribeUrl, Object source);\n\n    @Override\n    default List<URL> convert(URL subscribeUrl, Object source) {\n        return this.convert(new com.alibaba.dubbo.common.DelegateURL(subscribeUrl), source).stream()\n                .map(url -> url.getOriginalURL())\n                .collect(Collectors.toList());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.cluster.loadbalance;\n\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.List;\n\nimport com.alibaba.dubbo.common.Constants;\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.rpc.Invocation;\nimport com.alibaba.dubbo.rpc.Invoker;\nimport com.alibaba.dubbo.rpc.cluster.LoadBalance;\n\n@Deprecated\npublic abstract class AbstractLoadBalance implements LoadBalance {\n\n    @Override\n    public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) {\n        if (invokers == null || invokers.size() == 0) return null;\n        if (invokers.size() == 1) return invokers.get(0);\n        return doSelect(invokers, url, invocation);\n    }\n\n    protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation);\n\n    protected int getWeight(Invoker<?> invoker, Invocation invocation) {\n        int weight = invoker.getUrl()\n                .getMethodParameter(RpcUtils.getMethodName(invocation), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);\n        if (weight > 0) {\n            long timestamp = invoker.getUrl().getParameter(Constants.TIMESTAMP_KEY, 0L);\n            if (timestamp > 0L) {\n                int uptime = (int) (System.currentTimeMillis() - timestamp);\n                int warmup = invoker.getUrl().getParameter(Constants.WARMUP_KEY, Constants.DEFAULT_WARMUP);\n                if (uptime > 0 && uptime < warmup) {\n                    weight = calculateWarmupWeight(uptime, warmup, weight);\n                }\n            }\n        }\n        return weight;\n    }\n\n    static int calculateWarmupWeight(int uptime, int warmup, int weight) {\n        int ww = (int) ((float) uptime / ((float) warmup / (float) weight));\n        return ww < 1 ? 1 : (ww > weight ? weight : ww);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/FutureAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.protocol.dubbo;\n\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Result;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CompletionException;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.function.BiConsumer;\n\nimport com.alibaba.dubbo.remoting.RemotingException;\nimport com.alibaba.dubbo.remoting.exchange.ResponseCallback;\nimport com.alibaba.dubbo.remoting.exchange.ResponseFuture;\nimport com.alibaba.dubbo.rpc.RpcException;\n\n/**\n * 2019-06-20\n */\n@Deprecated\npublic class FutureAdapter<V> implements Future<V> {\n\n    private CompletableFuture<Object> future;\n\n    public FutureAdapter(CompletableFuture<Object> future) {\n        this.future = future;\n    }\n\n    public FutureAdapter(ResponseFuture responseFuture) {\n        this.future = new CompletableFuture<>();\n        responseFuture.setCallback(new ResponseCallback() {\n            @Override\n            public void done(Object response) {\n                future.complete(response);\n            }\n\n            @Override\n            public void caught(Throwable exception) {\n                future.completeExceptionally(exception);\n            }\n        });\n    }\n\n    public ResponseFuture getFuture() {\n        return new ResponseFuture() {\n            @Override\n            public Object get() throws RemotingException {\n                try {\n                    return future.get();\n                } catch (InterruptedException | ExecutionException e) {\n                    throw new RemotingException(e);\n                }\n            }\n\n            @Override\n            public Object get(int timeoutInMillis) throws RemotingException {\n                try {\n                    return future.get(timeoutInMillis, TimeUnit.MILLISECONDS);\n                } catch (InterruptedException | TimeoutException | ExecutionException e) {\n                    throw new RemotingException(e);\n                }\n            }\n\n            @Override\n            public void setCallback(ResponseCallback callback) {\n                FutureAdapter.this.setCallback(callback);\n            }\n\n            @Override\n            public boolean isDone() {\n                return future.isDone();\n            }\n        };\n    }\n\n    void setCallback(ResponseCallback callback) {\n        BiConsumer<Object, ? super Throwable> biConsumer = new BiConsumer<Object, Throwable>() {\n\n            @Override\n            public void accept(Object obj, Throwable t) {\n                if (t != null) {\n                    if (t instanceof CompletionException) {\n                        t = t.getCause();\n                    }\n                    callback.caught(t);\n                } else {\n                    AppResponse appResponse = (AppResponse) obj;\n                    if (appResponse.hasException()) {\n                        callback.caught(appResponse.getException());\n                    } else {\n                        callback.done((V) appResponse.getValue());\n                    }\n                }\n            }\n        };\n        future.whenComplete(biConsumer);\n    }\n\n    @Override\n    public boolean cancel(boolean mayInterruptIfRunning) {\n        return false;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return false;\n    }\n\n    @Override\n    public boolean isDone() {\n        return future.isDone();\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public V get() throws InterruptedException, ExecutionException {\n        try {\n            return (V) (((Result) future.get()).recreate());\n        } catch (InterruptedException | ExecutionException e) {\n            throw e;\n        } catch (Throwable e) {\n            throw new RpcException(e);\n        }\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {\n        try {\n            return (V) (((Result) future.get(timeout, unit)).recreate());\n        } catch (InterruptedException | ExecutionException | TimeoutException e) {\n            throw e;\n        } catch (Throwable e) {\n            throw new RpcException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/service/EchoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.service;\n\n@Deprecated\npublic interface EchoService extends org.apache.dubbo.rpc.service.EchoService {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/service/GenericException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.service;\n\n@Deprecated\npublic class GenericException extends org.apache.dubbo.rpc.service.GenericException {\n\n    private static final long serialVersionUID = -1182299763306599962L;\n\n    public GenericException() {}\n\n    public GenericException(String exceptionMessage) {\n        super(exceptionMessage);\n    }\n\n    public GenericException(String exceptionClass, String exceptionMessage) {\n        super(exceptionClass, exceptionMessage);\n    }\n\n    public GenericException(Throwable cause) {\n        super(cause);\n    }\n\n    public GenericException(String message, Throwable cause, String exceptionClass, String exceptionMessage) {\n        super(message, cause, exceptionClass, exceptionMessage);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/service/GenericService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.service;\n\n@Deprecated\npublic interface GenericService extends org.apache.dubbo.rpc.service.GenericService {\n\n    @Override\n    Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException;\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/support/RpcUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.rpc.support;\n\nimport java.lang.reflect.Type;\n\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.rpc.Invocation;\n\n/**\n * 2019-04-18\n */\npublic class RpcUtils extends org.apache.dubbo.rpc.support.RpcUtils {\n\n    public static Class<?> getReturnType(Invocation invocation) {\n        return org.apache.dubbo.rpc.support.RpcUtils.getReturnType(invocation);\n    }\n\n    // TODO why not get return type when initialize Invocation?\n    public static Type[] getReturnTypes(Invocation invocation) {\n        return org.apache.dubbo.rpc.support.RpcUtils.getReturnTypes(invocation);\n    }\n\n    public static Long getInvocationId(Invocation inv) {\n        return org.apache.dubbo.rpc.support.RpcUtils.getInvocationId(inv);\n    }\n\n    /**\n     * Idempotent operation: invocation id will be added in async operation by default\n     *\n     * @param url\n     * @param inv\n     */\n    public static void attachInvocationIdIfAsync(URL url, Invocation inv) {\n        org.apache.dubbo.rpc.support.RpcUtils.attachInvocationIdIfAsync(url.getOriginalURL(), inv);\n    }\n\n    public static String getMethodName(Invocation invocation) {\n        return org.apache.dubbo.rpc.support.RpcUtils.getMethodName(invocation);\n    }\n\n    public static Object[] getArguments(Invocation invocation) {\n        return org.apache.dubbo.rpc.support.RpcUtils.getArguments(invocation);\n    }\n\n    public static Class<?>[] getParameterTypes(Invocation invocation) {\n        return org.apache.dubbo.rpc.support.RpcUtils.getParameterTypes(invocation);\n    }\n\n    public static boolean isAsync(URL url, Invocation inv) {\n        return org.apache.dubbo.rpc.support.RpcUtils.isAsync(url.getOriginalURL(), inv);\n    }\n\n    public static boolean isReturnTypeFuture(Invocation inv) {\n        return org.apache.dubbo.rpc.support.RpcUtils.isReturnTypeFuture(inv);\n    }\n\n    public static boolean isOneway(URL url, Invocation inv) {\n        return org.apache.dubbo.rpc.support.RpcUtils.isOneway(url.getOriginalURL(), inv);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/validation/Validation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.validation;\n\n@Deprecated\npublic interface Validation extends org.apache.dubbo.validation.Validation {}\n"
  },
  {
    "path": "dubbo-compatible/src/main/java/com/alibaba/dubbo/validation/Validator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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.dubbo.validation;\n\n@Deprecated\npublic interface Validator extends org.apache.dubbo.validation.Validator {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/cache/CacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache;\n\nimport org.apache.dubbo.rpc.RpcInvocation;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.cache.Cache;\nimport com.alibaba.dubbo.cache.CacheFactory;\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.rpc.Invocation;\nimport com.alibaba.dubbo.rpc.Invoker;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass CacheTest {\n\n    @Test\n    void testCacheFactory() {\n        URL url = URL.valueOf(\"test://test:11/test?cache=jacache&.cache.write.expire=1\");\n        CacheFactory cacheFactory = new MyCacheFactory();\n        Invocation invocation = new NullInvocation();\n        Cache cache = cacheFactory.getCache(url, invocation);\n        cache.put(\"testKey\", \"testValue\");\n\n        org.apache.dubbo.cache.CacheFactory factory = cacheFactory;\n        org.apache.dubbo.common.URL u =\n                org.apache.dubbo.common.URL.valueOf(\"test://test:11/test?cache=jacache&.cache.write.expire=1\");\n        org.apache.dubbo.rpc.Invocation inv = new RpcInvocation();\n        org.apache.dubbo.cache.Cache c = factory.getCache(u, inv);\n        String v = (String) c.get(\"testKey\");\n        Assertions.assertEquals(\"testValue\", v);\n    }\n\n    static class NullInvocation implements Invocation {\n        @Override\n        public String getTargetServiceUniqueName() {\n            return null;\n        }\n\n        @Override\n        public String getProtocolServiceKey() {\n            return null;\n        }\n\n        @Override\n        public String getMethodName() {\n            return null;\n        }\n\n        @Override\n        public Class<?>[] getParameterTypes() {\n            return new Class[0];\n        }\n\n        @Override\n        public Object[] getArguments() {\n            return new Object[0];\n        }\n\n        @Override\n        public Map<String, String> getAttachments() {\n            return null;\n        }\n\n        @Override\n        public String getAttachment(String key) {\n            return null;\n        }\n\n        @Override\n        public String getAttachment(String key, String defaultValue) {\n            return null;\n        }\n\n        @Override\n        public Invoker<?> getInvoker() {\n            return null;\n        }\n\n        @Override\n        public Object put(Object key, Object value) {\n            return null;\n        }\n\n        @Override\n        public Object get(Object key) {\n            return null;\n        }\n\n        @Override\n        public Map<Object, Object> getAttributes() {\n            return null;\n        }\n\n        @Override\n        public void addInvokedInvoker(org.apache.dubbo.rpc.Invoker<?> invoker) {}\n\n        @Override\n        public List<org.apache.dubbo.rpc.Invoker<?>> getInvokedInvokers() {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/cache/MyCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.cache.Cache;\nimport com.alibaba.dubbo.common.URL;\n\npublic class MyCache implements Cache {\n\n    private Map<Object, Object> map = new HashMap<Object, Object>();\n\n    public MyCache(URL url) {}\n\n    @Override\n    public void put(Object key, Object value) {\n        map.put(key, value);\n    }\n\n    @Override\n    public Object get(Object key) {\n        return map.get(key);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/cache/MyCacheFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache;\n\nimport com.alibaba.dubbo.cache.Cache;\nimport com.alibaba.dubbo.cache.support.AbstractCacheFactory;\nimport com.alibaba.dubbo.common.URL;\n\npublic class MyCacheFactory extends AbstractCacheFactory {\n\n    @Override\n    protected Cache createCache(URL url) {\n        return new MyCache(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/ExtensionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\nimport org.apache.dubbo.common.extension.activate.impl.OldActivateExt1Impl2;\nimport org.apache.dubbo.common.extension.activate.impl.OldActivateExt1Impl3;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass ExtensionTest {\n\n    @Test\n    void testExtensionFactory() {\n        try {\n            ExtensionInjector myfactory =\n                    ExtensionLoader.getExtensionLoader(ExtensionInjector.class).getExtension(\"myfactory\");\n            Assertions.assertTrue(myfactory instanceof ExtensionInjector);\n            Assertions.assertTrue(myfactory instanceof ExtensionFactory);\n            Assertions.assertTrue(myfactory instanceof com.alibaba.dubbo.common.extension.ExtensionFactory);\n            Assertions.assertTrue(myfactory instanceof MyExtensionFactory);\n\n            ExtensionInjector spring =\n                    ExtensionLoader.getExtensionLoader(ExtensionInjector.class).getExtension(\"spring\");\n            Assertions.assertTrue(spring instanceof ExtensionInjector);\n            Assertions.assertFalse(spring instanceof ExtensionFactory);\n            Assertions.assertFalse(spring instanceof com.alibaba.dubbo.common.extension.ExtensionFactory);\n        } catch (IllegalArgumentException expected) {\n            fail();\n        }\n    }\n\n    private <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        return ApplicationModel.defaultModel().getExtensionDirector().getExtensionLoader(type);\n    }\n\n    @Test\n    void testLoadActivateExtension() {\n        // test default\n        URL url = URL.valueOf(\"test://localhost/test\").addParameter(GROUP_KEY, \"old_group\");\n        List<ActivateExt1> list =\n                getExtensionLoader(ActivateExt1.class).getActivateExtension(url, new String[] {}, \"old_group\");\n        Assertions.assertEquals(2, list.size());\n        Assertions.assertTrue(list.get(0).getClass() == OldActivateExt1Impl2.class\n                || list.get(0).getClass() == OldActivateExt1Impl3.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/MockDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Dispatcher;\n\npublic class MockDispatcher implements Dispatcher {\n    @Override\n    public ChannelHandler dispatch(ChannelHandler handler, URL url) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/MyExtensionFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension;\n\nimport com.alibaba.dubbo.common.extension.ExtensionFactory;\n\npublic class MyExtensionFactory implements ExtensionFactory {\n\n    @Override\n    public <T> T getExtension(final Class<T> type, final String name) {\n        if (type == InjectObject.class) {\n            return (T) new InjectObject(name);\n        }\n        return null;\n    }\n\n    public static class InjectObject {\n\n        private final String name;\n\n        public InjectObject(final String name) {\n            this.name = name;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/activate/ActivateExt1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(\"impl1\")\npublic interface ActivateExt1 {\n    String echo(String msg);\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/activate/impl/ActivateExt1Impl1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\n\n@Activate(\n        order = 1,\n        group = {\"default_group\"})\npublic class ActivateExt1Impl1 implements ActivateExt1 {\n    public String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/activate/impl/OldActivateExt1Impl2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\n\nimport com.alibaba.dubbo.common.extension.Activate;\n\n@Activate(group = \"old_group\")\npublic class OldActivateExt1Impl2 implements ActivateExt1 {\n    public String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/activate/impl/OldActivateExt1Impl3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.activate.impl;\n\nimport org.apache.dubbo.common.extension.activate.ActivateExt1;\n\nimport com.alibaba.dubbo.common.extension.Activate;\n\n@Activate(group = \"old_group\")\npublic class OldActivateExt1Impl3 implements ActivateExt1 {\n    public String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/ActivateComparatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass ActivateComparatorTest {\n\n    private ActivateComparator activateComparator;\n\n    @BeforeEach\n    public void setup() {\n        activateComparator =\n                new ActivateComparator(ApplicationModel.defaultModel().getExtensionDirector());\n    }\n\n    @Test\n    void testActivateComparator() {\n        Filter1 f1 = new Filter1();\n        Filter2 f2 = new Filter2();\n        Filter3 f3 = new Filter3();\n        Filter4 f4 = new Filter4();\n        OldFilter5 f5 = new OldFilter5();\n        List<Class<?>> filters = new ArrayList<>();\n        filters.add(f1.getClass());\n        filters.add(f2.getClass());\n        filters.add(f3.getClass());\n        filters.add(f4.getClass());\n        filters.add(f5.getClass());\n\n        Collections.sort(filters, activateComparator);\n\n        Assertions.assertEquals(f4.getClass(), filters.get(0));\n        Assertions.assertEquals(f5.getClass(), filters.get(1));\n        Assertions.assertEquals(f3.getClass(), filters.get(2));\n        Assertions.assertEquals(f2.getClass(), filters.get(3));\n        Assertions.assertEquals(f1.getClass(), filters.get(4));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/Filter0.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface Filter0 {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/Filter1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate\npublic class Filter1 implements Filter0 {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/Filter2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate(before = \"_1\")\npublic class Filter2 implements Filter0 {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/Filter3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate(after = \"_4\")\npublic class Filter3 implements Filter0 {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/Filter4.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate(before = \"_2\")\npublic class Filter4 implements Filter0 {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/OldFilter0.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\npublic interface OldFilter0 extends Filter0 {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/OldFilter5.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport com.alibaba.dubbo.common.extension.Activate;\n\n@Activate(after = \"_4\")\npublic class OldFilter5 implements OldFilter0 {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/Order0Filter0.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface Order0Filter0 {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/Order0Filter1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate\npublic class Order0Filter1 implements Order0Filter0 {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/extension/support/Order0Filter2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.extension.support;\n\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate\npublic class Order0Filter2 implements Order0Filter0 {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/common/utils/AnnotationUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.utils;\n\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.annotation.Service;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.excludedType;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.findAnnotation;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotation;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotations;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAllDeclaredAnnotations;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAllMetaAnnotations;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAnnotation;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAttribute;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getAttributes;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getDeclaredAnnotations;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getDefaultValue;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getMetaAnnotations;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.getValue;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.isAnnotationPresent;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.isAnyAnnotationPresent;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.isSameType;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.isType;\nimport static org.apache.dubbo.common.utils.MethodUtils.findMethod;\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link AnnotationUtils} Test\n *\n * @since 2.7.6\n */\nclass AnnotationUtilsTest {\n\n    @Test\n    void testIsType() {\n        // null checking\n        assertFalse(isType(null));\n        // Method checking\n        assertFalse(isType(findMethod(A.class, \"execute\")));\n        // Class checking\n        assertTrue(isType(A.class));\n    }\n\n    @Test\n    void testIsSameType() {\n        assertTrue(isSameType(A.class.getAnnotation(Service.class), Service.class));\n        assertFalse(isSameType(A.class.getAnnotation(Service.class), Deprecated.class));\n        assertFalse(isSameType(A.class.getAnnotation(Service.class), null));\n        assertFalse(isSameType(null, Deprecated.class));\n        assertFalse(isSameType(null, null));\n    }\n\n    @Test\n    void testExcludedType() {\n        assertFalse(excludedType(Service.class).test(A.class.getAnnotation(Service.class)));\n        assertTrue(excludedType(Service.class).test(A.class.getAnnotation(Deprecated.class)));\n    }\n\n    @Test\n    void testGetAttribute() {\n        Annotation annotation = A.class.getAnnotation(Service.class);\n        assertEquals(\"java.lang.CharSequence\", getAttribute(annotation, \"interfaceName\"));\n        assertEquals(CharSequence.class, getAttribute(annotation, \"interfaceClass\"));\n        assertEquals(\"\", getAttribute(annotation, \"version\"));\n        assertEquals(\"\", getAttribute(annotation, \"group\"));\n        assertEquals(\"\", getAttribute(annotation, \"path\"));\n        assertEquals(true, getAttribute(annotation, \"export\"));\n        assertEquals(false, getAttribute(annotation, \"deprecated\"));\n    }\n\n    @Test\n    void testGetAttributesMap() {\n        Annotation annotation = A.class.getAnnotation(Service.class);\n        Map<String, Object> attributes = getAttributes(annotation, false);\n        assertEquals(\"java.lang.CharSequence\", attributes.get(\"interfaceName\"));\n        assertEquals(CharSequence.class, attributes.get(\"interfaceClass\"));\n        assertEquals(\"\", attributes.get(\"group\"));\n        assertEquals(getDefaultValue(annotation, \"export\"), attributes.get(\"export\"));\n\n        Map<String, Object> filteredAttributes = filterDefaultValues(annotation, attributes);\n        assertEquals(2, filteredAttributes.size());\n        assertEquals(\"java.lang.CharSequence\", filteredAttributes.get(\"interfaceName\"));\n        assertEquals(CharSequence.class, filteredAttributes.get(\"interfaceClass\"));\n        assertFalse(filteredAttributes.containsKey(\"group\"));\n        assertFalse(filteredAttributes.containsKey(\"export\"));\n\n        Map<String, Object> nonDefaultAttributes = getAttributes(annotation, true);\n        assertEquals(nonDefaultAttributes, filteredAttributes);\n    }\n\n    @Test\n    void testGetValue() {\n        Adaptive adaptive = A.class.getAnnotation(Adaptive.class);\n        String[] value = getValue(adaptive);\n        assertEquals(asList(\"a\", \"b\", \"c\"), asList(value));\n    }\n\n    @Test\n    void testGetDeclaredAnnotations() {\n        List<Annotation> annotations = getDeclaredAnnotations(A.class);\n        assertADeclaredAnnotations(annotations, 0);\n\n        annotations = getDeclaredAnnotations(A.class, a -> isSameType(a, Service.class));\n        assertEquals(1, annotations.size());\n        Service service = (Service) annotations.get(0);\n        assertEquals(\"java.lang.CharSequence\", service.interfaceName());\n        assertEquals(CharSequence.class, service.interfaceClass());\n    }\n\n    @Test\n    void testGetAllDeclaredAnnotations() {\n        List<Annotation> annotations = getAllDeclaredAnnotations(A.class);\n        assertADeclaredAnnotations(annotations, 0);\n\n        annotations = getAllDeclaredAnnotations(B.class);\n        assertTrue(isSameType(annotations.get(0), Service5.class));\n        assertADeclaredAnnotations(annotations, 1);\n\n        annotations = new LinkedList<>(getAllDeclaredAnnotations(C.class));\n        assertTrue(isSameType(annotations.get(0), MyAdaptive.class));\n        assertTrue(isSameType(annotations.get(1), Service5.class));\n        assertADeclaredAnnotations(annotations, 2);\n\n        annotations = getAllDeclaredAnnotations(findMethod(A.class, \"execute\"));\n        MyAdaptive myAdaptive = (MyAdaptive) annotations.get(0);\n        assertArrayEquals(new String[] {\"e\"}, myAdaptive.value());\n\n        annotations = getAllDeclaredAnnotations(findMethod(B.class, \"execute\"));\n        Adaptive adaptive = (Adaptive) annotations.get(0);\n        assertArrayEquals(new String[] {\"f\"}, adaptive.value());\n    }\n\n    @Test\n    void testGetMetaAnnotations() {\n        List<Annotation> metaAnnotations = getMetaAnnotations(Service.class, a -> isSameType(a, Inherited.class));\n        assertEquals(1, metaAnnotations.size());\n        assertEquals(Inherited.class, metaAnnotations.get(0).annotationType());\n\n        metaAnnotations = getMetaAnnotations(Service.class);\n        HashSet<Object> set1 = new HashSet<>();\n        metaAnnotations.forEach(t -> set1.add(t.annotationType()));\n        HashSet<Object> set2 = new HashSet<>();\n        set2.add(Inherited.class);\n        set2.add(Deprecated.class);\n        assertEquals(2, metaAnnotations.size());\n        assertEquals(set1, set2);\n    }\n\n    @Test\n    void testGetAllMetaAnnotations() {\n        List<Annotation> metaAnnotations = getAllMetaAnnotations(Service5.class);\n        int offset = 0;\n\n        HashSet<Object> set1 = new HashSet<>();\n        metaAnnotations.forEach(t -> set1.add(t.annotationType()));\n        HashSet<Object> set2 = new HashSet<>();\n        set2.add(Inherited.class);\n        set2.add(DubboService.class);\n        set2.add(Service4.class);\n        set2.add(Service3.class);\n        set2.add(Service2.class);\n        assertEquals(9, metaAnnotations.size());\n        assertEquals(set1, set2);\n\n        metaAnnotations = getAllMetaAnnotations(MyAdaptive.class);\n        HashSet<Object> set3 = new HashSet<>();\n        metaAnnotations.forEach(t -> set3.add(t.annotationType()));\n        HashSet<Object> set4 = new HashSet<>();\n        metaAnnotations.forEach(t -> set3.add(t.annotationType()));\n        set4.add(Inherited.class);\n        set4.add(Adaptive.class);\n        assertEquals(2, metaAnnotations.size());\n        assertEquals(set3, set4);\n    }\n\n    @Test\n    void testIsAnnotationPresent() {\n        assertTrue(isAnnotationPresent(A.class, true, Service.class));\n        assertTrue(\n                isAnnotationPresent(A.class, true, Service.class, com.alibaba.dubbo.config.annotation.Service.class));\n        assertTrue(isAnnotationPresent(A.class, Service.class));\n        assertTrue(isAnnotationPresent(A.class, \"org.apache.dubbo.config.annotation.Service\"));\n        assertTrue(AnnotationUtils.isAllAnnotationPresent(\n                A.class, Service.class, Service.class, com.alibaba.dubbo.config.annotation.Service.class));\n        assertTrue(isAnnotationPresent(A.class, Deprecated.class));\n    }\n\n    @Test\n    void testIsAnyAnnotationPresent() {\n        assertTrue(isAnyAnnotationPresent(\n                A.class, Service.class, com.alibaba.dubbo.config.annotation.Service.class, Deprecated.class));\n        assertTrue(isAnyAnnotationPresent(A.class, Service.class, com.alibaba.dubbo.config.annotation.Service.class));\n        assertTrue(isAnyAnnotationPresent(A.class, Service.class, Deprecated.class));\n        assertTrue(\n                isAnyAnnotationPresent(A.class, com.alibaba.dubbo.config.annotation.Service.class, Deprecated.class));\n        assertTrue(isAnyAnnotationPresent(A.class, Service.class));\n        assertTrue(isAnyAnnotationPresent(A.class, com.alibaba.dubbo.config.annotation.Service.class));\n        assertTrue(isAnyAnnotationPresent(A.class, Deprecated.class));\n    }\n\n    @Test\n    void testGetAnnotation() {\n        assertNotNull(getAnnotation(A.class, \"org.apache.dubbo.config.annotation.Service\"));\n        assertNotNull(getAnnotation(A.class, \"com.alibaba.dubbo.config.annotation.Service\"));\n        assertNotNull(getAnnotation(A.class, \"org.apache.dubbo.common.extension.Adaptive\"));\n        assertNull(getAnnotation(A.class, \"java.lang.Deprecated\"));\n        assertNull(getAnnotation(A.class, \"java.lang.String\"));\n        assertNull(getAnnotation(A.class, \"NotExistedClass\"));\n    }\n\n    @Test\n    void testFindAnnotation() {\n        Service service = findAnnotation(A.class, Service.class);\n        assertEquals(\"java.lang.CharSequence\", service.interfaceName());\n        assertEquals(CharSequence.class, service.interfaceClass());\n\n        service = findAnnotation(B.class, Service.class);\n        assertEquals(CharSequence.class, service.interfaceClass());\n    }\n\n    @Test\n    void testFindMetaAnnotations() {\n        List<DubboService> services = findMetaAnnotations(B.class, DubboService.class);\n        assertEquals(1, services.size());\n\n        DubboService service = services.get(0);\n        assertEquals(\"\", service.interfaceName());\n        assertEquals(Cloneable.class, service.interfaceClass());\n\n        services = findMetaAnnotations(Service5.class, DubboService.class);\n        assertEquals(1, services.size());\n\n        service = services.get(0);\n        assertEquals(\"\", service.interfaceName());\n        assertEquals(Cloneable.class, service.interfaceClass());\n    }\n\n    @Test\n    void testFindMetaAnnotation() {\n        DubboService service = findMetaAnnotation(B.class, DubboService.class);\n        assertEquals(Cloneable.class, service.interfaceClass());\n\n        service = findMetaAnnotation(B.class, \"org.apache.dubbo.config.annotation.DubboService\");\n        assertEquals(Cloneable.class, service.interfaceClass());\n\n        service = findMetaAnnotation(Service5.class, DubboService.class);\n        assertEquals(Cloneable.class, service.interfaceClass());\n    }\n\n    @Service(interfaceName = \"java.lang.CharSequence\", interfaceClass = CharSequence.class)\n    @com.alibaba.dubbo.config.annotation.Service(\n            interfaceName = \"java.lang.CharSequence\",\n            interfaceClass = CharSequence.class)\n    @Adaptive(value = {\"a\", \"b\", \"c\"})\n    static class A {\n\n        @MyAdaptive(\"e\")\n        public void execute() {}\n    }\n\n    @Documented\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.TYPE})\n    @Inherited\n    @DubboService(interfaceClass = Cloneable.class)\n    @interface Service2 {}\n\n    @Documented\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.TYPE})\n    @Inherited\n    @Service2\n    @interface Service3 {}\n\n    @Documented\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.TYPE})\n    @Inherited\n    @Service3\n    @interface Service4 {}\n\n    @Documented\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.TYPE})\n    @Inherited\n    @Service4\n    @interface Service5 {}\n\n    @Documented\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.TYPE, ElementType.METHOD})\n    @Inherited\n    @Adaptive\n    @interface MyAdaptive {\n\n        String[] value() default {};\n    }\n\n    @Service5\n    static class B extends A {\n\n        @Adaptive(\"f\")\n        @Override\n        public void execute() {}\n    }\n\n    @MyAdaptive\n    static class C extends B {}\n\n    private void assertADeclaredAnnotations(List<Annotation> annotations, int offset) {\n        int size = 3 + offset;\n        assertEquals(size, annotations.size());\n        boolean apacheServiceFound = false;\n        boolean alibabaServiceFound = false;\n        boolean adaptiveFound = false;\n\n        for (Annotation annotation : annotations) {\n            if (!apacheServiceFound && (annotation instanceof Service)) {\n                assertEquals(\"java.lang.CharSequence\", ((Service) annotation).interfaceName());\n                assertEquals(CharSequence.class, ((Service) annotation).interfaceClass());\n                apacheServiceFound = true;\n                continue;\n            }\n            if (!alibabaServiceFound && (annotation instanceof com.alibaba.dubbo.config.annotation.Service)) {\n                assertEquals(\n                        \"java.lang.CharSequence\",\n                        ((com.alibaba.dubbo.config.annotation.Service) annotation).interfaceName());\n                assertEquals(\n                        CharSequence.class,\n                        ((com.alibaba.dubbo.config.annotation.Service) annotation).interfaceClass());\n                alibabaServiceFound = true;\n                continue;\n            }\n            if (!adaptiveFound && (annotation instanceof Adaptive)) {\n                assertArrayEquals(new String[] {\"a\", \"b\", \"c\"}, ((Adaptive) annotation).value());\n                adaptiveFound = true;\n                continue;\n            }\n        }\n        assertTrue(apacheServiceFound && alibabaServiceFound && adaptiveFound);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/ApplicationConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.config.ApplicationConfig;\nimport com.alibaba.dubbo.config.MonitorConfig;\nimport com.alibaba.dubbo.config.RegistryConfig;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.contains;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.sameInstance;\nimport static org.hamcrest.collection.IsCollectionWithSize.hasSize;\n\nclass ApplicationConfigTest {\n    @Test\n    void testName() {\n        ApplicationConfig application = new ApplicationConfig();\n        application.setName(\"app\");\n        assertThat(application.getName(), equalTo(\"app\"));\n        application = new ApplicationConfig(\"app2\");\n        assertThat(application.getName(), equalTo(\"app2\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(APPLICATION_KEY, \"app2\"));\n    }\n\n    @Test\n    void testVersion() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setVersion(\"1.0.0\");\n        assertThat(application.getVersion(), equalTo(\"1.0.0\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(\"application.version\", \"1.0.0\"));\n    }\n\n    @Test\n    void testOwner() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setOwner(\"owner\");\n        assertThat(application.getOwner(), equalTo(\"owner\"));\n    }\n\n    @Test\n    void testOrganization() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setOrganization(\"org\");\n        assertThat(application.getOrganization(), equalTo(\"org\"));\n    }\n\n    @Test\n    void testArchitecture() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setArchitecture(\"arch\");\n        assertThat(application.getArchitecture(), equalTo(\"arch\"));\n    }\n\n    @Test\n    void testEnvironment1() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setEnvironment(\"develop\");\n        assertThat(application.getEnvironment(), equalTo(\"develop\"));\n        application.setEnvironment(\"test\");\n        assertThat(application.getEnvironment(), equalTo(\"test\"));\n        application.setEnvironment(\"product\");\n        assertThat(application.getEnvironment(), equalTo(\"product\"));\n    }\n\n    @Test\n    void testEnvironment2() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            ApplicationConfig application = new ApplicationConfig(\"app\");\n            application.setEnvironment(\"illegal-env\");\n        });\n    }\n\n    @Test\n    void testRegistry() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        RegistryConfig registry = new RegistryConfig();\n        application.setRegistry(registry);\n        assertThat(application.getRegistry(), sameInstance(registry));\n        application.setRegistries(Collections.singletonList(registry));\n        assertThat(application.getRegistries(), contains(registry));\n        assertThat(application.getRegistries(), hasSize(1));\n    }\n\n    @Test\n    void testMonitor() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setMonitor(new MonitorConfig(\"monitor-addr\"));\n        assertThat(application.getMonitor().getAddress(), equalTo(\"monitor-addr\"));\n        application.setMonitor(\"monitor-addr\");\n        assertThat(application.getMonitor().getAddress(), equalTo(\"monitor-addr\"));\n    }\n\n    @Test\n    void testLogger() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setLogger(\"log4j2\");\n        assertThat(application.getLogger(), equalTo(\"log4j2\"));\n    }\n\n    @Test\n    void testDefault() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setDefault(true);\n        assertThat(application.isDefault(), is(true));\n    }\n\n    @Test\n    void testDumpDirectory() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setDumpDirectory(\"/dump\");\n        assertThat(application.getDumpDirectory(), equalTo(\"/dump\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(DUMP_DIRECTORY, \"/dump\"));\n    }\n\n    @Test\n    void testQosEnable() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setQosEnable(true);\n        assertThat(application.getQosEnable(), is(true));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(QOS_ENABLE, \"true\"));\n    }\n\n    @Test\n    void testQosPort() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setQosPort(8080);\n        assertThat(application.getQosPort(), equalTo(8080));\n    }\n\n    @Test\n    void testQosAcceptForeignIp() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setQosAcceptForeignIp(true);\n        assertThat(application.getQosAcceptForeignIp(), is(true));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(ACCEPT_FOREIGN_IP, \"true\"));\n    }\n\n    @Test\n    void testParameters() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setQosAcceptForeignIp(true);\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(\"k1\", \"v1\");\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(\"k1\", \"v1\"));\n        assertThat(parameters, hasEntry(ACCEPT_FOREIGN_IP, \"true\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/ArgumentConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.config.ArgumentConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.is;\n\nclass ArgumentConfigTest {\n    @Test\n    void testIndex() {\n        ArgumentConfig argument = new ArgumentConfig();\n        argument.setIndex(1);\n        assertThat(argument.getIndex(), is(1));\n    }\n\n    @Test\n    void testType() {\n        ArgumentConfig argument = new ArgumentConfig();\n        argument.setType(\"int\");\n        assertThat(argument.getType(), equalTo(\"int\"));\n    }\n\n    @Test\n    void testCallback() {\n        ArgumentConfig argument = new ArgumentConfig();\n        argument.setCallback(true);\n        assertThat(argument.isCallback(), is(true));\n    }\n\n    @Test\n    void testArguments() {\n        ArgumentConfig argument = new ArgumentConfig();\n        argument.setIndex(1);\n        argument.setType(\"int\");\n        argument.setCallback(true);\n        Map<String, String> parameters = new HashMap<String, String>();\n        AbstractServiceConfig.appendParameters(parameters, argument);\n        assertThat(parameters, hasEntry(\"callback\", \"true\"));\n        assertThat(parameters.size(), is(1));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/ConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.service.DemoService;\nimport org.apache.dubbo.service.DemoServiceImpl;\n\nimport com.alibaba.dubbo.config.ReferenceConfig;\nimport com.alibaba.dubbo.config.ServiceConfig;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass ConfigTest {\n    private com.alibaba.dubbo.config.ApplicationConfig applicationConfig =\n            new com.alibaba.dubbo.config.ApplicationConfig(\"first-dubbo-test\");\n    private com.alibaba.dubbo.config.RegistryConfig registryConfig =\n            new com.alibaba.dubbo.config.RegistryConfig(\"multicast://224.5.6.7:1234\");\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n    }\n\n    @BeforeEach\n    public void setup() {\n        // In IDE env, make sure adding the following argument to VM options\n        System.setProperty(\"java.net.preferIPv4Stack\", \"true\");\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testConfig() {\n        com.alibaba.dubbo.config.ServiceConfig<DemoService> service = new ServiceConfig<>();\n        service.setApplication(applicationConfig);\n        service.setRegistry(registryConfig);\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n\n        com.alibaba.dubbo.config.ReferenceConfig<DemoService> reference = new ReferenceConfig<>();\n        reference.setApplication(applicationConfig);\n        reference.setRegistry(registryConfig);\n        reference.setInterface(DemoService.class);\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance()\n                .application(applicationConfig)\n                .registry(registryConfig)\n                .service(service)\n                .reference(reference)\n                .start();\n\n        DemoService demoService = bootstrap.getCache().get(reference);\n        String message = demoService.sayHello(\"dubbo\");\n        Assertions.assertEquals(\"hello dubbo\", message);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport com.alibaba.dubbo.config.ConsumerConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_TCP_RESPONSE_TIMEOUT;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\n\nclass ConsumerConfigTest {\n    @Test\n    void testTimeout() throws Exception {\n        try {\n            SystemPropertyConfigUtils.clearSystemProperty(SYSTEM_TCP_RESPONSE_TIMEOUT);\n            ConsumerConfig consumer = new ConsumerConfig();\n            consumer.setTimeout(10);\n            assertThat(consumer.getTimeout(), is(10));\n            assertThat(SystemPropertyConfigUtils.getSystemProperty(SYSTEM_TCP_RESPONSE_TIMEOUT), equalTo(\"10\"));\n        } finally {\n            SystemPropertyConfigUtils.clearSystemProperty(SYSTEM_TCP_RESPONSE_TIMEOUT);\n        }\n    }\n\n    @Test\n    void testDefault() throws Exception {\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setDefault(true);\n        assertThat(consumer.isDefault(), is(true));\n    }\n\n    @Test\n    void testClient() throws Exception {\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setClient(\"client\");\n        assertThat(consumer.getClient(), equalTo(\"client\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/MethodConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.rpc.model.AsyncMethodInfo;\nimport org.apache.dubbo.service.Person;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.config.ArgumentConfig;\nimport com.alibaba.dubbo.config.MethodConfig;\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.config.Constants.ON_INVOKE_INSTANCE_ATTRIBUTE_KEY;\nimport static org.apache.dubbo.config.Constants.ON_INVOKE_METHOD_ATTRIBUTE_KEY;\nimport static org.apache.dubbo.config.Constants.ON_RETURN_INSTANCE_ATTRIBUTE_KEY;\nimport static org.apache.dubbo.config.Constants.ON_RETURN_METHOD_ATTRIBUTE_KEY;\nimport static org.apache.dubbo.config.Constants.ON_THROW_INSTANCE_ATTRIBUTE_KEY;\nimport static org.apache.dubbo.config.Constants.ON_THROW_METHOD_ATTRIBUTE_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.contains;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.hasKey;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.not;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass MethodConfigTest {\n    @Test\n    void testName() {\n        MethodConfig method = new MethodConfig();\n        method.setName(\"hello\");\n        assertThat(method.getName(), equalTo(\"hello\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters, not(hasKey(\"name\")));\n    }\n\n    @Test\n    void testStat() {\n        MethodConfig method = new MethodConfig();\n        method.setStat(10);\n        assertThat(method.getStat(), equalTo(10));\n    }\n\n    @Test\n    void testRetry() {\n        MethodConfig method = new MethodConfig();\n        method.setRetry(true);\n        assertThat(method.isRetry(), is(true));\n    }\n\n    @Test\n    void testReliable() {\n        MethodConfig method = new MethodConfig();\n        method.setReliable(true);\n        assertThat(method.isReliable(), is(true));\n    }\n\n    @Test\n    void testExecutes() {\n        MethodConfig method = new MethodConfig();\n        method.setExecutes(10);\n        assertThat(method.getExecutes(), equalTo(10));\n    }\n\n    @Test\n    void testDeprecated() {\n        MethodConfig method = new MethodConfig();\n        method.setDeprecated(true);\n        assertThat(method.getDeprecated(), is(true));\n    }\n\n    @Test\n    void testArguments() {\n        MethodConfig method = new MethodConfig();\n        ArgumentConfig argument = new ArgumentConfig();\n        method.setArguments(Collections.singletonList(argument));\n        assertThat(method.getArguments(), contains(argument));\n        assertThat(method.getArguments(), Matchers.<org.apache.dubbo.config.ArgumentConfig>hasSize(1));\n    }\n\n    @Test\n    void testSticky() {\n        MethodConfig method = new MethodConfig();\n        method.setSticky(true);\n        assertThat(method.getSticky(), is(true));\n    }\n\n    @Test\n    void testConvertMethodConfig2AsyncInfo() throws Exception {\n        MethodConfig methodConfig = new MethodConfig();\n        String methodName = \"setName\";\n        methodConfig.setOninvokeMethod(methodName);\n        methodConfig.setOnthrowMethod(methodName);\n        methodConfig.setOnreturnMethod(methodName);\n        methodConfig.setOninvoke(new Person());\n        methodConfig.setOnthrow(new Person());\n        methodConfig.setOnreturn(new Person());\n\n        AsyncMethodInfo methodInfo = methodConfig.convertMethodConfig2AsyncInfo();\n\n        assertEquals(methodInfo.getOninvokeMethod(), Person.class.getMethod(methodName, String.class));\n        assertEquals(methodInfo.getOnthrowMethod(), Person.class.getMethod(methodName, String.class));\n        assertEquals(methodInfo.getOnreturnMethod(), Person.class.getMethod(methodName, String.class));\n    }\n\n    // @Test\n    void testOnreturn() {\n        MethodConfig method = new MethodConfig();\n        method.setOnreturn(\"on-return-object\");\n        assertThat(method.getOnreturn(), equalTo(\"on-return-object\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_RETURN_INSTANCE_ATTRIBUTE_KEY, \"on-return-object\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    @Test\n    void testOnreturnMethod() {\n        MethodConfig method = new MethodConfig();\n        method.setOnreturnMethod(\"on-return-method\");\n        assertThat(method.getOnreturnMethod(), equalTo(\"on-return-method\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_RETURN_METHOD_ATTRIBUTE_KEY, \"on-return-method\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    // @Test\n    void testOnthrow() {\n        MethodConfig method = new MethodConfig();\n        method.setOnthrow(\"on-throw-object\");\n        assertThat(method.getOnthrow(), equalTo(\"on-throw-object\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_THROW_INSTANCE_ATTRIBUTE_KEY, \"on-throw-object\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    @Test\n    void testOnthrowMethod() {\n        MethodConfig method = new MethodConfig();\n        method.setOnthrowMethod(\"on-throw-method\");\n        assertThat(method.getOnthrowMethod(), equalTo(\"on-throw-method\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_THROW_METHOD_ATTRIBUTE_KEY, \"on-throw-method\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    // @Test\n    void testOninvoke() {\n        MethodConfig method = new MethodConfig();\n        method.setOninvoke(\"on-invoke-object\");\n        assertThat(method.getOninvoke(), equalTo(\"on-invoke-object\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_INVOKE_INSTANCE_ATTRIBUTE_KEY, \"on-invoke-object\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    @Test\n    void testOninvokeMethod() {\n        MethodConfig method = new MethodConfig();\n        method.setOninvokeMethod(\"on-invoke-method\");\n        assertThat(method.getOninvokeMethod(), equalTo(\"on-invoke-method\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_INVOKE_METHOD_ATTRIBUTE_KEY, \"on-invoke-method\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    @Test\n    void testReturn() {\n        MethodConfig method = new MethodConfig();\n        method.setReturn(true);\n        assertThat(method.isReturn(), is(true));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/ModuleConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.config.ModuleConfig;\nimport com.alibaba.dubbo.config.MonitorConfig;\nimport com.alibaba.dubbo.config.RegistryConfig;\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.contains;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.sameInstance;\n\nclass ModuleConfigTest {\n\n    @Test\n    void testName2() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setName(\"module-name\");\n        assertThat(module.getName(), equalTo(\"module-name\"));\n        assertThat(module.getId(), equalTo(null));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ModuleConfig.appendParameters(parameters, module);\n        assertThat(parameters, hasEntry(\"module\", \"module-name\"));\n    }\n\n    @Test\n    void testVersion() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setName(\"module-name\");\n        module.setVersion(\"1.0.0\");\n        assertThat(module.getVersion(), equalTo(\"1.0.0\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ModuleConfig.appendParameters(parameters, module);\n        assertThat(parameters, hasEntry(\"module.version\", \"1.0.0\"));\n    }\n\n    @Test\n    void testOwner() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setOwner(\"owner\");\n        assertThat(module.getOwner(), equalTo(\"owner\"));\n    }\n\n    @Test\n    void testOrganization() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setOrganization(\"org\");\n        assertThat(module.getOrganization(), equalTo(\"org\"));\n    }\n\n    @Test\n    void testRegistry() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        RegistryConfig registry = new RegistryConfig();\n        module.setRegistry(registry);\n        assertThat(module.getRegistry(), sameInstance(registry));\n    }\n\n    @Test\n    void testRegistries() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        RegistryConfig registry = new RegistryConfig();\n        module.setRegistries(Collections.singletonList(registry));\n        assertThat(module.getRegistries(), Matchers.<org.apache.dubbo.config.RegistryConfig>hasSize(1));\n        assertThat(module.getRegistries(), contains(registry));\n    }\n\n    @Test\n    void testMonitor() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setMonitor(\"monitor-addr1\");\n        assertThat(module.getMonitor().getAddress(), equalTo(\"monitor-addr1\"));\n        module.setMonitor(new MonitorConfig(\"monitor-addr2\"));\n        assertThat(module.getMonitor().getAddress(), equalTo(\"monitor-addr2\"));\n    }\n\n    @Test\n    void testDefault() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setDefault(true);\n        assertThat(module.isDefault(), is(true));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/ProtocolConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.config.ProtocolConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.is;\n\nclass ProtocolConfigTest {\n\n    @Test\n    void testName() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setName(\"name\");\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProtocolConfig.appendParameters(parameters, protocol);\n        assertThat(protocol.getName(), equalTo(\"name\"));\n        assertThat(protocol.getId(), equalTo(null));\n        assertThat(parameters.isEmpty(), is(true));\n    }\n\n    @Test\n    void testHost() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setHost(\"host\");\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProtocolConfig.appendParameters(parameters, protocol);\n        assertThat(protocol.getHost(), equalTo(\"host\"));\n        assertThat(parameters.isEmpty(), is(true));\n    }\n\n    @Test\n    void testPort() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setPort(8080);\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProtocolConfig.appendParameters(parameters, protocol);\n        assertThat(protocol.getPort(), equalTo(8080));\n        assertThat(parameters.isEmpty(), is(true));\n    }\n\n    @Test\n    void testPath() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setContextpath(\"context-path\");\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProtocolConfig.appendParameters(parameters, protocol);\n        assertThat(protocol.getPath(), equalTo(\"context-path\"));\n        assertThat(protocol.getContextpath(), equalTo(\"context-path\"));\n        assertThat(parameters.isEmpty(), is(true));\n        protocol.setPath(\"path\");\n        assertThat(protocol.getPath(), equalTo(\"path\"));\n        assertThat(protocol.getContextpath(), equalTo(\"path\"));\n    }\n\n    @Test\n    void testThreads() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setThreads(10);\n        assertThat(protocol.getThreads(), is(10));\n    }\n\n    @Test\n    void testIothreads() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setIothreads(10);\n        assertThat(protocol.getIothreads(), is(10));\n    }\n\n    @Test\n    void testQueues() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setQueues(10);\n        assertThat(protocol.getQueues(), is(10));\n    }\n\n    @Test\n    void testAccepts() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setAccepts(10);\n        assertThat(protocol.getAccepts(), is(10));\n    }\n\n    @Test\n    void testAccesslog() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setAccesslog(\"access.log\");\n        assertThat(protocol.getAccesslog(), equalTo(\"access.log\"));\n    }\n\n    @Test\n    void testRegister() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setRegister(true);\n        assertThat(protocol.isRegister(), is(true));\n    }\n\n    @Test\n    void testParameters() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setParameters(Collections.singletonMap(\"k1\", \"v1\"));\n        assertThat(protocol.getParameters(), hasEntry(\"k1\", \"v1\"));\n    }\n\n    @Test\n    void testDefault() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setDefault(true);\n        assertThat(protocol.isDefault(), is(true));\n    }\n\n    @Test\n    void testKeepAlive() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setKeepAlive(true);\n        assertThat(protocol.getKeepAlive(), is(true));\n    }\n\n    @Test\n    void testOptimizer() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setOptimizer(\"optimizer\");\n        assertThat(protocol.getOptimizer(), equalTo(\"optimizer\"));\n    }\n\n    @Test\n    void testExtension() throws Exception {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setExtension(\"extension\");\n        assertThat(protocol.getExtension(), equalTo(\"extension\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/ProviderConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.config.ProviderConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.hasKey;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.not;\n\nclass ProviderConfigTest {\n    @Test\n    void testProtocol() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setProtocol(\"protocol\");\n        assertThat(provider.getProtocol().getName(), equalTo(\"protocol\"));\n    }\n\n    @Test\n    void testDefault() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setDefault(true);\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.isDefault(), is(true));\n        assertThat(parameters, not(hasKey(\"default\")));\n    }\n\n    @Test\n    void testHost() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setHost(\"demo-host\");\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.getHost(), equalTo(\"demo-host\"));\n        assertThat(parameters, not(hasKey(\"host\")));\n    }\n\n    @Test\n    void testPort() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setPort(8080);\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.getPort(), is(8080));\n        assertThat(parameters, not(hasKey(\"port\")));\n    }\n\n    @Test\n    void testPath() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setPath(\"/path\");\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.getPath(), equalTo(\"/path\"));\n        assertThat(provider.getContextpath(), equalTo(\"/path\"));\n        assertThat(parameters, not(hasKey(\"path\")));\n    }\n\n    @Test\n    void testContextPath() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setContextpath(\"/context-path\");\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.getContextpath(), equalTo(\"/context-path\"));\n        assertThat(parameters, not(hasKey(\"/context-path\")));\n    }\n\n    @Test\n    void testThreads() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setThreads(10);\n        assertThat(provider.getThreads(), is(10));\n    }\n\n    @Test\n    void testIothreads() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setIothreads(10);\n        assertThat(provider.getIothreads(), is(10));\n    }\n\n    @Test\n    void testAlive() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setAlive(10);\n        assertThat(provider.getAlive(), is(10));\n    }\n\n    @Test\n    void testQueues() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setQueues(10);\n        assertThat(provider.getQueues(), is(10));\n    }\n\n    @Test\n    void testAccepts() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setAccepts(10);\n        assertThat(provider.getAccepts(), is(10));\n    }\n\n    @Test\n    void testCharset() throws Exception {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setCharset(\"utf-8\");\n        assertThat(provider.getCharset(), equalTo(\"utf-8\"));\n    }\n\n    @Test\n    void testPayload() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setPayload(10);\n        assertThat(provider.getPayload(), is(10));\n    }\n\n    @Test\n    void testBuffer() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setBuffer(10);\n        assertThat(provider.getBuffer(), is(10));\n    }\n\n    @Test\n    void testServer() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setServer(\"demo-server\");\n        assertThat(provider.getServer(), equalTo(\"demo-server\"));\n    }\n\n    @Test\n    void testClient() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setClient(\"client\");\n        assertThat(provider.getClient(), equalTo(\"client\"));\n    }\n\n    @Test\n    void testPrompt() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setPrompt(\"#\");\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.getPrompt(), equalTo(\"#\"));\n        assertThat(parameters, hasEntry(\"prompt\", \"%23\"));\n    }\n\n    @Test\n    void testDispatcher() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setDispatcher(\"mockdispatcher\");\n        assertThat(provider.getDispatcher(), equalTo(\"mockdispatcher\"));\n    }\n\n    @Test\n    void testNetworker() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setNetworker(\"networker\");\n        assertThat(provider.getNetworker(), equalTo(\"networker\"));\n    }\n\n    @Test\n    void testWait() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setWait(10);\n        assertThat(provider.getWait(), equalTo(10));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.service.DemoService;\nimport org.apache.dubbo.service.DemoServiceImpl;\n\nimport com.alibaba.dubbo.config.ApplicationConfig;\nimport com.alibaba.dubbo.config.ProtocolConfig;\nimport com.alibaba.dubbo.config.ReferenceConfig;\nimport com.alibaba.dubbo.config.RegistryConfig;\nimport com.alibaba.dubbo.config.ServiceConfig;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass ReferenceConfigTest {\n    private ApplicationConfig application = new ApplicationConfig();\n    private RegistryConfig registry = new RegistryConfig();\n    private ProtocolConfig protocol = new ProtocolConfig();\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testInjvm() throws Exception {\n\n        application.setName(\"test-protocol-random-port\");\n        registry.setAddress(\"multicast://224.5.6.7:1234\");\n\n        protocol.setName(\"dubbo\");\n\n        ServiceConfig<DemoService> demoService;\n        demoService = new ServiceConfig<DemoService>();\n        demoService.setInterface(DemoService.class);\n        demoService.setRef(new DemoServiceImpl());\n        demoService.setApplication(application);\n        demoService.setRegistry(registry);\n        demoService.setProtocol(protocol);\n\n        ReferenceConfig<DemoService> rc = new ReferenceConfig<DemoService>();\n        rc.setApplication(application);\n        rc.setRegistry(registry);\n        rc.setInterface(DemoService.class.getName());\n        rc.setInjvm(false);\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance()\n                .application(application)\n                .registry(registry)\n                .protocol(protocol)\n                .service(demoService)\n                .reference(rc);\n\n        try {\n            bootstrap.start();\n        } finally {\n            bootstrap.stop();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/RegistryConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.config.RegistryConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.hasKey;\nimport static org.hamcrest.Matchers.not;\n\nclass RegistryConfigTest {\n    @Test\n    void testProtocol() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setProtocol(\"protocol\");\n        assertThat(registry.getProtocol(), equalTo(registry.getProtocol()));\n    }\n\n    @Test\n    void testAddress() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setAddress(\"localhost\");\n        assertThat(registry.getAddress(), equalTo(\"localhost\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        RegistryConfig.appendParameters(parameters, registry);\n        assertThat(parameters, not(hasKey(\"address\")));\n    }\n\n    @Test\n    void testUsername() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setUsername(\"username\");\n        assertThat(registry.getUsername(), equalTo(\"username\"));\n    }\n\n    @Test\n    void testPassword() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setPassword(\"password\");\n        assertThat(registry.getPassword(), equalTo(\"password\"));\n    }\n\n    @Test\n    void testWait() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setWait(10);\n        assertThat(registry.getWait(), is(10));\n        assertThat(System.getProperty(SHUTDOWN_WAIT_KEY), equalTo(\"10\"));\n    }\n\n    @Test\n    void testCheck() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setCheck(true);\n        assertThat(registry.isCheck(), is(true));\n    }\n\n    @Test\n    void testFile() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setFile(\"file\");\n        assertThat(registry.getFile(), equalTo(\"file\"));\n    }\n\n    @Test\n    void testTransporter() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setTransporter(\"transporter\");\n        assertThat(registry.getTransporter(), equalTo(\"transporter\"));\n    }\n\n    @Test\n    void testClient() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setClient(\"client\");\n        assertThat(registry.getClient(), equalTo(\"client\"));\n    }\n\n    @Test\n    void testTimeout() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setTimeout(10);\n        assertThat(registry.getTimeout(), is(10));\n    }\n\n    @Test\n    void testSession() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setSession(10);\n        assertThat(registry.getSession(), is(10));\n    }\n\n    @Test\n    void testDynamic() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setDynamic(true);\n        assertThat(registry.isDynamic(), is(true));\n    }\n\n    @Test\n    void testRegister() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setRegister(true);\n        assertThat(registry.isRegister(), is(true));\n    }\n\n    @Test\n    void testSubscribe() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setSubscribe(true);\n        assertThat(registry.isSubscribe(), is(true));\n    }\n\n    @Test\n    void testCluster() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setCluster(\"cluster\");\n        assertThat(registry.getCluster(), equalTo(\"cluster\"));\n    }\n\n    @Test\n    void testGroup() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setGroup(\"group\");\n        assertThat(registry.getGroup(), equalTo(\"group\"));\n    }\n\n    @Test\n    void testVersion() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setVersion(\"1.0.0\");\n        assertThat(registry.getVersion(), equalTo(\"1.0.0\"));\n    }\n\n    @Test\n    void testParameters() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setParameters(Collections.singletonMap(\"k1\", \"v1\"));\n        assertThat(registry.getParameters(), hasEntry(\"k1\", \"v1\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        RegistryConfig.appendParameters(parameters, registry);\n        assertThat(parameters, hasEntry(\"k1\", \"v1\"));\n    }\n\n    @Test\n    void testDefault() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setDefault(true);\n        assertThat(registry.isDefault(), is(true));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/SignatureTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.IOUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.io.IOException;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.collection.IsCollectionWithSize.hasSize;\n\npublic class SignatureTest {\n\n    @ParameterizedTest\n    @ValueSource(\n            classes = {\n                com.alibaba.dubbo.config.ApplicationConfig.class,\n                com.alibaba.dubbo.config.ArgumentConfig.class,\n                com.alibaba.dubbo.config.ConsumerConfig.class,\n                com.alibaba.dubbo.config.MethodConfig.class,\n                com.alibaba.dubbo.config.ModuleConfig.class,\n                com.alibaba.dubbo.config.MonitorConfig.class,\n                com.alibaba.dubbo.config.ProtocolConfig.class,\n                com.alibaba.dubbo.config.ProviderConfig.class,\n                com.alibaba.dubbo.config.ReferenceConfig.class,\n                com.alibaba.dubbo.config.RegistryConfig.class,\n                com.alibaba.dubbo.config.ServiceConfig.class\n            })\n    void test(Class<?> targetClass) throws IOException {\n        String[] lines = IOUtils.readLines(\n                this.getClass().getClassLoader().getResourceAsStream(\"definition/\" + targetClass.getName()));\n\n        // only compare setter now.\n        // getter cannot make it compatible with the old version.\n        Set<String> setters = Arrays.stream(lines)\n                .filter(StringUtils::isNotEmpty)\n                .filter(s -> !s.startsWith(\"//\"))\n                .filter(s -> s.contains(\"set\"))\n                .collect(Collectors.toSet());\n\n        for (Method method : targetClass.getMethods()) {\n            setters.remove(\n                    method.toString().replace(method.getDeclaringClass().getName() + \".\", targetClass.getName() + \".\"));\n        }\n\n        assertThat(setters.toString(), setters, hasSize(0));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/api/Box.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\npublic interface Box {\n\n    String getName();\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/api/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\npublic interface DemoService {\n\n    String sayName(String name);\n\n    Box getBox();\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/api/HelloService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\npublic interface HelloService {\n    String sayHello(String name);\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.annotation.Service;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionDefinition;\nimport org.springframework.transaction.TransactionException;\nimport org.springframework.transaction.TransactionStatus;\n\n/**\n * {@link Service} Bean\n *\n * @since 2.6.5\n */\n@PropertySource(\"classpath:/META-INF/default.properties\")\npublic class ServiceAnnotationTestConfiguration {\n\n    /**\n     * Current application configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:application name=\"dubbo-demo-application\"/&gt;\n     * </prev>\n     *\n     * @return {@link ApplicationConfig} Bean\n     */\n    @Bean(\"dubbo-demo-application\")\n    public ApplicationConfig applicationConfig() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"dubbo-demo-application\");\n        return applicationConfig;\n    }\n\n    /**\n     * Current registry center configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:registry id=\"my-registry\" address=\"N/A\"/&gt;\n     * </prev>\n     *\n     * @return {@link RegistryConfig} Bean\n     */\n    @Bean(\"my-registry\")\n    public RegistryConfig registryConfig() {\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setAddress(\"N/A\");\n        return registryConfig;\n    }\n\n    /**\n     * Current protocol configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:protocol name=\"dubbo\" port=\"12345\"/&gt;\n     * </prev>\n     *\n     * @return {@link ProtocolConfig} Bean\n     */\n    @Bean // (\"dubbo\")\n    public ProtocolConfig protocolConfig() {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        protocolConfig.setName(\"dubbo\");\n        protocolConfig.setPort(12345);\n        return protocolConfig;\n    }\n\n    @Primary\n    @Bean\n    public PlatformTransactionManager platformTransactionManager() {\n        return new PlatformTransactionManager() {\n\n            @Override\n            public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {\n                return null;\n            }\n\n            @Override\n            public void commit(TransactionStatus status) throws TransactionException {}\n\n            @Override\n            public void rollback(TransactionStatus status) throws TransactionException {}\n        };\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.context.annotation.consumer.ConsumerConfiguration;\nimport org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl;\nimport org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport static org.springframework.core.annotation.AnnotationUtils.findAnnotation;\n\n/**\n * {@link DubboComponentScanRegistrar} Test\n *\n * @since 2.5.8\n */\nclass DubboComponentScanRegistrarTest {\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void tearDown() {}\n\n    @Test\n    void test() {\n\n        AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext();\n\n        providerContext.register(ProviderConfiguration.class);\n\n        providerContext.refresh();\n\n        DemoService demoService = providerContext.getBean(DemoService.class);\n\n        String value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        Class<?> beanClass = AopUtils.getTargetClass(demoService);\n\n        // DemoServiceImpl with @Transactional\n        Assertions.assertEquals(DemoServiceImpl.class, beanClass);\n\n        // Test @Transactional is present or not\n        Assertions.assertNotNull(findAnnotation(beanClass, Transactional.class));\n\n        // consumer app\n        AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();\n\n        consumerContext.register(ConsumerConfiguration.class);\n\n        consumerContext.refresh();\n\n        ConsumerConfiguration consumerConfiguration = consumerContext.getBean(ConsumerConfiguration.class);\n\n        demoService = consumerConfiguration.getDemoService();\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        ConsumerConfiguration.Child child = consumerContext.getBean(ConsumerConfiguration.Child.class);\n\n        // From Child\n\n        demoService = child.getDemoServiceFromChild();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        // From Parent\n\n        demoService = child.getDemoServiceFromParent();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        // From Ancestor\n\n        demoService = child.getDemoServiceFromAncestor();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        providerContext.close();\n        consumerContext.close();\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.core.io.support.ResourcePropertySource;\n\n/**\n * {@link DubboConfigConfiguration} Test\n *\n * @since 2.5.8\n */\nclass DubboConfigConfigurationTest {\n\n    private AnnotationConfigApplicationContext context;\n\n    @BeforeEach\n    public void before() throws IOException {\n        DubboBootstrap.reset();\n\n        context = new AnnotationConfigApplicationContext();\n        ResourcePropertySource propertySource = new ResourcePropertySource(\"META-INF/config.properties\");\n        context.getEnvironment().getPropertySources().addFirst(propertySource);\n    }\n\n    @AfterEach\n    public void after() {\n        context.close();\n    }\n\n    @Test\n    void testSingle() throws IOException {\n\n        context.register(DubboConfigConfiguration.Single.class);\n        context.refresh();\n\n        // application\n        ApplicationConfig applicationConfig = context.getBean(\"applicationBean\", ApplicationConfig.class);\n        Assertions.assertEquals(\"dubbo-demo-application\", applicationConfig.getName());\n\n        // module\n        ModuleConfig moduleConfig = context.getBean(\"moduleBean\", ModuleConfig.class);\n        Assertions.assertEquals(\"dubbo-demo-module\", moduleConfig.getName());\n\n        // registry\n        RegistryConfig registryConfig = context.getBean(RegistryConfig.class);\n        Assertions.assertEquals(\"zookeeper://192.168.99.100:32770\", registryConfig.getAddress());\n\n        // protocol\n        ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class);\n        Assertions.assertEquals(\"dubbo\", protocolConfig.getName());\n        Assertions.assertEquals(Integer.valueOf(20880), protocolConfig.getPort());\n    }\n\n    @Test\n    void testMultiple() {\n        context.register(DubboConfigConfiguration.Multiple.class);\n        context.refresh();\n\n        RegistryConfig registry1 = context.getBean(\"registry1\", RegistryConfig.class);\n        Assertions.assertEquals(2181, registry1.getPort());\n\n        RegistryConfig registry2 = context.getBean(\"registry2\", RegistryConfig.class);\n        Assertions.assertEquals(2182, registry2.getPort());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.PropertySource;\n\nimport static org.apache.dubbo.config.spring.util.BeanRegistrar.hasAlias;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\n\n/**\n * {@link EnableDubboConfig} Test\n *\n * @since 2.5.8\n */\nclass EnableDubboConfigTest {\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n    }\n\n    // @Test\n    public void testSingle() {\n\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n        context.register(TestConfig.class);\n        context.refresh();\n\n        // application\n        ApplicationConfig applicationConfig = context.getBean(\"applicationBean\", ApplicationConfig.class);\n        Assertions.assertEquals(\"dubbo-demo-application\", applicationConfig.getName());\n\n        // module\n        ModuleConfig moduleConfig = context.getBean(\"moduleBean\", ModuleConfig.class);\n        Assertions.assertEquals(\"dubbo-demo-module\", moduleConfig.getName());\n\n        // registry\n        RegistryConfig registryConfig = context.getBean(RegistryConfig.class);\n        Assertions.assertEquals(\"zookeeper://192.168.99.100:32770\", registryConfig.getAddress());\n\n        // protocol\n        ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class);\n        Assertions.assertEquals(\"dubbo\", protocolConfig.getName());\n        Assertions.assertEquals(Integer.valueOf(20880), protocolConfig.getPort());\n\n        // monitor\n        MonitorConfig monitorConfig = context.getBean(MonitorConfig.class);\n        Assertions.assertEquals(\"zookeeper://127.0.0.1:32770\", monitorConfig.getAddress());\n\n        // provider\n        ProviderConfig providerConfig = context.getBean(ProviderConfig.class);\n        Assertions.assertEquals(\"127.0.0.1\", providerConfig.getHost());\n\n        // consumer\n        ConsumerConfig consumerConfig = context.getBean(ConsumerConfig.class);\n        Assertions.assertEquals(\"netty\", consumerConfig.getClient());\n\n        // asserts aliases\n        assertFalse(hasAlias(context, \"org.apache.dubbo.config.RegistryConfig#0\", \"zookeeper\"));\n        assertFalse(hasAlias(context, \"org.apache.dubbo.config.MonitorConfig#0\", \"zookeeper\"));\n    }\n\n    // @Test\n    public void testMultiple() {\n\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n        context.register(TestMultipleConfig.class);\n        context.refresh();\n\n        RegistryConfig registry1 = context.getBean(\"registry1\", RegistryConfig.class);\n        Assertions.assertEquals(2181, registry1.getPort());\n\n        RegistryConfig registry2 = context.getBean(\"registry2\", RegistryConfig.class);\n        Assertions.assertEquals(2182, registry2.getPort());\n\n        ConfigManager configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n        Collection<ProtocolConfig> protocolConfigs = configManager.getProtocols();\n        Assertions.assertEquals(3, protocolConfigs.size());\n\n        configManager.getProtocol(\"dubbo\").get();\n        configManager.getProtocol(\"rest\").get();\n\n        // asserts aliases\n        //        assertTrue(hasAlias(context, \"applicationBean2\", \"dubbo-demo-application2\"));\n        //        assertTrue(hasAlias(context, \"applicationBean3\", \"dubbo-demo-application3\"));\n\n    }\n\n    @EnableDubboConfig\n    @PropertySource(\"META-INF/config.properties\")\n    private static class TestMultipleConfig {}\n\n    @EnableDubboConfig(multiple = false)\n    @PropertySource(\"META-INF/config.properties\")\n    private static class TestConfig {}\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationTestConfiguration;\nimport org.apache.dubbo.config.spring.context.annotation.consumer.test.TestConsumerConfiguration;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionDefinition;\nimport org.springframework.transaction.TransactionException;\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n/**\n * {@link EnableDubbo} Test\n *\n * @since 2.5.8\n */\nclass EnableDubboTest {\n\n    private AnnotationConfigApplicationContext context;\n\n    @BeforeEach\n    public void setUp() {\n        context = new AnnotationConfigApplicationContext();\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void tearDown() {\n        context.close();\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testConsumer() {\n\n        context.register(TestProviderConfiguration.class, TestConsumerConfiguration.class);\n        context.refresh();\n\n        TestConsumerConfiguration consumerConfiguration = context.getBean(TestConsumerConfiguration.class);\n\n        DemoService demoService = consumerConfiguration.getDemoService();\n        String value = demoService.sayName(\"Mercy\");\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        DemoService autowiredDemoService = consumerConfiguration.getAutowiredDemoService();\n        Assertions.assertEquals(\"Hello,Mercy\", autowiredDemoService.sayName(\"Mercy\"));\n\n        DemoService autowiredReferDemoService = consumerConfiguration.getAutowiredReferDemoService();\n        Assertions.assertEquals(\"Hello,Mercy\", autowiredReferDemoService.sayName(\"Mercy\"));\n\n        TestConsumerConfiguration.Child child = context.getBean(TestConsumerConfiguration.Child.class);\n\n        // From Child\n\n        demoService = child.getDemoServiceFromChild();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        // From Parent\n\n        demoService = child.getDemoServiceFromParent();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        // From Ancestor\n\n        demoService = child.getDemoServiceFromAncestor();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        // Test my-registry2 bean presentation\n        RegistryConfig registryConfig = context.getBean(\"my-registry\", RegistryConfig.class);\n\n        // Test multiple binding\n        Assertions.assertEquals(\"N/A\", registryConfig.getAddress());\n    }\n\n    @EnableDubbo(scanBasePackages = \"org.apache.dubbo.config.spring.context.annotation.provider\")\n    @ComponentScan(basePackages = \"org.apache.dubbo.config.spring.context.annotation.provider\")\n    @PropertySource(\"classpath:/META-INF/dubbo-provider.properties\")\n    @Import(ServiceAnnotationTestConfiguration.class)\n    @EnableTransactionManagement\n    public static class TestProviderConfiguration {\n\n        @Primary\n        @Bean\n        public PlatformTransactionManager platformTransactionManager() {\n            return new PlatformTransactionManager() {\n\n                @Override\n                public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {\n                    return null;\n                }\n\n                @Override\n                public void commit(TransactionStatus status) throws TransactionException {}\n\n                @Override\n                public void rollback(TransactionStatus status) throws TransactionException {}\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.consumer;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\n\n@Configuration(\"consumerConfiguration\")\n@DubboComponentScan(basePackageClasses = ConsumerConfiguration.class)\n@PropertySource(\"META-INF/default.properties\")\npublic class ConsumerConfiguration {\n\n    private static final String remoteURL = \"dubbo://127.0.0.1:12345?version=2.5.7\";\n\n    /**\n     * Current application configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:application name=\"dubbo-demo-application\"/&gt;\n     * </prev>\n     *\n     * @return {@link ApplicationConfig} Bean\n     */\n    @Bean(\"dubbo-demo-application\")\n    public ApplicationConfig applicationConfig() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"dubbo-demo-application\");\n        return applicationConfig;\n    }\n\n    /**\n     * Current registry center configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:registry address=\"N/A\"/&gt;\n     * </prev>\n     *\n     * @return {@link RegistryConfig} Bean\n     */\n    @Bean\n    public RegistryConfig registryConfig() {\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setAddress(\"N/A\");\n        return registryConfig;\n    }\n\n    @Autowired\n    private DemoService demoServiceFromAncestor;\n\n    @Reference(version = \"2.5.7\", url = remoteURL)\n    private DemoService demoService;\n\n    public DemoService getDemoService() {\n        return demoService;\n    }\n\n    public void setDemoService(DemoService demoService) {\n        this.demoService = demoService;\n    }\n\n    @Bean\n    public Child c() {\n        return new Child();\n    }\n\n    public abstract static class Ancestor {\n\n        @Reference(version = \"2.5.7\", url = remoteURL)\n        private DemoService demoServiceFromAncestor;\n\n        public DemoService getDemoServiceFromAncestor() {\n            return demoServiceFromAncestor;\n        }\n\n        public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) {\n            this.demoServiceFromAncestor = demoServiceFromAncestor;\n        }\n    }\n\n    public abstract static class Parent extends Ancestor {\n\n        private DemoService demoServiceFromParent;\n\n        public DemoService getDemoServiceFromParent() {\n            return demoServiceFromParent;\n        }\n\n        @Reference(version = \"2.5.7\", url = remoteURL)\n        public void setDemoServiceFromParent(DemoService demoServiceFromParent) {\n            this.demoServiceFromParent = demoServiceFromParent;\n        }\n    }\n\n    public static class Child extends Parent {\n\n        @Autowired\n        private DemoService demoService;\n\n        @Reference(version = \"2.5.7\", url = remoteURL)\n        private DemoService demoServiceFromChild;\n\n        public DemoService getDemoService() {\n            return demoService;\n        }\n\n        public DemoService getDemoServiceFromChild() {\n            return demoServiceFromChild;\n        }\n\n        public void setDemoServiceFromChild(DemoService demoServiceFromChild) {\n            this.demoServiceFromChild = demoServiceFromChild;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.consumer.test;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n/**\n * Test Consumer Configuration\n *\n * @since 2.5.7\n */\n@EnableDubbo(scanBasePackageClasses = TestConsumerConfiguration.class)\n@PropertySource(\"classpath:/META-INF/dubbb-consumer.properties\")\n@EnableTransactionManagement\npublic class TestConsumerConfiguration {\n\n    private static final String remoteURL = \"dubbo://127.0.0.1:12345?version=2.5.7\";\n\n    @Reference(\n            id = \"demoService\",\n            version = \"2.5.7\",\n            url = remoteURL,\n            application = \"dubbo-demo-application\",\n            filter = \"mymock\")\n    private DemoService demoService;\n\n    @Autowired\n    @Qualifier(\"demoServiceImpl\")\n    private DemoService autowiredDemoService;\n\n    @Autowired\n    @Qualifier(\"demoService\")\n    private DemoService autowiredReferDemoService;\n\n    public DemoService getAutowiredDemoService() {\n        return autowiredDemoService;\n    }\n\n    public DemoService getAutowiredReferDemoService() {\n        return autowiredReferDemoService;\n    }\n\n    public DemoService getDemoService() {\n        return demoService;\n    }\n\n    public void setDemoService(DemoService demoService) {\n        this.demoService = demoService;\n    }\n\n    @Bean\n    public Child c() {\n        return new Child();\n    }\n\n    public abstract static class Ancestor {\n\n        @DubboReference(version = \"2.5.7\", url = remoteURL, filter = \"mymock\", application = \"dubbo-demo-application\")\n        private DemoService demoServiceFromAncestor;\n\n        public DemoService getDemoServiceFromAncestor() {\n            return demoServiceFromAncestor;\n        }\n\n        public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) {\n            this.demoServiceFromAncestor = demoServiceFromAncestor;\n        }\n    }\n\n    public abstract static class Parent extends Ancestor {\n\n        private DemoService demoServiceFromParent;\n\n        public DemoService getDemoServiceFromParent() {\n            return demoServiceFromParent;\n        }\n\n        @com.alibaba.dubbo.config.annotation.Reference(\n                version = \"2.5.7\",\n                url = remoteURL,\n                filter = \"mymock\",\n                application = \"dubbo-demo-application\")\n        public void setDemoServiceFromParent(DemoService demoServiceFromParent) {\n            this.demoServiceFromParent = demoServiceFromParent;\n        }\n    }\n\n    public static class Child extends Parent {\n\n        @Reference(version = \"2.5.7\", url = remoteURL, filter = \"mymock\", application = \"dubbo-demo-application\")\n        private DemoService demoServiceFromChild;\n\n        public DemoService getDemoServiceFromChild() {\n            return demoServiceFromChild;\n        }\n\n        public void setDemoServiceFromChild(DemoService demoServiceFromChild) {\n            this.demoServiceFromChild = demoServiceFromChild;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DefaultHelloService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.provider;\n\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.springframework.stereotype.Service;\n\n/**\n * Default {@link HelloService} annotation with Spring's {@link Service}\n * and Dubbo's {@link org.apache.dubbo.config.annotation.Service}\n *\n */\n@Service\n@DubboService\npublic class DefaultHelloService implements HelloService {\n\n    @Override\n    public String sayHello(String name) {\n        return \"Greeting, \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.provider;\n\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * {@link DemoService} Service implementation\n *\n * @since 2.5.8\n */\n@org.apache.dubbo.config.annotation.Service(\n        version = \"2.5.7\",\n        application = \"${demo.service.application}\",\n        protocol = \"${demo.service.protocol}\",\n        registry = \"${demo.service.registry}\",\n        methods = @Method(timeout = 100, name = \"sayName\"))\n@Service\n@Transactional\npublic class DemoServiceImpl implements DemoService {\n\n    @Override\n    public String sayName(String name) {\n        return \"Hello,\" + name;\n    }\n\n    @Override\n    public Box getBox() {\n        throw new UnsupportedOperationException(\"For Purposes!\");\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/HelloServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.provider;\n\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport com.alibaba.dubbo.config.annotation.Service;\n\n/**\n * {@link HelloService} Implementation just annotating Dubbo's {@link Service}\n *\n * @since 2.5.9\n */\n@Service(interfaceName = \"org.apache.dubbo.config.spring.api.HelloService\", version = \"2\")\npublic class HelloServiceImpl implements HelloService {\n\n    @Override\n    public String sayHello(String name) {\n        return \"Hello, \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.provider;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;\n\nimport java.util.UUID;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionDefinition;\nimport org.springframework.transaction.TransactionException;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\nimport org.springframework.transaction.support.AbstractPlatformTransactionManager;\nimport org.springframework.transaction.support.DefaultTransactionStatus;\n\n@DubboComponentScan(basePackages = \"org.apache.dubbo.config.spring.context.annotation.provider\")\n@PropertySource(\"classpath:/META-INF/default.properties\")\n@EnableTransactionManagement\npublic class ProviderConfiguration {\n\n    /**\n     * Current application configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:application name=\"dubbo-demo-application\"/&gt;\n     * </prev>\n     *\n     * @return {@link ApplicationConfig} Bean\n     */\n    @Bean(\"dubbo-demo-application\")\n    public ApplicationConfig applicationConfig() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"dubbo-demo-application\");\n        return applicationConfig;\n    }\n\n    /**\n     * Current registry center configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:registry id=\"my-registry\" address=\"N/A\"/&gt;\n     * </prev>\n     *\n     * @return {@link RegistryConfig} Bean\n     */\n    @Bean(\"my-registry\")\n    public RegistryConfig registryConfig() {\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setAddress(\"N/A\");\n        return registryConfig;\n    }\n\n    /**\n     * Current protocol configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:protocol name=\"dubbo\" port=\"12345\"/&gt;\n     * </prev>\n     *\n     * @return {@link ProtocolConfig} Bean\n     */\n    @Bean(\"dubbo\")\n    public ProtocolConfig protocolConfig() {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        protocolConfig.setName(\"dubbo\");\n        protocolConfig.setPort(12345);\n        return protocolConfig;\n    }\n\n    @Primary\n    @Bean\n    public PlatformTransactionManager platformTransactionManager() {\n        return new AbstractPlatformTransactionManager() {\n            private Logger logger = LoggerFactory.getLogger(\"TestPlatformTransactionManager\");\n\n            @Override\n            protected Object doGetTransaction() throws TransactionException {\n                String transaction = \"transaction_\" + UUID.randomUUID().toString();\n                logger.info(\"Create transaction: \" + transaction);\n                return transaction;\n            }\n\n            @Override\n            protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {\n                logger.info(\"Begin transaction: \" + transaction);\n            }\n\n            @Override\n            protected void doCommit(DefaultTransactionStatus status) throws TransactionException {\n                logger.info(\"Commit transaction: \" + status.getTransaction());\n            }\n\n            @Override\n            protected void doRollback(DefaultTransactionStatus status) throws TransactionException {\n                logger.info(\"Rollback transaction: \" + status.getTransaction());\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/filter/MockDao.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.filter;\n\npublic interface MockDao {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/filter/MockDaoImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.filter;\n\npublic class MockDaoImpl implements MockDao {}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/config/spring/filter/MockFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.filter;\n\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\n\npublic class MockFilter implements Filter {\n\n    private LoadBalance loadBalance;\n\n    private Protocol protocol;\n\n    private MockDao mockDao;\n\n    public MockDao getMockDao() {\n        return mockDao;\n    }\n\n    public void setMockDao(MockDao mockDao) {\n        this.mockDao = mockDao;\n    }\n\n    public LoadBalance getLoadBalance() {\n        return loadBalance;\n    }\n\n    public void setLoadBalance(LoadBalance loadBalance) {\n        this.loadBalance = loadBalance;\n    }\n\n    public Protocol getProtocol() {\n        return protocol;\n    }\n\n    public void setProtocol(Protocol protocol) {\n        this.protocol = protocol;\n    }\n\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        return invoker.invoke(invocation);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/echo/EchoServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.echo;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.service.EchoService;\nimport org.apache.dubbo.service.DemoService;\nimport org.apache.dubbo.service.DemoServiceImpl;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass EchoServiceTest {\n\n    @Test\n    void testEcho() {\n        DemoService server = new DemoServiceImpl();\n        ProxyFactory proxyFactory =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n        Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n        URL url = URL.valueOf(\"dubbo://127.0.0.1:5342/\" + DemoService.class.getName() + \"?version=1.0.0\");\n        Exporter<DemoService> exporter = protocol.export(proxyFactory.getInvoker(server, DemoService.class, url));\n        Invoker<DemoService> invoker = protocol.refer(DemoService.class, url);\n        EchoService client = (EchoService) proxyFactory.getProxy(invoker);\n        Object result = client.$echo(\"haha\");\n        Assertions.assertEquals(\"haha\", result);\n\n        org.apache.dubbo.rpc.service.EchoService newClient =\n                (org.apache.dubbo.rpc.service.EchoService) proxyFactory.getProxy(invoker);\n        Object res = newClient.$echo(\"hehe\");\n        Assertions.assertEquals(\"hehe\", res);\n        invoker.destroy();\n        exporter.unexport();\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/filter/FilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.filter;\n\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\n\nimport com.alibaba.dubbo.rpc.Filter;\nimport com.alibaba.dubbo.rpc.Invocation;\nimport com.alibaba.dubbo.rpc.Invoker;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass FilterTest {\n\n    Filter myFilter = new MyFilter();\n\n    @Test\n    void testInvokeException() {\n        try {\n            Invoker<FilterTest> invoker = new LegacyInvoker<FilterTest>(null);\n            Invocation invocation = new LegacyInvocation(\"aa\");\n            myFilter.invoke(invoker, invocation);\n            fail();\n        } catch (RpcException e) {\n            Assertions.assertTrue(e.getMessage().contains(\"arg0 illegal\"));\n        }\n    }\n\n    @Test\n    void testDefault() throws Throwable {\n        Invoker<FilterTest> invoker = new LegacyInvoker<FilterTest>(null);\n        org.apache.dubbo.rpc.Invocation invocation = new RpcInvocation(\n                null, \"echo\", \"DemoService\", \"DemoService\", new Class[] {String.class}, new Object[] {\"bbb\"});\n        org.apache.dubbo.rpc.Result res = myFilter.invoke(invoker, invocation);\n        Assertions.assertEquals(\"alibaba\", res.recreate());\n    }\n\n    @Test\n    void testRecreate() throws Throwable {\n        Invoker<FilterTest> invoker = new LegacyInvoker<FilterTest>(null);\n        org.apache.dubbo.rpc.Invocation invocation = new RpcInvocation(\n                null, \"echo\", \"DemoService\", \"DemoService\", new Class[] {String.class}, new Object[] {\"cc\"});\n        org.apache.dubbo.rpc.Result res = myFilter.invoke(invoker, invocation);\n        Assertions.assertEquals(\"123test\", res.recreate());\n    }\n\n    @AfterAll\n    public static void tear() {\n        Assertions.assertEquals(3, MyFilter.count);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/filter/LegacyInvocation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.filter;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.rpc.Invocation;\nimport com.alibaba.dubbo.rpc.Invoker;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.rpc.Constants.TOKEN_KEY;\n\n/**\n * MockInvocation.java\n */\npublic class LegacyInvocation implements Invocation {\n\n    private String arg0;\n\n    public LegacyInvocation(String arg0) {\n        this.arg0 = arg0;\n    }\n\n    @Override\n    public String getTargetServiceUniqueName() {\n        return null;\n    }\n\n    @Override\n    public String getProtocolServiceKey() {\n        return null;\n    }\n\n    public String getMethodName() {\n        return \"echo\";\n    }\n\n    public Class<?>[] getParameterTypes() {\n        return new Class[] {String.class};\n    }\n\n    public Object[] getArguments() {\n        return new Object[] {arg0};\n    }\n\n    public Map<String, String> getAttachments() {\n        Map<String, String> attachments = new HashMap<String, String>();\n        attachments.put(PATH_KEY, \"dubbo\");\n        attachments.put(GROUP_KEY, \"dubbo\");\n        attachments.put(VERSION_KEY, \"1.0.0\");\n        attachments.put(DUBBO_VERSION_KEY, \"1.0.0\");\n        attachments.put(TOKEN_KEY, \"sfag\");\n        attachments.put(TIMEOUT_KEY, \"1000\");\n        return attachments;\n    }\n\n    public Invoker<?> getInvoker() {\n        return null;\n    }\n\n    @Override\n    public Object put(Object key, Object value) {\n        return null;\n    }\n\n    @Override\n    public Object get(Object key) {\n        return null;\n    }\n\n    @Override\n    public Map<Object, Object> getAttributes() {\n        return null;\n    }\n\n    public String getAttachment(String key) {\n        return getAttachments().get(key);\n    }\n\n    public String getAttachment(String key, String defaultValue) {\n        return getAttachments().get(key);\n    }\n\n    @Override\n    public void addInvokedInvoker(org.apache.dubbo.rpc.Invoker<?> invoker) {}\n\n    @Override\n    public List<org.apache.dubbo.rpc.Invoker<?>> getInvokedInvokers() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/filter/LegacyInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.filter;\n\nimport org.apache.dubbo.service.DemoService;\n\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.rpc.Invocation;\nimport com.alibaba.dubbo.rpc.Invoker;\nimport com.alibaba.dubbo.rpc.Result;\nimport com.alibaba.dubbo.rpc.RpcException;\nimport com.alibaba.dubbo.rpc.RpcResult;\n\npublic class LegacyInvoker<T> implements Invoker<T> {\n\n    URL url;\n    Class<T> type;\n    boolean hasException = false;\n\n    public LegacyInvoker(URL url) {\n        this.url = url;\n        type = (Class<T>) DemoService.class;\n    }\n\n    public LegacyInvoker(URL url, boolean hasException) {\n        this.url = url;\n        type = (Class<T>) DemoService.class;\n        this.hasException = hasException;\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return type;\n    }\n\n    public URL getUrl() {\n        return url;\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return false;\n    }\n\n    public Result invoke(Invocation invocation) throws RpcException {\n        RpcResult result = new RpcResult();\n        if (!hasException) {\n            result.setValue(\"alibaba\");\n        } else {\n            result.setException(new RuntimeException(\"mocked exception\"));\n        }\n        return result;\n    }\n\n    @Override\n    public void destroy() {}\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/filter/MyFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.filter;\n\nimport com.alibaba.dubbo.rpc.Filter;\nimport com.alibaba.dubbo.rpc.Invocation;\nimport com.alibaba.dubbo.rpc.Invoker;\nimport com.alibaba.dubbo.rpc.Result;\nimport com.alibaba.dubbo.rpc.RpcException;\nimport com.alibaba.dubbo.rpc.RpcResult;\n\npublic class MyFilter implements Filter {\n\n    public static int count = 0;\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        count++;\n\n        if (invocation.getArguments()[0].equals(\"aa\")) {\n            throw new RpcException(new IllegalArgumentException(\"arg0 illegal\"));\n        }\n\n        if (invocation.getArguments()[0].equals(\"cc\")) {\n            return new RpcResult(\"123test\");\n        }\n\n        Result tmp = invoker.invoke(invocation);\n        return tmp;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.generic;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.compact.Dubbo2CompactUtils;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.MethodDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.service.GenericService;\nimport org.apache.dubbo.service.ComplexObject;\nimport org.apache.dubbo.service.DemoService;\nimport org.apache.dubbo.service.DemoServiceImpl;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.alibaba.dubbo.config.ReferenceConfig;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nclass GenericServiceTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testGeneric() {\n        DemoService server = new DemoServiceImpl();\n        ProxyFactory proxyFactory =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n        Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n        URL url = URL.valueOf(\"dubbo://127.0.0.1:5342/\" + DemoService.class.getName() + \"?version=1.0.0\");\n        Exporter<DemoService> exporter = protocol.export(proxyFactory.getInvoker(server, DemoService.class, url));\n        Invoker<DemoService> invoker = protocol.refer(DemoService.class, url);\n\n        GenericService client = (GenericService) proxyFactory.getProxy(invoker, true);\n        Object result = client.$invoke(\"sayHello\", new String[] {\"java.lang.String\"}, new Object[] {\"haha\"});\n        Assertions.assertEquals(\"hello haha\", result);\n\n        org.apache.dubbo.rpc.service.GenericService newClient =\n                (org.apache.dubbo.rpc.service.GenericService) proxyFactory.getProxy(invoker, true);\n        Object res = newClient.$invoke(\"sayHello\", new String[] {\"java.lang.String\"}, new Object[] {\"hehe\"});\n        Assertions.assertEquals(\"hello hehe\", res);\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    @Test\n    void testGeneric2() {\n        DemoService server = new DemoServiceImpl();\n        ProxyFactory proxyFactory =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n        Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n        URL url = URL.valueOf(\n                \"dubbo://127.0.0.1:5342/\" + DemoService.class.getName() + \"?version=1.0.0&generic=true$timeout=3000\");\n        Exporter<DemoService> exporter = protocol.export(proxyFactory.getInvoker(server, DemoService.class, url));\n        Invoker<GenericService> invoker = protocol.refer(GenericService.class, url);\n\n        GenericService client = proxyFactory.getProxy(invoker, true);\n        Object result = client.$invoke(\"sayHello\", new String[] {\"java.lang.String\"}, new Object[] {\"haha\"});\n        Assertions.assertEquals(\"hello haha\", result);\n\n        Invoker<DemoService> invoker2 = protocol.refer(DemoService.class, url);\n\n        GenericService client2 = (GenericService) proxyFactory.getProxy(invoker2, true);\n        Object result2 = client2.$invoke(\"sayHello\", new String[] {\"java.lang.String\"}, new Object[] {\"haha\"});\n        Assertions.assertEquals(\"hello haha\", result2);\n\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    @Test\n    void testGenericCompatible() {\n        DubboBootstrap.getInstance().application(\"test-app\").initialize();\n\n        DemoService server = new DemoServiceImpl();\n        ProxyFactory proxyFactory =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n        Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n        URL url = URL.valueOf(\n                \"dubbo://127.0.0.1:5342/\" + DemoService.class.getName() + \"?version=1.0.0&generic=true$timeout=3000\");\n        Exporter<DemoService> exporter = protocol.export(proxyFactory.getInvoker(server, DemoService.class, url));\n\n        // simulate normal invoke\n        ReferenceConfig oldReferenceConfig = new ReferenceConfig<>();\n        oldReferenceConfig.setGeneric(true);\n        oldReferenceConfig.setInterface(DemoService.class.getName());\n        oldReferenceConfig.refresh();\n        Invoker invoker = protocol.refer(oldReferenceConfig.getInterfaceClass(), url);\n        GenericService client = (GenericService) proxyFactory.getProxy(invoker, true);\n        Assertions.assertInstanceOf(Dubbo2CompactUtils.getGenericServiceClass(), client);\n\n        Object result = client.$invoke(\"sayHello\", new String[] {\"java.lang.String\"}, new Object[] {\"haha\"});\n        Assertions.assertEquals(\"hello haha\", result);\n\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    @Test\n    void testGenericComplexCompute4FullServiceMetadata() {\n        DemoService server = new DemoServiceImpl();\n        ProxyFactory proxyFactory =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n        Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n        URL url = URL.valueOf(\n                \"dubbo://127.0.0.1:5342/\" + DemoService.class.getName() + \"?version=1.0.0&generic=true$timeout=3000\");\n        Exporter<DemoService> exporter = protocol.export(proxyFactory.getInvoker(server, DemoService.class, url));\n\n        String var1 = \"v1\";\n        int var2 = 234;\n        long l = 555;\n        String[] var3 = {\"var31\", \"var32\"};\n        List<Integer> var4 = Arrays.asList(2, 4, 8);\n        ComplexObject.TestEnum testEnum = ComplexObject.TestEnum.VALUE2;\n\n        FullServiceDefinition fullServiceDefinition = ServiceDefinitionBuilder.buildFullDefinition(DemoService.class);\n        MethodDefinition methodDefinition = getMethod(\"complexCompute\", fullServiceDefinition.getMethods());\n        Map mapObject = createComplexObject(fullServiceDefinition, var1, var2, l, var3, var4, testEnum);\n        ComplexObject complexObject = map2bean(mapObject);\n\n        Invoker<GenericService> invoker = protocol.refer(GenericService.class, url);\n\n        GenericService client = proxyFactory.getProxy(invoker, true);\n        Object result = client.$invoke(\n                methodDefinition.getName(), methodDefinition.getParameterTypes(), new Object[] {\"haha\", mapObject});\n\n        String r1 = (String) result;\n        Assertions.assertTrue(r1.startsWith(\"haha###\"));\n        Assertions.assertTrue(r1.contains(\"v1_k1=v1_v1\"));\n        Assertions.assertTrue(r1.contains(\"v1_k2=v1_v2\"));\n\n        Invoker<DemoService> invoker2 = protocol.refer(DemoService.class, url);\n        GenericService client2 = (GenericService) proxyFactory.getProxy(invoker2, true);\n        Object result2 = client2.$invoke(\n                \"complexCompute\", methodDefinition.getParameterTypes(), new Object[] {\"haha2\", mapObject});\n\n        String r2 = (String) result2;\n        Assertions.assertTrue(r2.startsWith(\"haha2###\"));\n        Assertions.assertTrue(r2.contains(\"v1_k1=v1_v1\"));\n        Assertions.assertTrue(r2.contains(\"v1_k2=v1_v2\"));\n\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    @Test\n    void testGenericFindComplexObject4FullServiceMetadata() {\n        DemoService server = new DemoServiceImpl();\n        ProxyFactory proxyFactory =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n        Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n        URL url = URL.valueOf(\n                \"dubbo://127.0.0.1:5342/\" + DemoService.class.getName() + \"?version=1.0.0&generic=true$timeout=3000\");\n        Exporter<DemoService> exporter = protocol.export(proxyFactory.getInvoker(server, DemoService.class, url));\n\n        String var1 = \"v1\";\n        int var2 = 234;\n        long l = 555;\n        String[] var3 = {\"var31\", \"var32\"};\n        List<Integer> var4 = Arrays.asList(2, 4, 8);\n        ComplexObject.TestEnum testEnum = ComplexObject.TestEnum.VALUE2;\n        // ComplexObject complexObject = createComplexObject(var1, var2, l, var3, var4, testEnum);\n\n        Invoker<GenericService> invoker = protocol.refer(GenericService.class, url);\n\n        GenericService client = proxyFactory.getProxy(invoker, true);\n        Object result = client.$invoke(\n                \"findComplexObject\",\n                new String[] {\n                    \"java.lang.String\",\n                    \"int\",\n                    \"long\",\n                    \"java.lang.String[]\",\n                    \"java.util.List\",\n                    \"org.apache.dubbo.service.ComplexObject$TestEnum\"\n                },\n                new Object[] {var1, var2, l, var3, var4, testEnum});\n        Assertions.assertNotNull(result);\n        ComplexObject r = map2bean((Map) result);\n        Assertions.assertEquals(r, createComplexObject(var1, var2, l, var3, var4, testEnum));\n\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    MethodDefinition getMethod(String methodName, List<MethodDefinition> list) {\n        for (MethodDefinition methodDefinition : list) {\n            if (methodDefinition.getName().equals(methodName)) {\n                return methodDefinition;\n            }\n        }\n        return null;\n    }\n\n    Map<String, Object> createComplexObject(\n            FullServiceDefinition fullServiceDefinition,\n            String var1,\n            int var2,\n            long l,\n            String[] var3,\n            List<Integer> var4,\n            ComplexObject.TestEnum testEnum) {\n        List<TypeDefinition> typeDefinitions = fullServiceDefinition.getTypes();\n        TypeDefinition topTypeDefinition = null;\n        TypeDefinition innerTypeDefinition = null;\n        TypeDefinition inner2TypeDefinition = null;\n        TypeDefinition inner3TypeDefinition = null;\n        for (TypeDefinition typeDefinition : typeDefinitions) {\n            if (typeDefinition.getType().equals(ComplexObject.class.getCanonicalName())) {\n                topTypeDefinition = typeDefinition;\n            } else if (typeDefinition.getType().equals(ComplexObject.InnerObject.class.getCanonicalName())) {\n                innerTypeDefinition = typeDefinition;\n            } else if (typeDefinition.getType().equals(ComplexObject.InnerObject2.class.getCanonicalName())) {\n                inner2TypeDefinition = typeDefinition;\n            } else if (typeDefinition.getType().equals(ComplexObject.InnerObject3.class.getCanonicalName())) {\n                inner3TypeDefinition = typeDefinition;\n            }\n        }\n        Assertions.assertEquals(\"long\", topTypeDefinition.getProperties().get(\"v\"));\n        Assertions.assertEquals(\n                \"java.util.Map<java.lang.String,java.lang.String>\",\n                topTypeDefinition.getProperties().get(\"maps\"));\n        Assertions.assertEquals(\n                \"org.apache.dubbo.service.ComplexObject.InnerObject\",\n                topTypeDefinition.getProperties().get(\"innerObject\"));\n        Assertions.assertEquals(\n                \"java.util.List<java.lang.Integer>\",\n                topTypeDefinition.getProperties().get(\"intList\"));\n        Assertions.assertEquals(\n                \"java.lang.String[]\", topTypeDefinition.getProperties().get(\"strArrays\"));\n        Assertions.assertEquals(\n                \"org.apache.dubbo.service.ComplexObject.InnerObject3[]\",\n                topTypeDefinition.getProperties().get(\"innerObject3\"));\n        Assertions.assertEquals(\n                \"org.apache.dubbo.service.ComplexObject.TestEnum\",\n                topTypeDefinition.getProperties().get(\"testEnum\"));\n        Assertions.assertEquals(\n                \"java.util.List<org.apache.dubbo.service.ComplexObject.InnerObject2>\",\n                topTypeDefinition.getProperties().get(\"innerObject2\"));\n\n        Assertions.assertSame(\n                \"java.lang.String\", innerTypeDefinition.getProperties().get(\"innerA\"));\n        Assertions.assertSame(\"int\", innerTypeDefinition.getProperties().get(\"innerB\"));\n\n        Assertions.assertSame(\n                \"java.lang.String\", inner2TypeDefinition.getProperties().get(\"innerA2\"));\n        Assertions.assertSame(\"int\", inner2TypeDefinition.getProperties().get(\"innerB2\"));\n\n        Assertions.assertSame(\n                \"java.lang.String\", inner3TypeDefinition.getProperties().get(\"innerA3\"));\n\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"v\", l);\n        Map maps = new HashMap<>(4);\n        maps.put(var1 + \"_k1\", var1 + \"_v1\");\n        maps.put(var1 + \"_k2\", var1 + \"_v2\");\n        result.put(\"maps\", maps);\n        result.put(\"intList\", var4);\n        result.put(\"strArrays\", var3);\n        result.put(\"testEnum\", testEnum.name());\n\n        Map innerObjectMap = new HashMap<>(4);\n        result.put(\"innerObject\", innerObjectMap);\n        innerObjectMap.put(\"innerA\", var1);\n        innerObjectMap.put(\"innerB\", var2);\n\n        List<Map> innerObject2List = new ArrayList<>();\n        result.put(\"innerObject2\", innerObject2List);\n        Map innerObject2Tmp1 = new HashMap<>(4);\n        innerObject2Tmp1.put(\"innerA2\", var1 + \"_21\");\n        innerObject2Tmp1.put(\"innerB2\", var2 + 100000);\n        Map innerObject2Tmp2 = new HashMap<>(4);\n        innerObject2Tmp2.put(\"innerA2\", var1 + \"_22\");\n        innerObject2Tmp2.put(\"innerB2\", var2 + 200000);\n        innerObject2List.add(innerObject2Tmp1);\n        innerObject2List.add(innerObject2Tmp2);\n\n        Map innerObject3Tmp1 = new HashMap<>(4);\n        innerObject3Tmp1.put(\"innerA3\", var1 + \"_31\");\n        Map innerObject3Tmp2 = new HashMap<>(4);\n        innerObject3Tmp2.put(\"innerA3\", var1 + \"_32\");\n        Map innerObject3Tmp3 = new HashMap<>(4);\n        innerObject3Tmp3.put(\"innerA3\", var1 + \"_32\");\n        result.put(\"innerObject3\", new Map[] {innerObject3Tmp1, innerObject3Tmp2, innerObject3Tmp3});\n\n        return result;\n    }\n\n    Map<String, Object> bean2Map(ComplexObject complexObject) {\n        return JsonUtils.toJavaObject(JsonUtils.toJson(complexObject), Map.class);\n    }\n\n    ComplexObject map2bean(Map<String, Object> map) {\n        return JsonUtils.toJavaObject(JsonUtils.toJson(map), ComplexObject.class);\n    }\n\n    ComplexObject createComplexObject(\n            String var1, int var2, long l, String[] var3, List<Integer> var4, ComplexObject.TestEnum testEnum) {\n        return new ComplexObject(var1, var2, l, var3, var4, testEnum);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/AbstractAnnotationProcessingTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing;\n\nimport org.apache.dubbo.metadata.annotation.processing.util.TypeUtils;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.util.Elements;\nimport javax.lang.model.util.Types;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Abstract {@link Annotation} Processing Test case\n *\n * @since 2.7.6\n */\n@ExtendWith(CompilerInvocationInterceptor.class)\npublic abstract class AbstractAnnotationProcessingTest {\n\n    static ThreadLocal<AbstractAnnotationProcessingTest> testInstanceHolder = new ThreadLocal<>();\n\n    protected ProcessingEnvironment processingEnv;\n\n    protected Elements elements;\n\n    protected Types types;\n\n    @BeforeEach\n    public final void init() {\n        testInstanceHolder.set(this);\n    }\n\n    @AfterEach\n    public final void destroy() {\n        testInstanceHolder.remove();\n    }\n\n    protected abstract void addCompiledClasses(Set<Class<?>> classesToBeCompiled);\n\n    protected abstract void beforeEach();\n\n    protected TypeElement getType(Class<?> type) {\n        return TypeUtils.getType(processingEnv, type);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/AnnotationProcessingTestProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.TypeElement;\n\nimport java.lang.reflect.Method;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.InvocationInterceptor;\nimport org.junit.jupiter.api.extension.ReflectiveInvocationContext;\n\nimport static javax.lang.model.SourceVersion.latestSupported;\n\n@SupportedAnnotationTypes(\"*\")\npublic class AnnotationProcessingTestProcessor extends AbstractProcessor {\n\n    private final AbstractAnnotationProcessingTest abstractAnnotationProcessingTest;\n    private final InvocationInterceptor.Invocation<Void> invocation;\n\n    private final ReflectiveInvocationContext<Method> invocationContext;\n\n    private final ExtensionContext extensionContext;\n\n    public AnnotationProcessingTestProcessor(\n            AbstractAnnotationProcessingTest abstractAnnotationProcessingTest,\n            InvocationInterceptor.Invocation<Void> invocation,\n            ReflectiveInvocationContext<Method> invocationContext,\n            ExtensionContext extensionContext) {\n        this.abstractAnnotationProcessingTest = abstractAnnotationProcessingTest;\n        this.invocation = invocation;\n        this.invocationContext = invocationContext;\n        this.extensionContext = extensionContext;\n    }\n\n    @Override\n    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n        if (!roundEnv.processingOver()) {\n            prepare();\n            abstractAnnotationProcessingTest.beforeEach();\n            try {\n                invocation.proceed();\n            } catch (Throwable throwable) {\n                throw new RuntimeException(throwable);\n            }\n        }\n        return false;\n    }\n\n    private void prepare() {\n        abstractAnnotationProcessingTest.processingEnv = super.processingEnv;\n        abstractAnnotationProcessingTest.elements = super.processingEnv.getElementUtils();\n        abstractAnnotationProcessingTest.types = super.processingEnv.getTypeUtils();\n    }\n\n    @Override\n    public SourceVersion getSupportedSourceVersion() {\n        return latestSupported();\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/CompilerInvocationInterceptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing;\n\nimport org.apache.dubbo.metadata.tools.Compiler;\n\nimport java.lang.reflect.Method;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.InvocationInterceptor;\nimport org.junit.jupiter.api.extension.ReflectiveInvocationContext;\n\nimport static org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest.testInstanceHolder;\n\npublic class CompilerInvocationInterceptor implements InvocationInterceptor {\n\n    @Override\n    public void interceptTestMethod(\n            Invocation<Void> invocation,\n            ReflectiveInvocationContext<Method> invocationContext,\n            ExtensionContext extensionContext)\n            throws Throwable {\n        Set<Class<?>> classesToBeCompiled = new LinkedHashSet<>();\n        AbstractAnnotationProcessingTest abstractAnnotationProcessingTest = testInstanceHolder.get();\n        classesToBeCompiled.add(getClass());\n        abstractAnnotationProcessingTest.addCompiledClasses(classesToBeCompiled);\n        Compiler compiler = new Compiler();\n        compiler.processors(new AnnotationProcessingTestProcessor(\n                abstractAnnotationProcessingTest, invocation, invocationContext, extensionContext));\n        compiler.compile(classesToBeCompiled.toArray(new Class[0]));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.ElementKind;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link ArrayTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass ArrayTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private ArrayTypeDefinitionBuilder builder;\n\n    private TypeElement testType;\n\n    private VariableElement integersField;\n\n    private VariableElement stringsField;\n\n    private VariableElement primitiveTypeModelsField;\n\n    private VariableElement modelsField;\n\n    private VariableElement colorsField;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(ArrayTypeModel.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new ArrayTypeDefinitionBuilder();\n        testType = getType(ArrayTypeModel.class);\n        integersField = findField(testType, \"integers\");\n        stringsField = findField(testType, \"strings\");\n        primitiveTypeModelsField = findField(testType, \"primitiveTypeModels\");\n        modelsField = findField(testType, \"models\");\n        colorsField = findField(testType, \"colors\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, integersField.asType()));\n        assertTrue(builder.accept(processingEnv, stringsField.asType()));\n        assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType()));\n        assertTrue(builder.accept(processingEnv, modelsField.asType()));\n        assertTrue(builder.accept(processingEnv, colorsField.asType()));\n    }\n\n    @Test\n    void testBuild() {\n\n        buildAndAssertTypeDefinition(processingEnv, integersField, \"int[]\", \"int\", builder);\n\n        buildAndAssertTypeDefinition(processingEnv, stringsField, \"java.lang.String[]\", \"java.lang.String\", builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                primitiveTypeModelsField,\n                \"org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel[]\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                modelsField,\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model[]\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model\",\n                builder,\n                (def, subDef) -> {\n                    TypeElement subType = elements.getTypeElement(subDef.getType());\n                    assertEquals(ElementKind.CLASS, subType.getKind());\n                });\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                colorsField,\n                \"org.apache.dubbo.metadata.annotation.processing.model.Color[]\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Color\",\n                builder,\n                (def, subDef) -> {\n                    TypeElement subType = elements.getTypeElement(subDef.getType());\n                    assertEquals(ElementKind.ENUM, subType.getKind());\n                });\n    }\n\n    static void buildAndAssertTypeDefinition(\n            ProcessingEnvironment processingEnv,\n            VariableElement field,\n            String expectedType,\n            String compositeType,\n            TypeBuilder builder,\n            BiConsumer<TypeDefinition, TypeDefinition>... assertions) {\n        Map<String, TypeDefinition> typeCache = new HashMap<>();\n        TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field, typeCache);\n        String subTypeName = typeDefinition.getItems().get(0);\n        TypeDefinition subTypeDefinition = typeCache.get(subTypeName);\n        assertEquals(expectedType, typeDefinition.getType());\n        //        assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref());\n        assertEquals(compositeType, subTypeDefinition.getType());\n        //        assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName());\n        Stream.of(assertions).forEach(assertion -> assertion.accept(typeDefinition, subTypeDefinition));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.CollectionTypeModel;\n\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.builder.ArrayTypeDefinitionBuilderTest.buildAndAssertTypeDefinition;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link CollectionTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass CollectionTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private CollectionTypeDefinitionBuilder builder;\n\n    private VariableElement stringsField;\n\n    private VariableElement colorsField;\n\n    private VariableElement primitiveTypeModelsField;\n\n    private VariableElement modelsField;\n\n    private VariableElement modelArraysField;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(CollectionTypeModel.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new CollectionTypeDefinitionBuilder();\n        TypeElement testType = getType(CollectionTypeModel.class);\n        stringsField = findField(testType, \"strings\");\n        colorsField = findField(testType, \"colors\");\n        primitiveTypeModelsField = findField(testType, \"primitiveTypeModels\");\n        modelsField = findField(testType, \"models\");\n        modelArraysField = findField(testType, \"modelArrays\");\n\n        assertEquals(\"strings\", stringsField.getSimpleName().toString());\n        assertEquals(\"colors\", colorsField.getSimpleName().toString());\n        assertEquals(\n                \"primitiveTypeModels\", primitiveTypeModelsField.getSimpleName().toString());\n        assertEquals(\"models\", modelsField.getSimpleName().toString());\n        assertEquals(\"modelArrays\", modelArraysField.getSimpleName().toString());\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, stringsField.asType()));\n        assertTrue(builder.accept(processingEnv, colorsField.asType()));\n        assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType()));\n        assertTrue(builder.accept(processingEnv, modelsField.asType()));\n        assertTrue(builder.accept(processingEnv, modelArraysField.asType()));\n    }\n\n    @Test\n    void testBuild() {\n\n        buildAndAssertTypeDefinition(\n                processingEnv, stringsField, \"java.util.Collection<java.lang.String>\", \"java.lang.String\", builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                colorsField,\n                \"java.util.List<org.apache.dubbo.metadata.annotation.processing.model.Color>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Color\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                primitiveTypeModelsField,\n                \"java.util.Queue<org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                modelsField,\n                \"java.util.Deque<org.apache.dubbo.metadata.annotation.processing.model.Model>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                modelArraysField,\n                \"java.util.Set<org.apache.dubbo.metadata.annotation.processing.model.Model[]>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model[]\",\n                builder);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.Color;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.lang.model.element.TypeElement;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link EnumTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass EnumTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private EnumTypeDefinitionBuilder builder;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(Color.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new EnumTypeDefinitionBuilder();\n    }\n\n    @Test\n    void testAccept() {\n        TypeElement typeElement = getType(Color.class);\n        assertTrue(builder.accept(processingEnv, typeElement.asType()));\n    }\n\n    @Test\n    void testBuild() {\n        TypeElement typeElement = getType(Color.class);\n        Map<String, TypeDefinition> typeCache = new HashMap<>();\n        TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, typeElement, typeCache);\n        assertEquals(Color.class.getName(), typeDefinition.getType());\n        assertEquals(asList(\"RED\", \"YELLOW\", \"BLUE\"), typeDefinition.getEnums());\n        //        assertEquals(typeDefinition.getTypeBuilderName(), builder.getClass().getName());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel;\nimport org.apache.dubbo.metadata.annotation.processing.model.CollectionTypeModel;\nimport org.apache.dubbo.metadata.annotation.processing.model.Color;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\nimport org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel;\nimport org.apache.dubbo.metadata.annotation.processing.model.SimpleTypeModel;\n\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link GeneralTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass GeneralTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private GeneralTypeDefinitionBuilder builder;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(Model.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new GeneralTypeDefinitionBuilder();\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, getType(Model.class).asType()));\n        assertTrue(\n                builder.accept(processingEnv, getType(PrimitiveTypeModel.class).asType()));\n        assertTrue(builder.accept(processingEnv, getType(SimpleTypeModel.class).asType()));\n        assertTrue(builder.accept(processingEnv, getType(ArrayTypeModel.class).asType()));\n        assertTrue(\n                builder.accept(processingEnv, getType(CollectionTypeModel.class).asType()));\n        assertFalse(builder.accept(processingEnv, getType(Color.class).asType()));\n    }\n\n    @Test\n    void testBuild() {}\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.MapTypeModel;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link MapTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass MapTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private MapTypeDefinitionBuilder builder;\n\n    private VariableElement stringsField;\n\n    private VariableElement colorsField;\n\n    private VariableElement primitiveTypeModelsField;\n\n    private VariableElement modelsField;\n\n    private VariableElement modelArraysField;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(MapTypeModel.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new MapTypeDefinitionBuilder();\n        TypeElement testType = getType(MapTypeModel.class);\n        stringsField = findField(testType, \"strings\");\n        colorsField = findField(testType, \"colors\");\n        primitiveTypeModelsField = findField(testType, \"primitiveTypeModels\");\n        modelsField = findField(testType, \"models\");\n        modelArraysField = findField(testType, \"modelArrays\");\n\n        assertEquals(\"strings\", stringsField.getSimpleName().toString());\n        assertEquals(\"colors\", colorsField.getSimpleName().toString());\n        assertEquals(\n                \"primitiveTypeModels\", primitiveTypeModelsField.getSimpleName().toString());\n        assertEquals(\"models\", modelsField.getSimpleName().toString());\n        assertEquals(\"modelArrays\", modelArraysField.getSimpleName().toString());\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, stringsField.asType()));\n        assertTrue(builder.accept(processingEnv, colorsField.asType()));\n        assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType()));\n        assertTrue(builder.accept(processingEnv, modelsField.asType()));\n        assertTrue(builder.accept(processingEnv, modelArraysField.asType()));\n    }\n\n    @Test\n    void testBuild() {\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                stringsField,\n                \"java.util.Map<java.lang.String,java.lang.String>\",\n                \"java.lang.String\",\n                \"java.lang.String\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                colorsField,\n                \"java.util.SortedMap<java.lang.String,org.apache.dubbo.metadata.annotation.processing.model.Color>\",\n                \"java.lang.String\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Color\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                primitiveTypeModelsField,\n                \"java.util.NavigableMap<org.apache.dubbo.metadata.annotation.processing.model.Color,org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Color\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                modelsField,\n                \"java.util.HashMap<java.lang.String,org.apache.dubbo.metadata.annotation.processing.model.Model>\",\n                \"java.lang.String\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                modelArraysField,\n                \"java.util.TreeMap<org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel,org.apache.dubbo.metadata.annotation.processing.model.Model[]>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model[]\",\n                builder);\n    }\n\n    static void buildAndAssertTypeDefinition(\n            ProcessingEnvironment processingEnv,\n            VariableElement field,\n            String expectedType,\n            String keyType,\n            String valueType,\n            TypeBuilder builder,\n            BiConsumer<TypeDefinition, TypeDefinition>... assertions) {\n        Map<String, TypeDefinition> typeCache = new HashMap<>();\n        TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field, typeCache);\n        String keyTypeName = typeDefinition.getItems().get(0);\n        TypeDefinition keyTypeDefinition = typeCache.get(keyTypeName);\n        String valueTypeName = typeDefinition.getItems().get(1);\n        TypeDefinition valueTypeDefinition = typeCache.get(valueTypeName);\n        assertEquals(expectedType, typeDefinition.getType());\n        //        assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref());\n        assertEquals(keyType, keyTypeDefinition.getType());\n        assertEquals(valueType, valueTypeDefinition.getType());\n        //        assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName());\n        Stream.of(assertions).forEach(assertion -> assertion.accept(typeDefinition, keyTypeDefinition));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link PrimitiveTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass PrimitiveTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private PrimitiveTypeDefinitionBuilder builder;\n\n    private VariableElement zField;\n\n    private VariableElement bField;\n\n    private VariableElement cField;\n\n    private VariableElement sField;\n\n    private VariableElement iField;\n\n    private VariableElement lField;\n\n    private VariableElement fField;\n\n    private VariableElement dField;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(PrimitiveTypeModel.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n\n        builder = new PrimitiveTypeDefinitionBuilder();\n\n        TypeElement testType = getType(PrimitiveTypeModel.class);\n\n        zField = findField(testType, \"z\");\n        bField = findField(testType, \"b\");\n        cField = findField(testType, \"c\");\n        sField = findField(testType, \"s\");\n        iField = findField(testType, \"i\");\n        lField = findField(testType, \"l\");\n        fField = findField(testType, \"f\");\n        dField = findField(testType, \"d\");\n\n        assertEquals(\"boolean\", zField.asType().toString());\n        assertEquals(\"byte\", bField.asType().toString());\n        assertEquals(\"char\", cField.asType().toString());\n        assertEquals(\"short\", sField.asType().toString());\n        assertEquals(\"int\", iField.asType().toString());\n        assertEquals(\"long\", lField.asType().toString());\n        assertEquals(\"float\", fField.asType().toString());\n        assertEquals(\"double\", dField.asType().toString());\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, zField.asType()));\n        assertTrue(builder.accept(processingEnv, bField.asType()));\n        assertTrue(builder.accept(processingEnv, cField.asType()));\n        assertTrue(builder.accept(processingEnv, sField.asType()));\n        assertTrue(builder.accept(processingEnv, iField.asType()));\n        assertTrue(builder.accept(processingEnv, lField.asType()));\n        assertTrue(builder.accept(processingEnv, fField.asType()));\n        assertTrue(builder.accept(processingEnv, dField.asType()));\n    }\n\n    @Test\n    void testBuild() {\n        buildAndAssertTypeDefinition(processingEnv, zField, builder);\n        buildAndAssertTypeDefinition(processingEnv, bField, builder);\n        buildAndAssertTypeDefinition(processingEnv, cField, builder);\n        buildAndAssertTypeDefinition(processingEnv, sField, builder);\n        buildAndAssertTypeDefinition(processingEnv, iField, builder);\n        buildAndAssertTypeDefinition(processingEnv, lField, builder);\n        buildAndAssertTypeDefinition(processingEnv, zField, builder);\n        buildAndAssertTypeDefinition(processingEnv, fField, builder);\n        buildAndAssertTypeDefinition(processingEnv, dField, builder);\n    }\n\n    static void buildAndAssertTypeDefinition(\n            ProcessingEnvironment processingEnv, VariableElement field, TypeBuilder builder) {\n        Map<String, TypeDefinition> typeCache = new HashMap<>();\n        TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field, typeCache);\n        assertBasicTypeDefinition(typeDefinition, field.asType().toString(), builder);\n        //        assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref());\n    }\n\n    static void assertBasicTypeDefinition(TypeDefinition typeDefinition, String type, TypeBuilder builder) {\n        assertEquals(type, typeDefinition.getType());\n        //        assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName());\n        assertTrue(typeDefinition.getProperties().isEmpty());\n        assertTrue(typeDefinition.getItems().isEmpty());\n        assertTrue(typeDefinition.getEnums().isEmpty());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.builder.ServiceDefinitionBuilder.build;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link ServiceDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass ServiceDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(TestServiceImpl.class);\n    }\n\n    @Override\n    protected void beforeEach() {}\n\n    @Test\n    void testBuild() {\n        ServiceDefinition serviceDefinition = build(processingEnv, getType(TestServiceImpl.class));\n        assertEquals(TestServiceImpl.class.getTypeName(), serviceDefinition.getCanonicalName());\n        assertEquals(\"org/apache/dubbo/metadata/tools/TestServiceImpl.class\", serviceDefinition.getCodeSource());\n\n        // types\n        List<String> typeNames = Arrays.asList(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                \"org.apache.dubbo.metadata.tools.GenericTestService\",\n                \"org.apache.dubbo.metadata.tools.DefaultTestService\",\n                \"org.apache.dubbo.metadata.tools.TestService\",\n                \"java.lang.AutoCloseable\",\n                \"java.io.Serializable\",\n                \"java.util.EventListener\");\n        for (String typeName : typeNames) {\n            String gotTypeName = getTypeName(typeName, serviceDefinition.getTypes());\n            assertEquals(typeName, gotTypeName);\n        }\n\n        // methods\n        assertEquals(14, serviceDefinition.getMethods().size());\n    }\n\n    private static String getTypeName(String type, List<TypeDefinition> types) {\n        for (TypeDefinition typeDefinition : types) {\n            if (type.equals(typeDefinition.getType())) {\n                return typeDefinition.getType();\n            }\n        }\n        return type;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.SimpleTypeModel;\n\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.builder.PrimitiveTypeDefinitionBuilderTest.buildAndAssertTypeDefinition;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link SimpleTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass SimpleTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private SimpleTypeDefinitionBuilder builder;\n\n    private VariableElement vField;\n\n    private VariableElement zField;\n\n    private VariableElement cField;\n\n    private VariableElement bField;\n\n    private VariableElement sField;\n\n    private VariableElement iField;\n\n    private VariableElement lField;\n\n    private VariableElement fField;\n\n    private VariableElement dField;\n\n    private VariableElement strField;\n\n    private VariableElement bdField;\n\n    private VariableElement biField;\n\n    private VariableElement dtField;\n\n    private VariableElement invalidField;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(SimpleTypeModel.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new SimpleTypeDefinitionBuilder();\n        TypeElement testType = getType(SimpleTypeModel.class);\n        vField = findField(testType, \"v\");\n        zField = findField(testType, \"z\");\n        cField = findField(testType, \"c\");\n        bField = findField(testType, \"b\");\n        sField = findField(testType, \"s\");\n        iField = findField(testType, \"i\");\n        lField = findField(testType, \"l\");\n        fField = findField(testType, \"f\");\n        dField = findField(testType, \"d\");\n        strField = findField(testType, \"str\");\n        bdField = findField(testType, \"bd\");\n        biField = findField(testType, \"bi\");\n        dtField = findField(testType, \"dt\");\n        invalidField = findField(testType, \"invalid\");\n\n        assertEquals(\"java.lang.Void\", vField.asType().toString());\n        assertEquals(\"java.lang.Boolean\", zField.asType().toString());\n        assertEquals(\"java.lang.Character\", cField.asType().toString());\n        assertEquals(\"java.lang.Byte\", bField.asType().toString());\n        assertEquals(\"java.lang.Short\", sField.asType().toString());\n        assertEquals(\"java.lang.Integer\", iField.asType().toString());\n        assertEquals(\"java.lang.Long\", lField.asType().toString());\n        assertEquals(\"java.lang.Float\", fField.asType().toString());\n        assertEquals(\"java.lang.Double\", dField.asType().toString());\n        assertEquals(\"java.lang.String\", strField.asType().toString());\n        assertEquals(\"java.math.BigDecimal\", bdField.asType().toString());\n        assertEquals(\"java.math.BigInteger\", biField.asType().toString());\n        assertEquals(\"java.util.Date\", dtField.asType().toString());\n        assertEquals(\"int\", invalidField.asType().toString());\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, vField.asType()));\n        assertTrue(builder.accept(processingEnv, zField.asType()));\n        assertTrue(builder.accept(processingEnv, cField.asType()));\n        assertTrue(builder.accept(processingEnv, bField.asType()));\n        assertTrue(builder.accept(processingEnv, sField.asType()));\n        assertTrue(builder.accept(processingEnv, iField.asType()));\n        assertTrue(builder.accept(processingEnv, lField.asType()));\n        assertTrue(builder.accept(processingEnv, fField.asType()));\n        assertTrue(builder.accept(processingEnv, dField.asType()));\n        assertTrue(builder.accept(processingEnv, strField.asType()));\n        assertTrue(builder.accept(processingEnv, bdField.asType()));\n        assertTrue(builder.accept(processingEnv, biField.asType()));\n        assertTrue(builder.accept(processingEnv, dtField.asType()));\n        // false condition\n        assertFalse(builder.accept(processingEnv, invalidField.asType()));\n    }\n\n    @Test\n    void testBuild() {\n        buildAndAssertTypeDefinition(processingEnv, vField, builder);\n        buildAndAssertTypeDefinition(processingEnv, zField, builder);\n        buildAndAssertTypeDefinition(processingEnv, cField, builder);\n        buildAndAssertTypeDefinition(processingEnv, sField, builder);\n        buildAndAssertTypeDefinition(processingEnv, iField, builder);\n        buildAndAssertTypeDefinition(processingEnv, lField, builder);\n        buildAndAssertTypeDefinition(processingEnv, fField, builder);\n        buildAndAssertTypeDefinition(processingEnv, dField, builder);\n        buildAndAssertTypeDefinition(processingEnv, strField, builder);\n        buildAndAssertTypeDefinition(processingEnv, bdField, builder);\n        buildAndAssertTypeDefinition(processingEnv, biField, builder);\n        buildAndAssertTypeDefinition(processingEnv, dtField, builder);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/ArrayTypeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\n/**\n * Array Type Model\n *\n * @since 2.7.6\n */\npublic class ArrayTypeModel {\n\n    private int[] integers; // Primitive type array\n\n    private String[] strings; // Simple type array\n\n    private PrimitiveTypeModel[] primitiveTypeModels; // Complex type array\n\n    private Model[] models; // Hierarchical Complex type array\n\n    private Color[] colors; // Enum type array\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/CollectionTypeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.List;\nimport java.util.Queue;\nimport java.util.Set;\n\n/**\n * {@link Collection} Type Model\n *\n * @since 2.7.6\n */\npublic class CollectionTypeModel {\n\n    private Collection<String> strings; // The composite element is simple type\n\n    private List<Color> colors; // The composite element is Enum type\n\n    private Queue<PrimitiveTypeModel> primitiveTypeModels; // The composite element is POJO type\n\n    private Deque<Model> models; // The composite element is hierarchical POJO type\n\n    private Set<Model[]> modelArrays; // The composite element is hierarchical POJO type\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Color.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\n/**\n * Color enumeration\n *\n * @since 2.7.6\n */\npublic enum Color {\n    RED(1),\n    YELLOW(2),\n    BLUE(3);\n\n    private final int value;\n\n    Color(int value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return \"Color{\" + \"value=\" + value + \"} \" + super.toString();\n    }\n\n    public int getValue() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/MapTypeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.NavigableMap;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\n/**\n * {@link Map} Type model\n *\n * @since 2.7.6\n */\npublic class MapTypeModel {\n\n    private Map<String, String> strings; // The composite element is simple type\n\n    private SortedMap<String, Color> colors; // The composite element is Enum type\n\n    private NavigableMap<Color, PrimitiveTypeModel> primitiveTypeModels; // The composite element is POJO type\n\n    private HashMap<String, Model> models; // The composite element is hierarchical POJO type\n\n    private TreeMap<PrimitiveTypeModel, Model[]> modelArrays; // The composite element is hierarchical POJO type\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Model.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\nimport org.apache.dubbo.metadata.tools.Parent;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Model Object\n */\npublic class Model extends Parent {\n\n    private float f;\n\n    private double d;\n\n    private TimeUnit tu;\n\n    private String str;\n\n    private BigInteger bi;\n\n    private BigDecimal bd;\n\n    public float getF() {\n        return f;\n    }\n\n    public void setF(float f) {\n        this.f = f;\n    }\n\n    public double getD() {\n        return d;\n    }\n\n    public void setD(double d) {\n        this.d = d;\n    }\n\n    public TimeUnit getTu() {\n        return tu;\n    }\n\n    public void setTu(TimeUnit tu) {\n        this.tu = tu;\n    }\n\n    public String getStr() {\n        return str;\n    }\n\n    public void setStr(String str) {\n        this.str = str;\n    }\n\n    public BigInteger getBi() {\n        return bi;\n    }\n\n    public void setBi(BigInteger bi) {\n        this.bi = bi;\n    }\n\n    public BigDecimal getBd() {\n        return bd;\n    }\n\n    public void setBd(BigDecimal bd) {\n        this.bd = bd;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/PrimitiveTypeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\n/**\n * Primitive Type model\n *\n * @since 2.7.6\n */\npublic class PrimitiveTypeModel {\n\n    private boolean z;\n\n    private byte b;\n\n    private char c;\n\n    private short s;\n\n    private int i;\n\n    private long l;\n\n    private float f;\n\n    private double d;\n\n    public boolean isZ() {\n        return z;\n    }\n\n    public byte getB() {\n        return b;\n    }\n\n    public char getC() {\n        return c;\n    }\n\n    public short getS() {\n        return s;\n    }\n\n    public int getI() {\n        return i;\n    }\n\n    public long getL() {\n        return l;\n    }\n\n    public float getF() {\n        return f;\n    }\n\n    public double getD() {\n        return d;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/SimpleTypeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.Date;\n\n/**\n * Simple Type model\n *\n * @since 2.7.6\n */\npublic class SimpleTypeModel {\n\n    private Void v;\n\n    private Boolean z;\n\n    private Character c;\n\n    private Byte b;\n\n    private Short s;\n\n    private Integer i;\n\n    private Long l;\n\n    private Float f;\n\n    private Double d;\n\n    private String str;\n\n    private BigDecimal bd;\n\n    private BigInteger bi;\n\n    private Date dt;\n\n    private int invalid;\n\n    public Void getV() {\n        return v;\n    }\n\n    public void setV(Void v) {\n        this.v = v;\n    }\n\n    public Boolean getZ() {\n        return z;\n    }\n\n    public void setZ(Boolean z) {\n        this.z = z;\n    }\n\n    public Character getC() {\n        return c;\n    }\n\n    public void setC(Character c) {\n        this.c = c;\n    }\n\n    public Byte getB() {\n        return b;\n    }\n\n    public void setB(Byte b) {\n        this.b = b;\n    }\n\n    public Short getS() {\n        return s;\n    }\n\n    public void setS(Short s) {\n        this.s = s;\n    }\n\n    public Integer getI() {\n        return i;\n    }\n\n    public void setI(Integer i) {\n        this.i = i;\n    }\n\n    public Long getL() {\n        return l;\n    }\n\n    public void setL(Long l) {\n        this.l = l;\n    }\n\n    public Float getF() {\n        return f;\n    }\n\n    public void setF(Float f) {\n        this.f = f;\n    }\n\n    public Double getD() {\n        return d;\n    }\n\n    public void setD(Double d) {\n        this.d = d;\n    }\n\n    public String getStr() {\n        return str;\n    }\n\n    public void setStr(String str) {\n        this.str = str;\n    }\n\n    public BigDecimal getBd() {\n        return bd;\n    }\n\n    public void setBd(BigDecimal bd) {\n        this.bd = bd;\n    }\n\n    public BigInteger getBi() {\n        return bi;\n    }\n\n    public void setBi(BigInteger bi) {\n        this.bi = bi;\n    }\n\n    public Date getDt() {\n        return dt;\n    }\n\n    public void setDt(Date dt) {\n        this.dt = dt;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.tools.TestService;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.AnnotationMirror;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.TypeMirror;\nimport javax.ws.rs.Path;\n\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findAnnotation;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findMetaAnnotation;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAllAnnotations;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAnnotation;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAnnotations;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getValue;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getAllDeclaredMethods;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * The {@link AnnotationUtils} Test\n *\n * @since 2.7.6\n */\nclass AnnotationUtilsTest extends AbstractAnnotationProcessingTest {\n\n    private TypeElement testType;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {}\n\n    @Override\n    protected void beforeEach() {\n        testType = getType(TestServiceImpl.class);\n    }\n\n    @Test\n    void testGetAnnotation() {\n        AnnotationMirror serviceAnnotation = getAnnotation(testType, Service.class);\n        assertEquals(\"3.0.0\", getAttribute(serviceAnnotation, \"version\"));\n        assertEquals(\"test\", getAttribute(serviceAnnotation, \"group\"));\n        assertEquals(\"org.apache.dubbo.metadata.tools.TestService\", getAttribute(serviceAnnotation, \"interfaceName\"));\n\n        assertNull(getAnnotation(testType, (Class) null));\n        assertNull(getAnnotation(testType, (String) null));\n\n        assertNull(getAnnotation(testType.asType(), (Class) null));\n        assertNull(getAnnotation(testType.asType(), (String) null));\n\n        assertNull(getAnnotation((Element) null, (Class) null));\n        assertNull(getAnnotation((Element) null, (String) null));\n\n        assertNull(getAnnotation((TypeElement) null, (Class) null));\n        assertNull(getAnnotation((TypeElement) null, (String) null));\n    }\n\n    @Test\n    void testGetAnnotations() {\n        List<AnnotationMirror> annotations = getAnnotations(testType);\n        Iterator<AnnotationMirror> iterator = annotations.iterator();\n\n        assertEquals(2, annotations.size());\n        assertEquals(\n                \"com.alibaba.dubbo.config.annotation.Service\",\n                iterator.next().getAnnotationType().toString());\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                iterator.next().getAnnotationType().toString());\n\n        annotations = getAnnotations(testType, Service.class);\n        iterator = annotations.iterator();\n        assertEquals(1, annotations.size());\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                iterator.next().getAnnotationType().toString());\n\n        annotations = getAnnotations(testType.asType(), Service.class);\n        iterator = annotations.iterator();\n        assertEquals(1, annotations.size());\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                iterator.next().getAnnotationType().toString());\n\n        annotations = getAnnotations(testType.asType(), Service.class.getTypeName());\n        iterator = annotations.iterator();\n        assertEquals(1, annotations.size());\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                iterator.next().getAnnotationType().toString());\n\n        annotations = getAnnotations(testType, Override.class);\n        assertEquals(0, annotations.size());\n\n        annotations = getAnnotations(testType, com.alibaba.dubbo.config.annotation.Service.class);\n        assertEquals(1, annotations.size());\n\n        assertTrue(getAnnotations(null, (Class) null).isEmpty());\n        assertTrue(getAnnotations(null, (String) null).isEmpty());\n        assertTrue(getAnnotations(testType, (Class) null).isEmpty());\n        assertTrue(getAnnotations(testType, (String) null).isEmpty());\n\n        assertTrue(getAnnotations(null, Service.class).isEmpty());\n        assertTrue(getAnnotations(null, Service.class.getTypeName()).isEmpty());\n    }\n\n    @Test\n    void testGetAllAnnotations() {\n\n        List<AnnotationMirror> annotations = getAllAnnotations(testType);\n        assertEquals(5, annotations.size());\n\n        annotations = getAllAnnotations(testType.asType(), annotation -> true);\n        assertEquals(5, annotations.size());\n\n        annotations = getAllAnnotations(processingEnv, TestServiceImpl.class);\n        assertEquals(5, annotations.size());\n\n        annotations = getAllAnnotations(testType.asType(), Service.class);\n        assertEquals(2, annotations.size());\n\n        annotations = getAllAnnotations(testType, Override.class);\n        assertEquals(0, annotations.size());\n\n        annotations = getAllAnnotations(testType.asType(), com.alibaba.dubbo.config.annotation.Service.class);\n        assertEquals(2, annotations.size());\n\n        assertTrue(getAllAnnotations((Element) null, (Class) null).isEmpty());\n        assertTrue(getAllAnnotations((TypeMirror) null, (String) null).isEmpty());\n        assertTrue(getAllAnnotations((ProcessingEnvironment) null, (Class) null).isEmpty());\n        assertTrue(\n                getAllAnnotations((ProcessingEnvironment) null, (String) null).isEmpty());\n\n        assertTrue(getAllAnnotations((Element) null).isEmpty());\n        assertTrue(getAllAnnotations((TypeMirror) null).isEmpty());\n        assertTrue(getAllAnnotations(processingEnv, (Class) null).isEmpty());\n        assertTrue(getAllAnnotations(processingEnv, (String) null).isEmpty());\n\n        assertTrue(getAllAnnotations(testType, (Class) null).isEmpty());\n        assertTrue(getAllAnnotations(testType.asType(), (Class) null).isEmpty());\n\n        assertTrue(getAllAnnotations(testType, (String) null).isEmpty());\n        assertTrue(getAllAnnotations(testType.asType(), (String) null).isEmpty());\n\n        assertTrue(getAllAnnotations((Element) null, Service.class).isEmpty());\n        assertTrue(getAllAnnotations((TypeMirror) null, Service.class.getTypeName())\n                .isEmpty());\n    }\n\n    @Test\n    void testFindAnnotation() {\n\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                findAnnotation(testType, Service.class).getAnnotationType().toString());\n        assertEquals(\n                \"com.alibaba.dubbo.config.annotation.Service\",\n                findAnnotation(testType, com.alibaba.dubbo.config.annotation.Service.class)\n                        .getAnnotationType()\n                        .toString());\n        assertEquals(\n                \"javax.ws.rs.Path\",\n                findAnnotation(testType, Path.class).getAnnotationType().toString());\n        assertEquals(\n                \"javax.ws.rs.Path\",\n                findAnnotation(testType.asType(), Path.class)\n                        .getAnnotationType()\n                        .toString());\n        assertEquals(\n                \"javax.ws.rs.Path\",\n                findAnnotation(testType.asType(), Path.class.getTypeName())\n                        .getAnnotationType()\n                        .toString());\n        assertNull(findAnnotation(testType, Override.class));\n\n        assertNull(findAnnotation((Element) null, (Class) null));\n        assertNull(findAnnotation((Element) null, (String) null));\n        assertNull(findAnnotation((TypeMirror) null, (Class) null));\n        assertNull(findAnnotation((TypeMirror) null, (String) null));\n\n        assertNull(findAnnotation(testType, (Class) null));\n        assertNull(findAnnotation(testType, (String) null));\n        assertNull(findAnnotation(testType.asType(), (Class) null));\n        assertNull(findAnnotation(testType.asType(), (String) null));\n    }\n\n    @Test\n    void testFindMetaAnnotation() {\n        getAllDeclaredMethods(getType(TestService.class)).forEach(method -> {\n            assertEquals(\n                    \"javax.ws.rs.HttpMethod\",\n                    findMetaAnnotation(method, \"javax.ws.rs.HttpMethod\")\n                            .getAnnotationType()\n                            .toString());\n        });\n    }\n\n    @Test\n    void testGetAttribute() {\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\",\n                getAttribute(findAnnotation(testType, Service.class), \"interfaceName\"));\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\",\n                getAttribute(findAnnotation(testType, Service.class).getElementValues(), \"interfaceName\"));\n        assertEquals(\"/echo\", getAttribute(findAnnotation(testType, Path.class), \"value\"));\n\n        assertNull(getAttribute(findAnnotation(testType, Path.class), null));\n        assertNull(getAttribute(findAnnotation(testType, (Class) null), null));\n    }\n\n    @Test\n    void testGetValue() {\n        AnnotationMirror pathAnnotation = getAnnotation(getType(TestService.class), Path.class);\n        assertEquals(\"/echo\", getValue(pathAnnotation));\n    }\n\n    @Test\n    void testIsAnnotationPresent() {\n        assertTrue(isAnnotationPresent(testType, \"org.apache.dubbo.config.annotation.Service\"));\n        assertTrue(isAnnotationPresent(testType, \"com.alibaba.dubbo.config.annotation.Service\"));\n        assertTrue(isAnnotationPresent(testType, \"javax.ws.rs.Path\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.Color;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.lang.reflect.Type;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Test;\n\nimport static javax.lang.model.element.Modifier.FINAL;\nimport static javax.lang.model.element.Modifier.PRIVATE;\nimport static javax.lang.model.element.Modifier.PUBLIC;\nimport static javax.lang.model.element.Modifier.STATIC;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getAllDeclaredFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getAllNonStaticFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredField;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getNonStaticFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isEnumMemberField;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isField;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isNonStaticField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link FieldUtils} Test\n *\n * @since 2.7.6\n */\nclass FieldUtilsTest extends AbstractAnnotationProcessingTest {\n\n    private TypeElement testType;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {}\n\n    @Override\n    protected void beforeEach() {\n        testType = getType(TestServiceImpl.class);\n    }\n\n    @Test\n    void testGetDeclaredFields() {\n        TypeElement type = getType(Model.class);\n        List<VariableElement> fields = getDeclaredFields(type);\n        assertModelFields(fields);\n\n        fields = getDeclaredFields(type.asType());\n        assertModelFields(fields);\n\n        assertTrue(getDeclaredFields((Element) null).isEmpty());\n        assertTrue(getDeclaredFields((TypeMirror) null).isEmpty());\n\n        fields = getDeclaredFields(type, f -> \"f\".equals(f.getSimpleName().toString()));\n        assertEquals(1, fields.size());\n        assertEquals(\"f\", fields.get(0).getSimpleName().toString());\n    }\n\n    @Test\n    void testGetAllDeclaredFields() {\n        TypeElement type = getType(Model.class);\n\n        List<VariableElement> fields = getAllDeclaredFields(type);\n\n        assertModelAllFields(fields);\n\n        assertTrue(getAllDeclaredFields((Element) null).isEmpty());\n        assertTrue(getAllDeclaredFields((TypeMirror) null).isEmpty());\n\n        fields = getAllDeclaredFields(type, f -> \"f\".equals(f.getSimpleName().toString()));\n        assertEquals(1, fields.size());\n        assertEquals(\"f\", fields.get(0).getSimpleName().toString());\n    }\n\n    @Test\n    void testGetDeclaredField() {\n        TypeElement type = getType(Model.class);\n        testGetDeclaredField(type, \"f\", float.class);\n        testGetDeclaredField(type, \"d\", double.class);\n        testGetDeclaredField(type, \"tu\", TimeUnit.class);\n        testGetDeclaredField(type, \"str\", String.class);\n        testGetDeclaredField(type, \"bi\", BigInteger.class);\n        testGetDeclaredField(type, \"bd\", BigDecimal.class);\n\n        assertNull(getDeclaredField(type, \"b\"));\n        assertNull(getDeclaredField(type, \"s\"));\n        assertNull(getDeclaredField(type, \"i\"));\n        assertNull(getDeclaredField(type, \"l\"));\n        assertNull(getDeclaredField(type, \"z\"));\n\n        assertNull(getDeclaredField((Element) null, \"z\"));\n        assertNull(getDeclaredField((TypeMirror) null, \"z\"));\n    }\n\n    @Test\n    void testFindField() {\n        TypeElement type = getType(Model.class);\n        testFindField(type, \"f\", float.class);\n        testFindField(type, \"d\", double.class);\n        testFindField(type, \"tu\", TimeUnit.class);\n        testFindField(type, \"str\", String.class);\n        testFindField(type, \"bi\", BigInteger.class);\n        testFindField(type, \"bd\", BigDecimal.class);\n        testFindField(type, \"b\", byte.class);\n        testFindField(type, \"s\", short.class);\n        testFindField(type, \"i\", int.class);\n        testFindField(type, \"l\", long.class);\n        testFindField(type, \"z\", boolean.class);\n\n        assertNull(findField((Element) null, \"f\"));\n        assertNull(findField((Element) null, null));\n\n        assertNull(findField((TypeMirror) null, \"f\"));\n        assertNull(findField((TypeMirror) null, null));\n\n        assertNull(findField(type, null));\n        assertNull(findField(type.asType(), null));\n    }\n\n    @Test\n    void testIsEnumField() {\n        TypeElement type = getType(Color.class);\n        VariableElement field = findField(type, \"RED\");\n        assertTrue(isEnumMemberField(field));\n\n        field = findField(type, \"YELLOW\");\n        assertTrue(isEnumMemberField(field));\n\n        field = findField(type, \"BLUE\");\n        assertTrue(isEnumMemberField(field));\n\n        type = getType(Model.class);\n        field = findField(type, \"f\");\n        assertFalse(isEnumMemberField(field));\n\n        assertFalse(isEnumMemberField(null));\n    }\n\n    @Test\n    void testIsNonStaticField() {\n        TypeElement type = getType(Model.class);\n        assertTrue(isNonStaticField(findField(type, \"f\")));\n\n        type = getType(Color.class);\n        assertFalse(isNonStaticField(findField(type, \"BLUE\")));\n    }\n\n    @Test\n    void testIsField() {\n        TypeElement type = getType(Model.class);\n        assertTrue(isField(findField(type, \"f\")));\n        assertTrue(isField(findField(type, \"f\"), PRIVATE));\n\n        type = getType(Color.class);\n        assertTrue(isField(findField(type, \"BLUE\"), PUBLIC, STATIC, FINAL));\n\n        assertFalse(isField(null));\n        assertFalse(isField(null, PUBLIC, STATIC, FINAL));\n    }\n\n    @Test\n    void testGetNonStaticFields() {\n        TypeElement type = getType(Model.class);\n\n        List<VariableElement> fields = getNonStaticFields(type);\n        assertModelFields(fields);\n\n        fields = getNonStaticFields(type.asType());\n        assertModelFields(fields);\n\n        assertTrue(getAllNonStaticFields((Element) null).isEmpty());\n        assertTrue(getAllNonStaticFields((TypeMirror) null).isEmpty());\n    }\n\n    @Test\n    void testGetAllNonStaticFields() {\n        TypeElement type = getType(Model.class);\n\n        List<VariableElement> fields = getAllNonStaticFields(type);\n        assertModelAllFields(fields);\n\n        fields = getAllNonStaticFields(type.asType());\n        assertModelAllFields(fields);\n\n        assertTrue(getAllNonStaticFields((Element) null).isEmpty());\n        assertTrue(getAllNonStaticFields((TypeMirror) null).isEmpty());\n    }\n\n    private void assertModelFields(List<VariableElement> fields) {\n        assertEquals(6, fields.size());\n        assertEquals(\"d\", fields.get(1).getSimpleName().toString());\n        assertEquals(\"tu\", fields.get(2).getSimpleName().toString());\n        assertEquals(\"str\", fields.get(3).getSimpleName().toString());\n        assertEquals(\"bi\", fields.get(4).getSimpleName().toString());\n        assertEquals(\"bd\", fields.get(5).getSimpleName().toString());\n    }\n\n    private void assertModelAllFields(List<VariableElement> fields) {\n        assertEquals(11, fields.size());\n        assertEquals(\"f\", fields.get(0).getSimpleName().toString());\n        assertEquals(\"d\", fields.get(1).getSimpleName().toString());\n        assertEquals(\"tu\", fields.get(2).getSimpleName().toString());\n        assertEquals(\"str\", fields.get(3).getSimpleName().toString());\n        assertEquals(\"bi\", fields.get(4).getSimpleName().toString());\n        assertEquals(\"bd\", fields.get(5).getSimpleName().toString());\n        assertEquals(\"b\", fields.get(6).getSimpleName().toString());\n        assertEquals(\"s\", fields.get(7).getSimpleName().toString());\n        assertEquals(\"i\", fields.get(8).getSimpleName().toString());\n        assertEquals(\"l\", fields.get(9).getSimpleName().toString());\n        assertEquals(\"z\", fields.get(10).getSimpleName().toString());\n    }\n\n    private void testGetDeclaredField(TypeElement type, String fieldName, Type fieldType) {\n        VariableElement field = getDeclaredField(type, fieldName);\n        assertField(field, fieldName, fieldType);\n    }\n\n    private void testFindField(TypeElement type, String fieldName, Type fieldType) {\n        VariableElement field = findField(type, fieldName);\n        assertField(field, fieldName, fieldType);\n    }\n\n    private void assertField(VariableElement field, String fieldName, Type fieldType) {\n        assertEquals(fieldName, field.getSimpleName().toString());\n        assertEquals(fieldType.getTypeName(), field.asType().toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.info;\nimport static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.warn;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\n\n/**\n * {@link LoggerUtils} Test\n *\n * @since 2.7.6\n */\nclass LoggerUtilsTest {\n\n    @Test\n    void testLogger() {\n        assertNotNull(LoggerUtils.LOGGER);\n    }\n\n    @Test\n    void testInfo() {\n        info(\"Hello,World\");\n        info(\"Hello,%s\", \"World\");\n        info(\"%s,%s\", \"Hello\", \"World\");\n    }\n\n    @Test\n    void testWarn() {\n        warn(\"Hello,World\");\n        warn(\"Hello,%s\", \"World\");\n        warn(\"%s,%s\", \"Hello\", \"World\");\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static javax.lang.model.element.Modifier.PRIVATE;\nimport static javax.lang.model.util.ElementFilter.fieldsIn;\nimport static javax.lang.model.util.ElementFilter.methodsIn;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getAllDeclaredMembers;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getDeclaredMembers;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.hasModifiers;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.isPublicNonStatic;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.matchParameterTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.findMethod;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link MemberUtils} Test\n *\n * @since 2.7.6\n */\nclass MemberUtilsTest extends AbstractAnnotationProcessingTest {\n\n    private TypeElement testType;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {}\n\n    @Override\n    protected void beforeEach() {\n        testType = getType(TestServiceImpl.class);\n    }\n\n    @Test\n    void testIsPublicNonStatic() {\n        assertFalse(isPublicNonStatic(null));\n        methodsIn(getDeclaredMembers(testType.asType())).forEach(method -> assertTrue(isPublicNonStatic(method)));\n    }\n\n    @Test\n    void testHasModifiers() {\n        assertFalse(hasModifiers(null));\n        List<? extends Element> members = getAllDeclaredMembers(testType.asType());\n        List<VariableElement> fields = fieldsIn(members);\n        assertTrue(hasModifiers(fields.get(0), PRIVATE));\n    }\n\n    @Test\n    void testDeclaredMembers() {\n        TypeElement type = getType(Model.class);\n        List<? extends Element> members = getDeclaredMembers(type.asType());\n        List<VariableElement> fields = fieldsIn(members);\n        assertEquals(19, members.size());\n        assertEquals(6, fields.size());\n        assertEquals(\"f\", fields.get(0).getSimpleName().toString());\n        assertEquals(\"d\", fields.get(1).getSimpleName().toString());\n        assertEquals(\"tu\", fields.get(2).getSimpleName().toString());\n        assertEquals(\"str\", fields.get(3).getSimpleName().toString());\n        assertEquals(\"bi\", fields.get(4).getSimpleName().toString());\n        assertEquals(\"bd\", fields.get(5).getSimpleName().toString());\n\n        members = getAllDeclaredMembers(type.asType());\n        fields = fieldsIn(members);\n        assertEquals(11, fields.size());\n        assertEquals(\"f\", fields.get(0).getSimpleName().toString());\n        assertEquals(\"d\", fields.get(1).getSimpleName().toString());\n        assertEquals(\"tu\", fields.get(2).getSimpleName().toString());\n        assertEquals(\"str\", fields.get(3).getSimpleName().toString());\n        assertEquals(\"bi\", fields.get(4).getSimpleName().toString());\n        assertEquals(\"bd\", fields.get(5).getSimpleName().toString());\n        assertEquals(\"b\", fields.get(6).getSimpleName().toString());\n        assertEquals(\"s\", fields.get(7).getSimpleName().toString());\n        assertEquals(\"i\", fields.get(8).getSimpleName().toString());\n        assertEquals(\"l\", fields.get(9).getSimpleName().toString());\n        assertEquals(\"z\", fields.get(10).getSimpleName().toString());\n    }\n\n    @Test\n    void testMatchParameterTypes() {\n        ExecutableElement method = findMethod(testType, \"echo\", \"java.lang.String\");\n        assertTrue(matchParameterTypes(method.getParameters(), \"java.lang.String\"));\n        assertFalse(matchParameterTypes(method.getParameters(), \"java.lang.Object\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\nimport org.apache.dubbo.metadata.tools.TestService;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.findMethod;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getAllDeclaredMethods;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getDeclaredMethods;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodName;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodParameterTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getOverrideMethod;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getPublicNonStaticMethods;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getReturnType;\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link MethodUtils} Test\n *\n * @since 2.7.6\n */\nclass MethodUtilsTest extends AbstractAnnotationProcessingTest {\n\n    private TypeElement testType;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {}\n\n    @Override\n    protected void beforeEach() {\n        testType = getType(TestServiceImpl.class);\n    }\n\n    @Test\n    void testDeclaredMethods() {\n        TypeElement type = getType(Model.class);\n        List<ExecutableElement> methods = getDeclaredMethods(type);\n        assertEquals(12, methods.size());\n\n        methods = getAllDeclaredMethods(type);\n        // registerNatives() no provided in JDK 17\n        assertTrue(methods.size() >= 33);\n\n        assertTrue(getAllDeclaredMethods((TypeElement) null).isEmpty());\n        assertTrue(getAllDeclaredMethods((TypeMirror) null).isEmpty());\n    }\n\n    private List<? extends ExecutableElement> doGetAllDeclaredMethods() {\n        return getAllDeclaredMethods(testType, Object.class);\n    }\n\n    @Test\n    void testGetAllDeclaredMethods() {\n        List<? extends ExecutableElement> methods = doGetAllDeclaredMethods();\n        assertEquals(14, methods.size());\n    }\n\n    @Test\n    void testGetPublicNonStaticMethods() {\n        List<? extends ExecutableElement> methods = getPublicNonStaticMethods(testType, Object.class);\n        assertEquals(14, methods.size());\n\n        methods = getPublicNonStaticMethods(testType.asType(), Object.class);\n        assertEquals(14, methods.size());\n    }\n\n    @Test\n    void testIsMethod() {\n        List<? extends ExecutableElement> methods = getPublicNonStaticMethods(testType, Object.class);\n        assertEquals(14, methods.stream().map(MethodUtils::isMethod).count());\n    }\n\n    @Test\n    void testIsPublicNonStaticMethod() {\n        List<? extends ExecutableElement> methods = getPublicNonStaticMethods(testType, Object.class);\n        assertEquals(\n                14, methods.stream().map(MethodUtils::isPublicNonStaticMethod).count());\n    }\n\n    @Test\n    void testFindMethod() {\n        TypeElement type = getType(Model.class);\n        // Test methods from java.lang.Object\n        // Object#toString()\n        String methodName = \"toString\";\n        ExecutableElement method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#hashCode()\n        methodName = \"hashCode\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#getClass()\n        methodName = \"getClass\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#finalize()\n        methodName = \"finalize\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#clone()\n        methodName = \"clone\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#notify()\n        methodName = \"notify\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#notifyAll()\n        methodName = \"notifyAll\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#wait(long)\n        methodName = \"wait\";\n        method = findMethod(type.asType(), methodName, long.class);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#wait(long,int)\n        methodName = \"wait\";\n        method = findMethod(type.asType(), methodName, long.class, int.class);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#equals(Object)\n        methodName = \"equals\";\n        method = findMethod(type.asType(), methodName, Object.class);\n        assertEquals(method.getSimpleName().toString(), methodName);\n    }\n\n    @Test\n    void testGetOverrideMethod() {\n        List<? extends ExecutableElement> methods = doGetAllDeclaredMethods();\n\n        ExecutableElement overrideMethod = getOverrideMethod(processingEnv, testType, methods.get(0));\n        assertNull(overrideMethod);\n\n        ExecutableElement declaringMethod = findMethod(getType(TestService.class), \"echo\", \"java.lang.String\");\n\n        overrideMethod = getOverrideMethod(processingEnv, testType, declaringMethod);\n        assertEquals(methods.get(0), overrideMethod);\n    }\n\n    @Test\n    void testGetMethodName() {\n        ExecutableElement method = findMethod(testType, \"echo\", \"java.lang.String\");\n        assertEquals(\"echo\", getMethodName(method));\n        assertNull(getMethodName(null));\n    }\n\n    @Test\n    void testReturnType() {\n        ExecutableElement method = findMethod(testType, \"echo\", \"java.lang.String\");\n        assertEquals(\"java.lang.String\", getReturnType(method));\n        assertNull(getReturnType(null));\n    }\n\n    @Test\n    void testMatchParameterTypes() {\n        ExecutableElement method = findMethod(testType, \"echo\", \"java.lang.String\");\n        assertArrayEquals(new String[] {\"java.lang.String\"}, getMethodParameterTypes(method));\n        assertTrue(getMethodParameterTypes(null).length == 0);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.tools.DefaultTestService;\nimport org.apache.dubbo.metadata.tools.GenericTestService;\nimport org.apache.dubbo.metadata.tools.TestService;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.lang.model.element.TypeElement;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.DUBBO_SERVICE_ANNOTATION_TYPE;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.GROUP_ATTRIBUTE_NAME;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.INTERFACE_CLASS_ATTRIBUTE_NAME;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.INTERFACE_NAME_ATTRIBUTE_NAME;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.LEGACY_SERVICE_ANNOTATION_TYPE;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SERVICE_ANNOTATION_TYPE;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SUPPORTED_ANNOTATION_TYPES;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.VERSION_ATTRIBUTE_NAME;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getAnnotation;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getGroup;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getVersion;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.isServiceAnnotationPresent;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.resolveServiceInterfaceName;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link ServiceAnnotationUtils} Test\n *\n * @since 2.7.6\n */\nclass ServiceAnnotationUtilsTest extends AbstractAnnotationProcessingTest {\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {}\n\n    @Override\n    protected void beforeEach() {}\n\n    @Test\n    void testConstants() {\n        assertEquals(\"org.apache.dubbo.config.annotation.DubboService\", DUBBO_SERVICE_ANNOTATION_TYPE);\n        assertEquals(\"org.apache.dubbo.config.annotation.Service\", SERVICE_ANNOTATION_TYPE);\n        assertEquals(\"com.alibaba.dubbo.config.annotation.Service\", LEGACY_SERVICE_ANNOTATION_TYPE);\n        assertEquals(\"interfaceClass\", INTERFACE_CLASS_ATTRIBUTE_NAME);\n        assertEquals(\"interfaceName\", INTERFACE_NAME_ATTRIBUTE_NAME);\n        assertEquals(\"group\", GROUP_ATTRIBUTE_NAME);\n        assertEquals(\"version\", VERSION_ATTRIBUTE_NAME);\n        assertEquals(\n                new LinkedHashSet<>(asList(\n                        \"org.apache.dubbo.config.annotation.DubboService\",\n                        \"org.apache.dubbo.config.annotation.Service\",\n                        \"com.alibaba.dubbo.config.annotation.Service\")),\n                SUPPORTED_ANNOTATION_TYPES);\n    }\n\n    @Test\n    void testIsServiceAnnotationPresent() {\n\n        assertTrue(isServiceAnnotationPresent(getType(TestServiceImpl.class)));\n        assertTrue(isServiceAnnotationPresent(getType(GenericTestService.class)));\n        assertTrue(isServiceAnnotationPresent(getType(DefaultTestService.class)));\n\n        assertFalse(isServiceAnnotationPresent(getType(TestService.class)));\n    }\n\n    @Test\n    void testGetAnnotation() {\n        TypeElement type = getType(TestServiceImpl.class);\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                getAnnotation(type).getAnnotationType().toString());\n\n        type = getType(GenericTestService.class);\n        assertEquals(\n                \"com.alibaba.dubbo.config.annotation.Service\",\n                getAnnotation(type).getAnnotationType().toString());\n\n        type = getType(DefaultTestService.class);\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                getAnnotation(type).getAnnotationType().toString());\n\n        assertThrows(IllegalArgumentException.class, () -> getAnnotation(getType(TestService.class)));\n    }\n\n    @Test\n    void testResolveServiceInterfaceName() {\n        TypeElement type = getType(TestServiceImpl.class);\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", resolveServiceInterfaceName(type, getAnnotation(type)));\n\n        type = getType(GenericTestService.class);\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", resolveServiceInterfaceName(type, getAnnotation(type)));\n\n        type = getType(DefaultTestService.class);\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", resolveServiceInterfaceName(type, getAnnotation(type)));\n    }\n\n    @Test\n    void testGetVersion() {\n        TypeElement type = getType(TestServiceImpl.class);\n        assertEquals(\"3.0.0\", getVersion(getAnnotation(type)));\n\n        type = getType(GenericTestService.class);\n        assertEquals(\"2.0.0\", getVersion(getAnnotation(type)));\n\n        type = getType(DefaultTestService.class);\n        assertEquals(\"1.0.0\", getVersion(getAnnotation(type)));\n    }\n\n    @Test\n    void testGetGroup() {\n        TypeElement type = getType(TestServiceImpl.class);\n        assertEquals(\"test\", getGroup(getAnnotation(type)));\n\n        type = getType(GenericTestService.class);\n        assertEquals(\"generic\", getGroup(getAnnotation(type)));\n\n        type = getType(DefaultTestService.class);\n        assertEquals(\"default\", getGroup(getAnnotation(type)));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel;\nimport org.apache.dubbo.metadata.annotation.processing.model.Color;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\nimport org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel;\nimport org.apache.dubbo.metadata.tools.DefaultTestService;\nimport org.apache.dubbo.metadata.tools.GenericTestService;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.DeclaredType;\nimport javax.lang.model.type.TypeKind;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.io.File;\nimport java.lang.reflect.Type;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getAllInterfaces;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getAllSuperTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getInterfaces;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResource;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResourceName;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getSuperType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isAnnotationType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isArrayType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isClassType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isDeclaredType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isEnumType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isInterfaceType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isPrimitiveType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSameType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSimpleType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isTypeElement;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.listDeclaredTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.listTypeElements;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofTypeElement;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * The {@link TypeUtils} Test\n *\n * @since 2.7.6\n */\nclass TypeUtilsTest extends AbstractAnnotationProcessingTest {\n\n    private TypeElement testType;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(ArrayTypeModel.class);\n        classesToBeCompiled.add(Color.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        testType = getType(TestServiceImpl.class);\n    }\n\n    @Test\n    void testIsSimpleType() {\n\n        assertTrue(isSimpleType(getType(Void.class)));\n        assertTrue(isSimpleType(getType(Boolean.class)));\n        assertTrue(isSimpleType(getType(Character.class)));\n        assertTrue(isSimpleType(getType(Byte.class)));\n        assertTrue(isSimpleType(getType(Short.class)));\n        assertTrue(isSimpleType(getType(Integer.class)));\n        assertTrue(isSimpleType(getType(Long.class)));\n        assertTrue(isSimpleType(getType(Float.class)));\n        assertTrue(isSimpleType(getType(Double.class)));\n        assertTrue(isSimpleType(getType(String.class)));\n        assertTrue(isSimpleType(getType(BigDecimal.class)));\n        assertTrue(isSimpleType(getType(BigInteger.class)));\n        assertTrue(isSimpleType(getType(Date.class)));\n        assertTrue(isSimpleType(getType(Object.class)));\n\n        assertFalse(isSimpleType(getType(getClass())));\n        assertFalse(isSimpleType((TypeElement) null));\n        assertFalse(isSimpleType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsSameType() {\n        assertTrue(isSameType(getType(Void.class).asType(), \"java.lang.Void\"));\n        assertFalse(isSameType(getType(String.class).asType(), \"java.lang.Void\"));\n\n        assertFalse(isSameType(getType(Void.class).asType(), (Type) null));\n        assertFalse(isSameType(null, (Type) null));\n\n        assertFalse(isSameType(getType(Void.class).asType(), (String) null));\n        assertFalse(isSameType(null, (String) null));\n    }\n\n    @Test\n    void testIsArrayType() {\n        TypeElement type = getType(ArrayTypeModel.class);\n        assertTrue(isArrayType(findField(type.asType(), \"integers\").asType()));\n        assertTrue(isArrayType(findField(type.asType(), \"strings\").asType()));\n        assertTrue(isArrayType(findField(type.asType(), \"primitiveTypeModels\").asType()));\n        assertTrue(isArrayType(findField(type.asType(), \"models\").asType()));\n        assertTrue(isArrayType(findField(type.asType(), \"colors\").asType()));\n\n        assertFalse(isArrayType((Element) null));\n        assertFalse(isArrayType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsEnumType() {\n        TypeElement type = getType(Color.class);\n        assertTrue(isEnumType(type.asType()));\n\n        type = getType(ArrayTypeModel.class);\n        assertFalse(isEnumType(type.asType()));\n\n        assertFalse(isEnumType((Element) null));\n        assertFalse(isEnumType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsClassType() {\n        TypeElement type = getType(ArrayTypeModel.class);\n        assertTrue(isClassType(type.asType()));\n\n        type = getType(Model.class);\n        assertTrue(isClassType(type.asType()));\n\n        assertFalse(isClassType((Element) null));\n        assertFalse(isClassType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsPrimitiveType() {\n        TypeElement type = getType(PrimitiveTypeModel.class);\n        getDeclaredFields(type.asType()).stream()\n                .map(VariableElement::asType)\n                .forEach(t -> assertTrue(isPrimitiveType(t)));\n\n        assertFalse(isPrimitiveType(getType(ArrayTypeModel.class)));\n\n        assertFalse(isPrimitiveType((Element) null));\n        assertFalse(isPrimitiveType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsInterfaceType() {\n        TypeElement type = getType(CharSequence.class);\n        assertTrue(isInterfaceType(type));\n        assertTrue(isInterfaceType(type.asType()));\n\n        type = getType(Model.class);\n        assertFalse(isInterfaceType(type));\n        assertFalse(isInterfaceType(type.asType()));\n\n        assertFalse(isInterfaceType((Element) null));\n        assertFalse(isInterfaceType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsAnnotationType() {\n        TypeElement type = getType(Override.class);\n\n        assertTrue(isAnnotationType(type));\n        assertTrue(isAnnotationType(type.asType()));\n\n        type = getType(Model.class);\n        assertFalse(isAnnotationType(type));\n        assertFalse(isAnnotationType(type.asType()));\n\n        assertFalse(isAnnotationType((Element) null));\n        assertFalse(isAnnotationType((TypeMirror) null));\n    }\n\n    @Test\n    void testGetHierarchicalTypes() {\n        Set hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, true, true);\n        Iterator iterator = hierarchicalTypes.iterator();\n        assertEquals(8, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.GenericTestService\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.DefaultTestService\",\n                iterator.next().toString());\n        assertEquals(\"java.lang.Object\", iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(8, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.GenericTestService\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.DefaultTestService\",\n                iterator.next().toString());\n        assertEquals(\"java.lang.Object\", iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), Object.class);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(7, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.GenericTestService\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.DefaultTestService\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, true, false);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(4, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.GenericTestService\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.DefaultTestService\",\n                iterator.next().toString());\n        assertEquals(\"java.lang.Object\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, false, true);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(5, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), false, false, true);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(4, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, false, false);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(1, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), false, false, false);\n        assertEquals(0, hierarchicalTypes.size());\n\n        assertTrue(getHierarchicalTypes((TypeElement) null).isEmpty());\n        assertTrue(getHierarchicalTypes((TypeMirror) null).isEmpty());\n    }\n\n    @Test\n    void testGetInterfaces() {\n        TypeElement type = getType(Model.class);\n        List<TypeMirror> interfaces = getInterfaces(type);\n        assertTrue(interfaces.isEmpty());\n\n        interfaces = getInterfaces(testType.asType());\n\n        assertEquals(3, interfaces.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", interfaces.get(0).toString());\n        assertEquals(\"java.lang.AutoCloseable\", interfaces.get(1).toString());\n        assertEquals(\"java.io.Serializable\", interfaces.get(2).toString());\n\n        assertTrue(getInterfaces((TypeElement) null).isEmpty());\n        assertTrue(getInterfaces((TypeMirror) null).isEmpty());\n    }\n\n    @Test\n    void testGetAllInterfaces() {\n        Set<? extends TypeMirror> interfaces = getAllInterfaces(testType.asType());\n        assertEquals(4, interfaces.size());\n        Iterator<? extends TypeMirror> iterator = interfaces.iterator();\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        Set<TypeElement> allInterfaces = getAllInterfaces(testType);\n        assertEquals(4, interfaces.size());\n\n        Iterator<TypeElement> allIterator = allInterfaces.iterator();\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\",\n                allIterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", allIterator.next().toString());\n        assertEquals(\"java.io.Serializable\", allIterator.next().toString());\n        assertEquals(\"java.util.EventListener\", allIterator.next().toString());\n\n        assertTrue(getAllInterfaces((TypeElement) null).isEmpty());\n        assertTrue(getAllInterfaces((TypeMirror) null).isEmpty());\n    }\n\n    @Test\n    void testGetType() {\n        TypeElement element = TypeUtils.getType(processingEnv, String.class);\n        assertEquals(element, TypeUtils.getType(processingEnv, element.asType()));\n        assertEquals(element, TypeUtils.getType(processingEnv, \"java.lang.String\"));\n\n        assertNull(TypeUtils.getType(processingEnv, (Type) null));\n        assertNull(TypeUtils.getType(processingEnv, (TypeMirror) null));\n        assertNull(TypeUtils.getType(processingEnv, (CharSequence) null));\n        assertNull(TypeUtils.getType(null, (CharSequence) null));\n    }\n\n    @Test\n    void testGetSuperType() {\n        TypeElement gtsTypeElement = getSuperType(testType);\n        assertEquals(gtsTypeElement, getType(GenericTestService.class));\n        TypeElement dtsTypeElement = getSuperType(gtsTypeElement);\n        assertEquals(dtsTypeElement, getType(DefaultTestService.class));\n\n        TypeMirror gtsType = getSuperType(testType.asType());\n        assertEquals(gtsType, getType(GenericTestService.class).asType());\n        TypeMirror dtsType = getSuperType(gtsType);\n        assertEquals(dtsType, getType(DefaultTestService.class).asType());\n\n        assertNull(getSuperType((TypeElement) null));\n        assertNull(getSuperType((TypeMirror) null));\n    }\n\n    @Test\n    void testGetAllSuperTypes() {\n        Set<?> allSuperTypes = getAllSuperTypes(testType);\n        Iterator<?> iterator = allSuperTypes.iterator();\n        assertEquals(3, allSuperTypes.size());\n        assertEquals(iterator.next(), getType(GenericTestService.class));\n        assertEquals(iterator.next(), getType(DefaultTestService.class));\n        assertEquals(iterator.next(), getType(Object.class));\n\n        allSuperTypes = getAllSuperTypes(testType);\n        iterator = allSuperTypes.iterator();\n        assertEquals(3, allSuperTypes.size());\n        assertEquals(iterator.next(), getType(GenericTestService.class));\n        assertEquals(iterator.next(), getType(DefaultTestService.class));\n        assertEquals(iterator.next(), getType(Object.class));\n\n        assertTrue(getAllSuperTypes((TypeElement) null).isEmpty());\n        assertTrue(getAllSuperTypes((TypeMirror) null).isEmpty());\n    }\n\n    @Test\n    void testIsDeclaredType() {\n        assertTrue(isDeclaredType(testType));\n        assertTrue(isDeclaredType(testType.asType()));\n        assertFalse(isDeclaredType((Element) null));\n        assertFalse(isDeclaredType((TypeMirror) null));\n        assertFalse(isDeclaredType(types.getNullType()));\n        assertFalse(isDeclaredType(types.getPrimitiveType(TypeKind.BYTE)));\n        assertFalse(isDeclaredType(types.getArrayType(types.getPrimitiveType(TypeKind.BYTE))));\n    }\n\n    @Test\n    void testOfDeclaredType() {\n        assertEquals(testType.asType(), ofDeclaredType(testType));\n        assertEquals(testType.asType(), ofDeclaredType(testType.asType()));\n        assertEquals(ofDeclaredType(testType), ofDeclaredType(testType.asType()));\n\n        assertNull(ofDeclaredType((Element) null));\n        assertNull(ofDeclaredType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsTypeElement() {\n        assertTrue(isTypeElement(testType));\n        assertTrue(isTypeElement(testType.asType()));\n\n        assertFalse(isTypeElement((Element) null));\n        assertFalse(isTypeElement((TypeMirror) null));\n    }\n\n    @Test\n    void testOfTypeElement() {\n        assertEquals(testType, ofTypeElement(testType));\n        assertEquals(testType, ofTypeElement(testType.asType()));\n\n        assertNull(ofTypeElement((Element) null));\n        assertNull(ofTypeElement((TypeMirror) null));\n    }\n\n    @Test\n    void testOfDeclaredTypes() {\n        Set<DeclaredType> declaredTypes =\n                ofDeclaredTypes(asList(getType(String.class), getType(TestServiceImpl.class), getType(Color.class)));\n        assertTrue(declaredTypes.contains(getType(String.class).asType()));\n        assertTrue(declaredTypes.contains(getType(TestServiceImpl.class).asType()));\n        assertTrue(declaredTypes.contains(getType(Color.class).asType()));\n\n        assertTrue(ofDeclaredTypes(null).isEmpty());\n    }\n\n    @Test\n    void testListDeclaredTypes() {\n        List<DeclaredType> types = listDeclaredTypes(asList(testType, testType, testType));\n        assertEquals(1, types.size());\n        assertEquals(ofDeclaredType(testType), types.get(0));\n\n        types = listDeclaredTypes(asList(new Element[] {null}));\n        assertTrue(types.isEmpty());\n    }\n\n    @Test\n    void testListTypeElements() {\n        List<TypeElement> typeElements = listTypeElements(asList(testType.asType(), ofDeclaredType(testType)));\n        assertEquals(1, typeElements.size());\n        assertEquals(testType, typeElements.get(0));\n\n        typeElements = listTypeElements(\n                asList(types.getPrimitiveType(TypeKind.BYTE), types.getNullType(), types.getNoType(TypeKind.NONE)));\n        assertTrue(typeElements.isEmpty());\n\n        typeElements = listTypeElements(asList(new TypeMirror[] {null}));\n        assertTrue(typeElements.isEmpty());\n\n        typeElements = listTypeElements(null);\n        assertTrue(typeElements.isEmpty());\n    }\n\n    @Test\n    @Disabled\n    public void testGetResource() throws URISyntaxException {\n        URL resource = getResource(processingEnv, testType);\n        assertNotNull(resource);\n        assertTrue(new File(resource.toURI()).exists());\n        assertEquals(resource, getResource(processingEnv, testType.asType()));\n        assertEquals(resource, getResource(processingEnv, \"org.apache.dubbo.metadata.tools.TestServiceImpl\"));\n\n        assertThrows(RuntimeException.class, () -> getResource(processingEnv, \"NotFound\"));\n    }\n\n    @Test\n    void testGetResourceName() {\n        assertEquals(\"java/lang/String.class\", getResourceName(\"java.lang.String\"));\n        assertNull(getResourceName(null));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/rest/DefaultRestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.rest;\n\nimport org.apache.dubbo.config.annotation.DubboService;\n\nimport java.util.Map;\n\n/**\n * The default implementation of {@link RestService}\n *\n * @since 2.7.6\n */\n@DubboService(version = \"1.0.0\", group = \"default\")\npublic class DefaultRestService implements RestService {\n\n    @Override\n    public String param(String param) {\n        return null;\n    }\n\n    @Override\n    public String params(int a, String b) {\n        return null;\n    }\n\n    @Override\n    public String headers(String header, String header2, Integer param) {\n        return null;\n    }\n\n    @Override\n    public String pathVariables(String path1, String path2, String param) {\n        return null;\n    }\n\n    @Override\n    public String form(String form) {\n        return null;\n    }\n\n    @Override\n    public User requestBodyMap(Map<String, Object> data, String param) {\n        return null;\n    }\n\n    @Override\n    public Map<String, Object> requestBodyUser(User user) {\n        return null;\n    }\n\n    public User user(User user) {\n        return user;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/rest/RestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.rest;\n\nimport java.util.Map;\n\n/**\n * An interface for REST service\n *\n * @since 2.7.6\n */\npublic interface RestService {\n\n    String param(String param);\n\n    String params(int a, String b);\n\n    String headers(String header, String header2, Integer param);\n\n    String pathVariables(String path1, String path2, String param);\n\n    String form(String form);\n\n    User requestBodyMap(Map<String, Object> data, String param);\n\n    Map<String, Object> requestBodyUser(User user);\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/rest/SpringRestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.rest;\n\nimport org.apache.dubbo.config.annotation.DubboService;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestHeader;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Spring MVC {@link RestService}\n *\n * @since 2.7.6\n */\n@DubboService(version = \"2.0.0\", group = \"spring\")\n@RestController\npublic class SpringRestService implements RestService {\n\n    @Override\n    @GetMapping(value = \"/param\")\n    public String param(@RequestParam(defaultValue = \"value-param\") String param) {\n        return null;\n    }\n\n    @Override\n    @PostMapping(\"/params\")\n    public String params(\n            @RequestParam(defaultValue = \"value-a\") int a, @RequestParam(defaultValue = \"value-b\") String b) {\n        return null;\n    }\n\n    @Override\n    @GetMapping(\"/headers\")\n    public String headers(\n            @RequestHeader(name = \"h\", defaultValue = \"value-h\") String header,\n            @RequestHeader(name = \"h2\", defaultValue = \"value-h2\") String header2,\n            @RequestParam(value = \"v\", defaultValue = \"1\") Integer param) {\n        return null;\n    }\n\n    @Override\n    @GetMapping(\"/path-variables/{p1}/{p2}\")\n    public String pathVariables(\n            @PathVariable(\"p1\") String path1, @PathVariable(\"p2\") String path2, @RequestParam(\"v\") String param) {\n        return null;\n    }\n\n    @Override\n    @PostMapping(\"/form\")\n    public String form(@RequestParam(\"f\") String form) {\n        return String.valueOf(form);\n    }\n\n    @Override\n    @PostMapping(value = \"/request/body/map\", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)\n    public User requestBodyMap(@RequestBody Map<String, Object> data, @RequestParam(\"param\") String param) {\n        User user = new User();\n        user.setId(((Integer) data.get(\"id\")).longValue());\n        user.setName((String) data.get(\"name\"));\n        user.setAge((Integer) data.get(\"age\"));\n        return user;\n    }\n\n    @PostMapping(value = \"/request/body/user\", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)\n    @Override\n    public Map<String, Object> requestBodyUser(@RequestBody User user) {\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\", user.getId());\n        map.put(\"name\", user.getName());\n        map.put(\"age\", user.getAge());\n        return map;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/rest/StandardRestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.rest;\n\nimport org.apache.dubbo.config.annotation.DubboService;\n\nimport javax.ws.rs.Consumes;\nimport javax.ws.rs.FormParam;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.HeaderParam;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.PathParam;\nimport javax.ws.rs.Produces;\nimport javax.ws.rs.QueryParam;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * JAX-RS {@link RestService}\n */\n@DubboService(\n        version = \"3.0.0\",\n        protocol = {\"dubbo\", \"rest\"},\n        group = \"standard\")\n@Path(\"/\")\npublic class StandardRestService implements RestService {\n\n    @Override\n    @Path(\"param\")\n    @GET\n    public String param(@QueryParam(\"param\") String param) {\n        return param;\n    }\n\n    @Override\n    @Path(\"params\")\n    @POST\n    public String params(@QueryParam(\"a\") int a, @QueryParam(\"b\") String b) {\n        return a + b;\n    }\n\n    @Override\n    @Path(\"headers\")\n    @GET\n    public String headers(\n            @HeaderParam(\"h\") String header, @HeaderParam(\"h2\") String header2, @QueryParam(\"v\") Integer param) {\n        String result = header + \" , \" + header2 + \" , \" + param;\n        return result;\n    }\n\n    @Override\n    @Path(\"path-variables/{p1}/{p2}\")\n    @GET\n    public String pathVariables(\n            @PathParam(\"p1\") String path1, @PathParam(\"p2\") String path2, @QueryParam(\"v\") String param) {\n        String result = path1 + \" , \" + path2 + \" , \" + param;\n        return result;\n    }\n\n    // @CookieParam does not support : https://github.com/OpenFeign/feign/issues/913\n    // @CookieValue also does not support\n\n    @Override\n    @Path(\"form\")\n    @POST\n    public String form(@FormParam(\"f\") String form) {\n        return String.valueOf(form);\n    }\n\n    @Override\n    @Path(\"request/body/map\")\n    @POST\n    @Produces(\"application/json;charset=UTF-8\")\n    public User requestBodyMap(Map<String, Object> data, @QueryParam(\"param\") String param) {\n        User user = new User();\n        user.setId(((Integer) data.get(\"id\")).longValue());\n        user.setName((String) data.get(\"name\"));\n        user.setAge((Integer) data.get(\"age\"));\n        return user;\n    }\n\n    @Path(\"request/body/user\")\n    @POST\n    @Override\n    @Consumes(\"application/json;charset=UTF-8\")\n    public Map<String, Object> requestBodyUser(User user) {\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\", user.getId());\n        map.put(\"name\", user.getName());\n        map.put(\"age\", user.getAge());\n        return map;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/rest/User.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.rest;\n\nimport java.io.Serializable;\n\n/**\n * User Entity\n *\n * @since 2.7.6\n */\npublic class User implements Serializable {\n\n    private Long id;\n\n    private String name;\n\n    private Integer age;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n\n    @Override\n    public String toString() {\n        return \"User{\" + \"id=\" + id + \", name='\" + name + '\\'' + \", age=\" + age + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/tools/Ancestor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport java.io.Serializable;\n\npublic class Ancestor implements Serializable {\n\n    private boolean z;\n\n    public boolean isZ() {\n        return z;\n    }\n\n    public void setZ(boolean z) {\n        this.z = z;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/tools/Compiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport javax.annotation.processing.Processor;\nimport javax.tools.JavaCompiler;\nimport javax.tools.JavaFileObject;\nimport javax.tools.StandardJavaFileManager;\nimport javax.tools.StandardLocation;\nimport javax.tools.ToolProvider;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport static java.util.Arrays.asList;\n\n/**\n * The Java Compiler\n */\npublic class Compiler {\n\n    private final File sourceDirectory;\n\n    private final JavaCompiler javaCompiler;\n\n    private final StandardJavaFileManager javaFileManager;\n\n    private final Set<Processor> processors = new LinkedHashSet<>();\n\n    public Compiler() throws IOException {\n        this(defaultTargetDirectory());\n    }\n\n    public Compiler(File targetDirectory) throws IOException {\n        this(defaultSourceDirectory(), targetDirectory);\n    }\n\n    public Compiler(File sourceDirectory, File targetDirectory) throws IOException {\n        this.sourceDirectory = sourceDirectory;\n        this.javaCompiler = ToolProvider.getSystemJavaCompiler();\n        this.javaFileManager = javaCompiler.getStandardFileManager(null, null, null);\n        this.javaFileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(targetDirectory));\n        this.javaFileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(targetDirectory));\n    }\n\n    private static File defaultSourceDirectory() {\n        return new File(defaultRootDirectory(), \"src/test/java\");\n    }\n\n    private static File defaultRootDirectory() {\n        return detectClassPath(Compiler.class).getParentFile().getParentFile();\n    }\n\n    private static File defaultTargetDirectory() {\n        File dir = new File(defaultRootDirectory(), \"target/generated-classes\");\n        dir.mkdirs();\n        return dir;\n    }\n\n    private static File detectClassPath(Class<?> targetClass) {\n        URL classFileURL = targetClass.getProtectionDomain().getCodeSource().getLocation();\n        if (\"file\".equals(classFileURL.getProtocol())) {\n            return new File(classFileURL.getPath());\n        } else {\n            throw new RuntimeException(\"No support\");\n        }\n    }\n\n    public Compiler processors(Processor... processors) {\n        this.processors.addAll(asList(processors));\n        return this;\n    }\n\n    private Iterable<? extends JavaFileObject> getJavaFileObjects(Class<?>... sourceClasses) {\n        int size = sourceClasses == null ? 0 : sourceClasses.length;\n        File[] javaSourceFiles = new File[size];\n        for (int i = 0; i < size; i++) {\n            File javaSourceFile = javaSourceFile(sourceClasses[i].getName());\n            javaSourceFiles[i] = javaSourceFile;\n        }\n        return javaFileManager.getJavaFileObjects(javaSourceFiles);\n    }\n\n    private File javaSourceFile(String sourceClassName) {\n        String javaSourceFilePath = sourceClassName.replace('.', '/').concat(\".java\");\n        return new File(sourceDirectory, javaSourceFilePath);\n    }\n\n    public boolean compile(Class<?>... sourceClasses) {\n        JavaCompiler.CompilationTask task = javaCompiler.getTask(\n                null,\n                this.javaFileManager,\n                null,\n                asList(\"-parameters\", \"-Xlint:unchecked\", \"-nowarn\", \"-Xlint:deprecation\"),\n                //                null,\n                null,\n                getJavaFileObjects(sourceClasses));\n        if (!processors.isEmpty()) {\n            task.setProcessors(processors);\n        }\n        return task.call();\n    }\n\n    public JavaCompiler getJavaCompiler() {\n        return javaCompiler;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/tools/CompilerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\n/**\n * The Compiler test case\n */\nclass CompilerTest {\n\n    @Test\n    void testCompile() throws IOException {\n        Compiler compiler = new Compiler();\n        compiler.compile(TestServiceImpl.class, DefaultTestService.class, GenericTestService.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/tools/DefaultTestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * {@link TestService} Implementation\n *\n * @since 2.7.6\n */\n@Service(interfaceName = \"org.apache.dubbo.metadata.tools.TestService\", version = \"1.0.0\", group = \"default\")\npublic class DefaultTestService implements TestService {\n\n    private String name;\n\n    @Override\n    public String echo(String message) {\n        return \"[ECHO] \" + message;\n    }\n\n    @Override\n    public Model model(Model model) {\n        return model;\n    }\n\n    @Override\n    public String testPrimitive(boolean z, int i) {\n        return null;\n    }\n\n    @Override\n    public Model testEnum(TimeUnit timeUnit) {\n        return null;\n    }\n\n    @Override\n    public String testArray(String[] strArray, int[] intArray, Model[] modelArray) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/tools/GenericTestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport java.util.EventListener;\n\nimport com.alibaba.dubbo.config.annotation.Service;\n\n/**\n * {@link TestService} Implementation\n *\n * @since 2.7.6\n */\n@Service(version = \"2.0.0\", group = \"generic\")\npublic class GenericTestService extends DefaultTestService implements TestService, EventListener {\n    @Override\n    public String echo(String message) {\n        return \"[ECHO] \" + message;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/tools/Parent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\npublic class Parent extends Ancestor {\n\n    private byte b;\n\n    private short s;\n\n    private int i;\n\n    private long l;\n\n    public byte getB() {\n        return b;\n    }\n\n    public void setB(byte b) {\n        this.b = b;\n    }\n\n    public short getS() {\n        return s;\n    }\n\n    public void setS(short s) {\n        this.s = s;\n    }\n\n    public int getI() {\n        return i;\n    }\n\n    public void setI(int i) {\n        this.i = i;\n    }\n\n    public long getL() {\n        return l;\n    }\n\n    public void setL(long l) {\n        this.l = l;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/tools/TestProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.Processor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.TypeElement;\n\nimport java.util.Set;\n\nimport static javax.lang.model.SourceVersion.latestSupported;\n\n/**\n * {@link Processor} for test\n *\n * @since 2.7.6\n */\n@SupportedAnnotationTypes(\"*\")\npublic class TestProcessor extends AbstractProcessor {\n\n    @Override\n    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n        return false;\n    }\n\n    public ProcessingEnvironment getProcessingEnvironment() {\n        return super.processingEnv;\n    }\n\n    public SourceVersion getSupportedSourceVersion() {\n        return latestSupported();\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/tools/TestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\n\nimport javax.ws.rs.DefaultValue;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.PUT;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.PathParam;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Test Service\n *\n * @since 2.7.6\n */\n@Path(\"/echo\")\npublic interface TestService {\n\n    @GET\n    <T> String echo(@PathParam(\"message\") @DefaultValue(\"mercyblitz\") String message);\n\n    @POST\n    Model model(@PathParam(\"model\") Model model);\n\n    // Test primitive\n    @PUT\n    String testPrimitive(boolean z, int i);\n\n    // Test enumeration\n    @PUT\n    Model testEnum(TimeUnit timeUnit);\n\n    // Test Array\n    @GET\n    String testArray(String[] strArray, int[] intArray, Model[] modelArray);\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/metadata/tools/TestServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport org.apache.dubbo.config.annotation.Service;\n\nimport java.io.Serializable;\n\n/**\n * {@link TestService} Implementation\n *\n * @since 2.7.6\n */\n@com.alibaba.dubbo.config.annotation.Service(\n        interfaceName = \"org.apache.dubbo.metadata.tools.TestService\",\n        interfaceClass = TestService.class,\n        version = \"3.0.0\",\n        group = \"test\")\n@Service(\n        interfaceName = \"org.apache.dubbo.metadata.tools.TestService\",\n        interfaceClass = TestService.class,\n        version = \"3.0.0\",\n        group = \"test\")\npublic class TestServiceImpl extends GenericTestService implements TestService, AutoCloseable, Serializable {\n\n    @Override\n    public String echo(String message) {\n        return \"[ECHO] \" + message;\n    }\n\n    @Override\n    public void close() throws Exception {}\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.Future;\n\nimport com.alibaba.dubbo.rpc.RpcContext;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass RpcContextTest {\n    private static final Logger logger = LoggerFactory.getLogger(RpcContextTest.class);\n\n    @Test\n    void testSetFuture() {\n        CompletableFuture completableFuture = new CompletableFuture();\n        RpcContext.getContext().setFuture(completableFuture);\n\n        CompletableFuture result = FutureContext.getContext().getCompatibleCompletableFuture();\n        assertEquals(result, completableFuture);\n    }\n\n    @Test\n    void testSetFutureAlibaba() {\n        CompletableFuture completableFuture = new CompletableFuture();\n        RpcContext.getContext().setFuture(completableFuture);\n\n        Future future = RpcContext.getContext().getFuture();\n\n        logger.info(String.valueOf(future));\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/CompatibleRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport java.util.List;\n\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.rpc.Invocation;\nimport com.alibaba.dubbo.rpc.Invoker;\nimport com.alibaba.dubbo.rpc.RpcException;\nimport com.alibaba.dubbo.rpc.cluster.Router;\n\npublic class CompatibleRouter implements Router {\n\n    @Override\n    public URL getUrl() {\n        return null;\n    }\n\n    @Override\n    public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {\n        return null;\n    }\n\n    @Override\n    public int compareTo(Router o) {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/CompatibleRouter2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport java.util.List;\n\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.rpc.Invocation;\nimport com.alibaba.dubbo.rpc.Invoker;\nimport com.alibaba.dubbo.rpc.RpcException;\nimport com.alibaba.dubbo.rpc.cluster.Router;\n\npublic class CompatibleRouter2 implements Router {\n    @Override\n    public URL getUrl() {\n        return null;\n    }\n\n    @Override\n    public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {\n        return null;\n    }\n\n    @Override\n    public int compareTo(Router o) {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/NewRouter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport java.util.List;\n\npublic class NewRouter implements Router {\n    @Override\n    public URL getUrl() {\n        return null;\n    }\n\n    @Override\n    public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {\n        return null;\n    }\n\n    @Override\n    public boolean isRuntime() {\n        return false;\n    }\n\n    @Override\n    public boolean isForce() {\n        return false;\n    }\n\n    @Override\n    public int getPriority() {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/RouterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nclass RouterTest {\n\n    private static List<Router> routers = new ArrayList<>();\n\n    @BeforeAll\n    public static void setUp() {\n        CompatibleRouter compatibleRouter = new CompatibleRouter();\n        routers.add(compatibleRouter);\n        CompatibleRouter2 compatibleRouter2 = new CompatibleRouter2();\n        routers.add(compatibleRouter2);\n        NewRouter newRouter = new NewRouter();\n        routers.add(newRouter);\n    }\n\n    @Test\n    void testCompareTo() {\n        try {\n            Collections.sort(routers);\n            Assertions.assertTrue(true);\n        } catch (Exception e) {\n            Assertions.assertFalse(false);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/rpc/filter/GenericImplFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.filter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.compact.Dubbo2GenericExceptionUtils;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.support.DemoService;\nimport org.apache.dubbo.rpc.support.Person;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.mockito.Mockito.any;\nimport static org.mockito.Mockito.when;\n\nclass GenericImplFilterTest {\n\n    private GenericImplFilter genericImplFilter =\n            new GenericImplFilter(ApplicationModel.defaultModel().getDefaultModule());\n\n    @Test\n    void testInvokeWithException() throws Exception {\n\n        RpcInvocation invocation = new RpcInvocation(\n                \"getPerson\",\n                \"org.apache.dubbo.rpc.support.DemoService\",\n                \"org.apache.dubbo.rpc.support.DemoService:dubbo\",\n                new Class[] {Person.class},\n                new Object[] {new Person(\"dubbo\", 10)});\n\n        URL url = URL.valueOf(\"test://test:11/org.apache.dubbo.rpc.support.DemoService?\"\n                + \"accesslog=true&group=dubbo&version=1.1&generic=true\");\n        Invoker invoker = Mockito.mock(Invoker.class);\n\n        AppResponse mockRpcResult =\n                new AppResponse(Dubbo2GenericExceptionUtils.newGenericException(new RuntimeException(\"failed\")));\n        when(invoker.invoke(any(Invocation.class)))\n                .thenReturn(AsyncRpcResult.newDefaultAsyncResult(mockRpcResult, invocation));\n        when(invoker.getUrl()).thenReturn(url);\n        when(invoker.getInterface()).thenReturn(DemoService.class);\n\n        Result asyncResult = genericImplFilter.invoke(invoker, invocation);\n        Result result = asyncResult.get();\n        genericImplFilter.onResponse(result, invoker, invocation);\n        Assertions.assertEquals(RuntimeException.class, result.getException().getClass());\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/rpc/support/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\n\npublic interface DemoService {\n    void sayHello(String name);\n\n    String echo(String text);\n\n    long timestamp();\n\n    String getThreadName();\n\n    int getSize(String[] strs);\n\n    int getSize(Object[] os);\n\n    Object invoke(String service, String method) throws Exception;\n\n    int stringLength(String str);\n\n    Type enumlength(Type... types);\n\n    //    Type enumlength(Type type);\n\n    //    String get(CustomArgument arg1);\n\n    byte getbyte(byte arg);\n\n    Person getPerson(Person person);\n\n    String testReturnType(String str);\n\n    List<String> testReturnType1(String str);\n\n    CompletableFuture<String> testReturnType2(String str);\n\n    CompletableFuture<List<String>> testReturnType3(String str);\n\n    CompletableFuture testReturnType4(String str);\n\n    CompletableFuture<Map<String, String>> testReturnType5(String str);\n\n    void $invoke(String s1, String s2);\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/rpc/support/Person.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\nimport java.io.Serializable;\n\n/**\n * Person.java\n */\npublic class Person implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n    private String name;\n    private int age;\n\n    public Person() {}\n\n    public Person(String name, int age) {\n        this.name = name;\n        this.age = age;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/rpc/support/Type.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.support;\n\npublic enum Type {\n    High,\n    Normal,\n    Lower\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/serialization/MyObjectInput.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.serialization;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.lang.reflect.Type;\n\nimport com.alibaba.dubbo.common.serialize.ObjectInput;\n\npublic class MyObjectInput implements ObjectInput {\n\n    private final BufferedReader reader;\n\n    public MyObjectInput(InputStream inputStream) {\n        this.reader = new BufferedReader(new InputStreamReader(inputStream));\n    }\n\n    @Override\n    public Object readObject() throws IOException, ClassNotFoundException {\n        return null;\n    }\n\n    @Override\n    public <T> T readObject(Class<T> cls) throws IOException, ClassNotFoundException {\n        return null;\n    }\n\n    @Override\n    public <T> T readObject(Class<T> cls, Type type) throws IOException, ClassNotFoundException {\n        return null;\n    }\n\n    @Override\n    public boolean readBool() throws IOException {\n        return false;\n    }\n\n    @Override\n    public byte readByte() throws IOException {\n        return 0;\n    }\n\n    @Override\n    public short readShort() throws IOException {\n        return 0;\n    }\n\n    @Override\n    public int readInt() throws IOException {\n        return 0;\n    }\n\n    @Override\n    public long readLong() throws IOException {\n        return 0;\n    }\n\n    @Override\n    public float readFloat() throws IOException {\n        return 0;\n    }\n\n    @Override\n    public double readDouble() throws IOException {\n        return 0;\n    }\n\n    @Override\n    public String readUTF() throws IOException {\n        return reader.readLine();\n    }\n\n    @Override\n    public byte[] readBytes() throws IOException {\n        return new byte[0];\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/serialization/MyObjectOutput.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.serialization;\n\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\n\nimport com.alibaba.dubbo.common.serialize.ObjectOutput;\n\npublic class MyObjectOutput implements ObjectOutput {\n\n    private final BufferedWriter writer;\n\n    public MyObjectOutput(OutputStream outputStream) {\n        writer = new BufferedWriter(new OutputStreamWriter(outputStream));\n    }\n\n    @Override\n    public void writeObject(Object obj) throws IOException {}\n\n    @Override\n    public void writeBool(boolean v) throws IOException {}\n\n    @Override\n    public void writeByte(byte v) throws IOException {}\n\n    @Override\n    public void writeShort(short v) throws IOException {}\n\n    @Override\n    public void writeInt(int v) throws IOException {}\n\n    @Override\n    public void writeLong(long v) throws IOException {}\n\n    @Override\n    public void writeFloat(float v) throws IOException {}\n\n    @Override\n    public void writeDouble(double v) throws IOException {}\n\n    @Override\n    public void writeUTF(String v) throws IOException {\n        writer.write(v);\n        writer.write('\\n');\n    }\n\n    @Override\n    public void writeBytes(byte[] v) throws IOException {}\n\n    @Override\n    public void writeBytes(byte[] v, int off, int len) throws IOException {}\n\n    @Override\n    public void flushBuffer() throws IOException {\n        writer.flush();\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/serialization/MySerialization.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.serialization;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport com.alibaba.dubbo.common.URL;\nimport com.alibaba.dubbo.common.serialize.ObjectInput;\nimport com.alibaba.dubbo.common.serialize.ObjectOutput;\nimport com.alibaba.dubbo.common.serialize.Serialization;\n\npublic class MySerialization implements Serialization {\n\n    @Override\n    public ObjectOutput serialize(URL url, OutputStream output) throws IOException {\n        return new MyObjectOutput(output);\n    }\n\n    @Override\n    public ObjectInput deserialize(URL url, InputStream input) throws IOException {\n        return new MyObjectInput(input);\n    }\n\n    @Override\n    public byte getContentTypeId() {\n        return 101;\n    }\n\n    @Override\n    public String getContentType() {\n        return \"x-application/my\";\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/serialization/SerializationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.serialization;\n\nimport org.apache.dubbo.common.serialize.ObjectInput;\nimport org.apache.dubbo.common.serialize.ObjectOutput;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.hamcrest.CoreMatchers;\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\nimport static org.mockito.Mockito.mock;\n\nclass SerializationTest {\n\n    private MySerialization mySerialization;\n\n    private MyObjectOutput myObjectOutput;\n    private MyObjectInput myObjectInput;\n    private ByteArrayOutputStream byteArrayOutputStream;\n    private ByteArrayInputStream byteArrayInputStream;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        this.mySerialization = new MySerialization();\n\n        this.byteArrayOutputStream = new ByteArrayOutputStream();\n        this.myObjectOutput = new MyObjectOutput(byteArrayOutputStream);\n    }\n\n    @Test\n    void testContentType() {\n        assertThat(mySerialization.getContentType(), is(\"x-application/my\"));\n    }\n\n    @Test\n    void testContentTypeId() {\n        assertThat(mySerialization.getContentTypeId(), is((byte) 101));\n    }\n\n    @Test\n    void testObjectOutput() throws IOException {\n        ObjectOutput objectOutput = mySerialization.serialize(null, mock(OutputStream.class));\n        assertThat(objectOutput, Matchers.<ObjectOutput>instanceOf(MyObjectOutput.class));\n    }\n\n    @Test\n    void testObjectInput() throws IOException {\n        ObjectInput objectInput = mySerialization.deserialize(null, mock(InputStream.class));\n        assertThat(objectInput, Matchers.<ObjectInput>instanceOf(MyObjectInput.class));\n    }\n\n    @Test\n    @DisabledOnOs(OS.WINDOWS) // Charset maynot UTF-8 on Windows JDK 8 ~ 17\n    void testWriteUTF() throws IOException {\n        myObjectOutput.writeUTF(\"Pace\");\n        myObjectOutput.writeUTF(\"和平\");\n        myObjectOutput.writeUTF(\" Мир\");\n        flushToInput();\n\n        assertThat(myObjectInput.readUTF(), CoreMatchers.is(\"Pace\"));\n        assertThat(myObjectInput.readUTF(), CoreMatchers.is(\"和平\"));\n        assertThat(myObjectInput.readUTF(), CoreMatchers.is(\" Мир\"));\n    }\n\n    private void flushToInput() throws IOException {\n        this.myObjectOutput.flushBuffer();\n        this.byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());\n        this.myObjectInput = new MyObjectInput(byteArrayInputStream);\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/service/ComplexObject.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.service;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\n/**\n * ON 2018/11/5\n */\npublic class ComplexObject {\n\n    public ComplexObject() {}\n\n    public ComplexObject(\n            String var1, int var2, long l, String[] var3, List<Integer> var4, ComplexObject.TestEnum testEnum) {\n        this.setInnerObject(new ComplexObject.InnerObject());\n        this.getInnerObject().setInnerA(var1);\n        this.getInnerObject().setInnerB(var2);\n        this.setIntList(var4);\n        this.setStrArrays(var3);\n        this.setTestEnum(testEnum);\n        this.setV(l);\n        InnerObject2 io21 = new InnerObject2();\n        io21.setInnerA2(var1 + \"_21\");\n        io21.setInnerB2(var2 + 100000);\n        InnerObject2 io22 = new InnerObject2();\n        io22.setInnerA2(var1 + \"_22\");\n        io22.setInnerB2(var2 + 200000);\n        this.setInnerObject2(new ArrayList<>(Arrays.asList(io21, io22)));\n\n        InnerObject3 io31 = new InnerObject3();\n        io31.setInnerA3(var1 + \"_31\");\n        InnerObject3 io32 = new InnerObject3();\n        io32.setInnerA3(var1 + \"_32\");\n        InnerObject3 io33 = new InnerObject3();\n        io33.setInnerA3(var1 + \"_33\");\n        this.setInnerObject3(new InnerObject3[] {io31, io32, io33});\n        this.maps = new HashMap<>(4);\n        this.maps.put(var1 + \"_k1\", var1 + \"_v1\");\n        this.maps.put(var1 + \"_k2\", var1 + \"_v2\");\n    }\n\n    private InnerObject innerObject;\n    private List<InnerObject2> innerObject2;\n    private InnerObject3[] innerObject3;\n    private String[] strArrays;\n    private List<Integer> intList;\n    private long v;\n    private TestEnum testEnum;\n    private Map<String, String> maps;\n\n    public InnerObject getInnerObject() {\n        return innerObject;\n    }\n\n    public void setInnerObject(InnerObject innerObject) {\n        this.innerObject = innerObject;\n    }\n\n    public String[] getStrArrays() {\n        return strArrays;\n    }\n\n    public void setStrArrays(String[] strArrays) {\n        this.strArrays = strArrays;\n    }\n\n    public List<Integer> getIntList() {\n        return intList;\n    }\n\n    public void setIntList(List<Integer> intList) {\n        this.intList = intList;\n    }\n\n    public long getV() {\n        return v;\n    }\n\n    public void setV(long v) {\n        this.v = v;\n    }\n\n    public TestEnum getTestEnum() {\n        return testEnum;\n    }\n\n    public void setTestEnum(TestEnum testEnum) {\n        this.testEnum = testEnum;\n    }\n\n    public List<InnerObject2> getInnerObject2() {\n        return innerObject2;\n    }\n\n    public void setInnerObject2(List<InnerObject2> innerObject2) {\n        this.innerObject2 = innerObject2;\n    }\n\n    public InnerObject3[] getInnerObject3() {\n        return innerObject3;\n    }\n\n    public void setInnerObject3(InnerObject3[] innerObject3) {\n        this.innerObject3 = innerObject3;\n    }\n\n    public Map<String, String> getMaps() {\n        return maps;\n    }\n\n    public void setMaps(Map<String, String> maps) {\n        this.maps = maps;\n    }\n\n    @Override\n    public String toString() {\n        return \"ComplexObject{\" + \"innerObject=\"\n                + innerObject + \", innerObject2=\"\n                + innerObject2 + \", innerObject3=\"\n                + Arrays.toString(innerObject3) + \", strArrays=\"\n                + Arrays.toString(strArrays) + \", intList=\"\n                + intList + \", v=\"\n                + v + \", testEnum=\"\n                + testEnum + \", maps=\"\n                + maps + '}';\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof ComplexObject)) return false;\n        ComplexObject that = (ComplexObject) o;\n        return getV() == that.getV()\n                && Objects.equals(getInnerObject(), that.getInnerObject())\n                && Objects.equals(getInnerObject2(), that.getInnerObject2())\n                && Arrays.equals(getInnerObject3(), that.getInnerObject3())\n                && Arrays.equals(getStrArrays(), that.getStrArrays())\n                && Objects.equals(getIntList(), that.getIntList())\n                && getTestEnum() == that.getTestEnum()\n                && Objects.equals(getMaps(), that.getMaps());\n    }\n\n    @Override\n    public int hashCode() {\n        int result = Objects.hash(getInnerObject(), getInnerObject2(), getIntList(), getV(), getTestEnum(), getMaps());\n        result = 31 * result + Arrays.hashCode(getInnerObject3());\n        result = 31 * result + Arrays.hashCode(getStrArrays());\n        return result;\n    }\n\n    public enum TestEnum {\n        VALUE1,\n        VALUE2\n    }\n\n    public static class InnerObject {\n        String innerA;\n        int innerB;\n\n        public String getInnerA() {\n            return innerA;\n        }\n\n        public void setInnerA(String innerA) {\n            this.innerA = innerA;\n        }\n\n        public int getInnerB() {\n            return innerB;\n        }\n\n        public void setInnerB(int innerB) {\n            this.innerB = innerB;\n        }\n\n        @Override\n        public String toString() {\n            return \"InnerObject{\" + \"innerA='\" + innerA + '\\'' + \", innerB=\" + innerB + '}';\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof InnerObject)) return false;\n            InnerObject that = (InnerObject) o;\n            return getInnerB() == that.getInnerB() && Objects.equals(getInnerA(), that.getInnerA());\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(getInnerA(), getInnerB());\n        }\n    }\n\n    public static class InnerObject2 {\n        String innerA2;\n        int innerB2;\n\n        public String getInnerA2() {\n            return innerA2;\n        }\n\n        public void setInnerA2(String innerA2) {\n            this.innerA2 = innerA2;\n        }\n\n        public int getInnerB2() {\n            return innerB2;\n        }\n\n        public void setInnerB2(int innerB2) {\n            this.innerB2 = innerB2;\n        }\n\n        @Override\n        public String toString() {\n            return \"InnerObject{\" + \"innerA='\" + innerA2 + '\\'' + \", innerB=\" + innerB2 + '}';\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof InnerObject2)) return false;\n            InnerObject2 that = (InnerObject2) o;\n            return getInnerB2() == that.getInnerB2() && Objects.equals(getInnerA2(), that.getInnerA2());\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(getInnerA2(), getInnerB2());\n        }\n    }\n\n    public static class InnerObject3 {\n        String innerA3;\n\n        public String getInnerA3() {\n            return innerA3;\n        }\n\n        public void setInnerA3(String innerA3) {\n            this.innerA3 = innerA3;\n        }\n\n        @Override\n        public String toString() {\n            return \"InnerObject3{\" + \"innerA3='\" + innerA3 + '\\'' + '}';\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof InnerObject3)) return false;\n            InnerObject3 that = (InnerObject3) o;\n            return Objects.equals(getInnerA3(), that.getInnerA3());\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(getInnerA3());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/service/CustomArgument.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.service;\n\nimport java.io.Serializable;\n\n@SuppressWarnings(\"serial\")\npublic class CustomArgument implements Serializable {\n\n    Type type;\n    String name;\n\n    public CustomArgument() {}\n\n    public CustomArgument(Type type, String name) {\n        super();\n        this.type = type;\n        this.name = name;\n    }\n\n    public Type getType() {\n        return type;\n    }\n\n    public void setType(Type type) {\n        this.type = type;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/service/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.service;\n\nimport java.util.List;\n\npublic interface DemoService {\n    String sayHello(String name);\n\n    long timestamp();\n\n    String getThreadName();\n\n    int getSize(String[] strs);\n\n    int getSize(Object[] os);\n\n    Object invoke(String service, String method) throws Exception;\n\n    int stringLength(String str);\n\n    Type enumlength(Type... types);\n\n    //  Type enumlength(Type type);\n\n    String get(CustomArgument arg1);\n\n    byte getbyte(byte arg);\n\n    String complexCompute(String input, ComplexObject co);\n\n    ComplexObject findComplexObject(\n            String var1, int var2, long l, String[] var3, List<Integer> var4, ComplexObject.TestEnum testEnum);\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/service/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.service;\n\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport java.util.List;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class DemoServiceImpl implements DemoService {\n    private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);\n\n    public DemoServiceImpl() {\n        super();\n    }\n\n    public String sayHello(String name) {\n        return \"hello \" + name;\n    }\n\n    public long timestamp() {\n        return System.currentTimeMillis();\n    }\n\n    public String getThreadName() {\n        return Thread.currentThread().getName();\n    }\n\n    public int getSize(String[] strs) {\n        if (strs == null) return -1;\n        return strs.length;\n    }\n\n    public int getSize(Object[] os) {\n        if (os == null) return -1;\n        return os.length;\n    }\n\n    public Object invoke(String service, String method) throws Exception {\n        logger.info(\n                \"RpcContext.getServerAttachment().getRemoteHost()={}\",\n                RpcContext.getServiceContext().getRemoteHost());\n        return service + \":\" + method;\n    }\n\n    public Type enumlength(Type... types) {\n        if (types.length == 0) return Type.Lower;\n        return types[0];\n    }\n\n    public Type enumlength(Type type) {\n        return type;\n    }\n\n    public int stringLength(String str) {\n        return str.length();\n    }\n\n    public String get(CustomArgument arg1) {\n        return arg1.toString();\n    }\n\n    public byte getbyte(byte arg) {\n        return arg;\n    }\n\n    @Override\n    public String complexCompute(String input, ComplexObject co) {\n        return input + \"###\" + co.toString();\n    }\n\n    @Override\n    public ComplexObject findComplexObject(\n            String var1, int var2, long l, String[] var3, List<Integer> var4, ComplexObject.TestEnum testEnum) {\n\n        return new ComplexObject(var1, var2, l, var3, var4, testEnum);\n    }\n\n    public Person gerPerson(Person person) {\n        return person;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/service/MockInvocation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.service;\n\nimport org.apache.dubbo.rpc.AttachmentsAdapter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.rpc.Constants.TOKEN_KEY;\n\n/**\n * MockInvocation.java\n */\npublic class MockInvocation implements Invocation {\n\n    private String arg0;\n\n    private Map<String, Object> attachments;\n\n    public MockInvocation(String arg0) {\n        this.arg0 = arg0;\n\n        attachments = new HashMap<>();\n        attachments.put(PATH_KEY, \"dubbo\");\n        attachments.put(GROUP_KEY, \"dubbo\");\n        attachments.put(VERSION_KEY, \"1.0.0\");\n        attachments.put(DUBBO_VERSION_KEY, \"1.0.0\");\n        attachments.put(TOKEN_KEY, \"sfag\");\n        attachments.put(TIMEOUT_KEY, \"1000\");\n    }\n\n    @Override\n    public String getTargetServiceUniqueName() {\n        return null;\n    }\n\n    @Override\n    public String getProtocolServiceKey() {\n        return null;\n    }\n\n    public String getMethodName() {\n        return \"echo\";\n    }\n\n    @Override\n    public String getServiceName() {\n        return \"DemoService\";\n    }\n\n    public Class<?>[] getParameterTypes() {\n        return new Class[] {String.class};\n    }\n\n    public Object[] getArguments() {\n        return new Object[] {arg0};\n    }\n\n    public Map<String, String> getAttachments() {\n        return new AttachmentsAdapter.ObjectToStringMap(attachments);\n    }\n\n    @Override\n    public Map<String, Object> getObjectAttachments() {\n        return attachments;\n    }\n\n    @Override\n    public Map<String, Object> copyObjectAttachments() {\n        return new HashMap<>(attachments);\n    }\n\n    @Override\n    public void foreachAttachment(Consumer<Map.Entry<String, Object>> consumer) {\n        attachments.entrySet().forEach(consumer);\n    }\n\n    @Override\n    public void setAttachment(String key, String value) {\n        setObjectAttachment(key, value);\n    }\n\n    @Override\n    public void setAttachment(String key, Object value) {\n        setObjectAttachment(key, value);\n    }\n\n    @Override\n    public void setObjectAttachment(String key, Object value) {\n        attachments.put(key, value);\n    }\n\n    @Override\n    public void setAttachmentIfAbsent(String key, String value) {\n        setObjectAttachmentIfAbsent(key, value);\n    }\n\n    @Override\n    public void setAttachmentIfAbsent(String key, Object value) {\n        setObjectAttachmentIfAbsent(key, value);\n    }\n\n    @Override\n    public void setObjectAttachmentIfAbsent(String key, Object value) {\n        attachments.put(key, value);\n    }\n\n    public Invoker<?> getInvoker() {\n        return null;\n    }\n\n    @Override\n    public Object put(Object key, Object value) {\n        return null;\n    }\n\n    @Override\n    public Object get(Object key) {\n        return null;\n    }\n\n    @Override\n    public void setServiceModel(ServiceModel serviceModel) {}\n\n    @Override\n    public ServiceModel getServiceModel() {\n        return null;\n    }\n\n    @Override\n    public Map<Object, Object> getAttributes() {\n        return null;\n    }\n\n    public String getAttachment(String key) {\n        return (String) getObjectAttachments().get(key);\n    }\n\n    @Override\n    public Object getObjectAttachment(String key) {\n        return attachments.get(key);\n    }\n\n    public String getAttachment(String key, String defaultValue) {\n        return (String) getObjectAttachments().get(key);\n    }\n\n    @Override\n    public Object getObjectAttachment(String key, Object defaultValue) {\n        Object result = attachments.get(key);\n        if (result == null) {\n            return defaultValue;\n        }\n        return result;\n    }\n\n    @Override\n    public void addInvokedInvoker(Invoker<?> invoker) {}\n\n    @Override\n    public List<Invoker<?>> getInvokedInvokers() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/service/Person.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.service;\n\nimport java.io.Serializable;\n\n/**\n * Person.java\n */\npublic class Person implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n    private String name;\n    private int age;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/java/org/apache/dubbo/service/Type.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.service;\n\npublic enum Type {\n    High,\n    Normal,\n    Lower\n}\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/config.properties",
    "content": "application.prefix = dubbo.application.\napplication.prefixes = dubbo.applications.\n# single bean definition\n\n## application\ndubbo.application.id = applicationBean\ndubbo.application.name = dubbo-demo-application\n\n## module\ndubbo.module.id = moduleBean\ndubbo.module.name = dubbo-demo-module\n\n## registry\ndubbo.registry.address = zookeeper://192.168.99.100:32770\ndubbo.registry.useAsConfigCenter = false\ndubbo.registry.useAsMetadataCenter = false\n\n## protocol\ndubbo.protocol.name = dubbo\ndubbo.protocol.port = 20880\n\ndubbo.protocols.rest.port=8080\n\n## monitor\ndubbo.monitor.address = zookeeper://127.0.0.1:32770\n\n## provider\ndubbo.provider.host = 127.0.0.1\n\n## consumer\ndubbo.consumer.client = netty\n\n# multiple Bean definition\ndubbo.registries.registry1.address = zookeeper://localhost:2181\ndubbo.registries.registry2.address = zookeeper://localhost:2182\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/default.properties",
    "content": "demo.service.version = 2.5.7\ndemo.service.application = dubbo-demo-application\ndemo.service.protocol = dubbo\ndemo.service.registry = my-registry\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/dubbb-consumer.properties",
    "content": "# Dubbo Consumer Properties as an alternative for\n# Spring XML Bean definition : META-INF/spring/dubbo-annotation-consumer.xml\ndemo.service.application = dubbo-demo-application\ndemo.service.registry = my-registry\n\n## Dubbo configs binding properties\n###  <dubbo:application name=\"dubbo-demo-application\"/>\ndubbo.applications.dubbo-demo-application.name = dubbo-demo-application\n\n### <dubbo:registry id=\"my-registry\" address=\"N/A\"/>\ndubbo.registries.my-registry.address = N/A\ndubbo.registries.my-registry2.address = N/A\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/dubbb-provider.properties",
    "content": "# Dubbo Provider Properties as an alternative for\n# Spring XML Bean definition : META-INF/spring/dubbo-annotation-provider.xml\n\n## Service Providers' Placeholders for org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl\n\ndemo.service.application = dubbo-demo-application\ndemo.service.protocol = dubbo\ndemo.service.registry = my-registry\n\n\n## Dubbo configs binding properties\n\n### <dubbo:application name=\"dubbo-annotation-provider\"/>\ndubbo.application.id = dubbo-demo-application\ndubbo.application.name = dubbo-demo-application\n\n### <dubbo:registry id=\"my-registry\" address=\"N/A\"/>\ndubbo.registry.id = my-registry\ndubbo.registry.address = N/A\n\n### <dubbo:protocol name=\"dubbo\" port=\"12345\"/>\ndubbo.protocol.id = dubbo\ndubbo.protocol.name = dubbo\ndubbo.protocol.port = 12345\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.activate.ActivateExt1",
    "content": "old1=org.apache.dubbo.common.extension.activate.impl.OldActivateExt1Impl2\nold2=org.apache.dubbo.common.extension.activate.impl.OldActivateExt1Impl3\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.support.Filter0",
    "content": "_1=org.apache.dubbo.common.extension.support.Filter1\n_2=org.apache.dubbo.common.extension.support.Filter2\n_3=org.apache.dubbo.common.extension.support.Filter3\n_4=org.apache.dubbo.common.extension.support.Filter4\n_5=org.apache.dubbo.common.extension.support.OldFilter5"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter",
    "content": "mymock=org.apache.dubbo.config.spring.filter.MockFilter"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/dubbo-consumer.properties",
    "content": "# Dubbo Consumer Properties as an alternative for\n# Spring XML Bean definition : META-INF/spring/dubbo-annotation-consumer.xml\ndemo.service.application = dubbo-annotation-test\ndemo.service.registry = my-registry\n\n## Dubbo configs binding properties\n###  <dubbo:application name=\"dubbo-demo-application\"/>\n# In this UT, the provider will be responsible of loading ApplicationConfig.\ndubbo.applications.dubbo-demo-application.name = dubbo-demo-application\n\n### <dubbo:registry id=\"my-registry\" address=\"N/A\"/>\ndubbo.registries.my-registry.address = N/A\ndubbo.registries.my-registry2.address = N/A\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/dubbo-provider.properties",
    "content": "# Dubbo Provider Properties as an alternative for\n# Spring XML Bean definition : META-INF/spring/dubbo-annotation-provider.xml\n\n## Service Providers' Placeholders for org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl\n\ndemo.service.application = dubbo-demo-application\ndemo.service.protocol = dubbo\ndemo.service.registry = my-registry\n\n\n## Dubbo configs binding properties\n\n### <dubbo:application name=\"dubbo-demo-application\"/>\ndubbo.application.id = dubbo-demo-application\ndubbo.application.name = dubbo-demo-application\n\n### <dubbo:registry id=\"my-registry\" address=\"N/A\"/>\ndubbo.registry.id = my-registry\ndubbo.registry.address = N/A\n\n### <dubbo:protocol name=\"dubbo\" port=\"12345\"/>\ndubbo.protocol.name = dubbo\ndubbo.protocol.port = 12345\ndubbo.monitor.address=N/A\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/services/com.alibaba.dubbo.common.extension.ExtensionFactory",
    "content": "myfactory=org.apache.dubbo.common.extension.MyExtensionFactory"
  },
  {
    "path": "dubbo-compatible/src/test/resources/META-INF/services/org.apache.dubbo.remoting.Dispatcher",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nmockdispatcher=org.apache.dubbo.common.extension.MockDispatcher"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.ApplicationConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic void com.alibaba.dubbo.config.ApplicationConfig.setVersion(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.getOrganization()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setOrganization(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.getArchitecture()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setArchitecture(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.getEnvironment()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setEnvironment(java.lang.String)\npublic com.alibaba.dubbo.config.RegistryConfig com.alibaba.dubbo.config.ApplicationConfig.getRegistry()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setRegistry(com.alibaba.dubbo.config.RegistryConfig)\npublic java.util.List com.alibaba.dubbo.config.ApplicationConfig.getRegistries()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setRegistries(java.util.List)\npublic com.alibaba.dubbo.config.MonitorConfig com.alibaba.dubbo.config.ApplicationConfig.getMonitor()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setMonitor(java.lang.String)\npublic void com.alibaba.dubbo.config.ApplicationConfig.setMonitor(com.alibaba.dubbo.config.MonitorConfig)\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.getCompiler()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setCompiler(java.lang.String)\npublic void com.alibaba.dubbo.config.ApplicationConfig.setLogger(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.getDumpDirectory()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setDumpDirectory(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ApplicationConfig.getQosEnable()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setQosEnable(java.lang.Boolean)\npublic java.lang.Integer com.alibaba.dubbo.config.ApplicationConfig.getQosPort()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setQosPort(java.lang.Integer)\npublic java.lang.Boolean com.alibaba.dubbo.config.ApplicationConfig.getQosAcceptForeignIp()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setQosAcceptForeignIp(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.getName()\npublic java.lang.Boolean com.alibaba.dubbo.config.ApplicationConfig.isDefault()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setName(java.lang.String)\npublic java.util.Map com.alibaba.dubbo.config.ApplicationConfig.getParameters()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setDefault(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.getLogger()\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.getOwner()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setOwner(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.getVersion()\npublic void com.alibaba.dubbo.config.ApplicationConfig.setParameters(java.util.Map)\npublic void com.alibaba.dubbo.config.ApplicationConfig.setId(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.toString()\npublic java.lang.String com.alibaba.dubbo.config.ApplicationConfig.getId()\npublic final void com.alibaba.dubbo.config.ApplicationConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.ApplicationConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.ApplicationConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.ApplicationConfig.equals(java.lang.Object)\npublic native int com.alibaba.dubbo.config.ApplicationConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.ApplicationConfig.getClass()\npublic final native void com.alibaba.dubbo.config.ApplicationConfig.notify()\npublic final native void com.alibaba.dubbo.config.ApplicationConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.ArgumentConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic void com.alibaba.dubbo.config.ArgumentConfig.setCallback(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ArgumentConfig.isCallback()\npublic void com.alibaba.dubbo.config.ArgumentConfig.setIndex(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ArgumentConfig.getType()\npublic java.lang.Integer com.alibaba.dubbo.config.ArgumentConfig.getIndex()\npublic void com.alibaba.dubbo.config.ArgumentConfig.setType(java.lang.String)\npublic final void com.alibaba.dubbo.config.ArgumentConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.ArgumentConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.ArgumentConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.ArgumentConfig.equals(java.lang.Object)\npublic java.lang.String com.alibaba.dubbo.config.ArgumentConfig.toString()\npublic native int com.alibaba.dubbo.config.ArgumentConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.ArgumentConfig.getClass()\npublic final native void com.alibaba.dubbo.config.ArgumentConfig.notify()\npublic final native void com.alibaba.dubbo.config.ArgumentConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.ConsumerConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic void com.alibaba.dubbo.config.ConsumerConfig.setTimeout(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getClient()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setClient(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getThreadpool()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setThreadpool(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ConsumerConfig.getCorethreads()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setCorethreads(java.lang.Integer)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setThreads(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ConsumerConfig.getQueues()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setQueues(java.lang.Integer)\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.getDefault()\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.isDefault()\npublic java.lang.Integer com.alibaba.dubbo.config.ConsumerConfig.getThreads()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setDefault(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setVersion(java.lang.String)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setGeneric(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setGeneric(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getGeneric()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setListener(java.lang.String)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setOnconnect(java.lang.String)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setOndisconnect(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.getStubevent()\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getReconnect()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setReconnect(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.getSticky()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setSticky(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.getLazy()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setInit(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setInjvm(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setLazy(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.isInjvm()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setCheck(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.isCheck()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setGroup(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getGroup()\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.isInit()\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.isGeneric()\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getFilter()\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getListener()\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getVersion()\npublic com.alibaba.dubbo.config.RegistryConfig com.alibaba.dubbo.config.ConsumerConfig.getRegistry()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setRegistry(com.alibaba.dubbo.config.RegistryConfig)\npublic java.util.List com.alibaba.dubbo.config.ConsumerConfig.getRegistries()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setRegistries(java.util.List)\npublic com.alibaba.dubbo.config.MonitorConfig com.alibaba.dubbo.config.ConsumerConfig.getMonitor()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setMonitor(com.alibaba.dubbo.config.MonitorConfig)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setMonitor(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getCluster()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setCluster(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ConsumerConfig.getConnections()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setConnections(java.lang.Integer)\npublic com.alibaba.dubbo.config.ApplicationConfig com.alibaba.dubbo.config.ConsumerConfig.getApplication()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setApplication(com.alibaba.dubbo.config.ApplicationConfig)\npublic com.alibaba.dubbo.config.ModuleConfig com.alibaba.dubbo.config.ConsumerConfig.getModule()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setModule(com.alibaba.dubbo.config.ModuleConfig)\npublic java.lang.Integer com.alibaba.dubbo.config.ConsumerConfig.getCallbacks()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setCallbacks(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getOnconnect()\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getOndisconnect()\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getLocal()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setLocal(java.lang.String)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setLocal(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setStub(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setStub(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getProxy()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setProxy(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getLayer()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setLayer(java.lang.String)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setScope(java.lang.String)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setFilter(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getOwner()\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getScope()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setOwner(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getStub()\npublic java.lang.Integer com.alibaba.dubbo.config.ConsumerConfig.getRetries()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setRetries(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getLoadbalance()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setLoadbalance(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ConsumerConfig.getActives()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setActives(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getMerger()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setMerger(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getValidation()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setValidation(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.isAsync()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setForks(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ConsumerConfig.getForks()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setAsync(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ConsumerConfig.getSent()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setSent(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getMock()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setMock(java.lang.String)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setMock(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ConsumerConfig.setCache(java.lang.String)\npublic java.util.Map com.alibaba.dubbo.config.ConsumerConfig.getParameters()\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getCache()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setParameters(java.util.Map)\npublic java.lang.Integer com.alibaba.dubbo.config.ConsumerConfig.getTimeout()\npublic void com.alibaba.dubbo.config.ConsumerConfig.setId(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.toString()\npublic java.lang.String com.alibaba.dubbo.config.ConsumerConfig.getId()\npublic final void com.alibaba.dubbo.config.ConsumerConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.ConsumerConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.ConsumerConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.ConsumerConfig.equals(java.lang.Object)\npublic native int com.alibaba.dubbo.config.ConsumerConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.ConsumerConfig.getClass()\npublic final native void com.alibaba.dubbo.config.ConsumerConfig.notify()\npublic final native void com.alibaba.dubbo.config.ConsumerConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.MethodConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic java.lang.Boolean com.alibaba.dubbo.config.MethodConfig.getSticky()\npublic void com.alibaba.dubbo.config.MethodConfig.setSticky(java.lang.Boolean)\npublic static java.util.List com.alibaba.dubbo.config.MethodConfig.constructMethodConfig(com.alibaba.dubbo.config.annotation.Method[])\npublic java.lang.Boolean com.alibaba.dubbo.config.MethodConfig.isReliable()\npublic void com.alibaba.dubbo.config.MethodConfig.setReliable(java.lang.Boolean)\npublic java.lang.Integer com.alibaba.dubbo.config.MethodConfig.getExecutes()\npublic void com.alibaba.dubbo.config.MethodConfig.setExecutes(java.lang.Integer)\npublic java.lang.Boolean com.alibaba.dubbo.config.MethodConfig.getDeprecated()\npublic void com.alibaba.dubbo.config.MethodConfig.setDeprecated(java.lang.Boolean)\npublic java.util.List com.alibaba.dubbo.config.MethodConfig.getArguments()\npublic void com.alibaba.dubbo.config.MethodConfig.setArguments(java.util.List)\npublic java.lang.Object com.alibaba.dubbo.config.MethodConfig.getOnreturn()\npublic void com.alibaba.dubbo.config.MethodConfig.setOnreturn(java.lang.Object)\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.getOnreturnMethod()\npublic void com.alibaba.dubbo.config.MethodConfig.setOnreturnMethod(java.lang.String)\npublic java.lang.Object com.alibaba.dubbo.config.MethodConfig.getOnthrow()\npublic void com.alibaba.dubbo.config.MethodConfig.setOnthrow(java.lang.Object)\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.getOnthrowMethod()\npublic void com.alibaba.dubbo.config.MethodConfig.setOnthrowMethod(java.lang.String)\npublic java.lang.Object com.alibaba.dubbo.config.MethodConfig.getOninvoke()\npublic void com.alibaba.dubbo.config.MethodConfig.setOninvoke(java.lang.Object)\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.getOninvokeMethod()\npublic void com.alibaba.dubbo.config.MethodConfig.setOninvokeMethod(java.lang.String)\npublic void com.alibaba.dubbo.config.MethodConfig.setReturn(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.MethodConfig.isReturn()\npublic java.lang.Integer com.alibaba.dubbo.config.MethodConfig.getStat()\npublic void com.alibaba.dubbo.config.MethodConfig.setStat(java.lang.Integer)\npublic java.lang.Boolean com.alibaba.dubbo.config.MethodConfig.isRetry()\npublic void com.alibaba.dubbo.config.MethodConfig.setRetry(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.getName()\npublic void com.alibaba.dubbo.config.MethodConfig.setName(java.lang.String)\npublic void com.alibaba.dubbo.config.MethodConfig.setTimeout(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.MethodConfig.getRetries()\npublic void com.alibaba.dubbo.config.MethodConfig.setRetries(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.getLoadbalance()\npublic void com.alibaba.dubbo.config.MethodConfig.setLoadbalance(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.MethodConfig.getActives()\npublic void com.alibaba.dubbo.config.MethodConfig.setActives(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.getMerger()\npublic void com.alibaba.dubbo.config.MethodConfig.setMerger(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.getValidation()\npublic void com.alibaba.dubbo.config.MethodConfig.setValidation(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.MethodConfig.isAsync()\npublic void com.alibaba.dubbo.config.MethodConfig.setForks(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.MethodConfig.getForks()\npublic void com.alibaba.dubbo.config.MethodConfig.setAsync(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.MethodConfig.getSent()\npublic void com.alibaba.dubbo.config.MethodConfig.setSent(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.getMock()\npublic void com.alibaba.dubbo.config.MethodConfig.setMock(java.lang.String)\npublic void com.alibaba.dubbo.config.MethodConfig.setMock(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.MethodConfig.setCache(java.lang.String)\npublic java.util.Map com.alibaba.dubbo.config.MethodConfig.getParameters()\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.getCache()\npublic void com.alibaba.dubbo.config.MethodConfig.setParameters(java.util.Map)\npublic java.lang.Integer com.alibaba.dubbo.config.MethodConfig.getTimeout()\npublic void com.alibaba.dubbo.config.MethodConfig.setId(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.toString()\npublic java.lang.String com.alibaba.dubbo.config.MethodConfig.getId()\npublic final void com.alibaba.dubbo.config.MethodConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.MethodConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.MethodConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.MethodConfig.equals(java.lang.Object)\npublic native int com.alibaba.dubbo.config.MethodConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.MethodConfig.getClass()\npublic final native void com.alibaba.dubbo.config.MethodConfig.notify()\npublic final native void com.alibaba.dubbo.config.MethodConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.ModuleConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic void com.alibaba.dubbo.config.ModuleConfig.setVersion(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ModuleConfig.getOrganization()\npublic void com.alibaba.dubbo.config.ModuleConfig.setOrganization(java.lang.String)\npublic com.alibaba.dubbo.config.RegistryConfig com.alibaba.dubbo.config.ModuleConfig.getRegistry()\npublic void com.alibaba.dubbo.config.ModuleConfig.setRegistry(com.alibaba.dubbo.config.RegistryConfig)\npublic java.util.List com.alibaba.dubbo.config.ModuleConfig.getRegistries()\npublic void com.alibaba.dubbo.config.ModuleConfig.setRegistries(java.util.List)\npublic com.alibaba.dubbo.config.MonitorConfig com.alibaba.dubbo.config.ModuleConfig.getMonitor()\npublic void com.alibaba.dubbo.config.ModuleConfig.setMonitor(java.lang.String)\npublic void com.alibaba.dubbo.config.ModuleConfig.setMonitor(com.alibaba.dubbo.config.MonitorConfig)\npublic java.lang.String com.alibaba.dubbo.config.ModuleConfig.getName()\npublic java.lang.Boolean com.alibaba.dubbo.config.ModuleConfig.isDefault()\npublic void com.alibaba.dubbo.config.ModuleConfig.setName(java.lang.String)\npublic void com.alibaba.dubbo.config.ModuleConfig.setDefault(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ModuleConfig.getOwner()\npublic void com.alibaba.dubbo.config.ModuleConfig.setOwner(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ModuleConfig.getVersion()\npublic void com.alibaba.dubbo.config.ModuleConfig.setId(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ModuleConfig.toString()\npublic java.lang.String com.alibaba.dubbo.config.ModuleConfig.getId()\npublic final void com.alibaba.dubbo.config.ModuleConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.ModuleConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.ModuleConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.ModuleConfig.equals(java.lang.Object)\npublic native int com.alibaba.dubbo.config.ModuleConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.ModuleConfig.getClass()\npublic final native void com.alibaba.dubbo.config.ModuleConfig.notify()\npublic final native void com.alibaba.dubbo.config.ModuleConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.MonitorConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic void com.alibaba.dubbo.config.MonitorConfig.setVersion(java.lang.String)\npublic void com.alibaba.dubbo.config.MonitorConfig.setProtocol(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.MonitorConfig.getUsername()\npublic void com.alibaba.dubbo.config.MonitorConfig.setUsername(java.lang.String)\npublic void com.alibaba.dubbo.config.MonitorConfig.setPassword(java.lang.String)\npublic void com.alibaba.dubbo.config.MonitorConfig.setInterval(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.MonitorConfig.getInterval()\npublic void com.alibaba.dubbo.config.MonitorConfig.setGroup(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.MonitorConfig.getGroup()\npublic java.lang.String com.alibaba.dubbo.config.MonitorConfig.getAddress()\npublic java.lang.Boolean com.alibaba.dubbo.config.MonitorConfig.isDefault()\npublic java.util.Map com.alibaba.dubbo.config.MonitorConfig.getParameters()\npublic java.lang.String com.alibaba.dubbo.config.MonitorConfig.getProtocol()\npublic void com.alibaba.dubbo.config.MonitorConfig.setDefault(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.MonitorConfig.getPassword()\npublic void com.alibaba.dubbo.config.MonitorConfig.setAddress(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.MonitorConfig.getVersion()\npublic void com.alibaba.dubbo.config.MonitorConfig.setParameters(java.util.Map)\npublic void com.alibaba.dubbo.config.MonitorConfig.setId(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.MonitorConfig.toString()\npublic java.lang.String com.alibaba.dubbo.config.MonitorConfig.getId()\npublic final void com.alibaba.dubbo.config.MonitorConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.MonitorConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.MonitorConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.MonitorConfig.equals(java.lang.Object)\npublic native int com.alibaba.dubbo.config.MonitorConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.MonitorConfig.getClass()\npublic final native void com.alibaba.dubbo.config.MonitorConfig.notify()\npublic final native void com.alibaba.dubbo.config.MonitorConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.ProtocolConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getClient()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setClient(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getThreadpool()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setThreadpool(java.lang.String)\npublic void com.alibaba.dubbo.config.ProtocolConfig.setThreads(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ProtocolConfig.getQueues()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setQueues(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getContextpath()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setContextpath(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ProtocolConfig.getIothreads()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setIothreads(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ProtocolConfig.getAccepts()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setAccepts(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getSerialization()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setSerialization(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getCharset()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setCharset(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ProtocolConfig.getPayload()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setPayload(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ProtocolConfig.getHeartbeat()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setHeartbeat(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getServer()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setServer(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getAccesslog()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setAccesslog(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getTelnet()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setTelnet(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getPrompt()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setPrompt(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getStatus()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setStatus(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ProtocolConfig.isRegister()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setRegister(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getTransporter()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setTransporter(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getExchanger()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setExchanger(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getDispather()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setDispather(java.lang.String)\npublic void com.alibaba.dubbo.config.ProtocolConfig.setDispatcher(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getNetworker()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setNetworker(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getOptimizer()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setOptimizer(java.lang.String)\npublic void com.alibaba.dubbo.config.ProtocolConfig.setExtension(java.lang.String)\npublic void com.alibaba.dubbo.config.ProtocolConfig.setHost(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getCodec()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setCodec(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getName()\npublic java.lang.Boolean com.alibaba.dubbo.config.ProtocolConfig.isDefault()\npublic void com.alibaba.dubbo.config.ProtocolConfig.destroy()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setName(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ProtocolConfig.getThreads()\npublic java.util.Map com.alibaba.dubbo.config.ProtocolConfig.getParameters()\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getPath()\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getHost()\npublic java.lang.Integer com.alibaba.dubbo.config.ProtocolConfig.getPort()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setDefault(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getExtension()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setPort(java.lang.Integer)\npublic void com.alibaba.dubbo.config.ProtocolConfig.setKeepAlive(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ProtocolConfig.getKeepAlive()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setPath(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getDispatcher()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setBuffer(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ProtocolConfig.getBuffer()\npublic void com.alibaba.dubbo.config.ProtocolConfig.setParameters(java.util.Map)\npublic void com.alibaba.dubbo.config.ProtocolConfig.setId(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.toString()\npublic java.lang.String com.alibaba.dubbo.config.ProtocolConfig.getId()\npublic final void com.alibaba.dubbo.config.ProtocolConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.ProtocolConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.ProtocolConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.ProtocolConfig.equals(java.lang.Object)\npublic native int com.alibaba.dubbo.config.ProtocolConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.ProtocolConfig.getClass()\npublic final native void com.alibaba.dubbo.config.ProtocolConfig.notify()\npublic final native void com.alibaba.dubbo.config.ProtocolConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.ProviderConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getClient()\npublic void com.alibaba.dubbo.config.ProviderConfig.setClient(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getThreadpool()\npublic void com.alibaba.dubbo.config.ProviderConfig.setThreadpool(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setThreads(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getQueues()\npublic void com.alibaba.dubbo.config.ProviderConfig.setQueues(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getCluster()\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getConnections()\npublic void com.alibaba.dubbo.config.ProviderConfig.setProtocol(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getRetries()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getLoadbalance()\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getActives()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getContextpath()\npublic void com.alibaba.dubbo.config.ProviderConfig.setContextpath(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getIothreads()\npublic void com.alibaba.dubbo.config.ProviderConfig.setIothreads(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getAccepts()\npublic void com.alibaba.dubbo.config.ProviderConfig.setAccepts(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getCharset()\npublic void com.alibaba.dubbo.config.ProviderConfig.setCharset(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getPayload()\npublic void com.alibaba.dubbo.config.ProviderConfig.setPayload(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getServer()\npublic void com.alibaba.dubbo.config.ProviderConfig.setServer(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getTelnet()\npublic void com.alibaba.dubbo.config.ProviderConfig.setTelnet(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getPrompt()\npublic void com.alibaba.dubbo.config.ProviderConfig.setPrompt(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getStatus()\npublic void com.alibaba.dubbo.config.ProviderConfig.setStatus(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getTransporter()\npublic void com.alibaba.dubbo.config.ProviderConfig.setTransporter(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getExchanger()\npublic void com.alibaba.dubbo.config.ProviderConfig.setExchanger(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getDispather()\npublic void com.alibaba.dubbo.config.ProviderConfig.setDispather(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setDispatcher(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getNetworker()\npublic void com.alibaba.dubbo.config.ProviderConfig.setNetworker(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ProviderConfig.isAsync()\npublic void com.alibaba.dubbo.config.ProviderConfig.setHost(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getCodec()\npublic void com.alibaba.dubbo.config.ProviderConfig.setCodec(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getWait()\npublic void com.alibaba.dubbo.config.ProviderConfig.setWait(java.lang.Integer)\npublic java.lang.Boolean com.alibaba.dubbo.config.ProviderConfig.isDefault()\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getThreads()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getPath()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getHost()\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getPort()\npublic void com.alibaba.dubbo.config.ProviderConfig.setDefault(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ProviderConfig.setPort(java.lang.Integer)\npublic void com.alibaba.dubbo.config.ProviderConfig.setPath(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getDispatcher()\npublic void com.alibaba.dubbo.config.ProviderConfig.setBuffer(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getBuffer()\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getTimeout()\npublic void com.alibaba.dubbo.config.ProviderConfig.setVersion(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setListener(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setProtocol(com.alibaba.dubbo.config.ProtocolConfig)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getExecutes()\npublic void com.alibaba.dubbo.config.ProviderConfig.setExecutes(java.lang.Integer)\npublic void com.alibaba.dubbo.config.ProviderConfig.setDeprecated(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getSerialization()\npublic void com.alibaba.dubbo.config.ProviderConfig.setSerialization(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getAccesslog()\npublic void com.alibaba.dubbo.config.ProviderConfig.setAccesslog(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setAccesslog(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ProviderConfig.isRegister()\npublic void com.alibaba.dubbo.config.ProviderConfig.setRegister(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ProviderConfig.getExport()\npublic void com.alibaba.dubbo.config.ProviderConfig.setExport(java.lang.Boolean)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getWeight()\npublic void com.alibaba.dubbo.config.ProviderConfig.setWeight(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getDocument()\npublic void com.alibaba.dubbo.config.ProviderConfig.setDocument(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ProviderConfig.isDeprecated()\npublic void com.alibaba.dubbo.config.ProviderConfig.setDynamic(java.lang.Boolean)\npublic java.util.List com.alibaba.dubbo.config.ProviderConfig.getProtocols()\npublic void com.alibaba.dubbo.config.ProviderConfig.setProtocols(java.util.List)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getWarmup()\npublic void com.alibaba.dubbo.config.ProviderConfig.setWarmup(java.lang.Integer)\npublic void com.alibaba.dubbo.config.ProviderConfig.setGroup(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getGroup()\npublic void com.alibaba.dubbo.config.ProviderConfig.setDelay(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getToken()\npublic void com.alibaba.dubbo.config.ProviderConfig.setToken(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setToken(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getTag()\npublic void com.alibaba.dubbo.config.ProviderConfig.setTag(java.lang.String)\npublic com.alibaba.dubbo.config.ProtocolConfig com.alibaba.dubbo.config.ProviderConfig.getProtocol()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getFilter()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getListener()\npublic java.lang.Boolean com.alibaba.dubbo.config.ProviderConfig.isDynamic()\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getDelay()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getVersion()\npublic com.alibaba.dubbo.config.RegistryConfig com.alibaba.dubbo.config.ProviderConfig.getRegistry()\npublic void com.alibaba.dubbo.config.ProviderConfig.setRegistry(com.alibaba.dubbo.config.RegistryConfig)\npublic java.util.List com.alibaba.dubbo.config.ProviderConfig.getRegistries()\npublic void com.alibaba.dubbo.config.ProviderConfig.setRegistries(java.util.List)\npublic com.alibaba.dubbo.config.MonitorConfig com.alibaba.dubbo.config.ProviderConfig.getMonitor()\npublic void com.alibaba.dubbo.config.ProviderConfig.setMonitor(com.alibaba.dubbo.config.MonitorConfig)\npublic void com.alibaba.dubbo.config.ProviderConfig.setMonitor(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setOnconnect(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setOndisconnect(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setCluster(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setConnections(java.lang.Integer)\npublic com.alibaba.dubbo.config.ApplicationConfig com.alibaba.dubbo.config.ProviderConfig.getApplication()\npublic void com.alibaba.dubbo.config.ProviderConfig.setApplication(com.alibaba.dubbo.config.ApplicationConfig)\npublic com.alibaba.dubbo.config.ModuleConfig com.alibaba.dubbo.config.ProviderConfig.getModule()\npublic void com.alibaba.dubbo.config.ProviderConfig.setModule(com.alibaba.dubbo.config.ModuleConfig)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getCallbacks()\npublic void com.alibaba.dubbo.config.ProviderConfig.setCallbacks(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getOnconnect()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getOndisconnect()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getLocal()\npublic void com.alibaba.dubbo.config.ProviderConfig.setLocal(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setLocal(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ProviderConfig.setStub(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ProviderConfig.setStub(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getProxy()\npublic void com.alibaba.dubbo.config.ProviderConfig.setProxy(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getLayer()\npublic void com.alibaba.dubbo.config.ProviderConfig.setLayer(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setScope(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setFilter(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getOwner()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getScope()\npublic void com.alibaba.dubbo.config.ProviderConfig.setOwner(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getStub()\npublic void com.alibaba.dubbo.config.ProviderConfig.setTimeout(java.lang.Integer)\npublic void com.alibaba.dubbo.config.ProviderConfig.setRetries(java.lang.Integer)\npublic void com.alibaba.dubbo.config.ProviderConfig.setLoadbalance(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setActives(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getMerger()\npublic void com.alibaba.dubbo.config.ProviderConfig.setMerger(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getValidation()\npublic void com.alibaba.dubbo.config.ProviderConfig.setValidation(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setForks(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ProviderConfig.getForks()\npublic void com.alibaba.dubbo.config.ProviderConfig.setAsync(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ProviderConfig.getSent()\npublic void com.alibaba.dubbo.config.ProviderConfig.setSent(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getMock()\npublic void com.alibaba.dubbo.config.ProviderConfig.setMock(java.lang.String)\npublic void com.alibaba.dubbo.config.ProviderConfig.setMock(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ProviderConfig.setCache(java.lang.String)\npublic java.util.Map com.alibaba.dubbo.config.ProviderConfig.getParameters()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getCache()\npublic void com.alibaba.dubbo.config.ProviderConfig.setParameters(java.util.Map)\npublic void com.alibaba.dubbo.config.ProviderConfig.setId(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.toString()\npublic java.lang.String com.alibaba.dubbo.config.ProviderConfig.getId()\npublic final void com.alibaba.dubbo.config.ProviderConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.ProviderConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.ProviderConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.ProviderConfig.equals(java.lang.Object)\npublic native int com.alibaba.dubbo.config.ProviderConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.ProviderConfig.getClass()\npublic final native void com.alibaba.dubbo.config.ProviderConfig.notify()\npublic final native void com.alibaba.dubbo.config.ProviderConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.ReferenceConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getClient()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setClient(java.lang.String)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setProtocol(java.lang.String)\npublic java.lang.Class com.alibaba.dubbo.config.ReferenceConfig.getInterfaceClass()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setInterfaceClass(java.lang.Class)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getInterface()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setInterface(java.lang.Class)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setInterface(java.lang.String)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setMethods(java.util.List)\npublic com.alibaba.dubbo.config.ConsumerConfig com.alibaba.dubbo.config.ReferenceConfig.getConsumer()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setConsumer(com.alibaba.dubbo.config.ConsumerConfig)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getUniqueServiceName()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getGroup()\npublic com.alibaba.dubbo.common.URL com.alibaba.dubbo.config.ReferenceConfig.toUrl()\npublic java.util.List com.alibaba.dubbo.config.ReferenceConfig.toUrls()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getUrl()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setUrl(java.lang.String)\npublic synchronized java.lang.Object com.alibaba.dubbo.config.ReferenceConfig.get()\npublic java.util.List com.alibaba.dubbo.config.ReferenceConfig.getMethods()\npublic synchronized void com.alibaba.dubbo.config.ReferenceConfig.destroy()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getProtocol()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getVersion()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setVersion(java.lang.String)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setGeneric(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setGeneric(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getGeneric()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setListener(java.lang.String)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setOnconnect(java.lang.String)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setOndisconnect(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ReferenceConfig.getStubevent()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getReconnect()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setReconnect(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ReferenceConfig.getSticky()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setSticky(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ReferenceConfig.getLazy()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setInit(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setInjvm(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setLazy(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ReferenceConfig.isInjvm()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setCheck(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ReferenceConfig.isCheck()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setGroup(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ReferenceConfig.isInit()\npublic java.lang.Boolean com.alibaba.dubbo.config.ReferenceConfig.isGeneric()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getFilter()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getListener()\npublic com.alibaba.dubbo.config.RegistryConfig com.alibaba.dubbo.config.ReferenceConfig.getRegistry()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setRegistry(com.alibaba.dubbo.config.RegistryConfig)\npublic java.util.List com.alibaba.dubbo.config.ReferenceConfig.getRegistries()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setRegistries(java.util.List)\npublic com.alibaba.dubbo.config.MonitorConfig com.alibaba.dubbo.config.ReferenceConfig.getMonitor()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setMonitor(com.alibaba.dubbo.config.MonitorConfig)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setMonitor(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getCluster()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setCluster(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ReferenceConfig.getConnections()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setConnections(java.lang.Integer)\npublic com.alibaba.dubbo.config.ApplicationConfig com.alibaba.dubbo.config.ReferenceConfig.getApplication()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setApplication(com.alibaba.dubbo.config.ApplicationConfig)\npublic com.alibaba.dubbo.config.ModuleConfig com.alibaba.dubbo.config.ReferenceConfig.getModule()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setModule(com.alibaba.dubbo.config.ModuleConfig)\npublic java.lang.Integer com.alibaba.dubbo.config.ReferenceConfig.getCallbacks()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setCallbacks(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getOnconnect()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getOndisconnect()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getLocal()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setLocal(java.lang.String)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setLocal(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setStub(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setStub(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getProxy()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setProxy(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getLayer()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setLayer(java.lang.String)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setScope(java.lang.String)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setFilter(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getOwner()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getScope()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setOwner(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getStub()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setTimeout(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ReferenceConfig.getRetries()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setRetries(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getLoadbalance()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setLoadbalance(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ReferenceConfig.getActives()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setActives(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getMerger()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setMerger(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getValidation()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setValidation(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ReferenceConfig.isAsync()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setForks(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ReferenceConfig.getForks()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setAsync(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ReferenceConfig.getSent()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setSent(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getMock()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setMock(java.lang.String)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setMock(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ReferenceConfig.setCache(java.lang.String)\npublic java.util.Map com.alibaba.dubbo.config.ReferenceConfig.getParameters()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getCache()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setParameters(java.util.Map)\npublic java.lang.Integer com.alibaba.dubbo.config.ReferenceConfig.getTimeout()\npublic void com.alibaba.dubbo.config.ReferenceConfig.setId(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.toString()\npublic java.lang.String com.alibaba.dubbo.config.ReferenceConfig.getId()\npublic final void com.alibaba.dubbo.config.ReferenceConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.ReferenceConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.ReferenceConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.ReferenceConfig.equals(java.lang.Object)\npublic native int com.alibaba.dubbo.config.ReferenceConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.ReferenceConfig.getClass()\npublic final native void com.alibaba.dubbo.config.ReferenceConfig.notify()\npublic final native void com.alibaba.dubbo.config.ReferenceConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.RegistryConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic void com.alibaba.dubbo.config.RegistryConfig.setVersion(java.lang.String)\npublic void com.alibaba.dubbo.config.RegistryConfig.setTimeout(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getClient()\npublic void com.alibaba.dubbo.config.RegistryConfig.setClient(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getCluster()\npublic void com.alibaba.dubbo.config.RegistryConfig.setCluster(java.lang.String)\npublic void com.alibaba.dubbo.config.RegistryConfig.setProtocol(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getUsername()\npublic void com.alibaba.dubbo.config.RegistryConfig.setUsername(java.lang.String)\npublic void com.alibaba.dubbo.config.RegistryConfig.setPassword(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getServer()\npublic void com.alibaba.dubbo.config.RegistryConfig.setServer(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.RegistryConfig.isRegister()\npublic void com.alibaba.dubbo.config.RegistryConfig.setRegister(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getTransporter()\npublic void com.alibaba.dubbo.config.RegistryConfig.setTransporter(java.lang.String)\npublic void com.alibaba.dubbo.config.RegistryConfig.setDynamic(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getTransport()\npublic void com.alibaba.dubbo.config.RegistryConfig.setTransport(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.RegistryConfig.getSession()\npublic void com.alibaba.dubbo.config.RegistryConfig.setSession(java.lang.Integer)\npublic java.lang.Boolean com.alibaba.dubbo.config.RegistryConfig.isSubscribe()\npublic void com.alibaba.dubbo.config.RegistryConfig.setSubscribe(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.RegistryConfig.setCheck(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.RegistryConfig.isCheck()\npublic void com.alibaba.dubbo.config.RegistryConfig.setGroup(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getGroup()\npublic java.lang.Integer com.alibaba.dubbo.config.RegistryConfig.getWait()\npublic void com.alibaba.dubbo.config.RegistryConfig.setWait(java.lang.Integer)\npublic void com.alibaba.dubbo.config.RegistryConfig.setFile(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getAddress()\npublic java.lang.Boolean com.alibaba.dubbo.config.RegistryConfig.isDefault()\npublic java.util.Map com.alibaba.dubbo.config.RegistryConfig.getParameters()\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getProtocol()\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getFile()\npublic java.lang.Integer com.alibaba.dubbo.config.RegistryConfig.getPort()\npublic void com.alibaba.dubbo.config.RegistryConfig.setDefault(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getPassword()\npublic void com.alibaba.dubbo.config.RegistryConfig.setAddress(java.lang.String)\npublic void com.alibaba.dubbo.config.RegistryConfig.setPort(java.lang.Integer)\npublic java.lang.Boolean com.alibaba.dubbo.config.RegistryConfig.isDynamic()\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getVersion()\npublic void com.alibaba.dubbo.config.RegistryConfig.setParameters(java.util.Map)\npublic java.lang.Integer com.alibaba.dubbo.config.RegistryConfig.getTimeout()\npublic void com.alibaba.dubbo.config.RegistryConfig.setId(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.toString()\npublic java.lang.String com.alibaba.dubbo.config.RegistryConfig.getId()\npublic final void com.alibaba.dubbo.config.RegistryConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.RegistryConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.RegistryConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.RegistryConfig.equals(java.lang.Object)\npublic native int com.alibaba.dubbo.config.RegistryConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.RegistryConfig.getClass()\npublic final native void com.alibaba.dubbo.config.RegistryConfig.notify()\npublic final native void com.alibaba.dubbo.config.RegistryConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/definition/com.alibaba.dubbo.config.ServiceConfig",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npublic void com.alibaba.dubbo.config.ServiceConfig.setGeneric(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getGeneric()\npublic boolean com.alibaba.dubbo.config.ServiceConfig.isExported()\npublic boolean com.alibaba.dubbo.config.ServiceConfig.isUnexported()\npublic void com.alibaba.dubbo.config.ServiceConfig.setProvider(com.alibaba.dubbo.config.ProviderConfig)\npublic java.util.List com.alibaba.dubbo.config.ServiceConfig.getExportedUrls()\npublic void com.alibaba.dubbo.config.ServiceConfig.setProviders(java.util.List)\npublic java.lang.Class com.alibaba.dubbo.config.ServiceConfig.getInterfaceClass()\npublic void com.alibaba.dubbo.config.ServiceConfig.setInterfaceClass(java.lang.Class)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getInterface()\npublic void com.alibaba.dubbo.config.ServiceConfig.setInterface(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setInterface(java.lang.Class)\npublic void com.alibaba.dubbo.config.ServiceConfig.setMethods(java.util.List)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getUniqueServiceName()\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getGroup()\npublic void com.alibaba.dubbo.config.ServiceConfig.setMock(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ServiceConfig.setMock(java.lang.String)\npublic com.alibaba.dubbo.common.URL com.alibaba.dubbo.config.ServiceConfig.toUrl()\npublic java.util.List com.alibaba.dubbo.config.ServiceConfig.toUrls()\npublic synchronized void com.alibaba.dubbo.config.ServiceConfig.unexport()\npublic java.util.List com.alibaba.dubbo.config.ServiceConfig.getMethods()\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getPath()\npublic java.lang.Object com.alibaba.dubbo.config.ServiceConfig.getRef()\npublic synchronized void com.alibaba.dubbo.config.ServiceConfig.export()\npublic java.util.List com.alibaba.dubbo.config.ServiceConfig.getProviders()\npublic com.alibaba.dubbo.config.ProviderConfig com.alibaba.dubbo.config.ServiceConfig.getProvider()\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getVersion()\npublic void com.alibaba.dubbo.config.ServiceConfig.setPath(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setRef(java.lang.Object)\npublic void com.alibaba.dubbo.config.ServiceConfig.setVersion(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setListener(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setProtocol(com.alibaba.dubbo.config.ProtocolConfig)\npublic java.lang.Integer com.alibaba.dubbo.config.ServiceConfig.getExecutes()\npublic void com.alibaba.dubbo.config.ServiceConfig.setExecutes(java.lang.Integer)\npublic void com.alibaba.dubbo.config.ServiceConfig.setDeprecated(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getSerialization()\npublic void com.alibaba.dubbo.config.ServiceConfig.setSerialization(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getAccesslog()\npublic void com.alibaba.dubbo.config.ServiceConfig.setAccesslog(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setAccesslog(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ServiceConfig.isRegister()\npublic void com.alibaba.dubbo.config.ServiceConfig.setRegister(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ServiceConfig.getExport()\npublic void com.alibaba.dubbo.config.ServiceConfig.setExport(java.lang.Boolean)\npublic java.lang.Integer com.alibaba.dubbo.config.ServiceConfig.getWeight()\npublic void com.alibaba.dubbo.config.ServiceConfig.setWeight(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getDocument()\npublic void com.alibaba.dubbo.config.ServiceConfig.setDocument(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ServiceConfig.isDeprecated()\npublic void com.alibaba.dubbo.config.ServiceConfig.setDynamic(java.lang.Boolean)\npublic java.util.List com.alibaba.dubbo.config.ServiceConfig.getProtocols()\npublic void com.alibaba.dubbo.config.ServiceConfig.setProtocols(java.util.List)\npublic java.lang.Integer com.alibaba.dubbo.config.ServiceConfig.getWarmup()\npublic void com.alibaba.dubbo.config.ServiceConfig.setWarmup(java.lang.Integer)\npublic void com.alibaba.dubbo.config.ServiceConfig.setGroup(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setDelay(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getToken()\npublic void com.alibaba.dubbo.config.ServiceConfig.setToken(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setToken(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getTag()\npublic void com.alibaba.dubbo.config.ServiceConfig.setTag(java.lang.String)\npublic com.alibaba.dubbo.config.ProtocolConfig com.alibaba.dubbo.config.ServiceConfig.getProtocol()\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getFilter()\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getListener()\npublic java.lang.Boolean com.alibaba.dubbo.config.ServiceConfig.isDynamic()\npublic java.lang.Integer com.alibaba.dubbo.config.ServiceConfig.getDelay()\npublic com.alibaba.dubbo.config.RegistryConfig com.alibaba.dubbo.config.ServiceConfig.getRegistry()\npublic void com.alibaba.dubbo.config.ServiceConfig.setRegistry(com.alibaba.dubbo.config.RegistryConfig)\npublic java.util.List com.alibaba.dubbo.config.ServiceConfig.getRegistries()\npublic void com.alibaba.dubbo.config.ServiceConfig.setRegistries(java.util.List)\npublic com.alibaba.dubbo.config.MonitorConfig com.alibaba.dubbo.config.ServiceConfig.getMonitor()\npublic void com.alibaba.dubbo.config.ServiceConfig.setMonitor(com.alibaba.dubbo.config.MonitorConfig)\npublic void com.alibaba.dubbo.config.ServiceConfig.setMonitor(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setOnconnect(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setOndisconnect(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getCluster()\npublic void com.alibaba.dubbo.config.ServiceConfig.setCluster(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ServiceConfig.getConnections()\npublic void com.alibaba.dubbo.config.ServiceConfig.setConnections(java.lang.Integer)\npublic com.alibaba.dubbo.config.ApplicationConfig com.alibaba.dubbo.config.ServiceConfig.getApplication()\npublic void com.alibaba.dubbo.config.ServiceConfig.setApplication(com.alibaba.dubbo.config.ApplicationConfig)\npublic com.alibaba.dubbo.config.ModuleConfig com.alibaba.dubbo.config.ServiceConfig.getModule()\npublic void com.alibaba.dubbo.config.ServiceConfig.setModule(com.alibaba.dubbo.config.ModuleConfig)\npublic java.lang.Integer com.alibaba.dubbo.config.ServiceConfig.getCallbacks()\npublic void com.alibaba.dubbo.config.ServiceConfig.setCallbacks(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getOnconnect()\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getOndisconnect()\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getLocal()\npublic void com.alibaba.dubbo.config.ServiceConfig.setLocal(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setLocal(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ServiceConfig.setStub(java.lang.Boolean)\npublic void com.alibaba.dubbo.config.ServiceConfig.setStub(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getProxy()\npublic void com.alibaba.dubbo.config.ServiceConfig.setProxy(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getLayer()\npublic void com.alibaba.dubbo.config.ServiceConfig.setLayer(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setScope(java.lang.String)\npublic void com.alibaba.dubbo.config.ServiceConfig.setFilter(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getOwner()\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getScope()\npublic void com.alibaba.dubbo.config.ServiceConfig.setOwner(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getStub()\npublic void com.alibaba.dubbo.config.ServiceConfig.setTimeout(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ServiceConfig.getRetries()\npublic void com.alibaba.dubbo.config.ServiceConfig.setRetries(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getLoadbalance()\npublic void com.alibaba.dubbo.config.ServiceConfig.setLoadbalance(java.lang.String)\npublic java.lang.Integer com.alibaba.dubbo.config.ServiceConfig.getActives()\npublic void com.alibaba.dubbo.config.ServiceConfig.setActives(java.lang.Integer)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getMerger()\npublic void com.alibaba.dubbo.config.ServiceConfig.setMerger(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getValidation()\npublic void com.alibaba.dubbo.config.ServiceConfig.setValidation(java.lang.String)\npublic java.lang.Boolean com.alibaba.dubbo.config.ServiceConfig.isAsync()\npublic void com.alibaba.dubbo.config.ServiceConfig.setForks(java.lang.Integer)\npublic java.lang.Integer com.alibaba.dubbo.config.ServiceConfig.getForks()\npublic void com.alibaba.dubbo.config.ServiceConfig.setAsync(java.lang.Boolean)\npublic java.lang.Boolean com.alibaba.dubbo.config.ServiceConfig.getSent()\npublic void com.alibaba.dubbo.config.ServiceConfig.setSent(java.lang.Boolean)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getMock()\npublic void com.alibaba.dubbo.config.ServiceConfig.setCache(java.lang.String)\npublic java.util.Map com.alibaba.dubbo.config.ServiceConfig.getParameters()\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getCache()\npublic void com.alibaba.dubbo.config.ServiceConfig.setParameters(java.util.Map)\npublic java.lang.Integer com.alibaba.dubbo.config.ServiceConfig.getTimeout()\npublic void com.alibaba.dubbo.config.ServiceConfig.setId(java.lang.String)\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.toString()\npublic java.lang.String com.alibaba.dubbo.config.ServiceConfig.getId()\npublic final void com.alibaba.dubbo.config.ServiceConfig.wait(long,int) throws java.lang.InterruptedException\npublic final native void com.alibaba.dubbo.config.ServiceConfig.wait(long) throws java.lang.InterruptedException\npublic final void com.alibaba.dubbo.config.ServiceConfig.wait() throws java.lang.InterruptedException\npublic boolean com.alibaba.dubbo.config.ServiceConfig.equals(java.lang.Object)\npublic native int com.alibaba.dubbo.config.ServiceConfig.hashCode()\npublic final native java.lang.Class com.alibaba.dubbo.config.ServiceConfig.getClass()\npublic final native void com.alibaba.dubbo.config.ServiceConfig.notify()\npublic final native void com.alibaba.dubbo.config.ServiceConfig.notifyAll()\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/dubbo.properties",
    "content": "dubbo.application.enable-file-cache=false\ndubbo.service.shutdown.wait=200\n"
  },
  {
    "path": "dubbo-compatible/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-config</artifactId>\n    <version>${revision}</version>\n  </parent>\n  <artifactId>dubbo-config-api</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The config api module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-registry</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-metadata</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-config-center</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-tracing</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-injvm</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <!-- FIXME, we shouldn't rely on these modules, even in test scope -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-dubbo</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>io.swagger</groupId>\n      <artifactId>swagger-annotations</artifactId>\n      <scope>test</scope>\n      <exclusions>\n        <exclusion>\n          <groupId>javax.ws.rs</groupId>\n          <artifactId>jsr311-api</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>org.jboss.resteasy</groupId>\n      <artifactId>resteasy-jaxrs</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-fastjson2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-multicast</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-framework</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-recipes</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.zookeeper</groupId>\n      <artifactId>zookeeper</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-nacos</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n      <exclusions>\n        <exclusion>\n          <groupId>com.google.guava</groupId>\n          <artifactId>guava</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-nacos</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n      <exclusions>\n        <exclusion>\n          <groupId>com.google.guava</groupId>\n          <artifactId>guava</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-filter-cache</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-filter-validation</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.testcontainers</groupId>\n      <artifactId>testcontainers</artifactId>\n      <version>1.21.4</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.jboss.resteasy</groupId>\n      <artifactId>resteasy-jackson-provider</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * Dynamically add some parameters / check config\n */\n@SPI(scope = ExtensionScope.MODULE)\npublic interface ConfigInitializer {\n\n    default void initReferConfig(ReferenceConfig referenceConfig) {}\n\n    default void initServiceConfig(ServiceConfig serviceConfig) {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * 2019/12/30\n * it will be instead of CommonConfigPostProcessor\n */\n@SPI(scope = ExtensionScope.MODULE)\npublic interface ConfigPostProcessor {\n\n    default void postProcessReferConfig(ReferenceConfig referenceConfig) {}\n\n    default void postProcessServiceConfig(ServiceConfig serviceConfig) {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.deploy.ApplicationDeployer;\nimport org.apache.dubbo.common.deploy.ModuleDeployer;\nimport org.apache.dubbo.config.deploy.DefaultApplicationDeployer;\nimport org.apache.dubbo.config.deploy.DefaultModuleDeployer;\nimport org.apache.dubbo.config.deploy.FrameworkModelCleaner;\nimport org.apache.dubbo.config.utils.DefaultConfigValidator;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\npublic class ConfigScopeModelInitializer implements ScopeModelInitializer {\n\n    @Override\n    public void initializeFrameworkModel(FrameworkModel frameworkModel) {\n        frameworkModel.addDestroyListener(new FrameworkModelCleaner());\n    }\n\n    @Override\n    public void initializeApplicationModel(ApplicationModel applicationModel) {\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        beanFactory.registerBean(DefaultConfigValidator.class);\n        // applicationDeployer\n        ApplicationDeployer applicationDeployer = beanFactory.registerBean(DefaultApplicationDeployer.class);\n        applicationModel.setDeployer(applicationDeployer);\n    }\n\n    @Override\n    public void initializeModuleModel(ModuleModel moduleModel) {\n        ScopeBeanFactory beanFactory = moduleModel.getBeanFactory();\n        // moduleDeployer\n        ModuleDeployer moduleDeployer = beanFactory.registerBean(DefaultModuleDeployer.class);\n        moduleModel.setDeployer(moduleDeployer);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.rpc.GracefulShutdown;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_SHUTDOWN_HOOK;\n\n/**\n * The shutdown hook thread to do the cleanup stuff.\n * This is a singleton in order to ensure there is only one shutdown hook registered.\n * Because {@link ApplicationShutdownHooks} use {@link java.util.IdentityHashMap}\n * to store the shutdown hooks.\n */\npublic class DubboShutdownHook extends Thread {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DubboShutdownHook.class);\n\n    private final ApplicationModel applicationModel;\n\n    /**\n     * Has it already been registered or not?\n     */\n    private final AtomicBoolean registered = new AtomicBoolean(false);\n\n    /**\n     * Has it already been destroyed or not?\n     */\n    private final AtomicBoolean destroyed = new AtomicBoolean(false);\n\n    /**\n     * Whether ignore listen on shutdown hook?\n     */\n    private final boolean ignoreListenShutdownHook;\n\n    public DubboShutdownHook(ApplicationModel applicationModel) {\n        super(\"DubboShutdownHook\");\n        this.applicationModel = applicationModel;\n        Assert.notNull(this.applicationModel, \"ApplicationModel is null\");\n        ignoreListenShutdownHook = Boolean.parseBoolean(\n                ConfigurationUtils.getProperty(applicationModel, CommonConstants.IGNORE_LISTEN_SHUTDOWN_HOOK));\n        if (ignoreListenShutdownHook) {\n            logger.info(\n                    CommonConstants.IGNORE_LISTEN_SHUTDOWN_HOOK + \" configured, will ignore add shutdown hook to jvm.\");\n        }\n    }\n\n    @Override\n    public void run() {\n\n        if (!ignoreListenShutdownHook && destroyed.compareAndSet(false, true)) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"Run shutdown hook now.\");\n            }\n\n            doDestroy();\n        }\n    }\n\n    private void doDestroy() {\n        int timeout = ConfigurationUtils.getServerShutdownTimeout(applicationModel);\n        ConfigurationUtils.setExpectedShutdownTime(System.currentTimeMillis() + timeout);\n\n        // send readonly for shutdown hook\n        List<GracefulShutdown> gracefulShutdowns =\n                GracefulShutdown.getGracefulShutdowns(applicationModel.getFrameworkModel());\n        for (GracefulShutdown gracefulShutdown : gracefulShutdowns) {\n            gracefulShutdown.readonly();\n        }\n\n        boolean hasModuleBindSpring = false;\n        // check if any modules are bound to Spring\n        for (ModuleModel module : applicationModel.getModuleModels()) {\n            if (module.isLifeCycleManagedExternally()) {\n                hasModuleBindSpring = true;\n                break;\n            }\n        }\n        if (hasModuleBindSpring) {\n            if (timeout > 0) {\n                long start = System.currentTimeMillis();\n                /*\n                 To avoid shutdown conflicts between Dubbo and Spring,\n                 wait for the modules bound to Spring to be handled by Spring until timeout.\n                */\n                logger.info(\n                        \"Waiting for modules(\" + applicationModel.getDesc() + \") managed by Spring to be shutdown.\");\n                while (!applicationModel.isDestroyed()\n                        && hasModuleBindSpring\n                        && (System.currentTimeMillis() - start) < timeout) {\n                    try {\n                        TimeUnit.MILLISECONDS.sleep(10);\n                        hasModuleBindSpring = false;\n                        if (!applicationModel.isDestroyed()) {\n                            for (ModuleModel module : applicationModel.getModuleModels()) {\n                                if (module.isLifeCycleManagedExternally()) {\n                                    hasModuleBindSpring = true;\n                                    break;\n                                }\n                            }\n                        }\n                    } catch (InterruptedException e) {\n                        logger.warn(LoggerCodeConstants.INTERNAL_INTERRUPTED, \"\", \"\", e.getMessage(), e);\n                        Thread.currentThread().interrupt();\n                    }\n                }\n                if (!applicationModel.isDestroyed()) {\n                    long usage = System.currentTimeMillis() - start;\n                    logger.info(\"Dubbo wait for application(\" + applicationModel.getDesc()\n                            + \") managed by Spring to be shutdown failed, \" + \"time usage: \" + usage + \"ms\");\n                }\n            }\n        }\n        if (!applicationModel.isDestroyed()) {\n            logger.info(\"Dubbo shutdown hooks execute now. \" + applicationModel.getDesc());\n            applicationModel.destroy();\n        }\n    }\n\n    /**\n     * Register the ShutdownHook\n     */\n    public void register() {\n        if (!ignoreListenShutdownHook && registered.compareAndSet(false, true)) {\n            try {\n                Runtime.getRuntime().addShutdownHook(this);\n            } catch (IllegalStateException e) {\n                logger.warn(CONFIG_FAILED_SHUTDOWN_HOOK, \"\", \"\", \"register shutdown hook failed: \" + e.getMessage(), e);\n            } catch (Exception e) {\n                logger.warn(CONFIG_FAILED_SHUTDOWN_HOOK, \"\", \"\", \"register shutdown hook failed: \" + e.getMessage(), e);\n            }\n        }\n    }\n\n    /**\n     * Unregister the ShutdownHook\n     */\n    public void unregister() {\n        if (!ignoreListenShutdownHook && registered.compareAndSet(true, false)) {\n            if (this.isAlive()) {\n                // DubboShutdownHook thread is running\n                return;\n            }\n            try {\n                Runtime.getRuntime().removeShutdownHook(this);\n            } catch (IllegalStateException e) {\n                logger.warn(\n                        CONFIG_FAILED_SHUTDOWN_HOOK, \"\", \"\", \"unregister shutdown hook failed: \" + e.getMessage(), e);\n            } catch (Exception e) {\n                logger.warn(\n                        CONFIG_FAILED_SHUTDOWN_HOOK, \"\", \"\", \"unregister shutdown hook failed: \" + e.getMessage(), e);\n            }\n        }\n    }\n\n    public boolean getRegistered() {\n        return registered.get();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.config.utils.ConfigValidationUtils;\nimport org.apache.dubbo.registry.client.metadata.MetadataUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.cluster.support.ClusterUtils;\nimport org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster;\nimport org.apache.dubbo.rpc.model.AsyncMethodInfo;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.DubboStub;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;\nimport org.apache.dubbo.rpc.service.GenericService;\nimport org.apache.dubbo.rpc.stub.StubSuppliers;\nimport org.apache.dubbo.rpc.support.ProtocolUtils;\n\nimport java.beans.Transient;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_DOMAIN;\nimport static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR_CHAR;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CLUSTER_DOMAIN;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_MESH_PORT;\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_IP_TO_REGISTRY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.MESH_ENABLE;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.POD_NAMESPACE;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROXY_CLASS_REF;\nimport static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SEMICOLON_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SVC;\nimport static org.apache.dubbo.common.constants.CommonConstants.TRIPLE;\nimport static org.apache.dubbo.common.constants.CommonConstants.UNLOAD_CLUSTER_RELATED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_NO_VALID_PROVIDER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_DESTROY_INVOKER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_LOAD_ENV_VARIABLE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_NO_METHOD_FOUND;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_PROPERTY_CONFLICT;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDED_BY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY;\nimport static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost;\nimport static org.apache.dubbo.common.utils.StringUtils.splitToSet;\nimport static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL;\nimport static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;\nimport static org.apache.dubbo.rpc.Constants.GENERIC_KEY;\nimport static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;\nimport static org.apache.dubbo.rpc.cluster.Constants.PEER_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\n\n/**\n * Please avoid using this class for any new application,\n * use {@link ReferenceConfigBase} instead.\n */\npublic class ReferenceConfig<T> extends ReferenceConfigBase<T> {\n\n    public static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ReferenceConfig.class);\n\n    /**\n     * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios.\n     * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}.\n     * For example:\n     *\n     * <li>when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample,\n     * then the protocol is <b>RegistryProtocol</b></li>\n     *\n     * <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then\n     * the protocol is <b>DubboProtocol</b></li>\n     * <p>\n     * Actually，when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wrap three\n     * layers, and eventually will get a <b>ProtocolSerializationWrapper</b> or <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>\n     */\n    private Protocol protocolSPI;\n\n    /**\n     * A {@link ProxyFactory} implementation that will generate a reference service's proxy,the JavassistProxyFactory is\n     * its default implementation\n     */\n    private ProxyFactory proxyFactory;\n\n    private ConsumerModel consumerModel;\n\n    /**\n     * The interface proxy reference\n     */\n    private transient volatile T ref;\n\n    /**\n     * The invoker of the reference service\n     */\n    private transient volatile Invoker<?> invoker;\n\n    /**\n     * The flag whether the ReferenceConfig has been initialized\n     */\n    private transient volatile boolean initialized;\n\n    /**\n     * whether this ReferenceConfig has been destroyed\n     */\n    private transient volatile boolean destroyed;\n\n    /**\n     * The service names that the Dubbo interface subscribed.\n     *\n     * @since 2.7.8\n     */\n    private String services;\n\n    protected final transient ReentrantLock lock = new ReentrantLock();\n\n    public ReferenceConfig() {\n        super();\n    }\n\n    public ReferenceConfig(ModuleModel moduleModel) {\n        super(moduleModel);\n    }\n\n    public ReferenceConfig(Reference reference) {\n        super(reference);\n    }\n\n    public ReferenceConfig(ModuleModel moduleModel, Reference reference) {\n        super(moduleModel, reference);\n    }\n\n    @Override\n    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {\n        super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);\n\n        protocolSPI = this.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n        proxyFactory = this.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n    }\n\n    /**\n     * Get a string presenting the service names that the Dubbo interface subscribed.\n     * If it is a multiple-values, the content will be a comma-delimited String.\n     *\n     * @return non-null\n     * @see RegistryConstants#SUBSCRIBED_SERVICE_NAMES_KEY\n     * @since 2.7.8\n     */\n    @Deprecated\n    @Parameter(key = SUBSCRIBED_SERVICE_NAMES_KEY)\n    public String getServices() {\n        return services;\n    }\n\n    /**\n     * It's an alias method for {@link #getServices()}, but the more convenient.\n     *\n     * @return the String {@link List} presenting the Dubbo interface subscribed\n     * @since 2.7.8\n     */\n    @Deprecated\n    @Parameter(excluded = true)\n    public Set<String> getSubscribedServices() {\n        return splitToSet(getServices(), COMMA_SEPARATOR_CHAR);\n    }\n\n    /**\n     * Set the service names that the Dubbo interface subscribed.\n     *\n     * @param services If it is a multiple-values, the content will be a comma-delimited String.\n     * @since 2.7.8\n     */\n    public void setServices(String services) {\n        this.services = services;\n    }\n\n    @Override\n    @Transient\n    public T get(boolean check) {\n        if (destroyed) {\n            throw new IllegalStateException(\"The invoker of ReferenceConfig(\" + url + \") has already destroyed!\");\n        }\n\n        if (ref == null) {\n            if (getScopeModel().isLifeCycleManagedExternally()) {\n                // prepare model for reference\n                getScopeModel().getDeployer().prepare();\n            } else {\n                // ensure start module, compatible with old api usage\n                getScopeModel().getDeployer().start();\n            }\n\n            init(check);\n        }\n\n        return ref;\n    }\n\n    @Override\n    public void checkOrDestroy(long timeout) {\n        if (!initialized || ref == null) {\n            return;\n        }\n        try {\n            checkInvokerAvailable(timeout);\n        } catch (Throwable t) {\n            logAndCleanup(t);\n            throw t;\n        }\n    }\n\n    private void logAndCleanup(Throwable t) {\n        try {\n            if (invoker != null) {\n                invoker.destroy();\n            }\n        } catch (Throwable destroy) {\n            logger.warn(\n                    CONFIG_FAILED_DESTROY_INVOKER,\n                    \"\",\n                    \"\",\n                    \"Unexpected error occurred when destroy invoker of ReferenceConfig(\" + url + \").\",\n                    t);\n        }\n        if (consumerModel != null) {\n            ModuleServiceRepository repository = getScopeModel().getServiceRepository();\n            repository.unregisterConsumer(consumerModel);\n        }\n        initialized = false;\n        invoker = null;\n        ref = null;\n        consumerModel = null;\n        serviceMetadata.setTarget(null);\n        serviceMetadata.getAttributeMap().remove(PROXY_CLASS_REF);\n\n        // Thrown by checkInvokerAvailable().\n        if (t.getClass() == IllegalStateException.class\n                && t.getMessage().contains(\"No provider available for the service\")) {\n\n            // 2-2 - No provider available.\n            logger.error(CLUSTER_NO_VALID_PROVIDER, \"server crashed\", \"\", \"No provider available.\", t);\n        }\n    }\n\n    @Override\n    public void destroy() {\n        lock.lock();\n        try {\n            super.destroy();\n            if (destroyed) {\n                return;\n            }\n            destroyed = true;\n            try {\n                if (invoker != null) {\n                    invoker.destroy();\n                }\n            } catch (Throwable t) {\n                logger.warn(\n                        CONFIG_FAILED_DESTROY_INVOKER,\n                        \"\",\n                        \"\",\n                        \"Unexpected error occurred when destroy invoker of ReferenceConfig(\" + url + \").\",\n                        t);\n            }\n            invoker = null;\n            ref = null;\n            if (consumerModel != null) {\n                ModuleServiceRepository repository = getScopeModel().getServiceRepository();\n                repository.unregisterConsumer(consumerModel);\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    protected void init() {\n        init(true);\n    }\n\n    protected void init(boolean check) {\n        lock.lock();\n        try {\n            if (initialized && ref != null) {\n                return;\n            }\n            try {\n                if (!this.isRefreshed()) {\n                    this.refresh();\n                }\n                // auto detect proxy type\n                String proxyType = getProxy();\n                if (StringUtils.isBlank(proxyType) && DubboStub.class.isAssignableFrom(interfaceClass)) {\n                    setProxy(CommonConstants.NATIVE_STUB);\n                }\n\n                // init serviceMetadata\n                initServiceMetadata(consumer);\n\n                serviceMetadata.setServiceType(getServiceInterfaceClass());\n                // TODO, uncomment this line once service key is unified\n                serviceMetadata.generateServiceKey();\n\n                Map<String, String> referenceParameters = appendConfig();\n\n                ModuleServiceRepository repository = getScopeModel().getServiceRepository();\n                ServiceDescriptor serviceDescriptor;\n                if (CommonConstants.NATIVE_STUB.equals(getProxy())) {\n                    serviceDescriptor = StubSuppliers.getServiceDescriptor(interfaceName);\n                    repository.registerService(serviceDescriptor);\n                    setInterface(serviceDescriptor.getInterfaceName());\n                } else {\n                    serviceDescriptor = repository.registerService(interfaceClass);\n                }\n                consumerModel = new ConsumerModel(\n                        serviceMetadata.getServiceKey(),\n                        proxy,\n                        serviceDescriptor,\n                        getScopeModel(),\n                        serviceMetadata,\n                        createAsyncMethodInfo(),\n                        interfaceClassLoader);\n\n                // Compatible with dependencies on ServiceModel#getReferenceConfig() , and will be removed in a future\n                // version.\n                consumerModel.setConfig(this);\n\n                repository.registerConsumer(consumerModel);\n\n                serviceMetadata.getAttachments().putAll(referenceParameters);\n\n                ref = createProxy(referenceParameters);\n\n                serviceMetadata.setTarget(ref);\n                serviceMetadata.addAttribute(PROXY_CLASS_REF, ref);\n\n                consumerModel.setDestroyRunner(getDestroyRunner());\n                consumerModel.setProxyObject(ref);\n                consumerModel.initMethodModels();\n\n                if (check) {\n                    checkInvokerAvailable(0);\n                }\n            } catch (Throwable t) {\n                logAndCleanup(t);\n\n                throw t;\n            }\n            initialized = true;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    /**\n     * convert and aggregate async method info\n     *\n     * @return Map<String, AsyncMethodInfo>\n     */\n    private Map<String, AsyncMethodInfo> createAsyncMethodInfo() {\n        Map<String, AsyncMethodInfo> attributes = null;\n        if (CollectionUtils.isNotEmpty(getMethods())) {\n            attributes = new HashMap<>(16);\n            for (MethodConfig methodConfig : getMethods()) {\n                AsyncMethodInfo asyncMethodInfo = methodConfig.convertMethodConfig2AsyncInfo();\n                if (asyncMethodInfo != null) {\n                    attributes.put(methodConfig.getName(), asyncMethodInfo);\n                }\n            }\n        }\n\n        return attributes;\n    }\n\n    /**\n     * Append all configuration required for service reference.\n     *\n     * @return reference parameters\n     */\n    private Map<String, String> appendConfig() {\n        Map<String, String> map = new HashMap<>(16);\n\n        map.put(INTERFACE_KEY, interfaceName);\n        map.put(SIDE_KEY, CONSUMER_SIDE);\n\n        ReferenceConfigBase.appendRuntimeParameters(map);\n\n        if (!ProtocolUtils.isGeneric(generic)) {\n            String revision = Version.getVersion(interfaceClass, version);\n            if (StringUtils.isNotEmpty(revision)) {\n                map.put(REVISION_KEY, revision);\n            }\n\n            String[] methods = methods(interfaceClass);\n            if (methods.length == 0) {\n                logger.warn(\n                        CONFIG_NO_METHOD_FOUND,\n                        \"\",\n                        \"\",\n                        \"No method found in service interface: \" + interfaceClass.getName());\n                map.put(METHODS_KEY, ANY_VALUE);\n            } else {\n                map.put(METHODS_KEY, StringUtils.join(new TreeSet<>(Arrays.asList(methods)), COMMA_SEPARATOR));\n            }\n        }\n\n        AbstractConfig.appendParameters(map, getApplication());\n        AbstractConfig.appendParameters(map, getModule());\n        AbstractConfig.appendParameters(map, consumer);\n        AbstractConfig.appendParameters(map, this);\n\n        String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);\n        if (StringUtils.isEmpty(hostToRegistry)) {\n            hostToRegistry = NetUtils.getLocalHost();\n        } else if (isInvalidLocalHost(hostToRegistry)) {\n            throw new IllegalArgumentException(\"Specified invalid registry ip from property:\" + DUBBO_IP_TO_REGISTRY\n                    + \", value:\" + hostToRegistry);\n        }\n\n        map.put(REGISTER_IP_KEY, hostToRegistry);\n\n        if (CollectionUtils.isNotEmpty(getMethods())) {\n            for (MethodConfig methodConfig : getMethods()) {\n                AbstractConfig.appendParameters(map, methodConfig, methodConfig.getName());\n                String retryKey = methodConfig.getName() + \".retry\";\n                if (map.containsKey(retryKey)) {\n                    String retryValue = map.remove(retryKey);\n                    if (\"false\".equals(retryValue)) {\n                        map.put(methodConfig.getName() + \".retries\", \"0\");\n                    }\n                }\n            }\n        }\n\n        return map;\n    }\n\n    @SuppressWarnings({\"unchecked\"})\n    private T createProxy(Map<String, String> referenceParameters) {\n        urls.clear();\n\n        meshModeHandleUrl(referenceParameters);\n\n        if (StringUtils.isNotEmpty(url)) {\n            // user specified URL, could be peer-to-peer address, or register center's address.\n            parseUrl(referenceParameters);\n        } else {\n            // if protocols not in jvm checkRegistry\n            aggregateUrlFromRegistry(referenceParameters);\n        }\n        createInvoker();\n\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Referred dubbo service: [\" + referenceParameters.get(INTERFACE_KEY) + \"].\"\n                    + (ProtocolUtils.isGeneric(referenceParameters.get(GENERIC_KEY))\n                            ? \" it's GenericService reference\"\n                            : \" it's not GenericService reference\"));\n        }\n\n        URL consumerUrl = new ServiceConfigURL(\n                CONSUMER_PROTOCOL,\n                referenceParameters.get(REGISTER_IP_KEY),\n                0,\n                referenceParameters.get(INTERFACE_KEY),\n                referenceParameters);\n        consumerUrl = consumerUrl.setScopeModel(getScopeModel());\n        consumerUrl = consumerUrl.setServiceModel(consumerModel);\n        MetadataUtils.publishServiceDefinition(consumerUrl, consumerModel.getServiceModel(), getApplicationModel());\n\n        // create service proxy\n        return (T) proxyFactory.getProxy(invoker, ProtocolUtils.isGeneric(generic));\n    }\n\n    /**\n     * if enable mesh mode, handle url.\n     *\n     * @param referenceParameters referenceParameters\n     */\n    private void meshModeHandleUrl(Map<String, String> referenceParameters) {\n        if (!checkMeshConfig(referenceParameters)) {\n            return;\n        }\n        if (StringUtils.isNotEmpty(url)) {\n            // user specified URL, could be peer-to-peer address, or register center's address.\n            if (logger.isInfoEnabled()) {\n                logger.info(\"The url already exists, mesh no longer processes url: \" + url);\n            }\n            return;\n        }\n\n        // get provider namespace if (@DubboReference, <reference provider-namespace=\"xx\"/>) present\n        String podNamespace = referenceParameters.get(RegistryConstants.PROVIDER_NAMESPACE);\n\n        // get pod namespace from env if annotation not present the provider namespace\n        if (StringUtils.isEmpty(podNamespace)) {\n            if (StringUtils.isEmpty(System.getenv(POD_NAMESPACE))) {\n                if (logger.isWarnEnabled()) {\n                    logger.warn(\n                            CONFIG_FAILED_LOAD_ENV_VARIABLE,\n                            \"\",\n                            \"\",\n                            \"Can not get env variable: POD_NAMESPACE, it may not be running in the K8S environment , \"\n                                    + \"finally use 'default' replace.\");\n                }\n                podNamespace = \"default\";\n            } else {\n                podNamespace = System.getenv(POD_NAMESPACE);\n            }\n        }\n\n        // In mesh mode, providedBy equals K8S Service name.\n        String providedBy = referenceParameters.get(PROVIDED_BY);\n        // cluster_domain default is 'cluster.local',generally unchanged.\n        String clusterDomain =\n                Optional.ofNullable(System.getenv(CLUSTER_DOMAIN)).orElse(DEFAULT_CLUSTER_DOMAIN);\n        // By VirtualService and DestinationRule, envoy will generate a new route rule,such as\n        // 'demo.default.svc.cluster.local:80',the default port is 80.\n        Integer meshPort = Optional.ofNullable(getProviderPort()).orElse(DEFAULT_MESH_PORT);\n        // DubboReference default is -1, process it.\n        meshPort = meshPort > -1 ? meshPort : DEFAULT_MESH_PORT;\n        // get mesh url.\n        url = TRIPLE + \"://\" + providedBy + \".\" + podNamespace + SVC + clusterDomain + \":\" + meshPort;\n    }\n\n    /**\n     * check if mesh config is correct\n     *\n     * @param referenceParameters referenceParameters\n     * @return mesh config is correct\n     */\n    private boolean checkMeshConfig(Map<String, String> referenceParameters) {\n        if (!\"true\".equals(referenceParameters.getOrDefault(MESH_ENABLE, \"false\"))) {\n            // In mesh mode, unloadClusterRelated can only be false.\n            referenceParameters.put(UNLOAD_CLUSTER_RELATED, \"false\");\n            return false;\n        }\n\n        getScopeModel()\n                .getConfigManager()\n                .getProtocol(TRIPLE)\n                .orElseThrow(() -> new IllegalStateException(\"In mesh mode, a triple protocol must be specified\"));\n\n        String providedBy = referenceParameters.get(PROVIDED_BY);\n        if (StringUtils.isEmpty(providedBy)) {\n            throw new IllegalStateException(\"In mesh mode, the providedBy of ReferenceConfig is must be set\");\n        }\n\n        return true;\n    }\n\n    /**\n     * Parse the directly configured url.\n     */\n    private void parseUrl(Map<String, String> referenceParameters) {\n        String[] us = SEMICOLON_SPLIT_PATTERN.split(url);\n        if (ArrayUtils.isNotEmpty(us)) {\n            for (String u : us) {\n                URL url = URL.valueOf(u);\n                if (StringUtils.isEmpty(url.getPath())) {\n                    url = url.setPath(interfaceName);\n                }\n                url = url.setScopeModel(getScopeModel());\n                url = url.setServiceModel(consumerModel);\n                if (UrlUtils.isRegistry(url)) {\n                    urls.add(url.putAttribute(REFER_KEY, referenceParameters));\n                } else {\n                    URL peerUrl = getScopeModel()\n                            .getApplicationModel()\n                            .getBeanFactory()\n                            .getBean(ClusterUtils.class)\n                            .mergeUrl(url, referenceParameters);\n                    peerUrl = peerUrl.putAttribute(PEER_KEY, true);\n                    urls.add(peerUrl);\n                }\n            }\n        }\n    }\n\n    /**\n     * Get URLs from the registry and aggregate them.\n     */\n    private void aggregateUrlFromRegistry(Map<String, String> referenceParameters) {\n        checkRegistry();\n        List<URL> us = ConfigValidationUtils.loadRegistries(this, false);\n        if (CollectionUtils.isNotEmpty(us)) {\n            for (URL u : us) {\n                URL monitorUrl = ConfigValidationUtils.loadMonitor(this, u);\n                if (monitorUrl != null) {\n                    u = u.putAttribute(MONITOR_KEY, monitorUrl);\n                }\n                u = u.setScopeModel(getScopeModel());\n                u = u.setServiceModel(consumerModel);\n                if (isInjvm() != null && isInjvm()) {\n                    u = u.addParameter(LOCAL_PROTOCOL, true);\n                }\n                urls.add(u.putAttribute(REFER_KEY, referenceParameters));\n            }\n        }\n        if (urls.isEmpty() && shouldJvmRefer(referenceParameters)) {\n            URL injvmUrl = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName())\n                    .addParameters(referenceParameters);\n            injvmUrl = injvmUrl.setScopeModel(getScopeModel());\n            injvmUrl = injvmUrl.setServiceModel(consumerModel);\n            urls.add(injvmUrl.putAttribute(REFER_KEY, referenceParameters));\n        }\n        if (urls.isEmpty()) {\n            throw new IllegalStateException(\"No such any registry to reference \" + interfaceName + \" on the consumer \"\n                    + NetUtils.getLocalHost() + \" use dubbo version \"\n                    + Version.getVersion()\n                    + \", please config <dubbo:registry address=\\\"...\\\" /> to your spring config.\");\n        }\n    }\n\n    /**\n     * \\create a reference invoker\n     */\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private void createInvoker() {\n        if (urls.size() == 1) {\n            URL curUrl = urls.get(0);\n            invoker = protocolSPI.refer(interfaceClass, curUrl);\n            // registry url, mesh-enable and unloadClusterRelated is true, not need Cluster.\n            if (!UrlUtils.isRegistry(curUrl) && !curUrl.getParameter(UNLOAD_CLUSTER_RELATED, false)) {\n                List<Invoker<?>> invokers = new ArrayList<>();\n                invokers.add(invoker);\n                invoker = Cluster.getCluster(getScopeModel(), Cluster.DEFAULT)\n                        .join(new StaticDirectory(curUrl, invokers), true);\n            }\n        } else {\n            List<Invoker<?>> invokers = new ArrayList<>();\n            URL registryUrl = null;\n            for (URL url : urls) {\n                // For multi-registry scenarios, it is not checked whether each referInvoker is available.\n                // Because this invoker may become available later.\n                invokers.add(protocolSPI.refer(interfaceClass, url));\n\n                if (UrlUtils.isRegistry(url)) {\n                    // use last registry url\n                    registryUrl = url;\n                }\n            }\n\n            if (registryUrl != null) {\n                // registry url is available\n                // for multi-subscription scenario, use 'zone-aware' policy by default\n                String cluster = registryUrl.getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME);\n                // The invoker wrap sequence would be: ZoneAwareClusterInvoker(StaticDirectory) ->\n                // FailoverClusterInvoker\n                // (RegistryDirectory, routing happens here) -> Invoker\n                invoker = Cluster.getCluster(registryUrl.getScopeModel(), cluster, false)\n                        .join(new StaticDirectory(registryUrl, invokers), false);\n            } else {\n                // not a registry url, must be direct invoke.\n                if (CollectionUtils.isEmpty(invokers)) {\n                    throw new IllegalArgumentException(\"invokers == null\");\n                }\n                URL curUrl = invokers.get(0).getUrl();\n                String cluster = curUrl.getParameter(CLUSTER_KEY, Cluster.DEFAULT);\n                invoker =\n                        Cluster.getCluster(getScopeModel(), cluster).join(new StaticDirectory(curUrl, invokers), true);\n            }\n        }\n    }\n\n    private void checkInvokerAvailable(long timeout) throws IllegalStateException {\n        if (!shouldCheck()) {\n            return;\n        }\n        boolean available = invoker.isAvailable();\n        if (available) {\n            return;\n        }\n\n        long startTime = System.currentTimeMillis();\n        long checkDeadline = startTime + timeout;\n        do {\n            try {\n                Thread.sleep(100);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                break;\n            }\n            available = invoker.isAvailable();\n        } while (!available && checkDeadline > System.currentTimeMillis());\n        logger.warn(\n                LoggerCodeConstants.REGISTRY_EMPTY_ADDRESS,\n                \"\",\n                \"\",\n                \"Check reference of [\" + getUniqueServiceName() + \"] failed very beginning. \" + \"After \"\n                        + (System.currentTimeMillis() - startTime) + \"ms reties, finally \"\n                        + (available ? \"succeed\" : \"failed\")\n                        + \".\");\n        if (!available) {\n            // 2-2 - No provider available.\n\n            IllegalStateException illegalStateException =\n                    new IllegalStateException(\"Failed to check the status of the service \"\n                            + interfaceName\n                            + \". No provider available for the service \"\n                            + (group == null ? \"\" : group + \"/\")\n                            + interfaceName + (version == null ? \"\" : \":\" + version)\n                            + \" from the url \"\n                            + invoker.getUrl()\n                            + \" to the consumer \"\n                            + NetUtils.getLocalHost() + \" use dubbo version \" + Version.getVersion());\n\n            logger.error(\n                    CLUSTER_NO_VALID_PROVIDER,\n                    \"provider not started\",\n                    \"\",\n                    \"No provider available.\",\n                    illegalStateException);\n\n            throw illegalStateException;\n        }\n    }\n\n    /**\n     * This method should be called right after the creation of this class's instance, before any property in other config modules is used.\n     * Check each config modules are created properly and override their properties if necessary.\n     */\n    protected void checkAndUpdateSubConfigs() {\n        if (StringUtils.isEmpty(interfaceName)) {\n            throw new IllegalStateException(\"<dubbo:reference interface=\\\"\\\" /> interface not allow null!\");\n        }\n\n        // get consumer's global configuration\n        completeCompoundConfigs();\n\n        // init some null configuration.\n        List<ConfigInitializer> configInitializers = this.getExtensionLoader(ConfigInitializer.class)\n                .getActivateExtension(URL.valueOf(\"configInitializer://\"), (String[]) null);\n        configInitializers.forEach(e -> e.initReferConfig(this));\n\n        if (getGeneric() == null && getConsumer() != null) {\n            setGeneric(getConsumer().getGeneric());\n        }\n        if (ProtocolUtils.isGeneric(generic)) {\n            if (interfaceClass != null && !interfaceClass.equals(GenericService.class)) {\n                logger.warn(\n                        CONFIG_PROPERTY_CONFLICT,\n                        \"\",\n                        \"\",\n                        String.format(\n                                \"Found conflicting attributes for interface type: [interfaceClass=%s] and [generic=%s], \"\n                                        + \"because the 'generic' attribute has higher priority than 'interfaceClass', so change 'interfaceClass' to '%s'. \"\n                                        + \"Note: it will make this reference bean as a candidate bean of type '%s' instead of '%s' when resolving dependency in Spring.\",\n                                interfaceClass.getName(),\n                                generic,\n                                GenericService.class.getName(),\n                                GenericService.class.getName(),\n                                interfaceClass.getName()));\n            }\n            interfaceClass = GenericService.class;\n        } else {\n            try {\n                if (getInterfaceClassLoader() != null\n                        && (interfaceClass == null || interfaceClass.getClassLoader() != getInterfaceClassLoader())) {\n                    interfaceClass = Class.forName(interfaceName, true, getInterfaceClassLoader());\n                } else if (interfaceClass == null) {\n                    interfaceClass = Class.forName(\n                            interfaceName, true, Thread.currentThread().getContextClassLoader());\n                }\n            } catch (ClassNotFoundException e) {\n                throw new IllegalStateException(e.getMessage(), e);\n            }\n        }\n\n        checkStubAndLocal(interfaceClass);\n\n        if (StringUtils.isEmpty(url)) {\n            checkRegistry();\n        }\n\n        resolveFile();\n        ConfigValidationUtils.validateReferenceConfig(this);\n        postProcessConfig();\n    }\n\n    @Override\n    protected void postProcessRefresh() {\n        super.postProcessRefresh();\n        checkAndUpdateSubConfigs();\n    }\n\n    protected void completeCompoundConfigs() {\n        super.completeCompoundConfigs(consumer);\n        if (consumer != null) {\n            if (StringUtils.isEmpty(registryIds)) {\n                setRegistryIds(consumer.getRegistryIds());\n            }\n        }\n    }\n\n    /**\n     * Figure out should refer the service in the same JVM from configurations. The default behavior is true\n     * 1. if injvm is specified, then use it\n     * 2. then if a url is specified, then assume it's a remote call\n     * 3. otherwise, check scope parameter\n     * 4. if scope is not specified but the target service is provided in the same JVM, then prefer to make the local\n     * call, which is the default behavior\n     */\n    protected boolean shouldJvmRefer(Map<String, String> map) {\n        boolean isJvmRefer;\n        if (isInjvm() == null) {\n            // if an url is specified, don't do local reference\n            if (StringUtils.isNotEmpty(url)) {\n                isJvmRefer = false;\n            } else {\n                // by default, reference local service if there is\n                URL tmpUrl = new ServiceConfigURL(\"temp\", \"localhost\", 0, map);\n                isJvmRefer = InjvmProtocol.getInjvmProtocol(getScopeModel()).isInjvmRefer(tmpUrl);\n            }\n        } else {\n            isJvmRefer = isInjvm();\n        }\n        return isJvmRefer;\n    }\n\n    private void postProcessConfig() {\n        List<ConfigPostProcessor> configPostProcessors = this.getExtensionLoader(ConfigPostProcessor.class)\n                .getActivateExtension(URL.valueOf(\"configPostProcessor://\"), (String[]) null);\n\n        HashSet<ConfigPostProcessor> allConfigPostProcessor = new HashSet<>();\n\n        // merge common and old config\n        allConfigPostProcessor.addAll(configPostProcessors);\n        allConfigPostProcessor.addAll(configPostProcessors);\n\n        allConfigPostProcessor.forEach(component -> component.postProcessReferConfig(this));\n    }\n\n    /**\n     * Return if ReferenceConfig has been initialized\n     * Note: Cannot use `isInitialized` as it may be treated as a Java Bean property\n     *\n     * @return initialized\n     */\n    @Transient\n    public boolean configInitialized() {\n        return initialized;\n    }\n\n    /**\n     * just for test\n     *\n     * @return\n     */\n    @Deprecated\n    @Transient\n    public Invoker<?> getInvoker() {\n        return invoker;\n    }\n\n    @Transient\n    public Runnable getDestroyRunner() {\n        return this::destroy;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.constants.RegisterTypeEnum;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.config.utils.ConfigValidationUtils;\nimport org.apache.dubbo.metadata.ServiceNameMapping;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.event.MetricsInitEvent;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.registry.client.metadata.MetadataUtils;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.ServerService;\nimport org.apache.dubbo.rpc.cluster.ConfiguratorFactory;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.beans.Transient;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.TreeSet;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_IP_TO_REGISTRY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_ISOLATION;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXPORTER_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXT_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.IS_EXTRA;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SERVICE_EXECUTOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.SERVICE_NAME_MAPPING_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_ISOLATED_EXECUTOR_CONFIGURATION_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_EXPORT_SERVICE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_NO_METHOD_FOUND;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_SERVER_DISCONNECTED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNEXPORT_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_USE_RANDOM_PORT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL;\nimport static org.apache.dubbo.common.utils.NetUtils.getAvailablePort;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHost;\nimport static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost;\nimport static org.apache.dubbo.common.utils.NetUtils.isInvalidPort;\nimport static org.apache.dubbo.config.Constants.DUBBO_PORT_TO_BIND;\nimport static org.apache.dubbo.config.Constants.DUBBO_PORT_TO_REGISTRY;\nimport static org.apache.dubbo.config.Constants.SCOPE_NONE;\nimport static org.apache.dubbo.registry.Constants.REGISTER_KEY;\nimport static org.apache.dubbo.remoting.Constants.BIND_IP_KEY;\nimport static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY;\nimport static org.apache.dubbo.remoting.Constants.IS_PU_SERVER_KEY;\nimport static org.apache.dubbo.rpc.Constants.GENERIC_KEY;\nimport static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;\nimport static org.apache.dubbo.rpc.Constants.PROXY_KEY;\nimport static org.apache.dubbo.rpc.Constants.SCOPE_KEY;\nimport static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;\nimport static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;\nimport static org.apache.dubbo.rpc.Constants.TOKEN_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;\nimport static org.apache.dubbo.rpc.support.ProtocolUtils.isGeneric;\n\npublic class ServiceConfig<T> extends ServiceConfigBase<T> {\n\n    private static final long serialVersionUID = 7868244018230856253L;\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ServiceConfig.class);\n\n    /**\n     * A random port cache, the different protocols who have no port specified have different random port\n     */\n    private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<>();\n\n    private Protocol protocolSPI;\n\n    /**\n     * A {@link ProxyFactory} implementation that will generate a exported service proxy,the JavassistProxyFactory is its\n     * default implementation\n     */\n    private ProxyFactory proxyFactory;\n\n    private ProviderModel providerModel;\n\n    /**\n     * Whether the provider has been exported\n     */\n    private transient volatile boolean exported;\n\n    /**\n     * The flag whether a service has unexported ,if the method unexported is invoked, the value is true\n     */\n    private transient volatile boolean unexported;\n\n    private transient volatile AtomicBoolean initialized = new AtomicBoolean(false);\n\n    /**\n     * The exported services\n     */\n    private final ConcurrentHashMap<RegisterTypeEnum, List<Exporter<?>>> exporters = new ConcurrentHashMap<>();\n\n    private final List<ServiceListener> serviceListeners = new ArrayList<>();\n\n    /**\n     * Whether to expose methods in this service as MCP tools, default value is false\n     */\n    private boolean mcpEnabled = false;\n\n    public ServiceConfig() {}\n\n    public ServiceConfig(ModuleModel moduleModel) {\n        super(moduleModel);\n    }\n\n    public ServiceConfig(Service service) {\n        super(service);\n    }\n\n    public ServiceConfig(ModuleModel moduleModel, Service service) {\n        super(moduleModel, service);\n    }\n\n    @Override\n    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {\n        super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);\n        protocolSPI = this.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n        proxyFactory = this.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n    }\n\n    @Override\n    @Parameter(excluded = true, attribute = false)\n    public boolean isExported() {\n        return exported;\n    }\n\n    @Override\n    @Parameter(excluded = true, attribute = false)\n    public boolean isUnexported() {\n        return unexported;\n    }\n\n    @Parameter(attribute = false, key = \"mcp.enabled\")\n    public boolean isMcpEnabled() {\n        return mcpEnabled;\n    }\n\n    public void setMcpEnabled(boolean mcpEnabled) {\n        this.mcpEnabled = mcpEnabled;\n    }\n\n    @Override\n    public synchronized void unexport() {\n        if (!exported) {\n            return;\n        }\n        if (unexported) {\n            return;\n        }\n        if (!exporters.isEmpty()) {\n            for (List<Exporter<?>> es : exporters.values()) {\n                for (Exporter<?> exporter : es) {\n                    try {\n                        exporter.unregister();\n                    } catch (Throwable t) {\n                        logger.warn(\n                                CONFIG_UNEXPORT_ERROR,\n                                \"\",\n                                \"\",\n                                \"Unexpected error occurred when unexport \" + exporter,\n                                t);\n                    }\n                }\n            }\n            waitForIdle();\n            for (List<Exporter<?>> es : exporters.values()) {\n                for (Exporter<?> exporter : es) {\n                    try {\n                        exporter.unexport();\n                    } catch (Throwable t) {\n                        logger.warn(\n                                CONFIG_UNEXPORT_ERROR,\n                                \"\",\n                                \"\",\n                                \"Unexpected error occurred when unexport \" + exporter,\n                                t);\n                    }\n                }\n            }\n            exporters.clear();\n        }\n        unexported = true;\n        onUnExported();\n        ModuleServiceRepository repository = getScopeModel().getServiceRepository();\n        repository.unregisterProvider(providerModel);\n    }\n\n    private void waitForIdle() {\n        int timeout = ConfigurationUtils.getServerShutdownTimeout(getScopeModel());\n\n        long idleTime = System.currentTimeMillis() - providerModel.getLastInvokeTime();\n\n        // 1. if service has idle for 10s(shutdown time), un-export directly\n        if (idleTime > timeout) {\n            return;\n        }\n\n        // 2. if service has idle for  more than 6.7s(2/3 of shutdown time), wait for the rest time, then un-export\n        // directly\n        int tick = timeout / 3;\n        if (timeout - idleTime < tick) {\n            logger.info(\"Service \" + getUniqueServiceName() + \" has idle for \" + idleTime + \" ms, wait for \"\n                    + (timeout - idleTime) + \" ms to un-export\");\n            try {\n                Thread.sleep(timeout - idleTime);\n            } catch (InterruptedException e) {\n                logger.warn(INTERNAL_ERROR, \"unknown error in registry module\", \"\", e.getMessage(), e);\n                Thread.currentThread().interrupt();\n            }\n            return;\n        }\n\n        // 3. Wait for 3.33s(1/3 of shutdown time), if service has idle for 3.33s(1/3 of shutdown time), un-export\n        // directly,\n        //    otherwise wait for the rest time until idle for 3.33s(1/3 of shutdown time). The max wait time is\n        // 10s(shutdown time).\n        idleTime = 0;\n        long startTime = System.currentTimeMillis();\n        while (idleTime < tick) {\n            // service idle time.\n            idleTime = System.currentTimeMillis() - Math.max(providerModel.getLastInvokeTime(), startTime);\n            if (idleTime >= tick || System.currentTimeMillis() - startTime > timeout) {\n                return;\n            }\n            // idle rest time or timeout rest time\n            long waitTime = Math.min(tick - idleTime, timeout + startTime - System.currentTimeMillis());\n            logger.info(\"Service \" + getUniqueServiceName() + \" has idle for \" + idleTime + \" ms, wait for \" + waitTime\n                    + \" ms to un-export\");\n            try {\n                Thread.sleep(waitTime);\n            } catch (InterruptedException e) {\n                logger.warn(INTERNAL_ERROR, \"unknown error in registry module\", \"\", e.getMessage(), e);\n                Thread.currentThread().interrupt();\n            }\n        }\n    }\n\n    /**\n     * for early init serviceMetadata\n     */\n    public void init() {\n        if (this.initialized.compareAndSet(false, true)) {\n            // load ServiceListeners from extension\n            ExtensionLoader<ServiceListener> extensionLoader = this.getExtensionLoader(ServiceListener.class);\n            this.serviceListeners.addAll(extensionLoader.getSupportedExtensionInstances());\n        }\n        initServiceMetadata(provider);\n        serviceMetadata.setServiceType(getInterfaceClass());\n        serviceMetadata.setTarget(getRef());\n        serviceMetadata.generateServiceKey();\n    }\n\n    @Override\n    public void export(RegisterTypeEnum registerType) {\n        if (this.exported) {\n            return;\n        }\n\n        if (getScopeModel().isLifeCycleManagedExternally()) {\n            // prepare model for reference\n            getScopeModel().getDeployer().prepare();\n        } else {\n            // ensure start module, compatible with old api usage\n            getScopeModel().getDeployer().start();\n        }\n\n        synchronized (this) {\n            if (this.exported) {\n                return;\n            }\n\n            if (!this.isRefreshed()) {\n                this.refresh();\n            }\n            if (this.shouldExport()) {\n                this.init();\n\n                if (shouldDelay()) {\n                    // should register if delay export\n                    doDelayExport();\n                } else if (Integer.valueOf(-1).equals(getDelay())\n                        && Boolean.parseBoolean(ConfigurationUtils.getProperty(\n                                getScopeModel(), CommonConstants.DubboProperty.DUBBO_MANUAL_REGISTER_KEY, \"false\"))) {\n                    // should not register by default\n                    doExport(RegisterTypeEnum.MANUAL_REGISTER);\n                } else {\n                    doExport(registerType);\n                }\n            }\n        }\n\n        getScopeModel().getDeployer().registerServiceInstance();\n    }\n\n    @Override\n    public void register(boolean byDeployer) {\n        if (!this.exported) {\n            return;\n        }\n\n        synchronized (this) {\n            if (!this.exported) {\n                return;\n            }\n\n            for (Exporter<?> exporter :\n                    exporters.getOrDefault(RegisterTypeEnum.AUTO_REGISTER, Collections.emptyList())) {\n                exporter.register();\n            }\n\n            if (byDeployer) {\n                for (Exporter<?> exporter :\n                        exporters.getOrDefault(RegisterTypeEnum.AUTO_REGISTER_BY_DEPLOYER, Collections.emptyList())) {\n                    exporter.register();\n                }\n            }\n        }\n    }\n\n    protected void doDelayExport() {\n        ExecutorRepository.getInstance(getScopeModel().getApplicationModel())\n                .getServiceExportExecutor()\n                .schedule(\n                        () -> {\n                            try {\n                                doExport(RegisterTypeEnum.AUTO_REGISTER);\n                            } catch (Exception e) {\n                                logger.error(\n                                        CONFIG_FAILED_EXPORT_SERVICE,\n                                        \"configuration server disconnected\",\n                                        \"\",\n                                        \"Failed to (async)export service config: \" + interfaceName,\n                                        e);\n                            }\n                        },\n                        getDelay(),\n                        TimeUnit.MILLISECONDS);\n    }\n\n    protected void exported() {\n        exported = true;\n        List<URL> exportedURLs = this.getExportedUrls();\n        exportedURLs.forEach(url -> {\n            if (url.getParameter(SERVICE_NAME_MAPPING_KEY, false)) {\n                ServiceNameMapping serviceNameMapping = ServiceNameMapping.getDefaultExtension(getScopeModel());\n                ScheduledExecutorService scheduledExecutor = getScopeModel()\n                        .getBeanFactory()\n                        .getBean(FrameworkExecutorRepository.class)\n                        .getSharedScheduledExecutor();\n                mapServiceName(url, serviceNameMapping, scheduledExecutor);\n            }\n        });\n\n        onExported();\n\n        if (hasRegistrySpecified()) {\n            getScopeModel().getDeployer().getApplicationDeployer().exportMetadataService();\n        }\n    }\n\n    public boolean hasRegistrySpecified() {\n        return CollectionUtils.isNotEmpty(this.getRegistries())\n                || CollectionUtils.isNotEmpty(getScopeModel()\n                        .getApplicationModel()\n                        .getApplicationConfigManager()\n                        .getRegistries());\n    }\n\n    protected void mapServiceName(\n            URL url, ServiceNameMapping serviceNameMapping, ScheduledExecutorService scheduledExecutor) {\n        if (!exported) {\n            return;\n        }\n        logger.info(\"[INSTANCE_REGISTER] [METADATA_REGISTER] Try to register interface application mapping for service \"\n                + url.getServiceKey());\n        boolean succeeded = false;\n        try {\n            succeeded = serviceNameMapping.map(url);\n            if (succeeded) {\n                logger.info(\n                        \"[INSTANCE_REGISTER][METADATA_REGISTER] Successfully registered interface application mapping for service \"\n                                + url.getServiceKey());\n            } else {\n                logger.error(\n                        CONFIG_SERVER_DISCONNECTED,\n                        \"configuration server disconnected\",\n                        \"\",\n                        \"[INSTANCE_REGISTER] [METADATA_REGISTER] Failed register interface application mapping for service \"\n                                + url.getServiceKey());\n            }\n        } catch (Exception e) {\n            logger.error(\n                    CONFIG_SERVER_DISCONNECTED,\n                    \"configuration server disconnected\",\n                    \"\",\n                    \"[INSTANCE_REGISTER] [METADATA_REGISTER] Failed register interface application mapping for service \"\n                            + url.getServiceKey(),\n                    e);\n        }\n        if (!succeeded && serviceNameMapping.hasValidMetadataCenter()) {\n            scheduleToMapping(scheduledExecutor, serviceNameMapping, url);\n        }\n    }\n\n    private void scheduleToMapping(\n            ScheduledExecutorService scheduledExecutor, ServiceNameMapping serviceNameMapping, URL url) {\n        Integer mappingRetryInterval = getApplication().getMappingRetryInterval();\n        scheduledExecutor.schedule(\n                () -> mapServiceName(url, serviceNameMapping, scheduledExecutor),\n                mappingRetryInterval == null ? 5000 : mappingRetryInterval,\n                TimeUnit.MILLISECONDS);\n    }\n\n    private void checkAndUpdateSubConfigs() {\n\n        // Use default configs defined explicitly with global scope\n        completeCompoundConfigs();\n\n        checkProtocol();\n\n        // init some null configuration.\n        List<ConfigInitializer> configInitializers = this.getExtensionLoader(ConfigInitializer.class)\n                .getActivateExtension(URL.valueOf(\"configInitializer://\", getScopeModel()), (String[]) null);\n        configInitializers.forEach(e -> e.initServiceConfig(this));\n\n        // if protocol is not injvm checkRegistry\n        if (!isOnlyInJvm()) {\n            checkRegistry();\n        }\n\n        if (StringUtils.isEmpty(interfaceName)) {\n            throw new IllegalStateException(\"<dubbo:service interface=\\\"\\\" /> interface not allow null!\");\n        }\n\n        if (ref instanceof GenericService) {\n            interfaceClass = GenericService.class;\n            if (StringUtils.isEmpty(generic)) {\n                generic = Boolean.TRUE.toString();\n            }\n        } else {\n            try {\n                if (getInterfaceClassLoader() != null) {\n                    interfaceClass = Class.forName(interfaceName, true, getInterfaceClassLoader());\n                } else {\n                    interfaceClass = Class.forName(\n                            interfaceName, true, Thread.currentThread().getContextClassLoader());\n                }\n            } catch (ClassNotFoundException e) {\n                throw new IllegalStateException(e.getMessage(), e);\n            }\n            checkRef();\n            generic = Boolean.FALSE.toString();\n        }\n        if (local != null) {\n            if (\"true\".equals(local)) {\n                local = interfaceName + \"Local\";\n            }\n            Class<?> localClass;\n            try {\n                localClass = ClassUtils.forNameWithThreadContextClassLoader(local);\n            } catch (ClassNotFoundException e) {\n                throw new IllegalStateException(e.getMessage(), e);\n            }\n            if (!interfaceClass.isAssignableFrom(localClass)) {\n                throw new IllegalStateException(\"The local implementation class \" + localClass.getName()\n                        + \" not implement interface \" + interfaceName);\n            }\n        }\n        if (stub != null) {\n            if (\"true\".equals(stub)) {\n                stub = interfaceName + \"Stub\";\n            }\n            Class<?> stubClass;\n            try {\n                stubClass = ClassUtils.forNameWithThreadContextClassLoader(stub);\n            } catch (ClassNotFoundException e) {\n                throw new IllegalStateException(e.getMessage(), e);\n            }\n            if (!interfaceClass.isAssignableFrom(stubClass)) {\n                throw new IllegalStateException(\"The stub implementation class \" + stubClass.getName()\n                        + \" not implement interface \" + interfaceName);\n            }\n        }\n        checkStubAndLocal(interfaceClass);\n        ConfigValidationUtils.validateServiceConfig(this);\n        postProcessConfig();\n    }\n\n    @Override\n    protected void postProcessRefresh() {\n        super.postProcessRefresh();\n        checkAndUpdateSubConfigs();\n    }\n\n    protected synchronized void doExport(RegisterTypeEnum registerType) {\n        if (unexported) {\n            throw new IllegalStateException(\"The service \" + interfaceClass.getName() + \" has already unexported!\");\n        }\n        if (exported) {\n            return;\n        }\n\n        if (StringUtils.isEmpty(path)) {\n            path = interfaceName;\n        }\n        doExportUrls(registerType);\n        exported();\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private void doExportUrls(RegisterTypeEnum registerType) {\n        ModuleServiceRepository repository = getScopeModel().getServiceRepository();\n        ServiceDescriptor serviceDescriptor;\n        final boolean serverService = ref instanceof ServerService;\n        if (serverService) {\n            serviceDescriptor = ((ServerService) ref).getServiceDescriptor();\n            if (!this.provider.getUseJavaPackageAsPath()) {\n                // for stub service, path always interface name or IDL package name\n                this.path = serviceDescriptor.getInterfaceName();\n            }\n            repository.registerService(serviceDescriptor);\n        } else {\n            serviceDescriptor = repository.registerService(getInterfaceClass());\n        }\n        providerModel = new ProviderModel(\n                serviceMetadata.getServiceKey(),\n                ref,\n                serviceDescriptor,\n                getScopeModel(),\n                serviceMetadata,\n                interfaceClassLoader);\n\n        // Compatible with dependencies on ServiceModel#getServiceConfig(), and will be removed in a future version\n        providerModel.setConfig(this);\n\n        providerModel.setDestroyRunner(getDestroyRunner());\n        repository.registerProvider(providerModel);\n\n        List<URL> registryURLs = !Boolean.FALSE.equals(isRegister())\n                ? ConfigValidationUtils.loadRegistries(this, true)\n                : Collections.emptyList();\n\n        for (ProtocolConfig protocolConfig : protocols) {\n            String pathKey = URL.buildKey(\n                    getContextPath(protocolConfig).map(p -> p + \"/\" + path).orElse(path), group, version);\n            // stub service will use generated service name\n            if (!serverService) {\n                // In case user specified path, register service one more time to map it to path.\n                repository.registerService(pathKey, interfaceClass);\n            }\n            doExportUrlsFor1Protocol(protocolConfig, registryURLs, registerType);\n        }\n\n        providerModel.setServiceUrls(urls);\n    }\n\n    private void doExportUrlsFor1Protocol(\n            ProtocolConfig protocolConfig, List<URL> registryURLs, RegisterTypeEnum registerType) {\n        Map<String, String> map = buildAttributes(protocolConfig);\n\n        // remove null key and null value\n        map.keySet().removeIf(key -> StringUtils.isEmpty(key) || StringUtils.isEmpty(map.get(key)));\n        // init serviceMetadata attachments\n        serviceMetadata.getAttachments().putAll(map);\n\n        URL url = buildUrl(protocolConfig, map);\n\n        processServiceExecutor(url);\n\n        if (CollectionUtils.isEmpty(registryURLs)) {\n            registerType = RegisterTypeEnum.NEVER_REGISTER;\n        }\n        exportUrl(url, registryURLs, registerType);\n\n        initServiceMethodMetrics(url);\n    }\n\n    private void initServiceMethodMetrics(URL url) {\n        String[] methods = Optional.ofNullable(url.getParameter(METHODS_KEY))\n                .map(i -> i.split(\",\"))\n                .orElse(new String[] {});\n        boolean serviceLevel = MethodMetric.isServiceLevel(application.getApplicationModel());\n        Arrays.stream(methods).forEach(method -> {\n            RpcInvocation invocation = new RpcInvocation(\n                    url.getServiceKey(),\n                    url.getServiceModel(),\n                    method,\n                    interfaceName,\n                    url.getProtocolServiceKey(),\n                    null,\n                    null,\n                    null,\n                    null,\n                    null,\n                    null);\n            MetricsEventBus.publish(\n                    MetricsInitEvent.toMetricsInitEvent(application.getApplicationModel(), invocation, serviceLevel));\n        });\n    }\n\n    private void processServiceExecutor(URL url) {\n        if (getExecutor() != null) {\n            String mode = application.getExecutorManagementMode();\n            if (!EXECUTOR_MANAGEMENT_MODE_ISOLATION.equals(mode)) {\n                logger.warn(\n                        COMMON_ISOLATED_EXECUTOR_CONFIGURATION_ERROR,\n                        \"\",\n                        \"\",\n                        \"The current executor management mode is \" + mode\n                                + \", the configured service executor cannot take effect unless the mode is configured as \"\n                                + EXECUTOR_MANAGEMENT_MODE_ISOLATION);\n                return;\n            }\n            /**\n             * Because executor is not a string type, it cannot be attached to the url parameter, so it is added to URL#attributes\n             * and obtained it in IsolationExecutorRepository#createExecutor method\n             */\n            providerModel.getServiceMetadata().addAttribute(SERVICE_EXECUTOR, getExecutor());\n            url.getAttributes().put(SERVICE_EXECUTOR, getExecutor());\n        }\n    }\n\n    private Map<String, String> buildAttributes(ProtocolConfig protocolConfig) {\n\n        Map<String, String> map = new HashMap<>();\n        map.put(SIDE_KEY, PROVIDER_SIDE);\n\n        // append params with basic configs,\n        ServiceConfig.appendRuntimeParameters(map);\n        AbstractConfig.appendParameters(map, getApplication());\n        AbstractConfig.appendParameters(map, getModule());\n        // remove 'default.' prefix for configs from ProviderConfig\n        // appendParameters(map, provider, Constants.DEFAULT_KEY);\n        AbstractConfig.appendParameters(map, provider);\n        AbstractConfig.appendParameters(map, protocolConfig);\n        AbstractConfig.appendParameters(map, this);\n\n        // append params with method configs,\n        if (CollectionUtils.isNotEmpty(getMethods())) {\n            getMethods().forEach(method -> appendParametersWithMethod(method, map));\n        }\n\n        if (isGeneric(generic)) {\n            map.put(GENERIC_KEY, generic);\n            map.put(METHODS_KEY, ANY_VALUE);\n        } else {\n            String revision = Version.getVersion(interfaceClass, version);\n            if (StringUtils.isNotEmpty(revision)) {\n                map.put(REVISION_KEY, revision);\n            }\n\n            String[] methods = methods(interfaceClass);\n            if (methods.length == 0) {\n                logger.warn(\n                        CONFIG_NO_METHOD_FOUND,\n                        \"\",\n                        \"\",\n                        \"No method found in service interface: \" + interfaceClass.getName());\n                map.put(METHODS_KEY, ANY_VALUE);\n            } else {\n                map.put(METHODS_KEY, StringUtils.join(new TreeSet<>(Arrays.asList(methods)), COMMA_SEPARATOR));\n            }\n        }\n\n        /**\n         * Here the token value configured by the provider is used to assign the value to ServiceConfig#token\n         */\n        if (ConfigUtils.isEmpty(token) && provider != null) {\n            token = provider.getToken();\n        }\n\n        if (!ConfigUtils.isEmpty(token)) {\n            if (ConfigUtils.isDefault(token)) {\n                map.put(TOKEN_KEY, UUID.randomUUID().toString());\n            } else {\n                map.put(TOKEN_KEY, token);\n            }\n        }\n\n        if (ref instanceof ServerService) {\n            map.put(PROXY_KEY, CommonConstants.NATIVE_STUB);\n        }\n\n        return map;\n    }\n\n    private void appendParametersWithMethod(MethodConfig method, Map<String, String> params) {\n        AbstractConfig.appendParameters(params, method, method.getName());\n\n        String retryKey = method.getName() + \".retry\";\n        if (params.containsKey(retryKey)) {\n            String retryValue = params.remove(retryKey);\n            if (\"false\".equals(retryValue)) {\n                params.put(method.getName() + \".retries\", \"0\");\n            }\n        }\n\n        List<ArgumentConfig> arguments = method.getArguments();\n        if (CollectionUtils.isNotEmpty(arguments)) {\n            Method matchedMethod = findMatchedMethod(method);\n            if (matchedMethod != null) {\n                arguments.forEach(argument -> appendArgumentConfig(argument, matchedMethod, params));\n            }\n        }\n    }\n\n    private Method findMatchedMethod(MethodConfig methodConfig) {\n        for (Method method : interfaceClass.getMethods()) {\n            if (method.getName().equals(methodConfig.getName())) {\n                return method;\n            }\n        }\n        return null;\n    }\n\n    private void appendArgumentConfig(ArgumentConfig argument, Method method, Map<String, String> params) {\n        if (StringUtils.isNotEmpty(argument.getType())) {\n            Integer index = findArgumentIndexIndexWithGivenType(argument, method);\n            AbstractConfig.appendParameters(params, argument, method.getName() + \".\" + index);\n        } else if (hasIndex(argument)) {\n            AbstractConfig.appendParameters(params, argument, method.getName() + \".\" + argument.getIndex());\n        } else {\n            throw new IllegalArgumentException(\n                    \"Argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>\");\n        }\n    }\n\n    private boolean hasIndex(ArgumentConfig argument) {\n        return argument.getIndex() != -1;\n    }\n\n    private boolean isTypeMatched(String type, Integer index, Class<?>[] argtypes) {\n        return index != null\n                && index >= 0\n                && index < argtypes.length\n                && argtypes[index].getName().equals(type);\n    }\n\n    private Integer findArgumentIndexIndexWithGivenType(ArgumentConfig argument, Method method) {\n        Class<?>[] argTypes = method.getParameterTypes();\n        // one callback in the method\n        if (hasIndex(argument)) {\n            Integer index = argument.getIndex();\n            String type = argument.getType();\n            if (isTypeMatched(type, index, argTypes)) {\n                return index;\n            } else {\n                throw new IllegalArgumentException(\n                        \"Argument config error : the index attribute and type attribute not match :index :\"\n                                + argument.getIndex() + \", type:\" + argument.getType());\n            }\n        } else {\n            // multiple callbacks in the method\n            for (int j = 0; j < argTypes.length; j++) {\n                if (isTypeMatched(argument.getType(), j, argTypes)) {\n                    return j;\n                }\n            }\n            throw new IllegalArgumentException(\n                    \"Argument config error : no argument matched with the type:\" + argument.getType());\n        }\n    }\n\n    private URL buildUrl(ProtocolConfig protocolConfig, Map<String, String> params) {\n        String name = protocolConfig.getName();\n        if (StringUtils.isEmpty(name)) {\n            name = DUBBO;\n        }\n\n        // export service\n        String host = findConfiguredHosts(protocolConfig, provider, params);\n        if (NetUtils.isIPV6URLStdFormat(host)) {\n            if (!host.contains(\"[\")) {\n                host = \"[\" + host + \"]\";\n            }\n        } else if (NetUtils.getLocalHostV6() != null) {\n            String ipv6Host = NetUtils.getLocalHostV6();\n            params.put(CommonConstants.IPV6_KEY, ipv6Host);\n        }\n\n        Integer port =\n                findConfiguredPort(protocolConfig, provider, this.getExtensionLoader(Protocol.class), name, params);\n        URL url = new ServiceConfigURL(\n                name,\n                null,\n                null,\n                host,\n                port,\n                getContextPath(protocolConfig).map(p -> p + \"/\" + path).orElse(path),\n                params);\n\n        // You can customize Configurator to append extra parameters\n        if (this.getExtensionLoader(ConfiguratorFactory.class).hasExtension(url.getProtocol())) {\n            url = this.getExtensionLoader(ConfiguratorFactory.class)\n                    .getExtension(url.getProtocol())\n                    .getConfigurator(url)\n                    .configure(url);\n        }\n        url = url.setScopeModel(getScopeModel());\n        url = url.setServiceModel(providerModel);\n        return url;\n    }\n\n    private void exportUrl(URL url, List<URL> registryURLs, RegisterTypeEnum registerType) {\n        String scope = url.getParameter(SCOPE_KEY);\n        // don't export when none is configured\n        if (!SCOPE_NONE.equalsIgnoreCase(scope)) {\n\n            // export to local if the config is not remote (export to remote only when config is remote)\n            if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {\n                exportLocal(url);\n            }\n\n            // export to remote if the config is not local (export to local only when config is local)\n            if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {\n                // export to extra protocol is used in remote export\n                String extProtocol = url.getParameter(EXT_PROTOCOL, \"\");\n                List<String> protocols = new ArrayList<>();\n\n                if (StringUtils.isNotBlank(extProtocol)) {\n                    // export original url\n                    url = URLBuilder.from(url)\n                            .addParameter(IS_PU_SERVER_KEY, Boolean.TRUE.toString())\n                            .build();\n                }\n\n                url = exportRemote(url, registryURLs, registerType);\n                if (!isGeneric(generic) && !getScopeModel().isInternal()) {\n                    MetadataUtils.publishServiceDefinition(url, providerModel.getServiceModel(), getApplicationModel());\n                }\n\n                if (StringUtils.isNotBlank(extProtocol)) {\n                    String[] extProtocols = extProtocol.split(\",\", -1);\n                    protocols.addAll(Arrays.asList(extProtocols));\n                }\n                // export extra protocols\n                for (String protocol : protocols) {\n                    if (StringUtils.isNotBlank(protocol)) {\n                        URL localUrl = URLBuilder.from(url)\n                                .setProtocol(protocol)\n                                .addParameter(IS_EXTRA, Boolean.TRUE.toString())\n                                .removeParameter(EXT_PROTOCOL)\n                                .build();\n                        localUrl = exportRemote(localUrl, registryURLs, registerType);\n                        if (!isGeneric(generic) && !getScopeModel().isInternal()) {\n                            MetadataUtils.publishServiceDefinition(\n                                    localUrl, providerModel.getServiceModel(), getApplicationModel());\n                        }\n                        this.urls.add(localUrl);\n                    }\n                }\n            }\n        }\n        this.urls.add(url);\n    }\n\n    private URL exportRemote(URL url, List<URL> registryURLs, RegisterTypeEnum registerType) {\n        if (CollectionUtils.isNotEmpty(registryURLs) && registerType != RegisterTypeEnum.NEVER_REGISTER) {\n            for (URL registryURL : registryURLs) {\n                if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) {\n                    url = url.addParameterIfAbsent(SERVICE_NAME_MAPPING_KEY, \"true\");\n                }\n\n                // if protocol is only injvm ,not register\n                if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {\n                    continue;\n                }\n\n                url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));\n                URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);\n                if (monitorUrl != null) {\n                    url = url.putAttribute(MONITOR_KEY, monitorUrl);\n                }\n\n                // For providers, this is used to enable custom proxy to generate invoker\n                String proxy = url.getParameter(PROXY_KEY);\n                if (StringUtils.isNotEmpty(proxy)) {\n                    registryURL = registryURL.addParameter(PROXY_KEY, proxy);\n                }\n\n                if (logger.isInfoEnabled()) {\n                    if (url.getParameter(REGISTER_KEY, true)) {\n                        logger.info(\"[INSTANCE_REGISTER] Register dubbo service \" + interfaceClass.getName() + \" url \"\n                                + url + \" to registry \" + registryURL.getAddress());\n                    } else {\n                        logger.info(\"Export dubbo service \" + interfaceClass.getName() + \" to url \" + url);\n                    }\n                }\n\n                doExportUrl(registryURL.putAttribute(EXPORT_KEY, url), true, registerType);\n            }\n\n        } else {\n\n            if (logger.isInfoEnabled()) {\n                logger.info(\"[SERVICE_PUBLISH][METADATA_REGISTER] Export dubbo service \" + interfaceClass.getName()\n                        + \" to url \" + url);\n            }\n\n            doExportUrl(url, true, registerType);\n        }\n\n        return url;\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private void doExportUrl(URL url, boolean withMetaData, RegisterTypeEnum registerType) {\n        if (!url.getParameter(REGISTER_KEY, true)) {\n            registerType = RegisterTypeEnum.MANUAL_REGISTER;\n        }\n        if (registerType == RegisterTypeEnum.NEVER_REGISTER\n                || registerType == RegisterTypeEnum.MANUAL_REGISTER\n                || registerType == RegisterTypeEnum.AUTO_REGISTER_BY_DEPLOYER) {\n            url = url.addParameter(REGISTER_KEY, false);\n        }\n\n        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);\n        if (withMetaData) {\n            invoker = new DelegateProviderMetaDataInvoker(invoker, this);\n        }\n        Exporter<?> exporter = protocolSPI.export(invoker);\n        ConcurrentHashMapUtils.computeIfAbsent(exporters, registerType, k -> new CopyOnWriteArrayList<>())\n                .add(exporter);\n    }\n\n    /**\n     * always export injvm\n     */\n    private void exportLocal(URL url) {\n        URL local = URLBuilder.from(url)\n                .setProtocol(LOCAL_PROTOCOL)\n                .setHost(LOCALHOST_VALUE)\n                .setPort(0)\n                .build();\n        local = local.setScopeModel(getScopeModel()).setServiceModel(providerModel);\n        local = local.addParameter(EXPORTER_LISTENER_KEY, LOCAL_PROTOCOL);\n        doExportUrl(local, false, RegisterTypeEnum.AUTO_REGISTER);\n        logger.info(\"[SERVICE_PUBLISH][METADATA_REGISTER] Export dubbo service \" + interfaceClass.getName()\n                + \" to local registry url : \" + local);\n    }\n\n    /**\n     * Determine if it is injvm\n     *\n     * @return\n     */\n    private boolean isOnlyInJvm() {\n        return getProtocols().size() == 1\n                && LOCAL_PROTOCOL.equalsIgnoreCase(getProtocols().get(0).getName());\n    }\n\n    private void postProcessConfig() {\n        List<ConfigPostProcessor> configPostProcessors = this.getExtensionLoader(ConfigPostProcessor.class)\n                .getActivateExtension(URL.valueOf(\"configPostProcessor://\", getScopeModel()), (String[]) null);\n\n        HashSet<ConfigPostProcessor> allConfigPostProcessor = new HashSet<>();\n\n        // merge common and old config\n        allConfigPostProcessor.addAll(configPostProcessors);\n        allConfigPostProcessor.addAll(configPostProcessors);\n\n        allConfigPostProcessor.forEach(component -> component.postProcessServiceConfig(this));\n    }\n\n    public void addServiceListener(ServiceListener listener) {\n        this.serviceListeners.add(listener);\n    }\n\n    protected void onExported() {\n        for (ServiceListener serviceListener : this.serviceListeners) {\n            serviceListener.exported(this);\n        }\n    }\n\n    protected void onUnExported() {\n        for (ServiceListener serviceListener : this.serviceListeners) {\n            serviceListener.unexported(this);\n        }\n    }\n\n    /**\n     * Register & bind IP address for service provider, can be configured separately.\n     * Configuration priority: environment variables -> java system properties -> host property in config file ->\n     * /etc/hosts -> default network address -> first available network address\n     *\n     * @param protocolConfig\n     * @param map\n     * @return\n     */\n    private static String findConfiguredHosts(\n            ProtocolConfig protocolConfig, ProviderConfig provider, Map<String, String> map) {\n        boolean anyhost = false;\n\n        String hostToBind = getValueFromConfig(protocolConfig, DUBBO_IP_TO_BIND);\n        if (StringUtils.isNotEmpty(hostToBind) && isInvalidLocalHost(hostToBind)) {\n            throw new IllegalArgumentException(\n                    \"Specified invalid bind ip from property:\" + DUBBO_IP_TO_BIND + \", value:\" + hostToBind);\n        }\n\n        // if bind ip is not found in environment, keep looking up\n        if (StringUtils.isEmpty(hostToBind)) {\n            hostToBind = protocolConfig.getHost();\n            if (provider != null && StringUtils.isEmpty(hostToBind)) {\n                hostToBind = provider.getHost();\n            }\n            if (isInvalidLocalHost(hostToBind)) {\n                anyhost = true;\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"No valid ip found from environment, try to get local host.\");\n                }\n                hostToBind = getLocalHost();\n            }\n        }\n\n        map.put(BIND_IP_KEY, hostToBind);\n\n        // bind ip is not used for registry ip by default\n        String hostToRegistry = getValueFromConfig(protocolConfig, DUBBO_IP_TO_REGISTRY);\n        if (StringUtils.isNotEmpty(hostToRegistry) && isInvalidLocalHost(hostToRegistry)) {\n            throw new IllegalArgumentException(\"Specified invalid registry ip from property:\" + DUBBO_IP_TO_REGISTRY\n                    + \", value:\" + hostToRegistry);\n        } else if (StringUtils.isEmpty(hostToRegistry)) {\n            // bind ip is used as registry ip by default\n            hostToRegistry = hostToBind;\n        }\n\n        map.put(ANYHOST_KEY, String.valueOf(anyhost));\n\n        return hostToRegistry;\n    }\n\n    /**\n     * Register port and bind port for the provider, can be configured separately\n     * Configuration priority: environment variable -> java system properties -> port property in protocol config file\n     * -> protocol default port\n     *\n     * @param protocolConfig\n     * @param name\n     * @return\n     */\n    private static synchronized Integer findConfiguredPort(\n            ProtocolConfig protocolConfig,\n            ProviderConfig provider,\n            ExtensionLoader<Protocol> extensionLoader,\n            String name,\n            Map<String, String> map) {\n        Integer portToBind;\n\n        // parse bind port from environment\n        String port = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_BIND);\n        portToBind = parsePort(port);\n\n        // if there's no bind port found from environment, keep looking up.\n        if (portToBind == null) {\n            portToBind = protocolConfig.getPort();\n            if (provider != null && (portToBind == null || portToBind == 0)) {\n                portToBind = provider.getPort();\n            }\n            final int defaultPort = extensionLoader.getExtension(name).getDefaultPort();\n            if (portToBind == null || portToBind == 0) {\n                portToBind = defaultPort;\n            }\n            if (portToBind <= 0) {\n                portToBind = getRandomPort(name);\n                if (portToBind == null || portToBind < 0) {\n                    portToBind = getAvailablePort(defaultPort);\n                    putRandomPort(name, portToBind);\n                }\n            }\n        }\n\n        // save bind port, used as url's key later\n        map.put(BIND_PORT_KEY, String.valueOf(portToBind));\n\n        // bind port is not used as registry port by default\n        String portToRegistryStr = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_REGISTRY);\n        Integer portToRegistry = parsePort(portToRegistryStr);\n        if (portToRegistry == null) {\n            portToRegistry = portToBind;\n        }\n\n        return portToRegistry;\n    }\n\n    private static Integer parsePort(String configPort) {\n        Integer port = null;\n        if (StringUtils.isNotEmpty(configPort)) {\n            try {\n                int intPort = Integer.parseInt(configPort);\n                if (isInvalidPort(intPort)) {\n                    throw new IllegalArgumentException(\"Specified invalid port from env value:\" + configPort);\n                }\n                port = intPort;\n            } catch (Exception e) {\n                throw new IllegalArgumentException(\"Specified invalid port from env value:\" + configPort);\n            }\n        }\n        return port;\n    }\n\n    private static String getValueFromConfig(ProtocolConfig protocolConfig, String key) {\n        String protocolPrefix = protocolConfig.getName().toUpperCase() + \"_\";\n        String value = ConfigUtils.getSystemProperty(protocolPrefix + key);\n        if (StringUtils.isEmpty(value)) {\n            value = ConfigUtils.getSystemProperty(key);\n        }\n        return value;\n    }\n\n    private static Integer getRandomPort(String protocol) {\n        protocol = protocol.toLowerCase();\n        return RANDOM_PORT_MAP.getOrDefault(protocol, Integer.MIN_VALUE);\n    }\n\n    private static void putRandomPort(String protocol, Integer port) {\n        protocol = protocol.toLowerCase();\n        if (!RANDOM_PORT_MAP.containsKey(protocol)) {\n            RANDOM_PORT_MAP.put(protocol, port);\n            logger.warn(\n                    CONFIG_USE_RANDOM_PORT,\n                    \"\",\n                    \"\",\n                    \"[SERVICE_PUBLISH] Use random available port(\" + port + \") for protocol \" + protocol);\n        }\n    }\n\n    @Transient\n    public Runnable getDestroyRunner() {\n        return this::unexport;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * Listener for service config\n */\n@SPI\npublic interface ServiceListener {\n\n    /**\n     * Callback when ServiceConfig is exported\n     * @param sc\n     */\n    void exported(ServiceConfig sc);\n\n    /**\n     * Callback when ServiceConfig is unexported\n     * @param sc\n     */\n    void unexported(ServiceConfig sc);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/BootstrapTakeoverMode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap;\n\nimport org.apache.dubbo.config.ServiceConfig;\n\n/**\n * Mode of which of DubboBootstrap lifecycle being takeover\n * SPRING: will be controlled by spring context\n * MANUAL: will be controlled by users, after all services init, should call {@link DubboBootstrap#start()} to init app-level env\n * AUTO: env will be init once {@link ServiceConfig#export()} finished\n * SERVLET: will be controlled by java servlet container\n */\npublic enum BootstrapTakeoverMode {\n    SPRING,\n    MANUAL,\n    AUTO,\n    SERVLET\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap;\n\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.config.ReferenceCache;\nimport org.apache.dubbo.common.deploy.ApplicationDeployer;\nimport org.apache.dubbo.common.deploy.DeployListenerAdapter;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.bootstrap.builders.ApplicationBuilder;\nimport org.apache.dubbo.config.bootstrap.builders.ConfigCenterBuilder;\nimport org.apache.dubbo.config.bootstrap.builders.ConsumerBuilder;\nimport org.apache.dubbo.config.bootstrap.builders.MetadataReportBuilder;\nimport org.apache.dubbo.config.bootstrap.builders.ProtocolBuilder;\nimport org.apache.dubbo.config.bootstrap.builders.ProviderBuilder;\nimport org.apache.dubbo.config.bootstrap.builders.ReferenceBuilder;\nimport org.apache.dubbo.config.bootstrap.builders.RegistryBuilder;\nimport org.apache.dubbo.config.bootstrap.builders.ServiceBuilder;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.function.Consumer;\n\nimport static java.util.Collections.singletonList;\n\n/**\n * See {@link ApplicationModel} and {@link ExtensionLoader} for why this class is designed to be singleton.\n * <p>\n * The bootstrap class of Dubbo\n * <p>\n * Get singleton instance by calling static method {@link #getInstance()}.\n * Designed as singleton because some classes inside Dubbo, such as ExtensionLoader, are designed only for one instance per process.\n *\n * @since 2.7.5\n */\npublic final class DubboBootstrap {\n\n    private static final String NAME = DubboBootstrap.class.getSimpleName();\n\n    private static final Logger logger = LoggerFactory.getLogger(DubboBootstrap.class);\n\n    private static final ConcurrentMap<ApplicationModel, DubboBootstrap> instanceMap = new ConcurrentHashMap<>();\n    private static volatile DubboBootstrap instance;\n\n    private final AtomicBoolean awaited = new AtomicBoolean(false);\n\n    private volatile BootstrapTakeoverMode takeoverMode = BootstrapTakeoverMode.AUTO;\n\n    private final Lock lock = new ReentrantLock();\n\n    private final Condition condition = lock.newCondition();\n\n    private final ExecutorRepository executorRepository;\n\n    private final Environment environment;\n\n    private final ApplicationModel applicationModel;\n\n    private final ConfigManager configManager;\n\n    private final ApplicationDeployer applicationDeployer;\n\n    /**\n     * See {@link ApplicationModel} and {@link ExtensionLoader} for why DubboBootstrap is designed to be singleton.\n     */\n    public static DubboBootstrap getInstance() {\n        if (instance == null) {\n            synchronized (DubboBootstrap.class) {\n                if (instance == null) {\n                    instance = DubboBootstrap.getInstance(ApplicationModel.defaultModel());\n                }\n            }\n        }\n        return instance;\n    }\n\n    public static DubboBootstrap getInstance(ApplicationModel applicationModel) {\n        return ConcurrentHashMapUtils.computeIfAbsent(\n                instanceMap, applicationModel, _k -> new DubboBootstrap(applicationModel));\n    }\n\n    public static DubboBootstrap newInstance() {\n        return getInstance(FrameworkModel.defaultModel().newApplication());\n    }\n\n    public static DubboBootstrap newInstance(FrameworkModel frameworkModel) {\n        return getInstance(frameworkModel.newApplication());\n    }\n\n    /**\n     * Try reset dubbo status for new instance.\n     *\n     * @deprecated For testing purposes only\n     */\n    @Deprecated\n    public static void reset() {\n        reset(true);\n    }\n\n    /**\n     * Try reset dubbo status for new instance.\n     *\n     * @deprecated For testing purposes only\n     */\n    @Deprecated\n    public static void reset(boolean destroy) {\n        if (destroy) {\n            if (instance != null) {\n                instance.destroy();\n                instance = null;\n            }\n            FrameworkModel.destroyAll();\n        } else {\n            instance = null;\n        }\n\n        ApplicationModel.reset();\n    }\n\n    private DubboBootstrap(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        configManager = applicationModel.getApplicationConfigManager();\n        environment = applicationModel.modelEnvironment();\n\n        executorRepository = ExecutorRepository.getInstance(applicationModel);\n        applicationDeployer = applicationModel.getDeployer();\n        // listen deploy events\n        applicationDeployer.addDeployListener(new DeployListenerAdapter<ApplicationModel>() {\n            @Override\n            public void onStarted(ApplicationModel scopeModel) {\n                notifyStarted(applicationModel);\n            }\n\n            @Override\n            public void onStopped(ApplicationModel scopeModel) {\n                notifyStopped(applicationModel);\n            }\n\n            @Override\n            public void onFailure(ApplicationModel scopeModel, Throwable cause) {\n                notifyStopped(applicationModel);\n            }\n        });\n        // register DubboBootstrap bean\n        applicationModel.getBeanFactory().registerBean(this);\n    }\n\n    private void notifyStarted(ApplicationModel applicationModel) {\n        ExtensionLoader<DubboBootstrapStartStopListener> exts =\n                applicationModel.getExtensionLoader(DubboBootstrapStartStopListener.class);\n        exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(DubboBootstrap.this));\n    }\n\n    private void notifyStopped(ApplicationModel applicationModel) {\n        ExtensionLoader<DubboBootstrapStartStopListener> exts =\n                applicationModel.getExtensionLoader(DubboBootstrapStartStopListener.class);\n        exts.getSupportedExtensionInstances().forEach(ext -> ext.onStop(DubboBootstrap.this));\n        executeMutually(() -> {\n            awaited.set(true);\n            condition.signalAll();\n        });\n        instanceMap.remove(applicationModel);\n    }\n\n    /**\n     * Initialize\n     */\n    public void initialize() {\n        applicationDeployer.initialize();\n    }\n\n    /**\n     * Start dubbo application and wait for finish\n     */\n    public DubboBootstrap start() {\n        this.start(true);\n        return this;\n    }\n\n    /**\n     * Start dubbo application\n     *\n     * @param wait If true, wait for startup to complete, or else no waiting.\n     * @return\n     */\n    public DubboBootstrap start(boolean wait) {\n        Future future = applicationDeployer.start();\n        if (wait) {\n            try {\n                future.get();\n            } catch (Exception e) {\n                throw new IllegalStateException(\"await dubbo application start finish failure\", e);\n            }\n        }\n        return this;\n    }\n\n    /**\n     * Start dubbo application but no wait for finish.\n     *\n     * @return the future object\n     */\n    public Future asyncStart() {\n        return applicationDeployer.start();\n    }\n\n    /**\n     * Stop dubbo application\n     *\n     * @return\n     * @throws IllegalStateException\n     */\n    public DubboBootstrap stop() throws IllegalStateException {\n        destroy();\n        return this;\n    }\n\n    public void destroy() {\n        applicationModel.destroy();\n    }\n\n    public boolean isInitialized() {\n        return applicationDeployer.isInitialized();\n    }\n\n    public boolean isPending() {\n        return applicationDeployer.isPending();\n    }\n\n    /**\n     * @return true if the dubbo application is starting or has been started.\n     */\n    public boolean isRunning() {\n        return applicationDeployer.isRunning();\n    }\n\n    /**\n     * @return true if the dubbo application is starting.\n     * @see #isStarted()\n     */\n    public boolean isStarting() {\n        return applicationDeployer.isStarting();\n    }\n\n    /**\n     * @return true if the dubbo application has been started.\n     * @see #start()\n     * @see #isStarting()\n     */\n    public boolean isStarted() {\n        return applicationDeployer.isStarted();\n    }\n\n    public boolean isCompletion() {\n        return applicationDeployer.isCompletion();\n    }\n\n    /**\n     * @return true if the dubbo application is stopping.\n     * @see #isStopped()\n     */\n    public boolean isStopping() {\n        return applicationDeployer.isStopping();\n    }\n\n    /**\n     * @return true if the dubbo application is stopping.\n     * @see #isStopped()\n     */\n    public boolean isStopped() {\n        return applicationDeployer.isStopped();\n    }\n\n    /**\n     * Block current thread to be await.\n     *\n     * @return {@link DubboBootstrap}\n     */\n    public DubboBootstrap await() {\n        // if has been waited, no need to wait again, return immediately\n        if (!awaited.get()) {\n            if (!isStopped()) {\n                executeMutually(() -> {\n                    while (!awaited.get()) {\n                        if (logger.isInfoEnabled()) {\n                            logger.info(NAME + \" awaiting ...\");\n                        }\n                        try {\n                            condition.await();\n                        } catch (InterruptedException e) {\n                            Thread.currentThread().interrupt();\n                        }\n                    }\n                });\n            }\n        }\n        return this;\n    }\n\n    public ReferenceCache getCache() {\n        return applicationDeployer.getReferenceCache();\n    }\n\n    private void executeMutually(Runnable runnable) {\n        try {\n            lock.lock();\n            runnable.run();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public ApplicationConfig getApplication() {\n        return configManager.getApplicationOrElseThrow();\n    }\n\n    public void setTakeoverMode(BootstrapTakeoverMode takeoverMode) {\n        // TODO this.started.set(false);\n        this.takeoverMode = takeoverMode;\n    }\n\n    public BootstrapTakeoverMode getTakeoverMode() {\n        return takeoverMode;\n    }\n\n    public ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    public ConfigManager getConfigManager() {\n        return configManager;\n    }\n\n    // MetadataReportConfig correlative methods\n\n    public DubboBootstrap metadataReport(Consumer<MetadataReportBuilder> consumerBuilder) {\n        return metadataReport(null, consumerBuilder);\n    }\n\n    public DubboBootstrap metadataReport(String id, Consumer<MetadataReportBuilder> consumerBuilder) {\n        MetadataReportBuilder metadataReportBuilder = createMetadataReportBuilder(id);\n        consumerBuilder.accept(metadataReportBuilder);\n        return this;\n    }\n\n    public DubboBootstrap metadataReport(MetadataReportConfig metadataReportConfig) {\n        configManager.addMetadataReport(metadataReportConfig);\n        return this;\n    }\n\n    public DubboBootstrap metadataReports(List<MetadataReportConfig> metadataReportConfigs) {\n        if (CollectionUtils.isEmpty(metadataReportConfigs)) {\n            return this;\n        }\n\n        configManager.addMetadataReports(metadataReportConfigs);\n        return this;\n    }\n\n    // {@link ApplicationConfig} correlative methods\n\n    /**\n     * Set the name of application\n     *\n     * @param name the name of application\n     * @return current {@link DubboBootstrap} instance\n     */\n    public DubboBootstrap application(String name) {\n        return application(name, builder -> {\n            // DO NOTHING\n        });\n    }\n\n    /**\n     * Set the name of application and it's future build\n     *\n     * @param name            the name of application\n     * @param consumerBuilder {@link ApplicationBuilder}\n     * @return current {@link DubboBootstrap} instance\n     */\n    public DubboBootstrap application(String name, Consumer<ApplicationBuilder> consumerBuilder) {\n        ApplicationBuilder builder = createApplicationBuilder(name);\n        consumerBuilder.accept(builder);\n        return application(builder.build());\n    }\n\n    /**\n     * Set the {@link ApplicationConfig}\n     *\n     * @param applicationConfig the {@link ApplicationConfig}\n     * @return current {@link DubboBootstrap} instance\n     */\n    public DubboBootstrap application(ApplicationConfig applicationConfig) {\n        applicationConfig.setScopeModel(applicationModel);\n        configManager.setApplication(applicationConfig);\n        return this;\n    }\n\n    // {@link RegistryConfig} correlative methods\n\n    /**\n     * Add an instance of {@link RegistryConfig}\n     *\n     * @param consumerBuilder the {@link Consumer} of {@link RegistryBuilder}\n     * @return current {@link DubboBootstrap} instance\n     */\n    public DubboBootstrap registry(Consumer<RegistryBuilder> consumerBuilder) {\n        return registry(null, consumerBuilder);\n    }\n\n    /**\n     * Add an instance of {@link RegistryConfig} with the specified ID\n     *\n     * @param id              the {@link RegistryConfig#getId() id}  of {@link RegistryConfig}\n     * @param consumerBuilder the {@link Consumer} of {@link RegistryBuilder}\n     * @return current {@link DubboBootstrap} instance\n     */\n    public DubboBootstrap registry(String id, Consumer<RegistryBuilder> consumerBuilder) {\n        RegistryBuilder builder = createRegistryBuilder(id);\n        consumerBuilder.accept(builder);\n        return registry(builder.build());\n    }\n\n    /**\n     * Add an instance of {@link RegistryConfig}\n     *\n     * @param registryConfig an instance of {@link RegistryConfig}\n     * @return current {@link DubboBootstrap} instance\n     */\n    public DubboBootstrap registry(RegistryConfig registryConfig) {\n        registryConfig.setScopeModel(applicationModel);\n        configManager.addRegistry(registryConfig);\n        return this;\n    }\n\n    /**\n     * Add an instance of {@link RegistryConfig}\n     *\n     * @param registryConfigs the multiple instances of {@link RegistryConfig}\n     * @return current {@link DubboBootstrap} instance\n     */\n    public DubboBootstrap registries(List<RegistryConfig> registryConfigs) {\n        if (CollectionUtils.isEmpty(registryConfigs)) {\n            return this;\n        }\n        registryConfigs.forEach(this::registry);\n        return this;\n    }\n\n    // {@link ProtocolConfig} correlative methods\n    public DubboBootstrap protocol(Consumer<ProtocolBuilder> consumerBuilder) {\n        return protocol(null, consumerBuilder);\n    }\n\n    public DubboBootstrap protocol(String id, Consumer<ProtocolBuilder> consumerBuilder) {\n        ProtocolBuilder builder = createProtocolBuilder(id);\n        consumerBuilder.accept(builder);\n        return protocol(builder.build());\n    }\n\n    public DubboBootstrap protocol(ProtocolConfig protocolConfig) {\n        return protocols(singletonList(protocolConfig));\n    }\n\n    public DubboBootstrap protocols(List<ProtocolConfig> protocolConfigs) {\n        if (CollectionUtils.isEmpty(protocolConfigs)) {\n            return this;\n        }\n        for (ProtocolConfig protocolConfig : protocolConfigs) {\n            protocolConfig.setScopeModel(applicationModel);\n            configManager.addProtocol(protocolConfig);\n        }\n        return this;\n    }\n\n    // {@link ServiceConfig} correlative methods\n    public <S> DubboBootstrap service(Consumer<ServiceBuilder<S>> consumerBuilder) {\n        return service(null, consumerBuilder);\n    }\n\n    public <S> DubboBootstrap service(String id, Consumer<ServiceBuilder<S>> consumerBuilder) {\n        return service(createServiceConfig(id, consumerBuilder));\n    }\n\n    private <S> ServiceConfig createServiceConfig(String id, Consumer<ServiceBuilder<S>> consumerBuilder) {\n        ServiceBuilder builder = createServiceBuilder(id);\n        consumerBuilder.accept(builder);\n        return builder.build();\n    }\n\n    public DubboBootstrap services(List<ServiceConfig> serviceConfigs) {\n        if (CollectionUtils.isEmpty(serviceConfigs)) {\n            return this;\n        }\n        for (ServiceConfig serviceConfig : serviceConfigs) {\n            this.service(serviceConfig);\n        }\n        return this;\n    }\n\n    public DubboBootstrap service(ServiceConfig<?> serviceConfig) {\n        this.service(serviceConfig, applicationModel.getDefaultModule());\n        return this;\n    }\n\n    public DubboBootstrap service(ServiceConfig<?> serviceConfig, ModuleModel moduleModel) {\n        serviceConfig.setScopeModel(moduleModel);\n        moduleModel.getConfigManager().addService(serviceConfig);\n        return this;\n    }\n\n    // {@link Reference} correlative methods\n    public <S> DubboBootstrap reference(Consumer<ReferenceBuilder<S>> consumerBuilder) {\n        return reference(null, consumerBuilder);\n    }\n\n    public <S> DubboBootstrap reference(String id, Consumer<ReferenceBuilder<S>> consumerBuilder) {\n        return reference(createReferenceConfig(id, consumerBuilder));\n    }\n\n    private <S> ReferenceConfig createReferenceConfig(String id, Consumer<ReferenceBuilder<S>> consumerBuilder) {\n        ReferenceBuilder builder = createReferenceBuilder(id);\n        consumerBuilder.accept(builder);\n        return builder.build();\n    }\n\n    public DubboBootstrap references(List<ReferenceConfig> referenceConfigs) {\n        if (CollectionUtils.isEmpty(referenceConfigs)) {\n            return this;\n        }\n        for (ReferenceConfig referenceConfig : referenceConfigs) {\n            this.reference(referenceConfig);\n        }\n        return this;\n    }\n\n    public DubboBootstrap reference(ReferenceConfig<?> referenceConfig) {\n        return reference(referenceConfig, applicationModel.getDefaultModule());\n    }\n\n    public DubboBootstrap reference(ReferenceConfig<?> referenceConfig, ModuleModel moduleModel) {\n        referenceConfig.setScopeModel(moduleModel);\n        moduleModel.getConfigManager().addReference(referenceConfig);\n        return this;\n    }\n\n    // {@link ProviderConfig} correlative methods\n    public DubboBootstrap provider(Consumer<ProviderBuilder> builderConsumer) {\n        provider(null, builderConsumer);\n        return this;\n    }\n\n    public DubboBootstrap provider(String id, Consumer<ProviderBuilder> builderConsumer) {\n        this.provider(createProviderConfig(id, builderConsumer));\n        return this;\n    }\n\n    private ProviderConfig createProviderConfig(String id, Consumer<ProviderBuilder> builderConsumer) {\n        ProviderBuilder builder = createProviderBuilder(id);\n        builderConsumer.accept(builder);\n        return builder.build();\n    }\n\n    public DubboBootstrap provider(ProviderConfig providerConfig) {\n        return this.provider(providerConfig, applicationModel.getDefaultModule());\n    }\n\n    public DubboBootstrap providers(List<ProviderConfig> providerConfigs) {\n        for (ProviderConfig providerConfig : providerConfigs) {\n            this.provider(providerConfig, applicationModel.getDefaultModule());\n        }\n        return this;\n    }\n\n    public DubboBootstrap provider(ProviderConfig providerConfig, ModuleModel moduleModel) {\n        providerConfig.setScopeModel(moduleModel);\n        moduleModel.getConfigManager().addProvider(providerConfig);\n        return this;\n    }\n\n    // {@link ConsumerConfig} correlative methods\n    public DubboBootstrap consumer(Consumer<ConsumerBuilder> builderConsumer) {\n        return consumer(null, builderConsumer);\n    }\n\n    public DubboBootstrap consumer(String id, Consumer<ConsumerBuilder> builderConsumer) {\n        return consumer(createConsumerConfig(id, builderConsumer));\n    }\n\n    private ConsumerConfig createConsumerConfig(String id, Consumer<ConsumerBuilder> builderConsumer) {\n        ConsumerBuilder builder = createConsumerBuilder(id);\n        builderConsumer.accept(builder);\n        return builder.build();\n    }\n\n    public DubboBootstrap consumer(ConsumerConfig consumerConfig) {\n        return this.consumer(consumerConfig, applicationModel.getDefaultModule());\n    }\n\n    public DubboBootstrap consumers(List<ConsumerConfig> consumerConfigs) {\n        for (ConsumerConfig consumerConfig : consumerConfigs) {\n            this.consumer(consumerConfig, applicationModel.getDefaultModule());\n        }\n        return this;\n    }\n\n    public DubboBootstrap consumer(ConsumerConfig consumerConfig, ModuleModel moduleModel) {\n        consumerConfig.setScopeModel(moduleModel);\n        moduleModel.getConfigManager().addConsumer(consumerConfig);\n        return this;\n    }\n\n    public DubboBootstrap module(ModuleConfig moduleConfig) {\n        this.module(moduleConfig, applicationModel.getDefaultModule());\n        return this;\n    }\n\n    public DubboBootstrap module(ModuleConfig moduleConfig, ModuleModel moduleModel) {\n        moduleConfig.setScopeModel(moduleModel);\n        moduleModel.getConfigManager().setModule(moduleConfig);\n        return this;\n    }\n    // module configs end\n\n    // {@link ConfigCenterConfig} correlative methods\n    public DubboBootstrap configCenter(Consumer<ConfigCenterBuilder> consumerBuilder) {\n        return configCenter(null, consumerBuilder);\n    }\n\n    public DubboBootstrap configCenter(String id, Consumer<ConfigCenterBuilder> consumerBuilder) {\n        ConfigCenterBuilder configCenterBuilder = createConfigCenterBuilder(id);\n        consumerBuilder.accept(configCenterBuilder);\n        return this;\n    }\n\n    public DubboBootstrap configCenter(ConfigCenterConfig configCenterConfig) {\n        configCenterConfig.setScopeModel(applicationModel);\n        configManager.addConfigCenter(configCenterConfig);\n        return this;\n    }\n\n    public DubboBootstrap configCenters(List<ConfigCenterConfig> configCenterConfigs) {\n        if (CollectionUtils.isEmpty(configCenterConfigs)) {\n            return this;\n        }\n        for (ConfigCenterConfig configCenterConfig : configCenterConfigs) {\n            this.configCenter(configCenterConfig);\n        }\n        return this;\n    }\n\n    public DubboBootstrap monitor(MonitorConfig monitor) {\n        monitor.setScopeModel(applicationModel);\n        configManager.setMonitor(monitor);\n        return this;\n    }\n\n    public DubboBootstrap metrics(MetricsConfig metrics) {\n        metrics.setScopeModel(applicationModel);\n        configManager.setMetrics(metrics);\n        return this;\n    }\n\n    public DubboBootstrap tracing(TracingConfig tracing) {\n        tracing.setScopeModel(applicationModel);\n        configManager.setTracing(tracing);\n        return this;\n    }\n\n    public DubboBootstrap ssl(SslConfig sslConfig) {\n        sslConfig.setScopeModel(applicationModel);\n        configManager.setSsl(sslConfig);\n        return this;\n    }\n\n    /* serve for builder apis, begin */\n\n    private ApplicationBuilder createApplicationBuilder(String name) {\n        return new ApplicationBuilder().name(name);\n    }\n\n    private RegistryBuilder createRegistryBuilder(String id) {\n        return new RegistryBuilder().id(id);\n    }\n\n    private MetadataReportBuilder createMetadataReportBuilder(String id) {\n        return new MetadataReportBuilder().id(id);\n    }\n\n    private ConfigCenterBuilder createConfigCenterBuilder(String id) {\n        return new ConfigCenterBuilder().id(id);\n    }\n\n    private ProtocolBuilder createProtocolBuilder(String id) {\n        return new ProtocolBuilder().id(id);\n    }\n\n    private ServiceBuilder createServiceBuilder(String id) {\n        return new ServiceBuilder().id(id);\n    }\n\n    private ReferenceBuilder createReferenceBuilder(String id) {\n        return new ReferenceBuilder().id(id);\n    }\n\n    private ProviderBuilder createProviderBuilder(String id) {\n        return new ProviderBuilder().id(id);\n    }\n\n    private ConsumerBuilder createConsumerBuilder(String id) {\n        return new ConsumerBuilder().id(id);\n    }\n    /* serve for builder apis, end */\n\n    public Module newModule() {\n        return new Module(applicationModel.newModule());\n    }\n\n    public Module newModule(ModuleConfig moduleConfig) {\n        ModuleModel moduleModel = applicationModel.newModule();\n        moduleConfig.setScopeModel(moduleModel);\n        moduleModel.getConfigManager().setModule(moduleConfig);\n        return new Module(moduleModel);\n    }\n\n    public DubboBootstrap endModule() {\n        return this;\n    }\n\n    public class Module {\n        private ModuleModel moduleModel;\n        private DubboBootstrap bootstrap;\n\n        public Module(ModuleModel moduleModel) {\n            this.moduleModel = moduleModel;\n            this.bootstrap = DubboBootstrap.this;\n        }\n\n        public DubboBootstrap endModule() {\n            return this.bootstrap.endModule();\n        }\n\n        public ModuleModel getModuleModel() {\n            return moduleModel;\n        }\n\n        public Module config(ModuleConfig moduleConfig) {\n            this.moduleModel.getConfigManager().setModule(moduleConfig);\n            return this;\n        }\n\n        // {@link ServiceConfig} correlative methods\n        public <S> Module service(Consumer<ServiceBuilder<S>> consumerBuilder) {\n            return service(null, consumerBuilder);\n        }\n\n        public <S> Module service(String id, Consumer<ServiceBuilder<S>> consumerBuilder) {\n            return service(createServiceConfig(id, consumerBuilder));\n        }\n\n        public Module services(List<ServiceConfig> serviceConfigs) {\n            if (CollectionUtils.isEmpty(serviceConfigs)) {\n                return this;\n            }\n            for (ServiceConfig serviceConfig : serviceConfigs) {\n                this.service(serviceConfig);\n            }\n            return this;\n        }\n\n        public Module service(ServiceConfig<?> serviceConfig) {\n            DubboBootstrap.this.service(serviceConfig, moduleModel);\n            return this;\n        }\n\n        // {@link Reference} correlative methods\n        public <S> Module reference(Consumer<ReferenceBuilder<S>> consumerBuilder) {\n            return reference(null, consumerBuilder);\n        }\n\n        public <S> Module reference(String id, Consumer<ReferenceBuilder<S>> consumerBuilder) {\n            return reference(createReferenceConfig(id, consumerBuilder));\n        }\n\n        public Module reference(ReferenceConfig<?> referenceConfig) {\n            DubboBootstrap.this.reference(referenceConfig, moduleModel);\n            return this;\n        }\n\n        public Module references(List<ReferenceConfig> referenceConfigs) {\n            if (CollectionUtils.isEmpty(referenceConfigs)) {\n                return this;\n            }\n            for (ReferenceConfig referenceConfig : referenceConfigs) {\n                this.reference(referenceConfig);\n            }\n            return this;\n        }\n\n        // {@link ProviderConfig} correlative methods\n        public Module provider(Consumer<ProviderBuilder> builderConsumer) {\n            return provider(null, builderConsumer);\n        }\n\n        public Module provider(String id, Consumer<ProviderBuilder> builderConsumer) {\n            return provider(createProviderConfig(id, builderConsumer));\n        }\n\n        public Module provider(ProviderConfig providerConfig) {\n            DubboBootstrap.this.provider(providerConfig, moduleModel);\n            return this;\n        }\n\n        public Module providers(List<ProviderConfig> providerConfigs) {\n            if (CollectionUtils.isEmpty(providerConfigs)) {\n                return this;\n            }\n            for (ProviderConfig providerConfig : providerConfigs) {\n                DubboBootstrap.this.provider(providerConfig, moduleModel);\n            }\n            return this;\n        }\n\n        // {@link ConsumerConfig} correlative methods\n        public Module consumer(Consumer<ConsumerBuilder> builderConsumer) {\n            return consumer(null, builderConsumer);\n        }\n\n        public Module consumer(String id, Consumer<ConsumerBuilder> builderConsumer) {\n            return consumer(createConsumerConfig(id, builderConsumer));\n        }\n\n        public Module consumer(ConsumerConfig consumerConfig) {\n            DubboBootstrap.this.consumer(consumerConfig, moduleModel);\n            return this;\n        }\n\n        public Module consumers(List<ConsumerConfig> consumerConfigs) {\n            if (CollectionUtils.isEmpty(consumerConfigs)) {\n                return this;\n            }\n            for (ConsumerConfig consumerConfig : consumerConfigs) {\n                DubboBootstrap.this.consumer(consumerConfig, moduleModel);\n            }\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrapStartStopListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * call on DubboBootstrap start or stop.\n *\n * @scene 2.7.9\n * @see DubboBootstrap\n */\n@SPI\n@Deprecated\npublic interface DubboBootstrapStartStopListener {\n\n    void onStart(DubboBootstrap bootstrap);\n\n    void onStop(DubboBootstrap bootstrap);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/AbstractBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.AbstractConfig;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * AbstractBuilder\n *\n * @param <C> The type of {@link AbstractConfig Config}\n * @param <B> The type of {@link AbstractBuilder Builder}\n * @since 2.7\n */\npublic abstract class AbstractBuilder<C extends AbstractConfig, B extends AbstractBuilder> {\n    /**\n     * The config id\n     */\n    protected String id;\n\n    public B id(String id) {\n        this.id = id;\n        return getThis();\n    }\n\n    protected abstract B getThis();\n\n    protected static Map<String, String> appendParameter(Map<String, String> parameters, String key, String value) {\n        if (parameters == null) {\n            parameters = new HashMap<>();\n        }\n        parameters.put(key, value);\n        return parameters;\n    }\n\n    protected static Map<String, String> appendParameters(\n            Map<String, String> parameters, Map<String, String> appendParameters) {\n        if (parameters == null) {\n            parameters = new HashMap<>();\n        }\n        parameters.putAll(appendParameters);\n        return parameters;\n    }\n\n    protected void build(C instance) {\n        if (!StringUtils.isEmpty(id)) {\n            instance.setId(id);\n        }\n    }\n\n    /**\n     * Build an instance of {@link AbstractConfig config}\n     *\n     * @return an instance of {@link AbstractConfig config}\n     */\n    public abstract C build();\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/AbstractInterfaceBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.AbstractInterfaceConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.rpc.Filter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * AbstractBuilder\n *\n * @since 2.7\n */\npublic abstract class AbstractInterfaceBuilder<\n                T extends AbstractInterfaceConfig, B extends AbstractInterfaceBuilder<T, B>>\n        extends AbstractMethodBuilder<T, B> {\n    /**\n     * Local impl class name for the service interface\n     */\n    protected String local;\n\n    /**\n     * Local stub class name for the service interface\n     */\n    protected String stub;\n\n    /**\n     * Service monitor\n     */\n    protected MonitorConfig monitor;\n\n    /**\n     * Strategies for generating dynamic agents，there are two strategies can be chosen: jdk and javassist\n     */\n    protected String proxy;\n\n    /**\n     * Cluster type\n     */\n    protected String cluster;\n\n    /**\n     * The {@link Filter} when the provider side exposed a service or the customer side references a remote service used,\n     * if there are more than one, you can use commas to separate them\n     */\n    protected String filter;\n\n    /**\n     * The Listener when the provider side exposes a service or the customer side references a remote service used\n     * if there are more than one, you can use commas to separate them\n     */\n    protected String listener;\n\n    /**\n     * The owner of the service providers\n     */\n    protected String owner;\n\n    /**\n     * Connection limits, 0 means shared connection, otherwise it defines the connections delegated to the current service\n     */\n    protected Integer connections;\n\n    /**\n     * The layer of service providers\n     */\n    protected String layer;\n\n    /**\n     * The application info\n     */\n    protected ApplicationConfig application;\n\n    /**\n     * The module info\n     */\n    protected ModuleConfig module;\n\n    /**\n     * Registry centers\n     */\n    protected List<RegistryConfig> registries;\n\n    protected String registryIds;\n\n    // connection events\n    protected String onconnect;\n\n    /**\n     * Disconnection events\n     */\n    protected String ondisconnect;\n\n    protected MetadataReportConfig metadataReportConfig;\n\n    protected ConfigCenterConfig configCenter;\n\n    // callback limits\n    private Integer callbacks;\n    // the scope for referring/exporting a service, if it's local, it means searching in current JVM only.\n    private String scope;\n\n    private String tag;\n\n    /**\n     * @param local\n     * @see AbstractInterfaceBuilder#stub(String)\n     * @deprecated Replace to <code>stub(String)</code>\n     */\n    @Deprecated\n    public B local(String local) {\n        this.local = local;\n        return getThis();\n    }\n\n    /**\n     * @param local\n     * @see AbstractInterfaceBuilder#stub(Boolean)\n     * @deprecated Replace to <code>stub(Boolean)</code>\n     */\n    @Deprecated\n    public B local(Boolean local) {\n        if (local != null) {\n            this.local = local.toString();\n        } else {\n            this.local = null;\n        }\n        return getThis();\n    }\n\n    public B stub(String stub) {\n        this.stub = stub;\n        return getThis();\n    }\n\n    public B stub(Boolean stub) {\n        if (stub != null) {\n            this.stub = stub.toString();\n        } else {\n            this.stub = null;\n        }\n        return getThis();\n    }\n\n    public B monitor(MonitorConfig monitor) {\n        this.monitor = monitor;\n        return getThis();\n    }\n\n    public B monitor(String monitor) {\n        this.monitor = new MonitorConfig(monitor);\n        return getThis();\n    }\n\n    public B proxy(String proxy) {\n        this.proxy = proxy;\n        return getThis();\n    }\n\n    public B cluster(String cluster) {\n        this.cluster = cluster;\n        return getThis();\n    }\n\n    public B filter(String filter) {\n        this.filter = filter;\n        return getThis();\n    }\n\n    public B listener(String listener) {\n        this.listener = listener;\n        return getThis();\n    }\n\n    public B owner(String owner) {\n        this.owner = owner;\n        return getThis();\n    }\n\n    public B connections(Integer connections) {\n        this.connections = connections;\n        return getThis();\n    }\n\n    public B layer(String layer) {\n        this.layer = layer;\n        return getThis();\n    }\n\n    public B application(ApplicationConfig application) {\n        this.application = application;\n        return getThis();\n    }\n\n    public B module(ModuleConfig module) {\n        this.module = module;\n        return getThis();\n    }\n\n    public B addRegistries(List<RegistryConfig> registries) {\n        if (this.registries == null) {\n            this.registries = new ArrayList<>();\n        }\n        this.registries.addAll(registries);\n        return getThis();\n    }\n\n    public B addRegistry(RegistryConfig registry) {\n        if (this.registries == null) {\n            this.registries = new ArrayList<>();\n        }\n        this.registries.add(registry);\n        return getThis();\n    }\n\n    public B registryIds(String registryIds) {\n        this.registryIds = registryIds;\n        return getThis();\n    }\n\n    public B onconnect(String onconnect) {\n        this.onconnect = onconnect;\n        return getThis();\n    }\n\n    public B ondisconnect(String ondisconnect) {\n        this.ondisconnect = ondisconnect;\n        return getThis();\n    }\n\n    public B metadataReportConfig(MetadataReportConfig metadataReportConfig) {\n        this.metadataReportConfig = metadataReportConfig;\n        return getThis();\n    }\n\n    public B configCenter(ConfigCenterConfig configCenter) {\n        this.configCenter = configCenter;\n        return getThis();\n    }\n\n    public B callbacks(Integer callbacks) {\n        this.callbacks = callbacks;\n        return getThis();\n    }\n\n    public B scope(String scope) {\n        this.scope = scope;\n        return getThis();\n    }\n\n    public B tag(String tag) {\n        this.tag = tag;\n        return getThis();\n    }\n\n    @Override\n    public void build(T instance) {\n        super.build(instance);\n\n        if (!StringUtils.isEmpty(local)) {\n            instance.setLocal(local);\n        }\n        if (!StringUtils.isEmpty(stub)) {\n            instance.setStub(stub);\n        }\n        if (monitor != null) {\n            instance.setMonitor(monitor);\n        }\n        if (!StringUtils.isEmpty(proxy)) {\n            instance.setProxy(proxy);\n        }\n        if (!StringUtils.isEmpty(cluster)) {\n            instance.setCluster(cluster);\n        }\n        if (!StringUtils.isEmpty(filter)) {\n            instance.setFilter(filter);\n        }\n        if (!StringUtils.isEmpty(listener)) {\n            instance.setListener(listener);\n        }\n        if (!StringUtils.isEmpty(owner)) {\n            instance.setOwner(owner);\n        }\n        if (connections != null) {\n            instance.setConnections(connections);\n        }\n        if (!StringUtils.isEmpty(layer)) {\n            instance.setLayer(layer);\n        }\n        if (application != null) {\n            instance.setApplication(application);\n        }\n        if (module != null) {\n            instance.setModule(module);\n        }\n        if (registries != null) {\n            instance.setRegistries(registries);\n        }\n        if (!StringUtils.isEmpty(registryIds)) {\n            instance.setRegistryIds(registryIds);\n        }\n        if (!StringUtils.isEmpty(onconnect)) {\n            instance.setOnconnect(onconnect);\n        }\n        if (!StringUtils.isEmpty(ondisconnect)) {\n            instance.setOndisconnect(ondisconnect);\n        }\n        if (metadataReportConfig != null) {\n            instance.setMetadataReportConfig(metadataReportConfig);\n        }\n        if (configCenter != null) {\n            instance.setConfigCenter(configCenter);\n        }\n        if (callbacks != null) {\n            instance.setCallbacks(callbacks);\n        }\n        if (!StringUtils.isEmpty(scope)) {\n            instance.setScope(scope);\n        }\n        if (StringUtils.isNotEmpty(tag)) {\n            instance.setTag(tag);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/AbstractMethodBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.AbstractMethodConfig;\n\nimport java.util.Map;\n\n/**\n * AbstractBuilder\n *\n * @since 2.7\n */\npublic abstract class AbstractMethodBuilder<T extends AbstractMethodConfig, B extends AbstractMethodBuilder<T, B>>\n        extends AbstractBuilder<T, B> {\n    /**\n     * The timeout for remote invocation in milliseconds\n     */\n    protected Integer timeout;\n\n    /**\n     * The retry times\n     */\n    protected Integer retries;\n\n    /**\n     * max concurrent invocations\n     */\n    protected Integer actives;\n\n    /**\n     * The load balance\n     */\n    protected String loadbalance;\n\n    /**\n     * Whether to async\n     * note that: it is an unreliable asynchronism that ignores return values and does not block threads.\n     */\n    protected Boolean async;\n\n    /**\n     * Whether to ack async-sent\n     */\n    protected Boolean sent;\n\n    /**\n     * The name of mock class which gets called when a service fails to execute\n     *\n     * note that: the mock doesn't support on the provider side，and the mock is executed when a non-business exception\n     * occurs after a remote service call\n     */\n    protected String mock;\n\n    /**\n     * Merger\n     */\n    protected String merger;\n\n    /**\n     * Cache the return result with the call parameter as key, the following options are available: lru, threadlocal,\n     * jcache, etc.\n     */\n    protected String cache;\n\n    /**\n     * Whether JSR303 standard annotation validation is enabled or not, if enabled, annotations on method parameters will\n     * be validated\n     */\n    protected String validation;\n\n    /**\n     * The customized parameters\n     */\n    protected Map<String, String> parameters;\n\n    /**\n     * Forks for forking cluster\n     */\n    protected Integer forks;\n\n    public B timeout(Integer timeout) {\n        this.timeout = timeout;\n        return getThis();\n    }\n\n    public B retries(Integer retries) {\n        this.retries = retries;\n        return getThis();\n    }\n\n    public B actives(Integer actives) {\n        this.actives = actives;\n        return getThis();\n    }\n\n    public B loadbalance(String loadbalance) {\n        this.loadbalance = loadbalance;\n        return getThis();\n    }\n\n    public B async(Boolean async) {\n        this.async = async;\n        return getThis();\n    }\n\n    public B sent(Boolean sent) {\n        this.sent = sent;\n        return getThis();\n    }\n\n    public B mock(String mock) {\n        this.mock = mock;\n        return getThis();\n    }\n\n    public B mock(Boolean mock) {\n        if (mock != null) {\n            this.mock = mock.toString();\n        } else {\n            this.mock = null;\n        }\n        return getThis();\n    }\n\n    public B merger(String merger) {\n        this.merger = merger;\n        return getThis();\n    }\n\n    public B cache(String cache) {\n        this.cache = cache;\n        return getThis();\n    }\n\n    public B validation(String validation) {\n        this.validation = validation;\n        return getThis();\n    }\n\n    public B appendParameters(Map<String, String> appendParameters) {\n        this.parameters = appendParameters(parameters, appendParameters);\n        return getThis();\n    }\n\n    public B appendParameter(String key, String value) {\n        this.parameters = appendParameter(parameters, key, value);\n        return getThis();\n    }\n\n    public B forks(Integer forks) {\n        this.forks = forks;\n        return getThis();\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public void build(T instance) {\n        super.build(instance);\n\n        if (actives != null) {\n            instance.setActives(actives);\n        }\n        if (async != null) {\n            instance.setAsync(async);\n        }\n        if (!StringUtils.isEmpty(cache)) {\n            instance.setCache(cache);\n        }\n        if (forks != null) {\n            instance.setForks(forks);\n        }\n        if (!StringUtils.isEmpty(loadbalance)) {\n            instance.setLoadbalance(loadbalance);\n        }\n        if (!StringUtils.isEmpty(merger)) {\n            instance.setMerger(merger);\n        }\n        if (!StringUtils.isEmpty(mock)) {\n            instance.setMock(mock);\n        }\n        if (retries != null) {\n            instance.setRetries(retries);\n        }\n        if (sent != null) {\n            instance.setSent(sent);\n        }\n        if (timeout != null) {\n            instance.setTimeout(timeout);\n        }\n        if (!StringUtils.isEmpty(validation)) {\n            instance.setValidation(validation);\n        }\n        if (parameters != null) {\n            instance.setParameters(parameters);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/AbstractReferenceBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.AbstractReferenceConfig;\n\n/**\n * AbstractBuilder\n *\n * @since 2.7\n */\npublic abstract class AbstractReferenceBuilder<\n                T extends AbstractReferenceConfig, B extends AbstractReferenceBuilder<T, B>>\n        extends AbstractInterfaceBuilder<T, B> {\n\n    /**\n     * Check if service provider exists, if not exists, it will be fast fail\n     */\n    protected Boolean check;\n\n    /**\n     * Whether to eagle-init\n     */\n    protected Boolean init;\n\n    /**\n     * Whether to use generic interface\n     */\n    protected String generic;\n\n    /**\n     * Whether to find reference's instance from the current JVM\n     */\n    protected Boolean injvm;\n\n    /**\n     * Lazy create connection\n     */\n    protected Boolean lazy;\n\n    protected String reconnect;\n\n    protected Boolean sticky;\n\n    /**\n     * The remote service version the customer side will reference\n     */\n    protected String version;\n\n    /**\n     * The remote service group the customer side will reference\n     */\n    protected String group;\n\n    public B check(Boolean check) {\n        this.check = check;\n        return getThis();\n    }\n\n    public B init(Boolean init) {\n        this.init = init;\n        return getThis();\n    }\n\n    public B generic(String generic) {\n        this.generic = generic;\n        return getThis();\n    }\n\n    public B generic(Boolean generic) {\n        if (generic != null) {\n            this.generic = generic.toString();\n        } else {\n            this.generic = null;\n        }\n        return getThis();\n    }\n\n    /**\n     * @param injvm\n     * @see AbstractInterfaceBuilder#scope(String)\n     * @deprecated instead, use the parameter <b>scope</b> to judge if it's in jvm, scope=local\n     */\n    @Deprecated\n    public B injvm(Boolean injvm) {\n        this.injvm = injvm;\n        return getThis();\n    }\n\n    public B lazy(Boolean lazy) {\n        this.lazy = lazy;\n        return getThis();\n    }\n\n    public B reconnect(String reconnect) {\n        this.reconnect = reconnect;\n        return getThis();\n    }\n\n    public B sticky(Boolean sticky) {\n        this.sticky = sticky;\n        return getThis();\n    }\n\n    public B version(String version) {\n        this.version = version;\n        return getThis();\n    }\n\n    public B group(String group) {\n        this.group = group;\n        return getThis();\n    }\n\n    @Override\n    public void build(T instance) {\n        super.build(instance);\n\n        if (check != null) {\n            instance.setCheck(check);\n        }\n        if (init != null) {\n            instance.setInit(init);\n        }\n        if (!StringUtils.isEmpty(generic)) {\n            instance.setGeneric(generic);\n        }\n        if (injvm != null) {\n            instance.setInjvm(injvm);\n        }\n        if (lazy != null) {\n            instance.setLazy(lazy);\n        }\n        if (!StringUtils.isEmpty(reconnect)) {\n            instance.setReconnect(reconnect);\n        }\n        if (sticky != null) {\n            instance.setSticky(sticky);\n        }\n        if (!StringUtils.isEmpty(version)) {\n            instance.setVersion(version);\n        }\n        if (!StringUtils.isEmpty(group)) {\n            instance.setGroup(group);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/AbstractServiceBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.AbstractServiceConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Executor;\n\n/**\n * AbstractBuilder\n *\n * @since 2.7\n */\npublic abstract class AbstractServiceBuilder<T extends AbstractServiceConfig, B extends AbstractServiceBuilder<T, B>>\n        extends AbstractInterfaceBuilder<T, B> {\n\n    /**\n     * The service version\n     */\n    protected String version;\n\n    /**\n     * The service group\n     */\n    protected String group;\n\n    /**\n     * whether the service is deprecated\n     */\n    protected Boolean deprecated;\n\n    /**\n     * The time delay register service (milliseconds)\n     */\n    protected Integer delay;\n\n    /**\n     * Whether to export the service\n     */\n    protected Boolean export;\n\n    /**\n     * The service weight\n     */\n    protected Integer weight;\n\n    /**\n     * Document center\n     */\n    protected String document;\n\n    /**\n     * Whether to register as a dynamic service or not on register center, it the value is false, the status will be disabled\n     * after the service registered,and it needs to be enabled manually; if you want to disable the service, you also need\n     * manual processing\n     */\n    protected Boolean dynamic;\n\n    /**\n     * Whether to use token\n     */\n    protected String token;\n\n    /**\n     * Whether to export access logs to logs\n     */\n    protected String accesslog;\n\n    /**\n     * The protocol list the service will export with\n     */\n    protected List<ProtocolConfig> protocols;\n\n    protected String protocolIds;\n\n    // max allowed execute times\n    private Integer executes;\n\n    /**\n     * Whether to register\n     */\n    private Boolean register;\n\n    /**\n     * Warm up period\n     */\n    private Integer warmup;\n\n    /**\n     * The serialization type\n     */\n    private String serialization;\n\n    /**\n     * used for thread pool isolation between services\n     */\n    private Executor executor;\n\n    /**\n     * The prefer serialization type\n     */\n    private String preferSerialization;\n\n    public B version(String version) {\n        this.version = version;\n        return getThis();\n    }\n\n    public B group(String group) {\n        this.group = group;\n        return getThis();\n    }\n\n    public B deprecated(Boolean deprecated) {\n        this.deprecated = deprecated;\n        return getThis();\n    }\n\n    public B delay(Integer delay) {\n        this.delay = delay;\n        return getThis();\n    }\n\n    public B export(Boolean export) {\n        this.export = export;\n        return getThis();\n    }\n\n    public B weight(Integer weight) {\n        this.weight = weight;\n        return getThis();\n    }\n\n    public B document(String document) {\n        this.document = document;\n        return getThis();\n    }\n\n    public B dynamic(Boolean dynamic) {\n        this.dynamic = dynamic;\n        return getThis();\n    }\n\n    public B token(String token) {\n        this.token = token;\n        return getThis();\n    }\n\n    public B token(Boolean token) {\n        if (token != null) {\n            this.token = token.toString();\n        } else {\n            this.token = null;\n        }\n        return getThis();\n    }\n\n    public B accesslog(String accesslog) {\n        this.accesslog = accesslog;\n        return getThis();\n    }\n\n    public B accesslog(Boolean accesslog) {\n        if (accesslog != null) {\n            this.accesslog = accesslog.toString();\n        } else {\n            this.accesslog = null;\n        }\n        return getThis();\n    }\n\n    public B addProtocols(List<ProtocolConfig> protocols) {\n        if (this.protocols == null) {\n            this.protocols = new ArrayList<>();\n        }\n        this.protocols.addAll(protocols);\n        return getThis();\n    }\n\n    public B addProtocol(ProtocolConfig protocol) {\n        if (this.protocols == null) {\n            this.protocols = new ArrayList<>();\n        }\n        this.protocols.add(protocol);\n        return getThis();\n    }\n\n    public B protocolIds(String protocolIds) {\n        this.protocolIds = protocolIds;\n        return getThis();\n    }\n\n    public B executes(Integer executes) {\n        this.executes = executes;\n        return getThis();\n    }\n\n    public B register(Boolean register) {\n        this.register = register;\n        return getThis();\n    }\n\n    public B warmup(Integer warmup) {\n        this.warmup = warmup;\n        return getThis();\n    }\n\n    public B serialization(String serialization) {\n        this.serialization = serialization;\n        return getThis();\n    }\n\n    public B executor(Executor executor) {\n        this.executor = executor;\n        return getThis();\n    }\n\n    /**\n     * The prefer serialization type\n     *\n     * @param preferSerialization prefer serialization type\n     * @return {@link B}\n     */\n    public B preferSerialization(String preferSerialization) {\n        this.preferSerialization = preferSerialization;\n        return getThis();\n    }\n\n    @Override\n    public void build(T instance) {\n        super.build(instance);\n\n        if (!StringUtils.isEmpty(version)) {\n            instance.setVersion(version);\n        }\n        if (!StringUtils.isEmpty(group)) {\n            instance.setGroup(group);\n        }\n        if (deprecated != null) {\n            instance.setDeprecated(deprecated);\n        }\n        if (delay != null) {\n            instance.setDelay(delay);\n        }\n        if (export != null) {\n            instance.setExport(export);\n        }\n        if (weight != null) {\n            instance.setWeight(weight);\n        }\n        if (!StringUtils.isEmpty(document)) {\n            instance.setDocument(document);\n        }\n        if (dynamic != null) {\n            instance.setDynamic(dynamic);\n        }\n        if (!StringUtils.isEmpty(token)) {\n            instance.setToken(token);\n        }\n        if (!StringUtils.isEmpty(accesslog)) {\n            instance.setAccesslog(accesslog);\n        }\n        if (protocols != null) {\n            instance.setProtocols(protocols);\n        }\n        if (!StringUtils.isEmpty(protocolIds)) {\n            instance.setProtocolIds(protocolIds);\n        }\n        if (executes != null) {\n            instance.setExecutes(executes);\n        }\n        if (register != null) {\n            instance.setRegister(register);\n        }\n        if (warmup != null) {\n            instance.setWarmup(warmup);\n        }\n        if (!StringUtils.isEmpty(serialization)) {\n            instance.setSerialization(serialization);\n        }\n        if (executor != null) {\n            instance.setExecutor(executor);\n        }\n        if (StringUtils.isNotBlank(preferSerialization)) {\n            instance.setPreferSerialization(preferSerialization);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ApplicationBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.RegistryConfig;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.apache.dubbo.config.Constants.PRODUCTION_ENVIRONMENT;\n\n/**\n * This is a builder for build {@link ApplicationConfig}.\n * @since 2.7\n */\npublic class ApplicationBuilder extends AbstractBuilder<ApplicationConfig, ApplicationBuilder> {\n    private String name;\n    private String metadata;\n    private String version;\n    private String owner;\n    private String organization;\n    private String architecture;\n    private String environment = PRODUCTION_ENVIRONMENT;\n    private String compiler;\n    private String logger;\n    private List<RegistryConfig> registries;\n    private String registryIds;\n    private MonitorConfig monitor;\n    private Boolean isDefault;\n    private String dumpDirectory;\n    private Boolean qosEnable;\n    private Integer qosPort;\n    private Boolean qosAcceptForeignIp;\n    private Map<String, String> parameters;\n    private String shutwait;\n    private Integer metadataServicePort;\n    private String livenessProbe;\n    private String readinessProbe;\n    private String startupProbe;\n\n    public static ApplicationBuilder newBuilder() {\n        return new ApplicationBuilder();\n    }\n\n    public ApplicationBuilder name(String name) {\n        this.name = name;\n        return getThis();\n    }\n\n    public ApplicationBuilder metadata(String metadata) {\n        this.metadata = metadata;\n        return getThis();\n    }\n\n    public ApplicationBuilder version(String version) {\n        this.version = version;\n        return getThis();\n    }\n\n    public ApplicationBuilder owner(String owner) {\n        this.owner = owner;\n        return getThis();\n    }\n\n    public ApplicationBuilder organization(String organization) {\n        this.organization = organization;\n        return getThis();\n    }\n\n    public ApplicationBuilder architecture(String architecture) {\n        this.architecture = architecture;\n        return getThis();\n    }\n\n    public ApplicationBuilder environment(String environment) {\n        this.environment = environment;\n        return getThis();\n    }\n\n    public ApplicationBuilder compiler(String compiler) {\n        this.compiler = compiler;\n        return getThis();\n    }\n\n    public ApplicationBuilder logger(String logger) {\n        this.logger = logger;\n        return getThis();\n    }\n\n    public ApplicationBuilder addRegistry(RegistryConfig registry) {\n        if (this.registries == null) {\n            this.registries = new ArrayList<>();\n        }\n        this.registries.add(registry);\n        return getThis();\n    }\n\n    public ApplicationBuilder addRegistries(List<? extends RegistryConfig> registries) {\n        if (this.registries == null) {\n            this.registries = new ArrayList<>();\n        }\n        this.registries.addAll(registries);\n        return getThis();\n    }\n\n    public ApplicationBuilder registryIds(String registryIds) {\n        this.registryIds = registryIds;\n        return getThis();\n    }\n\n    public ApplicationBuilder monitor(MonitorConfig monitor) {\n        this.monitor = monitor;\n        return getThis();\n    }\n\n    public ApplicationBuilder monitor(String monitor) {\n        this.monitor = new MonitorConfig(monitor);\n        return getThis();\n    }\n\n    public ApplicationBuilder isDefault(Boolean isDefault) {\n        this.isDefault = isDefault;\n        return getThis();\n    }\n\n    public ApplicationBuilder dumpDirectory(String dumpDirectory) {\n        this.dumpDirectory = dumpDirectory;\n        return getThis();\n    }\n\n    public ApplicationBuilder qosEnable(Boolean qosEnable) {\n        this.qosEnable = qosEnable;\n        return getThis();\n    }\n\n    public ApplicationBuilder qosPort(Integer qosPort) {\n        this.qosPort = qosPort;\n        return getThis();\n    }\n\n    public ApplicationBuilder qosAcceptForeignIp(Boolean qosAcceptForeignIp) {\n        this.qosAcceptForeignIp = qosAcceptForeignIp;\n        return getThis();\n    }\n\n    public ApplicationBuilder shutwait(String shutwait) {\n        this.shutwait = shutwait;\n        return getThis();\n    }\n\n    public ApplicationBuilder appendParameter(String key, String value) {\n        this.parameters = appendParameter(parameters, key, value);\n        return getThis();\n    }\n\n    public ApplicationBuilder appendParameters(Map<String, String> appendParameters) {\n        this.parameters = appendParameters(parameters, appendParameters);\n        return getThis();\n    }\n\n    public ApplicationBuilder metadataServicePort(Integer metadataServicePort) {\n        this.metadataServicePort = metadataServicePort;\n        return getThis();\n    }\n\n    public ApplicationBuilder livenessProbe(String livenessProbe) {\n        this.livenessProbe = livenessProbe;\n        return getThis();\n    }\n\n    public ApplicationBuilder readinessProbe(String readinessProbe) {\n        this.readinessProbe = readinessProbe;\n        return getThis();\n    }\n\n    public ApplicationBuilder startupProbe(String startupProbe) {\n        this.startupProbe = startupProbe;\n        return getThis();\n    }\n\n    public ApplicationConfig build() {\n        ApplicationConfig config = new ApplicationConfig();\n        super.build(config);\n\n        config.setName(name);\n        config.setMetadataType(metadata);\n        config.setVersion(this.version);\n        config.setOwner(this.owner);\n        config.setOrganization(this.organization);\n        config.setArchitecture(this.architecture);\n        config.setEnvironment(this.environment);\n        config.setCompiler(this.compiler);\n        config.setLogger(this.logger);\n        config.setRegistries(this.registries);\n        config.setRegistryIds(this.registryIds);\n        config.setMonitor(this.monitor);\n        config.setDefault(this.isDefault);\n        config.setDumpDirectory(this.dumpDirectory);\n        config.setQosEnable(this.qosEnable);\n        config.setQosPort(this.qosPort);\n        config.setQosAcceptForeignIp(this.qosAcceptForeignIp);\n        config.setMetadataServicePort(this.metadataServicePort);\n        config.setLivenessProbe(this.livenessProbe);\n        config.setReadinessProbe(this.readinessProbe);\n        config.setStartupProbe(this.startupProbe);\n        config.setParameters(this.parameters);\n        if (!StringUtils.isEmpty(shutwait)) {\n            config.setShutwait(shutwait);\n        }\n        return config;\n    }\n\n    @Override\n    protected ApplicationBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ArgumentBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ArgumentConfig;\n\n/**\n * This is a builder for build {@link ArgumentConfig}.\n * @since 2.7\n */\npublic class ArgumentBuilder {\n    /**\n     * The argument index: index -1 represents not set\n     */\n    private Integer index = -1;\n\n    /**\n     * Argument type\n     */\n    private String type;\n\n    /**\n     * Whether the argument is the callback interface\n     */\n    private Boolean callback;\n\n    public static ArgumentBuilder newBuilder() {\n        return new ArgumentBuilder();\n    }\n\n    public ArgumentBuilder index(Integer index) {\n        this.index = index;\n        return this;\n    }\n\n    public ArgumentBuilder type(String type) {\n        this.type = type;\n        return this;\n    }\n\n    public ArgumentBuilder callback(Boolean callback) {\n        this.callback = callback;\n        return this;\n    }\n\n    public ArgumentConfig build() {\n        ArgumentConfig argumentConfig = new ArgumentConfig();\n        argumentConfig.setIndex(index);\n        argumentConfig.setType(type);\n        argumentConfig.setCallback(callback);\n        return argumentConfig;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ConfigCenterBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ConfigCenterConfig;\n\nimport java.util.Map;\n\n/**\n * This is a builder for build {@link ConfigCenterConfig}.\n *\n * @since 2.7\n */\npublic class ConfigCenterBuilder extends AbstractBuilder<ConfigCenterConfig, ConfigCenterBuilder> {\n\n    private String protocol;\n    private String address;\n    private String cluster;\n    private String namespace = \"dubbo\";\n    private String group = \"dubbo\";\n    private String username;\n    private String password;\n    private Long timeout = 3000L;\n    private Boolean highestPriority = true;\n    private Boolean check = true;\n\n    private String configFile = \"dubbo.properties\";\n    private String appConfigFile;\n\n    private Map<String, String> parameters;\n\n    public static ConfigCenterBuilder newBuilder() {\n        return new ConfigCenterBuilder();\n    }\n\n    public ConfigCenterBuilder protocol(String protocol) {\n        this.protocol = protocol;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder address(String address) {\n        this.address = address;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder cluster(String cluster) {\n        this.cluster = cluster;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder namespace(String namespace) {\n        this.namespace = namespace;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder group(String group) {\n        this.group = group;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder username(String username) {\n        this.username = username;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder password(String password) {\n        this.password = password;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder timeout(Long timeout) {\n        this.timeout = timeout;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder highestPriority(Boolean highestPriority) {\n        this.highestPriority = highestPriority;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder check(Boolean check) {\n        this.check = check;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder configFile(String configFile) {\n        this.configFile = configFile;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder appConfigFile(String appConfigFile) {\n        this.appConfigFile = appConfigFile;\n        return getThis();\n    }\n\n    public ConfigCenterBuilder appendParameters(Map<String, String> appendParameters) {\n        this.parameters = appendParameters(this.parameters, appendParameters);\n        return getThis();\n    }\n\n    public ConfigCenterBuilder appendParameter(String key, String value) {\n        this.parameters = appendParameter(this.parameters, key, value);\n        return getThis();\n    }\n\n    @Override\n    public ConfigCenterConfig build() {\n        ConfigCenterConfig configCenter = new ConfigCenterConfig();\n        super.build(configCenter);\n\n        configCenter.setProtocol(protocol);\n        configCenter.setAddress(address);\n        configCenter.setCluster(cluster);\n        configCenter.setNamespace(namespace);\n        configCenter.setGroup(group);\n        configCenter.setUsername(username);\n        configCenter.setPassword(password);\n        configCenter.setTimeout(timeout);\n        configCenter.setHighestPriority(highestPriority);\n        configCenter.setCheck(check);\n        configCenter.setConfigFile(configFile);\n        configCenter.setAppConfigFile(appConfigFile);\n        configCenter.setParameters(parameters);\n\n        return configCenter;\n    }\n\n    @Override\n    protected ConfigCenterBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ConsumerBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ConsumerConfig;\n\n/**\n * This is a builder for build {@link ConsumerConfig}.\n *\n * @since 2.7\n */\npublic class ConsumerBuilder extends AbstractReferenceBuilder<ConsumerConfig, ConsumerBuilder> {\n\n    /**\n     * Whether to use the default protocol\n     */\n    private Boolean isDefault;\n\n    /**\n     * Networking framework client uses: netty, mina, etc.\n     */\n    private String client;\n\n    /**\n     * Consumer thread pool type: cached, fixed, limit, eager\n     */\n    private String threadpool;\n\n    /**\n     * Consumer threadpool core thread size\n     */\n    private Integer corethreads;\n\n    /**\n     * Consumer threadpool thread size\n     */\n    private Integer threads;\n\n    /**\n     * Consumer threadpool queue size\n     */\n    private Integer queues;\n\n    /**\n     * By default, a TCP long-connection communication is shared between the consumer process and the provider process.\n     * This property can be set to share multiple TCP long-connection communications. Note that only the dubbo protocol takes effect.\n     */\n    private Integer shareconnections;\n\n    /**\n     *  Url Merge Processor\n     *  Used to customize the URL merge of consumer and provider\n     */\n    private String urlMergeProcessor;\n\n    public static ConsumerBuilder newBuilder() {\n        return new ConsumerBuilder();\n    }\n\n    public ConsumerBuilder isDefault(Boolean isDefault) {\n        this.isDefault = isDefault;\n        return getThis();\n    }\n\n    public ConsumerBuilder client(String client) {\n        this.client = client;\n        return getThis();\n    }\n\n    public ConsumerBuilder threadPool(String threadPool) {\n        this.threadpool = threadPool;\n        return getThis();\n    }\n\n    public ConsumerBuilder coreThreads(Integer coreThreads) {\n        this.corethreads = coreThreads;\n        return getThis();\n    }\n\n    public ConsumerBuilder threads(Integer threads) {\n        this.threads = threads;\n        return getThis();\n    }\n\n    public ConsumerBuilder queues(Integer queues) {\n        this.queues = queues;\n        return getThis();\n    }\n\n    public ConsumerBuilder shareConnections(Integer shareConnections) {\n        this.shareconnections = shareConnections;\n        return getThis();\n    }\n\n    public ConsumerBuilder urlMergeProcessor(String urlMergeProcessor) {\n        this.urlMergeProcessor = urlMergeProcessor;\n        return getThis();\n    }\n\n    @Override\n    public ConsumerConfig build() {\n        ConsumerConfig consumer = new ConsumerConfig();\n        super.build(consumer);\n\n        consumer.setDefault(isDefault);\n        consumer.setClient(client);\n        consumer.setThreadpool(threadpool);\n        consumer.setCorethreads(corethreads);\n        consumer.setThreads(threads);\n        consumer.setQueues(queues);\n        consumer.setShareconnections(shareconnections);\n        consumer.setUrlMergeProcessor(urlMergeProcessor);\n\n        return consumer;\n    }\n\n    @Override\n    protected ConsumerBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/InternalServiceConfigBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProtocolServer;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Executor;\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY;\n\npublic class InternalServiceConfigBuilder<T> {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n    private static final Set<String> ACCEPTABLE_PROTOCOL =\n            Stream.of(\"dubbo\", \"tri\", \"injvm\").collect(Collectors.toSet());\n\n    private final ApplicationModel applicationModel;\n    private String protocol;\n    private Integer port;\n    private String registryId;\n    private Class<T> interfaceClass;\n    private Executor executor;\n    private T ref;\n    private String version;\n\n    private InternalServiceConfigBuilder(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    public static <T> InternalServiceConfigBuilder<T> newBuilder(ApplicationModel applicationModel) {\n        return new InternalServiceConfigBuilder<>(applicationModel);\n    }\n\n    public InternalServiceConfigBuilder<T> interfaceClass(Class<T> interfaceClass) {\n        this.interfaceClass = interfaceClass;\n        return getThis();\n    }\n\n    public InternalServiceConfigBuilder<T> executor(Executor executor) {\n        this.executor = executor;\n        return getThis();\n    }\n\n    public InternalServiceConfigBuilder<T> ref(T ref) {\n        this.ref = ref;\n        return getThis();\n    }\n\n    public InternalServiceConfigBuilder<T> registryId(String registryId) {\n        this.registryId = registryId;\n        return getThis();\n    }\n\n    public InternalServiceConfigBuilder<T> protocol(String protocol, String key) {\n        if (StringUtils.isEmpty(protocol) && StringUtils.isNotBlank(key)) {\n            Map<String, String> params = getApplicationConfig().getParameters();\n\n            if (CollectionUtils.isNotEmptyMap(params)) {\n                protocol = params.get(key);\n            }\n        }\n        this.protocol = StringUtils.isNotEmpty(protocol) ? protocol : getRelatedOrDefaultProtocol();\n\n        return getThis();\n    }\n\n    public InternalServiceConfigBuilder<T> version(String version) {\n        this.version = version;\n        return getThis();\n    }\n\n    /**\n     * Get other configured protocol from environment in priority order. If get nothing, use default dubbo.\n     *\n     * @return\n     */\n    private String getRelatedOrDefaultProtocol() {\n        String protocol = \"\";\n        // <dubbo:protocol/>\n        if (StringUtils.isEmpty(protocol)) {\n            Collection<ProtocolConfig> protocols =\n                    applicationModel.getApplicationConfigManager().getProtocols();\n            if (CollectionUtils.isNotEmpty(protocols)) {\n                protocol = protocols.stream()\n                        .map(ProtocolConfig::getName)\n                        .filter(StringUtils::isNotEmpty)\n                        .filter(p -> ACCEPTABLE_PROTOCOL.contains(p))\n                        .findFirst()\n                        .orElse(\"\");\n            }\n        }\n        // <dubbo:provider/>\n        List<ModuleModel> moduleModels = applicationModel.getPubModuleModels();\n        if (StringUtils.isEmpty(protocol)) {\n            Stream<ProviderConfig> providerConfigStream = moduleModels.stream()\n                    .map(ModuleModel::getConfigManager)\n                    .map(ModuleConfigManager::getProviders)\n                    .filter(CollectionUtils::isNotEmpty)\n                    .flatMap(Collection::stream);\n            protocol = providerConfigStream\n                    .filter((providerConfig) -> providerConfig.getProtocol() != null\n                            || CollectionUtils.isNotEmpty(providerConfig.getProtocols()))\n                    .map(providerConfig -> {\n                        if (providerConfig.getProtocol() != null\n                                && StringUtils.isNotEmpty(\n                                        providerConfig.getProtocol().getName())) {\n                            return providerConfig.getProtocol().getName();\n                        } else {\n                            return providerConfig.getProtocols().stream()\n                                    .map(ProtocolConfig::getName)\n                                    .filter(StringUtils::isNotEmpty)\n                                    .findFirst()\n                                    .orElse(\"\");\n                        }\n                    })\n                    .filter(StringUtils::isNotEmpty)\n                    .filter(p -> ACCEPTABLE_PROTOCOL.contains(p))\n                    .findFirst()\n                    .orElse(\"\");\n        }\n        // <dubbo:application/>\n        if (StringUtils.isEmpty(protocol)) {\n            protocol = getApplicationConfig().getProtocol();\n            if (StringUtils.isEmpty(protocol)) {\n                Map<String, String> params = getApplicationConfig().getParameters();\n                if (CollectionUtils.isNotEmptyMap(params)) {\n                    protocol = params.get(APPLICATION_PROTOCOL_KEY);\n                }\n            }\n        }\n        // <dubbo:consumer/>\n        if (StringUtils.isEmpty(protocol)) {\n            protocol = moduleModels.stream()\n                    .map(ModuleModel::getConfigManager)\n                    .map(ModuleConfigManager::getConsumers)\n                    .filter(CollectionUtils::isNotEmpty)\n                    .flatMap(Collection::stream)\n                    .map(ConsumerConfig::getProtocol)\n                    .filter(StringUtils::isNotEmpty)\n                    .filter(p -> ACCEPTABLE_PROTOCOL.contains(p))\n                    .findFirst()\n                    .orElse(\"\");\n        }\n        return StringUtils.isNotEmpty(protocol) && ACCEPTABLE_PROTOCOL.contains(protocol) ? protocol : DUBBO_PROTOCOL;\n    }\n\n    public InternalServiceConfigBuilder<T> protocol(String protocol) {\n        this.protocol(protocol, null);\n        return getThis();\n    }\n\n    public InternalServiceConfigBuilder<T> port(Integer specPort) {\n        return port(specPort, null);\n    }\n\n    public InternalServiceConfigBuilder<T> port(Integer specPort, String key) {\n        Assert.notEmptyString(this.protocol, \"export protocol is null\");\n        Assert.notNull(this.interfaceClass, \"export interfaceClass is null\");\n\n        if (specPort != null) {\n            this.port = specPort;\n            return getThis();\n        }\n        Map<String, String> params = getApplicationConfig().getParameters();\n        if (CollectionUtils.isNotEmptyMap(params) && StringUtils.isNotBlank(key)) {\n            String rawPort = getApplicationConfig().getParameters().get(key);\n            if (StringUtils.isNotEmpty(rawPort)) {\n                specPort = Integer.parseInt(rawPort);\n            }\n        }\n\n        if (specPort == null || specPort < -1) {\n            try {\n                if (logger.isInfoEnabled()) {\n                    logger.info(interfaceClass.getName()\n                            + \"Service Port hasn't been set will use default protocol defined in protocols.\");\n                }\n\n                Protocol protocol =\n                        applicationModel.getExtensionLoader(Protocol.class).getExtension(this.protocol);\n                if (protocol != null && protocol.getServers() != null) {\n                    Iterator<ProtocolServer> it = protocol.getServers().iterator();\n                    // export service may export before normal service export, it.hasNext() will return false.\n                    // so need use specified protocol port.\n                    if (it.hasNext()) {\n                        ProtocolServer server = it.next();\n                        String rawPort = server.getUrl().getParameter(BIND_PORT_KEY);\n                        if (rawPort == null) {\n                            String addr = server.getAddress();\n                            rawPort = addr.substring(addr.indexOf(\":\") + 1);\n                        }\n                        this.port = Integer.parseInt(rawPort);\n                    } else {\n                        ProtocolConfig specifiedProtocolConfig = getProtocolConfig();\n                        if (specifiedProtocolConfig != null) {\n                            Integer protocolPort = specifiedProtocolConfig.getPort();\n                            if (null != protocolPort && protocolPort != -1) {\n                                this.port = protocolPort;\n                            }\n                        }\n                    }\n                }\n            } catch (Exception e) {\n                logger.error(\n                        INTERNAL_ERROR,\n                        \"invalid specified \" + port + \"  port, error \" + e.getMessage(),\n                        \"\",\n                        \"Failed to find any valid protocol, will use random port to export  service.\",\n                        e);\n            }\n        }\n        if (this.port == null) {\n            this.port = -1;\n        }\n        return getThis();\n    }\n\n    private ProtocolConfig getProtocolConfig() {\n        return applicationModel\n                .getApplicationConfigManager()\n                .getProtocol(protocol)\n                .orElse(null);\n    }\n\n    public ServiceConfig<T> build(Consumer<ServiceConfig<T>> configConsumer) {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        protocolConfig.setName(this.protocol);\n        protocolConfig.setPort(this.port);\n\n        this.nullAssert();\n\n        logger.info(\"[SERVICE_PUBLISH] [METADATA_REGISTER] Using \" + this.protocol + \" protocol to export \"\n                + interfaceClass.getName() + \" service on port \" + protocolConfig.getPort());\n\n        applicationModel\n                .getApplicationConfigManager()\n                .getProtocol(this.protocol)\n                .ifPresent(p -> {\n                    protocolConfig.mergeProtocol(p);\n                    // clear extra protocols possibly merged from global ProtocolConfig\n                    protocolConfig.setExtProtocol(null);\n                });\n\n        ApplicationConfig applicationConfig = getApplicationConfig();\n\n        ServiceConfig<T> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setScopeModel(applicationModel.getInternalModule());\n        serviceConfig.setApplication(applicationConfig);\n\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.refresh();\n        registryConfig.setNeedRefresh(false);\n        registryConfig.setId(this.registryId);\n        registryConfig.setAddress(\"N/A\");\n        registryConfig.setScopeModel(this.applicationModel);\n\n        serviceConfig.setRegistry(registryConfig);\n\n        serviceConfig.setRegister(false);\n        serviceConfig.setProtocol(protocolConfig);\n        serviceConfig.setDelay(0);\n        serviceConfig.setInterface(interfaceClass);\n        serviceConfig.setRef(this.ref);\n        serviceConfig.setGroup(applicationConfig.getName());\n\n        if (StringUtils.isNotEmpty(version)) {\n            serviceConfig.setVersion(version);\n        } else {\n            serviceConfig.setVersion(\"1.0.0\");\n        }\n        serviceConfig.setFilter(\"-default\");\n\n        serviceConfig.setExecutor(executor);\n\n        if (null != configConsumer) {\n            configConsumer.accept(serviceConfig);\n        }\n\n        return serviceConfig;\n    }\n\n    public ServiceConfig<T> build() {\n        return build(null);\n    }\n\n    private void nullAssert() {\n        Assert.notNull(port, \"export service port is null\");\n        Assert.notNull(protocol, \"export service protocol is null\");\n        Assert.notNull(interfaceClass, \"export service interfaceClass is null\");\n        Assert.notNull(ref, \"export service ref is null\");\n        Assert.notNull(registryId, \"export service registryId is null\");\n    }\n\n    protected InternalServiceConfigBuilder<T> getThis() {\n        return this;\n    }\n\n    private ApplicationConfig getApplicationConfig() {\n        return applicationModel.getApplicationConfigManager().getApplicationOrElseThrow();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/MetadataReportBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.MetadataReportConfig;\n\nimport java.util.Map;\n\n/**\n * This is a builder for build {@link MetadataReportConfig}.\n *\n * @since 2.7\n */\npublic class MetadataReportBuilder extends AbstractBuilder<MetadataReportConfig, MetadataReportBuilder> {\n\n    /**\n     * Register center address\n     */\n    private String address;\n\n    /**\n     * Username to login register center\n     */\n    private String username;\n\n    /**\n     * Password to login register center\n     */\n    private String password;\n\n    /**\n     * Request timeout in milliseconds for register center\n     */\n    private Integer timeout;\n\n    /**\n     * The group the metadata in . It is the same as registry\n     */\n    private String group;\n\n    /**\n     * Customized parameters\n     */\n    private Map<String, String> parameters;\n\n    private Integer retryTimes;\n\n    private Integer retryPeriod;\n    /**\n     * By default the metadata store will store full metadata repeatedly every day .\n     */\n    private Boolean cycleReport;\n\n    /**\n     * Sync report, default async\n     */\n    private Boolean syncReport;\n\n    /**\n     * Decide the behaviour when initial connection try fails,\n     * 'true' means interrupt the whole process once fail.\n     * The default value is true\n     */\n    private Boolean check;\n\n    public static MetadataReportBuilder newBuilder() {\n        return new MetadataReportBuilder();\n    }\n\n    public MetadataReportBuilder address(String address) {\n        this.address = address;\n        return getThis();\n    }\n\n    public MetadataReportBuilder username(String username) {\n        this.username = username;\n        return getThis();\n    }\n\n    public MetadataReportBuilder password(String password) {\n        this.password = password;\n        return getThis();\n    }\n\n    public MetadataReportBuilder timeout(Integer timeout) {\n        this.timeout = timeout;\n        return getThis();\n    }\n\n    public MetadataReportBuilder group(String group) {\n        this.group = group;\n        return getThis();\n    }\n\n    public MetadataReportBuilder appendParameters(Map<String, String> appendParameters) {\n        this.parameters = appendParameters(this.parameters, appendParameters);\n        return getThis();\n    }\n\n    public MetadataReportBuilder appendParameter(String key, String value) {\n        this.parameters = appendParameter(this.parameters, key, value);\n        return getThis();\n    }\n\n    public MetadataReportBuilder retryTimes(Integer retryTimes) {\n        this.retryTimes = retryTimes;\n        return getThis();\n    }\n\n    public MetadataReportBuilder retryPeriod(Integer retryPeriod) {\n        this.retryPeriod = retryPeriod;\n        return getThis();\n    }\n\n    public MetadataReportBuilder cycleReport(Boolean cycleReport) {\n        this.cycleReport = cycleReport;\n        return getThis();\n    }\n\n    public MetadataReportBuilder syncReport(Boolean syncReport) {\n        this.syncReport = syncReport;\n        return getThis();\n    }\n\n    public MetadataReportBuilder check(Boolean check) {\n        this.check = check;\n        return getThis();\n    }\n\n    @Override\n    public MetadataReportConfig build() {\n        MetadataReportConfig metadataReport = new MetadataReportConfig();\n        super.build(metadataReport);\n\n        metadataReport.setAddress(address);\n        metadataReport.setUsername(username);\n        metadataReport.setPassword(password);\n        metadataReport.setTimeout(timeout);\n        metadataReport.setGroup(group);\n        metadataReport.setParameters(parameters);\n        metadataReport.setRetryTimes(retryTimes);\n        metadataReport.setRetryPeriod(retryPeriod);\n        metadataReport.setCycleReport(cycleReport);\n        metadataReport.setSyncReport(syncReport);\n        metadataReport.setCheck(check);\n\n        return metadataReport;\n    }\n\n    @Override\n    protected MetadataReportBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/MethodBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ArgumentConfig;\nimport org.apache.dubbo.config.MethodConfig;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * This is a builder for build {@link MethodConfig}.\n *\n * @since 2.7\n */\npublic class MethodBuilder extends AbstractMethodBuilder<MethodConfig, MethodBuilder> {\n    /**\n     * The method name\n     */\n    private String name;\n\n    /**\n     * Stat\n     */\n    private Integer stat;\n\n    /**\n     * Whether to retry\n     */\n    private Boolean retry;\n\n    /**\n     * If it's reliable\n     */\n    private Boolean reliable;\n\n    /**\n     * Thread limits for method invocations\n     */\n    private Integer executes;\n\n    /**\n     * If it's deprecated\n     */\n    private Boolean deprecated;\n\n    /**\n     * Whether to enable sticky\n     */\n    private Boolean sticky;\n\n    /**\n     * Whether need to return\n     */\n    private Boolean isReturn;\n\n    /**\n     * Callback instance when async-call is invoked\n     */\n    private Object oninvoke;\n\n    /**\n     * Callback method when async-call is invoked\n     */\n    private String oninvokeMethod;\n\n    /**\n     * Callback instance when async-call is returned\n     */\n    private Object onreturn;\n\n    /**\n     * Callback method when async-call is returned\n     */\n    private String onreturnMethod;\n\n    /**\n     * Callback instance when async-call has exception thrown\n     */\n    private Object onthrow;\n\n    /**\n     * Callback method when async-call has exception thrown\n     */\n    private String onthrowMethod;\n\n    /**\n     * The method arguments\n     */\n    private List<ArgumentConfig> arguments;\n\n    /**\n     * These properties come from MethodConfig's parent Config module, they will neither be collected directly from xml or API nor be delivered to url\n     */\n    private String service;\n\n    private String serviceId;\n\n    public static MethodBuilder newBuilder() {\n        return new MethodBuilder();\n    }\n\n    public MethodBuilder name(String name) {\n        this.name = name;\n        return getThis();\n    }\n\n    public MethodBuilder stat(Integer stat) {\n        this.stat = stat;\n        return getThis();\n    }\n\n    public MethodBuilder retry(Boolean retry) {\n        this.retry = retry;\n        return getThis();\n    }\n\n    public MethodBuilder reliable(Boolean reliable) {\n        this.reliable = reliable;\n        return getThis();\n    }\n\n    public MethodBuilder executes(Integer executes) {\n        this.executes = executes;\n        return getThis();\n    }\n\n    public MethodBuilder deprecated(Boolean deprecated) {\n        this.deprecated = deprecated;\n        return getThis();\n    }\n\n    public MethodBuilder sticky(Boolean sticky) {\n        this.sticky = sticky;\n        return getThis();\n    }\n\n    public MethodBuilder isReturn(Boolean isReturn) {\n        this.isReturn = isReturn;\n        return getThis();\n    }\n\n    public MethodBuilder oninvoke(Object oninvoke) {\n        this.oninvoke = oninvoke;\n        return getThis();\n    }\n\n    public MethodBuilder oninvokeMethod(String oninvokeMethod) {\n        this.oninvokeMethod = oninvokeMethod;\n        return getThis();\n    }\n\n    public MethodBuilder onreturn(Object onreturn) {\n        this.onreturn = onreturn;\n        return getThis();\n    }\n\n    public MethodBuilder onreturnMethod(String onreturnMethod) {\n        this.onreturnMethod = onreturnMethod;\n        return getThis();\n    }\n\n    public MethodBuilder onthrow(Object onthrow) {\n        this.onthrow = onthrow;\n        return getThis();\n    }\n\n    public MethodBuilder onthrowMethod(String onthrowMethod) {\n        this.onthrowMethod = onthrowMethod;\n        return getThis();\n    }\n\n    public MethodBuilder addArguments(List<? extends ArgumentConfig> arguments) {\n        if (this.arguments == null) {\n            this.arguments = new ArrayList<>();\n        }\n        this.arguments.addAll(arguments);\n        return getThis();\n    }\n\n    public MethodBuilder addArgument(ArgumentConfig argument) {\n        if (this.arguments == null) {\n            this.arguments = new ArrayList<>();\n        }\n        this.arguments.add(argument);\n        return getThis();\n    }\n\n    public MethodBuilder service(String service) {\n        this.service = service;\n        return getThis();\n    }\n\n    public MethodBuilder serviceId(String serviceId) {\n        this.serviceId = serviceId;\n        return getThis();\n    }\n\n    @Override\n    public MethodConfig build() {\n        MethodConfig methodConfig = new MethodConfig();\n        super.build(methodConfig);\n\n        methodConfig.setArguments(arguments);\n        methodConfig.setDeprecated(deprecated);\n        methodConfig.setExecutes(executes);\n        methodConfig.setName(name);\n        methodConfig.setOninvoke(oninvoke);\n        methodConfig.setOninvokeMethod(oninvokeMethod);\n        methodConfig.setOnreturn(onreturn);\n        methodConfig.setOnreturnMethod(onreturnMethod);\n        methodConfig.setOnthrow(onthrow);\n        methodConfig.setOnthrowMethod(onthrowMethod);\n        methodConfig.setReturn(isReturn);\n        methodConfig.setService(service);\n        methodConfig.setServiceId(serviceId);\n        methodConfig.setSticky(sticky);\n        methodConfig.setReliable(reliable);\n        methodConfig.setStat(stat);\n        methodConfig.setRetry(retry);\n\n        return methodConfig;\n    }\n\n    @Override\n    protected MethodBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/MetricsBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.nested.AggregationConfig;\nimport org.apache.dubbo.config.nested.HistogramConfig;\nimport org.apache.dubbo.config.nested.PrometheusConfig;\n\n/**\n * This is a builder for build {@link MetricsConfig}.\n */\npublic class MetricsBuilder extends AbstractBuilder<MetricsConfig, MetricsBuilder> {\n\n    private String protocol;\n\n    /**\n     * Enable jvm metrics when collecting.\n     */\n    private Boolean enableJvm;\n\n    /**\n     * Enable threadpool metrics when collecting.\n     */\n    private Boolean enableThreadpool;\n\n    /**\n     * Enable registry metrics.\n     */\n    private Boolean enableRegistry;\n\n    /**\n     * Enable metadata metrics.\n     */\n    private Boolean enableMetadata;\n\n    /**\n     * Export metrics service.\n     */\n    private Boolean exportMetricsService;\n\n    /**\n     * Enable metrics init.\n     */\n    private Boolean enableMetricsInit;\n\n    /**\n     * Enable collector sync.\n     */\n    private Boolean enableCollectorSync;\n\n    /**\n     * Collector sync period.\n     */\n    private Integer collectorSyncPeriod;\n\n    /**\n     * The prometheus metrics config\n     */\n    private PrometheusConfig prometheus;\n\n    /**\n     * The metrics aggregation config\n     */\n    private AggregationConfig aggregation;\n\n    private HistogramConfig histogram;\n\n    private String exportServiceProtocol;\n\n    private Integer exportServicePort;\n\n    /**\n     * Decide whether to use the global registry of the micrometer.\n     */\n    private Boolean useGlobalRegistry;\n\n    /**\n     * Enable rpc metrics.\n     */\n    private Boolean enableRpc;\n\n    /**\n     * The level of the metrics, the value can be \"SERVICE\", \"METHOD\", default is method.\n     */\n    private String rpcLevel;\n\n    public static MetricsBuilder newBuilder() {\n        return new MetricsBuilder();\n    }\n\n    public MetricsBuilder protocol(String protocol) {\n        this.protocol = protocol;\n        return getThis();\n    }\n\n    public MetricsBuilder enableJvm(Boolean enableJvm) {\n        this.enableJvm = enableJvm;\n        return getThis();\n    }\n\n    public MetricsBuilder enableThreadPool(Boolean enableThreadPool) {\n        this.enableThreadpool = enableThreadPool;\n        return getThis();\n    }\n\n    public MetricsBuilder enableRegistry(Boolean enableRegistry) {\n        this.enableRegistry = enableRegistry;\n        return getThis();\n    }\n\n    public MetricsBuilder enableMetadata(Boolean enableMetadata) {\n        this.enableMetadata = enableMetadata;\n        return getThis();\n    }\n\n    public MetricsBuilder exportMetricsService(Boolean exportMetricsService) {\n        this.exportMetricsService = exportMetricsService;\n        return getThis();\n    }\n\n    public MetricsBuilder enableMetricsInit(Boolean enableMetricsInit) {\n        this.enableMetricsInit = enableMetricsInit;\n        return getThis();\n    }\n\n    public MetricsBuilder enableCollectorSync(Boolean enableCollectorSync) {\n        this.enableCollectorSync = enableCollectorSync;\n        return getThis();\n    }\n\n    public MetricsBuilder collectorSyncPeriod(Integer collectorSyncPeriod) {\n        this.collectorSyncPeriod = collectorSyncPeriod;\n        return getThis();\n    }\n\n    public MetricsBuilder prometheus(PrometheusConfig prometheus) {\n        this.prometheus = prometheus;\n        return getThis();\n    }\n\n    public MetricsBuilder aggregation(AggregationConfig aggregation) {\n        this.aggregation = aggregation;\n        return getThis();\n    }\n\n    public MetricsBuilder histogram(HistogramConfig histogram) {\n        this.histogram = histogram;\n        return getThis();\n    }\n\n    public MetricsBuilder exportServiceProtocol(String exportServiceProtocol) {\n        this.exportServiceProtocol = exportServiceProtocol;\n        return getThis();\n    }\n\n    public MetricsBuilder exportServicePort(Integer exportServicePort) {\n        this.exportServicePort = exportServicePort;\n        return getThis();\n    }\n\n    public MetricsBuilder useGlobalRegistry(Boolean useGlobalRegistry) {\n        this.useGlobalRegistry = useGlobalRegistry;\n        return getThis();\n    }\n\n    public MetricsBuilder enableRpc(Boolean enableRpc) {\n        this.enableRpc = enableRpc;\n        return getThis();\n    }\n\n    public MetricsBuilder rpcLevel(String rpcLevel) {\n        this.rpcLevel = rpcLevel;\n        return getThis();\n    }\n\n    @Override\n    public MetricsConfig build() {\n        MetricsConfig metrics = new MetricsConfig();\n        super.build(metrics);\n\n        metrics.setProtocol(protocol);\n        metrics.setEnableJvm(enableJvm);\n        metrics.setEnableThreadpool(enableThreadpool);\n        metrics.setEnableRegistry(enableRegistry);\n        metrics.setEnableMetadata(enableMetadata);\n        metrics.setExportMetricsService(exportMetricsService);\n        metrics.setEnableMetricsInit(enableMetricsInit);\n        metrics.setEnableCollectorSync(enableCollectorSync);\n        metrics.setCollectorSyncPeriod(collectorSyncPeriod);\n        metrics.setPrometheus(prometheus);\n        metrics.setAggregation(aggregation);\n        metrics.setHistogram(histogram);\n        metrics.setExportServiceProtocol(exportServiceProtocol);\n        metrics.setExportServicePort(exportServicePort);\n        metrics.setUseGlobalRegistry(useGlobalRegistry);\n        metrics.setEnableRpc(enableRpc);\n        metrics.setRpcLevel(rpcLevel);\n        return metrics;\n    }\n\n    @Override\n    protected MetricsBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ModuleBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.RegistryConfig;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * This is a builder for build {@link ModuleConfig}.\n *\n * @since 2.7\n */\npublic class ModuleBuilder extends AbstractBuilder<ModuleConfig, ModuleBuilder> {\n    /**\n     * Module name\n     */\n    private String name;\n\n    /**\n     * Module version\n     */\n    private String version;\n\n    /**\n     * Module owner\n     */\n    private String owner;\n\n    /**\n     * Module's organization\n     */\n    private String organization;\n\n    /**\n     * Registry centers\n     */\n    private List<RegistryConfig> registries;\n\n    /**\n     * Monitor center\n     */\n    private MonitorConfig monitor;\n\n    /**\n     * If it's default\n     */\n    private Boolean isDefault;\n\n    public static ModuleBuilder newBuilder() {\n        return new ModuleBuilder();\n    }\n\n    public ModuleBuilder name(String name) {\n        this.name = name;\n        return getThis();\n    }\n\n    public ModuleBuilder version(String version) {\n        this.version = version;\n        return getThis();\n    }\n\n    public ModuleBuilder owner(String owner) {\n        this.owner = owner;\n        return getThis();\n    }\n\n    public ModuleBuilder organization(String organization) {\n        this.organization = organization;\n        return getThis();\n    }\n\n    public ModuleBuilder addRegistries(List<? extends RegistryConfig> registries) {\n        if (this.registries == null) {\n            this.registries = new ArrayList<>();\n        }\n        this.registries.addAll(registries);\n        return getThis();\n    }\n\n    public ModuleBuilder addRegistry(RegistryConfig registry) {\n        if (this.registries == null) {\n            this.registries = new ArrayList<>();\n        }\n        this.registries.add(registry);\n        return getThis();\n    }\n\n    public ModuleBuilder monitor(MonitorConfig monitor) {\n        this.monitor = monitor;\n        return getThis();\n    }\n\n    public ModuleBuilder isDefault(Boolean isDefault) {\n        this.isDefault = isDefault;\n        return getThis();\n    }\n\n    @Override\n    public ModuleConfig build() {\n        ModuleConfig moduleConfig = new ModuleConfig();\n        super.build(moduleConfig);\n\n        moduleConfig.setDefault(isDefault);\n        moduleConfig.setMonitor(monitor);\n        moduleConfig.setName(name);\n        moduleConfig.setOrganization(organization);\n        moduleConfig.setOwner(owner);\n        moduleConfig.setRegistries(registries);\n        moduleConfig.setVersion(version);\n\n        return moduleConfig;\n    }\n\n    @Override\n    protected ModuleBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/MonitorBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.MonitorConfig;\n\nimport java.util.Map;\n\n/**\n * This is a builder for build {@link MonitorConfig}.\n *\n * @since 2.7\n */\npublic class MonitorBuilder extends AbstractBuilder<MonitorConfig, MonitorBuilder> {\n    /**\n     * The protocol of the monitor, if the value is registry, it will search the monitor address from the registry center,\n     * otherwise, it will directly connect to the monitor center\n     */\n    private String protocol;\n\n    /**\n     * The monitor address\n     */\n    private String address;\n\n    /**\n     * The monitor user name\n     */\n    private String username;\n\n    /**\n     * The password\n     */\n    private String password;\n\n    private String group;\n\n    private String version;\n\n    private String interval;\n\n    /**\n     * customized parameters\n     */\n    private Map<String, String> parameters;\n\n    /**\n     * If it's default\n     */\n    private Boolean isDefault;\n\n    public static MonitorBuilder newBuilder() {\n        return new MonitorBuilder();\n    }\n\n    public MonitorBuilder protocol(String protocol) {\n        this.protocol = protocol;\n        return getThis();\n    }\n\n    public MonitorBuilder address(String address) {\n        this.address = address;\n        return getThis();\n    }\n\n    public MonitorBuilder username(String username) {\n        this.username = username;\n        return getThis();\n    }\n\n    public MonitorBuilder password(String password) {\n        this.password = password;\n        return getThis();\n    }\n\n    public MonitorBuilder group(String group) {\n        this.group = group;\n        return getThis();\n    }\n\n    public MonitorBuilder version(String version) {\n        this.version = version;\n        return getThis();\n    }\n\n    public MonitorBuilder interval(String interval) {\n        this.interval = interval;\n        return getThis();\n    }\n\n    public MonitorBuilder isDefault(Boolean isDefault) {\n        this.isDefault = isDefault;\n        return getThis();\n    }\n\n    public MonitorBuilder appendParameter(String key, String value) {\n        this.parameters = appendParameter(parameters, key, value);\n        return getThis();\n    }\n\n    public MonitorBuilder appendParameters(Map<String, String> appendParameters) {\n        this.parameters = appendParameters(parameters, appendParameters);\n        return getThis();\n    }\n\n    @Override\n    public MonitorConfig build() {\n        MonitorConfig monitorConfig = new MonitorConfig();\n        super.build(monitorConfig);\n\n        monitorConfig.setProtocol(protocol);\n        monitorConfig.setAddress(address);\n        monitorConfig.setUsername(username);\n        monitorConfig.setPassword(password);\n        monitorConfig.setGroup(group);\n        monitorConfig.setVersion(version);\n        monitorConfig.setInterval(interval);\n        monitorConfig.setParameters(parameters);\n        monitorConfig.setDefault(isDefault);\n\n        return monitorConfig;\n    }\n\n    @Override\n    protected MonitorBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ProtocolBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ProtocolConfig;\n\nimport java.util.Map;\n\n/**\n * This is a builder for build {@link ProtocolConfig}.\n *\n * @since 2.7\n */\npublic class ProtocolBuilder extends AbstractBuilder<ProtocolConfig, ProtocolBuilder> {\n    /**\n     * Protocol name\n     */\n    private String name;\n\n    /**\n     * Service ip address (when there are multiple network cards available)\n     */\n    private String host;\n\n    /**\n     * Service port\n     */\n    private Integer port;\n\n    /**\n     * Context path\n     */\n    private String contextpath;\n\n    /**\n     * Thread pool\n     */\n    private String threadpool;\n\n    /**\n     * Thread pool core thread size\n     */\n    private Integer corethreads;\n\n    /**\n     * Thread pool size (fixed size)\n     */\n    private Integer threads;\n\n    /**\n     * IO thread pool size (fixed size)\n     */\n    private Integer iothreads;\n\n    /**\n     * Thread pool's queue length\n     */\n    private Integer queues;\n\n    /**\n     * Max acceptable connections\n     */\n    private Integer accepts;\n\n    /**\n     * Protocol codec\n     */\n    private String codec;\n\n    /**\n     * Serialization\n     */\n    private String serialization;\n\n    /**\n     * Charset\n     */\n    private String charset;\n\n    /**\n     * Payload max length\n     */\n    private Integer payload;\n\n    /**\n     * Buffer size\n     */\n    private Integer buffer;\n\n    /**\n     * Heartbeat interval\n     */\n    private Integer heartbeat;\n\n    /**\n     * Access log\n     */\n    private String accesslog;\n\n    /**\n     * Transporter\n     */\n    private String transporter;\n\n    /**\n     * How information is exchanged\n     */\n    private String exchanger;\n\n    /**\n     * Thread dispatch mode\n     */\n    private String dispatcher;\n\n    /**\n     * Networker\n     */\n    private String networker;\n\n    /**\n     * Sever impl\n     */\n    private String server;\n\n    /**\n     * Client impl\n     */\n    private String client;\n\n    /**\n     * Supported telnet commands, separated with comma.\n     */\n    private String telnet;\n\n    /**\n     * Command line prompt\n     */\n    private String prompt;\n\n    /**\n     * Status check\n     */\n    private String status;\n\n    /**\n     * Whether to register\n     */\n    private Boolean register;\n\n    /**\n     * whether it is a persistent connection\n     */\n    // TODO add this to provider config\n    private Boolean keepAlive;\n\n    // TODO add this to provider config\n    private String optimizer;\n\n    /**\n     * The extension\n     */\n    private String extension;\n\n    /**\n     * The customized parameters\n     */\n    private Map<String, String> parameters;\n\n    private Boolean sslEnabled;\n\n    /*\n     * Extra Protocol for this service, using Port Unification Server\n     */\n    private String extProtocol;\n\n    /**\n     * If it's default\n     */\n    private Boolean isDefault;\n\n    public static ProtocolBuilder newBuilder() {\n        return new ProtocolBuilder();\n    }\n\n    public ProtocolBuilder id(String id) {\n        return super.id(id);\n    }\n\n    public ProtocolBuilder name(String name) {\n        this.name = name;\n        return getThis();\n    }\n\n    public ProtocolBuilder host(String host) {\n        this.host = host;\n        return getThis();\n    }\n\n    public ProtocolBuilder port(Integer port) {\n        this.port = port;\n        return getThis();\n    }\n\n    public ProtocolBuilder contextpath(String contextpath) {\n        this.contextpath = contextpath;\n        return getThis();\n    }\n\n    /**\n     * @param path\n     * @return ProtocolBuilder\n     * @see ProtocolBuilder#contextpath(String)\n     */\n    @Deprecated\n    public ProtocolBuilder path(String path) {\n        this.contextpath = path;\n        return getThis();\n    }\n\n    public ProtocolBuilder threadpool(String threadpool) {\n        this.threadpool = threadpool;\n        return getThis();\n    }\n\n    public ProtocolBuilder corethreads(Integer corethreads) {\n        this.corethreads = corethreads;\n        return getThis();\n    }\n\n    public ProtocolBuilder threads(Integer threads) {\n        this.threads = threads;\n        return getThis();\n    }\n\n    public ProtocolBuilder iothreads(Integer iothreads) {\n        this.iothreads = iothreads;\n        return getThis();\n    }\n\n    public ProtocolBuilder queues(Integer queues) {\n        this.queues = queues;\n        return getThis();\n    }\n\n    public ProtocolBuilder accepts(Integer accepts) {\n        this.accepts = accepts;\n        return getThis();\n    }\n\n    public ProtocolBuilder codec(String codec) {\n        this.codec = codec;\n        return getThis();\n    }\n\n    public ProtocolBuilder serialization(String serialization) {\n        this.serialization = serialization;\n        return getThis();\n    }\n\n    public ProtocolBuilder charset(String charset) {\n        this.charset = charset;\n        return getThis();\n    }\n\n    public ProtocolBuilder payload(Integer payload) {\n        this.payload = payload;\n        return getThis();\n    }\n\n    public ProtocolBuilder buffer(Integer buffer) {\n        this.buffer = buffer;\n        return getThis();\n    }\n\n    public ProtocolBuilder heartbeat(Integer heartbeat) {\n        this.heartbeat = heartbeat;\n        return getThis();\n    }\n\n    public ProtocolBuilder accesslog(String accesslog) {\n        this.accesslog = accesslog;\n        return getThis();\n    }\n\n    public ProtocolBuilder transporter(String transporter) {\n        this.transporter = transporter;\n        return getThis();\n    }\n\n    public ProtocolBuilder exchanger(String exchanger) {\n        this.exchanger = exchanger;\n        return getThis();\n    }\n\n    public ProtocolBuilder dispatcher(String dispatcher) {\n        this.dispatcher = dispatcher;\n        return getThis();\n    }\n\n    /**\n     * @param dispather\n     * @return ProtocolBuilder\n     * @see ProtocolBuilder#dispatcher(String)\n     */\n    @Deprecated\n    public ProtocolBuilder dispather(String dispather) {\n        this.dispatcher = dispather;\n        return getThis();\n    }\n\n    public ProtocolBuilder networker(String networker) {\n        this.networker = networker;\n        return getThis();\n    }\n\n    public ProtocolBuilder server(String server) {\n        this.server = server;\n        return getThis();\n    }\n\n    public ProtocolBuilder client(String client) {\n        this.client = client;\n        return getThis();\n    }\n\n    public ProtocolBuilder telnet(String telnet) {\n        this.telnet = telnet;\n        return getThis();\n    }\n\n    public ProtocolBuilder prompt(String prompt) {\n        this.prompt = prompt;\n        return getThis();\n    }\n\n    public ProtocolBuilder status(String status) {\n        this.status = status;\n        return getThis();\n    }\n\n    public ProtocolBuilder register(Boolean register) {\n        this.register = register;\n        return getThis();\n    }\n\n    public ProtocolBuilder keepAlive(Boolean keepAlive) {\n        this.keepAlive = keepAlive;\n        return getThis();\n    }\n\n    public ProtocolBuilder optimizer(String optimizer) {\n        this.optimizer = optimizer;\n        return getThis();\n    }\n\n    public ProtocolBuilder extension(String extension) {\n        this.extension = extension;\n        return getThis();\n    }\n\n    public ProtocolBuilder appendParameter(String key, String value) {\n        this.parameters = appendParameter(parameters, key, value);\n        return getThis();\n    }\n\n    public ProtocolBuilder appendParameters(Map<String, String> appendParameters) {\n        this.parameters = appendParameters(parameters, appendParameters);\n        return getThis();\n    }\n\n    public ProtocolBuilder isSslEnabled(Boolean sslEnabled) {\n        this.sslEnabled = sslEnabled;\n        return getThis();\n    }\n\n    public ProtocolBuilder extProtocol(String extProtocol) {\n        this.extProtocol = extProtocol;\n        return getThis();\n    }\n\n    public ProtocolBuilder isDefault(Boolean isDefault) {\n        this.isDefault = isDefault;\n        return getThis();\n    }\n\n    @Override\n    public ProtocolConfig build() {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        super.build(protocolConfig);\n\n        protocolConfig.setAccepts(accepts);\n        protocolConfig.setAccesslog(accesslog);\n        protocolConfig.setBuffer(buffer);\n        protocolConfig.setCharset(charset);\n        protocolConfig.setClient(client);\n        protocolConfig.setCodec(codec);\n        protocolConfig.setContextpath(contextpath);\n        protocolConfig.setCorethreads(corethreads);\n        protocolConfig.setDefault(isDefault);\n        protocolConfig.setDispatcher(dispatcher);\n        protocolConfig.setExchanger(exchanger);\n        protocolConfig.setExtension(extension);\n        protocolConfig.setHeartbeat(heartbeat);\n        protocolConfig.setHost(host);\n        protocolConfig.setIothreads(iothreads);\n        protocolConfig.setKeepAlive(keepAlive);\n        protocolConfig.setName(name);\n        protocolConfig.setNetworker(networker);\n        protocolConfig.setOptimizer(optimizer);\n        protocolConfig.setParameters(parameters);\n        protocolConfig.setPayload(payload);\n        protocolConfig.setPort(port);\n        protocolConfig.setPrompt(prompt);\n        protocolConfig.setQueues(queues);\n        protocolConfig.setRegister(register);\n        protocolConfig.setSerialization(serialization);\n        protocolConfig.setServer(server);\n        protocolConfig.setStatus(status);\n        protocolConfig.setTelnet(telnet);\n        protocolConfig.setThreadpool(threadpool);\n        protocolConfig.setThreads(threads);\n        protocolConfig.setTransporter(transporter);\n        protocolConfig.setSslEnabled(sslEnabled);\n        protocolConfig.setExtProtocol(extProtocol);\n\n        return protocolConfig;\n    }\n\n    @Override\n    protected ProtocolBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ProviderBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ProviderConfig;\n\n/**\n * This is a builder for build {@link ProviderConfig}.\n *\n * @since 2.7\n */\npublic class ProviderBuilder extends AbstractServiceBuilder<ProviderConfig, ProviderBuilder> {\n\n    /**\n     * Service ip addresses (used when there are multiple network cards available)\n     */\n    private String host;\n\n    /**\n     * Service port\n     */\n    private Integer port;\n\n    /**\n     * Context path\n     */\n    private String contextpath;\n\n    /**\n     * Thread pool\n     */\n    private String threadpool;\n\n    /**\n     * Thread pool name\n     */\n    private String threadname;\n\n    /**\n     * Thread pool size (fixed size)\n     */\n    private Integer threads;\n\n    /**\n     * IO thread pool size (fixed size)\n     */\n    private Integer iothreads;\n\n    /**\n     * Thread pool keepAliveTime, default unit TimeUnit.MILLISECONDS\n     */\n    private Integer alive;\n\n    /**\n     * Thread pool queue length\n     */\n    private Integer queues;\n\n    /**\n     * Max acceptable connections\n     */\n    private Integer accepts;\n\n    /**\n     * Protocol codec\n     */\n    private String codec;\n\n    /**\n     * The serialization charset\n     */\n    private String charset;\n\n    /**\n     * Payload max length\n     */\n    private Integer payload;\n\n    /**\n     * The network io buffer size\n     */\n    private Integer buffer;\n\n    /**\n     * Transporter\n     */\n    private String transporter;\n\n    /**\n     * How information gets exchanged\n     */\n    private String exchanger;\n\n    /**\n     * Thread dispatching mode\n     */\n    private String dispatcher;\n\n    /**\n     * Networker\n     */\n    private String networker;\n\n    /**\n     * The server-side implementation model of the protocol\n     */\n    private String server;\n\n    /**\n     * The client-side implementation model of the protocol\n     */\n    private String client;\n\n    /**\n     * Supported telnet commands, separated with comma.\n     */\n    private String telnet;\n\n    /**\n     * Command line prompt\n     */\n    private String prompt;\n\n    /**\n     * Status check\n     */\n    private String status;\n\n    /**\n     * Wait time when stop\n     */\n    private Integer wait;\n\n    /**\n     * Whether to use the default protocol\n     */\n    private Boolean isDefault;\n\n    public static ProviderBuilder newBuilder() {\n        return new ProviderBuilder();\n    }\n\n    public ProviderBuilder host(String host) {\n        this.host = host;\n        return getThis();\n    }\n\n    public ProviderBuilder port(Integer port) {\n        this.port = port;\n        return getThis();\n    }\n\n    public ProviderBuilder contextPath(String contextPath) {\n        this.contextpath = contextPath;\n        return getThis();\n    }\n\n    public ProviderBuilder threadPool(String threadPool) {\n        this.threadpool = threadPool;\n        return getThis();\n    }\n\n    public ProviderBuilder threadName(String threadName) {\n        this.threadname = threadName;\n        return getThis();\n    }\n\n    public ProviderBuilder threads(Integer threads) {\n        this.threads = threads;\n        return getThis();\n    }\n\n    public ProviderBuilder ioThreads(Integer ioThreads) {\n        this.iothreads = ioThreads;\n        return getThis();\n    }\n\n    public ProviderBuilder alive(Integer alive) {\n        this.alive = alive;\n        return getThis();\n    }\n\n    public ProviderBuilder queues(Integer queues) {\n        this.queues = queues;\n        return getThis();\n    }\n\n    public ProviderBuilder accepts(Integer accepts) {\n        this.accepts = accepts;\n        return getThis();\n    }\n\n    public ProviderBuilder codec(String codec) {\n        this.codec = codec;\n        return getThis();\n    }\n\n    public ProviderBuilder charset(String charset) {\n        this.charset = charset;\n        return getThis();\n    }\n\n    public ProviderBuilder payload(Integer payload) {\n        this.payload = payload;\n        return getThis();\n    }\n\n    public ProviderBuilder buffer(Integer buffer) {\n        this.buffer = buffer;\n        return getThis();\n    }\n\n    public ProviderBuilder transporter(String transporter) {\n        this.transporter = transporter;\n        return getThis();\n    }\n\n    public ProviderBuilder exchanger(String exchanger) {\n        this.exchanger = exchanger;\n        return getThis();\n    }\n\n    public ProviderBuilder dispatcher(String dispatcher) {\n        this.dispatcher = dispatcher;\n        return getThis();\n    }\n\n    public ProviderBuilder networker(String networker) {\n        this.networker = networker;\n        return getThis();\n    }\n\n    public ProviderBuilder server(String server) {\n        this.server = server;\n        return getThis();\n    }\n\n    public ProviderBuilder client(String client) {\n        this.client = client;\n        return getThis();\n    }\n\n    public ProviderBuilder telnet(String telnet) {\n        this.telnet = telnet;\n        return getThis();\n    }\n\n    public ProviderBuilder prompt(String prompt) {\n        this.prompt = prompt;\n        return getThis();\n    }\n\n    public ProviderBuilder status(String status) {\n        this.status = status;\n        return getThis();\n    }\n\n    public ProviderBuilder wait(Integer wait) {\n        this.wait = wait;\n        return getThis();\n    }\n\n    public ProviderBuilder isDefault(Boolean isDefault) {\n        this.isDefault = isDefault;\n        return getThis();\n    }\n\n    public ProviderConfig build() {\n        ProviderConfig provider = new ProviderConfig();\n        super.build(provider);\n\n        provider.setHost(host);\n        provider.setPort(port);\n        provider.setContextpath(contextpath);\n        provider.setThreadpool(threadpool);\n        provider.setThreadname(threadname);\n        provider.setThreads(threads);\n        provider.setIothreads(iothreads);\n        provider.setAlive(alive);\n        provider.setQueues(queues);\n        provider.setAccepts(accepts);\n        provider.setCodec(codec);\n        provider.setPayload(payload);\n        provider.setCharset(charset);\n        provider.setBuffer(buffer);\n        provider.setTransporter(transporter);\n        provider.setExchanger(exchanger);\n        provider.setDispatcher(dispatcher);\n        provider.setNetworker(networker);\n        provider.setServer(server);\n        provider.setClient(client);\n        provider.setTelnet(telnet);\n        provider.setPrompt(prompt);\n        provider.setStatus(status);\n        provider.setWait(wait);\n        provider.setDefault(isDefault);\n\n        return provider;\n    }\n\n    @Override\n    protected ProviderBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.ReferenceConfigBase;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.apache.dubbo.common.utils.StringUtils.toCommaDelimitedString;\n\n/**\n * This is a builder for build {@link ReferenceConfigBase}.\n *\n * @since 2.7\n */\npublic class ReferenceBuilder<T> extends AbstractReferenceBuilder<ReferenceConfig<T>, ReferenceBuilder<T>> {\n    /**\n     * The interface name of the reference service\n     */\n    private String interfaceName;\n\n    /**\n     * The interface class of the reference service\n     */\n    private Class<?> interfaceClass;\n\n    /**\n     * client type\n     */\n    private String client;\n\n    /**\n     * The url for peer-to-peer invocation\n     */\n    private String url;\n\n    /**\n     * The method configs\n     */\n    private List<MethodConfig> methods;\n\n    /**\n     * The consumer config (default)\n     */\n    private ConsumerConfig consumer;\n\n    /**\n     * Only the service provider of the specified protocol is invoked, and other protocols are ignored.\n     */\n    private String protocol;\n\n    /**\n     * The string presenting the service names that the Dubbo interface subscribed\n     *\n     * @since 2.7.8\n     */\n    private String services;\n\n    public static <T> ReferenceBuilder<T> newBuilder() {\n        return new ReferenceBuilder<>();\n    }\n\n    public ReferenceBuilder<T> id(String id) {\n        return super.id(id);\n    }\n\n    public ReferenceBuilder<T> interfaceName(String interfaceName) {\n        this.interfaceName = interfaceName;\n        return getThis();\n    }\n\n    public ReferenceBuilder<T> interfaceClass(Class<?> interfaceClass) {\n        this.interfaceClass = interfaceClass;\n        return getThis();\n    }\n\n    public ReferenceBuilder<T> client(String client) {\n        this.client = client;\n        return getThis();\n    }\n\n    public ReferenceBuilder<T> url(String url) {\n        this.url = url;\n        return getThis();\n    }\n\n    public ReferenceBuilder<T> addMethods(List<MethodConfig> methods) {\n        if (this.methods == null) {\n            this.methods = new ArrayList<>();\n        }\n        this.methods.addAll(methods);\n        return getThis();\n    }\n\n    public ReferenceBuilder<T> addMethod(MethodConfig method) {\n        if (this.methods == null) {\n            this.methods = new ArrayList<>();\n        }\n        this.methods.add(method);\n        return getThis();\n    }\n\n    public ReferenceBuilder<T> consumer(ConsumerConfig consumer) {\n        this.consumer = consumer;\n        return getThis();\n    }\n\n    public ReferenceBuilder<T> protocol(String protocol) {\n        this.protocol = protocol;\n        return getThis();\n    }\n\n    /**\n     * @param service       one service name\n     * @param otherServices other service names\n     * @return {@link ReferenceBuilder}\n     * @since 2.7.8\n     */\n    public ReferenceBuilder<T> services(String service, String... otherServices) {\n        this.services = toCommaDelimitedString(service, otherServices);\n        return getThis();\n    }\n\n    @Override\n    public ReferenceConfig<T> build() {\n        ReferenceConfig<T> reference = new ReferenceConfig<>();\n        super.build(reference);\n\n        reference.setInterface(interfaceName);\n        if (interfaceClass != null) {\n            reference.setInterface(interfaceClass);\n        }\n        reference.setClient(client);\n        reference.setUrl(url);\n        reference.setMethods(methods);\n        reference.setConsumer(consumer);\n        reference.setProtocol(protocol);\n        // @since 2.7.8\n        reference.setServices(services);\n\n        return reference;\n    }\n\n    @Override\n    protected ReferenceBuilder<T> getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.RegistryConfig;\n\nimport java.util.Map;\n\n/**\n * This is a builder for build {@link RegistryConfig}.\n *\n * @since 2.7\n */\npublic class RegistryBuilder extends AbstractBuilder<RegistryConfig, RegistryBuilder> {\n    /**\n     * Register center address\n     */\n    private String address;\n\n    /**\n     * Username to login register center\n     */\n    private String username;\n\n    /**\n     * Password to login register center\n     */\n    private String password;\n\n    /**\n     * Default port for register center\n     */\n    private Integer port;\n\n    /**\n     * Protocol for register center\n     */\n    private String protocol;\n\n    /**\n     * Network transmission type\n     */\n    private String transporter;\n\n    private String server;\n\n    private String client;\n\n    private String cluster;\n\n    /**\n     * The group the services registry in\n     */\n    private String group;\n\n    private String version;\n\n    /**\n     * Request timeout in milliseconds for register center\n     */\n    private Integer timeout;\n\n    /**\n     * Session timeout in milliseconds for register center\n     */\n    private Integer session;\n\n    /**\n     * File for saving register center dynamic list\n     */\n    private String file;\n\n    /**\n     * Wait time before stop\n     */\n    private Integer wait;\n\n    /**\n     * Whether to check if register center is available when boot up\n     */\n    private Boolean check;\n\n    /**\n     * Whether to allow dynamic service to register on the register center\n     */\n    private Boolean dynamic;\n\n    /**\n     * Whether to export service on the register center\n     */\n    private Boolean register;\n\n    /**\n     * Whether allow to subscribe service on the register center\n     */\n    private Boolean subscribe;\n\n    /**\n     * The customized parameters\n     */\n    private Map<String, String> parameters;\n\n    /**\n     * Whether it's default\n     */\n    private Boolean isDefault;\n\n    /**\n     * Simple the registry. both useful for provider and consumer\n     *\n     * @since 2.7.0\n     */\n    private Boolean simplified;\n    /**\n     * After simplify the registry, should add some parameter individually. just for provider.\n     * <p>\n     * such as: extra-keys = A,b,c,d\n     *\n     * @since 2.7.0\n     */\n    private String extraKeys;\n\n    /**\n     * the address work as config center or not\n     */\n    private Boolean useAsConfigCenter;\n\n    /**\n     * the address work as remote metadata center or not\n     */\n    private Boolean useAsMetadataCenter;\n\n    /**\n     * list of rpc protocols accepted by this registry, for example, \"dubbo,rest\"\n     */\n    private String accepts;\n\n    /**\n     * Always use this registry first if set to true, useful when subscribe to multiple registries\n     */\n    private Boolean preferred;\n\n    /**\n     * Affects traffic distribution among registries, useful when subscribe to multiple registries\n     * Take effect only when no preferred registry is specified.\n     */\n    private Integer weight;\n\n    public static RegistryBuilder newBuilder() {\n        return new RegistryBuilder();\n    }\n\n    public RegistryBuilder id(String id) {\n        return super.id(id);\n    }\n\n    public RegistryBuilder address(String address) {\n        this.address = address;\n        return getThis();\n    }\n\n    public RegistryBuilder username(String username) {\n        this.username = username;\n        return getThis();\n    }\n\n    public RegistryBuilder password(String password) {\n        this.password = password;\n        return getThis();\n    }\n\n    public RegistryBuilder port(Integer port) {\n        this.port = port;\n        return getThis();\n    }\n\n    public RegistryBuilder protocol(String protocol) {\n        this.protocol = protocol;\n        return getThis();\n    }\n\n    public RegistryBuilder transporter(String transporter) {\n        this.transporter = transporter;\n        return getThis();\n    }\n\n    /**\n     * @param transport\n     * @see #transporter(String)\n     * @deprecated\n     */\n    @Deprecated\n    public RegistryBuilder transport(String transport) {\n        this.transporter = transport;\n        return getThis();\n    }\n\n    public RegistryBuilder server(String server) {\n        this.server = server;\n        return getThis();\n    }\n\n    public RegistryBuilder client(String client) {\n        this.client = client;\n        return getThis();\n    }\n\n    public RegistryBuilder cluster(String cluster) {\n        this.cluster = cluster;\n        return getThis();\n    }\n\n    public RegistryBuilder group(String group) {\n        this.group = group;\n        return getThis();\n    }\n\n    public RegistryBuilder version(String version) {\n        this.version = version;\n        return getThis();\n    }\n\n    public RegistryBuilder timeout(Integer timeout) {\n        this.timeout = timeout;\n        return getThis();\n    }\n\n    public RegistryBuilder session(Integer session) {\n        this.session = session;\n        return getThis();\n    }\n\n    public RegistryBuilder file(String file) {\n        this.file = file;\n        return getThis();\n    }\n\n    /**\n     * @param wait\n     * @see ProviderBuilder#wait(Integer)\n     * @deprecated\n     */\n    @Deprecated\n    public RegistryBuilder wait(Integer wait) {\n        this.wait = wait;\n        return getThis();\n    }\n\n    public RegistryBuilder isCheck(Boolean check) {\n        this.check = check;\n        return getThis();\n    }\n\n    public RegistryBuilder isDynamic(Boolean dynamic) {\n        this.dynamic = dynamic;\n        return getThis();\n    }\n\n    public RegistryBuilder register(Boolean register) {\n        this.register = register;\n        return getThis();\n    }\n\n    public RegistryBuilder subscribe(Boolean subscribe) {\n        this.subscribe = subscribe;\n        return getThis();\n    }\n\n    public RegistryBuilder appendParameter(String key, String value) {\n        this.parameters = appendParameter(parameters, key, value);\n        return getThis();\n    }\n\n    /**\n     * @param name   the parameter name\n     * @param value the parameter value\n     * @return {@link RegistryBuilder}\n     * @since 2.7.8\n     */\n    public RegistryBuilder parameter(String name, String value) {\n        return appendParameter(name, value);\n    }\n\n    public RegistryBuilder appendParameters(Map<String, String> appendParameters) {\n        this.parameters = appendParameters(parameters, appendParameters);\n        return getThis();\n    }\n\n    public RegistryBuilder isDefault(Boolean isDefault) {\n        this.isDefault = isDefault;\n        return getThis();\n    }\n\n    public RegistryBuilder simplified(Boolean simplified) {\n        this.simplified = simplified;\n        return getThis();\n    }\n\n    public RegistryBuilder extraKeys(String extraKeys) {\n        this.extraKeys = extraKeys;\n        return getThis();\n    }\n\n    public RegistryBuilder useAsConfigCenter(Boolean useAsConfigCenter) {\n        this.useAsConfigCenter = useAsConfigCenter;\n        return getThis();\n    }\n\n    public RegistryBuilder useAsMetadataCenter(Boolean useAsMetadataCenter) {\n        this.useAsMetadataCenter = useAsMetadataCenter;\n        return getThis();\n    }\n\n    public RegistryBuilder preferred(Boolean preferred) {\n        this.preferred = preferred;\n        return getThis();\n    }\n\n    public RegistryBuilder accepts(String accepts) {\n        this.accepts = accepts;\n        return getThis();\n    }\n\n    public RegistryBuilder weight(Integer weight) {\n        this.weight = weight;\n        return getThis();\n    }\n\n    @Override\n    public RegistryConfig build() {\n        RegistryConfig registry = new RegistryConfig();\n        super.build(registry);\n\n        registry.setCheck(check);\n        registry.setClient(client);\n        registry.setCluster(cluster);\n        registry.setDefault(isDefault);\n        registry.setDynamic(dynamic);\n        registry.setExtraKeys(extraKeys);\n        registry.setFile(file);\n        registry.setGroup(group);\n        registry.setParameters(parameters);\n        registry.setPassword(password);\n        registry.setPort(port);\n        registry.setProtocol(protocol);\n        registry.setRegister(register);\n        registry.setServer(server);\n        registry.setSession(session);\n        registry.setSimplified(simplified);\n        registry.setSubscribe(subscribe);\n        registry.setTimeout(timeout);\n        registry.setTransporter(transporter);\n        registry.setUsername(username);\n        registry.setVersion(version);\n        registry.setWait(wait);\n        registry.setUseAsConfigCenter(useAsConfigCenter);\n        registry.setUseAsMetadataCenter(useAsMetadataCenter);\n        registry.setAccepts(accepts);\n        registry.setPreferred(preferred);\n        registry.setWeight(weight);\n        registry.setAddress(address);\n\n        return registry;\n    }\n\n    @Override\n    protected RegistryBuilder getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ServiceBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceConfigBase;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * This is a builder for build {@link ServiceConfigBase}.\n *\n * @since 2.7\n */\npublic class ServiceBuilder<U> extends AbstractServiceBuilder<ServiceConfig<U>, ServiceBuilder<U>> {\n    /**\n     * The interface name of the exported service\n     */\n    private String interfaceName;\n\n    /**\n     * The interface class of the exported service\n     */\n    private Class<?> interfaceClass;\n\n    /**\n     * The reference of the interface implementation\n     */\n    private U ref;\n\n    /**\n     * The service name\n     */\n    private String path;\n\n    /**\n     * The method configuration\n     */\n    private List<MethodConfig> methods;\n\n    /**\n     * The provider configuration\n     */\n    private ProviderConfig provider;\n\n    /**\n     * The providerIds\n     */\n    private String providerIds;\n    /**\n     * whether it is a GenericService\n     */\n    private String generic;\n\n    public static <T> ServiceBuilder<T> newBuilder() {\n        return new ServiceBuilder<>();\n    }\n\n    public ServiceBuilder<U> id(String id) {\n        return super.id(id);\n    }\n\n    public ServiceBuilder<U> interfaceName(String interfaceName) {\n        this.interfaceName = interfaceName;\n        return getThis();\n    }\n\n    public ServiceBuilder<U> interfaceClass(Class<?> interfaceClass) {\n        this.interfaceClass = interfaceClass;\n        return getThis();\n    }\n\n    public ServiceBuilder<U> ref(U ref) {\n        this.ref = ref;\n        return getThis();\n    }\n\n    public ServiceBuilder<U> path(String path) {\n        this.path = path;\n        return getThis();\n    }\n\n    public ServiceBuilder<U> addMethod(MethodConfig method) {\n        if (this.methods == null) {\n            this.methods = new ArrayList<>();\n        }\n        this.methods.add(method);\n        return getThis();\n    }\n\n    public ServiceBuilder<U> addMethods(List<? extends MethodConfig> methods) {\n        if (this.methods == null) {\n            this.methods = new ArrayList<>();\n        }\n        this.methods.addAll(methods);\n        return getThis();\n    }\n\n    public ServiceBuilder<U> provider(ProviderConfig provider) {\n        this.provider = provider;\n        return getThis();\n    }\n\n    public ServiceBuilder<U> providerIds(String providerIds) {\n        this.providerIds = providerIds;\n        return getThis();\n    }\n\n    public ServiceBuilder<U> generic(String generic) {\n        this.generic = generic;\n        return getThis();\n    }\n\n    //    @Override\n    //    public ServiceBuilder<U> mock(String mock) {\n    //        throw new IllegalArgumentException(\"mock doesn't support on provider side\");\n    //    }\n\n    //    @Override\n    //    public ServiceBuilder<U> mock(Boolean mock) {\n    //        throw new IllegalArgumentException(\"mock doesn't support on provider side\");\n    //    }\n\n    @Override\n    public ServiceConfig<U> build() {\n        ServiceConfig<U> serviceConfig = new ServiceConfig<>();\n        super.build(serviceConfig);\n\n        serviceConfig.setInterface(interfaceName);\n        serviceConfig.setInterface(interfaceClass);\n        serviceConfig.setRef(ref);\n        serviceConfig.setPath(path);\n        serviceConfig.setMethods(methods);\n        serviceConfig.setProvider(provider);\n        serviceConfig.setProviderIds(providerIds);\n        serviceConfig.setGeneric(generic);\n\n        return serviceConfig;\n    }\n\n    @Override\n    protected ServiceBuilder<U> getThis() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/TripleBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.nested.TripleConfig;\n\n/**\n * This is a builder for build {@link TripleConfig}.\n *\n * @since 3.3\n */\npublic class TripleBuilder {\n\n    /**\n     * Maximum allowed size for HTTP1 request bodies.\n     * Limits the size of request to prevent excessively large request.\n     * <p>The default value is 8MiB.\n     */\n    private Integer maxBodySize;\n\n    /**\n     * Maximum allowed size for HTTP1 response bodies.\n     * Limits the size of responses to prevent excessively large response.\n     * <p>The default value is 8MiB.\n     */\n    private Integer maxResponseBodySize;\n\n    /**\n     * Set the maximum chunk size.\n     * HTTP requests and responses can be quite large, in which case it's better to process the data as a stream of\n     * chunks.\n     * This sets the limit, in bytes, at which Netty will send a chunk down the pipeline.\n     * <p>The default value is 8KiB.\n     */\n    private Integer maxChunkSize;\n\n    /**\n     * Set the maximum line length of header lines.\n     * This limits how much memory Netty will use when parsing HTTP header key-value pairs.\n     * You would typically set this to the same value as {@link #maxInitialLineLength(Integer)}.\n     * <p>The default value is 8KiB.\n     */\n    private Integer maxHeaderSize;\n\n    /**\n     * Set the maximum length of the first line of the HTTP header.\n     * This limits how much memory Netty will use when parsed the initial HTTP header line.\n     * You would typically set this to the same value as {@link #maxHeaderSize(Integer)}.\n     * <p>The default value is 4096.\n     */\n    private Integer maxInitialLineLength;\n\n    /**\n     * Set the initial size of the temporary buffer used when parsing the lines of the HTTP headers.\n     * <p>The default value is 128 octets.\n     */\n    private Integer initialBufferSize;\n\n    /**\n     * The header table size.\n     */\n    private Integer headerTableSize;\n\n    /**\n     * Whether to enable push, default is false.\n     */\n    private Boolean enablePush;\n\n    /**\n     * Maximum concurrent streams.\n     */\n    private Integer maxConcurrentStreams;\n\n    /**\n     * Initial window size.\n     */\n    private Integer initialWindowSize;\n\n    /**\n     * Connection initial window size.\n     */\n    private Integer connectionInitialWindowSize;\n\n    /**\n     * Maximum frame size.\n     */\n    private Integer maxFrameSize;\n\n    /**\n     * Maximum header list size.\n     */\n    private Integer maxHeaderListSize;\n\n    public static TripleBuilder newBuilder() {\n        return new TripleBuilder();\n    }\n\n    public TripleBuilder maxBodySize(Integer maxBodySize) {\n        this.maxBodySize = maxBodySize;\n        return getThis();\n    }\n\n    public TripleBuilder maxResponseBodySize(Integer maxResponseBodySize) {\n        this.maxResponseBodySize = maxResponseBodySize;\n        return getThis();\n    }\n\n    public TripleBuilder maxChunkSize(Integer maxChunkSize) {\n        this.maxChunkSize = maxChunkSize;\n        return getThis();\n    }\n\n    public TripleBuilder maxHeaderSize(Integer maxHeaderSize) {\n        this.maxHeaderSize = maxHeaderSize;\n        return getThis();\n    }\n\n    public TripleBuilder maxInitialLineLength(Integer maxInitialLineLength) {\n        this.maxInitialLineLength = maxInitialLineLength;\n        return getThis();\n    }\n\n    public TripleBuilder initialBufferSize(Integer initialBufferSize) {\n        this.initialBufferSize = initialBufferSize;\n        return getThis();\n    }\n\n    public TripleBuilder headerTableSize(Integer headerTableSize) {\n        this.headerTableSize = headerTableSize;\n        return getThis();\n    }\n\n    public TripleBuilder enablePush(Boolean enablePush) {\n        this.enablePush = enablePush;\n        return getThis();\n    }\n\n    public TripleBuilder maxConcurrentStreams(Integer maxConcurrentStreams) {\n        this.maxConcurrentStreams = maxConcurrentStreams;\n        return getThis();\n    }\n\n    public TripleBuilder initialWindowSize(Integer initialWindowSize) {\n        this.initialWindowSize = initialWindowSize;\n        return getThis();\n    }\n\n    public TripleBuilder connectionInitialWindowSize(Integer connectionInitialWindowSize) {\n        this.connectionInitialWindowSize = connectionInitialWindowSize;\n        return getThis();\n    }\n\n    public TripleBuilder maxFrameSize(Integer maxFrameSize) {\n        this.maxFrameSize = maxFrameSize;\n        return getThis();\n    }\n\n    public TripleBuilder maxHeaderListSize(Integer maxHeaderListSize) {\n        this.maxHeaderListSize = maxHeaderListSize;\n        return getThis();\n    }\n\n    protected TripleBuilder getThis() {\n        return this;\n    }\n\n    public TripleConfig build() {\n        TripleConfig triple = new TripleConfig();\n\n        if (maxBodySize != null) {\n            triple.setMaxBodySize(maxBodySize);\n        }\n        if (maxResponseBodySize != null) {\n            triple.setMaxResponseBodySize(maxResponseBodySize);\n        }\n        if (maxChunkSize != null) {\n            triple.setMaxChunkSize(maxChunkSize);\n        }\n        if (maxHeaderSize != null) {\n            triple.setMaxHeaderSize(maxHeaderSize);\n        }\n        if (maxInitialLineLength != null) {\n            triple.setMaxInitialLineLength(maxInitialLineLength);\n        }\n        if (initialBufferSize != null) {\n            triple.setInitialBufferSize(initialBufferSize);\n        }\n        if (headerTableSize != null) {\n            triple.setHeaderTableSize(headerTableSize);\n        }\n        if (enablePush != null) {\n            triple.setEnablePush(enablePush);\n        }\n        if (maxConcurrentStreams != null) {\n            triple.setMaxConcurrentStreams(maxConcurrentStreams);\n        }\n        if (initialWindowSize != null) {\n            triple.setInitialWindowSize(initialWindowSize);\n        }\n        if (connectionInitialWindowSize != null) {\n            triple.setConnectionInitialWindowSize(connectionInitialWindowSize);\n        }\n        if (maxFrameSize != null) {\n            triple.setMaxFrameSize(maxFrameSize);\n        }\n        if (maxHeaderListSize != null) {\n            triple.setMaxHeaderListSize(maxHeaderListSize);\n        }\n        return triple;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/package-info.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * A bunch of builder classes to facilitate programming of raw API.\n * TODO, these are experimental APIs and are possible to change at any time before marked as production.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.deploy;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.config.ReferenceCache;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory;\nimport org.apache.dubbo.common.config.configcenter.wrapper.CompositeDynamicConfiguration;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.deploy.AbstractDeployer;\nimport org.apache.dubbo.common.deploy.ApplicationDeployListener;\nimport org.apache.dubbo.common.deploy.ApplicationDeployer;\nimport org.apache.dubbo.common.deploy.DeployListener;\nimport org.apache.dubbo.common.deploy.DeployState;\nimport org.apache.dubbo.common.deploy.ModuleDeployer;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.lang.ShutdownHookCallbacks;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.DubboShutdownHook;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.utils.CompositeReferenceCache;\nimport org.apache.dubbo.config.utils.ConfigValidationUtils;\nimport org.apache.dubbo.metadata.report.MetadataReportFactory;\nimport org.apache.dubbo.metadata.report.MetadataReportInstance;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.config.event.ConfigCenterEvent;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.report.DefaultMetricsReporterFactory;\nimport org.apache.dubbo.metrics.report.MetricsReporter;\nimport org.apache.dubbo.metrics.report.MetricsReporterFactory;\nimport org.apache.dubbo.metrics.service.MetricsServiceExporter;\nimport org.apache.dubbo.metrics.utils.MetricsSupportUtil;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\nimport org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils;\nimport org.apache.dubbo.registry.support.RegistryManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\nimport org.apache.dubbo.tracing.DubboObservationRegistry;\nimport org.apache.dubbo.tracing.utils.ObservationSupportUtil;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\n\nimport static java.lang.String.format;\nimport static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_EXECUTE_DESTROY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_INIT_CONFIG_CENTER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_START_MODEL;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_REFRESH_INSTANCE_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_REGISTER_INSTANCE_ERROR;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_DEFAULT;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\nimport static org.apache.dubbo.config.Constants.DEFAULT_APP_NAME;\nimport static org.apache.dubbo.metadata.MetadataConstants.DEFAULT_METADATA_PUBLISH_DELAY;\nimport static org.apache.dubbo.metadata.MetadataConstants.METADATA_PUBLISH_DELAY_KEY;\nimport static org.apache.dubbo.remoting.Constants.CLIENT_KEY;\n\n/**\n * initialize and start application instance\n */\npublic class DefaultApplicationDeployer extends AbstractDeployer<ApplicationModel> implements ApplicationDeployer {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DefaultApplicationDeployer.class);\n\n    private final ApplicationModel applicationModel;\n\n    private final ConfigManager configManager;\n\n    private final Environment environment;\n\n    private final ReferenceCache referenceCache;\n\n    private final FrameworkExecutorRepository frameworkExecutorRepository;\n    private final ExecutorRepository executorRepository;\n\n    private final AtomicBoolean hasPreparedApplicationInstance = new AtomicBoolean(false);\n    private volatile boolean hasPreparedInternalModule = false;\n\n    private ScheduledFuture<?> asyncMetadataFuture;\n    private volatile CompletableFuture<Boolean> startFuture;\n    private final DubboShutdownHook dubboShutdownHook;\n\n    private volatile MetricsServiceExporter metricsServiceExporter;\n\n    private final Object stateLock = new Object();\n    private final Object startLock = new Object();\n    private final Object destroyLock = new Object();\n    private final Object internalModuleLock = new Object();\n\n    public DefaultApplicationDeployer(ApplicationModel applicationModel) {\n        super(applicationModel);\n        this.applicationModel = applicationModel;\n        configManager = applicationModel.getApplicationConfigManager();\n        environment = applicationModel.modelEnvironment();\n\n        referenceCache = new CompositeReferenceCache(applicationModel);\n        frameworkExecutorRepository =\n                applicationModel.getFrameworkModel().getBeanFactory().getBean(FrameworkExecutorRepository.class);\n        executorRepository = ExecutorRepository.getInstance(applicationModel);\n        dubboShutdownHook = new DubboShutdownHook(applicationModel);\n\n        // load spi listener\n        Set<ApplicationDeployListener> deployListeners = applicationModel\n                .getExtensionLoader(ApplicationDeployListener.class)\n                .getSupportedExtensionInstances();\n        for (ApplicationDeployListener listener : deployListeners) {\n            this.addDeployListener(listener);\n        }\n    }\n\n    public static ApplicationDeployer get(ScopeModel moduleOrApplicationModel) {\n        ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(moduleOrApplicationModel);\n        ApplicationDeployer applicationDeployer = applicationModel.getDeployer();\n        if (applicationDeployer == null) {\n            applicationDeployer = applicationModel.getBeanFactory().getOrRegisterBean(DefaultApplicationDeployer.class);\n        }\n        return applicationDeployer;\n    }\n\n    @Override\n    public ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    private <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        return applicationModel.getExtensionLoader(type);\n    }\n\n    private void unRegisterShutdownHook() {\n        dubboShutdownHook.unregister();\n    }\n\n    /**\n     * Enable registration of instance for pure Consumer process by setting registerConsumer to 'true'\n     * by default is false.\n     */\n    private boolean isRegisterConsumerInstance() {\n        Boolean registerConsumer = getApplicationOrElseThrow().getRegisterConsumer();\n        if (registerConsumer == null) {\n            return false;\n        }\n        return Boolean.TRUE.equals(registerConsumer);\n    }\n\n    @Override\n    public ReferenceCache getReferenceCache() {\n        return referenceCache;\n    }\n\n    /**\n     * Initialize\n     */\n    @Override\n    public void initialize() {\n        if (initialized) {\n            return;\n        }\n        // Ensure that the initialization is completed when concurrent calls\n        synchronized (startLock) {\n            if (initialized) {\n                return;\n            }\n            onInitialize();\n\n            // register shutdown hook\n            registerShutdownHook();\n\n            startConfigCenter();\n\n            loadApplicationConfigs();\n\n            initModuleDeployers();\n\n            initMetricsReporter();\n\n            initMetricsService();\n\n            // @since 3.2.3\n            initObservationRegistry();\n\n            // @since 2.7.8\n            startMetadataCenter();\n\n            initialized = true;\n\n            if (logger.isInfoEnabled()) {\n                logger.info(getIdentifier() + \" has been initialized!\");\n            }\n        }\n    }\n\n    private void registerShutdownHook() {\n        dubboShutdownHook.register();\n    }\n\n    private void initModuleDeployers() {\n        // make sure created default module\n        applicationModel.getDefaultModule();\n        // deployer initialize\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            moduleModel.getDeployer().initialize();\n        }\n    }\n\n    private void loadApplicationConfigs() {\n        configManager.loadConfigs();\n    }\n\n    private void startConfigCenter() {\n\n        // load application config\n        configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);\n\n        // try set model name\n        if (StringUtils.isBlank(applicationModel.getModelName())) {\n            applicationModel.setModelName(applicationModel.tryGetApplicationName());\n        }\n\n        // load config centers\n        configManager.loadConfigsOfTypeFromProps(ConfigCenterConfig.class);\n\n        useRegistryAsConfigCenterIfNecessary();\n\n        // check Config Center\n        Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();\n        if (CollectionUtils.isEmpty(configCenters)) {\n            ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();\n            configCenterConfig.setScopeModel(applicationModel);\n            configCenterConfig.refresh();\n            ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);\n            if (configCenterConfig.isValid()) {\n                configManager.addConfigCenter(configCenterConfig);\n                configCenters = configManager.getConfigCenters();\n            }\n        } else {\n            for (ConfigCenterConfig configCenterConfig : configCenters) {\n                configCenterConfig.refresh();\n                ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);\n            }\n        }\n\n        if (CollectionUtils.isNotEmpty(configCenters)) {\n            CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();\n            for (ConfigCenterConfig configCenter : configCenters) {\n                // Pass config from ConfigCenterBean to environment\n                environment.updateExternalConfigMap(configCenter.getExternalConfiguration());\n                environment.updateAppExternalConfigMap(configCenter.getAppExternalConfiguration());\n\n                // Fetch config from remote config center\n                compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));\n            }\n            environment.setDynamicConfiguration(compositeDynamicConfiguration);\n        }\n    }\n\n    private void startMetadataCenter() {\n\n        useRegistryAsMetadataCenterIfNecessary();\n\n        ApplicationConfig applicationConfig = getApplicationOrElseThrow();\n\n        String metadataType = applicationConfig.getMetadataType();\n        // FIXME, multiple metadata config support.\n        Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();\n        if (CollectionUtils.isEmpty(metadataReportConfigs)) {\n            if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {\n                throw new IllegalStateException(\n                        \"No MetadataConfig found, Metadata Center address is required when 'metadata=remote' is enabled.\");\n            }\n            return;\n        }\n\n        MetadataReportInstance metadataReportInstance =\n                applicationModel.getBeanFactory().getBean(MetadataReportInstance.class);\n        List<MetadataReportConfig> validMetadataReportConfigs = new ArrayList<>(metadataReportConfigs.size());\n        for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) {\n            if (ConfigValidationUtils.isValidMetadataConfig(metadataReportConfig)) {\n                ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);\n                validMetadataReportConfigs.add(metadataReportConfig);\n            }\n        }\n        metadataReportInstance.init(validMetadataReportConfigs);\n        if (!metadataReportInstance.isInitialized()) {\n            throw new IllegalStateException(String.format(\n                    \"%s MetadataConfigs found, but none of them is valid.\", metadataReportConfigs.size()));\n        }\n    }\n\n    /**\n     * For compatibility purpose, use registry as the default config center when\n     * there's no config center specified explicitly and\n     * useAsConfigCenter of registryConfig is null or true\n     */\n    private void useRegistryAsConfigCenterIfNecessary() {\n        // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated.\n        if (environment.getDynamicConfiguration().isPresent()) {\n            return;\n        }\n\n        if (CollectionUtils.isNotEmpty(configManager.getConfigCenters())) {\n            return;\n        }\n\n        // load registry\n        configManager.loadConfigsOfTypeFromProps(RegistryConfig.class);\n\n        List<RegistryConfig> defaultRegistries = configManager.getDefaultRegistries();\n        if (!defaultRegistries.isEmpty()) {\n            defaultRegistries.stream()\n                    .filter(this::isUsedRegistryAsConfigCenter)\n                    .map(this::registryAsConfigCenter)\n                    .forEach(configCenter -> {\n                        if (configManager.getConfigCenter(configCenter.getId()).isPresent()) {\n                            return;\n                        }\n                        configManager.addConfigCenter(configCenter);\n                        logger.info(\"use registry as config-center: \" + configCenter);\n                    });\n        }\n    }\n\n    private void initMetricsService() {\n        this.metricsServiceExporter =\n                getExtensionLoader(MetricsServiceExporter.class).getDefaultExtension();\n        metricsServiceExporter.init();\n    }\n\n    private void initMetricsReporter() {\n        if (!MetricsSupportUtil.isSupportMetrics()) {\n            return;\n        }\n        DefaultMetricsCollector collector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);\n        Optional<MetricsConfig> configOptional = configManager.getMetrics();\n        // If no specific metrics type is configured and there is no Prometheus dependency in the dependencies.\n        MetricsConfig metricsConfig = configOptional.orElse(new MetricsConfig(applicationModel));\n        if (PROTOCOL_PROMETHEUS.equals(metricsConfig.getProtocol()) && !MetricsSupportUtil.isSupportPrometheus()) {\n            return;\n        }\n        if (StringUtils.isBlank(metricsConfig.getProtocol())) {\n            metricsConfig.setProtocol(\n                    MetricsSupportUtil.isSupportPrometheus() ? PROTOCOL_PROMETHEUS : PROTOCOL_DEFAULT);\n        }\n        collector.setCollectEnabled(true);\n        collector.collectApplication();\n        collector.setThreadpoolCollectEnabled(\n                Optional.ofNullable(metricsConfig.getEnableThreadpool()).orElse(true));\n        collector.setMetricsInitEnabled(\n                Optional.ofNullable(metricsConfig.getEnableMetricsInit()).orElse(true));\n        MetricsReporterFactory metricsReporterFactory =\n                getExtensionLoader(MetricsReporterFactory.class).getAdaptiveExtension();\n        MetricsReporter metricsReporter = null;\n        try {\n            metricsReporter = metricsReporterFactory.createMetricsReporter(metricsConfig.toUrl());\n        } catch (IllegalStateException e) {\n            if (e.getMessage().startsWith(\"No such extension org.apache.dubbo.metrics.report.MetricsReporterFactory\")) {\n                logger.warn(COMMON_METRICS_COLLECTOR_EXCEPTION, \"\", \"\", e.getMessage());\n                return;\n            } else {\n                throw e;\n            }\n        }\n        metricsReporter.init();\n        applicationModel.getBeanFactory().registerBean(metricsReporter);\n        // If the protocol is not the default protocol, the default protocol is also initialized.\n        if (!PROTOCOL_DEFAULT.equals(metricsConfig.getProtocol())) {\n            DefaultMetricsReporterFactory defaultMetricsReporterFactory =\n                    new DefaultMetricsReporterFactory(applicationModel);\n            MetricsReporter defaultMetricsReporter =\n                    defaultMetricsReporterFactory.createMetricsReporter(metricsConfig.toUrl());\n            defaultMetricsReporter.init();\n            applicationModel.getBeanFactory().registerBean(defaultMetricsReporter);\n        }\n    }\n\n    /**\n     * init ObservationRegistry(Micrometer)\n     */\n    private void initObservationRegistry() {\n        if (!ObservationSupportUtil.isSupportObservation()) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\n                        \"Not found micrometer-observation or plz check the version of micrometer-observation version if already introduced, need > 1.10.0\");\n            }\n            return;\n        }\n        if (!ObservationSupportUtil.isSupportTracing()) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Not found micrometer-tracing dependency, skip init ObservationRegistry.\");\n            }\n            return;\n        }\n        Optional<TracingConfig> configOptional = configManager.getTracing();\n        if (!configOptional.isPresent() || !configOptional.get().getEnabled()) {\n            return;\n        }\n\n        DubboObservationRegistry dubboObservationRegistry =\n                new DubboObservationRegistry(applicationModel, configOptional.get());\n        dubboObservationRegistry.initObservationRegistry();\n    }\n\n    private boolean isUsedRegistryAsConfigCenter(RegistryConfig registryConfig) {\n        return isUsedRegistryAsCenter(\n                registryConfig, registryConfig::getUseAsConfigCenter, \"config\", DynamicConfigurationFactory.class);\n    }\n\n    private ConfigCenterConfig registryAsConfigCenter(RegistryConfig registryConfig) {\n        String protocol = registryConfig.getProtocol();\n        Integer port = registryConfig.getPort();\n        URL url = URL.valueOf(registryConfig.getAddress(), registryConfig.getScopeModel());\n        String id = \"config-center-\" + protocol + \"-\" + url.getHost() + \"-\" + port;\n        ConfigCenterConfig cc = new ConfigCenterConfig();\n        cc.setId(id);\n        cc.setScopeModel(applicationModel);\n        if (cc.getParameters() == null) {\n            cc.setParameters(new HashMap<>());\n        }\n        if (CollectionUtils.isNotEmptyMap(registryConfig.getParameters())) {\n            cc.getParameters().putAll(registryConfig.getParameters()); // copy the parameters\n        }\n        cc.getParameters().put(CLIENT_KEY, registryConfig.getClient());\n        cc.setProtocol(protocol);\n        cc.setPort(port);\n        if (StringUtils.isNotEmpty(registryConfig.getGroup())) {\n            cc.setGroup(registryConfig.getGroup());\n        }\n        cc.setAddress(getRegistryCompatibleAddress(registryConfig));\n        cc.setNamespace(registryConfig.getGroup());\n        cc.setUsername(registryConfig.getUsername());\n        cc.setPassword(registryConfig.getPassword());\n        if (registryConfig.getTimeout() != null) {\n            cc.setTimeout(registryConfig.getTimeout().longValue());\n        }\n        cc.setHighestPriority(false);\n        return cc;\n    }\n\n    private void useRegistryAsMetadataCenterIfNecessary() {\n\n        Collection<MetadataReportConfig> originMetadataConfigs = configManager.getMetadataConfigs();\n        if (originMetadataConfigs.stream().anyMatch(m -> Objects.nonNull(m.getAddress()))) {\n            return;\n        }\n\n        Collection<MetadataReportConfig> metadataConfigsToOverride = originMetadataConfigs.stream()\n                .filter(m -> Objects.isNull(m.getAddress()))\n                .collect(Collectors.toList());\n\n        if (metadataConfigsToOverride.size() > 1) {\n            return;\n        }\n\n        MetadataReportConfig metadataConfigToOverride =\n                metadataConfigsToOverride.stream().findFirst().orElse(null);\n\n        List<RegistryConfig> defaultRegistries = configManager.getDefaultRegistries();\n        if (!defaultRegistries.isEmpty()) {\n            defaultRegistries.stream()\n                    .filter(this::isUsedRegistryAsMetadataCenter)\n                    .map(registryConfig -> registryAsMetadataCenter(registryConfig, metadataConfigToOverride))\n                    .forEach(metadataReportConfig ->\n                            overrideMetadataReportConfig(metadataConfigToOverride, metadataReportConfig));\n        }\n    }\n\n    private void overrideMetadataReportConfig(\n            MetadataReportConfig metadataConfigToOverride, MetadataReportConfig metadataReportConfig) {\n        if (metadataReportConfig.getId() == null) {\n            Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();\n            if (CollectionUtils.isNotEmpty(metadataReportConfigs)) {\n                for (MetadataReportConfig existedConfig : metadataReportConfigs) {\n                    if (existedConfig.getId() == null\n                            && existedConfig.getAddress().equals(metadataReportConfig.getAddress())) {\n                        return;\n                    }\n                }\n            }\n            configManager.removeConfig(metadataConfigToOverride);\n            configManager.addMetadataReport(metadataReportConfig);\n        } else {\n            Optional<MetadataReportConfig> configOptional =\n                    configManager.getConfig(MetadataReportConfig.class, metadataReportConfig.getId());\n            if (configOptional.isPresent()) {\n                return;\n            }\n            configManager.removeConfig(metadataConfigToOverride);\n            configManager.addMetadataReport(metadataReportConfig);\n        }\n        logger.info(\"use registry as metadata-center: \" + metadataReportConfig);\n    }\n\n    private boolean isUsedRegistryAsMetadataCenter(RegistryConfig registryConfig) {\n        return isUsedRegistryAsCenter(\n                registryConfig, registryConfig::getUseAsMetadataCenter, \"metadata\", MetadataReportFactory.class);\n    }\n\n    /**\n     * Is used the specified registry as a center infrastructure\n     *\n     * @param registryConfig       the {@link RegistryConfig}\n     * @param usedRegistryAsCenter the configured value on\n     * @param centerType           the type name of center\n     * @param extensionClass       an extension class of a center infrastructure\n     * @return\n     * @since 2.7.8\n     */\n    private boolean isUsedRegistryAsCenter(\n            RegistryConfig registryConfig,\n            Supplier<Boolean> usedRegistryAsCenter,\n            String centerType,\n            Class<?> extensionClass) {\n        final boolean supported;\n\n        Boolean configuredValue = usedRegistryAsCenter.get();\n        if (configuredValue != null) { // If configured, take its value.\n            supported = configuredValue.booleanValue();\n        } else { // Or check the extension existence\n            String protocol = registryConfig.getProtocol();\n            supported = supportsExtension(extensionClass, protocol);\n            if (logger.isInfoEnabled()) {\n                logger.info(format(\n                        \"No value is configured in the registry, the %s extension[name : %s] %s as the %s center\",\n                        extensionClass.getSimpleName(),\n                        protocol,\n                        supported ? \"supports\" : \"does not support\",\n                        centerType));\n            }\n        }\n\n        if (logger.isInfoEnabled()) {\n            logger.info(format(\n                    \"The registry[%s] will be %s as the %s center\",\n                    registryConfig, supported ? \"used\" : \"not used\", centerType));\n        }\n        return supported;\n    }\n\n    /**\n     * Supports the extension with the specified class and name\n     *\n     * @param extensionClass the {@link Class} of extension\n     * @param name           the name of extension\n     * @return if supports, return <code>true</code>, or <code>false</code>\n     * @since 2.7.8\n     */\n    private boolean supportsExtension(Class<?> extensionClass, String name) {\n        if (isNotEmpty(name)) {\n            ExtensionLoader<?> extensionLoader = getExtensionLoader(extensionClass);\n            return extensionLoader.hasExtension(name);\n        }\n        return false;\n    }\n\n    private MetadataReportConfig registryAsMetadataCenter(\n            RegistryConfig registryConfig, MetadataReportConfig originMetadataReportConfig) {\n        MetadataReportConfig metadataReportConfig = originMetadataReportConfig == null\n                ? new MetadataReportConfig(registryConfig.getApplicationModel())\n                : originMetadataReportConfig;\n        if (metadataReportConfig.getId() == null) {\n            metadataReportConfig.setId(registryConfig.getId());\n        }\n        metadataReportConfig.setScopeModel(applicationModel);\n        if (metadataReportConfig.getParameters() == null) {\n            metadataReportConfig.setParameters(new HashMap<>());\n        }\n        if (CollectionUtils.isNotEmptyMap(registryConfig.getParameters())) {\n            for (Map.Entry<String, String> entry :\n                    registryConfig.getParameters().entrySet()) {\n                metadataReportConfig\n                        .getParameters()\n                        .putIfAbsent(entry.getKey(), entry.getValue()); // copy the parameters\n            }\n        }\n        metadataReportConfig.getParameters().put(CLIENT_KEY, registryConfig.getClient());\n        if (metadataReportConfig.getGroup() == null) {\n            metadataReportConfig.setGroup(registryConfig.getGroup());\n        }\n        if (metadataReportConfig.getAddress() == null) {\n            metadataReportConfig.setAddress(getRegistryCompatibleAddress(registryConfig));\n        }\n        if (metadataReportConfig.getUsername() == null) {\n            metadataReportConfig.setUsername(registryConfig.getUsername());\n        }\n        if (metadataReportConfig.getPassword() == null) {\n            metadataReportConfig.setPassword(registryConfig.getPassword());\n        }\n        if (metadataReportConfig.getTimeout() == null) {\n            metadataReportConfig.setTimeout(registryConfig.getTimeout());\n        }\n        return metadataReportConfig;\n    }\n\n    private String getRegistryCompatibleAddress(RegistryConfig registryConfig) {\n        String registryAddress = registryConfig.getAddress();\n        String[] addresses = REGISTRY_SPLIT_PATTERN.split(registryAddress);\n        if (ArrayUtils.isEmpty(addresses)) {\n            throw new IllegalStateException(\"Invalid registry address found.\");\n        }\n        String address = addresses[0];\n        // since 2.7.8\n        // Issue : https://github.com/apache/dubbo/issues/6476\n        StringBuilder metadataAddressBuilder = new StringBuilder();\n        URL url = URL.valueOf(address, registryConfig.getScopeModel());\n        String protocolFromAddress = url.getProtocol();\n        if (isEmpty(protocolFromAddress)) {\n            // If the protocol from address is missing, is like :\n            // \"dubbo.registry.address = 127.0.0.1:2181\"\n            String protocolFromConfig = registryConfig.getProtocol();\n            metadataAddressBuilder.append(protocolFromConfig).append(\"://\");\n        }\n        metadataAddressBuilder.append(address);\n        return metadataAddressBuilder.toString();\n    }\n\n    /**\n     * Start the bootstrap\n     *\n     * @return\n     */\n    @Override\n    public Future start() {\n        synchronized (startLock) {\n            if (isStopping() || isStopped() || isFailed()) {\n                throw new IllegalStateException(getIdentifier() + \" is stopping or stopped, can not start again\");\n            }\n\n            try {\n                // maybe call start again after add new module, check if any new module\n                boolean hasPendingModule = hasPendingModule();\n\n                if (isStarting()) {\n                    // currently, is starting, maybe both start by module and application\n                    // if it has new modules, start them\n                    if (hasPendingModule) {\n                        startModules();\n                    }\n                    // if it is starting, reuse previous startFuture\n                    return startFuture;\n                }\n\n                // if is started and no new module, just return\n                if ((isStarted() || isCompletion()) && !hasPendingModule) {\n                    return CompletableFuture.completedFuture(false);\n                }\n\n                // pending -> starting : first start app\n                // started -> starting : re-start app\n                onStarting();\n\n                initialize();\n\n                doStart();\n            } catch (Throwable e) {\n                onFailed(getIdentifier() + \" start failure\", e);\n                throw e;\n            }\n\n            return startFuture;\n        }\n    }\n\n    private boolean hasPendingModule() {\n        boolean found = false;\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            if (moduleModel.getDeployer().isPending()) {\n                found = true;\n                break;\n            }\n        }\n        return found;\n    }\n\n    @Override\n    public Future getStartFuture() {\n        return startFuture;\n    }\n\n    private void doStart() {\n        startModules();\n\n        // prepare application instance\n        //        prepareApplicationInstance();\n\n        // Ignore checking new module after start\n        //        executorRepository.getSharedExecutor().submit(() -> {\n        //            try {\n        //                while (isStarting()) {\n        //                    // notify when any module state changed\n        //                    synchronized (stateLock) {\n        //                        try {\n        //                            stateLock.wait(500);\n        //                        } catch (InterruptedException e) {\n        //                            // ignore\n        //                        }\n        //                    }\n        //\n        //                    // if has new module, do start again\n        //                    if (hasPendingModule()) {\n        //                        startModules();\n        //                    }\n        //                }\n        //            } catch (Throwable e) {\n        //                onFailed(getIdentifier() + \" check start occurred an exception\", e);\n        //            }\n        //        });\n    }\n\n    private void startModules() {\n        // ensure init and start internal module first\n        prepareInternalModule();\n\n        // filter and start pending modules, ignore new module during starting, throw exception of module start\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            if (moduleModel.getDeployer().isPending()) {\n                moduleModel.getDeployer().start();\n            }\n        }\n    }\n\n    @Override\n    public void prepareApplicationInstance(ModuleModel moduleModel) {\n        if (hasPreparedApplicationInstance.get()) {\n            return;\n        }\n\n        // export MetricsService\n        exportMetricsService();\n\n        if (moduleModel.getDeployer().hasRegistryInteraction()) {\n            ApplicationConfig applicationConfig = configManager.getApplicationOrElseThrow();\n            if (DEFAULT_APP_NAME.equals(applicationConfig.getName())) {\n                throw new IllegalStateException(\"Application name must be set when registry is enabled.\");\n            }\n        }\n\n        if (isRegisterConsumerInstance() || moduleModel.getDeployer().hasRegistryInteraction()) {\n            if (hasPreparedApplicationInstance.compareAndSet(false, true)) {\n                // register the local ServiceInstance if required\n                registerServiceInstance();\n            }\n        }\n    }\n\n    @Override\n    public synchronized void exportMetadataService() {\n        doExportMetadataService();\n    }\n\n    public void prepareInternalModule() {\n        if (hasPreparedInternalModule) {\n            return;\n        }\n        synchronized (internalModuleLock) {\n            if (hasPreparedInternalModule) {\n                return;\n            }\n\n            // start internal module\n            ModuleDeployer internalModuleDeployer =\n                    applicationModel.getInternalModule().getDeployer();\n            if (!internalModuleDeployer.isCompletion()) {\n                Future future = internalModuleDeployer.start();\n                // wait for internal module startup\n                try {\n                    future.get(5, TimeUnit.SECONDS);\n                    hasPreparedInternalModule = true;\n                } catch (Exception e) {\n                    logger.warn(\n                            CONFIG_FAILED_START_MODEL,\n                            \"\",\n                            \"\",\n                            \"wait for internal module startup failed: \" + e.getMessage(),\n                            e);\n                }\n            }\n        }\n    }\n\n    private void exportMetricsService() {\n        boolean exportMetrics = applicationModel\n                .getApplicationConfigManager()\n                .getMetrics()\n                .map(MetricsConfig::getExportMetricsService)\n                .orElse(true);\n        if (exportMetrics) {\n            try {\n                metricsServiceExporter.export();\n            } catch (Exception e) {\n                logger.error(\n                        LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"exportMetricsService an exception occurred when handle starting event\",\n                        e);\n            }\n        }\n    }\n\n    private void unexportMetricsService() {\n        if (metricsServiceExporter != null) {\n            try {\n                metricsServiceExporter.unexport();\n            } catch (Exception ignored) {\n                // ignored\n            }\n        }\n    }\n\n    private boolean hasExportedServices() {\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            if (CollectionUtils.isNotEmpty(moduleModel.getConfigManager().getServices())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean isBackground() {\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            if (moduleModel.getDeployer().isBackground()) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private DynamicConfiguration prepareEnvironment(ConfigCenterConfig configCenter) {\n        if (configCenter.isValid()) {\n            if (!configCenter.checkOrUpdateInitialized(true)) {\n                return null;\n            }\n\n            DynamicConfiguration dynamicConfiguration;\n            try {\n                dynamicConfiguration = getDynamicConfiguration(configCenter.toUrl());\n            } catch (Exception e) {\n                if (!configCenter.isCheck()) {\n                    logger.warn(\n                            CONFIG_FAILED_INIT_CONFIG_CENTER,\n                            \"\",\n                            \"\",\n                            \"The configuration center failed to initialize\",\n                            e);\n                    configCenter.setInitialized(false);\n                    return null;\n                } else {\n                    throw new IllegalStateException(e);\n                }\n            }\n            ApplicationModel applicationModel = getApplicationModel();\n\n            if (StringUtils.isNotEmpty(configCenter.getConfigFile())) {\n                String configContent =\n                        dynamicConfiguration.getProperties(configCenter.getConfigFile(), configCenter.getGroup());\n                if (StringUtils.isNotEmpty(configContent)) {\n                    logger.info(String.format(\n                            \"Got global remote configuration from config center with key-%s and group-%s: \\n %s\",\n                            configCenter.getConfigFile(), configCenter.getGroup(), configContent));\n                }\n                String appGroup = \"\";\n                String appConfigContent = null;\n                String appConfigFile = null;\n                Optional<ApplicationConfig> applicationOptional = getApplication();\n                if (applicationOptional.isPresent()) {\n                    appGroup = applicationOptional.get().getName();\n                    if (isNotEmpty(appGroup)) {\n                        appConfigFile = isNotEmpty(configCenter.getAppConfigFile())\n                                ? configCenter.getAppConfigFile()\n                                : configCenter.getConfigFile();\n                        appConfigContent = dynamicConfiguration.getProperties(appConfigFile, appGroup);\n                        if (StringUtils.isNotEmpty(appConfigContent)) {\n                            logger.info(String.format(\n                                    \"Got application specific remote configuration from config center with key %s and group %s: \\n %s\",\n                                    appConfigFile, appGroup, appConfigContent));\n                        }\n                    }\n                }\n                try {\n                    Map<String, String> configMap = parseProperties(configContent);\n                    Map<String, String> appConfigMap = parseProperties(appConfigContent);\n\n                    environment.updateExternalConfigMap(configMap);\n                    environment.updateAppExternalConfigMap(appConfigMap);\n\n                    // Add metrics\n                    MetricsEventBus.publish(ConfigCenterEvent.toChangeEvent(\n                            applicationModel,\n                            configCenter.getConfigFile(),\n                            configCenter.getGroup(),\n                            configCenter.getProtocol(),\n                            ConfigChangeType.ADDED.name(),\n                            configMap.size()));\n                    if (isNotEmpty(appGroup)) {\n                        MetricsEventBus.publish(ConfigCenterEvent.toChangeEvent(\n                                applicationModel,\n                                appConfigFile,\n                                appGroup,\n                                configCenter.getProtocol(),\n                                ConfigChangeType.ADDED.name(),\n                                appConfigMap.size()));\n                    }\n                } catch (IOException e) {\n                    throw new IllegalStateException(\"Failed to parse configurations from Config Center.\", e);\n                }\n            }\n            return dynamicConfiguration;\n        }\n        return null;\n    }\n\n    /**\n     * Get the instance of {@link DynamicConfiguration} by the specified connection {@link URL} of config-center\n     *\n     * @param connectionURL of config-center\n     * @return non-null\n     * @since 2.7.5\n     */\n    private DynamicConfiguration getDynamicConfiguration(URL connectionURL) {\n        String protocol = connectionURL.getProtocol();\n\n        DynamicConfigurationFactory factory =\n                ConfigurationUtils.getDynamicConfigurationFactory(applicationModel, protocol);\n        return factory.getDynamicConfiguration(connectionURL);\n    }\n\n    private volatile boolean registered = false;\n\n    private final AtomicInteger instanceRefreshScheduleTimes = new AtomicInteger(0);\n\n    /**\n     * Indicate that how many threads are updating service\n     */\n    private final AtomicInteger serviceRefreshState = new AtomicInteger(0);\n\n    public synchronized void registerServiceInstance() {\n        if (!registered) {\n            try {\n                registered = true;\n\n                ServiceInstanceMetadataUtils.registerMetadataAndInstance(applicationModel);\n\n            } catch (Exception e) {\n                logger.error(\n                        CONFIG_REGISTER_INSTANCE_ERROR,\n                        \"configuration server disconnected\",\n                        \"\",\n                        \"Register instance error.\",\n                        e);\n            }\n            // scheduled task for updating Metadata and ServiceInstance\n            asyncMetadataFuture = frameworkExecutorRepository\n                    .getSharedScheduledExecutor()\n                    .scheduleWithFixedDelay(\n                            () -> {\n\n                                // ignore refresh metadata on stopping\n                                if (applicationModel.isDestroyed()) {\n                                    return;\n                                }\n\n                                // refresh for 30 times (default for 30s) when deployer is not started, prevent submit\n                                // too many revision\n                                if (instanceRefreshScheduleTimes.incrementAndGet() % 30 != 0 && !isCompletion()) {\n                                    return;\n                                }\n\n                                // refresh for 5 times (default for 5s) when services are being updated by other\n                                // threads, prevent submit too many revision\n                                // note: should not always wait here\n                                if (serviceRefreshState.get() != 0 && instanceRefreshScheduleTimes.get() % 5 != 0) {\n                                    return;\n                                }\n\n                                try {\n                                    if (!applicationModel.isDestroyed() && registered) {\n                                        ServiceInstanceMetadataUtils.refreshMetadataAndInstance(applicationModel);\n                                    }\n                                } catch (Exception e) {\n                                    if (!applicationModel.isDestroyed()) {\n                                        logger.error(\n                                                CONFIG_REFRESH_INSTANCE_ERROR,\n                                                \"\",\n                                                \"\",\n                                                \"Refresh instance and metadata error.\",\n                                                e);\n                                    }\n                                }\n                            },\n                            0,\n                            ConfigurationUtils.get(\n                                    applicationModel, METADATA_PUBLISH_DELAY_KEY, DEFAULT_METADATA_PUBLISH_DELAY),\n                            TimeUnit.MILLISECONDS);\n        }\n    }\n\n    @Override\n    public void refreshServiceInstance() {\n        if (registered) {\n            try {\n                ServiceInstanceMetadataUtils.refreshMetadataAndInstance(applicationModel);\n            } catch (Exception e) {\n                logger.error(CONFIG_REFRESH_INSTANCE_ERROR, \"\", \"\", \"Refresh instance and metadata error.\", e);\n            }\n        }\n    }\n\n    @Override\n    public void increaseServiceRefreshCount() {\n        serviceRefreshState.incrementAndGet();\n    }\n\n    @Override\n    public void decreaseServiceRefreshCount() {\n        serviceRefreshState.decrementAndGet();\n    }\n\n    private void unregisterServiceInstance() {\n        if (registered) {\n            ServiceInstanceMetadataUtils.unregisterMetadataAndInstance(applicationModel);\n        }\n    }\n\n    @Override\n    public void stop() {\n        applicationModel.destroy();\n    }\n\n    @Override\n    public void preDestroy() {\n        synchronized (destroyLock) {\n            if (isStopping() || isStopped()) {\n                return;\n            }\n            onStopping();\n\n            offline();\n\n            unregisterServiceInstance();\n\n            unexportMetricsService();\n\n            unRegisterShutdownHook();\n            if (asyncMetadataFuture != null) {\n                asyncMetadataFuture.cancel(true);\n            }\n        }\n    }\n\n    private void offline() {\n        try {\n            for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n                ModuleServiceRepository serviceRepository = moduleModel.getServiceRepository();\n                List<ProviderModel> exportedServices = serviceRepository.getExportedServices();\n                for (ProviderModel exportedService : exportedServices) {\n                    List<ProviderModel.RegisterStatedURL> statedUrls = exportedService.getStatedUrl();\n                    for (ProviderModel.RegisterStatedURL statedURL : statedUrls) {\n                        if (statedURL.isRegistered()) {\n                            doOffline(statedURL);\n                        }\n                    }\n                }\n            }\n        } catch (Throwable t) {\n            logger.error(\n                    LoggerCodeConstants.INTERNAL_ERROR, \"\", \"\", \"Exceptions occurred when unregister services.\", t);\n        }\n    }\n\n    private void doOffline(ProviderModel.RegisterStatedURL statedURL) {\n        RegistryFactory registryFactory = statedURL\n                .getRegistryUrl()\n                .getOrDefaultApplicationModel()\n                .getExtensionLoader(RegistryFactory.class)\n                .getAdaptiveExtension();\n        Registry registry = registryFactory.getRegistry(statedURL.getRegistryUrl());\n        registry.unregister(statedURL.getProviderUrl());\n        statedURL.setRegistered(false);\n    }\n\n    @Override\n    public void postDestroy() {\n        synchronized (destroyLock) {\n            // expect application model is destroyed before here\n            if (isStopped()) {\n                return;\n            }\n            try {\n                destroyRegistries();\n                destroyMetadataReports();\n\n                executeShutdownCallbacks();\n\n                // TODO should we close unused protocol server which only used by this application?\n                // protocol server will be closed on all applications of same framework are stopped currently, but no\n                // associate to application\n                // see org.apache.dubbo.config.deploy.FrameworkModelCleaner#destroyProtocols\n                // see\n                // org.apache.dubbo.config.bootstrap.DubboBootstrapMultiInstanceTest#testMultiProviderApplicationStopOneByOne\n\n                // destroy all executor services\n                destroyExecutorRepository();\n\n                onStopped();\n            } catch (Throwable ex) {\n                String msg = getIdentifier() + \" an error occurred while stopping application: \" + ex.getMessage();\n                onFailed(msg, ex);\n            }\n        }\n    }\n\n    private void executeShutdownCallbacks() {\n        ShutdownHookCallbacks shutdownHookCallbacks =\n                applicationModel.getBeanFactory().getBean(ShutdownHookCallbacks.class);\n        shutdownHookCallbacks.callback();\n    }\n\n    @Override\n    public void notifyModuleChanged(ModuleModel moduleModel, DeployState state) {\n        checkState(moduleModel, state);\n\n        // notify module state changed or module changed\n        synchronized (stateLock) {\n            stateLock.notifyAll();\n        }\n    }\n\n    @Override\n    public void checkState(ModuleModel moduleModel, DeployState moduleState) {\n        synchronized (stateLock) {\n            if (!moduleModel.isInternal() && moduleState == DeployState.STARTED) {\n                prepareApplicationInstance(moduleModel);\n            }\n            DeployState newState = calculateState();\n            switch (newState) {\n                case STARTED:\n                    onStarted();\n                    break;\n                case COMPLETION:\n                    onCompletion();\n                    break;\n                case STARTING:\n                    onStarting();\n                    break;\n                case STOPPING:\n                    onStopping();\n                    break;\n                case STOPPED:\n                    onStopped();\n                    break;\n                case FAILED:\n                    Throwable error = null;\n                    ModuleModel errorModule = null;\n                    for (ModuleModel module : applicationModel.getModuleModels()) {\n                        ModuleDeployer deployer = module.getDeployer();\n                        if (deployer.isFailed() && deployer.getError() != null) {\n                            error = deployer.getError();\n                            errorModule = module;\n                            break;\n                        }\n                    }\n                    onFailed(getIdentifier() + \" found failed module: \" + errorModule.getDesc(), error);\n                    break;\n                case PENDING:\n                    // cannot change to pending from other state\n                    // setPending();\n                    break;\n                default:\n            }\n        }\n    }\n\n    private DeployState calculateState() {\n        int total = 0, pending = 0, starting = 0, started = 0, completion = 0, stopping = 0, stopped = 0, failed = 0;\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            ModuleDeployer deployer = moduleModel.getDeployer();\n            if (deployer == null) {\n                pending++;\n            } else if (deployer.isPending()) {\n                pending++;\n            } else if (deployer.isStarting()) {\n                starting++;\n            } else if (deployer.isCompletion()) {\n                completion++;\n            } else if (deployer.isStarted()) {\n                started++;\n            } else if (deployer.isStopping()) {\n                stopping++;\n            } else if (deployer.isStopped()) {\n                stopped++;\n            } else if (deployer.isFailed()) {\n                failed++;\n            }\n            total++;\n        }\n        // any module is failed\n        if (failed > 0) {\n            return DeployState.FAILED;\n        }\n        // all modules have not starting or started\n        if (pending == total) {\n            return DeployState.PENDING;\n        }\n        // all modules have completed\n        if (completion == total) {\n            return DeployState.COMPLETION;\n        }\n        // all modules are stopped\n        if (stopped == total) {\n            return DeployState.STOPPED;\n        }\n        // some module is starting or pending, it's in starting state\n        if (starting > 0 || pending > 0) {\n            return DeployState.STARTING;\n        }\n        // some module is stopping or stopped, it's in stopping state\n        if (stopping > 0 || stopped > 0) {\n            return DeployState.STOPPING;\n        }\n        // all modules have been started\n        if (started > 0) {\n            return DeployState.STARTED;\n        }\n        return DeployState.UNKNOWN;\n    }\n\n    private void onInitialize() {\n        for (DeployListener<ApplicationModel> listener : listeners) {\n            try {\n                listener.onInitialize(applicationModel);\n            } catch (Throwable e) {\n                logger.error(\n                        CONFIG_FAILED_START_MODEL,\n                        \"\",\n                        \"\",\n                        getIdentifier() + \" an exception occurred when handle initialize event\",\n                        e);\n            }\n        }\n    }\n\n    private void doExportMetadataService() {\n        if (!isStarting() && !isStarted() && !isCompletion()) {\n            return;\n        }\n        for (DeployListener<ApplicationModel> listener : listeners) {\n            try {\n                if (listener instanceof ApplicationDeployListener) {\n                    ((ApplicationDeployListener) listener).onModuleStarted(applicationModel);\n                }\n            } catch (Throwable e) {\n                logger.error(\n                        CONFIG_FAILED_START_MODEL,\n                        \"\",\n                        \"\",\n                        getIdentifier() + \" an exception occurred when handle starting event\",\n                        e);\n            }\n        }\n    }\n\n    private void onStarting() {\n        // pending -> starting\n        // started -> starting\n        // completion -> starting\n        if (!(isPending() || isStarted() || isCompletion())) {\n            return;\n        }\n        setStarting();\n        startFuture = new CompletableFuture();\n        if (logger.isInfoEnabled()) {\n            logger.info(getIdentifier() + \" is starting.\");\n        }\n    }\n\n    private void onStarted() {\n        // starting -> started\n        if (!isStarting()) {\n            return;\n        }\n        setStarted();\n        startMetricsCollector();\n        if (logger.isInfoEnabled()) {\n            logger.info(getIdentifier() + \" is ready.\");\n        }\n        // refresh metadata\n        try {\n            if (registered) {\n                ServiceInstanceMetadataUtils.refreshMetadataAndInstance(applicationModel);\n            }\n        } catch (Exception e) {\n            logger.error(CONFIG_REFRESH_INSTANCE_ERROR, \"\", \"\", \"Refresh instance and metadata error.\", e);\n        }\n    }\n\n    private void onCompletion() {\n        try {\n            // started -> completion\n            if (!isStarted()) {\n                return;\n            }\n            setCompletion();\n            if (logger.isInfoEnabled()) {\n                logger.info(getIdentifier() + \" has completed.\");\n            }\n        } finally {\n            // complete future\n            completeStartFuture(true);\n        }\n    }\n\n    private void startMetricsCollector() {\n        DefaultMetricsCollector collector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);\n        if (Objects.nonNull(collector) && collector.isThreadpoolCollectEnabled()) {\n            collector.registryDefaultSample();\n        }\n    }\n\n    private void completeStartFuture(boolean success) {\n        if (startFuture != null) {\n            startFuture.complete(success);\n        }\n    }\n\n    private void onStopping() {\n        try {\n            if (isStopping() || isStopped()) {\n                return;\n            }\n            setStopping();\n            if (logger.isInfoEnabled()) {\n                logger.info(getIdentifier() + \" is stopping.\");\n            }\n        } finally {\n            completeStartFuture(false);\n        }\n    }\n\n    private void onStopped() {\n        try {\n            if (isStopped()) {\n                return;\n            }\n            setStopped();\n            if (logger.isInfoEnabled()) {\n                logger.info(getIdentifier() + \" has stopped.\");\n            }\n        } finally {\n            completeStartFuture(false);\n        }\n    }\n\n    private void onFailed(String msg, Throwable ex) {\n        try {\n            setFailed(ex);\n            logger.error(CONFIG_FAILED_START_MODEL, \"\", \"\", msg, ex);\n        } finally {\n            completeStartFuture(false);\n        }\n    }\n\n    private void destroyExecutorRepository() {\n        // shutdown export/refer executor\n        executorRepository.shutdownServiceExportExecutor();\n        executorRepository.shutdownServiceReferExecutor();\n        ExecutorRepository.getInstance(applicationModel).destroyAll();\n    }\n\n    private void destroyRegistries() {\n        RegistryManager.getInstance(applicationModel).destroyAll();\n    }\n\n    private void destroyServiceDiscoveries() {\n        RegistryManager.getInstance(applicationModel).getServiceDiscoveries().forEach(serviceDiscovery -> {\n            try {\n                serviceDiscovery.destroy();\n            } catch (Throwable ignored) {\n                logger.warn(CONFIG_FAILED_EXECUTE_DESTROY, \"\", \"\", ignored.getMessage(), ignored);\n            }\n        });\n        if (logger.isDebugEnabled()) {\n            logger.debug(getIdentifier() + \"'s all ServiceDiscoveries have been destroyed.\");\n        }\n    }\n\n    private void destroyMetadataReports() {\n        // only destroy MetadataReport of this application\n        List<MetadataReportFactory> metadataReportFactories =\n                getExtensionLoader(MetadataReportFactory.class).getLoadedExtensionInstances();\n        for (MetadataReportFactory metadataReportFactory : metadataReportFactories) {\n            metadataReportFactory.destroy();\n        }\n    }\n\n    private ApplicationConfig getApplicationOrElseThrow() {\n        return configManager.getApplicationOrElseThrow();\n    }\n\n    private Optional<ApplicationConfig> getApplication() {\n        return configManager.getApplication();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultMetricsServiceExporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.deploy;\n\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.bootstrap.builders.InternalServiceConfigBuilder;\nimport org.apache.dubbo.metrics.service.MetricsService;\nimport org.apache.dubbo.metrics.service.MetricsServiceExporter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport java.util.Optional;\nimport java.util.concurrent.ExecutorService;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_DEFAULT;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\n\n/**\n * Export metrics service\n */\npublic class DefaultMetricsServiceExporter implements MetricsServiceExporter, ScopeModelAware {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private ApplicationModel applicationModel;\n    private MetricsService metricsService;\n    private volatile ServiceConfig<MetricsService> serviceConfig;\n\n    @Override\n    public void init() {\n        initialize();\n    }\n\n    private void initialize() {\n        MetricsConfig metricsConfig =\n                applicationModel.getApplicationConfigManager().getMetrics().orElse(null);\n        // TODO compatible with old usage of metrics, remove protocol check after new metrics is ready for use.\n        if (metricsConfig != null && metricsService == null) {\n            String protocol = Optional.ofNullable(metricsConfig.getProtocol()).orElse(PROTOCOL_PROMETHEUS);\n            if (PROTOCOL_DEFAULT.equals(protocol) || PROTOCOL_PROMETHEUS.equals(protocol)) {\n                this.metricsService = applicationModel\n                        .getExtensionLoader(MetricsService.class)\n                        .getDefaultExtension();\n            } else {\n                logger.warn(\n                        COMMON_METRICS_COLLECTOR_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Protocol \" + protocol + \" not support for new metrics mechanism. \"\n                                + \"Using old metrics mechanism instead.\");\n            }\n        }\n    }\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    @Override\n    public MetricsServiceExporter export() {\n        if (metricsService != null) {\n            if (!isExported()) {\n                ExecutorService internalServiceExecutor = applicationModel\n                        .getFrameworkModel()\n                        .getBeanFactory()\n                        .getBean(FrameworkExecutorRepository.class)\n                        .getInternalServiceExecutor();\n                ServiceConfig<MetricsService> serviceConfig = InternalServiceConfigBuilder.<MetricsService>newBuilder(\n                                applicationModel)\n                        .interfaceClass(MetricsService.class)\n                        .protocol(getMetricsConfig().getExportServiceProtocol())\n                        .port(getMetricsConfig().getExportServicePort())\n                        .executor(internalServiceExecutor)\n                        .ref(metricsService)\n                        .registryId(\"internal-metrics-registry\")\n                        .build();\n\n                // export\n                serviceConfig.export();\n\n                if (logger.isInfoEnabled()) {\n                    logger.info(\"The MetricsService exports urls : \" + serviceConfig.getExportedUrls());\n                }\n                this.serviceConfig = serviceConfig;\n            } else {\n                if (logger.isWarnEnabled()) {\n                    logger.warn(\n                            LoggerCodeConstants.INTERNAL_ERROR,\n                            \"\",\n                            \"\",\n                            \"The MetricsService has been exported : \" + serviceConfig.getExportedUrls());\n                }\n            }\n        } else {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"The MetricsConfig not exist, will not export metrics service.\");\n            }\n        }\n\n        return this;\n    }\n\n    @Override\n    public MetricsServiceExporter unexport() {\n        if (isExported()) {\n            serviceConfig.unexport();\n        }\n        return this;\n    }\n\n    private MetricsConfig getMetricsConfig() {\n        Optional<MetricsConfig> metricsConfig =\n                applicationModel.getApplicationConfigManager().getMetrics();\n        if (metricsConfig.isPresent()) {\n            return metricsConfig.get();\n        } else {\n            throw new IllegalStateException(\"There's no MetricsConfig specified.\");\n        }\n    }\n\n    private boolean isExported() {\n        return serviceConfig != null && serviceConfig.isExported() && !serviceConfig.isUnexported();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultModuleDeployer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.deploy;\n\nimport org.apache.dubbo.common.config.ReferenceCache;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.constants.RegisterTypeEnum;\nimport org.apache.dubbo.common.deploy.AbstractDeployer;\nimport org.apache.dubbo.common.deploy.ApplicationDeployer;\nimport org.apache.dubbo.common.deploy.DeployListener;\nimport org.apache.dubbo.common.deploy.DeployState;\nimport org.apache.dubbo.common.deploy.ModuleDeployListener;\nimport org.apache.dubbo.common.deploy.ModuleDeployer;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceConfigBase;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.config.utils.SimpleReferenceCache;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Future;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_EXPORT_SERVICE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_REFERENCE_MODEL;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_REFER_SERVICE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_START_MODEL;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_WAIT_EXPORT_REFER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNABLE_DESTROY_MODEL;\n\n/**\n * Export/refer services of module\n */\npublic class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> implements ModuleDeployer {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DefaultModuleDeployer.class);\n\n    private final List<CompletableFuture<?>> asyncExportingFutures = new ArrayList<>();\n\n    private final List<CompletableFuture<?>> asyncReferringFutures = new ArrayList<>();\n\n    private final List<ServiceConfigBase<?>> exportedServices = new ArrayList<>();\n\n    private final ModuleModel moduleModel;\n\n    private final FrameworkExecutorRepository frameworkExecutorRepository;\n    private final ExecutorRepository executorRepository;\n\n    private final ModuleConfigManager configManager;\n\n    private final SimpleReferenceCache referenceCache;\n\n    private final ApplicationDeployer applicationDeployer;\n    private CompletableFuture startFuture;\n    private Boolean background;\n    private Boolean exportAsync;\n    private Boolean referAsync;\n\n    private boolean registryInteracted;\n\n    private CompletableFuture<?> exportFuture;\n    private CompletableFuture<?> referFuture;\n\n    public DefaultModuleDeployer(ModuleModel moduleModel) {\n        super(moduleModel);\n        this.moduleModel = moduleModel;\n        configManager = moduleModel.getConfigManager();\n        frameworkExecutorRepository = moduleModel\n                .getApplicationModel()\n                .getFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class);\n        executorRepository = ExecutorRepository.getInstance(moduleModel.getApplicationModel());\n        referenceCache = SimpleReferenceCache.newCache();\n        applicationDeployer = DefaultApplicationDeployer.get(moduleModel);\n\n        // load spi listener\n        Set<ModuleDeployListener> listeners =\n                moduleModel.getExtensionLoader(ModuleDeployListener.class).getSupportedExtensionInstances();\n        for (ModuleDeployListener listener : listeners) {\n            this.addDeployListener(listener);\n        }\n    }\n\n    @Override\n    public void initialize() throws IllegalStateException {\n        if (initialized) {\n            return;\n        }\n        // Ensure that the initialization is completed when concurrent calls\n        synchronized (this) {\n            if (initialized) {\n                return;\n            }\n            onInitialize();\n\n            loadConfigs();\n\n            // read ModuleConfig\n            ModuleConfig moduleConfig = moduleModel\n                    .getConfigManager()\n                    .getModule()\n                    .orElseThrow(() -> new IllegalStateException(\"Default module config is not initialized\"));\n            exportAsync = Boolean.TRUE.equals(moduleConfig.getExportAsync());\n            referAsync = Boolean.TRUE.equals(moduleConfig.getReferAsync());\n\n            // start in background\n            background = moduleConfig.getBackground();\n            if (background == null) {\n                // compatible with old usages\n                background = isExportBackground() || isReferBackground();\n            }\n\n            initialized = true;\n            if (logger.isInfoEnabled()) {\n                logger.info(getIdentifier() + \" has been initialized!\");\n            }\n        }\n    }\n\n    @Override\n    public Future start() throws IllegalStateException {\n        // initialize，maybe deadlock applicationDeployer lock & moduleDeployer lock\n        applicationDeployer.initialize();\n\n        return startSync();\n    }\n\n    private synchronized Future startSync() throws IllegalStateException {\n        if (isStopping() || isStopped() || isFailed()) {\n            throw new IllegalStateException(getIdentifier() + \" is stopping or stopped, can not start again\");\n        }\n\n        try {\n            if (isStarting() || isStarted() || isCompletion()) {\n                return startFuture;\n            }\n\n            onModuleStarting();\n\n            initialize();\n\n            // export services\n            exportServices();\n\n            // prepare application instance\n            // exclude internal module to avoid wait itself\n            if (moduleModel != moduleModel.getApplicationModel().getInternalModule()) {\n                applicationDeployer.prepareInternalModule();\n            }\n\n            // refer services\n            referServices();\n\n            // if no async export/refer services, just set started\n            if (asyncExportingFutures.isEmpty() && asyncReferringFutures.isEmpty()) {\n                // publish module started event\n                onModuleStarted();\n\n                // register services to registry\n                registerServices();\n\n                // check reference config\n                checkReferences();\n\n                // publish module completion event\n                onModuleCompletion();\n\n                // complete module start future after application state changed\n                completeStartFuture(true);\n            } else {\n                frameworkExecutorRepository.getSharedExecutor().submit(() -> {\n                    try {\n                        // wait for export finish\n                        waitExportFinish();\n\n                        // wait for refer finish\n                        waitReferFinish();\n\n                        // publish module started event\n                        onModuleStarted();\n\n                        // register services to registry\n                        registerServices();\n\n                        // check reference config\n                        checkReferences();\n\n                        // publish module completion event\n                        onModuleCompletion();\n                    } catch (Throwable e) {\n                        logger.warn(\n                                CONFIG_FAILED_WAIT_EXPORT_REFER,\n                                \"\",\n                                \"\",\n                                \"wait for export/refer services occurred an exception\",\n                                e);\n                        onModuleFailed(getIdentifier() + \" start failed: \" + e, e);\n                    } finally {\n                        // complete module start future after application state changed\n                        completeStartFuture(true);\n                    }\n                });\n            }\n\n        } catch (Throwable e) {\n            onModuleFailed(getIdentifier() + \" start failed: \" + e, e);\n            throw e;\n        }\n\n        return startFuture;\n    }\n\n    @Override\n    public Future getStartFuture() {\n        return startFuture;\n    }\n\n    private boolean hasExportedServices() {\n        return !configManager.getServices().isEmpty();\n    }\n\n    @Override\n    public void stop() throws IllegalStateException {\n        moduleModel.destroy();\n    }\n\n    @Override\n    public void preDestroy() throws IllegalStateException {\n        if (isStopping() || isStopped()) {\n            return;\n        }\n        onModuleStopping();\n\n        offline();\n    }\n\n    private void offline() {\n        try {\n            ModuleServiceRepository serviceRepository = moduleModel.getServiceRepository();\n            List<ProviderModel> exportedServices = serviceRepository.getExportedServices();\n            for (ProviderModel exportedService : exportedServices) {\n                List<ProviderModel.RegisterStatedURL> statedUrls = exportedService.getStatedUrl();\n                for (ProviderModel.RegisterStatedURL statedURL : statedUrls) {\n                    if (statedURL.isRegistered()) {\n                        doOffline(statedURL);\n                    }\n                }\n            }\n        } catch (Throwable t) {\n            logger.error(\n                    LoggerCodeConstants.INTERNAL_ERROR, \"\", \"\", \"Exceptions occurred when unregister services.\", t);\n        }\n    }\n\n    private void doOffline(ProviderModel.RegisterStatedURL statedURL) {\n        RegistryFactory registryFactory = statedURL\n                .getRegistryUrl()\n                .getOrDefaultApplicationModel()\n                .getExtensionLoader(RegistryFactory.class)\n                .getAdaptiveExtension();\n        Registry registry = registryFactory.getRegistry(statedURL.getRegistryUrl());\n        registry.unregister(statedURL.getProviderUrl());\n        statedURL.setRegistered(false);\n    }\n\n    @Override\n    public synchronized void postDestroy() throws IllegalStateException {\n        if (isStopped()) {\n            return;\n        }\n        unexportServices();\n        unreferServices();\n\n        ModuleServiceRepository serviceRepository = moduleModel.getServiceRepository();\n        if (serviceRepository != null) {\n            List<ConsumerModel> consumerModels = serviceRepository.getReferredServices();\n\n            for (ConsumerModel consumerModel : consumerModels) {\n                try {\n                    if (consumerModel.getDestroyRunner() != null) {\n                        consumerModel.getDestroyRunner().run();\n                    }\n                } catch (Throwable t) {\n                    logger.error(\n                            CONFIG_UNABLE_DESTROY_MODEL,\n                            \"there are problems with the custom implementation.\",\n                            \"\",\n                            \"Unable to destroy model: consumerModel.\",\n                            t);\n                }\n            }\n\n            List<ProviderModel> exportedServices = serviceRepository.getExportedServices();\n            for (ProviderModel providerModel : exportedServices) {\n                try {\n                    if (providerModel.getDestroyRunner() != null) {\n                        providerModel.getDestroyRunner().run();\n                    }\n                } catch (Throwable t) {\n                    logger.error(\n                            CONFIG_UNABLE_DESTROY_MODEL,\n                            \"there are problems with the custom implementation.\",\n                            \"\",\n                            \"Unable to destroy model: providerModel.\",\n                            t);\n                }\n            }\n            serviceRepository.destroy();\n        }\n        onModuleStopped();\n    }\n\n    private void onInitialize() {\n        for (DeployListener<ModuleModel> listener : listeners) {\n            try {\n                listener.onInitialize(moduleModel);\n            } catch (Throwable e) {\n                logger.error(\n                        CONFIG_FAILED_START_MODEL,\n                        \"\",\n                        \"\",\n                        getIdentifier() + \" an exception occurred when handle initialize event\",\n                        e);\n            }\n        }\n    }\n\n    private void onModuleStarting() {\n        setStarting();\n        startFuture = new CompletableFuture();\n        logger.info(getIdentifier() + \" is starting.\");\n        applicationDeployer.notifyModuleChanged(moduleModel, DeployState.STARTING);\n    }\n\n    private void onModuleStarted() {\n        if (isStarting()) {\n            setStarted();\n            logger.info(getIdentifier() + \" has started.\");\n            applicationDeployer.notifyModuleChanged(moduleModel, DeployState.STARTED);\n        }\n    }\n\n    private void onModuleCompletion() {\n        if (isStarted()) {\n            setCompletion();\n            logger.info(getIdentifier() + \" has completed.\");\n            applicationDeployer.notifyModuleChanged(moduleModel, DeployState.COMPLETION);\n        }\n    }\n\n    private void onModuleFailed(String msg, Throwable ex) {\n        try {\n            try {\n                // un-export all services if start failure\n                unexportServices();\n            } catch (Throwable t) {\n                logger.info(\"Failed to un-export services after module failed.\", t);\n            }\n\n            setFailed(ex);\n            logger.error(CONFIG_FAILED_START_MODEL, \"\", \"\", \"Model start failed: \" + msg, ex);\n            applicationDeployer.notifyModuleChanged(moduleModel, DeployState.FAILED);\n        } finally {\n            completeStartFuture(false);\n        }\n    }\n\n    private void completeStartFuture(boolean value) {\n        if (startFuture != null && !startFuture.isDone()) {\n            startFuture.complete(value);\n        }\n        if (exportFuture != null && !exportFuture.isDone()) {\n            exportFuture.cancel(true);\n        }\n        if (referFuture != null && !referFuture.isDone()) {\n            referFuture.cancel(true);\n        }\n    }\n\n    private void onModuleStopping() {\n        try {\n            setStopping();\n            logger.info(getIdentifier() + \" is stopping.\");\n            applicationDeployer.notifyModuleChanged(moduleModel, DeployState.STOPPING);\n        } finally {\n            completeStartFuture(false);\n        }\n    }\n\n    private void onModuleStopped() {\n        try {\n            setStopped();\n            logger.info(getIdentifier() + \" has stopped.\");\n            applicationDeployer.notifyModuleChanged(moduleModel, DeployState.STOPPED);\n        } finally {\n            completeStartFuture(false);\n        }\n    }\n\n    private void loadConfigs() {\n        // load module configs\n        moduleModel.getConfigManager().loadConfigs();\n        moduleModel.getConfigManager().refreshAll();\n    }\n\n    private void exportServices() {\n        for (ServiceConfigBase sc : configManager.getServices()) {\n            exportServiceInternal(sc);\n        }\n    }\n\n    private void registerServices() {\n        for (ServiceConfigBase sc : configManager.getServices()) {\n            if (!Boolean.FALSE.equals(sc.isRegister())) {\n                registerServiceInternal(sc);\n            }\n        }\n        applicationDeployer.refreshServiceInstance();\n    }\n\n    private void checkReferences() {\n        Optional<ModuleConfig> module = configManager.getModule();\n        long timeout = module.map(ModuleConfig::getCheckReferenceTimeout).orElse(30000L);\n        for (ReferenceConfigBase<?> rc : configManager.getReferences()) {\n            referenceCache.check(rc, timeout);\n        }\n    }\n\n    private void exportServiceInternal(ServiceConfigBase sc) {\n        ServiceConfig<?> serviceConfig = (ServiceConfig<?>) sc;\n        if (!serviceConfig.isRefreshed()) {\n            serviceConfig.refresh();\n        }\n        if (sc.isExported()) {\n            return;\n        }\n        if (exportAsync || sc.shouldExportAsync()) {\n            ExecutorService executor = executorRepository.getServiceExportExecutor();\n            CompletableFuture<Void> future = CompletableFuture.runAsync(\n                    () -> {\n                        try {\n                            if (!sc.isExported()) {\n                                sc.export();\n                                exportedServices.add(sc);\n                            }\n                        } catch (Throwable t) {\n                            logger.error(\n                                    CONFIG_FAILED_EXPORT_SERVICE,\n                                    \"\",\n                                    \"\",\n                                    \"Failed to async export service config: \" + getIdentifier() + \" , catch error : \"\n                                            + t.getMessage(),\n                                    t);\n                        }\n                    },\n                    executor);\n\n            asyncExportingFutures.add(future);\n        } else {\n            if (!sc.isExported()) {\n                sc.export(RegisterTypeEnum.AUTO_REGISTER_BY_DEPLOYER);\n                exportedServices.add(sc);\n            }\n        }\n\n        if (serviceConfig.hasRegistrySpecified()) {\n            registryInteracted = true;\n        }\n    }\n\n    private void registerServiceInternal(ServiceConfigBase sc) {\n        ServiceConfig<?> serviceConfig = (ServiceConfig<?>) sc;\n        if (!serviceConfig.isRefreshed()) {\n            serviceConfig.refresh();\n        }\n        if (!sc.isExported()) {\n            return;\n        }\n        if (sc.shouldDelay()) {\n            return;\n        }\n        sc.register(true);\n    }\n\n    private void unexportServices() {\n        exportedServices.forEach(sc -> {\n            try {\n                configManager.removeConfig(sc);\n                sc.unexport();\n            } catch (Throwable t) {\n                logger.info(\"Failed to un-export service. Service Key: \" + sc.getUniqueServiceName(), t);\n            }\n        });\n        exportedServices.clear();\n\n        asyncExportingFutures.forEach(future -> {\n            if (!future.isDone()) {\n                future.cancel(true);\n            }\n        });\n        asyncExportingFutures.clear();\n    }\n\n    private void referServices() {\n        configManager.getReferences().forEach(rc -> {\n            try {\n                ReferenceConfig<?> referenceConfig = (ReferenceConfig<?>) rc;\n                if (!referenceConfig.isRefreshed()) {\n                    referenceConfig.refresh();\n                }\n\n                if (rc.shouldInit()) {\n                    if (referAsync || rc.shouldReferAsync()) {\n                        ExecutorService executor = executorRepository.getServiceReferExecutor();\n                        CompletableFuture<Void> future = CompletableFuture.runAsync(\n                                () -> {\n                                    try {\n                                        referenceCache.get(rc, false);\n                                    } catch (Throwable t) {\n                                        logger.error(\n                                                CONFIG_FAILED_EXPORT_SERVICE,\n                                                \"\",\n                                                \"\",\n                                                \"Failed to async export service config: \" + getIdentifier()\n                                                        + \" , catch error : \" + t.getMessage(),\n                                                t);\n                                    }\n                                },\n                                executor);\n\n                        asyncReferringFutures.add(future);\n                    } else {\n                        referenceCache.get(rc, false);\n                    }\n                }\n            } catch (Throwable t) {\n                logger.error(\n                        CONFIG_FAILED_REFERENCE_MODEL,\n                        \"\",\n                        \"\",\n                        \"Model reference failed: \" + getIdentifier() + \" , catch error : \" + t.getMessage(),\n                        t);\n                referenceCache.destroy(rc);\n                throw t;\n            }\n        });\n    }\n\n    private void unreferServices() {\n        try {\n            asyncReferringFutures.forEach(future -> {\n                if (!future.isDone()) {\n                    future.cancel(true);\n                }\n            });\n            asyncReferringFutures.clear();\n            referenceCache.destroyAll();\n            for (ReferenceConfigBase<?> rc : configManager.getReferences()) {\n                rc.destroy();\n            }\n        } catch (Exception ignored) {\n        }\n    }\n\n    private void waitExportFinish() {\n        try {\n            logger.info(getIdentifier() + \" waiting services exporting ...\");\n            exportFuture = CompletableFuture.allOf(asyncExportingFutures.toArray(new CompletableFuture[0]));\n            exportFuture.get();\n        } catch (Throwable e) {\n            logger.warn(\n                    CONFIG_FAILED_EXPORT_SERVICE,\n                    \"\",\n                    \"\",\n                    getIdentifier() + \" export services occurred an exception: \" + e.toString());\n        } finally {\n            logger.info(getIdentifier() + \" export services finished.\");\n            asyncExportingFutures.clear();\n        }\n    }\n\n    private void waitReferFinish() {\n        try {\n            logger.info(getIdentifier() + \" waiting services referring ...\");\n            referFuture = CompletableFuture.allOf(asyncReferringFutures.toArray(new CompletableFuture[0]));\n            referFuture.get();\n        } catch (Throwable e) {\n            logger.warn(\n                    CONFIG_FAILED_REFER_SERVICE,\n                    \"\",\n                    \"\",\n                    getIdentifier() + \" refer services occurred an exception: \" + e.toString());\n        } finally {\n            logger.info(getIdentifier() + \" refer services finished.\");\n            asyncReferringFutures.clear();\n        }\n    }\n\n    @Override\n    public boolean isBackground() {\n        return background;\n    }\n\n    private boolean isExportBackground() {\n        return moduleModel.getConfigManager().getProviders().stream()\n                .map(ProviderConfig::getExportBackground)\n                .anyMatch(k -> k != null && k);\n    }\n\n    private boolean isReferBackground() {\n        return moduleModel.getConfigManager().getConsumers().stream()\n                .map(ConsumerConfig::getReferBackground)\n                .anyMatch(k -> k != null && k);\n    }\n\n    @Override\n    public ReferenceCache getReferenceCache() {\n        return referenceCache;\n    }\n\n    @Override\n    public void registerServiceInstance() {\n        applicationDeployer.registerServiceInstance();\n    }\n\n    /**\n     * Prepare for export/refer service, trigger initializing application and module\n     */\n    @Override\n    public void prepare() {\n        applicationDeployer.initialize();\n        this.initialize();\n    }\n\n    @Override\n    public boolean hasRegistryInteraction() {\n        return registryInteracted;\n    }\n\n    @Override\n    public ApplicationDeployer getApplicationDeployer() {\n        return applicationDeployer;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/FrameworkModelCleaner.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.deploy;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModelDestroyListener;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNDEFINED_PROTOCOL;\n\n/**\n * A cleaner to release resources of framework model\n */\npublic class FrameworkModelCleaner implements ScopeModelDestroyListener<FrameworkModel> {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(FrameworkModelCleaner.class);\n\n    private final AtomicBoolean protocolDestroyed = new AtomicBoolean(false);\n\n    @Override\n    public boolean isProtocol() {\n        return true;\n    }\n\n    @Override\n    public void onDestroy(FrameworkModel frameworkModel) {\n        destroyFrameworkResources(frameworkModel);\n    }\n\n    /**\n     * Destroy all framework resources.\n     */\n    private void destroyFrameworkResources(FrameworkModel frameworkModel) {\n        // destroy protocol in framework scope\n        destroyProtocols(frameworkModel);\n    }\n\n    /**\n     * Destroy all the protocols.\n     */\n    private void destroyProtocols(FrameworkModel frameworkModel) {\n        if (protocolDestroyed.compareAndSet(false, true)) {\n            ExtensionLoader<Protocol> loader = frameworkModel.getExtensionLoader(Protocol.class);\n            for (String protocolName : loader.getLoadedExtensions()) {\n                try {\n                    Protocol protocol = loader.getLoadedExtension(protocolName);\n                    if (protocol != null) {\n                        protocol.destroy();\n                    }\n                } catch (Throwable t) {\n                    logger.warn(CONFIG_UNDEFINED_PROTOCOL, \"\", \"\", t.getMessage(), t);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/invoker/DelegateProviderMetaDataInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.invoker;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\n/**\n * An invoker wrapper that wrap the invoker and all the metadata (ServiceConfig)\n */\npublic class DelegateProviderMetaDataInvoker<T> implements Invoker {\n    protected final Invoker<T> invoker;\n    private final ServiceConfig<?> metadata;\n\n    public DelegateProviderMetaDataInvoker(Invoker<T> invoker, ServiceConfig<?> metadata) {\n        this.invoker = invoker;\n        this.metadata = metadata;\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return invoker.getInterface();\n    }\n\n    @Override\n    public URL getUrl() {\n        return invoker.getUrl();\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return invoker.isAvailable();\n    }\n\n    @Override\n    public Result invoke(Invocation invocation) throws RpcException {\n        return invoker.invoke(invocation);\n    }\n\n    @Override\n    public void destroy() {\n        invoker.destroy();\n    }\n\n    public ServiceConfig<?> getMetadata() {\n        return metadata;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ArgumentConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.bootstrap.builders.InternalServiceConfigBuilder;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.metadata.MetadataServiceV2;\nimport org.apache.dubbo.metadata.util.MetadataServiceVersionUtils;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegationV2;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_SERVICE_PORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_SERVICE_PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TRIPLE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_METADATA_SERVICE_EXPORTED;\nimport static org.apache.dubbo.metadata.util.MetadataServiceVersionUtils.V1;\nimport static org.apache.dubbo.metadata.util.MetadataServiceVersionUtils.V2;\n\n/**\n * Export metadata service\n */\npublic class ConfigurableMetadataServiceExporter {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    @Deprecated\n    private final MetadataServiceDelegation metadataService;\n\n    private final MetadataServiceDelegationV2 metadataServiceV2;\n\n    @Deprecated\n    private volatile ServiceConfig<MetadataService> serviceConfig;\n\n    private volatile ServiceConfig<MetadataServiceV2> serviceConfigV2;\n\n    private final ApplicationModel applicationModel;\n\n    public ConfigurableMetadataServiceExporter(\n            ApplicationModel applicationModel,\n            MetadataServiceDelegation metadataService,\n            MetadataServiceDelegationV2 metadataServiceV2) {\n        this.applicationModel = applicationModel;\n        this.metadataService = metadataService;\n        this.metadataServiceV2 = metadataServiceV2;\n    }\n\n    public synchronized ConfigurableMetadataServiceExporter export() {\n        if (!isExported()) {\n            if (MetadataServiceVersionUtils.needExportV1(applicationModel)) {\n                exportV1();\n            }\n            if (MetadataServiceVersionUtils.needExportV2(applicationModel)) {\n                exportV2();\n            }\n        } else {\n            if (logger.isWarnEnabled()) {\n                logger.warn(\n                        CONFIG_METADATA_SERVICE_EXPORTED,\n                        \"\",\n                        \"\",\n                        \"The MetadataService has been exported : \" + getExportedUrls());\n            }\n        }\n\n        return this;\n    }\n\n    /**\n     * Get exported urls which include v1 and v2 if existed\n     * @return exported urls\n     */\n    public List<URL> getExportedUrls() {\n        List<URL> urls = new ArrayList<>();\n        if (serviceConfig != null) {\n            urls.addAll(serviceConfig.getExportedUrls());\n        }\n        if (serviceConfigV2 != null) {\n            urls.addAll(serviceConfigV2.getExportedUrls());\n        }\n        return urls;\n    }\n\n    private static final String INTERNAL_METADATA_REGISTRY_ID = \"internal-metadata-registry\";\n\n    private void exportV1() {\n        ExecutorService internalServiceExecutor = applicationModel\n                .getFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getInternalServiceExecutor();\n        this.serviceConfig = InternalServiceConfigBuilder.<MetadataService>newBuilder(applicationModel)\n                .interfaceClass(MetadataService.class)\n                .protocol(getApplicationConfig().getMetadataServiceProtocol(), METADATA_SERVICE_PROTOCOL_KEY)\n                .port(getApplicationConfig().getMetadataServicePort(), METADATA_SERVICE_PORT_KEY)\n                .registryId(INTERNAL_METADATA_REGISTRY_ID)\n                .executor(internalServiceExecutor)\n                .ref(metadataService)\n                .version(V1)\n                .build(configConsumer -> configConsumer.setMethods(generateMethodConfig()));\n\n        serviceConfig.export();\n        metadataService.setMetadataURL(serviceConfig.getExportedUrls().get(0));\n\n        if (logger.isInfoEnabled()) {\n            logger.info(\"[SERVICE_PUBLISH] [METADATA_REGISTER] The MetadataService exports urls : \"\n                    + serviceConfig.getExportedUrls());\n        }\n    }\n\n    private void exportV2() {\n        ExecutorService internalServiceExecutor = applicationModel\n                .getFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getInternalServiceExecutor();\n        this.serviceConfigV2 = InternalServiceConfigBuilder.<MetadataServiceV2>newBuilder(applicationModel)\n                .interfaceClass(MetadataServiceV2.class)\n                .protocol(TRIPLE, METADATA_SERVICE_PROTOCOL_KEY)\n                .port(getApplicationConfig().getMetadataServicePort(), METADATA_SERVICE_PORT_KEY)\n                .registryId(INTERNAL_METADATA_REGISTRY_ID)\n                .executor(internalServiceExecutor)\n                .ref(metadataServiceV2)\n                .version(V2)\n                .build();\n\n        serviceConfigV2.export();\n        metadataServiceV2.setMetadataUrl(serviceConfigV2.getExportedUrls().get(0));\n\n        if (logger.isInfoEnabled()) {\n            logger.info(\"[SERVICE_PUBLISH][METADATA_REGISTER] The MetadataServiceV2 exports urls : \"\n                    + serviceConfigV2.getExportedUrls());\n        }\n    }\n\n    public ConfigurableMetadataServiceExporter unexport() {\n        if (isExported()) {\n            serviceConfig.unexport();\n            serviceConfigV2.unexport();\n            metadataService.setMetadataURL(null);\n        }\n        return this;\n    }\n\n    private boolean v1Exported() {\n        return serviceConfig != null && serviceConfig.isExported() && !serviceConfig.isUnexported();\n    }\n\n    private boolean v2Exported() {\n        return serviceConfigV2 != null && serviceConfigV2.isExported() && !serviceConfigV2.isUnexported();\n    }\n\n    public boolean isExported() {\n        return v1Exported() || v2Exported();\n    }\n\n    private ApplicationConfig getApplicationConfig() {\n        return applicationModel.getApplicationConfigManager().getApplication().get();\n    }\n\n    /**\n     * Generate Method Config for Service Discovery Metadata <p/>\n     * <p>\n     * Make {@link MetadataService} support argument callback,\n     * used to notify {@link org.apache.dubbo.registry.client.ServiceInstance}'s\n     * metadata change event\n     *\n     * @since 3.0\n     */\n    private List<MethodConfig> generateMethodConfig() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setName(\"getAndListenInstanceMetadata\");\n\n        ArgumentConfig argumentConfig = new ArgumentConfig();\n        argumentConfig.setIndex(1);\n        argumentConfig.setCallback(true);\n\n        methodConfig.setArguments(Collections.singletonList(argumentConfig));\n\n        return Collections.singletonList(methodConfig);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ExporterDeployListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.metadata;\n\nimport org.apache.dubbo.common.deploy.ApplicationDeployListener;\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegationV2;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_REGISTER_MODE;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_REGISTER_MODE;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;\n\npublic class ExporterDeployListener implements ApplicationDeployListener, Prioritized {\n    protected volatile ConfigurableMetadataServiceExporter metadataServiceExporter;\n\n    @Override\n    public void onInitialize(ApplicationModel scopeModel) {}\n\n    @Override\n    public void onStarting(ApplicationModel scopeModel) {}\n\n    @Override\n    public synchronized void onStarted(ApplicationModel applicationModel) {}\n\n    @Override\n    public void onCompletion(ApplicationModel scopeModel) {}\n\n    @Override\n    public synchronized void onStopping(ApplicationModel scopeModel) {}\n\n    private String getMetadataType(ApplicationModel applicationModel) {\n        String type = applicationModel\n                .getApplicationConfigManager()\n                .getApplicationOrElseThrow()\n                .getMetadataType();\n        if (StringUtils.isEmpty(type)) {\n            type = DEFAULT_METADATA_STORAGE_TYPE;\n        }\n        return type;\n    }\n\n    private String getRegisterMode(ApplicationModel applicationModel) {\n        String type = applicationModel\n                .getApplicationConfigManager()\n                .getApplicationOrElseThrow()\n                .getRegisterMode();\n        if (StringUtils.isEmpty(type)) {\n            type = DEFAULT_REGISTER_MODE;\n        }\n        return type;\n    }\n\n    public ConfigurableMetadataServiceExporter getMetadataServiceExporter() {\n        return metadataServiceExporter;\n    }\n\n    public void setMetadataServiceExporter(ConfigurableMetadataServiceExporter metadataServiceExporter) {\n        this.metadataServiceExporter = metadataServiceExporter;\n    }\n\n    @Override\n    public synchronized void onModuleStarted(ApplicationModel applicationModel) {\n        // start metadata service exporter\n        @Deprecated\n        MetadataServiceDelegation metadataService =\n                applicationModel.getBeanFactory().getOrRegisterBean(MetadataServiceDelegation.class);\n\n        MetadataServiceDelegationV2 metadataServiceV2 =\n                applicationModel.getBeanFactory().getOrRegisterBean(MetadataServiceDelegationV2.class);\n\n        if (metadataServiceExporter == null) {\n            metadataServiceExporter =\n                    new ConfigurableMetadataServiceExporter(applicationModel, metadataService, metadataServiceV2);\n            // fixme, let's disable local metadata service export at this moment\n            if (!REMOTE_METADATA_STORAGE_TYPE.equals(getMetadataType(applicationModel))\n                    && !INTERFACE_REGISTER_MODE.equals(getRegisterMode(applicationModel))) {\n                metadataServiceExporter.export();\n            }\n        }\n    }\n\n    @Override\n    public synchronized void onStopped(ApplicationModel scopeModel) {\n        if (metadataServiceExporter != null && metadataServiceExporter.isExported()) {\n            try {\n                metadataServiceExporter.unexport();\n            } catch (Exception ignored) {\n                // ignored\n            }\n        }\n    }\n\n    @Override\n    public void onFailure(ApplicationModel scopeModel, Throwable cause) {}\n\n    @Override\n    public int getPriority() {\n        return MAX_PRIORITY;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/MetadataServiceURLParamsMetadataCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.metadata;\n\nimport org.apache.dubbo.common.BaseServiceMetadata;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.metadata.MetadataServiceV2;\nimport org.apache.dubbo.metadata.util.MetadataServiceVersionUtils;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstanceCustomizer;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegationV2;\nimport org.apache.dubbo.registry.client.metadata.SpringCloudMetadataServiceURLBuilder;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.utils.StringUtils.isBlank;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_VERSION_NAME;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getMetadataServiceParameter;\n\n/**\n * Used to interact with non-dubbo systems, also see {@link SpringCloudMetadataServiceURLBuilder}\n */\npublic class MetadataServiceURLParamsMetadataCustomizer implements ServiceInstanceCustomizer {\n\n    @Override\n    public void customize(ServiceInstance serviceInstance, ApplicationModel applicationModel) {\n        Map<String, String> metadata = serviceInstance.getMetadata();\n\n        String propertyName = resolveMetadataPropertyName(serviceInstance);\n        String propertyValue = resolveMetadataPropertyValue(applicationModel);\n        if (!isBlank(propertyName) && !isBlank(propertyValue)) {\n            metadata.put(propertyName, propertyValue);\n        }\n        String version = resolveMetadataServiceVersion(applicationModel);\n        metadata.put(METADATA_SERVICE_VERSION_NAME, version);\n    }\n\n    public static String resolveMetadataServiceVersion(ApplicationModel applicationModel) {\n        boolean needExportV2 = MetadataServiceVersionUtils.needExportV2(applicationModel);\n        String version;\n        if (needExportV2) {\n            version = MetadataServiceDelegationV2.VERSION;\n        } else {\n            version = MetadataServiceDelegation.VERSION;\n        }\n        return version;\n    }\n\n    private String resolveMetadataPropertyName(ServiceInstance serviceInstance) {\n        return METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME;\n    }\n\n    private String resolveMetadataPropertyValue(ApplicationModel applicationModel) {\n        ModuleServiceRepository serviceRepository =\n                applicationModel.getInternalModule().getServiceRepository();\n\n        String key;\n\n        if (MetadataServiceVersionUtils.needExportV2(applicationModel)) {\n            key = BaseServiceMetadata.buildServiceKey(\n                    MetadataServiceV2.class.getName(),\n                    applicationModel.getApplicationName(),\n                    MetadataServiceDelegationV2.VERSION);\n        } else {\n            // If MetadataService and MetadataServiceV2 are both exported, use v1 path for capacity.\n            // Client will use version and protocol to judge if it needs to refer v2 path.\n            key = BaseServiceMetadata.buildServiceKey(\n                    MetadataService.class.getName(), applicationModel.getApplicationName(), MetadataService.VERSION);\n        }\n        ProviderModel providerModel = serviceRepository.lookupExportedService(key);\n        String metadataValue = \"\";\n        if (providerModel != null) {\n            List<URL> metadataURLs = providerModel.getServiceUrls();\n            if (CollectionUtils.isNotEmpty(metadataURLs)) {\n                metadataValue = getMetadataServiceParameter(metadataURLs.get(0));\n            }\n        }\n        return metadataValue;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/CompositeReferenceCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils;\n\nimport org.apache.dubbo.common.BaseServiceMetadata;\nimport org.apache.dubbo.common.config.ReferenceCache;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_API_WRONG_USE;\n\n/**\n * A impl of ReferenceCache for Application\n */\npublic class CompositeReferenceCache implements ReferenceCache {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(CompositeReferenceCache.class);\n\n    private final ApplicationModel applicationModel;\n\n    public CompositeReferenceCache(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    @Override\n    public <T> T get(ReferenceConfigBase<T> referenceConfig, boolean check) {\n\n        Class<?> type = referenceConfig.getInterfaceClass();\n        String key = BaseServiceMetadata.buildServiceKey(\n                type.getName(), referenceConfig.getGroup(), referenceConfig.getVersion());\n\n        boolean singleton = referenceConfig.getSingleton() == null || referenceConfig.getSingleton();\n        T proxy = null;\n        if (singleton) {\n            proxy = get(key, (Class<T>) type);\n        } else {\n            logger.warn(\n                    CONFIG_API_WRONG_USE,\n                    \"the api method is being used incorrectly\",\n                    \"\",\n                    \"Using non-singleton ReferenceConfig and ReferenceCache at the same time may cause memory leak. \"\n                            + \"Call ReferenceConfig#get() directly for non-singleton ReferenceConfig instead of using ReferenceCache#get(ReferenceConfig)\");\n        }\n        if (proxy == null) {\n            proxy = referenceConfig.get(check);\n        }\n        return proxy;\n    }\n\n    @Override\n    public <T> T get(String key, Class<T> type) {\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            T proxy = moduleModel.getDeployer().getReferenceCache().get(key, type);\n            if (proxy != null) {\n                return proxy;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public <T> T get(String key) {\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            T proxy = moduleModel.getDeployer().getReferenceCache().get(key);\n            if (proxy != null) {\n                return proxy;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public <T> List<T> getAll(Class<T> type) {\n        List<T> proxies = new ArrayList<>();\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            proxies.addAll(moduleModel.getDeployer().getReferenceCache().getAll(type));\n        }\n        return proxies;\n    }\n\n    @Override\n    public <T> T get(Class<T> type) {\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            T proxy = moduleModel.getDeployer().getReferenceCache().get(type);\n            if (proxy != null) {\n                return proxy;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public void destroy(String key, Class<?> type) {\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            moduleModel.getDeployer().getReferenceCache().destroy(key, type);\n        }\n    }\n\n    @Override\n    public void check(String key, Class<?> type, long timeout) {\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            moduleModel.getDeployer().getReferenceCache().check(key, type, timeout);\n        }\n    }\n\n    @Override\n    public <T> void check(ReferenceConfigBase<T> referenceConfig, long timeout) {\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            moduleModel.getDeployer().getReferenceCache().check(referenceConfig, timeout);\n        }\n    }\n\n    @Override\n    public void destroy(Class<?> type) {\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            moduleModel.getDeployer().getReferenceCache().destroy(type);\n        }\n    }\n\n    @Override\n    public <T> void destroy(ReferenceConfigBase<T> referenceConfig) {\n        referenceConfig.getScopeModel().getDeployer().getReferenceCache().destroy(referenceConfig);\n    }\n\n    @Override\n    public void destroyAll() {\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            moduleModel.getDeployer().getReferenceCache().destroyAll();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.config.PropertiesConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.Serialization;\nimport org.apache.dubbo.common.status.StatusChecker;\nimport org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.AbstractInterfaceConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.monitor.MonitorFactory;\nimport org.apache.dubbo.monitor.MonitorService;\nimport org.apache.dubbo.registry.RegistryService;\nimport org.apache.dubbo.remoting.Codec2;\nimport org.apache.dubbo.remoting.Dispatcher;\nimport org.apache.dubbo.remoting.Transporter;\nimport org.apache.dubbo.remoting.exchange.Exchanger;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.rpc.ExporterListener;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.InvokerListener;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONFIG_NAMESPACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_IP_TO_REGISTRY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_MONITOR_ADDRESS;\nimport static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.FILTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_PARAMETER_FORMAT_ERROR;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_ALL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INSTANCE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INTERFACE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DUBBO_REGISTER_MODE_DEFAULT_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL_TYPE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\nimport static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;\nimport static org.apache.dubbo.config.Constants.ARCHITECTURE;\nimport static org.apache.dubbo.config.Constants.CONTEXTPATH_KEY;\nimport static org.apache.dubbo.config.Constants.ENVIRONMENT;\nimport static org.apache.dubbo.config.Constants.IGNORE_CHECK_KEYS;\nimport static org.apache.dubbo.config.Constants.LAYER_KEY;\nimport static org.apache.dubbo.config.Constants.NAME;\nimport static org.apache.dubbo.config.Constants.ORGANIZATION;\nimport static org.apache.dubbo.config.Constants.OWNER;\nimport static org.apache.dubbo.config.Constants.REGISTER_KEY;\nimport static org.apache.dubbo.config.Constants.STATUS_KEY;\nimport static org.apache.dubbo.monitor.Constants.LOGSTAT_PROTOCOL;\nimport static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;\nimport static org.apache.dubbo.registry.Constants.SUBSCRIBE_KEY;\nimport static org.apache.dubbo.remoting.Constants.CLIENT_KEY;\nimport static org.apache.dubbo.remoting.Constants.CODEC_KEY;\nimport static org.apache.dubbo.remoting.Constants.DISPATCHER_KEY;\nimport static org.apache.dubbo.remoting.Constants.EXCHANGER_KEY;\nimport static org.apache.dubbo.remoting.Constants.PREFER_SERIALIZATION_KEY;\nimport static org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY;\nimport static org.apache.dubbo.remoting.Constants.SERVER_KEY;\nimport static org.apache.dubbo.remoting.Constants.TELNET_KEY;\nimport static org.apache.dubbo.remoting.Constants.TRANSPORTER_KEY;\nimport static org.apache.dubbo.rpc.Constants.FAIL_PREFIX;\nimport static org.apache.dubbo.rpc.Constants.FORCE_PREFIX;\nimport static org.apache.dubbo.rpc.Constants.LOCAL_KEY;\nimport static org.apache.dubbo.rpc.Constants.MOCK_KEY;\nimport static org.apache.dubbo.rpc.Constants.PROXY_KEY;\nimport static org.apache.dubbo.rpc.Constants.RETURN_PREFIX;\nimport static org.apache.dubbo.rpc.Constants.THROW_PREFIX;\nimport static org.apache.dubbo.rpc.Constants.TOKEN_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\n\npublic class ConfigValidationUtils {\n    private static ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConfigValidationUtils.class);\n    /**\n     * The maximum length of a <b>parameter's value</b>\n     */\n    private static final int MAX_LENGTH = 200;\n\n    /**\n     * The maximum length of a <b>path</b>\n     */\n    private static final int MAX_PATH_LENGTH = 200;\n\n    /**\n     * The rule qualification for <b>name</b>\n     */\n    private static final Pattern PATTERN_NAME = Pattern.compile(\"[\\\\-._0-9a-zA-Z]+\");\n\n    /**\n     * The rule qualification for <b>multiply name</b>\n     */\n    private static final Pattern PATTERN_MULTI_NAME = Pattern.compile(\"[,\\\\-._0-9a-zA-Z]+\");\n\n    /**\n     * The rule qualification for <b>method names</b>\n     */\n    private static final Pattern PATTERN_METHOD_NAME = Pattern.compile(\"[a-zA-Z][0-9a-zA-Z]*\");\n\n    /**\n     * The rule qualification for <b>path</b>\n     */\n    private static final Pattern PATTERN_PATH = Pattern.compile(\"[/\\\\-$._0-9a-zA-Z]+\");\n\n    /**\n     * The pattern matches a value who has a symbol\n     */\n    private static final Pattern PATTERN_NAME_HAS_SYMBOL = Pattern.compile(\"[:*,\\\\s/\\\\-._0-9a-zA-Z]+\");\n\n    /**\n     * The pattern matches a property key\n     */\n    private static final Pattern PATTERN_KEY = Pattern.compile(\"[*,\\\\-._0-9a-zA-Z]+\");\n\n    public static final String IPV6_START_MARK = \"[\";\n\n    public static final String IPV6_END_MARK = \"]\";\n\n    public static List<URL> loadRegistries(AbstractInterfaceConfig interfaceConfig, boolean provider) {\n        // check && override if necessary\n        List<URL> registryList = new ArrayList<>();\n        ApplicationConfig application = interfaceConfig.getApplication();\n        List<RegistryConfig> registries = interfaceConfig.getRegistries();\n        if (CollectionUtils.isNotEmpty(registries)) {\n            for (RegistryConfig config : registries) {\n                // try to refresh registry in case it is set directly by user using config.setRegistries()\n                if (!config.isRefreshed()) {\n                    config.refresh();\n                }\n                String address = config.getAddress();\n                if (StringUtils.isEmpty(address)) {\n                    address = ANYHOST_VALUE;\n                }\n                if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {\n                    Map<String, String> map = new HashMap<>();\n                    AbstractConfig.appendParameters(map, application);\n                    AbstractConfig.appendParameters(map, config);\n                    map.put(PATH_KEY, RegistryService.class.getName());\n                    AbstractInterfaceConfig.appendRuntimeParameters(map);\n                    if (!map.containsKey(PROTOCOL_KEY)) {\n                        map.put(PROTOCOL_KEY, DUBBO_PROTOCOL);\n                    }\n                    String registryCluster = config.getId();\n                    if (isEmpty(registryCluster)) {\n                        registryCluster = DEFAULT_KEY;\n                    }\n                    if (map.containsKey(CONFIG_NAMESPACE_KEY)) {\n                        registryCluster += \":\" + map.get(CONFIG_NAMESPACE_KEY);\n                    }\n                    map.put(REGISTRY_CLUSTER_KEY, registryCluster);\n                    List<URL> urls = UrlUtils.parseURLs(address, map);\n\n                    for (URL url : urls) {\n                        url = URLBuilder.from(url)\n                                .addParameter(REGISTRY_KEY, url.getProtocol())\n                                .setProtocol(extractRegistryType(url))\n                                .setScopeModel(interfaceConfig.getScopeModel())\n                                .build();\n                        // provider delay register state will be checked in RegistryProtocol#export\n                        if (provider && url.getParameter(REGISTER_KEY, true)) {\n                            registryList.add(url);\n                        }\n                        if (!provider && url.getParameter(SUBSCRIBE_KEY, true)) {\n                            registryList.add(url);\n                        }\n                    }\n                }\n            }\n        }\n        return genCompatibleRegistries(interfaceConfig.getScopeModel(), registryList, provider);\n    }\n\n    private static List<URL> genCompatibleRegistries(ScopeModel scopeModel, List<URL> registryList, boolean provider) {\n        List<URL> result = new ArrayList<>(registryList.size());\n        registryList.forEach(registryURL -> {\n            if (provider) {\n                // for registries enabled service discovery, automatically register interface compatible addresses.\n                String registerMode;\n                if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) {\n                    registerMode = registryURL.getParameter(\n                            REGISTER_MODE_KEY,\n                            ConfigurationUtils.getCachedDynamicProperty(\n                                    scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_INSTANCE));\n                    if (!isValidRegisterMode(registerMode)) {\n                        registerMode = DEFAULT_REGISTER_MODE_INSTANCE;\n                    }\n                    result.add(registryURL);\n                    if (DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)\n                            && registryNotExists(registryURL, registryList, REGISTRY_PROTOCOL)) {\n                        URL interfaceCompatibleRegistryURL = URLBuilder.from(registryURL)\n                                .setProtocol(REGISTRY_PROTOCOL)\n                                .removeParameter(REGISTRY_TYPE_KEY)\n                                .build();\n                        result.add(interfaceCompatibleRegistryURL);\n                    }\n                } else {\n                    registerMode = registryURL.getParameter(\n                            REGISTER_MODE_KEY,\n                            ConfigurationUtils.getCachedDynamicProperty(\n                                    scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_ALL));\n                    if (!isValidRegisterMode(registerMode)) {\n                        registerMode = DEFAULT_REGISTER_MODE_INTERFACE;\n                    }\n                    if ((DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(registerMode)\n                                    || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode))\n                            && registryNotExists(registryURL, registryList, SERVICE_REGISTRY_PROTOCOL)) {\n                        URL serviceDiscoveryRegistryURL = URLBuilder.from(registryURL)\n                                .setProtocol(SERVICE_REGISTRY_PROTOCOL)\n                                .removeParameter(REGISTRY_TYPE_KEY)\n                                .build();\n                        result.add(serviceDiscoveryRegistryURL);\n                    }\n\n                    if (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(registerMode)\n                            || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) {\n                        result.add(registryURL);\n                    }\n                }\n\n                FrameworkStatusReportService reportService = ScopeModelUtil.getApplicationModel(scopeModel)\n                        .getBeanFactory()\n                        .getBean(FrameworkStatusReportService.class);\n                reportService.reportRegistrationStatus(reportService.createRegistrationReport(registerMode));\n            } else {\n                result.add(registryURL);\n            }\n        });\n\n        return result;\n    }\n\n    private static boolean isValidRegisterMode(String mode) {\n        return isNotEmpty(mode)\n                && (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(mode)\n                        || DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(mode)\n                        || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(mode));\n    }\n\n    private static boolean registryNotExists(URL registryURL, List<URL> registryList, String registryType) {\n        return registryList.stream()\n                .noneMatch(url -> registryType.equals(url.getProtocol())\n                        && registryURL.getBackupAddress().equals(url.getBackupAddress()));\n    }\n\n    public static URL loadMonitor(AbstractInterfaceConfig interfaceConfig, URL registryURL) {\n        Map<String, String> map = new HashMap<>();\n        map.put(INTERFACE_KEY, MonitorService.class.getName());\n        AbstractInterfaceConfig.appendRuntimeParameters(map);\n        // set ip\n        String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);\n        if (StringUtils.isEmpty(hostToRegistry)) {\n            hostToRegistry = NetUtils.getLocalHost();\n        } else if (NetUtils.isInvalidLocalHost(hostToRegistry)) {\n            throw new IllegalArgumentException(\"Specified invalid registry ip from property:\" + DUBBO_IP_TO_REGISTRY\n                    + \", value:\" + hostToRegistry);\n        }\n        map.put(REGISTER_IP_KEY, hostToRegistry);\n\n        MonitorConfig monitor = interfaceConfig.getMonitor();\n        ApplicationConfig application = interfaceConfig.getApplication();\n        AbstractConfig.appendParameters(map, monitor);\n        AbstractConfig.appendParameters(map, application);\n        String address = null;\n        String sysAddress = SystemPropertyConfigUtils.getSystemProperty(DUBBO_MONITOR_ADDRESS);\n        if (sysAddress != null && sysAddress.length() > 0) {\n            address = sysAddress;\n        } else if (monitor != null) {\n            address = monitor.getAddress();\n        }\n        String protocol = monitor == null ? null : monitor.getProtocol();\n        if (monitor != null\n                && (REGISTRY_PROTOCOL.equals(protocol) || SERVICE_REGISTRY_PROTOCOL.equals(protocol))\n                && registryURL != null) {\n            return URLBuilder.from(registryURL)\n                    .setProtocol(DUBBO_PROTOCOL)\n                    .addParameter(PROTOCOL_KEY, protocol)\n                    .putAttribute(REFER_KEY, map)\n                    .build();\n        } else if (ConfigUtils.isNotEmpty(address) || ConfigUtils.isNotEmpty(protocol)) {\n            if (!map.containsKey(PROTOCOL_KEY)) {\n                if (interfaceConfig\n                        .getScopeModel()\n                        .getExtensionLoader(MonitorFactory.class)\n                        .hasExtension(LOGSTAT_PROTOCOL)) {\n                    map.put(PROTOCOL_KEY, LOGSTAT_PROTOCOL);\n                } else if (ConfigUtils.isNotEmpty(protocol)) {\n                    map.put(PROTOCOL_KEY, protocol);\n                } else {\n                    map.put(PROTOCOL_KEY, DUBBO_PROTOCOL);\n                }\n            }\n            if (ConfigUtils.isEmpty(address)) {\n                address = LOCALHOST_VALUE;\n            }\n            return UrlUtils.parseURL(address, map);\n        }\n        return null;\n    }\n\n    public static void validateAbstractInterfaceConfig(AbstractInterfaceConfig config) {\n        checkName(LOCAL_KEY, config.getLocal());\n        checkName(\"stub\", config.getStub());\n        checkMultiName(\"owner\", config.getOwner());\n\n        checkExtension(config.getScopeModel(), ProxyFactory.class, PROXY_KEY, config.getProxy());\n        checkExtension(config.getScopeModel(), Cluster.class, CLUSTER_KEY, config.getCluster());\n        checkMultiExtension(\n                config.getScopeModel(),\n                Arrays.asList(Filter.class, ClusterFilter.class),\n                FILTER_KEY,\n                config.getFilter());\n        checkNameHasSymbol(LAYER_KEY, config.getLayer());\n\n        List<MethodConfig> methods = config.getMethods();\n        if (CollectionUtils.isNotEmpty(methods)) {\n            methods.forEach(ConfigValidationUtils::validateMethodConfig);\n        }\n    }\n\n    public static void validateServiceConfig(ServiceConfig config) {\n        checkKey(VERSION_KEY, config.getVersion());\n        checkKey(GROUP_KEY, config.getGroup());\n        checkName(TOKEN_KEY, config.getToken());\n        checkPathName(PATH_KEY, config.getPath());\n\n        checkMultiExtension(config.getScopeModel(), ExporterListener.class, \"listener\", config.getListener());\n\n        validateAbstractInterfaceConfig(config);\n\n        List<RegistryConfig> registries = config.getRegistries();\n        if (registries != null) {\n            for (RegistryConfig registry : registries) {\n                validateRegistryConfig(registry);\n            }\n        }\n\n        List<ProtocolConfig> protocols = config.getProtocols();\n        if (protocols != null) {\n            for (ProtocolConfig protocol : protocols) {\n                validateProtocolConfig(protocol);\n            }\n        }\n\n        ProviderConfig providerConfig = config.getProvider();\n        if (providerConfig != null) {\n            validateProviderConfig(providerConfig);\n        }\n    }\n\n    public static void validateReferenceConfig(ReferenceConfig config) {\n        checkMultiExtension(config.getScopeModel(), InvokerListener.class, \"listener\", config.getListener());\n        checkKey(VERSION_KEY, config.getVersion());\n        checkKey(GROUP_KEY, config.getGroup());\n        checkName(CLIENT_KEY, config.getClient());\n\n        validateAbstractInterfaceConfig(config);\n\n        List<RegistryConfig> registries = config.getRegistries();\n        if (registries != null) {\n            for (RegistryConfig registry : registries) {\n                validateRegistryConfig(registry);\n            }\n        }\n\n        ConsumerConfig consumerConfig = config.getConsumer();\n        if (consumerConfig != null) {\n            validateConsumerConfig(consumerConfig);\n        }\n    }\n\n    public static void validateConfigCenterConfig(ConfigCenterConfig config) {\n        if (config != null) {\n            checkParameterName(config.getParameters());\n        }\n    }\n\n    public static void validateApplicationConfig(ApplicationConfig config) {\n        if (config == null) {\n            return;\n        }\n\n        if (!config.isValid()) {\n            throw new IllegalStateException(\"No application config found or it's not a valid config! \"\n                    + \"Please add <dubbo:application name=\\\"...\\\" /> to your spring config.\");\n        }\n\n        // backward compatibility\n        ScopeModel scopeModel = ScopeModelUtil.getOrDefaultApplicationModel(config.getScopeModel());\n        PropertiesConfiguration configuration = scopeModel.modelEnvironment().getPropertiesConfiguration();\n        String wait = configuration.getProperty(SHUTDOWN_WAIT_KEY);\n        if (wait != null && wait.trim().length() > 0) {\n            System.setProperty(SHUTDOWN_WAIT_KEY, wait.trim());\n        } else {\n            wait = configuration.getProperty(SHUTDOWN_WAIT_SECONDS_KEY);\n            if (wait != null && wait.trim().length() > 0) {\n                System.setProperty(SHUTDOWN_WAIT_SECONDS_KEY, wait.trim());\n            }\n        }\n\n        checkName(NAME, config.getName());\n        checkMultiName(OWNER, config.getOwner());\n        checkName(ORGANIZATION, config.getOrganization());\n        checkName(ARCHITECTURE, config.getArchitecture());\n        checkName(ENVIRONMENT, config.getEnvironment());\n        checkParameterName(config.getParameters());\n        checkQosDependency(config);\n    }\n\n    private static void checkQosDependency(ApplicationConfig config) {\n        if (!Boolean.FALSE.equals(config.getQosEnable())) {\n            try {\n                ClassUtils.forName(\"org.apache.dubbo.qos.protocol.QosProtocolWrapper\");\n            } catch (ClassNotFoundException e) {\n                logger.info(\n                        \"QosProtocolWrapper not found, qos will not be enabled, please check if 'dubbo-qos' dependency was imported correctly.\");\n            }\n        }\n    }\n\n    public static void validateModuleConfig(ModuleConfig config) {\n        if (config != null) {\n            checkName(NAME, config.getName());\n            checkName(OWNER, config.getOwner());\n            checkName(ORGANIZATION, config.getOrganization());\n        }\n    }\n\n    public static boolean isValidMetadataConfig(MetadataReportConfig metadataReportConfig) {\n        if (metadataReportConfig == null) {\n            return false;\n        }\n\n        if (Boolean.FALSE.equals(metadataReportConfig.getReportMetadata())\n                && Boolean.FALSE.equals(metadataReportConfig.getReportDefinition())) {\n            return false;\n        }\n\n        return !isEmpty(metadataReportConfig.getAddress());\n    }\n\n    public static void validateMetadataConfig(MetadataReportConfig metadataReportConfig) {\n        if (!isValidMetadataConfig(metadataReportConfig)) {\n            return;\n        }\n\n        String address = metadataReportConfig.getAddress();\n        String protocol = metadataReportConfig.getProtocol();\n\n        if ((isEmpty(address) || !address.contains(\"://\")) && isEmpty(protocol)) {\n            throw new IllegalArgumentException(\n                    \"Please specify valid protocol or address for metadata report \" + address);\n        }\n    }\n\n    public static void validateMetricsConfig(MetricsConfig metricsConfig) {\n        if (metricsConfig == null) {\n            return;\n        }\n    }\n\n    public static void validateTracingConfig(TracingConfig tracingConfig) {\n        if (tracingConfig == null) {\n            return;\n        }\n    }\n\n    public static void validateSslConfig(SslConfig sslConfig) {\n        if (sslConfig == null) {\n            return;\n        }\n    }\n\n    public static void validateMonitorConfig(MonitorConfig config) {\n        if (config != null) {\n            if (!config.isValid()) {\n                logger.info(\"There's no valid monitor config found, if you want to open monitor statistics for Dubbo, \"\n                        + \"please make sure your monitor is configured properly.\");\n            }\n\n            checkParameterName(config.getParameters());\n        }\n    }\n\n    public static void validateProtocolConfig(ProtocolConfig config) {\n        if (config != null) {\n            String name = config.getName();\n            checkName(\"name\", name);\n            checkHost(HOST_KEY, config.getHost());\n            checkPathName(\"contextpath\", config.getContextpath());\n\n            if (DUBBO_PROTOCOL.equals(name)) {\n                checkMultiExtension(config.getScopeModel(), Codec2.class, CODEC_KEY, config.getCodec());\n                checkMultiExtension(\n                        config.getScopeModel(), Serialization.class, SERIALIZATION_KEY, config.getSerialization());\n                checkMultiExtension(\n                        config.getScopeModel(),\n                        Serialization.class,\n                        PREFER_SERIALIZATION_KEY,\n                        config.getPreferSerialization());\n                checkMultiExtension(config.getScopeModel(), Transporter.class, SERVER_KEY, config.getServer());\n                checkMultiExtension(config.getScopeModel(), Transporter.class, CLIENT_KEY, config.getClient());\n            }\n\n            checkMultiExtension(config.getScopeModel(), TelnetHandler.class, TELNET_KEY, config.getTelnet());\n            checkMultiExtension(config.getScopeModel(), StatusChecker.class, \"status\", config.getStatus());\n            checkExtension(config.getScopeModel(), Transporter.class, TRANSPORTER_KEY, config.getTransporter());\n            checkExtension(config.getScopeModel(), Exchanger.class, EXCHANGER_KEY, config.getExchanger());\n            checkExtension(config.getScopeModel(), Dispatcher.class, DISPATCHER_KEY, config.getDispatcher());\n            checkExtension(config.getScopeModel(), Dispatcher.class, \"dispather\", config.getDispatcher());\n            checkExtension(config.getScopeModel(), ThreadPool.class, THREADPOOL_KEY, config.getThreadpool());\n        }\n    }\n\n    public static void validateProviderConfig(ProviderConfig config) {\n        checkPathName(CONTEXTPATH_KEY, config.getContextpath());\n        checkExtension(config.getScopeModel(), ThreadPool.class, THREADPOOL_KEY, config.getThreadpool());\n        checkMultiExtension(config.getScopeModel(), TelnetHandler.class, TELNET_KEY, config.getTelnet());\n        checkMultiExtension(config.getScopeModel(), StatusChecker.class, STATUS_KEY, config.getStatus());\n        checkExtension(config.getScopeModel(), Transporter.class, TRANSPORTER_KEY, config.getTransporter());\n        checkExtension(config.getScopeModel(), Exchanger.class, EXCHANGER_KEY, config.getExchanger());\n        checkMultiExtension(config.getScopeModel(), Serialization.class, SERIALIZATION_KEY, config.getSerialization());\n        checkMultiExtension(\n                config.getScopeModel(), Serialization.class, PREFER_SERIALIZATION_KEY, config.getPreferSerialization());\n    }\n\n    public static void validateConsumerConfig(ConsumerConfig config) {\n        if (config == null) {\n            return;\n        }\n    }\n\n    public static void validateRegistryConfig(RegistryConfig config) {\n        checkName(PROTOCOL_KEY, config.getProtocol());\n        checkName(USERNAME_KEY, config.getUsername());\n        checkLength(PASSWORD_KEY, config.getPassword());\n        checkPathLength(FILE_KEY, config.getFile());\n        checkName(TRANSPORTER_KEY, config.getTransporter());\n        checkName(SERVER_KEY, config.getServer());\n        checkName(CLIENT_KEY, config.getClient());\n        checkParameterName(config.getParameters());\n    }\n\n    public static void validateMethodConfig(MethodConfig config) {\n        checkExtension(config.getScopeModel(), LoadBalance.class, LOADBALANCE_KEY, config.getLoadbalance());\n        checkParameterName(config.getParameters());\n        checkMethodName(\"name\", config.getName());\n\n        String mock = config.getMock();\n        if (isNotEmpty(mock)) {\n            if (mock.startsWith(RETURN_PREFIX) || mock.startsWith(THROW_PREFIX + \" \")) {\n                checkLength(MOCK_KEY, mock);\n            } else if (mock.startsWith(FAIL_PREFIX) || mock.startsWith(FORCE_PREFIX)) {\n                checkNameHasSymbol(MOCK_KEY, mock);\n            } else {\n                checkName(MOCK_KEY, mock);\n            }\n        }\n    }\n\n    private static String extractRegistryType(URL url) {\n        return UrlUtils.hasServiceDiscoveryRegistryTypeKey(url)\n                ? SERVICE_REGISTRY_PROTOCOL\n                : getRegistryProtocolType(url);\n    }\n\n    private static String getRegistryProtocolType(URL url) {\n        String registryProtocol = url.getParameter(REGISTRY_PROTOCOL_TYPE);\n        return isNotEmpty(registryProtocol) ? registryProtocol : REGISTRY_PROTOCOL;\n    }\n\n    public static void checkExtension(ScopeModel scopeModel, Class<?> type, String property, String value) {\n        checkName(property, value);\n        if (isNotEmpty(value) && !scopeModel.getExtensionLoader(type).hasExtension(value)) {\n            throw new IllegalStateException(\"No such extension \" + value + \" for \" + property + \"/\" + type.getName());\n        }\n    }\n\n    /**\n     * Check whether there is a <code>Extension</code> who's name (property) is <code>value</code> (special treatment is\n     * required)\n     *\n     * @param type     The Extension type\n     * @param property The extension key\n     * @param value    The Extension name\n     */\n    public static void checkMultiExtension(ScopeModel scopeModel, Class<?> type, String property, String value) {\n        checkMultiExtension(scopeModel, Collections.singletonList(type), property, value);\n    }\n\n    public static void checkMultiExtension(ScopeModel scopeModel, List<Class<?>> types, String property, String value) {\n        checkMultiName(property, value);\n        if (isNotEmpty(value)) {\n            String[] values = value.split(\"\\\\s*[,]+\\\\s*\");\n            for (String v : values) {\n                v = StringUtils.trim(v);\n                if (v.startsWith(REMOVE_VALUE_PREFIX)) {\n                    continue;\n                }\n                if (DEFAULT_KEY.equals(v)) {\n                    continue;\n                }\n                boolean match = false;\n                for (Class<?> type : types) {\n                    if (scopeModel.getExtensionLoader(type).hasExtension(v)) {\n                        match = true;\n                    }\n                }\n                if (!match) {\n                    throw new IllegalStateException(\"No such extension \" + v + \" for \" + property + \"/\"\n                            + types.stream().map(Class::getName).collect(Collectors.joining(\",\")));\n                }\n            }\n        }\n    }\n\n    public static void checkLength(String property, String value) {\n        checkProperty(property, value, MAX_LENGTH, null);\n    }\n\n    public static void checkPathLength(String property, String value) {\n        checkProperty(property, value, MAX_PATH_LENGTH, null);\n    }\n\n    public static void checkName(String property, String value) {\n        checkProperty(property, value, MAX_LENGTH, PATTERN_NAME);\n    }\n\n    public static void checkHost(String property, String value) {\n        if (StringUtils.isEmpty(value)) {\n            return;\n        }\n        if (value.startsWith(IPV6_START_MARK) && value.endsWith(IPV6_END_MARK)) {\n            // if the value start with \"[\" and end with \"]\", check whether it is IPV6\n            try {\n                InetAddress.getByName(value);\n                return;\n            } catch (UnknownHostException e) {\n                // not a IPv6 string, do nothing, go on to checkName\n            }\n        }\n        checkName(property, value);\n    }\n\n    public static void checkNameHasSymbol(String property, String value) {\n        checkProperty(property, value, MAX_LENGTH, PATTERN_NAME_HAS_SYMBOL);\n    }\n\n    public static void checkKey(String property, String value) {\n        checkProperty(property, value, MAX_LENGTH, PATTERN_KEY);\n    }\n\n    public static void checkMultiName(String property, String value) {\n        checkProperty(property, value, MAX_LENGTH, PATTERN_MULTI_NAME);\n    }\n\n    public static void checkPathName(String property, String value) {\n        checkProperty(property, value, MAX_PATH_LENGTH, PATTERN_PATH);\n    }\n\n    public static void checkMethodName(String property, String value) {\n        checkProperty(property, value, MAX_LENGTH, PATTERN_METHOD_NAME);\n    }\n\n    public static void checkParameterName(Map<String, String> parameters) {\n        if (CollectionUtils.isEmptyMap(parameters)) {\n            return;\n        }\n        List<String> ignoreCheckKeys = new ArrayList<>();\n        ignoreCheckKeys.add(BACKUP_KEY);\n        ignoreCheckKeys.add(PASSWORD_KEY);\n        String ignoreCheckKeysStr = parameters.get(IGNORE_CHECK_KEYS);\n        if (!StringUtils.isBlank(ignoreCheckKeysStr)) {\n            ignoreCheckKeys.addAll(Arrays.asList(ignoreCheckKeysStr.split(\",\")));\n        }\n        for (Map.Entry<String, String> entry : parameters.entrySet()) {\n            if (!ignoreCheckKeys.contains(entry.getKey())) {\n                checkNameHasSymbol(entry.getKey(), entry.getValue());\n            }\n        }\n    }\n\n    public static void checkProperty(String property, String value, int maxlength, Pattern pattern) {\n        if (StringUtils.isEmpty(value)) {\n            return;\n        }\n        if (value.length() > maxlength) {\n            logger.error(\n                    CONFIG_PARAMETER_FORMAT_ERROR,\n                    \"the value content is too long\",\n                    \"\",\n                    \"Parameter value format error. Invalid \" + property + \"=\\\"\" + value + \"\\\" is longer than \"\n                            + maxlength);\n        }\n        if (pattern != null) {\n            Matcher matcher = pattern.matcher(value);\n            if (!matcher.matches()) {\n                logger.error(\n                        CONFIG_PARAMETER_FORMAT_ERROR,\n                        \"the value content is illegal character\",\n                        \"\",\n                        \"Parameter value format error. Invalid \" + property\n                                + \"=\\\"\" + value + \"\\\" contains illegal \"\n                                + \"character, only digit, letter, '-', '_' or '.' is legal.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils;\n\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.context.ConfigValidator;\n\npublic class DefaultConfigValidator implements ConfigValidator {\n\n    @Override\n    public void validate(AbstractConfig config) {\n        if (config instanceof ProtocolConfig) {\n            ConfigValidationUtils.validateProtocolConfig((ProtocolConfig) config);\n        } else if (config instanceof RegistryConfig) {\n            ConfigValidationUtils.validateRegistryConfig((RegistryConfig) config);\n        } else if (config instanceof MetadataReportConfig) {\n            ConfigValidationUtils.validateMetadataConfig((MetadataReportConfig) config);\n        } else if (config instanceof ProviderConfig) {\n            ConfigValidationUtils.validateProviderConfig((ProviderConfig) config);\n        } else if (config instanceof ConsumerConfig) {\n            ConfigValidationUtils.validateConsumerConfig((ConsumerConfig) config);\n        } else if (config instanceof ApplicationConfig) {\n            ConfigValidationUtils.validateApplicationConfig((ApplicationConfig) config);\n        } else if (config instanceof MonitorConfig) {\n            ConfigValidationUtils.validateMonitorConfig((MonitorConfig) config);\n        } else if (config instanceof ModuleConfig) {\n            ConfigValidationUtils.validateModuleConfig((ModuleConfig) config);\n        } else if (config instanceof MetricsConfig) {\n            ConfigValidationUtils.validateMetricsConfig((MetricsConfig) config);\n        } else if (config instanceof TracingConfig) {\n            ConfigValidationUtils.validateTracingConfig((TracingConfig) config);\n        } else if (config instanceof SslConfig) {\n            ConfigValidationUtils.validateSslConfig((SslConfig) config);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/SimpleReferenceCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils;\n\nimport org.apache.dubbo.common.BaseServiceMetadata;\nimport org.apache.dubbo.common.config.ReferenceCache;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.rpc.service.Destroyable;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_API_WRONG_USE;\n\n/**\n * A simple util class for cache {@link ReferenceConfigBase}.\n * <p>\n * {@link ReferenceConfigBase} is a heavy Object, it's necessary to cache these object\n * for the framework which create {@link ReferenceConfigBase} frequently.\n * <p>\n * You can implement and use your own {@link ReferenceConfigBase} cache if you need use complicate strategy.\n */\npublic class SimpleReferenceCache implements ReferenceCache {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(SimpleReferenceCache.class);\n    public static final String DEFAULT_NAME = \"_DEFAULT_\";\n    /**\n     * Create the key with the <b>Group</b>, <b>Interface</b> and <b>version</b> attribute of {@link ReferenceConfigBase}.\n     * <p>\n     * key example: <code>group1/org.apache.dubbo.foo.FooService:1.0.0</code>.\n     */\n    public static final KeyGenerator DEFAULT_KEY_GENERATOR = referenceConfig -> {\n        String iName = referenceConfig.getInterface();\n        if (StringUtils.isBlank(iName)) {\n            Class<?> clazz = referenceConfig.getInterfaceClass();\n            iName = clazz.getName();\n        }\n        if (StringUtils.isBlank(iName)) {\n            throw new IllegalArgumentException(\"No interface info in ReferenceConfig\" + referenceConfig);\n        }\n\n        return BaseServiceMetadata.buildServiceKey(iName, referenceConfig.getGroup(), referenceConfig.getVersion());\n    };\n\n    private static final AtomicInteger nameIndex = new AtomicInteger();\n\n    static final ConcurrentMap<String, SimpleReferenceCache> CACHE_HOLDER = new ConcurrentHashMap<>();\n    private final String name;\n    private final KeyGenerator generator;\n\n    private final ConcurrentMap<String, List<ReferenceConfigBase<?>>> referenceKeyMap = new ConcurrentHashMap<>();\n    private final ConcurrentMap<Class<?>, List<ReferenceConfigBase<?>>> referenceTypeMap = new ConcurrentHashMap<>();\n    private final Map<ReferenceConfigBase<?>, Object> references = new ConcurrentHashMap<>();\n\n    protected SimpleReferenceCache(String name, KeyGenerator generator) {\n        this.name = name;\n        this.generator = generator;\n    }\n\n    /**\n     * Get the cache use default name and {@link #DEFAULT_KEY_GENERATOR} to generate cache key.\n     * Create cache if not existed yet.\n     */\n    public static SimpleReferenceCache getCache() {\n        return getCache(DEFAULT_NAME);\n    }\n\n    public static SimpleReferenceCache newCache() {\n        return getCache(DEFAULT_NAME + \"#\" + nameIndex.incrementAndGet());\n    }\n\n    /**\n     * Get the cache use specified name and {@link KeyGenerator}.\n     * Create cache if not existed yet.\n     */\n    public static SimpleReferenceCache getCache(String name) {\n        return getCache(name, DEFAULT_KEY_GENERATOR);\n    }\n\n    /**\n     * Get the cache use specified {@link KeyGenerator}.\n     * Create cache if not existed yet.\n     */\n    public static SimpleReferenceCache getCache(String name, KeyGenerator keyGenerator) {\n        return ConcurrentHashMapUtils.computeIfAbsent(\n                CACHE_HOLDER, name, k -> new SimpleReferenceCache(k, keyGenerator));\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> T get(ReferenceConfigBase<T> rc, boolean check) {\n        String key = generator.generateKey(rc);\n        Class<?> type = rc.getInterfaceClass();\n\n        boolean singleton = rc.getSingleton() == null || rc.getSingleton();\n        T proxy = null;\n        // Check existing proxy of the same 'key' and 'type' first.\n        if (singleton) {\n            proxy = get(key, (Class<T>) type);\n        } else {\n            logger.warn(\n                    CONFIG_API_WRONG_USE,\n                    \"\",\n                    \"\",\n                    \"Using non-singleton ReferenceConfig and ReferenceCache at the same time may cause memory leak. \"\n                            + \"Call ReferenceConfig#get() directly for non-singleton ReferenceConfig instead of using ReferenceCache#get(ReferenceConfig)\");\n        }\n\n        if (proxy == null) {\n            List<ReferenceConfigBase<?>> referencesOfType = ConcurrentHashMapUtils.computeIfAbsent(\n                    referenceTypeMap, type, _t -> Collections.synchronizedList(new ArrayList<>()));\n            referencesOfType.add(rc);\n            List<ReferenceConfigBase<?>> referenceConfigList = ConcurrentHashMapUtils.computeIfAbsent(\n                    referenceKeyMap, key, _k -> Collections.synchronizedList(new ArrayList<>()));\n            referenceConfigList.add(rc);\n            proxy = rc.get(check);\n        }\n\n        return proxy;\n    }\n\n    /**\n     * Fetch cache with the specified key. The key is decided by KeyGenerator passed-in. If the default KeyGenerator is\n     * used, then the key is in the format of <code>group/interfaceClass:version</code>\n     *\n     * @param key  cache key\n     * @param type object class\n     * @param <T>  object type\n     * @return object from the cached ReferenceConfigBase\n     * @see KeyGenerator#generateKey(ReferenceConfigBase)\n     */\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> T get(String key, Class<T> type) {\n        List<ReferenceConfigBase<?>> referenceConfigs = referenceKeyMap.get(key);\n        if (CollectionUtils.isNotEmpty(referenceConfigs)) {\n            return (T) referenceConfigs.get(0).get();\n        }\n        return null;\n    }\n\n    /**\n     * Check and return existing ReferenceConfig and its corresponding proxy instance.\n     *\n     * @param key ServiceKey\n     * @param <T> service interface type\n     * @return the existing proxy instance of the same service key\n     */\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> T get(String key) {\n        List<ReferenceConfigBase<?>> referenceConfigBases = referenceKeyMap.get(key);\n        if (CollectionUtils.isNotEmpty(referenceConfigBases)) {\n            return (T) referenceConfigBases.get(0).get();\n        }\n        return null;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> List<T> getAll(Class<T> type) {\n        List<ReferenceConfigBase<?>> referenceConfigBases = referenceTypeMap.get(type);\n        if (CollectionUtils.isEmpty(referenceConfigBases)) {\n            return Collections.EMPTY_LIST;\n        }\n        List proxiesOfType = new ArrayList(referenceConfigBases.size());\n        for (ReferenceConfigBase<?> rc : referenceConfigBases) {\n            proxiesOfType.add(rc.get());\n        }\n        return Collections.unmodifiableList(proxiesOfType);\n    }\n\n    /**\n     * Check and return existing ReferenceConfig and its corresponding proxy instance.\n     *\n     * @param type service interface class\n     * @param <T>  service interface type\n     * @return the existing proxy instance of the same interface definition\n     */\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> T get(Class<T> type) {\n        List<ReferenceConfigBase<?>> referenceConfigBases = referenceTypeMap.get(type);\n        if (CollectionUtils.isNotEmpty(referenceConfigBases)) {\n            return (T) referenceConfigBases.get(0).get();\n        }\n        return null;\n    }\n\n    @Override\n    public void check(String key, Class<?> type, long timeout) {\n        List<ReferenceConfigBase<?>> referencesOfKey = referenceKeyMap.get(key);\n        if (CollectionUtils.isEmpty(referencesOfKey)) {\n            return;\n        }\n        List<ReferenceConfigBase<?>> referencesOfType = referenceTypeMap.get(type);\n        if (CollectionUtils.isEmpty(referencesOfType)) {\n            return;\n        }\n        for (ReferenceConfigBase<?> rc : referencesOfKey) {\n            rc.checkOrDestroy(timeout);\n        }\n    }\n\n    @Override\n    public <T> void check(ReferenceConfigBase<T> referenceConfig, long timeout) {\n        String key = generator.generateKey(referenceConfig);\n        Class<?> type = referenceConfig.getInterfaceClass();\n        check(key, type, timeout);\n    }\n\n    @Override\n    public void destroy(String key, Class<?> type) {\n        List<ReferenceConfigBase<?>> referencesOfKey = referenceKeyMap.remove(key);\n        if (CollectionUtils.isEmpty(referencesOfKey)) {\n            return;\n        }\n        List<ReferenceConfigBase<?>> referencesOfType = referenceTypeMap.get(type);\n        if (CollectionUtils.isEmpty(referencesOfType)) {\n            return;\n        }\n        for (ReferenceConfigBase<?> rc : referencesOfKey) {\n            referencesOfType.remove(rc);\n            destroyReference(rc);\n        }\n    }\n\n    @Override\n    public void destroy(Class<?> type) {\n        List<ReferenceConfigBase<?>> referencesOfType = referenceTypeMap.remove(type);\n        for (ReferenceConfigBase<?> rc : referencesOfType) {\n            String key = generator.generateKey(rc);\n            referenceKeyMap.remove(key);\n            destroyReference(rc);\n        }\n    }\n\n    /**\n     * clear and destroy one {@link ReferenceConfigBase} in the cache.\n     *\n     * @param referenceConfig use for create key.\n     */\n    @Override\n    public <T> void destroy(ReferenceConfigBase<T> referenceConfig) {\n        String key = generator.generateKey(referenceConfig);\n        Class<?> type = referenceConfig.getInterfaceClass();\n        destroy(key, type);\n    }\n\n    /**\n     * clear and destroy all {@link ReferenceConfigBase} in the cache.\n     */\n    @Override\n    public void destroyAll() {\n        if (CollectionUtils.isEmptyMap(referenceKeyMap)) {\n            return;\n        }\n\n        referenceKeyMap.forEach((_k, referencesOfKey) -> {\n            for (ReferenceConfigBase<?> rc : referencesOfKey) {\n                destroyReference(rc);\n            }\n        });\n\n        referenceKeyMap.clear();\n        referenceTypeMap.clear();\n    }\n\n    private void destroyReference(ReferenceConfigBase<?> rc) {\n        Destroyable proxy = (Destroyable) rc.get();\n        if (proxy != null) {\n            proxy.$destroy();\n        }\n        rc.destroy();\n    }\n\n    public Map<String, List<ReferenceConfigBase<?>>> getReferenceMap() {\n        return referenceKeyMap;\n    }\n\n    public Map<Class<?>, List<ReferenceConfigBase<?>>> getReferenceTypeMap() {\n        return referenceTypeMap;\n    }\n\n    @Override\n    public String toString() {\n        return \"ReferenceCache(name: \" + name + \")\";\n    }\n\n    public interface KeyGenerator {\n        String generateKey(ReferenceConfigBase<?> referenceConfig);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.deploy.ApplicationDeployListener",
    "content": "exporter=org.apache.dubbo.config.metadata.ExporterDeployListener\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.service.MetricsServiceExporter",
    "content": "default=org.apache.dubbo.config.deploy.DefaultMetricsServiceExporter\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer",
    "content": "metadata-url=org.apache.dubbo.config.metadata.MetadataServiceURLParamsMetadataCustomizer\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "dubbo-config-api=org.apache.dubbo.config.ConfigScopeModelInitializer\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/demo/MultiClassLoaderService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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 demo;\n\npublic interface MultiClassLoaderService {\n\n    Object call(MultiClassLoaderServiceRequest innerRequest);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/demo/MultiClassLoaderServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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 demo;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\npublic class MultiClassLoaderServiceImpl implements MultiClassLoaderService {\n    private AtomicReference<MultiClassLoaderServiceRequest> innerRequestReference;\n    private AtomicReference<MultiClassLoaderServiceResult> innerResultReference;\n\n    public MultiClassLoaderServiceImpl(\n            AtomicReference<MultiClassLoaderServiceRequest> innerRequestReference,\n            AtomicReference<MultiClassLoaderServiceResult> innerResultReference) {\n        this.innerRequestReference = innerRequestReference;\n        this.innerResultReference = innerResultReference;\n    }\n\n    @Override\n    public MultiClassLoaderServiceResult call(MultiClassLoaderServiceRequest innerRequest) {\n        innerRequestReference.set(innerRequest);\n        return innerResultReference.get();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/demo/MultiClassLoaderServiceRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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 demo;\n\nimport java.io.Serializable;\n\npublic class MultiClassLoaderServiceRequest implements Serializable {}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/demo/MultiClassLoaderServiceResult.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS 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 demo;\n\nimport java.io.Serializable;\n\npublic class MultiClassLoaderServiceResult implements Serializable {}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.api.Greeting;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigMode;\nimport org.apache.dubbo.config.support.Nested;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.config.utils.ConfigValidationUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass AbstractConfigTest {\n\n    @BeforeEach\n    public void beforeEach() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void afterEach() {\n        SysProps.clear();\n    }\n\n    @Test\n    void testValidateProtocolConfig() {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        protocolConfig.setCodec(\"exchange\");\n        protocolConfig.setName(\"test\");\n        protocolConfig.setHost(\"host\");\n        ConfigValidationUtils.validateProtocolConfig(protocolConfig);\n    }\n\n    @Test\n    void testValidateProtocolConfigSerialization() {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        protocolConfig.setCodec(\"exchange\");\n        protocolConfig.setName(\"dubbo\");\n        protocolConfig.setHost(\"host\");\n        protocolConfig.setSerialization(\"fastjson2\");\n        protocolConfig.setPreferSerialization(\"hessian2\");\n        ConfigValidationUtils.validateProtocolConfig(protocolConfig);\n    }\n\n    @Test\n    void testValidateProtocolConfigViolateSerialization() {\n\n        Assertions.assertThrowsExactly(IllegalStateException.class, () -> {\n            ProtocolConfig protocolConfig = new ProtocolConfig();\n            protocolConfig.setCodec(\"exchange\");\n            protocolConfig.setName(\"dubbo\");\n            protocolConfig.setHost(\"host\");\n            protocolConfig.setSerialization(\"violate\");\n            protocolConfig.setPreferSerialization(\"violate\");\n            ConfigValidationUtils.validateProtocolConfig(protocolConfig);\n        });\n    }\n\n    @Test\n    void testAppendParameters1() {\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(\"num\", \"ONE\");\n        AbstractConfig.appendParameters(parameters, new ParameterConfig(1, \"hello/world\", 30, \"password\"), \"prefix\");\n        Assertions.assertEquals(\"one\", parameters.get(\"prefix.key.1\"));\n        Assertions.assertEquals(\"two\", parameters.get(\"prefix.key.2\"));\n        Assertions.assertEquals(\"ONE,1\", parameters.get(\"prefix.num\"));\n        Assertions.assertEquals(\"hello%2Fworld\", parameters.get(\"prefix.naming\"));\n        Assertions.assertEquals(\"30\", parameters.get(\"prefix.age\"));\n        Assertions.assertFalse(parameters.containsKey(\"prefix.secret\"));\n    }\n\n    @Test\n    void testAppendParameters2() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            Map<String, String> parameters = new HashMap<String, String>();\n            AbstractConfig.appendParameters(parameters, new ParameterConfig());\n        });\n    }\n\n    @Test\n    void testAppendParameters3() {\n        Map<String, String> parameters = new HashMap<String, String>();\n        AbstractConfig.appendParameters(parameters, null);\n        assertTrue(parameters.isEmpty());\n    }\n\n    @Test\n    void testAppendParameters4() {\n        Map<String, String> parameters = new HashMap<String, String>();\n        AbstractConfig.appendParameters(parameters, new ParameterConfig(1, \"hello/world\", 30, \"password\"));\n        Assertions.assertEquals(\"one\", parameters.get(\"key.1\"));\n        Assertions.assertEquals(\"two\", parameters.get(\"key.2\"));\n        Assertions.assertEquals(\"1\", parameters.get(\"num\"));\n        Assertions.assertEquals(\"hello%2Fworld\", parameters.get(\"naming\"));\n        Assertions.assertEquals(\"30\", parameters.get(\"age\"));\n    }\n\n    @Test\n    void testAppendAttributes1() {\n        ParameterConfig config = new ParameterConfig(1, \"hello/world\", 30, \"password\", \"BEIJING\");\n        Map<String, String> parameters = new HashMap<>();\n        AbstractConfig.appendParameters(parameters, config);\n\n        Map<String, String> attributes = new HashMap<>();\n        AbstractConfig.appendAttributes(attributes, config);\n\n        Assertions.assertEquals(null, parameters.get(\"secret\"));\n        Assertions.assertEquals(null, parameters.get(\"parameters\"));\n        // secret is excluded for url parameters, but keep for attributes\n        Assertions.assertEquals(config.getSecret(), attributes.get(\"secret\"));\n        Assertions.assertEquals(config.getName(), attributes.get(\"name\"));\n        Assertions.assertEquals(String.valueOf(config.getNumber()), attributes.get(\"number\"));\n        Assertions.assertEquals(String.valueOf(config.getAge()), attributes.get(\"age\"));\n        Assertions.assertEquals(StringUtils.encodeParameters(config.getParameters()), attributes.get(\"parameters\"));\n        Assertions.assertTrue(parameters.containsKey(\"detail.address\")); // detailAddress -> detail.address\n        Assertions.assertTrue(attributes.containsKey(\"detail-address\")); // detailAddress -> detail-address\n    }\n\n    @Test\n    void checkExtension() {\n        Assertions.assertThrows(\n                IllegalStateException.class,\n                () -> ConfigValidationUtils.checkExtension(\n                        ApplicationModel.defaultModel(), Greeting.class, \"hello\", \"world\"));\n    }\n\n    @Test\n    void checkMultiExtension1() {\n        Assertions.assertThrows(\n                IllegalStateException.class,\n                () -> ConfigValidationUtils.checkMultiExtension(\n                        ApplicationModel.defaultModel(), Greeting.class, \"hello\", \"default,world\"));\n    }\n\n    @Test\n    void checkMultiExtension2() {\n        try {\n            ConfigValidationUtils.checkMultiExtension(\n                    ApplicationModel.defaultModel(), Greeting.class, \"hello\", \"default,-world\");\n        } catch (Throwable t) {\n            Assertions.fail(t);\n        }\n    }\n\n    @Test\n    void checkMultiExtension3() {\n        Assertions.assertThrows(\n                IllegalStateException.class,\n                () -> ConfigValidationUtils.checkMultiExtension(\n                        ApplicationModel.defaultModel(), Greeting.class, \"hello\", \"default ,     world\"));\n    }\n\n    @Test\n    void checkMultiExtension4() {\n        try {\n            ConfigValidationUtils.checkMultiExtension(\n                    ApplicationModel.defaultModel(), Greeting.class, \"hello\", \"default  ,  -world   \");\n        } catch (Throwable t) {\n            Assertions.fail(t);\n        }\n    }\n\n    @Test\n    void checkLength() {\n        Assertions.assertDoesNotThrow(() -> {\n            StringBuilder builder = new StringBuilder();\n            for (int i = 0; i <= 200; i++) {\n                builder.append('a');\n            }\n            ConfigValidationUtils.checkLength(\"hello\", builder.toString());\n        });\n    }\n\n    @Test\n    void checkPathLength() {\n        Assertions.assertDoesNotThrow(() -> {\n            StringBuilder builder = new StringBuilder();\n            for (int i = 0; i <= 200; i++) {\n                builder.append('a');\n            }\n            ConfigValidationUtils.checkPathLength(\"hello\", builder.toString());\n        });\n    }\n\n    @Test\n    void checkName() {\n        Assertions.assertDoesNotThrow(() -> ConfigValidationUtils.checkName(\"hello\", \"world%\"));\n    }\n\n    @Test\n    void checkNameHasSymbol() {\n        try {\n            ConfigValidationUtils.checkNameHasSymbol(\"hello\", \":*,/ -0123\\tabcdABCD\");\n            ConfigValidationUtils.checkNameHasSymbol(\"mock\", \"force:return world\");\n        } catch (Exception e) {\n            fail(\"the value should be legal.\");\n        }\n    }\n\n    @Test\n    void checkKey() {\n        try {\n            ConfigValidationUtils.checkKey(\"hello\", \"*,-0123abcdABCD\");\n        } catch (Exception e) {\n            fail(\"the value should be legal.\");\n        }\n    }\n\n    @Test\n    void checkMultiName() {\n        try {\n            ConfigValidationUtils.checkMultiName(\"hello\", \",-._0123abcdABCD\");\n        } catch (Exception e) {\n            fail(\"the value should be legal.\");\n        }\n    }\n\n    @Test\n    void checkPathName() {\n        try {\n            ConfigValidationUtils.checkPathName(\"hello\", \"/-$._0123abcdABCD\");\n        } catch (Exception e) {\n            fail(\"the value should be legal.\");\n        }\n    }\n\n    @Test\n    void checkMethodName() {\n        try {\n            ConfigValidationUtils.checkMethodName(\"hello\", \"abcdABCD0123abcd\");\n        } catch (Exception e) {\n            fail(\"the value should be legal.\");\n        }\n\n        try {\n            ConfigValidationUtils.checkMethodName(\"hello\", \"0a\");\n        } catch (Exception e) {\n            // ignore\n            fail(\"the value should be legal.\");\n        }\n    }\n\n    @Test\n    void checkParameterName() {\n        Map<String, String> parameters = Collections.singletonMap(\"hello\", \":*,/-._0123abcdABCD\");\n        try {\n            ConfigValidationUtils.checkParameterName(parameters);\n        } catch (Exception e) {\n            fail(\"the value should be legal.\");\n        }\n    }\n\n    @Test\n    @Config(\n            interfaceClass = Greeting.class,\n            filter = {\"f1, f2\"},\n            listener = {\"l1, l2\"},\n            parameters = {\"k1\", \"v1\", \"k2\", \"v2\"})\n    public void appendAnnotation() throws Exception {\n        Config config = getClass().getMethod(\"appendAnnotation\").getAnnotation(Config.class);\n        AnnotationConfig annotationConfig = new AnnotationConfig();\n        annotationConfig.appendAnnotation(Config.class, config);\n        Assertions.assertSame(Greeting.class, annotationConfig.getInterface());\n        Assertions.assertEquals(\"f1, f2\", annotationConfig.getFilter());\n        Assertions.assertEquals(\"l1, l2\", annotationConfig.getListener());\n        Assertions.assertEquals(2, annotationConfig.getParameters().size());\n        Assertions.assertEquals(\"v1\", annotationConfig.getParameters().get(\"k1\"));\n        Assertions.assertEquals(\"v2\", annotationConfig.getParameters().get(\"k2\"));\n        assertThat(annotationConfig.toString(), Matchers.containsString(\"filter=\\\"f1, f2\\\" \"));\n        assertThat(annotationConfig.toString(), Matchers.containsString(\"listener=\\\"l1, l2\\\" \"));\n    }\n\n    @Test\n    void testRefreshAll() {\n        try {\n            OverrideConfig overrideConfig = new OverrideConfig();\n            overrideConfig.setAddress(\"override-config://127.0.0.1:2181\");\n            overrideConfig.setProtocol(\"override-config\");\n            overrideConfig.setEscape(\"override-config://\");\n            overrideConfig.setExclude(\"override-config\");\n\n            Map<String, String> external = new HashMap<>();\n            external.put(\"dubbo.override.address\", \"external://127.0.0.1:2181\");\n            // @Parameter(exclude=true)\n            external.put(\"dubbo.override.exclude\", \"external\");\n            // @Parameter(key=\"key1\", useKeyAsProperty=false)\n            external.put(\"dubbo.override.key\", \"external\");\n            // @Parameter(key=\"key2\", useKeyAsProperty=true)\n            external.put(\"dubbo.override.key2\", \"external\");\n            ApplicationModel.defaultModel().modelEnvironment().initialize();\n            ApplicationModel.defaultModel().modelEnvironment().setExternalConfigMap(external);\n\n            SysProps.setProperty(\"dubbo.override.address\", \"system://127.0.0.1:2181\");\n            SysProps.setProperty(\"dubbo.override.protocol\", \"system\");\n            // this will not override, use 'key' instead, @Parameter(key=\"key1\", useKeyAsProperty=false)\n            SysProps.setProperty(\"dubbo.override.key1\", \"system\");\n            SysProps.setProperty(\"dubbo.override.key2\", \"system\");\n\n            // Load configuration from  system properties -> externalConfiguration -> RegistryConfig -> dubbo.properties\n            overrideConfig.refresh();\n\n            Assertions.assertEquals(\"system://127.0.0.1:2181\", overrideConfig.getAddress());\n            Assertions.assertEquals(\"system\", overrideConfig.getProtocol());\n            Assertions.assertEquals(\"override-config://\", overrideConfig.getEscape());\n            Assertions.assertEquals(\"external\", overrideConfig.getKey());\n            Assertions.assertEquals(\"system\", overrideConfig.getKey2());\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n        }\n    }\n\n    @Test\n    void testRefreshSystem() {\n        try {\n            OverrideConfig overrideConfig = new OverrideConfig();\n            overrideConfig.setAddress(\"override-config://127.0.0.1:2181\");\n            overrideConfig.setProtocol(\"override-config\");\n            overrideConfig.setEscape(\"override-config://\");\n            overrideConfig.setExclude(\"override-config\");\n\n            SysProps.setProperty(\"dubbo.override.address\", \"system://127.0.0.1:2181\");\n            SysProps.setProperty(\"dubbo.override.protocol\", \"system\");\n            SysProps.setProperty(\"dubbo.override.key\", \"system\");\n\n            overrideConfig.refresh();\n\n            Assertions.assertEquals(\"system://127.0.0.1:2181\", overrideConfig.getAddress());\n            Assertions.assertEquals(\"system\", overrideConfig.getProtocol());\n            Assertions.assertEquals(\"override-config://\", overrideConfig.getEscape());\n            Assertions.assertEquals(\"system\", overrideConfig.getKey());\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n        }\n    }\n\n    @Test\n    void testRefreshProperties() throws Exception {\n        try {\n            ApplicationModel.defaultModel().modelEnvironment().setExternalConfigMap(new HashMap<>());\n            OverrideConfig overrideConfig = new OverrideConfig();\n            overrideConfig.setAddress(\"override-config://127.0.0.1:2181\");\n            overrideConfig.setProtocol(\"override-config\");\n            overrideConfig.setEscape(\"override-config://\");\n\n            Properties properties = new Properties();\n            properties.load(this.getClass().getResourceAsStream(\"/dubbo.properties\"));\n            ApplicationModel.defaultModel()\n                    .modelEnvironment()\n                    .getPropertiesConfiguration()\n                    .setProperties(properties);\n\n            overrideConfig.refresh();\n\n            Assertions.assertEquals(\"override-config://127.0.0.1:2181\", overrideConfig.getAddress());\n            Assertions.assertEquals(\"override-config\", overrideConfig.getProtocol());\n            Assertions.assertEquals(\"override-config://\", overrideConfig.getEscape());\n            Assertions.assertEquals(\"properties\", overrideConfig.getKey2());\n            // Assertions.assertEquals(\"properties\", overrideConfig.getUseKeyAsProperty());\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n        }\n    }\n\n    @Test\n    void testRefreshExternal() {\n        try {\n            OverrideConfig overrideConfig = new OverrideConfig();\n            overrideConfig.setAddress(\"override-config://127.0.0.1:2181\");\n            overrideConfig.setProtocol(\"override-config\");\n            overrideConfig.setEscape(\"override-config://\");\n            overrideConfig.setExclude(\"override-config\");\n\n            Map<String, String> external = new HashMap<>();\n            external.put(\"dubbo.override.address\", \"external://127.0.0.1:2181\");\n            external.put(\"dubbo.override.protocol\", \"external\");\n            external.put(\"dubbo.override.escape\", \"external://\");\n            // @Parameter(exclude=true)\n            external.put(\"dubbo.override.exclude\", \"external\");\n            // @Parameter(key=\"key1\", useKeyAsProperty=false)\n            external.put(\"dubbo.override.key\", \"external\");\n            // @Parameter(key=\"key2\", useKeyAsProperty=true)\n            external.put(\"dubbo.override.key2\", \"external\");\n            ApplicationModel.defaultModel().modelEnvironment().initialize();\n            ApplicationModel.defaultModel().modelEnvironment().setExternalConfigMap(external);\n\n            overrideConfig.refresh();\n\n            Assertions.assertEquals(\"external://127.0.0.1:2181\", overrideConfig.getAddress());\n            Assertions.assertEquals(\"external\", overrideConfig.getProtocol());\n            Assertions.assertEquals(\"external://\", overrideConfig.getEscape());\n            Assertions.assertEquals(\"external\", overrideConfig.getExclude());\n            Assertions.assertEquals(\"external\", overrideConfig.getKey());\n            Assertions.assertEquals(\"external\", overrideConfig.getKey2());\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n        }\n    }\n\n    @Test\n    void testRefreshById() {\n        try {\n            OverrideConfig overrideConfig = new OverrideConfig();\n            overrideConfig.setId(\"override-id\");\n            overrideConfig.setAddress(\"override-config://127.0.0.1:2181\");\n            overrideConfig.setProtocol(\"override-config\");\n            overrideConfig.setEscape(\"override-config://\");\n            overrideConfig.setExclude(\"override-config\");\n\n            Map<String, String> external = new HashMap<>();\n            external.put(\"dubbo.overrides.override-id.address\", \"external-override-id://127.0.0.1:2181\");\n            external.put(\"dubbo.overrides.override-id.key\", \"external\");\n            external.put(\"dubbo.overrides.override-id.key2\", \"external\");\n            external.put(\"dubbo.override.address\", \"external://127.0.0.1:2181\");\n            external.put(\"dubbo.override.exclude\", \"external\");\n            ApplicationModel.defaultModel().modelEnvironment().initialize();\n            ApplicationModel.defaultModel().modelEnvironment().setExternalConfigMap(external);\n\n            // refresh config\n            overrideConfig.refresh();\n\n            Assertions.assertEquals(\"external-override-id://127.0.0.1:2181\", overrideConfig.getAddress());\n            Assertions.assertEquals(\"override-config\", overrideConfig.getProtocol());\n            Assertions.assertEquals(\"override-config://\", overrideConfig.getEscape());\n            Assertions.assertEquals(\"external\", overrideConfig.getKey());\n            Assertions.assertEquals(\"external\", overrideConfig.getKey2());\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n        }\n    }\n\n    @Test\n    void testRefreshParameters() {\n        try {\n            Map<String, String> parameters = new HashMap<>();\n            parameters.put(\"key1\", \"value1\");\n            parameters.put(\"key2\", \"value2\");\n            OverrideConfig overrideConfig = new OverrideConfig();\n            overrideConfig.setParameters(parameters);\n\n            Map<String, String> external = new HashMap<>();\n            external.put(\"dubbo.override.parameters\", \"[{key3:value3},{key4:value4},{key2:value5}]\");\n            ApplicationModel.defaultModel().modelEnvironment().initialize();\n            ApplicationModel.defaultModel().modelEnvironment().setExternalConfigMap(external);\n\n            // refresh config\n            overrideConfig.refresh();\n\n            Assertions.assertEquals(\"value1\", overrideConfig.getParameters().get(\"key1\"));\n            Assertions.assertEquals(\"value5\", overrideConfig.getParameters().get(\"key2\"));\n            Assertions.assertEquals(\"value3\", overrideConfig.getParameters().get(\"key3\"));\n            Assertions.assertEquals(\"value4\", overrideConfig.getParameters().get(\"key4\"));\n\n            SysProps.setProperty(\"dubbo.override.parameters\", \"[{key3:value6}]\");\n            overrideConfig.refresh();\n\n            Assertions.assertEquals(\"value6\", overrideConfig.getParameters().get(\"key3\"));\n            Assertions.assertEquals(\"value4\", overrideConfig.getParameters().get(\"key4\"));\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n        }\n    }\n\n    @Test\n    void testRefreshParametersWithAttribute() {\n        try {\n            OverrideConfig overrideConfig = new OverrideConfig();\n            SysProps.setProperty(\"dubbo.override.parameters.key00\", \"value00\");\n            overrideConfig.refresh();\n            assertEquals(\"value00\", overrideConfig.getParameters().get(\"key00\"));\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n        }\n    }\n\n    @Test\n    void testRefreshParametersWithOverrideConfigMode() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        try {\n            // test OVERRIDE_ALL configMode\n            {\n                SysProps.setProperty(ConfigKeys.DUBBO_CONFIG_MODE, ConfigMode.OVERRIDE_ALL.name());\n                SysProps.setProperty(\"dubbo.override.address\", \"system://127.0.0.1:2181\");\n                SysProps.setProperty(\"dubbo.override.protocol\", \"system\");\n                SysProps.setProperty(\"dubbo.override.parameters\", \"[{key1:systemValue1},{key2:systemValue2}]\");\n\n                ApplicationModel applicationModel1 = frameworkModel.newApplication();\n                OverrideConfig overrideConfig = new OverrideConfig(applicationModel1);\n                overrideConfig.setAddress(\"override-config://127.0.0.1:2181\");\n                overrideConfig.setProtocol(\"override-config\");\n                Map<String, String> parameters = new HashMap<>();\n                parameters.put(\"key1\", \"value1\");\n                parameters.put(\"key3\", \"value3\");\n                overrideConfig.setParameters(parameters);\n\n                // overrideConfig's config is overridden by system config\n                overrideConfig.refresh();\n                Assertions.assertEquals(overrideConfig.getAddress(), \"system://127.0.0.1:2181\");\n                Assertions.assertEquals(overrideConfig.getProtocol(), \"system\");\n                Assertions.assertEquals(\n                        overrideConfig.getParameters(),\n                        StringUtils.parseParameters(\"[{key1:systemValue1},{key2:systemValue2},{key3:value3}]\"));\n            }\n            // test OVERRIDE_IF_ABSENT configMode\n            {\n                SysProps.setProperty(ConfigKeys.DUBBO_CONFIG_MODE, ConfigMode.OVERRIDE_IF_ABSENT.name());\n                SysProps.setProperty(\"dubbo.override.address\", \"system://127.0.0.1:2181\");\n                SysProps.setProperty(\"dubbo.override.protocol\", \"system\");\n                SysProps.setProperty(\"dubbo.override.parameters\", \"[{key1:systemValue1},{key2:systemValue2}]\");\n                SysProps.setProperty(\"dubbo.override.key\", \"systemKey\");\n\n                ApplicationModel applicationModel = frameworkModel.newApplication();\n                OverrideConfig overrideConfig = new OverrideConfig(applicationModel);\n                overrideConfig.setAddress(\"override-config://127.0.0.1:2181\");\n                overrideConfig.setProtocol(\"override-config\");\n                Map<String, String> parameters = new HashMap<>();\n                parameters.put(\"key1\", \"value1\");\n                parameters.put(\"key3\", \"value3\");\n                overrideConfig.setParameters(parameters);\n\n                // overrideConfig's config is overridden/set by system config only when the overrideConfig's config is\n                // absent/empty\n                overrideConfig.refresh();\n                Assertions.assertEquals(overrideConfig.getAddress(), \"override-config://127.0.0.1:2181\");\n                Assertions.assertEquals(overrideConfig.getProtocol(), \"override-config\");\n                Assertions.assertEquals(overrideConfig.getKey(), \"systemKey\");\n                Assertions.assertEquals(\n                        overrideConfig.getParameters(),\n                        StringUtils.parseParameters(\"[{key1:value1},{key2:systemValue2},{key3:value3}]\"));\n            }\n\n        } finally {\n            frameworkModel.destroy();\n        }\n    }\n\n    @Test\n    void testOnlyPrefixedKeyTakeEffect() {\n        try {\n            OverrideConfig overrideConfig = new OverrideConfig();\n            overrideConfig.setNotConflictKey(\"value-from-config\");\n\n            Map<String, String> external = new HashMap<>();\n            external.put(\"notConflictKey\", \"value-from-external\");\n            external.put(\"dubbo.override.notConflictKey2\", \"value-from-external\");\n\n            ApplicationModel.defaultModel().modelEnvironment().setExternalConfigMap(external);\n\n            overrideConfig.refresh();\n\n            Assertions.assertEquals(\"value-from-config\", overrideConfig.getNotConflictKey());\n            Assertions.assertEquals(\"value-from-external\", overrideConfig.getNotConflictKey2());\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n        }\n    }\n\n    @Test\n    void tetMetaData() {\n        OverrideConfig overrideConfig = new OverrideConfig();\n        overrideConfig.setId(\"override-id\");\n        overrideConfig.setAddress(\"override-config://127.0.0.1:2181\");\n        overrideConfig.setProtocol(\"override-config\");\n        overrideConfig.setEscape(\"override-config://\");\n        overrideConfig.setExclude(\"override-config\");\n\n        Map<String, String> metaData = overrideConfig.getMetaData();\n        Assertions.assertEquals(\"override-config://127.0.0.1:2181\", metaData.get(\"address\"));\n        Assertions.assertEquals(\"override-config\", metaData.get(\"protocol\"));\n        Assertions.assertEquals(\"override-config://\", metaData.get(\"escape\"));\n        Assertions.assertEquals(\"override-config\", metaData.get(\"exclude\"));\n        Assertions.assertNull(metaData.get(\"key\"));\n        Assertions.assertNull(metaData.get(\"key2\"));\n\n        // with prefix\n        Map<String, String> prefixMetadata =\n                overrideConfig.getMetaData(OverrideConfig.getTypePrefix(OverrideConfig.class));\n        Assertions.assertEquals(\"override-config://127.0.0.1:2181\", prefixMetadata.get(\"dubbo.override.address\"));\n        Assertions.assertEquals(\"override-config\", prefixMetadata.get(\"dubbo.override.protocol\"));\n        Assertions.assertEquals(\"override-config://\", prefixMetadata.get(\"dubbo.override.escape\"));\n        Assertions.assertEquals(\"override-config\", prefixMetadata.get(\"dubbo.override.exclude\"));\n    }\n\n    @Test\n    void testEquals() {\n        ApplicationConfig application1 = new ApplicationConfig();\n        ApplicationConfig application2 = new ApplicationConfig();\n        application1.setName(\"app1\");\n        application2.setName(\"app2\");\n        Assertions.assertNotEquals(application1, application2);\n        application1.setName(\"sameName\");\n        application2.setName(\"sameName\");\n        Assertions.assertEquals(application1, application2);\n\n        ProtocolConfig protocol1 = new ProtocolConfig();\n        protocol1.setName(\"dubbo\");\n        protocol1.setPort(1234);\n        ProtocolConfig protocol2 = new ProtocolConfig();\n        protocol2.setName(\"dubbo\");\n        protocol2.setPort(1235);\n        Assertions.assertNotEquals(protocol1, protocol2);\n    }\n\n    @Test\n    void testRegistryConfigEquals() {\n        RegistryConfig hangzhou = new RegistryConfig();\n        hangzhou.setAddress(\"nacos://localhost:8848\");\n        HashMap<String, String> parameters = new HashMap<>();\n        parameters.put(\"namespace\", \"hangzhou\");\n        hangzhou.setParameters(parameters);\n\n        RegistryConfig shanghai = new RegistryConfig();\n        shanghai.setAddress(\"nacos://localhost:8848\");\n        parameters = new HashMap<>();\n        parameters.put(\"namespace\", \"shanghai\");\n\n        shanghai.setParameters(parameters);\n\n        Assertions.assertNotEquals(hangzhou, shanghai);\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.ANNOTATION_TYPE})\n    public @interface ConfigField {\n        String value() default \"\";\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})\n    public @interface Config {\n        Class<?> interfaceClass() default void.class;\n\n        String interfaceName() default \"\";\n\n        String[] filter() default {};\n\n        String[] listener() default {};\n\n        String[] parameters() default {};\n\n        ConfigField[] configFields() default {};\n\n        ConfigField configField() default @ConfigField;\n    }\n\n    private static class OverrideConfig extends AbstractConfig {\n        public String address;\n        public String protocol;\n        public String exclude;\n        public String key;\n        public String key2;\n        public String escape;\n        public String notConflictKey;\n        public String notConflictKey2;\n        protected Map<String, String> parameters;\n\n        public OverrideConfig() {}\n\n        public OverrideConfig(ScopeModel scopeModel) {\n            super(scopeModel);\n        }\n\n        public String getAddress() {\n            return address;\n        }\n\n        public void setAddress(String address) {\n            this.address = address;\n        }\n\n        public String getProtocol() {\n            return protocol;\n        }\n\n        public void setProtocol(String protocol) {\n            this.protocol = protocol;\n        }\n\n        @Parameter(excluded = true)\n        public String getExclude() {\n            return exclude;\n        }\n\n        public void setExclude(String exclude) {\n            this.exclude = exclude;\n        }\n\n        @Parameter(key = \"key1\")\n        public String getKey() {\n            return key;\n        }\n\n        public void setKey(String key) {\n            this.key = key;\n        }\n\n        @Parameter(key = \"mykey\")\n        public String getKey2() {\n            return key2;\n        }\n\n        public void setKey2(String key2) {\n            this.key2 = key2;\n        }\n\n        @Parameter(escaped = true)\n        public String getEscape() {\n            return escape;\n        }\n\n        public void setEscape(String escape) {\n            this.escape = escape;\n        }\n\n        public String getNotConflictKey() {\n            return notConflictKey;\n        }\n\n        public void setNotConflictKey(String notConflictKey) {\n            this.notConflictKey = notConflictKey;\n        }\n\n        public String getNotConflictKey2() {\n            return notConflictKey2;\n        }\n\n        public void setNotConflictKey2(String notConflictKey2) {\n            this.notConflictKey2 = notConflictKey2;\n        }\n\n        public Map<String, String> getParameters() {\n            return parameters;\n        }\n\n        public void setParameters(Map<String, String> parameters) {\n            this.parameters = parameters;\n        }\n    }\n\n    private static class ParameterConfig {\n        private int number;\n        private String name;\n        private int age;\n        private String secret;\n        private String detailAddress;\n\n        ParameterConfig() {}\n\n        ParameterConfig(int number, String name, int age, String secret) {\n            this(number, name, age, secret, \"\");\n        }\n\n        ParameterConfig(int number, String name, int age, String secret, String detailAddress) {\n            this.number = number;\n            this.name = name;\n            this.age = age;\n            this.secret = secret;\n            this.detailAddress = detailAddress;\n        }\n\n        public String getDetailAddress() {\n            return detailAddress;\n        }\n\n        public void setDetailAddress(String detailAddress) {\n            this.detailAddress = detailAddress;\n        }\n\n        @Parameter(key = \"num\", append = true)\n        public int getNumber() {\n            return number;\n        }\n\n        public void setNumber(int number) {\n            this.number = number;\n        }\n\n        @Parameter(key = \"naming\", append = true, escaped = true, required = true)\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public int getAge() {\n            return age;\n        }\n\n        public void setAge(int age) {\n            this.age = age;\n        }\n\n        @Parameter(excluded = true)\n        public String getSecret() {\n            return secret;\n        }\n\n        public void setSecret(String secret) {\n            this.secret = secret;\n        }\n\n        public Map getParameters() {\n            Map<String, String> map = new HashMap<String, String>();\n            map.put(\"key.1\", \"one\");\n            map.put(\"key.2\", \"two\");\n            return map;\n        }\n    }\n\n    private static class AnnotationConfig extends AbstractConfig {\n        private Class interfaceClass;\n        private String filter;\n        private String listener;\n        private Map<String, String> parameters;\n        private String[] configFields;\n\n        public Class getInterface() {\n            return interfaceClass;\n        }\n\n        public void setInterface(Class interfaceName) {\n            this.interfaceClass = interfaceName;\n        }\n\n        public String getFilter() {\n            return filter;\n        }\n\n        public void setFilter(String filter) {\n            this.filter = filter;\n        }\n\n        public String getListener() {\n            return listener;\n        }\n\n        public void setListener(String listener) {\n            this.listener = listener;\n        }\n\n        public Map<String, String> getParameters() {\n            return parameters;\n        }\n\n        public void setParameters(Map<String, String> parameters) {\n            this.parameters = parameters;\n        }\n\n        public String[] getConfigFields() {\n            return configFields;\n        }\n\n        public void setConfigFields(String[] configFields) {\n            this.configFields = configFields;\n        }\n    }\n\n    @Test\n    void testMetaData() throws Exception {\n\n        // Expect empty metadata for new instance\n        // Check and set default value of field in checkDefault() method\n\n        List<Class<? extends AbstractConfig>> configClasses = Arrays.asList(\n                ApplicationConfig.class,\n                ConsumerConfig.class,\n                ProviderConfig.class,\n                ReferenceConfig.class,\n                ServiceConfig.class,\n                ProtocolConfig.class,\n                RegistryConfig.class,\n                ConfigCenterConfig.class,\n                MetadataReportConfig.class,\n                ModuleConfig.class,\n                SslConfig.class,\n                MetricsConfig.class,\n                MonitorConfig.class,\n                MethodConfig.class);\n\n        for (Class<? extends AbstractConfig> configClass : configClasses) {\n            AbstractConfig config = configClass.getDeclaredConstructor().newInstance();\n            Map<String, String> metaData = config.getMetaData();\n            Assertions.assertEquals(\n                    0,\n                    metaData.size(),\n                    \"Expect empty metadata for new instance but found: \" + metaData + \" of \"\n                            + configClass.getSimpleName());\n        }\n    }\n\n    @Test\n    void testRefreshNested() {\n        try {\n            OuterConfig outerConfig = new OuterConfig();\n\n            Map<String, String> external = new HashMap<>();\n            external.put(\"dubbo.outer.a1\", \"1\");\n            external.put(\"dubbo.outer.b.b1\", \"11\");\n            external.put(\"dubbo.outer.b.b2\", \"12\");\n            ApplicationModel.defaultModel().modelEnvironment().initialize();\n            ApplicationModel.defaultModel().modelEnvironment().setExternalConfigMap(external);\n\n            // refresh config\n            outerConfig.refresh();\n\n            Assertions.assertEquals(1, outerConfig.getA1());\n            Assertions.assertEquals(11, outerConfig.getB().getB1());\n            Assertions.assertEquals(12, outerConfig.getB().getB2());\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n        }\n    }\n\n    @Test\n    void testRefreshNestedWithId() {\n        try {\n            System.setProperty(\"dubbo.outers.test.a1\", \"1\");\n            System.setProperty(\"dubbo.outers.test.b.b1\", \"11\");\n            System.setProperty(\"dubbo.outers.test.b.b2\", \"12\");\n\n            ApplicationModel.defaultModel().modelEnvironment().initialize();\n\n            OuterConfig outerConfig = new OuterConfig(\"test\");\n            outerConfig.refresh();\n\n            Assertions.assertEquals(1, outerConfig.getA1());\n            Assertions.assertEquals(11, outerConfig.getB().getB1());\n            Assertions.assertEquals(12, outerConfig.getB().getB2());\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n            System.clearProperty(\"dubbo.outers.test.a1\");\n            System.clearProperty(\"dubbo.outers.test.b.b1\");\n            System.clearProperty(\"dubbo.outers.test.b.b2\");\n        }\n    }\n\n    @Test\n    void testRefreshNestedBySystemProperties() {\n        try {\n            Properties p = System.getProperties();\n            p.put(\"dubbo.outer.a1\", \"1\");\n            p.put(\"dubbo.outer.b.b1\", \"11\");\n            p.put(\"dubbo.outer.b.b2\", \"12\");\n\n            ApplicationModel.defaultModel().modelEnvironment().initialize();\n\n            OuterConfig outerConfig = new OuterConfig();\n            outerConfig.refresh();\n\n            Assertions.assertEquals(1, outerConfig.getA1());\n            Assertions.assertEquals(11, outerConfig.getB().getB1());\n            Assertions.assertEquals(12, outerConfig.getB().getB2());\n        } finally {\n            ApplicationModel.defaultModel().modelEnvironment().destroy();\n            System.clearProperty(\"dubbo.outer.a1\");\n            System.clearProperty(\"dubbo.outer.b.b1\");\n            System.clearProperty(\"dubbo.outer.b.b2\");\n        }\n    }\n\n    private static class OuterConfig extends AbstractConfig {\n        private Integer a1;\n\n        @Nested\n        private InnerConfig b;\n\n        OuterConfig() {}\n\n        OuterConfig(String id) {\n            this.setId(id);\n        }\n\n        public Integer getA1() {\n            return a1;\n        }\n\n        public void setA1(Integer a1) {\n            this.a1 = a1;\n        }\n\n        public InnerConfig getB() {\n            return b;\n        }\n\n        public void setB(InnerConfig b) {\n            this.b = b;\n        }\n    }\n\n    public static class InnerConfig {\n        private Integer b1;\n\n        private Integer b2;\n\n        public Integer getB1() {\n            return b1;\n        }\n\n        public void setB1(Integer b1) {\n            this.b1 = b1;\n        }\n\n        public Integer getB2() {\n            return b2;\n        }\n\n        public void setB2(Integer b2) {\n            this.b2 = b2;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractMethodConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.isEmptyOrNullString;\nimport static org.hamcrest.Matchers.sameInstance;\n\nclass AbstractMethodConfigTest {\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testTimeout() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setTimeout(10);\n        assertThat(methodConfig.getTimeout(), equalTo(10));\n    }\n\n    @Test\n    void testForks() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setForks(10);\n        assertThat(methodConfig.getForks(), equalTo(10));\n    }\n\n    @Test\n    void testRetries() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setRetries(3);\n        assertThat(methodConfig.getRetries(), equalTo(3));\n    }\n\n    @Test\n    void testLoadbalance() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setLoadbalance(\"mockloadbalance\");\n        assertThat(methodConfig.getLoadbalance(), equalTo(\"mockloadbalance\"));\n    }\n\n    @Test\n    void testAsync() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setAsync(true);\n        assertThat(methodConfig.isAsync(), is(true));\n    }\n\n    @Test\n    void testActives() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setActives(10);\n        assertThat(methodConfig.getActives(), equalTo(10));\n    }\n\n    @Test\n    void testSent() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setSent(true);\n        assertThat(methodConfig.getSent(), is(true));\n    }\n\n    @Test\n    void testMock() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setMock((Boolean) null);\n        assertThat(methodConfig.getMock(), isEmptyOrNullString());\n        methodConfig.setMock(true);\n        assertThat(methodConfig.getMock(), equalTo(\"true\"));\n        methodConfig.setMock(\"return null\");\n        assertThat(methodConfig.getMock(), equalTo(\"return null\"));\n        methodConfig.setMock(\"mock\");\n        assertThat(methodConfig.getMock(), equalTo(\"mock\"));\n    }\n\n    @Test\n    void testMerger() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setMerger(\"merger\");\n        assertThat(methodConfig.getMerger(), equalTo(\"merger\"));\n    }\n\n    @Test\n    void testCache() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setCache(\"cache\");\n        assertThat(methodConfig.getCache(), equalTo(\"cache\"));\n    }\n\n    @Test\n    void testValidation() {\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setValidation(\"validation\");\n        assertThat(methodConfig.getValidation(), equalTo(\"validation\"));\n    }\n\n    @Test\n    void testParameters() throws Exception {\n        MethodConfig methodConfig = new MethodConfig();\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(\"key\", \"value\");\n        methodConfig.setParameters(parameters);\n        assertThat(methodConfig.getParameters(), sameInstance(parameters));\n    }\n\n    private static class MethodConfig extends AbstractMethodConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractReferenceConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.rpc.cluster.router.condition.ConditionStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.condition.config.AppStateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;\nimport org.apache.dubbo.rpc.cluster.router.tag.TagStateRouterFactory;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;\nimport static org.apache.dubbo.common.constants.CommonConstants.INVOKER_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.STUB_EVENT_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_STICKY_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasKey;\nimport static org.hamcrest.Matchers.hasValue;\nimport static org.hamcrest.Matchers.is;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass AbstractReferenceConfigTest {\n\n    @AfterAll\n    public static void afterAll() throws Exception {\n        FrameworkModel.destroyAll();\n    }\n\n    @Test\n    void testCheck() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setCheck(true);\n        assertThat(referenceConfig.isCheck(), is(true));\n    }\n\n    @Test\n    void testInit() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setInit(true);\n        assertThat(referenceConfig.isInit(), is(true));\n    }\n\n    @Test\n    void testGeneric() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setGeneric(true);\n        assertThat(referenceConfig.isGeneric(), is(true));\n        Map<String, String> parameters = new HashMap<String, String>();\n        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);\n        // FIXME: not sure why AbstractReferenceConfig has both isGeneric and getGeneric\n        assertThat(parameters, hasKey(\"generic\"));\n    }\n\n    @Test\n    void testInjvm() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setInjvm(true);\n        assertThat(referenceConfig.isInjvm(), is(true));\n    }\n\n    @Test\n    void testFilter() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setFilter(\"mockfilter\");\n        assertThat(referenceConfig.getFilter(), equalTo(\"mockfilter\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(REFERENCE_FILTER_KEY, \"prefilter\");\n        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);\n        assertThat(parameters, hasValue(\"prefilter,mockfilter\"));\n    }\n\n    @Test\n    void testRouter() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setRouter(\"condition\");\n        assertThat(referenceConfig.getRouter(), equalTo(\"condition\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(ROUTER_KEY, \"tag\");\n        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);\n        assertThat(parameters, hasValue(\"tag,condition\"));\n        URL url = mock(URL.class);\n        when(url.getParameter(ROUTER_KEY)).thenReturn(\"condition\");\n        List<StateRouterFactory> routerFactories =\n                ExtensionLoader.getExtensionLoader(StateRouterFactory.class).getActivateExtension(url, ROUTER_KEY);\n        assertThat(\n                routerFactories.stream()\n                        .anyMatch(routerFactory -> routerFactory.getClass().equals(ConditionStateRouterFactory.class)),\n                is(true));\n        when(url.getParameter(ROUTER_KEY)).thenReturn(\"-tag,-app\");\n        routerFactories =\n                ExtensionLoader.getExtensionLoader(StateRouterFactory.class).getActivateExtension(url, ROUTER_KEY);\n        assertThat(\n                routerFactories.stream()\n                        .allMatch(routerFactory -> !routerFactory.getClass().equals(TagStateRouterFactory.class)\n                                && !routerFactory.getClass().equals(AppStateRouterFactory.class)),\n                is(true));\n    }\n\n    @Test\n    void testListener() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setListener(\"mockinvokerlistener\");\n        assertThat(referenceConfig.getListener(), equalTo(\"mockinvokerlistener\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(INVOKER_LISTENER_KEY, \"prelistener\");\n        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);\n        assertThat(parameters, hasValue(\"prelistener,mockinvokerlistener\"));\n    }\n\n    @Test\n    void testLazy() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setLazy(true);\n        assertThat(referenceConfig.getLazy(), is(true));\n    }\n\n    @Test\n    void testOnconnect() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setOnconnect(\"onConnect\");\n        assertThat(referenceConfig.getOnconnect(), equalTo(\"onConnect\"));\n        assertThat(referenceConfig.getStubevent(), is(true));\n    }\n\n    @Test\n    void testOndisconnect() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setOndisconnect(\"onDisconnect\");\n        assertThat(referenceConfig.getOndisconnect(), equalTo(\"onDisconnect\"));\n        assertThat(referenceConfig.getStubevent(), is(true));\n    }\n\n    @Test\n    void testStubevent() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setOnconnect(\"onConnect\");\n        Map<String, String> parameters = new HashMap<String, String>();\n        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);\n        assertThat(parameters, hasKey(STUB_EVENT_KEY));\n    }\n\n    @Test\n    void testReconnect() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setReconnect(\"reconnect\");\n        Map<String, String> parameters = new HashMap<String, String>();\n        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);\n        assertThat(referenceConfig.getReconnect(), equalTo(\"reconnect\"));\n        assertThat(parameters, hasKey(Constants.RECONNECT_KEY));\n    }\n\n    @Test\n    void testSticky() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setSticky(true);\n        Map<String, String> parameters = new HashMap<String, String>();\n        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);\n        assertThat(referenceConfig.getSticky(), is(true));\n        assertThat(parameters, hasKey(CLUSTER_STICKY_KEY));\n    }\n\n    @Test\n    void testVersion() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setVersion(\"version\");\n        assertThat(referenceConfig.getVersion(), equalTo(\"version\"));\n    }\n\n    @Test\n    void testGroup() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setGroup(\"group\");\n        assertThat(referenceConfig.getGroup(), equalTo(\"group\"));\n    }\n\n    @Test\n    void testGenericOverride() {\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setGeneric(\"false\");\n        referenceConfig.refresh();\n        Assertions.assertFalse(referenceConfig.isGeneric());\n        Assertions.assertEquals(\"false\", referenceConfig.getGeneric());\n\n        ReferenceConfig referenceConfig1 = new ReferenceConfig();\n        referenceConfig1.setGeneric(GENERIC_SERIALIZATION_NATIVE_JAVA);\n        referenceConfig1.refresh();\n        Assertions.assertEquals(GENERIC_SERIALIZATION_NATIVE_JAVA, referenceConfig1.getGeneric());\n        Assertions.assertTrue(referenceConfig1.isGeneric());\n\n        ReferenceConfig referenceConfig2 = new ReferenceConfig();\n        referenceConfig2.refresh();\n        Assertions.assertNull(referenceConfig2.getGeneric());\n    }\n\n    private static class ReferenceConfig extends AbstractReferenceConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractServiceConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.EXPORTER_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SERVICE_FILTER_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.hasSize;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.notNullValue;\nimport static org.hamcrest.Matchers.nullValue;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass AbstractServiceConfigTest {\n    @Test\n    void testVersion() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setVersion(\"version\");\n        assertThat(serviceConfig.getVersion(), equalTo(\"version\"));\n    }\n\n    @Test\n    void testGroup() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setGroup(\"group\");\n        assertThat(serviceConfig.getGroup(), equalTo(\"group\"));\n    }\n\n    @Test\n    void testDelay() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setDelay(1000);\n        assertThat(serviceConfig.getDelay(), equalTo(1000));\n    }\n\n    @Test\n    void testExport() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setExport(true);\n        assertThat(serviceConfig.getExport(), is(true));\n    }\n\n    @Test\n    void testWeight() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setWeight(500);\n        assertThat(serviceConfig.getWeight(), equalTo(500));\n    }\n\n    @Test\n    void testDocument() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setDocument(\"http://dubbo.apache.org\");\n        assertThat(serviceConfig.getDocument(), equalTo(\"http://dubbo.apache.org\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        AbstractServiceConfig.appendParameters(parameters, serviceConfig);\n        assertThat(parameters, hasEntry(\"document\", \"http%3A%2F%2Fdubbo.apache.org\"));\n    }\n\n    @Test\n    void testToken() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setToken(\"token\");\n        assertThat(serviceConfig.getToken(), equalTo(\"token\"));\n        serviceConfig.setToken((Boolean) null);\n        assertThat(serviceConfig.getToken(), nullValue());\n        serviceConfig.setToken(true);\n        assertThat(serviceConfig.getToken(), is(\"true\"));\n    }\n\n    @Test\n    void testDeprecated() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setDeprecated(true);\n        assertThat(serviceConfig.isDeprecated(), is(true));\n    }\n\n    @Test\n    void testDynamic() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setDynamic(true);\n        assertThat(serviceConfig.isDynamic(), is(true));\n    }\n\n    @Test\n    void testProtocol() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        assertThat(serviceConfig.getProtocol(), nullValue());\n        serviceConfig.setProtocol(new ProtocolConfig());\n        assertThat(serviceConfig.getProtocol(), notNullValue());\n        serviceConfig.setProtocols(new ArrayList<>(Collections.singletonList(new ProtocolConfig())));\n        assertThat(serviceConfig.getProtocols(), hasSize(1));\n    }\n\n    @Test\n    void testAccesslog() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setAccesslog(\"access.log\");\n        assertThat(serviceConfig.getAccesslog(), equalTo(\"access.log\"));\n        serviceConfig.setAccesslog((Boolean) null);\n        assertThat(serviceConfig.getAccesslog(), nullValue());\n        serviceConfig.setAccesslog(true);\n        assertThat(serviceConfig.getAccesslog(), equalTo(\"true\"));\n    }\n\n    @Test\n    void testExecutes() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setExecutes(10);\n        assertThat(serviceConfig.getExecutes(), equalTo(10));\n    }\n\n    @Test\n    void testFilter() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setFilter(\"mockfilter\");\n        assertThat(serviceConfig.getFilter(), equalTo(\"mockfilter\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(SERVICE_FILTER_KEY, \"prefilter\");\n        AbstractServiceConfig.appendParameters(parameters, serviceConfig);\n        assertThat(parameters, hasEntry(SERVICE_FILTER_KEY, \"prefilter,mockfilter\"));\n    }\n\n    @Test\n    void testListener() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setListener(\"mockexporterlistener\");\n        assertThat(serviceConfig.getListener(), equalTo(\"mockexporterlistener\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(EXPORTER_LISTENER_KEY, \"prelistener\");\n        AbstractServiceConfig.appendParameters(parameters, serviceConfig);\n        assertThat(parameters, hasEntry(EXPORTER_LISTENER_KEY, \"prelistener,mockexporterlistener\"));\n    }\n\n    @Test\n    void testRegister() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setRegister(true);\n        assertThat(serviceConfig.isRegister(), is(true));\n    }\n\n    @Test\n    void testWarmup() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setWarmup(100);\n        assertThat(serviceConfig.getWarmup(), equalTo(100));\n    }\n\n    @Test\n    void testSerialization() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setSerialization(\"serialization\");\n        assertThat(serviceConfig.getSerialization(), equalTo(\"serialization\"));\n    }\n\n    @Test\n    void testPreferSerialization() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setPreferSerialization(\"preferSerialization\");\n        assertThat(serviceConfig.getPreferSerialization(), equalTo(\"preferSerialization\"));\n    }\n\n    @Test\n    void testPreferSerializationDefault1() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        assertNull(serviceConfig.getPreferSerialization());\n\n        serviceConfig.checkDefault();\n        assertNull(serviceConfig.getPreferSerialization());\n\n        serviceConfig = new ServiceConfig();\n        serviceConfig.setSerialization(\"x-serialization\");\n        assertNull(serviceConfig.getPreferSerialization());\n\n        serviceConfig.checkDefault();\n        assertThat(serviceConfig.getPreferSerialization(), equalTo(\"x-serialization\"));\n    }\n\n    @Test\n    void testPreferSerializationDefault2() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        assertNull(serviceConfig.getPreferSerialization());\n\n        serviceConfig.refresh();\n        assertNull(serviceConfig.getPreferSerialization());\n\n        serviceConfig = new ServiceConfig();\n        serviceConfig.setSerialization(\"x-serialization\");\n        assertNull(serviceConfig.getPreferSerialization());\n\n        serviceConfig.refresh();\n        assertThat(serviceConfig.getPreferSerialization(), equalTo(\"x-serialization\"));\n    }\n\n    private static class ServiceConfig extends AbstractServiceConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ApplicationConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_ISOLATION;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.contains;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.sameInstance;\nimport static org.hamcrest.collection.IsCollectionWithSize.hasSize;\n\nclass ApplicationConfigTest {\n\n    @BeforeEach\n    public void beforeEach() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void afterEach() {\n        SysProps.clear();\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testName() {\n        ApplicationConfig application = new ApplicationConfig();\n        application.setName(\"app\");\n        assertThat(application.getName(), equalTo(\"app\"));\n        assertThat(application.getId(), equalTo(null));\n\n        application = new ApplicationConfig(\"app2\");\n        assertThat(application.getName(), equalTo(\"app2\"));\n        assertThat(application.getId(), equalTo(null));\n\n        Map<String, String> parameters = new HashMap<String, String>();\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(APPLICATION_KEY, \"app2\"));\n    }\n\n    @Test\n    void testVersion() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setVersion(\"1.0.0\");\n        assertThat(application.getVersion(), equalTo(\"1.0.0\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(\"application.version\", \"1.0.0\"));\n    }\n\n    @Test\n    void testOwner() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setOwner(\"owner\");\n        assertThat(application.getOwner(), equalTo(\"owner\"));\n    }\n\n    @Test\n    void testOrganization() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setOrganization(\"org\");\n        assertThat(application.getOrganization(), equalTo(\"org\"));\n    }\n\n    @Test\n    void testArchitecture() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setArchitecture(\"arch\");\n        assertThat(application.getArchitecture(), equalTo(\"arch\"));\n    }\n\n    @Test\n    void testEnvironment1() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setEnvironment(\"develop\");\n        assertThat(application.getEnvironment(), equalTo(\"develop\"));\n        application.setEnvironment(\"test\");\n        assertThat(application.getEnvironment(), equalTo(\"test\"));\n        application.setEnvironment(\"product\");\n        assertThat(application.getEnvironment(), equalTo(\"product\"));\n    }\n\n    @Test\n    void testEnvironment2() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            ApplicationConfig application = new ApplicationConfig(\"app\");\n            application.setEnvironment(\"illegal-env\");\n        });\n    }\n\n    @Test\n    void testRegistry() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        RegistryConfig registry = new RegistryConfig();\n        application.setRegistry(registry);\n        assertThat(application.getRegistry(), sameInstance(registry));\n        application.setRegistries(Collections.singletonList(registry));\n        assertThat(application.getRegistries(), contains(registry));\n        assertThat(application.getRegistries(), hasSize(1));\n    }\n\n    @Test\n    void testMonitor() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setMonitor(new MonitorConfig(\"monitor-addr\"));\n        assertThat(application.getMonitor().getAddress(), equalTo(\"monitor-addr\"));\n        application.setMonitor(\"monitor-addr\");\n        assertThat(application.getMonitor().getAddress(), equalTo(\"monitor-addr\"));\n    }\n\n    @Test\n    void testLogger() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setLogger(\"log4j2\");\n        assertThat(application.getLogger(), equalTo(\"log4j2\"));\n    }\n\n    @Test\n    void testDefault() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setDefault(true);\n        assertThat(application.isDefault(), is(true));\n    }\n\n    @Test\n    void testDumpDirectory() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setDumpDirectory(\"/dump\");\n        assertThat(application.getDumpDirectory(), equalTo(\"/dump\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(DUMP_DIRECTORY, \"/dump\"));\n    }\n\n    @Test\n    void testQosEnable() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setQosEnable(true);\n        assertThat(application.getQosEnable(), is(true));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(QOS_ENABLE, \"true\"));\n    }\n\n    @Test\n    void testQosPort() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setQosPort(8080);\n        assertThat(application.getQosPort(), equalTo(8080));\n    }\n\n    @Test\n    void testQosAcceptForeignIp() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setQosAcceptForeignIp(true);\n        assertThat(application.getQosAcceptForeignIp(), is(true));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(ACCEPT_FOREIGN_IP, \"true\"));\n    }\n\n    @Test\n    void testParameters() throws Exception {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        application.setQosAcceptForeignIp(true);\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(\"k1\", \"v1\");\n        ApplicationConfig.appendParameters(parameters, application);\n        assertThat(parameters, hasEntry(\"k1\", \"v1\"));\n        assertThat(parameters, hasEntry(ACCEPT_FOREIGN_IP, \"true\"));\n    }\n\n    @Test\n    void testAppendEnvironmentProperties() {\n        ApplicationConfig application = new ApplicationConfig(\"app\");\n        SysProps.setProperty(\"dubbo.labels\", \"tag1=value1;tag2=value2 ; tag3 = value3\");\n        application.refresh();\n        Map<String, String> parameters = application.getParameters();\n        Assertions.assertEquals(\"value1\", parameters.get(\"tag1\"));\n        Assertions.assertEquals(\"value2\", parameters.get(\"tag2\"));\n        Assertions.assertEquals(\"value3\", parameters.get(\"tag3\"));\n\n        ApplicationConfig application1 = new ApplicationConfig(\"app\");\n        SysProps.setProperty(\"dubbo.env.keys\", \"tag1, tag2,tag3\");\n        // mock environment variables\n        SysProps.setProperty(\"tag1\", \"value1\");\n        SysProps.setProperty(\"tag2\", \"value2\");\n        SysProps.setProperty(\"tag3\", \"value3\");\n        application1.refresh();\n        Map<String, String> parameters1 = application1.getParameters();\n        Assertions.assertEquals(\"value2\", parameters1.get(\"tag2\"));\n        Assertions.assertEquals(\"value3\", parameters1.get(\"tag3\"));\n\n        Map<String, String> urlParameters = new HashMap<>();\n        ApplicationConfig.appendParameters(urlParameters, application1);\n        Assertions.assertEquals(\"value1\", urlParameters.get(\"tag1\"));\n        Assertions.assertEquals(\"value2\", urlParameters.get(\"tag2\"));\n        Assertions.assertEquals(\"value3\", urlParameters.get(\"tag3\"));\n    }\n\n    @Test\n    void testMetaData() {\n        ApplicationConfig config = new ApplicationConfig();\n        Map<String, String> metaData = config.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"Expect empty metadata but found: \" + metaData);\n    }\n\n    @Test\n    void testOverrideEmptyConfig() {\n        String owner = \"tom1\";\n        SysProps.setProperty(\"dubbo.application.name\", \"demo-app\");\n        SysProps.setProperty(\"dubbo.application.owner\", owner);\n        SysProps.setProperty(\"dubbo.application.version\", \"1.2.3\");\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n\n        DubboBootstrap.getInstance().application(applicationConfig).initialize();\n\n        Assertions.assertEquals(owner, applicationConfig.getOwner());\n        Assertions.assertEquals(\"1.2.3\", applicationConfig.getVersion());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testOverrideConfigById() {\n        String owner = \"tom2\";\n        SysProps.setProperty(\"dubbo.applications.demo-app.owner\", owner);\n        SysProps.setProperty(\"dubbo.applications.demo-app.version\", \"1.2.3\");\n        SysProps.setProperty(\"dubbo.applications.demo-app.name\", \"demo-app\");\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setId(\"demo-app\");\n\n        DubboBootstrap.getInstance().application(applicationConfig).initialize();\n\n        Assertions.assertEquals(\"demo-app\", applicationConfig.getId());\n        Assertions.assertEquals(\"demo-app\", applicationConfig.getName());\n        Assertions.assertEquals(owner, applicationConfig.getOwner());\n        Assertions.assertEquals(\"1.2.3\", applicationConfig.getVersion());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testOverrideConfigByName() {\n        String owner = \"tom3\";\n        SysProps.setProperty(\"dubbo.applications.demo-app.owner\", owner);\n        SysProps.setProperty(\"dubbo.applications.demo-app.version\", \"1.2.3\");\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"demo-app\");\n\n        DubboBootstrap.getInstance().application(applicationConfig).initialize();\n\n        Assertions.assertEquals(owner, applicationConfig.getOwner());\n        Assertions.assertEquals(\"1.2.3\", applicationConfig.getVersion());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testLoadConfig() {\n        String owner = \"tom4\";\n        SysProps.setProperty(\"dubbo.applications.demo-app.owner\", owner);\n        SysProps.setProperty(\"dubbo.applications.demo-app.version\", \"1.2.3\");\n\n        DubboBootstrap.getInstance().initialize();\n\n        ApplicationConfig applicationConfig = DubboBootstrap.getInstance().getApplication();\n\n        Assertions.assertEquals(\"demo-app\", applicationConfig.getId());\n        Assertions.assertEquals(\"demo-app\", applicationConfig.getName());\n        Assertions.assertEquals(owner, applicationConfig.getOwner());\n        Assertions.assertEquals(\"1.2.3\", applicationConfig.getVersion());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testOverrideConfigConvertCase() {\n        SysProps.setProperty(\"dubbo.application.NAME\", \"demo-app\");\n        SysProps.setProperty(\"dubbo.application.qos-Enable\", \"false\");\n        SysProps.setProperty(\"dubbo.application.qos_host\", \"127.0.0.1\");\n        SysProps.setProperty(\"dubbo.application.qosPort\", \"2345\");\n\n        DubboBootstrap.getInstance().initialize();\n\n        ApplicationConfig applicationConfig = DubboBootstrap.getInstance().getApplication();\n\n        Assertions.assertEquals(false, applicationConfig.getQosEnable());\n        Assertions.assertEquals(\"127.0.0.1\", applicationConfig.getQosHost());\n        Assertions.assertEquals(2345, applicationConfig.getQosPort());\n        Assertions.assertEquals(\"demo-app\", applicationConfig.getName());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testDefaultValue() {\n        SysProps.setProperty(\"dubbo.application.NAME\", \"demo-app\");\n\n        DubboBootstrap.getInstance().initialize();\n\n        ApplicationConfig applicationConfig = DubboBootstrap.getInstance().getApplication();\n\n        Assertions.assertEquals(DUBBO, applicationConfig.getProtocol());\n        Assertions.assertEquals(EXECUTOR_MANAGEMENT_MODE_ISOLATION, applicationConfig.getExecutorManagementMode());\n        Assertions.assertEquals(Boolean.TRUE, applicationConfig.getEnableFileCache());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ArgumentConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.is;\n\nclass ArgumentConfigTest {\n    @Test\n    void testIndex() {\n        ArgumentConfig argument = new ArgumentConfig();\n        argument.setIndex(1);\n        assertThat(argument.getIndex(), is(1));\n    }\n\n    @Test\n    void testType() {\n        ArgumentConfig argument = new ArgumentConfig();\n        argument.setType(\"int\");\n        assertThat(argument.getType(), equalTo(\"int\"));\n    }\n\n    @Test\n    void testCallback() {\n        ArgumentConfig argument = new ArgumentConfig();\n        argument.setCallback(true);\n        assertThat(argument.isCallback(), is(true));\n    }\n\n    @Test\n    void testArguments() {\n        ArgumentConfig argument = new ArgumentConfig();\n        argument.setIndex(1);\n        argument.setType(\"int\");\n        argument.setCallback(true);\n        Map<String, String> parameters = new HashMap<String, String>();\n        AbstractServiceConfig.appendParameters(parameters, argument);\n        assertThat(parameters, hasEntry(\"callback\", \"true\"));\n        assertThat(parameters.size(), is(1));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.remoting.Constants.CLIENT_KEY;\n\nclass ConfigCenterConfigTest {\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void afterEach() {\n        SysProps.clear();\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testPrefix() {\n        ConfigCenterConfig config = new ConfigCenterConfig();\n        Assertions.assertEquals(Arrays.asList(\"dubbo.config-center\"), config.getPrefixes());\n\n        config.setId(\"configcenterA\");\n        Assertions.assertEquals(\n                Arrays.asList(\"dubbo.config-centers.configcenterA\", \"dubbo.config-center\"), config.getPrefixes());\n    }\n\n    @Test\n    void testToUrl() {\n        ConfigCenterConfig config = new ConfigCenterConfig();\n        config.setNamespace(\"namespace\");\n        config.setGroup(\"group\");\n        config.setAddress(ZookeeperRegistryCenterConfig.getConnectionAddress());\n        config.setHighestPriority(null);\n        config.refresh();\n\n        Assertions.assertEquals(\n                ZookeeperRegistryCenterConfig.getConnectionAddress() + \"/\"\n                        + ConfigCenterConfig.class.getName()\n                        + \"?check=true&config-file=dubbo.properties&group=group&namespace=namespace&timeout=30000\",\n                config.toUrl().toFullString());\n    }\n\n    @Test\n    void testOverrideConfig() {\n\n        String zkAddr = ZookeeperRegistryCenterConfig.getConnectionAddress();\n        // sysprops has no id\n        SysProps.setProperty(\"dubbo.config-center.check\", \"false\");\n        SysProps.setProperty(\"dubbo.config-center.address\", zkAddr);\n\n        // No id and no address\n        ConfigCenterConfig configCenter = new ConfigCenterConfig();\n        configCenter.setAddress(\"N/A\");\n\n        try {\n            DubboBootstrap.getInstance()\n                    .application(\"demo-app\")\n                    .configCenter(configCenter)\n                    .initialize();\n        } catch (Exception e) {\n            // ignore\n            e.printStackTrace();\n        }\n\n        Collection<ConfigCenterConfig> configCenters =\n                ApplicationModel.defaultModel().getApplicationConfigManager().getConfigCenters();\n        Assertions.assertEquals(1, configCenters.size());\n        Assertions.assertEquals(configCenter, configCenters.iterator().next());\n        Assertions.assertEquals(zkAddr, configCenter.getAddress());\n        Assertions.assertEquals(false, configCenter.isCheck());\n\n        DubboBootstrap.getInstance().stop();\n    }\n\n    @Test\n    void testOverrideConfig2() {\n\n        String zkAddr = \"nacos://127.0.0.1:8848\";\n        // sysprops has no id\n        SysProps.setProperty(\"dubbo.config-center.check\", \"false\");\n        SysProps.setProperty(\"dubbo.config-center.address\", zkAddr);\n\n        // No id but has address\n        ConfigCenterConfig configCenter = new ConfigCenterConfig();\n        configCenter.setAddress(ZookeeperRegistryCenterConfig.getConnectionAddress());\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .configCenter(configCenter)\n                .start();\n\n        Collection<ConfigCenterConfig> configCenters =\n                ApplicationModel.defaultModel().getApplicationConfigManager().getConfigCenters();\n        Assertions.assertEquals(1, configCenters.size());\n        Assertions.assertEquals(configCenter, configCenters.iterator().next());\n        Assertions.assertEquals(zkAddr, configCenter.getAddress());\n        Assertions.assertEquals(false, configCenter.isCheck());\n\n        DubboBootstrap.getInstance().stop();\n    }\n\n    @Test\n    void testOverrideConfigBySystemProps() {\n\n        // Config instance has Id, but sysprops without id\n        SysProps.setProperty(\"dubbo.config-center.check\", \"false\");\n        SysProps.setProperty(\"dubbo.config-center.timeout\", \"1234\");\n\n        // Config instance has id\n        ConfigCenterConfig configCenter = new ConfigCenterConfig();\n        configCenter.setTimeout(3000L);\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .configCenter(configCenter)\n                .initialize();\n\n        Collection<ConfigCenterConfig> configCenters =\n                ApplicationModel.defaultModel().getApplicationConfigManager().getConfigCenters();\n        Assertions.assertEquals(1, configCenters.size());\n        Assertions.assertEquals(configCenter, configCenters.iterator().next());\n        Assertions.assertEquals(1234, configCenter.getTimeout());\n        Assertions.assertEquals(false, configCenter.isCheck());\n\n        DubboBootstrap.getInstance().stop();\n    }\n\n    @Test\n    void testOverrideConfigByDubboProps() {\n\n        ApplicationModel.defaultModel().getDefaultModule();\n        // Config instance has id, dubbo props has no id\n        ApplicationModel.defaultModel()\n                .modelEnvironment()\n                .getPropertiesConfiguration()\n                .setProperty(\"dubbo.config-center.check\", \"false\");\n        ApplicationModel.defaultModel()\n                .modelEnvironment()\n                .getPropertiesConfiguration()\n                .setProperty(\"dubbo.config-center.timeout\", \"1234\");\n\n        try {\n            // Config instance has id\n            ConfigCenterConfig configCenter = new ConfigCenterConfig();\n            configCenter.setTimeout(3000L);\n\n            DubboBootstrap.getInstance()\n                    .application(\"demo-app\")\n                    .configCenter(configCenter)\n                    .initialize();\n\n            Collection<ConfigCenterConfig> configCenters = ApplicationModel.defaultModel()\n                    .getApplicationConfigManager()\n                    .getConfigCenters();\n            Assertions.assertEquals(1, configCenters.size());\n            Assertions.assertEquals(configCenter, configCenters.iterator().next());\n            Assertions.assertEquals(3000L, configCenter.getTimeout());\n            Assertions.assertEquals(false, configCenter.isCheck());\n        } finally {\n            ApplicationModel.defaultModel()\n                    .modelEnvironment()\n                    .getPropertiesConfiguration()\n                    .refresh();\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testOverrideConfigBySystemPropsWithId() {\n\n        // Both config instance and sysprops have id\n        SysProps.setProperty(\"dubbo.config-centers.configcenterA.check\", \"false\");\n        SysProps.setProperty(\"dubbo.config-centers.configcenterA.timeout\", \"1234\");\n\n        // Config instance has id\n        ConfigCenterConfig configCenter = new ConfigCenterConfig();\n        configCenter.setId(\"configcenterA\");\n        configCenter.setTimeout(3000L);\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .configCenter(configCenter)\n                .start();\n\n        Collection<ConfigCenterConfig> configCenters =\n                ApplicationModel.defaultModel().getApplicationConfigManager().getConfigCenters();\n        Assertions.assertEquals(1, configCenters.size());\n        Assertions.assertEquals(configCenter, configCenters.iterator().next());\n        Assertions.assertEquals(1234, configCenter.getTimeout());\n        Assertions.assertEquals(false, configCenter.isCheck());\n\n        DubboBootstrap.getInstance().stop();\n    }\n\n    @Test\n    void testOverrideConfigByDubboPropsWithId() {\n\n        ApplicationModel.defaultModel().getDefaultModule();\n        // Config instance has id, dubbo props has id\n        ApplicationModel.defaultModel()\n                .modelEnvironment()\n                .getPropertiesConfiguration()\n                .setProperty(\"dubbo.config-centers.configcenterA.check\", \"false\");\n        ApplicationModel.defaultModel()\n                .modelEnvironment()\n                .getPropertiesConfiguration()\n                .setProperty(\"dubbo.config-centers.configcenterA.timeout\", \"1234\");\n\n        try {\n            // Config instance has id\n            ConfigCenterConfig configCenter = new ConfigCenterConfig();\n            configCenter.setId(\"configcenterA\");\n            configCenter.setTimeout(3000L);\n\n            DubboBootstrap.getInstance()\n                    .application(\"demo-app\")\n                    .configCenter(configCenter)\n                    .start();\n\n            Collection<ConfigCenterConfig> configCenters = ApplicationModel.defaultModel()\n                    .getApplicationConfigManager()\n                    .getConfigCenters();\n            Assertions.assertEquals(1, configCenters.size());\n            Assertions.assertEquals(configCenter, configCenters.iterator().next());\n            Assertions.assertEquals(3000L, configCenter.getTimeout());\n            Assertions.assertEquals(false, configCenter.isCheck());\n        } finally {\n            ApplicationModel.defaultModel()\n                    .modelEnvironment()\n                    .getPropertiesConfiguration()\n                    .refresh();\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testMetaData() {\n        ConfigCenterConfig configCenter = new ConfigCenterConfig();\n        Map<String, String> metaData = configCenter.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"Expect empty metadata but found: \" + metaData);\n    }\n\n    @Test\n    void testParameters() {\n        ConfigCenterConfig cc = new ConfigCenterConfig();\n        cc.setParameters(new LinkedHashMap<>());\n        cc.getParameters().put(CLIENT_KEY, null);\n\n        Map<String, String> params = new LinkedHashMap<>();\n        ConfigCenterConfig.appendParameters(params, cc);\n\n        Map<String, String> attributes = new LinkedHashMap<>();\n        ConfigCenterConfig.appendAttributes(attributes, cc);\n\n        String encodedParametersStr = attributes.get(\"parameters\");\n        Assertions.assertEquals(\"[]\", encodedParametersStr);\n        Assertions.assertEquals(\n                0, StringUtils.parseParameters(encodedParametersStr).size());\n    }\n\n    @Test\n    void testAttributes() {\n        ConfigCenterConfig cc = new ConfigCenterConfig();\n        cc.setAddress(ZookeeperRegistryCenterConfig.getConnectionAddress());\n        Map<String, String> attributes = new LinkedHashMap<>();\n        ConfigCenterConfig.appendAttributes(attributes, cc);\n\n        Assertions.assertEquals(cc.getAddress(), attributes.get(\"address\"));\n        Assertions.assertEquals(cc.getProtocol(), attributes.get(\"protocol\"));\n        Assertions.assertEquals(\"\" + cc.getPort(), attributes.get(\"port\"));\n        Assertions.assertEquals(null, attributes.get(\"valid\"));\n        Assertions.assertEquals(null, attributes.get(\"refreshed\"));\n    }\n\n    @Test\n    void testSetAddress() {\n        String address = ZookeeperRegistryCenterConfig.getConnectionAddress();\n        ConfigCenterConfig cc = new ConfigCenterConfig();\n        cc.setUsername(\"user123\"); // set username first\n        cc.setPassword(\"pass123\");\n        cc.setAddress(address); // set address last, expect did not override username/password\n\n        Assertions.assertEquals(address, cc.getAddress());\n        Assertions.assertEquals(\"zookeeper\", cc.getProtocol());\n        Assertions.assertEquals(2181, cc.getPort());\n        Assertions.assertEquals(\"user123\", cc.getUsername());\n        Assertions.assertEquals(\"pass123\", cc.getPassword());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigScopeModelInitializerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass ConfigScopeModelInitializerTest {\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n        applicationModel = frameworkModel.newApplication();\n        moduleModel = applicationModel.newModule();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void test() {\n        Assertions.assertNotNull(applicationModel.getDeployer());\n        Assertions.assertNotNull(moduleModel.getDeployer());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.config.api.DemoService;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_TCP_RESPONSE_TIMEOUT;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\n\nclass ConsumerConfigTest {\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void afterEach() {\n        SysProps.clear();\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testTimeout() {\n        SystemPropertyConfigUtils.clearSystemProperty(SYSTEM_TCP_RESPONSE_TIMEOUT);\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setTimeout(10);\n        assertThat(consumer.getTimeout(), is(10));\n        assertThat(SystemPropertyConfigUtils.getSystemProperty(SYSTEM_TCP_RESPONSE_TIMEOUT), equalTo(\"10\"));\n    }\n\n    @Test\n    void testDefault() throws Exception {\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setDefault(true);\n        assertThat(consumer.isDefault(), is(true));\n    }\n\n    @Test\n    void testClient() {\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setClient(\"client\");\n        assertThat(consumer.getClient(), equalTo(\"client\"));\n    }\n\n    @Test\n    void testThreadpool() {\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setThreadpool(\"fixed\");\n        assertThat(consumer.getThreadpool(), equalTo(\"fixed\"));\n    }\n\n    @Test\n    void testCorethreads() {\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setCorethreads(10);\n        assertThat(consumer.getCorethreads(), equalTo(10));\n    }\n\n    @Test\n    void testThreads() {\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setThreads(20);\n        assertThat(consumer.getThreads(), equalTo(20));\n    }\n\n    @Test\n    void testQueues() {\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setQueues(5);\n        assertThat(consumer.getQueues(), equalTo(5));\n    }\n\n    @Test\n    void testOverrideConfigSingle() {\n        SysProps.setProperty(\"dubbo.consumer.check\", \"false\");\n        SysProps.setProperty(\"dubbo.consumer.group\", \"demo\");\n        SysProps.setProperty(\"dubbo.consumer.threads\", \"10\");\n\n        ConsumerConfig consumerConfig = new ConsumerConfig();\n        consumerConfig.setGroup(\"groupA\");\n        consumerConfig.setThreads(20);\n        consumerConfig.setCheck(true);\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .consumer(consumerConfig)\n                .initialize();\n\n        Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel()\n                .getDefaultModule()\n                .getConfigManager()\n                .getConsumers();\n        Assertions.assertEquals(1, consumers.size());\n        Assertions.assertEquals(consumerConfig, consumers.iterator().next());\n        Assertions.assertEquals(false, consumerConfig.isCheck());\n        Assertions.assertEquals(\"demo\", consumerConfig.getGroup());\n        Assertions.assertEquals(10, consumerConfig.getThreads());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testOverrideConfigByPluralityId() {\n        SysProps.setProperty(\"dubbo.consumer.group\", \"demoA\"); // ignore\n        SysProps.setProperty(\"dubbo.consumers.consumerA.check\", \"false\");\n        SysProps.setProperty(\"dubbo.consumers.consumerA.group\", \"demoB\");\n        SysProps.setProperty(\"dubbo.consumers.consumerA.threads\", \"10\");\n\n        ConsumerConfig consumerConfig = new ConsumerConfig();\n        consumerConfig.setId(\"consumerA\");\n        consumerConfig.setGroup(\"groupA\");\n        consumerConfig.setThreads(20);\n        consumerConfig.setCheck(true);\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .consumer(consumerConfig)\n                .initialize();\n\n        Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel()\n                .getDefaultModule()\n                .getConfigManager()\n                .getConsumers();\n        Assertions.assertEquals(1, consumers.size());\n        Assertions.assertEquals(consumerConfig, consumers.iterator().next());\n        Assertions.assertEquals(false, consumerConfig.isCheck());\n        Assertions.assertEquals(\"demoB\", consumerConfig.getGroup());\n        Assertions.assertEquals(10, consumerConfig.getThreads());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testOverrideConfigBySingularId() {\n        // override success\n        SysProps.setProperty(\"dubbo.consumer.group\", \"demoA\");\n        SysProps.setProperty(\"dubbo.consumer.threads\", \"15\");\n        // ignore singular format: dubbo.{tag-name}.{config-id}.{config-item}={config-value}\n        SysProps.setProperty(\"dubbo.consumer.consumerA.check\", \"false\");\n        SysProps.setProperty(\"dubbo.consumer.consumerA.group\", \"demoB\");\n        SysProps.setProperty(\"dubbo.consumer.consumerA.threads\", \"10\");\n\n        ConsumerConfig consumerConfig = new ConsumerConfig();\n        consumerConfig.setId(\"consumerA\");\n        consumerConfig.setGroup(\"groupA\");\n        consumerConfig.setThreads(20);\n        consumerConfig.setCheck(true);\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .consumer(consumerConfig)\n                .initialize();\n\n        Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel()\n                .getDefaultModule()\n                .getConfigManager()\n                .getConsumers();\n        Assertions.assertEquals(1, consumers.size());\n        Assertions.assertEquals(consumerConfig, consumers.iterator().next());\n        Assertions.assertEquals(true, consumerConfig.isCheck());\n        Assertions.assertEquals(\"demoA\", consumerConfig.getGroup());\n        Assertions.assertEquals(15, consumerConfig.getThreads());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testOverrideConfigByDubboProps() {\n        ApplicationModel.defaultModel().getDefaultModule();\n        ApplicationModel.defaultModel()\n                .modelEnvironment()\n                .getPropertiesConfiguration()\n                .setProperty(\"dubbo.consumers.consumerA.check\", \"false\");\n        ApplicationModel.defaultModel()\n                .modelEnvironment()\n                .getPropertiesConfiguration()\n                .setProperty(\"dubbo.consumers.consumerA.group\", \"demo\");\n        ApplicationModel.defaultModel()\n                .modelEnvironment()\n                .getPropertiesConfiguration()\n                .setProperty(\"dubbo.consumers.consumerA.threads\", \"10\");\n\n        try {\n            ConsumerConfig consumerConfig = new ConsumerConfig();\n            consumerConfig.setId(\"consumerA\");\n            consumerConfig.setGroup(\"groupA\");\n\n            DubboBootstrap.getInstance()\n                    .application(\"demo-app\")\n                    .consumer(consumerConfig)\n                    .initialize();\n\n            Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel()\n                    .getDefaultModule()\n                    .getConfigManager()\n                    .getConsumers();\n            Assertions.assertEquals(1, consumers.size());\n            Assertions.assertEquals(consumerConfig, consumers.iterator().next());\n            Assertions.assertEquals(false, consumerConfig.isCheck());\n            Assertions.assertEquals(\"groupA\", consumerConfig.getGroup());\n            Assertions.assertEquals(10, consumerConfig.getThreads());\n        } finally {\n            ApplicationModel.defaultModel()\n                    .modelEnvironment()\n                    .getPropertiesConfiguration()\n                    .refresh();\n            DubboBootstrap.getInstance().destroy();\n        }\n    }\n\n    @Test\n    void testReferenceAndConsumerConfigOverlay() {\n        SysProps.setProperty(\"dubbo.consumer.group\", \"demo\");\n        SysProps.setProperty(\"dubbo.consumer.threads\", \"12\");\n        SysProps.setProperty(\"dubbo.consumer.timeout\", \"1234\");\n        SysProps.setProperty(\"dubbo.consumer.init\", \"false\");\n        SysProps.setProperty(\"dubbo.consumer.check\", \"false\");\n        SysProps.setProperty(\"dubbo.registry.address\", \"N/A\");\n\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setInterface(DemoService.class);\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .reference(referenceConfig)\n                .initialize();\n\n        Assertions.assertEquals(\"demo\", referenceConfig.getGroup());\n        Assertions.assertEquals(1234, referenceConfig.getTimeout());\n        Assertions.assertEquals(false, referenceConfig.isInit());\n        Assertions.assertEquals(false, referenceConfig.isCheck());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testMetaData() {\n        ConsumerConfig consumerConfig = new ConsumerConfig();\n        Map<String, String> metaData = consumerConfig.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"Expect empty metadata but found: \" + metaData);\n    }\n\n    @Test\n    void testSerialize() {\n        ConsumerConfig consumerConfig = new ConsumerConfig();\n        consumerConfig.setCorethreads(1);\n        consumerConfig.setQueues(1);\n        consumerConfig.setThreads(1);\n        consumerConfig.setThreadpool(\"Mock\");\n        consumerConfig.setGroup(\"Test\");\n        consumerConfig.setMeshEnable(false);\n        consumerConfig.setReferThreadNum(2);\n        consumerConfig.setShareconnections(2);\n        consumerConfig.setTimeout(2);\n        consumerConfig.setUrlMergeProcessor(\"test\");\n        consumerConfig.setReferBackground(false);\n        consumerConfig.setActives(1);\n        consumerConfig.setAsync(false);\n        consumerConfig.setCache(\"false\");\n        consumerConfig.setCallbacks(1);\n        consumerConfig.setConnections(1);\n        consumerConfig.setInterfaceClassLoader(Thread.currentThread().getContextClassLoader());\n        consumerConfig.setApplication(new ApplicationConfig());\n        consumerConfig.setRegistries(Collections.singletonList(new RegistryConfig()));\n        consumerConfig.setModule(new ModuleConfig());\n        consumerConfig.setMetadataReportConfig(new MetadataReportConfig());\n        consumerConfig.setMonitor(new MonitorConfig());\n        consumerConfig.setConfigCenter(new ConfigCenterConfig());\n\n        try {\n            JsonUtils.toJson(consumerConfig);\n        } catch (Throwable t) {\n            Assertions.fail(t);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/DubboShutdownHookTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\n\npublic class DubboShutdownHookTest {\n    private DubboShutdownHook dubboShutdownHook;\n    private ApplicationModel applicationModel;\n\n    @BeforeEach\n    public void init() {\n        SysProps.setProperty(CommonConstants.IGNORE_LISTEN_SHUTDOWN_HOOK, \"false\");\n        FrameworkModel frameworkModel = new FrameworkModel();\n        applicationModel = frameworkModel.newApplication();\n        ModuleModel moduleModel = applicationModel.newModule();\n        dubboShutdownHook = new DubboShutdownHook(applicationModel);\n    }\n\n    @AfterEach\n    public void clear() {\n        SysProps.clear();\n    }\n\n    @Test\n    public void testDubboShutdownHook() {\n        Assertions.assertNotNull(dubboShutdownHook);\n        Assertions.assertLinesMatch(asList(\"DubboShutdownHook\"), asList(dubboShutdownHook.getName()));\n        Assertions.assertFalse(dubboShutdownHook.getRegistered());\n    }\n\n    @Test\n    public void testDestoryNoModuleManagedExternally() {\n        boolean hasModuleManagedExternally = false;\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            if (moduleModel.isLifeCycleManagedExternally()) {\n                hasModuleManagedExternally = true;\n                break;\n            }\n        }\n        Assertions.assertFalse(hasModuleManagedExternally);\n        dubboShutdownHook.run();\n        Assertions.assertTrue(applicationModel.isDestroyed());\n    }\n\n    @Test\n    public void testDestoryWithModuleManagedExternally() throws InterruptedException {\n        applicationModel.getModuleModels().get(0).setLifeCycleManagedExternally(true);\n        new Thread(() -> {\n                    applicationModel.getModuleModels().get(0).destroy();\n                })\n                .start();\n        TimeUnit.MILLISECONDS.sleep(10);\n        dubboShutdownHook.run();\n        Assertions.assertTrue(applicationModel.isDestroyed());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MetadataReportConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass MetadataReportConfigTest {\n    @Test\n    void testFile() {\n        MetadataReportConfig metadataReportConfig = new MetadataReportConfig();\n        metadataReportConfig.setFile(\"file\");\n        assertThat(metadataReportConfig.getFile(), equalTo(\"file\"));\n\n        metadataReportConfig.setAddress(\"file://dir-to-file\");\n        URL url = metadataReportConfig.toUrl();\n        assertThat(url.getParameter(\"file\"), equalTo(\"file\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MethodConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.config.annotation.Argument;\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.api.DemoService;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.common.Person;\nimport org.apache.dubbo.config.provider.impl.DemoServiceImpl;\nimport org.apache.dubbo.rpc.model.AsyncMethodInfo;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.config.Constants.ON_INVOKE_INSTANCE_ATTRIBUTE_KEY;\nimport static org.apache.dubbo.config.Constants.ON_INVOKE_METHOD_ATTRIBUTE_KEY;\nimport static org.apache.dubbo.config.Constants.ON_RETURN_INSTANCE_ATTRIBUTE_KEY;\nimport static org.apache.dubbo.config.Constants.ON_RETURN_METHOD_ATTRIBUTE_KEY;\nimport static org.apache.dubbo.config.Constants.ON_THROW_INSTANCE_ATTRIBUTE_KEY;\nimport static org.apache.dubbo.config.Constants.ON_THROW_METHOD_ATTRIBUTE_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.contains;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.hasKey;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.not;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass MethodConfigTest {\n    private static final String METHOD_NAME = \"sayHello\";\n    private static final int TIMEOUT = 1300;\n    private static final int RETRIES = 4;\n    private static final String LOADBALANCE = \"random\";\n    private static final boolean ASYNC = true;\n    private static final int ACTIVES = 3;\n    private static final int EXECUTES = 5;\n    private static final boolean DEPRECATED = true;\n    private static final boolean STICKY = true;\n    private static final String ONINVOKE = \"invokeNotify\";\n    private static final String ONINVOKE_METHOD = \"onInvoke\";\n    private static final String ONTHROW = \"throwNotify\";\n    private static final String ONTHROW_METHOD = \"onThrow\";\n    private static final String ONRETURN = \"returnNotify\";\n    private static final String ONRETURN_METHOD = \"onReturn\";\n    private static final String CACHE = \"c\";\n    private static final String VALIDATION = \"v\";\n    private static final int ARGUMENTS_INDEX = 24;\n    private static final boolean ARGUMENTS_CALLBACK = true;\n    private static final String ARGUMENTS_TYPE = \"sss\";\n\n    @Reference(\n            methods = {\n                @Method(\n                        name = METHOD_NAME,\n                        timeout = TIMEOUT,\n                        retries = RETRIES,\n                        loadbalance = LOADBALANCE,\n                        async = ASYNC,\n                        actives = ACTIVES,\n                        executes = EXECUTES,\n                        deprecated = DEPRECATED,\n                        sticky = STICKY,\n                        oninvoke = ONINVOKE + \".\" + ONINVOKE_METHOD,\n                        onthrow = ONTHROW + \".\" + ONTHROW_METHOD,\n                        onreturn = ONRETURN + \".\" + ONRETURN_METHOD,\n                        cache = CACHE,\n                        validation = VALIDATION,\n                        arguments = {\n                            @Argument(index = ARGUMENTS_INDEX, callback = ARGUMENTS_CALLBACK, type = ARGUMENTS_TYPE)\n                        })\n            })\n    private String testField;\n\n    @BeforeEach\n    public void beforeEach() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void afterEach() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    // TODO remove this test\n    @Test\n    void testStaticConstructor() throws NoSuchFieldException {\n        Method[] methods = this.getClass()\n                .getDeclaredField(\"testField\")\n                .getAnnotation(Reference.class)\n                .methods();\n        List<MethodConfig> methodConfigs = MethodConfig.constructMethodConfig(methods);\n        MethodConfig methodConfig = methodConfigs.get(0);\n\n        assertThat(METHOD_NAME, equalTo(methodConfig.getName()));\n        assertThat(TIMEOUT, equalTo(methodConfig.getTimeout()));\n        assertThat(RETRIES, equalTo(methodConfig.getRetries()));\n        assertThat(LOADBALANCE, equalTo(methodConfig.getLoadbalance()));\n        assertThat(ASYNC, equalTo(methodConfig.isAsync()));\n        assertThat(ACTIVES, equalTo(methodConfig.getActives()));\n        assertThat(EXECUTES, equalTo(methodConfig.getExecutes()));\n        assertThat(DEPRECATED, equalTo(methodConfig.getDeprecated()));\n        assertThat(STICKY, equalTo(methodConfig.getSticky()));\n        assertThat(ONINVOKE, equalTo(methodConfig.getOninvoke()));\n        assertThat(ONINVOKE_METHOD, equalTo(methodConfig.getOninvokeMethod()));\n        assertThat(ONTHROW, equalTo(methodConfig.getOnthrow()));\n        assertThat(ONTHROW_METHOD, equalTo(methodConfig.getOnthrowMethod()));\n        assertThat(ONRETURN, equalTo(methodConfig.getOnreturn()));\n        assertThat(ONRETURN_METHOD, equalTo(methodConfig.getOnreturnMethod()));\n        assertThat(CACHE, equalTo(methodConfig.getCache()));\n        assertThat(VALIDATION, equalTo(methodConfig.getValidation()));\n        assertThat(ARGUMENTS_INDEX, equalTo(methodConfig.getArguments().get(0).getIndex()));\n        assertThat(\n                ARGUMENTS_CALLBACK, equalTo(methodConfig.getArguments().get(0).isCallback()));\n        assertThat(ARGUMENTS_TYPE, equalTo(methodConfig.getArguments().get(0).getType()));\n    }\n\n    @Test\n    void testName() {\n        MethodConfig method = new MethodConfig();\n        method.setName(\"hello\");\n        assertThat(method.getName(), equalTo(\"hello\"));\n        Map<String, String> parameters = new HashMap<>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters, not(hasKey(\"name\")));\n    }\n\n    @Test\n    void testStat() {\n        MethodConfig method = new MethodConfig();\n        method.setStat(10);\n        assertThat(method.getStat(), equalTo(10));\n    }\n\n    @Test\n    void testRetry() {\n        MethodConfig method = new MethodConfig();\n        method.setRetry(true);\n        assertThat(method.isRetry(), is(true));\n    }\n\n    @Test\n    void testReliable() {\n        MethodConfig method = new MethodConfig();\n        method.setReliable(true);\n        assertThat(method.isReliable(), is(true));\n    }\n\n    @Test\n    void testExecutes() {\n        MethodConfig method = new MethodConfig();\n        method.setExecutes(10);\n        assertThat(method.getExecutes(), equalTo(10));\n    }\n\n    @Test\n    void testDeprecated() {\n        MethodConfig method = new MethodConfig();\n        method.setDeprecated(true);\n        assertThat(method.getDeprecated(), is(true));\n    }\n\n    @Test\n    void testArguments() {\n        MethodConfig method = new MethodConfig();\n        ArgumentConfig argument = new ArgumentConfig();\n        method.setArguments(Collections.singletonList(argument));\n        assertThat(method.getArguments(), contains(argument));\n        assertThat(method.getArguments(), Matchers.<ArgumentConfig>hasSize(1));\n    }\n\n    @Test\n    void testSticky() {\n        MethodConfig method = new MethodConfig();\n        method.setSticky(true);\n        assertThat(method.getSticky(), is(true));\n    }\n\n    @Test\n    void testConvertMethodConfig2AsyncInfo() throws Exception {\n        MethodConfig methodConfig = new MethodConfig();\n        String methodName = \"setName\";\n        methodConfig.setOninvokeMethod(methodName);\n        methodConfig.setOnthrowMethod(methodName);\n        methodConfig.setOnreturnMethod(methodName);\n        methodConfig.setOninvoke(new Person());\n        methodConfig.setOnthrow(new Person());\n        methodConfig.setOnreturn(new Person());\n\n        AsyncMethodInfo methodInfo = methodConfig.convertMethodConfig2AsyncInfo();\n\n        assertEquals(methodInfo.getOninvokeMethod(), Person.class.getMethod(methodName, String.class));\n        assertEquals(methodInfo.getOnthrowMethod(), Person.class.getMethod(methodName, String.class));\n        assertEquals(methodInfo.getOnreturnMethod(), Person.class.getMethod(methodName, String.class));\n    }\n\n    // @Test\n    void testOnReturn() {\n        MethodConfig method = new MethodConfig();\n        method.setOnreturn(\"on-return-object\");\n        assertThat(method.getOnreturn(), equalTo(\"on-return-object\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_RETURN_INSTANCE_ATTRIBUTE_KEY, \"on-return-object\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    @Test\n    void testOnReturnMethod() {\n        MethodConfig method = new MethodConfig();\n        method.setOnreturnMethod(\"on-return-method\");\n        assertThat(method.getOnreturnMethod(), equalTo(\"on-return-method\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_RETURN_METHOD_ATTRIBUTE_KEY, \"on-return-method\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    // @Test\n    void testOnThrow() {\n        MethodConfig method = new MethodConfig();\n        method.setOnthrow(\"on-throw-object\");\n        assertThat(method.getOnthrow(), equalTo(\"on-throw-object\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_THROW_INSTANCE_ATTRIBUTE_KEY, \"on-throw-object\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    @Test\n    void testOnThrowMethod() {\n        MethodConfig method = new MethodConfig();\n        method.setOnthrowMethod(\"on-throw-method\");\n        assertThat(method.getOnthrowMethod(), equalTo(\"on-throw-method\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_THROW_METHOD_ATTRIBUTE_KEY, \"on-throw-method\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    // @Test\n    void testOnInvoke() {\n        MethodConfig method = new MethodConfig();\n        method.setOninvoke(\"on-invoke-object\");\n        assertThat(method.getOninvoke(), equalTo(\"on-invoke-object\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_INVOKE_INSTANCE_ATTRIBUTE_KEY, \"on-invoke-object\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    @Test\n    void testOnInvokeMethod() {\n        MethodConfig method = new MethodConfig();\n        method.setOninvokeMethod(\"on-invoke-method\");\n        assertThat(method.getOninvokeMethod(), equalTo(\"on-invoke-method\"));\n        Map<String, String> attributes = new HashMap<>();\n        MethodConfig.appendAttributes(attributes, method);\n        assertThat(attributes, hasEntry(ON_INVOKE_METHOD_ATTRIBUTE_KEY, \"on-invoke-method\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MethodConfig.appendParameters(parameters, method);\n        assertThat(parameters.size(), is(0));\n    }\n\n    @Test\n    void testReturn() {\n        MethodConfig method = new MethodConfig();\n        method.setReturn(true);\n        assertThat(method.isReturn(), is(true));\n    }\n\n    @Test\n    void testOverrideMethodConfigOfReference() {\n\n        String interfaceName = DemoService.class.getName();\n        SysProps.setProperty(\"dubbo.reference.\" + interfaceName + \".sayName.timeout\", \"1234\");\n        SysProps.setProperty(\"dubbo.reference.\" + interfaceName + \".sayName.sticky\", \"true\");\n        SysProps.setProperty(\"dubbo.reference.\" + interfaceName + \".sayName.parameters\", \"[{a:1},{b:2}]\");\n        SysProps.setProperty(\"dubbo.reference.\" + interfaceName + \".init\", \"false\");\n\n        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(interfaceName);\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setName(\"sayName\");\n        methodConfig.setTimeout(1000);\n        referenceConfig.setMethods(Arrays.asList(methodConfig));\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .reference(referenceConfig)\n                .initialize();\n\n        Map<String, String> params = new LinkedHashMap<>();\n        params.put(\"a\", \"1\");\n        params.put(\"b\", \"2\");\n\n        Assertions.assertEquals(1234, methodConfig.getTimeout());\n        Assertions.assertEquals(true, methodConfig.getSticky());\n        Assertions.assertEquals(params, methodConfig.getParameters());\n        Assertions.assertEquals(false, referenceConfig.isInit());\n    }\n\n    @Test\n    void testAddMethodConfigOfReference() {\n\n        String interfaceName = DemoService.class.getName();\n        SysProps.setProperty(\"dubbo.reference.\" + interfaceName + \".sayName.timeout\", \"1234\");\n        SysProps.setProperty(\"dubbo.reference.\" + interfaceName + \".sayName.sticky\", \"true\");\n        SysProps.setProperty(\"dubbo.reference.\" + interfaceName + \".sayName.parameters\", \"[{a:1},{b:2}]\");\n        SysProps.setProperty(\"dubbo.reference.\" + interfaceName + \".init\", \"false\");\n\n        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(interfaceName);\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .reference(referenceConfig)\n                .initialize();\n\n        List<MethodConfig> methodConfigs = referenceConfig.getMethods();\n        Assertions.assertEquals(1, methodConfigs.size());\n        MethodConfig methodConfig = methodConfigs.get(0);\n\n        Map<String, String> params = new LinkedHashMap<>();\n        params.put(\"a\", \"1\");\n        params.put(\"b\", \"2\");\n\n        Assertions.assertEquals(1234, methodConfig.getTimeout());\n        Assertions.assertEquals(true, methodConfig.getSticky());\n        Assertions.assertEquals(params, methodConfig.getParameters());\n        Assertions.assertEquals(false, referenceConfig.isInit());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testOverrideMethodConfigOfService() {\n\n        String interfaceName = DemoService.class.getName();\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".sayName.timeout\", \"1234\");\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".sayName.sticky\", \"true\");\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".sayName.parameters\", \"[{a:1},{b:2}]\");\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".group\", \"demo\");\n        SysProps.setProperty(\"dubbo.registry.address\", \"N/A\");\n\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(interfaceName);\n        serviceConfig.setRef(new DemoServiceImpl());\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setName(\"sayName\");\n        methodConfig.setTimeout(1000);\n        serviceConfig.setMethods(Collections.singletonList(methodConfig));\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .service(serviceConfig)\n                .initialize();\n\n        Map<String, String> params = new LinkedHashMap<>();\n        params.put(\"a\", \"1\");\n        params.put(\"b\", \"2\");\n\n        Assertions.assertEquals(1234, methodConfig.getTimeout());\n        Assertions.assertEquals(true, methodConfig.getSticky());\n        Assertions.assertEquals(params, methodConfig.getParameters());\n        Assertions.assertEquals(\"demo\", serviceConfig.getGroup());\n\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testAddMethodConfigOfService() {\n\n        String interfaceName = DemoService.class.getName();\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".sayName.timeout\", \"1234\");\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".sayName.sticky\", \"true\");\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".sayName.parameters\", \"[{a:1},{b:2}]\");\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".sayName.0.callback\", \"true\");\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".group\", \"demo\");\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".echo\", \"non-method-config\");\n        SysProps.setProperty(\"dubbo.registry.address\", \"N/A\");\n\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(interfaceName);\n        serviceConfig.setRef(new DemoServiceImpl());\n\n        Assertions.assertNull(serviceConfig.getMethods());\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .service(serviceConfig)\n                .initialize();\n\n        List<MethodConfig> methodConfigs = serviceConfig.getMethods();\n        Assertions.assertEquals(1, methodConfigs.size());\n        MethodConfig methodConfig = methodConfigs.get(0);\n\n        List<ArgumentConfig> arguments = methodConfig.getArguments();\n        Assertions.assertEquals(1, arguments.size());\n        ArgumentConfig argumentConfig = arguments.get(0);\n\n        Map<String, String> params = new LinkedHashMap<>();\n        params.put(\"a\", \"1\");\n        params.put(\"b\", \"2\");\n\n        Assertions.assertEquals(\"demo\", serviceConfig.getGroup());\n        Assertions.assertEquals(params, methodConfig.getParameters());\n        Assertions.assertEquals(1234, methodConfig.getTimeout());\n        Assertions.assertEquals(true, methodConfig.getSticky());\n        Assertions.assertEquals(0, argumentConfig.getIndex());\n        Assertions.assertEquals(true, argumentConfig.isCallback());\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testVerifyMethodConfigOfService() {\n\n        String interfaceName = DemoService.class.getName();\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".sayHello.timeout\", \"1234\");\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".group\", \"demo\");\n        SysProps.setProperty(\"dubbo.registry.address\", \"N/A\");\n\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(interfaceName);\n        serviceConfig.setRef(new DemoServiceImpl());\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setName(\"sayHello\");\n        methodConfig.setTimeout(1000);\n        serviceConfig.setMethods(Collections.singletonList(methodConfig));\n\n        try {\n            DubboBootstrap.getInstance()\n                    .application(\"demo-app\")\n                    .service(serviceConfig)\n                    .initialize();\n            Assertions.fail(\"Method config verification should failed\");\n        } catch (Exception e) {\n            // ignore\n            Throwable cause = e.getCause();\n            Assertions.assertEquals(IllegalStateException.class, cause.getClass());\n            Assertions.assertTrue(cause.getMessage().contains(\"not found method\"), cause.toString());\n        } finally {\n            DubboBootstrap.getInstance().destroy();\n        }\n    }\n\n    @Test\n    void testIgnoreInvalidMethodConfigOfService() {\n\n        String interfaceName = DemoService.class.getName();\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".sayHello.timeout\", \"1234\");\n        SysProps.setProperty(\"dubbo.service.\" + interfaceName + \".sayName.timeout\", \"1234\");\n        SysProps.setProperty(\"dubbo.registry.address\", \"N/A\");\n        SysProps.setProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_INVALID_METHOD_CONFIG, \"true\");\n\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(interfaceName);\n        serviceConfig.setRef(new DemoServiceImpl());\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setName(\"sayHello\");\n        methodConfig.setTimeout(1000);\n        serviceConfig.setMethods(Collections.singletonList(methodConfig));\n\n        DubboBootstrap.getInstance()\n                .application(\"demo-app\")\n                .service(serviceConfig)\n                .initialize();\n\n        // expect sayHello method config will be ignored, and sayName method config will be created.\n        Assertions.assertEquals(1, serviceConfig.getMethods().size());\n        Assertions.assertEquals(\"sayName\", serviceConfig.getMethods().get(0).getName());\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    @Test\n    void testMetaData() {\n        MethodConfig methodConfig = new MethodConfig();\n        Map<String, String> metaData = methodConfig.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"Expect empty metadata but found: \" + metaData);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MetricsConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.config.nested.AggregationConfig;\nimport org.apache.dubbo.config.nested.HistogramConfig;\nimport org.apache.dubbo.config.nested.PrometheusConfig;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass MetricsConfigTest {\n\n    @Test\n    void testToUrl() {\n        MetricsConfig metrics = new MetricsConfig();\n        metrics.setProtocol(PROTOCOL_PROMETHEUS);\n\n        PrometheusConfig prometheus = new PrometheusConfig();\n        PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();\n        PrometheusConfig.Pushgateway pushgateway = new PrometheusConfig.Pushgateway();\n\n        exporter.setEnabled(true);\n        pushgateway.setEnabled(true);\n        prometheus.setExporter(exporter);\n        prometheus.setPushgateway(pushgateway);\n        metrics.setPrometheus(prometheus);\n\n        AggregationConfig aggregation = new AggregationConfig();\n        aggregation.setEnabled(true);\n        metrics.setAggregation(aggregation);\n\n        HistogramConfig histogram = new HistogramConfig();\n        histogram.setEnabled(true);\n        metrics.setHistogram(histogram);\n\n        URL url = metrics.toUrl();\n\n        assertThat(url.getProtocol(), equalTo(PROTOCOL_PROMETHEUS));\n        assertThat(url.getAddress(), equalTo(\"localhost:9090\"));\n        assertThat(url.getHost(), equalTo(\"localhost\"));\n        assertThat(url.getPort(), equalTo(9090));\n        assertThat(url.getParameter(\"prometheus.exporter.enabled\"), equalTo(\"true\"));\n        assertThat(url.getParameter(\"prometheus.pushgateway.enabled\"), equalTo(\"true\"));\n        assertThat(url.getParameter(\"aggregation.enabled\"), equalTo(\"true\"));\n        assertThat(url.getParameter(\"histogram.enabled\"), equalTo(\"true\"));\n    }\n\n    @Test\n    void testProtocol() {\n        MetricsConfig metrics = new MetricsConfig();\n        metrics.setProtocol(PROTOCOL_PROMETHEUS);\n        assertThat(metrics.getProtocol(), equalTo(PROTOCOL_PROMETHEUS));\n    }\n\n    @Test\n    void testPrometheus() {\n        MetricsConfig metrics = new MetricsConfig();\n\n        PrometheusConfig prometheus = new PrometheusConfig();\n        PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();\n        PrometheusConfig.Pushgateway pushgateway = new PrometheusConfig.Pushgateway();\n\n        exporter.setEnabled(true);\n        exporter.setEnableHttpServiceDiscovery(true);\n        exporter.setHttpServiceDiscoveryUrl(\"localhost:8080\");\n        prometheus.setExporter(exporter);\n\n        pushgateway.setEnabled(true);\n        pushgateway.setBaseUrl(\"localhost:9091\");\n        pushgateway.setUsername(\"username\");\n        pushgateway.setPassword(\"password\");\n        pushgateway.setJob(\"job\");\n        pushgateway.setPushInterval(30);\n        prometheus.setPushgateway(pushgateway);\n\n        metrics.setPrometheus(prometheus);\n\n        assertThat(metrics.getPrometheus().getExporter().getEnabled(), equalTo(true));\n        assertThat(metrics.getPrometheus().getExporter().getEnableHttpServiceDiscovery(), equalTo(true));\n        assertThat(metrics.getPrometheus().getExporter().getHttpServiceDiscoveryUrl(), equalTo(\"localhost:8080\"));\n        assertThat(metrics.getPrometheus().getPushgateway().getEnabled(), equalTo(true));\n        assertThat(metrics.getPrometheus().getPushgateway().getBaseUrl(), equalTo(\"localhost:9091\"));\n        assertThat(metrics.getPrometheus().getPushgateway().getUsername(), equalTo(\"username\"));\n        assertThat(metrics.getPrometheus().getPushgateway().getPassword(), equalTo(\"password\"));\n        assertThat(metrics.getPrometheus().getPushgateway().getJob(), equalTo(\"job\"));\n        assertThat(metrics.getPrometheus().getPushgateway().getPushInterval(), equalTo(30));\n    }\n\n    @Test\n    void testAggregation() {\n        MetricsConfig metrics = new MetricsConfig();\n\n        AggregationConfig aggregation = new AggregationConfig();\n        aggregation.setEnabled(true);\n        aggregation.setBucketNum(5);\n        aggregation.setTimeWindowSeconds(120);\n        metrics.setAggregation(aggregation);\n\n        assertThat(metrics.getAggregation().getEnabled(), equalTo(true));\n        assertThat(metrics.getAggregation().getBucketNum(), equalTo(5));\n        assertThat(metrics.getAggregation().getTimeWindowSeconds(), equalTo(120));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ModuleConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.contains;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.sameInstance;\n\nclass ModuleConfigTest {\n\n    @Test\n    void testName2() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setName(\"module-name\");\n        assertThat(module.getName(), equalTo(\"module-name\"));\n        assertThat(module.getId(), equalTo(null));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ModuleConfig.appendParameters(parameters, module);\n        assertThat(parameters, hasEntry(\"module\", \"module-name\"));\n    }\n\n    @Test\n    void testVersion() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setName(\"module-name\");\n        module.setVersion(\"1.0.0\");\n        assertThat(module.getVersion(), equalTo(\"1.0.0\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        ModuleConfig.appendParameters(parameters, module);\n        assertThat(parameters, hasEntry(\"module.version\", \"1.0.0\"));\n    }\n\n    @Test\n    void testOwner() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setOwner(\"owner\");\n        assertThat(module.getOwner(), equalTo(\"owner\"));\n    }\n\n    @Test\n    void testOrganization() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setOrganization(\"org\");\n        assertThat(module.getOrganization(), equalTo(\"org\"));\n    }\n\n    @Test\n    void testRegistry() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        RegistryConfig registry = new RegistryConfig();\n        module.setRegistry(registry);\n        assertThat(module.getRegistry(), sameInstance(registry));\n    }\n\n    @Test\n    void testRegistries() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        RegistryConfig registry = new RegistryConfig();\n        module.setRegistries(Collections.singletonList(registry));\n        assertThat(module.getRegistries(), Matchers.<RegistryConfig>hasSize(1));\n        assertThat(module.getRegistries(), contains(registry));\n    }\n\n    @Test\n    void testMonitor() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setMonitor(\"monitor-addr1\");\n        assertThat(module.getMonitor().getAddress(), equalTo(\"monitor-addr1\"));\n        module.setMonitor(new MonitorConfig(\"monitor-addr2\"));\n        assertThat(module.getMonitor().getAddress(), equalTo(\"monitor-addr2\"));\n    }\n\n    @Test\n    void testDefault() throws Exception {\n        ModuleConfig module = new ModuleConfig();\n        module.setDefault(true);\n        assertThat(module.isDefault(), is(true));\n    }\n\n    @Test\n    void testMetaData() {\n        MonitorConfig config = new MonitorConfig();\n        Map<String, String> metaData = config.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"Expect empty metadata but found: \" + metaData);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MonitorConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.is;\n\nclass MonitorConfigTest {\n    @Test\n    void testAddress() throws Exception {\n        MonitorConfig monitor = new MonitorConfig();\n        monitor.setAddress(\"monitor-addr\");\n        assertThat(monitor.getAddress(), equalTo(\"monitor-addr\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MonitorConfig.appendParameters(parameters, monitor);\n        assertThat(parameters.isEmpty(), is(true));\n    }\n\n    @Test\n    void testProtocol() throws Exception {\n        MonitorConfig monitor = new MonitorConfig();\n        monitor.setProtocol(\"protocol\");\n        assertThat(monitor.getProtocol(), equalTo(\"protocol\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MonitorConfig.appendParameters(parameters, monitor);\n        assertThat(parameters.isEmpty(), is(true));\n    }\n\n    @Test\n    void testUsername() throws Exception {\n        MonitorConfig monitor = new MonitorConfig();\n        monitor.setUsername(\"user\");\n        assertThat(monitor.getUsername(), equalTo(\"user\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MonitorConfig.appendParameters(parameters, monitor);\n        assertThat(parameters.isEmpty(), is(true));\n    }\n\n    @Test\n    void testPassword() throws Exception {\n        MonitorConfig monitor = new MonitorConfig();\n        monitor.setPassword(\"secret\");\n        assertThat(monitor.getPassword(), equalTo(\"secret\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        MonitorConfig.appendParameters(parameters, monitor);\n        assertThat(parameters.isEmpty(), is(true));\n    }\n\n    @Test\n    void testGroup() throws Exception {\n        MonitorConfig monitor = new MonitorConfig();\n        monitor.setGroup(\"group\");\n        assertThat(monitor.getGroup(), equalTo(\"group\"));\n    }\n\n    @Test\n    void testVersion() throws Exception {\n        MonitorConfig monitor = new MonitorConfig();\n        monitor.setVersion(\"1.0.0\");\n        assertThat(monitor.getVersion(), equalTo(\"1.0.0\"));\n    }\n\n    @Test\n    void testParameters() throws Exception {\n        MonitorConfig monitor = new MonitorConfig();\n        Map<String, String> parameters = Collections.singletonMap(\"k1\", \"v1\");\n        monitor.setParameters(parameters);\n        assertThat(monitor.getParameters(), hasEntry(\"k1\", \"v1\"));\n    }\n\n    @Test\n    void testDefault() throws Exception {\n        MonitorConfig monitor = new MonitorConfig();\n        monitor.setDefault(true);\n        assertThat(monitor.isDefault(), is(true));\n    }\n\n    @Test\n    void testInterval() throws Exception {\n        MonitorConfig monitor = new MonitorConfig();\n        monitor.setInterval(\"100\");\n        assertThat(monitor.getInterval(), equalTo(\"100\"));\n    }\n\n    @Test\n    void testMetaData() {\n        MonitorConfig config = new MonitorConfig();\n        Map<String, String> metaData = config.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"Expect empty metadata but found: \" + metaData);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ProtocolConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigManager;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass ProtocolConfigTest {\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void afterEach() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testName() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        String protocolName = \"xprotocol\";\n        protocol.setName(protocolName);\n        Map<String, String> parameters = new HashMap<>();\n        ProtocolConfig.appendParameters(parameters, protocol);\n        assertThat(protocol.getName(), equalTo(protocolName));\n        assertThat(protocol.getId(), equalTo(null));\n        assertThat(parameters.isEmpty(), is(true));\n    }\n\n    @Test\n    void testHost() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setHost(\"host\");\n        Map<String, String> parameters = new HashMap<String, String>();\n        ProtocolConfig.appendParameters(parameters, protocol);\n        assertThat(protocol.getHost(), equalTo(\"host\"));\n        assertThat(parameters.isEmpty(), is(true));\n    }\n\n    @Test\n    void testPort() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        int port = NetUtils.getAvailablePort();\n        protocol.setPort(port);\n        Map<String, String> parameters = new HashMap<>();\n        ProtocolConfig.appendParameters(parameters, protocol);\n        assertThat(protocol.getPort(), equalTo(port));\n        assertThat(parameters.isEmpty(), is(true));\n    }\n\n    @Test\n    void testPath() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setContextpath(\"context-path\");\n        Map<String, String> parameters = new HashMap<>();\n        ProtocolConfig.appendParameters(parameters, protocol);\n        assertThat(protocol.getPath(), equalTo(\"context-path\"));\n        assertThat(protocol.getContextpath(), equalTo(\"context-path\"));\n        assertThat(parameters.isEmpty(), is(true));\n        protocol.setPath(\"path\");\n        assertThat(protocol.getPath(), equalTo(\"path\"));\n        assertThat(protocol.getContextpath(), equalTo(\"path\"));\n    }\n\n    @Test\n    void testCorethreads() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setCorethreads(10);\n        assertThat(protocol.getCorethreads(), is(10));\n    }\n\n    @Test\n    void testThreads() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setThreads(10);\n        assertThat(protocol.getThreads(), is(10));\n    }\n\n    @Test\n    void testIothreads() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setIothreads(10);\n        assertThat(protocol.getIothreads(), is(10));\n    }\n\n    @Test\n    void testQueues() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setQueues(10);\n        assertThat(protocol.getQueues(), is(10));\n    }\n\n    @Test\n    void testAccepts() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setAccepts(10);\n        assertThat(protocol.getAccepts(), is(10));\n    }\n\n    @Test\n    void testCodec() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setName(\"dubbo\");\n        protocol.setCodec(\"mockcodec\");\n        assertThat(protocol.getCodec(), equalTo(\"mockcodec\"));\n    }\n\n    @Test\n    void testAccesslog() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setAccesslog(\"access.log\");\n        assertThat(protocol.getAccesslog(), equalTo(\"access.log\"));\n    }\n\n    @Test\n    void testTelnet() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setTelnet(\"mocktelnethandler\");\n        assertThat(protocol.getTelnet(), equalTo(\"mocktelnethandler\"));\n    }\n\n    @Test\n    void testRegister() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setRegister(true);\n        assertThat(protocol.isRegister(), is(true));\n    }\n\n    @Test\n    void testTransporter() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setTransporter(\"mocktransporter\");\n        assertThat(protocol.getTransporter(), equalTo(\"mocktransporter\"));\n    }\n\n    @Test\n    void testExchanger() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setExchanger(\"mockexchanger\");\n        assertThat(protocol.getExchanger(), equalTo(\"mockexchanger\"));\n    }\n\n    @Test\n    void testDispatcher() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setDispatcher(\"mockdispatcher\");\n        assertThat(protocol.getDispatcher(), equalTo(\"mockdispatcher\"));\n    }\n\n    @Test\n    void testNetworker() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setNetworker(\"networker\");\n        assertThat(protocol.getNetworker(), equalTo(\"networker\"));\n    }\n\n    @Test\n    void testParameters() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setParameters(Collections.singletonMap(\"k1\", \"v1\"));\n        assertThat(protocol.getParameters(), hasEntry(\"k1\", \"v1\"));\n    }\n\n    @Test\n    void testDefault() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setDefault(true);\n        assertThat(protocol.isDefault(), is(true));\n    }\n\n    @Test\n    void testKeepAlive() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setKeepAlive(true);\n        assertThat(protocol.getKeepAlive(), is(true));\n    }\n\n    @Test\n    void testOptimizer() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setOptimizer(\"optimizer\");\n        assertThat(protocol.getOptimizer(), equalTo(\"optimizer\"));\n    }\n\n    @Test\n    void testExtension() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setExtension(\"extension\");\n        assertThat(protocol.getExtension(), equalTo(\"extension\"));\n    }\n\n    @Test\n    void testMetaData() {\n        ProtocolConfig config = new ProtocolConfig();\n        Map<String, String> metaData = config.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"actual: \" + metaData);\n    }\n\n    @Test\n    void testOverrideEmptyConfig() {\n        int port = NetUtils.getAvailablePort();\n        // dubbo.protocol.name=rest\n        // dubbo.protocol.port=port\n        SysProps.setProperty(\"dubbo.protocol.name\", \"rest\");\n        SysProps.setProperty(\"dubbo.protocol.port\", String.valueOf(port));\n\n        try {\n            ProtocolConfig protocolConfig = new ProtocolConfig();\n\n            DubboBootstrap.getInstance()\n                    .application(\"test-app\")\n                    .protocol(protocolConfig)\n                    .initialize();\n\n            Assertions.assertEquals(\"rest\", protocolConfig.getName());\n            Assertions.assertEquals(port, protocolConfig.getPort());\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testOverrideConfigByName() {\n        int port = NetUtils.getAvailablePort();\n        SysProps.setProperty(\"dubbo.protocols.rest.port\", String.valueOf(port));\n\n        try {\n            ProtocolConfig protocolConfig = new ProtocolConfig();\n            protocolConfig.setName(\"rest\");\n\n            DubboBootstrap.getInstance()\n                    .application(\"test-app\")\n                    .protocol(protocolConfig)\n                    .initialize();\n\n            Assertions.assertEquals(\"rest\", protocolConfig.getName());\n            Assertions.assertEquals(port, protocolConfig.getPort());\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testOverrideConfigById() {\n        int port = NetUtils.getAvailablePort();\n        SysProps.setProperty(\"dubbo.protocols.rest1.name\", \"rest\");\n        SysProps.setProperty(\"dubbo.protocols.rest1.port\", String.valueOf(port));\n\n        try {\n            ProtocolConfig protocolConfig = new ProtocolConfig();\n            protocolConfig.setName(\"xxx\");\n            protocolConfig.setId(\"rest1\");\n\n            DubboBootstrap.getInstance()\n                    .application(\"test-app\")\n                    .protocol(protocolConfig)\n                    .initialize();\n\n            Assertions.assertEquals(\"rest\", protocolConfig.getName());\n            Assertions.assertEquals(port, protocolConfig.getPort());\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testCreateConfigFromPropsWithId() {\n        int port1 = NetUtils.getAvailablePort();\n        int port2 = NetUtils.getAvailablePort();\n        SysProps.setProperty(\"dubbo.protocols.rest1.name\", \"rest\");\n        SysProps.setProperty(\"dubbo.protocols.rest1.port\", String.valueOf(port1));\n        SysProps.setProperty(\"dubbo.protocol.name\", \"dubbo\"); // ignore\n        SysProps.setProperty(\"dubbo.protocol.port\", String.valueOf(port2));\n\n        try {\n\n            DubboBootstrap bootstrap = DubboBootstrap.getInstance();\n            bootstrap.application(\"test-app\").initialize();\n\n            ConfigManager configManager = bootstrap.getConfigManager();\n            Collection<ProtocolConfig> protocols = configManager.getProtocols();\n            Assertions.assertEquals(1, protocols.size());\n\n            ProtocolConfig protocol = configManager.getProtocol(\"rest1\").get();\n\n            Assertions.assertEquals(\"rest\", protocol.getName());\n            Assertions.assertEquals(port1, protocol.getPort());\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testCreateConfigFromPropsWithName() {\n        int port1 = NetUtils.getAvailablePort();\n        int port2 = NetUtils.getAvailablePort();\n        SysProps.setProperty(\"dubbo.protocols.rest.port\", String.valueOf(port1));\n        SysProps.setProperty(\"dubbo.protocol.name\", \"dubbo\"); // ignore\n        SysProps.setProperty(\"dubbo.protocol.port\", String.valueOf(port2));\n\n        try {\n\n            DubboBootstrap bootstrap = DubboBootstrap.getInstance();\n            bootstrap.application(\"test-app\").initialize();\n\n            ConfigManager configManager = bootstrap.getConfigManager();\n            Collection<ProtocolConfig> protocols = configManager.getProtocols();\n            Assertions.assertEquals(1, protocols.size());\n\n            ProtocolConfig protocol = configManager.getProtocol(\"rest\").get();\n\n            Assertions.assertEquals(\"rest\", protocol.getName());\n            Assertions.assertEquals(port1, protocol.getPort());\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testCreateDefaultConfigFromProps() {\n        int port = NetUtils.getAvailablePort();\n        SysProps.setProperty(\"dubbo.protocol.name\", \"rest\");\n        SysProps.setProperty(\"dubbo.protocol.port\", String.valueOf(port));\n        String protocolId = \"rest-protocol\";\n        SysProps.setProperty(\"dubbo.protocol.id\", protocolId); // Allow override config id from props\n\n        try {\n\n            DubboBootstrap bootstrap = DubboBootstrap.getInstance();\n            bootstrap.application(\"test-app\").initialize();\n\n            ConfigManager configManager = bootstrap.getConfigManager();\n            Collection<ProtocolConfig> protocols = configManager.getProtocols();\n            Assertions.assertEquals(1, protocols.size());\n\n            ProtocolConfig protocol = configManager.getProtocol(\"rest\").get();\n            Assertions.assertEquals(\"rest\", protocol.getName());\n            Assertions.assertEquals(port, protocol.getPort());\n            Assertions.assertEquals(protocolId, protocol.getId());\n\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testPreferSerializationDefault1() {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        assertNull(protocolConfig.getPreferSerialization());\n\n        protocolConfig.checkDefault();\n        assertThat(protocolConfig.getPreferSerialization(), equalTo(\"hessian2,fastjson2\"));\n\n        protocolConfig = new ProtocolConfig();\n        protocolConfig.setSerialization(\"x-serialization\");\n        assertNull(protocolConfig.getPreferSerialization());\n\n        protocolConfig.checkDefault();\n        assertThat(protocolConfig.getPreferSerialization(), equalTo(\"x-serialization\"));\n    }\n\n    @Test\n    void testPreferSerializationDefault2() {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        assertNull(protocolConfig.getPreferSerialization());\n\n        protocolConfig.refresh();\n        assertThat(protocolConfig.getPreferSerialization(), equalTo(\"hessian2,fastjson2\"));\n\n        protocolConfig = new ProtocolConfig();\n        protocolConfig.setSerialization(\"x-serialization\");\n        assertNull(protocolConfig.getPreferSerialization());\n\n        protocolConfig.refresh();\n        assertThat(protocolConfig.getPreferSerialization(), equalTo(\"x-serialization\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ProviderConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.hasKey;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.not;\n\nclass ProviderConfigTest {\n\n    @Test\n    void testProtocol() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setProtocol(\"protocol\");\n        assertThat(provider.getProtocol().getName(), equalTo(\"protocol\"));\n    }\n\n    @Test\n    void testDefault() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setDefault(true);\n        Map<String, String> parameters = new HashMap<>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.isDefault(), is(true));\n        assertThat(parameters, not(hasKey(\"default\")));\n    }\n\n    @Test\n    void testHost() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setHost(\"demo-host\");\n        Map<String, String> parameters = new HashMap<>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.getHost(), equalTo(\"demo-host\"));\n        assertThat(parameters, not(hasKey(\"host\")));\n    }\n\n    @Test\n    void testPort() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setPort(8080);\n        Map<String, String> parameters = new HashMap<>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.getPort(), is(8080));\n        assertThat(parameters, not(hasKey(\"port\")));\n    }\n\n    @Test\n    void testPath() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setPath(\"/path\");\n        Map<String, String> parameters = new HashMap<>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.getPath(), equalTo(\"/path\"));\n        assertThat(provider.getContextpath(), equalTo(\"/path\"));\n        assertThat(parameters, not(hasKey(\"path\")));\n    }\n\n    @Test\n    void testContextPath() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setContextpath(\"/context-path\");\n        Map<String, String> parameters = new HashMap<>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.getContextpath(), equalTo(\"/context-path\"));\n        assertThat(parameters, not(hasKey(\"/context-path\")));\n    }\n\n    @Test\n    void testThreadpool() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setThreadpool(\"mockthreadpool\");\n        assertThat(provider.getThreadpool(), equalTo(\"mockthreadpool\"));\n    }\n\n    @Test\n    void testThreadname() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setThreadname(\"test-thread-pool\");\n        assertThat(provider.getThreadname(), equalTo(\"test-thread-pool\"));\n    }\n\n    @Test\n    void testThreads() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setThreads(10);\n        assertThat(provider.getThreads(), is(10));\n    }\n\n    @Test\n    void testIothreads() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setIothreads(10);\n        assertThat(provider.getIothreads(), is(10));\n    }\n\n    @Test\n    void testAlive() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setAlive(10);\n        assertThat(provider.getAlive(), is(10));\n    }\n\n    @Test\n    void testQueues() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setQueues(10);\n        assertThat(provider.getQueues(), is(10));\n    }\n\n    @Test\n    void testAccepts() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setAccepts(10);\n        assertThat(provider.getAccepts(), is(10));\n    }\n\n    @Test\n    void testCharset() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setCharset(\"utf-8\");\n        assertThat(provider.getCharset(), equalTo(\"utf-8\"));\n    }\n\n    @Test\n    void testPayload() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setPayload(10);\n        assertThat(provider.getPayload(), is(10));\n    }\n\n    @Test\n    void testBuffer() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setBuffer(10);\n        assertThat(provider.getBuffer(), is(10));\n    }\n\n    @Test\n    void testServer() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setServer(\"demo-server\");\n        assertThat(provider.getServer(), equalTo(\"demo-server\"));\n    }\n\n    @Test\n    void testClient() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setClient(\"client\");\n        assertThat(provider.getClient(), equalTo(\"client\"));\n    }\n\n    @Test\n    void testTelnet() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setTelnet(\"mocktelnethandler\");\n        assertThat(provider.getTelnet(), equalTo(\"mocktelnethandler\"));\n    }\n\n    @Test\n    void testPrompt() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setPrompt(\"#\");\n        Map<String, String> parameters = new HashMap<>();\n        ProviderConfig.appendParameters(parameters, provider);\n        assertThat(provider.getPrompt(), equalTo(\"#\"));\n        assertThat(parameters, hasEntry(\"prompt\", \"%23\"));\n    }\n\n    @Test\n    void testStatus() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setStatus(\"mockstatuschecker\");\n        assertThat(provider.getStatus(), equalTo(\"mockstatuschecker\"));\n    }\n\n    @Test\n    void testTransporter() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setTransporter(\"mocktransporter\");\n        assertThat(provider.getTransporter(), equalTo(\"mocktransporter\"));\n    }\n\n    @Test\n    void testExchanger() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setExchanger(\"mockexchanger\");\n        assertThat(provider.getExchanger(), equalTo(\"mockexchanger\"));\n    }\n\n    @Test\n    void testDispatcher() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setDispatcher(\"mockdispatcher\");\n        assertThat(provider.getDispatcher(), equalTo(\"mockdispatcher\"));\n    }\n\n    @Test\n    void testNetworker() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setNetworker(\"networker\");\n        assertThat(provider.getNetworker(), equalTo(\"networker\"));\n    }\n\n    @Test\n    void testWait() {\n        ProviderConfig provider = new ProviderConfig();\n        provider.setWait(10);\n        assertThat(provider.getWait(), equalTo(10));\n    }\n\n    @Test\n    void testMetaData() {\n        ProviderConfig config = new ProviderConfig();\n        Map<String, String> metaData = config.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"Expect empty metadata but found: \" + metaData);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.compiler.support.CtClassBuilder;\nimport org.apache.dubbo.common.compiler.support.JavassistCompiler;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.annotation.Argument;\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.api.DemoService;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.config.provider.impl.DemoServiceImpl;\nimport org.apache.dubbo.registry.client.migration.MigrationInvoker;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;\nimport org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.ScopeClusterInvoker;\nimport org.apache.dubbo.rpc.listener.ListenerInvokerWrapper;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\nimport org.apache.dubbo.rpc.protocol.ReferenceCountInvokerWrapper;\nimport org.apache.dubbo.rpc.protocol.injvm.InjvmInvoker;\nimport org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.lang.reflect.Constructor;\nimport java.net.URLDecoder;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.stream.Collectors;\nimport javassist.CannotCompileException;\nimport javassist.CtClass;\nimport javassist.NotFoundException;\n\nimport demo.MultiClassLoaderService;\nimport demo.MultiClassLoaderServiceImpl;\nimport demo.MultiClassLoaderServiceRequest;\nimport demo.MultiClassLoaderServiceResult;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.mockito.Mockito;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXPORTER_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.LIVENESS_PROBE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_SERVICE_PORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_SERVICE_PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.READINESS_PROBE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFER_ASYNC_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFER_BACKGROUND_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFER_THREAD_NUM_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED;\nimport static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.STARTUP_PROBE;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.URL_MERGE_PROCESSOR_KEY;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;\nimport static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;\nimport static org.apache.dubbo.rpc.Constants.DEFAULT_STUB_EVENT;\nimport static org.apache.dubbo.rpc.Constants.LOCAL_KEY;\nimport static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;\nimport static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;\nimport static org.apache.dubbo.rpc.cluster.Constants.PEER_KEY;\n\nclass ReferenceConfigTest {\n    private static final Logger logger = LoggerFactory.getLogger(ReferenceConfigTest.class);\n    private static String zkUrl1;\n    private static String zkUrl2;\n    private static String registryUrl1;\n\n    @BeforeAll\n    public static void beforeAll() {\n        int zkServerPort1 = 2181;\n        int zkServerPort2 = 2182;\n        zkUrl1 = \"zookeeper://localhost:\" + zkServerPort1;\n        zkUrl2 = \"zookeeper://localhost:\" + zkServerPort2;\n        registryUrl1 = \"registry://localhost:\" + zkServerPort1 + \"?registry=zookeeper\";\n    }\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        DubboBootstrap.reset();\n        FrameworkModel.destroyAll();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n        ApplicationModel.defaultModel().getApplicationConfigManager();\n        DubboBootstrap.getInstance();\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        DubboBootstrap.reset();\n        FrameworkModel.destroyAll();\n        SysProps.clear();\n        Mockito.framework().clearInlineMocks();\n    }\n\n    /**\n     * Test whether the configuration required for the aggregation service reference meets expectations\n     */\n    @Test\n    void testAppendConfig() {\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n        applicationConfig.setVersion(\"v1\");\n        applicationConfig.setOwner(\"owner1\");\n        applicationConfig.setOrganization(\"bu1\");\n        applicationConfig.setArchitecture(\"architecture1\");\n        applicationConfig.setEnvironment(\"test\");\n        applicationConfig.setCompiler(\"javassist\");\n        applicationConfig.setLogger(\"log4j2\");\n        applicationConfig.setDumpDirectory(\"/\");\n        applicationConfig.setQosEnable(false);\n        applicationConfig.setQosHost(\"127.0.0.1\");\n        applicationConfig.setQosPort(77777);\n        applicationConfig.setQosAcceptForeignIp(false);\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(\"key1\", \"value1\");\n        parameters.put(\"key2\", \"value2\");\n        applicationConfig.setParameters(parameters);\n        applicationConfig.setShutwait(\"5\");\n        applicationConfig.setMetadataType(\"local\");\n        applicationConfig.setRegisterConsumer(false);\n        applicationConfig.setRepository(\"repository1\");\n        applicationConfig.setEnableFileCache(false);\n        applicationConfig.setProtocol(\"dubbo\");\n        applicationConfig.setMetadataServicePort(88888);\n        applicationConfig.setMetadataServiceProtocol(\"tri\");\n        applicationConfig.setLivenessProbe(\"livenessProbe\");\n        applicationConfig.setReadinessProbe(\"readinessProb\");\n        applicationConfig.setStartupProbe(\"startupProbe\");\n\n        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setClient(\"netty\");\n        referenceConfig.setGeneric(Boolean.FALSE.toString());\n        referenceConfig.setProtocol(\"dubbo\");\n        referenceConfig.setInit(true);\n        referenceConfig.setLazy(false);\n        referenceConfig.setInjvm(false);\n        referenceConfig.setReconnect(\"reconnect\");\n        referenceConfig.setSticky(false);\n        referenceConfig.setStub(DEFAULT_STUB_EVENT);\n        referenceConfig.setRouter(\"default\");\n        referenceConfig.setReferAsync(true);\n\n        MonitorConfig monitorConfig = new MonitorConfig();\n        applicationConfig.setMonitor(monitorConfig);\n\n        ModuleConfig moduleConfig = new ModuleConfig();\n        moduleConfig.setMonitor(\"default\");\n        moduleConfig.setName(\"module1\");\n        moduleConfig.setOrganization(\"application1\");\n        moduleConfig.setVersion(\"v1\");\n        moduleConfig.setOwner(\"owner1\");\n\n        ConsumerConfig consumerConfig = new ConsumerConfig();\n        consumerConfig.setClient(\"netty\");\n        consumerConfig.setThreadpool(\"fixed\");\n        consumerConfig.setCorethreads(200);\n        consumerConfig.setQueues(500);\n        consumerConfig.setThreads(300);\n        consumerConfig.setShareconnections(10);\n        consumerConfig.setUrlMergeProcessor(\"default\");\n        consumerConfig.setReferThreadNum(20);\n        consumerConfig.setReferBackground(false);\n        referenceConfig.setConsumer(consumerConfig);\n\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setName(\"sayName\");\n        methodConfig.setStat(1);\n        methodConfig.setRetries(0);\n        methodConfig.setExecutes(10);\n        methodConfig.setDeprecated(false);\n        methodConfig.setSticky(false);\n        methodConfig.setReturn(false);\n        methodConfig.setService(\"service\");\n        methodConfig.setServiceId(DemoService.class.getName());\n        methodConfig.setParentPrefix(\"demo\");\n\n        referenceConfig.setMethods(Collections.singletonList(methodConfig));\n\n        referenceConfig.setInterface(DemoService.class);\n        referenceConfig.getInterfaceClass();\n        referenceConfig.setCheck(false);\n        RegistryConfig registry = new RegistryConfig();\n        registry.setAddress(zkUrl1);\n        applicationConfig.setRegistries(Collections.singletonList(registry));\n        applicationConfig.setRegistryIds(registry.getId());\n        moduleConfig.setRegistries(Collections.singletonList(registry));\n\n        referenceConfig.setRegistry(registry);\n\n        DubboBootstrap dubboBootstrap = DubboBootstrap.newInstance(FrameworkModel.defaultModel());\n        dubboBootstrap\n                .application(applicationConfig)\n                .reference(referenceConfig)\n                .registry(registry)\n                .module(moduleConfig)\n                .initialize();\n\n        referenceConfig.init();\n\n        ServiceMetadata serviceMetadata = referenceConfig.getServiceMetadata();\n\n        // verify additional side parameter\n        Assertions.assertEquals(CONSUMER_SIDE, serviceMetadata.getAttachments().get(SIDE_KEY));\n\n        // verify additional interface parameter\n        Assertions.assertEquals(\n                DemoService.class.getName(), serviceMetadata.getAttachments().get(INTERFACE_KEY));\n\n        // verify additional metadata-type parameter\n        Assertions.assertEquals(\n                DEFAULT_METADATA_STORAGE_TYPE, serviceMetadata.getAttachments().get(METADATA_KEY));\n\n        // verify additional register.ip parameter\n        Assertions.assertEquals(\n                NetUtils.getLocalHost(), serviceMetadata.getAttachments().get(REGISTER_IP_KEY));\n\n        // verify additional runtime parameters\n        Assertions.assertEquals(\n                Version.getProtocolVersion(), serviceMetadata.getAttachments().get(DUBBO_VERSION_KEY));\n        Assertions.assertEquals(\n                Version.getVersion(), serviceMetadata.getAttachments().get(RELEASE_KEY));\n        Assertions.assertTrue(serviceMetadata.getAttachments().containsKey(TIMESTAMP_KEY));\n        Assertions.assertEquals(\n                String.valueOf(ConfigUtils.getPid()),\n                serviceMetadata.getAttachments().get(PID_KEY));\n\n        // verify additional application config\n        Assertions.assertEquals(\n                applicationConfig.getName(), serviceMetadata.getAttachments().get(APPLICATION_KEY));\n        Assertions.assertEquals(\n                applicationConfig.getOwner(), serviceMetadata.getAttachments().get(\"owner\"));\n        Assertions.assertEquals(\n                applicationConfig.getVersion(), serviceMetadata.getAttachments().get(APPLICATION_VERSION_KEY));\n        Assertions.assertEquals(\n                applicationConfig.getOrganization(),\n                serviceMetadata.getAttachments().get(\"organization\"));\n        Assertions.assertEquals(\n                applicationConfig.getArchitecture(),\n                serviceMetadata.getAttachments().get(\"architecture\"));\n        Assertions.assertEquals(\n                applicationConfig.getEnvironment(),\n                serviceMetadata.getAttachments().get(\"environment\"));\n        Assertions.assertEquals(\n                applicationConfig.getCompiler(),\n                serviceMetadata.getAttachments().get(\"compiler\"));\n        Assertions.assertEquals(\n                applicationConfig.getLogger(), serviceMetadata.getAttachments().get(\"logger\"));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"registries\"));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"registry.ids\"));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"monitor\"));\n        Assertions.assertEquals(\n                applicationConfig.getDumpDirectory(),\n                serviceMetadata.getAttachments().get(DUMP_DIRECTORY));\n        Assertions.assertEquals(\n                applicationConfig.getQosEnable().toString(),\n                serviceMetadata.getAttachments().get(QOS_ENABLE));\n        Assertions.assertEquals(\n                applicationConfig.getQosHost(), serviceMetadata.getAttachments().get(QOS_HOST));\n        Assertions.assertEquals(\n                applicationConfig.getQosPort().toString(),\n                serviceMetadata.getAttachments().get(QOS_PORT));\n        Assertions.assertEquals(\n                applicationConfig.getQosAcceptForeignIp().toString(),\n                serviceMetadata.getAttachments().get(ACCEPT_FOREIGN_IP));\n        Assertions.assertEquals(\n                applicationConfig.getParameters().get(\"key1\"),\n                serviceMetadata.getAttachments().get(\"key1\"));\n        Assertions.assertEquals(\n                applicationConfig.getParameters().get(\"key2\"),\n                serviceMetadata.getAttachments().get(\"key2\"));\n        Assertions.assertEquals(\n                applicationConfig.getShutwait(),\n                serviceMetadata.getAttachments().get(\"shutwait\"));\n        Assertions.assertEquals(\n                applicationConfig.getMetadataType(),\n                serviceMetadata.getAttachments().get(METADATA_KEY));\n        Assertions.assertEquals(\n                applicationConfig.getRegisterConsumer().toString(),\n                serviceMetadata.getAttachments().get(\"register.consumer\"));\n        Assertions.assertEquals(\n                applicationConfig.getRepository(),\n                serviceMetadata.getAttachments().get(\"repository\"));\n        Assertions.assertEquals(\n                applicationConfig.getEnableFileCache().toString(),\n                serviceMetadata.getAttachments().get(REGISTRY_LOCAL_FILE_CACHE_ENABLED));\n        Assertions.assertEquals(\n                applicationConfig.getMetadataServicePort().toString(),\n                serviceMetadata.getAttachments().get(METADATA_SERVICE_PORT_KEY));\n        Assertions.assertEquals(\n                applicationConfig.getMetadataServiceProtocol().toString(),\n                serviceMetadata.getAttachments().get(METADATA_SERVICE_PROTOCOL_KEY));\n        Assertions.assertEquals(\n                applicationConfig.getLivenessProbe(),\n                serviceMetadata.getAttachments().get(LIVENESS_PROBE_KEY));\n        Assertions.assertEquals(\n                applicationConfig.getReadinessProbe(),\n                serviceMetadata.getAttachments().get(READINESS_PROBE_KEY));\n        Assertions.assertEquals(\n                applicationConfig.getStartupProbe(),\n                serviceMetadata.getAttachments().get(STARTUP_PROBE));\n\n        // verify additional module config\n        Assertions.assertEquals(\n                moduleConfig.getName(), serviceMetadata.getAttachments().get(\"module\"));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"monitor\"));\n        Assertions.assertEquals(\n                moduleConfig.getOrganization(), serviceMetadata.getAttachments().get(\"module.organization\"));\n        Assertions.assertEquals(\n                moduleConfig.getOwner(), serviceMetadata.getAttachments().get(\"module.owner\"));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"registries\"));\n        Assertions.assertEquals(\n                moduleConfig.getVersion(), serviceMetadata.getAttachments().get(\"module.version\"));\n\n        // verify additional consumer config\n        Assertions.assertEquals(\n                consumerConfig.getClient(), serviceMetadata.getAttachments().get(\"client\"));\n        Assertions.assertEquals(\n                consumerConfig.getThreadpool(), serviceMetadata.getAttachments().get(\"threadpool\"));\n        Assertions.assertEquals(\n                consumerConfig.getCorethreads().toString(),\n                serviceMetadata.getAttachments().get(\"corethreads\"));\n        Assertions.assertEquals(\n                consumerConfig.getQueues().toString(),\n                serviceMetadata.getAttachments().get(\"queues\"));\n        Assertions.assertEquals(\n                consumerConfig.getThreads().toString(),\n                serviceMetadata.getAttachments().get(\"threads\"));\n        Assertions.assertEquals(\n                consumerConfig.getShareconnections().toString(),\n                serviceMetadata.getAttachments().get(\"shareconnections\"));\n        Assertions.assertEquals(\n                consumerConfig.getUrlMergeProcessor(),\n                serviceMetadata.getAttachments().get(URL_MERGE_PROCESSOR_KEY));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(REFER_THREAD_NUM_KEY));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(REFER_BACKGROUND_KEY));\n\n        // verify additional reference config\n        Assertions.assertEquals(\n                referenceConfig.getClient(), serviceMetadata.getAttachments().get(\"client\"));\n        Assertions.assertEquals(\n                referenceConfig.getGeneric(), serviceMetadata.getAttachments().get(\"generic\"));\n        Assertions.assertEquals(\n                referenceConfig.getProtocol(), serviceMetadata.getAttachments().get(\"protocol\"));\n        Assertions.assertEquals(\n                referenceConfig.isInit().toString(),\n                serviceMetadata.getAttachments().get(\"init\"));\n        Assertions.assertEquals(\n                referenceConfig.getLazy().toString(),\n                serviceMetadata.getAttachments().get(\"lazy\"));\n        Assertions.assertEquals(\n                referenceConfig.isInjvm().toString(),\n                serviceMetadata.getAttachments().get(\"injvm\"));\n        Assertions.assertEquals(\n                referenceConfig.getReconnect(), serviceMetadata.getAttachments().get(\"reconnect\"));\n        Assertions.assertEquals(\n                referenceConfig.getSticky().toString(),\n                serviceMetadata.getAttachments().get(\"sticky\"));\n        Assertions.assertEquals(\n                referenceConfig.getStub(), serviceMetadata.getAttachments().get(\"stub\"));\n        Assertions.assertEquals(\n                referenceConfig.getProvidedBy(),\n                serviceMetadata.getAttachments().get(\"provided-by\"));\n        Assertions.assertEquals(\n                referenceConfig.getRouter(), serviceMetadata.getAttachments().get(\"router\"));\n        Assertions.assertEquals(\n                referenceConfig.getReferAsync().toString(),\n                serviceMetadata.getAttachments().get(REFER_ASYNC_KEY));\n\n        // verify additional method config\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"name\"));\n        Assertions.assertEquals(\n                methodConfig.getStat().toString(),\n                serviceMetadata.getAttachments().get(\"sayName.stat\"));\n        Assertions.assertEquals(\n                methodConfig.getRetries().toString(),\n                serviceMetadata.getAttachments().get(\"sayName.retries\"));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"sayName.reliable\"));\n        Assertions.assertEquals(\n                methodConfig.getExecutes().toString(),\n                serviceMetadata.getAttachments().get(\"sayName.executes\"));\n        Assertions.assertEquals(\n                methodConfig.getDeprecated().toString(),\n                serviceMetadata.getAttachments().get(\"sayName.deprecated\"));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"sayName.stick\"));\n        Assertions.assertEquals(\n                methodConfig.isReturn().toString(),\n                serviceMetadata.getAttachments().get(\"sayName.return\"));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"sayName.service\"));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"sayName.service.id\"));\n        Assertions.assertFalse(serviceMetadata.getAttachments().containsKey(\"sayName.parent.prefix\"));\n\n        // verify additional revision and methods parameter\n        Assertions.assertEquals(\n                Version.getVersion(referenceConfig.getInterfaceClass(), referenceConfig.getVersion()),\n                serviceMetadata.getAttachments().get(REVISION_KEY));\n        Assertions.assertTrue(serviceMetadata.getAttachments().containsKey(METHODS_KEY));\n        Assertions.assertEquals(\n                DemoService.class.getMethods().length,\n                StringUtils.split((String) serviceMetadata.getAttachments().get(METHODS_KEY), ',').length);\n\n        dubboBootstrap.stop();\n    }\n\n    @Test\n    void testCreateInvokerForLocalRefer() {\n\n        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setScope(LOCAL_KEY);\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(\"key1\", \"value1\");\n        parameters.put(\"key2\", \"value2\");\n        applicationConfig.setParameters(parameters);\n\n        referenceConfig.setInterface(DemoService.class);\n        referenceConfig.getInterfaceClass();\n        referenceConfig.setCheck(false);\n\n        DubboBootstrap dubboBootstrap = DubboBootstrap.newInstance(FrameworkModel.defaultModel());\n        dubboBootstrap.application(applicationConfig).reference(referenceConfig).initialize();\n\n        referenceConfig.init();\n        Assertions.assertTrue(referenceConfig.getInvoker() instanceof ScopeClusterInvoker);\n        ScopeClusterInvoker<?> scopeClusterInvoker = (ScopeClusterInvoker<?>) referenceConfig.getInvoker();\n        Invoker<?> mockInvoker = scopeClusterInvoker.getInvoker();\n        //        Assertions.assertTrue(mockInvoker instanceof MockClusterInvoker);\n        //        Invoker<?> withCount = ((MockClusterInvoker<?>) mockInvoker).getDirectory().getAllInvokers().get(0);\n        Invoker<?> withCount =\n                scopeClusterInvoker.getDirectory().getAllInvokers().get(0);\n\n        Assertions.assertTrue(withCount instanceof ReferenceCountInvokerWrapper);\n        Invoker<?> withFilter = ((ReferenceCountInvokerWrapper<?>) withCount).getInvoker();\n        Assertions.assertTrue(withFilter instanceof ListenerInvokerWrapper\n                || withFilter instanceof FilterChainBuilder.CallbackRegistrationInvoker);\n        if (withFilter instanceof ListenerInvokerWrapper) {\n            Assertions.assertTrue(\n                    ((ListenerInvokerWrapper<?>) (((ReferenceCountInvokerWrapper<?>) withCount).getInvoker()))\n                                    .getInvoker()\n                            instanceof InjvmInvoker);\n        }\n        if (withFilter instanceof FilterChainBuilder.CallbackRegistrationInvoker) {\n            Invoker filterInvoker = ((FilterChainBuilder.CallbackRegistrationInvoker) withFilter).getFilterInvoker();\n            FilterChainBuilder.CopyOfFilterChainNode filterInvoker1 =\n                    (FilterChainBuilder.CopyOfFilterChainNode) filterInvoker;\n            ListenerInvokerWrapper originalInvoker = (ListenerInvokerWrapper) filterInvoker1.getOriginalInvoker();\n            Invoker invoker = originalInvoker.getInvoker();\n            Assertions.assertTrue(invoker instanceof InjvmInvoker);\n        }\n        URL url = withFilter.getUrl();\n        Assertions.assertEquals(\"application1\", url.getParameter(\"application\"));\n        Assertions.assertEquals(\"value1\", url.getParameter(\"key1\"));\n        Assertions.assertEquals(\"value2\", url.getParameter(\"key2\"));\n\n        dubboBootstrap.stop();\n    }\n\n    /**\n     * Verify the configuration of the registry protocol for remote reference\n     */\n    @Test\n    void testCreateInvokerForRemoteRefer() {\n\n        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setGeneric(Boolean.FALSE.toString());\n        referenceConfig.setProtocol(\"dubbo\");\n        referenceConfig.setInit(true);\n        referenceConfig.setLazy(false);\n        referenceConfig.setInjvm(false);\n\n        DubboBootstrap dubboBootstrap = DubboBootstrap.newInstance(FrameworkModel.defaultModel());\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(\"key1\", \"value1\");\n        parameters.put(\"key2\", \"value2\");\n        applicationConfig.setParameters(parameters);\n\n        referenceConfig.refreshed.set(true);\n        referenceConfig.setInterface(DemoService.class);\n        referenceConfig.getInterfaceClass();\n        referenceConfig.setCheck(false);\n        RegistryConfig registry = new RegistryConfig();\n        registry.setAddress(zkUrl1);\n        applicationConfig.setRegistries(Collections.singletonList(registry));\n        applicationConfig.setRegistryIds(registry.getId());\n\n        referenceConfig.setRegistry(registry);\n\n        dubboBootstrap.application(applicationConfig).reference(referenceConfig).initialize();\n\n        referenceConfig.init();\n        Assertions.assertTrue(referenceConfig.getInvoker() instanceof MigrationInvoker);\n\n        dubboBootstrap.destroy();\n    }\n\n    /**\n     * Verify that the remote url is directly configured for remote reference\n     */\n    @Test\n    void testCreateInvokerWithRemoteUrlForRemoteRefer() {\n\n        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setGeneric(Boolean.FALSE.toString());\n        referenceConfig.setProtocol(\"dubbo\");\n        referenceConfig.setInit(true);\n        referenceConfig.setLazy(false);\n        referenceConfig.setInjvm(false);\n\n        DubboBootstrap dubboBootstrap = DubboBootstrap.newInstance(FrameworkModel.defaultModel());\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(\"key1\", \"value1\");\n        parameters.put(\"key2\", \"value2\");\n        applicationConfig.setParameters(parameters);\n\n        referenceConfig.refreshed.set(true);\n        referenceConfig.setInterface(DemoService.class);\n        referenceConfig.getInterfaceClass();\n        referenceConfig.setCheck(false);\n\n        referenceConfig.setUrl(\"dubbo://127.0.0.1:20880\");\n\n        dubboBootstrap.application(applicationConfig).reference(referenceConfig).initialize();\n\n        referenceConfig.init();\n        Assertions.assertTrue(referenceConfig.getInvoker() instanceof ScopeClusterInvoker);\n        Invoker scopeClusterInvoker = referenceConfig.getInvoker();\n        //        Assertions.assertTrue(((ScopeClusterInvoker) scopeClusterInvoker).getInvoker() instanceof\n        // MockClusterInvoker);\n        Assertions.assertEquals(\n                Boolean.TRUE,\n                ((ScopeClusterInvoker) scopeClusterInvoker)\n                        .getInvoker()\n                        .getUrl()\n                        .getAttribute(PEER_KEY));\n        dubboBootstrap.destroy();\n    }\n\n    /**\n     * Verify that the registry url is directly configured for remote reference\n     */\n    @Test\n    void testCreateInvokerWithRegistryUrlForRemoteRefer() {\n\n        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setGeneric(Boolean.FALSE.toString());\n        referenceConfig.setProtocol(\"dubbo\");\n        referenceConfig.setInit(true);\n        referenceConfig.setLazy(false);\n        referenceConfig.setInjvm(false);\n\n        DubboBootstrap dubboBootstrap = DubboBootstrap.newInstance(FrameworkModel.defaultModel());\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(\"key1\", \"value1\");\n        parameters.put(\"key2\", \"value2\");\n        applicationConfig.setParameters(parameters);\n\n        referenceConfig.refreshed.set(true);\n        referenceConfig.setInterface(DemoService.class);\n        referenceConfig.getInterfaceClass();\n        referenceConfig.setCheck(false);\n\n        referenceConfig.setUrl(registryUrl1);\n\n        dubboBootstrap.application(applicationConfig).reference(referenceConfig).initialize();\n\n        referenceConfig.init();\n        Assertions.assertTrue(referenceConfig.getInvoker() instanceof MigrationInvoker);\n        dubboBootstrap.destroy();\n    }\n\n    /**\n     * Verify the service reference of multiple registries\n     */\n    @Test\n    void testMultipleRegistryForRemoteRefer() {\n        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setGeneric(Boolean.FALSE.toString());\n        referenceConfig.setProtocol(\"dubbo\");\n        referenceConfig.setInit(true);\n        referenceConfig.setLazy(false);\n        referenceConfig.setInjvm(false);\n\n        DubboBootstrap dubboBootstrap = DubboBootstrap.newInstance(FrameworkModel.defaultModel());\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(\"key1\", \"value1\");\n        parameters.put(\"key2\", \"value2\");\n        applicationConfig.setParameters(parameters);\n\n        referenceConfig.refreshed.set(true);\n        referenceConfig.setInterface(DemoService.class);\n        referenceConfig.getInterfaceClass();\n        referenceConfig.setCheck(false);\n        RegistryConfig registry1 = new RegistryConfig();\n        registry1.setAddress(zkUrl1);\n        registry1.setId(\"zk1\");\n\n        RegistryConfig registry2 = new RegistryConfig();\n        registry2.setAddress(zkUrl2);\n        registry2.setId(\"zk2\");\n\n        List<RegistryConfig> registryConfigs = new ArrayList<>();\n        registryConfigs.add(registry1);\n        registryConfigs.add(registry2);\n        applicationConfig.setRegistries(registryConfigs);\n        applicationConfig.setRegistryIds(\"zk1,zk2\");\n\n        referenceConfig.setRegistries(registryConfigs);\n\n        dubboBootstrap.application(applicationConfig).reference(referenceConfig).initialize();\n\n        referenceConfig.init();\n        Assertions.assertTrue(referenceConfig.getInvoker() instanceof ZoneAwareClusterInvoker);\n\n        dubboBootstrap.destroy();\n    }\n\n    @Test\n    @Disabled(\"Disabled due to Github Actions environment\")\n    public void testInjvm() throws Exception {\n        ApplicationConfig application = new ApplicationConfig();\n        application.setName(\"test-protocol-random-port\");\n        application.setEnableFileCache(false);\n        ApplicationModel.defaultModel().getApplicationConfigManager().setApplication(application);\n\n        RegistryConfig registry = new RegistryConfig();\n        registry.setAddress(zkUrl1);\n\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setName(\"dubbo\");\n\n        ServiceConfig<DemoService> demoService;\n        demoService = new ServiceConfig<>();\n        demoService.setInterface(DemoService.class);\n        demoService.setRef(new DemoServiceImpl());\n        demoService.setRegistry(registry);\n        demoService.setProtocol(protocol);\n\n        ReferenceConfig<DemoService> rc = new ReferenceConfig<>();\n        rc.setRegistry(registry);\n        rc.setInterface(DemoService.class.getName());\n        rc.setScope(SCOPE_REMOTE);\n\n        try {\n            System.setProperty(\"java.net.preferIPv4Stack\", \"true\");\n            demoService.export();\n            rc.get();\n            Assertions.assertFalse(\n                    LOCAL_PROTOCOL.equalsIgnoreCase(rc.getInvoker().getUrl().getProtocol()));\n        } finally {\n            System.clearProperty(\"java.net.preferIPv4Stack\");\n            rc.destroy();\n            demoService.unexport();\n        }\n\n        // Manually trigger dubbo resource recycling.\n        DubboBootstrap.getInstance().destroy();\n    }\n\n    /**\n     * unit test for dubbo-1765\n     */\n    @Test\n    void test1ReferenceRetry() {\n        ApplicationConfig application = new ApplicationConfig();\n        application.setName(\"test-reference-retry\");\n        application.setEnableFileCache(false);\n        ApplicationModel.defaultModel().getApplicationConfigManager().setApplication(application);\n\n        RegistryConfig registry = new RegistryConfig();\n        registry.setAddress(zkUrl1);\n\n        ReferenceConfig<DemoService> rc = new ReferenceConfig<>();\n        rc.setRegistry(registry);\n        rc.setInterface(DemoService.class.getName());\n\n        boolean success = false;\n        DemoService demoService = null;\n        try {\n            demoService = rc.get();\n            success = true;\n        } catch (Exception e) {\n            // ignore\n        }\n        Assertions.assertFalse(success);\n        Assertions.assertNull(demoService);\n\n        try {\n            System.setProperty(\"java.net.preferIPv4Stack\", \"true\");\n            ProxyFactory proxy =\n                    ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n            DemoService service = new DemoServiceImpl();\n            URL url = URL.valueOf(\"injvm://127.0.0.1/DemoService\")\n                    .addParameter(INTERFACE_KEY, DemoService.class.getName())\n                    .setScopeModel(ApplicationModel.defaultModel().getDefaultModule());\n            url = url.addParameter(EXPORTER_LISTENER_KEY, LOCAL_PROTOCOL);\n            Protocol protocolSPI = ApplicationModel.defaultModel()\n                    .getExtensionLoader(Protocol.class)\n                    .getAdaptiveExtension();\n            protocolSPI.export(proxy.getInvoker(service, DemoService.class, url));\n            demoService = rc.get();\n            success = true;\n        } catch (Exception e) {\n            // ignore\n        } finally {\n            rc.destroy();\n            InjvmProtocol.getInjvmProtocol(FrameworkModel.defaultModel()).destroy();\n            System.clearProperty(\"java.net.preferIPv4Stack\");\n        }\n        Assertions.assertTrue(success);\n        Assertions.assertNotNull(demoService);\n    }\n\n    @Test\n    void test2ReferenceRetry() {\n        ApplicationConfig application = new ApplicationConfig();\n        application.setName(\"test-reference-retry2\");\n        application.setEnableFileCache(false);\n        ApplicationModel.defaultModel().getApplicationConfigManager().setApplication(application);\n\n        RegistryConfig registry = new RegistryConfig();\n        registry.setAddress(zkUrl1);\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setName(\"mockprotocol\");\n\n        ReferenceConfig<DemoService> rc = new ReferenceConfig<>();\n        rc.setRegistry(registry);\n        rc.setInterface(DemoService.class.getName());\n\n        boolean success = false;\n        DemoService demoService = null;\n        try {\n            demoService = rc.get();\n            success = true;\n        } catch (Exception e) {\n            // ignore\n        }\n        Assertions.assertFalse(success);\n        Assertions.assertNull(demoService);\n\n        ServiceConfig<DemoService> sc = new ServiceConfig<>();\n        sc.setInterface(DemoService.class.getName());\n        sc.setRef(new DemoServiceImpl());\n        sc.setRegistry(registry);\n        sc.setProtocol(protocol);\n\n        try {\n            System.setProperty(\"java.net.preferIPv4Stack\", \"true\");\n            sc.export();\n            demoService = rc.get();\n            success = true;\n        } catch (Exception e) {\n            // ignore\n        } finally {\n            rc.destroy();\n            sc.unexport();\n            System.clearProperty(\"java.net.preferIPv4Stack\");\n        }\n        Assertions.assertTrue(success);\n        Assertions.assertNotNull(demoService);\n    }\n\n    @Test\n    void testMetaData() {\n        ReferenceConfig config = new ReferenceConfig();\n        Map<String, String> metaData = config.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"Expect empty metadata but found: \" + metaData);\n\n        // test merged and override consumer attributes\n        ConsumerConfig consumerConfig = new ConsumerConfig();\n        consumerConfig.setAsync(true);\n        consumerConfig.setActives(10);\n        config.setConsumer(consumerConfig);\n        config.setAsync(false); // override\n\n        metaData = config.getMetaData();\n        Assertions.assertEquals(2, metaData.size());\n        Assertions.assertEquals(String.valueOf(consumerConfig.getActives()), metaData.get(\"actives\"));\n        Assertions.assertEquals(String.valueOf(config.isAsync()), metaData.get(\"async\"));\n    }\n\n    @Test\n    void testGetPrefixes() {\n\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setInterface(DemoService.class);\n\n        List<String> prefixes = referenceConfig.getPrefixes();\n        Assertions.assertTrue(prefixes.contains(\"dubbo.reference.\" + referenceConfig.getInterface()));\n\n        long start = System.currentTimeMillis();\n        for (int i = 0; i < 1000; i++) {\n            referenceConfig.getPrefixes();\n        }\n        long end = System.currentTimeMillis();\n        logger.info(\"ReferenceConfig get prefixes cost: {}\", end - start);\n    }\n\n    @Test\n    void testGenericAndInterfaceConflicts() {\n\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setInterface(DemoService.class);\n        referenceConfig.setGeneric(\"true\");\n\n        DubboBootstrap.getInstance()\n                .application(\"demo app\")\n                .reference(referenceConfig)\n                .initialize();\n\n        Assertions.assertEquals(GenericService.class, referenceConfig.getInterfaceClass());\n    }\n\n    @Test\n    void testLargeReferences() throws InterruptedException {\n        int amount = 10000;\n        ModuleConfigManager configManager = DubboBootstrap.getInstance()\n                .getApplicationModel()\n                .getDefaultModule()\n                .getConfigManager();\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"test-app\");\n        MetadataReportConfig metadataReportConfig = new MetadataReportConfig();\n        metadataReportConfig.setAddress(\"metadata://\");\n        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();\n        configCenterConfig.setAddress(\"diamond://\");\n\n        testInitReferences(0, amount, applicationConfig, metadataReportConfig, configCenterConfig);\n        configManager.clear();\n        testInitReferences(0, 1, applicationConfig, metadataReportConfig, configCenterConfig);\n        configManager.clear();\n\n        long t1 = System.currentTimeMillis();\n        int nThreads = 8;\n        ExecutorService executorService = Executors.newFixedThreadPool(nThreads);\n        for (int i = 0; i < nThreads; i++) {\n            int perCount = (int) (1.0 * amount / nThreads);\n            int start = perCount * i;\n            int end = start + perCount;\n            if (i == nThreads - 1) {\n                end = amount;\n            }\n            int finalEnd = end;\n            logger.info(\"start thread {}: range: {} - {}, count: {}\", i, start, end, (end - start));\n            executorService.submit(() -> {\n                testInitReferences(start, finalEnd, applicationConfig, metadataReportConfig, configCenterConfig);\n            });\n        }\n        executorService.shutdown();\n        executorService.awaitTermination(100, TimeUnit.SECONDS);\n\n        long t2 = System.currentTimeMillis();\n        long cost = t2 - t1;\n        logger.info(\"Init large references cost: {}ms\", cost);\n        Assertions.assertEquals(amount, configManager.getReferences().size());\n        Assertions.assertTrue(cost < 1000, \"Init large references too slowly: \" + cost);\n\n        // test equals\n        testSearchReferences();\n    }\n\n    private void testSearchReferences() {\n        long t1 = System.currentTimeMillis();\n        Collection<ReferenceConfigBase<?>> references = DubboBootstrap.getInstance()\n                .getApplicationModel()\n                .getDefaultModule()\n                .getConfigManager()\n                .getReferences();\n        Iterator<ReferenceConfigBase<?>> it = references.iterator();\n        ReferenceConfigBase<?> first = it.next();\n        List<ReferenceConfigBase<?>> results =\n                references.stream().filter(first::equals).collect(Collectors.toList());\n        long t2 = System.currentTimeMillis();\n        long cost = t2 - t1;\n        logger.info(\"Search large references cost: {}ms\", cost);\n        Assertions.assertEquals(1, results.size());\n        Assertions.assertTrue(cost < 1000, \"Search large references too slowly: \" + cost);\n    }\n\n    private long testInitReferences(\n            int start,\n            int end,\n            ApplicationConfig applicationConfig,\n            MetadataReportConfig metadataReportConfig,\n            ConfigCenterConfig configCenterConfig) {\n        // test add large number of references\n        long t1 = System.currentTimeMillis();\n        try {\n            for (int i = start; i < end; i++) {\n                ReferenceConfig referenceConfig = new ReferenceConfig();\n                referenceConfig.setInterface(\"com.test.TestService\" + i);\n                referenceConfig.setApplication(applicationConfig);\n                referenceConfig.setMetadataReportConfig(metadataReportConfig);\n                referenceConfig.setConfigCenter(configCenterConfig);\n                DubboBootstrap.getInstance().reference(referenceConfig);\n\n                // ApplicationModel.defaultModel().getConfigManager().getConfigCenters();\n            }\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        long t2 = System.currentTimeMillis();\n        return t2 - t1;\n    }\n\n    @Test\n    void testConstructWithReferenceAnnotation() throws NoSuchFieldException {\n        Reference reference = getClass().getDeclaredField(\"innerTest\").getAnnotation(Reference.class);\n        ReferenceConfig referenceConfig = new ReferenceConfig(reference);\n        Assertions.assertEquals(1, referenceConfig.getMethods().size());\n        Assertions.assertEquals((referenceConfig.getMethods().get(0)).getName(), \"sayHello\");\n        Assertions.assertEquals(1300, (int) (referenceConfig.getMethods().get(0)).getTimeout());\n        Assertions.assertEquals(4, (int) (referenceConfig.getMethods().get(0)).getRetries());\n        Assertions.assertEquals((referenceConfig.getMethods().get(0)).getLoadbalance(), \"random\");\n        Assertions.assertEquals(3, (int) (referenceConfig.getMethods().get(0)).getActives());\n        Assertions.assertEquals(5, (int) (referenceConfig.getMethods().get(0)).getExecutes());\n        Assertions.assertTrue((referenceConfig.getMethods().get(0)).isAsync());\n        Assertions.assertEquals((referenceConfig.getMethods().get(0)).getOninvokeMethod(), \"i\");\n        Assertions.assertEquals((referenceConfig.getMethods().get(0)).getOnreturnMethod(), \"r\");\n        Assertions.assertEquals((referenceConfig.getMethods().get(0)).getOnthrowMethod(), \"t\");\n        Assertions.assertEquals((referenceConfig.getMethods().get(0)).getCache(), \"c\");\n    }\n\n    @Test\n    void testDifferentClassLoader() throws Exception {\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"TestApp\");\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        DemoService demoService = new DemoServiceImpl();\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();\n        try {\n            serviceConfig.setInterface(DemoService.class);\n            serviceConfig.setRegistry(new RegistryConfig(zkUrl1));\n            serviceConfig.setScopeModel(moduleModel);\n            serviceConfig.setRef(demoService);\n            serviceConfig.export();\n\n            String basePath = DemoService.class\n                    .getProtectionDomain()\n                    .getCodeSource()\n                    .getLocation()\n                    .getFile();\n            basePath = URLDecoder.decode(basePath, \"UTF-8\");\n            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n            TestClassLoader classLoader1 = new TestClassLoader(classLoader, basePath);\n            TestClassLoader classLoader2 = new TestClassLoader(classLoader, basePath);\n\n            Class<?> class1 = classLoader1.loadClass(DemoService.class.getName(), false);\n            Class<?> class2 = classLoader2.loadClass(DemoService.class.getName(), false);\n\n            Assertions.assertNotEquals(class1, class2);\n\n            ReferenceConfig<DemoService> referenceConfig1 = new ReferenceConfig<>();\n            referenceConfig1.setInterface(class1);\n            referenceConfig1.setRegistry(new RegistryConfig(zkUrl1));\n            referenceConfig1.setScopeModel(moduleModel);\n            referenceConfig1.setScope(\"remote\");\n            Object demoService1 = referenceConfig1.get();\n\n            for (Class<?> anInterface : demoService1.getClass().getInterfaces()) {\n                Assertions.assertNotEquals(DemoService.class, anInterface);\n            }\n            Assertions.assertTrue(Arrays.stream(demoService1.getClass().getInterfaces())\n                    .anyMatch((clazz) -> clazz.getClassLoader().equals(classLoader1)));\n\n            java.lang.reflect.Method callBean1 = demoService1.getClass().getDeclaredMethod(\"callInnerClass\");\n            callBean1.setAccessible(true);\n            Object result1 = callBean1.invoke(demoService1);\n\n            Assertions.assertNotEquals(result1.getClass(), DemoService.InnerClass.class);\n            Assertions.assertEquals(classLoader1, result1.getClass().getClassLoader());\n\n            ReferenceConfig<DemoService> referenceConfig2 = new ReferenceConfig<>();\n            referenceConfig2.setInterface(class2);\n            referenceConfig2.setRegistry(new RegistryConfig(zkUrl1));\n            referenceConfig2.setScopeModel(moduleModel);\n            referenceConfig2.setScope(\"remote\");\n            Object demoService2 = referenceConfig2.get();\n\n            for (Class<?> anInterface : demoService2.getClass().getInterfaces()) {\n                Assertions.assertNotEquals(DemoService.class, anInterface);\n            }\n            Assertions.assertTrue(Arrays.stream(demoService2.getClass().getInterfaces())\n                    .anyMatch((clazz) -> clazz.getClassLoader().equals(classLoader2)));\n\n            java.lang.reflect.Method callBean2 = demoService2.getClass().getDeclaredMethod(\"callInnerClass\");\n            callBean2.setAccessible(true);\n            Object result2 = callBean2.invoke(demoService2);\n\n            Assertions.assertNotEquals(callBean1, callBean2);\n            Assertions.assertNotEquals(result2.getClass(), DemoService.InnerClass.class);\n            Assertions.assertEquals(classLoader2, result2.getClass().getClassLoader());\n            Assertions.assertNotEquals(result1.getClass(), result2.getClass());\n\n            applicationModel.destroy();\n            DubboBootstrap.getInstance().destroy();\n            Thread.currentThread().setContextClassLoader(classLoader);\n            Thread.currentThread().getContextClassLoader().loadClass(DemoService.class.getName());\n        } finally {\n            serviceConfig.unexport();\n        }\n    }\n\n    @Test\n    @DisabledForJreRange(min = JRE.JAVA_16)\n    public void testDifferentClassLoaderRequest() throws Exception {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        String basePath = DemoService.class\n                .getProtectionDomain()\n                .getCodeSource()\n                .getLocation()\n                .getFile();\n        basePath = java.net.URLDecoder.decode(basePath, \"UTF-8\");\n        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n        TestClassLoader1 classLoader1 = new TestClassLoader1(basePath);\n        TestClassLoader1 classLoader2 = new TestClassLoader1(basePath);\n        TestClassLoader2 classLoader3 = new TestClassLoader2(classLoader2, basePath);\n\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"TestApp\");\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n        ModuleModel moduleModel = applicationModel.newModule();\n\n        Class<?> clazz1 = classLoader1.loadClass(MultiClassLoaderService.class.getName(), false);\n        Class<?> clazz1impl = classLoader1.loadClass(MultiClassLoaderServiceImpl.class.getName(), false);\n        Class<?> requestClazzCustom1 = compileCustomRequest(classLoader1);\n        Class<?> resultClazzCustom1 = compileCustomResult(classLoader1);\n        classLoader1.loadedClass.put(requestClazzCustom1.getName(), requestClazzCustom1);\n        classLoader1.loadedClass.put(resultClazzCustom1.getName(), resultClazzCustom1);\n        AtomicReference innerRequestReference = new AtomicReference();\n        AtomicReference innerResultReference = new AtomicReference();\n        innerResultReference.set(resultClazzCustom1.getDeclaredConstructor().newInstance());\n        Constructor<?> declaredConstructor =\n                clazz1impl.getDeclaredConstructor(AtomicReference.class, AtomicReference.class);\n\n        ServiceConfig serviceConfig = new ServiceConfig<>();\n        try {\n            serviceConfig.setInterfaceClassLoader(classLoader1);\n            serviceConfig.setInterface(clazz1);\n            serviceConfig.setRegistry(new RegistryConfig(zkUrl1));\n            serviceConfig.setScopeModel(moduleModel);\n            serviceConfig.setRef(declaredConstructor.newInstance(innerRequestReference, innerResultReference));\n            serviceConfig.export();\n\n            Class<?> clazz2 = classLoader2.loadClass(MultiClassLoaderService.class.getName(), false);\n            Class<?> requestClazzOrigin = classLoader2.loadClass(MultiClassLoaderServiceRequest.class.getName(), false);\n            Class<?> requestClazzCustom2 = compileCustomRequest(classLoader2);\n            Class<?> resultClazzCustom3 = compileCustomResult(classLoader3);\n            classLoader2.loadedClass.put(requestClazzCustom2.getName(), requestClazzCustom2);\n            classLoader3.loadedClass.put(resultClazzCustom3.getName(), resultClazzCustom3);\n\n            ReferenceConfig<DemoService> referenceConfig1 = new ReferenceConfig<>();\n            referenceConfig1.setInterface(clazz2);\n            referenceConfig1.setInterfaceClassLoader(classLoader3);\n            referenceConfig1.setRegistry(new RegistryConfig(zkUrl1));\n            referenceConfig1.setScopeModel(moduleModel);\n            referenceConfig1.setScope(\"remote\");\n            referenceConfig1.setTimeout(30000);\n            Object object1 = referenceConfig1.get();\n\n            java.lang.reflect.Method callBean1 = object1.getClass().getDeclaredMethod(\"call\", requestClazzOrigin);\n            callBean1.setAccessible(true);\n            Object result1 = callBean1.invoke(\n                    object1, requestClazzCustom2.getDeclaredConstructor().newInstance());\n\n            Assertions.assertEquals(resultClazzCustom3, result1.getClass());\n            Assertions.assertNotEquals(classLoader2, result1.getClass().getClassLoader());\n            Assertions.assertEquals(\n                    classLoader1, innerRequestReference.get().getClass().getClassLoader());\n\n            Thread.currentThread().setContextClassLoader(classLoader1);\n            callBean1.invoke(\n                    object1, requestClazzCustom2.getDeclaredConstructor().newInstance());\n            Assertions.assertEquals(classLoader1, Thread.currentThread().getContextClassLoader());\n\n            applicationModel.destroy();\n            DubboBootstrap.getInstance().destroy();\n            Thread.currentThread().setContextClassLoader(classLoader);\n            Thread.currentThread().getContextClassLoader().loadClass(DemoService.class.getName());\n        } finally {\n            serviceConfig.unexport();\n        }\n    }\n\n    @Test\n    void testClassLoader() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"Test\"));\n\n        ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();\n        ClassLoader classLoader = new ClassLoader(originClassLoader) {};\n        Thread.currentThread().setContextClassLoader(classLoader);\n\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>(applicationModel.newModule());\n        try {\n            serviceConfig.setInterface(DemoService.class);\n            serviceConfig.setProtocol(new ProtocolConfig(\"dubbo\", -1));\n            serviceConfig.setRegistry(new RegistryConfig(\"N/A\"));\n            serviceConfig.setRef(new DemoServiceImpl());\n            serviceConfig.export();\n\n            ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>(applicationModel.newModule());\n            referenceConfig.setInterface(DemoService.class);\n            referenceConfig.setRegistry(new RegistryConfig(\"N/A\"));\n            DemoService demoService = referenceConfig.get();\n\n            demoService.sayName(\"Dubbo\");\n            Assertions.assertEquals(classLoader, Thread.currentThread().getContextClassLoader());\n\n            Thread.currentThread().setContextClassLoader(null);\n            demoService.sayName(\"Dubbo\");\n            Assertions.assertNull(Thread.currentThread().getContextClassLoader());\n\n            Thread.currentThread().setContextClassLoader(originClassLoader);\n            frameworkModel.destroy();\n        } finally {\n            serviceConfig.unexport();\n        }\n    }\n\n    private Class<?> compileCustomRequest(ClassLoader classLoader) throws NotFoundException, CannotCompileException {\n        CtClassBuilder builder = new CtClassBuilder();\n        builder.setClassName(MultiClassLoaderServiceRequest.class.getName() + \"A\");\n        builder.setSuperClassName(MultiClassLoaderServiceRequest.class.getName());\n        CtClass cls = builder.build(classLoader);\n        // FIXME support JDK 17\n        return cls.toClass(classLoader, JavassistCompiler.class.getProtectionDomain());\n    }\n\n    private Class<?> compileCustomResult(ClassLoader classLoader) throws NotFoundException, CannotCompileException {\n        CtClassBuilder builder = new CtClassBuilder();\n        builder.setClassName(MultiClassLoaderServiceResult.class.getName() + \"A\");\n        builder.setSuperClassName(MultiClassLoaderServiceResult.class.getName());\n        CtClass cls = builder.build(classLoader);\n        return cls.toClass(classLoader, JavassistCompiler.class.getProtectionDomain());\n    }\n\n    @Reference(\n            methods = {\n                @Method(\n                        name = \"sayHello\",\n                        timeout = 1300,\n                        retries = 4,\n                        loadbalance = \"random\",\n                        async = true,\n                        actives = 3,\n                        executes = 5,\n                        deprecated = true,\n                        sticky = true,\n                        oninvoke = \"instance.i\",\n                        onthrow = \"instance.t\",\n                        onreturn = \"instance.r\",\n                        cache = \"c\",\n                        validation = \"v\",\n                        arguments = {@Argument(index = 24, callback = true, type = \"sss\")})\n            })\n    private InnerTest innerTest;\n\n    private class InnerTest {}\n\n    private static class TestClassLoader extends ClassLoader {\n        private String basePath;\n\n        public TestClassLoader(ClassLoader parent, String basePath) {\n            super(parent);\n            this.basePath = basePath;\n        }\n\n        @Override\n        protected Class<?> findClass(String name) throws ClassNotFoundException {\n            try {\n                byte[] bytes = loadClassData(name);\n                return defineClass(name, bytes, 0, bytes.length);\n            } catch (Exception e) {\n                throw new ClassNotFoundException();\n            }\n        }\n\n        @Override\n        public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n            Class<?> loadedClass = this.findLoadedClass(name);\n            if (loadedClass != null) {\n                return loadedClass;\n            } else {\n                try {\n                    if (name.equals(\"org.apache.dubbo.config.api.DemoService\")\n                            || name.equals(\"org.apache.dubbo.config.api.DemoService$InnerClass\")) {\n                        Class<?> aClass = this.findClass(name);\n                        if (resolve) {\n                            this.resolveClass(aClass);\n                        }\n                        return aClass;\n                    } else {\n                        return super.loadClass(name, resolve);\n                    }\n                } catch (Exception e) {\n                    return super.loadClass(name, resolve);\n                }\n            }\n        }\n\n        public byte[] loadClassData(String className) throws IOException {\n            className = className.replaceAll(\"\\\\.\", \"/\");\n            String path = basePath + File.separator + className + \".class\";\n            FileInputStream fileInputStream;\n            byte[] classBytes;\n            fileInputStream = new FileInputStream(path);\n            int length = fileInputStream.available();\n            classBytes = new byte[length];\n            fileInputStream.read(classBytes);\n            fileInputStream.close();\n            return classBytes;\n        }\n    }\n\n    private static class TestClassLoader1 extends ClassLoader {\n        private String basePath;\n\n        public TestClassLoader1(String basePath) {\n            this.basePath = basePath;\n        }\n\n        Map<String, Class<?>> loadedClass = new ConcurrentHashMap<>();\n\n        @Override\n        protected Class<?> findClass(String name) throws ClassNotFoundException {\n            try {\n                byte[] bytes = loadClassData(name);\n                return defineClass(name, bytes, 0, bytes.length);\n            } catch (Exception e) {\n                throw new ClassNotFoundException();\n            }\n        }\n\n        @Override\n        public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n            if (loadedClass.containsKey(name)) {\n                return loadedClass.get(name);\n            }\n            if (name.startsWith(\"demo\")) {\n                Class<?> aClass = this.findClass(name);\n                this.loadedClass.put(name, aClass);\n                if (resolve) {\n                    this.resolveClass(aClass);\n                }\n                return aClass;\n            } else {\n                Class<?> loadedClass = this.findLoadedClass(name);\n                if (loadedClass != null) {\n                    return loadedClass;\n                } else {\n                    return super.loadClass(name, resolve);\n                }\n            }\n        }\n\n        public byte[] loadClassData(String className) throws IOException {\n            className = className.replaceAll(\"\\\\.\", \"/\");\n            String path = basePath + File.separator + className + \".class\";\n            FileInputStream fileInputStream;\n            byte[] classBytes;\n            fileInputStream = new FileInputStream(path);\n            int length = fileInputStream.available();\n            classBytes = new byte[length];\n            fileInputStream.read(classBytes);\n            fileInputStream.close();\n            return classBytes;\n        }\n    }\n\n    private static class TestClassLoader2 extends ClassLoader {\n        private String basePath;\n        private TestClassLoader1 testClassLoader;\n\n        Map<String, Class<?>> loadedClass = new ConcurrentHashMap<>();\n\n        public TestClassLoader2(TestClassLoader1 testClassLoader, String basePath) {\n            this.testClassLoader = testClassLoader;\n            this.basePath = basePath;\n        }\n\n        @Override\n        protected Class<?> findClass(String name) throws ClassNotFoundException {\n            try {\n                byte[] bytes = loadClassData(name);\n                return defineClass(name, bytes, 0, bytes.length);\n            } catch (Exception e) {\n                throw new ClassNotFoundException();\n            }\n        }\n\n        @Override\n        public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n            if (loadedClass.containsKey(name)) {\n                return loadedClass.get(name);\n            }\n            if (name.startsWith(\"demo.MultiClassLoaderServiceRe\")) {\n                Class<?> aClass = this.findClass(name);\n                this.loadedClass.put(name, aClass);\n                if (resolve) {\n                    this.resolveClass(aClass);\n                }\n                return aClass;\n            } else {\n                return testClassLoader.loadClass(name, resolve);\n            }\n        }\n\n        public byte[] loadClassData(String className) throws IOException {\n            className = className.replaceAll(\"\\\\.\", \"/\");\n            String path = basePath + File.separator + className + \".class\";\n            FileInputStream fileInputStream;\n            byte[] classBytes;\n            fileInputStream = new FileInputStream(path);\n            int length = fileInputStream.available();\n            classBytes = new byte[length];\n            fileInputStream.read(classBytes);\n            fileInputStream.close();\n            return classBytes;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/RegistryConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PREFERRED_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;\nimport static org.apache.dubbo.config.Constants.SHUTDOWN_TIMEOUT_KEY;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.hasKey;\nimport static org.hamcrest.Matchers.not;\n\nclass RegistryConfigTest {\n\n    @BeforeEach\n    public void beforeEach() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void afterEach() {\n        SysProps.clear();\n    }\n\n    @Test\n    void testProtocol() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setProtocol(\"protocol\");\n        assertThat(registry.getProtocol(), equalTo(registry.getProtocol()));\n    }\n\n    @Test\n    void testAddress() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setAddress(\"zookeeper://mrh:123@localhost:9103/registry?backup=localhost:9104&k1=v1\");\n        assertThat(\n                registry.getAddress(),\n                equalTo(\"zookeeper://mrh:123@localhost:9103/registry?backup=localhost:9104&k1=v1\"));\n        assertThat(registry.getProtocol(), equalTo(\"zookeeper\"));\n        assertThat(registry.getUsername(), equalTo(\"mrh\"));\n        assertThat(registry.getPassword(), equalTo(\"123\"));\n        assertThat(registry.getParameters().get(\"k1\"), equalTo(\"v1\"));\n        Map<String, String> parameters = new HashMap<>();\n        RegistryConfig.appendParameters(parameters, registry);\n        assertThat(parameters, not(hasKey(\"address\")));\n    }\n\n    @Test\n    void testUsername() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setUsername(\"username\");\n        assertThat(registry.getUsername(), equalTo(\"username\"));\n    }\n\n    @Test\n    void testPassword() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setPassword(\"password\");\n        assertThat(registry.getPassword(), equalTo(\"password\"));\n    }\n\n    @Test\n    void testWait() throws Exception {\n        try {\n            RegistryConfig registry = new RegistryConfig();\n            registry.setWait(10);\n            assertThat(registry.getWait(), is(10));\n            assertThat(System.getProperty(SHUTDOWN_WAIT_KEY), equalTo(\"10\"));\n        } finally {\n            System.clearProperty(SHUTDOWN_TIMEOUT_KEY);\n        }\n    }\n\n    @Test\n    void testCheck() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setCheck(true);\n        assertThat(registry.isCheck(), is(true));\n    }\n\n    @Test\n    void testFile() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setFile(\"file\");\n        assertThat(registry.getFile(), equalTo(\"file\"));\n    }\n\n    @Test\n    void testTransporter() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setTransporter(\"transporter\");\n        assertThat(registry.getTransporter(), equalTo(\"transporter\"));\n    }\n\n    @Test\n    void testClient() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setClient(\"client\");\n        assertThat(registry.getClient(), equalTo(\"client\"));\n    }\n\n    @Test\n    void testTimeout() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setTimeout(10);\n        assertThat(registry.getTimeout(), is(10));\n    }\n\n    @Test\n    void testSession() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setSession(10);\n        assertThat(registry.getSession(), is(10));\n    }\n\n    @Test\n    void testDynamic() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setDynamic(true);\n        assertThat(registry.isDynamic(), is(true));\n    }\n\n    @Test\n    void testRegister() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setRegister(true);\n        assertThat(registry.isRegister(), is(true));\n    }\n\n    @Test\n    void testSubscribe() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setSubscribe(true);\n        assertThat(registry.isSubscribe(), is(true));\n    }\n\n    @Test\n    void testCluster() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setCluster(\"cluster\");\n        assertThat(registry.getCluster(), equalTo(\"cluster\"));\n    }\n\n    @Test\n    void testGroup() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setGroup(\"group\");\n        assertThat(registry.getGroup(), equalTo(\"group\"));\n    }\n\n    @Test\n    void testVersion() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setVersion(\"1.0.0\");\n        assertThat(registry.getVersion(), equalTo(\"1.0.0\"));\n    }\n\n    @Test\n    void testParameters() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setParameters(Collections.singletonMap(\"k1\", \"v1\"));\n        assertThat(registry.getParameters(), hasEntry(\"k1\", \"v1\"));\n        Map<String, String> parameters = new HashMap<String, String>();\n        RegistryConfig.appendParameters(parameters, registry);\n        assertThat(parameters, hasEntry(\"k1\", \"v1\"));\n    }\n\n    @Test\n    void testDefault() throws Exception {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setDefault(true);\n        assertThat(registry.isDefault(), is(true));\n    }\n\n    @Test\n    void testEquals() throws Exception {\n        RegistryConfig registry1 = new RegistryConfig();\n        RegistryConfig registry2 = new RegistryConfig();\n        registry1.setAddress(ZookeeperRegistryCenterConfig.getConnectionAddress2());\n        registry2.setAddress(\"zookeeper://127.0.0.1:2183\");\n        Assertions.assertNotEquals(registry1, registry2);\n    }\n\n    @Test\n    void testMetaData() {\n        RegistryConfig config = new RegistryConfig();\n        Map<String, String> metaData = config.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"Expect empty metadata but found: \" + metaData);\n    }\n\n    @Test\n    void testOverrideConfigBySystemProps() {\n\n        SysProps.setProperty(\"dubbo.registry.address\", \"zookeeper://${zookeeper.address}:${zookeeper.port}\");\n        SysProps.setProperty(\"dubbo.registry.useAsConfigCenter\", \"false\");\n        SysProps.setProperty(\"dubbo.registry.useAsMetadataCenter\", \"false\");\n        SysProps.setProperty(\"zookeeper.address\", \"localhost\");\n        SysProps.setProperty(\"zookeeper.port\", \"2188\");\n\n        DubboBootstrap.getInstance().application(\"demo-app\").initialize();\n        Collection<RegistryConfig> registries =\n                ApplicationModel.defaultModel().getApplicationConfigManager().getRegistries();\n        Assertions.assertEquals(1, registries.size());\n        RegistryConfig registryConfig = registries.iterator().next();\n        Assertions.assertEquals(\"zookeeper://localhost:2188\", registryConfig.getAddress());\n    }\n\n    public void testPreferredWithTrueValue() {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setPreferred(true);\n        Map<String, String> map = new HashMap<>();\n        // process Parameter annotation\n        AbstractConfig.appendParameters(map, registry);\n        // Simulate the check that ZoneAwareClusterInvoker#doInvoke do\n        URL url = UrlUtils.parseURL(ZookeeperRegistryCenterConfig.getConnectionAddress1(), map);\n        Assertions.assertTrue(url.getParameter(PREFERRED_KEY, false));\n    }\n\n    @Test\n    void testPreferredWithFalseValue() {\n        RegistryConfig registry = new RegistryConfig();\n        registry.setPreferred(false);\n        Map<String, String> map = new HashMap<>();\n        // Process Parameter annotation\n        AbstractConfig.appendParameters(map, registry);\n        // Simulate the check that ZoneAwareClusterInvoker#doInvoke do\n        URL url = UrlUtils.parseURL(ZookeeperRegistryCenterConfig.getConnectionAddress1(), map);\n        Assertions.assertFalse(url.getParameter(PREFERRED_KEY, false));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.api.DemoService;\nimport org.apache.dubbo.config.api.Greeting;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.mock.MockProtocol2;\nimport org.apache.dubbo.config.mock.MockRegistryFactory2;\nimport org.apache.dubbo.config.mock.MockServiceListener;\nimport org.apache.dubbo.config.mock.TestProxyFactory;\nimport org.apache.dubbo.config.provider.impl.DemoServiceImpl;\nimport org.apache.dubbo.metadata.MappingListener;\nimport org.apache.dubbo.metadata.ServiceNameMapping;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.google.common.collect.Lists;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_BEAN;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_DEFAULT;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.config.Constants.SHUTDOWN_TIMEOUT_KEY;\nimport static org.apache.dubbo.remoting.Constants.BIND_IP_KEY;\nimport static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY;\nimport static org.apache.dubbo.rpc.Constants.GENERIC_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;\nimport static org.awaitility.Awaitility.await;\nimport static org.hamcrest.CoreMatchers.containsString;\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.hasKey;\nimport static org.hamcrest.Matchers.hasSize;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyLong;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.withSettings;\n\nclass ServiceConfigTest {\n\n    private Protocol protocolDelegate = Mockito.mock(Protocol.class);\n    private Registry registryDelegate = Mockito.mock(Registry.class);\n    private Exporter exporter = Mockito.mock(Exporter.class);\n    private ServiceConfig<DemoServiceImpl> service;\n    private ServiceConfig<DemoServiceImpl> service2;\n    private ServiceConfig<DemoServiceImpl> serviceWithoutRegistryConfig;\n    private ServiceConfig<DemoServiceImpl> delayService;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        DubboBootstrap.reset();\n\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n\n        service = new ServiceConfig<>();\n        service2 = new ServiceConfig<>();\n        serviceWithoutRegistryConfig = new ServiceConfig<>();\n        delayService = new ServiceConfig<>();\n\n        MockProtocol2.delegate = protocolDelegate;\n        MockRegistryFactory2.registry = registryDelegate;\n        Mockito.when(protocolDelegate.export(Mockito.any(Invoker.class))).thenReturn(exporter);\n\n        ApplicationConfig app = new ApplicationConfig(\"app\");\n\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        protocolConfig.setName(\"mockprotocol2\");\n\n        ProviderConfig provider = new ProviderConfig();\n        provider.setExport(true);\n        provider.setProtocol(protocolConfig);\n\n        RegistryConfig registry = new RegistryConfig();\n        registry.setProtocol(\"mockprotocol2\");\n        registry.setAddress(\"N/A\");\n\n        ArgumentConfig argument = new ArgumentConfig();\n        argument.setIndex(0);\n        argument.setCallback(false);\n\n        MethodConfig method = new MethodConfig();\n        method.setName(\"echo\");\n        method.setArguments(Collections.singletonList(argument));\n\n        service.setProvider(provider);\n        service.setApplication(app);\n        service.setRegistry(registry);\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n        service.setMethods(Collections.singletonList(method));\n        service.setGroup(\"demo1\");\n\n        service2.setProvider(provider);\n        service2.setApplication(app);\n        service2.setRegistry(registry);\n        service2.setInterface(DemoService.class);\n        service2.setRef(new DemoServiceImpl());\n        service2.setMethods(Collections.singletonList(method));\n        service2.setProxy(\"testproxyfactory\");\n        service2.setGroup(\"demo2\");\n\n        delayService.setProvider(provider);\n        delayService.setApplication(app);\n        delayService.setRegistry(registry);\n        delayService.setInterface(DemoService.class);\n        delayService.setRef(new DemoServiceImpl());\n        delayService.setMethods(Collections.singletonList(method));\n        delayService.setDelay(100);\n        delayService.setGroup(\"demo3\");\n\n        serviceWithoutRegistryConfig.setProvider(provider);\n        serviceWithoutRegistryConfig.setApplication(app);\n        serviceWithoutRegistryConfig.setInterface(DemoService.class);\n        serviceWithoutRegistryConfig.setRef(new DemoServiceImpl());\n        serviceWithoutRegistryConfig.setMethods(Collections.singletonList(method));\n        serviceWithoutRegistryConfig.setGroup(\"demo4\");\n    }\n\n    @AfterEach\n    public void tearDown() {\n        SysProps.clear();\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testExport() throws Exception {\n        service.export();\n\n        try {\n            assertThat(service.getExportedUrls(), hasSize(1));\n            URL url = service.toUrl();\n            assertThat(url.getProtocol(), equalTo(\"mockprotocol2\"));\n            assertThat(url.getPath(), equalTo(DemoService.class.getName()));\n            assertThat(url.getParameters(), hasEntry(ANYHOST_KEY, \"true\"));\n            assertThat(url.getParameters(), hasEntry(APPLICATION_KEY, \"app\"));\n            assertThat(url.getParameters(), hasKey(BIND_IP_KEY));\n            assertThat(url.getParameters(), hasKey(BIND_PORT_KEY));\n            assertThat(url.getParameters(), hasEntry(EXPORT_KEY, \"true\"));\n            assertThat(url.getParameters(), hasEntry(\"echo.0.callback\", \"false\"));\n            assertThat(url.getParameters(), hasEntry(GENERIC_KEY, \"false\"));\n            assertThat(url.getParameters(), hasEntry(INTERFACE_KEY, DemoService.class.getName()));\n            assertThat(url.getParameters(), hasKey(METHODS_KEY));\n            assertThat(url.getParameters().get(METHODS_KEY), containsString(\"echo\"));\n            assertThat(url.getParameters(), hasEntry(SIDE_KEY, PROVIDER));\n            // export DemoService in \"mockprotocol2\" protocol.\n            Mockito.verify(protocolDelegate, times(1)).export(Mockito.any(Invoker.class));\n            // MetadataService will be exported on either dubbo or triple (the only two default acceptable protocol)\n        } finally {\n            service.unexport();\n        }\n    }\n\n    @Test\n    void testVersionAndGroupConfigFromProvider() {\n        // Service no configuration version , the Provider configured.\n        service.getProvider().setVersion(\"1.0.0\");\n        service.getProvider().setGroup(\"groupA\");\n        service.export();\n\n        try {\n            String serviceVersion = service.getVersion();\n            String serviceVersion2 = service.toUrl().getVersion();\n\n            String group = service.getGroup();\n            String group2 = service.toUrl().getGroup();\n\n            assertEquals(serviceVersion2, serviceVersion);\n            assertEquals(group, group2);\n        } finally {\n            service.unexport();\n        }\n    }\n\n    @Test\n    void testProxy() throws Exception {\n        service2.export();\n\n        try {\n            assertThat(service2.getExportedUrls(), hasSize(1));\n            assertEquals(2, TestProxyFactory.count); // local injvm and registry protocol, so expected is 2\n            TestProxyFactory.count = 0;\n        } finally {\n            service2.unexport();\n        }\n    }\n\n    @Test\n    void testDelayExport() throws Exception {\n        CountDownLatch latch = new CountDownLatch(1);\n        delayService.addServiceListener(new ServiceListener() {\n            @Override\n            public void exported(ServiceConfig sc) {\n                assertEquals(delayService, sc);\n                assertThat(delayService.getExportedUrls(), hasSize(1));\n                latch.countDown();\n            }\n\n            @Override\n            public void unexported(ServiceConfig sc) {}\n        });\n        delayService.export();\n        try {\n            assertTrue(delayService.getExportedUrls().isEmpty());\n            latch.await();\n        } finally {\n            delayService.unexport();\n        }\n    }\n\n    @Test\n    void testUnexport() throws Exception {\n        System.setProperty(SHUTDOWN_WAIT_KEY, \"0\");\n        try {\n            service.export();\n            service.unexport();\n            //            Thread.sleep(1000);\n            Mockito.verify(exporter, Mockito.atLeastOnce()).unexport();\n        } finally {\n            System.clearProperty(SHUTDOWN_TIMEOUT_KEY);\n        }\n    }\n\n    @Test\n    void testInterfaceClass() throws Exception {\n        ServiceConfig<Greeting> service = new ServiceConfig<>();\n        service.setInterface(Greeting.class.getName());\n        service.setRef(Mockito.mock(Greeting.class));\n        assertThat(service.getInterfaceClass() == Greeting.class, is(true));\n        service = new ServiceConfig<>();\n        service.setRef(Mockito.mock(Greeting.class, withSettings().extraInterfaces(GenericService.class)));\n        assertThat(service.getInterfaceClass() == GenericService.class, is(true));\n    }\n\n    @Test\n    void testInterface1() throws Exception {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            ProtocolConfig protocolConfig = new ProtocolConfig(CommonConstants.TRIPLE);\n            ServiceConfig<DemoService> service = new ServiceConfig<>();\n            service.setProtocol(protocolConfig);\n            service.setInterface(DemoServiceImpl.class);\n        });\n    }\n\n    @Test\n    void testInterface2() throws Exception {\n        ServiceConfig<DemoService> service = new ServiceConfig<>();\n        service.setInterface(DemoService.class);\n        assertThat(service.getInterface(), equalTo(DemoService.class.getName()));\n    }\n\n    @Test\n    void testNoInterfaceSupport() throws Exception {\n        ProtocolConfig protocolConfig = new ProtocolConfig(CommonConstants.TRIPLE);\n        protocolConfig.setNoInterfaceSupport(true);\n        ServiceConfig<DemoService> service = new ServiceConfig<>();\n        service.setProtocol(protocolConfig);\n        service.setInterface(DemoServiceImpl.class);\n        assertThat(service.getInterface(), equalTo(DemoServiceImpl.class.getName()));\n    }\n\n    @Test\n    void testProvider() throws Exception {\n        ServiceConfig service = new ServiceConfig();\n        ProviderConfig provider = new ProviderConfig();\n        service.setProvider(provider);\n        assertThat(service.getProvider(), is(provider));\n    }\n\n    @Test\n    void testGeneric1() throws Exception {\n        ServiceConfig service = new ServiceConfig();\n        service.setGeneric(GENERIC_SERIALIZATION_DEFAULT);\n        assertThat(service.getGeneric(), equalTo(GENERIC_SERIALIZATION_DEFAULT));\n        service.setGeneric(GENERIC_SERIALIZATION_NATIVE_JAVA);\n        assertThat(service.getGeneric(), equalTo(GENERIC_SERIALIZATION_NATIVE_JAVA));\n        service.setGeneric(GENERIC_SERIALIZATION_BEAN);\n        assertThat(service.getGeneric(), equalTo(GENERIC_SERIALIZATION_BEAN));\n    }\n\n    @Test\n    void testGeneric2() throws Exception {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            ServiceConfig service = new ServiceConfig();\n            service.setGeneric(\"illegal\");\n        });\n    }\n\n    @Test\n    void testApplicationInUrl() {\n        service.export();\n        try {\n            assertNotNull(service.toUrl().getApplication());\n            Assertions.assertEquals(\"app\", service.toUrl().getApplication());\n        } finally {\n            service.unexport();\n        }\n    }\n\n    @Test\n    void testMetaData() {\n        // test new instance\n        ServiceConfig config = new ServiceConfig();\n        Map<String, String> metaData = config.getMetaData();\n        Assertions.assertEquals(0, metaData.size(), \"Expect empty metadata but found: \" + metaData);\n\n        // test merged and override provider attributes\n        ProviderConfig providerConfig = new ProviderConfig();\n        providerConfig.setAsync(true);\n        providerConfig.setActives(10);\n        config.setProvider(providerConfig);\n        config.setAsync(false); // override\n\n        metaData = config.getMetaData();\n        Assertions.assertEquals(2, metaData.size());\n        Assertions.assertEquals(\"\" + providerConfig.getActives(), metaData.get(\"actives\"));\n        Assertions.assertEquals(\"\" + config.isAsync(), metaData.get(\"async\"));\n    }\n\n    @Test\n    void testExportWithoutRegistryConfig() {\n        serviceWithoutRegistryConfig.export();\n\n        try {\n            assertThat(serviceWithoutRegistryConfig.getExportedUrls(), hasSize(1));\n            URL url = serviceWithoutRegistryConfig.toUrl();\n            assertThat(url.getProtocol(), equalTo(\"mockprotocol2\"));\n            assertThat(url.getPath(), equalTo(DemoService.class.getName()));\n            assertThat(url.getParameters(), hasEntry(ANYHOST_KEY, \"true\"));\n            assertThat(url.getParameters(), hasEntry(APPLICATION_KEY, \"app\"));\n            assertThat(url.getParameters(), hasKey(BIND_IP_KEY));\n            assertThat(url.getParameters(), hasKey(BIND_PORT_KEY));\n            assertThat(url.getParameters(), hasEntry(EXPORT_KEY, \"true\"));\n            assertThat(url.getParameters(), hasEntry(\"echo.0.callback\", \"false\"));\n            assertThat(url.getParameters(), hasEntry(GENERIC_KEY, \"false\"));\n            assertThat(url.getParameters(), hasEntry(INTERFACE_KEY, DemoService.class.getName()));\n            assertThat(url.getParameters(), hasKey(METHODS_KEY));\n            assertThat(url.getParameters().get(METHODS_KEY), containsString(\"echo\"));\n            assertThat(url.getParameters(), hasEntry(SIDE_KEY, PROVIDER));\n            // export DemoService in \"mockprotocol2\" protocol (MetadataService will be not exported if no registry\n            // specified)\n            Mockito.verify(protocolDelegate, times(1)).export(Mockito.any(Invoker.class));\n        } finally {\n            serviceWithoutRegistryConfig.unexport();\n        }\n    }\n\n    @Test\n    void testServiceListener() {\n        ExtensionLoader<ServiceListener> extensionLoader = ExtensionLoader.getExtensionLoader(ServiceListener.class);\n        MockServiceListener mockServiceListener = (MockServiceListener) extensionLoader.getExtension(\"mock\");\n        assertNotNull(mockServiceListener);\n        mockServiceListener.clearExportedServices();\n\n        service.export();\n\n        try {\n            Map<String, ServiceConfig> exportedServices = mockServiceListener.getExportedServices();\n            assertEquals(1, exportedServices.size());\n            ServiceConfig serviceConfig = exportedServices.get(service.getUniqueServiceName());\n            assertSame(service, serviceConfig);\n        } finally {\n            service.unexport();\n        }\n    }\n\n    @Test\n    void testMethodConfigWithInvalidArgumentConfig() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();\n\n            service.setInterface(DemoService.class);\n            service.setRef(new DemoServiceImpl());\n            service.setProtocol(new ProtocolConfig() {\n                {\n                    setName(\"dubbo\");\n                }\n            });\n\n            MethodConfig methodConfig = new MethodConfig();\n            methodConfig.setName(\"sayName\");\n            // invalid argument index.\n            methodConfig.setArguments(Lists.newArrayList(new ArgumentConfig() {\n                {\n                    // unset config.\n                }\n            }));\n            service.setMethods(Lists.newArrayList(methodConfig));\n\n            service.export();\n            service.unexport();\n        });\n    }\n\n    @Test\n    void testMethodConfigWithConfiguredArgumentTypeAndIndex() {\n        ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();\n\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n        service.setProtocol(new ProtocolConfig() {\n            {\n                setName(\"dubbo\");\n            }\n        });\n\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setName(\"sayName\");\n        // invalid argument index.\n        methodConfig.setArguments(Lists.newArrayList(new ArgumentConfig() {\n            {\n                setType(String.class.getName());\n                setIndex(0);\n                setCallback(false);\n            }\n        }));\n        service.setMethods(Lists.newArrayList(methodConfig));\n\n        service.export();\n\n        try {\n            assertFalse(service.getExportedUrls().isEmpty());\n            assertEquals(\n                    \"false\", service.getExportedUrls().get(0).getParameters().get(\"sayName.0.callback\"));\n        } finally {\n            service.unexport();\n        }\n    }\n\n    @Test\n    void testMethodConfigWithConfiguredArgumentIndex() {\n        ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();\n\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n        service.setProtocol(new ProtocolConfig() {\n            {\n                setName(\"dubbo\");\n            }\n        });\n\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setName(\"sayName\");\n        // invalid argument index.\n        methodConfig.setArguments(Lists.newArrayList(new ArgumentConfig() {\n            {\n                setIndex(0);\n                setCallback(false);\n            }\n        }));\n        service.setMethods(Lists.newArrayList(methodConfig));\n\n        service.export();\n\n        try {\n            assertFalse(service.getExportedUrls().isEmpty());\n            assertEquals(\n                    \"false\", service.getExportedUrls().get(0).getParameters().get(\"sayName.0.callback\"));\n        } finally {\n            service.unexport();\n        }\n    }\n\n    @Test\n    void testMethodConfigWithConfiguredArgumentType() {\n        ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();\n\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n        service.setProtocol(new ProtocolConfig() {\n            {\n                setName(\"dubbo\");\n            }\n        });\n\n        MethodConfig methodConfig = new MethodConfig();\n        methodConfig.setName(\"sayName\");\n        // invalid argument index.\n        methodConfig.setArguments(Lists.newArrayList(new ArgumentConfig() {\n            {\n                setType(String.class.getName());\n                setCallback(false);\n            }\n        }));\n        service.setMethods(Lists.newArrayList(methodConfig));\n\n        service.export();\n\n        try {\n            assertFalse(service.getExportedUrls().isEmpty());\n            assertEquals(\n                    \"false\", service.getExportedUrls().get(0).getParameters().get(\"sayName.0.callback\"));\n        } finally {\n            service.unexport();\n        }\n    }\n\n    @Test\n    void testMethodConfigWithUnknownArgumentType() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();\n\n            service.setInterface(DemoService.class);\n            service.setRef(new DemoServiceImpl());\n            service.setProtocol(new ProtocolConfig() {\n                {\n                    setName(\"dubbo\");\n                }\n            });\n\n            MethodConfig methodConfig = new MethodConfig();\n            methodConfig.setName(\"sayName\");\n            // invalid argument index.\n            methodConfig.setArguments(Lists.newArrayList(new ArgumentConfig() {\n                {\n                    setType(Integer.class.getName());\n                    setCallback(false);\n                }\n            }));\n            service.setMethods(Lists.newArrayList(methodConfig));\n\n            service.export();\n            service.unexport();\n        });\n    }\n\n    @Test\n    void testMethodConfigWithUnmatchedArgument() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();\n\n            service.setInterface(DemoService.class);\n            service.setRef(new DemoServiceImpl());\n            service.setProtocol(new ProtocolConfig() {\n                {\n                    setName(\"dubbo\");\n                }\n            });\n\n            MethodConfig methodConfig = new MethodConfig();\n            methodConfig.setName(\"sayName\");\n            // invalid argument index.\n            methodConfig.setArguments(Lists.newArrayList(new ArgumentConfig() {\n                {\n                    setType(Integer.class.getName());\n                    setIndex(0);\n                }\n            }));\n            service.setMethods(Lists.newArrayList(methodConfig));\n\n            service.export();\n            service.unexport();\n        });\n    }\n\n    @Test\n    void testMethodConfigWithInvalidArgumentIndex() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();\n\n            service.setInterface(DemoService.class);\n            service.setRef(new DemoServiceImpl());\n            service.setProtocol(new ProtocolConfig() {\n                {\n                    setName(\"dubbo\");\n                }\n            });\n\n            MethodConfig methodConfig = new MethodConfig();\n            methodConfig.setName(\"sayName\");\n            // invalid argument index.\n            methodConfig.setArguments(Lists.newArrayList(new ArgumentConfig() {\n                {\n                    setType(String.class.getName());\n                    setIndex(1);\n                }\n            }));\n            service.setMethods(Lists.newArrayList(methodConfig));\n\n            service.export();\n            service.unexport();\n        });\n    }\n\n    @Test\n    void testOverride() {\n        System.setProperty(\"dubbo.service.version\", \"TEST\");\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(DemoService.class);\n        serviceConfig.setRef(new DemoServiceImpl());\n        serviceConfig.setVersion(\"1.0.0\");\n        serviceConfig.refresh();\n        Assertions.assertEquals(\"1.0.0\", serviceConfig.getVersion());\n        System.clearProperty(\"dubbo.service.version\");\n    }\n\n    @Test\n    void testMappingRetry() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>(applicationModel.newModule());\n        serviceConfig.exported();\n        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);\n        AtomicInteger count = new AtomicInteger(0);\n        ServiceNameMapping serviceNameMapping = new ServiceNameMapping() {\n            @Override\n            public boolean map(URL url) {\n                if (count.incrementAndGet() < 5) {\n                    throw new RuntimeException();\n                }\n                return count.get() > 10;\n            }\n\n            @Override\n            public boolean hasValidMetadataCenter() {\n                return true;\n            }\n\n            @Override\n            public Set<String> getMapping(URL consumerURL) {\n                return null;\n            }\n\n            @Override\n            public Set<String> getAndListen(URL registryURL, URL subscribedURL, MappingListener listener) {\n                return null;\n            }\n\n            @Override\n            public MappingListener stopListen(URL subscribeURL, MappingListener listener) {\n                return null;\n            }\n\n            @Override\n            public void putCachedMapping(String serviceKey, Set<String> apps) {}\n\n            @Override\n            public Set<String> getRemoteMapping(URL consumerURL) {\n                return null;\n            }\n\n            @Override\n            public Set<String> removeCachedMapping(String serviceKey) {\n                return null;\n            }\n\n            @Override\n            public void $destroy() {}\n        };\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"app\");\n        applicationConfig.setMappingRetryInterval(10);\n        serviceConfig.setApplication(applicationConfig);\n        serviceConfig.mapServiceName(URL.valueOf(\"\"), serviceNameMapping, scheduledExecutorService);\n\n        await().until(() -> count.get() > 10);\n        scheduledExecutorService.shutdown();\n    }\n\n    @Test\n    void testMappingNoRetry() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>(applicationModel.newModule());\n        serviceConfig.exported();\n        ScheduledExecutorService scheduledExecutorService = Mockito.spy(Executors.newScheduledThreadPool(1));\n        AtomicInteger count = new AtomicInteger(0);\n        ServiceNameMapping serviceNameMapping = new ServiceNameMapping() {\n            @Override\n            public boolean map(URL url) {\n                return false;\n            }\n\n            @Override\n            public boolean hasValidMetadataCenter() {\n                return false;\n            }\n\n            @Override\n            public Set<String> getAndListen(URL registryURL, URL subscribedURL, MappingListener listener) {\n                return null;\n            }\n\n            @Override\n            public MappingListener stopListen(URL subscribeURL, MappingListener listener) {\n                return null;\n            }\n\n            @Override\n            public void putCachedMapping(String serviceKey, Set<String> apps) {}\n\n            @Override\n            public Set<String> getMapping(URL consumerURL) {\n                return null;\n            }\n\n            @Override\n            public Set<String> getRemoteMapping(URL consumerURL) {\n                return null;\n            }\n\n            @Override\n            public Set<String> removeCachedMapping(String serviceKey) {\n                return null;\n            }\n\n            @Override\n            public void $destroy() {}\n        };\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"app\");\n        applicationConfig.setMappingRetryInterval(10);\n        serviceConfig.setApplication(applicationConfig);\n        serviceConfig.mapServiceName(URL.valueOf(\"\"), serviceNameMapping, scheduledExecutorService);\n\n        verify(scheduledExecutorService, times(0)).schedule((Runnable) any(), anyLong(), any());\n\n        scheduledExecutorService.shutdown();\n    }\n\n    @Test\n    void testToString() {\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();\n        service.setRef(new DemoServiceImpl() {\n            @Override\n            public String toString() {\n                throw new IllegalStateException();\n            }\n        });\n        try {\n            serviceConfig.toString();\n        } catch (Throwable t) {\n            Assertions.fail(t);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/SysProps.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * Use to set and clear System property\n */\npublic class SysProps {\n\n    private static Map<String, String> map = new LinkedHashMap<String, String>();\n\n    public static void reset() {\n        map.clear();\n    }\n\n    public static void setProperty(String key, String value) {\n        map.put(key, value);\n        System.setProperty(key, value);\n    }\n\n    public static void clear() {\n        for (String key : map.keySet()) {\n            System.clearProperty(key);\n        }\n        reset();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/Box.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.api;\n\npublic interface Box {\n\n    String getName();\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.api;\n\npublic class DemoException extends Exception {\n\n    private static final long serialVersionUID = -8213943026163641747L;\n\n    public DemoException() {\n        super();\n    }\n\n    public DemoException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public DemoException(String message) {\n        super(message);\n    }\n\n    public DemoException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.api;\n\nimport java.io.Serializable;\nimport java.util.List;\n\npublic interface DemoService {\n\n    String sayName(String name);\n\n    Box getBox();\n\n    void throwDemoException() throws DemoException;\n\n    List<User> getUsers(List<User> users);\n\n    int echo(int i);\n\n    default InnerClass callInnerClass() {\n        return new InnerClass();\n    }\n\n    class InnerClass implements Serializable {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/Greeting.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.api;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface Greeting {\n    String hello();\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/User.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.api;\n\nimport java.io.Serializable;\n\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private String name;\n\n    public User() {}\n\n    public User(String name) {\n        this.name = name;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public int hashCode() {\n        return name == null ? -1 : name.hashCode();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof User)) {\n            return false;\n        }\n        User other = (User) obj;\n        if (this == other) {\n            return true;\n        }\n        if (name != null && other.name != null) {\n            return name.equals(other.name);\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.deploy.ApplicationDeployListener;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.config.AbstractInterfaceConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.SysProps;\nimport org.apache.dubbo.config.api.DemoService;\nimport org.apache.dubbo.config.deploy.DefaultApplicationDeployer;\nimport org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter;\nimport org.apache.dubbo.config.metadata.ExporterDeployListener;\nimport org.apache.dubbo.config.nested.TripleConfig;\nimport org.apache.dubbo.config.provider.impl.DemoServiceImpl;\nimport org.apache.dubbo.config.utils.ConfigValidationUtils;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.MetadataReportInstance;\nimport org.apache.dubbo.monitor.MonitorService;\nimport org.apache.dubbo.registry.RegistryService;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Properties;\nimport java.util.stream.Collectors;\n\nimport com.google.common.collect.Maps;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONFIG_NAMESPACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_MONITOR_ADDRESS;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;\nimport static org.apache.dubbo.metadata.MetadataConstants.REPORT_CONSUMER_URL_KEY;\nimport static org.hamcrest.CoreMatchers.anything;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.hasEntry;\nimport static org.hamcrest.Matchers.is;\n\n/**\n * {@link DubboBootstrap} Test\n *\n * @since 2.7.5\n */\nclass DubboBootstrapTest {\n\n    private static File dubboProperties;\n    private static String zkServerAddress;\n\n    @BeforeAll\n    public static void setUp(@TempDir Path folder) {\n        DubboBootstrap.reset();\n        zkServerAddress = System.getProperty(\"zookeeper.connection.address.1\");\n        dubboProperties = folder.resolve(CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY)\n                .toFile();\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY, dubboProperties.getAbsolutePath());\n    }\n\n    @AfterAll\n    public static void tearDown() {\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_PROPERTIES_KEY);\n    }\n\n    @BeforeEach\n    public void beforeEach() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void afterEach() throws IOException {\n        DubboBootstrap.reset();\n        ApplicationModel.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void checkApplication() {\n        SysProps.setProperty(\"dubbo.application.name\", \"demo\");\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.refresh();\n        Assertions.assertEquals(\"demo\", applicationConfig.getName());\n    }\n\n    @Test\n    void compatibleApplicationShutdown() {\n        try {\n            System.clearProperty(SHUTDOWN_WAIT_KEY);\n            System.clearProperty(SHUTDOWN_WAIT_SECONDS_KEY);\n\n            writeDubboProperties(SHUTDOWN_WAIT_KEY, \"100\");\n            ApplicationModel.defaultModel()\n                    .modelEnvironment()\n                    .getPropertiesConfiguration()\n                    .refresh();\n            ConfigValidationUtils.validateApplicationConfig(new ApplicationConfig(\"demo\"));\n            Assertions.assertEquals(\"100\", System.getProperty(SHUTDOWN_WAIT_KEY));\n\n            System.clearProperty(SHUTDOWN_WAIT_KEY);\n            writeDubboProperties(SHUTDOWN_WAIT_SECONDS_KEY, \"1000\");\n            ApplicationModel.defaultModel()\n                    .modelEnvironment()\n                    .getPropertiesConfiguration()\n                    .refresh();\n            ConfigValidationUtils.validateApplicationConfig(new ApplicationConfig(\"demo\"));\n            Assertions.assertEquals(\"1000\", System.getProperty(SHUTDOWN_WAIT_SECONDS_KEY));\n        } finally {\n            System.clearProperty(\"dubbo.application.name\");\n            System.clearProperty(SHUTDOWN_WAIT_KEY);\n            System.clearProperty(SHUTDOWN_WAIT_SECONDS_KEY);\n        }\n    }\n\n    @Test\n    void testLoadRegistries() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setInterface(DemoService.class);\n        serviceConfig.setRef(new DemoServiceImpl());\n        serviceConfig.setApplication(new ApplicationConfig(\"testLoadRegistries\"));\n\n        String registryId = \"nacosRegistry\";\n        String namespace1 = \"test\";\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setId(registryId);\n        registryConfig.setAddress(\"nacos://addr1:8848\");\n        Map<String, String> registryParamMap = Maps.newHashMap();\n        registryParamMap.put(CONFIG_NAMESPACE_KEY, namespace1);\n        registryConfig.setParameters(registryParamMap);\n\n        String namespace2 = \"test2\";\n        RegistryConfig registryConfig2 = new RegistryConfig();\n        registryConfig2.setAddress(\"polaris://addr1:9999\");\n        Map<String, String> registryParamMap2 = Maps.newHashMap();\n        registryParamMap2.put(CONFIG_NAMESPACE_KEY, namespace2);\n        registryConfig2.setParameters(registryParamMap2);\n\n        serviceConfig.setRegistries(Arrays.asList(registryConfig, registryConfig2));\n\n        // load configs from props\n        DubboBootstrap.getInstance().initialize();\n\n        serviceConfig.refresh();\n\n        // ApplicationModel.defaultModel().getEnvironment().setDynamicConfiguration(new\n        // CompositeDynamicConfiguration());\n        List<URL> urls = ConfigValidationUtils.loadRegistries(serviceConfig, true);\n        Assertions.assertEquals(4, urls.size());\n\n        Map<String, List<URL>> urlsMap =\n                urls.stream().collect(Collectors.groupingBy(url -> url.getParameter(REGISTRY_KEY)));\n        Assertions.assertEquals(2, urlsMap.get(\"nacos\").size());\n        for (URL url : urlsMap.get(\"nacos\")) {\n            Assertions.assertTrue(url.getProtocol().contains(\"registry\"));\n            Assertions.assertEquals(\"addr1:8848\", url.getAddress());\n            Assertions.assertEquals(RegistryService.class.getName(), url.getPath());\n            Assertions.assertEquals(registryId + \":\" + namespace1, url.getParameter(REGISTRY_CLUSTER_KEY));\n            Assertions.assertTrue(url.getParameters().containsKey(\"timestamp\"));\n            Assertions.assertTrue(url.getParameters().containsKey(\"pid\"));\n            Assertions.assertTrue(url.getParameters().containsKey(\"registry\"));\n            Assertions.assertTrue(url.getParameters().containsKey(\"dubbo\"));\n        }\n\n        Assertions.assertEquals(2, urlsMap.get(\"polaris\").size());\n        for (URL url : urlsMap.get(\"polaris\")) {\n            Assertions.assertTrue(url.getProtocol().contains(\"registry\"));\n            Assertions.assertEquals(\"addr1:9999\", url.getAddress());\n            Assertions.assertEquals(RegistryService.class.getName(), url.getPath());\n            Assertions.assertEquals(DEFAULT_KEY + \":\" + namespace2, url.getParameter(REGISTRY_CLUSTER_KEY));\n            Assertions.assertTrue(url.getParameters().containsKey(\"timestamp\"));\n            Assertions.assertTrue(url.getParameters().containsKey(\"pid\"));\n            Assertions.assertTrue(url.getParameters().containsKey(\"registry\"));\n            Assertions.assertTrue(url.getParameters().containsKey(\"dubbo\"));\n        }\n    }\n\n    @Test\n    void testRegistryWithMetadataReport() {\n        ServiceConfig serviceConfig = new ServiceConfig();\n        serviceConfig.setInterface(DemoService.class);\n        serviceConfig.setRef(new DemoServiceImpl());\n\n        List<RegistryConfig> registryConfigs = new ArrayList<>();\n        List<MetadataReportConfig> metadataReportConfigs = new ArrayList<>();\n\n        String registryId = \"nacosRegistry\";\n        String namespace1 = \"test\";\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setId(registryId);\n        registryConfig.setAddress(zkServerAddress);\n        Map<String, String> registryParamMap = Maps.newHashMap();\n        registryParamMap.put(CONFIG_NAMESPACE_KEY, namespace1);\n        registryConfig.setParameters(registryParamMap);\n        registryConfigs.add(registryConfig);\n\n        MetadataReportConfig metadataReportConfig = new MetadataReportConfig();\n        metadataReportConfig.setRegistry(registryId);\n        metadataReportConfig.setAddress(registryConfig.getAddress());\n        Map<String, String> metadataParamMap = Maps.newHashMap();\n        metadataParamMap.put(CONFIG_NAMESPACE_KEY, namespace1);\n        metadataParamMap.put(REPORT_CONSUMER_URL_KEY, Boolean.TRUE.toString());\n        metadataReportConfig.setParameters(metadataParamMap);\n        metadataReportConfig.setReportMetadata(true);\n        metadataReportConfigs.add(metadataReportConfig);\n\n        String namespace2 = \"test2\";\n        RegistryConfig registryConfig2 = new RegistryConfig();\n        registryConfig2.setAddress(zkServerAddress);\n        Map<String, String> registryParamMap2 = Maps.newHashMap();\n        registryParamMap2.put(CONFIG_NAMESPACE_KEY, namespace2);\n        registryConfig2.setParameters(registryParamMap2);\n        registryConfigs.add(registryConfig2);\n\n        MetadataReportConfig metadataReportConfig2 = new MetadataReportConfig();\n        metadataReportConfig2.setAddress(registryConfig2.getAddress());\n        Map<String, String> metadataParamMap2 = Maps.newHashMap();\n        metadataParamMap2.put(CONFIG_NAMESPACE_KEY, namespace2);\n        metadataParamMap2.put(REPORT_CONSUMER_URL_KEY, Boolean.TRUE.toString());\n        metadataReportConfig2.setParameters(metadataParamMap2);\n        metadataReportConfig2.setReportMetadata(true);\n        metadataReportConfigs.add(metadataReportConfig2);\n\n        serviceConfig.setRegistries(registryConfigs);\n\n        DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(\"testRegistryWithMetadataReport\"))\n                .registries(registryConfigs)\n                .metadataReports(metadataReportConfigs)\n                .service(serviceConfig)\n                .protocol(new ProtocolConfig(CommonConstants.DUBBO_PROTOCOL, -1))\n                .start();\n\n        ApplicationModel applicationModel = DubboBootstrap.getInstance().getApplicationModel();\n        MetadataReportInstance metadataReportInstance =\n                applicationModel.getBeanFactory().getBean(MetadataReportInstance.class);\n\n        Map<String, MetadataReport> metadataReports = metadataReportInstance.getMetadataReports(true);\n        Assertions.assertEquals(2, metadataReports.size());\n\n        List<URL> urls = ConfigValidationUtils.loadRegistries(serviceConfig, true);\n        Assertions.assertEquals(4, urls.size());\n\n        for (URL url : urls) {\n            Assertions.assertTrue(metadataReports.containsKey(url.getParameter(REGISTRY_CLUSTER_KEY)));\n        }\n    }\n\n    @Test\n    void testLoadUserMonitor_address_only() {\n        // -Ddubbo.monitor.address=monitor-addr:12080\n        SysProps.setProperty(DUBBO_MONITOR_ADDRESS, \"monitor-addr:12080\");\n        URL url = ConfigValidationUtils.loadMonitor(\n                getTestInterfaceConfig(new MonitorConfig()), new ServiceConfigURL(\"dubbo\", \"addr1\", 9090));\n        Assertions.assertEquals(\"monitor-addr:12080\", url.getAddress());\n        Assertions.assertEquals(MonitorService.class.getName(), url.getParameter(\"interface\"));\n        Assertions.assertNotNull(url.getParameter(\"dubbo\"));\n        Assertions.assertNotNull(url.getParameter(\"pid\"));\n        Assertions.assertNotNull(url.getParameter(\"timestamp\"));\n    }\n\n    @Test\n    void testLoadUserMonitor_registry() {\n        // dubbo.monitor.protocol=registry\n        MonitorConfig monitorConfig = new MonitorConfig();\n        monitorConfig.setProtocol(\"registry\");\n\n        URL url = ConfigValidationUtils.loadMonitor(\n                getTestInterfaceConfig(monitorConfig),\n                URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));\n        Assertions.assertEquals(\"dubbo\", url.getProtocol());\n        Assertions.assertEquals(\"registry\", url.getParameter(\"protocol\"));\n    }\n\n    @Test\n    void testLoadUserMonitor_service_discovery() {\n        // dubbo.monitor.protocol=service-discovery-registry\n        MonitorConfig monitorConfig = new MonitorConfig();\n        monitorConfig.setProtocol(\"service-discovery-registry\");\n\n        URL url = ConfigValidationUtils.loadMonitor(\n                getTestInterfaceConfig(monitorConfig),\n                URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));\n        Assertions.assertEquals(\"dubbo\", url.getProtocol());\n        Assertions.assertEquals(\"service-discovery-registry\", url.getParameter(\"protocol\"));\n    }\n\n    @Test\n    void testLoadUserMonitor_no_monitor() {\n        URL url = ConfigValidationUtils.loadMonitor(\n                getTestInterfaceConfig(null), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));\n        Assertions.assertNull(url);\n    }\n\n    @Test\n    void testLoadUserMonitor_user() {\n        // dubbo.monitor.protocol=user\n        MonitorConfig monitorConfig = new MonitorConfig();\n        monitorConfig.setProtocol(\"user\");\n\n        URL url = ConfigValidationUtils.loadMonitor(\n                getTestInterfaceConfig(monitorConfig),\n                URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));\n        Assertions.assertEquals(\"user\", url.getProtocol());\n    }\n\n    @Test\n    void testLoadUserMonitor_user_address() {\n        // dubbo.monitor.address=user://1.2.3.4:5678?k=v\n        MonitorConfig monitorConfig = new MonitorConfig();\n        monitorConfig.setAddress(\"user://1.2.3.4:5678?param1=value1\");\n        URL url = ConfigValidationUtils.loadMonitor(\n                getTestInterfaceConfig(monitorConfig),\n                URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));\n        Assertions.assertEquals(\"user\", url.getProtocol());\n        Assertions.assertEquals(\"1.2.3.4:5678\", url.getAddress());\n        Assertions.assertEquals(\"value1\", url.getParameter(\"param1\"));\n    }\n\n    private InterfaceConfig getTestInterfaceConfig(MonitorConfig monitorConfig) {\n        InterfaceConfig interfaceConfig = new InterfaceConfig();\n        interfaceConfig.setApplication(new ApplicationConfig(\"testLoadMonitor\"));\n        if (monitorConfig != null) {\n            interfaceConfig.setMonitor(monitorConfig);\n        }\n        return interfaceConfig;\n    }\n\n    @Test\n    void testBootstrapStart() {\n        ServiceConfig<DemoService> service = new ServiceConfig<>();\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance();\n        bootstrap\n                .application(new ApplicationConfig(\"bootstrap-test\"))\n                .registry(new RegistryConfig(zkServerAddress))\n                .protocol(new ProtocolConfig(CommonConstants.DUBBO_PROTOCOL, -1))\n                .service(service)\n                .start();\n\n        Assertions.assertTrue(bootstrap.isInitialized());\n        Assertions.assertTrue(bootstrap.isCompletion());\n        Assertions.assertFalse(bootstrap.isStopped());\n\n        ApplicationModel applicationModel = bootstrap.getApplicationModel();\n        DefaultApplicationDeployer applicationDeployer = getApplicationDeployer(applicationModel);\n        Assertions.assertNotNull(ReflectUtils.getFieldValue(applicationDeployer, \"asyncMetadataFuture\"));\n        Assertions.assertTrue(applicationModel\n                        .getDefaultModule()\n                        .getServiceRepository()\n                        .getExportedServices()\n                        .size()\n                > 0);\n    }\n\n    private DefaultApplicationDeployer getApplicationDeployer(ApplicationModel applicationModel) {\n        return (DefaultApplicationDeployer) DefaultApplicationDeployer.get(applicationModel);\n    }\n\n    @Test\n    void testLocalMetadataServiceExporter() {\n        ServiceConfig<DemoService> service = new ServiceConfig<>();\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n\n        int availablePort = NetUtils.getAvailablePort();\n\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"bootstrap-test\");\n        applicationConfig.setMetadataServicePort(availablePort);\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance();\n        bootstrap\n                .application(applicationConfig)\n                .registry(new RegistryConfig(zkServerAddress))\n                .protocol(new ProtocolConfig(CommonConstants.DUBBO_PROTOCOL, -1))\n                .service(service)\n                .start();\n\n        assertMetadataService(bootstrap, availablePort, true);\n    }\n\n    @Test\n    void testRemoteMetadataServiceExporter() {\n        ServiceConfig<DemoService> service = new ServiceConfig<>();\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n\n        int availablePort = NetUtils.getAvailablePort();\n\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"bootstrap-test\");\n        applicationConfig.setMetadataServicePort(availablePort);\n        applicationConfig.setMetadataType(REMOTE_METADATA_STORAGE_TYPE);\n\n        RegistryConfig registryConfig = new RegistryConfig(zkServerAddress);\n        registryConfig.setUseAsMetadataCenter(false);\n        registryConfig.setUseAsConfigCenter(false);\n\n        DubboBootstrap.getInstance()\n                .application(applicationConfig)\n                .registry(registryConfig)\n                .protocol(new ProtocolConfig(CommonConstants.DUBBO_PROTOCOL, -1))\n                .service(service)\n                .metadataReport(new MetadataReportConfig(zkServerAddress))\n                .start();\n\n        assertMetadataService(DubboBootstrap.getInstance(), availablePort, false);\n    }\n\n    @Test\n    void testRemoteMetadataServiceExporterCheckMetadataType() {\n\n        Assertions.assertThrowsExactly(IllegalStateException.class, () -> {\n            ServiceConfig<DemoService> service = new ServiceConfig<>();\n            service.setInterface(DemoService.class);\n            service.setRef(new DemoServiceImpl());\n\n            int availablePort = NetUtils.getAvailablePort();\n\n            ApplicationConfig applicationConfig = new ApplicationConfig(\"bootstrap-test\");\n            applicationConfig.setMetadataServicePort(availablePort);\n            applicationConfig.setMetadataType(REMOTE_METADATA_STORAGE_TYPE);\n\n            RegistryConfig registryConfig = new RegistryConfig(zkServerAddress);\n            registryConfig.setUseAsMetadataCenter(false);\n            registryConfig.setUseAsConfigCenter(false);\n\n            DubboBootstrap.getInstance()\n                    .application(applicationConfig)\n                    .registry(registryConfig)\n                    .protocol(new ProtocolConfig(CommonConstants.DUBBO_PROTOCOL, -1))\n                    .service(service)\n                    .start();\n        });\n    }\n\n    @Test\n    void testDefaultTriple() {\n        ServiceConfig<DemoService> service = new ServiceConfig<>();\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n\n        TripleConfig triple = new TripleConfig();\n        triple.setMaxBodySize(50);\n        triple.setMaxResponseBodySize(100);\n\n        ProtocolConfig protocolConfig = new ProtocolConfig(CommonConstants.DUBBO_PROTOCOL, -1);\n        protocolConfig.setTriple(triple);\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance();\n        bootstrap\n                .application(new ApplicationConfig(\"bootstrap-test\"))\n                .registry(new RegistryConfig(zkServerAddress))\n                .protocol(protocolConfig)\n                .service(service)\n                .start();\n\n        TripleConfig tripleConfig = bootstrap\n                .getConfigManager()\n                .getProtocol(protocolConfig.getName())\n                .flatMap(protocol -> Optional.of(protocol.getTriple()))\n                .orElse(null);\n\n        // check custom value\n        Assertions.assertEquals(50, tripleConfig.getMaxBodySizeOrDefault());\n        Assertions.assertEquals(100, tripleConfig.getMaxResponseBodySizeOrDefault());\n\n        // check default value\n        Assertions.assertEquals(1 << 23, tripleConfig.getMaxChunkSizeOrDefault());\n        Assertions.assertEquals(8192, tripleConfig.getMaxHeaderSizeOrDefault());\n        Assertions.assertEquals(4096, tripleConfig.getMaxInitialLineLengthOrDefault());\n        Assertions.assertEquals(16384, tripleConfig.getInitialBufferSizeOrDefault());\n        Assertions.assertEquals(4096, tripleConfig.getHeaderTableSizeOrDefault());\n        Assertions.assertFalse(tripleConfig.getEnablePushOrDefault());\n        Assertions.assertEquals(Integer.MAX_VALUE, tripleConfig.getMaxConcurrentStreamsOrDefault());\n        Assertions.assertEquals(1 << 23, tripleConfig.getInitialWindowSizeOrDefault());\n        Assertions.assertEquals(1 << 16, tripleConfig.getConnectionInitialWindowSizeOrDefault());\n        Assertions.assertEquals(1 << 23, tripleConfig.getMaxFrameSizeOrDefault());\n        Assertions.assertEquals(1 << 15, tripleConfig.getMaxHeaderListSizeOrDefault());\n    }\n\n    private ExporterDeployListener getListener(ApplicationModel model) {\n        return (ExporterDeployListener)\n                model.getExtensionLoader(ApplicationDeployListener.class).getExtension(\"exporter\");\n    }\n\n    private void assertMetadataService(DubboBootstrap bootstrap, int availablePort, boolean metadataExported) {\n        ExporterDeployListener listener = getListener(bootstrap.getApplicationModel());\n        ConfigurableMetadataServiceExporter metadataServiceExporter = listener.getMetadataServiceExporter();\n        Assertions.assertEquals(metadataExported, metadataServiceExporter.isExported());\n        DubboProtocol protocol = DubboProtocol.getDubboProtocol(bootstrap.getApplicationModel());\n        Map<String, Exporter<?>> exporters = protocol.getExporterMap();\n        if (metadataExported) {\n            Assertions.assertEquals(2, exporters.size());\n\n            ServiceConfig<MetadataService> serviceConfig = new ServiceConfig<>();\n            serviceConfig.setRegistry(new RegistryConfig(\"N/A\"));\n            serviceConfig.setInterface(MetadataService.class);\n            serviceConfig.setGroup(\n                    ApplicationModel.defaultModel().getCurrentConfig().getName());\n            serviceConfig.setVersion(MetadataService.VERSION);\n            assertThat(exporters, hasEntry(is(serviceConfig.getUniqueServiceName() + \":\" + availablePort), anything()));\n        } else {\n            Assertions.assertEquals(1, exporters.size());\n        }\n    }\n\n    private void writeDubboProperties(String key, String value) {\n        OutputStream os = null;\n        try {\n            os = new BufferedOutputStream(new FileOutputStream(dubboProperties));\n            Properties properties = new Properties();\n            properties.put(key, value);\n            properties.store(os, \"\");\n            os.close();\n        } catch (IOException e) {\n            if (os != null) {\n                try {\n                    os.close();\n                } catch (IOException ioe) {\n                    // ignore\n                }\n            }\n        }\n    }\n\n    public static class InterfaceConfig extends AbstractInterfaceConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/MultiInstanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap;\n\nimport org.apache.dubbo.common.deploy.ApplicationDeployer;\nimport org.apache.dubbo.common.deploy.DeployListener;\nimport org.apache.dubbo.common.deploy.DeployState;\nimport org.apache.dubbo.common.deploy.ModuleDeployer;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigKeys;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.SysProps;\nimport org.apache.dubbo.config.api.DemoService;\nimport org.apache.dubbo.config.api.Greeting;\nimport org.apache.dubbo.config.context.ConfigMode;\nimport org.apache.dubbo.config.mock.GreetingLocal2;\nimport org.apache.dubbo.config.provider.impl.DemoServiceImpl;\nimport org.apache.dubbo.registry.client.migration.MigrationInvoker;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.FrameworkServiceRepository;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.test.check.DubboTestChecker;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.remoting.Constants.EVENT_LOOP_BOSS_POOL_NAME;\n\n@Disabled\nclass MultiInstanceTest {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MultiInstanceTest.class);\n\n    private RegistryConfig registryConfig;\n\n    private static DubboTestChecker testChecker;\n    private static String testClassName;\n\n    @BeforeEach\n    public void beforeAll() {\n        FrameworkModel.destroyAll();\n        registryConfig = new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress1());\n\n        // pre-check threads\n        // precheckUnclosedThreads();\n    }\n\n    @AfterEach\n    public void afterAll() throws Exception {\n        FrameworkModel.destroyAll();\n\n        // check threads\n        // checkUnclosedThreads();\n    }\n\n    private static Map<Thread, StackTraceElement[]> precheckUnclosedThreads() throws IOException {\n        // create a special DubboTestChecker\n        if (testChecker == null) {\n            testChecker = new DubboTestChecker();\n            testChecker.init(null);\n            testClassName = MultiInstanceTest.class.getName();\n        }\n        return testChecker.checkUnclosedThreads(testClassName, 0);\n    }\n\n    private static void checkUnclosedThreads() {\n        Map<Thread, StackTraceElement[]> unclosedThreadMap = testChecker.checkUnclosedThreads(testClassName, 3000);\n        if (unclosedThreadMap.size() > 0) {\n            String str = getStackTraceString(unclosedThreadMap);\n            Assertions.fail(\"Found unclosed threads: \" + unclosedThreadMap.size() + \"\\n\" + str);\n        }\n    }\n\n    private static String getStackTraceString(Map<Thread, StackTraceElement[]> unclosedThreadMap) {\n        StringBuilder sb = new StringBuilder();\n        for (Thread thread : unclosedThreadMap.keySet()) {\n            sb.append(DubboTestChecker.getFullStacktrace(thread, unclosedThreadMap.get(thread)));\n            sb.append(\"\\n\");\n        }\n        return sb.toString();\n    }\n\n    @BeforeEach\n    public void setup() {\n        FrameworkModel.destroyAll();\n    }\n\n    @AfterEach\n    public void afterEach() {\n        SysProps.clear();\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testIsolatedApplications() {\n\n        DubboBootstrap dubboBootstrap1 = DubboBootstrap.newInstance(new FrameworkModel());\n        DubboBootstrap dubboBootstrap2 = DubboBootstrap.newInstance(new FrameworkModel());\n        try {\n            ApplicationModel applicationModel1 = dubboBootstrap1.getApplicationModel();\n            ApplicationModel applicationModel2 = dubboBootstrap2.getApplicationModel();\n            Assertions.assertNotSame(applicationModel1, applicationModel2);\n            Assertions.assertNotSame(applicationModel1.getFrameworkModel(), applicationModel2.getFrameworkModel());\n            Assertions.assertNotSame(dubboBootstrap1.getConfigManager(), dubboBootstrap2.getConfigManager());\n\n            // bootstrap1: provider app\n            configProviderApp(dubboBootstrap1).start();\n\n            // bootstrap2: consumer app\n            configConsumerApp(dubboBootstrap2).start();\n            testConsumer(dubboBootstrap2);\n\n            DemoService demoServiceFromProvider = dubboBootstrap1.getCache().get(DemoService.class);\n            Assertions.assertNull(demoServiceFromProvider);\n        } finally {\n            dubboBootstrap2.destroy();\n            dubboBootstrap1.destroy();\n        }\n    }\n\n    @Test\n    void testDefaultProviderApplication() {\n        DubboBootstrap dubboBootstrap = DubboBootstrap.getInstance();\n        try {\n            configProviderApp(dubboBootstrap).start();\n        } finally {\n            dubboBootstrap.destroy();\n            DubboBootstrap.reset();\n        }\n    }\n\n    @Test\n    void testDefaultConsumerApplication() {\n        SysProps.setProperty(\"dubbo.consumer.check\", \"false\");\n        DubboBootstrap dubboBootstrap = DubboBootstrap.getInstance();\n        try {\n            configConsumerApp(dubboBootstrap).start();\n            testConsumer(dubboBootstrap);\n        } catch (Exception e) {\n            Assertions.assertTrue(e.toString().contains(\"No provider available\"), StringUtils.toString(e));\n        } finally {\n            dubboBootstrap.destroy();\n            DubboBootstrap.reset();\n            SysProps.clear();\n        }\n    }\n\n    @Test\n    void testDefaultMixedApplication() {\n        DubboBootstrap dubboBootstrap = DubboBootstrap.getInstance();\n        try {\n            dubboBootstrap.application(\"mixed-app\");\n            configProviderApp(dubboBootstrap);\n            configConsumerApp(dubboBootstrap);\n            dubboBootstrap.start();\n\n            testConsumer(dubboBootstrap);\n        } finally {\n            dubboBootstrap.destroy();\n            DubboBootstrap.reset();\n        }\n    }\n\n    @Test\n    void testSharedApplications() {\n\n        FrameworkModel frameworkModel = new FrameworkModel();\n        DubboBootstrap dubboBootstrap1 = DubboBootstrap.newInstance(frameworkModel);\n        DubboBootstrap dubboBootstrap2 = DubboBootstrap.newInstance(frameworkModel);\n        try {\n            ApplicationModel applicationModel1 = dubboBootstrap1.getApplicationModel();\n            ApplicationModel applicationModel2 = dubboBootstrap2.getApplicationModel();\n            Assertions.assertNotSame(applicationModel1, applicationModel2);\n            Assertions.assertSame(applicationModel1.getFrameworkModel(), applicationModel2.getFrameworkModel());\n            Assertions.assertNotSame(dubboBootstrap1.getConfigManager(), dubboBootstrap2.getConfigManager());\n\n            configProviderApp(dubboBootstrap1).start();\n            configConsumerApp(dubboBootstrap2).start();\n            testConsumer(dubboBootstrap2);\n        } finally {\n            dubboBootstrap1.destroy();\n            dubboBootstrap2.destroy();\n        }\n    }\n\n    @Test\n    void testMultiModuleApplication() throws InterruptedException {\n\n        // SysProps.setProperty(METADATA_PUBLISH_DELAY_KEY, \"100\");\n        String version1 = \"1.0\";\n        String version2 = \"2.0\";\n        String version3 = \"3.0\";\n\n        DubboBootstrap providerBootstrap = null;\n        DubboBootstrap consumerBootstrap = null;\n\n        try {\n            // provider app\n            providerBootstrap = DubboBootstrap.newInstance();\n\n            ServiceConfig serviceConfig1 = new ServiceConfig();\n            serviceConfig1.setInterface(DemoService.class);\n            serviceConfig1.setRef(new DemoServiceImpl());\n            serviceConfig1.setVersion(version1);\n\n            ServiceConfig serviceConfig2 = new ServiceConfig();\n            serviceConfig2.setInterface(DemoService.class);\n            serviceConfig2.setRef(new DemoServiceImpl());\n            serviceConfig2.setVersion(version2);\n\n            ServiceConfig serviceConfig3 = new ServiceConfig();\n            serviceConfig3.setInterface(DemoService.class);\n            serviceConfig3.setRef(new DemoServiceImpl());\n            serviceConfig3.setVersion(version3);\n\n            providerBootstrap\n                    .application(\"provider-app\")\n                    .registry(registryConfig)\n                    .protocol(new ProtocolConfig(\"dubbo\", -1))\n                    .service(serviceConfig1)\n                    .newModule()\n                    .service(serviceConfig2)\n                    .endModule()\n                    .newModule()\n                    .service(serviceConfig3)\n                    .endModule();\n\n            ApplicationModel applicationModel = providerBootstrap.getApplicationModel();\n            List<ModuleModel> moduleModels = applicationModel.getModuleModels();\n            Assertions.assertEquals(4, moduleModels.size());\n            Assertions.assertSame(moduleModels.get(0), applicationModel.getInternalModule());\n            Assertions.assertSame(moduleModels.get(1), applicationModel.getDefaultModule());\n            Assertions.assertSame(applicationModel.getDefaultModule(), serviceConfig1.getScopeModel());\n            Assertions.assertSame(moduleModels.get(2), serviceConfig2.getScopeModel());\n            Assertions.assertSame(moduleModels.get(3), serviceConfig3.getScopeModel());\n            Assertions.assertNotSame(applicationModel.getDefaultModule(), applicationModel.getInternalModule());\n\n            providerBootstrap.start();\n\n            // Thread.sleep(200);\n\n            // consumer app\n            consumerBootstrap = DubboBootstrap.newInstance();\n            consumerBootstrap\n                    .application(\"consumer-app\")\n                    .registry(registryConfig)\n                    .reference(builder -> builder.interfaceClass(DemoService.class)\n                            .version(version1)\n                            .injvm(false))\n                    .newModule()\n                    .reference(builder -> builder.interfaceClass(DemoService.class)\n                            .version(version2)\n                            .injvm(false))\n                    .endModule();\n            consumerBootstrap.start();\n\n            DemoService referProxy1 = consumerBootstrap.getCache().get(DemoService.class.getName() + \":\" + version1);\n            Assertions.assertEquals(\"say:dubbo\", referProxy1.sayName(\"dubbo\"));\n\n            DemoService referProxy2 = consumerBootstrap.getCache().get(DemoService.class.getName() + \":\" + version2);\n            Assertions.assertEquals(\"say:dubbo\", referProxy2.sayName(\"dubbo\"));\n\n            Assertions.assertNotEquals(referProxy1, referProxy2);\n        } finally {\n            if (providerBootstrap != null) {\n                providerBootstrap.destroy();\n            }\n            if (consumerBootstrap != null) {\n                consumerBootstrap.destroy();\n            }\n        }\n    }\n\n    @Test\n    void testMultiProviderApplicationsStopOneByOne() {\n        FrameworkModel.destroyAll();\n\n        String version1 = \"1.0\";\n        String version2 = \"2.0\";\n\n        DubboBootstrap providerBootstrap1 = null;\n        DubboBootstrap providerBootstrap2 = null;\n\n        try {\n\n            // save threads before provider app 1\n            Map<Thread, StackTraceElement[]> stackTraces0 = Thread.getAllStackTraces();\n\n            // start provider app 1\n            ServiceConfig serviceConfig1 = new ServiceConfig();\n            serviceConfig1.setInterface(DemoService.class);\n            serviceConfig1.setRef(new DemoServiceImpl());\n            serviceConfig1.setVersion(version1);\n\n            ProtocolConfig protocolConfig1 = new ProtocolConfig(\"dubbo\", NetUtils.getAvailablePort());\n\n            providerBootstrap1 = DubboBootstrap.getInstance();\n            providerBootstrap1\n                    .application(\"provider1\")\n                    .registry(new RegistryConfig(registryConfig.getAddress()))\n                    .service(serviceConfig1)\n                    .protocol(protocolConfig1)\n                    .start();\n\n            // save threads of provider app 1\n            Map<Thread, StackTraceElement[]> lastAllThreadStackTraces = Thread.getAllStackTraces();\n            Map<Thread, StackTraceElement[]> stackTraces1 = findNewThreads(lastAllThreadStackTraces, stackTraces0);\n            Assertions.assertTrue(stackTraces1.size() > 0, \"Get threads of provider app 1 failed\");\n\n            // start zk server 2\n            RegistryConfig registryConfig2 = new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress2());\n\n            // start provider app 2 use a difference zk server 2\n            ServiceConfig serviceConfig2 = new ServiceConfig();\n            serviceConfig2.setInterface(DemoService.class);\n            serviceConfig2.setRef(new DemoServiceImpl());\n            serviceConfig2.setVersion(version2);\n\n            ProtocolConfig protocolConfig2 = new ProtocolConfig(\"dubbo\", NetUtils.getAvailablePort());\n\n            providerBootstrap2 = DubboBootstrap.newInstance();\n            providerBootstrap2\n                    .application(\"provider2\")\n                    .registry(registryConfig2)\n                    .service(serviceConfig2)\n                    .protocol(protocolConfig2)\n                    .start();\n\n            // save threads of provider app 2\n            Map<Thread, StackTraceElement[]> stackTraces2 = findNewThreads(Thread.getAllStackTraces(), stackTraces0);\n            Assertions.assertTrue(stackTraces2.size() > 0, \"Get threads of provider app 2 failed\");\n\n            // stop provider app 1 and check threads\n            providerBootstrap1.stop();\n\n            // TODO Remove ignore thread prefix of NettyServerBoss if supporting close protocol server only used by one\n            // application\n            // see org.apache.dubbo.config.deploy.DefaultApplicationDeployer.postDestroy\n            // NettyServer will close when all applications are shutdown, but not close if any application of the\n            // framework is alive, just ignore it currently\n            checkUnclosedThreadsOfApp(stackTraces1, \"Found unclosed threads of app 1: \", new String[] {\n                EVENT_LOOP_BOSS_POOL_NAME, \"Dubbo-global-shared-handler\", \"Dubbo-framework\"\n            });\n\n            // stop provider app 2 and check threads\n            providerBootstrap2.stop();\n            // shutdown register center after dubbo application to avoid unregister services blocking\n            checkUnclosedThreadsOfApp(stackTraces2, \"Found unclosed threads of app 2: \", null);\n\n        } finally {\n            if (providerBootstrap1 != null) {\n                providerBootstrap1.stop();\n            }\n            if (providerBootstrap2 != null) {\n                providerBootstrap2.stop();\n            }\n        }\n    }\n\n    private Map<Thread, StackTraceElement[]> findNewThreads(\n            Map<Thread, StackTraceElement[]> newAllThreadMap, Map<Thread, StackTraceElement[]> prevThreadMap) {\n        Map<Thread, StackTraceElement[]> deltaThreadMap = new HashMap<>(newAllThreadMap);\n        deltaThreadMap.keySet().removeAll(prevThreadMap.keySet());\n        // expect deltaThreadMap not contains any elements of prevThreadMap\n        Assertions.assertFalse(deltaThreadMap.keySet().stream()\n                .filter(thread -> prevThreadMap.containsKey(thread))\n                .findAny()\n                .isPresent());\n        return deltaThreadMap;\n    }\n\n    private void checkUnclosedThreadsOfApp(\n            Map<Thread, StackTraceElement[]> stackTraces1, String msg, String[] ignoredThreadPrefixes) {\n        int waitTimeMs = 5000;\n        try {\n            Thread.sleep(waitTimeMs);\n        } catch (InterruptedException e) {\n        }\n        HashMap<Thread, StackTraceElement[]> unclosedThreadMap1 = new HashMap<>(stackTraces1);\n        unclosedThreadMap1.keySet().removeIf(thread -> !thread.isAlive());\n        if (ignoredThreadPrefixes != null && ignoredThreadPrefixes.length > 0) {\n            unclosedThreadMap1.keySet().removeIf(thread -> isIgnoredThread(thread.getName(), ignoredThreadPrefixes));\n        }\n        if (unclosedThreadMap1.size() > 0) {\n            String str = getStackTraceString(unclosedThreadMap1);\n            Assertions.fail(msg + unclosedThreadMap1.size() + \"\\n\" + str);\n        }\n    }\n\n    private boolean isIgnoredThread(String name, String[] ignoredThreadPrefixes) {\n        if (ignoredThreadPrefixes != null && ignoredThreadPrefixes.length > 0) {\n            for (String prefix : ignoredThreadPrefixes) {\n                if (name.startsWith(prefix)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    @Test\n    void testMultiModuleDeployAndReload() throws Exception {\n\n        String version1 = \"1.0\";\n        String version2 = \"2.0\";\n        String version3 = \"3.0\";\n\n        String serviceKey1 = DemoService.class.getName() + \":\" + version1;\n        String serviceKey2 = DemoService.class.getName() + \":\" + version2;\n        String serviceKey3 = DemoService.class.getName() + \":\" + version3;\n\n        DubboBootstrap providerBootstrap = null;\n        DubboBootstrap consumerBootstrap = null;\n\n        try {\n            // provider app\n            providerBootstrap = DubboBootstrap.newInstance();\n\n            ServiceConfig serviceConfig1 = new ServiceConfig();\n            serviceConfig1.setInterface(DemoService.class);\n            serviceConfig1.setRef(new DemoServiceImpl());\n            serviceConfig1.setVersion(version1);\n\n            // provider module 1\n            providerBootstrap\n                    .application(\"provider-app\")\n                    .registry(registryConfig)\n                    .protocol(new ProtocolConfig(\"dubbo\", -1))\n                    .service(builder -> builder.interfaceClass(Greeting.class).ref(new GreetingLocal2()))\n                    .newModule()\n                    .service(serviceConfig1)\n                    .endModule();\n\n            ApplicationModel applicationModel = providerBootstrap.getApplicationModel();\n            List<ModuleModel> moduleModels = applicationModel.getModuleModels();\n            Assertions.assertEquals(3, moduleModels.size());\n            Assertions.assertSame(moduleModels.get(0), applicationModel.getInternalModule());\n            Assertions.assertSame(moduleModels.get(1), applicationModel.getDefaultModule());\n            Assertions.assertSame(moduleModels.get(2), serviceConfig1.getScopeModel());\n\n            ModuleDeployer moduleDeployer1 = serviceConfig1.getScopeModel().getDeployer();\n            moduleDeployer1.start().get();\n            Assertions.assertTrue(moduleDeployer1.isCompletion());\n            ModuleDeployer internalModuleDeployer =\n                    applicationModel.getInternalModule().getDeployer();\n            Assertions.assertTrue(internalModuleDeployer.isCompletion());\n\n            FrameworkServiceRepository frameworkServiceRepository =\n                    applicationModel.getFrameworkModel().getServiceRepository();\n            Assertions.assertNotNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey1));\n            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey2));\n            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey3));\n\n            // consumer module 1\n            consumerBootstrap = DubboBootstrap.newInstance();\n            consumerBootstrap\n                    .application(\"consumer-app\")\n                    .registry(registryConfig)\n                    .reference(builder -> builder.interfaceClass(DemoService.class)\n                            .version(version1)\n                            .injvm(false));\n            consumerBootstrap.start();\n\n            DemoService referProxy1 = consumerBootstrap.getCache().get(serviceKey1);\n            String result1 = referProxy1.sayName(\"dubbo\");\n            Assertions.assertEquals(\"say:dubbo\", result1);\n\n            // destroy provider module 1\n            serviceConfig1.getScopeModel().destroy();\n\n            // provider module 2\n            ServiceConfig serviceConfig2 = new ServiceConfig();\n            serviceConfig2.setInterface(DemoService.class);\n            serviceConfig2.setRef(new DemoServiceImpl());\n            serviceConfig2.setVersion(version2);\n\n            providerBootstrap.newModule().service(serviceConfig2).endModule();\n\n            // start provider module 2 and wait\n            serviceConfig2.getScopeModel().getDeployer().start().get();\n            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey1));\n            Assertions.assertNotNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey2));\n            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey3));\n\n            // consumer module2\n            ModuleModel consumerModule2 = consumerBootstrap\n                    .newModule()\n                    .reference(builder -> builder.interfaceClass(DemoService.class)\n                            .version(version2)\n                            .injvm(false))\n                    .getModuleModel();\n\n            ModuleDeployer moduleDeployer2 = consumerModule2.getDeployer();\n            moduleDeployer2.start().get();\n\n            DemoService referProxy2 = moduleDeployer2.getReferenceCache().get(serviceKey2);\n            String result2 = referProxy2.sayName(\"dubbo2\");\n            Assertions.assertEquals(\"say:dubbo2\", result2);\n\n            // destroy provider module 2\n            serviceConfig2.getScopeModel().destroy();\n\n            // provider module 3\n            ServiceConfig serviceConfig3 = new ServiceConfig();\n            serviceConfig3.setInterface(DemoService.class);\n            serviceConfig3.setRef(new DemoServiceImpl());\n            serviceConfig3.setVersion(version3);\n\n            providerBootstrap.newModule().service(serviceConfig3).endModule();\n\n            serviceConfig3.getScopeModel().getDeployer().start().get();\n            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey1));\n            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey2));\n            Assertions.assertNotNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey3));\n\n            // consumer module3\n            ModuleModel consumerModule3 = consumerBootstrap\n                    .newModule()\n                    .reference(builder -> builder.interfaceClass(DemoService.class)\n                            .version(version3)\n                            .injvm(false))\n                    .getModuleModel();\n\n            consumerBootstrap.start();\n\n            DemoService referProxy3 =\n                    consumerModule3.getDeployer().getReferenceCache().get(serviceKey3);\n            String result3 = referProxy3.sayName(\"dubbo3\");\n            Assertions.assertEquals(\"say:dubbo3\", result3);\n\n        } finally {\n            if (providerBootstrap != null) {\n                providerBootstrap.destroy();\n            }\n            if (consumerBootstrap != null) {\n                consumerBootstrap.destroy();\n            }\n        }\n    }\n\n    @Test\n    void testBothStartByModuleAndByApplication() throws Exception {\n        String version1 = \"1.0\";\n        String version2 = \"2.0\";\n        String version3 = \"3.0\";\n\n        String serviceKey1 = DemoService.class.getName() + \":\" + version1;\n        String serviceKey2 = DemoService.class.getName() + \":\" + version2;\n        String serviceKey3 = DemoService.class.getName() + \":\" + version3;\n\n        // provider app\n        DubboBootstrap providerBootstrap = null;\n        try {\n            providerBootstrap = DubboBootstrap.newInstance();\n\n            ServiceConfig serviceConfig1 = new ServiceConfig();\n            serviceConfig1.setInterface(DemoService.class);\n            serviceConfig1.setRef(new DemoServiceImpl());\n            serviceConfig1.setVersion(version1);\n\n            // provider module 1\n            providerBootstrap\n                    .application(\"provider-app\")\n                    .registry(registryConfig)\n                    .protocol(new ProtocolConfig(\"dubbo\", -1))\n                    .service(builder -> builder.interfaceClass(Greeting.class).ref(new GreetingLocal2()))\n                    .newModule()\n                    .service(serviceConfig1)\n                    .endModule();\n\n            // 1. start module1 and wait\n            ModuleDeployer moduleDeployer1 = serviceConfig1.getScopeModel().getDeployer();\n            moduleDeployer1.start().get();\n            Assertions.assertEquals(DeployState.COMPLETION, moduleDeployer1.getState());\n\n            ApplicationModel applicationModel = providerBootstrap.getApplicationModel();\n            ApplicationDeployer applicationDeployer = applicationModel.getDeployer();\n            Assertions.assertEquals(DeployState.STARTING, applicationDeployer.getState());\n            ModuleModel defaultModule = applicationModel.getDefaultModule();\n            Assertions.assertEquals(\n                    DeployState.PENDING, defaultModule.getDeployer().getState());\n\n            // 2. start application after module1 is started\n            providerBootstrap.start();\n            Assertions.assertEquals(DeployState.COMPLETION, applicationDeployer.getState());\n            Assertions.assertEquals(\n                    DeployState.COMPLETION, defaultModule.getDeployer().getState());\n\n            // 3. add module2 and re-start application\n            ServiceConfig serviceConfig2 = new ServiceConfig();\n            serviceConfig2.setInterface(DemoService.class);\n            serviceConfig2.setRef(new DemoServiceImpl());\n            serviceConfig2.setVersion(version2);\n            ModuleModel moduleModel2 =\n                    providerBootstrap.newModule().service(serviceConfig2).getModuleModel();\n            providerBootstrap.start();\n            Assertions.assertEquals(DeployState.COMPLETION, applicationDeployer.getState());\n            Assertions.assertEquals(\n                    DeployState.COMPLETION, moduleModel2.getDeployer().getState());\n\n            // 4. add module3 and start module3\n            ServiceConfig serviceConfig3 = new ServiceConfig();\n            serviceConfig3.setInterface(DemoService.class);\n            serviceConfig3.setRef(new DemoServiceImpl());\n            serviceConfig3.setVersion(version3);\n            ModuleModel moduleModel3 =\n                    providerBootstrap.newModule().service(serviceConfig3).getModuleModel();\n            moduleModel3.getDeployer().start().get();\n            Assertions.assertEquals(DeployState.COMPLETION, applicationDeployer.getState());\n            Assertions.assertEquals(\n                    DeployState.COMPLETION, moduleModel3.getDeployer().getState());\n\n        } finally {\n            if (providerBootstrap != null) {\n                providerBootstrap.stop();\n            }\n        }\n    }\n\n    @Test\n    void testBothStartModuleAndApplicationNoWait() throws Exception {\n        String version1 = \"1.0\";\n        String version2 = \"2.0\";\n        String version3 = \"3.0\";\n\n        String serviceKey1 = DemoService.class.getName() + \":\" + version1;\n        String serviceKey2 = DemoService.class.getName() + \":\" + version2;\n        String serviceKey3 = DemoService.class.getName() + \":\" + version3;\n\n        // provider app\n        DubboBootstrap providerBootstrap = null;\n        try {\n            providerBootstrap = DubboBootstrap.newInstance();\n\n            ServiceConfig serviceConfig1 = new ServiceConfig();\n            serviceConfig1.setInterface(DemoService.class);\n            serviceConfig1.setRef(new DemoServiceImpl());\n            serviceConfig1.setVersion(version1);\n\n            // provider module 1\n            providerBootstrap\n                    .application(\"provider-app\")\n                    .registry(registryConfig)\n                    .protocol(new ProtocolConfig(\"dubbo\", -1))\n                    .service(builder -> builder.interfaceClass(Greeting.class).ref(new GreetingLocal2()))\n                    .newModule()\n                    .service(serviceConfig1)\n                    .endModule();\n\n            ApplicationModel applicationModel = providerBootstrap.getApplicationModel();\n\n            // 1. start module1 but no wait\n            ModuleDeployer moduleDeployer1 = serviceConfig1.getScopeModel().getDeployer();\n            moduleDeployer1.start();\n            Assertions.assertTrue(moduleDeployer1.isRunning());\n\n            ApplicationDeployer applicationDeployer = applicationModel.getDeployer();\n            Assertions.assertEquals(DeployState.STARTING, applicationDeployer.getState());\n            ModuleModel defaultModule = applicationModel.getDefaultModule();\n            Assertions.assertEquals(\n                    DeployState.PENDING, defaultModule.getDeployer().getState());\n\n            // 2. start application after module1 is starting\n            providerBootstrap.start();\n            Assertions.assertEquals(DeployState.COMPLETION, applicationDeployer.getState());\n            Assertions.assertEquals(DeployState.COMPLETION, moduleDeployer1.getState());\n            Assertions.assertEquals(\n                    DeployState.COMPLETION, defaultModule.getDeployer().getState());\n\n        } finally {\n            if (providerBootstrap != null) {\n                providerBootstrap.stop();\n            }\n        }\n    }\n\n    @Test\n    void testOldApiDeploy() throws Exception {\n\n        try {\n            SysProps.setProperty(ConfigKeys.DUBBO_CONFIG_MODE, ConfigMode.OVERRIDE.name());\n            // provider app\n            ApplicationModel providerApplicationModel = ApplicationModel.defaultModel();\n            ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();\n            serviceConfig.setScopeModel(providerApplicationModel.getDefaultModule());\n            serviceConfig.setRef(new DemoServiceImpl());\n            serviceConfig.setInterface(DemoService.class);\n            serviceConfig.setApplication(new ApplicationConfig(\"provider-app\"));\n            serviceConfig.setRegistry(new RegistryConfig(registryConfig.getAddress()));\n            // add service\n            // serviceConfig.getScopeModel().getConfigManager().addService(serviceConfig);\n\n            // detect deploy events\n            DeployEventHandler serviceDeployEventHandler = new DeployEventHandler(serviceConfig.getScopeModel());\n            serviceConfig.getScopeModel().getDeployer().addDeployListener(serviceDeployEventHandler);\n            // before starting\n            Map<DeployState, Long> serviceDeployEventMap = serviceDeployEventHandler.deployEventMap;\n            Assertions.assertFalse(serviceDeployEventMap.containsKey(DeployState.STARTING));\n            Assertions.assertFalse(serviceDeployEventMap.containsKey(DeployState.STARTED));\n            Assertions.assertFalse(serviceDeployEventMap.containsKey(DeployState.COMPLETION));\n\n            // export service and start module\n            serviceConfig.export();\n            // expect internal module is started\n            Assertions.assertTrue(\n                    providerApplicationModel.getInternalModule().getDeployer().isCompletion());\n            // expect service module is starting\n            Assertions.assertTrue(serviceDeployEventMap.containsKey(DeployState.STARTING));\n            // wait for service module started\n            serviceConfig.getScopeModel().getDeployer().getStartFuture().get();\n            Assertions.assertTrue(serviceDeployEventMap.containsKey(DeployState.STARTED));\n            Assertions.assertTrue(serviceDeployEventMap.containsKey(DeployState.COMPLETION));\n\n            // consumer app\n            ApplicationModel consumerApplicationModel = ApplicationModel.defaultModel();\n            ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();\n            referenceConfig.setScopeModel(consumerApplicationModel.getDefaultModule());\n            referenceConfig.setApplication(new ApplicationConfig(\"consumer-app\"));\n            referenceConfig.setInterface(DemoService.class);\n            referenceConfig.setRegistry(new RegistryConfig(registryConfig.getAddress()));\n            referenceConfig.setScope(\"remote\");\n\n            // detect deploy events\n            DeployEventHandler referDeployEventHandler = new DeployEventHandler(referenceConfig.getScopeModel());\n            referenceConfig.getScopeModel().getDeployer().addDeployListener(referDeployEventHandler);\n\n            // before starting\n            Map<DeployState, Long> deployEventMap = referDeployEventHandler.deployEventMap;\n            Assertions.assertFalse(deployEventMap.containsKey(DeployState.STARTING));\n            Assertions.assertFalse(deployEventMap.containsKey(DeployState.STARTED));\n            Assertions.assertFalse(deployEventMap.containsKey(DeployState.COMPLETION));\n\n            // get ref proxy and start module\n            DemoService demoService = referenceConfig.get();\n            // expect internal module is started\n            Assertions.assertTrue(\n                    consumerApplicationModel.getInternalModule().getDeployer().isCompletion());\n            Assertions.assertTrue(deployEventMap.containsKey(DeployState.STARTING));\n            // wait for reference module started\n            referenceConfig.getScopeModel().getDeployer().getStartFuture().get();\n            Assertions.assertTrue(deployEventMap.containsKey(DeployState.STARTED));\n            Assertions.assertTrue(deployEventMap.containsKey(DeployState.COMPLETION));\n\n            // stop consumer app\n            consumerApplicationModel.destroy();\n            Assertions.assertTrue(deployEventMap.containsKey(DeployState.STOPPING));\n            Assertions.assertTrue(deployEventMap.containsKey(DeployState.STOPPED));\n\n            // stop provider app\n            providerApplicationModel.destroy();\n            Assertions.assertTrue(serviceDeployEventMap.containsKey(DeployState.STOPPING));\n            Assertions.assertTrue(serviceDeployEventMap.containsKey(DeployState.STOPPED));\n\n        } finally {\n            FrameworkModel.destroyAll();\n        }\n    }\n\n    @Test\n    void testAsyncExportAndReferServices() throws ExecutionException, InterruptedException {\n        DubboBootstrap providerBootstrap = DubboBootstrap.newInstance();\n        DubboBootstrap consumerBootstrap = DubboBootstrap.newInstance();\n        try {\n\n            ServiceConfig serviceConfig = new ServiceConfig();\n            serviceConfig.setInterface(Greeting.class);\n            serviceConfig.setRef(new GreetingLocal2());\n            serviceConfig.setExportAsync(true);\n\n            ReferenceConfig<Greeting> referenceConfig = new ReferenceConfig<>();\n            referenceConfig.setInterface(Greeting.class);\n            referenceConfig.setInjvm(false);\n            referenceConfig.setReferAsync(true);\n            referenceConfig.setCheck(false);\n\n            // provider app\n            Future providerFuture = providerBootstrap\n                    .application(\"provider-app\")\n                    .registry(registryConfig)\n                    .protocol(new ProtocolConfig(\"dubbo\", -1))\n                    .service(serviceConfig)\n                    .asyncStart();\n            logger.info(\"provider app has start async\");\n            // it might be started if running on fast machine.\n            // Assertions.assertFalse(serviceConfig.getScopeModel().getDeployer().isStarted(), \"Async export seems\n            // something wrong\");\n\n            // consumer app\n            Future consumerFuture = consumerBootstrap\n                    .application(\"consumer-app\")\n                    .registry(registryConfig)\n                    .reference(referenceConfig)\n                    .asyncStart();\n            logger.info(\"consumer app has start async\");\n            // it might be started if running on fast machine.\n            // Assertions.assertFalse(referenceConfig.getScopeModel().getDeployer().isStarted(), \"Async refer seems\n            // something wrong\");\n\n            // wait for provider app startup\n            providerFuture.get();\n            logger.info(\"provider app is startup\");\n            Assertions.assertEquals(true, serviceConfig.isExported());\n            ServiceDescriptor serviceDescriptor =\n                    serviceConfig.getScopeModel().getServiceRepository().lookupService(Greeting.class.getName());\n            Assertions.assertNotNull(serviceDescriptor);\n\n            // wait for consumer app startup\n            consumerFuture.get();\n            logger.info(\"consumer app is startup\");\n            Object target = referenceConfig.getServiceMetadata().getTarget();\n            Assertions.assertNotNull(target);\n            // wait for invokers notified from registry\n            MigrationInvoker migrationInvoker = (MigrationInvoker) referenceConfig.getInvoker();\n            for (int i = 0; i < 10; i++) {\n                if (((List<Invoker>) migrationInvoker.getDirectory().getAllInvokers())\n                        .stream().anyMatch(invoker -> invoker.getInterface() == Greeting.class)) {\n                    break;\n                }\n                Thread.sleep(100);\n            }\n            Greeting greetingService = (Greeting) target;\n            String result = greetingService.hello();\n            Assertions.assertEquals(\"local\", result);\n        } finally {\n            providerBootstrap.stop();\n            consumerBootstrap.stop();\n        }\n    }\n\n    private DubboBootstrap configConsumerApp(DubboBootstrap dubboBootstrap) {\n        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(DemoService.class);\n        referenceConfig.setInjvm(false);\n\n        if (!dubboBootstrap.getConfigManager().getApplication().isPresent()) {\n            dubboBootstrap.application(\"consumer-app\");\n        }\n        dubboBootstrap.registry(registryConfig).reference(referenceConfig);\n        return dubboBootstrap;\n    }\n\n    private void testConsumer(DubboBootstrap dubboBootstrap) {\n        DemoService demoService = dubboBootstrap.getCache().get(DemoService.class);\n        String result = demoService.sayName(\"dubbo\");\n        Assertions.assertEquals(\"say:dubbo\", result);\n    }\n\n    private DubboBootstrap configProviderApp(DubboBootstrap dubboBootstrap) {\n        ProtocolConfig protocol1 = new ProtocolConfig();\n        protocol1.setName(\"dubbo\");\n        protocol1.setPort(2001);\n\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(DemoService.class);\n        serviceConfig.setRef(new DemoServiceImpl());\n\n        if (!dubboBootstrap.getConfigManager().getApplication().isPresent()) {\n            dubboBootstrap.application(\"provider-app\");\n        }\n        dubboBootstrap.registry(registryConfig).protocol(protocol1).service(serviceConfig);\n        return dubboBootstrap;\n    }\n\n    private static class DeployEventHandler implements DeployListener<ModuleModel> {\n\n        Map<DeployState, Long> deployEventMap = new LinkedHashMap<>();\n\n        ModuleModel moduleModel;\n\n        public DeployEventHandler(ModuleModel moduleModel) {\n            this.moduleModel = moduleModel;\n        }\n\n        @Override\n        public void onInitialize(ModuleModel scopeModel) {\n            Assertions.assertEquals(moduleModel, scopeModel);\n        }\n\n        @Override\n        public void onStarting(ModuleModel scopeModel) {\n            Assertions.assertEquals(moduleModel, scopeModel);\n            deployEventMap.put(DeployState.STARTING, System.currentTimeMillis());\n        }\n\n        @Override\n        public void onStarted(ModuleModel scopeModel) {\n            Assertions.assertEquals(moduleModel, scopeModel);\n            deployEventMap.put(DeployState.STARTED, System.currentTimeMillis());\n        }\n\n        @Override\n        public void onCompletion(ModuleModel scopeModel) {\n            Assertions.assertEquals(moduleModel, scopeModel);\n            deployEventMap.put(DeployState.COMPLETION, System.currentTimeMillis());\n        }\n\n        @Override\n        public void onStopping(ModuleModel scopeModel) {\n            Assertions.assertEquals(moduleModel, scopeModel);\n            deployEventMap.put(DeployState.STOPPING, System.currentTimeMillis());\n        }\n\n        @Override\n        public void onStopped(ModuleModel scopeModel) {\n            Assertions.assertEquals(moduleModel, scopeModel);\n            deployEventMap.put(DeployState.STOPPED, System.currentTimeMillis());\n        }\n\n        @Override\n        public void onFailure(ModuleModel scopeModel, Throwable cause) {\n            Assertions.assertEquals(moduleModel, scopeModel);\n            deployEventMap.put(DeployState.FAILED, System.currentTimeMillis());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.AbstractConfig;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass AbstractBuilderTest {\n\n    @Test\n    void id() {\n        Builder builder = new Builder();\n        builder.id(\"id\");\n        Assertions.assertEquals(\"id\", builder.build().getId());\n    }\n\n    @Test\n    void appendParameter() {\n        Map<String, String> source = null;\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(\"default.num\", \"one\");\n        parameters.put(\"num\", \"ONE\");\n        source = AbstractBuilder.appendParameters(source, parameters);\n\n        Assertions.assertTrue(source.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", source.get(\"num\"));\n    }\n\n    @Test\n    void appendParameter2() {\n        Map<String, String> source = new HashMap<>();\n        source.put(\"default.num\", \"one1\");\n        source.put(\"num\", \"ONE1\");\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(\"default.num\", \"one\");\n        parameters.put(\"num\", \"ONE\");\n        source = AbstractBuilder.appendParameters(source, parameters);\n\n        Assertions.assertTrue(source.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", source.get(\"num\"));\n    }\n\n    @Test\n    void appendParameters() {\n        Map<String, String> source = null;\n\n        source = AbstractBuilder.appendParameter(source, \"default.num\", \"one\");\n        source = AbstractBuilder.appendParameter(source, \"num\", \"ONE\");\n\n        Assertions.assertTrue(source.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", source.get(\"num\"));\n    }\n\n    @Test\n    void appendParameters2() {\n        Map<String, String> source = new HashMap<>();\n        source.put(\"default.num\", \"one1\");\n        source.put(\"num\", \"ONE1\");\n\n        source = AbstractBuilder.appendParameter(source, \"default.num\", \"one\");\n        source = AbstractBuilder.appendParameter(source, \"num\", \"ONE\");\n\n        Assertions.assertTrue(source.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", source.get(\"num\"));\n    }\n\n    @Test\n    void build() {\n        Builder builder = new Builder();\n        builder.id(\"id\");\n\n        Config config = builder.build();\n        Config config2 = builder.build();\n\n        Assertions.assertEquals(\"id\", config.getId());\n\n        Assertions.assertNotSame(config, config2);\n    }\n\n    private static class Builder extends AbstractBuilder<Config, Builder> {\n        public Config build() {\n            Config parameterConfig = new Config();\n            super.build(parameterConfig);\n\n            return parameterConfig;\n        }\n\n        @Override\n        protected Builder getThis() {\n            return this;\n        }\n    }\n\n    private static class Config extends AbstractConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractInterfaceBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.AbstractInterfaceConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass AbstractInterfaceBuilderTest {\n\n    @BeforeEach\n    void beforeEach() {\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void local() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.local(\"GreetingMock\");\n        Assertions.assertEquals(\"GreetingMock\", builder.build().getLocal());\n    }\n\n    @Test\n    void local1() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.local((Boolean) null);\n        Assertions.assertNull(builder.build().getLocal());\n        builder.local(false);\n        Assertions.assertEquals(\"false\", builder.build().getLocal());\n        builder.local(true);\n        Assertions.assertEquals(\"true\", builder.build().getLocal());\n    }\n\n    @Test\n    void stub() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.stub(\"GreetingMock\");\n        Assertions.assertEquals(\"GreetingMock\", builder.build().getStub());\n    }\n\n    @Test\n    void stub1() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.stub((Boolean) null);\n        Assertions.assertNull(builder.build().getLocal());\n        builder.stub(false);\n        Assertions.assertEquals(\"false\", builder.build().getStub());\n        builder.stub(true);\n        Assertions.assertEquals(\"true\", builder.build().getStub());\n    }\n\n    @Test\n    void monitor() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.monitor(\"123\");\n\n        MonitorConfig monitorConfig = new MonitorConfig(\"123\");\n        Assertions.assertEquals(monitorConfig, builder.build().getMonitor());\n    }\n\n    @Test\n    void monitor1() {\n        MonitorConfig monitorConfig = new MonitorConfig(\"123\");\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.monitor(monitorConfig);\n\n        Assertions.assertEquals(monitorConfig, builder.build().getMonitor());\n    }\n\n    @Test\n    void proxy() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.proxy(\"mockproxyfactory\");\n\n        Assertions.assertEquals(\"mockproxyfactory\", builder.build().getProxy());\n    }\n\n    @Test\n    void cluster() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.cluster(\"mockcluster\");\n\n        Assertions.assertEquals(\"mockcluster\", builder.build().getCluster());\n    }\n\n    @Test\n    void filter() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.filter(\"mockfilter\");\n\n        Assertions.assertEquals(\"mockfilter\", builder.build().getFilter());\n    }\n\n    @Test\n    void listener() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.listener(\"mockinvokerlistener\");\n\n        Assertions.assertEquals(\"mockinvokerlistener\", builder.build().getListener());\n    }\n\n    @Test\n    void owner() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.owner(\"owner\");\n\n        Assertions.assertEquals(\"owner\", builder.build().getOwner());\n    }\n\n    @Test\n    void connections() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.connections(1);\n\n        Assertions.assertEquals(1, builder.build().getConnections().intValue());\n    }\n\n    @Test\n    void layer() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.layer(\"layer\");\n\n        Assertions.assertEquals(\"layer\", builder.build().getLayer());\n    }\n\n    @Test\n    void application() {\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"AbtractInterfaceBuilderTest\");\n\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.application(applicationConfig);\n\n        Assertions.assertEquals(applicationConfig, builder.build().getApplication());\n    }\n\n    @Test\n    void module() {\n        ModuleConfig moduleConfig = new ModuleConfig();\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.module(moduleConfig);\n\n        Assertions.assertEquals(moduleConfig, builder.build().getModule());\n    }\n\n    @Test\n    void addRegistries() {\n        RegistryConfig registryConfig = new RegistryConfig();\n\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.addRegistries(Collections.singletonList(registryConfig));\n\n        Assertions.assertEquals(1, builder.build().getRegistries().size());\n        Assertions.assertSame(registryConfig, builder.build().getRegistries().get(0));\n        Assertions.assertSame(registryConfig, builder.build().getRegistry());\n    }\n\n    @Test\n    void addRegistry() {\n        RegistryConfig registryConfig = new RegistryConfig();\n\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.addRegistry(registryConfig);\n\n        Assertions.assertEquals(1, builder.build().getRegistries().size());\n        Assertions.assertSame(registryConfig, builder.build().getRegistries().get(0));\n        Assertions.assertSame(registryConfig, builder.build().getRegistry());\n    }\n\n    @Test\n    void registryIds() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.registryIds(\"registryIds\");\n\n        Assertions.assertEquals(\"registryIds\", builder.build().getRegistryIds());\n    }\n\n    @Test\n    void onconnect() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.onconnect(\"onconnect\");\n\n        Assertions.assertEquals(\"onconnect\", builder.build().getOnconnect());\n    }\n\n    @Test\n    void ondisconnect() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.ondisconnect(\"ondisconnect\");\n\n        Assertions.assertEquals(\"ondisconnect\", builder.build().getOndisconnect());\n    }\n\n    @Test\n    void metadataReportConfig() {\n        MetadataReportConfig metadataReportConfig = new MetadataReportConfig();\n\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.metadataReportConfig(metadataReportConfig);\n\n        Assertions.assertEquals(metadataReportConfig, builder.build().getMetadataReportConfig());\n    }\n\n    @Test\n    void configCenter() {\n        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();\n\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.configCenter(configCenterConfig);\n\n        Assertions.assertEquals(configCenterConfig, builder.build().getConfigCenter());\n    }\n\n    @Test\n    void callbacks() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.callbacks(2);\n        Assertions.assertEquals(2, builder.build().getCallbacks().intValue());\n    }\n\n    @Test\n    void scope() {\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.scope(\"scope\");\n\n        Assertions.assertEquals(\"scope\", builder.build().getScope());\n    }\n\n    @Test\n    void build() {\n        MonitorConfig monitorConfig = new MonitorConfig(\"123\");\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"appName\");\n        ModuleConfig moduleConfig = new ModuleConfig();\n        RegistryConfig registryConfig = new RegistryConfig();\n        MetadataReportConfig metadataReportConfig = new MetadataReportConfig();\n        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();\n\n        InterfaceBuilder builder = new InterfaceBuilder();\n        builder.id(\"id\")\n                .local(true)\n                .stub(false)\n                .monitor(\"123\")\n                .proxy(\"mockproxyfactory\")\n                .cluster(\"mockcluster\")\n                .filter(\"mockfilter\")\n                .listener(\"mockinvokerlistener\")\n                .owner(\"owner\")\n                .connections(1)\n                .layer(\"layer\")\n                .application(applicationConfig)\n                .module(moduleConfig)\n                .addRegistry(registryConfig)\n                .registryIds(\"registryIds\")\n                .onconnect(\"onconnet\")\n                .ondisconnect(\"ondisconnect\")\n                .metadataReportConfig(metadataReportConfig)\n                .configCenter(configCenterConfig)\n                .callbacks(2)\n                .scope(\"scope\");\n\n        InterfaceConfig config = builder.build();\n        InterfaceConfig config2 = builder.build();\n\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertEquals(\"true\", config.getLocal());\n        Assertions.assertEquals(\"false\", config.getStub());\n        Assertions.assertEquals(monitorConfig, config.getMonitor());\n        Assertions.assertEquals(\"mockproxyfactory\", config.getProxy());\n        Assertions.assertEquals(\"mockcluster\", config.getCluster());\n        Assertions.assertEquals(\"mockfilter\", config.getFilter());\n        Assertions.assertEquals(\"mockinvokerlistener\", config.getListener());\n        Assertions.assertEquals(\"owner\", config.getOwner());\n        Assertions.assertEquals(1, config.getConnections().intValue());\n        Assertions.assertEquals(\"layer\", config.getLayer());\n        Assertions.assertEquals(applicationConfig, config.getApplication());\n        Assertions.assertEquals(moduleConfig, config.getModule());\n        Assertions.assertEquals(registryConfig, config.getRegistry());\n        Assertions.assertEquals(\"registryIds\", config.getRegistryIds());\n        Assertions.assertEquals(\"onconnet\", config.getOnconnect());\n        Assertions.assertEquals(\"ondisconnect\", config.getOndisconnect());\n        Assertions.assertEquals(metadataReportConfig, config.getMetadataReportConfig());\n        Assertions.assertEquals(configCenterConfig, config.getConfigCenter());\n        Assertions.assertEquals(2, config.getCallbacks().intValue());\n        Assertions.assertEquals(\"scope\", config.getScope());\n\n        Assertions.assertNotSame(config, config2);\n    }\n\n    private static class InterfaceBuilder extends AbstractInterfaceBuilder<InterfaceConfig, InterfaceBuilder> {\n\n        public InterfaceConfig build() {\n            InterfaceConfig config = new InterfaceConfig();\n            super.build(config);\n\n            return config;\n        }\n\n        @Override\n        protected InterfaceBuilder getThis() {\n            return this;\n        }\n    }\n\n    private static class InterfaceConfig extends AbstractInterfaceConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractMethodBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.AbstractMethodConfig;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass AbstractMethodBuilderTest {\n\n    @Test\n    void timeout() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.timeout(10);\n\n        Assertions.assertEquals(10, builder.build().getTimeout());\n    }\n\n    @Test\n    void retries() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.retries(3);\n\n        Assertions.assertEquals(3, builder.build().getRetries());\n    }\n\n    @Test\n    void actives() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.actives(3);\n\n        Assertions.assertEquals(3, builder.build().getActives());\n    }\n\n    @Test\n    void loadbalance() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.loadbalance(\"mockloadbalance\");\n\n        Assertions.assertEquals(\"mockloadbalance\", builder.build().getLoadbalance());\n    }\n\n    @Test\n    void async() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.async(true);\n\n        Assertions.assertTrue(builder.build().isAsync());\n    }\n\n    @Test\n    void sent() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.sent(true);\n\n        Assertions.assertTrue(builder.build().getSent());\n    }\n\n    @Test\n    void mock() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.mock(\"mock\");\n        Assertions.assertEquals(\"mock\", builder.build().getMock());\n        builder.mock(\"return null\");\n        Assertions.assertEquals(\"return null\", builder.build().getMock());\n    }\n\n    @Test\n    void mock1() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.mock(true);\n        Assertions.assertEquals(\"true\", builder.build().getMock());\n        builder.mock(false);\n        Assertions.assertEquals(\"false\", builder.build().getMock());\n    }\n\n    @Test\n    void merger() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.merger(\"merger\");\n        Assertions.assertEquals(\"merger\", builder.build().getMerger());\n    }\n\n    @Test\n    void cache() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.cache(\"cache\");\n        Assertions.assertEquals(\"cache\", builder.build().getCache());\n    }\n\n    @Test\n    void validation() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.validation(\"validation\");\n        Assertions.assertEquals(\"validation\", builder.build().getValidation());\n    }\n\n    @Test\n    void appendParameter() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.appendParameter(\"default.num\", \"one\").appendParameter(\"num\", \"ONE\");\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void appendParameters() {\n        Map<String, String> source = new HashMap<>();\n        source.put(\"default.num\", \"one\");\n        source.put(\"num\", \"ONE\");\n\n        MethodBuilder builder = new MethodBuilder();\n        builder.appendParameters(source);\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void forks() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.forks(5);\n\n        Assertions.assertEquals(5, builder.build().getForks());\n    }\n\n    @Test\n    void build() {\n        MethodBuilder builder = new MethodBuilder();\n        builder.id(\"id\")\n                .timeout(1)\n                .retries(2)\n                .actives(3)\n                .loadbalance(\"mockloadbalance\")\n                .async(true)\n                .sent(false)\n                .mock(\"mock\")\n                .merger(\"merger\")\n                .cache(\"cache\")\n                .validation(\"validation\")\n                .appendParameter(\"default.num\", \"one\");\n\n        MethodConfig config = builder.build();\n        MethodConfig config2 = builder.build();\n\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertEquals(1, config.getTimeout());\n        Assertions.assertEquals(2, config.getRetries());\n        Assertions.assertEquals(3, config.getActives());\n        Assertions.assertEquals(\"mockloadbalance\", config.getLoadbalance());\n        Assertions.assertTrue(config.isAsync());\n        Assertions.assertFalse(config.getSent());\n        Assertions.assertEquals(\"mock\", config.getMock());\n        Assertions.assertEquals(\"merger\", config.getMerger());\n        Assertions.assertEquals(\"cache\", config.getCache());\n        Assertions.assertEquals(\"validation\", config.getValidation());\n        Assertions.assertTrue(config.getParameters().containsKey(\"default.num\"));\n        Assertions.assertEquals(\"one\", config.getParameters().get(\"default.num\"));\n\n        Assertions.assertNotSame(config, config2);\n    }\n\n    private static class MethodBuilder extends AbstractMethodBuilder<MethodConfig, MethodBuilder> {\n\n        public MethodConfig build() {\n            MethodConfig parameterConfig = new MethodConfig();\n            super.build(parameterConfig);\n\n            return parameterConfig;\n        }\n\n        @Override\n        protected MethodBuilder getThis() {\n            return this;\n        }\n    }\n\n    private static class MethodConfig extends AbstractMethodConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractReferenceBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.AbstractReferenceConfig;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_BEAN;\n\nclass AbstractReferenceBuilderTest {\n\n    @Test\n    void check() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.check(true);\n        Assertions.assertTrue(builder.build().isCheck());\n        builder.check(false);\n        Assertions.assertFalse(builder.build().isCheck());\n    }\n\n    @Test\n    void init() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.init(true);\n        Assertions.assertTrue(builder.build().isInit());\n        builder.init(false);\n        Assertions.assertFalse(builder.build().isInit());\n    }\n\n    @Test\n    void generic() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.generic(true);\n        Assertions.assertTrue(builder.build().isGeneric());\n        builder.generic(false);\n        Assertions.assertFalse(builder.build().isGeneric());\n    }\n\n    @Test\n    void generic1() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.generic(GENERIC_SERIALIZATION_BEAN);\n        Assertions.assertEquals(GENERIC_SERIALIZATION_BEAN, builder.build().getGeneric());\n    }\n\n    @Test\n    void injvm() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.injvm(true);\n        Assertions.assertTrue(builder.build().isInjvm());\n        builder.injvm(false);\n        Assertions.assertFalse(builder.build().isInjvm());\n    }\n\n    @Test\n    void lazy() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.lazy(true);\n        Assertions.assertTrue(builder.build().getLazy());\n        builder.lazy(false);\n        Assertions.assertFalse(builder.build().getLazy());\n    }\n\n    @Test\n    void reconnect() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.reconnect(\"reconnect\");\n        Assertions.assertEquals(\"reconnect\", builder.build().getReconnect());\n    }\n\n    @Test\n    void sticky() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.sticky(true);\n        Assertions.assertTrue(builder.build().getSticky());\n        builder.sticky(false);\n        Assertions.assertFalse(builder.build().getSticky());\n    }\n\n    @Test\n    void version() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.version(\"version\");\n        Assertions.assertEquals(\"version\", builder.build().getVersion());\n    }\n\n    @Test\n    void group() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.group(\"group\");\n        Assertions.assertEquals(\"group\", builder.build().getGroup());\n    }\n\n    @Test\n    void build() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.check(true)\n                .init(false)\n                .generic(true)\n                .injvm(false)\n                .lazy(true)\n                .reconnect(\"reconnect\")\n                .sticky(false)\n                .version(\"version\")\n                .group(\"group\")\n                .id(\"id\");\n\n        ReferenceConfig config = builder.build();\n        ReferenceConfig config2 = builder.build();\n\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertTrue(config.isCheck());\n        Assertions.assertFalse(config.isInit());\n        Assertions.assertTrue(config.isGeneric());\n        Assertions.assertFalse(config.isInjvm());\n        Assertions.assertTrue(config.getLazy());\n        Assertions.assertFalse(config.getSticky());\n        Assertions.assertEquals(\"reconnect\", config.getReconnect());\n        Assertions.assertEquals(\"version\", config.getVersion());\n        Assertions.assertEquals(\"group\", config.getGroup());\n\n        Assertions.assertNotSame(config, config2);\n    }\n\n    private static class ReferenceBuilder extends AbstractReferenceBuilder<ReferenceConfig, ReferenceBuilder> {\n\n        public ReferenceConfig build() {\n            ReferenceConfig parameterConfig = new ReferenceConfig();\n            super.build(parameterConfig);\n\n            return parameterConfig;\n        }\n\n        @Override\n        protected ReferenceBuilder getThis() {\n            return this;\n        }\n    }\n\n    private static class ReferenceConfig extends AbstractReferenceConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractServiceBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.AbstractServiceConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass AbstractServiceBuilderTest {\n\n    @Test\n    void version() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.version(\"version\");\n        Assertions.assertEquals(\"version\", builder.build().getVersion());\n    }\n\n    @Test\n    void group() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.group(\"group\");\n        Assertions.assertEquals(\"group\", builder.build().getGroup());\n    }\n\n    @Test\n    void deprecated() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.deprecated(true);\n        Assertions.assertTrue(builder.build().isDeprecated());\n        builder.deprecated(false);\n        Assertions.assertFalse(builder.build().isDeprecated());\n    }\n\n    @Test\n    void delay() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.delay(1000);\n        Assertions.assertEquals(1000, builder.build().getDelay());\n    }\n\n    @Test\n    void export() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.export(true);\n        Assertions.assertTrue(builder.build().getExport());\n        builder.export(false);\n        Assertions.assertFalse(builder.build().getExport());\n    }\n\n    @Test\n    void weight() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.weight(500);\n        Assertions.assertEquals(500, builder.build().getWeight());\n    }\n\n    @Test\n    void document() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.document(\"http://dubbo.apache.org\");\n        Assertions.assertEquals(\"http://dubbo.apache.org\", builder.build().getDocument());\n    }\n\n    @Test\n    void dynamic() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.dynamic(true);\n        Assertions.assertTrue(builder.build().isDynamic());\n        builder.dynamic(false);\n        Assertions.assertFalse(builder.build().isDynamic());\n    }\n\n    @Test\n    void token() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.token(\"token\");\n        Assertions.assertEquals(\"token\", builder.build().getToken());\n    }\n\n    @Test\n    void token1() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.token(true);\n        Assertions.assertEquals(\"true\", builder.build().getToken());\n        builder.token(false);\n        Assertions.assertEquals(\"false\", builder.build().getToken());\n        builder.token((Boolean) null);\n        Assertions.assertNull(builder.build().getToken());\n    }\n\n    @Test\n    void accesslog() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.accesslog(\"accesslog\");\n        Assertions.assertEquals(\"accesslog\", builder.build().getAccesslog());\n    }\n\n    @Test\n    void accesslog1() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.accesslog(true);\n        Assertions.assertEquals(\"true\", builder.build().getAccesslog());\n        builder.accesslog(false);\n        Assertions.assertEquals(\"false\", builder.build().getAccesslog());\n        builder.accesslog((Boolean) null);\n        Assertions.assertNull(builder.build().getAccesslog());\n    }\n\n    @Test\n    void addProtocols() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        ServiceBuilder builder = new ServiceBuilder();\n        Assertions.assertNull(builder.build().getProtocols());\n        builder.addProtocols(Collections.singletonList(protocol));\n        Assertions.assertNotNull(builder.build().getProtocols());\n        Assertions.assertEquals(1, builder.build().getProtocols().size());\n    }\n\n    @Test\n    void addProtocol() {\n        ProtocolConfig protocol = new ProtocolConfig();\n        ServiceBuilder builder = new ServiceBuilder();\n        Assertions.assertNull(builder.build().getProtocols());\n        builder.addProtocol(protocol);\n        Assertions.assertNotNull(builder.build().getProtocols());\n        Assertions.assertEquals(1, builder.build().getProtocols().size());\n        Assertions.assertEquals(protocol, builder.build().getProtocol());\n    }\n\n    @Test\n    void protocolIds() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.protocolIds(\"protocolIds\");\n        Assertions.assertEquals(\"protocolIds\", builder.build().getProtocolIds());\n    }\n\n    @Test\n    void tag() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.tag(\"tag\");\n        Assertions.assertEquals(\"tag\", builder.build().getTag());\n    }\n\n    @Test\n    void executes() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.executes(10);\n        Assertions.assertEquals(10, builder.build().getExecutes());\n    }\n\n    @Test\n    void register() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.register(true);\n        Assertions.assertTrue(builder.build().isRegister());\n        builder.register(false);\n        Assertions.assertFalse(builder.build().isRegister());\n    }\n\n    @Test\n    void warmup() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.warmup(100);\n        Assertions.assertEquals(100, builder.build().getWarmup());\n    }\n\n    @Test\n    void serialization() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.serialization(\"serialization\");\n        Assertions.assertEquals(\"serialization\", builder.build().getSerialization());\n    }\n\n    @Test\n    void build() {\n        ProtocolConfig protocol = new ProtocolConfig();\n\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.version(\"version\")\n                .group(\"group\")\n                .deprecated(true)\n                .delay(1000)\n                .export(false)\n                .weight(1)\n                .document(\"document\")\n                .dynamic(true)\n                .token(\"token\")\n                .accesslog(\"accesslog\")\n                .addProtocol(protocol)\n                .protocolIds(\"protocolIds\")\n                .tag(\"tag\")\n                .executes(100)\n                .register(false)\n                .warmup(200)\n                .serialization(\"serialization\")\n                .id(\"id\");\n\n        ServiceConfig config = builder.build();\n        ServiceConfig config2 = builder.build();\n\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertEquals(\"version\", config.getVersion());\n        Assertions.assertEquals(\"group\", config.getGroup());\n        Assertions.assertEquals(\"document\", config.getDocument());\n        Assertions.assertEquals(\"token\", config.getToken());\n        Assertions.assertEquals(\"accesslog\", config.getAccesslog());\n        Assertions.assertEquals(\"protocolIds\", config.getProtocolIds());\n        Assertions.assertEquals(\"tag\", config.getTag());\n        Assertions.assertEquals(\"serialization\", config.getSerialization());\n        Assertions.assertTrue(config.isDeprecated());\n        Assertions.assertFalse(config.getExport());\n        Assertions.assertTrue(config.isDynamic());\n        Assertions.assertFalse(config.isRegister());\n        Assertions.assertEquals(1000, config.getDelay());\n        Assertions.assertEquals(1, config.getWeight());\n        Assertions.assertEquals(100, config.getExecutes());\n        Assertions.assertEquals(200, config.getWarmup());\n\n        Assertions.assertNotSame(config, config2);\n    }\n\n    private static class ServiceBuilder extends AbstractServiceBuilder<ServiceConfig, ServiceBuilder> {\n\n        public ServiceConfig build() {\n            ServiceConfig parameterConfig = new ServiceConfig();\n            super.build(parameterConfig);\n\n            return parameterConfig;\n        }\n\n        @Override\n        protected ServiceBuilder getThis() {\n            return this;\n        }\n    }\n\n    private static class ServiceConfig extends AbstractServiceConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ApplicationBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.RegistryConfig;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ApplicationBuilderTest {\n\n    @Test\n    void name() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.name(\"app\");\n        Assertions.assertEquals(\"app\", builder.build().getName());\n    }\n\n    @Test\n    void version() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.version(\"version\");\n        Assertions.assertEquals(\"version\", builder.build().getVersion());\n    }\n\n    @Test\n    void owner() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.owner(\"owner\");\n        Assertions.assertEquals(\"owner\", builder.build().getOwner());\n    }\n\n    @Test\n    void organization() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.organization(\"organization\");\n        Assertions.assertEquals(\"organization\", builder.build().getOrganization());\n    }\n\n    @Test\n    void architecture() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.architecture(\"architecture\");\n        Assertions.assertEquals(\"architecture\", builder.build().getArchitecture());\n    }\n\n    @Test\n    void environment() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        Assertions.assertEquals(\"product\", builder.build().getEnvironment());\n        builder.environment(\"develop\");\n        Assertions.assertEquals(\"develop\", builder.build().getEnvironment());\n        builder.environment(\"test\");\n        Assertions.assertEquals(\"test\", builder.build().getEnvironment());\n        builder.environment(\"product\");\n        Assertions.assertEquals(\"product\", builder.build().getEnvironment());\n    }\n\n    @Test\n    void compiler() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.compiler(\"compiler\");\n        Assertions.assertEquals(\"compiler\", builder.build().getCompiler());\n    }\n\n    @Test\n    void logger() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.logger(\"log4j2\");\n        Assertions.assertEquals(\"log4j2\", builder.build().getLogger());\n    }\n\n    @Test\n    void addRegistry() {\n        RegistryConfig registry = new RegistryConfig();\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.addRegistry(registry);\n        Assertions.assertNotNull(builder.build().getRegistry());\n        Assertions.assertEquals(1, builder.build().getRegistries().size());\n        Assertions.assertSame(registry, builder.build().getRegistry());\n    }\n\n    @Test\n    void addRegistries() {\n        RegistryConfig registry = new RegistryConfig();\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.addRegistries(Collections.singletonList(registry));\n        Assertions.assertNotNull(builder.build().getRegistry());\n        Assertions.assertEquals(1, builder.build().getRegistries().size());\n        Assertions.assertSame(registry, builder.build().getRegistry());\n    }\n\n    @Test\n    void registryIds() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.registryIds(\"registryIds\");\n        Assertions.assertEquals(\"registryIds\", builder.build().getRegistryIds());\n    }\n\n    @Test\n    void monitor() {\n        MonitorConfig monitor = new MonitorConfig(\"monitor-addr\");\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.monitor(monitor);\n        Assertions.assertSame(monitor, builder.build().getMonitor());\n        Assertions.assertEquals(\"monitor-addr\", builder.build().getMonitor().getAddress());\n    }\n\n    @Test\n    void monitor1() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.monitor(\"monitor-addr\");\n        Assertions.assertEquals(\"monitor-addr\", builder.build().getMonitor().getAddress());\n    }\n\n    @Test\n    void isDefault() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.isDefault(true);\n        Assertions.assertTrue(builder.build().isDefault());\n        builder.isDefault(false);\n        Assertions.assertFalse(builder.build().isDefault());\n        builder.isDefault(null);\n        Assertions.assertNull(builder.build().isDefault());\n    }\n\n    @Test\n    void dumpDirectory() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.dumpDirectory(\"dumpDirectory\");\n        Assertions.assertEquals(\"dumpDirectory\", builder.build().getDumpDirectory());\n    }\n\n    @Test\n    void qosEnable() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.qosEnable(true);\n        Assertions.assertTrue(builder.build().getQosEnable());\n        builder.qosEnable(false);\n        Assertions.assertFalse(builder.build().getQosEnable());\n        builder.qosEnable(null);\n        Assertions.assertNull(builder.build().getQosEnable());\n    }\n\n    @Test\n    void qosPort() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.qosPort(8080);\n        Assertions.assertEquals(8080, builder.build().getQosPort());\n    }\n\n    @Test\n    void qosAcceptForeignIp() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.qosAcceptForeignIp(true);\n        Assertions.assertTrue(builder.build().getQosAcceptForeignIp());\n        builder.qosAcceptForeignIp(false);\n        Assertions.assertFalse(builder.build().getQosAcceptForeignIp());\n        builder.qosAcceptForeignIp(null);\n        Assertions.assertNull(builder.build().getQosAcceptForeignIp());\n    }\n\n    @Test\n    void shutwait() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.shutwait(\"shutwait\");\n        Assertions.assertEquals(\"shutwait\", builder.build().getShutwait());\n    }\n\n    @Test\n    void appendParameter() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.appendParameter(\"default.num\", \"one\").appendParameter(\"num\", \"ONE\");\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void appendParameters() {\n        Map<String, String> source = new HashMap<>();\n        source.put(\"default.num\", \"one\");\n        source.put(\"num\", \"ONE\");\n\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.appendParameters(source);\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void metadataServicePort() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.metadataServicePort(12345);\n        Assertions.assertEquals(12345, builder.build().getMetadataServicePort());\n    }\n\n    @Test\n    void livenessProbe() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.livenessProbe(\"TestProbe\");\n        Assertions.assertEquals(\"TestProbe\", builder.build().getLivenessProbe());\n    }\n\n    @Test\n    void readinessProbe() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.readinessProbe(\"TestProbe\");\n        Assertions.assertEquals(\"TestProbe\", builder.build().getReadinessProbe());\n    }\n\n    @Test\n    void startupProbe() {\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.startupProbe(\"TestProbe\");\n        Assertions.assertEquals(\"TestProbe\", builder.build().getStartupProbe());\n    }\n\n    @Test\n    void build() {\n        MonitorConfig monitor = new MonitorConfig(\"monitor-addr\");\n        RegistryConfig registry = new RegistryConfig();\n\n        ApplicationBuilder builder = new ApplicationBuilder();\n        builder.id(\"id\")\n                .name(\"name\")\n                .version(\"version\")\n                .owner(\"owner\")\n                .organization(\"organization\")\n                .architecture(\"architecture\")\n                .environment(\"develop\")\n                .compiler(\"compiler\")\n                .logger(\"log4j2\")\n                .monitor(monitor)\n                .isDefault(false)\n                .dumpDirectory(\"dumpDirectory\")\n                .qosEnable(true)\n                .qosPort(8080)\n                .qosAcceptForeignIp(false)\n                .shutwait(\"shutwait\")\n                .registryIds(\"registryIds\")\n                .addRegistry(registry)\n                .appendParameter(\"default.num\", \"one\")\n                .metadataServicePort(12345)\n                .livenessProbe(\"liveness\")\n                .readinessProbe(\"readiness\")\n                .startupProbe(\"startup\");\n\n        ApplicationConfig config = builder.build();\n        ApplicationConfig config2 = builder.build();\n\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertEquals(\"name\", config.getName());\n        Assertions.assertEquals(\"version\", config.getVersion());\n        Assertions.assertEquals(\"owner\", config.getOwner());\n        Assertions.assertEquals(\"organization\", config.getOrganization());\n        Assertions.assertEquals(\"architecture\", config.getArchitecture());\n        Assertions.assertEquals(\"develop\", config.getEnvironment());\n        Assertions.assertEquals(\"compiler\", config.getCompiler());\n        Assertions.assertEquals(\"log4j2\", config.getLogger());\n        Assertions.assertSame(monitor, config.getMonitor());\n        Assertions.assertFalse(config.isDefault());\n        Assertions.assertEquals(\"dumpDirectory\", config.getDumpDirectory());\n        Assertions.assertTrue(config.getQosEnable());\n        Assertions.assertEquals(8080, config.getQosPort());\n        Assertions.assertFalse(config.getQosAcceptForeignIp());\n        Assertions.assertEquals(\"shutwait\", config.getShutwait());\n        Assertions.assertEquals(\"registryIds\", config.getRegistryIds());\n        Assertions.assertSame(registry, config.getRegistry());\n        Assertions.assertTrue(config.getParameters().containsKey(\"default.num\"));\n        Assertions.assertEquals(\"one\", config.getParameters().get(\"default.num\"));\n        Assertions.assertEquals(12345, config.getMetadataServicePort());\n        Assertions.assertEquals(\"liveness\", config.getLivenessProbe());\n        Assertions.assertEquals(\"readiness\", config.getReadinessProbe());\n        Assertions.assertEquals(\"startup\", config.getStartupProbe());\n\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ArgumentBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ArgumentConfig;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ArgumentBuilderTest {\n\n    @Test\n    void index() {\n        ArgumentBuilder builder = ArgumentBuilder.newBuilder();\n        builder.index(1);\n        Assertions.assertEquals(1, builder.build().getIndex());\n    }\n\n    @Test\n    void type() {\n        ArgumentBuilder builder = ArgumentBuilder.newBuilder();\n        builder.type(\"int\");\n        Assertions.assertEquals(\"int\", builder.build().getType());\n    }\n\n    @Test\n    void callback() {\n        ArgumentBuilder builder = ArgumentBuilder.newBuilder();\n        builder.callback(true);\n        Assertions.assertTrue(builder.build().isCallback());\n        builder.callback(false);\n        Assertions.assertFalse(builder.build().isCallback());\n    }\n\n    @Test\n    void build() {\n        ArgumentBuilder builder = ArgumentBuilder.newBuilder();\n        builder.index(1).type(\"int\").callback(true);\n\n        ArgumentConfig argument1 = builder.build();\n        ArgumentConfig argument2 = builder.build();\n\n        Assertions.assertTrue(argument1.isCallback());\n        Assertions.assertEquals(\"int\", argument1.getType());\n        Assertions.assertEquals(1, argument1.getIndex());\n\n        Assertions.assertNotSame(argument1, argument2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ConfigCenterBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ConfigCenterConfig;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ConfigCenterBuilderTest {\n\n    @Test\n    void protocol() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.protocol(\"protocol\");\n        Assertions.assertEquals(\"protocol\", builder.build().getProtocol());\n    }\n\n    @Test\n    void address() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.address(\"address\");\n        Assertions.assertEquals(\"address\", builder.build().getAddress());\n    }\n\n    @Test\n    void cluster() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.cluster(\"cluster\");\n        Assertions.assertEquals(\"cluster\", builder.build().getCluster());\n    }\n\n    @Test\n    void namespace() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.namespace(\"namespace\");\n        Assertions.assertEquals(\"namespace\", builder.build().getNamespace());\n    }\n\n    @Test\n    void group() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.group(\"group\");\n        Assertions.assertEquals(\"group\", builder.build().getGroup());\n    }\n\n    @Test\n    void username() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.username(\"username\");\n        Assertions.assertEquals(\"username\", builder.build().getUsername());\n    }\n\n    @Test\n    void password() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.password(\"password\");\n        Assertions.assertEquals(\"password\", builder.build().getPassword());\n    }\n\n    @Test\n    void timeout() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.timeout(1000L);\n        Assertions.assertEquals(1000L, builder.build().getTimeout());\n    }\n\n    @Test\n    void highestPriority() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.highestPriority(true);\n        Assertions.assertTrue(builder.build().isHighestPriority());\n    }\n\n    @Test\n    void check() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.check(true);\n        Assertions.assertTrue(builder.build().isCheck());\n    }\n\n    @Test\n    void configFile() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.configFile(\"configFile\");\n        Assertions.assertEquals(\"configFile\", builder.build().getConfigFile());\n    }\n\n    @Test\n    void appConfigFile() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.appConfigFile(\"appConfigFile\");\n        Assertions.assertEquals(\"appConfigFile\", builder.build().getAppConfigFile());\n    }\n\n    @Test\n    void appendParameter() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.appendParameter(\"default.num\", \"one\").appendParameter(\"num\", \"ONE\");\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void appendParameters() {\n        Map<String, String> source = new HashMap<>();\n        source.put(\"default.num\", \"one\");\n        source.put(\"num\", \"ONE\");\n\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.appendParameters(source);\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void build() {\n        ConfigCenterBuilder builder = ConfigCenterBuilder.newBuilder();\n        builder.check(true)\n                .protocol(\"protocol\")\n                .address(\"address\")\n                .appConfigFile(\"appConfigFile\")\n                .cluster(\"cluster\")\n                .configFile(\"configFile\")\n                .group(\"group\")\n                .highestPriority(false)\n                .namespace(\"namespace\")\n                .password(\"password\")\n                .timeout(1000L)\n                .username(\"usernama\")\n                .appendParameter(\"default.num\", \"one\")\n                .id(\"id\");\n\n        ConfigCenterConfig config = builder.build();\n        ConfigCenterConfig config2 = builder.build();\n\n        Assertions.assertTrue(config.isCheck());\n        Assertions.assertFalse(config.isHighestPriority());\n        Assertions.assertEquals(1000L, config.getTimeout());\n        Assertions.assertEquals(\"protocol\", config.getProtocol());\n        Assertions.assertEquals(\"address\", config.getAddress());\n        Assertions.assertEquals(\"appConfigFile\", config.getAppConfigFile());\n        Assertions.assertEquals(\"cluster\", config.getCluster());\n        Assertions.assertEquals(\"configFile\", config.getConfigFile());\n        Assertions.assertEquals(\"group\", config.getGroup());\n        Assertions.assertEquals(\"namespace\", config.getNamespace());\n        Assertions.assertEquals(\"password\", config.getPassword());\n        Assertions.assertEquals(\"usernama\", config.getUsername());\n        Assertions.assertTrue(config.getParameters().containsKey(\"default.num\"));\n        Assertions.assertEquals(\"one\", config.getParameters().get(\"default.num\"));\n        Assertions.assertEquals(\"id\", config.getId());\n\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ConsumerBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ConsumerConfig;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ConsumerBuilderTest {\n\n    @Test\n    void isDefault() {\n        ConsumerBuilder builder = ConsumerBuilder.newBuilder();\n        builder.isDefault(false);\n        Assertions.assertFalse(builder.build().isDefault());\n    }\n\n    @Test\n    void client() {\n        ConsumerBuilder builder = ConsumerBuilder.newBuilder();\n        builder.client(\"client\");\n        Assertions.assertEquals(\"client\", builder.build().getClient());\n    }\n\n    @Test\n    void threadPool() {\n        ConsumerBuilder builder = ConsumerBuilder.newBuilder();\n        builder.threadPool(\"threadPool\");\n        Assertions.assertEquals(\"threadPool\", builder.build().getThreadpool());\n    }\n\n    @Test\n    void coreThreads() {\n        ConsumerBuilder builder = ConsumerBuilder.newBuilder();\n        builder.coreThreads(10);\n        Assertions.assertEquals(10, builder.build().getCorethreads());\n    }\n\n    @Test\n    void threads() {\n        ConsumerBuilder builder = ConsumerBuilder.newBuilder();\n        builder.threads(100);\n        Assertions.assertEquals(100, builder.build().getThreads());\n    }\n\n    @Test\n    void queues() {\n        ConsumerBuilder builder = ConsumerBuilder.newBuilder();\n        builder.queues(200);\n        Assertions.assertEquals(200, builder.build().getQueues());\n    }\n\n    @Test\n    void shareConnections() {\n        ConsumerBuilder builder = ConsumerBuilder.newBuilder();\n        builder.shareConnections(300);\n        Assertions.assertEquals(300, builder.build().getShareconnections());\n    }\n\n    @Test\n    void build() {\n        ConsumerBuilder builder = ConsumerBuilder.newBuilder();\n        builder.isDefault(true)\n                .client(\"client\")\n                .threadPool(\"threadPool\")\n                .coreThreads(10)\n                .threads(100)\n                .queues(200)\n                .shareConnections(300)\n                .id(\"id\");\n\n        ConsumerConfig config = builder.build();\n        ConsumerConfig config2 = builder.build();\n\n        Assertions.assertTrue(config.isDefault());\n        Assertions.assertEquals(\"client\", config.getClient());\n        Assertions.assertEquals(\"threadPool\", config.getThreadpool());\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertEquals(10, config.getCorethreads());\n        Assertions.assertEquals(100, config.getThreads());\n        Assertions.assertEquals(200, config.getQueues());\n        Assertions.assertEquals(300, config.getShareconnections());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/MetadataReportBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.MetadataReportConfig;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass MetadataReportBuilderTest {\n\n    @Test\n    void address() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.address(\"address\");\n        Assertions.assertEquals(\"address\", builder.build().getAddress());\n    }\n\n    @Test\n    void username() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.username(\"username\");\n        Assertions.assertEquals(\"username\", builder.build().getUsername());\n    }\n\n    @Test\n    void password() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.password(\"password\");\n        Assertions.assertEquals(\"password\", builder.build().getPassword());\n    }\n\n    @Test\n    void timeout() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.timeout(1000);\n        Assertions.assertEquals(1000, builder.build().getTimeout());\n    }\n\n    @Test\n    void group() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.group(\"group\");\n        Assertions.assertEquals(\"group\", builder.build().getGroup());\n    }\n\n    @Test\n    void appendParameter() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.appendParameter(\"default.num\", \"one\").appendParameter(\"num\", \"ONE\");\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void appendParameters() {\n        Map<String, String> source = new HashMap<>();\n        source.put(\"default.num\", \"one\");\n        source.put(\"num\", \"ONE\");\n\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.appendParameters(source);\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void retryTimes() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.retryTimes(1);\n        Assertions.assertEquals(1, builder.build().getRetryTimes());\n    }\n\n    @Test\n    void retryPeriod() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.retryPeriod(2);\n        Assertions.assertEquals(2, builder.build().getRetryPeriod());\n    }\n\n    @Test\n    void cycleReport() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.cycleReport(true);\n        Assertions.assertTrue(builder.build().getCycleReport());\n        builder.cycleReport(false);\n        Assertions.assertFalse(builder.build().getCycleReport());\n        builder.cycleReport(null);\n        Assertions.assertNull(builder.build().getCycleReport());\n    }\n\n    @Test\n    void syncReport() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.syncReport(true);\n        Assertions.assertTrue(builder.build().getSyncReport());\n        builder.syncReport(false);\n        Assertions.assertFalse(builder.build().getSyncReport());\n        builder.syncReport(null);\n        Assertions.assertNull(builder.build().getSyncReport());\n    }\n\n    @Test\n    void build() {\n        MetadataReportBuilder builder = new MetadataReportBuilder();\n        builder.address(\"address\")\n                .username(\"username\")\n                .password(\"password\")\n                .timeout(1000)\n                .group(\"group\")\n                .retryTimes(1)\n                .retryPeriod(2)\n                .cycleReport(true)\n                .syncReport(false)\n                .appendParameter(\"default.num\", \"one\")\n                .id(\"id\");\n\n        MetadataReportConfig config = builder.build();\n        MetadataReportConfig config2 = builder.build();\n\n        Assertions.assertTrue(config.getCycleReport());\n        Assertions.assertFalse(config.getSyncReport());\n        Assertions.assertEquals(1000, config.getTimeout());\n        Assertions.assertEquals(1, config.getRetryTimes());\n        Assertions.assertEquals(2, config.getRetryPeriod());\n        Assertions.assertEquals(\"address\", config.getAddress());\n        Assertions.assertEquals(\"username\", config.getUsername());\n        Assertions.assertEquals(\"password\", config.getPassword());\n        Assertions.assertEquals(\"group\", config.getGroup());\n        Assertions.assertTrue(config.getParameters().containsKey(\"default.num\"));\n        Assertions.assertEquals(\"one\", config.getParameters().get(\"default.num\"));\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/MethodBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ArgumentConfig;\nimport org.apache.dubbo.config.MethodConfig;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass MethodBuilderTest {\n\n    @Test\n    void name() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.name(\"name\");\n        Assertions.assertEquals(\"name\", builder.build().getName());\n    }\n\n    @Test\n    void stat() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.stat(1);\n        Assertions.assertEquals(1, builder.build().getStat());\n    }\n\n    @Test\n    void retry() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.retry(true);\n        Assertions.assertTrue(builder.build().isRetry());\n    }\n\n    @Test\n    void reliable() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.reliable(true);\n        Assertions.assertTrue(builder.build().isReliable());\n    }\n\n    @Test\n    void executes() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.executes(1);\n        Assertions.assertEquals(1, builder.build().getExecutes());\n    }\n\n    @Test\n    void deprecated() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.deprecated(true);\n        Assertions.assertTrue(builder.build().getDeprecated());\n    }\n\n    @Test\n    void sticky() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.sticky(true);\n        Assertions.assertTrue(builder.build().getSticky());\n    }\n\n    @Test\n    void isReturn() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.isReturn(true);\n        Assertions.assertTrue(builder.build().isReturn());\n    }\n\n    @Test\n    void oninvoke() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.oninvoke(\"on-invoke-object\");\n        Assertions.assertEquals(\"on-invoke-object\", builder.build().getOninvoke());\n    }\n\n    @Test\n    void oninvokeMethod() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.oninvokeMethod(\"on-invoke-method\");\n        Assertions.assertEquals(\"on-invoke-method\", builder.build().getOninvokeMethod());\n    }\n\n    @Test\n    void onreturn() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.onreturn(\"on-return-object\");\n        Assertions.assertEquals(\"on-return-object\", builder.build().getOnreturn());\n    }\n\n    @Test\n    void onreturnMethod() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.onreturnMethod(\"on-return-method\");\n        Assertions.assertEquals(\"on-return-method\", builder.build().getOnreturnMethod());\n    }\n\n    @Test\n    void onthrow() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.onthrow(\"on-throw-object\");\n        Assertions.assertEquals(\"on-throw-object\", builder.build().getOnthrow());\n    }\n\n    @Test\n    void onthrowMethod() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.onthrowMethod(\"on-throw-method\");\n        Assertions.assertEquals(\"on-throw-method\", builder.build().getOnthrowMethod());\n    }\n\n    @Test\n    void addArguments() {\n        ArgumentConfig argument = new ArgumentConfig();\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.addArguments(Collections.singletonList(argument));\n        Assertions.assertTrue(builder.build().getArguments().contains(argument));\n        Assertions.assertEquals(1, builder.build().getArguments().size());\n    }\n\n    @Test\n    void addArgument() {\n        ArgumentConfig argument = new ArgumentConfig();\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.addArgument(argument);\n        Assertions.assertTrue(builder.build().getArguments().contains(argument));\n        Assertions.assertEquals(1, builder.build().getArguments().size());\n    }\n\n    @Test\n    void service() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.service(\"service\");\n        Assertions.assertEquals(\"service\", builder.build().getService());\n    }\n\n    @Test\n    void serviceId() {\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.serviceId(\"serviceId\");\n        Assertions.assertEquals(\"serviceId\", builder.build().getServiceId());\n    }\n\n    @Test\n    void build() {\n        ArgumentConfig argument = new ArgumentConfig();\n        MethodBuilder builder = MethodBuilder.newBuilder();\n        builder.name(\"name\")\n                .stat(1)\n                .retry(true)\n                .reliable(false)\n                .executes(2)\n                .deprecated(true)\n                .sticky(false)\n                .isReturn(true)\n                .oninvoke(\"on-invoke-object\")\n                .oninvokeMethod(\"on-invoke-method\")\n                .service(\"service\")\n                .onreturn(\"on-return-object\")\n                .onreturnMethod(\"on-return-method\")\n                .serviceId(\"serviceId\")\n                .onthrow(\"on-throw-object\")\n                .onthrowMethod(\"on-throw-method\")\n                .addArgument(argument);\n\n        MethodConfig config = builder.build();\n        MethodConfig config2 = builder.build();\n\n        Assertions.assertTrue(config.isRetry());\n        Assertions.assertFalse(config.isReliable());\n        Assertions.assertTrue(config.getDeprecated());\n        Assertions.assertFalse(config.getSticky());\n        Assertions.assertTrue(config.isReturn());\n        Assertions.assertEquals(1, config.getStat());\n        Assertions.assertEquals(2, config.getExecutes());\n        Assertions.assertEquals(\"on-invoke-object\", config.getOninvoke());\n        Assertions.assertEquals(\"on-invoke-method\", config.getOninvokeMethod());\n        Assertions.assertEquals(\"on-return-object\", config.getOnreturn());\n        Assertions.assertEquals(\"on-return-method\", config.getOnreturnMethod());\n        Assertions.assertEquals(\"on-throw-object\", config.getOnthrow());\n        Assertions.assertEquals(\"on-throw-method\", config.getOnthrowMethod());\n        Assertions.assertEquals(\"name\", config.getName());\n        Assertions.assertEquals(\"service\", config.getService());\n        Assertions.assertEquals(\"serviceId\", config.getServiceId());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/MetricsBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.nested.AggregationConfig;\nimport org.apache.dubbo.config.nested.HistogramConfig;\nimport org.apache.dubbo.config.nested.PrometheusConfig;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass MetricsBuilderTest {\n\n    @Test\n    void protocol() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.protocol(\"test\");\n        Assertions.assertEquals(\"test\", builder.build().getProtocol());\n    }\n\n    @Test\n    void enableJvm() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.enableJvm(true);\n        Assertions.assertTrue(builder.build().getEnableJvm());\n    }\n\n    @Test\n    void enableThreadPool() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.enableThreadPool(false);\n        Assertions.assertFalse(builder.build().getEnableThreadpool());\n    }\n\n    @Test\n    void enableRegistry() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.enableRegistry(true);\n        Assertions.assertTrue(builder.build().getEnableRegistry());\n    }\n\n    @Test\n    void enableMetadata() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.enableMetadata(true);\n        Assertions.assertTrue(builder.build().getEnableMetadata());\n    }\n\n    @Test\n    void exportMetricsService() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.exportMetricsService(false);\n        Assertions.assertFalse(builder.build().getExportMetricsService());\n    }\n\n    @Test\n    void enableMetricsInit() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.enableMetricsInit(true);\n        Assertions.assertTrue(builder.build().getEnableMetricsInit());\n    }\n\n    @Test\n    void enableCollectorSync() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.enableCollectorSync(true);\n        Assertions.assertTrue(builder.build().getEnableCollectorSync());\n    }\n\n    @Test\n    void collectorSyncPeriod() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.collectorSyncPeriod(10);\n        Assertions.assertEquals(10, builder.build().getCollectorSyncPeriod());\n    }\n\n    @Test\n    void exportServiceProtocol() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.exportServiceProtocol(\"tri\");\n        Assertions.assertEquals(\"tri\", builder.build().getExportServiceProtocol());\n    }\n\n    @Test\n    void exportServicePort() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.exportServicePort(2999);\n        Assertions.assertEquals(2999, builder.build().getExportServicePort());\n    }\n\n    @Test\n    void useGlobalRegistry() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.useGlobalRegistry(true);\n        Assertions.assertTrue(builder.build().getUseGlobalRegistry());\n    }\n\n    @Test\n    void enableRpc() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.enableRpc(false);\n        Assertions.assertFalse(builder.build().getEnableRpc());\n    }\n\n    @Test\n    void rpcLevel() {\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.rpcLevel(\"SERVICE\");\n        Assertions.assertEquals(\"SERVICE\", builder.build().getRpcLevel());\n    }\n\n    @Test\n    void aggregation() {\n        AggregationConfig aggregation = new AggregationConfig();\n        aggregation.setEnabled(true);\n        aggregation.setEnableQps(false);\n        aggregation.setBucketNum(100);\n\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.aggregation(aggregation);\n\n        Assertions.assertSame(aggregation, builder.build().getAggregation());\n        Assertions.assertTrue(builder.build().getAggregation().getEnabled());\n        Assertions.assertFalse(builder.build().getAggregation().getEnableQps());\n        Assertions.assertEquals(100, builder.build().getAggregation().getBucketNum());\n    }\n\n    @Test\n    void histogram() {\n        HistogramConfig histogram = new HistogramConfig();\n        histogram.setEnabled(true);\n        histogram.setMaxExpectedMs(1000);\n        histogram.setBucketsMs(new Integer[] {100, 200, 300, 400, 500});\n        histogram.setPercentiles(new double[] {0.5, 0.9, 0.95, 0.99});\n\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.histogram(histogram);\n\n        Assertions.assertSame(histogram, builder.build().getHistogram());\n        Assertions.assertTrue(builder.build().getHistogram().getEnabled());\n        Assertions.assertEquals(1000, builder.build().getHistogram().getMaxExpectedMs());\n        Assertions.assertArrayEquals(\n                new Integer[] {100, 200, 300, 400, 500},\n                builder.build().getHistogram().getBucketsMs());\n        Assertions.assertArrayEquals(\n                new double[] {0.5, 0.9, 0.95, 0.99},\n                builder.build().getHistogram().getPercentiles());\n    }\n\n    @Test\n    void prometheus() {\n        PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();\n        exporter.setEnabled(true);\n        exporter.setEnableHttpServiceDiscovery(true);\n        exporter.setHttpServiceDiscoveryUrl(\"localhost:8080\");\n\n        PrometheusConfig.Pushgateway pushGateway = new PrometheusConfig.Pushgateway();\n        pushGateway.setEnabled(true);\n        pushGateway.setBaseUrl(\"localhost:9091\");\n        pushGateway.setUsername(\"username\");\n        pushGateway.setPassword(\"password\");\n        pushGateway.setJob(\"job\");\n        pushGateway.setPushInterval(30);\n\n        PrometheusConfig prometheus = new PrometheusConfig();\n        prometheus.setExporter(exporter);\n        prometheus.setPushgateway(pushGateway);\n\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.prometheus(prometheus);\n\n        Assertions.assertSame(prometheus, builder.build().getPrometheus());\n        Assertions.assertSame(exporter, builder.build().getPrometheus().getExporter());\n        Assertions.assertSame(pushGateway, builder.build().getPrometheus().getPushgateway());\n        Assertions.assertTrue(builder.build().getPrometheus().getExporter().getEnabled());\n        Assertions.assertTrue(builder.build().getPrometheus().getExporter().getEnableHttpServiceDiscovery());\n        Assertions.assertEquals(\n                \"localhost:8080\", builder.build().getPrometheus().getExporter().getHttpServiceDiscoveryUrl());\n        Assertions.assertTrue(builder.build().getPrometheus().getPushgateway().getEnabled());\n        Assertions.assertEquals(\n                \"localhost:9091\",\n                builder.build().getPrometheus().getPushgateway().getBaseUrl());\n        Assertions.assertEquals(\n                \"username\", builder.build().getPrometheus().getPushgateway().getUsername());\n        Assertions.assertEquals(\n                \"password\", builder.build().getPrometheus().getPushgateway().getPassword());\n        Assertions.assertEquals(\n                \"job\", builder.build().getPrometheus().getPushgateway().getJob());\n        Assertions.assertEquals(\n                30, builder.build().getPrometheus().getPushgateway().getPushInterval());\n    }\n\n    @Test\n    void build() {\n        PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();\n        exporter.setEnabled(true);\n        exporter.setEnableHttpServiceDiscovery(true);\n        exporter.setHttpServiceDiscoveryUrl(\"localhost:8080\");\n\n        PrometheusConfig.Pushgateway pushGateway = new PrometheusConfig.Pushgateway();\n        pushGateway.setEnabled(true);\n        pushGateway.setBaseUrl(\"localhost:9091\");\n        pushGateway.setUsername(\"username\");\n        pushGateway.setPassword(\"password\");\n        pushGateway.setJob(\"job\");\n        pushGateway.setPushInterval(30);\n\n        PrometheusConfig prometheus = new PrometheusConfig();\n        prometheus.setExporter(exporter);\n        prometheus.setPushgateway(pushGateway);\n\n        HistogramConfig histogram = new HistogramConfig();\n        histogram.setEnabled(true);\n        histogram.setMaxExpectedMs(1000);\n        histogram.setBucketsMs(new Integer[] {100, 200, 300, 400, 500});\n        histogram.setPercentiles(new double[] {0.5, 0.9, 0.95, 0.99});\n\n        AggregationConfig aggregation = new AggregationConfig();\n        aggregation.setEnabled(true);\n        aggregation.setEnableQps(false);\n        aggregation.setBucketNum(100);\n\n        MetricsBuilder builder = MetricsBuilder.newBuilder();\n        builder.protocol(\"test\")\n                .enableJvm(true)\n                .enableThreadPool(true)\n                .enableRegistry(false)\n                .enableMetadata(false)\n                .exportMetricsService(true)\n                .enableMetricsInit(false)\n                .enableCollectorSync(true)\n                .collectorSyncPeriod(10)\n                .prometheus(prometheus)\n                .histogram(histogram)\n                .aggregation(aggregation)\n                .exportServiceProtocol(\"tri\")\n                .exportServicePort(10010)\n                .useGlobalRegistry(true)\n                .enableRpc(true)\n                .rpcLevel(\"METHOD\");\n\n        MetricsConfig config = builder.build();\n        MetricsConfig config2 = builder.build();\n\n        Assertions.assertEquals(\"test\", config.getProtocol());\n        Assertions.assertTrue(config.getEnableJvm());\n        Assertions.assertTrue(config.getEnableThreadpool());\n        Assertions.assertFalse(config.getEnableRegistry());\n        Assertions.assertFalse(config.getEnableMetadata());\n        Assertions.assertTrue(config.getExportMetricsService());\n        Assertions.assertFalse(config.getEnableMetricsInit());\n        Assertions.assertTrue(config.getEnableCollectorSync());\n        Assertions.assertEquals(10, config.getCollectorSyncPeriod());\n        Assertions.assertSame(prometheus, config.getPrometheus());\n        Assertions.assertSame(exporter, config.getPrometheus().getExporter());\n        Assertions.assertSame(pushGateway, config.getPrometheus().getPushgateway());\n        Assertions.assertTrue(config.getPrometheus().getExporter().getEnabled());\n        Assertions.assertTrue(config.getPrometheus().getExporter().getEnableHttpServiceDiscovery());\n        Assertions.assertEquals(\n                \"localhost:8080\", config.getPrometheus().getExporter().getHttpServiceDiscoveryUrl());\n        Assertions.assertTrue(config.getPrometheus().getPushgateway().getEnabled());\n        Assertions.assertEquals(\n                \"localhost:9091\", config.getPrometheus().getPushgateway().getBaseUrl());\n        Assertions.assertEquals(\n                \"username\", config.getPrometheus().getPushgateway().getUsername());\n        Assertions.assertEquals(\n                \"password\", config.getPrometheus().getPushgateway().getPassword());\n        Assertions.assertEquals(\"job\", config.getPrometheus().getPushgateway().getJob());\n        Assertions.assertEquals(30, config.getPrometheus().getPushgateway().getPushInterval());\n        Assertions.assertSame(histogram, config.getHistogram());\n        Assertions.assertTrue(config.getHistogram().getEnabled());\n        Assertions.assertEquals(1000, config.getHistogram().getMaxExpectedMs());\n        Assertions.assertArrayEquals(\n                new Integer[] {100, 200, 300, 400, 500}, config.getHistogram().getBucketsMs());\n        Assertions.assertArrayEquals(\n                new double[] {0.5, 0.9, 0.95, 0.99}, config.getHistogram().getPercentiles());\n        Assertions.assertSame(aggregation, config.getAggregation());\n        Assertions.assertTrue(config.getAggregation().getEnabled());\n        Assertions.assertFalse(config.getAggregation().getEnableQps());\n        Assertions.assertEquals(100, config.getAggregation().getBucketNum());\n        Assertions.assertEquals(\"tri\", config.getExportServiceProtocol());\n        Assertions.assertEquals(10010, config.getExportServicePort());\n        Assertions.assertTrue(config.getUseGlobalRegistry());\n        Assertions.assertTrue(config.getEnableRpc());\n        Assertions.assertEquals(\"METHOD\", config.getRpcLevel());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ModuleBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.RegistryConfig;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ModuleBuilderTest {\n\n    @Test\n    void name() {\n        ModuleBuilder builder = ModuleBuilder.newBuilder();\n        builder.name(\"name\");\n        Assertions.assertEquals(\"name\", builder.build().getName());\n    }\n\n    @Test\n    void version() {\n        ModuleBuilder builder = ModuleBuilder.newBuilder();\n        builder.version(\"version\");\n        Assertions.assertEquals(\"version\", builder.build().getVersion());\n    }\n\n    @Test\n    void owner() {\n        ModuleBuilder builder = ModuleBuilder.newBuilder();\n        builder.owner(\"owner\");\n        Assertions.assertEquals(\"owner\", builder.build().getOwner());\n    }\n\n    @Test\n    void organization() {\n        ModuleBuilder builder = ModuleBuilder.newBuilder();\n        builder.organization(\"organization\");\n        Assertions.assertEquals(\"organization\", builder.build().getOrganization());\n    }\n\n    @Test\n    void addRegistries() {\n        RegistryConfig registry = new RegistryConfig();\n        ModuleBuilder builder = ModuleBuilder.newBuilder();\n        builder.addRegistries(Collections.singletonList(registry));\n        Assertions.assertTrue(builder.build().getRegistries().contains(registry));\n        Assertions.assertEquals(1, builder.build().getRegistries().size());\n    }\n\n    @Test\n    void addRegistry() {\n        RegistryConfig registry = new RegistryConfig();\n        ModuleBuilder builder = ModuleBuilder.newBuilder();\n        builder.addRegistry(registry);\n        Assertions.assertTrue(builder.build().getRegistries().contains(registry));\n        Assertions.assertEquals(1, builder.build().getRegistries().size());\n    }\n\n    @Test\n    void monitor() {\n        MonitorConfig monitor = new MonitorConfig();\n        ModuleBuilder builder = ModuleBuilder.newBuilder();\n        builder.monitor(monitor);\n        Assertions.assertSame(monitor, builder.build().getMonitor());\n    }\n\n    @Test\n    void isDefault() {\n        ModuleBuilder builder = ModuleBuilder.newBuilder();\n        builder.isDefault(true);\n        Assertions.assertTrue(builder.build().isDefault());\n    }\n\n    @Test\n    void build() {\n        RegistryConfig registry = new RegistryConfig();\n        MonitorConfig monitor = new MonitorConfig();\n\n        ModuleBuilder builder = ModuleBuilder.newBuilder();\n        builder.name(\"name\")\n                .version(\"version\")\n                .owner(\"owner\")\n                .organization(\"organization\")\n                .addRegistry(registry)\n                .monitor(monitor)\n                .isDefault(false);\n\n        ModuleConfig config = builder.build();\n        ModuleConfig config2 = builder.build();\n\n        Assertions.assertEquals(\"name\", config.getName());\n        Assertions.assertEquals(\"version\", config.getVersion());\n        Assertions.assertEquals(\"owner\", config.getOwner());\n        Assertions.assertEquals(\"organization\", config.getOrganization());\n        Assertions.assertTrue(builder.build().getRegistries().contains(registry));\n        Assertions.assertSame(monitor, builder.build().getMonitor());\n        Assertions.assertFalse(config.isDefault());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/MonitorBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.MonitorConfig;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass MonitorBuilderTest {\n\n    @Test\n    void protocol() {\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.protocol(\"protocol\");\n        Assertions.assertEquals(\"protocol\", builder.build().getProtocol());\n    }\n\n    @Test\n    void address() {\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.address(\"address\");\n        Assertions.assertEquals(\"address\", builder.build().getAddress());\n    }\n\n    @Test\n    void username() {\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.username(\"username\");\n        Assertions.assertEquals(\"username\", builder.build().getUsername());\n    }\n\n    @Test\n    void password() {\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.password(\"password\");\n        Assertions.assertEquals(\"password\", builder.build().getPassword());\n    }\n\n    @Test\n    void group() {\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.group(\"group\");\n        Assertions.assertEquals(\"group\", builder.build().getGroup());\n    }\n\n    @Test\n    void version() {\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.version(\"version\");\n        Assertions.assertEquals(\"version\", builder.build().getVersion());\n    }\n\n    @Test\n    void interval() {\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.interval(\"interval\");\n        Assertions.assertEquals(\"interval\", builder.build().getInterval());\n    }\n\n    @Test\n    void isDefault() {\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.isDefault(true);\n        Assertions.assertTrue(builder.build().isDefault());\n    }\n\n    @Test\n    void appendParameter() {\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.appendParameter(\"default.num\", \"one\").appendParameter(\"num\", \"ONE\");\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void appendParameters() {\n        Map<String, String> source = new HashMap<>();\n        source.put(\"default.num\", \"one\");\n        source.put(\"num\", \"ONE\");\n\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.appendParameters(source);\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void build() {\n        MonitorBuilder builder = MonitorBuilder.newBuilder();\n        builder.protocol(\"protocol\")\n                .address(\"address\")\n                .group(\"group\")\n                .interval(\"interval\")\n                .isDefault(true)\n                .password(\"password\")\n                .username(\"username\")\n                .version(\"version\")\n                .appendParameter(\"default.num\", \"one\")\n                .id(\"id\");\n\n        MonitorConfig config = builder.build();\n        MonitorConfig config2 = builder.build();\n\n        Assertions.assertEquals(\"protocol\", config.getProtocol());\n        Assertions.assertEquals(\"address\", config.getAddress());\n        Assertions.assertEquals(\"group\", config.getGroup());\n        Assertions.assertEquals(\"interval\", config.getInterval());\n        Assertions.assertEquals(\"password\", config.getPassword());\n        Assertions.assertEquals(\"username\", config.getUsername());\n        Assertions.assertEquals(\"version\", config.getVersion());\n        Assertions.assertTrue(config.isDefault());\n        Assertions.assertTrue(config.getParameters().containsKey(\"default.num\"));\n        Assertions.assertEquals(\"one\", config.getParameters().get(\"default.num\"));\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ProtocolBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ProtocolConfig;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ProtocolBuilderTest {\n\n    @Test\n    void name() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.name(\"name\");\n        Assertions.assertEquals(\"name\", builder.build().getName());\n    }\n\n    @Test\n    void host() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.host(\"host\");\n        Assertions.assertEquals(\"host\", builder.build().getHost());\n    }\n\n    @Test\n    void port() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.port(8080);\n        Assertions.assertEquals(8080, builder.build().getPort());\n    }\n\n    @Test\n    void contextpath() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.contextpath(\"contextpath\");\n        Assertions.assertEquals(\"contextpath\", builder.build().getContextpath());\n    }\n\n    @Test\n    void path() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.path(\"path\");\n        Assertions.assertEquals(\"path\", builder.build().getPath());\n    }\n\n    @Test\n    void threadpool() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.threadpool(\"mockthreadpool\");\n        Assertions.assertEquals(\"mockthreadpool\", builder.build().getThreadpool());\n    }\n\n    @Test\n    void corethreads() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.corethreads(10);\n        Assertions.assertEquals(10, builder.build().getCorethreads());\n    }\n\n    @Test\n    void threads() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.threads(20);\n        Assertions.assertEquals(20, builder.build().getThreads());\n    }\n\n    @Test\n    void iothreads() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.iothreads(25);\n        Assertions.assertEquals(25, builder.build().getIothreads());\n    }\n\n    @Test\n    void queues() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.queues(30);\n        Assertions.assertEquals(30, builder.build().getQueues());\n    }\n\n    @Test\n    void accepts() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.accepts(35);\n        Assertions.assertEquals(35, builder.build().getAccepts());\n    }\n\n    @Test\n    void codec() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.codec(\"mockcodec\");\n        Assertions.assertEquals(\"mockcodec\", builder.build().getCodec());\n    }\n\n    @Test\n    void serialization() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.serialization(\"serialization\");\n        Assertions.assertEquals(\"serialization\", builder.build().getSerialization());\n    }\n\n    @Test\n    void charset() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.charset(\"utf-8\");\n        Assertions.assertEquals(\"utf-8\", builder.build().getCharset());\n    }\n\n    @Test\n    void payload() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.payload(40);\n        Assertions.assertEquals(40, builder.build().getPayload());\n    }\n\n    @Test\n    void buffer() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.buffer(1024);\n        Assertions.assertEquals(1024, builder.build().getBuffer());\n    }\n\n    @Test\n    void heartbeat() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.heartbeat(1000);\n        Assertions.assertEquals(1000, builder.build().getHeartbeat());\n    }\n\n    @Test\n    void accesslog() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.accesslog(\"accesslog\");\n        Assertions.assertEquals(\"accesslog\", builder.build().getAccesslog());\n    }\n\n    @Test\n    void transporter() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.transporter(\"mocktransporter\");\n        Assertions.assertEquals(\"mocktransporter\", builder.build().getTransporter());\n    }\n\n    @Test\n    void exchanger() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.exchanger(\"mockexchanger\");\n        Assertions.assertEquals(\"mockexchanger\", builder.build().getExchanger());\n    }\n\n    @Test\n    void dispatcher() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.dispatcher(\"mockdispatcher\");\n        Assertions.assertEquals(\"mockdispatcher\", builder.build().getDispatcher());\n    }\n\n    @Test\n    void dispather() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.dispather(\"mockdispatcher\");\n        Assertions.assertEquals(\"mockdispatcher\", builder.build().getDispatcher());\n    }\n\n    @Test\n    void networker() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.networker(\"networker\");\n        Assertions.assertEquals(\"networker\", builder.build().getNetworker());\n    }\n\n    @Test\n    void server() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.server(\"server\");\n        Assertions.assertEquals(\"server\", builder.build().getServer());\n    }\n\n    @Test\n    void client() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.client(\"client\");\n        Assertions.assertEquals(\"client\", builder.build().getClient());\n    }\n\n    @Test\n    void telnet() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.telnet(\"mocktelnethandler\");\n        Assertions.assertEquals(\"mocktelnethandler\", builder.build().getTelnet());\n    }\n\n    @Test\n    void prompt() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.prompt(\"prompt\");\n        Assertions.assertEquals(\"prompt\", builder.build().getPrompt());\n    }\n\n    @Test\n    void status() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.status(\"mockstatuschecker\");\n        Assertions.assertEquals(\"mockstatuschecker\", builder.build().getStatus());\n    }\n\n    @Test\n    void register() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.register(true);\n        Assertions.assertTrue(builder.build().isRegister());\n    }\n\n    @Test\n    void keepAlive() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.keepAlive(true);\n        Assertions.assertTrue(builder.build().getKeepAlive());\n    }\n\n    @Test\n    void optimizer() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.optimizer(\"optimizer\");\n        Assertions.assertEquals(\"optimizer\", builder.build().getOptimizer());\n    }\n\n    @Test\n    void extension() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.extension(\"extension\");\n        Assertions.assertEquals(\"extension\", builder.build().getExtension());\n    }\n\n    @Test\n    void appendParameter() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.appendParameter(\"default.num\", \"one\").appendParameter(\"num\", \"ONE\");\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void appendParameters() {\n        Map<String, String> source = new HashMap<>();\n        source.put(\"default.num\", \"one\");\n        source.put(\"num\", \"ONE\");\n\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.appendParameters(source);\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void isDefault() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.isDefault(true);\n        Assertions.assertTrue(builder.build().isDefault());\n    }\n\n    @Test\n    void build() {\n        ProtocolBuilder builder = new ProtocolBuilder();\n        builder.name(\"name\")\n                .host(\"host\")\n                .port(8080)\n                .contextpath(\"contextpath\")\n                .threadpool(\"mockthreadpool\")\n                .corethreads(1)\n                .threads(2)\n                .iothreads(3)\n                .queues(4)\n                .accepts(5)\n                .codec(\"mockcodec\")\n                .serialization(\"serialization\")\n                .charset(\"utf-8\")\n                .payload(6)\n                .buffer(1024)\n                .heartbeat(1000)\n                .accesslog(\"accesslog\")\n                .transporter(\"mocktransporter\")\n                .exchanger(\"mockexchanger\")\n                .dispatcher(\"mockdispatcher\")\n                .networker(\"networker\")\n                .server(\"server\")\n                .client(\"client\")\n                .telnet(\"mocktelnethandler\")\n                .prompt(\"prompt\")\n                .status(\"mockstatuschecker\")\n                .register(true)\n                .keepAlive(false)\n                .optimizer(\"optimizer\")\n                .extension(\"extension\")\n                .isDefault(true)\n                .appendParameter(\"default.num\", \"one\")\n                .id(\"id\");\n\n        ProtocolConfig config = builder.build();\n        ProtocolConfig config2 = builder.build();\n\n        Assertions.assertEquals(8080, config.getPort());\n        Assertions.assertEquals(1, config.getCorethreads());\n        Assertions.assertEquals(2, config.getThreads());\n        Assertions.assertEquals(3, config.getIothreads());\n        Assertions.assertEquals(4, config.getQueues());\n        Assertions.assertEquals(5, config.getAccepts());\n        Assertions.assertEquals(6, config.getPayload());\n        Assertions.assertEquals(1024, config.getBuffer());\n        Assertions.assertEquals(1000, config.getHeartbeat());\n        Assertions.assertEquals(\"name\", config.getName());\n        Assertions.assertEquals(\"host\", config.getHost());\n        Assertions.assertEquals(\"contextpath\", config.getContextpath());\n        Assertions.assertEquals(\"mockthreadpool\", config.getThreadpool());\n        Assertions.assertEquals(\"mockcodec\", config.getCodec());\n        Assertions.assertEquals(\"serialization\", config.getSerialization());\n        Assertions.assertEquals(\"utf-8\", config.getCharset());\n        Assertions.assertEquals(\"accesslog\", config.getAccesslog());\n        Assertions.assertEquals(\"mocktransporter\", config.getTransporter());\n        Assertions.assertEquals(\"mockexchanger\", config.getExchanger());\n        Assertions.assertEquals(\"mockdispatcher\", config.getDispatcher());\n        Assertions.assertEquals(\"networker\", config.getNetworker());\n        Assertions.assertEquals(\"server\", config.getServer());\n        Assertions.assertEquals(\"client\", config.getClient());\n        Assertions.assertEquals(\"mocktelnethandler\", config.getTelnet());\n        Assertions.assertEquals(\"prompt\", config.getPrompt());\n        Assertions.assertEquals(\"mockstatuschecker\", config.getStatus());\n        Assertions.assertEquals(\"optimizer\", config.getOptimizer());\n        Assertions.assertEquals(\"extension\", config.getExtension());\n        Assertions.assertTrue(config.isRegister());\n        Assertions.assertFalse(config.getKeepAlive());\n        Assertions.assertTrue(config.isDefault());\n        Assertions.assertTrue(config.getParameters().containsKey(\"default.num\"));\n        Assertions.assertEquals(\"one\", config.getParameters().get(\"default.num\"));\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ProviderBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ProviderConfig;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass ProviderBuilderTest {\n\n    @Test\n    void setHost() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.host(\"host\");\n        Assertions.assertEquals(\"host\", builder.build().getHost());\n    }\n\n    @Test\n    void port() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.port(8080);\n        Assertions.assertEquals(8080, builder.build().getPort());\n    }\n\n    @Test\n    void contextPath() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.contextPath(\"contextpath\");\n        Assertions.assertEquals(\"contextpath\", builder.build().getContextpath());\n    }\n\n    @Test\n    void threadPool() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.threadPool(\"mockthreadpool\");\n        Assertions.assertEquals(\"mockthreadpool\", builder.build().getThreadpool());\n    }\n\n    @Test\n    void threads() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.threads(20);\n        Assertions.assertEquals(20, builder.build().getThreads());\n    }\n\n    @Test\n    void ioThreads() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.ioThreads(25);\n        Assertions.assertEquals(25, builder.build().getIothreads());\n    }\n\n    @Test\n    void queues() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.queues(30);\n        Assertions.assertEquals(30, builder.build().getQueues());\n    }\n\n    @Test\n    void accepts() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.accepts(35);\n        Assertions.assertEquals(35, builder.build().getAccepts());\n    }\n\n    @Test\n    void codec() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.codec(\"mockcodec\");\n        Assertions.assertEquals(\"mockcodec\", builder.build().getCodec());\n    }\n\n    @Test\n    void charset() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.charset(\"utf-8\");\n        Assertions.assertEquals(\"utf-8\", builder.build().getCharset());\n    }\n\n    @Test\n    void payload() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.payload(40);\n        Assertions.assertEquals(40, builder.build().getPayload());\n    }\n\n    @Test\n    void buffer() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.buffer(1024);\n        Assertions.assertEquals(1024, builder.build().getBuffer());\n    }\n\n    @Test\n    void transporter() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.transporter(\"mocktransporter\");\n        Assertions.assertEquals(\"mocktransporter\", builder.build().getTransporter());\n    }\n\n    @Test\n    void exchanger() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.exchanger(\"mockexchanger\");\n        Assertions.assertEquals(\"mockexchanger\", builder.build().getExchanger());\n    }\n\n    @Test\n    void dispatcher() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.dispatcher(\"mockdispatcher\");\n        Assertions.assertEquals(\"mockdispatcher\", builder.build().getDispatcher());\n    }\n\n    @Test\n    void networker() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.networker(\"networker\");\n        Assertions.assertEquals(\"networker\", builder.build().getNetworker());\n    }\n\n    @Test\n    void server() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.server(\"server\");\n        Assertions.assertEquals(\"server\", builder.build().getServer());\n    }\n\n    @Test\n    void client() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.client(\"client\");\n        Assertions.assertEquals(\"client\", builder.build().getClient());\n    }\n\n    @Test\n    void telnet() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.telnet(\"mocktelnethandler\");\n        Assertions.assertEquals(\"mocktelnethandler\", builder.build().getTelnet());\n    }\n\n    @Test\n    void prompt() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.prompt(\"prompt\");\n        Assertions.assertEquals(\"prompt\", builder.build().getPrompt());\n    }\n\n    @Test\n    void status() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.status(\"mockstatuschecker\");\n        Assertions.assertEquals(\"mockstatuschecker\", builder.build().getStatus());\n    }\n\n    @Test\n    void Wait() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.wait(Integer.valueOf(1000));\n        Assertions.assertEquals(1000, builder.build().getWait());\n    }\n\n    @Test\n    void isDefault() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.isDefault(true);\n        Assertions.assertTrue(builder.build().isDefault());\n    }\n\n    @Test\n    void build() {\n        ProviderBuilder builder = ProviderBuilder.newBuilder();\n        builder.host(\"host\")\n                .port(8080)\n                .contextPath(\"contextpath\")\n                .threadPool(\"mockthreadpool\")\n                .threads(2)\n                .ioThreads(3)\n                .queues(4)\n                .accepts(5)\n                .codec(\"mockcodec\")\n                .charset(\"utf-8\")\n                .payload(6)\n                .buffer(1024)\n                .transporter(\"mocktransporter\")\n                .exchanger(\"mockexchanger\")\n                .dispatcher(\"mockdispatcher\")\n                .networker(\"networker\")\n                .server(\"server\")\n                .client(\"client\")\n                .telnet(\"mocktelnethandler\")\n                .prompt(\"prompt\")\n                .status(\"mockstatuschecker\")\n                .wait(Integer.valueOf(1000))\n                .isDefault(true)\n                .id(\"id\");\n\n        ProviderConfig config = builder.build();\n        ProviderConfig config2 = builder.build();\n\n        Assertions.assertEquals(8080, config.getPort());\n        Assertions.assertEquals(2, config.getThreads());\n        Assertions.assertEquals(3, config.getIothreads());\n        Assertions.assertEquals(4, config.getQueues());\n        Assertions.assertEquals(5, config.getAccepts());\n        Assertions.assertEquals(6, config.getPayload());\n        Assertions.assertEquals(1024, config.getBuffer());\n        Assertions.assertEquals(1000, config.getWait());\n        Assertions.assertEquals(\"host\", config.getHost());\n        Assertions.assertEquals(\"contextpath\", config.getContextpath());\n        Assertions.assertEquals(\"mockthreadpool\", config.getThreadpool());\n        Assertions.assertEquals(\"mockcodec\", config.getCodec());\n        Assertions.assertEquals(\"utf-8\", config.getCharset());\n        Assertions.assertEquals(\"mocktransporter\", config.getTransporter());\n        Assertions.assertEquals(\"mockexchanger\", config.getExchanger());\n        Assertions.assertEquals(\"mockdispatcher\", config.getDispatcher());\n        Assertions.assertEquals(\"networker\", config.getNetworker());\n        Assertions.assertEquals(\"server\", config.getServer());\n        Assertions.assertEquals(\"client\", config.getClient());\n        Assertions.assertEquals(\"mocktelnethandler\", config.getTelnet());\n        Assertions.assertEquals(\"prompt\", config.getPrompt());\n        Assertions.assertEquals(\"mockstatuschecker\", config.getStatus());\n        Assertions.assertTrue(config.isDefault());\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.api.DemoService;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.utils.CollectionUtils.ofSet;\n\nclass ReferenceBuilderTest {\n\n    @Test\n    void interfaceName() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.interfaceName(DemoService.class.getName());\n        Assertions.assertEquals(\n                \"org.apache.dubbo.config.api.DemoService\", builder.build().getInterface());\n    }\n\n    @Test\n    void interfaceClass() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.interfaceClass(DemoService.class);\n        Assertions.assertEquals(DemoService.class, builder.build().getInterfaceClass());\n    }\n\n    @Test\n    void client() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.client(\"client\");\n        Assertions.assertEquals(\"client\", builder.build().getClient());\n    }\n\n    @Test\n    void url() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.url(\"url\");\n        Assertions.assertEquals(\"url\", builder.build().getUrl());\n    }\n\n    @Test\n    void addMethods() {\n        MethodConfig method = new MethodConfig();\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.addMethods(Collections.singletonList(method));\n        Assertions.assertTrue(builder.build().getMethods().contains(method));\n        Assertions.assertEquals(1, builder.build().getMethods().size());\n    }\n\n    @Test\n    void addMethod() {\n        MethodConfig method = new MethodConfig();\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.addMethod(method);\n        Assertions.assertTrue(builder.build().getMethods().contains(method));\n        Assertions.assertEquals(1, builder.build().getMethods().size());\n    }\n\n    @Test\n    void consumer() {\n        ConsumerConfig consumer = new ConsumerConfig();\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.consumer(consumer);\n        Assertions.assertSame(consumer, builder.build().getConsumer());\n    }\n\n    @Test\n    void protocol() {\n        ReferenceBuilder builder = new ReferenceBuilder();\n        builder.protocol(\"protocol\");\n        Assertions.assertEquals(\"protocol\", builder.build().getProtocol());\n    }\n\n    @Test\n    void build() {\n        ConsumerConfig consumer = new ConsumerConfig();\n        MethodConfig method = new MethodConfig();\n\n        ReferenceBuilder<DemoService> builder = new ReferenceBuilder<>();\n        builder.id(\"id\")\n                .interfaceClass(DemoService.class)\n                .protocol(\"protocol\")\n                .client(\"client\")\n                .url(\"url\")\n                .consumer(consumer)\n                .addMethod(method)\n                // introduced since 2.7.8\n                .services(\"test-service\", \"test-service2\");\n\n        ReferenceConfig config = builder.build();\n        ReferenceConfig config2 = builder.build();\n\n        Assertions.assertEquals(\"org.apache.dubbo.config.api.DemoService\", config.getInterface());\n        Assertions.assertEquals(DemoService.class, config.getInterfaceClass());\n        Assertions.assertEquals(\"protocol\", config.getProtocol());\n        Assertions.assertEquals(\"client\", config.getClient());\n        Assertions.assertEquals(\"url\", config.getUrl());\n        Assertions.assertEquals(consumer, config.getConsumer());\n        Assertions.assertEquals(\"test-service,test-service2\", config.getServices());\n        Assertions.assertEquals(ofSet(\"test-service\", \"test-service2\"), config.getSubscribedServices());\n        Assertions.assertTrue(config.getMethods().contains(method));\n        Assertions.assertEquals(1, config.getMethods().size());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.RegistryConfig;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass RegistryBuilderTest {\n\n    @Test\n    void address() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.address(\"address\");\n        Assertions.assertEquals(\"address\", builder.build().getAddress());\n    }\n\n    @Test\n    void username() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.username(\"username\");\n        Assertions.assertEquals(\"username\", builder.build().getUsername());\n    }\n\n    @Test\n    void password() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.password(\"password\");\n        Assertions.assertEquals(\"password\", builder.build().getPassword());\n    }\n\n    @Test\n    void port() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.port(8080);\n        Assertions.assertEquals(8080, builder.build().getPort());\n    }\n\n    @Test\n    void protocol() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.protocol(\"protocol\");\n        Assertions.assertEquals(\"protocol\", builder.build().getProtocol());\n    }\n\n    @Test\n    void transporter() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.transporter(\"transporter\");\n        Assertions.assertEquals(\"transporter\", builder.build().getTransporter());\n    }\n\n    @Test\n    void transport() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.transport(\"transport\");\n        Assertions.assertEquals(\"transport\", builder.build().getTransport());\n    }\n\n    @Test\n    void server() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.server(\"server\");\n        Assertions.assertEquals(\"server\", builder.build().getServer());\n    }\n\n    @Test\n    void client() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.client(\"client\");\n        Assertions.assertEquals(\"client\", builder.build().getClient());\n    }\n\n    @Test\n    void cluster() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.cluster(\"cluster\");\n        Assertions.assertEquals(\"cluster\", builder.build().getCluster());\n    }\n\n    @Test\n    void group() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.group(\"group\");\n        Assertions.assertEquals(\"group\", builder.build().getGroup());\n    }\n\n    @Test\n    void version() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.version(\"version\");\n        Assertions.assertEquals(\"version\", builder.build().getVersion());\n    }\n\n    @Test\n    void timeout() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.timeout(1000);\n        Assertions.assertEquals(1000, builder.build().getTimeout());\n    }\n\n    @Test\n    void session() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.session(2000);\n        Assertions.assertEquals(2000, builder.build().getSession());\n    }\n\n    @Test\n    void file() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.file(\"file\");\n        Assertions.assertEquals(\"file\", builder.build().getFile());\n    }\n\n    @Test\n    void testWait() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.wait(Integer.valueOf(1000));\n        Assertions.assertEquals(1000, builder.build().getWait());\n    }\n\n    @Test\n    void isCheck() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.isCheck(true);\n        Assertions.assertTrue(builder.build().isCheck());\n    }\n\n    @Test\n    void isDynamic() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.isDynamic(true);\n        Assertions.assertTrue(builder.build().isDynamic());\n    }\n\n    @Test\n    void register() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.register(true);\n        Assertions.assertTrue(builder.build().isRegister());\n    }\n\n    @Test\n    void subscribe() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.subscribe(true);\n        Assertions.assertTrue(builder.build().isSubscribe());\n    }\n\n    @Test\n    void appendParameter() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.appendParameter(\"default.num\", \"one\").appendParameter(\"num\", \"ONE\");\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void appendParameters() {\n        Map<String, String> source = new HashMap<>();\n        source.put(\"default.num\", \"one\");\n        source.put(\"num\", \"ONE\");\n\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.appendParameters(source);\n\n        Map<String, String> parameters = builder.build().getParameters();\n\n        Assertions.assertTrue(parameters.containsKey(\"default.num\"));\n        Assertions.assertEquals(\"ONE\", parameters.get(\"num\"));\n    }\n\n    @Test\n    void isDefault() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.isDefault(true);\n        Assertions.assertTrue(builder.build().isDefault());\n    }\n\n    @Test\n    void simplified() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.simplified(true);\n        Assertions.assertTrue(builder.build().getSimplified());\n    }\n\n    @Test\n    void extraKeys() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.extraKeys(\"extraKeys\");\n        Assertions.assertEquals(\"extraKeys\", builder.build().getExtraKeys());\n    }\n\n    @Test\n    void build() {\n        RegistryBuilder builder = new RegistryBuilder();\n        builder.address(\"address\")\n                .username(\"username\")\n                .password(\"password\")\n                .port(8080)\n                .protocol(\"protocol\")\n                .transporter(\"transporter\")\n                .server(\"server\")\n                .client(\"client\")\n                .cluster(\"cluster\")\n                .group(\"group\")\n                .version(\"version\")\n                .timeout(1000)\n                .session(2000)\n                .file(\"file\")\n                .wait(Integer.valueOf(10))\n                .isCheck(true)\n                .isDynamic(false)\n                .register(true)\n                .subscribe(false)\n                .isDefault(true)\n                .simplified(false)\n                .extraKeys(\"A\")\n                .parameter(\"default.num\", \"one\")\n                .id(\"id\");\n\n        RegistryConfig config = builder.build();\n        RegistryConfig config2 = builder.build();\n\n        Assertions.assertEquals(8080, config.getPort());\n        Assertions.assertEquals(1000, config.getTimeout());\n        Assertions.assertEquals(2000, config.getSession());\n        Assertions.assertEquals(10, config.getWait());\n        Assertions.assertTrue(config.isCheck());\n        Assertions.assertFalse(config.isDynamic());\n        Assertions.assertTrue(config.isRegister());\n        Assertions.assertFalse(config.isSubscribe());\n        Assertions.assertTrue(config.isDefault());\n        Assertions.assertFalse(config.getSimplified());\n        Assertions.assertEquals(\"address\", config.getAddress());\n        Assertions.assertEquals(\"username\", config.getUsername());\n        Assertions.assertEquals(\"password\", config.getPassword());\n        Assertions.assertEquals(\"protocol\", config.getProtocol());\n        Assertions.assertEquals(\"transporter\", config.getTransporter());\n        Assertions.assertEquals(\"server\", config.getServer());\n        Assertions.assertEquals(\"client\", config.getClient());\n        Assertions.assertEquals(\"cluster\", config.getCluster());\n        Assertions.assertEquals(\"group\", config.getGroup());\n        Assertions.assertEquals(\"version\", config.getVersion());\n        Assertions.assertEquals(\"file\", config.getFile());\n        Assertions.assertEquals(\"A\", config.getExtraKeys());\n        Assertions.assertTrue(config.getParameters().containsKey(\"default.num\"));\n        Assertions.assertEquals(\"one\", config.getParameters().get(\"default.num\"));\n        Assertions.assertEquals(\"id\", config.getId());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ServiceBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.ServiceConfig;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_BEAN;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_DEFAULT;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass ServiceBuilderTest {\n\n    @Test\n    void path() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.path(\"path\");\n        Assertions.assertEquals(\"path\", builder.build().getPath());\n    }\n\n    @Test\n    void addMethod() {\n        MethodConfig method = new MethodConfig();\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.addMethod(method);\n        Assertions.assertTrue(builder.build().getMethods().contains(method));\n        Assertions.assertEquals(1, builder.build().getMethods().size());\n    }\n\n    @Test\n    void addMethods() {\n        MethodConfig method = new MethodConfig();\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.addMethods(Collections.singletonList(method));\n        Assertions.assertTrue(builder.build().getMethods().contains(method));\n        Assertions.assertEquals(1, builder.build().getMethods().size());\n    }\n\n    @Test\n    void provider() {\n        ProviderConfig provider = new ProviderConfig();\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.provider(provider);\n        Assertions.assertSame(provider, builder.build().getProvider());\n    }\n\n    @Test\n    void providerIds() {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.providerIds(\"providerIds\");\n        Assertions.assertEquals(\"providerIds\", builder.build().getProviderIds());\n    }\n\n    @Test\n    void generic() throws Exception {\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.generic(GENERIC_SERIALIZATION_DEFAULT);\n        assertThat(builder.build().getGeneric(), equalTo(GENERIC_SERIALIZATION_DEFAULT));\n        builder.generic(GENERIC_SERIALIZATION_NATIVE_JAVA);\n        assertThat(builder.build().getGeneric(), equalTo(GENERIC_SERIALIZATION_NATIVE_JAVA));\n        builder.generic(GENERIC_SERIALIZATION_BEAN);\n        assertThat(builder.build().getGeneric(), equalTo(GENERIC_SERIALIZATION_BEAN));\n    }\n\n    @Test\n    void generic1() throws Exception {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            ServiceBuilder builder = new ServiceBuilder();\n            builder.generic(\"illegal\").build();\n        });\n    }\n    //\n    //    @Test\n    //    public void Mock() throws Exception {\n    //        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n    //            ServiceBuilder builder = new ServiceBuilder();\n    //            builder.mock(\"true\");\n    //        });\n    //    }\n    //\n    //    @Test\n    //    public void Mock1() throws Exception {\n    //        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n    //            ServiceBuilder builder = new ServiceBuilder();\n    //            builder.mock(true);\n    //        });\n    //    }\n\n    @Test\n    void build() {\n        MethodConfig method = new MethodConfig();\n        ProviderConfig provider = new ProviderConfig();\n\n        ServiceBuilder builder = new ServiceBuilder();\n        builder.path(\"path\")\n                .addMethod(method)\n                .provider(provider)\n                .providerIds(\"providerIds\")\n                .generic(GENERIC_SERIALIZATION_DEFAULT);\n\n        ServiceConfig config = builder.build();\n        ServiceConfig config2 = builder.build();\n\n        assertThat(config.getGeneric(), equalTo(GENERIC_SERIALIZATION_DEFAULT));\n        Assertions.assertEquals(\"path\", config.getPath());\n        Assertions.assertEquals(\"providerIds\", config.getProviderIds());\n        Assertions.assertSame(provider, config.getProvider());\n        Assertions.assertTrue(config.getMethods().contains(method));\n        Assertions.assertEquals(1, config.getMethods().size());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/TripleBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.bootstrap.builders;\n\nimport org.apache.dubbo.config.nested.TripleConfig;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass TripleBuilderTest {\n\n    @Test\n    void maxBodySize() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.maxBodySize(10240);\n        Assertions.assertEquals(10240, builder.build().getMaxBodySize());\n    }\n\n    @Test\n    void maxResponseBodySize() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.maxResponseBodySize(8192);\n        Assertions.assertEquals(8192, builder.build().getMaxResponseBodySize());\n    }\n\n    @Test\n    void maxChunkSize() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.maxChunkSize(2048);\n        Assertions.assertEquals(2048, builder.build().getMaxChunkSize());\n    }\n\n    @Test\n    void maxHeaderSize() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.maxHeaderSize(40960);\n        Assertions.assertEquals(40960, builder.build().getMaxHeaderSize());\n    }\n\n    @Test\n    void maxInitialLineLength() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.maxInitialLineLength(Integer.MAX_VALUE);\n        Assertions.assertEquals(Integer.MAX_VALUE, builder.build().getMaxInitialLineLength());\n    }\n\n    @Test\n    void initialBufferSize() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.initialBufferSize(3000);\n        Assertions.assertEquals(3000, builder.build().getInitialBufferSize());\n    }\n\n    @Test\n    void headerTableSize() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.headerTableSize(1000);\n        Assertions.assertEquals(1000, builder.build().getHeaderTableSize());\n    }\n\n    @Test\n    void enablePush() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.enablePush(false);\n        Assertions.assertFalse(builder.build().getEnablePush());\n    }\n\n    @Test\n    void maxConcurrentStreams() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.maxConcurrentStreams(3000);\n        Assertions.assertEquals(3000, builder.build().getMaxConcurrentStreams());\n    }\n\n    @Test\n    void initialWindowSize() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.initialWindowSize(10240);\n        Assertions.assertEquals(10240, builder.build().getInitialWindowSize());\n    }\n\n    @Test\n    void connectionInitialWindowSize() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.connectionInitialWindowSize(8192);\n        Assertions.assertEquals(8192, builder.build().getConnectionInitialWindowSize());\n    }\n\n    @Test\n    void maxFrameSize() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.maxFrameSize(4096);\n        Assertions.assertEquals(4096, builder.build().getMaxFrameSize());\n    }\n\n    @Test\n    void maxHeaderListSize() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.maxHeaderListSize(2000);\n        Assertions.assertEquals(2000, builder.build().getMaxHeaderListSize());\n    }\n\n    @Test\n    void build() {\n        TripleBuilder builder = TripleBuilder.newBuilder();\n        builder.maxBodySize(2048)\n                .maxResponseBodySize(3072)\n                .maxChunkSize(10240)\n                .maxHeaderSize(400)\n                .maxInitialLineLength(100)\n                .initialBufferSize(8192)\n                .headerTableSize(300)\n                .enablePush(true)\n                .maxConcurrentStreams(Integer.MAX_VALUE)\n                .initialWindowSize(4096)\n                .connectionInitialWindowSize(8192)\n                .maxFrameSize(1024)\n                .maxHeaderListSize(500);\n\n        TripleConfig config = builder.build();\n        TripleConfig config2 = builder.build();\n\n        Assertions.assertEquals(2048, config.getMaxBodySize());\n        Assertions.assertEquals(3072, config.getMaxResponseBodySize());\n        Assertions.assertEquals(10240, config.getMaxChunkSize());\n        Assertions.assertEquals(400, config.getMaxHeaderSize());\n        Assertions.assertEquals(100, config.getMaxInitialLineLength());\n        Assertions.assertEquals(8192, config.getInitialBufferSize());\n        Assertions.assertEquals(300, config.getHeaderTableSize());\n        Assertions.assertTrue(config.getEnablePush());\n        Assertions.assertEquals(Integer.MAX_VALUE, config.getMaxConcurrentStreams());\n        Assertions.assertEquals(4096, config.getInitialWindowSize());\n        Assertions.assertEquals(1024, config.getMaxFrameSize());\n        Assertions.assertEquals(500, config.getMaxHeaderListSize());\n        Assertions.assertNotSame(config, config2);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/cache/CacheService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.cache;\n\n/**\n * ValidationService\n */\npublic interface CacheService {\n\n    String findCache(String id);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/cache/CacheServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.cache;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * ValidationServiceImpl\n */\npublic class CacheServiceImpl implements CacheService {\n\n    private final AtomicInteger i = new AtomicInteger();\n\n    public String findCache(String id) {\n        return \"request: \" + id + \", response: \" + i.getAndIncrement();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/cache/CacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.cache;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.CacheFactory;\nimport org.apache.dubbo.cache.support.threadlocal.ThreadLocalCache;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.RpcInvocation;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass CacheTest {\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void tearDown() {\n        //        ApplicationModel.defaultModel().getConfigManager().clear();\n    }\n\n    private void testCache(String type) throws Exception {\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"cache-test\");\n        RegistryConfig registryConfig = new RegistryConfig(\"N/A\");\n        ProtocolConfig protocolConfig = new ProtocolConfig(\"injvm\");\n        ServiceConfig<CacheService> service = new ServiceConfig<CacheService>();\n        service.setApplication(applicationConfig);\n        service.setRegistry(registryConfig);\n        service.setProtocol(protocolConfig);\n        service.setInterface(CacheService.class.getName());\n        service.setRef(new CacheServiceImpl());\n        service.export();\n        try {\n            ReferenceConfig<CacheService> reference = new ReferenceConfig<CacheService>();\n            reference.setApplication(applicationConfig);\n            reference.setInterface(CacheService.class);\n            reference.setUrl(\"injvm://127.0.0.1?scope=remote&cache=true\");\n\n            MethodConfig method = new MethodConfig();\n            method.setName(\"findCache\");\n            method.setCache(type);\n            reference.setMethods(Arrays.asList(method));\n\n            CacheService cacheService = reference.get();\n            try {\n                // verify cache, same result is returned for multiple invocations (in fact, the return value increases\n                // on every invocation on the server side)\n                String fix = null;\n                cacheService.findCache(\"0\");\n                for (int i = 0; i < 3; i++) {\n                    String result = cacheService.findCache(\"0\");\n                    assertTrue(fix == null || fix.equals(result));\n                    fix = result;\n                    Thread.sleep(100);\n                }\n\n                if (\"lru\".equals(type)) {\n                    // default cache.size is 1000 for LRU, should have cache expired if invoke more than 1001 times\n                    for (int n = 0; n < 1001; n++) {\n                        String pre = null;\n                        cacheService.findCache(String.valueOf(n));\n                        for (int i = 0; i < 10; i++) {\n                            String result = cacheService.findCache(String.valueOf(n));\n                            assertTrue(pre == null || pre.equals(result));\n                            pre = result;\n                        }\n                    }\n\n                    // verify if the first cache item is expired in LRU cache\n                    String result = cacheService.findCache(\"0\");\n                    assertFalse(fix == null || fix.equals(result));\n                }\n            } finally {\n                reference.destroy();\n            }\n        } finally {\n            service.unexport();\n        }\n    }\n\n    @Test\n    void testCacheLru() throws Exception {\n        testCache(\"lru\");\n    }\n\n    @Test\n    void testCacheThreadlocal() throws Exception {\n        testCache(\"threadlocal\");\n    }\n\n    @Test\n    void testCacheProvider() {\n        CacheFactory cacheFactory =\n                ExtensionLoader.getExtensionLoader(CacheFactory.class).getAdaptiveExtension();\n\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(\"findCache.cache\", \"threadlocal\");\n        URL url = new ServiceConfigURL(\n                \"dubbo\", \"127.0.0.1\", 29582, \"org.apache.dubbo.config.cache.CacheService\", parameters);\n\n        Invocation invocation = new RpcInvocation(\n                \"findCache\",\n                CacheService.class.getName(),\n                \"\",\n                new Class[] {String.class},\n                new String[] {\"0\"},\n                null,\n                null,\n                null);\n\n        Cache cache = cacheFactory.getCache(url, invocation);\n        assertTrue(cache instanceof ThreadLocalCache);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/common/Person.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.common;\n\nimport java.io.Serializable;\n\n/**\n * Person.java\n */\npublic class Person implements Serializable {\n    private static final long serialVersionUID = 1L;\n    private String name;\n    private int age;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.deploy;\n\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.metrics.utils.MetricsSupportUtil;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\n\nclass DefaultApplicationDeployerTest {\n\n    @Test\n    void isSupportPrometheus() {\n        boolean supportPrometheus = MetricsSupportUtil.isSupportPrometheus();\n        Assert.assertTrue(supportPrometheus, \"MetricsSupportUtil.isSupportPrometheus() should return true\");\n    }\n\n    @Test\n    void isImportPrometheus() {\n        MetricsConfig metricsConfig = new MetricsConfig();\n        metricsConfig.setProtocol(\"prometheus\");\n        boolean importPrometheus =\n                PROTOCOL_PROMETHEUS.equals(metricsConfig.getProtocol()) && !MetricsSupportUtil.isSupportPrometheus();\n        Assert.assertTrue(!importPrometheus, \" should return false\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/AbstractRegistryCenterExporterListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration;\n\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.ExporterListener;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;\nimport org.apache.dubbo.rpc.listener.ListenerExporterWrapper;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * The abstraction of {@link ExporterListener} is to record exported exporters, which should be extended by different sub-classes.\n */\npublic abstract class AbstractRegistryCenterExporterListener implements ExporterListener {\n\n    /**\n     * Exported exporters.\n     */\n    private List<Exporter<?>> exportedExporters = new ArrayList();\n\n    /**\n     * Resolve all filters\n     */\n    private Set<Filter> filters = new HashSet<>();\n\n    /**\n     * Returns the interface of exported service.\n     */\n    protected abstract Class<?> getInterface();\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void exported(Exporter<?> exporter) throws RpcException {\n        ListenerExporterWrapper listenerExporterWrapper = (ListenerExporterWrapper) exporter;\n\n        Invoker invoker = listenerExporterWrapper.getInvoker();\n        if (!(invoker instanceof FilterChainBuilder.CallbackRegistrationInvoker)) {\n            exportedExporters.add(exporter);\n            return;\n        }\n        FilterChainBuilder.CallbackRegistrationInvoker callbackRegistrationInvoker =\n                (FilterChainBuilder.CallbackRegistrationInvoker) invoker;\n        if (callbackRegistrationInvoker == null || callbackRegistrationInvoker.getInterface() != getInterface()) {\n            return;\n        }\n        exportedExporters.add(exporter);\n        FilterChainBuilder.CopyOfFilterChainNode filterChainNode = getFilterChainNode(callbackRegistrationInvoker);\n        do {\n            Filter filter = this.getFilter(filterChainNode);\n            if (filter != null) {\n                filters.add(filter);\n            }\n            filterChainNode = this.getNextNode(filterChainNode);\n        } while (filterChainNode != null);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void unexported(Exporter<?> exporter) {\n        exportedExporters.remove(exporter);\n    }\n\n    /**\n     * Returns the exported exporters.\n     */\n    public List<Exporter<?>> getExportedExporters() {\n        return Collections.unmodifiableList(exportedExporters);\n    }\n\n    /**\n     * Returns all filters\n     */\n    public Set<Filter> getFilters() {\n        return Collections.unmodifiableSet(filters);\n    }\n\n    /**\n     * Use reflection to obtain {@link Filter}\n     */\n    private FilterChainBuilder.CopyOfFilterChainNode getFilterChainNode(\n            FilterChainBuilder.CallbackRegistrationInvoker callbackRegistrationInvoker) {\n        if (callbackRegistrationInvoker != null) {\n            Field field = null;\n            try {\n                field = callbackRegistrationInvoker.getClass().getDeclaredField(\"filterInvoker\");\n                field.setAccessible(true);\n                return (FilterChainBuilder.CopyOfFilterChainNode) field.get(callbackRegistrationInvoker);\n            } catch (NoSuchFieldException | IllegalAccessException e) {\n                // ignore\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Use reflection to obtain {@link Filter}\n     */\n    private Filter getFilter(FilterChainBuilder.CopyOfFilterChainNode filterChainNode) {\n        if (filterChainNode != null) {\n            Field field = null;\n            try {\n                field = filterChainNode.getClass().getDeclaredField(\"filter\");\n                field.setAccessible(true);\n                return (Filter) field.get(filterChainNode);\n            } catch (NoSuchFieldException | IllegalAccessException e) {\n                // ignore\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Use reflection to obtain {@link FilterChainBuilder.CopyOfFilterChainNode}\n     */\n    private FilterChainBuilder.CopyOfFilterChainNode getNextNode(\n            FilterChainBuilder.CopyOfFilterChainNode filterChainNode) {\n        if (filterChainNode != null) {\n            Field field = null;\n            try {\n                field = filterChainNode.getClass().getDeclaredField(\"nextNode\");\n                field.setAccessible(true);\n                Object object = field.get(filterChainNode);\n                if (object instanceof FilterChainBuilder.CopyOfFilterChainNode) {\n                    return (FilterChainBuilder.CopyOfFilterChainNode) object;\n                }\n            } catch (NoSuchFieldException | IllegalAccessException e) {\n                // ignore\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/AbstractRegistryCenterServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration;\n\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceListener;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * This implementation of {@link ServiceListener} is to record exported services, which should be extended by different sub-classes.\n */\npublic abstract class AbstractRegistryCenterServiceListener implements ServiceListener {\n\n    private List<ServiceConfig> exportedServices = new ArrayList<>(2);\n\n    /**\n     * Return the interface name of exported service.\n     */\n    protected abstract Class<?> getInterface();\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void exported(ServiceConfig sc) {\n        // All exported services will be added\n        if (sc.getInterfaceClass() == getInterface()) {\n            exportedServices.add(sc);\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void unexported(ServiceConfig sc) {\n        // remove the exported services.\n        exportedServices.remove(sc);\n    }\n\n    /**\n     * Return all exported services.\n     */\n    public List<ServiceConfig> getExportedServices() {\n        return Collections.unmodifiableList(exportedServices);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration;\n\npublic interface Constants {\n\n    String MULTIPLE_CONFIG_CENTER_SERVICE_DISCOVERY_REGISTRY = \"multipleConfigCenterServiceDiscoveryRegistry\";\n\n    String SINGLE_CONFIG_CENTER_EXPORT_PROVIDER = \"singleConfigCenterExportProvider\";\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/IntegrationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration;\n\n/**\n * The interface for integration testcases.\n */\npublic interface IntegrationTest {\n\n    /**\n     * Run the integration testcases.\n     */\n    void integrate();\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/AbstractStorage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * This abstraction class to implement the basic methods for {@link Storage}.\n *\n * @param <T> The type to store\n */\npublic abstract class AbstractStorage<T> implements Storage<T> {\n\n    private Map<String, T> storage = new ConcurrentHashMap<>();\n\n    /**\n     * Generate the key for storage\n     *\n     * @param host the host in the register center.\n     * @param port the port in the register center.\n     * @return the generated key with the given host and port.\n     */\n    private String generateKey(String host, int port) {\n        return String.format(\"%s:%d\", host, port);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public T get(String host, int port) {\n        return storage.get(generateKey(host, port));\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void put(String host, int port, T value) {\n        storage.put(generateKey(host, port), value);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public boolean contains(String host, int port) {\n        return storage.containsKey(generateKey(host, port));\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public int size() {\n        return storage.size();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void clear() {\n        storage.clear();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/Storage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple;\n\n/**\n * This interface to store the given type instance in multiple registry center.\n * @param <T> The type to store\n */\npublic interface Storage<T> {\n\n    /**\n     * Gets the stored instance with the given host and port.\n     * @param host the host in the register center.\n     * @param port the port in the register center.\n     * @return the stored instance.\n     */\n    T get(String host, int port);\n\n    /**\n     * Sets the stored instance with the given host and port as key.\n     * @param host the host in the register center.\n     * @param port the port in the register center.\n     * @param value the instance to store.\n     */\n    void put(String host, int port, T value);\n\n    /**\n     * Checks if the instance exists with the given host and port.\n     * @param host the host in the register center.\n     * @param port the port in the register center.\n     * @return {@code true} if the instance exists with the given host and port, otherwise {@code false}\n     */\n    boolean contains(String host, int port);\n\n    /**\n     * Returns the size of all stored values.\n     */\n    int size();\n\n    /**\n     * Clear all data.\n     */\n    void clear();\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportmetadata/MultipleRegistryCenterExportMetadataExporterListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportmetadata;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterExporterListener;\nimport org.apache.dubbo.metadata.MetadataService;\n\n@Activate(group = CommonConstants.PROVIDER, order = 1000)\npublic class MultipleRegistryCenterExportMetadataExporterListener extends AbstractRegistryCenterExporterListener {\n\n    /**\n     * Returns the interface of exported service.\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return MetadataService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportmetadata/MultipleRegistryCenterExportMetadataIntegrationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportmetadata;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.integration.IntegrationTest;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.ExporterListener;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;\n\n/**\n * The testcases are only for checking the process of exporting metadata service.\n */\nclass MultipleRegistryCenterExportMetadataIntegrationTest implements IntegrationTest {\n\n    private static final Logger logger =\n            LoggerFactory.getLogger(MultipleRegistryCenterExportMetadataIntegrationTest.class);\n\n    /**\n     * Define the provider application name.\n     */\n    private static String PROVIDER_APPLICATION_NAME = \"multiple-registry-center-export-metadata\";\n\n    /**\n     * The name for getting the specified instance, which is loaded using SPI.\n     */\n    private static String SPI_NAME = \"multipleConfigCenterExportMetadata\";\n\n    /**\n     * Define the protocol's name.\n     */\n    private static String PROTOCOL_NAME = \"injvm\";\n    /**\n     * Define the {@link ServiceConfig} instance.\n     */\n    private ServiceConfig<MultipleRegistryCenterExportMetadataService> serviceConfig;\n\n    /**\n     * The listener to record exported services\n     */\n    private MultipleRegistryCenterExportMetadataServiceListener serviceListener;\n\n    /**\n     * The listener to record exported exporters.\n     */\n    private MultipleRegistryCenterExportMetadataExporterListener exporterListener;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        logger.info(getClass().getSimpleName() + \" testcase is beginning...\");\n        DubboBootstrap.reset();\n        // initialize service config\n        serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(MultipleRegistryCenterExportMetadataService.class);\n        serviceConfig.setRef(new MultipleRegistryCenterExportMetadataServiceImpl());\n        serviceConfig.setAsync(false);\n        serviceConfig.setScope(SCOPE_LOCAL);\n\n        // initialize bootstrap\n        DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))\n                .protocol(new ProtocolConfig(PROTOCOL_NAME))\n                .service(serviceConfig)\n                .registry(new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress1()))\n                .registry(new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress2()));\n    }\n\n    /**\n     * Define {@link ServiceListener}, {@link ExporterListener} and {@link Filter} for helping check.\n     * <p>Use SPI to load them before exporting.\n     * <p>After that, there are some checkpoints need to verify as follow:\n     * <ul>\n     *     <li>There is nothing in ServiceListener or not</li>\n     *     <li>There is nothing in ExporterListener or not</li>\n     *     <li>ServiceConfig is exported or not</li>\n     * </ul>\n     */\n    private void beforeExport() {\n        // ---------------initialize--------------- //\n        serviceListener = (MultipleRegistryCenterExportMetadataServiceListener)\n                ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension(SPI_NAME);\n        exporterListener = (MultipleRegistryCenterExportMetadataExporterListener)\n                ExtensionLoader.getExtensionLoader(ExporterListener.class).getExtension(SPI_NAME);\n\n        // ---------------checkpoints--------------- //\n        // There is nothing in ServiceListener\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        // There is nothing in ExporterListener\n        Assertions.assertTrue(exporterListener.getExportedExporters().isEmpty());\n        // ServiceConfig isn't exported\n        Assertions.assertFalse(serviceConfig.isExported());\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Test\n    @Override\n    public void integrate() {\n        beforeExport();\n        DubboBootstrap.getInstance().start();\n        afterExport();\n    }\n\n    /**\n     * There are some checkpoints need to check after exported as follow:\n     * <ul>\n     *     <li>The metadata service is only one or not</li>\n     *     <li>The exported service is MetadataService or not</li>\n     *     <li>The MetadataService is exported or not</li>\n     *     <li>The exported exporters are right or not</li>\n     * </ul>\n     */\n    private void afterExport() {\n        // The metadata service is only one\n        Assertions.assertEquals(serviceListener.getExportedServices().size(), 1);\n        // The exported service is MetadataService\n        Assertions.assertEquals(\n                serviceListener.getExportedServices().get(0).getInterfaceClass(), MetadataService.class);\n        // The MetadataService is exported\n        Assertions.assertTrue(serviceListener.getExportedServices().get(0).isExported());\n        // FIXME there may be something wrong with the whole process of\n        //  registering service-discovery-registry.\n        //  So, all testcases may need to be modified.\n        // There are two exported exporters\n        // 1. Metadata Service exporter with Injvm protocol\n        // 2. MultipleRegistryCenterExportMetadataService exporter with Injvm protocol\n        Assertions.assertEquals(exporterListener.getExportedExporters().size(), 2);\n        List<Exporter<?>> injvmExporters = exporterListener.getExportedExporters();\n        // Make sure there two injvmExporters\n        Assertions.assertEquals(2, injvmExporters.size());\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        DubboBootstrap.reset();\n        serviceConfig = null;\n        // The exported service has been unexported\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        serviceListener = null;\n        logger.info(getClass().getSimpleName() + \" testcase is ending...\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportmetadata/MultipleRegistryCenterExportMetadataService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportmetadata;\n\n/**\n * This interface is used to check if the exported metadata service works well or not in multiple registry center.\n */\npublic interface MultipleRegistryCenterExportMetadataService {\n\n    /**\n     * The simple method for testing.\n     */\n    String hello(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportmetadata/MultipleRegistryCenterExportMetadataServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportmetadata;\n\n/**\n * The simple implementation for {@link MultipleRegistryCenterExportMetadataService}\n */\npublic class MultipleRegistryCenterExportMetadataServiceImpl implements MultipleRegistryCenterExportMetadataService {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String hello(String name) {\n        return \"Hello \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportmetadata/MultipleRegistryCenterExportMetadataServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportmetadata;\n\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterServiceListener;\nimport org.apache.dubbo.metadata.MetadataService;\n\n/**\n * This implementation of {@link ServiceListener} is to record exported metadata services in multiple registry center.\n */\npublic class MultipleRegistryCenterExportMetadataServiceListener extends AbstractRegistryCenterServiceListener {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return MetadataService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderExporterListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportprovider;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterExporterListener;\n\n@Activate(group = CommonConstants.PROVIDER, order = 1000)\npublic class MultipleRegistryCenterExportProviderExporterListener extends AbstractRegistryCenterExporterListener {\n\n    /**\n     * Returns the interface of exported service.\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return MultipleRegistryCenterExportProviderService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportprovider;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\n@Activate(group = CommonConstants.PROVIDER, order = 10001)\npublic class MultipleRegistryCenterExportProviderFilter implements Filter, Filter.Listener {\n\n    /**\n     * The filter is called or not\n     */\n    private boolean called = false;\n\n    /**\n     * There has error after invoked\n     */\n    private boolean error = false;\n\n    /**\n     * The returned result\n     */\n    private String response;\n    /**\n     * Always call invoker.invoke() in the implementation to hand over the request to the next filter node.\n     *\n     * @param invoker\n     * @param invocation\n     */\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        called = true;\n        return invoker.invoke(invocation);\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {\n        response = String.valueOf(appResponse.getValue());\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        error = true;\n    }\n\n    /**\n     * Returns if the filter has called.\n     */\n    public boolean hasCalled() {\n        return called;\n    }\n\n    /**\n     * Returns if there exists error.\n     */\n    public boolean hasError() {\n        return error;\n    }\n\n    /**\n     * Returns the response.\n     */\n    public String getResponse() {\n        return response;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderIntegrationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportprovider;\n\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.integration.IntegrationTest;\nimport org.apache.dubbo.metadata.ServiceNameMapping;\nimport org.apache.dubbo.metadata.report.MetadataReportInstance;\nimport org.apache.dubbo.registry.integration.RegistryProtocolListener;\nimport org.apache.dubbo.rpc.ExporterListener;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * The testcases are only for checking the core process of exporting provider.\n */\nclass MultipleRegistryCenterExportProviderIntegrationTest implements IntegrationTest {\n\n    private static final Logger logger =\n            LoggerFactory.getLogger(MultipleRegistryCenterExportProviderIntegrationTest.class);\n\n    /**\n     * Define the provider application name.\n     */\n    private static String PROVIDER_APPLICATION_NAME = \"multiple-registry-center-for-export-provider\";\n\n    /**\n     * The name for getting the specified instance, which is loaded using SPI.\n     */\n    private static String SPI_NAME = \"multipleConfigCenterExportProvider\";\n\n    /**\n     * Define the protocol's name.\n     */\n    private static String PROTOCOL_NAME = CommonConstants.DUBBO;\n    /**\n     * Define the protocol's port.\n     */\n    private static int PROTOCOL_PORT = 20800;\n\n    /**\n     * Define the {@link ServiceConfig} instance.\n     */\n    private ServiceConfig<MultipleRegistryCenterExportProviderService> serviceConfig;\n\n    /**\n     * Define a {@link RegistryProtocolListener} instance.\n     */\n    private MultipleRegistryCenterExportProviderRegistryProtocolListener registryProtocolListener;\n\n    /**\n     * Define a {@link ExporterListener} instance.\n     */\n    private MultipleRegistryCenterExportProviderExporterListener exporterListener;\n\n    /**\n     * Define a {@link Filter} instance.\n     */\n    private MultipleRegistryCenterExportProviderFilter filter;\n\n    /**\n     * Define a {@link ServiceListener} instance.\n     */\n    private MultipleRegistryCenterExportProviderServiceListener serviceListener;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        logger.info(getClass().getSimpleName() + \" testcase is beginning...\");\n        DubboBootstrap.reset();\n        // initialize service config\n        serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(MultipleRegistryCenterExportProviderService.class);\n        serviceConfig.setRef(new MultipleRegistryCenterExportProviderServiceImpl());\n        serviceConfig.setAsync(false);\n\n        // initialize bootstrap\n        DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))\n                .protocol(new ProtocolConfig(PROTOCOL_NAME, PROTOCOL_PORT))\n                .service(serviceConfig)\n                .registry(new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress1()))\n                .registry(new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress2()));\n    }\n\n    /**\n     * There are some checkpoints need to verify as follow:\n     * <ul>\n     *     <li>ServiceConfig is exported or not</li>\n     *     <li>MultipleRegistryCenterExportProviderRegistryProtocolListener is null or not</li>\n     *     <li>There is nothing in ServiceListener or not</li>\n     *     <li>There is nothing in ExporterListener or not</li>\n     * </ul>\n     */\n    private void beforeExport() {\n        registryProtocolListener = (MultipleRegistryCenterExportProviderRegistryProtocolListener)\n                ExtensionLoader.getExtensionLoader(RegistryProtocolListener.class)\n                        .getExtension(SPI_NAME);\n        exporterListener = (MultipleRegistryCenterExportProviderExporterListener)\n                ExtensionLoader.getExtensionLoader(ExporterListener.class).getExtension(SPI_NAME);\n        filter = (MultipleRegistryCenterExportProviderFilter)\n                ExtensionLoader.getExtensionLoader(Filter.class).getExtension(SPI_NAME);\n        serviceListener = (MultipleRegistryCenterExportProviderServiceListener)\n                ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension(SPI_NAME);\n        // ---------------checkpoints--------------- //\n        // ServiceConfig isn't exported\n        Assertions.assertFalse(serviceConfig.isExported());\n        // registryProtocolListener is just initialized by SPI\n        // so, all of fields are the default value.\n        Assertions.assertNotNull(registryProtocolListener);\n        Assertions.assertFalse(registryProtocolListener.isExported());\n        // There is nothing in ServiceListener\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        // There is nothing in ExporterListener\n        Assertions.assertTrue(exporterListener.getExportedExporters().isEmpty());\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Test\n    @Override\n    public void integrate() {\n        beforeExport();\n        DubboBootstrap.getInstance().start();\n        afterExport();\n        ReferenceConfig<MultipleRegistryCenterExportProviderService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(MultipleRegistryCenterExportProviderService.class);\n        referenceConfig.get().hello(PROVIDER_APPLICATION_NAME);\n        afterInvoke();\n    }\n\n    /**\n     * There are some checkpoints need to check after exported as follow:\n     * <ul>\n     *     <li>the exporter is exported or not</li>\n     *     <li>The exported exporter are three</li>\n     *     <li>The exported service is MultipleRegistryCenterExportProviderService or not</li>\n     *     <li>The MultipleRegistryCenterExportProviderService is exported or not</li>\n     *     <li>The exported exporter contains MultipleRegistryCenterExportProviderFilter or not</li>\n     * </ul>\n     */\n    private void afterExport() {\n        // The exporter is exported\n        Assertions.assertTrue(registryProtocolListener.isExported());\n        // The exported service is only one\n        Assertions.assertEquals(serviceListener.getExportedServices().size(), 1);\n        // The exported service is MultipleRegistryCenterExportProviderService\n        Assertions.assertEquals(\n                serviceListener.getExportedServices().get(0).getInterfaceClass(),\n                MultipleRegistryCenterExportProviderService.class);\n        // The MultipleRegistryCenterExportProviderService is exported\n        Assertions.assertTrue(serviceListener.getExportedServices().get(0).isExported());\n        // The exported exporter are three\n        // 1. InjvmExporter\n        // 2. DubboExporter with service-discovery-registry protocol\n        // 3. DubboExporter with registry protocol\n        Assertions.assertEquals(exporterListener.getExportedExporters().size(), 4);\n        // The exported exporter contains MultipleRegistryCenterExportProviderFilter\n        Assertions.assertTrue(exporterListener.getFilters().contains(filter));\n\n        // The consumer can be notified and get provider's metadata through metadata mapping info.\n        // So, the metadata mapping is necessary to check after exported service (or provider)\n        // The best way to verify this issue is to check if the exported service (or provider)\n        // has been registered in the path of /dubbo/mapping/****\n        // FixME We should check if the exported service (or provider) has been registered in multiple registry centers.\n        //  However, the registered exporter are override in RegistryProtocol#export, so there is only the first\n        // registry center\n        //  that can register the mapping relationship. This is really a problem that needs to be fix.\n        //  Now, we are discussing the solution for this issue.\n        //  For this testcase, we still check the only exported service (or provider).\n        //  all testcase below are temporary and will be replaced after the above problem is fixed.\n        // What are the parameters?\n        // registryKey: the registryKey is the default cluster, CommonConstants.DEFAULT_KEY\n        // key: The exported interface's name\n        // group: the group is \"mapping\", ServiceNameMapping.DEFAULT_MAPPING_GROUP\n        ConfigItem configItem = ApplicationModel.defaultModel()\n                .getBeanFactory()\n                .getBean(MetadataReportInstance.class)\n                .getMetadataReport(CommonConstants.DEFAULT_KEY)\n                .getConfigItem(serviceConfig.getInterface(), ServiceNameMapping.DEFAULT_MAPPING_GROUP);\n        // Check if the exported service (provider) is registered\n        Assertions.assertNotNull(configItem);\n        // Check if registered service (provider)'s name is right\n        Assertions.assertEquals(PROVIDER_APPLICATION_NAME, configItem.getContent());\n        // Check if registered service (provider)'s version exists\n        Assertions.assertNotNull(configItem.getTicket());\n    }\n\n    /**\n     * There are some checkpoints need to check after invoked as follow:\n     * <ul>\n     *     <li>The MultipleRegistryCenterExportProviderFilter has called or not</li>\n     *     <li>The MultipleRegistryCenterExportProviderFilter exists error after invoked</li>\n     *     <li>The MultipleRegistryCenterExportProviderFilter's response is right or not</li>\n     * </ul>\n     */\n    private void afterInvoke() {\n        // The MultipleRegistryCenterExportProviderFilter has called\n        Assertions.assertTrue(filter.hasCalled());\n        // The MultipleRegistryCenterExportProviderFilter doesn't exist error\n        Assertions.assertFalse(filter.hasError());\n        // Check the MultipleRegistryCenterExportProviderFilter's response\n        Assertions.assertEquals(\"Hello \" + PROVIDER_APPLICATION_NAME, filter.getResponse());\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        DubboBootstrap.reset();\n        serviceConfig = null;\n        // The exported service has been unexported\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        logger.info(getClass().getSimpleName() + \" testcase is ending...\");\n        registryProtocolListener = null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderRegistryProtocolListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportprovider;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol;\nimport org.apache.dubbo.registry.integration.RegistryProtocol;\nimport org.apache.dubbo.registry.integration.RegistryProtocolListener;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\n/**\n * The {@link RegistryProtocolListener} for {@link MultipleRegistryCenterExportProviderService}\n */\n@Activate(order = 100)\npublic class MultipleRegistryCenterExportProviderRegistryProtocolListener implements RegistryProtocolListener {\n\n    private boolean exported = false;\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void onExport(RegistryProtocol registryProtocol, Exporter<?> exporter) {\n        if (registryProtocol instanceof InterfaceCompatibleRegistryProtocol\n                && exporter != null\n                && exporter.getInvoker() != null\n                && exporter.getInvoker().getInterface().equals(MultipleRegistryCenterExportProviderService.class)) {\n            this.exported = true;\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void onRefer(RegistryProtocol registryProtocol, ClusterInvoker<?> invoker, URL url, URL registryURL) {}\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void onDestroy() {}\n\n    /**\n     * Returns if this exporter is exported.\n     */\n    public boolean isExported() {\n        return exported;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportprovider;\n\n/**\n * This interface is used to check if the exported provider works well or not in multiple registry center.\n */\npublic interface MultipleRegistryCenterExportProviderService {\n\n    /**\n     * The simple method for testing.\n     */\n    String hello(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportprovider;\n\n/**\n * The implementation of {@link MultipleRegistryCenterExportProviderService}\n */\npublic class MultipleRegistryCenterExportProviderServiceImpl implements MultipleRegistryCenterExportProviderService {\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String hello(String name) {\n        return \"Hello \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.exportprovider;\n\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterServiceListener;\n\n/**\n * This implementation of {@link ServiceListener} is to record exported services with injvm protocol in single registry center.\n */\npublic class MultipleRegistryCenterExportProviderServiceListener extends AbstractRegistryCenterServiceListener {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return MultipleRegistryCenterExportProviderService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/injvm/MultipleRegistryCenterInjvmExporterListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.injvm;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterExporterListener;\n\n@Activate(group = CommonConstants.PROVIDER, order = 1000)\npublic class MultipleRegistryCenterInjvmExporterListener extends AbstractRegistryCenterExporterListener {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return MultipleRegistryCenterInjvmService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/injvm/MultipleRegistryCenterInjvmFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.injvm;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\n@Activate(group = CommonConstants.PROVIDER, order = 10200)\npublic class MultipleRegistryCenterInjvmFilter implements Filter, Filter.Listener {\n\n    /**\n     * The filter is called or not\n     */\n    private boolean called = false;\n\n    /**\n     * There has error after invoked\n     */\n    private boolean error = false;\n\n    /**\n     * The returned result\n     */\n    private String response;\n    /**\n     * Always call invoker.invoke() in the implementation to hand over the request to the next filter node.\n     *\n     * @param invoker\n     * @param invocation\n     */\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        called = true;\n        return invoker.invoke(invocation);\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {\n        response = String.valueOf(appResponse.getValue());\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        error = true;\n    }\n\n    /**\n     * Returns if the filter has called.\n     */\n    public boolean hasCalled() {\n        return called;\n    }\n\n    /**\n     * Returns if there exists error.\n     */\n    public boolean hasError() {\n        return error;\n    }\n\n    /**\n     * Returns the response.\n     */\n    public String getResponse() {\n        return response;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/injvm/MultipleRegistryCenterInjvmIntegrationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.injvm;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.integration.IntegrationTest;\nimport org.apache.dubbo.rpc.ExporterListener;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;\n\n/**\n * The testcases are only for checking the process of exporting provider using injvm protocol.\n */\nclass MultipleRegistryCenterInjvmIntegrationTest implements IntegrationTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(MultipleRegistryCenterInjvmIntegrationTest.class);\n\n    /**\n     * Define the provider application name.\n     */\n    private static String PROVIDER_APPLICATION_NAME = \"multiple-registry-center-provider-for-injvm-protocol\";\n\n    /**\n     * The name for getting the specified instance, which is loaded using SPI.\n     */\n    private static String SPI_NAME = \"multipleConfigCenterInjvm\";\n\n    /**\n     * Define the {@link ServiceConfig} instance.\n     */\n    private ServiceConfig<MultipleRegistryCenterInjvmService> serviceConfig;\n\n    /**\n     * The listener to record exported services\n     */\n    private MultipleRegistryCenterInjvmServiceListener serviceListener;\n\n    /**\n     * The listener to record exported exporters.\n     */\n    private MultipleRegistryCenterInjvmExporterListener exporterListener;\n\n    /**\n     * The filter for checking filter chain.\n     */\n    private MultipleRegistryCenterInjvmFilter filter;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        logger.info(getClass().getSimpleName() + \" testcase is beginning...\");\n        DubboBootstrap.reset();\n        // initialize service config\n        serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(MultipleRegistryCenterInjvmService.class);\n        serviceConfig.setRef(new MultipleRegistryCenterInjvmServiceImpl());\n        serviceConfig.setAsync(false);\n        serviceConfig.setScope(SCOPE_LOCAL);\n\n        DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))\n                .protocol(new ProtocolConfig(\"injvm\"))\n                .service(serviceConfig)\n                .registry(new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress1()))\n                .registry(new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress2()));\n    }\n\n    /**\n     * Define {@link ServiceListener}, {@link ExporterListener} and {@link Filter} for helping check.\n     * <p>Use SPI to load them before exporting.\n     * <p>After that, there are some checkpoints need to verify as follow:\n     * <ul>\n     *     <li>There is nothing in ServiceListener or not</li>\n     *     <li>There is nothing in ExporterListener or not</li>\n     *     <li>ServiceConfig is exported or not</li>\n     * </ul>\n     */\n    private void beforeExport() {\n        // ---------------initialize--------------- //\n        serviceListener = (MultipleRegistryCenterInjvmServiceListener)\n                ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension(SPI_NAME);\n        exporterListener = (MultipleRegistryCenterInjvmExporterListener)\n                ExtensionLoader.getExtensionLoader(ExporterListener.class).getExtension(SPI_NAME);\n        filter = (MultipleRegistryCenterInjvmFilter)\n                ExtensionLoader.getExtensionLoader(Filter.class).getExtension(SPI_NAME);\n\n        // ---------------checkpoints--------------- //\n        // There is nothing in ServiceListener\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        // There is nothing in ExporterListener\n        Assertions.assertTrue(exporterListener.getExportedExporters().isEmpty());\n        // ServiceConfig isn't exported\n        Assertions.assertFalse(serviceConfig.isExported());\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Test\n    @Override\n    public void integrate() {\n        beforeExport();\n        DubboBootstrap.getInstance().start();\n        afterExport();\n        ReferenceConfig<MultipleRegistryCenterInjvmService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(MultipleRegistryCenterInjvmService.class);\n        referenceConfig.setScope(SCOPE_LOCAL);\n        referenceConfig.get().hello(\"Dubbo in multiple registry center\");\n        afterInvoke();\n    }\n\n    /**\n     * There are some checkpoints need to check after exported as follow:\n     * <ul>\n     *     <li>The exported service is only one or not</li>\n     *     <li>The exported service is MultipleRegistryCenterInjvmService or not</li>\n     *     <li>The MultipleRegistryCenterInjvmService is exported or not</li>\n     *     <li>The exported exporter is only one or not</li>\n     *     <li>The exported exporter contains MultipleRegistryCenterInjvmFilter or not</li>\n     * </ul>\n     */\n    private void afterExport() {\n        // The exported service is only one\n        Assertions.assertEquals(serviceListener.getExportedServices().size(), 1);\n        // The exported service is MultipleRegistryCenterInjvmService\n        Assertions.assertEquals(\n                serviceListener.getExportedServices().get(0).getInterfaceClass(),\n                MultipleRegistryCenterInjvmService.class);\n        // The MultipleRegistryCenterInjvmService is exported\n        Assertions.assertTrue(serviceListener.getExportedServices().get(0).isExported());\n        // The exported exporter is only one\n        Assertions.assertEquals(exporterListener.getExportedExporters().size(), 3);\n        // The exported exporter contains MultipleRegistryCenterInjvmFilter\n        Assertions.assertTrue(exporterListener.getFilters().contains(filter));\n    }\n\n    /**\n     * There are some checkpoints need to check after invoked as follow:\n     * <ul>\n     *     <li>The MultipleRegistryCenterInjvmFilter has called or not</li>\n     *     <li>The MultipleRegistryCenterInjvmFilter exists error after invoked</li>\n     *     <li>The MultipleRegistryCenterInjvmFilter's response is right or not</li>\n     * </ul>\n     */\n    private void afterInvoke() {\n        // The MultipleRegistryCenterInjvmFilter has called\n        Assertions.assertTrue(filter.hasCalled());\n        // The MultipleRegistryCenterInjvmFilter doesn't exist error\n        Assertions.assertFalse(filter.hasError());\n        // Check the MultipleRegistryCenterInjvmFilter's response\n        Assertions.assertEquals(\"Hello Dubbo in multiple registry center\", filter.getResponse());\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        DubboBootstrap.reset();\n        serviceConfig = null;\n        // The exported service has been unexported\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        serviceListener = null;\n        logger.info(getClass().getSimpleName() + \" testcase is ending...\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/injvm/MultipleRegistryCenterInjvmService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.injvm;\n/**\n * This interface is used to check if the exported injvm protocol works well or not.\n */\npublic interface MultipleRegistryCenterInjvmService {\n    /**\n     * The simple method for testing.\n     */\n    String hello(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/injvm/MultipleRegistryCenterInjvmServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.injvm;\n\n/**\n * The simple implementation for {@link MultipleRegistryCenterInjvmService}\n */\npublic class MultipleRegistryCenterInjvmServiceImpl implements MultipleRegistryCenterInjvmService {\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String hello(String name) {\n        return \"Hello \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/injvm/MultipleRegistryCenterInjvmServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.injvm;\n\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterServiceListener;\n\n/**\n * This implementation of {@link ServiceListener} is to record exported services with injvm protocol in multiple registry center.\n */\npublic class MultipleRegistryCenterInjvmServiceListener extends AbstractRegistryCenterServiceListener {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return MultipleRegistryCenterInjvmService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/package-info.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * There are two scenario in integration testcases.<p>\n * The one is single registry center, the other is multiple registry centers.<p>\n * The purpose of all of testcases in this package is to test for multiple registry center.\n */\npackage org.apache.dubbo.config.integration.multiple;\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.servicediscoveryregistry;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.integration.IntegrationTest;\nimport org.apache.dubbo.registry.RegistryServiceListener;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperConfig;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.config.integration.Constants.MULTIPLE_CONFIG_CENTER_SERVICE_DISCOVERY_REGISTRY;\n\n/**\n * The testcases are only for checking the process of exporting provider using service-discovery-registry protocol.\n */\nclass MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest implements IntegrationTest {\n\n    private static final Logger logger =\n            LoggerFactory.getLogger(MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.class);\n\n    /**\n     * Define the provider application name.\n     */\n    public static String PROVIDER_APPLICATION_NAME =\n            \"multiple-registry-center-provider-for-service-discovery-registry-protocol\";\n\n    /**\n     * Define the protocol's name.\n     */\n    private static String PROTOCOL_NAME = CommonConstants.DUBBO;\n    /**\n     * Define the protocol's port.\n     */\n    private static int PROTOCOL_PORT = 20880;\n\n    /**\n     * Define the {@link ServiceConfig} instance.\n     */\n    private ServiceConfig<MultipleRegistryCenterServiceDiscoveryRegistryService> serviceConfig;\n\n    /**\n     * Define a {@link RegistryServiceListener} instance.\n     */\n    private MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener registryServiceListener;\n\n    /**\n     * The localhost.\n     */\n    private static String HOST = \"127.0.0.1\";\n\n    /**\n     * The port of register center.\n     */\n    private Set<Integer> ports = new HashSet<>(2);\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        logger.info(getClass().getSimpleName() + \" testcase is beginning...\");\n        DubboBootstrap.reset();\n        // initialize service config\n        serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(MultipleRegistryCenterServiceDiscoveryRegistryService.class);\n        serviceConfig.setRef(new MultipleRegistryCenterServiceDiscoveryRegistryServiceImpl());\n        serviceConfig.setAsync(false);\n\n        RegistryConfig registryConfig1 = new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress1());\n        Map<String, String> parameters1 = new HashMap<>();\n        parameters1.put(\"registry.listeners\", MULTIPLE_CONFIG_CENTER_SERVICE_DISCOVERY_REGISTRY);\n        registryConfig1.updateParameters(parameters1);\n        DubboBootstrap.getInstance().registry(registryConfig1);\n        ports.add(ZookeeperConfig.DEFAULT_CLIENT_PORT_1);\n\n        RegistryConfig registryConfig2 = new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress2());\n        Map<String, String> parameters2 = new HashMap<>();\n        parameters2.put(\"registry.listeners\", MULTIPLE_CONFIG_CENTER_SERVICE_DISCOVERY_REGISTRY);\n        registryConfig2.updateParameters(parameters2);\n        DubboBootstrap.getInstance().registry(registryConfig2);\n        ports.add(ZookeeperConfig.DEFAULT_CLIENT_PORT_2);\n\n        DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))\n                .protocol(new ProtocolConfig(PROTOCOL_NAME, PROTOCOL_PORT))\n                .service(serviceConfig);\n        // ---------------initialize--------------- //\n        registryServiceListener = (MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener)\n                ExtensionLoader.getExtensionLoader(RegistryServiceListener.class)\n                        .getExtension(MULTIPLE_CONFIG_CENTER_SERVICE_DISCOVERY_REGISTRY);\n        // RegistryServiceListener is not null\n        Assertions.assertNotNull(registryServiceListener);\n        registryServiceListener.getStorage().clear();\n    }\n\n    /**\n     * Define a {@link RegistryServiceListener} for helping check.<p>\n     * There are some checkpoints need to verify as follow:\n     * <ul>\n     *     <li>ServiceConfig is exported or not</li>\n     *     <li>ServiceDiscoveryRegistryStorage is empty or not</li>\n     * </ul>\n     */\n    private void beforeExport() {\n        // ---------------checkpoints--------------- //\n        // ServiceConfig isn't exported\n        Assertions.assertFalse(serviceConfig.isExported());\n\n        // ServiceDiscoveryRegistryStorage is empty\n        Assertions.assertEquals(registryServiceListener.getStorage().size(), 0);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Test\n    @Override\n    public void integrate() {\n        beforeExport();\n        DubboBootstrap.getInstance().start();\n        afterExport();\n        ReferenceConfig<MultipleRegistryCenterServiceDiscoveryRegistryService> referenceConfig =\n                new ReferenceConfig<>();\n        referenceConfig.setInterface(MultipleRegistryCenterServiceDiscoveryRegistryService.class);\n        referenceConfig.get().hello(\"Dubbo in multiple registry center\");\n        afterInvoke();\n    }\n\n    /**\n     * There are some checkpoints need to check after exported as follow:\n     * <ul>\n     *     <li>ServiceDiscoveryRegistry is right or not</li>\n     *     <li>All register center has been registered and subscribed</li>\n     * </ul>\n     */\n    private void afterExport() {\n        // ServiceDiscoveryRegistry is not null\n        Assertions.assertEquals(registryServiceListener.getStorage().size(), 2);\n        // All register center has been registered and subscribed\n        for (int port : ports) {\n            Assertions.assertTrue(registryServiceListener.getStorage().contains(HOST, port));\n            ServiceDiscoveryRegistryInfoWrapper serviceDiscoveryRegistryInfoWrapper =\n                    registryServiceListener.getStorage().get(HOST, port);\n            // check if it's registered\n            Assertions.assertTrue(serviceDiscoveryRegistryInfoWrapper.isRegistered());\n            // check if it's subscribed\n            Assertions.assertFalse(serviceDiscoveryRegistryInfoWrapper.isSubscribed());\n            MetadataServiceDelegation metadataService = DubboBootstrap.getInstance()\n                    .getApplicationModel()\n                    .getBeanFactory()\n                    .getBean(MetadataServiceDelegation.class);\n            // check if the count of exported urls is right or not\n            Assertions.assertEquals(metadataService.getExportedURLs().size(), 1);\n            // check the exported url is right or not.\n            Assertions.assertTrue(metadataService\n                    .getExportedURLs()\n                    .first()\n                    .contains(MultipleRegistryCenterServiceDiscoveryRegistryService.class.getName()));\n            // check the count of metadatainfo is right or not.\n            Assertions.assertEquals(2, metadataService.getMetadataInfos().size());\n        }\n    }\n\n    /**\n     * There are some checkpoints need to check after invoked as follow:\n     */\n    private void afterInvoke() {}\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        DubboBootstrap.reset();\n        serviceConfig = null;\n        // TODO: we need to check whether this scenario is normal\n        // TODO: the Exporter and ServiceDiscoveryRegistry are same in multiple registry center\n        /*\n        for (int port: ports) {\n            Assertions.assertTrue(registryServiceListener.getStorage().contains(HOST, port));\n            ServiceDiscoveryRegistryInfoWrapper serviceDiscoveryRegistryInfoWrapper = registryServiceListener.getStorage().get(HOST, port);\n            // check if it's registered\n            Assertions.assertFalse(serviceDiscoveryRegistryInfoWrapper.isRegistered());\n            // check if it's subscribed\n            Assertions.assertFalse(serviceDiscoveryRegistryInfoWrapper.isSubscribed());\n        }\n        */\n        registryServiceListener.getStorage().clear();\n        registryServiceListener = null;\n        logger.info(getClass().getSimpleName() + \" testcase is ending...\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.servicediscoveryregistry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryServiceListener;\nimport org.apache.dubbo.registry.client.ServiceDiscoveryRegistry;\n\nimport static org.apache.dubbo.config.integration.Constants.MULTIPLE_CONFIG_CENTER_SERVICE_DISCOVERY_REGISTRY;\n\n@Activate(value = MULTIPLE_CONFIG_CENTER_SERVICE_DISCOVERY_REGISTRY)\npublic class MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener implements RegistryServiceListener {\n\n    private ServiceDiscoveryRegistryStorage storage = new ServiceDiscoveryRegistryStorage();\n\n    /**\n     * Create an {@link ServiceDiscoveryRegistryInfoWrapper} instance.\n     */\n    private ServiceDiscoveryRegistryInfoWrapper createServiceDiscoveryRegistryInfoWrapper(\n            ServiceDiscoveryRegistry serviceDiscoveryRegistry) {\n        URL url = serviceDiscoveryRegistry.getUrl();\n        String host = url.getHost();\n        int port = url.getPort();\n        ServiceDiscoveryRegistryInfoWrapper serviceDiscoveryRegistryInfoWrapper =\n                new ServiceDiscoveryRegistryInfoWrapper();\n        serviceDiscoveryRegistryInfoWrapper.setHost(host);\n        serviceDiscoveryRegistryInfoWrapper.setPort(port);\n        serviceDiscoveryRegistryInfoWrapper.setServiceDiscoveryRegistry(serviceDiscoveryRegistry);\n        serviceDiscoveryRegistryInfoWrapper.setRegistered(true);\n        return serviceDiscoveryRegistryInfoWrapper;\n    }\n\n    /**\n     * Checks if the registry is checked application\n     */\n    private boolean isCheckedApplication(Registry registry) {\n        return registry.getUrl()\n                .getApplication()\n                .equals(MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.PROVIDER_APPLICATION_NAME);\n    }\n\n    public void onRegister(URL url, Registry registry) {\n        if (registry instanceof ServiceDiscoveryRegistry && isCheckedApplication(registry)) {\n            ServiceDiscoveryRegistry serviceDiscoveryRegistry = (ServiceDiscoveryRegistry) registry;\n            String host = serviceDiscoveryRegistry.getUrl().getHost();\n            int port = serviceDiscoveryRegistry.getUrl().getPort();\n            if (!storage.contains(host, port)) {\n                storage.put(host, port, createServiceDiscoveryRegistryInfoWrapper(serviceDiscoveryRegistry));\n            }\n            storage.get(host, port).setRegistered(true);\n        }\n    }\n\n    public void onUnregister(URL url, Registry registry) {\n        if (registry instanceof ServiceDiscoveryRegistry && isCheckedApplication(registry)) {\n            String host = registry.getUrl().getHost();\n            int port = registry.getUrl().getPort();\n            storage.get(host, port).setRegistered(false);\n        }\n    }\n\n    public void onSubscribe(URL url, Registry registry) {\n        if (registry instanceof ServiceDiscoveryRegistry && isCheckedApplication(registry)) {\n            ServiceDiscoveryRegistry serviceDiscoveryRegistry = (ServiceDiscoveryRegistry) registry;\n            String host = serviceDiscoveryRegistry.getUrl().getHost();\n            int port = serviceDiscoveryRegistry.getUrl().getPort();\n            if (!storage.contains(host, port)) {\n                storage.put(host, port, createServiceDiscoveryRegistryInfoWrapper(serviceDiscoveryRegistry));\n            }\n            storage.get(host, port).setSubscribed(true);\n        }\n    }\n\n    public void onUnsubscribe(URL url, Registry registry) {\n        if (registry instanceof ServiceDiscoveryRegistry && isCheckedApplication(registry)) {\n            String host = registry.getUrl().getHost();\n            int port = registry.getUrl().getPort();\n            storage.get(host, port).setSubscribed(false);\n        }\n    }\n\n    /**\n     * Return the stored {@link ServiceDiscoveryRegistryInfoWrapper} instances.\n     */\n    public ServiceDiscoveryRegistryStorage getStorage() {\n        return storage;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.servicediscoveryregistry;\n/**\n * This interface is used to check if the exported service-discovery-registry protocol works well or not.\n */\npublic interface MultipleRegistryCenterServiceDiscoveryRegistryService {\n    /**\n     * The simple method for testing.\n     */\n    String hello(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.servicediscoveryregistry;\n/**\n * The simple implementation for {@link MultipleRegistryCenterServiceDiscoveryRegistryService}\n */\npublic class MultipleRegistryCenterServiceDiscoveryRegistryServiceImpl\n        implements MultipleRegistryCenterServiceDiscoveryRegistryService {\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String hello(String name) {\n        return \"Hello \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/servicediscoveryregistry/ServiceDiscoveryRegistryInfoWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.servicediscoveryregistry;\n\nimport org.apache.dubbo.registry.client.ServiceDiscoveryRegistry;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;\n\n/**\n * The instance to wrap {@link org.apache.dubbo.registry.client.ServiceDiscoveryRegistry}\n */\npublic class ServiceDiscoveryRegistryInfoWrapper {\n\n    private ServiceDiscoveryRegistry serviceDiscoveryRegistry;\n    private MetadataServiceDelegation inMemoryWritableMetadataService;\n    private boolean registered;\n    private boolean subscribed;\n    private String host;\n    private int port;\n\n    public ServiceDiscoveryRegistry getServiceDiscoveryRegistry() {\n        return serviceDiscoveryRegistry;\n    }\n\n    public void setServiceDiscoveryRegistry(ServiceDiscoveryRegistry serviceDiscoveryRegistry) {\n        this.serviceDiscoveryRegistry = serviceDiscoveryRegistry;\n    }\n\n    public boolean isRegistered() {\n        return registered;\n    }\n\n    public void setRegistered(boolean registered) {\n        this.registered = registered;\n    }\n\n    public boolean isSubscribed() {\n        return subscribed;\n    }\n\n    public void setSubscribed(boolean subscribed) {\n        this.subscribed = subscribed;\n    }\n\n    public String getHost() {\n        return host;\n    }\n\n    public void setHost(String host) {\n        this.host = host;\n    }\n\n    public int getPort() {\n        return port;\n    }\n\n    public void setPort(int port) {\n        this.port = port;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/servicediscoveryregistry/ServiceDiscoveryRegistryStorage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.multiple.servicediscoveryregistry;\n\nimport org.apache.dubbo.config.integration.multiple.AbstractStorage;\n\n/**\n * The storage to store {@link ServiceDiscoveryRegistryInfoWrapper} instances in multiple registry center.\n */\npublic class ServiceDiscoveryRegistryStorage extends AbstractStorage<ServiceDiscoveryRegistryInfoWrapper> {}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.integration.IntegrationTest;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.registry.ListenerRegistryWrapper;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.client.ServiceDiscoveryRegistry;\nimport org.apache.dubbo.registry.client.ServiceDiscoveryRegistryDirectory;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;\nimport org.apache.dubbo.registry.client.migration.MigrationInvoker;\nimport org.apache.dubbo.registry.support.RegistryManager;\nimport org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;\nimport static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;\n\n/**\n * This abstraction class will implement some methods as base for single registry center.\n */\n@DisabledForJreRange(min = JRE.JAVA_16)\nclass SingleRegistryCenterDubboProtocolIntegrationTest implements IntegrationTest {\n\n    private static final Logger logger =\n            LoggerFactory.getLogger(SingleRegistryCenterDubboProtocolIntegrationTest.class);\n    /**\n     * Define the provider application name.\n     */\n    private static String PROVIDER_APPLICATION_NAME = \"single-registry-center-provider-for-dubbo-protocol\";\n    /**\n     * Define the protocol's name.\n     */\n    private static String PROTOCOL_NAME = CommonConstants.DUBBO;\n    /**\n     * Define the protocol's port.\n     */\n    private static int PROTOCOL_PORT = 20800;\n\n    /**\n     * Define the {@link ServiceConfig} instance.\n     */\n    private ServiceConfig<SingleRegistryCenterIntegrationServiceImpl> serviceConfig;\n\n    /**\n     * Define the {@link ReferenceConfig} instance.\n     */\n    private ReferenceConfig<SingleRegistryCenterIntegrationService> referenceConfig;\n\n    /**\n     * Define the {@link RegistryConfig} instance.\n     */\n    private RegistryConfig registryConfig;\n\n    /**\n     * The service instance of {@link SingleRegistryCenterIntegrationService}\n     */\n    private SingleRegistryCenterIntegrationService singleRegistryCenterIntegrationService;\n\n    /**\n     * Define the {@link SingleRegistryCenterExportedServiceListener} instance to obtain the exported services.\n     */\n    private SingleRegistryCenterExportedServiceListener singleRegistryCenterExportedServiceListener;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        logger.info(getClass().getSimpleName() + \" testcase is beginning...\");\n        DubboBootstrap.reset();\n        // initialize ServiceConfig\n        serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(SingleRegistryCenterIntegrationService.class);\n        serviceConfig.setRef(new SingleRegistryCenterIntegrationServiceImpl());\n        serviceConfig.setAsync(false);\n\n        DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))\n                .protocol(new ProtocolConfig(PROTOCOL_NAME, PROTOCOL_PORT))\n                .service(serviceConfig);\n        registryConfig = new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress());\n        DubboBootstrap.getInstance().registry(registryConfig);\n    }\n\n    @Test\n    @Override\n    public void integrate() {\n        this.beforeExport();\n        // export provider\n        DubboBootstrap.getInstance().start();\n        this.afterExport();\n\n        // initialize consumer\n        this.initConsumer();\n        this.beforeRefer();\n        singleRegistryCenterIntegrationService = referenceConfig.get();\n        this.afterRefer();\n    }\n\n    /**\n     * There are some checkpoints needed to check as follow :\n     * <ul>\n     *     <li>ServiceConfig is exported or not</li>\n     *     <li>ServiceConfig's exportedUrl has values or not</li>\n     *     <li>DubboBootstrap is initialized or not</li>\n     *     <li>DubboBootstrap is started or not</li>\n     *     <li>DubboBootstrap is shutdown or not</li>\n     *     <li>The ServiceListener is loaded by SPI or not</li>\n     * </ul>\n     */\n    private void beforeExport() {\n        // ServiceConfig is exported or not\n        Assertions.assertFalse(serviceConfig.isExported());\n        // ServiceConfig's exportedUrl has values or not\n        Assertions.assertEquals(0, serviceConfig.getExportedUrls().size());\n        // DubboBootstrap is pending or not\n        Assertions.assertTrue(DubboBootstrap.getInstance().isPending());\n        // DubboBootstrap is initialized or not\n        Assertions.assertFalse(DubboBootstrap.getInstance().isInitialized());\n        // DubboBootstrap is started or not\n        Assertions.assertFalse(DubboBootstrap.getInstance().isStarted());\n        // DubboBootstrap is stopped or not\n        Assertions.assertFalse(DubboBootstrap.getInstance().isStopped());\n        // The ServiceListener is loaded by SPI or not\n        Assertions.assertNull(singleRegistryCenterExportedServiceListener);\n    }\n\n    /**\n     * There are some checkpoints needed to check as follow :\n     * <ul>\n     *     <li>DubboBootstrap is initialized or not</li>\n     *     <li>DubboBootstrap is started or not</li>\n     *     <li>DubboBootstrap is shutdown or not</li>\n     *     <li>Service has been exported or not</li>\n     *     <li>There is exported urls or not</li>\n     *     <li>Protocol name is right or not</li>\n     *     <li>Protocol port is right or not</li>\n     *     <li>ServiceDiscoveryRegistry's protocol is right or not</li>\n     *     <li>Registered service in registry center is right or not</li>\n     *     <li>MetadataInfo has reported or not</li>\n     *     <li>MetadataInfo has reported or not has service or not</li>\n     *     <li>MetadataInfo's application name is right or not</li>\n     *     <li>MetadataInfo's service exists or not</li>\n     *     <li>The name of MetadataInfo's service is right or not</li>\n     *     <li>The group of MetadataInfo's service is right or not</li>\n     *     <li>The version of MetadataInfo's service is right or not</li>\n     *     <li>The protocol of MetadataInfo's service is right or not</li>\n     *     <li>The serviceKey of MetadataInfo's service is right or not</li>\n     *     <li>The matchKey of MetadataInfo's service is right or not</li>\n     *     <li>The exported service are right or not</li>\n     * </ul>\n     */\n    private void afterExport() {\n        // DubboBootstrap is initialized or not\n        Assertions.assertTrue(DubboBootstrap.getInstance().isInitialized());\n        // DubboBootstrap is pending or not\n        Assertions.assertFalse(DubboBootstrap.getInstance().isPending());\n        // DubboBootstrap is started or not\n        Assertions.assertTrue(DubboBootstrap.getInstance().isCompletion());\n        // DubboBootstrap is running\n        Assertions.assertTrue(DubboBootstrap.getInstance().isRunning());\n        // DubboBootstrap is shutdown or not\n        Assertions.assertFalse(DubboBootstrap.getInstance().isStopped());\n        // Service has been exported or not\n        Assertions.assertTrue(this.serviceConfig.isExported());\n        // There is exported urls or not\n        Assertions.assertEquals(1, this.serviceConfig.getExportedUrls().size());\n        URL exportedUrl = this.serviceConfig.getExportedUrls().get(0);\n        // Protocol name is right or not\n        Assertions.assertEquals(exportedUrl.getProtocol(), PROTOCOL_NAME);\n        // Protocol port is right or not\n        Assertions.assertEquals(exportedUrl.getPort(), PROTOCOL_PORT);\n        // Application name is right or not\n        Assertions.assertEquals(exportedUrl.getApplication(), PROVIDER_APPLICATION_NAME);\n\n        // obtain ServiceDiscoveryRegistry instance\n        ServiceDiscoveryRegistry serviceDiscoveryRegistry = this.getServiceDiscoveryRegistry();\n        // ServiceDiscoveryRegistry instance cannot be null\n        Assertions.assertNotNull(serviceDiscoveryRegistry);\n        // ServiceDiscoveryRegistry's protocol is right or not\n        Assertions.assertTrue(serviceDiscoveryRegistry.getServiceDiscovery() instanceof ZookeeperServiceDiscovery);\n        // Convert to ZookeeperServiceDiscovery instance\n        ZookeeperServiceDiscovery zookeeperServiceDiscovery =\n                (ZookeeperServiceDiscovery) serviceDiscoveryRegistry.getServiceDiscovery();\n        // Gets registered service by ZookeeperServiceDiscovery\n        Set<String> services = zookeeperServiceDiscovery.getServices();\n        // check service exists\n        Assertions.assertTrue(!services.isEmpty());\n        // Registered service in registry center is right or not\n        Assertions.assertTrue(services.contains(PROVIDER_APPLICATION_NAME));\n\n        // obtain InMemoryWritableMetadataService instance\n        MetadataServiceDelegation inMemoryWritableMetadataService = (MetadataServiceDelegation)\n                serviceConfig.getScopeModel().getBeanFactory().getBean(MetadataService.class);\n        // Exported url is right or not in InMemoryWritableMetadataService\n        Assertions.assertEquals(\n                1, inMemoryWritableMetadataService.getExportedURLs().size());\n        // MetadataInfo exists or not in InMemoryWritableMetadataService\n        Assertions.assertFalse(\n                inMemoryWritableMetadataService.getMetadataInfos().isEmpty());\n        // MetadataInfo has reported or not has service or not\n        Assertions.assertFalse(inMemoryWritableMetadataService\n                .getMetadataInfos()\n                .get(0)\n                .getServices()\n                .isEmpty());\n        // MetadataInfo has reported or not has service or not\n        Assertions.assertEquals(\n                1,\n                inMemoryWritableMetadataService\n                        .getMetadataInfos()\n                        .get(0)\n                        .getServices()\n                        .size());\n        // obtain the service's key\n        String key = SingleRegistryCenterIntegrationService.class.getName() + \":\" + PROTOCOL_NAME;\n        MetadataInfo.ServiceInfo serviceInfo = inMemoryWritableMetadataService\n                .getMetadataInfos()\n                .get(0)\n                .getServices()\n                .get(key);\n        // MetadataInfo's service exists or not\n        Assertions.assertNotNull(serviceInfo);\n        // The name of MetadataInfo's service is right or not\n        Assertions.assertEquals(serviceInfo.getName(), SingleRegistryCenterIntegrationService.class.getName());\n        // The group of MetadataInfo's service is right or not\n        Assertions.assertNull(serviceInfo.getGroup());\n        // The version of MetadataInfo's service is right or not\n        Assertions.assertNull(serviceInfo.getVersion());\n        // The protocol of MetadataInfo's service is right or not\n        Assertions.assertEquals(serviceInfo.getProtocol(), PROTOCOL_NAME);\n        // The serviceKey of MetadataInfo's service is right or not\n        Assertions.assertEquals(serviceInfo.getServiceKey(), SingleRegistryCenterIntegrationService.class.getName());\n        // The matchKey of MetadataInfo's service is right or not\n        Assertions.assertEquals(serviceInfo.getMatchKey(), key);\n        // The exported services are right or not\n        // 1. The exported service must contain SingleRegistryCenterIntegrationService\n        // 2. The exported service's interface must be SingleRegistryCenterIntegrationService.class\n        // 3. All exported services must be exported\n        singleRegistryCenterExportedServiceListener = (SingleRegistryCenterExportedServiceListener)\n                ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension(\"exported\");\n        Assertions.assertNotNull(singleRegistryCenterExportedServiceListener);\n        Assertions.assertEquals(\n                1,\n                singleRegistryCenterExportedServiceListener\n                        .getExportedServices()\n                        .size());\n        Assertions.assertEquals(\n                SingleRegistryCenterIntegrationService.class,\n                singleRegistryCenterExportedServiceListener\n                        .getExportedServices()\n                        .get(0)\n                        .getInterfaceClass());\n        ServiceConfig singleRegistryCenterServiceConfig = singleRegistryCenterExportedServiceListener\n                .getExportedServices()\n                .get(0);\n        Assertions.assertNotNull(singleRegistryCenterServiceConfig);\n        Assertions.assertTrue(singleRegistryCenterServiceConfig.isExported());\n    }\n\n    /**\n     * Returns {@link ServiceDiscoveryRegistry} instance.\n     * <p>\n     * FIXME It's not a good way to obtain {@link ServiceDiscoveryRegistry} using Reflection.\n     */\n    private ServiceDiscoveryRegistry getServiceDiscoveryRegistry() {\n        Collection<Registry> registries =\n                RegistryManager.getInstance(ApplicationModel.defaultModel()).getRegistries();\n        for (Registry registry : registries) {\n            if (registry instanceof ServiceDiscoveryRegistry) {\n                return (ServiceDiscoveryRegistry) registry;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Initialize the consumer.\n     */\n    private void initConsumer() {\n        referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(SingleRegistryCenterIntegrationService.class);\n        DubboBootstrap.getInstance().reference(referenceConfig);\n        referenceConfig.setRegistry(registryConfig);\n        referenceConfig.setScope(SCOPE_REMOTE);\n        referenceConfig.setGeneric(\"false\");\n        referenceConfig.setProtocol(PROTOCOL_NAME);\n    }\n\n    /**\n     * There are some checkpoints needed to check before referring as follow :\n     * <ul>\n     *     <li>ReferenceConfig has integrated into DubboBootstrap or not</li>\n     * </ul>\n     */\n    private void beforeRefer() {\n        // ReferenceConfig has integrated into DubboBootstrap or not\n        Assertions.assertEquals(\n                referenceConfig.getScopeModel(),\n                DubboBootstrap.getInstance().getApplicationModel().getDefaultModule());\n    }\n\n    /**\n     * There are some checkpoints needed to check after referred as follow :\n     * <ul>\n     *     <li>SingleRegistryCenterIntegrationService instance can't be null</li>\n     *     <li>RPC works well or not</li>\n     *     <li>Invoker is right or not</li>\n     *     <li>Directory is null or not</li>\n     *     <li>Registered interface is right or not</li>\n     *     <li>Directory is available or not</li>\n     *     <li>Directory is destroyed or not</li>\n     *     <li>Directory has received notification or not</li>\n     *     <li>ServiceDiscoveryRegistryDirectory should register or not</li>\n     *     <li>ServiceDiscoveryRegistryDirectory's registered consumer url is right or not</li>\n     *     <li>ServiceDiscoveryRegistryDirectory's registry is right or not</li>\n     *     <li>Directory's invokers are right or not</li>\n     * </ul>\n     */\n    private void afterRefer() {\n        // SingleRegistryCenterIntegrationService instance can't be null\n        Assertions.assertNotNull(singleRegistryCenterIntegrationService);\n        // Invoker is right or not\n        Assertions.assertNotNull(referenceConfig.getInvoker());\n        Assertions.assertTrue(referenceConfig.getInvoker() instanceof MigrationInvoker);\n        // RPC works well or not\n        Assertions.assertEquals(\"Hello Reference\", singleRegistryCenterIntegrationService.hello(\"Reference\"));\n        // get ServiceDiscoveryRegistryDirectory instance\n        Directory directory = ((MigrationInvoker) referenceConfig.getInvoker()).getDirectory();\n        // Directory is null or not\n        Assertions.assertNotNull(directory);\n        // Check Directory's type\n        Assertions.assertTrue(directory instanceof ServiceDiscoveryRegistryDirectory);\n        // Registered interface is right or not\n        Assertions.assertEquals(directory.getInterface(), SingleRegistryCenterIntegrationService.class);\n        // Directory is available or not\n        Assertions.assertTrue(directory.isAvailable());\n        // Directory is destroyed or not\n        Assertions.assertFalse(directory.isDestroyed());\n        // Directory has received notification or not\n        Assertions.assertTrue(directory.isNotificationReceived());\n        ServiceDiscoveryRegistryDirectory serviceDiscoveryRegistryDirectory =\n                (ServiceDiscoveryRegistryDirectory) directory;\n        // ServiceDiscoveryRegistryDirectory should register or not\n        Assertions.assertTrue(serviceDiscoveryRegistryDirectory.isShouldRegister());\n        // ServiceDiscoveryRegistryDirectory's registered consumer url is right or not\n        Assertions.assertEquals(\n                CONSUMERS_CATEGORY,\n                serviceDiscoveryRegistryDirectory.getRegisteredConsumerUrl().getCategory());\n        // ServiceDiscoveryRegistryDirectory's registry is right or not\n        Assertions.assertTrue(serviceDiscoveryRegistryDirectory.getRegistry() instanceof ListenerRegistryWrapper);\n        // Directory's invokers are right or not\n        Assertions.assertEquals(\n                1, serviceDiscoveryRegistryDirectory.getAllInvokers().size());\n        Assertions.assertEquals(\n                serviceDiscoveryRegistryDirectory.getInvokers(), serviceDiscoveryRegistryDirectory.getAllInvokers());\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        DubboBootstrap.reset();\n        PROVIDER_APPLICATION_NAME = null;\n        PROTOCOL_NAME = null;\n        PROTOCOL_PORT = 0;\n        serviceConfig = null;\n        referenceConfig = null;\n        // The exported service has been unexported\n        Assertions.assertTrue(singleRegistryCenterExportedServiceListener\n                .getExportedServices()\n                .isEmpty());\n        singleRegistryCenterExportedServiceListener = null;\n        logger.info(getClass().getSimpleName() + \" testcase is ending...\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/SingleRegistryCenterExportedServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single;\n\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterServiceListener;\n\n/**\n * This implementation of {@link ServiceListener} is to record exported services in single registry center.\n */\npublic class SingleRegistryCenterExportedServiceListener extends AbstractRegistryCenterServiceListener {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return SingleRegistryCenterIntegrationService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/SingleRegistryCenterIntegrationService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single;\n\n/**\n * This interface for integration testcases in single registry center.\n */\npublic interface SingleRegistryCenterIntegrationService {\n\n    String hello(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/SingleRegistryCenterIntegrationServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * The implementation for {@link SingleRegistryCenterIntegrationService}\n */\npublic class SingleRegistryCenterIntegrationServiceImpl implements SingleRegistryCenterIntegrationService {\n\n    private static final Logger logger = LoggerFactory.getLogger(SingleRegistryCenterIntegrationServiceImpl.class);\n\n    @Override\n    public String hello(String name) {\n        String value = \"Hello \" + name;\n        logger.info(value);\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportmetadata/SingleRegistryCenterExportMetadataExporterListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportmetadata;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterExporterListener;\nimport org.apache.dubbo.metadata.MetadataService;\n\n@Activate(group = CommonConstants.PROVIDER, order = 1000)\npublic class SingleRegistryCenterExportMetadataExporterListener extends AbstractRegistryCenterExporterListener {\n\n    /**\n     * Returns the interface of exported service.\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return MetadataService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportmetadata/SingleRegistryCenterExportMetadataIntegrationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportmetadata;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.integration.IntegrationTest;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.ExporterListener;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;\n\n/**\n * The testcases are only for checking the process of exporting metadata service.\n */\nclass SingleRegistryCenterExportMetadataIntegrationTest implements IntegrationTest {\n\n    private static final Logger logger =\n            LoggerFactory.getLogger(SingleRegistryCenterExportMetadataIntegrationTest.class);\n\n    /**\n     * Define the provider application name.\n     */\n    private static String PROVIDER_APPLICATION_NAME = \"single-registry-center-export-metadata\";\n\n    /**\n     * The name for getting the specified instance, which is loaded using SPI.\n     */\n    private static String SPI_NAME = \"singleConfigCenterExportMetadata\";\n\n    /**\n     * Define the protocol's name.\n     */\n    private static String PROTOCOL_NAME = \"injvm\";\n    /**\n     * Define the {@link ServiceConfig} instance.\n     */\n    private ServiceConfig<SingleRegistryCenterExportMetadataService> serviceConfig;\n\n    /**\n     * The listener to record exported services\n     */\n    private SingleRegistryCenterExportMetadataServiceListener serviceListener;\n\n    /**\n     * The listener to record exported exporters.\n     */\n    private SingleRegistryCenterExportMetadataExporterListener exporterListener;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        logger.info(getClass().getSimpleName() + \" testcase is beginning...\");\n        DubboBootstrap.reset();\n        // initialize service config\n        serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(SingleRegistryCenterExportMetadataService.class);\n        serviceConfig.setRef(new SingleRegistryCenterExportMetadataServiceImpl());\n        serviceConfig.setAsync(false);\n        serviceConfig.setScope(SCOPE_LOCAL);\n\n        // initialize bootstrap\n        DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))\n                .protocol(new ProtocolConfig(PROTOCOL_NAME))\n                .service(serviceConfig);\n        RegistryConfig registryConfig = new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress());\n        DubboBootstrap.getInstance().registry(registryConfig);\n    }\n\n    /**\n     * Define {@link ServiceListener}, {@link ExporterListener} and {@link Filter} for helping check.\n     * <p>Use SPI to load them before exporting.\n     * <p>After that, there are some checkpoints need to verify as follow:\n     * <ul>\n     *     <li>There is nothing in ServiceListener or not</li>\n     *     <li>There is nothing in ExporterListener or not</li>\n     *     <li>ServiceConfig is exported or not</li>\n     * </ul>\n     */\n    private void beforeExport() {\n        // ---------------initialize--------------- //\n        serviceListener = (SingleRegistryCenterExportMetadataServiceListener)\n                ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension(SPI_NAME);\n        exporterListener = (SingleRegistryCenterExportMetadataExporterListener)\n                ExtensionLoader.getExtensionLoader(ExporterListener.class).getExtension(SPI_NAME);\n\n        // ---------------checkpoints--------------- //\n        // There is nothing in ServiceListener\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        // There is nothing in ExporterListener\n        Assertions.assertTrue(exporterListener.getExportedExporters().isEmpty());\n        // ServiceConfig isn't exported\n        Assertions.assertFalse(serviceConfig.isExported());\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Test\n    @Override\n    public void integrate() {\n        beforeExport();\n        DubboBootstrap.getInstance().start();\n        afterExport();\n    }\n\n    /**\n     * There are some checkpoints need to check after exported as follow:\n     * <ul>\n     *     <li>The metadata service is only one or not</li>\n     *     <li>The exported service is MetadataService or not</li>\n     *     <li>The MetadataService is exported or not</li>\n     *     <li>The exported exporters are right or not</li>\n     * </ul>\n     */\n    private void afterExport() {\n        // The metadata service is only one\n        Assertions.assertEquals(serviceListener.getExportedServices().size(), 1);\n        // The exported service is MetadataService\n        Assertions.assertEquals(\n                serviceListener.getExportedServices().get(0).getInterfaceClass(), MetadataService.class);\n        // The MetadataService is exported\n        Assertions.assertTrue(serviceListener.getExportedServices().get(0).isExported());\n        // There are two exported exporters\n        // 1. Metadata Service exporter with Injvm protocol\n        // 2. SingleRegistryCenterExportMetadataService exporter with Injvm protocol\n        Assertions.assertEquals(exporterListener.getExportedExporters().size(), 2);\n        List<Exporter<?>> injvmExporters = exporterListener.getExportedExporters();\n        // Make sure there are 2 injvmExporters\n        Assertions.assertEquals(2, injvmExporters.size());\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        DubboBootstrap.reset();\n        serviceConfig = null;\n        // The exported service has been unexported\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        serviceListener = null;\n        logger.info(getClass().getSimpleName() + \" testcase is ending...\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportmetadata/SingleRegistryCenterExportMetadataService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportmetadata;\n\n/**\n * This interface is used to check if the exported metadata service works well or not.\n */\npublic interface SingleRegistryCenterExportMetadataService {\n\n    /**\n     * The simple method for testing.\n     */\n    String hello(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportmetadata/SingleRegistryCenterExportMetadataServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportmetadata;\n\n/**\n * The simple implementation for {@link SingleRegistryCenterExportMetadataService}\n */\npublic class SingleRegistryCenterExportMetadataServiceImpl implements SingleRegistryCenterExportMetadataService {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String hello(String name) {\n        return \"Hello \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportmetadata/SingleRegistryCenterExportMetadataServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportmetadata;\n\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterServiceListener;\nimport org.apache.dubbo.metadata.MetadataService;\n\n/**\n * This implementation of {@link ServiceListener} is to record exported metadata services in single registry center.\n */\npublic class SingleRegistryCenterExportMetadataServiceListener extends AbstractRegistryCenterServiceListener {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return MetadataService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderExporterListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportprovider;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterExporterListener;\n\n@Activate(group = CommonConstants.PROVIDER, order = 1000)\npublic class SingleRegistryCenterExportProviderExporterListener extends AbstractRegistryCenterExporterListener {\n\n    /**\n     * Returns the interface of exported service.\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return SingleRegistryCenterExportProviderService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportprovider;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\n@Activate(group = CommonConstants.PROVIDER, order = 10000)\npublic class SingleRegistryCenterExportProviderFilter implements Filter, Filter.Listener {\n\n    /**\n     * The filter is called or not\n     */\n    private boolean called = false;\n\n    /**\n     * There has error after invoked\n     */\n    private boolean error = false;\n\n    /**\n     * The returned result\n     */\n    private String response;\n    /**\n     * Always call invoker.invoke() in the implementation to hand over the request to the next filter node.\n     *\n     * @param invoker\n     * @param invocation\n     */\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        called = true;\n        return invoker.invoke(invocation);\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {\n        response = String.valueOf(appResponse.getValue());\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        error = true;\n    }\n\n    /**\n     * Returns if the filter has called.\n     */\n    public boolean hasCalled() {\n        return called;\n    }\n\n    /**\n     * Returns if there exists error.\n     */\n    public boolean hasError() {\n        return error;\n    }\n\n    /**\n     * Returns the response.\n     */\n    public String getResponse() {\n        return response;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderIntegrationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportprovider;\n\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.integration.IntegrationTest;\nimport org.apache.dubbo.metadata.ServiceNameMapping;\nimport org.apache.dubbo.metadata.report.MetadataReportInstance;\nimport org.apache.dubbo.registry.integration.RegistryProtocolListener;\nimport org.apache.dubbo.rpc.ExporterListener;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_PROTOCOL_LISTENER_KEY;\nimport static org.apache.dubbo.config.integration.Constants.SINGLE_CONFIG_CENTER_EXPORT_PROVIDER;\nimport static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;\n\n/**\n * The testcases are only for checking the core process of exporting provider.\n */\nclass SingleRegistryCenterExportProviderIntegrationTest implements IntegrationTest {\n\n    private static final Logger logger =\n            LoggerFactory.getLogger(SingleRegistryCenterExportProviderIntegrationTest.class);\n\n    /**\n     * Define the provider application name.\n     */\n    private static String PROVIDER_APPLICATION_NAME = \"single-registry-center-for-export-provider\";\n\n    /**\n     * Define the protocol's name.\n     */\n    private static String PROTOCOL_NAME = CommonConstants.DUBBO;\n    /**\n     * Define the protocol's port.\n     */\n    private static int PROTOCOL_PORT = 20800;\n\n    /**\n     * Define the {@link ServiceConfig} instance.\n     */\n    private ServiceConfig<SingleRegistryCenterExportProviderService> serviceConfig;\n\n    /**\n     * Define a {@link RegistryProtocolListener} instance.\n     */\n    private SingleRegistryCenterExportProviderRegistryProtocolListener registryProtocolListener;\n\n    /**\n     * Define a {@link ExporterListener} instance.\n     */\n    private SingleRegistryCenterExportProviderExporterListener exporterListener;\n\n    /**\n     * Define a {@link Filter} instance.\n     */\n    private SingleRegistryCenterExportProviderFilter filter;\n\n    /**\n     * Define a {@link ServiceListener} instance.\n     */\n    private SingleRegistryCenterExportProviderServiceListener serviceListener;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        logger.info(getClass().getSimpleName() + \" testcase is beginning...\");\n        DubboBootstrap.reset();\n        // initialize service config\n        serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(SingleRegistryCenterExportProviderService.class);\n        serviceConfig.setRef(new SingleRegistryCenterExportProviderServiceImpl());\n        serviceConfig.setAsync(false);\n\n        // initialize bootstrap\n        DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))\n                .protocol(new ProtocolConfig(PROTOCOL_NAME, PROTOCOL_PORT))\n                .service(serviceConfig);\n\n        RegistryConfig registryConfig = new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress());\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(REGISTRY_PROTOCOL_LISTENER_KEY, \"singleConfigCenterExportProvider\");\n        registryConfig.updateParameters(parameters);\n        DubboBootstrap.getInstance().registry(registryConfig);\n    }\n\n    /**\n     * There are some checkpoints need to verify as follow:\n     * <ul>\n     *     <li>ServiceConfig is exported or not</li>\n     *     <li>SingleRegistryCenterExportProviderRegistryProtocolListener is null or not</li>\n     *     <li>There is nothing in ServiceListener or not</li>\n     *     <li>There is nothing in ExporterListener or not</li>\n     * </ul>\n     */\n    private void beforeExport() {\n        registryProtocolListener = (SingleRegistryCenterExportProviderRegistryProtocolListener)\n                ExtensionLoader.getExtensionLoader(RegistryProtocolListener.class)\n                        .getExtension(SINGLE_CONFIG_CENTER_EXPORT_PROVIDER);\n        exporterListener = (SingleRegistryCenterExportProviderExporterListener)\n                ExtensionLoader.getExtensionLoader(ExporterListener.class)\n                        .getExtension(SINGLE_CONFIG_CENTER_EXPORT_PROVIDER);\n        filter = (SingleRegistryCenterExportProviderFilter)\n                ExtensionLoader.getExtensionLoader(Filter.class).getExtension(SINGLE_CONFIG_CENTER_EXPORT_PROVIDER);\n        serviceListener = (SingleRegistryCenterExportProviderServiceListener)\n                ExtensionLoader.getExtensionLoader(ServiceListener.class)\n                        .getExtension(SINGLE_CONFIG_CENTER_EXPORT_PROVIDER);\n        // ---------------checkpoints--------------- //\n        // ServiceConfig isn't exported\n        Assertions.assertFalse(serviceConfig.isExported());\n        // registryProtocolListener is just initialized by SPI\n        // so, all of fields are the default value.\n        Assertions.assertNotNull(registryProtocolListener);\n        Assertions.assertFalse(registryProtocolListener.isExported());\n        // There is nothing in ServiceListener\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        // There is nothing in ExporterListener\n        Assertions.assertTrue(exporterListener.getExportedExporters().isEmpty());\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Test\n    @Override\n    public void integrate() {\n        beforeExport();\n        DubboBootstrap.getInstance().start();\n        afterExport();\n        ReferenceConfig<SingleRegistryCenterExportProviderService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(SingleRegistryCenterExportProviderService.class);\n        referenceConfig.setScope(SCOPE_LOCAL);\n        referenceConfig.get().hello(PROVIDER_APPLICATION_NAME);\n        afterInvoke();\n    }\n\n    /**\n     * There are some checkpoints need to check after exported as follow:\n     * <ul>\n     *     <li>the exporter is exported or not</li>\n     *     <li>The exported exporter are three</li>\n     *     <li>The exported service is SingleRegistryCenterExportProviderService or not</li>\n     *     <li>The SingleRegistryCenterExportProviderService is exported or not</li>\n     *     <li>The exported exporter contains SingleRegistryCenterExportProviderFilter or not</li>\n     *     <li>The metadata mapping info is right or not</li>\n     * </ul>\n     */\n    private void afterExport() {\n        // The exporter is exported\n        Assertions.assertTrue(registryProtocolListener.isExported());\n        // The exported service is only one\n        Assertions.assertEquals(serviceListener.getExportedServices().size(), 1);\n        // The exported service is SingleRegistryCenterExportProviderService\n        Assertions.assertEquals(\n                serviceListener.getExportedServices().get(0).getInterfaceClass(),\n                SingleRegistryCenterExportProviderService.class);\n        // The SingleRegistryCenterExportProviderService is exported\n        Assertions.assertTrue(serviceListener.getExportedServices().get(0).isExported());\n        // The exported exporter are three\n        // 1. InjvmExporter\n        // 2. DubboExporter with service-discovery-registry protocol\n        // 3. DubboExporter with registry protocol\n        Assertions.assertEquals(exporterListener.getExportedExporters().size(), 4);\n        // The exported exporter contains SingleRegistryCenterExportProviderFilter\n        Assertions.assertTrue(exporterListener.getFilters().contains(filter));\n        // The consumer can be notified and get provider's metadata through metadata mapping info.\n        // So, the metadata mapping is necessary to check after exported service (or provider)\n        // The best way to verify this issue is to check if the exported service (or provider)\n        // has been registered in the path of /dubbo/mapping/****\n        // What are the parameters?\n        // registryKey: the registryKey is the default cluster, CommonConstants.DEFAULT_KEY\n        // key: The exported interface's name\n        // group: the group is \"mapping\", ServiceNameMapping.DEFAULT_MAPPING_GROUP\n        ConfigItem configItem = ApplicationModel.defaultModel()\n                .getBeanFactory()\n                .getBean(MetadataReportInstance.class)\n                .getMetadataReport(CommonConstants.DEFAULT_KEY)\n                .getConfigItem(serviceConfig.getInterface(), ServiceNameMapping.DEFAULT_MAPPING_GROUP);\n        // Check if the exported service (provider) is registered\n        Assertions.assertNotNull(configItem);\n        // Check if registered service (provider)'s name is right\n        Assertions.assertEquals(PROVIDER_APPLICATION_NAME, configItem.getContent());\n        // Check if registered service (provider)'s version exists\n        Assertions.assertNotNull(configItem.getTicket());\n    }\n\n    /**\n     * There are some checkpoints need to check after invoked as follow:\n     * <ul>\n     *     <li>The SingleRegistryCenterExportProviderFilter has called or not</li>\n     *     <li>The SingleRegistryCenterExportProviderFilter exists error after invoked</li>\n     *     <li>The SingleRegistryCenterExportProviderFilter's response is right or not</li>\n     * </ul>\n     */\n    private void afterInvoke() {\n        // The SingleRegistryCenterExportProviderFilter has called\n        Assertions.assertTrue(filter.hasCalled());\n        // The SingleRegistryCenterExportProviderFilter doesn't exist error\n        Assertions.assertFalse(filter.hasError());\n        // Check the SingleRegistryCenterExportProviderFilter's response\n        Assertions.assertEquals(\"Hello \" + PROVIDER_APPLICATION_NAME, filter.getResponse());\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        DubboBootstrap.reset();\n        serviceConfig = null;\n        // The exported service has been unexported\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        logger.info(getClass().getSimpleName() + \" testcase is ending...\");\n        registryProtocolListener = null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderRegistryProtocolListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportprovider;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol;\nimport org.apache.dubbo.registry.integration.RegistryProtocol;\nimport org.apache.dubbo.registry.integration.RegistryProtocolListener;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\nimport static org.apache.dubbo.config.integration.Constants.SINGLE_CONFIG_CENTER_EXPORT_PROVIDER;\n\n/**\n * The {@link RegistryProtocolListener} for {@link SingleRegistryCenterExportProviderService}\n */\n@Activate(order = 100, value = SINGLE_CONFIG_CENTER_EXPORT_PROVIDER)\npublic class SingleRegistryCenterExportProviderRegistryProtocolListener implements RegistryProtocolListener {\n\n    private boolean exported = false;\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void onExport(RegistryProtocol registryProtocol, Exporter<?> exporter) {\n        if (registryProtocol instanceof InterfaceCompatibleRegistryProtocol\n                && exporter != null\n                && exporter.getInvoker() != null\n                && exporter.getInvoker().getInterface().equals(SingleRegistryCenterExportProviderService.class)) {\n            this.exported = true;\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void onRefer(RegistryProtocol registryProtocol, ClusterInvoker<?> invoker, URL url, URL registryURL) {}\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void onDestroy() {}\n\n    /**\n     * Returns if this exporter is exported.\n     */\n    public boolean isExported() {\n        return exported;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportprovider;\n\n/**\n * This interface is used to check if the exported provider works well or not.\n */\npublic interface SingleRegistryCenterExportProviderService {\n\n    /**\n     * The simple method for testing.\n     */\n    String hello(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportprovider;\n\n/**\n * The implementation of {@link SingleRegistryCenterExportProviderService}\n */\npublic class SingleRegistryCenterExportProviderServiceImpl implements SingleRegistryCenterExportProviderService {\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String hello(String name) {\n        return \"Hello \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.exportprovider;\n\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterServiceListener;\n\n/**\n * This implementation of {@link ServiceListener} is to record exported services with injvm protocol in single registry center.\n */\npublic class SingleRegistryCenterExportProviderServiceListener extends AbstractRegistryCenterServiceListener {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return SingleRegistryCenterExportProviderService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/injvm/SingleRegistryCenterInjvmExporterListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.injvm;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterExporterListener;\n\n@Activate(group = CommonConstants.PROVIDER, order = 1000)\npublic class SingleRegistryCenterInjvmExporterListener extends AbstractRegistryCenterExporterListener {\n\n    /**\n     * Returns the interface of exported service.\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return SingleRegistryCenterInjvmService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/injvm/SingleRegistryCenterInjvmFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.injvm;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\n@Activate(group = CommonConstants.PROVIDER, order = 10000)\npublic class SingleRegistryCenterInjvmFilter implements Filter, Filter.Listener {\n\n    /**\n     * The filter is called or not\n     */\n    private boolean called = false;\n\n    /**\n     * There has error after invoked\n     */\n    private boolean error = false;\n\n    /**\n     * The returned result\n     */\n    private String response;\n    /**\n     * Always call invoker.invoke() in the implementation to hand over the request to the next filter node.\n     *\n     * @param invoker\n     * @param invocation\n     */\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        called = true;\n        return invoker.invoke(invocation);\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {\n        response = String.valueOf(appResponse.getValue());\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        error = true;\n    }\n\n    /**\n     * Returns if the filter has called.\n     */\n    public boolean hasCalled() {\n        return called;\n    }\n\n    /**\n     * Returns if there exists error.\n     */\n    public boolean hasError() {\n        return error;\n    }\n\n    /**\n     * Returns the response.\n     */\n    public String getResponse() {\n        return response;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.injvm;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.integration.IntegrationTest;\nimport org.apache.dubbo.rpc.ExporterListener;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;\n\n/**\n * The testcases are only for checking the process of exporting provider using injvm protocol.\n */\nclass SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(SingleRegistryCenterInjvmIntegrationTest.class);\n\n    /**\n     * Define the provider application name.\n     */\n    private static String PROVIDER_APPLICATION_NAME = \"single-registry-center-provider-for-injvm-protocol\";\n\n    /**\n     * The name for getting the specified instance, which is loaded using SPI.\n     */\n    private static String SPI_NAME = \"singleConfigCenterInjvm\";\n    /**\n     * Define the {@link ServiceConfig} instance.\n     */\n    private ServiceConfig<SingleRegistryCenterInjvmService> serviceConfig;\n\n    /**\n     * The listener to record exported services\n     */\n    private SingleRegistryCenterInjvmServiceListener serviceListener;\n\n    /**\n     * The listener to record exported exporters.\n     */\n    private SingleRegistryCenterInjvmExporterListener exporterListener;\n\n    /**\n     * The filter for checking filter chain.\n     */\n    private SingleRegistryCenterInjvmFilter filter;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        logger.info(getClass().getSimpleName() + \" testcase is beginning...\");\n        DubboBootstrap.reset();\n        // initialize service config\n        serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(SingleRegistryCenterInjvmService.class);\n        serviceConfig.setRef(new SingleRegistryCenterInjvmServiceImpl());\n        serviceConfig.setAsync(false);\n        serviceConfig.setScope(SCOPE_LOCAL);\n\n        // initialize bootstrap\n        DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))\n                .protocol(new ProtocolConfig(\"injvm\"))\n                .service(serviceConfig);\n        RegistryConfig registryConfig = new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress());\n        DubboBootstrap.getInstance().registry(registryConfig);\n    }\n\n    /**\n     * Define {@link ServiceListener}, {@link ExporterListener} and {@link Filter} for helping check.\n     * <p>Use SPI to load them before exporting.\n     * <p>After that, there are some checkpoints need to verify as follow:\n     * <ul>\n     *     <li>There is nothing in ServiceListener or not</li>\n     *     <li>There is nothing in ExporterListener or not</li>\n     *     <li>ServiceConfig is exported or not</li>\n     * </ul>\n     */\n    private void beforeExport() {\n        // ---------------initialize--------------- //\n        serviceListener = (SingleRegistryCenterInjvmServiceListener)\n                ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension(SPI_NAME);\n        exporterListener = (SingleRegistryCenterInjvmExporterListener)\n                ExtensionLoader.getExtensionLoader(ExporterListener.class).getExtension(SPI_NAME);\n        filter = (SingleRegistryCenterInjvmFilter)\n                ExtensionLoader.getExtensionLoader(Filter.class).getExtension(SPI_NAME);\n\n        // ---------------checkpoints--------------- //\n        // There is nothing in ServiceListener\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        // There is nothing in ExporterListener\n        Assertions.assertTrue(exporterListener.getExportedExporters().isEmpty());\n        // ServiceConfig isn't exported\n        Assertions.assertFalse(serviceConfig.isExported());\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Test\n    @Override\n    public void integrate() {\n        beforeExport();\n        DubboBootstrap.getInstance().start();\n        afterExport();\n        ReferenceConfig<SingleRegistryCenterInjvmService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(SingleRegistryCenterInjvmService.class);\n        referenceConfig.setScope(SCOPE_LOCAL);\n        referenceConfig.get().hello(\"Dubbo\");\n        afterInvoke();\n    }\n\n    /**\n     * There are some checkpoints need to check after exported as follow:\n     * <ul>\n     *     <li>The exported service is only one or not</li>\n     *     <li>The exported service is SingleRegistryCenterInjvmService or not</li>\n     *     <li>The SingleRegistryCenterInjvmService is exported or not</li>\n     *     <li>The exported exporter is only one or not</li>\n     *     <li>The exported exporter contains SingleRegistryCenterInjvmFilter or not</li>\n     * </ul>\n     */\n    private void afterExport() {\n        // The exported service is only one\n        Assertions.assertEquals(serviceListener.getExportedServices().size(), 1);\n        // The exported service is SingleRegistryCenterInjvmService\n        Assertions.assertEquals(\n                serviceListener.getExportedServices().get(0).getInterfaceClass(),\n                SingleRegistryCenterInjvmService.class);\n        // The SingleRegistryCenterInjvmService is exported\n        Assertions.assertTrue(serviceListener.getExportedServices().get(0).isExported());\n        // The exported exporter is only one\n        Assertions.assertEquals(exporterListener.getExportedExporters().size(), 3);\n        // The exported exporter contains SingleRegistryCenterInjvmFilter\n        Assertions.assertTrue(exporterListener.getFilters().contains(filter));\n    }\n\n    /**\n     * There are some checkpoints need to check after invoked as follow:\n     * <ul>\n     *     <li>The SingleRegistryCenterInjvmFilter has called or not</li>\n     *     <li>The SingleRegistryCenterInjvmFilter exists error after invoked</li>\n     *     <li>The SingleRegistryCenterInjvmFilter's response is right or not</li>\n     * </ul>\n     */\n    private void afterInvoke() {\n        // The SingleRegistryCenterInjvmFilter has called\n        Assertions.assertTrue(filter.hasCalled());\n        // The SingleRegistryCenterInjvmFilter doesn't exist error\n        Assertions.assertFalse(filter.hasError());\n        // Check the SingleRegistryCenterInjvmFilter's response\n        Assertions.assertEquals(\"Hello Dubbo\", filter.getResponse());\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        DubboBootstrap.reset();\n        serviceConfig = null;\n        // The exported service has been unexported\n        Assertions.assertTrue(serviceListener.getExportedServices().isEmpty());\n        serviceListener = null;\n        logger.info(getClass().getSimpleName() + \" testcase is ending...\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/injvm/SingleRegistryCenterInjvmService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.injvm;\n\n/**\n * This interface is used to check if the exported injvm protocol works well or not.\n */\npublic interface SingleRegistryCenterInjvmService {\n\n    /**\n     * The simple method for testing.\n     */\n    String hello(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/injvm/SingleRegistryCenterInjvmServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.injvm;\n\n/**\n * The simple implementation for {@link SingleRegistryCenterInjvmService}\n */\npublic class SingleRegistryCenterInjvmServiceImpl implements SingleRegistryCenterInjvmService {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String hello(String name) {\n        return \"Hello \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/injvm/SingleRegistryCenterInjvmServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.integration.single.injvm;\n\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.config.integration.AbstractRegistryCenterServiceListener;\n\n/**\n * This implementation of {@link ServiceListener} is to record exported services with injvm protocol in single registry center.\n */\npublic class SingleRegistryCenterInjvmServiceListener extends AbstractRegistryCenterServiceListener {\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected Class<?> getInterface() {\n        return SingleRegistryCenterInjvmService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/package-info.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * There are two scenario in integration testcases.<p>\n * The one is single registry center, the other is multiple registry centers.<p>\n * The purpose of all of testcases in this package is to test for single registry center.\n */\npackage org.apache.dubbo.config.integration.single;\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/invoker/DelegateProviderMetaDataInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.invoker;\n\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.api.Greeting;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.sameInstance;\n\nclass DelegateProviderMetaDataInvokerTest {\n    private ServiceConfig service;\n    private Invoker<Greeting> invoker;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        service = Mockito.mock(ServiceConfig.class);\n        invoker = Mockito.mock(Invoker.class);\n    }\n\n    @Test\n    void testDelegate() {\n        DelegateProviderMetaDataInvoker<Greeting> delegate =\n                new DelegateProviderMetaDataInvoker<Greeting>(invoker, service);\n        delegate.getInterface();\n        Mockito.verify(invoker).getInterface();\n        delegate.getUrl();\n        Mockito.verify(invoker).getUrl();\n        delegate.isAvailable();\n        Mockito.verify(invoker).isAvailable();\n        Invocation invocation = Mockito.mock(Invocation.class);\n        delegate.invoke(invocation);\n        Mockito.verify(invoker).invoke(invocation);\n        delegate.destroy();\n        Mockito.verify(invoker).destroy();\n        assertThat(delegate.getMetadata(), sameInstance(service));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/MetadataServiceURLParamsMetadataCustomizerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.api.DemoService;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.provider.impl.DemoServiceImpl;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.io.IOException;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME;\n\nclass MetadataServiceURLParamsMetadataCustomizerTest {\n\n    public DefaultServiceInstance instance;\n    private URL metadataServiceURL = URL.valueOf(\n            \"dubbo://10.225.12.124:2002/org.apache.dubbo.metadata.MetadataService\"\n                    + \"?application=MetadataServiceURLParamsMetadataCustomizerTest&group=MetadataServiceURLParamsMetadataCustomizerTest\"\n                    + \"&interface=org.apache.dubbo.metadata.MetadataService&side=provider&timestamp=1637573430740&version=1.0.0\");\n\n    public static DefaultServiceInstance createInstance() {\n        return new DefaultServiceInstance(\"A\", \"127.0.0.1\", 20880, ApplicationModel.defaultModel());\n    }\n\n    @BeforeEach\n    public void init() {\n        instance = createInstance();\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        Mockito.framework().clearInlineMocks();\n    }\n\n    @Test\n    void test() throws InterruptedException {\n        DubboBootstrap providerBootstrap = DubboBootstrap.newInstance();\n        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(DemoService.class);\n        serviceConfig.setRef(new DemoServiceImpl());\n        serviceConfig.setDelay(1000);\n\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"MetadataServiceURLParamsMetadataCustomizerTest\");\n        applicationConfig.setMetadataType(DEFAULT_METADATA_STORAGE_TYPE);\n\n        providerBootstrap\n                .application(applicationConfig)\n                .registry(new RegistryConfig(\"N/A\"))\n                .protocol(new ProtocolConfig(\"dubbo\", 2002))\n                .service(serviceConfig);\n\n        // will start exporter.export()\n        providerBootstrap.start();\n\n        ApplicationModel applicationModel = providerBootstrap.getApplicationModel();\n        MetadataServiceURLParamsMetadataCustomizer customizer = new MetadataServiceURLParamsMetadataCustomizer();\n\n        Thread.sleep(5000); // wait for service delay export\n\n        customizer.customize(instance, applicationModel);\n        String val = instance.getMetadata().get(METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME);\n        Assertions.assertNotNull(val);\n\n        Map<String, String> map = JsonUtils.toJavaObject(val, Map.class);\n        Assertions.assertEquals(map.get(PORT_KEY), String.valueOf(metadataServiceURL.getPort()));\n        Assertions.assertEquals(map.get(PROTOCOL_KEY), metadataServiceURL.getProtocol());\n        Assertions.assertEquals(map.get(VERSION_KEY), metadataServiceURL.getVersion());\n        Assertions.assertFalse(map.containsKey(TIMESTAMP_KEY));\n        Assertions.assertFalse(map.containsKey(GROUP_KEY));\n        Assertions.assertFalse(map.containsKey(APPLICATION_KEY));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/GreetingLocal1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\npublic class GreetingLocal1 {}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/GreetingLocal2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.config.api.Greeting;\n\npublic class GreetingLocal2 implements Greeting {\n    @Override\n    public String hello() {\n        return \"local\";\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/GreetingLocal3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.config.api.Greeting;\n\npublic class GreetingLocal3 implements Greeting {\n    private Greeting greeting;\n\n    public GreetingLocal3(Greeting greeting) {\n        this.greeting = greeting;\n    }\n\n    @Override\n    public String hello() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCluster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\npublic class MockCluster implements Cluster {\n    @Override\n    public <T> Invoker<T> join(Directory<T> directory, boolean buildFilterChain) throws RpcException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockCodec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Codec;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class MockCodec implements Codec {\n    @Override\n    public void encode(Channel channel, OutputStream output, Object message) throws IOException {}\n\n    @Override\n    public Object decode(Channel channel, InputStream input) throws IOException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Dispatcher;\n\npublic class MockDispatcher implements Dispatcher {\n    @Override\n    public ChannelHandler dispatch(ChannelHandler handler, URL url) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockExchanger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeClient;\nimport org.apache.dubbo.remoting.exchange.ExchangeHandler;\nimport org.apache.dubbo.remoting.exchange.ExchangeServer;\nimport org.apache.dubbo.remoting.exchange.Exchanger;\n\npublic class MockExchanger implements Exchanger {\n    @Override\n    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {\n        return null;\n    }\n\n    @Override\n    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockExporterListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.ExporterListener;\nimport org.apache.dubbo.rpc.RpcException;\n\npublic class MockExporterListener implements ExporterListener {\n    @Override\n    public void exported(Exporter<?> exporter) throws RpcException {}\n\n    @Override\n    public void unexported(Exporter<?> exporter) {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\npublic class MockFilter implements Filter {\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockInvokerListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.InvokerListener;\nimport org.apache.dubbo.rpc.RpcException;\n\npublic class MockInvokerListener implements InvokerListener {\n    @Override\n    public void referred(Invoker<?> invoker) throws RpcException {}\n\n    @Override\n    public void destroyed(Invoker<?> invoker) {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockLoadBalance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\n\nimport java.util.List;\n\npublic class MockLoadBalance implements LoadBalance {\n    @Override\n    public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockProtocol.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport org.mockito.Mockito;\n\npublic class MockProtocol implements Protocol {\n\n    /* (non-Javadoc)\n     * @see org.apache.dubbo.rpc.Protocol#getDefaultPort()\n     */\n    @Override\n    public int getDefaultPort() {\n\n        return 0;\n    }\n\n    /* (non-Javadoc)\n     * @see org.apache.dubbo.rpc.Protocol#export(org.apache.dubbo.rpc.Invoker)\n     */\n    @Override\n    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {\n        return Mockito.mock(Exporter.class);\n    }\n\n    /* (non-Javadoc)\n     * @see org.apache.dubbo.rpc.Protocol#refer(java.lang.Class, org.apache.dubbo.common.URL)\n     */\n    @Override\n    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {\n\n        final URL u = url;\n\n        return new Invoker<T>() {\n            @Override\n            public Class<T> getInterface() {\n                return null;\n            }\n\n            public URL getUrl() {\n                return u;\n            }\n\n            @Override\n            public boolean isAvailable() {\n                return true;\n            }\n\n            @Override\n            public Result invoke(Invocation invocation) throws RpcException {\n                return null;\n            }\n\n            @Override\n            public void destroy() {}\n        };\n    }\n\n    /* (non-Javadoc)\n     * @see org.apache.dubbo.rpc.Protocol#destroy()\n     */\n    @Override\n    public void destroy() {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockProtocol2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.RpcException;\n\npublic class MockProtocol2 implements Protocol {\n    public static Protocol delegate;\n\n    @Override\n    public int getDefaultPort() {\n        return delegate.getDefaultPort();\n    }\n\n    @Override\n    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {\n        return delegate.export(invoker);\n    }\n\n    @Override\n    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {\n        return delegate.refer(type, url);\n    }\n\n    @Override\n    public void destroy() {\n        delegate.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockProxyFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.RpcException;\n\npublic class MockProxyFactory implements ProxyFactory {\n    @Override\n    public <T> T getProxy(Invoker<T> invoker) throws RpcException {\n        return null;\n    }\n\n    @Override\n    public <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {\n        return null;\n    }\n\n    @Override\n    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\n\n/**\n * TODO Comment of MockRegistry\n */\npublic class MockRegistry implements Registry {\n\n    static URL subscribedUrl = new ServiceConfigURL(\"null\", \"0.0.0.0\", 0);\n\n    public static URL getSubscribedUrl() {\n        return subscribedUrl;\n    }\n\n    /*\n     * @see org.apache.dubbo.common.Node#getUrl()\n     */\n    public URL getUrl() {\n        return null;\n    }\n\n    /*\n     * @see org.apache.dubbo.common.Node#isAvailable()\n     */\n    @Override\n    public boolean isAvailable() {\n        return true;\n    }\n\n    /*\n     * @see org.apache.dubbo.common.Node#destroy()\n     */\n    @Override\n    public void destroy() {}\n\n    /*\n     * @see org.apache.dubbo.registry.RegistryService#register(org.apache.dubbo.common.URL)\n     */\n    @Override\n    public void register(URL url) {}\n\n    /*\n     * @see org.apache.dubbo.registry.RegistryService#unregister(org.apache.dubbo.common.URL)\n     */\n    @Override\n    public void unregister(URL url) {}\n\n    /*\n     * @see org.apache.dubbo.registry.RegistryService#subscribe(org.apache.dubbo.common.URL, org.apache.dubbo.registry.NotifyListener)\n     */\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        this.subscribedUrl = url;\n        List<URL> urls = new ArrayList<URL>();\n\n        urls.add(url.setProtocol(\"mockprotocol\").removeParameter(CATEGORY_KEY).addParameter(METHODS_KEY, \"sayHello\"));\n\n        listener.notify(urls);\n    }\n\n    /*\n     * @see org.apache.dubbo.registry.RegistryService#unsubscribe(org.apache.dubbo.common.URL, org.apache.dubbo.registry.NotifyListener)\n     */\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {}\n\n    /*\n     * @see org.apache.dubbo.registry.RegistryService#lookup(org.apache.dubbo.common.URL)\n     */\n    @Override\n    public List<URL> lookup(URL url) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\n\n/**\n * TODO Comment of MockRegistryFactory\n */\npublic class MockRegistryFactory implements RegistryFactory {\n\n    /*\n     * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(org.apache.dubbo.common.URL)\n     */\n    @Override\n    public Registry getRegistry(URL url) {\n\n        return new MockRegistry();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockRegistryFactory2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\n\npublic class MockRegistryFactory2 implements RegistryFactory {\n    public static Registry registry;\n\n    @Override\n    public Registry getRegistry(URL url) {\n        return registry;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class MockServiceDiscovery extends AbstractServiceDiscovery {\n    private URL registryURL;\n\n    public MockServiceDiscovery(ApplicationModel applicationModel, URL registryURL) {\n        super(applicationModel, registryURL);\n    }\n\n    public MockServiceDiscovery(String serviceName, URL registryURL) {\n        super(serviceName, registryURL);\n    }\n\n    @Override\n    public void doDestroy() throws Exception {}\n\n    @Override\n    public void doRegister(ServiceInstance serviceInstance) throws RuntimeException {\n        this.serviceInstance = serviceInstance;\n    }\n\n    @Override\n    protected void doUpdate(ServiceInstance oldServiceInstance, ServiceInstance newServiceInstance)\n            throws RuntimeException {\n        this.serviceInstance = newServiceInstance;\n    }\n\n    @Override\n    public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException {\n        this.serviceInstance = null;\n    }\n\n    @Override\n    public Set<String> getServices() {\n        return new HashSet<>();\n    }\n\n    @Override\n    public List<ServiceInstance> getInstances(String serviceName) throws NullPointerException {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public URL getUrl() {\n        return registryURL;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.metadata.MetadataService;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class MockServiceListener implements ServiceListener {\n\n    private Map<String, ServiceConfig> exportedServices = new ConcurrentHashMap<>();\n\n    @Override\n    public void exported(ServiceConfig sc) {\n        // Ignore MetadataService\n        if (sc.getInterfaceClass() == MetadataService.class) {\n            return;\n        }\n        exportedServices.put(sc.getUniqueServiceName(), sc);\n    }\n\n    @Override\n    public void unexported(ServiceConfig sc) {}\n\n    public Map<String, ServiceConfig> getExportedServices() {\n        return exportedServices;\n    }\n\n    public void clearExportedServices() {\n        exportedServices.clear();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockStatusChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.status.Status;\nimport org.apache.dubbo.common.status.StatusChecker;\n\npublic class MockStatusChecker implements StatusChecker {\n    @Override\n    public Status check() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockTelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\n\npublic class MockTelnetHandler implements TelnetHandler {\n    @Override\n    public String telnet(Channel channel, String message) throws RemotingException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockThreadPool.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\n\nimport java.util.concurrent.Executor;\n\npublic class MockThreadPool implements ThreadPool {\n    @Override\n    public Executor getExecutor(URL url) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockTransporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Client;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.RemotingServer;\nimport org.apache.dubbo.remoting.Transporter;\n\nimport org.mockito.Mockito;\n\npublic class MockTransporter implements Transporter {\n    private RemotingServer server = Mockito.mock(RemotingServer.class);\n    private Client client = Mockito.mock(Client.class);\n\n    @Override\n    public RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException {\n        return server;\n    }\n\n    @Override\n    public Client connect(URL url, ChannelHandler handler) throws RemotingException {\n        return client;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/TestProxyFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.mock;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.proxy.jdk.JdkProxyFactory;\n\npublic class TestProxyFactory extends JdkProxyFactory {\n    public static int count = 0;\n\n    @Override\n    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {\n        count++;\n        return super.getInvoker(proxy, type, url);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/nested/AggregationConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass AggregationConfigTest {\n\n    @Test\n    void testEnabled() {\n        AggregationConfig aggregationConfig = new AggregationConfig();\n        aggregationConfig.setEnabled(true);\n        assertThat(aggregationConfig.getEnabled(), equalTo(true));\n    }\n\n    @Test\n    void testBucketNum() {\n        AggregationConfig aggregationConfig = new AggregationConfig();\n        aggregationConfig.setBucketNum(5);\n        assertThat(aggregationConfig.getBucketNum(), equalTo(5));\n    }\n\n    @Test\n    void testTimeWindowSeconds() {\n        AggregationConfig aggregationConfig = new AggregationConfig();\n        aggregationConfig.setTimeWindowSeconds(120);\n        assertThat(aggregationConfig.getTimeWindowSeconds(), equalTo(120));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/nested/PrometheusConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.nested;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass PrometheusConfigTest {\n\n    @Test\n    void testExporter() {\n        PrometheusConfig prometheusConfig = new PrometheusConfig();\n        PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();\n\n        exporter.setEnabled(true);\n        exporter.setEnableHttpServiceDiscovery(true);\n        exporter.setHttpServiceDiscoveryUrl(\"localhost:8080\");\n        prometheusConfig.setExporter(exporter);\n\n        assertThat(prometheusConfig.getExporter().getEnabled(), equalTo(true));\n        assertThat(prometheusConfig.getExporter().getEnableHttpServiceDiscovery(), equalTo(true));\n        assertThat(prometheusConfig.getExporter().getHttpServiceDiscoveryUrl(), equalTo(\"localhost:8080\"));\n    }\n\n    @Test\n    void testPushgateway() {\n        PrometheusConfig prometheusConfig = new PrometheusConfig();\n        PrometheusConfig.Pushgateway pushgateway = new PrometheusConfig.Pushgateway();\n\n        pushgateway.setEnabled(true);\n        pushgateway.setBaseUrl(\"localhost:9091\");\n        pushgateway.setUsername(\"username\");\n        pushgateway.setPassword(\"password\");\n        pushgateway.setJob(\"job\");\n        pushgateway.setPushInterval(30);\n        prometheusConfig.setPushgateway(pushgateway);\n\n        assertThat(prometheusConfig.getPushgateway().getEnabled(), equalTo(true));\n        assertThat(prometheusConfig.getPushgateway().getBaseUrl(), equalTo(\"localhost:9091\"));\n        assertThat(prometheusConfig.getPushgateway().getUsername(), equalTo(\"username\"));\n        assertThat(prometheusConfig.getPushgateway().getPassword(), equalTo(\"password\"));\n        assertThat(prometheusConfig.getPushgateway().getJob(), equalTo(\"job\"));\n        assertThat(prometheusConfig.getPushgateway().getPushInterval(), equalTo(30));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/provider/impl/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.provider.impl;\n\nimport org.apache.dubbo.config.api.Box;\nimport org.apache.dubbo.config.api.DemoException;\nimport org.apache.dubbo.config.api.DemoService;\nimport org.apache.dubbo.config.api.User;\n\nimport java.util.List;\n\npublic class DemoServiceImpl implements DemoService {\n\n    public String sayName(String name) {\n        return \"say:\" + name;\n    }\n\n    public Box getBox() {\n        return null;\n    }\n\n    public void throwDemoException() throws DemoException {\n        throw new DemoException(\"DemoServiceImpl\");\n    }\n\n    public List<User> getUsers(List<User> users) {\n        return users;\n    }\n\n    public int echo(int i) {\n        return i;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.url;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.SysProps;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLDecoder;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass ExporterSideConfigUrlTest extends UrlTestBase {\n\n    private static final Logger log = LoggerFactory.getLogger(ExporterSideConfigUrlTest.class);\n\n    // ======================================================\n    //   tests start\n    // ======================================================\n    @BeforeAll\n    public static void start() {}\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n        initServConf();\n    }\n\n    @AfterEach()\n    public void teardown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void exporterMethodConfigUrlTest() {\n        verifyExporterUrlGeneration(methodConfForService, methodConfForServiceTable);\n    }\n\n    @Test\n    void exporterServiceConfigUrlTest() {\n        verifyExporterUrlGeneration(servConf, servConfTable);\n    }\n\n    @Test\n    void exporterProviderConfigUrlTest() {\n\n        verifyExporterUrlGeneration(provConf, provConfTable);\n    }\n\n    @Test\n    void exporterRegistryConfigUrlTest() {\n\n        // verifyExporterUrlGeneration(regConfForService, regConfForServiceTable);\n    }\n\n    protected <T> void verifyExporterUrlGeneration(T config, Object[][] dataTable) {\n\n        // 1. fill corresponding config with data\n        ////////////////////////////////////////////////////////////\n        fillConfigs(config, dataTable, TESTVALUE1);\n\n        // 2. export service and get url parameter string from db\n        ////////////////////////////////////////////////////////////\n        servConf.export();\n        String paramStringFromDb = getProviderParamString();\n        try {\n            paramStringFromDb = URLDecoder.decode(paramStringFromDb, \"UTF-8\");\n        } catch (UnsupportedEncodingException e) {\n            // impossible\n        }\n\n        assertUrlStringWithLocalTable(\n                paramStringFromDb, dataTable, config.getClass().getName(), TESTVALUE1);\n\n        // 4. unexport service\n        ////////////////////////////////////////////////////////////\n        servConf.unexport();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.url;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.api.DemoService;\nimport org.apache.dubbo.config.mock.MockRegistry;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;\n\n@Disabled\nclass InvokerSideConfigUrlTest extends UrlTestBase {\n    private static final Logger log = LoggerFactory.getLogger(InvokerSideConfigUrlTest.class);\n\n    // ======================================================\n    //   invoker related data preparing\n    // ======================================================\n    private RegistryConfig regConfForConsumer;\n    private RegistryConfig regConfForReference;\n    private MethodConfig methodConfForReference;\n    private ConsumerConfig consumerConf;\n    private ReferenceConfig<DemoService> refConf;\n\n    private Object appConfForConsumerTable[][] = {\n        {\"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n    };\n\n    private Object appConfForReferenceTable[][] = {\n        {\"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n    };\n\n    private Object regConfForConsumerTable[][] = {\n        //            {\"timeout\", \"registry.timeout\", \"int\", 5000, 9000, \"\", \"\", \"\", \"\", \"\"},\n        //            {\"file\", \"registry.file\", \"string\", \"\", \"regConfForServiceTable.log\", \"\", \"\", \"\", \"\", \"\"},\n        //            {\"wait\", \"registry.wait\", \"int\", 0, 9000, \"\", \"\", \"\", \"\", \"\"},\n        //            {\"transport\", \"registry.transporter\", \"string\", \"netty\", \"mina\", \"\", \"\", \"\", \"\", \"\"},\n        {\"subscribe\", \"subscribe\", \"boolean\", true, false, \"\", \"\", \"\", \"\", \"\"},\n        {\"dynamic\", \"dynamic\", \"boolean\", true, false, \"\", \"\", \"\", \"\", \"\"},\n    };\n\n    private Object regConfForReferenceTable[][] = {\n        {\"timeout\", \"registry.timeout\", \"int\", 5000, 9000, \"\", \"\", \"\", \"\", \"\"},\n        {\"file\", \"registry.file\", \"string\", \"\", \"regConfForServiceTable.log\", \"\", \"\", \"\", \"\", \"\"},\n        {\"wait\", \"registry.wait\", \"int\", 0, 9000, \"\", \"\", \"\", \"\", \"\"},\n        {\"transport\", \"registry.transporter\", \"string\", \"netty\", \"mina\", \"\", \"\", \"\", \"\", \"\"},\n        {\"subscribe\", \"subscribe\", \"boolean\", true, false, \"\", \"\", \"\", \"\", \"\"},\n        {\"dynamic\", \"dynamic\", \"boolean\", true, false, \"\", \"\", \"\", \"\", \"\"},\n    };\n\n    private Object methodConfForReferenceTable[][] = {\n        {\"actives\", \"eatTiger.actives\", \"int\", 0, 90, \"\", \"\", \"\", \"\", \"\"},\n        {\"executes\", \"eatTiger.executes\", \"int\", 0, 90, \"\", \"\", \"\", \"\", \"\"},\n        {\"deprecated\", \"eatTiger.deprecated\", \"boolean\", false, true, \"\", \"\", \"\", \"\", \"\"},\n        {\"async\", \"eatTiger.async\", \"boolean\", false, true, \"\", \"\", \"\", \"\", \"\"},\n        {\"timeout\", \"eatTiger.timeout\", \"int\", 0, 90, \"\", \"\", \"\", \"\", \"\"},\n    };\n\n    private Object refConfTable[][] = {\n        //            {\"version\", \"version\", \"string\", \"0.0.0\", \"1.2.3\", \"\", \"\", \"\", \"\", \"\"},\n        //            {\"group\", \"group\", \"string\", \"\", \"HaominTest\", \"\", \"\", \"\", \"\", \"\"},\n\n        //            {\"delay\", \"delay\", \"int\", 0, 5, \"\", \"\", \"\", \"\", \"\"}, // not boolean\n        {\"timeout\", \"timeout\", \"int\", 5000, 3000, \"\", \"\", \"\", \"\", \"\"},\n        {\"retries\", \"retries\", \"int\", 2, 5, \"\", \"\", \"\", \"\", \"\"},\n        {\"connections\", \"connections\", \"boolean\", 100, 20, \"\", \"\", \"\", \"\", \"\"},\n        {\"loadbalance\", \"loadbalance\", \"string\", \"random\", \"roundrobin\", \"leastactive\", \"\", \"\", \"\"},\n        {\"async\", \"async\", \"boolean\", false, true, \"\", \"\", \"\", \"\", \"\"},\n        // excluded = true\n        //            {\"generic\", \"generic\", \"boolean\", false, true, \"\", \"\", \"\", \"\", \"\"},\n        {\"check\", \"check\", \"boolean\", false, true, \"\", \"\", \"\", \"\", \"\"},\n        // {\"local\", \"local\", \"string\", \"false\", \"HelloServiceLocal\", \"true\", \"\", \"\", \"\", \"\"},\n        // {\"local\", \"local\", \"string\", \"false\", \"true\", \"\", \"\", \"\", \"\", \"\"},\n        // {\"mock\", \"mock\", \"string\", \"false\", \"dubbo.test.HelloServiceMock\", \"true\", \"\", \"\", \"\", \"\"},\n        {\"mock\", \"mock\", \"string\", \"false\", \"false\", \"\", \"\", \"\", \"\", \"\"},\n        {\"proxy\", \"proxy\", \"boolean\", \"javassist\", \"jdk\", \"\", \"\", \"\", \"\", \"\"},\n        {\"client\", \"client\", \"string\", \"netty\", \"mina\", \"\", \"\", \"\", \"\", \"\"},\n        {\"client\", \"client\", \"string\", \"netty\", \"mina\", \"\", \"\", \"\", \"\", \"\"},\n        {\"owner\", \"owner\", \"string\", \"\", \"haomin,ludvik\", \"\", \"\", \"\", \"\", \"\"},\n        {\"actives\", \"actives\", \"int\", 0, 30, \"\", \"\", \"\", \"\", \"\"},\n        {\"cluster\", \"cluster\", \"string\", \"failover\", \"failfast\", \"failsafe\", \"failback\", \"forking\", \"\", \"\"},\n        // excluded = true\n        //            {\"filter\", \"service.filter\", \"string\", \"default\", \"-generic\", \"\", \"\", \"\", \"\", \"\"},\n        // excluded = true\n        //            {\"listener\", \"exporter.listener\", \"string\", \"default\", \"-deprecated\", \"\", \"\", \"\", \"\", \"\"},\n        // {\"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n    };\n\n    private Object consumerConfTable[][] = {\n        {\"timeout\", \"timeout\", \"int\", 5000, 8000, \"\", \"\", \"\", \"\", \"\"},\n        {\"retries\", \"retries\", \"int\", 2, 5, \"\", \"\", \"\", \"\", \"\"},\n        {\"loadbalance\", \"loadbalance\", \"string\", \"random\", \"leastactive\", \"\", \"\", \"\", \"\", \"\"},\n        {\"async\", \"async\", \"boolean\", false, true, \"\", \"\", \"\", \"\", \"\"},\n        {\"connections\", \"connections\", \"int\", 100, 5, \"\", \"\", \"\", \"\", \"\"},\n        //            {\"generic\", \"generic\", \"boolean\", false, false, \"\", \"\", \"\", \"\", \"\"},\n        {\"check\", \"check\", \"boolean\", true, false, \"\", \"\", \"\", \"\", \"\"},\n        {\"proxy\", \"proxy\", \"string\", \"javassist\", \"jdk\", \"javassist\", \"\", \"\", \"\", \"\"},\n        {\"owner\", \"owner\", \"string\", \"\", \"haomin\", \"\", \"\", \"\", \"\", \"\"},\n        {\"actives\", \"actives\", \"int\", 0, 5, \"\", \"\", \"\", \"\", \"\"},\n        {\"cluster\", \"cluster\", \"string\", \"failover\", \"forking\", \"\", \"\", \"\", \"\", \"\"},\n        {\"filter\", \"\", \"string\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n        {\"listener\", \"\", \"string\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n        //            {\"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n    };\n\n    // ======================================================\n    //   test Start\n    // ======================================================\n\n    @BeforeAll\n    public static void start() {\n        // RegistryController.startRegistryIfAbsence(1);\n    }\n\n    @BeforeEach\n    public void setUp() {\n        initServConf();\n        initRefConf();\n        //        ApplicationModel.defaultModel().getConfigManager().clear();\n    }\n\n    @AfterEach()\n    public void teardown() {\n        // RegistryServer.reloadCache();\n        //        ApplicationModel.defaultModel().getConfigManager().clear();\n    }\n\n    @Test\n    void consumerConfUrlTest() {\n        verifyInvokerUrlGeneration(consumerConf, consumerConfTable);\n    }\n\n    @Test\n    void refConfUrlTest() {\n        verifyInvokerUrlGeneration(refConf, refConfTable);\n    }\n\n    @Disabled(\n            \"parameter on register center will not be merged any longer with query parameter request from the consumer\")\n    @Test\n    void regConfForConsumerUrlTest() {\n        verifyInvokerUrlGeneration(regConfForConsumer, regConfForConsumerTable);\n    }\n\n    // ======================================================\n    //   private helper\n    // ======================================================\n    private void initRefConf() {\n        regConfForConsumer = new RegistryConfig();\n        regConfForReference = new RegistryConfig();\n        methodConfForReference = new MethodConfig();\n\n        refConf = new ReferenceConfig<DemoService>();\n        consumerConf = new ConsumerConfig();\n\n        methodConfForReference.setName(\"sayName\");\n        regConfForReference.setAddress(\"127.0.0.1:9090\");\n        regConfForReference.setProtocol(\"mockregistry\");\n        refConf.setInterface(\"org.apache.dubbo.config.api.DemoService\");\n\n        refConf.setApplication(application);\n        //        consumerConf.setApplication(appConfForConsumer);\n\n        refConf.setRegistry(regConfForReference);\n        consumerConf.setRegistry(regConfForConsumer);\n\n        refConf.setConsumer(consumerConf);\n\n        refConf.setMethods(Arrays.asList(new MethodConfig[] {methodConfForReference}));\n\n        refConf.setScope(SCOPE_REMOTE);\n    }\n\n    private <T> void verifyInvokerUrlGeneration(T config, Object[][] dataTable) {\n        servConf.export();\n\n        fillConfigs(config, dataTable, TESTVALUE1);\n        refConf.get();\n\n        String subScribedUrlStr = getSubscribedUrlString();\n\n        String configName = config.getClass().getName();\n        int column = TESTVALUE1;\n\n        assertUrlStringWithLocalTable(subScribedUrlStr, dataTable, configName, column);\n\n        try {\n            refConf.destroy();\n        } catch (Exception e) {\n        }\n    }\n\n    private String getSubscribedUrlString() {\n        return MockRegistry.getSubscribedUrl().toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/RpcConfigGetSetProxy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.url;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.AbstractConfig;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\npublic class RpcConfigGetSetProxy {\n\n    private static final String RPC_CONFIG_BASECLASS = AbstractConfig.class.getName();\n    private static final Logger log = LoggerFactory.getLogger(RpcConfigGetSetProxy.class);\n\n    private Object proxiee = null;\n    private Class<?> proxieeClass = null;\n    private Boolean isOk = false;\n\n    public RpcConfigGetSetProxy(Object p) {\n\n        if (p == null) {\n            return;\n        }\n\n        if (!isKindOf(p.getClass(), RPC_CONFIG_BASECLASS)) {\n            return;\n        }\n\n        proxiee = p;\n        // proxieeClass = c;\n        proxieeClass = p.getClass();\n        isOk = true;\n    }\n\n    public static boolean isKindOf(Class<?> c, String type) {\n\n        // get the class def for obj and type\n\n        Class<?> tClass;\n        try {\n            tClass = Class.forName(type);\n        } catch (ClassNotFoundException e) {\n            return false;\n        }\n\n        // check against type and superclasses\n        while (c != null) {\n            if (c == tClass) return true;\n            c = c.getSuperclass();\n        }\n\n        return false;\n    }\n\n    public boolean isOk() {\n        return isOk;\n    }\n\n    public Object setValue(String key, Object value) {\n\n        if (!isOk()) {\n            return null;\n        }\n\n        Method m = findSetMethod(key, value, proxieeClass);\n        return invoke(m, value);\n    }\n\n    public Object getValue(String key) {\n\n        if (!isOk()) {\n            return null;\n        }\n\n        Method m = findGetMethod(key, proxieeClass);\n        return invoke(m, null);\n    }\n\n    private Object invoke(Method m, Object value) {\n\n        if (m == null) {\n            return null;\n        }\n\n        try {\n            if (value == null) {\n                return m.invoke(proxiee, (Object[]) null);\n            } else {\n                return m.invoke(proxiee, value);\n            }\n        } catch (IllegalArgumentException e) {\n            log.error(\"IllegalArgumentException\", e);\n            return null;\n        } catch (IllegalAccessException e) {\n            log.error(\"IllegalAccessException\", e);\n            return null;\n        } catch (InvocationTargetException e) {\n            log.error(\"InvocationTargetException\", e);\n            return null;\n        }\n    }\n\n    private Method findGetMethod(String key, Class<?> clazz) {\n\n        Method m = findMethod(key, null, \"get\", clazz);\n        if (m != null) {\n            return m;\n        }\n\n        return findMethod(key, null, \"is\", clazz);\n    }\n\n    private Method findSetMethod(String key, Object value, Class<?> clazz) {\n\n        return findMethod(key, value, \"set\", clazz);\n    }\n\n    private Method getMethod(String methodName, Object value, Class<?> clazz) {\n\n        try {\n            if (value == null) {\n                return clazz.getMethod(methodName, (Class<?>[]) null);\n            } else {\n                return clazz.getMethod(methodName, value.getClass());\n            }\n        } catch (SecurityException e) {\n            log.error(\"SecurityException: \" + e.getMessage());\n            return null;\n        } catch (NoSuchMethodException e) {\n            log.error(\"NoSuchMethodException: \" + e.getMessage());\n            return null;\n        }\n    }\n\n    private Method findMethod(String key, Object value, String prefix, Class<?> clazz) {\n\n        if (key.length() < 2) {\n            return null;\n        }\n\n        key = key.substring(0, 1).toUpperCase() + key.substring(1);\n        String methodName = prefix + key;\n\n        return getMethod(methodName, value, clazz);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/UrlTestBase.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.url;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.api.DemoService;\nimport org.apache.dubbo.config.provider.impl.DemoServiceImpl;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\nimport static org.junit.jupiter.api.Assertions.fail;\n\n@SuppressWarnings(\"unused\")\npublic class UrlTestBase {\n\n    // ======================================================\n    //   data column definition\n    // ======================================================\n    protected static final int KEY = 0;\n    protected static final int URL_KEY = 1;\n    protected static final int TESTVALUE1 = 4;\n    private static final Logger log = LoggerFactory.getLogger(UrlTestBase.class);\n    private static final int TYPE = 2;\n    private static final int DEFAULT = 3;\n    private static final int TESTVALUE2 = 5;\n    private static final int TESTVALUE3 = 6;\n    private static final int TESTVALUE4 = 7;\n    private static final int TESTVALUE5 = 8;\n    private static final int TESTVALUE6 = 9;\n    private static final int TESTVALUE7 = 10;\n    protected ApplicationConfig application;\n    protected RegistryConfig regConfForProvider;\n    protected RegistryConfig regConfForService;\n    protected ProviderConfig provConf;\n    protected ProtocolConfig protoConfForProvider;\n    protected ProtocolConfig protoConfForService;\n    protected MethodConfig methodConfForService;\n    protected ServiceConfig<DemoService> servConf;\n    protected Object servConfTable[][] = {\n        {\"proxy\", \"proxy\", \"string\", \"javassist\", \"jdk\", \"javassist\", \"\", \"\", \"\", \"\"},\n        {\"actives\", \"actives\", \"int\", 0, 90, \"\", \"\", \"\", \"\", \"\"},\n        {\"executes\", \"executes\", \"int\", 0, 90, \"\", \"\", \"\", \"\", \"\"},\n        {\"deprecated\", \"deprecated\", \"boolean\", false, true, \"\", \"\", \"\", \"\", \"\"},\n        {\"dynamic\", \"dynamic\", \"boolean\", true, false, \"\", \"\", \"\", \"\", \"\"},\n        {\"accesslog\", \"accesslog\", \"string\", \"\", \"haominTest\", \"\", \"\", \"\", \"\", \"\"},\n        {\n            \"document\",\n            \"document\",\n            \"string\",\n            \"\",\n            \"http://dubbo.apache.org/zh-cn/docs/user/quick-start.html?testquery=你好你好\",\n            \"\",\n            \"\",\n            \"\",\n            \"\",\n            \"\"\n        },\n        {\"weight\", \"weight\", \"int\", 0, 90, \"\", \"\", \"\", \"\", \"\"},\n\n        // {\"filter\", \"service.filter\", \"string\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n        // {\"listener\", \"listener\", \"string\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n\n    };\n    protected Object regConfForServiceTable[][] = {\n        //            {\"timeout\", \"registry.timeout\", \"int\", 5000, 9000, \"\", \"\", \"\", \"\", \"\"},\n        //            {\"file\", \"registry.file\", \"string\", \"\", \"regConfForServiceTable.log\", \"\", \"\", \"\", \"\", \"\"},\n        //            {\"wait\", \"registry.wait\", \"int\", 0, 9000, \"\", \"\", \"\", \"\", \"\"},\n        //            {\"transport\", \"registry.transporter\", \"string\", \"netty\", \"mina\", \"\", \"\", \"\", \"\", \"\"},\n        //            {\"subscribe\", \"subscribe\", \"boolean\", true, false, \"\", \"\", \"\", \"\", \"\"},\n        {\"dynamic\", \"dynamic\", \"boolean\", true, false, \"\", \"\", \"\", \"\", \"\"},\n    };\n    protected Object provConfTable[][] = {\n        {\"cluster\", \"cluster\", \"string\", \"string\", \"failover\", \"failfast\", \"failsafe\", \"\", \"\", \"\"},\n        {\"async\", \"async\", \"boolean\", false, true, \"\", \"\", \"\", \"\", \"\"},\n        {\"loadbalance\", \"loadbalance\", \"string\", \"random\", \"leastactive\", \"\", \"\", \"\", \"\", \"\"},\n        {\"connections\", \"connections\", \"int\", 0, 60, \"\", \"\", \"\", \"\", \"\"},\n        {\"retries\", \"retries\", \"int\", 2, 60, \"\", \"\", \"\", \"\", \"\"},\n        {\"timeout\", \"timeout\", \"int\", 5000, 60, \"\", \"\", \"\", \"\", \"\"},\n        // change by fengting listener 没有缺省值\n        // {\"listener\", \"exporter.listener\", \"string\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n        // {\"filter\", \"service.filter\", \"string\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n\n    };\n    protected Object methodConfForServiceTable[][] = {\n        {\"actives\", \"sayName.actives\", \"int\", 0, 90, \"\", \"\", \"\", \"\", \"\"},\n        {\"executes\", \"sayName.executes\", \"int\", 0, 90, \"\", \"\", \"\", \"\", \"\"},\n        {\"deprecated\", \"sayName.deprecated\", \"boolean\", false, true, \"\", \"\", \"\", \"\", \"\"},\n        {\"async\", \"sayName.async\", \"boolean\", false, true, \"\", \"\", \"\", \"\", \"\"},\n        {\"timeout\", \"sayName.timeout\", \"int\", 0, 90, \"\", \"\", \"\", \"\", \"\"},\n    };\n    protected DemoService demoService = new DemoServiceImpl();\n    private Object appConfForProviderTable[][] = {\n        {\"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n    };\n    private Object appConfForServiceTable[][] = {\n        {\"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n    };\n    private Object regConfForProviderTable[][] = {\n        {\"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n    };\n    private Object protoConfForProviderTable[][] = {\n        {\"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n    };\n    private Object protoConfForServiceTable[][] = {\n        {\"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"},\n    };\n\n    // ======================================================\n    //   data table manipulation utils\n    // ======================================================\n    protected String genParamString(Object urlKey, Object value) {\n\n        return (String) urlKey + \"=\" + value.toString();\n    }\n\n    protected <T> void fillConfigs(T conf, Object[][] table, int column) {\n\n        for (Object[] row : table) {\n            fillConfig(conf, row, column);\n        }\n    }\n\n    protected <T> void fillConfig(T conf, Object[] row, int column) {\n\n        RpcConfigGetSetProxy proxy = new RpcConfigGetSetProxy(conf);\n        proxy.setValue((String) row[KEY], row[column]);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    protected void initServConf() {\n        regConfForProvider = new RegistryConfig();\n        regConfForService = new RegistryConfig();\n        provConf = new ProviderConfig();\n        protoConfForProvider = new ProtocolConfig(\"mockprotocol\");\n        protoConfForService = new ProtocolConfig(\"mockprotocol\");\n        methodConfForService = new MethodConfig();\n        servConf = new ServiceConfig<DemoService>();\n\n        //        provConf.setApplication(appConfForProvider);\n        application = new ApplicationConfig();\n        application.setMetadataServicePort(20881);\n        servConf.setApplication(application);\n\n        provConf.setRegistry(regConfForProvider);\n        servConf.setRegistry(regConfForService);\n\n        provConf.setProtocols(new ArrayList<>(Arrays.asList(protoConfForProvider)));\n        servConf.setProtocols(new ArrayList<>(Arrays.asList(protoConfForService)));\n\n        servConf.setMethods(Arrays.asList(new MethodConfig[] {methodConfForService}));\n        servConf.setProvider(provConf);\n\n        servConf.setRef(demoService);\n        servConf.setInterface(DemoService.class);\n\n        methodConfForService.setName(\"sayName\");\n        regConfForService.setAddress(\"127.0.0.1:9090\");\n        regConfForService.setProtocol(\"mockregistry\");\n        application.setName(\"ConfigTests\");\n    }\n\n    protected String getProviderParamString() {\n        return servConf.getExportedUrls().get(0).toString();\n    }\n\n    /**\n     * @param paramStringFromDb\n     * @param dataTable\n     * @param configName\n     * @param column\n     */\n    protected void assertUrlStringWithLocalTable(\n            String paramStringFromDb, Object[][] dataTable, String configName, int column) {\n        final String FAILLOG_HEADER = \"The following config items are not found in URLONE: \";\n\n        log.warn(\"Verifying service url for \" + configName + \"... \");\n        log.warn(\"Consumer url string: \" + paramStringFromDb);\n\n        String failLog = FAILLOG_HEADER;\n        for (Object[] row : dataTable) {\n\n            String targetString = genParamString(row[URL_KEY], row[column]);\n\n            log.warn(\"Checking \" + (String) row[KEY] + \"for\" + targetString);\n            if (paramStringFromDb.contains(targetString)) {\n                log.warn((String) row[KEY] + \" --> \" + targetString + \" OK!\");\n            } else {\n                failLog += targetString + \", \";\n            }\n        }\n\n        if (!failLog.equals(FAILLOG_HEADER)) {\n            fail(failLog);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ConfigValidationUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.config.AbstractInterfaceConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nclass ConfigValidationUtilsTest {\n\n    @Test\n    void testValidateMetadataConfig() {\n        MetadataReportConfig config = new MetadataReportConfig();\n        config.setAddress(\"protocol://ip:host\");\n        try {\n            ConfigValidationUtils.validateMetadataConfig(config);\n        } catch (Exception e) {\n            Assertions.fail(\"valid config expected.\");\n        }\n\n        config.setAddress(\"ip:host\");\n        config.setProtocol(\"protocol\");\n        try {\n            ConfigValidationUtils.validateMetadataConfig(config);\n        } catch (Exception e) {\n            Assertions.fail(\"valid config expected.\");\n        }\n\n        config.setAddress(\"ip:host\");\n        config.setProtocol(null);\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            ConfigValidationUtils.validateMetadataConfig(config);\n        });\n    }\n\n    @Test\n    void testValidateApplicationConfig() throws Exception {\n        try (MockedStatic<ConfigValidationUtils> mockedStatic = Mockito.mockStatic(ConfigValidationUtils.class); ) {\n            mockedStatic\n                    .when(() -> ConfigValidationUtils.validateApplicationConfig(any()))\n                    .thenCallRealMethod();\n            ApplicationConfig config = new ApplicationConfig();\n            Assertions.assertThrows(IllegalStateException.class, () -> {\n                ConfigValidationUtils.validateApplicationConfig(config);\n            });\n\n            config.setName(\"testName\");\n            config.setOwner(\"testOwner\");\n            config.setOrganization(\"testOrg\");\n            config.setArchitecture(\"testArchitecture\");\n            config.setEnvironment(\"test\");\n            Map<String, String> map = new HashMap();\n            map.put(\"k1\", \"v1\");\n            map.put(\"k2\", \"v2\");\n            config.setParameters(map);\n            ConfigValidationUtils.validateApplicationConfig(config);\n            mockedStatic.verify(\n                    () -> {\n                        ConfigValidationUtils.checkName(any(), any());\n                    },\n                    times(4));\n            mockedStatic.verify(\n                    () -> {\n                        ConfigValidationUtils.checkMultiName(any(), any());\n                    },\n                    times(1));\n            mockedStatic.verify(\n                    () -> {\n                        ConfigValidationUtils.checkParameterName(any());\n                    },\n                    times(1));\n        }\n    }\n\n    @Test\n    void testCheckQosInApplicationConfig() throws Exception {\n        ConfigValidationUtils mock = Mockito.mock(ConfigValidationUtils.class);\n        ErrorTypeAwareLogger loggerMock = Mockito.mock(ErrorTypeAwareLogger.class);\n        injectField(mock.getClass().getDeclaredField(\"logger\"), loggerMock);\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"testName\");\n        config.setQosEnable(false);\n        mock.validateApplicationConfig(config);\n        verify(loggerMock, never()).warn(any(), any(Throwable.class));\n\n        config.setQosEnable(true);\n        mock.validateApplicationConfig(config);\n        verify(loggerMock).info(anyString());\n    }\n\n    private void injectField(Field field, Object newValue) throws Exception {\n        field.setAccessible(true);\n        field.set(null, newValue);\n    }\n\n    public static class InterfaceConfig extends AbstractInterfaceConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/MockReferenceConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils;\n\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.utils.service.FooService;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic class MockReferenceConfig extends ReferenceConfig<FooService> {\n    static AtomicLong counter = new AtomicLong();\n\n    FooService value;\n    boolean destroyMethodRun = false;\n\n    public static void setCounter(long c) {\n        counter.set(c);\n    }\n\n    public boolean isGetMethodRun() {\n        return value != null;\n    }\n\n    public boolean isDestroyMethodRun() {\n        return destroyMethodRun;\n    }\n\n    @Override\n    public synchronized FooService get(boolean check) {\n        if (value != null) return value;\n\n        counter.getAndIncrement();\n        value = super.get(check);\n        return value;\n    }\n\n    public long getCounter() {\n        return counter.get();\n    }\n\n    @Override\n    public synchronized void destroy() {\n        super.destroy();\n        destroyMethodRun = true;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ReferenceCacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils;\n\nimport org.apache.dubbo.common.config.ReferenceCache;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.SysProps;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.utils.service.FooService;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ReferenceCacheTest {\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n        MockReferenceConfig.setCounter(0);\n        XxxMockReferenceConfig.setCounter(0);\n        SimpleReferenceCache.CACHE_HOLDER.clear();\n    }\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SimpleReferenceCache.CACHE_HOLDER.clear();\n    }\n\n    @Test\n    void testGetCacheSameReference() throws Exception {\n        ReferenceCache cache = SimpleReferenceCache.getCache();\n        MockReferenceConfig config =\n                buildMockReferenceConfig(\"org.apache.dubbo.config.utils.service.FooService\", \"group1\", \"1.0.0\");\n        assertEquals(0L, config.getCounter());\n        Object proxy = cache.get(config);\n        assertTrue(config.isGetMethodRun());\n\n        // singleton reference config by default\n        MockReferenceConfig configCopy =\n                buildMockReferenceConfig(\"org.apache.dubbo.config.utils.service.FooService\", \"group1\", \"1.0.0\");\n        assertEquals(1L, configCopy.getCounter());\n        Object proxyOfCopyConfig = cache.get(configCopy);\n        assertFalse(configCopy.isGetMethodRun());\n\n        assertEquals(1L, config.getCounter());\n        assertEquals(1L, configCopy.getCounter());\n        assertEquals(proxy, proxyOfCopyConfig);\n    }\n\n    @Test\n    void testGetCacheDiffReference() throws Exception {\n        ReferenceCache cache = SimpleReferenceCache.getCache();\n        MockReferenceConfig config =\n                buildMockReferenceConfig(\"org.apache.dubbo.config.utils.service.FooService\", \"group1\", \"1.0.0\");\n        assertEquals(0L, config.getCounter());\n        cache.get(config);\n        assertEquals(1L, config.getCounter());\n        assertTrue(config.isGetMethodRun());\n        cache.get(config);\n        assertEquals(1L, config.getCounter());\n\n        XxxMockReferenceConfig configCopy =\n                buildXxxMockReferenceConfig(\"org.apache.dubbo.config.utils.service.XxxService\", \"group1\", \"1.0.0\");\n        assertEquals(0L, configCopy.getCounter());\n        cache.get(configCopy);\n        assertTrue(configCopy.isGetMethodRun());\n        assertEquals(1L, configCopy.getCounter());\n    }\n\n    @Test\n    void testGetCacheWithKey() throws Exception {\n        ReferenceCache cache = SimpleReferenceCache.getCache();\n        MockReferenceConfig config =\n                buildMockReferenceConfig(\"org.apache.dubbo.config.utils.service.FooService\", \"group1\", \"1.0.0\");\n        FooService value = cache.get(config);\n        assertEquals(\n                value, cache.get(\"group1/org.apache.dubbo.config.utils.service.FooService:1.0.0\", FooService.class));\n    }\n\n    @Test\n    void testGetCacheDiffName() throws Exception {\n        SimpleReferenceCache cache = SimpleReferenceCache.getCache();\n        MockReferenceConfig config =\n                buildMockReferenceConfig(\"org.apache.dubbo.config.utils.service.FooService\", \"group1\", \"1.0.0\");\n        assertEquals(0L, config.getCounter());\n        cache.get(config);\n        assertTrue(config.isGetMethodRun());\n        assertEquals(1L, config.getCounter());\n\n        cache = SimpleReferenceCache.getCache(\"foo\");\n        config = buildMockReferenceConfig(\"org.apache.dubbo.config.utils.service.FooService\", \"group1\", \"1.0.0\");\n        assertEquals(1L, config.getCounter());\n        cache.get(config);\n        // still init for the same ReferenceConfig if the cache is different\n        assertTrue(config.isGetMethodRun());\n        assertEquals(2L, config.getCounter());\n    }\n\n    @Test\n    void testDestroy() throws Exception {\n        SimpleReferenceCache cache = SimpleReferenceCache.getCache();\n        MockReferenceConfig config =\n                buildMockReferenceConfig(\"org.apache.dubbo.config.utils.service.FooService\", \"group1\", \"1.0.0\");\n        cache.get(config);\n        XxxMockReferenceConfig configCopy =\n                buildXxxMockReferenceConfig(\"org.apache.dubbo.config.utils.service.XxxService\", \"group1\", \"1.0.0\");\n        cache.get(configCopy);\n        assertEquals(2, cache.getReferenceMap().size());\n        cache.destroy(config);\n        assertTrue(config.isDestroyMethodRun());\n        assertEquals(1, cache.getReferenceMap().size());\n        cache.destroy(configCopy);\n        assertTrue(configCopy.isDestroyMethodRun());\n        assertEquals(0, cache.getReferenceMap().size());\n    }\n\n    @Test\n    void testDestroyAll() throws Exception {\n        SimpleReferenceCache cache = SimpleReferenceCache.getCache();\n        MockReferenceConfig config =\n                buildMockReferenceConfig(\"org.apache.dubbo.config.utils.service.FooService\", \"group1\", \"1.0.0\");\n        cache.get(config);\n        XxxMockReferenceConfig configCopy =\n                buildXxxMockReferenceConfig(\"org.apache.dubbo.config.utils.service.XxxService\", \"group1\", \"1.0.0\");\n        cache.get(configCopy);\n        assertEquals(2, cache.getReferenceMap().size());\n        cache.destroyAll();\n        assertTrue(config.isDestroyMethodRun());\n        assertTrue(configCopy.isDestroyMethodRun());\n        assertEquals(0, cache.getReferenceMap().size());\n    }\n\n    private MockReferenceConfig buildMockReferenceConfig(String service, String group, String version) {\n        MockReferenceConfig config = new MockReferenceConfig();\n        config.setApplication(new ApplicationConfig(\"cache\"));\n        config.setRegistry(new RegistryConfig(\"multicast://224.5.6.7:1234\"));\n        config.setCheck(false);\n        config.setInterface(service);\n        config.setGroup(group);\n        config.setVersion(version);\n        return config;\n    }\n\n    private XxxMockReferenceConfig buildXxxMockReferenceConfig(String service, String group, String version) {\n        XxxMockReferenceConfig config = new XxxMockReferenceConfig();\n        config.setApplication(new ApplicationConfig(\"cache\"));\n        config.setRegistry(new RegistryConfig(\"multicast://224.5.6.7:1234\"));\n        config.setInterface(service);\n        config.setCheck(false);\n        config.setGroup(group);\n        config.setVersion(version);\n        return config;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/TestPreferSerializationProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils;\n\nimport org.apache.dubbo.common.serialization.PreferSerializationProvider;\n\npublic class TestPreferSerializationProvider implements PreferSerializationProvider {\n    @Override\n    public String getPreferSerialization() {\n        return \"fastjson2,hessian2\";\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/XxxMockReferenceConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils;\n\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.utils.service.XxxService;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic class XxxMockReferenceConfig extends ReferenceConfig<XxxService> {\n    static AtomicLong counter = new AtomicLong();\n\n    XxxService value;\n    boolean destroyMethodRun = false;\n\n    public static void setCounter(long c) {\n        counter.set(c);\n    }\n\n    public boolean isGetMethodRun() {\n        return value != null;\n    }\n\n    public boolean isDestroyMethodRun() {\n        return destroyMethodRun;\n    }\n\n    @Override\n    public synchronized XxxService get(boolean check) {\n        if (value != null) return value;\n\n        counter.getAndIncrement();\n        value = super.get(check);\n        return value;\n    }\n\n    public long getCounter() {\n        return counter.get();\n    }\n\n    @Override\n    public synchronized void destroy() {\n        super.destroy();\n        destroyMethodRun = true;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/service/FooService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils.service;\n\npublic interface FooService {}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/service/FooServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils.service;\n\npublic class FooServiceImpl implements FooService {}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/service/XxxService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils.service;\n\npublic interface XxxService {}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/service/XxxServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.utils.service;\n\npublic class XxxServiceImpl implements XxxService {}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.common.status.StatusChecker",
    "content": "mockstatuschecker=org.apache.dubbo.config.mock.MockStatusChecker\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.common.threadpool.ThreadPool",
    "content": "mockthreadpool=org.apache.dubbo.config.mock.MockThreadPool\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.config.ServiceListener",
    "content": "mock=org.apache.dubbo.config.mock.MockServiceListener\nexported=org.apache.dubbo.config.integration.single.SingleRegistryCenterExportedServiceListener\nsingleConfigCenterInjvm=org.apache.dubbo.config.integration.single.injvm.SingleRegistryCenterInjvmServiceListener\nmultipleConfigCenterInjvm=org.apache.dubbo.config.integration.multiple.injvm.MultipleRegistryCenterInjvmServiceListener\nsingleConfigCenterExportProvider=org.apache.dubbo.config.integration.single.exportprovider.SingleRegistryCenterExportProviderServiceListener\nsingleConfigCenterExportMetadata=org.apache.dubbo.config.integration.single.exportmetadata.SingleRegistryCenterExportMetadataServiceListener\nmultipleConfigCenterExportMetadata=org.apache.dubbo.config.integration.multiple.exportmetadata.MultipleRegistryCenterExportMetadataServiceListener\nmultipleConfigCenterExportProvider=org.apache.dubbo.config.integration.multiple.exportprovider.MultipleRegistryCenterExportProviderServiceListener\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryFactory",
    "content": "mockregistry=org.apache.dubbo.config.mock.MockRegistryFactory\nmockprotocol2=org.apache.dubbo.config.mock.MockRegistryFactory2\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryServiceListener",
    "content": "multipleConfigCenterServiceDiscoveryRegistry=org.apache.dubbo.config.integration.multiple.servicediscoveryregistry.MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.registry.integration.RegistryProtocolListener",
    "content": "singleConfigCenterExportProvider=org.apache.dubbo.config.integration.single.exportprovider.SingleRegistryCenterExportProviderRegistryProtocolListener\nmultipleConfigCenterExportProvider=org.apache.dubbo.config.integration.multiple.exportprovider.MultipleRegistryCenterExportProviderRegistryProtocolListener\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.remoting.Codec",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nmockcodec=org.apache.dubbo.config.mock.MockCodec"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.remoting.Dispatcher",
    "content": "mockdispatcher=org.apache.dubbo.config.mock.MockDispatcher\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.remoting.Transporter",
    "content": "mocktransporter=org.apache.dubbo.config.mock.MockTransporter\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.remoting.exchange.Exchanger",
    "content": "mockexchanger=org.apache.dubbo.config.mock.MockExchanger\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.remoting.telnet.TelnetHandler",
    "content": "mocktelnethandler=org.apache.dubbo.config.mock.MockTelnetHandler\n\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.ExporterListener",
    "content": "mockexporterlistener=org.apache.dubbo.config.mock.MockExporterListener\nsingleConfigCenterInjvm=org.apache.dubbo.config.integration.single.injvm.SingleRegistryCenterInjvmExporterListener\nmultipleConfigCenterInjvm=org.apache.dubbo.config.integration.multiple.injvm.MultipleRegistryCenterInjvmExporterListener\nsingleConfigCenterExportProvider=org.apache.dubbo.config.integration.single.exportprovider.SingleRegistryCenterExportProviderExporterListener\nsingleConfigCenterExportMetadata=org.apache.dubbo.config.integration.single.exportmetadata.SingleRegistryCenterExportMetadataExporterListener\nmultipleConfigCenterExportMetadata=org.apache.dubbo.config.integration.multiple.exportmetadata.MultipleRegistryCenterExportMetadataExporterListener\nmultipleConfigCenterExportProvider=org.apache.dubbo.config.integration.multiple.exportprovider.MultipleRegistryCenterExportProviderExporterListener\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.Filter",
    "content": "mockfilter=org.apache.dubbo.config.mock.MockFilter\nsingleConfigCenterInjvm=org.apache.dubbo.config.integration.single.injvm.SingleRegistryCenterInjvmFilter\nmultipleConfigCenterInjvm=org.apache.dubbo.config.integration.multiple.injvm.MultipleRegistryCenterInjvmFilter\nsingleConfigCenterExportProvider=org.apache.dubbo.config.integration.single.exportprovider.SingleRegistryCenterExportProviderFilter\nmultipleConfigCenterExportProvider=org.apache.dubbo.config.integration.multiple.exportprovider.MultipleRegistryCenterExportProviderFilter\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.InvokerListener",
    "content": "mockinvokerlistener=org.apache.dubbo.config.mock.MockInvokerListener"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.Protocol",
    "content": "mockprotocol=org.apache.dubbo.config.mock.MockProtocol\nmockprotocol2=org.apache.dubbo.config.mock.MockProtocol2"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.ProxyFactory",
    "content": "mockproxyfactory=org.apache.dubbo.config.mock.MockProxyFactory\ntestproxyfactory=org.apache.dubbo.config.mock.TestProxyFactory"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.cluster.Cluster",
    "content": "mockcluster=org.apache.dubbo.config.mock.MockCluster"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.cluster.LoadBalance",
    "content": "mockloadbalance=org.apache.dubbo.config.mock.MockLoadBalance"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/dubbo.properties",
    "content": "dubbo.override.key2=properties\ndubbo.override.protocol=properties\ndubbo.service.shutdown.wait=200\n"
  },
  {
    "path": "dubbo-config/dubbo-config-api/src/test/resources/security/serialize.allowlist",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\ndemo.\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-config</artifactId>\n    <version>${revision}</version>\n  </parent>\n  <artifactId>dubbo-config-spring</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The spring config module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n    <spring-boot.version>2.7.18</spring-boot.version>\n    <!-- Uncomment spring_version property to check Spring 4.x compatibility -->\n    <!-- <spring_version>4.3.30.RELEASE</spring_version> -->\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-prometheus</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-beans</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-web</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-context</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>javax.servlet</groupId>\n      <artifactId>javax.servlet-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n\n    <!-- Testing Dependencies -->\n    <dependency>\n      <groupId>org.aspectj</groupId>\n      <artifactId>aspectjweaver</artifactId>\n      <version>1.9.25.1</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-dubbo</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-injvm</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-fastjson2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>javax.validation</groupId>\n      <artifactId>validation-api</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.hibernate</groupId>\n      <artifactId>hibernate-validator</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.glassfish</groupId>\n      <artifactId>javax.el</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-tx</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.tomcat.embed</groupId>\n      <artifactId>tomcat-embed-core</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <version>${spring-boot.version}</version>\n      <scope>test</scope>\n      <exclusions>\n        <exclusion>\n          <groupId>ch.qos.logback</groupId>\n          <artifactId>logback-classic</artifactId>\n        </exclusion>\n        <exclusion>\n          <groupId>org.apache.logging.log4j</groupId>\n          <artifactId>log4j-to-slf4j</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- Zookeeper dependencies for testing -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n      <exclusions>\n        <exclusion>\n          <groupId>com.google.guava</groupId>\n          <artifactId>guava</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-zookeeper-curator5</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-recipes</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-x-discovery</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.zookeeper</groupId>\n      <artifactId>zookeeper</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- Nacos dependencies for testing -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-nacos</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-nacos</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.alibaba.nacos</groupId>\n      <artifactId>nacos-client</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <testResources>\n      <testResource>\n        <directory>src/test/resources</directory>\n      </testResource>\n      <testResource>\n        <directory>src/test/java</directory>\n        <includes>\n          <include>**/*.xml</include>\n          <include>**/*.yml</include>\n          <include>**/*.properties</include>\n        </includes>\n      </testResource>\n    </testResources>\n\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-surefire-plugin</artifactId>\n        <configuration>\n          <forkCount>1</forkCount>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ConfigCenterBean.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\n\n/**\n * Starting from 2.7.0+, export and refer will only be executed when Spring is fully initialized.\n * <p>\n * Each Config bean will get refreshed on the start of the exporting and referring process.\n * <p>\n * So it's ok for this bean not to be the first Dubbo Config bean being initialized.\n * <p>\n */\npublic class ConfigCenterBean extends ConfigCenterConfig\n        implements ApplicationContextAware, DisposableBean, EnvironmentAware {\n\n    private transient ApplicationContext applicationContext;\n\n    private Boolean includeSpringEnv = false;\n\n    public ConfigCenterBean() {}\n\n    public ConfigCenterBean(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) {\n        this.applicationContext = applicationContext;\n    }\n\n    @Override\n    public void destroy() throws Exception {}\n\n    @Override\n    public void setEnvironment(Environment environment) {\n        if (includeSpringEnv) {\n            // Get PropertySource mapped to 'dubbo.properties' in Spring Environment.\n            setExternalConfig(getConfigurations(getConfigFile(), environment));\n            // Get PropertySource mapped to 'application.dubbo.properties' in Spring Environment.\n            setAppExternalConfig(getConfigurations(\n                    StringUtils.isNotEmpty(getAppConfigFile())\n                            ? getAppConfigFile()\n                            : (\"application.\" + getConfigFile()),\n                    environment));\n        }\n    }\n\n    private Map<String, String> getConfigurations(String key, Environment environment) {\n        Object rawProperties = environment.getProperty(key, Object.class);\n        Map<String, String> externalProperties = new HashMap<>();\n        try {\n            if (rawProperties instanceof Map) {\n                externalProperties.putAll((Map<String, String>) rawProperties);\n            } else if (rawProperties instanceof String) {\n                externalProperties.putAll(ConfigurationUtils.parseProperties((String) rawProperties));\n            }\n\n            if (environment instanceof ConfigurableEnvironment && externalProperties.isEmpty()) {\n                ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment;\n                PropertySource propertySource =\n                        configurableEnvironment.getPropertySources().get(key);\n                if (propertySource != null) {\n                    Object source = propertySource.getSource();\n                    if (source instanceof Map) {\n                        ((Map<String, Object>) source).forEach((k, v) -> {\n                            externalProperties.put(k, (String) v);\n                        });\n                    }\n                }\n            }\n        } catch (Exception e) {\n            throw new IllegalStateException(e);\n        }\n        return externalProperties;\n    }\n\n    public ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n\n    public Boolean getIncludeSpringEnv() {\n        return includeSpringEnv;\n    }\n\n    public void setIncludeSpringEnv(Boolean includeSpringEnv) {\n        this.includeSpringEnv = includeSpringEnv;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\n/**\n * Constants of dubbo spring config\n */\npublic interface Constants {\n\n    /**\n     * attributes of reference annotation\n     */\n    String REFERENCE_PROPS = \"referenceProps\";\n\n    /**\n     * Registration sources of the reference, may be xml file or annotation location\n     */\n    String REFERENCE_SOURCES = \"referenceSources\";\n\n    /**\n     * The name of an attribute that can be\n     * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a\n     * {@link org.springframework.beans.factory.config.BeanDefinition} so that\n     * factory beans can signal their object type when it can't be deduced from\n     * the factory bean class.\n     * <p/>\n     * From FactoryBean.OBJECT_TYPE_ATTRIBUTE of Spring 5.2.\n     */\n    String OBJECT_TYPE_ATTRIBUTE = \"factoryBeanObjectType\";\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.common.aot.NativeDetector;\nimport org.apache.dubbo.common.bytecode.Proxy;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.spring.aot.AotWithSpringDetector;\nimport org.apache.dubbo.config.spring.context.DubboConfigApplicationListener;\nimport org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;\nimport org.apache.dubbo.config.spring.reference.ReferenceAttributes;\nimport org.apache.dubbo.config.spring.reference.ReferenceBeanManager;\nimport org.apache.dubbo.config.spring.reference.ReferenceBeanSupport;\nimport org.apache.dubbo.config.spring.schema.DubboBeanDefinitionParser;\nimport org.apache.dubbo.config.spring.util.LazyTargetInvocationHandler;\nimport org.apache.dubbo.config.spring.util.LazyTargetSource;\nimport org.apache.dubbo.config.spring.util.LockUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.proxy.AbstractProxyFactory;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.BeanNameAware;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_INITIALIZER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROXY_FAILED;\n\n/**\n * <p>\n * Spring FactoryBean for {@link ReferenceConfig}.\n * </p>\n *\n *\n * <p></p>\n * Step 1: Register ReferenceBean in Java-config class:\n * <pre class=\"code\">\n * &#64;Configuration\n * public class ReferenceConfiguration {\n *     &#64;Bean\n *     &#64;DubboReference(group = \"demo\")\n *     public ReferenceBean&lt;HelloService&gt; helloService() {\n *         return new ReferenceBean();\n *     }\n *\n *     // As GenericService\n *     &#64;Bean\n *     &#64;DubboReference(group = \"demo\", interfaceClass = HelloService.class)\n *     public ReferenceBean&lt;GenericService&gt; genericHelloService() {\n *         return new ReferenceBean();\n *     }\n * }\n * </pre>\n * <p>\n * Or register ReferenceBean in xml:\n * <pre class=\"code\">\n * &lt;dubbo:reference id=\"helloService\" interface=\"org.apache.dubbo.config.spring.api.HelloService\"/&gt;\n * &lt;!-- As GenericService --&gt;\n * &lt;dubbo:reference id=\"genericHelloService\" interface=\"org.apache.dubbo.config.spring.api.HelloService\" generic=\"true\"/&gt;\n * </pre>\n * <p>\n * Step 2: Inject ReferenceBean by @Autowired\n * <pre class=\"code\">\n * public class FooController {\n *     &#64;Autowired\n *     private HelloService helloService;\n *\n *     &#64;Autowired\n *     private GenericService genericHelloService;\n * }\n * </pre>\n *\n * @see org.apache.dubbo.config.annotation.DubboReference\n * @see org.apache.dubbo.config.spring.reference.ReferenceBeanBuilder\n */\npublic class ReferenceBean<T>\n        implements FactoryBean<T>,\n                ApplicationContextAware,\n                BeanClassLoaderAware,\n                BeanNameAware,\n                InitializingBean,\n                DisposableBean {\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n    private transient ApplicationContext applicationContext;\n\n    private ClassLoader beanClassLoader;\n\n    // lazy proxy of reference\n    private Object lazyProxy;\n\n    // beanName\n    protected String id;\n\n    // reference key\n    private String key;\n\n    /**\n     * The interface class of the reference service\n     */\n    private Class<?> interfaceClass;\n\n    /*\n     * remote service interface class name\n     */\n    // 'interfaceName' field for compatible with seata-1.4.0:\n    // io.seata.rm.tcc.remoting.parser.DubboRemotingParser#getServiceDesc()\n    private String interfaceName;\n\n    // proxy style\n    private String proxy;\n\n    // from annotation attributes\n    private Map<String, Object> referenceProps;\n\n    // from xml bean definition\n    private MutablePropertyValues propertyValues;\n\n    // actual reference config\n    private volatile ReferenceConfig referenceConfig;\n\n    // ReferenceBeanManager\n    private ReferenceBeanManager referenceBeanManager;\n\n    // Registration sources of this reference, may be xml file or annotation location\n    private List<Map<String, Object>> sources = new ArrayList<>();\n\n    public ReferenceBean() {\n        super();\n    }\n\n    public ReferenceBean(Map<String, Object> referenceProps) {\n        this.referenceProps = referenceProps;\n    }\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) {\n        this.applicationContext = applicationContext;\n    }\n\n    @Override\n    public void setBeanClassLoader(ClassLoader classLoader) {\n        this.beanClassLoader = classLoader;\n    }\n\n    @Override\n    public void setBeanName(String name) {\n        this.setId(name);\n    }\n\n    /**\n     * Create bean instance.\n     *\n     * <p></p>\n     * Why we need a lazy proxy?\n     * <p>\n     * <p/>\n     * When Spring searches beans by type, if Spring cannot determine the type of a factory bean, it may try to initialize it.\n     * The ReferenceBean is also a FactoryBean.\n     * <br/>\n     * (This has already been resolved by decorating the BeanDefinition: {@link DubboBeanDefinitionParser#configReferenceBean})\n     * <p>\n     * <p/>\n     * In addition, if some ReferenceBeans are dependent on beans that are initialized very early,\n     * and dubbo config beans are not ready yet, there will be many unexpected problems if initializing the dubbo reference immediately.\n     * <p>\n     * <p/>\n     * When it is initialized, only a lazy proxy object will be created,\n     * and dubbo reference-related resources will not be initialized.\n     * <br/>\n     * In this way, the influence of Spring is eliminated, and the dubbo configuration initialization is controllable.\n     *\n     * @see DubboConfigBeanInitializer\n     * @see ReferenceBeanManager#initReferenceBean(ReferenceBean)\n     * @see DubboBeanDefinitionParser#configReferenceBean\n     */\n    @Override\n    public T getObject() {\n        if (lazyProxy == null) {\n            createLazyProxy();\n        }\n        return (T) lazyProxy;\n    }\n\n    @Override\n    public Class<?> getObjectType() {\n        return getInterfaceClass();\n    }\n\n    @Override\n    @Parameter(excluded = true)\n    public boolean isSingleton() {\n        return true;\n    }\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        ConfigurableListableBeanFactory beanFactory = getBeanFactory();\n\n        // pre init xml reference bean or @DubboReference annotation\n        Assert.notEmptyString(getId(), \"The id of ReferenceBean cannot be empty\");\n        BeanDefinition beanDefinition = beanFactory.getBeanDefinition(getId());\n        if (AotWithSpringDetector.useGeneratedArtifacts()) {\n            this.interfaceClass =\n                    (Class<?>) beanDefinition.getPropertyValues().get(ReferenceAttributes.INTERFACE_CLASS);\n            this.interfaceName = (String) beanDefinition.getPropertyValues().get(ReferenceAttributes.INTERFACE_NAME);\n\n        } else {\n            this.interfaceClass = (Class<?>) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_CLASS);\n            this.interfaceName = (String) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_NAME);\n        }\n        Assert.notNull(this.interfaceClass, \"The interface class of ReferenceBean is not initialized\");\n\n        if (beanDefinition.hasAttribute(Constants.REFERENCE_PROPS)) {\n            // @DubboReference annotation at java-config class @Bean method\n            // @DubboReference annotation at reference field or setter method\n            referenceProps = (Map<String, Object>) beanDefinition.getAttribute(Constants.REFERENCE_PROPS);\n        } else {\n            if (beanDefinition instanceof AnnotatedBeanDefinition) {\n                // Return ReferenceBean in java-config class @Bean method\n                if (referenceProps == null) {\n                    referenceProps = new LinkedHashMap<>();\n                }\n                ReferenceBeanSupport.convertReferenceProps(referenceProps, interfaceClass);\n                if (this.interfaceName == null) {\n                    this.interfaceName = (String) referenceProps.get(ReferenceAttributes.INTERFACE);\n                }\n            } else {\n                // xml reference bean\n                propertyValues = beanDefinition.getPropertyValues();\n            }\n        }\n\n        if (referenceProps != null) {\n            this.proxy = (String) referenceProps.get(ReferenceAttributes.PROXY);\n        }\n        Assert.notNull(this.interfaceName, \"The interface name of ReferenceBean is not initialized\");\n\n        this.referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);\n        referenceBeanManager.addReference(this);\n    }\n\n    private ConfigurableListableBeanFactory getBeanFactory() {\n        return (ConfigurableListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();\n    }\n\n    @Override\n    public void destroy() {\n        // do nothing\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    /**\n     * The interface of this ReferenceBean, for injection purpose\n     *\n     * @return\n     */\n    public Class<?> getInterfaceClass() {\n        // Compatible with seata-1.4.0: io.seata.rm.tcc.remoting.parser.DubboRemotingParser#getServiceDesc()\n        return interfaceClass;\n    }\n\n    /**\n     * The interface of remote service\n     */\n    public String getServiceInterface() {\n        return interfaceName;\n    }\n\n    /**\n     * The group of the service\n     */\n    public String getGroup() {\n        // Compatible with seata-1.4.0: io.seata.rm.tcc.remoting.parser.DubboRemotingParser#getServiceDesc()\n        return referenceConfig.getGroup();\n    }\n\n    /**\n     * The version of the service\n     */\n    public String getVersion() {\n        // Compatible with seata-1.4.0: io.seata.rm.tcc.remoting.parser.DubboRemotingParser#getServiceDesc()\n        return referenceConfig.getVersion();\n    }\n\n    public String getKey() {\n        return key;\n    }\n\n    public Map<String, Object> getReferenceProps() {\n        return referenceProps;\n    }\n\n    public MutablePropertyValues getPropertyValues() {\n        return propertyValues;\n    }\n\n    public ReferenceConfig getReferenceConfig() {\n        return referenceConfig;\n    }\n\n    public void setKeyAndReferenceConfig(String key, ReferenceConfig referenceConfig) {\n        this.key = key;\n        this.referenceConfig = referenceConfig;\n    }\n\n    /**\n     * Create lazy proxy for reference.\n     */\n    private void createLazyProxy() {\n\n        // set proxy interfaces\n        // see also: org.apache.dubbo.rpc.proxy.AbstractProxyFactory.getProxy(org.apache.dubbo.rpc.Invoker<T>, boolean)\n        List<Class<?>> interfaces = new ArrayList<>();\n        interfaces.add(interfaceClass);\n        Class<?>[] internalInterfaces = AbstractProxyFactory.getInternalInterfaces();\n        Collections.addAll(interfaces, internalInterfaces);\n        if (!StringUtils.isEquals(interfaceClass.getName(), interfaceName)) {\n            // add service interface\n            try {\n                Class<?> serviceInterface = ClassUtils.forName(interfaceName, beanClassLoader);\n                interfaces.add(serviceInterface);\n            } catch (ClassNotFoundException e) {\n                // generic call maybe without service interface class locally\n            }\n        }\n\n        if (NativeDetector.inNativeImage()) {\n            generateFromJdk(interfaces);\n        }\n\n        if (this.lazyProxy == null\n                && (StringUtils.isEmpty(this.proxy) || CommonConstants.DEFAULT_PROXY.equalsIgnoreCase(this.proxy))) {\n            generateFromJavassistFirst(interfaces);\n        }\n\n        if (this.lazyProxy == null) {\n            generateFromJdk(interfaces);\n        }\n    }\n\n    private void generateFromJavassistFirst(List<Class<?>> interfaces) {\n        try {\n            this.lazyProxy = Proxy.getProxy(interfaces.toArray(new Class[0]))\n                    .newInstance(new LazyTargetInvocationHandler(new DubboReferenceLazyInitTargetSource()));\n        } catch (Throwable fromJavassist) {\n            // try fall back to JDK proxy factory\n            try {\n                this.lazyProxy = java.lang.reflect.Proxy.newProxyInstance(\n                        beanClassLoader,\n                        interfaces.toArray(new Class[0]),\n                        new LazyTargetInvocationHandler(new DubboReferenceLazyInitTargetSource()));\n                logger.error(\n                        PROXY_FAILED,\n                        \"\",\n                        \"\",\n                        \"Failed to generate proxy by Javassist failed. Fallback to use JDK proxy success. \"\n                                + \"Interfaces: \" + interfaces,\n                        fromJavassist);\n            } catch (Throwable fromJdk) {\n                logger.error(\n                        PROXY_FAILED,\n                        \"\",\n                        \"\",\n                        \"Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. \"\n                                + \"Interfaces: \" + interfaces + \" Javassist Error.\",\n                        fromJavassist);\n                logger.error(\n                        PROXY_FAILED,\n                        \"\",\n                        \"\",\n                        \"Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. \"\n                                + \"Interfaces: \" + interfaces + \" JDK Error.\",\n                        fromJdk);\n                throw fromJavassist;\n            }\n        }\n    }\n\n    private void generateFromJdk(List<Class<?>> interfaces) {\n        try {\n            this.lazyProxy = java.lang.reflect.Proxy.newProxyInstance(\n                    beanClassLoader,\n                    interfaces.toArray(new Class[0]),\n                    new LazyTargetInvocationHandler(new DubboReferenceLazyInitTargetSource()));\n        } catch (Throwable fromJdk) {\n            logger.error(\n                    PROXY_FAILED,\n                    \"\",\n                    \"\",\n                    \"Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. \"\n                            + \"Interfaces: \" + interfaces + \" JDK Error.\",\n                    fromJdk);\n            throw fromJdk;\n        }\n    }\n\n    private Object getCallProxy() throws Exception {\n        if (referenceConfig == null) {\n            synchronized (LockUtils.getSingletonMutex(applicationContext)) {\n                if (referenceConfig == null) {\n                    referenceBeanManager.initReferenceBean(this);\n                    applicationContext\n                            .getBean(\n                                    DubboConfigApplicationListener.class.getName(),\n                                    DubboConfigApplicationListener.class)\n                            .init();\n                    logger.warn(\n                            CONFIG_DUBBO_BEAN_INITIALIZER,\n                            \"\",\n                            \"\",\n                            \"ReferenceBean is not ready yet, please make sure to \"\n                                    + \"call reference interface method after dubbo is started.\");\n                }\n            }\n        }\n        // get reference proxy\n        // Subclasses should synchronize on the given Object if they perform any sort of extended singleton creation\n        // phase.\n        // In particular, subclasses should not have their own mutexes involved in singleton creation, to avoid the\n        // potential for deadlocks in lazy-init situations.\n        // The redundant type cast is to be compatible with earlier than spring-4.2\n        if (referenceConfig.configInitialized()) {\n            return referenceConfig.get();\n        }\n        synchronized (LockUtils.getSingletonMutex(applicationContext)) {\n            return referenceConfig.get();\n        }\n    }\n\n    private class DubboReferenceLazyInitTargetSource implements LazyTargetSource {\n        @Override\n        public Object getTarget() throws Exception {\n            return getCallProxy();\n        }\n    }\n\n    public void setInterfaceClass(Class<?> interfaceClass) {\n        this.interfaceClass = interfaceClass;\n    }\n\n    public void setInterfaceName(String interfaceName) {\n        this.interfaceName = interfaceName;\n    }\n\n    /**\n     * It is only used in native scenarios to get referenceProps\n     * because attribute is not passed by BeanDefinition by default.\n     * @param referencePropsJson\n     */\n    public void setReferencePropsJson(String referencePropsJson) {\n        if (StringUtils.isNotEmpty(referencePropsJson)) {\n            this.referenceProps = JsonUtils.toJavaObject(referencePropsJson, Map.class);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.config.support.Parameter;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.beans.factory.BeanNameAware;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.ApplicationEventPublisherAware;\n\n/**\n * ServiceFactoryBean\n *\n * @export\n */\npublic class ServiceBean<T> extends ServiceConfig<T>\n        implements InitializingBean,\n                DisposableBean,\n                ApplicationContextAware,\n                BeanNameAware,\n                ApplicationEventPublisherAware {\n\n    private static final long serialVersionUID = 213195494150089726L;\n\n    private final transient Service service;\n\n    private transient ApplicationContext applicationContext;\n\n    private transient String beanName;\n\n    private ApplicationEventPublisher applicationEventPublisher;\n\n    @Autowired\n    public ServiceBean(ModuleModel moduleModel) {\n        super(moduleModel);\n        this.service = null;\n    }\n\n    public ServiceBean(ApplicationContext applicationContext) {\n        super();\n        this.service = null;\n        this.applicationContext = applicationContext;\n        this.setScopeModel(DubboBeanUtils.getModuleModel(applicationContext));\n    }\n\n    public ServiceBean(ApplicationContext applicationContext, ModuleModel moduleModel) {\n        super(moduleModel);\n        this.service = null;\n        this.applicationContext = applicationContext;\n    }\n\n    public ServiceBean(ApplicationContext applicationContext, Service service) {\n        super(service);\n        this.service = service;\n        this.applicationContext = applicationContext;\n        this.setScopeModel(DubboBeanUtils.getModuleModel(applicationContext));\n    }\n\n    public ServiceBean(ApplicationContext applicationContext, ModuleModel moduleModel, Service service) {\n        super(moduleModel, service);\n        this.service = service;\n        this.applicationContext = applicationContext;\n    }\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) {\n        this.applicationContext = applicationContext;\n    }\n\n    @Override\n    public void setBeanName(String name) {\n        this.beanName = name;\n    }\n\n    /**\n     * Gets associated {@link Service}\n     *\n     * @return associated {@link Service}\n     */\n    public Service getService() {\n        return service;\n    }\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        if (StringUtils.isEmpty(getPath())) {\n            if (StringUtils.isNotEmpty(getInterface())) {\n                setPath(getInterface());\n            }\n        }\n        // register service bean\n        ModuleModel moduleModel = DubboBeanUtils.getModuleModel(applicationContext);\n        moduleModel.getConfigManager().addService(this);\n        moduleModel.getDeployer().setPending();\n    }\n\n    /**\n     * Get the name of {@link ServiceBean}\n     *\n     * @return {@link ServiceBean}'s name\n     * @since 2.6.5\n     */\n    @Parameter(excluded = true, attribute = false)\n    public String getBeanName() {\n        return this.beanName;\n    }\n\n    /**\n     * @since 2.6.5\n     */\n    @Override\n    protected void exported() {\n        super.exported();\n        // Publish ServiceBeanExportedEvent\n        publishExportEvent();\n    }\n\n    /**\n     * @since 2.6.5\n     */\n    private void publishExportEvent() {\n        ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this);\n        applicationEventPublisher.publishEvent(exportEvent);\n    }\n\n    @Override\n    public void destroy() throws Exception {\n        // no need to call unexport() here, see\n        // org.apache.dubbo.config.spring.extension.SpringExtensionInjector.ShutdownHookListener\n    }\n\n    // merged from dubbox\n    @Override\n    protected Class getServiceClass(T ref) {\n        if (AopUtils.isAopProxy(ref)) {\n            return AopUtils.getTargetClass(ref);\n        }\n        return super.getServiceClass(ref);\n    }\n\n    /**\n     * @param applicationEventPublisher\n     * @since 2.6.5\n     */\n    @Override\n    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {\n        this.applicationEventPublisher = applicationEventPublisher;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/SpringScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\n/**\n * Register scope beans in spring module\n */\npublic class SpringScopeModelInitializer implements ScopeModelInitializer {\n\n    @Override\n    public void initializeFrameworkModel(FrameworkModel frameworkModel) {}\n\n    @Override\n    public void initializeApplicationModel(ApplicationModel applicationModel) {}\n\n    @Override\n    public void initializeModuleModel(ModuleModel moduleModel) {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/aot/AotWithSpringDetector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.aot;\n\nimport org.apache.dubbo.common.aot.NativeDetector;\n\nimport org.springframework.core.SpringProperties;\n\npublic abstract class AotWithSpringDetector {\n\n    /**\n     * System property that indicates the application should run with AOT\n     * generated artifacts. If such optimizations are not available, it is\n     * recommended to throw an exception rather than fall back to the regular\n     * runtime behavior.\n     */\n    public static final String AOT_ENABLED = \"spring.aot.enabled\";\n\n    private static final String AOT_PROCESSING = \"spring.aot.processing\";\n\n    /**\n     * Determine whether AOT optimizations must be considered at runtime. This\n     * is mandatory in a native image but can be triggered on the JVM using\n     * the {@value #AOT_ENABLED} Spring property.\n     *\n     * @return whether AOT optimizations must be considered\n     */\n    public static boolean useGeneratedArtifacts() {\n        return (NativeDetector.inNativeImage() || SpringProperties.getFlag(AOT_ENABLED));\n    }\n\n    public static boolean isAotProcessing() {\n        return (NativeDetector.inNativeImage() || SpringProperties.getFlag(AOT_PROCESSING));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationBeanPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.spring.util.AnnotationUtils;\n\nimport java.beans.PropertyDescriptor;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Member;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.PropertyValues;\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.annotation.InjectionMetadata;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;\nimport org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_INITIALIZER;\nimport static org.springframework.core.BridgeMethodResolver.findBridgedMethod;\nimport static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair;\n\n/**\n * Abstract common {@link BeanPostProcessor} implementation for customized annotation that annotated injected-object.\n */\n@SuppressWarnings(\"unchecked\")\npublic abstract class AbstractAnnotationBeanPostProcessor\n        implements InstantiationAwareBeanPostProcessor,\n                MergedBeanDefinitionPostProcessor,\n                BeanFactoryAware,\n                BeanClassLoaderAware,\n                EnvironmentAware,\n                DisposableBean {\n\n    private static final int CACHE_SIZE = Integer.getInteger(\"\", 32);\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private final Class<? extends Annotation>[] annotationTypes;\n\n    private final ConcurrentMap<String, AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata>\n            injectionMetadataCache = new ConcurrentHashMap<>(CACHE_SIZE);\n\n    private ConfigurableListableBeanFactory beanFactory;\n\n    private Environment environment;\n\n    private ClassLoader classLoader;\n\n    private int order = Ordered.LOWEST_PRECEDENCE;\n\n    /**\n     * @param annotationTypes the multiple types of {@link Annotation annotations}\n     */\n    public AbstractAnnotationBeanPostProcessor(Class<? extends Annotation>... annotationTypes) {\n        Assert.notEmpty(annotationTypes, \"The argument of annotations' types must not empty\");\n        this.annotationTypes = annotationTypes;\n    }\n\n    private static <T> Collection<T> combine(Collection<? extends T>... elements) {\n        List<T> allElements = new ArrayList<>();\n        for (Collection<? extends T> e : elements) {\n            allElements.addAll(e);\n        }\n        return allElements;\n    }\n\n    /**\n     * Annotation type\n     *\n     * @return non-null\n     * @deprecated 2.7.3, uses {@link #getAnnotationTypes()}\n     */\n    @Deprecated\n    public final Class<? extends Annotation> getAnnotationType() {\n        return annotationTypes[0];\n    }\n\n    protected final Class<? extends Annotation>[] getAnnotationTypes() {\n        return annotationTypes;\n    }\n\n    @Override\n    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n        Assert.isInstanceOf(\n                ConfigurableListableBeanFactory.class,\n                beanFactory,\n                \"AnnotationInjectedBeanPostProcessor requires a ConfigurableListableBeanFactory\");\n        this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;\n    }\n\n    /**\n     * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated fields\n     *\n     * @param beanClass The {@link Class} of Bean\n     * @return non-null {@link List}\n     */\n    private List<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> findFieldAnnotationMetadata(\n            final Class<?> beanClass) {\n\n        final List<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> elements = new LinkedList<>();\n\n        ReflectionUtils.doWithFields(beanClass, field -> {\n            for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {\n\n                AnnotationAttributes attributes =\n                        AnnotationUtils.getAnnotationAttributes(field, annotationType, getEnvironment(), true, true);\n\n                if (attributes != null) {\n\n                    if (Modifier.isStatic(field.getModifiers())) {\n                        if (logger.isWarnEnabled()) {\n                            logger.warn(\n                                    CONFIG_DUBBO_BEAN_INITIALIZER,\n                                    \"\",\n                                    \"\",\n                                    \"@\" + annotationType.getName() + \" is not supported on static fields: \" + field);\n                        }\n                        return;\n                    }\n\n                    elements.add(new AnnotatedFieldElement(field, attributes));\n                }\n            }\n        });\n\n        return elements;\n    }\n\n    /**\n     * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated methods\n     *\n     * @param beanClass The {@link Class} of Bean\n     * @return non-null {@link List}\n     */\n    private List<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> findAnnotatedMethodMetadata(\n            final Class<?> beanClass) {\n\n        final List<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> elements = new LinkedList<>();\n\n        ReflectionUtils.doWithMethods(beanClass, method -> {\n            Method bridgedMethod = findBridgedMethod(method);\n\n            if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) {\n                return;\n            }\n\n            if (method.getAnnotation(Bean.class) != null) {\n                // DO NOT inject to Java-config class's @Bean method\n                return;\n            }\n\n            for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {\n\n                AnnotationAttributes attributes = AnnotationUtils.getAnnotationAttributes(\n                        bridgedMethod, annotationType, getEnvironment(), true, true);\n\n                if (attributes != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {\n                    if (Modifier.isStatic(method.getModifiers())) {\n                        throw new IllegalStateException(\"When using @\" + annotationType.getName()\n                                + \" to inject interface proxy, it is not supported on static methods: \" + method);\n                    }\n                    if (method.getParameterTypes().length != 1) {\n                        throw new IllegalStateException(\"When using @\" + annotationType.getName()\n                                + \" to inject interface proxy, the method must have only one parameter: \" + method);\n                    }\n                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);\n                    elements.add(new AnnotatedMethodElement(method, pd, attributes));\n                }\n            }\n        });\n\n        return elements;\n    }\n\n    private AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(\n            final Class<?> beanClass) {\n        Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements =\n                findFieldAnnotationMetadata(beanClass);\n        Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> methodElements =\n                findAnnotatedMethodMetadata(beanClass);\n        return new AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);\n    }\n\n    protected AnnotatedInjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {\n        // Fall back to class name as cache key, for backwards compatibility with custom callers.\n        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());\n        // Quick check on the concurrent map first, with minimal locking.\n        AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata metadata =\n                this.injectionMetadataCache.get(cacheKey);\n        if (needsRefreshInjectionMetadata(metadata, clazz)) {\n            synchronized (this.injectionMetadataCache) {\n                metadata = this.injectionMetadataCache.get(cacheKey);\n\n                if (needsRefreshInjectionMetadata(metadata, clazz)) {\n                    if (metadata != null) {\n                        metadata.clear(pvs);\n                    }\n                    try {\n                        metadata = buildAnnotatedMetadata(clazz);\n                        this.injectionMetadataCache.put(cacheKey, metadata);\n                    } catch (NoClassDefFoundError err) {\n                        throw new IllegalStateException(\n                                \"Failed to introspect object class [\" + clazz.getName()\n                                        + \"] for annotation metadata: could not find class that it depends on\",\n                                err);\n                    }\n                }\n            }\n        }\n        return metadata;\n    }\n\n    // Use custom check method to compatible with Spring 4.x\n    private boolean needsRefreshInjectionMetadata(AnnotatedInjectionMetadata metadata, Class<?> clazz) {\n        return (metadata == null || metadata.needsRefresh(clazz));\n    }\n\n    @Override\n    public void destroy() throws Exception {\n\n        injectionMetadataCache.clear();\n\n        if (logger.isInfoEnabled()) {\n            logger.info(getClass() + \" was destroying!\");\n        }\n    }\n\n    @Override\n    public void setBeanClassLoader(ClassLoader classLoader) {\n        this.classLoader = classLoader;\n    }\n\n    @Override\n    public void setEnvironment(Environment environment) {\n        this.environment = environment;\n    }\n\n    protected Environment getEnvironment() {\n        return environment;\n    }\n\n    protected ClassLoader getClassLoader() {\n        return classLoader;\n    }\n\n    protected ConfigurableListableBeanFactory getBeanFactory() {\n        return beanFactory;\n    }\n\n    /**\n     * Get injected-object from specified {@link AnnotationAttributes annotation attributes} and Bean Class\n     *\n     * @param attributes      {@link AnnotationAttributes the annotation attributes}\n     * @param bean            Current bean that will be injected\n     * @param beanName        Current bean name that will be injected\n     * @param injectedType    the type of injected-object\n     * @param injectedElement {@link AnnotatedInjectElement}\n     * @return An injected object\n     * @throws Exception If getting is failed\n     */\n    protected Object getInjectedObject(\n            AnnotationAttributes attributes,\n            Object bean,\n            String beanName,\n            Class<?> injectedType,\n            AnnotatedInjectElement injectedElement)\n            throws Exception {\n        return doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);\n    }\n\n    /**\n     * Prepare injection data after found injection elements\n     *\n     * @param metadata\n     * @throws Exception\n     */\n    protected void prepareInjection(AnnotatedInjectionMetadata metadata) throws Exception {}\n\n    /**\n     * Subclass must implement this method to get injected-object. The context objects could help this method if\n     * necessary :\n     * <ul>\n     * <li>{@link #getBeanFactory() BeanFactory}</li>\n     * <li>{@link #getClassLoader() ClassLoader}</li>\n     * <li>{@link #getEnvironment() Environment}</li>\n     * </ul>\n     *\n     * @param attributes      {@link AnnotationAttributes the annotation attributes}\n     * @param bean            Current bean that will be injected\n     * @param beanName        Current bean name that will be injected\n     * @param injectedType    the type of injected-object\n     * @param injectedElement {@link AnnotatedInjectElement}\n     * @return The injected object\n     * @throws Exception If resolving an injected object is failed.\n     */\n    protected abstract Object doGetInjectedBean(\n            AnnotationAttributes attributes,\n            Object bean,\n            String beanName,\n            Class<?> injectedType,\n            AnnotatedInjectElement injectedElement)\n            throws Exception;\n\n    @Override\n    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {\n        return null;\n    }\n\n    @Override\n    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {\n        return true;\n    }\n\n    @Override\n    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n        return bean;\n    }\n\n    @Override\n    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n        return bean;\n    }\n\n    /**\n     * {@link Annotation Annotated} {@link InjectionMetadata} implementation\n     */\n    protected static class AnnotatedInjectionMetadata extends InjectionMetadata {\n\n        private Class<?> targetClass;\n        private final Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements;\n\n        private final Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> methodElements;\n\n        public AnnotatedInjectionMetadata(\n                Class<?> targetClass,\n                Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements,\n                Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> methodElements) {\n            super(targetClass, combine(fieldElements, methodElements));\n            this.targetClass = targetClass;\n            this.fieldElements = fieldElements;\n            this.methodElements = methodElements;\n        }\n\n        public Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> getFieldElements() {\n            return fieldElements;\n        }\n\n        public Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> getMethodElements() {\n            return methodElements;\n        }\n\n        // @Override // since Spring 5.2.4\n        protected boolean needsRefresh(Class<?> clazz) {\n            if (this.targetClass == clazz) {\n                return false;\n            }\n            // IGNORE Spring CGLIB enhanced class\n            if (targetClass.isAssignableFrom(clazz) && clazz.getName().contains(\"$$EnhancerBySpringCGLIB$$\")) {\n                return false;\n            }\n\n            if (targetClass.isAssignableFrom(clazz) && clazz.getName().contains(\"$$SpringCGLIB$$\")) {\n                return false;\n            }\n\n            return true;\n        }\n    }\n\n    /**\n     * {@link Annotation Annotated} {@link Method} {@link InjectionMetadata.InjectedElement}\n     */\n    protected class AnnotatedInjectElement extends InjectionMetadata.InjectedElement {\n\n        public final AnnotationAttributes attributes;\n\n        public volatile Object injectedObject;\n\n        public Class<?> injectedType;\n\n        protected AnnotatedInjectElement(Member member, PropertyDescriptor pd, AnnotationAttributes attributes) {\n            super(member, pd);\n            this.attributes = attributes;\n        }\n\n        @Override\n        protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {\n\n            Object injectedObject = getInjectedObject(attributes, bean, beanName, getInjectedType(), this);\n\n            if (member instanceof Field) {\n                Field field = (Field) member;\n                ReflectionUtils.makeAccessible(field);\n                field.set(bean, injectedObject);\n            } else if (member instanceof Method) {\n                Method method = (Method) member;\n                ReflectionUtils.makeAccessible(method);\n                method.invoke(bean, injectedObject);\n            }\n        }\n\n        public Class<?> getInjectedType() throws ClassNotFoundException {\n            if (injectedType == null) {\n                if (this.isField) {\n                    injectedType = ((Field) this.member).getType();\n                } else if (this.pd != null) {\n                    return this.pd.getPropertyType();\n                } else {\n                    Method method = (Method) this.member;\n                    if (method.getParameterTypes().length > 0) {\n                        injectedType = method.getParameterTypes()[0];\n                    } else {\n                        throw new IllegalStateException(\"get injected type failed\");\n                    }\n                }\n            }\n            return injectedType;\n        }\n\n        public String getPropertyName() {\n            if (member instanceof Field) {\n                Field field = (Field) member;\n                return field.getName();\n            } else if (this.pd != null) {\n                // If it is method element, using propertyName of PropertyDescriptor\n                return pd.getName();\n            } else {\n                Method method = (Method) this.member;\n                return method.getName();\n            }\n        }\n    }\n\n    protected class AnnotatedMethodElement extends AnnotatedInjectElement {\n\n        public final Method method;\n\n        protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, AnnotationAttributes attributes) {\n            super(method, pd, attributes);\n            this.method = method;\n        }\n    }\n\n    public class AnnotatedFieldElement extends AnnotatedInjectElement {\n\n        public final Field field;\n\n        protected AnnotatedFieldElement(Field field, AnnotationAttributes attributes) {\n            super(field, null, attributes);\n            this.field = field;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.spring.util.AnnotationUtils;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Map;\n\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.beans.PropertyValue;\nimport org.springframework.beans.PropertyValues;\nimport org.springframework.core.env.PropertyResolver;\n\n/**\n * {@link Annotation} {@link PropertyValues} Adapter\n *\n * @see Annotation\n * @see PropertyValues\n * @since 2.5.11\n */\npublic class AnnotationPropertyValuesAdapter implements PropertyValues {\n\n    private final PropertyValues delegate;\n\n    /**\n     * @param attributes\n     * @param propertyResolver\n     * @param ignoreAttributeNames\n     * @since 2.7.3\n     */\n    public AnnotationPropertyValuesAdapter(\n            Map<String, Object> attributes, PropertyResolver propertyResolver, String... ignoreAttributeNames) {\n        this.delegate = new MutablePropertyValues(\n                AnnotationUtils.getAttributes(attributes, propertyResolver, ignoreAttributeNames));\n    }\n\n    public AnnotationPropertyValuesAdapter(\n            Annotation annotation,\n            PropertyResolver propertyResolver,\n            boolean ignoreDefaultValue,\n            String... ignoreAttributeNames) {\n        this.delegate = new MutablePropertyValues(\n                AnnotationUtils.getAttributes(annotation, propertyResolver, ignoreDefaultValue, ignoreAttributeNames));\n    }\n\n    public AnnotationPropertyValuesAdapter(\n            Annotation annotation, PropertyResolver propertyResolver, String... ignoreAttributeNames) {\n        this(annotation, propertyResolver, true, ignoreAttributeNames);\n    }\n\n    @Override\n    public PropertyValue[] getPropertyValues() {\n        return delegate.getPropertyValues();\n    }\n\n    @Override\n    public PropertyValue getPropertyValue(String propertyName) {\n        return delegate.getPropertyValue(propertyName);\n    }\n\n    @Override\n    public PropertyValues changesSince(PropertyValues old) {\n        return delegate.changesSince(old);\n    }\n\n    @Override\n    public boolean contains(String propertyName) {\n        return delegate.contains(propertyName);\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return delegate.isEmpty();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigAliasPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar;\nimport org.apache.dubbo.config.spring.util.BeanRegistrar;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\n\nimport static org.springframework.util.ObjectUtils.nullSafeEquals;\nimport static org.springframework.util.StringUtils.hasText;\n\n/**\n * A Post-Processor class to set the alias of Dubbo Config bean using its {@link AbstractConfig#getId()}\n *\n * @since 2.7.5\n */\npublic class DubboConfigAliasPostProcessor implements BeanDefinitionRegistryPostProcessor, BeanPostProcessor {\n\n    /**\n     * The bean name of {@link DubboConfigConfigurationRegistrar}\n     */\n    public static final String BEAN_NAME = \"dubboConfigAliasPostProcessor\";\n\n    private BeanDefinitionRegistry registry;\n\n    @Override\n    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {\n        this.registry = registry;\n    }\n\n    @Override\n    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n        // DO NOTHING\n    }\n\n    @Override\n    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n        // DO NOTHING\n        return bean;\n    }\n\n    @Override\n    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n        if (bean instanceof AbstractConfig) {\n            String id = ((AbstractConfig) bean).getId();\n            if (hasText(id) // id MUST be present in AbstractConfig\n                    && !nullSafeEquals(id, beanName) // id MUST NOT be equal to bean name\n                    && !BeanRegistrar.hasAlias(registry, beanName, id)) { // id MUST NOT be present in AliasRegistry\n                registry.registerAlias(beanName, id);\n            }\n        }\n        return bean;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.common.compact.Dubbo2CompactUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.spring.Constants;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.aot.AotWithSpringDetector;\nimport org.apache.dubbo.config.spring.context.event.DubboConfigInitEvent;\nimport org.apache.dubbo.config.spring.reference.ReferenceAttributes;\nimport org.apache.dubbo.config.spring.reference.ReferenceBeanManager;\nimport org.apache.dubbo.config.spring.reference.ReferenceBeanSupport;\nimport org.apache.dubbo.config.spring.util.AnnotationUtils;\nimport org.apache.dubbo.config.spring.util.SpringCompatUtils;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.beans.PropertyDescriptor;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Member;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.PropertyValue;\nimport org.springframework.beans.PropertyValues;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.annotation.InjectionMetadata;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinitionHolder;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.AbstractBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.GenericBeanDefinition;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.type.MethodMetadata;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_INITIALIZER;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;\nimport static org.springframework.util.StringUtils.hasText;\n\n/**\n * <p>\n * Step 1:\n * The purpose of implementing {@link BeanFactoryPostProcessor} is to scan the registration reference bean definition earlier,\n * so that it can be shared with the xml bean configuration.\n * </p>\n *\n * <p>\n * Step 2:\n * By implementing {@link org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor},\n * inject the reference bean instance into the fields and setter methods which annotated with {@link DubboReference}.\n * </p>\n *\n * @see DubboReference\n * @see Reference\n * @see com.alibaba.dubbo.config.annotation.Reference\n * @since 2.5.7\n */\npublic class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBeanPostProcessor\n        implements ApplicationContextAware, BeanFactoryPostProcessor {\n\n    /**\n     * The bean name of {@link ReferenceAnnotationBeanPostProcessor}\n     */\n    public static final String BEAN_NAME = ReferenceAnnotationBeanPostProcessor.class.getName();\n\n    /**\n     * Cache size\n     */\n    private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + \".cache.size\", 32);\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private final ConcurrentMap<InjectionMetadata.InjectedElement, String> injectedFieldReferenceBeanCache =\n            new ConcurrentHashMap<>(CACHE_SIZE);\n\n    private final ConcurrentMap<InjectionMetadata.InjectedElement, String> injectedMethodReferenceBeanCache =\n            new ConcurrentHashMap<>(CACHE_SIZE);\n\n    protected ApplicationContext applicationContext;\n\n    protected ReferenceBeanManager referenceBeanManager;\n    protected BeanDefinitionRegistry beanDefinitionRegistry;\n\n    /**\n     * {@link com.alibaba.dubbo.config.annotation.Reference @com.alibaba.dubbo.config.annotation.Reference} has been supported since 2.7.3\n     * <p>\n     * {@link DubboReference @DubboReference} has been supported since 2.7.7\n     */\n    public ReferenceAnnotationBeanPostProcessor() {\n        super(loadAnnotationTypes());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static Class<? extends Annotation>[] loadAnnotationTypes() {\n        if (Dubbo2CompactUtils.isEnabled() && Dubbo2CompactUtils.isReferenceClassLoaded()) {\n            return (Class<? extends Annotation>[])\n                    new Class<?>[] {DubboReference.class, Reference.class, Dubbo2CompactUtils.getReferenceClass()};\n        } else {\n            return (Class<? extends Annotation>[]) new Class<?>[] {DubboReference.class, Reference.class};\n        }\n    }\n\n    @Override\n    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\n        String[] beanNames = beanFactory.getBeanDefinitionNames();\n        for (String beanName : beanNames) {\n            Class<?> beanType;\n            if (beanFactory.isFactoryBean(beanName)) {\n                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);\n                if (isReferenceBean(beanDefinition)) {\n                    continue;\n                }\n                if (isAnnotatedReferenceBean(beanDefinition)) {\n                    // process @DubboReference at java-config @bean method\n                    processReferenceAnnotatedBeanDefinition(beanName, (AnnotatedBeanDefinition) beanDefinition);\n                    continue;\n                }\n\n                String beanClassName = beanDefinition.getBeanClassName();\n                beanType = ClassUtils.resolveClass(beanClassName, getClassLoader());\n            } else {\n                beanType = beanFactory.getType(beanName);\n            }\n            if (beanType != null) {\n                AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);\n                try {\n                    prepareInjection(metadata);\n                } catch (BeansException e) {\n                    throw e;\n                } catch (Exception e) {\n                    throw new IllegalStateException(\"Prepare dubbo reference injection element failed\", e);\n                }\n            }\n        }\n\n        if (beanFactory instanceof AbstractBeanFactory) {\n            List<BeanPostProcessor> beanPostProcessors = ((AbstractBeanFactory) beanFactory).getBeanPostProcessors();\n            for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {\n                if (beanPostProcessor == this) {\n                    // This bean has been registered as BeanPostProcessor at\n                    // org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor.postProcessBeanFactory()\n                    // so destroy this bean here, prevent register it as BeanPostProcessor again, avoid cause\n                    // BeanPostProcessorChecker detection error\n                    beanDefinitionRegistry.removeBeanDefinition(BEAN_NAME);\n                    break;\n                }\n            }\n        }\n\n        try {\n            // this is an early event, it will be notified at\n            // org.springframework.context.support.AbstractApplicationContext.registerListeners()\n            applicationContext.publishEvent(new DubboConfigInitEvent(applicationContext));\n        } catch (Exception e) {\n            // if spring version is less than 4.2, it does not support early application event\n            logger.warn(\n                    CONFIG_DUBBO_BEAN_INITIALIZER,\n                    \"\",\n                    \"\",\n                    \"publish early application event failed, please upgrade spring version to 4.2.x or later: \" + e);\n        }\n    }\n\n    /**\n     * check whether is @DubboReference at java-config @bean method\n     */\n    private boolean isAnnotatedReferenceBean(BeanDefinition beanDefinition) {\n        if (beanDefinition instanceof AnnotatedBeanDefinition) {\n            AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;\n            String beanClassName = SpringCompatUtils.getFactoryMethodReturnType(annotatedBeanDefinition);\n            if (beanClassName != null && ReferenceBean.class.getName().equals(beanClassName)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * process @DubboReference at java-config @bean method\n     * <pre class=\"code\">\n     * &#064;Configuration\n     * public class ConsumerConfig {\n     *\n     *      &#064;Bean\n     *      &#064;DubboReference(group=\"demo\", version=\"1.2.3\")\n     *      public ReferenceBean&lt;DemoService&gt; demoService() {\n     *          return new ReferenceBean();\n     *      }\n     *\n     * }\n     * </pre>\n     *\n     * @param beanName\n     * @param beanDefinition\n     */\n    protected void processReferenceAnnotatedBeanDefinition(String beanName, AnnotatedBeanDefinition beanDefinition) {\n\n        MethodMetadata factoryMethodMetadata = SpringCompatUtils.getFactoryMethodMetadata(beanDefinition);\n\n        // Extract beanClass from generic return type of java-config bean method: ReferenceBean<DemoService>\n        // see\n        // org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryBeanFromMethod\n        Class beanClass = getBeanFactory().getType(beanName);\n        if (beanClass == Object.class) {\n            beanClass = SpringCompatUtils.getGenericTypeOfReturnType(factoryMethodMetadata);\n        }\n        if (beanClass == Object.class) {\n            // bean class is invalid, ignore it\n            return;\n        }\n\n        if (beanClass == null) {\n            String beanMethodSignature =\n                    factoryMethodMetadata.getDeclaringClassName() + \"#\" + factoryMethodMetadata.getMethodName() + \"()\";\n            throw new BeanCreationException(\n                    \"The ReferenceBean is missing necessary generic type, which returned by the @Bean method of Java-config class. \"\n                            + \"The generic type of the returned ReferenceBean must be specified as the referenced interface type, \"\n                            + \"such as ReferenceBean<DemoService>. Please check bean method: \"\n                            + beanMethodSignature);\n        }\n\n        // get dubbo reference annotation attributes\n        Map<String, Object> annotationAttributes = null;\n        // try all dubbo reference annotation types\n        for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {\n            if (factoryMethodMetadata.isAnnotated(annotationType.getName())) {\n                // Since Spring 5.2\n                // return factoryMethodMetadata.getAnnotations().get(annotationType).filterDefaultValues().asMap();\n                // Compatible with Spring 4.x\n                annotationAttributes = factoryMethodMetadata.getAnnotationAttributes(annotationType.getName());\n                annotationAttributes = filterDefaultValues(annotationType, annotationAttributes);\n                break;\n            }\n        }\n\n        if (annotationAttributes != null) {\n            // @DubboReference on @Bean method\n            LinkedHashMap<String, Object> attributes = new LinkedHashMap<>(annotationAttributes);\n            // reset id attribute\n            attributes.put(ReferenceAttributes.ID, beanName);\n            // convert annotation props\n            ReferenceBeanSupport.convertReferenceProps(attributes, beanClass);\n\n            // get interface\n            String interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE);\n\n            // check beanClass and reference interface class\n            if (!StringUtils.isEquals(interfaceName, beanClass.getName()) && beanClass != GenericService.class) {\n                String beanMethodSignature = factoryMethodMetadata.getDeclaringClassName() + \"#\"\n                        + factoryMethodMetadata.getMethodName() + \"()\";\n                throw new BeanCreationException(\n                        \"The 'interfaceClass' or 'interfaceName' attribute value of @DubboReference annotation \"\n                                + \"is inconsistent with the generic type of the ReferenceBean returned by the bean method. \"\n                                + \"The interface class of @DubboReference is: \"\n                                + interfaceName + \", but return ReferenceBean<\" + beanClass.getName() + \">. \"\n                                + \"Please remove the 'interfaceClass' and 'interfaceName' attributes from @DubboReference annotation. \"\n                                + \"Please check bean method: \"\n                                + beanMethodSignature);\n            }\n\n            Class interfaceClass = beanClass;\n\n            // set attribute instead of property values\n            beanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);\n            beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);\n            beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);\n        } else {\n            // raw reference bean\n            // the ReferenceBean is not yet initialized\n            beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, beanClass);\n            if (beanClass != GenericService.class) {\n                beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, beanClass.getName());\n            }\n        }\n\n        // set id\n        beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, beanName);\n    }\n\n    @Override\n    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {\n        if (beanType != null) {\n            if (isReferenceBean(beanDefinition)) {\n                // mark property value as optional\n                List<PropertyValue> propertyValues =\n                        beanDefinition.getPropertyValues().getPropertyValueList();\n                for (PropertyValue propertyValue : propertyValues) {\n                    propertyValue.setOptional(true);\n                }\n            } else if (isAnnotatedReferenceBean(beanDefinition)) {\n                // extract beanClass from java-config bean method generic return type: ReferenceBean<DemoService>\n                // Class beanClass = getBeanFactory().getType(beanName);\n            } else {\n                AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);\n                metadata.checkConfigMembers(beanDefinition);\n                try {\n                    prepareInjection(metadata);\n                } catch (Exception e) {\n                    throw new IllegalStateException(\"Prepare dubbo reference injection element failed\", e);\n                }\n            }\n        }\n    }\n\n    /**\n     * Alternatives to the {@link #postProcessProperties(PropertyValues, Object, String)}, that removed as of Spring\n     * Framework 6.0.0, and in favor of {@link #postProcessProperties(PropertyValues, Object, String)}.\n     * <p>In order to be compatible with the lower version of Spring, it is still retained.\n     *\n     * @see #postProcessProperties\n     */\n    public PropertyValues postProcessPropertyValues(\n            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {\n        return postProcessProperties(pvs, bean, beanName);\n    }\n\n    /**\n     * Alternatives to the {@link #postProcessPropertyValues(PropertyValues, PropertyDescriptor[], Object, String)}.\n     *\n     * @see #postProcessPropertyValues\n     */\n    @Override\n    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)\n            throws BeansException {\n        try {\n            AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);\n            prepareInjection(metadata);\n            metadata.inject(bean, beanName, pvs);\n        } catch (BeansException ex) {\n            throw ex;\n        } catch (Throwable ex) {\n            throw new BeanCreationException(\n                    beanName, \"Injection of @\" + getAnnotationType().getSimpleName() + \" dependencies is failed\", ex);\n        }\n        return pvs;\n    }\n\n    private boolean isReferenceBean(BeanDefinition beanDefinition) {\n        return ReferenceBean.class.getName().equals(beanDefinition.getBeanClassName());\n    }\n\n    protected void prepareInjection(AnnotatedInjectionMetadata metadata) throws BeansException {\n        try {\n            // find and register bean definition for @DubboReference/@Reference\n            for (AnnotatedFieldElement fieldElement : metadata.getFieldElements()) {\n                if (fieldElement.injectedObject != null) {\n                    continue;\n                }\n                Class<?> injectedType = fieldElement.field.getType();\n                AnnotationAttributes attributes = fieldElement.attributes;\n                String referenceBeanName = registerReferenceBean(\n                        fieldElement.getPropertyName(), injectedType, attributes, fieldElement.field);\n\n                // associate fieldElement and reference bean\n                fieldElement.injectedObject = referenceBeanName;\n                injectedFieldReferenceBeanCache.put(fieldElement, referenceBeanName);\n            }\n\n            for (AnnotatedMethodElement methodElement : metadata.getMethodElements()) {\n                if (methodElement.injectedObject != null) {\n                    continue;\n                }\n                Class<?> injectedType = methodElement.getInjectedType();\n                AnnotationAttributes attributes = methodElement.attributes;\n                String referenceBeanName = registerReferenceBean(\n                        methodElement.getPropertyName(), injectedType, attributes, methodElement.method);\n\n                // associate methodElement and reference bean\n                methodElement.injectedObject = referenceBeanName;\n                injectedMethodReferenceBeanCache.put(methodElement, referenceBeanName);\n            }\n        } catch (ClassNotFoundException e) {\n            throw new BeanCreationException(\"prepare reference annotation failed\", e);\n        }\n    }\n\n    public String registerReferenceBean(\n            String propertyName, Class<?> injectedType, Map<String, Object> attributes, Member member)\n            throws BeansException {\n\n        boolean renameable = true;\n        // referenceBeanName\n        String referenceBeanName = AnnotationUtils.getAttribute(attributes, ReferenceAttributes.ID);\n        if (hasText(referenceBeanName)) {\n            renameable = false;\n        } else {\n            referenceBeanName = propertyName;\n        }\n\n        String checkLocation = \"Please check \" + member.toString();\n\n        // convert annotation props\n        ReferenceBeanSupport.convertReferenceProps(attributes, injectedType);\n\n        // get interface\n        String interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE);\n        if (StringUtils.isBlank(interfaceName)) {\n            throw new BeanCreationException(\n                    \"Need to specify the 'interfaceName' or 'interfaceClass' attribute of '@DubboReference' if enable generic. \"\n                            + checkLocation);\n        }\n\n        // check reference key\n        String referenceKey = ReferenceBeanSupport.generateReferenceKey(attributes, applicationContext);\n\n        // find reference bean name by reference key\n        List<String> registeredReferenceBeanNames = referenceBeanManager.getBeanNamesByKey(referenceKey);\n        if (registeredReferenceBeanNames.size() > 0) {\n            // found same name and reference key\n            if (registeredReferenceBeanNames.contains(referenceBeanName)) {\n                return referenceBeanName;\n            }\n        }\n\n        // check bean definition\n        boolean isContains;\n        if ((isContains = beanDefinitionRegistry.containsBeanDefinition(referenceBeanName))\n                || beanDefinitionRegistry.isAlias(referenceBeanName)) {\n            String preReferenceBeanName = referenceBeanName;\n            if (!isContains) {\n                // Look in the alias for the origin bean name\n                String[] aliases = beanDefinitionRegistry.getAliases(referenceBeanName);\n                if (ArrayUtils.isNotEmpty(aliases)) {\n                    for (String alias : aliases) {\n                        if (beanDefinitionRegistry.containsBeanDefinition(alias)) {\n                            preReferenceBeanName = alias;\n                            break;\n                        }\n                    }\n                }\n            }\n            BeanDefinition prevBeanDefinition = beanDefinitionRegistry.getBeanDefinition(preReferenceBeanName);\n            String prevBeanType = prevBeanDefinition.getBeanClassName();\n            String prevBeanDesc = referenceBeanName + \"[\" + prevBeanType + \"]\";\n            String newBeanDesc = referenceBeanName + \"[\" + referenceKey + \"]\";\n\n            if (isReferenceBean(prevBeanDefinition)) {\n                // check reference key\n                String prevReferenceKey =\n                        ReferenceBeanSupport.generateReferenceKey(prevBeanDefinition, applicationContext);\n                if (StringUtils.isEquals(prevReferenceKey, referenceKey)) {\n                    // found matched dubbo reference bean, ignore register\n                    return referenceBeanName;\n                }\n                // get interfaceName from attribute\n                Assert.notNull(prevBeanDefinition, \"The interface class of ReferenceBean is not initialized\");\n                prevBeanDesc = referenceBeanName + \"[\" + prevReferenceKey + \"]\";\n            }\n\n            // bean name from attribute 'id' or java-config bean, cannot be renamed\n            if (!renameable) {\n                throw new BeanCreationException(\n                        \"Already exists another bean definition with the same bean name [\" + referenceBeanName + \"], \"\n                                + \"but cannot rename the reference bean name (specify the id attribute or java-config bean), \"\n                                + \"please modify the name of one of the beans: \"\n                                + \"prev: \"\n                                + prevBeanDesc + \", new: \" + newBeanDesc + \". \" + checkLocation);\n            }\n\n            // the prev bean type is different, rename the new reference bean\n            int index = 2;\n            String newReferenceBeanName = null;\n            while (newReferenceBeanName == null\n                    || beanDefinitionRegistry.containsBeanDefinition(newReferenceBeanName)\n                    || beanDefinitionRegistry.isAlias(newReferenceBeanName)) {\n                newReferenceBeanName = referenceBeanName + \"#\" + index;\n                index++;\n                // double check found same name and reference key\n                if (registeredReferenceBeanNames.contains(newReferenceBeanName)) {\n                    return newReferenceBeanName;\n                }\n            }\n            newBeanDesc = newReferenceBeanName + \"[\" + referenceKey + \"]\";\n\n            logger.warn(\n                    CONFIG_DUBBO_BEAN_INITIALIZER,\n                    \"\",\n                    \"\",\n                    \"Already exists another bean definition with the same bean name [\" + referenceBeanName + \"], \"\n                            + \"rename dubbo reference bean to [\"\n                            + newReferenceBeanName + \"]. \"\n                            + \"It is recommended to modify the name of one of the beans to avoid injection problems. \"\n                            + \"prev: \"\n                            + prevBeanDesc + \", new: \" + newBeanDesc + \". \" + checkLocation);\n            referenceBeanName = newReferenceBeanName;\n        }\n        attributes.put(ReferenceAttributes.ID, referenceBeanName);\n\n        // If registered matched reference before, just register alias\n        if (registeredReferenceBeanNames.size() > 0) {\n            beanDefinitionRegistry.registerAlias(registeredReferenceBeanNames.get(0), referenceBeanName);\n            referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);\n            return referenceBeanName;\n        }\n\n        Class interfaceClass = injectedType;\n\n        // TODO Only register one reference bean for same (group, interface, version)\n\n        // Register the reference bean definition to the beanFactory\n        RootBeanDefinition beanDefinition = new RootBeanDefinition();\n        beanDefinition.setBeanClassName(ReferenceBean.class.getName());\n        beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, referenceBeanName);\n\n        // set attribute instead of property values\n        beanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);\n        beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);\n        beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);\n\n        beanDefinition.getPropertyValues().add(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);\n        beanDefinition.getPropertyValues().add(ReferenceAttributes.INTERFACE_NAME, interfaceName);\n\n        if (AotWithSpringDetector.isAotProcessing()) {\n            beanDefinition.getPropertyValues().add(\"referencePropsJson\", JsonUtils.toJson(attributes));\n        }\n        // create decorated definition for reference bean, Avoid being instantiated when getting the beanType of\n        // ReferenceBean\n        // see org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean()\n        GenericBeanDefinition targetDefinition = new GenericBeanDefinition();\n        targetDefinition.setBeanClass(interfaceClass);\n        beanDefinition.setDecoratedDefinition(\n                new BeanDefinitionHolder(targetDefinition, referenceBeanName + \"_decorated\"));\n\n        // signal object type since Spring 5.2\n        beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);\n\n        beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);\n        referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);\n        logger.info(\"Register dubbo reference bean: \" + referenceBeanName + \" = \" + referenceKey + \" at \" + member);\n        return referenceBeanName;\n    }\n\n    @Override\n    protected Object doGetInjectedBean(\n            AnnotationAttributes attributes,\n            Object bean,\n            String beanName,\n            Class<?> injectedType,\n            AnnotatedInjectElement injectedElement)\n            throws Exception {\n\n        if (injectedElement.injectedObject == null) {\n            throw new IllegalStateException(\n                    \"The AnnotatedInjectElement of @DubboReference should be inited before injection\");\n        }\n\n        return getBeanFactory().getBean((String) injectedElement.injectedObject);\n    }\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        this.applicationContext = applicationContext;\n        this.referenceBeanManager =\n                applicationContext.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);\n        this.beanDefinitionRegistry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();\n    }\n\n    @Override\n    public void destroy() throws Exception {\n        super.destroy();\n        this.injectedFieldReferenceBeanCache.clear();\n        this.injectedMethodReferenceBeanCache.clear();\n    }\n\n    /**\n     * Gets all beans of {@link ReferenceBean}\n     *\n     * @deprecated use {@link ReferenceBeanManager#getReferences()} instead\n     */\n    @Deprecated\n    public Collection<ReferenceBean<?>> getReferenceBeans() {\n        return Collections.emptyList();\n    }\n\n    /**\n     * Get {@link ReferenceBean} {@link Map} in injected field.\n     *\n     * @return non-null {@link Map}\n     * @since 2.5.11\n     */\n    public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedFieldReferenceBeanMap() {\n        Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> map = new HashMap<>();\n        for (Map.Entry<InjectionMetadata.InjectedElement, String> entry : injectedFieldReferenceBeanCache.entrySet()) {\n            map.put(entry.getKey(), referenceBeanManager.getById(entry.getValue()));\n        }\n        return Collections.unmodifiableMap(map);\n    }\n\n    /**\n     * Get {@link ReferenceBean} {@link Map} in injected method.\n     *\n     * @return non-null {@link Map}\n     * @since 2.5.11\n     */\n    public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedMethodReferenceBeanMap() {\n        Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> map = new HashMap<>();\n        for (Map.Entry<InjectionMetadata.InjectedElement, String> entry : injectedMethodReferenceBeanCache.entrySet()) {\n            map.put(entry.getKey(), referenceBeanManager.getById(entry.getValue()));\n        }\n        return Collections.unmodifiableMap(map);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.common.compact.Dubbo2CompactUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.AnnotationUtils;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.Constants;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.spring.ServiceBean;\nimport org.apache.dubbo.config.spring.aot.AotWithSpringDetector;\nimport org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner;\nimport org.apache.dubbo.config.spring.schema.AnnotationBeanDefinitionParser;\nimport org.apache.dubbo.config.spring.util.DubboAnnotationUtils;\nimport org.apache.dubbo.config.spring.util.ObjectUtils;\nimport org.apache.dubbo.config.spring.util.SpringCompatUtils;\n\nimport java.io.IOException;\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.BeanDefinitionStoreException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinitionHolder;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.config.SingletonBeanRegistry;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.beans.factory.xml.BeanDefinitionParser;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.ResourceLoaderAware;\nimport org.springframework.context.annotation.AnnotationBeanNameGenerator;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.springframework.context.annotation.ClassPathBeanDefinitionScanner;\nimport org.springframework.context.annotation.ConfigurationClassPostProcessor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.type.MethodMetadata;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\nimport org.springframework.core.type.filter.TypeFilter;\nimport org.springframework.util.CollectionUtils;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUPLICATED_BEAN_DEFINITION;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_NO_ANNOTATIONS_FOUND;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_NO_BEANS_SCANNED;\nimport static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;\nimport static org.apache.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilder.create;\nimport static org.apache.dubbo.config.spring.util.DubboAnnotationUtils.resolveInterfaceName;\nimport static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;\nimport static org.springframework.context.annotation.AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR;\nimport static org.springframework.util.ClassUtils.resolveClassName;\n\n/**\n * A {@link BeanFactoryPostProcessor} used for processing of {@link Service @Service} annotated classes and annotated bean in java config classes.\n * It's also the infrastructure class of XML {@link BeanDefinitionParser} on &lt;dubbo:annotation /&gt;\n *\n * @see AnnotationBeanDefinitionParser\n * @see BeanDefinitionRegistryPostProcessor\n * @since 2.7.7\n */\npublic class ServiceAnnotationPostProcessor\n        implements BeanDefinitionRegistryPostProcessor,\n                EnvironmentAware,\n                ResourceLoaderAware,\n                BeanClassLoaderAware,\n                ApplicationContextAware,\n                InitializingBean {\n\n    public static final String BEAN_NAME = \"dubboServiceAnnotationPostProcessor\";\n\n    private static final List<Class<? extends Annotation>> serviceAnnotationTypes = loadServiceAnnotationTypes();\n\n    private static List<Class<? extends Annotation>> loadServiceAnnotationTypes() {\n        if (Dubbo2CompactUtils.isEnabled() && Dubbo2CompactUtils.isServiceClassLoaded()) {\n            return asList(\n                    // @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007\n                    DubboService.class,\n                    // @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.Service\n                    Service.class,\n                    // @since 2.7.3 Add the compatibility for legacy Dubbo's @Service , the issue :\n                    // https://github.com/apache/dubbo/issues/4330\n                    Dubbo2CompactUtils.getServiceClass());\n        } else {\n            return asList(\n                    // @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007\n                    DubboService.class,\n                    // @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.Service\n                    Service.class);\n        }\n    }\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    protected final Set<String> packagesToScan;\n\n    private Set<String> resolvedPackagesToScan;\n\n    private Environment environment;\n\n    private ResourceLoader resourceLoader;\n\n    private ClassLoader classLoader;\n\n    private BeanDefinitionRegistry registry;\n\n    protected ServicePackagesHolder servicePackagesHolder;\n\n    private volatile boolean scanned = false;\n\n    public ServiceAnnotationPostProcessor(String... packagesToScan) {\n        this(asList(packagesToScan));\n    }\n\n    public ServiceAnnotationPostProcessor(Collection<?> packagesToScan) {\n        this.packagesToScan = (Set<String>) packagesToScan.stream().collect(Collectors.toSet());\n    }\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        this.resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);\n    }\n\n    @Override\n    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {\n        this.registry = registry;\n        scanServiceBeans(resolvedPackagesToScan, registry);\n    }\n\n    @Override\n    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n        if (this.registry == null) {\n            // In spring 3.x, may be not call postProcessBeanDefinitionRegistry()\n            this.registry = (BeanDefinitionRegistry) beanFactory;\n        }\n\n        // scan bean definitions\n        String[] beanNames = beanFactory.getBeanDefinitionNames();\n        for (String beanName : beanNames) {\n            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);\n            Map<String, Object> annotationAttributes = getServiceAnnotationAttributes(beanDefinition);\n            if (annotationAttributes != null) {\n                // process @DubboService at java-config @bean method\n                processAnnotatedBeanDefinition(\n                        beanName, (AnnotatedBeanDefinition) beanDefinition, annotationAttributes);\n            }\n        }\n\n        if (!scanned) {\n            // In spring 3.x, may be not call postProcessBeanDefinitionRegistry(), so scan service class here\n            scanServiceBeans(resolvedPackagesToScan, registry);\n        }\n    }\n\n    /**\n     * Scan and registers service beans whose classes was annotated {@link Service}\n     *\n     * @param packagesToScan The base packages to scan\n     * @param registry       {@link BeanDefinitionRegistry}\n     */\n    private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {\n\n        scanned = true;\n        if (CollectionUtils.isEmpty(packagesToScan)) {\n            if (logger.isWarnEnabled()) {\n                logger.warn(\n                        CONFIG_NO_BEANS_SCANNED,\n                        \"\",\n                        \"\",\n                        \"packagesToScan is empty , ServiceBean registry will be ignored!\");\n            }\n            return;\n        }\n\n        DubboClassPathBeanDefinitionScanner scanner =\n                new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);\n\n        BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);\n        scanner.setBeanNameGenerator(beanNameGenerator);\n        for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {\n            scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));\n        }\n\n        ScanExcludeFilter scanExcludeFilter = new ScanExcludeFilter();\n        scanner.addExcludeFilter(scanExcludeFilter);\n\n        for (String packageToScan : packagesToScan) {\n\n            // avoid duplicated scans\n            if (servicePackagesHolder.isPackageScanned(packageToScan)) {\n                if (logger.isInfoEnabled()) {\n                    logger.info(\"Ignore package who has already bean scanned: \" + packageToScan);\n                }\n                continue;\n            }\n\n            if (AotWithSpringDetector.useGeneratedArtifacts()) {\n                scanner.setIncludeAnnotationConfig(false);\n            }\n            // Registers @Service Bean first\n            scanner.scan(packageToScan);\n\n            // Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.\n            Set<BeanDefinitionHolder> beanDefinitionHolders =\n                    findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);\n\n            if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {\n                if (logger.isInfoEnabled()) {\n                    List<String> serviceClasses = new ArrayList<>(beanDefinitionHolders.size());\n                    for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {\n                        serviceClasses.add(\n                                beanDefinitionHolder.getBeanDefinition().getBeanClassName());\n                    }\n                    logger.info(\"Found \" + beanDefinitionHolders.size()\n                            + \" classes annotated by Dubbo @Service under package [\" + packageToScan + \"]: \"\n                            + serviceClasses);\n                }\n\n                for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {\n                    processScannedBeanDefinition(beanDefinitionHolder);\n                    servicePackagesHolder.addScannedClass(\n                            beanDefinitionHolder.getBeanDefinition().getBeanClassName());\n                }\n            } else {\n                if (logger.isWarnEnabled()) {\n                    logger.warn(\n                            CONFIG_NO_ANNOTATIONS_FOUND,\n                            \"No annotations were found on the class\",\n                            \"\",\n                            \"No class annotated by Dubbo @DubboService or @Service was found under package [\"\n                                    + packageToScan + \"], ignore re-scanned classes: \"\n                                    + scanExcludeFilter.getExcludedCount());\n                }\n            }\n\n            servicePackagesHolder.addScannedPackage(packageToScan);\n        }\n    }\n\n    /**\n     * It'd be better to use BeanNameGenerator instance that should reference\n     * {@link ConfigurationClassPostProcessor#componentScanBeanNameGenerator},\n     * thus it maybe a potential problem on bean name generation.\n     *\n     * @param registry {@link BeanDefinitionRegistry}\n     * @return {@link BeanNameGenerator} instance\n     * @see SingletonBeanRegistry\n     * @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR\n     * @see ConfigurationClassPostProcessor#processConfigBeanDefinitions\n     * @since 2.5.8\n     */\n    private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry registry) {\n\n        BeanNameGenerator beanNameGenerator = null;\n\n        if (registry instanceof SingletonBeanRegistry) {\n            SingletonBeanRegistry singletonBeanRegistry = SingletonBeanRegistry.class.cast(registry);\n            beanNameGenerator =\n                    (BeanNameGenerator) singletonBeanRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);\n        }\n\n        if (beanNameGenerator == null) {\n\n            if (logger.isInfoEnabled()) {\n\n                logger.info(\"BeanNameGenerator bean can't be found in BeanFactory with name [\"\n                        + CONFIGURATION_BEAN_NAME_GENERATOR + \"]\");\n                logger.info(\"BeanNameGenerator will be a instance of \" + AnnotationBeanNameGenerator.class.getName()\n                        + \" , it maybe a potential problem on bean name generation.\");\n            }\n\n            beanNameGenerator = new AnnotationBeanNameGenerator();\n        }\n\n        return beanNameGenerator;\n    }\n\n    /**\n     * Finds a {@link Set} of {@link BeanDefinitionHolder BeanDefinitionHolders} whose bean type annotated\n     * {@link Service} Annotation.\n     *\n     * @param scanner       {@link ClassPathBeanDefinitionScanner}\n     * @param packageToScan package to scan\n     * @param registry      {@link BeanDefinitionRegistry}\n     * @return non-null\n     * @since 2.5.8\n     */\n    private Set<BeanDefinitionHolder> findServiceBeanDefinitionHolders(\n            ClassPathBeanDefinitionScanner scanner,\n            String packageToScan,\n            BeanDefinitionRegistry registry,\n            BeanNameGenerator beanNameGenerator) {\n\n        Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(packageToScan);\n\n        Set<BeanDefinitionHolder> beanDefinitionHolders = new LinkedHashSet<>(beanDefinitions.size());\n\n        for (BeanDefinition beanDefinition : beanDefinitions) {\n\n            String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);\n            BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);\n            beanDefinitionHolders.add(beanDefinitionHolder);\n        }\n\n        return beanDefinitionHolders;\n    }\n\n    /**\n     * Registers {@link ServiceBean} from new annotated {@link Service} {@link BeanDefinition}\n     *\n     * @param beanDefinitionHolder\n     * @see ServiceBean\n     * @see BeanDefinition\n     */\n    private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder) {\n\n        Class<?> beanClass = resolveClass(beanDefinitionHolder);\n\n        Annotation service = findServiceAnnotation(beanClass);\n\n        // The attributes of @Service annotation\n        Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);\n\n        String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);\n\n        String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();\n\n        // ServiceBean Bean name\n        String beanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);\n\n        AbstractBeanDefinition serviceBeanDefinition =\n                buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, annotatedServiceBeanName);\n\n        registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);\n    }\n\n    /**\n     * Find the {@link Annotation annotation} of @Service\n     *\n     * @param beanClass the {@link Class class} of Bean\n     * @return <code>null</code> if not found\n     * @since 2.7.3\n     */\n    private Annotation findServiceAnnotation(Class<?> beanClass) {\n        return serviceAnnotationTypes.stream()\n                .map(annotationType -> ClassUtils.isPresent(\n                                        \"org.springframework.core.annotation.AnnotatedElementUtils\",\n                                        Thread.currentThread().getContextClassLoader())\n                                && ReflectUtils.hasMethod(\n                                        org.springframework.core.annotation.AnnotatedElementUtils.class,\n                                        \"findMergedAnnotation\")\n                        ? org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation(\n                                beanClass, annotationType)\n                        : org.apache.dubbo.common.utils.AnnotationUtils.findAnnotation(beanClass, annotationType))\n                .filter(Objects::nonNull)\n                .findFirst()\n                .orElse(null);\n    }\n\n    /**\n     * Generates the bean name of {@link ServiceBean}\n     *\n     * @param serviceAnnotationAttributes\n     * @param serviceInterface            the class of interface annotated {@link Service}\n     * @return ServiceBean@interfaceClassName#annotatedServiceBeanName\n     * @since 2.7.3\n     */\n    private String generateServiceBeanName(Map<String, Object> serviceAnnotationAttributes, String serviceInterface) {\n        ServiceBeanNameBuilder builder = create(serviceInterface, environment)\n                .group((String) serviceAnnotationAttributes.get(\"group\"))\n                .version((String) serviceAnnotationAttributes.get(\"version\"));\n        return builder.build();\n    }\n\n    private Class<?> resolveClass(BeanDefinitionHolder beanDefinitionHolder) {\n\n        BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();\n\n        return resolveClass(beanDefinition);\n    }\n\n    private Class<?> resolveClass(BeanDefinition beanDefinition) {\n\n        String beanClassName = beanDefinition.getBeanClassName();\n\n        return resolveClassName(beanClassName, classLoader);\n    }\n\n    private Set<String> resolvePackagesToScan(Set<String> packagesToScan) {\n        Set<String> resolvedPackagesToScan = new LinkedHashSet<>(packagesToScan.size());\n        for (String packageToScan : packagesToScan) {\n            if (StringUtils.hasText(packageToScan)) {\n                String resolvedPackageToScan = environment.resolvePlaceholders(packageToScan.trim());\n                resolvedPackagesToScan.add(resolvedPackageToScan);\n            }\n        }\n        return resolvedPackagesToScan;\n    }\n\n    /**\n     * Build the {@link AbstractBeanDefinition Bean Definition}\n     *\n     * @param serviceAnnotationAttributes\n     * @param serviceInterface\n     * @param refServiceBeanName\n     * @return\n     * @since 2.7.3\n     */\n    private AbstractBeanDefinition buildServiceBeanDefinition(\n            Map<String, Object> serviceAnnotationAttributes, String serviceInterface, String refServiceBeanName) {\n\n        BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);\n\n        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();\n        beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);\n\n        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();\n\n        String[] ignoreAttributeNames = ObjectUtils.of(\n                \"provider\",\n                \"monitor\",\n                \"application\",\n                \"module\",\n                \"registry\",\n                \"protocol\",\n                \"methods\",\n                \"interfaceName\",\n                \"parameters\",\n                \"executor\");\n\n        propertyValues.addPropertyValues(\n                new AnnotationPropertyValuesAdapter(serviceAnnotationAttributes, environment, ignoreAttributeNames));\n\n        // set config id, for ConfigManager cache key\n        // builder.addPropertyValue(\"id\", beanName);\n        // References \"ref\" property to annotated-@Service Bean\n        addPropertyReference(builder, \"ref\", refServiceBeanName);\n        // Set interface\n        builder.addPropertyValue(\"interface\", serviceInterface);\n        // Convert parameters into map\n        builder.addPropertyValue(\"parameters\", DubboAnnotationUtils.convertParameters((String[])\n                serviceAnnotationAttributes.get(\"parameters\")));\n        // Add methods parameters\n        List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get(\"methods\"));\n        if (!methodConfigs.isEmpty()) {\n            if (AotWithSpringDetector.isAotProcessing()) {\n                List<String> methodsJson = new ArrayList<>();\n                methodConfigs.forEach(methodConfig -> methodsJson.add(JsonUtils.toJson(methodConfig)));\n                builder.addPropertyValue(\"methodsJson\", methodsJson);\n            } else {\n                builder.addPropertyValue(\"methods\", methodConfigs);\n            }\n        }\n\n        // convert provider to providerIds\n        String providerConfigId = (String) serviceAnnotationAttributes.get(\"provider\");\n        if (StringUtils.hasText(providerConfigId)) {\n            addPropertyValue(builder, \"providerIds\", providerConfigId);\n        }\n\n        // Convert registry[] to registryIds\n        String[] registryConfigIds = (String[]) serviceAnnotationAttributes.get(\"registry\");\n        if (registryConfigIds != null && registryConfigIds.length > 0) {\n            resolveStringArray(registryConfigIds);\n            builder.addPropertyValue(\"registryIds\", StringUtils.join(registryConfigIds, ','));\n        }\n\n        // Convert protocol[] to protocolIds\n        String[] protocolConfigIds = (String[]) serviceAnnotationAttributes.get(\"protocol\");\n        if (protocolConfigIds != null && protocolConfigIds.length > 0) {\n            resolveStringArray(protocolConfigIds);\n            builder.addPropertyValue(\"protocolIds\", StringUtils.join(protocolConfigIds, ','));\n        }\n\n        // TODO Could we ignore these attributes: application/monitor/module ? Use global config\n        // monitor reference\n        String monitorConfigId = (String) serviceAnnotationAttributes.get(\"monitor\");\n        if (StringUtils.hasText(monitorConfigId)) {\n            addPropertyReference(builder, \"monitor\", monitorConfigId);\n        }\n\n        // module reference\n        String moduleConfigId = (String) serviceAnnotationAttributes.get(\"module\");\n        if (StringUtils.hasText(moduleConfigId)) {\n            addPropertyReference(builder, \"module\", moduleConfigId);\n        }\n\n        String executorBeanName = (String) serviceAnnotationAttributes.get(\"executor\");\n        if (StringUtils.hasText(executorBeanName)) {\n            addPropertyReference(builder, \"executor\", executorBeanName);\n        }\n\n        // service bean definition should not be lazy\n        builder.setLazyInit(false);\n\n        return builder.getBeanDefinition();\n    }\n\n    private String[] resolveStringArray(String[] strs) {\n        if (strs == null) {\n            return null;\n        }\n        for (int i = 0; i < strs.length; i++) {\n            strs[i] = environment.resolvePlaceholders(strs[i]);\n        }\n        return strs;\n    }\n\n    private List convertMethodConfigs(Object methodsAnnotation) {\n        if (methodsAnnotation == null) {\n            return Collections.EMPTY_LIST;\n        }\n        return MethodConfig.constructMethodConfig((Method[]) methodsAnnotation);\n    }\n\n    private void addPropertyReference(BeanDefinitionBuilder builder, String propertyName, String beanName) {\n        String resolvedBeanName = environment.resolvePlaceholders(beanName);\n        builder.addPropertyReference(propertyName, resolvedBeanName);\n    }\n\n    private void addPropertyValue(BeanDefinitionBuilder builder, String propertyName, String value) {\n        String resolvedBeanName = environment.resolvePlaceholders(value);\n        builder.addPropertyValue(propertyName, resolvedBeanName);\n    }\n\n    /**\n     * Get dubbo service annotation class at java-config @bean method\n     *\n     * @return return service annotation attributes map if found, or return null if not found.\n     */\n    private Map<String, Object> getServiceAnnotationAttributes(BeanDefinition beanDefinition) {\n        if (beanDefinition instanceof AnnotatedBeanDefinition) {\n            AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;\n            MethodMetadata factoryMethodMetadata = SpringCompatUtils.getFactoryMethodMetadata(annotatedBeanDefinition);\n            if (factoryMethodMetadata != null) {\n                // try all dubbo service annotation types\n                for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {\n                    if (factoryMethodMetadata.isAnnotated(annotationType.getName())) {\n                        // Since Spring 5.2\n                        // return\n                        // factoryMethodMetadata.getAnnotations().get(annotationType).filterDefaultValues().asMap();\n                        // Compatible with Spring 4.x\n                        Map<String, Object> annotationAttributes =\n                                factoryMethodMetadata.getAnnotationAttributes(annotationType.getName());\n                        return filterDefaultValues(annotationType, annotationAttributes);\n                    }\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * process @DubboService at java-config @bean method\n     * <pre class=\"code\">\n     * &#064;Configuration\n     * public class ProviderConfig {\n     *\n     *      &#064;Bean\n     *      &#064;DubboService(group=\"demo\", version=\"1.2.3\")\n     *      public DemoService demoService() {\n     *          return new DemoServiceImpl();\n     *      }\n     *\n     * }\n     * </pre>\n     *\n     * @param refServiceBeanName\n     * @param refServiceBeanDefinition\n     * @param attributes\n     */\n    private void processAnnotatedBeanDefinition(\n            String refServiceBeanName,\n            AnnotatedBeanDefinition refServiceBeanDefinition,\n            Map<String, Object> attributes) {\n\n        Map<String, Object> serviceAnnotationAttributes = new LinkedHashMap<>(attributes);\n\n        // get bean class from return type\n        String returnTypeName = SpringCompatUtils.getFactoryMethodReturnType(refServiceBeanDefinition);\n        Class<?> beanClass = resolveClassName(returnTypeName, classLoader);\n\n        String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);\n\n        // ServiceBean Bean name\n        String serviceBeanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);\n\n        AbstractBeanDefinition serviceBeanDefinition =\n                buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, refServiceBeanName);\n\n        // set id\n        serviceBeanDefinition.getPropertyValues().add(Constants.ID, serviceBeanName);\n\n        registerServiceBeanDefinition(serviceBeanName, serviceBeanDefinition, serviceInterface);\n    }\n\n    private void registerServiceBeanDefinition(\n            String serviceBeanName, AbstractBeanDefinition serviceBeanDefinition, String serviceInterface) {\n        // check service bean\n        if (registry.containsBeanDefinition(serviceBeanName)) {\n            BeanDefinition existingDefinition = registry.getBeanDefinition(serviceBeanName);\n            if (existingDefinition.equals(serviceBeanDefinition)) {\n                // exist equipment bean definition\n                return;\n            }\n\n            String msg = \"Found duplicated BeanDefinition of service interface [\" + serviceInterface\n                    + \"] with bean name [\" + serviceBeanName + \"], existing definition [ \" + existingDefinition\n                    + \"], new definition [\" + serviceBeanDefinition + \"]\";\n            logger.error(CONFIG_DUPLICATED_BEAN_DEFINITION, \"\", \"\", msg);\n            throw new BeanDefinitionStoreException(\n                    serviceBeanDefinition.getResourceDescription(), serviceBeanName, msg);\n        }\n\n        registry.registerBeanDefinition(serviceBeanName, serviceBeanDefinition);\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Register ServiceBean[\" + serviceBeanName + \"]: \" + serviceBeanDefinition);\n        }\n    }\n\n    @Override\n    public void setEnvironment(Environment environment) {\n        this.environment = environment;\n    }\n\n    @Override\n    public void setResourceLoader(ResourceLoader resourceLoader) {\n        this.resourceLoader = resourceLoader;\n    }\n\n    @Override\n    public void setBeanClassLoader(ClassLoader classLoader) {\n        this.classLoader = classLoader;\n    }\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        this.servicePackagesHolder =\n                applicationContext.getBean(ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);\n    }\n\n    private class ScanExcludeFilter implements TypeFilter {\n\n        private int excludedCount;\n\n        @Override\n        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n                throws IOException {\n            String className = metadataReader.getClassMetadata().getClassName();\n            boolean excluded = servicePackagesHolder.isClassScanned(className);\n            if (excluded) {\n                excludedCount++;\n            }\n            return excluded;\n        }\n\n        public int getExcludedCount() {\n            return excludedCount;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.ServiceBean;\nimport org.apache.dubbo.config.spring.util.AnnotationUtils;\n\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.StringUtils;\n\nimport static org.apache.dubbo.config.spring.util.DubboAnnotationUtils.resolveInterfaceName;\nimport static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;\n\n/**\n * Dubbo {@link Service @Service} Bean Builder\n *\n * @see Service\n * @see Reference\n * @see ServiceBean\n * @see ReferenceBean\n * @since 2.6.5\n */\npublic class ServiceBeanNameBuilder {\n\n    private static final String SEPARATOR = \":\";\n\n    // Required\n    private final String interfaceClassName;\n\n    private final Environment environment;\n\n    // Optional\n    private String version;\n\n    private String group;\n\n    private ServiceBeanNameBuilder(Class<?> interfaceClass, Environment environment) {\n        this(interfaceClass.getName(), environment);\n    }\n\n    private ServiceBeanNameBuilder(String interfaceClassName, Environment environment) {\n        this.interfaceClassName = interfaceClassName;\n        this.environment = environment;\n    }\n\n    private ServiceBeanNameBuilder(\n            AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {\n        this(resolveInterfaceName(attributes, defaultInterfaceClass), environment);\n        this.group(AnnotationUtils.getAttribute(attributes, \"group\"));\n        this.version(AnnotationUtils.getAttribute(attributes, \"version\"));\n    }\n\n    /**\n     * @param attributes\n     * @param defaultInterfaceClass\n     * @param environment\n     * @return\n     * @since 2.7.3\n     */\n    public static ServiceBeanNameBuilder create(\n            AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {\n        return new ServiceBeanNameBuilder(attributes, defaultInterfaceClass, environment);\n    }\n\n    public static ServiceBeanNameBuilder create(Class<?> interfaceClass, Environment environment) {\n        return new ServiceBeanNameBuilder(interfaceClass, environment);\n    }\n\n    public static ServiceBeanNameBuilder create(String interfaceClass, Environment environment) {\n        return new ServiceBeanNameBuilder(interfaceClass, environment);\n    }\n\n    public static ServiceBeanNameBuilder create(Service service, Class<?> interfaceClass, Environment environment) {\n        return create(getAnnotationAttributes(service, false, false), interfaceClass, environment);\n    }\n\n    public static ServiceBeanNameBuilder create(Reference reference, Class<?> interfaceClass, Environment environment) {\n        return create(getAnnotationAttributes(reference, false, false), interfaceClass, environment);\n    }\n\n    private static void append(StringBuilder builder, String value) {\n        builder.append(SEPARATOR);\n        if (StringUtils.hasText(value)) {\n            builder.append(value);\n        }\n    }\n\n    public ServiceBeanNameBuilder group(String group) {\n        this.group = group;\n        return this;\n    }\n\n    public ServiceBeanNameBuilder version(String version) {\n        this.version = version;\n        return this;\n    }\n\n    public String build() {\n        StringBuilder beanNameBuilder = new StringBuilder(\"ServiceBean\");\n        // Required\n        append(beanNameBuilder, interfaceClassName);\n        // Optional\n        append(beanNameBuilder, version);\n        append(beanNameBuilder, group);\n        // Build and remove last \":\"\n        String rawBeanName = beanNameBuilder.toString();\n        // Resolve placeholders\n        return environment.resolvePlaceholders(rawBeanName);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServicePackagesHolder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * A temp holder for scanned packages of service.\n */\npublic class ServicePackagesHolder {\n\n    public static final String BEAN_NAME = \"dubboServicePackagesHolder\";\n\n    private final Set<String> scannedPackages = new HashSet<>();\n\n    private final Set<String> scannedClasses = new HashSet<>();\n\n    public void addScannedPackage(String apackage) {\n        apackage = normalizePackage(apackage);\n        synchronized (scannedPackages) {\n            scannedPackages.add(apackage);\n        }\n    }\n\n    public boolean isPackageScanned(String packageName) {\n        packageName = normalizePackage(packageName);\n        synchronized (scannedPackages) {\n            if (scannedPackages.contains(packageName)) {\n                return true;\n            }\n            for (String scannedPackage : scannedPackages) {\n                if (isSubPackage(packageName, scannedPackage)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    public void addScannedClass(String className) {\n        synchronized (scannedClasses) {\n            scannedClasses.add(className);\n        }\n    }\n\n    public boolean isClassScanned(String className) {\n        synchronized (scannedClasses) {\n            return scannedClasses.contains(className);\n        }\n    }\n\n    /**\n     * Whether test package is sub package of parent package\n     * @param testPkg\n     * @param parent\n     * @return\n     */\n    private boolean isSubPackage(String testPkg, String parent) {\n        // child pkg startsWith parent pkg\n        return testPkg.startsWith(parent);\n    }\n\n    private String normalizePackage(String apackage) {\n        if (!apackage.endsWith(\".\")) {\n            apackage += \".\";\n        }\n        return apackage;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/config/ConfigurableSourceBeanMetadataElement.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.config;\n\nimport org.springframework.beans.BeanMetadataAttributeAccessor;\nimport org.springframework.beans.BeanMetadataElement;\n\n/**\n * Configurable the {@link BeanMetadataAttributeAccessor#setSource(Object) source} for {@link BeanMetadataElement}\n *\n * @since 2.7.5\n */\npublic interface ConfigurableSourceBeanMetadataElement {\n\n    /**\n     * Set the source into the specified {@link BeanMetadataElement}\n     *\n     * @param beanMetadataElement {@link BeanMetadataElement} instance\n     */\n    default void setSource(BeanMetadataElement beanMetadataElement) {\n        if (beanMetadataElement instanceof BeanMetadataAttributeAccessor) {\n            ((BeanMetadataAttributeAccessor) beanMetadataElement).setSource(this);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigDefaultPropertyValueBeanPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.config;\n\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.Constants;\nimport org.apache.dubbo.config.spring.util.GenericBeanPostProcessorAdapter;\nimport org.apache.dubbo.config.spring.util.ObjectUtils;\n\nimport javax.annotation.PostConstruct;\n\nimport java.beans.PropertyDescriptor;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.PriorityOrdered;\n\nimport static org.springframework.aop.support.AopUtils.getTargetClass;\nimport static org.springframework.beans.BeanUtils.getPropertyDescriptor;\nimport static org.springframework.util.ReflectionUtils.invokeMethod;\n\n/**\n * The {@link BeanPostProcessor} class for the default property value of {@link AbstractConfig Dubbo's Config Beans}\n *\n * @since 2.7.6\n */\npublic class DubboConfigDefaultPropertyValueBeanPostProcessor extends GenericBeanPostProcessorAdapter<AbstractConfig>\n        implements MergedBeanDefinitionPostProcessor, PriorityOrdered {\n\n    /**\n     * The bean name of {@link DubboConfigDefaultPropertyValueBeanPostProcessor}\n     */\n    public static final String BEAN_NAME = \"dubboConfigDefaultPropertyValueBeanPostProcessor\";\n\n    @Override\n    protected void processBeforeInitialization(AbstractConfig dubboConfigBean, String beanName) throws BeansException {\n        // ignore auto generate bean name\n        if (!beanName.contains(\"#\")) {\n            // [Feature] https://github.com/apache/dubbo/issues/5721\n            setPropertyIfAbsent(dubboConfigBean, Constants.ID, beanName);\n\n            // beanName should not be used as config name, fix https://github.com/apache/dubbo/pull/7624\n            // setPropertyIfAbsent(dubboConfigBean, \"name\", beanName);\n        }\n    }\n\n    @Override\n    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {\n        // DO NOTHING\n    }\n\n    protected void setPropertyIfAbsent(Object bean, String propertyName, String beanName) {\n\n        Class<?> beanClass = getTargetClass(bean);\n\n        PropertyDescriptor propertyDescriptor = getPropertyDescriptor(beanClass, propertyName);\n\n        if (propertyDescriptor != null) { // the property is present\n\n            Method getterMethod = propertyDescriptor.getReadMethod();\n\n            if (getterMethod == null) { // if The getter method is absent\n                return;\n            }\n\n            Object propertyValue = invokeMethod(getterMethod, bean);\n\n            if (propertyValue != null) { // If The return value of \"getId\" method is not null\n                return;\n            }\n\n            Method setterMethod = propertyDescriptor.getWriteMethod();\n            if (setterMethod != null) { // the getter and setter methods are present\n                if (Arrays.equals(\n                        ObjectUtils.of(String.class), setterMethod.getParameterTypes())) { // the param type is String\n                    // set bean name to the value of the property\n                    invokeMethod(setterMethod, bean, beanName);\n                }\n            }\n        }\n    }\n\n    /**\n     * @return Higher than {@link InitDestroyAnnotationBeanPostProcessor#getOrder()}\n     * @see InitDestroyAnnotationBeanPostProcessor\n     * @see CommonAnnotationBeanPostProcessor\n     * @see PostConstruct\n     */\n    @Override\n    public int getOrder() {\n        return Ordered.LOWEST_PRECEDENCE + 1;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapApplicationListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.bootstrap.BootstrapTakeoverMode;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.context.event.DubboConfigInitEvent;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ApplicationContextEvent;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.core.Ordered;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_INITIALIZER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_NOT_FOUND;\nimport static org.springframework.util.ObjectUtils.nullSafeEquals;\n\n/**\n * The {@link ApplicationListener} for {@link DubboBootstrap}'s lifecycle when the {@link ContextRefreshedEvent}\n * and {@link ContextClosedEvent} raised\n *\n * @since 2.7.5\n */\n@Deprecated\npublic class DubboBootstrapApplicationListener implements ApplicationListener, ApplicationContextAware, Ordered {\n\n    /**\n     * The bean name of {@link DubboBootstrapApplicationListener}\n     *\n     * @since 2.7.6\n     */\n    public static final String BEAN_NAME = \"dubboBootstrapApplicationListener\";\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private ApplicationContext applicationContext;\n    private DubboBootstrap bootstrap;\n    private boolean shouldInitConfigBeans;\n    private ModuleModel moduleModel;\n\n    public DubboBootstrapApplicationListener() {}\n\n    public DubboBootstrapApplicationListener(boolean shouldInitConfigBeans) {\n        // maybe register DubboBootstrapApplicationListener manual during spring context starting\n        this.shouldInitConfigBeans = shouldInitConfigBeans;\n    }\n\n    private void setBootstrap(DubboBootstrap bootstrap) {\n        this.bootstrap = bootstrap;\n        if (bootstrap.getTakeoverMode() != BootstrapTakeoverMode.MANUAL) {\n            bootstrap.setTakeoverMode(BootstrapTakeoverMode.SPRING);\n        }\n    }\n\n    @Override\n    public void onApplicationEvent(ApplicationEvent event) {\n        if (isOriginalEventSource(event)) {\n            if (event instanceof DubboConfigInitEvent) {\n                // This event will be notified at AbstractApplicationContext.registerListeners(),\n                // init dubbo config beans before spring singleton beans\n                initDubboConfigBeans();\n            } else if (event instanceof ApplicationContextEvent) {\n                this.onApplicationContextEvent((ApplicationContextEvent) event);\n            }\n        }\n    }\n\n    private void initDubboConfigBeans() {\n        // load DubboConfigBeanInitializer to init config beans\n        if (applicationContext.containsBean(DubboConfigBeanInitializer.BEAN_NAME)) {\n            applicationContext.getBean(DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);\n        } else {\n            logger.warn(\n                    CONFIG_DUBBO_BEAN_NOT_FOUND,\n                    \"\",\n                    \"\",\n                    \"Bean '\" + DubboConfigBeanInitializer.BEAN_NAME + \"' was not found\");\n        }\n\n        // All infrastructure config beans are loaded, initialize dubbo here\n        moduleModel.getDeployer().initialize();\n    }\n\n    private void onApplicationContextEvent(ApplicationContextEvent event) {\n        if (DubboBootstrapStartStopListenerSpringAdapter.applicationContext == null) {\n            DubboBootstrapStartStopListenerSpringAdapter.applicationContext = event.getApplicationContext();\n        }\n\n        if (event instanceof ContextRefreshedEvent) {\n            onContextRefreshedEvent((ContextRefreshedEvent) event);\n        } else if (event instanceof ContextClosedEvent) {\n            onContextClosedEvent((ContextClosedEvent) event);\n        }\n    }\n\n    private void onContextRefreshedEvent(ContextRefreshedEvent event) {\n        if (bootstrap.getTakeoverMode() == BootstrapTakeoverMode.SPRING) {\n            moduleModel.getDeployer().start();\n        }\n    }\n\n    private void onContextClosedEvent(ContextClosedEvent event) {\n        if (bootstrap.getTakeoverMode() == BootstrapTakeoverMode.SPRING) {\n            // will call dubboBootstrap.stop() through shutdown callback.\n            // bootstrap.getApplicationModel().getBeanFactory().getBean(DubboShutdownHook.class).run();\n            moduleModel.getDeployer().stop();\n        }\n    }\n\n    /**\n     * Is original {@link ApplicationContext} as the event source\n     *\n     * @param event {@link ApplicationEvent}\n     * @return if original, return <code>true</code>, or <code>false</code>\n     */\n    private boolean isOriginalEventSource(ApplicationEvent event) {\n\n        boolean originalEventSource = nullSafeEquals(getApplicationContext(), event.getSource());\n        return originalEventSource;\n    }\n\n    @Override\n    public int getOrder() {\n        return LOWEST_PRECEDENCE;\n    }\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        this.applicationContext = applicationContext;\n        moduleModel = DubboBeanUtils.getModuleModel(applicationContext);\n        this.setBootstrap(DubboBootstrap.getInstance(moduleModel.getApplicationModel()));\n        if (shouldInitConfigBeans) {\n            checkCallStackAndInit();\n        }\n    }\n\n    private void checkCallStackAndInit() {\n        // check call stack whether contains\n        // org.springframework.context.support.AbstractApplicationContext.registerListeners()\n        Exception exception = new Exception();\n        StackTraceElement[] stackTrace = exception.getStackTrace();\n        boolean found = false;\n        for (StackTraceElement frame : stackTrace) {\n            if (frame.getMethodName().equals(\"registerListeners\")\n                    && frame.getClassName().endsWith(\"AbstractApplicationContext\")) {\n                found = true;\n                break;\n            }\n        }\n        if (found) {\n            // init config beans here, compatible with spring 3.x/4.1.x\n            initDubboConfigBeans();\n        } else {\n            logger.warn(\n                    CONFIG_DUBBO_BEAN_INITIALIZER,\n                    \"\",\n                    \"\",\n                    \"DubboBootstrapApplicationListener initialization is unexpected, \"\n                            + \"it should be created in AbstractApplicationContext.registerListeners() method\",\n                    exception);\n        }\n    }\n\n    public ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapStartStopListenerSpringAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrapStartStopListener;\nimport org.apache.dubbo.config.spring.context.event.DubboBootstrapStatedEvent;\nimport org.apache.dubbo.config.spring.context.event.DubboBootstrapStopedEvent;\n\nimport org.springframework.context.ApplicationContext;\n\n/**\n * convcert Dubbo bootstrap event to spring environment.\n *\n * @scene 2.7.9\n */\n@Deprecated\npublic class DubboBootstrapStartStopListenerSpringAdapter implements DubboBootstrapStartStopListener {\n\n    static ApplicationContext applicationContext;\n\n    @Override\n    public void onStart(DubboBootstrap bootstrap) {\n        if (applicationContext != null) {\n            applicationContext.publishEvent(new DubboBootstrapStatedEvent(bootstrap));\n        }\n    }\n\n    @Override\n    public void onStop(DubboBootstrap bootstrap) {\n        if (applicationContext != null) {\n            applicationContext.publishEvent(new DubboBootstrapStopedEvent(bootstrap));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboConfigApplicationListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.spring.context.event.DubboConfigInitEvent;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ApplicationListener;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_NOT_FOUND;\nimport static org.springframework.util.ObjectUtils.nullSafeEquals;\n\n/**\n * An ApplicationListener to load config beans\n */\npublic class DubboConfigApplicationListener\n        implements ApplicationListener<DubboConfigInitEvent>, ApplicationContextAware {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DubboConfigApplicationListener.class);\n\n    private ApplicationContext applicationContext;\n\n    private ModuleModel moduleModel;\n\n    private final AtomicBoolean initialized = new AtomicBoolean();\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        this.applicationContext = applicationContext;\n        this.moduleModel = DubboBeanUtils.getModuleModel(applicationContext);\n    }\n\n    @Override\n    public void onApplicationEvent(DubboConfigInitEvent event) {\n        if (nullSafeEquals(applicationContext, event.getSource())) {\n            init();\n        }\n    }\n\n    public synchronized void init() {\n        // It's expected to be notified at\n        // org.springframework.context.support.AbstractApplicationContext.registerListeners(),\n        // before loading non-lazy singleton beans. At this moment, all BeanFactoryPostProcessor have been processed,\n        if (initialized.compareAndSet(false, true)) {\n            initDubboConfigBeans();\n        }\n    }\n\n    private void initDubboConfigBeans() {\n        // load DubboConfigBeanInitializer to init config beans\n        if (applicationContext.containsBean(DubboConfigBeanInitializer.BEAN_NAME)) {\n            applicationContext.getBean(DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);\n        } else {\n            logger.warn(\n                    CONFIG_DUBBO_BEAN_NOT_FOUND,\n                    \"\",\n                    \"\",\n                    \"Bean '\" + DubboConfigBeanInitializer.BEAN_NAME + \"' was not found\");\n        }\n\n        // All infrastructure config beans are loaded, initialize dubbo here\n        moduleModel.getDeployer().prepare();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboConfigBeanInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.context.AbstractConfigManager;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.spring.ConfigCenterBean;\nimport org.apache.dubbo.config.spring.reference.ReferenceBeanManager;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.FatalBeanException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\n\n/**\n *\n * Dubbo config bean initializer.\n *\n * NOTE: Dubbo config beans MUST be initialized after registering all BeanPostProcessors,\n * that is after the AbstractApplicationContext#registerBeanPostProcessors() method.\n */\npublic class DubboConfigBeanInitializer implements BeanFactoryAware, InitializingBean {\n\n    public static String BEAN_NAME = \"dubboConfigBeanInitializer\";\n\n    private final Logger logger = LoggerFactory.getLogger(getClass());\n\n    private final AtomicBoolean initialized = new AtomicBoolean(false);\n    private ConfigurableListableBeanFactory beanFactory;\n    private ReferenceBeanManager referenceBeanManager;\n\n    private ConfigManager configManager;\n    private ModuleModel moduleModel;\n\n    @Override\n    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n        this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;\n    }\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        init();\n    }\n\n    private void init() {\n        if (initialized.compareAndSet(false, true)) {\n            referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);\n            configManager = DubboBeanUtils.getConfigManager(beanFactory);\n            moduleModel = DubboBeanUtils.getModuleModel(beanFactory);\n            try {\n                prepareDubboConfigBeans();\n                referenceBeanManager.prepareReferenceBeans();\n            } catch (Throwable e) {\n                throw new FatalBeanException(\"Initialization dubbo config beans failed\", e);\n            }\n        }\n    }\n\n    /**\n     * Initializes there Dubbo's Config Beans before @Reference bean autowiring\n     */\n    private void prepareDubboConfigBeans() {\n        logger.info(\"loading dubbo config beans ...\");\n\n        // Make sure all these config beans are initialed and registered to ConfigManager\n        // load application config beans\n        loadConfigBeansOfType(ApplicationConfig.class, configManager);\n        loadConfigBeansOfType(RegistryConfig.class, configManager);\n        loadConfigBeansOfType(ProtocolConfig.class, configManager);\n        loadConfigBeansOfType(MonitorConfig.class, configManager);\n        loadConfigBeansOfType(ConfigCenterBean.class, configManager);\n        loadConfigBeansOfType(MetadataReportConfig.class, configManager);\n        loadConfigBeansOfType(MetricsConfig.class, configManager);\n        loadConfigBeansOfType(TracingConfig.class, configManager);\n        loadConfigBeansOfType(SslConfig.class, configManager);\n\n        // load module config beans\n        loadConfigBeansOfType(ModuleConfig.class, moduleModel.getConfigManager());\n        loadConfigBeansOfType(ProviderConfig.class, moduleModel.getConfigManager());\n        loadConfigBeansOfType(ConsumerConfig.class, moduleModel.getConfigManager());\n\n        // load ConfigCenterBean from properties, fix https://github.com/apache/dubbo/issues/9207\n        List<ConfigCenterBean> configCenterBeans = configManager.loadConfigsOfTypeFromProps(ConfigCenterBean.class);\n        for (ConfigCenterBean configCenterBean : configCenterBeans) {\n            String beanName = configCenterBean.getId() != null ? configCenterBean.getId() : \"configCenterBean\";\n            beanFactory.initializeBean(configCenterBean, beanName);\n        }\n\n        logger.info(\"dubbo config beans are loaded.\");\n    }\n\n    private void loadConfigBeansOfType(\n            Class<? extends AbstractConfig> configClass, AbstractConfigManager configManager) {\n        String[] beanNames = beanFactory.getBeanNamesForType(configClass, true, false);\n        for (String beanName : beanNames) {\n            AbstractConfig configBean = beanFactory.getBean(beanName, configClass);\n            // Register config bean here, avoid relying on unreliable @PostConstruct init method\n            configManager.addConfig(configBean);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboContextPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar;\nimport org.apache.dubbo.config.spring.extension.SpringExtensionInjector;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.config.spring.util.EnvironmentUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.SortedMap;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\n\npublic class DubboContextPostProcessor\n        implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware, EnvironmentAware {\n\n    /**\n     * The bean name of {@link DubboConfigConfigurationRegistrar}\n     */\n    public static final String BEAN_NAME = \"dubboContextPostProcessor\";\n\n    private ApplicationContext applicationContext;\n\n    private ConfigurableEnvironment environment;\n\n    @Override\n    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n        ApplicationModel applicationModel = DubboBeanUtils.getApplicationModel(beanFactory);\n        ModuleModel moduleModel = DubboBeanUtils.getModuleModel(beanFactory);\n\n        // Initialize SpringExtensionInjector\n        SpringExtensionInjector.get(applicationModel).init(applicationContext);\n        SpringExtensionInjector.get(moduleModel).init(applicationContext);\n        DubboBeanUtils.getInitializationContext(beanFactory).setApplicationContext(applicationContext);\n\n        // Initialize dubbo Environment before ConfigManager\n        // Extract dubbo props from Spring env and put them to app config\n        SortedMap<String, String> dubboProperties = EnvironmentUtils.filterDubboProperties(environment);\n        applicationModel.getModelEnvironment().getAppConfigMap().putAll(dubboProperties);\n\n        // register ConfigManager singleton\n        beanFactory.registerSingleton(ConfigManager.BEAN_NAME, applicationModel.getApplicationConfigManager());\n    }\n\n    @Override\n    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {\n        DubboSpringInitializer.initialize(beanDefinitionRegistry);\n    }\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        this.applicationContext = applicationContext;\n    }\n\n    @Override\n    public void setEnvironment(Environment environment) {\n        this.environment = (ConfigurableEnvironment) environment;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboDeployApplicationListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.deploy.DeployListenerAdapter;\nimport org.apache.dubbo.common.deploy.DeployState;\nimport org.apache.dubbo.common.deploy.ModuleDeployer;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.config.spring.context.event.DubboApplicationStateEvent;\nimport org.apache.dubbo.config.spring.context.event.DubboModuleStateEvent;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.config.spring.util.LockUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModelConstants;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.concurrent.Future;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ApplicationContextEvent;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.core.Ordered;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_START_MODEL;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_STOP_DUBBO_ERROR;\nimport static org.springframework.util.ObjectUtils.nullSafeEquals;\n\n/**\n * An ApplicationListener to control Dubbo application.\n */\npublic class DubboDeployApplicationListener\n        implements ApplicationListener<ApplicationContextEvent>, ApplicationContextAware, Ordered {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DubboDeployApplicationListener.class);\n\n    private ApplicationContext applicationContext;\n\n    private ApplicationModel applicationModel;\n    private ModuleModel moduleModel;\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        this.applicationContext = applicationContext;\n        this.applicationModel = DubboBeanUtils.getApplicationModel(applicationContext);\n        this.moduleModel = DubboBeanUtils.getModuleModel(applicationContext);\n        // listen deploy events and publish DubboApplicationStateEvent\n        applicationModel.getDeployer().addDeployListener(new DeployListenerAdapter<ApplicationModel>() {\n            @Override\n            public void onStarting(ApplicationModel scopeModel) {\n                publishApplicationEvent(DeployState.STARTING);\n            }\n\n            @Override\n            public void onStarted(ApplicationModel scopeModel) {\n                publishApplicationEvent(DeployState.STARTED);\n            }\n\n            @Override\n            public void onCompletion(ApplicationModel scopeModel) {\n                publishApplicationEvent(DeployState.COMPLETION);\n            }\n\n            @Override\n            public void onStopping(ApplicationModel scopeModel) {\n                publishApplicationEvent(DeployState.STOPPING);\n            }\n\n            @Override\n            public void onStopped(ApplicationModel scopeModel) {\n                publishApplicationEvent(DeployState.STOPPED);\n            }\n\n            @Override\n            public void onFailure(ApplicationModel scopeModel, Throwable cause) {\n                publishApplicationEvent(DeployState.FAILED, cause);\n            }\n        });\n        moduleModel.getDeployer().addDeployListener(new DeployListenerAdapter<ModuleModel>() {\n            @Override\n            public void onStarting(ModuleModel scopeModel) {\n                publishModuleEvent(DeployState.STARTING);\n            }\n\n            @Override\n            public void onStarted(ModuleModel scopeModel) {\n                publishModuleEvent(DeployState.STARTED);\n            }\n\n            @Override\n            public void onCompletion(ModuleModel scopeModel) {\n                publishModuleEvent(DeployState.COMPLETION);\n            }\n\n            @Override\n            public void onStopping(ModuleModel scopeModel) {\n                publishModuleEvent(DeployState.STOPPING);\n            }\n\n            @Override\n            public void onStopped(ModuleModel scopeModel) {\n                publishModuleEvent(DeployState.STOPPED);\n            }\n\n            @Override\n            public void onFailure(ModuleModel scopeModel, Throwable cause) {\n                publishModuleEvent(DeployState.FAILED, cause);\n            }\n        });\n    }\n\n    private void publishApplicationEvent(DeployState state) {\n        applicationContext.publishEvent(new DubboApplicationStateEvent(applicationModel, state));\n    }\n\n    private void publishApplicationEvent(DeployState state, Throwable cause) {\n        applicationContext.publishEvent(new DubboApplicationStateEvent(applicationModel, state, cause));\n    }\n\n    private void publishModuleEvent(DeployState state) {\n        applicationContext.publishEvent(new DubboModuleStateEvent(moduleModel, state));\n    }\n\n    private void publishModuleEvent(DeployState state, Throwable cause) {\n        applicationContext.publishEvent(new DubboModuleStateEvent(moduleModel, state, cause));\n    }\n\n    @Override\n    public void onApplicationEvent(ApplicationContextEvent event) {\n        if (nullSafeEquals(applicationContext, event.getSource())) {\n            if (event instanceof ContextRefreshedEvent) {\n                onContextRefreshedEvent((ContextRefreshedEvent) event);\n            } else if (event instanceof ContextClosedEvent) {\n                onContextClosedEvent((ContextClosedEvent) event);\n            }\n        }\n    }\n\n    private void onContextRefreshedEvent(ContextRefreshedEvent event) {\n        ModuleDeployer deployer = moduleModel.getDeployer();\n        Assert.notNull(deployer, \"Module deployer is null\");\n        Object singletonMutex = LockUtils.getSingletonMutex(applicationContext);\n        // start module\n        Future future = null;\n        synchronized (singletonMutex) {\n            future = deployer.start();\n        }\n\n        // if the module does not start in background, await finish\n        if (!deployer.isBackground()) {\n            try {\n                future.get();\n            } catch (InterruptedException e) {\n                logger.warn(\n                        CONFIG_FAILED_START_MODEL,\n                        \"\",\n                        \"\",\n                        \"Interrupted while waiting for dubbo module start: \" + e.getMessage());\n            } catch (Exception e) {\n                logger.warn(\n                        CONFIG_FAILED_START_MODEL,\n                        \"\",\n                        \"\",\n                        \"An error occurred while waiting for dubbo module start: \" + e.getMessage(),\n                        e);\n            }\n        }\n    }\n\n    private void onContextClosedEvent(ContextClosedEvent event) {\n        try {\n            Object value = moduleModel.getAttribute(ModelConstants.KEEP_RUNNING_ON_SPRING_CLOSED);\n            if (value == null) {\n                value = ConfigurationUtils.getProperty(moduleModel, ModelConstants.KEEP_RUNNING_ON_SPRING_CLOSED_KEY);\n            }\n            boolean keepRunningOnClosed = Boolean.parseBoolean(String.valueOf(value));\n            if (!keepRunningOnClosed && !moduleModel.isDestroyed()) {\n                moduleModel.destroy();\n            }\n        } catch (Exception e) {\n            logger.error(\n                    CONFIG_STOP_DUBBO_ERROR,\n                    \"\",\n                    \"\",\n                    \"Unexpected error occurred when stop dubbo module: \" + e.getMessage(),\n                    e);\n        }\n        // remove context bind cache\n        DubboSpringInitializer.remove(event.getApplicationContext());\n    }\n\n    @Override\n    public int getOrder() {\n        return LOWEST_PRECEDENCE;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboInfraBeanRegisterPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\n\n/**\n * Register some infrastructure beans if not exists.\n * This post-processor MUST impl BeanDefinitionRegistryPostProcessor,\n * in order to enable the registered BeanFactoryPostProcessor bean to be loaded and executed.\n *\n * @see org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(\n *org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List)\n */\npublic class DubboInfraBeanRegisterPostProcessor implements BeanDefinitionRegistryPostProcessor {\n\n    /**\n     * The bean name of {@link ReferenceAnnotationBeanPostProcessor}\n     */\n    public static final String BEAN_NAME = \"dubboInfraBeanRegisterPostProcessor\";\n\n    private BeanDefinitionRegistry registry;\n\n    @Override\n    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {\n        this.registry = registry;\n    }\n\n    @Override\n    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\n        // In Spring 3.2.x, registry may be null because do not call postProcessBeanDefinitionRegistry method before\n        // postProcessBeanFactory\n        if (registry != null) {\n            // register ReferenceAnnotationBeanPostProcessor early before\n            // PropertySourcesPlaceholderConfigurer/PropertyPlaceholderConfigurer\n            // for processing early init ReferenceBean\n            ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor = beanFactory.getBean(\n                    ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);\n            beanFactory.addBeanPostProcessor(referenceAnnotationBeanPostProcessor);\n\n            // register PropertySourcesPlaceholderConfigurer bean if not exits\n            DubboBeanUtils.registerPlaceholderConfigurerBeanIfNotExists(beanFactory, registry);\n        }\n\n        // fix https://github.com/apache/dubbo/issues/10278\n        if (registry != null) {\n            registry.removeBeanDefinition(BEAN_NAME);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModelConstants;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.ApplicationContext;\n\n/**\n * Dubbo spring initialization context object\n */\npublic class DubboSpringInitContext {\n\n    private BeanDefinitionRegistry registry;\n\n    private ConfigurableListableBeanFactory beanFactory;\n\n    private ApplicationContext applicationContext;\n\n    private ModuleModel moduleModel;\n\n    private final Map<String, Object> moduleAttributes = new HashMap<>();\n\n    private volatile boolean bound;\n\n    public void markAsBound() {\n        bound = true;\n    }\n\n    public BeanDefinitionRegistry getRegistry() {\n        return registry;\n    }\n\n    void setRegistry(BeanDefinitionRegistry registry) {\n        this.registry = registry;\n    }\n\n    public ConfigurableListableBeanFactory getBeanFactory() {\n        return beanFactory;\n    }\n\n    void setBeanFactory(ConfigurableListableBeanFactory beanFactory) {\n        this.beanFactory = beanFactory;\n    }\n\n    public ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n\n    void setApplicationContext(ApplicationContext applicationContext) {\n        this.applicationContext = applicationContext;\n    }\n\n    public ApplicationModel getApplicationModel() {\n        return (moduleModel == null) ? null : moduleModel.getApplicationModel();\n    }\n\n    public ModuleModel getModuleModel() {\n        return moduleModel;\n    }\n\n    /**\n     * Change the binding ModuleModel, the ModuleModel and DubboBootstrap must be matched.\n     *\n     * @param moduleModel\n     */\n    public void setModuleModel(ModuleModel moduleModel) {\n        if (bound) {\n            throw new IllegalStateException(\"Cannot change ModuleModel after bound context\");\n        }\n        this.moduleModel = moduleModel;\n    }\n\n    public boolean isKeepRunningOnSpringClosed() {\n        return (boolean) moduleAttributes.get(ModelConstants.KEEP_RUNNING_ON_SPRING_CLOSED);\n    }\n\n    /**\n     * Keep Dubbo running when spring is stopped\n     * @param keepRunningOnSpringClosed\n     */\n    public void setKeepRunningOnSpringClosed(boolean keepRunningOnSpringClosed) {\n        this.setModuleAttribute(ModelConstants.KEEP_RUNNING_ON_SPRING_CLOSED, keepRunningOnSpringClosed);\n    }\n\n    public Map<String, Object> getModuleAttributes() {\n        return moduleAttributes;\n    }\n\n    public void setModuleAttribute(String key, Object value) {\n        this.moduleAttributes.put(key, value);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\n\nimport static org.apache.dubbo.common.extension.ExtensionScope.FRAMEWORK;\n\n/**\n * Custom dubbo spring initialization\n */\n@SPI(scope = FRAMEWORK)\npublic interface DubboSpringInitCustomizer {\n\n    /**\n     * <p>Customize dubbo spring initialization on bean registry processing phase.</p>\n     * <p>You can register a {@link BeanFactoryPostProcessor} or {@link BeanPostProcessor} for custom processing.</p>\n     * <p>Or change the bind module model via {@link DubboSpringInitContext#setModuleModel(ModuleModel)}.</p>\n     *\n     * <p><b>Note:</b></p>\n     * <p>1. The bean factory may be not ready yet when triggered by parsing dubbo xml definition.</p>\n     * <p>2. Some bean definitions may be not registered at this moment. If you plan to process all bean definitions,\n     * it is recommended to register a custom {@link BeanFactoryPostProcessor} to do so.</p>\n     *\n     * @param context\n     */\n    void customize(DubboSpringInitContext context);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitCustomizerHolder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Hold a set of DubboSpringInitCustomizer, for register customizers by programming.\n * <p>All customizers are store in thread local, and they will be clear after apply once.</p>\n *\n * <p>Usages:</p>\n *<pre>\n * DubboSpringInitCustomizerHolder.get().addCustomizer(context -> {...});\n * ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(..);\n * ...\n * DubboSpringInitCustomizerHolder.get().addCustomizer(context -> {...});\n * ClassPathXmlApplicationContext consumerContext = new ClassPathXmlApplicationContext(..);\n * </pre>\n */\npublic class DubboSpringInitCustomizerHolder {\n\n    private static final ThreadLocal<DubboSpringInitCustomizerHolder> holders =\n            ThreadLocal.withInitial(DubboSpringInitCustomizerHolder::new);\n\n    public static DubboSpringInitCustomizerHolder get() {\n        return holders.get();\n    }\n\n    private Set<DubboSpringInitCustomizer> customizers = new HashSet<>();\n\n    public void addCustomizer(DubboSpringInitCustomizer customizer) {\n        this.customizers.add(customizer);\n    }\n\n    public void clearCustomizers() {\n        this.customizers = new HashSet<>();\n    }\n\n    public Set<DubboSpringInitCustomizer> getCustomizers() {\n        return customizers;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.spring.aot.AotWithSpringDetector;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Dubbo spring initialization entry point\n */\npublic class DubboSpringInitializer {\n\n    private static final Logger logger = LoggerFactory.getLogger(DubboSpringInitializer.class);\n\n    private static final Map<BeanDefinitionRegistry, DubboSpringInitContext> REGISTRY_CONTEXT_MAP =\n            new ConcurrentHashMap<>();\n\n    public DubboSpringInitializer() {}\n\n    public static void initialize(BeanDefinitionRegistry registry) {\n\n        // prepare context and do customize\n        DubboSpringInitContext context = new DubboSpringInitContext();\n\n        // Spring ApplicationContext may not ready at this moment (e.g. load from xml), so use registry as key\n        if (REGISTRY_CONTEXT_MAP.putIfAbsent(registry, context) != null) {\n            return;\n        }\n\n        // find beanFactory\n        ConfigurableListableBeanFactory beanFactory = findBeanFactory(registry);\n\n        // init dubbo context\n        initContext(context, registry, beanFactory);\n    }\n\n    public static boolean remove(BeanDefinitionRegistry registry) {\n        return REGISTRY_CONTEXT_MAP.remove(registry) != null;\n    }\n\n    public static boolean remove(ApplicationContext springContext) {\n        AutowireCapableBeanFactory autowireCapableBeanFactory = springContext.getAutowireCapableBeanFactory();\n        for (Map.Entry<BeanDefinitionRegistry, DubboSpringInitContext> entry : REGISTRY_CONTEXT_MAP.entrySet()) {\n            DubboSpringInitContext initContext = entry.getValue();\n            if (initContext.getApplicationContext() == springContext\n                    || initContext.getBeanFactory() == autowireCapableBeanFactory\n                    || initContext.getRegistry() == autowireCapableBeanFactory) {\n                DubboSpringInitContext context = REGISTRY_CONTEXT_MAP.remove(entry.getKey());\n                logger.info(\"Unbind \" + safeGetModelDesc(context.getModuleModel()) + \" from spring container: \"\n                        + ObjectUtils.identityToString(entry.getKey()));\n                return true;\n            }\n        }\n        return false;\n    }\n\n    static Map<BeanDefinitionRegistry, DubboSpringInitContext> getContextMap() {\n        return REGISTRY_CONTEXT_MAP;\n    }\n\n    static DubboSpringInitContext findBySpringContext(ApplicationContext applicationContext) {\n        for (DubboSpringInitContext initContext : REGISTRY_CONTEXT_MAP.values()) {\n            if (initContext.getApplicationContext() == applicationContext) {\n                return initContext;\n            }\n        }\n        return null;\n    }\n\n    private static void initContext(\n            DubboSpringInitContext context,\n            BeanDefinitionRegistry registry,\n            ConfigurableListableBeanFactory beanFactory) {\n        context.setRegistry(registry);\n        context.setBeanFactory(beanFactory);\n\n        // customize context, you can change the bind module model via DubboSpringInitCustomizer SPI\n        customize(context);\n\n        // init ModuleModel\n        ModuleModel moduleModel = context.getModuleModel();\n        if (moduleModel == null) {\n            ApplicationModel applicationModel;\n            if (findContextForApplication(ApplicationModel.defaultModel()) == null) {\n                // first spring context use default application instance\n                applicationModel = ApplicationModel.defaultModel();\n                logger.info(\"Use default application: \" + applicationModel.getDesc());\n            } else {\n                // create a new application instance for later spring context\n                applicationModel = FrameworkModel.defaultModel().newApplication();\n                logger.info(\"Create new application: \" + applicationModel.getDesc());\n            }\n\n            // init ModuleModel\n            moduleModel = applicationModel.getDefaultModule();\n            context.setModuleModel(moduleModel);\n            logger.info(\"Use default module model of target application: \" + moduleModel.getDesc());\n        } else {\n            logger.info(\"Use module model from customizer: \" + moduleModel.getDesc());\n        }\n        logger.info(\n                \"Bind \" + moduleModel.getDesc() + \" to spring container: \" + ObjectUtils.identityToString(registry));\n\n        // set module attributes\n        Map<String, Object> moduleAttributes = context.getModuleAttributes();\n        if (moduleAttributes.size() > 0) {\n            moduleModel.getAttributes().putAll(moduleAttributes);\n        }\n\n        // bind dubbo initialization context to spring context\n        registerContextBeans(beanFactory, context);\n\n        // mark context as bound\n        context.markAsBound();\n        moduleModel.setLifeCycleManagedExternally(true);\n\n        if (!AotWithSpringDetector.useGeneratedArtifacts()) {\n            // register common beans\n            DubboBeanUtils.registerCommonBeans(registry);\n        }\n    }\n\n    private static String safeGetModelDesc(ScopeModel scopeModel) {\n        return scopeModel != null ? scopeModel.getDesc() : null;\n    }\n\n    private static ConfigurableListableBeanFactory findBeanFactory(BeanDefinitionRegistry registry) {\n        ConfigurableListableBeanFactory beanFactory;\n        if (registry instanceof ConfigurableListableBeanFactory) {\n            beanFactory = (ConfigurableListableBeanFactory) registry;\n        } else if (registry instanceof GenericApplicationContext) {\n            GenericApplicationContext genericApplicationContext = (GenericApplicationContext) registry;\n            beanFactory = genericApplicationContext.getBeanFactory();\n        } else {\n            throw new IllegalStateException(\"Can not find Spring BeanFactory from registry: \"\n                    + registry.getClass().getName());\n        }\n        return beanFactory;\n    }\n\n    private static void registerContextBeans(\n            ConfigurableListableBeanFactory beanFactory, DubboSpringInitContext context) {\n        // register singleton\n        if (!beanFactory.containsSingleton(DubboSpringInitContext.class.getName())) {\n            registerSingleton(beanFactory, context);\n        }\n        if (!beanFactory.containsSingleton(\n                context.getApplicationModel().getClass().getName())) {\n            registerSingleton(beanFactory, context.getApplicationModel());\n        }\n        if (!beanFactory.containsSingleton(context.getModuleModel().getClass().getName())) {\n            registerSingleton(beanFactory, context.getModuleModel());\n        }\n    }\n\n    private static void registerSingleton(ConfigurableListableBeanFactory beanFactory, Object bean) {\n        beanFactory.registerSingleton(bean.getClass().getName(), bean);\n    }\n\n    private static DubboSpringInitContext findContextForApplication(ApplicationModel applicationModel) {\n        for (DubboSpringInitContext initializationContext : REGISTRY_CONTEXT_MAP.values()) {\n            if (initializationContext.getApplicationModel() == applicationModel) {\n                return initializationContext;\n            }\n        }\n        return null;\n    }\n\n    private static void customize(DubboSpringInitContext context) {\n\n        // find initialization customizers\n        Set<DubboSpringInitCustomizer> customizers = FrameworkModel.defaultModel()\n                .getExtensionLoader(DubboSpringInitCustomizer.class)\n                .getSupportedExtensionInstances();\n        for (DubboSpringInitCustomizer customizer : customizers) {\n            customizer.customize(context);\n        }\n\n        // load customizers in thread local holder\n        DubboSpringInitCustomizerHolder customizerHolder = DubboSpringInitCustomizerHolder.get();\n        customizers = customizerHolder.getCustomizers();\n        for (DubboSpringInitCustomizer customizer : customizers) {\n            customizer.customize(context);\n        }\n        customizerHolder.clearCustomizers();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/ConfigurationBeanBindingPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.spring.context.config.ConfigurationBeanBinder;\nimport org.apache.dubbo.config.spring.context.config.ConfigurationBeanCustomizer;\nimport org.apache.dubbo.config.spring.context.config.DefaultConfigurationBeanBinder;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.core.PriorityOrdered;\n\nimport static org.apache.dubbo.config.spring.context.annotation.ConfigurationBeanBindingRegistrar.ENABLE_CONFIGURATION_BINDING_CLASS;\nimport static org.apache.dubbo.config.spring.util.WrapperUtils.unwrap;\nimport static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors;\nimport static org.springframework.core.annotation.AnnotationAwareOrderComparator.sort;\nimport static org.springframework.util.ClassUtils.getUserClass;\nimport static org.springframework.util.ObjectUtils.nullSafeEquals;\n\n/**\n * The {@link BeanPostProcessor} class to bind the configuration bean\n *\n */\n@SuppressWarnings(\"unchecked\")\npublic class ConfigurationBeanBindingPostProcessor implements BeanPostProcessor, BeanFactoryAware, PriorityOrdered {\n\n    /**\n     * The bean name of {@link ConfigurationBeanBindingPostProcessor}\n     */\n    public static final String BEAN_NAME = \"configurationBeanBindingPostProcessor\";\n\n    static final String CONFIGURATION_PROPERTIES_ATTRIBUTE_NAME = \"configurationProperties\";\n\n    static final String IGNORE_UNKNOWN_FIELDS_ATTRIBUTE_NAME = \"ignoreUnknownFields\";\n\n    static final String IGNORE_INVALID_FIELDS_ATTRIBUTE_NAME = \"ignoreInvalidFields\";\n\n    private final Log log = LogFactory.getLog(getClass());\n\n    private ConfigurableListableBeanFactory beanFactory = null;\n\n    private ConfigurationBeanBinder configurationBeanBinder = null;\n\n    private List<ConfigurationBeanCustomizer> configurationBeanCustomizers = null;\n\n    private int order = LOWEST_PRECEDENCE;\n\n    @Override\n    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\n        BeanDefinition beanDefinition = getNullableBeanDefinition(beanName);\n\n        if (isConfigurationBean(bean, beanDefinition)) {\n            bindConfigurationBean(bean, beanDefinition);\n            customize(beanName, bean);\n        }\n\n        return bean;\n    }\n\n    @Override\n    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n        return bean;\n    }\n\n    /**\n     * Set the order for current instance\n     *\n     * @param order the order\n     */\n    public void setOrder(int order) {\n        this.order = order;\n    }\n\n    public ConfigurationBeanBinder getConfigurationBeanBinder() {\n        if (configurationBeanBinder == null) {\n            initConfigurationBeanBinder();\n        }\n        return configurationBeanBinder;\n    }\n\n    public void setConfigurationBeanBinder(ConfigurationBeanBinder configurationBeanBinder) {\n        this.configurationBeanBinder = configurationBeanBinder;\n    }\n\n    /**\n     * Get the {@link List} of {@link ConfigurationBeanCustomizer ConfigurationBeanCustomizers}\n     *\n     * @return non-null\n     */\n    public List<ConfigurationBeanCustomizer> getConfigurationBeanCustomizers() {\n        if (configurationBeanCustomizers == null) {\n            initBindConfigurationBeanCustomizers();\n        }\n        return configurationBeanCustomizers;\n    }\n\n    public void setConfigurationBeanCustomizers(Collection<ConfigurationBeanCustomizer> configurationBeanCustomizers) {\n        List<ConfigurationBeanCustomizer> customizers =\n                new ArrayList<ConfigurationBeanCustomizer>(configurationBeanCustomizers);\n        sort(customizers);\n        this.configurationBeanCustomizers = Collections.unmodifiableList(customizers);\n    }\n\n    private BeanDefinition getNullableBeanDefinition(String beanName) {\n        return beanFactory.containsBeanDefinition(beanName) ? beanFactory.getBeanDefinition(beanName) : null;\n    }\n\n    private boolean isConfigurationBean(Object bean, BeanDefinition beanDefinition) {\n        return beanDefinition != null\n                && ENABLE_CONFIGURATION_BINDING_CLASS.equals(beanDefinition.getSource())\n                && nullSafeEquals(getBeanClassName(bean), beanDefinition.getBeanClassName());\n    }\n\n    private String getBeanClassName(Object bean) {\n        return getUserClass(bean.getClass()).getName();\n    }\n\n    private void bindConfigurationBean(Object configurationBean, BeanDefinition beanDefinition) {\n\n        Map<String, Object> configurationProperties = getConfigurationProperties(beanDefinition);\n\n        boolean ignoreUnknownFields = getIgnoreUnknownFields(beanDefinition);\n\n        boolean ignoreInvalidFields = getIgnoreInvalidFields(beanDefinition);\n\n        getConfigurationBeanBinder()\n                .bind(configurationProperties, ignoreUnknownFields, ignoreInvalidFields, configurationBean);\n\n        if (log.isInfoEnabled()) {\n            log.info(\"The configuration bean [\" + configurationBean + \"] have been binding by the \"\n                    + \"configuration properties [\" + configurationProperties + \"]\");\n        }\n    }\n\n    private void initConfigurationBeanBinder() {\n        if (configurationBeanBinder == null) {\n            try {\n                configurationBeanBinder = beanFactory.getBean(ConfigurationBeanBinder.class);\n            } catch (BeansException ignored) {\n                if (log.isInfoEnabled()) {\n                    log.info(\"configurationBeanBinder Bean can't be found in ApplicationContext.\");\n                }\n                // Use Default implementation\n                configurationBeanBinder = defaultConfigurationBeanBinder();\n            }\n        }\n    }\n\n    private void initBindConfigurationBeanCustomizers() {\n        Collection<ConfigurationBeanCustomizer> customizers = beansOfTypeIncludingAncestors(\n                        beanFactory, ConfigurationBeanCustomizer.class)\n                .values();\n        setConfigurationBeanCustomizers(customizers);\n    }\n\n    private void customize(String beanName, Object configurationBean) {\n        for (ConfigurationBeanCustomizer customizer : getConfigurationBeanCustomizers()) {\n            customizer.customize(beanName, configurationBean);\n        }\n    }\n\n    /**\n     * Create {@link ConfigurationBeanBinder} instance.\n     *\n     * @return {@link DefaultConfigurationBeanBinder}\n     */\n    private ConfigurationBeanBinder defaultConfigurationBeanBinder() {\n        return new DefaultConfigurationBeanBinder();\n    }\n\n    static void initBeanMetadataAttributes(\n            AbstractBeanDefinition beanDefinition,\n            Map<String, Object> configurationProperties,\n            boolean ignoreUnknownFields,\n            boolean ignoreInvalidFields) {\n        beanDefinition.setAttribute(CONFIGURATION_PROPERTIES_ATTRIBUTE_NAME, configurationProperties);\n        beanDefinition.setAttribute(IGNORE_UNKNOWN_FIELDS_ATTRIBUTE_NAME, ignoreUnknownFields);\n        beanDefinition.setAttribute(IGNORE_INVALID_FIELDS_ATTRIBUTE_NAME, ignoreInvalidFields);\n    }\n\n    private static <T> T getAttribute(BeanDefinition beanDefinition, String attributeName) {\n        return (T) beanDefinition.getAttribute(attributeName);\n    }\n\n    private static Map<String, Object> getConfigurationProperties(BeanDefinition beanDefinition) {\n        return getAttribute(beanDefinition, CONFIGURATION_PROPERTIES_ATTRIBUTE_NAME);\n    }\n\n    private static boolean getIgnoreUnknownFields(BeanDefinition beanDefinition) {\n        return getAttribute(beanDefinition, IGNORE_UNKNOWN_FIELDS_ATTRIBUTE_NAME);\n    }\n\n    private static boolean getIgnoreInvalidFields(BeanDefinition beanDefinition) {\n        return getAttribute(beanDefinition, IGNORE_INVALID_FIELDS_ATTRIBUTE_NAME);\n    }\n\n    @Override\n    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n        this.beanFactory = unwrap(beanFactory);\n    }\n\n    @Override\n    public int getOrder() {\n        return order;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/ConfigurationBeanBindingRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionReaderUtils;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\nimport static java.lang.Boolean.valueOf;\nimport static java.util.Collections.singleton;\nimport static org.apache.dubbo.config.spring.context.annotation.ConfigurationBeanBindingPostProcessor.initBeanMetadataAttributes;\nimport static org.apache.dubbo.config.spring.context.annotation.EnableConfigurationBeanBinding.DEFAULT_IGNORE_INVALID_FIELDS;\nimport static org.apache.dubbo.config.spring.context.annotation.EnableConfigurationBeanBinding.DEFAULT_IGNORE_UNKNOWN_FIELDS;\nimport static org.apache.dubbo.config.spring.context.annotation.EnableConfigurationBeanBinding.DEFAULT_MULTIPLE;\nimport static org.apache.dubbo.config.spring.util.AnnotationUtils.getAttribute;\nimport static org.apache.dubbo.config.spring.util.AnnotationUtils.getRequiredAttribute;\nimport static org.apache.dubbo.config.spring.util.DubboBeanUtils.registerInfrastructureBean;\nimport static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties;\nimport static org.apache.dubbo.config.spring.util.PropertySourcesUtils.normalizePrefix;\nimport static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;\n\n/**\n * The {@link ImportBeanDefinitionRegistrar} implementation for {@link EnableConfigurationBeanBinding @EnableConfigurationBinding}\n *\n */\npublic class ConfigurationBeanBindingRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {\n\n    static final Class ENABLE_CONFIGURATION_BINDING_CLASS = EnableConfigurationBeanBinding.class;\n\n    private static final String ENABLE_CONFIGURATION_BINDING_CLASS_NAME = ENABLE_CONFIGURATION_BINDING_CLASS.getName();\n\n    private final Log log = LogFactory.getLog(getClass());\n\n    private ConfigurableEnvironment environment;\n\n    @Override\n    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {\n\n        Map<String, Object> attributes = metadata.getAnnotationAttributes(ENABLE_CONFIGURATION_BINDING_CLASS_NAME);\n\n        registerConfigurationBeanDefinitions(attributes, registry);\n    }\n\n    public void registerConfigurationBeanDefinitions(Map<String, Object> attributes, BeanDefinitionRegistry registry) {\n\n        String prefix = getRequiredAttribute(attributes, \"prefix\");\n\n        prefix = environment.resolvePlaceholders(prefix);\n\n        Class<?> configClass = getRequiredAttribute(attributes, \"type\");\n\n        boolean multiple = getAttribute(attributes, \"multiple\", valueOf(DEFAULT_MULTIPLE));\n\n        boolean ignoreUnknownFields =\n                getAttribute(attributes, \"ignoreUnknownFields\", valueOf(DEFAULT_IGNORE_UNKNOWN_FIELDS));\n\n        boolean ignoreInvalidFields =\n                getAttribute(attributes, \"ignoreInvalidFields\", valueOf(DEFAULT_IGNORE_INVALID_FIELDS));\n\n        registerConfigurationBeans(prefix, configClass, multiple, ignoreUnknownFields, ignoreInvalidFields, registry);\n    }\n\n    private void registerConfigurationBeans(\n            String prefix,\n            Class<?> configClass,\n            boolean multiple,\n            boolean ignoreUnknownFields,\n            boolean ignoreInvalidFields,\n            BeanDefinitionRegistry registry) {\n\n        Map<String, Object> configurationProperties =\n                getSubProperties(environment.getPropertySources(), environment, prefix);\n\n        if (CollectionUtils.isEmpty(configurationProperties)) {\n            if (log.isDebugEnabled()) {\n                log.debug(\"There is no property for binding to configuration class [\" + configClass.getName()\n                        + \"] within prefix [\" + prefix + \"]\");\n            }\n            return;\n        }\n\n        Set<String> beanNames = multiple\n                ? resolveMultipleBeanNames(configurationProperties)\n                : singleton(resolveSingleBeanName(configurationProperties, configClass, registry));\n\n        for (String beanName : beanNames) {\n            registerConfigurationBean(\n                    beanName,\n                    configClass,\n                    multiple,\n                    ignoreUnknownFields,\n                    ignoreInvalidFields,\n                    configurationProperties,\n                    registry);\n        }\n\n        registerConfigurationBindingBeanPostProcessor(registry);\n    }\n\n    private void registerConfigurationBean(\n            String beanName,\n            Class<?> configClass,\n            boolean multiple,\n            boolean ignoreUnknownFields,\n            boolean ignoreInvalidFields,\n            Map<String, Object> configurationProperties,\n            BeanDefinitionRegistry registry) {\n\n        BeanDefinitionBuilder builder = rootBeanDefinition(configClass);\n\n        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();\n\n        setSource(beanDefinition);\n\n        Map<String, Object> subProperties = resolveSubProperties(multiple, beanName, configurationProperties);\n\n        initBeanMetadataAttributes(beanDefinition, subProperties, ignoreUnknownFields, ignoreInvalidFields);\n\n        registry.registerBeanDefinition(beanName, beanDefinition);\n\n        if (log.isInfoEnabled()) {\n            log.info(\"The configuration bean definition [name : \" + beanName + \", content : \" + beanDefinition\n                    + \"] has been registered.\");\n        }\n    }\n\n    private Map<String, Object> resolveSubProperties(\n            boolean multiple, String beanName, Map<String, Object> configurationProperties) {\n        if (!multiple) {\n            return configurationProperties;\n        }\n\n        MutablePropertySources propertySources = new MutablePropertySources();\n\n        propertySources.addLast(new MapPropertySource(\"_\", configurationProperties));\n\n        return getSubProperties(propertySources, environment, normalizePrefix(beanName));\n    }\n\n    private void setSource(AbstractBeanDefinition beanDefinition) {\n        beanDefinition.setSource(ENABLE_CONFIGURATION_BINDING_CLASS);\n    }\n\n    private void registerConfigurationBindingBeanPostProcessor(BeanDefinitionRegistry registry) {\n        registerInfrastructureBean(\n                registry, ConfigurationBeanBindingPostProcessor.BEAN_NAME, ConfigurationBeanBindingPostProcessor.class);\n    }\n\n    @Override\n    public void setEnvironment(Environment environment) {\n\n        Assert.isInstanceOf(ConfigurableEnvironment.class, environment);\n\n        this.environment = (ConfigurableEnvironment) environment;\n    }\n\n    private Set<String> resolveMultipleBeanNames(Map<String, Object> properties) {\n\n        Set<String> beanNames = new LinkedHashSet<String>();\n\n        for (String propertyName : properties.keySet()) {\n\n            int index = propertyName.indexOf(\".\");\n\n            if (index > 0) {\n\n                String beanName = propertyName.substring(0, index);\n\n                beanNames.add(beanName);\n            }\n        }\n\n        return beanNames;\n    }\n\n    private String resolveSingleBeanName(\n            Map<String, Object> properties, Class<?> configClass, BeanDefinitionRegistry registry) {\n\n        String beanName = (String) properties.get(\"id\");\n\n        if (!StringUtils.hasText(beanName)) {\n            BeanDefinitionBuilder builder = rootBeanDefinition(configClass);\n            beanName = BeanDefinitionReaderUtils.generateBeanName(builder.getRawBeanDefinition(), registry);\n        }\n\n        return beanName;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/ConfigurationBeanBindingsRegister.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * The {@link ImportBeanDefinitionRegistrar Registrar class} for {@link EnableConfigurationBeanBindings}\n *\n */\npublic class ConfigurationBeanBindingsRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {\n\n    private ConfigurableEnvironment environment;\n\n    @Override\n    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n\n        AnnotationAttributes attributes = AnnotationAttributes.fromMap(\n                importingClassMetadata.getAnnotationAttributes(EnableConfigurationBeanBindings.class.getName()));\n\n        AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray(\"value\");\n\n        ConfigurationBeanBindingRegistrar registrar = new ConfigurationBeanBindingRegistrar();\n\n        registrar.setEnvironment(environment);\n\n        for (AnnotationAttributes element : annotationAttributes) {\n            registrar.registerConfigurationBeanDefinitions(element, registry);\n        }\n    }\n\n    @Override\n    public void setEnvironment(Environment environment) {\n        Assert.isInstanceOf(ConfigurableEnvironment.class, environment);\n        this.environment = (ConfigurableEnvironment) environment;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboClassPathBeanDefinitionScanner.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.spring.aot.AotWithSpringDetector;\n\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.annotation.ClassPathBeanDefinitionScanner;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\n\nimport static org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors;\n\n/**\n * Dubbo {@link ClassPathBeanDefinitionScanner} that exposes some methods to be public.\n *\n * @see #doScan(String...)\n * @see #registerDefaultFilters()\n * @since 2.5.7\n */\npublic class DubboClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {\n\n    /**\n     * key is package to scan, value is BeanDefinition\n     */\n    private final ConcurrentMap<String, Set<BeanDefinition>> beanDefinitionMap = new ConcurrentHashMap<>();\n\n    public DubboClassPathBeanDefinitionScanner(\n            BeanDefinitionRegistry registry,\n            boolean useDefaultFilters,\n            Environment environment,\n            ResourceLoader resourceLoader) {\n\n        super(registry, useDefaultFilters);\n\n        setEnvironment(environment);\n\n        setResourceLoader(resourceLoader);\n\n        if (!AotWithSpringDetector.useGeneratedArtifacts()) {\n            registerAnnotationConfigProcessors(registry);\n        }\n    }\n\n    public DubboClassPathBeanDefinitionScanner(\n            BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) {\n\n        this(registry, false, environment, resourceLoader);\n    }\n\n    @Override\n    public Set<BeanDefinition> findCandidateComponents(String basePackage) {\n        Set<BeanDefinition> beanDefinitions = beanDefinitionMap.get(basePackage);\n        // if beanDefinitions size is null => scan\n        if (Objects.isNull(beanDefinitions)) {\n            beanDefinitions = super.findCandidateComponents(basePackage);\n            beanDefinitionMap.put(basePackage, beanDefinitions);\n        }\n        return beanDefinitions;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScan.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.annotation.Service;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Import;\n\n/**\n * Dubbo Component Scan {@link Annotation},scans the classpath for annotated components that will be auto-registered as\n * Spring beans. Dubbo-provided {@link Service} and {@link Reference}.\n *\n * @see Service\n * @see Reference\n * @since 2.5.7\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Import(DubboComponentScanRegistrar.class)\npublic @interface DubboComponentScan {\n\n    /**\n     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation\n     * declarations e.g.: {@code @DubboComponentScan(\"org.my.pkg\")} instead of\n     * {@code @DubboComponentScan(basePackages=\"org.my.pkg\")}.\n     *\n     * @return the base packages to scan\n     */\n    String[] value() default {};\n\n    /**\n     * Base packages to scan for annotated @Service classes. {@link #value()} is an\n     * alias for (and mutually exclusive with) this attribute.\n     * <p>\n     * Use {@link #basePackageClasses()} for a type-safe alternative to String-based\n     * package names.\n     *\n     * @return the base packages to scan\n     */\n    String[] basePackages() default {};\n\n    /**\n     * Type-safe alternative to {@link #basePackages()} for specifying the packages to\n     * scan for annotated @Service classes. The package of each class specified will be\n     * scanned.\n     *\n     * @return classes from the base packages to scan\n     */\n    Class<?>[] basePackageClasses() default {};\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;\nimport org.apache.dubbo.config.spring.context.DubboSpringInitializer;\nimport org.apache.dubbo.config.spring.util.SpringCompatUtils;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionReaderUtils;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.ClassUtils;\n\nimport static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;\n\n/**\n * Dubbo {@link DubboComponentScan} Bean Registrar\n *\n * @see Service\n * @see DubboComponentScan\n * @see ImportBeanDefinitionRegistrar\n * @see ServiceAnnotationPostProcessor\n * @see ReferenceAnnotationBeanPostProcessor\n * @since 2.5.7\n */\npublic class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {\n\n    @Override\n    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n\n        // initialize dubbo beans\n        DubboSpringInitializer.initialize(registry);\n\n        Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);\n\n        registerServiceAnnotationPostProcessor(packagesToScan, registry);\n    }\n\n    /**\n     * Registers {@link ServiceAnnotationPostProcessor}\n     *\n     * @param packagesToScan packages to scan without resolving placeholders\n     * @param registry       {@link BeanDefinitionRegistry}\n     * @since 2.5.8\n     */\n    private void registerServiceAnnotationPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {\n\n        BeanDefinitionBuilder builder = rootBeanDefinition(SpringCompatUtils.serviceAnnotationPostProcessor());\n        builder.addConstructorArgValue(packagesToScan);\n        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);\n        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();\n        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);\n    }\n\n    private Set<String> getPackagesToScan(AnnotationMetadata metadata) {\n        // get from @DubboComponentScan\n        Set<String> packagesToScan =\n                getPackagesToScan0(metadata, DubboComponentScan.class, \"basePackages\", \"basePackageClasses\");\n\n        // get from @EnableDubbo, compatible with spring 3.x\n        if (packagesToScan.isEmpty()) {\n            packagesToScan =\n                    getPackagesToScan0(metadata, EnableDubbo.class, \"scanBasePackages\", \"scanBasePackageClasses\");\n        }\n\n        if (packagesToScan.isEmpty()) {\n            return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));\n        }\n        return packagesToScan;\n    }\n\n    private Set<String> getPackagesToScan0(\n            AnnotationMetadata metadata,\n            Class annotationClass,\n            String basePackagesName,\n            String basePackageClassesName) {\n\n        AnnotationAttributes attributes =\n                AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(annotationClass.getName()));\n        if (attributes == null) {\n            return Collections.emptySet();\n        }\n\n        Set<String> packagesToScan = new LinkedHashSet<>();\n        // basePackages\n        String[] basePackages = attributes.getStringArray(basePackagesName);\n        packagesToScan.addAll(Arrays.asList(basePackages));\n        // basePackageClasses\n        Class<?>[] basePackageClasses = attributes.getClassArray(basePackageClassesName);\n        for (Class<?> basePackageClass : basePackageClasses) {\n            packagesToScan.add(ClassUtils.getPackageName(basePackageClass));\n        }\n        // value\n        if (attributes.containsKey(\"value\")) {\n            String[] value = attributes.getStringArray(\"value\");\n            packagesToScan.addAll(Arrays.asList(value));\n        }\n        return packagesToScan;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.spring.ConfigCenterBean;\n\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Dubbo {@link AbstractConfig Config} {@link Configuration}\n *\n * @revised 2.7.5\n * @see Configuration\n * @see EnableConfigurationBeanBindings\n * @see EnableConfigurationBeanBinding\n * @see ApplicationConfig\n * @see ModuleConfig\n * @see RegistryConfig\n * @see ProtocolConfig\n * @see MonitorConfig\n * @see ProviderConfig\n * @see ConsumerConfig\n * @see org.apache.dubbo.config.ConfigCenterConfig\n * @since 2.5.8\n */\npublic class DubboConfigConfiguration {\n\n    /**\n     * Single Dubbo {@link AbstractConfig Config} Bean Binding\n     */\n    @EnableConfigurationBeanBindings({\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.application\", type = ApplicationConfig.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.module\", type = ModuleConfig.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.registry\", type = RegistryConfig.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.protocol\", type = ProtocolConfig.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.monitor\", type = MonitorConfig.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.provider\", type = ProviderConfig.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.consumer\", type = ConsumerConfig.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.config-center\", type = ConfigCenterBean.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.metadata-report\", type = MetadataReportConfig.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.metrics\", type = MetricsConfig.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.tracing\", type = TracingConfig.class),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.ssl\", type = SslConfig.class)\n    })\n    public static class Single {}\n\n    /**\n     * Multiple Dubbo {@link AbstractConfig Config} Bean Binding\n     */\n    @EnableConfigurationBeanBindings({\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.applications\", type = ApplicationConfig.class, multiple = true),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.modules\", type = ModuleConfig.class, multiple = true),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.registries\", type = RegistryConfig.class, multiple = true),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.protocols\", type = ProtocolConfig.class, multiple = true),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.monitors\", type = MonitorConfig.class, multiple = true),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.providers\", type = ProviderConfig.class, multiple = true),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.consumers\", type = ConsumerConfig.class, multiple = true),\n        @EnableConfigurationBeanBinding(\n                prefix = \"dubbo.config-centers\",\n                type = ConfigCenterBean.class,\n                multiple = true),\n        @EnableConfigurationBeanBinding(\n                prefix = \"dubbo.metadata-reports\",\n                type = MetadataReportConfig.class,\n                multiple = true),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.metricses\", type = MetricsConfig.class, multiple = true),\n        @EnableConfigurationBeanBinding(prefix = \"dubbo.tracings\", type = TracingConfig.class, multiple = true)\n    })\n    public static class Multiple {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.spring.context.DubboSpringInitializer;\n\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.type.AnnotationMetadata;\n\n/**\n * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register}, which order can be configured\n *\n * @see EnableDubboConfig\n * @see DubboConfigConfiguration\n * @see Ordered\n * @since 2.5.8\n */\npublic class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {\n\n    @Override\n    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n        // initialize dubbo beans\n        DubboSpringInitializer.initialize(registry);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableConfigurationBeanBinding.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.spring.context.config.ConfigurationBeanCustomizer;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.env.PropertySources;\n\n/**\n * Enables Spring's annotation-driven configuration bean from {@link PropertySources properties}.\n *\n * @see ConfigurationBeanBindingRegistrar\n * @see ConfigurationBeanBindingPostProcessor\n * @see ConfigurationBeanCustomizer\n */\n@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Import(ConfigurationBeanBindingRegistrar.class)\npublic @interface EnableConfigurationBeanBinding {\n\n    /**\n     * The default value for {@link #multiple()}\n     *\n     * @since 1.0.6\n     */\n    boolean DEFAULT_MULTIPLE = false;\n\n    /**\n     * The default value for {@link #ignoreUnknownFields()}\n     *\n     * @since 1.0.6\n     */\n    boolean DEFAULT_IGNORE_UNKNOWN_FIELDS = true;\n\n    /**\n     * The default value for {@link #ignoreInvalidFields()}\n     *\n     * @since 1.0.6\n     */\n    boolean DEFAULT_IGNORE_INVALID_FIELDS = true;\n\n    /**\n     * The name prefix of the properties that are valid to bind to the type of configuration.\n     *\n     * @return the name prefix of the properties to bind\n     */\n    String prefix();\n\n    /**\n     * @return The binding type of configuration.\n     */\n    Class<?> type();\n\n    /**\n     * It indicates whether {@link #prefix()} binding to multiple Spring Beans.\n     *\n     * @return the default value is <code>false</code>\n     * @see #DEFAULT_MULTIPLE\n     */\n    boolean multiple() default DEFAULT_MULTIPLE;\n\n    /**\n     * Set whether to ignore unknown fields, that is, whether to ignore bind\n     * parameters that do not have corresponding fields in the target object.\n     * <p>Default is \"true\". Turn this off to enforce that all bind parameters\n     * must have a matching field in the target object.\n     *\n     * @return the default value is <code>true</code>\n     * @see #DEFAULT_IGNORE_UNKNOWN_FIELDS\n     */\n    boolean ignoreUnknownFields() default DEFAULT_IGNORE_UNKNOWN_FIELDS;\n\n    /**\n     * Set whether to ignore invalid fields, that is, whether to ignore bind\n     * parameters that have corresponding fields in the target object which are\n     * not accessible (for example because of null values in the nested path).\n     * <p>Default is \"true\".\n     *\n     * @return the default value is <code>true</code>\n     * @see #DEFAULT_IGNORE_INVALID_FIELDS\n     */\n    boolean ignoreInvalidFields() default DEFAULT_IGNORE_INVALID_FIELDS;\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableConfigurationBeanBindings.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Import;\n\n/**\n * The annotation composes the multiple {@link EnableConfigurationBeanBinding EnableConfigurationBeanBindings}\n *\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Import(ConfigurationBeanBindingsRegister.class)\npublic @interface EnableConfigurationBeanBindings {\n\n    /**\n     * @return the array of {@link EnableConfigurationBeanBinding EnableConfigurationBeanBindings}\n     */\n    EnableConfigurationBeanBinding[] value();\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubbo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.AbstractConfig;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Enables Dubbo components as Spring Beans, equals\n * {@link DubboComponentScan} and {@link EnableDubboConfig} combination.\n * <p>\n * Note : {@link EnableDubbo} must base on Spring Framework 4.2 and above\n *\n * @see DubboComponentScan\n * @see EnableDubboConfig\n * @since 2.5.8\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\n@Documented\n@EnableDubboConfig\n@DubboComponentScan\npublic @interface EnableDubbo {\n\n    /**\n     * Base packages to scan for annotated @Service classes.\n     * <p>\n     * Use {@link #scanBasePackageClasses()} for a type-safe alternative to String-based\n     * package names.\n     *\n     * @return the base packages to scan\n     * @see DubboComponentScan#basePackages()\n     */\n    @AliasFor(annotation = DubboComponentScan.class, attribute = \"basePackages\")\n    String[] scanBasePackages() default {};\n\n    /**\n     * Type-safe alternative to {@link #scanBasePackages()} for specifying the packages to\n     * scan for annotated @Service classes. The package of each class specified will be\n     * scanned.\n     *\n     * @return classes from the base packages to scan\n     * @see DubboComponentScan#basePackageClasses\n     */\n    @AliasFor(annotation = DubboComponentScan.class, attribute = \"basePackageClasses\")\n    Class<?>[] scanBasePackageClasses() default {};\n\n    /**\n     * It indicates whether {@link AbstractConfig} binding to multiple Spring Beans.\n     *\n     * @return the default value is <code>true</code>\n     * @see EnableDubboConfig#multiple()\n     */\n    @AliasFor(annotation = EnableDubboConfig.class, attribute = \"multiple\")\n    boolean multipleConfig() default true;\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Import;\n\n/**\n * As a convenient and multiple {@link EnableConfigurationBeanBinding}\n * in default behavior , is equal to single bean bindings with below convention prefixes of properties:\n * <ul>\n * <li>{@link ApplicationConfig} binding to property : \"dubbo.application\"</li>\n * <li>{@link ModuleConfig} binding to property :  \"dubbo.module\"</li>\n * <li>{@link RegistryConfig} binding to property :  \"dubbo.registry\"</li>\n * <li>{@link ProtocolConfig} binding to property :  \"dubbo.protocol\"</li>\n * <li>{@link MonitorConfig} binding to property :  \"dubbo.monitor\"</li>\n * <li>{@link ProviderConfig} binding to property :  \"dubbo.provider\"</li>\n * <li>{@link ConsumerConfig} binding to property :  \"dubbo.consumer\"</li>\n * </ul>\n * <p>\n * In contrast, on multiple bean bindings that requires to set {@link #multiple()} to be <code>true</code> :\n * <ul>\n * <li>{@link ApplicationConfig} binding to property : \"dubbo.applications\"</li>\n * <li>{@link ModuleConfig} binding to property :  \"dubbo.modules\"</li>\n * <li>{@link RegistryConfig} binding to property :  \"dubbo.registries\"</li>\n * <li>{@link ProtocolConfig} binding to property :  \"dubbo.protocols\"</li>\n * <li>{@link MonitorConfig} binding to property :  \"dubbo.monitors\"</li>\n * <li>{@link ProviderConfig} binding to property :  \"dubbo.providers\"</li>\n * <li>{@link ConsumerConfig} binding to property :  \"dubbo.consumers\"</li>\n * </ul>\n *\n * @see EnableConfigurationBeanBinding\n * @see DubboConfigConfiguration\n * @see DubboConfigConfigurationRegistrar\n * @since 2.5.8\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\n@Documented\n@Import(DubboConfigConfigurationRegistrar.class)\npublic @interface EnableDubboConfig {\n\n    /**\n     * It indicates whether binding to multiple Spring Beans.\n     *\n     * @return the default value is <code>true</code>\n     * @revised 2.5.9\n     */\n    boolean multiple() default true;\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/ConfigurationBeanBinder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.config;\n\nimport org.apache.dubbo.config.spring.context.annotation.EnableConfigurationBeanBinding;\n\nimport java.util.Map;\n\nimport org.springframework.core.env.Environment;\n\n/**\n * The binder for the configuration bean\n *\n */\npublic interface ConfigurationBeanBinder {\n\n    /**\n     * Bind the properties in the {@link Environment} to Configuration bean under specified prefix.\n     *\n     * @param configurationProperties The configuration properties\n     * @param ignoreUnknownFields     whether to ignore unknown fields, the value is come\n     *                                from the attribute of {@link EnableConfigurationBeanBinding#ignoreUnknownFields()}\n     * @param ignoreInvalidFields     whether to ignore invalid fields, the value is come\n     *                                from the attribute of {@link EnableConfigurationBeanBinding#ignoreInvalidFields()}\n     * @param configurationBean       the bean of configuration\n     */\n    void bind(\n            Map<String, Object> configurationProperties,\n            boolean ignoreUnknownFields,\n            boolean ignoreInvalidFields,\n            Object configurationBean);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/ConfigurationBeanCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.config;\n\nimport org.apache.dubbo.config.spring.context.annotation.ConfigurationBeanBindingPostProcessor;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.Ordered;\n\n/**\n * The customizer for the configuration bean after {@link ConfigurationBeanBinder#bind its binding}.\n * <p>\n * If There are multiple {@link ConfigurationBeanCustomizer} beans in the Spring {@link ApplicationContext context},\n * they are executed orderly, thus the subclass should be aware to implement the {@link #getOrder()} method.\n *\n * @see ConfigurationBeanBinder\n * @see ConfigurationBeanBindingPostProcessor\n */\npublic interface ConfigurationBeanCustomizer extends Ordered {\n\n    /**\n     * Customize the configuration bean\n     *\n     * @param beanName          the name of the configuration bean\n     * @param configurationBean the configuration bean\n     */\n    void customize(String beanName, Object configurationBean);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/DefaultConfigurationBeanBinder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.config;\n\nimport java.util.Map;\n\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.validation.DataBinder;\n\n/**\n * The default {@link ConfigurationBeanBinder} implementation\n *\n * @see ConfigurationBeanBinder\n */\npublic class DefaultConfigurationBeanBinder implements ConfigurationBeanBinder {\n\n    @Override\n    public void bind(\n            Map<String, Object> configurationProperties,\n            boolean ignoreUnknownFields,\n            boolean ignoreInvalidFields,\n            Object configurationBean) {\n        DataBinder dataBinder = new DataBinder(configurationBean);\n        // Set ignored*\n        dataBinder.setIgnoreInvalidFields(ignoreUnknownFields);\n        dataBinder.setIgnoreUnknownFields(ignoreInvalidFields);\n        // Get properties under specified prefix from PropertySources\n        // Convert Map to MutablePropertyValues\n        MutablePropertyValues propertyValues = new MutablePropertyValues(configurationProperties);\n        // Bind\n        dataBinder.bind(propertyValues);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.config;\n\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.spring.context.properties.DubboConfigBinder;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.Ordered;\n\n/**\n * The Bean customizer for {@link AbstractConfig Dubbo Config}. Generally, The subclass will be  registered as a Spring\n * Bean that is used to {@link #customize(String, AbstractConfig) customize} {@link AbstractConfig Dubbo Config} bean\n * after {@link DubboConfigBinder#bind(String, AbstractConfig) its binding}.\n * <p>\n * If There are multiple {@link DubboConfigBeanCustomizer} beans in the Spring {@link ApplicationContext context}, they\n * are executed orderly, thus the subclass should be aware to implement the {@link #getOrder()} method.\n *\n * @see DubboConfigBinder#bind(String, AbstractConfig)\n * @since 2.6.6\n */\npublic interface DubboConfigBeanCustomizer extends ConfigurationBeanCustomizer, Ordered {\n\n    /**\n     * Customize {@link AbstractConfig Dubbo Config Bean}\n     *\n     * @param beanName        the name of {@link AbstractConfig Dubbo Config Bean}\n     * @param dubboConfigBean the instance of {@link AbstractConfig Dubbo Config Bean}\n     */\n    void customize(String beanName, AbstractConfig dubboConfigBean);\n\n    @Override\n    default void customize(String beanName, Object configurationBean) {\n        if (configurationBean instanceof AbstractConfig) {\n            customize(beanName, (AbstractConfig) configurationBean);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.config;\n\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.spring.beans.factory.config.DubboConfigDefaultPropertyValueBeanPostProcessor;\nimport org.apache.dubbo.config.spring.util.ObjectUtils;\n\nimport java.beans.PropertyDescriptor;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\n\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.springframework.beans.BeanUtils.getPropertyDescriptor;\n\n/**\n * {@link DubboConfigBeanCustomizer} for the default value for the \"name\" property that will be taken bean name\n * if absent.\n *\n * @since 2.6.6\n * @deprecated {@link DubboConfigDefaultPropertyValueBeanPostProcessor} instead\n */\n@Deprecated\npublic class NamePropertyDefaultValueDubboConfigBeanCustomizer implements DubboConfigBeanCustomizer {\n\n    /**\n     * The bean name of {@link NamePropertyDefaultValueDubboConfigBeanCustomizer}\n     *\n     * @since 2.7.1\n     */\n    public static final String BEAN_NAME = \"namePropertyDefaultValueDubboConfigBeanCustomizer\";\n\n    /**\n     * The name of property that is \"name\" maybe is absent in target class\n     */\n    private static final String PROPERTY_NAME = \"name\";\n\n    @Override\n    public void customize(String beanName, AbstractConfig dubboConfigBean) {\n\n        PropertyDescriptor propertyDescriptor = getPropertyDescriptor(dubboConfigBean.getClass(), PROPERTY_NAME);\n\n        if (propertyDescriptor != null) { // \"name\" property is present\n\n            Method getNameMethod = propertyDescriptor.getReadMethod();\n\n            if (getNameMethod == null) { // if \"getName\" method is absent\n                return;\n            }\n\n            Object propertyValue = ReflectionUtils.invokeMethod(getNameMethod, dubboConfigBean);\n\n            if (propertyValue != null) { // If The return value of \"getName\" method is not null\n                return;\n            }\n\n            Method setNameMethod = propertyDescriptor.getWriteMethod();\n            if (setNameMethod != null) { // \"setName\" and \"getName\" methods are present\n                if (Arrays.equals(\n                        ObjectUtils.of(String.class), setNameMethod.getParameterTypes())) { // the param type is String\n                    // set bean name to the value of the \"name\" property\n                    ReflectionUtils.invokeMethod(setNameMethod, dubboConfigBean, beanName);\n                }\n            }\n        }\n    }\n\n    @Override\n    public int getOrder() {\n        return HIGHEST_PRECEDENCE;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/DubboApplicationStateEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.event;\n\nimport org.apache.dubbo.common.deploy.DeployState;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * Dubbo's application state event on starting/started/stopping/stopped\n */\npublic class DubboApplicationStateEvent extends ApplicationEvent {\n\n    private final DeployState state;\n\n    private Throwable cause;\n\n    public DubboApplicationStateEvent(ApplicationModel applicationModel, DeployState state) {\n        super(applicationModel);\n        this.state = state;\n    }\n\n    public DubboApplicationStateEvent(ApplicationModel applicationModel, DeployState state, Throwable cause) {\n        super(applicationModel);\n        this.state = state;\n        this.cause = cause;\n    }\n\n    public ApplicationModel getApplicationModel() {\n        return (ApplicationModel) getSource();\n    }\n\n    public DeployState getState() {\n        return state;\n    }\n\n    public Throwable getCause() {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/DubboBootstrapStatedEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.event;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * A {@link org.springframework.context.ApplicationEvent} after {@link org.apache.dubbo.config.bootstrap.DubboBootstrap#start()} success\n *\n * @see org.springframework.context.ApplicationEvent\n * @see org.springframework.context.ApplicationListener\n * @see org.apache.dubbo.config.bootstrap.DubboBootstrap\n * @since 2.7.9\n */\n@Deprecated\npublic class DubboBootstrapStatedEvent extends ApplicationEvent {\n\n    /**\n     * Create a new ApplicationEvent.\n     *\n     * @param bootstrap {@link org.apache.dubbo.config.bootstrap.DubboBootstrap} bootstrap\n     */\n    public DubboBootstrapStatedEvent(DubboBootstrap bootstrap) {\n        super(bootstrap);\n    }\n\n    /**\n     * Get {@link org.apache.dubbo.config.bootstrap.DubboBootstrap} instance\n     *\n     * @return non-null\n     */\n    public DubboBootstrap getDubboBootstrap() {\n        return (DubboBootstrap) super.getSource();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/DubboBootstrapStopedEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.event;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * A {@link org.springframework.context.ApplicationEvent} after {@link org.apache.dubbo.config.bootstrap.DubboBootstrap#stop()} success\n *\n * @see org.springframework.context.ApplicationEvent\n * @see org.springframework.context.ApplicationListener\n * @see org.apache.dubbo.config.bootstrap.DubboBootstrap\n * @since 2.7.9\n */\n@Deprecated\npublic class DubboBootstrapStopedEvent extends ApplicationEvent {\n\n    /**\n     * Create a new ApplicationEvent.\n     *\n     * @param bootstrap {@link org.apache.dubbo.config.bootstrap.DubboBootstrap} bootstrap\n     */\n    public DubboBootstrapStopedEvent(DubboBootstrap bootstrap) {\n        super(bootstrap);\n    }\n\n    /**\n     * Get {@link org.apache.dubbo.config.bootstrap.DubboBootstrap} instance\n     *\n     * @return non-null\n     */\n    public DubboBootstrap getDubboBootstrap() {\n        return (DubboBootstrap) super.getSource();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/DubboConfigInitEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.event;\n\nimport org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * An {@link ApplicationEvent} to trigger init {@link DubboConfigBeanInitializer}.\n *\n */\npublic class DubboConfigInitEvent extends ApplicationEvent {\n    /**\n     * Create a new {@code ApplicationEvent}.\n     *\n     * @param source the object on which the event initially occurred or with\n     *               which the event is associated (never {@code null})\n     */\n    public DubboConfigInitEvent(ApplicationContext source) {\n        super(source);\n    }\n\n    /**\n     * Get the {@code ApplicationContext} that the event was raised for.\n     */\n    public final ApplicationContext getApplicationContext() {\n        return (ApplicationContext) getSource();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/DubboModuleStateEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.event;\n\nimport org.apache.dubbo.common.deploy.DeployState;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * Dubbo's module state event on starting/started/stopping/stopped\n */\npublic class DubboModuleStateEvent extends ApplicationEvent {\n\n    private final DeployState state;\n\n    private Throwable cause;\n\n    public DubboModuleStateEvent(ModuleModel applicationModel, DeployState state) {\n        super(applicationModel);\n        this.state = state;\n    }\n\n    public DubboModuleStateEvent(ModuleModel applicationModel, DeployState state, Throwable cause) {\n        super(applicationModel);\n        this.state = state;\n        this.cause = cause;\n    }\n\n    public ModuleModel getModule() {\n        return (ModuleModel) getSource();\n    }\n\n    public DeployState getState() {\n        return state;\n    }\n\n    public Throwable getCause() {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.event;\n\nimport org.apache.dubbo.config.spring.ServiceBean;\n\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\n\n/**\n * A {@link ApplicationEvent} after {@link ServiceBean} {@link ServiceBean#export() export} invocation\n *\n * @see ApplicationEvent\n * @see ApplicationListener\n * @see ServiceBean\n * @since 2.6.5\n */\npublic class ServiceBeanExportedEvent extends ApplicationEvent {\n\n    /**\n     * Create a new ApplicationEvent.\n     *\n     * @param serviceBean {@link ServiceBean} bean\n     */\n    public ServiceBeanExportedEvent(ServiceBean serviceBean) {\n        super(serviceBean);\n    }\n\n    /**\n     * Get {@link ServiceBean} instance\n     *\n     * @return non-null\n     */\n    public ServiceBean getServiceBean() {\n        return (ServiceBean) super.getSource();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/AbstractDubboConfigBinder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.properties;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\n\n/**\n * Abstract {@link DubboConfigBinder} implementation\n */\npublic abstract class AbstractDubboConfigBinder implements DubboConfigBinder {\n\n    private Iterable<PropertySource<?>> propertySources;\n\n    private boolean ignoreUnknownFields = true;\n\n    private boolean ignoreInvalidFields = false;\n\n    /**\n     * Get multiple {@link PropertySource propertySources}\n     *\n     * @return multiple {@link PropertySource propertySources}\n     */\n    protected Iterable<PropertySource<?>> getPropertySources() {\n        return propertySources;\n    }\n\n    public boolean isIgnoreUnknownFields() {\n        return ignoreUnknownFields;\n    }\n\n    @Override\n    public void setIgnoreUnknownFields(boolean ignoreUnknownFields) {\n        this.ignoreUnknownFields = ignoreUnknownFields;\n    }\n\n    public boolean isIgnoreInvalidFields() {\n        return ignoreInvalidFields;\n    }\n\n    @Override\n    public void setIgnoreInvalidFields(boolean ignoreInvalidFields) {\n        this.ignoreInvalidFields = ignoreInvalidFields;\n    }\n\n    @Override\n    public final void setEnvironment(Environment environment) {\n\n        if (environment instanceof ConfigurableEnvironment) {\n            this.propertySources = ((ConfigurableEnvironment) environment).getPropertySources();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.properties;\n\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.spring.util.PropertySourcesUtils;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.IntStream;\n\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.validation.DataBinder;\nimport org.springframework.validation.FieldError;\n\n/**\n * Default {@link DubboConfigBinder} implementation based on Spring {@link DataBinder}\n */\npublic class DefaultDubboConfigBinder extends AbstractDubboConfigBinder {\n\n    @Override\n    public <C extends AbstractConfig> void bind(String prefix, C dubboConfig) {\n        DataBinder dataBinder = new DataBinder(dubboConfig);\n        // Set ignored*\n        dataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields());\n        dataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields());\n        // Get properties under specified prefix from PropertySources\n        Map<String, Object> properties = PropertySourcesUtils.getSubProperties(getPropertySources(), prefix);\n        // Convert Map to MutablePropertyValues\n        MutablePropertyValues propertyValues = new MutablePropertyValues(properties);\n        // Bind\n        dataBinder.bind(propertyValues);\n        BindingResult bindingResult = dataBinder.getBindingResult();\n        if (bindingResult.hasGlobalErrors()) {\n            throw new RuntimeException(\n                    \"Data bind global error, please check config. config: \" + bindingResult.getGlobalError() + \"\");\n        }\n        if (bindingResult.hasFieldErrors()) {\n            throw new RuntimeException(buildErrorMsg(\n                    bindingResult.getFieldErrors(),\n                    prefix,\n                    dubboConfig.getClass().getSimpleName()));\n        }\n    }\n\n    private String buildErrorMsg(List<FieldError> errors, String prefix, String config) {\n        StringBuilder builder = new StringBuilder(\"Data bind error, please check config. config: \" + config\n                + \", prefix: \" + prefix + \" , error fields: [\" + errors.get(0).getField());\n        if (errors.size() > 1) {\n            IntStream.range(1, errors.size()).forEach(i -> {\n                builder.append(\", \" + errors.get(i).getField());\n            });\n        }\n        builder.append(']');\n        return builder.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/DubboConfigBinder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.properties;\n\nimport org.apache.dubbo.config.AbstractConfig;\n\nimport org.springframework.context.EnvironmentAware;\n\n/**\n * {@link AbstractConfig DubboConfig} Binder\n *\n * @see AbstractConfig\n * @see EnvironmentAware\n * @since 2.5.11\n */\npublic interface DubboConfigBinder extends EnvironmentAware {\n\n    /**\n     * Set whether to ignore unknown fields, that is, whether to ignore bind\n     * parameters that do not have corresponding fields in the target object.\n     * <p>Default is \"true\". Turn this off to enforce that all bind parameters\n     * must have a matching field in the target object.\n     *\n     * @see #bind\n     */\n    void setIgnoreUnknownFields(boolean ignoreUnknownFields);\n\n    /**\n     * Set whether to ignore invalid fields, that is, whether to ignore bind\n     * parameters that have corresponding fields in the target object which are\n     * not accessible (for example because of null values in the nested path).\n     * <p>Default is \"false\".\n     *\n     * @see #bind\n     */\n    void setIgnoreInvalidFields(boolean ignoreInvalidFields);\n\n    /**\n     * Bind the properties to Dubbo Config Object under specified prefix.\n     *\n     * @param prefix\n     * @param dubboConfig\n     */\n    <C extends AbstractConfig> void bind(String prefix, C dubboConfig);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/extension/SpringExtensionInjector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.extension;\n\nimport org.apache.dubbo.common.extension.ExtensionAccessor;\nimport org.apache.dubbo.common.extension.ExtensionInjector;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Arrays;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.context.ApplicationContext;\n\npublic class SpringExtensionInjector implements ExtensionInjector {\n\n    private ApplicationContext context;\n\n    @Deprecated\n    public static void addApplicationContext(final ApplicationContext context) {}\n\n    public static SpringExtensionInjector get(final ExtensionAccessor extensionAccessor) {\n        return (SpringExtensionInjector) extensionAccessor.getExtension(ExtensionInjector.class, \"spring\");\n    }\n\n    public ApplicationContext getContext() {\n        return context;\n    }\n\n    public void init(final ApplicationContext context) {\n        this.context = context;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> T getInstance(Class<T> type, String name) {\n        if (context == null) {\n            // ignore if spring context is not bound\n            return null;\n        }\n\n        // check @SPI annotation\n        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {\n            return null;\n        }\n\n        T bean = getOptionalBean(context, name, type);\n        if (bean != null) {\n            return bean;\n        }\n\n        // logger.warn(\"No spring extension (bean) named:\" + name + \", try to find an extension (bean) of type \" +\n        // type.getName());\n        return null;\n    }\n\n    private <T> T getOptionalBean(final ListableBeanFactory beanFactory, final String name, final Class<T> type) {\n        if (StringUtils.isEmpty(name)) {\n            return getOptionalBeanByType(beanFactory, type);\n        }\n        if (beanFactory.containsBean(name)) {\n            return beanFactory.getBean(name, type);\n        }\n        return null;\n    }\n\n    private <T> T getOptionalBeanByType(final ListableBeanFactory beanFactory, final Class<T> type) {\n        String[] beanNamesForType = beanFactory.getBeanNamesForType(type, true, false);\n        if (beanNamesForType == null) {\n            return null;\n        }\n        if (beanNamesForType.length > 1) {\n            throw new IllegalStateException(\"Expect single but found \" + beanNamesForType.length\n                    + \" beans in spring context: \" + Arrays.toString(beanNamesForType));\n        }\n        return beanFactory.getBean(beanNamesForType[0], type);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceAttributes.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference;\n\n/**\n * Attribute names of {@link org.apache.dubbo.config.annotation.DubboReference}\n * and {@link org.apache.dubbo.config.ReferenceConfig}\n */\npublic interface ReferenceAttributes {\n\n    String ID = \"id\";\n\n    String INTERFACE = \"interface\";\n\n    String INTERFACE_NAME = \"interfaceName\";\n\n    String INTERFACE_CLASS = \"interfaceClass\";\n\n    String ACTUAL_INTERFACE = \"actualInterface\";\n\n    String GENERIC = \"generic\";\n\n    String REGISTRY = \"registry\";\n\n    String REGISTRIES = \"registries\";\n\n    String REGISTRY_IDS = \"registryIds\";\n\n    String GROUP = \"group\";\n\n    String VERSION = \"version\";\n\n    String ARGUMENTS = \"arguments\";\n\n    String METHODS = \"methods\";\n\n    String PARAMETERS = \"parameters\";\n\n    String PROVIDED_BY = \"providedBy\";\n\n    String PROVIDER_PORT = \"providerPort\";\n\n    String URL = \"url\";\n\n    String CLIENT = \"client\";\n\n    //    /**\n    //     * When enable, prefer to call local service in the same JVM if it's present, default value is true\n    //     * @deprecated using scope=\"local\" or scope=\"remote\" instead\n    //     */\n    //    @Deprecated\n    String INJVM = \"injvm\";\n\n    String CHECK = \"check\";\n\n    String INIT = \"init\";\n\n    String LAZY = \"lazy\";\n\n    String STUBEVENT = \"stubevent\";\n\n    String RECONNECT = \"reconnect\";\n\n    String STICKY = \"sticky\";\n\n    String PROXY = \"proxy\";\n\n    String STUB = \"stub\";\n\n    String CLUSTER = \"cluster\";\n\n    String CONNECTIONS = \"connections\";\n\n    String CALLBACKS = \"callbacks\";\n\n    String ONCONNECT = \"onconnect\";\n\n    String ONDISCONNECT = \"ondisconnect\";\n\n    String OWNER = \"owner\";\n\n    String LAYER = \"layer\";\n\n    String RETRIES = \"retries\";\n\n    String LOAD_BALANCE = \"loadbalance\";\n\n    String ASYNC = \"async\";\n\n    String ACTIVES = \"actives\";\n\n    String SENT = \"sent\";\n\n    String MOCK = \"mock\";\n\n    String VALIDATION = \"validation\";\n\n    String TIMEOUT = \"timeout\";\n\n    String CACHE = \"cache\";\n\n    String FILTER = \"filter\";\n\n    String LISTENER = \"listener\";\n\n    String APPLICATION = \"application\";\n\n    String MODULE = \"module\";\n\n    String CONSUMER = \"consumer\";\n\n    String MONITOR = \"monitor\";\n\n    String PROTOCOL = \"protocol\";\n\n    String TAG = \"tag\";\n\n    String MERGER = \"merger\";\n\n    String SERVICES = \"services\";\n\n    String SCOPE = \"scope\";\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference;\n\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.ReferenceBean;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * <p>\n * Builder for ReferenceBean, used to return ReferenceBean instance in Java-config @Bean method,\n * equivalent to {@link DubboReference} annotation.\n * </p>\n *\n * <p>\n * <b>It is recommended to use {@link DubboReference} on the @Bean method in the Java-config class.</b>\n * </p>\n *\n * Step 1: Register ReferenceBean in Java-config class:\n * <pre class=\"code\">\n * &#64;Configuration\n * public class ReferenceConfiguration {\n *\n *     &#64;Bean\n *     public ReferenceBean&lt;HelloService&gt; helloService() {\n *         return new ReferenceBeanBuilder()\n *                 .setGroup(\"demo\")\n *                 .build();\n *     }\n *\n *     &#64;Bean\n *     public ReferenceBean&lt;HelloService&gt; helloService2() {\n *         return new ReferenceBean();\n *     }\n *\n *     &#64;Bean\n *     public ReferenceBean&lt;GenericService&gt; genericHelloService() {\n *         return new ReferenceBeanBuilder()\n *                 .setGroup(\"demo\")\n *                 .setInterface(HelloService.class)\n *                 .build();\n *     }\n *\n * }\n * </pre>\n *\n * Step 2: Inject ReferenceBean by @Autowired\n * <pre class=\"code\">\n * public class FooController {\n *     &#64;Autowired\n *     private HelloService helloService;\n *\n *     &#64;Autowired\n *     private GenericService genericHelloService;\n * }\n * </pre>\n *\n * @see org.apache.dubbo.config.annotation.DubboReference\n * @see org.apache.dubbo.config.spring.ReferenceBean\n */\npublic class ReferenceBeanBuilder {\n    private Map<String, Object> attributes = new HashMap<>();\n\n    public <T> ReferenceBean<T> build() {\n        return new ReferenceBean(attributes);\n    }\n\n    public ReferenceBeanBuilder setServices(String services) {\n        attributes.put(ReferenceAttributes.SERVICES, services);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setInterface(String interfaceName) {\n        attributes.put(ReferenceAttributes.INTERFACE_NAME, interfaceName);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setInterface(Class interfaceClass) {\n        attributes.put(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setClient(String client) {\n        attributes.put(ReferenceAttributes.CLIENT, client);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setUrl(String url) {\n        attributes.put(ReferenceAttributes.URL, url);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setConsumer(ConsumerConfig consumer) {\n        attributes.put(ReferenceAttributes.CONSUMER, consumer);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setConsumer(String consumer) {\n        attributes.put(ReferenceAttributes.CONSUMER, consumer);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setProtocol(String protocol) {\n        attributes.put(ReferenceAttributes.PROTOCOL, protocol);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setCheck(Boolean check) {\n        attributes.put(ReferenceAttributes.CHECK, check);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setInit(Boolean init) {\n        attributes.put(ReferenceAttributes.INIT, init);\n        return this;\n    }\n\n    // @Deprecated\n    public ReferenceBeanBuilder setGeneric(Boolean generic) {\n        attributes.put(ReferenceAttributes.GENERIC, generic);\n        return this;\n    }\n\n    /**\n     * @param injvm\n     * @deprecated instead, use the parameter <b>scope</b> to judge if it's in jvm, scope=local\n     */\n    @Deprecated\n    public ReferenceBeanBuilder setInjvm(Boolean injvm) {\n        attributes.put(ReferenceAttributes.INJVM, injvm);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setListener(String listener) {\n        attributes.put(ReferenceAttributes.LISTENER, listener);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setLazy(Boolean lazy) {\n        attributes.put(ReferenceAttributes.LAZY, lazy);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setOnconnect(String onconnect) {\n        attributes.put(ReferenceAttributes.ONCONNECT, onconnect);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setOndisconnect(String ondisconnect) {\n        attributes.put(ReferenceAttributes.ONDISCONNECT, ondisconnect);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setReconnect(String reconnect) {\n        attributes.put(ReferenceAttributes.RECONNECT, reconnect);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setSticky(Boolean sticky) {\n        attributes.put(ReferenceAttributes.STICKY, sticky);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setVersion(String version) {\n        attributes.put(ReferenceAttributes.VERSION, version);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setGroup(String group) {\n        attributes.put(ReferenceAttributes.GROUP, group);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setProvidedBy(String providedBy) {\n        attributes.put(ReferenceAttributes.PROVIDED_BY, providedBy);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setProviderPort(Integer providerPort) {\n        attributes.put(ReferenceAttributes.PROVIDER_PORT, providerPort);\n        return this;\n    }\n\n    //    public ReferenceBeanBuilder setRouter(String router) {\n    //        attributes.put(ReferenceAttributes.ROUTER, router);\n    //        return this;\n    //    }\n\n    public ReferenceBeanBuilder setStub(String stub) {\n        attributes.put(ReferenceAttributes.STUB, stub);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setCluster(String cluster) {\n        attributes.put(ReferenceAttributes.CLUSTER, cluster);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setProxy(String proxy) {\n        attributes.put(ReferenceAttributes.PROXY, proxy);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setConnections(Integer connections) {\n        attributes.put(ReferenceAttributes.CONNECTIONS, connections);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setFilter(String filter) {\n        attributes.put(ReferenceAttributes.FILTER, filter);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setLayer(String layer) {\n        attributes.put(ReferenceAttributes.LAYER, layer);\n        return this;\n    }\n\n    //    @Deprecated\n    //    public ReferenceBeanBuilder setApplication(ApplicationConfig application) {\n    //        attributes.put(ReferenceAttributes.APPLICATION, application);\n    //        return this;\n    //    }\n\n    //    @Deprecated\n    //    public ReferenceBeanBuilder setModule(ModuleConfig module) {\n    //        attributes.put(ReferenceAttributes.MODULE, module);\n    //        return this;\n    //    }\n\n    public ReferenceBeanBuilder setRegistry(String[] registryIds) {\n        attributes.put(ReferenceAttributes.REGISTRY, registryIds);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setRegistry(RegistryConfig registry) {\n        setRegistries(Arrays.asList(registry));\n        return this;\n    }\n\n    public ReferenceBeanBuilder setRegistries(List<? extends RegistryConfig> registries) {\n        attributes.put(ReferenceAttributes.REGISTRIES, registries);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setMethods(List<? extends MethodConfig> methods) {\n        attributes.put(ReferenceAttributes.METHODS, methods);\n        return this;\n    }\n\n    @Deprecated\n    public ReferenceBeanBuilder setMonitor(MonitorConfig monitor) {\n        attributes.put(ReferenceAttributes.MONITOR, monitor);\n        return this;\n    }\n\n    @Deprecated\n    public ReferenceBeanBuilder setMonitor(String monitor) {\n        attributes.put(ReferenceAttributes.MONITOR, monitor);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setOwner(String owner) {\n        attributes.put(ReferenceAttributes.OWNER, owner);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setCallbacks(Integer callbacks) {\n        attributes.put(ReferenceAttributes.CALLBACKS, callbacks);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setScope(String scope) {\n        attributes.put(ReferenceAttributes.SCOPE, scope);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setTag(String tag) {\n        attributes.put(ReferenceAttributes.TAG, tag);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setTimeout(Integer timeout) {\n        attributes.put(ReferenceAttributes.TIMEOUT, timeout);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setRetries(Integer retries) {\n        attributes.put(ReferenceAttributes.RETRIES, retries);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setLoadBalance(String loadbalance) {\n        attributes.put(ReferenceAttributes.LOAD_BALANCE, loadbalance);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setAsync(Boolean async) {\n        attributes.put(ReferenceAttributes.ASYNC, async);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setActives(Integer actives) {\n        attributes.put(ReferenceAttributes.ACTIVES, actives);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setSent(Boolean sent) {\n        attributes.put(ReferenceAttributes.SENT, sent);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setMock(String mock) {\n        attributes.put(ReferenceAttributes.MOCK, mock);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setMerger(String merger) {\n        attributes.put(ReferenceAttributes.MERGER, merger);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setCache(String cache) {\n        attributes.put(ReferenceAttributes.CACHE, cache);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setValidation(String validation) {\n        attributes.put(ReferenceAttributes.VALIDATION, validation);\n        return this;\n    }\n\n    public ReferenceBeanBuilder setParameters(Map<String, String> parameters) {\n        attributes.put(ReferenceAttributes.PARAMETERS, parameters);\n        return this;\n    }\n\n    //    public ReferenceBeanBuilder setAuth(Boolean auth) {\n    //        attributes.put(ReferenceAttributes.AUTH, auth);\n    //        return this;\n    //    }\n    //\n    //    public ReferenceBeanBuilder setForks(Integer forks) {\n    //        attributes.put(ReferenceAttributes.FORKS, forks);\n    //        return this;\n    //    }\n    //\n    //    @Deprecated\n    //    public ReferenceBeanBuilder setConfigCenter(ConfigCenterConfig configCenter) {\n    //        attributes.put(ReferenceAttributes.CONFIG_CENTER, configCenter);\n    //        return this;\n    //    }\n    //\n    //    @Deprecated\n    //    public ReferenceBeanBuilder setMetadataReportConfig(MetadataReportConfig metadataReportConfig) {\n    //        attributes.put(ReferenceAttributes.METADATA_REPORT_CONFIG, metadataReportConfig);\n    //        return this;\n    //    }\n    //\n    //    @Deprecated\n    //    public ReferenceBeanBuilder setMetrics(MetricsConfig metrics) {\n    //        attributes.put(ReferenceAttributes.METRICS, metrics);\n    //        return this;\n    //    }\n\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_INITIALIZER;\n\npublic class ReferenceBeanManager implements ApplicationContextAware {\n    public static final String BEAN_NAME = \"dubboReferenceBeanManager\";\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    // reference key -> reference bean names\n    private ConcurrentMap<String, CopyOnWriteArrayList<String>> referenceKeyMap = new ConcurrentHashMap<>();\n\n    // reference alias -> reference bean name\n    private ConcurrentMap<String, String> referenceAliasMap = new ConcurrentHashMap<>();\n\n    // reference bean name -> ReferenceBean\n    private ConcurrentMap<String, ReferenceBean> referenceBeanMap = new ConcurrentHashMap<>();\n\n    // reference key -> ReferenceConfig instance\n    private ConcurrentMap<String, ReferenceConfig> referenceConfigMap = new ConcurrentHashMap<>();\n\n    private ApplicationContext applicationContext;\n    private volatile boolean initialized = false;\n    private ModuleModel moduleModel;\n\n    public void addReference(ReferenceBean referenceBean) throws Exception {\n        String referenceBeanName = referenceBean.getId();\n        Assert.notEmptyString(referenceBeanName, \"The id of ReferenceBean cannot be empty\");\n\n        if (!initialized) {\n            // TODO add issue url to describe early initialization\n            logger.warn(\n                    CONFIG_DUBBO_BEAN_INITIALIZER,\n                    \"\",\n                    \"\",\n                    \"Early initialize reference bean before DubboConfigBeanInitializer,\"\n                            + \" the BeanPostProcessor has not been loaded at this time, which may cause abnormalities in some components (such as seata): \"\n                            + referenceBeanName\n                            + \" = \" + ReferenceBeanSupport.generateReferenceKey(referenceBean, applicationContext));\n        }\n        String referenceKey = getReferenceKeyByBeanName(referenceBeanName);\n        if (StringUtils.isEmpty(referenceKey)) {\n            referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, applicationContext);\n        }\n        ReferenceBean oldReferenceBean = referenceBeanMap.get(referenceBeanName);\n        if (oldReferenceBean != null) {\n            if (referenceBean != oldReferenceBean) {\n                String oldReferenceKey =\n                        ReferenceBeanSupport.generateReferenceKey(oldReferenceBean, applicationContext);\n                throw new IllegalStateException(\"Found duplicated ReferenceBean with id: \" + referenceBeanName\n                        + \", old: \" + oldReferenceKey + \", new: \" + referenceKey);\n            }\n            return;\n        }\n        referenceBeanMap.put(referenceBeanName, referenceBean);\n        // save cache, map reference key to referenceBeanName\n        this.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);\n\n        // if add reference after prepareReferenceBeans(), should init it immediately.\n        if (initialized) {\n            initReferenceBean(referenceBean);\n        }\n    }\n\n    private String getReferenceKeyByBeanName(String referenceBeanName) {\n        Set<Map.Entry<String, CopyOnWriteArrayList<String>>> entries = referenceKeyMap.entrySet();\n        for (Map.Entry<String, CopyOnWriteArrayList<String>> entry : entries) {\n            if (entry.getValue().contains(referenceBeanName)) {\n                return entry.getKey();\n            }\n        }\n        return null;\n    }\n\n    public void registerReferenceKeyAndBeanName(String referenceKey, String referenceBeanNameOrAlias) {\n        CopyOnWriteArrayList<String> list = ConcurrentHashMapUtils.computeIfAbsent(\n                referenceKeyMap, referenceKey, (key) -> new CopyOnWriteArrayList<>());\n        if (list.addIfAbsent(referenceBeanNameOrAlias)) {\n            // register bean name as alias\n            referenceAliasMap.put(referenceBeanNameOrAlias, list.get(0));\n        }\n    }\n\n    public ReferenceBean getById(String referenceBeanNameOrAlias) {\n        String referenceBeanName = transformName(referenceBeanNameOrAlias);\n        return referenceBeanMap.get(referenceBeanName);\n    }\n\n    // convert reference name/alias to referenceBeanName\n    private String transformName(String referenceBeanNameOrAlias) {\n        return referenceAliasMap.getOrDefault(referenceBeanNameOrAlias, referenceBeanNameOrAlias);\n    }\n\n    public List<String> getBeanNamesByKey(String key) {\n        return Collections.unmodifiableList(referenceKeyMap.getOrDefault(key, new CopyOnWriteArrayList<>()));\n    }\n\n    public Collection<ReferenceBean> getReferences() {\n        return new HashSet<>(referenceBeanMap.values());\n    }\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        this.applicationContext = applicationContext;\n    }\n\n    /**\n     * Initialize all reference beans, call at Dubbo starting\n     *\n     * @throws Exception\n     */\n    public void prepareReferenceBeans() throws Exception {\n        // get moduleModel here (called by DubboConfigBeanInitializer#afterPropertiesSet) to avoid getting null result.\n        moduleModel = DubboBeanUtils.getModuleModel(applicationContext);\n        initialized = true;\n        for (ReferenceBean referenceBean : getReferences()) {\n            initReferenceBean(referenceBean);\n        }\n    }\n\n    /**\n     * NOTE: This method should only call after all dubbo config beans and all property resolvers is loaded.\n     *\n     * @param referenceBean\n     * @throws Exception\n     */\n    public synchronized void initReferenceBean(ReferenceBean referenceBean) throws Exception {\n\n        if (referenceBean.getReferenceConfig() != null) {\n            return;\n        }\n\n        // TOTO check same unique service name but difference reference key (means difference attributes).\n\n        // reference key\n        String referenceKey = getReferenceKeyByBeanName(referenceBean.getId());\n        if (StringUtils.isEmpty(referenceKey)) {\n            referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, applicationContext);\n        }\n\n        ReferenceConfig referenceConfig = referenceConfigMap.get(referenceKey);\n        if (referenceConfig == null) {\n            // create real ReferenceConfig\n            Map<String, Object> referenceAttributes = ReferenceBeanSupport.getReferenceAttributes(referenceBean);\n            referenceConfig = ReferenceCreator.create(referenceAttributes, applicationContext)\n                    .defaultInterfaceClass(referenceBean.getObjectType())\n                    .build();\n\n            // set id if it is not a generated name\n            if (referenceBean.getId() != null && !referenceBean.getId().contains(\"#\")) {\n                referenceConfig.setId(referenceBean.getId());\n            }\n\n            // cache referenceConfig\n            referenceConfigMap.put(referenceKey, referenceConfig);\n\n            // register ReferenceConfig\n            moduleModel.getConfigManager().addReference(referenceConfig);\n            moduleModel.getDeployer().setPending();\n        }\n\n        // associate referenceConfig to referenceBean\n        referenceBean.setKeyAndReferenceConfig(referenceKey, referenceConfig);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanSupport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference;\n\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.annotation.ProvidedBy;\nimport org.apache.dubbo.config.spring.Constants;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.util.AnnotationUtils;\nimport org.apache.dubbo.config.spring.util.DubboAnnotationUtils;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\n\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.beans.PropertyValue;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinitionHolder;\nimport org.springframework.beans.factory.config.RuntimeBeanReference;\nimport org.springframework.beans.factory.config.TypedStringValue;\nimport org.springframework.beans.factory.support.AbstractBeanFactory;\nimport org.springframework.beans.factory.support.ManagedList;\nimport org.springframework.beans.factory.support.ManagedMap;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.util.ObjectUtils;\n\nimport static org.apache.dubbo.common.utils.StringUtils.join;\n\npublic class ReferenceBeanSupport {\n\n    private static final List<String> IGNORED_ATTRS = Arrays.asList(\n            ReferenceAttributes.ID,\n            ReferenceAttributes.GROUP,\n            ReferenceAttributes.VERSION,\n            ReferenceAttributes.INTERFACE,\n            ReferenceAttributes.INTERFACE_NAME,\n            ReferenceAttributes.INTERFACE_CLASS);\n\n    public static void convertReferenceProps(Map<String, Object> attributes, Class defaultInterfaceClass) {\n\n        // interface class\n        String interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE);\n        if (interfaceName == null) {\n            interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE_NAME);\n        }\n        if (interfaceName == null) {\n            Object interfaceClassValue = attributes.get(ReferenceAttributes.INTERFACE_CLASS);\n            if (interfaceClassValue instanceof Class) {\n                interfaceName = ((Class<?>) interfaceClassValue).getName();\n            } else if (interfaceClassValue instanceof String) {\n                if (interfaceClassValue.equals(\"void\")) {\n                    attributes.remove(ReferenceAttributes.INTERFACE_CLASS);\n                } else {\n                    interfaceName = (String) interfaceClassValue;\n                }\n            }\n        }\n        if (interfaceName == null && defaultInterfaceClass != GenericService.class) {\n            interfaceName = defaultInterfaceClass.getName();\n        }\n        Assert.notEmptyString(interfaceName, \"The interface class or name of reference was not found\");\n        ProvidedBy providedbBy = null;\n        if (defaultInterfaceClass != null) {\n            providedbBy = (ProvidedBy) defaultInterfaceClass.getAnnotation(ProvidedBy.class);\n        }\n        if (providedbBy != null && providedbBy.name() != null && providedbBy.name().length > 0) {\n            int providedByReferenceLength = providedbBy.name().length;\n            Object providedByServices = attributes.get(ReferenceAttributes.PROVIDED_BY);\n            int providedByInterfaceLength = 0;\n            String[] providedByInterfaceServices = null;\n            if (providedByServices != null) {\n                providedByInterfaceLength = ((String[]) providedByServices).length;\n                providedByInterfaceServices = (String[]) providedByServices;\n            }\n            String[] providedbByServices = new String[providedByReferenceLength + providedByInterfaceLength];\n            System.arraycopy(providedbBy.name(), 0, providedbByServices, 0, providedByReferenceLength);\n            if (providedByInterfaceLength > 0) {\n                System.arraycopy(\n                        providedByInterfaceServices,\n                        0,\n                        providedbByServices,\n                        providedByReferenceLength,\n                        providedByInterfaceLength);\n            }\n            attributes.put(ReferenceAttributes.PROVIDED_BY, providedbByServices);\n        }\n        attributes.put(ReferenceAttributes.INTERFACE, interfaceName);\n        attributes.remove(ReferenceAttributes.INTERFACE_NAME);\n        attributes.remove(ReferenceAttributes.INTERFACE_CLASS);\n\n        // reset generic value\n        String generic = String.valueOf(defaultInterfaceClass == GenericService.class);\n        String oldGeneric = attributes.containsValue(ReferenceAttributes.GENERIC)\n                ? String.valueOf(attributes.get(ReferenceAttributes.GENERIC))\n                : \"false\";\n        if (!StringUtils.isEquals(oldGeneric, generic)) {\n            attributes.put(ReferenceAttributes.GENERIC, generic);\n        }\n\n        // Specially convert @DubboReference attribute name/value to ReferenceConfig property\n        // String[] registry => String registryIds\n        String[] registryIds = (String[]) attributes.get(ReferenceAttributes.REGISTRY);\n        if (registryIds != null) {\n            String value = join(registryIds, \",\");\n            attributes.remove(ReferenceAttributes.REGISTRY);\n            attributes.put(ReferenceAttributes.REGISTRY_IDS, value);\n        }\n    }\n\n    public static String generateReferenceKey(Map<String, Object> attributes, ApplicationContext applicationContext) {\n\n        String interfaceClass = (String) attributes.get(ReferenceAttributes.INTERFACE);\n        Assert.notEmptyString(interfaceClass, \"No interface class or name found from attributes\");\n        String group = (String) attributes.get(ReferenceAttributes.GROUP);\n        String version = (String) attributes.get(ReferenceAttributes.VERSION);\n\n        // ReferenceBean:group/interface:version\n        StringBuilder beanNameBuilder = new StringBuilder(\"ReferenceBean:\");\n        if (StringUtils.isNotEmpty(group)) {\n            beanNameBuilder.append(group).append('/');\n        }\n        beanNameBuilder.append(interfaceClass);\n        if (StringUtils.isNotEmpty(version)) {\n            beanNameBuilder.append(':').append(version);\n        }\n\n        // append attributes\n        beanNameBuilder.append('(');\n        // sort attributes keys\n        List<String> sortedAttrKeys = new ArrayList<>(attributes.keySet());\n        Collections.sort(sortedAttrKeys);\n        for (String key : sortedAttrKeys) {\n            if (IGNORED_ATTRS.contains(key)) {\n                continue;\n            }\n            Object value = attributes.get(key);\n            value = convertToString(key, value);\n\n            beanNameBuilder.append(key).append('=').append(value).append(',');\n        }\n\n        // replace the latest \",\" to be \")\"\n        if (beanNameBuilder.charAt(beanNameBuilder.length() - 1) == ',') {\n            beanNameBuilder.setCharAt(beanNameBuilder.length() - 1, ')');\n        } else {\n            beanNameBuilder.append(')');\n        }\n\n        String referenceKey = beanNameBuilder.toString();\n        if (applicationContext != null) {\n            // resolve placeholder with Spring Environment\n            referenceKey = applicationContext.getEnvironment().resolvePlaceholders(referenceKey);\n            // resolve placeholder with Spring BeanFactory ( using\n            // PropertyResourceConfigurer/PropertySourcesPlaceholderConfigurer )\n            referenceKey = ((AbstractBeanFactory) applicationContext.getAutowireCapableBeanFactory())\n                    .resolveEmbeddedValue(referenceKey);\n        }\n        return referenceKey;\n    }\n\n    private static String convertToString(String key, Object obj) {\n        if (obj == null) {\n            return null;\n        }\n        if (ReferenceAttributes.PARAMETERS.equals(key) && obj instanceof String[]) {\n            // convert parameters array pairs to map\n            obj = DubboAnnotationUtils.convertParameters((String[]) obj);\n        }\n\n        // to string\n        if (obj instanceof Annotation) {\n            AnnotationAttributes attributes = AnnotationUtils.getAnnotationAttributes((Annotation) obj, true);\n            for (Map.Entry<String, Object> entry : attributes.entrySet()) {\n                entry.setValue(convertToString(entry.getKey(), entry.getValue()));\n            }\n            return String.valueOf(attributes);\n        } else if (obj.getClass().isArray()) {\n            Object[] array = ObjectUtils.toObjectArray(obj);\n            String[] newArray = new String[array.length];\n            for (int i = 0; i < array.length; i++) {\n                newArray[i] = convertToString(null, array[i]);\n            }\n            Arrays.sort(newArray);\n            return Arrays.toString(newArray);\n        } else if (obj instanceof Map) {\n            Map<String, Object> map = (Map<String, Object>) obj;\n            TreeMap newMap = new TreeMap();\n            for (Map.Entry<String, Object> entry : map.entrySet()) {\n                newMap.put(entry.getKey(), convertToString(entry.getKey(), entry.getValue()));\n            }\n            return String.valueOf(newMap);\n        } else {\n            return String.valueOf(obj);\n        }\n    }\n\n    /**\n     * Convert to raw props, without parsing nested config objects\n     */\n    public static Map<String, Object> convertPropertyValues(MutablePropertyValues propertyValues) {\n        Map<String, Object> referenceProps = new LinkedHashMap<>();\n        for (PropertyValue propertyValue : propertyValues.getPropertyValueList()) {\n            String propertyName = propertyValue.getName();\n            Object value = propertyValue.getValue();\n            if (ReferenceAttributes.METHODS.equals(propertyName)\n                    || ReferenceAttributes.ARGUMENTS.equals(propertyName)) {\n                ManagedList managedList = (ManagedList) value;\n                List<Map<String, Object>> elementList = new ArrayList<>();\n                for (Object el : managedList) {\n                    Map<String, Object> element = convertPropertyValues(\n                            ((BeanDefinitionHolder) el).getBeanDefinition().getPropertyValues());\n                    element.remove(ReferenceAttributes.ID);\n                    elementList.add(element);\n                }\n                value = elementList.toArray(new Object[0]);\n            } else if (ReferenceAttributes.PARAMETERS.equals(propertyName)) {\n                value = createParameterMap((ManagedMap) value);\n            }\n            // convert ref\n            if (value instanceof RuntimeBeanReference) {\n                RuntimeBeanReference beanReference = (RuntimeBeanReference) value;\n                value = beanReference.getBeanName();\n            }\n\n            if (value == null || (value instanceof String && StringUtils.isBlank((String) value))) {\n                // ignore null or blank string\n                continue;\n            }\n\n            referenceProps.put(propertyName, value);\n        }\n\n        return referenceProps;\n    }\n\n    private static Map<String, String> createParameterMap(ManagedMap managedMap) {\n        Map<String, String> map = new LinkedHashMap<>();\n        Set<Map.Entry<String, TypedStringValue>> entrySet = managedMap.entrySet();\n        for (Map.Entry<String, TypedStringValue> entry : entrySet) {\n            map.put(entry.getKey(), entry.getValue().getValue());\n        }\n        return map;\n    }\n\n    public static String generateReferenceKey(ReferenceBean referenceBean, ApplicationContext applicationContext) {\n        return generateReferenceKey(getReferenceAttributes(referenceBean), applicationContext);\n    }\n\n    public static String generateReferenceKey(BeanDefinition beanDefinition, ApplicationContext applicationContext) {\n        return generateReferenceKey(getReferenceAttributes(beanDefinition), applicationContext);\n    }\n\n    public static Map<String, Object> getReferenceAttributes(ReferenceBean referenceBean) {\n        Map<String, Object> referenceProps = referenceBean.getReferenceProps();\n        if (referenceProps == null) {\n            MutablePropertyValues propertyValues = referenceBean.getPropertyValues();\n            if (propertyValues == null) {\n                throw new RuntimeException(\n                        \"ReferenceBean is invalid, 'referenceProps' and 'propertyValues' cannot both be empty.\");\n            }\n            referenceProps = convertPropertyValues(propertyValues);\n        }\n        return referenceProps;\n    }\n\n    public static Map<String, Object> getReferenceAttributes(BeanDefinition beanDefinition) {\n        Map<String, Object> referenceProps = null;\n        if (beanDefinition.hasAttribute(Constants.REFERENCE_PROPS)) {\n            referenceProps = (Map<String, Object>) beanDefinition.getAttribute(Constants.REFERENCE_PROPS);\n        } else {\n            referenceProps = convertPropertyValues(beanDefinition.getPropertyValues());\n        }\n        return referenceProps;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceCreator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.config.ArgumentConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.annotation.Argument;\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationPropertyValuesAdapter;\nimport org.apache.dubbo.config.spring.util.AnnotationUtils;\nimport org.apache.dubbo.config.spring.util.DubboAnnotationUtils;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.config.spring.util.ObjectUtils;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Map;\n\nimport org.springframework.beans.propertyeditors.StringTrimmerEditor;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\nimport org.springframework.validation.DataBinder;\n\n/**\n * {@link ReferenceConfig} Creator for @{@link DubboReference}\n *\n * @since 3.0\n */\npublic class ReferenceCreator {\n\n    // Ignore those fields\n    static final String[] IGNORE_FIELD_NAMES =\n            ObjectUtils.of(\"application\", \"module\", \"consumer\", \"monitor\", \"registry\", \"interfaceClass\");\n\n    private static final String ONRETURN = \"onreturn\";\n\n    private static final String ONTHROW = \"onthrow\";\n\n    private static final String ONINVOKE = \"oninvoke\";\n\n    private static final String ISRETURN = \"isReturn\";\n\n    private static final String METHOD = \"Method\";\n\n    protected final Logger logger = LoggerFactory.getLogger(getClass());\n\n    protected final Map<String, Object> attributes;\n\n    protected final ApplicationContext applicationContext;\n\n    protected final ClassLoader classLoader;\n\n    protected Class<?> defaultInterfaceClass;\n    private final ModuleModel moduleModel;\n\n    private ReferenceCreator(Map<String, Object> attributes, ApplicationContext applicationContext) {\n        Assert.notNull(attributes, \"The Annotation attributes must not be null!\");\n        Assert.notNull(applicationContext, \"The ApplicationContext must not be null!\");\n        this.attributes = attributes;\n        this.applicationContext = applicationContext;\n        this.classLoader = applicationContext.getClassLoader() != null\n                ? applicationContext.getClassLoader()\n                : Thread.currentThread().getContextClassLoader();\n        moduleModel = DubboBeanUtils.getModuleModel(applicationContext);\n        Assert.notNull(moduleModel, \"ModuleModel not found in Spring ApplicationContext\");\n    }\n\n    public final ReferenceConfig build() throws Exception {\n\n        ReferenceConfig configBean = new ReferenceConfig();\n\n        configureBean(configBean);\n\n        if (logger.isInfoEnabled()) {\n            logger.info(\"The configBean[type:\" + configBean.getClass().getSimpleName() + \"<\"\n                    + defaultInterfaceClass.getTypeName() + \">\" + \"] has been built.\");\n        }\n\n        return configBean;\n    }\n\n    protected void configureBean(ReferenceConfig referenceConfig) throws Exception {\n\n        populateBean(referenceConfig);\n\n        configureMonitorConfig(referenceConfig);\n\n        configureModuleConfig(referenceConfig);\n\n        configureConsumerConfig(referenceConfig);\n    }\n\n    private void configureMonitorConfig(ReferenceConfig configBean) {\n        String monitorConfigId = AnnotationUtils.getAttribute(attributes, \"monitor\");\n        if (StringUtils.hasText(monitorConfigId)) {\n            MonitorConfig monitorConfig = getConfig(monitorConfigId, MonitorConfig.class);\n            configBean.setMonitor(monitorConfig);\n        }\n    }\n\n    private void configureModuleConfig(ReferenceConfig configBean) {\n        String moduleConfigId = AnnotationUtils.getAttribute(attributes, \"module\");\n        if (StringUtils.hasText(moduleConfigId)) {\n            ModuleConfig moduleConfig = getConfig(moduleConfigId, ModuleConfig.class);\n            configBean.setModule(moduleConfig);\n        }\n    }\n\n    private void configureConsumerConfig(ReferenceConfig<?> referenceBean) {\n        ConsumerConfig consumerConfig = null;\n        Object consumer = AnnotationUtils.getAttribute(attributes, \"consumer\");\n        if (consumer != null) {\n            if (consumer instanceof String) {\n                consumerConfig = getConfig((String) consumer, ConsumerConfig.class);\n            } else if (consumer instanceof ConsumerConfig) {\n                consumerConfig = (ConsumerConfig) consumer;\n            } else {\n                throw new IllegalArgumentException(\"Unexpected 'consumer' attribute value: \" + consumer);\n            }\n            referenceBean.setConsumer(consumerConfig);\n        }\n    }\n\n    private <T extends AbstractConfig> T getConfig(String configIdOrName, Class<T> configType) {\n        // 1. find in ModuleConfigManager\n        T config = moduleModel\n                .getConfigManager()\n                .getConfig(configType, configIdOrName)\n                .orElse(null);\n        if (config == null) {\n            // 2. find in Spring ApplicationContext\n            if (applicationContext.containsBean(configIdOrName)) {\n                config = applicationContext.getBean(configIdOrName, configType);\n            }\n        }\n        if (config == null) {\n            throw new IllegalArgumentException(configType.getSimpleName() + \" not found: \" + configIdOrName);\n        }\n        return config;\n    }\n\n    protected void populateBean(ReferenceConfig referenceConfig) {\n        Assert.notNull(defaultInterfaceClass, \"The default interface class cannot be empty!\");\n        // convert attributes, e.g. interface, registry\n        ReferenceBeanSupport.convertReferenceProps(attributes, defaultInterfaceClass);\n\n        DataBinder dataBinder = new DataBinder(referenceConfig);\n        // Register CustomEditors for special fields\n        dataBinder.registerCustomEditor(String.class, \"filter\", new StringTrimmerEditor(true));\n        dataBinder.registerCustomEditor(String.class, \"listener\", new StringTrimmerEditor(true));\n\n        DefaultConversionService conversionService = new DefaultConversionService();\n\n        // convert String[] to Map (such as @Method.parameters())\n        conversionService.addConverter(String[].class, Map.class, DubboAnnotationUtils::convertParameters);\n\n        // convert Map to MethodConfig\n        conversionService.addConverter(\n                Map.class, MethodConfig.class, source -> createMethodConfig(source, conversionService));\n\n        // convert @Method to MethodConfig\n        conversionService.addConverter(Method.class, MethodConfig.class, source -> {\n            Map<String, Object> methodAttributes = AnnotationUtils.getAnnotationAttributes(source, true);\n            return createMethodConfig(methodAttributes, conversionService);\n        });\n\n        // convert Map to ArgumentConfig\n        conversionService.addConverter(Map.class, ArgumentConfig.class, source -> {\n            ArgumentConfig argumentConfig = new ArgumentConfig();\n            DataBinder argDataBinder = new DataBinder(argumentConfig);\n            argDataBinder.setConversionService(conversionService);\n            argDataBinder.bind(new AnnotationPropertyValuesAdapter(source, applicationContext.getEnvironment()));\n            return argumentConfig;\n        });\n\n        // convert @Argument to ArgumentConfig\n        conversionService.addConverter(Argument.class, ArgumentConfig.class, source -> {\n            ArgumentConfig argumentConfig = new ArgumentConfig();\n            DataBinder argDataBinder = new DataBinder(argumentConfig);\n            argDataBinder.setConversionService(conversionService);\n            argDataBinder.bind(new AnnotationPropertyValuesAdapter(source, applicationContext.getEnvironment()));\n            return argumentConfig;\n        });\n\n        // Bind annotation attributes\n        dataBinder.setConversionService(conversionService);\n        dataBinder.bind(new AnnotationPropertyValuesAdapter(\n                attributes, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES));\n    }\n\n    private MethodConfig createMethodConfig(\n            Map<String, Object> methodAttributes, DefaultConversionService conversionService) {\n        String[] callbacks = new String[] {ONINVOKE, ONRETURN, ONTHROW};\n        for (String callbackName : callbacks) {\n            Object value = methodAttributes.get(callbackName);\n            if (value instanceof String) {\n                // parse callback: beanName.methodName\n                String strValue = (String) value;\n                int index = strValue.lastIndexOf(\".\");\n                if (index != -1) {\n                    String beanName = strValue.substring(0, index);\n                    String methodName = strValue.substring(index + 1);\n                    methodAttributes.put(callbackName, applicationContext.getBean(beanName));\n                    methodAttributes.put(callbackName + METHOD, methodName);\n                } else {\n                    methodAttributes.put(callbackName, applicationContext.getBean(strValue));\n                }\n            }\n        }\n\n        MethodConfig methodConfig = new MethodConfig();\n        DataBinder mcDataBinder = new DataBinder(methodConfig);\n        methodConfig.setReturn((Boolean) methodAttributes.get(ISRETURN));\n        mcDataBinder.setConversionService(conversionService);\n        AnnotationPropertyValuesAdapter propertyValues =\n                new AnnotationPropertyValuesAdapter(methodAttributes, applicationContext.getEnvironment());\n        mcDataBinder.bind(propertyValues);\n        return methodConfig;\n    }\n\n    public static ReferenceCreator create(Map<String, Object> attributes, ApplicationContext applicationContext) {\n        return new ReferenceCreator(attributes, applicationContext);\n    }\n\n    public ReferenceCreator defaultInterfaceClass(Class<?> interfaceClass) {\n        this.defaultInterfaceClass = interfaceClass;\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/AnnotationBeanDefinitionParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.schema;\n\nimport org.apache.dubbo.config.spring.util.SpringCompatUtils;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;\nimport org.springframework.beans.factory.xml.ParserContext;\nimport org.w3c.dom.Element;\n\nimport static org.springframework.util.StringUtils.commaDelimitedListToStringArray;\nimport static org.springframework.util.StringUtils.trimArrayElements;\n\n/**\n * @link BeanDefinitionParser}\n * @see ServiceAnnotationPostProcessor\n * @see ReferenceAnnotationBeanPostProcessor\n * @since 2.5.9\n */\npublic class AnnotationBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {\n\n    /**\n     * parse\n     * <prev>\n     * &lt;dubbo:annotation package=\"\" /&gt;\n     * </prev>\n     *\n     * @param element\n     * @param parserContext\n     * @param builder\n     */\n    @Override\n    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {\n\n        String packageToScan = element.getAttribute(\"package\");\n\n        String[] packagesToScan = trimArrayElements(commaDelimitedListToStringArray(packageToScan));\n\n        builder.addConstructorArgValue(packagesToScan);\n\n        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);\n\n        /**\n         * @since 2.7.6 Register the common beans\n         * @since 2.7.8 comment this code line, and migrated to\n         * @see DubboNamespaceHandler#parse(Element, ParserContext)\n         * @see https://github.com/apache/dubbo/issues/6174\n         */\n        // registerCommonBeans(parserContext.getRegistry());\n    }\n\n    @Override\n    protected boolean shouldGenerateIdAsFallback() {\n        return true;\n    }\n\n    @Override\n    protected Class<?> getBeanClass(Element element) {\n        return SpringCompatUtils.serviceAnnotationPostProcessor();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.schema;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.MethodUtils;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.AbstractServiceConfig;\nimport org.apache.dubbo.config.ArgumentConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.nested.AggregationConfig;\nimport org.apache.dubbo.config.nested.HistogramConfig;\nimport org.apache.dubbo.config.nested.PrometheusConfig;\nimport org.apache.dubbo.config.spring.Constants;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.ServiceBean;\nimport org.apache.dubbo.config.spring.reference.ReferenceAttributes;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Pattern;\n\nimport org.springframework.beans.PropertyValue;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinitionHolder;\nimport org.springframework.beans.factory.config.RuntimeBeanReference;\nimport org.springframework.beans.factory.config.TypedStringValue;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.GenericBeanDefinition;\nimport org.springframework.beans.factory.support.ManagedList;\nimport org.springframework.beans.factory.support.ManagedMap;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.beans.factory.xml.BeanDefinitionParser;\nimport org.springframework.beans.factory.xml.ParserContext;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.HIDE_KEY_PREFIX;\nimport static org.apache.dubbo.config.spring.util.SpringCompatUtils.getPropertyValue;\n\n/**\n * AbstractBeanDefinitionParser\n *\n * @export\n */\npublic class DubboBeanDefinitionParser implements BeanDefinitionParser {\n\n    private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class);\n    private static final Pattern GROUP_AND_VERSION = Pattern.compile(\"^[\\\\-.0-9_a-zA-Z]+(\\\\:[\\\\-.0-9_a-zA-Z]+)?$\");\n    private static final String ONRETURN = \"onreturn\";\n    private static final String ONTHROW = \"onthrow\";\n    private static final String ONINVOKE = \"oninvoke\";\n    private static final String EXECUTOR = \"executor\";\n    private static final String METHOD = \"Method\";\n    private static final String BEAN_NAME = \"BEAN_NAME\";\n    private static boolean resolvePlaceholdersEnabled = true;\n    private final Class<?> beanClass;\n    private static Map<String, Map<String, Class>> beanPropsCache = new HashMap<>();\n\n    public DubboBeanDefinitionParser(Class<?> beanClass) {\n        this.beanClass = beanClass;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static RootBeanDefinition parse(\n            Element element, ParserContext parserContext, Class<?> beanClass, boolean registered) {\n        RootBeanDefinition beanDefinition = new RootBeanDefinition();\n        beanDefinition.setBeanClass(beanClass);\n        beanDefinition.setLazyInit(false);\n        if (ServiceBean.class.equals(beanClass)) {\n            beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);\n        }\n        // config id\n        String configId = resolveAttribute(element, \"id\", parserContext);\n        if (StringUtils.isNotEmpty(configId)) {\n            beanDefinition.getPropertyValues().addPropertyValue(\"id\", configId);\n        }\n\n        String configName = \"\";\n        // get configName from name\n        if (StringUtils.isEmpty(configId)) {\n            configName = resolveAttribute(element, \"name\", parserContext);\n        }\n\n        String beanName = configId;\n        if (StringUtils.isEmpty(beanName)) {\n            // generate bean name\n            String prefix = beanClass.getName();\n            int counter = 0;\n            beanName = prefix + (StringUtils.isEmpty(configName) ? \"#\" : (\"#\" + configName + \"#\")) + counter;\n            while (parserContext.getRegistry().containsBeanDefinition(beanName)) {\n                beanName = prefix + (StringUtils.isEmpty(configName) ? \"#\" : (\"#\" + configName + \"#\")) + (counter++);\n            }\n        }\n        beanDefinition.setAttribute(BEAN_NAME, beanName);\n\n        if (ProtocolConfig.class.equals(beanClass)) {\n            //            for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {\n            //                BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);\n            //                PropertyValue property = definition.getPropertyValues().getPropertyValue(\"protocol\");\n            //                if (property != null) {\n            //                    Object value = property.getValue();\n            //                    if (value instanceof ProtocolConfig && beanName.equals(((ProtocolConfig)\n            // value).getName())) {\n            //                        definition.getPropertyValues().addPropertyValue(\"protocol\", new\n            // RuntimeBeanReference(beanName));\n            //                    }\n            //                }\n            //            }\n        } else if (ServiceBean.class.equals(beanClass)) {\n            String className = resolveAttribute(element, \"class\", parserContext);\n            if (StringUtils.isNotEmpty(className)) {\n                RootBeanDefinition classDefinition = new RootBeanDefinition();\n                classDefinition.setBeanClass(ReflectUtils.forName(className));\n                classDefinition.setLazyInit(false);\n                parseProperties(element.getChildNodes(), classDefinition, parserContext);\n                beanDefinition\n                        .getPropertyValues()\n                        .addPropertyValue(\"ref\", new BeanDefinitionHolder(classDefinition, beanName + \"Impl\"));\n            }\n        }\n\n        Map<String, Class> beanPropTypeMap = beanPropsCache.get(beanClass.getName());\n        if (beanPropTypeMap == null) {\n            beanPropTypeMap = new HashMap<>();\n            beanPropsCache.put(beanClass.getName(), beanPropTypeMap);\n            if (ReferenceBean.class.equals(beanClass)) {\n                // extract bean props from ReferenceConfig\n                getPropertyMap(ReferenceConfig.class, beanPropTypeMap);\n            } else {\n                getPropertyMap(beanClass, beanPropTypeMap);\n            }\n        }\n\n        ManagedMap parameters = null;\n        Set<String> processedProps = new HashSet<>();\n        for (Map.Entry<String, Class> entry : beanPropTypeMap.entrySet()) {\n            String beanProperty = entry.getKey();\n            Class type = entry.getValue();\n            String property = StringUtils.camelToSplitName(beanProperty, \"-\");\n            processedProps.add(property);\n            if (\"parameters\".equals(property)) {\n                parameters = parseParameters(element.getChildNodes(), beanDefinition, parserContext);\n            } else if (\"methods\".equals(property)) {\n                parseMethods(beanName, element.getChildNodes(), beanDefinition, parserContext);\n            } else if (\"arguments\".equals(property)) {\n                parseArguments(beanName, element.getChildNodes(), beanDefinition, parserContext);\n            } else {\n                String value = resolveAttribute(element, property, parserContext);\n                if (StringUtils.isNotBlank(value)) {\n                    value = value.trim();\n                    if (\"registry\".equals(property) && RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(value)) {\n                        RegistryConfig registryConfig = new RegistryConfig();\n                        registryConfig.setAddress(RegistryConfig.NO_AVAILABLE);\n                        // see AbstractInterfaceConfig#registries, It will be invoker setRegistries method when\n                        // BeanDefinition is registered,\n                        beanDefinition.getPropertyValues().addPropertyValue(\"registries\", registryConfig);\n                        // If registry is N/A, don't init it until the reference is invoked\n                        beanDefinition.setLazyInit(true);\n                    } else if (\"provider\".equals(property)\n                            || \"registry\".equals(property)\n                            || (\"protocol\".equals(property)\n                                    && AbstractServiceConfig.class.isAssignableFrom(beanClass))) {\n                        /**\n                         * For 'provider' 'protocol' 'registry', keep literal value (should be id/name) and set the value to 'registryIds' 'providerIds' protocolIds'\n                         * The following process should make sure each id refers to the corresponding instance, here's how to find the instance for different use cases:\n                         * 1. Spring, check existing bean by id, see{@link ServiceBean#afterPropertiesSet()}; then try to use id to find configs defined in remote Config Center\n                         * 2. API, directly use id to find configs defined in remote Config Center; if all config instances are defined locally, please use {@link org.apache.dubbo.config.ServiceConfig#setRegistries(List)}\n                         */\n                        beanDefinition.getPropertyValues().addPropertyValue(beanProperty + \"Ids\", value);\n                    } else {\n                        Object reference;\n                        if (isPrimitive(type)) {\n                            value = getCompatibleDefaultValue(property, value);\n                            reference = value;\n                        } else if (ONRETURN.equals(property) || ONTHROW.equals(property) || ONINVOKE.equals(property)) {\n                            int index = value.lastIndexOf(\".\");\n                            String ref = value.substring(0, index);\n                            String method = value.substring(index + 1);\n                            reference = new RuntimeBeanReference(ref);\n                            beanDefinition.getPropertyValues().addPropertyValue(property + METHOD, method);\n                        } else if (EXECUTOR.equals(property)) {\n                            reference = new RuntimeBeanReference(value);\n                        } else {\n                            if (\"ref\".equals(property)\n                                    && parserContext.getRegistry().containsBeanDefinition(value)) {\n                                BeanDefinition refBean =\n                                        parserContext.getRegistry().getBeanDefinition(value);\n                                if (!refBean.isSingleton()) {\n                                    throw new IllegalStateException(\n                                            \"The exported service ref \" + value + \" must be singleton! Please set the \"\n                                                    + value + \" bean scope to singleton, eg: <bean id=\\\"\" + value\n                                                    + \"\\\" scope=\\\"singleton\\\" ...>\");\n                                }\n                            }\n                            reference = new RuntimeBeanReference(value);\n                        }\n                        if (reference != null) {\n                            beanDefinition.getPropertyValues().addPropertyValue(beanProperty, reference);\n                        }\n                    }\n                }\n            }\n        }\n\n        NamedNodeMap attributes = element.getAttributes();\n        int len = attributes.getLength();\n        for (int i = 0; i < len; i++) {\n            Node node = attributes.item(i);\n            String name = node.getLocalName();\n            if (!processedProps.contains(name)) {\n                if (parameters == null) {\n                    parameters = new ManagedMap();\n                }\n                String value = node.getNodeValue();\n                parameters.put(name, new TypedStringValue(value, String.class));\n            }\n        }\n        if (parameters != null) {\n            beanDefinition.getPropertyValues().addPropertyValue(\"parameters\", parameters);\n        }\n\n        // post-process after parse attributes\n        if (ProviderConfig.class.equals(beanClass)) {\n            parseNested(\n                    element, parserContext, ServiceBean.class, true, \"service\", \"provider\", beanName, beanDefinition);\n        } else if (ConsumerConfig.class.equals(beanClass)) {\n            parseNested(\n                    element,\n                    parserContext,\n                    ReferenceBean.class,\n                    true,\n                    \"reference\",\n                    \"consumer\",\n                    beanName,\n                    beanDefinition);\n        } else if (ReferenceBean.class.equals(beanClass)) {\n            configReferenceBean(element, parserContext, beanDefinition, null);\n        } else if (MetricsConfig.class.equals(beanClass)) {\n            parseMetrics(element, parserContext, beanDefinition);\n        }\n\n        // register bean definition\n        if (parserContext.getRegistry().containsBeanDefinition(beanName)) {\n            throw new IllegalStateException(\"Duplicate spring bean name: \" + beanName);\n        }\n\n        if (registered) {\n            parserContext.getRegistry().registerBeanDefinition(beanName, beanDefinition);\n        }\n        return beanDefinition;\n    }\n\n    private static void parseMetrics(Element element, ParserContext parserContext, RootBeanDefinition beanDefinition) {\n        NodeList childNodes = element.getChildNodes();\n        PrometheusConfig prometheus = null;\n        for (int i = 0; i < childNodes.getLength(); i++) {\n            if (!(childNodes.item(i) instanceof Element)) {\n                continue;\n            }\n\n            Element child = (Element) childNodes.item(i);\n            if (\"aggregation\".equals(child.getNodeName()) || \"aggregation\".equals(child.getLocalName())) {\n                AggregationConfig aggregation = new AggregationConfig();\n                assignProperties(aggregation, child, parserContext);\n                beanDefinition.getPropertyValues().addPropertyValue(\"aggregation\", aggregation);\n            } else if (\"histogram\".equals(child.getNodeName()) || \"histogram\".equals(child.getLocalName())) {\n                HistogramConfig histogram = new HistogramConfig();\n                assignProperties(histogram, child, parserContext);\n                beanDefinition.getPropertyValues().addPropertyValue(\"histogram\", histogram);\n            } else if (\"prometheus-exporter\".equals(child.getNodeName())\n                    || \"prometheus-exporter\".equals(child.getLocalName())) {\n                if (prometheus == null) {\n                    prometheus = new PrometheusConfig();\n                }\n\n                PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();\n                assignProperties(exporter, child, parserContext);\n                prometheus.setExporter(exporter);\n            } else if (\"prometheus-pushgateway\".equals(child.getNodeName())\n                    || \"prometheus-pushgateway\".equals(child.getLocalName())) {\n                if (prometheus == null) {\n                    prometheus = new PrometheusConfig();\n                }\n\n                PrometheusConfig.Pushgateway pushgateway = new PrometheusConfig.Pushgateway();\n                assignProperties(pushgateway, child, parserContext);\n                prometheus.setPushgateway(pushgateway);\n            }\n        }\n\n        if (prometheus != null) {\n            beanDefinition.getPropertyValues().addPropertyValue(\"prometheus\", prometheus);\n        }\n    }\n\n    private static void assignProperties(Object obj, Element ele, ParserContext parserContext) {\n        Method[] methods = obj.getClass().getMethods();\n        for (Method method : methods) {\n            if (MethodUtils.isSetter(method)) {\n                String beanProperty = method.getName().substring(3, 4).toLowerCase()\n                        + method.getName().substring(4);\n                String property = StringUtils.camelToSplitName(beanProperty, \"-\");\n                String value = resolveAttribute(ele, property, parserContext);\n                if (StringUtils.isNotEmpty(value)) {\n                    try {\n                        Object v = ClassUtils.convertPrimitive(method.getParameterTypes()[0], value);\n                        method.invoke(obj, v);\n                    } catch (IllegalAccessException | InvocationTargetException e) {\n                        throw new IllegalStateException(e);\n                    }\n                }\n            }\n        }\n    }\n\n    private static void configReferenceBean(\n            Element element,\n            ParserContext parserContext,\n            RootBeanDefinition beanDefinition,\n            BeanDefinition consumerDefinition) {\n        // process interface class\n        String interfaceName = resolveAttribute(element, ReferenceAttributes.INTERFACE, parserContext);\n        String generic = resolveAttribute(element, ReferenceAttributes.GENERIC, parserContext);\n        if (StringUtils.isBlank(generic) && consumerDefinition != null) {\n            // get generic from consumerConfig\n            generic = getPropertyValue(consumerDefinition.getPropertyValues(), ReferenceAttributes.GENERIC);\n        }\n        if (generic != null) {\n            generic = resolvePlaceholders(generic, parserContext);\n            beanDefinition.getPropertyValues().add(ReferenceAttributes.GENERIC, generic);\n        }\n        beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);\n\n        Class interfaceClass = ReferenceConfig.determineInterfaceClass(generic, interfaceName);\n        beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);\n\n        // TODO Only register one reference bean for same (group, interface, version)\n\n        // create decorated definition for reference bean, Avoid being instantiated when getting the beanType of\n        // ReferenceBean\n        // see org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean()\n        GenericBeanDefinition targetDefinition = new GenericBeanDefinition();\n        targetDefinition.setBeanClass(interfaceClass);\n        String beanName = (String) beanDefinition.getAttribute(BEAN_NAME);\n        beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, beanName + \"_decorated\"));\n\n        // signal object type since Spring 5.2\n        beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);\n\n        // mark property value as optional\n        List<PropertyValue> propertyValues = beanDefinition.getPropertyValues().getPropertyValueList();\n        for (PropertyValue propertyValue : propertyValues) {\n            propertyValue.setOptional(true);\n        }\n    }\n\n    private static void getPropertyMap(Class<?> beanClass, Map<String, Class> beanPropsMap) {\n        for (Method setter : beanClass.getMethods()) {\n            String name = setter.getName();\n            if (name.length() > 3\n                    && name.startsWith(\"set\")\n                    && Modifier.isPublic(setter.getModifiers())\n                    && setter.getParameterTypes().length == 1) {\n                Class<?> type = setter.getParameterTypes()[0];\n                String beanProperty = name.substring(3, 4).toLowerCase() + name.substring(4);\n                // check the setter/getter whether match\n                Method getter = null;\n                try {\n                    getter = beanClass.getMethod(\"get\" + name.substring(3), new Class<?>[0]);\n                } catch (NoSuchMethodException e) {\n                    try {\n                        getter = beanClass.getMethod(\"is\" + name.substring(3), new Class<?>[0]);\n                    } catch (NoSuchMethodException e2) {\n                        // ignore, there is no need any log here since some class implement the interface:\n                        // EnvironmentAware,\n                        // ApplicationAware, etc. They only have setter method, otherwise will cause the error log\n                        // during application start up.\n                    }\n                }\n                if (getter == null\n                        || !Modifier.isPublic(getter.getModifiers())\n                        || !type.equals(getter.getReturnType())) {\n                    continue;\n                }\n                beanPropsMap.put(beanProperty, type);\n            }\n        }\n    }\n\n    private static String getCompatibleDefaultValue(String property, String value) {\n        if (\"async\".equals(property) && \"false\".equals(value)\n                || \"timeout\".equals(property) && \"0\".equals(value)\n                || \"delay\".equals(property) && \"0\".equals(value)\n                || \"version\".equals(property) && \"0.0.0\".equals(value)\n                || \"stat\".equals(property) && \"-1\".equals(value)\n                || \"reliable\".equals(property) && \"false\".equals(value)) {\n            // backward compatibility for the default value in old version's xsd\n            value = null;\n        }\n        return value;\n    }\n\n    private static boolean isPrimitive(Class<?> cls) {\n        return cls.isPrimitive()\n                || cls == Boolean.class\n                || cls == Byte.class\n                || cls == Character.class\n                || cls == Short.class\n                || cls == Integer.class\n                || cls == Long.class\n                || cls == Float.class\n                || cls == Double.class\n                || cls == String.class\n                || cls == Date.class\n                || cls == Class.class;\n    }\n\n    private static void parseNested(\n            Element element,\n            ParserContext parserContext,\n            Class<?> beanClass,\n            boolean registered,\n            String tag,\n            String property,\n            String ref,\n            BeanDefinition beanDefinition) {\n        NodeList nodeList = element.getChildNodes();\n        if (nodeList == null) {\n            return;\n        }\n        boolean first = true;\n        for (int i = 0; i < nodeList.getLength(); i++) {\n            Node node = nodeList.item(i);\n            if (!(node instanceof Element)) {\n                continue;\n            }\n            if (tag.equals(node.getNodeName()) || tag.equals(node.getLocalName())) {\n                if (first) {\n                    first = false;\n                    String isDefault = resolveAttribute(element, \"default\", parserContext);\n                    if (StringUtils.isEmpty(isDefault)) {\n                        beanDefinition.getPropertyValues().addPropertyValue(\"default\", \"false\");\n                    }\n                }\n                RootBeanDefinition subDefinition = parse((Element) node, parserContext, beanClass, registered);\n                if (subDefinition != null) {\n                    if (StringUtils.isNotEmpty(ref)) {\n                        subDefinition.getPropertyValues().addPropertyValue(property, new RuntimeBeanReference(ref));\n                    }\n                    if (ReferenceBean.class.equals(beanClass)) {\n                        configReferenceBean((Element) node, parserContext, subDefinition, beanDefinition);\n                    }\n                }\n            }\n        }\n    }\n\n    private static void parseProperties(\n            NodeList nodeList, RootBeanDefinition beanDefinition, ParserContext parserContext) {\n        if (nodeList == null) {\n            return;\n        }\n        for (int i = 0; i < nodeList.getLength(); i++) {\n            if (!(nodeList.item(i) instanceof Element)) {\n                continue;\n            }\n            Element element = (Element) nodeList.item(i);\n            if (\"property\".equals(element.getNodeName()) || \"property\".equals(element.getLocalName())) {\n                String name = resolveAttribute(element, \"name\", parserContext);\n                if (StringUtils.isNotEmpty(name)) {\n                    String value = resolveAttribute(element, \"value\", parserContext);\n                    String ref = resolveAttribute(element, \"ref\", parserContext);\n                    if (StringUtils.isNotEmpty(value)) {\n                        beanDefinition.getPropertyValues().addPropertyValue(name, value);\n                    } else if (StringUtils.isNotEmpty(ref)) {\n                        beanDefinition.getPropertyValues().addPropertyValue(name, new RuntimeBeanReference(ref));\n                    } else {\n                        throw new UnsupportedOperationException(\"Unsupported <property name=\\\"\" + name\n                                + \"\\\"> sub tag, Only supported <property name=\\\"\" + name\n                                + \"\\\" ref=\\\"...\\\" /> or <property name=\\\"\" + name + \"\\\" value=\\\"...\\\" />\");\n                    }\n                }\n            }\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static ManagedMap parseParameters(\n            NodeList nodeList, RootBeanDefinition beanDefinition, ParserContext parserContext) {\n        if (nodeList == null) {\n            return null;\n        }\n        ManagedMap parameters = null;\n        for (int i = 0; i < nodeList.getLength(); i++) {\n            if (!(nodeList.item(i) instanceof Element)) {\n                continue;\n            }\n            Element element = (Element) nodeList.item(i);\n            if (\"parameter\".equals(element.getNodeName()) || \"parameter\".equals(element.getLocalName())) {\n                if (parameters == null) {\n                    parameters = new ManagedMap();\n                }\n                String key = resolveAttribute(element, \"key\", parserContext);\n                String value = resolveAttribute(element, \"value\", parserContext);\n                boolean hide = \"true\".equals(resolveAttribute(element, \"hide\", parserContext));\n                if (hide) {\n                    key = HIDE_KEY_PREFIX + key;\n                }\n                parameters.put(key, new TypedStringValue(value, String.class));\n            }\n        }\n        return parameters;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static void parseMethods(\n            String id, NodeList nodeList, RootBeanDefinition beanDefinition, ParserContext parserContext) {\n        if (nodeList == null) {\n            return;\n        }\n        ManagedList methods = null;\n        for (int i = 0; i < nodeList.getLength(); i++) {\n            if (!(nodeList.item(i) instanceof Element)) {\n                continue;\n            }\n            Element element = (Element) nodeList.item(i);\n            if (\"method\".equals(element.getNodeName()) || \"method\".equals(element.getLocalName())) {\n                String methodName = resolveAttribute(element, \"name\", parserContext);\n                if (StringUtils.isEmpty(methodName)) {\n                    throw new IllegalStateException(\"<dubbo:method> name attribute == null\");\n                }\n                if (methods == null) {\n                    methods = new ManagedList();\n                }\n                RootBeanDefinition methodBeanDefinition = parse(element, parserContext, MethodConfig.class, false);\n                String beanName = id + \".\" + methodName;\n\n                // If the PropertyValue named \"id\" can't be found,\n                // bean name will be taken as the \"id\" PropertyValue for MethodConfig\n                if (!hasPropertyValue(methodBeanDefinition, \"id\")) {\n                    addPropertyValue(methodBeanDefinition, \"id\", beanName);\n                }\n\n                BeanDefinitionHolder methodBeanDefinitionHolder =\n                        new BeanDefinitionHolder(methodBeanDefinition, beanName);\n                methods.add(methodBeanDefinitionHolder);\n            }\n        }\n        if (methods != null) {\n            beanDefinition.getPropertyValues().addPropertyValue(\"methods\", methods);\n        }\n    }\n\n    private static boolean hasPropertyValue(AbstractBeanDefinition beanDefinition, String propertyName) {\n        return beanDefinition.getPropertyValues().contains(propertyName);\n    }\n\n    private static void addPropertyValue(\n            AbstractBeanDefinition beanDefinition, String propertyName, String propertyValue) {\n        if (StringUtils.isBlank(propertyName) || StringUtils.isBlank(propertyValue)) {\n            return;\n        }\n        beanDefinition.getPropertyValues().addPropertyValue(propertyName, propertyValue);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static void parseArguments(\n            String id, NodeList nodeList, RootBeanDefinition beanDefinition, ParserContext parserContext) {\n        if (nodeList == null) {\n            return;\n        }\n        ManagedList arguments = null;\n        for (int i = 0; i < nodeList.getLength(); i++) {\n            if (!(nodeList.item(i) instanceof Element)) {\n                continue;\n            }\n            Element element = (Element) nodeList.item(i);\n            if (\"argument\".equals(element.getNodeName()) || \"argument\".equals(element.getLocalName())) {\n                String argumentIndex = resolveAttribute(element, \"index\", parserContext);\n                if (arguments == null) {\n                    arguments = new ManagedList();\n                }\n                BeanDefinition argumentBeanDefinition = parse(element, parserContext, ArgumentConfig.class, false);\n                String name = id + \".\" + argumentIndex;\n                BeanDefinitionHolder argumentBeanDefinitionHolder =\n                        new BeanDefinitionHolder(argumentBeanDefinition, name);\n                arguments.add(argumentBeanDefinitionHolder);\n            }\n        }\n        if (arguments != null) {\n            beanDefinition.getPropertyValues().addPropertyValue(\"arguments\", arguments);\n        }\n    }\n\n    @Override\n    public BeanDefinition parse(Element element, ParserContext parserContext) {\n        return parse(element, parserContext, beanClass, true);\n    }\n\n    private static String resolveAttribute(Element element, String attributeName, ParserContext parserContext) {\n        String attributeValue = element.getAttribute(attributeName);\n        // Early resolve place holder may be wrong ( Before\n        // PropertySourcesPlaceholderConfigurer/PropertyPlaceholderConfigurer )\n        // https://github.com/apache/dubbo/pull/6079\n        // https://github.com/apache/dubbo/issues/6035\n        //        Environment environment = parserContext.getReaderContext().getEnvironment();\n        //        return environment.resolvePlaceholders(attributeValue);\n        return attributeValue;\n    }\n\n    private static String resolvePlaceholders(String str, ParserContext parserContext) {\n        if (resolvePlaceholdersEnabled) {\n            try {\n                return parserContext.getReaderContext().getEnvironment().resolveRequiredPlaceholders(str);\n            } catch (NoSuchMethodError e) {\n                resolvePlaceholdersEnabled = false;\n            }\n        }\n        return str;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.schema;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.spring.ConfigCenterBean;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.ServiceBean;\nimport org.apache.dubbo.config.spring.aot.AotWithSpringDetector;\nimport org.apache.dubbo.config.spring.beans.factory.config.ConfigurableSourceBeanMetadataElement;\nimport org.apache.dubbo.config.spring.context.DubboSpringInitializer;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.xml.NamespaceHandlerSupport;\nimport org.springframework.beans.factory.xml.ParserContext;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.w3c.dom.Element;\n\n/**\n * DubboNamespaceHandler\n *\n * @export\n */\npublic class DubboNamespaceHandler extends NamespaceHandlerSupport implements ConfigurableSourceBeanMetadataElement {\n    @Override\n    public void init() {\n        registerBeanDefinitionParser(\"application\", new DubboBeanDefinitionParser(ApplicationConfig.class));\n        registerBeanDefinitionParser(\"module\", new DubboBeanDefinitionParser(ModuleConfig.class));\n        registerBeanDefinitionParser(\"registry\", new DubboBeanDefinitionParser(RegistryConfig.class));\n        registerBeanDefinitionParser(\"config-center\", new DubboBeanDefinitionParser(ConfigCenterBean.class));\n        registerBeanDefinitionParser(\"metadata-report\", new DubboBeanDefinitionParser(MetadataReportConfig.class));\n        registerBeanDefinitionParser(\"monitor\", new DubboBeanDefinitionParser(MonitorConfig.class));\n        registerBeanDefinitionParser(\"metrics\", new DubboBeanDefinitionParser(MetricsConfig.class));\n        registerBeanDefinitionParser(\"tracing\", new DubboBeanDefinitionParser(TracingConfig.class));\n        registerBeanDefinitionParser(\"ssl\", new DubboBeanDefinitionParser(SslConfig.class));\n        registerBeanDefinitionParser(\"provider\", new DubboBeanDefinitionParser(ProviderConfig.class));\n        registerBeanDefinitionParser(\"consumer\", new DubboBeanDefinitionParser(ConsumerConfig.class));\n        registerBeanDefinitionParser(\"protocol\", new DubboBeanDefinitionParser(ProtocolConfig.class));\n        registerBeanDefinitionParser(\"service\", new DubboBeanDefinitionParser(ServiceBean.class));\n        registerBeanDefinitionParser(\"reference\", new DubboBeanDefinitionParser(ReferenceBean.class));\n        registerBeanDefinitionParser(\"annotation\", new AnnotationBeanDefinitionParser());\n    }\n\n    /**\n     * Override {@link NamespaceHandlerSupport#parse(Element, ParserContext)} method\n     *\n     * @param element       {@link Element}\n     * @param parserContext {@link ParserContext}\n     * @return\n     * @since 2.7.5\n     */\n    @Override\n    public BeanDefinition parse(Element element, ParserContext parserContext) {\n        BeanDefinitionRegistry registry = parserContext.getRegistry();\n        registerAnnotationConfigProcessors(registry);\n\n        // initialize dubbo beans\n        DubboSpringInitializer.initialize(parserContext.getRegistry());\n\n        BeanDefinition beanDefinition = super.parse(element, parserContext);\n        setSource(beanDefinition);\n        return beanDefinition;\n    }\n\n    /**\n     * Register the processors for the Spring Annotation-Driven features\n     *\n     * @param registry {@link BeanDefinitionRegistry}\n     * @see AnnotationConfigUtils\n     * @since 2.7.5\n     */\n    private void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {\n        if (!AotWithSpringDetector.useGeneratedArtifacts()) {\n            AnnotationConfigUtils.registerAnnotationConfigProcessors(registry);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/DataSourceStatusChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.status;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.status.Status;\nimport org.apache.dubbo.common.status.StatusChecker;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.config.spring.extension.SpringExtensionInjector;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport javax.sql.DataSource;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.ResultSet;\nimport java.util.Map;\n\nimport org.springframework.context.ApplicationContext;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_WARN_STATUS_CHECKER;\n\n@Activate\npublic class DataSourceStatusChecker implements StatusChecker {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DataSourceStatusChecker.class);\n\n    private ApplicationModel applicationModel;\n\n    private ApplicationContext applicationContext;\n\n    public DataSourceStatusChecker(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    public DataSourceStatusChecker(ApplicationContext context) {\n        this.applicationContext = context;\n    }\n\n    @Override\n    public Status check() {\n        if (applicationContext == null) {\n            SpringExtensionInjector springExtensionInjector = SpringExtensionInjector.get(applicationModel);\n            applicationContext = springExtensionInjector.getContext();\n        }\n\n        if (applicationContext == null) {\n            return new Status(Status.Level.UNKNOWN);\n        }\n\n        Map<String, DataSource> dataSources = applicationContext.getBeansOfType(DataSource.class, false, false);\n        if (CollectionUtils.isEmptyMap(dataSources)) {\n            return new Status(Status.Level.UNKNOWN);\n        }\n        Status.Level level = Status.Level.OK;\n        StringBuilder buf = new StringBuilder();\n        for (Map.Entry<String, DataSource> entry : dataSources.entrySet()) {\n            DataSource dataSource = entry.getValue();\n            if (buf.length() > 0) {\n                buf.append(\", \");\n            }\n            buf.append(entry.getKey());\n\n            try (Connection connection = dataSource.getConnection()) {\n                DatabaseMetaData metaData = connection.getMetaData();\n                try (ResultSet resultSet = metaData.getTypeInfo()) {\n                    if (!resultSet.next()) {\n                        level = Status.Level.ERROR;\n                    }\n                }\n                buf.append(metaData.getURL());\n                buf.append('(');\n                buf.append(metaData.getDatabaseProductName());\n                buf.append('-');\n                buf.append(metaData.getDatabaseProductVersion());\n                buf.append(')');\n            } catch (Throwable e) {\n                logger.warn(CONFIG_WARN_STATUS_CHECKER, \"\", \"\", e.getMessage(), e);\n                return new Status(level, e.getMessage());\n            }\n        }\n        return new Status(level, buf.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/SpringStatusChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.status;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.status.Status;\nimport org.apache.dubbo.common.status.StatusChecker;\nimport org.apache.dubbo.config.spring.extension.SpringExtensionInjector;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Method;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.Lifecycle;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_WARN_STATUS_CHECKER;\n\n@Activate\npublic class SpringStatusChecker implements StatusChecker {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SpringStatusChecker.class);\n\n    private ApplicationModel applicationModel;\n\n    private ApplicationContext applicationContext;\n\n    public SpringStatusChecker(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    public SpringStatusChecker(ApplicationContext applicationContext) {\n        this.applicationContext = applicationContext;\n    }\n\n    @Override\n    public Status check() {\n\n        if (applicationContext == null && applicationModel != null) {\n            SpringExtensionInjector springExtensionInjector = SpringExtensionInjector.get(applicationModel);\n            applicationContext = springExtensionInjector.getContext();\n        }\n\n        if (applicationContext == null) {\n            return new Status(Status.Level.UNKNOWN);\n        }\n\n        Status.Level level;\n        if (applicationContext instanceof Lifecycle) {\n            if (((Lifecycle) applicationContext).isRunning()) {\n                level = Status.Level.OK;\n            } else {\n                level = Status.Level.ERROR;\n            }\n        } else {\n            level = Status.Level.UNKNOWN;\n        }\n        StringBuilder buf = new StringBuilder();\n        try {\n            Class<?> cls = applicationContext.getClass();\n            Method method = null;\n            while (cls != null && method == null) {\n                try {\n                    method = cls.getDeclaredMethod(\"getConfigLocations\", new Class<?>[0]);\n                } catch (NoSuchMethodException t) {\n                    cls = cls.getSuperclass();\n                }\n            }\n            if (method != null) {\n                if (!method.isAccessible()) {\n                    method.setAccessible(true);\n                }\n                String[] configs = (String[]) method.invoke(applicationContext, new Object[0]);\n                if (configs != null && configs.length > 0) {\n                    for (String config : configs) {\n                        if (buf.length() > 0) {\n                            buf.append(',');\n                        }\n                        buf.append(config);\n                    }\n                }\n            }\n        } catch (Throwable t) {\n            if (t.getCause() instanceof UnsupportedOperationException) {\n                logger.debug(t.getMessage(), t);\n            } else {\n                logger.warn(CONFIG_WARN_STATUS_CHECKER, \"\", \"\", t.getMessage(), t);\n            }\n        }\n        return new Status(level, buf.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinitionHolder;\nimport org.springframework.beans.factory.config.SingletonBeanRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.context.annotation.AnnotatedBeanDefinitionReader;\nimport org.springframework.context.annotation.AnnotationBeanNameGenerator;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.springframework.context.annotation.ClassPathBeanDefinitionScanner;\nimport org.springframework.context.annotation.ConfigurationClassPostProcessor;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.ObjectUtils;\n\nimport static java.lang.String.format;\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.utils.ReflectUtils.EMPTY_CLASS_ARRAY;\nimport static org.springframework.context.annotation.AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR;\nimport static org.springframework.util.ClassUtils.resolveClassName;\nimport static org.springframework.util.ObjectUtils.nullSafeEquals;\n\n/**\n * Annotated {@link BeanDefinition} Utilities\n *\n * @see BeanDefinition\n */\npublic abstract class AnnotatedBeanDefinitionRegistryUtils {\n\n    private static final Log logger = LogFactory.getLog(AnnotatedBeanDefinitionRegistryUtils.class);\n\n    /**\n     * Is present bean that was registered by the specified {@link Annotation annotated} {@link Class class}\n     *\n     * @param registry       {@link BeanDefinitionRegistry}\n     * @param annotatedClass the {@link Annotation annotated} {@link Class class}\n     * @return if present, return <code>true</code>, or <code>false</code>\n     * @since 1.0.3\n     */\n    public static boolean isPresentBean(BeanDefinitionRegistry registry, Class<?> annotatedClass) {\n\n        boolean present = false;\n\n        String[] beanNames = registry.getBeanDefinitionNames();\n\n        ClassLoader classLoader = annotatedClass.getClassLoader();\n\n        for (String beanName : beanNames) {\n            BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);\n            if (beanDefinition instanceof AnnotatedBeanDefinition) {\n                AnnotationMetadata annotationMetadata = ((AnnotatedBeanDefinition) beanDefinition).getMetadata();\n                String className = annotationMetadata.getClassName();\n                Class<?> targetClass = resolveClassName(className, classLoader);\n                present = nullSafeEquals(targetClass, annotatedClass);\n                if (present) {\n                    if (logger.isDebugEnabled()) {\n                        logger.debug(format(\n                                \"The annotatedClass[class : %s , bean name : %s] was present in registry[%s]\",\n                                className, beanName, registry));\n                    }\n                    break;\n                }\n            }\n        }\n\n        return present;\n    }\n\n    /**\n     * Register Beans if not present in {@link BeanDefinitionRegistry registry}\n     *\n     * @param registry         {@link BeanDefinitionRegistry}\n     * @param annotatedClasses {@link Annotation annotation} class\n     */\n    public static void registerBeans(BeanDefinitionRegistry registry, Class<?>... annotatedClasses) {\n\n        if (ObjectUtils.isEmpty(annotatedClasses)) {\n            return;\n        }\n\n        Set<Class<?>> classesToRegister = new LinkedHashSet<Class<?>>(asList(annotatedClasses));\n\n        // Remove all annotated-classes that have been registered\n        Iterator<Class<?>> iterator = classesToRegister.iterator();\n\n        while (iterator.hasNext()) {\n            Class<?> annotatedClass = iterator.next();\n            if (isPresentBean(registry, annotatedClass)) {\n                iterator.remove();\n            }\n        }\n\n        AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(registry.getClass().getSimpleName() + \" will register annotated classes : \"\n                    + asList(annotatedClasses) + \" .\");\n        }\n\n        reader.register(classesToRegister.toArray(EMPTY_CLASS_ARRAY));\n    }\n\n    /**\n     * Scan base packages for register {@link Component @Component}s\n     *\n     * @param registry     {@link BeanDefinitionRegistry}\n     * @param basePackages base packages\n     * @return the count of registered components.\n     */\n    public static int scanBasePackages(BeanDefinitionRegistry registry, String... basePackages) {\n\n        int count = 0;\n\n        if (!ObjectUtils.isEmpty(basePackages)) {\n\n            boolean debugEnabled = logger.isDebugEnabled();\n\n            if (debugEnabled) {\n                logger.debug(registry.getClass().getSimpleName() + \" will scan base packages \"\n                        + Arrays.asList(basePackages) + \".\");\n            }\n\n            List<String> registeredBeanNames = Arrays.asList(registry.getBeanDefinitionNames());\n\n            ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner =\n                    new ClassPathBeanDefinitionScanner(registry);\n            count = classPathBeanDefinitionScanner.scan(basePackages);\n\n            List<String> scannedBeanNames = new ArrayList<String>(count);\n            scannedBeanNames.addAll(Arrays.asList(registry.getBeanDefinitionNames()));\n            scannedBeanNames.removeAll(registeredBeanNames);\n\n            if (debugEnabled) {\n                logger.debug(\"The Scanned Components[ count : \" + count + \"] under base packages \"\n                        + Arrays.asList(basePackages) + \" : \");\n            }\n\n            for (String scannedBeanName : scannedBeanNames) {\n                BeanDefinition scannedBeanDefinition = registry.getBeanDefinition(scannedBeanName);\n                if (debugEnabled) {\n                    logger.debug(\"Component [ name : \" + scannedBeanName + \" , class : \"\n                            + scannedBeanDefinition.getBeanClassName() + \" ]\");\n                }\n            }\n        }\n\n        return count;\n    }\n\n    /**\n     * It'd better to use BeanNameGenerator instance that should reference\n     * {@link ConfigurationClassPostProcessor},\n     * thus it maybe a potential problem on bean name generation.\n     *\n     * @param registry {@link BeanDefinitionRegistry}\n     * @return try to find the {@link BeanNameGenerator} bean named {@link AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR},\n     * if it can't be found, return an instance of {@link AnnotationBeanNameGenerator}\n     * @see SingletonBeanRegistry\n     * @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR\n     * @see ConfigurationClassPostProcessor#processConfigBeanDefinitions\n     * @since 1.0.6\n     */\n    public static BeanNameGenerator resolveAnnotatedBeanNameGenerator(BeanDefinitionRegistry registry) {\n        BeanNameGenerator beanNameGenerator = null;\n\n        if (registry instanceof SingletonBeanRegistry) {\n            SingletonBeanRegistry singletonBeanRegistry = SingletonBeanRegistry.class.cast(registry);\n            beanNameGenerator =\n                    (BeanNameGenerator) singletonBeanRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);\n        }\n\n        if (beanNameGenerator == null) {\n\n            if (logger.isInfoEnabled()) {\n\n                logger.info(\"BeanNameGenerator bean can't be found in BeanFactory with name [\"\n                        + CONFIGURATION_BEAN_NAME_GENERATOR + \"]\");\n                logger.info(\"BeanNameGenerator will be a instance of \" + AnnotationBeanNameGenerator.class.getName()\n                        + \" , it maybe a potential problem on bean name generation.\");\n            }\n\n            beanNameGenerator = new AnnotationBeanNameGenerator();\n        }\n\n        return beanNameGenerator;\n    }\n\n    /**\n     * Finds a {@link Set} of {@link BeanDefinitionHolder BeanDefinitionHolders}\n     *\n     * @param scanner           {@link ClassPathBeanDefinitionScanner}\n     * @param packageToScan     package to scan\n     * @param registry          {@link BeanDefinitionRegistry}\n     * @param beanNameGenerator {@link BeanNameGenerator}\n     * @return non-null\n     */\n    public static Set<BeanDefinitionHolder> findBeanDefinitionHolders(\n            ClassPathBeanDefinitionScanner scanner,\n            String packageToScan,\n            BeanDefinitionRegistry registry,\n            BeanNameGenerator beanNameGenerator) {\n\n        Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(packageToScan);\n\n        Set<BeanDefinitionHolder> beanDefinitionHolders =\n                new LinkedHashSet<BeanDefinitionHolder>(beanDefinitions.size());\n\n        for (BeanDefinition beanDefinition : beanDefinitions) {\n\n            String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);\n            BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);\n            beanDefinitionHolders.add(beanDefinitionHolder);\n        }\n\n        return beanDefinitionHolders;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotationUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.lang.reflect.AnnotatedElement;\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.util.ClassUtils;\n\nimport static java.lang.String.valueOf;\nimport static java.util.Arrays.asList;\nimport static org.springframework.core.annotation.AnnotationAttributes.fromMap;\nimport static org.springframework.core.annotation.AnnotationUtils.findAnnotation;\nimport static org.springframework.core.annotation.AnnotationUtils.getDefaultValue;\nimport static org.springframework.util.ClassUtils.resolveClassName;\nimport static org.springframework.util.CollectionUtils.arrayToList;\nimport static org.springframework.util.CollectionUtils.isEmpty;\nimport static org.springframework.util.ObjectUtils.nullSafeEquals;\nimport static org.springframework.util.ReflectionUtils.findMethod;\nimport static org.springframework.util.ReflectionUtils.invokeMethod;\nimport static org.springframework.util.StringUtils.trimWhitespace;\n\n/**\n * {@link Annotation} Utilities\n * @see Annotation\n */\n@SuppressWarnings(\"unchecked\")\npublic abstract class AnnotationUtils {\n\n    /**\n     * The class name of AnnotatedElementUtils that is introduced since Spring Framework 4\n     */\n    public static final String ANNOTATED_ELEMENT_UTILS_CLASS_NAME =\n            \"org.springframework.core.annotation.AnnotatedElementUtils\";\n\n    /**\n     * Is specified {@link Annotation} present on {@link Method}'s declaring class or parameters or itself.\n     *\n     * @param method          {@link Method}\n     * @param annotationClass {@link Annotation} type\n     * @param <A>             {@link Annotation} type\n     * @return If present , return <code>true</code> , or <code>false</code>\n     */\n    public static <A extends Annotation> boolean isPresent(Method method, Class<A> annotationClass) {\n\n        Map<ElementType, List<A>> annotationsMap = findAnnotations(method, annotationClass);\n\n        return !annotationsMap.isEmpty();\n    }\n\n    /**\n     * Find specified {@link Annotation} type maps from {@link Method}\n     *\n     * @param method          {@link Method}\n     * @param annotationClass {@link Annotation} type\n     * @param <A>             {@link Annotation} type\n     * @return {@link Annotation} type maps , the {@link ElementType} as key ,\n     * the list of {@link Annotation} as value.\n     * If {@link Annotation} was annotated on {@link Method}'s parameters{@link ElementType#PARAMETER} ,\n     * the associated {@link Annotation} list may contain multiple elements.\n     */\n    public static <A extends Annotation> Map<ElementType, List<A>> findAnnotations(\n            Method method, Class<A> annotationClass) {\n\n        Retention retention = annotationClass.getAnnotation(Retention.class);\n\n        RetentionPolicy retentionPolicy = retention.value();\n\n        if (!RetentionPolicy.RUNTIME.equals(retentionPolicy)) {\n            return Collections.emptyMap();\n        }\n\n        Map<ElementType, List<A>> annotationsMap = new LinkedHashMap<ElementType, List<A>>();\n\n        Target target = annotationClass.getAnnotation(Target.class);\n\n        ElementType[] elementTypes = target.value();\n\n        for (ElementType elementType : elementTypes) {\n\n            List<A> annotationsList = new LinkedList<A>();\n\n            switch (elementType) {\n                case PARAMETER:\n                    Annotation[][] parameterAnnotations = method.getParameterAnnotations();\n\n                    for (Annotation[] annotations : parameterAnnotations) {\n\n                        for (Annotation annotation : annotations) {\n\n                            if (annotationClass.equals(annotation.annotationType())) {\n\n                                annotationsList.add((A) annotation);\n                            }\n                        }\n                    }\n\n                    break;\n\n                case METHOD:\n                    A annotation = findAnnotation(method, annotationClass);\n\n                    if (annotation != null) {\n\n                        annotationsList.add(annotation);\n                    }\n\n                    break;\n\n                case TYPE:\n                    Class<?> beanType = method.getDeclaringClass();\n\n                    A annotation2 = findAnnotation(beanType, annotationClass);\n\n                    if (annotation2 != null) {\n\n                        annotationsList.add(annotation2);\n                    }\n\n                    break;\n            }\n\n            if (!annotationsList.isEmpty()) {\n\n                annotationsMap.put(elementType, annotationsList);\n            }\n        }\n\n        return Collections.unmodifiableMap(annotationsMap);\n    }\n\n    /**\n     * Get the {@link Annotation} attributes\n     *\n     * @param annotation           specified {@link Annotation}\n     * @param ignoreDefaultValue   whether ignore default value or not\n     * @param ignoreAttributeNames the attribute names of annotation should be ignored\n     * @return non-null\n     * @since 1.0.2\n     */\n    public static Map<String, Object> getAttributes(\n            Annotation annotation, boolean ignoreDefaultValue, String... ignoreAttributeNames) {\n        return getAttributes(annotation, null, ignoreDefaultValue, ignoreAttributeNames);\n    }\n\n    /**\n     * Get the {@link Annotation} attributes\n     *\n     * @param annotation           specified {@link Annotation}\n     * @param propertyResolver     {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param ignoreDefaultValue   whether ignore default value or not\n     * @param ignoreAttributeNames the attribute names of annotation should be ignored\n     * @return non-null\n     * @since 1.0.2\n     */\n    public static Map<String, Object> getAttributes(\n            Annotation annotation,\n            PropertyResolver propertyResolver,\n            boolean ignoreDefaultValue,\n            String... ignoreAttributeNames) {\n        return getAttributes(annotation, propertyResolver, false, false, ignoreDefaultValue, ignoreAttributeNames);\n    }\n\n    /**\n     * Get the {@link Annotation} attributes\n     *\n     * @param annotationAttributes the attributes of specified {@link Annotation}\n     * @param propertyResolver     {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param ignoreAttributeNames the attribute names of annotation should be ignored\n     * @return non-null\n     * @since 1.0.4\n     */\n    public static Map<String, Object> getAttributes(\n            Map<String, Object> annotationAttributes,\n            PropertyResolver propertyResolver,\n            String... ignoreAttributeNames) {\n\n        Set<String> ignoreAttributeNamesSet =\n                new HashSet<String>((Collection<? extends String>) arrayToList(ignoreAttributeNames));\n\n        Map<String, Object> actualAttributes = new LinkedHashMap<String, Object>();\n\n        for (Map.Entry<String, Object> annotationAttribute : annotationAttributes.entrySet()) {\n\n            String attributeName = annotationAttribute.getKey();\n            Object attributeValue = annotationAttribute.getValue();\n\n            // ignore attribute name\n            if (ignoreAttributeNamesSet.contains(attributeName)) {\n                continue;\n            }\n\n            if (attributeValue instanceof String) {\n                attributeValue = resolvePlaceholders(valueOf(attributeValue), propertyResolver);\n            } else if (attributeValue instanceof String[]) {\n                String[] values = (String[]) attributeValue;\n                for (int i = 0; i < values.length; i++) {\n                    values[i] = resolvePlaceholders(values[i], propertyResolver);\n                }\n                attributeValue = values;\n            }\n            actualAttributes.put(attributeName, attributeValue);\n        }\n        return actualAttributes;\n    }\n\n    /**\n     * @param annotation             specified {@link Annotation}\n     * @param propertyResolver       {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param classValuesAsString    whether to turn Class references into Strings (for\n     *                               compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to\n     *                               preserve them as Class references\n     * @param nestedAnnotationsAsMap whether to turn nested Annotation instances into\n     *                               {@link AnnotationAttributes} maps (for compatibility with\n     *                               {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as\n     *                               Annotation instances\n     * @param ignoreDefaultValue     whether ignore default value or not\n     * @param ignoreAttributeNames   the attribute names of annotation should be ignored\n     * @return\n     * @since 1.0.11\n     */\n    public static Map<String, Object> getAttributes(\n            Annotation annotation,\n            PropertyResolver propertyResolver,\n            boolean classValuesAsString,\n            boolean nestedAnnotationsAsMap,\n            boolean ignoreDefaultValue,\n            String... ignoreAttributeNames) {\n\n        Map<String, Object> annotationAttributes =\n                org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes(\n                        annotation, classValuesAsString, nestedAnnotationsAsMap);\n\n        String[] actualIgnoreAttributeNames = ignoreAttributeNames;\n\n        if (ignoreDefaultValue && !isEmpty(annotationAttributes)) {\n\n            List<String> attributeNamesToIgnore = new LinkedList<String>(asList(ignoreAttributeNames));\n\n            for (Map.Entry<String, Object> annotationAttribute : annotationAttributes.entrySet()) {\n                String attributeName = annotationAttribute.getKey();\n                Object attributeValue = annotationAttribute.getValue();\n                if (nullSafeEquals(attributeValue, getDefaultValue(annotation, attributeName))) {\n                    attributeNamesToIgnore.add(attributeName);\n                }\n            }\n            // extends the ignored list\n            actualIgnoreAttributeNames = attributeNamesToIgnore.toArray(new String[attributeNamesToIgnore.size()]);\n        }\n\n        return getAttributes(annotationAttributes, propertyResolver, actualIgnoreAttributeNames);\n    }\n\n    private static String resolvePlaceholders(String attributeValue, PropertyResolver propertyResolver) {\n        String resolvedValue = attributeValue;\n        if (propertyResolver != null) {\n            resolvedValue = propertyResolver.resolvePlaceholders(resolvedValue);\n            resolvedValue = trimWhitespace(resolvedValue);\n        }\n        return resolvedValue;\n    }\n\n    /**\n     * Get the attribute value\n     *\n     * @param annotation    {@link Annotation annotation}\n     * @param attributeName the name of attribute\n     * @param <T>           the type of attribute value\n     * @return the attribute value if found\n     * @since 1.0.3\n     */\n    public static <T> T getAttribute(Annotation annotation, String attributeName) {\n        return getAttribute(\n                org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes(annotation), attributeName);\n    }\n\n    /**\n     * Get the attribute value\n     *\n     * @param attributes    {@link Map the annotation attributes} or {@link AnnotationAttributes}\n     * @param attributeName the name of attribute\n     * @param <T>           the type of attribute value\n     * @return the attribute value if found\n     * @since 1.0.3\n     */\n    public static <T> T getAttribute(Map<String, Object> attributes, String attributeName) {\n        return getAttribute(attributes, attributeName, false);\n    }\n\n    /**\n     * Get the attribute value the will\n     *\n     * @param attributes    {@link Map the annotation attributes} or {@link AnnotationAttributes}\n     * @param attributeName the name of attribute\n     * @param required      the required attribute or not\n     * @param <T>           the type of attribute value\n     * @return the attribute value if found\n     * @throws IllegalStateException if attribute value can't be found\n     * @since 1.0.6\n     */\n    public static <T> T getAttribute(Map<String, Object> attributes, String attributeName, boolean required) {\n        T value = getAttribute(attributes, attributeName, null);\n        if (required && value == null) {\n            throw new IllegalStateException(\"The attribute['\" + attributeName + \"] is required!\");\n        }\n        return value;\n    }\n\n    /**\n     * Get the attribute value with default value\n     *\n     * @param attributes    {@link Map the annotation attributes} or {@link AnnotationAttributes}\n     * @param attributeName the name of attribute\n     * @param defaultValue  the default value of attribute\n     * @param <T>           the type of attribute value\n     * @return the attribute value if found\n     * @since 1.0.6\n     */\n    public static <T> T getAttribute(Map<String, Object> attributes, String attributeName, T defaultValue) {\n        T value = (T) attributes.get(attributeName);\n        return value == null ? defaultValue : value;\n    }\n\n    /**\n     * Get the required attribute value\n     *\n     * @param attributes    {@link Map the annotation attributes} or {@link AnnotationAttributes}\n     * @param attributeName the name of attribute\n     * @param <T>           the type of attribute value\n     * @return the attribute value if found\n     * @throws IllegalStateException if attribute value can't be found\n     * @since 1.0.6\n     */\n    public static <T> T getRequiredAttribute(Map<String, Object> attributes, String attributeName) {\n        return getAttribute(attributes, attributeName, true);\n    }\n\n    /**\n     * Get the {@link AnnotationAttributes}\n     *\n     * @param annotation           specified {@link Annotation}\n     * @param ignoreDefaultValue   whether ignore default value or not\n     * @param ignoreAttributeNames the attribute names of annotation should be ignored\n     * @return non-null\n     * @see #getAnnotationAttributes(Annotation, PropertyResolver, boolean, String...)\n     * @since 1.0.3\n     */\n    public static AnnotationAttributes getAnnotationAttributes(\n            Annotation annotation, boolean ignoreDefaultValue, String... ignoreAttributeNames) {\n        return getAnnotationAttributes(annotation, null, ignoreDefaultValue, ignoreAttributeNames);\n    }\n\n    /**\n     * Get the {@link AnnotationAttributes}\n     *\n     * @param annotation             specified {@link Annotation}\n     * @param propertyResolver       {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param classValuesAsString    whether to turn Class references into Strings (for\n     *                               compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to\n     *                               preserve them as Class references\n     * @param nestedAnnotationsAsMap whether to turn nested Annotation instances into\n     *                               {@link AnnotationAttributes} maps (for compatibility with\n     *                               {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as\n     *                               Annotation instances\n     * @param ignoreAttributeNames   the attribute names of annotation should be ignored\n     * @param ignoreDefaultValue     whether ignore default value or not\n     * @return non-null\n     * @see #getAttributes(Annotation, PropertyResolver, boolean, String...)\n     * @see #getAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, String...)\n     * @since 1.0.11\n     */\n    public static AnnotationAttributes getAnnotationAttributes(\n            Annotation annotation,\n            PropertyResolver propertyResolver,\n            boolean classValuesAsString,\n            boolean nestedAnnotationsAsMap,\n            boolean ignoreDefaultValue,\n            String... ignoreAttributeNames) {\n        return fromMap(getAttributes(\n                annotation,\n                propertyResolver,\n                classValuesAsString,\n                nestedAnnotationsAsMap,\n                ignoreDefaultValue,\n                ignoreAttributeNames));\n    }\n\n    /**\n     * Get the {@link AnnotationAttributes}\n     *\n     * @param annotation           specified {@link Annotation}\n     * @param propertyResolver     {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param ignoreDefaultValue   whether ignore default value or not\n     * @param ignoreAttributeNames the attribute names of annotation should be ignored\n     * @return non-null\n     * @see #getAttributes(Annotation, PropertyResolver, boolean, String...)\n     * @see #getAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, String...)\n     * @since 1.0.3\n     */\n    public static AnnotationAttributes getAnnotationAttributes(\n            Annotation annotation,\n            PropertyResolver propertyResolver,\n            boolean ignoreDefaultValue,\n            String... ignoreAttributeNames) {\n        return getAnnotationAttributes(\n                annotation, propertyResolver, false, false, ignoreDefaultValue, ignoreAttributeNames);\n    }\n\n    /**\n     * Get the {@link AnnotationAttributes}\n     *\n     * @param annotatedElement     {@link AnnotatedElement the annotated element}\n     * @param annotationType       the {@link Class tyoe} pf {@link Annotation annotation}\n     * @param propertyResolver     {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param ignoreDefaultValue   whether ignore default value or not\n     * @param ignoreAttributeNames the attribute names of annotation should be ignored\n     * @return if <code>annotatedElement</code> can't be found in <code>annotatedElement</code>, return <code>null</code>\n     * @since 1.0.3\n     */\n    public static AnnotationAttributes getAnnotationAttributes(\n            AnnotatedElement annotatedElement,\n            Class<? extends Annotation> annotationType,\n            PropertyResolver propertyResolver,\n            boolean ignoreDefaultValue,\n            String... ignoreAttributeNames) {\n        return getAnnotationAttributes(\n                annotatedElement,\n                annotationType,\n                propertyResolver,\n                false,\n                false,\n                ignoreDefaultValue,\n                ignoreAttributeNames);\n    }\n\n    /**\n     * Get the {@link AnnotationAttributes}\n     *\n     * @param annotatedElement     {@link AnnotatedElement the annotated element}\n     * @param annotationType       the {@link Class tyoe} pf {@link Annotation annotation}\n     * @param propertyResolver     {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param ignoreDefaultValue   whether ignore default value or not\n     * @param ignoreAttributeNames the attribute names of annotation should be ignored\n     * @return if <code>annotatedElement</code> can't be found in <code>annotatedElement</code>, return <code>null</code>\n     * @since 1.0.11\n     */\n    public static AnnotationAttributes getAnnotationAttributes(\n            AnnotatedElement annotatedElement,\n            Class<? extends Annotation> annotationType,\n            PropertyResolver propertyResolver,\n            boolean classValuesAsString,\n            boolean nestedAnnotationsAsMap,\n            boolean ignoreDefaultValue,\n            String... ignoreAttributeNames) {\n        Annotation annotation = annotatedElement.getAnnotation(annotationType);\n        return annotation == null\n                ? null\n                : getAnnotationAttributes(\n                        annotation,\n                        propertyResolver,\n                        classValuesAsString,\n                        nestedAnnotationsAsMap,\n                        ignoreDefaultValue,\n                        ignoreAttributeNames);\n    }\n\n    /**\n     * Get the {@link AnnotationAttributes}, if the argument <code>tryMergedAnnotation</code> is <code>true</code>,\n     * the {@link AnnotationAttributes} will be got from\n     * {@link #tryGetMergedAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, String...) merged annotation} first,\n     * if failed, and then to get from\n     * {@link #getAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, boolean, String...) normal one}\n     *\n     * @param annotatedElement     {@link AnnotatedElement the annotated element}\n     * @param annotationType       the {@link Class tyoe} pf {@link Annotation annotation}\n     * @param propertyResolver     {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param ignoreDefaultValue   whether ignore default value or not\n     * @param tryMergedAnnotation  whether try merged annotation or not\n     * @param ignoreAttributeNames the attribute names of annotation should be ignored\n     * @return if <code>annotatedElement</code> can't be found in <code>annotatedElement</code>, return <code>null</code>\n     * @since 1.0.3\n     */\n    public static AnnotationAttributes getAnnotationAttributes(\n            AnnotatedElement annotatedElement,\n            Class<? extends Annotation> annotationType,\n            PropertyResolver propertyResolver,\n            boolean ignoreDefaultValue,\n            boolean tryMergedAnnotation,\n            String... ignoreAttributeNames) {\n        return getAnnotationAttributes(\n                annotatedElement,\n                annotationType,\n                propertyResolver,\n                false,\n                false,\n                ignoreDefaultValue,\n                tryMergedAnnotation,\n                ignoreAttributeNames);\n    }\n\n    /**\n     * Get the {@link AnnotationAttributes}, if the argument <code>tryMergedAnnotation</code> is <code>true</code>,\n     * the {@link AnnotationAttributes} will be got from\n     * {@link #tryGetMergedAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, String...) merged annotation} first,\n     * if failed, and then to get from\n     * {@link #getAnnotationAttributes(AnnotatedElement, Class, PropertyResolver, boolean, boolean, String...) normal one}\n     *\n     * @param annotatedElement       {@link AnnotatedElement the annotated element}\n     * @param annotationType         the {@link Class tyoe} pf {@link Annotation annotation}\n     * @param propertyResolver       {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param classValuesAsString    whether to turn Class references into Strings (for\n     *                               compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to\n     *                               preserve them as Class references\n     * @param nestedAnnotationsAsMap whether to turn nested Annotation instances into\n     *                               {@link AnnotationAttributes} maps (for compatibility with\n     *                               {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as\n     *                               Annotation instances\n     * @param ignoreDefaultValue     whether ignore default value or not\n     * @param tryMergedAnnotation    whether try merged annotation or not\n     * @param ignoreAttributeNames   the attribute names of annotation should be ignored\n     * @return if <code>annotatedElement</code> can't be found in <code>annotatedElement</code>, return <code>null</code>\n     * @since 1.0.11\n     */\n    public static AnnotationAttributes getAnnotationAttributes(\n            AnnotatedElement annotatedElement,\n            Class<? extends Annotation> annotationType,\n            PropertyResolver propertyResolver,\n            boolean classValuesAsString,\n            boolean nestedAnnotationsAsMap,\n            boolean ignoreDefaultValue,\n            boolean tryMergedAnnotation,\n            String... ignoreAttributeNames) {\n\n        AnnotationAttributes attributes = null;\n\n        if (tryMergedAnnotation) {\n            attributes = tryGetMergedAnnotationAttributes(\n                    annotatedElement,\n                    annotationType,\n                    propertyResolver,\n                    classValuesAsString,\n                    nestedAnnotationsAsMap,\n                    ignoreDefaultValue,\n                    ignoreAttributeNames);\n        }\n\n        if (attributes == null) {\n            attributes = getAnnotationAttributes(\n                    annotatedElement,\n                    annotationType,\n                    propertyResolver,\n                    classValuesAsString,\n                    nestedAnnotationsAsMap,\n                    ignoreDefaultValue,\n                    ignoreAttributeNames);\n        }\n\n        return attributes;\n    }\n\n    /**\n     * Try to get the merged {@link Annotation annotation}\n     *\n     * @param annotatedElement {@link AnnotatedElement the annotated element}\n     * @param annotationType   the {@link Class tyoe} pf {@link Annotation annotation}\n     * @return If current version of Spring Framework is below 4.2, return <code>null</code>\n     * @since 1.0.3\n     */\n    public static Annotation tryGetMergedAnnotation(\n            AnnotatedElement annotatedElement, Class<? extends Annotation> annotationType) {\n        return tryGetMergedAnnotation(annotatedElement, annotationType, false, false);\n    }\n\n    /**\n     * Try to get the merged {@link Annotation annotation}\n     *\n     * @param annotatedElement       {@link AnnotatedElement the annotated element}\n     * @param annotationType         the {@link Class tyoe} pf {@link Annotation annotation}\n     * @param classValuesAsString    whether to turn Class references into Strings (for\n     *                               compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to\n     *                               preserve them as Class references\n     * @param nestedAnnotationsAsMap whether to turn nested Annotation instances into\n     *                               {@link AnnotationAttributes} maps (for compatibility with\n     *                               {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as\n     *                               Annotation instances\n     * @return If current version of Spring Framework is below 4.2, return <code>null</code>\n     * @since 1.0.11\n     */\n    public static Annotation tryGetMergedAnnotation(\n            AnnotatedElement annotatedElement,\n            Class<? extends Annotation> annotationType,\n            boolean classValuesAsString,\n            boolean nestedAnnotationsAsMap) {\n\n        Annotation mergedAnnotation = null;\n\n        ClassLoader classLoader = annotationType.getClassLoader();\n\n        if (ClassUtils.isPresent(ANNOTATED_ELEMENT_UTILS_CLASS_NAME, classLoader)) {\n            Class<?> annotatedElementUtilsClass = resolveClassName(ANNOTATED_ELEMENT_UTILS_CLASS_NAME, classLoader);\n            // getMergedAnnotation method appears in the Spring Framework 5.x\n            Method getMergedAnnotationMethod =\n                    findMethod(annotatedElementUtilsClass, \"getMergedAnnotation\", AnnotatedElement.class, Class.class);\n            if (getMergedAnnotationMethod != null) {\n                mergedAnnotation =\n                        (Annotation) invokeMethod(getMergedAnnotationMethod, null, annotatedElement, annotationType);\n            } else {\n                // getMergedAnnotation method appears in the Spring Framework 4.2\n                getMergedAnnotationMethod = findMethod(\n                        annotatedElementUtilsClass,\n                        \"getMergedAnnotation\",\n                        AnnotatedElement.class,\n                        Class.class,\n                        boolean.class,\n                        boolean.class);\n                if (getMergedAnnotationMethod != null) {\n                    mergedAnnotation = (Annotation) invokeMethod(\n                            getMergedAnnotationMethod,\n                            null,\n                            annotatedElement,\n                            annotationType,\n                            classValuesAsString,\n                            nestedAnnotationsAsMap);\n                }\n            }\n        }\n\n        return mergedAnnotation;\n    }\n\n    /**\n     * Try to get {@link AnnotationAttributes the annotation attributes} after merging and resolving the placeholders\n     *\n     * @param annotatedElement     {@link AnnotatedElement the annotated element}\n     * @param annotationType       the {@link Class tyoe} pf {@link Annotation annotation}\n     * @param propertyResolver     {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param ignoreDefaultValue   whether ignore default value or not\n     * @param ignoreAttributeNames the attribute names of annotation should be ignored\n     * @return If the specified annotation type is not found, return <code>null</code>\n     * @since 1.0.3\n     */\n    public static AnnotationAttributes tryGetMergedAnnotationAttributes(\n            AnnotatedElement annotatedElement,\n            Class<? extends Annotation> annotationType,\n            PropertyResolver propertyResolver,\n            boolean ignoreDefaultValue,\n            String... ignoreAttributeNames) {\n        return tryGetMergedAnnotationAttributes(\n                annotatedElement,\n                annotationType,\n                propertyResolver,\n                false,\n                false,\n                ignoreDefaultValue,\n                ignoreAttributeNames);\n    }\n\n    /**\n     * Try to get {@link AnnotationAttributes the annotation attributes} after merging and resolving the placeholders\n     *\n     * @param annotatedElement       {@link AnnotatedElement the annotated element}\n     * @param annotationType         the {@link Class tyoe} pf {@link Annotation annotation}\n     * @param propertyResolver       {@link PropertyResolver} instance, e.g {@link Environment}\n     * @param classValuesAsString    whether to turn Class references into Strings (for\n     *                               compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to\n     *                               preserve them as Class references\n     * @param nestedAnnotationsAsMap whether to turn nested Annotation instances into\n     *                               {@link AnnotationAttributes} maps (for compatibility with\n     *                               {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as\n     *                               Annotation instances\n     * @param ignoreDefaultValue     whether ignore default value or not\n     * @param ignoreAttributeNames   the attribute names of annotation should be ignored\n     * @return If the specified annotation type is not found, return <code>null</code>\n     * @since 1.0.11\n     */\n    public static AnnotationAttributes tryGetMergedAnnotationAttributes(\n            AnnotatedElement annotatedElement,\n            Class<? extends Annotation> annotationType,\n            PropertyResolver propertyResolver,\n            boolean classValuesAsString,\n            boolean nestedAnnotationsAsMap,\n            boolean ignoreDefaultValue,\n            String... ignoreAttributeNames) {\n        Annotation annotation =\n                tryGetMergedAnnotation(annotatedElement, annotationType, classValuesAsString, nestedAnnotationsAsMap);\n        return annotation == null\n                ? null\n                : getAnnotationAttributes(\n                        annotation,\n                        propertyResolver,\n                        classValuesAsString,\n                        nestedAnnotationsAsMap,\n                        ignoreDefaultValue,\n                        ignoreAttributeNames);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport org.springframework.core.AliasRegistry;\n\nimport static org.springframework.util.ObjectUtils.containsElement;\nimport static org.springframework.util.StringUtils.hasText;\n\n/**\n * Bean Registrar\n */\npublic abstract class BeanRegistrar {\n\n    /**\n     * Detect the alias is present or not in the given bean name from {@link AliasRegistry}\n     *\n     * @param registry {@link AliasRegistry}\n     * @param beanName the bean name\n     * @param alias    alias to test\n     * @return if present, return <code>true</code>, or <code>false</code>\n     */\n    public static boolean hasAlias(AliasRegistry registry, String beanName, String alias) {\n        return hasText(beanName) && hasText(alias) && containsElement(registry.getAliases(beanName), alias);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboAnnotationUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.springframework.util.Assert;\n\nimport static org.springframework.util.ClassUtils.getAllInterfacesForClass;\nimport static org.springframework.util.StringUtils.hasText;\n\n/**\n * Dubbo Annotation Utilities Class\n *\n * @see org.springframework.core.annotation.AnnotationUtils\n * @since 2.5.11\n */\npublic class DubboAnnotationUtils {\n\n    @Deprecated\n    public static String resolveInterfaceName(Service service, Class<?> defaultInterfaceClass)\n            throws IllegalStateException {\n\n        String interfaceName;\n        if (hasText(service.interfaceName())) {\n            interfaceName = service.interfaceName();\n        } else if (!void.class.equals(service.interfaceClass())) {\n            interfaceName = service.interfaceClass().getName();\n        } else if (defaultInterfaceClass.isInterface()) {\n            interfaceName = defaultInterfaceClass.getName();\n        } else {\n            throw new IllegalStateException(\"The @Service undefined interfaceClass or interfaceName, and the type \"\n                    + defaultInterfaceClass.getName() + \" is not a interface.\");\n        }\n\n        return interfaceName;\n    }\n\n    /**\n     * Resolve the service interface name from @Service annotation attributes.\n     * <p/>\n     * Note: the service interface class maybe not found locally if is a generic service.\n     *\n     * @param attributes             annotation attributes of {@link Service @Service}\n     * @param defaultInterfaceClass the default class of interface\n     * @return the interface name if found\n     * @throws IllegalStateException if interface name was not found\n     */\n    public static String resolveInterfaceName(Map<String, Object> attributes, Class<?> defaultInterfaceClass) {\n        // 1. get from DubboService.interfaceName()\n        String interfaceClassName = AnnotationUtils.getAttribute(attributes, \"interfaceName\");\n        if (StringUtils.hasText(interfaceClassName)) {\n            if (\"org.apache.dubbo.rpc.service.GenericService\".equals(interfaceClassName)\n                    || \"com.alibaba.dubbo.rpc.service.GenericService\".equals(interfaceClassName)) {\n                throw new IllegalStateException(\n                        \"@Service interfaceName() cannot be GenericService: \" + interfaceClassName);\n            }\n            return interfaceClassName;\n        }\n\n        // 2. get from DubboService.interfaceClass()\n        Class<?> interfaceClass = AnnotationUtils.getAttribute(attributes, \"interfaceClass\");\n        if (interfaceClass == null || void.class.equals(interfaceClass)) { // default or set void.class for purpose.\n            interfaceClass = null;\n        } else if (GenericService.class.isAssignableFrom(interfaceClass)) {\n            throw new IllegalStateException(\n                    \"@Service interfaceClass() cannot be GenericService :\" + interfaceClass.getName());\n        }\n\n        // 3. get from annotation element type, ignore GenericService\n        if (interfaceClass == null\n                && defaultInterfaceClass != null\n                && !GenericService.class.isAssignableFrom(defaultInterfaceClass)) {\n            // Find all interfaces from the annotated class\n            // To resolve an issue : https://github.com/apache/dubbo/issues/3251\n            Class<?>[] allInterfaces = getAllInterfacesForClass(defaultInterfaceClass);\n            if (allInterfaces.length > 0) {\n                interfaceClass = allInterfaces[0];\n            } else {\n                interfaceClass = defaultInterfaceClass;\n            }\n        }\n\n        Assert.notNull(\n                interfaceClass, \"@Service interfaceClass() or interfaceName() or interface class must be present!\");\n        // Assert.isTrue(interfaceClass.isInterface(), \"The annotated type must be an interface!\");\n        return interfaceClass.getName();\n    }\n\n    @Deprecated\n    public static String resolveInterfaceName(Reference reference, Class<?> defaultInterfaceClass)\n            throws IllegalStateException {\n\n        String interfaceName;\n        if (!\"\".equals(reference.interfaceName())) {\n            interfaceName = reference.interfaceName();\n        } else if (!void.class.equals(reference.interfaceClass())) {\n            interfaceName = reference.interfaceClass().getName();\n        } else if (defaultInterfaceClass.isInterface()) {\n            interfaceName = defaultInterfaceClass.getName();\n        } else {\n            throw new IllegalStateException(\"The @Reference undefined interfaceClass or interfaceName, and the type \"\n                    + defaultInterfaceClass.getName() + \" is not a interface.\");\n        }\n\n        return interfaceName;\n    }\n\n    /**\n     * Resolve the parameters of {@link org.apache.dubbo.config.annotation.DubboService}\n     * and {@link org.apache.dubbo.config.annotation.DubboReference} from the specified.\n     * It iterates elements in order.The former element plays as key or key&value role, it would be\n     * spilt if it contains specific string, for instance, \":\" and \"=\". As for later element can't\n     * be split in anytime.It will throw IllegalArgumentException If converted array length isn't\n     * even number.\n     * The convert cases below work in right way,which are best practice.\n     * <pre>\n     * (array->map)\n     * [\"a\",\"b\"] ==> {a=b}\n     * [\" a \",\" b \"] ==> {a=b}\n     * [\"a=b\"] ==>{a=b}\n     * [\"a:b\"] ==>{a=b}\n     * [\"a=b\",\"c\",\"d\"] ==>{a=b,c=d}\n     * [\"a\",\"a:b\"] ==>{a=\"a:b\"}\n     * [\"a\",\"a,b\"] ==>{a=\"a,b\"}\n     * </pre>\n     *\n     * @param parameters\n     * @return\n     */\n    public static Map<String, String> convertParameters(String[] parameters) {\n        if (ArrayUtils.isEmpty(parameters)) {\n            return new HashMap<>();\n        }\n\n        List<String> compatibleParameterArray = Arrays.stream(parameters)\n                .map(String::trim)\n                .reduce(\n                        new ArrayList<>(parameters.length),\n                        (list, parameter) -> {\n                            if (list.size() % 2 == 1) {\n                                // value doesn't split\n                                list.add(parameter);\n                                return list;\n                            }\n\n                            String[] sp1 = parameter.split(\":\");\n                            if (sp1.length > 0 && sp1.length % 2 == 0) {\n                                // key split\n                                list.addAll(Arrays.stream(sp1).map(String::trim).collect(Collectors.toList()));\n                                return list;\n                            }\n                            sp1 = parameter.split(\"=\");\n                            if (sp1.length > 0 && sp1.length % 2 == 0) {\n                                list.addAll(Arrays.stream(sp1).map(String::trim).collect(Collectors.toList()));\n                                return list;\n                            }\n                            list.add(parameter);\n                            return list;\n                        },\n                        (a, b) -> a);\n\n        return CollectionUtils.toStringMap(compatibleParameterArray.toArray(new String[0]));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigAliasPostProcessor;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ServicePackagesHolder;\nimport org.apache.dubbo.config.spring.beans.factory.config.DubboConfigDefaultPropertyValueBeanPostProcessor;\nimport org.apache.dubbo.config.spring.context.DubboConfigApplicationListener;\nimport org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;\nimport org.apache.dubbo.config.spring.context.DubboContextPostProcessor;\nimport org.apache.dubbo.config.spring.context.DubboDeployApplicationListener;\nimport org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor;\nimport org.apache.dubbo.config.spring.context.DubboSpringInitContext;\nimport org.apache.dubbo.config.spring.reference.ReferenceBeanManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.AbstractBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\n\n/**\n * Dubbo Bean utilities class\n *\n * @since 2.7.6\n */\npublic interface DubboBeanUtils {\n\n    Log log = LogFactory.getLog(DubboBeanUtils.class);\n\n    /**\n     * Register the common beans\n     *\n     * @param registry {@link BeanDefinitionRegistry}\n     * @see ReferenceAnnotationBeanPostProcessor\n     * @see DubboConfigDefaultPropertyValueBeanPostProcessor\n     * @see DubboConfigAliasPostProcessor\n     */\n    static void registerCommonBeans(BeanDefinitionRegistry registry) {\n\n        registerInfrastructureBean(registry, ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);\n\n        registerInfrastructureBean(registry, DubboContextPostProcessor.BEAN_NAME, DubboContextPostProcessor.class);\n\n        registerInfrastructureBean(registry, ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);\n\n        // Since 2.5.7 Register @Reference Annotation Bean Processor as an infrastructure Bean\n        registerInfrastructureBean(\n                registry,\n                SpringCompatUtils.referenceAnnotationBeanPostProcessor().getName(),\n                SpringCompatUtils.referenceAnnotationBeanPostProcessor());\n\n        // TODO Whether DubboConfigAliasPostProcessor can be removed ?\n        // Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093\n        registerInfrastructureBean(\n                registry, DubboConfigAliasPostProcessor.BEAN_NAME, DubboConfigAliasPostProcessor.class);\n\n        // register ApplicationListeners\n        registerInfrastructureBean(\n                registry, DubboDeployApplicationListener.class.getName(), DubboDeployApplicationListener.class);\n        registerInfrastructureBean(\n                registry, DubboConfigApplicationListener.class.getName(), DubboConfigApplicationListener.class);\n\n        // Since 2.7.6 Register DubboConfigDefaultPropertyValueBeanPostProcessor as an infrastructure Bean\n        registerInfrastructureBean(\n                registry,\n                DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME,\n                DubboConfigDefaultPropertyValueBeanPostProcessor.class);\n\n        // Dubbo config initializer\n        registerInfrastructureBean(registry, DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);\n\n        // register infra bean if not exists later\n        registerInfrastructureBean(\n                registry,\n                DubboInfraBeanRegisterPostProcessor.BEAN_NAME,\n                SpringCompatUtils.dubboInfraBeanRegisterPostProcessor());\n    }\n\n    /**\n     * Register Infrastructure Bean\n     *\n     * @param beanDefinitionRegistry {@link BeanDefinitionRegistry}\n     * @param beanType               the type of bean\n     * @param beanName               the name of bean\n     * @return if it's a first time to register, return <code>true</code>, or <code>false</code>\n     */\n    static boolean registerInfrastructureBean(\n            BeanDefinitionRegistry beanDefinitionRegistry, String beanName, Class<?> beanType) {\n\n        boolean registered = false;\n\n        if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) {\n            RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);\n            beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);\n            beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);\n            registered = true;\n\n            if (log.isDebugEnabled()) {\n                log.debug(\"The Infrastructure bean definition [\" + beanDefinition + \"with name [\" + beanName\n                        + \"] has been registered.\");\n            }\n        }\n\n        return registered;\n    }\n\n    /**\n     * Register a placeholder configurer beans if not exists.\n     * Call this method in BeanDefinitionRegistryPostProcessor,\n     * in order to enable the registered BeanFactoryPostProcessor bean to be loaded and executed.\n     *\n     * @param beanFactory\n     * @param registry\n     * @see DubboInfraBeanRegisterPostProcessor\n     * @see org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List)\n     */\n    static void registerPlaceholderConfigurerBeanIfNotExists(\n            ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry) {\n        // Auto register a PropertyPlaceholderConfigurer bean to resolve placeholders with Spring Environment\n        // PropertySources\n        // when loading dubbo xml config with @ImportResource\n        if (!checkBeanExists(beanFactory, PropertySourcesPlaceholderConfigurer.class)) {\n            Map<String, Object> propertySourcesPlaceholderPropertyValues = new HashMap<>();\n            propertySourcesPlaceholderPropertyValues.put(\"ignoreUnresolvablePlaceholders\", true);\n\n            registerBeanDefinition(\n                    registry,\n                    PropertySourcesPlaceholderConfigurer.class.getName(),\n                    PropertySourcesPlaceholderConfigurer.class,\n                    propertySourcesPlaceholderPropertyValues);\n        }\n    }\n\n    static boolean registerBeanDefinition(\n            BeanDefinitionRegistry registry,\n            String beanName,\n            Class<?> beanClass,\n            Map<String, Object> extraPropertyValues) {\n        if (registry.containsBeanDefinition(beanName)) {\n            return false;\n        }\n\n        BeanDefinition beanDefinition =\n                BeanDefinitionBuilder.genericBeanDefinition(beanClass).getBeanDefinition();\n        if (extraPropertyValues != null) {\n            for (Map.Entry<String, Object> entry : extraPropertyValues.entrySet()) {\n                beanDefinition.getPropertyValues().add(entry.getKey(), entry.getValue());\n            }\n        }\n\n        registry.registerBeanDefinition(beanName, beanDefinition);\n        return true;\n    }\n\n    static boolean checkBeanExists(ConfigurableListableBeanFactory beanFactory, Class<?> targetClass) {\n        String[] beanNames = beanFactory.getBeanNamesForType(targetClass, true, false);\n        return (beanNames != null && beanNames.length > 0);\n    }\n\n    static ReferenceAnnotationBeanPostProcessor getReferenceAnnotationBeanPostProcessor(\n            AbstractBeanFactory beanFactory) {\n        for (BeanPostProcessor beanPostProcessor : beanFactory.getBeanPostProcessors()) {\n            if (beanPostProcessor instanceof ReferenceAnnotationBeanPostProcessor) {\n                return (ReferenceAnnotationBeanPostProcessor) beanPostProcessor;\n            }\n        }\n        return null;\n    }\n\n    static ReferenceAnnotationBeanPostProcessor getReferenceAnnotationBeanPostProcessor(\n            ApplicationContext applicationContext) {\n        return getReferenceAnnotationBeanPostProcessor(\n                (AbstractBeanFactory) applicationContext.getAutowireCapableBeanFactory());\n    }\n\n    static DubboSpringInitContext getInitializationContext(BeanFactory beanFactory) {\n        String beanName = DubboSpringInitContext.class.getName();\n        if (beanFactory != null && beanFactory.containsBean(beanName)) {\n            return beanFactory.getBean(beanName, DubboSpringInitContext.class);\n        }\n        return null;\n    }\n\n    static ApplicationModel getApplicationModel(BeanFactory beanFactory) {\n        String beanName = ApplicationModel.class.getName();\n        if (beanFactory != null && beanFactory.containsBean(beanName)) {\n            return beanFactory.getBean(beanName, ApplicationModel.class);\n        }\n        return null;\n    }\n\n    static ModuleModel getModuleModel(BeanFactory beanFactory) {\n        String beanName = ModuleModel.class.getName();\n        if (beanFactory != null && beanFactory.containsBean(beanName)) {\n            return beanFactory.getBean(beanName, ModuleModel.class);\n        }\n        return null;\n    }\n\n    static ConfigManager getConfigManager(BeanFactory beanFactory) {\n        String beanName = ConfigManager.BEAN_NAME;\n        if (beanFactory.containsBean(beanName)) {\n            return beanFactory.getBean(beanName, ConfigManager.class);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/EnvironmentUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\nimport org.springframework.core.env.CompositePropertySource;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * The utilities class for {@link Environment}\n *\n * @see Environment\n * @since 2.7.0\n */\npublic abstract class EnvironmentUtils {\n\n    /**\n     * The separator of property name\n     */\n    public static final String PROPERTY_NAME_SEPARATOR = \".\";\n\n    /**\n     * The prefix of property name of Dubbo\n     */\n    public static final String DUBBO_PREFIX = \"dubbo\";\n\n    /**\n     * Extras The properties from {@link ConfigurableEnvironment}\n     *\n     * @param environment {@link ConfigurableEnvironment}\n     * @return Read-only Map\n     */\n    public static Map<String, Object> extractProperties(ConfigurableEnvironment environment) {\n        return Collections.unmodifiableMap(doExtraProperties(environment));\n    }\n\n    private static Map<String, Object> doExtraProperties(ConfigurableEnvironment environment) {\n\n        Map<String, Object> properties = new LinkedHashMap<>(); // orderly\n\n        Map<String, PropertySource<?>> map = doGetPropertySources(environment);\n\n        for (PropertySource<?> source : map.values()) {\n\n            if (source instanceof EnumerablePropertySource) {\n\n                EnumerablePropertySource propertySource = (EnumerablePropertySource) source;\n\n                String[] propertyNames = propertySource.getPropertyNames();\n\n                if (ObjectUtils.isEmpty(propertyNames)) {\n                    continue;\n                }\n\n                for (String propertyName : propertyNames) {\n\n                    if (!properties.containsKey(propertyName)) { // put If absent\n                        properties.put(propertyName, propertySource.getProperty(propertyName));\n                    }\n                }\n            }\n        }\n\n        return properties;\n    }\n\n    private static Map<String, PropertySource<?>> doGetPropertySources(ConfigurableEnvironment environment) {\n        Map<String, PropertySource<?>> map = new LinkedHashMap<>();\n        MutablePropertySources sources = environment.getPropertySources();\n        for (PropertySource<?> source : sources) {\n            extract(\"\", map, source);\n        }\n        return map;\n    }\n\n    private static void extract(String root, Map<String, PropertySource<?>> map, PropertySource<?> source) {\n        if (source instanceof CompositePropertySource) {\n            for (PropertySource<?> nest : ((CompositePropertySource) source).getPropertySources()) {\n                extract(source.getName() + \":\", map, nest);\n            }\n        } else {\n            map.put(root + source.getName(), source);\n        }\n    }\n\n    /**\n     * Filters Dubbo Properties from {@link ConfigurableEnvironment}\n     *\n     * @param environment {@link ConfigurableEnvironment}\n     * @return Read-only SortedMap\n     */\n    public static SortedMap<String, String> filterDubboProperties(ConfigurableEnvironment environment) {\n\n        SortedMap<String, String> dubboProperties = new TreeMap<>();\n\n        Map<String, Object> properties = extractProperties(environment);\n\n        for (Map.Entry<String, Object> entry : properties.entrySet()) {\n            String propertyName = entry.getKey();\n\n            if (propertyName.startsWith(DUBBO_PREFIX + PROPERTY_NAME_SEPARATOR) && entry.getValue() != null) {\n                dubboProperties.put(\n                        propertyName,\n                        environment.resolvePlaceholders(entry.getValue().toString()));\n            }\n        }\n\n        return Collections.unmodifiableSortedMap(dubboProperties);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/GenericBeanPostProcessorAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Generic {@link BeanPostProcessor} Adapter\n *\n * @see BeanPostProcessor\n */\n@SuppressWarnings(\"unchecked\")\npublic abstract class GenericBeanPostProcessorAdapter<T> implements BeanPostProcessor {\n\n    private final Class<T> beanType;\n\n    public GenericBeanPostProcessorAdapter() {\n        ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();\n        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();\n        this.beanType = (Class<T>) actualTypeArguments[0];\n    }\n\n    @Override\n    public final Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n        if (ClassUtils.isAssignableValue(beanType, bean)) {\n            return doPostProcessBeforeInitialization((T) bean, beanName);\n        }\n        return bean;\n    }\n\n    @Override\n    public final Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n        if (ClassUtils.isAssignableValue(beanType, bean)) {\n            return doPostProcessAfterInitialization((T) bean, beanName);\n        }\n        return bean;\n    }\n\n    /**\n     * Bean Type\n     *\n     * @return Bean Type\n     */\n    public final Class<T> getBeanType() {\n        return beanType;\n    }\n\n    /**\n     * Adapter BeanPostProcessor#postProcessBeforeInitialization(Object, String) method , sub-type\n     * could override this method.\n     *\n     * @param bean     Bean Object\n     * @param beanName Bean Name\n     * @return Bean Object\n     * @see BeanPostProcessor#postProcessBeforeInitialization(Object, String)\n     */\n    protected T doPostProcessBeforeInitialization(T bean, String beanName) throws BeansException {\n\n        processBeforeInitialization(bean, beanName);\n\n        return bean;\n    }\n\n    /**\n     * Adapter BeanPostProcessor#postProcessAfterInitialization(Object, String) method , sub-type\n     * could override this method.\n     *\n     * @param bean     Bean Object\n     * @param beanName Bean Name\n     * @return Bean Object\n     * @see BeanPostProcessor#postProcessAfterInitialization(Object, String)\n     */\n    protected T doPostProcessAfterInitialization(T bean, String beanName) throws BeansException {\n\n        processAfterInitialization(bean, beanName);\n\n        return bean;\n    }\n\n    /**\n     * Process {@link T Bean} with name without return value before initialization,\n     * <p>\n     * This method will be invoked by BeanPostProcessor#postProcessBeforeInitialization(Object, String)\n     *\n     * @param bean     Bean Object\n     * @param beanName Bean Name\n     * @throws BeansException  in case of errors\n     */\n    protected void processBeforeInitialization(T bean, String beanName) throws BeansException {}\n\n    /**\n     * Process {@link T Bean} with name without return value after initialization,\n     * <p>\n     * This method will be invoked by BeanPostProcessor#postProcessAfterInitialization(Object, String)\n     *\n     * @param bean     Bean Object\n     * @param beanName Bean Name\n     * @throws BeansException  in case of errors\n     */\n    protected void processAfterInitialization(T bean, String beanName) throws BeansException {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/LazyTargetInvocationHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\npublic class LazyTargetInvocationHandler implements InvocationHandler {\n    private final LazyTargetSource lazyTargetSource;\n    private volatile Object target;\n\n    public LazyTargetInvocationHandler(LazyTargetSource lazyTargetSource) {\n        this.lazyTargetSource = lazyTargetSource;\n    }\n\n    @Override\n    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n        String methodName = method.getName();\n        Class<?>[] parameterTypes = method.getParameterTypes();\n        if (parameterTypes.length == 0) {\n            if (\"toString\".equals(methodName)) {\n                if (target != null) {\n                    return target.toString();\n                } else {\n                    return this.toString();\n                }\n            } else if (\"hashCode\".equals(methodName)) {\n                return this.hashCode();\n            }\n        } else if (parameterTypes.length == 1 && \"equals\".equals(methodName)) {\n            return this.equals(args[0]);\n        }\n\n        if (target == null) {\n            target = lazyTargetSource.getTarget();\n        }\n        if (method.getDeclaringClass().isInstance(target)) {\n            try {\n                return method.invoke(target, args);\n            } catch (InvocationTargetException exception) {\n                Throwable targetException = exception.getTargetException();\n                if (targetException != null) {\n                    throw targetException;\n                }\n            }\n        }\n        throw new IllegalStateException(\"The proxied interface [\" + method.getDeclaringClass() + \"] contains a method [\"\n                + method + \"] that is not implemented by the proxy class [\" + target.getClass() + \"]\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/LazyTargetSource.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\npublic interface LazyTargetSource {\n    Object getTarget() throws Exception;\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/LockUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport java.lang.reflect.Method;\n\nimport org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;\nimport org.springframework.context.ApplicationContext;\n\npublic class LockUtils {\n\n    private static final String DUBBO_SINGLETON_MUTEX_KEY = \"DUBBO_SINGLETON_MUTEX\";\n\n    /**\n     * Get the mutex to lock the singleton in the specified {@link ApplicationContext}\n     */\n    public static synchronized Object getSingletonMutex(ApplicationContext applicationContext) {\n        DefaultSingletonBeanRegistry autowireCapableBeanFactory =\n                (DefaultSingletonBeanRegistry) applicationContext.getAutowireCapableBeanFactory();\n        try {\n            return autowireCapableBeanFactory.getSingletonMutex();\n        } catch (Throwable t1) {\n            try {\n                // try protected\n                Method method = DefaultSingletonBeanRegistry.class.getDeclaredMethod(\"getSingletonMutex\");\n                method.setAccessible(true);\n                return method.invoke(autowireCapableBeanFactory);\n            } catch (Throwable t2) {\n                // Before Spring 4.2, there is no getSingletonMutex method\n                if (!autowireCapableBeanFactory.containsSingleton(DUBBO_SINGLETON_MUTEX_KEY)) {\n                    autowireCapableBeanFactory.registerSingleton(DUBBO_SINGLETON_MUTEX_KEY, new Object());\n                }\n                return autowireCapableBeanFactory.getSingleton(DUBBO_SINGLETON_MUTEX_KEY);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ObjectUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\n/**\n * Object Utilities\n */\n@SuppressWarnings(\"unchecked\")\npublic abstract class ObjectUtils {\n\n    /**\n     * Empty String array\n     */\n    public static final String[] EMPTY_STRING_ARRAY = {};\n\n    /**\n     * Convert from variable arguments to array\n     *\n     * @param values variable arguments\n     * @param <T>    The class\n     * @return array\n     */\n    public static <T> T[] of(T... values) {\n        return values;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/PropertySourcesUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.PropertySources;\nimport org.springframework.core.env.PropertySourcesPropertyResolver;\n\nimport static java.util.Collections.unmodifiableMap;\n\n/**\n * {@link PropertySources} Utilities\n *\n * @see PropertySources\n */\npublic abstract class PropertySourcesUtils {\n\n    /**\n     * Get Sub {@link Properties}\n     *\n     * @param propertySources {@link PropertySource} Iterable\n     * @param prefix          the prefix of property name\n     * @return Map\n     * @see Properties\n     */\n    public static Map<String, Object> getSubProperties(Iterable<PropertySource<?>> propertySources, String prefix) {\n\n        MutablePropertySources mutablePropertySources = new MutablePropertySources();\n\n        for (PropertySource<?> source : propertySources) {\n            mutablePropertySources.addLast(source);\n        }\n\n        return getSubProperties(mutablePropertySources, prefix);\n    }\n\n    /**\n     * Get Sub {@link Properties}\n     *\n     * @param environment {@link ConfigurableEnvironment}\n     * @param prefix      the prefix of property name\n     * @return Map\n     * @see Properties\n     */\n    public static Map<String, Object> getSubProperties(ConfigurableEnvironment environment, String prefix) {\n        return getSubProperties(environment.getPropertySources(), environment, prefix);\n    }\n\n    /**\n     * Normalize the prefix\n     *\n     * @param prefix the prefix\n     * @return the prefix\n     */\n    public static String normalizePrefix(String prefix) {\n        return prefix.endsWith(\".\") ? prefix : prefix + \".\";\n    }\n\n    /**\n     * Get prefixed {@link Properties}\n     *\n     * @param propertySources {@link PropertySources}\n     * @param prefix          the prefix of property name\n     * @return Map\n     * @see Properties\n     */\n    public static Map<String, Object> getSubProperties(PropertySources propertySources, String prefix) {\n        return getSubProperties(propertySources, new PropertySourcesPropertyResolver(propertySources), prefix);\n    }\n\n    /**\n     * Get prefixed {@link Properties}\n     *\n     * @param propertySources  {@link PropertySources}\n     * @param propertyResolver {@link PropertyResolver} to resolve the placeholder if present\n     * @param prefix           the prefix of property name\n     * @return Map\n     * @see Properties\n     */\n    public static Map<String, Object> getSubProperties(\n            PropertySources propertySources, PropertyResolver propertyResolver, String prefix) {\n\n        Map<String, Object> subProperties = new LinkedHashMap<>();\n\n        String normalizedPrefix = normalizePrefix(prefix);\n\n        Iterator<PropertySource<?>> iterator = propertySources.iterator();\n\n        while (iterator.hasNext()) {\n            PropertySource<?> source = iterator.next();\n            for (String name : getPropertyNames(source)) {\n                if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) {\n                    String subName = name.substring(normalizedPrefix.length());\n                    if (!subProperties.containsKey(subName)) { // take first one\n                        Object value = source.getProperty(name);\n                        if (value instanceof String) {\n                            // Resolve placeholder\n                            value = propertyResolver.resolvePlaceholders((String) value);\n                        }\n                        subProperties.put(subName, value);\n                    }\n                }\n            }\n        }\n\n        return unmodifiableMap(subProperties);\n    }\n\n    /**\n     * Get the property names as the array from the specified {@link PropertySource} instance.\n     *\n     * @param propertySource {@link PropertySource} instance\n     * @return non-null\n     */\n    public static String[] getPropertyNames(PropertySource propertySource) {\n        String[] propertyNames = propertySource instanceof EnumerablePropertySource\n                ? ((EnumerablePropertySource) propertySource).getPropertyNames()\n                : null;\n\n        if (propertyNames == null) {\n            propertyNames = ObjectUtils.EMPTY_STRING_ARRAY;\n        }\n\n        return propertyNames;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/SpringCompatUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;\nimport org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.springframework.beans.PropertyValue;\nimport org.springframework.beans.PropertyValues;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.TypedStringValue;\nimport org.springframework.core.type.MethodMetadata;\nimport org.springframework.core.type.StandardMethodMetadata;\n\n/**\n * Spring Compatibility Utils for spring 3.x/4.x/5.x/6.x\n */\npublic class SpringCompatUtils {\n\n    private static volatile Boolean factoryMethodMetadataEnabled = null;\n\n    private static final Log logger = LogFactory.getLog(SpringCompatUtils.class);\n\n    public static <T> T getPropertyValue(PropertyValues pvs, String propertyName) {\n        PropertyValue pv = pvs.getPropertyValue(propertyName);\n        Object val = pv != null ? pv.getValue() : null;\n        if (val instanceof TypedStringValue) {\n            TypedStringValue typedString = (TypedStringValue) val;\n            return (T) typedString.getValue();\n        }\n        return (T) val;\n    }\n\n    public static boolean isFactoryMethodMetadataEnabled() {\n        if (factoryMethodMetadataEnabled == null) {\n            try {\n                // check AnnotatedBeanDefinition.getFactoryMethodMetadata() since spring 4.1\n                AnnotatedBeanDefinition.class.getMethod(\"getFactoryMethodMetadata\");\n\n                // check MethodMetadata.getReturnTypeName() since spring 4.2\n                MethodMetadata.class.getMethod(\"getReturnTypeName\");\n\n                factoryMethodMetadataEnabled = true;\n            } catch (NoSuchMethodException e) {\n                factoryMethodMetadataEnabled = false;\n            }\n        }\n        return factoryMethodMetadataEnabled;\n    }\n\n    public static String getFactoryMethodReturnType(AnnotatedBeanDefinition annotatedBeanDefinition) {\n        try {\n            if (isFactoryMethodMetadataEnabled()) {\n                MethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();\n                return factoryMethodMetadata != null ? factoryMethodMetadata.getReturnTypeName() : null;\n            } else {\n                Object source = annotatedBeanDefinition.getSource();\n                if (source instanceof StandardMethodMetadata) {\n                    StandardMethodMetadata methodMetadata = (StandardMethodMetadata) source;\n                    Method introspectedMethod = methodMetadata.getIntrospectedMethod();\n                    if (introspectedMethod != null) {\n                        return introspectedMethod.getReturnType().getName();\n                    }\n                }\n            }\n        } catch (Throwable e) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"get return type of AnnotatedBeanDefinition failed\", e);\n            }\n        }\n        return null;\n    }\n\n    public static MethodMetadata getFactoryMethodMetadata(AnnotatedBeanDefinition annotatedBeanDefinition) {\n        if (isFactoryMethodMetadataEnabled()) {\n            return annotatedBeanDefinition.getFactoryMethodMetadata();\n        } else {\n            Object source = annotatedBeanDefinition.getSource();\n            if (source instanceof StandardMethodMetadata) {\n                return (MethodMetadata) source;\n            }\n            return null;\n        }\n    }\n\n    /**\n     * Get the generic type of return type of the method.\n     *\n     * <pre>\n     *  Source method:\n     *  ReferenceBean&lt;DemoService> demoService()\n     *\n     *  Result: DemoService.class\n     * </pre>\n     *\n     * @param factoryMethodMetadata\n     * @return\n     */\n    public static Class getGenericTypeOfReturnType(MethodMetadata factoryMethodMetadata) {\n        if (factoryMethodMetadata instanceof StandardMethodMetadata) {\n            Method introspectedMethod = ((StandardMethodMetadata) factoryMethodMetadata).getIntrospectedMethod();\n            Type returnType = introspectedMethod.getGenericReturnType();\n            if (returnType instanceof ParameterizedType) {\n                ParameterizedType parameterizedType = (ParameterizedType) returnType;\n                Type actualTypeArgument = parameterizedType.getActualTypeArguments()[0];\n                if (actualTypeArgument instanceof Class) {\n                    return (Class) actualTypeArgument;\n                }\n            }\n        }\n        return null;\n    }\n\n    public static Class<?> referenceAnnotationBeanPostProcessor() {\n        try {\n            return Class.forName(\n                    \"org.apache.dubbo.config.spring6.beans.factory.annotation.ReferenceAnnotationWithAotBeanPostProcessor\");\n        } catch (ClassNotFoundException e) {\n            return ReferenceAnnotationBeanPostProcessor.class;\n        }\n    }\n\n    public static Class<?> serviceAnnotationPostProcessor() {\n        try {\n            return Class.forName(\n                    \"org.apache.dubbo.config.spring6.beans.factory.annotation.ServiceAnnotationWithAotPostProcessor\");\n        } catch (ClassNotFoundException e) {\n            return ServiceAnnotationPostProcessor.class;\n        }\n    }\n\n    public static Class<?> dubboInfraBeanRegisterPostProcessor() {\n        try {\n            return Class.forName(\"org.apache.dubbo.config.spring6.context.DubboInfraBeanRegisterPostProcessor\");\n        } catch (ClassNotFoundException e) {\n            return DubboInfraBeanRegisterPostProcessor.class;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/SpringParameterNameReader.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.ParameterNameReader;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\n\nimport org.springframework.core.DefaultParameterNameDiscoverer;\nimport org.springframework.core.ParameterNameDiscoverer;\n\n@Activate(onClass = \"org.springframework.core.DefaultParameterNameDiscoverer\")\npublic class SpringParameterNameReader implements ParameterNameReader {\n\n    private final ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();\n\n    @Override\n    public String[] readParameterNames(Method method) {\n        return discoverer.getParameterNames(method);\n    }\n\n    @Override\n    public String[] readParameterNames(Constructor<?> ctor) {\n        return discoverer.getParameterNames(ctor);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/WrapperUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * The utilities class for wrapper interfaces\n *\n */\npublic abstract class WrapperUtils {\n\n    /**\n     * Unwrap {@link BeanFactory} to {@link ConfigurableListableBeanFactory}\n     *\n     * @param beanFactory {@link ConfigurableListableBeanFactory}\n     * @return {@link ConfigurableListableBeanFactory}\n     * @throws IllegalArgumentException If <code>beanFactory</code> argument is not an instance of {@link ConfigurableListableBeanFactory}\n     */\n    public static ConfigurableListableBeanFactory unwrap(BeanFactory beanFactory) throws IllegalArgumentException {\n        Assert.isInstanceOf(\n                ConfigurableListableBeanFactory.class,\n                beanFactory,\n                \"The 'beanFactory' argument is not an instance of ConfigurableListableBeanFactory, \"\n                        + \"is it running in Spring container?\");\n        return ConfigurableListableBeanFactory.class.cast(beanFactory);\n    }\n\n    /**\n     * Unwrap {@link Environment} to {@link ConfigurableEnvironment}\n     *\n     * @param environment {@link Environment}\n     * @return {@link ConfigurableEnvironment}\n     * @throws IllegalArgumentException If <code>environment</code> argument is not an instance of {@link ConfigurableEnvironment}\n     */\n    public static ConfigurableEnvironment unwrap(Environment environment) throws IllegalArgumentException {\n        Assert.isInstanceOf(\n                ConfigurableEnvironment.class,\n                environment,\n                \"The 'environment' argument is not a instance of ConfigurableEnvironment, \"\n                        + \"is it running in Spring container?\");\n        return (ConfigurableEnvironment) environment;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n            xmlns:beans=\"http://www.springframework.org/schema/beans\"\n            xmlns:tool=\"http://www.springframework.org/schema/tool\"\n            xmlns=\"http://code.alibabatech.com/schema/dubbo\"\n            targetNamespace=\"http://code.alibabatech.com/schema/dubbo\">\n\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\"/>\n    <xsd:import namespace=\"http://www.springframework.org/schema/beans\"\n                schemaLocation=\"http://www.springframework.org/schema/beans/spring-beans.xsd\"/>\n    <xsd:import namespace=\"http://www.springframework.org/schema/tool\"/>\n\n    <xsd:annotation>\n        <xsd:documentation>\n            <![CDATA[ Namespace support for the dubbo services provided by dubbo framework. ]]></xsd:documentation>\n    </xsd:annotation>\n\n    <xsd:complexType name=\"abstractMethodType\">\n        <xsd:attribute name=\"timeout\" type=\"xsd:string\" default=\"0\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The method invoke timeout. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"retries\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The method retry times. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"failbacktasks\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The max failback tasks capacity size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"actives\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The max active requests. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"loadbalance\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The method load balance. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"async\" type=\"xsd:string\" default=\"false\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The method does async. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"sent\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The async method return await message sent ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"mock\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Use service mock implementation. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"merger\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The multi-group result merger ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"validation\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Use service jsr303 validation, true/false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"cache\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Use service cache, lru/threadlocal/jcache. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"abstractInterfaceType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractMethodType\">\n                <xsd:attribute name=\"id\" type=\"xsd:ID\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"local\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Use service local implementation. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"stub\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Use service local implementation. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"proxy\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Use proxy factory. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"cluster\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Use cluster strategy. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"forks\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ ForkingCluster forks. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"filter\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The filter. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"listener\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The listener. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"owner\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The owner. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"layer\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ layer info. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"application\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service application. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"module\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service module. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"registry\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service registry. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"monitor\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service monitor. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"callbacks\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The callback instance limit peer connection.]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"onconnect\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service client connected. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"ondisconnect\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service client disconnected. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"scope\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Defines the service visibility, choise:[local remote]. default is remote, which can be invoked by network。  ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"tag\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Defines the service tag]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"connections\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The exclusive connections. default share one connection. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"abstractReferenceType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractInterfaceType\">\n                <xsd:attribute name=\"version\" type=\"xsd:string\" default=\"0.0.0\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service version. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"group\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service group. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"check\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Check dependency providers. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"init\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Eager init reference. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"generic\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Generic service. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"injvm\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[Deprecated. Replace to  set scope=local ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"sticky\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Enable/Disable cluster sticky policy.Default false ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"reconnect\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ remoting reconnect timer. false represent close reconnect. integer represent interval(ms) .default true(2000ms).]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"lazy\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ lazy create connection. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"provided-by\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ declares which app or service this interface belongs to. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"provider-port\" type=\"xsd:integer\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ declares provider service port. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"provider-namespace\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ assign namespace that the provider belong to when mesh enable. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"router\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The routers ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"abstractServiceType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractInterfaceType\">\n                <xsd:attribute name=\"register\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service can be register to registry. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"version\" type=\"xsd:string\" default=\"0.0.0\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service version. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"group\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service group. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"deprecated\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ whether the service is deprecated. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"delay\" type=\"xsd:string\" default=\"0\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service export delay millisecond. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"export\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service is export. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"weight\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service weight. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"document\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service document. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"dynamic\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ the service registered to the registry is dynamic(true) or static(false). ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"token\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service use token. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"accesslog\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service use accesslog. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"executes\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service allow execute requests. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service protocol. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"warmup\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The warmup time in Milliseconds. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"serialization\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The serialization protocol of service. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"executor\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Bean name of service executor(thread pool), used for thread pool isolation between services. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"applicationType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"version\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application version. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"owner\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application owner name (email prefix). ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"organization\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The organization name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"architecture\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The architecture. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"environment\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application environment, eg: dev/test/run ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"compiler\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The java code compiler. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"logger\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application logger. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"registry\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application registry. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"monitor\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application monitor. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"shutwait\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application shutDown-wait time. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"default\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"metadata-type\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metadata type: local or remote. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"register-consumer\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Register consumer instance or not, default false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"register-mode\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Register interface/instance/all addresses to registry, default all. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"enable-empty-protection\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Enable empty protection on empty address notification, default true. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The preferred protocol to use, set protocol name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"executor-management-mode\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Thread pool management: default/isolation. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"dump-directory\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The file path directory of the saving thread dump. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"dump-enable\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Saving thread dump or not, default true. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"moduleType\">\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"version\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module version. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"owner\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module owner name (email prefix). ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"organization\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module organization. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"registry\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module registry. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"monitor\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module monitor. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"default\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"registryType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"address\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry address. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"port\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry default port. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry lookup protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"username\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry username. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"password\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry password. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"transport\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol transporter type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"transporter\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol transporter type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol server type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol client type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"cluster\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry cluster type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"zone\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry zone type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"forks\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ ForkingCluster forks. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"group\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry group. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"version\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry version. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"timeout\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The request timeout. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"session\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The session timeout. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"file\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry address file store. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"wait\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The wait time for shutdown. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"check\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Check registry status on startup. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"dynamic\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ the service registered to this registry is dynamic(true) or static(false). ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"register\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ register service to this registry(true) or not(false). ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"subscribe\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ subscribe service to this registry(true) or not(false). ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"default\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"simplified\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is simple. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"extra-keys\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Extra Parameter Keys. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"use-as-config-center\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ work as config center or not. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"use-as-metadata-center\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ work as metadata center or not. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"accepts\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ list of rpc protocols accepted by this registry, separated with \",\". ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"preferred\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is this registry the preferred one. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"weight\" type=\"xsd:integer\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ weight of registry. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"register-mode\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Register interface/instance/all addresses to registry, default all. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"enable-empty-protection\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Enable empty protection on empty address notification, default true. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"metadataReportType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"address\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metadataReport address. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"username\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metadataReport username. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"password\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metadataReport password. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"timeout\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The request timeout. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"group\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The group of metadata-report. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"retry-times\" type=\"xsd:integer\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ if fail, retry times. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"retry-period\" type=\"xsd:integer\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ if fail, retry period. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"cycle-report\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ report cyclely. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"sync-report\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Sync or Async report. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"cluster\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Need cluster support, default false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"registry\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ registry config id. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"report-metadata\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Whether to report metadata to remote center, default is false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"report-definition\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Whether to report service definition to remote center, default is true. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"configCenterType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The config center protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"address\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The config center address. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"cluster\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The config center cluster, it's real meaning may very on different Config Center products. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"namespace\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The namespace of the config center, generally it's used for multi-tenant, but it's real meaning depends on the actual Config Center you use. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"group\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The group of the config center, generally it's used to identify an isolated space for a batch of config items, but it's real meaning depends on the actual Config Center you use.. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"config-file\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The key used to get the configs at startup. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"app-config-file\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The key used to get the configs at startup. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"username\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The username for AUTH. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"password\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The password for AUTH. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"timeout\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The request timeout. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"highest-priority\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Deprecated. Whether the configs from config center has the highest priority. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"include-spring-env\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Load the config items by Dubbo itself or Spring. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"check\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The policy to apply when connecting to config center fails. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"monitorType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"address\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor address. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"username\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor username. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"password\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor password. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"group\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor group. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"version\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor version. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"interval\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor interval. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"default\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"parameterType\">\n        <xsd:attribute name=\"key\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The parameter key. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"value\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The parameter value. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"hide\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Hide parameter. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"metricsType\">\n        <xsd:attribute name=\"port\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metrics service port. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metrics service protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"methodType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractMethodType\">\n                <xsd:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xsd:element ref=\"argument\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                </xsd:choice>\n                <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The method name (method.toString()). ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"executes\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The max active requests. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"stat\" type=\"xsd:string\" default=\"-1\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The method parameter index for statistics. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"retry\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Deprecated. Replace to retries. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"reliable\" type=\"xsd:string\" default=\"false\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Deprecated. Replace to napoli protocol. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"deprecated\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The method deprecated. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"sticky\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Enable/Disable cluster sticky policy.Default false ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"return\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Method result is return. default is true.]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"oninvoke\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Method invoke trigger.]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"onreturn\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Method return trigger. return attribute must be true.]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"onthrow\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Method on error trigger.return attribute must be true.]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"argumentType\">\n        <xsd:attribute name=\"index\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The argument index. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"type\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The argument type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"callback\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The argument is callback. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"consumerType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractReferenceType\">\n                <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xsd:element ref=\"reference\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                </xsd:sequence>\n                <xsd:attribute name=\"default\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"client\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Transporter layer framework: netty mina.... ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"threadpool\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Consumer threadpool: cached, fixed, limited, eager]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"corethreads\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool core threads size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"threads\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"queues\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool queue size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"mesh-enable\" type=\"xsd:boolean\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Enable mesh mode. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"referenceType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractReferenceType\">\n                <xsd:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xsd:element ref=\"method\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                </xsd:choice>\n                <xsd:attribute name=\"interface\" type=\"xsd:token\" use=\"required\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service interface class name. ]]></xsd:documentation>\n                        <xsd:appinfo>\n                            <tool:annotation>\n                                <tool:expected-type type=\"java.lang.Class\"/>\n                            </tool:annotation>\n                        </xsd:appinfo>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"url\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Provider list url. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"client\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Protocol transport client type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"consumer\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Deprecated. Replace to reference-default. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service protocol. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"unloadClusterRelated\" type=\"xsd:boolean\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ In the mesh mode, uninstall the directory, router and load balance related to the cluster in the currently invoked invoker.\n                            Delegate retry, load balancing, timeout and other traffic management capabilities to Sidecar. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"protocolType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"host\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The service host. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"port\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The service port. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"threadpool\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"threadname\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"thread-pool-exhausted-listeners\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool exhausted listeners. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"threads\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"corethreads\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool core threads size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"iothreads\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The IO thread pool size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"alive\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool keepAliveTime. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"queues\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool queue size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"accepts\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The accept connection size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"codec\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol codec. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"serialization\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol serialization. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"keepalive\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol keepAlive. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"optimizer\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The serialization optimizer. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"extension\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The extension for protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"charset\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol charset. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"payload\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The max payload. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"buffer\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The buffer size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"heartbeat\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The heartbeat interval.(ms) ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"accesslog\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol use accesslog. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"telnet\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol use telnet commands. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"prompt\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol telnet prompt. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"status\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol check status. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"transporter\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol transporter type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"exchanger\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol exchanger type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"dispather\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Deprecated. replace to \"dispatcher\". ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"dispatcher\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol dispatcher type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"networker\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol \"networker\" type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol server type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol client type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The protocol context path. replace to \"contextpath\". ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"contextpath\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol context path. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"register\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol can be register to registry. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"default\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"ssl-enabled\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is SSL enabled. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"preferred-protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Tell consumer the preferred protocol to consume. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"providerType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractServiceType\">\n                <xsd:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xsd:element ref=\"service\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                </xsd:choice>\n                <xsd:attribute name=\"host\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service host. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"port\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service port. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"threadpool\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"threadname\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool name. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"threads\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"iothreads\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The IO thread pool size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"alive\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool keepAliveTime. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"queues\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool queue size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"accepts\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The accept connection size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"codec\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol codec. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"charset\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol charset. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"payload\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The max payload. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"buffer\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The buffer size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"transporter\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol transporter type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"exchanger\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol exchanger type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"dispather\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Deprecated. replace to \"dispatcher\". ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"dispatcher\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol dispatcher type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"networker\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol \"networker\" type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"server\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol server type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"client\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol client type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"telnet\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol use telnet commands. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"prompt\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol telnet prompt. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"status\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol check status. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"path\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The protocol context path. replace to \"contextpath\". ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"contextpath\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol context path. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"wait\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The provider shutdown wait time. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"default\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"serviceType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractServiceType\">\n                <xsd:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xsd:element ref=\"method\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"beans:property\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                </xsd:choice>\n                <xsd:attribute name=\"interface\" type=\"xsd:token\" use=\"required\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Defines the interface to advertise for this service in the service registry. ]]></xsd:documentation>\n                        <xsd:appinfo>\n                            <tool:annotation>\n                                <tool:expected-type type=\"java.lang.Class\"/>\n                            </tool:annotation>\n                        </xsd:appinfo>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"ref\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service implementation instance bean id. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"class\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service implementation class name. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"path\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service path. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"provider\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Deprecated. Replace to protocol. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"generic\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Generic service. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"sslType\">\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server-key-cert-chain-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The server cert. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server-private-key-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The server key. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server-key-password\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The server key. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server-trust-cert-collection-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The trusted server cert. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client-key-cert-chain-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The client cert. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client-private-key-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The client key. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client-key-password\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The client key pwd. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client-trust-cert-collection-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The trusted client cert. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:element name=\"ssl\" type=\"sslType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The ssl config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.SslConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"application\" type=\"applicationType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The application config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ApplicationConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"module\" type=\"moduleType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The module config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ModuleConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"registry\" type=\"registryType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The registry config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.RegistryConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"metadata-report\" type=\"metadataReportType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The metadataReport config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.MetadataReportConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"config-center\" type=\"configCenterType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The config center config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ConfigCenterConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"monitor\" type=\"monitorType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The logstat monitor config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.MonitorConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"provider\" type=\"providerType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ Export service default config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ProviderConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"consumer\" type=\"consumerType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ Service reference default config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ConsumerConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"protocol\" type=\"protocolType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ Service provider config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ProtocolConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"service\" type=\"serviceType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ Export service config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ServiceConfigBase\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"reference\" type=\"referenceType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ Reference service config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ReferenceConfigBase\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"method\" type=\"methodType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The service method config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.MethodConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"argument\" type=\"argumentType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The service argument config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ArgumentConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"parameter\" type=\"parameterType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The service url parameter ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"metrics\" type=\"metricsType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The metrics service ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.MetricsConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n</xsd:schema>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector",
    "content": "spring=org.apache.dubbo.config.spring.extension.SpringExtensionInjector\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.status.StatusChecker",
    "content": "spring=org.apache.dubbo.config.spring.status.SpringStatusChecker\ndatasource=org.apache.dubbo.config.spring.status.DataSourceStatusChecker"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader",
    "content": "spring=org.apache.dubbo.config.spring.util.SpringParameterNameReader\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.bootstrap.DubboBootstrapStartStopListener",
    "content": "default=org.apache.dubbo.config.spring.context.DubboBootstrapStartStopListenerSpringAdapter"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "dubbo-config-spring=org.apache.dubbo.config.spring.SpringScopeModelInitializer\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n            xmlns:beans=\"http://www.springframework.org/schema/beans\"\n            xmlns:tool=\"http://www.springframework.org/schema/tool\"\n            xmlns=\"http://dubbo.apache.org/schema/dubbo\"\n            targetNamespace=\"http://dubbo.apache.org/schema/dubbo\">\n\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\"/>\n    <xsd:import namespace=\"http://www.springframework.org/schema/beans\"\n                schemaLocation=\"http://www.springframework.org/schema/beans/spring-beans.xsd\"/>\n    <xsd:import namespace=\"http://www.springframework.org/schema/tool\"/>\n\n    <xsd:annotation>\n        <xsd:documentation>\n            <![CDATA[ Namespace support for the dubbo services provided by dubbo framework. ]]></xsd:documentation>\n    </xsd:annotation>\n\n    <xsd:complexType name=\"abstractMethodType\">\n        <xsd:attribute name=\"timeout\" type=\"xsd:string\" default=\"0\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The method invoke timeout. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"retries\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The method retry times. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"failbacktasks\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The max failback tasks capacity size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"actives\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The max active requests. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"loadbalance\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The method load balance. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"async\" type=\"xsd:string\" default=\"false\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The method does async. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"sent\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The async method return await message sent ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"mock\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Use service mock implementation. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"merger\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The multi-group result merger ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"validation\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Use service jsr303 validation, true/false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"cache\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Use service cache, lru/threadlocal/jcache. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"abstractInterfaceType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractMethodType\">\n                <xsd:attribute name=\"id\" type=\"xsd:ID\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"local\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Use service local implementation. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"stub\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Use service local implementation. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"proxy\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Use proxy factory. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"cluster\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Use cluster strategy. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"forks\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ ForkingCluster forks. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"filter\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The filter. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"listener\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The listener. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"owner\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The owner. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"layer\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ layer info. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"application\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service application. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"module\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service module. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"registry\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service registry. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"monitor\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service monitor. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"callbacks\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The callback instance limit peer connection.]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"onconnect\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service client connected. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"ondisconnect\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service client disconnected. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"scope\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Defines the service visibility, choise:[local remote]. default is remote, which can be invoked by network。  ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"tag\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Defines the service tag]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"connections\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The exclusive connections. default share one connection. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"abstractReferenceType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractInterfaceType\">\n                <xsd:attribute name=\"version\" type=\"xsd:string\" default=\"0.0.0\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service version. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"group\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service group. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"check\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Check dependency providers. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"init\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Eager init reference. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"generic\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Generic service. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"injvm\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[Deprecated. Replace to  set scope=local ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"sticky\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Enable/Disable cluster sticky policy.Default false ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"reconnect\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ remoting reconnect timer. false represent close reconnect. integer represent interval(ms) .default true(2000ms).]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"lazy\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ lazy create connection. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"provided-by\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ declares which app or service this interface belongs to. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"provider-port\" type=\"xsd:integer\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ declares provider service port. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"provider-namespace\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ assign namespace that the provider belong to when mesh enable. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"router\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The routers ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"refer-async\" type=\"xsd:boolean\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Weather the reference is refer asynchronously, default false. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"abstractServiceType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractInterfaceType\">\n                <xsd:attribute name=\"register\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service can be register to registry. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"version\" type=\"xsd:string\" default=\"0.0.0\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service version. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"group\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service group. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"deprecated\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ whether the service is deprecated. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"delay\" type=\"xsd:string\" default=\"0\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service export delay millisecond. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"export\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service is export. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"weight\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service weight. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"document\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service document. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"dynamic\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ the service registered to the registry is dynamic(true) or static(false). ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"token\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service use token. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"accesslog\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service use accesslog. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"executes\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service allow execute requests. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service protocol. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"warmup\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The warmup time in Milliseconds. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"serialization\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The serialization protocol of service. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"prefer-serialization\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The prefer serialization protocol of service, multiple serialization protocol are separated by commas, default fastjson2,hessian2. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"export-async\" type=\"xsd:boolean\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Weather the service is export asynchronously, default false. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"executor\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Bean name of service executor(thread pool), used for thread pool isolation between services. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"payload\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The max payload. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"applicationType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"version\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application version. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"owner\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application owner name (email prefix). ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"organization\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The organization name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"architecture\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The architecture. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"environment\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application environment, eg: dev/test/run ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"compiler\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The java code compiler. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"logger\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application logger. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"registry\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application registry. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"monitor\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The application monitor. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"default\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"metadata-type\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metadata type: local or remote. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"register-consumer\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Register consumer instance or not, default false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"register-mode\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Register interface/instance/all addresses to registry, default all. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"enable-empty-protection\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Enable empty protection on empty address notification, default true. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The preferred protocol to use, set protocol name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"executor-management-mode\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Thread pool management: default/isolation. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"dump-directory\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The file path directory of the saving thread dump. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"dump-enable\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Saving thread dump or not, default true. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"mapping-retry-interval\" type=\"xsd:integer\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The retry interval of service name mapping. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"serialize-check-status\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The check level of serialize check. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"auto-trust-serialize-class\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Whether trust class for serialization by scanning. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"trust-serialize-class-level\" type=\"xsd:integer\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The trust package level of serialize class scanning. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"check-serializable\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Whether restrict the serialized should implement Serializable interface. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"qos-enable\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Whether to enable qos or not. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"qos-check\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Whether qos should start success or not, will check qosEnable first. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"qos-host\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The qos host to listen. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"qos-port\" type=\"xsd:integer\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The qos host to listen. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"qos-accept-foreign-ip\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Whether to accept foreign ip. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"qos-accept-foreign-ip-whitelist\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Support specifying foreign ip in whitelist when accepting foreign ip is disabled. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"qos-anonymous-access-permission-level\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Anonymous (any foreign ip) access level, the default is NONE, can not access any cmd. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"qos-anonymous-allow-commands\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Anonymous(any foreign ip) allow commands, default is empty, can not access any cmd. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"moduleType\">\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"version\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module version. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"owner\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module owner name (email prefix). ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"organization\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module organization. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"registry\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module registry. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"monitor\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The module monitor. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"default\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"background\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Whether start module in background, if true do not await finish. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"refer-async\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Weather the reference is refer asynchronously, default false.  ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"refer-thread-num\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Thread num for asynchronous refer pool size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"export-async\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Weather the service is export asynchronously, default false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"export-thread-num\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Thread num for asynchronous export pool size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"check-reference-timeout\" type=\"xsd:long\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The timeout to check references. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"registryType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"address\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry address. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"port\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry default port. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry lookup protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"username\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry username. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"password\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry password. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"transport\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol transporter type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"transporter\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol transporter type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol server type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol client type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"cluster\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry cluster type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"zone\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry zone type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"forks\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ ForkingCluster forks. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"group\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry group. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"version\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry version. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"timeout\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The request timeout. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"session\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The session timeout. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"file\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry address file store. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"wait\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The wait time for shutdown. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"check\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Check registry status on startup. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"dynamic\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ the service registered to this registry is dynamic(true) or static(false). ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"register\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ register service to this registry(true) or not(false). ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"subscribe\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ subscribe service to this registry(true) or not(false). ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"default\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"simplified\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is simple. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"extra-keys\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Extra Parameter Keys. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"use-as-config-center\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ work as config center or not. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"use-as-metadata-center\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ work as metadata center or not. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"accepts\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ list of rpc protocols accepted by this registry, separated with \",\". ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"preferred\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is this registry the preferred one. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"weight\" type=\"xsd:integer\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ weight of registry. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"register-mode\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Register interface/instance/all addresses to registry, default all. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"enable-empty-protection\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Enable empty protection on empty address notification, default true. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"secure\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ list of rpc protocols accepted by this registry, separated with \",\". ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"metadataReportType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The config center protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"address\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metadataReport address. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"port\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The registry default port. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"username\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metadataReport username. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"password\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metadataReport password. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"timeout\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The request timeout. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"group\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The group of metadata-report. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"retry-times\" type=\"xsd:integer\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ if fail, retry times. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"retry-period\" type=\"xsd:integer\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ if fail, retry period. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"cycle-report\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ report cyclely. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"sync-report\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Sync or Async report. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"cluster\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Need cluster support, default false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"registry\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ registry config id. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"file\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metadata report file store. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"check\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The policy to apply when connecting to metadata center fails. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"report-metadata\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Whether to report metadata to remote center, default is false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"report-definition\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Whether to report service definition to remote center, default is true. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"configCenterType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The config center protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"address\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The config center address. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"cluster\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The config center cluster, it's real meaning may very on different Config Center products. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"namespace\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The namespace of the config center, generally it's used for multi-tenant, but it's real meaning depends on the actual Config Center you use. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"group\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The group of the config center, generally it's used to identify an isolated space for a batch of config items, but it's real meaning depends on the actual Config Center you use. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"config-file\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The key used to get the configs at startup. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"app-config-file\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The key used to get the configs at startup. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"username\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The username for AUTH. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"password\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The password for AUTH. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"timeout\" type=\"xsd:string\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The request timeout. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"highest-priority\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Deprecated. Whether the configs from config center has the highest priority. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"include-spring-env\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Load the config items by Dubbo itself or Spring. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"check\" type=\"xsd:boolean\" use=\"optional\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The policy to apply when connecting to config center fails. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"monitorType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n        </xsd:sequence>\n        <xsd:attribute name=\"address\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor address. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"username\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor username. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"password\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor password. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"group\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor group. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"version\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor version. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"interval\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The monitor interval. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"default\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"parameterType\">\n        <xsd:attribute name=\"key\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The parameter key. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"value\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The parameter value. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"hide\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Hide parameter. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"metricsType\">\n        <xsd:all>\n            <xsd:element ref=\"prometheus-exporter\" minOccurs=\"0\"/>\n            <xsd:element ref=\"prometheus-pushgateway\" minOccurs=\"0\"/>\n            <xsd:element ref=\"aggregation\" minOccurs=\"0\"/>\n            <xsd:element ref=\"histogram\" minOccurs=\"0\"/>\n        </xsd:all>\n        <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The metrics protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"enable-jvm\" type=\"xsd:boolean\" default=\"false\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable jvm metrics when collecting. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"enable-threadpool\" type=\"xsd:boolean\" default=\"true\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable threadpool metrics when collecting. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"enable-registry\" type=\"xsd:boolean\" default=\"true\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable registry metrics when collecting. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"enable-metadata\" type=\"xsd:boolean\" default=\"true\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable metadata metrics when collecting. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"enable-netty\" type=\"xsd:boolean\" default=\"true\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable netty metrics when collecting. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"export-metrics-service\" type=\"xsd:boolean\" default=\"true\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable export metrics service. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"enable-rpc\" type=\"xsd:boolean\" default=\"true\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable record rpc metrics. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"rpc-level\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is the metric for rpc requests at the METHOD level or SERVICE level ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"tracingType\">\n        <xsd:all>\n            <xsd:element ref=\"sampling\" minOccurs=\"0\"/>\n            <xsd:element ref=\"propagation\" minOccurs=\"0\"/>\n            <xsd:element ref=\"baggage\" minOccurs=\"0\"/>\n        </xsd:all>\n        <xsd:attribute name=\"enabled\" type=\"xsd:boolean\" default=\"false\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable tracing. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"tripleType\">\n        <xsd:attribute name=\"max-body-size\" type=\"xsd:integer\" default=\"8388608\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Maximum allowed size for HTTP1 request bodies. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"max-response-body-size\" type=\"xsd:integer\" default=\"8388608\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Maximum allowed size for HTTP1 response bodies. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"max-chunk-size\" type=\"xsd:integer\" default=\"8388608\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Set the maximum chunk size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"max-header-size\" type=\"xsd:integer\" default=\"8192\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Set the maximum line length of header lines. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"max-initial-line-length\" type=\"xsd:integer\" default=\"4096\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Set the maximum length of the first line of the HTTP header. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"initial-buffer-size\" type=\"xsd:integer\" default=\"16384\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Set the initial size of the temporary buffer used when parsing the lines of the HTTP headers. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"header-table-size\" type=\"xsd:integer\" default=\"4096\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The header table size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"enable-push\" type=\"xsd:boolean\" default=\"false\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Whether to enable push, default is false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"max-concurrent-streams\" type=\"xsd:integer\" default=\"2147483647\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Maximum concurrent streams ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"initial-window-size\" type=\"xsd:integer\" default=\"8388608\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Whether to enable push, default is false. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"max-frame-size\" type=\"xsd:integer\" default=\"8388608\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Maximum concurrent streams ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n\n        <xsd:attribute name=\"max-header-list-size\" type=\"xsd:integer\" default=\"32768\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Maximum header list size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"prometheusExporterType\">\n        <xsd:attribute name=\"enabled\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable prometheus exporter. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"enable-http-service-discovery\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable http service discovery for prometheus. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"http-service-discovery-url\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Http service discovery url. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"prometheusPushgatewayType\">\n        <xsd:attribute name=\"enabled\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable publishing via a Prometheus Pushgateway. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"base-url\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Base URL for the Pushgateway. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"username\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Login user of the Prometheus Pushgateway. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"password\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Login password of the Prometheus Pushgateway. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"push-interval\" type=\"xsd:integer\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Frequency with which to push metrics. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"job\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Job identifier for this application instance. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"aggregationType\">\n        <xsd:attribute name=\"enabled\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable local aggregation or not. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"bucket-num\" type=\"xsd:integer\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Bucket num for time window quantile. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"time-window-seconds\" type=\"xsd:integer\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Time window seconds for time window quantile. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n\n    <xsd:complexType name=\"histogramType\">\n        <xsd:attribute name=\"enabled\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable local rt histogram or not. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"samplingType\">\n        <xsd:attribute name=\"probability\" type=\"xsd:float\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Probability in the range from 0.0 to 1.0 that a trace will be sampled. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"propagationType\">\n        <xsd:attribute name=\"type\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Tracing context propagation type, include W3C and B3. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"baggageType\">\n        <xsd:all>\n            <xsd:element ref=\"remoteFields\" minOccurs=\"0\"/>\n            <xsd:element ref=\"correlation\" minOccurs=\"0\"/>\n        </xsd:all>\n        <xsd:attribute name=\"enabled\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Enable baggage or not. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"correlationType\">\n        <xsd:all>\n            <xsd:element ref=\"fields\" minOccurs=\"0\"/>\n        </xsd:all>\n        <xsd:attribute name=\"enabled\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Whether to enable correlation of the baggage context with logging contexts. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"fieldsType\">\n        <xsd:simpleContent>\n            <xsd:extension base=\"xsd:string\">\n                <xsd:attribute name=\"name\" type=\"xsd:string\"/>\n            </xsd:extension>\n        </xsd:simpleContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"tracingExporterType\">\n        <xsd:all>\n            <xsd:element ref=\"zipkin-config\" minOccurs=\"0\"/>\n        </xsd:all>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"zipkinConfigType\">\n        <xsd:attribute name=\"endpoint\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The url of zipkin server. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"connectTimeout\" type=\"xsd:duration\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Connection timeout for requests to Zipkin. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"readTimeout\" type=\"xsd:duration\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ Read timeout for requests to Zipkin. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"methodType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractMethodType\">\n                <xsd:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xsd:element ref=\"argument\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                </xsd:choice>\n                <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The method name (method.toString()). ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"executes\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The max active requests. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"stat\" type=\"xsd:string\" default=\"-1\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The method parameter index for statistics. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"retry\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Deprecated. Replace to retries. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"reliable\" type=\"xsd:string\" default=\"false\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Deprecated. Replace to napoli protocol. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"deprecated\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The method deprecated. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"sticky\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Enable/Disable cluster sticky policy.Default false ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"return\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Method result is return. default is true.]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"oninvoke\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Method invoke trigger.]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"onreturn\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Method return trigger. return attribute must be true.]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"onthrow\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Method on error trigger.return attribute must be true.]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"argumentType\">\n        <xsd:attribute name=\"index\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The argument index. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"type\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The argument type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"callback\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The argument is callback. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"consumerType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractReferenceType\">\n                <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xsd:element ref=\"reference\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                </xsd:sequence>\n                <xsd:attribute name=\"default\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"client\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Transporter layer framework: netty mina.... ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"threadpool\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Consumer threadpool: cached, fixed, limited, eager]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"corethreads\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool core threads size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"threads\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"queues\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool queue size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"shareconnections\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The default share connections. default share one connection. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"url-merge-processor\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The Url merge processor. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"refer-thread-num\" type=\"xsd:integer\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Thread num for asynchronous refer pool size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"refer-background\" type=\"xsd:boolean\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Whether refer should run in background or not, default false. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"mesh-enable\" type=\"xsd:boolean\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Enable mesh mode. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"referenceType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractReferenceType\">\n                <xsd:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xsd:element ref=\"method\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                </xsd:choice>\n                <xsd:attribute name=\"interface\" type=\"xsd:token\" use=\"required\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service interface class name. ]]></xsd:documentation>\n                        <xsd:appinfo>\n                            <tool:annotation>\n                                <tool:expected-type type=\"java.lang.Class\"/>\n                            </tool:annotation>\n                        </xsd:appinfo>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"url\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Provider list url. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"client\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Protocol transport client type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"consumer\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Deprecated. Replace to reference-default. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"protocol\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service protocol. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"services\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service names that the Dubbo interface subscribed.\n                            If it is a multiple-values, the content will be a comma-delimited String. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"unloadClusterRelated\" type=\"xsd:boolean\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ In the mesh mode, uninstall the directory, router and load balance related to the cluster in the currently invoked invoker.\n                            Delegate retry, load balancing, timeout and other traffic management capabilities to Sidecar. ]]>\n                        </xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"protocolType\">\n        <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n            <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n            <xsd:element ref=\"triple\" minOccurs=\"0\" />\n        </xsd:sequence>\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"host\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The service host. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"port\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The service port. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"ext-protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ extra protocol.]]]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"threadpool\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"threadname\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool name. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"thread-pool-exhausted-listeners\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool exhausted listeners. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"threads\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"corethreads\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool core threads size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"iothreads\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The IO thread pool size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"alive\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool keepAliveTime. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"queues\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The thread pool queue size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"accepts\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The accept connection size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"codec\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol codec. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"serialization\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol serialization. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"prefer-serialization\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The prefer serialization protocol of service, multiple serialization protocol are separated by commas, default fastjson2,hessian2. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"keepalive\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol keepAlive. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"optimizer\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The serialization optimizer. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"extension\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The extension for protocol. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"charset\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol charset. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"payload\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The max payload. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"buffer\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The buffer size. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"heartbeat\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The heartbeat interval.(ms) ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"accesslog\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol use accesslog. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"telnet\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol use telnet commands. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"prompt\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol telnet prompt. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"status\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol check status. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"transporter\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol transporter type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"exchanger\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol exchanger type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"dispather\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Deprecated. replace to \"dispatcher\". ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"dispatcher\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol dispatcher type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"networker\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol \"networker\" type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol server type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol client type. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation>\n                    <![CDATA[ The protocol context path. replace to \"contextpath\". ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"contextpath\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol context path. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"json-check-level\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The level of json compatibility check. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"register\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The protocol can be register to registry. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"default\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"ssl-enabled\" type=\"xsd:boolean\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Is SSL enabled. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"preferred-protocol\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ Tell consumer the preferred protocol to consume. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"providerType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractServiceType\">\n                <xsd:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xsd:element ref=\"service\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                </xsd:choice>\n                <xsd:attribute name=\"host\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service host. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"port\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service port. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"threadpool\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"threadname\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool name. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"threads\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"iothreads\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The IO thread pool size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"alive\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool keepAliveTime. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"queues\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The thread pool queue size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"accepts\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The accept connection size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"codec\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol codec. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"charset\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol charset. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"buffer\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The buffer size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"transporter\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol transporter type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"exchanger\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol exchanger type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"dispather\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Deprecated. replace to \"dispatcher\". ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"dispatcher\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol dispatcher type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"networker\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol \"networker\" type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"server\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol server type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"client\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol client type. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"telnet\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol use telnet commands. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"prompt\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol telnet prompt. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"status\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol check status. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"path\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The protocol context path. replace to \"contextpath\". ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"contextpath\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The protocol context path. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"wait\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The provider shutdown wait time. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"default\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"export-thread-num\" type=\"xsd:integer\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Thread num for asynchronous export pool size. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"export-background\" type=\"xsd:boolean\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Deprecated. Whether export should run in background or not, default false. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"serviceType\">\n        <xsd:complexContent>\n            <xsd:extension base=\"abstractServiceType\">\n                <xsd:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n                    <xsd:element ref=\"method\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"parameter\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                    <xsd:element ref=\"beans:property\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n                </xsd:choice>\n                <xsd:attribute name=\"interface\" type=\"xsd:token\" use=\"required\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ Defines the interface to advertise for this service in the service registry. ]]></xsd:documentation>\n                        <xsd:appinfo>\n                            <tool:annotation>\n                                <tool:expected-type type=\"java.lang.Class\"/>\n                            </tool:annotation>\n                        </xsd:appinfo>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"ref\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation>\n                            <![CDATA[ The service implementation instance bean id. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"class\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service implementation class name. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"path\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ The service path. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"provider\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Deprecated. Replace to protocol. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:attribute name=\"generic\" type=\"xsd:string\">\n                    <xsd:annotation>\n                        <xsd:documentation><![CDATA[ Generic service. ]]></xsd:documentation>\n                    </xsd:annotation>\n                </xsd:attribute>\n                <xsd:anyAttribute namespace=\"##other\" processContents=\"lax\"/>\n            </xsd:extension>\n        </xsd:complexContent>\n    </xsd:complexType>\n\n    <xsd:complexType name=\"sslType\">\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server-key-cert-chain-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The server cert. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server-private-key-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The server key. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server-key-password\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The server key. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"server-trust-cert-collection-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The trusted server cert. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client-key-cert-chain-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The client cert. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client-private-key-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The client key. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client-key-password\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The client key pwd. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"client-trust-cert-collection-path\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The trusted client cert. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:element name=\"ssl\" type=\"sslType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The ssl config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.SslConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:complexType name=\"annotationType\">\n        <xsd:attribute name=\"id\" type=\"xsd:ID\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n        <xsd:attribute name=\"package\" type=\"xsd:string\">\n            <xsd:annotation>\n                <xsd:documentation><![CDATA[ The scan package. ]]></xsd:documentation>\n            </xsd:annotation>\n        </xsd:attribute>\n    </xsd:complexType>\n\n    <xsd:element name=\"annotation\" type=\"annotationType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The annotation config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ServiceConfig\"/>\n                    <tool:exports type=\"org.apache.dubbo.config.ReferenceConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"application\" type=\"applicationType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The application config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ApplicationConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"module\" type=\"moduleType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The module config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ModuleConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"registry\" type=\"registryType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The registry config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.RegistryConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"metadata-report\" type=\"metadataReportType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The metadataReport config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.MetadataReportConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"config-center\" type=\"configCenterType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The config center config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ConfigCenterConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"monitor\" type=\"monitorType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The logstat monitor config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.MonitorConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"provider\" type=\"providerType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ Export service default config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ProviderConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"consumer\" type=\"consumerType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ Service reference default config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ConsumerConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"protocol\" type=\"protocolType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ Service provider config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ProtocolConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"service\" type=\"serviceType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ Export service config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ServiceConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"reference\" type=\"referenceType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ Reference service config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ReferenceConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"method\" type=\"methodType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The service method config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.MethodConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"argument\" type=\"argumentType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The service argument config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.ArgumentConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"parameter\" type=\"parameterType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The service url parameter ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"metrics\" type=\"metricsType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The metrics service ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.MetricsConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"tracing\" type=\"tracingType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The tracing service ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.TracingConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"triple\" type=\"tripleType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The triple config ]]></xsd:documentation>\n            <xsd:appinfo>\n                <tool:annotation>\n                    <tool:exports type=\"org.apache.dubbo.config.nested.TripleConfig\"/>\n                </tool:annotation>\n            </xsd:appinfo>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"prometheus-exporter\" type=\"prometheusExporterType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The metrics prometheus exporter config. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"prometheus-pushgateway\" type=\"prometheusPushgatewayType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The metrics prometheus pushgateway config. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"aggregation\" type=\"aggregationType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The metrics aggregation config. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"histogram\" type=\"histogramType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The metrics rt histogram config. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"sampling\" type=\"samplingType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The tracing sampling config. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"propagation\" type=\"propagationType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The tracing propagation config. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"baggage\" type=\"baggageType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The tracing baggage config. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"remoteFields\" type=\"fieldsType\">\n        <xsd:annotation>\n            <xsd:documentation>\n                <![CDATA[ The tracing baggage remoteFields config. List of fields that are referenced\n                the same in-process as it is on the wire. For example, the field \"x-vcap-request-id\" would\n                 be set as-is including the prefix. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"correlation\" type=\"correlationType\">\n        <xsd:annotation>\n            <xsd:documentation><![CDATA[ The tracing baggage correlation config. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"fields\" type=\"fieldsType\">\n        <xsd:annotation>\n            <xsd:documentation>\n                <![CDATA[ List of fields that should be correlated with the logging context. That\n                means that these fields would end up as key-value pairs in e.g. MDC. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"tracing-exporter\" type=\"tracingExporterType\">\n        <xsd:annotation>\n            <xsd:documentation>\n                <![CDATA[ Exporter of tracing. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n\n    <xsd:element name=\"zipkin-config\" type=\"zipkinConfigType\">\n        <xsd:annotation>\n            <xsd:documentation>\n                <![CDATA[ Config of zipkin exporter. ]]></xsd:documentation>\n        </xsd:annotation>\n    </xsd:element>\n</xsd:schema>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/resources/META-INF/spring.handlers",
    "content": "http\\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler\nhttp\\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/main/resources/META-INF/spring.schemas",
    "content": "http\\://dubbo.apache.org/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd\nhttp\\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/compat/dubbo.xsd"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/AbstractRegistryService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.RegistryService;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_NOTIFY_EVENT;\n\npublic abstract class AbstractRegistryService implements RegistryService {\n\n    // logger\n    protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    // registered services\n    // Map<serviceName, Map<url, queryString>>\n    private final ConcurrentMap<String, List<URL>> registered = new ConcurrentHashMap<String, List<URL>>();\n\n    // subscribed services\n    // Map<serviceName, queryString>\n    private final ConcurrentMap<String, Map<String, String>> subscribed =\n            new ConcurrentHashMap<String, Map<String, String>>();\n\n    // notified services\n    // Map<serviceName, Map<url, queryString>>\n    private final ConcurrentMap<String, List<URL>> notified = new ConcurrentHashMap<String, List<URL>>();\n\n    // notification listeners for the subscribed services\n    // Map<serviceName, List<notificationListener>>\n    private final ConcurrentMap<String, List<NotifyListener>> notifyListeners =\n            new ConcurrentHashMap<String, List<NotifyListener>>();\n\n    @Override\n    public void register(URL url) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Register service: \" + url.getServiceKey() + \",url:\" + url);\n        }\n        register(url.getServiceKey(), url);\n    }\n\n    @Override\n    public void unregister(URL url) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Unregister service: \" + url.getServiceKey() + \",url:\" + url);\n        }\n        unregister(url.getServiceKey(), url);\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Subscribe service: \" + url.getServiceKey() + \",url:\" + url);\n        }\n        subscribe(url.getServiceKey(), url, listener);\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Unsubscribe service: \" + url.getServiceKey() + \",url:\" + url);\n        }\n        unsubscribe(url.getServiceKey(), url, listener);\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        return getRegistered(url.getServiceKey());\n    }\n\n    public void register(String service, URL url) {\n        if (service == null) {\n            throw new IllegalArgumentException(\"service == null\");\n        }\n        if (url == null) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n        List<URL> urls = ConcurrentHashMapUtils.computeIfAbsent(registered, service, k -> new CopyOnWriteArrayList<>());\n        if (!urls.contains(url)) {\n            urls.add(url);\n        }\n    }\n\n    public void unregister(String service, URL url) {\n        if (service == null) {\n            throw new IllegalArgumentException(\"service == null\");\n        }\n        if (url == null) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n        List<URL> urls = registered.get(service);\n        if (urls != null) {\n            URL deleteURL = null;\n            for (URL u : urls) {\n                if (u.toIdentityString().equals(url.toIdentityString())) {\n                    deleteURL = u;\n                    break;\n                }\n            }\n            if (deleteURL != null) {\n                urls.remove(deleteURL);\n            }\n        }\n    }\n\n    public void subscribe(String service, URL url, NotifyListener listener) {\n        if (service == null) {\n            throw new IllegalArgumentException(\"service == null\");\n        }\n        if (url == null) {\n            throw new IllegalArgumentException(\"parameters == null\");\n        }\n        if (listener == null) {\n            throw new IllegalArgumentException(\"listener == null\");\n        }\n        subscribed.put(service, url.getParameters());\n        addListener(service, listener);\n    }\n\n    public void unsubscribe(String service, URL url, NotifyListener listener) {\n        if (service == null) {\n            throw new IllegalArgumentException(\"service == null\");\n        }\n        if (url == null) {\n            throw new IllegalArgumentException(\"parameters == null\");\n        }\n        if (listener == null) {\n            throw new IllegalArgumentException(\"listener == null\");\n        }\n        subscribed.remove(service);\n        removeListener(service, listener);\n    }\n\n    private void addListener(final String service, final NotifyListener listener) {\n        if (listener == null) {\n            return;\n        }\n        List<NotifyListener> listeners =\n                ConcurrentHashMapUtils.computeIfAbsent(notifyListeners, service, k -> new CopyOnWriteArrayList<>());\n        if (!listeners.contains(listener)) {\n            listeners.add(listener);\n        }\n    }\n\n    private void removeListener(final String service, final NotifyListener listener) {\n        if (listener == null) {\n            return;\n        }\n        List<NotifyListener> listeners = notifyListeners.get(service);\n        if (listeners != null) {\n            listeners.remove(listener);\n        }\n    }\n\n    private void doNotify(String service, List<URL> urls) {\n        notified.put(service, urls);\n        List<NotifyListener> listeners = notifyListeners.get(service);\n        if (listeners != null) {\n            for (NotifyListener listener : listeners) {\n                try {\n                    notify(service, urls, listener);\n                } catch (Throwable t) {\n                    logger.error(\n                            CONFIG_FAILED_NOTIFY_EVENT,\n                            \"\",\n                            \"\",\n                            \"Failed to notify registry event, service: \" + service + \", urls: \" + urls + \", cause: \"\n                                    + t.getMessage(),\n                            t);\n                }\n            }\n        }\n    }\n\n    protected void notify(String service, List<URL> urls, NotifyListener listener) {\n        listener.notify(urls);\n    }\n\n    protected final void forbid(String service) {\n        doNotify(service, new ArrayList<URL>(0));\n    }\n\n    protected final void notify(String service, List<URL> urls) {\n        if (StringUtils.isEmpty(service) || CollectionUtils.isEmpty(urls)) {\n            return;\n        }\n        doNotify(service, urls);\n    }\n\n    public Map<String, List<URL>> getRegistered() {\n        return Collections.unmodifiableMap(registered);\n    }\n\n    public List<URL> getRegistered(String service) {\n        return Collections.unmodifiableList(registered.get(service));\n    }\n\n    public Map<String, Map<String, String>> getSubscribed() {\n        return Collections.unmodifiableMap(subscribed);\n    }\n\n    public Map<String, String> getSubscribed(String service) {\n        return subscribed.get(service);\n    }\n\n    public Map<String, List<URL>> getNotified() {\n        return Collections.unmodifiableMap(notified);\n    }\n\n    public List<URL> getNotified(String service) {\n        return Collections.unmodifiableList(notified.get(service));\n    }\n\n    public Map<String, List<NotifyListener>> getListeners() {\n        return Collections.unmodifiableMap(notifyListeners);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ArgumentConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.config.spring.action.DemoActionByAnnotation;\nimport org.apache.dubbo.config.spring.action.DemoActionBySetter;\nimport org.apache.dubbo.config.spring.annotation.consumer.AnnotationAction;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration;\nimport org.apache.dubbo.config.spring.filter.MockFilter;\nimport org.apache.dubbo.config.spring.impl.DemoServiceImpl;\nimport org.apache.dubbo.config.spring.impl.HelloServiceImpl;\nimport org.apache.dubbo.config.spring.impl.NotifyService;\nimport org.apache.dubbo.config.spring.registry.MockRegistry;\nimport org.apache.dubbo.config.spring.registry.MockRegistryFactory;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryService;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_BEAN;\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_TCP_RESPONSE_TIMEOUT;\nimport static org.apache.dubbo.rpc.Constants.GENERIC_KEY;\nimport static org.hamcrest.CoreMatchers.containsString;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass ConfigTest {\n\n    private static String resourcePath = ConfigTest.class.getPackage().getName().replace('.', '/');\n\n    @BeforeEach\n    public void setUp() {\n        SysProps.clear();\n        DubboBootstrap.reset();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void tearDown() {\n        SysProps.clear();\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testSpringExtensionInject() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/spring-extension-inject.xml\");\n        try {\n            ctx.start();\n            MockFilter filter = (MockFilter)\n                    ExtensionLoader.getExtensionLoader(Filter.class).getExtension(\"mymock\");\n            assertNotNull(filter.getMockDao());\n            assertNotNull(filter.getProtocol());\n            assertNotNull(filter.getLoadBalance());\n        } finally {\n            ctx.stop();\n            ctx.close();\n        }\n    }\n\n    @Test\n    void testServiceClass() {\n        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourcePath + \"/service-class.xml\");\n        try {\n            ctx.start();\n\n            DemoService demoService = refer(\"dubbo://127.0.0.1:20887\");\n            String hello = demoService.sayName(\"hello\");\n            assertEquals(\"welcome:hello\", hello);\n        } finally {\n            ctx.stop();\n            ctx.close();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testServiceAnnotation() {\n        DubboBootstrap consumerBootstrap = null;\n        AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext();\n        try {\n            providerContext.register(ProviderConfiguration.class);\n            providerContext.refresh();\n\n            ReferenceConfig<HelloService> reference = new ReferenceConfig<HelloService>();\n            reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE));\n            reference.setInterface(HelloService.class);\n            reference.setUrl(\"dubbo://127.0.0.1:12345\");\n\n            consumerBootstrap = DubboBootstrap.newInstance()\n                    .application(new ApplicationConfig(\"consumer\"))\n                    .reference(reference)\n                    .start();\n            HelloService helloService = consumerBootstrap.getCache().get(reference);\n\n            String hello = helloService.sayHello(\"hello\");\n            assertEquals(\"Hello, hello\", hello);\n        } finally {\n            providerContext.close();\n            if (consumerBootstrap != null) {\n                consumerBootstrap.stop();\n            }\n        }\n    }\n\n    @Test\n    @SuppressWarnings(\"unchecked\")\n    public void testProviderNestedService() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/provider-nested-service.xml\");\n        try {\n            ctx.start();\n            ServiceConfig<DemoService> serviceConfig = (ServiceConfig<DemoService>) ctx.getBean(\"serviceConfig\");\n            assertNotNull(serviceConfig.getProvider());\n            assertEquals(2000, serviceConfig.getProvider().getTimeout().intValue());\n\n            ServiceConfig<DemoService> serviceConfig2 = (ServiceConfig<DemoService>) ctx.getBean(\"serviceConfig2\");\n            assertNotNull(serviceConfig2.getProvider());\n            assertEquals(1000, serviceConfig2.getProvider().getTimeout().intValue());\n        } finally {\n            ctx.stop();\n            ctx.close();\n        }\n    }\n\n    private DemoService refer(String url) {\n        ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>();\n        reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE));\n        reference.setInterface(DemoService.class);\n        reference.setUrl(url);\n\n        DubboBootstrap bootstrap = DubboBootstrap.newInstance()\n                .application(new ApplicationConfig(\"consumer\"))\n                .reference(reference)\n                .start();\n        return bootstrap.getCache().get(reference);\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testToString() {\n        ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>();\n        reference.setApplication(new ApplicationConfig(\"consumer\"));\n        reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE));\n        reference.setInterface(DemoService.class);\n        reference.setUrl(\"dubbo://127.0.0.1:20881\");\n        String str = reference.toString();\n        assertTrue(str.startsWith(\"<dubbo:reference \"));\n        assertTrue(str.contains(\" url=\\\"dubbo://127.0.0.1:20881\\\" \"));\n        assertTrue(str.contains(\" interface=\\\"org.apache.dubbo.config.spring.api.DemoService\\\" \"));\n        assertTrue(str.endsWith(\" />\"));\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testForks() {\n        ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>();\n        reference.setApplication(new ApplicationConfig(\"consumer\"));\n        reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE));\n        reference.setInterface(DemoService.class);\n        reference.setUrl(\"dubbo://127.0.0.1:20881\");\n\n        int forks = 10;\n        reference.setForks(forks);\n        String str = reference.toString();\n        assertTrue(str.contains(\"forks=\\\"\" + forks + \"\\\"\"));\n    }\n\n    @Test\n    void testMultiProtocol() {\n        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourcePath + \"/multi-protocol.xml\");\n\n        try {\n            ctx.start();\n\n            DemoService demoService = refer(\"dubbo://127.0.0.1:20881\");\n            String hello = demoService.sayName(\"hello\");\n            assertEquals(\"say:hello\", hello);\n        } finally {\n            ctx.stop();\n            ctx.close();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testMultiProtocolDefault() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/multi-protocol-default.xml\");\n        try {\n            ctx.start();\n            DemoService demoService = refer(\"rmi://127.0.0.1:10991\");\n            String hello = demoService.sayName(\"hello\");\n            assertEquals(\"say:hello\", hello);\n        } finally {\n            ctx.stop();\n            ctx.close();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testMultiProtocolError() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/multi-protocol-error.xml\");\n        try {\n            ctx.start();\n            ctx.stop();\n            ctx.close();\n            fail();\n        } catch (BeanCreationException e) {\n            assertTrue(e.getMessage().contains(\"Found multi-protocols\"));\n        } finally {\n            try {\n                ctx.close();\n            } catch (Exception e) {\n            }\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testMultiProtocolRegister() {\n        SimpleRegistryService registryService = new SimpleRegistryService();\n        Exporter<RegistryService> exporter = SimpleRegistryExporter.export(4547, registryService);\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/multi-protocol-register.xml\");\n        try {\n            ctx.start();\n            List<URL> urls = registryService.getRegistered().get(\"org.apache.dubbo.config.spring.api.DemoService\");\n            assertNotNull(urls);\n            assertEquals(1, urls.size());\n            assertEquals(\n                    \"dubbo://\" + NetUtils.getLocalHost() + \":20824/org.apache.dubbo.config.spring.api.DemoService\",\n                    urls.get(0).toIdentityString());\n        } finally {\n            ctx.stop();\n            ctx.close();\n            exporter.unexport();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testMultiRegistry() {\n        SimpleRegistryService registryService1 = new SimpleRegistryService();\n        Exporter<RegistryService> exporter1 = SimpleRegistryExporter.export(4545, registryService1);\n        SimpleRegistryService registryService2 = new SimpleRegistryService();\n        Exporter<RegistryService> exporter2 = SimpleRegistryExporter.export(4546, registryService2);\n        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourcePath + \"/multi-registry.xml\");\n        try {\n            ctx.start();\n            List<URL> urls1 = registryService1.getRegistered().get(\"org.apache.dubbo.config.spring.api.DemoService\");\n            assertNull(urls1);\n            List<URL> urls2 = registryService2.getRegistered().get(\"org.apache.dubbo.config.spring.api.DemoService\");\n            assertNotNull(urls2);\n            assertEquals(1, urls2.size());\n            assertEquals(\n                    \"dubbo://\" + NetUtils.getLocalHost() + \":20880/org.apache.dubbo.config.spring.api.DemoService\",\n                    urls2.get(0).toIdentityString());\n        } finally {\n            ctx.stop();\n            ctx.close();\n            exporter1.unexport();\n            exporter2.unexport();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testDelayFixedTime() throws Exception {\n        SimpleRegistryService registryService = new SimpleRegistryService();\n        Exporter<RegistryService> exporter = SimpleRegistryExporter.export(4548, registryService);\n        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourcePath + \"/delay-fixed-time.xml\");\n        try {\n            ctx.start();\n            List<URL> urls = registryService.getRegistered().get(\"org.apache.dubbo.config.spring.api.DemoService\");\n            assertNull(urls);\n            int i = 0;\n            while ((i++) < 60 && urls == null) {\n                urls = registryService.getRegistered().get(\"org.apache.dubbo.config.spring.api.DemoService\");\n                Thread.sleep(10);\n            }\n            assertNotNull(urls);\n            assertEquals(1, urls.size());\n            assertEquals(\n                    \"dubbo://\" + NetUtils.getLocalHost() + \":20888/org.apache.dubbo.config.spring.api.DemoService\",\n                    urls.get(0).toIdentityString());\n        } finally {\n            ctx.stop();\n            ctx.close();\n            exporter.unexport();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testDelayOnInitialized() throws Exception {\n        SimpleRegistryService registryService = new SimpleRegistryService();\n        Exporter<RegistryService> exporter = SimpleRegistryExporter.export(4548, registryService);\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/delay-on-initialized.xml\");\n        try {\n            // ctx.start();\n            List<URL> urls = registryService.getRegistered().get(\"org.apache.dubbo.config.spring.api.DemoService\");\n            assertNotNull(urls);\n            assertEquals(1, urls.size());\n            assertEquals(\n                    \"dubbo://\" + NetUtils.getLocalHost() + \":20888/org.apache.dubbo.config.spring.api.DemoService\",\n                    urls.get(0).toIdentityString());\n        } finally {\n            ctx.stop();\n            ctx.close();\n            exporter.unexport();\n        }\n    }\n\n    @Test\n    void testRmiTimeout() throws Exception {\n        SystemPropertyConfigUtils.clearSystemProperty(SYSTEM_TCP_RESPONSE_TIMEOUT);\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setTimeout(1000);\n        assertEquals(\"1000\", SystemPropertyConfigUtils.getSystemProperty(SYSTEM_TCP_RESPONSE_TIMEOUT));\n        consumer.setTimeout(2000);\n        assertEquals(\"1000\", SystemPropertyConfigUtils.getSystemProperty(SYSTEM_TCP_RESPONSE_TIMEOUT));\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testAutowireAndAOP() throws Exception {\n        ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(\n                resourcePath + \"/demo-provider.xml\", resourcePath + \"/demo-provider-properties.xml\");\n        try {\n            providerContext.start();\n            ClassPathXmlApplicationContext byNameContext =\n                    new ClassPathXmlApplicationContext(resourcePath + \"/aop-autowire-byname.xml\");\n            try {\n                byNameContext.start();\n                DemoActionBySetter demoActionBySetter =\n                        (DemoActionBySetter) byNameContext.getBean(\"demoActionBySetter\");\n                assertNotNull(demoActionBySetter.getDemoService());\n                assertEquals(\n                        \"aop:say:hello\", demoActionBySetter.getDemoService().sayName(\"hello\"));\n                DemoActionByAnnotation demoActionByAnnotation =\n                        (DemoActionByAnnotation) byNameContext.getBean(\"demoActionByAnnotation\");\n                assertNotNull(demoActionByAnnotation.getDemoService());\n                assertEquals(\n                        \"aop:say:hello\", demoActionByAnnotation.getDemoService().sayName(\"hello\"));\n            } finally {\n                byNameContext.stop();\n                byNameContext.close();\n            }\n            ClassPathXmlApplicationContext byTypeContext =\n                    new ClassPathXmlApplicationContext(resourcePath + \"/aop-autowire-bytype.xml\");\n            try {\n                byTypeContext.start();\n                DemoActionBySetter demoActionBySetter =\n                        (DemoActionBySetter) byTypeContext.getBean(\"demoActionBySetter\");\n                assertNotNull(demoActionBySetter.getDemoService());\n                assertEquals(\n                        \"aop:say:hello\", demoActionBySetter.getDemoService().sayName(\"hello\"));\n                DemoActionByAnnotation demoActionByAnnotation =\n                        (DemoActionByAnnotation) byTypeContext.getBean(\"demoActionByAnnotation\");\n                assertNotNull(demoActionByAnnotation.getDemoService());\n                assertEquals(\n                        \"aop:say:hello\", demoActionByAnnotation.getDemoService().sayName(\"hello\"));\n            } finally {\n                byTypeContext.stop();\n                byTypeContext.close();\n            }\n        } finally {\n            providerContext.stop();\n            providerContext.close();\n        }\n    }\n\n    @Test\n    void testAppendFilter() throws Exception {\n        ApplicationConfig application = new ApplicationConfig(\"provider\");\n\n        ProviderConfig provider = new ProviderConfig();\n        provider.setFilter(\"classloader,monitor\");\n\n        ConsumerConfig consumer = new ConsumerConfig();\n        consumer.setFilter(\"classloader,monitor\");\n\n        ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();\n        service.setFilter(\"accesslog,trace\");\n        service.setProvider(provider);\n        service.setProtocol(new ProtocolConfig(\"dubbo\", 20880));\n        service.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE));\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n\n        ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>();\n        reference.setFilter(\"accesslog,trace\");\n        reference.setConsumer(consumer);\n        reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE));\n        reference.setInterface(DemoService.class);\n        reference.setUrl(\n                \"dubbo://\" + NetUtils.getLocalHost() + \":20880?\" + DemoService.class.getName() + \"?check=false\");\n\n        try {\n            DubboBootstrap.getInstance()\n                    .application(application)\n                    .provider(provider)\n                    .service(service)\n                    .reference(reference)\n                    .start();\n\n            List<URL> urls = service.getExportedUrls();\n            assertNotNull(urls);\n            assertEquals(1, urls.size());\n            assertEquals(\"classloader,monitor,accesslog,trace\", urls.get(0).getParameter(\"service.filter\"));\n\n            urls = reference.getExportedUrls();\n            assertNotNull(urls);\n            assertEquals(1, urls.size());\n            assertEquals(\"classloader,monitor,accesslog,trace\", urls.get(0).getParameter(\"reference.filter\"));\n\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testInitReference() throws Exception {\n        ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(\n                resourcePath + \"/demo-provider.xml\", resourcePath + \"/demo-provider-properties.xml\");\n\n        try {\n            providerContext.start();\n\n            // consumer app\n            ClassPathXmlApplicationContext consumerContext = new ClassPathXmlApplicationContext(\n                    resourcePath + \"/init-reference.xml\", resourcePath + \"/init-reference-properties.xml\");\n            try {\n                consumerContext.start();\n\n                NotifyService notifyService = consumerContext.getBean(NotifyService.class);\n\n                // check reference bean\n                Map<String, ReferenceBean> referenceBeanMap = consumerContext.getBeansOfType(ReferenceBean.class);\n                Assertions.assertEquals(2, referenceBeanMap.size());\n                ReferenceBean referenceBean = referenceBeanMap.get(\"&demoService\");\n                Assertions.assertNotNull(referenceBean);\n                ReferenceConfig referenceConfig = referenceBean.getReferenceConfig();\n                // reference parameters\n                Assertions.assertNotNull(referenceConfig.getParameters().get(\"connec.timeout\"));\n                Assertions.assertEquals(\"demo_tag\", referenceConfig.getTag());\n\n                // methods\n                Assertions.assertEquals(1, referenceConfig.getMethods().size());\n                MethodConfig methodConfig = referenceConfig.getMethods().get(0);\n                Assertions.assertEquals(\"sayName\", methodConfig.getName());\n                Assertions.assertEquals(notifyService, methodConfig.getOninvoke());\n                Assertions.assertEquals(notifyService, methodConfig.getOnreturn());\n                Assertions.assertEquals(notifyService, methodConfig.getOnthrow());\n                Assertions.assertEquals(\"onInvoke\", methodConfig.getOninvokeMethod());\n                Assertions.assertEquals(\"onReturn\", methodConfig.getOnreturnMethod());\n                Assertions.assertEquals(\"onThrow\", methodConfig.getOnthrowMethod());\n\n                // method arguments\n                Assertions.assertEquals(1, methodConfig.getArguments().size());\n                ArgumentConfig argumentConfig = methodConfig.getArguments().get(0);\n                Assertions.assertEquals(0, argumentConfig.getIndex());\n                Assertions.assertEquals(true, argumentConfig.isCallback());\n\n                // method parameters\n                Assertions.assertEquals(1, methodConfig.getParameters().size());\n                Assertions.assertEquals(\"my-token\", methodConfig.getParameters().get(\"access-token\"));\n\n                // do call\n                DemoService demoService = (DemoService) consumerContext.getBean(\"demoService\");\n                assertEquals(\"say:world\", demoService.sayName(\"world\"));\n\n                GenericService demoService2 = (GenericService) consumerContext.getBean(\"demoService2\");\n                assertEquals(\n                        \"say:world\",\n                        demoService2.$invoke(\"sayName\", new String[] {\"java.lang.String\"}, new Object[] {\"world\"}));\n\n            } finally {\n                consumerContext.stop();\n                consumerContext.close();\n            }\n        } finally {\n            providerContext.stop();\n            providerContext.close();\n        }\n    }\n\n    // DUBBO-571 methods key in provider's URLONE doesn't contain the methods from inherited super interface\n    @Test\n    void test_noMethodInterface_methodsKeyHasValue() throws Exception {\n        List<URL> urls = null;\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/demo-provider-no-methods-interface.xml\");\n        try {\n            ctx.start();\n\n            ServiceBean bean = (ServiceBean) ctx.getBean(\"service\");\n            urls = bean.getExportedUrls();\n            assertEquals(1, urls.size());\n            URL url = urls.get(0);\n            assertEquals(\"getBox,sayName\", url.getParameter(\"methods\"));\n        } finally {\n            ctx.stop();\n            ctx.close();\n            // Check if the port is closed\n            if (urls != null) {\n                for (URL url : urls) {\n                    Assertions.assertFalse(NetUtils.isPortInUsed(url.getPort()));\n                }\n            }\n        }\n    }\n\n    // DUBBO-147 find all invoker instances which have been tried from RpcContext\n    @Disabled(\"waiting-to-fix\")\n    @Test\n    void test_RpcContext_getUrls() throws Exception {\n        ClassPathXmlApplicationContext providerContext =\n                new ClassPathXmlApplicationContext(resourcePath + \"/demo-provider-long-waiting.xml\");\n\n        try {\n            providerContext.start();\n\n            ClassPathXmlApplicationContext ctx =\n                    new ClassPathXmlApplicationContext(resourcePath + \"/init-reference-getUrls.xml\");\n            try {\n                ctx.start();\n                DemoService demoService = (DemoService) ctx.getBean(\"demoService\");\n                try {\n                    demoService.sayName(\"Haha\");\n                    fail();\n                } catch (RpcException expected) {\n                    assertThat(expected.getMessage(), containsString(\"Tried 3 times\"));\n                }\n\n                assertEquals(3, RpcContext.getServiceContext().getUrls().size());\n            } finally {\n                ctx.stop();\n                ctx.close();\n            }\n        } finally {\n            providerContext.stop();\n            providerContext.close();\n        }\n    }\n\n    // BUG: DUBBO-846 in version 2.0.9, config retry=\"false\" on provider's method doesn't work\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void test_retrySettingFail() throws Exception {\n        ClassPathXmlApplicationContext providerContext =\n                new ClassPathXmlApplicationContext(resourcePath + \"/demo-provider-long-waiting.xml\");\n\n        try {\n            providerContext.start();\n            ClassPathXmlApplicationContext ctx =\n                    new ClassPathXmlApplicationContext(resourcePath + \"/init-reference-retry-false.xml\");\n            try {\n                ctx.start();\n                DemoService demoService = (DemoService) ctx.getBean(\"demoService\");\n                try {\n                    demoService.sayName(\"Haha\");\n                    fail();\n                } catch (RpcException expected) {\n                    assertThat(expected.getMessage(), containsString(\"Tried 1 times\"));\n                }\n\n                assertEquals(1, RpcContext.getServiceContext().getUrls().size());\n            } finally {\n                ctx.stop();\n                ctx.close();\n            }\n        } finally {\n            providerContext.stop();\n            providerContext.close();\n        }\n    }\n\n    // BuG: DUBBO-146 Provider doesn't have exception output, and consumer has timeout error when serialization fails\n    // for example, object transported on the wire doesn't implement Serializable\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void test_returnSerializationFail() throws Exception {\n        ClassPathXmlApplicationContext providerContext =\n                new ClassPathXmlApplicationContext(resourcePath + \"/demo-provider-UnserializableBox.xml\");\n        try {\n            providerContext.start();\n            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(\n                    resourcePath + \"/init-reference.xml\", resourcePath + \"/init-reference-properties.xml\");\n            try {\n                ctx.start();\n                DemoService demoService = (DemoService) ctx.getBean(\"demoService\");\n                try {\n                    demoService.getBox();\n                    fail();\n                } catch (RpcException expected) {\n                    assertThat(expected.getMessage(), containsString(\"must implement java.io.Serializable\"));\n                }\n            } finally {\n                ctx.stop();\n                ctx.close();\n            }\n        } finally {\n            providerContext.stop();\n            providerContext.close();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testXmlOverrideProperties() throws Exception {\n        ClassPathXmlApplicationContext providerContext =\n                new ClassPathXmlApplicationContext(resourcePath + \"/xml-override-properties.xml\");\n        try {\n            providerContext.start();\n            ApplicationConfig application = (ApplicationConfig) providerContext.getBean(\"application\");\n            assertEquals(\"demo-provider\", application.getName());\n            assertEquals(\"world\", application.getOwner());\n\n            RegistryConfig registry = (RegistryConfig) providerContext.getBean(\"registry\");\n            assertEquals(\"N/A\", registry.getAddress());\n\n            ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean(\"dubbo\");\n            assertEquals(20813, dubbo.getPort().intValue());\n\n        } finally {\n            providerContext.stop();\n            providerContext.close();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testApiOverrideProperties() throws Exception {\n        ApplicationConfig application = new ApplicationConfig();\n        application.setName(\"api-override-properties\");\n\n        RegistryConfig registry = new RegistryConfig();\n        registry.setAddress(\"N/A\");\n\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setName(\"dubbo\");\n        protocol.setPort(13123);\n\n        ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n        service.setRegistry(registry);\n        service.setProtocol(protocol);\n\n        ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>();\n        reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE));\n        reference.setInterface(DemoService.class);\n        reference.setUrl(\"dubbo://127.0.0.1:13123\");\n\n        try {\n            DubboBootstrap.getInstance()\n                    .application(application)\n                    .registry(registry)\n                    .protocol(protocol)\n                    .service(service)\n                    .reference(reference)\n                    .start();\n\n            URL url = service.getExportedUrls().get(0);\n            assertEquals(\"api-override-properties\", url.getParameter(\"application\"));\n            assertEquals(\"world\", url.getParameter(\"owner\"));\n            assertEquals(13123, url.getPort());\n\n            url = reference.getExportedUrls().get(0);\n            assertEquals(\"2000\", url.getParameter(\"timeout\"));\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testSystemPropertyOverrideProtocol() throws Exception {\n        SysProps.setProperty(\"dubbo.protocols.tri.port\", \"\"); // empty config should be ignored\n        SysProps.setProperty(\"dubbo.protocols.dubbo.port\", \"20812\"); // override success\n        SysProps.setProperty(\"dubbo.protocol.port\", \"20899\"); // override fail\n        ClassPathXmlApplicationContext providerContext =\n                new ClassPathXmlApplicationContext(resourcePath + \"/override-protocol.xml\");\n        try {\n            providerContext.start();\n            ConfigManager configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n            ProtocolConfig protocol = configManager.getProtocol(\"dubbo\").get();\n            assertEquals(20812, protocol.getPort());\n        } finally {\n            providerContext.close();\n        }\n    }\n\n    @Test\n    void testSystemPropertyOverrideMultiProtocol() throws Exception {\n        SysProps.setProperty(\"dubbo.protocols.dubbo.port\", \"20814\");\n        SysProps.setProperty(\"dubbo.protocols.tri.port\", \"10914\");\n        ClassPathXmlApplicationContext providerContext =\n                new ClassPathXmlApplicationContext(resourcePath + \"/override-multi-protocol.xml\");\n        try {\n            providerContext.start();\n            ConfigManager configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n\n            ProtocolConfig dubboProtocol = configManager.getProtocol(\"dubbo\").get();\n            assertEquals(20814, dubboProtocol.getPort().intValue());\n            ProtocolConfig tripleProtocol = configManager.getProtocol(\"tri\").get();\n            assertEquals(10914, tripleProtocol.getPort().intValue());\n        } finally {\n            providerContext.stop();\n            providerContext.close();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testSystemPropertyOverrideXmlDefault() throws Exception {\n        SysProps.setProperty(\"dubbo.application.name\", \"sysover\");\n        SysProps.setProperty(\"dubbo.application.owner\", \"sysowner\");\n        SysProps.setProperty(\"dubbo.registry.address\", \"N/A\");\n        SysProps.setProperty(\"dubbo.protocol.name\", \"dubbo\");\n        SysProps.setProperty(\"dubbo.protocol.port\", \"20819\");\n        ClassPathXmlApplicationContext providerContext =\n                new ClassPathXmlApplicationContext(resourcePath + \"/system-properties-override-default.xml\");\n        try {\n            providerContext.start();\n            ServiceConfig<DemoService> service =\n                    (ServiceConfig<DemoService>) providerContext.getBean(\"demoServiceConfig\");\n            assertEquals(\"sysover\", service.getApplication().getName());\n            assertEquals(\"sysowner\", service.getApplication().getOwner());\n            assertEquals(\"N/A\", service.getRegistry().getAddress());\n            assertEquals(\"dubbo\", service.getProtocol().getName());\n            assertEquals(20819, service.getProtocol().getPort().intValue());\n        } finally {\n            providerContext.stop();\n            providerContext.close();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testSystemPropertyOverrideXml() throws Exception {\n        SysProps.setProperty(\"dubbo.application.name\", \"sysover\");\n        SysProps.setProperty(\"dubbo.application.owner\", \"sysowner\");\n        SysProps.setProperty(\"dubbo.registry.address\", \"N/A\");\n        SysProps.setProperty(\"dubbo.protocol.name\", \"dubbo\");\n        SysProps.setProperty(\"dubbo.protocol.port\", \"20819\");\n        SysProps.setProperty(\"dubbo.service.register\", \"false\");\n        ClassPathXmlApplicationContext providerContext =\n                new ClassPathXmlApplicationContext(resourcePath + \"/system-properties-override.xml\");\n        try {\n            providerContext.start();\n            ServiceConfig<DemoService> service =\n                    (ServiceConfig<DemoService>) providerContext.getBean(\"demoServiceConfig\");\n            URL url = service.getExportedUrls().get(0);\n            assertEquals(\"sysover\", url.getParameter(\"application\"));\n            assertEquals(\"sysowner\", url.getParameter(\"owner\"));\n            assertEquals(\"dubbo\", url.getProtocol());\n            assertEquals(20819, url.getPort());\n            String register = url.getParameter(\"register\");\n            assertTrue(register != null && !\"\".equals(register));\n            assertEquals(false, Boolean.valueOf(register));\n        } finally {\n            providerContext.stop();\n            providerContext.close();\n        }\n    }\n\n    @Test\n    void testSystemPropertyOverrideReferenceConfig() throws Exception {\n        SysProps.setProperty(\"dubbo.reference.org.apache.dubbo.config.spring.api.DemoService.retries\", \"5\");\n        SysProps.setProperty(\"dubbo.consumer.check\", \"false\");\n        SysProps.setProperty(\"dubbo.consumer.timeout\", \"1234\");\n\n        try {\n            ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();\n            service.setInterface(DemoService.class);\n            service.setRef(new DemoServiceImpl());\n            ProtocolConfig protocolConfig = new ProtocolConfig(\"injvm\");\n\n            ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>();\n            reference.setInterface(DemoService.class);\n            reference.setInjvm(true);\n            reference.setRetries(2);\n\n            DubboBootstrap.getInstance()\n                    .application(new ApplicationConfig(\"testSystemPropertyOverrideReferenceConfig\"))\n                    .registry(new RegistryConfig(RegistryConfig.NO_AVAILABLE))\n                    .protocol(protocolConfig)\n                    .service(service)\n                    .reference(reference)\n                    .start();\n\n            // override retries\n            assertEquals(Integer.valueOf(5), reference.getRetries());\n            // set default value of check\n            assertEquals(false, reference.shouldCheck());\n\n            ModuleConfigManager moduleConfigManager =\n                    ApplicationModel.defaultModel().getDefaultModule().getConfigManager();\n            ConsumerConfig defaultConsumer =\n                    moduleConfigManager.getDefaultConsumer().get();\n            assertEquals(1234, defaultConsumer.getTimeout());\n            assertEquals(false, defaultConsumer.isCheck());\n        } finally {\n            // If we don't stop here, somewhere else will throw BeanCreationException of duplication.\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testSystemPropertyOverrideApiDefault() throws Exception {\n        SysProps.setProperty(\"dubbo.application.name\", \"sysover\");\n        SysProps.setProperty(\"dubbo.application.owner\", \"sysowner\");\n        SysProps.setProperty(\"dubbo.registry.address\", \"N/A\");\n        SysProps.setProperty(\"dubbo.protocol.name\", \"dubbo\");\n        SysProps.setProperty(\"dubbo.protocol.port\", \"20834\");\n\n        try {\n            ServiceConfig<DemoService> serviceConfig = new ServiceConfig<DemoService>();\n            serviceConfig.setInterface(DemoService.class);\n            serviceConfig.setRef(new DemoServiceImpl());\n\n            DubboBootstrap.getInstance().service(serviceConfig).start();\n\n            assertEquals(\"sysover\", serviceConfig.getApplication().getName());\n            assertEquals(\"sysowner\", serviceConfig.getApplication().getOwner());\n            assertEquals(\"N/A\", serviceConfig.getRegistry().getAddress());\n            assertEquals(\"dubbo\", serviceConfig.getProtocol().getName());\n            assertEquals(20834, serviceConfig.getProtocol().getPort().intValue());\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testSystemPropertyOverrideApi() throws Exception {\n        SysProps.setProperty(\"dubbo.application.name\", \"sysover\");\n        SysProps.setProperty(\"dubbo.application.owner\", \"sysowner\");\n        SysProps.setProperty(\"dubbo.registry.address\", \"N/A\");\n        SysProps.setProperty(\"dubbo.protocol.name\", \"dubbo\");\n        SysProps.setProperty(\"dubbo.protocol.port\", \"20834\");\n        try {\n            ApplicationConfig application = new ApplicationConfig();\n            application.setName(\"aaa\");\n\n            RegistryConfig registry = new RegistryConfig();\n            registry.setAddress(\"127.0.0.1\");\n\n            ProtocolConfig protocol = new ProtocolConfig();\n            protocol.setName(\"rmi\");\n            protocol.setPort(1099);\n\n            ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();\n            service.setInterface(DemoService.class);\n            service.setRef(new DemoServiceImpl());\n            service.setApplication(application);\n            service.setRegistry(registry);\n            service.setProtocol(protocol);\n\n            DubboBootstrap.getInstance()\n                    .application(application)\n                    .registry(registry)\n                    .protocol(protocol)\n                    .service(service)\n                    .start();\n\n            URL url = service.getExportedUrls().get(0);\n            assertEquals(\"sysover\", url.getParameter(\"application\"));\n            assertEquals(\"sysowner\", url.getParameter(\"owner\"));\n            assertEquals(\"dubbo\", url.getProtocol());\n            assertEquals(20834, url.getPort());\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testSystemPropertyOverrideProperties() throws Exception {\n        try {\n            int port = 1234;\n            SysProps.setProperty(\"dubbo.protocol.port\", String.valueOf(port));\n            ApplicationConfig application = new ApplicationConfig();\n            application.setName(\"aaa\");\n\n            RegistryConfig registry = new RegistryConfig();\n            registry.setAddress(\"N/A\");\n\n            ProtocolConfig protocol = new ProtocolConfig();\n            protocol.setName(\"rmi\");\n\n            ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();\n            service.setInterface(DemoService.class);\n            service.setRef(new DemoServiceImpl());\n            service.setApplication(application);\n            service.setRegistry(registry);\n            service.setProtocol(protocol);\n\n            DubboBootstrap.getInstance()\n                    .application(application)\n                    .registry(registry)\n                    .protocol(protocol)\n                    .service(service)\n                    .start();\n\n            URL url = service.getExportedUrls().get(0);\n            // from api\n            assertEquals(\"aaa\", url.getParameter(\"application\"));\n            // from dubbo-binder.properties\n            assertEquals(\"world\", url.getParameter(\"owner\"));\n            // from system property\n            assertEquals(1234, url.getPort());\n        } finally {\n            System.clearProperty(\"dubbo.protocol.port\");\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    @SuppressWarnings(\"unchecked\")\n    public void testCustomizeParameter() throws Exception {\n        ClassPathXmlApplicationContext context =\n                new ClassPathXmlApplicationContext(resourcePath + \"/customize-parameter.xml\");\n        try {\n            context.start();\n            ServiceBean<DemoService> serviceBean = (ServiceBean<DemoService>) context.getBean(\"demoServiceExport\");\n            URL url = (URL) serviceBean.getExportedUrls().get(0);\n            assertEquals(\"protocol-paramA\", url.getParameter(\"protocol.paramA\"));\n            assertEquals(\"service-paramA\", url.getParameter(\"service.paramA\"));\n        } finally {\n            context.close();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testPath() throws Exception {\n        ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();\n        service.setPath(\"a/b$c\");\n        try {\n            service.setPath(\"a?b\");\n            fail();\n        } catch (IllegalStateException e) {\n            assertTrue(e.getMessage().contains(\"\"));\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testAnnotation() {\n        SimpleRegistryService registryService = new SimpleRegistryService();\n        Exporter<RegistryService> exporter = SimpleRegistryExporter.export(4548, registryService);\n        try {\n            SysProps.setProperty(\"provider.version\", \"1.2\");\n            ClassPathXmlApplicationContext providerContext =\n                    new ClassPathXmlApplicationContext(resourcePath + \"/annotation-provider.xml\");\n            try {\n                providerContext.start();\n\n                ClassPathXmlApplicationContext consumerContext =\n                        new ClassPathXmlApplicationContext(resourcePath + \"/annotation-consumer.xml\");\n                try {\n                    consumerContext.start();\n                    AnnotationAction annotationAction = (AnnotationAction) consumerContext.getBean(\"annotationAction\");\n                    String hello = annotationAction.doSayName(\"hello\");\n                    assertEquals(\"annotation:hello\", hello);\n                } finally {\n                    consumerContext.stop();\n                    consumerContext.close();\n                }\n            } finally {\n                providerContext.stop();\n                providerContext.close();\n            }\n        } finally {\n            System.clearProperty(\"provider.version\");\n            exporter.unexport();\n        }\n    }\n\n    @Test\n    void testDubboProtocolPortOverride() throws Exception {\n        int port = NetUtils.getAvailablePort();\n        SysProps.setProperty(\"dubbo.protocol.port\", String.valueOf(port));\n        ServiceConfig<DemoService> service = null;\n        try {\n            ApplicationConfig application = new ApplicationConfig();\n            application.setName(\"dubbo-protocol-port-override\");\n\n            RegistryConfig registry = new RegistryConfig();\n            registry.setAddress(\"N/A\");\n\n            ProtocolConfig protocol = new ProtocolConfig();\n\n            service = new ServiceConfig<DemoService>();\n            service.setInterface(DemoService.class);\n            service.setRef(new DemoServiceImpl());\n            service.setApplication(application);\n            service.setRegistry(registry);\n            service.setProtocol(protocol);\n\n            DubboBootstrap.getInstance()\n                    .application(application)\n                    .registry(registry)\n                    .protocol(protocol)\n                    .service(service)\n                    .start();\n\n            assertEquals(port, service.getExportedUrls().get(0).getPort());\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix\")\n    public void testProtocolRandomPort() throws Exception {\n        ServiceConfig<DemoService> demoService = null;\n        ServiceConfig<HelloService> helloService = null;\n\n        ApplicationConfig application = new ApplicationConfig();\n        application.setName(\"test-protocol-random-port\");\n\n        RegistryConfig registry = new RegistryConfig();\n        registry.setAddress(\"N/A\");\n\n        ProtocolConfig protocol = new ProtocolConfig();\n        protocol.setName(\"dubbo\");\n        protocol.setPort(-1);\n\n        demoService = new ServiceConfig<DemoService>();\n        demoService.setInterface(DemoService.class);\n        demoService.setRef(new DemoServiceImpl());\n        demoService.setApplication(application);\n        demoService.setRegistry(registry);\n        demoService.setProtocol(protocol);\n\n        helloService = new ServiceConfig<HelloService>();\n        helloService.setInterface(HelloService.class);\n        helloService.setRef(new HelloServiceImpl());\n        helloService.setApplication(application);\n        helloService.setRegistry(registry);\n        helloService.setProtocol(protocol);\n\n        try {\n            DubboBootstrap.getInstance()\n                    .application(application)\n                    .registry(registry)\n                    .protocol(protocol)\n                    .service(demoService)\n                    .service(helloService)\n                    .start();\n\n            assertEquals(\n                    demoService.getExportedUrls().get(0).getPort(),\n                    helloService.getExportedUrls().get(0).getPort());\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    @Disabled(\"waiting-to-fix, see: https://github.com/apache/dubbo/pull/8534\")\n    public void testReferGenericExport() throws Exception {\n        RegistryConfig rc = new RegistryConfig();\n        rc.setAddress(RegistryConfig.NO_AVAILABLE);\n\n        ServiceConfig<GenericService> sc = new ServiceConfig<GenericService>();\n        sc.setRegistry(rc);\n        sc.setInterface(DemoService.class.getName());\n        sc.setRef((method, parameterTypes, args) -> null);\n\n        ReferenceConfig<DemoService> ref = new ReferenceConfig<DemoService>();\n        ref.setRegistry(rc);\n        ref.setInterface(DemoService.class.getName());\n\n        try {\n            DubboBootstrap.getInstance()\n                    .application(new ApplicationConfig(\"test-refer-generic-export\"))\n                    .service(sc)\n                    .reference(ref)\n                    .start();\n            fail();\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testGenericServiceConfig() throws Exception {\n        ServiceConfig<GenericService> service = new ServiceConfig<GenericService>();\n        service.setRegistry(new RegistryConfig(\"mock://localhost\"));\n        service.setInterface(DemoService.class.getName());\n        service.setGeneric(GENERIC_SERIALIZATION_BEAN);\n        service.setRef((method, parameterTypes, args) -> null);\n\n        try {\n            DubboBootstrap.getInstance()\n                    .application(new ApplicationConfig(\"test\"))\n                    .service(service)\n                    .start();\n\n            Collection<Registry> collection = MockRegistryFactory.getCachedRegistry();\n            MockRegistry registry = (MockRegistry) collection.iterator().next();\n            URL url = registry.getRegistered().get(0);\n            assertEquals(GENERIC_SERIALIZATION_BEAN, url.getParameter(GENERIC_KEY));\n        } finally {\n            MockRegistryFactory.cleanCachedRegistry();\n            DubboBootstrap.getInstance().stop();\n        }\n    }\n\n    @Test\n    void testGenericServiceConfigThroughSpring() throws Exception {\n        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourcePath + \"/generic-export.xml\");\n        try {\n            ctx.start();\n            ServiceConfig serviceConfig = (ServiceConfig) ctx.getBean(\"dubboDemoService\");\n            URL url = (URL) serviceConfig.getExportedUrls().get(0);\n            assertEquals(GENERIC_SERIALIZATION_BEAN, url.getParameter(GENERIC_KEY));\n        } finally {\n            ctx.close();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ControllerServiceConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.spring.api.SpringControllerService;\n\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\n@Disabled\npublic class ControllerServiceConfigTest {\n\n    @Test\n    void testServiceConfig() {\n\n        ServiceConfig<SpringControllerService> serviceServiceConfig = new ServiceConfig<>();\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"dubbo\");\n        serviceServiceConfig.setApplication(applicationConfig);\n        serviceServiceConfig.setProtocol(new ProtocolConfig(\"dubbo\", 8080));\n        serviceServiceConfig.setRef(new SpringControllerService());\n        serviceServiceConfig.setInterface(SpringControllerService.class.getName());\n        serviceServiceConfig.export();\n        serviceServiceConfig.unexport();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/DubboStateListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.common.deploy.DeployState;\nimport org.apache.dubbo.config.spring.context.event.DubboApplicationStateEvent;\n\nimport org.springframework.context.ApplicationListener;\n\npublic class DubboStateListener implements ApplicationListener<DubboApplicationStateEvent> {\n\n    private DeployState state;\n\n    @Override\n    public void onApplicationEvent(DubboApplicationStateEvent event) {\n        state = event.getState();\n    }\n\n    public DeployState getState() {\n        return state;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/EmbeddedZooKeeper.java",
    "content": "/*\n * Copyright 2014 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.test.common.utils.TestSocketUtils;\n\nimport org.apache.zookeeper.server.ServerConfig;\nimport org.apache.zookeeper.server.ZooKeeperServerMain;\nimport org.apache.zookeeper.server.quorum.QuorumPeerConfig;\nimport org.springframework.context.SmartLifecycle;\nimport org.springframework.util.ErrorHandler;\n\nimport java.io.File;\nimport java.lang.reflect.Method;\nimport java.util.Properties;\nimport java.util.UUID;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.SYSTEM_JAVA_IO_TMPDIR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TESTING_INIT_ZOOKEEPER_SERVER_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TESTING_REGISTRY_FAILED_TO_STOP_ZOOKEEPER;\n\n/**\n * from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java\n * <p>\n * Helper class to start an embedded instance of standalone (non clustered) ZooKeeper.\n * <p>\n * NOTE: at least an external standalone server (if not an ensemble) are recommended, even for\n * {@link org.springframework.xd.dirt.server.singlenode.SingleNodeApplication}\n */\npublic class EmbeddedZooKeeper implements SmartLifecycle {\n\n    /**\n     * Logger.\n     */\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(EmbeddedZooKeeper.class);\n\n    /**\n     * ZooKeeper client port. This will be determined dynamically upon startup.\n     */\n    private final int clientPort;\n\n    /**\n     * Whether to auto-start. Default is true.\n     */\n    private boolean autoStartup = true;\n\n    /**\n     * Lifecycle phase. Default is 0.\n     */\n    private int phase = 0;\n\n    /**\n     * Thread for running the ZooKeeper server.\n     */\n    private volatile Thread zkServerThread;\n\n    /**\n     * ZooKeeper server.\n     */\n    private volatile ZooKeeperServerMain zkServer;\n\n    /**\n     * {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread.\n     */\n    private ErrorHandler errorHandler;\n\n    private boolean daemon = true;\n\n    /**\n     * Construct an EmbeddedZooKeeper with a random port.\n     */\n    public EmbeddedZooKeeper() {\n        clientPort = TestSocketUtils.findAvailableTcpPort();\n    }\n\n    /**\n     * Construct an EmbeddedZooKeeper with the provided port.\n     *\n     * @param clientPort port for ZooKeeper server to bind to\n     */\n    public EmbeddedZooKeeper(int clientPort, boolean daemon) {\n        this.clientPort = clientPort;\n        this.daemon = daemon;\n    }\n\n    /**\n     * Returns the port that clients should use to connect to this embedded server.\n     *\n     * @return dynamically determined client port\n     */\n    public int getClientPort() {\n        return this.clientPort;\n    }\n\n    /**\n     * Specify whether to start automatically. Default is true.\n     *\n     * @param autoStartup whether to start automatically\n     */\n    public void setAutoStartup(boolean autoStartup) {\n        this.autoStartup = autoStartup;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public boolean isAutoStartup() {\n        return this.autoStartup;\n    }\n\n    /**\n     * Specify the lifecycle phase for the embedded server.\n     *\n     * @param phase the lifecycle phase\n     */\n    public void setPhase(int phase) {\n        this.phase = phase;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public int getPhase() {\n        return this.phase;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public boolean isRunning() {\n        return (zkServerThread != null);\n    }\n\n    /**\n     * Start the ZooKeeper server in a background thread.\n     * <p>\n     * Register an error handler via {@link #setErrorHandler} in order to handle\n     * any exceptions thrown during startup or execution.\n     */\n    @Override\n    public synchronized void start() {\n        if (zkServerThread == null) {\n            zkServerThread = new Thread(new ServerRunnable(), \"ZooKeeper Server Starter\");\n            zkServerThread.setDaemon(daemon);\n            zkServerThread.start();\n        }\n    }\n\n    /**\n     * Shutdown the ZooKeeper server.\n     */\n    @Override\n    public synchronized void stop() {\n        if (zkServerThread != null) {\n            // The shutdown method is protected...thus this hack to invoke it.\n            // This will log an exception on shutdown; see\n            // https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details.\n            try {\n                Method shutdown = ZooKeeperServerMain.class.getDeclaredMethod(\"shutdown\");\n                shutdown.setAccessible(true);\n                shutdown.invoke(zkServer);\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n\n            // It is expected that the thread will exit after\n            // the server is shutdown; this will block until\n            // the shutdown is complete.\n            try {\n                zkServerThread.join(5000);\n                zkServerThread = null;\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                logger.warn(TESTING_REGISTRY_FAILED_TO_STOP_ZOOKEEPER, \"\", \"\", \"Interrupted while waiting for embedded ZooKeeper to exit\");\n                // abandoning zk thread\n                zkServerThread = null;\n            }\n        }\n    }\n\n    /**\n     * Stop the server if running and invoke the callback when complete.\n     */\n    @Override\n    public void stop(Runnable callback) {\n        stop();\n        callback.run();\n    }\n\n    /**\n     * Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none\n     * is provided, only error-level logging will occur.\n     *\n     * @param errorHandler the {@link ErrorHandler} to be invoked\n     */\n    public void setErrorHandler(ErrorHandler errorHandler) {\n        this.errorHandler = errorHandler;\n    }\n\n    /**\n     * Runnable implementation that starts the ZooKeeper server.\n     */\n    private class ServerRunnable implements Runnable {\n\n        @Override\n        public void run() {\n            try {\n                Properties properties = new Properties();\n                File file = new File(SystemPropertyConfigUtils.getSystemProperty(SYSTEM_JAVA_IO_TMPDIR)\n                    + File.separator + UUID.randomUUID());\n                file.deleteOnExit();\n                properties.setProperty(\"dataDir\", file.getAbsolutePath());\n                properties.setProperty(\"clientPort\", String.valueOf(clientPort));\n\n                QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();\n                quorumPeerConfig.parseProperties(properties);\n\n                zkServer = new ZooKeeperServerMain();\n                ServerConfig configuration = new ServerConfig();\n                configuration.readFrom(quorumPeerConfig);\n\n                zkServer.runFromConfig(configuration);\n            } catch (Exception e) {\n                if (errorHandler != null) {\n                    errorHandler.handleError(e);\n                } else {\n                    logger.error(TESTING_INIT_ZOOKEEPER_SERVER_ERROR, \"ZooKeeper server error\", \"\", \"Exception running embedded ZooKeeper.\", e);\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/GenericDemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.rpc.service.GenericException;\nimport org.apache.dubbo.rpc.service.GenericService;\n\npublic class GenericDemoService implements GenericService {\n\n    public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/JavaConfigBeanTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.impl.DemoServiceImpl;\nimport org.apache.dubbo.rpc.Constants;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.util.Collection;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nclass JavaConfigBeanTest {\n\n    private static final String MY_PROTOCOL_ID = \"myProtocol\";\n    private static final String MY_REGISTRY_ID = \"my-registry\";\n\n    @BeforeEach\n    public void beforeEach() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void afterEach() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testBean() {\n\n        SysProps.setProperty(\"dubbo.application.owner\", \"Tom\");\n        SysProps.setProperty(\"dubbo.application.qos-enable\", \"false\");\n        SysProps.setProperty(\"dubbo.protocol.name\", \"dubbo\");\n        SysProps.setProperty(\"dubbo.protocol.port\", \"2346\");\n        String registryAddress = ZookeeperRegistryCenterConfig.getConnectionAddress();\n        SysProps.setProperty(\"dubbo.registry.address\", registryAddress);\n        SysProps.setProperty(\"dubbo.provider.group\", \"test\");\n\n        AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(\n                TestConfiguration.class, ConsumerConfiguration.class, ProviderConfiguration.class);\n        try {\n            consumerContext.start();\n\n            ConfigManager configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n            ApplicationConfig application = configManager.getApplication().get();\n            Assertions.assertEquals(false, application.getQosEnable());\n            Assertions.assertEquals(\"Tom\", application.getOwner());\n\n            RegistryConfig registry = configManager.getRegistry(MY_REGISTRY_ID).get();\n            Assertions.assertEquals(registryAddress, registry.getAddress());\n\n            Collection<ProtocolConfig> protocols = configManager.getProtocols();\n            Assertions.assertEquals(1, protocols.size());\n            ProtocolConfig protocolConfig = protocols.iterator().next();\n            Assertions.assertEquals(\"dubbo\", protocolConfig.getName());\n            Assertions.assertEquals(2346, protocolConfig.getPort());\n            Assertions.assertEquals(MY_PROTOCOL_ID, protocolConfig.getId());\n\n            ApplicationModel applicationModel = consumerContext.getBean(ApplicationModel.class);\n            ModuleConfigManager moduleConfigManager =\n                    applicationModel.getDefaultModule().getConfigManager();\n            ConsumerConfig consumerConfig =\n                    moduleConfigManager.getDefaultConsumer().get();\n            Assertions.assertEquals(1000, consumerConfig.getTimeout());\n            Assertions.assertEquals(\"demo\", consumerConfig.getGroup());\n            Assertions.assertEquals(false, consumerConfig.isCheck());\n            Assertions.assertEquals(2, consumerConfig.getRetries());\n\n            Map<String, ReferenceBean> referenceBeanMap = consumerContext.getBeansOfType(ReferenceBean.class);\n            Assertions.assertEquals(1, referenceBeanMap.size());\n            ReferenceBean referenceBean = referenceBeanMap.get(\"&demoService\");\n            Assertions.assertNotNull(referenceBean);\n            ReferenceConfig referenceConfig = referenceBean.getReferenceConfig();\n            // use consumer's attributes as default value\n            Assertions.assertEquals(consumerConfig.getTimeout(), referenceConfig.getTimeout());\n            Assertions.assertEquals(consumerConfig.getGroup(), referenceConfig.getGroup());\n            // consumer cannot override reference's attribute\n            Assertions.assertEquals(5, referenceConfig.getRetries());\n\n            DemoService referProxy = (DemoService) referenceConfig.get();\n            Assertions.assertTrue(referProxy instanceof DemoService);\n            String result = referProxy.sayName(\"dubbo\");\n            Assertions.assertEquals(\"say:dubbo\", result);\n\n        } finally {\n            consumerContext.close();\n        }\n    }\n\n    @EnableDubbo(scanBasePackages = \"org.apache.dubbo.config.spring.annotation.consumer\")\n    @Configuration\n    static class TestConfiguration {\n\n        @Bean(\"dubbo-demo-application\")\n        public ApplicationConfig applicationConfig() {\n            ApplicationConfig applicationConfig = new ApplicationConfig();\n            applicationConfig.setName(\"dubbo-demo-application\");\n            return applicationConfig;\n        }\n\n        @Bean(MY_PROTOCOL_ID)\n        public ProtocolConfig protocolConfig() {\n            ProtocolConfig protocolConfig = new ProtocolConfig();\n            protocolConfig.setName(\"rest\");\n            protocolConfig.setPort(1234);\n            return protocolConfig;\n        }\n\n        @Bean(MY_REGISTRY_ID)\n        public RegistryConfig registryConfig() {\n            RegistryConfig registryConfig = new RegistryConfig();\n            registryConfig.setAddress(\"N/A\");\n            return registryConfig;\n        }\n\n        @Bean\n        public ConsumerConfig consumerConfig() {\n            ConsumerConfig consumer = new ConsumerConfig();\n            consumer.setTimeout(1000);\n            consumer.setGroup(\"demo\");\n            consumer.setCheck(false);\n            consumer.setRetries(2);\n            return consumer;\n        }\n    }\n\n    @Configuration\n    static class ConsumerConfiguration {\n\n        @Bean\n        @DubboReference(scope = Constants.SCOPE_LOCAL, retries = 5)\n        public ReferenceBean<DemoService> demoService() {\n            return new ReferenceBean<>();\n        }\n    }\n\n    @Configuration\n    static class ProviderConfiguration {\n\n        @Bean\n        @DubboService(group = \"demo\")\n        public DemoService demoServiceImpl() {\n            return new DemoServiceImpl();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ServiceBeanTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport org.hamcrest.MatcherAssert;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.not;\nimport static org.hamcrest.CoreMatchers.nullValue;\nimport static org.mockito.Mockito.mock;\n\nclass ServiceBeanTest {\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testGetService() {\n        TestService service = mock(TestService.class);\n        ServiceBean serviceBean = new ServiceBean(null, service);\n\n        Service beanService = serviceBean.getService();\n        MatcherAssert.assertThat(beanService, not(nullValue()));\n    }\n\n    abstract class TestService implements Service {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/SimpleRegistryExporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.registry.RegistryService;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CALLBACK_INSTANCES_LIMIT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_STICKY_KEY;\n\npublic class SimpleRegistryExporter {\n\n    private static final Protocol protocol =\n            ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n\n    private static final ProxyFactory PROXY_FACTORY =\n            ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n\n    public static synchronized Exporter<RegistryService> exportIfAbsent(int port) {\n        try {\n            ServerSocket serverSocket = new ServerSocket();\n            if (NetUtils.isReuseAddressSupported()) {\n                // SO_REUSEADDR should be enabled before bind.\n                serverSocket.setReuseAddress(true);\n            }\n            serverSocket.bind(new InetSocketAddress(port));\n            serverSocket.close();\n            return export(port);\n        } catch (IOException e) {\n            return null;\n        }\n    }\n\n    public static Exporter<RegistryService> export(int port) {\n        return export(port, new SimpleRegistryService());\n    }\n\n    public static Exporter<RegistryService> export(int port, RegistryService registryService) {\n        return protocol.export(PROXY_FACTORY.getInvoker(\n                registryService,\n                RegistryService.class,\n                new URLBuilder(DUBBO_PROTOCOL, NetUtils.getLocalHost(), port, RegistryService.class.getName())\n                        .setPath(RegistryService.class.getName())\n                        .addParameter(INTERFACE_KEY, RegistryService.class.getName())\n                        .addParameter(CLUSTER_STICKY_KEY, \"true\")\n                        .addParameter(CALLBACK_INSTANCES_LIMIT_KEY, \"1000\")\n                        .addParameter(\"ondisconnect\", \"disconnect\")\n                        .addParameter(\"subscribe.1.callback\", \"true\")\n                        .addParameter(\"unsubscribe.1.callback\", \"false\")\n                        .build()));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/SimpleRegistryService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.RegistryService;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\npublic class SimpleRegistryService extends AbstractRegistryService {\n\n    private static final Logger logger = LoggerFactory.getLogger(SimpleRegistryService.class);\n    private final ConcurrentMap<String, ConcurrentMap<String, URL>> remoteRegistered =\n            new ConcurrentHashMap<String, ConcurrentMap<String, URL>>();\n    private final ConcurrentMap<String, ConcurrentMap<String, NotifyListener>> remoteListeners =\n            new ConcurrentHashMap<String, ConcurrentMap<String, NotifyListener>>();\n    private List<String> registries;\n\n    @Override\n    public void register(String service, URL url) {\n        super.register(service, url);\n        String client = RpcContext.getServiceContext().getRemoteAddressString();\n        Map<String, URL> urls =\n                ConcurrentHashMapUtils.computeIfAbsent(remoteRegistered, client, k -> new ConcurrentHashMap<>());\n        urls.put(service, url);\n        notify(service, getRegistered().get(service));\n    }\n\n    @Override\n    public void unregister(String service, URL url) {\n        super.unregister(service, url);\n        String client = RpcContext.getServiceContext().getRemoteAddressString();\n        Map<String, URL> urls = remoteRegistered.get(client);\n        if (urls != null && urls.size() > 0) {\n            urls.remove(service);\n        }\n        notify(service, getRegistered().get(service));\n    }\n\n    @Override\n    public void subscribe(String service, URL url, NotifyListener listener) {\n        String client = RpcContext.getServiceContext().getRemoteAddressString();\n        if (logger.isInfoEnabled()) {\n            logger.info(\"[subscribe] service: \" + service + \",client:\" + client);\n        }\n        List<URL> urls = getRegistered().get(service);\n        if ((RegistryService.class.getName() + \":0.0.0\").equals(service) && CollectionUtils.isEmpty(urls)) {\n            register(\n                    service,\n                    new ServiceConfigURL(\n                            \"dubbo\",\n                            NetUtils.getLocalHost(),\n                            RpcContext.getServiceContext().getLocalPort(),\n                            RegistryService.class.getName(),\n                            url.getParameters()));\n            List<String> rs = registries;\n            if (rs != null && rs.size() > 0) {\n                for (String registry : rs) {\n                    register(service, UrlUtils.parseURL(registry, url.getParameters()));\n                }\n            }\n        }\n        super.subscribe(service, url, listener);\n\n        Map<String, NotifyListener> listeners =\n                ConcurrentHashMapUtils.computeIfAbsent(remoteListeners, client, k -> new ConcurrentHashMap<>());\n        listeners.put(service, listener);\n        urls = getRegistered().get(service);\n        if (urls != null && urls.size() > 0) {\n            listener.notify(urls);\n        }\n    }\n\n    @Override\n    public void unsubscribe(String service, URL url, NotifyListener listener) {\n        super.unsubscribe(service, url, listener);\n        String client = RpcContext.getServiceContext().getRemoteAddressString();\n        Map<String, NotifyListener> listeners = remoteListeners.get(client);\n        if (listeners != null && listeners.size() > 0) {\n            listeners.remove(service);\n        }\n        List<URL> urls = getRegistered().get(service);\n        if (urls != null && urls.size() > 0) {\n            listener.notify(urls);\n        }\n    }\n\n    public void disconnect() {\n        String client = RpcContext.getServiceContext().getRemoteAddressString();\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Disconnected \" + client);\n        }\n        ConcurrentMap<String, URL> urls = remoteRegistered.get(client);\n        if (urls != null && urls.size() > 0) {\n            for (Map.Entry<String, URL> entry : urls.entrySet()) {\n                super.unregister(entry.getKey(), entry.getValue());\n            }\n        }\n        Map<String, NotifyListener> listeners = remoteListeners.get(client);\n        if (listeners != null && listeners.size() > 0) {\n            for (Map.Entry<String, NotifyListener> entry : listeners.entrySet()) {\n                String service = entry.getKey();\n                super.unsubscribe(\n                        service,\n                        new ServiceConfigURL(\n                                \"subscribe\",\n                                RpcContext.getServiceContext().getRemoteHost(),\n                                RpcContext.getServiceContext().getRemotePort(),\n                                RegistryService.class.getName(),\n                                getSubscribed(service)),\n                        entry.getValue());\n            }\n        }\n    }\n\n    public List<String> getRegistries() {\n        return registries;\n    }\n\n    public void setRegistries(List<String> registries) {\n        this.registries = registries;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/SysProps.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * Use to set and clear System property\n */\npublic class SysProps {\n\n    private static Map<String, String> map = new LinkedHashMap<String, String>();\n\n    public static void reset() {\n        map.clear();\n    }\n\n    public static void setProperty(String key, String value) {\n        map.put(key, value);\n        System.setProperty(key, value);\n    }\n\n    public static void clear() {\n        for (String key : map.keySet()) {\n            System.clearProperty(key);\n        }\n        reset();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoActionByAnnotation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.action;\n\nimport org.apache.dubbo.config.spring.api.DemoService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\n\n/**\n * DemoAction\n */\npublic class DemoActionByAnnotation {\n\n    @Autowired\n    private DemoService demoService;\n\n    public DemoService getDemoService() {\n        return demoService;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoActionBySetter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.action;\n\nimport org.apache.dubbo.config.spring.api.DemoService;\n\n/**\n * DemoAction\n */\npublic class DemoActionBySetter {\n\n    private DemoService demoService;\n\n    public DemoService getDemoService() {\n        return demoService;\n    }\n\n    public void setDemoService(DemoService demoService) {\n        this.demoService = demoService;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoInterceptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.action;\n\nimport org.aopalliance.intercept.MethodInterceptor;\nimport org.aopalliance.intercept.MethodInvocation;\n\npublic class DemoInterceptor implements MethodInterceptor {\n\n    public Object invoke(MethodInvocation invocation) throws Throwable {\n        return \"aop:\" + invocation.proceed();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/consumer/AnnotationAction.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.annotation.consumer;\n\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\nimport org.springframework.stereotype.Controller;\n\n@Controller(\"annotationAction\")\npublic class AnnotationAction {\n\n    @Reference(\n            version = \"1.2\",\n            methods = {@Method(name = \"sayName\", timeout = 5000)})\n    private DemoService demoService;\n\n    public String doSayName(String name) {\n        return demoService.sayName(name);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/merged/MergedReference.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.annotation.merged;\n\nimport org.apache.dubbo.config.annotation.Reference;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.core.annotation.AliasFor;\n\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})\n@Reference\npublic @interface MergedReference {\n\n    @AliasFor(annotation = Reference.class, attribute = \"group\")\n    String group() default \"dubbo\";\n\n    @AliasFor(annotation = Reference.class, attribute = \"version\")\n    String version() default \"1.0.0\";\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/merged/MergedService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.annotation.merged;\n\nimport org.apache.dubbo.config.annotation.Service;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.core.annotation.AliasFor;\n\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE})\n@Service\npublic @interface MergedService {\n\n    @AliasFor(annotation = Service.class, attribute = \"group\")\n    String group() default \"dubbo\";\n\n    @AliasFor(annotation = Service.class, attribute = \"version\")\n    String version() default \"1.0.0\";\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/provider/AnnotationServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.annotation.provider;\n\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\n/**\n * DemoServiceImpl\n */\n@Service(version = \"${provider.version}\")\npublic class AnnotationServiceImpl implements DemoService {\n\n    public String sayName(String name) {\n        return \"annotation:\" + name;\n    }\n\n    public Box getBox() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/api/Box.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\npublic interface Box {\n\n    String getName();\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/api/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\npublic interface DemoService {\n\n    String sayName(String name);\n\n    Box getBox();\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/api/DemoServiceSon.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\n/**\n * DemoService\n */\npublic interface DemoServiceSon extends DemoService {\n    // no methods\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/api/HelloService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\npublic interface HelloService {\n    String sayHello(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/api/MethodCallback.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\npublic interface MethodCallback {\n    void oninvoke1(String request);\n\n    void onreturn1(String response, String request);\n\n    void onthrow1(Throwable ex, String request);\n\n    void oninvoke2(String request);\n\n    void onreturn2(String response, String request);\n\n    void onthrow2(Throwable ex, String request);\n\n    String getOnInvoke1();\n\n    String getOnReturn1();\n\n    String getOnThrow1();\n\n    String getOnInvoke2();\n\n    String getOnReturn2();\n\n    String getOnThrow2();\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/api/ProvidedByDemoService1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\nimport org.apache.dubbo.config.annotation.ProvidedBy;\n\n/**\n * DemoService\n */\n@ProvidedBy(name = \"provided-demo-service-interface\")\npublic interface ProvidedByDemoService1 {\n\n    String sayName(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/api/ProvidedByDemoService2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\n/**\n * DemoService\n */\npublic interface ProvidedByDemoService2 {\n\n    String sayName(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/api/ProvidedByDemoService3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\nimport org.apache.dubbo.config.annotation.ProvidedBy;\n\n/**\n * DemoService\n */\n@ProvidedBy(name = {\"provided-demo-service-interface1\", \"provided-demo-service-interface2\"})\npublic interface ProvidedByDemoService3 {\n\n    String sayName(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/api/SpringControllerService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.api;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n@RequestMapping(\"/controller\")\npublic class SpringControllerService {\n\n    @GetMapping(\"/sayHello\")\n    public String sayHello(String say) {\n        return say;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigAliasPostProcessorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nclass DubboConfigAliasPostProcessorTest {\n\n    private static final String APP_NAME = \"APP_NAME\";\n    private static final String APP_ID = \"APP_ID\";\n\n    @BeforeEach\n    void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void test() {\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfigurationX.class);\n        try {\n            context.start();\n            Assertions.assertEquals(context.getAliases(APP_NAME)[0], APP_ID);\n            Assertions.assertEquals(context.getAliases(APP_ID)[0], APP_NAME);\n            Assertions.assertEquals(context.getBean(APP_NAME), context.getBean(APP_ID));\n        } finally {\n            context.close();\n        }\n    }\n\n    @EnableDubbo(scanBasePackages = \"\")\n    @Configuration\n    static class TestConfigurationX {\n\n        @Bean(APP_NAME)\n        public ApplicationConfig applicationConfig() {\n            ApplicationConfig applicationConfig = new ApplicationConfig();\n            applicationConfig.setName(APP_NAME);\n            applicationConfig.setId(APP_ID);\n            return applicationConfig;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/MergedAnnotationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.spring.annotation.merged.MergedReference;\nimport org.apache.dubbo.config.spring.annotation.merged.MergedService;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\nimport java.lang.reflect.Field;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\nimport org.springframework.util.ReflectionUtils;\n\nclass MergedAnnotationTest {\n\n    @Test\n    void testMergedReference() {\n        Field field = ReflectionUtils.findField(TestBean1.class, \"demoService\");\n        Reference reference = AnnotatedElementUtils.getMergedAnnotation(field, Reference.class);\n        Assertions.assertEquals(\"dubbo\", reference.group());\n        Assertions.assertEquals(\"1.0.0\", reference.version());\n\n        Field field2 = ReflectionUtils.findField(TestBean2.class, \"demoService\");\n        Reference reference2 = AnnotatedElementUtils.getMergedAnnotation(field2, Reference.class);\n        Assertions.assertEquals(\"group\", reference2.group());\n        Assertions.assertEquals(\"2.0\", reference2.version());\n    }\n\n    @Test\n    void testMergedService() {\n        Service service1 = AnnotatedElementUtils.getMergedAnnotation(DemoServiceImpl1.class, Service.class);\n        Assertions.assertEquals(\"dubbo\", service1.group());\n        Assertions.assertEquals(\"1.0.0\", service1.version());\n\n        Service service2 = AnnotatedElementUtils.getMergedAnnotation(DemoServiceImpl2.class, Service.class);\n        Assertions.assertEquals(\"group\", service2.group());\n        Assertions.assertEquals(\"2.0\", service2.version());\n    }\n\n    @MergedService\n    public static class DemoServiceImpl1 {}\n\n    @MergedService(group = \"group\", version = \"2.0\")\n    public static class DemoServiceImpl2 {}\n\n    private static class TestBean1 {\n        @MergedReference\n        private DemoService demoService;\n    }\n\n    private static class TestBean2 {\n        @MergedReference(group = \"group\", version = \"2.0\")\n        private DemoService demoService;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/MethodConfigCallbackTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.api.MethodCallback;\nimport org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration;\nimport org.apache.dubbo.config.spring.impl.MethodCallbackImpl;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.awaitility.Awaitility.await;\n\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(\n        classes = {\n            ProviderConfiguration.class,\n            MethodConfigCallbackTest.class,\n            MethodConfigCallbackTest.MethodCallbackConfiguration.class\n        })\n@TestPropertySource(\n        properties = {\n            \"dubbo.protocol.port=-1\",\n            \"dubbo.registry.address=${zookeeper.connection.address}\",\n            \"dubbo.metrics.enabled = false\",\n            \"dubbo.metrics.protocol = disabled\"\n        })\n@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)\n@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)\nclass MethodConfigCallbackTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private ConfigurableApplicationContext context;\n\n    @DubboReference(\n            check = false,\n            async = true,\n            injvm = false, // Currently, local call is not supported method callback cause by Injvm protocol is not\n            // supported ClusterFilter\n            methods = {\n                @Method(\n                        name = \"sayHello\",\n                        oninvoke = \"methodCallback.oninvoke1\",\n                        onreturn = \"methodCallback.onreturn1\",\n                        onthrow = \"methodCallback.onthrow1\")\n            })\n    private HelloService helloServiceMethodCallBack;\n\n    @DubboReference(\n            check = false,\n            async = true,\n            injvm = false, // Currently, local call is not supported method callback cause by Injvm protocol is not\n            // supported ClusterFilter\n            methods = {\n                @Method(\n                        name = \"sayHello\",\n                        oninvoke = \"methodCallback.oninvoke2\",\n                        onreturn = \"methodCallback.onreturn2\",\n                        onthrow = \"methodCallback.onthrow2\")\n            })\n    private HelloService helloServiceMethodCallBack2;\n\n    @Test\n    void testMethodAnnotationCallBack() {\n        int threadCnt = Math.min(4, Runtime.getRuntime().availableProcessors());\n        int callCnt = 2 * threadCnt;\n        for (int i = 0; i < threadCnt; i++) {\n            new Thread(() -> {\n                        for (int j = 0; j < callCnt; j++) {\n                            helloServiceMethodCallBack.sayHello(\"dubbo\");\n                            helloServiceMethodCallBack2.sayHello(\"dubbo(2)\");\n                        }\n                    })\n                    .start();\n        }\n        await().until(() -> MethodCallbackImpl.cnt.get() >= (2 * threadCnt * callCnt));\n        MethodCallback notify = (MethodCallback) context.getBean(\"methodCallback\");\n        StringBuilder invoke1Builder = new StringBuilder();\n        StringBuilder invoke2Builder = new StringBuilder();\n        StringBuilder return1Builder = new StringBuilder();\n        StringBuilder return2Builder = new StringBuilder();\n        for (int i = 0; i < threadCnt * callCnt; i++) {\n            invoke1Builder.append(\"dubbo invoke success!\");\n            invoke2Builder.append(\"dubbo invoke success(2)!\");\n            return1Builder.append(\"dubbo return success!\");\n            return2Builder.append(\"dubbo return success(2)!\");\n        }\n        Assertions.assertEquals(invoke1Builder.toString(), notify.getOnInvoke1());\n        Assertions.assertEquals(return1Builder.toString(), notify.getOnReturn1());\n        Assertions.assertEquals(invoke2Builder.toString(), notify.getOnInvoke2());\n        Assertions.assertEquals(return2Builder.toString(), notify.getOnReturn2());\n    }\n\n    @Configuration\n    static class MethodCallbackConfiguration {\n\n        @Bean(\"methodCallback\")\n        public MethodCallback methodCallback() {\n            return new MethodCallbackImpl();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ParameterConvertTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.spring.util.DubboAnnotationUtils;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.test.annotation.DirtiesContext;\n\n/**\n * {@link DubboAnnotationUtils#convertParameters} Test\n */\n@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)\nclass ParameterConvertTest {\n\n    @Test\n    void test() {\n        /**\n         *     (array->map)\n         *     [\"a\",\"b\"] ==> {a=b}\n         *     [\" a \",\" b \"] ==> {a=b}\n         *     [\"a=b\"] ==>{a=b}\n         *     [\"a:b\"] ==>{a=b}\n         *     [\"a=b\",\"c\",\"d\"] ==>{a=b,c=d}\n         *     [\"a=b\",\"c:d\"] ==>{a=b,c=d}\n         *     [\"a\",\"a:b\"] ==>{a=a:b}\n         */\n        Map<String, String> parametersMap = new HashMap<>();\n        parametersMap.put(\"a\", \"b\");\n        Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[] {\"a\", \"b\"}));\n        Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[] {\" a \", \" b \"}));\n        Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[] {\"a=b\"}));\n        Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[] {\"a:b\"}));\n\n        parametersMap.put(\"c\", \"d\");\n        Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[] {\"a=b\", \"c\", \"d\"}));\n        Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[] {\"a:b\", \"c=d\"}));\n\n        parametersMap.clear();\n        parametersMap.put(\"a\", \"a:b\");\n        Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[] {\"a\", \"a:b\"}));\n\n        parametersMap.clear();\n        parametersMap.put(\"a\", \"0,100\");\n        Assertions.assertEquals(parametersMap, DubboAnnotationUtils.convertParameters(new String[] {\"a\", \"0,100\"}));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.reference.ReferenceBeanManager;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport java.net.InetSocketAddress;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.InjectionMetadata;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.stereotype.Component;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n/**\n * {@link ReferenceAnnotationBeanPostProcessor} Test\n *\n * @since 2.5.7\n */\n@EnableDubbo(scanBasePackages = \"org.apache.dubbo.config.spring.context.annotation.provider\")\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(\n        classes = {\n            ServiceAnnotationTestConfiguration.class,\n            ReferenceAnnotationBeanPostProcessorTest.class,\n            ReferenceAnnotationBeanPostProcessorTest.MyConfiguration.class,\n            ReferenceAnnotationBeanPostProcessorTest.TestAspect.class\n        })\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\n@TestPropertySource(\n        properties = {\n            \"consumer.version = ${demo.service.version}\",\n            \"consumer.url = dubbo://127.0.0.1:12345?version=2.5.7\",\n            \"dubbo.metrics.enabled = false\",\n            \"dubbo.metrics.protocol = disabled\"\n        })\n@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)\nclass ReferenceAnnotationBeanPostProcessorTest {\n\n    @BeforeAll\n    public static void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n    }\n\n    private static final String AOP_SUFFIX = \"(based on AOP)\";\n\n    @Aspect\n    @Component\n    public static class TestAspect {\n\n        @Around(\"execution(* org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl.*(..))\")\n        public Object aroundDemoService(ProceedingJoinPoint pjp) throws Throwable {\n            return pjp.proceed() + AOP_SUFFIX + \" from \"\n                    + RpcContext.getContext().getLocalAddress();\n        }\n\n        @Around(\"execution(* org.apache.dubbo.config.spring.context.annotation.provider.*HelloService*.*(..))\")\n        public Object aroundHelloService(ProceedingJoinPoint pjp) throws Throwable {\n            return pjp.proceed() + AOP_SUFFIX + \" from \"\n                    + RpcContext.getContext().getLocalAddress();\n        }\n    }\n\n    @Autowired\n    private ConfigurableApplicationContext context;\n\n    @Autowired\n    private HelloService defaultHelloService;\n\n    @Autowired\n    private HelloService helloServiceImpl;\n\n    @Autowired\n    private DemoService demoServiceImpl;\n\n    // #5 ReferenceBean (Field Injection #3)\n    @Reference(id = \"helloService\", methods = @Method(name = \"sayHello\", timeout = 100))\n    private HelloService helloService;\n\n    // #6 ReferenceBean (Field Injection #4)\n    @DubboReference(version = \"2\", url = \"dubbo://127.0.0.1:12345?version=2\", tag = \"demo_tag\")\n    private HelloService helloService2;\n\n    // #7 ReferenceBean (Field Injection #5)\n    // The HelloService is the same as above service(#6 ReferenceBean (Field Injection #4)), helloService3 will be\n    // registered as an alias of helloService2\n    @DubboReference(version = \"2\", url = \"dubbo://127.0.0.1:12345?version=2\", tag = \"demo_tag\")\n    private HelloService helloService3;\n\n    // #8 ReferenceBean (Method Injection #3)\n    @DubboReference(version = \"3\", url = \"dubbo://127.0.0.1:12345?version=2\", tag = \"demo_tag\")\n    public void setHelloService2(HelloService helloService2) {\n        // The helloService2 beanName is the same as above(#6 ReferenceBean (Field Injection #4)), and this will rename\n        // to helloService2#2\n        renamedHelloService2 = helloService2;\n    }\n\n    // #9 ReferenceBean (Method Injection #4)\n    @DubboReference(version = \"4\", url = \"dubbo://127.0.0.1:12345?version=2\")\n    public void setHelloService3(DemoService helloService3) {\n        // The helloService3 beanName is the same as above(#7 ReferenceBean (Field Injection #5) is an alias),\n        // The current beanName(helloService3) is not registered in the beanDefinitionMap, but it is already an alias.\n        // so this will rename to helloService3#2\n        this.renamedHelloService3 = helloService3;\n    }\n\n    private HelloService renamedHelloService2;\n\n    private DemoService renamedHelloService3;\n\n    @Test\n    void testAop() throws Exception {\n\n        Assertions.assertTrue(context.containsBean(\"helloService\"));\n\n        TestBean testBean = context.getBean(TestBean.class);\n\n        Map<String, DemoService> demoServicesMap = context.getBeansOfType(DemoService.class);\n\n        Assertions.assertNotNull(testBean.getDemoServiceFromAncestor());\n        Assertions.assertNotNull(testBean.getDemoServiceFromParent());\n        Assertions.assertNotNull(testBean.getDemoService());\n        Assertions.assertNotNull(testBean.myDemoService);\n        Assertions.assertEquals(3, demoServicesMap.size());\n\n        Assertions.assertNotNull(context.getBean(\"demoServiceImpl\"));\n        Assertions.assertNotNull(context.getBean(\"myDemoService\"));\n        Assertions.assertNotNull(context.getBean(\"demoService\"));\n        Assertions.assertNotNull(context.getBean(\"demoServiceFromParent\"));\n\n        String callSuffix = AOP_SUFFIX + \" from \" + InetSocketAddress.createUnresolved(NetUtils.getLocalHost(), 12345);\n        String localCallSuffix = AOP_SUFFIX + \" from \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0);\n        String directInvokeSuffix = AOP_SUFFIX + \" from null\";\n\n        String defaultHelloServiceResult = \"Greeting, Mercy\";\n        Assertions.assertEquals(defaultHelloServiceResult + directInvokeSuffix, defaultHelloService.sayHello(\"Mercy\"));\n        Assertions.assertEquals(defaultHelloServiceResult + localCallSuffix, helloService.sayHello(\"Mercy\"));\n\n        String helloServiceImplResult = \"Hello, Mercy\";\n        Assertions.assertEquals(helloServiceImplResult + directInvokeSuffix, helloServiceImpl.sayHello(\"Mercy\"));\n        Assertions.assertEquals(helloServiceImplResult + callSuffix, helloService2.sayHello(\"Mercy\"));\n\n        String demoServiceResult = \"Hello,Mercy\";\n        Assertions.assertEquals(demoServiceResult + directInvokeSuffix, demoServiceImpl.sayName(\"Mercy\"));\n        Assertions.assertEquals(\n                demoServiceResult + callSuffix,\n                testBean.getDemoServiceFromAncestor().sayName(\"Mercy\"));\n        Assertions.assertEquals(demoServiceResult + callSuffix, testBean.myDemoService.sayName(\"Mercy\"));\n        Assertions.assertEquals(\n                demoServiceResult + callSuffix, testBean.getDemoService().sayName(\"Mercy\"));\n        Assertions.assertEquals(\n                demoServiceResult + callSuffix,\n                testBean.getDemoServiceFromParent().sayName(\"Mercy\"));\n\n        DemoService myDemoService = context.getBean(\"myDemoService\", DemoService.class);\n        Assertions.assertEquals(demoServiceResult + callSuffix, myDemoService.sayName(\"Mercy\"));\n    }\n\n    @Test\n    void testGetInjectedFieldReferenceBeanMap() {\n\n        ReferenceAnnotationBeanPostProcessor beanPostProcessor = getReferenceAnnotationBeanPostProcessor();\n\n        Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> referenceBeanMap =\n                beanPostProcessor.getInjectedFieldReferenceBeanMap();\n\n        Assertions.assertEquals(5, referenceBeanMap.size());\n\n        Map<String, Integer> checkingFieldNames = new HashMap<>();\n        checkingFieldNames.put(\n                \"private org.apache.dubbo.config.spring.api.HelloService org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessorTest$MyConfiguration.helloService\",\n                0);\n        checkingFieldNames.put(\n                \"private org.apache.dubbo.config.spring.api.HelloService org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessorTest.helloService\",\n                0);\n        checkingFieldNames.put(\n                \"private org.apache.dubbo.config.spring.api.HelloService org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessorTest.helloService2\",\n                0);\n        checkingFieldNames.put(\n                \"private org.apache.dubbo.config.spring.api.HelloService org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessorTest.helloService3\",\n                0);\n        checkingFieldNames.put(\n                \"private org.apache.dubbo.config.spring.api.DemoService org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessorTest$ParentBean.demoServiceFromParent\",\n                0);\n\n        for (Map.Entry<InjectionMetadata.InjectedElement, ReferenceBean<?>> entry : referenceBeanMap.entrySet()) {\n            InjectionMetadata.InjectedElement injectedElement = entry.getKey();\n            String member = injectedElement.getMember().toString();\n            Integer count = checkingFieldNames.get(member);\n            Assertions.assertNotNull(count);\n            checkingFieldNames.put(member, count + 1);\n        }\n\n        for (Map.Entry<String, Integer> entry : checkingFieldNames.entrySet()) {\n            Assertions.assertEquals(1, entry.getValue().intValue(), \"check field element failed: \" + entry.getKey());\n        }\n    }\n\n    private ReferenceAnnotationBeanPostProcessor getReferenceAnnotationBeanPostProcessor() {\n        return DubboBeanUtils.getReferenceAnnotationBeanPostProcessor(context);\n    }\n\n    @Test\n    void testGetInjectedMethodReferenceBeanMap() {\n\n        ReferenceAnnotationBeanPostProcessor beanPostProcessor = getReferenceAnnotationBeanPostProcessor();\n\n        Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> referenceBeanMap =\n                beanPostProcessor.getInjectedMethodReferenceBeanMap();\n\n        Assertions.assertEquals(4, referenceBeanMap.size());\n\n        Map<String, Integer> checkingMethodNames = new HashMap<>();\n        checkingMethodNames.put(\"setDemoServiceFromAncestor\", 0);\n        checkingMethodNames.put(\"setDemoService\", 0);\n        checkingMethodNames.put(\"setHelloService2\", 0);\n        checkingMethodNames.put(\"setHelloService3\", 0);\n\n        for (Map.Entry<InjectionMetadata.InjectedElement, ReferenceBean<?>> entry : referenceBeanMap.entrySet()) {\n\n            InjectionMetadata.InjectedElement injectedElement = entry.getKey();\n            java.lang.reflect.Method method = (java.lang.reflect.Method) injectedElement.getMember();\n            Integer count = checkingMethodNames.get(method.getName());\n            Assertions.assertNotNull(count);\n            Assertions.assertEquals(0, count.intValue());\n            checkingMethodNames.put(method.getName(), count + 1);\n        }\n\n        for (Map.Entry<String, Integer> entry : checkingMethodNames.entrySet()) {\n            Assertions.assertEquals(1, entry.getValue().intValue(), \"check method element failed: \" + entry.getKey());\n        }\n    }\n\n    @Test\n    void testReferenceBeansMethodAnnotation() {\n\n        ReferenceBeanManager referenceBeanManager =\n                context.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);\n\n        Collection<ReferenceBean> referenceBeans = referenceBeanManager.getReferences();\n\n        Assertions.assertEquals(5, referenceBeans.size());\n\n        for (ReferenceBean referenceBean : referenceBeans) {\n            ReferenceConfig referenceConfig = referenceBean.getReferenceConfig();\n            Assertions.assertNotNull(referenceConfig);\n            Assertions.assertNotNull(referenceConfig.get());\n        }\n\n        ReferenceBean helloServiceReferenceBean = referenceBeanManager.getById(\"helloService\");\n        Assertions.assertEquals(\"helloService\", helloServiceReferenceBean.getId());\n        ReferenceConfig referenceConfig = helloServiceReferenceBean.getReferenceConfig();\n        Assertions.assertEquals(1, referenceConfig.getMethods().size());\n\n        ReferenceBean demoServiceFromParentReferenceBean = referenceBeanManager.getById(\"demoServiceFromParent\");\n        ReferenceBean demoServiceReferenceBean = referenceBeanManager.getById(\"demoService\");\n        Assertions.assertEquals(demoServiceFromParentReferenceBean.getKey(), demoServiceReferenceBean.getKey());\n        Assertions.assertEquals(\n                demoServiceFromParentReferenceBean.getReferenceConfig(), demoServiceReferenceBean.getReferenceConfig());\n        Assertions.assertSame(demoServiceFromParentReferenceBean, demoServiceReferenceBean);\n\n        ReferenceBean helloService2Bean = referenceBeanManager.getById(\"helloService2\");\n        Assertions.assertNotNull(helloService2Bean);\n        Assertions.assertNotNull(helloService2Bean.getReferenceConfig());\n        Assertions.assertEquals(\n                \"demo_tag\", helloService2Bean.getReferenceConfig().getTag());\n\n        Assertions.assertNotNull(referenceBeanManager.getById(\"myDemoService\"));\n        Assertions.assertNotNull(referenceBeanManager.getById(\"helloService2#2\"));\n    }\n\n    private static class AncestorBean {\n\n        private DemoService demoServiceFromAncestor;\n\n        @Autowired\n        private ApplicationContext applicationContext;\n\n        public DemoService getDemoServiceFromAncestor() {\n            return demoServiceFromAncestor;\n        }\n\n        // #4 ReferenceBean (Method Injection #2)\n        @Reference(id = \"myDemoService\", version = \"2.5.7\", url = \"dubbo://127.0.0.1:12345?version=2.5.7\")\n        public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) {\n            this.demoServiceFromAncestor = demoServiceFromAncestor;\n        }\n\n        public ApplicationContext getApplicationContext() {\n            return applicationContext;\n        }\n    }\n\n    private static class ParentBean extends AncestorBean {\n\n        // #2 ReferenceBean (Field Injection #2)\n        @Reference(version = \"${consumer.version}\", url = \"${consumer.url}\")\n        private DemoService demoServiceFromParent;\n\n        public DemoService getDemoServiceFromParent() {\n            return demoServiceFromParent;\n        }\n    }\n\n    static class TestBean extends ParentBean {\n\n        private DemoService demoService;\n\n        @Autowired\n        private DemoService myDemoService;\n\n        @Autowired\n        private ApplicationContext applicationContext;\n\n        public DemoService getDemoService() {\n            return demoService;\n        }\n\n        // #3 ReferenceBean (Method Injection #1)\n        @Reference(version = \"2.5.7\", url = \"dubbo://127.0.0.1:12345?version=2.5.7\")\n        public void setDemoService(DemoService demoService) {\n            this.demoService = demoService;\n        }\n    }\n\n    @Configuration\n    static class MyConfiguration {\n\n        // #1 ReferenceBean (Field Injection #1)\n        @Reference(methods = @Method(name = \"sayHello\", timeout = 100))\n        private HelloService helloService;\n\n        @Bean\n        public TestBean testBean() {\n            return new TestBean();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceCreatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.ArgumentConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MethodConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.annotation.Argument;\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.impl.NotifyService;\nimport org.apache.dubbo.config.spring.reference.ReferenceCreator;\nimport org.apache.dubbo.config.spring.util.AnnotationUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.apache.dubbo.common.utils.CollectionUtils.ofSet;\nimport static org.springframework.core.annotation.AnnotationUtils.findAnnotation;\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\nimport static org.springframework.util.ReflectionUtils.findField;\n\n/**\n * {@link ReferenceCreator} Test\n *\n * @see ReferenceCreator\n * @see DubboReference\n * @see Reference\n * @since 2.6.4\n */\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = {ReferenceCreatorTest.class, ReferenceCreatorTest.ConsumerConfiguration.class})\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\nclass ReferenceCreatorTest {\n\n    private static final String MODULE_CONFIG_ID = \"mymodule\";\n    private static final String CONSUMER_CONFIG_ID = \"myconsumer\";\n    private static final String MONITOR_CONFIG_ID = \"mymonitor\";\n    private static final String REGISTRY_CONFIG_ID = \"myregistry\";\n\n    @DubboReference(\n            // interfaceClass = HelloService.class,\n            version = \"1.0.0\",\n            group = \"TEST_GROUP\",\n            url = \"dubbo://localhost:12345\",\n            client = \"client\",\n            generic = false,\n            injvm = false,\n            check = false,\n            init = false,\n            lazy = true,\n            stubevent = true,\n            reconnect = \"reconnect\",\n            sticky = true,\n            proxy = \"javassist\",\n            stub = \"org.apache.dubbo.config.spring.api.HelloService\",\n            cluster = \"failover\",\n            connections = 3,\n            callbacks = 1,\n            onconnect = \"onconnect\",\n            ondisconnect = \"ondisconnect\",\n            owner = \"owner\",\n            layer = \"layer\",\n            retries = 1,\n            loadbalance = \"random\",\n            async = true,\n            actives = 3,\n            sent = true,\n            mock = \"mock\",\n            validation = \"validation\",\n            timeout = 3,\n            cache = \"cache\",\n            filter = {\"echo\", \"generic\", \"accesslog\"},\n            listener = {\"deprecated\"},\n            parameters = {\"n1=v1  \", \"n2 = v2 \", \"  n3 =   v3  \"},\n            application = \"application\",\n            module = MODULE_CONFIG_ID,\n            consumer = CONSUMER_CONFIG_ID,\n            monitor = MONITOR_CONFIG_ID,\n            registry = {REGISTRY_CONFIG_ID},\n            // @since 2.7.3\n            id = \"reference\",\n            // @since 2.7.8\n            services = {\"service1\", \"service2\", \"service3\", \"service2\", \"service1\"},\n            providedBy = {\"service1\", \"service2\", \"service3\"},\n            methods =\n                    @Method(\n                            name = \"sayHello\",\n                            isReturn = false,\n                            loadbalance = \"loadbalance\",\n                            oninvoke = \"notifyService.onInvoke\",\n                            onreturn = \"notifyService.onReturn\",\n                            onthrow = \"notifyService.onThrow\",\n                            timeout = 1000,\n                            retries = 2,\n                            parameters = {\"a\", \"1\", \"b\", \"2\"},\n                            arguments = @Argument(index = 0, callback = true)))\n    private HelloService helloService;\n\n    @Autowired\n    private ApplicationContext context;\n\n    @Autowired\n    private NotifyService notifyService;\n\n    @BeforeAll\n    public static void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    void testBuild() throws Exception {\n\n        Field helloServiceField = findField(getClass(), \"helloService\");\n        DubboReference reference = findAnnotation(helloServiceField, DubboReference.class);\n        // filter default value\n        AnnotationAttributes attributes = AnnotationUtils.getAnnotationAttributes(reference, true);\n        ReferenceConfig referenceBean = ReferenceCreator.create(attributes, context)\n                .defaultInterfaceClass(helloServiceField.getType())\n                .build();\n        Assertions.assertEquals(HelloService.class, referenceBean.getInterfaceClass());\n        Assertions.assertEquals(\"org.apache.dubbo.config.spring.api.HelloService\", referenceBean.getInterface());\n        Assertions.assertEquals(\"1.0.0\", referenceBean.getVersion());\n        Assertions.assertEquals(\"TEST_GROUP\", referenceBean.getGroup());\n        Assertions.assertEquals(\"dubbo://localhost:12345\", referenceBean.getUrl());\n        Assertions.assertEquals(\"client\", referenceBean.getClient());\n        Assertions.assertEquals(null, referenceBean.isGeneric());\n        Assertions.assertEquals(false, referenceBean.isInjvm());\n        Assertions.assertEquals(false, referenceBean.isCheck());\n        Assertions.assertEquals(false, referenceBean.isInit());\n        Assertions.assertEquals(true, referenceBean.getLazy());\n        Assertions.assertEquals(true, referenceBean.getStubevent());\n        Assertions.assertEquals(\"reconnect\", referenceBean.getReconnect());\n        Assertions.assertEquals(true, referenceBean.getSticky());\n        Assertions.assertEquals(\"javassist\", referenceBean.getProxy());\n        Assertions.assertEquals(\"org.apache.dubbo.config.spring.api.HelloService\", referenceBean.getStub());\n        Assertions.assertEquals(\"failover\", referenceBean.getCluster());\n        Assertions.assertEquals(Integer.valueOf(3), referenceBean.getConnections());\n        Assertions.assertEquals(Integer.valueOf(1), referenceBean.getCallbacks());\n        Assertions.assertEquals(\"onconnect\", referenceBean.getOnconnect());\n        Assertions.assertEquals(\"ondisconnect\", referenceBean.getOndisconnect());\n        Assertions.assertEquals(\"owner\", referenceBean.getOwner());\n        Assertions.assertEquals(\"layer\", referenceBean.getLayer());\n        Assertions.assertEquals(Integer.valueOf(1), referenceBean.getRetries());\n        Assertions.assertEquals(\"random\", referenceBean.getLoadbalance());\n        Assertions.assertEquals(true, referenceBean.isAsync());\n        Assertions.assertEquals(Integer.valueOf(3), referenceBean.getActives());\n        Assertions.assertEquals(true, referenceBean.getSent());\n        Assertions.assertEquals(\"mock\", referenceBean.getMock());\n        Assertions.assertEquals(\"validation\", referenceBean.getValidation());\n        Assertions.assertEquals(Integer.valueOf(3), referenceBean.getTimeout());\n        Assertions.assertEquals(\"cache\", referenceBean.getCache());\n        Assertions.assertEquals(\"echo,generic,accesslog\", referenceBean.getFilter());\n        Assertions.assertEquals(\"deprecated\", referenceBean.getListener());\n        Assertions.assertEquals(\"reference\", referenceBean.getId());\n        Assertions.assertEquals(ofSet(\"service1\", \"service2\", \"service3\"), referenceBean.getSubscribedServices());\n        Assertions.assertEquals(\"service1,service2,service3\", referenceBean.getProvidedBy());\n        Assertions.assertEquals(REGISTRY_CONFIG_ID, referenceBean.getRegistryIds());\n\n        // parameters\n        Map<String, String> parameters = new HashMap<String, String>();\n        parameters.put(\"n1\", \"v1\");\n        parameters.put(\"n2\", \"v2\");\n        parameters.put(\"n3\", \"v3\");\n        Assertions.assertEquals(parameters, referenceBean.getParameters());\n\n        // methods\n        List<MethodConfig> methods = referenceBean.getMethods();\n        Assertions.assertNotNull(methods);\n        Assertions.assertEquals(1, methods.size());\n        MethodConfig methodConfig = methods.get(0);\n        Assertions.assertEquals(\"sayHello\", methodConfig.getName());\n        Assertions.assertEquals(false, methodConfig.isReturn());\n        Assertions.assertEquals(1000, methodConfig.getTimeout());\n        Assertions.assertEquals(2, methodConfig.getRetries());\n        Assertions.assertEquals(\"loadbalance\", methodConfig.getLoadbalance());\n        Assertions.assertEquals(notifyService, methodConfig.getOninvoke());\n        Assertions.assertEquals(notifyService, methodConfig.getOnreturn());\n        Assertions.assertEquals(notifyService, methodConfig.getOnthrow());\n        Assertions.assertEquals(\"onInvoke\", methodConfig.getOninvokeMethod());\n        Assertions.assertEquals(\"onReturn\", methodConfig.getOnreturnMethod());\n        Assertions.assertEquals(\"onThrow\", methodConfig.getOnthrowMethod());\n        // method parameters\n        Map<String, String> methodParameters = new HashMap<String, String>();\n        methodParameters.put(\"a\", \"1\");\n        methodParameters.put(\"b\", \"2\");\n        Assertions.assertEquals(methodParameters, methodConfig.getParameters());\n\n        // method arguments\n        List<ArgumentConfig> arguments = methodConfig.getArguments();\n        Assertions.assertEquals(1, arguments.size());\n        ArgumentConfig argumentConfig = arguments.get(0);\n        Assertions.assertEquals(0, argumentConfig.getIndex());\n        Assertions.assertEquals(true, argumentConfig.isCallback());\n\n        // Asserts Null fields\n        Assertions.assertThrows(IllegalStateException.class, referenceBean::getApplication);\n        Assertions.assertNotNull(referenceBean.getModule());\n        Assertions.assertNotNull(referenceBean.getConsumer());\n        Assertions.assertNotNull(referenceBean.getMonitor());\n    }\n\n    @Configuration\n    public static class ConsumerConfiguration {\n\n        @Bean\n        public NotifyService notifyService() {\n            return new NotifyService();\n        }\n\n        @Bean(\"org.apache.dubbo.rpc.model.ModuleModel\")\n        public ModuleModel moduleModel() {\n            return ApplicationModel.defaultModel().getDefaultModule();\n        }\n\n        @Bean(CONSUMER_CONFIG_ID)\n        public ConsumerConfig consumerConfig() {\n            return new ConsumerConfig();\n        }\n\n        @Bean(MONITOR_CONFIG_ID)\n        public MonitorConfig monitorConfig() {\n            return new MonitorConfig();\n        }\n\n        @Bean(MODULE_CONFIG_ID)\n        public ModuleConfig moduleConfig() {\n            return new ModuleConfig();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ServiceBean;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n/**\n * {@link ServiceAnnotationPostProcessor} Test\n *\n * @since 2.7.7\n */\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(\n        classes = {\n            ServiceAnnotationTestConfiguration.class,\n            ServiceAnnotationPostProcessorTest.class,\n            ServiceAnnotationPostProcessorTest.DuplicatedScanConfig.class\n        })\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\n@TestPropertySource(\n        properties = {\n            \"provider.package = org.apache.dubbo.config.spring.context.annotation.provider\",\n            \"dubbo.metrics.enabled = false\",\n            \"dubbo.metrics.protocol = disabled\"\n        })\n@EnableDubbo(scanBasePackages = \"${provider.package}\")\nclass ServiceAnnotationPostProcessorTest {\n\n    @BeforeAll\n    public static void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private ConfigurableListableBeanFactory beanFactory;\n\n    @Test\n    void test() {\n\n        Map<String, HelloService> helloServicesMap = beanFactory.getBeansOfType(HelloService.class);\n\n        Assertions.assertEquals(2, helloServicesMap.size());\n\n        Map<String, ServiceBean> serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class);\n\n        Assertions.assertEquals(3, serviceBeansMap.size());\n\n        Map<String, ServiceAnnotationPostProcessor> beanPostProcessorsMap =\n                beanFactory.getBeansOfType(ServiceAnnotationPostProcessor.class);\n\n        Assertions.assertEquals(2, beanPostProcessorsMap.size());\n    }\n\n    @Test\n    void testMethodAnnotation() {\n\n        Map<String, ServiceBean> serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class);\n\n        Assertions.assertEquals(3, serviceBeansMap.size());\n\n        ServiceBean demoServiceBean =\n                serviceBeansMap.get(\"ServiceBean:org.apache.dubbo.config.spring.api.DemoService:2.5.7:\");\n\n        Assertions.assertNotNull(demoServiceBean.getMethods());\n    }\n\n    @DubboComponentScan({\"org.apache.dubbo.config.spring.context.annotation\", \"${provider.package}\"})\n    static class DuplicatedScanConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.annotation.Service;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionDefinition;\nimport org.springframework.transaction.TransactionException;\nimport org.springframework.transaction.TransactionStatus;\n\n/**\n * {@link Service} Bean\n *\n * @since 2.6.5\n */\n@PropertySource(\"classpath:/META-INF/default.properties\")\npublic class ServiceAnnotationTestConfiguration {\n\n    /**\n     * Current application configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:application name=\"dubbo-demo-application\"/&gt;\n     * </prev>\n     *\n     * @return {@link ApplicationConfig} Bean\n     */\n    @Bean(\"dubbo-demo-application\")\n    public ApplicationConfig applicationConfig() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"dubbo-demo-application\");\n        return applicationConfig;\n    }\n\n    /**\n     * Current registry center configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:registry id=\"my-registry\" address=\"N/A\"/&gt;\n     * </prev>\n     *\n     * @return {@link RegistryConfig} Bean\n     */\n    @Bean(\"my-registry\")\n    public RegistryConfig registryConfig() {\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setAddress(\"N/A\");\n        return registryConfig;\n    }\n\n    /**\n     * Current protocol configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:protocol name=\"dubbo\" port=\"12345\"/&gt;\n     * </prev>\n     *\n     * @return {@link ProtocolConfig} Bean\n     */\n    @Bean // (\"dubbo\")\n    public ProtocolConfig protocolConfig() {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        protocolConfig.setName(\"dubbo\");\n        protocolConfig.setPort(12345);\n        return protocolConfig;\n    }\n\n    @Primary\n    @Bean\n    public PlatformTransactionManager platformTransactionManager() {\n        return new PlatformTransactionManager() {\n\n            @Override\n            public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {\n                return null;\n            }\n\n            @Override\n            public void commit(TransactionStatus status) throws TransactionException {}\n\n            @Override\n            public void rollback(TransactionStatus status) throws TransactionException {}\n        };\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.annotation;\n\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.apache.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilderTest.GROUP;\nimport static org.apache.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilderTest.VERSION;\n\n/**\n * {@link ServiceBeanNameBuilder} Test\n *\n * @see ServiceBeanNameBuilder\n * @since 2.6.6\n */\n@Service(\n        interfaceClass = DemoService.class,\n        group = GROUP,\n        version = VERSION,\n        application = \"application\",\n        module = \"module\",\n        registry = {\"1\", \"2\", \"3\"})\nclass ServiceBeanNameBuilderTest {\n\n    @Reference(\n            interfaceClass = DemoService.class,\n            group = \"DUBBO\",\n            version = \"${dubbo.version}\",\n            application = \"application\",\n            module = \"module\",\n            registry = {\"1\", \"2\", \"3\"})\n    static final Class<?> INTERFACE_CLASS = DemoService.class;\n\n    static final String GROUP = \"DUBBO\";\n\n    static final String VERSION = \"1.0.0\";\n\n    private MockEnvironment environment;\n\n    @BeforeEach\n    public void prepare() {\n        environment = new MockEnvironment();\n        environment.setProperty(\"dubbo.version\", \"1.0.0\");\n    }\n\n    @Test\n    void testServiceAnnotation() {\n        Service service = AnnotationUtils.getAnnotation(ServiceBeanNameBuilderTest.class, Service.class);\n        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, INTERFACE_CLASS, environment);\n        Assertions.assertEquals(\n                \"ServiceBean:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO\", builder.build());\n    }\n\n    @Test\n    void testReferenceAnnotation() {\n        Reference reference = AnnotationUtils.getAnnotation(\n                ReflectionUtils.findField(ServiceBeanNameBuilderTest.class, \"INTERFACE_CLASS\"), Reference.class);\n        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, INTERFACE_CLASS, environment);\n        Assertions.assertEquals(\n                \"ServiceBean:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO\", builder.build());\n    }\n\n    @Test\n    void testServiceNameBuild() {\n        ServiceBeanNameBuilder vBuilder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, environment);\n        String vBeanName = vBuilder.version(\"DUBBO\").build();\n\n        ServiceBeanNameBuilder gBuilder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, environment);\n        String gBeanName = gBuilder.group(\"DUBBO\").build();\n\n        Assertions.assertNotEquals(vBeanName, gBeanName);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/DubboConfigDefaultPropertyValueBeanPostProcessorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.config;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\nclass DubboConfigDefaultPropertyValueBeanPostProcessorTest {\n\n    @BeforeEach\n    void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void test() {\n        AnnotationConfigApplicationContext context =\n                new AnnotationConfigApplicationContext(ProviderConfiguration.class);\n        try {\n            context.start();\n            ApplicationConfig applicationConfig = context.getBean(ApplicationConfig.class);\n            Assertions.assertEquals(applicationConfig.getName(), applicationConfig.getId());\n\n            ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class);\n            Assertions.assertEquals(protocolConfig.getName(), protocolConfig.getId());\n        } finally {\n            context.close();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/MultipleServicesWithMethodConfigsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.config;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ServiceBean;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = MultipleServicesWithMethodConfigsTest.class)\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\n@ImportResource(locations = \"classpath:/META-INF/spring/multiple-services-with-methods.xml\")\n@TestPropertySource(properties = {\"dubbo.metrics.enabled = false\", \"dubbo.metrics.protocol = disabled\"})\nclass MultipleServicesWithMethodConfigsTest {\n\n    @BeforeAll\n    public static void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Test\n    void test() {\n\n        Map<String, ServiceBean> serviceBeanMap = applicationContext.getBeansOfType(ServiceBean.class);\n        for (ServiceBean serviceBean : serviceBeanMap.values()) {\n            Assertions.assertEquals(1, serviceBean.getMethods().size());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.config;\n\nimport java.io.IOException;\nimport java.util.AbstractMap;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Pattern;\n\nimport org.springframework.beans.factory.config.YamlProcessor;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.support.EncodedResource;\nimport org.springframework.core.io.support.PropertySourceFactory;\nimport org.yaml.snakeyaml.DumperOptions;\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.Constructor;\nimport org.yaml.snakeyaml.nodes.MappingNode;\nimport org.yaml.snakeyaml.nodes.Tag;\nimport org.yaml.snakeyaml.parser.ParserException;\nimport org.yaml.snakeyaml.representer.Representer;\nimport org.yaml.snakeyaml.resolver.Resolver;\n\n/**\n * YAML {@link PropertySourceFactory} implementation, some source code is copied Spring Boot\n * org.springframework.boot.env.YamlPropertySourceLoader , see {@link #createYaml()} and {@link #process()}\n *\n * @since 2.6.5\n */\npublic class YamlPropertySourceFactory extends YamlProcessor implements PropertySourceFactory {\n\n    @Override\n    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {\n        setResources(resource.getResource());\n        return new MapPropertySource(name, process());\n    }\n\n    @Override\n    protected Yaml createYaml() {\n        return new Yaml(\n                new Constructor(new LoaderOptions()) {\n                    @Override\n                    protected Map<Object, Object> constructMapping(MappingNode node) {\n                        try {\n                            return super.constructMapping(node);\n                        } catch (IllegalStateException ex) {\n                            throw new ParserException(\n                                    \"while parsing MappingNode\",\n                                    node.getStartMark(),\n                                    ex.getMessage(),\n                                    node.getEndMark());\n                        }\n                    }\n\n                    @Override\n                    protected Map<Object, Object> createDefaultMap(int initSize) {\n                        final Map<Object, Object> delegate = super.createDefaultMap(initSize);\n                        return new AbstractMap<Object, Object>() {\n                            @Override\n                            public Object put(Object key, Object value) {\n                                if (delegate.containsKey(key)) {\n                                    throw new IllegalStateException(\"Duplicate key: \" + key);\n                                }\n                                return delegate.put(key, value);\n                            }\n\n                            @Override\n                            public Set<Entry<Object, Object>> entrySet() {\n                                return delegate.entrySet();\n                            }\n                        };\n                    }\n                },\n                new Representer(new DumperOptions()),\n                new DumperOptions(),\n                new Resolver() {\n                    @Override\n                    public void addImplicitResolver(Tag tag, Pattern regexp, String first) {\n                        if (tag == Tag.TIMESTAMP) {\n                            return;\n                        }\n                        super.addImplicitResolver(tag, regexp, first);\n                    }\n                });\n    }\n\n    /**\n     * {@link Resolver} that limits {@link Tag#TIMESTAMP} tags.\n     */\n    private static class LimitedResolver extends Resolver {\n        @Override\n        public void addImplicitResolver(Tag tag, Pattern regexp, String first) {\n            if (tag == Tag.TIMESTAMP) {\n                return;\n            }\n            super.addImplicitResolver(tag, regexp, first);\n        }\n    }\n\n    public Map<String, Object> process() {\n        final Map<String, Object> result = new LinkedHashMap<String, Object>();\n        process((properties, map) -> result.putAll(getFlattenedMap(map)));\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.beans.factory.config;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n/**\n * {@link YamlPropertySourceFactory} Test\n *\n * @since 2.6.5\n */\n@ExtendWith(SpringExtension.class)\n@PropertySource(\n        name = \"yaml-source\",\n        value = {\"classpath:/META-INF/dubbo.yml\"},\n        factory = YamlPropertySourceFactory.class)\n@Configuration\n@ContextConfiguration(classes = YamlPropertySourceFactoryTest.class)\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\nclass YamlPropertySourceFactoryTest {\n\n    @Autowired\n    private Environment environment;\n\n    @Value(\"${dubbo.consumer.default}\")\n    private Boolean isDefault;\n\n    @Value(\"${dubbo.consumer.client}\")\n    private String client;\n\n    @Value(\"${dubbo.consumer.threadpool}\")\n    private String threadPool;\n\n    @Value(\"${dubbo.consumer.corethreads}\")\n    private Integer coreThreads;\n\n    @Value(\"${dubbo.consumer.threads}\")\n    private Integer threads;\n\n    @Value(\"${dubbo.consumer.queues}\")\n    private Integer queues;\n\n    @Test\n    void testProperty() {\n        Assertions.assertEquals(isDefault, environment.getProperty(\"dubbo.consumer.default\", Boolean.class));\n        Assertions.assertEquals(client, environment.getProperty(\"dubbo.consumer.client\", String.class));\n        Assertions.assertEquals(threadPool, environment.getProperty(\"dubbo.consumer.threadpool\", String.class));\n        Assertions.assertEquals(coreThreads, environment.getProperty(\"dubbo.consumer.corethreads\", Integer.class));\n        Assertions.assertEquals(threads, environment.getProperty(\"dubbo.consumer.threads\", Integer.class));\n        Assertions.assertEquals(queues, environment.getProperty(\"dubbo.consumer.queues\", Integer.class));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/conditional1/XmlReferenceBeanConditionalTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.boot.conditional1;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.core.annotation.Order;\n\n/**\n * issue: https://github.com/apache/dubbo-spring-boot-project/issues/779\n */\n@SpringBootTest(\n        properties = {\"dubbo.registry.address=N/A\", \"dubbo.metrics.enabled=false\", \"dubbo.metrics.protocol=disabled\"},\n        classes = {XmlReferenceBeanConditionalTest.class})\n@Configuration\n// @ComponentScan\nclass XmlReferenceBeanConditionalTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private HelloService helloService;\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Test\n    void testConsumer() {\n\n        Map<String, HelloService> helloServiceMap = applicationContext.getBeansOfType(HelloService.class);\n        Assertions.assertEquals(1, helloServiceMap.size());\n        Assertions.assertNotNull(helloServiceMap.get(\"helloService\"));\n        Assertions.assertNull(helloServiceMap.get(\"myHelloService\"));\n    }\n\n    @Order(Integer.MAX_VALUE - 2)\n    @Configuration\n    @ImportResource(\"classpath:/org/apache/dubbo/config/spring/boot/conditional1/consumer/dubbo-consumer.xml\")\n    public static class ConsumerConfiguration {}\n\n    @Order(Integer.MAX_VALUE - 1)\n    @Configuration\n    public static class ConsumerConfiguration2 {\n\n        // TEST Conditional, this bean should be ignored\n        @Bean\n        @ConditionalOnMissingBean\n        public HelloService myHelloService() {\n            return new HelloService() {\n                @Override\n                public String sayHello(String name) {\n                    return \"HI, \" + name;\n                }\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/conditional1/consumer/dubbo-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~\n  ~   Licensed to the Apache Software Foundation (ASF) under one or more\n  ~   contributor license agreements.  See the NOTICE file distributed with\n  ~   this work for additional information regarding copyright ownership.\n  ~   The ASF licenses this file to You under the Apache License, Version 2.0\n  ~   (the \"License\"); you may not use this file except in compliance with\n  ~   the License.  You may obtain a copy of the License at\n  ~\n  ~       http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~   Unless required by applicable law or agreed to in writing, software\n  ~   distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~   See the License for the specific language governing permissions and\n  ~   limitations under the License.\n  ~\n  -->\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:dubbo=\"http://code.alibabatech.com/schema/dubbo\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans \n\t\thttp://www.springframework.org/schema/beans/spring-beans.xsd\n\t\thttp://code.alibabatech.com/schema/dubbo\n\t\thttp://code.alibabatech.com/schema/dubbo/dubbo.xsd\" default-lazy-init =\"false\">\n\n\t<dubbo:application name=\"consumer-app\"/>\n\n\t<dubbo:registry client=\"curator\" address=\"${dubbo.registry.address}\"/>\n\n\t<dubbo:protocol name=\"dubbo\" port=\"${myapp.dubbo.port:20880}\"/>\n\n\t<dubbo:reference id=\"helloService\" group=\"${myapp.group:foo}\" interface=\"org.apache.dubbo.config.spring.api.HelloService\" init=\"false\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/conditional2/JavaConfigAnnotationReferenceBeanConditionalTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.boot.conditional2;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.context.annotation.provider.HelloServiceImpl;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\n/**\n * issue: https://github.com/apache/dubbo-spring-boot-project/issues/779\n */\n@SpringBootTest(\n        properties = {\n            \"dubbo.application.name=consumer-app\",\n            \"dubbo.registry.address=N/A\",\n            \"myapp.group=demo\",\n            \"dubbo.metrics.enabled=false\",\n            \"dubbo.metrics.protocol=disabled\"\n        },\n        classes = {JavaConfigAnnotationReferenceBeanConditionalTest.class})\n@Configuration\n// @ComponentScan\n@EnableDubbo\nclass JavaConfigAnnotationReferenceBeanConditionalTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private HelloService helloService;\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Test\n    void testConsumer() {\n\n        Map<String, HelloService> helloServiceMap = applicationContext.getBeansOfType(HelloService.class);\n        Assertions.assertEquals(1, helloServiceMap.size());\n        Assertions.assertNotNull(helloServiceMap.get(\"helloService\"));\n        Assertions.assertNull(helloServiceMap.get(\"myHelloService\"));\n    }\n\n    @Order(Integer.MAX_VALUE - 2)\n    @Configuration\n    public static class AnnotationBeanConfiguration {\n\n        @Bean\n        @DubboReference(group = \"${myapp.group}\", init = false)\n        public ReferenceBean<HelloService> helloService() {\n            return new ReferenceBean();\n        }\n    }\n\n    @Order(Integer.MAX_VALUE - 1)\n    @Configuration\n    public static class ConditionalBeanConfiguration {\n\n        // TEST Conditional, this bean should be ignored\n        @Bean\n        @ConditionalOnMissingBean\n        public HelloService myHelloService() {\n            return new HelloServiceImpl();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/conditional3/JavaConfigRawReferenceBeanConditionalTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.boot.conditional3;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.context.annotation.provider.HelloServiceImpl;\nimport org.apache.dubbo.config.spring.reference.ReferenceBeanBuilder;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\n/**\n * issue: https://github.com/apache/dubbo-spring-boot-project/issues/779\n */\n@SpringBootTest(\n        properties = {\n            \"dubbo.application.name=consumer-app\",\n            \"dubbo.registry.address=N/A\",\n            \"myapp.group=demo\",\n            \"dubbo.metrics.enabled=false\",\n            \"dubbo.metrics.protocol=disabled\"\n        },\n        classes = {JavaConfigRawReferenceBeanConditionalTest.class})\n@Configuration\n// @ComponentScan\n@EnableDubbo\nclass JavaConfigRawReferenceBeanConditionalTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private HelloService helloService;\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Test\n    void testConsumer() {\n\n        Map<String, HelloService> helloServiceMap = applicationContext.getBeansOfType(HelloService.class);\n        Assertions.assertEquals(1, helloServiceMap.size());\n        Assertions.assertNotNull(helloServiceMap.get(\"helloService\"));\n        Assertions.assertNull(helloServiceMap.get(\"myHelloService\"));\n    }\n\n    @Order(Integer.MAX_VALUE - 2)\n    @Configuration\n    public static class RawReferenceBeanConfiguration {\n\n        @Bean\n        public ReferenceBean<HelloService> helloService() {\n            return new ReferenceBeanBuilder()\n                    .setGroup(\"${myapp.group}\")\n                    .setInit(false)\n                    .build();\n        }\n    }\n\n    @Order(Integer.MAX_VALUE - 1)\n    @Configuration\n    public static class ConditionalBeanConfiguration {\n\n        // TEST Conditional, this bean should be ignored\n        @Bean\n        @ConditionalOnMissingBean\n        public HelloService myHelloService() {\n            return new HelloServiceImpl();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/conditional4/JavaConfigReferenceBeanConditionalTest4.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.boot.conditional4;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.context.annotation.provider.HelloServiceImpl;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\n/**\n * issue: https://github.com/apache/dubbo-spring-boot-project/issues/779\n */\n@SpringBootTest(\n        properties = {\"dubbo.application.name=consumer-app\", \"dubbo.registry.address=N/A\", \"myapp.group=demo\"},\n        classes = {JavaConfigReferenceBeanConditionalTest4.class})\n@Configuration\n// @ComponentScan\n@EnableDubbo\npublic class JavaConfigReferenceBeanConditionalTest4 {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private HelloService helloService;\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Test\n    public void testConsumer() {\n\n        Map<String, HelloService> helloServiceMap = applicationContext.getBeansOfType(HelloService.class);\n        Assertions.assertEquals(1, helloServiceMap.size());\n        Assertions.assertNull(helloServiceMap.get(\"helloService\"));\n        HelloService helloService = helloServiceMap.get(\"helloServiceImpl\");\n        Assertions.assertNotNull(helloService);\n        Assertions.assertTrue(\n                helloService instanceof HelloServiceImpl, \"Not expected bean type: \" + helloService.getClass());\n    }\n\n    @Order(Integer.MAX_VALUE - 2)\n    @Configuration\n    public static class ServiceBeanConfiguration {\n\n        @Bean\n        public HelloService helloServiceImpl() {\n            return new HelloServiceImpl();\n        }\n    }\n\n    // make sure that the one using condition runs after.\n    @Order(Integer.MAX_VALUE - 1)\n    @Configuration\n    public static class AnnotationBeanConfiguration {\n\n        // TEST Conditional, this bean should be ignored\n        @Bean\n        @ConditionalOnMissingBean(HelloService.class)\n        @DubboReference(group = \"${myapp.group}\", init = false)\n        public ReferenceBean<HelloService> helloService() {\n            return new ReferenceBean();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.boot.configprops;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\n\n@SpringBootTest(\n        properties = {\n            \"dubbo.application.NAME = dubbo-demo-application\",\n            \"dubbo.module.name = dubbo-demo-module\",\n            \"dubbo.registry.address = zookeeper://192.168.99.100:32770\",\n            \"dubbo.protocol.name=dubbo\",\n            \"dubbo.protocol.port=20880\",\n            \"dubbo.metrics.protocol=prometheus\",\n            \"dubbo.metrics.enable-jvm=true\",\n            \"dubbo.metrics.prometheus.exporter.enabled=true\",\n            \"dubbo.metrics.prometheus.exporter.enable-http-service-discovery=true\",\n            \"dubbo.metrics.prometheus.exporter.http-service-discovery-url=localhost:8080\",\n            \"dubbo.metrics.aggregation.enabled=true\",\n            \"dubbo.metrics.aggregation.bucket-num=5\",\n            \"dubbo.metrics.aggregation.time-window-seconds=120\",\n            \"dubbo.metrics.histogram.enabled=true\",\n            \"dubbo.monitor.address=zookeeper://127.0.0.1:32770\",\n            \"dubbo.Config-center.address=${zookeeper.connection.address.1}\",\n            \"dubbo.config-Center.group=group1\",\n            \"dubbo.metadata-report.address=${zookeeper.connection.address.2}\",\n            \"dubbo.METADATA-REPORT.username=User\",\n            \"dubbo.provider.host=127.0.0.1\",\n            \"dubbo.consumer.client=netty\"\n        },\n        classes = {SpringBootConfigPropsTest.class})\n@Configuration\n@ComponentScan\n@EnableDubbo\nclass SpringBootConfigPropsTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private ConfigManager configManager;\n\n    @Autowired\n    private ModuleModel moduleModel;\n\n    @Test\n    void testConfigProps() {\n\n        ApplicationConfig applicationConfig = configManager.getApplicationOrElseThrow();\n        Assertions.assertEquals(\"dubbo-demo-application\", applicationConfig.getName());\n\n        MonitorConfig monitorConfig = configManager.getMonitor().get();\n        Assertions.assertEquals(\"zookeeper://127.0.0.1:32770\", monitorConfig.getAddress());\n\n        MetricsConfig metricsConfig = configManager.getMetrics().get();\n        Assertions.assertEquals(PROTOCOL_PROMETHEUS, metricsConfig.getProtocol());\n        Assertions.assertTrue(metricsConfig.getPrometheus().getExporter().getEnabled());\n        Assertions.assertTrue(metricsConfig.getPrometheus().getExporter().getEnableHttpServiceDiscovery());\n        Assertions.assertEquals(\n                \"localhost:8080\", metricsConfig.getPrometheus().getExporter().getHttpServiceDiscoveryUrl());\n        Assertions.assertEquals(5, metricsConfig.getAggregation().getBucketNum());\n        Assertions.assertEquals(120, metricsConfig.getAggregation().getTimeWindowSeconds());\n        Assertions.assertTrue(metricsConfig.getAggregation().getEnabled());\n        Assertions.assertTrue(metricsConfig.getHistogram().getEnabled());\n\n        List<ProtocolConfig> defaultProtocols = configManager.getDefaultProtocols();\n        Assertions.assertEquals(1, defaultProtocols.size());\n        ProtocolConfig protocolConfig = defaultProtocols.get(0);\n        Assertions.assertEquals(\"dubbo\", protocolConfig.getName());\n        Assertions.assertEquals(20880, protocolConfig.getPort());\n\n        List<RegistryConfig> defaultRegistries = configManager.getDefaultRegistries();\n        Assertions.assertEquals(1, defaultRegistries.size());\n        RegistryConfig registryConfig = defaultRegistries.get(0);\n        Assertions.assertEquals(\"zookeeper://192.168.99.100:32770\", registryConfig.getAddress());\n\n        Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();\n        Assertions.assertEquals(1, configCenters.size());\n        ConfigCenterConfig centerConfig = configCenters.iterator().next();\n        Assertions.assertEquals(ZookeeperRegistryCenterConfig.getConnectionAddress1(), centerConfig.getAddress());\n        Assertions.assertEquals(\"group1\", centerConfig.getGroup());\n\n        Collection<MetadataReportConfig> metadataConfigs = configManager.getMetadataConfigs();\n        Assertions.assertEquals(1, metadataConfigs.size());\n        MetadataReportConfig reportConfig = metadataConfigs.iterator().next();\n        Assertions.assertEquals(ZookeeperRegistryCenterConfig.getConnectionAddress2(), reportConfig.getAddress());\n        Assertions.assertEquals(\"User\", reportConfig.getUsername());\n\n        // module configs\n        ModuleConfigManager moduleConfigManager = moduleModel.getConfigManager();\n        ModuleConfig moduleConfig = moduleConfigManager.getModule().get();\n        Assertions.assertEquals(\"dubbo-demo-module\", moduleConfig.getName());\n\n        ProviderConfig providerConfig = moduleConfigManager.getDefaultProvider().get();\n        Assertions.assertEquals(\"127.0.0.1\", providerConfig.getHost());\n\n        ConsumerConfig consumerConfig = moduleConfigManager.getDefaultConsumer().get();\n        Assertions.assertEquals(\"netty\", consumerConfig.getClient());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.boot.configprops;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\n\n@SpringBootTest(\n        properties = {\n            \"dubbo.applications.application1.name = dubbo-demo-application\",\n            \"dubbo.modules.demo-module.name = dubbo-demo-module\",\n            \"dubbo.registries.my-registry.address = zookeeper://192.168.99.100:32770\",\n            \"dubbo.protocols.dubbo.port=20880\",\n            \"dubbo.metricses.my-metrics.protocol=prometheus\",\n            \"dubbo.metricses.my-metrics.prometheus.pushgateway.enabled=true\",\n            \"dubbo.metricses.my-metrics.prometheus.pushgateway.base-url=localhost:9091\",\n            \"dubbo.metricses.my-metrics.prometheus.pushgateway.username=username\",\n            \"dubbo.metricses.my-metrics.prometheus.pushgateway.password=password\",\n            \"dubbo.metricses.my-metrics.prometheus.pushgateway.job=job\",\n            \"dubbo.metricses.my-metrics.prometheus.pushgateway.push-interval=30\",\n            \"dubbo.metricses.my-metrics.aggregation.enabled=true\",\n            \"dubbo.metricses.my-metrics.aggregation.bucket-num=5\",\n            \"dubbo.metricses.my-metrics.aggregation.time-window-seconds=120\",\n            \"dubbo.metricses.my-metrics.histogram.enabled=true\",\n            \"dubbo.monitors.my-monitor.address=zookeeper://127.0.0.1:32770\",\n            \"dubbo.config-centers.my-configcenter.address=${zookeeper.connection.address.1}\",\n            \"dubbo.config-centers.my-configcenter.group=group1\",\n            \"dubbo.metadata-reports.my-metadata.address=${zookeeper.connection.address.2}\",\n            \"dubbo.metadata-reports.my-metadata.username=User\",\n            \"dubbo.providers.my-provider.host=127.0.0.1\",\n            \"dubbo.consumers.my-consumer.client=netty\"\n        },\n        classes = {SpringBootMultipleConfigPropsTest.class})\n@Configuration\n@ComponentScan\n@EnableDubbo\nclass SpringBootMultipleConfigPropsTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private ConfigManager configManager;\n\n    @Autowired\n    private ModuleModel moduleModel;\n\n    @Test\n    void testConfigProps() {\n\n        ApplicationConfig applicationConfig = configManager.getApplicationOrElseThrow();\n        Assertions.assertEquals(\"dubbo-demo-application\", applicationConfig.getName());\n\n        MonitorConfig monitorConfig = configManager.getMonitor().get();\n        Assertions.assertEquals(\"zookeeper://127.0.0.1:32770\", monitorConfig.getAddress());\n\n        MetricsConfig metricsConfig = configManager.getMetrics().get();\n        Assertions.assertEquals(PROTOCOL_PROMETHEUS, metricsConfig.getProtocol());\n        Assertions.assertTrue(metricsConfig.getPrometheus().getPushgateway().getEnabled());\n        Assertions.assertEquals(\n                \"localhost:9091\", metricsConfig.getPrometheus().getPushgateway().getBaseUrl());\n        Assertions.assertEquals(\n                \"username\", metricsConfig.getPrometheus().getPushgateway().getUsername());\n        Assertions.assertEquals(\n                \"password\", metricsConfig.getPrometheus().getPushgateway().getPassword());\n        Assertions.assertEquals(\n                \"job\", metricsConfig.getPrometheus().getPushgateway().getJob());\n        Assertions.assertEquals(\n                30, metricsConfig.getPrometheus().getPushgateway().getPushInterval());\n        Assertions.assertEquals(5, metricsConfig.getAggregation().getBucketNum());\n        Assertions.assertEquals(120, metricsConfig.getAggregation().getTimeWindowSeconds());\n        Assertions.assertTrue(metricsConfig.getAggregation().getEnabled());\n        Assertions.assertTrue(metricsConfig.getHistogram().getEnabled());\n\n        List<ProtocolConfig> defaultProtocols = configManager.getDefaultProtocols();\n        Assertions.assertEquals(1, defaultProtocols.size());\n        ProtocolConfig protocolConfig = defaultProtocols.get(0);\n        Assertions.assertEquals(\"dubbo\", protocolConfig.getName());\n        Assertions.assertEquals(20880, protocolConfig.getPort());\n\n        List<RegistryConfig> defaultRegistries = configManager.getDefaultRegistries();\n        Assertions.assertEquals(1, defaultRegistries.size());\n        RegistryConfig registryConfig = defaultRegistries.get(0);\n        Assertions.assertEquals(\"zookeeper://192.168.99.100:32770\", registryConfig.getAddress());\n\n        Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();\n        Assertions.assertEquals(1, configCenters.size());\n        ConfigCenterConfig centerConfig = configCenters.iterator().next();\n        Assertions.assertEquals(ZookeeperRegistryCenterConfig.getConnectionAddress1(), centerConfig.getAddress());\n        Assertions.assertEquals(\"group1\", centerConfig.getGroup());\n\n        Collection<MetadataReportConfig> metadataConfigs = configManager.getMetadataConfigs();\n        Assertions.assertEquals(1, metadataConfigs.size());\n        MetadataReportConfig reportConfig = metadataConfigs.iterator().next();\n        Assertions.assertEquals(ZookeeperRegistryCenterConfig.getConnectionAddress2(), reportConfig.getAddress());\n        Assertions.assertEquals(\"User\", reportConfig.getUsername());\n\n        // module configs\n        ModuleConfigManager moduleConfigManager = moduleModel.getConfigManager();\n\n        ModuleConfig moduleConfig = moduleConfigManager.getModule().get();\n        Assertions.assertEquals(\"dubbo-demo-module\", moduleConfig.getName());\n\n        ProviderConfig providerConfig = moduleConfigManager.getDefaultProvider().get();\n        Assertions.assertEquals(\"127.0.0.1\", providerConfig.getHost());\n\n        ConsumerConfig consumerConfig = moduleConfigManager.getDefaultConsumer().get();\n        Assertions.assertEquals(\"netty\", consumerConfig.getClient());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/importxml/SpringBootImportDubboXmlTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.boot.importxml;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\n\n@SpringBootTest(\n        properties = {\n            \"dubbo.registry.protocol=zookeeper\",\n            \"dubbo.registry.address=localhost:2181\",\n            \"dubbo.metrics.enabled=false\",\n            \"dubbo.metrics.protocol=disabled\"\n        },\n        classes = {SpringBootImportDubboXmlTest.class})\n@Configuration\n@ComponentScan\n@ImportResource(\"classpath:/org/apache/dubbo/config/spring/boot/importxml/consumer/dubbo-consumer.xml\")\nclass SpringBootImportDubboXmlTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private HelloService helloService;\n\n    @Test\n    void testConsumer() {\n        try {\n            helloService.sayHello(\"dubbo\");\n            Assertions.fail(\"Should not be called successfully\");\n        } catch (Exception e) {\n            String s = e.toString();\n            Assertions.assertTrue(s.contains(\"No provider available\"), s);\n            Assertions.assertTrue(s.contains(\"service org.apache.dubbo.config.spring.api.HelloService\"), s);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/importxml/consumer/dubbo-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~\n  ~   Licensed to the Apache Software Foundation (ASF) under one or more\n  ~   contributor license agreements.  See the NOTICE file distributed with\n  ~   this work for additional information regarding copyright ownership.\n  ~   The ASF licenses this file to You under the Apache License, Version 2.0\n  ~   (the \"License\"); you may not use this file except in compliance with\n  ~   the License.  You may obtain a copy of the License at\n  ~\n  ~       http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~   Unless required by applicable law or agreed to in writing, software\n  ~   distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~   See the License for the specific language governing permissions and\n  ~   limitations under the License.\n  ~\n  -->\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:dubbo=\"http://code.alibabatech.com/schema/dubbo\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans \n\t\thttp://www.springframework.org/schema/beans/spring-beans.xsd\n\t\thttp://code.alibabatech.com/schema/dubbo\n\t\thttp://code.alibabatech.com/schema/dubbo/dubbo.xsd\" default-lazy-init =\"false\">\n\n\t<description>wisdom app Service Dubbo Admin Consumers</description>\n\t<dubbo:application name=\"cimmdms\"\n\t\towner=\"wisdom\" organization=\"wisdom\" logger=\"slf4j\">\n\t\t<dubbo:parameter key=\"qos.enable\" value=\"false\" />\n\t</dubbo:application>\n\n\t<dubbo:protocol name=\"dubbo\" accesslog=\"true\" />\n\t\n\t<dubbo:registry id=\"cimmdmsSrvClientRegistry\"\n\t\tprotocol=\"${dubbo.registry.protocol}\" address=\"${dubbo.registry.address}\" client=\"curator\"\n\t\tgroup=\"dubboservice/wisdom/cimmdmsservice/group_mdms_dev\"\n\t\tsubscribe=\"true\" check=\"true\">\n\t</dubbo:registry>\n\n\t<dubbo:consumer id=\"wisdomcimmdmsSrvConsumer\"\n\t\tregistry=\"cimmdmsSrvClientRegistry\" init=\"false\" check=\"false\"\n\t\tretries=\"0\" timeout=\"25000\">\n\t\t<dubbo:reference consumer=\"wisdomcimmdmsSrvConsumer\" interface=\"org.apache.dubbo.config.spring.api.HelloService\" id=\"mdmMessageProviderService\" />\n\t</dubbo:consumer>\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/importxml2/HelloServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.boot.importxml2;\n\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\n@DubboService(group = \"${myapp.group:foo2}\")\npublic class HelloServiceImpl implements HelloService {\n\n    @Override\n    public String sayHello(String name) {\n        return \"Hello, \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/importxml2/SpringBootImportAndScanTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.boot.importxml2;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;\nimport org.apache.dubbo.config.spring.reference.ReferenceBeanManager;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\n\n@SpringBootTest(\n        properties = {\n            // \"dubbo.scan.base-packages=org.apache.dubbo.config.spring.boot.importxml2\",\n            \"dubbo.registry.address=N/A\",\n            \"myapp.dubbo.port=20881\",\n            \"myapp.name=dubbo-provider\",\n            \"myapp.group=test\",\n            \"dubbo.metrics.enabled=false\",\n            \"dubbo.metrics.protocol=disabled\"\n        },\n        classes = SpringBootImportAndScanTest.class)\n@Configuration\n@ComponentScan\n@DubboComponentScan\n@ImportResource(\"classpath:/org/apache/dubbo/config/spring/boot/importxml2/dubbo-provider.xml\")\nclass SpringBootImportAndScanTest implements ApplicationContextAware {\n\n    private ApplicationContext applicationContext;\n\n    @BeforeAll\n    public static void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void tearDown() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private HelloService helloService;\n\n    @Test\n    void testProvider() {\n\n        String result = helloService.sayHello(\"dubbo\");\n        Assertions.assertEquals(\"Hello, dubbo\", result);\n\n        Map<String, ReferenceBean> referenceBeanMap = applicationContext.getBeansOfType(ReferenceBean.class);\n        Assertions.assertEquals(1, referenceBeanMap.size());\n        Assertions.assertNotNull(referenceBeanMap.get(\"&helloService\"));\n\n        ReferenceBeanManager referenceBeanManager =\n                applicationContext.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);\n        Assertions.assertNotNull(referenceBeanManager.getById(\"helloService\"));\n    }\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        this.applicationContext = applicationContext;\n    }\n\n    @Configuration\n    public static class ConsumerConfiguration {\n\n        // Match and reuse 'helloService' reference bean definition in dubbo-provider.xml\n        @DubboReference(group = \"${myapp.group}\")\n        private HelloService helloService;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/importxml2/dubbo-provider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~\n  ~   Licensed to the Apache Software Foundation (ASF) under one or more\n  ~   contributor license agreements.  See the NOTICE file distributed with\n  ~   this work for additional information regarding copyright ownership.\n  ~   The ASF licenses this file to You under the Apache License, Version 2.0\n  ~   (the \"License\"); you may not use this file except in compliance with\n  ~   the License.  You may obtain a copy of the License at\n  ~\n  ~       http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~   Unless required by applicable law or agreed to in writing, software\n  ~   distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~   See the License for the specific language governing permissions and\n  ~   limitations under the License.\n  ~\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n<!--    <context:property-placeholder/>-->\n\n    <dubbo:application name=\"${myapp.name:foo}\"/>\n\n    <dubbo:registry client=\"curator\" address=\"${dubbo.registry.address}\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"${myapp.dubbo.port:20880}\"/>\n\n    <dubbo:provider delay=\"-1\"/>\n\n    <dubbo:reference id=\"helloService\" group=\"${myapp.group:foo}\" interface=\"org.apache.dubbo.config.spring.api.HelloService\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/KeepRunningOnSpringClosedTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context;\n\nimport org.apache.dubbo.common.deploy.ApplicationDeployer;\nimport org.apache.dubbo.common.deploy.DeployState;\nimport org.apache.dubbo.common.deploy.ModuleDeployer;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.DubboStateListener;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nclass KeepRunningOnSpringClosedTest {\n\n    @BeforeEach\n    void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @Test\n    void test() {\n\n        // set KeepRunningOnSpringClosed flag for next spring context\n        DubboSpringInitCustomizerHolder.get().addCustomizer(context -> {\n            context.setKeepRunningOnSpringClosed(true);\n        });\n\n        ClassPathXmlApplicationContext providerContext = null;\n        try {\n            String resourcePath = \"org/apache/dubbo/config/spring\";\n            providerContext = new ClassPathXmlApplicationContext(\n                    resourcePath + \"/demo-provider.xml\", resourcePath + \"/demo-provider-properties.xml\");\n            providerContext.start();\n\n            // Expect 1: dubbo application state is STARTED after spring context start finish.\n            // No need check and wait\n\n            DubboStateListener dubboStateListener = providerContext.getBean(DubboStateListener.class);\n            Assertions.assertEquals(DeployState.COMPLETION, dubboStateListener.getState());\n\n            ModuleModel moduleModel = providerContext.getBean(ModuleModel.class);\n            ModuleDeployer moduleDeployer = moduleModel.getDeployer();\n            Assertions.assertTrue(moduleDeployer.isCompletion());\n\n            ApplicationDeployer applicationDeployer =\n                    moduleModel.getApplicationModel().getDeployer();\n            Assertions.assertEquals(DeployState.COMPLETION, applicationDeployer.getState());\n            Assertions.assertTrue(applicationDeployer.isCompletion());\n            Assertions.assertTrue(applicationDeployer.isStarted());\n            Assertions.assertFalse(applicationDeployer.isStopped());\n            Assertions.assertNotNull(DubboSpringInitializer.findBySpringContext(providerContext));\n\n            // close spring context\n            providerContext.close();\n\n            // Expect 2: dubbo application will not be destroyed after closing spring context cause\n            // setKeepRunningOnSpringClosed(true)\n            Assertions.assertEquals(DeployState.COMPLETION, applicationDeployer.getState());\n            Assertions.assertTrue(applicationDeployer.isCompletion());\n            Assertions.assertTrue(applicationDeployer.isStarted());\n            Assertions.assertFalse(applicationDeployer.isStopped());\n            Assertions.assertNull(DubboSpringInitializer.findBySpringContext(providerContext));\n        } finally {\n            DubboBootstrap.getInstance().stop();\n            SysProps.clear();\n            if (providerContext != null) {\n                providerContext.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.context.annotation.consumer.ConsumerConfiguration;\nimport org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl;\nimport org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport static org.springframework.core.annotation.AnnotationUtils.findAnnotation;\n\n/**\n * {@link DubboComponentScanRegistrar} Test\n *\n * @since 2.5.8\n */\nclass DubboComponentScanRegistrarTest {\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void test() {\n\n        AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext();\n\n        providerContext.register(ProviderConfiguration.class);\n\n        providerContext.refresh();\n\n        DemoService demoService = providerContext.getBean(DemoService.class);\n\n        String value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        Class<?> beanClass = AopUtils.getTargetClass(demoService);\n\n        // DemoServiceImpl with @Transactional\n        Assertions.assertEquals(DemoServiceImpl.class, beanClass);\n\n        // Test @Transactional is present or not\n        Assertions.assertNotNull(findAnnotation(beanClass, Transactional.class));\n\n        // consumer app\n        AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();\n\n        consumerContext.register(ConsumerConfiguration.class);\n\n        consumerContext.refresh();\n\n        ConsumerConfiguration consumerConfiguration = consumerContext.getBean(ConsumerConfiguration.class);\n\n        demoService = consumerConfiguration.getDemoService();\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        ConsumerConfiguration.Child child = consumerContext.getBean(ConsumerConfiguration.Child.class);\n\n        // From Child\n\n        demoService = child.getDemoServiceFromChild();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        // From Parent\n\n        demoService = child.getDemoServiceFromParent();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        // From Ancestor\n\n        demoService = child.getDemoServiceFromAncestor();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        providerContext.close();\n        consumerContext.close();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.core.io.support.ResourcePropertySource;\n\n/**\n * {@link DubboConfigConfiguration} Test\n *\n * @since 2.5.8\n */\nclass DubboConfigConfigurationTest {\n\n    private AnnotationConfigApplicationContext context;\n\n    @BeforeEach\n    public void before() throws IOException {\n        DubboBootstrap.reset();\n\n        context = new AnnotationConfigApplicationContext();\n        ResourcePropertySource propertySource = new ResourcePropertySource(\"META-INF/config.properties\");\n        context.getEnvironment().getPropertySources().addFirst(propertySource);\n    }\n\n    @AfterEach\n    public void after() {\n        context.close();\n    }\n\n    @Test\n    void testSingle() throws IOException {\n\n        context.register(DubboConfigConfiguration.Single.class);\n        context.refresh();\n\n        // application\n        ApplicationConfig applicationConfig = context.getBean(\"applicationBean\", ApplicationConfig.class);\n        Assertions.assertEquals(\"dubbo-demo-application\", applicationConfig.getName());\n\n        // module\n        ModuleConfig moduleConfig = context.getBean(\"moduleBean\", ModuleConfig.class);\n        Assertions.assertEquals(\"dubbo-demo-module\", moduleConfig.getName());\n\n        // registry\n        RegistryConfig registryConfig = context.getBean(RegistryConfig.class);\n        Assertions.assertEquals(\"zookeeper://192.168.99.100:32770\", registryConfig.getAddress());\n\n        // protocol\n        ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class);\n        Assertions.assertEquals(\"dubbo\", protocolConfig.getName());\n        Assertions.assertEquals(Integer.valueOf(20880), protocolConfig.getPort());\n    }\n\n    @Test\n    void testMultiple() {\n        context.register(DubboConfigConfiguration.Multiple.class);\n        context.refresh();\n\n        RegistryConfig registry1 = context.getBean(\"registry1\", RegistryConfig.class);\n        Assertions.assertEquals(2181, registry1.getPort());\n\n        RegistryConfig registry2 = context.getBean(\"registry2\", RegistryConfig.class);\n        Assertions.assertEquals(2182, registry2.getPort());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.PropertySource;\n\nimport static org.apache.dubbo.config.spring.util.BeanRegistrar.hasAlias;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\n\n/**\n * {@link EnableDubboConfig} Test\n *\n * @since 2.5.8\n */\nclass EnableDubboConfigTest {\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n    }\n\n    // @Test\n    public void testSingle() {\n\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n        context.register(TestConfig.class);\n        context.refresh();\n\n        // application\n        ApplicationConfig applicationConfig = context.getBean(\"applicationBean\", ApplicationConfig.class);\n        Assertions.assertEquals(\"dubbo-demo-application\", applicationConfig.getName());\n\n        // module\n        ModuleConfig moduleConfig = context.getBean(\"moduleBean\", ModuleConfig.class);\n        Assertions.assertEquals(\"dubbo-demo-module\", moduleConfig.getName());\n\n        // registry\n        RegistryConfig registryConfig = context.getBean(RegistryConfig.class);\n        Assertions.assertEquals(\"zookeeper://192.168.99.100:32770\", registryConfig.getAddress());\n\n        // protocol\n        ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class);\n        Assertions.assertEquals(\"dubbo\", protocolConfig.getName());\n        Assertions.assertEquals(Integer.valueOf(20880), protocolConfig.getPort());\n\n        // monitor\n        MonitorConfig monitorConfig = context.getBean(MonitorConfig.class);\n        Assertions.assertEquals(\"zookeeper://127.0.0.1:32770\", monitorConfig.getAddress());\n\n        // provider\n        ProviderConfig providerConfig = context.getBean(ProviderConfig.class);\n        Assertions.assertEquals(\"127.0.0.1\", providerConfig.getHost());\n\n        // consumer\n        ConsumerConfig consumerConfig = context.getBean(ConsumerConfig.class);\n        Assertions.assertEquals(\"netty\", consumerConfig.getClient());\n\n        // asserts aliases\n        assertFalse(hasAlias(context, \"org.apache.dubbo.config.RegistryConfig#0\", \"zookeeper\"));\n        assertFalse(hasAlias(context, \"org.apache.dubbo.config.MonitorConfig#0\", \"zookeeper\"));\n    }\n\n    // @Test\n    public void testMultiple() {\n\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n        context.register(TestMultipleConfig.class);\n        context.refresh();\n\n        RegistryConfig registry1 = context.getBean(\"registry1\", RegistryConfig.class);\n        Assertions.assertEquals(2181, registry1.getPort());\n\n        RegistryConfig registry2 = context.getBean(\"registry2\", RegistryConfig.class);\n        Assertions.assertEquals(2182, registry2.getPort());\n\n        ConfigManager configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n        Collection<ProtocolConfig> protocolConfigs = configManager.getProtocols();\n        Assertions.assertEquals(3, protocolConfigs.size());\n\n        configManager.getProtocol(\"dubbo\").get();\n        configManager.getProtocol(\"rest\").get();\n\n        // asserts aliases\n        //        assertTrue(hasAlias(context, \"applicationBean2\", \"dubbo-demo-application2\"));\n        //        assertTrue(hasAlias(context, \"applicationBean3\", \"dubbo-demo-application3\"));\n\n    }\n\n    @EnableDubboConfig\n    @PropertySource(\"META-INF/config.properties\")\n    private static class TestMultipleConfig {}\n\n    @EnableDubboConfig(multiple = false)\n    @PropertySource(\"META-INF/config.properties\")\n    private static class TestConfig {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation;\n\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationTestConfiguration;\nimport org.apache.dubbo.config.spring.context.annotation.consumer.test.TestConsumerConfiguration;\nimport org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionDefinition;\nimport org.springframework.transaction.TransactionException;\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport static org.springframework.core.annotation.AnnotationUtils.findAnnotation;\n\n/**\n * {@link EnableDubbo} Test\n *\n * @since 2.5.8\n */\nclass EnableDubboTest {\n\n    private AnnotationConfigApplicationContext context;\n\n    @BeforeEach\n    public void setUp() {\n        context = new AnnotationConfigApplicationContext();\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void tearDown() {\n        context.close();\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testProvider() {\n\n        context.register(TestProviderConfiguration.class);\n\n        context.refresh();\n\n        DemoService demoService = context.getBean(DemoService.class);\n\n        String value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        Class<?> beanClass = AopUtils.getTargetClass(demoService);\n\n        // DemoServiceImpl with @Transactional\n        Assertions.assertEquals(DemoServiceImpl.class, beanClass);\n\n        // Test @Transactional is present or not\n        Assertions.assertNotNull(findAnnotation(beanClass, Transactional.class));\n    }\n\n    @Test\n    void testConsumer() {\n\n        context.register(TestProviderConfiguration.class, TestConsumerConfiguration.class);\n        context.refresh();\n\n        TestConsumerConfiguration consumerConfiguration = context.getBean(TestConsumerConfiguration.class);\n\n        DemoService demoService = consumerConfiguration.getDemoService();\n        String value = demoService.sayName(\"Mercy\");\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        DemoService autowiredDemoService = consumerConfiguration.getAutowiredDemoService();\n        Assertions.assertEquals(\"Hello,Mercy\", autowiredDemoService.sayName(\"Mercy\"));\n\n        DemoService autowiredReferDemoService = consumerConfiguration.getAutowiredReferDemoService();\n        Assertions.assertEquals(\"Hello,Mercy\", autowiredReferDemoService.sayName(\"Mercy\"));\n\n        TestConsumerConfiguration.Child child = context.getBean(TestConsumerConfiguration.Child.class);\n\n        // From Child\n\n        demoService = child.getDemoServiceFromChild();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        // From Parent\n\n        //        demoService = child.getDemoServiceFromParent();\n        //\n        //        Assertions.assertNotNull(demoService);\n        //\n        //        value = demoService.sayName(\"Mercy\");\n        //\n        //        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        // From Ancestor\n\n        demoService = child.getDemoServiceFromAncestor();\n\n        Assertions.assertNotNull(demoService);\n\n        value = demoService.sayName(\"Mercy\");\n\n        Assertions.assertEquals(\"Hello,Mercy\", value);\n\n        // Test my-registry2 bean presentation\n        RegistryConfig registryConfig = context.getBean(\"my-registry\", RegistryConfig.class);\n\n        // Test multiple binding\n        Assertions.assertEquals(\"N/A\", registryConfig.getAddress());\n    }\n\n    @EnableDubbo(scanBasePackages = \"org.apache.dubbo.config.spring.context.annotation.provider\")\n    @ComponentScan(basePackages = \"org.apache.dubbo.config.spring.context.annotation.provider\")\n    @PropertySource(\"classpath:/META-INF/dubbo-provider.properties\")\n    @Import(ServiceAnnotationTestConfiguration.class)\n    @EnableTransactionManagement\n    public static class TestProviderConfiguration {\n\n        @Primary\n        @Bean\n        public PlatformTransactionManager platformTransactionManager() {\n            return new PlatformTransactionManager() {\n\n                @Override\n                public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {\n                    return null;\n                }\n\n                @Override\n                public void commit(TransactionStatus status) throws TransactionException {}\n\n                @Override\n                public void rollback(TransactionStatus status) throws TransactionException {}\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.consumer;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\n\n@Configuration(\"consumerConfiguration\")\n@DubboComponentScan(basePackageClasses = ConsumerConfiguration.class)\n@PropertySource(\"META-INF/default.properties\")\npublic class ConsumerConfiguration {\n\n    private static final String remoteURL = \"dubbo://127.0.0.1:12345?version=2.5.7\";\n\n    /**\n     * Current application configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:application name=\"dubbo-demo-application\"/&gt;\n     * </prev>\n     *\n     * @return {@link ApplicationConfig} Bean\n     */\n    @Bean(\"dubbo-demo-application\")\n    public ApplicationConfig applicationConfig() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"dubbo-demo-application\");\n        return applicationConfig;\n    }\n\n    /**\n     * Current registry center configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:registry address=\"N/A\"/&gt;\n     * </prev>\n     *\n     * @return {@link RegistryConfig} Bean\n     */\n    @Bean\n    public RegistryConfig registryConfig() {\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setAddress(\"N/A\");\n        return registryConfig;\n    }\n\n    @Autowired\n    private DemoService demoServiceFromAncestor;\n\n    @Reference(version = \"2.5.7\", url = remoteURL)\n    private DemoService demoService;\n\n    public DemoService getDemoService() {\n        return demoService;\n    }\n\n    public void setDemoService(DemoService demoService) {\n        this.demoService = demoService;\n    }\n\n    @Bean\n    public Child c() {\n        return new Child();\n    }\n\n    public abstract static class Ancestor {\n\n        @Reference(version = \"2.5.7\", url = remoteURL)\n        private DemoService demoServiceFromAncestor;\n\n        public DemoService getDemoServiceFromAncestor() {\n            return demoServiceFromAncestor;\n        }\n\n        public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) {\n            this.demoServiceFromAncestor = demoServiceFromAncestor;\n        }\n    }\n\n    public abstract static class Parent extends Ancestor {\n\n        private DemoService demoServiceFromParent;\n\n        public DemoService getDemoServiceFromParent() {\n            return demoServiceFromParent;\n        }\n\n        @Reference(version = \"2.5.7\", url = remoteURL)\n        public void setDemoServiceFromParent(DemoService demoServiceFromParent) {\n            this.demoServiceFromParent = demoServiceFromParent;\n        }\n    }\n\n    public static class Child extends Parent {\n\n        @Autowired\n        private DemoService demoService;\n\n        @Reference(version = \"2.5.7\", url = remoteURL)\n        private DemoService demoServiceFromChild;\n\n        public DemoService getDemoService() {\n            return demoService;\n        }\n\n        public DemoService getDemoServiceFromChild() {\n            return demoServiceFromChild;\n        }\n\n        public void setDemoServiceFromChild(DemoService demoServiceFromChild) {\n            this.demoServiceFromChild = demoServiceFromChild;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.consumer.test;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n/**\n * Test Consumer Configuration\n *\n * @since 2.5.7\n */\n@EnableDubbo(scanBasePackageClasses = TestConsumerConfiguration.class)\n@PropertySource(\"classpath:/META-INF/dubbb-consumer.properties\")\n@EnableTransactionManagement\npublic class TestConsumerConfiguration {\n\n    private static final String remoteURL = \"dubbo://127.0.0.1:12345?version=2.5.7\";\n\n    @Reference(\n            id = \"demoService\",\n            version = \"2.5.7\",\n            url = remoteURL,\n            application = \"dubbo-demo-application\",\n            filter = \"mymock\")\n    private DemoService demoService;\n\n    @Autowired\n    @Qualifier(\"demoServiceImpl\")\n    private DemoService autowiredDemoService;\n\n    @Autowired\n    @Qualifier(\"demoService\")\n    private DemoService autowiredReferDemoService;\n\n    public DemoService getAutowiredDemoService() {\n        return autowiredDemoService;\n    }\n\n    public DemoService getAutowiredReferDemoService() {\n        return autowiredReferDemoService;\n    }\n\n    public DemoService getDemoService() {\n        return demoService;\n    }\n\n    public void setDemoService(DemoService demoService) {\n        this.demoService = demoService;\n    }\n\n    @Bean\n    public Child c() {\n        return new Child();\n    }\n\n    public abstract static class Ancestor {\n\n        @DubboReference(version = \"2.5.7\", url = remoteURL, filter = \"mymock\", application = \"dubbo-demo-application\")\n        private DemoService demoServiceFromAncestor;\n\n        public DemoService getDemoServiceFromAncestor() {\n            return demoServiceFromAncestor;\n        }\n\n        public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) {\n            this.demoServiceFromAncestor = demoServiceFromAncestor;\n        }\n    }\n\n    public static class Child extends Ancestor {\n\n        @Reference(version = \"2.5.7\", url = remoteURL, filter = \"mymock\", application = \"dubbo-demo-application\")\n        private DemoService demoServiceFromChild;\n\n        public DemoService getDemoServiceFromChild() {\n            return demoServiceFromChild;\n        }\n\n        public void setDemoServiceFromChild(DemoService demoServiceFromChild) {\n            this.demoServiceFromChild = demoServiceFromChild;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DefaultHelloService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.provider;\n\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.springframework.stereotype.Service;\n\n/**\n * Default {@link HelloService} annotation with Spring's {@link Service}\n * and Dubbo's {@link org.apache.dubbo.config.annotation.Service}\n *\n */\n@Service\n@DubboService\npublic class DefaultHelloService implements HelloService {\n\n    @Override\n    public String sayHello(String name) {\n        return \"Greeting, \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.provider;\n\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * {@link DemoService} Service implementation\n *\n * @since 2.5.8\n */\n@org.apache.dubbo.config.annotation.Service(\n        version = \"2.5.7\",\n        application = \"${demo.service.application}\",\n        protocol = \"${demo.service.protocol}\",\n        registry = \"${demo.service.registry}\",\n        methods = @Method(timeout = 100, name = \"sayName\"))\n@Service\n@Transactional\npublic class DemoServiceImpl implements DemoService {\n\n    @Override\n    public String sayName(String name) {\n        return \"Hello,\" + name;\n    }\n\n    @Override\n    public Box getBox() {\n        throw new UnsupportedOperationException(\"For Purposes!\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/HelloServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.provider;\n\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\n/**\n * {@link HelloService} Implementation just annotating Dubbo's {@link Service}\n *\n * @since 2.5.9\n */\n@Service(interfaceName = \"org.apache.dubbo.config.spring.api.HelloService\", version = \"2\")\npublic class HelloServiceImpl implements HelloService {\n\n    @Override\n    public String sayHello(String name) {\n        return \"Hello, \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.annotation.provider;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;\n\nimport java.util.UUID;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionDefinition;\nimport org.springframework.transaction.TransactionException;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\nimport org.springframework.transaction.support.AbstractPlatformTransactionManager;\nimport org.springframework.transaction.support.DefaultTransactionStatus;\n\n@DubboComponentScan(basePackages = \"org.apache.dubbo.config.spring.context.annotation.provider\")\n@PropertySource(\"classpath:/META-INF/default.properties\")\n@EnableTransactionManagement\npublic class ProviderConfiguration {\n\n    /**\n     * Current application configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:application name=\"dubbo-demo-application\"/&gt;\n     * </prev>\n     *\n     * @return {@link ApplicationConfig} Bean\n     */\n    @Bean(\"dubbo-demo-application\")\n    public ApplicationConfig applicationConfig() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"dubbo-demo-application\");\n        return applicationConfig;\n    }\n\n    /**\n     * Current registry center configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:registry id=\"my-registry\" address=\"N/A\"/&gt;\n     * </prev>\n     *\n     * @return {@link RegistryConfig} Bean\n     */\n    @Bean(\"my-registry\")\n    public RegistryConfig registryConfig() {\n        RegistryConfig registryConfig = new RegistryConfig();\n        registryConfig.setAddress(\"N/A\");\n        return registryConfig;\n    }\n\n    /**\n     * Current protocol configuration, to replace XML config:\n     * <prev>\n     * &lt;dubbo:protocol name=\"dubbo\" port=\"12345\"/&gt;\n     * </prev>\n     *\n     * @return {@link ProtocolConfig} Bean\n     */\n    @Bean(\"dubbo\")\n    public ProtocolConfig protocolConfig() {\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        protocolConfig.setName(\"dubbo\");\n        protocolConfig.setPort(12345);\n        return protocolConfig;\n    }\n\n    @Primary\n    @Bean\n    public PlatformTransactionManager platformTransactionManager() {\n        return new AbstractPlatformTransactionManager() {\n            private Logger logger = LoggerFactory.getLogger(\"TestPlatformTransactionManager\");\n\n            @Override\n            protected Object doGetTransaction() throws TransactionException {\n                String transaction = \"transaction_\" + UUID.randomUUID().toString();\n                logger.info(\"Create transaction: \" + transaction);\n                return transaction;\n            }\n\n            @Override\n            protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {\n                logger.info(\"Begin transaction: \" + transaction);\n            }\n\n            @Override\n            protected void doCommit(DefaultTransactionStatus status) throws TransactionException {\n                logger.info(\"Commit transaction: \" + status.getTransaction());\n            }\n\n            @Override\n            protected void doRollback(DefaultTransactionStatus status) throws TransactionException {\n                logger.info(\"Rollback transaction: \" + status.getTransaction());\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/customize/DubboSpringInitCustomizerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.customize;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.DubboSpringInitCustomizerHolder;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nclass DubboSpringInitCustomizerTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n        SysProps.setProperty(\"dubbo.registry.address\", ZookeeperRegistryCenterConfig.getConnectionAddress());\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testReloadSpringContext() {\n\n        ClassPathXmlApplicationContext providerContext1 = null;\n        ClassPathXmlApplicationContext providerContext2 = null;\n\n        ApplicationModel applicationModel = new FrameworkModel().newApplication();\n        applicationModel.getDefaultModule();\n\n        try {\n            // start spring context 1\n            ModuleModel moduleModel1 = applicationModel.newModule();\n            DubboSpringInitCustomizerHolder.get().addCustomizer(context -> {\n                context.setModuleModel(moduleModel1);\n            });\n\n            providerContext1 = new ClassPathXmlApplicationContext(\"dubbo-provider-v1.xml\", getClass());\n            ModuleModel moduleModelFromSpring1 = providerContext1.getBean(ModuleModel.class);\n            Assertions.assertSame(moduleModel1, moduleModelFromSpring1);\n            String serviceKey1 = HelloService.class.getName() + \":1.0.0\";\n            ServiceDescriptor serviceDescriptor1 =\n                    moduleModelFromSpring1.getServiceRepository().lookupService(serviceKey1);\n            Assertions.assertNotNull(serviceDescriptor1);\n\n            // close spring context 1\n            providerContext1.close();\n            Assertions.assertTrue(moduleModel1.isDestroyed());\n            Assertions.assertFalse(moduleModel1.getApplicationModel().isDestroyed());\n            providerContext1 = null;\n\n            ModuleModel moduleModel2 = applicationModel.newModule();\n            DubboSpringInitCustomizerHolder.get().addCustomizer(context -> {\n                context.setModuleModel(moduleModel2);\n            });\n\n            // load spring context 2\n            providerContext2 = new ClassPathXmlApplicationContext(\"dubbo-provider-v2.xml\", getClass());\n            ModuleModel moduleModelFromSpring2 = providerContext2.getBean(ModuleModel.class);\n            Assertions.assertSame(moduleModel2, moduleModelFromSpring2);\n            Assertions.assertNotSame(moduleModelFromSpring1, moduleModelFromSpring2);\n            String serviceKey2 = HelloService.class.getName() + \":2.0.0\";\n            ServiceDescriptor serviceDescriptor2 =\n                    moduleModelFromSpring2.getServiceRepository().lookupService(serviceKey2);\n            Assertions.assertNotNull(serviceDescriptor2);\n            Assertions.assertNotSame(serviceDescriptor1, serviceDescriptor2);\n\n            providerContext2.close();\n            providerContext2 = null;\n        } finally {\n            if (providerContext1 != null) {\n                providerContext1.close();\n            }\n            if (providerContext2 != null) {\n                providerContext2.close();\n            }\n            applicationModel.destroy();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/customize/dubbo-provider-v1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"demo-provider\">\n    </dubbo:application>\n\n    <dubbo:registry address=\"${dubbo.registry.address}\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"-1\"/>\n\n    <bean id=\"helloServiceImpl\" class=\"org.apache.dubbo.config.spring.impl.HelloServiceImpl\"/>\n\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.HelloService\" timeout=\"3000\"\n                   version=\"1.0.0\" ref=\"helloServiceImpl\" protocol=\"dubbo\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/customize/dubbo-provider-v2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"demo-provider\">\n    </dubbo:application>\n\n    <dubbo:registry address=\"${dubbo.registry.address}\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"-1\"/>\n\n    <bean id=\"helloServiceImpl\" class=\"org.apache.dubbo.config.spring.context.annotation.provider.DefaultHelloService\"/>\n\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.HelloService\" timeout=\"3000\"\n                   version=\"2.0.0\" ref=\"helloServiceImpl\" protocol=\"dubbo\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.context.properties;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n@ExtendWith(SpringExtension.class)\n@TestPropertySource(locations = \"classpath:/dubbo-binder.properties\")\n@ContextConfiguration(classes = DefaultDubboConfigBinder.class)\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\nclass DefaultDubboConfigBinderTest {\n\n    @BeforeAll\n    public static void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private DubboConfigBinder dubboConfigBinder;\n\n    @Test\n    void testBinder() {\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        dubboConfigBinder.bind(\"dubbo.application\", applicationConfig);\n        Assertions.assertEquals(\"hello\", applicationConfig.getName());\n        Assertions.assertEquals(\"world\", applicationConfig.getOwner());\n\n        RegistryConfig registryConfig = new RegistryConfig();\n        dubboConfigBinder.bind(\"dubbo.registry\", registryConfig);\n        Assertions.assertEquals(\"10.20.153.17\", registryConfig.getAddress());\n\n        ProtocolConfig protocolConfig = new ProtocolConfig();\n        dubboConfigBinder.bind(\"dubbo.protocol\", protocolConfig);\n        Assertions.assertEquals(Integer.valueOf(20881), protocolConfig.getPort());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/BeanForContext2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.extension;\n\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.impl.DemoServiceImpl;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class BeanForContext2 {\n    @Bean(\"bean1\")\n    public DemoService context2Bean() {\n        return new DemoServiceImpl();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionInjectorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.extension;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.impl.DemoServiceImpl;\nimport org.apache.dubbo.config.spring.impl.HelloServiceImpl;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.rpc.Protocol;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@EnableDubbo(scanBasePackages = \"\")\n@Configuration\nclass SpringExtensionInjectorTest {\n\n    @BeforeEach\n    public void init() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void destroy() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testSpringInjector() {\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n        try {\n            context.setDisplayName(\"Context1\");\n            context.register(getClass());\n            context.refresh();\n\n            SpringExtensionInjector springExtensionInjector =\n                    SpringExtensionInjector.get(DubboBeanUtils.getApplicationModel(context));\n            Assertions.assertEquals(springExtensionInjector.getContext(), context);\n\n            Protocol protocol = springExtensionInjector.getInstance(Protocol.class, \"protocol\");\n            Assertions.assertNull(protocol);\n\n            DemoService demoServiceBean1 = springExtensionInjector.getInstance(DemoService.class, \"bean1\");\n            Assertions.assertNotNull(demoServiceBean1);\n            DemoService demoServiceBean2 = springExtensionInjector.getInstance(DemoService.class, \"bean2\");\n            Assertions.assertNotNull(demoServiceBean2);\n\n            HelloService helloServiceBean = springExtensionInjector.getInstance(HelloService.class, \"hello\");\n            Assertions.assertNotNull(helloServiceBean);\n\n            HelloService helloService = springExtensionInjector.getInstance(HelloService.class, null);\n            Assertions.assertEquals(helloService, helloServiceBean);\n\n            Assertions.assertThrows(\n                    IllegalStateException.class,\n                    () -> springExtensionInjector.getInstance(DemoService.class, null),\n                    \"Expect single but found 2 beans in spring context: [bean1, bean2]\");\n\n        } finally {\n            context.close();\n        }\n    }\n\n    @Bean(\"bean1\")\n    public DemoService bean1() {\n        return new DemoServiceImpl();\n    }\n\n    @Bean(\"bean2\")\n    public DemoService bean2() {\n        return new DemoServiceImpl();\n    }\n\n    @Bean(\"hello\")\n    public HelloService helloService() {\n        return new HelloServiceImpl();\n    }\n\n    @Bean\n    public ApplicationConfig applicationConfig() {\n        return new ApplicationConfig(\"test-app\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/filter/MockDao.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.filter;\n\npublic interface MockDao {}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/filter/MockDaoImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.filter;\n\npublic class MockDaoImpl implements MockDao {}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/filter/MockFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.filter;\n\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.LoadBalance;\n\npublic class MockFilter implements Filter {\n\n    private LoadBalance loadBalance;\n\n    private Protocol protocol;\n\n    private MockDao mockDao;\n\n    public MockDao getMockDao() {\n        return mockDao;\n    }\n\n    public void setMockDao(MockDao mockDao) {\n        this.mockDao = mockDao;\n    }\n\n    public LoadBalance getLoadBalance() {\n        return loadBalance;\n    }\n\n    public void setLoadBalance(LoadBalance loadBalance) {\n        this.loadBalance = loadBalance;\n    }\n\n    public Protocol getProtocol() {\n        return protocol;\n    }\n\n    public void setProtocol(Protocol protocol) {\n        this.protocol = protocol;\n    }\n\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        return invoker.invoke(invocation);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.impl;\n\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\npublic class DemoServiceImpl implements DemoService {\n\n    private String prefix = \"say:\";\n\n    public String sayName(String name) {\n        return prefix + name;\n    }\n\n    public Box getBox() {\n        return null;\n    }\n\n    public String getPrefix() {\n        return prefix;\n    }\n\n    public void setPrefix(String prefix) {\n        this.prefix = prefix;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/DemoServiceImpl_LongWaiting.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.impl;\n\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\n/**\n * DemoServiceImpl\n */\npublic class DemoServiceImpl_LongWaiting implements DemoService {\n\n    public String sayName(String name) {\n        try {\n            Thread.sleep(100 * 1000);\n        } catch (InterruptedException e) {\n        }\n\n        return \"say:\" + name;\n    }\n\n    public Box getBox() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/DemoServiceSonImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.impl;\n\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoServiceSon;\n\npublic class DemoServiceSonImpl implements DemoServiceSon {\n\n    private String prefix = \"say:\";\n\n    public String sayName(String name) {\n        return prefix + name;\n    }\n\n    public Box getBox() {\n        return null;\n    }\n\n    public String getPrefix() {\n        return prefix;\n    }\n\n    public void setPrefix(String prefix) {\n        this.prefix = prefix;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/HelloServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.impl;\n\nimport org.apache.dubbo.config.spring.api.HelloService;\n\npublic class HelloServiceImpl implements HelloService {\n\n    public String sayHello(String name) {\n        return \"Hello, \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/MethodCallbackImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.impl;\n\nimport org.apache.dubbo.config.spring.api.MethodCallback;\n\nimport javax.annotation.PostConstruct;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.transaction.support.TransactionSynchronizationManager;\n\npublic class MethodCallbackImpl implements MethodCallback {\n    private String onInvoke1 = \"\";\n\n    private final Object lock = new Object();\n\n    private String onReturn1 = \"\";\n    private String onThrow1 = \"\";\n\n    private String onInvoke2 = \"\";\n    private String onReturn2 = \"\";\n    private String onThrow2 = \"\";\n\n    @Autowired\n    private Environment environment;\n\n    @Autowired\n    private ApplicationContext context;\n\n    public static AtomicInteger cnt = new AtomicInteger();\n\n    @PostConstruct\n    protected void init() {\n        checkInjection();\n    }\n\n    @Transactional(rollbackFor = Exception.class)\n    @Override\n    public void oninvoke1(String request) {\n        try {\n            checkInjection();\n            checkTranscation();\n            synchronized (lock) {\n                this.onInvoke1 += \"dubbo invoke success!\";\n            }\n        } catch (Exception e) {\n            synchronized (lock) {\n                this.onInvoke1 += e.toString();\n            }\n            throw e;\n        }\n    }\n\n    @Transactional(rollbackFor = Exception.class)\n    @Override\n    public void oninvoke2(String request) {\n        try {\n            checkInjection();\n            checkTranscation();\n            synchronized (lock) {\n                this.onInvoke2 += \"dubbo invoke success(2)!\";\n            }\n        } catch (Exception e) {\n            synchronized (lock) {\n                this.onInvoke2 += e.toString();\n            }\n            throw e;\n        }\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void onreturn1(String response, String request) {\n        try {\n            checkInjection();\n            checkTranscation();\n            synchronized (lock) {\n                this.onReturn1 += \"dubbo return success!\";\n            }\n        } catch (Exception e) {\n            synchronized (lock) {\n                this.onReturn1 += e.toString();\n            }\n            throw e;\n        } finally {\n            cnt.incrementAndGet();\n        }\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void onreturn2(String response, String request) {\n        try {\n            checkInjection();\n            checkTranscation();\n            synchronized (lock) {\n                this.onReturn2 += \"dubbo return success(2)!\";\n            }\n        } catch (Exception e) {\n            synchronized (lock) {\n                this.onReturn2 += e.toString();\n            }\n            throw e;\n        } finally {\n            cnt.incrementAndGet();\n        }\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void onthrow1(Throwable ex, String request) {\n        try {\n            checkInjection();\n            checkTranscation();\n            synchronized (lock) {\n                this.onThrow1 += \"dubbo throw exception!\";\n            }\n        } catch (Exception e) {\n            synchronized (lock) {\n                this.onThrow1 += e.toString();\n            }\n            throw e;\n        }\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void onthrow2(Throwable ex, String request) {\n        try {\n            checkInjection();\n            checkTranscation();\n            synchronized (lock) {\n                this.onThrow2 += \"dubbo throw exception(2)!\";\n            }\n        } catch (Exception e) {\n            synchronized (lock) {\n                this.onThrow2 += e.toString();\n            }\n            throw e;\n        }\n    }\n\n    public String getOnInvoke1() {\n        return this.onInvoke1;\n    }\n\n    public String getOnReturn1() {\n        return this.onReturn1;\n    }\n\n    public String getOnThrow1() {\n        return this.onThrow1;\n    }\n\n    public String getOnInvoke2() {\n        return this.onInvoke2;\n    }\n\n    public String getOnReturn2() {\n        return this.onReturn2;\n    }\n\n    public String getOnThrow2() {\n        return this.onThrow2;\n    }\n\n    private void checkInjection() {\n        if (environment == null) {\n            throw new IllegalStateException(\"environment is null\");\n        }\n        if (context == null) {\n            throw new IllegalStateException(\"application context is null\");\n        }\n    }\n\n    private void checkTranscation() {\n        if (!TransactionSynchronizationManager.isActualTransactionActive()) {\n            throw new IllegalStateException(\"No active transaction\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/NotifyService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.impl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class NotifyService {\n    private static final Logger logger = LoggerFactory.getLogger(NotifyService.class);\n\n    public void onInvoke(Object[] params) {\n        logger.info(\"invoke param-0: {}\", params[0]);\n    }\n\n    public void onReturn(Object result, Object[] params) {\n        logger.info(\"invoke param-0: {}, return: {}\", params[0], result);\n    }\n\n    public void onThrow(Throwable t, Object[] params) {\n        logger.info(\"invoke param-0: {}, throw: {}\", params[0], t.getMessage());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/UnserializableBox.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.impl;\n\nimport org.apache.dubbo.config.spring.api.Box;\n\npublic class UnserializableBox implements Box {\n    private static final long serialVersionUID = -4141012025649711421L;\n\n    private int count = 3;\n    private String name = \"Jerry\";\n\n    public int getCount() {\n        return count;\n    }\n\n    public void setCount(int count) {\n        this.count = count;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public String toString() {\n        return \"Box [count=\" + count + \", name=\" + name + \"]\";\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/UnserializableBoxDemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.impl;\n\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\n/**\n * DemoServiceImpl\n */\npublic class UnserializableBoxDemoServiceImpl implements DemoService {\n\n    public String sayName(String name) {\n        return \"say:\" + name;\n    }\n\n    public Box getBox() {\n        return new UnserializableBox();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/api/ApiIsolationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.api;\n\nimport org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.common.threadpool.manager.IsolationExecutorRepository;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.impl.DemoServiceImpl;\nimport org.apache.dubbo.config.spring.impl.HelloServiceImpl;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_ISOLATION;\n\npublic class ApiIsolationTest {\n    private static RegistryConfig registryConfig;\n\n    @BeforeAll\n    public static void beforeAll() {\n        FrameworkModel.destroyAll();\n        registryConfig = new RegistryConfig(ZookeeperRegistryCenterConfig.getConnectionAddress1());\n    }\n\n    @AfterAll\n    public static void afterAll() throws Exception {\n        FrameworkModel.destroyAll();\n    }\n\n    private String version1 = \"1.0\";\n    private String version2 = \"2.0\";\n    private String version3 = \"3.0\";\n\n    @Test\n    @Disabled\n    public void test() throws Exception {\n\n        DubboBootstrap providerBootstrap = null;\n        DubboBootstrap consumerBootstrap1 = null;\n        DubboBootstrap consumerBootstrap2 = null;\n\n        try {\n\n            // provider app\n            providerBootstrap = DubboBootstrap.newInstance();\n\n            ServiceConfig serviceConfig1 = new ServiceConfig();\n            serviceConfig1.setInterface(DemoService.class);\n            serviceConfig1.setRef(new DemoServiceImpl());\n            serviceConfig1.setVersion(version1);\n            // set executor1 for serviceConfig1, max threads is 10\n            NamedThreadFactory threadFactory1 = new NamedThreadFactory(\"DemoService-executor\");\n            ExecutorService executor1 = Executors.newFixedThreadPool(10, threadFactory1);\n            serviceConfig1.setExecutor(executor1);\n\n            ServiceConfig serviceConfig2 = new ServiceConfig();\n            serviceConfig2.setInterface(HelloService.class);\n            serviceConfig2.setRef(new HelloServiceImpl());\n            serviceConfig2.setVersion(version2);\n            // set executor2 for serviceConfig2, max threads is 100\n            NamedThreadFactory threadFactory2 = new NamedThreadFactory(\"HelloService-executor\");\n            ExecutorService executor2 = Executors.newFixedThreadPool(100, threadFactory2);\n            serviceConfig2.setExecutor(executor2);\n\n            ServiceConfig serviceConfig3 = new ServiceConfig();\n            serviceConfig3.setInterface(HelloService.class);\n            serviceConfig3.setRef(new HelloServiceImpl());\n            serviceConfig3.setVersion(version3);\n            // Because executor is not set for serviceConfig3, the default executor of serviceConfig3 is built using\n            // the threadpool parameter of the protocolConfig ( FixedThreadpool , max threads is 200)\n            serviceConfig3.setExecutor(null);\n\n            // It takes effect only if [executor-management-mode=isolation] is configured\n            ApplicationConfig applicationConfig = new ApplicationConfig(\"provider-app\");\n            applicationConfig.setExecutorManagementMode(EXECUTOR_MANAGEMENT_MODE_ISOLATION);\n\n            providerBootstrap\n                    .application(applicationConfig)\n                    .registry(registryConfig)\n                    // export with tri and dubbo protocol\n                    .protocol(new ProtocolConfig(\"tri\", 20001))\n                    .protocol(new ProtocolConfig(\"dubbo\", 20002))\n                    .service(serviceConfig1)\n                    .service(serviceConfig2)\n                    .service(serviceConfig3);\n\n            providerBootstrap.start();\n\n            // Verify that the executor is the previously configured\n            ApplicationModel applicationModel = providerBootstrap.getApplicationModel();\n            ExecutorRepository repository = ExecutorRepository.getInstance(applicationModel);\n            Assertions.assertTrue(repository instanceof IsolationExecutorRepository);\n            Assertions.assertEquals(executor1, repository.getExecutor(serviceConfig1.toUrl()));\n            Assertions.assertEquals(executor2, repository.getExecutor(serviceConfig2.toUrl()));\n            // the default executor of serviceConfig3 is built using the threadpool parameter of the protocol\n            ThreadPoolExecutor executor3 = (ThreadPoolExecutor) repository.getExecutor(serviceConfig3.toUrl());\n            Assertions.assertTrue(executor3.getThreadFactory() instanceof NamedInternalThreadFactory);\n            NamedInternalThreadFactory threadFactory3 = (NamedInternalThreadFactory) executor3.getThreadFactory();\n\n            // consumer app start with dubbo protocol and rpc call\n            consumerBootstrap1 = configConsumerBootstrapWithProtocol(\"dubbo\");\n            rpcInvoke(consumerBootstrap1);\n\n            // consumer app start with tri protocol and rpc call\n            consumerBootstrap2 = configConsumerBootstrapWithProtocol(\"tri\");\n            rpcInvoke(consumerBootstrap2);\n\n            // Verify that when the provider accepts different service requests,\n            // whether to use the respective executor(threadFactory) of different services to create threads\n            AtomicInteger threadNum1 = threadFactory1.getThreadNum();\n            AtomicInteger threadNum2 = threadFactory2.getThreadNum();\n            AtomicInteger threadNum3 = threadFactory3.getThreadNum();\n            Assertions.assertEquals(threadNum1.get(), 11);\n            Assertions.assertEquals(threadNum2.get(), 101);\n            Assertions.assertEquals(threadNum3.get(), 201);\n\n        } finally {\n            if (providerBootstrap != null) {\n                providerBootstrap.destroy();\n            }\n            if (consumerBootstrap1 != null) {\n                consumerBootstrap1.destroy();\n            }\n            if (consumerBootstrap2 != null) {\n                consumerBootstrap2.destroy();\n            }\n        }\n    }\n\n    private void rpcInvoke(DubboBootstrap consumerBootstrap) {\n        DemoService demoServiceV1 = consumerBootstrap.getCache().get(DemoService.class.getName() + \":\" + version1);\n        HelloService helloServiceV2 = consumerBootstrap.getCache().get(HelloService.class.getName() + \":\" + version2);\n        HelloService helloServiceV3 = consumerBootstrap.getCache().get(HelloService.class.getName() + \":\" + version3);\n        for (int i = 0; i < 250; i++) {\n            demoServiceV1.sayName(\"name, version = \" + version1);\n        }\n        for (int i = 0; i < 250; i++) {\n            helloServiceV2.sayHello(\"hello, version = \" + version2);\n        }\n        for (int i = 0; i < 250; i++) {\n            helloServiceV3.sayHello(\"hello, version = \" + version3);\n        }\n    }\n\n    private DubboBootstrap configConsumerBootstrapWithProtocol(String protocol) {\n        DubboBootstrap consumerBootstrap;\n        consumerBootstrap = DubboBootstrap.newInstance();\n        consumerBootstrap\n                .application(\"consumer-app\")\n                .registry(registryConfig)\n                .reference(builder -> builder.interfaceClass(DemoService.class)\n                        .version(version1)\n                        .protocol(protocol)\n                        .injvm(false))\n                .reference(builder -> builder.interfaceClass(HelloService.class)\n                        .version(version2)\n                        .protocol(protocol)\n                        .injvm(false))\n                .reference(builder -> builder.interfaceClass(HelloService.class)\n                        .version(version3)\n                        .protocol(protocol)\n                        .injvm(false));\n        consumerBootstrap.start();\n        return consumerBootstrap;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/BaseTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring;\n\nimport org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.common.threadpool.manager.IsolationExecutorRepository;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.isolation.spring.support.DemoServiceExecutor;\nimport org.apache.dubbo.config.spring.isolation.spring.support.HelloServiceExecutor;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.ApplicationContext;\n\npublic abstract class BaseTest {\n\n    protected ServiceConfig serviceConfig1;\n    protected ServiceConfig serviceConfig2;\n    protected ServiceConfig serviceConfig3;\n\n    @Test\n    public void test() throws Exception {\n        test();\n    }\n\n    protected void assertExecutor(ApplicationContext providerContext, ApplicationContext consumerContext) {\n\n        // find configured \"executor-demo-service\" executor\n        Map<String, DemoServiceExecutor> beansOfType1 = providerContext.getBeansOfType(DemoServiceExecutor.class);\n        ThreadPoolExecutor executor1 = beansOfType1.get(\"executor-demo-service\");\n        NamedThreadFactory threadFactory1 = (NamedThreadFactory) executor1.getThreadFactory();\n\n        // find configured \"executor-hello-service\" executor\n        Map<String, HelloServiceExecutor> beansOfType2 = providerContext.getBeansOfType(HelloServiceExecutor.class);\n        ThreadPoolExecutor executor2 = beansOfType2.get(\"executor-hello-service\");\n        NamedThreadFactory threadFactory2 = (NamedThreadFactory) executor2.getThreadFactory();\n\n        // Verify that the executor is the previously configured\n        Map<String, ApplicationModel> applicationModelMap = providerContext.getBeansOfType(ApplicationModel.class);\n        ApplicationModel applicationModel = applicationModelMap.get(ApplicationModel.class.getName());\n        ExecutorRepository repository = ExecutorRepository.getInstance(applicationModel);\n        Assertions.assertTrue(repository instanceof IsolationExecutorRepository);\n        Assertions.assertEquals(executor1, repository.getExecutor(serviceConfig1.toUrl()));\n        Assertions.assertEquals(executor2, repository.getExecutor(serviceConfig2.toUrl()));\n        // the default executor of serviceConfig3 is built using the threadpool parameter of the protocol\n        ThreadPoolExecutor executor3 = (ThreadPoolExecutor) repository.getExecutor(serviceConfig3.toUrl());\n        Assertions.assertTrue(executor3.getThreadFactory() instanceof NamedInternalThreadFactory);\n        NamedInternalThreadFactory threadFactory3 = (NamedInternalThreadFactory) executor3.getThreadFactory();\n\n        // rpc invoke with dubbo protocol\n        DemoService demoServiceV1 = consumerContext.getBean(\"dubbo-demoServiceV1\", DemoService.class);\n        HelloService helloServiceV2 = consumerContext.getBean(\"dubbo-helloServiceV2\", HelloService.class);\n        HelloService helloServiceV3 = consumerContext.getBean(\"dubbo-helloServiceV3\", HelloService.class);\n        rpcInvoke(demoServiceV1, helloServiceV2, helloServiceV3);\n\n        // rpc invoke with tri protocol\n        demoServiceV1 = consumerContext.getBean(\"tri-demoServiceV1\", DemoService.class);\n        helloServiceV2 = consumerContext.getBean(\"tri-helloServiceV2\", HelloService.class);\n        helloServiceV3 = consumerContext.getBean(\"tri-helloServiceV3\", HelloService.class);\n        rpcInvoke(demoServiceV1, helloServiceV2, helloServiceV3);\n\n        // Verify that when the provider accepts different service requests,\n        // whether to use the respective executor(threadFactory) of different services to create threads\n        AtomicInteger threadNum1 = threadFactory1.getThreadNum();\n        AtomicInteger threadNum2 = threadFactory2.getThreadNum();\n        AtomicInteger threadNum3 = threadFactory3.getThreadNum();\n        Assertions.assertEquals(threadNum1.get(), 11);\n        Assertions.assertEquals(threadNum2.get(), 101);\n        Assertions.assertEquals(threadNum3.get(), 201);\n    }\n\n    private void rpcInvoke(DemoService demoServiceV1, HelloService helloServiceV2, HelloService helloServiceV3) {\n        for (int i = 0; i < 250; i++) {\n            demoServiceV1.sayName(\"name\");\n        }\n        for (int i = 0; i < 250; i++) {\n            helloServiceV2.sayHello(\"hello\");\n        }\n        for (int i = 0; i < 250; i++) {\n            helloServiceV3.sayHello(\"hello\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/annotation/AnnotationIsolationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.annotation;\n\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.isolation.spring.BaseTest;\nimport org.apache.dubbo.config.spring.isolation.spring.support.DemoServiceExecutor;\nimport org.apache.dubbo.config.spring.isolation.spring.support.HelloServiceExecutor;\n\nimport java.util.Map;\nimport java.util.concurrent.Executor;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_ISOLATION;\n\npublic class AnnotationIsolationTest extends BaseTest {\n\n    @Test\n    public void test() throws Exception {\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n        // start provider app\n        AnnotationConfigApplicationContext providerContext =\n                new AnnotationConfigApplicationContext(ProviderConfiguration.class);\n        providerContext.start();\n\n        // start consumer app\n        AnnotationConfigApplicationContext consumerContext =\n                new AnnotationConfigApplicationContext(ConsumerConfiguration.class);\n        consumerContext.start();\n\n        // getAndSet serviceConfig\n        setServiceConfig(providerContext);\n\n        // assert isolation of executor\n        assertExecutor(providerContext, consumerContext);\n\n        // close context\n        providerContext.close();\n        consumerContext.close();\n    }\n\n    private void setServiceConfig(AnnotationConfigApplicationContext providerContext) {\n        Map<String, ServiceConfig> serviceConfigMap = providerContext.getBeansOfType(ServiceConfig.class);\n        serviceConfig1 =\n                serviceConfigMap.get(\"ServiceBean:org.apache.dubbo.config.spring.api.DemoService:1.0.0:Group1\");\n        serviceConfig2 =\n                serviceConfigMap.get(\"ServiceBean:org.apache.dubbo.config.spring.api.HelloService:2.0.0:Group2\");\n        serviceConfig3 =\n                serviceConfigMap.get(\"ServiceBean:org.apache.dubbo.config.spring.api.HelloService:3.0.0:Group3\");\n    }\n\n    // note scanBasePackages, refer three service with dubbo and tri protocol\n    @Configuration\n    @EnableDubbo(scanBasePackages = \"org.apache.dubbo.demo.consumer.comp\")\n    @ComponentScan(value = {\"org.apache.dubbo.config.spring.isolation.spring.annotation.consumer\"})\n    static class ConsumerConfiguration {\n        @Bean\n        public RegistryConfig registryConfig() {\n            RegistryConfig registryConfig = new RegistryConfig();\n            registryConfig.setAddress(\"zookeeper://127.0.0.1:2181\");\n            return registryConfig;\n        }\n\n        @Bean\n        public ApplicationConfig applicationConfig() {\n            ApplicationConfig applicationConfig = new ApplicationConfig(\"consumer-app\");\n            return applicationConfig;\n        }\n    }\n\n    // note scanBasePackages, expose three service with dubbo and tri protocol\n    @Configuration\n    @EnableDubbo(scanBasePackages = \"org.apache.dubbo.config.spring.isolation.spring.annotation.provider\")\n    static class ProviderConfiguration {\n        @Bean\n        public RegistryConfig registryConfig() {\n            RegistryConfig registryConfig = new RegistryConfig();\n            registryConfig.setAddress(\"zookeeper://127.0.0.1:2181\");\n            return registryConfig;\n        }\n\n        // NOTE: we need config executor-management-mode=\"isolation\"\n        @Bean\n        public ApplicationConfig applicationConfig() {\n            ApplicationConfig applicationConfig = new ApplicationConfig(\"provider-app\");\n\n            applicationConfig.setExecutorManagementMode(EXECUTOR_MANAGEMENT_MODE_ISOLATION);\n            return applicationConfig;\n        }\n\n        // expose services with dubbo protocol\n        @Bean\n        public ProtocolConfig dubbo() {\n            ProtocolConfig protocolConfig = new ProtocolConfig(\"dubbo\", NetUtils.getAvailablePort());\n            return protocolConfig;\n        }\n\n        // expose services with tri protocol\n        @Bean\n        public ProtocolConfig tri() {\n            ProtocolConfig protocolConfig = new ProtocolConfig(\"tri\", NetUtils.getAvailablePort());\n            return protocolConfig;\n        }\n\n        // customized thread pool\n        @Bean(\"executor-demo-service\")\n        public Executor demoServiceExecutor() {\n            return new DemoServiceExecutor();\n        }\n\n        // customized thread pool\n        @Bean(\"executor-hello-service\")\n        public Executor helloServiceExecutor() {\n            return new HelloServiceExecutor();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/annotation/consumer/dubbo/DemoServiceV1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.annotation.consumer.dubbo;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\nimport org.springframework.stereotype.Component;\n\n@Component(\"dubbo-demoServiceV1\")\npublic class DemoServiceV1 implements DemoService {\n    @DubboReference(version = \"1.0.0\", group = \"Group1\", scope = \"remote\", protocol = \"dubbo\")\n    private DemoService demoService;\n\n    @Override\n    public String sayName(String name) {\n        return demoService.sayName(name);\n    }\n\n    @Override\n    public Box getBox() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/annotation/consumer/dubbo/HelloServiceV2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.annotation.consumer.dubbo;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.springframework.stereotype.Component;\n\n@Component(\"dubbo-helloServiceV2\")\npublic class HelloServiceV2 implements HelloService {\n    @DubboReference(version = \"2.0.0\", group = \"Group2\", scope = \"remote\", protocol = \"dubbo\")\n    private HelloService helloService;\n\n    @Override\n    public String sayHello(String name) {\n        return helloService.sayHello(name);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/annotation/consumer/dubbo/HelloServiceV3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.annotation.consumer.dubbo;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.springframework.stereotype.Component;\n\n@Component(\"dubbo-helloServiceV3\")\npublic class HelloServiceV3 implements HelloService {\n    @DubboReference(version = \"3.0.0\", group = \"Group3\", scope = \"remote\", protocol = \"dubbo\")\n    private HelloService helloService;\n\n    @Override\n    public String sayHello(String name) {\n        return helloService.sayHello(name);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/annotation/consumer/tri/DemoServiceV1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.annotation.consumer.tri;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\nimport org.springframework.stereotype.Component;\n\n@Component(\"tri-demoServiceV1\")\npublic class DemoServiceV1 implements DemoService {\n    @DubboReference(version = \"1.0.0\", group = \"Group1\", scope = \"remote\", protocol = \"tri\")\n    private DemoService demoService;\n\n    @Override\n    public String sayName(String name) {\n        return demoService.sayName(name);\n    }\n\n    @Override\n    public Box getBox() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/annotation/consumer/tri/HelloServiceV2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.annotation.consumer.tri;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.springframework.stereotype.Component;\n\n@Component(\"tri-helloServiceV2\")\npublic class HelloServiceV2 implements HelloService {\n    @DubboReference(version = \"2.0.0\", group = \"Group2\", scope = \"remote\", protocol = \"tri\")\n    private HelloService helloService;\n\n    @Override\n    public String sayHello(String name) {\n        return helloService.sayHello(name);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/annotation/consumer/tri/HelloServiceV3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.annotation.consumer.tri;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.springframework.stereotype.Component;\n\n@Component(\"tri-helloServiceV3\")\npublic class HelloServiceV3 implements HelloService {\n    @DubboReference(version = \"3.0.0\", group = \"Group3\", scope = \"remote\", protocol = \"tri\")\n    private HelloService helloService;\n\n    @Override\n    public String sayHello(String name) {\n        return helloService.sayHello(name);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/annotation/provider/DemoServiceImplV1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.annotation.provider;\n\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoService;\n\n@DubboService(executor = \"executor-demo-service\", version = \"1.0.0\", group = \"Group1\")\npublic class DemoServiceImplV1 implements DemoService {\n\n    @Override\n    public String sayName(String name) {\n        return \"server name\";\n    }\n\n    @Override\n    public Box getBox() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/annotation/provider/HelloServiceImplV2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.annotation.provider;\n\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@DubboService(version = \"3.0.0\", group = \"Group3\")\npublic class HelloServiceImplV2 implements HelloService {\n    private static final Logger logger = LoggerFactory.getLogger(HelloServiceImplV2.class);\n\n    @Override\n    public String sayHello(String name) {\n        return \"server hello\";\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/annotation/provider/HelloServiceImplV3.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.annotation.provider;\n\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@DubboService(executor = \"executor-hello-service\", version = \"2.0.0\", group = \"Group2\")\npublic class HelloServiceImplV3 implements HelloService {\n    private static final Logger logger = LoggerFactory.getLogger(HelloServiceImplV3.class);\n\n    @Override\n    public String sayHello(String name) {\n        return \"server hello\";\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/support/DemoServiceExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.support;\n\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\n\nimport java.util.concurrent.LinkedBlockingDeque;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\npublic class DemoServiceExecutor extends ThreadPoolExecutor {\n    public DemoServiceExecutor() {\n        super(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(), new NamedThreadFactory(\"DemoServiceExecutor\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/support/HelloServiceExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.support;\n\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\n\nimport java.util.concurrent.LinkedBlockingDeque;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\npublic class HelloServiceExecutor extends ThreadPoolExecutor {\n    public HelloServiceExecutor() {\n        super(\n                100,\n                100,\n                60,\n                TimeUnit.SECONDS,\n                new LinkedBlockingDeque<>(),\n                new NamedThreadFactory(\"HelloServiceExecutor\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/isolation/spring/xml/XmlIsolationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.isolation.spring.xml;\n\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.spring.isolation.spring.BaseTest;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\npublic class XmlIsolationTest extends BaseTest {\n\n    @Test\n    public void test() throws Exception {\n        // start provider app\n        ClassPathXmlApplicationContext providerContext =\n                new ClassPathXmlApplicationContext(\"META-INF/isolation/dubbo-provider.xml\");\n        providerContext.start();\n\n        // start consumer app\n        ClassPathXmlApplicationContext consumerContext =\n                new ClassPathXmlApplicationContext(\"META-INF/isolation/dubbo-consumer.xml\");\n        consumerContext.start();\n\n        // getAndSet serviceConfig\n        setServiceConfig(providerContext);\n\n        // assert isolation of executor\n        assertExecutor(providerContext, consumerContext);\n\n        // close context\n        providerContext.close();\n        consumerContext.close();\n    }\n\n    private void setServiceConfig(ClassPathXmlApplicationContext providerContext) {\n        Map<String, ServiceConfig> serviceConfigMap = providerContext.getBeansOfType(ServiceConfig.class);\n        serviceConfig1 = serviceConfigMap.get(\"org.apache.dubbo.config.spring.ServiceBean#0\");\n        serviceConfig2 = serviceConfigMap.get(\"org.apache.dubbo.config.spring.ServiceBean#1\");\n        serviceConfig3 = serviceConfigMap.get(\"org.apache.dubbo.config.spring.ServiceBean#2\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue6000/Issue6000Test.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.issues.issue6000;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.issues.issue6000.adubbo.HelloDubbo;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\n\n/**\n * The test-case for https://github.com/apache/dubbo/issues/6000\n * Autowired a ReferenceBean failed in some situation in Spring environment\n */\n@Configuration\n@EnableDubbo\n@ComponentScan\n@PropertySource(\"classpath:/META-INF/issues/issue6000/config.properties\")\nclass Issue6000Test {\n    private static final Logger logger = LoggerFactory.getLogger(Issue6000Test.class);\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void test() {\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Issue6000Test.class);\n        try {\n\n            HelloDubbo helloDubbo = context.getBean(HelloDubbo.class);\n            String result = helloDubbo.sayHello(\"dubbo\");\n            logger.info(result);\n\n        } catch (Exception e) {\n            String s = e.toString();\n            Assertions.assertTrue(s.contains(\"No provider available\"), s);\n            Assertions.assertTrue(s.contains(\"org.apache.dubbo.config.spring.api.HelloService:1.0.0\"), s);\n        } finally {\n            context.close();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue6000/adubbo/HelloDubbo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.issues.issue6000.adubbo;\n\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HelloDubbo {\n    HelloService helloService;\n\n    @Autowired\n    public void setHelloService(HelloService helloService) {\n        this.helloService = helloService;\n    }\n\n    public String sayHello(String name) {\n        return helloService.sayHello(name);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue6000/dubbo/MyReferenceConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.issues.issue6000.dubbo;\n\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * This configuration class is considered to be initialized after HelloDubbo,\n * but the reference bean defined in it can be injected into HelloDubbo\n */\n@Configuration\npublic class MyReferenceConfig {\n    @Reference(version = \"1.0.0\", check = false)\n    HelloService helloService;\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue6252/Issue6252Test.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.issues.issue6252;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\n\n/**\n * The test-case for https://github.com/apache/dubbo/issues/6252\n *\n * @since 2.7.8\n */\n@Configuration\n@EnableDubboConfig\n@PropertySource(\"classpath:/META-INF/issues/issue6252/config.properties\")\nclass Issue6252Test {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @DubboReference\n    private DemoService demoService;\n\n    @Test\n    void test() {\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Issue6252Test.class);\n        try {\n            DemoService demoService = context.getBean(DemoService.class);\n        } finally {\n            context.close();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue7003/Issue7003Test.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.issues.issue7003;\n\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.stereotype.Component;\n\n/**\n *\n * Multiple duplicate Dubbo Reference annotations with the same attribute generate only one instance.\n * The test-case for https://github.com/apache/dubbo/issues/7003\n */\n@Configuration\n@EnableDubbo\n@ComponentScan\n@PropertySource(\"classpath:/META-INF/issues/issue7003/config.properties\")\nclass Issue7003Test {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void test() {\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Issue7003Test.class);\n        try {\n\n            Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n            Assertions.assertEquals(1, referenceBeanMap.size());\n\n            Collection<ReferenceConfigBase<?>> references = ApplicationModel.defaultModel()\n                    .getDefaultModule()\n                    .getConfigManager()\n                    .getReferences();\n            Assertions.assertEquals(1, references.size());\n\n        } finally {\n            context.close();\n        }\n    }\n\n    @Component\n    static class ClassA {\n\n        @DubboReference(group = \"demo\", version = \"1.2.3\", check = false)\n        private HelloService helloService;\n    }\n\n    @Component\n    static class ClassB {\n\n        @DubboReference(check = false, version = \"1.2.3\", group = \"demo\")\n        private HelloService helloService;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue9172/MultipleConsumerAndProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.issues.issue9172;\n\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.impl.DemoServiceImpl;\nimport org.apache.dubbo.config.spring.impl.HelloServiceImpl;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.PropertySource;\n\n/**\n * Test for issue 9172\n */\nclass MultipleConsumerAndProviderTest {\n\n    @BeforeEach\n    void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void test() {\n\n        AnnotationConfigApplicationContext providerContext = null;\n        AnnotationConfigApplicationContext consumerContext = null;\n\n        try {\n            providerContext = new AnnotationConfigApplicationContext(ProviderConfiguration.class);\n            consumerContext = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);\n\n            ModuleModel consumerModuleModel = DubboBeanUtils.getModuleModel(consumerContext);\n            ModuleConfigManager consumerConfigManager = consumerModuleModel.getConfigManager();\n            ReferenceConfigBase helloServiceOneConfig = consumerConfigManager.getReference(\"helloServiceOne\");\n            ReferenceConfigBase demoServiceTwoConfig = consumerConfigManager.getReference(\"demoServiceTwo\");\n            Assertions.assertEquals(\n                    consumerConfigManager.getConsumer(\"consumer-one\").get(), helloServiceOneConfig.getConsumer());\n            Assertions.assertEquals(\n                    consumerConfigManager.getConsumer(\"consumer-two\").get(), demoServiceTwoConfig.getConsumer());\n            Assertions.assertEquals(\n                    consumerConfigManager.getRegistry(\"registry-one\").get(), helloServiceOneConfig.getRegistry());\n            Assertions.assertEquals(\n                    consumerConfigManager.getRegistry(\"registry-two\").get(), demoServiceTwoConfig.getRegistry());\n\n            HelloService helloServiceOne = consumerContext.getBean(\"helloServiceOne\", HelloService.class);\n            DemoService demoServiceTwo = consumerContext.getBean(\"demoServiceTwo\", DemoService.class);\n            String sayHello = helloServiceOne.sayHello(\"dubbo\");\n            String sayName = demoServiceTwo.sayName(\"dubbo\");\n            Assertions.assertEquals(\"Hello, dubbo\", sayHello);\n            Assertions.assertEquals(\"say:dubbo\", sayName);\n        } finally {\n            if (providerContext != null) {\n                providerContext.close();\n            }\n            if (consumerContext != null) {\n                consumerContext.close();\n            }\n        }\n    }\n\n    @EnableDubbo(scanBasePackages = \"\")\n    @PropertySource(\"classpath:/META-INF/issues/issue9172/consumer.properties\")\n    static class ConsumerConfiguration {\n\n        @DubboReference(consumer = \"consumer-one\")\n        private HelloService helloServiceOne;\n\n        @DubboReference(consumer = \"consumer-two\")\n        private DemoService demoServiceTwo;\n    }\n\n    @EnableDubbo(scanBasePackages = \"\")\n    @PropertySource(\"classpath:/META-INF/issues/issue9172/provider.properties\")\n    static class ProviderConfiguration {\n\n        @Bean\n        @DubboService(provider = \"provider-one\")\n        public HelloService helloServiceOne() {\n            return new HelloServiceImpl();\n        }\n\n        @Bean\n        @DubboService(provider = \"provider-two\")\n        public DemoService demoServiceTwo() {\n            return new DemoServiceImpl();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue9207/ConfigCenterBeanTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.issues.issue9207;\n\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.spring.ConfigCenterBean;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.StringReader;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\n\nclass ConfigCenterBeanTest {\n\n    private static final String DUBBO_PROPERTIES_FILE =\n            \"/META-INF/issues/issue9207/dubbo-properties-in-configcenter.properties\";\n    private static final String DUBBO_EXTERNAL_CONFIG_KEY = \"my-dubbo.properties\";\n\n    @BeforeEach\n    void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testConfigCenterBeanFromProps() throws IOException {\n        SysProps.setProperty(\"dubbo.config-center.include-spring-env\", \"true\");\n        SysProps.setProperty(\"dubbo.config-center.config-file\", DUBBO_EXTERNAL_CONFIG_KEY);\n\n        AnnotationConfigApplicationContext applicationContext =\n                new AnnotationConfigApplicationContext(ProviderConfiguration.class);\n        try {\n            ConfigManager configManager =\n                    DubboBeanUtils.getApplicationModel(applicationContext).getApplicationConfigManager();\n            Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();\n            Assertions.assertEquals(1, configCenters.size());\n\n            ConfigCenterConfig cc = configCenters.stream().findFirst().get();\n            Assertions.assertFalse(cc.getExternalConfiguration().isEmpty());\n            Assertions.assertTrue(cc instanceof ConfigCenterBean);\n\n            // check loaded external config\n            String content = readContent(DUBBO_PROPERTIES_FILE);\n            content = applicationContext.getEnvironment().resolvePlaceholders(content);\n            Properties properties = new Properties();\n            properties.load(new StringReader(content));\n            Assertions.assertEquals(properties, cc.getExternalConfiguration());\n        } finally {\n            SysProps.clear();\n            if (applicationContext != null) {\n                applicationContext.close();\n            }\n        }\n    }\n\n    @EnableDubbo(scanBasePackages = \"\")\n    @Configuration\n    static class ProviderConfiguration {\n\n        @Bean\n        public BeanFactoryPostProcessor envPostProcessor(ConfigurableEnvironment environment) {\n            return new BeanFactoryPostProcessor() {\n                @Override\n                public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n                    // add custom external configs to spring environment early before processing normal bean.\n                    // e.g. we can do it in BeanFactoryPostProcessor or EnvironmentPostProcessor\n                    Map<String, Object> dubboProperties = new HashMap<>();\n                    String content = readContent(DUBBO_PROPERTIES_FILE);\n                    dubboProperties.put(DUBBO_EXTERNAL_CONFIG_KEY, content);\n                    MapPropertySource dubboPropertySource =\n                            new MapPropertySource(\"dubbo external config\", dubboProperties);\n                    environment.getPropertySources().addLast(dubboPropertySource);\n                }\n            };\n        }\n    }\n\n    private static String readContent(String file) {\n        BufferedReader reader =\n                new BufferedReader(new InputStreamReader(ConfigCenterBeanTest.class.getResourceAsStream(file)));\n        String content = reader.lines().collect(Collectors.joining(\"\\n\"));\n        return content;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/metrics/SpringBootConfigMetricsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.metrics;\n\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\n\n@SpringBootTest(\n        properties = {\n            \"dubbo.application.NAME = dubbo-demo-application\",\n            \"dubbo.module.name = dubbo-demo-module\",\n            \"dubbo.registry.address = zookeeper://localhost:2181\",\n            \"dubbo.protocol.name=dubbo\",\n            \"dubbo.protocol.port=20880\",\n            \"dubbo.metrics.protocol=prometheus\",\n            \"dubbo.metrics.export-service-protocol=tri\",\n            \"dubbo.metrics.export-service-port=9999\",\n            \"dubbo.metrics.enable-jvm=true\",\n            \"dubbo.metrics.prometheus.exporter.enabled=true\",\n            \"dubbo.metrics.prometheus.exporter.enable-http-service-discovery=true\",\n            \"dubbo.metrics.prometheus.exporter.http-service-discovery-url=localhost:8080\",\n            \"dubbo.metrics.aggregation.enabled=true\",\n            \"dubbo.metrics.aggregation.bucket-num=5\",\n            \"dubbo.metrics.aggregation.time-window-seconds=120\",\n            \"dubbo.metrics.histogram.enabled=true\",\n            \"dubbo.metadata-report.address=${zookeeper.connection.address.2}\"\n        },\n        classes = {SpringBootConfigMetricsTest.class})\n@Configuration\n@ComponentScan\n@EnableDubbo\npublic class SpringBootConfigMetricsTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private ConfigManager configManager;\n\n    @Test\n    public void testMetrics() {\n        MetricsConfig metricsConfig = configManager.getMetrics().get();\n\n        Assertions.assertEquals(PROTOCOL_PROMETHEUS, metricsConfig.getProtocol());\n        Assertions.assertTrue(metricsConfig.getEnableJvm());\n        Assertions.assertEquals(\"tri\", metricsConfig.getExportServiceProtocol());\n        Assertions.assertEquals(9999, metricsConfig.getExportServicePort());\n        Assertions.assertTrue(metricsConfig.getPrometheus().getExporter().getEnabled());\n        Assertions.assertTrue(metricsConfig.getPrometheus().getExporter().getEnableHttpServiceDiscovery());\n        Assertions.assertEquals(\n                \"localhost:8080\", metricsConfig.getPrometheus().getExporter().getHttpServiceDiscoveryUrl());\n        Assertions.assertEquals(5, metricsConfig.getAggregation().getBucketNum());\n        Assertions.assertEquals(120, metricsConfig.getAggregation().getTimeWindowSeconds());\n        Assertions.assertTrue(metricsConfig.getAggregation().getEnabled());\n        Assertions.assertTrue(metricsConfig.getHistogram().getEnabled());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/DemoBeanFactoryPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.propertyconfigurer.consumer;\n\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.core.PriorityOrdered;\n\npublic class DemoBeanFactoryPostProcessor implements BeanFactoryPostProcessor, PriorityOrdered {\n\n    private HelloService demoService;\n\n    public DemoBeanFactoryPostProcessor(HelloService demoService) {\n        this.demoService = demoService;\n    }\n\n    @Override\n    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n        if (demoService == null) {\n            throw new IllegalStateException(\"demoService is not injected\");\n        }\n    }\n\n    /**\n     * call before PropertyPlaceholderConfigurer\n     */\n    @Override\n    public int getOrder() {\n        return HIGHEST_PRECEDENCE;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/PropertyConfigurerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.propertyconfigurer.consumer;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport java.net.InetSocketAddress;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nclass PropertyConfigurerTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testEarlyInit() {\n\n        ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(\n                \"org/apache/dubbo/config/spring/propertyconfigurer/provider/dubbo-provider.xml\");\n        try {\n            providerContext.start();\n\n            // Resolve placeholder by PropertyPlaceholderConfigurer in dubbo-consumer.xml, without import property\n            // source.\n            AnnotationConfigApplicationContext context =\n                    new AnnotationConfigApplicationContext(ConsumerConfiguration.class);\n            context.start();\n\n            HelloService service = (HelloService) context.getBean(\"demoService\");\n            String result = service.sayHello(\"world\");\n            Assertions.assertEquals(\n                    \"Hello world, response from provider: \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0),\n                    result);\n\n            context.close();\n\n        } finally {\n            providerContext.close();\n        }\n    }\n\n    @Configuration\n    @EnableDubbo(scanBasePackages = \"org.apache.dubbo.config.spring.propertyconfigurer.consumer\")\n    @ComponentScan(value = {\"org.apache.dubbo.config.spring.propertyconfigurer.consumer\"})\n    @ImportResource(\"classpath:/org/apache/dubbo/config/spring/propertyconfigurer/consumer/dubbo-consumer.xml\")\n    static class ConsumerConfiguration {\n        @Bean\n        public DemoBeanFactoryPostProcessor bizBeanFactoryPostProcessor(HelloService service) {\n            return new DemoBeanFactoryPostProcessor(service);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/app.properties",
    "content": "dubbo.registry.address=${zookeeper.connection.address}?registry-type=service\nbiz.group=greeting\nbiz.group2=group2\ndubbo.call-timeout=2000\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/dubbo-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <bean id=\"propertyConfigurer\" class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n        <property name=\"location\">\n            <value>classpath:/org/apache/dubbo/config/spring/propertyconfigurer/consumer/app.properties</value>\n        </property>\n    </bean>\n\n    <dubbo:application name=\"demo-consumer\">\n    </dubbo:application>\n\n    <!--    <dubbo:metadata-report address=\"${zookeeper.connection.address}\"/>-->\n\n    <dubbo:registry address=\"${dubbo.registry.address}\"/>\n\n    <!--  timeout=\"${dubbo.call-timeout}\"  -->\n    <dubbo:reference id=\"demoService\" check=\"false\" group=\"${biz.group}\" timeout=\"${dubbo.call-timeout:foo-timeout}\"\n                     interface=\"org.apache.dubbo.config.spring.api.HelloService\"/>\n\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/PropertySourcesConfigurerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.propertyconfigurer.consumer2;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.propertyconfigurer.consumer.DemoBeanFactoryPostProcessor;\n\nimport java.net.InetSocketAddress;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nclass PropertySourcesConfigurerTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testEarlyInit() {\n\n        ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(\n                \"org/apache/dubbo/config/spring/propertyconfigurer/provider/dubbo-provider.xml\");\n        try {\n            providerContext.start();\n\n            // consumer app\n            // Resolve placeholder by PropertySourcesPlaceholderConfigurer in dubbo-consumer.xml, without import\n            // property source.\n            AnnotationConfigApplicationContext context =\n                    new AnnotationConfigApplicationContext(ConsumerConfiguration.class);\n            try {\n                context.start();\n                HelloService service = (HelloService) context.getBean(\"demoService\");\n                String result = service.sayHello(\"world\");\n                Assertions.assertEquals(\n                        \"Hello world, response from provider: \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0),\n                        result);\n            } finally {\n                context.close();\n            }\n\n        } finally {\n            providerContext.close();\n        }\n    }\n\n    @Configuration\n    @EnableDubbo(scanBasePackages = \"org.apache.dubbo.config.spring.propertyconfigurer.consumer2\")\n    @ComponentScan(value = {\"org.apache.dubbo.config.spring.propertyconfigurer.consumer2\"})\n    @ImportResource(\"classpath:/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/dubbo-consumer.xml\")\n    static class ConsumerConfiguration {\n        @Bean\n        public DemoBeanFactoryPostProcessor bizBeanFactoryPostProcessor(HelloService service) {\n            return new DemoBeanFactoryPostProcessor(service);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/app.properties",
    "content": "dubbo.registry.address=${zookeeper.connection.address}?registry-type=service\nbiz.group=greeting\nbiz.group2=group2\ndubbo.call-timeout=2000\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/dubbo-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <bean id=\"propertyConfigurer\" class=\"org.springframework.context.support.PropertySourcesPlaceholderConfigurer\">\n        <property name=\"location\">\n            <value>classpath:/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/app.properties</value>\n        </property>\n    </bean>\n\n    <dubbo:application name=\"demo-consumer\">\n    </dubbo:application>\n\n    <!--    <dubbo:metadata-report address=\"${zookeeper.connection.address}\"/>-->\n\n    <dubbo:registry address=\"${dubbo.registry.address}\"/>\n\n    <!--  timeout=\"${dubbo.call-timeout}\"  -->\n    <dubbo:reference id=\"demoService\" check=\"false\" group=\"${biz.group}\" timeout=\"${dubbo.call-timeout:foo-timeout}\"\n                     interface=\"org.apache.dubbo.config.spring.api.HelloService\"/>\n\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/PropertySourcesInJavaConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.propertyconfigurer.consumer3;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.propertyconfigurer.consumer.DemoBeanFactoryPostProcessor;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.core.io.ClassPathResource;\n\nclass PropertySourcesInJavaConfigTest {\n\n    private static final String SCAN_PACKAGE_NAME =\n            \"org.apache.dubbo.config.spring.propertyconfigurer.consumer3.notexist\";\n    private static final String PACKAGE_PATH = \"/org/apache/dubbo/config/spring/propertyconfigurer/consumer3\";\n    private static final String PROVIDER_CONFIG_PATH =\n            \"org/apache/dubbo/config/spring/propertyconfigurer/provider/dubbo-provider.xml\";\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testImportPropertySource() {\n\n        ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(PROVIDER_CONFIG_PATH);\n        try {\n            providerContext.start();\n\n            // Resolve placeholder by import property sources\n            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n                    ConsumerConfiguration.class, ImportPropertyConfiguration.class);\n            try {\n                // expect auto create PropertySourcesPlaceholderConfigurer bean\n                String[] beanNames = context.getBeanNamesForType(PropertySourcesPlaceholderConfigurer.class);\n                Assertions.assertEquals(1, beanNames.length);\n                Assertions.assertEquals(PropertySourcesPlaceholderConfigurer.class.getName(), beanNames[0]);\n\n                HelloService service = (HelloService) context.getBean(\"demoService\");\n                String result = service.sayHello(\"world\");\n                Assertions.assertEquals(\n                        \"Hello world, response from provider: \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0),\n                        result);\n            } finally {\n                context.close();\n            }\n\n        } finally {\n            providerContext.close();\n        }\n    }\n\n    @Test\n    void testCustomPropertySourceBean() {\n\n        ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(PROVIDER_CONFIG_PATH);\n        try {\n            providerContext.start();\n\n            // Resolve placeholder by custom PropertySourcesPlaceholderConfigurer bean\n            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n                    ConsumerConfiguration.class, PropertyBeanConfiguration.class);\n            try {\n                // expect using custom PropertySourcesPlaceholderConfigurer bean\n                String[] beanNames = context.getBeanNamesForType(PropertySourcesPlaceholderConfigurer.class);\n                Assertions.assertEquals(1, beanNames.length);\n                Assertions.assertEquals(\"myPropertySourcesPlaceholderConfigurer\", beanNames[0]);\n\n                HelloService service = (HelloService) context.getBean(\"demoService\");\n                String result = service.sayHello(\"world\");\n                Assertions.assertEquals(\n                        \"Hello world, response from provider: \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0),\n                        result);\n            } finally {\n                context.close();\n            }\n\n        } finally {\n            providerContext.close();\n        }\n    }\n\n    @Configuration\n    @EnableDubbo(scanBasePackages = SCAN_PACKAGE_NAME)\n    @ComponentScan(value = {SCAN_PACKAGE_NAME})\n    @ImportResource(\"classpath:\" + PACKAGE_PATH + \"/dubbo-consumer.xml\")\n    static class ConsumerConfiguration {\n        @Bean\n        public DemoBeanFactoryPostProcessor bizBeanFactoryPostProcessor(HelloService service) {\n            return new DemoBeanFactoryPostProcessor(service);\n        }\n    }\n\n    @Configuration\n    @PropertySource(\"classpath:\" + PACKAGE_PATH + \"/app.properties\")\n    static class ImportPropertyConfiguration {}\n\n    @Configuration\n    static class PropertyBeanConfiguration {\n        @Bean\n        public MyPropertySourcesPlaceholderConfigurer myPropertySourcesPlaceholderConfigurer() {\n            MyPropertySourcesPlaceholderConfigurer placeholderConfigurer = new MyPropertySourcesPlaceholderConfigurer();\n            placeholderConfigurer.setLocation(new ClassPathResource(PACKAGE_PATH + \"/app.properties\"));\n            return placeholderConfigurer;\n        }\n    }\n\n    static class MyPropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer {\n        @Override\n        protected String convertProperty(String propertyName, String propertyValue) {\n            // .. do something ..\n            return propertyValue;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/app.properties",
    "content": "dubbo.registry.address=${zookeeper.connection.address}?registry-type=service\nbiz.group=greeting\nbiz.group2=group2\ndubbo.call-timeout=2000\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/dubbo-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"demo-consumer\">\n    </dubbo:application>\n\n    <!--    <dubbo:metadata-report address=\"${zookeeper.connection.address}\"/>-->\n\n    <dubbo:registry address=\"${dubbo.registry.address}\"/>\n\n    <!--  timeout=\"${dubbo.call-timeout}\"  -->\n    <dubbo:reference id=\"demoService\" check=\"false\" group=\"${biz.group}\" timeout=\"${dubbo.call-timeout:foo-timeout}\"\n                     interface=\"org.apache.dubbo.config.spring.api.HelloService\"/>\n\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/provider/HelloServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.propertyconfigurer.provider;\n\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class HelloServiceImpl implements HelloService {\n    private static final Logger logger = LoggerFactory.getLogger(HelloServiceImpl.class);\n\n    @Override\n    public String sayHello(String name) {\n        logger.info(\"Hello \" + name + \", request from consumer: \"\n                + RpcContext.getContext().getRemoteAddress());\n        try {\n            Thread.sleep(1000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        return \"Hello \" + name + \", response from provider: \"\n                + RpcContext.getContext().getLocalAddress();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/provider/app.properties",
    "content": "dubbo.application.name=demo-provider\ndubbo.registry.address=${zookeeper.connection.address}?registry-type=service\ndubbo.config-center.address=${zookeeper.connection.address}\ndubbo.metadata-report.address=${zookeeper.connection.address}\nbiz.group=greeting\nbiz.group2=group2\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/provider/dubbo-provider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <bean id=\"propertyConfigurer\" class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n        <property name=\"location\">\n            <value>classpath:/org/apache/dubbo/config/spring/propertyconfigurer/provider/app.properties</value>\n        </property>\n        <property name=\"fileEncoding\">\n            <value>UTF-8</value>\n        </property>\n    </bean>\n\n    <dubbo:application name=\"demo-provider\">\n    </dubbo:application>\n\n    <dubbo:config-center address=\"${dubbo.config-center.address}\"/>\n    <dubbo:metadata-report address=\"${dubbo.metadata-report.address}\"/>\n    <dubbo:registry id=\"registry1\" address=\"${dubbo.registry.address}\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"-1\"/>\n    <dubbo:protocol name=\"rest\" port=\"-1\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.propertyconfigurer.provider.HelloServiceImpl\"/>\n\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.HelloService\" timeout=\"3000\"\n                   group=\"${biz.group:abc}\" ref=\"demoService\" registry=\"registry1\" protocol=\"dubbo\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/DubboConfigBeanInitializerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;\nimport org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration;\nimport org.apache.dubbo.config.spring.util.DubboBeanUtils;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Tests for {@link org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer}\n */\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(\n        classes = {\n            DubboConfigBeanInitializerTest.class,\n            DubboConfigBeanInitializerTest.AppConfiguration.class,\n        })\n@TestPropertySource(\n        properties = {\n            \"dubbo.protocol.port=-1\",\n            \"dubbo.registry.address=${zookeeper.connection.address}\",\n            \"dubbo.metrics.enabled = false\",\n            \"dubbo.metrics.protocol = disabled\"\n        })\n@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)\n@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)\nclass DubboConfigBeanInitializerTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private FooService fooService;\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Test\n    void test() {\n        Assertions.assertNotNull(fooService, \"fooService is null\");\n        Assertions.assertNotNull(fooService.helloService, \"ooService.helloService is null\");\n\n        // expect fooService is registered before dubbo config bean\n        List<String> beanNames = Arrays.asList(applicationContext.getBeanDefinitionNames());\n        int fooServiceIndex = beanNames.indexOf(\"fooService\");\n        int applicationConfigIndex = beanNames.indexOf(\"dubbo-demo-application\");\n        int registryConfigIndex = beanNames.indexOf(\"my-registry\");\n        int configInitializerIndex = beanNames.indexOf(DubboConfigBeanInitializer.BEAN_NAME);\n        Assertions.assertTrue(fooServiceIndex < applicationConfigIndex);\n        Assertions.assertTrue(fooServiceIndex < registryConfigIndex);\n        Assertions.assertTrue(fooServiceIndex < configInitializerIndex);\n    }\n\n    @Configuration\n    // Import BusinessConfig first, make sure FooService bean is register early,\n    // expect dubbo config beans are initialized before FooService bean\n    @Import({BusinessConfig.class, ConsumerConfig.class, ProviderConfiguration.class})\n    static class AppConfiguration {}\n\n    @Configuration\n    static class BusinessConfig {\n        @Bean\n        public FooService fooService(ApplicationContext applicationContext) {\n            // Dubbo config beans should be initialized at DubboConfigInitializer, before init FooService bean\n            Assertions.assertTrue(DubboBeanUtils.getModuleModel(applicationContext)\n                    .getDeployer()\n                    .isInitialized());\n            Assertions.assertTrue(DubboBeanUtils.getApplicationModel(applicationContext)\n                    .getDeployer()\n                    .isInitialized());\n            Assertions.assertTrue(DubboBootstrap.getInstance().isInitialized());\n            return new FooService();\n        }\n    }\n\n    @Configuration\n    static class ConsumerConfig {\n        @DubboReference\n        private HelloService helloService;\n    }\n\n    static class FooService {\n        @Autowired\n        private HelloService helloService;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/ReferenceKeyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference;\n\nimport org.apache.dubbo.config.annotation.Argument;\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.Method;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.api.ProvidedByDemoService1;\nimport org.apache.dubbo.config.spring.api.ProvidedByDemoService2;\nimport org.apache.dubbo.config.spring.api.ProvidedByDemoService3;\nimport org.apache.dubbo.config.spring.impl.DemoServiceImpl;\nimport org.apache.dubbo.config.spring.impl.HelloServiceImpl;\nimport org.apache.dubbo.config.spring.util.AnnotationUtils;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.core.annotation.AnnotationAttributes;\n\nclass ReferenceKeyTest {\n\n    @BeforeEach\n    protected void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testReferenceKey() throws Exception {\n\n        String helloService1 = getReferenceKey(\"helloService\");\n        String helloService2 = getReferenceKey(\"helloService2\");\n        String helloService3 = getReferenceKey(\"helloService3\");\n        String helloService4 = getReferenceKey(\"helloService4\");\n\n        Assertions.assertEquals(\n                \"ReferenceBean:org.apache.dubbo.config.spring.api.HelloService(methods=[{name=sayHello, retries=0, timeout=100}])\",\n                helloService1);\n        Assertions.assertEquals(helloService1, helloService2);\n\n        Assertions.assertEquals(\n                \"ReferenceBean:org.apache.dubbo.config.spring.api.HelloService(methods=[{arguments=[{callback=true, index=0}], name=sayHello, timeout=100}])\",\n                helloService3);\n        Assertions.assertEquals(helloService3, helloService4);\n\n        String helloServiceWithArray0 = getReferenceKey(\"helloServiceWithArray0\");\n        String helloServiceWithArray1 = getReferenceKey(\"helloServiceWithArray1\");\n        String helloServiceWithArray2 = getReferenceKey(\"helloServiceWithArray2\");\n\n        String helloServiceWithMethod1 = getReferenceKey(\"helloServiceWithMethod1\");\n        String helloServiceWithMethod2 = getReferenceKey(\"helloServiceWithMethod2\");\n\n        String helloServiceWithArgument1 = getReferenceKey(\"helloServiceWithArgument1\");\n        String helloServiceWithArgument2 = getReferenceKey(\"helloServiceWithArgument2\");\n\n        Assertions.assertEquals(\n                \"ReferenceBean:org.apache.dubbo.config.spring.api.HelloService(check=false,filter=[echo],parameters={a=2, b=1})\",\n                helloServiceWithArray0);\n        Assertions.assertNotEquals(helloServiceWithArray0, helloServiceWithArray1);\n\n        Assertions.assertEquals(\n                \"ReferenceBean:org.apache.dubbo.config.spring.api.HelloService(check=false,filter=[echo],parameters={a=1, b=2})\",\n                helloServiceWithArray1);\n        Assertions.assertEquals(helloServiceWithArray1, helloServiceWithArray2);\n\n        Assertions.assertEquals(\n                \"ReferenceBean:org.apache.dubbo.config.spring.api.HelloService(check=false,filter=[echo],methods=[{name=sayHello, parameters={c=1, d=2}, timeout=100}],parameters={a=1, b=2})\",\n                helloServiceWithMethod1);\n        Assertions.assertEquals(helloServiceWithMethod1, helloServiceWithMethod2);\n\n        Assertions.assertEquals(\n                \"ReferenceBean:org.apache.dubbo.config.spring.api.HelloService(check=false,filter=[echo],methods=[{arguments=[{callback=true, type=String}, {type=int}], name=sayHello, timeout=100}],parameters={a=1, b=2})\",\n                helloServiceWithArgument1);\n        Assertions.assertEquals(helloServiceWithArgument1, helloServiceWithArgument2);\n    }\n\n    @Test\n    void testConfig() {\n\n        AnnotationConfigApplicationContext context =\n                new AnnotationConfigApplicationContext(ConsumerConfiguration.class);\n        context.start();\n\n        Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n        Assertions.assertEquals(2, referenceBeanMap.size());\n        Assertions.assertEquals(\n                \"ReferenceBean:demo/org.apache.dubbo.config.spring.api.DemoService:1.2.3(consumer=my-consumer,init=false,methods=[{arguments=[{callback=true, index=0}], name=sayName, parameters={access-token=my-token, b=2}, retries=0}],parameters={connec.timeout=1000},protocol=dubbo,registryIds=my-registry,scope=remote,timeout=1000,url=dubbo://127.0.0.1:20813)\",\n                referenceBeanMap.get(\"&demoService\").getKey());\n    }\n\n    @Test\n    @Disabled(\"support multi reference config\")\n    public void testConfig2() {\n        try {\n            AnnotationConfigApplicationContext context =\n                    new AnnotationConfigApplicationContext(ConsumerConfiguration2.class);\n            context.start();\n            Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n            Assertions.fail(\"Reference bean check failed\");\n        } catch (BeansException e) {\n            String msg = getStackTrace(e);\n            Assertions.assertTrue(\n                    msg.contains(\n                            \"Found multiple ReferenceConfigs with unique service name [demo/org.apache.dubbo.config.spring.api.DemoService:1.2.3]\"),\n                    msg);\n            //            Assertions.assertTrue(msg.contains(\"Already exists another reference bean with the same bean\n            // name and type but difference attributes\"), msg);\n            //            Assertions.assertTrue(msg.contains(\"ConsumerConfiguration2.demoService\"), msg);\n        }\n    }\n\n    @Test\n    void testConfig3() {\n        AnnotationConfigApplicationContext context =\n                new AnnotationConfigApplicationContext(ConsumerConfiguration3.class);\n        context.start();\n        Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n        Assertions.assertEquals(3, referenceBeanMap.size());\n        Assertions.assertNotNull(referenceBeanMap.get(\"&demoService#2\"));\n\n        ConsumerConfiguration3 consumerConfiguration3 = context.getBean(ConsumerConfiguration3.class);\n        Assertions.assertEquals(consumerConfiguration3.demoService, consumerConfiguration3.helloService);\n    }\n\n    @Test\n    void testConfig4() {\n        AnnotationConfigApplicationContext context = null;\n        try {\n            context = new AnnotationConfigApplicationContext(ConsumerConfiguration4.class);\n            context.start();\n            Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n            Assertions.fail(\"Reference bean check failed\");\n        } catch (BeansException e) {\n            String msg = getStackTrace(e);\n            Assertions.assertTrue(msg.contains(\"Duplicate spring bean name: demoService\"), msg);\n        } finally {\n            if (context != null) {\n                context.close();\n            }\n        }\n    }\n\n    @Test\n    void testConfig5() {\n        try {\n            AnnotationConfigApplicationContext context =\n                    new AnnotationConfigApplicationContext(ConsumerConfiguration5.class);\n            context.start();\n            Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n            Assertions.fail(\"Reference bean check failed\");\n        } catch (BeansException e) {\n            Assertions.assertTrue(getStackTrace(e).contains(\"Duplicate spring bean name: demoService\"));\n        }\n    }\n\n    @Test\n    void testConfig6() {\n        try {\n            AnnotationConfigApplicationContext context =\n                    new AnnotationConfigApplicationContext(ConsumerConfiguration6.class);\n            context.start();\n            Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n            Assertions.fail(\"Reference bean check failed\");\n        } catch (BeansException e) {\n            String checkString =\n                    \"Already exists another bean definition with the same bean name [demoService], but cannot rename the reference bean name\";\n            String msg = getStackTrace(e);\n            Assertions.assertTrue(msg.contains(checkString), msg);\n            Assertions.assertTrue(msg.contains(\"ConsumerConfiguration6.demoService\"), msg);\n        }\n    }\n\n    @Test\n    void testConfig7() throws Exception {\n        String fieldName1 = \"providedByDemoService1\";\n        String fieldName2 = \"providedByDemoService2\";\n        String fieldName3 = \"providedByDemoServiceInterface\";\n        String fieldName4 = \"multiProvidedByDemoServiceInterface\";\n        Map<String, Object> attributes1 = getReferenceAttributes(fieldName1);\n        Map<String, Object> attributes2 = getReferenceAttributes(fieldName2);\n        Map<String, Object> attributes3 = getReferenceAttributes(fieldName3);\n        Map<String, Object> attributes4 = getReferenceAttributes(fieldName4);\n\n        Assertions.assertEquals(\"provided-demo-service-interface\", ((String[]) attributes1.get(\"providedBy\"))[0]);\n        Assertions.assertEquals(\"provided-demo-service1\", ((String[]) attributes1.get(\"providedBy\"))[1]);\n        Assertions.assertEquals(\"provided-demo-service2\", ((String[]) attributes2.get(\"providedBy\"))[0]);\n        Assertions.assertEquals(\"provided-demo-service-interface\", ((String[]) attributes3.get(\"providedBy\"))[0]);\n        String[] serviceName4 = (String[]) attributes4.get(\"providedBy\");\n        List<String> expectServices = new ArrayList<>();\n        expectServices.add(\"provided-demo-service-interface1\");\n        expectServices.add(\"provided-demo-service-interface2\");\n        Assertions.assertTrue(serviceName4.length == 2\n                && expectServices.contains(serviceName4[0])\n                && expectServices.contains(serviceName4[1]));\n        Assertions.assertEquals(\"provided-demo-service-interface\", ((String[]) attributes3.get(\"providedBy\"))[0]);\n    }\n\n    private String getStackTrace(Throwable ex) {\n        StringWriter stringWriter = new StringWriter();\n        ex.printStackTrace(new PrintWriter(stringWriter));\n        return stringWriter.toString();\n    }\n\n    private String getReferenceKey(String fieldName) throws NoSuchFieldException {\n        Field field = ReferenceConfiguration.class.getDeclaredField(fieldName);\n        AnnotationAttributes attributes =\n                AnnotationUtils.getAnnotationAttributes(field, DubboReference.class, null, true);\n        ReferenceBeanSupport.convertReferenceProps(attributes, field.getType());\n        return ReferenceBeanSupport.generateReferenceKey(attributes, null);\n    }\n\n    private Map<String, Object> getReferenceAttributes(String fieldName) throws NoSuchFieldException {\n        Field field = ConsumerConfiguration7.class.getDeclaredField(fieldName);\n        AnnotationAttributes attributes =\n                AnnotationUtils.getAnnotationAttributes(field, DubboReference.class, null, true);\n        ReferenceBeanSupport.convertReferenceProps(attributes, field.getType());\n        return attributes;\n    }\n\n    static class ReferenceConfiguration {\n        @DubboReference(methods = @Method(name = \"sayHello\", timeout = 100, retries = 0))\n        private HelloService helloService;\n\n        @DubboReference(methods = @Method(timeout = 100, name = \"sayHello\", retries = 0))\n        private HelloService helloService2;\n\n        @DubboReference(\n                methods = @Method(name = \"sayHello\", timeout = 100, arguments = @Argument(index = 0, callback = true)))\n        private HelloService helloService3;\n\n        @DubboReference(\n                methods = @Method(arguments = @Argument(callback = true, index = 0), name = \"sayHello\", timeout = 100))\n        private HelloService helloService4;\n\n        // Instance 1\n        @DubboReference(\n                check = false,\n                parameters = {\"a\", \"2\", \"b\", \"1\"},\n                filter = {\"echo\"})\n        private HelloService helloServiceWithArray0;\n\n        // Instance 2\n        @DubboReference(\n                check = false,\n                parameters = {\"a=1\", \"b\", \"2\"},\n                filter = {\"echo\"})\n        private HelloService helloServiceWithArray1;\n\n        @DubboReference(\n                parameters = {\"b\", \"2\", \"a\", \"1\"},\n                filter = {\"echo\"},\n                check = false)\n        private HelloService helloServiceWithArray2;\n\n        // Instance 3\n        @DubboReference(\n                check = false,\n                parameters = {\"a\", \"1\", \"b\", \"2\"},\n                filter = {\"echo\"},\n                methods = {\n                    @Method(\n                            parameters = {\"d\", \"2\", \"c\", \"1\"},\n                            name = \"sayHello\",\n                            timeout = 100)\n                })\n        private HelloService helloServiceWithMethod1;\n\n        @DubboReference(\n                parameters = {\"b=2\", \"a=1\"},\n                filter = {\"echo\"},\n                check = false,\n                methods = {\n                    @Method(\n                            name = \"sayHello\",\n                            timeout = 100,\n                            parameters = {\"c\", \"1\", \"d\", \"2\"})\n                })\n        private HelloService helloServiceWithMethod2;\n\n        // Instance 4\n        @DubboReference(\n                parameters = {\"a\", \"1\", \"b\", \"2\"},\n                filter = {\"echo\"},\n                methods = {\n                    @Method(\n                            name = \"sayHello\",\n                            arguments = {\n                                @Argument(callback = true, type = \"String\"),\n                                @Argument(callback = false, type = \"int\")\n                            },\n                            timeout = 100)\n                },\n                check = false)\n        private HelloService helloServiceWithArgument1;\n\n        @DubboReference(\n                check = false,\n                filter = {\"echo\"},\n                parameters = {\"b\", \"2\", \"a\", \"1\"},\n                methods = {\n                    @Method(\n                            name = \"sayHello\",\n                            timeout = 100,\n                            arguments = {\n                                @Argument(callback = false, type = \"int\"),\n                                @Argument(callback = true, type = \"String\")\n                            })\n                })\n        private HelloService helloServiceWithArgument2;\n    }\n\n    @Configuration\n    @ImportResource({\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-keys.xml\",\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-properties.xml\"\n    })\n    static class ConsumerConfiguration {\n\n        // both are reference beans, same as xml config\n        @DubboReference(\n                group = \"demo\",\n                version = \"1.2.3\",\n                consumer = \"my-consumer\",\n                init = false,\n                methods = {\n                    @Method(\n                            arguments = {@Argument(callback = true, index = 0)},\n                            name = \"sayName\",\n                            parameters = {\"access-token\", \"my-token\", \"b\", \"2\"},\n                            retries = 0)\n                },\n                parameters = {\"connec.timeout\", \"1000\"},\n                protocol = \"dubbo\",\n                registry = \"my-registry\",\n                scope = \"remote\",\n                timeout = 1000,\n                url = \"dubbo://127.0.0.1:20813\")\n        private DemoService demoService;\n    }\n\n    @Configuration\n    @ImportResource({\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-keys.xml\",\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-properties.xml\"\n    })\n    static class ConsumerConfiguration2 {\n\n        // both are reference beans, same bean name and type, but difference attributes from xml config\n        @DubboReference(\n                group = \"demo\",\n                version = \"1.2.3\",\n                consumer = \"my-consumer\",\n                init = false,\n                scope = \"local\",\n                timeout = 100)\n        private DemoService demoService;\n    }\n\n    @Configuration\n    @ImportResource({\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-keys.xml\",\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-properties.xml\"\n    })\n    static class ConsumerConfiguration3 {\n\n        // both are reference beans, same bean name but difference interface type\n        @DubboReference(\n                group = \"demo\",\n                version = \"1.2.4\",\n                consumer = \"my-consumer\",\n                init = false,\n                url = \"dubbo://127.0.0.1:20813\")\n        private HelloService demoService;\n\n        @Autowired\n        private HelloService helloService;\n    }\n\n    @Configuration\n    @ImportResource({\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-keys.xml\",\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-properties.xml\"\n    })\n    static class ConsumerConfiguration4 {\n\n        // not reference bean: same bean name and type\n        @Bean\n        public DemoService demoService() {\n            return new DemoServiceImpl();\n        }\n    }\n\n    @Configuration\n    @ImportResource({\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-keys.xml\",\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-properties.xml\"\n    })\n    static class ConsumerConfiguration5 {\n\n        // not reference bean: same bean name but difference type\n        @Bean\n        public HelloService demoService() {\n            return new HelloServiceImpl();\n        }\n    }\n\n    @Configuration\n    @ImportResource({\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-keys.xml\",\n        \"classpath:/org/apache/dubbo/config/spring/init-reference-properties.xml\"\n    })\n    static class ConsumerConfiguration6 {\n\n        // both are reference beans, same bean name but difference interface type, fixed bean name\n        @DubboReference(\n                id = \"demoService\",\n                group = \"demo\",\n                version = \"1.2.3\",\n                consumer = \"my-consumer\",\n                init = false,\n                url = \"dubbo://127.0.0.1:20813\")\n        private HelloService demoService;\n\n        //        @Autowired\n        //        private HelloService helloService;\n    }\n\n    @Configuration\n    static class ConsumerConfiguration7 {\n\n        // both are reference beans, same as xml config\n        @DubboReference(providedBy = \"provided-demo-service1\")\n        private ProvidedByDemoService1 providedByDemoService1;\n\n        @DubboReference(providedBy = \"provided-demo-service2\")\n        private ProvidedByDemoService2 providedByDemoService2;\n\n        @DubboReference(providedBy = {\"provided-demo-service3\", \"provided-demo-service4\"})\n        private ProvidedByDemoService2 multiProvidedByDemoService;\n\n        @DubboReference\n        private ProvidedByDemoService1 providedByDemoServiceInterface;\n\n        @DubboReference\n        private ProvidedByDemoService3 multiProvidedByDemoServiceInterface;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/javaconfig/JavaConfigReferenceBeanTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference.javaconfig;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.impl.HelloServiceImpl;\nimport org.apache.dubbo.config.spring.reference.ReferenceBeanBuilder;\nimport org.apache.dubbo.rpc.service.GenericException;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.lang.reflect.Modifier;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\n\nclass JavaConfigReferenceBeanTest {\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testAnnotationAtField() {\n        AnnotationConfigApplicationContext context =\n                new AnnotationConfigApplicationContext(CommonConfig.class, AnnotationAtFieldConfiguration.class);\n\n        try {\n            Map<String, HelloService> helloServiceMap = context.getBeansOfType(HelloService.class);\n            Assertions.assertEquals(2, helloServiceMap.size());\n            Assertions.assertNotNull(helloServiceMap.get(\"helloService\"));\n            Assertions.assertNotNull(helloServiceMap.get(\"helloServiceImpl\"));\n\n            Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n            Assertions.assertEquals(1, referenceBeanMap.size());\n            ReferenceBean referenceBean = referenceBeanMap.get(\"&helloService\");\n            Assertions.assertEquals(\"demo\", referenceBean.getGroup());\n            Assertions.assertEquals(HelloService.class, referenceBean.getInterfaceClass());\n            Assertions.assertEquals(HelloService.class.getName(), referenceBean.getServiceInterface());\n        } finally {\n            context.close();\n        }\n    }\n\n    @Test\n    @Disabled(\"support multi reference config\")\n    public void testAnnotationAtField2() {\n        AnnotationConfigApplicationContext context = null;\n        try {\n            context = new AnnotationConfigApplicationContext(\n                    CommonConfig.class, AnnotationAtFieldConfiguration.class, AnnotationAtFieldConfiguration2.class);\n            Assertions.fail(\"Should not load duplicated @DubboReference fields\");\n        } catch (Exception e) {\n            String msg = getStackTrace(e);\n            Assertions.assertTrue(\n                    msg.contains(\n                            \"Found multiple ReferenceConfigs with unique service name [demo/org.apache.dubbo.config.spring.api.HelloService]\"),\n                    msg);\n        } finally {\n            if (context != null) {\n                context.close();\n            }\n        }\n    }\n\n    @Test\n    void testLazyProxy1() {\n        AnnotationConfigApplicationContext context = null;\n        try {\n            context = new AnnotationConfigApplicationContext(CommonConfig.class, LazyProxyConfiguration1.class);\n            HelloService helloServiceClient = context.getBean(\"helloServiceClient\", HelloService.class);\n            Assertions.assertNotNull(helloServiceClient);\n            Assertions.assertInstanceOf(HelloService.class, helloServiceClient);\n            Class<? extends HelloService> clientClass = helloServiceClient.getClass();\n            Assertions.assertFalse(Modifier.isFinal(clientClass.getModifiers()));\n            Assertions.assertEquals(\"Hello, dubbo\", helloServiceClient.sayHello(\"dubbo\"));\n        } finally {\n            if (context != null) {\n                context.close();\n            }\n        }\n    }\n\n    @Test\n    void testLazyProxy2() {\n        AnnotationConfigApplicationContext context = null;\n        try {\n            context = new AnnotationConfigApplicationContext(CommonConfig.class, LazyProxyConfiguration2.class);\n            HelloService helloServiceClient = context.getBean(\"helloServiceClient\", HelloService.class);\n            Assertions.assertNotNull(helloServiceClient);\n            Assertions.assertInstanceOf(HelloService.class, helloServiceClient);\n            Class<? extends HelloService> clientClass = helloServiceClient.getClass();\n            Assertions.assertFalse(Modifier.isFinal(clientClass.getModifiers()));\n            Assertions.assertEquals(\"Hello, dubbo\", helloServiceClient.sayHello(\"dubbo\"));\n        } finally {\n            if (context != null) {\n                context.close();\n            }\n        }\n    }\n\n    @Test\n    void testLazyProxy3() {\n        AnnotationConfigApplicationContext context = null;\n        try {\n            context = new AnnotationConfigApplicationContext(CommonConfig.class, LazyProxyConfiguration3.class);\n            HelloService helloServiceClient = context.getBean(\"helloServiceClient\", HelloService.class);\n            Assertions.assertNotNull(helloServiceClient);\n            Assertions.assertInstanceOf(HelloService.class, helloServiceClient);\n            Class<? extends HelloService> clientClass = helloServiceClient.getClass();\n            Assertions.assertTrue(Modifier.isFinal(clientClass.getModifiers()));\n            Assertions.assertEquals(\"Hello, dubbo\", helloServiceClient.sayHello(\"dubbo\"));\n        } finally {\n            if (context != null) {\n                context.close();\n            }\n        }\n    }\n\n    private String getStackTrace(Throwable ex) {\n        StringWriter stringWriter = new StringWriter();\n        ex.printStackTrace(new PrintWriter(stringWriter));\n        return stringWriter.toString();\n    }\n\n    @Test\n    void testAnnotationBean() {\n        AnnotationConfigApplicationContext context =\n                new AnnotationConfigApplicationContext(CommonConfig.class, AnnotationBeanConfiguration.class);\n\n        try {\n            Map<String, HelloService> helloServiceMap = context.getBeansOfType(HelloService.class);\n            Assertions.assertEquals(2, helloServiceMap.size());\n            Assertions.assertNotNull(helloServiceMap.get(\"helloService\"));\n            Assertions.assertNotNull(helloServiceMap.get(\"helloServiceImpl\"));\n\n            Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n            Assertions.assertEquals(1, referenceBeanMap.size());\n            ReferenceBean referenceBean = referenceBeanMap.get(\"&helloService\");\n            Assertions.assertEquals(\"demo\", referenceBean.getGroup());\n            Assertions.assertEquals(HelloService.class, referenceBean.getInterfaceClass());\n            Assertions.assertEquals(HelloService.class.getName(), referenceBean.getServiceInterface());\n        } finally {\n            context.close();\n        }\n    }\n\n    @Test\n    void testGenericServiceAnnotationBean() {\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n                CommonConfig.class, GenericServiceAnnotationBeanConfiguration.class);\n\n        try {\n            Map<String, HelloService> helloServiceMap = context.getBeansOfType(HelloService.class);\n            Assertions.assertEquals(1, helloServiceMap.size());\n            Assertions.assertNotNull(helloServiceMap.get(\"helloServiceImpl\"));\n\n            Map<String, GenericService> genericServiceMap = context.getBeansOfType(GenericService.class);\n            Assertions.assertEquals(3, genericServiceMap.size());\n            Assertions.assertNotNull(genericServiceMap.get(\"genericHelloService\"));\n\n            Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n            Assertions.assertEquals(2, referenceBeanMap.size());\n\n            ReferenceBean genericHelloServiceReferenceBean = referenceBeanMap.get(\"&genericHelloService\");\n            Assertions.assertEquals(\"demo\", genericHelloServiceReferenceBean.getGroup());\n            Assertions.assertEquals(GenericService.class, genericHelloServiceReferenceBean.getInterfaceClass());\n            Assertions.assertEquals(\n                    HelloService.class.getName(), genericHelloServiceReferenceBean.getServiceInterface());\n\n            ReferenceBean genericServiceWithoutInterfaceBean = referenceBeanMap.get(\"&genericServiceWithoutInterface\");\n            Assertions.assertEquals(\"demo\", genericServiceWithoutInterfaceBean.getGroup());\n            Assertions.assertEquals(GenericService.class, genericServiceWithoutInterfaceBean.getInterfaceClass());\n            Assertions.assertEquals(\n                    \"org.apache.dubbo.config.spring.api.LocalMissClass\",\n                    genericServiceWithoutInterfaceBean.getServiceInterface());\n\n            GenericService genericServiceWithoutInterface =\n                    context.getBean(\"genericServiceWithoutInterface\", GenericService.class);\n            Assertions.assertNotNull(genericServiceWithoutInterface);\n            Object sayHelloResult = genericServiceWithoutInterface.$invoke(\n                    \"sayHello\", new String[] {\"java.lang.String\"}, new Object[] {\"Dubbo\"});\n            Assertions.assertEquals(\"Hello Dubbo\", sayHelloResult);\n        } finally {\n            context.close();\n        }\n    }\n\n    @Test\n    void testReferenceBean() {\n        AnnotationConfigApplicationContext context =\n                new AnnotationConfigApplicationContext(CommonConfig.class, ReferenceBeanConfiguration.class);\n\n        try {\n            Map<String, HelloService> helloServiceMap = context.getBeansOfType(HelloService.class);\n            Assertions.assertEquals(2, helloServiceMap.size());\n            Assertions.assertNotNull(helloServiceMap.get(\"helloService\"));\n            Assertions.assertNotNull(helloServiceMap.get(\"helloServiceImpl\"));\n\n            Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n            Assertions.assertEquals(2, referenceBeanMap.size());\n            ReferenceBean referenceBean = referenceBeanMap.get(\"&helloService\");\n            Assertions.assertEquals(HelloService.class, referenceBean.getInterfaceClass());\n            Assertions.assertEquals(HelloService.class.getName(), referenceBean.getServiceInterface());\n\n            ReferenceBean demoServiceReferenceBean = referenceBeanMap.get(\"&demoService\");\n            Assertions.assertEquals(DemoService.class, demoServiceReferenceBean.getInterfaceClass());\n            Assertions.assertEquals(DemoService.class.getName(), demoServiceReferenceBean.getServiceInterface());\n        } finally {\n            context.close();\n        }\n    }\n\n    @Test\n    void testGenericServiceReferenceBean() {\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n                CommonConfig.class, GenericServiceReferenceBeanConfiguration.class);\n\n        try {\n            Map<String, HelloService> helloServiceMap = context.getBeansOfType(HelloService.class);\n            Assertions.assertEquals(1, helloServiceMap.size());\n            Assertions.assertNotNull(helloServiceMap.get(\"helloServiceImpl\"));\n\n            Map<String, GenericService> genericServiceMap = context.getBeansOfType(GenericService.class);\n            Assertions.assertEquals(2, genericServiceMap.size());\n            Assertions.assertNotNull(genericServiceMap.get(\"localMissClassGenericServiceImpl\"));\n            Assertions.assertNotNull(genericServiceMap.get(\"genericHelloService\"));\n\n            Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);\n            Assertions.assertEquals(1, referenceBeanMap.size());\n\n            ReferenceBean genericHelloServiceReferenceBean = referenceBeanMap.get(\"&genericHelloService\");\n            Assertions.assertEquals(\"demo\", genericHelloServiceReferenceBean.getGroup());\n            Assertions.assertEquals(GenericService.class, genericHelloServiceReferenceBean.getInterfaceClass());\n            Assertions.assertEquals(\n                    HelloService.class.getName(), genericHelloServiceReferenceBean.getServiceInterface());\n        } finally {\n            context.close();\n        }\n    }\n\n    @Test\n    void testRawReferenceBean() {\n        AnnotationConfigApplicationContext context = null;\n        try {\n            context = new AnnotationConfigApplicationContext(\n                    CommonConfig.class, ReferenceBeanWithoutGenericTypeConfiguration.class);\n            Assertions.fail(\"Should not load application\");\n\n        } catch (Exception e) {\n            String s = e.toString();\n            Assertions.assertTrue(s.contains(\"The ReferenceBean is missing necessary generic type\"), s);\n            Assertions.assertTrue(s.contains(\"ReferenceBeanWithoutGenericTypeConfiguration#helloService()\"), s);\n        } finally {\n            if (context != null) {\n                context.close();\n            }\n        }\n    }\n\n    @Test\n    void testInconsistentBean() {\n        AnnotationConfigApplicationContext context = null;\n        try {\n            context = new AnnotationConfigApplicationContext(CommonConfig.class, InconsistentBeanConfiguration.class);\n            Assertions.fail(\"Should not load application\");\n        } catch (Exception e) {\n            String s = e.toString();\n            Assertions.assertTrue(\n                    s.contains(\"@DubboReference annotation is inconsistent with the generic type of the ReferenceBean\"),\n                    s);\n            Assertions.assertTrue(s.contains(\"ReferenceBean<org.apache.dubbo.config.spring.api.HelloService>\"), s);\n            Assertions.assertTrue(s.contains(\"InconsistentBeanConfiguration#helloService()\"), s);\n        } finally {\n            if (context != null) {\n                context.close();\n            }\n        }\n    }\n\n    @Test\n    void testMissingGenericTypeBean() {\n        AnnotationConfigApplicationContext context = null;\n        try {\n            context = new AnnotationConfigApplicationContext(\n                    CommonConfig.class, MissingGenericTypeAnnotationBeanConfiguration.class);\n            Assertions.fail(\"Should not load application\");\n        } catch (Exception e) {\n            String s = e.toString();\n            Assertions.assertTrue(s.contains(\"The ReferenceBean is missing necessary generic type\"), s);\n            Assertions.assertTrue(s.contains(\"MissingGenericTypeAnnotationBeanConfiguration#helloService()\"), s);\n        } finally {\n            if (context != null) {\n                context.close();\n            }\n        }\n    }\n\n    @Test\n    void testMissingInterfaceTypeBean() {\n        AnnotationConfigApplicationContext context = null;\n        try {\n            context = new AnnotationConfigApplicationContext(\n                    CommonConfig.class, MissingInterfaceTypeAnnotationBeanConfiguration.class);\n            Assertions.fail(\"Should not load application\");\n        } catch (Exception e) {\n            String s = e.toString();\n            Assertions.assertTrue(s.contains(\"The interface class or name of reference was not found\"), s);\n        } finally {\n            if (context != null) {\n                context.close();\n            }\n        }\n    }\n\n    @Configuration\n    @EnableDubbo\n    @PropertySource(\"classpath:/org/apache/dubbo/config/spring/reference/javaconfig/consumer.properties\")\n    public static class CommonConfig {\n\n        @Bean\n        public List<String> testBean(HelloService helloService) {\n            return Arrays.asList(helloService.getClass().getName());\n        }\n\n        @Bean\n        @DubboService(group = \"${myapp.group}\")\n        public HelloService helloServiceImpl() {\n            return new HelloServiceImpl();\n        }\n\n        @Bean\n        @DubboService(group = \"${myapp.group}\", interfaceName = \"org.apache.dubbo.config.spring.api.LocalMissClass\")\n        public GenericService localMissClassGenericServiceImpl() {\n            return new GenericService() {\n                @Override\n                public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException {\n                    if (\"sayHello\".equals(method)) {\n                        return \"Hello \" + args[0];\n                    }\n                    return null;\n                }\n            };\n        }\n    }\n\n    @Configuration\n    public static class LazyProxyConfiguration1 {\n\n        @DubboReference(group = \"${myapp.group}\")\n        private HelloService helloService;\n\n        @Bean(name = \"helloServiceClient\")\n        public HelloService helloService() {\n            return helloService;\n        }\n    }\n\n    @Configuration\n    public static class LazyProxyConfiguration2 {\n\n        @DubboReference(group = \"${myapp.group}\", proxy = \"javassist\")\n        private HelloService helloService;\n\n        @Bean(name = \"helloServiceClient\")\n        public HelloService helloService() {\n            return helloService;\n        }\n    }\n\n    @Configuration\n    public static class LazyProxyConfiguration3 {\n\n        @DubboReference(group = \"${myapp.group}\", proxy = \"jdk\")\n        private HelloService helloService;\n\n        @Bean(name = \"helloServiceClient\")\n        public HelloService helloService() {\n            return helloService;\n        }\n    }\n\n    @Configuration\n    public static class AnnotationAtFieldConfiguration {\n\n        @DubboReference(group = \"${myapp.group}\")\n        private HelloService helloService;\n    }\n\n    @Configuration\n    public static class AnnotationAtFieldConfiguration2 {\n\n        @DubboReference(group = \"${myapp.group}\", timeout = 2000)\n        private HelloService helloService;\n    }\n\n    @Configuration\n    public static class AnnotationBeanConfiguration {\n\n        @Bean\n        @DubboReference(group = \"${myapp.group}\")\n        public ReferenceBean<HelloService> helloService() {\n            return new ReferenceBean();\n        }\n    }\n\n    @Configuration\n    public static class GenericServiceAnnotationBeanConfiguration {\n\n        @Bean\n        @Reference(group = \"${myapp.group}\", interfaceClass = HelloService.class)\n        public ReferenceBean<GenericService> genericHelloService() {\n            return new ReferenceBean();\n        }\n\n        @Bean\n        @DubboReference(\n                group = \"${myapp.group}\",\n                interfaceName = \"org.apache.dubbo.config.spring.api.LocalMissClass\",\n                scope = \"local\")\n        public ReferenceBean<GenericService> genericServiceWithoutInterface() {\n            return new ReferenceBean();\n        }\n    }\n\n    @Configuration\n    public static class ReferenceBeanConfiguration {\n\n        @Bean\n        public ReferenceBean<HelloService> helloService() {\n            return new ReferenceBeanBuilder().setGroup(\"${myapp.group}\").build();\n        }\n\n        @Bean\n        public ReferenceBean<DemoService> demoService() {\n            return new ReferenceBean();\n        }\n    }\n\n    @Configuration\n    public static class GenericServiceReferenceBeanConfiguration {\n\n        @Bean\n        public ReferenceBean<GenericService> genericHelloService() {\n            return new ReferenceBeanBuilder()\n                    .setGroup(\"${myapp.group}\")\n                    .setInterface(HelloService.class)\n                    .build();\n        }\n    }\n\n    @Configuration\n    public static class ReferenceBeanWithoutGenericTypeConfiguration {\n\n        // The ReferenceBean is missing necessary generic type\n        @Bean\n        public ReferenceBean helloService() {\n            return new ReferenceBeanBuilder()\n                    .setGroup(\"${myapp.group}\")\n                    .setInterface(HelloService.class)\n                    .build();\n        }\n    }\n\n    @Configuration\n    public static class InconsistentBeanConfiguration {\n\n        // The 'interfaceClass' or 'interfaceName' attribute value of @DubboReference annotation is inconsistent with\n        // the generic type of the ReferenceBean returned by the bean method.\n        @Bean\n        @DubboReference(group = \"${myapp.group}\", interfaceClass = DemoService.class)\n        public ReferenceBean<HelloService> helloService() {\n            return new ReferenceBean();\n        }\n    }\n\n    @Configuration\n    public static class MissingGenericTypeAnnotationBeanConfiguration {\n\n        // The ReferenceBean is missing necessary generic type\n        @Bean\n        @DubboReference(group = \"${myapp.group}\", interfaceClass = DemoService.class)\n        public ReferenceBean helloService() {\n            return new ReferenceBean();\n        }\n    }\n\n    @Configuration\n    public static class MissingInterfaceTypeAnnotationBeanConfiguration {\n\n        // The ReferenceBean is missing necessary generic type\n        @Bean\n        @DubboReference(group = \"${myapp.group}\")\n        public ReferenceBean<GenericService> helloService() {\n            return new ReferenceBean();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/javaconfig/consumer.properties",
    "content": "dubbo.application.name=consumer-app\ndubbo.protocol.name=dubbo\ndubbo.protocol.port=-1\ndubbo.registry.address=${zookeeper.connection.address}\ndubbo.reference.org.apache.dubbo.config.spring.api.DemoService.init=false\n#dubbo.reference.org.apache.dubbo.config.spring.api.HelloService.init=false\n#dubbo.consumer.init=false\nmyapp.group=demo\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcall/LocalCallTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference.localcall;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport java.net.InetSocketAddress;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(\n        locations = {\n            \"classpath:/org/apache/dubbo/config/spring/reference/localcall/local-call-provider.xml\",\n            \"classpath:/org/apache/dubbo/config/spring/reference/localcall/local-call-consumer.xml\"\n        })\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\nclass LocalCallTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Autowired\n    private HelloService helloService;\n\n    @Autowired\n    // @Qualifier(\"localHelloService\")\n    private HelloService localHelloService;\n\n    @Test\n    void testLocalCall() {\n        // see also: org.apache.dubbo.rpc.protocol.injvm.InjvmInvoker.doInvoke\n        // InjvmInvoker set remote address to 127.0.0.1:0\n        String result = helloService.sayHello(\"world\");\n        Assertions.assertEquals(\n                \"Hello world, response from provider: \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0), result);\n\n        // direct call local service, the remote address is null\n        String originResult = localHelloService.sayHello(\"world\");\n        Assertions.assertEquals(\"Hello world, response from provider: null\", originResult);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcall/LocalCallTest2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference.localcall;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport java.net.InetSocketAddress;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(\n        locations = {\"classpath:/org/apache/dubbo/config/spring/reference/localcall/local-call-provider.xml\"})\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\npublic class LocalCallTest2 {\n\n    @BeforeAll\n    public static void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void tearDown() {\n        DubboBootstrap.reset();\n    }\n\n    @DubboReference\n    private HelloService helloService;\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Test\n    public void testLocalCall() {\n        // see also: org.apache.dubbo.rpc.protocol.injvm.InjvmInvoker.doInvoke\n        // InjvmInvoker set remote address to 127.0.0.1:0\n        String result = helloService.sayHello(\"world\");\n        Assertions.assertEquals(\n                \"Hello world, response from provider: \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0), result);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcall/LocalHelloServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference.localcall;\n\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.rpc.RpcContext;\n\npublic class LocalHelloServiceImpl implements HelloService {\n\n    @Override\n    public String sayHello(String name) {\n        return \"Hello \" + name + \", response from provider: \"\n                + RpcContext.getContext().getLocalAddress();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcall/local-call-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:reference id=\"helloService\" interface=\"org.apache.dubbo.config.spring.api.HelloService\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcall/local-call-provider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\" xmlns:context=\"http://www.springframework.org/schema/context\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">\n    <context:property-placeholder/>\n\n    <dubbo:application name=\"demo-provider\"/>\n\n    <dubbo:registry address=\"${zookeeper.connection.address}\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"20880\"/>\n\n    <bean id=\"localHelloService\" class=\"org.apache.dubbo.config.spring.reference.localcall.LocalHelloServiceImpl\"/>\n\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.HelloService\" ref=\"localHelloService\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcalla/LocalCallReferenceAnnotationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference.localcalla;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport java.net.InetSocketAddress;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n@EnableDubbo\n@ExtendWith(SpringExtension.class)\n@PropertySource(\"classpath:/org/apache/dubbo/config/spring/reference/localcalla/local-call-config.properties\")\n@ContextConfiguration(\n        classes = {LocalCallReferenceAnnotationTest.class, LocalCallReferenceAnnotationTest.LocalCallConfiguration.class\n        })\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\nclass LocalCallReferenceAnnotationTest {\n\n    @BeforeAll\n    public static void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterAll\n    public static void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Autowired\n    private HelloService helloService;\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Test\n    void testLocalCall() {\n        // see also: org.apache.dubbo.rpc.protocol.injvm.InjvmInvoker.doInvoke\n        // InjvmInvoker set remote address to 127.0.0.1:0\n        String result = helloService.sayHello(\"world\");\n        Assertions.assertEquals(\n                \"Hello world, response from provider: \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0), result);\n    }\n\n    @Configuration\n    public static class LocalCallConfiguration {\n        @DubboReference(injvm = true)\n        private HelloService helloService;\n    }\n\n    @DubboService\n    public static class AnotherLocalHelloServiceImpl implements HelloService {\n        @Override\n        public String sayHello(String name) {\n            return \"Hello \" + name + \", response from provider: \"\n                    + RpcContext.getContext().getLocalAddress();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcalla/local-call-config.properties",
    "content": "dubbo.application.name=local-call-demo\ndubbo.protocol.name=dubbo\ndubbo.protocol.port=-1\ndubbo.registry.address=N/A\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcallam/LocalCallMultipleReferenceAnnotationsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference.localcallam;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport java.net.InetSocketAddress;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n@EnableDubbo\n@ExtendWith(SpringExtension.class)\n@PropertySource(\"classpath:/org/apache/dubbo/config/spring/reference/localcallam/local-call-config.properties\")\n@ContextConfiguration(\n        classes = {\n            LocalCallMultipleReferenceAnnotationsTest.class,\n            LocalCallMultipleReferenceAnnotationsTest.LocalCallConfiguration.class\n        })\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\n@TestPropertySource(properties = {\"dubbo.metrics.enabled=false\", \"dubbo.metrics.protocol=disabled\"})\nclass LocalCallMultipleReferenceAnnotationsTest {\n\n    @BeforeAll\n    public static void setUp() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    private HelloService helloService;\n\n    @Autowired\n    private HelloService demoHelloService;\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Test\n    void testLocalCall() {\n        // see also: org.apache.dubbo.rpc.protocol.injvm.InjvmInvoker.doInvoke\n        // InjvmInvoker set remote address to 127.0.0.1:0\n        String result = helloService.sayHello(\"world\");\n        Assertions.assertEquals(\n                \"Hello world, response from provider: \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0), result);\n\n        String demoResult = demoHelloService.sayHello(\"world\");\n        Assertions.assertEquals(\n                \"Hello world, response from provider: \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0),\n                demoResult);\n\n        Map<String, ReferenceBean> referenceBeanMap = applicationContext.getBeansOfType(ReferenceBean.class);\n        Assertions.assertEquals(2, referenceBeanMap.size());\n\n        boolean hasHelloRef =\n                referenceBeanMap.containsKey(\"&helloService\") || referenceBeanMap.containsKey(\"&helloService3\");\n        boolean hasDemoRef =\n                referenceBeanMap.containsKey(\"&demoHelloService\") || referenceBeanMap.containsKey(\"&helloService3\");\n\n        Assertions.assertTrue(hasHelloRef, \"Expected a hello reference bean (&helloService or &helloService3)\");\n        Assertions.assertTrue(hasDemoRef, \"Expected a demo reference bean (&demoHelloService or &helloService3)\");\n\n        // helloService3 and demoHelloService share the same ReferenceConfig instance\n        ReferenceBean helloService3ReferenceBean = applicationContext.getBean(\"&helloService3\", ReferenceBean.class);\n        ReferenceBean demoHelloServiceReferenceBean =\n                applicationContext.getBean(\"&demoHelloService\", ReferenceBean.class);\n        Assertions.assertSame(helloService3ReferenceBean, demoHelloServiceReferenceBean);\n    }\n\n    @Configuration\n    public static class LocalCallConfiguration {\n        @DubboReference\n        private HelloService helloService;\n\n        @DubboReference(group = \"demo\", version = \"2.0.0\")\n        private HelloService demoHelloService;\n\n        @DubboReference(group = \"${biz.group}\", version = \"${biz.version}\")\n        private HelloService helloService3;\n    }\n\n    @Configuration\n    public static class LocalCallConfiguration2 {\n\n        @DubboReference\n        private HelloService helloService;\n\n        @DubboReference(group = \"${biz.group}\", version = \"2.0.0\")\n        private HelloService demoHelloService;\n    }\n\n    @Configuration\n    public static class LocalCallConfiguration3 {\n\n        @DubboReference(group = \"foo\")\n        private HelloService demoHelloService;\n    }\n\n    @DubboService\n    public static class AnotherLocalHelloServiceImpl implements HelloService {\n        @Override\n        public String sayHello(String name) {\n            return \"Hello \" + name + \", response from provider: \"\n                    + RpcContext.getContext().getLocalAddress();\n        }\n    }\n\n    @DubboService(group = \"demo\", version = \"2.0.0\")\n    public static class DemoHelloServiceImpl implements HelloService {\n        @Override\n        public String sayHello(String name) {\n            return \"Hello \" + name + \", response from provider: \"\n                    + RpcContext.getContext().getLocalAddress();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcallam/local-call-config.properties",
    "content": "dubbo.application.name=local-call-demo\ndubbo.protocol.name=dubbo\ndubbo.protocol.port=-1\ndubbo.registry.address=${zookeeper.connection.address}\nbiz.group=demo\nbiz.version=2.0.0\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcallmix/LocalCallReferenceMixTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference.localcallmix;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport java.net.InetSocketAddress;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n@EnableDubbo\n@ExtendWith(SpringExtension.class)\n@PropertySource(\"classpath:/org/apache/dubbo/config/spring/reference/localcallmix/local-call-config.properties\")\n@ContextConfiguration(\n        classes = {LocalCallReferenceMixTest.class, LocalCallReferenceMixTest.LocalCallConfiguration.class})\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\n@ImportResource(\"classpath:/org/apache/dubbo/config/spring/reference/localcallmix/local-call-consumer.xml\")\nclass LocalCallReferenceMixTest {\n\n    @BeforeAll\n    public static void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterAll\n    public static void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Autowired\n    private HelloService helloService;\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    @Test\n    void testLocalCall() {\n        // see also: org.apache.dubbo.rpc.protocol.injvm.InjvmInvoker.doInvoke\n        // InjvmInvoker set remote address to 127.0.0.1:0\n        String result = helloService.sayHello(\"world\");\n        Assertions.assertEquals(\n                \"Hello world, response from provider: \" + InetSocketAddress.createUnresolved(\"127.0.0.1\", 0), result);\n    }\n\n    @Configuration\n    public static class LocalCallConfiguration {\n        @DubboReference(injvm = true)\n        private HelloService helloService;\n    }\n\n    @DubboService\n    public static class AnotherLocalHelloServiceImpl implements HelloService {\n        @Override\n        public String sayHello(String name) {\n            return \"Hello \" + name + \", response from provider: \"\n                    + RpcContext.getContext().getLocalAddress();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcallmix/local-call-config.properties",
    "content": "dubbo.application.name=local-call-demo\ndubbo.protocol.name=dubbo\ndubbo.protocol.port=-1\ndubbo.registry.address=N/A\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcallmix/local-call-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:reference id=\"helloService\" interface=\"org.apache.dubbo.config.spring.api.HelloService\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/registryNA/consumer/DubboXmlConsumerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference.registryNA.consumer;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.HelloService;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nclass DubboXmlConsumerTest {\n\n    @BeforeEach\n    void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testConsumer() {\n        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(\n                \"classpath:/org/apache/dubbo/config/spring/reference/registryNA/consumer/dubbo-registryNA-consumer.xml\");\n        context.start();\n        HelloService helloService = context.getBean(\"helloService\", HelloService.class);\n        IllegalStateException exception =\n                Assertions.assertThrows(IllegalStateException.class, () -> helloService.sayHello(\"dubbo\"));\n        Assertions.assertTrue(exception\n                .getMessage()\n                .contains(\"No such any registry to reference org.apache.dubbo.config.spring.api.HelloService\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/registryNA/consumer/dubbo-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"demo-consumer\">\n    </dubbo:application>\n\n    <dubbo:metadata-report address=\"zookeeper://127.0.0.1:2181\"/>\n\n    <dubbo:registry id=\"demo1\" address=\"zookeeper://127.0.0.1:2181?registry-type=service\"/>\n\n    <dubbo:reference id=\"helloService\" check=\"false\" interface=\"org.apache.dubbo.config.spring.api.HelloService\" />\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/registryNA/consumer/dubbo-registryNA-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"demo-consumer\">\n    </dubbo:application>\n\n    <dubbo:metadata-report address=\"zookeeper://127.0.0.1:2181\"/>\n\n    <dubbo:registry id=\"demo1\" address=\"zookeeper://127.0.0.1:2181?registry-type=service\"/>\n\n    <dubbo:reference id=\"helloService\" check=\"false\" interface=\"org.apache.dubbo.config.spring.api.HelloService\" registry=\"N/A\" />\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/registryNA/provider/DubboXmlProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.reference.registryNA.provider;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.HelloService;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\npublic class DubboXmlProviderTest {\n\n    @BeforeEach\n    void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Test\n    void testProvider() {\n        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(\n                \"classpath:/org/apache/dubbo/config/spring/reference/registryNA/provider/dubbo-provider.xml\");\n        context.start();\n        Object bean = context.getBean(\"helloService\");\n        Assertions.assertNotNull(bean);\n    }\n\n    @Test\n    void testProvider2() {\n        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(\n                \"classpath:/org/apache/dubbo/config/spring/reference/registryNA/provider/dubbo-provider.xml\");\n        context.start();\n        Assertions.assertNotNull(context.getBean(\"helloService\"));\n        ClassPathXmlApplicationContext context2 = new ClassPathXmlApplicationContext(\n                \"classpath:/org/apache/dubbo/config/spring/reference/registryNA/consumer/dubbo-consumer.xml\");\n        context2.start();\n        HelloService helloService = context2.getBean(\"helloService\", HelloService.class);\n        Assertions.assertNotNull(helloService);\n        RpcException exception = Assertions.assertThrows(RpcException.class, () -> helloService.sayHello(\"dubbo\"));\n        Assertions.assertTrue(\n                exception\n                        .getMessage()\n                        .contains(\n                                \"Failed to invoke the method sayHello in the service org.apache.dubbo.config.spring.api.HelloService. No provider available for the service org.apache.dubbo.config.spring.api.HelloService\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/registryNA/provider/dubbo-provider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"demo-provider\" >\n    </dubbo:application>\n\n    <dubbo:config-center address=\"zookeeper://127.0.0.1:2181\"/>\n    <dubbo:metadata-report address=\"zookeeper://127.0.0.1:2181\"/>\n    <dubbo:registry id=\"registry1\" address=\"zookeeper://127.0.0.1:2181?registry-type=service\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"-1\"/>\n    <dubbo:protocol name=\"rest\" port=\"-1\"/>\n    <dubbo:protocol name=\"tri\" port=\"-1\"/>\n\n    <bean id=\"helloService\" class=\"org.apache.dubbo.config.spring.impl.HelloServiceImpl\"/>\n\n    <dubbo:service delay=\"5000\" interface=\"org.apache.dubbo.config.spring.api.HelloService\" timeout=\"3000\" ref=\"helloService\" registry=\"N/A\" protocol=\"dubbo\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/MockRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class MockRegistry implements Registry {\n\n    private URL url;\n\n    private List<URL> registered = new ArrayList<URL>();\n\n    private List<URL> subscribered = new ArrayList<URL>();\n\n    public MockRegistry(URL url) {\n        if (url == null) {\n            throw new NullPointerException();\n        }\n        this.url = url;\n    }\n\n    public List<URL> getRegistered() {\n        return registered;\n    }\n\n    public List<URL> getSubscribered() {\n        return subscribered;\n    }\n\n    public URL getUrl() {\n        return url;\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return true;\n    }\n\n    @Override\n    public void destroy() {}\n\n    @Override\n    public void register(URL url) {\n        registered.add(url);\n    }\n\n    @Override\n    public void unregister(URL url) {\n        registered.remove(url);\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        subscribered.add(url);\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        subscribered.remove(url);\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/MockRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class MockRegistryFactory implements RegistryFactory {\n\n    private static final Map<URL, Registry> REGISTRIES = new HashMap<URL, Registry>();\n\n    public static Collection<Registry> getCachedRegistry() {\n        return REGISTRIES.values();\n    }\n\n    public static void cleanCachedRegistry() {\n        REGISTRIES.clear();\n    }\n\n    @Override\n    public Registry getRegistry(URL url) {\n        MockRegistry registry = new MockRegistry(url);\n        REGISTRIES.put(url, registry);\n        return registry;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/MockServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class MockServiceDiscovery extends AbstractServiceDiscovery {\n    private URL registryURL;\n\n    public MockServiceDiscovery(ApplicationModel applicationModel, URL registryURL) {\n        super(applicationModel, registryURL);\n    }\n\n    public MockServiceDiscovery(String serviceName, URL registryURL) {\n        super(serviceName, registryURL);\n    }\n\n    @Override\n    public void doDestroy() throws Exception {}\n\n    @Override\n    public void doRegister(ServiceInstance serviceInstance) throws RuntimeException {}\n\n    @Override\n    public void doUpdate(ServiceInstance oldServiceInstance, ServiceInstance newServiceInstance)\n            throws RuntimeException {}\n\n    @Override\n    public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException {}\n\n    @Override\n    public Set<String> getServices() {\n        return new HashSet<>();\n    }\n\n    @Override\n    public List<ServiceInstance> getInstances(String serviceName) throws NullPointerException {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public URL getUrl() {\n        return registryURL;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/nacos/demo/consumer/DemoServiceConsumerBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.registry.nacos.demo.consumer;\n\nimport org.apache.dubbo.config.annotation.Reference;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.config.spring.registry.nacos.demo.service.DemoService;\n\nimport javax.annotation.PostConstruct;\n\nimport java.io.IOException;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.PropertySource;\n\n/**\n * {@link DemoService} consumer demo\n */\n@EnableDubbo\n@PropertySource(value = \"classpath:/nacos-consumer-config.properties\")\npublic class DemoServiceConsumerBootstrap {\n    private static final Logger logger = LoggerFactory.getLogger(DemoServiceConsumerBootstrap.class);\n\n    @Reference(version = \"${demo.service.version}\")\n    private DemoService demoService;\n\n    @PostConstruct\n    public void init() throws InterruptedException {\n        for (int j = 0; j < 10; j++) {\n            logger.info(demoService.sayName(\"小马哥（mercyblitz）\"));\n        }\n        Thread.sleep(TimeUnit.SECONDS.toMillis(5));\n    }\n\n    public static void main(String[] args) throws IOException {\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n        context.register(DemoServiceConsumerBootstrap.class);\n        context.refresh();\n        System.in.read();\n        context.close();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/nacos/demo/consumer/DemoServiceConsumerXmlBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.registry.nacos.demo.consumer;\n\nimport org.apache.dubbo.config.spring.registry.nacos.demo.service.DemoService;\n\nimport java.io.IOException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\n/**\n * {@link DemoService} consumer demo XML bootstrap\n */\npublic class DemoServiceConsumerXmlBootstrap {\n    private static final Logger logger = LoggerFactory.getLogger(DemoServiceConsumerXmlBootstrap.class);\n\n    public static void main(String[] args) throws IOException {\n        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();\n        context.setConfigLocation(\"/META-INF/spring/dubbo-nacos-consumer-context.xml\");\n        context.refresh();\n\n        for (int i = 1; i <= 5; i++) {\n            DemoService demoService = context.getBean(\"demoService\" + i, DemoService.class);\n            for (int j = 0; j < 10; j++) {\n                logger.info(demoService.sayName(\"小马哥（mercyblitz）\"));\n            }\n        }\n\n        System.in.read();\n        context.close();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/nacos/demo/provider/DemoServiceProviderBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.registry.nacos.demo.provider;\n\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport java.io.IOException;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.PropertySource;\n\n/**\n * {@link org.apache.dubbo.config.spring.registry.nacos.demo.service.DemoService} provider demo\n */\n@EnableDubbo(scanBasePackages = \"org.apache.dubbo.demo.service\")\n@PropertySource(value = \"classpath:/nacos-provider-config.properties\")\npublic class DemoServiceProviderBootstrap {\n\n    public static void main(String[] args) throws IOException {\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n        context.register(DemoServiceProviderBootstrap.class);\n        context.refresh();\n        System.in.read();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/nacos/demo/provider/DemoServiceProviderXmlBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.registry.nacos.demo.provider;\n\nimport java.io.IOException;\n\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\n/**\n * {@link org.apache.dubbo.config.spring.registry.nacos.demo.service.DemoService} provider demo XML bootstrap\n */\npublic class DemoServiceProviderXmlBootstrap {\n\n    public static void main(String[] args) throws IOException {\n        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();\n        context.setConfigLocation(\"/META-INF/spring/dubbo-nacos-provider-context.xml\");\n        context.refresh();\n        System.in.read();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/nacos/demo/service/DefaultService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.registry.nacos.demo.service;\n\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport org.springframework.beans.factory.annotation.Value;\n\n/**\n * Default {@link DemoService}\n *\n * @since 2.6.5\n */\n@Service(version = \"${demo.service.version}\")\npublic class DefaultService implements DemoService {\n\n    @Value(\"${demo.service.name}\")\n    private String serviceName;\n\n    public String sayName(String name) {\n        RpcContext rpcContext = RpcContext.getServiceContext();\n        return String.format(\n                \"Service [name :%s , protocol: %s , port : %d] %s(\\\"%s\\\") : Hello,%s\",\n                serviceName,\n                rpcContext.getUrl().getProtocol(),\n                rpcContext.getLocalPort(),\n                rpcContext.getMethodName(),\n                name,\n                name);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/nacos/demo/service/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.registry.nacos.demo.service;\n\n/**\n * DemoService\n *\n * @since 2.6.5\n */\npublic interface DemoService {\n\n    String sayName(String name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/nacos/nacos/NacosServiceNameTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.registry.nacos.nacos;\n\nimport org.apache.dubbo.registry.nacos.NacosServiceName;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;\nimport static org.apache.dubbo.registry.nacos.NacosServiceName.WILDCARD;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link NacosServiceName} Test\n *\n * @since 2.7.3\n */\nclass NacosServiceNameTest {\n\n    private static final String category = DEFAULT_CATEGORY;\n\n    private static final String serviceInterface = \"org.apache.dubbo.registry.nacos.NacosServiceName\";\n\n    private static final String version = \"1.0.0\";\n\n    private static final String group = \"default\";\n\n    private final NacosServiceName name = new NacosServiceName();\n\n    @BeforeEach\n    public void init() {\n        name.setCategory(category);\n        name.setServiceInterface(serviceInterface);\n        name.setVersion(version);\n        name.setGroup(group);\n    }\n\n    @Test\n    void testGetter() {\n        assertEquals(category, name.getCategory());\n        assertEquals(serviceInterface, name.getServiceInterface());\n        assertEquals(version, name.getVersion());\n        assertEquals(group, name.getGroup());\n        assertEquals(\"providers:org.apache.dubbo.registry.nacos.NacosServiceName:1.0.0:default\", name.getValue());\n    }\n\n    @Test\n    void testToString() {\n        assertEquals(\"providers:org.apache.dubbo.registry.nacos.NacosServiceName:1.0.0:default\", name.toString());\n    }\n\n    @Test\n    void testIsConcrete() {\n\n        assertTrue(name.isConcrete());\n\n        name.setGroup(WILDCARD);\n        assertFalse(name.isConcrete());\n\n        init();\n        name.setVersion(WILDCARD);\n        assertFalse(name.isConcrete());\n\n        init();\n        name.setGroup(null);\n        name.setVersion(null);\n        assertTrue(name.isConcrete());\n    }\n\n    @Test\n    void testIsCompatible() {\n\n        NacosServiceName concrete = new NacosServiceName();\n\n        assertFalse(name.isCompatible(concrete));\n\n        // set category\n        concrete.setCategory(category);\n        assertFalse(name.isCompatible(concrete));\n\n        concrete.setServiceInterface(serviceInterface);\n        assertFalse(name.isCompatible(concrete));\n\n        concrete.setVersion(version);\n        assertFalse(name.isCompatible(concrete));\n\n        concrete.setGroup(group);\n        assertTrue(name.isCompatible(concrete));\n\n        // wildcard cases\n        name.setGroup(WILDCARD);\n        assertTrue(name.isCompatible(concrete));\n\n        init();\n        name.setVersion(WILDCARD);\n        assertTrue(name.isCompatible(concrete));\n\n        // range cases\n        init();\n        name.setGroup(group + \",2.0.0\");\n        assertTrue(name.isCompatible(concrete));\n\n        init();\n        name.setVersion(version + \",2.0.0\");\n        assertTrue(name.isCompatible(concrete));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.samples;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.PropertySource;\n\n/**\n * Zookeeper Dubbo Spring Provider Bootstrap\n *\n * @since 2.7.8\n */\n@EnableDubboConfig\n@PropertySource(\"classpath:/META-INF/service-introspection/zookeeper-dubbb-consumer.properties\")\npublic class ZookeeperDubboSpringConsumerBootstrap {\n    private static final Logger logger = LoggerFactory.getLogger(ZookeeperDubboSpringConsumerBootstrap.class);\n\n    @DubboReference(services = \"${dubbo.provider.name},${dubbo.provider.name1},${dubbo.provider.name2}\")\n    private DemoService demoService;\n\n    public static void main(String[] args) throws Exception {\n        Class<?> beanType = ZookeeperDubboSpringConsumerBootstrap.class;\n        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(beanType);\n\n        ZookeeperDubboSpringConsumerBootstrap bootstrap = context.getBean(ZookeeperDubboSpringConsumerBootstrap.class);\n\n        for (int i = 0; i < 100; i++) {\n            logger.info(bootstrap.demoService.sayName(\"Hello\"));\n            Thread.sleep(1000L);\n        }\n\n        System.in.read();\n\n        context.close();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerXmlBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.samples;\n\nimport org.apache.dubbo.config.spring.api.DemoService;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\n/**\n * Zookeeper Dubbo Spring Provider XML Bootstrap\n *\n * @since 2.7.8\n */\npublic class ZookeeperDubboSpringConsumerXmlBootstrap {\n    private static final Logger logger = LoggerFactory.getLogger(ZookeeperDubboSpringConsumerXmlBootstrap.class);\n\n    public static void main(String[] args) throws Exception {\n        String location = \"classpath:/META-INF/service-introspection/zookeeper-dubbo-consumer.xml\";\n        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(location);\n\n        DemoService demoService = context.getBean(\"demoService\", DemoService.class);\n\n        for (int i = 0; i < 100; i++) {\n            logger.info(demoService.sayName(\"Hello\"));\n        }\n\n        context.close();\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringProviderBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.samples;\n\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.config.spring.api.Box;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.PropertySource;\n\nimport static java.lang.String.format;\n\n/**\n * Zookeeper Dubbo Spring Provider Bootstrap\n *\n * @since 2.7.8\n */\n@EnableDubbo\n@PropertySource(\"classpath:/META-INF/service-introspection/zookeeper-dubbb-provider.properties\")\npublic class ZookeeperDubboSpringProviderBootstrap {\n\n    public static void main(String[] args) throws Exception {\n        AnnotationConfigApplicationContext context =\n                new AnnotationConfigApplicationContext(ZookeeperDubboSpringProviderBootstrap.class);\n        System.in.read();\n        context.close();\n    }\n}\n\n@DubboService\nclass DefaultDemoService implements DemoService {\n\n    @Override\n    public String sayName(String name) {\n        RpcContext rpcContext = RpcContext.getServiceContext();\n        return format(\"[%s:%s] Say - %s\", rpcContext.getLocalHost(), rpcContext.getLocalPort(), name);\n    }\n\n    @Override\n    public Box getBox() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.schema;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfigBase;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.config.spring.ServiceBean;\nimport org.apache.dubbo.config.spring.SysProps;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.config.spring.impl.DemoServiceImpl;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.not;\nimport static org.hamcrest.CoreMatchers.nullValue;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass DubboNamespaceHandlerTest {\n\n    private static String resourcePath = \"org.apache.dubbo.config.spring\".replace('.', '/');\n\n    @BeforeEach\n    public void setUp() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"false\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"disabled\");\n    }\n\n    @AfterEach\n    public void tearDown() {\n        DubboBootstrap.reset();\n        SysProps.clear();\n    }\n\n    @Configuration\n    @PropertySource(\"classpath:/META-INF/demo-provider.properties\")\n    @ImportResource(locations = \"classpath:/org/apache/dubbo/config/spring/demo-provider.xml\")\n    static class XmlConfiguration {}\n\n    @Test\n    void testProviderXmlOnConfigurationClass() {\n        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n        applicationContext.register(XmlConfiguration.class);\n        applicationContext.refresh();\n        testProviderXml(applicationContext);\n    }\n\n    @Test\n    void testProviderXml() {\n        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(\n                resourcePath + \"/demo-provider.xml\", resourcePath + \"/demo-provider-properties.xml\");\n        ctx.start();\n\n        testProviderXml(ctx);\n    }\n\n    private void testProviderXml(ApplicationContext context) {\n\n        String appName = \"demo-provider\";\n        String configId = ApplicationConfig.class.getName() + \"#\" + appName + \"#0\";\n        Map<String, ApplicationConfig> applicationConfigMap = context.getBeansOfType(ApplicationConfig.class);\n        ApplicationConfig providerAppConfig = context.getBean(configId, ApplicationConfig.class);\n        assertNotNull(providerAppConfig);\n        assertEquals(appName, providerAppConfig.getName());\n        //        assertEquals(configId, providerAppConfig.getId());\n\n        ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class);\n        assertThat(protocolConfig, not(nullValue()));\n        assertThat(protocolConfig.getName(), is(\"dubbo\"));\n        assertThat(protocolConfig.getPort(), is(20813));\n\n        ApplicationConfig applicationConfig = context.getBean(ApplicationConfig.class);\n        assertThat(applicationConfig, not(nullValue()));\n        assertThat(applicationConfig.getName(), is(\"demo-provider\"));\n\n        RegistryConfig registryConfig = context.getBean(RegistryConfig.class);\n        assertThat(registryConfig, not(nullValue()));\n        assertThat(registryConfig.getAddress(), is(\"N/A\"));\n\n        DemoService service = context.getBean(DemoService.class);\n        assertThat(service, not(nullValue()));\n    }\n\n    @Test\n    void testMultiProtocol() {\n        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourcePath + \"/multi-protocol.xml\");\n        ctx.start();\n\n        Map<String, ProtocolConfig> protocolConfigMap = ctx.getBeansOfType(ProtocolConfig.class);\n        assertThat(protocolConfigMap.size(), is(2));\n\n        ConfigManager configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n        Collection<ProtocolConfig> protocolConfigs = configManager.getProtocols();\n        assertThat(protocolConfigs.size(), is(2));\n\n        ProtocolConfig rmiProtocolConfig = configManager.getProtocol(\"rmi\").get();\n        assertThat(rmiProtocolConfig.getPort(), is(10991));\n\n        ProtocolConfig dubboProtocolConfig = configManager.getProtocol(\"dubbo\").get();\n        assertThat(dubboProtocolConfig.getPort(), is(20881));\n    }\n\n    @Test\n    void testDefaultProtocol() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/override-protocol.xml\");\n        ctx.start();\n\n        ProtocolConfig protocolConfig = ctx.getBean(ProtocolConfig.class);\n        protocolConfig.refresh();\n        assertThat(protocolConfig.getName(), is(\"dubbo\"));\n    }\n\n    @Test\n    void testCustomParameter() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/customize-parameter.xml\");\n        ctx.start();\n\n        ProtocolConfig protocolConfig = ctx.getBean(ProtocolConfig.class);\n        assertThat(protocolConfig.getParameters().size(), is(1));\n        assertThat(protocolConfig.getParameters().get(\"protocol-paramA\"), is(\"protocol-paramA\"));\n\n        ServiceBean serviceBean = ctx.getBean(ServiceBean.class);\n        assertThat(serviceBean.getParameters().size(), is(1));\n        assertThat(serviceBean.getParameters().get(\"service-paramA\"), is(\"service-paramA\"));\n    }\n\n    @Test\n    void testDelayFixedTime() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(\"classpath:/\" + resourcePath + \"/delay-fixed-time.xml\");\n        ctx.start();\n\n        assertThat(ctx.getBean(ServiceBean.class).getDelay(), is(300));\n    }\n\n    @Test\n    void testTimeoutConfig() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/provider-nested-service.xml\");\n        ctx.start();\n\n        ModuleConfigManager configManager =\n                ApplicationModel.defaultModel().getDefaultModule().getConfigManager();\n        Collection<ProviderConfig> providerConfigs = configManager.getProviders();\n        Assertions.assertEquals(2, providerConfigs.size());\n\n        ProviderConfig defaultProvider = configManager.getDefaultProvider().get();\n        assertThat(defaultProvider.getTimeout(), is(2000));\n\n        ProviderConfig provider2 = configManager.getProvider(\"provider2\").get();\n\n        ServiceConfigBase<Object> serviceConfig2 = configManager.getService(\"serviceConfig2\");\n        Assertions.assertEquals(1000, provider2.getTimeout());\n        Assertions.assertEquals(provider2.getTimeout(), serviceConfig2.getTimeout());\n    }\n\n    @Test\n    void testMonitor() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/provider-with-monitor.xml\");\n        ctx.start();\n\n        assertThat(ctx.getBean(MonitorConfig.class), not(nullValue()));\n    }\n\n    //    @Test\n    //    public void testMultiMonitor() {\n    //        Assertions.assertThrows(BeanCreationException.class, () -> {\n    //            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourcePath +\n    // \"/multi-monitor.xml\");\n    //            ctx.start();\n    //        });\n    //    }\n    //\n    //    @Test\n    //    public void testMultiProviderConfig() {\n    //        Assertions.assertThrows(BeanCreationException.class, () -> {\n    //            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourcePath +\n    // \"/provider-multi.xml\");\n    //            ctx.start();\n    //        });\n    //    }\n\n    @Test\n    void testModuleInfo() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/provider-with-module.xml\");\n        ctx.start();\n\n        ModuleConfig moduleConfig = ctx.getBean(ModuleConfig.class);\n        assertThat(moduleConfig.getName(), is(\"test-module\"));\n    }\n\n    @Test\n    void testNotificationWithWrongBean() {\n        Assertions.assertThrows(BeanCreationException.class, () -> {\n            ClassPathXmlApplicationContext ctx =\n                    new ClassPathXmlApplicationContext(resourcePath + \"/consumer-notification.xml\");\n            ctx.start();\n        });\n    }\n\n    @Test\n    void testProperty() {\n        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourcePath + \"/service-class.xml\");\n        ctx.start();\n\n        ServiceBean serviceBean = ctx.getBean(ServiceBean.class);\n\n        String prefix = ((DemoServiceImpl) serviceBean.getRef()).getPrefix();\n        assertThat(prefix, is(\"welcome:\"));\n    }\n\n    @Test\n    void testMetricsAggregation() {\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/metrics-aggregation.xml\");\n        ctx.start();\n\n        ConfigManager configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n\n        MetricsConfig metricsBean = ctx.getBean(MetricsConfig.class);\n        MetricsConfig metrics = configManager.getMetrics().get();\n\n        assertTrue(metrics.getEnableJvm());\n\n        assertEquals(metrics.getAggregation().getEnabled(), true);\n        assertEquals(metrics.getAggregation().getBucketNum(), 5);\n        assertEquals(metrics.getAggregation().getTimeWindowSeconds(), 120);\n\n        assertEquals(\n                metrics.getAggregation().getEnabled(),\n                metricsBean.getAggregation().getEnabled());\n        assertEquals(\n                metrics.getAggregation().getBucketNum(),\n                metricsBean.getAggregation().getBucketNum());\n        assertEquals(\n                metrics.getAggregation().getTimeWindowSeconds(),\n                metricsBean.getAggregation().getTimeWindowSeconds());\n    }\n\n    @Test\n    void testMetricsPrometheus() {\n        SysProps.setProperty(\"dubbo.metrics.enabled\", \"true\");\n        SysProps.setProperty(\"dubbo.metrics.protocol\", \"prometheus\");\n        ClassPathXmlApplicationContext ctx =\n                new ClassPathXmlApplicationContext(resourcePath + \"/metrics-prometheus.xml\");\n        ctx.start();\n\n        ConfigManager configManager = ApplicationModel.defaultModel().getApplicationConfigManager();\n\n        MetricsConfig metricsBean = ctx.getBean(MetricsConfig.class);\n        MetricsConfig metrics = configManager.getMetrics().get();\n\n        assertEquals(metrics.getProtocol(), PROTOCOL_PROMETHEUS);\n        assertEquals(metrics.getPrometheus().getExporter().getEnabled(), true);\n        assertEquals(metrics.getPrometheus().getExporter().getEnableHttpServiceDiscovery(), true);\n        assertEquals(metrics.getPrometheus().getExporter().getHttpServiceDiscoveryUrl(), \"localhost:8080\");\n        assertEquals(metrics.getPrometheus().getPushgateway().getEnabled(), true);\n        assertEquals(metrics.getPrometheus().getPushgateway().getBaseUrl(), \"localhost:9091\");\n        assertEquals(metrics.getPrometheus().getPushgateway().getPushInterval(), 30);\n        assertEquals(metrics.getPrometheus().getPushgateway().getUsername(), \"username\");\n        assertEquals(metrics.getPrometheus().getPushgateway().getPassword(), \"password\");\n        assertEquals(metrics.getPrometheus().getPushgateway().getJob(), \"job\");\n\n        assertEquals(metricsBean.getProtocol(), PROTOCOL_PROMETHEUS);\n        assertEquals(metricsBean.getPrometheus().getExporter().getEnabled(), true);\n        assertEquals(metricsBean.getPrometheus().getExporter().getEnableHttpServiceDiscovery(), true);\n        assertEquals(metricsBean.getPrometheus().getExporter().getHttpServiceDiscoveryUrl(), \"localhost:8080\");\n        assertEquals(metricsBean.getPrometheus().getPushgateway().getEnabled(), true);\n        assertEquals(metricsBean.getPrometheus().getPushgateway().getBaseUrl(), \"localhost:9091\");\n        assertEquals(metricsBean.getPrometheus().getPushgateway().getPushInterval(), 30);\n        assertEquals(metricsBean.getPrometheus().getPushgateway().getUsername(), \"username\");\n        assertEquals(metricsBean.getPrometheus().getPushgateway().getPassword(), \"password\");\n        assertEquals(metricsBean.getPrometheus().getPushgateway().getJob(), \"job\");\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/GenericServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.schema;\n\nimport org.apache.dubbo.config.ServiceConfigBase;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.config.spring.ServiceBean;\nimport org.apache.dubbo.config.spring.api.DemoService;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = GenericServiceTest.class)\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\n@ImportResource(locations = \"classpath:/META-INF/spring/dubbo-generic-consumer.xml\")\n@TestPropertySource(properties = {\"dubbo.metrics.enabled = false\", \"dubbo.metrics.protocol = disabled\"})\nclass GenericServiceTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    @Qualifier(\"demoServiceRef\")\n    private GenericService demoServiceRef;\n\n    @Autowired\n    @Qualifier(\"demoService\")\n    private ServiceBean serviceBean;\n\n    @Test\n    void testGeneric() {\n        assertNotNull(demoServiceRef);\n        assertNotNull(serviceBean);\n\n        ModuleConfigManager configManager = DubboBootstrap.getInstance()\n                .getApplicationModel()\n                .getDefaultModule()\n                .getConfigManager();\n        ServiceConfigBase<Object> serviceConfig = configManager.getService(\"demoService\");\n        Assertions.assertEquals(DemoService.class.getName(), serviceConfig.getInterface());\n        Assertions.assertEquals(true, serviceConfig.isExported());\n\n        Object result = demoServiceRef.$invoke(\"sayHello\", new String[] {\"java.lang.String\"}, new Object[] {\"dubbo\"});\n        Assertions.assertEquals(\"Welcome dubbo\", result);\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/GenericServiceWithoutInterfaceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.schema;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;\n\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = GenericServiceWithoutInterfaceTest.class)\n@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)\n@ImportResource(locations = \"classpath:/META-INF/spring/dubbo-generic-consumer-without-interface.xml\")\n@TestPropertySource(properties = {\"dubbo.metrics.enabled = false\", \"dubbo.metrics.protocol = disabled\"})\nclass GenericServiceWithoutInterfaceTest {\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Autowired\n    @Qualifier(\"genericServiceWithoutInterfaceRef\")\n    private GenericService genericServiceWithoutInterfaceRef;\n\n    @Test\n    void testGenericWithoutInterface() {\n\n        // Test generic service without interface class locally\n        Object result = genericServiceWithoutInterfaceRef.$invoke(\n                \"sayHello\", new String[] {\"java.lang.String\"}, new Object[] {\"generic\"});\n        Assertions.assertEquals(\"Welcome generic\", result);\n\n        ReferenceConfigBase<Object> reference = DubboBootstrap.getInstance()\n                .getApplicationModel()\n                .getDefaultModule()\n                .getConfigManager()\n                .getReference(\"genericServiceWithoutInterfaceRef\");\n        Assertions.assertNull(reference.getServiceInterfaceClass());\n        Assertions.assertEquals(\"org.apache.dubbo.config.spring.api.LocalMissClass\", reference.getInterface());\n        Assertions.assertThrows(ClassNotFoundException.class, () -> ClassUtils.forName(reference.getInterface()));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/MyGenericService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.schema;\n\nimport org.apache.dubbo.rpc.service.GenericException;\nimport org.apache.dubbo.rpc.service.GenericService;\n\npublic class MyGenericService implements GenericService {\n\n    public Object $invoke(String methodName, String[] parameterTypes, Object[] args) throws GenericException {\n        if (\"sayHello\".equals(methodName)) {\n            return \"Welcome \" + args[0];\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/DataSourceStatusCheckerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.status;\n\nimport org.apache.dubbo.common.status.Status;\nimport org.apache.dubbo.config.spring.ServiceBean;\n\nimport javax.sql.DataSource;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Answers;\nimport org.mockito.Mock;\nimport org.mockito.Mockito;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.ArgumentMatchers.anyBoolean;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.MockitoAnnotations.initMocks;\n\nclass DataSourceStatusCheckerTest {\n    private DataSourceStatusChecker dataSourceStatusChecker;\n\n    @Mock\n    private ApplicationContext applicationContext;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        initMocks(this);\n        this.dataSourceStatusChecker = new DataSourceStatusChecker(applicationContext);\n        new ServiceBean<Object>(applicationContext).setApplicationContext(applicationContext);\n    }\n\n    @AfterEach\n    public void tearDown() throws Exception {\n        Mockito.reset(applicationContext);\n    }\n\n    @Test\n    void testWithoutApplicationContext() {\n        Status status = dataSourceStatusChecker.check();\n\n        assertThat(status.getLevel(), is(Status.Level.UNKNOWN));\n    }\n\n    @Test\n    void testWithoutDatasource() {\n        Map<String, DataSource> map = new HashMap<String, DataSource>();\n        given(applicationContext.getBeansOfType(eq(DataSource.class), anyBoolean(), anyBoolean()))\n                .willReturn(map);\n\n        Status status = dataSourceStatusChecker.check();\n\n        assertThat(status.getLevel(), is(Status.Level.UNKNOWN));\n    }\n\n    @Test\n    void testWithDatasourceHasNextResult() throws SQLException {\n        Map<String, DataSource> map = new HashMap<String, DataSource>();\n        DataSource dataSource = mock(DataSource.class);\n        Connection connection = mock(Connection.class, Answers.RETURNS_DEEP_STUBS);\n        given(dataSource.getConnection()).willReturn(connection);\n        given(connection.getMetaData().getTypeInfo().next()).willReturn(true);\n\n        map.put(\"mockDatabase\", dataSource);\n        given(applicationContext.getBeansOfType(eq(DataSource.class), anyBoolean(), anyBoolean()))\n                .willReturn(map);\n        Status status = dataSourceStatusChecker.check();\n\n        assertThat(status.getLevel(), is(Status.Level.OK));\n    }\n\n    @Test\n    void testWithDatasourceNotHasNextResult() throws SQLException {\n        Map<String, DataSource> map = new HashMap<String, DataSource>();\n        DataSource dataSource = mock(DataSource.class);\n        Connection connection = mock(Connection.class, Answers.RETURNS_DEEP_STUBS);\n        given(dataSource.getConnection()).willReturn(connection);\n        given(connection.getMetaData().getTypeInfo().next()).willReturn(false);\n\n        map.put(\"mockDatabase\", dataSource);\n        given(applicationContext.getBeansOfType(eq(DataSource.class), anyBoolean(), anyBoolean()))\n                .willReturn(map);\n        Status status = dataSourceStatusChecker.check();\n\n        assertThat(status.getLevel(), is(Status.Level.ERROR));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/SpringStatusCheckerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.status;\n\nimport org.apache.dubbo.common.status.Status;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.Lifecycle;\nimport org.springframework.web.context.support.GenericWebApplicationContext;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\nclass SpringStatusCheckerTest {\n\n    //    @Mock\n    //    private ApplicationLifeCycle applicationContext;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        // initMocks(this);\n    }\n\n    @AfterEach\n    public void tearDown() throws Exception {\n        // Mockito.reset(applicationContext);\n    }\n\n    @Test\n    void testWithoutApplicationContext() {\n        SpringStatusChecker springStatusChecker = new SpringStatusChecker((ApplicationContext) null);\n        Status status = springStatusChecker.check();\n\n        assertThat(status.getLevel(), is(Status.Level.UNKNOWN));\n    }\n\n    @Test\n    void testWithLifeCycleRunning() {\n        ApplicationLifeCycle applicationLifeCycle = mock(ApplicationLifeCycle.class);\n        given(applicationLifeCycle.getConfigLocations()).willReturn(new String[] {\"test1\", \"test2\"});\n        given(applicationLifeCycle.isRunning()).willReturn(true);\n\n        SpringStatusChecker springStatusChecker = new SpringStatusChecker(applicationLifeCycle);\n        Status status = springStatusChecker.check();\n\n        assertThat(status.getLevel(), is(Status.Level.OK));\n        assertThat(status.getMessage(), is(\"test1,test2\"));\n    }\n\n    @Test\n    void testWithoutLifeCycleRunning() {\n        ApplicationLifeCycle applicationLifeCycle = mock(ApplicationLifeCycle.class);\n        given(applicationLifeCycle.isRunning()).willReturn(false);\n\n        SpringStatusChecker springStatusChecker = new SpringStatusChecker(applicationLifeCycle);\n        Status status = springStatusChecker.check();\n\n        assertThat(status.getLevel(), is(Status.Level.ERROR));\n    }\n\n    interface ApplicationLifeCycle extends Lifecycle, ApplicationContext {\n        String[] getConfigLocations();\n    }\n\n    // TODO improve GenericWebApplicationContext test scenario\n    @Test\n    void testGenericWebApplicationContext() {\n        GenericWebApplicationContext context = mock(GenericWebApplicationContext.class);\n        given(context.isRunning()).willReturn(true);\n\n        SpringStatusChecker checker = new SpringStatusChecker(context);\n        Status status = checker.check();\n        Assertions.assertEquals(Status.Level.OK, status.getLevel());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/util/EnvironmentUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring.util;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.SortedMap;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.core.env.CompositePropertySource;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.apache.dubbo.config.spring.util.EnvironmentUtils.filterDubboProperties;\n\n/**\n * {@link EnvironmentUtils} Test\n *\n * @see EnvironmentUtils\n * @since 2.7.0\n */\nclass EnvironmentUtilsTest {\n\n    @Test\n    void testExtraProperties() {\n\n        String key = \"test.name\";\n        System.setProperty(key, \"Tom\");\n\n        try {\n            StandardEnvironment environment = new StandardEnvironment();\n\n            Map<String, Object> map = new HashMap<>();\n\n            map.put(key, \"Mercy\");\n\n            MapPropertySource propertySource = new MapPropertySource(\"first\", map);\n\n            CompositePropertySource compositePropertySource = new CompositePropertySource(\"comp\");\n\n            compositePropertySource.addFirstPropertySource(propertySource);\n\n            MutablePropertySources propertySources = environment.getPropertySources();\n\n            propertySources.addFirst(compositePropertySource);\n\n            Map<String, Object> properties = EnvironmentUtils.extractProperties(environment);\n\n            Assertions.assertEquals(\"Mercy\", properties.get(key));\n        } finally {\n            System.clearProperty(key);\n        }\n    }\n\n    @Test\n    void testFilterDubboProperties() {\n\n        MockEnvironment environment = new MockEnvironment();\n        environment.setProperty(\"message\", \"Hello,World\");\n        environment.setProperty(\"dubbo.registry.address\", \"zookeeper://10.10.10.1:2181\");\n        environment.setProperty(\"dubbo.consumer.check\", \"false\");\n\n        SortedMap<String, String> dubboProperties = filterDubboProperties(environment);\n\n        Assertions.assertEquals(2, dubboProperties.size());\n        Assertions.assertEquals(\"zookeeper://10.10.10.1:2181\", dubboProperties.get(\"dubbo.registry.address\"));\n        Assertions.assertEquals(\"false\", dubboProperties.get(\"dubbo.consumer.check\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties",
    "content": "application.prefix = dubbo.application.\napplication.prefixes = dubbo.applications.\n# single bean definition\n\n## application\ndubbo.application.id = applicationBean\ndubbo.application.name = dubbo-demo-application\n\n## module\ndubbo.module.id = moduleBean\ndubbo.module.name = dubbo-demo-module\n\n## registry\ndubbo.registry.address = zookeeper://192.168.99.100:32770\ndubbo.registry.useAsConfigCenter = false\ndubbo.registry.useAsMetadataCenter = false\n\n## protocol\ndubbo.protocol.name = dubbo\ndubbo.protocol.port = 20880\n\ndubbo.protocols.rest.port=8080\ndubbo.protocols.thrift.port=9090\n\n## monitor\ndubbo.monitor.address = zookeeper://127.0.0.1:32770\n\n## provider\ndubbo.provider.host = 127.0.0.1\n\n## consumer\ndubbo.consumer.client = netty\n\n# multiple Bean definition\ndubbo.registries.registry1.address = zookeeper://localhost:2181\ndubbo.registries.registry2.address = zookeeper://localhost:2182\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/default.properties",
    "content": "demo.service.version = 2.5.7\ndemo.service.application = dubbo-demo-application\ndemo.service.protocol = dubbo\ndemo.service.registry = my-registry\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/demo-provider.properties",
    "content": "# The properties for org/apache/dubbo/config/spring/demo-provider.xml\n\n# <dubbo:application name=\"${dubbo.application.name}\"/>\ndubbo.application.name = demo-provider\n\n# <dubbo:registry address=\"${dubbo.registry.address}\"/>\ndubbo.registry.address = N/A\n\n# <dubbo:protocol name=\"${dubbo.protocol.name}\" port=\"${dubbo.protocol.port}\"/>\ndubbo.protocol.name = dubbo\ndubbo.protocol.port = 20813\n\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-consumer.properties",
    "content": "# Dubbo Consumer Properties as an alternative for\n# Spring XML Bean definition : META-INF/spring/dubbo-annotation-consumer.xml\ndemo.service.application = dubbo-demo-application\ndemo.service.registry = my-registry\n\n## Dubbo configs binding properties\n###  <dubbo:application name=\"dubbo-demo-application\"/>\ndubbo.applications.dubbo-demo-application.name = dubbo-demo-application\n\n### <dubbo:registry id=\"my-registry\" address=\"N/A\"/>\ndubbo.registries.my-registry.address = N/A\ndubbo.registries.my-registry2.address = N/A\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-provider.properties",
    "content": "# Dubbo Provider Properties as an alternative for\n# Spring XML Bean definition : META-INF/spring/dubbo-annotation-provider.xml\n\n## Service Providers' Placeholders for org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl\n\ndemo.service.application = dubbo-demo-application\ndemo.service.protocol = dubbo\ndemo.service.registry = my-registry\n\n\n## Dubbo configs binding properties\n\n### <dubbo:application name=\"dubbo-annotation-provider\"/>\ndubbo.application.id = dubbo-demo-application\ndubbo.application.name = dubbo-demo-application\n\n### <dubbo:registry id=\"my-registry\" address=\"N/A\"/>\ndubbo.registry.id = my-registry\ndubbo.registry.address = N/A\n\n### <dubbo:protocol name=\"dubbo\" port=\"12345\"/>\ndubbo.protocol.id = dubbo\ndubbo.protocol.name = dubbo\ndubbo.protocol.port = 12345\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.metrics.service.MetricsService",
    "content": "default=org.apache.dubbo.metrics.service.DefaultMetricsService\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.metrics.service.MetricsServiceExporter",
    "content": "default=org.apache.dubbo.config.deploy.DefaultMetricsServiceExporter\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory",
    "content": "mock=org.apache.dubbo.config.spring.registry.MockRegistryFactory"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter",
    "content": "mymock=org.apache.dubbo.config.spring.filter.MockFilter"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-consumer.properties",
    "content": "# Dubbo Consumer Properties as an alternative for\n# Spring XML Bean definition : META-INF/spring/dubbo-annotation-consumer.xml\ndemo.service.application = dubbo-annotation-test\ndemo.service.registry = my-registry\n\n## Dubbo configs binding properties\n###  <dubbo:application name=\"dubbo-demo-application\"/>\n# In this UT, the provider will be responsible of loading ApplicationConfig.\ndubbo.applications.dubbo-demo-application.name = dubbo-demo-application\n\n### <dubbo:registry id=\"my-registry\" address=\"N/A\"/>\ndubbo.registries.my-registry.address = N/A\ndubbo.registries.my-registry2.address = N/A\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-provider.properties",
    "content": "# Dubbo Provider Properties as an alternative for\n# Spring XML Bean definition : META-INF/spring/dubbo-annotation-provider.xml\n\n## Service Providers' Placeholders for org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl\n\ndemo.service.application = dubbo-demo-application\ndemo.service.protocol = dubbo\ndemo.service.registry = my-registry\n\n\n## Dubbo configs binding properties\n\n### <dubbo:application name=\"dubbo-demo-application\"/>\ndubbo.application.id = dubbo-demo-application\ndubbo.application.name = dubbo-demo-application\n\n### <dubbo:registry id=\"my-registry\" address=\"N/A\"/>\ndubbo.registry.id = my-registry\ndubbo.registry.address = N/A\n\n### <dubbo:protocol name=\"dubbo\" port=\"12345\"/>\ndubbo.protocol.name = dubbo\ndubbo.protocol.port = 12345\ndubbo.monitor.address=N/A\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo.yml",
    "content": "dubbo:\n  consumer:\n    default: false\n    client: netty\n    threadpool: cached\n    corethreads: 1\n    threads: 10\n    queues: 99"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/init-reference.properties",
    "content": "# The properties for org/apache/dubbo/config/spring/init-reference*.xml\n\ncall.timeout=1000\nconnection.timeout=1000\nsayName.retry=false\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/isolation/dubbo-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"demo-consumer\">\n    </dubbo:application>\n\n    <dubbo:metadata-report address=\"zookeeper://127.0.0.1:2181\"/>\n\n    <dubbo:registry id=\"demo1\" address=\"zookeeper://127.0.0.1:2181\"/>\n\n    <!-- refer with dubbo protocol-->\n    <dubbo:reference version=\"1.0.0\" group=\"Group1\" id=\"dubbo-demoServiceV1\" check=\"false\" scope=\"remote\"\n                     interface=\"org.apache.dubbo.config.spring.api.DemoService\" protocol=\"dubbo\"/>\n\n    <dubbo:reference version=\"2.0.0\" group=\"Group2\" id=\"dubbo-helloServiceV2\" check=\"false\" scope=\"remote\"\n                     interface=\"org.apache.dubbo.config.spring.api.HelloService\" protocol=\"dubbo\"/>\n\n    <dubbo:reference version=\"3.0.0\" group=\"Group3\" id=\"dubbo-helloServiceV3\" check=\"false\" scope=\"remote\"\n                     interface=\"org.apache.dubbo.config.spring.api.HelloService\" protocol=\"dubbo\"/>\n\n    <!-- refer with tri protocol-->\n    <dubbo:reference version=\"1.0.0\" group=\"Group1\" id=\"tri-demoServiceV1\" check=\"false\" scope=\"remote\"\n                     interface=\"org.apache.dubbo.config.spring.api.DemoService\" protocol=\"tri\"/>\n\n    <dubbo:reference version=\"2.0.0\" group=\"Group2\" id=\"tri-helloServiceV2\" check=\"false\" scope=\"remote\"\n                     interface=\"org.apache.dubbo.config.spring.api.HelloService\" protocol=\"tri\"/>\n\n    <dubbo:reference version=\"3.0.0\" group=\"Group3\" id=\"tri-helloServiceV3\" check=\"false\" scope=\"remote\"\n                     interface=\"org.apache.dubbo.config.spring.api.HelloService\" protocol=\"tri\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/isolation/dubbo-provider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <!-- NOTE: we need config executor-management-mode=\"isolation\" -->\n    <dubbo:application name=\"demo-provider\" executor-management-mode=\"isolation\">\n    </dubbo:application>\n\n    <dubbo:config-center address=\"zookeeper://127.0.0.1:2181\"/>\n    <dubbo:metadata-report address=\"zookeeper://127.0.0.1:2181\"/>\n    <dubbo:registry id=\"registry1\" address=\"zookeeper://127.0.0.1:2181\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"-1\"/>\n    <dubbo:protocol name=\"tri\" port=\"-1\"/>\n\n    <!-- expose three service with dubbo and tri protocol-->\n    <bean id=\"demoServiceV1\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n    <bean id=\"helloServiceV2\" class=\"org.apache.dubbo.config.spring.impl.HelloServiceImpl\"/>\n    <bean id=\"helloServiceV3\" class=\"org.apache.dubbo.config.spring.impl.HelloServiceImpl\"/>\n\n    <!-- customized thread pool -->\n    <bean id=\"executor-demo-service\"\n          class=\"org.apache.dubbo.config.spring.isolation.spring.support.DemoServiceExecutor\"/>\n    <bean id=\"executor-hello-service\"\n          class=\"org.apache.dubbo.config.spring.isolation.spring.support.HelloServiceExecutor\"/>\n\n    <!-- this service use [executor=\"executor-demo-service\"] as isolated thread pool-->\n    <dubbo:service executor=\"executor-demo-service\"\n                   interface=\"org.apache.dubbo.config.spring.api.DemoService\" version=\"1.0.0\" group=\"Group1\"\n                   timeout=\"3000\" ref=\"demoServiceV1\" registry=\"registry1\" protocol=\"dubbo,tri\"/>\n\n    <!-- this service use [executor=\"executor-hello-service\"] as isolated thread pool-->\n    <dubbo:service executor=\"executor-hello-service\"\n                   interface=\"org.apache.dubbo.config.spring.api.HelloService\" version=\"2.0.0\" group=\"Group2\"\n                   timeout=\"5000\" ref=\"helloServiceV2\" registry=\"registry1\" protocol=\"dubbo,tri\"/>\n\n    <!-- not set executor for this service, the default executor built using threadpool parameter of the protocolConfig -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.HelloService\" version=\"3.0.0\" group=\"Group3\"\n                   timeout=\"5000\" ref=\"helloServiceV3\" registry=\"registry1\" protocol=\"dubbo,tri\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/issues/issue6000/config.properties",
    "content": "dubbo.application.name=demo-6000\ndubbo.protocol.name=dubbo\ndubbo.protocol.port=-1\ndubbo.registry.address=${zookeeper.connection.address}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/issues/issue6252/config.properties",
    "content": "dubbo.application.name=demo-zk\ndubbo.application.qos-enable=false\ndubbo.protocol.name=dubbo\ndubbo.protocol.port=-1\ndubbo.scan.basePackages=com.example.demo\ndubbo.consumer.check=false\ndubbo.registries.z214.address=${zookeeper.connection.address.1}\ndubbo.registries.z214.timeout=20000\ndubbo.registries.z214.subscribe=false\ndubbo.registries.z214.useAsConfigCenter=false\ndubbo.registries.z214.useAsMetadataCenter=false\ndubbo.registries.z205.address=${zookeeper.connection.address.2}\ndubbo.registries.z205.timeout=20000\ndubbo.registries.z205.useAsConfigCenter=false\ndubbo.registries.z205.useAsMetadataCenter=false\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/issues/issue7003/config.properties",
    "content": "dubbo.application.name=demo-app\ndubbo.protocol.name=dubbo\ndubbo.protocol.port=-1\ndubbo.registry.address=${zookeeper.connection.address}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/issues/issue9172/consumer.properties",
    "content": "dubbo.application.name=consumer-app\ndubbo.application.owner=com.test\ndubbo.application.organization=test\ndubbo.application.logger=slf4j\ndubbo.application.compiler=javassist\ndubbo.application.qosEnable=false\n\n# registry-one\ndubbo.registries.registry-one.id=registry-one\ndubbo.registries.registry-one.protocol=zookeeper\ndubbo.registries.registry-one.client=curator\ndubbo.registries.registry-one.address=localhost:2181\n\ndubbo.consumers.consumer-one.registryIds=registry-one\ndubbo.consumers.consumer-one.check=true\ndubbo.consumers.consumer-one.timeout=15000\ndubbo.consumers.consumer-one.injvm=false\ndubbo.consumers.consumer-one.group=group-one\n\n# registry-two\ndubbo.registries.registry-two.id=registry-two\ndubbo.registries.registry-two.protocol=zookeeper\ndubbo.registries.registry-two.client=curator\ndubbo.registries.registry-two.address=localhost:2182\n\ndubbo.consumers.consumer-two.registryIds=registry-two\ndubbo.consumers.consumer-two.check=true\ndubbo.consumers.consumer-two.timeout=15000\ndubbo.consumers.consumer-two.injvm=false\ndubbo.consumers.consumer-two.group=group-two\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/issues/issue9172/provider.properties",
    "content": "dubbo.application.name=provider-app\ndubbo.application.owner=com.test\ndubbo.application.organization=test\ndubbo.application.logger=slf4j\ndubbo.application.compiler=javassist\ndubbo.application.qosEnable=false\n\n# registry-one\ndubbo.registries.registry-one.id=registry-one\ndubbo.registries.registry-one.protocol=zookeeper\ndubbo.registries.registry-one.client=curator\ndubbo.registries.registry-one.address=localhost:2181\n\ndubbo.providers.provider-one.registryIds=registry-one\ndubbo.providers.provider-one.group=group-one\n\n# registry-two\ndubbo.registries.registry-two.id=registry-two\ndubbo.registries.registry-two.protocol=zookeeper\ndubbo.registries.registry-two.client=curator\ndubbo.registries.registry-two.address=localhost:2182\n\ndubbo.providers.provider-two.registryIds=registry-two\ndubbo.providers.provider-two.group=group-two\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/issues/issue9207/dubbo-properties-in-configcenter.properties",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\ndubbo.application.name=provider-app\ndubbo.config-center.address=zookeeper://${zookeeper.address:127.0.0.1}:2181\ndubbo.registry.address=zookeeper://${zookeeper.address:127.0.0.1}:2181\ndubbo.protocol.name=dubbo\ndubbo.protocol.port=20880\ndubbo.consumer.timeout=3000\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbb-consumer.properties",
    "content": "# Dubbo Consumer for Zookeeper\n\ndubbo.application.name = zookeeper-dubbo-spring-consumer\n\ndubbo.registry.address = ${zookeeper.connection.address}?registry-type=service\ndubbo.registry.useAsConfigCenter = true\ndubbo.registry.useAsMetadataCenter = true\n\ndubbo.protocol.name = dubbo\ndubbo.protocol.port = -1\n\ndubbo.provider.name = zookeeper-dubbo-spring-provider\ndubbo.provider.name1 = zookeeper-dubbo-spring-provider-1\ndubbo.provider.name2 = zookeeper-dubbo-spring-provider-2\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbb-provider.properties",
    "content": "# Dubbo Provider for Zookeeper\n\ndubbo.application.name = zookeeper-dubbo-spring-provider-1\n\ndubbo.registry.address = ${zookeeper.connection.address}?registry-type=service\ndubbo.registry.useAsConfigCenter = true\ndubbo.registry.useAsMetadataCenter = true\n\ndubbo.protocol.name = dubbo\ndubbo.protocol.port = -1\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbo-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <!-- 当前应用信息配置 -->\n    <dubbo:application name=\"zookeeper-dubbo-spring-consumer\"/>\n\n    <!-- 连接注册中心配置 -->\n    <dubbo:registry address=\"${zookeeper.connection.address}?registry-type=service\" use-as-config-center=\"true\"\n                    use-as-metadata-center=\"true\"/>\n\n    <dubbo:reference id=\"demoService\" interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                     services=\"zookeeper-dubbo-spring-provider,zookeeper-dubbo-spring-provider\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <!-- 当前应用信息配置 -->\n    <dubbo:application name=\"dubbo-annotation-test\"/>\n\n    <!-- 连接注册中心配置 -->\n    <dubbo:registry address=\"N/A\"/>\n    <dubbo:monitor version=\"1.1\"/>\n    <dubbo:module name=\"defaultModule\"/>\n    <dubbo:consumer version=\"1.2.0\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-provider.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- 当前应用信息配置 -->\n    <dubbo:application name=\"dubbo-annotation-test\"/>\n\n    <!-- 连接注册中心配置 -->\n    <dubbo:registry id=\"my-registry\" address=\"N/A\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"12345\"/>\n\n    <!-- Annotation 注册 -->\n    <dubbo:annotation id=\"doubleServiceAnnotationPostProcessor\"\n                      package=\"org.apache.dubbo.config.spring.context.com.alibaba.dubbo.config.annotation.provider ,\n             org.apache.dubbo.config.spring.context.com.alibaba.dubbo.config.annotation.provider\"/>\n\n    <dubbo:annotation id=\"emptyServiceAnnotationPostProcessor\"\n                      package=\"    \"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <!-- 当前应用信息配置 -->\n    <dubbo:application name=\"dubbo-spring-test\"/>\n\n    <!-- 连接注册中心配置 -->\n    <dubbo:registry address=\"N/A\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-generic-consumer-without-interface.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <!-- 当前应用信息配置 -->\n    <dubbo:application name=\"dubbo-generic-consumer-without-interface\"/>\n\n    <!-- 连接注册中心配置 -->\n    <dubbo:registry address=\"${zookeeper.connection.address}\"/>\n\n    <bean id=\"genericService\" class=\"org.apache.dubbo.config.spring.schema.MyGenericService\"/>\n\n    <!-- generic service without interface class -->\n    <dubbo:reference id=\"genericServiceWithoutInterfaceRef\" interface=\"org.apache.dubbo.config.spring.api.LocalMissClass\" generic=\"true\" init=\"false\"/>\n    <dubbo:service id=\"genericServiceWithoutInterface\" interface=\"org.apache.dubbo.config.spring.api.LocalMissClass\" generic=\"true\"\n                   ref=\"genericService\"/>\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-generic-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <!-- 当前应用信息配置 -->\n    <dubbo:application name=\"dubbo-generic-consumer\"/>\n\n    <!-- 连接注册中心配置 -->\n    <dubbo:registry address=\"${zookeeper.connection.address}\"/>\n\n    <dubbo:reference id=\"demoServiceRef\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" generic=\"true\" init=\"false\"/>\n\n    <bean id=\"genericService\" class=\"org.apache.dubbo.config.spring.schema.MyGenericService\"/>\n\n    <dubbo:service id=\"demoService\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" generic=\"true\"\n                   ref=\"genericService\"/>\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-nacos-consumer-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"dubbo-consumer-xml-demo\"/>\n\n    <!-- Nacos Registry -->\n    <dubbo:registry address=\"nacos://127.0.0.1:8848\"/>\n\n    <!-- Reference interface -->\n    <dubbo:reference id=\"demoService1\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" version=\"2.0.0\"\n                     group=\"default\"/>\n\n    <dubbo:reference id=\"demoService2\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" version=\"*\"\n                     group=\"default\"/>\n\n    <dubbo:reference id=\"demoService3\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" version=\"2.0.0\"\n                     group=\"default\"/>\n\n    <dubbo:reference id=\"demoService4\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" version=\"2.0.0\" group=\"*\"/>\n\n    <dubbo:reference id=\"demoService5\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" version=\"2.0.0\"\n                     group=\"default,test\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-nacos-provider-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"dubbo-provider-xml-demo\"/>\n\n    <!-- Nacos Registry -->\n    <dubbo:registry address=\"nacos://127.0.0.1:8848\"/>\n\n    <!-- Use random port as Dubbo -->\n    <dubbo:protocol name=\"dubbo\" port=\"-1\"/>\n\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\" version=\"2.0.0\"\n                   group=\"default\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.registry.nacos.demo.service.DefaultService\"/>\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <bean id=\"a\" class=\"java.lang.String\" abstract=\"true\">\n        <property name=\"value\" value=\"1\" />\n    </bean>\n\n    <bean id=\"b\" parent=\"a\" >\n        <property name=\"value2\" value=\"2\" />\n    </bean>\n\n    <bean id=\"c\" class=\"java.lang.Object\">\n        <property name=\"b\" ref=\"b\" />\n    </bean>\n\n    <!-- 当前应用信息配置 -->\n    <dubbo:application name=\"dubbo-spring-test\" >\n        <dubbo:parameter key=\"\" value=\"\" />\n    </dubbo:application>\n\n    <!-- 连接注册中心配置 -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"12345\" />\n\n    <dubbo:annotation package=\"org.apache.dubbo.config.spring.com.alibaba.dubbo.config.annotation.provider\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/multiple-services-with-methods.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application id=\"application\" name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry id=\"registry\" address=\"N/A\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"-1\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                   class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\">\n        <dubbo:method name=\"sayName\" timeout=\"500\" />\n    </dubbo:service>\n\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                   class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl_LongWaiting\" version=\"2.0.0\">\n        <dubbo:method name=\"sayName\" timeout=\"1000\" />\n    </dubbo:service>\n\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n       http://www.springframework.org/schema/beans/spring-beans.xsd\">\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/dubbo-binder.properties",
    "content": "dubbo.application.name=hello\ndubbo.application.owner=world\ndubbo.registry.address=10.20.153.17\ndubbo.protocol.port=20881\ndubbo.service.invoke.timeout=2000\ndubbo.consumer.timeout\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/dubbo.properties",
    "content": "dubbo.application.enable-file-cache=false\ndubbo.service.shutdown.wait=200\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/nacos-consumer-config.properties",
    "content": "## Dubbo Application info\ndubbo.application.name=dubbo-consumer-demo\n## Nacos registry address\ndubbo.registry.address=nacos://127.0.0.1:8848\n# @Reference version\ndemo.service.version=1.0.0\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/nacos-provider-config.properties",
    "content": "## Dubbo Application info\ndubbo.application.name=dubbo-provider-demo\n## Nacos registry address\ndubbo.registry.protocol=nacos\ndubbo.registry.address=127.0.0.1:8848\n## Exports multiple protocols\n### Dubbo Protocol using random port\ndubbo.protocols.dubbo.port=-1\n# Provider @Service info\ndemo.service.version=1.0.0\ndemo.service.name=demoService\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/annotation-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\" xmlns:context=\"http://www.springframework.org/schema/context\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n        http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd\">\n\n    <dubbo:application name=\"annotation-consumer\"/>\n    <dubbo:registry address=\"127.0.0.1:4548\"/>\n    <dubbo:annotation package=\"org.apache.dubbo.config.spring.annotation.consumer\"/>\n    <context:component-scan base-package=\"org.apache.dubbo.config.spring.annotation.consumer\" />\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/annotation-provider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\" xmlns:context=\"http://www.springframework.org/schema/context\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd\">\n\n    <dubbo:application name=\"annotation-provider\"/>\n    <dubbo:registry address=\"127.0.0.1:4548\"/>\n    <dubbo:annotation package=\"org.apache.dubbo.config.spring.annotation.provider\"/>\n    <context:component-scan base-package=\"org.apache.dubbo.config.spring.annotation.provider\" />\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/annotation-version-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n        http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"annotation-consumer\"/>\n    <dubbo:registry address=\"127.0.0.1:4548\"/>\n    <dubbo:annotation package=\"org.apache.dubbo.config.spring.com.alibaba.dubbo.config.annotation.consumer\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/annotation-version-provider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"annotation-provider\"/>\n    <dubbo:registry address=\"127.0.0.1:4548\"/>\n    <dubbo:annotation package=\"org.apache.dubbo.config.spring.com.alibaba.dubbo.config.annotation.provider\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/aop-autowire-byname.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\"\n       default-autowire=\"byName\">\n\n    <context:annotation-config/>\n    <bean id=\"demoInterceptor\" class=\"org.apache.dubbo.config.spring.action.DemoInterceptor\"/>\n    <bean id=\"demoAdvisor\" class=\"org.springframework.aop.support.RegexpMethodPointcutAdvisor\">\n        <property name=\"advice\" ref=\"demoInterceptor\"/>\n        <property name=\"patterns\">\n            <list>\n                <value>.*</value>\n            </list>\n        </property>\n    </bean>\n    <bean id=\"demoProxyCreator\" class=\"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator\">\n        <property name=\"beanNames\">\n            <list>\n                <value>demoService</value>\n            </list>\n        </property>\n        <property name=\"interceptorNames\">\n            <list>\n                <value>demoAdvisor</value>\n            </list>\n        </property>\n    </bean>\n\n    <!-- 当前应用信息配置 -->\n    <dubbo:application name=\"consumer\"/>\n\n    <!-- 连接注册中心配置 -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- 引用服务配置 -->\n    <dubbo:reference id=\"demoService\" interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                     url=\"dubbo://127.0.0.1:20813\" scope=\"remote\">\n    </dubbo:reference>\n\n    <bean id=\"demoActionBySetter\" class=\"org.apache.dubbo.config.spring.action.DemoActionBySetter\"/>\n\n    <bean id=\"demoActionByAnnotation\" class=\"org.apache.dubbo.config.spring.action.DemoActionByAnnotation\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/aop-autowire-bytype.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\"\n       default-autowire=\"byName\">\n\n    <context:annotation-config/>\n    <bean id=\"demoInterceptor\" class=\"org.apache.dubbo.config.spring.action.DemoInterceptor\"/>\n    <bean id=\"demoAdvisor\" class=\"org.springframework.aop.support.RegexpMethodPointcutAdvisor\">\n        <property name=\"advice\" ref=\"demoInterceptor\"/>\n        <property name=\"patterns\">\n            <list>\n                <value>.*</value>\n            </list>\n        </property>\n    </bean>\n    <bean id=\"demoProxyCreator\" class=\"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator\">\n        <property name=\"beanNames\">\n            <list>\n                <value>demoService</value>\n            </list>\n        </property>\n        <property name=\"interceptorNames\">\n            <list>\n                <value>demoAdvisor</value>\n            </list>\n        </property>\n    </bean>\n\n    <!-- 当前应用信息配置 -->\n    <dubbo:application name=\"consumer\"/>\n\n    <!-- 连接注册中心配置 -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- 引用服务配置 -->\n    <dubbo:reference id=\"demoService\" interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                     url=\"dubbo://127.0.0.1:20813\"/>\n\n    <bean id=\"demoActionBySetter\" class=\"org.apache.dubbo.config.spring.action.DemoActionBySetter\"/>\n\n    <bean id=\"demoActionByAnnotation\" class=\"org.apache.dubbo.config.spring.action.DemoActionByAnnotation\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/consumer-notification.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-consumer\"/>\n\n    <!-- service reference configuration -->\n    <dubbo:reference id=\"demoService\" interface=\"org.apache.dubbo.config.spring.api.DemoService\">\n        <dubbo:method name=\"sayName\" onreturn=\"notify.getBox\" onthrow=\"notify.getBox\" oninvoke=\"notify.getBox\"/>\n    </dubbo:reference>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/customize-parameter.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns:p=\"http://www.springframework.org/schema/p\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\"\n       default-autowire=\"byName\">\n\n    <dubbo:application name=\"customize-parameter\"/>\n\n    <dubbo:registry address=\"N/A\" id=\"naRegistry\"/>\n\n    <dubbo:protocol name=\"dubbo\" p:protocol-paramA=\"protocol-paramA\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n    <dubbo:service id=\"demoServiceExport\" p:service-paramA=\"service-paramA\" registry=\"naRegistry\" ref=\"demoService\"\n                   interface=\"org.apache.dubbo.config.spring.api.DemoService\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/delay-fixed-time.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <dubbo:application name=\"demo-provider\"/>\n\n    <dubbo:registry address=\"N/A\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"20888\"/>\n\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\" delay=\"300\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/delay-on-initialized.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- register center configuration -->\n    <dubbo:registry address=\"127.0.0.1:4548\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20888\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\" delay=\"-1\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/demo-provider-UnserializableBox.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20813\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.UnserializableBoxDemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/demo-provider-long-waiting.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol id=\"dubbo1\" name=\"dubbo\" port=\"20813\"/>\n    <dubbo:protocol id=\"dubbo2\" name=\"dubbo\" port=\"20814\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"\n                   protocol=\"dubbo1,dubbo2\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl_LongWaiting\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/demo-provider-no-methods-interface.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- service configuration -->\n    <dubbo:service id=\"service\" interface=\"org.apache.dubbo.config.spring.api.DemoServiceSon\" ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceSonImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/demo-provider-properties.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\">\n\n    <bean class=\"org.springframework.context.support.PropertySourcesPlaceholderConfigurer\">\n        <property name=\"location\" value=\"classpath:/META-INF/demo-provider.properties\"/>\n    </bean>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/demo-provider.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"${dubbo.registry.address:foo-address}\"/>\n\n    <!-- service protocol configuration -->\n    <dubbo:protocol name=\"${dubbo.protocol.name:foo-protocol}\" port=\"${dubbo.protocol.port:20881}\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" group=\"demo\" version=\"1.2.3\" ref=\"demoService\"/>\n\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" group=\"demo\" version=\"1.2.4\" ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n    <bean id=\"dubboEventListener\" class=\"org.apache.dubbo.config.spring.DubboStateListener\" />\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/generic-export.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"generic-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20813\"/>\n\n    <!-- service configuration -->\n    <dubbo:service id=\"dubboDemoService\" generic=\"bean\" interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                   ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.GenericDemoService\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/init-reference-getUrls.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-consumer\"/>\n\n    <!-- service reference configuration -->\n    <dubbo:reference id=\"demoService\" interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                     url=\"dubbo://127.0.0.1:20813;dubbo://127.0.0.1:20814\" init=\"true\" timeout=\"100\" scope=\"remote\">\n        <dubbo:parameter key=\"connec.timeout\" value=\"1000\"/>\n    </dubbo:reference>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/init-reference-keys.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-consumer\"/>\n\n    <dubbo:registry id=\"my-registry\" address=\"N/A\" />\n\n    <dubbo:consumer id=\"my-consumer\" registry=\"my-registry\" group=\"demo\" version=\"1.2.4\" scope=\"remote\"\n                    timeout=\"${call.timeout:foo100}\" >\n        <dubbo:reference id=\"demoService2\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" generic=\"true\"\n                         url=\"dubbo://127.0.0.1:20813\" init=\"false\" />\n        <!-- consumer parameters -->\n        <dubbo:parameter key=\"connec.timeout\" value=\"${connection.timeout:foo1000}\"/>\n    </dubbo:consumer>\n\n    <!-- service reference configuration -->\n    <dubbo:reference id=\"demoService\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" group=\"demo\" version=\"1.2.3\"\n                     url=\"dubbo://127.0.0.1:20813\" timeout=\"${call.timeout:foo100}\" init=\"false\"\n                     scope=\"remote\" protocol=\"dubbo\" registry=\"my-registry\" consumer=\"my-consumer\" >\n        <dubbo:method name=\"sayName\" retries=\"0\">\n            <!-- method arguments -->\n            <dubbo:argument index=\"0\" callback=\"true\" />\n            <!-- method parameters -->\n            <dubbo:parameter key=\"b\" value=\"2\" />\n            <dubbo:parameter key=\"access-token\" value=\"my-token\" />\n        </dubbo:method>\n        <!-- reference parameters -->\n        <dubbo:parameter key=\"connec.timeout\" value=\"${connection.timeout:foo1000}\"/>\n    </dubbo:reference>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/init-reference-properties.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\">\n\n    <bean class=\"org.springframework.context.support.PropertySourcesPlaceholderConfigurer\">\n        <property name=\"location\" value=\"classpath:/META-INF/init-reference.properties\"/>\n    </bean>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/init-reference-retry-false.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-consumer\"/>\n\n    <!-- service reference configuration -->\n    <dubbo:reference id=\"demoService\" interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                     url=\"dubbo://127.0.0.1:20813;dubbo://127.0.0.1:20814\" init=\"true\" timeout=\"100\" scope=\"remote\">\n        <dubbo:parameter key=\"connec.timeout\" value=\"1000\"/>\n        <dubbo:method name=\"sayName\" retry=\"false\"/>\n    </dubbo:reference>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/init-reference.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-consumer\"/>\n\n    <dubbo:registry id=\"my-registry\" address=\"zookeeper://localhost:2181\" />\n\n    <dubbo:consumer id=\"my-consumer\" registry=\"my-registry\" group=\"demo\" version=\"1.2.4\" scope=\"remote\" init=\"true\"\n                    timeout=\"${call.timeout:foo100}\" >\n        <dubbo:reference id=\"demoService2\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" generic=\"true\"\n                         url=\"dubbo://127.0.0.1:20813\" />\n    </dubbo:consumer>\n\n    <bean id=\"notifyService\" class=\"org.apache.dubbo.config.spring.impl.NotifyService\" />\n\n    <!-- service reference configuration -->\n    <dubbo:reference id=\"demoService\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" group=\"demo\" version=\"1.2.3\"\n                     url=\"dubbo://127.0.0.1:20813\" init=\"true\" timeout=\"${call.timeout:foo100}\"\n                     scope=\"remote\" protocol=\"dubbo\" registry=\"my-registry\" consumer=\"my-consumer\" tag=\"demo_tag\" >\n        <dubbo:parameter key=\"connec.timeout\" value=\"${connection.timeout:foo1000}\"/>\n        <dubbo:method name=\"sayName\" retry=\"${sayName.retry:foo-retry}\" oninvoke=\"notifyService.onInvoke\"\n                      onreturn=\"notifyService.onReturn\" onthrow=\"notifyService.onThrow\">\n            <dubbo:argument index=\"0\" callback=\"true\" />\n            <dubbo:parameter key=\"access-token\" value=\"my-token\" />\n        </dubbo:method>\n    </dubbo:reference>\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/metrics-aggregation.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-consumer\" />\n\n    <dubbo:metrics enable-jvm=\"true\">\n        <dubbo:aggregation enabled=\"true\" bucket-num=\"5\" time-window-seconds=\"120\" />\n    </dubbo:metrics>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/metrics-prometheus.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-consumer\" />\n\n    <dubbo:metrics protocol=\"prometheus\">\n        <dubbo:prometheus-exporter enabled=\"true\" enable-http-service-discovery=\"true\" http-service-discovery-url=\"localhost:8080\"    />\n        <dubbo:prometheus-pushgateway enabled=\"true\" base-url=\"localhost:9091\" push-interval=\"30\" username=\"username\" password=\"password\" job=\"job\" />\n    </dubbo:metrics>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/multi-monitor.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <dubbo:application name=\"service-class\"/>\n\n    <dubbo:registry address=\"N/A\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"20887\"/>\n\n    <dubbo:provider timeout=\"2000\"/>\n\n    <dubbo:service id=\"serviceConfig\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"/>\n\n    <dubbo:monitor version=\"1.1\"/>\n    <dubbo:monitor version=\"1.2\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/multi-protocol-default.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20881\" default=\"false\"/>\n\n    <dubbo:protocol name=\"rmi\" port=\"10991\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/multi-protocol-error.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20881\"/>\n\n    <dubbo:protocol name=\"rmi\" port=\"10991\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/multi-protocol-register.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"127.0.0.1:4547\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20824\"/>\n\n    <dubbo:protocol name=\"rmi\" port=\"10924\" register=\"false\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\" protocol=\"dubbo,rmi\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/multi-protocol.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20881\"/>\n\n    <dubbo:protocol name=\"rmi\" port=\"10991\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\" protocol=\"dubbo\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/multi-registry.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry id=\"reg1\" address=\"127.0.0.1:4545\"/>\n\n    <dubbo:registry id=\"reg2\" address=\"127.0.0.1:4546\"/>\n\n    <dubbo:registry id=\"reg3\" address=\"127.0.0.1:4547\" default=\"false\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20880\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\" registry=\"reg2\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/override-multi-protocol.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20813\"/>\n    <dubbo:protocol name=\"tri\" port=\"50051\"/>\n\n    <dubbo:provider protocol=\"dubbo,tri\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/override-protocol.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20813\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/provider-multi.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"service-class\"/>\n\n    <dubbo:registry address=\"N/A\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"20887\"/>\n\n    <dubbo:provider timeout=\"2000\"/>\n\n    <dubbo:service id=\"serviceConfig\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"/>\n\n    <dubbo:provider timeout=\"1000\" default=\"true\" delay=\"1000\">\n        <dubbo:service id=\"serviceConfig2\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"\n                       group=\"demo2\"/>\n    </dubbo:provider>\n    <dubbo:provider default=\"true\" delay=\"500\">\n        <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"\n                       group=\"demo2\"/>\n    </dubbo:provider>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/provider-nested-service.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <dubbo:application name=\"service-class\"/>\n\n    <dubbo:registry address=\"N/A\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"20887\"/>\n\n    <dubbo:provider id=\"defaultProvider\" timeout=\"2000\"/>\n\n    <dubbo:service id=\"serviceConfig\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"/>\n\n    <!-- nested configuration -->\n    <dubbo:provider id=\"provider2\" timeout=\"1000\">\n        <dubbo:service id=\"serviceConfig2\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"\n                       version=\"2.0.0\"/>\n    </dubbo:provider>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/provider-with-module.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <dubbo:application name=\"service-class\"/>\n\n    <dubbo:registry address=\"N/A\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"20887\"/>\n\n    <dubbo:provider timeout=\"2000\"/>\n\n    <dubbo:service id=\"serviceConfig\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"/>\n\n    <!-- nested configuration -->\n    <dubbo:provider timeout=\"1000\">\n        <dubbo:service id=\"serviceConfig2\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"\n                       version=\"2.0.0\"/>\n    </dubbo:provider>\n    <dubbo:module name=\"test-module\" version=\"1.1\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/provider-with-monitor.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <dubbo:application name=\"service-class\"/>\n\n    <dubbo:registry address=\"N/A\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"20887\"/>\n\n    <dubbo:provider timeout=\"2000\"/>\n\n    <dubbo:service id=\"serviceConfig\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"/>\n    <dubbo:monitor default=\"true\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/service-class.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <dubbo:application name=\"service-class\"/>\n\n    <dubbo:registry address=\"N/A\"/>\n\n    <dubbo:protocol name=\"dubbo\" port=\"20887\"/>\n\n    <!-- service configuration -->\n    <dubbo:service interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                   class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\">\n        <property name=\"prefix\" value=\"welcome:\"/>\n    </dubbo:service>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/spring-extension-inject.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"N/A\"/>\n\n    <bean id=\"mockDao\" class=\"org.apache.dubbo.config.spring.filter.MockDaoImpl\"/>\n\n    <!-- service configuration -->\n    <dubbo:service id=\"demoServiceConfig\" interface=\"org.apache.dubbo.config.spring.api.DemoService\" ref=\"demoService\"\n                   filter=\"mymock,default\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/system-properties-override-default.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- service configuration -->\n    <dubbo:service id=\"demoServiceConfig\" interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                   ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/system-properties-override.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry address=\"127.0.0.1\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"rmi\" port=\"20813\"/>\n\n    <!-- service configuration -->\n    <dubbo:service id=\"demoServiceConfig\" register=\"true\" interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                   ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/org/apache/dubbo/config/spring/xml-override-properties.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<beans xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://dubbo.apache.org/schema/dubbo\"\n       xmlns=\"http://www.springframework.org/schema/beans\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd\n    http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd\n    \">\n\n    <!-- current application configuration -->\n    <dubbo:application id=\"application\" name=\"demo-provider\"/>\n\n    <!-- registry center configuration -->\n    <dubbo:registry id=\"registry\" address=\"N/A\"/>\n\n    <!-- protocol configuration -->\n    <dubbo:protocol name=\"dubbo\" port=\"20813\"/>\n\n    <!-- service configuration -->\n    <dubbo:service id=\"demoServiceConfig\" interface=\"org.apache.dubbo.config.spring.api.DemoService\"\n                   ref=\"demoService\"/>\n\n    <bean id=\"demoService\" class=\"org.apache.dubbo.config.spring.impl.DemoServiceImpl\"/>\n\n</beans>"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/webapps/test/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<web-app version=\"3.1\">\n    <display-name>dubbo-demo</display-name>\n\n    <context-param>\n        <param-name>contextConfigLocation</param-name>\n        <param-value>classpath:applicationContext.xml</param-value>\n    </context-param>\n\n    <listener>\n        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>\n    </listener>\n\n</web-app>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/webapps/test2/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<web-app version=\"3.1\">\n    <display-name>dubbo-demo</display-name>\n\n    <context-param>\n        <param-name>contextConfigLocation</param-name>\n        <param-value>classpath:applicationContext.xml</param-value>\n    </context-param>\n\n</web-app>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring/src/test/resources/webapps/test3/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<web-app version=\"3.1\" metadata-complete=\"true\">\n    <display-name>dubbo-demo</display-name>\n\n    <context-param>\n        <param-name>contextConfigLocation</param-name>\n        <param-value>classpath:applicationContext.xml</param-value>\n    </context-param>\n\n</web-app>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-config</artifactId>\n    <version>${revision}</version>\n  </parent>\n\n  <artifactId>dubbo-config-spring6</artifactId>\n\n  <properties>\n    <maven.compiler.source>17</maven.compiler.source>\n    <maven.compiler.target>17</maven.compiler.target>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-beans</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-core</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-web</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-context</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>javax.servlet</groupId>\n      <artifactId>javax.servlet-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <version>${spring-boot-3.version}</version>\n      <scope>test</scope>\n      <exclusions>\n        <exclusion>\n          <groupId>ch.qos.logback</groupId>\n          <artifactId>logback-classic</artifactId>\n        </exclusion>\n        <exclusion>\n          <groupId>org.apache.logging.log4j</groupId>\n          <artifactId>log4j-to-slf4j</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/main/java/org/apache/dubbo/config/spring6/beans/factory/annotation/ReferenceAnnotationWithAotBeanPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.beans.factory.annotation;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.ReferenceBean;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;\nimport org.apache.dubbo.config.spring.context.event.DubboConfigInitEvent;\nimport org.apache.dubbo.config.spring.util.SpringCompatUtils;\nimport org.apache.dubbo.config.spring6.beans.factory.aot.ReferencedFieldValueResolver;\nimport org.apache.dubbo.config.spring6.beans.factory.aot.ReferencedMethodArgumentsResolver;\nimport org.apache.dubbo.config.spring6.utils.AotUtils;\nimport org.apache.dubbo.rpc.service.Destroyable;\nimport org.apache.dubbo.rpc.service.EchoService;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Member;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Parameter;\n\nimport org.springframework.aop.SpringProxy;\nimport org.springframework.aop.framework.Advised;\nimport org.springframework.aot.generate.AccessControl;\nimport org.springframework.aot.generate.GeneratedClass;\nimport org.springframework.aot.generate.GeneratedMethod;\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.hint.support.ClassHintUtils;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.aot.AutowiredArgumentsCodeGenerator;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotContribution;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanRegistrationCode;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.config.DependencyDescriptor;\nimport org.springframework.beans.factory.support.AutowireCandidateResolver;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.core.DecoratingProxy;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.javapoet.ClassName;\nimport org.springframework.javapoet.CodeBlock;\nimport org.springframework.lang.Nullable;\nimport org.springframework.util.CollectionUtils;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_DUBBO_BEAN_INITIALIZER;\n\n/**\n * The purpose of implementing {@link BeanRegistrationAotProcessor} is to\n * supplement for {@link ReferenceAnnotationBeanPostProcessor} ability of AOT.\n *\n * @since 3.3\n */\npublic class ReferenceAnnotationWithAotBeanPostProcessor extends ReferenceAnnotationBeanPostProcessor\n        implements BeanRegistrationAotProcessor {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    @Nullable\n    private ConfigurableListableBeanFactory beanFactory;\n\n    /**\n     * {@link com.alibaba.dubbo.config.annotation.Reference @com.alibaba.dubbo.config.annotation.Reference} has been supported since 2.7.3\n     * <p>\n     * {@link DubboReference @DubboReference} has been supported since 2.7.7\n     */\n    public ReferenceAnnotationWithAotBeanPostProcessor() {\n        super();\n    }\n\n    @Override\n    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\n        String[] beanNames = beanFactory.getBeanDefinitionNames();\n        for (String beanName : beanNames) {\n            Class<?> beanType;\n            if (beanFactory.isFactoryBean(beanName)) {\n                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);\n                if (isReferenceBean(beanDefinition)) {\n                    continue;\n                }\n                if (isAnnotatedReferenceBean(beanDefinition)) {\n                    // process @DubboReference at java-config @bean method\n                    processReferenceAnnotatedBeanDefinition(beanName, (AnnotatedBeanDefinition) beanDefinition);\n                    continue;\n                }\n\n                String beanClassName = beanDefinition.getBeanClassName();\n                beanType = ClassUtils.resolveClass(beanClassName, getClassLoader());\n            } else {\n                beanType = beanFactory.getType(beanName);\n            }\n            if (beanType != null) {\n                AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);\n                try {\n                    prepareInjection(metadata);\n                } catch (BeansException e) {\n                    throw e;\n                } catch (Exception e) {\n                    throw new IllegalStateException(\"Prepare dubbo reference injection element failed\", e);\n                }\n            }\n        }\n\n        try {\n            // this is an early event, it will be notified at\n            // org.springframework.context.support.AbstractApplicationContext.registerListeners()\n            applicationContext.publishEvent(new DubboConfigInitEvent(applicationContext));\n        } catch (Exception e) {\n            // if spring version is less than 4.2, it does not support early application event\n            logger.warn(\n                    CONFIG_DUBBO_BEAN_INITIALIZER,\n                    \"\",\n                    \"\",\n                    \"publish early application event failed, please upgrade spring version to 4.2.x or later: \" + e);\n        }\n    }\n\n    /**\n     * check whether is @DubboReference at java-config @bean method\n     */\n    private boolean isAnnotatedReferenceBean(BeanDefinition beanDefinition) {\n        if (beanDefinition instanceof AnnotatedBeanDefinition) {\n            AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;\n            String beanClassName = SpringCompatUtils.getFactoryMethodReturnType(annotatedBeanDefinition);\n            if (beanClassName != null && ReferenceBean.class.getName().equals(beanClassName)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private boolean isReferenceBean(BeanDefinition beanDefinition) {\n        return ReferenceBean.class.getName().equals(beanDefinition.getBeanClassName());\n    }\n\n    @Override\n    @Nullable\n    public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {\n        Class<?> beanClass = registeredBean.getBeanClass();\n        String beanName = registeredBean.getBeanName();\n        RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();\n        AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanDefinition, beanClass, beanName);\n        if (!CollectionUtils.isEmpty(metadata.getFieldElements())\n                || !CollectionUtils.isEmpty(metadata.getMethodElements())) {\n            return new AotContribution(beanClass, metadata, getAutowireCandidateResolver());\n        }\n        return null;\n    }\n\n    private AnnotatedInjectionMetadata findInjectionMetadata(\n            RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {\n        AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);\n        metadata.checkConfigMembers(beanDefinition);\n        return metadata;\n    }\n\n    @Nullable\n    private AutowireCandidateResolver getAutowireCandidateResolver() {\n        if (this.beanFactory instanceof DefaultListableBeanFactory) {\n            return ((DefaultListableBeanFactory) this.beanFactory).getAutowireCandidateResolver();\n        }\n        return null;\n    }\n\n    private static class AotContribution implements BeanRegistrationAotContribution {\n\n        private static final String REGISTERED_BEAN_PARAMETER = \"registeredBean\";\n\n        private static final String INSTANCE_PARAMETER = \"instance\";\n\n        private final Class<?> target;\n\n        private final AnnotatedInjectionMetadata annotatedInjectionMetadata;\n\n        @Nullable\n        private final AutowireCandidateResolver candidateResolver;\n\n        AotContribution(\n                Class<?> target,\n                AnnotatedInjectionMetadata annotatedInjectionMetadata,\n                AutowireCandidateResolver candidateResolver) {\n\n            this.target = target;\n            this.annotatedInjectionMetadata = annotatedInjectionMetadata;\n            this.candidateResolver = candidateResolver;\n        }\n\n        @Override\n        public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {\n            GeneratedClass generatedClass = generationContext\n                    .getGeneratedClasses()\n                    .addForFeatureComponent(\"DubboReference\", this.target, type -> {\n                        type.addJavadoc(\"DubboReference for {@link $T}.\", this.target);\n                        type.addModifiers(javax.lang.model.element.Modifier.PUBLIC);\n                    });\n            GeneratedMethod generateMethod = generatedClass.getMethods().add(\"apply\", method -> {\n                method.addJavadoc(\"Apply the dubbo reference.\");\n                method.addModifiers(javax.lang.model.element.Modifier.PUBLIC, javax.lang.model.element.Modifier.STATIC);\n                method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER);\n                method.addParameter(this.target, INSTANCE_PARAMETER);\n                method.returns(this.target);\n                method.addCode(generateMethodCode(generatedClass.getName(), generationContext.getRuntimeHints()));\n            });\n            beanRegistrationCode.addInstancePostProcessor(generateMethod.toMethodReference());\n\n            if (this.candidateResolver != null) {\n                registerHints(generationContext.getRuntimeHints());\n            }\n        }\n\n        private CodeBlock generateMethodCode(ClassName targetClassName, RuntimeHints hints) {\n            CodeBlock.Builder code = CodeBlock.builder();\n            if (!CollectionUtils.isEmpty(this.annotatedInjectionMetadata.getFieldElements())) {\n                for (AnnotatedInjectElement referenceElement : this.annotatedInjectionMetadata.getFieldElements()) {\n                    code.addStatement(generateStatementForElement(targetClassName, referenceElement, hints));\n                }\n            }\n            if (!CollectionUtils.isEmpty(this.annotatedInjectionMetadata.getMethodElements())) {\n                for (AnnotatedInjectElement referenceElement : this.annotatedInjectionMetadata.getMethodElements()) {\n                    code.addStatement(generateStatementForElement(targetClassName, referenceElement, hints));\n                }\n            }\n            code.addStatement(\"return $L\", INSTANCE_PARAMETER);\n            return code.build();\n        }\n\n        private CodeBlock generateStatementForElement(\n                ClassName targetClassName, AnnotatedInjectElement referenceElement, RuntimeHints hints) {\n\n            Member member = referenceElement.getMember();\n            AnnotationAttributes attributes = referenceElement.attributes;\n            Object injectedObject = referenceElement.injectedObject;\n\n            try {\n                Class<?> c = referenceElement.getInjectedType();\n                AotUtils.registerSerializationForService(c, hints);\n                hints.reflection().registerType(TypeReference.of(c), MemberCategory.INVOKE_PUBLIC_METHODS);\n                // need to enumerate all interfaces by the proxy\n                hints.proxies().registerJdkProxy(c, EchoService.class, Destroyable.class);\n                hints.proxies().registerJdkProxy(c, EchoService.class, Destroyable.class, GenericService.class);\n                hints.proxies()\n                        .registerJdkProxy(\n                                c,\n                                EchoService.class,\n                                Destroyable.class,\n                                SpringProxy.class,\n                                Advised.class,\n                                DecoratingProxy.class);\n                hints.proxies()\n                        .registerJdkProxy(\n                                c,\n                                EchoService.class,\n                                GenericService.class,\n                                Destroyable.class,\n                                SpringProxy.class,\n                                Advised.class,\n                                DecoratingProxy.class);\n            } catch (ClassNotFoundException e) {\n                throw new RuntimeException(e);\n            }\n\n            if (member instanceof Field) {\n                return generateMethodStatementForField(\n                        targetClassName, (Field) member, attributes, injectedObject, hints);\n            }\n            if (member instanceof Method) {\n                return generateMethodStatementForMethod(\n                        targetClassName, (Method) member, attributes, injectedObject, hints);\n            }\n            throw new IllegalStateException(\n                    \"Unsupported member type \" + member.getClass().getName());\n        }\n\n        private CodeBlock generateMethodStatementForField(\n                ClassName targetClassName,\n                Field field,\n                AnnotationAttributes attributes,\n                Object injectedObject,\n                RuntimeHints hints) {\n\n            hints.reflection().registerField(field);\n            CodeBlock resolver =\n                    CodeBlock.of(\"$T.$L($S)\", ReferencedFieldValueResolver.class, \"forRequiredField\", field.getName());\n            CodeBlock shortcutResolver = CodeBlock.of(\"$L.withShortcut($S)\", resolver, injectedObject);\n            AccessControl accessControl = AccessControl.forMember(field);\n\n            if (!accessControl.isAccessibleFrom(targetClassName)) {\n                return CodeBlock.of(\n                        \"$L.resolveAndSet($L, $L)\", shortcutResolver, REGISTERED_BEAN_PARAMETER, INSTANCE_PARAMETER);\n            }\n            return CodeBlock.of(\n                    \"$L.$L = $L.resolve($L)\",\n                    INSTANCE_PARAMETER,\n                    field.getName(),\n                    shortcutResolver,\n                    REGISTERED_BEAN_PARAMETER);\n        }\n\n        private CodeBlock generateMethodStatementForMethod(\n                ClassName targetClassName,\n                Method method,\n                AnnotationAttributes attributes,\n                Object injectedObject,\n                RuntimeHints hints) {\n\n            CodeBlock.Builder code = CodeBlock.builder();\n            code.add(\"$T.$L\", ReferencedMethodArgumentsResolver.class, \"forRequiredMethod\");\n            code.add(\"($S\", method.getName());\n            if (method.getParameterCount() > 0) {\n                code.add(\", $L\", generateParameterTypesCode(method.getParameterTypes()));\n            }\n            code.add(\")\");\n            if (method.getParameterCount() > 0) {\n                Parameter[] parameters = method.getParameters();\n                String[] parameterNames = new String[parameters.length];\n                for (int i = 0; i < parameterNames.length; i++) {\n                    parameterNames[i] = parameters[i].getName();\n                }\n                code.add(\".withShortcut($L)\", generateParameterNamesCode(parameterNames));\n            }\n            AccessControl accessControl = AccessControl.forMember(method);\n            if (!accessControl.isAccessibleFrom(targetClassName)) {\n                hints.reflection().registerMethod(method, ExecutableMode.INVOKE);\n                code.add(\".resolveAndInvoke($L, $L)\", REGISTERED_BEAN_PARAMETER, INSTANCE_PARAMETER);\n            } else {\n                hints.reflection().registerMethod(method, ExecutableMode.INTROSPECT);\n                CodeBlock arguments = new AutowiredArgumentsCodeGenerator(this.target, method)\n                        .generateCode(method.getParameterTypes());\n                CodeBlock injectionCode =\n                        CodeBlock.of(\"args -> $L.$L($L)\", INSTANCE_PARAMETER, method.getName(), arguments);\n                code.add(\".resolve($L, $L)\", REGISTERED_BEAN_PARAMETER, injectionCode);\n            }\n            return code.build();\n        }\n\n        private CodeBlock generateParameterNamesCode(String[] parameterNames) {\n            CodeBlock.Builder code = CodeBlock.builder();\n            for (int i = 0; i < parameterNames.length; i++) {\n                code.add(i != 0 ? \", \" : \"\");\n                code.add(\"$S\", parameterNames[i]);\n            }\n            return code.build();\n        }\n\n        private CodeBlock generateParameterTypesCode(Class<?>[] parameterTypes) {\n            CodeBlock.Builder code = CodeBlock.builder();\n            for (int i = 0; i < parameterTypes.length; i++) {\n                code.add(i != 0 ? \", \" : \"\");\n                code.add(\"$T.class\", parameterTypes[i]);\n            }\n            return code.build();\n        }\n\n        private void registerHints(RuntimeHints runtimeHints) {\n            if (!CollectionUtils.isEmpty(this.annotatedInjectionMetadata.getFieldElements())) {\n                for (AnnotatedInjectElement referenceElement : this.annotatedInjectionMetadata.getFieldElements()) {\n                    Member member = referenceElement.getMember();\n                    if (member instanceof Field) {\n                        Field field = (Field) member;\n                        DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(field, true);\n                        registerProxyIfNecessary(runtimeHints, dependencyDescriptor);\n                    }\n                }\n            }\n            if (!CollectionUtils.isEmpty(this.annotatedInjectionMetadata.getMethodElements())) {\n                for (AnnotatedInjectElement referenceElement : this.annotatedInjectionMetadata.getMethodElements()) {\n                    Member member = referenceElement.getMember();\n                    if (member instanceof Method) {\n                        Method method = (Method) member;\n                        Class<?>[] parameterTypes = method.getParameterTypes();\n                        for (int i = 0; i < parameterTypes.length; i++) {\n                            MethodParameter methodParam = new MethodParameter(method, i);\n                            DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(methodParam, true);\n                            registerProxyIfNecessary(runtimeHints, dependencyDescriptor);\n                        }\n                    }\n                }\n            }\n        }\n\n        private void registerProxyIfNecessary(RuntimeHints runtimeHints, DependencyDescriptor dependencyDescriptor) {\n            if (this.candidateResolver != null) {\n                Class<?> proxyClass = this.candidateResolver.getLazyResolutionProxyClass(dependencyDescriptor, null);\n                if (proxyClass != null) {\n                    ClassHintUtils.registerProxyIfNecessary(proxyClass, runtimeHints);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/main/java/org/apache/dubbo/config/spring6/beans/factory/annotation/ServiceAnnotationWithAotPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.beans.factory.annotation;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.spring.ServiceBean;\nimport org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;\nimport org.apache.dubbo.config.spring.schema.AnnotationBeanDefinitionParser;\nimport org.apache.dubbo.config.spring6.utils.AotUtils;\n\nimport java.util.Collection;\n\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotContribution;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanRegistrationCode;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\n\n/**\n * The purpose of implementing {@link BeanRegistrationAotProcessor} is to\n * supplement for {@link ServiceAnnotationPostProcessor} ability of AOT.\n *\n * @see AnnotationBeanDefinitionParser\n * @see BeanDefinitionRegistryPostProcessor\n * @since 3.3\n */\npublic class ServiceAnnotationWithAotPostProcessor extends ServiceAnnotationPostProcessor\n        implements BeanRegistrationAotProcessor {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    public ServiceAnnotationWithAotPostProcessor(String... packagesToScan) {\n        super(packagesToScan);\n    }\n\n    public ServiceAnnotationWithAotPostProcessor(Collection<?> packagesToScan) {\n        super(packagesToScan);\n    }\n\n    @Override\n    public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {\n        Class<?> beanClass = registeredBean.getBeanClass();\n        if (beanClass.equals(ServiceBean.class)) {\n            RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();\n            String interfaceName = (String) beanDefinition.getPropertyValues().get(\"interface\");\n            try {\n                Class<?> c = Class.forName(interfaceName);\n                return new DubboServiceBeanRegistrationAotContribution(c);\n            } catch (ClassNotFoundException e) {\n                throw new RuntimeException(e);\n            }\n        } else if (servicePackagesHolder.isClassScanned(beanClass.getName())) {\n            return new DubboServiceBeanRegistrationAotContribution(beanClass);\n        }\n\n        return null;\n    }\n\n    private static class DubboServiceBeanRegistrationAotContribution implements BeanRegistrationAotContribution {\n\n        private final Class<?> cl;\n\n        public DubboServiceBeanRegistrationAotContribution(Class<?> cl) {\n            this.cl = cl;\n        }\n\n        @Override\n        public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {\n            generationContext\n                    .getRuntimeHints()\n                    .reflection()\n                    .registerType(TypeReference.of(cl), MemberCategory.INVOKE_PUBLIC_METHODS);\n            AotUtils.registerSerializationForService(cl, generationContext.getRuntimeHints());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/main/java/org/apache/dubbo/config/spring6/beans/factory/aot/AutowiredElementResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.beans.factory.aot;\n\nimport javax.lang.model.element.Element;\n\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.beans.factory.config.DependencyDescriptor;\nimport org.springframework.core.log.LogMessage;\n\n/**\n * Base class for resolvers that support autowiring related to an\n * {@link Element}.\n */\nabstract class AutowiredElementResolver {\n\n    private final Log logger = LogFactory.getLog(getClass());\n\n    protected final void registerDependentBeans(\n            ConfigurableBeanFactory beanFactory, String beanName, Set<String> autowiredBeanNames) {\n\n        for (String autowiredBeanName : autowiredBeanNames) {\n            if (beanFactory.containsBean(autowiredBeanName)) {\n                beanFactory.registerDependentBean(autowiredBeanName, beanName);\n            }\n            logger.trace(LogMessage.format(\n                    \"Autowiring by type from bean name %s' to bean named '%s'\", beanName, autowiredBeanName));\n        }\n    }\n\n    /**\n     * {@link DependencyDescriptor} that supports shortcut bean resolution.\n     */\n    @SuppressWarnings(\"serial\")\n    static class ShortcutDependencyDescriptor extends DependencyDescriptor {\n\n        private final String shortcut;\n\n        private final Class<?> requiredType;\n\n        public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {\n            super(original);\n            this.shortcut = shortcut;\n            this.requiredType = requiredType;\n        }\n\n        @Override\n        public Object resolveShortcut(BeanFactory beanFactory) {\n            return beanFactory.getBean(this.shortcut, this.requiredType);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/main/java/org/apache/dubbo/config/spring6/beans/factory/aot/ReferencedFieldValueResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.beans.factory.aot;\n\nimport org.apache.dubbo.config.spring6.beans.factory.annotation.ReferenceAnnotationWithAotBeanPostProcessor;\n\nimport java.lang.reflect.Field;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.TypeConverter;\nimport org.springframework.beans.factory.InjectionPoint;\nimport org.springframework.beans.factory.UnsatisfiedDependencyException;\nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.beans.factory.config.DependencyDescriptor;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.lang.Nullable;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.function.ThrowingConsumer;\n\n/**\n * Resolver used to support the autowiring of fields. Typically used in\n * AOT-processed applications as a targeted alternative to the\n * {@link ReferenceAnnotationWithAotBeanPostProcessor\n * ReferenceAnnotationBeanPostProcessor}.\n *\n * <p>When resolving arguments in a native image, the {@link Field} being used must\n * be marked with an {@link ExecutableMode#INTROSPECT introspection} hint so\n * that field annotations can be read. Full {@link ExecutableMode#INVOKE\n * invocation} hints are only required if the\n * {@link #resolveAndSet(RegisteredBean, Object)} method of this class is being\n * used (typically to support private fields).\n */\npublic final class ReferencedFieldValueResolver extends AutowiredElementResolver {\n\n    private final String fieldName;\n\n    private final boolean required;\n\n    @Nullable\n    private final String shortcut;\n\n    private ReferencedFieldValueResolver(String fieldName, boolean required, @Nullable String shortcut) {\n\n        Assert.hasText(fieldName, \"'fieldName' must not be empty\");\n        this.fieldName = fieldName;\n        this.required = required;\n        this.shortcut = shortcut;\n    }\n\n    /**\n     * Create a new {@link ReferencedFieldValueResolver} for the specified field\n     * where injection is optional.\n     *\n     * @param fieldName the field name\n     * @return a new {@link ReferencedFieldValueResolver} instance\n     */\n    public static ReferencedFieldValueResolver forField(String fieldName) {\n        return new ReferencedFieldValueResolver(fieldName, false, null);\n    }\n\n    /**\n     * Create a new {@link ReferencedFieldValueResolver} for the specified field\n     * where injection is required.\n     *\n     * @param fieldName the field name\n     * @return a new {@link ReferencedFieldValueResolver} instance\n     */\n    public static ReferencedFieldValueResolver forRequiredField(String fieldName) {\n        return new ReferencedFieldValueResolver(fieldName, true, null);\n    }\n\n    /**\n     * Return a new {@link ReferencedFieldValueResolver} instance that uses a\n     * direct bean name injection shortcut.\n     *\n     * @param beanName the bean name to use as a shortcut\n     * @return a new {@link ReferencedFieldValueResolver} instance that uses the\n     * shortcuts\n     */\n    public ReferencedFieldValueResolver withShortcut(String beanName) {\n        return new ReferencedFieldValueResolver(this.fieldName, this.required, beanName);\n    }\n\n    /**\n     * Resolve the field for the specified registered bean and provide it to the\n     * given action.\n     *\n     * @param registeredBean the registered bean\n     * @param action         the action to execute with the resolved field value\n     */\n    public <T> void resolve(RegisteredBean registeredBean, ThrowingConsumer<T> action) {\n        Assert.notNull(registeredBean, \"'registeredBean' must not be null\");\n        Assert.notNull(action, \"'action' must not be null\");\n        T resolved = resolve(registeredBean);\n        if (resolved != null) {\n            action.accept(resolved);\n        }\n    }\n\n    /**\n     * Resolve the field value for the specified registered bean.\n     *\n     * @param registeredBean the registered bean\n     * @param requiredType   the required type\n     * @return the resolved field value\n     */\n    @Nullable\n    @SuppressWarnings(\"unchecked\")\n    public <T> T resolve(RegisteredBean registeredBean, Class<T> requiredType) {\n        Object value = resolveObject(registeredBean);\n        Assert.isInstanceOf(requiredType, value);\n        return (T) value;\n    }\n\n    /**\n     * Resolve the field value for the specified registered bean.\n     *\n     * @param registeredBean the registered bean\n     * @return the resolved field value\n     */\n    @Nullable\n    @SuppressWarnings(\"unchecked\")\n    public <T> T resolve(RegisteredBean registeredBean) {\n        return (T) resolveObject(registeredBean);\n    }\n\n    /**\n     * Resolve the field value for the specified registered bean.\n     *\n     * @param registeredBean the registered bean\n     * @return the resolved field value\n     */\n    @Nullable\n    public Object resolveObject(RegisteredBean registeredBean) {\n        Assert.notNull(registeredBean, \"'registeredBean' must not be null\");\n        return resolveValue(registeredBean, getField(registeredBean));\n    }\n\n    /**\n     * Resolve the field value for the specified registered bean and set it\n     * using reflection.\n     *\n     * @param registeredBean the registered bean\n     * @param instance       the bean instance\n     */\n    public void resolveAndSet(RegisteredBean registeredBean, Object instance) {\n        Assert.notNull(registeredBean, \"'registeredBean' must not be null\");\n        Assert.notNull(instance, \"'instance' must not be null\");\n        Field field = getField(registeredBean);\n        Object resolved = resolveValue(registeredBean, field);\n        if (resolved != null) {\n            ReflectionUtils.makeAccessible(field);\n            ReflectionUtils.setField(field, instance, resolved);\n        }\n    }\n\n    @Nullable\n    private Object resolveValue(RegisteredBean registeredBean, Field field) {\n        String beanName = registeredBean.getBeanName();\n        Class<?> beanClass = registeredBean.getBeanClass();\n        ConfigurableBeanFactory beanFactory = registeredBean.getBeanFactory();\n        DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);\n        descriptor.setContainingClass(beanClass);\n        if (this.shortcut != null) {\n            descriptor = new ShortcutDependencyDescriptor(descriptor, this.shortcut, field.getType());\n        }\n        Set<String> autowiredBeanNames = new LinkedHashSet<>(1);\n        TypeConverter typeConverter = beanFactory.getTypeConverter();\n        try {\n            Assert.isInstanceOf(AutowireCapableBeanFactory.class, beanFactory);\n\n            Object injectedObject = beanFactory.getBean(shortcut);\n\n            Object value = ((AutowireCapableBeanFactory) beanFactory)\n                    .resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);\n            registerDependentBeans(beanFactory, beanName, autowiredBeanNames);\n            return injectedObject;\n        } catch (BeansException ex) {\n            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);\n        }\n    }\n\n    private Field getField(RegisteredBean registeredBean) {\n        Field field = ReflectionUtils.findField(registeredBean.getBeanClass(), this.fieldName);\n        Assert.notNull(\n                field,\n                () -> \"No field '\" + this.fieldName + \"' found on \"\n                        + registeredBean.getBeanClass().getName());\n        return field;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/main/java/org/apache/dubbo/config/spring6/beans/factory/aot/ReferencedMethodArgumentsResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.beans.factory.aot;\n\nimport org.apache.dubbo.config.spring6.beans.factory.annotation.ReferenceAnnotationWithAotBeanPostProcessor;\n\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.TypeConverter;\nimport org.springframework.beans.factory.InjectionPoint;\nimport org.springframework.beans.factory.UnsatisfiedDependencyException;\nimport org.springframework.beans.factory.aot.AutowiredArguments;\nimport org.springframework.beans.factory.aot.AutowiredFieldValueResolver;\nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.beans.factory.config.DependencyDescriptor;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.lang.Nullable;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.function.ThrowingConsumer;\n\n/**\n * Resolver used to support the autowiring of methods. Typically used in\n * AOT-processed applications as a targeted alternative to the\n * {@link ReferenceAnnotationWithAotBeanPostProcessor\n * ReferenceAnnotationBeanPostProcessor}.\n *\n * <p>When resolving arguments in a native image, the {@link Method} being used\n * must be marked with an {@link ExecutableMode#INTROSPECT introspection} hint\n * so that field annotations can be read. Full {@link ExecutableMode#INVOKE\n * invocation} hints are only required if the\n * {@link #resolveAndInvoke(RegisteredBean, Object)} method of this class is\n * being used (typically to support private methods).\n */\npublic final class ReferencedMethodArgumentsResolver extends AutowiredElementResolver {\n\n    private final String methodName;\n\n    private final Class<?>[] parameterTypes;\n\n    private final boolean required;\n\n    @Nullable\n    private final String[] shortcuts;\n\n    private ReferencedMethodArgumentsResolver(\n            String methodName, Class<?>[] parameterTypes, boolean required, @Nullable String[] shortcuts) {\n\n        Assert.hasText(methodName, \"'methodName' must not be empty\");\n        this.methodName = methodName;\n        this.parameterTypes = parameterTypes;\n        this.required = required;\n        this.shortcuts = shortcuts;\n    }\n\n    /**\n     * Create a new {@link ReferencedMethodArgumentsResolver} for the specified\n     * method where injection is optional.\n     *\n     * @param methodName     the method name\n     * @param parameterTypes the factory method parameter types\n     * @return a new {@link org.springframework.beans.factory.aot.AutowiredFieldValueResolver} instance\n     */\n    public static ReferencedMethodArgumentsResolver forMethod(String methodName, Class<?>... parameterTypes) {\n\n        return new ReferencedMethodArgumentsResolver(methodName, parameterTypes, false, null);\n    }\n\n    /**\n     * Create a new {@link ReferencedMethodArgumentsResolver} for the specified\n     * method where injection is required.\n     *\n     * @param methodName     the method name\n     * @param parameterTypes the factory method parameter types\n     * @return a new {@link AutowiredFieldValueResolver} instance\n     */\n    public static ReferencedMethodArgumentsResolver forRequiredMethod(String methodName, Class<?>... parameterTypes) {\n\n        return new ReferencedMethodArgumentsResolver(methodName, parameterTypes, true, null);\n    }\n\n    /**\n     * Return a new {@link ReferencedMethodArgumentsResolver} instance\n     * that uses direct bean name injection shortcuts for specific parameters.\n     *\n     * @param beanNames the bean names to use as shortcuts (aligned with the\n     *                  method parameters)\n     * @return a new {@link ReferencedMethodArgumentsResolver} instance that uses\n     * the shortcuts\n     */\n    public ReferencedMethodArgumentsResolver withShortcut(String... beanNames) {\n        return new ReferencedMethodArgumentsResolver(this.methodName, this.parameterTypes, this.required, beanNames);\n    }\n\n    /**\n     * Resolve the method arguments for the specified registered bean and\n     * provide it to the given action.\n     *\n     * @param registeredBean the registered bean\n     * @param action         the action to execute with the resolved method arguments\n     */\n    public void resolve(RegisteredBean registeredBean, ThrowingConsumer<AutowiredArguments> action) {\n\n        Assert.notNull(registeredBean, \"'registeredBean' must not be null\");\n        Assert.notNull(action, \"'action' must not be null\");\n        AutowiredArguments resolved = resolve(registeredBean);\n        if (resolved != null) {\n            action.accept(resolved);\n        }\n    }\n\n    /**\n     * Resolve the method arguments for the specified registered bean.\n     *\n     * @param registeredBean the registered bean\n     * @return the resolved method arguments\n     */\n    @Nullable\n    public AutowiredArguments resolve(RegisteredBean registeredBean) {\n        Assert.notNull(registeredBean, \"'registeredBean' must not be null\");\n        return resolveArguments(registeredBean, getMethod(registeredBean));\n    }\n\n    /**\n     * Resolve the method arguments for the specified registered bean and invoke\n     * the method using reflection.\n     *\n     * @param registeredBean the registered bean\n     * @param instance       the bean instance\n     */\n    public void resolveAndInvoke(RegisteredBean registeredBean, Object instance) {\n        Assert.notNull(registeredBean, \"'registeredBean' must not be null\");\n        Assert.notNull(instance, \"'instance' must not be null\");\n        Method method = getMethod(registeredBean);\n        AutowiredArguments resolved = resolveArguments(registeredBean, method);\n        if (resolved != null) {\n            ReflectionUtils.makeAccessible(method);\n            ReflectionUtils.invokeMethod(method, instance, resolved.toArray());\n        }\n    }\n\n    @Nullable\n    private AutowiredArguments resolveArguments(RegisteredBean registeredBean, Method method) {\n\n        String beanName = registeredBean.getBeanName();\n        Class<?> beanClass = registeredBean.getBeanClass();\n        ConfigurableBeanFactory beanFactory = registeredBean.getBeanFactory();\n        Assert.isInstanceOf(AutowireCapableBeanFactory.class, beanFactory);\n        AutowireCapableBeanFactory autowireCapableBeanFactory = (AutowireCapableBeanFactory) beanFactory;\n        int argumentCount = method.getParameterCount();\n        Object[] arguments = new Object[argumentCount];\n        Set<String> autowiredBeanNames = new LinkedHashSet<>(argumentCount);\n        TypeConverter typeConverter = beanFactory.getTypeConverter();\n        for (int i = 0; i < argumentCount; i++) {\n            MethodParameter parameter = new MethodParameter(method, i);\n            DependencyDescriptor descriptor = new DependencyDescriptor(parameter, this.required);\n            descriptor.setContainingClass(beanClass);\n            String shortcut = (this.shortcuts != null) ? this.shortcuts[i] : null;\n            if (shortcut != null) {\n                descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut, parameter.getParameterType());\n            }\n            try {\n                Object injectedArgument = beanFactory.getBean(shortcut);\n                Object argument = autowireCapableBeanFactory.resolveDependency(\n                        descriptor, beanName, autowiredBeanNames, typeConverter);\n                arguments[i] = injectedArgument;\n            } catch (BeansException ex) {\n                throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(parameter), ex);\n            }\n        }\n        registerDependentBeans(beanFactory, beanName, autowiredBeanNames);\n        return AutowiredArguments.of(arguments);\n    }\n\n    private Method getMethod(RegisteredBean registeredBean) {\n        Method method = ReflectionUtils.findMethod(registeredBean.getBeanClass(), this.methodName, this.parameterTypes);\n        Assert.notNull(\n                method,\n                () -> \"Method '\" + this.methodName + \"' with parameter types [\"\n                        + toCommaSeparatedNames(this.parameterTypes) + \"] declared on \"\n                        + registeredBean.getBeanClass().getName() + \" could not be found.\");\n        return method;\n    }\n\n    private String toCommaSeparatedNames(Class<?>... parameterTypes) {\n        return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(\", \"));\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/main/java/org/apache/dubbo/config/spring6/context/DubboInfraBeanRegisterPostProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.context;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\n\n/**\n * Register some infrastructure beans if not exists.\n * This post-processor MUST impl BeanDefinitionRegistryPostProcessor,\n * in order to enable the registered BeanFactoryPostProcessor bean to be loaded and executed.\n *\n * @see org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(\n *ConfigurableListableBeanFactory, java.util.List)\n */\npublic class DubboInfraBeanRegisterPostProcessor implements BeanDefinitionRegistryPostProcessor {\n\n    @Override\n    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {}\n\n    @Override\n    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/main/java/org/apache/dubbo/config/spring6/utils/AotUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\nimport org.apache.dubbo.common.compiler.support.ClassUtils;\n\nimport java.io.Serializable;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeReference;\n\npublic class AotUtils {\n\n    private AotUtils() {}\n\n    public static void registerSerializationForService(Class<?> serviceType, RuntimeHints hints) {\n        Set<Class<?>> serializationTypeCache = new LinkedHashSet<>();\n        Arrays.stream(serviceType.getMethods()).forEach((method) -> {\n            Arrays.stream(method.getParameterTypes())\n                    .forEach(\n                            (parameterType) -> registerSerializationType(parameterType, hints, serializationTypeCache));\n\n            registerSerializationType(method.getReturnType(), hints, serializationTypeCache);\n        });\n    }\n\n    private static void registerSerializationType(\n            Class<?> registerType, RuntimeHints hints, Set<Class<?>> serializationTypeCache) {\n        if (isPrimitive(registerType)) {\n            hints.serialization().registerType(TypeReference.of(ClassUtils.getBoxedClass(registerType)));\n            serializationTypeCache.add(registerType);\n        } else {\n            if (Serializable.class.isAssignableFrom(registerType)) {\n                hints.serialization().registerType(TypeReference.of(registerType));\n                serializationTypeCache.add(registerType);\n\n                Arrays.stream(registerType.getDeclaredFields()).forEach((field -> {\n                    if (!serializationTypeCache.contains(field.getType())) {\n                        registerSerializationType(field.getType(), hints, serializationTypeCache);\n                        serializationTypeCache.add(field.getType());\n                    }\n                }));\n\n                if (registerType.getSuperclass() != null) {\n                    registerSerializationType(registerType.getSuperclass(), hints, serializationTypeCache);\n                }\n            }\n        }\n    }\n\n    private static boolean isPrimitive(Class<?> cls) {\n        return cls.isPrimitive()\n                || cls == Boolean.class\n                || cls == Byte.class\n                || cls == Character.class\n                || cls == Short.class\n                || cls == Integer.class\n                || cls == Long.class\n                || cls == Float.class\n                || cls == Double.class\n                || cls == String.class\n                || cls == Date.class\n                || cls == Class.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/test/java/org/apache/dubbo/config/spring6/utils/AotUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.aot.hint.RuntimeHints;\n\npublic class AotUtilsTest {\n\n    @Test\n    void registerSerializationForServiceTest() {\n\n        RuntimeHints runtimeHints = new RuntimeHints();\n        AotUtils.registerSerializationForService(DemoService.class, runtimeHints);\n\n        AtomicBoolean containHelloRequest = new AtomicBoolean(false);\n        runtimeHints.serialization().javaSerializationHints().forEach(s -> {\n            if (s.getType().getName().equals(HelloRequest.class.getName())) {\n                containHelloRequest.set(true);\n            }\n        });\n\n        AtomicBoolean containPerson = new AtomicBoolean(false);\n        runtimeHints.serialization().javaSerializationHints().forEach(s -> {\n            if (s.getType().getName().equals(HelloRequest.class.getName())) {\n                containPerson.set(true);\n            }\n        });\n\n        AtomicBoolean containString = new AtomicBoolean(false);\n        runtimeHints.serialization().javaSerializationHints().forEach(s -> {\n            if (s.getType().getName().equals(HelloRequest.class.getName())) {\n                containString.set(true);\n            }\n        });\n\n        AtomicBoolean containHelloRequestSuper = new AtomicBoolean(false);\n        runtimeHints.serialization().javaSerializationHints().forEach(s -> {\n            if (s.getType().getName().equals(HelloRequest.class.getName())) {\n                containHelloRequestSuper.set(true);\n            }\n        });\n\n        AtomicBoolean containHelloResponse = new AtomicBoolean(false);\n        runtimeHints.serialization().javaSerializationHints().forEach(s -> {\n            if (s.getType().getName().equals(HelloRequest.class.getName())) {\n                containHelloResponse.set(true);\n            }\n        });\n\n        Assertions.assertTrue(containHelloRequest.get());\n        Assertions.assertTrue(containPerson.get());\n        Assertions.assertTrue(containString.get());\n        Assertions.assertTrue(containHelloRequestSuper.get());\n        Assertions.assertTrue(containHelloResponse.get());\n    }\n\n    @Test\n    void registerSerializationForCircularDependencyFieldTest() {\n        RuntimeHints runtimeHints = new RuntimeHints();\n        AotUtils.registerSerializationForService(CircularDependencyDemoService.class, runtimeHints);\n        AtomicBoolean containDemoA = new AtomicBoolean(false);\n        runtimeHints.serialization().javaSerializationHints().forEach(s -> {\n            if (s.getType().getName().equals(DemoA.class.getName())) {\n                containDemoA.set(true);\n            }\n        });\n        AtomicBoolean containDemoB = new AtomicBoolean(false);\n        runtimeHints.serialization().javaSerializationHints().forEach(s -> {\n            if (s.getType().getName().equals(DemoB.class.getName())) {\n                containDemoB.set(true);\n            }\n        });\n\n        Assertions.assertTrue(containDemoA.get());\n        Assertions.assertTrue(containDemoB.get());\n\n        AotUtils.registerSerializationForService(DemoService.class, runtimeHints);\n        AtomicBoolean containSexEnum = new AtomicBoolean(false);\n        runtimeHints.serialization().javaSerializationHints().forEach(s -> {\n            if (s.getType().getName().equals(SexEnum.class.getName())) {\n                containSexEnum.set(true);\n            }\n        });\n        Assertions.assertTrue(containSexEnum.get());\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/test/java/org/apache/dubbo/config/spring6/utils/CircularDependencyDemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\npublic interface CircularDependencyDemoService {\n    String sayHello(DemoA a);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/test/java/org/apache/dubbo/config/spring6/utils/DemoA.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\nimport java.io.Serializable;\n\npublic class DemoA implements Serializable {\n    private DemoB b;\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/test/java/org/apache/dubbo/config/spring6/utils/DemoB.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\nimport java.io.Serializable;\n\npublic class DemoB implements Serializable {\n    private DemoA a;\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/test/java/org/apache/dubbo/config/spring6/utils/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\npublic interface DemoService {\n\n    HelloResponse sayHello(HelloRequest request);\n\n    String sayHelloForSerializable(java.io.Serializable name);\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/test/java/org/apache/dubbo/config/spring6/utils/HelloRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\nimport java.io.Serializable;\n\npublic class HelloRequest extends HelloRequestSuper implements Serializable {\n    private Person person;\n\n    public HelloRequest(Person person) {\n        this.person = person;\n    }\n\n    public Person getPerson() {\n        return person;\n    }\n\n    public void setPerson(Person person) {\n        this.person = person;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/test/java/org/apache/dubbo/config/spring6/utils/HelloRequestSuper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\nimport java.io.Serializable;\n\npublic class HelloRequestSuper implements Serializable {\n    private String su;\n\n    public HelloRequestSuper() {}\n\n    public HelloRequestSuper(String su) {\n        this.su = su;\n    }\n\n    public String getSu() {\n        return su;\n    }\n\n    public void setSu(String su) {\n        this.su = su;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/test/java/org/apache/dubbo/config/spring6/utils/HelloResponse.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\nimport java.io.Serializable;\n\npublic class HelloResponse implements Serializable {\n    private String response;\n\n    public HelloResponse(String response) {\n        this.response = response;\n    }\n\n    public String getResponse() {\n        return response;\n    }\n\n    public void setResponse(String response) {\n        this.response = response;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/test/java/org/apache/dubbo/config/spring6/utils/Person.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\nimport java.io.Serializable;\n\npublic class Person implements Serializable {\n\n    private String name;\n\n    private SexEnum sex;\n\n    public Person(String name, SexEnum sex) {\n        this.name = name;\n        this.sex = sex;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public SexEnum getSex() {\n        return sex;\n    }\n\n    public void setSex(SexEnum sex) {\n        this.sex = sex;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/dubbo-config-spring6/src/test/java/org/apache/dubbo/config/spring6/utils/SexEnum.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.config.spring6.utils;\n\npublic enum SexEnum {\n    BOY(\"boy\"),\n    GIRL(\"girl\");\n\n    private final String desc;\n\n    SexEnum(String desc) {\n        this.desc = desc;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n}\n"
  },
  {
    "path": "dubbo-config/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n  </parent>\n  <artifactId>dubbo-config</artifactId>\n  <packaging>pom</packaging>\n  <name>${project.artifactId}</name>\n  <description>The config module of dubbo project</description>\n  <modules>\n    <module>dubbo-config-api</module>\n    <module>dubbo-config-spring</module>\n  </modules>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-test-check</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-test-common</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <profiles>\n    <profile>\n      <id>spring6</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <modules>\n        <module>dubbo-config-spring6</module>\n      </modules>\n    </profile>\n    <profile>\n      <id>release</id>\n      <modules>\n        <module>dubbo-config-spring6</module>\n      </modules>\n    </profile>\n    <profile>\n      <id>jdk-version-ge-17</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <modules>\n        <module>dubbo-config-spring6</module>\n      </modules>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-apollo/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-configcenter</artifactId>\n    <version>${revision}</version>\n  </parent>\n\n  <artifactId>dubbo-configcenter-apollo</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The Apollo implementation of the configcenter api</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n    <apollo_mock_server_version>2.5.0</apollo_mock_server_version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-prometheus</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>com.ctrip.framework.apollo</groupId>\n      <artifactId>apollo-client</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.ctrip.framework.apollo</groupId>\n      <artifactId>apollo-mockserver</artifactId>\n      <version>${apollo_mock_server_version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-config-center</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.apollo;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.metrics.config.event.ConfigCenterEvent;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.stream.Collectors;\n\nimport com.ctrip.framework.apollo.Config;\nimport com.ctrip.framework.apollo.ConfigChangeListener;\nimport com.ctrip.framework.apollo.ConfigFile;\nimport com.ctrip.framework.apollo.ConfigService;\nimport com.ctrip.framework.apollo.core.enums.ConfigFileFormat;\nimport com.ctrip.framework.apollo.enums.ConfigSourceType;\nimport com.ctrip.framework.apollo.enums.PropertyChangeType;\nimport com.ctrip.framework.apollo.model.ConfigChange;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONFIG_NAMESPACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ThirdPartyProperty.APOLLO_ADDR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ThirdPartyProperty.APOLLO_APPID_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ThirdPartyProperty.APOLLO_CLUSTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ThirdPartyProperty.APOLLO_ENV_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_CLOSE_CONNECT_APOLLO;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_CONNECT_REGISTRY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_NOT_EFFECT_EMPTY_RULE_APOLLO;\nimport static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE;\n\n/**\n * Apollo implementation, https://github.com/ctripcorp/apollo\n * <p>\n * Apollo will be used for management of both governance rules and .properties files, by default, these two different\n * kinds of data share the same namespace 'dubbo'. To gain better performance, we recommend separate them by giving\n * namespace and group different values, for example:\n * <p>\n * <dubbo:config-center namespace=\"governance\" group=\"dubbo\" />, 'dubbo=governance' is for governance rules while\n * 'group=dubbo' is for properties files.\n * <p>\n * Please see http://dubbo.apache.org/zh-cn/docs/user/configuration/config-center.html for details.\n */\npublic class ApolloDynamicConfiguration implements DynamicConfiguration {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ApolloDynamicConfiguration.class);\n    private static final String APOLLO_PROTOCOL_PREFIX = \"http://\";\n    private static final String APOLLO_APPLICATION_KEY = \"application\";\n\n    private final URL url;\n    private final Config dubboConfig;\n    private final ConfigFile dubboConfigFile;\n    private final ConcurrentMap<String, ApolloListener> listeners = new ConcurrentHashMap<>();\n    private final ApplicationModel applicationModel;\n\n    ApolloDynamicConfiguration(URL url, ApplicationModel applicationModel) {\n        this.url = url;\n        this.applicationModel = applicationModel;\n        // Instead of using Dubbo's configuration, I would suggest use the original configuration method Apollo\n        // provides.\n        String configEnv = url.getParameter(APOLLO_ENV_KEY);\n        String configAddr = getAddressWithProtocolPrefix(url);\n        String configCluster = url.getParameter(CLUSTER_KEY);\n        String configAppId = url.getParameter(APOLLO_APPID_KEY);\n        if (StringUtils.isEmpty(SystemPropertyConfigUtils.getSystemProperty(APOLLO_ENV_KEY)) && configEnv != null) {\n            SystemPropertyConfigUtils.getSystemProperty(APOLLO_ENV_KEY, configEnv);\n        }\n        if (StringUtils.isEmpty(SystemPropertyConfigUtils.getSystemProperty(APOLLO_ADDR_KEY))\n                && !ANYHOST_VALUE.equals(url.getHost())) {\n            SystemPropertyConfigUtils.setSystemProperty(APOLLO_ADDR_KEY, configAddr);\n        }\n        if (StringUtils.isEmpty(SystemPropertyConfigUtils.getSystemProperty(APOLLO_CLUSTER_KEY))\n                && configCluster != null) {\n            SystemPropertyConfigUtils.getSystemProperty(APOLLO_CLUSTER_KEY, configCluster);\n        }\n        if (StringUtils.isEmpty(SystemPropertyConfigUtils.getSystemProperty(APOLLO_APPID_KEY)) && configAppId != null) {\n            SystemPropertyConfigUtils.getSystemProperty(APOLLO_APPID_KEY, configAppId);\n        }\n\n        String namespace = url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP);\n        String apolloNamespace = StringUtils.isEmpty(namespace) ? url.getGroup(DEFAULT_GROUP) : namespace;\n        dubboConfig = ConfigService.getConfig(apolloNamespace);\n        dubboConfigFile = ConfigService.getConfigFile(apolloNamespace, ConfigFileFormat.Properties);\n\n        // Decide to fail or to continue when failed to connect to remote server.\n        boolean check = url.getParameter(CHECK_KEY, true);\n        if (dubboConfig.getSourceType() != ConfigSourceType.REMOTE) {\n            if (check) {\n                throw new IllegalStateException(\"Failed to connect to config center, the config center is Apollo, \"\n                        + \"the address is: \" + (StringUtils.isNotEmpty(configAddr) ? configAddr : configEnv));\n            } else {\n                // 5-1 Failed to connect to configuration center.\n\n                logger.warn(\n                        CONFIG_FAILED_CONNECT_REGISTRY,\n                        \"configuration server offline\",\n                        \"\",\n                        \"Failed to connect to config center, the config center is Apollo, \" + \"the address is: \"\n                                + (StringUtils.isNotEmpty(configAddr) ? configAddr : configEnv)\n                                + \", will use the local cache value instead before eventually the connection is established.\");\n            }\n        }\n    }\n\n    @Override\n    public void close() {\n        try {\n            listeners.clear();\n        } catch (UnsupportedOperationException e) {\n            logger.warn(\n                    CONFIG_FAILED_CLOSE_CONNECT_APOLLO,\n                    \"\",\n                    \"\",\n                    \"Failed to close connect from config center, the config center is Apollo\");\n        }\n    }\n\n    private String getAddressWithProtocolPrefix(URL url) {\n        String address = url.getBackupAddress();\n        if (StringUtils.isNotEmpty(address)) {\n            address = Arrays.stream(COMMA_SPLIT_PATTERN.split(address))\n                    .map(addr -> {\n                        if (addr.startsWith(APOLLO_PROTOCOL_PREFIX)) {\n                            return addr;\n                        }\n                        return APOLLO_PROTOCOL_PREFIX + addr;\n                    })\n                    .collect(Collectors.joining(\",\"));\n        }\n        return address;\n    }\n\n    /**\n     * Since all governance rules will lay under dubbo group, this method now always uses the default dubboConfig and\n     * ignores the group parameter.\n     */\n    @Override\n    public void addListener(String key, String group, ConfigurationListener listener) {\n        ApolloListener apolloListener =\n                ConcurrentHashMapUtils.computeIfAbsent(listeners, group + key, k -> createTargetListener(key, group));\n        apolloListener.addListener(listener);\n        dubboConfig.addChangeListener(apolloListener, Collections.singleton(key));\n    }\n\n    @Override\n    public void removeListener(String key, String group, ConfigurationListener listener) {\n        ApolloListener apolloListener = listeners.get(group + key);\n        if (apolloListener != null) {\n            apolloListener.removeListener(listener);\n            if (!apolloListener.hasInternalListener()) {\n                dubboConfig.removeChangeListener(apolloListener);\n            }\n        }\n    }\n\n    @Override\n    public String getConfig(String key, String group, long timeout) throws IllegalStateException {\n        if (StringUtils.isNotEmpty(group)) {\n            if (group.equals(url.getApplication())) {\n                return ConfigService.getAppConfig().getProperty(key, null);\n            } else {\n                return ConfigService.getConfig(group).getProperty(key, null);\n            }\n        }\n        return dubboConfig.getProperty(key, null);\n    }\n\n    /**\n     * Recommend specify namespace and group when using Apollo.\n     * <p>\n     * <dubbo:config-center namespace=\"governance\" group=\"dubbo\" />, 'dubbo=governance' is for governance rules while\n     * 'group=dubbo' is for properties files.\n     *\n     * @param key     default value is 'dubbo.properties', currently useless for Apollo.\n     * @param group\n     * @param timeout\n     * @return\n     * @throws IllegalStateException\n     */\n    @Override\n    public String getProperties(String key, String group, long timeout) throws IllegalStateException {\n        if (StringUtils.isEmpty(group)) {\n            return dubboConfigFile.getContent();\n        }\n        if (group.equals(url.getApplication())) {\n            return ConfigService.getConfigFile(APOLLO_APPLICATION_KEY, ConfigFileFormat.Properties)\n                    .getContent();\n        }\n\n        ConfigFile configFile = ConfigService.getConfigFile(group, ConfigFileFormat.Properties);\n        if (configFile == null) {\n            throw new IllegalStateException(\"There is no namespace named \" + group + \" in Apollo.\");\n        }\n        return configFile.getContent();\n    }\n\n    /**\n     * This method will be used by Configuration to get valid value at runtime.\n     * The group is expected to be 'app level', which can be fetched from the 'config.appnamespace' in url if necessary.\n     * But I think Apollo's inheritance feature of namespace can solve the problem .\n     */\n    @Override\n    public String getInternalProperty(String key) {\n        return dubboConfig.getProperty(key, null);\n    }\n\n    /**\n     * Ignores the group parameter.\n     *\n     * @param key   property key the native listener will listen on\n     * @param group to distinguish different set of properties\n     * @return\n     */\n    private ApolloListener createTargetListener(String key, String group) {\n        return new ApolloListener();\n    }\n\n    public class ApolloListener implements ConfigChangeListener {\n\n        private Set<ConfigurationListener> listeners = new CopyOnWriteArraySet<>();\n\n        ApolloListener() {}\n\n        @Override\n        public void onChange(com.ctrip.framework.apollo.model.ConfigChangeEvent changeEvent) {\n            for (String key : changeEvent.changedKeys()) {\n                ConfigChange change = changeEvent.getChange(key);\n                if (\"\".equals(change.getNewValue())) {\n                    logger.warn(\n                            CONFIG_NOT_EFFECT_EMPTY_RULE_APOLLO,\n                            \"\",\n                            \"\",\n                            \"an empty rule is received for \" + key + \", the current working rule is \"\n                                    + change.getOldValue() + \", the empty rule will not take effect.\");\n                    return;\n                }\n\n                ConfigChangedEvent event =\n                        new ConfigChangedEvent(key, change.getNamespace(), change.getNewValue(), getChangeType(change));\n                listeners.forEach(listener -> listener.process(event));\n\n                MetricsEventBus.publish(ConfigCenterEvent.toChangeEvent(\n                        applicationModel,\n                        event.getKey(),\n                        event.getGroup(),\n                        ConfigCenterEvent.APOLLO_PROTOCOL,\n                        ConfigChangeType.ADDED.name(),\n                        SELF_INCREMENT_SIZE));\n            }\n        }\n\n        private ConfigChangeType getChangeType(ConfigChange change) {\n            if (change.getChangeType() == PropertyChangeType.DELETED) {\n                return ConfigChangeType.DELETED;\n            }\n            return ConfigChangeType.MODIFIED;\n        }\n\n        void addListener(ConfigurationListener configurationListener) {\n            this.listeners.add(configurationListener);\n        }\n\n        void removeListener(ConfigurationListener configurationListener) {\n            this.listeners.remove(configurationListener);\n        }\n\n        boolean hasInternalListener() {\n            return listeners != null && listeners.size() > 0;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfigurationFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.apollo;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\npublic class ApolloDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory {\n\n    private ApplicationModel applicationModel;\n\n    public ApolloDynamicConfigurationFactory(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    @Override\n    protected DynamicConfiguration createDynamicConfiguration(URL url) {\n        return new ApolloDynamicConfiguration(url, applicationModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-apollo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory",
    "content": "apollo=org.apache.dubbo.configcenter.support.apollo.ApolloDynamicConfigurationFactory"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-apollo/src/test/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.apollo;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.Properties;\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\n\nimport com.google.common.util.concurrent.SettableFuture;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.RegisterExtension;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.fail;\n\n/**\n * Apollo dynamic configuration mock test.\n * Notice: EmbeddedApollo(apollo mock server) only support < junit5, please not upgrade the junit version in this UT,\n * the junit version in this UT is junit4, and the dependency comes from apollo-mockserver.\n */\nclass ApolloDynamicConfigurationTest {\n    private static final String SESSION_TIMEOUT_KEY = \"session\";\n    private static final String DEFAULT_NAMESPACE = \"dubbo\";\n    private static ApolloDynamicConfiguration apolloDynamicConfiguration;\n    private static URL url;\n    private static ApplicationModel applicationModel;\n\n    /**\n     * The constant embeddedApollo.\n     */\n    @RegisterExtension\n    public static EmbeddedApolloJunit5 embeddedApollo = new EmbeddedApolloJunit5();\n\n    /**\n     * Sets up.\n     */\n    @BeforeEach\n    public void setUp() {\n        FrameworkModel.destroyAll();\n        String apolloUrl = System.getProperty(\"apollo.configService\");\n        String urlForDubbo = \"apollo://\" + apolloUrl.substring(apolloUrl.lastIndexOf(\"/\") + 1)\n                + \"/org.apache.dubbo.apollo.testService?namespace=dubbo&check=true\";\n        url = URL.valueOf(urlForDubbo).addParameter(SESSION_TIMEOUT_KEY, 15000);\n        applicationModel = ApplicationModel.defaultModel();\n    }\n\n    //    /**\n    //     * Embedded Apollo does not work as expected.\n    //     */\n    //    @Test\n    //    public void testProperties() {\n    //        URL url = this.url.addParameter(GROUP_KEY, \"dubbo\")\n    //                .addParameter(\"namespace\", \"governance\");\n    //\n    //        apolloDynamicConfiguration = new ApolloDynamicConfiguration(url);\n    //        putData(\"dubbo\", \"dubbo.registry.address\", \"zookeeper://127.0.0.1:2181\");\n    //        assertEquals(\"zookeeper://127.0.0.1:2181\", apolloDynamicConfiguration.getProperties(null, \"dubbo\"));\n    //\n    //        putData(\"governance\", \"router.tag\", \"router tag rule\");\n    //        assertEquals(\"router tag rule\", apolloDynamicConfiguration.getConfig(\"router.tag\", \"governance\"));\n    //\n    //    }\n\n    /**\n     * Test get rule.\n     */\n    @Test\n    void testGetRule() {\n        String mockKey = \"mockKey1\";\n        String mockValue = String.valueOf(new Random().nextInt());\n        putMockRuleData(mockKey, mockValue, DEFAULT_NAMESPACE);\n        apolloDynamicConfiguration = new ApolloDynamicConfiguration(url, applicationModel);\n        assertEquals(mockValue, apolloDynamicConfiguration.getConfig(mockKey, DEFAULT_NAMESPACE, 3000L));\n\n        mockKey = \"notExistKey\";\n        assertNull(apolloDynamicConfiguration.getConfig(mockKey, DEFAULT_NAMESPACE, 3000L));\n    }\n\n    /**\n     * Test get internal property.\n     *\n     * @throws InterruptedException the interrupted exception\n     */\n    @Test\n    void testGetInternalProperty() throws InterruptedException {\n        String mockKey = \"mockKey2\";\n        String mockValue = String.valueOf(new Random().nextInt());\n        putMockRuleData(mockKey, mockValue, DEFAULT_NAMESPACE);\n        TimeUnit.MILLISECONDS.sleep(1000);\n        apolloDynamicConfiguration = new ApolloDynamicConfiguration(url, applicationModel);\n        assertEquals(mockValue, apolloDynamicConfiguration.getInternalProperty(mockKey));\n\n        mockValue = \"mockValue2\";\n        System.setProperty(mockKey, mockValue);\n        assertEquals(mockValue, apolloDynamicConfiguration.getInternalProperty(mockKey));\n\n        mockKey = \"notExistKey\";\n        assertNull(apolloDynamicConfiguration.getInternalProperty(mockKey));\n    }\n\n    /**\n     * Test add listener.\n     *\n     * @throws Exception the exception\n     */\n    @Test\n    void testAddListener() throws Exception {\n        String mockKey = \"mockKey3\";\n        String mockValue = String.valueOf(new Random().nextInt());\n\n        final SettableFuture<org.apache.dubbo.common.config.configcenter.ConfigChangedEvent> future =\n                SettableFuture.create();\n\n        apolloDynamicConfiguration = new ApolloDynamicConfiguration(url, applicationModel);\n\n        apolloDynamicConfiguration.addListener(mockKey, DEFAULT_NAMESPACE, new ConfigurationListener() {\n            @Override\n            public void process(org.apache.dubbo.common.config.configcenter.ConfigChangedEvent event) {\n                future.set(event);\n            }\n        });\n\n        putData(mockKey, mockValue);\n        org.apache.dubbo.common.config.configcenter.ConfigChangedEvent result = future.get(3000, TimeUnit.MILLISECONDS);\n        assertEquals(mockValue, result.getContent());\n        assertEquals(mockKey, result.getKey());\n        assertEquals(ConfigChangeType.MODIFIED, result.getChangeType());\n    }\n\n    private static void putData(String namespace, String key, String value) {\n        embeddedApollo.addOrModifyProperty(namespace, key, value);\n    }\n\n    private static void putData(String key, String value) {\n        embeddedApollo.addOrModifyProperty(DEFAULT_NAMESPACE, key, value);\n    }\n\n    private static void putMockRuleData(String key, String value, String group) {\n        String fileName =\n                ApolloDynamicConfigurationTest.class.getResource(\"/\").getPath() + \"mockdata-\" + group + \".properties\";\n        putMockData(key, value, fileName);\n    }\n\n    private static void putMockData(String key, String value, String fileName) {\n        Properties pro = new Properties();\n        FileOutputStream oFile = null;\n        try {\n            oFile = new FileOutputStream(fileName);\n            pro.setProperty(key, value);\n            pro.store(oFile, \"put mock data\");\n        } catch (IOException exx) {\n            fail(exx.getMessage());\n\n        } finally {\n            if (null != oFile) {\n                try {\n                    oFile.close();\n                } catch (IOException e) {\n                    fail(e.getMessage());\n                }\n            }\n        }\n    }\n\n    /**\n     * Tear down.\n     */\n    @AfterEach\n    public void tearDown() {}\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-apollo/src/test/java/org/apache/dubbo/configcenter/support/apollo/EmbeddedApolloJunit5.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.apollo;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.JsonUtils;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport com.ctrip.framework.apollo.build.ApolloInjector;\nimport com.ctrip.framework.apollo.core.dto.ApolloConfig;\nimport com.ctrip.framework.apollo.core.dto.ApolloConfigNotification;\nimport com.ctrip.framework.apollo.core.utils.ResourceUtils;\nimport com.ctrip.framework.apollo.internals.ConfigServiceLocator;\nimport com.google.common.collect.Maps;\nimport com.google.common.collect.Sets;\nimport okhttp3.mockwebserver.Dispatcher;\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport okhttp3.mockwebserver.RecordedRequest;\nimport org.junit.jupiter.api.extension.AfterAllCallback;\nimport org.junit.jupiter.api.extension.BeforeAllCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_CLOSE_CONNECT_APOLLO;\n\npublic class EmbeddedApolloJunit5 implements BeforeAllCallback, AfterAllCallback {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(EmbeddedApolloJunit5.class);\n\n    private static Method CONFIG_SERVICE_LOCATOR_CLEAR;\n    private static ConfigServiceLocator CONFIG_SERVICE_LOCATOR;\n\n    private final Map<String, Map<String, String>> addedOrModifiedPropertiesOfNamespace = Maps.newConcurrentMap();\n    private final Map<String, Set<String>> deletedKeysOfNamespace = Maps.newConcurrentMap();\n\n    private MockWebServer server;\n\n    static {\n        try {\n            System.setProperty(\"apollo.longPollingInitialDelayInMills\", \"0\");\n            CONFIG_SERVICE_LOCATOR = ApolloInjector.getInstance(ConfigServiceLocator.class);\n            CONFIG_SERVICE_LOCATOR_CLEAR = ConfigServiceLocator.class.getDeclaredMethod(\"initConfigServices\");\n            CONFIG_SERVICE_LOCATOR_CLEAR.setAccessible(true);\n        } catch (NoSuchMethodException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void clear() throws Exception {\n        resetOverriddenProperties();\n    }\n\n    private void mockConfigServiceUrl(String url) throws Exception {\n        System.setProperty(\"apollo.configService\", url);\n\n        CONFIG_SERVICE_LOCATOR_CLEAR.invoke(CONFIG_SERVICE_LOCATOR);\n    }\n\n    private String loadConfigFor(String namespace) {\n        String filename = String.format(\"mockdata-%s.properties\", namespace);\n        final Properties prop = ResourceUtils.readConfigFile(filename, new Properties());\n        Map<String, String> configurations = Maps.newHashMap();\n        for (String propertyName : prop.stringPropertyNames()) {\n            configurations.put(propertyName, prop.getProperty(propertyName));\n        }\n        ApolloConfig apolloConfig = new ApolloConfig(\"someAppId\", \"someCluster\", namespace, \"someReleaseKey\");\n\n        Map<String, String> mergedConfigurations = mergeOverriddenProperties(namespace, configurations);\n        apolloConfig.setConfigurations(mergedConfigurations);\n        return JsonUtils.toJson(apolloConfig);\n    }\n\n    private String mockLongPollBody(String notificationsStr) {\n        List<ApolloConfigNotification> oldNotifications =\n                JsonUtils.toJavaList(notificationsStr, ApolloConfigNotification.class);\n        List<ApolloConfigNotification> newNotifications = new ArrayList<>();\n        for (ApolloConfigNotification notification : oldNotifications) {\n            newNotifications.add(new ApolloConfigNotification(\n                    notification.getNamespaceName(), notification.getNotificationId() + 1));\n        }\n        return JsonUtils.toJson(newNotifications);\n    }\n\n    /**\n     * Incorporate user modifications to namespace\n     */\n    private Map<String, String> mergeOverriddenProperties(String namespace, Map<String, String> configurations) {\n        if (addedOrModifiedPropertiesOfNamespace.containsKey(namespace)) {\n            configurations.putAll(addedOrModifiedPropertiesOfNamespace.get(namespace));\n        }\n        if (deletedKeysOfNamespace.containsKey(namespace)) {\n            for (String k : deletedKeysOfNamespace.get(namespace)) {\n                configurations.remove(k);\n            }\n        }\n        return configurations;\n    }\n\n    /**\n     * Add new property or update existed property\n     */\n    public void addOrModifyProperty(String namespace, String someKey, String someValue) {\n        if (addedOrModifiedPropertiesOfNamespace.containsKey(namespace)) {\n            addedOrModifiedPropertiesOfNamespace.get(namespace).put(someKey, someValue);\n        } else {\n            Map<String, String> m = Maps.newConcurrentMap();\n            m.put(someKey, someValue);\n            addedOrModifiedPropertiesOfNamespace.put(namespace, m);\n        }\n    }\n\n    /**\n     * Delete existed property\n     */\n    public void deleteProperty(String namespace, String someKey) {\n        if (deletedKeysOfNamespace.containsKey(namespace)) {\n            deletedKeysOfNamespace.get(namespace).add(someKey);\n        } else {\n            Set<String> m = Sets.newConcurrentHashSet();\n            m.add(someKey);\n            deletedKeysOfNamespace.put(namespace, m);\n        }\n    }\n\n    /**\n     * reset overridden properties\n     */\n    public void resetOverriddenProperties() {\n        addedOrModifiedPropertiesOfNamespace.clear();\n        deletedKeysOfNamespace.clear();\n    }\n\n    @Override\n    public void afterAll(ExtensionContext extensionContext) throws Exception {\n        try {\n            clear();\n            server.close();\n        } catch (Exception e) {\n            logger.error(CONFIG_FAILED_CLOSE_CONNECT_APOLLO, \"\", \"\", \"stop apollo server error\", e);\n        }\n    }\n\n    @Override\n    public void beforeAll(ExtensionContext extensionContext) throws Exception {\n        clear();\n        server = new MockWebServer();\n        final Dispatcher dispatcher = new Dispatcher() {\n            @Override\n            public MockResponse dispatch(RecordedRequest request) throws InterruptedException {\n                if (request.getPath().startsWith(\"/notifications/v2\")) {\n                    String notifications = request.getRequestUrl().queryParameter(\"notifications\");\n                    return new MockResponse().setResponseCode(200).setBody(mockLongPollBody(notifications));\n                }\n                if (request.getPath().startsWith(\"/configs\")) {\n                    List<String> pathSegments = request.getRequestUrl().pathSegments();\n                    // appId and cluster might be used in the future\n                    String appId = pathSegments.get(1);\n                    String cluster = pathSegments.get(2);\n                    String namespace = pathSegments.get(3);\n                    return new MockResponse().setResponseCode(200).setBody(loadConfigFor(namespace));\n                }\n                return new MockResponse().setResponseCode(404);\n            }\n        };\n\n        server.setDispatcher(dispatcher);\n        server.start();\n\n        mockConfigServiceUrl(\"http://localhost:\" + server.getPort());\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-apollo/src/test/resources/META-INF/app.properties",
    "content": "app.id=someAppId\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-apollo/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-apollo/src/test/resources/mockdata-dubbo.properties",
    "content": "key1=value1\nkey2=value2\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-file/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-configcenter</artifactId>\n    <version>${revision}</version>\n  </parent>\n\n  <artifactId>dubbo-configcenter-file</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The File implementation of the configcenter api</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-prometheus</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-config-center</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-file/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter.file;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.config.configcenter.TreePathDynamicConfiguration;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.function.ThrowableConsumer;\nimport org.apache.dubbo.common.function.ThrowableFunction;\nimport org.apache.dubbo.common.lang.ShutdownHookCallbacks;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Path;\nimport java.nio.file.WatchEvent;\nimport java.nio.file.WatchKey;\nimport java.nio.file.WatchService;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.apache.commons.io.FileUtils;\n\nimport static java.lang.String.format;\nimport static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;\nimport static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;\nimport static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;\nimport static java.util.Collections.emptySet;\nimport static java.util.Collections.unmodifiableMap;\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport static org.apache.commons.io.FileUtils.readFileToString;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_ERROR_PROCESS_LISTENER;\n\n/**\n * File-System based {@link DynamicConfiguration} implementation\n *\n * @since 2.7.5\n */\npublic class FileSystemDynamicConfiguration extends TreePathDynamicConfiguration {\n\n    public static final String CONFIG_CENTER_DIR_PARAM_NAME = PARAM_NAME_PREFIX + \"dir\";\n\n    public static final String CONFIG_CENTER_ENCODING_PARAM_NAME = PARAM_NAME_PREFIX + \"encoding\";\n\n    public static final String DEFAULT_CONFIG_CENTER_DIR_PATH =\n            SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.USER_HOME) + File.separator\n                    + \".dubbo\" + File.separator + \"config-center\";\n\n    public static final int DEFAULT_THREAD_POOL_SIZE = 1;\n\n    public static final String DEFAULT_CONFIG_CENTER_ENCODING = \"UTF-8\";\n\n    private static final WatchEvent.Kind[] INTEREST_PATH_KINDS = of(ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);\n\n    /**\n     * The class name of {@linkplain sun.nio.fs.PollingWatchService}\n     */\n    private static final String POLLING_WATCH_SERVICE_CLASS_NAME = \"sun.nio.fs.PollingWatchService\";\n\n    private static final int THREAD_POOL_SIZE = 1;\n\n    /**\n     * Logger\n     */\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(FileSystemDynamicConfiguration.class);\n\n    /**\n     * The unmodifiable map for {@link ConfigChangeType} whose key is the {@link WatchEvent.Kind#name() name} of\n     * {@link WatchEvent.Kind WatchEvent's Kind}\n     */\n    private static final Map<String, ConfigChangeType> CONFIG_CHANGE_TYPES_MAP =\n            unmodifiableMap(new HashMap<String, ConfigChangeType>() {\n                // Initializes the elements that is mapping ConfigChangeType\n                {\n                    put(ENTRY_CREATE.name(), ConfigChangeType.ADDED);\n                    put(ENTRY_DELETE.name(), ConfigChangeType.DELETED);\n                    put(ENTRY_MODIFY.name(), ConfigChangeType.MODIFIED);\n                }\n            });\n\n    private static final Optional<WatchService> watchService;\n\n    /**\n     * Is Pooling Based Watch Service\n     *\n     * @see #detectPoolingBasedWatchService(Optional)\n     */\n    private static final boolean BASED_POOLING_WATCH_SERVICE;\n\n    private static final WatchEvent.Modifier[] MODIFIERS;\n\n    /**\n     * the delay to action in seconds. If null, execute indirectly\n     */\n    private static final Integer DELAY;\n\n    /**\n     * The thread pool for {@link WatchEvent WatchEvents} loop\n     * It's optional if there is not any {@link ConfigurationListener} registration\n     *\n     * @see ThreadPoolExecutor\n     */\n    private static final ThreadPoolExecutor WATCH_EVENTS_LOOP_THREAD_POOL;\n\n    // static initialization\n    static {\n        watchService = newWatchService();\n        BASED_POOLING_WATCH_SERVICE = detectPoolingBasedWatchService(watchService);\n        MODIFIERS = initWatchEventModifiers();\n        DELAY = initDelay(MODIFIERS);\n        WATCH_EVENTS_LOOP_THREAD_POOL = newWatchEventsLoopThreadPool();\n    }\n\n    /**\n     * The Root Directory for config center\n     */\n    private final File rootDirectory;\n\n    private final String encoding;\n\n    /**\n     * The {@link Set} of {@link #groupDirectory(String) directories} that may be processing,\n     * <p>\n     * if {@link #isBasedPoolingWatchService()} is <code>false</code>, this properties will be\n     * {@link Collections#emptySet() empty}\n     *\n     * @see #initProcessingDirectories()\n     */\n    private final Set<File> processingDirectories;\n\n    private final Map<File, List<ConfigurationListener>> listenersRepository;\n    private ScopeModel scopeModel;\n    private AtomicBoolean hasRegisteredShutdownHook = new AtomicBoolean();\n\n    public FileSystemDynamicConfiguration() {\n        this(new File(DEFAULT_CONFIG_CENTER_DIR_PATH));\n    }\n\n    public FileSystemDynamicConfiguration(File rootDirectory) {\n        this(rootDirectory, DEFAULT_CONFIG_CENTER_ENCODING);\n    }\n\n    public FileSystemDynamicConfiguration(File rootDirectory, String encoding) {\n        this(rootDirectory, encoding, DEFAULT_THREAD_POOL_PREFIX);\n    }\n\n    public FileSystemDynamicConfiguration(File rootDirectory, String encoding, String threadPoolPrefixName) {\n        this(rootDirectory, encoding, threadPoolPrefixName, DEFAULT_THREAD_POOL_SIZE);\n    }\n\n    public FileSystemDynamicConfiguration(\n            File rootDirectory, String encoding, String threadPoolPrefixName, int threadPoolSize) {\n        this(rootDirectory, encoding, threadPoolPrefixName, threadPoolSize, DEFAULT_THREAD_POOL_KEEP_ALIVE_TIME);\n    }\n\n    public FileSystemDynamicConfiguration(\n            File rootDirectory, String encoding, String threadPoolPrefixName, int threadPoolSize, long keepAliveTime) {\n        super(rootDirectory.getAbsolutePath(), threadPoolPrefixName, threadPoolSize, keepAliveTime, DEFAULT_GROUP, -1L);\n        this.rootDirectory = rootDirectory;\n        this.encoding = encoding;\n        this.processingDirectories = initProcessingDirectories();\n        this.listenersRepository = new HashMap<>();\n        registerDubboShutdownHook();\n    }\n\n    public FileSystemDynamicConfiguration(\n            File rootDirectory,\n            String encoding,\n            String threadPoolPrefixName,\n            int threadPoolSize,\n            long keepAliveTime,\n            ScopeModel scopeModel) {\n        super(rootDirectory.getAbsolutePath(), threadPoolPrefixName, threadPoolSize, keepAliveTime, DEFAULT_GROUP, -1L);\n        this.rootDirectory = rootDirectory;\n        this.encoding = encoding;\n        this.processingDirectories = initProcessingDirectories();\n        this.listenersRepository = new HashMap<>();\n        this.scopeModel = scopeModel;\n        registerDubboShutdownHook();\n    }\n\n    public FileSystemDynamicConfiguration(URL url) {\n        this(\n                initDirectory(url),\n                getEncoding(url),\n                getThreadPoolPrefixName(url),\n                getThreadPoolSize(url),\n                getThreadPoolKeepAliveTime(url),\n                url.getScopeModel());\n    }\n\n    private Set<File> initProcessingDirectories() {\n        return isBasedPoolingWatchService() ? new LinkedHashSet<>() : emptySet();\n    }\n\n    public File configFile(String key, String group) {\n        return new File(buildPathKey(group, key));\n    }\n\n    private void doInListener(String configFilePath, BiConsumer<File, List<ConfigurationListener>> consumer) {\n        watchService.ifPresent(watchService -> {\n            File configFile = new File(configFilePath);\n            executeMutually(configFile.getParentFile(), () -> {\n                // process the WatchEvents if not start\n                if (!isProcessingWatchEvents()) {\n                    processWatchEvents(watchService);\n                }\n\n                List<ConfigurationListener> listeners = getListeners(configFile);\n                consumer.accept(configFile, listeners);\n\n                // Nothing to return\n                return null;\n            });\n        });\n    }\n\n    /**\n     * Register the Dubbo ShutdownHook\n     *\n     * @since 2.7.8\n     */\n    private void registerDubboShutdownHook() {\n        if (!hasRegisteredShutdownHook.compareAndSet(false, true)) {\n            return;\n        }\n        ShutdownHookCallbacks shutdownHookCallbacks =\n                ScopeModelUtil.getApplicationModel(scopeModel).getBeanFactory().getBean(ShutdownHookCallbacks.class);\n        shutdownHookCallbacks.addCallback(() -> {\n            watchService.ifPresent(w -> {\n                try {\n                    w.close();\n                } catch (IOException e) {\n                    throw new RuntimeException(e);\n                }\n            });\n            getWatchEventsLoopThreadPool().shutdown();\n        });\n    }\n\n    private static boolean isProcessingWatchEvents() {\n        return getWatchEventsLoopThreadPool().getActiveCount() > 0;\n    }\n\n    /**\n     * Process the {@link WatchEvent WatchEvents} loop in async execution\n     *\n     * @param watchService {@link WatchService}\n     */\n    private void processWatchEvents(WatchService watchService) {\n        getWatchEventsLoopThreadPool()\n                .execute(\n                        () -> { // WatchEvents Loop\n                            while (true) {\n                                WatchKey watchKey = null;\n                                try {\n                                    watchKey = watchService.take();\n\n                                    if (!watchKey.isValid()) {\n                                        continue;\n                                    }\n\n                                    for (WatchEvent event : watchKey.pollEvents()) {\n                                        WatchEvent.Kind kind = event.kind();\n                                        // configChangeType's key to match WatchEvent's Kind\n                                        ConfigChangeType configChangeType = CONFIG_CHANGE_TYPES_MAP.get(kind.name());\n\n                                        if (configChangeType == null) {\n                                            continue;\n                                        }\n\n                                        Path configDirectoryPath = (Path) watchKey.watchable();\n                                        Path currentPath = (Path) event.context();\n                                        Path configFilePath = configDirectoryPath.resolve(currentPath);\n                                        File configDirectory = configDirectoryPath.toFile();\n\n                                        executeMutually(configDirectory, () -> {\n                                            fireConfigChangeEvent(\n                                                    configDirectory, configFilePath.toFile(), configChangeType);\n                                            signalConfigDirectory(configDirectory);\n                                            return null;\n                                        });\n                                    }\n\n                                } catch (Exception e) {\n                                    return;\n                                } finally {\n                                    if (watchKey != null) {\n                                        // reset\n                                        watchKey.reset();\n                                    }\n                                }\n                            }\n                        });\n    }\n\n    private void signalConfigDirectory(File configDirectory) {\n        if (isBasedPoolingWatchService()) {\n            // remove configDirectory from processing set because it's done\n            removeProcessingDirectory(configDirectory);\n            // notify configDirectory\n            notifyProcessingDirectory(configDirectory);\n            if (logger.isDebugEnabled()) {\n                logger.debug(format(\"The config rootDirectory[%s] is signalled...\", configDirectory.getName()));\n            }\n        }\n    }\n\n    private void removeProcessingDirectory(File configDirectory) {\n        processingDirectories.remove(configDirectory);\n    }\n\n    private void notifyProcessingDirectory(File configDirectory) {\n        configDirectory.notifyAll();\n    }\n\n    private List<ConfigurationListener> getListeners(File configFile) {\n        return listenersRepository.computeIfAbsent(configFile, p -> new LinkedList<>());\n    }\n\n    private void fireConfigChangeEvent(File configDirectory, File configFile, ConfigChangeType configChangeType) {\n        String key = configFile.getName();\n        String value = getConfig(configFile);\n        // fire ConfigChangeEvent one by one\n        getListeners(configFile).forEach(listener -> {\n            try {\n                listener.process(new ConfigChangedEvent(key, configDirectory.getName(), value, configChangeType));\n            } catch (Throwable e) {\n                if (logger.isErrorEnabled()) {\n                    logger.error(CONFIG_ERROR_PROCESS_LISTENER, \"\", \"\", e.getMessage(), e);\n                }\n            }\n        });\n    }\n\n    private boolean canRead(File file) {\n        return file.exists() && file.canRead();\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        return null;\n    }\n\n    @Override\n    protected boolean doPublishConfig(String pathKey, String content) throws Exception {\n        return delay(pathKey, configFile -> {\n            FileUtils.write(configFile, content, getEncoding());\n            return true;\n        });\n    }\n\n    @Override\n    protected String doGetConfig(String pathKey) throws Exception {\n        File configFile = new File(pathKey);\n        return getConfig(configFile);\n    }\n\n    @Override\n    protected boolean doRemoveConfig(String pathKey) throws Exception {\n        delay(pathKey, configFile -> {\n            String content = getConfig(configFile);\n            FileUtils.deleteQuietly(configFile);\n            return content;\n        });\n        return true;\n    }\n\n    @Override\n    protected Collection<String> doGetConfigKeys(String groupPath) {\n        File[] files = new File(groupPath).listFiles(File::isFile);\n        if (files == null) {\n            return new TreeSet<>();\n        } else {\n            return Stream.of(files).map(File::getName).collect(Collectors.toList());\n        }\n    }\n\n    @Override\n    protected void doAddListener(String pathKey, ConfigurationListener listener, String key, String group) {\n        doInListener(pathKey, (configFilePath, listeners) -> {\n            if (listeners.isEmpty()) { // If no element, it indicates watchService was registered before\n                ThrowableConsumer.execute(configFilePath, configFile -> {\n                    FileUtils.forceMkdirParent(configFile);\n                    // A rootDirectory to be watched\n                    File configDirectory = configFile.getParentFile();\n                    if (configDirectory != null) {\n                        // Register the configDirectory\n                        configDirectory.toPath().register(watchService.get(), INTEREST_PATH_KINDS, MODIFIERS);\n                    }\n                });\n            }\n            // Add into cache\n            listeners.add(listener);\n        });\n    }\n\n    @Override\n    protected void doRemoveListener(String pathKey, ConfigurationListener listener) {\n        doInListener(pathKey, (file, listeners) -> {\n            // Remove into cache\n            listeners.remove(listener);\n        });\n    }\n\n    /**\n     * Delay action for {@link #configFile(String, String) config file}\n     *\n     * @param configFilePath the key to represent a configuration\n     * @param function       the customized {@link Function function} with {@link File}\n     * @param <V>            the computed value\n     * @return\n     */\n    protected <V> V delay(String configFilePath, ThrowableFunction<File, V> function) {\n        File configFile = new File(configFilePath);\n        // Must be based on PoolingWatchService and has listeners under config file\n        if (isBasedPoolingWatchService()) {\n            File configDirectory = configFile.getParentFile();\n            executeMutually(configDirectory, () -> {\n                if (hasListeners(configFile) && isProcessing(configDirectory)) {\n                    Integer delay = getDelay();\n                    if (delay != null) {\n                        // wait for delay in seconds\n                        long timeout = SECONDS.toMillis(delay);\n                        if (logger.isDebugEnabled()) {\n                            logger.debug(format(\n                                    \"The config[path : %s] is about to delay in %d ms.\", configFilePath, timeout));\n                        }\n                        configDirectory.wait(timeout);\n                    }\n                }\n                addProcessing(configDirectory);\n                return null;\n            });\n        }\n\n        V value = null;\n\n        try {\n            value = function.apply(configFile);\n        } catch (Throwable e) {\n            if (logger.isErrorEnabled()) {\n                logger.error(CONFIG_ERROR_PROCESS_LISTENER, \"\", \"\", e.getMessage(), e);\n            }\n        }\n\n        return value;\n    }\n\n    private boolean hasListeners(File configFile) {\n        return getListeners(configFile).size() > 0;\n    }\n\n    /**\n     * Is processing on {@link #buildGroupPath(String) config rootDirectory}\n     *\n     * @param configDirectory {@link #buildGroupPath(String) config rootDirectory}\n     * @return if processing , return <code>true</code>, or <code>false</code>\n     */\n    private boolean isProcessing(File configDirectory) {\n        return processingDirectories.contains(configDirectory);\n    }\n\n    private void addProcessing(File configDirectory) {\n        processingDirectories.add(configDirectory);\n    }\n\n    public Set<String> getConfigGroups() {\n        return Stream.of(getRootDirectory().listFiles())\n                .filter(File::isDirectory)\n                .map(File::getName)\n                .collect(Collectors.toSet());\n    }\n\n    protected String getConfig(File configFile) {\n        return ThrowableFunction.execute(\n                configFile, file -> canRead(configFile) ? readFileToString(configFile, getEncoding()) : null);\n    }\n\n    @Override\n    protected void doClose() throws Exception {}\n\n    public File getRootDirectory() {\n        return rootDirectory;\n    }\n\n    public String getEncoding() {\n        return encoding;\n    }\n\n    protected Integer getDelay() {\n        return DELAY;\n    }\n\n    /**\n     * It's whether the implementation of {@link WatchService} is based on {@linkplain sun.nio.fs.PollingWatchService}\n     * or not.\n     * <p>\n     *\n     * @return if based, return <code>true</code>, or <code>false</code>\n     * @see #detectPoolingBasedWatchService(Optional)\n     */\n    protected static boolean isBasedPoolingWatchService() {\n        return BASED_POOLING_WATCH_SERVICE;\n    }\n\n    protected static ThreadPoolExecutor getWatchEventsLoopThreadPool() {\n        return WATCH_EVENTS_LOOP_THREAD_POOL;\n    }\n\n    protected ThreadPoolExecutor getWorkersThreadPool() {\n        return super.getWorkersThreadPool();\n    }\n\n    private <V> V executeMutually(final Object mutex, Callable<V> callable) {\n        V value = null;\n        synchronized (mutex) {\n            try {\n                value = callable.call();\n            } catch (Exception e) {\n                if (logger.isErrorEnabled()) {\n                    logger.error(CONFIG_ERROR_PROCESS_LISTENER, \"\", \"\", e.getMessage(), e);\n                }\n            }\n        }\n        return value;\n    }\n\n    private static <T> T[] of(T... values) {\n        return values;\n    }\n\n    private static Integer initDelay(WatchEvent.Modifier[] modifiers) {\n        if (isBasedPoolingWatchService()) {\n            return 2;\n        } else {\n            return null;\n        }\n    }\n\n    private static WatchEvent.Modifier[] initWatchEventModifiers() {\n        return of();\n    }\n\n    /**\n     * Detect the argument of {@link WatchService} is based on {@linkplain sun.nio.fs.PollingWatchService}\n     * or not.\n     * <p>\n     * Some platforms do not provide the native implementation of {@link WatchService}, just use\n     * {@linkplain sun.nio.fs.PollingWatchService} in periodic poll file modifications.\n     *\n     * @param watchService the instance of {@link WatchService}\n     * @return if based, return <code>true</code>, or <code>false</code>\n     */\n    private static boolean detectPoolingBasedWatchService(Optional<WatchService> watchService) {\n        String className =\n                watchService.map(Object::getClass).map(Class::getName).orElse(null);\n        return POLLING_WATCH_SERVICE_CLASS_NAME.equals(className);\n    }\n\n    private static Optional<WatchService> newWatchService() {\n        Optional<WatchService> watchService = null;\n        FileSystem fileSystem = FileSystems.getDefault();\n        try {\n            watchService = Optional.of(fileSystem.newWatchService());\n        } catch (IOException e) {\n            if (logger.isErrorEnabled()) {\n                logger.error(CONFIG_ERROR_PROCESS_LISTENER, \"\", \"\", e.getMessage(), e);\n            }\n            watchService = Optional.empty();\n        }\n        return watchService;\n    }\n\n    protected static File initDirectory(URL url) {\n        String directoryPath = getParameter(url, CONFIG_CENTER_DIR_PARAM_NAME, url == null ? null : url.getPath());\n        File rootDirectory = null;\n        if (!StringUtils.isBlank(directoryPath)) {\n            rootDirectory = new File(\"/\" + directoryPath);\n        }\n\n        if (directoryPath == null || !rootDirectory.exists()) { // If the directory does not exist\n            rootDirectory = new File(DEFAULT_CONFIG_CENTER_DIR_PATH);\n        }\n\n        if (!rootDirectory.exists() && !rootDirectory.mkdirs()) {\n            throw new IllegalStateException(\n                    format(\"Dubbo config center rootDirectory[%s] can't be created!\", rootDirectory.getAbsolutePath()));\n        }\n        return rootDirectory;\n    }\n\n    protected static String getEncoding(URL url) {\n        return getParameter(url, CONFIG_CENTER_ENCODING_PARAM_NAME, DEFAULT_CONFIG_CENTER_ENCODING);\n    }\n\n    private static ThreadPoolExecutor newWatchEventsLoopThreadPool() {\n        return new ThreadPoolExecutor(\n                THREAD_POOL_SIZE,\n                THREAD_POOL_SIZE,\n                0L,\n                MILLISECONDS,\n                new SynchronousQueue(),\n                new NamedThreadFactory(\"dubbo-config-center-watch-events-loop\", true));\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-file/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter.file;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory;\n\n/**\n * File-System based {@link DynamicConfigurationFactory} implementation\n *\n * @since 2.7.5\n */\npublic class FileSystemDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory {\n\n    @Override\n    protected DynamicConfiguration createDynamicConfiguration(URL url) {\n        return new FileSystemDynamicConfiguration(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-file/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory",
    "content": "file=org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfigurationFactory\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-file/src/test/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter.file;\n\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link FileSystemDynamicConfigurationFactory} Test\n *\n * @since 2.7.5\n */\nclass FileSystemDynamicConfigurationFactoryTest {\n\n    @Test\n    void testGetFactory() {\n        assertEquals(\n                FileSystemDynamicConfigurationFactory.class,\n                ConfigurationUtils.getDynamicConfigurationFactory(ApplicationModel.defaultModel(), \"file\")\n                        .getClass());\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-file/src/test/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.config.configcenter.file;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.apache.commons.io.FileUtils;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.URL.valueOf;\nimport static org.apache.dubbo.common.config.configcenter.DynamicConfiguration.DEFAULT_GROUP;\nimport static org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration.CONFIG_CENTER_DIR_PARAM_NAME;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link FileSystemDynamicConfiguration} Test\n */\n// Test often failed on GitHub Actions Platform because of file system on Azure\n// Change to Disabled because DisabledIfEnvironmentVariable does not work on GitHub.\n@Disabled\nclass FileSystemDynamicConfigurationTest {\n\n    private final Logger logger = LoggerFactory.getLogger(getClass());\n\n    private FileSystemDynamicConfiguration configuration;\n\n    private static final String KEY = \"abc-def-ghi\";\n\n    private static final String CONTENT = \"Hello,World\";\n\n    @BeforeEach\n    public void init() {\n        File rootDirectory = new File(getClassPath(), \"config-center\");\n        rootDirectory.mkdirs();\n        try {\n            FileUtils.cleanDirectory(rootDirectory);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        URL url = valueOf(\"dubbo://127.0.0.1:20880\")\n                .addParameter(CONFIG_CENTER_DIR_PARAM_NAME, rootDirectory.getAbsolutePath());\n        configuration = new FileSystemDynamicConfiguration(url);\n    }\n\n    @AfterEach\n    public void destroy() throws Exception {\n        FileUtils.deleteQuietly(configuration.getRootDirectory());\n        configuration.close();\n    }\n\n    private String getClassPath() {\n        return getClass().getProtectionDomain().getCodeSource().getLocation().getPath();\n    }\n\n    @Test\n    void testInit() {\n\n        assertEquals(new File(getClassPath(), \"config-center\"), configuration.getRootDirectory());\n        assertEquals(\"UTF-8\", configuration.getEncoding());\n        assertEquals(\n                ThreadPoolExecutor.class, configuration.getWorkersThreadPool().getClass());\n        assertEquals(1, (configuration.getWorkersThreadPool()).getCorePoolSize());\n        assertEquals(1, (configuration.getWorkersThreadPool()).getMaximumPoolSize());\n\n        if (configuration.isBasedPoolingWatchService()) {\n            assertEquals(2, configuration.getDelay());\n        } else {\n            assertNull(configuration.getDelay());\n        }\n    }\n\n    @Test\n    void testPublishAndGetConfig() {\n        assertTrue(configuration.publishConfig(KEY, CONTENT));\n        assertTrue(configuration.publishConfig(KEY, CONTENT));\n        assertTrue(configuration.publishConfig(KEY, CONTENT));\n        assertEquals(CONTENT, configuration.getConfig(KEY, DEFAULT_GROUP));\n    }\n\n    @Test\n    void testAddAndRemoveListener() throws InterruptedException {\n\n        configuration.publishConfig(KEY, \"A\");\n\n        AtomicBoolean processedEvent = new AtomicBoolean();\n\n        configuration.addListener(KEY, event -> {\n            processedEvent.set(true);\n            assertEquals(KEY, event.getKey());\n            logger.info(\n                    String.format(\"[%s] \" + event + \"\\n\", Thread.currentThread().getName()));\n        });\n\n        configuration.publishConfig(KEY, \"B\");\n        while (!processedEvent.get()) {\n            Thread.sleep(1 * 1000L);\n        }\n\n        processedEvent.set(false);\n        configuration.publishConfig(KEY, \"C\");\n        while (!processedEvent.get()) {\n            Thread.sleep(1 * 1000L);\n        }\n\n        processedEvent.set(false);\n        configuration.publishConfig(KEY, \"D\");\n        while (!processedEvent.get()) {\n            Thread.sleep(1 * 1000L);\n        }\n\n        configuration.addListener(\"test\", \"test\", event -> {\n            processedEvent.set(true);\n            assertEquals(\"test\", event.getKey());\n            logger.info(\n                    String.format(\"[%s] \" + event + \"\\n\", Thread.currentThread().getName()));\n        });\n        processedEvent.set(false);\n        configuration.publishConfig(\"test\", \"test\", \"TEST\");\n        while (!processedEvent.get()) {\n            Thread.sleep(1 * 1000L);\n        }\n\n        configuration.publishConfig(\"test\", \"test\", \"TEST\");\n        configuration.publishConfig(\"test\", \"test\", \"TEST\");\n        configuration.publishConfig(\"test\", \"test\", \"TEST\");\n\n        processedEvent.set(false);\n        configuration.getRootDirectory();\n        File keyFile = new File(KEY, DEFAULT_GROUP);\n        FileUtils.deleteQuietly(keyFile);\n        while (!processedEvent.get()) {\n            Thread.sleep(1 * 1000L);\n        }\n    }\n\n    @Test\n    void testRemoveConfig() throws Exception {\n\n        assertTrue(configuration.publishConfig(KEY, DEFAULT_GROUP, \"A\"));\n\n        assertEquals(\n                \"A\",\n                FileUtils.readFileToString(configuration.configFile(KEY, DEFAULT_GROUP), configuration.getEncoding()));\n\n        assertTrue(configuration.removeConfig(KEY, DEFAULT_GROUP));\n\n        assertFalse(configuration.configFile(KEY, DEFAULT_GROUP).exists());\n    }\n    //\n    //    @Test\n    //    public void testGetConfigKeys() throws Exception {\n    //\n    //        assertTrue(configuration.publishConfig(\"A\", DEFAULT_GROUP, \"A\"));\n    //\n    //        assertTrue(configuration.publishConfig(\"B\", DEFAULT_GROUP, \"B\"));\n    //\n    //        assertTrue(configuration.publishConfig(\"C\", DEFAULT_GROUP, \"C\"));\n    //\n    //        assertEquals(new TreeSet(asList(\"A\", \"B\", \"C\")), configuration.getConfigKeys(DEFAULT_GROUP));\n    //    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-file/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-nacos/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-configcenter</artifactId>\n    <version>${revision}</version>\n  </parent>\n\n  <artifactId>dubbo-configcenter-nacos</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The nacos implementation of the config-center api</description>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>com.alibaba.nacos</groupId>\n      <artifactId>nacos-client</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-prometheus</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-config-center</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosConfigServiceWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.nacos;\n\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.config.listener.Listener;\nimport com.alibaba.nacos.api.exception.NacosException;\n\nimport static org.apache.dubbo.common.utils.StringUtils.HYPHEN_CHAR;\nimport static org.apache.dubbo.common.utils.StringUtils.SLASH_CHAR;\n\npublic class NacosConfigServiceWrapper {\n\n    private static final String INNERCLASS_SYMBOL = \"$\";\n\n    private static final String INNERCLASS_COMPATIBLE_SYMBOL = \"___\";\n\n    private static final long DEFAULT_TIMEOUT = 3000L;\n\n    private final ConfigService configService;\n\n    public NacosConfigServiceWrapper(ConfigService configService) {\n        this.configService = configService;\n    }\n\n    public ConfigService getConfigService() {\n        return configService;\n    }\n\n    public void addListener(String dataId, String group, Listener listener) throws NacosException {\n        configService.addListener(handleInnerSymbol(dataId), handleInnerSymbol(group), listener);\n    }\n\n    public String getConfig(String dataId, String group) throws NacosException {\n        return configService.getConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), DEFAULT_TIMEOUT);\n    }\n\n    public String getConfig(String dataId, String group, long timeout) throws NacosException {\n        return configService.getConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), timeout);\n    }\n\n    public boolean publishConfig(String dataId, String group, String content) throws NacosException {\n        return configService.publishConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), content);\n    }\n\n    public boolean publishConfigCas(String dataId, String group, String content, String casMd5) throws NacosException {\n        return configService.publishConfigCas(handleInnerSymbol(dataId), handleInnerSymbol(group), content, casMd5);\n    }\n\n    public boolean removeConfig(String dataId, String group) throws NacosException {\n        return configService.removeConfig(handleInnerSymbol(dataId), handleInnerSymbol(group));\n    }\n\n    public void shutdown() throws NacosException {\n        configService.shutDown();\n    }\n\n    /**\n     * see {@link com.alibaba.nacos.client.config.utils.ParamUtils#isValid(java.lang.String)}\n     */\n    private String handleInnerSymbol(String data) {\n        if (data == null) {\n            return null;\n        }\n        return data.replace(INNERCLASS_SYMBOL, INNERCLASS_COMPATIBLE_SYMBOL).replace(SLASH_CHAR, HYPHEN_CHAR);\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.MD5Utils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metrics.config.event.ConfigCenterEvent;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.Executor;\n\nimport com.alibaba.nacos.api.NacosFactory;\nimport com.alibaba.nacos.api.PropertyKeyConst;\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.config.listener.AbstractSharedListener;\nimport com.alibaba.nacos.api.exception.NacosException;\n\nimport static com.alibaba.nacos.api.PropertyKeyConst.PASSWORD;\nimport static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;\nimport static com.alibaba.nacos.api.PropertyKeyConst.USERNAME;\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_ERROR_NACOS;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_INTERRUPTED;\nimport static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;\nimport static org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of;\nimport static org.apache.dubbo.common.utils.StringUtils.HYPHEN_CHAR;\nimport static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE;\n\n/**\n * The nacos implementation of {@link DynamicConfiguration}\n */\npublic class NacosDynamicConfiguration implements DynamicConfiguration {\n\n    private static final String GET_CONFIG_KEYS_PATH = \"/v1/cs/configs\";\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n    /**\n     * the default timeout in millis to get config from nacos\n     */\n    private static final long DEFAULT_TIMEOUT = 5000L;\n\n    private final Properties nacosProperties;\n\n    private static final String NACOS_RETRY_KEY = \"nacos.retry\";\n\n    private static final String NACOS_RETRY_WAIT_KEY = \"nacos.retry-wait\";\n\n    private static final String NACOS_CHECK_KEY = \"nacos.check\";\n\n    /**\n     * The nacos configService\n     */\n    private final NacosConfigServiceWrapper configService;\n\n    private ApplicationModel applicationModel;\n\n    /**\n     * The map store the key to {@link NacosConfigListener} mapping\n     */\n    private final ConcurrentMap<String, NacosConfigListener> watchListenerMap;\n\n    private final MD5Utils md5Utils = new MD5Utils();\n\n    NacosDynamicConfiguration(URL url, ApplicationModel applicationModel) {\n        this.nacosProperties = buildNacosProperties(url);\n        this.configService = buildConfigService(url);\n        this.watchListenerMap = new ConcurrentHashMap<>();\n        this.applicationModel = applicationModel;\n    }\n\n    private NacosConfigServiceWrapper buildConfigService(URL url) {\n        int retryTimes = url.getPositiveParameter(NACOS_RETRY_KEY, 10);\n        int sleepMsBetweenRetries = url.getPositiveParameter(NACOS_RETRY_WAIT_KEY, 1000);\n        boolean check = url.getParameter(NACOS_CHECK_KEY, true);\n        ConfigService tmpConfigServices = null;\n        try {\n            for (int i = 0; i < retryTimes + 1; i++) {\n                tmpConfigServices = NacosFactory.createConfigService(nacosProperties);\n                String serverStatus = tmpConfigServices.getServerStatus();\n                boolean configServiceAvailable = testConfigService(tmpConfigServices);\n                if (!check || (UP.equals(serverStatus) && configServiceAvailable)) {\n                    break;\n                } else {\n                    logger.warn(\n                            LoggerCodeConstants.CONFIG_ERROR_NACOS,\n                            \"\",\n                            \"\",\n                            \"Failed to connect to nacos config server. \" + \"Server status: \"\n                                    + serverStatus + \". \" + \"Config Service Available: \"\n                                    + configServiceAvailable + \". \"\n                                    + (i < retryTimes\n                                            ? \"Dubbo will try to retry in \" + sleepMsBetweenRetries + \". \"\n                                            : \"Exceed retry max times.\")\n                                    + \"Try times: \"\n                                    + (i + 1));\n                }\n                tmpConfigServices.shutDown();\n                tmpConfigServices = null;\n                Thread.sleep(sleepMsBetweenRetries);\n            }\n        } catch (NacosException e) {\n            logger.error(CONFIG_ERROR_NACOS, \"\", \"\", e.getErrMsg(), e);\n            throw new IllegalStateException(e);\n        } catch (InterruptedException e) {\n            logger.error(INTERNAL_INTERRUPTED, \"\", \"\", \"Interrupted when creating nacos config service client.\", e);\n            Thread.currentThread().interrupt();\n            throw new IllegalStateException(e);\n        }\n\n        if (tmpConfigServices == null) {\n            logger.error(\n                    CONFIG_ERROR_NACOS,\n                    \"\",\n                    \"\",\n                    \"Failed to create nacos config service client. Reason: server status check failed.\");\n            throw new IllegalStateException(\n                    \"Failed to create nacos config service client. Reason: server status check failed.\");\n        }\n\n        return new NacosConfigServiceWrapper(tmpConfigServices);\n    }\n\n    private boolean testConfigService(ConfigService configService) {\n        try {\n            configService.getConfig(\"Dubbo-Nacos-Test\", \"Dubbo-Nacos-Test\", DEFAULT_TIMEOUT);\n            return true;\n        } catch (NacosException e) {\n            return false;\n        }\n    }\n\n    private Properties buildNacosProperties(URL url) {\n        Properties properties = new Properties();\n        setServerAddr(url, properties);\n        setProperties(url, properties);\n        return properties;\n    }\n\n    private void setServerAddr(URL url, Properties properties) {\n        StringBuilder serverAddrBuilder = new StringBuilder(url.getHost()) // Host\n                .append(':')\n                .append(url.getPort()); // Port\n\n        // Append backup parameter as other servers\n        String backup = url.getParameter(BACKUP_KEY);\n        if (backup != null) {\n            serverAddrBuilder.append(',').append(backup);\n        }\n        String serverAddr = serverAddrBuilder.toString();\n        properties.put(SERVER_ADDR, serverAddr);\n    }\n\n    private static void setProperties(URL url, Properties properties) {\n        // Get the parameters from constants\n        Map<String, String> parameters = url.getParameters(of(PropertyKeyConst.class));\n        // Put all parameters\n        properties.putAll(parameters);\n        if (StringUtils.isNotEmpty(url.getUsername())) {\n            properties.put(USERNAME, url.getUsername());\n        }\n        if (StringUtils.isNotEmpty(url.getPassword())) {\n            properties.put(PASSWORD, url.getPassword());\n        }\n    }\n\n    private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName) {\n        String propertyValue = url.getParameter(propertyName);\n        if (StringUtils.isNotEmpty(propertyValue)) {\n            properties.setProperty(propertyName, propertyValue);\n        }\n    }\n\n    private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName, String defaultValue) {\n        String propertyValue = url.getParameter(propertyName);\n        if (StringUtils.isNotEmpty(propertyValue)) {\n            properties.setProperty(propertyName, propertyValue);\n        } else {\n            properties.setProperty(propertyName, defaultValue);\n        }\n    }\n\n    /**\n     * Ignores the group parameter.\n     *\n     * @param key   property key the native listener will listen on\n     * @param group to distinguish different set of properties\n     * @return\n     */\n    private NacosConfigListener createTargetListener(String key, String group) {\n        NacosConfigListener configListener = new NacosConfigListener();\n        configListener.fillContext(key, group);\n        return configListener;\n    }\n\n    @Override\n    public void close() throws Exception {\n        configService.shutdown();\n    }\n\n    @Override\n    public void addListener(String key, String group, ConfigurationListener listener) {\n        String listenerKey = buildListenerKey(key, group);\n        NacosConfigListener nacosConfigListener = ConcurrentHashMapUtils.computeIfAbsent(\n                watchListenerMap, listenerKey, k -> createTargetListener(key, group));\n        nacosConfigListener.addListener(listener);\n        try {\n            configService.addListener(key, group, nacosConfigListener);\n        } catch (NacosException e) {\n            logger.error(CONFIG_ERROR_NACOS, \"\", \"\", e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public void removeListener(String key, String group, ConfigurationListener listener) {\n        String listenerKey = buildListenerKey(key, group);\n        NacosConfigListener eventListener = watchListenerMap.get(listenerKey);\n        if (eventListener != null) {\n            eventListener.removeListener(listener);\n        }\n    }\n\n    @Override\n    public String getConfig(String key, String group, long timeout) throws IllegalStateException {\n        try {\n            long nacosTimeout = timeout < 0 ? getDefaultTimeout() : timeout;\n            if (StringUtils.isEmpty(group)) {\n                group = DEFAULT_GROUP;\n            }\n            return configService.getConfig(key, group, nacosTimeout);\n        } catch (NacosException e) {\n            logger.error(CONFIG_ERROR_NACOS, \"\", \"\", e.getMessage(), e);\n        }\n        return null;\n    }\n\n    @Override\n    public ConfigItem getConfigItem(String key, String group) {\n        String content = getConfig(key, group);\n        String casMd5 = \"\";\n        if (StringUtils.isNotEmpty(content)) {\n            casMd5 = md5Utils.getMd5(content);\n        }\n        return new ConfigItem(content, casMd5);\n    }\n\n    @Override\n    public Object getInternalProperty(String key) {\n        try {\n            return configService.getConfig(key, DEFAULT_GROUP, getDefaultTimeout());\n        } catch (NacosException e) {\n            logger.error(CONFIG_ERROR_NACOS, \"\", \"\", e.getMessage(), e);\n        }\n        return null;\n    }\n\n    @Override\n    public boolean publishConfig(String key, String group, String content) {\n        boolean published = false;\n        try {\n            published = configService.publishConfig(key, group, content);\n        } catch (NacosException e) {\n            logger.error(CONFIG_ERROR_NACOS, \"\", \"\", e.getMessage(), e);\n        }\n        return published;\n    }\n\n    @Override\n    public boolean publishConfigCas(String key, String group, String content, Object ticket) {\n        try {\n            if (!(ticket instanceof String)) {\n                throw new IllegalArgumentException(\"nacos publishConfigCas requires string type ticket\");\n            }\n            return configService.publishConfigCas(key, group, content, (String) ticket);\n        } catch (NacosException e) {\n            logger.warn(CONFIG_ERROR_NACOS, \"nacos publishConfigCas failed.\", \"\", e.getMessage(), e);\n            return false;\n        }\n    }\n\n    @Override\n    public long getDefaultTimeout() {\n        return DEFAULT_TIMEOUT;\n    }\n\n    @Override\n    public boolean removeConfig(String key, String group) {\n        boolean removed = false;\n        try {\n            removed = configService.removeConfig(key, group);\n        } catch (NacosException e) {\n            if (logger.isErrorEnabled()) {\n                logger.error(CONFIG_ERROR_NACOS, \"\", \"\", e.getMessage(), e);\n            }\n        }\n        return removed;\n    }\n\n    private String getProperty(String name, String defaultValue) {\n        return nacosProperties.getProperty(name, defaultValue);\n    }\n\n    public class NacosConfigListener extends AbstractSharedListener {\n\n        private Set<ConfigurationListener> listeners = new CopyOnWriteArraySet<>();\n        /**\n         * cache data to store old value\n         */\n        private Map<String, String> cacheData = new ConcurrentHashMap<>();\n\n        @Override\n        public Executor getExecutor() {\n            return null;\n        }\n\n        /**\n         * receive\n         *\n         * @param dataId     data ID\n         * @param group      group\n         * @param configInfo content\n         */\n        @Override\n        public void innerReceive(String dataId, String group, String configInfo) {\n            String oldValue = cacheData.get(dataId);\n            ConfigChangedEvent event =\n                    new ConfigChangedEvent(dataId, group, configInfo, getChangeType(configInfo, oldValue));\n            if (configInfo == null) {\n                cacheData.remove(dataId);\n            } else {\n                cacheData.put(dataId, configInfo);\n            }\n            listeners.forEach(listener -> listener.process(event));\n\n            MetricsEventBus.publish(ConfigCenterEvent.toChangeEvent(\n                    applicationModel,\n                    event.getKey(),\n                    event.getGroup(),\n                    ConfigCenterEvent.NACOS_PROTOCOL,\n                    ConfigChangeType.ADDED.name(),\n                    SELF_INCREMENT_SIZE));\n        }\n\n        void addListener(ConfigurationListener configurationListener) {\n\n            this.listeners.add(configurationListener);\n        }\n\n        void removeListener(ConfigurationListener configurationListener) {\n            this.listeners.remove(configurationListener);\n        }\n\n        private ConfigChangeType getChangeType(String configInfo, String oldValue) {\n            if (StringUtils.isBlank(configInfo)) {\n                return ConfigChangeType.DELETED;\n            }\n            if (StringUtils.isBlank(oldValue)) {\n                return ConfigChangeType.ADDED;\n            }\n            return ConfigChangeType.MODIFIED;\n        }\n    }\n\n    protected String buildListenerKey(String key, String group) {\n        return key + HYPHEN_CHAR + group;\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport com.alibaba.nacos.api.PropertyKeyConst;\n\n/**\n * The nacos implementation of {@link AbstractDynamicConfigurationFactory}\n */\npublic class NacosDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory {\n\n    private ApplicationModel applicationModel;\n\n    public NacosDynamicConfigurationFactory(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    @Override\n    protected DynamicConfiguration createDynamicConfiguration(URL url) {\n        URL nacosURL = url;\n        if (CommonConstants.DUBBO.equals(url.getParameter(PropertyKeyConst.NAMESPACE))) {\n            // Nacos use empty string as default namespace, replace default namespace \"dubbo\" to \"\"\n            nacosURL = url.removeParameter(PropertyKeyConst.NAMESPACE);\n        }\n        return new NacosDynamicConfiguration(nacosURL, applicationModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory",
    "content": "nacos=org.apache.dubbo.configcenter.support.nacos.NacosDynamicConfigurationFactory"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/MockConfigService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.nacos;\n\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.config.filter.IConfigFilter;\nimport com.alibaba.nacos.api.config.listener.Listener;\nimport com.alibaba.nacos.api.exception.NacosException;\n\npublic class MockConfigService implements ConfigService {\n    @Override\n    public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {\n        return null;\n    }\n\n    @Override\n    public String getConfigAndSignListener(String dataId, String group, long timeoutMs, Listener listener)\n            throws NacosException {\n        return null;\n    }\n\n    @Override\n    public void addListener(String dataId, String group, Listener listener) throws NacosException {}\n\n    @Override\n    public boolean publishConfig(String dataId, String group, String content) throws NacosException {\n        return false;\n    }\n\n    @Override\n    public boolean publishConfig(String dataId, String group, String content, String type) throws NacosException {\n        return false;\n    }\n\n    @Override\n    public boolean publishConfigCas(String dataId, String group, String content, String casMd5) throws NacosException {\n        return false;\n    }\n\n    @Override\n    public boolean publishConfigCas(String dataId, String group, String content, String casMd5, String type)\n            throws NacosException {\n        return false;\n    }\n\n    @Override\n    public boolean removeConfig(String dataId, String group) throws NacosException {\n        return false;\n    }\n\n    @Override\n    public void removeListener(String dataId, String group, Listener listener) {}\n\n    @Override\n    public String getServerStatus() {\n        return null;\n    }\n\n    @Override\n    public void shutDown() throws NacosException {}\n\n    @Override\n    public void addConfigFilter(IConfigFilter iConfigFilter) {}\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\n\nimport com.alibaba.nacos.api.NacosFactory;\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * Unit test for nacos config center support\n */\n// FIXME: waiting for embedded Nacos support, then we can open the switch.\n@Disabled(\"https://github.com/alibaba/nacos/issues/1188\")\nclass NacosDynamicConfigurationTest {\n    private static final Logger logger = LoggerFactory.getLogger(NacosDynamicConfigurationTest.class);\n    private static final String SESSION_TIMEOUT_KEY = \"session\";\n\n    private static NacosDynamicConfiguration config;\n\n    /**\n     * A test client to put data to Nacos server for testing purpose\n     */\n    private static ConfigService nacosClient;\n\n    @Test\n    void testGetConfig() throws Exception {\n        put(\"org.apache.dubbo.nacos.testService.configurators\", \"hello\");\n        Thread.sleep(200);\n        put(\"dubbo.properties\", \"test\", \"aaa=bbb\");\n        Thread.sleep(200);\n        put(\"org.apache.dubbo.demo.DemoService:1.0.0.test:xxxx.configurators\", \"helloworld\");\n        Thread.sleep(200);\n        Assertions.assertEquals(\n                \"hello\",\n                config.getConfig(\n                        \"org.apache.dubbo.nacos.testService.configurators\", DynamicConfiguration.DEFAULT_GROUP));\n        Assertions.assertEquals(\"aaa=bbb\", config.getConfig(\"dubbo.properties\", \"test\"));\n        Assertions.assertEquals(\n                \"helloworld\",\n                config.getConfig(\n                        \"org.apache.dubbo.demo.DemoService:1.0.0.test:xxxx.configurators\",\n                        DynamicConfiguration.DEFAULT_GROUP));\n    }\n\n    @Test\n    void testAddListener() throws Exception {\n        CountDownLatch latch = new CountDownLatch(4);\n        TestListener listener1 = new TestListener(latch);\n        TestListener listener2 = new TestListener(latch);\n        TestListener listener3 = new TestListener(latch);\n        TestListener listener4 = new TestListener(latch);\n\n        config.addListener(\"AService.configurators\", listener1);\n        config.addListener(\"AService.configurators\", listener2);\n        config.addListener(\"testapp.tag-router\", listener3);\n        config.addListener(\"testapp.tag-router\", listener4);\n\n        put(\"AService.configurators\", \"new value1\");\n        Thread.sleep(200);\n        put(\"testapp.tag-router\", \"new value2\");\n        Thread.sleep(200);\n        put(\"testapp\", \"new value3\");\n        Thread.sleep(5000);\n\n        latch.await();\n\n        Assertions.assertEquals(1, listener1.getCount(\"AService.configurators\"));\n        Assertions.assertEquals(1, listener2.getCount(\"AService.configurators\"));\n        Assertions.assertEquals(1, listener3.getCount(\"testapp.tag-router\"));\n        Assertions.assertEquals(1, listener4.getCount(\"testapp.tag-router\"));\n\n        Assertions.assertEquals(\"new value1\", listener1.getValue());\n        Assertions.assertEquals(\"new value1\", listener2.getValue());\n        Assertions.assertEquals(\"new value2\", listener3.getValue());\n        Assertions.assertEquals(\"new value2\", listener4.getValue());\n    }\n    //\n    //    @Test\n    //    public void testGetConfigKeys() {\n    //\n    //        put(\"key1\", \"a\");\n    //        put(\"key2\", \"b\");\n    //\n    //        SortedSet<String> keys = config.getConfigKeys(DynamicConfiguration.DEFAULT_GROUP);\n    //\n    //        Assertions.assertFalse(keys.isEmpty());\n    //\n    //    }\n\n    private void put(String key, String value) {\n        put(key, DynamicConfiguration.DEFAULT_GROUP, value);\n    }\n\n    private void put(String key, String group, String value) {\n        try {\n            nacosClient.publishConfig(key, group, value);\n        } catch (Exception e) {\n            logger.error(\"Error put value to nacos.\");\n        }\n    }\n\n    @BeforeAll\n    public static void setUp() {\n        String urlForDubbo = \"nacos://\" + \"127.0.0.1:8848\" + \"/org.apache.dubbo.nacos.testService\";\n        // timeout in 15 seconds.\n        URL url = URL.valueOf(urlForDubbo).addParameter(SESSION_TIMEOUT_KEY, 15000);\n        config = new NacosDynamicConfiguration(url, ApplicationModel.defaultModel());\n\n        try {\n            nacosClient = NacosFactory.createConfigService(\"127.0.0.1:8848\");\n        } catch (NacosException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Test\n    void testPublishConfig() {\n        String key = \"user-service\";\n        String group = \"org.apache.dubbo.service.UserService\";\n        String content = \"test\";\n\n        assertTrue(config.publishConfig(key, group, content));\n        assertEquals(\"test\", config.getProperties(key, group));\n    }\n\n    @AfterAll\n    public static void tearDown() {}\n\n    private class TestListener implements ConfigurationListener {\n        private CountDownLatch latch;\n        private String value;\n        private Map<String, Integer> countMap = new HashMap<>();\n\n        public TestListener(CountDownLatch latch) {\n            this.latch = latch;\n        }\n\n        @Override\n        public void process(ConfigChangedEvent event) {\n            logger.info(\"{}: {}\", this, event);\n            Integer count = countMap.computeIfAbsent(event.getKey(), k -> 0);\n            countMap.put(event.getKey(), ++count);\n            value = event.getContent();\n            latch.countDown();\n        }\n\n        public int getCount(String key) {\n            return countMap.get(key);\n        }\n\n        public String getValue() {\n            return value;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/RetryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Properties;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.alibaba.nacos.api.NacosFactory;\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.DOWN;\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP;\nimport static org.mockito.ArgumentMatchers.any;\n\nclass RetryTest {\n\n    private static ApplicationModel applicationModel = ApplicationModel.defaultModel();\n\n    @Test\n    void testRetryCreate() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            AtomicInteger atomicInteger = new AtomicInteger(0);\n            ConfigService mock = new MockConfigService() {\n                @Override\n                public String getServerStatus() {\n                    return atomicInteger.incrementAndGet() > 10 ? UP : DOWN;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createConfigService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10);\n            Assertions.assertThrows(\n                    IllegalStateException.class, () -> new NacosDynamicConfiguration(url, applicationModel));\n\n            try {\n                new NacosDynamicConfiguration(url, applicationModel);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n\n    @Test\n    void testDisable() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            ConfigService mock = new MockConfigService() {\n                @Override\n                public String getServerStatus() {\n                    return DOWN;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createConfigService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10)\n                    .addParameter(\"nacos.check\", \"false\");\n            try {\n                new NacosDynamicConfiguration(url, applicationModel);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n\n    @Test\n    void testRequest() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            AtomicInteger atomicInteger = new AtomicInteger(0);\n            ConfigService mock = new MockConfigService() {\n                @Override\n                public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {\n                    if (atomicInteger.incrementAndGet() > 10) {\n                        return \"\";\n                    } else {\n                        throw new NacosException();\n                    }\n                }\n\n                @Override\n                public String getServerStatus() {\n                    return UP;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createConfigService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10);\n            Assertions.assertThrows(\n                    IllegalStateException.class, () -> new NacosDynamicConfiguration(url, applicationModel));\n\n            try {\n                new NacosDynamicConfiguration(url, applicationModel);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-nacos/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-configcenter</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-configcenter-zookeeper</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The zookeeper implementation of the config-center api</description>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-zookeeper-curator5</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-framework</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-recipes</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.zookeeper</groupId>\n      <artifactId>zookeeper</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-prometheus</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-config-center</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n  </dependencies>\n\n  <profiles>\n    <profile>\n      <id>curator5</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-remoting-zookeeper-curator5</artifactId>\n          <version>${project.parent.version}</version>\n        </dependency>\n      </dependencies>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/CacheListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.zookeeper;\n\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * one path has one zookeeperDataListener\n */\npublic class CacheListener {\n\n    private final ConcurrentMap<String, ZookeeperDataListener> pathKeyListeners = new ConcurrentHashMap<>();\n\n    public CacheListener() {}\n\n    public ZookeeperDataListener addListener(\n            String pathKey,\n            ConfigurationListener configurationListener,\n            String key,\n            String group,\n            ApplicationModel applicationModel) {\n        ZookeeperDataListener zookeeperDataListener = ConcurrentHashMapUtils.computeIfAbsent(\n                pathKeyListeners,\n                pathKey,\n                _pathKey -> new ZookeeperDataListener(_pathKey, key, group, applicationModel));\n        zookeeperDataListener.addListener(configurationListener);\n        return zookeeperDataListener;\n    }\n\n    public ZookeeperDataListener removeListener(String pathKey, ConfigurationListener configurationListener) {\n        ZookeeperDataListener zookeeperDataListener = pathKeyListeners.get(pathKey);\n        if (zookeeperDataListener != null) {\n            zookeeperDataListener.removeListener(configurationListener);\n            if (CollectionUtils.isEmpty(zookeeperDataListener.getListeners())) {\n                pathKeyListeners.remove(pathKey);\n            }\n        }\n        return zookeeperDataListener;\n    }\n\n    public ZookeeperDataListener getCachedListener(String pathKey) {\n        return pathKeyListeners.get(pathKey);\n    }\n\n    public Map<String, ZookeeperDataListener> getPathKeyListeners() {\n        return pathKeyListeners;\n    }\n\n    public void clear() {\n        pathKeyListeners.clear();\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDataListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.zookeeper;\n\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metrics.config.event.ConfigCenterEvent;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.remoting.zookeeper.curator5.DataListener;\nimport org.apache.dubbo.remoting.zookeeper.curator5.EventType;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE;\n\n/**\n * one path has multi configurationListeners\n */\npublic class ZookeeperDataListener implements DataListener {\n\n    private String path;\n    private String key;\n    private String group;\n    private Set<ConfigurationListener> listeners;\n    private ApplicationModel applicationModel;\n\n    public ZookeeperDataListener(String path, String key, String group, ApplicationModel applicationModel) {\n        this.path = path;\n        this.key = key;\n        this.group = group;\n        this.listeners = new CopyOnWriteArraySet<>();\n        this.applicationModel = applicationModel;\n    }\n\n    public void addListener(ConfigurationListener configurationListener) {\n        listeners.add(configurationListener);\n    }\n\n    public void removeListener(ConfigurationListener configurationListener) {\n        listeners.remove(configurationListener);\n    }\n\n    public Set<ConfigurationListener> getListeners() {\n        return listeners;\n    }\n\n    @Override\n    public void dataChanged(String path, Object value, EventType eventType) {\n        if (!this.path.equals(path)) {\n            return;\n        }\n        ConfigChangeType changeType;\n        if (EventType.NodeCreated.equals(eventType)) {\n            changeType = ConfigChangeType.ADDED;\n        } else if (value == null) {\n            changeType = ConfigChangeType.DELETED;\n        } else {\n            changeType = ConfigChangeType.MODIFIED;\n        }\n        ConfigChangedEvent configChangeEvent = new ConfigChangedEvent(key, group, (String) value, changeType);\n        if (CollectionUtils.isNotEmpty(listeners)) {\n            listeners.forEach(listener -> listener.process(configChangeEvent));\n        }\n\n        MetricsEventBus.publish(ConfigCenterEvent.toChangeEvent(\n                applicationModel,\n                configChangeEvent.getKey(),\n                configChangeEvent.getGroup(),\n                ConfigCenterEvent.ZK_PROTOCOL,\n                ConfigChangeType.ADDED.name(),\n                SELF_INCREMENT_SIZE));\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.TreePathDynamicConfiguration;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClient;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClientManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.data.Stat;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_CONNECT_REGISTRY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_ZOOKEEPER_EXCEPTION;\n\npublic class ZookeeperDynamicConfiguration extends TreePathDynamicConfiguration {\n\n    private final Executor executor;\n    private ZookeeperClient zkClient;\n\n    private final CacheListener cacheListener;\n    private static final int DEFAULT_ZK_EXECUTOR_THREADS_NUM = 1;\n    private static final int DEFAULT_QUEUE = 10000;\n    private static final Long THREAD_KEEP_ALIVE_TIME = 0L;\n    private final ApplicationModel applicationModel;\n\n    ZookeeperDynamicConfiguration(\n            URL url, ZookeeperClientManager zookeeperClientManager, ApplicationModel applicationModel) {\n        super(url);\n\n        this.cacheListener = new CacheListener();\n        this.applicationModel = applicationModel;\n\n        final String threadName = this.getClass().getSimpleName();\n        this.executor = new ThreadPoolExecutor(\n                DEFAULT_ZK_EXECUTOR_THREADS_NUM,\n                DEFAULT_ZK_EXECUTOR_THREADS_NUM,\n                THREAD_KEEP_ALIVE_TIME,\n                TimeUnit.MILLISECONDS,\n                new LinkedBlockingQueue<>(DEFAULT_QUEUE),\n                new NamedThreadFactory(threadName, true),\n                new AbortPolicyWithReport(threadName, url));\n\n        zkClient = zookeeperClientManager.connect(url);\n        boolean isConnected = zkClient.isConnected();\n        if (!isConnected) {\n\n            IllegalStateException illegalStateException = new IllegalStateException(\n                    \"Failed to connect with zookeeper, pls check if url \" + url + \" is correct.\");\n\n            if (logger != null) {\n                logger.error(\n                        CONFIG_FAILED_CONNECT_REGISTRY,\n                        \"configuration server offline\",\n                        \"\",\n                        \"Failed to connect with zookeeper\",\n                        illegalStateException);\n            }\n\n            throw illegalStateException;\n        }\n    }\n\n    /**\n     * @param key e.g., {service}.configurators, {service}.tagrouters, {group}.dubbo.properties\n     * @return\n     */\n    @Override\n    public String getInternalProperty(String key) {\n        return zkClient.getContent(buildPathKey(\"\", key));\n    }\n\n    @Override\n    protected void doClose() throws Exception {\n        // remove data listener\n        Map<String, ZookeeperDataListener> pathKeyListeners = cacheListener.getPathKeyListeners();\n        for (Map.Entry<String, ZookeeperDataListener> entry : pathKeyListeners.entrySet()) {\n            zkClient.removeDataListener(entry.getKey(), entry.getValue());\n        }\n        cacheListener.clear();\n\n        // zkClient is shared in framework, should not close it here\n        // zkClient.close();\n        // See: org.apache.dubbo.remoting.zookeeper.AbstractZookeeperTransporter#destroy()\n        // All zk clients is created and destroyed in ZookeeperTransporter.\n        zkClient = null;\n    }\n\n    @Override\n    protected boolean doPublishConfig(String pathKey, String content) throws Exception {\n        zkClient.createOrUpdate(pathKey, content, false);\n        return true;\n    }\n\n    @Override\n    public boolean publishConfigCas(String key, String group, String content, Object ticket) {\n        try {\n            if (ticket != null && !(ticket instanceof Stat)) {\n                throw new IllegalArgumentException(\"zookeeper publishConfigCas requires stat type ticket\");\n            }\n            String pathKey = buildPathKey(group, key);\n            zkClient.createOrUpdate(pathKey, content, false, ticket == null ? 0 : ((Stat) ticket).getVersion());\n            return true;\n        } catch (Exception e) {\n            logger.warn(REGISTRY_ZOOKEEPER_EXCEPTION, \"\", \"\", \"zookeeper publishConfigCas failed.\", e);\n            return false;\n        }\n    }\n\n    @Override\n    protected String doGetConfig(String pathKey) throws Exception {\n        return zkClient.getContent(pathKey);\n    }\n\n    @Override\n    public ConfigItem getConfigItem(String key, String group) {\n        String pathKey = buildPathKey(group, key);\n        return zkClient.getConfigItem(pathKey);\n    }\n\n    @Override\n    protected boolean doRemoveConfig(String pathKey) throws Exception {\n        zkClient.delete(pathKey);\n        return true;\n    }\n\n    @Override\n    protected Collection<String> doGetConfigKeys(String groupPath) {\n        return zkClient.getChildren(groupPath);\n    }\n\n    @Override\n    protected void doAddListener(String pathKey, ConfigurationListener listener, String key, String group) {\n        ZookeeperDataListener cachedListener = cacheListener.getCachedListener(pathKey);\n        if (cachedListener != null) {\n            cachedListener.addListener(listener);\n        } else {\n            ZookeeperDataListener addedListener =\n                    cacheListener.addListener(pathKey, listener, key, group, applicationModel);\n            zkClient.addDataListener(pathKey, addedListener, executor);\n        }\n    }\n\n    @Override\n    protected void doRemoveListener(String pathKey, ConfigurationListener listener) {\n        ZookeeperDataListener zookeeperDataListener = cacheListener.removeListener(pathKey, listener);\n        if (zookeeperDataListener != null && CollectionUtils.isEmpty(zookeeperDataListener.getListeners())) {\n            zkClient.removeDataListener(pathKey, zookeeperDataListener);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClientManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\npublic class ZookeeperDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory {\n\n    private final ZookeeperClientManager zookeeperClientManager;\n\n    private final ApplicationModel applicationModel;\n\n    public ZookeeperDynamicConfigurationFactory(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        this.zookeeperClientManager = ZookeeperClientManager.getInstance(applicationModel);\n    }\n\n    @Override\n    protected DynamicConfiguration createDynamicConfiguration(URL url) {\n        return new ZookeeperDynamicConfiguration(url, zookeeperClientManager, applicationModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory",
    "content": "zookeeper=org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory"
  },
  {
    "path": "dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.configcenter.support.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * TODO refactor using mockito\n */\n@Disabled(\"Disabled Due to Zookeeper in Github Actions\")\nclass ZookeeperDynamicConfigurationTest {\n    private static CuratorFramework client;\n\n    private static URL configUrl;\n    private static DynamicConfiguration configuration;\n    private static int zookeeperServerPort1;\n    private static String zookeeperConnectionAddress1;\n\n    @BeforeAll\n    public static void setUp() throws Exception {\n        zookeeperConnectionAddress1 = System.getProperty(\"zookeeper.connection.address.1\");\n        zookeeperServerPort1 = Integer.parseInt(\n                zookeeperConnectionAddress1.substring(zookeeperConnectionAddress1.lastIndexOf(\":\") + 1));\n\n        client = CuratorFrameworkFactory.newClient(\n                \"127.0.0.1:\" + zookeeperServerPort1, 60 * 1000, 60 * 1000, new ExponentialBackoffRetry(1000, 3));\n        client.start();\n\n        try {\n            setData(\"/dubbo/config/dubbo/dubbo.properties\", \"The content from dubbo.properties\");\n            setData(\"/dubbo/config/dubbo/service:version:group.configurators\", \"The content from configurators\");\n            setData(\"/dubbo/config/appname\", \"The content from higher level node\");\n            setData(\"/dubbo/config/dubbo/appname.tag-router\", \"The content from appname tagrouters\");\n            setData(\n                    \"/dubbo/config/dubbo/never.change.DemoService.configurators\",\n                    \"Never change value from configurators\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        configUrl = URL.valueOf(zookeeperConnectionAddress1);\n        configuration = ExtensionLoader.getExtensionLoader(DynamicConfigurationFactory.class)\n                .getExtension(configUrl.getProtocol())\n                .getDynamicConfiguration(configUrl);\n    }\n\n    private static void setData(String path, String data) throws Exception {\n        if (client.checkExists().forPath(path) == null) {\n            client.create().creatingParentsIfNeeded().forPath(path);\n        }\n        client.setData().forPath(path, data.getBytes());\n    }\n\n    private ConfigurationListener mockListener(CountDownLatch latch, String[] value, Map<String, Integer> countMap) {\n        ConfigurationListener listener = Mockito.mock(ConfigurationListener.class);\n        Mockito.doAnswer(invoke -> {\n                    ConfigChangedEvent event = invoke.getArgument(0);\n                    Integer count = countMap.computeIfAbsent(event.getKey(), k -> 0);\n                    countMap.put(event.getKey(), ++count);\n                    value[0] = event.getContent();\n                    latch.countDown();\n                    return null;\n                })\n                .when(listener)\n                .process(Mockito.any());\n        return listener;\n    }\n\n    @Test\n    void testGetConfig() {\n        Assertions.assertEquals(\n                \"The content from dubbo.properties\", configuration.getConfig(\"dubbo.properties\", \"dubbo\"));\n    }\n\n    @Test\n    void testAddListener() throws Exception {\n        CountDownLatch latch = new CountDownLatch(4);\n\n        String[] value1 = new String[1], value2 = new String[1], value3 = new String[1], value4 = new String[1];\n        Map<String, Integer> countMap1 = new HashMap<>(),\n                countMap2 = new HashMap<>(),\n                countMap3 = new HashMap<>(),\n                countMap4 = new HashMap<>();\n        ConfigurationListener listener1 = mockListener(latch, value1, countMap1);\n        ConfigurationListener listener2 = mockListener(latch, value2, countMap2);\n        ConfigurationListener listener3 = mockListener(latch, value3, countMap3);\n        ConfigurationListener listener4 = mockListener(latch, value4, countMap4);\n\n        configuration.addListener(\"service:version:group.configurators\", listener1);\n        configuration.addListener(\"service:version:group.configurators\", listener2);\n        configuration.addListener(\"appname.tag-router\", listener3);\n        configuration.addListener(\"appname.tag-router\", listener4);\n\n        Thread.sleep(100);\n        setData(\"/dubbo/config/dubbo/service:version:group.configurators\", \"new value1\");\n        Thread.sleep(100);\n        setData(\"/dubbo/config/dubbo/appname.tag-router\", \"new value2\");\n        Thread.sleep(100);\n        setData(\"/dubbo/config/appname\", \"new value3\");\n\n        Thread.sleep(5000);\n\n        latch.await();\n\n        Assertions.assertEquals(1, countMap1.get(\"service:version:group.configurators\"));\n        Assertions.assertEquals(1, countMap2.get(\"service:version:group.configurators\"));\n        Assertions.assertEquals(1, countMap3.get(\"appname.tag-router\"));\n        Assertions.assertEquals(1, countMap4.get(\"appname.tag-router\"));\n\n        Assertions.assertEquals(\"new value1\", value1[0]);\n        Assertions.assertEquals(\"new value1\", value2[0]);\n        Assertions.assertEquals(\"new value2\", value3[0]);\n        Assertions.assertEquals(\"new value2\", value4[0]);\n    }\n\n    @Test\n    void testPublishConfig() {\n        String key = \"user-service\";\n        String group = \"org.apache.dubbo.service.UserService\";\n        String content = \"test\";\n\n        assertTrue(configuration.publishConfig(key, group, content));\n        assertEquals(\"test\", configuration.getProperties(key, group));\n    }\n\n    @Test\n    void testPublishConfigCas() {\n        String key = \"user-service-cas\";\n        String group = \"org.apache.dubbo.service.UserService\";\n        String content = \"test\";\n        ConfigItem configItem = configuration.getConfigItem(key, group);\n        assertTrue(configuration.publishConfigCas(key, group, content, configItem.getTicket()));\n        configItem = configuration.getConfigItem(key, group);\n        assertEquals(\"test\", configItem.getContent());\n        assertTrue(configuration.publishConfigCas(key, group, \"newtest\", configItem.getTicket()));\n        assertFalse(configuration.publishConfigCas(key, group, \"newtest2\", configItem.getTicket()));\n        assertEquals(\"newtest\", configuration.getConfigItem(key, group).getContent());\n    }\n    //\n    //    @Test\n    //    public void testGetConfigKeysAndContents() {\n    //\n    //        String group = \"mapping\";\n    //        String key = \"org.apache.dubbo.service.UserService\";\n    //        String content = \"app1\";\n    //\n    //        String key2 = \"org.apache.dubbo.service.UserService2\";\n    //\n    //        assertTrue(configuration.publishConfig(key, group, content));\n    //        assertTrue(configuration.publishConfig(key2, group, content));\n    //\n    //        Set<String> configKeys = configuration.getConfigKeys(group);\n    //\n    //        assertEquals(new TreeSet(asList(key, key2)), configKeys);\n    //    }\n\n}\n"
  },
  {
    "path": "dubbo-configcenter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-configcenter</artifactId>\n  <packaging>pom</packaging>\n  <name>${project.artifactId}</name>\n  <description>The service config-center module of the Dubbo project</description>\n\n  <modules>\n    <module>dubbo-configcenter-zookeeper</module>\n    <module>dubbo-configcenter-apollo</module>\n    <module>dubbo-configcenter-nacos</module>\n    <module>dubbo-configcenter-file</module>\n  </modules>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n</project>\n"
  },
  {
    "path": "dubbo-demo/README.md",
    "content": "# Dubbo Demo\n\nThis directory contains basic Dubbo usages to help Dubbo developers with debugging and smoke test purposes. Check [dubbo-samples](https://github.com/apache/dubbo-samples) repository for more examples that showcase Dubbo's rich features.\n\n## Brief introduction\n\n1. **`dubbo-demo-api`**\n   This demo demonstrates the basic usage of Dubbo's RPC protocol, serving as a fundamental example. It showcases how to define and implement a simple RPC service using Dubbo, how to start a server that serves at a specified port and then a consumer that consumes the service. \n2. **`dubbo-demo-springboot`**\n   This demo illustrates the integration of Dubbo with Spring Boot, showing how Dubbo services can be utilized and configured within a Spring Boot application. It demonstrates how to configure and manage Dubbo services seamlessly through Spring Boot, making it ideal for developers leveraging the popular Spring Boot framework.\n3. **`dubbo-demo-springboot-idl`**\n   This demo focuses on showcasing how to use Dubbo with Spring Boot when IDL (Interface Definition Language) files such as Proto files are available. It illustrates how developers can work with Dubbo services defined through IDL, integrating them into a Spring Boot application.\n\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-demo-api</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-demo-api-consumer</artifactId>\n\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-demo-api-interface</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-dubbo</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.demo.consumer;\n\nimport org.apache.dubbo.api.demo.DemoService;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class Application {\n    private static final Logger logger = LoggerFactory.getLogger(Application.class);\n\n    private static final String ZOOKEEPER_URL = \"zookeeper://127.0.0.1:2181\";\n\n    public static void main(String[] args) {\n        runWithBootstrap();\n    }\n\n    private static void runWithBootstrap() {\n        ReferenceConfig<DemoService> reference = new ReferenceConfig<>();\n        reference.setInterface(DemoService.class);\n        reference.setGeneric(\"true\");\n\n        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();\n        configCenterConfig.setAddress(ZOOKEEPER_URL);\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance();\n        bootstrap\n                .application(new ApplicationConfig(\"dubbo-demo-api-consumer\"))\n                .configCenter(configCenterConfig)\n                .registry(new RegistryConfig(ZOOKEEPER_URL))\n                .metadataReport(new MetadataReportConfig(ZOOKEEPER_URL))\n                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, -1))\n                .reference(reference)\n                .start();\n\n        DemoService demoService = bootstrap.getCache().get(reference);\n        String message = demoService.sayHello(\"dubbo\");\n        logger.info(message);\n\n        // generic invoke\n        GenericService genericService = (GenericService) demoService;\n        Object genericInvokeResult = genericService.$invoke(\n                \"sayHello\", new String[] {String.class.getName()}, new Object[] {\"dubbo generic invoke\"});\n        logger.info(genericInvokeResult.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%style{%d{HH:mm:ss.SSS}}{Magenta} %style{|-}{White}%highlight{%-5p} [%t] %style{%40.40c}{Cyan}:%style{%-3L}{Blue} %style{-|}{White} %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect)}\" disableAnsi=\"false\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-api/dubbo-demo-api-interface/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-demo-api</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-demo-api-interface</artifactId>\n\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n  </properties>\n\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-api/dubbo-demo-api-interface/src/main/java/org/apache/dubbo/api/demo/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.api.demo;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic interface DemoService {\n\n    String sayHello(String name);\n\n    /**\n     * Asynchronous method example.\n     * <p>\n     * This method returns a {@link CompletableFuture<String>} to demonstrate Dubbo's asynchronous invocation capability.\n     * Developers are recommended to refer to the official sample project for complete usage:\n     * <a href=\"https://github.com/lqscript/dubbo-samples/tree/master/2-advanced/dubbo-samples-async/dubbo-samples-async-original-future\">\n     *     Dubbo Async Invocation Sample</a>\n     * </p>\n     *\n     * @param name Input name parameter\n     * @return Asynchronous result wrapped in CompletableFuture\n     */\n    default CompletableFuture<String> sayHelloAsync(String name) {\n        return CompletableFuture.completedFuture(sayHello(name));\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-demo-api</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-demo-api-provider</artifactId>\n\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-demo-api-interface</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-dubbo</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.demo.provider;\n\nimport org.apache.dubbo.api.demo.DemoService;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\npublic class Application {\n\n    private static final String ZOOKEEPER_URL = \"zookeeper://127.0.0.1:2181\";\n\n    public static void main(String[] args) {\n        startWithBootstrap();\n    }\n\n    private static void startWithBootstrap() {\n        ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();\n        service.setInterface(DemoService.class);\n        service.setRef(new DemoServiceImpl());\n\n        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();\n        configCenterConfig.setAddress(ZOOKEEPER_URL);\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance();\n        bootstrap\n                .application(new ApplicationConfig(\"dubbo-demo-api-provider\"))\n                .configCenter(configCenterConfig)\n                .registry(new RegistryConfig(ZOOKEEPER_URL))\n                .metadataReport(new MetadataReportConfig(ZOOKEEPER_URL))\n                .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1))\n                .service(service)\n                .start()\n                .await();\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.demo.provider;\n\nimport org.apache.dubbo.api.demo.DemoService;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class DemoServiceImpl implements DemoService {\n    private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);\n\n    @Override\n    public String sayHello(String name) {\n        logger.info(\"Hello \" + name + \", request from consumer: \"\n                + RpcContext.getServiceContext().getRemoteAddress());\n        return \"Hello \" + name + \", response from provider: \"\n                + RpcContext.getServiceContext().getLocalAddress();\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%style{%d{HH:mm:ss.SSS}}{Magenta} %style{|-}{White}%highlight{%-5p} [%t] %style{%40.40c}{Cyan}:%style{%-3L}{Blue} %style{-|}{White} %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect)}\" disableAnsi=\"false\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-demo-api</artifactId>\n  <packaging>pom</packaging>\n\n  <modules>\n    <module>dubbo-demo-api-provider</module>\n    <module>dubbo-demo-api-consumer</module>\n    <module>dubbo-demo-api-interface</module>\n  </modules>\n\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n    <spring-boot-maven-plugin.version>2.7.18</spring-boot-maven-plugin.version>\n  </properties>\n\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-mcp-server/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-demo-mcp-server</artifactId>\n\n  <properties>\n    <spring-boot-maven-plugin.version>2.7.18</spring-boot-maven-plugin.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n      <exclusions>\n        <exclusion>\n          <groupId>com.google.protobuf</groupId>\n          <artifactId>protobuf-java-util</artifactId>\n        </exclusion>\n        <exclusion>\n          <groupId>com.google.protobuf</groupId>\n          <artifactId>protobuf-java</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-triple-servlet</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rest-openapi</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-mcp</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-spring-boot-autoconfigure</artifactId>\n      <version>${project.version}</version>\n      <exclusions>\n        <exclusion>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-log4j2</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter</artifactId>\n      <exclusions>\n        <exclusion>\n          <groupId>org.springframework.boot</groupId>\n          <artifactId>spring-boot-starter-logging</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n\n    <!-- generate json format javadoc for openapi -->\n    <dependency>\n      <groupId>com.github.therapi</groupId>\n      <artifactId>therapi-runtime-javadoc-scribe</artifactId>\n      <version>0.15.0</version>\n      <scope>provided</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n        <version>${spring-boot-maven-plugin.version}</version>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <configuration>\n          <compilerArgs>\n            <compilerArg>-parameters</compilerArg>\n          </compilerArgs>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>jdk-version-ge-17</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-spring-boot-3-autoconfigure</artifactId>\n          <version>${project.version}</version>\n        </dependency>\n      </dependencies>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-mcp-server/src/main/java/org/apache/dubbo/mcp/server/demo/McpDemoApplication.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.server.demo;\n\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\n@EnableDubbo\npublic class McpDemoApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(McpDemoApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-mcp-server/src/main/java/org/apache/dubbo/mcp/server/demo/demo/ComplexRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.server.demo.demo;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic class ComplexRequest {\n    private String greeting;\n    private int count;\n    private boolean active;\n    private NestedDetail nestedDetail;\n    private List<String> tags;\n    private Map<String, String> attributes;\n\n    // Default constructor (important for deserialization)\n    public ComplexRequest() {}\n\n    // Getters and Setters\n    public String getGreeting() {\n        return greeting;\n    }\n\n    public void setGreeting(String greeting) {\n        this.greeting = greeting;\n    }\n\n    public int getCount() {\n        return count;\n    }\n\n    public void setCount(int count) {\n        this.count = count;\n    }\n\n    public boolean isActive() {\n        return active;\n    }\n\n    public void setActive(boolean active) {\n        this.active = active;\n    }\n\n    public NestedDetail getNestedDetail() {\n        return nestedDetail;\n    }\n\n    public void setNestedDetail(NestedDetail nestedDetail) {\n        this.nestedDetail = nestedDetail;\n    }\n\n    public List<String> getTags() {\n        return tags;\n    }\n\n    public void setTags(List<String> tags) {\n        this.tags = tags;\n    }\n\n    public Map<String, String> getAttributes() {\n        return attributes;\n    }\n\n    public void setAttributes(Map<String, String> attributes) {\n        this.attributes = attributes;\n    }\n\n    @Override\n    public String toString() {\n        return \"ComplexRequest{\" + \"greeting='\"\n                + greeting + '\\'' + \", count=\"\n                + count + \", active=\"\n                + active + \", nestedDetail=\"\n                + nestedDetail + \", tags=\"\n                + tags + \", attributes=\"\n                + attributes + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-mcp-server/src/main/java/org/apache/dubbo/mcp/server/demo/demo/ComplexResponse.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.server.demo.demo;\n\npublic class ComplexResponse {\n    private String message;\n    private boolean success;\n    private int code;\n\n    // Default constructor\n    public ComplexResponse() {}\n\n    public ComplexResponse(String message, boolean success, int code) {\n        this.message = message;\n        this.success = success;\n        this.code = code;\n    }\n\n    // Getters and Setters\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public boolean isSuccess() {\n        return success;\n    }\n\n    public void setSuccess(boolean success) {\n        this.success = success;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    @Override\n    public String toString() {\n        return \"ComplexResponse{\" + \"message='\" + message + '\\'' + \", success=\" + success + \", code=\" + code + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-mcp-server/src/main/java/org/apache/dubbo/mcp/server/demo/demo/HelloService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.server.demo.demo;\n\nimport org.apache.dubbo.mcp.annotations.McpTool;\nimport org.apache.dubbo.remoting.http12.rest.Mapping;\n\n@Mapping(\"\")\npublic interface HelloService {\n    @McpTool\n    @Mapping(\"/hello\")\n    String sayHello(String name);\n\n    @McpTool\n    @Mapping(\"/greetComplex\")\n    ComplexResponse greetComplex(ComplexRequest request);\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-mcp-server/src/main/java/org/apache/dubbo/mcp/server/demo/demo/HelloServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.server.demo.demo;\n\nimport org.apache.dubbo.config.annotation.DubboService;\n\n@DubboService(mcpEnabled = true)\npublic class HelloServiceImpl implements HelloService {\n    @Override\n    public String sayHello(String name) {\n        System.out.println(\"HelloServiceImpl.sayHello called with: \" + name);\n        if (name == null || name.trim().isEmpty()) {\n            return \"Hello, guest!\";\n        }\n        return \"Hello, \" + name + \"!\";\n    }\n\n    @Override\n    public ComplexResponse greetComplex(ComplexRequest request) {\n        System.out.println(\"HelloServiceImpl.greetComplex called with: \" + request);\n        if (request == null) {\n            return new ComplexResponse(\"Error: Request was null\", false, 400);\n        }\n        String message = \"Received: \" + request.getGreeting() + \". Count: \"\n                + request.getCount() + \". Active: \"\n                + request.isActive() + \". Detail: \"\n                + (request.getNestedDetail() != null ? request.getNestedDetail().getDetailInfo() : \"N/A\") + \". Tags: \"\n                + (request.getTags() != null ? String.join(\", \", request.getTags()) : \"None\") + \". Attributes: \"\n                + (request.getAttributes() != null ? request.getAttributes().toString() : \"None\");\n        return new ComplexResponse(message, true, 200);\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-mcp-server/src/main/java/org/apache/dubbo/mcp/server/demo/demo/NestedDetail.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.server.demo.demo;\n\npublic class NestedDetail {\n    private String detailInfo;\n    private Double value;\n\n    // Default constructor\n    public NestedDetail() {}\n\n    // Getters and Setters\n    public String getDetailInfo() {\n        return detailInfo;\n    }\n\n    public void setDetailInfo(String detailInfo) {\n        this.detailInfo = detailInfo;\n    }\n\n    public Double getValue() {\n        return value;\n    }\n\n    public void setValue(Double value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return \"NestedDetail{\" + \"detailInfo='\" + detailInfo + '\\'' + \", value=\" + value + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-mcp-server/src/main/resources/application.yml",
    "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, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nspring:\n  application:\n    name: dubbo-mcp-server\ndubbo:\n  application:\n    name: ${spring.application.name}\n    qos-enable: false\n  protocol:\n    name: tri\n    port: 50055\n    triple:\n      verbose: true\n      rest:\n        openapi:\n          enabled: true\n        mcp:\n          enabled: true\n          protocol: streamable\n\n\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-mcp-server/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%style{%d{HH:mm:ss.SSS}}{Magenta} %style{|-}{White}%highlight{%-5p} [%t] %style{%40.40c}{Cyan}:%style{%-3L}{Blue} %style{-|}{White} %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect)}\" disableAnsi=\"false\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n        <Logger name=\"org.apache.dubbo.rpc.protocol.tri\" level=\"debug\"/>\n        <Logger name=\"org.apache.dubbo.remoting.http12\" level=\"debug\"/>\n        <Logger name=\"org.apache.dubbo.config\" level=\"warn\"/>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-demo-spring-boot</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-demo-spring-boot-consumer</artifactId>\n\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-demo-spring-boot-interface</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <!-- Observability -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-tracing-otel-zipkin-spring-boot-starter</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-spring-boot-starter</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter</artifactId>\n      <exclusions>\n        <exclusion>\n          <groupId>org.springframework.boot</groupId>\n          <artifactId>spring-boot-starter-logging</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-log4j2</artifactId>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/src/main/java/org/apache/dubbo/springboot/demo/consumer/ConsumerApplication.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.demo.consumer;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.springboot.demo.DemoService;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.stereotype.Service;\n\n@SpringBootApplication\n@Service\n@EnableDubbo\npublic class ConsumerApplication {\n    private static final Logger logger = LoggerFactory.getLogger(ConsumerApplication.class);\n\n    @DubboReference\n    private DemoService demoService;\n\n    public static void main(String[] args) {\n\n        ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args);\n        ConsumerApplication application = context.getBean(ConsumerApplication.class);\n        String result = application.doSayHello(\"world\");\n        logger.info(\"result: {}\", result);\n\n        CompletableFuture<String> future = application.doSayHelloAsync(\"world\");\n        try {\n            logger.info(\"async call returned: {}\", future.get());\n        } catch (InterruptedException e) {\n            throw new RuntimeException(e);\n        } catch (ExecutionException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public String doSayHello(String name) {\n        return demoService.sayHello(name);\n    }\n\n    public CompletableFuture<String> doSayHelloAsync(String name) {\n        CompletableFuture<String> sayHelloAsyncFuture = demoService.sayHelloAsync(name);\n        return sayHelloAsyncFuture;\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/src/main/resources/application.yml",
    "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, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nspring:\n  application:\n    name: dubbo-springboot-demo-consumer\n\ndubbo:\n  application:\n    name: ${spring.application.name}\n    qos-port: 33333\n  protocol:\n    name: dubbo\n    port: -1\n  registry:\n    id: zk-registry\n    address: zookeeper://127.0.0.1:2181\n  config-center:\n    address: zookeeper://127.0.0.1:2181\n  metadata-report:\n    address: zookeeper://127.0.0.1:2181\n\n\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%style{%d{HH:mm:ss.SSS}}{Magenta} %style{|-}{White}%highlight{%-5p} [%t] %style{%40.40c}{Cyan}:%style{%-3L}{Blue} [%X{traceId}, %X{spanId}] %style{-|}{White} %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect)}\" disableAnsi=\"false\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-interface/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-demo-spring-boot</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-demo-spring-boot-interface</artifactId>\n\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n  </properties>\n\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-interface/src/main/java/org/apache/dubbo/springboot/demo/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.demo;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic interface DemoService {\n\n    String sayHello(String name);\n\n    default CompletableFuture<String> sayHelloAsync(String name) {\n        return CompletableFuture.completedFuture(sayHello(name));\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-demo-spring-boot</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-demo-spring-boot-provider</artifactId>\n\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-demo-spring-boot-interface</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <!-- Observability -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-tracing-otel-zipkin-spring-boot-starter</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-spring-boot-starter</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter</artifactId>\n      <exclusions>\n        <exclusion>\n          <groupId>org.springframework.boot</groupId>\n          <artifactId>spring-boot-starter-logging</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-log4j2</artifactId>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/java/org/apache/dubbo/springboot/demo/provider/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.demo.provider;\n\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.springboot.demo.DemoService;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@DubboService\npublic class DemoServiceImpl implements DemoService {\n\n    private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);\n\n    @Override\n    public String sayHello(String name) {\n        logger.info(\"Hello \" + name + \", request from consumer: \"\n                + RpcContext.getContext().getRemoteAddress());\n        return \"Hello \" + name;\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/java/org/apache/dubbo/springboot/demo/provider/ProviderApplication.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.demo.provider;\n\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\n@EnableDubbo(scanBasePackages = {\"org.apache.dubbo.springboot.demo.provider\"})\npublic class ProviderApplication {\n    public static void main(String[] args) throws Exception {\n        SpringApplication.run(ProviderApplication.class, args);\n        new CountDownLatch(1).await();\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/resources/application.yml",
    "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, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nspring:\n  application:\n    name: dubbo-springboot-demo-provider\n\ndubbo:\n  application:\n    name: ${spring.application.name}\n  protocol:\n    name: tri\n    port: -1\n  registry:\n    id: zk-registry\n    address: zookeeper://127.0.0.1:2181\n  config-center:\n    address: zookeeper://127.0.0.1:2181\n  metadata-report:\n    address: zookeeper://127.0.0.1:2181\n  metrics:\n    protocol: prometheus\n    enable-jvm: true\n    enable-registry: true\n    aggregation:\n      enabled: true\n    prometheus:\n      exporter:\n        enabled: true\n    enable-metadata: true\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%style{%d{HH:mm:ss.SSS}}{Magenta} %style{|-}{White}%highlight{%-5p} [%t] %style{%40.40c}{Cyan}:%style{%-3L}{Blue} [%X{traceId}, %X{spanId}] %style{-|}{White} %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect)}\" disableAnsi=\"false\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-demo-spring-boot</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-demo-spring-boot-servlet</artifactId>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n      <exclusions>\n        <exclusion>\n          <groupId>com.google.protobuf</groupId>\n          <artifactId>protobuf-java-util</artifactId>\n        </exclusion>\n        <exclusion>\n          <groupId>com.google.protobuf</groupId>\n          <artifactId>protobuf-java</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-triple-servlet</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rest-openapi</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-spring-boot-autoconfigure</artifactId>\n      <version>${project.version}</version>\n      <exclusions>\n        <exclusion>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-log4j2</artifactId>\n    </dependency>\n\n    <!-- generate json format javadoc for openapi -->\n    <dependency>\n      <groupId>com.github.therapi</groupId>\n      <artifactId>therapi-runtime-javadoc-scribe</artifactId>\n      <version>0.15.0</version>\n      <scope>provided</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <configuration>\n          <compilerArgs>\n            <compilerArg>-parameters</compilerArg>\n          </compilerArgs>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>jdk-version-ge-17</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-spring-boot-3-autoconfigure</artifactId>\n          <version>${project.version}</version>\n        </dependency>\n      </dependencies>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/ApiConsumer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.demo.servlet;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\n\nimport java.util.concurrent.CompletableFuture;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ApiConsumer {\n    private static final Logger logger = LoggerFactory.getLogger(ApiConsumer.class);\n\n    public static void main(String[] args) throws InterruptedException {\n        ReferenceConfig<GreeterService> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(GreeterService.class);\n        referenceConfig.setCheck(false);\n        referenceConfig.setProtocol(CommonConstants.TRIPLE);\n        referenceConfig.setLazy(true);\n        referenceConfig.setTimeout(100000);\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance();\n        bootstrap\n                .application(new ApplicationConfig(\"dubbo-demo-triple-api-consumer\"))\n                .registry(new RegistryConfig(\"zookeeper://127.0.0.1:2181\"))\n                .protocol(new ProtocolConfig(CommonConstants.TRIPLE, -1))\n                .reference(referenceConfig)\n                .start();\n\n        GreeterService greeterService = referenceConfig.get();\n        logger.info(\"dubbo referenceConfig started\");\n        logger.info(\"Call sayHello\");\n        HelloReply reply = greeterService.sayHello(buildRequest(\"triple\"));\n        logger.info(\"sayHello reply: {}\", reply.getMessage());\n\n        logger.info(\"Call sayHelloAsync\");\n        CompletableFuture<String> sayHelloAsync = greeterService.sayHelloAsync(\"triple\");\n        sayHelloAsync.thenAccept(value -> logger.info(\"sayHelloAsync reply: {}\", value));\n\n        StreamObserver<HelloReply> responseObserver = new StreamObserver<HelloReply>() {\n            @Override\n            public void onNext(HelloReply reply) {\n                logger.info(\"sayHelloServerStream onNext: {}\", reply.getMessage());\n            }\n\n            @Override\n            public void onError(Throwable t) {\n                logger.info(\"sayHelloServerStream onError: {}\", t.getMessage());\n            }\n\n            @Override\n            public void onCompleted() {\n                logger.info(\"sayHelloServerStream onCompleted\");\n            }\n        };\n        logger.info(\"Call sayHelloServerStream\");\n        greeterService.sayHelloServerStream(buildRequest(\"triple\"), responseObserver);\n\n        StreamObserver<HelloReply> sayHelloServerStreamNoParameterResponseObserver = new StreamObserver<HelloReply>() {\n            @Override\n            public void onNext(HelloReply reply) {\n                logger.info(\"sayHelloServerStreamNoParameter onNext: {}\", reply.getMessage());\n            }\n\n            @Override\n            public void onError(Throwable t) {\n                logger.info(\"sayHelloServerStreamNoParameter onError: {}\", t.getMessage());\n            }\n\n            @Override\n            public void onCompleted() {\n                logger.info(\"sayHelloServerStreamNoParameter onCompleted\");\n            }\n        };\n\n        greeterService.sayHelloServerStreamNoParameter(sayHelloServerStreamNoParameterResponseObserver);\n\n        StreamObserver<HelloReply> biResponseObserver = new StreamObserver<HelloReply>() {\n            @Override\n            public void onNext(HelloReply reply) {\n                logger.info(\"biRequestObserver onNext: {}\", reply.getMessage());\n            }\n\n            @Override\n            public void onError(Throwable t) {\n                logger.info(\"biResponseObserver onError: {}\", t.getMessage());\n            }\n\n            @Override\n            public void onCompleted() {\n                logger.info(\"biResponseObserver onCompleted\");\n            }\n        };\n        logger.info(\"Call biRequestObserver\");\n        StreamObserver<HelloRequest> biRequestObserver = greeterService.sayHelloBiStream(biResponseObserver);\n        for (int i = 0; i < 5; i++) {\n            biRequestObserver.onNext(buildRequest(\"triple\" + i));\n        }\n        biRequestObserver.onCompleted();\n\n        Thread.sleep(2000);\n    }\n\n    private static HelloRequest buildRequest(String name) {\n        HelloRequest request = new HelloRequest();\n        request.setName(name);\n        return request;\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.demo.servlet;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.remoting.http12.message.ServerSentEvent;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic interface GreeterService {\n\n    /**\n     * Sends a greeting\n     */\n    HelloReply sayHello(HelloRequest request);\n\n    /**\n     * Sends a greeting asynchronously\n     */\n    CompletableFuture<String> sayHelloAsync(String request);\n\n    /**\n     * Sends a greeting with server streaming\n     */\n    void sayHelloServerStream(HelloRequest request, StreamObserver<HelloReply> responseObserver);\n\n    void sayHelloServerStreamNoParameter(StreamObserver<HelloReply> responseObserver);\n\n    void sayHelloServerStreamSSE(StreamObserver<ServerSentEvent<HelloReply>> responseObserver);\n\n    /**\n     * Sends greetings with bi streaming\n     */\n    StreamObserver<HelloRequest> sayHelloBiStream(StreamObserver<HelloReply> responseObserver);\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.demo.servlet;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.remoting.http12.message.ServerSentEvent;\n\nimport java.time.Duration;\nimport java.util.concurrent.CompletableFuture;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@DubboService\npublic class GreeterServiceImpl implements GreeterService {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(GreeterServiceImpl.class);\n\n    @Override\n    public HelloReply sayHello(HelloRequest request) {\n        LOGGER.info(\"Received sayHello request: {}\", request.getName());\n        return toReply(\"Hello \" + request.getName());\n    }\n\n    @Override\n    public CompletableFuture<String> sayHelloAsync(String name) {\n        LOGGER.info(\"Received sayHelloAsync request: {}\", name);\n        return CompletableFuture.supplyAsync(() -> \"Hello \" + name);\n    }\n\n    @Override\n    public void sayHelloServerStream(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n        LOGGER.info(\"Received sayHelloServerStream request\");\n        for (int i = 1; i < 6; i++) {\n            LOGGER.info(\"sayHelloServerStream onNext: {} {} times\", request.getName(), i);\n            responseObserver.onNext(toReply(\"Hello \" + request.getName() + ' ' + i + \" times\"));\n        }\n        LOGGER.info(\"sayHelloServerStream onCompleted\");\n        responseObserver.onCompleted();\n    }\n\n    @Override\n    public void sayHelloServerStreamNoParameter(StreamObserver<HelloReply> responseObserver) {\n        LOGGER.info(\"Received sayHelloServerStreamNoParameter request\");\n        for (int i = 1; i < 6; i++) {\n            LOGGER.info(\"sayHelloServerStreamNoParameter onNext:  {} times\", i);\n            responseObserver.onNext(toReply(\"Hello \" + ' ' + i + \" times\"));\n        }\n        LOGGER.info(\"sayHelloServerStreamNoParameter onCompleted\");\n        responseObserver.onCompleted();\n    }\n\n    @Override\n    public void sayHelloServerStreamSSE(StreamObserver<ServerSentEvent<HelloReply>> responseObserver) {\n        LOGGER.info(\"Received sayHelloServerStreamSSE request\");\n        responseObserver.onNext(ServerSentEvent.<HelloReply>builder()\n                .retry(Duration.ofSeconds(20))\n                .build());\n        responseObserver.onNext(ServerSentEvent.<HelloReply>builder()\n                .event(\"say\")\n                .comment(\"hello world\")\n                .build());\n        for (int i = 1; i < 6; i++) {\n            LOGGER.info(\"sayHelloServerStreamSSE onNext:  {} times\", i);\n            responseObserver.onNext(ServerSentEvent.<HelloReply>builder()\n                    .data(toReply(\"Hello \" + ' ' + i + \" times\"))\n                    .build());\n        }\n        LOGGER.info(\"sayHelloServerStreamSSE onCompleted\");\n        responseObserver.onCompleted();\n    }\n\n    @Override\n    public StreamObserver<HelloRequest> sayHelloBiStream(StreamObserver<HelloReply> responseObserver) {\n        LOGGER.info(\"Received sayHelloBiStream request\");\n        return new StreamObserver<HelloRequest>() {\n            @Override\n            public void onNext(HelloRequest request) {\n                LOGGER.info(\"sayHelloBiStream onNext: {}\", request.getName());\n                responseObserver.onNext(toReply(\"Hello \" + request.getName()));\n            }\n\n            @Override\n            public void onError(Throwable throwable) {\n                LOGGER.error(\"sayHelloBiStream onError\", throwable);\n            }\n\n            @Override\n            public void onCompleted() {\n                LOGGER.info(\"sayHelloBiStream onCompleted\");\n            }\n        };\n    }\n\n    private static HelloReply toReply(String message) {\n        HelloReply reply = new HelloReply();\n        reply.setMessage(message);\n        return reply;\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/HelloReply.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.demo.servlet;\n\nimport java.io.Serializable;\n\npublic class HelloReply implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private String message;\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/HelloRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.demo.servlet;\n\nimport java.io.Serializable;\n\npublic class HelloRequest implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private String name;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/ProviderApplication.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.demo.servlet;\n\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\n@EnableDubbo\npublic class ProviderApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ProviderApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml",
    "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, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nspring:\n  application:\n    name: dubbo-springboot-demo-servlet\n\ndubbo:\n  application:\n    name: ${spring.application.name}\n    qos-enable: false\n  protocol:\n    name: tri\n    port: 8082\n    triple:\n      rest:\n        openapi:\n          enabled: true\n          cache: false\n      servlet:\n        enabled: true\n  registry:\n    id: zk-registry\n    address: zookeeper://127.0.0.1:2181\n\nserver:\n  port: 8081\n  http2:\n    enabled: true\n  tomcat:\n    keep-alive-timeout: 180000\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%style{%d{HH:mm:ss.SSS}}{Magenta} %style{|-}{White}%highlight{%-5p} [%t] %style{%40.40c}{Cyan}:%style{%-3L}{Blue} %style{-|}{White} %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect)}\" disableAnsi=\"false\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Logger name=\"org.apache.dubbo.rpc.protocol.tri.h12\" level=\"debug\"/>\n        <Logger name=\"org.apache.dubbo.rpc.protocol.tri.rest\" level=\"debug\"/>\n        <Logger name=\"org.apache.dubbo.remoting.http12\" level=\"debug\"/>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-demo-spring-boot</artifactId>\n  <packaging>pom</packaging>\n  <modules>\n    <module>dubbo-demo-spring-boot-consumer</module>\n    <module>dubbo-demo-spring-boot-provider</module>\n    <module>dubbo-demo-spring-boot-interface</module>\n    <module>dubbo-demo-spring-boot-servlet</module>\n  </modules>\n\n  <properties>\n    <source.level>1.8</source.level>\n    <target.level>1.8</target.level>\n    <skip_maven_deploy>true</skip_maven_deploy>\n    <spring-boot.version>2.7.18</spring-boot.version>\n    <spring-boot-maven-plugin.version>2.7.18</spring-boot-maven-plugin.version>\n    <micrometer-core.version>1.16.4</micrometer-core.version>\n  </properties>\n\n  <dependencyManagement>\n    <dependencies>\n      <dependency>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-dependencies</artifactId>\n        <version>${spring-boot.version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter</artifactId>\n        <version>${spring-boot.version}</version>\n        <exclusions>\n          <exclusion>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-logging</artifactId>\n          </exclusion>\n        </exclusions>\n      </dependency>\n      <dependency>\n        <groupId>io.micrometer</groupId>\n        <artifactId>micrometer-core</artifactId>\n        <version>${micrometer-core.version}</version>\n      </dependency>\n    </dependencies>\n  </dependencyManagement>\n\n  <build>\n    <pluginManagement>\n      <plugins>\n        <plugin>\n          <groupId>org.springframework.boot</groupId>\n          <artifactId>spring-boot-maven-plugin</artifactId>\n          <version>${spring-boot-maven-plugin.version}</version>\n          <executions>\n            <execution>\n              <goals>\n                <goal>repackage</goal>\n              </goals>\n            </execution>\n          </executions>\n        </plugin>\n      </plugins>\n    </pluginManagement>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>spring-boot-3</id>\n      <properties>\n        <spring-boot.version>3.2.1</spring-boot.version>\n        <spring-boot-maven-plugin.version>3.2.1</spring-boot-maven-plugin.version>\n      </properties>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-demo-spring-boot-idl</artifactId>\n    <version>${revision}</version>\n  </parent>\n\n  <artifactId>dubbo-demo-spring-boot-idl-consumer</artifactId>\n\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n  </properties>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/java/org/apache/dubbo/springboot/idl/demo/consumer/ConsumerApplication.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.idl.demo.consumer;\n\nimport org.apache.dubbo.config.annotation.DubboReference;\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.apache.dubbo.demo.hello.GreeterService;\nimport org.apache.dubbo.demo.hello.HelloReply;\nimport org.apache.dubbo.demo.hello.HelloRequest;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.stereotype.Service;\n\n@SpringBootApplication\n@Service\n@EnableDubbo\npublic class ConsumerApplication {\n    private static final Logger logger = LoggerFactory.getLogger(ConsumerApplication.class);\n\n    @DubboReference\n    private GreeterService demoService;\n\n    public static void main(String[] args) {\n\n        ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args);\n        ConsumerApplication application = context.getBean(ConsumerApplication.class);\n        HelloReply result = application.doSayHello(\"world\");\n        logger.info(\"result: {}\", result.getMessage());\n    }\n\n    public HelloReply doSayHello(String name) {\n        return demoService.sayHello(HelloRequest.newBuilder().setName(name).build());\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/proto/helloworld.proto",
    "content": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nsyntax = \"proto3\";\n\noption java_multiple_files = true;\noption java_package = \"org.apache.dubbo.demo.hello\";\noption java_outer_classname = \"HelloWorldProto\";\noption objc_class_prefix = \"HLW\";\n\npackage helloworld;\n\n// The request message containing the user's name.\nmessage HelloRequest {\n    string name = 1;\n}\n\n// The response message containing the greetings.\nmessage HelloReply {\n    string message = 1;\n}\n\n// Service definition.\nservice GreeterService {\n    // Sends a greeting.\n    rpc sayHello(HelloRequest) returns (HelloReply);\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/application.yml",
    "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, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nspring:\n  application:\n    name: dubbo-springboot-idl-demo-consumer\n\ndubbo:\n  application:\n    name: ${spring.application.name}\n  protocol:\n    name: tri\n    port: -1\n  registry:\n    id: zk-registry\n    address: zookeeper://127.0.0.1:2181\n  config-center:\n    address: zookeeper://127.0.0.1:2181\n  metadata-report:\n    address: zookeeper://127.0.0.1:2181\n\n\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%style{%d{HH:mm:ss.SSS}}{Magenta} %style{|-}{White}%highlight{%-5p} [%t] %style{%40.40c}{Cyan}:%style{%-3L}{Blue} [%X{traceId}, %X{spanId}] %style{-|}{White} %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect)}\" disableAnsi=\"false\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/README.md",
    "content": "## 1. startup\n\n1. run the maven plugin `dubbo:compile`, generate protobuf java file.\n2. run `ProviderApplication`\n\n## 2. http request\n\n### 2.1 sample request\n\n```shell\ncurl -v -d '{\"name\":\"dubbo\"}' -H 'Content-Type: application/json' http://127.0.0.1:50051/org.apache.dubbo.demo.hello.GreeterService/sayHello\n```\n\n### 2.2 request async\n\n```shell\ncurl -v -d '{\"name\":\"dubbo async\"}' -H 'Content-Type: application/json' http://127.0.0.1:50051/org.apache.dubbo.demo.hello.GreeterService/sayHelloAsync\n```\n\n### 2.3 server stream\n\n```shell\ncurl -v -d '{\"name\":\"dubbo\"}' -H 'Content-Type: application/json' http://127.0.0.1:50051/org.apache.dubbo.demo.hello.GreeterService/sayHelloStream\n```\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-demo-spring-boot-idl</artifactId>\n    <version>${revision}</version>\n  </parent>\n\n  <artifactId>dubbo-demo-spring-boot-idl-provider</artifactId>\n\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n  </properties>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/java/org/apache/dubbo/springboot/idl/demo/provider/GreeterServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.idl.demo.provider;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.demo.hello.GreeterService;\nimport org.apache.dubbo.demo.hello.HelloReply;\nimport org.apache.dubbo.demo.hello.HelloRequest;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@DubboService\npublic class GreeterServiceImpl implements GreeterService {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(GreeterServiceImpl.class);\n\n    @Override\n    public HelloReply sayHello(HelloRequest request) {\n        LOGGER.info(\"Received sayHello request: {}\", request.getName());\n        return toReply(\"Hello \" + request.getName());\n    }\n\n    @Override\n    public CompletableFuture<HelloReply> sayHelloAsync(HelloRequest request) {\n        LOGGER.info(\"Received sayHelloAsync request: {}\", request.getName());\n        HelloReply.newBuilder().setMessage(\"Hello \" + request.getName());\n        return CompletableFuture.supplyAsync(() ->\n                HelloReply.newBuilder().setMessage(\"Hello \" + request.getName()).build());\n    }\n\n    @Override\n    public void sayHelloStream(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n        LOGGER.info(\"Received sayHelloStream request: {}\", request.getName());\n        for (int i = 0; i < 5; i++) {\n            try {\n                TimeUnit.SECONDS.sleep(1);\n            } catch (InterruptedException e) {\n                responseObserver.onError(e);\n            }\n            responseObserver.onNext(HelloReply.newBuilder()\n                    .setMessage(i + \"# Hello \" + request.getName())\n                    .build());\n        }\n        responseObserver.onCompleted();\n    }\n\n    private static HelloReply toReply(String message) {\n        return HelloReply.newBuilder().setMessage(message).build();\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/java/org/apache/dubbo/springboot/idl/demo/provider/ProviderApplication.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.idl.demo.provider;\n\nimport org.apache.dubbo.config.spring.context.annotation.EnableDubbo;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\n@EnableDubbo\npublic class ProviderApplication {\n    public static void main(String[] args) throws Exception {\n        SpringApplication.run(ProviderApplication.class, args);\n        new CountDownLatch(1).await();\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/proto/helloworld.proto",
    "content": "// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nsyntax = \"proto3\";\n\noption java_multiple_files = true;\noption java_package = \"org.apache.dubbo.demo.hello\";\noption java_outer_classname = \"HelloWorldProto\";\noption objc_class_prefix = \"HLW\";\n\npackage helloworld;\n\n// The request message containing the user's name.\nmessage HelloRequest {\n    string name = 1;\n}\n\n// The response message containing the greetings.\nmessage HelloReply {\n    string message = 1;\n}\n\n// Service definition.\nservice GreeterService {\n    // Sends a greeting.\n    rpc sayHello(HelloRequest) returns (HelloReply);\n    rpc sayHelloStream(HelloRequest) returns (stream HelloReply);\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/proto/message.proto",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nsyntax = \"proto3\";\n\noption java_multiple_files = true;\noption java_package = \"org.apache.dubbo.demo.message\";\noption java_outer_classname = \"Message\";\noption objc_class_prefix = \"HLW\";\n\npackage message;\n\n// The request message containing the user's name.\nmessage HelloRequest {\n    string name = 1;\n}\n\n// The response message containing the greetings.\nmessage HelloReply {\n    string message = 1;\n}\n\n// Service definition.\nservice MessageService {\n    // Sends a greeting.\n    rpc sayHello(HelloRequest) returns (HelloReply);\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/resources/application.yml",
    "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, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nspring:\n  application:\n    name: dubbo-springboot-idl-demo-provider\n\ndubbo:\n  application:\n    name: ${spring.application.name}\n  protocol:\n    name: tri\n    port: -1\n  registry:\n    id: zk-registry\n    address: zookeeper://127.0.0.1:2181\n  config-center:\n    address: zookeeper://127.0.0.1:2181\n  metadata-report:\n    address: zookeeper://127.0.0.1:2181\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%style{%d{HH:mm:ss.SSS}}{Magenta} %style{|-}{White}%highlight{%-5p} [%t] %style{%40.40c}{Cyan}:%style{%-3L}{Blue} %style{-|}{White} %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect)}\" disableAnsi=\"false\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Logger name=\"org.apache.dubbo.rpc.protocol.tri.h12\" level=\"debug\"/>\n        <Logger name=\"org.apache.dubbo.rpc.protocol.tri.rest\" level=\"debug\"/>\n        <Logger name=\"org.apache.dubbo.remoting.http12\" level=\"debug\"/>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/test/java/org/apache/dubbo/springboot/idl/demo/MessageServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.springboot.idl.demo;\n\nimport org.apache.dubbo.demo.message.DubboMessageServiceTriple;\nimport org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry;\n\nimport com.google.protobuf.Descriptors.FileDescriptor;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\npublic class MessageServiceTest {\n\n    @Test\n    public void testMessageGenerator() {\n        try {\n            // load class\n            Class.forName(DubboMessageServiceTriple.class.getName());\n        } catch (ClassNotFoundException ignored) {\n        }\n        FileDescriptor schemaDescriptor =\n                SchemaDescriptorRegistry.getSchemaDescriptor(DubboMessageServiceTriple.SERVICE_NAME);\n        Assertions.assertNotNull(schemaDescriptor);\n        Assertions.assertEquals(\"message.proto\", schemaDescriptor.getName());\n    }\n}\n"
  },
  {
    "path": "dubbo-demo/dubbo-demo-spring-boot-idl/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-demo-spring-boot-idl</artifactId>\n  <packaging>pom</packaging>\n  <modules>\n    <module>dubbo-demo-spring-boot-idl-provider</module>\n    <module>dubbo-demo-spring-boot-idl-consumer</module>\n  </modules>\n\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n    <spring-boot.version>2.7.18</spring-boot.version>\n    <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-spring-boot-starter</artifactId>\n      <version>${revision}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter</artifactId>\n      <version>${spring-boot.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java-util</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <!-- add os-maven-plugin to plugins just for Eclipse m2e, not for `mvn install` -->\n        <groupId>kr.motd.maven</groupId>\n        <artifactId>os-maven-plugin</artifactId>\n        <version>${maven_os_plugin_version}</version>\n        <executions>\n          <execution>\n            <goals>\n              <goal>detect</goal>\n            </goals>\n            <phase>initialize</phase>\n          </execution>\n        </executions>\n      </plugin>\n\n      <!-- Override the maven-javadoc-plugin configuration that depends on the pass -->\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-javadoc-plugin</artifactId>\n        <configuration>\n          <skip>true</skip>\n        </configuration>\n      </plugin>\n    </plugins>\n    <extensions>\n      <!-- add os-maven-plugin to extensions for `mvn install` -->\n      <extension>\n        <groupId>kr.motd.maven</groupId>\n        <artifactId>os-maven-plugin</artifactId>\n        <version>${maven_os_plugin_version}</version>\n      </extension>\n    </extensions>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-dependencies-bom/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache</groupId>\n    <artifactId>apache</artifactId>\n    <version>31</version>\n    <relativePath />\n  </parent>\n\n  <groupId>org.apache.dubbo</groupId>\n  <artifactId>dubbo-dependencies-bom</artifactId>\n  <version>${revision}</version>\n  <packaging>pom</packaging>\n\n  <name>dubbo-dependencies-bom</name>\n  <description>Dubbo dependencies BOM</description>\n  <url>https://github.com/apache/dubbo</url>\n  <inceptionYear>2011</inceptionYear>\n\n  <organization>\n    <name>The Apache Software Foundation</name>\n    <url>http://www.apache.org/</url>\n  </organization>\n  <licenses>\n    <license>\n      <name>Apache License, Version 2.0</name>\n      <url>http://www.apache.org/licenses/LICENSE-2.0</url>\n      <distribution>repo</distribution>\n    </license>\n  </licenses>\n  <developers>\n    <developer>\n      <id>dubbo.io</id>\n      <name>The Dubbo Project Contributors</name>\n      <email>dev-subscribe@dubbo.apache.org</email>\n      <url>http://dubbo.apache.org/</url>\n    </developer>\n  </developers>\n  <mailingLists>\n    <mailingList>\n      <name>Development List</name>\n      <subscribe>dev-subscribe@dubbo.apache.org</subscribe>\n      <unsubscribe>dev-unsubscribe@dubbo.apache.org</unsubscribe>\n      <post>dev@dubbo.apache.org</post>\n    </mailingList>\n    <mailingList>\n      <name>Commits List</name>\n      <subscribe>commits-subscribe@dubbo.apache.org</subscribe>\n      <unsubscribe>commits-unsubscribe@dubbo.apache.org</unsubscribe>\n      <post>commits@dubbo.apache.org</post>\n    </mailingList>\n    <mailingList>\n      <name>Issues List</name>\n      <subscribe>issues-subscribe@dubbo.apache.org</subscribe>\n      <unsubscribe>issues-unsubscribe@dubbo.apache.org</unsubscribe>\n      <post>issues@dubbo.apache.org</post>\n    </mailingList>\n  </mailingLists>\n\n  <scm>\n    <connection>scm:git:https://github.com/apache/dubbo.git</connection>\n    <developerConnection>scm:git:https://github.com/apache/dubbo.git</developerConnection>\n    <tag>HEAD</tag>\n    <url>https://github.com/apache/dubbo</url>\n  </scm>\n\n  <issueManagement>\n    <system>Github Issues</system>\n    <url>https://github.com/apache/dubbo/issues</url>\n  </issueManagement>\n\n  <properties>\n    <!-- Common libs -->\n    <!-- <spring_version>4.3.30.RELEASE</spring_version> -->\n    <spring_version>5.3.39</spring_version>\n    <spring_boot_version>2.7.18</spring_boot_version>\n    <spring_security_version>5.8.16</spring_security_version>\n    <javassist_version>3.30.2-GA</javassist_version>\n    <byte-buddy_version>1.18.7</byte-buddy_version>\n    <netty_version>3.2.10.Final</netty_version>\n    <netty4_version>4.2.10.Final</netty4_version>\n    <httpclient_version>4.5.14</httpclient_version>\n    <httpcore_version>4.4.16</httpcore_version>\n    <fastjson_version>1.2.83_noneautotype</fastjson_version>\n    <fastjson2_version>2.0.60</fastjson2_version>\n    <zookeeper_version>3.7.2</zookeeper_version>\n    <curator_version>5.9.0</curator_version>\n    <curator_test_version>2.12.0</curator_test_version>\n    <hessian_version>4.0.66</hessian_version>\n    <protobuf-java_version>4.34.0</protobuf-java_version>\n    <jsr305_version>3.0.2</jsr305_version>\n    <javax_annotation-api_version>1.3.2</javax_annotation-api_version>\n    <servlet_version>3.1.0</servlet_version>\n    <jakarta_websocket_version>2.2.0</jakarta_websocket_version>\n    <jakarta_servlet_version>6.1.0</jakarta_servlet_version>\n    <jetty_version>9.4.58.v20250814</jetty_version>\n    <validation_new_version>3.1.1</validation_new_version>\n    <validation_version>2.0.1.Final</validation_version>\n    <hibernate_validator_version>6.2.5.Final</hibernate_validator_version>\n    <hibernate_validator_new_version>7.0.5.Final</hibernate_validator_new_version>\n    <jel_version>3.0.1-b12</jel_version>\n    <jcache_version>1.1.1</jcache_version>\n    <apollo_client_version>2.5.0</apollo_client_version>\n    <snakeyaml_version>2.6</snakeyaml_version>\n    <commons_lang3_version>3.20.0</commons_lang3_version>\n    <envoy_api_version>0.1.35</envoy_api_version>\n    <micrometer.version>1.16.4</micrometer.version>\n    <opentelemetry.version>1.60.1</opentelemetry.version>\n    <zipkin-reporter.version>3.5.1</zipkin-reporter.version>\n    <zipkin.version>3.5.1</zipkin.version>\n    <micrometer-tracing.version>1.6.4</micrometer-tracing.version>\n    <t_digest.version>3.3</t_digest.version>\n    <prometheus_client.version>0.16.0</prometheus_client.version>\n    <reactive.version>1.0.4</reactive.version>\n    <reactor.version>3.8.4</reactor.version>\n    <mutiny.version>2.9.5</mutiny.version>\n    <rxjava.version>2.2.21</rxjava.version>\n    <okhttp_version>4.12.0</okhttp_version>\n\n    <rs_api_version>2.1.1</rs_api_version>\n    <resteasy_version>3.15.6.Final</resteasy_version>\n    <codehaus-jackson_version>1.9.13</codehaus-jackson_version>\n    <tomcat_embed_version>9.0.113</tomcat_embed_version>\n    <nacos_version>2.5.2</nacos_version>\n    <sentinel.version>1.8.9</sentinel.version>\n    <seata.version>1.8.0</seata.version>\n    <grpc.version>1.79.0</grpc.version>\n    <grpc_contrib_verdion>0.8.1</grpc_contrib_verdion>\n    <jprotoc_version>1.2.2</jprotoc_version>\n    <mustache_version>0.9.14</mustache_version>\n    <!-- Log libs -->\n    <slf4j_version>1.7.36</slf4j_version>\n    <jcl_version>1.3.6</jcl_version>\n    <log4j_version>1.2.17</log4j_version>\n    <logback_version>1.2.13</logback_version>\n    <!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->\n    <log4j2_version>2.25.3</log4j2_version>\n    <commons_io_version>2.21.0</commons_io_version>\n    <commons-codec_version>1.21.0</commons-codec_version>\n    <groovy_version>4.0.30</groovy_version>\n\n    <!-- Test libs -->\n    <junit_jupiter_version>5.14.3</junit_jupiter_version>\n    <junit_platform_version>1.13.1</junit_platform_version>\n    <junit_jupiter_version>5.14.3</junit_jupiter_version>\n    <junit_platform_version>1.14.3</junit_platform_version>\n    <awaitility_version>4.3.0</awaitility_version>\n    <hamcrest_version>2.2</hamcrest_version>\n    <cglib_version>2.2.2</cglib_version>\n    <mockito_version>4.11.0</mockito_version>\n    <spock_version>2.4-groovy-4.0</spock_version>\n\n    <jaxb_version>2.2.7</jaxb_version>\n    <activation_version>1.2.0</activation_version>\n    <test_container_version>1.21.4</test_container_version>\n    <hessian_lite_version>4.0.5</hessian_lite_version>\n    <swagger_version>1.6.16</swagger_version>\n\n    <snappy_java_version>1.1.10.8</snappy_java_version>\n    <bouncycastle-bcprov_version>1.83</bouncycastle-bcprov_version>\n    <metrics_version>2.0.6</metrics_version>\n    <gson_version>2.13.2</gson_version>\n    <jackson_version>2.21.1</jackson_version>\n    <mortbay_jetty_version>6.1.26</mortbay_jetty_version>\n    <portlet_version>2.0</portlet_version>\n    <maven_flatten_version>1.7.3</maven_flatten_version>\n    <commons_compress_version>1.28.0</commons_compress_version>\n    <spotless-maven-plugin.version>2.46.1</spotless-maven-plugin.version>\n    <spotless.action>check</spotless.action>\n    <dubbo-shared-resources.version>1.0.0</dubbo-shared-resources.version>\n    <palantirJavaFormat.version>2.38.0</palantirJavaFormat.version>\n    <jakarta.xml.bind-api.version>4.0.5</jakarta.xml.bind-api.version>\n    <jaxb-runtime.version>2.4.0-b180830.0438</jaxb-runtime.version>\n    <!-- Spring boot buddy is lower than the delivery dependency package version and can only show the defined dependency version -->\n    <byte-buddy.version>1.15.1</byte-buddy.version>\n    <prometheus-client.version>0.16.0</prometheus-client.version>\n\n    <revision>3.3.7-SNAPSHOT</revision>\n  </properties>\n\n  <dependencyManagement>\n    <dependencies>\n      <!-- Common libs -->\n      <dependency>\n        <groupId>org.springframework</groupId>\n        <artifactId>spring-framework-bom</artifactId>\n        <version>${spring_version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.springframework.security</groupId>\n        <artifactId>spring-security-bom</artifactId>\n        <version>${spring_security_version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n      <dependency>\n        <groupId>io.netty</groupId>\n        <artifactId>netty-bom</artifactId>\n        <version>${netty4_version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n\n      <dependency>\n        <groupId>io.micrometer</groupId>\n        <artifactId>micrometer-bom</artifactId>\n        <version>${micrometer.version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n      <dependency>\n        <groupId>io.micrometer</groupId>\n        <artifactId>micrometer-tracing-bom</artifactId>\n        <version>${micrometer-tracing.version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n      <dependency>\n        <groupId>io.opentelemetry</groupId>\n        <artifactId>opentelemetry-bom</artifactId>\n        <version>${opentelemetry.version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n      <dependency>\n        <groupId>io.zipkin.reporter2</groupId>\n        <artifactId>zipkin-reporter-bom</artifactId>\n        <version>${zipkin-reporter.version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n      <dependency>\n        <groupId>io.zipkin.zipkin2</groupId>\n        <artifactId>zipkin</artifactId>\n        <version>${zipkin.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.prometheus</groupId>\n        <artifactId>simpleclient_bom</artifactId>\n        <version>${prometheus-client.version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n      <!-- Spring Boot -->\n      <dependency>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-dependencies</artifactId>\n        <version>${spring_boot_version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n        <exclusions>\n          <exclusion>\n            <groupId>io.micrometer</groupId>\n            <artifactId>micrometer-core</artifactId>\n          </exclusion>\n        </exclusions>\n      </dependency>\n      <dependency>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-logging</artifactId>\n        <version>${spring_boot_version}</version>\n        <exclusions>\n          <exclusion>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n          </exclusion>\n          <exclusion>\n            <groupId>org.apache.logging.log4j</groupId>\n            <artifactId>log4j-to-slf4j</artifactId>\n          </exclusion>\n          <exclusion>\n            <groupId>org.slf4j</groupId>\n            <artifactId>log4j-over-slf4j</artifactId>\n          </exclusion>\n          <exclusion>\n            <groupId>org.slf4j</groupId>\n            <artifactId>log4j-to-slf4j</artifactId>\n          </exclusion>\n        </exclusions>\n      </dependency>\n      <dependency>\n        <groupId>io.netty</groupId>\n        <artifactId>netty-all</artifactId>\n        <version>${netty4_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.javassist</groupId>\n        <artifactId>javassist</artifactId>\n        <version>${javassist_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>net.bytebuddy</groupId>\n        <artifactId>byte-buddy</artifactId>\n        <version>${byte-buddy_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>net.bytebuddy</groupId>\n        <artifactId>byte-buddy-agent</artifactId>\n        <version>${byte-buddy_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.jboss.netty</groupId>\n        <artifactId>netty</artifactId>\n        <version>${netty_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.httpcomponents</groupId>\n        <artifactId>httpclient</artifactId>\n        <version>${httpclient_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.httpcomponents</groupId>\n        <artifactId>httpcore</artifactId>\n        <version>${httpcore_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.alibaba</groupId>\n        <artifactId>fastjson</artifactId>\n        <version>${fastjson_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.alibaba.fastjson2</groupId>\n        <artifactId>fastjson2</artifactId>\n        <version>${fastjson2_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.zookeeper</groupId>\n        <artifactId>zookeeper</artifactId>\n        <version>${zookeeper_version}</version>\n        <exclusions>\n          <exclusion>\n            <groupId>org.slf4j</groupId>\n            <artifactId>log4j-slf4j-impl</artifactId>\n          </exclusion>\n          <exclusion>\n            <groupId>log4j</groupId>\n            <artifactId>log4j</artifactId>\n          </exclusion>\n          <exclusion>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-core</artifactId>\n          </exclusion>\n          <exclusion>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n          </exclusion>\n          <exclusion>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-log4j12</artifactId>\n          </exclusion>\n          <exclusion>\n            <groupId>org.apache.yetus</groupId>\n            <artifactId>audience-annotations</artifactId>\n          </exclusion>\n          <exclusion>\n            <groupId>io.netty</groupId>\n            <artifactId>*</artifactId>\n          </exclusion>\n        </exclusions>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.curator</groupId>\n        <artifactId>curator-framework</artifactId>\n        <version>${curator_version}</version>\n        <exclusions>\n          <exclusion>\n            <groupId>org.apache.zookeeper</groupId>\n            <artifactId>zookeeper</artifactId>\n          </exclusion>\n        </exclusions>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.curator</groupId>\n        <artifactId>curator-x-discovery</artifactId>\n        <version>${curator_version}</version>\n        <exclusions>\n          <exclusion>\n            <groupId>org.apache.zookeeper</groupId>\n            <artifactId>zookeeper</artifactId>\n          </exclusion>\n        </exclusions>\n      </dependency>\n\n      <!-- Alibaba -->\n\n      <dependency>\n        <groupId>com.caucho</groupId>\n        <artifactId>hessian</artifactId>\n        <version>${hessian_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>hessian-lite</artifactId>\n        <version>${hessian_lite_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.google.protobuf</groupId>\n        <artifactId>protobuf-java</artifactId>\n        <version>${protobuf-java_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.google.protobuf</groupId>\n        <artifactId>protobuf-java-util</artifactId>\n        <version>${protobuf-java_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.google.code.findbugs</groupId>\n        <artifactId>jsr305</artifactId>\n        <version>${jsr305_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.bouncycastle</groupId>\n        <artifactId>bcprov-jdk18on</artifactId>\n        <version>${bouncycastle-bcprov_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.bouncycastle</groupId>\n        <artifactId>bcpkix-jdk18on</artifactId>\n        <version>${bouncycastle-bcprov_version}</version>\n      </dependency>\n\n      <!-- Common Annotations API -->\n      <dependency>\n        <groupId>javax.annotation</groupId>\n        <artifactId>javax.annotation-api</artifactId>\n        <version>${javax_annotation-api_version}</version>\n      </dependency>\n      <!-- Servlet API -->\n      <dependency>\n        <groupId>javax.servlet</groupId>\n        <artifactId>javax.servlet-api</artifactId>\n        <version>${servlet_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>jakarta.servlet</groupId>\n        <artifactId>jakarta.servlet-api</artifactId>\n        <version>${jakarta_servlet_version}</version>\n        <scope>provided</scope>\n      </dependency>\n      <dependency>\n        <groupId>jakarta.websocket</groupId>\n        <artifactId>jakarta.websocket-api</artifactId>\n        <version>${jakarta_websocket_version}</version>\n        <scope>provided</scope>\n      </dependency>\n      <dependency>\n        <groupId>jakarta.websocket</groupId>\n        <artifactId>jakarta.websocket-client-api</artifactId>\n        <version>${jakarta_websocket_version}</version>\n        <scope>provided</scope>\n      </dependency>\n      <dependency>\n        <groupId>com.squareup.okhttp3</groupId>\n        <artifactId>okhttp</artifactId>\n        <version>${okhttp_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.squareup.okhttp3</groupId>\n        <artifactId>mockwebserver</artifactId>\n        <version>${okhttp_version}</version>\n      </dependency>\n\n      <dependency>\n        <groupId>org.eclipse.jetty</groupId>\n        <artifactId>jetty-server</artifactId>\n        <version>${jetty_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.eclipse.jetty</groupId>\n        <artifactId>jetty-servlet</artifactId>\n        <version>${jetty_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.mortbay.jetty</groupId>\n        <artifactId>jetty</artifactId>\n        <version>${mortbay_jetty_version}</version>\n        <optional>true</optional>\n      </dependency>\n      <dependency>\n        <groupId>javax.validation</groupId>\n        <artifactId>validation-api</artifactId>\n        <version>${validation_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.hibernate</groupId>\n        <artifactId>hibernate-validator</artifactId>\n        <version>${hibernate_validator_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.glassfish</groupId>\n        <artifactId>javax.el</artifactId>\n        <version>${jel_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>jakarta.validation</groupId>\n        <artifactId>jakarta.validation-api</artifactId>\n        <version>${validation_new_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.hibernate.validator</groupId>\n        <artifactId>hibernate-validator</artifactId>\n        <version>${hibernate_validator_new_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>javax.cache</groupId>\n        <artifactId>cache-api</artifactId>\n        <version>${jcache_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>javax.ws.rs</groupId>\n        <artifactId>javax.ws.rs-api</artifactId>\n        <version>${rs_api_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.jboss.resteasy</groupId>\n        <artifactId>resteasy-jaxrs</artifactId>\n        <version>${resteasy_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.jboss.resteasy</groupId>\n        <artifactId>resteasy-client</artifactId>\n        <version>${resteasy_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.jboss.resteasy</groupId>\n        <artifactId>resteasy-netty4</artifactId>\n        <version>${resteasy_version}</version>\n        <exclusions>\n          <exclusion>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-all</artifactId>\n          </exclusion>\n        </exclusions>\n      </dependency>\n      <dependency>\n        <groupId>org.jboss.resteasy</groupId>\n        <artifactId>resteasy-jdk-http</artifactId>\n        <version>${resteasy_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.jboss.resteasy</groupId>\n        <artifactId>resteasy-jackson-provider</artifactId>\n        <version>${resteasy_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.codehaus.jackson</groupId>\n        <artifactId>jackson-core-asl</artifactId>\n        <version>${codehaus-jackson_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.codehaus.jackson</groupId>\n        <artifactId>jackson-mapper-asl</artifactId>\n        <version>${codehaus-jackson_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.codehaus.jackson</groupId>\n        <artifactId>jackson-jaxrs</artifactId>\n        <version>${codehaus-jackson_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.codehaus.jackson</groupId>\n        <artifactId>jackson-xc</artifactId>\n        <version>${codehaus-jackson_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.jboss.resteasy</groupId>\n        <artifactId>resteasy-jaxb-provider</artifactId>\n        <version>${resteasy_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.tomcat.embed</groupId>\n        <artifactId>tomcat-embed-core</artifactId>\n        <version>${tomcat_embed_version}</version>\n      </dependency>\n      <!-- Log libs -->\n      <dependency>\n        <groupId>org.slf4j</groupId>\n        <artifactId>slf4j-api</artifactId>\n        <version>${slf4j_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>commons-logging</groupId>\n        <artifactId>commons-logging</artifactId>\n        <version>${jcl_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>commons-io</groupId>\n        <artifactId>commons-io</artifactId>\n        <version>${commons_io_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>commons-codec</groupId>\n        <artifactId>commons-codec</artifactId>\n        <version>${commons-codec_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>log4j</groupId>\n        <artifactId>log4j</artifactId>\n        <version>${log4j_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>ch.qos.logback</groupId>\n        <artifactId>logback-classic</artifactId>\n        <version>${logback_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.logging.log4j</groupId>\n        <artifactId>log4j-api</artifactId>\n        <version>${log4j2_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.logging.log4j</groupId>\n        <artifactId>log4j-core</artifactId>\n        <version>${log4j2_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.logging.log4j</groupId>\n        <artifactId>log4j-slf4j-impl</artifactId>\n        <version>${log4j2_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.logging.log4j</groupId>\n        <artifactId>log4j-slf4j2-impl</artifactId>\n        <version>${log4j2_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.ctrip.framework.apollo</groupId>\n        <artifactId>apollo-client</artifactId>\n        <version>${apollo_client_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.curator</groupId>\n        <artifactId>curator-recipes</artifactId>\n        <version>${curator_version}</version>\n        <exclusions>\n          <exclusion>\n            <groupId>org.apache.zookeeper</groupId>\n            <artifactId>zookeeper</artifactId>\n          </exclusion>\n        </exclusions>\n      </dependency>\n      <dependency>\n        <groupId>org.yaml</groupId>\n        <artifactId>snakeyaml</artifactId>\n        <version>${snakeyaml_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.commons</groupId>\n        <artifactId>commons-lang3</artifactId>\n        <version>${commons_lang3_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.envoyproxy.controlplane</groupId>\n        <artifactId>api</artifactId>\n        <version>${envoy_api_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.groovy</groupId>\n        <artifactId>groovy</artifactId>\n        <version>${groovy_version}</version>\n      </dependency>\n\n      <!-- for dubbo-rpc-webservice -->\n      <dependency>\n        <groupId>javax.xml.bind</groupId>\n        <artifactId>jaxb-api</artifactId>\n        <version>${jaxb_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.sun.xml.bind</groupId>\n        <artifactId>jaxb-impl</artifactId>\n        <version>${jaxb_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.sun.xml.bind</groupId>\n        <artifactId>jaxb-core</artifactId>\n        <version>${jaxb_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>javax.activation</groupId>\n        <artifactId>javax.activation-api</artifactId>\n        <version>${activation_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.sun.activation</groupId>\n        <artifactId>javax.activation</artifactId>\n        <version>${activation_version}</version>\n      </dependency>\n\n      <!-- swagger -->\n      <dependency>\n        <groupId>io.swagger</groupId>\n        <artifactId>swagger-annotations</artifactId>\n        <version>${swagger_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.swagger</groupId>\n        <artifactId>swagger-jaxrs</artifactId>\n        <version>${swagger_version}</version>\n      </dependency>\n\n      <!-- Test libs -->\n      <dependency>\n        <groupId>org.junit.jupiter</groupId>\n        <artifactId>junit-jupiter-engine</artifactId>\n        <version>${junit_jupiter_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.junit.platform</groupId>\n        <artifactId>junit-platform-engine</artifactId>\n        <version>${junit_platform_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.junit.platform</groupId>\n        <artifactId>junit-platform-commons</artifactId>\n        <version>${junit_platform_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.junit.platform</groupId>\n        <artifactId>junit-platform-launcher</artifactId>\n        <version>${junit_platform_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.junit.jupiter</groupId>\n        <artifactId>junit-jupiter-api</artifactId>\n        <version>${junit_jupiter_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.junit.jupiter</groupId>\n        <artifactId>junit-jupiter-params</artifactId>\n        <version>${junit_jupiter_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.awaitility</groupId>\n        <artifactId>awaitility</artifactId>\n        <version>${awaitility_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.hamcrest</groupId>\n        <artifactId>hamcrest</artifactId>\n        <version>${hamcrest_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.mockito</groupId>\n        <artifactId>mockito-core</artifactId>\n        <version>${mockito_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.mockito</groupId>\n        <artifactId>mockito-inline</artifactId>\n        <version>${mockito_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>cglib</groupId>\n        <artifactId>cglib-nodep</artifactId>\n        <version>${cglib_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.springframework</groupId>\n        <artifactId>spring-test</artifactId>\n        <version>${spring_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.spockframework</groupId>\n        <artifactId>spock-core</artifactId>\n        <version>${spock_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.spockframework</groupId>\n        <artifactId>spock-spring</artifactId>\n        <version>${spock_version}</version>\n        <scope>test</scope>\n      </dependency>\n      <dependency>\n        <groupId>org.spockframework</groupId>\n        <artifactId>spock-junit4</artifactId>\n        <version>${spock_version}</version>\n        <scope>test</scope>\n      </dependency>\n\n      <dependency>\n        <groupId>com.google.code.gson</groupId>\n        <artifactId>gson</artifactId>\n        <version>${gson_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.fasterxml.jackson</groupId>\n        <artifactId>jackson-bom</artifactId>\n        <version>${jackson_version}</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n      <dependency>\n        <groupId>javax.portlet</groupId>\n        <artifactId>portlet-api</artifactId>\n        <version>${portlet_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.testcontainers</groupId>\n        <artifactId>testcontainers</artifactId>\n        <version>${test_container_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.alibaba.nacos</groupId>\n        <artifactId>nacos-client</artifactId>\n        <version>${nacos_version}</version>\n      </dependency>\n      <!-- sentinel related dependencies -->\n      <dependency>\n        <groupId>com.alibaba.csp</groupId>\n        <artifactId>sentinel-apache-dubbo3-adapter</artifactId>\n        <version>${sentinel.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.alibaba.csp</groupId>\n        <artifactId>sentinel-transport-simple-http</artifactId>\n        <version>${sentinel.version}</version>\n      </dependency>\n      <!-- seata related dependencies -->\n      <dependency>\n        <groupId>io.seata</groupId>\n        <artifactId>seata-spring-boot-starter</artifactId>\n        <version>${seata.version}</version>\n        <exclusions>\n          <exclusion>\n            <groupId>io.seata</groupId>\n            <artifactId>seata-core</artifactId>\n          </exclusion>\n        </exclusions>\n      </dependency>\n      <dependency>\n        <groupId>io.seata</groupId>\n        <artifactId>seata-core</artifactId>\n        <version>${seata.version}</version>\n      </dependency>\n      <!-- grpc related dependencies -->\n      <dependency>\n        <groupId>io.grpc</groupId>\n        <artifactId>grpc-core</artifactId>\n        <version>${grpc.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.grpc</groupId>\n        <artifactId>grpc-netty-shaded</artifactId>\n        <version>${grpc.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.grpc</groupId>\n        <artifactId>grpc-netty</artifactId>\n        <version>${grpc.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.grpc</groupId>\n        <artifactId>grpc-protobuf</artifactId>\n        <version>${grpc.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.grpc</groupId>\n        <artifactId>grpc-stub</artifactId>\n        <version>${grpc.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.grpc</groupId>\n        <artifactId>grpc-grpclb</artifactId>\n        <version>${grpc.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.grpc</groupId>\n        <artifactId>grpc-context</artifactId>\n        <version>${grpc.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.salesforce.servicelibs</groupId>\n        <artifactId>grpc-contrib</artifactId>\n        <version>${grpc_contrib_verdion}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.salesforce.servicelibs</groupId>\n        <artifactId>jprotoc</artifactId>\n        <version>${jprotoc_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>com.github.spullara.mustache.java</groupId>\n        <artifactId>compiler</artifactId>\n        <version>${mustache_version}</version>\n      </dependency>\n      <!-- tri compress support-->\n      <dependency>\n        <groupId>org.apache.commons</groupId>\n        <artifactId>commons-compress</artifactId>\n        <version>${commons_compress_version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.xerial.snappy</groupId>\n        <artifactId>snappy-java</artifactId>\n        <version>${snappy_java_version}</version>\n        <optional>true</optional>\n      </dependency>\n      <!-- metrics related dependencies-->\n      <dependency>\n        <groupId>com.tdunning</groupId>\n        <artifactId>t-digest</artifactId>\n        <version>${t_digest.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.prometheus</groupId>\n        <artifactId>simpleclient</artifactId>\n        <version>${prometheus_client.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.prometheus</groupId>\n        <artifactId>simpleclient_pushgateway</artifactId>\n        <version>${prometheus_client.version}</version>\n      </dependency>\n      <!-- reactive related dependencies -->\n      <dependency>\n        <groupId>org.reactivestreams</groupId>\n        <artifactId>reactive-streams</artifactId>\n        <version>${reactive.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.projectreactor</groupId>\n        <artifactId>reactor-core</artifactId>\n        <version>${reactor.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.smallrye.reactive</groupId>\n        <artifactId>mutiny</artifactId>\n        <version>${mutiny.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>io.reactivex.rxjava2</groupId>\n        <artifactId>rxjava</artifactId>\n        <version>${rxjava.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>jakarta.xml.bind</groupId>\n        <artifactId>jakarta.xml.bind-api</artifactId>\n        <version>${jakarta.xml.bind-api.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.glassfish.jaxb</groupId>\n        <artifactId>jaxb-runtime</artifactId>\n        <version>${jaxb-runtime.version}</version>\n      </dependency>\n    </dependencies>\n  </dependencyManagement>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.codehaus.mojo</groupId>\n        <artifactId>flatten-maven-plugin</artifactId>\n        <version>${maven_flatten_version}</version>\n        <configuration>\n          <updatePomFile>true</updatePomFile>\n          <flattenMode>bom</flattenMode>\n          <pomElements>\n            <dependencyManagement>expand</dependencyManagement>\n            <properties>remove</properties>\n            <repositories>remove</repositories>\n            <profiles>remove</profiles>\n          </pomElements>\n        </configuration>\n        <executions>\n          <execution>\n            <id>flatten</id>\n            <goals>\n              <goal>flatten</goal>\n            </goals>\n            <phase>process-resources</phase>\n          </execution>\n          <execution>\n            <id>flatten.clean</id>\n            <goals>\n              <goal>clean</goal>\n            </goals>\n            <phase>clean</phase>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>release</id>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-gpg-plugin</artifactId>\n            <executions>\n              <execution>\n                <goals>\n                  <goal>sign</goal>\n                </goals>\n                <phase>verify</phase>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n    <profile>\n      <id>java11+</id>\n      <activation>\n        <jdk>[11,)</jdk>\n      </activation>\n      <build>\n        <!--- newer versions of plugins requires JDK 11 -->\n        <plugins>\n          <plugin>\n            <groupId>com.diffplug.spotless</groupId>\n            <artifactId>spotless-maven-plugin</artifactId>\n            <version>${spotless-maven-plugin.version}</version>\n            <configuration>\n              <java>\n                <palantirJavaFormat>\n                  <version>${palantirJavaFormat.version}</version>\n                </palantirJavaFormat>\n                <removeUnusedImports />\n                <importOrder>\n                  <file>dubbo-importorder.txt</file>\n                </importOrder>\n                <licenseHeader>\n                  <file>checkstyle-header.txt</file>\n                </licenseHeader>\n              </java>\n              <pom>\n                <sortPom>\n                  <expandEmptyElements>false</expandEmptyElements>\n                  <spaceBeforeCloseEmptyElement>true</spaceBeforeCloseEmptyElement>\n                </sortPom>\n              </pom>\n              <upToDateChecking>\n                <enabled>true</enabled>\n              </upToDateChecking>\n            </configuration>\n            <dependencies>\n              <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>dubbo-shared-resources</artifactId>\n                <version>${dubbo-shared-resources.version}</version>\n              </dependency>\n            </dependencies>\n            <executions>\n              <execution>\n                <goals>\n                  <goal>${spotless.action}</goal>\n                </goals>\n                <phase>process-sources</phase>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n    <profile>\n      <id>skip-spotless</id>\n      <properties>\n        <spotless.skip>true</spotless.skip>\n      </properties>\n    </profile>\n  </profiles>\n\n</project>\n"
  },
  {
    "path": "dubbo-distribution/dubbo-all/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo</artifactId>\n  <packaging>jar</packaging>\n  <name>dubbo</name>\n  <description>The all in one project of dubbo</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <!-- cluster -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-cluster</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- common -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- compatible -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-compatible</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- config -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- config-center -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-file</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-zookeeper</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-apollo</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-nacos</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- filter -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-filter-cache</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-filter-validation</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- metadata -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-nacos</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-definition-protobuf</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- metrics -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-event</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-registry</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-prometheus</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-metadata</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-config-center</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-netty</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-otlp</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <!-- tracing -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-tracing</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- plugin -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-auth</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-security</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-reactive</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-spring-security</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rest-jaxrs</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rest-spring</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rest-openapi</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-triple-servlet</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-triple-websocket</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- registry -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-multicast</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-multiple</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-nacos</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- remoting -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-http12</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-http3</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-websocket</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-zookeeper-curator5</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- rpc -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-dubbo</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-injvm</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- serialization -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-fastjson2</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- Transitive dependencies -->\n    <dependency>\n      <groupId>org.javassist</groupId>\n      <artifactId>javassist</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.netty</groupId>\n      <artifactId>netty-all</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.yaml</groupId>\n      <artifactId>snakeyaml</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>hessian-lite</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.alibaba.fastjson2</groupId>\n      <artifactId>fastjson2</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java</artifactId>\n    </dependency>\n  </dependencies>\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-shade-plugin</artifactId>\n        <executions>\n          <execution>\n            <goals>\n              <goal>shade</goal>\n            </goals>\n            <phase>package</phase>\n            <configuration>\n              <createSourcesJar>true</createSourcesJar>\n              <promoteTransitiveDependencies>false</promoteTransitiveDependencies>\n              <artifactSet>\n                <includes>\n                  <include>org.apache.dubbo:dubbo-auth</include>\n                  <include>org.apache.dubbo:dubbo-cluster</include>\n                  <include>org.apache.dubbo:dubbo-common</include>\n                  <include>org.apache.dubbo:dubbo-compatible</include>\n                  <include>org.apache.dubbo:dubbo-config-api</include>\n                  <include>org.apache.dubbo:dubbo-config-spring</include>\n                  <include>org.apache.dubbo:dubbo-configcenter-file</include>\n                  <include>org.apache.dubbo:dubbo-configcenter-apollo</include>\n                  <include>org.apache.dubbo:dubbo-configcenter-nacos</include>\n                  <include>org.apache.dubbo:dubbo-configcenter-zookeeper</include>\n                  <include>org.apache.dubbo:dubbo-filter-cache</include>\n                  <include>org.apache.dubbo:dubbo-filter-validation</include>\n                  <include>org.apache.dubbo:dubbo-mcp</include>\n                  <include>org.apache.dubbo:dubbo-metadata-api</include>\n                  <include>org.apache.dubbo:dubbo-metadata-definition-protobuf</include>\n                  <include>org.apache.dubbo:dubbo-metadata-report-nacos</include>\n                  <include>org.apache.dubbo:dubbo-metadata-report-zookeeper</include>\n                  <include>org.apache.dubbo:dubbo-metrics-event</include>\n                  <include>org.apache.dubbo:dubbo-metrics-api</include>\n                  <include>org.apache.dubbo:dubbo-metrics-default</include>\n                  <include>org.apache.dubbo:dubbo-metrics-registry</include>\n                  <include>org.apache.dubbo:dubbo-metrics-metadata</include>\n                  <include>org.apache.dubbo:dubbo-metrics-config-center</include>\n                  <include>org.apache.dubbo:dubbo-metrics-netty</include>\n                  <include>org.apache.dubbo:dubbo-metrics-prometheus</include>\n                  <include>org.apache.dubbo:dubbo-metrics-otlp</include>\n                  <include>org.apache.dubbo:dubbo-tracing</include>\n                  <include>org.apache.dubbo:dubbo-qos</include>\n                  <include>org.apache.dubbo:dubbo-qos-api</include>\n                  <include>org.apache.dubbo:dubbo-security</include>\n                  <include>org.apache.dubbo:dubbo-reactive</include>\n                  <include>org.apache.dubbo:dubbo-mutiny</include>\n                  <include>org.apache.dubbo:dubbo-spring-security</include>\n                  <include>org.apache.dubbo:dubbo-spring6-security</include>\n                  <include>org.apache.dubbo:dubbo-registry-api</include>\n                  <include>org.apache.dubbo:dubbo-registry-multicast</include>\n                  <include>org.apache.dubbo:dubbo-registry-multiple</include>\n                  <include>org.apache.dubbo:dubbo-registry-nacos</include>\n                  <include>org.apache.dubbo:dubbo-registry-zookeeper</include>\n                  <include>org.apache.dubbo:dubbo-remoting-api</include>\n                  <include>org.apache.dubbo:dubbo-remoting-http12</include>\n                  <include>org.apache.dubbo:dubbo-remoting-http3</include>\n                  <include>org.apache.dubbo:dubbo-remoting-websocket</include>\n                  <include>org.apache.dubbo:dubbo-remoting-netty4</include>\n                  <include>org.apache.dubbo:dubbo-remoting-netty</include>\n                  <include>org.apache.dubbo:dubbo-remoting-zookeeper-curator5</include>\n                  <include>org.apache.dubbo:dubbo-rpc-api</include>\n                  <include>org.apache.dubbo:dubbo-rpc-dubbo</include>\n                  <include>org.apache.dubbo:dubbo-rpc-injvm</include>\n                  <include>org.apache.dubbo:dubbo-rpc-triple</include>\n                  <include>org.apache.dubbo:dubbo-rest-jaxrs</include>\n                  <include>org.apache.dubbo:dubbo-rest-spring</include>\n                  <include>org.apache.dubbo:dubbo-rest-openapi</include>\n                  <include>org.apache.dubbo:dubbo-triple-servlet</include>\n                  <include>org.apache.dubbo:dubbo-triple-websocket</include>\n                  <include>org.apache.dubbo:dubbo-serialization-api</include>\n                  <include>org.apache.dubbo:dubbo-serialization-hessian2</include>\n                  <include>org.apache.dubbo:dubbo-serialization-fastjson2</include>\n                  <include>org.apache.dubbo:dubbo-plugin-loom</include>\n                </includes>\n              </artifactSet>\n              <transformers>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/com.alibaba.dubbo.container.page.PageHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.auth.spi.AccessKeyStorage</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.auth.spi.Authenticator</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.compiler.Compiler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.config.OrderedPropertiesProvider</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.context.ApplicationExt</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.context.ModuleExt</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.convert.Converter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.convert.multiple.MultiValueConverter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.deploy.ApplicationDeployListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.deploy.ModuleDeployListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionLoader</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.infra.InfraAdapter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.lang.ShutdownHookCallback</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.logger.LoggerAdapter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.serialize.MultipleSerialization</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.serialize.Serialization</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.status.StatusChecker</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.status.reporter.FrameworkStatusReporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.store.DataStore</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.ThreadPool</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.manager.ExecutorRepository</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.url.component.param.DynamicParamSource</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.ConfigInitializer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.ConfigPostProcessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.ServiceListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.bootstrap.DubboBootstrapStartStopListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.spring.context.DubboSpringInitCustomizer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.spring.extension.SpringExtensionInjector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataParamsFilter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.builder.TypeBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.monitor.MonitorFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.probe.LivenessProbe</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.probe.ReadinessProbe</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.probe.StartupProbe</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.permission.PermissionChecker</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.PenetrateAttachmentSelector</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.AddressListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.ProviderFirstParams</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryServiceListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.RegistryClusterIdentifier</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.MetadataServiceURLBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.ssl.CertProvider</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.MigrationAddressComparator</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.PreMigratingConditionChecker</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.integration.RegistryProtocolListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.ChannelHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Codec</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Codec2</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Dispatcher</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.transport.netty4.ChannelAddressAccessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.dubbo.ByteAccessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.pu.PortUnificationTransporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.connection.ConnectionManager</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.WireProtocol</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.h2.Http2ServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ExporterListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.HeaderFilter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.InvokerListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.PenetrateAttachmentSelector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ProxyFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ZoneDetector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RuleConverter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.ClusterFilter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.InvocationInterceptorBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.mesh.route.MeshEnvListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.ValuePattern</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ApplicationInitListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.BuiltinServiceDetector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.injvm.ParamDeepCopyUtil</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.PathResolver</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.validation.Validation</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.ServiceInstanceNotificationCustomizer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.compressor.Compressor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.stream.ClientStreamFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.ExceptionHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.service.MetricsService</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.service.MetricsServiceExporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.report.MetricsReporterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.pu.PortUnificationTransporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.executor.IsolationExecutorSupportFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.spring.security.jackson.ObjectMapperCodecCustomer</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.PackableMethodFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.aot.api.ProxyDescriberRegistrar</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.aot.api.ResourceDescriberRegistrar</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.json.JsonUtil</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.integration.ServiceURLCustomizer</resource>\n                </transformer>\n              </transformers>\n              <filters>\n                <filter>\n                  <artifact>org.apache.dubbo:dubbo</artifact>\n                  <excludes>\n                    <!-- These following two line are optional, it can remove some warning log -->\n                    <exclude>com/**</exclude>\n                    <exclude>org/**</exclude>\n                    <!-- This one is required -->\n                    <exclude>META-INF/dubbo/**</exclude>\n                  </excludes>\n                </filter>\n              </filters>\n            </configuration>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>spring6-security</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-spring6-security</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n      </dependencies>\n    </profile>\n    <profile>\n      <id>mcp</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-mcp</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n      </dependencies>\n    </profile>\n    <profile>\n      <id>reactive-mutiny</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-mutiny</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n      </dependencies>\n    </profile>\n    <profile>\n      <id>loom</id>\n      <activation>\n        <jdk>[21,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-plugin-loom</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n      </dependencies>\n    </profile>\n    <profile>\n      <id>release</id>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-spring6-security</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-plugin-loom</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-mcp</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-mutiny</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n      </dependencies>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-javadoc-plugin</artifactId>\n            <version>${maven_javadoc_version}</version>\n            <configuration>\n              <includeDependencySources>true</includeDependencySources>\n              <dependencySourceIncludes>\n                <dependencySourceInclude>org.apache.dubbo:dubbo-*</dependencySourceInclude>\n              </dependencySourceIncludes>\n              <show>public</show>\n              <charset>UTF-8</charset>\n              <encoding>UTF-8</encoding>\n              <docencoding>UTF-8</docencoding>\n              <links>\n                <link>http://docs.oracle.com/javase/7/docs/api</link>\n              </links>\n            </configuration>\n            <executions>\n              <execution>\n                <id>attach-javadoc</id>\n                <goals>\n                  <goal>jar</goal>\n                </goals>\n                <configuration>\n                  <doclint>none</doclint>\n                </configuration>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-distribution/dubbo-all-shaded/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n Licensed to the Apache Software Foundation (ASF) under one or more\n contributor license agreements.  See the NOTICE file distributed with\n this work for additional information regarding copyright ownership.\n The ASF licenses this file to You under the Apache License, Version 2.0\n (the \"License\"); you may not use this file except in compliance with\n the License.  You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-all-shaded</artifactId>\n  <packaging>jar</packaging>\n  <name>dubbo-all-shaded</name>\n  <description>The all in one project of dubbo with dependencies prone to conflict shaded</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <!-- cluster -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-cluster</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- common -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- compatible -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-compatible</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- config -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- config-center -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-file</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-zookeeper</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-apollo</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-nacos</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- filter -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-filter-cache</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-filter-validation</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- metadata -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-report-nacos</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-definition-protobuf</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- metrics -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-event</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-registry</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-prometheus</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-metadata</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-config-center</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-netty</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-otlp</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <!-- tracing -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-tracing</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- plugin -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-auth</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-security</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-reactive</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-spring-security</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rest-jaxrs</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rest-spring</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rest-openapi</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-triple-servlet</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-triple-websocket</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- registry -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-multicast</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-multiple</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-nacos</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- remoting -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-http12</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-http3</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-websocket</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-zookeeper-curator5</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- rpc -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-dubbo</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-injvm</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- serialization -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-fastjson2</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- Transitive dependencies -->\n    <dependency>\n      <groupId>org.javassist</groupId>\n      <artifactId>javassist</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.netty</groupId>\n      <artifactId>netty-all</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.yaml</groupId>\n      <artifactId>snakeyaml</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>hessian-lite</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.alibaba.fastjson2</groupId>\n      <artifactId>fastjson2</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java</artifactId>\n    </dependency>\n  </dependencies>\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-shade-plugin</artifactId>\n        <executions>\n          <execution>\n            <goals>\n              <goal>shade</goal>\n            </goals>\n            <phase>package</phase>\n            <configuration>\n              <createSourcesJar>true</createSourcesJar>\n              <shadeSourcesContent>true</shadeSourcesContent>\n              <promoteTransitiveDependencies>false</promoteTransitiveDependencies>\n              <artifactSet>\n                <includes>\n                  <include>org.apache.dubbo:dubbo-auth</include>\n                  <include>org.apache.dubbo:dubbo-cluster</include>\n                  <include>org.apache.dubbo:dubbo-common</include>\n                  <include>org.apache.dubbo:dubbo-compatible</include>\n                  <include>org.apache.dubbo:dubbo-config-api</include>\n                  <include>org.apache.dubbo:dubbo-config-spring</include>\n                  <include>org.apache.dubbo:dubbo-configcenter-file</include>\n                  <include>org.apache.dubbo:dubbo-configcenter-apollo</include>\n                  <include>org.apache.dubbo:dubbo-configcenter-nacos</include>\n                  <include>org.apache.dubbo:dubbo-configcenter-zookeeper</include>\n                  <include>org.apache.dubbo:dubbo-filter-cache</include>\n                  <include>org.apache.dubbo:dubbo-filter-validation</include>\n                  <include>org.apache.dubbo:dubbo-mcp</include>\n                  <include>org.apache.dubbo:dubbo-metadata-api</include>\n                  <include>org.apache.dubbo:dubbo-metadata-definition-protobuf</include>\n                  <include>org.apache.dubbo:dubbo-metadata-report-nacos</include>\n                  <include>org.apache.dubbo:dubbo-metadata-report-zookeeper</include>\n                  <include>org.apache.dubbo:dubbo-metrics-event</include>\n                  <include>org.apache.dubbo:dubbo-metrics-api</include>\n                  <include>org.apache.dubbo:dubbo-metrics-default</include>\n                  <include>org.apache.dubbo:dubbo-metrics-registry</include>\n                  <include>org.apache.dubbo:dubbo-metrics-metadata</include>\n                  <include>org.apache.dubbo:dubbo-metrics-config-center</include>\n                  <include>org.apache.dubbo:dubbo-metrics-netty</include>\n                  <include>org.apache.dubbo:dubbo-metrics-prometheus</include>\n                  <include>org.apache.dubbo:dubbo-metrics-otlp</include>\n                  <include>org.apache.dubbo:dubbo-tracing</include>\n                  <include>org.apache.dubbo:dubbo-qos</include>\n                  <include>org.apache.dubbo:dubbo-qos-api</include>\n                  <include>org.apache.dubbo:dubbo-security</include>\n                  <include>org.apache.dubbo:dubbo-reactive</include>\n                  <include>org.apache.dubbo:dubbo-mutiny</include>\n                  <include>org.apache.dubbo:dubbo-spring-security</include>\n                  <include>org.apache.dubbo:dubbo-spring6-security</include>\n                  <include>org.apache.dubbo:dubbo-registry-api</include>\n                  <include>org.apache.dubbo:dubbo-registry-multicast</include>\n                  <include>org.apache.dubbo:dubbo-registry-multiple</include>\n                  <include>org.apache.dubbo:dubbo-registry-nacos</include>\n                  <include>org.apache.dubbo:dubbo-registry-zookeeper</include>\n                  <include>org.apache.dubbo:dubbo-remoting-api</include>\n                  <include>org.apache.dubbo:dubbo-remoting-http12</include>\n                  <include>org.apache.dubbo:dubbo-remoting-http3</include>\n                  <include>org.apache.dubbo:dubbo-remoting-websocket</include>\n                  <include>org.apache.dubbo:dubbo-remoting-netty4</include>\n                  <include>org.apache.dubbo:dubbo-remoting-netty</include>\n                  <include>org.apache.dubbo:dubbo-remoting-zookeeper-curator5</include>\n                  <include>org.apache.dubbo:dubbo-rpc-api</include>\n                  <include>org.apache.dubbo:dubbo-rpc-dubbo</include>\n                  <include>org.apache.dubbo:dubbo-rpc-injvm</include>\n                  <include>org.apache.dubbo:dubbo-rpc-triple</include>\n                  <include>org.apache.dubbo:dubbo-rest-jaxrs</include>\n                  <include>org.apache.dubbo:dubbo-rest-spring</include>\n                  <include>org.apache.dubbo:dubbo-rest-openapi</include>\n                  <include>org.apache.dubbo:dubbo-triple-servlet</include>\n                  <include>org.apache.dubbo:dubbo-triple-websocket</include>\n                  <include>org.apache.dubbo:dubbo-serialization-api</include>\n                  <include>org.apache.dubbo:dubbo-serialization-hessian2</include>\n                  <include>org.apache.dubbo:dubbo-serialization-fastjson2</include>\n                  <include>org.apache.dubbo:dubbo-plugin-loom</include>\n\n                  <include>io.netty:*</include>\n                </includes>\n              </artifactSet>\n              <transformers>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/com.alibaba.dubbo.container.page.PageHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.auth.spi.AccessKeyStorage</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.auth.spi.Authenticator</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.compiler.Compiler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.config.OrderedPropertiesProvider</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.context.ApplicationExt</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.context.ModuleExt</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.convert.Converter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.convert.multiple.MultiValueConverter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.deploy.ApplicationDeployListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.deploy.ModuleDeployListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionLoader</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.infra.InfraAdapter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.lang.ShutdownHookCallback</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.logger.LoggerAdapter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.serialize.MultipleSerialization</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.serialize.Serialization</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.status.StatusChecker</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.status.reporter.FrameworkStatusReporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.store.DataStore</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.ThreadPool</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.manager.ExecutorRepository</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.url.component.param.DynamicParamSource</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.ConfigInitializer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.ConfigPostProcessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.ServiceListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.bootstrap.DubboBootstrapStartStopListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.spring.context.DubboSpringInitCustomizer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.spring.extension.SpringExtensionInjector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataParamsFilter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.builder.TypeBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.monitor.MonitorFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.probe.LivenessProbe</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.probe.ReadinessProbe</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.probe.StartupProbe</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.permission.PermissionChecker</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.PenetrateAttachmentSelector</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.AddressListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.ProviderFirstParams</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryServiceListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.RegistryClusterIdentifier</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.MetadataServiceURLBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.ssl.CertProvider</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.MigrationAddressComparator</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.PreMigratingConditionChecker</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.integration.RegistryProtocolListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.ChannelHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Codec</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Codec2</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Dispatcher</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.transport.netty4.ChannelAddressAccessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.dubbo.ByteAccessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.pu.PortUnificationTransporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.connection.ConnectionManager</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.WireProtocol</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.h2.Http2ServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ExporterListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.HeaderFilter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.InvokerListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.PenetrateAttachmentSelector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ProxyFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ZoneDetector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RuleConverter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.ClusterFilter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.InvocationInterceptorBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.mesh.route.MeshEnvListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.ValuePattern</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ApplicationInitListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.BuiltinServiceDetector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.injvm.ParamDeepCopyUtil</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.PathResolver</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.validation.Validation</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.ServiceInstanceNotificationCustomizer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.compressor.Compressor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.stream.ClientStreamFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.ExceptionHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.service.MetricsService</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.service.MetricsServiceExporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.report.MetricsReporterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.pu.PortUnificationTransporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.executor.IsolationExecutorSupportFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.spring.security.jackson.ObjectMapperCodecCustomer</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.PackableMethodFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.aot.api.ProxyDescriberRegistrar</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.aot.api.ResourceDescriberRegistrar</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.json.JsonUtil</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.integration.ServiceURLCustomizer</resource>\n                </transformer>\n\n              </transformers>\n              <filters>\n                <filter>\n                  <artifact>org.apache.dubbo:dubbo</artifact>\n                  <excludes>\n                    <!-- These following two line is optional, it can remove some warn log -->\n                    <exclude>com/**</exclude>\n                    <exclude>org/**</exclude>\n                    <!-- This one is required -->\n                    <exclude>META-INF/dubbo/**</exclude>\n                  </excludes>\n                </filter>\n                <filter>\n                  <artifact>io.netty:*</artifact>\n                  <excludes>\n                    <exclude>META-INF/**</exclude>\n                  </excludes>\n                </filter>\n              </filters>\n              <relocations>\n                <relocation>\n                  <pattern>io.netty</pattern>\n                  <shadedPattern>org.apache.dubbo.netty.shaded.io.netty</shadedPattern>\n                </relocation>\n              </relocations>\n            </configuration>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>spring6-security</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-spring6-security</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n      </dependencies>\n    </profile>\n    <profile>\n      <id>mcp</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-mcp</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n      </dependencies>\n    </profile>\n    <profile>\n      <id>reactive-mutiny</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-mutiny</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n      </dependencies>\n    </profile>\n    <profile>\n      <id>loom</id>\n      <activation>\n        <jdk>[21,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-plugin-loom</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n      </dependencies>\n    </profile>\n    <profile>\n      <id>release</id>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-spring6-security</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-plugin-loom</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-mutiny</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-mcp</artifactId>\n          <version>${project.version}</version>\n          <scope>compile</scope>\n          <optional>true</optional>\n        </dependency>\n      </dependencies>\n      <build>\n        <plugins>\n          <plugin>\n            <artifactId>maven-javadoc-plugin</artifactId>\n            <version>${maven_javadoc_version}</version>\n            <configuration>\n              <includeDependencySources>true</includeDependencySources>\n              <dependencySourceIncludes>\n                <dependencySourceInclude>org.apache.dubbo:dubbo-*</dependencySourceInclude>\n              </dependencySourceIncludes>\n              <show>public</show>\n              <charset>UTF-8</charset>\n              <encoding>UTF-8</encoding>\n              <docencoding>UTF-8</docencoding>\n              <links>\n                <link>http://docs.oracle.com/javase/7/docs/api</link>\n              </links>\n            </configuration>\n            <executions>\n              <execution>\n                <id>attach-javadoc</id>\n                <goals>\n                  <goal>jar</goal>\n                </goals>\n                <configuration>\n                  <doclint>none</doclint>\n                </configuration>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-distribution/dubbo-apache-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-apache-release</artifactId>\n  <packaging>pom</packaging>\n  <name>dubbo-apache-release</name>\n  <description>The apache source release</description>\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-demo-api-provider</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-demo-api-consumer</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n  </dependencies>\n\n  <profiles>\n    <profile>\n      <id>release</id>\n      <build>\n        <finalName>apache-dubbo-${project.version}</finalName>\n        <plugins>\n          <plugin>\n            <artifactId>maven-assembly-plugin</artifactId>\n            <version>3.8.0</version>\n            <executions>\n              <execution>\n                <id>bin</id>\n                <goals>\n                  <goal>single</goal>\n                </goals>\n                <phase>package</phase>\n                <configuration>\n                  <descriptors>\n                    <descriptor>src/assembly/bin-release.xml</descriptor>\n                  </descriptors>\n                </configuration>\n              </execution>\n              <execution>\n                <id>src</id>\n                <goals>\n                  <goal>single</goal>\n                </goals>\n                <phase>package</phase>\n                <configuration>\n                  <descriptors>\n                    <descriptor>src/assembly/source-release.xml</descriptor>\n                  </descriptors>\n                </configuration>\n              </execution>\n            </executions>\n          </plugin>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-gpg-plugin</artifactId>\n            <version>1.6</version>\n            <executions>\n              <execution>\n                <goals>\n                  <goal>sign</goal>\n                </goals>\n                <phase>verify</phase>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-distribution/dubbo-apache-release/src/assembly/bin-release.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<assembly xmlns=\"http://maven.apache.org/ASSEMBLY/2.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n          xsi:schemaLocation=\"http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd\">\n    <id>bin</id>\n    <formats>\n        <format>zip</format>\n    </formats>\n    <includeBaseDirectory>true</includeBaseDirectory>\n    <baseDirectory>${project.build.finalName}-bin</baseDirectory>\n    <fileSets>\n        <fileSet>\n            <directory>../../</directory>\n            <includes>\n                <include>DISCLAIMER</include>\n                <include>NOTICE</include>\n                <include>LICENSE</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>../../dubbo-demo</directory>\n            <includes>\n                <include>README.md</include>\n            </includes>\n        </fileSet>\n    </fileSets>\n\n    <dependencySets>\n        <dependencySet>\n            <useProjectArtifact>true</useProjectArtifact>\n            <unpack>false</unpack>\n            <outputDirectory>/dubbo-demo</outputDirectory>\n            <scope>runtime</scope>\n            <includes>\n                <include>org.apache.dubbo:dubbo-demo-api*</include>\n            </includes>\n        </dependencySet>\n    </dependencySets>\n</assembly>\n"
  },
  {
    "path": "dubbo-distribution/dubbo-apache-release/src/assembly/source-release.xml",
    "content": "<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<assembly xmlns=\"http://maven.apache.org/ASSEMBLY/2.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n          xsi:schemaLocation=\"http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd\">\n    <id>src</id>\n    <formats>\n        <format>zip</format>\n    </formats>\n    <includeBaseDirectory>true</includeBaseDirectory>\n    <baseDirectory>${project.build.finalName}-src</baseDirectory>\n\n    <fileSets>\n        <fileSet>\n            <directory>../../</directory>\n            <useDefaultExcludes>true</useDefaultExcludes>\n            <includes>\n                <include>**/*</include>\n            </includes>\n            <excludes>\n                <exclude>**/target/**</exclude>\n                <exclude>**/build/**</exclude>\n                <exclude>**/eclipse-classes/**</exclude>\n                <exclude>*.enc</exclude>\n                <exclude>*.gpg</exclude>\n                <exclude>**/surefire*</exclude>\n                <exclude>**/svn-commit*</exclude>\n                <exclude>**/.idea/**</exclude>\n                <exclude>**/*.iml</exclude>\n                <exclude>**/*.ipr</exclude>\n                <exclude>**/*.iws</exclude>\n                <exclude>**/cobertura.ser</exclude>\n                <exclude>**/*.log</exclude>\n                <exclude>release.properties</exclude>\n                <exclude>**/*.xml.*</exclude>\n                <exclude>**/*.patch</exclude>\n                <exclude>**/.mvn/**</exclude>\n                <exclude>**/*.jar</exclude>\n                <exclude>**/mvnw*</exclude>\n                <exclude>**/.flattened-pom.xml</exclude>\n            </excludes>\n        </fileSet>\n    </fileSets>\n</assembly>\n"
  },
  {
    "path": "dubbo-distribution/dubbo-bom/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n  <modelVersion>4.0.0</modelVersion>\n\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-bom</artifactId>\n  <packaging>pom</packaging>\n\n  <name>dubbo-bom</name>\n\n  <dependencyManagement>\n    <dependencies>\n      <!-- cluster -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-cluster</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- common -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-common</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- compatible -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-compatible</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- compiler -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-compiler</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- config -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-config</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-config-api</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-config-spring</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-config-spring6</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- config-center -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-configcenter</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-configcenter-file</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-configcenter-zookeeper</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-configcenter-apollo</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-configcenter-nacos</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <!-- dependencies-bom -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-dependencies-bom</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-bom</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-all-shaded</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- filter -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-filter</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-filter-cache</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-filter-validation</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- metadata -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metadata</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metadata-api</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metadata-rest</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metadata-report-nacos</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metadata-processor</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metadata-definition-protobuf</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- metrics -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metrics</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metrics-api</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metrics-event</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metrics-default</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metrics-registry</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metrics-prometheus</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metrics-metadata</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metrics-config-center</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metrics-netty</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-metrics-otlp</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <!-- tracing -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-tracing</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- native -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-native</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-maven-plugin</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- plugin -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-auth</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-mcp</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-security</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-qos-api</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-qos</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-reactive</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-mutiny</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-security</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring6-security</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-plugin-loom</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-rest-jaxrs</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-rest-spring</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-rest-openapi</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-triple-servlet</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-triple-websocket</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- registry -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-registry</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-registry-api</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-registry-multicast</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-registry-multiple</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-registry-nacos</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-registry-zookeeper</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- remoting -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-remoting</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-remoting-api</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-remoting-http12</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-remoting-http3</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-remoting-websocket</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-remoting-netty</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-remoting-netty4</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-remoting-zookeeper-curator5</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- rpc -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-rpc</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-rpc-api</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-rpc-dubbo</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-rpc-injvm</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-rpc-triple</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- serialization -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-serialization</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-serialization-api</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-serialization-hessian2</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-serialization-fastjson2</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- spring-boot -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot-actuator</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot-actuator-autoconfigure</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot-autoconfigure</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot-3-autoconfigure</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot-compatible</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot-autoconfigure-compatible</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot-actuator-autoconfigure-compatible</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot-starter</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-spring-boot-starters</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-tracing-otel-zipkin-spring-boot-starter</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-tracing-otel-otlp-spring-boot-starter</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-tracing-brave-zipkin-spring-boot-starter</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-observability-spring-boot-starter</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-nacos-spring-boot-starter</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-zookeeper-curator5-spring-boot-starter</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-sentinel-spring-boot-starter</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-seata-spring-boot-starter</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n      <!-- test -->\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-test</artifactId>\n        <version>${project.version}</version>\n        <type>pom</type>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-test-check</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-test-common</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-test-modules</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-test-spring</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-test-spring3.2</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-test-spring4.1</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n      <dependency>\n        <groupId>org.apache.dubbo</groupId>\n        <artifactId>dubbo-test-spring4.2</artifactId>\n        <version>${project.version}</version>\n      </dependency>\n\n    </dependencies>\n  </dependencyManagement>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.codehaus.mojo</groupId>\n        <artifactId>flatten-maven-plugin</artifactId>\n        <version>${maven_flatten_version}</version>\n        <configuration>\n          <updatePomFile>true</updatePomFile>\n          <flattenMode>bom</flattenMode>\n          <pomElements>\n            <dependencyManagement>expand</dependencyManagement>\n            <properties>remove</properties>\n            <repositories>remove</repositories>\n            <profiles>remove</profiles>\n          </pomElements>\n        </configuration>\n        <executions>\n          <execution>\n            <id>flatten</id>\n            <goals>\n              <goal>flatten</goal>\n            </goals>\n            <phase>process-resources</phase>\n          </execution>\n          <execution>\n            <id>flatten.clean</id>\n            <goals>\n              <goal>clean</goal>\n            </goals>\n            <phase>clean</phase>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>release</id>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-gpg-plugin</artifactId>\n            <executions>\n              <execution>\n                <goals>\n                  <goal>sign</goal>\n                </goals>\n                <phase>verify</phase>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n  </profiles>\n\n</project>\n"
  },
  {
    "path": "dubbo-distribution/dubbo-core-spi/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-core-spi</artifactId>\n  <packaging>jar</packaging>\n  <name>dubbo-core-spi</name>\n  <description>All the SPI definitions of Dubbo</description>\n  <properties>\n    <skip_maven_deploy>true</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-cluster</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-api</artifactId>\n      <version>${project.version}</version>\n      <scope>compile</scope>\n      <optional>true</optional>\n    </dependency>\n    <!-- metadata -->\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-shade-plugin</artifactId>\n        <executions>\n          <execution>\n            <goals>\n              <goal>shade</goal>\n            </goals>\n            <phase>package</phase>\n            <configuration>\n              <createSourcesJar>true</createSourcesJar>\n              <promoteTransitiveDependencies>false</promoteTransitiveDependencies>\n              <artifactSet>\n                <includes>\n                  <include>org.apache.dubbo:dubbo-cluster</include>\n                  <include>org.apache.dubbo:dubbo-common</include>\n                  <include>org.apache.dubbo:dubbo-config-api</include>\n                  <include>org.apache.dubbo:dubbo-metadata-api</include>\n                  <include>org.apache.dubbo:dubbo-metrics-api</include>\n                  <include>org.apache.dubbo:dubbo-metrics-default</include>\n                  <include>org.apache.dubbo:dubbo-tracing</include>\n                  <include>org.apache.dubbo:dubbo-registry-api</include>\n                  <include>org.apache.dubbo:dubbo-remoting-api</include>\n                  <include>org.apache.dubbo:dubbo-remoting</include>\n                  <include>org.apache.dubbo:dubbo-rpc-api</include>\n                  <include>org.apache.dubbo:dubbo-serialization-api</include>\n                </includes>\n              </artifactSet>\n              <transformers>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/com.alibaba.dubbo.container.page.PageHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.auth.spi.AccessKeyStorage</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.auth.spi.Authenticator</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.compiler.Compiler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.config.OrderedPropertiesProvider</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.context.ApplicationExt</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.context.ModuleExt</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.convert.Converter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.convert.multiple.MultiValueConverter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.deploy.ApplicationDeployListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.deploy.ModuleDeployListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionLoader</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.infra.InfraAdapter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.lang.ShutdownHookCallback</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.logger.LoggerAdapter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.serialize.MultipleSerialization</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.serialize.Serialization</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.status.StatusChecker</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.status.reporter.FrameworkStatusReporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.store.DataStore</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.ThreadPool</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.manager.ExecutorRepository</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.url.component.param.DynamicParamSource</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.ConfigInitializer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.ConfigPostProcessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.ServiceListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.bootstrap.DubboBootstrapStartStopListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.spring.context.DubboSpringInitCustomizer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.config.spring.extension.SpringExtensionInjector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataParamsFilter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.builder.TypeBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.monitor.MonitorFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.probe.LivenessProbe</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.probe.ReadinessProbe</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.probe.StartupProbe</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.qos.permission.PermissionChecker</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.PenetrateAttachmentSelector</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.AddressListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.ProviderFirstParams</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryServiceListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.RegistryClusterIdentifier</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.MetadataServiceURLBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.ssl.CertProvider</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.MigrationAddressComparator</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.PreMigratingConditionChecker</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.integration.RegistryProtocolListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.ChannelHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Codec</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Codec2</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Dispatcher</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.transport.netty4.ChannelAddressAccessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.dubbo.ByteAccessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.pu.PortUnificationTransporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.connection.ConnectionManager</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.WireProtocol</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.h2.Http2ServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ExporterListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.HeaderFilter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.InvokerListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.PenetrateAttachmentSelector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ProxyFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.ZoneDetector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RuleConverter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.ClusterFilter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.InvocationInterceptorBuilder</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.mesh.route.MeshEnvListenerFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.ValuePattern</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ApplicationInitListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.BuiltinServiceDetector</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.injvm.ParamDeepCopyUtil</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.PathResolver</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.validation.Validation</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.ServiceInstanceNotificationCustomizer</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.compressor.Compressor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.stream.ClientStreamFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.ExceptionHandler</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.service.MetricsService</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.service.MetricsServiceExporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.report.MetricsReporterFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedListener</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.api.pu.PortUnificationTransporter</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.executor.IsolationExecutorSupportFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.spring.security.jackson.ObjectMapperCodecCustomer</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.model.PackableMethodFactory</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.aot.api.ProxyDescriberRegistrar</resource>\n                </transformer>\n\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.aot.api.ResourceDescriberRegistrar</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.common.json.JsonUtil</resource>\n                </transformer>\n                <transformer implementation=\"org.apache.maven.plugins.shade.resource.AppendingTransformer\">\n                  <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.integration.ServiceURLCustomizer</resource>\n                </transformer>\n              </transformers>\n              <filters>\n                <filter>\n                  <artifact>org.apache.dubbo:dubbo</artifact>\n                  <excludes>\n                    <!-- These following two line is optional, it can remove some warn log -->\n                    <exclude>com/**</exclude>\n                    <exclude>org/**</exclude>\n                    <!-- This one is required -->\n                    <exclude>META-INF/dubbo/**</exclude>\n                  </excludes>\n                </filter>\n              </filters>\n            </configuration>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "dubbo-maven-plugin/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n  </parent>\n\n  <artifactId>dubbo-maven-plugin</artifactId>\n  <packaging>maven-plugin</packaging>\n  <description>Dubbo Maven Plugin</description>\n\n  <properties>\n    <dubbo.version>${revision}</dubbo.version>\n    <!-- the protobuf-java version should be same with the version defined at dubbo-dependencies-bom -->\n    <protobuf-java.version>4.33.4</protobuf-java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.maven</groupId>\n      <artifactId>maven-plugin-api</artifactId>\n      <version>3.9.14</version>\n      <scope>provided</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.maven</groupId>\n      <artifactId>maven-core</artifactId>\n      <version>3.9.14</version>\n      <scope>provided</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.codehaus.plexus</groupId>\n      <artifactId>plexus-utils</artifactId>\n      <version>3.6.0</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.maven.plugin-tools</groupId>\n      <artifactId>maven-plugin-annotations</artifactId>\n      <version>3.15.2</version>\n      <scope>provided</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.maven.shared</groupId>\n      <artifactId>maven-common-artifact-filters</artifactId>\n      <version>3.4.0</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>commons-io</groupId>\n      <artifactId>commons-io</artifactId>\n      <version>2.21.0</version>\n    </dependency>\n\n    <!-- Takes no effect for this dependency. To notify github dependencies bot to update ${protobuf-java.version} property.  -->\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java</artifactId>\n      <version>${protobuf-java.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.sonatype.plexus</groupId>\n      <artifactId>plexus-build-api</artifactId>\n      <version>0.0.7</version>\n      <exclusions>\n        <exclusion>\n          <groupId>org.codehaus.plexus</groupId>\n          <artifactId>plexus-utils</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <resources>\n      <resource>\n        <filtering>true</filtering>\n        <directory>src/main/resources</directory>\n      </resource>\n    </resources>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-plugin-plugin</artifactId>\n        <version>3.15.2</version>\n        <configuration>\n          <goalPrefix>dubbo</goalPrefix>\n        </configuration>\n        <executions>\n          <execution>\n            <id>default-addPluginArtifactMetadata</id>\n            <goals>\n              <goal>addPluginArtifactMetadata</goal>\n            </goals>\n            <phase>package</phase>\n          </execution>\n          <execution>\n            <id>default-descriptor</id>\n            <goals>\n              <goal>descriptor</goal>\n            </goals>\n            <phase>process-classes</phase>\n          </execution>\n        </executions>\n      </plugin>\n\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/AbstractAotMojo.java",
    "content": "/*\n * Copyright 2012-2022 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.aot;\n\n\nimport org.apache.maven.execution.MavenSession;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.MojoFailureException;\nimport org.apache.maven.plugins.annotations.Component;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;\nimport org.apache.maven.toolchain.ToolchainManager;\n\nimport javax.tools.Diagnostic;\nimport javax.tools.DiagnosticListener;\nimport javax.tools.JavaCompiler;\nimport javax.tools.JavaFileObject;\nimport javax.tools.StandardJavaFileManager;\nimport javax.tools.ToolProvider;\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\n/**\n * Abstract base class for AOT processing MOJOs.\n */\npublic abstract class AbstractAotMojo extends AbstractDependencyFilterMojo {\n\n    /**\n     * The current Maven session. This is used for toolchain manager API calls.\n     */\n    @Parameter(defaultValue = \"${session}\", readonly = true)\n    private MavenSession session;\n\n    /**\n     * The toolchain manager to use to locate a custom JDK.\n     */\n    @Component\n    private ToolchainManager toolchainManager;\n\n    /**\n     * Skip the execution.\n     */\n    @Parameter(property = \"dubbo.aot.skip\", defaultValue = \"false\")\n    private boolean skip;\n\n    /**\n     * List of JVM system properties to pass to the AOT process.\n     */\n    @Parameter\n    private Map<String, String> systemPropertyVariables;\n\n    /**\n     * JVM arguments that should be associated with the AOT process. On command line, make\n     * sure to wrap multiple values between quotes.\n     */\n    @Parameter(property = \"dubbo.aot.jvmArguments\")\n    private String jvmArguments;\n\n\n    /**\n     * Arguments that should be provided to the AOT compile process. On command line, make\n     * sure to wrap multiple values between quotes.\n     */\n    @Parameter(property = \"dubbo.aot.compilerArguments\")\n    private String compilerArguments;\n\n    @Override\n    public void execute() throws MojoExecutionException, MojoFailureException {\n        if (this.skip) {\n            getLog().debug(\"Skipping AOT execution as per configuration\");\n            return;\n        }\n        try {\n            executeAot();\n        } catch (Exception ex) {\n            throw new MojoExecutionException(ex.getMessage(), ex);\n        }\n    }\n\n    protected abstract void executeAot() throws Exception;\n\n    protected void generateAotAssets(URL[] classPath, String processorClassName, String... arguments) throws Exception {\n        List<String> command = CommandLineBuilder.forMainClass(processorClassName)\n            .withSystemProperties(this.systemPropertyVariables)\n            .withJvmArguments(new RunArguments(this.jvmArguments).asArray()).withClasspath(classPath)\n            .withArguments(arguments).build();\n        if (getLog().isDebugEnabled()) {\n            getLog().debug(\"Generating AOT assets using command: \" + command);\n        }\n        JavaProcessExecutor processExecutor = new JavaProcessExecutor(this.session, this.toolchainManager);\n        getLog().info(\"dir: \" + this.project.getBasedir());\n        processExecutor.run(this.project.getBasedir(), command, Collections.emptyMap());\n    }\n\n    protected final void compileSourceFiles(URL[] classPath, File sourcesDirectory, File outputDirectory)\n        throws Exception {\n        List<File> sourceFiles;\n        try (Stream<Path> pathStream = Files.walk(sourcesDirectory.toPath())) {\n            sourceFiles = pathStream.filter(Files::isRegularFile).map(Path::toFile).collect(Collectors.toList());\n        }\n        if (sourceFiles.isEmpty()) {\n            return;\n        }\n        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();\n        try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {\n            JavaCompilerPluginConfiguration compilerConfiguration = new JavaCompilerPluginConfiguration(this.project);\n            List<String> options = new ArrayList<>();\n            options.add(\"-cp\");\n            options.add(CommandLineBuilder.ClasspathBuilder.build(Arrays.asList(classPath)));\n            options.add(\"-d\");\n            options.add(outputDirectory.toPath().toAbsolutePath().toString());\n            String releaseVersion = compilerConfiguration.getReleaseVersion();\n            if (releaseVersion != null) {\n                options.add(\"--release\");\n                options.add(releaseVersion);\n            }\n            else {\n                options.add(\"--source\");\n                options.add(compilerConfiguration.getSourceMajorVersion());\n                options.add(\"--target\");\n                options.add(compilerConfiguration.getTargetMajorVersion());\n            }\n            options.addAll(new RunArguments(this.compilerArguments).getArgs());\n            Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(sourceFiles);\n            Errors errors = new Errors();\n            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, errors, options, null, compilationUnits);\n            boolean result = task.call();\n            if (!result || errors.hasReportedErrors()) {\n                throw new IllegalStateException(\"Unable to compile generated source\" + errors);\n            }\n        }\n    }\n\n    protected final List<URL> getClassPath(File[] directories, ArtifactsFilter... artifactFilters)\n        throws MojoExecutionException {\n        List<URL> urls = new ArrayList<>();\n        Arrays.stream(directories).map(this::toURL).forEach(urls::add);\n        urls.addAll(getDependencyURLs(artifactFilters));\n        return urls;\n    }\n\n    protected final void copyAll(Path from, Path to) throws IOException {\n        if (!Files.exists(from)) {\n            return;\n        }\n        List<Path> files;\n        try (Stream<Path> pathStream = Files.walk(from)) {\n            files = pathStream.filter(Files::isRegularFile).collect(Collectors.toList());\n        }\n        for (Path file : files) {\n            String relativeFileName = file.subpath(from.getNameCount(), file.getNameCount()).toString();\n            getLog().debug(\"Copying '\" + relativeFileName + \"' to \" + to);\n            Path target = to.resolve(relativeFileName);\n            Files.createDirectories(target.getParent());\n            Files.copy(file, target, StandardCopyOption.REPLACE_EXISTING);\n        }\n    }\n\n    /**\n     * {@link DiagnosticListener} used to collect errors.\n     */\n    protected static class Errors implements DiagnosticListener<JavaFileObject> {\n\n        private final StringBuilder message = new StringBuilder();\n\n        @Override\n        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {\n            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {\n                this.message.append(\"\\n\");\n                this.message.append(diagnostic.getMessage(Locale.getDefault()));\n                if (diagnostic.getSource() != null) {\n                    this.message.append(\" \");\n                    this.message.append(diagnostic.getSource().getName());\n                    this.message.append(\" \");\n                    this.message.append(diagnostic.getLineNumber()).append(\":\").append(diagnostic.getColumnNumber());\n                }\n            }\n        }\n\n        boolean hasReportedErrors() {\n            return this.message.length() > 0;\n        }\n\n        @Override\n        public String toString() {\n            return this.message.toString();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/AbstractDependencyFilterMojo.java",
    "content": "/*\n * Copyright 2012-2022 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.artifact.resolver.filter.ArtifactFilter;\nimport org.apache.maven.plugin.AbstractMojo;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.project.MavenProject;\nimport org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;\nimport org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;\n\nimport java.io.File;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.StringTokenizer;\n\n/**\n * A base mojo filtering the dependencies of the project.\n */\npublic abstract class AbstractDependencyFilterMojo extends AbstractMojo {\n\n    /**\n     * The Maven project.\n     */\n    @Parameter(defaultValue = \"${project}\", readonly = true, required = true)\n    protected MavenProject project;\n\n    /**\n     * Collection of artifact definitions to include. The {@link Include} element defines\n     * mandatory {@code groupId} and {@code artifactId} properties and an optional\n     * mandatory {@code groupId} and {@code artifactId} properties and an optional\n     * {@code classifier} property.\n     */\n    @Parameter(property = \"dubbo.includes\")\n    private List<Include> includes;\n\n    /**\n     * Collection of artifact definitions to exclude. The {@link Exclude} element defines\n     * mandatory {@code groupId} and {@code artifactId} properties and an optional\n     * {@code classifier} property.\n     */\n    @Parameter(property = \"dubbo.excludes\")\n    private List<Exclude> excludes;\n\n    /**\n     * Comma separated list of groupId names to exclude (exact match).\n     */\n    @Parameter(property = \"dubbo.excludeGroupIds\", defaultValue = \"\")\n    private String excludeGroupIds;\n\n    protected void setExcludes(List<Exclude> excludes) {\n        this.excludes = excludes;\n    }\n\n    protected void setIncludes(List<Include> includes) {\n        this.includes = includes;\n    }\n\n    protected void setExcludeGroupIds(String excludeGroupIds) {\n        this.excludeGroupIds = excludeGroupIds;\n    }\n\n    protected List<URL> getDependencyURLs(ArtifactsFilter... additionalFilters) throws MojoExecutionException {\n        Set<Artifact> artifacts = filterDependencies(this.project.getArtifacts(), additionalFilters);\n        List<URL> urls = new ArrayList<>();\n        for (Artifact artifact : artifacts) {\n            if (artifact.getFile() != null) {\n                urls.add(toURL(artifact.getFile()));\n            }\n        }\n        return urls;\n    }\n\n    protected final Set<Artifact> filterDependencies(Set<Artifact> dependencies, ArtifactsFilter... additionalFilters)\n        throws MojoExecutionException {\n        try {\n            Set<Artifact> filtered = new LinkedHashSet<>(dependencies);\n            filtered.retainAll(getFilters(additionalFilters).filter(dependencies));\n            return filtered;\n        }\n        catch (ArtifactFilterException ex) {\n            throw new MojoExecutionException(ex.getMessage(), ex);\n        }\n    }\n\n    protected URL toURL(File file) {\n        try {\n            return file.toURI().toURL();\n        }\n        catch (MalformedURLException ex) {\n            throw new IllegalStateException(\"Invalid URL for \" + file, ex);\n        }\n    }\n\n    /**\n     * Return artifact filters configured for this MOJO.\n     * @param additionalFilters optional additional filters to apply\n     * @return the filters\n     */\n    private FilterArtifacts getFilters(ArtifactsFilter... additionalFilters) {\n        FilterArtifacts filters = new FilterArtifacts();\n        for (ArtifactsFilter additionalFilter : additionalFilters) {\n            filters.addFilter(additionalFilter);\n        }\n        filters.addFilter(new MatchingGroupIdFilter(cleanFilterConfig(this.excludeGroupIds)));\n        if (this.includes != null && !this.includes.isEmpty()) {\n            filters.addFilter(new IncludeFilter(this.includes));\n        }\n        if (this.excludes != null && !this.excludes.isEmpty()) {\n            filters.addFilter(new ExcludeFilter(this.excludes));\n        }\n        return filters;\n    }\n\n    private String cleanFilterConfig(String content) {\n        if (content == null || content.trim().isEmpty()) {\n            return \"\";\n        }\n        StringBuilder cleaned = new StringBuilder();\n        StringTokenizer tokenizer = new StringTokenizer(content, \",\");\n        while (tokenizer.hasMoreElements()) {\n            cleaned.append(tokenizer.nextToken().trim());\n            if (tokenizer.hasMoreElements()) {\n                cleaned.append(\",\");\n            }\n        }\n        return cleaned.toString();\n    }\n\n    /**\n     * {@link ArtifactFilter} to exclude test scope dependencies.\n     */\n    protected static class ExcludeTestScopeArtifactFilter extends AbstractArtifactFeatureFilter {\n\n        ExcludeTestScopeArtifactFilter() {\n            super(\"\", Artifact.SCOPE_TEST);\n        }\n\n        @Override\n        protected String getArtifactFeature(Artifact artifact) {\n            return artifact.getScope();\n        }\n\n    }\n\n}\n\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/CommandLineBuilder.java",
    "content": "/*\n * Copyright 2012-2022 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport java.io.File;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\n/**\n * Helper class to build the command-line arguments of a java process.\n */\nfinal class CommandLineBuilder {\n\n\tprivate final List<String> options = new ArrayList<>();\n\n\tprivate final List<URL> classpathElements = new ArrayList<>();\n\n\tprivate final String mainClass;\n\n\tprivate final List<String> arguments = new ArrayList<>();\n\n\tprivate CommandLineBuilder(String mainClass) {\n\t\tthis.mainClass = mainClass;\n\t}\n\n\tstatic CommandLineBuilder forMainClass(String mainClass) {\n\t\treturn new CommandLineBuilder(mainClass);\n\t}\n\n\tCommandLineBuilder withJvmArguments(String... jvmArguments) {\n\t\tif (jvmArguments != null) {\n\t\t\tthis.options.addAll(Arrays.stream(jvmArguments).filter(Objects::nonNull).collect(Collectors.toList()));\n\t\t}\n\t\treturn this;\n\t}\n\n\tCommandLineBuilder withSystemProperties(Map<String, String> systemProperties) {\n\t\tif (systemProperties != null) {\n\t\t\tsystemProperties.entrySet().stream().map((e) -> SystemPropertyFormatter.format(e.getKey(), e.getValue()))\n\t\t\t\t\t.forEach(this.options::add);\n\t\t}\n\t\treturn this;\n\t}\n\n\tCommandLineBuilder withClasspath(URL... elements) {\n\t\tthis.classpathElements.addAll(Arrays.asList(elements));\n\t\treturn this;\n\t}\n\n\tCommandLineBuilder withArguments(String... arguments) {\n\t\tif (arguments != null) {\n\t\t\tthis.arguments.addAll(Arrays.stream(arguments).filter(Objects::nonNull).collect(Collectors.toList()));\n\t\t}\n\t\treturn this;\n\t}\n\n\tList<String> build() {\n\t\tList<String> commandLine = new ArrayList<>();\n\t\tif (!this.options.isEmpty()) {\n\t\t\tcommandLine.addAll(this.options);\n\t\t}\n\t\tif (!this.classpathElements.isEmpty()) {\n\t\t\tcommandLine.add(\"-cp\");\n\t\t\tcommandLine.add(ClasspathBuilder.build(this.classpathElements));\n\t\t}\n\t\tcommandLine.add(this.mainClass);\n\t\tif (!this.arguments.isEmpty()) {\n\t\t\tcommandLine.addAll(this.arguments);\n\t\t}\n\t\treturn commandLine;\n\t}\n\n\tstatic class ClasspathBuilder {\n\n\t\tstatic String build(List<URL> classpathElements) {\n\t\t\tStringBuilder classpath = new StringBuilder();\n\t\t\tfor (URL element : classpathElements) {\n\t\t\t\tif (classpath.length() > 0) {\n\t\t\t\t\tclasspath.append(File.pathSeparator);\n\t\t\t\t}\n\t\t\t\tclasspath.append(toFile(element));\n\t\t\t}\n\t\t\treturn classpath.toString();\n\t\t}\n\n\t\tprivate static File toFile(URL element) {\n\t\t\ttry {\n\t\t\t\treturn new File(element.toURI());\n\t\t\t}\n\t\t\tcatch (URISyntaxException ex) {\n\t\t\t\tthrow new IllegalArgumentException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * Format System properties.\n\t */\n\tprivate static class SystemPropertyFormatter {\n\n\t\tstatic String format(String key, String value) {\n\t\t\tif (key == null) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\tif (value == null || value.isEmpty()) {\n\t\t\t\treturn String.format(\"-D%s\", key);\n\t\t\t}\n\t\t\treturn String.format(\"-D%s=\\\"%s\\\"\", key, value);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/DependencyFilter.java",
    "content": "/*\n * Copyright 2012-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 org.apache.dubbo.maven.plugin.aot;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.shared.artifact.filter.collection.AbstractArtifactsFilter;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Base class for {@link ArtifactsFilter} based on a {@link org.apache.dubbo.maven.plugin.aot.FilterableDependency} list.\n */\npublic abstract class DependencyFilter extends AbstractArtifactsFilter {\n\n\tprivate final List<? extends FilterableDependency> filters;\n\n\t/**\n\t * Create a new instance with the list of {@link FilterableDependency} instance(s) to\n\t * use.\n\t * @param dependencies the source dependencies\n\t */\n\tpublic DependencyFilter(List<? extends FilterableDependency> dependencies) {\n\t\tthis.filters = dependencies;\n\t}\n\n\t@Override\n\tpublic Set<Artifact> filter(Set<Artifact> artifacts) throws ArtifactFilterException {\n\t\tSet<Artifact> result = new HashSet<>();\n\t\tfor (Artifact artifact : artifacts) {\n\t\t\tif (!filter(artifact)) {\n\t\t\t\tresult.add(artifact);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprotected abstract boolean filter(Artifact artifact);\n\n\t/**\n\t * Check if the specified {@link Artifact} matches the\n\t * specified {@link org.apache.dubbo.maven.plugin.aot.FilterableDependency}. Returns\n\t * {@code true} if it should be excluded\n\t * @param artifact the Maven {@link Artifact}\n\t * @param dependency the {@link org.apache.dubbo.maven.plugin.aot.FilterableDependency}\n\t * @return {@code true} if the artifact matches the dependency\n\t */\n\tprotected final boolean equals(Artifact artifact, FilterableDependency dependency) {\n\t\tif (!dependency.getGroupId().equals(artifact.getGroupId())) {\n\t\t\treturn false;\n\t\t}\n\t\tif (!dependency.getArtifactId().equals(artifact.getArtifactId())) {\n\t\t\treturn false;\n\t\t}\n\t\treturn (dependency.getClassifier() == null\n\t\t\t\t|| artifact.getClassifier() != null && dependency.getClassifier().equals(artifact.getClassifier()));\n\t}\n\n\tprotected final List<? extends FilterableDependency> getFilters() {\n\t\treturn this.filters;\n\t}\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/DubboProcessAotMojo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.plugins.annotations.ResolutionScope;\n\n@Mojo(\n        name = \"dubbo-process-aot\",\n        defaultPhase = LifecyclePhase.PREPARE_PACKAGE,\n        threadSafe = true,\n        requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,\n        requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)\npublic class DubboProcessAotMojo extends AbstractAotMojo {\n\n    private static final String AOT_PROCESSOR_CLASS_NAME = \"org.apache.dubbo.aot.generate.AotProcessor\";\n\n    /**\n     * Directory containing the classes and resource files that should be packaged into\n     * the archive.\n     */\n    @Parameter(defaultValue = \"${project.build.outputDirectory}\", required = true)\n    private File classesDirectory;\n\n    /**\n     * Directory containing the generated sources.\n     */\n    @Parameter(defaultValue = \"${project.build.directory}/dubbo-aot/main/sources\", required = true)\n    private File generatedSources;\n\n    /**\n     * Directory containing the generated resources.\n     */\n    @Parameter(defaultValue = \"${project.build.directory}/dubbo-aot/main/resources\", required = true)\n    private File generatedResources;\n\n    /**\n     * Directory containing the generated classes.\n     */\n    @Parameter(defaultValue = \"${project.build.directory}/dubbo-aot/main/classes\", required = true)\n    private File generatedClasses;\n\n    /**\n     * Name of the main class to use as the source for the AOT process. If not specified\n     * the first compiled class found that contains a 'main' method will be used.\n     */\n    @Parameter(property = \"dubbo.aot.main-class\")\n    private String mainClass;\n\n    /**\n     * Application arguments that should be taken into account for AOT processing.\n     */\n    @Parameter\n    private String[] arguments;\n\n    @Override\n    protected void executeAot() throws Exception {\n        URL[] classPath = getClassPath().toArray(new URL[0]);\n        generateAotAssets(classPath, AOT_PROCESSOR_CLASS_NAME, getAotArguments(mainClass));\n        compileSourceFiles(classPath, this.generatedSources, this.classesDirectory);\n        copyAll(this.generatedResources.toPath(), this.classesDirectory.toPath());\n        copyAll(this.generatedClasses.toPath(), this.classesDirectory.toPath());\n    }\n\n    private String[] getAotArguments(String applicationClass) {\n        List<String> aotArguments = new ArrayList<>();\n        aotArguments.add(applicationClass != null ? applicationClass : \"\");\n        aotArguments.add(this.generatedSources.toString());\n        aotArguments.add(this.generatedResources.toString());\n        aotArguments.add(this.generatedClasses.toString());\n        aotArguments.add(this.project.getGroupId());\n        aotArguments.add(this.project.getArtifactId());\n        aotArguments.addAll(new RunArguments(this.arguments).getArgs());\n        return aotArguments.toArray(new String[0]);\n    }\n\n    private List<URL> getClassPath() throws Exception {\n        File[] directories = new File[] {this.classesDirectory, this.generatedClasses};\n        return getClassPath(directories, new ExcludeTestScopeArtifactFilter());\n    }\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/Exclude.java",
    "content": "/*\n * Copyright 2012-2019 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\n/**\n * A model for a dependency to exclude.\n */\npublic class Exclude extends FilterableDependency {\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/ExcludeFilter.java",
    "content": "/*\n * Copyright 2012-2019 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport org.apache.maven.artifact.Artifact;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * An {DependencyFilter} that filters out any artifact matching an {@link Exclude}.\n */\npublic class ExcludeFilter extends DependencyFilter {\n\n\tpublic ExcludeFilter(Exclude... excludes) {\n\t\tthis(Arrays.asList(excludes));\n\t}\n\n\tpublic ExcludeFilter(List<Exclude> excludes) {\n\t\tsuper(excludes);\n\t}\n\n\t@Override\n\tprotected boolean filter(Artifact artifact) {\n\t\tfor (FilterableDependency dependency : getFilters()) {\n\t\t\tif (equals(artifact, dependency)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/FilterableDependency.java",
    "content": "/*\n * Copyright 2012-2019 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport org.apache.maven.plugins.annotations.Parameter;\n\n/**\n * A model for a dependency to include or exclude.\n */\nabstract class FilterableDependency {\n\n\t/**\n\t * The groupId of the artifact to exclude.\n\t */\n\t@Parameter(required = true)\n\tprivate String groupId;\n\n\t/**\n\t * The artifactId of the artifact to exclude.\n\t */\n\t@Parameter(required = true)\n\tprivate String artifactId;\n\n\t/**\n\t * The classifier of the artifact to exclude.\n\t */\n\t@Parameter\n\tprivate String classifier;\n\n\tString getGroupId() {\n\t\treturn this.groupId;\n\t}\n\n\tvoid setGroupId(String groupId) {\n\t\tthis.groupId = groupId;\n\t}\n\n\tString getArtifactId() {\n\t\treturn this.artifactId;\n\t}\n\n\tvoid setArtifactId(String artifactId) {\n\t\tthis.artifactId = artifactId;\n\t}\n\n\tString getClassifier() {\n\t\treturn this.classifier;\n\t}\n\n\tvoid setClassifier(String classifier) {\n\t\tthis.classifier = classifier;\n\t}\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/Include.java",
    "content": "/*\n * Copyright 2012-2019 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\n/**\n * A model for a dependency to include.\n */\npublic class Include extends FilterableDependency {\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/IncludeFilter.java",
    "content": "/*\n * Copyright 2012-2019 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;\n\nimport java.util.List;\n\n/**\n * An {@link ArtifactsFilter} that filters out any artifact not matching an\n * {@link Include}.\n */\npublic class IncludeFilter extends DependencyFilter {\n\n\tpublic IncludeFilter(List<Include> includes) {\n\t\tsuper(includes);\n\t}\n\n\t@Override\n\tprotected boolean filter(Artifact artifact) {\n\t\tfor (FilterableDependency dependency : getFilters()) {\n\t\t\tif (equals(artifact, dependency)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/JavaCompilerPluginConfiguration.java",
    "content": "/*\n * Copyright 2012-2022 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport org.apache.maven.model.Plugin;\nimport org.apache.maven.project.MavenProject;\nimport org.codehaus.plexus.util.xml.Xpp3Dom;\n\nimport java.util.Arrays;\n\n/**\n * Provides access to the Maven Java Compiler plugin configuration.\n */\nclass JavaCompilerPluginConfiguration {\n\n\tprivate final MavenProject project;\n\n\tJavaCompilerPluginConfiguration(MavenProject project) {\n\t\tthis.project = project;\n\t}\n\n\tString getSourceMajorVersion() {\n\t\tString version = getConfigurationValue(\"source\");\n\n\t\tif (version == null) {\n\t\t\tversion = getPropertyValue(\"maven.compiler.source\");\n\t\t}\n\n\t\treturn majorVersionFor(version);\n\t}\n\n\tString getTargetMajorVersion() {\n\t\tString version = getConfigurationValue(\"target\");\n\n\t\tif (version == null) {\n\t\t\tversion = getPropertyValue(\"maven.compiler.target\");\n\t\t}\n\n\t\treturn majorVersionFor(version);\n\t}\n\n\tString getReleaseVersion() {\n\t\tString version = getConfigurationValue(\"release\");\n\n\t\tif (version == null) {\n\t\t\tversion = getPropertyValue(\"maven.compiler.release\");\n\t\t}\n\n\t\treturn majorVersionFor(version);\n\t}\n\n\tprivate String getConfigurationValue(String propertyName) {\n\t\tPlugin plugin = this.project.getPlugin(\"org.apache.maven.plugins:maven-compiler-plugin\");\n\t\tif (plugin != null) {\n\t\t\tObject pluginConfiguration = plugin.getConfiguration();\n\t\t\tif (pluginConfiguration instanceof Xpp3Dom) {\n\t\t\t\treturn getNodeValue((Xpp3Dom)pluginConfiguration, propertyName);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate String getPropertyValue(String propertyName) {\n\t\tif (this.project.getProperties().containsKey(propertyName)) {\n\t\t\treturn this.project.getProperties().get(propertyName).toString();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate String getNodeValue(Xpp3Dom dom, String... childNames) {\n\t\tXpp3Dom childNode = dom.getChild(childNames[0]);\n\n\t\tif (childNode == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (childNames.length > 1) {\n\t\t\treturn getNodeValue(childNode, Arrays.copyOfRange(childNames, 1, childNames.length));\n\t\t}\n\n\t\treturn childNode.getValue();\n\t}\n\n\tprivate String majorVersionFor(String version) {\n\t\tif (version != null && version.startsWith(\"1.\")) {\n\t\t\treturn version.substring(\"1.\".length());\n\t\t}\n\t\treturn version;\n\t}\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/JavaExecutable.java",
    "content": "/*\n * Copyright 2012-2022 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\n\n/**\n * Provides access to the java binary executable, regardless of OS.\n */\npublic class JavaExecutable {\n\n    private final File file;\n\n    public JavaExecutable() {\n        String javaHome = SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_HOME);\n        Assert.assertTrue(StringUtils.isNotEmpty(javaHome), \"Unable to find java executable due to missing 'java.home'\");\n        this.file = findInJavaHome(javaHome);\n    }\n\n    private File findInJavaHome(String javaHome) {\n        File bin = new File(new File(javaHome), \"bin\");\n        File command = new File(bin, \"java.exe\");\n        command = command.exists() ? command : new File(bin, \"java\");\n        Assert.assertTrue(command.exists(), () -> \"Unable to find java in \" + javaHome);\n        return command;\n    }\n\n    /**\n     * Create a new {@link ProcessBuilder} that will run with the Java executable.\n     *\n     * @param arguments the command arguments\n     * @return a {@link ProcessBuilder}\n     */\n    public ProcessBuilder processBuilder(String... arguments) {\n        ProcessBuilder processBuilder = new ProcessBuilder(toString());\n        processBuilder.command().addAll(Arrays.asList(arguments));\n        return processBuilder;\n    }\n\n    @Override\n    public String toString() {\n        try {\n            return this.file.getCanonicalPath();\n        } catch (IOException ex) {\n            throw new IllegalStateException(ex);\n        }\n    }\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/JavaProcessExecutor.java",
    "content": "/*\n * Copyright 2012-2022 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport org.apache.maven.execution.MavenSession;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.toolchain.Toolchain;\nimport org.apache.maven.toolchain.ToolchainManager;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\n/**\n * Ease the execution of a Java process using Maven's toolchain support.\n */\nclass JavaProcessExecutor {\n\n\tprivate static final int EXIT_CODE_SIGINT = 130;\n\n\tprivate final MavenSession mavenSession;\n\n\tprivate final ToolchainManager toolchainManager;\n\n\tprivate final Consumer<RunProcess> runProcessCustomizer;\n\n\tJavaProcessExecutor(MavenSession mavenSession, ToolchainManager toolchainManager) {\n\t\tthis(mavenSession, toolchainManager, null);\n\t}\n\n\tprivate JavaProcessExecutor(MavenSession mavenSession, ToolchainManager toolchainManager,\n                                Consumer<RunProcess> runProcessCustomizer) {\n\t\tthis.mavenSession = mavenSession;\n\t\tthis.toolchainManager = toolchainManager;\n\t\tthis.runProcessCustomizer = runProcessCustomizer;\n\t}\n\n\tJavaProcessExecutor withRunProcessCustomizer(Consumer<RunProcess> customizer) {\n\t\tConsumer<RunProcess> combinedCustomizer = (this.runProcessCustomizer != null)\n\t\t\t\t? this.runProcessCustomizer.andThen(customizer) : customizer;\n\t\treturn new JavaProcessExecutor(this.mavenSession, this.toolchainManager, combinedCustomizer);\n\t}\n\n\tint run(File workingDirectory, List<String> args, Map<String, String> environmentVariables)\n\t\t\tthrows MojoExecutionException {\n\t\tRunProcess runProcess = new RunProcess(workingDirectory, getJavaExecutable());\n\t\tif (this.runProcessCustomizer != null) {\n\t\t\tthis.runProcessCustomizer.accept(runProcess);\n\t\t}\n\t\ttry {\n\t\t\tint exitCode = runProcess.run(true, args, environmentVariables);\n\t\t\tif (!hasTerminatedSuccessfully(exitCode)) {\n\t\t\t\tthrow new MojoExecutionException(\"Process terminated with exit code: \" + exitCode);\n\t\t\t}\n\t\t\treturn exitCode;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new MojoExecutionException(\"Process execution failed\", ex);\n\t\t}\n\t}\n\n\tRunProcess runAsync(File workingDirectory, List<String> args, Map<String, String> environmentVariables)\n\t\t\tthrows MojoExecutionException {\n\t\ttry {\n\t\t\tRunProcess runProcess = new RunProcess(workingDirectory, getJavaExecutable());\n\t\t\trunProcess.run(false, args, environmentVariables);\n\t\t\treturn runProcess;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new MojoExecutionException(\"Process execution failed\", ex);\n\t\t}\n\t}\n\n\tprivate boolean hasTerminatedSuccessfully(int exitCode) {\n\t\treturn (exitCode == 0 || exitCode == EXIT_CODE_SIGINT);\n\t}\n\n\tprivate String getJavaExecutable() {\n\t\tToolchain toolchain = this.toolchainManager.getToolchainFromBuildContext(\"jdk\", this.mavenSession);\n\t\tString javaExecutable = (toolchain != null) ? toolchain.findTool(\"java\") : null;\n\t\treturn (javaExecutable != null) ? javaExecutable : new JavaExecutable().toString();\n\t}\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/MatchingGroupIdFilter.java",
    "content": "/*\n * Copyright 2012-2019 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter;\n\n/**\n * An {@link org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter\n * ArtifactsFilter} that filters by matching groupId.\n *\n * Preferred over the\n * {@link org.apache.maven.shared.artifact.filter.collection.GroupIdFilter} due to that\n * classes use of {@link String#startsWith} to match on prefix.\n */\npublic class MatchingGroupIdFilter extends AbstractArtifactFeatureFilter {\n\n\t/**\n\t * Create a new instance with the CSV groupId values that should be excluded.\n\t * @param exclude the group values to exclude\n\t */\n\tpublic MatchingGroupIdFilter(String exclude) {\n\t\tsuper(\"\", exclude);\n\t}\n\n\t@Override\n\tprotected String getArtifactFeature(Artifact artifact) {\n\t\treturn artifact.getGroupId();\n\t}\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunArguments.java",
    "content": "/*\n * Copyright 2012-2019 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport org.codehaus.plexus.util.cli.CommandLineUtils;\n\nimport java.util.Arrays;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.Objects;\n\n/**\n * Parse and expose arguments specified in a single string.\n */\nclass RunArguments {\n\n\tprivate static final String[] NO_ARGS = {};\n\n\tprivate final Deque<String> args = new LinkedList<>();\n\n\tRunArguments(String arguments) {\n\t\tthis(parseArgs(arguments));\n\t}\n\n\tRunArguments(String[] args) {\n\t\tif (args != null) {\n\t\t\tArrays.stream(args).filter(Objects::nonNull).forEach(this.args::add);\n\t\t}\n\t}\n\n\tDeque<String> getArgs() {\n\t\treturn this.args;\n\t}\n\n\tString[] asArray() {\n\t\treturn this.args.toArray(new String[0]);\n\t}\n\n\tprivate static String[] parseArgs(String arguments) {\n\t\tif (arguments == null || arguments.trim().isEmpty()) {\n\t\t\treturn NO_ARGS;\n\t\t}\n\t\ttry {\n\t\t\targuments = arguments.replace('\\n', ' ').replace('\\t', ' ');\n\t\t\treturn CommandLineUtils.translateCommandline(arguments);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalArgumentException(\"Failed to parse arguments [\" + arguments + \"]\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunProcess.java",
    "content": "/*\n * Copyright 2012-2022 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.maven.plugin.aot;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\n/**\n * Utility used to run a process.\n */\npublic class RunProcess {\n\n\tprivate static final long JUST_ENDED_LIMIT = 500;\n\n\tprivate final File workingDirectory;\n\n\tprivate final String[] command;\n\n\tprivate volatile Process process;\n\n\tprivate volatile long endTime;\n\n\t/**\n\t * Creates new {@link RunProcess} instance for the specified command.\n\t * @param command the program to execute and its arguments\n\t */\n\tpublic RunProcess(String... command) {\n\t\tthis(null, command);\n\t}\n\n\t/**\n\t * Creates new {@link RunProcess} instance for the specified working directory and\n\t * command.\n\t * @param workingDirectory the working directory of the child process or {@code null}\n\t * to run in the working directory of the current Java process\n\t * @param command the program to execute and its arguments\n\t */\n\tpublic RunProcess(File workingDirectory, String... command) {\n\t\tthis.workingDirectory = workingDirectory;\n\t\tthis.command = command;\n\t}\n\n\tpublic int run(boolean waitForProcess, String... args) throws IOException {\n\t\treturn run(waitForProcess, Arrays.asList(args), Collections.emptyMap());\n\t}\n\n\tpublic int run(boolean waitForProcess, Collection<String> args, Map<String, String> environmentVariables)\n\t\t\tthrows IOException {\n\t\tProcessBuilder builder = new ProcessBuilder(this.command);\n\t\tbuilder.directory(this.workingDirectory);\n\t\tbuilder.command().addAll(args);\n\t\tbuilder.environment().putAll(environmentVariables);\n\t\tbuilder.redirectErrorStream(true);\n\t\tbuilder.inheritIO();\n\t\ttry {\n\t\t\tProcess process = builder.start();\n\t\t\tthis.process = process;\n\t\t\tif (waitForProcess) {\n\t\t\t\ttry {\n\t\t\t\t\treturn process.waitFor();\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn 5;\n\t\t}\n\t\tfinally {\n\t\t\tif (waitForProcess) {\n\t\t\t\tthis.endTime = System.currentTimeMillis();\n\t\t\t\tthis.process = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Return the running process.\n\t * @return the process or {@code null}\n\t */\n\tpublic Process getRunningProcess() {\n\t\treturn this.process;\n\t}\n\n\t/**\n\t * Return if the process was stopped.\n\t * @return {@code true} if stopped\n\t */\n\tpublic boolean handleSigInt() {\n\t\tif (allowChildToHandleSigInt()) {\n\t\t\treturn true;\n\t\t}\n\t\treturn doKill();\n\t}\n\n\tprivate boolean allowChildToHandleSigInt() {\n\t\tProcess process = this.process;\n\t\tif (process == null) {\n\t\t\treturn true;\n\t\t}\n\t\tlong end = System.currentTimeMillis() + 5000;\n\t\twhile (System.currentTimeMillis() < end) {\n\t\t\tif (!process.isAlive()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tThread.sleep(500);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Kill this process.\n\t */\n\tpublic void kill() {\n\t\tdoKill();\n\t}\n\n\tprivate boolean doKill() {\n\t\t// destroy the running process\n\t\tProcess process = this.process;\n\t\tif (process != null) {\n\t\t\ttry {\n\t\t\t\tprocess.destroy();\n\t\t\t\tprocess.waitFor();\n\t\t\t\tthis.process = null;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic boolean hasJustEnded() {\n\t\treturn System.currentTimeMillis() < (this.endTime + JUST_ENDED_LIMIT);\n\t}\n\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/DubboProtocCompilerMojo.java",
    "content": "/*\n * Copyright (c) 2019 Maven Protocol Buffers Plugin Authors. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.protoc;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.maven.plugin.protoc.command.DefaultProtocCommandBuilder;\nimport org.apache.dubbo.maven.plugin.protoc.enums.DubboGenerateTypeEnum;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.artifact.factory.ArtifactFactory;\nimport org.apache.maven.artifact.repository.ArtifactRepository;\nimport org.apache.maven.artifact.resolver.ArtifactResolutionException;\nimport org.apache.maven.artifact.resolver.ArtifactResolutionRequest;\nimport org.apache.maven.artifact.resolver.ArtifactResolutionResult;\nimport org.apache.maven.artifact.resolver.ResolutionErrorHandler;\nimport org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;\nimport org.apache.maven.artifact.versioning.VersionRange;\nimport org.apache.maven.execution.MavenSession;\nimport org.apache.maven.plugin.AbstractMojo;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.MojoFailureException;\nimport org.apache.maven.plugins.annotations.Component;\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.plugins.annotations.ResolutionScope;\nimport org.apache.maven.project.MavenProject;\nimport org.apache.maven.project.MavenProjectHelper;\nimport org.apache.maven.repository.RepositorySystem;\nimport org.codehaus.plexus.util.FileUtils;\nimport org.codehaus.plexus.util.Os;\nimport org.codehaus.plexus.util.StringUtils;\nimport org.codehaus.plexus.util.cli.CommandLineException;\nimport org.codehaus.plexus.util.cli.CommandLineUtils;\nimport org.codehaus.plexus.util.cli.Commandline;\nimport org.codehaus.plexus.util.io.RawInputStreamFacade;\nimport org.sonatype.plexus.build.incremental.BuildContext;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.security.MessageDigest;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport static java.lang.String.format;\nimport static java.util.Collections.emptyMap;\nimport static java.util.Collections.singleton;\nimport static org.codehaus.plexus.util.FileUtils.cleanDirectory;\nimport static org.codehaus.plexus.util.FileUtils.copyStreamToFile;\nimport static org.codehaus.plexus.util.FileUtils.getFiles;\n\n@Mojo(\n    name = \"compile\",\n    defaultPhase = LifecyclePhase.GENERATE_SOURCES,\n    requiresDependencyResolution = ResolutionScope.COMPILE,\n    threadSafe = true\n)\npublic class DubboProtocCompilerMojo extends AbstractMojo {\n    @Parameter(property = \"protoSourceDir\", defaultValue = \"${basedir}/src/main/proto\")\n    private File protoSourceDir;\n    @Parameter(property = \"outputDir\", defaultValue = \"${project.build.directory}/generated-sources/protobuf/java\")\n    private File outputDir;\n    @Parameter(required = false, property = \"dubboVersion\")\n    private String dubboVersion;\n    @Parameter(required = true, readonly = true, defaultValue = \"${project.remoteArtifactRepositories}\")\n    private List<ArtifactRepository> remoteRepositories;\n    @Parameter(required = false, property = \"protocExecutable\")\n    private String protocExecutable;\n    @Parameter(required = false, property = \"protocArtifact\")\n    private String protocArtifact;\n    @Parameter(required = false, property = \"protocVersion\")\n    private String protocVersion;\n    @Parameter(required = false, defaultValue = \"${project.build.directory}/protoc-plugins\")\n    private File protocPluginDirectory;\n    @Parameter(required = true, defaultValue = \"${project.build.directory}/protoc-dependencies\")\n    private File temporaryProtoFileDirectory;\n    @Parameter(required = true, property = \"dubboGenerateType\", defaultValue = \"tri\")\n    private String dubboGenerateType;\n    @Parameter(defaultValue = \"${project}\", readonly = true)\n    protected MavenProject project;\n    @Parameter(defaultValue = \"${session}\", readonly = true)\n    protected MavenSession session;\n    @Parameter(required = true, readonly = true, property = \"localRepository\")\n    private ArtifactRepository localRepository;\n    @Component\n    private ArtifactFactory artifactFactory;\n    @Component\n    private RepositorySystem repositorySystem;\n    @Component\n    private ResolutionErrorHandler resolutionErrorHandler;\n    @Component\n    protected MavenProjectHelper projectHelper;\n    @Component\n    protected BuildContext buildContext;\n    final CommandLineUtils.StringStreamConsumer output = new CommandLineUtils.StringStreamConsumer();\n    final CommandLineUtils.StringStreamConsumer error = new CommandLineUtils.StringStreamConsumer();\n    private final DefaultProtocCommandBuilder defaultProtocCommandBuilder = new DefaultProtocCommandBuilder();\n    private final DubboProtocPluginWrapperFactory dubboProtocPluginWrapperFactory = new DubboProtocPluginWrapperFactory();\n\n    public void execute() throws MojoExecutionException, MojoFailureException {\n        Properties versionMatrix = new Properties();\n        ClassLoader loader = Thread.currentThread().getContextClassLoader();\n        try (InputStream stream = loader.getResourceAsStream(\"version-matrix.properties\")) {\n            versionMatrix.load(stream);\n        } catch (IOException e) {\n            getLog().warn(\"Unable to load default version matrix\", e);\n        }\n\n        if (dubboVersion == null) {\n            dubboVersion = versionMatrix.getProperty(\"dubbo.version\");\n        }\n        if (protocVersion == null) {\n            protocVersion = versionMatrix.getProperty(\"protoc.version\");\n        }\n        if (protocArtifact == null) {\n            final String osName = SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.SYSTEM_OS_NAME);\n            final String osArch = SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.OS_ARCH);\n\n            final String detectedName = normalizeOs(osName);\n            final String detectedArch = normalizeArch(osArch);\n\n            protocArtifact = \"com.google.protobuf:protoc:\" + protocVersion + \":exe:\" + detectedName + '-' + detectedArch;\n        }\n\n        if (protocExecutable == null && protocArtifact != null) {\n            final Artifact artifact = createProtocArtifact(protocArtifact);\n            final File file = resolveBinaryArtifact(artifact);\n            protocExecutable = file.getAbsolutePath();\n        }\n        if (protocExecutable == null) {\n            getLog().warn(\"No 'protocExecutable' parameter is configured, using the default: 'protoc'\");\n            protocExecutable = \"protoc\";\n        }\n        getLog().info(\"using protocExecutable: \" + protocExecutable);\n        DubboProtocPlugin dubboProtocPlugin = buildDubboProtocPlugin(dubboVersion, dubboGenerateType, protocPluginDirectory);\n        getLog().info(\"build dubbo protoc plugin:\" + dubboProtocPlugin + \" success\");\n        List<String> commandArgs = defaultProtocCommandBuilder.buildProtocCommandArgs(new ProtocMetaData(protocExecutable, makeAllProtoPaths(), findAllProtoFiles(protoSourceDir), outputDir, dubboProtocPlugin\n        ));\n        if (!outputDir.exists()) {\n            FileUtils.mkdir(outputDir.getAbsolutePath());\n        }\n        try {\n            int exitStatus = executeCommandLine(commandArgs);\n            getLog().info(\"execute commandLine finished with exit code: \" + exitStatus);\n            if (exitStatus != 0) {\n                getLog().error(\"PROTOC FAILED: \" + getError());\n                throw new MojoFailureException(\n                    \"protoc did not exit cleanly. Review output for more information.\");\n            } else if (StringUtils.isNotBlank(getError())) {\n                getLog().warn(\"PROTOC: \" + getError());\n            }\n            linkProtoFilesToMaven();\n        } catch (CommandLineException e) {\n            throw new MojoExecutionException(e);\n        }\n    }\n\n    private static String normalizeOs(String value) {\n        value = normalize(value);\n        if (value.startsWith(\"linux\")) {\n            return \"linux\";\n        }\n        if (value.startsWith(\"mac\") || value.startsWith(\"osx\")) {\n            return \"osx\";\n        }\n        if (value.startsWith(\"windows\")) {\n            return \"windows\";\n        }\n\n        return \"unknown\";\n    }\n\n    private static String normalize(String value) {\n        if (value == null) {\n            return \"\";\n        }\n        return value.toLowerCase(Locale.US).replaceAll(\"[^a-z0-9]+\", \"\");\n    }\n\n    private static String normalizeArch(String value) {\n        value = normalize(value);\n        if (value.matches(\"^(x8664|amd64|ia32e|em64t|x64)$\")) {\n            return \"x86_64\";\n        }\n        if (\"aarch64\".equals(value)) {\n            return \"aarch_64\";\n        }\n        return \"unknown\";\n    }\n\n    public void linkProtoFilesToMaven() {\n        linkProtoSources();\n        linkGeneratedFiles();\n    }\n\n    public void linkProtoSources() {\n        projectHelper.addResource(project, protoSourceDir.getAbsolutePath(),\n            Collections.singletonList(\"**/*.proto*\"), Collections.singletonList(\"\"));\n    }\n\n    public void linkGeneratedFiles() {\n        project.addCompileSourceRoot(outputDir.getAbsolutePath());\n        buildContext.refresh(outputDir);\n    }\n\n    public List<File> findAllProtoFiles(final File protoSourceDir) {\n        if (protoSourceDir == null) {\n            throw new RuntimeException(\"'protoSourceDir' is null\");\n        }\n        if (!protoSourceDir.isDirectory()) {\n            throw new RuntimeException(format(\"%s is not a directory\", protoSourceDir));\n        }\n        final List<File> protoFilesInDirectory;\n        try {\n            protoFilesInDirectory = getFiles(protoSourceDir, \"**/*.proto*\", \"\");\n        } catch (IOException e) {\n            throw new RuntimeException(\"Unable to retrieve the list of files: \" + e.getMessage(), e);\n        }\n        getLog().info(\"protoFilesInDirectory: \" + protoFilesInDirectory);\n        return protoFilesInDirectory;\n    }\n\n    public int executeCommandLine(List<String> commandArgs) throws CommandLineException {\n        final Commandline cl = new Commandline();\n        cl.setExecutable(protocExecutable);\n        cl.addArguments(commandArgs.toArray(new String[]{}));\n        int attemptsLeft = 3;\n        while (true) {\n            try {\n                getLog().info(\"commandLine:\" + cl.toString());\n                return CommandLineUtils.executeCommandLine(cl, null, output, error);\n            } catch (CommandLineException e) {\n                if (--attemptsLeft == 0 || e.getCause() == null) {\n                    throw e;\n                }\n                getLog().warn(\"[PROTOC] Unable to invoke protoc, will retry \" + attemptsLeft + \" time(s)\", e);\n                try {\n                    Thread.sleep(1000L);\n                } catch (InterruptedException ex) {\n                    Thread.currentThread().interrupt();\n                    throw new RuntimeException(ex);\n                }\n            }\n        }\n    }\n\n    private DubboProtocPlugin buildDubboProtocPlugin(String dubboVersion, String dubboGenerateType, File protocPluginDirectory) {\n        DubboProtocPlugin dubboProtocPlugin = new DubboProtocPlugin();\n        DubboGenerateTypeEnum dubboGenerateTypeEnum = DubboGenerateTypeEnum.getByType(dubboGenerateType);\n        if (dubboGenerateTypeEnum == null) {\n            throw new RuntimeException(\" can not find the dubboGenerateType: \" + dubboGenerateType + \",please check it !\");\n        }\n        dubboProtocPlugin.setId(dubboGenerateType);\n        dubboProtocPlugin.setMainClass(dubboGenerateTypeEnum.getMainClass());\n        dubboProtocPlugin.setDubboVersion(dubboVersion);\n        dubboProtocPlugin.setPluginDirectory(protocPluginDirectory);\n        dubboProtocPlugin.setJavaHome(SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_HOME));\n        DubboProtocPluginWrapper protocPluginWrapper = dubboProtocPluginWrapperFactory.findByOs();\n        dubboProtocPlugin.setResolvedJars(resolvePluginDependencies());\n        File protocPlugin = protocPluginWrapper.createProtocPlugin(dubboProtocPlugin, getLog());\n        boolean debugEnabled = getLog().isDebugEnabled();\n        if (debugEnabled) {\n            getLog().debug(\"protocPlugin: \" + protocPlugin.getAbsolutePath());\n        }\n        dubboProtocPlugin.setProtocPlugin(protocPlugin);\n        return dubboProtocPlugin;\n    }\n\n    private List<File> resolvePluginDependencies() {\n        List<File> resolvedJars = new ArrayList<>();\n        final VersionRange versionSpec;\n        try {\n            versionSpec = VersionRange.createFromVersionSpec(dubboVersion);\n        } catch (InvalidVersionSpecificationException e) {\n            throw new RuntimeException(\"Invalid plugin version specification\", e);\n        }\n        final Artifact protocPluginArtifact =\n            artifactFactory.createDependencyArtifact(\n                \"org.apache.dubbo\",\n                \"dubbo-compiler\",\n                versionSpec,\n                \"jar\",\n                \"\",\n                Artifact.SCOPE_RUNTIME);\n        final ArtifactResolutionRequest request = new ArtifactResolutionRequest()\n            .setArtifact(project.getArtifact())\n            .setResolveRoot(false)\n            .setArtifactDependencies(Collections.singleton(protocPluginArtifact))\n            .setManagedVersionMap(emptyMap())\n            .setLocalRepository(localRepository)\n            .setRemoteRepositories(remoteRepositories)\n            .setOffline(session.isOffline())\n            .setForceUpdate(session.getRequest().isUpdateSnapshots())\n            .setServers(session.getRequest().getServers())\n            .setMirrors(session.getRequest().getMirrors())\n            .setProxies(session.getRequest().getProxies());\n\n        final ArtifactResolutionResult result = repositorySystem.resolve(request);\n\n        try {\n            resolutionErrorHandler.throwErrors(request, result);\n        } catch (ArtifactResolutionException e) {\n            throw new RuntimeException(\"Unable to resolve plugin artifact: \" + e.getMessage(), e);\n        }\n\n        final Set<Artifact> artifacts = result.getArtifacts();\n\n        if (artifacts == null || artifacts.isEmpty()) {\n            throw new RuntimeException(\"Unable to resolve plugin artifact\");\n        }\n\n        for (final Artifact artifact : artifacts) {\n            resolvedJars.add(artifact.getFile());\n        }\n\n        if (getLog().isDebugEnabled()) {\n            getLog().debug(\"Resolved jars: \" + resolvedJars);\n        }\n        return resolvedJars;\n    }\n\n    protected Artifact createProtocArtifact(final String artifactSpec) {\n        final String[] parts = artifactSpec.split(\":\");\n        if (parts.length < 3 || parts.length > 5) {\n            throw new RuntimeException(\n                \"Invalid artifact specification format\"\n                    + \", expected: groupId:artifactId:version[:type[:classifier]]\"\n                    + \", actual: \" + artifactSpec);\n        }\n        final String type = parts.length >= 4 ? parts[3] : \"exe\";\n        final String classifier = parts.length == 5 ? parts[4] : null;\n        // parts: [com.google.protobuf, protoc, 3.6.0, exe, osx-x86_64]\n        getLog().info(\"parts: \" + Arrays.toString(parts));\n        return createDependencyArtifact(parts[0], parts[1], parts[2], type, classifier);\n    }\n\n    protected Artifact createDependencyArtifact(\n        final String groupId,\n        final String artifactId,\n        final String version,\n        final String type,\n        final String classifier\n    ) {\n        final VersionRange versionSpec;\n        try {\n            versionSpec = VersionRange.createFromVersionSpec(version);\n        } catch (final InvalidVersionSpecificationException e) {\n            throw new RuntimeException(\"Invalid version specification\", e);\n        }\n        return artifactFactory.createDependencyArtifact(\n            groupId,\n            artifactId,\n            versionSpec,\n            type,\n            classifier,\n            Artifact.SCOPE_RUNTIME);\n    }\n\n    protected File resolveBinaryArtifact(final Artifact artifact) {\n        final ArtifactResolutionResult result;\n        final ArtifactResolutionRequest request = new ArtifactResolutionRequest()\n            .setArtifact(project.getArtifact())\n            .setResolveRoot(false)\n            .setResolveTransitively(false)\n            .setArtifactDependencies(singleton(artifact))\n            .setManagedVersionMap(emptyMap())\n            .setLocalRepository(localRepository)\n            .setRemoteRepositories(remoteRepositories)\n            .setOffline(session.isOffline())\n            .setForceUpdate(session.getRequest().isUpdateSnapshots())\n            .setServers(session.getRequest().getServers())\n            .setMirrors(session.getRequest().getMirrors())\n            .setProxies(session.getRequest().getProxies());\n        result = repositorySystem.resolve(request);\n        try {\n            resolutionErrorHandler.throwErrors(request, result);\n        } catch (final ArtifactResolutionException e) {\n            throw new RuntimeException(\"Unable to resolve artifact: \" + e.getMessage(), e);\n        }\n\n        final Set<Artifact> artifacts = result.getArtifacts();\n\n        if (artifacts == null || artifacts.isEmpty()) {\n            throw new RuntimeException(\"Unable to resolve artifact\");\n        }\n\n        final Artifact resolvedBinaryArtifact = artifacts.iterator().next();\n        if (getLog().isDebugEnabled()) {\n            getLog().debug(\"Resolved artifact: \" + resolvedBinaryArtifact);\n        }\n\n        final File sourceFile = resolvedBinaryArtifact.getFile();\n        final String sourceFileName = sourceFile.getName();\n        final String targetFileName;\n        if (Os.isFamily(Os.FAMILY_WINDOWS) && !sourceFileName.endsWith(\".exe\")) {\n            targetFileName = sourceFileName + \".exe\";\n        } else {\n            targetFileName = sourceFileName;\n        }\n        final File targetFile = new File(protocPluginDirectory, targetFileName);\n        if (targetFile.exists()) {\n            getLog().debug(\"Executable file already exists: \" + targetFile.getAbsolutePath());\n            return targetFile;\n        }\n        try {\n            FileUtils.forceMkdir(protocPluginDirectory);\n        } catch (final IOException e) {\n            throw new RuntimeException(\"Unable to create directory \" + protocPluginDirectory, e);\n        }\n        try {\n            FileUtils.copyFile(sourceFile, targetFile);\n        } catch (final IOException e) {\n            throw new RuntimeException(\"Unable to copy the file to \" + protocPluginDirectory, e);\n        }\n        if (!Os.isFamily(Os.FAMILY_WINDOWS)) {\n            boolean b = targetFile.setExecutable(true);\n            if (!b) {\n                throw new RuntimeException(\"Unable to make executable: \" + targetFile.getAbsolutePath());\n            }\n        }\n\n        if (getLog().isDebugEnabled()) {\n            getLog().debug(\"Executable file: \" + targetFile.getAbsolutePath());\n        }\n        return targetFile;\n    }\n\n    protected Set<File> makeAllProtoPaths() {\n        File temp = temporaryProtoFileDirectory;\n        if (temp.exists()) {\n            try {\n                cleanDirectory(temp);\n            } catch (IOException e) {\n                throw new RuntimeException(\"Unable to clean up temporary proto file directory\", e);\n            }\n        }\n        Set<File> protoDirectories = new LinkedHashSet<>();\n        if (protoSourceDir.exists()) {\n            protoDirectories.add(protoSourceDir);\n        }\n        //noinspection deprecation\n        for (Artifact artifact : project.getCompileArtifacts()) {\n            File file = artifact.getFile();\n            if (file.isFile() && file.canRead() && !file.getName().endsWith(\".xml\")) {\n                try (JarFile jar = new JarFile(file)) {\n                    Enumeration<JarEntry> jarEntries = jar.entries();\n                    while (jarEntries.hasMoreElements()) {\n                        JarEntry jarEntry = jarEntries.nextElement();\n                        String jarEntryName = jarEntry.getName();\n                        if (jarEntryName.endsWith(\".proto\")) {\n                            File targetDirectory;\n                            try {\n                                targetDirectory = new File(temp, hash(jar.getName()));\n                                String canonicalTargetDirectoryPath = targetDirectory.getCanonicalPath();\n                                File target = new File(targetDirectory, jarEntryName);\n                                String canonicalTargetPath = target.getCanonicalPath();\n                                if (!canonicalTargetPath.startsWith(canonicalTargetDirectoryPath + File.separator)) {\n                                    throw new RuntimeException(\n                                            \"ZIP SLIP: Entry \" + jarEntry.getName() + \" in \" + jar.getName()\n                                                    + \" is outside of the target dir\");\n                                }\n                                FileUtils.mkdir(target.getParentFile().getAbsolutePath());\n                                copyStreamToFile(new RawInputStreamFacade(jar.getInputStream(jarEntry)), target);\n                            } catch (IOException e) {\n                                throw new RuntimeException(\"Unable to unpack proto files\", e);\n                            }\n                            protoDirectories.add(targetDirectory);\n                        }\n                    }\n                } catch (IOException e) {\n                    throw new RuntimeException(\"Not a readable JAR artifact: \" + file.getAbsolutePath(), e);\n                }\n            } else if (file.isDirectory()) {\n                List<File> protoFiles;\n                try {\n                    protoFiles = getFiles(file, \"**/*.proto\", null);\n                } catch (IOException e) {\n                    throw new RuntimeException(\"Unable to scan for proto files in: \" + file.getAbsolutePath(), e);\n                }\n                if (!protoFiles.isEmpty()) {\n                    protoDirectories.add(file);\n                }\n            }\n        }\n        return protoDirectories;\n    }\n\n    private static String hash(String input) {\n        try {\n            byte[] bytes = MessageDigest.getInstance(\"MD5\").digest(input.getBytes(StandardCharsets.UTF_8));\n            StringBuilder sb = new StringBuilder(32);\n            for (byte b : bytes) {\n                sb.append(String.format(\"%02x\", b));\n            }\n            return sb.toString();\n        } catch (Exception e) {\n            throw new RuntimeException(\"Unable to create MD5 digest\", e);\n        }\n    }\n\n    public String getError() {\n        return fixUnicodeOutput(error.getOutput());\n    }\n\n    public String getOutput() {\n        return fixUnicodeOutput(output.getOutput());\n    }\n\n    private static String fixUnicodeOutput(final String message) {\n        // TODO default charset is not UTF-8 ?\n        return new String(message.getBytes(), StandardCharsets.UTF_8);\n    }\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/DubboProtocPlugin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.protoc;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class DubboProtocPlugin {\n\n    private String id;\n    private String mainClass;\n    private String dubboVersion;\n    private String javaHome;\n    private File pluginDirectory;\n    private List<File> resolvedJars = new ArrayList<>();\n    private List<String> args = new ArrayList<>();\n    private List<String> jvmArgs = new ArrayList<>();\n    private File protocPlugin = null;\n\n    public DubboProtocPlugin() {}\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    public String getMainClass() {\n        return mainClass;\n    }\n\n    public void setMainClass(String mainClass) {\n        this.mainClass = mainClass;\n    }\n\n    public String getDubboVersion() {\n        return dubboVersion;\n    }\n\n    public void setDubboVersion(String dubboVersion) {\n        this.dubboVersion = dubboVersion;\n    }\n\n    public String getJavaHome() {\n        return javaHome;\n    }\n\n    public void setJavaHome(String javaHome) {\n        this.javaHome = javaHome;\n    }\n\n    public File getPluginDirectory() {\n        return pluginDirectory;\n    }\n\n    public void setPluginDirectory(File pluginDirectory) {\n        this.pluginDirectory = pluginDirectory;\n    }\n\n    public List<File> getResolvedJars() {\n        return resolvedJars;\n    }\n\n    public void setResolvedJars(List<File> resolvedJars) {\n        this.resolvedJars = resolvedJars;\n    }\n\n    public void addResolvedJar(File jar) {\n        resolvedJars.add(jar);\n    }\n\n    public List<String> getArgs() {\n        return args;\n    }\n\n    public void setArgs(List<String> args) {\n        this.args = args;\n    }\n\n    public void addArg(String arg) {\n        args.add(arg);\n    }\n\n    public List<String> getJvmArgs() {\n        return jvmArgs;\n    }\n\n    public void setJvmArgs(List<String> jvmArgs) {\n        this.jvmArgs = jvmArgs;\n    }\n\n    public void addJvmArg(String jvmArg) {\n        jvmArgs.add(jvmArg);\n    }\n\n    public String getPluginName() {\n        return \"protoc-gen-\" + id;\n    }\n\n    public File getProtocPlugin() {\n        return protocPlugin;\n    }\n\n    public void setProtocPlugin(File protocPlugin) {\n        this.protocPlugin = protocPlugin;\n    }\n\n    @Override\n    public String toString() {\n        return \"DubboProtocPlugin{\" + \"id='\"\n                + id + '\\'' + \", mainClass='\"\n                + mainClass + '\\'' + \", dubboVersion='\"\n                + dubboVersion + '\\'' + \", javaHome='\"\n                + javaHome + '\\'' + \", pluginDirectory=\"\n                + pluginDirectory + \", resolvedJars=\"\n                + resolvedJars + \", args=\"\n                + args + \", jvmArgs=\"\n                + jvmArgs + \", protocPlugin=\"\n                + protocPlugin + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/DubboProtocPluginWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.protoc;\n\nimport java.io.File;\n\nimport org.apache.maven.plugin.logging.Log;\n\npublic interface DubboProtocPluginWrapper {\n\n    File createProtocPlugin(DubboProtocPlugin dubboProtocPlugin, Log log);\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/DubboProtocPluginWrapperFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.protoc;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.codehaus.plexus.util.Os;\n\npublic class DubboProtocPluginWrapperFactory {\n\n    private final LinuxDubboProtocPluginWrapper linuxProtocCommandBuilder = new LinuxDubboProtocPluginWrapper();\n    private final WinDubboProtocPluginWrapper winDubboProtocPluginWrapper = new WinDubboProtocPluginWrapper();\n\n    private final Map<String, DubboProtocPluginWrapper> dubboProtocPluginWrappers = new HashMap<>();\n\n    public DubboProtocPluginWrapperFactory() {\n        dubboProtocPluginWrappers.put(\"linux\", linuxProtocCommandBuilder);\n        dubboProtocPluginWrappers.put(\"windows\", winDubboProtocPluginWrapper);\n    }\n\n    public DubboProtocPluginWrapper findByOs() {\n        if (Os.isFamily(Os.FAMILY_WINDOWS)) {\n            return dubboProtocPluginWrappers.get(\"windows\");\n        }\n        return dubboProtocPluginWrappers.get(\"linux\");\n    }\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/LinuxDubboProtocPluginWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.protoc;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.List;\n\nimport org.apache.maven.plugin.logging.Log;\n\npublic class LinuxDubboProtocPluginWrapper implements DubboProtocPluginWrapper {\n\n    @Override\n    public File createProtocPlugin(DubboProtocPlugin dubboProtocPlugin, Log log) {\n        List<File> resolvedJars = dubboProtocPlugin.getResolvedJars();\n        createPluginDirectory(dubboProtocPlugin.getPluginDirectory());\n        File pluginExecutableFile = new File(dubboProtocPlugin.getPluginDirectory(), dubboProtocPlugin.getPluginName());\n        final File javaLocation = new File(dubboProtocPlugin.getJavaHome(), \"bin/java\");\n\n        if (log.isDebugEnabled()) {\n            log.debug(\"javaLocation=\" + javaLocation.getAbsolutePath());\n        }\n        try (final PrintWriter out = new PrintWriter(new FileWriter(pluginExecutableFile))) {\n            out.println(\"#!/bin/sh\");\n            out.println();\n            out.print(\"CP=\");\n            for (int i = 0; i < resolvedJars.size(); i++) {\n                if (i > 0) {\n                    out.print(\":\");\n                }\n                out.print(\"\\\"\" + resolvedJars.get(i).getAbsolutePath() + \"\\\"\");\n            }\n            out.println();\n            out.print(\"ARGS=\\\"\");\n            for (final String arg : dubboProtocPlugin.getArgs()) {\n                out.print(arg + \" \");\n            }\n            out.println(\"\\\"\");\n            out.print(\"JVMARGS=\\\"\");\n            for (final String jvmArg : dubboProtocPlugin.getJvmArgs()) {\n                out.print(jvmArg + \" \");\n            }\n            out.println(\"\\\"\");\n            out.println();\n            out.println(\"\\\"\" + javaLocation.getAbsolutePath() + \"\\\" $JVMARGS -cp $CP \"\n                    + dubboProtocPlugin.getMainClass() + \" $ARGS\");\n            out.println();\n            boolean b = pluginExecutableFile.setExecutable(true);\n            if (!b) {\n                throw new RuntimeException(\"Could not make plugin executable: \" + pluginExecutableFile);\n            }\n            return pluginExecutableFile;\n        } catch (IOException e) {\n            throw new RuntimeException(\"Could not write plugin script file: \" + pluginExecutableFile, e);\n        }\n    }\n\n    private void createPluginDirectory(File pluginDirectory) {\n        pluginDirectory.mkdirs();\n        if (!pluginDirectory.isDirectory()) {\n            throw new RuntimeException(\n                    \"Could not create protoc plugin directory: \" + pluginDirectory.getAbsolutePath());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/ProtocMetaData.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.protoc;\n\nimport java.io.File;\nimport java.util.Collection;\nimport java.util.List;\n\npublic class ProtocMetaData {\n\n    private String protocExecutable;\n    private Collection<File> protoSourceDirs;\n    private List<File> protoFiles;\n    private File outputDir;\n    private DubboProtocPlugin dubboProtocPlugin;\n\n    public ProtocMetaData() {}\n\n    public ProtocMetaData(\n            String protocExecutable,\n            Collection<File> protoSourceDirs,\n            List<File> protoFiles,\n            File outputDir,\n            DubboProtocPlugin dubboProtocPlugin) {\n        this.protocExecutable = protocExecutable;\n        this.protoSourceDirs = protoSourceDirs;\n        this.protoFiles = protoFiles;\n        this.outputDir = outputDir;\n        this.dubboProtocPlugin = dubboProtocPlugin;\n    }\n\n    public String getProtocExecutable() {\n        return protocExecutable;\n    }\n\n    public void setProtocExecutable(String protocExecutable) {\n        this.protocExecutable = protocExecutable;\n    }\n\n    public Collection<File> getProtoSourceDirs() {\n        return protoSourceDirs;\n    }\n\n    public void setProtoSourceDirs(Collection<File> protoSourceDirs) {\n        this.protoSourceDirs = protoSourceDirs;\n    }\n\n    public List<File> getProtoFiles() {\n        return protoFiles;\n    }\n\n    public void setProtoFiles(List<File> protoFiles) {\n        this.protoFiles = protoFiles;\n    }\n\n    public File getOutputDir() {\n        return outputDir;\n    }\n\n    public void setOutputDir(File outputDir) {\n        this.outputDir = outputDir;\n    }\n\n    public DubboProtocPlugin getDubboProtocPlugin() {\n        return dubboProtocPlugin;\n    }\n\n    public void setDubboProtocPlugin(DubboProtocPlugin dubboProtocPlugin) {\n        this.dubboProtocPlugin = dubboProtocPlugin;\n    }\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/WinDubboProtocPluginWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.protoc;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport org.apache.maven.plugin.logging.Log;\n\npublic class WinDubboProtocPluginWrapper implements DubboProtocPluginWrapper {\n\n    @Override\n    public File createProtocPlugin(DubboProtocPlugin dubboProtocPlugin, Log log) {\n        File pluginDirectory = dubboProtocPlugin.getPluginDirectory();\n        pluginDirectory.mkdirs();\n        if (!pluginDirectory.isDirectory()) {\n            throw new RuntimeException(\n                    \"Unable to create protoc plugin directory: \" + pluginDirectory.getAbsolutePath());\n        }\n        File batFile =\n                new File(dubboProtocPlugin.getPluginDirectory(), \"protoc-gen-\" + dubboProtocPlugin.getId() + \".bat\");\n\n        try (PrintWriter out = new PrintWriter(new FileWriter(batFile))) {\n            out.println(\"@echo off\");\n            out.println(\"set JAVA_HOME=\" + dubboProtocPlugin.getJavaHome());\n            StringBuilder classpath = new StringBuilder(256);\n            classpath.append(\"set CLASSPATH=\");\n            for (File jar : dubboProtocPlugin.getResolvedJars()) {\n                classpath.append(jar.getAbsolutePath()).append(\";\");\n            }\n            out.println(classpath);\n            out.println(\"\\\"%JAVA_HOME%\\\\bin\\\\java\\\" ^\");\n            for (String jvmArg : dubboProtocPlugin.getJvmArgs()) {\n                out.println(\"  \" + jvmArg + \" ^\");\n            }\n            out.println(\"  \" + dubboProtocPlugin.getMainClass() + \" ^\");\n            for (String arg : dubboProtocPlugin.getArgs()) {\n                out.println(\"  \" + arg + \" ^\");\n            }\n            out.println(\"  %*\");\n        } catch (IOException e) {\n            throw new RuntimeException(\"Unable to write BAT file: \" + batFile.getAbsolutePath(), e);\n        }\n\n        return batFile;\n    }\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/command/DefaultProtocCommandBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.protoc.command;\n\nimport org.apache.dubbo.maven.plugin.protoc.DubboProtocPlugin;\nimport org.apache.dubbo.maven.plugin.protoc.ProtocMetaData;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class DefaultProtocCommandBuilder implements ProtocCommandArgsBuilder {\n\n    @Override\n    public List<String> buildProtocCommandArgs(ProtocMetaData protocMetaData) {\n        List<String> command = new ArrayList<>();\n        for (final File protoSourceDir : protocMetaData.getProtoSourceDirs()) {\n            command.add(\"--proto_path=\" + protoSourceDir);\n        }\n        String outputOption = \"--java_out=\";\n        outputOption += protocMetaData.getOutputDir();\n        command.add(outputOption);\n        DubboProtocPlugin dubboProtocPlugin = protocMetaData.getDubboProtocPlugin();\n        command.add(\"--plugin=protoc-gen-\" + dubboProtocPlugin.getId() + '=' + dubboProtocPlugin.getProtocPlugin());\n        command.add(\"--\" + dubboProtocPlugin.getId() + \"_out=\" + protocMetaData.getOutputDir());\n        for (final File protoFile : protocMetaData.getProtoFiles()) {\n            command.add(protoFile.toString());\n        }\n        return command;\n    }\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/command/ProtocCommandArgsBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.protoc.command;\n\nimport org.apache.dubbo.maven.plugin.protoc.ProtocMetaData;\n\nimport java.util.List;\n\npublic interface ProtocCommandArgsBuilder {\n\n    List<String> buildProtocCommandArgs(ProtocMetaData protocMetaData) throws RuntimeException;\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/protoc/enums/DubboGenerateTypeEnum.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.maven.plugin.protoc.enums;\n\npublic enum DubboGenerateTypeEnum {\n    Tri(\"tri\", \"org.apache.dubbo.gen.tri.Dubbo3TripleGenerator\"),\n    Tri_reactor(\"tri_reactor\", \"org.apache.dubbo.gen.tri.reactive.ReactorDubbo3TripleGenerator\"),\n    ;\n    private String id;\n    private String mainClass;\n\n    DubboGenerateTypeEnum(String id, String mainClass) {\n        this.id = id;\n        this.mainClass = mainClass;\n    }\n\n    public static DubboGenerateTypeEnum getByType(String dubboGenerateType) {\n        DubboGenerateTypeEnum[] values = DubboGenerateTypeEnum.values();\n        for (DubboGenerateTypeEnum value : values) {\n            if (value.getId().equals(dubboGenerateType)) {\n                return value;\n            }\n        }\n        return null;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    public String getMainClass() {\n        return mainClass;\n    }\n\n    public void setMainClass(String mainClass) {\n        this.mainClass = mainClass;\n    }\n}\n"
  },
  {
    "path": "dubbo-maven-plugin/src/main/resources/version-matrix.properties",
    "content": "dubbo.version=${dubbo.version}\nprotoc.version=${protobuf-java.version}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metadata</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-metadata-api</artifactId>\n  <packaging>jar</packaging>\n\n  <name>dubbo-metadata-api</name>\n  <description>The metadata module of Dubbo project</description>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.parent.version}</version>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-cluster</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>compile</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>compile</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-metadata</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>compile</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-native</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <!--      <plugin>\n              <groupId>org.apache.dubbo</groupId>\n              <artifactId>dubbo-maven-plugin</artifactId>\n            </plugin>-->\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/AbstractCacheManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.cache.FileCacheStore;\nimport org.apache.dubbo.common.cache.FileCacheStoreFactory;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.LRUCache;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVER_SHUTDOWN_TIMEOUT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_FAILED_LOAD_MAPPING_CACHE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\npublic abstract class AbstractCacheManager<V> implements Disposable {\n    protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private ScheduledExecutorService executorService;\n\n    protected FileCacheStore cacheStore;\n    protected LRUCache<String, V> cache;\n\n    protected void init(\n            boolean enableFileCache,\n            String filePath,\n            String fileName,\n            int entrySize,\n            long fileSize,\n            int interval,\n            ScheduledExecutorService executorService) {\n        this.cache = new LRUCache<>(entrySize);\n\n        try {\n            cacheStore = FileCacheStoreFactory.getInstance(filePath, fileName, enableFileCache);\n            Map<String, String> properties = cacheStore.loadCache(entrySize);\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Successfully loaded \" + getName() + \" cache from file \" + fileName + \", entries \"\n                        + properties.size());\n            }\n            for (Map.Entry<String, String> entry : properties.entrySet()) {\n                String key = entry.getKey();\n                String value = entry.getValue();\n                V v = toValueType(value);\n                put(key, v);\n            }\n            // executorService can be empty if FileCacheStore fails\n            if (executorService == null) {\n                this.executorService = Executors.newSingleThreadScheduledExecutor(\n                        new NamedThreadFactory(\"Dubbo-cache-refreshing-scheduler\", true));\n            } else {\n                this.executorService = executorService;\n            }\n\n            this.executorService.scheduleWithFixedDelay(\n                    new CacheRefreshTask<>(this.cacheStore, this.cache, this, fileSize),\n                    10,\n                    interval,\n                    TimeUnit.MINUTES);\n        } catch (Exception e) {\n            logger.error(COMMON_FAILED_LOAD_MAPPING_CACHE, \"\", \"\", \"Load mapping from local cache file error \", e);\n        }\n    }\n\n    protected abstract V toValueType(String value);\n\n    protected abstract String getName();\n\n    protected boolean validate(String key, V value) {\n        return value != null;\n    }\n\n    public V get(String key) {\n        return cache.get(key);\n    }\n\n    public void put(String key, V apps) {\n        if (validate(key, apps)) {\n            cache.put(key, apps);\n        }\n    }\n\n    public V remove(String key) {\n        return cache.remove(key);\n    }\n\n    public Map<String, V> getAll() {\n        if (cache.isEmpty()) {\n            return Collections.emptyMap();\n        }\n\n        Map<String, V> copyMap = new HashMap<>();\n        cache.lock();\n        try {\n            for (Map.Entry<String, V> entry : cache.entrySet()) {\n                copyMap.put(entry.getKey(), entry.getValue());\n            }\n        } finally {\n            cache.releaseLock();\n        }\n        return Collections.unmodifiableMap(copyMap);\n    }\n\n    public void update(Map<String, V> newCache) {\n        for (Map.Entry<String, V> entry : newCache.entrySet()) {\n            put(entry.getKey(), entry.getValue());\n        }\n    }\n\n    public void destroy() {\n        if (executorService != null) {\n            executorService.shutdownNow();\n            try {\n                if (!executorService.awaitTermination(\n                        ConfigurationUtils.reCalShutdownTime(DEFAULT_SERVER_SHUTDOWN_TIMEOUT), TimeUnit.MILLISECONDS)) {\n                    logger.warn(\n                            COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"Wait global executor service terminated timeout.\");\n                }\n            } catch (InterruptedException e) {\n                logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"destroy resources failed: \" + e.getMessage(), e);\n            }\n        }\n        if (cacheStore != null) {\n            cacheStore.destroy();\n        }\n        if (cache != null) {\n            cache.clear();\n        }\n    }\n\n    public static class CacheRefreshTask<V> implements Runnable {\n        private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n        private static final String DEFAULT_COMMENT = \"Dubbo cache\";\n        private final FileCacheStore cacheStore;\n        private final LRUCache<String, V> cache;\n        private final AbstractCacheManager<V> cacheManager;\n        private final long maxFileSize;\n\n        public CacheRefreshTask(\n                FileCacheStore cacheStore,\n                LRUCache<String, V> cache,\n                AbstractCacheManager<V> cacheManager,\n                long maxFileSize) {\n            this.cacheStore = cacheStore;\n            this.cache = cache;\n            this.cacheManager = cacheManager;\n            this.maxFileSize = maxFileSize;\n        }\n\n        @Override\n        public void run() {\n            Map<String, String> properties = new HashMap<>();\n\n            cache.lock();\n            try {\n                for (Map.Entry<String, V> entry : cache.entrySet()) {\n                    properties.put(entry.getKey(), JsonUtils.toJson(entry.getValue()));\n                }\n            } finally {\n                cache.releaseLock();\n            }\n\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Dumping \" + cacheManager.getName() + \" caches, latest entries \" + properties.size());\n            }\n            cacheStore.refreshCache(properties, DEFAULT_COMMENT, maxFileSize);\n        }\n    }\n\n    // for test unit\n    public FileCacheStore getCacheStore() {\n        return cacheStore;\n    }\n\n    public LRUCache<String, V> getCache() {\n        return cache;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/AbstractServiceNameMapping.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashSet;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport static java.util.Collections.emptySet;\nimport static java.util.Collections.unmodifiableSet;\nimport static java.util.stream.Collectors.toSet;\nimport static java.util.stream.Stream.of;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_FAILED_LOAD_MAPPING_CACHE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY;\nimport static org.apache.dubbo.common.utils.CollectionUtils.toTreeSet;\nimport static org.apache.dubbo.common.utils.StringUtils.isBlank;\n\npublic abstract class AbstractServiceNameMapping implements ServiceNameMapping {\n    protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n    protected ApplicationModel applicationModel;\n    private final MappingCacheManager mappingCacheManager;\n    private final ConcurrentHashMap<String, Set<MappingListener>> mappingListeners = new ConcurrentHashMap<>();\n    // mapping lock is shared among registries of the same application.\n    private final ConcurrentMap<String, ReentrantLock> mappingLocks = new ConcurrentHashMap<>();\n\n    public AbstractServiceNameMapping(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        boolean enableFileCache = true;\n        Optional<ApplicationConfig> application =\n                applicationModel.getApplicationConfigManager().getApplication();\n        if (application.isPresent()) {\n            enableFileCache = Boolean.TRUE.equals(application.get().getEnableFileCache()) ? true : false;\n        }\n        this.mappingCacheManager = new MappingCacheManager(\n                enableFileCache,\n                applicationModel.tryGetApplicationName(),\n                applicationModel\n                        .getFrameworkModel()\n                        .getBeanFactory()\n                        .getBean(FrameworkExecutorRepository.class)\n                        .getCacheRefreshingScheduledExecutor());\n    }\n\n    // just for test\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    /**\n     * Get the service names from the specified Dubbo service interface, group, version and protocol\n     *\n     * @return\n     */\n    public abstract Set<String> get(URL url);\n\n    /**\n     * Get the service names from the specified Dubbo service interface, group, version and protocol\n     *\n     * @return\n     */\n    public abstract Set<String> getAndListen(URL url, MappingListener mappingListener);\n\n    protected abstract void removeListener(URL url, MappingListener mappingListener);\n\n    @Override\n    public Set<String> getAndListen(URL registryURL, URL subscribedURL, MappingListener listener) {\n        String key = ServiceNameMapping.buildMappingKey(subscribedURL);\n        // use previously cached services.\n        Set<String> mappingServices = mappingCacheManager.get(key);\n\n        // Asynchronously register listener in case previous cache does not exist or cache expired.\n        if (CollectionUtils.isEmpty(mappingServices)) {\n            try {\n                logger.info(\"[METADATA_REGISTER] Local cache mapping is empty\");\n                mappingServices = (new AsyncMappingTask(listener, subscribedURL, false)).call();\n            } catch (Exception e) {\n                // ignore\n            }\n            if (CollectionUtils.isEmpty(mappingServices)) {\n                String registryServices = registryURL.getParameter(SUBSCRIBED_SERVICE_NAMES_KEY);\n                if (StringUtils.isNotEmpty(registryServices)) {\n                    logger.info(subscribedURL.getServiceInterface() + \" mapping to \" + registryServices\n                            + \" instructed by registry subscribed-services.\");\n                    mappingServices = parseServices(registryServices);\n                }\n            }\n            if (CollectionUtils.isNotEmpty(mappingServices)) {\n                this.putCachedMapping(ServiceNameMapping.buildMappingKey(subscribedURL), mappingServices);\n            }\n        } else {\n            ExecutorService executorService = applicationModel\n                    .getFrameworkModel()\n                    .getBeanFactory()\n                    .getBean(FrameworkExecutorRepository.class)\n                    .getMappingRefreshingExecutor();\n            executorService.submit(new AsyncMappingTask(listener, subscribedURL, true));\n        }\n\n        return mappingServices;\n    }\n\n    @Override\n    public MappingListener stopListen(URL subscribeURL, MappingListener listener) {\n        synchronized (mappingListeners) {\n            if (listener != null) {\n                String mappingKey = ServiceNameMapping.buildMappingKey(subscribeURL);\n                Set<MappingListener> listeners = mappingListeners.get(mappingKey);\n                // todo, remove listener from remote metadata center\n                if (CollectionUtils.isNotEmpty(listeners)) {\n                    listeners.remove(listener);\n                    listener.stop();\n                    removeListener(subscribeURL, listener);\n                }\n                if (CollectionUtils.isEmpty(listeners)) {\n                    mappingListeners.remove(mappingKey);\n                    removeCachedMapping(mappingKey);\n                    removeMappingLock(mappingKey);\n                }\n            }\n            return listener;\n        }\n    }\n\n    static Set<String> parseServices(String literalServices) {\n        return isBlank(literalServices)\n                ? emptySet()\n                : unmodifiableSet(new TreeSet<>(of(literalServices.split(\",\"))\n                        .map(String::trim)\n                        .filter(StringUtils::isNotEmpty)\n                        .collect(toSet())));\n    }\n\n    @Override\n    public void putCachedMapping(String serviceKey, Set<String> apps) {\n        mappingCacheManager.put(serviceKey, toTreeSet(apps));\n    }\n\n    protected void putCachedMappingIfAbsent(String serviceKey, Set<String> apps) {\n        Lock lock = getMappingLock(serviceKey);\n        try {\n            lock.lock();\n            if (CollectionUtils.isEmpty(mappingCacheManager.get(serviceKey))) {\n                mappingCacheManager.put(serviceKey, toTreeSet(apps));\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public Set<String> getMapping(URL consumerURL) {\n        Set<String> mappingByUrl = ServiceNameMapping.getMappingByUrl(consumerURL);\n        if (mappingByUrl != null) {\n            return mappingByUrl;\n        }\n        return mappingCacheManager.get(ServiceNameMapping.buildMappingKey(consumerURL));\n    }\n\n    @Override\n    public Set<String> getRemoteMapping(URL consumerURL) {\n        return get(consumerURL);\n    }\n\n    @Override\n    public Set<String> removeCachedMapping(String serviceKey) {\n        return mappingCacheManager.remove(serviceKey);\n    }\n\n    public Lock getMappingLock(String key) {\n        return ConcurrentHashMapUtils.computeIfAbsent(mappingLocks, key, _k -> new ReentrantLock());\n    }\n\n    protected void removeMappingLock(String key) {\n        Lock lock = mappingLocks.get(key);\n        if (lock != null) {\n            try {\n                lock.lock();\n                mappingLocks.remove(key);\n            } finally {\n                lock.unlock();\n            }\n        }\n    }\n\n    @Override\n    public void $destroy() {\n        mappingCacheManager.destroy();\n        mappingListeners.clear();\n        mappingLocks.clear();\n    }\n\n    private class AsyncMappingTask implements Callable<Set<String>> {\n        private final MappingListener listener;\n        private final URL subscribedURL;\n        private final boolean notifyAtFirstTime;\n\n        public AsyncMappingTask(MappingListener listener, URL subscribedURL, boolean notifyAtFirstTime) {\n            this.listener = listener;\n            this.subscribedURL = subscribedURL;\n            this.notifyAtFirstTime = notifyAtFirstTime;\n        }\n\n        @Override\n        public Set<String> call() throws Exception {\n            synchronized (mappingListeners) {\n                Set<String> mappedServices = emptySet();\n                try {\n                    String mappingKey = ServiceNameMapping.buildMappingKey(subscribedURL);\n                    if (listener != null) {\n                        mappedServices = toTreeSet(getAndListen(subscribedURL, listener));\n                        Set<MappingListener> listeners = ConcurrentHashMapUtils.computeIfAbsent(\n                                mappingListeners, mappingKey, _k -> new HashSet<>());\n                        listeners.add(listener);\n                        if (CollectionUtils.isNotEmpty(mappedServices)) {\n                            if (notifyAtFirstTime) {\n                                // guarantee at-least-once notification no matter what kind of underlying meta server is\n                                // used.\n                                // listener notification will also cause updating of mapping cache.\n                                listener.onEvent(new MappingChangedEvent(mappingKey, mappedServices));\n                            }\n                        }\n                    } else {\n                        mappedServices = get(subscribedURL);\n                        if (CollectionUtils.isNotEmpty(mappedServices)) {\n                            AbstractServiceNameMapping.this.putCachedMapping(mappingKey, mappedServices);\n                        }\n                    }\n                } catch (Exception e) {\n                    logger.error(\n                            COMMON_FAILED_LOAD_MAPPING_CACHE,\n                            \"\",\n                            \"\",\n                            \"Failed getting mapping info from remote center. \",\n                            e);\n                }\n                return mappedServices;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DefaultMetadataParamsFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.extension.Activate;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.IPV6_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.FilterConstants.VALIDATION_KEY;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;\nimport static org.apache.dubbo.remoting.Constants.BIND_IP_KEY;\nimport static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY;\nimport static org.apache.dubbo.remoting.Constants.HEARTBEAT_TIMEOUT_KEY;\nimport static org.apache.dubbo.rpc.Constants.INTERFACES;\n\n@Activate\npublic class DefaultMetadataParamsFilter implements MetadataParamsFilter {\n    private final String[] excludedServiceParams;\n    private final String[] includedInstanceParams;\n\n    public DefaultMetadataParamsFilter() {\n        this.includedInstanceParams = new String[] {HEARTBEAT_TIMEOUT_KEY, TIMESTAMP_KEY, IPV6_KEY};\n        this.excludedServiceParams = new String[] {\n            MONITOR_KEY,\n            BIND_IP_KEY,\n            BIND_PORT_KEY,\n            QOS_ENABLE,\n            QOS_HOST,\n            QOS_PORT,\n            ACCEPT_FOREIGN_IP,\n            VALIDATION_KEY,\n            INTERFACES,\n            PID_KEY,\n            TIMESTAMP_KEY,\n            HEARTBEAT_TIMEOUT_KEY,\n            IPV6_KEY\n        };\n    }\n\n    @Override\n    public String[] instanceParamsIncluded() {\n        return includedInstanceParams;\n    }\n\n    @Override\n    public String[] serviceParamsExcluded() {\n        return excludedServiceParams;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.PathResolver;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.ServerService;\nimport org.apache.dubbo.rpc.TriRpcStatus;\nimport org.apache.dubbo.rpc.model.MethodDescriptor;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.model.StubMethodDescriptor;\nimport org.apache.dubbo.rpc.model.StubServiceDescriptor;\nimport org.apache.dubbo.rpc.service.Destroyable;\nimport org.apache.dubbo.rpc.stub.StubInvocationUtil;\nimport org.apache.dubbo.rpc.stub.StubInvoker;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\nimport org.apache.dubbo.rpc.stub.StubSuppliers;\nimport org.apache.dubbo.rpc.stub.UnaryStubMethodHandler;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.BiConsumer;\n\nimport com.google.protobuf.Message;\n\npublic final class DubboMetadataServiceV2Triple {\n\n    public static final String SERVICE_NAME = MetadataServiceV2.SERVICE_NAME;\n\n    private static final StubServiceDescriptor serviceDescriptor =\n            new StubServiceDescriptor(SERVICE_NAME, MetadataServiceV2.class);\n\n    static {\n        org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(\n                SERVICE_NAME, MetadataServiceV2OuterClass.getDescriptor());\n        StubSuppliers.addSupplier(SERVICE_NAME, DubboMetadataServiceV2Triple::newStub);\n        StubSuppliers.addSupplier(MetadataServiceV2.JAVA_SERVICE_NAME, DubboMetadataServiceV2Triple::newStub);\n        StubSuppliers.addDescriptor(SERVICE_NAME, serviceDescriptor);\n        StubSuppliers.addDescriptor(MetadataServiceV2.JAVA_SERVICE_NAME, serviceDescriptor);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static MetadataServiceV2 newStub(Invoker<?> invoker) {\n        return new MetadataServiceV2Stub((Invoker<MetadataServiceV2>) invoker);\n    }\n\n    private static final StubMethodDescriptor getMetadataInfoMethod = new StubMethodDescriptor(\n            \"GetMetadataInfo\",\n            MetadataRequest.class,\n            MetadataInfoV2.class,\n            MethodDescriptor.RpcType.UNARY,\n            obj -> ((Message) obj).toByteArray(),\n            obj -> ((Message) obj).toByteArray(),\n            MetadataRequest::parseFrom,\n            MetadataInfoV2::parseFrom);\n\n    private static final StubMethodDescriptor getMetadataInfoAsyncMethod = new StubMethodDescriptor(\n            \"GetMetadataInfo\",\n            MetadataRequest.class,\n            CompletableFuture.class,\n            MethodDescriptor.RpcType.UNARY,\n            obj -> ((Message) obj).toByteArray(),\n            obj -> ((Message) obj).toByteArray(),\n            MetadataRequest::parseFrom,\n            MetadataInfoV2::parseFrom);\n\n    private static final StubMethodDescriptor getMetadataInfoProxyAsyncMethod = new StubMethodDescriptor(\n            \"GetMetadataInfoAsync\",\n            MetadataRequest.class,\n            MetadataInfoV2.class,\n            MethodDescriptor.RpcType.UNARY,\n            obj -> ((Message) obj).toByteArray(),\n            obj -> ((Message) obj).toByteArray(),\n            MetadataRequest::parseFrom,\n            MetadataInfoV2::parseFrom);\n\n    private static final StubMethodDescriptor getOpenAPIInfoMethod = new StubMethodDescriptor(\n            \"GetOpenAPIInfo\",\n            OpenAPIRequest.class,\n            OpenAPIInfo.class,\n            MethodDescriptor.RpcType.UNARY,\n            obj -> ((Message) obj).toByteArray(),\n            obj -> ((Message) obj).toByteArray(),\n            OpenAPIRequest::parseFrom,\n            OpenAPIInfo::parseFrom);\n\n    private static final StubMethodDescriptor getOpenAPIInfoAsyncMethod = new StubMethodDescriptor(\n            \"GetOpenAPIInfo\",\n            OpenAPIRequest.class,\n            CompletableFuture.class,\n            MethodDescriptor.RpcType.UNARY,\n            obj -> ((Message) obj).toByteArray(),\n            obj -> ((Message) obj).toByteArray(),\n            OpenAPIRequest::parseFrom,\n            OpenAPIInfo::parseFrom);\n\n    private static final StubMethodDescriptor getOpenAPIInfoProxyAsyncMethod = new StubMethodDescriptor(\n            \"GetOpenAPIInfoAsync\",\n            OpenAPIRequest.class,\n            OpenAPIInfo.class,\n            MethodDescriptor.RpcType.UNARY,\n            obj -> ((Message) obj).toByteArray(),\n            obj -> ((Message) obj).toByteArray(),\n            OpenAPIRequest::parseFrom,\n            OpenAPIInfo::parseFrom);\n\n    static {\n        serviceDescriptor.addMethod(getMetadataInfoMethod);\n        serviceDescriptor.addMethod(getMetadataInfoProxyAsyncMethod);\n        serviceDescriptor.addMethod(getOpenAPIInfoMethod);\n        serviceDescriptor.addMethod(getOpenAPIInfoProxyAsyncMethod);\n    }\n\n    public static class MetadataServiceV2Stub implements MetadataServiceV2, Destroyable {\n        private final Invoker<MetadataServiceV2> invoker;\n\n        public MetadataServiceV2Stub(Invoker<MetadataServiceV2> invoker) {\n            this.invoker = invoker;\n        }\n\n        @Override\n        public void $destroy() {\n            invoker.destroy();\n        }\n\n        @Override\n        public MetadataInfoV2 getMetadataInfo(MetadataRequest request) {\n            return StubInvocationUtil.unaryCall(invoker, getMetadataInfoMethod, request);\n        }\n\n        public CompletableFuture<MetadataInfoV2> getMetadataInfoAsync(MetadataRequest request) {\n            return StubInvocationUtil.unaryCall(invoker, getMetadataInfoAsyncMethod, request);\n        }\n\n        public void getMetadataInfo(MetadataRequest request, StreamObserver<MetadataInfoV2> responseObserver) {\n            StubInvocationUtil.unaryCall(invoker, getMetadataInfoMethod, request, responseObserver);\n        }\n\n        @Override\n        public OpenAPIInfo getOpenAPIInfo(OpenAPIRequest request) {\n            return StubInvocationUtil.unaryCall(invoker, getOpenAPIInfoMethod, request);\n        }\n\n        public CompletableFuture<OpenAPIInfo> getOpenAPIInfoAsync(OpenAPIRequest request) {\n            return StubInvocationUtil.unaryCall(invoker, getOpenAPIInfoAsyncMethod, request);\n        }\n\n        public void getOpenAPIInfo(OpenAPIRequest request, StreamObserver<OpenAPIInfo> responseObserver) {\n            StubInvocationUtil.unaryCall(invoker, getOpenAPIInfoMethod, request, responseObserver);\n        }\n    }\n\n    public abstract static class MetadataServiceV2ImplBase\n            implements MetadataServiceV2, ServerService<MetadataServiceV2> {\n        private <T, R> BiConsumer<T, StreamObserver<R>> syncToAsync(java.util.function.Function<T, R> syncFun) {\n            return new BiConsumer<T, StreamObserver<R>>() {\n                @Override\n                public void accept(T t, StreamObserver<R> observer) {\n                    try {\n                        R ret = syncFun.apply(t);\n                        observer.onNext(ret);\n                        observer.onCompleted();\n                    } catch (Throwable e) {\n                        observer.onError(e);\n                    }\n                }\n            };\n        }\n\n        @Override\n        public CompletableFuture<MetadataInfoV2> getMetadataInfoAsync(MetadataRequest request) {\n            return CompletableFuture.completedFuture(getMetadataInfo(request));\n        }\n\n        @Override\n        public CompletableFuture<OpenAPIInfo> getOpenAPIInfoAsync(OpenAPIRequest request) {\n            return CompletableFuture.completedFuture(getOpenAPIInfo(request));\n        }\n\n        // This server stream type unary method is <b>only</b> used for generated stub to support async unary method.\n        // It will not be called if you are NOT using Dubbo3 generated triple stub and <b>DO NOT</b> implement this\n        // method.\n\n        public void getMetadataInfo(MetadataRequest request, StreamObserver<MetadataInfoV2> responseObserver) {\n            getMetadataInfoAsync(request).whenComplete((r, t) -> {\n                if (t != null) {\n                    responseObserver.onError(t);\n                } else {\n                    responseObserver.onNext(r);\n                    responseObserver.onCompleted();\n                }\n            });\n        }\n\n        public void getOpenAPIInfo(OpenAPIRequest request, StreamObserver<OpenAPIInfo> responseObserver) {\n            getOpenAPIInfoAsync(request).whenComplete((r, t) -> {\n                if (t != null) {\n                    responseObserver.onError(t);\n                } else {\n                    responseObserver.onNext(r);\n                    responseObserver.onCompleted();\n                }\n            });\n        }\n\n        @Override\n        public final Invoker<MetadataServiceV2> getInvoker(URL url) {\n            PathResolver pathResolver = url.getOrDefaultFrameworkModel()\n                    .getExtensionLoader(PathResolver.class)\n                    .getDefaultExtension();\n            Map<String, StubMethodHandler<?, ?>> handlers = new HashMap<>();\n            pathResolver.addNativeStub(\"/\" + SERVICE_NAME + \"/GetMetadataInfo\");\n            pathResolver.addNativeStub(\"/\" + SERVICE_NAME + \"/GetMetadataInfoAsync\");\n            // for compatibility\n            pathResolver.addNativeStub(\"/\" + JAVA_SERVICE_NAME + \"/GetMetadataInfo\");\n            pathResolver.addNativeStub(\"/\" + JAVA_SERVICE_NAME + \"/GetMetadataInfoAsync\");\n            pathResolver.addNativeStub(\"/\" + SERVICE_NAME + \"/GetOpenAPIInfo\");\n            pathResolver.addNativeStub(\"/\" + SERVICE_NAME + \"/GetOpenAPIInfoAsync\");\n            // for compatibility\n            pathResolver.addNativeStub(\"/\" + JAVA_SERVICE_NAME + \"/GetOpenAPIInfo\");\n            pathResolver.addNativeStub(\"/\" + JAVA_SERVICE_NAME + \"/GetOpenAPIInfoAsync\");\n            BiConsumer<MetadataRequest, StreamObserver<MetadataInfoV2>> getMetadataInfoFunc = this::getMetadataInfo;\n            handlers.put(getMetadataInfoMethod.getMethodName(), new UnaryStubMethodHandler<>(getMetadataInfoFunc));\n            BiConsumer<MetadataRequest, StreamObserver<MetadataInfoV2>> getMetadataInfoAsyncFunc =\n                    syncToAsync(this::getMetadataInfo);\n            handlers.put(\n                    getMetadataInfoProxyAsyncMethod.getMethodName(),\n                    new UnaryStubMethodHandler<>(getMetadataInfoAsyncFunc));\n            BiConsumer<OpenAPIRequest, StreamObserver<OpenAPIInfo>> getOpenAPIInfoFunc = this::getOpenAPIInfo;\n            handlers.put(getOpenAPIInfoMethod.getMethodName(), new UnaryStubMethodHandler<>(getOpenAPIInfoFunc));\n            BiConsumer<OpenAPIRequest, StreamObserver<OpenAPIInfo>> getOpenAPIInfoAsyncFunc =\n                    syncToAsync(this::getOpenAPIInfo);\n            handlers.put(\n                    getOpenAPIInfoProxyAsyncMethod.getMethodName(),\n                    new UnaryStubMethodHandler<>(getOpenAPIInfoAsyncFunc));\n\n            return new StubInvoker<>(this, url, MetadataServiceV2.class, handlers);\n        }\n\n        @Override\n        public MetadataInfoV2 getMetadataInfo(MetadataRequest request) {\n            throw unimplementedMethodException(getMetadataInfoMethod);\n        }\n\n        @Override\n        public OpenAPIInfo getOpenAPIInfo(OpenAPIRequest request) {\n            throw unimplementedMethodException(getOpenAPIInfoMethod);\n        }\n\n        @Override\n        public final ServiceDescriptor getServiceDescriptor() {\n            return serviceDescriptor;\n        }\n\n        private RpcException unimplementedMethodException(StubMethodDescriptor methodDescriptor) {\n            return TriRpcStatus.UNIMPLEMENTED\n                    .withDescription(String.format(\n                            \"Method %s is unimplemented\",\n                            \"/\" + serviceDescriptor.getInterfaceName() + \"/\" + methodDescriptor.getMethodName()))\n                    .asException();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/InstanceMetadataChangedListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\npublic interface InstanceMetadataChangedListener {\n    /**\n     * Call when metadata in provider side update <p/>\n     * Used to notify consumer to update metadata of ServiceInstance\n     *\n     * @param metadata latest metadata\n     */\n    void onEvent(String metadata);\n\n    /**\n     * Echo test\n     * Used to check consumer still online\n     */\n    default String echo(String msg) {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MappingCacheManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_MAPPING_CACHE_ENTRYSIZE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_MAPPING_CACHE_FILENAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_MAPPING_CACHE_FILEPATH;\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_MAPPING_CACHE_MAXFILESIZE;\n\n/**\n * TODO, Using randomly accessible file-based cache can be another choice if memory consumption turns to be an issue.\n */\npublic class MappingCacheManager extends AbstractCacheManager<Set<String>> {\n    private static final String DEFAULT_FILE_NAME = \".mapping\";\n    private static final int DEFAULT_ENTRY_SIZE = 10000;\n\n    public static MappingCacheManager getInstance(ScopeModel scopeModel) {\n        return scopeModel.getBeanFactory().getOrRegisterBean(MappingCacheManager.class);\n    }\n\n    public MappingCacheManager(boolean enableFileCache, String name, ScheduledExecutorService executorService) {\n        String filePath = SystemPropertyConfigUtils.getSystemProperty(DUBBO_MAPPING_CACHE_FILEPATH);\n        String fileName = SystemPropertyConfigUtils.getSystemProperty(DUBBO_MAPPING_CACHE_FILENAME);\n        if (StringUtils.isEmpty(fileName)) {\n            fileName = DEFAULT_FILE_NAME;\n        }\n\n        if (StringUtils.isNotEmpty(name)) {\n            fileName = fileName + \".\" + name;\n        }\n\n        String rawEntrySize = SystemPropertyConfigUtils.getSystemProperty(DUBBO_MAPPING_CACHE_ENTRYSIZE);\n        int entrySize = StringUtils.parseInteger(rawEntrySize);\n        entrySize = (entrySize == 0 ? DEFAULT_ENTRY_SIZE : entrySize);\n\n        String rawMaxFileSize = SystemPropertyConfigUtils.getSystemProperty(DUBBO_MAPPING_CACHE_MAXFILESIZE);\n        long maxFileSize = StringUtils.parseLong(rawMaxFileSize);\n\n        init(enableFileCache, filePath, fileName, entrySize, maxFileSize, 50, executorService);\n    }\n\n    @Override\n    protected Set<String> toValueType(String value) {\n        return new HashSet<>(JsonUtils.toJavaList(value, String.class));\n    }\n\n    @Override\n    protected String getName() {\n        return \"mapping\";\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MappingChangedEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport java.util.Set;\n\npublic class MappingChangedEvent {\n\n    private final String serviceKey;\n    private final Set<String> apps;\n\n    public MappingChangedEvent(String serviceKey, Set<String> apps) {\n        this.serviceKey = serviceKey;\n        this.apps = apps;\n    }\n\n    public String getServiceKey() {\n        return serviceKey;\n    }\n\n    public Set<String> getApps() {\n        return apps;\n    }\n\n    @Override\n    public String toString() {\n        return \"{serviceKey: \" + serviceKey + \", apps: \" + apps.toString() + \"}\";\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MappingListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\npublic interface MappingListener {\n    void onEvent(MappingChangedEvent event);\n\n    void stop();\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\npublic interface MetadataConstants {\n    String KEY_SEPARATOR = \":\";\n    String DEFAULT_PATH_TAG = \"metadata\";\n    String KEY_REVISION_PREFIX = \"revision\";\n    String META_DATA_STORE_TAG = \".metaData\";\n    String METADATA_PUBLISH_DELAY_KEY = \"dubbo.application.metadata.publish.delay\";\n    int DEFAULT_METADATA_PUBLISH_DELAY = 1000;\n    String METADATA_PROXY_TIMEOUT_KEY = \"dubbo.application.metadata.proxy.delay\";\n    int DEFAULT_METADATA_TIMEOUT_VALUE = 5000;\n    String REPORT_CONSUMER_URL_KEY = \"report-consumer-definition\";\n\n    String PATH_SEPARATOR = \"/\";\n\n    String NAMESPACE_KEY = \"namespace\";\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.ProtocolServiceKey;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.url.component.URLParam;\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.beans.Transient;\nimport java.io.Serializable;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeMap;\nimport java.util.TreeSet;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentNavigableMap;\nimport java.util.concurrent.ConcurrentSkipListMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DOT_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.IS_EXTRA;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.metadata.RevisionResolver.EMPTY_REVISION;\n\npublic class MetadataInfo implements Serializable {\n    public static final MetadataInfo EMPTY = new MetadataInfo();\n    private static final Logger logger = LoggerFactory.getLogger(MetadataInfo.class);\n\n    private String app;\n    // revision that will report to registry or remote meta center, must always update together with rawMetadataInfo,\n    // check {@link this#calAndGetRevision}\n    private volatile String revision;\n    // key format is '{group}/{interface name}:{version}:{protocol}'\n    private final Map<String, ServiceInfo> services;\n\n    /* used at runtime */\n    private transient AtomicBoolean initiated = new AtomicBoolean(false);\n    // Json formatted metadata that will report to remote meta center, must always update together with revision, check\n    // {@link this#calAndGetRevision}\n    private transient volatile String rawMetadataInfo;\n    // key format is '{group}/{interface name}:{version}'\n    private transient Map<String, Set<ServiceInfo>> subscribedServices;\n    private final transient Map<String, String> extendParams;\n    private final transient Map<String, String> instanceParams;\n    protected transient volatile boolean updated = false;\n    private transient ConcurrentNavigableMap<String, SortedSet<URL>> subscribedServiceURLs;\n    private transient ConcurrentNavigableMap<String, SortedSet<URL>> exportedServiceURLs;\n    private transient ExtensionLoader<MetadataParamsFilter> loader;\n\n    public MetadataInfo() {\n        this(null);\n    }\n\n    public MetadataInfo(String app) {\n        this(app, null, null);\n    }\n\n    public MetadataInfo(String app, String revision, Map<String, ServiceInfo> services) {\n        this.app = app;\n        this.revision = revision;\n        this.services = services == null ? new ConcurrentHashMap<>() : services;\n        this.extendParams = new ConcurrentHashMap<>();\n        this.instanceParams = new ConcurrentHashMap<>();\n    }\n\n    private MetadataInfo(\n            String app,\n            String revision,\n            Map<String, ServiceInfo> services,\n            AtomicBoolean initiated,\n            Map<String, String> extendParams,\n            Map<String, String> instanceParams,\n            boolean updated,\n            ConcurrentNavigableMap<String, SortedSet<URL>> subscribedServiceURLs,\n            ConcurrentNavigableMap<String, SortedSet<URL>> exportedServiceURLs,\n            ExtensionLoader<MetadataParamsFilter> loader) {\n        this.app = app;\n        this.revision = revision;\n        this.services = new ConcurrentHashMap<>(services);\n        this.initiated = new AtomicBoolean(initiated.get());\n        this.extendParams = new ConcurrentHashMap<>(extendParams);\n        this.instanceParams = new ConcurrentHashMap<>(instanceParams);\n        this.updated = updated;\n        this.subscribedServiceURLs =\n                subscribedServiceURLs == null ? null : new ConcurrentSkipListMap<>(subscribedServiceURLs);\n        this.exportedServiceURLs =\n                exportedServiceURLs == null ? null : new ConcurrentSkipListMap<>(exportedServiceURLs);\n        this.loader = loader;\n    }\n\n    /**\n     * Initialize is needed when MetadataInfo is created from deserialization on the consumer side before being used for RPC call.\n     */\n    public void init() {\n        if (!initiated.compareAndSet(false, true)) {\n            return;\n        }\n        if (CollectionUtils.isNotEmptyMap(services)) {\n            services.forEach((_k, serviceInfo) -> {\n                serviceInfo.init();\n                // create duplicate serviceKey(without protocol)->serviceInfo mapping to support metadata search when\n                // protocol is not specified on consumer side.\n                if (subscribedServices == null) {\n                    subscribedServices = new HashMap<>();\n                }\n                Set<ServiceInfo> serviceInfos =\n                        subscribedServices.computeIfAbsent(serviceInfo.getServiceKey(), _key -> new HashSet<>());\n                serviceInfos.add(serviceInfo);\n            });\n        }\n    }\n\n    public synchronized void addService(URL url) {\n        // fixme, pass in application mode context during initialization of MetadataInfo.\n        if (this.loader == null) {\n            this.loader = url.getOrDefaultApplicationModel().getExtensionLoader(MetadataParamsFilter.class);\n        }\n        List<MetadataParamsFilter> filters = loader.getActivateExtension(url, \"params-filter\");\n        // generate service level metadata\n        ServiceInfo serviceInfo = new ServiceInfo(url, filters);\n        this.services.put(serviceInfo.getMatchKey(), serviceInfo);\n        // extract common instance level params\n        extractInstanceParams(url, filters);\n\n        if (exportedServiceURLs == null) {\n            exportedServiceURLs = new ConcurrentSkipListMap<>();\n        }\n        addURL(exportedServiceURLs, url);\n        updated = true;\n    }\n\n    public synchronized void removeService(URL url) {\n        if (url == null) {\n            return;\n        }\n        this.services.remove(url.getProtocolServiceKey());\n        if (exportedServiceURLs != null) {\n            removeURL(exportedServiceURLs, url);\n        }\n\n        updated = true;\n    }\n\n    public String getRevision() {\n        return revision;\n    }\n\n    /**\n     * Calculation of this instance's status like revision and modification of the same instance must be synchronized among different threads.\n     * <p>\n     * Usage of this method is strictly restricted to certain points such as when during registration. Always try to use {@link this#getRevision()} instead.\n     */\n    public synchronized String calAndGetRevision() {\n        if (revision != null && !updated) {\n            return revision;\n        }\n\n        updated = false;\n\n        if (CollectionUtils.isEmptyMap(services)) {\n            this.revision = EMPTY_REVISION;\n        } else {\n            String tempRevision = calRevision();\n            if (!StringUtils.isEquals(this.revision, tempRevision)) {\n                if (logger.isInfoEnabled()) {\n                    logger.info(String.format(\n                            \"[METADATA_REGISTER] metadata revision changed: %s -> %s, app: %s, services: %d\",\n                            this.revision, tempRevision, this.app, this.services.size()));\n                }\n                this.revision = tempRevision;\n                this.rawMetadataInfo = JsonUtils.toJson(this);\n            }\n        }\n        return revision;\n    }\n\n    public synchronized String calRevision() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(app);\n        for (Map.Entry<String, ServiceInfo> entry : new TreeMap<>(services).entrySet()) {\n            sb.append(entry.getValue().toDescString());\n        }\n        return RevisionResolver.calRevision(sb.toString());\n    }\n\n    public void setRevision(String revision) {\n        this.revision = revision;\n    }\n\n    @Transient\n    public String getContent() {\n        return this.rawMetadataInfo;\n    }\n\n    public String getApp() {\n        return app;\n    }\n\n    public void setApp(String app) {\n        this.app = app;\n    }\n\n    public Map<String, ServiceInfo> getServices() {\n        return services;\n    }\n\n    /**\n     * Get service info of an interface with specified group, version and protocol\n     * @param protocolServiceKey key is of format '{group}/{interface name}:{version}:{protocol}'\n     * @return the specific service info related to protocolServiceKey\n     */\n    public ServiceInfo getServiceInfo(String protocolServiceKey) {\n        return services.get(protocolServiceKey);\n    }\n\n    /**\n     * Get service infos of an interface with specified group, version.\n     * There may have several service infos of different protocols, this method will simply pick the first one.\n     *\n     * @param serviceKeyWithoutProtocol key is of format '{group}/{interface name}:{version}'\n     * @return the first service info related to serviceKey\n     */\n    public ServiceInfo getNoProtocolServiceInfo(String serviceKeyWithoutProtocol) {\n        if (CollectionUtils.isEmptyMap(subscribedServices)) {\n            return null;\n        }\n        Set<ServiceInfo> subServices = subscribedServices.get(serviceKeyWithoutProtocol);\n        if (CollectionUtils.isNotEmpty(subServices)) {\n            List<ServiceInfo> validServices = subServices.stream()\n                    .filter(serviceInfo -> StringUtils.isEmpty(serviceInfo.getParameter(IS_EXTRA)))\n                    .collect(Collectors.toList());\n            if (CollectionUtils.isNotEmpty(validServices)) {\n                return validServices.iterator().next();\n            } else {\n                return subServices.iterator().next();\n            }\n        }\n        return null;\n    }\n\n    public ServiceInfo getValidServiceInfo(String serviceKey) {\n        ServiceInfo serviceInfo = getServiceInfo(serviceKey);\n        if (serviceInfo == null) {\n            serviceInfo = getNoProtocolServiceInfo(serviceKey);\n            if (serviceInfo == null) {\n                return null;\n            }\n        }\n        return serviceInfo;\n    }\n\n    public List<ServiceInfo> getMatchedServiceInfos(ProtocolServiceKey consumerProtocolServiceKey) {\n        return getServices().values().stream()\n                .filter(serviceInfo -> serviceInfo.matchProtocolServiceKey(consumerProtocolServiceKey))\n                .collect(Collectors.toList());\n    }\n\n    public Map<String, String> getExtendParams() {\n        return extendParams;\n    }\n\n    public Map<String, String> getInstanceParams() {\n        return instanceParams;\n    }\n\n    public String getParameter(String key, String serviceKey) {\n        ServiceInfo serviceInfo = getValidServiceInfo(serviceKey);\n        if (serviceInfo == null) {\n            return null;\n        }\n        return serviceInfo.getParameter(key);\n    }\n\n    public Map<String, String> getParameters(String serviceKey) {\n        ServiceInfo serviceInfo = getValidServiceInfo(serviceKey);\n        if (serviceInfo == null) {\n            return Collections.emptyMap();\n        }\n        return serviceInfo.getAllParams();\n    }\n\n    public String getServiceString(String protocolServiceKey) {\n        if (protocolServiceKey == null) {\n            return null;\n        }\n\n        ServiceInfo serviceInfo = getValidServiceInfo(protocolServiceKey);\n        if (serviceInfo == null) {\n            return null;\n        }\n        return serviceInfo.toFullString();\n    }\n\n    public synchronized void addSubscribedURL(URL url) {\n        if (subscribedServiceURLs == null) {\n            subscribedServiceURLs = new ConcurrentSkipListMap<>();\n        }\n        addURL(subscribedServiceURLs, url);\n    }\n\n    public boolean removeSubscribedURL(URL url) {\n        if (subscribedServiceURLs == null) {\n            return true;\n        }\n        return removeURL(subscribedServiceURLs, url);\n    }\n\n    public ConcurrentNavigableMap<String, SortedSet<URL>> getSubscribedServiceURLs() {\n        return subscribedServiceURLs;\n    }\n\n    public ConcurrentNavigableMap<String, SortedSet<URL>> getExportedServiceURLs() {\n        return exportedServiceURLs;\n    }\n\n    public Set<URL> collectExportedURLSet() {\n        if (exportedServiceURLs == null) {\n            return Collections.emptySet();\n        }\n        return exportedServiceURLs.values().stream()\n                .filter(CollectionUtils::isNotEmpty)\n                .flatMap(Collection::stream)\n                .collect(Collectors.toSet());\n    }\n\n    private boolean addURL(Map<String, SortedSet<URL>> serviceURLs, URL url) {\n        SortedSet<URL> urls = serviceURLs.computeIfAbsent(url.getServiceKey(), this::newSortedURLs);\n        // make sure the parameters of tmpUrl is variable\n        return urls.add(url);\n    }\n\n    boolean removeURL(Map<String, SortedSet<URL>> serviceURLs, URL url) {\n        String key = url.getServiceKey();\n        SortedSet<URL> urls = serviceURLs.getOrDefault(key, null);\n        if (urls == null) {\n            return true;\n        }\n        boolean r = urls.remove(url);\n        // if it is empty\n        if (urls.isEmpty()) {\n            serviceURLs.remove(key);\n        }\n        return r;\n    }\n\n    private SortedSet<URL> newSortedURLs(String serviceKey) {\n        return new TreeSet<>(URLComparator.INSTANCE);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(app, services);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj == this) {\n            return true;\n        }\n\n        if (!(obj instanceof MetadataInfo)) {\n            return false;\n        }\n\n        MetadataInfo other = (MetadataInfo) obj;\n\n        return Objects.equals(app, other.getApp())\n                && ((services == null && other.services == null)\n                        || (services != null && services.equals(other.services)));\n    }\n\n    private void extractInstanceParams(URL url, List<MetadataParamsFilter> filters) {\n        if (CollectionUtils.isEmpty(filters)) {\n            return;\n        }\n\n        String[] included, excluded;\n        if (filters.size() == 1) {\n            MetadataParamsFilter filter = filters.get(0);\n            included = filter.instanceParamsIncluded();\n            excluded = filter.instanceParamsExcluded();\n        } else {\n            Set<String> includedList = new HashSet<>();\n            Set<String> excludedList = new HashSet<>();\n            filters.forEach(filter -> {\n                if (ArrayUtils.isNotEmpty(filter.instanceParamsIncluded())) {\n                    includedList.addAll(Arrays.asList(filter.instanceParamsIncluded()));\n                }\n                if (ArrayUtils.isNotEmpty(filter.instanceParamsExcluded())) {\n                    excludedList.addAll(Arrays.asList(filter.instanceParamsExcluded()));\n                }\n            });\n            included = includedList.toArray(new String[0]);\n            excluded = excludedList.toArray(new String[0]);\n        }\n\n        Map<String, String> tmpInstanceParams = new HashMap<>();\n        if (ArrayUtils.isNotEmpty(included)) {\n            for (String p : included) {\n                String value = url.getParameter(p);\n                if (value != null) {\n                    tmpInstanceParams.put(p, value);\n                }\n            }\n        } else if (ArrayUtils.isNotEmpty(excluded)) {\n            tmpInstanceParams.putAll(url.getParameters());\n            for (String p : excluded) {\n                tmpInstanceParams.remove(p);\n            }\n        }\n\n        tmpInstanceParams.forEach((key, value) -> {\n            String oldValue = instanceParams.put(key, value);\n            if (!TIMESTAMP_KEY.equals(key) && oldValue != null && !oldValue.equals(value)) {\n                throw new IllegalStateException(String.format(\n                        \"Inconsistent instance metadata found in different services: %s, %s\", oldValue, value));\n            }\n        });\n    }\n\n    @Override\n    public String toString() {\n        return \"metadata{\" + \"app='\"\n                + app + \"',\" + \"revision='\"\n                + revision + \"',\" + \"size=\"\n                + (services == null ? 0 : services.size()) + \",\" + \"services=\"\n                + getSimplifiedServices(services) + \"}\";\n    }\n\n    public String toFullString() {\n        return \"metadata{\" + \"app='\" + app + \"',\" + \"revision='\" + revision + \"',\" + \"services=\" + services + \"}\";\n    }\n\n    private String getSimplifiedServices(Map<String, ServiceInfo> services) {\n        if (services == null) {\n            return \"[]\";\n        }\n\n        return services.keySet().toString();\n    }\n\n    @Override\n    public synchronized MetadataInfo clone() {\n        return new MetadataInfo(\n                app,\n                revision,\n                services,\n                initiated,\n                extendParams,\n                instanceParams,\n                updated,\n                subscribedServiceURLs,\n                exportedServiceURLs,\n                loader);\n    }\n\n    private Object readResolve() {\n        // create a new object from the deserialized one, in order to call constructor\n        return new MetadataInfo(this.app, this.revision, this.services);\n    }\n\n    public static class ServiceInfo implements Serializable {\n        private String name;\n        private String group;\n        private String version;\n        private String protocol;\n        private int port = -1;\n        private String path; // most of the time, path is the same with the interface name.\n        private Map<String, String> params;\n\n        // params configured on consumer side,\n        private transient volatile Map<String, String> consumerParams;\n        // cached method params\n        private transient volatile Map<String, Map<String, String>> methodParams;\n        private transient volatile Map<String, Map<String, String>> consumerMethodParams;\n        // cached numbers\n        private transient volatile Map<String, Number> numbers;\n        private transient volatile Map<String, Map<String, Number>> methodNumbers;\n        // service + group + version\n        private transient volatile String serviceKey;\n        // service + group + version + protocol\n        private transient volatile String matchKey;\n\n        private transient volatile ProtocolServiceKey protocolServiceKey;\n\n        private transient URL url;\n\n        public ServiceInfo() {}\n\n        public ServiceInfo(URL url, List<MetadataParamsFilter> filters) {\n            this(\n                    url.getServiceInterface(),\n                    url.getGroup(),\n                    url.getVersion(),\n                    url.getProtocol(),\n                    url.getPort(),\n                    url.getPath(),\n                    null);\n            this.url = url;\n            Map<String, String> params = extractServiceParams(url, filters);\n            // initialize method params caches.\n            this.methodParams = URLParam.initMethodParameters(params);\n            this.consumerMethodParams = URLParam.initMethodParameters(consumerParams);\n        }\n\n        public ServiceInfo(\n                String name,\n                String group,\n                String version,\n                String protocol,\n                int port,\n                String path,\n                Map<String, String> params) {\n            this.name = name;\n            this.group = group;\n            this.version = version;\n            this.protocol = protocol;\n            this.port = port;\n            this.path = path;\n            this.params = params == null ? new ConcurrentHashMap<>() : params;\n\n            this.serviceKey = buildServiceKey(name, group, version);\n            this.matchKey = buildMatchKey();\n        }\n\n        private Map<String, String> extractServiceParams(URL url, List<MetadataParamsFilter> filters) {\n            Map<String, String> params = new HashMap<>();\n\n            if (CollectionUtils.isEmpty(filters)) {\n                params.putAll(url.getParameters());\n                this.params = params;\n                return params;\n            }\n\n            String[] included, excluded;\n            if (filters.size() == 1) {\n                included = filters.get(0).serviceParamsIncluded();\n                excluded = filters.get(0).serviceParamsExcluded();\n            } else {\n                Set<String> includedList = new HashSet<>();\n                Set<String> excludedList = new HashSet<>();\n                for (MetadataParamsFilter filter : filters) {\n                    if (ArrayUtils.isNotEmpty(filter.serviceParamsIncluded())) {\n                        includedList.addAll(Arrays.asList(filter.serviceParamsIncluded()));\n                    }\n                    if (ArrayUtils.isNotEmpty(filter.serviceParamsExcluded())) {\n                        excludedList.addAll(Arrays.asList(filter.serviceParamsExcluded()));\n                    }\n                }\n                included = includedList.toArray(new String[0]);\n                excluded = excludedList.toArray(new String[0]);\n            }\n\n            if (ArrayUtils.isNotEmpty(included)) {\n                String[] methods = url.getParameter(METHODS_KEY, (String[]) null);\n                for (String p : included) {\n                    String value = url.getParameter(p);\n                    if (StringUtils.isNotEmpty(value) && params.get(p) == null) {\n                        params.put(p, value);\n                    }\n                    appendMethodParams(url, params, methods, p);\n                }\n            } else if (ArrayUtils.isNotEmpty(excluded)) {\n                for (Map.Entry<String, String> entry : url.getParameters().entrySet()) {\n                    String key = entry.getKey();\n                    String value = entry.getValue();\n                    boolean shouldAdd = true;\n                    for (String excludeKey : excluded) {\n                        if (key.equalsIgnoreCase(excludeKey) || key.contains(\".\" + excludeKey)) {\n                            shouldAdd = false;\n                            break;\n                        }\n                    }\n                    if (shouldAdd) {\n                        params.put(key, value);\n                    }\n                }\n            }\n\n            this.params = params;\n            return params;\n        }\n\n        private void appendMethodParams(URL url, Map<String, String> params, String[] methods, String p) {\n            if (methods != null) {\n                for (String method : methods) {\n                    String mValue = url.getMethodParameterStrict(method, p);\n                    if (StringUtils.isNotEmpty(mValue)) {\n                        params.put(method + DOT_SEPARATOR + p, mValue);\n                    }\n                }\n            }\n        }\n\n        /**\n         * Initialize necessary caches right after deserialization on the consumer side\n         */\n        protected void init() {\n            buildMatchKey();\n            buildServiceKey(name, group, version);\n            // init method params\n            this.methodParams = URLParam.initMethodParameters(params);\n            // Actually, consumer params is empty after deserialized on the consumer side, so no need to initialize.\n            // Check how InstanceAddressURL operates on consumer url for more detail.\n            //            this.consumerMethodParams = URLParam.initMethodParameters(consumerParams);\n            // no need to init numbers for it's only for cache purpose\n        }\n\n        public String getMatchKey() {\n            if (matchKey != null) {\n                return matchKey;\n            }\n            buildMatchKey();\n            return matchKey;\n        }\n\n        private String buildMatchKey() {\n            matchKey = getServiceKey();\n            if (StringUtils.isNotEmpty(protocol)) {\n                matchKey = getServiceKey() + GROUP_CHAR_SEPARATOR + protocol;\n            }\n            return matchKey;\n        }\n\n        public boolean matchProtocolServiceKey(ProtocolServiceKey protocolServiceKey) {\n            return ProtocolServiceKey.Matcher.isMatch(protocolServiceKey, getProtocolServiceKey());\n        }\n\n        public ProtocolServiceKey getProtocolServiceKey() {\n            if (protocolServiceKey != null) {\n                return protocolServiceKey;\n            }\n            protocolServiceKey = new ProtocolServiceKey(name, version, group, protocol);\n            return protocolServiceKey;\n        }\n\n        private String buildServiceKey(String name, String group, String version) {\n            this.serviceKey = URL.buildKey(name, group, version);\n            return this.serviceKey;\n        }\n\n        public String getServiceKey() {\n            if (serviceKey != null) {\n                return serviceKey;\n            }\n            buildServiceKey(name, group, version);\n            return serviceKey;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public String getGroup() {\n            return group;\n        }\n\n        public void setGroup(String group) {\n            this.group = group;\n        }\n\n        public String getVersion() {\n            return version;\n        }\n\n        public void setVersion(String version) {\n            this.version = version;\n        }\n\n        public String getPath() {\n            return path;\n        }\n\n        public void setPath(String path) {\n            this.path = path;\n        }\n\n        public String getProtocol() {\n            return protocol;\n        }\n\n        public void setProtocol(String protocol) {\n            this.protocol = protocol;\n        }\n\n        public int getPort() {\n            return port;\n        }\n\n        public void setPort(int port) {\n            this.port = port;\n        }\n\n        public Map<String, String> getParams() {\n            if (params == null) {\n                return Collections.emptyMap();\n            }\n            return params;\n        }\n\n        public void setParams(Map<String, String> params) {\n            this.params = params;\n        }\n\n        @Transient\n        public Map<String, String> getAllParams() {\n            if (consumerParams != null) {\n                Map<String, String> allParams =\n                        new HashMap<>((int) ((params.size() + consumerParams.size()) / 0.75f + 1));\n                allParams.putAll(params);\n                allParams.putAll(consumerParams);\n                return allParams;\n            }\n            return params;\n        }\n\n        public String getParameter(String key) {\n            if (consumerParams != null) {\n                String value = consumerParams.get(key);\n                if (value != null) {\n                    return value;\n                }\n            }\n            return params.get(key);\n        }\n\n        public String getMethodParameter(String method, String key, String defaultValue) {\n            String value = getMethodParameter(method, key, consumerMethodParams);\n            if (value != null) {\n                return value;\n            }\n            value = getMethodParameter(method, key, methodParams);\n            return value == null ? defaultValue : value;\n        }\n\n        private String getMethodParameter(String method, String key, Map<String, Map<String, String>> map) {\n            String value = null;\n            if (map == null) {\n                return value;\n            }\n\n            Map<String, String> keyMap = map.get(method);\n            if (keyMap != null) {\n                value = keyMap.get(key);\n            }\n            return value;\n        }\n\n        public boolean hasMethodParameter(String method, String key) {\n            String value = this.getMethodParameter(method, key, (String) null);\n            return StringUtils.isNotEmpty(value);\n        }\n\n        public boolean hasMethodParameter(String method) {\n            return (consumerMethodParams != null && consumerMethodParams.containsKey(method))\n                    || (methodParams != null && methodParams.containsKey(method));\n        }\n\n        public String toDescString() {\n            return this.getMatchKey() + port + path + new TreeMap<>(getParams());\n        }\n\n        public void addParameter(String key, String value) {\n            if (consumerParams != null) {\n                this.consumerParams.put(key, value);\n            }\n            // refresh method params\n            consumerMethodParams = URLParam.initMethodParameters(consumerParams);\n        }\n\n        public void addParameterIfAbsent(String key, String value) {\n            if (consumerParams != null) {\n                this.consumerParams.putIfAbsent(key, value);\n            }\n            // refresh method params\n            consumerMethodParams = URLParam.initMethodParameters(consumerParams);\n        }\n\n        public void addConsumerParams(Map<String, String> params) {\n            // copy once for one service subscription\n            if (consumerParams == null) {\n                consumerParams = new ConcurrentHashMap<>(params);\n                // init method params\n                consumerMethodParams = URLParam.initMethodParameters(consumerParams);\n            }\n        }\n\n        public Map<String, Number> getNumbers() {\n            // concurrent initialization is tolerant\n            if (numbers == null) {\n                numbers = new ConcurrentHashMap<>();\n            }\n            return numbers;\n        }\n\n        public Map<String, Map<String, Number>> getMethodNumbers() {\n            if (methodNumbers == null) { // concurrent initialization is tolerant\n                methodNumbers = new ConcurrentHashMap<>();\n            }\n            return methodNumbers;\n        }\n\n        public URL getUrl() {\n            return url;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (obj == null) {\n                return false;\n            }\n            if (!(obj instanceof ServiceInfo)) {\n                return false;\n            }\n\n            ServiceInfo serviceInfo = (ServiceInfo) obj;\n            /**\n             * Equals to Objects.equals(this.getMatchKey(), serviceInfo.getMatchKey()), but match key will not get initialized\n             * on json deserialization.\n             */\n            return Objects.equals(this.getVersion(), serviceInfo.getVersion())\n                    && Objects.equals(this.getGroup(), serviceInfo.getGroup())\n                    && Objects.equals(this.getName(), serviceInfo.getName())\n                    && Objects.equals(this.getProtocol(), serviceInfo.getProtocol())\n                    && Objects.equals(this.getPort(), serviceInfo.getPort())\n                    && this.getParams().equals(serviceInfo.getParams());\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(getVersion(), getGroup(), getName(), getProtocol(), getPort(), getParams());\n        }\n\n        @Override\n        public String toString() {\n            return getMatchKey();\n        }\n\n        public String toFullString() {\n            return \"service{\" + \"name='\"\n                    + name + \"',\" + \"group='\"\n                    + group + \"',\" + \"version='\"\n                    + version + \"',\" + \"protocol='\"\n                    + protocol + \"',\" + \"port='\"\n                    + port + \"',\" + \"params=\"\n                    + params + \",\" + \"}\";\n        }\n    }\n\n    static class URLComparator implements Comparator<URL> {\n\n        public static final URLComparator INSTANCE = new URLComparator();\n\n        @Override\n        public int compare(URL o1, URL o2) {\n            return o1.toFullString().compareTo(o2.toFullString());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\n/**\n * <pre>\n * Metadata information message.\n * </pre>\n *\n * Protobuf type {@code org.apache.dubbo.metadata.MetadataInfoV2}\n */\npublic final class MetadataInfoV2 extends com.google.protobuf.GeneratedMessageV3\n        implements\n        // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.MetadataInfoV2)\n        MetadataInfoV2OrBuilder {\n    private static final long serialVersionUID = 0L;\n\n    // Use MetadataInfoV2.newBuilder() to construct.\n    private MetadataInfoV2(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n        super(builder);\n    }\n\n    private MetadataInfoV2() {\n        app_ = \"\";\n        version_ = \"\";\n    }\n\n    @Override\n    @SuppressWarnings({\"unused\"})\n    protected Object newInstance(UnusedPrivateParameter unused) {\n        return new MetadataInfoV2();\n    }\n\n    public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n        return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataInfoV2_descriptor;\n    }\n\n    @SuppressWarnings({\"rawtypes\"})\n    @Override\n    protected com.google.protobuf.MapField internalGetMapField(int number) {\n        switch (number) {\n            case 3:\n                return internalGetServices();\n            default:\n                throw new RuntimeException(\"Invalid map field number: \" + number);\n        }\n    }\n\n    @Override\n    protected FieldAccessorTable internalGetFieldAccessorTable() {\n        return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataInfoV2_fieldAccessorTable\n                .ensureFieldAccessorsInitialized(MetadataInfoV2.class, Builder.class);\n    }\n\n    public static final int APP_FIELD_NUMBER = 1;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object app_ = \"\";\n\n    /**\n     * <pre>\n     * The application name.\n     * </pre>\n     *\n     * <code>string app = 1;</code>\n     * @return The app.\n     */\n    @Override\n    public String getApp() {\n        Object ref = app_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            app_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The application name.\n     * </pre>\n     *\n     * <code>string app = 1;</code>\n     * @return The bytes for app.\n     */\n    @Override\n    public com.google.protobuf.ByteString getAppBytes() {\n        Object ref = app_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            app_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    public static final int VERSION_FIELD_NUMBER = 2;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object version_ = \"\";\n\n    /**\n     * <pre>\n     * The application version.\n     * </pre>\n     *\n     * <code>string version = 2;</code>\n     * @return The version.\n     */\n    @Override\n    public String getVersion() {\n        Object ref = version_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            version_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The application version.\n     * </pre>\n     *\n     * <code>string version = 2;</code>\n     * @return The bytes for version.\n     */\n    @Override\n    public com.google.protobuf.ByteString getVersionBytes() {\n        Object ref = version_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            version_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    public static final int SERVICES_FIELD_NUMBER = 3;\n\n    private static final class ServicesDefaultEntryHolder {\n        static final com.google.protobuf.MapEntry<String, ServiceInfoV2> defaultEntry =\n                com.google.protobuf.MapEntry.<String, ServiceInfoV2>newDefaultInstance(\n                        MetadataServiceV2OuterClass\n                                .internal_static_org_apache_dubbo_metadata_MetadataInfoV2_ServicesEntry_descriptor,\n                        com.google.protobuf.WireFormat.FieldType.STRING,\n                        \"\",\n                        com.google.protobuf.WireFormat.FieldType.MESSAGE,\n                        ServiceInfoV2.getDefaultInstance());\n    }\n\n    @SuppressWarnings(\"serial\")\n    private com.google.protobuf.MapField<String, ServiceInfoV2> services_;\n\n    private com.google.protobuf.MapField<String, ServiceInfoV2> internalGetServices() {\n        if (services_ == null) {\n            return com.google.protobuf.MapField.emptyMapField(ServicesDefaultEntryHolder.defaultEntry);\n        }\n        return services_;\n    }\n\n    public int getServicesCount() {\n        return internalGetServices().getMap().size();\n    }\n\n    /**\n     * <pre>\n     * A map of service information.\n     * </pre>\n     *\n     * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n     */\n    @Override\n    public boolean containsServices(String key) {\n        if (key == null) {\n            throw new NullPointerException(\"map key\");\n        }\n        return internalGetServices().getMap().containsKey(key);\n    }\n\n    /**\n     * Use {@link #getServicesMap()} instead.\n     */\n    @Override\n    @Deprecated\n    public java.util.Map<String, ServiceInfoV2> getServices() {\n        return getServicesMap();\n    }\n\n    /**\n     * <pre>\n     * A map of service information.\n     * </pre>\n     *\n     * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n     */\n    @Override\n    public java.util.Map<String, ServiceInfoV2> getServicesMap() {\n        return internalGetServices().getMap();\n    }\n\n    /**\n     * <pre>\n     * A map of service information.\n     * </pre>\n     *\n     * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n     */\n    @Override\n    public /* nullable */ ServiceInfoV2 getServicesOrDefault(\n            String key,\n            /* nullable */\n            ServiceInfoV2 defaultValue) {\n        if (key == null) {\n            throw new NullPointerException(\"map key\");\n        }\n        java.util.Map<String, ServiceInfoV2> map = internalGetServices().getMap();\n        return map.containsKey(key) ? map.get(key) : defaultValue;\n    }\n\n    /**\n     * <pre>\n     * A map of service information.\n     * </pre>\n     *\n     * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n     */\n    @Override\n    public ServiceInfoV2 getServicesOrThrow(String key) {\n        if (key == null) {\n            throw new NullPointerException(\"map key\");\n        }\n        java.util.Map<String, ServiceInfoV2> map = internalGetServices().getMap();\n        if (!map.containsKey(key)) {\n            throw new IllegalArgumentException();\n        }\n        return map.get(key);\n    }\n\n    private byte memoizedIsInitialized = -1;\n\n    @Override\n    public final boolean isInitialized() {\n        byte isInitialized = memoizedIsInitialized;\n        if (isInitialized == 1) {\n            return true;\n        }\n        if (isInitialized == 0) {\n            return false;\n        }\n\n        memoizedIsInitialized = 1;\n        return true;\n    }\n\n    @Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(app_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 1, app_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(version_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 2, version_);\n        }\n        com.google.protobuf.GeneratedMessageV3.serializeStringMapTo(\n                output, internalGetServices(), ServicesDefaultEntryHolder.defaultEntry, 3);\n        getUnknownFields().writeTo(output);\n    }\n\n    @Override\n    public int getSerializedSize() {\n        int size = memoizedSize;\n        if (size != -1) {\n            return size;\n        }\n\n        size = 0;\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(app_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, app_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(version_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, version_);\n        }\n        for (java.util.Map.Entry<String, ServiceInfoV2> entry :\n                internalGetServices().getMap().entrySet()) {\n            com.google.protobuf.MapEntry<String, ServiceInfoV2> services__ = ServicesDefaultEntryHolder.defaultEntry\n                    .newBuilderForType()\n                    .setKey(entry.getKey())\n                    .setValue(entry.getValue())\n                    .build();\n            size += com.google.protobuf.CodedOutputStream.computeMessageSize(3, services__);\n        }\n        size += getUnknownFields().getSerializedSize();\n        memoizedSize = size;\n        return size;\n    }\n\n    @Override\n    public boolean equals(final Object obj) {\n        if (obj == this) {\n            return true;\n        }\n        if (!(obj instanceof MetadataInfoV2)) {\n            return super.equals(obj);\n        }\n        MetadataInfoV2 other = (MetadataInfoV2) obj;\n\n        if (!getApp().equals(other.getApp())) {\n            return false;\n        }\n        if (!getVersion().equals(other.getVersion())) {\n            return false;\n        }\n        if (!internalGetServices().equals(other.internalGetServices())) {\n            return false;\n        }\n        if (!getUnknownFields().equals(other.getUnknownFields())) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        if (memoizedHashCode != 0) {\n            return memoizedHashCode;\n        }\n        int hash = 41;\n        hash = (19 * hash) + getDescriptor().hashCode();\n        hash = (37 * hash) + APP_FIELD_NUMBER;\n        hash = (53 * hash) + getApp().hashCode();\n        hash = (37 * hash) + VERSION_FIELD_NUMBER;\n        hash = (53 * hash) + getVersion().hashCode();\n        if (!internalGetServices().getMap().isEmpty()) {\n            hash = (37 * hash) + SERVICES_FIELD_NUMBER;\n            hash = (53 * hash) + internalGetServices().hashCode();\n        }\n        hash = (29 * hash) + getUnknownFields().hashCode();\n        memoizedHashCode = hash;\n        return hash;\n    }\n\n    public static MetadataInfoV2 parseFrom(java.nio.ByteBuffer data)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static MetadataInfoV2 parseFrom(\n            java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static MetadataInfoV2 parseFrom(com.google.protobuf.ByteString data)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static MetadataInfoV2 parseFrom(\n            com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static MetadataInfoV2 parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static MetadataInfoV2 parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static MetadataInfoV2 parseFrom(java.io.InputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n    }\n\n    public static MetadataInfoV2 parseFrom(\n            java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static MetadataInfoV2 parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input);\n    }\n\n    public static MetadataInfoV2 parseDelimitedFrom(\n            java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static MetadataInfoV2 parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n    }\n\n    public static MetadataInfoV2 parseFrom(\n            com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @Override\n    public Builder newBuilderForType() {\n        return newBuilder();\n    }\n\n    public static Builder newBuilder() {\n        return DEFAULT_INSTANCE.toBuilder();\n    }\n\n    public static Builder newBuilder(MetadataInfoV2 prototype) {\n        return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n\n    @Override\n    public Builder toBuilder() {\n        return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @Override\n    protected Builder newBuilderForType(BuilderParent parent) {\n        Builder builder = new Builder(parent);\n        return builder;\n    }\n\n    /**\n     * <pre>\n     * Metadata information message.\n     * </pre>\n     *\n     * Protobuf type {@code org.apache.dubbo.metadata.MetadataInfoV2}\n     */\n    public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder<Builder>\n            implements\n            // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.MetadataInfoV2)\n            MetadataInfoV2OrBuilder {\n        public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataInfoV2_descriptor;\n        }\n\n        @SuppressWarnings({\"rawtypes\"})\n        protected com.google.protobuf.MapField internalGetMapField(int number) {\n            switch (number) {\n                case 3:\n                    return internalGetServices();\n                default:\n                    throw new RuntimeException(\"Invalid map field number: \" + number);\n            }\n        }\n\n        @SuppressWarnings({\"rawtypes\"})\n        protected com.google.protobuf.MapField internalGetMutableMapField(int number) {\n            switch (number) {\n                case 3:\n                    return internalGetMutableServices();\n                default:\n                    throw new RuntimeException(\"Invalid map field number: \" + number);\n            }\n        }\n\n        @Override\n        protected FieldAccessorTable internalGetFieldAccessorTable() {\n            return MetadataServiceV2OuterClass\n                    .internal_static_org_apache_dubbo_metadata_MetadataInfoV2_fieldAccessorTable\n                    .ensureFieldAccessorsInitialized(MetadataInfoV2.class, Builder.class);\n        }\n\n        // Construct using org.apache.dubbo.metadata.MetadataInfoV2.newBuilder()\n        private Builder() {}\n\n        private Builder(BuilderParent parent) {\n            super(parent);\n        }\n\n        @Override\n        public Builder clear() {\n            super.clear();\n            bitField0_ = 0;\n            app_ = \"\";\n            version_ = \"\";\n            internalGetMutableServices().clear();\n            return this;\n        }\n\n        @Override\n        public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataInfoV2_descriptor;\n        }\n\n        @Override\n        public MetadataInfoV2 getDefaultInstanceForType() {\n            return MetadataInfoV2.getDefaultInstance();\n        }\n\n        @Override\n        public MetadataInfoV2 build() {\n            MetadataInfoV2 result = buildPartial();\n            if (!result.isInitialized()) {\n                throw newUninitializedMessageException(result);\n            }\n            return result;\n        }\n\n        @Override\n        public MetadataInfoV2 buildPartial() {\n            MetadataInfoV2 result = new MetadataInfoV2(this);\n            if (bitField0_ != 0) {\n                buildPartial0(result);\n            }\n            onBuilt();\n            return result;\n        }\n\n        private void buildPartial0(MetadataInfoV2 result) {\n            int from_bitField0_ = bitField0_;\n            if (((from_bitField0_ & 0x00000001) != 0)) {\n                result.app_ = app_;\n            }\n            if (((from_bitField0_ & 0x00000002) != 0)) {\n                result.version_ = version_;\n            }\n            if (((from_bitField0_ & 0x00000004) != 0)) {\n                result.services_ = internalGetServices();\n                result.services_.makeImmutable();\n            }\n        }\n\n        @Override\n        public Builder clone() {\n            return super.clone();\n        }\n\n        @Override\n        public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) {\n            return super.setField(field, value);\n        }\n\n        @Override\n        public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) {\n            return super.clearField(field);\n        }\n\n        @Override\n        public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n            return super.clearOneof(oneof);\n        }\n\n        @Override\n        public Builder setRepeatedField(\n                com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) {\n            return super.setRepeatedField(field, index, value);\n        }\n\n        @Override\n        public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) {\n            return super.addRepeatedField(field, value);\n        }\n\n        @Override\n        public Builder mergeFrom(com.google.protobuf.Message other) {\n            if (other instanceof MetadataInfoV2) {\n                return mergeFrom((MetadataInfoV2) other);\n            } else {\n                super.mergeFrom(other);\n                return this;\n            }\n        }\n\n        public Builder mergeFrom(MetadataInfoV2 other) {\n            if (other == MetadataInfoV2.getDefaultInstance()) {\n                return this;\n            }\n            if (!other.getApp().isEmpty()) {\n                app_ = other.app_;\n                bitField0_ |= 0x00000001;\n                onChanged();\n            }\n            if (!other.getVersion().isEmpty()) {\n                version_ = other.version_;\n                bitField0_ |= 0x00000002;\n                onChanged();\n            }\n            internalGetMutableServices().mergeFrom(other.internalGetServices());\n            bitField0_ |= 0x00000004;\n            this.mergeUnknownFields(other.getUnknownFields());\n            onChanged();\n            return this;\n        }\n\n        @Override\n        public final boolean isInitialized() {\n            return true;\n        }\n\n        @Override\n        public Builder mergeFrom(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            if (extensionRegistry == null) {\n                throw new NullPointerException();\n            }\n            try {\n                boolean done = false;\n                while (!done) {\n                    int tag = input.readTag();\n                    switch (tag) {\n                        case 0:\n                            done = true;\n                            break;\n                        case 10: {\n                            app_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000001;\n                            break;\n                        } // case 10\n                        case 18: {\n                            version_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000002;\n                            break;\n                        } // case 18\n                        case 26: {\n                            com.google.protobuf.MapEntry<String, ServiceInfoV2> services__ = input.readMessage(\n                                    ServicesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry);\n                            internalGetMutableServices()\n                                    .getMutableMap()\n                                    .put(services__.getKey(), services__.getValue());\n                            bitField0_ |= 0x00000004;\n                            break;\n                        } // case 26\n                        default: {\n                            if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                                done = true; // was an endgroup tag\n                            }\n                            break;\n                        } // default:\n                    } // switch (tag)\n                } // while (!done)\n            } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                throw e.unwrapIOException();\n            } finally {\n                onChanged();\n            } // finally\n            return this;\n        }\n\n        private int bitField0_;\n\n        private Object app_ = \"\";\n\n        /**\n         * <pre>\n         * The application name.\n         * </pre>\n         *\n         * <code>string app = 1;</code>\n         * @return The app.\n         */\n        public String getApp() {\n            Object ref = app_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                app_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The application name.\n         * </pre>\n         *\n         * <code>string app = 1;</code>\n         * @return The bytes for app.\n         */\n        public com.google.protobuf.ByteString getAppBytes() {\n            Object ref = app_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                app_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The application name.\n         * </pre>\n         *\n         * <code>string app = 1;</code>\n         * @param value The app to set.\n         * @return This builder for chaining.\n         */\n        public Builder setApp(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            app_ = value;\n            bitField0_ |= 0x00000001;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The application name.\n         * </pre>\n         *\n         * <code>string app = 1;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearApp() {\n            app_ = getDefaultInstance().getApp();\n            bitField0_ = (bitField0_ & ~0x00000001);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The application name.\n         * </pre>\n         *\n         * <code>string app = 1;</code>\n         * @param value The bytes for app to set.\n         * @return This builder for chaining.\n         */\n        public Builder setAppBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            app_ = value;\n            bitField0_ |= 0x00000001;\n            onChanged();\n            return this;\n        }\n\n        private Object version_ = \"\";\n\n        /**\n         * <pre>\n         * The application version.\n         * </pre>\n         *\n         * <code>string version = 2;</code>\n         * @return The version.\n         */\n        public String getVersion() {\n            Object ref = version_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                version_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The application version.\n         * </pre>\n         *\n         * <code>string version = 2;</code>\n         * @return The bytes for version.\n         */\n        public com.google.protobuf.ByteString getVersionBytes() {\n            Object ref = version_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                version_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The application version.\n         * </pre>\n         *\n         * <code>string version = 2;</code>\n         * @param value The version to set.\n         * @return This builder for chaining.\n         */\n        public Builder setVersion(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            version_ = value;\n            bitField0_ |= 0x00000002;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The application version.\n         * </pre>\n         *\n         * <code>string version = 2;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearVersion() {\n            version_ = getDefaultInstance().getVersion();\n            bitField0_ = (bitField0_ & ~0x00000002);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The application version.\n         * </pre>\n         *\n         * <code>string version = 2;</code>\n         * @param value The bytes for version to set.\n         * @return This builder for chaining.\n         */\n        public Builder setVersionBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            version_ = value;\n            bitField0_ |= 0x00000002;\n            onChanged();\n            return this;\n        }\n\n        private com.google.protobuf.MapField<String, ServiceInfoV2> services_;\n\n        private com.google.protobuf.MapField<String, ServiceInfoV2> internalGetServices() {\n            if (services_ == null) {\n                return com.google.protobuf.MapField.emptyMapField(ServicesDefaultEntryHolder.defaultEntry);\n            }\n            return services_;\n        }\n\n        private com.google.protobuf.MapField<String, ServiceInfoV2> internalGetMutableServices() {\n            if (services_ == null) {\n                services_ = com.google.protobuf.MapField.newMapField(ServicesDefaultEntryHolder.defaultEntry);\n            }\n            if (!services_.isMutable()) {\n                services_ = services_.copy();\n            }\n            bitField0_ |= 0x00000004;\n            onChanged();\n            return services_;\n        }\n\n        public int getServicesCount() {\n            return internalGetServices().getMap().size();\n        }\n\n        /**\n         * <pre>\n         * A map of service information.\n         * </pre>\n         *\n         * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n         */\n        @Override\n        public boolean containsServices(String key) {\n            if (key == null) {\n                throw new NullPointerException(\"map key\");\n            }\n            return internalGetServices().getMap().containsKey(key);\n        }\n\n        /**\n         * Use {@link #getServicesMap()} instead.\n         */\n        @Override\n        @Deprecated\n        public java.util.Map<String, ServiceInfoV2> getServices() {\n            return getServicesMap();\n        }\n\n        /**\n         * <pre>\n         * A map of service information.\n         * </pre>\n         *\n         * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n         */\n        @Override\n        public java.util.Map<String, ServiceInfoV2> getServicesMap() {\n            return internalGetServices().getMap();\n        }\n\n        /**\n         * <pre>\n         * A map of service information.\n         * </pre>\n         *\n         * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n         */\n        @Override\n        public /* nullable */ ServiceInfoV2 getServicesOrDefault(\n                String key,\n                /* nullable */\n                ServiceInfoV2 defaultValue) {\n            if (key == null) {\n                throw new NullPointerException(\"map key\");\n            }\n            java.util.Map<String, ServiceInfoV2> map = internalGetServices().getMap();\n            return map.containsKey(key) ? map.get(key) : defaultValue;\n        }\n\n        /**\n         * <pre>\n         * A map of service information.\n         * </pre>\n         *\n         * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n         */\n        @Override\n        public ServiceInfoV2 getServicesOrThrow(String key) {\n            if (key == null) {\n                throw new NullPointerException(\"map key\");\n            }\n            java.util.Map<String, ServiceInfoV2> map = internalGetServices().getMap();\n            if (!map.containsKey(key)) {\n                throw new IllegalArgumentException();\n            }\n            return map.get(key);\n        }\n\n        public Builder clearServices() {\n            bitField0_ = (bitField0_ & ~0x00000004);\n            internalGetMutableServices().getMutableMap().clear();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * A map of service information.\n         * </pre>\n         *\n         * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n         */\n        public Builder removeServices(String key) {\n            if (key == null) {\n                throw new NullPointerException(\"map key\");\n            }\n            internalGetMutableServices().getMutableMap().remove(key);\n            return this;\n        }\n\n        /**\n         * Use alternate mutation accessors instead.\n         */\n        @Deprecated\n        public java.util.Map<String, ServiceInfoV2> getMutableServices() {\n            bitField0_ |= 0x00000004;\n            return internalGetMutableServices().getMutableMap();\n        }\n\n        /**\n         * <pre>\n         * A map of service information.\n         * </pre>\n         *\n         * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n         */\n        public Builder putServices(String key, ServiceInfoV2 value) {\n            if (key == null) {\n                throw new NullPointerException(\"map key\");\n            }\n            if (value == null) {\n                throw new NullPointerException(\"map value\");\n            }\n            internalGetMutableServices().getMutableMap().put(key, value);\n            bitField0_ |= 0x00000004;\n            return this;\n        }\n\n        /**\n         * <pre>\n         * A map of service information.\n         * </pre>\n         *\n         * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n         */\n        public Builder putAllServices(java.util.Map<String, ServiceInfoV2> values) {\n            internalGetMutableServices().getMutableMap().putAll(values);\n            bitField0_ |= 0x00000004;\n            return this;\n        }\n\n        @Override\n        public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n            return super.setUnknownFields(unknownFields);\n        }\n\n        @Override\n        public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n            return super.mergeUnknownFields(unknownFields);\n        }\n\n        // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.MetadataInfoV2)\n    }\n\n    // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.MetadataInfoV2)\n    private static final MetadataInfoV2 DEFAULT_INSTANCE;\n\n    static {\n        DEFAULT_INSTANCE = new MetadataInfoV2();\n    }\n\n    public static MetadataInfoV2 getDefaultInstance() {\n        return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<MetadataInfoV2> PARSER =\n            new com.google.protobuf.AbstractParser<MetadataInfoV2>() {\n                @Override\n                public MetadataInfoV2 parsePartialFrom(\n                        com.google.protobuf.CodedInputStream input,\n                        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                        throws com.google.protobuf.InvalidProtocolBufferException {\n                    Builder builder = newBuilder();\n                    try {\n                        builder.mergeFrom(input, extensionRegistry);\n                    } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                        throw e.setUnfinishedMessage(builder.buildPartial());\n                    } catch (com.google.protobuf.UninitializedMessageException e) {\n                        throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n                    } catch (java.io.IOException e) {\n                        throw new com.google.protobuf.InvalidProtocolBufferException(e)\n                                .setUnfinishedMessage(builder.buildPartial());\n                    }\n                    return builder.buildPartial();\n                }\n            };\n\n    public static com.google.protobuf.Parser<MetadataInfoV2> parser() {\n        return PARSER;\n    }\n\n    @Override\n    public com.google.protobuf.Parser<MetadataInfoV2> getParserForType() {\n        return PARSER;\n    }\n\n    @Override\n    public MetadataInfoV2 getDefaultInstanceForType() {\n        return DEFAULT_INSTANCE;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2OrBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\npublic interface MetadataInfoV2OrBuilder\n        extends\n        // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.MetadataInfoV2)\n        com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <pre>\n     * The application name.\n     * </pre>\n     *\n     * <code>string app = 1;</code>\n     * @return The app.\n     */\n    String getApp();\n\n    /**\n     * <pre>\n     * The application name.\n     * </pre>\n     *\n     * <code>string app = 1;</code>\n     * @return The bytes for app.\n     */\n    com.google.protobuf.ByteString getAppBytes();\n\n    /**\n     * <pre>\n     * The application version.\n     * </pre>\n     *\n     * <code>string version = 2;</code>\n     * @return The version.\n     */\n    String getVersion();\n\n    /**\n     * <pre>\n     * The application version.\n     * </pre>\n     *\n     * <code>string version = 2;</code>\n     * @return The bytes for version.\n     */\n    com.google.protobuf.ByteString getVersionBytes();\n\n    /**\n     * <pre>\n     * A map of service information.\n     * </pre>\n     *\n     * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n     */\n    int getServicesCount();\n\n    /**\n     * <pre>\n     * A map of service information.\n     * </pre>\n     *\n     * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n     */\n    boolean containsServices(String key);\n\n    /**\n     * Use {@link #getServicesMap()} instead.\n     */\n    @Deprecated\n    java.util.Map<String, ServiceInfoV2> getServices();\n\n    /**\n     * <pre>\n     * A map of service information.\n     * </pre>\n     *\n     * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n     */\n    java.util.Map<String, ServiceInfoV2> getServicesMap();\n\n    /**\n     * <pre>\n     * A map of service information.\n     * </pre>\n     *\n     * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n     */\n    /* nullable */\n    ServiceInfoV2 getServicesOrDefault(\n            String key,\n            /* nullable */\n            ServiceInfoV2 defaultValue);\n\n    /**\n     * <pre>\n     * A map of service information.\n     * </pre>\n     *\n     * <code>map&lt;string, .org.apache.dubbo.metadata.ServiceInfoV2&gt; services = 3;</code>\n     */\n    ServiceInfoV2 getServicesOrThrow(String key);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataParamsFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * This filter applies an either 'include' or 'exclude' policy with 'include' having higher priority.\n * That means if 'include' is specified then params specified in 'exclude' will be ignored\n *\n * If multiple Filter extensions are provided, then,\n * 1. All params specified as should be included within different Filter extension instances will determine the params that will finally be used.\n * 2. If none of the Filter extensions specified any params as should be included, then the final effective params would be those left after removed all the params specified as should be excluded.\n *\n * It is recommended for most users to use 'exclude' policy for service params and 'include' policy for instance params.\n * Please use 'params-filter=-default, -filterName1, filterName2' to activate or deactivate filter extensions.\n */\n@SPI\npublic interface MetadataParamsFilter {\n\n    /**\n     * params that need to be sent to metadata center\n     *\n     * @return arrays of keys\n     */\n    default String[] serviceParamsIncluded() {\n        return new String[0];\n    }\n\n    /**\n     * params that need to be excluded before sending to metadata center\n     *\n     * @return arrays of keys\n     */\n    default String[] serviceParamsExcluded() {\n        return new String[0];\n    }\n\n    /**\n     * params that need to be sent to registry center\n     *\n     * @return arrays of keys\n     */\n    default String[] instanceParamsIncluded() {\n        return new String[0];\n    }\n\n    /**\n     * params that need to be excluded before sending to registry center\n     *\n     * @return arrays of keys\n     */\n    default String[] instanceParamsExcluded() {\n        return new String[0];\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\n/**\n * <pre>\n * Metadata request message.\n * </pre>\n *\n * Protobuf type {@code org.apache.dubbo.metadata.MetadataRequest}\n */\npublic final class MetadataRequest extends com.google.protobuf.GeneratedMessageV3\n        implements\n        // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.MetadataRequest)\n        MetadataRequestOrBuilder {\n    private static final long serialVersionUID = 0L;\n\n    // Use MetadataRequest.newBuilder() to construct.\n    private MetadataRequest(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n        super(builder);\n    }\n\n    private MetadataRequest() {\n        revision_ = \"\";\n    }\n\n    @Override\n    @SuppressWarnings({\"unused\"})\n    protected Object newInstance(UnusedPrivateParameter unused) {\n        return new MetadataRequest();\n    }\n\n    public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n        return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataRequest_descriptor;\n    }\n\n    @Override\n    protected FieldAccessorTable internalGetFieldAccessorTable() {\n        return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataRequest_fieldAccessorTable\n                .ensureFieldAccessorsInitialized(MetadataRequest.class, Builder.class);\n    }\n\n    public static final int REVISION_FIELD_NUMBER = 1;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object revision_ = \"\";\n\n    /**\n     * <pre>\n     * The revision of the metadata.\n     * </pre>\n     *\n     * <code>string revision = 1;</code>\n     * @return The revision.\n     */\n    @Override\n    public String getRevision() {\n        Object ref = revision_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            revision_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The revision of the metadata.\n     * </pre>\n     *\n     * <code>string revision = 1;</code>\n     * @return The bytes for revision.\n     */\n    @Override\n    public com.google.protobuf.ByteString getRevisionBytes() {\n        Object ref = revision_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            revision_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    private byte memoizedIsInitialized = -1;\n\n    @Override\n    public final boolean isInitialized() {\n        byte isInitialized = memoizedIsInitialized;\n        if (isInitialized == 1) {\n            return true;\n        }\n        if (isInitialized == 0) {\n            return false;\n        }\n\n        memoizedIsInitialized = 1;\n        return true;\n    }\n\n    @Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(revision_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 1, revision_);\n        }\n        getUnknownFields().writeTo(output);\n    }\n\n    @Override\n    public int getSerializedSize() {\n        int size = memoizedSize;\n        if (size != -1) {\n            return size;\n        }\n\n        size = 0;\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(revision_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, revision_);\n        }\n        size += getUnknownFields().getSerializedSize();\n        memoizedSize = size;\n        return size;\n    }\n\n    @Override\n    public boolean equals(final Object obj) {\n        if (obj == this) {\n            return true;\n        }\n        if (!(obj instanceof MetadataRequest)) {\n            return super.equals(obj);\n        }\n        MetadataRequest other = (MetadataRequest) obj;\n\n        if (!getRevision().equals(other.getRevision())) {\n            return false;\n        }\n        if (!getUnknownFields().equals(other.getUnknownFields())) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        if (memoizedHashCode != 0) {\n            return memoizedHashCode;\n        }\n        int hash = 41;\n        hash = (19 * hash) + getDescriptor().hashCode();\n        hash = (37 * hash) + REVISION_FIELD_NUMBER;\n        hash = (53 * hash) + getRevision().hashCode();\n        hash = (29 * hash) + getUnknownFields().hashCode();\n        memoizedHashCode = hash;\n        return hash;\n    }\n\n    public static MetadataRequest parseFrom(java.nio.ByteBuffer data)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static MetadataRequest parseFrom(\n            java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static MetadataRequest parseFrom(com.google.protobuf.ByteString data)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static MetadataRequest parseFrom(\n            com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static MetadataRequest parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static MetadataRequest parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static MetadataRequest parseFrom(java.io.InputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n    }\n\n    public static MetadataRequest parseFrom(\n            java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static MetadataRequest parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input);\n    }\n\n    public static MetadataRequest parseDelimitedFrom(\n            java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static MetadataRequest parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n    }\n\n    public static MetadataRequest parseFrom(\n            com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @Override\n    public Builder newBuilderForType() {\n        return newBuilder();\n    }\n\n    public static Builder newBuilder() {\n        return DEFAULT_INSTANCE.toBuilder();\n    }\n\n    public static Builder newBuilder(MetadataRequest prototype) {\n        return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n\n    @Override\n    public Builder toBuilder() {\n        return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @Override\n    protected Builder newBuilderForType(BuilderParent parent) {\n        Builder builder = new Builder(parent);\n        return builder;\n    }\n\n    /**\n     * <pre>\n     * Metadata request message.\n     * </pre>\n     *\n     * Protobuf type {@code org.apache.dubbo.metadata.MetadataRequest}\n     */\n    public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder<Builder>\n            implements\n            // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.MetadataRequest)\n            MetadataRequestOrBuilder {\n        public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataRequest_descriptor;\n        }\n\n        @Override\n        protected FieldAccessorTable internalGetFieldAccessorTable() {\n            return MetadataServiceV2OuterClass\n                    .internal_static_org_apache_dubbo_metadata_MetadataRequest_fieldAccessorTable\n                    .ensureFieldAccessorsInitialized(MetadataRequest.class, Builder.class);\n        }\n\n        // Construct using org.apache.dubbo.metadata.MetadataRequest.newBuilder()\n        private Builder() {}\n\n        private Builder(BuilderParent parent) {\n            super(parent);\n        }\n\n        @Override\n        public Builder clear() {\n            super.clear();\n            bitField0_ = 0;\n            revision_ = \"\";\n            return this;\n        }\n\n        @Override\n        public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataRequest_descriptor;\n        }\n\n        @Override\n        public MetadataRequest getDefaultInstanceForType() {\n            return MetadataRequest.getDefaultInstance();\n        }\n\n        @Override\n        public MetadataRequest build() {\n            MetadataRequest result = buildPartial();\n            if (!result.isInitialized()) {\n                throw newUninitializedMessageException(result);\n            }\n            return result;\n        }\n\n        @Override\n        public MetadataRequest buildPartial() {\n            MetadataRequest result = new MetadataRequest(this);\n            if (bitField0_ != 0) {\n                buildPartial0(result);\n            }\n            onBuilt();\n            return result;\n        }\n\n        private void buildPartial0(MetadataRequest result) {\n            int from_bitField0_ = bitField0_;\n            if (((from_bitField0_ & 0x00000001) != 0)) {\n                result.revision_ = revision_;\n            }\n        }\n\n        @Override\n        public Builder clone() {\n            return super.clone();\n        }\n\n        @Override\n        public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) {\n            return super.setField(field, value);\n        }\n\n        @Override\n        public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) {\n            return super.clearField(field);\n        }\n\n        @Override\n        public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n            return super.clearOneof(oneof);\n        }\n\n        @Override\n        public Builder setRepeatedField(\n                com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) {\n            return super.setRepeatedField(field, index, value);\n        }\n\n        @Override\n        public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) {\n            return super.addRepeatedField(field, value);\n        }\n\n        @Override\n        public Builder mergeFrom(com.google.protobuf.Message other) {\n            if (other instanceof MetadataRequest) {\n                return mergeFrom((MetadataRequest) other);\n            } else {\n                super.mergeFrom(other);\n                return this;\n            }\n        }\n\n        public Builder mergeFrom(MetadataRequest other) {\n            if (other == MetadataRequest.getDefaultInstance()) {\n                return this;\n            }\n            if (!other.getRevision().isEmpty()) {\n                revision_ = other.revision_;\n                bitField0_ |= 0x00000001;\n                onChanged();\n            }\n            this.mergeUnknownFields(other.getUnknownFields());\n            onChanged();\n            return this;\n        }\n\n        @Override\n        public final boolean isInitialized() {\n            return true;\n        }\n\n        @Override\n        public Builder mergeFrom(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            if (extensionRegistry == null) {\n                throw new NullPointerException();\n            }\n            try {\n                boolean done = false;\n                while (!done) {\n                    int tag = input.readTag();\n                    switch (tag) {\n                        case 0:\n                            done = true;\n                            break;\n                        case 10: {\n                            revision_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000001;\n                            break;\n                        } // case 10\n                        default: {\n                            if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                                done = true; // was an endgroup tag\n                            }\n                            break;\n                        } // default:\n                    } // switch (tag)\n                } // while (!done)\n            } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                throw e.unwrapIOException();\n            } finally {\n                onChanged();\n            } // finally\n            return this;\n        }\n\n        private int bitField0_;\n\n        private Object revision_ = \"\";\n\n        /**\n         * <pre>\n         * The revision of the metadata.\n         * </pre>\n         *\n         * <code>string revision = 1;</code>\n         * @return The revision.\n         */\n        public String getRevision() {\n            Object ref = revision_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                revision_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The revision of the metadata.\n         * </pre>\n         *\n         * <code>string revision = 1;</code>\n         * @return The bytes for revision.\n         */\n        public com.google.protobuf.ByteString getRevisionBytes() {\n            Object ref = revision_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                revision_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The revision of the metadata.\n         * </pre>\n         *\n         * <code>string revision = 1;</code>\n         * @param value The revision to set.\n         * @return This builder for chaining.\n         */\n        public Builder setRevision(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            revision_ = value;\n            bitField0_ |= 0x00000001;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The revision of the metadata.\n         * </pre>\n         *\n         * <code>string revision = 1;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearRevision() {\n            revision_ = getDefaultInstance().getRevision();\n            bitField0_ = (bitField0_ & ~0x00000001);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The revision of the metadata.\n         * </pre>\n         *\n         * <code>string revision = 1;</code>\n         * @param value The bytes for revision to set.\n         * @return This builder for chaining.\n         */\n        public Builder setRevisionBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            revision_ = value;\n            bitField0_ |= 0x00000001;\n            onChanged();\n            return this;\n        }\n\n        @Override\n        public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n            return super.setUnknownFields(unknownFields);\n        }\n\n        @Override\n        public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n            return super.mergeUnknownFields(unknownFields);\n        }\n\n        // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.MetadataRequest)\n    }\n\n    // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.MetadataRequest)\n    private static final MetadataRequest DEFAULT_INSTANCE;\n\n    static {\n        DEFAULT_INSTANCE = new MetadataRequest();\n    }\n\n    public static MetadataRequest getDefaultInstance() {\n        return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<MetadataRequest> PARSER =\n            new com.google.protobuf.AbstractParser<MetadataRequest>() {\n                @Override\n                public MetadataRequest parsePartialFrom(\n                        com.google.protobuf.CodedInputStream input,\n                        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                        throws com.google.protobuf.InvalidProtocolBufferException {\n                    Builder builder = newBuilder();\n                    try {\n                        builder.mergeFrom(input, extensionRegistry);\n                    } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                        throw e.setUnfinishedMessage(builder.buildPartial());\n                    } catch (com.google.protobuf.UninitializedMessageException e) {\n                        throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n                    } catch (java.io.IOException e) {\n                        throw new com.google.protobuf.InvalidProtocolBufferException(e)\n                                .setUnfinishedMessage(builder.buildPartial());\n                    }\n                    return builder.buildPartial();\n                }\n            };\n\n    public static com.google.protobuf.Parser<MetadataRequest> parser() {\n        return PARSER;\n    }\n\n    @Override\n    public com.google.protobuf.Parser<MetadataRequest> getParserForType() {\n        return PARSER;\n    }\n\n    @Override\n    public MetadataRequest getDefaultInstanceForType() {\n        return DEFAULT_INSTANCE;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequestOrBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\npublic interface MetadataRequestOrBuilder\n        extends\n        // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.MetadataRequest)\n        com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <pre>\n     * The revision of the metadata.\n     * </pre>\n     *\n     * <code>string revision = 1;</code>\n     * @return The revision.\n     */\n    String getRevision();\n\n    /**\n     * <pre>\n     * The revision of the metadata.\n     * </pre>\n     *\n     * <code>string revision = 1;</code>\n     * @return The bytes for revision.\n     */\n    com.google.protobuf.ByteString getRevisionBytes();\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.http12.rest.Mapping;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPI;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\nimport static java.util.Collections.unmodifiableSortedSet;\nimport static org.apache.dubbo.common.URL.buildKey;\nimport static org.apache.dubbo.rpc.Constants.H2_SETTINGS_OPENAPI_PREFIX;\n\n/**\n * This service is used to expose the metadata information inside a Dubbo process.\n * Typical uses include:\n * 1. The Consumer queries the metadata information of the Provider to list the interfaces and each interface's configuration\n * 2. The Console (dubbo-admin) queries for the metadata of a specific process, or aggregate data of all processes.\n */\n@OpenAPI(hidden = \"true\")\npublic interface MetadataService {\n\n    /**\n     * The value of All service instances\n     */\n    String ALL_SERVICE_INTERFACES = \"*\";\n\n    /**\n     * The contract version of {@link MetadataService}, the future update must make sure compatible.\n     */\n    String VERSION = \"1.0.0\";\n\n    /**\n     * Gets the current Dubbo Service name\n     *\n     * @return non-null\n     */\n    String serviceName();\n\n    /**\n     * Gets the version of {@link MetadataService} that always equals {@link #VERSION}\n     *\n     * @return non-null\n     * @see #VERSION\n     */\n    default String version() {\n        return VERSION;\n    }\n\n    URL getMetadataURL();\n\n    /**\n     * the list of String that presents all Dubbo subscribed {@link URL urls}\n     *\n     * @return the non-null read-only {@link SortedSet sorted set} of {@link URL#toFullString() strings} presenting the {@link URL URLs}\n     * @see #toSortedStrings(Stream)\n     * @see URL#toFullString()\n     */\n    default SortedSet<String> getSubscribedURLs() {\n        throw new UnsupportedOperationException(\"This operation is not supported for consumer.\");\n    }\n\n    /**\n     * Get the {@link SortedSet sorted set} of String that presents all Dubbo exported {@link URL urls}\n     *\n     * @return the non-null read-only {@link SortedSet sorted set} of {@link URL#toFullString() strings} presenting the {@link URL URLs}\n     * @see #toSortedStrings(Stream)\n     * @see URL#toFullString()\n     */\n    default SortedSet<String> getExportedURLs() {\n        return getExportedURLs(ALL_SERVICE_INTERFACES);\n    }\n\n    /**\n     * Get the {@link SortedSet sorted set} of String that presents the specified Dubbo exported {@link URL urls} by the <code>serviceInterface</code>\n     *\n     * @param serviceInterface The class name of Dubbo service interface\n     * @return the non-null read-only {@link SortedSet sorted set} of {@link URL#toFullString() strings} presenting the {@link URL URLs}\n     * @see #toSortedStrings(Stream)\n     * @see URL#toFullString()\n     */\n    default SortedSet<String> getExportedURLs(String serviceInterface) {\n        return getExportedURLs(serviceInterface, null);\n    }\n\n    /**\n     * Get the {@link SortedSet sorted set} of String that presents the specified Dubbo exported {@link URL urls} by the\n     * <code>serviceInterface</code> and <code>group</code>\n     *\n     * @param serviceInterface The class name of Dubbo service interface\n     * @param group            the Dubbo Service Group (optional)\n     * @return the non-null read-only {@link SortedSet sorted set} of {@link URL#toFullString() strings} presenting the {@link URL URLs}\n     * @see #toSortedStrings(Stream)\n     * @see URL#toFullString()\n     */\n    default SortedSet<String> getExportedURLs(String serviceInterface, String group) {\n        return getExportedURLs(serviceInterface, group, null);\n    }\n\n    /**\n     * Get the {@link SortedSet sorted set} of String that presents the specified Dubbo exported {@link URL urls} by the\n     * <code>serviceInterface</code>, <code>group</code> and <code>version</code>\n     *\n     * @param serviceInterface The class name of Dubbo service interface\n     * @param group            the Dubbo Service Group (optional)\n     * @param version          the Dubbo Service Version (optional)\n     * @return the non-null read-only {@link SortedSet sorted set} of {@link URL#toFullString() strings} presenting the {@link URL URLs}\n     * @see #toSortedStrings(Stream)\n     * @see URL#toFullString()\n     */\n    default SortedSet<String> getExportedURLs(String serviceInterface, String group, String version) {\n        return getExportedURLs(serviceInterface, group, version, null);\n    }\n\n    /**\n     * Get the sorted set of String that presents the specified Dubbo exported {@link URL urls} by the\n     * <code>serviceInterface</code>, <code>group</code>, <code>version</code> and <code>protocol</code>\n     *\n     * @param serviceInterface The class name of Dubbo service interface\n     * @param group            the Dubbo Service Group (optional)\n     * @param version          the Dubbo Service Version (optional)\n     * @param protocol         the Dubbo Service Protocol (optional)\n     * @return the non-null read-only {@link SortedSet sorted set} of {@link URL#toFullString() strings} presenting the {@link URL URLs}\n     * @see #toSortedStrings(Stream)\n     * @see URL#toFullString()\n     */\n    SortedSet<String> getExportedURLs(String serviceInterface, String group, String version, String protocol);\n\n    default Set<URL> getExportedServiceURLs() {\n        return Collections.emptySet();\n    }\n\n    /**\n     * Interface definition.\n     *\n     * @return\n     */\n    default String getServiceDefinition(String interfaceName, String version, String group) {\n        return getServiceDefinition(buildKey(interfaceName, group, version));\n    }\n\n    String getServiceDefinition(String serviceKey);\n\n    MetadataInfo getMetadataInfo(String revision);\n\n    List<MetadataInfo> getMetadataInfos();\n\n    /**\n     * Convert the specified {@link Iterable} of {@link URL URLs} to be the {@link URL#toFullString() strings} presenting\n     * the {@link URL URLs}\n     *\n     * @param iterable {@link Iterable} of {@link URL}\n     * @return the non-null read-only {@link SortedSet sorted set} of {@link URL#toFullString() strings} presenting\n     * @see URL#toFullString()\n     */\n    static SortedSet<String> toSortedStrings(Iterable<URL> iterable) {\n        return toSortedStrings(StreamSupport.stream(iterable.spliterator(), false));\n    }\n\n    /**\n     * Convert the specified {@link Stream} of {@link URL URLs} to be the {@link URL#toFullString() strings} presenting\n     * the {@link URL URLs}\n     *\n     * @param stream {@link Stream} of {@link URL}\n     * @return the non-null read-only {@link SortedSet sorted set} of {@link URL#toFullString() strings} presenting\n     * @see URL#toFullString()\n     */\n    static SortedSet<String> toSortedStrings(Stream<URL> stream) {\n        return unmodifiableSortedSet(stream.map(URL::toFullString).collect(TreeSet::new, Set::add, Set::addAll));\n    }\n\n    static boolean isMetadataService(String interfaceName) {\n        return interfaceName != null && interfaceName.equals(MetadataService.class.getName());\n    }\n\n    /**\n     * Export Metadata in Service Instance of Service Discovery\n     * <p>\n     * Used for consumer to get Service Instance Metadata\n     * if Registry is unsupported with publishing metadata\n     *\n     * @param instanceMetadata {@link Map} of provider Service Instance Metadata\n     * @since 3.0\n     */\n    @Mapping(enabled = false)\n    void exportInstanceMetadata(String instanceMetadata);\n\n    /**\n     * Get all Metadata listener from local\n     * <p>\n     * Used for consumer to get Service Instance Metadata\n     * if Registry is unsupported with publishing metadata\n     *\n     * @return {@link Map} of {@link InstanceMetadataChangedListener}\n     * @since 3.0\n     */\n    @Mapping(enabled = false)\n    Map<String, InstanceMetadataChangedListener> getInstanceMetadataChangedListenerMap();\n\n    /**\n     * 1. Fetch Metadata in Service Instance of Service Discovery\n     * 2. Add a metadata change listener\n     * <p>\n     * Used for consumer to get Service Instance Metadata\n     * if Registry is unsupported with publishing metadata\n     *\n     * @param consumerId consumerId\n     * @param listener   {@link InstanceMetadataChangedListener} used to notify event\n     * @return {@link Map} of provider Service Instance Metadata\n     * @since 3.0\n     */\n    @Mapping(enabled = false)\n    String getAndListenInstanceMetadata(String consumerId, InstanceMetadataChangedListener listener);\n\n    /**\n     * 1. Get the openAPI definition\n     */\n    @Mapping(\"//${\" + H2_SETTINGS_OPENAPI_PREFIX + \".path:dubbo/openapi}/{*path}\")\n    String getOpenAPI(OpenAPIRequest request);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceDetector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.rpc.model.BuiltinServiceDetector;\n\npublic class MetadataServiceDetector implements BuiltinServiceDetector {\n\n    @Override\n    public Class<?> getService() {\n        return MetadataService.class;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic interface MetadataServiceV2 extends org.apache.dubbo.rpc.model.DubboStub {\n\n    String JAVA_SERVICE_NAME = \"org.apache.dubbo.metadata.MetadataServiceV2\";\n    String SERVICE_NAME = \"org.apache.dubbo.metadata.MetadataServiceV2\";\n\n    /**\n     * <pre>\n     *  Retrieves metadata information.\n     * </pre>\n     */\n    MetadataInfoV2 getMetadataInfo(MetadataRequest request);\n\n    CompletableFuture<MetadataInfoV2> getMetadataInfoAsync(MetadataRequest request);\n\n    /**\n     * <pre>\n     *  Retrieves OpenAPI information.\n     * </pre>\n     */\n    OpenAPIInfo getOpenAPIInfo(OpenAPIRequest request);\n\n    CompletableFuture<OpenAPIInfo> getOpenAPIInfoAsync(OpenAPIRequest request);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2Detector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.rpc.model.BuiltinServiceDetector;\n\npublic class MetadataServiceV2Detector implements BuiltinServiceDetector {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(MetadataServiceV2Detector.class);\n\n    public static final String NAME = \"metadataV2\";\n\n    @Override\n    public Class<?> getService() {\n        if (ClassUtils.hasProtobuf()) {\n            return MetadataServiceV2.class;\n        }\n        logger.info(\"To use MetadataServiceV2, Protobuf dependencies are required. Fallback to MetadataService(V1).\");\n        return null;\n    }\n\n    public static boolean support() {\n        return ClassUtils.hasProtobuf();\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\npublic final class MetadataServiceV2OuterClass {\n    private MetadataServiceV2OuterClass() {}\n\n    public static void registerAllExtensions(com.google.protobuf.ExtensionRegistryLite registry) {}\n\n    public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry) {\n        registerAllExtensions((com.google.protobuf.ExtensionRegistryLite) registry);\n    }\n\n    static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_MetadataRequest_descriptor;\n    static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_MetadataRequest_fieldAccessorTable;\n    static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_MetadataInfoV2_descriptor;\n    static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_MetadataInfoV2_fieldAccessorTable;\n    static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_MetadataInfoV2_ServicesEntry_descriptor;\n    static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_MetadataInfoV2_ServicesEntry_fieldAccessorTable;\n    static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_ServiceInfoV2_descriptor;\n    static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_ServiceInfoV2_fieldAccessorTable;\n    static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_descriptor;\n    static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_fieldAccessorTable;\n    static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor;\n    static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable;\n    static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor;\n    static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable;\n\n    public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() {\n        return descriptor;\n    }\n\n    private static com.google.protobuf.Descriptors.FileDescriptor descriptor;\n\n    static {\n        String[] descriptorData = {\n            \"\\n\\031metadata_service_v2.proto\\022\\031org.apache.\"\n                    + \"dubbo.metadata\\\"#\\n\\017MetadataRequest\\022\\020\\n\\010rev\"\n                    + \"ision\\030\\001 \\001(\\t\\\"\\324\\001\\n\\016MetadataInfoV2\\022\\013\\n\\003app\\030\\001 \"\n                    + \"\\001(\\t\\022\\017\\n\\007version\\030\\002 \\001(\\t\\022I\\n\\010services\\030\\003 \\003(\\01327\"\n                    + \".org.apache.dubbo.metadata.MetadataInfoV\"\n                    + \"2.ServicesEntry\\032Y\\n\\rServicesEntry\\022\\013\\n\\003key\\030\"\n                    + \"\\001 \\001(\\t\\0227\\n\\005value\\030\\002 \\001(\\0132(.org.apache.dubbo.\"\n                    + \"metadata.ServiceInfoV2:\\0028\\001\\\"\\340\\001\\n\\rServiceIn\"\n                    + \"foV2\\022\\014\\n\\004name\\030\\001 \\001(\\t\\022\\r\\n\\005group\\030\\002 \\001(\\t\\022\\017\\n\\007ver\"\n                    + \"sion\\030\\003 \\001(\\t\\022\\020\\n\\010protocol\\030\\004 \\001(\\t\\022\\014\\n\\004port\\030\\005 \\001\"\n                    + \"(\\005\\022\\014\\n\\004path\\030\\006 \\001(\\t\\022D\\n\\006params\\030\\007 \\003(\\01324.org.a\"\n                    + \"pache.dubbo.metadata.ServiceInfoV2.Param\"\n                    + \"sEntry\\032-\\n\\013ParamsEntry\\022\\013\\n\\003key\\030\\001 \\001(\\t\\022\\r\\n\\005va\"\n                    + \"lue\\030\\002 \\001(\\t:\\0028\\001\\\"\\311\\001\\n\\016OpenAPIRequest\\022\\r\\n\\005grou\"\n                    + \"p\\030\\001 \\001(\\t\\022\\017\\n\\007version\\030\\002 \\001(\\t\\022\\013\\n\\003tag\\030\\003 \\003(\\t\\022\\017\\n\"\n                    + \"\\007service\\030\\004 \\003(\\t\\022\\017\\n\\007openapi\\030\\005 \\001(\\t\\022=\\n\\006forma\"\n                    + \"t\\030\\006 \\001(\\0162(.org.apache.dubbo.metadata.Open\"\n                    + \"APIFormatH\\000\\210\\001\\001\\022\\023\\n\\006pretty\\030\\007 \\001(\\010H\\001\\210\\001\\001B\\t\\n\\007_\"\n                    + \"formatB\\t\\n\\007_pretty\\\"!\\n\\013OpenAPIInfo\\022\\022\\n\\ndefi\"\n                    + \"nition\\030\\001 \\001(\\t*.\\n\\rOpenAPIFormat\\022\\010\\n\\004JSON\\020\\000\\022\"\n                    + \"\\010\\n\\004YAML\\020\\001\\022\\t\\n\\005PROTO\\020\\0022\\342\\001\\n\\021MetadataService\"\n                    + \"V2\\022h\\n\\017GetMetadataInfo\\022*.org.apache.dubbo\"\n                    + \".metadata.MetadataRequest\\032).org.apache.d\"\n                    + \"ubbo.metadata.MetadataInfoV2\\022c\\n\\016GetOpenA\"\n                    + \"PIInfo\\022).org.apache.dubbo.metadata.OpenA\"\n                    + \"PIRequest\\032&.org.apache.dubbo.metadata.Op\"\n                    + \"enAPIInfoBZ\\n\\031org.apache.dubbo.metadataP\\001\"\n                    + \"Z;dubbo.apache.org/dubbo-go/v3/metadata/\"\n                    + \"triple_api;triple_apib\\006proto3\"\n        };\n        descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom(\n                descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] {});\n        internal_static_org_apache_dubbo_metadata_MetadataRequest_descriptor =\n                getDescriptor().getMessageTypes().get(0);\n        internal_static_org_apache_dubbo_metadata_MetadataRequest_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_MetadataRequest_descriptor, new String[] {\n                            \"Revision\",\n                        });\n        internal_static_org_apache_dubbo_metadata_MetadataInfoV2_descriptor =\n                getDescriptor().getMessageTypes().get(1);\n        internal_static_org_apache_dubbo_metadata_MetadataInfoV2_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_MetadataInfoV2_descriptor, new String[] {\n                            \"App\", \"Version\", \"Services\",\n                        });\n        internal_static_org_apache_dubbo_metadata_MetadataInfoV2_ServicesEntry_descriptor =\n                internal_static_org_apache_dubbo_metadata_MetadataInfoV2_descriptor\n                        .getNestedTypes()\n                        .get(0);\n        internal_static_org_apache_dubbo_metadata_MetadataInfoV2_ServicesEntry_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_MetadataInfoV2_ServicesEntry_descriptor,\n                        new String[] {\n                            \"Key\", \"Value\",\n                        });\n        internal_static_org_apache_dubbo_metadata_ServiceInfoV2_descriptor =\n                getDescriptor().getMessageTypes().get(2);\n        internal_static_org_apache_dubbo_metadata_ServiceInfoV2_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_ServiceInfoV2_descriptor, new String[] {\n                            \"Name\", \"Group\", \"Version\", \"Protocol\", \"Port\", \"Path\", \"Params\",\n                        });\n        internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_descriptor =\n                internal_static_org_apache_dubbo_metadata_ServiceInfoV2_descriptor\n                        .getNestedTypes()\n                        .get(0);\n        internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_descriptor, new String[] {\n                            \"Key\", \"Value\",\n                        });\n        internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor =\n                getDescriptor().getMessageTypes().get(3);\n        internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor, new String[] {\n                            \"Group\", \"Version\", \"Tag\", \"Service\", \"Openapi\", \"Format\", \"Pretty\", \"Format\", \"Pretty\",\n                        });\n        internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor =\n                getDescriptor().getMessageTypes().get(4);\n        internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor, new String[] {\n                            \"Definition\",\n                        });\n    }\n\n    // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIFormat.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\n/**\n * <pre>\n * Response format enumeration.\n * </pre>\n *\n * Protobuf enum {@code org.apache.dubbo.metadata.OpenAPIFormat}\n */\npublic enum OpenAPIFormat implements com.google.protobuf.ProtocolMessageEnum {\n    /**\n     * <pre>\n     * JSON format.\n     * </pre>\n     *\n     * <code>JSON = 0;</code>\n     */\n    JSON(0),\n    /**\n     * <pre>\n     * YAML format.\n     * </pre>\n     *\n     * <code>YAML = 1;</code>\n     */\n    YAML(1),\n    /**\n     * <pre>\n     * PROTO format.\n     * </pre>\n     *\n     * <code>PROTO = 2;</code>\n     */\n    PROTO(2),\n    UNRECOGNIZED(-1),\n    ;\n\n    /**\n     * <pre>\n     * JSON format.\n     * </pre>\n     *\n     * <code>JSON = 0;</code>\n     */\n    public static final int JSON_VALUE = 0;\n    /**\n     * <pre>\n     * YAML format.\n     * </pre>\n     *\n     * <code>YAML = 1;</code>\n     */\n    public static final int YAML_VALUE = 1;\n    /**\n     * <pre>\n     * PROTO format.\n     * </pre>\n     *\n     * <code>PROTO = 2;</code>\n     */\n    public static final int PROTO_VALUE = 2;\n\n    public final int getNumber() {\n        if (this == UNRECOGNIZED) {\n            throw new IllegalArgumentException(\"Can't get the number of an unknown enum value.\");\n        }\n        return value;\n    }\n\n    /**\n     * @param value The numeric wire value of the corresponding enum entry.\n     * @return The enum associated with the given numeric wire value.\n     * @deprecated Use {@link #forNumber(int)} instead.\n     */\n    @Deprecated\n    public static OpenAPIFormat valueOf(int value) {\n        return forNumber(value);\n    }\n\n    /**\n     * @param value The numeric wire value of the corresponding enum entry.\n     * @return The enum associated with the given numeric wire value.\n     */\n    public static OpenAPIFormat forNumber(int value) {\n        switch (value) {\n            case 0:\n                return JSON;\n            case 1:\n                return YAML;\n            case 2:\n                return PROTO;\n            default:\n                return null;\n        }\n    }\n\n    public static com.google.protobuf.Internal.EnumLiteMap<OpenAPIFormat> internalGetValueMap() {\n        return internalValueMap;\n    }\n\n    private static final com.google.protobuf.Internal.EnumLiteMap<OpenAPIFormat> internalValueMap =\n            new com.google.protobuf.Internal.EnumLiteMap<OpenAPIFormat>() {\n                public OpenAPIFormat findValueByNumber(int number) {\n                    return OpenAPIFormat.forNumber(number);\n                }\n            };\n\n    public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() {\n        if (this == UNRECOGNIZED) {\n            throw new IllegalStateException(\"Can't get the descriptor of an unrecognized enum value.\");\n        }\n        return getDescriptor().getValues().get(ordinal());\n    }\n\n    public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() {\n        return getDescriptor();\n    }\n\n    public static final com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() {\n        return MetadataServiceV2OuterClass.getDescriptor().getEnumTypes().get(0);\n    }\n\n    private static final OpenAPIFormat[] VALUES = values();\n\n    public static OpenAPIFormat valueOf(com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n        if (desc.getType() != getDescriptor()) {\n            throw new IllegalArgumentException(\"EnumValueDescriptor is not for this type.\");\n        }\n        if (desc.getIndex() == -1) {\n            return UNRECOGNIZED;\n        }\n        return VALUES[desc.getIndex()];\n    }\n\n    private final int value;\n\n    private OpenAPIFormat(int value) {\n        this.value = value;\n    }\n\n    // @@protoc_insertion_point(enum_scope:org.apache.dubbo.metadata.OpenAPIFormat)\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\n/**\n * <pre>\n * OpenAPI information message.\n * </pre>\n *\n * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIInfo}\n */\npublic final class OpenAPIInfo extends com.google.protobuf.GeneratedMessageV3\n        implements\n        // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.OpenAPIInfo)\n        OpenAPIInfoOrBuilder {\n    private static final long serialVersionUID = 0L;\n\n    // Use OpenAPIInfo.newBuilder() to construct.\n    private OpenAPIInfo(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n        super(builder);\n    }\n\n    private OpenAPIInfo() {\n        definition_ = \"\";\n    }\n\n    @Override\n    @SuppressWarnings({\"unused\"})\n    protected Object newInstance(UnusedPrivateParameter unused) {\n        return new OpenAPIInfo();\n    }\n\n    public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n        return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor;\n    }\n\n    @Override\n    protected FieldAccessorTable internalGetFieldAccessorTable() {\n        return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable\n                .ensureFieldAccessorsInitialized(OpenAPIInfo.class, Builder.class);\n    }\n\n    public static final int DEFINITION_FIELD_NUMBER = 1;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object definition_ = \"\";\n\n    /**\n     * <pre>\n     * The OpenAPI definition.\n     * </pre>\n     *\n     * <code>string definition = 1;</code>\n     * @return The definition.\n     */\n    @Override\n    public String getDefinition() {\n        Object ref = definition_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            definition_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The OpenAPI definition.\n     * </pre>\n     *\n     * <code>string definition = 1;</code>\n     * @return The bytes for definition.\n     */\n    @Override\n    public com.google.protobuf.ByteString getDefinitionBytes() {\n        Object ref = definition_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            definition_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    private byte memoizedIsInitialized = -1;\n\n    @Override\n    public final boolean isInitialized() {\n        byte isInitialized = memoizedIsInitialized;\n        if (isInitialized == 1) {\n            return true;\n        }\n        if (isInitialized == 0) {\n            return false;\n        }\n\n        memoizedIsInitialized = 1;\n        return true;\n    }\n\n    @Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(definition_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 1, definition_);\n        }\n        getUnknownFields().writeTo(output);\n    }\n\n    @Override\n    public int getSerializedSize() {\n        int size = memoizedSize;\n        if (size != -1) {\n            return size;\n        }\n\n        size = 0;\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(definition_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, definition_);\n        }\n        size += getUnknownFields().getSerializedSize();\n        memoizedSize = size;\n        return size;\n    }\n\n    @Override\n    public boolean equals(final Object obj) {\n        if (obj == this) {\n            return true;\n        }\n        if (!(obj instanceof OpenAPIInfo)) {\n            return super.equals(obj);\n        }\n        OpenAPIInfo other = (OpenAPIInfo) obj;\n\n        if (!getDefinition().equals(other.getDefinition())) {\n            return false;\n        }\n        if (!getUnknownFields().equals(other.getUnknownFields())) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        if (memoizedHashCode != 0) {\n            return memoizedHashCode;\n        }\n        int hash = 41;\n        hash = (19 * hash) + getDescriptor().hashCode();\n        hash = (37 * hash) + DEFINITION_FIELD_NUMBER;\n        hash = (53 * hash) + getDefinition().hashCode();\n        hash = (29 * hash) + getUnknownFields().hashCode();\n        memoizedHashCode = hash;\n        return hash;\n    }\n\n    public static OpenAPIInfo parseFrom(java.nio.ByteBuffer data)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static OpenAPIInfo parseFrom(\n            java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static OpenAPIInfo parseFrom(com.google.protobuf.ByteString data)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static OpenAPIInfo parseFrom(\n            com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static OpenAPIInfo parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static OpenAPIInfo parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static OpenAPIInfo parseFrom(java.io.InputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n    }\n\n    public static OpenAPIInfo parseFrom(\n            java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static OpenAPIInfo parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input);\n    }\n\n    public static OpenAPIInfo parseDelimitedFrom(\n            java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static OpenAPIInfo parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n    }\n\n    public static OpenAPIInfo parseFrom(\n            com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @Override\n    public Builder newBuilderForType() {\n        return newBuilder();\n    }\n\n    public static Builder newBuilder() {\n        return DEFAULT_INSTANCE.toBuilder();\n    }\n\n    public static Builder newBuilder(OpenAPIInfo prototype) {\n        return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n\n    @Override\n    public Builder toBuilder() {\n        return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @Override\n    protected Builder newBuilderForType(BuilderParent parent) {\n        Builder builder = new Builder(parent);\n        return builder;\n    }\n\n    /**\n     * <pre>\n     * OpenAPI information message.\n     * </pre>\n     *\n     * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIInfo}\n     */\n    public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder<Builder>\n            implements\n            // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.OpenAPIInfo)\n            OpenAPIInfoOrBuilder {\n        public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor;\n        }\n\n        @Override\n        protected FieldAccessorTable internalGetFieldAccessorTable() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable\n                    .ensureFieldAccessorsInitialized(OpenAPIInfo.class, Builder.class);\n        }\n\n        // Construct using org.apache.dubbo.metadata.OpenAPIInfo.newBuilder()\n        private Builder() {}\n\n        private Builder(BuilderParent parent) {\n            super(parent);\n        }\n\n        @Override\n        public Builder clear() {\n            super.clear();\n            bitField0_ = 0;\n            definition_ = \"\";\n            return this;\n        }\n\n        @Override\n        public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor;\n        }\n\n        @Override\n        public OpenAPIInfo getDefaultInstanceForType() {\n            return OpenAPIInfo.getDefaultInstance();\n        }\n\n        @Override\n        public OpenAPIInfo build() {\n            OpenAPIInfo result = buildPartial();\n            if (!result.isInitialized()) {\n                throw newUninitializedMessageException(result);\n            }\n            return result;\n        }\n\n        @Override\n        public OpenAPIInfo buildPartial() {\n            OpenAPIInfo result = new OpenAPIInfo(this);\n            if (bitField0_ != 0) {\n                buildPartial0(result);\n            }\n            onBuilt();\n            return result;\n        }\n\n        private void buildPartial0(OpenAPIInfo result) {\n            int from_bitField0_ = bitField0_;\n            if (((from_bitField0_ & 0x00000001) != 0)) {\n                result.definition_ = definition_;\n            }\n        }\n\n        @Override\n        public Builder clone() {\n            return super.clone();\n        }\n\n        @Override\n        public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) {\n            return super.setField(field, value);\n        }\n\n        @Override\n        public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) {\n            return super.clearField(field);\n        }\n\n        @Override\n        public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n            return super.clearOneof(oneof);\n        }\n\n        @Override\n        public Builder setRepeatedField(\n                com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) {\n            return super.setRepeatedField(field, index, value);\n        }\n\n        @Override\n        public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) {\n            return super.addRepeatedField(field, value);\n        }\n\n        @Override\n        public Builder mergeFrom(com.google.protobuf.Message other) {\n            if (other instanceof OpenAPIInfo) {\n                return mergeFrom((OpenAPIInfo) other);\n            } else {\n                super.mergeFrom(other);\n                return this;\n            }\n        }\n\n        public Builder mergeFrom(OpenAPIInfo other) {\n            if (other == OpenAPIInfo.getDefaultInstance()) {\n                return this;\n            }\n            if (!other.getDefinition().isEmpty()) {\n                definition_ = other.definition_;\n                bitField0_ |= 0x00000001;\n                onChanged();\n            }\n            this.mergeUnknownFields(other.getUnknownFields());\n            onChanged();\n            return this;\n        }\n\n        @Override\n        public final boolean isInitialized() {\n            return true;\n        }\n\n        @Override\n        public Builder mergeFrom(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            if (extensionRegistry == null) {\n                throw new NullPointerException();\n            }\n            try {\n                boolean done = false;\n                while (!done) {\n                    int tag = input.readTag();\n                    switch (tag) {\n                        case 0:\n                            done = true;\n                            break;\n                        case 10: {\n                            definition_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000001;\n                            break;\n                        } // case 10\n                        default: {\n                            if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                                done = true; // was an endgroup tag\n                            }\n                            break;\n                        } // default:\n                    } // switch (tag)\n                } // while (!done)\n            } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                throw e.unwrapIOException();\n            } finally {\n                onChanged();\n            } // finally\n            return this;\n        }\n\n        private int bitField0_;\n\n        private Object definition_ = \"\";\n\n        /**\n         * <pre>\n         * The OpenAPI definition.\n         * </pre>\n         *\n         * <code>string definition = 1;</code>\n         * @return The definition.\n         */\n        public String getDefinition() {\n            Object ref = definition_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                definition_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The OpenAPI definition.\n         * </pre>\n         *\n         * <code>string definition = 1;</code>\n         * @return The bytes for definition.\n         */\n        public com.google.protobuf.ByteString getDefinitionBytes() {\n            Object ref = definition_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                definition_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The OpenAPI definition.\n         * </pre>\n         *\n         * <code>string definition = 1;</code>\n         * @param value The definition to set.\n         * @return This builder for chaining.\n         */\n        public Builder setDefinition(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            definition_ = value;\n            bitField0_ |= 0x00000001;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The OpenAPI definition.\n         * </pre>\n         *\n         * <code>string definition = 1;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearDefinition() {\n            definition_ = getDefaultInstance().getDefinition();\n            bitField0_ = (bitField0_ & ~0x00000001);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The OpenAPI definition.\n         * </pre>\n         *\n         * <code>string definition = 1;</code>\n         * @param value The bytes for definition to set.\n         * @return This builder for chaining.\n         */\n        public Builder setDefinitionBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            definition_ = value;\n            bitField0_ |= 0x00000001;\n            onChanged();\n            return this;\n        }\n\n        @Override\n        public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n            return super.setUnknownFields(unknownFields);\n        }\n\n        @Override\n        public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n            return super.mergeUnknownFields(unknownFields);\n        }\n\n        // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.OpenAPIInfo)\n    }\n\n    // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.OpenAPIInfo)\n    private static final OpenAPIInfo DEFAULT_INSTANCE;\n\n    static {\n        DEFAULT_INSTANCE = new OpenAPIInfo();\n    }\n\n    public static OpenAPIInfo getDefaultInstance() {\n        return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<OpenAPIInfo> PARSER =\n            new com.google.protobuf.AbstractParser<OpenAPIInfo>() {\n                @Override\n                public OpenAPIInfo parsePartialFrom(\n                        com.google.protobuf.CodedInputStream input,\n                        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                        throws com.google.protobuf.InvalidProtocolBufferException {\n                    Builder builder = newBuilder();\n                    try {\n                        builder.mergeFrom(input, extensionRegistry);\n                    } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                        throw e.setUnfinishedMessage(builder.buildPartial());\n                    } catch (com.google.protobuf.UninitializedMessageException e) {\n                        throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n                    } catch (java.io.IOException e) {\n                        throw new com.google.protobuf.InvalidProtocolBufferException(e)\n                                .setUnfinishedMessage(builder.buildPartial());\n                    }\n                    return builder.buildPartial();\n                }\n            };\n\n    public static com.google.protobuf.Parser<OpenAPIInfo> parser() {\n        return PARSER;\n    }\n\n    @Override\n    public com.google.protobuf.Parser<OpenAPIInfo> getParserForType() {\n        return PARSER;\n    }\n\n    @Override\n    public OpenAPIInfo getDefaultInstanceForType() {\n        return DEFAULT_INSTANCE;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfoOrBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\npublic interface OpenAPIInfoOrBuilder\n        extends\n        // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.OpenAPIInfo)\n        com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <pre>\n     * The OpenAPI definition.\n     * </pre>\n     *\n     * <code>string definition = 1;</code>\n     * @return The definition.\n     */\n    String getDefinition();\n\n    /**\n     * <pre>\n     * The OpenAPI definition.\n     * </pre>\n     *\n     * <code>string definition = 1;</code>\n     * @return The bytes for definition.\n     */\n    com.google.protobuf.ByteString getDefinitionBytes();\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\n/**\n * <pre>\n * OpenAPI request message.\n * </pre>\n *\n * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIRequest}\n */\npublic final class OpenAPIRequest extends com.google.protobuf.GeneratedMessageV3\n        implements\n        // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.OpenAPIRequest)\n        OpenAPIRequestOrBuilder {\n    private static final long serialVersionUID = 0L;\n\n    // Use OpenAPIRequest.newBuilder() to construct.\n    private OpenAPIRequest(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n        super(builder);\n    }\n\n    private OpenAPIRequest() {\n        group_ = \"\";\n        version_ = \"\";\n        tag_ = com.google.protobuf.LazyStringArrayList.emptyList();\n        service_ = com.google.protobuf.LazyStringArrayList.emptyList();\n        openapi_ = \"\";\n        format_ = 0;\n    }\n\n    @Override\n    @SuppressWarnings({\"unused\"})\n    protected Object newInstance(UnusedPrivateParameter unused) {\n        return new OpenAPIRequest();\n    }\n\n    public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n        return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor;\n    }\n\n    @Override\n    protected FieldAccessorTable internalGetFieldAccessorTable() {\n        return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable\n                .ensureFieldAccessorsInitialized(OpenAPIRequest.class, Builder.class);\n    }\n\n    private int bitField0_;\n    public static final int GROUP_FIELD_NUMBER = 1;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object group_ = \"\";\n\n    /**\n     * <pre>\n     * The openAPI group.\n     * </pre>\n     *\n     * <code>string group = 1;</code>\n     * @return The group.\n     */\n    @Override\n    public String getGroup() {\n        Object ref = group_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            group_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The openAPI group.\n     * </pre>\n     *\n     * <code>string group = 1;</code>\n     * @return The bytes for group.\n     */\n    @Override\n    public com.google.protobuf.ByteString getGroupBytes() {\n        Object ref = group_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            group_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    public static final int VERSION_FIELD_NUMBER = 2;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object version_ = \"\";\n\n    /**\n     * <pre>\n     * The openAPI version, using a major.minor.patch versioning scheme\n     * e.g. 1.0.1\n     * </pre>\n     *\n     * <code>string version = 2;</code>\n     * @return The version.\n     */\n    @Override\n    public String getVersion() {\n        Object ref = version_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            version_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The openAPI version, using a major.minor.patch versioning scheme\n     * e.g. 1.0.1\n     * </pre>\n     *\n     * <code>string version = 2;</code>\n     * @return The bytes for version.\n     */\n    @Override\n    public com.google.protobuf.ByteString getVersionBytes() {\n        Object ref = version_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            version_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    public static final int TAG_FIELD_NUMBER = 3;\n\n    @SuppressWarnings(\"serial\")\n    private com.google.protobuf.LazyStringArrayList tag_ = com.google.protobuf.LazyStringArrayList.emptyList();\n\n    /**\n     * <pre>\n     * The openAPI tags. Each tag is an or condition.\n     * </pre>\n     *\n     * <code>repeated string tag = 3;</code>\n     * @return A list containing the tag.\n     */\n    public com.google.protobuf.ProtocolStringList getTagList() {\n        return tag_;\n    }\n\n    /**\n     * <pre>\n     * The openAPI tags. Each tag is an or condition.\n     * </pre>\n     *\n     * <code>repeated string tag = 3;</code>\n     * @return The count of tag.\n     */\n    public int getTagCount() {\n        return tag_.size();\n    }\n\n    /**\n     * <pre>\n     * The openAPI tags. Each tag is an or condition.\n     * </pre>\n     *\n     * <code>repeated string tag = 3;</code>\n     * @param index The index of the element to return.\n     * @return The tag at the given index.\n     */\n    public String getTag(int index) {\n        return tag_.get(index);\n    }\n\n    /**\n     * <pre>\n     * The openAPI tags. Each tag is an or condition.\n     * </pre>\n     *\n     * <code>repeated string tag = 3;</code>\n     * @param index The index of the value to return.\n     * @return The bytes of the tag at the given index.\n     */\n    public com.google.protobuf.ByteString getTagBytes(int index) {\n        return tag_.getByteString(index);\n    }\n\n    public static final int SERVICE_FIELD_NUMBER = 4;\n\n    @SuppressWarnings(\"serial\")\n    private com.google.protobuf.LazyStringArrayList service_ = com.google.protobuf.LazyStringArrayList.emptyList();\n\n    /**\n     * <pre>\n     * The openAPI services. Each service is an or condition.\n     * </pre>\n     *\n     * <code>repeated string service = 4;</code>\n     * @return A list containing the service.\n     */\n    public com.google.protobuf.ProtocolStringList getServiceList() {\n        return service_;\n    }\n\n    /**\n     * <pre>\n     * The openAPI services. Each service is an or condition.\n     * </pre>\n     *\n     * <code>repeated string service = 4;</code>\n     * @return The count of service.\n     */\n    public int getServiceCount() {\n        return service_.size();\n    }\n\n    /**\n     * <pre>\n     * The openAPI services. Each service is an or condition.\n     * </pre>\n     *\n     * <code>repeated string service = 4;</code>\n     * @param index The index of the element to return.\n     * @return The service at the given index.\n     */\n    public String getService(int index) {\n        return service_.get(index);\n    }\n\n    /**\n     * <pre>\n     * The openAPI services. Each service is an or condition.\n     * </pre>\n     *\n     * <code>repeated string service = 4;</code>\n     * @param index The index of the value to return.\n     * @return The bytes of the service at the given index.\n     */\n    public com.google.protobuf.ByteString getServiceBytes(int index) {\n        return service_.getByteString(index);\n    }\n\n    public static final int OPENAPI_FIELD_NUMBER = 5;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object openapi_ = \"\";\n\n    /**\n     * <pre>\n     * The openAPI specification version, using a major.minor.patch versioning scheme\n     * e.g. 3.0.1, 3.1.0\n     * The default value is '3.0.1'.\n     * </pre>\n     *\n     * <code>string openapi = 5;</code>\n     * @return The openapi.\n     */\n    @Override\n    public String getOpenapi() {\n        Object ref = openapi_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            openapi_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The openAPI specification version, using a major.minor.patch versioning scheme\n     * e.g. 3.0.1, 3.1.0\n     * The default value is '3.0.1'.\n     * </pre>\n     *\n     * <code>string openapi = 5;</code>\n     * @return The bytes for openapi.\n     */\n    @Override\n    public com.google.protobuf.ByteString getOpenapiBytes() {\n        Object ref = openapi_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            openapi_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    public static final int FORMAT_FIELD_NUMBER = 6;\n    private int format_ = 0;\n\n    /**\n     * <pre>\n     * The format of the response.\n     * The default value is 'JSON'.\n     * </pre>\n     *\n     * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n     * @return Whether the format field is set.\n     */\n    @Override\n    public boolean hasFormat() {\n        return ((bitField0_ & 0x00000001) != 0);\n    }\n\n    /**\n     * <pre>\n     * The format of the response.\n     * The default value is 'JSON'.\n     * </pre>\n     *\n     * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n     * @return The enum numeric value on the wire for format.\n     */\n    @Override\n    public int getFormatValue() {\n        return format_;\n    }\n\n    /**\n     * <pre>\n     * The format of the response.\n     * The default value is 'JSON'.\n     * </pre>\n     *\n     * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n     * @return The format.\n     */\n    @Override\n    public OpenAPIFormat getFormat() {\n        OpenAPIFormat result = OpenAPIFormat.forNumber(format_);\n        return result == null ? OpenAPIFormat.UNRECOGNIZED : result;\n    }\n\n    public static final int PRETTY_FIELD_NUMBER = 7;\n    private boolean pretty_ = false;\n\n    /**\n     * <pre>\n     * Whether to pretty print for json.\n     * The default value is 'false'.\n     * </pre>\n     *\n     * <code>optional bool pretty = 7;</code>\n     * @return Whether the pretty field is set.\n     */\n    @Override\n    public boolean hasPretty() {\n        return ((bitField0_ & 0x00000002) != 0);\n    }\n\n    /**\n     * <pre>\n     * Whether to pretty print for json.\n     * The default value is 'false'.\n     * </pre>\n     *\n     * <code>optional bool pretty = 7;</code>\n     * @return The pretty.\n     */\n    @Override\n    public boolean getPretty() {\n        return pretty_;\n    }\n\n    private byte memoizedIsInitialized = -1;\n\n    @Override\n    public final boolean isInitialized() {\n        byte isInitialized = memoizedIsInitialized;\n        if (isInitialized == 1) {\n            return true;\n        }\n        if (isInitialized == 0) {\n            return false;\n        }\n\n        memoizedIsInitialized = 1;\n        return true;\n    }\n\n    @Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(group_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 1, group_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(version_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 2, version_);\n        }\n        for (int i = 0; i < tag_.size(); i++) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 3, tag_.getRaw(i));\n        }\n        for (int i = 0; i < service_.size(); i++) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 4, service_.getRaw(i));\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(openapi_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 5, openapi_);\n        }\n        if (((bitField0_ & 0x00000001) != 0)) {\n            output.writeEnum(6, format_);\n        }\n        if (((bitField0_ & 0x00000002) != 0)) {\n            output.writeBool(7, pretty_);\n        }\n        getUnknownFields().writeTo(output);\n    }\n\n    @Override\n    public int getSerializedSize() {\n        int size = memoizedSize;\n        if (size != -1) {\n            return size;\n        }\n\n        size = 0;\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(group_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, group_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(version_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, version_);\n        }\n        {\n            int dataSize = 0;\n            for (int i = 0; i < tag_.size(); i++) {\n                dataSize += computeStringSizeNoTag(tag_.getRaw(i));\n            }\n            size += dataSize;\n            size += 1 * getTagList().size();\n        }\n        {\n            int dataSize = 0;\n            for (int i = 0; i < service_.size(); i++) {\n                dataSize += computeStringSizeNoTag(service_.getRaw(i));\n            }\n            size += dataSize;\n            size += 1 * getServiceList().size();\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(openapi_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, openapi_);\n        }\n        if (((bitField0_ & 0x00000001) != 0)) {\n            size += com.google.protobuf.CodedOutputStream.computeEnumSize(6, format_);\n        }\n        if (((bitField0_ & 0x00000002) != 0)) {\n            size += com.google.protobuf.CodedOutputStream.computeBoolSize(7, pretty_);\n        }\n        size += getUnknownFields().getSerializedSize();\n        memoizedSize = size;\n        return size;\n    }\n\n    @Override\n    public boolean equals(final Object obj) {\n        if (obj == this) {\n            return true;\n        }\n        if (!(obj instanceof OpenAPIRequest)) {\n            return super.equals(obj);\n        }\n        OpenAPIRequest other = (OpenAPIRequest) obj;\n\n        if (!getGroup().equals(other.getGroup())) {\n            return false;\n        }\n        if (!getVersion().equals(other.getVersion())) {\n            return false;\n        }\n        if (!getTagList().equals(other.getTagList())) {\n            return false;\n        }\n        if (!getServiceList().equals(other.getServiceList())) {\n            return false;\n        }\n        if (!getOpenapi().equals(other.getOpenapi())) {\n            return false;\n        }\n        if (hasFormat() != other.hasFormat()) {\n            return false;\n        }\n        if (hasFormat()) {\n            if (format_ != other.format_) {\n                return false;\n            }\n        }\n        if (hasPretty() != other.hasPretty()) {\n            return false;\n        }\n        if (hasPretty()) {\n            if (getPretty() != other.getPretty()) {\n                return false;\n            }\n        }\n        if (!getUnknownFields().equals(other.getUnknownFields())) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        if (memoizedHashCode != 0) {\n            return memoizedHashCode;\n        }\n        int hash = 41;\n        hash = (19 * hash) + getDescriptor().hashCode();\n        hash = (37 * hash) + GROUP_FIELD_NUMBER;\n        hash = (53 * hash) + getGroup().hashCode();\n        hash = (37 * hash) + VERSION_FIELD_NUMBER;\n        hash = (53 * hash) + getVersion().hashCode();\n        if (getTagCount() > 0) {\n            hash = (37 * hash) + TAG_FIELD_NUMBER;\n            hash = (53 * hash) + getTagList().hashCode();\n        }\n        if (getServiceCount() > 0) {\n            hash = (37 * hash) + SERVICE_FIELD_NUMBER;\n            hash = (53 * hash) + getServiceList().hashCode();\n        }\n        hash = (37 * hash) + OPENAPI_FIELD_NUMBER;\n        hash = (53 * hash) + getOpenapi().hashCode();\n        if (hasFormat()) {\n            hash = (37 * hash) + FORMAT_FIELD_NUMBER;\n            hash = (53 * hash) + format_;\n        }\n        if (hasPretty()) {\n            hash = (37 * hash) + PRETTY_FIELD_NUMBER;\n            hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(getPretty());\n        }\n        hash = (29 * hash) + getUnknownFields().hashCode();\n        memoizedHashCode = hash;\n        return hash;\n    }\n\n    public static OpenAPIRequest parseFrom(java.nio.ByteBuffer data)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static OpenAPIRequest parseFrom(\n            java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static OpenAPIRequest parseFrom(com.google.protobuf.ByteString data)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static OpenAPIRequest parseFrom(\n            com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static OpenAPIRequest parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static OpenAPIRequest parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static OpenAPIRequest parseFrom(java.io.InputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n    }\n\n    public static OpenAPIRequest parseFrom(\n            java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static OpenAPIRequest parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input);\n    }\n\n    public static OpenAPIRequest parseDelimitedFrom(\n            java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static OpenAPIRequest parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n    }\n\n    public static OpenAPIRequest parseFrom(\n            com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @Override\n    public Builder newBuilderForType() {\n        return newBuilder();\n    }\n\n    public static Builder newBuilder() {\n        return DEFAULT_INSTANCE.toBuilder();\n    }\n\n    public static Builder newBuilder(OpenAPIRequest prototype) {\n        return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n\n    @Override\n    public Builder toBuilder() {\n        return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @Override\n    protected Builder newBuilderForType(BuilderParent parent) {\n        Builder builder = new Builder(parent);\n        return builder;\n    }\n\n    /**\n     * <pre>\n     * OpenAPI request message.\n     * </pre>\n     *\n     * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIRequest}\n     */\n    public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder<Builder>\n            implements\n            // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.OpenAPIRequest)\n            OpenAPIRequestOrBuilder {\n        public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor;\n        }\n\n        @Override\n        protected FieldAccessorTable internalGetFieldAccessorTable() {\n            return MetadataServiceV2OuterClass\n                    .internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable\n                    .ensureFieldAccessorsInitialized(OpenAPIRequest.class, Builder.class);\n        }\n\n        // Construct using org.apache.dubbo.metadata.OpenAPIRequest.newBuilder()\n        private Builder() {}\n\n        private Builder(BuilderParent parent) {\n            super(parent);\n        }\n\n        @Override\n        public Builder clear() {\n            super.clear();\n            bitField0_ = 0;\n            group_ = \"\";\n            version_ = \"\";\n            tag_ = com.google.protobuf.LazyStringArrayList.emptyList();\n            service_ = com.google.protobuf.LazyStringArrayList.emptyList();\n            openapi_ = \"\";\n            format_ = 0;\n            pretty_ = false;\n            return this;\n        }\n\n        @Override\n        public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor;\n        }\n\n        @Override\n        public OpenAPIRequest getDefaultInstanceForType() {\n            return OpenAPIRequest.getDefaultInstance();\n        }\n\n        @Override\n        public OpenAPIRequest build() {\n            OpenAPIRequest result = buildPartial();\n            if (!result.isInitialized()) {\n                throw newUninitializedMessageException(result);\n            }\n            return result;\n        }\n\n        @Override\n        public OpenAPIRequest buildPartial() {\n            OpenAPIRequest result = new OpenAPIRequest(this);\n            if (bitField0_ != 0) {\n                buildPartial0(result);\n            }\n            onBuilt();\n            return result;\n        }\n\n        private void buildPartial0(OpenAPIRequest result) {\n            int from_bitField0_ = bitField0_;\n            if (((from_bitField0_ & 0x00000001) != 0)) {\n                result.group_ = group_;\n            }\n            if (((from_bitField0_ & 0x00000002) != 0)) {\n                result.version_ = version_;\n            }\n            if (((from_bitField0_ & 0x00000004) != 0)) {\n                tag_.makeImmutable();\n                result.tag_ = tag_;\n            }\n            if (((from_bitField0_ & 0x00000008) != 0)) {\n                service_.makeImmutable();\n                result.service_ = service_;\n            }\n            if (((from_bitField0_ & 0x00000010) != 0)) {\n                result.openapi_ = openapi_;\n            }\n            int to_bitField0_ = 0;\n            if (((from_bitField0_ & 0x00000020) != 0)) {\n                result.format_ = format_;\n                to_bitField0_ |= 0x00000001;\n            }\n            if (((from_bitField0_ & 0x00000040) != 0)) {\n                result.pretty_ = pretty_;\n                to_bitField0_ |= 0x00000002;\n            }\n            result.bitField0_ |= to_bitField0_;\n        }\n\n        @Override\n        public Builder clone() {\n            return super.clone();\n        }\n\n        @Override\n        public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) {\n            return super.setField(field, value);\n        }\n\n        @Override\n        public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) {\n            return super.clearField(field);\n        }\n\n        @Override\n        public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n            return super.clearOneof(oneof);\n        }\n\n        @Override\n        public Builder setRepeatedField(\n                com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) {\n            return super.setRepeatedField(field, index, value);\n        }\n\n        @Override\n        public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) {\n            return super.addRepeatedField(field, value);\n        }\n\n        @Override\n        public Builder mergeFrom(com.google.protobuf.Message other) {\n            if (other instanceof OpenAPIRequest) {\n                return mergeFrom((OpenAPIRequest) other);\n            } else {\n                super.mergeFrom(other);\n                return this;\n            }\n        }\n\n        public Builder mergeFrom(OpenAPIRequest other) {\n            if (other == OpenAPIRequest.getDefaultInstance()) {\n                return this;\n            }\n            if (!other.getGroup().isEmpty()) {\n                group_ = other.group_;\n                bitField0_ |= 0x00000001;\n                onChanged();\n            }\n            if (!other.getVersion().isEmpty()) {\n                version_ = other.version_;\n                bitField0_ |= 0x00000002;\n                onChanged();\n            }\n            if (!other.tag_.isEmpty()) {\n                if (tag_.isEmpty()) {\n                    tag_ = other.tag_;\n                    bitField0_ |= 0x00000004;\n                } else {\n                    ensureTagIsMutable();\n                    tag_.addAll(other.tag_);\n                }\n                onChanged();\n            }\n            if (!other.service_.isEmpty()) {\n                if (service_.isEmpty()) {\n                    service_ = other.service_;\n                    bitField0_ |= 0x00000008;\n                } else {\n                    ensureServiceIsMutable();\n                    service_.addAll(other.service_);\n                }\n                onChanged();\n            }\n            if (!other.getOpenapi().isEmpty()) {\n                openapi_ = other.openapi_;\n                bitField0_ |= 0x00000010;\n                onChanged();\n            }\n            if (other.hasFormat()) {\n                setFormat(other.getFormat());\n            }\n            if (other.hasPretty()) {\n                setPretty(other.getPretty());\n            }\n            this.mergeUnknownFields(other.getUnknownFields());\n            onChanged();\n            return this;\n        }\n\n        @Override\n        public final boolean isInitialized() {\n            return true;\n        }\n\n        @Override\n        public Builder mergeFrom(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            if (extensionRegistry == null) {\n                throw new NullPointerException();\n            }\n            try {\n                boolean done = false;\n                while (!done) {\n                    int tag = input.readTag();\n                    switch (tag) {\n                        case 0:\n                            done = true;\n                            break;\n                        case 10: {\n                            group_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000001;\n                            break;\n                        } // case 10\n                        case 18: {\n                            version_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000002;\n                            break;\n                        } // case 18\n                        case 26: {\n                            String s = input.readStringRequireUtf8();\n                            ensureTagIsMutable();\n                            tag_.add(s);\n                            break;\n                        } // case 26\n                        case 34: {\n                            String s = input.readStringRequireUtf8();\n                            ensureServiceIsMutable();\n                            service_.add(s);\n                            break;\n                        } // case 34\n                        case 42: {\n                            openapi_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000010;\n                            break;\n                        } // case 42\n                        case 48: {\n                            format_ = input.readEnum();\n                            bitField0_ |= 0x00000020;\n                            break;\n                        } // case 48\n                        case 56: {\n                            pretty_ = input.readBool();\n                            bitField0_ |= 0x00000040;\n                            break;\n                        } // case 56\n                        default: {\n                            if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                                done = true; // was an endgroup tag\n                            }\n                            break;\n                        } // default:\n                    } // switch (tag)\n                } // while (!done)\n            } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                throw e.unwrapIOException();\n            } finally {\n                onChanged();\n            } // finally\n            return this;\n        }\n\n        private int bitField0_;\n\n        private Object group_ = \"\";\n\n        /**\n         * <pre>\n         * The openAPI group.\n         * </pre>\n         *\n         * <code>string group = 1;</code>\n         * @return The group.\n         */\n        public String getGroup() {\n            Object ref = group_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                group_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The openAPI group.\n         * </pre>\n         *\n         * <code>string group = 1;</code>\n         * @return The bytes for group.\n         */\n        public com.google.protobuf.ByteString getGroupBytes() {\n            Object ref = group_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                group_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The openAPI group.\n         * </pre>\n         *\n         * <code>string group = 1;</code>\n         * @param value The group to set.\n         * @return This builder for chaining.\n         */\n        public Builder setGroup(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            group_ = value;\n            bitField0_ |= 0x00000001;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI group.\n         * </pre>\n         *\n         * <code>string group = 1;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearGroup() {\n            group_ = getDefaultInstance().getGroup();\n            bitField0_ = (bitField0_ & ~0x00000001);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI group.\n         * </pre>\n         *\n         * <code>string group = 1;</code>\n         * @param value The bytes for group to set.\n         * @return This builder for chaining.\n         */\n        public Builder setGroupBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            group_ = value;\n            bitField0_ |= 0x00000001;\n            onChanged();\n            return this;\n        }\n\n        private Object version_ = \"\";\n\n        /**\n         * <pre>\n         * The openAPI version, using a major.minor.patch versioning scheme\n         * e.g. 1.0.1\n         * </pre>\n         *\n         * <code>string version = 2;</code>\n         * @return The version.\n         */\n        public String getVersion() {\n            Object ref = version_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                version_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The openAPI version, using a major.minor.patch versioning scheme\n         * e.g. 1.0.1\n         * </pre>\n         *\n         * <code>string version = 2;</code>\n         * @return The bytes for version.\n         */\n        public com.google.protobuf.ByteString getVersionBytes() {\n            Object ref = version_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                version_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The openAPI version, using a major.minor.patch versioning scheme\n         * e.g. 1.0.1\n         * </pre>\n         *\n         * <code>string version = 2;</code>\n         * @param value The version to set.\n         * @return This builder for chaining.\n         */\n        public Builder setVersion(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            version_ = value;\n            bitField0_ |= 0x00000002;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI version, using a major.minor.patch versioning scheme\n         * e.g. 1.0.1\n         * </pre>\n         *\n         * <code>string version = 2;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearVersion() {\n            version_ = getDefaultInstance().getVersion();\n            bitField0_ = (bitField0_ & ~0x00000002);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI version, using a major.minor.patch versioning scheme\n         * e.g. 1.0.1\n         * </pre>\n         *\n         * <code>string version = 2;</code>\n         * @param value The bytes for version to set.\n         * @return This builder for chaining.\n         */\n        public Builder setVersionBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            version_ = value;\n            bitField0_ |= 0x00000002;\n            onChanged();\n            return this;\n        }\n\n        private com.google.protobuf.LazyStringArrayList tag_ = com.google.protobuf.LazyStringArrayList.emptyList();\n\n        private void ensureTagIsMutable() {\n            if (!tag_.isModifiable()) {\n                tag_ = new com.google.protobuf.LazyStringArrayList(tag_);\n            }\n            bitField0_ |= 0x00000004;\n        }\n\n        /**\n         * <pre>\n         * The openAPI tags. Each tag is an or condition.\n         * </pre>\n         *\n         * <code>repeated string tag = 3;</code>\n         * @return A list containing the tag.\n         */\n        public com.google.protobuf.ProtocolStringList getTagList() {\n            tag_.makeImmutable();\n            return tag_;\n        }\n\n        /**\n         * <pre>\n         * The openAPI tags. Each tag is an or condition.\n         * </pre>\n         *\n         * <code>repeated string tag = 3;</code>\n         * @return The count of tag.\n         */\n        public int getTagCount() {\n            return tag_.size();\n        }\n\n        /**\n         * <pre>\n         * The openAPI tags. Each tag is an or condition.\n         * </pre>\n         *\n         * <code>repeated string tag = 3;</code>\n         * @param index The index of the element to return.\n         * @return The tag at the given index.\n         */\n        public String getTag(int index) {\n            return tag_.get(index);\n        }\n\n        /**\n         * <pre>\n         * The openAPI tags. Each tag is an or condition.\n         * </pre>\n         *\n         * <code>repeated string tag = 3;</code>\n         * @param index The index of the value to return.\n         * @return The bytes of the tag at the given index.\n         */\n        public com.google.protobuf.ByteString getTagBytes(int index) {\n            return tag_.getByteString(index);\n        }\n\n        /**\n         * <pre>\n         * The openAPI tags. Each tag is an or condition.\n         * </pre>\n         *\n         * <code>repeated string tag = 3;</code>\n         * @param index The index to set the value at.\n         * @param value The tag to set.\n         * @return This builder for chaining.\n         */\n        public Builder setTag(int index, String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            ensureTagIsMutable();\n            tag_.set(index, value);\n            bitField0_ |= 0x00000004;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI tags. Each tag is an or condition.\n         * </pre>\n         *\n         * <code>repeated string tag = 3;</code>\n         * @param value The tag to add.\n         * @return This builder for chaining.\n         */\n        public Builder addTag(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            ensureTagIsMutable();\n            tag_.add(value);\n            bitField0_ |= 0x00000004;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI tags. Each tag is an or condition.\n         * </pre>\n         *\n         * <code>repeated string tag = 3;</code>\n         * @param values The tag to add.\n         * @return This builder for chaining.\n         */\n        public Builder addAllTag(Iterable<String> values) {\n            ensureTagIsMutable();\n            com.google.protobuf.AbstractMessageLite.Builder.addAll(values, tag_);\n            bitField0_ |= 0x00000004;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI tags. Each tag is an or condition.\n         * </pre>\n         *\n         * <code>repeated string tag = 3;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearTag() {\n            tag_ = com.google.protobuf.LazyStringArrayList.emptyList();\n            bitField0_ = (bitField0_ & ~0x00000004);\n            ;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI tags. Each tag is an or condition.\n         * </pre>\n         *\n         * <code>repeated string tag = 3;</code>\n         * @param value The bytes of the tag to add.\n         * @return This builder for chaining.\n         */\n        public Builder addTagBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            ensureTagIsMutable();\n            tag_.add(value);\n            bitField0_ |= 0x00000004;\n            onChanged();\n            return this;\n        }\n\n        private com.google.protobuf.LazyStringArrayList service_ = com.google.protobuf.LazyStringArrayList.emptyList();\n\n        private void ensureServiceIsMutable() {\n            if (!service_.isModifiable()) {\n                service_ = new com.google.protobuf.LazyStringArrayList(service_);\n            }\n            bitField0_ |= 0x00000008;\n        }\n\n        /**\n         * <pre>\n         * The openAPI services. Each service is an or condition.\n         * </pre>\n         *\n         * <code>repeated string service = 4;</code>\n         * @return A list containing the service.\n         */\n        public com.google.protobuf.ProtocolStringList getServiceList() {\n            service_.makeImmutable();\n            return service_;\n        }\n\n        /**\n         * <pre>\n         * The openAPI services. Each service is an or condition.\n         * </pre>\n         *\n         * <code>repeated string service = 4;</code>\n         * @return The count of service.\n         */\n        public int getServiceCount() {\n            return service_.size();\n        }\n\n        /**\n         * <pre>\n         * The openAPI services. Each service is an or condition.\n         * </pre>\n         *\n         * <code>repeated string service = 4;</code>\n         * @param index The index of the element to return.\n         * @return The service at the given index.\n         */\n        public String getService(int index) {\n            return service_.get(index);\n        }\n\n        /**\n         * <pre>\n         * The openAPI services. Each service is an or condition.\n         * </pre>\n         *\n         * <code>repeated string service = 4;</code>\n         * @param index The index of the value to return.\n         * @return The bytes of the service at the given index.\n         */\n        public com.google.protobuf.ByteString getServiceBytes(int index) {\n            return service_.getByteString(index);\n        }\n\n        /**\n         * <pre>\n         * The openAPI services. Each service is an or condition.\n         * </pre>\n         *\n         * <code>repeated string service = 4;</code>\n         * @param index The index to set the value at.\n         * @param value The service to set.\n         * @return This builder for chaining.\n         */\n        public Builder setService(int index, String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            ensureServiceIsMutable();\n            service_.set(index, value);\n            bitField0_ |= 0x00000008;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI services. Each service is an or condition.\n         * </pre>\n         *\n         * <code>repeated string service = 4;</code>\n         * @param value The service to add.\n         * @return This builder for chaining.\n         */\n        public Builder addService(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            ensureServiceIsMutable();\n            service_.add(value);\n            bitField0_ |= 0x00000008;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI services. Each service is an or condition.\n         * </pre>\n         *\n         * <code>repeated string service = 4;</code>\n         * @param values The service to add.\n         * @return This builder for chaining.\n         */\n        public Builder addAllService(Iterable<String> values) {\n            ensureServiceIsMutable();\n            com.google.protobuf.AbstractMessageLite.Builder.addAll(values, service_);\n            bitField0_ |= 0x00000008;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI services. Each service is an or condition.\n         * </pre>\n         *\n         * <code>repeated string service = 4;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearService() {\n            service_ = com.google.protobuf.LazyStringArrayList.emptyList();\n            bitField0_ = (bitField0_ & ~0x00000008);\n            ;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI services. Each service is an or condition.\n         * </pre>\n         *\n         * <code>repeated string service = 4;</code>\n         * @param value The bytes of the service to add.\n         * @return This builder for chaining.\n         */\n        public Builder addServiceBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            ensureServiceIsMutable();\n            service_.add(value);\n            bitField0_ |= 0x00000008;\n            onChanged();\n            return this;\n        }\n\n        private Object openapi_ = \"\";\n\n        /**\n         * <pre>\n         * The openAPI specification version, using a major.minor.patch versioning scheme\n         * e.g. 3.0.1, 3.1.0\n         * The default value is '3.0.1'.\n         * </pre>\n         *\n         * <code>string openapi = 5;</code>\n         * @return The openapi.\n         */\n        public String getOpenapi() {\n            Object ref = openapi_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                openapi_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The openAPI specification version, using a major.minor.patch versioning scheme\n         * e.g. 3.0.1, 3.1.0\n         * The default value is '3.0.1'.\n         * </pre>\n         *\n         * <code>string openapi = 5;</code>\n         * @return The bytes for openapi.\n         */\n        public com.google.protobuf.ByteString getOpenapiBytes() {\n            Object ref = openapi_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                openapi_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The openAPI specification version, using a major.minor.patch versioning scheme\n         * e.g. 3.0.1, 3.1.0\n         * The default value is '3.0.1'.\n         * </pre>\n         *\n         * <code>string openapi = 5;</code>\n         * @param value The openapi to set.\n         * @return This builder for chaining.\n         */\n        public Builder setOpenapi(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            openapi_ = value;\n            bitField0_ |= 0x00000010;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI specification version, using a major.minor.patch versioning scheme\n         * e.g. 3.0.1, 3.1.0\n         * The default value is '3.0.1'.\n         * </pre>\n         *\n         * <code>string openapi = 5;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearOpenapi() {\n            openapi_ = getDefaultInstance().getOpenapi();\n            bitField0_ = (bitField0_ & ~0x00000010);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The openAPI specification version, using a major.minor.patch versioning scheme\n         * e.g. 3.0.1, 3.1.0\n         * The default value is '3.0.1'.\n         * </pre>\n         *\n         * <code>string openapi = 5;</code>\n         * @param value The bytes for openapi to set.\n         * @return This builder for chaining.\n         */\n        public Builder setOpenapiBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            openapi_ = value;\n            bitField0_ |= 0x00000010;\n            onChanged();\n            return this;\n        }\n\n        private int format_ = 0;\n\n        /**\n         * <pre>\n         * The format of the response.\n         * The default value is 'JSON'.\n         * </pre>\n         *\n         * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n         * @return Whether the format field is set.\n         */\n        @Override\n        public boolean hasFormat() {\n            return ((bitField0_ & 0x00000020) != 0);\n        }\n\n        /**\n         * <pre>\n         * The format of the response.\n         * The default value is 'JSON'.\n         * </pre>\n         *\n         * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n         * @return The enum numeric value on the wire for format.\n         */\n        @Override\n        public int getFormatValue() {\n            return format_;\n        }\n\n        /**\n         * <pre>\n         * The format of the response.\n         * The default value is 'JSON'.\n         * </pre>\n         *\n         * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n         * @param value The enum numeric value on the wire for format to set.\n         * @return This builder for chaining.\n         */\n        public Builder setFormatValue(int value) {\n            format_ = value;\n            bitField0_ |= 0x00000020;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The format of the response.\n         * The default value is 'JSON'.\n         * </pre>\n         *\n         * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n         * @return The format.\n         */\n        @Override\n        public OpenAPIFormat getFormat() {\n            OpenAPIFormat result = OpenAPIFormat.forNumber(format_);\n            return result == null ? OpenAPIFormat.UNRECOGNIZED : result;\n        }\n\n        /**\n         * <pre>\n         * The format of the response.\n         * The default value is 'JSON'.\n         * </pre>\n         *\n         * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n         * @param value The format to set.\n         * @return This builder for chaining.\n         */\n        public Builder setFormat(OpenAPIFormat value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            bitField0_ |= 0x00000020;\n            format_ = value.getNumber();\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The format of the response.\n         * The default value is 'JSON'.\n         * </pre>\n         *\n         * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearFormat() {\n            bitField0_ = (bitField0_ & ~0x00000020);\n            format_ = 0;\n            onChanged();\n            return this;\n        }\n\n        private boolean pretty_;\n\n        /**\n         * <pre>\n         * Whether to pretty print for json.\n         * The default value is 'false'.\n         * </pre>\n         *\n         * <code>optional bool pretty = 7;</code>\n         * @return Whether the pretty field is set.\n         */\n        @Override\n        public boolean hasPretty() {\n            return ((bitField0_ & 0x00000040) != 0);\n        }\n\n        /**\n         * <pre>\n         * Whether to pretty print for json.\n         * The default value is 'false'.\n         * </pre>\n         *\n         * <code>optional bool pretty = 7;</code>\n         * @return The pretty.\n         */\n        @Override\n        public boolean getPretty() {\n            return pretty_;\n        }\n\n        /**\n         * <pre>\n         * Whether to pretty print for json.\n         * The default value is 'false'.\n         * </pre>\n         *\n         * <code>optional bool pretty = 7;</code>\n         * @param value The pretty to set.\n         * @return This builder for chaining.\n         */\n        public Builder setPretty(boolean value) {\n\n            pretty_ = value;\n            bitField0_ |= 0x00000040;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * Whether to pretty print for json.\n         * The default value is 'false'.\n         * </pre>\n         *\n         * <code>optional bool pretty = 7;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearPretty() {\n            bitField0_ = (bitField0_ & ~0x00000040);\n            pretty_ = false;\n            onChanged();\n            return this;\n        }\n\n        @Override\n        public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n            return super.setUnknownFields(unknownFields);\n        }\n\n        @Override\n        public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n            return super.mergeUnknownFields(unknownFields);\n        }\n\n        // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.OpenAPIRequest)\n    }\n\n    // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.OpenAPIRequest)\n    private static final OpenAPIRequest DEFAULT_INSTANCE;\n\n    static {\n        DEFAULT_INSTANCE = new OpenAPIRequest();\n    }\n\n    public static OpenAPIRequest getDefaultInstance() {\n        return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<OpenAPIRequest> PARSER =\n            new com.google.protobuf.AbstractParser<OpenAPIRequest>() {\n                @Override\n                public OpenAPIRequest parsePartialFrom(\n                        com.google.protobuf.CodedInputStream input,\n                        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                        throws com.google.protobuf.InvalidProtocolBufferException {\n                    Builder builder = newBuilder();\n                    try {\n                        builder.mergeFrom(input, extensionRegistry);\n                    } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                        throw e.setUnfinishedMessage(builder.buildPartial());\n                    } catch (com.google.protobuf.UninitializedMessageException e) {\n                        throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n                    } catch (java.io.IOException e) {\n                        throw new com.google.protobuf.InvalidProtocolBufferException(e)\n                                .setUnfinishedMessage(builder.buildPartial());\n                    }\n                    return builder.buildPartial();\n                }\n            };\n\n    public static com.google.protobuf.Parser<OpenAPIRequest> parser() {\n        return PARSER;\n    }\n\n    @Override\n    public com.google.protobuf.Parser<OpenAPIRequest> getParserForType() {\n        return PARSER;\n    }\n\n    @Override\n    public OpenAPIRequest getDefaultInstanceForType() {\n        return DEFAULT_INSTANCE;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequestOrBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\npublic interface OpenAPIRequestOrBuilder\n        extends\n        // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.OpenAPIRequest)\n        com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <pre>\n     * The openAPI group.\n     * </pre>\n     *\n     * <code>string group = 1;</code>\n     * @return The group.\n     */\n    String getGroup();\n\n    /**\n     * <pre>\n     * The openAPI group.\n     * </pre>\n     *\n     * <code>string group = 1;</code>\n     * @return The bytes for group.\n     */\n    com.google.protobuf.ByteString getGroupBytes();\n\n    /**\n     * <pre>\n     * The openAPI version, using a major.minor.patch versioning scheme\n     * e.g. 1.0.1\n     * </pre>\n     *\n     * <code>string version = 2;</code>\n     * @return The version.\n     */\n    String getVersion();\n\n    /**\n     * <pre>\n     * The openAPI version, using a major.minor.patch versioning scheme\n     * e.g. 1.0.1\n     * </pre>\n     *\n     * <code>string version = 2;</code>\n     * @return The bytes for version.\n     */\n    com.google.protobuf.ByteString getVersionBytes();\n\n    /**\n     * <pre>\n     * The openAPI tags. Each tag is an or condition.\n     * </pre>\n     *\n     * <code>repeated string tag = 3;</code>\n     * @return A list containing the tag.\n     */\n    java.util.List<String> getTagList();\n\n    /**\n     * <pre>\n     * The openAPI tags. Each tag is an or condition.\n     * </pre>\n     *\n     * <code>repeated string tag = 3;</code>\n     * @return The count of tag.\n     */\n    int getTagCount();\n\n    /**\n     * <pre>\n     * The openAPI tags. Each tag is an or condition.\n     * </pre>\n     *\n     * <code>repeated string tag = 3;</code>\n     * @param index The index of the element to return.\n     * @return The tag at the given index.\n     */\n    String getTag(int index);\n\n    /**\n     * <pre>\n     * The openAPI tags. Each tag is an or condition.\n     * </pre>\n     *\n     * <code>repeated string tag = 3;</code>\n     * @param index The index of the value to return.\n     * @return The bytes of the tag at the given index.\n     */\n    com.google.protobuf.ByteString getTagBytes(int index);\n\n    /**\n     * <pre>\n     * The openAPI services. Each service is an or condition.\n     * </pre>\n     *\n     * <code>repeated string service = 4;</code>\n     * @return A list containing the service.\n     */\n    java.util.List<String> getServiceList();\n\n    /**\n     * <pre>\n     * The openAPI services. Each service is an or condition.\n     * </pre>\n     *\n     * <code>repeated string service = 4;</code>\n     * @return The count of service.\n     */\n    int getServiceCount();\n\n    /**\n     * <pre>\n     * The openAPI services. Each service is an or condition.\n     * </pre>\n     *\n     * <code>repeated string service = 4;</code>\n     * @param index The index of the element to return.\n     * @return The service at the given index.\n     */\n    String getService(int index);\n\n    /**\n     * <pre>\n     * The openAPI services. Each service is an or condition.\n     * </pre>\n     *\n     * <code>repeated string service = 4;</code>\n     * @param index The index of the value to return.\n     * @return The bytes of the service at the given index.\n     */\n    com.google.protobuf.ByteString getServiceBytes(int index);\n\n    /**\n     * <pre>\n     * The openAPI specification version, using a major.minor.patch versioning scheme\n     * e.g. 3.0.1, 3.1.0\n     * The default value is '3.0.1'.\n     * </pre>\n     *\n     * <code>string openapi = 5;</code>\n     * @return The openapi.\n     */\n    String getOpenapi();\n\n    /**\n     * <pre>\n     * The openAPI specification version, using a major.minor.patch versioning scheme\n     * e.g. 3.0.1, 3.1.0\n     * The default value is '3.0.1'.\n     * </pre>\n     *\n     * <code>string openapi = 5;</code>\n     * @return The bytes for openapi.\n     */\n    com.google.protobuf.ByteString getOpenapiBytes();\n\n    /**\n     * <pre>\n     * The format of the response.\n     * The default value is 'JSON'.\n     * </pre>\n     *\n     * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n     * @return Whether the format field is set.\n     */\n    boolean hasFormat();\n\n    /**\n     * <pre>\n     * The format of the response.\n     * The default value is 'JSON'.\n     * </pre>\n     *\n     * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n     * @return The enum numeric value on the wire for format.\n     */\n    int getFormatValue();\n\n    /**\n     * <pre>\n     * The format of the response.\n     * The default value is 'JSON'.\n     * </pre>\n     *\n     * <code>optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6;</code>\n     * @return The format.\n     */\n    OpenAPIFormat getFormat();\n\n    /**\n     * <pre>\n     * Whether to pretty print for json.\n     * The default value is 'false'.\n     * </pre>\n     *\n     * <code>optional bool pretty = 7;</code>\n     * @return Whether the pretty field is set.\n     */\n    boolean hasPretty();\n\n    /**\n     * <pre>\n     * Whether to pretty print for json.\n     * The default value is 'false'.\n     * </pre>\n     *\n     * <code>optional bool pretty = 7;</code>\n     * @return The pretty.\n     */\n    boolean getPretty();\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ParameterTypesComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport java.util.Arrays;\n\npublic class ParameterTypesComparator {\n\n    private Class[] parameterTypes;\n\n    public ParameterTypesComparator(Class[] parameterTypes) {\n        this.parameterTypes = parameterTypes;\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        ParameterTypesComparator that = (ParameterTypesComparator) o;\n        return Arrays.equals(parameterTypes, that.parameterTypes);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(parameterTypes);\n    }\n\n    public static ParameterTypesComparator getInstance(Class[] parameterTypes) {\n        return new ParameterTypesComparator(parameterTypes);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/RevisionResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.utils.MD5Utils;\n\npublic class RevisionResolver {\n\n    public static final String EMPTY_REVISION = \"0\";\n\n    private static MD5Utils md5Utils = new MD5Utils();\n\n    public static String calRevision(String metadata) {\n        return md5Utils.getMd5(metadata);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\n/**\n * <pre>\n * Service information message.\n * </pre>\n *\n * Protobuf type {@code org.apache.dubbo.metadata.ServiceInfoV2}\n */\npublic final class ServiceInfoV2 extends com.google.protobuf.GeneratedMessageV3\n        implements\n        // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.ServiceInfoV2)\n        ServiceInfoV2OrBuilder {\n    private static final long serialVersionUID = 0L;\n\n    // Use ServiceInfoV2.newBuilder() to construct.\n    private ServiceInfoV2(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n        super(builder);\n    }\n\n    private ServiceInfoV2() {\n        name_ = \"\";\n        group_ = \"\";\n        version_ = \"\";\n        protocol_ = \"\";\n        path_ = \"\";\n    }\n\n    @Override\n    @SuppressWarnings({\"unused\"})\n    protected Object newInstance(UnusedPrivateParameter unused) {\n        return new ServiceInfoV2();\n    }\n\n    public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n        return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_ServiceInfoV2_descriptor;\n    }\n\n    @SuppressWarnings({\"rawtypes\"})\n    @Override\n    protected com.google.protobuf.MapField internalGetMapField(int number) {\n        switch (number) {\n            case 7:\n                return internalGetParams();\n            default:\n                throw new RuntimeException(\"Invalid map field number: \" + number);\n        }\n    }\n\n    @Override\n    protected FieldAccessorTable internalGetFieldAccessorTable() {\n        return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_ServiceInfoV2_fieldAccessorTable\n                .ensureFieldAccessorsInitialized(ServiceInfoV2.class, Builder.class);\n    }\n\n    public static final int NAME_FIELD_NUMBER = 1;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object name_ = \"\";\n\n    /**\n     * <pre>\n     * The service name.\n     * </pre>\n     *\n     * <code>string name = 1;</code>\n     * @return The name.\n     */\n    @Override\n    public String getName() {\n        Object ref = name_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            name_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The service name.\n     * </pre>\n     *\n     * <code>string name = 1;</code>\n     * @return The bytes for name.\n     */\n    @Override\n    public com.google.protobuf.ByteString getNameBytes() {\n        Object ref = name_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            name_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    public static final int GROUP_FIELD_NUMBER = 2;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object group_ = \"\";\n\n    /**\n     * <pre>\n     * The service group.\n     * </pre>\n     *\n     * <code>string group = 2;</code>\n     * @return The group.\n     */\n    @Override\n    public String getGroup() {\n        Object ref = group_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            group_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The service group.\n     * </pre>\n     *\n     * <code>string group = 2;</code>\n     * @return The bytes for group.\n     */\n    @Override\n    public com.google.protobuf.ByteString getGroupBytes() {\n        Object ref = group_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            group_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    public static final int VERSION_FIELD_NUMBER = 3;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object version_ = \"\";\n\n    /**\n     * <pre>\n     * The service version.\n     * </pre>\n     *\n     * <code>string version = 3;</code>\n     * @return The version.\n     */\n    @Override\n    public String getVersion() {\n        Object ref = version_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            version_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The service version.\n     * </pre>\n     *\n     * <code>string version = 3;</code>\n     * @return The bytes for version.\n     */\n    @Override\n    public com.google.protobuf.ByteString getVersionBytes() {\n        Object ref = version_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            version_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    public static final int PROTOCOL_FIELD_NUMBER = 4;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object protocol_ = \"\";\n\n    /**\n     * <pre>\n     * The service protocol.\n     * </pre>\n     *\n     * <code>string protocol = 4;</code>\n     * @return The protocol.\n     */\n    @Override\n    public String getProtocol() {\n        Object ref = protocol_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            protocol_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The service protocol.\n     * </pre>\n     *\n     * <code>string protocol = 4;</code>\n     * @return The bytes for protocol.\n     */\n    @Override\n    public com.google.protobuf.ByteString getProtocolBytes() {\n        Object ref = protocol_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            protocol_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    public static final int PORT_FIELD_NUMBER = 5;\n    private int port_ = 0;\n\n    /**\n     * <pre>\n     * The service port.\n     * </pre>\n     *\n     * <code>int32 port = 5;</code>\n     * @return The port.\n     */\n    @Override\n    public int getPort() {\n        return port_;\n    }\n\n    public static final int PATH_FIELD_NUMBER = 6;\n\n    @SuppressWarnings(\"serial\")\n    private volatile Object path_ = \"\";\n\n    /**\n     * <pre>\n     * The service path.\n     * </pre>\n     *\n     * <code>string path = 6;</code>\n     * @return The path.\n     */\n    @Override\n    public String getPath() {\n        Object ref = path_;\n        if (ref instanceof String) {\n            return (String) ref;\n        } else {\n            com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n            String s = bs.toStringUtf8();\n            path_ = s;\n            return s;\n        }\n    }\n\n    /**\n     * <pre>\n     * The service path.\n     * </pre>\n     *\n     * <code>string path = 6;</code>\n     * @return The bytes for path.\n     */\n    @Override\n    public com.google.protobuf.ByteString getPathBytes() {\n        Object ref = path_;\n        if (ref instanceof String) {\n            com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n            path_ = b;\n            return b;\n        } else {\n            return (com.google.protobuf.ByteString) ref;\n        }\n    }\n\n    public static final int PARAMS_FIELD_NUMBER = 7;\n\n    private static final class ParamsDefaultEntryHolder {\n        static final com.google.protobuf.MapEntry<String, String> defaultEntry =\n                com.google.protobuf.MapEntry.<String, String>newDefaultInstance(\n                        MetadataServiceV2OuterClass\n                                .internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_descriptor,\n                        com.google.protobuf.WireFormat.FieldType.STRING,\n                        \"\",\n                        com.google.protobuf.WireFormat.FieldType.STRING,\n                        \"\");\n    }\n\n    @SuppressWarnings(\"serial\")\n    private com.google.protobuf.MapField<String, String> params_;\n\n    private com.google.protobuf.MapField<String, String> internalGetParams() {\n        if (params_ == null) {\n            return com.google.protobuf.MapField.emptyMapField(ParamsDefaultEntryHolder.defaultEntry);\n        }\n        return params_;\n    }\n\n    public int getParamsCount() {\n        return internalGetParams().getMap().size();\n    }\n\n    /**\n     * <pre>\n     * A map of service parameters.\n     * </pre>\n     *\n     * <code>map&lt;string, string&gt; params = 7;</code>\n     */\n    @Override\n    public boolean containsParams(String key) {\n        if (key == null) {\n            throw new NullPointerException(\"map key\");\n        }\n        return internalGetParams().getMap().containsKey(key);\n    }\n\n    /**\n     * Use {@link #getParamsMap()} instead.\n     */\n    @Override\n    @Deprecated\n    public java.util.Map<String, String> getParams() {\n        return getParamsMap();\n    }\n\n    /**\n     * <pre>\n     * A map of service parameters.\n     * </pre>\n     *\n     * <code>map&lt;string, string&gt; params = 7;</code>\n     */\n    @Override\n    public java.util.Map<String, String> getParamsMap() {\n        return internalGetParams().getMap();\n    }\n\n    /**\n     * <pre>\n     * A map of service parameters.\n     * </pre>\n     *\n     * <code>map&lt;string, string&gt; params = 7;</code>\n     */\n    @Override\n    public /* nullable */ String getParamsOrDefault(\n            String key,\n            /* nullable */\n            String defaultValue) {\n        if (key == null) {\n            throw new NullPointerException(\"map key\");\n        }\n        java.util.Map<String, String> map = internalGetParams().getMap();\n        return map.containsKey(key) ? map.get(key) : defaultValue;\n    }\n\n    /**\n     * <pre>\n     * A map of service parameters.\n     * </pre>\n     *\n     * <code>map&lt;string, string&gt; params = 7;</code>\n     */\n    @Override\n    public String getParamsOrThrow(String key) {\n        if (key == null) {\n            throw new NullPointerException(\"map key\");\n        }\n        java.util.Map<String, String> map = internalGetParams().getMap();\n        if (!map.containsKey(key)) {\n            throw new IllegalArgumentException();\n        }\n        return map.get(key);\n    }\n\n    private byte memoizedIsInitialized = -1;\n\n    @Override\n    public final boolean isInitialized() {\n        byte isInitialized = memoizedIsInitialized;\n        if (isInitialized == 1) {\n            return true;\n        }\n        if (isInitialized == 0) {\n            return false;\n        }\n\n        memoizedIsInitialized = 1;\n        return true;\n    }\n\n    @Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 1, name_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(group_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 2, group_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(version_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 3, version_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(protocol_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 4, protocol_);\n        }\n        if (port_ != 0) {\n            output.writeInt32(5, port_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(path_)) {\n            com.google.protobuf.GeneratedMessageV3.writeString(output, 6, path_);\n        }\n        com.google.protobuf.GeneratedMessageV3.serializeStringMapTo(\n                output, internalGetParams(), ParamsDefaultEntryHolder.defaultEntry, 7);\n        getUnknownFields().writeTo(output);\n    }\n\n    @Override\n    public int getSerializedSize() {\n        int size = memoizedSize;\n        if (size != -1) {\n            return size;\n        }\n\n        size = 0;\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, name_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(group_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, group_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(version_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, version_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(protocol_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, protocol_);\n        }\n        if (port_ != 0) {\n            size += com.google.protobuf.CodedOutputStream.computeInt32Size(5, port_);\n        }\n        if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(path_)) {\n            size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, path_);\n        }\n        for (java.util.Map.Entry<String, String> entry :\n                internalGetParams().getMap().entrySet()) {\n            com.google.protobuf.MapEntry<String, String> params__ = ParamsDefaultEntryHolder.defaultEntry\n                    .newBuilderForType()\n                    .setKey(entry.getKey())\n                    .setValue(entry.getValue())\n                    .build();\n            size += com.google.protobuf.CodedOutputStream.computeMessageSize(7, params__);\n        }\n        size += getUnknownFields().getSerializedSize();\n        memoizedSize = size;\n        return size;\n    }\n\n    @Override\n    public boolean equals(final Object obj) {\n        if (obj == this) {\n            return true;\n        }\n        if (!(obj instanceof ServiceInfoV2)) {\n            return super.equals(obj);\n        }\n        ServiceInfoV2 other = (ServiceInfoV2) obj;\n\n        if (!getName().equals(other.getName())) {\n            return false;\n        }\n        if (!getGroup().equals(other.getGroup())) {\n            return false;\n        }\n        if (!getVersion().equals(other.getVersion())) {\n            return false;\n        }\n        if (!getProtocol().equals(other.getProtocol())) {\n            return false;\n        }\n        if (getPort() != other.getPort()) {\n            return false;\n        }\n        if (!getPath().equals(other.getPath())) {\n            return false;\n        }\n        if (!internalGetParams().equals(other.internalGetParams())) {\n            return false;\n        }\n        if (!getUnknownFields().equals(other.getUnknownFields())) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        if (memoizedHashCode != 0) {\n            return memoizedHashCode;\n        }\n        int hash = 41;\n        hash = (19 * hash) + getDescriptor().hashCode();\n        hash = (37 * hash) + NAME_FIELD_NUMBER;\n        hash = (53 * hash) + getName().hashCode();\n        hash = (37 * hash) + GROUP_FIELD_NUMBER;\n        hash = (53 * hash) + getGroup().hashCode();\n        hash = (37 * hash) + VERSION_FIELD_NUMBER;\n        hash = (53 * hash) + getVersion().hashCode();\n        hash = (37 * hash) + PROTOCOL_FIELD_NUMBER;\n        hash = (53 * hash) + getProtocol().hashCode();\n        hash = (37 * hash) + PORT_FIELD_NUMBER;\n        hash = (53 * hash) + getPort();\n        hash = (37 * hash) + PATH_FIELD_NUMBER;\n        hash = (53 * hash) + getPath().hashCode();\n        if (!internalGetParams().getMap().isEmpty()) {\n            hash = (37 * hash) + PARAMS_FIELD_NUMBER;\n            hash = (53 * hash) + internalGetParams().hashCode();\n        }\n        hash = (29 * hash) + getUnknownFields().hashCode();\n        memoizedHashCode = hash;\n        return hash;\n    }\n\n    public static ServiceInfoV2 parseFrom(java.nio.ByteBuffer data)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static ServiceInfoV2 parseFrom(\n            java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static ServiceInfoV2 parseFrom(com.google.protobuf.ByteString data)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static ServiceInfoV2 parseFrom(\n            com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static ServiceInfoV2 parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n    }\n\n    public static ServiceInfoV2 parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n    }\n\n    public static ServiceInfoV2 parseFrom(java.io.InputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n    }\n\n    public static ServiceInfoV2 parseFrom(\n            java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static ServiceInfoV2 parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input);\n    }\n\n    public static ServiceInfoV2 parseDelimitedFrom(\n            java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static ServiceInfoV2 parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n    }\n\n    public static ServiceInfoV2 parseFrom(\n            com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @Override\n    public Builder newBuilderForType() {\n        return newBuilder();\n    }\n\n    public static Builder newBuilder() {\n        return DEFAULT_INSTANCE.toBuilder();\n    }\n\n    public static Builder newBuilder(ServiceInfoV2 prototype) {\n        return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n\n    @Override\n    public Builder toBuilder() {\n        return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @Override\n    protected Builder newBuilderForType(BuilderParent parent) {\n        Builder builder = new Builder(parent);\n        return builder;\n    }\n\n    /**\n     * <pre>\n     * Service information message.\n     * </pre>\n     *\n     * Protobuf type {@code org.apache.dubbo.metadata.ServiceInfoV2}\n     */\n    public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder<Builder>\n            implements\n            // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.ServiceInfoV2)\n            ServiceInfoV2OrBuilder {\n        public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_ServiceInfoV2_descriptor;\n        }\n\n        @SuppressWarnings({\"rawtypes\"})\n        protected com.google.protobuf.MapField internalGetMapField(int number) {\n            switch (number) {\n                case 7:\n                    return internalGetParams();\n                default:\n                    throw new RuntimeException(\"Invalid map field number: \" + number);\n            }\n        }\n\n        @SuppressWarnings({\"rawtypes\"})\n        protected com.google.protobuf.MapField internalGetMutableMapField(int number) {\n            switch (number) {\n                case 7:\n                    return internalGetMutableParams();\n                default:\n                    throw new RuntimeException(\"Invalid map field number: \" + number);\n            }\n        }\n\n        @Override\n        protected FieldAccessorTable internalGetFieldAccessorTable() {\n            return MetadataServiceV2OuterClass\n                    .internal_static_org_apache_dubbo_metadata_ServiceInfoV2_fieldAccessorTable\n                    .ensureFieldAccessorsInitialized(ServiceInfoV2.class, Builder.class);\n        }\n\n        // Construct using org.apache.dubbo.metadata.ServiceInfoV2.newBuilder()\n        private Builder() {}\n\n        private Builder(BuilderParent parent) {\n            super(parent);\n        }\n\n        @Override\n        public Builder clear() {\n            super.clear();\n            bitField0_ = 0;\n            name_ = \"\";\n            group_ = \"\";\n            version_ = \"\";\n            protocol_ = \"\";\n            port_ = 0;\n            path_ = \"\";\n            internalGetMutableParams().clear();\n            return this;\n        }\n\n        @Override\n        public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n            return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_ServiceInfoV2_descriptor;\n        }\n\n        @Override\n        public ServiceInfoV2 getDefaultInstanceForType() {\n            return ServiceInfoV2.getDefaultInstance();\n        }\n\n        @Override\n        public ServiceInfoV2 build() {\n            ServiceInfoV2 result = buildPartial();\n            if (!result.isInitialized()) {\n                throw newUninitializedMessageException(result);\n            }\n            return result;\n        }\n\n        @Override\n        public ServiceInfoV2 buildPartial() {\n            ServiceInfoV2 result = new ServiceInfoV2(this);\n            if (bitField0_ != 0) {\n                buildPartial0(result);\n            }\n            onBuilt();\n            return result;\n        }\n\n        private void buildPartial0(ServiceInfoV2 result) {\n            int from_bitField0_ = bitField0_;\n            if (((from_bitField0_ & 0x00000001) != 0)) {\n                result.name_ = name_;\n            }\n            if (((from_bitField0_ & 0x00000002) != 0)) {\n                result.group_ = group_;\n            }\n            if (((from_bitField0_ & 0x00000004) != 0)) {\n                result.version_ = version_;\n            }\n            if (((from_bitField0_ & 0x00000008) != 0)) {\n                result.protocol_ = protocol_;\n            }\n            if (((from_bitField0_ & 0x00000010) != 0)) {\n                result.port_ = port_;\n            }\n            if (((from_bitField0_ & 0x00000020) != 0)) {\n                result.path_ = path_;\n            }\n            if (((from_bitField0_ & 0x00000040) != 0)) {\n                result.params_ = internalGetParams();\n                result.params_.makeImmutable();\n            }\n        }\n\n        @Override\n        public Builder clone() {\n            return super.clone();\n        }\n\n        @Override\n        public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) {\n            return super.setField(field, value);\n        }\n\n        @Override\n        public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) {\n            return super.clearField(field);\n        }\n\n        @Override\n        public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n            return super.clearOneof(oneof);\n        }\n\n        @Override\n        public Builder setRepeatedField(\n                com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) {\n            return super.setRepeatedField(field, index, value);\n        }\n\n        @Override\n        public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) {\n            return super.addRepeatedField(field, value);\n        }\n\n        @Override\n        public Builder mergeFrom(com.google.protobuf.Message other) {\n            if (other instanceof ServiceInfoV2) {\n                return mergeFrom((ServiceInfoV2) other);\n            } else {\n                super.mergeFrom(other);\n                return this;\n            }\n        }\n\n        public Builder mergeFrom(ServiceInfoV2 other) {\n            if (other == ServiceInfoV2.getDefaultInstance()) {\n                return this;\n            }\n            if (!other.getName().isEmpty()) {\n                name_ = other.name_;\n                bitField0_ |= 0x00000001;\n                onChanged();\n            }\n            if (!other.getGroup().isEmpty()) {\n                group_ = other.group_;\n                bitField0_ |= 0x00000002;\n                onChanged();\n            }\n            if (!other.getVersion().isEmpty()) {\n                version_ = other.version_;\n                bitField0_ |= 0x00000004;\n                onChanged();\n            }\n            if (!other.getProtocol().isEmpty()) {\n                protocol_ = other.protocol_;\n                bitField0_ |= 0x00000008;\n                onChanged();\n            }\n            if (other.getPort() != 0) {\n                setPort(other.getPort());\n            }\n            if (!other.getPath().isEmpty()) {\n                path_ = other.path_;\n                bitField0_ |= 0x00000020;\n                onChanged();\n            }\n            internalGetMutableParams().mergeFrom(other.internalGetParams());\n            bitField0_ |= 0x00000040;\n            this.mergeUnknownFields(other.getUnknownFields());\n            onChanged();\n            return this;\n        }\n\n        @Override\n        public final boolean isInitialized() {\n            return true;\n        }\n\n        @Override\n        public Builder mergeFrom(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            if (extensionRegistry == null) {\n                throw new NullPointerException();\n            }\n            try {\n                boolean done = false;\n                while (!done) {\n                    int tag = input.readTag();\n                    switch (tag) {\n                        case 0:\n                            done = true;\n                            break;\n                        case 10: {\n                            name_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000001;\n                            break;\n                        } // case 10\n                        case 18: {\n                            group_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000002;\n                            break;\n                        } // case 18\n                        case 26: {\n                            version_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000004;\n                            break;\n                        } // case 26\n                        case 34: {\n                            protocol_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000008;\n                            break;\n                        } // case 34\n                        case 40: {\n                            port_ = input.readInt32();\n                            bitField0_ |= 0x00000010;\n                            break;\n                        } // case 40\n                        case 50: {\n                            path_ = input.readStringRequireUtf8();\n                            bitField0_ |= 0x00000020;\n                            break;\n                        } // case 50\n                        case 58: {\n                            com.google.protobuf.MapEntry<String, String> params__ = input.readMessage(\n                                    ParamsDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry);\n                            internalGetMutableParams().getMutableMap().put(params__.getKey(), params__.getValue());\n                            bitField0_ |= 0x00000040;\n                            break;\n                        } // case 58\n                        default: {\n                            if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                                done = true; // was an endgroup tag\n                            }\n                            break;\n                        } // default:\n                    } // switch (tag)\n                } // while (!done)\n            } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                throw e.unwrapIOException();\n            } finally {\n                onChanged();\n            } // finally\n            return this;\n        }\n\n        private int bitField0_;\n\n        private Object name_ = \"\";\n\n        /**\n         * <pre>\n         * The service name.\n         * </pre>\n         *\n         * <code>string name = 1;</code>\n         * @return The name.\n         */\n        public String getName() {\n            Object ref = name_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                name_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The service name.\n         * </pre>\n         *\n         * <code>string name = 1;</code>\n         * @return The bytes for name.\n         */\n        public com.google.protobuf.ByteString getNameBytes() {\n            Object ref = name_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                name_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The service name.\n         * </pre>\n         *\n         * <code>string name = 1;</code>\n         * @param value The name to set.\n         * @return This builder for chaining.\n         */\n        public Builder setName(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            name_ = value;\n            bitField0_ |= 0x00000001;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service name.\n         * </pre>\n         *\n         * <code>string name = 1;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearName() {\n            name_ = getDefaultInstance().getName();\n            bitField0_ = (bitField0_ & ~0x00000001);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service name.\n         * </pre>\n         *\n         * <code>string name = 1;</code>\n         * @param value The bytes for name to set.\n         * @return This builder for chaining.\n         */\n        public Builder setNameBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            name_ = value;\n            bitField0_ |= 0x00000001;\n            onChanged();\n            return this;\n        }\n\n        private Object group_ = \"\";\n\n        /**\n         * <pre>\n         * The service group.\n         * </pre>\n         *\n         * <code>string group = 2;</code>\n         * @return The group.\n         */\n        public String getGroup() {\n            Object ref = group_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                group_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The service group.\n         * </pre>\n         *\n         * <code>string group = 2;</code>\n         * @return The bytes for group.\n         */\n        public com.google.protobuf.ByteString getGroupBytes() {\n            Object ref = group_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                group_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The service group.\n         * </pre>\n         *\n         * <code>string group = 2;</code>\n         * @param value The group to set.\n         * @return This builder for chaining.\n         */\n        public Builder setGroup(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            group_ = value;\n            bitField0_ |= 0x00000002;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service group.\n         * </pre>\n         *\n         * <code>string group = 2;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearGroup() {\n            group_ = getDefaultInstance().getGroup();\n            bitField0_ = (bitField0_ & ~0x00000002);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service group.\n         * </pre>\n         *\n         * <code>string group = 2;</code>\n         * @param value The bytes for group to set.\n         * @return This builder for chaining.\n         */\n        public Builder setGroupBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            group_ = value;\n            bitField0_ |= 0x00000002;\n            onChanged();\n            return this;\n        }\n\n        private Object version_ = \"\";\n\n        /**\n         * <pre>\n         * The service version.\n         * </pre>\n         *\n         * <code>string version = 3;</code>\n         * @return The version.\n         */\n        public String getVersion() {\n            Object ref = version_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                version_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The service version.\n         * </pre>\n         *\n         * <code>string version = 3;</code>\n         * @return The bytes for version.\n         */\n        public com.google.protobuf.ByteString getVersionBytes() {\n            Object ref = version_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                version_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The service version.\n         * </pre>\n         *\n         * <code>string version = 3;</code>\n         * @param value The version to set.\n         * @return This builder for chaining.\n         */\n        public Builder setVersion(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            version_ = value;\n            bitField0_ |= 0x00000004;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service version.\n         * </pre>\n         *\n         * <code>string version = 3;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearVersion() {\n            version_ = getDefaultInstance().getVersion();\n            bitField0_ = (bitField0_ & ~0x00000004);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service version.\n         * </pre>\n         *\n         * <code>string version = 3;</code>\n         * @param value The bytes for version to set.\n         * @return This builder for chaining.\n         */\n        public Builder setVersionBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            version_ = value;\n            bitField0_ |= 0x00000004;\n            onChanged();\n            return this;\n        }\n\n        private Object protocol_ = \"\";\n\n        /**\n         * <pre>\n         * The service protocol.\n         * </pre>\n         *\n         * <code>string protocol = 4;</code>\n         * @return The protocol.\n         */\n        public String getProtocol() {\n            Object ref = protocol_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                protocol_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The service protocol.\n         * </pre>\n         *\n         * <code>string protocol = 4;</code>\n         * @return The bytes for protocol.\n         */\n        public com.google.protobuf.ByteString getProtocolBytes() {\n            Object ref = protocol_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                protocol_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The service protocol.\n         * </pre>\n         *\n         * <code>string protocol = 4;</code>\n         * @param value The protocol to set.\n         * @return This builder for chaining.\n         */\n        public Builder setProtocol(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            protocol_ = value;\n            bitField0_ |= 0x00000008;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service protocol.\n         * </pre>\n         *\n         * <code>string protocol = 4;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearProtocol() {\n            protocol_ = getDefaultInstance().getProtocol();\n            bitField0_ = (bitField0_ & ~0x00000008);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service protocol.\n         * </pre>\n         *\n         * <code>string protocol = 4;</code>\n         * @param value The bytes for protocol to set.\n         * @return This builder for chaining.\n         */\n        public Builder setProtocolBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            protocol_ = value;\n            bitField0_ |= 0x00000008;\n            onChanged();\n            return this;\n        }\n\n        private int port_;\n\n        /**\n         * <pre>\n         * The service port.\n         * </pre>\n         *\n         * <code>int32 port = 5;</code>\n         * @return The port.\n         */\n        @Override\n        public int getPort() {\n            return port_;\n        }\n\n        /**\n         * <pre>\n         * The service port.\n         * </pre>\n         *\n         * <code>int32 port = 5;</code>\n         * @param value The port to set.\n         * @return This builder for chaining.\n         */\n        public Builder setPort(int value) {\n\n            port_ = value;\n            bitField0_ |= 0x00000010;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service port.\n         * </pre>\n         *\n         * <code>int32 port = 5;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearPort() {\n            bitField0_ = (bitField0_ & ~0x00000010);\n            port_ = 0;\n            onChanged();\n            return this;\n        }\n\n        private Object path_ = \"\";\n\n        /**\n         * <pre>\n         * The service path.\n         * </pre>\n         *\n         * <code>string path = 6;</code>\n         * @return The path.\n         */\n        public String getPath() {\n            Object ref = path_;\n            if (!(ref instanceof String)) {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                String s = bs.toStringUtf8();\n                path_ = s;\n                return s;\n            } else {\n                return (String) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The service path.\n         * </pre>\n         *\n         * <code>string path = 6;</code>\n         * @return The bytes for path.\n         */\n        public com.google.protobuf.ByteString getPathBytes() {\n            Object ref = path_;\n            if (ref instanceof String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n                path_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        /**\n         * <pre>\n         * The service path.\n         * </pre>\n         *\n         * <code>string path = 6;</code>\n         * @param value The path to set.\n         * @return This builder for chaining.\n         */\n        public Builder setPath(String value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            path_ = value;\n            bitField0_ |= 0x00000020;\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service path.\n         * </pre>\n         *\n         * <code>string path = 6;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearPath() {\n            path_ = getDefaultInstance().getPath();\n            bitField0_ = (bitField0_ & ~0x00000020);\n            onChanged();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * The service path.\n         * </pre>\n         *\n         * <code>string path = 6;</code>\n         * @param value The bytes for path to set.\n         * @return This builder for chaining.\n         */\n        public Builder setPathBytes(com.google.protobuf.ByteString value) {\n            if (value == null) {\n                throw new NullPointerException();\n            }\n            checkByteStringIsUtf8(value);\n            path_ = value;\n            bitField0_ |= 0x00000020;\n            onChanged();\n            return this;\n        }\n\n        private com.google.protobuf.MapField<String, String> params_;\n\n        private com.google.protobuf.MapField<String, String> internalGetParams() {\n            if (params_ == null) {\n                return com.google.protobuf.MapField.emptyMapField(ParamsDefaultEntryHolder.defaultEntry);\n            }\n            return params_;\n        }\n\n        private com.google.protobuf.MapField<String, String> internalGetMutableParams() {\n            if (params_ == null) {\n                params_ = com.google.protobuf.MapField.newMapField(ParamsDefaultEntryHolder.defaultEntry);\n            }\n            if (!params_.isMutable()) {\n                params_ = params_.copy();\n            }\n            bitField0_ |= 0x00000040;\n            onChanged();\n            return params_;\n        }\n\n        public int getParamsCount() {\n            return internalGetParams().getMap().size();\n        }\n\n        /**\n         * <pre>\n         * A map of service parameters.\n         * </pre>\n         *\n         * <code>map&lt;string, string&gt; params = 7;</code>\n         */\n        @Override\n        public boolean containsParams(String key) {\n            if (key == null) {\n                throw new NullPointerException(\"map key\");\n            }\n            return internalGetParams().getMap().containsKey(key);\n        }\n\n        /**\n         * Use {@link #getParamsMap()} instead.\n         */\n        @Override\n        @Deprecated\n        public java.util.Map<String, String> getParams() {\n            return getParamsMap();\n        }\n\n        /**\n         * <pre>\n         * A map of service parameters.\n         * </pre>\n         *\n         * <code>map&lt;string, string&gt; params = 7;</code>\n         */\n        @Override\n        public java.util.Map<String, String> getParamsMap() {\n            return internalGetParams().getMap();\n        }\n\n        /**\n         * <pre>\n         * A map of service parameters.\n         * </pre>\n         *\n         * <code>map&lt;string, string&gt; params = 7;</code>\n         */\n        @Override\n        public /* nullable */ String getParamsOrDefault(\n                String key,\n                /* nullable */\n                String defaultValue) {\n            if (key == null) {\n                throw new NullPointerException(\"map key\");\n            }\n            java.util.Map<String, String> map = internalGetParams().getMap();\n            return map.containsKey(key) ? map.get(key) : defaultValue;\n        }\n\n        /**\n         * <pre>\n         * A map of service parameters.\n         * </pre>\n         *\n         * <code>map&lt;string, string&gt; params = 7;</code>\n         */\n        @Override\n        public String getParamsOrThrow(String key) {\n            if (key == null) {\n                throw new NullPointerException(\"map key\");\n            }\n            java.util.Map<String, String> map = internalGetParams().getMap();\n            if (!map.containsKey(key)) {\n                throw new IllegalArgumentException();\n            }\n            return map.get(key);\n        }\n\n        public Builder clearParams() {\n            bitField0_ = (bitField0_ & ~0x00000040);\n            internalGetMutableParams().getMutableMap().clear();\n            return this;\n        }\n\n        /**\n         * <pre>\n         * A map of service parameters.\n         * </pre>\n         *\n         * <code>map&lt;string, string&gt; params = 7;</code>\n         */\n        public Builder removeParams(String key) {\n            if (key == null) {\n                throw new NullPointerException(\"map key\");\n            }\n            internalGetMutableParams().getMutableMap().remove(key);\n            return this;\n        }\n\n        /**\n         * Use alternate mutation accessors instead.\n         */\n        @Deprecated\n        public java.util.Map<String, String> getMutableParams() {\n            bitField0_ |= 0x00000040;\n            return internalGetMutableParams().getMutableMap();\n        }\n\n        /**\n         * <pre>\n         * A map of service parameters.\n         * </pre>\n         *\n         * <code>map&lt;string, string&gt; params = 7;</code>\n         */\n        public Builder putParams(String key, String value) {\n            if (key == null) {\n                throw new NullPointerException(\"map key\");\n            }\n            if (value == null) {\n                throw new NullPointerException(\"map value\");\n            }\n            internalGetMutableParams().getMutableMap().put(key, value);\n            bitField0_ |= 0x00000040;\n            return this;\n        }\n\n        /**\n         * <pre>\n         * A map of service parameters.\n         * </pre>\n         *\n         * <code>map&lt;string, string&gt; params = 7;</code>\n         */\n        public Builder putAllParams(java.util.Map<String, String> values) {\n            internalGetMutableParams().getMutableMap().putAll(values);\n            bitField0_ |= 0x00000040;\n            return this;\n        }\n\n        @Override\n        public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n            return super.setUnknownFields(unknownFields);\n        }\n\n        @Override\n        public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n            return super.mergeUnknownFields(unknownFields);\n        }\n\n        // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.ServiceInfoV2)\n    }\n\n    // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.ServiceInfoV2)\n    private static final ServiceInfoV2 DEFAULT_INSTANCE;\n\n    static {\n        DEFAULT_INSTANCE = new ServiceInfoV2();\n    }\n\n    public static ServiceInfoV2 getDefaultInstance() {\n        return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<ServiceInfoV2> PARSER =\n            new com.google.protobuf.AbstractParser<ServiceInfoV2>() {\n                @Override\n                public ServiceInfoV2 parsePartialFrom(\n                        com.google.protobuf.CodedInputStream input,\n                        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                        throws com.google.protobuf.InvalidProtocolBufferException {\n                    Builder builder = newBuilder();\n                    try {\n                        builder.mergeFrom(input, extensionRegistry);\n                    } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                        throw e.setUnfinishedMessage(builder.buildPartial());\n                    } catch (com.google.protobuf.UninitializedMessageException e) {\n                        throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n                    } catch (java.io.IOException e) {\n                        throw new com.google.protobuf.InvalidProtocolBufferException(e)\n                                .setUnfinishedMessage(builder.buildPartial());\n                    }\n                    return builder.buildPartial();\n                }\n            };\n\n    public static com.google.protobuf.Parser<ServiceInfoV2> parser() {\n        return PARSER;\n    }\n\n    @Override\n    public com.google.protobuf.Parser<ServiceInfoV2> getParserForType() {\n        return PARSER;\n    }\n\n    @Override\n    public ServiceInfoV2 getDefaultInstanceForType() {\n        return DEFAULT_INSTANCE;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2OrBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\npublic interface ServiceInfoV2OrBuilder\n        extends\n        // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.ServiceInfoV2)\n        com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <pre>\n     * The service name.\n     * </pre>\n     *\n     * <code>string name = 1;</code>\n     * @return The name.\n     */\n    String getName();\n\n    /**\n     * <pre>\n     * The service name.\n     * </pre>\n     *\n     * <code>string name = 1;</code>\n     * @return The bytes for name.\n     */\n    com.google.protobuf.ByteString getNameBytes();\n\n    /**\n     * <pre>\n     * The service group.\n     * </pre>\n     *\n     * <code>string group = 2;</code>\n     * @return The group.\n     */\n    String getGroup();\n\n    /**\n     * <pre>\n     * The service group.\n     * </pre>\n     *\n     * <code>string group = 2;</code>\n     * @return The bytes for group.\n     */\n    com.google.protobuf.ByteString getGroupBytes();\n\n    /**\n     * <pre>\n     * The service version.\n     * </pre>\n     *\n     * <code>string version = 3;</code>\n     * @return The version.\n     */\n    String getVersion();\n\n    /**\n     * <pre>\n     * The service version.\n     * </pre>\n     *\n     * <code>string version = 3;</code>\n     * @return The bytes for version.\n     */\n    com.google.protobuf.ByteString getVersionBytes();\n\n    /**\n     * <pre>\n     * The service protocol.\n     * </pre>\n     *\n     * <code>string protocol = 4;</code>\n     * @return The protocol.\n     */\n    String getProtocol();\n\n    /**\n     * <pre>\n     * The service protocol.\n     * </pre>\n     *\n     * <code>string protocol = 4;</code>\n     * @return The bytes for protocol.\n     */\n    com.google.protobuf.ByteString getProtocolBytes();\n\n    /**\n     * <pre>\n     * The service port.\n     * </pre>\n     *\n     * <code>int32 port = 5;</code>\n     * @return The port.\n     */\n    int getPort();\n\n    /**\n     * <pre>\n     * The service path.\n     * </pre>\n     *\n     * <code>string path = 6;</code>\n     * @return The path.\n     */\n    String getPath();\n\n    /**\n     * <pre>\n     * The service path.\n     * </pre>\n     *\n     * <code>string path = 6;</code>\n     * @return The bytes for path.\n     */\n    com.google.protobuf.ByteString getPathBytes();\n\n    /**\n     * <pre>\n     * A map of service parameters.\n     * </pre>\n     *\n     * <code>map&lt;string, string&gt; params = 7;</code>\n     */\n    int getParamsCount();\n\n    /**\n     * <pre>\n     * A map of service parameters.\n     * </pre>\n     *\n     * <code>map&lt;string, string&gt; params = 7;</code>\n     */\n    boolean containsParams(String key);\n\n    /**\n     * Use {@link #getParamsMap()} instead.\n     */\n    @Deprecated\n    java.util.Map<String, String> getParams();\n\n    /**\n     * <pre>\n     * A map of service parameters.\n     * </pre>\n     *\n     * <code>map&lt;string, string&gt; params = 7;</code>\n     */\n    java.util.Map<String, String> getParamsMap();\n\n    /**\n     * <pre>\n     * A map of service parameters.\n     * </pre>\n     *\n     * <code>map&lt;string, string&gt; params = 7;</code>\n     */\n    /* nullable */\n    String getParamsOrDefault(\n            String key,\n            /* nullable */\n            String defaultValue);\n\n    /**\n     * <pre>\n     * A map of service parameters.\n     * </pre>\n     *\n     * <code>map&lt;string, string&gt; params = 7;</code>\n     */\n    String getParamsOrThrow(String key);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMapping.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\nimport org.apache.dubbo.rpc.service.Destroyable;\n\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport static java.util.Collections.emptySet;\nimport static java.util.stream.Collectors.toSet;\nimport static java.util.stream.Stream.of;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;\nimport static org.apache.dubbo.common.extension.ExtensionScope.APPLICATION;\n\n/**\n * This will interact with remote metadata center to find the interface-app mapping and will cache the data locally.\n *\n * Call variants of getCachedMapping() methods whenever need to use the mapping data.\n */\n@SPI(value = \"metadata\", scope = APPLICATION)\npublic interface ServiceNameMapping extends Destroyable {\n\n    String DEFAULT_MAPPING_GROUP = \"mapping\";\n\n    /**\n     * Map the specified Dubbo service interface, group, version and protocol to current Dubbo service name\n     */\n    boolean map(URL url);\n\n    boolean hasValidMetadataCenter();\n\n    /**\n     * Get the default extension of {@link ServiceNameMapping}\n     *\n     * @return non-null {@link ServiceNameMapping}\n     */\n    static ServiceNameMapping getDefaultExtension(ScopeModel scopeModel) {\n        return ScopeModelUtil.getApplicationModel(scopeModel).getDefaultExtension(ServiceNameMapping.class);\n    }\n\n    static String buildMappingKey(URL url) {\n        return buildGroup(url.getServiceInterface());\n    }\n\n    static String buildGroup(String serviceInterface) {\n        // the issue : https://github.com/apache/dubbo/issues/4671\n        //        return DEFAULT_MAPPING_GROUP + SLASH + serviceInterface;\n        return serviceInterface;\n    }\n\n    static String toStringKeys(Set<String> serviceNames) {\n        if (CollectionUtils.isEmpty(serviceNames)) {\n            return \"\";\n        }\n\n        StringBuilder builder = new StringBuilder();\n        for (String n : serviceNames) {\n            builder.append(n);\n            builder.append(COMMA_SEPARATOR);\n        }\n\n        builder.deleteCharAt(builder.length() - 1);\n        return builder.toString();\n    }\n\n    static Set<String> getAppNames(String content) {\n        if (StringUtils.isBlank(content)) {\n            return emptySet();\n        }\n        return new TreeSet<>(of(content.split(COMMA_SEPARATOR))\n                .map(String::trim)\n                .filter(StringUtils::isNotEmpty)\n                .collect(toSet()));\n    }\n\n    static Set<String> getMappingByUrl(URL consumerURL) {\n        String providedBy = consumerURL.getParameter(RegistryConstants.PROVIDED_BY);\n        if (StringUtils.isBlank(providedBy)) {\n            return null;\n        }\n        return AbstractServiceNameMapping.parseServices(providedBy);\n    }\n\n    /**\n     * Get the latest mapping result from remote center and register listener at the same time to get notified once mapping changes.\n     *\n     * @param listener listener that will be notified on mapping change\n     * @return the latest mapping result from remote center\n     */\n    Set<String> getAndListen(URL registryURL, URL subscribedURL, MappingListener listener);\n\n    MappingListener stopListen(URL subscribeURL, MappingListener listener);\n\n    void putCachedMapping(String serviceKey, Set<String> apps);\n\n    Set<String> getMapping(URL consumerURL);\n\n    Set<String> getRemoteMapping(URL consumerURL);\n\n    Set<String> removeCachedMapping(String serviceKey);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/aot/MetadataProxyDescriberRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.aot;\n\nimport org.apache.dubbo.aot.api.JdkProxyDescriber;\nimport org.apache.dubbo.aot.api.ProxyDescriberRegistrar;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.metadata.MetadataServiceV2;\nimport org.apache.dubbo.rpc.service.Destroyable;\nimport org.apache.dubbo.rpc.service.EchoService;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class MetadataProxyDescriberRegistrar implements ProxyDescriberRegistrar {\n    @Override\n    public List<JdkProxyDescriber> getJdkProxyDescribers() {\n        List<JdkProxyDescriber> describers = new ArrayList<>();\n        describers.add(buildJdkProxyDescriber(MetadataService.class));\n        describers.add(buildJdkProxyDescriber(MetadataServiceV2.class));\n        return describers;\n    }\n\n    private JdkProxyDescriber buildJdkProxyDescriber(Class<?> cl) {\n        List<String> proxiedInterfaces = new ArrayList<>();\n        proxiedInterfaces.add(cl.getName());\n        proxiedInterfaces.add(EchoService.class.getName());\n        proxiedInterfaces.add(Destroyable.class.getName());\n        return new JdkProxyDescriber(proxiedInterfaces, null);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/aot/MetadataReflectionTypeDescriberRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.aot;\n\nimport org.apache.dubbo.aot.api.MemberCategory;\nimport org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;\nimport org.apache.dubbo.aot.api.TypeDescriber;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataInfoV2;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.metadata.MetadataServiceV2;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class MetadataReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {\n\n    @Override\n    public List<TypeDescriber> getTypeDescribers() {\n        List<TypeDescriber> typeDescribers = new ArrayList<>();\n        typeDescribers.add(buildTypeDescriberWithPublicMethod(MetadataService.class));\n        typeDescribers.add(buildTypeDescriberWithPublicMethod(MetadataServiceV2.class));\n        typeDescribers.add(buildTypeDescriberWithDeclaredConstructors(MetadataInfo.class));\n        typeDescribers.add(buildTypeDescriberWithDeclaredConstructors(MetadataInfoV2.class));\n        return typeDescribers;\n    }\n\n    private TypeDescriber buildTypeDescriberWithPublicMethod(Class<?> cl) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_PUBLIC_METHODS);\n        return new TypeDescriber(\n                cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n\n    private TypeDescriber buildTypeDescriberWithDeclaredConstructors(Class<?> cl) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n        return new TypeDescriber(\n                cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.metadata.MappingListener;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\nimport org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic interface MetadataReport {\n    /**\n     * Service Definition -- START\n     **/\n    void storeProviderMetadata(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition);\n\n    String getServiceDefinition(MetadataIdentifier metadataIdentifier);\n\n    /**\n     * Application Metadata -- START\n     **/\n    default void publishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) {}\n\n    default void unPublishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) {}\n\n    default MetadataInfo getAppMetadata(SubscriberMetadataIdentifier identifier, Map<String, String> instanceMetadata) {\n        return null;\n    }\n\n    /**\n     * deprecated or need triage\n     **/\n    void storeConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, Map<String, String> serviceParameterMap);\n\n    List<String> getExportedURLs(ServiceMetadataIdentifier metadataIdentifier);\n\n    void destroy();\n\n    void saveServiceMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url);\n\n    void removeServiceMetadata(ServiceMetadataIdentifier metadataIdentifier);\n\n    void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, Set<String> urls);\n\n    List<String> getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier);\n\n    default ConfigItem getConfigItem(String key, String group) {\n        return new ConfigItem();\n    }\n\n    default boolean registerServiceAppMapping(\n            String serviceInterface, String defaultMappingGroup, String newConfigContent, Object ticket) {\n        return false;\n    }\n\n    default boolean registerServiceAppMapping(String serviceKey, String application, URL url) {\n        return false;\n    }\n\n    default void removeServiceAppMappingListener(String serviceKey, MappingListener listener) {}\n\n    /**\n     * Service<-->Application Mapping -- START\n     **/\n    default Set<String> getServiceAppMapping(String serviceKey, MappingListener listener, URL url) {\n        return Collections.emptySet();\n    }\n\n    default Set<String> getServiceAppMapping(String serviceKey, URL url) {\n        return Collections.emptySet();\n    }\n\n    boolean shouldReportDefinition();\n\n    boolean shouldReportMetadata();\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReportFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.metadata.report.MetadataReportFactory.DEFAULT;\n\n/**\n */\n@SPI(DEFAULT)\npublic interface MetadataReportFactory {\n\n    String DEFAULT = \"redis\";\n\n    @Adaptive({PROTOCOL_KEY})\n    MetadataReport getMetadataReport(URL url);\n\n    default void destroy() {}\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReportInstance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.metadata.report.support.NopMetadataReport;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_DIRECTORY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\nimport static org.apache.dubbo.metadata.MetadataConstants.NAMESPACE_KEY;\nimport static org.apache.dubbo.metadata.report.support.Constants.METADATA_REPORT_KEY;\n\n/**\n * Repository of MetadataReport instances that can talk to remote metadata server.\n *\n * MetadataReport instances are initiated during the beginning of deployer.start() and used by components that\n * need to interact with metadata server.\n *\n * If multiple metadata reports and registries need to be declared, it is recommended to group each two metadata report and registry together by giving them the same id:\n * <dubbo:registry id=demo1 address=\"registry://\"/>\n * <dubbo:metadata id=demo1 address=\"metadata://\"/>\n *\n * <dubbo:registry id=demo2 address=\"registry://\"/>\n * <dubbo:metadata id=demo2 address=\"metadata://\"/>\n */\npublic class MetadataReportInstance implements Disposable {\n\n    private final AtomicBoolean initialized = new AtomicBoolean(false);\n    private String metadataType;\n\n    // mapping of registry id to metadata report instance, registry instances will use this mapping to find related\n    // metadata reports\n    private final Map<String, MetadataReport> metadataReports = new HashMap<>();\n    private final ApplicationModel applicationModel;\n    private final NopMetadataReport nopMetadataReport;\n\n    public MetadataReportInstance(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        this.nopMetadataReport = new NopMetadataReport();\n    }\n\n    public void init(List<MetadataReportConfig> metadataReportConfigs) {\n        if (!initialized.compareAndSet(false, true)) {\n            return;\n        }\n\n        this.metadataType = applicationModel\n                .getApplicationConfigManager()\n                .getApplicationOrElseThrow()\n                .getMetadataType();\n        if (metadataType == null) {\n            this.metadataType = DEFAULT_METADATA_STORAGE_TYPE;\n        }\n\n        MetadataReportFactory metadataReportFactory =\n                applicationModel.getExtensionLoader(MetadataReportFactory.class).getAdaptiveExtension();\n        for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) {\n            init(metadataReportConfig, metadataReportFactory);\n        }\n    }\n\n    private void init(MetadataReportConfig config, MetadataReportFactory metadataReportFactory) {\n        URL url = config.toUrl();\n        if (METADATA_REPORT_KEY.equals(url.getProtocol())) {\n            String protocol = url.getParameter(METADATA_REPORT_KEY, DEFAULT_DIRECTORY);\n            url = URLBuilder.from(url)\n                    .setProtocol(protocol)\n                    .setPort(url.getParameter(PORT_KEY, url.getPort()))\n                    .setScopeModel(config.getScopeModel())\n                    .removeParameter(METADATA_REPORT_KEY)\n                    .build();\n        }\n        url = url.addParameterIfAbsent(\n                APPLICATION_KEY, applicationModel.getCurrentConfig().getName());\n        url = url.addParameterIfAbsent(\n                REGISTRY_LOCAL_FILE_CACHE_ENABLED,\n                String.valueOf(applicationModel.getCurrentConfig().getEnableFileCache()));\n        //        RegistryConfig registryConfig = applicationModel.getConfigManager().getRegistry(relatedRegistryId)\n        //                .orElseThrow(() -> new IllegalStateException(\"Registry id \" + relatedRegistryId + \" does not\n        // exist.\"));\n        MetadataReport metadataReport = metadataReportFactory.getMetadataReport(url);\n        if (metadataReport != null) {\n            metadataReports.put(getRelatedRegistryId(config, url), metadataReport);\n        }\n    }\n\n    private String getRelatedRegistryId(MetadataReportConfig config, URL url) {\n        String relatedRegistryId = config.getRegistry();\n        if (isEmpty(relatedRegistryId)) {\n            relatedRegistryId = config.getId();\n        }\n        if (isEmpty(relatedRegistryId)) {\n            relatedRegistryId = DEFAULT_KEY;\n        }\n        String namespace = url.getParameter(NAMESPACE_KEY);\n        if (!StringUtils.isEmpty(namespace)) {\n            relatedRegistryId += \":\" + namespace;\n        }\n        return relatedRegistryId;\n    }\n\n    public Map<String, MetadataReport> getMetadataReports(boolean checked) {\n        return metadataReports;\n    }\n\n    public MetadataReport getMetadataReport(String registryKey) {\n        MetadataReport metadataReport = metadataReports.get(registryKey);\n        if (metadataReport == null && metadataReports.size() > 0) {\n            metadataReport = metadataReports.values().iterator().next();\n        }\n        return metadataReport;\n    }\n\n    public MetadataReport getNopMetadataReport() {\n        return nopMetadataReport;\n    }\n\n    public String getMetadataType() {\n        return metadataType;\n    }\n\n    public boolean isInitialized() {\n        return initialized.get();\n    }\n\n    @Override\n    public void destroy() {\n        metadataReports.forEach((k, reporter) -> reporter.destroy());\n        metadataReports.clear();\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\npublic class MetadataScopeModelInitializer implements ScopeModelInitializer {\n\n    @Override\n    public void initializeApplicationModel(ApplicationModel applicationModel) {\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        beanFactory.registerBean(MetadataReportInstance.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/BaseApplicationMetadataIdentifier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport java.util.Objects;\n\nimport static org.apache.dubbo.metadata.MetadataConstants.DEFAULT_PATH_TAG;\n\n/**\n * The Base class of MetadataIdentifier for application scope\n * <p>\n * 2019-08-09\n */\npublic class BaseApplicationMetadataIdentifier {\n    protected String application;\n\n    protected String getUniqueKey(KeyTypeEnum keyType, String... params) {\n        if (keyType == KeyTypeEnum.PATH) {\n            return getFilePathKey(params);\n        }\n        return getIdentifierKey(params);\n    }\n\n    protected String getIdentifierKey(String... params) {\n        return KeyTypeEnum.UNIQUE_KEY.build(application, params);\n    }\n\n    private String getFilePathKey(String... params) {\n        return getFilePathKey(DEFAULT_PATH_TAG, params);\n    }\n\n    private String getFilePathKey(String pathTag, String... params) {\n        String prefix = KeyTypeEnum.PATH.build(pathTag, application);\n        return KeyTypeEnum.PATH.build(prefix, params);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof BaseApplicationMetadataIdentifier)) return false;\n        BaseApplicationMetadataIdentifier that = (BaseApplicationMetadataIdentifier) o;\n        return Objects.equals(application, that.application);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(application);\n    }\n\n    @Override\n    public String toString() {\n        return \"BaseApplicationMetadataIdentifier{\" + \"application='\" + application + '\\'' + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/BaseMetadataIdentifier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\npublic interface BaseMetadataIdentifier {\n\n    String getUniqueKey(KeyTypeEnum keyType);\n\n    String getIdentifierKey();\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/BaseServiceMetadataIdentifier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.Objects;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.metadata.MetadataConstants.DEFAULT_PATH_TAG;\n\n/**\n * The Base class of MetadataIdentifier for service scope\n * <p>\n * 2019-08-09\n */\npublic class BaseServiceMetadataIdentifier {\n    protected String serviceInterface;\n    protected String version;\n    protected String group;\n    protected String side;\n\n    protected String getUniqueKey(KeyTypeEnum keyType, String... params) {\n        if (keyType == KeyTypeEnum.PATH) {\n            return getFilePathKey(params);\n        }\n        return getIdentifierKey(params);\n    }\n\n    protected String getIdentifierKey(String... params) {\n        String prefix = KeyTypeEnum.UNIQUE_KEY.build(serviceInterface, version, group, side);\n        return KeyTypeEnum.UNIQUE_KEY.build(prefix, params);\n    }\n\n    private String getFilePathKey(String... params) {\n        return getFilePathKey(DEFAULT_PATH_TAG, params);\n    }\n\n    private String getFilePathKey(String pathTag, String... params) {\n        String prefix = KeyTypeEnum.PATH.build(pathTag, toServicePath(), version, group, side);\n        return KeyTypeEnum.PATH.build(prefix, params);\n    }\n\n    private String toServicePath() {\n        if (ANY_VALUE.equals(serviceInterface)) {\n            return \"\";\n        }\n        return URL.encode(serviceInterface);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof BaseServiceMetadataIdentifier)) return false;\n        BaseServiceMetadataIdentifier that = (BaseServiceMetadataIdentifier) o;\n        return Objects.equals(serviceInterface, that.serviceInterface)\n                && Objects.equals(version, that.version)\n                && Objects.equals(group, that.group)\n                && Objects.equals(side, that.side);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(serviceInterface, version, group, side);\n    }\n\n    @Override\n    public String toString() {\n        return \"BaseServiceMetadataIdentifier{\" + \"serviceInterface='\" + serviceInterface + '\\'' + \", version='\"\n                + version + '\\'' + \", group='\" + group + '\\'' + \", side='\" + side + '\\'' + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/KeyTypeEnum.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;\nimport static org.apache.dubbo.common.utils.PathUtils.buildPath;\nimport static org.apache.dubbo.common.utils.StringUtils.EMPTY_STRING;\nimport static org.apache.dubbo.common.utils.StringUtils.isBlank;\nimport static org.apache.dubbo.metadata.MetadataConstants.KEY_SEPARATOR;\n\n/**\n * 2019-08-15\n */\npublic enum KeyTypeEnum {\n    PATH(PATH_SEPARATOR) {\n        public String build(String one, String... others) {\n            return buildPath(one, others);\n        }\n    },\n\n    UNIQUE_KEY(KEY_SEPARATOR) {\n        public String build(String one, String... others) {\n            StringBuilder keyBuilder = new StringBuilder(one);\n            for (String other : others) {\n                keyBuilder.append(separator).append(isBlank(other) ? EMPTY_STRING : other);\n            }\n            return keyBuilder.toString();\n        }\n    };\n\n    final String separator;\n\n    KeyTypeEnum(String separator) {\n        this.separator = separator;\n    }\n\n    /**\n     * Build Key\n     *\n     * @param one    one\n     * @param others the others\n     * @return\n     * @since 2.7.8\n     */\n    public abstract String build(String one, String... others);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.Objects;\n\n/**\n * The MetadataIdentifier is used to store method descriptor.\n * <p>\n * The name of class is reserved because of it has been used in the previous version.\n * <p>\n * 2018/10/25\n */\npublic class MetadataIdentifier extends BaseServiceMetadataIdentifier implements BaseMetadataIdentifier {\n\n    private String application;\n\n    public MetadataIdentifier() {}\n\n    public MetadataIdentifier(String serviceInterface, String version, String group, String side, String application) {\n        this.serviceInterface = serviceInterface;\n        this.version = version;\n        this.group = group;\n        this.side = side;\n        this.application = application;\n    }\n\n    public MetadataIdentifier(URL url) {\n        this.serviceInterface = url.getServiceInterface();\n        this.version = url.getVersion();\n        this.group = url.getGroup();\n        this.side = url.getSide();\n        setApplication(url.getApplication());\n    }\n\n    public String getUniqueKey(KeyTypeEnum keyType) {\n        return super.getUniqueKey(keyType, application);\n    }\n\n    public String getIdentifierKey() {\n        return super.getIdentifierKey(application);\n    }\n\n    public String getServiceInterface() {\n        return serviceInterface;\n    }\n\n    public void setServiceInterface(String serviceInterface) {\n        this.serviceInterface = serviceInterface;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public String getSide() {\n        return side;\n    }\n\n    public void setSide(String side) {\n        this.side = side;\n    }\n\n    public String getApplication() {\n        return application;\n    }\n\n    public void setApplication(String application) {\n        this.application = application;\n    }\n\n    public String getUniqueServiceName() {\n        return serviceInterface != null ? URL.buildKey(serviceInterface, getGroup(), getVersion()) : null;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof MetadataIdentifier)) return false;\n        if (!super.equals(o)) return false;\n        MetadataIdentifier that = (MetadataIdentifier) o;\n        return Objects.equals(application, that.application);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), application);\n    }\n\n    @Override\n    public String toString() {\n        return \"MetadataIdentifier{\" + \"application='\"\n                + application + '\\'' + \", serviceInterface='\"\n                + serviceInterface + '\\'' + \", version='\"\n                + version + '\\'' + \", group='\"\n                + group + '\\'' + \", side='\"\n                + side + '\\'' + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/ServiceMetadataIdentifier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.Objects;\n\nimport static org.apache.dubbo.metadata.MetadataConstants.KEY_REVISION_PREFIX;\n\n/**\n * The ServiceMetadataIdentifier is used to store the {@link org.apache.dubbo.common.URL}\n * that are from provider and consumer\n * <p>\n * 2019-08-09\n */\npublic class ServiceMetadataIdentifier extends BaseServiceMetadataIdentifier implements BaseMetadataIdentifier {\n\n    private String revision;\n    private String protocol;\n\n    public ServiceMetadataIdentifier() {}\n\n    public ServiceMetadataIdentifier(\n            String serviceInterface, String version, String group, String side, String revision, String protocol) {\n        this.serviceInterface = serviceInterface;\n        this.version = version;\n        this.group = group;\n        this.side = side;\n        this.revision = revision;\n        this.protocol = protocol;\n    }\n\n    public ServiceMetadataIdentifier(URL url) {\n        this.serviceInterface = url.getServiceInterface();\n        this.version = url.getVersion();\n        this.group = url.getGroup();\n        this.side = url.getSide();\n        this.protocol = url.getProtocol();\n    }\n\n    public String getUniqueKey(KeyTypeEnum keyType) {\n        return super.getUniqueKey(keyType, protocol, KEY_REVISION_PREFIX + revision);\n    }\n\n    public String getIdentifierKey() {\n        return super.getIdentifierKey(protocol, KEY_REVISION_PREFIX + revision);\n    }\n\n    public void setRevision(String revision) {\n        this.revision = revision;\n    }\n\n    public void setProtocol(String protocol) {\n        this.protocol = protocol;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof ServiceMetadataIdentifier)) return false;\n        if (!super.equals(o)) return false;\n        ServiceMetadataIdentifier that = (ServiceMetadataIdentifier) o;\n        return Objects.equals(revision, that.revision) && Objects.equals(protocol, that.protocol);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), revision, protocol);\n    }\n\n    @Override\n    public String toString() {\n        return \"ServiceMetadataIdentifier{\" + \"revision='\"\n                + revision + '\\'' + \", protocol='\"\n                + protocol + '\\'' + \", serviceInterface='\"\n                + serviceInterface + '\\'' + \", version='\"\n                + version + '\\'' + \", group='\"\n                + group + '\\'' + \", side='\"\n                + side + '\\'' + \"} \"\n                + super.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/SubscriberMetadataIdentifier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.Objects;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;\n\n/**\n * 2019-08-12\n */\npublic class SubscriberMetadataIdentifier extends BaseApplicationMetadataIdentifier implements BaseMetadataIdentifier {\n\n    private String revision;\n\n    public SubscriberMetadataIdentifier() {}\n\n    public SubscriberMetadataIdentifier(String application, String revision) {\n        this.application = application;\n        this.revision = revision;\n    }\n\n    public SubscriberMetadataIdentifier(URL url) {\n        this.application = url.getApplication(\"\");\n        this.revision = url.getParameter(REVISION_KEY, \"\");\n    }\n\n    public String getUniqueKey(KeyTypeEnum keyType) {\n        return super.getUniqueKey(keyType, revision);\n    }\n\n    public String getIdentifierKey() {\n        return super.getIdentifierKey(revision);\n    }\n\n    public String getApplication() {\n        return application;\n    }\n\n    public void setApplication(String application) {\n        this.application = application;\n    }\n\n    public String getRevision() {\n        return revision;\n    }\n\n    public void setRevision(String revision) {\n        this.revision = revision;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof SubscriberMetadataIdentifier)) return false;\n        if (!super.equals(o)) return false;\n        SubscriberMetadataIdentifier that = (SubscriberMetadataIdentifier) o;\n        return Objects.equals(revision, that.revision);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), revision);\n    }\n\n    @Override\n    public String toString() {\n        return \"SubscriberMetadataIdentifier{\" + \"revision='\" + revision + '\\'' + \", application='\" + application + '\\''\n                + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;\nimport org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.metadata.event.MetadataEvent;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileLock;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.CYCLE_REPORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED;\nimport static org.apache.dubbo.common.constants.CommonConstants.REPORT_DEFINITION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REPORT_METADATA_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RETRY_PERIOD_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RETRY_TIMES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SYNC_REPORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.USER_HOME;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROXY_FAILED_EXPORT_SERVICE;\nimport static org.apache.dubbo.common.utils.StringUtils.replace;\nimport static org.apache.dubbo.metadata.report.support.Constants.CACHE;\nimport static org.apache.dubbo.metadata.report.support.Constants.DEFAULT_METADATA_REPORT_CYCLE_REPORT;\nimport static org.apache.dubbo.metadata.report.support.Constants.DEFAULT_METADATA_REPORT_RETRY_PERIOD;\nimport static org.apache.dubbo.metadata.report.support.Constants.DEFAULT_METADATA_REPORT_RETRY_TIMES;\nimport static org.apache.dubbo.metadata.report.support.Constants.DUBBO_METADATA;\n\npublic abstract class AbstractMetadataReport implements MetadataReport {\n\n    protected static final String DEFAULT_ROOT = \"dubbo\";\n\n    protected static final int ONE_DAY_IN_MILLISECONDS = 60 * 24 * 60 * 1000;\n    private static final int FOUR_HOURS_IN_MILLISECONDS = 60 * 4 * 60 * 1000;\n    // Log output\n    protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    // Local disk cache, where the special key value.registries records the list of metadata centers, and the others are\n    // the list of notified service providers\n    final Properties properties = new Properties();\n    private final ExecutorService reportCacheExecutor =\n            Executors.newFixedThreadPool(1, new NamedThreadFactory(\"DubboSaveMetadataReport\", true));\n    final Map<MetadataIdentifier, Object> allMetadataReports = new ConcurrentHashMap<>(4);\n\n    private final AtomicLong lastCacheChanged = new AtomicLong();\n    final Map<MetadataIdentifier, Object> failedReports = new ConcurrentHashMap<>(4);\n    private URL reportURL;\n    boolean syncReport;\n    // Local disk cache file\n    File file;\n    private AtomicBoolean initialized = new AtomicBoolean(false);\n    public MetadataReportRetry metadataReportRetry;\n    private ScheduledExecutorService reportTimerScheduler;\n\n    private final boolean reportMetadata;\n    private final boolean reportDefinition;\n    protected ApplicationModel applicationModel;\n\n    public AbstractMetadataReport(URL reportServerURL) {\n        setUrl(reportServerURL);\n        applicationModel = reportServerURL.getOrDefaultApplicationModel();\n\n        boolean localCacheEnabled = reportServerURL.getParameter(REGISTRY_LOCAL_FILE_CACHE_ENABLED, true);\n        // Start file save timer\n        String defaultFilename = SystemPropertyConfigUtils.getSystemProperty(USER_HOME) + DUBBO_METADATA\n                + reportServerURL.getApplication()\n                + \"-\" + replace(reportServerURL.getAddress(), \":\", \"-\")\n                + CACHE;\n        String filename = reportServerURL.getParameter(FILE_KEY, defaultFilename);\n        File file = null;\n        if (localCacheEnabled && ConfigUtils.isNotEmpty(filename)) {\n            file = new File(filename);\n            if (!file.exists()\n                    && file.getParentFile() != null\n                    && !file.getParentFile().exists()) {\n                if (!file.getParentFile().mkdirs()) {\n                    throw new IllegalArgumentException(\"Invalid service store file \" + file\n                            + \", cause: Failed to create directory \" + file.getParentFile() + \"!\");\n                }\n            }\n            // if this file exists, firstly delete it.\n            if (!initialized.getAndSet(true) && file.exists()) {\n                file.delete();\n            }\n        }\n        this.file = file;\n        loadProperties();\n        syncReport = reportServerURL.getParameter(SYNC_REPORT_KEY, false);\n        metadataReportRetry = new MetadataReportRetry(\n                reportServerURL.getParameter(RETRY_TIMES_KEY, DEFAULT_METADATA_REPORT_RETRY_TIMES),\n                reportServerURL.getParameter(RETRY_PERIOD_KEY, DEFAULT_METADATA_REPORT_RETRY_PERIOD));\n        // cycle report the data switch\n        if (reportServerURL.getParameter(CYCLE_REPORT_KEY, DEFAULT_METADATA_REPORT_CYCLE_REPORT)) {\n            reportTimerScheduler = Executors.newSingleThreadScheduledExecutor(\n                    new NamedThreadFactory(\"DubboMetadataReportTimer\", true));\n            reportTimerScheduler.scheduleAtFixedRate(\n                    this::publishAll, calculateStartTime(), ONE_DAY_IN_MILLISECONDS, TimeUnit.MILLISECONDS);\n        }\n\n        this.reportMetadata = reportServerURL.getParameter(REPORT_METADATA_KEY, false);\n        this.reportDefinition = reportServerURL.getParameter(REPORT_DEFINITION_KEY, true);\n    }\n\n    public URL getUrl() {\n        return reportURL;\n    }\n\n    protected void setUrl(URL url) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"metadataReport url == null\");\n        }\n        this.reportURL = url;\n    }\n\n    private void doSaveProperties(long version) {\n        if (version < lastCacheChanged.get()) {\n            return;\n        }\n        if (file == null) {\n            return;\n        }\n        // Save\n        try {\n            File lockfile = new File(file.getAbsolutePath() + \".lock\");\n            if (!lockfile.exists()) {\n                lockfile.createNewFile();\n            }\n            try (RandomAccessFile raf = new RandomAccessFile(lockfile, \"rw\");\n                    FileChannel channel = raf.getChannel()) {\n                FileLock lock = channel.tryLock();\n                if (lock == null) {\n                    throw new IOException(\n                            \"Can not lock the metadataReport cache file \" + file.getAbsolutePath()\n                                    + \", ignore and retry later, maybe multi java process use the file, please config: dubbo.metadata.file=xxx.properties\");\n                }\n                // Save\n                try {\n                    if (!file.exists()) {\n                        file.createNewFile();\n                    }\n\n                    Properties tmpProperties;\n                    if (!syncReport) {\n                        // When syncReport = false, properties.setProperty and properties.store are called from the same\n                        // thread(reportCacheExecutor), so deep copy is not required\n                        tmpProperties = properties;\n                    } else {\n                        // Using store method and setProperty method of the this.properties will cause lock contention\n                        // under multi-threading, so deep copy a new container\n                        tmpProperties = new Properties();\n                        Set<Map.Entry<Object, Object>> entries = properties.entrySet();\n                        for (Map.Entry<Object, Object> entry : entries) {\n                            tmpProperties.setProperty((String) entry.getKey(), (String) entry.getValue());\n                        }\n                    }\n\n                    try (FileOutputStream outputFile = new FileOutputStream(file)) {\n                        tmpProperties.store(outputFile, \"Dubbo metadataReport Cache\");\n                    }\n                } finally {\n                    lock.release();\n                }\n            }\n        } catch (Throwable e) {\n            if (version < lastCacheChanged.get()) {\n                return;\n            } else {\n                reportCacheExecutor.execute(new SaveProperties(lastCacheChanged.incrementAndGet()));\n            }\n            logger.warn(\n                    COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to save service store file, cause: \" + e.getMessage(),\n                    e);\n        }\n    }\n\n    void loadProperties() {\n        if (file != null && file.exists()) {\n            try (InputStream in = new FileInputStream(file)) {\n                properties.load(in);\n                if (logger.isInfoEnabled()) {\n                    logger.info(\"Load service store file \" + file + \", data: \" + properties);\n                }\n            } catch (Throwable e) {\n                logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"Failed to load service store file\" + file, e);\n            }\n        }\n    }\n\n    private void saveProperties(MetadataIdentifier metadataIdentifier, String value, boolean add, boolean sync) {\n        if (file == null) {\n            return;\n        }\n\n        try {\n            if (add) {\n                properties.setProperty(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), value);\n            } else {\n                properties.remove(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));\n            }\n            long version = lastCacheChanged.incrementAndGet();\n            if (sync) {\n                new SaveProperties(version).run();\n            } else {\n                reportCacheExecutor.execute(new SaveProperties(version));\n            }\n\n        } catch (Throwable t) {\n            logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", t.getMessage(), t);\n        }\n    }\n\n    @Override\n    public String toString() {\n        return getUrl().toString();\n    }\n\n    private class SaveProperties implements Runnable {\n        private long version;\n\n        private SaveProperties(long version) {\n            this.version = version;\n        }\n\n        @Override\n        public void run() {\n            doSaveProperties(version);\n        }\n    }\n\n    @Override\n    public void storeProviderMetadata(\n            MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) {\n        if (syncReport) {\n            storeProviderMetadataTask(providerMetadataIdentifier, serviceDefinition);\n        } else {\n            reportCacheExecutor.execute(() -> storeProviderMetadataTask(providerMetadataIdentifier, serviceDefinition));\n        }\n    }\n\n    private void storeProviderMetadataTask(\n            MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) {\n\n        MetadataEvent metadataEvent = MetadataEvent.toServiceSubscribeEvent(\n                applicationModel, providerMetadataIdentifier.getUniqueServiceName());\n        MetricsEventBus.post(\n                metadataEvent,\n                () -> {\n                    boolean result = true;\n                    try {\n                        if (logger.isInfoEnabled()) {\n                            logger.info(\"[METADATA_REGISTER] store provider metadata. Identifier : \"\n                                    + providerMetadataIdentifier + \"; definition: \" + serviceDefinition);\n                        }\n                        allMetadataReports.put(providerMetadataIdentifier, serviceDefinition);\n                        failedReports.remove(providerMetadataIdentifier);\n                        String data = JsonUtils.toJson(serviceDefinition);\n                        doStoreProviderMetadata(providerMetadataIdentifier, data);\n                        saveProperties(providerMetadataIdentifier, data, true, !syncReport);\n                    } catch (Exception e) {\n                        // retry again. If failed again, throw exception.\n                        failedReports.put(providerMetadataIdentifier, serviceDefinition);\n                        metadataReportRetry.startRetryTask();\n                        logger.error(\n                                PROXY_FAILED_EXPORT_SERVICE,\n                                \"\",\n                                \"\",\n                                \"Failed to put provider metadata \" + providerMetadataIdentifier + \" in  \"\n                                        + serviceDefinition + \", cause: \" + e.getMessage(),\n                                e);\n                        result = false;\n                    }\n                    return result;\n                },\n                aBoolean -> aBoolean);\n    }\n\n    @Override\n    public void storeConsumerMetadata(\n            MetadataIdentifier consumerMetadataIdentifier, Map<String, String> serviceParameterMap) {\n        if (syncReport) {\n            storeConsumerMetadataTask(consumerMetadataIdentifier, serviceParameterMap);\n        } else {\n            reportCacheExecutor.execute(\n                    () -> storeConsumerMetadataTask(consumerMetadataIdentifier, serviceParameterMap));\n        }\n    }\n\n    protected void storeConsumerMetadataTask(\n            MetadataIdentifier consumerMetadataIdentifier, Map<String, String> serviceParameterMap) {\n        try {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"[METADATA_REGISTER] store consumer metadata. Identifier : \" + consumerMetadataIdentifier\n                        + \"; definition: \" + serviceParameterMap);\n            }\n            allMetadataReports.put(consumerMetadataIdentifier, serviceParameterMap);\n            failedReports.remove(consumerMetadataIdentifier);\n\n            String data = JsonUtils.toJson(serviceParameterMap);\n            doStoreConsumerMetadata(consumerMetadataIdentifier, data);\n            saveProperties(consumerMetadataIdentifier, data, true, !syncReport);\n        } catch (Exception e) {\n            // retry again. If failed again, throw exception.\n            failedReports.put(consumerMetadataIdentifier, serviceParameterMap);\n            metadataReportRetry.startRetryTask();\n            logger.error(\n                    PROXY_FAILED_EXPORT_SERVICE,\n                    \"\",\n                    \"\",\n                    \"Failed to put consumer metadata \" + consumerMetadataIdentifier + \";  \" + serviceParameterMap\n                            + \", cause: \" + e.getMessage(),\n                    e);\n        }\n    }\n\n    @Override\n    public void destroy() {\n        if (reportCacheExecutor != null) {\n            reportCacheExecutor.shutdown();\n        }\n        if (reportTimerScheduler != null) {\n            reportTimerScheduler.shutdown();\n        }\n        if (metadataReportRetry != null) {\n            metadataReportRetry.destroy();\n            metadataReportRetry = null;\n        }\n    }\n\n    @Override\n    public void saveServiceMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) {\n        if (syncReport) {\n            doSaveMetadata(metadataIdentifier, url);\n        } else {\n            reportCacheExecutor.execute(() -> doSaveMetadata(metadataIdentifier, url));\n        }\n    }\n\n    @Override\n    public void removeServiceMetadata(ServiceMetadataIdentifier metadataIdentifier) {\n        if (syncReport) {\n            doRemoveMetadata(metadataIdentifier);\n        } else {\n            reportCacheExecutor.execute(() -> doRemoveMetadata(metadataIdentifier));\n        }\n    }\n\n    @Override\n    public List<String> getExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {\n        // TODO, fallback to local cache\n        return doGetExportedURLs(metadataIdentifier);\n    }\n\n    @Override\n    public void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, Set<String> urls) {\n        if (syncReport) {\n            doSaveSubscriberData(subscriberMetadataIdentifier, JsonUtils.toJson(urls));\n        } else {\n            reportCacheExecutor.execute(\n                    () -> doSaveSubscriberData(subscriberMetadataIdentifier, JsonUtils.toJson(urls)));\n        }\n    }\n\n    @Override\n    public List<String> getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {\n        String content = doGetSubscribedURLs(subscriberMetadataIdentifier);\n        return JsonUtils.toJavaList(content, String.class);\n    }\n\n    String getProtocol(URL url) {\n        String protocol = url.getSide();\n        protocol = protocol == null ? url.getProtocol() : protocol;\n        return protocol;\n    }\n\n    /**\n     * @return if need to continue\n     */\n    public boolean retry() {\n        return doHandleMetadataCollection(failedReports);\n    }\n\n    @Override\n    public boolean shouldReportDefinition() {\n        return reportDefinition;\n    }\n\n    @Override\n    public boolean shouldReportMetadata() {\n        return reportMetadata;\n    }\n\n    private boolean doHandleMetadataCollection(Map<MetadataIdentifier, Object> metadataMap) {\n        if (metadataMap.isEmpty()) {\n            return true;\n        }\n        Iterator<Map.Entry<MetadataIdentifier, Object>> iterable =\n                metadataMap.entrySet().iterator();\n        while (iterable.hasNext()) {\n            Map.Entry<MetadataIdentifier, Object> item = iterable.next();\n            if (PROVIDER_SIDE.equals(item.getKey().getSide())) {\n                this.storeProviderMetadata(item.getKey(), (FullServiceDefinition) item.getValue());\n            } else if (CONSUMER_SIDE.equals(item.getKey().getSide())) {\n                this.storeConsumerMetadata(item.getKey(), (Map) item.getValue());\n            }\n        }\n        return false;\n    }\n\n    /**\n     * not private. just for unittest.\n     */\n    void publishAll() {\n        logger.info(\"start to publish all metadata.\");\n        this.doHandleMetadataCollection(allMetadataReports);\n    }\n\n    /**\n     * between 2:00 am to 6:00 am, the time is random.\n     *\n     * @return\n     */\n    long calculateStartTime() {\n        Calendar calendar = Calendar.getInstance();\n        long nowMill = calendar.getTimeInMillis();\n        calendar.set(Calendar.HOUR_OF_DAY, 0);\n        calendar.set(Calendar.MINUTE, 0);\n        calendar.set(Calendar.SECOND, 0);\n        calendar.set(Calendar.MILLISECOND, 0);\n        long subtract = calendar.getTimeInMillis() + ONE_DAY_IN_MILLISECONDS - nowMill;\n        return subtract\n                + (FOUR_HOURS_IN_MILLISECONDS / 2)\n                + ThreadLocalRandom.current().nextInt(FOUR_HOURS_IN_MILLISECONDS);\n    }\n\n    class MetadataReportRetry {\n        protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n        final ScheduledExecutorService retryExecutor =\n                Executors.newScheduledThreadPool(0, new NamedThreadFactory(\"DubboMetadataReportRetryTimer\", true));\n        volatile ScheduledFuture retryScheduledFuture;\n        final AtomicInteger retryCounter = new AtomicInteger(0);\n        // retry task schedule period\n        long retryPeriod;\n        // if no failed report, wait how many times to run retry task.\n        int retryTimesIfNonFail = 600;\n\n        int retryLimit;\n\n        public MetadataReportRetry(int retryTimes, int retryPeriod) {\n            this.retryPeriod = retryPeriod;\n            this.retryLimit = retryTimes;\n        }\n\n        void startRetryTask() {\n            if (retryScheduledFuture == null) {\n                synchronized (retryCounter) {\n                    if (retryScheduledFuture == null) {\n                        retryScheduledFuture = retryExecutor.scheduleWithFixedDelay(\n                                () -> {\n                                    // Check and connect to the metadata\n                                    try {\n                                        int times = retryCounter.incrementAndGet();\n                                        logger.info(\"start to retry task for metadata report. retry times:\" + times);\n                                        if (retry() && times > retryTimesIfNonFail) {\n                                            cancelRetryTask();\n                                        }\n                                        if (times > retryLimit) {\n                                            cancelRetryTask();\n                                        }\n                                    } catch (Throwable t) { // Defensive fault tolerance\n                                        logger.error(\n                                                COMMON_UNEXPECTED_EXCEPTION,\n                                                \"\",\n                                                \"\",\n                                                \"Unexpected error occur at failed retry, cause: \" + t.getMessage(),\n                                                t);\n                                    }\n                                },\n                                500,\n                                retryPeriod,\n                                TimeUnit.MILLISECONDS);\n                    }\n                }\n            }\n        }\n\n        void cancelRetryTask() {\n            if (retryScheduledFuture != null) {\n                retryScheduledFuture.cancel(false);\n            }\n            retryExecutor.shutdown();\n        }\n\n        void destroy() {\n            cancelRetryTask();\n        }\n\n        /**\n         * @deprecated only for test\n         */\n        @Deprecated\n        ScheduledExecutorService getRetryExecutor() {\n            return retryExecutor;\n        }\n    }\n\n    private void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, List<String> urls) {\n        if (CollectionUtils.isEmpty(urls)) {\n            return;\n        }\n        List<String> encodedUrlList = new ArrayList<>(urls.size());\n        for (String url : urls) {\n            encodedUrlList.add(URL.encode(url));\n        }\n        doSaveSubscriberData(subscriberMetadataIdentifier, encodedUrlList);\n    }\n\n    protected abstract void doStoreProviderMetadata(\n            MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions);\n\n    protected abstract void doStoreConsumerMetadata(\n            MetadataIdentifier consumerMetadataIdentifier, String serviceParameterString);\n\n    protected abstract void doSaveMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url);\n\n    protected abstract void doRemoveMetadata(ServiceMetadataIdentifier metadataIdentifier);\n\n    protected abstract List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier);\n\n    protected abstract void doSaveSubscriberData(\n            SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urlListStr);\n\n    protected abstract String doGetSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier);\n\n    /**\n     * @deprecated only for unit test\n     */\n    @Deprecated\n    protected ExecutorService getReportCacheExecutor() {\n        return reportCacheExecutor;\n    }\n\n    /**\n     * @deprecated only for unit test\n     */\n    @Deprecated\n    protected MetadataReportRetry getMetadataReportRetry() {\n        return metadataReportRetry;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.MetadataReportFactory;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROXY_FAILED_EXPORT_SERVICE;\nimport static org.apache.dubbo.metadata.MetadataConstants.NAMESPACE_KEY;\n\npublic abstract class AbstractMetadataReportFactory implements MetadataReportFactory {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(AbstractMetadataReportFactory.class);\n    private static final String EXPORT_KEY = \"export\";\n    private static final String REFER_KEY = \"refer\";\n\n    /**\n     * The lock for the acquisition process of the registry\n     */\n    private final ReentrantLock lock = new ReentrantLock();\n\n    /**\n     * Registry Collection Map<metadataAddress, MetadataReport>\n     */\n    private final Map<String, MetadataReport> serviceStoreMap = new ConcurrentHashMap<>();\n\n    @Override\n    public MetadataReport getMetadataReport(URL url) {\n        url = url.setPath(MetadataReport.class.getName()).removeParameters(EXPORT_KEY, REFER_KEY);\n        String key = url.toServiceString(NAMESPACE_KEY);\n\n        MetadataReport metadataReport = serviceStoreMap.get(key);\n        if (metadataReport != null) {\n            return metadataReport;\n        }\n\n        // Lock the metadata access process to ensure a single instance of the metadata instance\n        lock.lock();\n        try {\n            metadataReport = serviceStoreMap.get(key);\n            if (metadataReport != null) {\n                return metadataReport;\n            }\n            boolean check = url.getParameter(CHECK_KEY, true) && url.getPort() != 0;\n            try {\n                metadataReport = createMetadataReport(url);\n            } catch (Exception e) {\n                if (!check) {\n                    logger.warn(PROXY_FAILED_EXPORT_SERVICE, \"\", \"\", \"The metadata reporter failed to initialize\", e);\n                } else {\n                    throw e;\n                }\n            }\n\n            if (check && metadataReport == null) {\n                throw new IllegalStateException(\"Can not create metadata Report \" + url);\n            }\n            if (metadataReport != null) {\n                serviceStoreMap.put(key, metadataReport);\n            }\n            return metadataReport;\n        } finally {\n            // Release the lock\n            lock.unlock();\n        }\n    }\n\n    @Override\n    public void destroy() {\n        lock.lock();\n        try {\n            for (MetadataReport metadataReport : serviceStoreMap.values()) {\n                try {\n                    metadataReport.destroy();\n                } catch (Throwable ignored) {\n                    // ignored\n                    logger.warn(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", ignored.getMessage(), ignored);\n                }\n            }\n            serviceStoreMap.clear();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    protected abstract MetadataReport createMetadataReport(URL url);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.support;\n\npublic interface Constants {\n    String METADATA_REPORT_KEY = \"metadata\";\n\n    Integer DEFAULT_METADATA_REPORT_RETRY_TIMES = 100;\n\n    Integer DEFAULT_METADATA_REPORT_RETRY_PERIOD = 3000;\n\n    Boolean DEFAULT_METADATA_REPORT_CYCLE_REPORT = true;\n\n    String CACHE = \".cache\";\n\n    String DUBBO_METADATA = \"/.dubbo/dubbo-metadata-\";\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/NopMetadataReport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class NopMetadataReport implements MetadataReport {\n    public NopMetadataReport() {}\n\n    @Override\n    public void storeProviderMetadata(\n            MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) {}\n\n    @Override\n    public String getServiceDefinition(MetadataIdentifier metadataIdentifier) {\n        return null;\n    }\n\n    @Override\n    public void storeConsumerMetadata(\n            MetadataIdentifier consumerMetadataIdentifier, Map<String, String> serviceParameterMap) {}\n\n    @Override\n    public List<String> getExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {\n        return null;\n    }\n\n    @Override\n    public void destroy() {}\n\n    @Override\n    public void saveServiceMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) {}\n\n    @Override\n    public void removeServiceMetadata(ServiceMetadataIdentifier metadataIdentifier) {}\n\n    @Override\n    public void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, Set<String> urls) {}\n\n    @Override\n    public List<String> getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {\n        return null;\n    }\n\n    @Override\n    public boolean shouldReportDefinition() {\n        return true;\n    }\n\n    @Override\n    public boolean shouldReportMetadata() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/util/MetadataServiceVersionUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.util;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataInfo.ServiceInfo;\nimport org.apache.dubbo.metadata.MetadataInfoV2;\nimport org.apache.dubbo.metadata.MetadataServiceV2Detector;\nimport org.apache.dubbo.metadata.ServiceInfoV2;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.TRIPLE;\n\npublic class MetadataServiceVersionUtils {\n\n    public static final String V1 = \"1.0.0\";\n\n    public static final String V2 = \"2.0.0\";\n\n    public static MetadataInfoV2 toV2(MetadataInfo metadataInfo) {\n        if (metadataInfo == null) {\n            return MetadataInfoV2.newBuilder().build();\n        }\n        Map<String, ServiceInfoV2> servicesV2 = new HashMap<>();\n\n        metadataInfo.getServices().forEach((name, serviceInfo) -> servicesV2.put(name, toV2(serviceInfo)));\n        return MetadataInfoV2.newBuilder()\n                .setVersion(ifNullSetEmpty(metadataInfo.getRevision()))\n                .setApp(ifNullSetEmpty(metadataInfo.getApp()))\n                .putAllServices(servicesV2)\n                .build();\n    }\n\n    public static ServiceInfoV2 toV2(ServiceInfo serviceInfo) {\n        if (serviceInfo == null) {\n            return ServiceInfoV2.newBuilder().build();\n        }\n        return ServiceInfoV2.newBuilder()\n                .setVersion(ifNullSetEmpty(serviceInfo.getVersion()))\n                .setGroup(ifNullSetEmpty(serviceInfo.getGroup()))\n                .setName(ifNullSetEmpty(serviceInfo.getName()))\n                .setPort(serviceInfo.getPort())\n                .setPath(ifNullSetEmpty(serviceInfo.getPath()))\n                .setProtocol(ifNullSetEmpty(serviceInfo.getProtocol()))\n                .putAllParams(serviceInfo.getAllParams())\n                .build();\n    }\n\n    private static String ifNullSetEmpty(String value) {\n        return value == null ? \"\" : value;\n    }\n\n    public static MetadataInfo toV1(MetadataInfoV2 metadataInfoV2) {\n        Map<String, ServiceInfoV2> servicesV2Map = metadataInfoV2.getServicesMap();\n        Map<String, ServiceInfo> serviceMap = new HashMap<>(servicesV2Map.size());\n        servicesV2Map.forEach((s, serviceInfoV2) -> serviceMap.put(s, toV1(serviceInfoV2)));\n        return new MetadataInfo(metadataInfoV2.getApp(), metadataInfoV2.getVersion(), serviceMap);\n    }\n\n    public static ServiceInfo toV1(ServiceInfoV2 serviceInfoV2) {\n        ServiceInfo serviceInfo = new ServiceInfo();\n        serviceInfo.setGroup(serviceInfoV2.getGroup());\n        serviceInfo.setVersion(serviceInfoV2.getVersion());\n        serviceInfo.setName(serviceInfoV2.getName());\n        serviceInfo.setPort(serviceInfoV2.getPort());\n        serviceInfo.setParams(serviceInfoV2.getParamsMap());\n        serviceInfo.setProtocol(serviceInfoV2.getProtocol());\n        serviceInfo.setPath(serviceInfoV2.getPath());\n        return serviceInfo;\n    }\n\n    /**\n     * check if we should export MetadataService\n     */\n    public static boolean needExportV1(ApplicationModel applicationModel) {\n        return !MetadataServiceV2Detector.support() || !onlyExportV2(applicationModel);\n    }\n\n    /**\n     * check if we should export MetadataServiceV2\n     */\n    public static boolean needExportV2(ApplicationModel applicationModel) {\n        return MetadataServiceV2Detector.support()\n                && (onlyExportV2(applicationModel) || tripleConfigured(applicationModel));\n    }\n\n    /**\n     * check if we should only export MetadataServiceV2\n     */\n    public static boolean onlyExportV2(ApplicationModel applicationModel) {\n        Optional<ApplicationConfig> applicationConfig = getApplicationConfig(applicationModel);\n        return applicationConfig\n                .filter(config ->\n                        Boolean.TRUE.equals(config.getOnlyUseMetadataV2()) && tripleConfigured(applicationModel))\n                .isPresent();\n    }\n\n    /**\n     * check if we can use triple as MetadataService protocol\n     */\n    public static boolean tripleConfigured(ApplicationModel applicationModel) {\n        Optional<ConfigManager> configManager = Optional.ofNullable(applicationModel.getApplicationConfigManager());\n\n        Optional<ApplicationConfig> appConfig = getApplicationConfig(applicationModel);\n\n        // if user configured MetadataService protocol\n        if (appConfig.isPresent() && appConfig.get().getMetadataServiceProtocol() != null) {\n            return TRIPLE.equals(appConfig.get().getMetadataServiceProtocol());\n        }\n        // if not specified, check all protocol configs\n        if (configManager.isPresent()\n                && CollectionUtils.isNotEmpty(configManager.get().getProtocols())) {\n            Collection<ProtocolConfig> protocols = configManager.get().getProtocols();\n            for (ProtocolConfig protocolConfig : protocols) {\n                if (TRIPLE.equals(protocolConfig.getName())) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    private static Optional<ApplicationConfig> getApplicationConfig(ApplicationModel applicationModel) {\n        Optional<ConfigManager> configManager = Optional.ofNullable(applicationModel.getApplicationConfigManager());\n\n        if (configManager.isPresent() && configManager.get().getApplication().isPresent()) {\n            return configManager.get().getApplication();\n        }\n        return Optional.empty();\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nsyntax = \"proto3\";\npackage org.apache.dubbo.metadata;\n\noption go_package = \"dubbo.apache.org/dubbo-go/v3/metadata/triple_api;triple_api\";\noption java_package = \"org.apache.dubbo.metadata\";\noption java_multiple_files = true;\n\n// Metadata service V2.\nservice MetadataServiceV2 {\n    // Retrieves metadata information.\n    rpc GetMetadataInfo(MetadataRequest) returns (MetadataInfoV2);\n\n    // Retrieves OpenAPI information.\n    rpc GetOpenAPIInfo(OpenAPIRequest) returns (OpenAPIInfo);\n}\n\n// Metadata request message.\nmessage MetadataRequest {\n    // The revision of the metadata.\n    string revision = 1;\n}\n\n// Metadata information message.\nmessage MetadataInfoV2 {\n    // The application name.\n    string app = 1;\n    // The application version.\n    string version = 2;\n    // A map of service information.\n    map<string, ServiceInfoV2> services = 3;\n}\n\n// Service information message.\nmessage ServiceInfoV2 {\n    // The service name.\n    string name = 1;\n    // The service group.\n    string group = 2;\n    // The service version.\n    string version = 3;\n    // The service protocol.\n    string protocol = 4;\n    // The service port.\n    int32 port = 5;\n    // The service path.\n    string path = 6;\n    // A map of service parameters.\n    map<string, string> params = 7;\n}\n\n// OpenAPI request message.\nmessage OpenAPIRequest {\n    // The openAPI group.\n    string group = 1;\n    // The openAPI version, using a major.minor.patch versioning scheme\n    // e.g. 1.0.1\n    string version = 2;\n    // The openAPI tags. Each tag is an or condition.\n    repeated string tag = 3;\n    // The openAPI services. Each service is an or condition.\n    repeated string service = 4;\n    // The openAPI specification version, using a major.minor.patch versioning scheme\n    // e.g. 3.0.1, 3.1.0\n    // The default value is '3.0.1'.\n    string openapi = 5;\n    // The format of the response.\n    // The default value is 'JSON'.\n    optional OpenAPIFormat format = 6;\n    // Whether to pretty print for json.\n    // The default value is 'false'.\n    optional bool pretty = 7;\n}\n\n// Response format enumeration.\nenum OpenAPIFormat {\n    // JSON format.\n    JSON = 0;\n    // YAML format.\n    YAML = 1;\n    // PROTO format.\n    PROTO = 2;\n}\n\n// OpenAPI information message.\nmessage OpenAPIInfo {\n    // The OpenAPI definition.\n    string definition = 1;\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.aot.api.ProxyDescriberRegistrar",
    "content": "metadata=org.apache.dubbo.metadata.aot.MetadataProxyDescriberRegistrar\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar",
    "content": "metadata=org.apache.dubbo.metadata.aot.MetadataReflectionTypeDescriberRegistrar\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataParamsFilter",
    "content": "dubbo=org.apache.dubbo.metadata.DefaultMetadataParamsFilter\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.BuiltinServiceDetector",
    "content": "metadata=org.apache.dubbo.metadata.MetadataServiceDetector\nmetadataV2=org.apache.dubbo.metadata.MetadataServiceV2Detector\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "dubbo-metadata-api=org.apache.dubbo.metadata.report.MetadataScopeModelInitializer\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/AbstractServiceNameMappingTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDED_BY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY;\nimport static org.mockito.Mockito.*;\n\n/**\n * @see AbstractServiceNameMapping\n */\nclass AbstractServiceNameMappingTest {\n\n    private ApplicationModel applicationModel = Mockito.mock(ApplicationModel.class);\n    private MockServiceNameMapping mapping;\n    private MockServiceNameMapping2 mapping2;\n\n    URL url = URL.valueOf(\"dubbo://127.0.0.1:21880/\" + AbstractServiceNameMappingTest.class.getName());\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        org.apache.dubbo.rpc.model.FrameworkModel frameworkModel =\n                org.apache.dubbo.rpc.model.FrameworkModel.defaultModel();\n        frameworkModel\n                .getBeanFactory()\n                .getOrRegisterBean(org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository.class);\n        org.apache.dubbo.config.context.ConfigManager configManager =\n                Mockito.mock(org.apache.dubbo.config.context.ConfigManager.class);\n        org.apache.dubbo.config.ApplicationConfig appConfig =\n                Mockito.mock(org.apache.dubbo.config.ApplicationConfig.class);\n        Mockito.when(applicationModel.getFrameworkModel()).thenReturn(frameworkModel);\n        Mockito.when(applicationModel.getApplicationConfigManager()).thenReturn(configManager);\n        Mockito.when(configManager.getApplication()).thenReturn(java.util.Optional.of(appConfig));\n        Mockito.when(appConfig.getEnableFileCache()).thenReturn(Boolean.TRUE);\n        Mockito.when(applicationModel.tryGetApplicationName()).thenReturn(\"unit-test\");\n        mapping = new MockServiceNameMapping(applicationModel);\n        mapping2 = new MockServiceNameMapping2(applicationModel);\n    }\n\n    @AfterEach\n    public void clearup() {\n        mapping.removeCachedMapping(ServiceNameMapping.buildMappingKey(url));\n    }\n\n    @Test\n    void testGetServices() {\n        url = url.addParameter(PROVIDED_BY, \"app1,app2\");\n        Set<String> services = mapping.getMapping(url);\n        Assertions.assertTrue(services.contains(\"app1\"));\n        Assertions.assertTrue(services.contains(\"app2\"));\n\n        //        // remove mapping cache, check get() works.\n        //        mapping.removeCachedMapping(ServiceNameMapping.buildMappingKey(url));\n        //        services = mapping.initInterfaceAppMapping(url);\n        //        Assertions.assertTrue(services.contains(\"remote-app1\"));\n        //        Assertions.assertTrue(services.contains(\"remote-app2\"));\n\n        //        Assertions.assertNotNull(mapping.getCachedMapping(url));\n        //        Assertions.assertIterableEquals(mapping.getCachedMapping(url), services);\n    }\n\n    @Test\n    void testGetAndListener() {\n        URL registryURL = URL.valueOf(\"registry://127.0.0.1:7777/test\");\n        registryURL = registryURL.addParameter(SUBSCRIBED_SERVICE_NAMES_KEY, \"registry-app1\");\n\n        Set<String> services = mapping2.getAndListen(registryURL, url, null);\n        Assertions.assertTrue(services.contains(\"registry-app1\"));\n\n        // remove mapping cache, check get() works.\n        mapping2.removeCachedMapping(ServiceNameMapping.buildMappingKey(url));\n        mapping2.enabled = true;\n        services = mapping2.getAndListen(registryURL, url, new MappingListener() {\n            @Override\n            public void onEvent(MappingChangedEvent event) {}\n\n            @Override\n            public void stop() {}\n        });\n        Assertions.assertTrue(services.contains(\"remote-app3\"));\n    }\n\n    private class MockServiceNameMapping extends AbstractServiceNameMapping {\n\n        public boolean enabled = false;\n\n        public MockServiceNameMapping(ApplicationModel applicationModel) {\n            super(applicationModel);\n        }\n\n        @Override\n        public Set<String> get(URL url) {\n            return new HashSet<>(Arrays.asList(\"remote-app1\", \"remote-app2\"));\n        }\n\n        @Override\n        public Set<String> getAndListen(URL url, MappingListener mappingListener) {\n            if (!enabled) {\n                return Collections.emptySet();\n            }\n            return new HashSet<>(Arrays.asList(\"remote-app3\"));\n        }\n\n        @Override\n        protected void removeListener(URL url, MappingListener mappingListener) {}\n\n        @Override\n        public boolean map(URL url) {\n            return false;\n        }\n\n        @Override\n        public boolean hasValidMetadataCenter() {\n            return false;\n        }\n    }\n\n    private class MockServiceNameMapping2 extends AbstractServiceNameMapping {\n\n        public boolean enabled = false;\n\n        public MockServiceNameMapping2(ApplicationModel applicationModel) {\n            super(applicationModel);\n        }\n\n        @Override\n        public Set<String> get(URL url) {\n            return Collections.emptySet();\n        }\n\n        @Override\n        public Set<String> getAndListen(URL url, MappingListener mappingListener) {\n            if (!enabled) {\n                return Collections.emptySet();\n            }\n            return new HashSet<>(Arrays.asList(\"remote-app3\"));\n        }\n\n        @Override\n        protected void removeListener(URL url, MappingListener mappingListener) {}\n\n        @Override\n        public boolean map(URL url) {\n            return false;\n        }\n\n        @Override\n        public boolean hasValidMetadataCenter() {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/MetadataInfoTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.JsonUtils;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.lang.reflect.Field;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PAYLOAD;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.metadata.RevisionResolver.EMPTY_REVISION;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * Some construction and filter cases are covered in InMemoryMetadataServiceTest\n */\nclass MetadataInfoTest {\n    private static final Logger logger = LoggerFactory.getLogger(MetadataInfoTest.class);\n    private static URL url = URL.valueOf(\"dubbo://30.225.21.30:20880/org.apache.dubbo.registry.service.DemoService2?\"\n            + \"REGISTRY_CLUSTER=registry1&anyhost=true&application=demo-provider2&delay=5000&deprecated=false&dubbo=2.0.2\"\n            + \"&dynamic=true&generic=false&group=greeting&interface=org.apache.dubbo.registry.service.DemoService2\"\n            + \"&metadata-type=remote&methods=sayHello&sayHello.timeout=7000&pid=36621&release=&revision=1.0.0&service-name-mapping=true\"\n            + \"&side=provider&timeout=5000&timestamp=1629970068002&version=1.0.0&params-filter=customized,-excluded\");\n\n    private static URL url2 = URL.valueOf(\"dubbo://30.225.21.30:20880/org.apache.dubbo.registry.service.DemoService?\"\n            + \"REGISTRY_CLUSTER=registry1&anyhost=true&application=demo-provider2&delay=5000&deprecated=false&dubbo=2.0.2\"\n            + \"&dynamic=true&generic=false&group=greeting&interface=org.apache.dubbo.registry.service.DemoService\"\n            + \"&metadata-type=remote&methods=sayHello&pid=36621&release=&revision=1.0.0&service-name-mapping=true\"\n            + \"&side=provider&timeout=5000&timestamp=1629970068002&version=1.0.0&params-filter=customized,-excluded\");\n\n    private static URL url3 = URL.valueOf(\"dubbo://30.225.21.30:20880/org.apache.dubbo.registry.service.DemoService?\"\n            + \"REGISTRY_CLUSTER=registry1&anyhost=true&application=demo-provider2&delay=5000&deprecated=false&dubbo=2.0.2\"\n            + \"&dynamic=true&generic=false&group=greeting&interface=org.apache.dubbo.registry.service.DemoService\"\n            + \"&metadata-type=remote&methods=sayHello&sayHello.timeout=7000&pid=36621&release=&revision=1.0.0&service-name-mapping=true\"\n            + \"&side=provider&timeout=5000&timestamp=1629970068002&version=1.0.0&params-filter=-customized,excluded\");\n\n    private static URL url4 = URL.valueOf(\n            \"dubbo://30.225.21.30:20880/org.apache.dubbo.registry.service.DemoService?\"\n                    + \"REGISTRY_CLUSTER=registry1&anyhost=true&application=demo-provider2&delay=5000&deprecated=false&dubbo=2.0.2\"\n                    + \"&dynamic=true&generic=false&group=greeting&interface=org.apache.dubbo.registry.service.DemoService\"\n                    + \"&metadata-type=remote&methods=sayHello&sayHello.timeout=7000&pid=36621&release=&revision=1.0.0&service-name-mapping=true\"\n                    + \"&side=provider&timeout=5000&timestamp=1629970068002&version=1.0.0&params-filter=-customized,excluded&payload=1024\");\n\n    @Test\n    void testEmptyRevision() {\n        MetadataInfo metadataInfo = new MetadataInfo(\"demo\");\n        metadataInfo.setApp(\"demo\");\n\n        Assertions.assertEquals(EMPTY_REVISION, metadataInfo.calAndGetRevision());\n    }\n\n    @Test\n    void testParamsFilterIncluded() {\n        MetadataInfo metadataInfo = new MetadataInfo(\"demo\");\n\n        // export normal url again\n        metadataInfo.addService(url);\n        MetadataInfo.ServiceInfo serviceInfo2 = metadataInfo.getServiceInfo(url.getProtocolServiceKey());\n        assertNotNull(serviceInfo2);\n        assertEquals(5, serviceInfo2.getParams().size());\n        assertNull(serviceInfo2.getParams().get(INTERFACE_KEY));\n        assertNull(serviceInfo2.getParams().get(\"delay\"));\n        assertNotNull(serviceInfo2.getParams().get(APPLICATION_KEY));\n        assertNotNull(serviceInfo2.getParams().get(VERSION_KEY));\n        assertNotNull(serviceInfo2.getParams().get(GROUP_KEY));\n        assertNotNull(serviceInfo2.getParams().get(TIMEOUT_KEY));\n        assertEquals(\"7000\", serviceInfo2.getMethodParameter(\"sayHello\", TIMEOUT_KEY, \"1000\"));\n    }\n\n    @Test\n    void testParamsFilterExcluded() {\n        MetadataInfo metadataInfo = new MetadataInfo(\"demo\");\n\n        // export normal url again\n        metadataInfo.addService(url3);\n        MetadataInfo.ServiceInfo serviceInfo3 = metadataInfo.getServiceInfo(url3.getProtocolServiceKey());\n        assertNotNull(serviceInfo3);\n        assertEquals(14, serviceInfo3.getParams().size());\n        assertNotNull(serviceInfo3.getParams().get(INTERFACE_KEY));\n        assertNotNull(serviceInfo3.getParams().get(APPLICATION_KEY));\n        assertNotNull(serviceInfo3.getParams().get(VERSION_KEY));\n        assertNull(serviceInfo3.getParams().get(GROUP_KEY));\n        assertNull(serviceInfo3.getParams().get(TIMEOUT_KEY));\n        assertNull(serviceInfo3.getParams().get(\"anyhost\"));\n        assertEquals(\"1000\", serviceInfo3.getMethodParameter(\"sayHello\", TIMEOUT_KEY, \"1000\"));\n    }\n\n    @Test\n    void testEqualsAndRevision() {\n        // same metadata\n        MetadataInfo metadataInfo = new MetadataInfo(\"demo\");\n        metadataInfo.addService(url);\n        MetadataInfo sameMetadataInfo = new MetadataInfo(\"demo\");\n        sameMetadataInfo.addService(url);\n        assertEquals(metadataInfo, sameMetadataInfo);\n        assertEquals(metadataInfo.calAndGetRevision(), sameMetadataInfo.calAndGetRevision());\n\n        // url with different params that are not counted in ServiceInfo\n        MetadataInfo metadataInfoWithDifferentParam1 = new MetadataInfo(\"demo\");\n        metadataInfoWithDifferentParam1.addService(url.addParameter(\"delay\", 6000));\n        assertEquals(metadataInfo, metadataInfoWithDifferentParam1);\n        assertEquals(metadataInfo.calAndGetRevision(), metadataInfoWithDifferentParam1.calAndGetRevision());\n        // url with different params that are counted in ServiceInfo\n        MetadataInfo metadataInfoWithDifferentParam2 = new MetadataInfo(\"demo\");\n        metadataInfoWithDifferentParam2.addService(url.addParameter(TIMEOUT_KEY, 6000));\n        assertNotEquals(metadataInfo, metadataInfoWithDifferentParam2);\n        assertNotEquals(metadataInfo.calAndGetRevision(), metadataInfoWithDifferentParam2.calAndGetRevision());\n\n        MetadataInfo metadataInfoWithDifferentGroup = new MetadataInfo(\"demo\");\n        metadataInfoWithDifferentGroup.addService(url.addParameter(GROUP_KEY, \"newGroup\"));\n        assertNotEquals(metadataInfo, metadataInfoWithDifferentGroup);\n        assertNotEquals(metadataInfo.calAndGetRevision(), metadataInfoWithDifferentGroup.calAndGetRevision());\n\n        MetadataInfo metadataInfoWithDifferentServices = new MetadataInfo(\"demo\");\n        metadataInfoWithDifferentServices.addService(url);\n        metadataInfoWithDifferentServices.addService(url2);\n        assertNotEquals(metadataInfo, metadataInfoWithDifferentServices);\n        assertNotEquals(metadataInfo.calAndGetRevision(), metadataInfoWithDifferentServices.calAndGetRevision());\n    }\n\n    @Test\n    void testChanged() {\n        MetadataInfo metadataInfo = new MetadataInfo(\"demo\");\n        metadataInfo.addService(url);\n        metadataInfo.addService(url2);\n        assertTrue(metadataInfo.updated);\n        metadataInfo.calAndGetRevision();\n        assertFalse(metadataInfo.updated);\n        metadataInfo.removeService(url2);\n        assertTrue(metadataInfo.updated);\n    }\n\n    @Test\n    void testJsonFormat() {\n        MetadataInfo metadataInfo = new MetadataInfo(\"demo\");\n\n        // export normal url again\n        metadataInfo.addService(url);\n        logger.info(JsonUtils.toJson(metadataInfo));\n\n        MetadataInfo metadataInfo2 = new MetadataInfo(\"demo\");\n        // export normal url again\n        metadataInfo2.addService(url);\n        metadataInfo2.addService(url2);\n        logger.info(JsonUtils.toJson(metadataInfo2));\n    }\n\n    @Test\n    void testJdkSerialize() throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);\n        MetadataInfo metadataInfo = new MetadataInfo(\"demo\");\n        metadataInfo.addService(url);\n        objectOutputStream.writeObject(metadataInfo);\n        objectOutputStream.close();\n        byteArrayOutputStream.close();\n        byte[] bytes = byteArrayOutputStream.toByteArray();\n\n        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);\n        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);\n        MetadataInfo metadataInfo2 = (MetadataInfo) objectInputStream.readObject();\n        objectInputStream.close();\n\n        Assertions.assertEquals(metadataInfo, metadataInfo2);\n        Field initiatedField = MetadataInfo.class.getDeclaredField(\"initiated\");\n        initiatedField.setAccessible(true);\n        Assertions.assertInstanceOf(AtomicBoolean.class, initiatedField.get(metadataInfo2));\n        Assertions.assertFalse(((AtomicBoolean) initiatedField.get(metadataInfo2)).get());\n    }\n\n    @Test\n    void testCal() {\n        MetadataInfo metadataInfo = new MetadataInfo(\"demo\");\n\n        // export normal url again\n        metadataInfo.addService(url);\n\n        metadataInfo.calAndGetRevision();\n\n        metadataInfo.addService(url2);\n\n        metadataInfo.calAndGetRevision();\n\n        metadataInfo.addService(url3);\n\n        metadataInfo.calAndGetRevision();\n\n        Map<String, Object> ret = JsonUtils.toJavaObject(metadataInfo.getContent(), Map.class);\n        assertNull(ret.get(\"content\"));\n        assertNull(ret.get(\"rawMetadataInfo\"));\n    }\n\n    @Test\n    void testPayload() {\n        MetadataInfo metadataInfo = new MetadataInfo(\"demo\");\n\n        metadataInfo.addService(url4);\n        MetadataInfo.ServiceInfo serviceInfo4 = metadataInfo.getServiceInfo(url4.getProtocolServiceKey());\n        assertNotNull(serviceInfo4);\n        assertEquals(\"1024\", serviceInfo4.getParameter(PAYLOAD));\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/filter/CustomizedParamsFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.metadata.MetadataParamsFilter;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\n\n@Activate(order = 3) // Will take effect after ExcludedParamsFilter\npublic class CustomizedParamsFilter implements MetadataParamsFilter {\n\n    @Override\n    public String[] serviceParamsIncluded() {\n        return new String[] {APPLICATION_KEY, TIMEOUT_KEY, GROUP_KEY, VERSION_KEY};\n    }\n\n    @Override\n    public String[] serviceParamsExcluded() {\n        return new String[0];\n    }\n\n    /**\n     * Not included in this test\n     */\n    @Override\n    public String[] instanceParamsIncluded() {\n        return new String[0];\n    }\n\n    @Override\n    public String[] instanceParamsExcluded() {\n        return new String[0];\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/filter/ExcludedParamsFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.metadata.MetadataParamsFilter;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\n\n@Activate(order = 1) // Will take effect before ExcludedParamsFilter\npublic class ExcludedParamsFilter implements MetadataParamsFilter {\n\n    @Override\n    public String[] serviceParamsIncluded() {\n        return new String[0];\n    }\n\n    @Override\n    public String[] serviceParamsExcluded() {\n        return new String[] {TIMEOUT_KEY, GROUP_KEY, \"anyhost\"};\n    }\n\n    /**\n     * Not included in this test\n     */\n    @Override\n    public String[] instanceParamsIncluded() {\n        return new String[0];\n    }\n\n    @Override\n    public String[] instanceParamsExcluded() {\n        return new String[0];\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/filter/ExcludedParamsFilter2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.metadata.MetadataParamsFilter;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.rpc.Constants.DEPRECATED_KEY;\n\n@Activate(order = 2) // Will take effect before ExcludedParamsFilter\npublic class ExcludedParamsFilter2 implements MetadataParamsFilter {\n\n    @Override\n    public String[] serviceParamsIncluded() {\n        return new String[0];\n    }\n\n    @Override\n    public String[] serviceParamsExcluded() {\n        return new String[] {DEPRECATED_KEY, SIDE_KEY};\n    }\n\n    /**\n     * Not included in this test\n     */\n    @Override\n    public String[] instanceParamsIncluded() {\n        return new String[0];\n    }\n\n    @Override\n    public String[] instanceParamsExcluded() {\n        return new String[0];\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/MetadataReportInstanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.when;\n\nclass MetadataReportInstanceTest {\n    private MetadataReportInstance metadataReportInstance;\n    private MetadataReportConfig metadataReportConfig;\n    private ConfigManager configManager;\n\n    private final String registryId = \"9103\";\n\n    @BeforeEach\n    public void setUp() {\n        configManager = mock(ConfigManager.class);\n        ApplicationModel applicationModel = spy(ApplicationModel.defaultModel());\n        metadataReportInstance = new MetadataReportInstance(applicationModel);\n\n        URL url = URL.valueOf(\"metadata://127.0.0.1:20880/TestService?version=1.0.0&metadata=JTest\");\n        metadataReportConfig = mock(MetadataReportConfig.class);\n        when(metadataReportConfig.getUsername()).thenReturn(\"username\");\n        when(metadataReportConfig.getPassword()).thenReturn(\"password\");\n\n        when(metadataReportConfig.getApplicationModel()).thenReturn(applicationModel);\n        when(metadataReportConfig.toUrl()).thenReturn(url);\n        when(metadataReportConfig.getScopeModel()).thenReturn(applicationModel);\n        when(metadataReportConfig.getRegistry()).thenReturn(registryId);\n\n        when(configManager.getMetadataConfigs()).thenReturn(Collections.emptyList());\n        when(applicationModel.getApplicationConfigManager()).thenReturn(configManager);\n        when(applicationModel.getApplicationConfigManager().getApplicationOrElseThrow())\n                .thenReturn(new ApplicationConfig(\"test\"));\n        when(applicationModel.getCurrentConfig()).thenReturn(new ApplicationConfig(\"test\"));\n    }\n\n    @Test\n    void test() {\n        Assertions.assertNull(\n                metadataReportInstance.getMetadataReport(registryId), \"the metadata report was not initialized.\");\n        Assertions.assertTrue(metadataReportInstance.getMetadataReports(true).isEmpty());\n\n        metadataReportInstance.init(Collections.singletonList(metadataReportConfig));\n        MetadataReport metadataReport = metadataReportInstance.getMetadataReport(registryId);\n        Assertions.assertNotNull(metadataReport);\n\n        MetadataReport metadataReport2 = metadataReportInstance.getMetadataReport(registryId + \"NOT_EXIST\");\n        Assertions.assertEquals(metadataReport, metadataReport2);\n\n        Map<String, MetadataReport> metadataReports = metadataReportInstance.getMetadataReports(true);\n        Assertions.assertEquals(metadataReports.size(), 1);\n        Assertions.assertEquals(metadataReports.get(registryId), metadataReport);\n\n        Assertions.assertEquals(metadataReportConfig.getUsername(), \"username\");\n        Assertions.assertEquals(metadataReportConfig.getPassword(), \"password\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/BaseApplicationMetadataIdentifierTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass BaseApplicationMetadataIdentifierTest {\n    private BaseApplicationMetadataIdentifier baseApplicationMetadataIdentifier;\n\n    {\n        baseApplicationMetadataIdentifier = new BaseApplicationMetadataIdentifier();\n        baseApplicationMetadataIdentifier.application = \"app\";\n    }\n\n    @Test\n    void getUniqueKey() {\n        String uniqueKey = baseApplicationMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY, \"reversion\");\n        Assertions.assertEquals(uniqueKey, \"app:reversion\");\n\n        String uniqueKey2 = baseApplicationMetadataIdentifier.getUniqueKey(KeyTypeEnum.PATH, \"reversion\");\n        Assertions.assertEquals(uniqueKey2, \"metadata/app/reversion\");\n    }\n\n    @Test\n    void getIdentifierKey() {\n        String identifierKey = baseApplicationMetadataIdentifier.getIdentifierKey(\"reversion\");\n        Assertions.assertEquals(identifierKey, \"app:reversion\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/BaseServiceMetadataIdentifierTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass BaseServiceMetadataIdentifierTest {\n\n    private BaseServiceMetadataIdentifier baseServiceMetadataIdentifier;\n\n    {\n        baseServiceMetadataIdentifier = new BaseServiceMetadataIdentifier();\n        baseServiceMetadataIdentifier.version = \"1.0.0\";\n        baseServiceMetadataIdentifier.group = \"test\";\n        baseServiceMetadataIdentifier.side = \"provider\";\n        baseServiceMetadataIdentifier.serviceInterface = \"BaseServiceMetadataIdentifierTest\";\n    }\n\n    @Test\n    void getUniqueKey() {\n        String uniqueKey = baseServiceMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY, \"appName\");\n        Assertions.assertEquals(uniqueKey, \"BaseServiceMetadataIdentifierTest:1.0.0:test:provider:appName\");\n\n        String uniqueKey2 = baseServiceMetadataIdentifier.getUniqueKey(KeyTypeEnum.PATH, \"appName\");\n        Assertions.assertEquals(uniqueKey2, \"metadata/BaseServiceMetadataIdentifierTest/1.0.0/test/provider/appName\");\n    }\n\n    @Test\n    void getIdentifierKey() {\n        String identifierKey = baseServiceMetadataIdentifier.getIdentifierKey(\"appName\");\n        Assertions.assertEquals(identifierKey, \"BaseServiceMetadataIdentifierTest:1.0.0:test:provider:appName\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/KeyTypeEnumTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link KeyTypeEnum} Test-Cases\n *\n * @since 2.7.8\n */\nclass KeyTypeEnumTest {\n\n    /**\n     * {@link KeyTypeEnum#build(String, String...)}\n     */\n    @Test\n    void testBuild() {\n        assertEquals(\"/A/B/C\", KeyTypeEnum.PATH.build(\"/A\", \"/B\", \"C\"));\n        assertEquals(\"A:B:C\", KeyTypeEnum.UNIQUE_KEY.build(\"A\", \"B\", \"C\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifierTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport org.apache.dubbo.metadata.MetadataConstants;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;\n\n/**\n * 2019/1/7\n */\nclass MetadataIdentifierTest {\n\n    @Test\n    void testGetUniqueKey() {\n        String interfaceName = \"org.apache.dubbo.metadata.integration.InterfaceNameTestService\";\n        String version = \"1.0.0.zk.md\";\n        String group = null;\n        String application = \"vic.zk.md\";\n        MetadataIdentifier providerMetadataIdentifier =\n                new MetadataIdentifier(interfaceName, version, group, PROVIDER_SIDE, application);\n        Assertions.assertEquals(\n                providerMetadataIdentifier.getUniqueKey(KeyTypeEnum.PATH),\n                \"metadata\" + PATH_SEPARATOR + interfaceName + PATH_SEPARATOR\n                        + (version == null ? \"\" : (version + PATH_SEPARATOR))\n                        + (group == null ? \"\" : (group + PATH_SEPARATOR)) + PROVIDER_SIDE + PATH_SEPARATOR\n                        + application);\n        Assertions.assertEquals(\n                providerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY),\n                interfaceName\n                        + MetadataConstants.KEY_SEPARATOR\n                        + (version == null ? \"\" : version)\n                        + MetadataConstants.KEY_SEPARATOR\n                        + (group == null ? \"\" : group)\n                        + MetadataConstants.KEY_SEPARATOR\n                        + PROVIDER_SIDE\n                        + MetadataConstants.KEY_SEPARATOR\n                        + application);\n    }\n\n    @Test\n    void testPutDuplicateIdentifier() {\n        ConcurrentHashMap<MetadataIdentifier, Object> map = new ConcurrentHashMap<>();\n        map.put(new MetadataIdentifier(\"com.ServiceInterface\", \"1.0.0\", \"gray\", \"consumer\", \"testApp\"), new Object());\n        map.put(new MetadataIdentifier(\"com.ServiceInterface\", \"1.0.0\", \"gray\", \"consumer\", \"testApp\"), new Object());\n        map.put(new MetadataIdentifier(\"com.ServiceInterface\", \"1.0.0\", \"gray\", \"consumer\", \"testApp\"), new Object());\n        Assertions.assertEquals(map.size(), 1);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/ServiceMetadataIdentifierTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\npublic class ServiceMetadataIdentifierTest {\n\n    @Test\n    void testPutDuplicateIdentifier() {\n        ConcurrentHashMap<ServiceMetadataIdentifier, Object> map = new ConcurrentHashMap<>();\n        map.put(\n                new ServiceMetadataIdentifier(\"com.ServiceInterface\", \"1.0.0\", \"gray\", \"consumer\", \"testApp\", \"dubbo\"),\n                new Object());\n        map.put(\n                new ServiceMetadataIdentifier(\"com.ServiceInterface\", \"1.0.0\", \"gray\", \"consumer\", \"testApp\", \"dubbo\"),\n                new Object());\n        map.put(\n                new ServiceMetadataIdentifier(\"com.ServiceInterface\", \"1.0.0\", \"gray\", \"consumer\", \"testApp\", \"dubbo\"),\n                new Object());\n        Assertions.assertEquals(map.size(), 1);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/SubscriberMetadataIdentifierTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.identifier;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\npublic class SubscriberMetadataIdentifierTest {\n\n    @Test\n    void testPutDuplicateIdentifier() {\n        ConcurrentHashMap<SubscriberMetadataIdentifier, Object> map = new ConcurrentHashMap<>();\n        map.put(new SubscriberMetadataIdentifier(\"testApp\", \"1.0.0\"), new Object());\n        map.put(new SubscriberMetadataIdentifier(\"testApp\", \"1.0.0\"), new Object());\n        map.put(new SubscriberMetadataIdentifier(\"testApp\", \"1.0.0\"), new Object());\n        Assertions.assertEquals(map.size(), 1);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.metadata.MappingListener;\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * 2018/9/14\n */\nclass AbstractMetadataReportFactoryTest {\n\n    private AbstractMetadataReportFactory metadataReportFactory = new AbstractMetadataReportFactory() {\n        @Override\n        protected MetadataReport createMetadataReport(URL url) {\n            return new MetadataReport() {\n\n                @Override\n                public void storeProviderMetadata(\n                        MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) {\n                    store.put(providerMetadataIdentifier.getIdentifierKey(), JsonUtils.toJson(serviceDefinition));\n                }\n\n                @Override\n                public void saveServiceMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) {}\n\n                @Override\n                public void removeServiceMetadata(ServiceMetadataIdentifier metadataIdentifier) {}\n\n                @Override\n                public void saveSubscribedData(\n                        SubscriberMetadataIdentifier subscriberMetadataIdentifier, Set<String> urls) {}\n\n                @Override\n                public List<String> getExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {\n                    return null;\n                }\n\n                @Override\n                public void destroy() {}\n\n                @Override\n                public List<String> getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {\n                    return null;\n                }\n\n                @Override\n                public void removeServiceAppMappingListener(String serviceKey, MappingListener listener) {}\n\n                @Override\n                public boolean shouldReportDefinition() {\n                    return true;\n                }\n\n                @Override\n                public boolean shouldReportMetadata() {\n                    return false;\n                }\n\n                @Override\n                public String getServiceDefinition(MetadataIdentifier consumerMetadataIdentifier) {\n                    return null;\n                }\n\n                @Override\n                public void storeConsumerMetadata(\n                        MetadataIdentifier consumerMetadataIdentifier, Map serviceParameterMap) {\n                    store.put(consumerMetadataIdentifier.getIdentifierKey(), JsonUtils.toJson(serviceParameterMap));\n                }\n\n                Map<String, String> store = new ConcurrentHashMap<>();\n            };\n        }\n    };\n\n    @Test\n    void testGetOneMetadataReport() {\n        URL url = URL.valueOf(\"zookeeper://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic\");\n        MetadataReport metadataReport1 = metadataReportFactory.getMetadataReport(url);\n        MetadataReport metadataReport2 = metadataReportFactory.getMetadataReport(url);\n        Assertions.assertEquals(metadataReport1, metadataReport2);\n    }\n\n    @Test\n    void testGetOneMetadataReportForIpFormat() {\n        String hostName = NetUtils.getLocalAddress().getHostName();\n        String ip = NetUtils.getIpByHost(hostName);\n        URL url1 = URL.valueOf(\n                \"zookeeper://\" + hostName + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic\");\n        URL url2 =\n                URL.valueOf(\"zookeeper://\" + ip + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic\");\n        MetadataReport metadataReport1 = metadataReportFactory.getMetadataReport(url1);\n        MetadataReport metadataReport2 = metadataReportFactory.getMetadataReport(url2);\n        Assertions.assertEquals(metadataReport1, metadataReport2);\n    }\n\n    @Test\n    void testGetForDiffService() {\n        URL url1 = URL.valueOf(\"zookeeper://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService1?version=1.0.0&application=vic\");\n        URL url2 = URL.valueOf(\"zookeeper://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService2?version=1.0.0&application=vic\");\n        MetadataReport metadataReport1 = metadataReportFactory.getMetadataReport(url1);\n        MetadataReport metadataReport2 = metadataReportFactory.getMetadataReport(url2);\n        Assertions.assertEquals(metadataReport1, metadataReport2);\n    }\n\n    @Test\n    void testGetForDiffGroup() {\n        URL url1 = URL.valueOf(\"zookeeper://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&group=aaa\");\n        URL url2 = URL.valueOf(\"zookeeper://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&group=bbb\");\n        MetadataReport metadataReport1 = metadataReportFactory.getMetadataReport(url1);\n        MetadataReport metadataReport2 = metadataReportFactory.getMetadataReport(url2);\n        Assertions.assertNotEquals(metadataReport1, metadataReport2);\n    }\n\n    @Test\n    void testGetForSameNamespace() {\n        URL url1 = URL.valueOf(\"zookeeper://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService1?version=1.0.0&application=vic&namespace=test\");\n        URL url2 = URL.valueOf(\"zookeeper://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService2?version=1.0.0&application=vic&namespace=test\");\n        MetadataReport metadataReport1 = metadataReportFactory.getMetadataReport(url1);\n        MetadataReport metadataReport2 = metadataReportFactory.getMetadataReport(url2);\n        Assertions.assertEquals(metadataReport1, metadataReport2);\n    }\n\n    @Test\n    void testGetForDiffNamespace() {\n        URL url1 = URL.valueOf(\"zookeeper://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&namespace=test\");\n        URL url2 = URL.valueOf(\"zookeeper://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&namespace=dev\");\n        MetadataReport metadataReport1 = metadataReportFactory.getMetadataReport(url1);\n        MetadataReport metadataReport2 = metadataReportFactory.getMetadataReport(url2);\n        Assertions.assertNotEquals(metadataReport1, metadataReport2);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.report.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metadata.MappingListener;\nimport org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\nimport org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;\nimport org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Calendar;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;\nimport static org.awaitility.Awaitility.await;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass AbstractMetadataReportTest {\n    private static final Logger logger = LoggerFactory.getLogger(AbstractMetadataReportTest.class);\n\n    private NewMetadataReport abstractMetadataReport;\n    private ApplicationModel applicationModel;\n\n    @BeforeEach\n    public void before() {\n        // set the simple name of current class as the application name\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        applicationModel = frameworkModel.newApplication();\n        applicationModel\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(getClass().getSimpleName()));\n\n        URL url = URL.valueOf(\"zookeeper://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&sync=true\");\n        abstractMetadataReport = new NewMetadataReport(url, applicationModel);\n    }\n\n    @AfterEach\n    public void reset() {\n        // reset\n        ApplicationModel.reset();\n    }\n\n    @Test\n    void testGetProtocol() {\n        URL url = URL.valueOf(\"dubbo://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&side=provider\");\n        String protocol = abstractMetadataReport.getProtocol(url);\n        assertEquals(\"provider\", protocol);\n\n        URL url2 = URL.valueOf(\"consumer://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic\");\n        String protocol2 = abstractMetadataReport.getProtocol(url2);\n        assertEquals(\"consumer\", protocol2);\n    }\n\n    @Test\n    void testStoreProviderUsual() throws ClassNotFoundException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.InterfaceNameTestService\";\n        String version = \"1.0.0\";\n        String group = null;\n        String application = \"vic\";\n        ThreadPoolExecutor reportCacheExecutor = (ThreadPoolExecutor) abstractMetadataReport.getReportCacheExecutor();\n\n        long completedTaskCount1 = reportCacheExecutor.getCompletedTaskCount();\n        MetadataIdentifier providerMetadataIdentifier =\n                storeProvider(abstractMetadataReport, interfaceName, version, group, application);\n        await().until(() -> reportCacheExecutor.getCompletedTaskCount() > completedTaskCount1);\n        Assertions.assertNotNull(\n                abstractMetadataReport.store.get(providerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY)));\n    }\n\n    @Test\n    void testStoreProviderSync() throws ClassNotFoundException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.InterfaceNameTestService\";\n        String version = \"1.0.0\";\n        String group = null;\n        String application = \"vic\";\n        abstractMetadataReport.syncReport = true;\n        MetadataIdentifier providerMetadataIdentifier =\n                storeProvider(abstractMetadataReport, interfaceName, version, group, application);\n        Assertions.assertNotNull(\n                abstractMetadataReport.store.get(providerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY)));\n    }\n\n    @Test\n    void testFileExistAfterPut() throws ClassNotFoundException {\n        // just for one method\n        String filePath = System.getProperty(\"user.home\") + \"/dubbo-md-unit.properties\";\n        URL singleUrl = URL.valueOf(\"redis://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.metadata.store.InterfaceNameTestService?version=1.0.0&application=singleTest&sync=true&file=\"\n                + filePath);\n        NewMetadataReport singleMetadataReport = new NewMetadataReport(singleUrl, applicationModel);\n\n        assertFalse(singleMetadataReport.file.exists());\n\n        String interfaceName = \"org.apache.dubbo.metadata.store.InterfaceNameTestService\";\n        String version = \"1.0.0\";\n        String group = null;\n        String application = \"vic\";\n        ThreadPoolExecutor reportCacheExecutor = (ThreadPoolExecutor) singleMetadataReport.getReportCacheExecutor();\n\n        long completedTaskCount1 = reportCacheExecutor.getCompletedTaskCount();\n        MetadataIdentifier providerMetadataIdentifier =\n                storeProvider(singleMetadataReport, interfaceName, version, group, application);\n        await().until(() -> reportCacheExecutor.getCompletedTaskCount() > completedTaskCount1);\n\n        assertTrue(singleMetadataReport.file.exists());\n        assertTrue(singleMetadataReport.properties.containsKey(\n                providerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY)));\n    }\n\n    @Test\n    void testRetry() throws ClassNotFoundException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.RetryTestService\";\n        String version = \"1.0.0.retry\";\n        String group = null;\n        String application = \"vic.retry\";\n        URL storeUrl = URL.valueOf(\"retryReport://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestServiceForRetry?version=1.0.0.retry&application=vic.retry&sync=true\");\n        RetryMetadataReport retryReport = new RetryMetadataReport(storeUrl, 2, applicationModel);\n        retryReport.metadataReportRetry.retryPeriod = 400L;\n        URL url = URL.valueOf(\"dubbo://\" + NetUtils.getLocalAddress().getHostName()\n                + \":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&sync=true\");\n        Assertions.assertNull(retryReport.metadataReportRetry.retryScheduledFuture);\n        assertEquals(0, retryReport.metadataReportRetry.retryCounter.get());\n        assertTrue(retryReport.store.isEmpty());\n        assertTrue(retryReport.failedReports.isEmpty());\n\n        ThreadPoolExecutor reportCacheExecutor = (ThreadPoolExecutor) retryReport.getReportCacheExecutor();\n        ScheduledThreadPoolExecutor retryExecutor = (ScheduledThreadPoolExecutor)\n                retryReport.getMetadataReportRetry().getRetryExecutor();\n\n        long completedTaskCount1 = reportCacheExecutor.getCompletedTaskCount();\n        long completedTaskCount2 = retryExecutor.getCompletedTaskCount();\n        storeProvider(retryReport, interfaceName, version, group, application);\n        await().until(() -> reportCacheExecutor.getCompletedTaskCount() > completedTaskCount1);\n\n        assertTrue(retryReport.store.isEmpty());\n        assertFalse(retryReport.failedReports.isEmpty());\n        assertNotNull(retryReport.metadataReportRetry.retryScheduledFuture);\n\n        await().until(() -> retryExecutor.getCompletedTaskCount() > completedTaskCount2 + 2);\n        assertNotEquals(0, retryReport.metadataReportRetry.retryCounter.get());\n        assertTrue(retryReport.metadataReportRetry.retryCounter.get() >= 3);\n        assertFalse(retryReport.store.isEmpty());\n        assertTrue(retryReport.failedReports.isEmpty());\n    }\n\n    @Test\n    void testRetryCancel() throws ClassNotFoundException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.RetryTestService\";\n        String version = \"1.0.0.retrycancel\";\n        String group = null;\n        String application = \"vic.retry\";\n        URL storeUrl = URL.valueOf(\n                \"retryReport://\" + NetUtils.getLocalAddress().getHostName()\n                        + \":4444/org.apache.dubbo.TestServiceForRetryCancel?version=1.0.0.retrycancel&application=vic.retry&sync=true\");\n        RetryMetadataReport retryReport = new RetryMetadataReport(storeUrl, 2, applicationModel);\n        retryReport.metadataReportRetry.retryPeriod = 150L;\n        retryReport.metadataReportRetry.retryTimesIfNonFail = 2;\n        retryReport.semaphore = new Semaphore(1);\n\n        ScheduledThreadPoolExecutor retryExecutor = (ScheduledThreadPoolExecutor)\n                retryReport.getMetadataReportRetry().getRetryExecutor();\n        long completedTaskCount = retryExecutor.getCompletedTaskCount();\n        storeProvider(retryReport, interfaceName, version, group, application);\n\n        // Wait for the assignment of retryScheduledFuture to complete\n        await().until(() -> retryReport.metadataReportRetry.retryScheduledFuture != null);\n        assertFalse(retryReport.metadataReportRetry.retryScheduledFuture.isCancelled());\n        assertFalse(retryReport.metadataReportRetry.retryExecutor.isShutdown());\n        retryReport.semaphore.release(2);\n        await().until(() -> retryExecutor.getCompletedTaskCount() > completedTaskCount + 2);\n        await().untilAsserted(() -> assertTrue(retryReport.metadataReportRetry.retryScheduledFuture.isCancelled()));\n        await().untilAsserted(() -> assertTrue(retryReport.metadataReportRetry.retryExecutor.isShutdown()));\n    }\n\n    private MetadataIdentifier storeProvider(\n            AbstractMetadataReport abstractMetadataReport,\n            String interfaceName,\n            String version,\n            String group,\n            String application)\n            throws ClassNotFoundException {\n        URL url = URL.valueOf(\n                \"xxx://\" + NetUtils.getLocalAddress().getHostName() + \":4444/\" + interfaceName + \"?version=\" + version\n                        + \"&application=\" + application + (group == null ? \"\" : \"&group=\" + group) + \"&testPKey=8989\");\n\n        MetadataIdentifier providerMetadataIdentifier =\n                new MetadataIdentifier(interfaceName, version, group, PROVIDER_SIDE, application);\n        Class interfaceClass = Class.forName(interfaceName);\n        FullServiceDefinition fullServiceDefinition =\n                ServiceDefinitionBuilder.buildFullDefinition(interfaceClass, url.getParameters());\n\n        abstractMetadataReport.storeProviderMetadata(providerMetadataIdentifier, fullServiceDefinition);\n\n        return providerMetadataIdentifier;\n    }\n\n    private MetadataIdentifier storeConsumer(\n            AbstractMetadataReport abstractMetadataReport,\n            String interfaceName,\n            String version,\n            String group,\n            String application,\n            Map<String, String> tmp) {\n        URL url = URL.valueOf(\n                \"xxx://\" + NetUtils.getLocalAddress().getHostName() + \":4444/\" + interfaceName + \"?version=\" + version\n                        + \"&application=\" + application + (group == null ? \"\" : \"&group=\" + group) + \"&testPKey=9090\");\n\n        tmp.putAll(url.getParameters());\n        MetadataIdentifier consumerMetadataIdentifier =\n                new MetadataIdentifier(interfaceName, version, group, CONSUMER_SIDE, application);\n\n        abstractMetadataReport.storeConsumerMetadata(consumerMetadataIdentifier, tmp);\n\n        return consumerMetadataIdentifier;\n    }\n\n    @Test\n    void testPublishAll() throws ClassNotFoundException {\n        ThreadPoolExecutor reportCacheExecutor = (ThreadPoolExecutor) abstractMetadataReport.getReportCacheExecutor();\n\n        assertTrue(abstractMetadataReport.store.isEmpty());\n        assertTrue(abstractMetadataReport.allMetadataReports.isEmpty());\n        String interfaceName = \"org.apache.dubbo.metadata.store.InterfaceNameTestService\";\n        String version = \"1.0.0\";\n        String group = null;\n        String application = \"vic\";\n        long completedTaskCount1 = reportCacheExecutor.getCompletedTaskCount();\n        MetadataIdentifier providerMetadataIdentifier1 =\n                storeProvider(abstractMetadataReport, interfaceName, version, group, application);\n        await().until(() -> reportCacheExecutor.getCompletedTaskCount() > completedTaskCount1);\n        assertEquals(1, abstractMetadataReport.allMetadataReports.size());\n        assertTrue(((FullServiceDefinition) abstractMetadataReport.allMetadataReports.get(providerMetadataIdentifier1))\n                .getParameters()\n                .containsKey(\"testPKey\"));\n\n        long completedTaskCount2 = reportCacheExecutor.getCompletedTaskCount();\n        MetadataIdentifier providerMetadataIdentifier2 =\n                storeProvider(abstractMetadataReport, interfaceName, version + \"_2\", group + \"_2\", application);\n        await().until(() -> reportCacheExecutor.getCompletedTaskCount() > completedTaskCount2);\n        assertEquals(2, abstractMetadataReport.allMetadataReports.size());\n        assertTrue(((FullServiceDefinition) abstractMetadataReport.allMetadataReports.get(providerMetadataIdentifier2))\n                .getParameters()\n                .containsKey(\"testPKey\"));\n        assertEquals(\n                ((FullServiceDefinition) abstractMetadataReport.allMetadataReports.get(providerMetadataIdentifier2))\n                        .getParameters()\n                        .get(\"version\"),\n                version + \"_2\");\n\n        Map<String, String> tmpMap = new HashMap<>();\n        tmpMap.put(\"testKey\", \"value\");\n        long completedTaskCount3 = reportCacheExecutor.getCompletedTaskCount();\n        MetadataIdentifier consumerMetadataIdentifier =\n                storeConsumer(abstractMetadataReport, interfaceName, version + \"_3\", group + \"_3\", application, tmpMap);\n        await().until(() -> reportCacheExecutor.getCompletedTaskCount() > completedTaskCount3);\n        assertEquals(3, abstractMetadataReport.allMetadataReports.size());\n\n        Map tmpMapResult = (Map) abstractMetadataReport.allMetadataReports.get(consumerMetadataIdentifier);\n        assertEquals(\"9090\", tmpMapResult.get(\"testPKey\"));\n        assertEquals(\"value\", tmpMapResult.get(\"testKey\"));\n        assertEquals(3, abstractMetadataReport.store.size());\n\n        abstractMetadataReport.store.clear();\n\n        assertEquals(0, abstractMetadataReport.store.size());\n\n        long completedTaskCount4 = reportCacheExecutor.getCompletedTaskCount();\n        abstractMetadataReport.publishAll();\n        await().until(() -> reportCacheExecutor.getCompletedTaskCount() > completedTaskCount4);\n\n        assertEquals(3, abstractMetadataReport.store.size());\n\n        String v = abstractMetadataReport.store.get(providerMetadataIdentifier1.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));\n        FullServiceDefinition data = JsonUtils.toJavaObject(v, FullServiceDefinition.class);\n        checkParam(data.getParameters(), application, version);\n\n        String v2 = abstractMetadataReport.store.get(providerMetadataIdentifier2.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));\n        data = JsonUtils.toJavaObject(v2, FullServiceDefinition.class);\n        checkParam(data.getParameters(), application, version + \"_2\");\n\n        String v3 = abstractMetadataReport.store.get(consumerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));\n        Map v3Map = JsonUtils.toJavaObject(v3, Map.class);\n        checkParam(v3Map, application, version + \"_3\");\n    }\n\n    @Test\n    void testCalculateStartTime() {\n        for (int i = 0; i < 300; i++) {\n            long t = abstractMetadataReport.calculateStartTime() + System.currentTimeMillis();\n            Calendar c = Calendar.getInstance();\n            c.setTimeInMillis(t);\n            assertTrue(c.get(Calendar.HOUR_OF_DAY) >= 2);\n            assertTrue(c.get(Calendar.HOUR_OF_DAY) <= 6);\n        }\n    }\n\n    private void checkParam(Map<String, String> map, String application, String version) {\n        assertEquals(map.get(\"application\"), application);\n        assertEquals(map.get(\"version\"), version);\n    }\n\n    private static class NewMetadataReport extends AbstractMetadataReport {\n\n        Map<String, String> store = new ConcurrentHashMap<>();\n\n        public NewMetadataReport(URL metadataReportURL, ApplicationModel applicationModel) {\n            super(metadataReportURL);\n            this.applicationModel = applicationModel;\n        }\n\n        @Override\n        protected void doStoreProviderMetadata(\n                MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) {\n            store.put(providerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), serviceDefinitions);\n        }\n\n        @Override\n        protected void doStoreConsumerMetadata(\n                MetadataIdentifier consumerMetadataIdentifier, String serviceParameterString) {\n            store.put(consumerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), serviceParameterString);\n        }\n\n        @Override\n        protected void doSaveMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n\n        @Override\n        protected void doRemoveMetadata(ServiceMetadataIdentifier metadataIdentifier) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n\n        @Override\n        protected List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n\n        @Override\n        protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urls) {}\n\n        @Override\n        protected String doGetSubscribedURLs(SubscriberMetadataIdentifier metadataIdentifier) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n\n        @Override\n        public String getServiceDefinition(MetadataIdentifier consumerMetadataIdentifier) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n\n        @Override\n        public void removeServiceAppMappingListener(String serviceKey, MappingListener listener) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n    }\n\n    private static class RetryMetadataReport extends AbstractMetadataReport {\n\n        Map<String, String> store = new ConcurrentHashMap<>();\n        int needRetryTimes;\n        int executeTimes = 0;\n        Semaphore semaphore = new Semaphore(Integer.MAX_VALUE);\n\n        public RetryMetadataReport(URL metadataReportURL, int needRetryTimes, ApplicationModel applicationModel) {\n            super(metadataReportURL);\n            this.needRetryTimes = needRetryTimes;\n            this.applicationModel = applicationModel;\n        }\n\n        @Override\n        protected void doStoreProviderMetadata(\n                MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) {\n            ++executeTimes;\n            logger.info(\"***\" + executeTimes + \";\" + System.currentTimeMillis());\n            semaphore.acquireUninterruptibly();\n            if (executeTimes <= needRetryTimes) {\n                throw new RuntimeException(\"must retry:\" + executeTimes);\n            }\n            store.put(providerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), serviceDefinitions);\n        }\n\n        @Override\n        protected void doStoreConsumerMetadata(\n                MetadataIdentifier consumerMetadataIdentifier, String serviceParameterString) {\n            ++executeTimes;\n            if (executeTimes <= needRetryTimes) {\n                throw new RuntimeException(\"must retry:\" + executeTimes);\n            }\n            store.put(consumerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), serviceParameterString);\n        }\n\n        @Override\n        protected void doSaveMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n\n        @Override\n        protected void doRemoveMetadata(ServiceMetadataIdentifier metadataIdentifier) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n\n        @Override\n        protected List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n\n        @Override\n        protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urls) {}\n\n        @Override\n        protected String doGetSubscribedURLs(SubscriberMetadataIdentifier metadataIdentifier) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n\n        @Override\n        public String getServiceDefinition(MetadataIdentifier consumerMetadataIdentifier) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n\n        @Override\n        public void removeServiceAppMappingListener(String serviceKey, MappingListener listener) {\n            throw new UnsupportedOperationException(\n                    \"This extension does not support working as a remote metadata center.\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InterfaceNameTestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store;\n\n/**\n * 2018/9/19\n */\npublic interface InterfaceNameTestService {\n\n    void test();\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InterfaceNameTestService2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store;\n\n/**\n * 2018/9/19\n */\npublic interface InterfaceNameTestService2 {\n\n    void test2();\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RetryTestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store;\n\n/**\n * 2018/10/26\n */\npublic interface RetryTestService {\n\n    void sayHello(String input);\n\n    String getName();\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/test/JTestMetadataReport4Test.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.test;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.metadata.MappingListener;\nimport org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;\nimport org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.support.AbstractMetadataReport;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * ZookeeperRegistry\n */\nclass JTestMetadataReport4Test extends AbstractMetadataReport {\n\n    private static final Logger logger = LoggerFactory.getLogger(JTestMetadataReport4Test.class);\n\n    public JTestMetadataReport4Test(URL url) {\n        super(url);\n    }\n\n    public volatile Map<String, String> store = new ConcurrentHashMap<>();\n\n    private static String getProtocol(URL url) {\n        String protocol = url.getSide();\n        protocol = protocol == null ? url.getProtocol() : protocol;\n        return protocol;\n    }\n\n    @Override\n    protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) {\n        store.put(providerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), serviceDefinitions);\n    }\n\n    @Override\n    protected void doStoreConsumerMetadata(\n            MetadataIdentifier consumerMetadataIdentifier, String serviceParameterString) {\n        store.put(consumerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), serviceParameterString);\n    }\n\n    @Override\n    protected void doSaveMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) {\n        store.put(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), url.toFullString());\n    }\n\n    @Override\n    protected void doRemoveMetadata(ServiceMetadataIdentifier metadataIdentifier) {\n        store.remove(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));\n    }\n\n    @Override\n    protected List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {\n        return Arrays.asList(store.getOrDefault(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), \"\"));\n    }\n\n    @Override\n    protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urls) {\n        store.put(subscriberMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), urls);\n    }\n\n    @Override\n    protected String doGetSubscribedURLs(SubscriberMetadataIdentifier metadataIdentifier) {\n        throw new UnsupportedOperationException(\"This extension does not support working as a remote metadata center.\");\n    }\n\n    public static String getProviderKey(URL url) {\n        return new MetadataIdentifier(url).getUniqueKey(KeyTypeEnum.UNIQUE_KEY);\n    }\n\n    public static String getConsumerKey(URL url) {\n        return new MetadataIdentifier(url).getUniqueKey(KeyTypeEnum.UNIQUE_KEY);\n    }\n\n    @Override\n    public String getServiceDefinition(MetadataIdentifier consumerMetadataIdentifier) {\n        return store.get(consumerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));\n    }\n\n    @Override\n    public void removeServiceAppMappingListener(String serviceKey, MappingListener listener) {}\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/test/JTestMetadataReportFactory4Test.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.test;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory;\n\n/**\n * ZookeeperRegistryFactory.\n */\npublic class JTestMetadataReportFactory4Test extends AbstractMetadataReportFactory {\n\n    @Override\n    public MetadataReport createMetadataReport(URL url) {\n        return new JTestMetadataReport4Test(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataParamsFilter",
    "content": "customized=org.apache.dubbo.metadata.filter.CustomizedParamsFilter\nexcluded=org.apache.dubbo.metadata.filter.ExcludedParamsFilter\nexcluded2=org.apache.dubbo.metadata.filter.ExcludedParamsFilter2\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory",
    "content": "JTest=org.apache.dubbo.metadata.test.JTestMetadataReportFactory4Test"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/resources/META-INF/dubbo/service-name-mapping.properties",
    "content": "dubbo\\:com.acme.Interface1\\:default = Service1\nthirft\\:com.acme.InterfaceX = Service1,Service2\nrest\\:com.acme.interfaceN = Service3\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-api/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-definition-protobuf/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metadata</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-metadata-definition-protobuf</artifactId>\n\n  <dependencies>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java-util</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-definition-protobuf/src/main/java/org/apache/dubbo/metadata/definition/protobuf/ProtobufTypeBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.protobuf;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.metadata.definition.TypeDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.builder.TypeBuilder;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport com.google.protobuf.ByteString;\nimport com.google.protobuf.Descriptors;\nimport com.google.protobuf.GeneratedMessageV3;\nimport com.google.protobuf.ProtocolStringList;\nimport com.google.protobuf.UnknownFieldSet;\n\n@Activate(onClass = \"com.google.protobuf.GeneratedMessageV3\")\npublic class ProtobufTypeBuilder implements TypeBuilder, Prioritized {\n    private final Logger logger = LoggerFactory.getLogger(getClass());\n    private static final Pattern MAP_PATTERN = Pattern.compile(\"^java\\\\.util\\\\.Map<(\\\\S+), (\\\\S+)>$\");\n    private static final Pattern LIST_PATTERN = Pattern.compile(\"^java\\\\.util\\\\.List<(\\\\S+)>$\");\n    private static final List<String> LIST = null;\n    /**\n     * provide a List<String> type for TypeDefinitionBuilder.build(type,class,cache)\n     * \"repeated string\" transform to ProtocolStringList, should be build as List<String> type.\n     */\n    private static Type STRING_LIST_TYPE;\n\n    private final boolean protobufExist;\n\n    static {\n        try {\n            STRING_LIST_TYPE =\n                    ProtobufTypeBuilder.class.getDeclaredField(\"LIST\").getGenericType();\n        } catch (NoSuchFieldException e) {\n            // do nothing\n        }\n    }\n\n    public ProtobufTypeBuilder() {\n        protobufExist = checkProtobufExist();\n    }\n\n    private boolean checkProtobufExist() {\n        try {\n            Class.forName(\"com.google.protobuf.GeneratedMessageV3\");\n            return true;\n        } catch (ClassNotFoundException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public int getPriority() {\n        return -1;\n    }\n\n    @Override\n    public boolean accept(Class<?> clazz) {\n        if (clazz == null) {\n            return false;\n        }\n\n        if (!protobufExist) {\n            return false;\n        }\n\n        return GeneratedMessageV3.class.isAssignableFrom(clazz);\n    }\n\n    @Override\n    public TypeDefinition build(Type type, Class<?> clazz, Map<String, TypeDefinition> typeCache) {\n        String canonicalName = clazz.getCanonicalName();\n        TypeDefinition typeDefinition = typeCache.get(canonicalName);\n        if (typeDefinition != null) {\n            return typeDefinition;\n        }\n        try {\n            GeneratedMessageV3.Builder builder = getMessageBuilder(clazz);\n            typeDefinition = buildProtobufTypeDefinition(clazz, builder, typeCache);\n            typeCache.put(canonicalName, typeDefinition);\n        } catch (Exception e) {\n            logger.info(\"TypeDefinition build failed.\", e);\n        }\n\n        return typeDefinition;\n    }\n\n    private GeneratedMessageV3.Builder getMessageBuilder(Class<?> requestType) throws Exception {\n        Method method = requestType.getMethod(\"newBuilder\");\n        return (GeneratedMessageV3.Builder) method.invoke(null, null);\n    }\n\n    private TypeDefinition buildProtobufTypeDefinition(\n            Class<?> clazz, GeneratedMessageV3.Builder builder, Map<String, TypeDefinition> typeCache) {\n        String canonicalName = clazz.getCanonicalName();\n        TypeDefinition td = new TypeDefinition(canonicalName);\n        if (builder == null) {\n            return td;\n        }\n\n        Map<String, String> properties = new HashMap<>();\n        Method[] methods = builder.getClass().getDeclaredMethods();\n        for (Method method : methods) {\n            String methodName = method.getName();\n\n            if (isSimplePropertySettingMethod(method)) {\n                // property of custom type or primitive type\n                TypeDefinition fieldTd = TypeDefinitionBuilder.build(\n                        method.getGenericParameterTypes()[0], method.getParameterTypes()[0], typeCache);\n                properties.put(generateSimpleFiledName(methodName), fieldTd.getType());\n            } else if (isMapPropertySettingMethod(method)) {\n                // property of map\n                Type type = method.getGenericParameterTypes()[0];\n                String fieldName = generateMapFieldName(methodName);\n                validateMapType(fieldName, type.toString());\n                TypeDefinition fieldTd = TypeDefinitionBuilder.build(type, method.getParameterTypes()[0], typeCache);\n                properties.put(fieldName, fieldTd.getType());\n            } else if (isListPropertyGettingMethod(method)) {\n                // property of list\n                Type type = method.getGenericReturnType();\n                String fieldName = generateListFieldName(methodName);\n                TypeDefinition fieldTd;\n                if (ProtocolStringList.class.isAssignableFrom(method.getReturnType())) {\n                    // property defined as \"repeated string\" transform to ProtocolStringList,\n                    // should be build as List<String>.\n                    fieldTd = TypeDefinitionBuilder.build(STRING_LIST_TYPE, List.class, typeCache);\n                } else {\n                    // property without generic type should not be build ex method return List\n                    if (!LIST_PATTERN.matcher(type.toString()).matches()) {\n                        continue;\n                    }\n                    fieldTd = TypeDefinitionBuilder.build(type, method.getReturnType(), typeCache);\n                }\n                properties.put(fieldName, fieldTd.getType());\n            }\n        }\n        td.setProperties(properties);\n        return td;\n    }\n\n    /**\n     * 1. Unsupported Map with key type is not String <br/>\n     * Bytes is a primitive type in Proto, transform to ByteString.class in java<br/>\n     *\n     * @param fieldName\n     * @param typeName\n     * @return\n     */\n    private void validateMapType(String fieldName, String typeName) {\n        Matcher matcher = MAP_PATTERN.matcher(typeName);\n        if (!matcher.matches()) {\n            throw new IllegalArgumentException(\"Map protobuf property \" + fieldName + \"of Type \" + typeName\n                    + \" can't be parsed.The type name should match[\" + MAP_PATTERN.toString() + \"].\");\n        }\n    }\n\n    /**\n     * get unCollection unMap property name from setting method.<br/>\n     * ex:setXXX();<br/>\n     *\n     * @param methodName\n     * @return\n     */\n    private String generateSimpleFiledName(String methodName) {\n        return toCamelCase(methodName.substring(3));\n    }\n\n    /**\n     * get map property name from setting method.<br/>\n     * ex: putAllXXX();<br/>\n     *\n     * @param methodName\n     * @return\n     */\n    private String generateMapFieldName(String methodName) {\n        return toCamelCase(methodName.substring(6));\n    }\n\n    /**\n     * get list property name from setting method.<br/>\n     * ex： getXXXList()<br/>\n     *\n     * @param methodName\n     * @return\n     */\n    private String generateListFieldName(String methodName) {\n        return toCamelCase(methodName.substring(3, methodName.length() - 4));\n    }\n\n    private String toCamelCase(String nameString) {\n        char[] chars = nameString.toCharArray();\n        chars[0] = Character.toLowerCase(chars[0]);\n        return new String(chars);\n    }\n\n    /**\n     * judge custom type or primitive type property<br/>\n     * 1. proto3 grammar ex: string name = 1 <br/>\n     * 2. proto3 grammar ex: optional string name =1 <br/>\n     * generated setting method ex: setNameValue(String name);\n     *\n     * @param method\n     * @return\n     */\n    private boolean isSimplePropertySettingMethod(Method method) {\n        String methodName = method.getName();\n        Class<?>[] types = method.getParameterTypes();\n\n        if (!methodName.startsWith(\"set\") || types.length != 1) {\n            return false;\n        }\n\n        // filter general setting method\n        // 1. - setUnknownFields( com.google.protobuf.UnknownFieldSet unknownFields)\n        // 2. - setField(com.google.protobuf.Descriptors.FieldDescriptor field,java.lang.Object value)\n        // 3. - setRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field,int index,java.lang.Object value）\n        if (\"setField\".equals(methodName) && types[0].equals(Descriptors.FieldDescriptor.class)\n                || \"setUnknownFields\".equals(methodName) && types[0].equals(UnknownFieldSet.class)\n                || \"setRepeatedField\".equals(methodName) && types[0].equals(Descriptors.FieldDescriptor.class)) {\n            return false;\n        }\n\n        // String property has two setting method.\n        // skip setXXXBytes(com.google.protobuf.ByteString value)\n        // parse setXXX(String string)\n        if (methodName.endsWith(\"Bytes\") && types[0].equals(ByteString.class)) {\n            return false;\n        }\n\n        // Protobuf property has two setting method.\n        // skip setXXX(com.google.protobuf.Builder value)\n        // parse setXXX(com.google.protobuf.Message value)\n        if (GeneratedMessageV3.Builder.class.isAssignableFrom(types[0])) {\n            return false;\n        }\n\n        // Enum property has two setting method.\n        // skip setXXXValue(int value)\n        // parse setXXX(SomeEnum value)\n        return !methodName.endsWith(\"Value\") || types[0] != int.class;\n    }\n\n    /**\n     * judge List property</br>\n     * proto3 grammar ex: repeated string names; </br>\n     * generated getting method：List<String> getNamesList()\n     *\n     * @param method\n     * @return\n     */\n    boolean isListPropertyGettingMethod(Method method) {\n        String methodName = method.getName();\n        Class<?> type = method.getReturnType();\n\n        if (!methodName.startsWith(\"get\") || !methodName.endsWith(\"List\")) {\n            return false;\n        }\n\n        // skip the setting method with Pb entity builder as parameter\n        if (methodName.endsWith(\"BuilderList\")) {\n            return false;\n        }\n\n        // if field name end with List, should skip\n        return List.class.isAssignableFrom(type);\n    }\n\n    /**\n     * judge map property</br>\n     * proto3 grammar : map<string,string> card = 1; </br>\n     * generated setting method: putAllCards(java.util.Map<String, string> values) </br>\n     *\n     * @param methodTemp\n     * @return\n     */\n    private boolean isMapPropertySettingMethod(Method methodTemp) {\n        String methodName = methodTemp.getName();\n        Class[] parameters = methodTemp.getParameterTypes();\n        return methodName.startsWith(\"putAll\") && parameters.length == 1 && Map.class.isAssignableFrom(parameters[0]);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-definition-protobuf/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder",
    "content": "protobuf=org.apache.dubbo.metadata.definition.protobuf.ProtobufTypeBuilder\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-definition-protobuf/src/test/java/org/apache/dubbo/metadata/definition/protobuf/ProtobufTypeBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.protobuf;\n\nimport org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.TypeDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.MethodDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.metadata.definition.protobuf.model.ServiceInterface;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n/**\n * 2019-07-01\n */\nclass ProtobufTypeBuilderTest {\n    @Test\n    void testProtobufBuilder() {\n        TypeDefinitionBuilder.initBuilders(FrameworkModel.defaultModel());\n\n        // TEST Pb Service metaData builder\n        FullServiceDefinition serviceDefinition = ServiceDefinitionBuilder.buildFullDefinition(ServiceInterface.class);\n        MethodDefinition methodDefinition = serviceDefinition.getMethods().get(0);\n        List<TypeDefinition> types = serviceDefinition.getTypes();\n        String parameterName = methodDefinition.getParameterTypes()[0];\n        TypeDefinition typeDefinition = null;\n        for (TypeDefinition type : serviceDefinition.getTypes()) {\n            if (parameterName.equals(type.getType())) {\n                typeDefinition = type;\n                break;\n            }\n        }\n        Map<String, String> propertiesMap = typeDefinition.getProperties();\n        assertThat(propertiesMap.size(), is(11));\n        assertThat(propertiesMap.containsKey(\"money\"), is(true));\n        assertThat(getTypeName(propertiesMap.get(\"money\"), types), equalTo(\"double\"));\n        assertThat(propertiesMap.containsKey(\"cash\"), is(true));\n        assertThat(getTypeName(propertiesMap.get(\"cash\"), types), equalTo(\"float\"));\n        assertThat(propertiesMap.containsKey(\"age\"), is(true));\n        assertThat(getTypeName(propertiesMap.get(\"age\"), types), equalTo(\"int\"));\n        assertThat(propertiesMap.containsKey(\"num\"), is(true));\n        assertThat(getTypeName(propertiesMap.get(\"num\"), types), equalTo(\"long\"));\n        assertThat(propertiesMap.containsKey(\"sex\"), is(true));\n        assertThat(getTypeName(propertiesMap.get(\"sex\"), types), equalTo(\"boolean\"));\n        assertThat(propertiesMap.containsKey(\"name\"), is(true));\n        assertThat(getTypeName(propertiesMap.get(\"name\"), types), equalTo(\"java.lang.String\"));\n        assertThat(propertiesMap.containsKey(\"msg\"), is(true));\n        assertThat(getTypeName(propertiesMap.get(\"msg\"), types), equalTo(\"com.google.protobuf.ByteString\"));\n        assertThat(propertiesMap.containsKey(\"phone\"), is(true));\n        assertThat(\n                getTypeName(propertiesMap.get(\"phone\"), types),\n                equalTo(\"java.util.List<org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\"));\n        assertThat(propertiesMap.containsKey(\"doubleMap\"), is(true));\n        assertThat(\n                getTypeName(propertiesMap.get(\"doubleMap\"), types),\n                equalTo(\n                        \"java.util.Map<java.lang.String,org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\"));\n        assertThat(\n                getTypeName(propertiesMap.get(\"bytesList\"), types),\n                equalTo(\"java.util.List<com.google.protobuf.ByteString>\"));\n        assertThat(\n                getTypeName(propertiesMap.get(\"bytesMap\"), types),\n                equalTo(\"java.util.Map<java.lang.String,com.google.protobuf.ByteString>\"));\n    }\n\n    private static String getTypeName(String type, List<TypeDefinition> types) {\n        for (TypeDefinition typeDefinition : types) {\n            if (type.equals(typeDefinition.getType())) {\n                return typeDefinition.getType();\n            }\n        }\n        return type;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-definition-protobuf/src/test/java/org/apache/dubbo/metadata/definition/protobuf/model/GooglePB.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.protobuf.model;\n\npublic final class GooglePB {\n    private GooglePB() {}\n\n    public static void registerAllExtensions(com.google.protobuf.ExtensionRegistryLite registry) {}\n\n    public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry) {\n        registerAllExtensions((com.google.protobuf.ExtensionRegistryLite) registry);\n    }\n    /**\n     * Protobuf enum {@code org.apache.dubbo.metadata.definition.protobuf.model.PhoneType}\n     */\n    public enum PhoneType implements com.google.protobuf.ProtocolMessageEnum {\n        /**\n         * <code>MOBILE = 0;</code>\n         */\n        MOBILE(0),\n        /**\n         * <code>HOME = 1;</code>\n         */\n        HOME(1),\n        /**\n         * <code>WORK = 2;</code>\n         */\n        WORK(2),\n        ;\n\n        /**\n         * <code>MOBILE = 0;</code>\n         */\n        public static final int MOBILE_VALUE = 0;\n        /**\n         * <code>HOME = 1;</code>\n         */\n        public static final int HOME_VALUE = 1;\n        /**\n         * <code>WORK = 2;</code>\n         */\n        public static final int WORK_VALUE = 2;\n\n        public final int getNumber() {\n            return value;\n        }\n\n        /**\n         * @deprecated Use {@link #forNumber(int)} instead.\n         */\n        @java.lang.Deprecated\n        public static PhoneType valueOf(int value) {\n            return forNumber(value);\n        }\n\n        public static PhoneType forNumber(int value) {\n            switch (value) {\n                case 0:\n                    return MOBILE;\n                case 1:\n                    return HOME;\n                case 2:\n                    return WORK;\n                default:\n                    return null;\n            }\n        }\n\n        public static com.google.protobuf.Internal.EnumLiteMap<PhoneType> internalGetValueMap() {\n            return internalValueMap;\n        }\n\n        private static final com.google.protobuf.Internal.EnumLiteMap<PhoneType> internalValueMap =\n                new com.google.protobuf.Internal.EnumLiteMap<PhoneType>() {\n                    public PhoneType findValueByNumber(int number) {\n                        return PhoneType.forNumber(number);\n                    }\n                };\n\n        public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() {\n            return getDescriptor().getValues().get(ordinal());\n        }\n\n        public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() {\n            return getDescriptor();\n        }\n\n        public static final com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() {\n            return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.getDescriptor()\n                    .getEnumTypes()\n                    .get(0);\n        }\n\n        private static final PhoneType[] VALUES = values();\n\n        public static PhoneType valueOf(com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n            if (desc.getType() != getDescriptor()) {\n                throw new java.lang.IllegalArgumentException(\"EnumValueDescriptor is not for this type.\");\n            }\n            return VALUES[desc.getIndex()];\n        }\n\n        private final int value;\n\n        private PhoneType(int value) {\n            this.value = value;\n        }\n\n        // @@protoc_insertion_point(enum_scope:org.apache.dubbo.metadata.definition.protobuf.model.PhoneType)\n    }\n\n    public interface PBRequestTypeOrBuilder\n            extends\n            // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType)\n            com.google.protobuf.MessageOrBuilder {\n\n        /**\n         * <code>optional double money = 1;</code>\n         */\n        boolean hasMoney();\n        /**\n         * <code>optional double money = 1;</code>\n         */\n        double getMoney();\n\n        /**\n         * <code>optional float cash = 2;</code>\n         */\n        boolean hasCash();\n        /**\n         * <code>optional float cash = 2;</code>\n         */\n        float getCash();\n\n        /**\n         * <code>optional int32 age = 3;</code>\n         */\n        boolean hasAge();\n        /**\n         * <code>optional int32 age = 3;</code>\n         */\n        int getAge();\n\n        /**\n         * <code>optional int64 num = 4;</code>\n         */\n        boolean hasNum();\n        /**\n         * <code>optional int64 num = 4;</code>\n         */\n        long getNum();\n\n        /**\n         * <code>optional bool sex = 5;</code>\n         */\n        boolean hasSex();\n        /**\n         * <code>optional bool sex = 5;</code>\n         */\n        boolean getSex();\n\n        /**\n         * <code>optional string name = 6;</code>\n         */\n        boolean hasName();\n        /**\n         * <code>optional string name = 6;</code>\n         */\n        java.lang.String getName();\n        /**\n         * <code>optional string name = 6;</code>\n         */\n        com.google.protobuf.ByteString getNameBytes();\n\n        /**\n         * <code>optional bytes msg = 7;</code>\n         */\n        boolean hasMsg();\n        /**\n         * <code>optional bytes msg = 7;</code>\n         */\n        com.google.protobuf.ByteString getMsg();\n\n        /**\n         * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n         */\n        java.util.List<org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber> getPhoneList();\n        /**\n         * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n         */\n        org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getPhone(int index);\n        /**\n         * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n         */\n        int getPhoneCount();\n        /**\n         * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n         */\n        java.util.List<? extends org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumberOrBuilder>\n                getPhoneOrBuilderList();\n        /**\n         * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n         */\n        org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumberOrBuilder getPhoneOrBuilder(int index);\n\n        /**\n         * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n         */\n        int getDoubleMapCount();\n        /**\n         * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n         */\n        boolean containsDoubleMap(java.lang.String key);\n        /**\n         * Use {@link #getDoubleMapMap()} instead.\n         */\n        @java.lang.Deprecated\n        java.util.Map<java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                getDoubleMap();\n        /**\n         * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n         */\n        java.util.Map<java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                getDoubleMapMap();\n        /**\n         * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n         */\n        org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getDoubleMapOrDefault(\n                java.lang.String key,\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber defaultValue);\n        /**\n         * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n         */\n        org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getDoubleMapOrThrow(\n                java.lang.String key);\n\n        /**\n         * <code>repeated bytes bytesList = 10;</code>\n         */\n        java.util.List<com.google.protobuf.ByteString> getBytesListList();\n        /**\n         * <code>repeated bytes bytesList = 10;</code>\n         */\n        int getBytesListCount();\n        /**\n         * <code>repeated bytes bytesList = 10;</code>\n         */\n        com.google.protobuf.ByteString getBytesList(int index);\n\n        /**\n         * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n         */\n        int getBytesMapCount();\n        /**\n         * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n         */\n        boolean containsBytesMap(java.lang.String key);\n        /**\n         * Use {@link #getBytesMapMap()} instead.\n         */\n        @java.lang.Deprecated\n        java.util.Map<java.lang.String, com.google.protobuf.ByteString> getBytesMap();\n        /**\n         * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n         */\n        java.util.Map<java.lang.String, com.google.protobuf.ByteString> getBytesMapMap();\n        /**\n         * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n         */\n        com.google.protobuf.ByteString getBytesMapOrDefault(\n                java.lang.String key, com.google.protobuf.ByteString defaultValue);\n        /**\n         * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n         */\n        com.google.protobuf.ByteString getBytesMapOrThrow(java.lang.String key);\n    }\n    /**\n     * Protobuf type {@code org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType}\n     */\n    public static final class PBRequestType extends com.google.protobuf.GeneratedMessageV3\n            implements\n            // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType)\n            PBRequestTypeOrBuilder {\n        private static final long serialVersionUID = 0L;\n        // Use PBRequestType.newBuilder() to construct.\n        private PBRequestType(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n            super(builder);\n        }\n\n        private PBRequestType() {\n            money_ = 0D;\n            cash_ = 0F;\n            age_ = 0;\n            num_ = 0L;\n            sex_ = false;\n            name_ = \"\";\n            msg_ = com.google.protobuf.ByteString.EMPTY;\n            phone_ = java.util.Collections.emptyList();\n            bytesList_ = java.util.Collections.emptyList();\n        }\n\n        @java.lang.Override\n        public final com.google.protobuf.UnknownFieldSet getUnknownFields() {\n            return this.unknownFields;\n        }\n\n        private PBRequestType(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            this();\n            int mutable_bitField0_ = 0;\n            com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n                    com.google.protobuf.UnknownFieldSet.newBuilder();\n            try {\n                boolean done = false;\n                while (!done) {\n                    int tag = input.readTag();\n                    switch (tag) {\n                        case 0:\n                            done = true;\n                            break;\n                        default: {\n                            if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) {\n                                done = true;\n                            }\n                            break;\n                        }\n                        case 9: {\n                            bitField0_ |= 0x00000001;\n                            money_ = input.readDouble();\n                            break;\n                        }\n                        case 21: {\n                            bitField0_ |= 0x00000002;\n                            cash_ = input.readFloat();\n                            break;\n                        }\n                        case 24: {\n                            bitField0_ |= 0x00000004;\n                            age_ = input.readInt32();\n                            break;\n                        }\n                        case 32: {\n                            bitField0_ |= 0x00000008;\n                            num_ = input.readInt64();\n                            break;\n                        }\n                        case 40: {\n                            bitField0_ |= 0x00000010;\n                            sex_ = input.readBool();\n                            break;\n                        }\n                        case 50: {\n                            com.google.protobuf.ByteString bs = input.readBytes();\n                            bitField0_ |= 0x00000020;\n                            name_ = bs;\n                            break;\n                        }\n                        case 58: {\n                            bitField0_ |= 0x00000040;\n                            msg_ = input.readBytes();\n                            break;\n                        }\n                        case 66: {\n                            if (!((mutable_bitField0_ & 0x00000080) == 0x00000080)) {\n                                phone_ = new java.util.ArrayList<\n                                        org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>();\n                                mutable_bitField0_ |= 0x00000080;\n                            }\n                            phone_.add(input.readMessage(\n                                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.PARSER,\n                                    extensionRegistry));\n                            break;\n                        }\n                        case 74: {\n                            if (!((mutable_bitField0_ & 0x00000100) == 0x00000100)) {\n                                doubleMap_ = com.google.protobuf.MapField.newMapField(\n                                        DoubleMapDefaultEntryHolder.defaultEntry);\n                                mutable_bitField0_ |= 0x00000100;\n                            }\n                            com.google.protobuf.MapEntry<String, PhoneNumber> doubleMap__ = input.readMessage(\n                                    DoubleMapDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry);\n                            doubleMap_.getMutableMap().put(doubleMap__.getKey(), doubleMap__.getValue());\n                            break;\n                        }\n                        case 82: {\n                            if (!((mutable_bitField0_ & 0x00000200) == 0x00000200)) {\n                                bytesList_ = new java.util.ArrayList<com.google.protobuf.ByteString>();\n                                mutable_bitField0_ |= 0x00000200;\n                            }\n                            bytesList_.add(input.readBytes());\n                            break;\n                        }\n                        case 90: {\n                            if (!((mutable_bitField0_ & 0x00000400) == 0x00000400)) {\n                                bytesMap_ = com.google.protobuf.MapField.newMapField(\n                                        BytesMapDefaultEntryHolder.defaultEntry);\n                                mutable_bitField0_ |= 0x00000400;\n                            }\n                            com.google.protobuf.MapEntry<String, com.google.protobuf.ByteString> bytesMap__ =\n                                    input.readMessage(\n                                            BytesMapDefaultEntryHolder.defaultEntry.getParserForType(),\n                                            extensionRegistry);\n                            bytesMap_.getMutableMap().put(bytesMap__.getKey(), bytesMap__.getValue());\n                            break;\n                        }\n                    }\n                }\n            } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                throw e.setUnfinishedMessage(this);\n            } catch (java.io.IOException e) {\n                throw new com.google.protobuf.InvalidProtocolBufferException(e).setUnfinishedMessage(this);\n            } finally {\n                if (((mutable_bitField0_ & 0x00000080) == 0x00000080)) {\n                    phone_ = java.util.Collections.unmodifiableList(phone_);\n                }\n                if (((mutable_bitField0_ & 0x00000200) == 0x00000200)) {\n                    bytesList_ = java.util.Collections.unmodifiableList(bytesList_);\n                }\n                this.unknownFields = unknownFields.build();\n                makeExtensionsImmutable();\n            }\n        }\n\n        public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n            return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                    .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_descriptor;\n        }\n\n        @SuppressWarnings({\"rawtypes\"})\n        protected com.google.protobuf.MapField internalGetMapField(int number) {\n            switch (number) {\n                case 9:\n                    return internalGetDoubleMap();\n                case 11:\n                    return internalGetBytesMap();\n                default:\n                    throw new RuntimeException(\"Invalid map field number: \" + number);\n            }\n        }\n\n        protected FieldAccessorTable internalGetFieldAccessorTable() {\n            return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                    .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_fieldAccessorTable\n                    .ensureFieldAccessorsInitialized(\n                            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.class,\n                            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.Builder.class);\n        }\n\n        private int bitField0_;\n        public static final int MONEY_FIELD_NUMBER = 1;\n        private double money_;\n        /**\n         * <code>optional double money = 1;</code>\n         */\n        public boolean hasMoney() {\n            return ((bitField0_ & 0x00000001) == 0x00000001);\n        }\n        /**\n         * <code>optional double money = 1;</code>\n         */\n        public double getMoney() {\n            return money_;\n        }\n\n        public static final int CASH_FIELD_NUMBER = 2;\n        private float cash_;\n        /**\n         * <code>optional float cash = 2;</code>\n         */\n        public boolean hasCash() {\n            return ((bitField0_ & 0x00000002) == 0x00000002);\n        }\n        /**\n         * <code>optional float cash = 2;</code>\n         */\n        public float getCash() {\n            return cash_;\n        }\n\n        public static final int AGE_FIELD_NUMBER = 3;\n        private int age_;\n        /**\n         * <code>optional int32 age = 3;</code>\n         */\n        public boolean hasAge() {\n            return ((bitField0_ & 0x00000004) == 0x00000004);\n        }\n        /**\n         * <code>optional int32 age = 3;</code>\n         */\n        public int getAge() {\n            return age_;\n        }\n\n        public static final int NUM_FIELD_NUMBER = 4;\n        private long num_;\n        /**\n         * <code>optional int64 num = 4;</code>\n         */\n        public boolean hasNum() {\n            return ((bitField0_ & 0x00000008) == 0x00000008);\n        }\n        /**\n         * <code>optional int64 num = 4;</code>\n         */\n        public long getNum() {\n            return num_;\n        }\n\n        public static final int SEX_FIELD_NUMBER = 5;\n        private boolean sex_;\n        /**\n         * <code>optional bool sex = 5;</code>\n         */\n        public boolean hasSex() {\n            return ((bitField0_ & 0x00000010) == 0x00000010);\n        }\n        /**\n         * <code>optional bool sex = 5;</code>\n         */\n        public boolean getSex() {\n            return sex_;\n        }\n\n        public static final int NAME_FIELD_NUMBER = 6;\n        private volatile java.lang.Object name_;\n        /**\n         * <code>optional string name = 6;</code>\n         */\n        public boolean hasName() {\n            return ((bitField0_ & 0x00000020) == 0x00000020);\n        }\n        /**\n         * <code>optional string name = 6;</code>\n         */\n        public java.lang.String getName() {\n            java.lang.Object ref = name_;\n            if (ref instanceof java.lang.String) {\n                return (java.lang.String) ref;\n            } else {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                java.lang.String s = bs.toStringUtf8();\n                if (bs.isValidUtf8()) {\n                    name_ = s;\n                }\n                return s;\n            }\n        }\n        /**\n         * <code>optional string name = 6;</code>\n         */\n        public com.google.protobuf.ByteString getNameBytes() {\n            java.lang.Object ref = name_;\n            if (ref instanceof java.lang.String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);\n                name_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        public static final int MSG_FIELD_NUMBER = 7;\n        private com.google.protobuf.ByteString msg_;\n        /**\n         * <code>optional bytes msg = 7;</code>\n         */\n        public boolean hasMsg() {\n            return ((bitField0_ & 0x00000040) == 0x00000040);\n        }\n        /**\n         * <code>optional bytes msg = 7;</code>\n         */\n        public com.google.protobuf.ByteString getMsg() {\n            return msg_;\n        }\n\n        public static final int PHONE_FIELD_NUMBER = 8;\n        private java.util.List<org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber> phone_;\n        /**\n         * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n         */\n        public java.util.List<org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber> getPhoneList() {\n            return phone_;\n        }\n        /**\n         * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n         */\n        public java.util.List<\n                        ? extends org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumberOrBuilder>\n                getPhoneOrBuilderList() {\n            return phone_;\n        }\n        /**\n         * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n         */\n        public int getPhoneCount() {\n            return phone_.size();\n        }\n        /**\n         * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n         */\n        public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getPhone(int index) {\n            return phone_.get(index);\n        }\n        /**\n         * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n         */\n        public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumberOrBuilder getPhoneOrBuilder(\n                int index) {\n            return phone_.get(index);\n        }\n\n        public static final int DOUBLEMAP_FIELD_NUMBER = 9;\n\n        private static final class DoubleMapDefaultEntryHolder {\n            static final com.google.protobuf.MapEntry<String, PhoneNumber> defaultEntry = com.google.protobuf.MapEntry\n                    .<java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                            newDefaultInstance(\n                                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                                            .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_DoubleMapEntry_descriptor,\n                                    com.google.protobuf.WireFormat.FieldType.STRING,\n                                    \"\",\n                                    com.google.protobuf.WireFormat.FieldType.MESSAGE,\n                                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber\n                                            .getDefaultInstance());\n        }\n\n        private com.google.protobuf.MapField<String, PhoneNumber> doubleMap_;\n\n        private com.google.protobuf.MapField<String, PhoneNumber> internalGetDoubleMap() {\n            if (doubleMap_ == null) {\n                return com.google.protobuf.MapField.emptyMapField(DoubleMapDefaultEntryHolder.defaultEntry);\n            }\n            return doubleMap_;\n        }\n\n        public int getDoubleMapCount() {\n            return internalGetDoubleMap().getMap().size();\n        }\n        /**\n         * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n         */\n        public boolean containsDoubleMap(java.lang.String key) {\n            if (key == null) {\n                throw new java.lang.NullPointerException();\n            }\n            return internalGetDoubleMap().getMap().containsKey(key);\n        }\n        /**\n         * Use {@link #getDoubleMapMap()} instead.\n         */\n        @java.lang.Deprecated\n        public java.util.Map<java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                getDoubleMap() {\n            return getDoubleMapMap();\n        }\n        /**\n         * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n         */\n        public java.util.Map<java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                getDoubleMapMap() {\n            return internalGetDoubleMap().getMap();\n        }\n        /**\n         * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n         */\n        public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getDoubleMapOrDefault(\n                java.lang.String key,\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber defaultValue) {\n            if (key == null) {\n                throw new java.lang.NullPointerException();\n            }\n            java.util.Map<java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                    map = internalGetDoubleMap().getMap();\n            return map.containsKey(key) ? map.get(key) : defaultValue;\n        }\n        /**\n         * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n         */\n        public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getDoubleMapOrThrow(\n                java.lang.String key) {\n            if (key == null) {\n                throw new java.lang.NullPointerException();\n            }\n            java.util.Map<java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                    map = internalGetDoubleMap().getMap();\n            if (!map.containsKey(key)) {\n                throw new java.lang.IllegalArgumentException();\n            }\n            return map.get(key);\n        }\n\n        public static final int BYTESLIST_FIELD_NUMBER = 10;\n        private java.util.List<com.google.protobuf.ByteString> bytesList_;\n        /**\n         * <code>repeated bytes bytesList = 10;</code>\n         */\n        public java.util.List<com.google.protobuf.ByteString> getBytesListList() {\n            return bytesList_;\n        }\n        /**\n         * <code>repeated bytes bytesList = 10;</code>\n         */\n        public int getBytesListCount() {\n            return bytesList_.size();\n        }\n        /**\n         * <code>repeated bytes bytesList = 10;</code>\n         */\n        public com.google.protobuf.ByteString getBytesList(int index) {\n            return bytesList_.get(index);\n        }\n\n        public static final int BYTESMAP_FIELD_NUMBER = 11;\n\n        private static final class BytesMapDefaultEntryHolder {\n            static final com.google.protobuf.MapEntry<String, com.google.protobuf.ByteString> defaultEntry =\n                    com.google.protobuf.MapEntry.<java.lang.String, com.google.protobuf.ByteString>newDefaultInstance(\n                            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                                    .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_BytesMapEntry_descriptor,\n                            com.google.protobuf.WireFormat.FieldType.STRING,\n                            \"\",\n                            com.google.protobuf.WireFormat.FieldType.BYTES,\n                            com.google.protobuf.ByteString.EMPTY);\n        }\n\n        private com.google.protobuf.MapField<String, com.google.protobuf.ByteString> bytesMap_;\n\n        private com.google.protobuf.MapField<String, com.google.protobuf.ByteString> internalGetBytesMap() {\n            if (bytesMap_ == null) {\n                return com.google.protobuf.MapField.emptyMapField(BytesMapDefaultEntryHolder.defaultEntry);\n            }\n            return bytesMap_;\n        }\n\n        public int getBytesMapCount() {\n            return internalGetBytesMap().getMap().size();\n        }\n        /**\n         * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n         */\n        public boolean containsBytesMap(java.lang.String key) {\n            if (key == null) {\n                throw new java.lang.NullPointerException();\n            }\n            return internalGetBytesMap().getMap().containsKey(key);\n        }\n        /**\n         * Use {@link #getBytesMapMap()} instead.\n         */\n        @java.lang.Deprecated\n        public java.util.Map<java.lang.String, com.google.protobuf.ByteString> getBytesMap() {\n            return getBytesMapMap();\n        }\n        /**\n         * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n         */\n        public java.util.Map<java.lang.String, com.google.protobuf.ByteString> getBytesMapMap() {\n            return internalGetBytesMap().getMap();\n        }\n        /**\n         * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n         */\n        public com.google.protobuf.ByteString getBytesMapOrDefault(\n                java.lang.String key, com.google.protobuf.ByteString defaultValue) {\n            if (key == null) {\n                throw new java.lang.NullPointerException();\n            }\n            java.util.Map<java.lang.String, com.google.protobuf.ByteString> map =\n                    internalGetBytesMap().getMap();\n            return map.containsKey(key) ? map.get(key) : defaultValue;\n        }\n        /**\n         * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n         */\n        public com.google.protobuf.ByteString getBytesMapOrThrow(java.lang.String key) {\n            if (key == null) {\n                throw new java.lang.NullPointerException();\n            }\n            java.util.Map<java.lang.String, com.google.protobuf.ByteString> map =\n                    internalGetBytesMap().getMap();\n            if (!map.containsKey(key)) {\n                throw new java.lang.IllegalArgumentException();\n            }\n            return map.get(key);\n        }\n\n        private byte memoizedIsInitialized = -1;\n\n        public final boolean isInitialized() {\n            byte isInitialized = memoizedIsInitialized;\n            if (isInitialized == 1) return true;\n            if (isInitialized == 0) return false;\n\n            for (int i = 0; i < getPhoneCount(); i++) {\n                if (!getPhone(i).isInitialized()) {\n                    memoizedIsInitialized = 0;\n                    return false;\n                }\n            }\n            for (org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber item :\n                    getDoubleMapMap().values()) {\n                if (!item.isInitialized()) {\n                    memoizedIsInitialized = 0;\n                    return false;\n                }\n            }\n            memoizedIsInitialized = 1;\n            return true;\n        }\n\n        public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n            if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                output.writeDouble(1, money_);\n            }\n            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                output.writeFloat(2, cash_);\n            }\n            if (((bitField0_ & 0x00000004) == 0x00000004)) {\n                output.writeInt32(3, age_);\n            }\n            if (((bitField0_ & 0x00000008) == 0x00000008)) {\n                output.writeInt64(4, num_);\n            }\n            if (((bitField0_ & 0x00000010) == 0x00000010)) {\n                output.writeBool(5, sex_);\n            }\n            if (((bitField0_ & 0x00000020) == 0x00000020)) {\n                com.google.protobuf.GeneratedMessageV3.writeString(output, 6, name_);\n            }\n            if (((bitField0_ & 0x00000040) == 0x00000040)) {\n                output.writeBytes(7, msg_);\n            }\n            for (int i = 0; i < phone_.size(); i++) {\n                output.writeMessage(8, phone_.get(i));\n            }\n            com.google.protobuf.GeneratedMessageV3.serializeStringMapTo(\n                    output, internalGetDoubleMap(), DoubleMapDefaultEntryHolder.defaultEntry, 9);\n            for (int i = 0; i < bytesList_.size(); i++) {\n                output.writeBytes(10, bytesList_.get(i));\n            }\n            com.google.protobuf.GeneratedMessageV3.serializeStringMapTo(\n                    output, internalGetBytesMap(), BytesMapDefaultEntryHolder.defaultEntry, 11);\n            unknownFields.writeTo(output);\n        }\n\n        public int getSerializedSize() {\n            int size = memoizedSize;\n            if (size != -1) return size;\n\n            size = 0;\n            if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                size += com.google.protobuf.CodedOutputStream.computeDoubleSize(1, money_);\n            }\n            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                size += com.google.protobuf.CodedOutputStream.computeFloatSize(2, cash_);\n            }\n            if (((bitField0_ & 0x00000004) == 0x00000004)) {\n                size += com.google.protobuf.CodedOutputStream.computeInt32Size(3, age_);\n            }\n            if (((bitField0_ & 0x00000008) == 0x00000008)) {\n                size += com.google.protobuf.CodedOutputStream.computeInt64Size(4, num_);\n            }\n            if (((bitField0_ & 0x00000010) == 0x00000010)) {\n                size += com.google.protobuf.CodedOutputStream.computeBoolSize(5, sex_);\n            }\n            if (((bitField0_ & 0x00000020) == 0x00000020)) {\n                size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, name_);\n            }\n            if (((bitField0_ & 0x00000040) == 0x00000040)) {\n                size += com.google.protobuf.CodedOutputStream.computeBytesSize(7, msg_);\n            }\n            for (int i = 0; i < phone_.size(); i++) {\n                size += com.google.protobuf.CodedOutputStream.computeMessageSize(8, phone_.get(i));\n            }\n            for (java.util.Map.Entry<\n                            java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                    entry : internalGetDoubleMap().getMap().entrySet()) {\n                com.google.protobuf.MapEntry<String, PhoneNumber> doubleMap__ = DoubleMapDefaultEntryHolder.defaultEntry\n                        .newBuilderForType()\n                        .setKey(entry.getKey())\n                        .setValue(entry.getValue())\n                        .build();\n                size += com.google.protobuf.CodedOutputStream.computeMessageSize(9, doubleMap__);\n            }\n            {\n                int dataSize = 0;\n                for (int i = 0; i < bytesList_.size(); i++) {\n                    dataSize += com.google.protobuf.CodedOutputStream.computeBytesSizeNoTag(bytesList_.get(i));\n                }\n                size += dataSize;\n                size += 1 * getBytesListList().size();\n            }\n            for (java.util.Map.Entry<java.lang.String, com.google.protobuf.ByteString> entry :\n                    internalGetBytesMap().getMap().entrySet()) {\n                com.google.protobuf.MapEntry<String, com.google.protobuf.ByteString> bytesMap__ =\n                        BytesMapDefaultEntryHolder.defaultEntry\n                                .newBuilderForType()\n                                .setKey(entry.getKey())\n                                .setValue(entry.getValue())\n                                .build();\n                size += com.google.protobuf.CodedOutputStream.computeMessageSize(11, bytesMap__);\n            }\n            size += unknownFields.getSerializedSize();\n            memoizedSize = size;\n            return size;\n        }\n\n        @java.lang.Override\n        public boolean equals(final java.lang.Object obj) {\n            if (obj == this) {\n                return true;\n            }\n            if (!(obj instanceof org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType)) {\n                return super.equals(obj);\n            }\n            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType other =\n                    (org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType) obj;\n\n            boolean result = true;\n            result = result && (hasMoney() == other.hasMoney());\n            if (hasMoney()) {\n                result = result\n                        && (java.lang.Double.doubleToLongBits(getMoney())\n                                == java.lang.Double.doubleToLongBits(other.getMoney()));\n            }\n            result = result && (hasCash() == other.hasCash());\n            if (hasCash()) {\n                result = result\n                        && (java.lang.Float.floatToIntBits(getCash())\n                                == java.lang.Float.floatToIntBits(other.getCash()));\n            }\n            result = result && (hasAge() == other.hasAge());\n            if (hasAge()) {\n                result = result && (getAge() == other.getAge());\n            }\n            result = result && (hasNum() == other.hasNum());\n            if (hasNum()) {\n                result = result && (getNum() == other.getNum());\n            }\n            result = result && (hasSex() == other.hasSex());\n            if (hasSex()) {\n                result = result && (getSex() == other.getSex());\n            }\n            result = result && (hasName() == other.hasName());\n            if (hasName()) {\n                result = result && getName().equals(other.getName());\n            }\n            result = result && (hasMsg() == other.hasMsg());\n            if (hasMsg()) {\n                result = result && getMsg().equals(other.getMsg());\n            }\n            result = result && getPhoneList().equals(other.getPhoneList());\n            result = result && internalGetDoubleMap().equals(other.internalGetDoubleMap());\n            result = result && getBytesListList().equals(other.getBytesListList());\n            result = result && internalGetBytesMap().equals(other.internalGetBytesMap());\n            result = result && unknownFields.equals(other.unknownFields);\n            return result;\n        }\n\n        @java.lang.Override\n        public int hashCode() {\n            if (memoizedHashCode != 0) {\n                return memoizedHashCode;\n            }\n            int hash = 41;\n            hash = (19 * hash) + getDescriptor().hashCode();\n            if (hasMoney()) {\n                hash = (37 * hash) + MONEY_FIELD_NUMBER;\n                hash = (53 * hash)\n                        + com.google.protobuf.Internal.hashLong(java.lang.Double.doubleToLongBits(getMoney()));\n            }\n            if (hasCash()) {\n                hash = (37 * hash) + CASH_FIELD_NUMBER;\n                hash = (53 * hash) + java.lang.Float.floatToIntBits(getCash());\n            }\n            if (hasAge()) {\n                hash = (37 * hash) + AGE_FIELD_NUMBER;\n                hash = (53 * hash) + getAge();\n            }\n            if (hasNum()) {\n                hash = (37 * hash) + NUM_FIELD_NUMBER;\n                hash = (53 * hash) + com.google.protobuf.Internal.hashLong(getNum());\n            }\n            if (hasSex()) {\n                hash = (37 * hash) + SEX_FIELD_NUMBER;\n                hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(getSex());\n            }\n            if (hasName()) {\n                hash = (37 * hash) + NAME_FIELD_NUMBER;\n                hash = (53 * hash) + getName().hashCode();\n            }\n            if (hasMsg()) {\n                hash = (37 * hash) + MSG_FIELD_NUMBER;\n                hash = (53 * hash) + getMsg().hashCode();\n            }\n            if (getPhoneCount() > 0) {\n                hash = (37 * hash) + PHONE_FIELD_NUMBER;\n                hash = (53 * hash) + getPhoneList().hashCode();\n            }\n            if (!internalGetDoubleMap().getMap().isEmpty()) {\n                hash = (37 * hash) + DOUBLEMAP_FIELD_NUMBER;\n                hash = (53 * hash) + internalGetDoubleMap().hashCode();\n            }\n            if (getBytesListCount() > 0) {\n                hash = (37 * hash) + BYTESLIST_FIELD_NUMBER;\n                hash = (53 * hash) + getBytesListList().hashCode();\n            }\n            if (!internalGetBytesMap().getMap().isEmpty()) {\n                hash = (37 * hash) + BYTESMAP_FIELD_NUMBER;\n                hash = (53 * hash) + internalGetBytesMap().hashCode();\n            }\n            hash = (29 * hash) + unknownFields.hashCode();\n            memoizedHashCode = hash;\n            return hash;\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseFrom(\n                java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseFrom(\n                java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseFrom(\n                com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseFrom(\n                com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseFrom(byte[] data)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseFrom(\n                byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseFrom(\n                java.io.InputStream input) throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseFrom(\n                java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseDelimitedFrom(\n                java.io.InputStream input) throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseDelimitedFrom(\n                java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(\n                    PARSER, input, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseFrom(\n                com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parseFrom(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n        }\n\n        public Builder newBuilderForType() {\n            return newBuilder();\n        }\n\n        public static Builder newBuilder() {\n            return DEFAULT_INSTANCE.toBuilder();\n        }\n\n        public static Builder newBuilder(\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType prototype) {\n            return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n        }\n\n        public Builder toBuilder() {\n            return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this);\n        }\n\n        @java.lang.Override\n        protected Builder newBuilderForType(BuilderParent parent) {\n            Builder builder = new Builder(parent);\n            return builder;\n        }\n        /**\n         * Protobuf type {@code org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType}\n         */\n        public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder<Builder>\n                implements\n                // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType)\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestTypeOrBuilder {\n            public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                        .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_descriptor;\n            }\n\n            @SuppressWarnings({\"rawtypes\"})\n            protected com.google.protobuf.MapField internalGetMapField(int number) {\n                switch (number) {\n                    case 9:\n                        return internalGetDoubleMap();\n                    case 11:\n                        return internalGetBytesMap();\n                    default:\n                        throw new RuntimeException(\"Invalid map field number: \" + number);\n                }\n            }\n\n            @SuppressWarnings({\"rawtypes\"})\n            protected com.google.protobuf.MapField internalGetMutableMapField(int number) {\n                switch (number) {\n                    case 9:\n                        return internalGetMutableDoubleMap();\n                    case 11:\n                        return internalGetMutableBytesMap();\n                    default:\n                        throw new RuntimeException(\"Invalid map field number: \" + number);\n                }\n            }\n\n            protected FieldAccessorTable internalGetFieldAccessorTable() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                        .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_fieldAccessorTable\n                        .ensureFieldAccessorsInitialized(\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.class,\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.Builder\n                                        .class);\n            }\n\n            // Construct using org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.newBuilder()\n            private Builder() {\n                maybeForceBuilderInitialization();\n            }\n\n            private Builder(BuilderParent parent) {\n                super(parent);\n                maybeForceBuilderInitialization();\n            }\n\n            private void maybeForceBuilderInitialization() {\n                if (com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders) {\n                    getPhoneFieldBuilder();\n                }\n            }\n\n            public Builder clear() {\n                super.clear();\n                money_ = 0D;\n                bitField0_ = (bitField0_ & ~0x00000001);\n                cash_ = 0F;\n                bitField0_ = (bitField0_ & ~0x00000002);\n                age_ = 0;\n                bitField0_ = (bitField0_ & ~0x00000004);\n                num_ = 0L;\n                bitField0_ = (bitField0_ & ~0x00000008);\n                sex_ = false;\n                bitField0_ = (bitField0_ & ~0x00000010);\n                name_ = \"\";\n                bitField0_ = (bitField0_ & ~0x00000020);\n                msg_ = com.google.protobuf.ByteString.EMPTY;\n                bitField0_ = (bitField0_ & ~0x00000040);\n                if (phoneBuilder_ == null) {\n                    phone_ = java.util.Collections.emptyList();\n                    bitField0_ = (bitField0_ & ~0x00000080);\n                } else {\n                    phoneBuilder_.clear();\n                }\n                internalGetMutableDoubleMap().clear();\n                bytesList_ = java.util.Collections.emptyList();\n                bitField0_ = (bitField0_ & ~0x00000200);\n                internalGetMutableBytesMap().clear();\n                return this;\n            }\n\n            public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                        .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_descriptor;\n            }\n\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType\n                    getDefaultInstanceForType() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.getDefaultInstance();\n            }\n\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType build() {\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType result = buildPartial();\n                if (!result.isInitialized()) {\n                    throw newUninitializedMessageException(result);\n                }\n                return result;\n            }\n\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType buildPartial() {\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType result =\n                        new org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType(this);\n                int from_bitField0_ = bitField0_;\n                int to_bitField0_ = 0;\n                if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n                    to_bitField0_ |= 0x00000001;\n                }\n                result.money_ = money_;\n                if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n                    to_bitField0_ |= 0x00000002;\n                }\n                result.cash_ = cash_;\n                if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n                    to_bitField0_ |= 0x00000004;\n                }\n                result.age_ = age_;\n                if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n                    to_bitField0_ |= 0x00000008;\n                }\n                result.num_ = num_;\n                if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n                    to_bitField0_ |= 0x00000010;\n                }\n                result.sex_ = sex_;\n                if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n                    to_bitField0_ |= 0x00000020;\n                }\n                result.name_ = name_;\n                if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n                    to_bitField0_ |= 0x00000040;\n                }\n                result.msg_ = msg_;\n                if (phoneBuilder_ == null) {\n                    if (((bitField0_ & 0x00000080) == 0x00000080)) {\n                        phone_ = java.util.Collections.unmodifiableList(phone_);\n                        bitField0_ = (bitField0_ & ~0x00000080);\n                    }\n                    result.phone_ = phone_;\n                } else {\n                    result.phone_ = phoneBuilder_.build();\n                }\n                result.doubleMap_ = internalGetDoubleMap();\n                result.doubleMap_.makeImmutable();\n                if (((bitField0_ & 0x00000200) == 0x00000200)) {\n                    bytesList_ = java.util.Collections.unmodifiableList(bytesList_);\n                    bitField0_ = (bitField0_ & ~0x00000200);\n                }\n                result.bytesList_ = bytesList_;\n                result.bytesMap_ = internalGetBytesMap();\n                result.bytesMap_.makeImmutable();\n                result.bitField0_ = to_bitField0_;\n                onBuilt();\n                return result;\n            }\n\n            public Builder clone() {\n                return (Builder) super.clone();\n            }\n\n            public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, java.lang.Object value) {\n                return (Builder) super.setField(field, value);\n            }\n\n            public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) {\n                return (Builder) super.clearField(field);\n            }\n\n            public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n                return (Builder) super.clearOneof(oneof);\n            }\n\n            public Builder setRepeatedField(\n                    com.google.protobuf.Descriptors.FieldDescriptor field, int index, java.lang.Object value) {\n                return (Builder) super.setRepeatedField(field, index, value);\n            }\n\n            public Builder addRepeatedField(\n                    com.google.protobuf.Descriptors.FieldDescriptor field, java.lang.Object value) {\n                return (Builder) super.addRepeatedField(field, value);\n            }\n\n            public Builder mergeFrom(com.google.protobuf.Message other) {\n                if (other instanceof org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType) {\n                    return mergeFrom(\n                            (org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType) other);\n                } else {\n                    super.mergeFrom(other);\n                    return this;\n                }\n            }\n\n            public Builder mergeFrom(org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType other) {\n                if (other\n                        == org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType\n                                .getDefaultInstance()) return this;\n                if (other.hasMoney()) {\n                    setMoney(other.getMoney());\n                }\n                if (other.hasCash()) {\n                    setCash(other.getCash());\n                }\n                if (other.hasAge()) {\n                    setAge(other.getAge());\n                }\n                if (other.hasNum()) {\n                    setNum(other.getNum());\n                }\n                if (other.hasSex()) {\n                    setSex(other.getSex());\n                }\n                if (other.hasName()) {\n                    bitField0_ |= 0x00000020;\n                    name_ = other.name_;\n                    onChanged();\n                }\n                if (other.hasMsg()) {\n                    setMsg(other.getMsg());\n                }\n                if (phoneBuilder_ == null) {\n                    if (!other.phone_.isEmpty()) {\n                        if (phone_.isEmpty()) {\n                            phone_ = other.phone_;\n                            bitField0_ = (bitField0_ & ~0x00000080);\n                        } else {\n                            ensurePhoneIsMutable();\n                            phone_.addAll(other.phone_);\n                        }\n                        onChanged();\n                    }\n                } else {\n                    if (!other.phone_.isEmpty()) {\n                        if (phoneBuilder_.isEmpty()) {\n                            phoneBuilder_.dispose();\n                            phoneBuilder_ = null;\n                            phone_ = other.phone_;\n                            bitField0_ = (bitField0_ & ~0x00000080);\n                            phoneBuilder_ = com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders\n                                    ? getPhoneFieldBuilder()\n                                    : null;\n                        } else {\n                            phoneBuilder_.addAllMessages(other.phone_);\n                        }\n                    }\n                }\n                internalGetMutableDoubleMap().mergeFrom(other.internalGetDoubleMap());\n                if (!other.bytesList_.isEmpty()) {\n                    if (bytesList_.isEmpty()) {\n                        bytesList_ = other.bytesList_;\n                        bitField0_ = (bitField0_ & ~0x00000200);\n                    } else {\n                        ensureBytesListIsMutable();\n                        bytesList_.addAll(other.bytesList_);\n                    }\n                    onChanged();\n                }\n                internalGetMutableBytesMap().mergeFrom(other.internalGetBytesMap());\n                this.mergeUnknownFields(other.unknownFields);\n                onChanged();\n                return this;\n            }\n\n            public final boolean isInitialized() {\n                for (int i = 0; i < getPhoneCount(); i++) {\n                    if (!getPhone(i).isInitialized()) {\n                        return false;\n                    }\n                }\n                for (org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber item :\n                        getDoubleMapMap().values()) {\n                    if (!item.isInitialized()) {\n                        return false;\n                    }\n                }\n                return true;\n            }\n\n            public Builder mergeFrom(\n                    com.google.protobuf.CodedInputStream input,\n                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                    throws java.io.IOException {\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType parsedMessage = null;\n                try {\n                    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n                } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                    parsedMessage = (org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType)\n                            e.getUnfinishedMessage();\n                    throw e.unwrapIOException();\n                } finally {\n                    if (parsedMessage != null) {\n                        mergeFrom(parsedMessage);\n                    }\n                }\n                return this;\n            }\n\n            private int bitField0_;\n\n            private double money_;\n            /**\n             * <code>optional double money = 1;</code>\n             */\n            public boolean hasMoney() {\n                return ((bitField0_ & 0x00000001) == 0x00000001);\n            }\n            /**\n             * <code>optional double money = 1;</code>\n             */\n            public double getMoney() {\n                return money_;\n            }\n            /**\n             * <code>optional double money = 1;</code>\n             */\n            public Builder setMoney(double value) {\n                bitField0_ |= 0x00000001;\n                money_ = value;\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional double money = 1;</code>\n             */\n            public Builder clearMoney() {\n                bitField0_ = (bitField0_ & ~0x00000001);\n                money_ = 0D;\n                onChanged();\n                return this;\n            }\n\n            private float cash_;\n            /**\n             * <code>optional float cash = 2;</code>\n             */\n            public boolean hasCash() {\n                return ((bitField0_ & 0x00000002) == 0x00000002);\n            }\n            /**\n             * <code>optional float cash = 2;</code>\n             */\n            public float getCash() {\n                return cash_;\n            }\n            /**\n             * <code>optional float cash = 2;</code>\n             */\n            public Builder setCash(float value) {\n                bitField0_ |= 0x00000002;\n                cash_ = value;\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional float cash = 2;</code>\n             */\n            public Builder clearCash() {\n                bitField0_ = (bitField0_ & ~0x00000002);\n                cash_ = 0F;\n                onChanged();\n                return this;\n            }\n\n            private int age_;\n            /**\n             * <code>optional int32 age = 3;</code>\n             */\n            public boolean hasAge() {\n                return ((bitField0_ & 0x00000004) == 0x00000004);\n            }\n            /**\n             * <code>optional int32 age = 3;</code>\n             */\n            public int getAge() {\n                return age_;\n            }\n            /**\n             * <code>optional int32 age = 3;</code>\n             */\n            public Builder setAge(int value) {\n                bitField0_ |= 0x00000004;\n                age_ = value;\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional int32 age = 3;</code>\n             */\n            public Builder clearAge() {\n                bitField0_ = (bitField0_ & ~0x00000004);\n                age_ = 0;\n                onChanged();\n                return this;\n            }\n\n            private long num_;\n            /**\n             * <code>optional int64 num = 4;</code>\n             */\n            public boolean hasNum() {\n                return ((bitField0_ & 0x00000008) == 0x00000008);\n            }\n            /**\n             * <code>optional int64 num = 4;</code>\n             */\n            public long getNum() {\n                return num_;\n            }\n            /**\n             * <code>optional int64 num = 4;</code>\n             */\n            public Builder setNum(long value) {\n                bitField0_ |= 0x00000008;\n                num_ = value;\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional int64 num = 4;</code>\n             */\n            public Builder clearNum() {\n                bitField0_ = (bitField0_ & ~0x00000008);\n                num_ = 0L;\n                onChanged();\n                return this;\n            }\n\n            private boolean sex_;\n            /**\n             * <code>optional bool sex = 5;</code>\n             */\n            public boolean hasSex() {\n                return ((bitField0_ & 0x00000010) == 0x00000010);\n            }\n            /**\n             * <code>optional bool sex = 5;</code>\n             */\n            public boolean getSex() {\n                return sex_;\n            }\n            /**\n             * <code>optional bool sex = 5;</code>\n             */\n            public Builder setSex(boolean value) {\n                bitField0_ |= 0x00000010;\n                sex_ = value;\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional bool sex = 5;</code>\n             */\n            public Builder clearSex() {\n                bitField0_ = (bitField0_ & ~0x00000010);\n                sex_ = false;\n                onChanged();\n                return this;\n            }\n\n            private java.lang.Object name_ = \"\";\n            /**\n             * <code>optional string name = 6;</code>\n             */\n            public boolean hasName() {\n                return ((bitField0_ & 0x00000020) == 0x00000020);\n            }\n            /**\n             * <code>optional string name = 6;</code>\n             */\n            public java.lang.String getName() {\n                java.lang.Object ref = name_;\n                if (!(ref instanceof java.lang.String)) {\n                    com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                    java.lang.String s = bs.toStringUtf8();\n                    if (bs.isValidUtf8()) {\n                        name_ = s;\n                    }\n                    return s;\n                } else {\n                    return (java.lang.String) ref;\n                }\n            }\n            /**\n             * <code>optional string name = 6;</code>\n             */\n            public com.google.protobuf.ByteString getNameBytes() {\n                java.lang.Object ref = name_;\n                if (ref instanceof String) {\n                    com.google.protobuf.ByteString b =\n                            com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);\n                    name_ = b;\n                    return b;\n                } else {\n                    return (com.google.protobuf.ByteString) ref;\n                }\n            }\n            /**\n             * <code>optional string name = 6;</code>\n             */\n            public Builder setName(java.lang.String value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000020;\n                name_ = value;\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional string name = 6;</code>\n             */\n            public Builder clearName() {\n                bitField0_ = (bitField0_ & ~0x00000020);\n                name_ = getDefaultInstance().getName();\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional string name = 6;</code>\n             */\n            public Builder setNameBytes(com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000020;\n                name_ = value;\n                onChanged();\n                return this;\n            }\n\n            private com.google.protobuf.ByteString msg_ = com.google.protobuf.ByteString.EMPTY;\n            /**\n             * <code>optional bytes msg = 7;</code>\n             */\n            public boolean hasMsg() {\n                return ((bitField0_ & 0x00000040) == 0x00000040);\n            }\n            /**\n             * <code>optional bytes msg = 7;</code>\n             */\n            public com.google.protobuf.ByteString getMsg() {\n                return msg_;\n            }\n            /**\n             * <code>optional bytes msg = 7;</code>\n             */\n            public Builder setMsg(com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000040;\n                msg_ = value;\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional bytes msg = 7;</code>\n             */\n            public Builder clearMsg() {\n                bitField0_ = (bitField0_ & ~0x00000040);\n                msg_ = getDefaultInstance().getMsg();\n                onChanged();\n                return this;\n            }\n\n            private java.util.List<org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber> phone_ =\n                    java.util.Collections.emptyList();\n\n            private void ensurePhoneIsMutable() {\n                if (!((bitField0_ & 0x00000080) == 0x00000080)) {\n                    phone_ = new java.util.ArrayList<\n                            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>(phone_);\n                    bitField0_ |= 0x00000080;\n                }\n            }\n\n            private com.google.protobuf.RepeatedFieldBuilderV3<PhoneNumber, PhoneNumber.Builder, PhoneNumberOrBuilder>\n                    phoneBuilder_;\n\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public java.util.List<org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                    getPhoneList() {\n                if (phoneBuilder_ == null) {\n                    return java.util.Collections.unmodifiableList(phone_);\n                } else {\n                    return phoneBuilder_.getMessageList();\n                }\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public int getPhoneCount() {\n                if (phoneBuilder_ == null) {\n                    return phone_.size();\n                } else {\n                    return phoneBuilder_.getCount();\n                }\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getPhone(int index) {\n                if (phoneBuilder_ == null) {\n                    return phone_.get(index);\n                } else {\n                    return phoneBuilder_.getMessage(index);\n                }\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public Builder setPhone(\n                    int index, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber value) {\n                if (phoneBuilder_ == null) {\n                    if (value == null) {\n                        throw new NullPointerException();\n                    }\n                    ensurePhoneIsMutable();\n                    phone_.set(index, value);\n                    onChanged();\n                } else {\n                    phoneBuilder_.setMessage(index, value);\n                }\n                return this;\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public Builder setPhone(\n                    int index,\n                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.Builder builderForValue) {\n                if (phoneBuilder_ == null) {\n                    ensurePhoneIsMutable();\n                    phone_.set(index, builderForValue.build());\n                    onChanged();\n                } else {\n                    phoneBuilder_.setMessage(index, builderForValue.build());\n                }\n                return this;\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public Builder addPhone(org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber value) {\n                if (phoneBuilder_ == null) {\n                    if (value == null) {\n                        throw new NullPointerException();\n                    }\n                    ensurePhoneIsMutable();\n                    phone_.add(value);\n                    onChanged();\n                } else {\n                    phoneBuilder_.addMessage(value);\n                }\n                return this;\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public Builder addPhone(\n                    int index, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber value) {\n                if (phoneBuilder_ == null) {\n                    if (value == null) {\n                        throw new NullPointerException();\n                    }\n                    ensurePhoneIsMutable();\n                    phone_.add(index, value);\n                    onChanged();\n                } else {\n                    phoneBuilder_.addMessage(index, value);\n                }\n                return this;\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public Builder addPhone(\n                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.Builder builderForValue) {\n                if (phoneBuilder_ == null) {\n                    ensurePhoneIsMutable();\n                    phone_.add(builderForValue.build());\n                    onChanged();\n                } else {\n                    phoneBuilder_.addMessage(builderForValue.build());\n                }\n                return this;\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public Builder addPhone(\n                    int index,\n                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.Builder builderForValue) {\n                if (phoneBuilder_ == null) {\n                    ensurePhoneIsMutable();\n                    phone_.add(index, builderForValue.build());\n                    onChanged();\n                } else {\n                    phoneBuilder_.addMessage(index, builderForValue.build());\n                }\n                return this;\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public Builder addAllPhone(\n                    java.lang.Iterable<\n                                    ? extends org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                            values) {\n                if (phoneBuilder_ == null) {\n                    ensurePhoneIsMutable();\n                    com.google.protobuf.AbstractMessageLite.Builder.addAll(values, phone_);\n                    onChanged();\n                } else {\n                    phoneBuilder_.addAllMessages(values);\n                }\n                return this;\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public Builder clearPhone() {\n                if (phoneBuilder_ == null) {\n                    phone_ = java.util.Collections.emptyList();\n                    bitField0_ = (bitField0_ & ~0x00000080);\n                    onChanged();\n                } else {\n                    phoneBuilder_.clear();\n                }\n                return this;\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public Builder removePhone(int index) {\n                if (phoneBuilder_ == null) {\n                    ensurePhoneIsMutable();\n                    phone_.remove(index);\n                    onChanged();\n                } else {\n                    phoneBuilder_.remove(index);\n                }\n                return this;\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.Builder getPhoneBuilder(\n                    int index) {\n                return getPhoneFieldBuilder().getBuilder(index);\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumberOrBuilder getPhoneOrBuilder(\n                    int index) {\n                if (phoneBuilder_ == null) {\n                    return phone_.get(index);\n                } else {\n                    return phoneBuilder_.getMessageOrBuilder(index);\n                }\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public java.util.List<\n                            ? extends org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumberOrBuilder>\n                    getPhoneOrBuilderList() {\n                if (phoneBuilder_ != null) {\n                    return phoneBuilder_.getMessageOrBuilderList();\n                } else {\n                    return java.util.Collections.unmodifiableList(phone_);\n                }\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.Builder addPhoneBuilder() {\n                return getPhoneFieldBuilder()\n                        .addBuilder(\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber\n                                        .getDefaultInstance());\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.Builder addPhoneBuilder(\n                    int index) {\n                return getPhoneFieldBuilder()\n                        .addBuilder(\n                                index,\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber\n                                        .getDefaultInstance());\n            }\n            /**\n             * <code>repeated .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber phone = 8;</code>\n             */\n            public java.util.List<org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.Builder>\n                    getPhoneBuilderList() {\n                return getPhoneFieldBuilder().getBuilderList();\n            }\n\n            private com.google.protobuf.RepeatedFieldBuilderV3<PhoneNumber, PhoneNumber.Builder, PhoneNumberOrBuilder>\n                    getPhoneFieldBuilder() {\n                if (phoneBuilder_ == null) {\n                    phoneBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3<\n                            PhoneNumber, PhoneNumber.Builder, PhoneNumberOrBuilder>(\n                            phone_, ((bitField0_ & 0x00000080) == 0x00000080), getParentForChildren(), isClean());\n                    phone_ = null;\n                }\n                return phoneBuilder_;\n            }\n\n            private com.google.protobuf.MapField<String, PhoneNumber> doubleMap_;\n\n            private com.google.protobuf.MapField<String, PhoneNumber> internalGetDoubleMap() {\n                if (doubleMap_ == null) {\n                    return com.google.protobuf.MapField.emptyMapField(DoubleMapDefaultEntryHolder.defaultEntry);\n                }\n                return doubleMap_;\n            }\n\n            private com.google.protobuf.MapField<String, PhoneNumber> internalGetMutableDoubleMap() {\n                onChanged();\n                ;\n                if (doubleMap_ == null) {\n                    doubleMap_ = com.google.protobuf.MapField.newMapField(DoubleMapDefaultEntryHolder.defaultEntry);\n                }\n                if (!doubleMap_.isMutable()) {\n                    doubleMap_ = doubleMap_.copy();\n                }\n                return doubleMap_;\n            }\n\n            public int getDoubleMapCount() {\n                return internalGetDoubleMap().getMap().size();\n            }\n            /**\n             * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n             */\n            public boolean containsDoubleMap(java.lang.String key) {\n                if (key == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                return internalGetDoubleMap().getMap().containsKey(key);\n            }\n            /**\n             * Use {@link #getDoubleMapMap()} instead.\n             */\n            @java.lang.Deprecated\n            public java.util.Map<\n                            java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                    getDoubleMap() {\n                return getDoubleMapMap();\n            }\n            /**\n             * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n             */\n            public java.util.Map<\n                            java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                    getDoubleMapMap() {\n                return internalGetDoubleMap().getMap();\n            }\n            /**\n             * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getDoubleMapOrDefault(\n                    java.lang.String key,\n                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber defaultValue) {\n                if (key == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                java.util.Map<\n                                java.lang.String,\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                        map = internalGetDoubleMap().getMap();\n                return map.containsKey(key) ? map.get(key) : defaultValue;\n            }\n            /**\n             * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getDoubleMapOrThrow(\n                    java.lang.String key) {\n                if (key == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                java.util.Map<\n                                java.lang.String,\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                        map = internalGetDoubleMap().getMap();\n                if (!map.containsKey(key)) {\n                    throw new java.lang.IllegalArgumentException();\n                }\n                return map.get(key);\n            }\n\n            public Builder clearDoubleMap() {\n                internalGetMutableDoubleMap().getMutableMap().clear();\n                return this;\n            }\n            /**\n             * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n             */\n            public Builder removeDoubleMap(java.lang.String key) {\n                if (key == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                internalGetMutableDoubleMap().getMutableMap().remove(key);\n                return this;\n            }\n            /**\n             * Use alternate mutation accessors instead.\n             */\n            @java.lang.Deprecated\n            public java.util.Map<\n                            java.lang.String, org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                    getMutableDoubleMap() {\n                return internalGetMutableDoubleMap().getMutableMap();\n            }\n            /**\n             * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n             */\n            public Builder putDoubleMap(\n                    java.lang.String key,\n                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber value) {\n                if (key == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                if (value == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                internalGetMutableDoubleMap().getMutableMap().put(key, value);\n                return this;\n            }\n            /**\n             * <code>map&lt;string, .org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber&gt; doubleMap = 9;</code>\n             */\n            public Builder putAllDoubleMap(\n                    java.util.Map<\n                                    java.lang.String,\n                                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber>\n                            values) {\n                internalGetMutableDoubleMap().getMutableMap().putAll(values);\n                return this;\n            }\n\n            private java.util.List<com.google.protobuf.ByteString> bytesList_ = java.util.Collections.emptyList();\n\n            private void ensureBytesListIsMutable() {\n                if (!((bitField0_ & 0x00000200) == 0x00000200)) {\n                    bytesList_ = new java.util.ArrayList<com.google.protobuf.ByteString>(bytesList_);\n                    bitField0_ |= 0x00000200;\n                }\n            }\n            /**\n             * <code>repeated bytes bytesList = 10;</code>\n             */\n            public java.util.List<com.google.protobuf.ByteString> getBytesListList() {\n                return java.util.Collections.unmodifiableList(bytesList_);\n            }\n            /**\n             * <code>repeated bytes bytesList = 10;</code>\n             */\n            public int getBytesListCount() {\n                return bytesList_.size();\n            }\n            /**\n             * <code>repeated bytes bytesList = 10;</code>\n             */\n            public com.google.protobuf.ByteString getBytesList(int index) {\n                return bytesList_.get(index);\n            }\n            /**\n             * <code>repeated bytes bytesList = 10;</code>\n             */\n            public Builder setBytesList(int index, com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                ensureBytesListIsMutable();\n                bytesList_.set(index, value);\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>repeated bytes bytesList = 10;</code>\n             */\n            public Builder addBytesList(com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                ensureBytesListIsMutable();\n                bytesList_.add(value);\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>repeated bytes bytesList = 10;</code>\n             */\n            public Builder addAllBytesList(java.lang.Iterable<? extends com.google.protobuf.ByteString> values) {\n                ensureBytesListIsMutable();\n                com.google.protobuf.AbstractMessageLite.Builder.addAll(values, bytesList_);\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>repeated bytes bytesList = 10;</code>\n             */\n            public Builder clearBytesList() {\n                bytesList_ = java.util.Collections.emptyList();\n                bitField0_ = (bitField0_ & ~0x00000200);\n                onChanged();\n                return this;\n            }\n\n            private com.google.protobuf.MapField<String, com.google.protobuf.ByteString> bytesMap_;\n\n            private com.google.protobuf.MapField<String, com.google.protobuf.ByteString> internalGetBytesMap() {\n                if (bytesMap_ == null) {\n                    return com.google.protobuf.MapField.emptyMapField(BytesMapDefaultEntryHolder.defaultEntry);\n                }\n                return bytesMap_;\n            }\n\n            private com.google.protobuf.MapField<String, com.google.protobuf.ByteString> internalGetMutableBytesMap() {\n                onChanged();\n                ;\n                if (bytesMap_ == null) {\n                    bytesMap_ = com.google.protobuf.MapField.newMapField(BytesMapDefaultEntryHolder.defaultEntry);\n                }\n                if (!bytesMap_.isMutable()) {\n                    bytesMap_ = bytesMap_.copy();\n                }\n                return bytesMap_;\n            }\n\n            public int getBytesMapCount() {\n                return internalGetBytesMap().getMap().size();\n            }\n            /**\n             * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n             */\n            public boolean containsBytesMap(java.lang.String key) {\n                if (key == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                return internalGetBytesMap().getMap().containsKey(key);\n            }\n            /**\n             * Use {@link #getBytesMapMap()} instead.\n             */\n            @java.lang.Deprecated\n            public java.util.Map<java.lang.String, com.google.protobuf.ByteString> getBytesMap() {\n                return getBytesMapMap();\n            }\n            /**\n             * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n             */\n            public java.util.Map<java.lang.String, com.google.protobuf.ByteString> getBytesMapMap() {\n                return internalGetBytesMap().getMap();\n            }\n            /**\n             * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n             */\n            public com.google.protobuf.ByteString getBytesMapOrDefault(\n                    java.lang.String key, com.google.protobuf.ByteString defaultValue) {\n                if (key == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                java.util.Map<java.lang.String, com.google.protobuf.ByteString> map =\n                        internalGetBytesMap().getMap();\n                return map.containsKey(key) ? map.get(key) : defaultValue;\n            }\n            /**\n             * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n             */\n            public com.google.protobuf.ByteString getBytesMapOrThrow(java.lang.String key) {\n                if (key == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                java.util.Map<java.lang.String, com.google.protobuf.ByteString> map =\n                        internalGetBytesMap().getMap();\n                if (!map.containsKey(key)) {\n                    throw new java.lang.IllegalArgumentException();\n                }\n                return map.get(key);\n            }\n\n            public Builder clearBytesMap() {\n                internalGetMutableBytesMap().getMutableMap().clear();\n                return this;\n            }\n            /**\n             * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n             */\n            public Builder removeBytesMap(java.lang.String key) {\n                if (key == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                internalGetMutableBytesMap().getMutableMap().remove(key);\n                return this;\n            }\n            /**\n             * Use alternate mutation accessors instead.\n             */\n            @java.lang.Deprecated\n            public java.util.Map<java.lang.String, com.google.protobuf.ByteString> getMutableBytesMap() {\n                return internalGetMutableBytesMap().getMutableMap();\n            }\n            /**\n             * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n             */\n            public Builder putBytesMap(java.lang.String key, com.google.protobuf.ByteString value) {\n                if (key == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                if (value == null) {\n                    throw new java.lang.NullPointerException();\n                }\n                internalGetMutableBytesMap().getMutableMap().put(key, value);\n                return this;\n            }\n            /**\n             * <code>map&lt;string, bytes&gt; bytesMap = 11;</code>\n             */\n            public Builder putAllBytesMap(java.util.Map<java.lang.String, com.google.protobuf.ByteString> values) {\n                internalGetMutableBytesMap().getMutableMap().putAll(values);\n                return this;\n            }\n\n            public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n                return super.setUnknownFields(unknownFields);\n            }\n\n            public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n                return super.mergeUnknownFields(unknownFields);\n            }\n\n            // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType)\n        }\n\n        // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType)\n        private static final org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType\n                DEFAULT_INSTANCE;\n\n        static {\n            DEFAULT_INSTANCE = new org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType();\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType getDefaultInstance() {\n            return DEFAULT_INSTANCE;\n        }\n\n        @java.lang.Deprecated\n        public static final com.google.protobuf.Parser<PBRequestType> PARSER =\n                new com.google.protobuf.AbstractParser<PBRequestType>() {\n                    public PBRequestType parsePartialFrom(\n                            com.google.protobuf.CodedInputStream input,\n                            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                            throws com.google.protobuf.InvalidProtocolBufferException {\n                        return new PBRequestType(input, extensionRegistry);\n                    }\n                };\n\n        public static com.google.protobuf.Parser<PBRequestType> parser() {\n            return PARSER;\n        }\n\n        @java.lang.Override\n        public com.google.protobuf.Parser<PBRequestType> getParserForType() {\n            return PARSER;\n        }\n\n        public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType getDefaultInstanceForType() {\n            return DEFAULT_INSTANCE;\n        }\n    }\n\n    public interface PBResponseTypeOrBuilder\n            extends\n            // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.definition.protobuf.model.PBResponseType)\n            com.google.protobuf.MessageOrBuilder {\n\n        /**\n         * <code>optional string msg = 1;</code>\n         */\n        boolean hasMsg();\n        /**\n         * <code>optional string msg = 1;</code>\n         */\n        java.lang.String getMsg();\n        /**\n         * <code>optional string msg = 1;</code>\n         */\n        com.google.protobuf.ByteString getMsgBytes();\n\n        /**\n         * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n         */\n        boolean hasCDubboPBRequestType();\n        /**\n         * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n         */\n        org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType getCDubboPBRequestType();\n        /**\n         * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n         */\n        org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestTypeOrBuilder\n                getCDubboPBRequestTypeOrBuilder();\n    }\n    /**\n     * Protobuf type {@code org.apache.dubbo.metadata.definition.protobuf.model.PBResponseType}\n     */\n    public static final class PBResponseType extends com.google.protobuf.GeneratedMessageV3\n            implements\n            // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.definition.protobuf.model.PBResponseType)\n            PBResponseTypeOrBuilder {\n        private static final long serialVersionUID = 0L;\n        // Use PBResponseType.newBuilder() to construct.\n        private PBResponseType(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n            super(builder);\n        }\n\n        private PBResponseType() {\n            msg_ = \"\";\n        }\n\n        @java.lang.Override\n        public final com.google.protobuf.UnknownFieldSet getUnknownFields() {\n            return this.unknownFields;\n        }\n\n        private PBResponseType(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            this();\n            int mutable_bitField0_ = 0;\n            com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n                    com.google.protobuf.UnknownFieldSet.newBuilder();\n            try {\n                boolean done = false;\n                while (!done) {\n                    int tag = input.readTag();\n                    switch (tag) {\n                        case 0:\n                            done = true;\n                            break;\n                        default: {\n                            if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) {\n                                done = true;\n                            }\n                            break;\n                        }\n                        case 10: {\n                            com.google.protobuf.ByteString bs = input.readBytes();\n                            bitField0_ |= 0x00000001;\n                            msg_ = bs;\n                            break;\n                        }\n                        case 26: {\n                            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.Builder\n                                    subBuilder = null;\n                            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                                subBuilder = cDubboPBRequestType_.toBuilder();\n                            }\n                            cDubboPBRequestType_ = input.readMessage(\n                                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.PARSER,\n                                    extensionRegistry);\n                            if (subBuilder != null) {\n                                subBuilder.mergeFrom(cDubboPBRequestType_);\n                                cDubboPBRequestType_ = subBuilder.buildPartial();\n                            }\n                            bitField0_ |= 0x00000002;\n                            break;\n                        }\n                    }\n                }\n            } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                throw e.setUnfinishedMessage(this);\n            } catch (java.io.IOException e) {\n                throw new com.google.protobuf.InvalidProtocolBufferException(e).setUnfinishedMessage(this);\n            } finally {\n                this.unknownFields = unknownFields.build();\n                makeExtensionsImmutable();\n            }\n        }\n\n        public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n            return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                    .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBResponseType_descriptor;\n        }\n\n        protected FieldAccessorTable internalGetFieldAccessorTable() {\n            return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                    .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBResponseType_fieldAccessorTable\n                    .ensureFieldAccessorsInitialized(\n                            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType.class,\n                            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType.Builder.class);\n        }\n\n        private int bitField0_;\n        public static final int MSG_FIELD_NUMBER = 1;\n        private volatile java.lang.Object msg_;\n        /**\n         * <code>optional string msg = 1;</code>\n         */\n        public boolean hasMsg() {\n            return ((bitField0_ & 0x00000001) == 0x00000001);\n        }\n        /**\n         * <code>optional string msg = 1;</code>\n         */\n        public java.lang.String getMsg() {\n            java.lang.Object ref = msg_;\n            if (ref instanceof java.lang.String) {\n                return (java.lang.String) ref;\n            } else {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                java.lang.String s = bs.toStringUtf8();\n                if (bs.isValidUtf8()) {\n                    msg_ = s;\n                }\n                return s;\n            }\n        }\n        /**\n         * <code>optional string msg = 1;</code>\n         */\n        public com.google.protobuf.ByteString getMsgBytes() {\n            java.lang.Object ref = msg_;\n            if (ref instanceof java.lang.String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);\n                msg_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        public static final int CDUBBOPBREQUESTTYPE_FIELD_NUMBER = 3;\n        private org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType cDubboPBRequestType_;\n        /**\n         * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n         */\n        public boolean hasCDubboPBRequestType() {\n            return ((bitField0_ & 0x00000002) == 0x00000002);\n        }\n        /**\n         * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n         */\n        public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType getCDubboPBRequestType() {\n            return cDubboPBRequestType_ == null\n                    ? org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.getDefaultInstance()\n                    : cDubboPBRequestType_;\n        }\n        /**\n         * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n         */\n        public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestTypeOrBuilder\n                getCDubboPBRequestTypeOrBuilder() {\n            return cDubboPBRequestType_ == null\n                    ? org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.getDefaultInstance()\n                    : cDubboPBRequestType_;\n        }\n\n        private byte memoizedIsInitialized = -1;\n\n        public final boolean isInitialized() {\n            byte isInitialized = memoizedIsInitialized;\n            if (isInitialized == 1) return true;\n            if (isInitialized == 0) return false;\n\n            if (hasCDubboPBRequestType()) {\n                if (!getCDubboPBRequestType().isInitialized()) {\n                    memoizedIsInitialized = 0;\n                    return false;\n                }\n            }\n            memoizedIsInitialized = 1;\n            return true;\n        }\n\n        public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n            if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                com.google.protobuf.GeneratedMessageV3.writeString(output, 1, msg_);\n            }\n            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                output.writeMessage(3, getCDubboPBRequestType());\n            }\n            unknownFields.writeTo(output);\n        }\n\n        public int getSerializedSize() {\n            int size = memoizedSize;\n            if (size != -1) return size;\n\n            size = 0;\n            if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, msg_);\n            }\n            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                size += com.google.protobuf.CodedOutputStream.computeMessageSize(3, getCDubboPBRequestType());\n            }\n            size += unknownFields.getSerializedSize();\n            memoizedSize = size;\n            return size;\n        }\n\n        @java.lang.Override\n        public boolean equals(final java.lang.Object obj) {\n            if (obj == this) {\n                return true;\n            }\n            if (!(obj instanceof org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType)) {\n                return super.equals(obj);\n            }\n            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType other =\n                    (org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType) obj;\n\n            boolean result = true;\n            result = result && (hasMsg() == other.hasMsg());\n            if (hasMsg()) {\n                result = result && getMsg().equals(other.getMsg());\n            }\n            result = result && (hasCDubboPBRequestType() == other.hasCDubboPBRequestType());\n            if (hasCDubboPBRequestType()) {\n                result = result && getCDubboPBRequestType().equals(other.getCDubboPBRequestType());\n            }\n            result = result && unknownFields.equals(other.unknownFields);\n            return result;\n        }\n\n        @java.lang.Override\n        public int hashCode() {\n            if (memoizedHashCode != 0) {\n                return memoizedHashCode;\n            }\n            int hash = 41;\n            hash = (19 * hash) + getDescriptor().hashCode();\n            if (hasMsg()) {\n                hash = (37 * hash) + MSG_FIELD_NUMBER;\n                hash = (53 * hash) + getMsg().hashCode();\n            }\n            if (hasCDubboPBRequestType()) {\n                hash = (37 * hash) + CDUBBOPBREQUESTTYPE_FIELD_NUMBER;\n                hash = (53 * hash) + getCDubboPBRequestType().hashCode();\n            }\n            hash = (29 * hash) + unknownFields.hashCode();\n            memoizedHashCode = hash;\n            return hash;\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseFrom(\n                java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseFrom(\n                java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseFrom(\n                com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseFrom(\n                com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseFrom(byte[] data)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseFrom(\n                byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseFrom(\n                java.io.InputStream input) throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseFrom(\n                java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseDelimitedFrom(\n                java.io.InputStream input) throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseDelimitedFrom(\n                java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(\n                    PARSER, input, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseFrom(\n                com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parseFrom(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n        }\n\n        public Builder newBuilderForType() {\n            return newBuilder();\n        }\n\n        public static Builder newBuilder() {\n            return DEFAULT_INSTANCE.toBuilder();\n        }\n\n        public static Builder newBuilder(\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType prototype) {\n            return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n        }\n\n        public Builder toBuilder() {\n            return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this);\n        }\n\n        @java.lang.Override\n        protected Builder newBuilderForType(BuilderParent parent) {\n            Builder builder = new Builder(parent);\n            return builder;\n        }\n        /**\n         * Protobuf type {@code org.apache.dubbo.metadata.definition.protobuf.model.PBResponseType}\n         */\n        public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder<Builder>\n                implements\n                // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.definition.protobuf.model.PBResponseType)\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseTypeOrBuilder {\n            public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                        .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBResponseType_descriptor;\n            }\n\n            protected FieldAccessorTable internalGetFieldAccessorTable() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                        .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBResponseType_fieldAccessorTable\n                        .ensureFieldAccessorsInitialized(\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType.class,\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType.Builder\n                                        .class);\n            }\n\n            // Construct using org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType.newBuilder()\n            private Builder() {\n                maybeForceBuilderInitialization();\n            }\n\n            private Builder(BuilderParent parent) {\n                super(parent);\n                maybeForceBuilderInitialization();\n            }\n\n            private void maybeForceBuilderInitialization() {\n                if (com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders) {\n                    getCDubboPBRequestTypeFieldBuilder();\n                }\n            }\n\n            public Builder clear() {\n                super.clear();\n                msg_ = \"\";\n                bitField0_ = (bitField0_ & ~0x00000001);\n                if (cDubboPBRequestTypeBuilder_ == null) {\n                    cDubboPBRequestType_ = null;\n                } else {\n                    cDubboPBRequestTypeBuilder_.clear();\n                }\n                bitField0_ = (bitField0_ & ~0x00000002);\n                return this;\n            }\n\n            public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                        .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBResponseType_descriptor;\n            }\n\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType\n                    getDefaultInstanceForType() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType.getDefaultInstance();\n            }\n\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType build() {\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType result = buildPartial();\n                if (!result.isInitialized()) {\n                    throw newUninitializedMessageException(result);\n                }\n                return result;\n            }\n\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType buildPartial() {\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType result =\n                        new org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType(this);\n                int from_bitField0_ = bitField0_;\n                int to_bitField0_ = 0;\n                if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n                    to_bitField0_ |= 0x00000001;\n                }\n                result.msg_ = msg_;\n                if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n                    to_bitField0_ |= 0x00000002;\n                }\n                if (cDubboPBRequestTypeBuilder_ == null) {\n                    result.cDubboPBRequestType_ = cDubboPBRequestType_;\n                } else {\n                    result.cDubboPBRequestType_ = cDubboPBRequestTypeBuilder_.build();\n                }\n                result.bitField0_ = to_bitField0_;\n                onBuilt();\n                return result;\n            }\n\n            public Builder clone() {\n                return (Builder) super.clone();\n            }\n\n            public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, java.lang.Object value) {\n                return (Builder) super.setField(field, value);\n            }\n\n            public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) {\n                return (Builder) super.clearField(field);\n            }\n\n            public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n                return (Builder) super.clearOneof(oneof);\n            }\n\n            public Builder setRepeatedField(\n                    com.google.protobuf.Descriptors.FieldDescriptor field, int index, java.lang.Object value) {\n                return (Builder) super.setRepeatedField(field, index, value);\n            }\n\n            public Builder addRepeatedField(\n                    com.google.protobuf.Descriptors.FieldDescriptor field, java.lang.Object value) {\n                return (Builder) super.addRepeatedField(field, value);\n            }\n\n            public Builder mergeFrom(com.google.protobuf.Message other) {\n                if (other instanceof org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType) {\n                    return mergeFrom(\n                            (org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType) other);\n                } else {\n                    super.mergeFrom(other);\n                    return this;\n                }\n            }\n\n            public Builder mergeFrom(\n                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType other) {\n                if (other\n                        == org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType\n                                .getDefaultInstance()) return this;\n                if (other.hasMsg()) {\n                    bitField0_ |= 0x00000001;\n                    msg_ = other.msg_;\n                    onChanged();\n                }\n                if (other.hasCDubboPBRequestType()) {\n                    mergeCDubboPBRequestType(other.getCDubboPBRequestType());\n                }\n                this.mergeUnknownFields(other.unknownFields);\n                onChanged();\n                return this;\n            }\n\n            public final boolean isInitialized() {\n                if (hasCDubboPBRequestType()) {\n                    if (!getCDubboPBRequestType().isInitialized()) {\n                        return false;\n                    }\n                }\n                return true;\n            }\n\n            public Builder mergeFrom(\n                    com.google.protobuf.CodedInputStream input,\n                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                    throws java.io.IOException {\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType parsedMessage = null;\n                try {\n                    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n                } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                    parsedMessage = (org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType)\n                            e.getUnfinishedMessage();\n                    throw e.unwrapIOException();\n                } finally {\n                    if (parsedMessage != null) {\n                        mergeFrom(parsedMessage);\n                    }\n                }\n                return this;\n            }\n\n            private int bitField0_;\n\n            private java.lang.Object msg_ = \"\";\n            /**\n             * <code>optional string msg = 1;</code>\n             */\n            public boolean hasMsg() {\n                return ((bitField0_ & 0x00000001) == 0x00000001);\n            }\n            /**\n             * <code>optional string msg = 1;</code>\n             */\n            public java.lang.String getMsg() {\n                java.lang.Object ref = msg_;\n                if (!(ref instanceof java.lang.String)) {\n                    com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                    java.lang.String s = bs.toStringUtf8();\n                    if (bs.isValidUtf8()) {\n                        msg_ = s;\n                    }\n                    return s;\n                } else {\n                    return (java.lang.String) ref;\n                }\n            }\n            /**\n             * <code>optional string msg = 1;</code>\n             */\n            public com.google.protobuf.ByteString getMsgBytes() {\n                java.lang.Object ref = msg_;\n                if (ref instanceof String) {\n                    com.google.protobuf.ByteString b =\n                            com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);\n                    msg_ = b;\n                    return b;\n                } else {\n                    return (com.google.protobuf.ByteString) ref;\n                }\n            }\n            /**\n             * <code>optional string msg = 1;</code>\n             */\n            public Builder setMsg(java.lang.String value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000001;\n                msg_ = value;\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional string msg = 1;</code>\n             */\n            public Builder clearMsg() {\n                bitField0_ = (bitField0_ & ~0x00000001);\n                msg_ = getDefaultInstance().getMsg();\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional string msg = 1;</code>\n             */\n            public Builder setMsgBytes(com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000001;\n                msg_ = value;\n                onChanged();\n                return this;\n            }\n\n            private org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType cDubboPBRequestType_ =\n                    null;\n            private com.google.protobuf.SingleFieldBuilderV3<\n                            PBRequestType, PBRequestType.Builder, PBRequestTypeOrBuilder>\n                    cDubboPBRequestTypeBuilder_;\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n             */\n            public boolean hasCDubboPBRequestType() {\n                return ((bitField0_ & 0x00000002) == 0x00000002);\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType getCDubboPBRequestType() {\n                if (cDubboPBRequestTypeBuilder_ == null) {\n                    return cDubboPBRequestType_ == null\n                            ? org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType\n                                    .getDefaultInstance()\n                            : cDubboPBRequestType_;\n                } else {\n                    return cDubboPBRequestTypeBuilder_.getMessage();\n                }\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n             */\n            public Builder setCDubboPBRequestType(\n                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType value) {\n                if (cDubboPBRequestTypeBuilder_ == null) {\n                    if (value == null) {\n                        throw new NullPointerException();\n                    }\n                    cDubboPBRequestType_ = value;\n                    onChanged();\n                } else {\n                    cDubboPBRequestTypeBuilder_.setMessage(value);\n                }\n                bitField0_ |= 0x00000002;\n                return this;\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n             */\n            public Builder setCDubboPBRequestType(\n                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.Builder\n                            builderForValue) {\n                if (cDubboPBRequestTypeBuilder_ == null) {\n                    cDubboPBRequestType_ = builderForValue.build();\n                    onChanged();\n                } else {\n                    cDubboPBRequestTypeBuilder_.setMessage(builderForValue.build());\n                }\n                bitField0_ |= 0x00000002;\n                return this;\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n             */\n            public Builder mergeCDubboPBRequestType(\n                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType value) {\n                if (cDubboPBRequestTypeBuilder_ == null) {\n                    if (((bitField0_ & 0x00000002) == 0x00000002)\n                            && cDubboPBRequestType_ != null\n                            && cDubboPBRequestType_\n                                    != org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType\n                                            .getDefaultInstance()) {\n                        cDubboPBRequestType_ =\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.newBuilder(\n                                                cDubboPBRequestType_)\n                                        .mergeFrom(value)\n                                        .buildPartial();\n                    } else {\n                        cDubboPBRequestType_ = value;\n                    }\n                    onChanged();\n                } else {\n                    cDubboPBRequestTypeBuilder_.mergeFrom(value);\n                }\n                bitField0_ |= 0x00000002;\n                return this;\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n             */\n            public Builder clearCDubboPBRequestType() {\n                if (cDubboPBRequestTypeBuilder_ == null) {\n                    cDubboPBRequestType_ = null;\n                    onChanged();\n                } else {\n                    cDubboPBRequestTypeBuilder_.clear();\n                }\n                bitField0_ = (bitField0_ & ~0x00000002);\n                return this;\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType.Builder\n                    getCDubboPBRequestTypeBuilder() {\n                bitField0_ |= 0x00000002;\n                onChanged();\n                return getCDubboPBRequestTypeFieldBuilder().getBuilder();\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestTypeOrBuilder\n                    getCDubboPBRequestTypeOrBuilder() {\n                if (cDubboPBRequestTypeBuilder_ != null) {\n                    return cDubboPBRequestTypeBuilder_.getMessageOrBuilder();\n                } else {\n                    return cDubboPBRequestType_ == null\n                            ? org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBRequestType\n                                    .getDefaultInstance()\n                            : cDubboPBRequestType_;\n                }\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PBRequestType CDubboPBRequestType = 3;</code>\n             */\n            private com.google.protobuf.SingleFieldBuilderV3<\n                            PBRequestType, PBRequestType.Builder, PBRequestTypeOrBuilder>\n                    getCDubboPBRequestTypeFieldBuilder() {\n                if (cDubboPBRequestTypeBuilder_ == null) {\n                    cDubboPBRequestTypeBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<\n                            PBRequestType, PBRequestType.Builder, PBRequestTypeOrBuilder>(\n                            getCDubboPBRequestType(), getParentForChildren(), isClean());\n                    cDubboPBRequestType_ = null;\n                }\n                return cDubboPBRequestTypeBuilder_;\n            }\n\n            public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n                return super.setUnknownFields(unknownFields);\n            }\n\n            public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n                return super.mergeUnknownFields(unknownFields);\n            }\n\n            // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.definition.protobuf.model.PBResponseType)\n        }\n\n        // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.definition.protobuf.model.PBResponseType)\n        private static final org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType\n                DEFAULT_INSTANCE;\n\n        static {\n            DEFAULT_INSTANCE = new org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType();\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType getDefaultInstance() {\n            return DEFAULT_INSTANCE;\n        }\n\n        @java.lang.Deprecated\n        public static final com.google.protobuf.Parser<PBResponseType> PARSER =\n                new com.google.protobuf.AbstractParser<PBResponseType>() {\n                    public PBResponseType parsePartialFrom(\n                            com.google.protobuf.CodedInputStream input,\n                            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                            throws com.google.protobuf.InvalidProtocolBufferException {\n                        return new PBResponseType(input, extensionRegistry);\n                    }\n                };\n\n        public static com.google.protobuf.Parser<PBResponseType> parser() {\n            return PARSER;\n        }\n\n        @java.lang.Override\n        public com.google.protobuf.Parser<PBResponseType> getParserForType() {\n            return PARSER;\n        }\n\n        public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PBResponseType getDefaultInstanceForType() {\n            return DEFAULT_INSTANCE;\n        }\n    }\n\n    public interface PhoneNumberOrBuilder\n            extends\n            // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber)\n            com.google.protobuf.MessageOrBuilder {\n\n        /**\n         * <code>required string number = 1;</code>\n         */\n        boolean hasNumber();\n        /**\n         * <code>required string number = 1;</code>\n         */\n        java.lang.String getNumber();\n        /**\n         * <code>required string number = 1;</code>\n         */\n        com.google.protobuf.ByteString getNumberBytes();\n\n        /**\n         * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PhoneType type = 2 [default = HOME];</code>\n         */\n        boolean hasType();\n        /**\n         * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PhoneType type = 2 [default = HOME];</code>\n         */\n        org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType getType();\n    }\n    /**\n     * Protobuf type {@code org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber}\n     */\n    public static final class PhoneNumber extends com.google.protobuf.GeneratedMessageV3\n            implements\n            // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber)\n            PhoneNumberOrBuilder {\n        private static final long serialVersionUID = 0L;\n        // Use PhoneNumber.newBuilder() to construct.\n        private PhoneNumber(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {\n            super(builder);\n        }\n\n        private PhoneNumber() {\n            number_ = \"\";\n            type_ = 1;\n        }\n\n        @java.lang.Override\n        public final com.google.protobuf.UnknownFieldSet getUnknownFields() {\n            return this.unknownFields;\n        }\n\n        private PhoneNumber(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            this();\n            int mutable_bitField0_ = 0;\n            com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n                    com.google.protobuf.UnknownFieldSet.newBuilder();\n            try {\n                boolean done = false;\n                while (!done) {\n                    int tag = input.readTag();\n                    switch (tag) {\n                        case 0:\n                            done = true;\n                            break;\n                        default: {\n                            if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) {\n                                done = true;\n                            }\n                            break;\n                        }\n                        case 10: {\n                            com.google.protobuf.ByteString bs = input.readBytes();\n                            bitField0_ |= 0x00000001;\n                            number_ = bs;\n                            break;\n                        }\n                        case 16: {\n                            int rawValue = input.readEnum();\n                            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType value =\n                                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType.valueOf(\n                                            rawValue);\n                            if (value == null) {\n                                unknownFields.mergeVarintField(2, rawValue);\n                            } else {\n                                bitField0_ |= 0x00000002;\n                                type_ = rawValue;\n                            }\n                            break;\n                        }\n                    }\n                }\n            } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                throw e.setUnfinishedMessage(this);\n            } catch (java.io.IOException e) {\n                throw new com.google.protobuf.InvalidProtocolBufferException(e).setUnfinishedMessage(this);\n            } finally {\n                this.unknownFields = unknownFields.build();\n                makeExtensionsImmutable();\n            }\n        }\n\n        public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n            return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                    .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PhoneNumber_descriptor;\n        }\n\n        protected FieldAccessorTable internalGetFieldAccessorTable() {\n            return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                    .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PhoneNumber_fieldAccessorTable\n                    .ensureFieldAccessorsInitialized(\n                            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.class,\n                            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.Builder.class);\n        }\n\n        private int bitField0_;\n        public static final int NUMBER_FIELD_NUMBER = 1;\n        private volatile java.lang.Object number_;\n        /**\n         * <code>required string number = 1;</code>\n         */\n        public boolean hasNumber() {\n            return ((bitField0_ & 0x00000001) == 0x00000001);\n        }\n        /**\n         * <code>required string number = 1;</code>\n         */\n        public java.lang.String getNumber() {\n            java.lang.Object ref = number_;\n            if (ref instanceof java.lang.String) {\n                return (java.lang.String) ref;\n            } else {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                java.lang.String s = bs.toStringUtf8();\n                if (bs.isValidUtf8()) {\n                    number_ = s;\n                }\n                return s;\n            }\n        }\n        /**\n         * <code>required string number = 1;</code>\n         */\n        public com.google.protobuf.ByteString getNumberBytes() {\n            java.lang.Object ref = number_;\n            if (ref instanceof java.lang.String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);\n                number_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        public static final int TYPE_FIELD_NUMBER = 2;\n        private int type_;\n        /**\n         * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PhoneType type = 2 [default = HOME];</code>\n         */\n        public boolean hasType() {\n            return ((bitField0_ & 0x00000002) == 0x00000002);\n        }\n        /**\n         * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PhoneType type = 2 [default = HOME];</code>\n         */\n        public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType getType() {\n            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType result =\n                    org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType.valueOf(type_);\n            return result == null\n                    ? org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType.HOME\n                    : result;\n        }\n\n        private byte memoizedIsInitialized = -1;\n\n        public final boolean isInitialized() {\n            byte isInitialized = memoizedIsInitialized;\n            if (isInitialized == 1) return true;\n            if (isInitialized == 0) return false;\n\n            if (!hasNumber()) {\n                memoizedIsInitialized = 0;\n                return false;\n            }\n            memoizedIsInitialized = 1;\n            return true;\n        }\n\n        public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n            if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                com.google.protobuf.GeneratedMessageV3.writeString(output, 1, number_);\n            }\n            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                output.writeEnum(2, type_);\n            }\n            unknownFields.writeTo(output);\n        }\n\n        public int getSerializedSize() {\n            int size = memoizedSize;\n            if (size != -1) return size;\n\n            size = 0;\n            if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, number_);\n            }\n            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                size += com.google.protobuf.CodedOutputStream.computeEnumSize(2, type_);\n            }\n            size += unknownFields.getSerializedSize();\n            memoizedSize = size;\n            return size;\n        }\n\n        @java.lang.Override\n        public boolean equals(final java.lang.Object obj) {\n            if (obj == this) {\n                return true;\n            }\n            if (!(obj instanceof org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber)) {\n                return super.equals(obj);\n            }\n            org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber other =\n                    (org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber) obj;\n\n            boolean result = true;\n            result = result && (hasNumber() == other.hasNumber());\n            if (hasNumber()) {\n                result = result && getNumber().equals(other.getNumber());\n            }\n            result = result && (hasType() == other.hasType());\n            if (hasType()) {\n                result = result && type_ == other.type_;\n            }\n            result = result && unknownFields.equals(other.unknownFields);\n            return result;\n        }\n\n        @java.lang.Override\n        public int hashCode() {\n            if (memoizedHashCode != 0) {\n                return memoizedHashCode;\n            }\n            int hash = 41;\n            hash = (19 * hash) + getDescriptor().hashCode();\n            if (hasNumber()) {\n                hash = (37 * hash) + NUMBER_FIELD_NUMBER;\n                hash = (53 * hash) + getNumber().hashCode();\n            }\n            if (hasType()) {\n                hash = (37 * hash) + TYPE_FIELD_NUMBER;\n                hash = (53 * hash) + type_;\n            }\n            hash = (29 * hash) + unknownFields.hashCode();\n            memoizedHashCode = hash;\n            return hash;\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseFrom(\n                java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseFrom(\n                java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseFrom(\n                com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseFrom(\n                com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseFrom(byte[] data)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseFrom(\n                byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseFrom(\n                java.io.InputStream input) throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseFrom(\n                java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseDelimitedFrom(\n                java.io.InputStream input) throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseDelimitedFrom(\n                java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(\n                    PARSER, input, extensionRegistry);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseFrom(\n                com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input);\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parseFrom(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry);\n        }\n\n        public Builder newBuilderForType() {\n            return newBuilder();\n        }\n\n        public static Builder newBuilder() {\n            return DEFAULT_INSTANCE.toBuilder();\n        }\n\n        public static Builder newBuilder(\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber prototype) {\n            return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n        }\n\n        public Builder toBuilder() {\n            return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this);\n        }\n\n        @java.lang.Override\n        protected Builder newBuilderForType(BuilderParent parent) {\n            Builder builder = new Builder(parent);\n            return builder;\n        }\n        /**\n         * Protobuf type {@code org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber}\n         */\n        public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder<Builder>\n                implements\n                // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber)\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumberOrBuilder {\n            public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                        .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PhoneNumber_descriptor;\n            }\n\n            protected FieldAccessorTable internalGetFieldAccessorTable() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                        .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PhoneNumber_fieldAccessorTable\n                        .ensureFieldAccessorsInitialized(\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.class,\n                                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.Builder.class);\n            }\n\n            // Construct using org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.newBuilder()\n            private Builder() {\n                maybeForceBuilderInitialization();\n            }\n\n            private Builder(BuilderParent parent) {\n                super(parent);\n                maybeForceBuilderInitialization();\n            }\n\n            private void maybeForceBuilderInitialization() {\n                if (com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders) {}\n            }\n\n            public Builder clear() {\n                super.clear();\n                number_ = \"\";\n                bitField0_ = (bitField0_ & ~0x00000001);\n                type_ = 1;\n                bitField0_ = (bitField0_ & ~0x00000002);\n                return this;\n            }\n\n            public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB\n                        .internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PhoneNumber_descriptor;\n            }\n\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber\n                    getDefaultInstanceForType() {\n                return org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber.getDefaultInstance();\n            }\n\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber build() {\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber result = buildPartial();\n                if (!result.isInitialized()) {\n                    throw newUninitializedMessageException(result);\n                }\n                return result;\n            }\n\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber buildPartial() {\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber result =\n                        new org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber(this);\n                int from_bitField0_ = bitField0_;\n                int to_bitField0_ = 0;\n                if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n                    to_bitField0_ |= 0x00000001;\n                }\n                result.number_ = number_;\n                if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n                    to_bitField0_ |= 0x00000002;\n                }\n                result.type_ = type_;\n                result.bitField0_ = to_bitField0_;\n                onBuilt();\n                return result;\n            }\n\n            public Builder clone() {\n                return (Builder) super.clone();\n            }\n\n            public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, java.lang.Object value) {\n                return (Builder) super.setField(field, value);\n            }\n\n            public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) {\n                return (Builder) super.clearField(field);\n            }\n\n            public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n                return (Builder) super.clearOneof(oneof);\n            }\n\n            public Builder setRepeatedField(\n                    com.google.protobuf.Descriptors.FieldDescriptor field, int index, java.lang.Object value) {\n                return (Builder) super.setRepeatedField(field, index, value);\n            }\n\n            public Builder addRepeatedField(\n                    com.google.protobuf.Descriptors.FieldDescriptor field, java.lang.Object value) {\n                return (Builder) super.addRepeatedField(field, value);\n            }\n\n            public Builder mergeFrom(com.google.protobuf.Message other) {\n                if (other instanceof org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber) {\n                    return mergeFrom((org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber) other);\n                } else {\n                    super.mergeFrom(other);\n                    return this;\n                }\n            }\n\n            public Builder mergeFrom(org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber other) {\n                if (other\n                        == org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber\n                                .getDefaultInstance()) return this;\n                if (other.hasNumber()) {\n                    bitField0_ |= 0x00000001;\n                    number_ = other.number_;\n                    onChanged();\n                }\n                if (other.hasType()) {\n                    setType(other.getType());\n                }\n                this.mergeUnknownFields(other.unknownFields);\n                onChanged();\n                return this;\n            }\n\n            public final boolean isInitialized() {\n                if (!hasNumber()) {\n                    return false;\n                }\n                return true;\n            }\n\n            public Builder mergeFrom(\n                    com.google.protobuf.CodedInputStream input,\n                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                    throws java.io.IOException {\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber parsedMessage = null;\n                try {\n                    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n                } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                    parsedMessage = (org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber)\n                            e.getUnfinishedMessage();\n                    throw e.unwrapIOException();\n                } finally {\n                    if (parsedMessage != null) {\n                        mergeFrom(parsedMessage);\n                    }\n                }\n                return this;\n            }\n\n            private int bitField0_;\n\n            private java.lang.Object number_ = \"\";\n            /**\n             * <code>required string number = 1;</code>\n             */\n            public boolean hasNumber() {\n                return ((bitField0_ & 0x00000001) == 0x00000001);\n            }\n            /**\n             * <code>required string number = 1;</code>\n             */\n            public java.lang.String getNumber() {\n                java.lang.Object ref = number_;\n                if (!(ref instanceof java.lang.String)) {\n                    com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                    java.lang.String s = bs.toStringUtf8();\n                    if (bs.isValidUtf8()) {\n                        number_ = s;\n                    }\n                    return s;\n                } else {\n                    return (java.lang.String) ref;\n                }\n            }\n            /**\n             * <code>required string number = 1;</code>\n             */\n            public com.google.protobuf.ByteString getNumberBytes() {\n                java.lang.Object ref = number_;\n                if (ref instanceof String) {\n                    com.google.protobuf.ByteString b =\n                            com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);\n                    number_ = b;\n                    return b;\n                } else {\n                    return (com.google.protobuf.ByteString) ref;\n                }\n            }\n            /**\n             * <code>required string number = 1;</code>\n             */\n            public Builder setNumber(java.lang.String value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000001;\n                number_ = value;\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>required string number = 1;</code>\n             */\n            public Builder clearNumber() {\n                bitField0_ = (bitField0_ & ~0x00000001);\n                number_ = getDefaultInstance().getNumber();\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>required string number = 1;</code>\n             */\n            public Builder setNumberBytes(com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000001;\n                number_ = value;\n                onChanged();\n                return this;\n            }\n\n            private int type_ = 1;\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PhoneType type = 2 [default = HOME];</code>\n             */\n            public boolean hasType() {\n                return ((bitField0_ & 0x00000002) == 0x00000002);\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PhoneType type = 2 [default = HOME];</code>\n             */\n            public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType getType() {\n                org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType result =\n                        org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType.valueOf(type_);\n                return result == null\n                        ? org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType.HOME\n                        : result;\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PhoneType type = 2 [default = HOME];</code>\n             */\n            public Builder setType(org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneType value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000002;\n                type_ = value.getNumber();\n                onChanged();\n                return this;\n            }\n            /**\n             * <code>optional .org.apache.dubbo.metadata.definition.protobuf.model.PhoneType type = 2 [default = HOME];</code>\n             */\n            public Builder clearType() {\n                bitField0_ = (bitField0_ & ~0x00000002);\n                type_ = 1;\n                onChanged();\n                return this;\n            }\n\n            public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n                return super.setUnknownFields(unknownFields);\n            }\n\n            public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) {\n                return super.mergeUnknownFields(unknownFields);\n            }\n\n            // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber)\n        }\n\n        // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.definition.protobuf.model.PhoneNumber)\n        private static final org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber DEFAULT_INSTANCE;\n\n        static {\n            DEFAULT_INSTANCE = new org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber();\n        }\n\n        public static org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getDefaultInstance() {\n            return DEFAULT_INSTANCE;\n        }\n\n        @java.lang.Deprecated\n        public static final com.google.protobuf.Parser<PhoneNumber> PARSER =\n                new com.google.protobuf.AbstractParser<PhoneNumber>() {\n                    public PhoneNumber parsePartialFrom(\n                            com.google.protobuf.CodedInputStream input,\n                            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                            throws com.google.protobuf.InvalidProtocolBufferException {\n                        return new PhoneNumber(input, extensionRegistry);\n                    }\n                };\n\n        public static com.google.protobuf.Parser<PhoneNumber> parser() {\n            return PARSER;\n        }\n\n        @java.lang.Override\n        public com.google.protobuf.Parser<PhoneNumber> getParserForType() {\n            return PARSER;\n        }\n\n        public org.apache.dubbo.metadata.definition.protobuf.model.GooglePB.PhoneNumber getDefaultInstanceForType() {\n            return DEFAULT_INSTANCE;\n        }\n    }\n\n    private static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_descriptor;\n    private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_fieldAccessorTable;\n    private static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_DoubleMapEntry_descriptor;\n    private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_DoubleMapEntry_fieldAccessorTable;\n    private static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_BytesMapEntry_descriptor;\n    private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_BytesMapEntry_fieldAccessorTable;\n    private static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBResponseType_descriptor;\n    private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBResponseType_fieldAccessorTable;\n    private static final com.google.protobuf.Descriptors.Descriptor\n            internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PhoneNumber_descriptor;\n    private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable\n            internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PhoneNumber_fieldAccessorTable;\n\n    public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() {\n        return descriptor;\n    }\n\n    private static com.google.protobuf.Descriptors.FileDescriptor descriptor;\n\n    static {\n        java.lang.String[] descriptorData = {\n            \"\\n\\016GooglePB.proto\\0223org.apache.dubbo.metad\" + \"ata.definition.protobuf.model\\\"\\301\\004\\n\\rPBRequ\"\n                    + \"estType\\022\\r\\n\\005money\\030\\001 \\001(\\001\\022\\014\\n\\004cash\\030\\002 \\001(\\002\\022\\013\\n\\003\"\n                    + \"age\\030\\003 \\001(\\005\\022\\013\\n\\003num\\030\\004 \\001(\\003\\022\\013\\n\\003sex\\030\\005 \\001(\\010\\022\\014\\n\\004n\"\n                    + \"ame\\030\\006 \\001(\\t\\022\\013\\n\\003msg\\030\\007 \\001(\\014\\022O\\n\\005phone\\030\\010 \\003(\\0132@.\"\n                    + \"org.apache.dubbo.metadata.definition.pro\"\n                    + \"tobuf.model.PhoneNumber\\022d\\n\\tdoubleMap\\030\\t \\003\"\n                    + \"(\\0132Q.org.apache.dubbo.metadata.definitio\"\n                    + \"n.protobuf.model.PBRequestType.DoubleMap\"\n                    + \"Entry\\022\\021\\n\\tbytesList\\030\\n \\003(\\014\\022b\\n\\010bytesMap\\030\\013 \\003\",\n            \"(\\0132P.org.apache.dubbo.metadata.definitio\" + \"n.protobuf.model.PBRequestType.BytesMapE\"\n                    + \"ntry\\032r\\n\\016DoubleMapEntry\\022\\013\\n\\003key\\030\\001 \\001(\\t\\022O\\n\\005v\"\n                    + \"alue\\030\\002 \\001(\\0132@.org.apache.dubbo.metadata.d\"\n                    + \"efinition.protobuf.model.PhoneNumber:\\0028\\001\"\n                    + \"\\032/\\n\\rBytesMapEntry\\022\\013\\n\\003key\\030\\001 \\001(\\t\\022\\r\\n\\005value\\030\"\n                    + \"\\002 \\001(\\014:\\0028\\001\\\"~\\n\\016PBResponseType\\022\\013\\n\\003msg\\030\\001 \\001(\\t\"\n                    + \"\\022_\\n\\023CDubboPBRequestType\\030\\003 \\001(\\0132B.org.apac\"\n                    + \"he.dubbo.metadata.definition.protobuf.mo\"\n                    + \"del.PBRequestType\\\"q\\n\\013PhoneNumber\\022\\016\\n\\006numb\",\n            \"er\\030\\001 \\002(\\t\\022R\\n\\004type\\030\\002 \\001(\\0162>.org.apache.dubb\"\n                    + \"o.metadata.definition.protobuf.model.Pho\"\n                    + \"neType:\\004HOME*+\\n\\tPhoneType\\022\\n\\n\\006MOBILE\\020\\000\\022\\010\\n\"\n                    + \"\\004HOME\\020\\001\\022\\010\\n\\004WORK\\020\\0022\\247\\001\\n\\017CDubboPBService\\022\\223\\001\"\n                    + \"\\n\\010sayHello\\022B.org.apache.dubbo.metadata.d\"\n                    + \"efinition.protobuf.model.PBRequestType\\032C\"\n                    + \".org.apache.dubbo.metadata.definition.pr\"\n                    + \"otobuf.model.PBResponseType\"\n        };\n        com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =\n                new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {\n                    public com.google.protobuf.ExtensionRegistry assignDescriptors(\n                            com.google.protobuf.Descriptors.FileDescriptor root) {\n                        descriptor = root;\n                        return null;\n                    }\n                };\n        com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom(\n                descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] {}, assigner);\n        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_descriptor =\n                getDescriptor().getMessageTypes().get(0);\n        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_descriptor,\n                        new java.lang.String[] {\n                            \"Money\",\n                            \"Cash\",\n                            \"Age\",\n                            \"Num\",\n                            \"Sex\",\n                            \"Name\",\n                            \"Msg\",\n                            \"Phone\",\n                            \"DoubleMap\",\n                            \"BytesList\",\n                            \"BytesMap\",\n                        });\n        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_DoubleMapEntry_descriptor =\n                internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_descriptor\n                        .getNestedTypes()\n                        .get(0);\n        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_DoubleMapEntry_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_DoubleMapEntry_descriptor,\n                        new java.lang.String[] {\n                            \"Key\", \"Value\",\n                        });\n        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_BytesMapEntry_descriptor =\n                internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_descriptor\n                        .getNestedTypes()\n                        .get(1);\n        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_BytesMapEntry_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBRequestType_BytesMapEntry_descriptor,\n                        new java.lang.String[] {\n                            \"Key\", \"Value\",\n                        });\n        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBResponseType_descriptor =\n                getDescriptor().getMessageTypes().get(1);\n        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBResponseType_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PBResponseType_descriptor,\n                        new java.lang.String[] {\n                            \"Msg\", \"CDubboPBRequestType\",\n                        });\n        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PhoneNumber_descriptor =\n                getDescriptor().getMessageTypes().get(2);\n        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PhoneNumber_fieldAccessorTable =\n                new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(\n                        internal_static_org_apache_dubbo_metadata_definition_protobuf_model_PhoneNumber_descriptor,\n                        new java.lang.String[] {\n                            \"Number\", \"Type\",\n                        });\n    }\n\n    // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-definition-protobuf/src/test/java/org/apache/dubbo/metadata/definition/protobuf/model/ServiceInterface.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.definition.protobuf.model;\n\npublic interface ServiceInterface {\n    GooglePB.PBResponseType sayHello(GooglePB.PBRequestType requestType);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-definition-protobuf/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metadata</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-metadata-processor</artifactId>\n  <packaging>jar</packaging>\n  <name>dubbo-metadata-processor</name>\n  <description>The metadata processor module of Dubbo project</description>\n\n  <dependencies>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n      <exclusions>\n        <exclusion>\n          <groupId>commons-io</groupId>\n          <artifactId>commons-io</artifactId>\n        </exclusion>\n        <exclusion>\n          <groupId>org.javassist</groupId>\n          <artifactId>javassist</artifactId>\n        </exclusion>\n        <exclusion>\n          <groupId>javax.annotation</groupId>\n          <artifactId>javax.annotation-api</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n\n    <!-- Test -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n      <exclusions>\n        <!--                <exclusion>-->\n        <!--                    <groupId>org.apache.dubbo</groupId>-->\n        <!--                    <artifactId>dubbo-registry-api</artifactId>-->\n        <!--                </exclusion>-->\n        <exclusion>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-remoting-api</artifactId>\n        </exclusion>\n        <exclusion>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-rpc-injvm</artifactId>\n        </exclusion>\n        <exclusion>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-filter-validation</artifactId>\n        </exclusion>\n        <exclusion>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-filter-cache</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n\n    <!-- JAX-RS API -->\n    <dependency>\n      <groupId>javax.ws.rs</groupId>\n      <artifactId>javax.ws.rs-api</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- Spring Web MVC -->\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-web</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/AbstractServiceAnnotationProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.Processor;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ElementKind;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.PackageElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.util.Elements;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static javax.lang.model.util.ElementFilter.methodsIn;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SUPPORTED_ANNOTATION_TYPES;\n\n/**\n * Abstract {@link Processor} for the classes that were annotated by Dubbo's @Service\n *\n * @since 2.7.6\n */\npublic abstract class AbstractServiceAnnotationProcessor extends AbstractProcessor {\n\n    protected Elements elements;\n\n    private List<? extends Element> objectMembers;\n\n    public synchronized void init(ProcessingEnvironment processingEnv) {\n        super.init(processingEnv);\n        this.elements = processingEnv.getElementUtils();\n        this.objectMembers = elements.getAllMembers(elements.getTypeElement(Object.class.getName()));\n    }\n\n    protected List<? extends Element> getActualMembers(TypeElement type) {\n        List<? extends Element> members = new LinkedList<>(elements.getAllMembers(type));\n        members.removeAll(objectMembers);\n        return members;\n    }\n\n    protected List<? extends ExecutableElement> getActualMethods(TypeElement type) {\n        return methodsIn(getActualMembers(type));\n    }\n\n    protected Map<String, ExecutableElement> getActualMethodsMap(TypeElement type) {\n        Map<String, ExecutableElement> methodsMap = new HashMap<>();\n        getActualMethods(type).forEach(method -> {\n            methodsMap.put(method.toString(), method);\n        });\n        return methodsMap;\n    }\n\n    public static String getMethodSignature(ExecutableElement method) {\n        if (!ElementKind.METHOD.equals(method.getKind())) {\n            throw new IllegalArgumentException(\"The argument must be Method Kind\");\n        }\n\n        StringBuilder methodSignatureBuilder = new StringBuilder();\n\n        method.getModifiers().forEach(member -> {\n            methodSignatureBuilder.append(member).append(' ');\n        });\n\n        methodSignatureBuilder.append(method.getReturnType()).append(' ').append(method.toString());\n\n        return methodSignatureBuilder.toString();\n    }\n\n    protected TypeElement getTypeElement(CharSequence className) {\n        return elements.getTypeElement(className);\n    }\n\n    protected PackageElement getPackageElement(Element type) {\n        return this.elements.getPackageOf(type);\n    }\n\n    @Override\n    public SourceVersion getSupportedSourceVersion() {\n        return SourceVersion.latest();\n    }\n\n    @Override\n    public final Set<String> getSupportedAnnotationTypes() {\n        return SUPPORTED_ANNOTATION_TYPES;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ClassPathMetadataStorage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing;\n\nimport javax.annotation.processing.Filer;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.tools.FileObject;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.Writer;\nimport java.util.Optional;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport static java.util.Optional.empty;\nimport static java.util.Optional.ofNullable;\nimport static javax.tools.StandardLocation.CLASS_OUTPUT;\nimport static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.info;\nimport static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.warn;\n\n/**\n * A storage class for metadata under class path\n */\npublic class ClassPathMetadataStorage {\n\n    private final Filer filer;\n\n    public ClassPathMetadataStorage(ProcessingEnvironment processingEnv) {\n        this.filer = processingEnv.getFiler();\n    }\n\n    public void write(Supplier<String> contentSupplier, String resourceName) {\n        try (Writer writer = getWriter(resourceName)) {\n            writer.write(contentSupplier.get());\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public <T> Optional<T> read(String resourceName, Function<Reader, T> consumer) {\n        if (exists(resourceName)) {\n            try (Reader reader = getReader(resourceName)) {\n                return ofNullable(consumer.apply(reader));\n            } catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return empty();\n    }\n\n    private boolean exists(String resourceName) {\n\n        return getResource(resourceName)\n                .map(FileObject::toUri)\n                .map(File::new)\n                .map(File::exists)\n                .orElse(false);\n    }\n\n    private Reader getReader(String resourceName) {\n        return getResource(resourceName)\n                .map(fileObject -> {\n                    try {\n                        return fileObject.openReader(false);\n                    } catch (IOException e) {\n                    }\n                    return null;\n                })\n                .orElse(null);\n    }\n\n    private FileObject createResource(String resourceName) throws IOException {\n        return filer.createResource(CLASS_OUTPUT, \"\", resourceName);\n    }\n\n    private Optional<FileObject> getResource(String resourceName) {\n        try {\n            FileObject fileObject = filer.getResource(CLASS_OUTPUT, \"\", resourceName);\n            return ofNullable(fileObject);\n        } catch (IOException e) {\n            warn(e.getMessage());\n        }\n        return empty();\n    }\n\n    private Writer getWriter(String resourceName) throws IOException {\n        FileObject fileObject = createResource(resourceName);\n        info(\n                \"The resource[path : %s , deleted : %s] will be written\",\n                fileObject.toUri().getPath(), fileObject.delete());\n        return fileObject.openWriter();\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/ServiceDefinitionMetadataAnnotationProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.Processor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.lang.model.element.TypeElement;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Set;\n\nimport static javax.lang.model.util.ElementFilter.typesIn;\nimport static org.apache.dubbo.metadata.annotation.processing.builder.ServiceDefinitionBuilder.build;\n\n/**\n * The {@link Processor} class to generate the metadata of {@link ServiceDefinition} whose classes are annotated by Dubbo's @Service\n *\n * @see Processor\n * @since 2.7.6\n */\npublic class ServiceDefinitionMetadataAnnotationProcessor extends AbstractServiceAnnotationProcessor {\n\n    private List<ServiceDefinition> serviceDefinitions = new LinkedList<>();\n\n    @Override\n    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n\n        typesIn(roundEnv.getRootElements()).forEach(serviceType -> process(processingEnv, serviceType, annotations));\n\n        if (roundEnv.processingOver()) {\n            ClassPathMetadataStorage writer = new ClassPathMetadataStorage(processingEnv);\n            writer.write(() -> JsonUtils.toJson(serviceDefinitions), \"META-INF/dubbo/service-definitions.json\");\n        }\n\n        return false;\n    }\n\n    private void process(\n            ProcessingEnvironment processingEnv, TypeElement serviceType, Set<? extends TypeElement> annotations) {\n        serviceDefinitions.add(build(processingEnv, serviceType));\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.type.ArrayType;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.lang.reflect.Array;\nimport java.util.Map;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isArrayType;\n\n/**\n * {@link TypeBuilder} for Java {@link Array}\n *\n * @since 2.7.6\n */\npublic class ArrayTypeDefinitionBuilder implements TypeBuilder<ArrayType> {\n\n    @Override\n    public boolean accept(ProcessingEnvironment processingEnv, TypeMirror type) {\n        return isArrayType(type);\n    }\n\n    @Override\n    public TypeDefinition build(\n            ProcessingEnvironment processingEnv, ArrayType type, Map<String, TypeDefinition> typeCache) {\n        TypeDefinition typeDefinition = new TypeDefinition(type.toString());\n        TypeMirror componentType = type.getComponentType();\n        TypeDefinition subTypeDefinition = TypeDefinitionBuilder.build(processingEnv, componentType, typeCache);\n        typeDefinition.getItems().add(subTypeDefinition.getType());\n        return typeDefinition;\n    }\n\n    @Override\n    public int getPriority() {\n        return MIN_PRIORITY - 4;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.DeclaredType;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.Elements;\nimport javax.lang.model.util.Types;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Objects;\n\n/**\n * {@link TypeBuilder} for Java {@link Collection}\n *\n * @since 2.7.6\n */\npublic class CollectionTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder {\n\n    @Override\n    public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) {\n        Elements elements = processingEnv.getElementUtils();\n        TypeElement collectionTypeElement = elements.getTypeElement(Collection.class.getTypeName());\n        TypeMirror collectionType = collectionTypeElement.asType();\n        Types types = processingEnv.getTypeUtils();\n        TypeMirror erasedType = types.erasure(type);\n        return types.isAssignable(erasedType, collectionType);\n    }\n\n    @Override\n    public TypeDefinition build(\n            ProcessingEnvironment processingEnv, DeclaredType type, Map<String, TypeDefinition> typeCache) {\n        String typeName = type.toString();\n        TypeDefinition typeDefinition = new TypeDefinition(typeName);\n        // Generic Type arguments\n        type.getTypeArguments().stream()\n                .map(typeArgument -> TypeDefinitionBuilder.build(\n                        processingEnv, typeArgument, typeCache)) // build the TypeDefinition from typeArgument\n                .filter(Objects::nonNull)\n                .map(TypeDefinition::getType)\n                .forEach(typeDefinition.getItems()::add); // Add into the declared TypeDefinition\n        return typeDefinition;\n    }\n\n    @Override\n    public int getPriority() {\n        return MIN_PRIORITY - 5;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/DeclaredTypeDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.type.DeclaredType;\nimport javax.lang.model.type.TypeMirror;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredType;\n\n/**\n * An interface of {@link TypeBuilder} for {@link DeclaredType}\n *\n * @since 2.7.6\n */\npublic interface DeclaredTypeDefinitionBuilder extends TypeBuilder<DeclaredType> {\n\n    @Override\n    default boolean accept(ProcessingEnvironment processingEnv, TypeMirror type) {\n        DeclaredType declaredType = ofDeclaredType(type);\n        if (declaredType == null) {\n            return false;\n        }\n        return accept(processingEnv, declaredType);\n    }\n\n    /**\n     * Test the specified {@link DeclaredType type} is accepted or not\n     *\n     * @param processingEnv {@link ProcessingEnvironment}\n     * @param type          {@link DeclaredType type}\n     * @return <code>true</code> if accepted\n     */\n    boolean accept(ProcessingEnvironment processingEnv, DeclaredType type);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.util.FieldUtils;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.Name;\nimport javax.lang.model.type.DeclaredType;\n\nimport java.util.Map;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isEnumType;\n\n/**\n * {@link TypeBuilder} for Java {@link Enum}\n *\n * @since 2.7.6\n */\npublic class EnumTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder {\n\n    @Override\n    public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) {\n        return isEnumType(type);\n    }\n\n    @Override\n    public TypeDefinition build(\n            ProcessingEnvironment processingEnv, DeclaredType type, Map<String, TypeDefinition> typeCache) {\n        TypeDefinition typeDefinition = new TypeDefinition(type.toString());\n        getDeclaredFields(type, FieldUtils::isEnumMemberField).stream()\n                .map(Element::getSimpleName)\n                .map(Name::toString)\n                .forEach(typeDefinition.getEnums()::add);\n        return typeDefinition;\n    }\n\n    @Override\n    public int getPriority() {\n        return MIN_PRIORITY - 2;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.DeclaredType;\n\nimport java.util.Map;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getNonStaticFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isClassType;\n\n/**\n * {@link TypeBuilder} for General Object\n *\n * @since 2.7.6\n */\npublic class GeneralTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder {\n\n    @Override\n    public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) {\n        return isClassType(type);\n    }\n\n    @Override\n    public TypeDefinition build(\n            ProcessingEnvironment processingEnv, DeclaredType type, Map<String, TypeDefinition> typeCache) {\n\n        String typeName = type.toString();\n\n        TypeElement typeElement = getType(processingEnv, typeName);\n\n        return buildProperties(processingEnv, typeElement, typeCache);\n    }\n\n    protected TypeDefinition buildProperties(\n            ProcessingEnvironment processingEnv, TypeElement type, Map<String, TypeDefinition> typeCache) {\n        TypeDefinition definition = new TypeDefinition(type.toString());\n        getNonStaticFields(type).forEach(field -> {\n            String fieldName = field.getSimpleName().toString();\n            TypeDefinition propertyType = TypeDefinitionBuilder.build(processingEnv, field, typeCache);\n            if (propertyType != null) {\n                typeCache.put(propertyType.getType(), propertyType);\n                definition.getProperties().put(fieldName, propertyType.getType());\n            }\n        });\n        return definition;\n    }\n\n    @Override\n    public int getPriority() {\n        return MIN_PRIORITY;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.DeclaredType;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.Elements;\nimport javax.lang.model.util.Types;\n\nimport java.util.Map;\nimport java.util.Objects;\n\n/**\n * {@link TypeBuilder} for Java {@link Map}\n *\n * @since 2.7.6\n */\npublic class MapTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder {\n\n    @Override\n    public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) {\n        Elements elements = processingEnv.getElementUtils();\n        TypeElement mapTypeElement = elements.getTypeElement(Map.class.getTypeName());\n        TypeMirror mapType = mapTypeElement.asType();\n        Types types = processingEnv.getTypeUtils();\n        TypeMirror erasedType = types.erasure(type);\n        return types.isAssignable(erasedType, mapType);\n    }\n\n    @Override\n    public TypeDefinition build(\n            ProcessingEnvironment processingEnv, DeclaredType type, Map<String, TypeDefinition> typeCache) {\n        TypeDefinition typeDefinition = new TypeDefinition(type.toString());\n        // Generic Type arguments\n        type.getTypeArguments().stream()\n                .map(typeArgument -> TypeDefinitionBuilder.build(\n                        processingEnv, typeArgument, typeCache)) // build the TypeDefinition from typeArgument\n                .filter(Objects::nonNull)\n                .map(TypeDefinition::getType)\n                .forEach(typeDefinition.getItems()::add); // Add into the declared TypeDefinition\n        return typeDefinition;\n    }\n\n    @Override\n    public int getPriority() {\n        return MIN_PRIORITY - 6;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/MethodDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.definition.model.MethodDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.ExecutableElement;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodName;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodParameterTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getReturnType;\n\n/**\n * A Builder class for {@link MethodDefinition}\n *\n * @see MethodDefinition\n * @since 2.7.6\n */\npublic interface MethodDefinitionBuilder {\n\n    static MethodDefinition build(\n            ProcessingEnvironment processingEnv, ExecutableElement method, Map<String, TypeDefinition> typeCache) {\n        MethodDefinition methodDefinition = new MethodDefinition();\n        methodDefinition.setName(getMethodName(method));\n        methodDefinition.setReturnType(getReturnType(method));\n        methodDefinition.setParameterTypes(getMethodParameterTypes(method));\n        methodDefinition.setParameters(getMethodParameters(processingEnv, method, typeCache));\n        return methodDefinition;\n    }\n\n    static List<TypeDefinition> getMethodParameters(\n            ProcessingEnvironment processingEnv, ExecutableElement method, Map<String, TypeDefinition> typeCache) {\n        return method.getParameters().stream()\n                .map(element -> TypeDefinitionBuilder.build(processingEnv, element, typeCache))\n                .collect(Collectors.toList());\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.type.PrimitiveType;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.util.Map;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isPrimitiveType;\n\n/**\n * {@link TypeBuilder} for Java {@link PrimitiveType primitive type}\n *\n * @since 2.7.6\n */\npublic class PrimitiveTypeDefinitionBuilder implements TypeBuilder<PrimitiveType> {\n\n    @Override\n    public boolean accept(ProcessingEnvironment processingEnv, TypeMirror type) {\n        return isPrimitiveType(type);\n    }\n\n    @Override\n    public TypeDefinition build(\n            ProcessingEnvironment processingEnv, PrimitiveType type, Map<String, TypeDefinition> typeCache) {\n        TypeDefinition typeDefinition = new TypeDefinition(type.toString());\n        return typeDefinition;\n    }\n\n    @Override\n    public int getPriority() {\n        return MIN_PRIORITY - 3;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getPublicNonStaticMethods;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResourceName;\n\n/**\n * A Builder for {@link ServiceDefinition}\n *\n * @see ServiceDefinition\n * @since 2.7.6\n */\npublic interface ServiceDefinitionBuilder {\n\n    static ServiceDefinition build(ProcessingEnvironment processingEnv, TypeElement type) {\n        ServiceDefinition serviceDefinition = new ServiceDefinition();\n        serviceDefinition.setCanonicalName(type.toString());\n        serviceDefinition.setCodeSource(getResourceName(type.toString()));\n\n        Map<String, TypeDefinition> types = new HashMap<>();\n\n        // Get all super types and interface excluding the specified type\n        // and then the result will be added into ServiceDefinition#getTypes()\n        getHierarchicalTypes(type.asType(), Object.class)\n                .forEach(t -> TypeDefinitionBuilder.build(processingEnv, t, types));\n\n        // Get all declared methods that will be added into ServiceDefinition#getMethods()\n        getPublicNonStaticMethods(type, Object.class).stream()\n                .map(method -> MethodDefinitionBuilder.build(processingEnv, method, types))\n                .forEach(serviceDefinition.getMethods()::add);\n\n        serviceDefinition.setTypes(new ArrayList<>(types.values()));\n\n        return serviceDefinition;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.util.TypeUtils;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.type.DeclaredType;\n\nimport java.util.Map;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSimpleType;\n\n/**\n * {@link TypeBuilder} for {@link TypeUtils#SIMPLE_TYPES Java Simple Type}\n *\n * @since 2.7.6\n */\npublic class SimpleTypeDefinitionBuilder implements DeclaredTypeDefinitionBuilder {\n\n    @Override\n    public boolean accept(ProcessingEnvironment processingEnv, DeclaredType type) {\n        return isSimpleType(type);\n    }\n\n    @Override\n    public TypeDefinition build(\n            ProcessingEnvironment processingEnv, DeclaredType type, Map<String, TypeDefinition> typeCache) {\n        TypeDefinition td = new TypeDefinition(type.toString());\n        return td;\n    }\n\n    @Override\n    public int getPriority() {\n        return MIN_PRIORITY - 1;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/TypeBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.util.Map;\n\n@SPI\npublic interface TypeBuilder<T extends TypeMirror> extends Prioritized {\n\n    /**\n     * Test the specified {@link TypeMirror type} is accepted or not\n     *\n     * @param processingEnv {@link ProcessingEnvironment}\n     * @param type          {@link TypeMirror type}\n     * @return <code>true</code> if accepted\n     */\n    boolean accept(ProcessingEnvironment processingEnv, TypeMirror type);\n\n    /**\n     * Build the instance of {@link TypeDefinition}\n     *\n     * @param processingEnv  {@link ProcessingEnvironment}\n     * @param type           {@link T type}\n     * @return an instance of {@link TypeDefinition}\n     */\n    TypeDefinition build(ProcessingEnvironment processingEnv, T type, Map<String, TypeDefinition> typeCache);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/builder/TypeDefinitionBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.util.Map;\n\n/**\n * A class builds the instance of {@link TypeDefinition}\n *\n * @since 2.7.6\n */\npublic interface TypeDefinitionBuilder<T extends TypeMirror> extends Prioritized {\n\n    /**\n     * Build the instance of {@link TypeDefinition} from the specified {@link Element element}\n     *\n     * @param processingEnv {@link ProcessingEnvironment}\n     * @param element       {@link Element source element}\n     * @return non-null\n     */\n    static TypeDefinition build(\n            ProcessingEnvironment processingEnv, Element element, Map<String, TypeDefinition> typeCache) {\n        TypeDefinition typeDefinition = build(processingEnv, element.asType(), typeCache);\n        // Comment this code for the compatibility\n        // typeDefinition.set$ref(element.toString());\n        return typeDefinition;\n    }\n\n    /**\n     * Build the instance of {@link TypeDefinition} from the specified {@link TypeMirror type}\n     *\n     * @param processingEnv {@link ProcessingEnvironment}\n     * @param type          {@link TypeMirror type}\n     * @return non-null\n     */\n    static TypeDefinition build(\n            ProcessingEnvironment processingEnv, TypeMirror type, Map<String, TypeDefinition> typeCache) {\n        // Build by all instances of TypeDefinitionBuilder that were loaded By Java SPI\n\n        TypeDefinition typeDefinition =\n                ApplicationModel.defaultModel()\n                        .getExtensionLoader(TypeBuilder.class)\n                        .getSupportedExtensionInstances()\n                        .stream()\n                        //        load(TypeDefinitionBuilder.class, TypeDefinitionBuilder.class.getClassLoader())\n                        .filter(builder -> builder.accept(processingEnv, type))\n                        .findFirst()\n                        .map(builder -> {\n                            return builder.build(processingEnv, type, typeCache);\n                            // typeDefinition.setTypeBuilderName(builder.getClass().getName());\n                        })\n                        .orElse(null);\n\n        if (typeDefinition != null) {\n            typeCache.put(typeDefinition.getType(), typeDefinition);\n        }\n        return typeDefinition;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.AnnotatedConstruct;\nimport javax.lang.model.element.AnnotationMirror;\nimport javax.lang.model.element.AnnotationValue;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.type.ArrayType;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Type;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport static java.lang.Enum.valueOf;\nimport static java.util.Collections.emptyList;\nimport static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY;\nimport static org.apache.dubbo.common.function.Streams.filterAll;\nimport static org.apache.dubbo.common.function.Streams.filterFirst;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSameType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isTypeElement;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofTypeElement;\n\n/**\n * The utilities class for annotation in the package \"javax.lang.model.*\"\n *\n * @since 2.7.6\n */\npublic interface AnnotationUtils {\n\n    static AnnotationMirror getAnnotation(\n            AnnotatedConstruct annotatedConstruct, Class<? extends Annotation> annotationClass) {\n        return annotationClass == null ? null : getAnnotation(annotatedConstruct, annotationClass.getTypeName());\n    }\n\n    static AnnotationMirror getAnnotation(AnnotatedConstruct annotatedConstruct, CharSequence annotationClassName) {\n        List<AnnotationMirror> annotations = getAnnotations(annotatedConstruct, annotationClassName);\n        return annotations.isEmpty() ? null : annotations.get(0);\n    }\n\n    static List<AnnotationMirror> getAnnotations(\n            AnnotatedConstruct annotatedConstruct, Class<? extends Annotation> annotationClass) {\n        return annotationClass == null\n                ? emptyList()\n                : getAnnotations(annotatedConstruct, annotationClass.getTypeName());\n    }\n\n    static List<AnnotationMirror> getAnnotations(\n            AnnotatedConstruct annotatedConstruct, CharSequence annotationClassName) {\n        return getAnnotations(\n                annotatedConstruct, annotation -> isSameType(annotation.getAnnotationType(), annotationClassName));\n    }\n\n    static List<AnnotationMirror> getAnnotations(AnnotatedConstruct annotatedConstruct) {\n        return getAnnotations(annotatedConstruct, EMPTY_ARRAY);\n    }\n\n    static List<AnnotationMirror> getAnnotations(\n            AnnotatedConstruct annotatedConstruct, Predicate<AnnotationMirror>... annotationFilters) {\n\n        AnnotatedConstruct actualAnnotatedConstruct = annotatedConstruct;\n\n        if (annotatedConstruct instanceof TypeMirror) {\n            actualAnnotatedConstruct = ofTypeElement((TypeMirror) actualAnnotatedConstruct);\n        }\n\n        return actualAnnotatedConstruct == null\n                ? emptyList()\n                : filterAll(\n                        (List<AnnotationMirror>) actualAnnotatedConstruct.getAnnotationMirrors(), annotationFilters);\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(TypeMirror type) {\n        return getAllAnnotations(ofTypeElement(type));\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(Element element) {\n        return getAllAnnotations(element, EMPTY_ARRAY);\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(TypeMirror type, Class<? extends Annotation> annotationClass) {\n        return getAllAnnotations(ofTypeElement(type), annotationClass);\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(Element element, Class<? extends Annotation> annotationClass) {\n        return element == null || annotationClass == null\n                ? emptyList()\n                : getAllAnnotations(element, annotationClass.getTypeName());\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(TypeMirror type, CharSequence annotationClassName) {\n        return getAllAnnotations(ofTypeElement(type), annotationClassName);\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(Element element, CharSequence annotationClassName) {\n        return getAllAnnotations(\n                element, annotation -> isSameType(annotation.getAnnotationType(), annotationClassName));\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(TypeMirror type, Predicate<AnnotationMirror>... annotationFilters) {\n        return getAllAnnotations(ofTypeElement(type), annotationFilters);\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(Element element, Predicate<AnnotationMirror>... annotationFilters) {\n\n        List<AnnotationMirror> allAnnotations = isTypeElement(element)\n                ? getHierarchicalTypes(ofTypeElement(element)).stream()\n                        .map(AnnotationUtils::getAnnotations)\n                        .flatMap(Collection::stream)\n                        .collect(Collectors.toList())\n                : element == null ? emptyList() : (List<AnnotationMirror>) element.getAnnotationMirrors();\n\n        return filterAll(allAnnotations, annotationFilters);\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(ProcessingEnvironment processingEnv, Type annotatedType) {\n        return getAllAnnotations(processingEnv, annotatedType, EMPTY_ARRAY);\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(\n            ProcessingEnvironment processingEnv, Type annotatedType, Predicate<AnnotationMirror>... annotationFilters) {\n        return annotatedType == null\n                ? emptyList()\n                : getAllAnnotations(processingEnv, annotatedType.getTypeName(), annotationFilters);\n    }\n\n    static List<AnnotationMirror> getAllAnnotations(\n            ProcessingEnvironment processingEnv,\n            CharSequence annotatedTypeName,\n            Predicate<AnnotationMirror>... annotationFilters) {\n        return getAllAnnotations(getType(processingEnv, annotatedTypeName), annotationFilters);\n    }\n\n    static AnnotationMirror findAnnotation(TypeMirror type, Class<? extends Annotation> annotationClass) {\n        return annotationClass == null ? null : findAnnotation(type, annotationClass.getTypeName());\n    }\n\n    static AnnotationMirror findAnnotation(TypeMirror type, CharSequence annotationClassName) {\n        return findAnnotation(ofTypeElement(type), annotationClassName);\n    }\n\n    static AnnotationMirror findAnnotation(Element element, Class<? extends Annotation> annotationClass) {\n        return annotationClass == null ? null : findAnnotation(element, annotationClass.getTypeName());\n    }\n\n    static AnnotationMirror findAnnotation(Element element, CharSequence annotationClassName) {\n        return filterFirst(getAllAnnotations(\n                element, annotation -> isSameType(annotation.getAnnotationType(), annotationClassName)));\n    }\n\n    static AnnotationMirror findMetaAnnotation(Element annotatedConstruct, CharSequence metaAnnotationClassName) {\n        return annotatedConstruct == null\n                ? null\n                : getAnnotations(annotatedConstruct).stream()\n                        .map(annotation -> findAnnotation(annotation.getAnnotationType(), metaAnnotationClassName))\n                        .filter(Objects::nonNull)\n                        .findFirst()\n                        .orElse(null);\n    }\n\n    static boolean isAnnotationPresent(Element element, CharSequence annotationClassName) {\n        return findAnnotation(element, annotationClassName) != null\n                || findMetaAnnotation(element, annotationClassName) != null;\n    }\n\n    static <T> T getAttribute(AnnotationMirror annotation, String attributeName) {\n        return annotation == null ? null : getAttribute(annotation.getElementValues(), attributeName);\n    }\n\n    static <T> T getAttribute(\n            Map<? extends ExecutableElement, ? extends AnnotationValue> attributesMap, String attributeName) {\n        T annotationValue = null;\n        for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : attributesMap.entrySet()) {\n            ExecutableElement attributeMethod = entry.getKey();\n            if (Objects.equals(attributeName, attributeMethod.getSimpleName().toString())) {\n                TypeMirror attributeType = attributeMethod.getReturnType();\n                AnnotationValue value = entry.getValue();\n                if (attributeType instanceof ArrayType) { // array-typed attribute values\n                    ArrayType arrayType = (ArrayType) attributeType;\n                    String componentType = arrayType.getComponentType().toString();\n                    ClassLoader classLoader = AnnotationUtils.class.getClassLoader();\n                    List<AnnotationValue> values = (List<AnnotationValue>) value.getValue();\n                    int size = values.size();\n                    try {\n                        Class componentClass = classLoader.loadClass(componentType);\n                        boolean isEnum = componentClass.isEnum();\n                        Object array = Array.newInstance(componentClass, values.size());\n                        for (int i = 0; i < size; i++) {\n                            Object element = values.get(i).getValue();\n                            if (isEnum) {\n                                element = valueOf(componentClass, element.toString());\n                            }\n                            Array.set(array, i, element);\n                        }\n                        annotationValue = (T) array;\n                    } catch (ClassNotFoundException e) {\n                        throw new RuntimeException(e);\n                    }\n                } else {\n                    annotationValue = (T) value.getValue();\n                }\n                break;\n            }\n        }\n        return annotationValue;\n    }\n\n    static <T> T getValue(AnnotationMirror annotation) {\n        return (T) getAttribute(annotation, \"value\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ExecutableElementComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.common.utils.CharSequenceComparator;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.Comparator;\nimport java.util.List;\n\n/**\n * The Comparator class for {@link ExecutableElement}, the comparison rule :\n * <ol>\n *     <li>Comparing to two {@link ExecutableElement#getSimpleName() element names} {@link String#compareTo(String) lexicographically}.\n *     If equals, go to step 2</li>\n *     <li>Comparing to the count of two parameters. If equals, go to step 3</li>\n *     <li>Comparing to the type names of parameters {@link String#compareTo(String) lexicographically}</li>\n * </ol>\n *\n * @since 2.7.6\n */\npublic class ExecutableElementComparator implements Comparator<ExecutableElement> {\n\n    public static final ExecutableElementComparator INSTANCE = new ExecutableElementComparator();\n\n    private ExecutableElementComparator() {}\n\n    @Override\n    public int compare(ExecutableElement e1, ExecutableElement e2) {\n\n        if (e1.equals(e2)) {\n            return 0;\n        }\n\n        // Step 1\n        int value = CharSequenceComparator.INSTANCE.compare(e1.getSimpleName(), e2.getSimpleName());\n\n        if (value == 0) { // Step 2\n\n            List<? extends VariableElement> ps1 = e1.getParameters();\n            List<? extends VariableElement> ps2 = e1.getParameters();\n\n            value = ps1.size() - ps2.size();\n\n            if (value == 0) { // Step 3\n                for (int i = 0; i < ps1.size(); i++) {\n                    value = CharSequenceComparator.INSTANCE.compare(\n                            ps1.get(i).getSimpleName(), ps2.get(i).getSimpleName());\n                    if (value != 0) {\n                        break;\n                    }\n                }\n            }\n        }\n        return Integer.compare(value, 0);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport static java.util.Collections.emptyList;\nimport static javax.lang.model.element.ElementKind.ENUM_CONSTANT;\nimport static javax.lang.model.element.ElementKind.FIELD;\nimport static javax.lang.model.element.Modifier.STATIC;\nimport static javax.lang.model.util.ElementFilter.fieldsIn;\nimport static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY;\nimport static org.apache.dubbo.common.function.Streams.filterAll;\nimport static org.apache.dubbo.common.function.Streams.filterFirst;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getDeclaredMembers;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.hasModifiers;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.matches;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isEnumType;\n\n/**\n * The utilities class for the field in the package \"javax.lang.model.\"\n *\n * @since 2.7.6\n */\npublic interface FieldUtils {\n\n    static List<VariableElement> getDeclaredFields(Element element, Predicate<VariableElement>... fieldFilters) {\n        return element == null ? emptyList() : getDeclaredFields(element.asType(), fieldFilters);\n    }\n\n    static List<VariableElement> getDeclaredFields(Element element) {\n        return getDeclaredFields(element, EMPTY_ARRAY);\n    }\n\n    static List<VariableElement> getDeclaredFields(TypeMirror type, Predicate<VariableElement>... fieldFilters) {\n        return filterAll(fieldsIn(getDeclaredMembers(type)), fieldFilters);\n    }\n\n    static List<VariableElement> getDeclaredFields(TypeMirror type) {\n        return getDeclaredFields(type, EMPTY_ARRAY);\n    }\n\n    static List<VariableElement> getAllDeclaredFields(Element element, Predicate<VariableElement>... fieldFilters) {\n        return element == null ? emptyList() : getAllDeclaredFields(element.asType(), fieldFilters);\n    }\n\n    static List<VariableElement> getAllDeclaredFields(Element element) {\n        return getAllDeclaredFields(element, EMPTY_ARRAY);\n    }\n\n    static List<VariableElement> getAllDeclaredFields(TypeMirror type, Predicate<VariableElement>... fieldFilters) {\n        return getHierarchicalTypes(type).stream()\n                .map(t -> getDeclaredFields(t, fieldFilters))\n                .flatMap(Collection::stream)\n                .collect(Collectors.toList());\n    }\n\n    static List<VariableElement> getAllDeclaredFields(TypeMirror type) {\n        return getAllDeclaredFields(type, EMPTY_ARRAY);\n    }\n\n    static VariableElement getDeclaredField(Element element, String fieldName) {\n        return element == null ? null : getDeclaredField(element.asType(), fieldName);\n    }\n\n    static VariableElement getDeclaredField(TypeMirror type, String fieldName) {\n        return filterFirst(getDeclaredFields(\n                type, field -> fieldName.equals(field.getSimpleName().toString())));\n    }\n\n    static VariableElement findField(Element element, String fieldName) {\n        return element == null ? null : findField(element.asType(), fieldName);\n    }\n\n    static VariableElement findField(TypeMirror type, String fieldName) {\n        return filterFirst(getAllDeclaredFields(type, field -> equals(field, fieldName)));\n    }\n\n    /**\n     * is Enum's member field or not\n     *\n     * @param field {@link VariableElement} must be public static final fields\n     * @return if field is public static final, return <code>true</code>, or <code>false</code>\n     */\n    static boolean isEnumMemberField(VariableElement field) {\n        if (field == null || !isEnumType(field.getEnclosingElement())) {\n            return false;\n        }\n        return ENUM_CONSTANT.equals(field.getKind());\n    }\n\n    static boolean isNonStaticField(VariableElement field) {\n        return isField(field) && !hasModifiers(field, STATIC);\n    }\n\n    static boolean isField(VariableElement field) {\n        return matches(field, FIELD) || isEnumMemberField(field);\n    }\n\n    static boolean isField(VariableElement field, Modifier... modifiers) {\n        return isField(field) && hasModifiers(field, modifiers);\n    }\n\n    static List<VariableElement> getNonStaticFields(TypeMirror type) {\n        return getDeclaredFields(type, FieldUtils::isNonStaticField);\n    }\n\n    static List<VariableElement> getNonStaticFields(Element element) {\n        return element == null ? emptyList() : getNonStaticFields(element.asType());\n    }\n\n    static List<VariableElement> getAllNonStaticFields(TypeMirror type) {\n        return getAllDeclaredFields(type, FieldUtils::isNonStaticField);\n    }\n\n    static List<VariableElement> getAllNonStaticFields(Element element) {\n        return element == null ? emptyList() : getAllNonStaticFields(element.asType());\n    }\n\n    static boolean equals(VariableElement field, CharSequence fieldName) {\n        return field != null\n                && fieldName != null\n                && field.getSimpleName().toString().equals(fieldName.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport static java.lang.String.format;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METADATA_PROCESSOR;\n\n/**\n * Logger Utils\n *\n * @since 2.7.6\n */\npublic interface LoggerUtils {\n\n    ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(\"dubbo-metadata-processor\");\n\n    static void info(String format, Object... args) {\n        if (LOGGER.isInfoEnabled()) {\n            LOGGER.info(format(format, args));\n        }\n    }\n\n    static void warn(String format, Object... args) {\n        if (LOGGER.isWarnEnabled()) {\n            LOGGER.warn(COMMON_METADATA_PROCESSOR, \"\", \"\", format(format, args));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ElementKind;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport static java.util.Collections.emptyList;\nimport static javax.lang.model.element.Modifier.PUBLIC;\nimport static javax.lang.model.element.Modifier.STATIC;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofTypeElement;\n\n/**\n * The utilities class for the members in the package \"javax.lang.model.\", such as \"field\", \"method\", \"constructor\"\n *\n * @since 2.7.6\n */\npublic interface MemberUtils {\n\n    static boolean matches(Element member, ElementKind kind) {\n        return member == null || kind == null ? false : kind.equals(member.getKind());\n    }\n\n    static boolean isPublicNonStatic(Element member) {\n        return hasModifiers(member, PUBLIC) && !hasModifiers(member, STATIC);\n    }\n\n    static boolean hasModifiers(Element member, Modifier... modifiers) {\n        if (member == null || modifiers == null) {\n            return false;\n        }\n        Set<Modifier> actualModifiers = member.getModifiers();\n        for (Modifier modifier : modifiers) {\n            if (!actualModifiers.contains(modifier)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    static List<? extends Element> getDeclaredMembers(TypeMirror type) {\n        TypeElement element = ofTypeElement(type);\n        return element == null ? emptyList() : element.getEnclosedElements();\n    }\n\n    static List<? extends Element> getAllDeclaredMembers(TypeMirror type) {\n        return getHierarchicalTypes(type).stream()\n                .map(MemberUtils::getDeclaredMembers)\n                .flatMap(Collection::stream)\n                .collect(Collectors.toList());\n    }\n\n    static boolean matchParameterTypes(List<? extends VariableElement> parameters, CharSequence... parameterTypes) {\n\n        int size = parameters.size();\n\n        if (size != parameterTypes.length) {\n            return false;\n        }\n\n        for (int i = 0; i < size; i++) {\n            VariableElement parameter = parameters.get(i);\n            if (!Objects.equals(parameter.asType().toString(), parameterTypes[i])) {\n                return false;\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.Elements;\n\nimport java.lang.reflect.Type;\nimport java.util.Collection;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport static java.util.Arrays.asList;\nimport static java.util.Collections.emptyList;\nimport static javax.lang.model.element.ElementKind.METHOD;\nimport static javax.lang.model.util.ElementFilter.methodsIn;\nimport static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY;\nimport static org.apache.dubbo.common.function.Streams.filter;\nimport static org.apache.dubbo.common.function.Streams.filterAll;\nimport static org.apache.dubbo.common.function.Streams.filterFirst;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getDeclaredMembers;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.isPublicNonStatic;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.matchParameterTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredType;\n\n/**\n * The utilities class for method in the package \"javax.lang.model.\"\n *\n * @since 2.7.6\n */\npublic interface MethodUtils {\n\n    static List<ExecutableElement> getDeclaredMethods(TypeElement type, Predicate<ExecutableElement>... methodFilters) {\n        return type == null ? emptyList() : getDeclaredMethods(type.asType(), methodFilters);\n    }\n\n    static List<ExecutableElement> getDeclaredMethods(TypeMirror type, Predicate<ExecutableElement>... methodFilters) {\n        return filterAll(methodsIn(getDeclaredMembers(type)), methodFilters);\n    }\n\n    static List<ExecutableElement> getAllDeclaredMethods(\n            TypeElement type, Predicate<ExecutableElement>... methodFilters) {\n        return type == null ? emptyList() : getAllDeclaredMethods(type.asType(), methodFilters);\n    }\n\n    static List<ExecutableElement> getAllDeclaredMethods(TypeElement type) {\n        return getAllDeclaredMethods(type, EMPTY_ARRAY);\n    }\n\n    static List<ExecutableElement> getAllDeclaredMethods(\n            TypeMirror type, Predicate<ExecutableElement>... methodFilters) {\n        return getHierarchicalTypes(type).stream()\n                .map(t -> getDeclaredMethods(t, methodFilters))\n                .flatMap(Collection::stream)\n                .collect(Collectors.toList());\n    }\n\n    static List<ExecutableElement> getAllDeclaredMethods(TypeMirror type) {\n        return getAllDeclaredMethods(type, EMPTY_ARRAY);\n    }\n\n    static List<ExecutableElement> getAllDeclaredMethods(TypeElement type, Type... excludedTypes) {\n        return type == null ? emptyList() : getAllDeclaredMethods(type.asType(), excludedTypes);\n    }\n\n    static List<ExecutableElement> getAllDeclaredMethods(TypeMirror type, Type... excludedTypes) {\n        return getHierarchicalTypes(type, excludedTypes).stream()\n                .map(t -> getDeclaredMethods(t))\n                .flatMap(Collection::stream)\n                .collect(Collectors.toList());\n    }\n\n    static List<ExecutableElement> getPublicNonStaticMethods(TypeElement type, Type... excludedTypes) {\n        return getPublicNonStaticMethods(ofDeclaredType(type), excludedTypes);\n    }\n\n    static List<ExecutableElement> getPublicNonStaticMethods(TypeMirror type, Type... excludedTypes) {\n        return filter(getAllDeclaredMethods(type, excludedTypes), MethodUtils::isPublicNonStaticMethod);\n    }\n\n    static boolean isMethod(ExecutableElement method) {\n        return method != null && METHOD.equals(method.getKind());\n    }\n\n    static boolean isPublicNonStaticMethod(ExecutableElement method) {\n        return isMethod(method) && isPublicNonStatic(method);\n    }\n\n    static ExecutableElement findMethod(\n            TypeElement type, String methodName, Type oneParameterType, Type... otherParameterTypes) {\n        return type == null ? null : findMethod(type.asType(), methodName, oneParameterType, otherParameterTypes);\n    }\n\n    static ExecutableElement findMethod(\n            TypeMirror type, String methodName, Type oneParameterType, Type... otherParameterTypes) {\n        List<Type> parameterTypes = new LinkedList<>();\n        parameterTypes.add(oneParameterType);\n        parameterTypes.addAll(asList(otherParameterTypes));\n        return findMethod(\n                type, methodName, parameterTypes.stream().map(Type::getTypeName).toArray(String[]::new));\n    }\n\n    static ExecutableElement findMethod(TypeElement type, String methodName, CharSequence... parameterTypes) {\n        return type == null ? null : findMethod(type.asType(), methodName, parameterTypes);\n    }\n\n    static ExecutableElement findMethod(TypeMirror type, String methodName, CharSequence... parameterTypes) {\n        return filterFirst(\n                getAllDeclaredMethods(type),\n                method -> methodName.equals(method.getSimpleName().toString()),\n                method -> matchParameterTypes(method.getParameters(), parameterTypes));\n    }\n\n    static ExecutableElement getOverrideMethod(\n            ProcessingEnvironment processingEnv, TypeElement type, ExecutableElement declaringMethod) {\n        Elements elements = processingEnv.getElementUtils();\n        return filterFirst(getAllDeclaredMethods(type), method -> elements.overrides(method, declaringMethod, type));\n    }\n\n    static String getMethodName(ExecutableElement method) {\n        return method == null ? null : method.getSimpleName().toString();\n    }\n\n    static String getReturnType(ExecutableElement method) {\n        return method == null ? null : TypeUtils.toString(method.getReturnType());\n    }\n\n    static String[] getMethodParameterTypes(ExecutableElement method) {\n        return method == null\n                ? new String[0]\n                : method.getParameters().stream()\n                        .map(VariableElement::asType)\n                        .map(TypeUtils::toString)\n                        .toArray(String[]::new);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport javax.lang.model.element.AnnotationMirror;\nimport javax.lang.model.element.TypeElement;\n\nimport java.util.LinkedHashSet;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport static java.lang.String.valueOf;\nimport static java.util.Arrays.asList;\nimport static java.util.Collections.unmodifiableSet;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent;\n\n/**\n * The utilities class for @Service annotation\n *\n * @since 2.7.6\n */\npublic interface ServiceAnnotationUtils {\n\n    /**\n     * The class name of @Service\n     *\n     * @deprecated Recommend {@link #DUBBO_SERVICE_ANNOTATION_TYPE}\n     */\n    @Deprecated\n    String SERVICE_ANNOTATION_TYPE = \"org.apache.dubbo.config.annotation.Service\";\n\n    /**\n     * The class name of the legacy @Service\n     *\n     * @deprecated Recommend {@link #DUBBO_SERVICE_ANNOTATION_TYPE}\n     */\n    @Deprecated\n    String LEGACY_SERVICE_ANNOTATION_TYPE = \"com.alibaba.dubbo.config.annotation.Service\";\n\n    /**\n     * The class name of @DubboService\n     *\n     * @since 2.7.9\n     */\n    String DUBBO_SERVICE_ANNOTATION_TYPE = \"org.apache.dubbo.config.annotation.DubboService\";\n\n    /**\n     * the attribute name of @Service.interfaceClass()\n     */\n    String INTERFACE_CLASS_ATTRIBUTE_NAME = \"interfaceClass\";\n\n    /**\n     * the attribute name of @Service.interfaceName()\n     */\n    String INTERFACE_NAME_ATTRIBUTE_NAME = \"interfaceName\";\n\n    /**\n     * the attribute name of @Service.group()\n     */\n    String GROUP_ATTRIBUTE_NAME = \"group\";\n\n    /**\n     * the attribute name of @Service.version()\n     */\n    String VERSION_ATTRIBUTE_NAME = \"version\";\n\n    Set<String> SUPPORTED_ANNOTATION_TYPES = unmodifiableSet(new LinkedHashSet<>(\n            asList(DUBBO_SERVICE_ANNOTATION_TYPE, SERVICE_ANNOTATION_TYPE, LEGACY_SERVICE_ANNOTATION_TYPE)));\n\n    static boolean isServiceAnnotationPresent(TypeElement annotatedType) {\n        return SUPPORTED_ANNOTATION_TYPES.stream()\n                .filter(type -> isAnnotationPresent(annotatedType, type))\n                .findFirst()\n                .isPresent();\n    }\n\n    static AnnotationMirror getAnnotation(TypeElement annotatedClass) {\n        return getAnnotation(annotatedClass.getAnnotationMirrors());\n    }\n\n    static AnnotationMirror getAnnotation(Iterable<? extends AnnotationMirror> annotationMirrors) {\n        AnnotationMirror matchedAnnotationMirror = null;\n\n        MAIN:\n        for (String supportedAnnotationType : SUPPORTED_ANNOTATION_TYPES) { // Prioritized\n            for (AnnotationMirror annotationMirror : annotationMirrors) {\n                String annotationType = annotationMirror.getAnnotationType().toString();\n                if (Objects.equals(supportedAnnotationType, annotationType)) {\n                    matchedAnnotationMirror = annotationMirror;\n                    break MAIN;\n                }\n            }\n        }\n\n        if (matchedAnnotationMirror == null) {\n            throw new IllegalArgumentException(\n                    \"The annotated element must be annotated any of \" + SUPPORTED_ANNOTATION_TYPES);\n        }\n\n        return matchedAnnotationMirror;\n    }\n\n    static String resolveServiceInterfaceName(TypeElement annotatedClass, AnnotationMirror serviceAnnotation) {\n        Object interfaceClass = getAttribute(serviceAnnotation, INTERFACE_CLASS_ATTRIBUTE_NAME);\n\n        if (interfaceClass == null) { // try to find the \"interfaceName\" attribute\n            interfaceClass = getAttribute(serviceAnnotation, INTERFACE_NAME_ATTRIBUTE_NAME);\n        }\n\n        if (interfaceClass == null) {\n            // last, get the interface class from first one\n            interfaceClass = ((TypeElement) annotatedClass).getInterfaces().get(0);\n        }\n\n        return valueOf(interfaceClass);\n    }\n\n    static String getGroup(AnnotationMirror serviceAnnotation) {\n        return getAttribute(serviceAnnotation, GROUP_ATTRIBUTE_NAME);\n    }\n\n    static String getVersion(AnnotationMirror serviceAnnotation) {\n        return getAttribute(serviceAnnotation, VERSION_ATTRIBUTE_NAME);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.TypeParameterElement;\nimport javax.lang.model.type.DeclaredType;\nimport javax.lang.model.type.TypeKind;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.Elements;\nimport javax.tools.FileObject;\nimport javax.tools.StandardLocation;\n\nimport java.io.IOException;\nimport java.lang.reflect.Type;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\nimport static java.lang.String.valueOf;\nimport static java.util.Arrays.asList;\nimport static java.util.Collections.emptyList;\nimport static java.util.Collections.emptySet;\nimport static java.util.stream.Collectors.toSet;\nimport static java.util.stream.Stream.of;\nimport static java.util.stream.StreamSupport.stream;\nimport static javax.lang.model.element.ElementKind.ANNOTATION_TYPE;\nimport static javax.lang.model.element.ElementKind.CLASS;\nimport static javax.lang.model.element.ElementKind.ENUM;\nimport static javax.lang.model.element.ElementKind.INTERFACE;\nimport static org.apache.dubbo.common.function.Predicates.EMPTY_ARRAY;\nimport static org.apache.dubbo.common.function.Streams.filterAll;\nimport static org.apache.dubbo.common.function.Streams.filterFirst;\nimport static org.apache.dubbo.common.utils.MethodUtils.invokeMethod;\n\n/**\n * The utilities class for type in the package \"javax.lang.model.*\"\n *\n * @since 2.7.6\n */\npublic interface TypeUtils {\n\n    List<String> SIMPLE_TYPES =\n            asList(ClassUtils.SIMPLE_TYPES.stream().map(Class::getName).toArray(String[]::new));\n\n    static boolean isSimpleType(Element element) {\n        return element != null && isSimpleType(element.asType());\n    }\n\n    static boolean isSimpleType(TypeMirror type) {\n        return type != null && SIMPLE_TYPES.contains(type.toString());\n    }\n\n    static boolean isSameType(TypeMirror type, CharSequence typeName) {\n        if (type == null || typeName == null) {\n            return false;\n        }\n        return Objects.equals(valueOf(type), valueOf(typeName));\n    }\n\n    static boolean isSameType(TypeMirror typeMirror, Type type) {\n        return type != null && isSameType(typeMirror, type.getTypeName());\n    }\n\n    static boolean isArrayType(TypeMirror type) {\n        return type != null && TypeKind.ARRAY.equals(type.getKind());\n    }\n\n    static boolean isArrayType(Element element) {\n        return element != null && isArrayType(element.asType());\n    }\n\n    static boolean isEnumType(TypeMirror type) {\n        DeclaredType declaredType = ofDeclaredType(type);\n        return declaredType != null && ENUM.equals(declaredType.asElement().getKind());\n    }\n\n    static boolean isEnumType(Element element) {\n        return element != null && isEnumType(element.asType());\n    }\n\n    static boolean isClassType(TypeMirror type) {\n        DeclaredType declaredType = ofDeclaredType(type);\n        return declaredType != null && isClassType(declaredType.asElement());\n    }\n\n    static boolean isClassType(Element element) {\n        return element != null && CLASS.equals(element.getKind());\n    }\n\n    static boolean isPrimitiveType(TypeMirror type) {\n        return type != null && type.getKind().isPrimitive();\n    }\n\n    static boolean isPrimitiveType(Element element) {\n        return element != null && isPrimitiveType(element.asType());\n    }\n\n    static boolean isInterfaceType(TypeMirror type) {\n        DeclaredType declaredType = ofDeclaredType(type);\n        return declaredType != null && isInterfaceType(declaredType.asElement());\n    }\n\n    static boolean isInterfaceType(Element element) {\n        return element != null && INTERFACE.equals(element.getKind());\n    }\n\n    static boolean isAnnotationType(TypeMirror type) {\n        DeclaredType declaredType = ofDeclaredType(type);\n        return declaredType != null && isAnnotationType(declaredType.asElement());\n    }\n\n    static boolean isAnnotationType(Element element) {\n        return element != null && ANNOTATION_TYPE.equals(element.getKind());\n    }\n\n    static Set<TypeElement> getHierarchicalTypes(TypeElement type) {\n        return getHierarchicalTypes(type, true, true, true);\n    }\n\n    static Set<DeclaredType> getHierarchicalTypes(TypeMirror type) {\n        return getHierarchicalTypes(type, EMPTY_ARRAY);\n    }\n\n    static Set<DeclaredType> getHierarchicalTypes(TypeMirror type, Predicate<DeclaredType>... typeFilters) {\n        return filterAll(ofDeclaredTypes(getHierarchicalTypes(ofTypeElement(type))), typeFilters);\n    }\n\n    static Set<DeclaredType> getHierarchicalTypes(TypeMirror type, Type... excludedTypes) {\n        return getHierarchicalTypes(\n                type, of(excludedTypes).map(Type::getTypeName).toArray(String[]::new));\n    }\n\n    static Set<DeclaredType> getHierarchicalTypes(TypeMirror type, CharSequence... excludedTypeNames) {\n        Set<String> typeNames =\n                of(excludedTypeNames).map(CharSequence::toString).collect(toSet());\n        return getHierarchicalTypes(type, t -> !typeNames.contains(t.toString()));\n    }\n\n    static Set<TypeElement> getHierarchicalTypes(\n            TypeElement type,\n            boolean includeSelf,\n            boolean includeSuperTypes,\n            boolean includeSuperInterfaces,\n            Predicate<TypeElement>... typeFilters) {\n\n        if (type == null) {\n            return emptySet();\n        }\n\n        Set<TypeElement> hierarchicalTypes = new LinkedHashSet<>();\n\n        if (includeSelf) {\n            hierarchicalTypes.add(type);\n        }\n\n        if (includeSuperTypes) {\n            hierarchicalTypes.addAll(getAllSuperTypes(type));\n        }\n\n        if (includeSuperInterfaces) {\n            hierarchicalTypes.addAll(getAllInterfaces(type));\n        }\n\n        return filterAll(hierarchicalTypes, typeFilters);\n    }\n\n    static Set<DeclaredType> getHierarchicalTypes(\n            TypeMirror type, boolean includeSelf, boolean includeSuperTypes, boolean includeSuperInterfaces) {\n        return ofDeclaredTypes(\n                getHierarchicalTypes(ofTypeElement(type), includeSelf, includeSuperTypes, includeSuperInterfaces));\n    }\n\n    static List<TypeMirror> getInterfaces(TypeElement type, Predicate<TypeMirror>... interfaceFilters) {\n        return type == null\n                ? emptyList()\n                : filterAll((List<TypeMirror>) ofTypeElement(type).getInterfaces(), interfaceFilters);\n    }\n\n    static List<TypeMirror> getInterfaces(TypeMirror type, Predicate<TypeMirror>... interfaceFilters) {\n        return getInterfaces(ofTypeElement(type), interfaceFilters);\n    }\n\n    static Set<TypeElement> getAllInterfaces(TypeElement type, Predicate<TypeElement>... interfaceFilters) {\n        return type == null ? emptySet() : filterAll(ofTypeElements(getAllInterfaces(type.asType())), interfaceFilters);\n    }\n\n    static Set<? extends TypeMirror> getAllInterfaces(TypeMirror type, Predicate<TypeMirror>... interfaceFilters) {\n        if (type == null) {\n            return emptySet();\n        }\n        Set<TypeMirror> allInterfaces = new LinkedHashSet<>();\n        getInterfaces(type).forEach(i -> {\n            // Add current type's interfaces\n            allInterfaces.add(i);\n            // Add\n            allInterfaces.addAll(getAllInterfaces(i));\n        });\n        // Add all super types' interfaces\n        getAllSuperTypes(type).forEach(superType -> allInterfaces.addAll(getAllInterfaces(superType)));\n        return filterAll(allInterfaces, interfaceFilters);\n    }\n\n    static TypeMirror findInterface(TypeMirror type, CharSequence interfaceClassName) {\n        return filterFirst(getAllInterfaces(type), t -> isSameType(t, interfaceClassName));\n    }\n\n    static TypeElement getType(ProcessingEnvironment processingEnv, Type type) {\n        return type == null ? null : getType(processingEnv, type.getTypeName());\n    }\n\n    static TypeElement getType(ProcessingEnvironment processingEnv, TypeMirror type) {\n        return type == null ? null : getType(processingEnv, type.toString());\n    }\n\n    static TypeElement getType(ProcessingEnvironment processingEnv, CharSequence typeName) {\n        if (processingEnv == null || typeName == null) {\n            return null;\n        }\n        Elements elements = processingEnv.getElementUtils();\n        return elements.getTypeElement(typeName);\n    }\n\n    static TypeElement getSuperType(TypeElement type) {\n        return type == null ? null : ofTypeElement(type.getSuperclass());\n    }\n\n    static DeclaredType getSuperType(TypeMirror type) {\n        TypeElement superType = getSuperType(ofTypeElement(type));\n        return superType == null ? null : ofDeclaredType(superType.asType());\n    }\n\n    static Set<TypeElement> getAllSuperTypes(TypeElement type) {\n        return getAllSuperTypes(type, EMPTY_ARRAY);\n    }\n\n    static Set<TypeElement> getAllSuperTypes(TypeElement type, Predicate<TypeElement>... typeFilters) {\n        if (type == null) {\n            return emptySet();\n        }\n\n        Set<TypeElement> allSuperTypes = new LinkedHashSet<>();\n        TypeElement superType = getSuperType(type);\n        if (superType != null) {\n            // add super type\n            allSuperTypes.add(superType);\n            // add ancestors' types\n            allSuperTypes.addAll(getAllSuperTypes(superType));\n        }\n        return filterAll(allSuperTypes, typeFilters);\n    }\n\n    static Set<DeclaredType> getAllSuperTypes(TypeMirror type) {\n        return getAllSuperTypes(type, EMPTY_ARRAY);\n    }\n\n    static Set<DeclaredType> getAllSuperTypes(TypeMirror type, Predicate<DeclaredType>... typeFilters) {\n        return filterAll(ofDeclaredTypes(getAllSuperTypes(ofTypeElement(type))), typeFilters);\n    }\n\n    static boolean isDeclaredType(Element element) {\n        return element != null && isDeclaredType(element.asType());\n    }\n\n    static boolean isDeclaredType(TypeMirror type) {\n        return type instanceof DeclaredType;\n    }\n\n    static DeclaredType ofDeclaredType(Element element) {\n        return element == null ? null : ofDeclaredType(element.asType());\n    }\n\n    static DeclaredType ofDeclaredType(TypeMirror type) {\n        return isDeclaredType(type) ? (DeclaredType) type : null;\n    }\n\n    static boolean isTypeElement(Element element) {\n        return element instanceof TypeElement;\n    }\n\n    static boolean isTypeElement(TypeMirror type) {\n        DeclaredType declaredType = ofDeclaredType(type);\n        return declaredType != null && isTypeElement(declaredType.asElement());\n    }\n\n    static TypeElement ofTypeElement(Element element) {\n        return isTypeElement(element) ? (TypeElement) element : null;\n    }\n\n    static TypeElement ofTypeElement(TypeMirror type) {\n        DeclaredType declaredType = ofDeclaredType(type);\n        if (declaredType != null) {\n            return ofTypeElement(declaredType.asElement());\n        }\n        return null;\n    }\n\n    static Set<DeclaredType> ofDeclaredTypes(Iterable<? extends Element> elements) {\n        return elements == null\n                ? emptySet()\n                : stream(elements.spliterator(), false)\n                        .map(TypeUtils::ofTypeElement)\n                        .filter(Objects::nonNull)\n                        .map(Element::asType)\n                        .map(TypeUtils::ofDeclaredType)\n                        .filter(Objects::nonNull)\n                        .collect(LinkedHashSet::new, Set::add, Set::addAll);\n    }\n\n    static Set<TypeElement> ofTypeElements(Iterable<? extends TypeMirror> types) {\n        return types == null\n                ? emptySet()\n                : stream(types.spliterator(), false)\n                        .map(TypeUtils::ofTypeElement)\n                        .filter(Objects::nonNull)\n                        .collect(LinkedHashSet::new, Set::add, Set::addAll);\n    }\n\n    static List<DeclaredType> listDeclaredTypes(Iterable<? extends Element> elements) {\n        return new ArrayList<>(ofDeclaredTypes(elements));\n    }\n\n    static List<TypeElement> listTypeElements(Iterable<? extends TypeMirror> types) {\n        return new ArrayList<>(ofTypeElements(types));\n    }\n\n    static URL getResource(ProcessingEnvironment processingEnv, Element type) {\n        return getResource(processingEnv, ofDeclaredType(type));\n    }\n\n    static URL getResource(ProcessingEnvironment processingEnv, TypeMirror type) {\n        return type == null ? null : getResource(processingEnv, type.toString());\n    }\n\n    static URL getResource(ProcessingEnvironment processingEnv, CharSequence type) {\n        String relativeName = getResourceName(type);\n        URL resource = null;\n        try {\n            if (relativeName != null) {\n                FileObject fileObject =\n                        processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, \"\", relativeName);\n                resource = fileObject.toUri().toURL();\n                // try to open it\n                resource.getContent();\n            }\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n\n        return resource;\n    }\n\n    static String getResourceName(CharSequence type) {\n        return type == null ? null : type.toString().replace('.', '/').concat(\".class\");\n    }\n\n    static String toString(TypeMirror type) {\n        TypeElement element = ofTypeElement(type);\n        if (element != null) {\n            List<? extends TypeParameterElement> typeParameterElements = element.getTypeParameters();\n            if (!typeParameterElements.isEmpty()) {\n                List<? extends TypeMirror> typeMirrors;\n                if (type instanceof DeclaredType) {\n                    typeMirrors = ((DeclaredType) type).getTypeArguments();\n                } else {\n                    typeMirrors = invokeMethod(type, \"getTypeArguments\");\n                }\n                StringBuilder typeBuilder = new StringBuilder(element.toString());\n                typeBuilder.append('<');\n                for (int i = 0; i < typeMirrors.size(); i++) {\n                    if (i > 0) {\n                        typeBuilder.append(\", \");\n                    }\n                    typeBuilder.append(typeMirrors.get(i).toString());\n                }\n                typeBuilder.append('>');\n                return typeBuilder.toString();\n            }\n        }\n        return type.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.annotation.processing.builder.TypeBuilder",
    "content": "array-type = org.apache.dubbo.metadata.annotation.processing.builder.ArrayTypeDefinitionBuilder\ncollection-type = org.apache.dubbo.metadata.annotation.processing.builder.CollectionTypeDefinitionBuilder\nenum-type = org.apache.dubbo.metadata.annotation.processing.builder.EnumTypeDefinitionBuilder\ngeneral-type = org.apache.dubbo.metadata.annotation.processing.builder.GeneralTypeDefinitionBuilder\nmap-type = org.apache.dubbo.metadata.annotation.processing.builder.MapTypeDefinitionBuilder\nprimitive-type = org.apache.dubbo.metadata.annotation.processing.builder.PrimitiveTypeDefinitionBuilder\nsimple-type = org.apache.dubbo.metadata.annotation.processing.builder.SimpleTypeDefinitionBuilder"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor",
    "content": "org.apache.dubbo.metadata.annotation.processing.ServiceDefinitionMetadataAnnotationProcessor\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/AbstractAnnotationProcessingTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing;\n\nimport org.apache.dubbo.metadata.annotation.processing.util.TypeUtils;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.util.Elements;\nimport javax.lang.model.util.Types;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Abstract {@link Annotation} Processing Test case\n *\n * @since 2.7.6\n */\n@ExtendWith(CompilerInvocationInterceptor.class)\npublic abstract class AbstractAnnotationProcessingTest {\n\n    static ThreadLocal<AbstractAnnotationProcessingTest> testInstanceHolder = new ThreadLocal<>();\n\n    protected ProcessingEnvironment processingEnv;\n\n    protected Elements elements;\n\n    protected Types types;\n\n    @BeforeEach\n    public final void init() {\n        testInstanceHolder.set(this);\n    }\n\n    @AfterEach\n    public final void destroy() {\n        testInstanceHolder.remove();\n    }\n\n    protected abstract void addCompiledClasses(Set<Class<?>> classesToBeCompiled);\n\n    protected abstract void beforeEach();\n\n    protected TypeElement getType(Class<?> type) {\n        return TypeUtils.getType(processingEnv, type);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/AnnotationProcessingTestProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.TypeElement;\n\nimport java.lang.reflect.Method;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.InvocationInterceptor;\nimport org.junit.jupiter.api.extension.ReflectiveInvocationContext;\n\nimport static javax.lang.model.SourceVersion.latestSupported;\n\n@SupportedAnnotationTypes(\"*\")\npublic class AnnotationProcessingTestProcessor extends AbstractProcessor {\n\n    private final AbstractAnnotationProcessingTest abstractAnnotationProcessingTest;\n    private final InvocationInterceptor.Invocation<Void> invocation;\n\n    private final ReflectiveInvocationContext<Method> invocationContext;\n\n    private final ExtensionContext extensionContext;\n\n    public AnnotationProcessingTestProcessor(\n            AbstractAnnotationProcessingTest abstractAnnotationProcessingTest,\n            InvocationInterceptor.Invocation<Void> invocation,\n            ReflectiveInvocationContext<Method> invocationContext,\n            ExtensionContext extensionContext) {\n        this.abstractAnnotationProcessingTest = abstractAnnotationProcessingTest;\n        this.invocation = invocation;\n        this.invocationContext = invocationContext;\n        this.extensionContext = extensionContext;\n    }\n\n    @Override\n    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n        if (!roundEnv.processingOver()) {\n            prepare();\n            abstractAnnotationProcessingTest.beforeEach();\n            try {\n                invocation.proceed();\n            } catch (Throwable throwable) {\n                throw new RuntimeException(throwable);\n            }\n        }\n        return false;\n    }\n\n    private void prepare() {\n        abstractAnnotationProcessingTest.processingEnv = super.processingEnv;\n        abstractAnnotationProcessingTest.elements = super.processingEnv.getElementUtils();\n        abstractAnnotationProcessingTest.types = super.processingEnv.getTypeUtils();\n    }\n\n    @Override\n    public SourceVersion getSupportedSourceVersion() {\n        return latestSupported();\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/CompilerInvocationInterceptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing;\n\nimport org.apache.dubbo.metadata.tools.Compiler;\n\nimport java.lang.reflect.Method;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.InvocationInterceptor;\nimport org.junit.jupiter.api.extension.ReflectiveInvocationContext;\n\nimport static org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest.testInstanceHolder;\n\npublic class CompilerInvocationInterceptor implements InvocationInterceptor {\n\n    @Override\n    public void interceptTestMethod(\n            Invocation<Void> invocation,\n            ReflectiveInvocationContext<Method> invocationContext,\n            ExtensionContext extensionContext)\n            throws Throwable {\n        Set<Class<?>> classesToBeCompiled = new LinkedHashSet<>();\n        AbstractAnnotationProcessingTest abstractAnnotationProcessingTest = testInstanceHolder.get();\n        classesToBeCompiled.add(getClass());\n        abstractAnnotationProcessingTest.addCompiledClasses(classesToBeCompiled);\n        Compiler compiler = new Compiler();\n        compiler.processors(new AnnotationProcessingTestProcessor(\n                abstractAnnotationProcessingTest, invocation, invocationContext, extensionContext));\n        compiler.compile(classesToBeCompiled.toArray(new Class[0]));\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ArrayTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.ElementKind;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link ArrayTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass ArrayTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private ArrayTypeDefinitionBuilder builder;\n\n    private TypeElement testType;\n\n    private VariableElement integersField;\n\n    private VariableElement stringsField;\n\n    private VariableElement primitiveTypeModelsField;\n\n    private VariableElement modelsField;\n\n    private VariableElement colorsField;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(ArrayTypeModel.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new ArrayTypeDefinitionBuilder();\n        testType = getType(ArrayTypeModel.class);\n        integersField = findField(testType, \"integers\");\n        stringsField = findField(testType, \"strings\");\n        primitiveTypeModelsField = findField(testType, \"primitiveTypeModels\");\n        modelsField = findField(testType, \"models\");\n        colorsField = findField(testType, \"colors\");\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, integersField.asType()));\n        assertTrue(builder.accept(processingEnv, stringsField.asType()));\n        assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType()));\n        assertTrue(builder.accept(processingEnv, modelsField.asType()));\n        assertTrue(builder.accept(processingEnv, colorsField.asType()));\n    }\n\n    @Test\n    void testBuild() {\n\n        buildAndAssertTypeDefinition(processingEnv, integersField, \"int[]\", \"int\", builder);\n\n        buildAndAssertTypeDefinition(processingEnv, stringsField, \"java.lang.String[]\", \"java.lang.String\", builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                primitiveTypeModelsField,\n                \"org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel[]\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                modelsField,\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model[]\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model\",\n                builder,\n                (def, subDef) -> {\n                    TypeElement subType = elements.getTypeElement(subDef.getType());\n                    assertEquals(ElementKind.CLASS, subType.getKind());\n                });\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                colorsField,\n                \"org.apache.dubbo.metadata.annotation.processing.model.Color[]\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Color\",\n                builder,\n                (def, subDef) -> {\n                    TypeElement subType = elements.getTypeElement(subDef.getType());\n                    assertEquals(ElementKind.ENUM, subType.getKind());\n                });\n    }\n\n    static void buildAndAssertTypeDefinition(\n            ProcessingEnvironment processingEnv,\n            VariableElement field,\n            String expectedType,\n            String compositeType,\n            TypeBuilder builder,\n            BiConsumer<TypeDefinition, TypeDefinition>... assertions) {\n        Map<String, TypeDefinition> typeCache = new HashMap<>();\n        TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field, typeCache);\n        String subTypeName = typeDefinition.getItems().get(0);\n        TypeDefinition subTypeDefinition = typeCache.get(subTypeName);\n        assertEquals(expectedType, typeDefinition.getType());\n        //        assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref());\n        assertEquals(compositeType, subTypeDefinition.getType());\n        //        assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName());\n        Stream.of(assertions).forEach(assertion -> assertion.accept(typeDefinition, subTypeDefinition));\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/CollectionTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.CollectionTypeModel;\n\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.builder.ArrayTypeDefinitionBuilderTest.buildAndAssertTypeDefinition;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link CollectionTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass CollectionTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private CollectionTypeDefinitionBuilder builder;\n\n    private VariableElement stringsField;\n\n    private VariableElement colorsField;\n\n    private VariableElement primitiveTypeModelsField;\n\n    private VariableElement modelsField;\n\n    private VariableElement modelArraysField;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(CollectionTypeModel.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new CollectionTypeDefinitionBuilder();\n        TypeElement testType = getType(CollectionTypeModel.class);\n        stringsField = findField(testType, \"strings\");\n        colorsField = findField(testType, \"colors\");\n        primitiveTypeModelsField = findField(testType, \"primitiveTypeModels\");\n        modelsField = findField(testType, \"models\");\n        modelArraysField = findField(testType, \"modelArrays\");\n\n        assertEquals(\"strings\", stringsField.getSimpleName().toString());\n        assertEquals(\"colors\", colorsField.getSimpleName().toString());\n        assertEquals(\n                \"primitiveTypeModels\", primitiveTypeModelsField.getSimpleName().toString());\n        assertEquals(\"models\", modelsField.getSimpleName().toString());\n        assertEquals(\"modelArrays\", modelArraysField.getSimpleName().toString());\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, stringsField.asType()));\n        assertTrue(builder.accept(processingEnv, colorsField.asType()));\n        assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType()));\n        assertTrue(builder.accept(processingEnv, modelsField.asType()));\n        assertTrue(builder.accept(processingEnv, modelArraysField.asType()));\n    }\n\n    @Test\n    void testBuild() {\n\n        buildAndAssertTypeDefinition(\n                processingEnv, stringsField, \"java.util.Collection<java.lang.String>\", \"java.lang.String\", builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                colorsField,\n                \"java.util.List<org.apache.dubbo.metadata.annotation.processing.model.Color>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Color\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                primitiveTypeModelsField,\n                \"java.util.Queue<org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                modelsField,\n                \"java.util.Deque<org.apache.dubbo.metadata.annotation.processing.model.Model>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                modelArraysField,\n                \"java.util.Set<org.apache.dubbo.metadata.annotation.processing.model.Model[]>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model[]\",\n                builder);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/EnumTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.Color;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.lang.model.element.TypeElement;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link EnumTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass EnumTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private EnumTypeDefinitionBuilder builder;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(Color.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new EnumTypeDefinitionBuilder();\n    }\n\n    @Test\n    void testAccept() {\n        TypeElement typeElement = getType(Color.class);\n        assertTrue(builder.accept(processingEnv, typeElement.asType()));\n    }\n\n    @Test\n    void testBuild() {\n        TypeElement typeElement = getType(Color.class);\n        Map<String, TypeDefinition> typeCache = new HashMap<>();\n        TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, typeElement, typeCache);\n        assertEquals(Color.class.getName(), typeDefinition.getType());\n        assertEquals(asList(\"RED\", \"YELLOW\", \"BLUE\"), typeDefinition.getEnums());\n        //        assertEquals(typeDefinition.getTypeBuilderName(), builder.getClass().getName());\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/GeneralTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel;\nimport org.apache.dubbo.metadata.annotation.processing.model.CollectionTypeModel;\nimport org.apache.dubbo.metadata.annotation.processing.model.Color;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\nimport org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel;\nimport org.apache.dubbo.metadata.annotation.processing.model.SimpleTypeModel;\n\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link GeneralTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass GeneralTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private GeneralTypeDefinitionBuilder builder;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(Model.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new GeneralTypeDefinitionBuilder();\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, getType(Model.class).asType()));\n        assertTrue(\n                builder.accept(processingEnv, getType(PrimitiveTypeModel.class).asType()));\n        assertTrue(builder.accept(processingEnv, getType(SimpleTypeModel.class).asType()));\n        assertTrue(builder.accept(processingEnv, getType(ArrayTypeModel.class).asType()));\n        assertTrue(\n                builder.accept(processingEnv, getType(CollectionTypeModel.class).asType()));\n        assertFalse(builder.accept(processingEnv, getType(Color.class).asType()));\n    }\n\n    @Test\n    void testBuild() {}\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/MapTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.MapTypeModel;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link MapTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass MapTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private MapTypeDefinitionBuilder builder;\n\n    private VariableElement stringsField;\n\n    private VariableElement colorsField;\n\n    private VariableElement primitiveTypeModelsField;\n\n    private VariableElement modelsField;\n\n    private VariableElement modelArraysField;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(MapTypeModel.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new MapTypeDefinitionBuilder();\n        TypeElement testType = getType(MapTypeModel.class);\n        stringsField = findField(testType, \"strings\");\n        colorsField = findField(testType, \"colors\");\n        primitiveTypeModelsField = findField(testType, \"primitiveTypeModels\");\n        modelsField = findField(testType, \"models\");\n        modelArraysField = findField(testType, \"modelArrays\");\n\n        assertEquals(\"strings\", stringsField.getSimpleName().toString());\n        assertEquals(\"colors\", colorsField.getSimpleName().toString());\n        assertEquals(\n                \"primitiveTypeModels\", primitiveTypeModelsField.getSimpleName().toString());\n        assertEquals(\"models\", modelsField.getSimpleName().toString());\n        assertEquals(\"modelArrays\", modelArraysField.getSimpleName().toString());\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, stringsField.asType()));\n        assertTrue(builder.accept(processingEnv, colorsField.asType()));\n        assertTrue(builder.accept(processingEnv, primitiveTypeModelsField.asType()));\n        assertTrue(builder.accept(processingEnv, modelsField.asType()));\n        assertTrue(builder.accept(processingEnv, modelArraysField.asType()));\n    }\n\n    @Test\n    void testBuild() {\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                stringsField,\n                \"java.util.Map<java.lang.String,java.lang.String>\",\n                \"java.lang.String\",\n                \"java.lang.String\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                colorsField,\n                \"java.util.SortedMap<java.lang.String,org.apache.dubbo.metadata.annotation.processing.model.Color>\",\n                \"java.lang.String\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Color\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                primitiveTypeModelsField,\n                \"java.util.NavigableMap<org.apache.dubbo.metadata.annotation.processing.model.Color,org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Color\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                modelsField,\n                \"java.util.HashMap<java.lang.String,org.apache.dubbo.metadata.annotation.processing.model.Model>\",\n                \"java.lang.String\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model\",\n                builder);\n\n        buildAndAssertTypeDefinition(\n                processingEnv,\n                modelArraysField,\n                \"java.util.TreeMap<org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel,org.apache.dubbo.metadata.annotation.processing.model.Model[]>\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel\",\n                \"org.apache.dubbo.metadata.annotation.processing.model.Model[]\",\n                builder);\n    }\n\n    static void buildAndAssertTypeDefinition(\n            ProcessingEnvironment processingEnv,\n            VariableElement field,\n            String expectedType,\n            String keyType,\n            String valueType,\n            TypeBuilder builder,\n            BiConsumer<TypeDefinition, TypeDefinition>... assertions) {\n        Map<String, TypeDefinition> typeCache = new HashMap<>();\n        TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field, typeCache);\n        String keyTypeName = typeDefinition.getItems().get(0);\n        TypeDefinition keyTypeDefinition = typeCache.get(keyTypeName);\n        String valueTypeName = typeDefinition.getItems().get(1);\n        TypeDefinition valueTypeDefinition = typeCache.get(valueTypeName);\n        assertEquals(expectedType, typeDefinition.getType());\n        //        assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref());\n        assertEquals(keyType, keyTypeDefinition.getType());\n        assertEquals(valueType, valueTypeDefinition.getType());\n        //        assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName());\n        Stream.of(assertions).forEach(assertion -> assertion.accept(typeDefinition, keyTypeDefinition));\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/PrimitiveTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link PrimitiveTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass PrimitiveTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private PrimitiveTypeDefinitionBuilder builder;\n\n    private VariableElement zField;\n\n    private VariableElement bField;\n\n    private VariableElement cField;\n\n    private VariableElement sField;\n\n    private VariableElement iField;\n\n    private VariableElement lField;\n\n    private VariableElement fField;\n\n    private VariableElement dField;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(PrimitiveTypeModel.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n\n        builder = new PrimitiveTypeDefinitionBuilder();\n\n        TypeElement testType = getType(PrimitiveTypeModel.class);\n\n        zField = findField(testType, \"z\");\n        bField = findField(testType, \"b\");\n        cField = findField(testType, \"c\");\n        sField = findField(testType, \"s\");\n        iField = findField(testType, \"i\");\n        lField = findField(testType, \"l\");\n        fField = findField(testType, \"f\");\n        dField = findField(testType, \"d\");\n\n        assertEquals(\"boolean\", zField.asType().toString());\n        assertEquals(\"byte\", bField.asType().toString());\n        assertEquals(\"char\", cField.asType().toString());\n        assertEquals(\"short\", sField.asType().toString());\n        assertEquals(\"int\", iField.asType().toString());\n        assertEquals(\"long\", lField.asType().toString());\n        assertEquals(\"float\", fField.asType().toString());\n        assertEquals(\"double\", dField.asType().toString());\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, zField.asType()));\n        assertTrue(builder.accept(processingEnv, bField.asType()));\n        assertTrue(builder.accept(processingEnv, cField.asType()));\n        assertTrue(builder.accept(processingEnv, sField.asType()));\n        assertTrue(builder.accept(processingEnv, iField.asType()));\n        assertTrue(builder.accept(processingEnv, lField.asType()));\n        assertTrue(builder.accept(processingEnv, fField.asType()));\n        assertTrue(builder.accept(processingEnv, dField.asType()));\n    }\n\n    @Test\n    void testBuild() {\n        buildAndAssertTypeDefinition(processingEnv, zField, builder);\n        buildAndAssertTypeDefinition(processingEnv, bField, builder);\n        buildAndAssertTypeDefinition(processingEnv, cField, builder);\n        buildAndAssertTypeDefinition(processingEnv, sField, builder);\n        buildAndAssertTypeDefinition(processingEnv, iField, builder);\n        buildAndAssertTypeDefinition(processingEnv, lField, builder);\n        buildAndAssertTypeDefinition(processingEnv, zField, builder);\n        buildAndAssertTypeDefinition(processingEnv, fField, builder);\n        buildAndAssertTypeDefinition(processingEnv, dField, builder);\n    }\n\n    static void buildAndAssertTypeDefinition(\n            ProcessingEnvironment processingEnv, VariableElement field, TypeBuilder builder) {\n        Map<String, TypeDefinition> typeCache = new HashMap<>();\n        TypeDefinition typeDefinition = TypeDefinitionBuilder.build(processingEnv, field, typeCache);\n        assertBasicTypeDefinition(typeDefinition, field.asType().toString(), builder);\n        //        assertEquals(field.getSimpleName().toString(), typeDefinition.get$ref());\n    }\n\n    static void assertBasicTypeDefinition(TypeDefinition typeDefinition, String type, TypeBuilder builder) {\n        assertEquals(type, typeDefinition.getType());\n        //        assertEquals(builder.getClass().getName(), typeDefinition.getTypeBuilderName());\n        assertTrue(typeDefinition.getProperties().isEmpty());\n        assertTrue(typeDefinition.getItems().isEmpty());\n        assertTrue(typeDefinition.getEnums().isEmpty());\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/ServiceDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.definition.model.ServiceDefinition;\nimport org.apache.dubbo.metadata.definition.model.TypeDefinition;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.builder.ServiceDefinitionBuilder.build;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link ServiceDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass ServiceDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(TestServiceImpl.class);\n    }\n\n    @Override\n    protected void beforeEach() {}\n\n    @Test\n    void testBuild() {\n        ServiceDefinition serviceDefinition = build(processingEnv, getType(TestServiceImpl.class));\n        assertEquals(TestServiceImpl.class.getTypeName(), serviceDefinition.getCanonicalName());\n        assertEquals(\"org/apache/dubbo/metadata/tools/TestServiceImpl.class\", serviceDefinition.getCodeSource());\n\n        // types\n        List<String> typeNames = Arrays.asList(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                \"org.apache.dubbo.metadata.tools.GenericTestService\",\n                \"org.apache.dubbo.metadata.tools.DefaultTestService\",\n                \"org.apache.dubbo.metadata.tools.TestService\",\n                \"java.lang.AutoCloseable\",\n                \"java.io.Serializable\",\n                \"java.util.EventListener\");\n        for (String typeName : typeNames) {\n            String gotTypeName = getTypeName(typeName, serviceDefinition.getTypes());\n            assertEquals(typeName, gotTypeName);\n        }\n\n        // methods\n        assertEquals(14, serviceDefinition.getMethods().size());\n    }\n\n    private static String getTypeName(String type, List<TypeDefinition> types) {\n        for (TypeDefinition typeDefinition : types) {\n            if (type.equals(typeDefinition.getType())) {\n                return typeDefinition.getType();\n            }\n        }\n        return type;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/builder/SimpleTypeDefinitionBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.builder;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.SimpleTypeModel;\n\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.builder.PrimitiveTypeDefinitionBuilderTest.buildAndAssertTypeDefinition;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link SimpleTypeDefinitionBuilder} Test\n *\n * @since 2.7.6\n */\nclass SimpleTypeDefinitionBuilderTest extends AbstractAnnotationProcessingTest {\n\n    private SimpleTypeDefinitionBuilder builder;\n\n    private VariableElement vField;\n\n    private VariableElement zField;\n\n    private VariableElement cField;\n\n    private VariableElement bField;\n\n    private VariableElement sField;\n\n    private VariableElement iField;\n\n    private VariableElement lField;\n\n    private VariableElement fField;\n\n    private VariableElement dField;\n\n    private VariableElement strField;\n\n    private VariableElement bdField;\n\n    private VariableElement biField;\n\n    private VariableElement dtField;\n\n    private VariableElement invalidField;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(SimpleTypeModel.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        builder = new SimpleTypeDefinitionBuilder();\n        TypeElement testType = getType(SimpleTypeModel.class);\n        vField = findField(testType, \"v\");\n        zField = findField(testType, \"z\");\n        cField = findField(testType, \"c\");\n        bField = findField(testType, \"b\");\n        sField = findField(testType, \"s\");\n        iField = findField(testType, \"i\");\n        lField = findField(testType, \"l\");\n        fField = findField(testType, \"f\");\n        dField = findField(testType, \"d\");\n        strField = findField(testType, \"str\");\n        bdField = findField(testType, \"bd\");\n        biField = findField(testType, \"bi\");\n        dtField = findField(testType, \"dt\");\n        invalidField = findField(testType, \"invalid\");\n\n        assertEquals(\"java.lang.Void\", vField.asType().toString());\n        assertEquals(\"java.lang.Boolean\", zField.asType().toString());\n        assertEquals(\"java.lang.Character\", cField.asType().toString());\n        assertEquals(\"java.lang.Byte\", bField.asType().toString());\n        assertEquals(\"java.lang.Short\", sField.asType().toString());\n        assertEquals(\"java.lang.Integer\", iField.asType().toString());\n        assertEquals(\"java.lang.Long\", lField.asType().toString());\n        assertEquals(\"java.lang.Float\", fField.asType().toString());\n        assertEquals(\"java.lang.Double\", dField.asType().toString());\n        assertEquals(\"java.lang.String\", strField.asType().toString());\n        assertEquals(\"java.math.BigDecimal\", bdField.asType().toString());\n        assertEquals(\"java.math.BigInteger\", biField.asType().toString());\n        assertEquals(\"java.util.Date\", dtField.asType().toString());\n        assertEquals(\"int\", invalidField.asType().toString());\n    }\n\n    @Test\n    void testAccept() {\n        assertTrue(builder.accept(processingEnv, vField.asType()));\n        assertTrue(builder.accept(processingEnv, zField.asType()));\n        assertTrue(builder.accept(processingEnv, cField.asType()));\n        assertTrue(builder.accept(processingEnv, bField.asType()));\n        assertTrue(builder.accept(processingEnv, sField.asType()));\n        assertTrue(builder.accept(processingEnv, iField.asType()));\n        assertTrue(builder.accept(processingEnv, lField.asType()));\n        assertTrue(builder.accept(processingEnv, fField.asType()));\n        assertTrue(builder.accept(processingEnv, dField.asType()));\n        assertTrue(builder.accept(processingEnv, strField.asType()));\n        assertTrue(builder.accept(processingEnv, bdField.asType()));\n        assertTrue(builder.accept(processingEnv, biField.asType()));\n        assertTrue(builder.accept(processingEnv, dtField.asType()));\n        // false condition\n        assertFalse(builder.accept(processingEnv, invalidField.asType()));\n    }\n\n    @Test\n    void testBuild() {\n        buildAndAssertTypeDefinition(processingEnv, vField, builder);\n        buildAndAssertTypeDefinition(processingEnv, zField, builder);\n        buildAndAssertTypeDefinition(processingEnv, cField, builder);\n        buildAndAssertTypeDefinition(processingEnv, sField, builder);\n        buildAndAssertTypeDefinition(processingEnv, iField, builder);\n        buildAndAssertTypeDefinition(processingEnv, lField, builder);\n        buildAndAssertTypeDefinition(processingEnv, fField, builder);\n        buildAndAssertTypeDefinition(processingEnv, dField, builder);\n        buildAndAssertTypeDefinition(processingEnv, strField, builder);\n        buildAndAssertTypeDefinition(processingEnv, bdField, builder);\n        buildAndAssertTypeDefinition(processingEnv, biField, builder);\n        buildAndAssertTypeDefinition(processingEnv, dtField, builder);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/ArrayTypeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\n/**\n * Array Type Model\n *\n * @since 2.7.6\n */\npublic class ArrayTypeModel {\n\n    private int[] integers; // Primitive type array\n\n    private String[] strings; // Simple type array\n\n    private PrimitiveTypeModel[] primitiveTypeModels; // Complex type array\n\n    private Model[] models; // Hierarchical Complex type array\n\n    private Color[] colors; // Enum type array\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/CollectionTypeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\nimport java.util.Collection;\nimport java.util.Deque;\nimport java.util.List;\nimport java.util.Queue;\nimport java.util.Set;\n\n/**\n * {@link Collection} Type Model\n *\n * @since 2.7.6\n */\npublic class CollectionTypeModel {\n\n    private Collection<String> strings; // The composite element is simple type\n\n    private List<Color> colors; // The composite element is Enum type\n\n    private Queue<PrimitiveTypeModel> primitiveTypeModels; // The composite element is POJO type\n\n    private Deque<Model> models; // The composite element is hierarchical POJO type\n\n    private Set<Model[]> modelArrays; // The composite element is hierarchical POJO type\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Color.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\n/**\n * Color enumeration\n *\n * @since 2.7.6\n */\npublic enum Color {\n    RED(1),\n    YELLOW(2),\n    BLUE(3);\n\n    private final int value;\n\n    Color(int value) {\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return \"Color{\" + \"value=\" + value + \"} \" + super.toString();\n    }\n\n    public int getValue() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/MapTypeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.NavigableMap;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\n/**\n * {@link Map} Type model\n *\n * @since 2.7.6\n */\npublic class MapTypeModel {\n\n    private Map<String, String> strings; // The composite element is simple type\n\n    private SortedMap<String, Color> colors; // The composite element is Enum type\n\n    private NavigableMap<Color, PrimitiveTypeModel> primitiveTypeModels; // The composite element is POJO type\n\n    private HashMap<String, Model> models; // The composite element is hierarchical POJO type\n\n    private TreeMap<PrimitiveTypeModel, Model[]> modelArrays; // The composite element is hierarchical POJO type\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/Model.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\nimport org.apache.dubbo.metadata.tools.Parent;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Model Object\n */\npublic class Model extends Parent {\n\n    private float f;\n\n    private double d;\n\n    private TimeUnit tu;\n\n    private String str;\n\n    private BigInteger bi;\n\n    private BigDecimal bd;\n\n    public float getF() {\n        return f;\n    }\n\n    public void setF(float f) {\n        this.f = f;\n    }\n\n    public double getD() {\n        return d;\n    }\n\n    public void setD(double d) {\n        this.d = d;\n    }\n\n    public TimeUnit getTu() {\n        return tu;\n    }\n\n    public void setTu(TimeUnit tu) {\n        this.tu = tu;\n    }\n\n    public String getStr() {\n        return str;\n    }\n\n    public void setStr(String str) {\n        this.str = str;\n    }\n\n    public BigInteger getBi() {\n        return bi;\n    }\n\n    public void setBi(BigInteger bi) {\n        this.bi = bi;\n    }\n\n    public BigDecimal getBd() {\n        return bd;\n    }\n\n    public void setBd(BigDecimal bd) {\n        this.bd = bd;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/PrimitiveTypeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\n/**\n * Primitive Type model\n *\n * @since 2.7.6\n */\npublic class PrimitiveTypeModel {\n\n    private boolean z;\n\n    private byte b;\n\n    private char c;\n\n    private short s;\n\n    private int i;\n\n    private long l;\n\n    private float f;\n\n    private double d;\n\n    public boolean isZ() {\n        return z;\n    }\n\n    public byte getB() {\n        return b;\n    }\n\n    public char getC() {\n        return c;\n    }\n\n    public short getS() {\n        return s;\n    }\n\n    public int getI() {\n        return i;\n    }\n\n    public long getL() {\n        return l;\n    }\n\n    public float getF() {\n        return f;\n    }\n\n    public double getD() {\n        return d;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/model/SimpleTypeModel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.model;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.Date;\n\n/**\n * Simple Type model\n *\n * @since 2.7.6\n */\npublic class SimpleTypeModel {\n\n    private Void v;\n\n    private Boolean z;\n\n    private Character c;\n\n    private Byte b;\n\n    private Short s;\n\n    private Integer i;\n\n    private Long l;\n\n    private Float f;\n\n    private Double d;\n\n    private String str;\n\n    private BigDecimal bd;\n\n    private BigInteger bi;\n\n    private Date dt;\n\n    private int invalid;\n\n    public Void getV() {\n        return v;\n    }\n\n    public void setV(Void v) {\n        this.v = v;\n    }\n\n    public Boolean getZ() {\n        return z;\n    }\n\n    public void setZ(Boolean z) {\n        this.z = z;\n    }\n\n    public Character getC() {\n        return c;\n    }\n\n    public void setC(Character c) {\n        this.c = c;\n    }\n\n    public Byte getB() {\n        return b;\n    }\n\n    public void setB(Byte b) {\n        this.b = b;\n    }\n\n    public Short getS() {\n        return s;\n    }\n\n    public void setS(Short s) {\n        this.s = s;\n    }\n\n    public Integer getI() {\n        return i;\n    }\n\n    public void setI(Integer i) {\n        this.i = i;\n    }\n\n    public Long getL() {\n        return l;\n    }\n\n    public void setL(Long l) {\n        this.l = l;\n    }\n\n    public Float getF() {\n        return f;\n    }\n\n    public void setF(Float f) {\n        this.f = f;\n    }\n\n    public Double getD() {\n        return d;\n    }\n\n    public void setD(Double d) {\n        this.d = d;\n    }\n\n    public String getStr() {\n        return str;\n    }\n\n    public void setStr(String str) {\n        this.str = str;\n    }\n\n    public BigDecimal getBd() {\n        return bd;\n    }\n\n    public void setBd(BigDecimal bd) {\n        this.bd = bd;\n    }\n\n    public BigInteger getBi() {\n        return bi;\n    }\n\n    public void setBi(BigInteger bi) {\n        this.bi = bi;\n    }\n\n    public Date getDt() {\n        return dt;\n    }\n\n    public void setDt(Date dt) {\n        this.dt = dt;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/AnnotationUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.tools.TestService;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.AnnotationMirror;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.TypeMirror;\nimport javax.ws.rs.Path;\n\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findAnnotation;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.findMetaAnnotation;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAllAnnotations;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAnnotation;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAnnotations;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getAttribute;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.getValue;\nimport static org.apache.dubbo.metadata.annotation.processing.util.AnnotationUtils.isAnnotationPresent;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getAllDeclaredMethods;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * The {@link AnnotationUtils} Test\n *\n * @since 2.7.6\n */\nclass AnnotationUtilsTest extends AbstractAnnotationProcessingTest {\n\n    private TypeElement testType;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {}\n\n    @Override\n    protected void beforeEach() {\n        testType = getType(TestServiceImpl.class);\n    }\n\n    @Test\n    void testGetAnnotation() {\n        AnnotationMirror serviceAnnotation = getAnnotation(testType, Service.class);\n        assertEquals(\"3.0.0\", getAttribute(serviceAnnotation, \"version\"));\n        assertEquals(\"test\", getAttribute(serviceAnnotation, \"group\"));\n        assertEquals(\"org.apache.dubbo.metadata.tools.TestService\", getAttribute(serviceAnnotation, \"interfaceName\"));\n\n        assertNull(getAnnotation(testType, (Class) null));\n        assertNull(getAnnotation(testType, (String) null));\n\n        assertNull(getAnnotation(testType.asType(), (Class) null));\n        assertNull(getAnnotation(testType.asType(), (String) null));\n\n        assertNull(getAnnotation((Element) null, (Class) null));\n        assertNull(getAnnotation((Element) null, (String) null));\n\n        assertNull(getAnnotation((TypeElement) null, (Class) null));\n        assertNull(getAnnotation((TypeElement) null, (String) null));\n    }\n\n    @Test\n    void testGetAnnotations() {\n        List<AnnotationMirror> annotations = getAnnotations(testType);\n        Iterator<AnnotationMirror> iterator = annotations.iterator();\n\n        assertEquals(1, annotations.size());\n        //        assertEquals(\"com.alibaba.dubbo.config.annotation.Service\",\n        // iterator.next().getAnnotationType().toString());\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                iterator.next().getAnnotationType().toString());\n\n        annotations = getAnnotations(testType, Service.class);\n        iterator = annotations.iterator();\n        assertEquals(1, annotations.size());\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                iterator.next().getAnnotationType().toString());\n\n        annotations = getAnnotations(testType.asType(), Service.class);\n        iterator = annotations.iterator();\n        assertEquals(1, annotations.size());\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                iterator.next().getAnnotationType().toString());\n\n        annotations = getAnnotations(testType.asType(), Service.class.getTypeName());\n        iterator = annotations.iterator();\n        assertEquals(1, annotations.size());\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                iterator.next().getAnnotationType().toString());\n\n        annotations = getAnnotations(testType, Override.class);\n        assertEquals(0, annotations.size());\n\n        //        annotations = getAnnotations(testType, com.alibaba.dubbo.config.annotation.Service.class);\n        //        assertEquals(1, annotations.size());\n\n        assertTrue(getAnnotations(null, (Class) null).isEmpty());\n        assertTrue(getAnnotations(null, (String) null).isEmpty());\n        assertTrue(getAnnotations(testType, (Class) null).isEmpty());\n        assertTrue(getAnnotations(testType, (String) null).isEmpty());\n\n        assertTrue(getAnnotations(null, Service.class).isEmpty());\n        assertTrue(getAnnotations(null, Service.class.getTypeName()).isEmpty());\n    }\n\n    @Test\n    void testGetAllAnnotations() {\n\n        List<AnnotationMirror> annotations = getAllAnnotations(testType);\n        assertEquals(4, annotations.size());\n\n        annotations = getAllAnnotations(testType.asType(), annotation -> true);\n        assertEquals(4, annotations.size());\n\n        annotations = getAllAnnotations(processingEnv, TestServiceImpl.class);\n        assertEquals(4, annotations.size());\n\n        annotations = getAllAnnotations(testType.asType(), Service.class);\n        assertEquals(3, annotations.size());\n\n        annotations = getAllAnnotations(testType, Override.class);\n        assertEquals(0, annotations.size());\n\n        //        annotations = getAllAnnotations(testType.asType(), com.alibaba.dubbo.config.annotation.Service.class);\n        //        assertEquals(2, annotations.size());\n\n        assertTrue(getAllAnnotations((Element) null, (Class) null).isEmpty());\n        assertTrue(getAllAnnotations((TypeMirror) null, (String) null).isEmpty());\n        assertTrue(getAllAnnotations((ProcessingEnvironment) null, (Class) null).isEmpty());\n        assertTrue(\n                getAllAnnotations((ProcessingEnvironment) null, (String) null).isEmpty());\n\n        assertTrue(getAllAnnotations((Element) null).isEmpty());\n        assertTrue(getAllAnnotations((TypeMirror) null).isEmpty());\n        assertTrue(getAllAnnotations(processingEnv, (Class) null).isEmpty());\n        assertTrue(getAllAnnotations(processingEnv, (String) null).isEmpty());\n\n        assertTrue(getAllAnnotations(testType, (Class) null).isEmpty());\n        assertTrue(getAllAnnotations(testType.asType(), (Class) null).isEmpty());\n\n        assertTrue(getAllAnnotations(testType, (String) null).isEmpty());\n        assertTrue(getAllAnnotations(testType.asType(), (String) null).isEmpty());\n\n        assertTrue(getAllAnnotations((Element) null, Service.class).isEmpty());\n        assertTrue(getAllAnnotations((TypeMirror) null, Service.class.getTypeName())\n                .isEmpty());\n    }\n\n    @Test\n    void testFindAnnotation() {\n\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                findAnnotation(testType, Service.class).getAnnotationType().toString());\n        //        assertEquals(\"com.alibaba.dubbo.config.annotation.Service\", findAnnotation(testType,\n        // com.alibaba.dubbo.config.annotation.Service.class).getAnnotationType().toString());\n        assertEquals(\n                \"javax.ws.rs.Path\",\n                findAnnotation(testType, Path.class).getAnnotationType().toString());\n        assertEquals(\n                \"javax.ws.rs.Path\",\n                findAnnotation(testType.asType(), Path.class)\n                        .getAnnotationType()\n                        .toString());\n        assertEquals(\n                \"javax.ws.rs.Path\",\n                findAnnotation(testType.asType(), Path.class.getTypeName())\n                        .getAnnotationType()\n                        .toString());\n        assertNull(findAnnotation(testType, Override.class));\n\n        assertNull(findAnnotation((Element) null, (Class) null));\n        assertNull(findAnnotation((Element) null, (String) null));\n        assertNull(findAnnotation((TypeMirror) null, (Class) null));\n        assertNull(findAnnotation((TypeMirror) null, (String) null));\n\n        assertNull(findAnnotation(testType, (Class) null));\n        assertNull(findAnnotation(testType, (String) null));\n        assertNull(findAnnotation(testType.asType(), (Class) null));\n        assertNull(findAnnotation(testType.asType(), (String) null));\n    }\n\n    @Test\n    void testFindMetaAnnotation() {\n        getAllDeclaredMethods(getType(TestService.class)).forEach(method -> {\n            assertEquals(\n                    \"javax.ws.rs.HttpMethod\",\n                    findMetaAnnotation(method, \"javax.ws.rs.HttpMethod\")\n                            .getAnnotationType()\n                            .toString());\n        });\n    }\n\n    @Test\n    void testGetAttribute() {\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\",\n                getAttribute(findAnnotation(testType, Service.class), \"interfaceName\"));\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\",\n                getAttribute(findAnnotation(testType, Service.class).getElementValues(), \"interfaceName\"));\n        assertEquals(\"/echo\", getAttribute(findAnnotation(testType, Path.class), \"value\"));\n\n        assertNull(getAttribute(findAnnotation(testType, Path.class), null));\n        assertNull(getAttribute(findAnnotation(testType, (Class) null), null));\n    }\n\n    @Test\n    void testGetValue() {\n        AnnotationMirror pathAnnotation = getAnnotation(getType(TestService.class), Path.class);\n        assertEquals(\"/echo\", getValue(pathAnnotation));\n    }\n\n    @Test\n    void testIsAnnotationPresent() {\n        assertTrue(isAnnotationPresent(testType, \"org.apache.dubbo.config.annotation.Service\"));\n        //        assertTrue(isAnnotationPresent(testType, \"com.alibaba.dubbo.config.annotation.Service\"));\n        assertTrue(isAnnotationPresent(testType, \"javax.ws.rs.Path\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/FieldUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.Color;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.lang.reflect.Type;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Test;\n\nimport static javax.lang.model.element.Modifier.FINAL;\nimport static javax.lang.model.element.Modifier.PRIVATE;\nimport static javax.lang.model.element.Modifier.PUBLIC;\nimport static javax.lang.model.element.Modifier.STATIC;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getAllDeclaredFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getAllNonStaticFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredField;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getNonStaticFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isEnumMemberField;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isField;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.isNonStaticField;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link FieldUtils} Test\n *\n * @since 2.7.6\n */\nclass FieldUtilsTest extends AbstractAnnotationProcessingTest {\n\n    private TypeElement testType;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {}\n\n    @Override\n    protected void beforeEach() {\n        testType = getType(TestServiceImpl.class);\n    }\n\n    @Test\n    void testGetDeclaredFields() {\n        TypeElement type = getType(Model.class);\n        List<VariableElement> fields = getDeclaredFields(type);\n        assertModelFields(fields);\n\n        fields = getDeclaredFields(type.asType());\n        assertModelFields(fields);\n\n        assertTrue(getDeclaredFields((Element) null).isEmpty());\n        assertTrue(getDeclaredFields((TypeMirror) null).isEmpty());\n\n        fields = getDeclaredFields(type, f -> \"f\".equals(f.getSimpleName().toString()));\n        assertEquals(1, fields.size());\n        assertEquals(\"f\", fields.get(0).getSimpleName().toString());\n    }\n\n    @Test\n    void testGetAllDeclaredFields() {\n        TypeElement type = getType(Model.class);\n\n        List<VariableElement> fields = getAllDeclaredFields(type);\n\n        assertModelAllFields(fields);\n\n        assertTrue(getAllDeclaredFields((Element) null).isEmpty());\n        assertTrue(getAllDeclaredFields((TypeMirror) null).isEmpty());\n\n        fields = getAllDeclaredFields(type, f -> \"f\".equals(f.getSimpleName().toString()));\n        assertEquals(1, fields.size());\n        assertEquals(\"f\", fields.get(0).getSimpleName().toString());\n    }\n\n    @Test\n    void testGetDeclaredField() {\n        TypeElement type = getType(Model.class);\n        testGetDeclaredField(type, \"f\", float.class);\n        testGetDeclaredField(type, \"d\", double.class);\n        testGetDeclaredField(type, \"tu\", TimeUnit.class);\n        testGetDeclaredField(type, \"str\", String.class);\n        testGetDeclaredField(type, \"bi\", BigInteger.class);\n        testGetDeclaredField(type, \"bd\", BigDecimal.class);\n\n        assertNull(getDeclaredField(type, \"b\"));\n        assertNull(getDeclaredField(type, \"s\"));\n        assertNull(getDeclaredField(type, \"i\"));\n        assertNull(getDeclaredField(type, \"l\"));\n        assertNull(getDeclaredField(type, \"z\"));\n\n        assertNull(getDeclaredField((Element) null, \"z\"));\n        assertNull(getDeclaredField((TypeMirror) null, \"z\"));\n    }\n\n    @Test\n    void testFindField() {\n        TypeElement type = getType(Model.class);\n        testFindField(type, \"f\", float.class);\n        testFindField(type, \"d\", double.class);\n        testFindField(type, \"tu\", TimeUnit.class);\n        testFindField(type, \"str\", String.class);\n        testFindField(type, \"bi\", BigInteger.class);\n        testFindField(type, \"bd\", BigDecimal.class);\n        testFindField(type, \"b\", byte.class);\n        testFindField(type, \"s\", short.class);\n        testFindField(type, \"i\", int.class);\n        testFindField(type, \"l\", long.class);\n        testFindField(type, \"z\", boolean.class);\n\n        assertNull(findField((Element) null, \"f\"));\n        assertNull(findField((Element) null, null));\n\n        assertNull(findField((TypeMirror) null, \"f\"));\n        assertNull(findField((TypeMirror) null, null));\n\n        assertNull(findField(type, null));\n        assertNull(findField(type.asType(), null));\n    }\n\n    @Test\n    void testIsEnumField() {\n        TypeElement type = getType(Color.class);\n        VariableElement field = findField(type, \"RED\");\n        assertTrue(isEnumMemberField(field));\n\n        field = findField(type, \"YELLOW\");\n        assertTrue(isEnumMemberField(field));\n\n        field = findField(type, \"BLUE\");\n        assertTrue(isEnumMemberField(field));\n\n        type = getType(Model.class);\n        field = findField(type, \"f\");\n        assertFalse(isEnumMemberField(field));\n\n        assertFalse(isEnumMemberField(null));\n    }\n\n    @Test\n    void testIsNonStaticField() {\n        TypeElement type = getType(Model.class);\n        assertTrue(isNonStaticField(findField(type, \"f\")));\n\n        type = getType(Color.class);\n        assertFalse(isNonStaticField(findField(type, \"BLUE\")));\n    }\n\n    @Test\n    void testIsField() {\n        TypeElement type = getType(Model.class);\n        assertTrue(isField(findField(type, \"f\")));\n        assertTrue(isField(findField(type, \"f\"), PRIVATE));\n\n        type = getType(Color.class);\n        assertTrue(isField(findField(type, \"BLUE\"), PUBLIC, STATIC, FINAL));\n\n        assertFalse(isField(null));\n        assertFalse(isField(null, PUBLIC, STATIC, FINAL));\n    }\n\n    @Test\n    void testGetNonStaticFields() {\n        TypeElement type = getType(Model.class);\n\n        List<VariableElement> fields = getNonStaticFields(type);\n        assertModelFields(fields);\n\n        fields = getNonStaticFields(type.asType());\n        assertModelFields(fields);\n\n        assertTrue(getAllNonStaticFields((Element) null).isEmpty());\n        assertTrue(getAllNonStaticFields((TypeMirror) null).isEmpty());\n    }\n\n    @Test\n    void testGetAllNonStaticFields() {\n        TypeElement type = getType(Model.class);\n\n        List<VariableElement> fields = getAllNonStaticFields(type);\n        assertModelAllFields(fields);\n\n        fields = getAllNonStaticFields(type.asType());\n        assertModelAllFields(fields);\n\n        assertTrue(getAllNonStaticFields((Element) null).isEmpty());\n        assertTrue(getAllNonStaticFields((TypeMirror) null).isEmpty());\n    }\n\n    private void assertModelFields(List<VariableElement> fields) {\n        assertEquals(6, fields.size());\n        assertEquals(\"d\", fields.get(1).getSimpleName().toString());\n        assertEquals(\"tu\", fields.get(2).getSimpleName().toString());\n        assertEquals(\"str\", fields.get(3).getSimpleName().toString());\n        assertEquals(\"bi\", fields.get(4).getSimpleName().toString());\n        assertEquals(\"bd\", fields.get(5).getSimpleName().toString());\n    }\n\n    private void assertModelAllFields(List<VariableElement> fields) {\n        assertEquals(11, fields.size());\n        assertEquals(\"f\", fields.get(0).getSimpleName().toString());\n        assertEquals(\"d\", fields.get(1).getSimpleName().toString());\n        assertEquals(\"tu\", fields.get(2).getSimpleName().toString());\n        assertEquals(\"str\", fields.get(3).getSimpleName().toString());\n        assertEquals(\"bi\", fields.get(4).getSimpleName().toString());\n        assertEquals(\"bd\", fields.get(5).getSimpleName().toString());\n        assertEquals(\"b\", fields.get(6).getSimpleName().toString());\n        assertEquals(\"s\", fields.get(7).getSimpleName().toString());\n        assertEquals(\"i\", fields.get(8).getSimpleName().toString());\n        assertEquals(\"l\", fields.get(9).getSimpleName().toString());\n        assertEquals(\"z\", fields.get(10).getSimpleName().toString());\n    }\n\n    private void testGetDeclaredField(TypeElement type, String fieldName, Type fieldType) {\n        VariableElement field = getDeclaredField(type, fieldName);\n        assertField(field, fieldName, fieldType);\n    }\n\n    private void testFindField(TypeElement type, String fieldName, Type fieldType) {\n        VariableElement field = findField(type, fieldName);\n        assertField(field, fieldName, fieldType);\n    }\n\n    private void assertField(VariableElement field, String fieldName, Type fieldType) {\n        assertEquals(fieldName, field.getSimpleName().toString());\n        assertEquals(fieldType.getTypeName(), field.asType().toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/LoggerUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.info;\nimport static org.apache.dubbo.metadata.annotation.processing.util.LoggerUtils.warn;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\n\n/**\n * {@link LoggerUtils} Test\n *\n * @since 2.7.6\n */\nclass LoggerUtilsTest {\n\n    @Test\n    void testLogger() {\n        assertNotNull(LoggerUtils.LOGGER);\n    }\n\n    @Test\n    void testInfo() {\n        info(\"Hello,World\");\n        info(\"Hello,%s\", \"World\");\n        info(\"%s,%s\", \"Hello\", \"World\");\n    }\n\n    @Test\n    void testWarn() {\n        warn(\"Hello,World\");\n        warn(\"Hello,%s\", \"World\");\n        warn(\"%s,%s\", \"Hello\", \"World\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MemberUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static javax.lang.model.element.Modifier.PRIVATE;\nimport static javax.lang.model.util.ElementFilter.fieldsIn;\nimport static javax.lang.model.util.ElementFilter.methodsIn;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getAllDeclaredMembers;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.getDeclaredMembers;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.hasModifiers;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.isPublicNonStatic;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MemberUtils.matchParameterTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.findMethod;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link MemberUtils} Test\n *\n * @since 2.7.6\n */\nclass MemberUtilsTest extends AbstractAnnotationProcessingTest {\n\n    private TypeElement testType;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {}\n\n    @Override\n    protected void beforeEach() {\n        testType = getType(TestServiceImpl.class);\n    }\n\n    @Test\n    void testIsPublicNonStatic() {\n        assertFalse(isPublicNonStatic(null));\n        methodsIn(getDeclaredMembers(testType.asType())).forEach(method -> assertTrue(isPublicNonStatic(method)));\n    }\n\n    @Test\n    void testHasModifiers() {\n        assertFalse(hasModifiers(null));\n        List<? extends Element> members = getAllDeclaredMembers(testType.asType());\n        List<VariableElement> fields = fieldsIn(members);\n        assertTrue(hasModifiers(fields.get(0), PRIVATE));\n    }\n\n    @Test\n    void testDeclaredMembers() {\n        TypeElement type = getType(Model.class);\n        List<? extends Element> members = getDeclaredMembers(type.asType());\n        List<VariableElement> fields = fieldsIn(members);\n        assertEquals(19, members.size());\n        assertEquals(6, fields.size());\n        assertEquals(\"f\", fields.get(0).getSimpleName().toString());\n        assertEquals(\"d\", fields.get(1).getSimpleName().toString());\n        assertEquals(\"tu\", fields.get(2).getSimpleName().toString());\n        assertEquals(\"str\", fields.get(3).getSimpleName().toString());\n        assertEquals(\"bi\", fields.get(4).getSimpleName().toString());\n        assertEquals(\"bd\", fields.get(5).getSimpleName().toString());\n\n        members = getAllDeclaredMembers(type.asType());\n        fields = fieldsIn(members);\n        assertEquals(11, fields.size());\n        assertEquals(\"f\", fields.get(0).getSimpleName().toString());\n        assertEquals(\"d\", fields.get(1).getSimpleName().toString());\n        assertEquals(\"tu\", fields.get(2).getSimpleName().toString());\n        assertEquals(\"str\", fields.get(3).getSimpleName().toString());\n        assertEquals(\"bi\", fields.get(4).getSimpleName().toString());\n        assertEquals(\"bd\", fields.get(5).getSimpleName().toString());\n        assertEquals(\"b\", fields.get(6).getSimpleName().toString());\n        assertEquals(\"s\", fields.get(7).getSimpleName().toString());\n        assertEquals(\"i\", fields.get(8).getSimpleName().toString());\n        assertEquals(\"l\", fields.get(9).getSimpleName().toString());\n        assertEquals(\"z\", fields.get(10).getSimpleName().toString());\n    }\n\n    @Test\n    void testMatchParameterTypes() {\n        ExecutableElement method = findMethod(testType, \"echo\", \"java.lang.String\");\n        assertTrue(matchParameterTypes(method.getParameters(), \"java.lang.String\"));\n        assertFalse(matchParameterTypes(method.getParameters(), \"java.lang.Object\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/MethodUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\nimport org.apache.dubbo.metadata.tools.TestService;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.findMethod;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getAllDeclaredMethods;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getDeclaredMethods;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodName;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getMethodParameterTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getOverrideMethod;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getPublicNonStaticMethods;\nimport static org.apache.dubbo.metadata.annotation.processing.util.MethodUtils.getReturnType;\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link MethodUtils} Test\n *\n * @since 2.7.6\n */\nclass MethodUtilsTest extends AbstractAnnotationProcessingTest {\n\n    private TypeElement testType;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {}\n\n    @Override\n    protected void beforeEach() {\n        testType = getType(TestServiceImpl.class);\n    }\n\n    @Test\n    void testDeclaredMethods() {\n        TypeElement type = getType(Model.class);\n        List<ExecutableElement> methods = getDeclaredMethods(type);\n        assertEquals(12, methods.size());\n\n        methods = getAllDeclaredMethods(type);\n        // registerNatives() no provided in JDK 17\n        assertTrue(methods.size() >= 33);\n\n        assertTrue(getAllDeclaredMethods((TypeElement) null).isEmpty());\n        assertTrue(getAllDeclaredMethods((TypeMirror) null).isEmpty());\n    }\n\n    private List<? extends ExecutableElement> doGetAllDeclaredMethods() {\n        return getAllDeclaredMethods(testType, Object.class);\n    }\n\n    @Test\n    void testGetAllDeclaredMethods() {\n        List<? extends ExecutableElement> methods = doGetAllDeclaredMethods();\n        assertEquals(14, methods.size());\n    }\n\n    @Test\n    void testGetPublicNonStaticMethods() {\n        List<? extends ExecutableElement> methods = getPublicNonStaticMethods(testType, Object.class);\n        assertEquals(14, methods.size());\n\n        methods = getPublicNonStaticMethods(testType.asType(), Object.class);\n        assertEquals(14, methods.size());\n    }\n\n    @Test\n    void testIsMethod() {\n        List<? extends ExecutableElement> methods = getPublicNonStaticMethods(testType, Object.class);\n        assertEquals(14, methods.stream().map(MethodUtils::isMethod).count());\n    }\n\n    @Test\n    void testIsPublicNonStaticMethod() {\n        List<? extends ExecutableElement> methods = getPublicNonStaticMethods(testType, Object.class);\n        assertEquals(\n                14, methods.stream().map(MethodUtils::isPublicNonStaticMethod).count());\n    }\n\n    @Test\n    void testFindMethod() {\n        TypeElement type = getType(Model.class);\n        // Test methods from java.lang.Object\n        // Object#toString()\n        String methodName = \"toString\";\n        ExecutableElement method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#hashCode()\n        methodName = \"hashCode\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#getClass()\n        methodName = \"getClass\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#finalize()\n        methodName = \"finalize\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#clone()\n        methodName = \"clone\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#notify()\n        methodName = \"notify\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#notifyAll()\n        methodName = \"notifyAll\";\n        method = findMethod(type.asType(), methodName);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#wait(long)\n        methodName = \"wait\";\n        method = findMethod(type.asType(), methodName, long.class);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#wait(long,int)\n        methodName = \"wait\";\n        method = findMethod(type.asType(), methodName, long.class, int.class);\n        assertEquals(method.getSimpleName().toString(), methodName);\n\n        // Object#equals(Object)\n        methodName = \"equals\";\n        method = findMethod(type.asType(), methodName, Object.class);\n        assertEquals(method.getSimpleName().toString(), methodName);\n    }\n\n    @Test\n    void testGetOverrideMethod() {\n        List<? extends ExecutableElement> methods = doGetAllDeclaredMethods();\n\n        ExecutableElement overrideMethod = getOverrideMethod(processingEnv, testType, methods.get(0));\n        assertNull(overrideMethod);\n\n        ExecutableElement declaringMethod = findMethod(getType(TestService.class), \"echo\", \"java.lang.String\");\n\n        overrideMethod = getOverrideMethod(processingEnv, testType, declaringMethod);\n        assertEquals(methods.get(0), overrideMethod);\n    }\n\n    @Test\n    void testGetMethodName() {\n        ExecutableElement method = findMethod(testType, \"echo\", \"java.lang.String\");\n        assertEquals(\"echo\", getMethodName(method));\n        assertNull(getMethodName(null));\n    }\n\n    @Test\n    void testReturnType() {\n        ExecutableElement method = findMethod(testType, \"echo\", \"java.lang.String\");\n        assertEquals(\"java.lang.String\", getReturnType(method));\n        assertNull(getReturnType(null));\n    }\n\n    @Test\n    void testMatchParameterTypes() {\n        ExecutableElement method = findMethod(testType, \"echo\", \"java.lang.String\");\n        assertArrayEquals(new String[] {\"java.lang.String\"}, getMethodParameterTypes(method));\n        assertTrue(getMethodParameterTypes(null).length == 0);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/ServiceAnnotationUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.tools.DefaultTestService;\nimport org.apache.dubbo.metadata.tools.GenericTestService;\nimport org.apache.dubbo.metadata.tools.TestService;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.lang.model.element.TypeElement;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.DUBBO_SERVICE_ANNOTATION_TYPE;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.GROUP_ATTRIBUTE_NAME;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.INTERFACE_CLASS_ATTRIBUTE_NAME;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.INTERFACE_NAME_ATTRIBUTE_NAME;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.LEGACY_SERVICE_ANNOTATION_TYPE;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SERVICE_ANNOTATION_TYPE;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.SUPPORTED_ANNOTATION_TYPES;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.VERSION_ATTRIBUTE_NAME;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getAnnotation;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getGroup;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.getVersion;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.isServiceAnnotationPresent;\nimport static org.apache.dubbo.metadata.annotation.processing.util.ServiceAnnotationUtils.resolveServiceInterfaceName;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * {@link ServiceAnnotationUtils} Test\n *\n * @since 2.7.6\n */\nclass ServiceAnnotationUtilsTest extends AbstractAnnotationProcessingTest {\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {}\n\n    @Override\n    protected void beforeEach() {}\n\n    @Test\n    void testConstants() {\n        assertEquals(\"org.apache.dubbo.config.annotation.DubboService\", DUBBO_SERVICE_ANNOTATION_TYPE);\n        assertEquals(\"org.apache.dubbo.config.annotation.Service\", SERVICE_ANNOTATION_TYPE);\n        assertEquals(\"com.alibaba.dubbo.config.annotation.Service\", LEGACY_SERVICE_ANNOTATION_TYPE);\n        assertEquals(\"interfaceClass\", INTERFACE_CLASS_ATTRIBUTE_NAME);\n        assertEquals(\"interfaceName\", INTERFACE_NAME_ATTRIBUTE_NAME);\n        assertEquals(\"group\", GROUP_ATTRIBUTE_NAME);\n        assertEquals(\"version\", VERSION_ATTRIBUTE_NAME);\n        assertEquals(\n                new LinkedHashSet<>(asList(\n                        \"org.apache.dubbo.config.annotation.DubboService\",\n                        \"org.apache.dubbo.config.annotation.Service\",\n                        \"com.alibaba.dubbo.config.annotation.Service\")),\n                SUPPORTED_ANNOTATION_TYPES);\n    }\n\n    @Test\n    void testIsServiceAnnotationPresent() {\n\n        assertTrue(isServiceAnnotationPresent(getType(TestServiceImpl.class)));\n        assertTrue(isServiceAnnotationPresent(getType(GenericTestService.class)));\n        assertTrue(isServiceAnnotationPresent(getType(DefaultTestService.class)));\n\n        assertFalse(isServiceAnnotationPresent(getType(TestService.class)));\n    }\n\n    @Test\n    void testGetAnnotation() {\n        TypeElement type = getType(TestServiceImpl.class);\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                getAnnotation(type).getAnnotationType().toString());\n\n        //        type = getType(GenericTestService.class);\n        //        assertEquals(\"com.alibaba.dubbo.config.annotation.Service\",\n        // getAnnotation(type).getAnnotationType().toString());\n\n        type = getType(DefaultTestService.class);\n        assertEquals(\n                \"org.apache.dubbo.config.annotation.Service\",\n                getAnnotation(type).getAnnotationType().toString());\n\n        assertThrows(IllegalArgumentException.class, () -> getAnnotation(getType(TestService.class)));\n    }\n\n    @Test\n    void testResolveServiceInterfaceName() {\n        TypeElement type = getType(TestServiceImpl.class);\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", resolveServiceInterfaceName(type, getAnnotation(type)));\n\n        type = getType(GenericTestService.class);\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", resolveServiceInterfaceName(type, getAnnotation(type)));\n\n        type = getType(DefaultTestService.class);\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", resolveServiceInterfaceName(type, getAnnotation(type)));\n    }\n\n    @Test\n    void testGetVersion() {\n        TypeElement type = getType(TestServiceImpl.class);\n        assertEquals(\"3.0.0\", getVersion(getAnnotation(type)));\n\n        type = getType(GenericTestService.class);\n        assertEquals(\"2.0.0\", getVersion(getAnnotation(type)));\n\n        type = getType(DefaultTestService.class);\n        assertEquals(\"1.0.0\", getVersion(getAnnotation(type)));\n    }\n\n    @Test\n    void testGetGroup() {\n        TypeElement type = getType(TestServiceImpl.class);\n        assertEquals(\"test\", getGroup(getAnnotation(type)));\n\n        type = getType(GenericTestService.class);\n        assertEquals(\"generic\", getGroup(getAnnotation(type)));\n\n        type = getType(DefaultTestService.class);\n        assertEquals(\"default\", getGroup(getAnnotation(type)));\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/annotation/processing/util/TypeUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.annotation.processing.util;\n\nimport org.apache.dubbo.metadata.annotation.processing.AbstractAnnotationProcessingTest;\nimport org.apache.dubbo.metadata.annotation.processing.model.ArrayTypeModel;\nimport org.apache.dubbo.metadata.annotation.processing.model.Color;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\nimport org.apache.dubbo.metadata.annotation.processing.model.PrimitiveTypeModel;\nimport org.apache.dubbo.metadata.tools.DefaultTestService;\nimport org.apache.dubbo.metadata.tools.GenericTestService;\nimport org.apache.dubbo.metadata.tools.TestServiceImpl;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.DeclaredType;\nimport javax.lang.model.type.TypeKind;\nimport javax.lang.model.type.TypeMirror;\n\nimport java.io.File;\nimport java.lang.reflect.Type;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.findField;\nimport static org.apache.dubbo.metadata.annotation.processing.util.FieldUtils.getDeclaredFields;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getAllInterfaces;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getAllSuperTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getHierarchicalTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getInterfaces;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResource;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getResourceName;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.getSuperType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isAnnotationType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isArrayType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isClassType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isDeclaredType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isEnumType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isInterfaceType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isPrimitiveType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSameType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isSimpleType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.isTypeElement;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.listDeclaredTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.listTypeElements;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredType;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofDeclaredTypes;\nimport static org.apache.dubbo.metadata.annotation.processing.util.TypeUtils.ofTypeElement;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * The {@link TypeUtils} Test\n *\n * @since 2.7.6\n */\nclass TypeUtilsTest extends AbstractAnnotationProcessingTest {\n\n    private TypeElement testType;\n\n    @Override\n    protected void addCompiledClasses(Set<Class<?>> classesToBeCompiled) {\n        classesToBeCompiled.add(ArrayTypeModel.class);\n        classesToBeCompiled.add(Color.class);\n    }\n\n    @Override\n    protected void beforeEach() {\n        testType = getType(TestServiceImpl.class);\n    }\n\n    @Test\n    void testIsSimpleType() {\n\n        assertTrue(isSimpleType(getType(Void.class)));\n        assertTrue(isSimpleType(getType(Boolean.class)));\n        assertTrue(isSimpleType(getType(Character.class)));\n        assertTrue(isSimpleType(getType(Byte.class)));\n        assertTrue(isSimpleType(getType(Short.class)));\n        assertTrue(isSimpleType(getType(Integer.class)));\n        assertTrue(isSimpleType(getType(Long.class)));\n        assertTrue(isSimpleType(getType(Float.class)));\n        assertTrue(isSimpleType(getType(Double.class)));\n        assertTrue(isSimpleType(getType(String.class)));\n        assertTrue(isSimpleType(getType(BigDecimal.class)));\n        assertTrue(isSimpleType(getType(BigInteger.class)));\n        assertTrue(isSimpleType(getType(Date.class)));\n        assertTrue(isSimpleType(getType(Object.class)));\n\n        assertFalse(isSimpleType(getType(getClass())));\n        assertFalse(isSimpleType((TypeElement) null));\n        assertFalse(isSimpleType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsSameType() {\n        assertTrue(isSameType(getType(Void.class).asType(), \"java.lang.Void\"));\n        assertFalse(isSameType(getType(String.class).asType(), \"java.lang.Void\"));\n\n        assertFalse(isSameType(getType(Void.class).asType(), (Type) null));\n        assertFalse(isSameType(null, (Type) null));\n\n        assertFalse(isSameType(getType(Void.class).asType(), (String) null));\n        assertFalse(isSameType(null, (String) null));\n    }\n\n    @Test\n    void testIsArrayType() {\n        TypeElement type = getType(ArrayTypeModel.class);\n        assertTrue(isArrayType(findField(type.asType(), \"integers\").asType()));\n        assertTrue(isArrayType(findField(type.asType(), \"strings\").asType()));\n        assertTrue(isArrayType(findField(type.asType(), \"primitiveTypeModels\").asType()));\n        assertTrue(isArrayType(findField(type.asType(), \"models\").asType()));\n        assertTrue(isArrayType(findField(type.asType(), \"colors\").asType()));\n\n        assertFalse(isArrayType((Element) null));\n        assertFalse(isArrayType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsEnumType() {\n        TypeElement type = getType(Color.class);\n        assertTrue(isEnumType(type.asType()));\n\n        type = getType(ArrayTypeModel.class);\n        assertFalse(isEnumType(type.asType()));\n\n        assertFalse(isEnumType((Element) null));\n        assertFalse(isEnumType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsClassType() {\n        TypeElement type = getType(ArrayTypeModel.class);\n        assertTrue(isClassType(type.asType()));\n\n        type = getType(Model.class);\n        assertTrue(isClassType(type.asType()));\n\n        assertFalse(isClassType((Element) null));\n        assertFalse(isClassType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsPrimitiveType() {\n        TypeElement type = getType(PrimitiveTypeModel.class);\n        getDeclaredFields(type.asType()).stream()\n                .map(VariableElement::asType)\n                .forEach(t -> assertTrue(isPrimitiveType(t)));\n\n        assertFalse(isPrimitiveType(getType(ArrayTypeModel.class)));\n\n        assertFalse(isPrimitiveType((Element) null));\n        assertFalse(isPrimitiveType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsInterfaceType() {\n        TypeElement type = getType(CharSequence.class);\n        assertTrue(isInterfaceType(type));\n        assertTrue(isInterfaceType(type.asType()));\n\n        type = getType(Model.class);\n        assertFalse(isInterfaceType(type));\n        assertFalse(isInterfaceType(type.asType()));\n\n        assertFalse(isInterfaceType((Element) null));\n        assertFalse(isInterfaceType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsAnnotationType() {\n        TypeElement type = getType(Override.class);\n\n        assertTrue(isAnnotationType(type));\n        assertTrue(isAnnotationType(type.asType()));\n\n        type = getType(Model.class);\n        assertFalse(isAnnotationType(type));\n        assertFalse(isAnnotationType(type.asType()));\n\n        assertFalse(isAnnotationType((Element) null));\n        assertFalse(isAnnotationType((TypeMirror) null));\n    }\n\n    @Test\n    void testGetHierarchicalTypes() {\n        Set hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, true, true);\n        Iterator iterator = hierarchicalTypes.iterator();\n        assertEquals(8, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.GenericTestService\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.DefaultTestService\",\n                iterator.next().toString());\n        assertEquals(\"java.lang.Object\", iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(8, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.GenericTestService\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.DefaultTestService\",\n                iterator.next().toString());\n        assertEquals(\"java.lang.Object\", iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), Object.class);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(7, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.GenericTestService\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.DefaultTestService\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, true, false);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(4, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.GenericTestService\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.DefaultTestService\",\n                iterator.next().toString());\n        assertEquals(\"java.lang.Object\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, false, true);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(5, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), false, false, true);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(4, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), true, false, false);\n        iterator = hierarchicalTypes.iterator();\n        assertEquals(1, hierarchicalTypes.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestServiceImpl\",\n                iterator.next().toString());\n\n        hierarchicalTypes = getHierarchicalTypes(testType.asType(), false, false, false);\n        assertEquals(0, hierarchicalTypes.size());\n\n        assertTrue(getHierarchicalTypes((TypeElement) null).isEmpty());\n        assertTrue(getHierarchicalTypes((TypeMirror) null).isEmpty());\n    }\n\n    @Test\n    void testGetInterfaces() {\n        TypeElement type = getType(Model.class);\n        List<TypeMirror> interfaces = getInterfaces(type);\n        assertTrue(interfaces.isEmpty());\n\n        interfaces = getInterfaces(testType.asType());\n\n        assertEquals(3, interfaces.size());\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", interfaces.get(0).toString());\n        assertEquals(\"java.lang.AutoCloseable\", interfaces.get(1).toString());\n        assertEquals(\"java.io.Serializable\", interfaces.get(2).toString());\n\n        assertTrue(getInterfaces((TypeElement) null).isEmpty());\n        assertTrue(getInterfaces((TypeMirror) null).isEmpty());\n    }\n\n    @Test\n    void testGetAllInterfaces() {\n        Set<? extends TypeMirror> interfaces = getAllInterfaces(testType.asType());\n        assertEquals(4, interfaces.size());\n        Iterator<? extends TypeMirror> iterator = interfaces.iterator();\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\", iterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", iterator.next().toString());\n        assertEquals(\"java.io.Serializable\", iterator.next().toString());\n        assertEquals(\"java.util.EventListener\", iterator.next().toString());\n\n        Set<TypeElement> allInterfaces = getAllInterfaces(testType);\n        assertEquals(4, interfaces.size());\n\n        Iterator<TypeElement> allIterator = allInterfaces.iterator();\n        assertEquals(\n                \"org.apache.dubbo.metadata.tools.TestService\",\n                allIterator.next().toString());\n        assertEquals(\"java.lang.AutoCloseable\", allIterator.next().toString());\n        assertEquals(\"java.io.Serializable\", allIterator.next().toString());\n        assertEquals(\"java.util.EventListener\", allIterator.next().toString());\n\n        assertTrue(getAllInterfaces((TypeElement) null).isEmpty());\n        assertTrue(getAllInterfaces((TypeMirror) null).isEmpty());\n    }\n\n    @Test\n    void testGetType() {\n        TypeElement element = TypeUtils.getType(processingEnv, String.class);\n        assertEquals(element, TypeUtils.getType(processingEnv, element.asType()));\n        assertEquals(element, TypeUtils.getType(processingEnv, \"java.lang.String\"));\n\n        assertNull(TypeUtils.getType(processingEnv, (Type) null));\n        assertNull(TypeUtils.getType(processingEnv, (TypeMirror) null));\n        assertNull(TypeUtils.getType(processingEnv, (CharSequence) null));\n        assertNull(TypeUtils.getType(null, (CharSequence) null));\n    }\n\n    @Test\n    void testGetSuperType() {\n        TypeElement gtsTypeElement = getSuperType(testType);\n        assertEquals(gtsTypeElement, getType(GenericTestService.class));\n        TypeElement dtsTypeElement = getSuperType(gtsTypeElement);\n        assertEquals(dtsTypeElement, getType(DefaultTestService.class));\n\n        TypeMirror gtsType = getSuperType(testType.asType());\n        assertEquals(gtsType, getType(GenericTestService.class).asType());\n        TypeMirror dtsType = getSuperType(gtsType);\n        assertEquals(dtsType, getType(DefaultTestService.class).asType());\n\n        assertNull(getSuperType((TypeElement) null));\n        assertNull(getSuperType((TypeMirror) null));\n    }\n\n    @Test\n    void testGetAllSuperTypes() {\n        Set<?> allSuperTypes = getAllSuperTypes(testType);\n        Iterator<?> iterator = allSuperTypes.iterator();\n        assertEquals(3, allSuperTypes.size());\n        assertEquals(iterator.next(), getType(GenericTestService.class));\n        assertEquals(iterator.next(), getType(DefaultTestService.class));\n        assertEquals(iterator.next(), getType(Object.class));\n\n        allSuperTypes = getAllSuperTypes(testType);\n        iterator = allSuperTypes.iterator();\n        assertEquals(3, allSuperTypes.size());\n        assertEquals(iterator.next(), getType(GenericTestService.class));\n        assertEquals(iterator.next(), getType(DefaultTestService.class));\n        assertEquals(iterator.next(), getType(Object.class));\n\n        assertTrue(getAllSuperTypes((TypeElement) null).isEmpty());\n        assertTrue(getAllSuperTypes((TypeMirror) null).isEmpty());\n    }\n\n    @Test\n    void testIsDeclaredType() {\n        assertTrue(isDeclaredType(testType));\n        assertTrue(isDeclaredType(testType.asType()));\n        assertFalse(isDeclaredType((Element) null));\n        assertFalse(isDeclaredType((TypeMirror) null));\n        assertFalse(isDeclaredType(types.getNullType()));\n        assertFalse(isDeclaredType(types.getPrimitiveType(TypeKind.BYTE)));\n        assertFalse(isDeclaredType(types.getArrayType(types.getPrimitiveType(TypeKind.BYTE))));\n    }\n\n    @Test\n    void testOfDeclaredType() {\n        assertEquals(testType.asType(), ofDeclaredType(testType));\n        assertEquals(testType.asType(), ofDeclaredType(testType.asType()));\n        assertEquals(ofDeclaredType(testType), ofDeclaredType(testType.asType()));\n\n        assertNull(ofDeclaredType((Element) null));\n        assertNull(ofDeclaredType((TypeMirror) null));\n    }\n\n    @Test\n    void testIsTypeElement() {\n        assertTrue(isTypeElement(testType));\n        assertTrue(isTypeElement(testType.asType()));\n\n        assertFalse(isTypeElement((Element) null));\n        assertFalse(isTypeElement((TypeMirror) null));\n    }\n\n    @Test\n    void testOfTypeElement() {\n        assertEquals(testType, ofTypeElement(testType));\n        assertEquals(testType, ofTypeElement(testType.asType()));\n\n        assertNull(ofTypeElement((Element) null));\n        assertNull(ofTypeElement((TypeMirror) null));\n    }\n\n    @Test\n    void testOfDeclaredTypes() {\n        Set<DeclaredType> declaredTypes =\n                ofDeclaredTypes(asList(getType(String.class), getType(TestServiceImpl.class), getType(Color.class)));\n        assertTrue(declaredTypes.contains(getType(String.class).asType()));\n        assertTrue(declaredTypes.contains(getType(TestServiceImpl.class).asType()));\n        assertTrue(declaredTypes.contains(getType(Color.class).asType()));\n\n        assertTrue(ofDeclaredTypes(null).isEmpty());\n    }\n\n    @Test\n    void testListDeclaredTypes() {\n        List<DeclaredType> types = listDeclaredTypes(asList(testType, testType, testType));\n        assertEquals(1, types.size());\n        assertEquals(ofDeclaredType(testType), types.get(0));\n\n        types = listDeclaredTypes(asList(new Element[] {null}));\n        assertTrue(types.isEmpty());\n    }\n\n    @Test\n    void testListTypeElements() {\n        List<TypeElement> typeElements = listTypeElements(asList(testType.asType(), ofDeclaredType(testType)));\n        assertEquals(1, typeElements.size());\n        assertEquals(testType, typeElements.get(0));\n\n        typeElements = listTypeElements(\n                asList(types.getPrimitiveType(TypeKind.BYTE), types.getNullType(), types.getNoType(TypeKind.NONE)));\n        assertTrue(typeElements.isEmpty());\n\n        typeElements = listTypeElements(asList(new TypeMirror[] {null}));\n        assertTrue(typeElements.isEmpty());\n\n        typeElements = listTypeElements(null);\n        assertTrue(typeElements.isEmpty());\n    }\n\n    @Test\n    @Disabled\n    public void testGetResource() throws URISyntaxException {\n        URL resource = getResource(processingEnv, testType);\n        assertNotNull(resource);\n        assertTrue(new File(resource.toURI()).exists());\n        assertEquals(resource, getResource(processingEnv, testType.asType()));\n        assertEquals(resource, getResource(processingEnv, \"org.apache.dubbo.metadata.tools.TestServiceImpl\"));\n\n        assertThrows(RuntimeException.class, () -> getResource(processingEnv, \"NotFound\"));\n    }\n\n    @Test\n    void testGetResourceName() {\n        assertEquals(\"java/lang/String.class\", getResourceName(\"java.lang.String\"));\n        assertNull(getResourceName(null));\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Ancestor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport java.io.Serializable;\n\npublic class Ancestor implements Serializable {\n\n    private boolean z;\n\n    public boolean isZ() {\n        return z;\n    }\n\n    public void setZ(boolean z) {\n        this.z = z;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Compiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport javax.annotation.processing.Processor;\nimport javax.tools.JavaCompiler;\nimport javax.tools.JavaFileObject;\nimport javax.tools.StandardJavaFileManager;\nimport javax.tools.StandardLocation;\nimport javax.tools.ToolProvider;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport static java.util.Arrays.asList;\n\n/**\n * The Java Compiler\n */\npublic class Compiler {\n\n    private final File sourceDirectory;\n\n    private final JavaCompiler javaCompiler;\n\n    private final StandardJavaFileManager javaFileManager;\n\n    private final Set<Processor> processors = new LinkedHashSet<>();\n\n    public Compiler() throws IOException {\n        this(defaultTargetDirectory());\n    }\n\n    public Compiler(File targetDirectory) throws IOException {\n        this(defaultSourceDirectory(), targetDirectory);\n    }\n\n    public Compiler(File sourceDirectory, File targetDirectory) throws IOException {\n        this.sourceDirectory = sourceDirectory;\n        this.javaCompiler = ToolProvider.getSystemJavaCompiler();\n        this.javaFileManager = javaCompiler.getStandardFileManager(null, null, null);\n        this.javaFileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(targetDirectory));\n        this.javaFileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(targetDirectory));\n    }\n\n    private static File defaultSourceDirectory() {\n        return new File(defaultRootDirectory(), \"src/test/java\");\n    }\n\n    private static File defaultRootDirectory() {\n        return detectClassPath(Compiler.class).getParentFile().getParentFile();\n    }\n\n    private static File defaultTargetDirectory() {\n        File dir = new File(defaultRootDirectory(), \"target/generated-classes\");\n        dir.mkdirs();\n        return dir;\n    }\n\n    private static File detectClassPath(Class<?> targetClass) {\n        URL classFileURL = targetClass.getProtectionDomain().getCodeSource().getLocation();\n        if (\"file\".equals(classFileURL.getProtocol())) {\n            return new File(classFileURL.getPath());\n        } else {\n            throw new RuntimeException(\"No support\");\n        }\n    }\n\n    public Compiler processors(Processor... processors) {\n        this.processors.addAll(asList(processors));\n        return this;\n    }\n\n    private Iterable<? extends JavaFileObject> getJavaFileObjects(Class<?>... sourceClasses) {\n        int size = sourceClasses == null ? 0 : sourceClasses.length;\n        File[] javaSourceFiles = new File[size];\n        for (int i = 0; i < size; i++) {\n            File javaSourceFile = javaSourceFile(sourceClasses[i].getName());\n            javaSourceFiles[i] = javaSourceFile;\n        }\n        return javaFileManager.getJavaFileObjects(javaSourceFiles);\n    }\n\n    private File javaSourceFile(String sourceClassName) {\n        String javaSourceFilePath = sourceClassName.replace('.', '/').concat(\".java\");\n        return new File(sourceDirectory, javaSourceFilePath);\n    }\n\n    public boolean compile(Class<?>... sourceClasses) {\n        JavaCompiler.CompilationTask task = javaCompiler.getTask(\n                null,\n                this.javaFileManager,\n                null,\n                asList(\"-parameters\", \"-Xlint:unchecked\", \"-nowarn\", \"-Xlint:deprecation\"),\n                //                null,\n                null,\n                getJavaFileObjects(sourceClasses));\n        if (!processors.isEmpty()) {\n            task.setProcessors(processors);\n        }\n        return task.call();\n    }\n\n    public JavaCompiler getJavaCompiler() {\n        return javaCompiler;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/CompilerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\n/**\n * The Compiler test case\n */\nclass CompilerTest {\n\n    @Test\n    void testCompile() throws IOException {\n        Compiler compiler = new Compiler();\n        compiler.compile(TestServiceImpl.class, DefaultTestService.class, GenericTestService.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/DefaultTestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport org.apache.dubbo.config.annotation.Service;\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * {@link TestService} Implementation\n *\n * @since 2.7.6\n */\n@Service(interfaceName = \"org.apache.dubbo.metadata.tools.TestService\", version = \"1.0.0\", group = \"default\")\npublic class DefaultTestService implements TestService {\n\n    private String name;\n\n    @Override\n    public String echo(String message) {\n        return \"[ECHO] \" + message;\n    }\n\n    @Override\n    public Model model(Model model) {\n        return model;\n    }\n\n    @Override\n    public String testPrimitive(boolean z, int i) {\n        return null;\n    }\n\n    @Override\n    public Model testEnum(TimeUnit timeUnit) {\n        return null;\n    }\n\n    @Override\n    public String testArray(String[] strArray, int[] intArray, Model[] modelArray) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/GenericTestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport org.apache.dubbo.config.annotation.Service;\n\nimport java.util.EventListener;\n\n/**\n * {@link TestService} Implementation\n *\n * @since 2.7.6\n */\n@Service(version = \"2.0.0\", group = \"generic\")\npublic class GenericTestService extends DefaultTestService implements TestService, EventListener {\n    @Override\n    public String echo(String message) {\n        return \"[ECHO] \" + message;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/Parent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\npublic class Parent extends Ancestor {\n\n    private byte b;\n\n    private short s;\n\n    private int i;\n\n    private long l;\n\n    public byte getB() {\n        return b;\n    }\n\n    public void setB(byte b) {\n        this.b = b;\n    }\n\n    public short getS() {\n        return s;\n    }\n\n    public void setS(short s) {\n        this.s = s;\n    }\n\n    public int getI() {\n        return i;\n    }\n\n    public void setI(int i) {\n        this.i = i;\n    }\n\n    public long getL() {\n        return l;\n    }\n\n    public void setL(long l) {\n        this.l = l;\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.Processor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.TypeElement;\n\nimport java.util.Set;\n\nimport static javax.lang.model.SourceVersion.latestSupported;\n\n/**\n * {@link Processor} for test\n *\n * @since 2.7.6\n */\n@SupportedAnnotationTypes(\"*\")\npublic class TestProcessor extends AbstractProcessor {\n\n    @Override\n    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n        return false;\n    }\n\n    public ProcessingEnvironment getProcessingEnvironment() {\n        return super.processingEnv;\n    }\n\n    public SourceVersion getSupportedSourceVersion() {\n        return latestSupported();\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport org.apache.dubbo.metadata.annotation.processing.model.Model;\n\nimport javax.ws.rs.DefaultValue;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.PUT;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.PathParam;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Test Service\n *\n * @since 2.7.6\n */\n@Path(\"/echo\")\npublic interface TestService {\n\n    @GET\n    <T> String echo(@PathParam(\"message\") @DefaultValue(\"mercyblitz\") String message);\n\n    @POST\n    Model model(@PathParam(\"model\") Model model);\n\n    // Test primitive\n    @PUT\n    String testPrimitive(boolean z, int i);\n\n    // Test enumeration\n    @PUT\n    Model testEnum(TimeUnit timeUnit);\n\n    // Test Array\n    @GET\n    String testArray(String[] strArray, int[] intArray, Model[] modelArray);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/java/org/apache/dubbo/metadata/tools/TestServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.tools;\n\nimport org.apache.dubbo.config.annotation.Service;\n\nimport java.io.Serializable;\n\n/**\n * {@link TestService} Implementation\n *\n * @since 2.7.6\n */\n@Service(\n        interfaceName = \"org.apache.dubbo.metadata.tools.TestService\",\n        interfaceClass = TestService.class,\n        version = \"3.0.0\",\n        group = \"test\")\npublic class TestServiceImpl extends GenericTestService implements TestService, AutoCloseable, Serializable {\n\n    @Override\n    public String echo(String message) {\n        return \"[ECHO] \" + message;\n    }\n\n    @Override\n    public void close() throws Exception {}\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/resources/dubbo.properties",
    "content": "dubbo.application.enable-file-cache=false\ndubbo.service.shutdown.wait=200\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-processor/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-nacos/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metadata</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-metadata-report-nacos</artifactId>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-nacos</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosConfigServiceWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store.nacos;\n\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.config.listener.Listener;\nimport com.alibaba.nacos.api.exception.NacosException;\n\nimport static org.apache.dubbo.common.utils.StringUtils.HYPHEN_CHAR;\nimport static org.apache.dubbo.common.utils.StringUtils.SLASH_CHAR;\n\npublic class NacosConfigServiceWrapper {\n\n    private static final String INNERCLASS_SYMBOL = \"$\";\n\n    private static final String INNERCLASS_COMPATIBLE_SYMBOL = \"___\";\n\n    private static final long DEFAULT_TIMEOUT = 3000L;\n\n    private ConfigService configService;\n\n    public NacosConfigServiceWrapper(ConfigService configService) {\n        this.configService = configService;\n    }\n\n    public ConfigService getConfigService() {\n        return configService;\n    }\n\n    public void addListener(String dataId, String group, Listener listener) throws NacosException {\n        configService.addListener(handleInnerSymbol(dataId), handleInnerSymbol(group), listener);\n    }\n\n    public void removeListener(String dataId, String group, Listener listener) throws NacosException {\n        configService.removeListener(handleInnerSymbol(dataId), handleInnerSymbol(group), listener);\n    }\n\n    public String getConfig(String dataId, String group) throws NacosException {\n        return configService.getConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), DEFAULT_TIMEOUT);\n    }\n\n    public String getConfig(String dataId, String group, long timeout) throws NacosException {\n        return configService.getConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), timeout);\n    }\n\n    public boolean publishConfig(String dataId, String group, String content) throws NacosException {\n        return configService.publishConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), content);\n    }\n\n    public boolean publishConfigCas(String dataId, String group, String content, String casMd5) throws NacosException {\n        return configService.publishConfigCas(handleInnerSymbol(dataId), handleInnerSymbol(group), content, casMd5);\n    }\n\n    public boolean removeConfig(String dataId, String group) throws NacosException {\n        return configService.removeConfig(handleInnerSymbol(dataId), handleInnerSymbol(group));\n    }\n\n    /**\n     * see {@link com.alibaba.nacos.client.config.utils.ParamUtils#isValid(java.lang.String)}\n     */\n    private String handleInnerSymbol(String data) {\n        if (data == null) {\n            return null;\n        }\n        return data.replace(INNERCLASS_SYMBOL, INNERCLASS_COMPATIBLE_SYMBOL).replace(SLASH_CHAR, HYPHEN_CHAR);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.MD5Utils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.MappingChangedEvent;\nimport org.apache.dubbo.metadata.MappingListener;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.ServiceNameMapping;\nimport org.apache.dubbo.metadata.report.identifier.BaseMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;\nimport org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.support.AbstractMetadataReport;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.Executor;\n\nimport com.alibaba.nacos.api.NacosFactory;\nimport com.alibaba.nacos.api.PropertyKeyConst;\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.config.listener.AbstractSharedListener;\nimport com.alibaba.nacos.api.exception.NacosException;\n\nimport static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_ERROR_NACOS;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_INTERRUPTED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION;\nimport static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;\nimport static org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of;\nimport static org.apache.dubbo.common.utils.StringUtils.HYPHEN_CHAR;\nimport static org.apache.dubbo.metadata.MetadataConstants.REPORT_CONSUMER_URL_KEY;\nimport static org.apache.dubbo.metadata.ServiceNameMapping.DEFAULT_MAPPING_GROUP;\nimport static org.apache.dubbo.metadata.ServiceNameMapping.getAppNames;\n\n/**\n * metadata report impl for nacos\n */\npublic class NacosMetadataReport extends AbstractMetadataReport {\n\n    private NacosConfigServiceWrapper configService;\n\n    /**\n     * The group used to store metadata in Nacos\n     */\n    private String group;\n\n    private ConcurrentHashMap<String, NacosConfigListener> watchListenerMap = new ConcurrentHashMap<>();\n\n    private ConcurrentHashMap<String, MappingDataListener> casListenerMap = new ConcurrentHashMap<>();\n\n    private MD5Utils md5Utils = new MD5Utils();\n\n    private static final String NACOS_RETRY_KEY = \"nacos.retry\";\n\n    private static final String NACOS_RETRY_WAIT_KEY = \"nacos.retry-wait\";\n\n    private static final String NACOS_CHECK_KEY = \"nacos.check\";\n\n    public NacosMetadataReport(URL url) {\n        super(url);\n        this.configService = buildConfigService(url);\n        group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);\n    }\n\n    private NacosConfigServiceWrapper buildConfigService(URL url) {\n        Properties nacosProperties = buildNacosProperties(url);\n        int retryTimes = url.getPositiveParameter(NACOS_RETRY_KEY, 10);\n        int sleepMsBetweenRetries = url.getPositiveParameter(NACOS_RETRY_WAIT_KEY, 1000);\n        boolean check = url.getParameter(NACOS_CHECK_KEY, true);\n        ConfigService tmpConfigServices = null;\n        try {\n            for (int i = 0; i < retryTimes + 1; i++) {\n                tmpConfigServices = NacosFactory.createConfigService(nacosProperties);\n                if (!check\n                        || (UP.equals(tmpConfigServices.getServerStatus()) && testConfigService(tmpConfigServices))) {\n                    break;\n                } else {\n                    logger.warn(\n                            LoggerCodeConstants.CONFIG_ERROR_NACOS,\n                            \"\",\n                            \"\",\n                            \"Failed to connect to nacos config server. \"\n                                    + (i < retryTimes\n                                            ? \"Dubbo will try to retry in \" + sleepMsBetweenRetries + \". \"\n                                            : \"Exceed retry max times.\")\n                                    + \"Try times: \"\n                                    + (i + 1));\n                }\n                tmpConfigServices.shutDown();\n                tmpConfigServices = null;\n                Thread.sleep(sleepMsBetweenRetries);\n            }\n        } catch (NacosException e) {\n            logger.error(CONFIG_ERROR_NACOS, \"\", \"\", e.getErrMsg(), e);\n            throw new IllegalStateException(e);\n        } catch (InterruptedException e) {\n            logger.error(INTERNAL_INTERRUPTED, \"\", \"\", \"Interrupted when creating nacos config service client.\", e);\n            Thread.currentThread().interrupt();\n            throw new IllegalStateException(e);\n        }\n\n        if (tmpConfigServices == null) {\n            logger.error(\n                    CONFIG_ERROR_NACOS,\n                    \"\",\n                    \"\",\n                    \"Failed to create nacos config service client. Reason: server status check failed.\");\n            throw new IllegalStateException(\n                    \"Failed to create nacos config service client. Reason: server status check failed.\");\n        }\n\n        return new NacosConfigServiceWrapper(tmpConfigServices);\n    }\n\n    private boolean testConfigService(ConfigService configService) {\n        try {\n            configService.getConfig(\"Dubbo-Nacos-Test\", \"Dubbo-Nacos-Test\", 3000L);\n            return true;\n        } catch (NacosException e) {\n            return false;\n        }\n    }\n\n    private Properties buildNacosProperties(URL url) {\n        Properties properties = new Properties();\n        setServerAddr(url, properties);\n        setProperties(url, properties);\n        return properties;\n    }\n\n    private void setServerAddr(URL url, Properties properties) {\n        StringBuilder serverAddrBuilder = new StringBuilder(url.getHost()) // Host\n                .append(':')\n                .append(url.getPort()); // Port\n        // Append backup parameter as other servers\n        String backup = url.getParameter(BACKUP_KEY);\n        if (backup != null) {\n            serverAddrBuilder.append(',').append(backup);\n        }\n        String serverAddr = serverAddrBuilder.toString();\n        properties.put(SERVER_ADDR, serverAddr);\n    }\n\n    private static void setProperties(URL url, Properties properties) {\n        // Get the parameters from constants\n        Map<String, String> parameters = url.getParameters(of(PropertyKeyConst.class));\n        // Put all parameters\n        properties.putAll(parameters);\n    }\n\n    private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName) {\n        String propertyValue = url.getParameter(propertyName);\n        if (StringUtils.isNotEmpty(propertyValue)) {\n            properties.setProperty(propertyName, propertyValue);\n        }\n    }\n\n    private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName, String defaultValue) {\n        String propertyValue = url.getParameter(propertyName);\n        if (StringUtils.isNotEmpty(propertyValue)) {\n            properties.setProperty(propertyName, propertyValue);\n        } else {\n            properties.setProperty(propertyName, defaultValue);\n        }\n    }\n\n    @Override\n    public void publishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) {\n        try {\n            if (metadataInfo.getContent() != null) {\n                configService.publishConfig(\n                        identifier.getApplication(), identifier.getRevision(), metadataInfo.getContent());\n            }\n        } catch (NacosException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public void unPublishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) {\n        try {\n            configService.removeConfig(identifier.getApplication(), identifier.getRevision());\n        } catch (NacosException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public MetadataInfo getAppMetadata(SubscriberMetadataIdentifier identifier, Map<String, String> instanceMetadata) {\n        try {\n            String content = configService.getConfig(identifier.getApplication(), identifier.getRevision(), 3000L);\n            return JsonUtils.toJavaObject(content, MetadataInfo.class);\n        } catch (NacosException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    @Override\n    protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) {\n        this.storeMetadata(providerMetadataIdentifier, serviceDefinitions);\n    }\n\n    @Override\n    protected void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String value) {\n        if (getUrl().getParameter(REPORT_CONSUMER_URL_KEY, false)) {\n            this.storeMetadata(consumerMetadataIdentifier, value);\n        }\n    }\n\n    @Override\n    protected void doSaveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier, URL url) {\n        storeMetadata(serviceMetadataIdentifier, URL.encode(url.toFullString()));\n    }\n\n    @Override\n    protected void doRemoveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier) {\n        deleteMetadata(serviceMetadataIdentifier);\n    }\n\n    @Override\n    protected List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {\n        String content = getConfig(metadataIdentifier);\n        if (StringUtils.isEmpty(content)) {\n            return Collections.emptyList();\n        }\n        return new ArrayList<>(Arrays.asList(URL.decode(content)));\n    }\n\n    @Override\n    protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urlListStr) {\n        storeMetadata(subscriberMetadataIdentifier, urlListStr);\n    }\n\n    @Override\n    protected String doGetSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {\n        return getConfig(subscriberMetadataIdentifier);\n    }\n\n    @Override\n    public String getServiceDefinition(MetadataIdentifier metadataIdentifier) {\n        return getConfig(metadataIdentifier);\n    }\n\n    @Override\n    public boolean registerServiceAppMapping(String key, String group, String content, Object ticket) {\n        try {\n            if (!(ticket instanceof String)) {\n                throw new IllegalArgumentException(\"nacos publishConfigCas requires string type ticket\");\n            }\n            return configService.publishConfigCas(key, group, content, (String) ticket);\n        } catch (NacosException e) {\n            logger.warn(REGISTRY_NACOS_EXCEPTION, \"\", \"\", \"nacos publishConfigCas failed.\", e);\n            return false;\n        }\n    }\n\n    @Override\n    public ConfigItem getConfigItem(String key, String group) {\n        String content = getConfig(key, group);\n        String casMd5 = \"0\";\n        if (StringUtils.isNotEmpty(content)) {\n            casMd5 = md5Utils.getMd5(content);\n        }\n        return new ConfigItem(content, casMd5);\n    }\n\n    /**\n     * allow adding listener without checking if the serviceKey is existed in the map.\n     * there are multiple references which have the same serviceKey but might have multiple listeners,\n     * because the extra parameters of their subscribed URLs might be different.\n     */\n    @Override\n    public Set<String> getServiceAppMapping(String serviceKey, MappingListener listener, URL url) {\n        String group = DEFAULT_MAPPING_GROUP;\n\n        addCasServiceMappingListener(serviceKey, group, listener);\n        String content = getConfig(serviceKey, group);\n        return ServiceNameMapping.getAppNames(content);\n    }\n\n    @Override\n    public void removeServiceAppMappingListener(String serviceKey, MappingListener listener) {\n        String group = DEFAULT_MAPPING_GROUP;\n\n        MappingDataListener mappingDataListener = casListenerMap.get(buildListenerKey(serviceKey, group));\n        if (null != mappingDataListener) {\n            removeCasServiceMappingListener(serviceKey, group, listener);\n        }\n    }\n\n    @Override\n    public Set<String> getServiceAppMapping(String serviceKey, URL url) {\n        String content = getConfig(serviceKey, DEFAULT_MAPPING_GROUP);\n        return ServiceNameMapping.getAppNames(content);\n    }\n\n    private String getConfig(String dataId, String group) {\n        try {\n            return configService.getConfig(dataId, group);\n        } catch (NacosException e) {\n            logger.error(REGISTRY_NACOS_EXCEPTION, \"\", \"\", e.getMessage());\n        }\n        return null;\n    }\n\n    private void addCasServiceMappingListener(String serviceKey, String group, MappingListener listener) {\n        MappingDataListener mappingDataListener = ConcurrentHashMapUtils.computeIfAbsent(\n                casListenerMap, buildListenerKey(serviceKey, group), k -> new MappingDataListener(serviceKey, group));\n        mappingDataListener.addListeners(listener);\n        addListener(serviceKey, DEFAULT_MAPPING_GROUP, mappingDataListener);\n    }\n\n    private void removeCasServiceMappingListener(String serviceKey, String group, MappingListener listener) {\n        MappingDataListener mappingDataListener = casListenerMap.get(buildListenerKey(serviceKey, group));\n        if (mappingDataListener != null) {\n            mappingDataListener.removeListeners(listener);\n            if (mappingDataListener.isEmpty()) {\n                removeListener(serviceKey, DEFAULT_MAPPING_GROUP, mappingDataListener);\n                casListenerMap.remove(buildListenerKey(serviceKey, group), mappingDataListener);\n            }\n        }\n    }\n\n    public void addListener(String key, String group, ConfigurationListener listener) {\n        String listenerKey = buildListenerKey(key, group);\n        NacosConfigListener nacosConfigListener = ConcurrentHashMapUtils.computeIfAbsent(\n                watchListenerMap, listenerKey, k -> createTargetListener(key, group));\n        nacosConfigListener.addListener(listener);\n        try {\n            configService.addListener(key, group, nacosConfigListener);\n        } catch (NacosException e) {\n            logger.error(REGISTRY_NACOS_EXCEPTION, \"\", \"\", e.getMessage());\n        }\n    }\n\n    public void removeListener(String key, String group, ConfigurationListener listener) {\n        String listenerKey = buildListenerKey(key, group);\n        NacosConfigListener nacosConfigListener = watchListenerMap.get(listenerKey);\n        try {\n            if (nacosConfigListener != null) {\n                nacosConfigListener.removeListener(listener);\n                if (nacosConfigListener.isEmpty()) {\n                    configService.removeListener(key, group, nacosConfigListener);\n                    watchListenerMap.remove(listenerKey);\n                }\n            }\n        } catch (NacosException e) {\n            logger.error(REGISTRY_NACOS_EXCEPTION, \"\", \"\", e.getMessage());\n        }\n    }\n\n    private NacosConfigListener createTargetListener(String key, String group) {\n        NacosConfigListener configListener = new NacosConfigListener();\n        configListener.fillContext(key, group);\n        return configListener;\n    }\n\n    private String buildListenerKey(String key, String group) {\n        return key + HYPHEN_CHAR + group;\n    }\n\n    private void storeMetadata(BaseMetadataIdentifier identifier, String value) {\n        try {\n            boolean publishResult =\n                    configService.publishConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group, value);\n            if (!publishResult) {\n                throw new RuntimeException(\"publish nacos metadata failed\");\n            }\n        } catch (Throwable t) {\n            logger.error(\n                    REGISTRY_NACOS_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to put \" + identifier + \" to nacos \" + value + \", cause: \" + t.getMessage(),\n                    t);\n            throw new RuntimeException(\n                    \"Failed to put \" + identifier + \" to nacos \" + value + \", cause: \" + t.getMessage(), t);\n        }\n    }\n\n    private void deleteMetadata(BaseMetadataIdentifier identifier) {\n        try {\n            boolean publishResult = configService.removeConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group);\n            if (!publishResult) {\n                throw new RuntimeException(\"remove nacos metadata failed\");\n            }\n        } catch (Throwable t) {\n            logger.error(\n                    REGISTRY_NACOS_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to remove \" + identifier + \" from nacos , cause: \" + t.getMessage(),\n                    t);\n            throw new RuntimeException(\"Failed to remove \" + identifier + \" from nacos , cause: \" + t.getMessage(), t);\n        }\n    }\n\n    private String getConfig(BaseMetadataIdentifier identifier) {\n        try {\n            return configService.getConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group, 3000L);\n        } catch (Throwable t) {\n            logger.error(\n                    REGISTRY_NACOS_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to get \" + identifier + \" from nacos , cause: \" + t.getMessage(),\n                    t);\n            throw new RuntimeException(\"Failed to get \" + identifier + \" from nacos , cause: \" + t.getMessage(), t);\n        }\n    }\n\n    public class NacosConfigListener extends AbstractSharedListener {\n\n        private Set<ConfigurationListener> listeners = new CopyOnWriteArraySet<>();\n        /**\n         * cache data to store old value\n         */\n        private Map<String, String> cacheData = new ConcurrentHashMap<>();\n\n        @Override\n        public Executor getExecutor() {\n            return null;\n        }\n\n        /**\n         * receive\n         *\n         * @param dataId     data ID\n         * @param group      group\n         * @param configInfo content\n         */\n        @Override\n        public void innerReceive(String dataId, String group, String configInfo) {\n            String oldValue = cacheData.get(dataId);\n            ConfigChangedEvent event =\n                    new ConfigChangedEvent(dataId, group, configInfo, getChangeType(configInfo, oldValue));\n            if (configInfo == null) {\n                cacheData.remove(dataId);\n            } else {\n                cacheData.put(dataId, configInfo);\n            }\n            listeners.forEach(listener -> listener.process(event));\n        }\n\n        void addListener(ConfigurationListener configurationListener) {\n\n            this.listeners.add(configurationListener);\n        }\n\n        void removeListener(ConfigurationListener configurationListener) {\n            this.listeners.remove(configurationListener);\n        }\n\n        boolean isEmpty() {\n            return this.listeners.isEmpty();\n        }\n\n        private ConfigChangeType getChangeType(String configInfo, String oldValue) {\n            if (StringUtils.isBlank(configInfo)) {\n                return ConfigChangeType.DELETED;\n            }\n            if (StringUtils.isBlank(oldValue)) {\n                return ConfigChangeType.ADDED;\n            }\n            return ConfigChangeType.MODIFIED;\n        }\n    }\n\n    static class MappingDataListener implements ConfigurationListener {\n\n        private String dataId;\n\n        private String groupId;\n\n        private String serviceKey;\n\n        private Set<MappingListener> listeners;\n\n        public MappingDataListener(String dataId, String groupId) {\n            this.serviceKey = dataId;\n            this.dataId = dataId;\n            this.groupId = groupId;\n            this.listeners = new HashSet<>();\n        }\n\n        public void addListeners(MappingListener mappingListener) {\n            listeners.add(mappingListener);\n        }\n\n        public void removeListeners(MappingListener mappingListener) {\n            listeners.remove(mappingListener);\n        }\n\n        public boolean isEmpty() {\n            return listeners.isEmpty();\n        }\n\n        @Override\n        public void process(ConfigChangedEvent event) {\n            if (ConfigChangeType.DELETED == event.getChangeType()) {\n                return;\n            }\n            if (!dataId.equals(event.getKey()) || !groupId.equals(event.getGroup())) {\n                return;\n            }\n\n            Set<String> apps = getAppNames(event.getContent());\n\n            MappingChangedEvent mappingChangedEvent = new MappingChangedEvent(serviceKey, apps);\n\n            listeners.forEach(listener -> listener.onEvent(mappingChangedEvent));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory;\n\n/**\n * metadata report factory impl for nacos\n */\npublic class NacosMetadataReportFactory extends AbstractMetadataReportFactory {\n    @Override\n    protected MetadataReport createMetadataReport(URL url) {\n        return new NacosMetadataReport(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory",
    "content": "nacos=org.apache.dubbo.metadata.store.nacos.NacosMetadataReportFactory\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/MockConfigService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store.nacos;\n\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.config.filter.IConfigFilter;\nimport com.alibaba.nacos.api.config.listener.Listener;\nimport com.alibaba.nacos.api.exception.NacosException;\n\npublic class MockConfigService implements ConfigService {\n    @Override\n    public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {\n        return null;\n    }\n\n    @Override\n    public String getConfigAndSignListener(String dataId, String group, long timeoutMs, Listener listener) {\n        return null;\n    }\n\n    @Override\n    public void addListener(String dataId, String group, Listener listener) {}\n\n    @Override\n    public boolean publishConfig(String dataId, String group, String content) {\n        return false;\n    }\n\n    @Override\n    public boolean publishConfig(String dataId, String group, String content, String type) {\n        return false;\n    }\n\n    @Override\n    public boolean publishConfigCas(String dataId, String group, String content, String casMd5) {\n        return false;\n    }\n\n    @Override\n    public boolean publishConfigCas(String dataId, String group, String content, String casMd5, String type) {\n        return false;\n    }\n\n    @Override\n    public boolean removeConfig(String dataId, String group) {\n        return false;\n    }\n\n    @Override\n    public void removeListener(String dataId, String group, Listener listener) {}\n\n    @Override\n    public String getServerStatus() {\n        return null;\n    }\n\n    @Override\n    public void shutDown() {}\n\n    @Override\n    public void addConfigFilter(IConfigFilter iConfigFilter) {}\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/RetryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store.nacos;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.Properties;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.alibaba.nacos.api.NacosFactory;\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.DOWN;\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP;\nimport static org.mockito.ArgumentMatchers.any;\n\nclass RetryTest {\n\n    @Test\n    void testRetryCreate() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            AtomicInteger atomicInteger = new AtomicInteger(0);\n            ConfigService mock = new MockConfigService() {\n                @Override\n                public String getServerStatus() {\n                    return atomicInteger.incrementAndGet() > 10 ? UP : DOWN;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createConfigService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10);\n            Assertions.assertThrows(IllegalStateException.class, () -> new NacosMetadataReport(url));\n\n            try {\n                new NacosMetadataReport(url);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n\n    @Test\n    void testDisable() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            ConfigService mock = new MockConfigService() {\n                @Override\n                public String getServerStatus() {\n                    return DOWN;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createConfigService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10)\n                    .addParameter(\"nacos.check\", \"false\");\n            try {\n                new NacosMetadataReport(url);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n\n    @Test\n    void testRequest() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            AtomicInteger atomicInteger = new AtomicInteger(0);\n            ConfigService mock = new MockConfigService() {\n                @Override\n                public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {\n                    if (atomicInteger.incrementAndGet() > 10) {\n                        return \"\";\n                    } else {\n                        throw new NacosException();\n                    }\n                }\n\n                @Override\n                public String getServerStatus() {\n                    return UP;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createConfigService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10);\n            Assertions.assertThrows(IllegalStateException.class, () -> new NacosMetadataReport(url));\n\n            try {\n                new NacosMetadataReport(url);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-nacos/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-zookeeper/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metadata</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-metadata-report-zookeeper</artifactId>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-configcenter-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-test-common</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-framework</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-recipes</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.zookeeper</groupId>\n      <artifactId>zookeeper</artifactId>\n    </dependency>\n  </dependencies>\n\n  <profiles>\n    <profile>\n      <id>curator5</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo</groupId>\n          <artifactId>dubbo-remoting-zookeeper-curator5</artifactId>\n          <version>${project.parent.version}</version>\n        </dependency>\n      </dependencies>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.MappingChangedEvent;\nimport org.apache.dubbo.metadata.MappingListener;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.report.identifier.BaseMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;\nimport org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.support.AbstractMetadataReport;\nimport org.apache.dubbo.remoting.zookeeper.curator5.DataListener;\nimport org.apache.dubbo.remoting.zookeeper.curator5.EventType;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClient;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClientManager;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport org.apache.zookeeper.data.Stat;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_ZOOKEEPER_EXCEPTION;\nimport static org.apache.dubbo.metadata.ServiceNameMapping.DEFAULT_MAPPING_GROUP;\nimport static org.apache.dubbo.metadata.ServiceNameMapping.getAppNames;\n\npublic class ZookeeperMetadataReport extends AbstractMetadataReport {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ZookeeperMetadataReport.class);\n\n    private final String root;\n\n    ZookeeperClient zkClient;\n\n    private ConcurrentMap<String, MappingDataListener> casListenerMap = new ConcurrentHashMap<>();\n\n    public ZookeeperMetadataReport(URL url, ZookeeperClientManager zookeeperClientManager) {\n        super(url);\n        if (url.isAnyHost()) {\n            throw new IllegalStateException(\"registry address == null\");\n        }\n        String group = url.getGroup(DEFAULT_ROOT);\n        if (!group.startsWith(PATH_SEPARATOR)) {\n            group = PATH_SEPARATOR + group;\n        }\n        this.root = group;\n        zkClient = zookeeperClientManager.connect(url);\n    }\n\n    protected String toRootDir() {\n        if (root.equals(PATH_SEPARATOR)) {\n            return root;\n        }\n        return root + PATH_SEPARATOR;\n    }\n\n    @Override\n    protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) {\n        storeMetadata(providerMetadataIdentifier, serviceDefinitions);\n    }\n\n    @Override\n    protected void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String value) {\n        storeMetadata(consumerMetadataIdentifier, value);\n    }\n\n    @Override\n    protected void doSaveMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) {\n        zkClient.createOrUpdate(getNodePath(metadataIdentifier), URL.encode(url.toFullString()), false);\n    }\n\n    @Override\n    protected void doRemoveMetadata(ServiceMetadataIdentifier metadataIdentifier) {\n        zkClient.delete(getNodePath(metadataIdentifier));\n    }\n\n    @Override\n    protected List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {\n        String content = zkClient.getContent(getNodePath(metadataIdentifier));\n        if (StringUtils.isEmpty(content)) {\n            return Collections.emptyList();\n        }\n        return new ArrayList<>(Collections.singletonList(URL.decode(content)));\n    }\n\n    @Override\n    protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urls) {\n        zkClient.createOrUpdate(getNodePath(subscriberMetadataIdentifier), urls, false);\n    }\n\n    @Override\n    protected String doGetSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {\n        return zkClient.getContent(getNodePath(subscriberMetadataIdentifier));\n    }\n\n    @Override\n    public String getServiceDefinition(MetadataIdentifier metadataIdentifier) {\n        return zkClient.getContent(getNodePath(metadataIdentifier));\n    }\n\n    private void storeMetadata(MetadataIdentifier metadataIdentifier, String v) {\n        zkClient.createOrUpdate(getNodePath(metadataIdentifier), v, false);\n    }\n\n    String getNodePath(BaseMetadataIdentifier metadataIdentifier) {\n        return toRootDir() + metadataIdentifier.getUniqueKey(KeyTypeEnum.PATH);\n    }\n\n    @Override\n    public void publishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) {\n        String path = getNodePath(identifier);\n        if (StringUtils.isBlank(zkClient.getContent(path)) && StringUtils.isNotEmpty(metadataInfo.getContent())) {\n            zkClient.createOrUpdate(path, metadataInfo.getContent(), false);\n        }\n    }\n\n    @Override\n    public void unPublishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) {\n        String path = getNodePath(identifier);\n        if (StringUtils.isNotEmpty(zkClient.getContent(path))) {\n            zkClient.delete(path);\n        }\n    }\n\n    @Override\n    public MetadataInfo getAppMetadata(SubscriberMetadataIdentifier identifier, Map<String, String> instanceMetadata) {\n        String content = zkClient.getContent(getNodePath(identifier));\n        return JsonUtils.toJavaObject(content, MetadataInfo.class);\n    }\n\n    @Override\n    public Set<String> getServiceAppMapping(String serviceKey, MappingListener listener, URL url) {\n        String path = buildPathKey(DEFAULT_MAPPING_GROUP, serviceKey);\n        MappingDataListener mappingDataListener = ConcurrentHashMapUtils.computeIfAbsent(casListenerMap, path, _k -> {\n            MappingDataListener newMappingListener = new MappingDataListener(serviceKey, path);\n            zkClient.addDataListener(path, newMappingListener);\n            return newMappingListener;\n        });\n        mappingDataListener.addListener(listener);\n        return getAppNames(zkClient.getContent(path));\n    }\n\n    @Override\n    public void removeServiceAppMappingListener(String serviceKey, MappingListener listener) {\n        String path = buildPathKey(DEFAULT_MAPPING_GROUP, serviceKey);\n        if (null != casListenerMap.get(path)) {\n            removeCasServiceMappingListener(path, listener);\n        }\n    }\n\n    @Override\n    public Set<String> getServiceAppMapping(String serviceKey, URL url) {\n        String path = buildPathKey(DEFAULT_MAPPING_GROUP, serviceKey);\n        return getAppNames(zkClient.getContent(path));\n    }\n\n    @Override\n    public ConfigItem getConfigItem(String serviceKey, String group) {\n        String path = buildPathKey(group, serviceKey);\n        return zkClient.getConfigItem(path);\n    }\n\n    @Override\n    public boolean registerServiceAppMapping(String key, String group, String content, Object ticket) {\n        try {\n            if (ticket != null && !(ticket instanceof Stat)) {\n                throw new IllegalArgumentException(\"zookeeper publishConfigCas requires stat type ticket\");\n            }\n            String pathKey = buildPathKey(group, key);\n            zkClient.createOrUpdate(pathKey, content, false, ticket == null ? null : ((Stat) ticket).getVersion());\n            return true;\n        } catch (Exception e) {\n            logger.warn(REGISTRY_ZOOKEEPER_EXCEPTION, \"\", \"\", \"zookeeper publishConfigCas failed.\", e);\n            return false;\n        }\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n        // release zk client reference, but should not close it\n        zkClient = null;\n    }\n\n    private String buildPathKey(String group, String serviceKey) {\n        return toRootDir() + group + PATH_SEPARATOR + serviceKey;\n    }\n\n    private void removeCasServiceMappingListener(String path, MappingListener listener) {\n        MappingDataListener mappingDataListener = casListenerMap.get(path);\n        mappingDataListener.removeListener(listener);\n        if (mappingDataListener.isEmpty()) {\n            zkClient.removeDataListener(path, mappingDataListener);\n            casListenerMap.remove(path, mappingDataListener);\n        }\n    }\n\n    private static class MappingDataListener implements DataListener {\n\n        private String serviceKey;\n        private String path;\n        private Set<MappingListener> listeners;\n\n        public MappingDataListener(String serviceKey, String path) {\n            this.serviceKey = serviceKey;\n            this.path = path;\n            this.listeners = new HashSet<>();\n        }\n\n        public void addListener(MappingListener listener) {\n            this.listeners.add(listener);\n        }\n\n        public void removeListener(MappingListener listener) {\n            this.listeners.remove(listener);\n        }\n\n        public boolean isEmpty() {\n            return listeners.isEmpty();\n        }\n\n        @Override\n        public void dataChanged(String path, Object value, EventType eventType) {\n            if (!this.path.equals(path)) {\n                return;\n            }\n            if (EventType.NodeCreated != eventType && EventType.NodeDataChanged != eventType) {\n                return;\n            }\n\n            Set<String> apps = getAppNames((String) value);\n\n            MappingChangedEvent event = new MappingChangedEvent(serviceKey, apps);\n\n            listeners.forEach(mappingListener -> mappingListener.onEvent(event));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.DisableInject;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClientManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\n/**\n * ZookeeperRegistryFactory.\n */\npublic class ZookeeperMetadataReportFactory extends AbstractMetadataReportFactory {\n\n    private ZookeeperClientManager zookeeperClientManager;\n\n    public ZookeeperMetadataReportFactory(ApplicationModel applicationModel) {\n        this.zookeeperClientManager = ZookeeperClientManager.getInstance(applicationModel);\n    }\n\n    @DisableInject\n    public void setZookeeperTransporter(ZookeeperClientManager zookeeperClientManager) {\n        this.zookeeperClientManager = zookeeperClientManager;\n    }\n\n    @Override\n    public MetadataReport createMetadataReport(URL url) {\n        return new ZookeeperMetadataReport(url, zookeeperClientManager);\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory",
    "content": "zookeeper=org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReportFactory\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-zookeeper/src/test/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport4TstService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store.zookeeper;\n\n/**\n * 2018/10/26\n */\npublic interface ZookeeperMetadataReport4TstService {\n\n    int getCounter();\n\n    void printResult(String var);\n}\n"
  },
  {
    "path": "dubbo-metadata/dubbo-metadata-report-zookeeper/src/test/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metadata.store.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.metadata.MappingChangedEvent;\nimport org.apache.dubbo.metadata.MappingListener;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;\nimport org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;\nimport static org.apache.dubbo.metadata.ServiceNameMapping.DEFAULT_MAPPING_GROUP;\n\n/**\n * 2018/10/9\n */\nclass ZookeeperMetadataReportTest {\n    private ZookeeperMetadataReport zookeeperMetadataReport;\n    private URL registryUrl;\n    private ZookeeperMetadataReportFactory zookeeperMetadataReportFactory;\n    private static String zookeeperConnectionAddress1;\n\n    @BeforeAll\n    public static void beforeAll() {\n        zookeeperConnectionAddress1 = System.getProperty(\"zookeeper.connection.address.1\");\n    }\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        this.registryUrl = URL.valueOf(zookeeperConnectionAddress1);\n\n        zookeeperMetadataReportFactory = new ZookeeperMetadataReportFactory(ApplicationModel.defaultModel());\n        this.zookeeperMetadataReport =\n                (ZookeeperMetadataReport) zookeeperMetadataReportFactory.getMetadataReport(registryUrl);\n    }\n\n    private void deletePath(MetadataIdentifier metadataIdentifier, ZookeeperMetadataReport zookeeperMetadataReport) {\n        String category = zookeeperMetadataReport.toRootDir() + metadataIdentifier.getUniqueKey(KeyTypeEnum.PATH);\n        zookeeperMetadataReport.zkClient.delete(category);\n    }\n\n    @Test\n    void testStoreProvider() throws ClassNotFoundException, InterruptedException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService\";\n        String version = \"1.0.0.zk.md\";\n        String group = null;\n        String application = \"vic.zk.md\";\n        MetadataIdentifier providerMetadataIdentifier =\n                storePrivider(zookeeperMetadataReport, interfaceName, version, group, application);\n\n        String fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(providerMetadataIdentifier));\n        fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier));\n        Assertions.assertNotNull(fileContent);\n\n        deletePath(providerMetadataIdentifier, zookeeperMetadataReport);\n        fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(providerMetadataIdentifier));\n        fileContent = waitSeconds(fileContent, 1000, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier));\n        Assertions.assertNull(fileContent);\n\n        providerMetadataIdentifier = storePrivider(zookeeperMetadataReport, interfaceName, version, group, application);\n        fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(providerMetadataIdentifier));\n        fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier));\n        Assertions.assertNotNull(fileContent);\n\n        FullServiceDefinition fullServiceDefinition = JsonUtils.toJavaObject(fileContent, FullServiceDefinition.class);\n        Assertions.assertEquals(fullServiceDefinition.getParameters().get(\"paramTest\"), \"zkTest\");\n    }\n\n    @Test\n    void testConsumer() throws ClassNotFoundException, InterruptedException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService\";\n        String version = \"1.0.0.zk.md\";\n        String group = null;\n        String application = \"vic.zk.md\";\n        MetadataIdentifier consumerMetadataIdentifier =\n                storeConsumer(zookeeperMetadataReport, interfaceName, version, group, application);\n\n        String fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier));\n        fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier));\n        Assertions.assertNotNull(fileContent);\n\n        deletePath(consumerMetadataIdentifier, zookeeperMetadataReport);\n        fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier));\n        fileContent = waitSeconds(fileContent, 1000, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier));\n        Assertions.assertNull(fileContent);\n\n        consumerMetadataIdentifier = storeConsumer(zookeeperMetadataReport, interfaceName, version, group, application);\n        fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier));\n        fileContent = waitSeconds(fileContent, 3000, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier));\n        Assertions.assertNotNull(fileContent);\n        Assertions.assertEquals(fileContent, \"{\\\"paramConsumerTest\\\":\\\"zkCm\\\"}\");\n    }\n\n    @Test\n    void testDoSaveMetadata() throws ExecutionException, InterruptedException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService\";\n        String version = \"1.0.0\";\n        String group = null;\n        String application = \"etc-metadata-report-consumer-test\";\n        String revision = \"90980\";\n        String protocol = \"xxx\";\n        URL url = generateURL(interfaceName, version, group, application);\n        ServiceMetadataIdentifier serviceMetadataIdentifier =\n                new ServiceMetadataIdentifier(interfaceName, version, group, \"provider\", revision, protocol);\n        zookeeperMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url);\n\n        String fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(serviceMetadataIdentifier));\n        Assertions.assertNotNull(fileContent);\n\n        Assertions.assertEquals(fileContent, URL.encode(url.toFullString()));\n    }\n\n    @Test\n    void testDoRemoveMetadata() throws ExecutionException, InterruptedException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService\";\n        String version = \"1.0.0\";\n        String group = null;\n        String application = \"etc-metadata-report-consumer-test\";\n        String revision = \"90980\";\n        String protocol = \"xxx\";\n        URL url = generateURL(interfaceName, version, group, application);\n        ServiceMetadataIdentifier serviceMetadataIdentifier =\n                new ServiceMetadataIdentifier(interfaceName, version, group, \"provider\", revision, protocol);\n        zookeeperMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url);\n        String fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(serviceMetadataIdentifier));\n\n        Assertions.assertNotNull(fileContent);\n\n        zookeeperMetadataReport.doRemoveMetadata(serviceMetadataIdentifier);\n\n        fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(serviceMetadataIdentifier));\n        Assertions.assertNull(fileContent);\n    }\n\n    @Test\n    void testDoGetExportedURLs() throws ExecutionException, InterruptedException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService\";\n        String version = \"1.0.0\";\n        String group = null;\n        String application = \"etc-metadata-report-consumer-test\";\n        String revision = \"90980\";\n        String protocol = \"xxx\";\n        URL url = generateURL(interfaceName, version, group, application);\n        ServiceMetadataIdentifier serviceMetadataIdentifier =\n                new ServiceMetadataIdentifier(interfaceName, version, group, \"provider\", revision, protocol);\n        zookeeperMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url);\n\n        List<String> r = zookeeperMetadataReport.doGetExportedURLs(serviceMetadataIdentifier);\n        Assertions.assertTrue(r.size() == 1);\n\n        String fileContent = r.get(0);\n        Assertions.assertNotNull(fileContent);\n\n        Assertions.assertEquals(fileContent, url.toFullString());\n    }\n\n    @Test\n    void testDoSaveSubscriberData() throws ExecutionException, InterruptedException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService\";\n        String version = \"1.0.0\";\n        String group = null;\n        String application = \"etc-metadata-report-consumer-test\";\n        String revision = \"90980\";\n        String protocol = \"xxx\";\n        URL url = generateURL(interfaceName, version, group, application);\n        SubscriberMetadataIdentifier subscriberMetadataIdentifier =\n                new SubscriberMetadataIdentifier(application, revision);\n        String r = JsonUtils.toJson(Arrays.asList(url.toString()));\n        zookeeperMetadataReport.doSaveSubscriberData(subscriberMetadataIdentifier, r);\n\n        String fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(subscriberMetadataIdentifier));\n\n        Assertions.assertNotNull(fileContent);\n\n        Assertions.assertEquals(fileContent, r);\n    }\n\n    @Test\n    void testDoGetSubscribedURLs() throws ExecutionException, InterruptedException {\n        String interfaceName = \"org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService\";\n        String version = \"1.0.0\";\n        String group = null;\n        String application = \"etc-metadata-report-consumer-test\";\n        String revision = \"90980\";\n        String protocol = \"xxx\";\n        URL url = generateURL(interfaceName, version, group, application);\n        SubscriberMetadataIdentifier subscriberMetadataIdentifier =\n                new SubscriberMetadataIdentifier(application, revision);\n        String r = JsonUtils.toJson(Arrays.asList(url.toString()));\n        zookeeperMetadataReport.doSaveSubscriberData(subscriberMetadataIdentifier, r);\n\n        String fileContent = zookeeperMetadataReport.zkClient.getContent(\n                zookeeperMetadataReport.getNodePath(subscriberMetadataIdentifier));\n\n        Assertions.assertNotNull(fileContent);\n\n        Assertions.assertEquals(fileContent, r);\n    }\n\n    private MetadataIdentifier storePrivider(\n            MetadataReport zookeeperMetadataReport,\n            String interfaceName,\n            String version,\n            String group,\n            String application)\n            throws ClassNotFoundException, InterruptedException {\n        URL url = URL.valueOf(\"xxx://\" + NetUtils.getLocalAddress().getHostName() + \":4444/\" + interfaceName\n                + \"?paramTest=zkTest&version=\" + version + \"&application=\" + application\n                + (group == null ? \"\" : \"&group=\" + group));\n\n        MetadataIdentifier providerMetadataIdentifier =\n                new MetadataIdentifier(interfaceName, version, group, PROVIDER_SIDE, application);\n        Class interfaceClass = Class.forName(interfaceName);\n        FullServiceDefinition fullServiceDefinition =\n                ServiceDefinitionBuilder.buildFullDefinition(interfaceClass, url.getParameters());\n\n        zookeeperMetadataReport.storeProviderMetadata(providerMetadataIdentifier, fullServiceDefinition);\n        Thread.sleep(2000);\n        return providerMetadataIdentifier;\n    }\n\n    private MetadataIdentifier storeConsumer(\n            MetadataReport zookeeperMetadataReport,\n            String interfaceName,\n            String version,\n            String group,\n            String application)\n            throws ClassNotFoundException, InterruptedException {\n        URL url = URL.valueOf(\"xxx://\" + NetUtils.getLocalAddress().getHostName() + \":4444/\" + interfaceName\n                + \"?version=\" + version + \"&application=\" + application + (group == null ? \"\" : \"&group=\" + group));\n\n        MetadataIdentifier consumerMetadataIdentifier =\n                new MetadataIdentifier(interfaceName, version, group, CONSUMER_SIDE, application);\n        Class interfaceClass = Class.forName(interfaceName);\n\n        Map<String, String> tmp = new HashMap<>();\n        tmp.put(\"paramConsumerTest\", \"zkCm\");\n        zookeeperMetadataReport.storeConsumerMetadata(consumerMetadataIdentifier, tmp);\n        Thread.sleep(2000);\n\n        return consumerMetadataIdentifier;\n    }\n\n    private String waitSeconds(String value, long moreTime, String path) throws InterruptedException {\n        if (value == null) {\n            Thread.sleep(moreTime);\n            return zookeeperMetadataReport.zkClient.getContent(path);\n        }\n        return value;\n    }\n\n    private URL generateURL(String interfaceName, String version, String group, String application) {\n        URL url = URL.valueOf(\"xxx://\" + NetUtils.getLocalAddress().getHostName() + \":8989/\" + interfaceName\n                + \"?paramTest=etcdTest&version=\"\n                + version + \"&application=\"\n                + application + (group == null ? \"\" : \"&group=\" + group));\n        return url;\n    }\n\n    @Test\n    void testMapping() throws InterruptedException {\n        String serviceKey = ZookeeperMetadataReportTest.class.getName();\n        URL url = URL.valueOf(\"test://127.0.0.1:8888/\" + serviceKey);\n        String appNames = \"demo1,demo2\";\n\n        CountDownLatch latch = new CountDownLatch(1);\n        Set<String> serviceAppMapping = zookeeperMetadataReport.getServiceAppMapping(\n                serviceKey,\n                new MappingListener() {\n                    @Override\n                    public void onEvent(MappingChangedEvent event) {\n                        Set<String> apps = event.getApps();\n                        Assertions.assertEquals(apps.size(), 2);\n                        Assertions.assertTrue(apps.contains(\"demo1\"));\n                        Assertions.assertTrue(apps.contains(\"demo2\"));\n                        latch.countDown();\n                    }\n\n                    @Override\n                    public void stop() {}\n                },\n                url);\n        Assertions.assertTrue(serviceAppMapping.isEmpty());\n\n        ConfigItem configItem = zookeeperMetadataReport.getConfigItem(serviceKey, DEFAULT_MAPPING_GROUP);\n        zookeeperMetadataReport.registerServiceAppMapping(\n                serviceKey, DEFAULT_MAPPING_GROUP, appNames, configItem.getTicket());\n        latch.await();\n    }\n\n    @Test\n    void testAppMetadata() {\n        String serviceKey = ZookeeperMetadataReportTest.class.getName();\n        String appName = \"demo\";\n        URL url = URL.valueOf(\"test://127.0.0.1:8888/\" + serviceKey);\n        MetadataInfo metadataInfo = new MetadataInfo(appName);\n        metadataInfo.addService(url);\n\n        SubscriberMetadataIdentifier identifier =\n                new SubscriberMetadataIdentifier(appName, metadataInfo.calAndGetRevision());\n        MetadataInfo appMetadata = zookeeperMetadataReport.getAppMetadata(identifier, Collections.emptyMap());\n        Assertions.assertNull(appMetadata);\n\n        zookeeperMetadataReport.publishAppMetadata(identifier, metadataInfo);\n        appMetadata = zookeeperMetadataReport.getAppMetadata(identifier, Collections.emptyMap());\n        Assertions.assertNotNull(appMetadata);\n        Assertions.assertEquals(appMetadata.calAndGetRevision(), metadataInfo.calAndGetRevision());\n    }\n}\n"
  },
  {
    "path": "dubbo-metadata/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-metadata</artifactId>\n  <packaging>pom</packaging>\n  <modules>\n    <module>dubbo-metadata-api</module>\n    <module>dubbo-metadata-definition-protobuf</module>\n    <module>dubbo-metadata-processor</module>\n    <module>dubbo-metadata-report-zookeeper</module>\n    <module>dubbo-metadata-report-nacos</module>\n  </modules>\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metrics</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-metrics-api</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The metrics module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-event</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-core</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.tdunning</groupId>\n      <artifactId>t-digest</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboAbstractTDigest.java",
    "content": "/*\n * Licensed to Ted Dunning under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.metrics.aggregate;\n\nimport com.tdunning.math.stats.Centroid;\nimport com.tdunning.math.stats.TDigest;\n\npublic abstract class DubboAbstractTDigest extends TDigest {\n    boolean recordAllData = false;\n\n    /**\n     * Same as {@link #weightedAverageSorted(double, double, double, double)} but flips\n     * the order of the variables if <code>x2</code> is greater than\n     * <code>x1</code>.\n     */\n    static double weightedAverage(double x1, double w1, double x2, double w2) {\n        if (x1 <= x2) {\n            return weightedAverageSorted(x1, w1, x2, w2);\n        } else {\n            return weightedAverageSorted(x2, w2, x1, w1);\n        }\n    }\n\n    /**\n     * Compute the weighted average between <code>x1</code> with a weight of\n     * <code>w1</code> and <code>x2</code> with a weight of <code>w2</code>.\n     * This expects <code>x1</code> to be less than or equal to <code>x2</code>\n     * and is guaranteed to return a number in <code>[x1, x2]</code>. An\n     * explicit check is required since this isn't guaranteed with floating-point\n     * numbers.\n     */\n    private static double weightedAverageSorted(double x1, double w1, double x2, double w2) {\n        assert x1 <= x2;\n        final double x = (x1 * w1 + x2 * w2) / (w1 + w2);\n        return Math.max(x1, Math.min(x, x2));\n    }\n\n    abstract void add(double x, int w, Centroid base);\n\n    /**\n     * Sets up so that all centroids will record all data assigned to them.  For testing only, really.\n     */\n    @Override\n    public TDigest recordAllData() {\n        recordAllData = true;\n        return this;\n    }\n\n    @Override\n    public boolean isRecording() {\n        return recordAllData;\n    }\n\n    /**\n     * Adds a sample to a histogram.\n     *\n     * @param x The value to add.\n     */\n    @Override\n    public void add(double x) {\n        add(x, 1);\n    }\n\n    @Override\n    public void add(TDigest other) {\n        for (Centroid centroid : other.centroids()) {\n            add(centroid.mean(), centroid.count(), centroid);\n        }\n    }\n\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboMergingDigest.java",
    "content": "/*\n * Licensed to Ted Dunning under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.metrics.aggregate;\n\n\nimport org.apache.dubbo.metrics.exception.MetricsNeverHappenException;\n\nimport com.tdunning.math.stats.Centroid;\nimport com.tdunning.math.stats.ScaleFunction;\nimport com.tdunning.math.stats.Sort;\nimport com.tdunning.math.stats.TDigest;\n\nimport java.nio.ByteBuffer;\nimport java.util.AbstractCollection;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.NoSuchElementException;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Maintains a t-digest by collecting new points in a buffer that is then sorted occasionally and merged\n * into a sorted array that contains previously computed centroids.\n * <p>\n * This can be very fast because the cost of sorting and merging is amortized over several insertion. If\n * we keep N centroids total and have the input array is k long, then the amortized cost is something like\n * <p>\n * N/k + log k\n * <p>\n * These costs even out when N/k = log k.  Balancing costs is often a good place to start in optimizing an\n * algorithm.  For different values of compression factor, the following table shows estimated asymptotic\n * values of N and suggested values of k:\n * <table>\n * <thead>\n * <tr><td>Compression</td><td>N</td><td>k</td></tr>\n * </thead>\n * <tbody>\n * <tr><td>50</td><td>78</td><td>25</td></tr>\n * <tr><td>100</td><td>157</td><td>42</td></tr>\n * <tr><td>200</td><td>314</td><td>73</td></tr>\n * </tbody>\n * <caption>Sizing considerations for t-digest</caption>\n * </table>\n * <p>\n * The virtues of this kind of t-digest implementation include:\n * <ul>\n * <li>No allocation is required after initialization</li>\n * <li>The data structure automatically compresses existing centroids when possible</li>\n * <li>No Java object overhead is incurred for centroids since data is kept in primitive arrays</li>\n * </ul>\n * <p>\n * The current implementation takes the liberty of using ping-pong buffers for implementing the merge resulting\n * in a substantial memory penalty, but the complexity of an in place merge was not considered as worthwhile\n * since even with the overhead, the memory cost is less than 40 bytes per centroid which is much less than half\n * what the AVLTreeDigest uses and no dynamic allocation is required at all.\n */\npublic class DubboMergingDigest extends DubboAbstractTDigest {\n    private int mergeCount = 0;\n\n    private final double publicCompression;\n    private final double compression;\n\n    // points to the first unused centroid\n    private final AtomicInteger lastUsedCell = new AtomicInteger(0);\n\n    // sum_i weight[i]  See also unmergedWeight\n    private double totalWeight = 0;\n\n    // number of points that have been added to each merged centroid\n    private final double[] weight;\n    // mean of points added to each merged centroid\n    private final double[] mean;\n\n    // history of all data added to centroids (for testing purposes)\n    private List<List<Double>> data = null;\n\n    double min = Double.POSITIVE_INFINITY;\n    double max = Double.NEGATIVE_INFINITY;\n\n    // sum_i tempWeight[i]\n    private AtomicInteger unmergedWeight = new AtomicInteger(0);\n\n    // this is the index of the next temporary centroid\n    // this is a more Java-like convention than lastUsedCell uses\n    private final AtomicInteger tempUsed = new AtomicInteger(0);\n    private final double[] tempWeight;\n    private final double[] tempMean;\n    private List<List<Double>> tempData = null;\n\n\n    // array used for sorting the temp centroids.  This is a field\n    // to avoid allocations during operation\n    private final int[] order;\n\n    // if true, alternate upward and downward merge passes\n    public boolean useAlternatingSort = true;\n    // if true, use higher working value of compression during construction, then reduce on presentation\n    public boolean useTwoLevelCompression = true;\n\n    // this forces centroid merging based on size limit rather than\n    // based on accumulated k-index. This can be much faster since we\n    // scale functions are more expensive than the corresponding\n    // weight limits.\n    public static boolean useWeightLimit = true;\n\n    /**\n     * Allocates a buffer merging t-digest.  This is the normally used constructor that\n     * allocates default sized internal arrays.  Other versions are available, but should\n     * only be used for special cases.\n     *\n     * @param compression The compression factor\n     */\n    @SuppressWarnings(\"WeakerAccess\")\n    public DubboMergingDigest(double compression) {\n        this(compression, -1);\n    }\n\n    /**\n     * If you know the size of the temporary buffer for incoming points, you can use this entry point.\n     *\n     * @param compression Compression factor for t-digest.  Same as 1/\\delta in the paper.\n     * @param bufferSize  How many samples to retain before merging.\n     */\n    @SuppressWarnings(\"WeakerAccess\")\n    public DubboMergingDigest(double compression, int bufferSize) {\n        // we can guarantee that we only need ceiling(compression).\n        this(compression, bufferSize, -1);\n    }\n\n    /**\n     * Fully specified constructor.  Normally only used for deserializing a buffer t-digest.\n     *\n     * @param compression Compression factor\n     * @param bufferSize  Number of temporary centroids\n     * @param size        Size of main buffer\n     */\n    @SuppressWarnings(\"WeakerAccess\")\n    public DubboMergingDigest(double compression, int bufferSize, int size) {\n        // ensure compression >= 10\n        // default size = 2 * ceil(compression)\n        // default bufferSize = 5 * size\n        // scale = max(2, bufferSize / size - 1)\n        // compression, publicCompression = sqrt(scale-1)*compression, compression\n        // ensure size > 2 * compression + weightLimitFudge\n        // ensure bufferSize > 2*size\n\n        // force reasonable value. Anything less than 10 doesn't make much sense because\n        // too few centroids are retained\n        if (compression < 10) {\n            compression = 10;\n        }\n\n        // the weight limit is too conservative about sizes and can require a bit of extra room\n        double sizeFudge = 0;\n        if (useWeightLimit) {\n            sizeFudge = 10;\n            if (compression < 30) sizeFudge += 20;\n        }\n\n        // default size\n        size = (int) Math.max(2 * compression + sizeFudge, size);\n\n        // default buffer\n        if (bufferSize == -1) {\n            // TODO update with current numbers\n            // having a big buffer is good for speed\n            // experiments show bufferSize = 1 gives half the performance of bufferSize=10\n            // bufferSize = 2 gives 40% worse performance than 10\n            // but bufferSize = 5 only costs about 5-10%\n            //\n            //   compression factor     time(us)\n            //    50          1         0.275799\n            //    50          2         0.151368\n            //    50          5         0.108856\n            //    50         10         0.102530\n            //   100          1         0.215121\n            //   100          2         0.142743\n            //   100          5         0.112278\n            //   100         10         0.107753\n            //   200          1         0.210972\n            //   200          2         0.148613\n            //   200          5         0.118220\n            //   200         10         0.112970\n            //   500          1         0.219469\n            //   500          2         0.158364\n            //   500          5         0.127552\n            //   500         10         0.121505\n            bufferSize = 5 * size;\n        }\n\n        // ensure enough space in buffer\n        if (bufferSize <= 2 * size) {\n            bufferSize = 2 * size;\n        }\n\n        // scale is the ratio of extra buffer to the final size\n        // we have to account for the fact that we copy all live centroids into the incoming space\n        double scale = Math.max(1, bufferSize / size - 1);\n        //noinspection ConstantConditions\n        if (!useTwoLevelCompression) {\n            scale = 1;\n        }\n\n        // publicCompression is how many centroids the user asked for\n        // compression is how many we actually keep\n        this.publicCompression = compression;\n        this.compression = Math.sqrt(scale) * publicCompression;\n\n        // changing the compression could cause buffers to be too small, readjust if so\n        if (size < this.compression + sizeFudge) {\n            size = (int) Math.ceil(this.compression + sizeFudge);\n        }\n\n        // ensure enough space in buffer (possibly again)\n        if (bufferSize <= 2 * size) {\n            bufferSize = 2 * size;\n        }\n\n        weight = new double[size];\n        mean = new double[size];\n\n        tempWeight = new double[bufferSize];\n        tempMean = new double[bufferSize];\n        order = new int[bufferSize];\n\n        lastUsedCell.set(0);\n    }\n\n    public double getMin() {\n        return min;\n    }\n\n    public double getMax() {\n        return max;\n    }\n\n    /**\n     * Over-ride the min and max values for testing purposes\n     */\n    @SuppressWarnings(\"SameParameterValue\")\n    void setMinMax(double min, double max) {\n        this.min = min;\n        this.max = max;\n    }\n\n    /**\n     * Turns on internal data recording.\n     */\n    @Override\n    public TDigest recordAllData() {\n        super.recordAllData();\n        data = new ArrayList<>();\n        tempData = new ArrayList<>();\n        return this;\n    }\n\n    @Override\n    void add(double x, int w, Centroid base) {\n        add(x, w, base.data());\n    }\n\n    @Override\n    public void add(double x, int w) {\n        add(x, w, (List<Double>) null);\n    }\n\n    private void add(double x, int w, List<Double> history) {\n        if (Double.isNaN(x)) {\n            return;\n        }\n\n        int where;\n        synchronized (this) {\n            // There is a small probability of entering here\n            if (tempUsed.get() >= tempWeight.length - lastUsedCell.get() - 1) {\n                mergeNewValues();\n            }\n            where = tempUsed.getAndIncrement();\n            tempWeight[where] = w;\n            tempMean[where] = x;\n            unmergedWeight.addAndGet(w);\n        }\n        if (x < min) {\n            min = x;\n        }\n        if (x > max) {\n            max = x;\n        }\n\n        if (data != null) {\n            if (tempData == null) {\n                tempData = new ArrayList<>();\n            }\n            while (tempData.size() <= where) {\n                tempData.add(new ArrayList<Double>());\n            }\n            if (history == null) {\n                history = Collections.singletonList(x);\n            }\n            tempData.get(where).addAll(history);\n        }\n    }\n\n    @Override\n    public void add(List<? extends TDigest> others) {\n        throw new MetricsNeverHappenException(\"Method not used\");\n    }\n\n    private void mergeNewValues() {\n        mergeNewValues(false, compression);\n    }\n\n    private void mergeNewValues(boolean force, double compression) {\n        if (totalWeight == 0 && unmergedWeight.get() == 0) {\n            // seriously nothing to do\n            return;\n        }\n        if (force || unmergedWeight.get() > 0) {\n            // note that we run the merge in reverse every other merge to avoid left-to-right bias in merging\n            merge(tempMean, tempWeight, tempUsed.get(), tempData, order, unmergedWeight.get(),\n                useAlternatingSort & mergeCount % 2 == 1, compression);\n            mergeCount++;\n            tempUsed.set(0);\n            unmergedWeight.set(0);\n            if (data != null) {\n                tempData = new ArrayList<>();\n            }\n        }\n    }\n\n    private void merge(double[] incomingMean, double[] incomingWeight, int incomingCount,\n                       List<List<Double>> incomingData, int[] incomingOrder,\n                       double unmergedWeight, boolean runBackwards, double compression) {\n        // when our incoming buffer fills up, we combine our existing centroids with the incoming data,\n        // and then reduce the centroids by merging if possible\n        assert lastUsedCell.get() <= 0 || weight[0] == 1;\n        assert lastUsedCell.get() <= 0 || weight[lastUsedCell.get() - 1] == 1;\n        System.arraycopy(mean, 0, incomingMean, incomingCount, lastUsedCell.get());\n\n        System.arraycopy(weight, 0, incomingWeight, incomingCount, lastUsedCell.get());\n        incomingCount += lastUsedCell.get();\n\n        if (incomingData != null) {\n            for (int i = 0; i < lastUsedCell.get(); i++) {\n                assert data != null;\n                incomingData.add(data.get(i));\n            }\n            data = new ArrayList<>();\n        }\n        if (incomingOrder == null) {\n            incomingOrder = new int[incomingCount];\n        }\n        Sort.stableSort(incomingOrder, incomingMean, incomingCount);\n\n        totalWeight += unmergedWeight;\n\n        // option to run backwards is to help investigate bias in errors\n        if (runBackwards) {\n            Sort.reverse(incomingOrder, 0, incomingCount);\n        }\n\n\n        // start by copying the least incoming value to the normal buffer\n        lastUsedCell.set(0);\n        mean[lastUsedCell.get()] = incomingMean[incomingOrder[0]];\n        weight[lastUsedCell.get()] = incomingWeight[incomingOrder[0]];\n        double wSoFar = 0;\n        if (data != null) {\n            assert incomingData != null;\n            data.add(incomingData.get(incomingOrder[0]));\n        }\n\n        // weight will contain all zeros after this loop\n\n        double normalizer = scale.normalizer(compression, totalWeight);\n        double k1 = scale.k(0, normalizer);\n        double wLimit = totalWeight * scale.q(k1 + 1, normalizer);\n        for (int i = 1; i < incomingCount; i++) {\n            int ix = incomingOrder[i];\n            double proposedWeight = weight[lastUsedCell.get()] + incomingWeight[ix];\n            double projectedW = wSoFar + proposedWeight;\n            boolean addThis;\n            if (useWeightLimit) {\n                double q0 = wSoFar / totalWeight;\n                double q2 = (wSoFar + proposedWeight) / totalWeight;\n                addThis = proposedWeight <= totalWeight * Math.min(scale.max(q0, normalizer), scale.max(q2, normalizer));\n            } else {\n                addThis = projectedW <= wLimit;\n            }\n            if (i == 1 || i == incomingCount - 1) {\n                // force last centroid to never merge\n                addThis = false;\n            }\n\n            if (addThis) {\n                // next point will fit\n                // so merge into existing centroid\n                weight[lastUsedCell.get()] += incomingWeight[ix];\n                mean[lastUsedCell.get()] = mean[lastUsedCell.get()] + (incomingMean[ix] - mean[lastUsedCell.get()]) * incomingWeight[ix] / weight[lastUsedCell.get()];\n                incomingWeight[ix] = 0;\n\n                if (data != null) {\n                    while (data.size() <= lastUsedCell.get()) {\n                        data.add(new ArrayList<Double>());\n                    }\n                    assert incomingData != null;\n                    assert data.get(lastUsedCell.get()) != incomingData.get(ix);\n                    data.get(lastUsedCell.get()).addAll(incomingData.get(ix));\n                }\n            } else {\n                // didn't fit ... move to next output, copy out first centroid\n                wSoFar += weight[lastUsedCell.get()];\n                if (!useWeightLimit) {\n                    k1 = scale.k(wSoFar / totalWeight, normalizer);\n                    wLimit = totalWeight * scale.q(k1 + 1, normalizer);\n                }\n\n                lastUsedCell.getAndIncrement();\n                mean[lastUsedCell.get()] = incomingMean[ix];\n                weight[lastUsedCell.get()] = incomingWeight[ix];\n                incomingWeight[ix] = 0;\n\n                if (data != null) {\n                    assert incomingData != null;\n                    assert data.size() == lastUsedCell.get();\n                    data.add(incomingData.get(ix));\n                }\n            }\n        }\n        // points to next empty cell\n        lastUsedCell.getAndIncrement();\n\n        // sanity check\n        double sum = 0;\n        for (int i = 0; i < lastUsedCell.get(); i++) {\n            sum += weight[i];\n        }\n        assert sum == totalWeight;\n        if (runBackwards) {\n            Sort.reverse(mean, 0, lastUsedCell.get());\n            Sort.reverse(weight, 0, lastUsedCell.get());\n            if (data != null) {\n                Collections.reverse(data);\n            }\n        }\n        assert weight[0] == 1;\n        assert weight[lastUsedCell.get() - 1] == 1;\n\n        if (totalWeight > 0) {\n            min = Math.min(min, mean[0]);\n            max = Math.max(max, mean[lastUsedCell.get() - 1]);\n        }\n    }\n\n    /**\n     * Merges any pending inputs and compresses the data down to the public setting.\n     * Note that this typically loses a bit of precision and thus isn't a thing to\n     * be doing all the time. It is best done only when we want to show results to\n     * the outside world.\n     */\n    @Override\n    public void compress() {\n        mergeNewValues(true, publicCompression);\n    }\n\n    @Override\n    public long size() {\n        return (long) (totalWeight + unmergedWeight.get());\n    }\n\n    @Override\n    public double cdf(double x) {\n        if (Double.isNaN(x) || Double.isInfinite(x)) {\n            throw new IllegalArgumentException(String.format(\"Invalid value: %f\", x));\n        }\n        mergeNewValues();\n\n        if (lastUsedCell.get() == 0) {\n            // no data to examine\n            return Double.NaN;\n        } else if (lastUsedCell.get() == 1) {\n            // exactly one centroid, should have max==min\n            double width = max - min;\n            if (x < min) {\n                return 0;\n            } else if (x > max) {\n                return 1;\n            } else if (x - min <= width) {\n                // min and max are too close together to do any viable interpolation\n                return 0.5;\n            } else {\n                // interpolate if somehow we have weight > 0 and max != min\n                return (x - min) / (max - min);\n            }\n        } else {\n            int n = lastUsedCell.get();\n            if (x < min) {\n                return 0;\n            }\n\n            if (x > max) {\n                return 1;\n            }\n\n            // check for the left tail\n            if (x < mean[0]) {\n                // note that this is different than mean[0] > min\n                // ... this guarantees we divide by non-zero number and interpolation works\n                if (mean[0] - min > 0) {\n                    // must be a sample exactly at min\n                    if (x == min) {\n                        return 0.5 / totalWeight;\n                    } else {\n                        return (1 + (x - min) / (mean[0] - min) * (weight[0] / 2 - 1)) / totalWeight;\n                    }\n                } else {\n                    // this should be redundant with the check x < min\n                    return 0;\n                }\n            }\n            assert x >= mean[0];\n\n            // and the right tail\n            if (x > mean[n - 1]) {\n                if (max - mean[n - 1] > 0) {\n                    if (x == max) {\n                        return 1 - 0.5 / totalWeight;\n                    } else {\n                        // there has to be a single sample exactly at max\n                        double dq = (1 + (max - x) / (max - mean[n - 1]) * (weight[n - 1] / 2 - 1)) / totalWeight;\n                        return 1 - dq;\n                    }\n                } else {\n                    return 1;\n                }\n            }\n\n            // we know that there are at least two centroids and mean[0] < x < mean[n-1]\n            // that means that there are either one or more consecutive centroids all at exactly x\n            // or there are consecutive centroids, c0 < x < c1\n            double weightSoFar = 0;\n            for (int it = 0; it < n - 1; it++) {\n                // weightSoFar does not include weight[it] yet\n                if (mean[it] == x) {\n                    // we have one or more centroids == x, treat them as one\n                    // dw will accumulate the weight of all of the centroids at x\n                    double dw = 0;\n                    while (it < n && mean[it] == x) {\n                        dw += weight[it];\n                        it++;\n                    }\n                    return (weightSoFar + dw / 2) / totalWeight;\n                } else if (mean[it] <= x && x < mean[it + 1]) {\n                    // landed between centroids ... check for floating point madness\n                    if (mean[it + 1] - mean[it] > 0) {\n                        // note how we handle singleton centroids here\n                        // the point is that for singleton centroids, we know that their entire\n                        // weight is exactly at the centroid and thus shouldn't be involved in\n                        // interpolation\n                        double leftExcludedW = 0;\n                        double rightExcludedW = 0;\n                        if (weight[it] == 1) {\n                            if (weight[it + 1] == 1) {\n                                // two singletons means no interpolation\n                                // left singleton is in, right is out\n                                return (weightSoFar + 1) / totalWeight;\n                            } else {\n                                leftExcludedW = 0.5;\n                            }\n                        } else if (weight[it + 1] == 1) {\n                            rightExcludedW = 0.5;\n                        }\n                        double dw = (weight[it] + weight[it + 1]) / 2;\n\n                        // can't have double singleton (handled that earlier)\n                        assert dw > 1;\n                        assert (leftExcludedW + rightExcludedW) <= 0.5;\n\n                        // adjust endpoints for any singleton\n                        double left = mean[it];\n                        double right = mean[it + 1];\n\n                        double dwNoSingleton = dw - leftExcludedW - rightExcludedW;\n\n                        // adjustments have only limited effect on endpoints\n                        assert dwNoSingleton > dw / 2;\n                        assert right - left > 0;\n                        double base = weightSoFar + weight[it] / 2 + leftExcludedW;\n                        return (base + dwNoSingleton * (x - left) / (right - left)) / totalWeight;\n                    } else {\n                        // this is simply caution against floating point madness\n                        // it is conceivable that the centroids will be different\n                        // but too near to allow safe interpolation\n                        double dw = (weight[it] + weight[it + 1]) / 2;\n                        return (weightSoFar + dw) / totalWeight;\n                    }\n                } else {\n                    weightSoFar += weight[it];\n                }\n            }\n            if (x == mean[n - 1]) {\n                return 1 - 0.5 / totalWeight;\n            } else {\n                throw new IllegalStateException(\"Can't happen ... loop fell through\");\n            }\n        }\n    }\n\n    @Override\n    public double quantile(double q) {\n        if (q < 0 || q > 1) {\n            throw new IllegalArgumentException(\"q should be in [0,1], got \" + q);\n        }\n        mergeNewValues();\n\n        if (lastUsedCell.get() == 0) {\n            // no centroids means no data, no way to get a quantile\n            return Double.NaN;\n        } else if (lastUsedCell.get() == 1) {\n            // with one data point, all quantiles lead to Rome\n            return mean[0];\n        }\n\n        // we know that there are at least two centroids now\n        int n = lastUsedCell.get();\n\n        // if values were stored in a sorted array, index would be the offset we are interested in\n        final double index = q * totalWeight;\n\n        // beyond the boundaries, we return min or max\n        // usually, the first centroid will have unit weight so this will make it moot\n        if (index < 1) {\n            return min;\n        }\n\n        // if the left centroid has more than one sample, we still know\n        // that one sample occurred at min so we can do some interpolation\n        if (weight[0] > 1 && index < weight[0] / 2) {\n            // there is a single sample at min so we interpolate with less weight\n            return min + (index - 1) / (weight[0] / 2 - 1) * (mean[0] - min);\n        }\n\n        // usually the last centroid will have unit weight so this test will make it moot\n        if (index > totalWeight - 1) {\n            return max;\n        }\n\n        // if the right-most centroid has more than one sample, we still know\n        // that one sample occurred at max so we can do some interpolation\n        if (weight[n - 1] > 1 && totalWeight - index <= weight[n - 1] / 2) {\n            return max - (totalWeight - index - 1) / (weight[n - 1] / 2 - 1) * (max - mean[n - 1]);\n        }\n\n        // in between extremes we interpolate between centroids\n        double weightSoFar = weight[0] / 2;\n        for (int i = 0; i < n - 1; i++) {\n            double dw = (weight[i] + weight[i + 1]) / 2;\n            if (weightSoFar + dw > index) {\n                // centroids i and i+1 bracket our current point\n\n                // check for unit weight\n                double leftUnit = 0;\n                if (weight[i] == 1) {\n                    if (index - weightSoFar < 0.5) {\n                        // within the singleton's sphere\n                        return mean[i];\n                    } else {\n                        leftUnit = 0.5;\n                    }\n                }\n                double rightUnit = 0;\n                if (weight[i + 1] == 1) {\n                    if (weightSoFar + dw - index <= 0.5) {\n                        // no interpolation needed near singleton\n                        return mean[i + 1];\n                    }\n                    rightUnit = 0.5;\n                }\n                double z1 = index - weightSoFar - leftUnit;\n                double z2 = weightSoFar + dw - index - rightUnit;\n                return weightedAverage(mean[i], z2, mean[i + 1], z1);\n            }\n            weightSoFar += dw;\n        }\n        // we handled singleton at end up above\n        assert weight[n - 1] > 1;\n        assert index <= totalWeight;\n        assert index >= totalWeight - weight[n - 1] / 2;\n\n        // weightSoFar = totalWeight - weight[n-1]/2 (very nearly)\n        // so we interpolate out to max value ever seen\n        double z1 = index - totalWeight - weight[n - 1] / 2.0;\n        double z2 = weight[n - 1] / 2 - z1;\n        return weightedAverage(mean[n - 1], z1, max, z2);\n    }\n\n    @Override\n    public int centroidCount() {\n        mergeNewValues();\n        return lastUsedCell.get();\n    }\n\n    @Override\n    public Collection<Centroid> centroids() {\n        // we don't actually keep centroid structures around so we have to fake it\n        compress();\n        return new AbstractCollection<Centroid>() {\n            @Override\n            public Iterator<Centroid> iterator() {\n                return new Iterator<Centroid>() {\n                    int i = 0;\n\n                    @Override\n                    public boolean hasNext() {\n                        return i < lastUsedCell.get();\n                    }\n\n                    @Override\n                    public Centroid next() {\n                        if (!hasNext()) {\n                            throw new NoSuchElementException();\n                        }\n                        Centroid rc = new Centroid(mean[i], (int) weight[i]);\n                        List<Double> datas = data != null ? data.get(i) : null;\n                        if (datas != null) {\n                            datas.forEach(rc::insertData);\n                        }\n                        i++;\n                        return rc;\n                    }\n\n                    @Override\n                    public void remove() {\n                        throw new UnsupportedOperationException(\"Default operation\");\n                    }\n                };\n            }\n\n            @Override\n            public int size() {\n                return lastUsedCell.get();\n            }\n        };\n    }\n\n    @Override\n    public double compression() {\n        return publicCompression;\n    }\n\n    @Override\n    public int byteSize() {\n        compress();\n        // format code, compression(float), buffer-size(int), temp-size(int), #centroids-1(int),\n        // then two doubles per centroid\n        return lastUsedCell.get() * 16 + 32;\n    }\n\n    @Override\n    public int smallByteSize() {\n        compress();\n        // format code(int), compression(float), buffer-size(short), temp-size(short), #centroids-1(short),\n        // then two floats per centroid\n        return lastUsedCell.get() * 8 + 30;\n    }\n\n    @SuppressWarnings(\"WeakerAccess\")\n    public ScaleFunction getScaleFunction() {\n        return scale;\n    }\n\n    @Override\n    public void setScaleFunction(ScaleFunction scaleFunction) {\n        super.setScaleFunction(scaleFunction);\n    }\n\n    public enum Encoding {\n        VERBOSE_ENCODING(1), SMALL_ENCODING(2);\n\n        private final int code;\n\n        Encoding(int code) {\n            this.code = code;\n        }\n    }\n\n    @Override\n    public void asBytes(ByteBuffer buf) {\n        compress();\n        buf.putInt(DubboMergingDigest.Encoding.VERBOSE_ENCODING.code);\n        buf.putDouble(min);\n        buf.putDouble(max);\n        buf.putDouble(publicCompression);\n        buf.putInt(lastUsedCell.get());\n        for (int i = 0; i < lastUsedCell.get(); i++) {\n            buf.putDouble(weight[i]);\n            buf.putDouble(mean[i]);\n        }\n    }\n\n    @Override\n    public void asSmallBytes(ByteBuffer buf) {\n        compress();\n        buf.putInt(DubboMergingDigest.Encoding.SMALL_ENCODING.code);    // 4\n        buf.putDouble(min);                          // + 8\n        buf.putDouble(max);                          // + 8\n        buf.putFloat((float) publicCompression);           // + 4\n        buf.putShort((short) mean.length);           // + 2\n        buf.putShort((short) tempMean.length);       // + 2\n        buf.putShort((short) lastUsedCell.get());          // + 2 = 30\n        for (int i = 0; i < lastUsedCell.get(); i++) {\n            buf.putFloat((float) weight[i]);\n            buf.putFloat((float) mean[i]);\n        }\n    }\n\n    @Override\n    public String toString() {\n        return \"MergingDigest\"\n            + \"-\" + getScaleFunction()\n            + \"-\" + (useWeightLimit ? \"weight\" : \"kSize\")\n            + \"-\" + (useAlternatingSort ? \"alternating\" : \"stable\")\n            + \"-\" + (useTwoLevelCompression ? \"twoLevel\" : \"oneLevel\");\n    }\n\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/Pane.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\n/**\n * The pane represents a window over a period of time.\n *\n * @param <T> The type of value the pane statistics.\n */\npublic class Pane<T> {\n\n    /**\n     * Time interval of the pane in milliseconds.\n     */\n    private final long intervalInMs;\n\n    /**\n     * Start timestamp of the pane in milliseconds.\n     */\n    private volatile long startInMs;\n\n    /**\n     * End timestamp of the pane in milliseconds.\n     * <p>\n     * endInMs = startInMs + intervalInMs\n     */\n    private volatile long endInMs;\n\n    /**\n     * Pane statistics value.\n     */\n    private T value;\n\n    /**\n     * @param intervalInMs interval of the pane in milliseconds.\n     * @param startInMs    start timestamp of the pane in milliseconds.\n     * @param value        the pane value.\n     */\n    public Pane(long intervalInMs, long startInMs, T value) {\n        this.intervalInMs = intervalInMs;\n        this.startInMs = startInMs;\n        this.endInMs = this.startInMs + this.intervalInMs;\n        this.value = value;\n    }\n\n    /**\n     * Get the interval of the pane in milliseconds.\n     *\n     * @return the interval of the pane in milliseconds.\n     */\n    public long getIntervalInMs() {\n        return this.intervalInMs;\n    }\n\n    /**\n     * Get start timestamp of the pane in milliseconds.\n     *\n     * @return the start timestamp of the pane in milliseconds.\n     */\n    public long getStartInMs() {\n        return this.startInMs;\n    }\n\n    /**\n     * Get end timestamp of the pane in milliseconds.\n     *\n     * @return the end timestamp of the pane in milliseconds.\n     */\n    public long getEndInMs() {\n        return this.endInMs;\n    }\n\n    /**\n     * Get the pane statistics value.\n     *\n     * @return the pane statistics value.\n     */\n    public T getValue() {\n        return this.value;\n    }\n\n    /**\n     * Set the new start timestamp to the pane, for reset the instance.\n     *\n     * @param newStartInMs the new start timestamp.\n     */\n    public void setStartInMs(long newStartInMs) {\n        this.startInMs = newStartInMs;\n        this.endInMs = this.startInMs + this.intervalInMs;\n    }\n\n    /**\n     * Set new value to the pane, for reset the instance.\n     *\n     * @param newData the new value.\n     */\n    public void setValue(T newData) {\n        this.value = newData;\n    }\n\n    /**\n     * Check whether given timestamp is in current pane.\n     *\n     * @param timeMillis timestamp in milliseconds.\n     * @return true if the given time is in current pane, otherwise false\n     */\n    public boolean isTimeInWindow(long timeMillis) {\n        // [)\n        return startInMs <= timeMillis && timeMillis < endInMs;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/SampleAggregatedEntry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\npublic class SampleAggregatedEntry {\n\n    private Long count;\n    private double max;\n    private double min;\n    private double avg;\n    private double total;\n\n    public Long getCount() {\n        return count;\n    }\n\n    public void setCount(Long count) {\n        this.count = count;\n    }\n\n    public double getMax() {\n        return max;\n    }\n\n    public void setMax(double max) {\n        this.max = max;\n    }\n\n    public double getMin() {\n        return min;\n    }\n\n    public void setMin(double min) {\n        this.min = min;\n    }\n\n    public double getAvg() {\n        return avg;\n    }\n\n    public void setAvg(double avg) {\n        this.avg = avg;\n    }\n\n    public double getTotal() {\n        return total;\n    }\n\n    public void setTotal(double total) {\n        this.total = total;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/SlidingWindow.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\nimport org.apache.dubbo.common.utils.Assert;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReferenceArray;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * SlidingWindow adopts sliding window algorithm for statistics.\n * <p>\n * A window contains {@code paneCount} panes,\n * {@code intervalInMs} = {@code paneCount} * {@code paneIntervalInMs}\n *\n * @param <T> Value type for window statistics.\n */\npublic abstract class SlidingWindow<T> {\n\n    /**\n     * The number of panes the sliding window contains.\n     */\n    protected int paneCount;\n\n    /**\n     * Total time interval of the sliding window in milliseconds.\n     */\n    protected long intervalInMs;\n\n    /**\n     * Time interval of a pane in milliseconds.\n     */\n    protected long paneIntervalInMs;\n\n    /**\n     * The panes reference, supports atomic operations.\n     */\n    protected final AtomicReferenceArray<Pane<T>> referenceArray;\n\n    /**\n     * The lock is used only when current pane is deprecated.\n     */\n    private final ReentrantLock updateLock = new ReentrantLock();\n\n    protected SlidingWindow(int paneCount, long intervalInMs) {\n        Assert.assertTrue(paneCount > 0, \"pane count is invalid: \" + paneCount);\n        Assert.assertTrue(intervalInMs > 0, \"total time interval of the sliding window should be positive\");\n        Assert.assertTrue(intervalInMs % paneCount == 0, \"total time interval needs to be evenly divided\");\n\n        this.paneCount = paneCount;\n        this.intervalInMs = intervalInMs;\n        this.paneIntervalInMs = intervalInMs / paneCount;\n        this.referenceArray = new AtomicReferenceArray<>(paneCount);\n    }\n\n    /**\n     * Get the pane at the current timestamp.\n     *\n     * @return the pane at current timestamp.\n     */\n    public Pane<T> currentPane() {\n        return currentPane(System.currentTimeMillis());\n    }\n\n    /**\n     * Get the pane at the specified timestamp in milliseconds.\n     *\n     * @param timeMillis a timestamp in milliseconds.\n     * @return the pane at the specified timestamp if the time is valid; null if time is invalid.\n     */\n    public Pane<T> currentPane(long timeMillis) {\n        if (timeMillis < 0) {\n            return null;\n        }\n\n        int paneIdx = calculatePaneIdx(timeMillis);\n        long paneStartInMs = calculatePaneStart(timeMillis);\n\n        while (true) {\n            Pane<T> oldPane = referenceArray.get(paneIdx);\n\n            // Create a pane instance when the pane does not exist.\n            if (oldPane == null) {\n                Pane<T> pane = new Pane<>(paneIntervalInMs, paneStartInMs, newEmptyValue(timeMillis));\n                if (referenceArray.compareAndSet(paneIdx, null, pane)) {\n                    return pane;\n                } else {\n                    // Contention failed, the thread will yield its time slice to wait for pane available.\n                    Thread.yield();\n                }\n            }\n            //\n            else if (paneStartInMs == oldPane.getStartInMs()) {\n                return oldPane;\n            }\n            // The pane has deprecated. To avoid the overhead of creating a new instance, reset the original pane\n            // directly.\n            else if (paneStartInMs > oldPane.getStartInMs()) {\n                if (updateLock.tryLock()) {\n                    try {\n                        return resetPaneTo(oldPane, paneStartInMs);\n                    } finally {\n                        updateLock.unlock();\n                    }\n                } else {\n                    // Contention failed, the thread will yield its time slice to wait for pane available.\n                    Thread.yield();\n                }\n            }\n            // The specified timestamp has passed.\n            else if (paneStartInMs < oldPane.getStartInMs()) {\n                return new Pane<>(paneIntervalInMs, paneStartInMs, newEmptyValue(timeMillis));\n            }\n        }\n    }\n\n    /**\n     * Get statistic value from pane at the specified timestamp.\n     *\n     * @param timeMillis the specified timestamp in milliseconds.\n     * @return the statistic value if pane at the specified timestamp is up-to-date; otherwise null.\n     */\n    public T getPaneValue(long timeMillis) {\n        if (timeMillis < 0) {\n            return null;\n        }\n\n        int paneIdx = calculatePaneIdx(timeMillis);\n\n        Pane<T> pane = referenceArray.get(paneIdx);\n\n        if (pane == null || !pane.isTimeInWindow(timeMillis)) {\n            return null;\n        }\n\n        return pane.getValue();\n    }\n\n    /**\n     * Create a new statistic value for pane.\n     *\n     * @param timeMillis the specified timestamp in milliseconds.\n     * @return new empty statistic value.\n     */\n    public abstract T newEmptyValue(long timeMillis);\n\n    /**\n     * Reset given pane to the specified start time and reset the value.\n     *\n     * @param pane      the given pane.\n     * @param startInMs the start timestamp of the pane in milliseconds.\n     * @return reset pane.\n     */\n    protected abstract Pane<T> resetPaneTo(final Pane<T> pane, long startInMs);\n\n    /**\n     * Calculate the pane index corresponding to the specified timestamp.\n     *\n     * @param timeMillis the specified timestamp.\n     * @return the pane index corresponding to the specified timestamp.\n     */\n    private int calculatePaneIdx(long timeMillis) {\n        return (int) ((timeMillis / paneIntervalInMs) % paneCount);\n    }\n\n    /**\n     * Calculate the pane start corresponding to the specified timestamp.\n     *\n     * @param timeMillis the specified timestamp.\n     * @return the pane start corresponding to the specified timestamp.\n     */\n    protected long calculatePaneStart(long timeMillis) {\n        return timeMillis - timeMillis % paneIntervalInMs;\n    }\n\n    /**\n     * Checks if the specified pane is deprecated at the current timestamp.\n     *\n     * @param pane the specified pane.\n     * @return true if the pane is deprecated; otherwise false.\n     */\n    public boolean isPaneDeprecated(final Pane<T> pane) {\n        return isPaneDeprecated(System.currentTimeMillis(), pane);\n    }\n\n    /**\n     * Checks if the specified pane is deprecated at the specified timestamp.\n     *\n     * @param timeMillis the specified time.\n     * @param pane       the specified pane.\n     * @return true if the pane is deprecated; otherwise false.\n     */\n    public boolean isPaneDeprecated(long timeMillis, final Pane<T> pane) {\n        // the pane is '[)'\n        return (timeMillis - pane.getStartInMs()) > intervalInMs;\n    }\n\n    /**\n     * Get valid pane list for entire sliding window at the current time.\n     * The list will only contain \"valid\" panes.\n     *\n     * @return valid pane list for entire sliding window.\n     */\n    public List<Pane<T>> list() {\n        return list(System.currentTimeMillis());\n    }\n\n    /**\n     * Get valid pane list for entire sliding window at the specified time.\n     * The list will only contain \"valid\" panes.\n     *\n     * @param timeMillis the specified time.\n     * @return valid pane list for entire sliding window.\n     */\n    public List<Pane<T>> list(long timeMillis) {\n        if (timeMillis < 0) {\n            return new ArrayList<>();\n        }\n\n        List<Pane<T>> result = new ArrayList<>(paneCount);\n\n        for (int idx = 0; idx < paneCount; idx++) {\n            Pane<T> pane = referenceArray.get(idx);\n            if (pane == null || isPaneDeprecated(timeMillis, pane)) {\n                continue;\n            }\n            result.add(pane);\n        }\n\n        return result;\n    }\n\n    /**\n     * Get aggregated value list for entire sliding window at the current time.\n     * The list will only contain value from \"valid\" panes.\n     *\n     * @return aggregated value list for entire sliding window.\n     */\n    public List<T> values() {\n        return values(System.currentTimeMillis());\n    }\n\n    /**\n     * Get aggregated value list for entire sliding window at the specified time.\n     * The list will only contain value from \"valid\" panes.\n     *\n     * @return aggregated value list for entire sliding window.\n     */\n    public List<T> values(long timeMillis) {\n        if (timeMillis < 0) {\n            return new ArrayList<>();\n        }\n\n        List<T> result = new ArrayList<>(paneCount);\n\n        for (int idx = 0; idx < paneCount; idx++) {\n            Pane<T> pane = referenceArray.get(idx);\n            if (pane == null || isPaneDeprecated(timeMillis, pane)) {\n                continue;\n            }\n            result.add(pane.getValue());\n        }\n        return result;\n    }\n\n    /**\n     * Get total interval of the sliding window in milliseconds.\n     *\n     * @return the total interval in milliseconds.\n     */\n    public long getIntervalInMs() {\n        return intervalInMs;\n    }\n\n    /**\n     * Get pane interval of the sliding window in milliseconds.\n     *\n     * @return the interval of a pane in milliseconds.\n     */\n    public long getPaneIntervalInMs() {\n        return paneIntervalInMs;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/TimeWindowAggregator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.concurrent.atomic.DoubleAccumulator;\nimport java.util.concurrent.atomic.LongAdder;\n\npublic class TimeWindowAggregator {\n\n    private final SnapshotSlidingWindow slidingWindow;\n\n    public TimeWindowAggregator(int bucketNum, int timeWindowSeconds) {\n        this.slidingWindow = new SnapshotSlidingWindow(bucketNum, TimeUnit.SECONDS.toMillis(timeWindowSeconds));\n    }\n\n    public SnapshotSlidingWindow getSlidingWindow() {\n        return slidingWindow;\n    }\n\n    public void add(double value) {\n        SnapshotObservation sample = this.slidingWindow.currentPane().getValue();\n        sample.add(value);\n    }\n\n    public SampleAggregatedEntry get() {\n        SampleAggregatedEntry aggregatedEntry = new SampleAggregatedEntry();\n\n        double total = 0L;\n        long count = 0;\n        double max = Double.MIN_VALUE;\n        double min = Double.MAX_VALUE;\n\n        List<SnapshotObservation> windows = this.slidingWindow.values();\n\n        for (SnapshotObservation window : windows) {\n            total += window.getTotal();\n            count += window.getCount();\n\n            max = Math.max(max, window.getMax());\n            min = Math.min(min, window.getMin());\n        }\n\n        if (count > 0) {\n            double avg = total / count;\n            aggregatedEntry.setAvg(Math.round(avg * 100.0) / 100.0);\n        } else {\n            aggregatedEntry.setAvg(0);\n        }\n\n        aggregatedEntry.setMax(max == Double.MIN_VALUE ? 0 : max);\n        aggregatedEntry.setMin(min == Double.MAX_VALUE ? 0 : min);\n        aggregatedEntry.setTotal(total);\n        aggregatedEntry.setCount(count);\n\n        return aggregatedEntry;\n    }\n\n    public static class SnapshotSlidingWindow extends SlidingWindow<SnapshotObservation> {\n\n        public SnapshotSlidingWindow(int sampleCount, long intervalInMs) {\n            super(sampleCount, intervalInMs);\n        }\n\n        @Override\n        public SnapshotObservation newEmptyValue(long timeMillis) {\n            return new SnapshotObservation();\n        }\n\n        @Override\n        protected Pane<SnapshotObservation> resetPaneTo(final Pane<SnapshotObservation> pane, long startTime) {\n            pane.setStartInMs(startTime);\n            pane.getValue().reset();\n            return pane;\n        }\n    }\n\n    public static class SnapshotObservation {\n\n        private final AtomicReference<Double> min = new AtomicReference<>(Double.MAX_VALUE);\n        private final AtomicReference<Double> max = new AtomicReference<>(0d);\n        private final DoubleAccumulator total = new DoubleAccumulator((x, y) -> x + y, 0);\n        private final LongAdder count = new LongAdder();\n\n        public void add(double sample) {\n            total.accumulate(sample);\n            count.increment();\n            updateMin(sample);\n            updateMax(sample);\n        }\n\n        private void updateMin(double sample) {\n            Double curMin;\n            do {\n                curMin = min.get();\n            } while (sample < curMin && !min.compareAndSet(curMin, sample));\n        }\n\n        private void updateMax(double sample) {\n            Double curMax;\n            do {\n                curMax = max.get();\n                if (sample <= curMax) {\n                    return;\n                }\n\n            } while (!max.compareAndSet(curMax, sample));\n        }\n\n        public void reset() {\n            min.set(Double.MAX_VALUE);\n            max.set(0d);\n            count.reset();\n            total.reset();\n        }\n\n        public double getMin() {\n            return min.get();\n        }\n\n        public double getMax() {\n            return max.get();\n        }\n\n        public Double getTotal() {\n            return total.get();\n        }\n\n        public long getCount() {\n            return count.sum();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/TimeWindowCounter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.LongAdder;\n\n/**\n * Wrapper around Counter like Long and Integer.\n */\npublic class TimeWindowCounter {\n\n    private final LongAdderSlidingWindow slidingWindow;\n\n    public TimeWindowCounter(int bucketNum, long timeWindowSeconds) {\n        this.slidingWindow = new LongAdderSlidingWindow(bucketNum, TimeUnit.SECONDS.toMillis(timeWindowSeconds));\n    }\n\n    public double get() {\n        double result = 0.0;\n        List<LongAdder> windows = this.slidingWindow.values();\n        for (LongAdder window : windows) {\n            result += window.sum();\n        }\n        return result;\n    }\n\n    public long bucketLivedSeconds() {\n        return TimeUnit.MILLISECONDS.toSeconds(\n                this.slidingWindow.values().size() * this.slidingWindow.getPaneIntervalInMs());\n    }\n\n    public long bucketLivedMillSeconds() {\n        return this.slidingWindow.getIntervalInMs()\n                - (System.currentTimeMillis() - this.slidingWindow.currentPane().getEndInMs());\n    }\n\n    public void increment() {\n        this.increment(1L);\n    }\n\n    public void increment(Long step) {\n        this.slidingWindow.currentPane().getValue().add(step);\n    }\n\n    public void decrement() {\n        this.decrement(1L);\n    }\n\n    public void decrement(Long step) {\n        this.slidingWindow.currentPane().getValue().add(-step);\n    }\n\n    /**\n     * Sliding window of type LongAdder.\n     */\n    private static class LongAdderSlidingWindow extends SlidingWindow<LongAdder> {\n\n        public LongAdderSlidingWindow(int sampleCount, long intervalInMs) {\n            super(sampleCount, intervalInMs);\n        }\n\n        @Override\n        public LongAdder newEmptyValue(long timeMillis) {\n            return new LongAdder();\n        }\n\n        @Override\n        protected Pane<LongAdder> resetPaneTo(final Pane<LongAdder> pane, long startTime) {\n            pane.setStartInMs(startTime);\n            pane.getValue().reset();\n            return pane;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/TimeWindowQuantile.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport com.tdunning.math.stats.TDigest;\n\n/**\n * Wrapper around TDigest.\n */\npublic class TimeWindowQuantile {\n\n    private final double compression;\n\n    private final DigestSlidingWindow slidingWindow;\n\n    public TimeWindowQuantile(double compression, int bucketNum, int timeWindowSeconds) {\n        this.compression = compression;\n        this.slidingWindow =\n                new DigestSlidingWindow(compression, bucketNum, TimeUnit.SECONDS.toMillis(timeWindowSeconds));\n    }\n\n    public double quantile(double q) {\n        TDigest mergeDigest = new DubboMergingDigest(compression);\n        List<TDigest> validWindows = this.slidingWindow.values();\n        for (TDigest window : validWindows) {\n            mergeDigest.add(window);\n        }\n        // This may return Double.NaN, and it's correct behavior.\n        // see: https://github.com/prometheus/client_golang/issues/85\n        return mergeDigest.quantile(q);\n    }\n\n    public void add(double value) {\n        this.slidingWindow.currentPane().getValue().add(value);\n    }\n\n    /**\n     * Sliding window of type TDigest.\n     */\n    private static class DigestSlidingWindow extends SlidingWindow<TDigest> {\n\n        private final double compression;\n\n        public DigestSlidingWindow(double compression, int sampleCount, long intervalInMs) {\n            super(sampleCount, intervalInMs);\n            this.compression = compression;\n        }\n\n        @Override\n        public TDigest newEmptyValue(long timeMillis) {\n            return new DubboMergingDigest(compression);\n        }\n\n        @Override\n        protected Pane<TDigest> resetPaneTo(final Pane<TDigest> pane, long startTime) {\n            pane.setStartInMs(startTime);\n            pane.setValue(new DubboMergingDigest(compression));\n            return pane;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/ApplicationMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\n\n/**\n * Application-level collector.\n * registration center, configuration center and other scenarios\n *\n * @Params <T>  metrics type\n */\npublic interface ApplicationMetricsCollector<E extends TimeCounterEvent> extends MetricsCollector<E> {\n\n    void increment(MetricsKey metricsKey);\n\n    void addApplicationRt(String registryOpType, Long responseTime);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/CombMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.metrics.data.BaseStatComposite;\nimport org.apache.dubbo.metrics.event.MetricsEventMulticaster;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.listener.AbstractMetricsListener;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.Invocation;\n\nimport java.util.List;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE;\n\npublic abstract class CombMetricsCollector<E extends TimeCounterEvent> extends AbstractMetricsListener<E>\n        implements ApplicationMetricsCollector<E>, ServiceMetricsCollector<E>, MethodMetricsCollector<E> {\n\n    protected final BaseStatComposite stats;\n    private MetricsEventMulticaster eventMulticaster;\n\n    public CombMetricsCollector(BaseStatComposite stats) {\n        this.stats = stats;\n    }\n\n    protected void setEventMulticaster(MetricsEventMulticaster eventMulticaster) {\n        this.eventMulticaster = eventMulticaster;\n    }\n\n    @Override\n    public void setNum(MetricsKeyWrapper metricsKey, String serviceKey, int num) {\n        this.stats.setServiceKey(metricsKey, serviceKey, num);\n    }\n\n    @Override\n    public void increment(MetricsKey metricsKey) {\n        this.stats.incrementApp(metricsKey, SELF_INCREMENT_SIZE);\n    }\n\n    public void increment(String serviceKey, MetricsKeyWrapper metricsKeyWrapper, int size) {\n        this.stats.incrementServiceKey(metricsKeyWrapper, serviceKey, size);\n    }\n\n    @Override\n    public void addApplicationRt(String registryOpType, Long responseTime) {\n        stats.calcApplicationRt(registryOpType, responseTime);\n    }\n\n    @Override\n    public void addServiceRt(String serviceKey, String registryOpType, Long responseTime) {\n        stats.calcServiceKeyRt(serviceKey, registryOpType, responseTime);\n    }\n\n    @Override\n    public void addServiceRt(Invocation invocation, String registryOpType, Long responseTime) {\n        stats.calcServiceKeyRt(invocation, registryOpType, responseTime);\n    }\n\n    @Override\n    public void addMethodRt(Invocation invocation, String registryOpType, Long responseTime) {\n        stats.calcMethodKeyRt(invocation, registryOpType, responseTime);\n    }\n\n    public void setAppNum(MetricsKey metricsKey, Long num) {\n        stats.setAppKey(metricsKey, num);\n    }\n\n    @Override\n    public void increment(MethodMetric methodMetric, MetricsKeyWrapper wrapper, int size) {\n        this.stats.incrementMethodKey(wrapper, methodMetric, size);\n    }\n\n    @Override\n    public void init(Invocation invocation, MetricsKeyWrapper wrapper) {\n        this.stats.initMethodKey(wrapper, invocation);\n    }\n\n    protected List<MetricSample> export(MetricsCategory category) {\n        return stats.export(category);\n    }\n\n    public MetricsEventMulticaster getEventMulticaster() {\n        return eventMulticaster;\n    }\n\n    @Override\n    public void onEvent(TimeCounterEvent event) {\n        eventMulticaster.publishEvent(event);\n    }\n\n    @Override\n    public void onEventFinish(TimeCounterEvent event) {\n        eventMulticaster.publishFinishEvent(event);\n    }\n\n    @Override\n    public void onEventError(TimeCounterEvent event) {\n        eventMulticaster.publishErrorEvent(event);\n    }\n\n    protected BaseStatComposite getStats() {\n        return stats;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/MethodMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.rpc.Invocation;\n\n/**\n * Method-level metrics collection for rpc invocation scenarios\n */\npublic interface MethodMetricsCollector<E extends TimeCounterEvent> extends MetricsCollector<E> {\n\n    void increment(MethodMetric methodMetric, MetricsKeyWrapper wrapper, int size);\n\n    void addMethodRt(Invocation invocation, String registryOpType, Long responseTime);\n\n    void init(Invocation invocation, MetricsKeyWrapper wrapper);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/MetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.metrics.event.MetricsEvent;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.listener.MetricsLifeListener;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.List;\n\n/**\n * Metrics Collector.\n * An interface of collector to collect framework internal metrics.\n */\n@SPI\npublic interface MetricsCollector<E extends TimeCounterEvent> extends MetricsLifeListener<E> {\n\n    default boolean isCollectEnabled() {\n        return false;\n    }\n\n    /**\n     * Collect metrics as {@link MetricSample}\n     *\n     * @return List of MetricSample\n     */\n    List<MetricSample> collect();\n\n    /**\n     * Check if samples have been changed.\n     * Note that this method will reset the changed flag to false using CAS.\n     *\n     * @return true if samples have been changed\n     */\n    boolean calSamplesChanged();\n\n    default void initMetrics(MetricsEvent event) {}\n    ;\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/ServiceMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.rpc.Invocation;\n\n/**\n * Service-level collector.\n * registration center, configuration center and other scenarios\n */\npublic interface ServiceMetricsCollector<E extends TimeCounterEvent> extends MetricsCollector<E> {\n\n    void increment(String serviceKey, MetricsKeyWrapper wrapper, int size);\n\n    void setNum(MetricsKeyWrapper metricsKey, String serviceKey, int num);\n\n    void addServiceRt(String serviceKey, String registryOpType, Long responseTime);\n\n    void addServiceRt(Invocation invocation, String registryOpType, Long responseTime);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/stat/MetricsStatHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.stat;\n\nimport org.apache.dubbo.metrics.event.MetricsEvent;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.rpc.Invocation;\n\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic interface MetricsStatHandler {\n    Map<MethodMetric, AtomicLong> get();\n\n    MetricsEvent increase(String applicationName, Invocation invocation);\n\n    MetricsEvent decrease(String applicationName, Invocation invocation);\n\n    MetricsEvent addApplication(String applicationName);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/ApplicationStatComposite.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.data;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.report.AbstractMetricsExport;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Application-level data container, for the initialized MetricsKey,\n * different from the null value of the Map type (the key is not displayed when there is no data),\n * the key is displayed and the initial data is 0 value of the AtomicLong type\n */\npublic class ApplicationStatComposite extends AbstractMetricsExport {\n\n    public ApplicationStatComposite(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    private final Map<MetricsKey, AtomicLong> applicationNumStats = new ConcurrentHashMap<>();\n\n    private final AtomicBoolean samplesChanged = new AtomicBoolean(true);\n\n    public void init(List<MetricsKey> appKeys) {\n        if (CollectionUtils.isEmpty(appKeys)) {\n            return;\n        }\n        appKeys.forEach(appKey -> {\n            applicationNumStats.put(appKey, new AtomicLong(0L));\n        });\n        samplesChanged.set(true);\n    }\n\n    public void incrementSize(MetricsKey metricsKey, int size) {\n        if (!applicationNumStats.containsKey(metricsKey)) {\n            return;\n        }\n        applicationNumStats.get(metricsKey).getAndAdd(size);\n    }\n\n    public void setAppKey(MetricsKey metricsKey, Long num) {\n        if (!applicationNumStats.containsKey(metricsKey)) {\n            return;\n        }\n        applicationNumStats.get(metricsKey).set(num);\n    }\n\n    public List<MetricSample> export(MetricsCategory category) {\n        List<MetricSample> list = new ArrayList<>();\n        for (MetricsKey type : applicationNumStats.keySet()) {\n            list.add(convertToSample(type, category, applicationNumStats.get(type)));\n        }\n        return list;\n    }\n\n    @SuppressWarnings({\"rawtypes\"})\n    private GaugeMetricSample convertToSample(MetricsKey type, MetricsCategory category, AtomicLong targetNumber) {\n        return new GaugeMetricSample<>(\n                type, MetricsSupport.applicationTags(getApplicationModel()), category, targetNumber, AtomicLong::get);\n    }\n\n    public Map<MetricsKey, AtomicLong> getApplicationNumStats() {\n        return applicationNumStats;\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // CAS to get and reset the flag in an atomic operation\n        return samplesChanged.compareAndSet(true, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/BaseStatComposite.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.data;\n\nimport org.apache.dubbo.metrics.collector.MetricsCollector;\nimport org.apache.dubbo.metrics.model.ApplicationMetric;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.ServiceKeyMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.report.MetricsExport;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * As a data aggregator, use internal data containers calculates and classifies\n * the registry data collected by {@link MetricsCollector MetricsCollector}, and\n * provides an {@link MetricsExport MetricsExport} interface for exporting standard output formats.\n */\npublic abstract class BaseStatComposite implements MetricsExport {\n\n    private ApplicationStatComposite applicationStatComposite;\n    private ServiceStatComposite serviceStatComposite;\n\n    private MethodStatComposite methodStatComposite;\n    private RtStatComposite rtStatComposite;\n\n    public BaseStatComposite(ApplicationModel applicationModel) {\n        init(new ApplicationStatComposite(applicationModel));\n        init(new ServiceStatComposite(applicationModel));\n        init(new MethodStatComposite(applicationModel));\n        init(new RtStatComposite(applicationModel));\n    }\n\n    protected void init(ApplicationStatComposite applicationStatComposite) {\n        this.applicationStatComposite = applicationStatComposite;\n    }\n\n    protected void init(ServiceStatComposite serviceStatComposite) {\n        this.serviceStatComposite = serviceStatComposite;\n    }\n\n    protected void init(MethodStatComposite methodStatComposite) {\n        this.methodStatComposite = methodStatComposite;\n    }\n\n    protected void init(RtStatComposite rtStatComposite) {\n        this.rtStatComposite = rtStatComposite;\n    }\n\n    public void calcApplicationRt(String registryOpType, Long responseTime) {\n        rtStatComposite.calcServiceKeyRt(\n                registryOpType, responseTime, new ApplicationMetric(rtStatComposite.getApplicationModel()));\n    }\n\n    public void calcServiceKeyRt(String serviceKey, String registryOpType, Long responseTime) {\n        rtStatComposite.calcServiceKeyRt(\n                registryOpType, responseTime, new ServiceKeyMetric(rtStatComposite.getApplicationModel(), serviceKey));\n    }\n\n    public void calcServiceKeyRt(Invocation invocation, String registryOpType, Long responseTime) {\n        rtStatComposite.calcServiceKeyRt(invocation, registryOpType, responseTime);\n    }\n\n    public void calcMethodKeyRt(Invocation invocation, String registryOpType, Long responseTime) {\n        rtStatComposite.calcMethodKeyRt(invocation, registryOpType, responseTime);\n    }\n\n    public void setServiceKey(MetricsKeyWrapper metricsKey, String serviceKey, int num) {\n        serviceStatComposite.setServiceKey(metricsKey, serviceKey, num);\n    }\n\n    public void setServiceKey(MetricsKeyWrapper metricsKey, String serviceKey, int num, Map<String, String> extra) {\n        serviceStatComposite.setExtraServiceKey(metricsKey, serviceKey, num, extra);\n    }\n\n    public void incrementApp(MetricsKey metricsKey, int size) {\n        applicationStatComposite.incrementSize(metricsKey, size);\n    }\n\n    public void incrementServiceKey(MetricsKeyWrapper metricsKeyWrapper, String attServiceKey, int size) {\n        serviceStatComposite.incrementServiceKey(metricsKeyWrapper, attServiceKey, size);\n    }\n\n    public void incrementServiceKey(\n            MetricsKeyWrapper metricsKeyWrapper, String attServiceKey, Map<String, String> extra, int size) {\n        serviceStatComposite.incrementExtraServiceKey(metricsKeyWrapper, attServiceKey, extra, size);\n    }\n\n    public void incrementMethodKey(MetricsKeyWrapper metricsKeyWrapper, MethodMetric methodMetric, int size) {\n        methodStatComposite.incrementMethodKey(metricsKeyWrapper, methodMetric, size);\n    }\n\n    public void initMethodKey(MetricsKeyWrapper metricsKeyWrapper, Invocation invocation) {\n        methodStatComposite.initMethodKey(metricsKeyWrapper, invocation);\n    }\n\n    @Override\n    public List<MetricSample> export(MetricsCategory category) {\n        List<MetricSample> list = new ArrayList<>();\n        list.addAll(applicationStatComposite.export(category));\n        list.addAll(rtStatComposite.export(category));\n        list.addAll(serviceStatComposite.export(category));\n        list.addAll(methodStatComposite.export(category));\n        return list;\n    }\n\n    public ApplicationStatComposite getApplicationStatComposite() {\n        return applicationStatComposite;\n    }\n\n    public RtStatComposite getRtStatComposite() {\n        return rtStatComposite;\n    }\n\n    public void setAppKey(MetricsKey metricsKey, Long num) {\n        applicationStatComposite.setAppKey(metricsKey, num);\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // Should ensure that all the composite's samplesChanged have been compareAndSet, and cannot flip the `or` logic\n        boolean changed = applicationStatComposite.calSamplesChanged();\n        changed = rtStatComposite.calSamplesChanged() || changed;\n        changed = serviceStatComposite.calSamplesChanged() || changed;\n        changed = methodStatComposite.calSamplesChanged() || changed;\n        return changed;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/MethodStatComposite.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.data;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.metrics.exception.MetricsNeverHappenException;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.sample.CounterMetricSample;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.report.AbstractMetricsExport;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Method-level data container,\n * if there is no actual call to the existing call method,\n * the key will not be displayed when exporting (to be optimized)\n */\npublic class MethodStatComposite extends AbstractMetricsExport {\n\n    private final AtomicBoolean samplesChanged = new AtomicBoolean(true);\n\n    public MethodStatComposite(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    private final ConcurrentHashMap<MetricsKeyWrapper, ConcurrentHashMap<MethodMetric, AtomicLong>> methodNumStats =\n            new ConcurrentHashMap<>();\n\n    public void initWrapper(List<MetricsKeyWrapper> metricsKeyWrappers) {\n        if (CollectionUtils.isEmpty(metricsKeyWrappers)) {\n            return;\n        }\n        metricsKeyWrappers.forEach(appKey -> {\n            methodNumStats.put(appKey, new ConcurrentHashMap<>());\n        });\n        samplesChanged.set(true);\n    }\n\n    public void initMethodKey(MetricsKeyWrapper wrapper, Invocation invocation) {\n        if (!methodNumStats.containsKey(wrapper)) {\n            return;\n        }\n\n        ConcurrentHashMapUtils.computeIfAbsent(\n                methodNumStats.get(wrapper),\n                new MethodMetric(getApplicationModel(), invocation, getServiceLevel()),\n                k -> new AtomicLong(0L));\n        samplesChanged.set(true);\n    }\n\n    public void incrementMethodKey(MetricsKeyWrapper wrapper, MethodMetric methodMetric, int size) {\n        if (!methodNumStats.containsKey(wrapper)) {\n            return;\n        }\n        AtomicLong stat = methodNumStats.get(wrapper).get(methodMetric);\n        if (stat == null) {\n            ConcurrentHashMapUtils.computeIfAbsent(\n                    methodNumStats.get(wrapper), methodMetric, (k) -> new AtomicLong(0L));\n            samplesChanged.set(true);\n            stat = methodNumStats.get(wrapper).get(methodMetric);\n        }\n        stat.getAndAdd(size);\n        //        MetricsSupport.fillZero(methodNumStats);\n    }\n\n    public List<MetricSample> export(MetricsCategory category) {\n        List<MetricSample> list = new ArrayList<>();\n        for (MetricsKeyWrapper wrapper : methodNumStats.keySet()) {\n            Map<MethodMetric, AtomicLong> stringAtomicLongMap = methodNumStats.get(wrapper);\n            for (MethodMetric methodMetric : stringAtomicLongMap.keySet()) {\n                if (wrapper.getSampleType() == MetricSample.Type.COUNTER) {\n                    list.add(new CounterMetricSample<>(\n                            wrapper, methodMetric.getTags(), category, stringAtomicLongMap.get(methodMetric)));\n                } else if (wrapper.getSampleType() == MetricSample.Type.GAUGE) {\n                    list.add(new GaugeMetricSample<>(\n                            wrapper, methodMetric.getTags(), category, stringAtomicLongMap, value -> value.get(\n                                            methodMetric)\n                                    .get()));\n                } else {\n                    throw new MetricsNeverHappenException(\"Unsupported metricSample type: \" + wrapper.getSampleType());\n                }\n            }\n        }\n        return list;\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // CAS to get and reset the flag in an atomic operation\n        return samplesChanged.compareAndSet(true, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.data;\n\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.Metric;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.ServiceKeyMetric;\nimport org.apache.dubbo.metrics.model.container.AtomicLongContainer;\nimport org.apache.dubbo.metrics.model.container.LongAccumulatorContainer;\nimport org.apache.dubbo.metrics.model.container.LongContainer;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.report.AbstractMetricsExport;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.atomic.LongAccumulator;\nimport java.util.function.BiConsumer;\nimport java.util.stream.Collectors;\n\n/**\n * The data container of the rt dimension, including application, service, and method levels,\n * if there is no actual call to the existing call method,\n * the key will not be displayed when exporting (to be optimized)\n */\n@SuppressWarnings({\"rawtypes\", \"unchecked\"})\npublic class RtStatComposite extends AbstractMetricsExport {\n\n    private final AtomicBoolean samplesChanged = new AtomicBoolean(true);\n\n    public RtStatComposite(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    private final ConcurrentHashMap<String, List<LongContainer<? extends Number>>> rtStats = new ConcurrentHashMap<>();\n\n    public void init(MetricsPlaceValue... placeValues) {\n        if (placeValues == null) {\n            return;\n        }\n        for (MetricsPlaceValue placeValue : placeValues) {\n            List<LongContainer<? extends Number>> containers = initStats(placeValue);\n            for (LongContainer<? extends Number> container : containers) {\n                ConcurrentHashMapUtils.computeIfAbsent(\n                                rtStats, container.getMetricsKeyWrapper().getType(), k -> new ArrayList<>())\n                        .add(container);\n            }\n        }\n        samplesChanged.set(true);\n    }\n\n    private List<LongContainer<? extends Number>> initStats(MetricsPlaceValue placeValue) {\n        List<LongContainer<? extends Number>> singleRtStats = new ArrayList<>();\n        singleRtStats.add(new AtomicLongContainer(new MetricsKeyWrapper(MetricsKey.METRIC_RT_LAST, placeValue)));\n        singleRtStats.add(new LongAccumulatorContainer(\n                new MetricsKeyWrapper(MetricsKey.METRIC_RT_MIN, placeValue),\n                new LongAccumulator(Long::min, Long.MAX_VALUE)));\n        singleRtStats.add(new LongAccumulatorContainer(\n                new MetricsKeyWrapper(MetricsKey.METRIC_RT_MAX, placeValue),\n                new LongAccumulator(Long::max, Long.MIN_VALUE)));\n        singleRtStats.add(new AtomicLongContainer(\n                new MetricsKeyWrapper(MetricsKey.METRIC_RT_SUM, placeValue),\n                (responseTime, longAccumulator) -> longAccumulator.addAndGet(responseTime)));\n        // AvgContainer is a special counter that stores the number of times but outputs function of sum/times\n        AtomicLongContainer avgContainer = new AtomicLongContainer(\n                new MetricsKeyWrapper(MetricsKey.METRIC_RT_AVG, placeValue), (k, v) -> v.incrementAndGet());\n        avgContainer.setValueSupplier(applicationName -> {\n            LongContainer<? extends Number> totalContainer = rtStats.values().stream()\n                    .flatMap(List::stream)\n                    .filter(longContainer -> longContainer.isKeyWrapper(MetricsKey.METRIC_RT_SUM, placeValue.getType()))\n                    .findFirst()\n                    .get();\n            AtomicLong totalRtTimes = avgContainer.get(applicationName);\n            AtomicLong totalRtSum = (AtomicLong) totalContainer.get(applicationName);\n            return totalRtSum.get() / totalRtTimes.get();\n        });\n        singleRtStats.add(avgContainer);\n        return singleRtStats;\n    }\n\n    public void calcServiceKeyRt(String registryOpType, Long responseTime, Metric key) {\n        for (LongContainer container : rtStats.get(registryOpType)) {\n            Number current = (Number) container.get(key);\n            if (current == null) {\n                container.putIfAbsent(key, container.getInitFunc().apply(key));\n                samplesChanged.set(true);\n                current = (Number) container.get(key);\n            }\n            container.getConsumerFunc().accept(responseTime, current);\n        }\n    }\n\n    public void calcServiceKeyRt(Invocation invocation, String registryOpType, Long responseTime) {\n        List<Action> actions;\n        if (invocation.getServiceModel() != null && invocation.getServiceModel().getServiceKey() != null) {\n            Map<String, Object> attributeMap =\n                    invocation.getServiceModel().getServiceMetadata().getAttributeMap();\n            Map<String, List<Action>> cache = (Map<String, List<Action>>) attributeMap.get(\"ServiceKeyRt\");\n            if (cache == null) {\n                attributeMap.putIfAbsent(\"ServiceKeyRt\", new ConcurrentHashMap<>(32));\n                cache = (Map<String, List<Action>>) attributeMap.get(\"ServiceKeyRt\");\n            }\n            actions = cache.get(registryOpType);\n            if (actions == null) {\n                actions = calServiceRtActions(invocation, registryOpType);\n                cache.putIfAbsent(registryOpType, actions);\n                samplesChanged.set(true);\n                actions = cache.get(registryOpType);\n            }\n        } else {\n            actions = calServiceRtActions(invocation, registryOpType);\n        }\n\n        for (Action action : actions) {\n            action.run(responseTime);\n        }\n    }\n\n    private List<Action> calServiceRtActions(Invocation invocation, String registryOpType) {\n        List<Action> actions;\n        actions = new LinkedList<>();\n\n        ServiceKeyMetric key = new ServiceKeyMetric(getApplicationModel(), invocation.getTargetServiceUniqueName());\n        for (LongContainer container : rtStats.get(registryOpType)) {\n            Number current = (Number) container.get(key);\n            if (current == null) {\n                container.putIfAbsent(key, container.getInitFunc().apply(key));\n                samplesChanged.set(true);\n                current = (Number) container.get(key);\n            }\n            actions.add(new Action(container.getConsumerFunc(), current));\n        }\n        return actions;\n    }\n\n    public void calcMethodKeyRt(Invocation invocation, String registryOpType, Long responseTime) {\n        List<Action> actions;\n\n        if (getServiceLevel()\n                && invocation.getServiceModel() != null\n                && invocation.getServiceModel().getServiceMetadata() != null) {\n            Map<String, Object> attributeMap =\n                    invocation.getServiceModel().getServiceMetadata().getAttributeMap();\n            Map<String, List<Action>> cache = (Map<String, List<Action>>) attributeMap.get(\"MethodKeyRt\");\n            if (cache == null) {\n                attributeMap.putIfAbsent(\"MethodKeyRt\", new ConcurrentHashMap<>(32));\n                cache = (Map<String, List<Action>>) attributeMap.get(\"MethodKeyRt\");\n            }\n            actions = cache.get(registryOpType);\n            if (actions == null) {\n                actions = calMethodRtActions(invocation, registryOpType);\n                cache.putIfAbsent(registryOpType, actions);\n                samplesChanged.set(true);\n                actions = cache.get(registryOpType);\n            }\n        } else {\n            actions = calMethodRtActions(invocation, registryOpType);\n        }\n\n        for (Action action : actions) {\n            action.run(responseTime);\n        }\n    }\n\n    private List<Action> calMethodRtActions(Invocation invocation, String registryOpType) {\n        List<Action> actions;\n        actions = new LinkedList<>();\n        for (LongContainer container : rtStats.get(registryOpType)) {\n            MethodMetric key = new MethodMetric(getApplicationModel(), invocation, getServiceLevel());\n            Number current = (Number) container.get(key);\n            if (current == null) {\n                container.putIfAbsent(key, container.getInitFunc().apply(key));\n                samplesChanged.set(true);\n                current = (Number) container.get(key);\n            }\n            actions.add(new Action(container.getConsumerFunc(), current));\n        }\n        return actions;\n    }\n\n    public List<MetricSample> export(MetricsCategory category) {\n        List<MetricSample> list = new ArrayList<>();\n        for (List<LongContainer<? extends Number>> containers : rtStats.values()) {\n            for (LongContainer<? extends Number> container : containers) {\n                MetricsKeyWrapper metricsKeyWrapper = container.getMetricsKeyWrapper();\n                for (Metric key : container.keySet()) {\n                    // Use keySet to obtain the original key instance reference of ConcurrentHashMap to avoid early\n                    // recycling of the micrometer\n                    list.add(new GaugeMetricSample<>(\n                            metricsKeyWrapper.targetKey(),\n                            metricsKeyWrapper.targetDesc(),\n                            key.getTags(),\n                            category,\n                            key,\n                            value -> container.getValueSupplier().apply(value)));\n                }\n            }\n        }\n        return list;\n    }\n\n    public List<LongContainer<? extends Number>> getRtStats() {\n        return rtStats.values().stream().flatMap(List::stream).collect(Collectors.toList());\n    }\n\n    private static class Action {\n        private final BiConsumer<Long, Number> consumerFunc;\n        private final Number initValue;\n\n        public Action(BiConsumer<Long, Number> consumerFunc, Number initValue) {\n            this.consumerFunc = consumerFunc;\n            this.initValue = initValue;\n        }\n\n        public void run(Long responseTime) {\n            consumerFunc.accept(responseTime, initValue);\n        }\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // CAS to get and reset the flag in an atomic operation\n        return samplesChanged.compareAndSet(true, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/ServiceStatComposite.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.data;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.ServiceKeyMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.report.AbstractMetricsExport;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Service-level data container, for the initialized MetricsKey,\n * different from the null value of the Map type (the key is not displayed when there is no data),\n * the key is displayed and the initial data is 0 value of the AtomicLong type\n */\npublic class ServiceStatComposite extends AbstractMetricsExport {\n\n    private final AtomicBoolean samplesChanged = new AtomicBoolean(true);\n\n    public ServiceStatComposite(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    private final ConcurrentHashMap<MetricsKeyWrapper, ConcurrentHashMap<ServiceKeyMetric, AtomicLong>>\n            serviceWrapperNumStats = new ConcurrentHashMap<>();\n\n    public void initWrapper(List<MetricsKeyWrapper> metricsKeyWrappers) {\n        if (CollectionUtils.isEmpty(metricsKeyWrappers)) {\n            return;\n        }\n        metricsKeyWrappers.forEach(appKey -> {\n            serviceWrapperNumStats.put(appKey, new ConcurrentHashMap<>());\n        });\n        samplesChanged.set(true);\n    }\n\n    public void incrementServiceKey(MetricsKeyWrapper wrapper, String serviceKey, int size) {\n        incrementExtraServiceKey(wrapper, serviceKey, null, size);\n    }\n\n    public void incrementExtraServiceKey(\n            MetricsKeyWrapper wrapper, String serviceKey, Map<String, String> extra, int size) {\n        if (!serviceWrapperNumStats.containsKey(wrapper)) {\n            return;\n        }\n        ServiceKeyMetric serviceKeyMetric = new ServiceKeyMetric(getApplicationModel(), serviceKey);\n        if (extra != null) {\n            serviceKeyMetric.setExtraInfo(extra);\n        }\n        ConcurrentHashMap<ServiceKeyMetric, AtomicLong> map = serviceWrapperNumStats.get(wrapper);\n        AtomicLong metrics = map.get(serviceKeyMetric);\n        if (metrics == null) {\n            metrics = ConcurrentHashMapUtils.computeIfAbsent(map, serviceKeyMetric, k -> new AtomicLong(0L));\n            samplesChanged.set(true);\n        }\n        metrics.getAndAdd(size);\n        //        MetricsSupport.fillZero(serviceWrapperNumStats);\n    }\n\n    public void setServiceKey(MetricsKeyWrapper wrapper, String serviceKey, int num) {\n        setExtraServiceKey(wrapper, serviceKey, num, null);\n    }\n\n    public void setExtraServiceKey(MetricsKeyWrapper wrapper, String serviceKey, int num, Map<String, String> extra) {\n        if (!serviceWrapperNumStats.containsKey(wrapper)) {\n            return;\n        }\n        ServiceKeyMetric serviceKeyMetric = new ServiceKeyMetric(getApplicationModel(), serviceKey);\n        if (extra != null) {\n            serviceKeyMetric.setExtraInfo(extra);\n        }\n        ConcurrentHashMap<ServiceKeyMetric, AtomicLong> stats = serviceWrapperNumStats.get(wrapper);\n        AtomicLong metrics = stats.get(serviceKeyMetric);\n        if (metrics == null) {\n            metrics = ConcurrentHashMapUtils.computeIfAbsent(stats, serviceKeyMetric, k -> new AtomicLong(0L));\n            samplesChanged.set(true);\n        }\n        metrics.set(num);\n    }\n\n    @Override\n    public List<MetricSample> export(MetricsCategory category) {\n        List<MetricSample> list = new ArrayList<>();\n        for (MetricsKeyWrapper wrapper : serviceWrapperNumStats.keySet()) {\n            Map<ServiceKeyMetric, AtomicLong> stringAtomicLongMap = serviceWrapperNumStats.get(wrapper);\n            for (ServiceKeyMetric serviceKeyMetric : stringAtomicLongMap.keySet()) {\n                list.add(new GaugeMetricSample<>(\n                        wrapper, serviceKeyMetric.getTags(), category, stringAtomicLongMap, value -> value.get(\n                                        serviceKeyMetric)\n                                .get()));\n            }\n        }\n        return list;\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // CAS to get and reset the flag in an atomic operation\n        return samplesChanged.compareAndSet(true, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.event;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.metrics.collector.MetricsCollector;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.List;\n\n/**\n * Global spi event publisher\n */\npublic class MetricsDispatcher extends SimpleMetricsEventMulticaster {\n\n    @SuppressWarnings({\"rawtypes\"})\n    public MetricsDispatcher(ApplicationModel applicationModel) {\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        ExtensionLoader<MetricsCollector> extensionLoader = applicationModel.getExtensionLoader(MetricsCollector.class);\n        if (extensionLoader != null) {\n            List<MetricsCollector> customizeCollectors = extensionLoader.getActivateExtensions();\n            for (MetricsCollector customizeCollector : customizeCollectors) {\n                beanFactory.registerBean(customizeCollector);\n            }\n            customizeCollectors.forEach(this::addListener);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsInitEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.event;\n\nimport org.apache.dubbo.metrics.MetricsConstants;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.TypeWrapper;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;\n\npublic class MetricsInitEvent extends TimeCounterEvent {\n\n    private static final TypeWrapper METRIC_EVENT = new TypeWrapper(MetricsLevel.SERVICE, METRIC_REQUESTS);\n\n    public MetricsInitEvent(ApplicationModel source, TypeWrapper typeWrapper) {\n        super(source, typeWrapper);\n    }\n\n    public static MetricsInitEvent toMetricsInitEvent(\n            ApplicationModel applicationModel, Invocation invocation, boolean serviceLevel) {\n        MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, serviceLevel);\n        MetricsInitEvent initEvent = new MetricsInitEvent(applicationModel, METRIC_EVENT);\n        initEvent.putAttachment(MetricsConstants.INVOCATION, invocation);\n        initEvent.putAttachment(MetricsConstants.METHOD_METRICS, methodMetric);\n        initEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));\n        initEvent.putAttachment(MetricsConstants.INVOCATION_SIDE, MetricsSupport.getSide(invocation));\n        return initEvent;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.event;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metrics.listener.MetricsLifeListener;\nimport org.apache.dubbo.metrics.listener.MetricsListener;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\n/**\n * A simple event publisher that defines lifecycle events and supports rt events\n */\npublic class SimpleMetricsEventMulticaster implements MetricsEventMulticaster {\n    private final List<MetricsListener<?>> listeners = Collections.synchronizedList(new ArrayList<>());\n\n    @Override\n    public void addListener(MetricsListener<?> listener) {\n        listeners.add(listener);\n    }\n\n    @Override\n    @SuppressWarnings({\"rawtypes\", \"unchecked\"})\n    public void publishEvent(MetricsEvent event) {\n        if (validateIfApplicationConfigExist(event)) return;\n        for (MetricsListener listener : listeners) {\n            if (listener.isSupport(event)) {\n                listener.onEvent(event);\n            }\n        }\n    }\n\n    private boolean validateIfApplicationConfigExist(MetricsEvent event) {\n        if (event.getSource() != null) {\n            // Check if exist application config\n            return StringUtils.isEmpty(event.appName());\n        }\n        return false;\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\"})\n    public void publishFinishEvent(TimeCounterEvent event) {\n        publishTimeEvent(event, metricsLifeListener -> metricsLifeListener.onEventFinish(event));\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\"})\n    public void publishErrorEvent(TimeCounterEvent event) {\n        publishTimeEvent(event, metricsLifeListener -> metricsLifeListener.onEventError(event));\n    }\n\n    @SuppressWarnings({\"rawtypes\"})\n    private void publishTimeEvent(MetricsEvent event, Consumer<MetricsLifeListener> consumer) {\n        if (validateIfApplicationConfigExist(event)) return;\n        if (event instanceof TimeCounterEvent) {\n            ((TimeCounterEvent) event).getTimePair().end();\n        }\n        for (MetricsListener listener : listeners) {\n            if (listener instanceof MetricsLifeListener && listener.isSupport(event)) {\n                consumer.accept(((MetricsLifeListener) listener));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/AbstractMetricsKeyListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.listener;\n\nimport org.apache.dubbo.metrics.event.MetricsEvent;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\n\nimport java.util.function.Consumer;\n\n/**\n * According to the event template of {@link MetricsEventBus},\n * build a consistent static method for general and custom monitoring consume methods\n *\n */\npublic abstract class AbstractMetricsKeyListener extends AbstractMetricsListener<TimeCounterEvent>\n        implements MetricsLifeListener<TimeCounterEvent> {\n\n    private final MetricsKey metricsKey;\n\n    public AbstractMetricsKeyListener(MetricsKey metricsKey) {\n        this.metricsKey = metricsKey;\n    }\n\n    /**\n     * The MetricsKey type determines whether events are supported\n     */\n    @Override\n    public boolean isSupport(MetricsEvent event) {\n        return super.isSupport(event) && event.isAssignableFrom(metricsKey);\n    }\n\n    @Override\n    public void onEvent(TimeCounterEvent event) {}\n\n    public static AbstractMetricsKeyListener onEvent(MetricsKey metricsKey, Consumer<TimeCounterEvent> postFunc) {\n\n        return new AbstractMetricsKeyListener(metricsKey) {\n            @Override\n            public void onEvent(TimeCounterEvent event) {\n                postFunc.accept(event);\n            }\n        };\n    }\n\n    public static AbstractMetricsKeyListener onFinish(MetricsKey metricsKey, Consumer<TimeCounterEvent> finishFunc) {\n\n        return new AbstractMetricsKeyListener(metricsKey) {\n            @Override\n            public void onEventFinish(TimeCounterEvent event) {\n                finishFunc.accept(event);\n            }\n        };\n    }\n\n    public static AbstractMetricsKeyListener onError(MetricsKey metricsKey, Consumer<TimeCounterEvent> errorFunc) {\n\n        return new AbstractMetricsKeyListener(metricsKey) {\n            @Override\n            public void onEventError(TimeCounterEvent event) {\n                errorFunc.accept(event);\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/AbstractMetricsListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.listener;\n\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ReflectionUtils;\nimport org.apache.dubbo.metrics.event.MetricsEvent;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic abstract class AbstractMetricsListener<E extends MetricsEvent> implements MetricsListener<E> {\n\n    private final ConcurrentHashMap<Class<?>, Boolean> eventMatchCache = new ConcurrentHashMap<>();\n\n    /**\n     * Whether to support the general determination of event points depends on the event type\n     */\n    public boolean isSupport(MetricsEvent event) {\n        Boolean eventMatch = ConcurrentHashMapUtils.computeIfAbsent(\n                eventMatchCache,\n                event.getClass(),\n                clazz -> ReflectionUtils.match(getClass(), AbstractMetricsListener.class, event));\n        return event.isAvailable() && eventMatch;\n    }\n\n    @Override\n    public abstract void onEvent(E event);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsApplicationListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.listener;\n\nimport org.apache.dubbo.metrics.collector.CombMetricsCollector;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\n\n/**\n * App-level listener type, in most cases, can use the static method\n * to produce an anonymous listener for general monitoring\n */\npublic class MetricsApplicationListener extends AbstractMetricsKeyListener {\n\n    public MetricsApplicationListener(MetricsKey metricsKey) {\n        super(metricsKey);\n    }\n\n    /**\n     * Perform auto-increment on the monitored key,\n     * Can use a custom listener instead of this generic operation\n     *\n     * @param metricsKey Monitor key\n     * @param collector  Corresponding collector\n     */\n    public static AbstractMetricsKeyListener onPostEventBuild(\n            MetricsKey metricsKey, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onEvent(metricsKey, event -> collector.increment(metricsKey));\n    }\n\n    /**\n     * To end the monitoring normally, in addition to increasing the number of corresponding indicators,\n     * use the introspection method to calculate the relevant rt indicators\n     *\n     * @param metricsKey Monitor key\n     * @param collector  Corresponding collector\n     */\n    public static AbstractMetricsKeyListener onFinishEventBuild(\n            MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onFinish(metricsKey, event -> {\n            collector.increment(metricsKey);\n            collector.addApplicationRt(placeType.getType(), event.getTimePair().calc());\n        });\n    }\n\n    /**\n     * Similar to onFinishEventBuild\n     */\n    public static AbstractMetricsKeyListener onErrorEventBuild(\n            MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onError(metricsKey, event -> {\n            collector.increment(metricsKey);\n            collector.addApplicationRt(placeType.getType(), event.getTimePair().calc());\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsLifeListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.listener;\n\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\n\n/**\n * Metrics Listener.\n */\npublic interface MetricsLifeListener<E extends TimeCounterEvent> extends MetricsListener<E> {\n\n    default void onEventFinish(E event) {}\n\n    default void onEventError(E event) {}\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.listener;\n\nimport org.apache.dubbo.metrics.collector.ServiceMetricsCollector;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\n\n/**\n * Service-level listener type, in most cases, can use the static method\n * to produce an anonymous listener for general monitoring.\n * Similar to App-level\n */\npublic class MetricsServiceListener extends AbstractMetricsKeyListener {\n\n    public MetricsServiceListener(MetricsKey metricsKey) {\n        super(metricsKey);\n    }\n\n    public static AbstractMetricsKeyListener onPostEventBuild(\n            MetricsKey metricsKey, MetricsPlaceValue placeType, ServiceMetricsCollector<TimeCounterEvent> collector) {\n        return AbstractMetricsKeyListener.onEvent(\n                metricsKey, event -> MetricsSupport.increment(metricsKey, placeType, collector, event));\n    }\n\n    public static AbstractMetricsKeyListener onFinishEventBuild(\n            MetricsKey metricsKey, MetricsPlaceValue placeType, ServiceMetricsCollector<TimeCounterEvent> collector) {\n        return AbstractMetricsKeyListener.onFinish(\n                metricsKey, event -> MetricsSupport.incrAndAddRt(metricsKey, placeType, collector, event));\n    }\n\n    public static AbstractMetricsKeyListener onErrorEventBuild(\n            MetricsKey metricsKey, MetricsPlaceValue placeType, ServiceMetricsCollector<TimeCounterEvent> collector) {\n        return AbstractMetricsKeyListener.onError(\n                metricsKey, event -> MetricsSupport.incrAndAddRt(metricsKey, placeType, collector, event));\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ApplicationMetric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\nimport java.util.Objects;\n\npublic class ApplicationMetric implements Metric {\n    private final ApplicationModel applicationModel;\n    protected Map<String, String> extraInfo;\n\n    public ApplicationMetric(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    public ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    public String getApplicationName() {\n        return getApplicationModel().getApplicationName();\n    }\n\n    @Override\n    public Map<String, String> getTags() {\n        return hostTags(gitTags(MetricsSupport.applicationTags(applicationModel, getExtraInfo())));\n    }\n\n    public Map<String, String> gitTags(Map<String, String> tags) {\n        return MetricsSupport.gitTags(tags);\n    }\n\n    public Map<String, String> hostTags(Map<String, String> tags) {\n        return MetricsSupport.hostTags(tags);\n    }\n\n    public Map<String, String> getExtraInfo() {\n        return extraInfo;\n    }\n\n    public void setExtraInfo(Map<String, String> extraInfo) {\n        this.extraInfo = extraInfo;\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        ApplicationMetric that = (ApplicationMetric) o;\n        return getApplicationName().equals(that.applicationModel.getApplicationName())\n                && Objects.equals(extraInfo, that.extraInfo);\n    }\n\n    private volatile int hashCode;\n\n    @Override\n    public int hashCode() {\n        if (hashCode == 0) {\n            hashCode = Objects.hash(getApplicationName(), extraInfo);\n        }\n        return hashCode;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ConfigCenterMetric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_CHANGE_TYPE;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_CONFIG_CENTER;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_KEY_KEY;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHost;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHostName;\n\npublic class ConfigCenterMetric implements Metric {\n\n    private String applicationName;\n    private String key;\n    private String group;\n    private String configCenter;\n    private String changeType;\n\n    public ConfigCenterMetric() {}\n\n    public ConfigCenterMetric(\n            String applicationName, String key, String group, String configCenter, String changeType) {\n        this.applicationName = applicationName;\n        this.key = key;\n        this.group = group;\n        this.configCenter = configCenter;\n        this.changeType = changeType;\n    }\n\n    @Override\n    public Map<String, String> getTags() {\n        Map<String, String> tags = new HashMap<>();\n        tags.put(TAG_IP, getLocalHost());\n        tags.put(TAG_HOSTNAME, getLocalHostName());\n        tags.put(TAG_APPLICATION_NAME, applicationName);\n\n        tags.put(TAG_KEY_KEY, key);\n        tags.put(TAG_GROUP_KEY, group);\n        tags.put(TAG_CONFIG_CENTER, configCenter);\n        tags.put(TAG_CHANGE_TYPE, changeType.toLowerCase());\n\n        return tags;\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        ConfigCenterMetric that = (ConfigCenterMetric) o;\n\n        if (!Objects.equals(applicationName, that.applicationName)) return false;\n        if (!Objects.equals(key, that.key)) return false;\n        if (!Objects.equals(group, that.group)) return false;\n        if (!Objects.equals(configCenter, that.configCenter)) return false;\n        return Objects.equals(changeType, that.changeType);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(applicationName, key, group, configCenter, changeType);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ErrorCodeMetric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_ERROR_CODE;\n\n/**\n * ErrorCodeMetric. Provide tags for error code metrics.\n */\npublic class ErrorCodeMetric implements Metric {\n\n    private final String errorCode;\n\n    private final String applicationName;\n\n    public ErrorCodeMetric(String applicationName, String errorCode) {\n        this.errorCode = errorCode;\n        this.applicationName = applicationName;\n    }\n\n    @Override\n    public Map<String, String> getTags() {\n        Map<String, String> tags = new HashMap<>();\n        tags.put(TAG_ERROR_CODE, errorCode);\n        tags.put(TAG_APPLICATION_NAME, applicationName);\n        return tags;\n    }\n\n    public String getErrorCode() {\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MethodMetric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;\n\n/**\n * Metric class for method.\n */\npublic class MethodMetric extends ServiceKeyMetric {\n    private String side;\n    private final String methodName;\n    private String group;\n    private String version;\n\n    public MethodMetric(ApplicationModel applicationModel, Invocation invocation, boolean serviceLevel) {\n        super(applicationModel, MetricsSupport.getInterfaceName(invocation));\n        this.side = MetricsSupport.getSide(invocation);\n        this.group = MetricsSupport.getGroup(invocation);\n        this.version = MetricsSupport.getVersion(invocation);\n        this.methodName = serviceLevel ? null : RpcUtils.getMethodName(invocation);\n    }\n\n    public static boolean isServiceLevel(ApplicationModel applicationModel) {\n        if (applicationModel == null) {\n            return false;\n        }\n        ConfigManager applicationConfigManager = applicationModel.getApplicationConfigManager();\n        if (applicationConfigManager == null) {\n            return false;\n        }\n        Optional<MetricsConfig> metrics = applicationConfigManager.getMetrics();\n        if (!metrics.isPresent()) {\n            return false;\n        }\n        String rpcLevel = metrics.map(MetricsConfig::getRpcLevel).orElse(MetricsLevel.METHOD.name());\n        rpcLevel = StringUtils.isBlank(rpcLevel) ? MetricsLevel.METHOD.name() : rpcLevel;\n        return MetricsLevel.SERVICE.name().equalsIgnoreCase(rpcLevel);\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    public Map<String, String> getTags() {\n        Map<String, String> tags = MetricsSupport.methodTags(getApplicationModel(), getServiceKey(), methodName);\n        tags.put(TAG_GROUP_KEY, group);\n        tags.put(TAG_VERSION_KEY, version);\n        return tags;\n    }\n\n    public String getMethodName() {\n        return methodName;\n    }\n\n    public String getSide() {\n        return side;\n    }\n\n    public void setSide(String side) {\n        this.side = side;\n    }\n\n    @Override\n    public String toString() {\n        return \"MethodMetric{\" + \"applicationName='\"\n                + getApplicationName() + '\\'' + \", side='\"\n                + side + '\\'' + \", interfaceName='\"\n                + getServiceKey() + '\\'' + \", methodName='\"\n                + methodName + '\\'' + \", group='\"\n                + group + '\\'' + \", version='\"\n                + version + '\\'' + '}';\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        MethodMetric that = (MethodMetric) o;\n        return Objects.equals(getApplicationModel(), that.getApplicationModel())\n                && Objects.equals(side, that.side)\n                && Objects.equals(getServiceKey(), that.getServiceKey())\n                && Objects.equals(methodName, that.methodName)\n                && Objects.equals(group, that.group)\n                && Objects.equals(version, that.version);\n    }\n\n    private volatile int hashCode = 0;\n\n    @Override\n    public int hashCode() {\n        if (hashCode == 0) {\n            hashCode = Objects.hash(getApplicationModel(), side, getServiceKey(), methodName, group, version);\n        }\n        return hashCode;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/Metric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\nimport java.util.Map;\n\npublic interface Metric {\n    Map<String, String> getTags();\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\n/**\n * Metric category.\n */\npublic enum MetricsCategory {\n    RT,\n    QPS,\n    REQUESTS,\n    APPLICATION,\n    CONFIGCENTER,\n    REGISTRY,\n    METADATA,\n    THREAD_POOL,\n    ERROR_CODE,\n    NETTY,\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsSupport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.lang.Nullable;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metrics.collector.MethodMetricsCollector;\nimport org.apache.dubbo.metrics.collector.ServiceMetricsCollector;\nimport org.apache.dubbo.metrics.event.MetricsEvent;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_MODULE;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHost;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHostName;\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;\nimport static org.apache.dubbo.metrics.MetricsConstants.INVOCATION;\nimport static org.apache.dubbo.metrics.MetricsConstants.METHOD_METRICS;\nimport static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE;\n\npublic class MetricsSupport {\n\n    private static final String version = Version.getVersion();\n\n    private static final String commitId = Version.getLastCommitId();\n\n    public static Map<String, String> applicationTags(ApplicationModel applicationModel) {\n        return applicationTags(applicationModel, null);\n    }\n\n    public static Map<String, String> applicationTags(\n            ApplicationModel applicationModel, @Nullable Map<String, String> extraInfo) {\n        Map<String, String> tags = new HashMap<>();\n        tags.put(TAG_APPLICATION_NAME, applicationModel.getApplicationName());\n        tags.put(TAG_APPLICATION_MODULE, applicationModel.getInternalId());\n        if (CollectionUtils.isNotEmptyMap(extraInfo)) {\n            tags.putAll(extraInfo);\n        }\n        return tags;\n    }\n\n    public static Map<String, String> gitTags(Map<String, String> tags) {\n        tags.put(MetricsKey.METADATA_GIT_COMMITID_METRIC.getName(), commitId);\n        tags.put(TAG_APPLICATION_VERSION_KEY, version);\n        return tags;\n    }\n\n    public static Map<String, String> hostTags(Map<String, String> tags) {\n        tags.put(TAG_IP, getLocalHost());\n        tags.put(TAG_HOSTNAME, getLocalHostName());\n        return tags;\n    }\n\n    public static Map<String, String> serviceTags(\n            ApplicationModel applicationModel, String serviceKey, Map<String, String> extraInfo) {\n        Map<String, String> tags = applicationTags(applicationModel, extraInfo);\n        tags.put(TAG_INTERFACE_KEY, serviceKey);\n        return tags;\n    }\n\n    public static Map<String, String> methodTags(\n            ApplicationModel applicationModel, String serviceKey, String methodName) {\n        Map<String, String> tags = applicationTags(applicationModel);\n        tags.put(TAG_INTERFACE_KEY, serviceKey);\n        tags.put(TAG_METHOD_KEY, methodName);\n        return tags;\n    }\n\n    public static MetricsKey getMetricsKey(Throwable throwable) {\n        MetricsKey targetKey = MetricsKey.METRIC_REQUESTS_FAILED;\n        if (throwable instanceof RpcException) {\n            RpcException e = (RpcException) throwable;\n            if (e.isTimeout()) {\n                targetKey = MetricsKey.METRIC_REQUESTS_TIMEOUT;\n            }\n            if (e.isLimitExceed()) {\n                targetKey = MetricsKey.METRIC_REQUESTS_LIMIT;\n            }\n            if (e.isBiz()) {\n                targetKey = MetricsKey.METRIC_REQUEST_BUSINESS_FAILED;\n            }\n            if (e.isSerialization()) {\n                targetKey = MetricsKey.METRIC_REQUESTS_CODEC_FAILED;\n            }\n            if (e.isNetwork()) {\n                targetKey = MetricsKey.METRIC_REQUESTS_NETWORK_FAILED;\n            }\n        } else {\n            targetKey = MetricsKey.METRIC_REQUEST_BUSINESS_FAILED;\n        }\n        return targetKey;\n    }\n\n    public static MetricsKey getAggMetricsKey(Throwable throwable) {\n        MetricsKey targetKey = MetricsKey.METRIC_REQUESTS_FAILED_AGG;\n        if (throwable instanceof RpcException) {\n            RpcException e = (RpcException) throwable;\n            if (e.isTimeout()) {\n                targetKey = MetricsKey.METRIC_REQUESTS_TIMEOUT_AGG;\n            }\n            if (e.isLimitExceed()) {\n                targetKey = MetricsKey.METRIC_REQUESTS_LIMIT_AGG;\n            }\n            if (e.isBiz()) {\n                targetKey = MetricsKey.METRIC_REQUEST_BUSINESS_FAILED_AGG;\n            }\n            if (e.isSerialization()) {\n                targetKey = MetricsKey.METRIC_REQUESTS_CODEC_FAILED_AGG;\n            }\n            if (e.isNetwork()) {\n                targetKey = MetricsKey.METRIC_REQUESTS_NETWORK_FAILED_AGG;\n            }\n        } else {\n            targetKey = MetricsKey.METRIC_REQUEST_BUSINESS_FAILED_AGG;\n        }\n        return targetKey;\n    }\n\n    public static String getSide(Invocation invocation) {\n        Optional<? extends Invoker<?>> invoker = Optional.ofNullable(invocation.getInvoker());\n        return invoker.isPresent() ? invoker.get().getUrl().getSide() : PROVIDER_SIDE;\n    }\n\n    public static String getInterfaceName(Invocation invocation) {\n        if (invocation.getServiceModel() != null && invocation.getServiceModel().getServiceMetadata() != null) {\n            return invocation.getServiceModel().getServiceMetadata().getServiceInterfaceName();\n        } else {\n            String serviceUniqueName = invocation.getTargetServiceUniqueName();\n            String interfaceAndVersion;\n            if (StringUtils.isBlank(serviceUniqueName)) {\n                return \"\";\n            }\n            String[] arr = serviceUniqueName.split(PATH_SEPARATOR);\n            if (arr.length == 2) {\n                interfaceAndVersion = arr[1];\n            } else {\n                interfaceAndVersion = arr[0];\n            }\n            String[] ivArr = interfaceAndVersion.split(GROUP_CHAR_SEPARATOR);\n            return ivArr[0];\n        }\n    }\n\n    public static String getGroup(Invocation invocation) {\n        if (invocation.getServiceModel() != null && invocation.getServiceModel().getServiceMetadata() != null) {\n            return invocation.getServiceModel().getServiceMetadata().getGroup();\n        } else {\n            String serviceUniqueName = invocation.getTargetServiceUniqueName();\n            String group = null;\n            String[] arr = serviceUniqueName.split(PATH_SEPARATOR);\n            if (arr.length == 2) {\n                group = arr[0];\n            }\n            return group;\n        }\n    }\n\n    public static String getVersion(Invocation invocation) {\n        if (invocation.getServiceModel() != null && invocation.getServiceModel().getServiceMetadata() != null) {\n            return invocation.getServiceModel().getServiceMetadata().getVersion();\n        } else {\n            String interfaceAndVersion;\n            String[] arr = invocation.getTargetServiceUniqueName().split(PATH_SEPARATOR);\n            if (arr.length == 2) {\n                interfaceAndVersion = arr[1];\n            } else {\n                interfaceAndVersion = arr[0];\n            }\n            String[] ivArr = interfaceAndVersion.split(GROUP_CHAR_SEPARATOR);\n            return ivArr.length == 2 ? ivArr[1] : null;\n        }\n    }\n\n    /**\n     * Incr service num\n     */\n    public static void increment(\n            MetricsKey metricsKey,\n            MetricsPlaceValue placeType,\n            ServiceMetricsCollector<TimeCounterEvent> collector,\n            MetricsEvent event) {\n        collector.increment(\n                event.getAttachmentValue(ATTACHMENT_KEY_SERVICE),\n                new MetricsKeyWrapper(metricsKey, placeType),\n                SELF_INCREMENT_SIZE);\n    }\n\n    /**\n     * Incr service num&&rt\n     */\n    public static void incrAndAddRt(\n            MetricsKey metricsKey,\n            MetricsPlaceValue placeType,\n            ServiceMetricsCollector<TimeCounterEvent> collector,\n            TimeCounterEvent event) {\n        collector.increment(\n                event.getAttachmentValue(ATTACHMENT_KEY_SERVICE),\n                new MetricsKeyWrapper(metricsKey, placeType),\n                SELF_INCREMENT_SIZE);\n        Invocation invocation = event.getAttachmentValue(INVOCATION);\n        if (invocation != null) {\n            collector.addServiceRt(\n                    invocation, placeType.getType(), event.getTimePair().calc());\n        } else {\n            collector.addServiceRt(\n                    (String) event.getAttachmentValue(ATTACHMENT_KEY_SERVICE),\n                    placeType.getType(),\n                    event.getTimePair().calc());\n        }\n    }\n\n    /**\n     * Incr method num\n     */\n    public static void increment(\n            MetricsKey metricsKey,\n            MetricsPlaceValue placeType,\n            MethodMetricsCollector<TimeCounterEvent> collector,\n            MetricsEvent event) {\n        collector.increment(\n                event.getAttachmentValue(METHOD_METRICS),\n                new MetricsKeyWrapper(metricsKey, placeType),\n                SELF_INCREMENT_SIZE);\n    }\n\n    public static void init(\n            MetricsKey metricsKey,\n            MetricsPlaceValue placeType,\n            MethodMetricsCollector<TimeCounterEvent> collector,\n            MetricsEvent event) {\n        collector.init(event.getAttachmentValue(INVOCATION), new MetricsKeyWrapper(metricsKey, placeType));\n    }\n\n    /**\n     * Dec method num\n     */\n    public static void dec(\n            MetricsKey metricsKey,\n            MetricsPlaceValue placeType,\n            MethodMetricsCollector<TimeCounterEvent> collector,\n            MetricsEvent event) {\n        collector.increment(\n                event.getAttachmentValue(METHOD_METRICS),\n                new MetricsKeyWrapper(metricsKey, placeType),\n                -SELF_INCREMENT_SIZE);\n    }\n\n    /**\n     * Incr method num&&rt\n     */\n    public static void incrAndAddRt(\n            MetricsKey metricsKey,\n            MetricsPlaceValue placeType,\n            MethodMetricsCollector<TimeCounterEvent> collector,\n            TimeCounterEvent event) {\n        collector.increment(\n                event.getAttachmentValue(METHOD_METRICS),\n                new MetricsKeyWrapper(metricsKey, placeType),\n                SELF_INCREMENT_SIZE);\n        collector.addMethodRt(\n                event.getAttachmentValue(INVOCATION),\n                placeType.getType(),\n                event.getTimePair().calc());\n    }\n\n    /**\n     * Generate a complete indicator item for an interface/method\n     */\n    public static <T> void fillZero(ConcurrentHashMap<?, ConcurrentHashMap<T, AtomicLong>> data) {\n        if (CollectionUtils.isEmptyMap(data)) {\n            return;\n        }\n        Set<T> allKeyMetrics =\n                data.values().stream().flatMap(map -> map.keySet().stream()).collect(Collectors.toSet());\n        data.forEach((keyWrapper, mapVal) -> {\n            for (T key : allKeyMetrics) {\n                ConcurrentHashMapUtils.computeIfAbsent(mapVal, key, k -> new AtomicLong(0));\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ServiceKeyMetric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\nimport java.util.Objects;\n\n/**\n * Metric class for service.\n */\npublic class ServiceKeyMetric extends ApplicationMetric {\n    private final String serviceKey;\n\n    public ServiceKeyMetric(ApplicationModel applicationModel, String serviceKey) {\n        super(applicationModel);\n        this.serviceKey = serviceKey;\n    }\n\n    @Override\n    public Map<String, String> getTags() {\n        return MetricsSupport.serviceTags(getApplicationModel(), serviceKey, getExtraInfo());\n    }\n\n    public String getServiceKey() {\n        return serviceKey;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (!(o instanceof ServiceKeyMetric)) {\n            return false;\n        }\n        ServiceKeyMetric that = (ServiceKeyMetric) o;\n        return serviceKey.equals(that.serviceKey) && Objects.equals(extraInfo, that.extraInfo);\n    }\n\n    private volatile int hashCode = 0;\n\n    @Override\n    public int hashCode() {\n        if (hashCode == 0) {\n            hashCode = Objects.hash(getApplicationName(), serviceKey, extraInfo);\n        }\n        return hashCode;\n    }\n\n    @Override\n    public String toString() {\n        return \"ServiceKeyMetric{\" + \"applicationName='\"\n                + getApplicationName() + '\\'' + \", serviceKey='\"\n                + serviceKey + '\\'' + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolMetric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\nimport org.apache.dubbo.common.utils.ConfigUtils;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_PID;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_THREAD_NAME;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHost;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHostName;\n\npublic class ThreadPoolMetric implements Metric {\n\n    private String applicationName;\n\n    private String threadPoolName;\n\n    private ThreadPoolExecutor threadPoolExecutor;\n\n    public ThreadPoolMetric(String applicationName, String threadPoolName, ThreadPoolExecutor threadPoolExecutor) {\n        this.applicationName = applicationName;\n        this.threadPoolExecutor = threadPoolExecutor;\n        this.threadPoolName = threadPoolName;\n    }\n\n    public String getThreadPoolName() {\n        return threadPoolName;\n    }\n\n    public void setThreadPoolName(String threadPoolName) {\n        this.threadPoolName = threadPoolName;\n    }\n\n    public ThreadPoolExecutor getThreadPoolExecutor() {\n        return threadPoolExecutor;\n    }\n\n    public void setThreadPoolExecutor(ThreadPoolExecutor threadPoolExecutor) {\n        this.threadPoolExecutor = threadPoolExecutor;\n    }\n\n    public String getApplicationName() {\n        return applicationName;\n    }\n\n    public void setApplicationName(String applicationName) {\n        this.applicationName = applicationName;\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        ThreadPoolMetric that = (ThreadPoolMetric) o;\n        return Objects.equals(applicationName, that.applicationName)\n                && Objects.equals(threadPoolName, that.threadPoolName);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(applicationName, threadPoolName);\n    }\n\n    @Override\n    public Map<String, String> getTags() {\n        Map<String, String> tags = new HashMap<>();\n        tags.put(TAG_IP, getLocalHost());\n        tags.put(TAG_PID, ConfigUtils.getPid() + \"\");\n        tags.put(TAG_HOSTNAME, getLocalHostName());\n        tags.put(TAG_APPLICATION_NAME, applicationName);\n        tags.put(TAG_THREAD_NAME, threadPoolName);\n        return tags;\n    }\n\n    public double getCorePoolSize() {\n        return threadPoolExecutor.getCorePoolSize();\n    }\n\n    public double getLargestPoolSize() {\n        return threadPoolExecutor.getLargestPoolSize();\n    }\n\n    public double getMaximumPoolSize() {\n        return threadPoolExecutor.getMaximumPoolSize();\n    }\n\n    public double getActiveCount() {\n        return threadPoolExecutor.getActiveCount();\n    }\n\n    public double getPoolSize() {\n        return threadPoolExecutor.getPoolSize();\n    }\n\n    public double getQueueSize() {\n        return threadPoolExecutor.getQueue().size();\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolRejectMetric.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\nimport org.apache.dubbo.common.utils.ConfigUtils;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_PID;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_THREAD_NAME;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHost;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHostName;\n\npublic class ThreadPoolRejectMetric implements Metric {\n\n    private String applicationName;\n\n    private String threadPoolName;\n\n    public ThreadPoolRejectMetric(String applicationName, String threadPoolName) {\n        this.applicationName = applicationName;\n        this.threadPoolName = threadPoolName;\n    }\n\n    public String getThreadPoolName() {\n        return threadPoolName;\n    }\n\n    public void setThreadPoolName(String threadPoolName) {\n        this.threadPoolName = threadPoolName;\n    }\n\n    public String getApplicationName() {\n        return applicationName;\n    }\n\n    public void setApplicationName(String applicationName) {\n        this.applicationName = applicationName;\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        ThreadPoolRejectMetric that = (ThreadPoolRejectMetric) o;\n        return Objects.equals(applicationName, that.applicationName)\n                && Objects.equals(threadPoolName, that.threadPoolName);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(applicationName, threadPoolName);\n    }\n\n    @Override\n    public Map<String, String> getTags() {\n        Map<String, String> tags = new HashMap<>();\n        tags.put(TAG_IP, getLocalHost());\n        tags.put(TAG_PID, ConfigUtils.getPid() + \"\");\n        tags.put(TAG_HOSTNAME, getLocalHostName());\n        tags.put(TAG_APPLICATION_NAME, applicationName);\n        tags.put(TAG_THREAD_NAME, threadPoolName);\n        return tags;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/container/AtomicLongContainer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.container;\n\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\n\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.function.BiConsumer;\n\npublic class AtomicLongContainer extends LongContainer<AtomicLong> {\n\n    public AtomicLongContainer(MetricsKeyWrapper metricsKeyWrapper) {\n        super(metricsKeyWrapper, AtomicLong::new, (responseTime, longAccumulator) -> longAccumulator.set(responseTime));\n    }\n\n    public AtomicLongContainer(MetricsKeyWrapper metricsKeyWrapper, BiConsumer<Long, AtomicLong> consumerFunc) {\n        super(metricsKeyWrapper, AtomicLong::new, consumerFunc);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/container/LongAccumulatorContainer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.container;\n\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\n\nimport java.util.concurrent.atomic.LongAccumulator;\n\npublic class LongAccumulatorContainer extends LongContainer<LongAccumulator> {\n    public LongAccumulatorContainer(MetricsKeyWrapper metricsKeyWrapper, LongAccumulator accumulator) {\n        super(\n                metricsKeyWrapper,\n                () -> accumulator,\n                (responseTime, longAccumulator) -> longAccumulator.accumulate(responseTime));\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/container/LongContainer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.container;\n\nimport org.apache.dubbo.metrics.model.Metric;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\n/**\n * Long type data container\n * @param <N>\n */\npublic class LongContainer<N extends Number> extends ConcurrentHashMap<Metric, N> {\n\n    /**\n     * Provide the metric type name\n     */\n    private final transient MetricsKeyWrapper metricsKeyWrapper;\n    /**\n     * The initial value corresponding to the key is generally 0 of different data types\n     */\n    private final transient Function<Metric, N> initFunc;\n    /**\n     * Statistical data calculation function, which can be self-increment, self-decrement, or more complex avg function\n     */\n    private final transient BiConsumer<Long, N> consumerFunc;\n    /**\n     * Data output function required by  {@link GaugeMetricSample GaugeMetricSample}\n     */\n    private transient Function<Metric, Long> valueSupplier;\n\n    public LongContainer(MetricsKeyWrapper metricsKeyWrapper, Supplier<N> initFunc, BiConsumer<Long, N> consumerFunc) {\n        super(128, 0.5f);\n        this.metricsKeyWrapper = metricsKeyWrapper;\n        this.initFunc = s -> initFunc.get();\n        this.consumerFunc = consumerFunc;\n        this.valueSupplier = k -> this.get(k).longValue();\n    }\n\n    public boolean specifyType(String type) {\n        return type.equals(getMetricsKeyWrapper().getType());\n    }\n\n    public MetricsKeyWrapper getMetricsKeyWrapper() {\n        return metricsKeyWrapper;\n    }\n\n    public boolean isKeyWrapper(MetricsKey metricsKey, String registryOpType) {\n        return metricsKeyWrapper.isKey(metricsKey, registryOpType);\n    }\n\n    public Function<Metric, N> getInitFunc() {\n        return initFunc;\n    }\n\n    public BiConsumer<Long, N> getConsumerFunc() {\n        return consumerFunc;\n    }\n\n    public Function<Metric, Long> getValueSupplier() {\n        return valueSupplier;\n    }\n\n    public void setValueSupplier(Function<Metric, Long> valueSupplier) {\n        this.valueSupplier = valueSupplier;\n    }\n\n    @Override\n    public String toString() {\n        return \"LongContainer{\" + \"metricsKeyWrapper=\" + metricsKeyWrapper + '}';\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        if (!super.equals(o)) return false;\n\n        LongContainer<?> that = (LongContainer<?>) o;\n\n        return metricsKeyWrapper.equals(that.metricsKeyWrapper);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = super.hashCode();\n        result = 31 * result + metricsKeyWrapper.hashCode();\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/CategoryOverall.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.key;\n\nimport org.apache.dubbo.common.lang.Nullable;\n\n/**\n *  The overall event set, including the event processing functions in three stages\n */\npublic class CategoryOverall {\n\n    private final MetricsCat post;\n    private MetricsCat finish;\n    private MetricsCat error;\n\n    /**\n     * @param placeType When placeType is null, it means that placeType is obtained dynamically\n     * @param post      Statistics of the number of events, as long as it occurs, it will take effect, so it cannot be null\n     */\n    public CategoryOverall(\n            @Nullable MetricsPlaceValue placeType,\n            MetricsCat post,\n            @Nullable MetricsCat finish,\n            @Nullable MetricsCat error) {\n        this.post = post.setPlaceType(placeType);\n        if (finish != null) {\n            this.finish = finish.setPlaceType(placeType);\n        }\n        if (error != null) {\n            this.error = error.setPlaceType(placeType);\n        }\n    }\n\n    public MetricsCat getPost() {\n        return post;\n    }\n\n    public MetricsCat getFinish() {\n        return finish;\n    }\n\n    public MetricsCat getError() {\n        return error;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsCat.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.key;\n\nimport org.apache.dubbo.metrics.collector.CombMetricsCollector;\nimport org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener;\n\nimport java.util.function.BiFunction;\nimport java.util.function.Function;\n\n/**\n * The behavior wrapper class of MetricsKey,\n * which saves the complete content of the key {@link MetricsPlaceValue},\n * the corresponding collector {@link CombMetricsCollector},\n * and the event listener (generate function) at the key level {@link AbstractMetricsKeyListener}\n */\npublic class MetricsCat {\n\n    private MetricsPlaceValue placeType;\n    private final Function<CombMetricsCollector, AbstractMetricsKeyListener> eventFunc;\n\n    /**\n     * @param metricsKey The key corresponding to the listening event, not necessarily the export key(export key may be dynamic)\n     * @param biFunc Binary function, corresponding to MetricsKey with less content, corresponding to post event\n     */\n    public MetricsCat(\n            MetricsKey metricsKey, BiFunction<MetricsKey, CombMetricsCollector, AbstractMetricsKeyListener> biFunc) {\n        this.eventFunc = collector -> biFunc.apply(metricsKey, collector);\n    }\n\n    /**\n     * @param tpFunc   Ternary function, corresponding to finish and error events, because an additional record rt is required, and the type of metricsKey is required\n     */\n    public MetricsCat(\n            MetricsKey metricsKey,\n            TpFunction<MetricsKey, MetricsPlaceValue, CombMetricsCollector, AbstractMetricsKeyListener> tpFunc) {\n        this.eventFunc = collector -> tpFunc.apply(metricsKey, placeType, collector);\n    }\n\n    public MetricsCat setPlaceType(MetricsPlaceValue placeType) {\n        this.placeType = placeType;\n        return this;\n    }\n\n    public Function<CombMetricsCollector, AbstractMetricsKeyListener> getEventFunc() {\n        return eventFunc;\n    }\n\n    @FunctionalInterface\n    public interface TpFunction<T, U, K, R> {\n        R apply(T t, U u, K k);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKeyWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.key;\n\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.Objects;\n\nimport io.micrometer.common.lang.Nullable;\n\n/**\n * Let {@link MetricsKey MetricsKey}  output dynamic, custom string content\n */\npublic class MetricsKeyWrapper {\n\n    /**\n     * Metrics key when exporting\n     */\n    private final MetricsKey metricsKey;\n\n    /**\n     * The value corresponding to the MetricsKey placeholder (if exist)\n     */\n    private final MetricsPlaceValue placeType;\n\n    /**\n     * Exported sample type\n     */\n    private MetricSample.Type sampleType = MetricSample.Type.COUNTER;\n\n    /**\n     * When the MetricsPlaceType is null, it is equivalent to a single MetricsKey.\n     * Use the decorator mode to share a container with MetricsKey\n     */\n    public MetricsKeyWrapper(MetricsKey metricsKey, @Nullable MetricsPlaceValue placeType) {\n        this.metricsKey = metricsKey;\n        this.placeType = placeType;\n    }\n\n    public MetricsKeyWrapper setSampleType(MetricSample.Type sampleType) {\n        this.sampleType = sampleType;\n        return this;\n    }\n\n    public MetricSample.Type getSampleType() {\n        return sampleType;\n    }\n\n    public MetricsPlaceValue getPlaceType() {\n        return placeType;\n    }\n\n    public String getType() {\n        return getPlaceType().getType();\n    }\n\n    public MetricsKey getMetricsKey() {\n        return metricsKey;\n    }\n\n    public boolean isKey(MetricsKey metricsKey, String registryOpType) {\n        return metricsKey == getMetricsKey() && registryOpType.equals(getType());\n    }\n\n    public MetricsLevel getLevel() {\n        return getPlaceType().getMetricsLevel();\n    }\n\n    public String targetKey() {\n        if (placeType == null) {\n            return metricsKey.getName();\n        }\n        try {\n            return String.format(metricsKey.getName(), getType());\n        } catch (Exception ignore) {\n            return metricsKey.getName();\n        }\n    }\n\n    public String targetDesc() {\n        if (placeType == null) {\n            return metricsKey.getDescription();\n        }\n        try {\n            return String.format(metricsKey.getDescription(), getType());\n        } catch (Exception ignore) {\n            return metricsKey.getDescription();\n        }\n    }\n\n    public static MetricsKeyWrapper wrapper(MetricsKey metricsKey) {\n        return new MetricsKeyWrapper(metricsKey, null);\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        MetricsKeyWrapper wrapper = (MetricsKeyWrapper) o;\n\n        if (metricsKey != wrapper.metricsKey) return false;\n        return Objects.equals(placeType, wrapper.placeType);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = metricsKey != null ? metricsKey.hashCode() : 0;\n        result = 31 * result + (placeType != null ? placeType.hashCode() : 0);\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsPlaceValue.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.key;\n\n/**\n * The value corresponding to the placeholder in {@link MetricsKey}\n */\npublic class MetricsPlaceValue {\n\n    private final String type;\n    private final MetricsLevel metricsLevel;\n\n    private MetricsPlaceValue(String type, MetricsLevel metricsLevel) {\n        this.type = type;\n        this.metricsLevel = metricsLevel;\n    }\n\n    public static MetricsPlaceValue of(String type, MetricsLevel metricsLevel) {\n        return new MetricsPlaceValue(type, metricsLevel);\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public MetricsLevel getMetricsLevel() {\n        return metricsLevel;\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        MetricsPlaceValue that = (MetricsPlaceValue) o;\n\n        if (!type.equals(that.type)) return false;\n        return metricsLevel == that.metricsLevel;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = type.hashCode();\n        result = 31 * result + metricsLevel.hashCode();\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/sample/CounterMetricSample.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.sample;\n\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\n\nimport java.util.Map;\n\npublic class CounterMetricSample<T extends Number> extends MetricSample {\n\n    private final T value;\n\n    public CounterMetricSample(\n            String name, String description, Map<String, String> tags, MetricsCategory category, T value) {\n        super(name, description, tags, Type.COUNTER, category);\n        this.value = value;\n    }\n\n    public CounterMetricSample(\n            MetricsKeyWrapper metricsKeyWrapper, Map<String, String> tags, MetricsCategory category, T value) {\n        this(metricsKeyWrapper.targetKey(), metricsKeyWrapper.targetDesc(), tags, category, value);\n    }\n\n    public T getValue() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/sample/GaugeMetricSample.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.sample;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\n\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.ToDoubleFunction;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION;\n\n/**\n * GaugeMetricSample.\n */\npublic class GaugeMetricSample<T> extends MetricSample {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(GaugeMetricSample.class);\n    private final AtomicBoolean warned = new AtomicBoolean(false);\n\n    private final T value;\n\n    private final ToDoubleFunction<T> apply;\n\n    public GaugeMetricSample(\n            MetricsKey metricsKey,\n            Map<String, String> tags,\n            MetricsCategory category,\n            T value,\n            ToDoubleFunction<T> apply) {\n        this(metricsKey.getName(), metricsKey.getDescription(), tags, category, null, value, apply);\n    }\n\n    public GaugeMetricSample(\n            MetricsKeyWrapper metricsKeyWrapper,\n            Map<String, String> tags,\n            MetricsCategory category,\n            T value,\n            ToDoubleFunction<T> apply) {\n        this(metricsKeyWrapper.targetKey(), metricsKeyWrapper.targetDesc(), tags, category, null, value, apply);\n    }\n\n    public GaugeMetricSample(\n            String name,\n            String description,\n            Map<String, String> tags,\n            MetricsCategory category,\n            T value,\n            ToDoubleFunction<T> apply) {\n        this(name, description, tags, category, null, value, apply);\n    }\n\n    public GaugeMetricSample(\n            String name,\n            String description,\n            Map<String, String> tags,\n            MetricsCategory category,\n            String baseUnit,\n            T value,\n            ToDoubleFunction<T> apply) {\n        super(name, description, tags, Type.GAUGE, category, baseUnit);\n        this.value = Objects.requireNonNull(value, \"The GaugeMetricSample value cannot be null\");\n        Objects.requireNonNull(apply, \"The GaugeMetricSample apply cannot be null\");\n        this.apply = (e) -> {\n            try {\n                return apply.applyAsDouble(e);\n            } catch (Throwable t) {\n                if (warned.compareAndSet(false, true)) {\n                    logger.error(\n                            COMMON_METRICS_COLLECTOR_EXCEPTION,\n                            \"\",\n                            \"\",\n                            \"Unexpected error occurred when applying the GaugeMetricSample\",\n                            t);\n                }\n                return 0;\n            }\n        };\n    }\n\n    public T getValue() {\n        return this.value;\n    }\n\n    public ToDoubleFunction<T> getApply() {\n        return this.apply;\n    }\n\n    public long applyAsLong() {\n        return (long) getApply().applyAsDouble(getValue());\n    }\n\n    public double applyAsDouble() {\n        return getApply().applyAsDouble(getValue());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/sample/MetricSample.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.sample;\n\nimport org.apache.dubbo.metrics.model.MetricsCategory;\n\nimport java.util.Map;\nimport java.util.Objects;\n\n/**\n * MetricSample.\n */\npublic class MetricSample {\n    private String name;\n    private String description;\n    private Map<String, String> tags;\n    private Type type;\n    private MetricsCategory category;\n    private String baseUnit;\n\n    public MetricSample(\n            String name, String description, Map<String, String> tags, Type type, MetricsCategory category) {\n        this(name, description, tags, type, category, null);\n    }\n\n    public MetricSample(\n            String name,\n            String description,\n            Map<String, String> tags,\n            Type type,\n            MetricsCategory category,\n            String baseUnit) {\n        this.name = name;\n        this.description = description;\n        this.tags = tags;\n        this.type = type;\n        this.category = category;\n        this.baseUnit = baseUnit;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    public Map<String, String> getTags() {\n        return tags;\n    }\n\n    public void setTags(Map<String, String> tags) {\n        this.tags = tags;\n    }\n\n    public Type getType() {\n        return type;\n    }\n\n    public void setType(Type type) {\n        this.type = type;\n    }\n\n    public MetricsCategory getCategory() {\n        return category;\n    }\n\n    public void setCategory(MetricsCategory category) {\n        this.category = category;\n    }\n\n    public String getBaseUnit() {\n        return baseUnit;\n    }\n\n    public void setBaseUnit(String baseUnit) {\n        this.baseUnit = baseUnit;\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        MetricSample that = (MetricSample) o;\n        return Objects.equals(name, that.name)\n                && Objects.equals(description, that.description)\n                && Objects.equals(baseUnit, that.baseUnit)\n                && type == that.type\n                && Objects.equals(category, that.category)\n                && Objects.equals(tags, that.tags);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name, description, baseUnit, type, category, tags);\n    }\n\n    @Override\n    public String toString() {\n        return \"MetricSample{\" + \"name='\"\n                + name + '\\'' + \", description='\"\n                + description + '\\'' + \", baseUnit='\"\n                + baseUnit + '\\'' + \", type=\"\n                + type + \", category=\"\n                + category + \", tags=\"\n                + tags + '}';\n    }\n\n    public enum Type {\n        COUNTER,\n        GAUGE,\n        LONG_TASK_TIMER,\n        TIMER,\n        DISTRIBUTION_SUMMARY\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsExport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.report;\n\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\n/**\n * Store public information such as application\n */\npublic abstract class AbstractMetricsExport implements MetricsExport {\n\n    private volatile Boolean serviceLevel;\n\n    private final ApplicationModel applicationModel;\n\n    public AbstractMetricsExport(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    public ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    public String getAppName() {\n        return getApplicationModel().getApplicationName();\n    }\n\n    protected boolean getServiceLevel() {\n        initServiceLevelConfig();\n        return this.serviceLevel;\n    }\n\n    private void initServiceLevelConfig() {\n        if (serviceLevel == null) {\n            synchronized (this) {\n                if (serviceLevel == null) {\n                    this.serviceLevel = MethodMetric.isServiceLevel(getApplicationModel());\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsReporterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.report;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\n/**\n * AbstractMetricsReporterFactory.\n */\npublic abstract class AbstractMetricsReporterFactory implements MetricsReporterFactory {\n\n    private final ApplicationModel applicationModel;\n\n    public AbstractMetricsReporterFactory(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    protected ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/report/MetricsExport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.report;\n\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.List;\n\n/**\n * Metrics data export.\n * Export data in a unified format for external collection(e.g. Prometheus).\n */\npublic interface MetricsExport {\n\n    /**\n     * export all.\n     */\n    List<MetricSample> export(MetricsCategory category);\n\n    /**\n     * Check if samples have been changed.\n     * Note that this method will reset the changed flag to false using CAS.\n     *\n     * @return true if samples have been changed\n     */\n    boolean calSamplesChanged();\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/report/MetricsReporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.report;\n\n/**\n * Metrics Reporter.\n * Report metrics to specific metrics server(e.g. Prometheus).\n */\npublic interface MetricsReporter {\n\n    /**\n     * Initialize metrics reporter.\n     */\n    void init();\n\n    void resetIfSamplesChanged();\n\n    String getResponse();\n\n    default String getResponseWithName(String metricsName) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/report/MetricsReporterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.report;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * The factory interface to create the instance of {@link MetricsReporter}.\n */\n@SPI(value = \"nop\", scope = ExtensionScope.APPLICATION)\npublic interface MetricsReporterFactory {\n\n    /**\n     * Create metrics reporter.\n     *\n     * @param url URL\n     * @return Metrics reporter implementation.\n     */\n    @Adaptive({CommonConstants.PROTOCOL_KEY})\n    MetricsReporter createMetricsReporter(URL url);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/service/MetricsEntity.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.service;\n\nimport org.apache.dubbo.metrics.model.MetricsCategory;\n\nimport java.util.Map;\nimport java.util.Objects;\n\n/**\n * Metrics response entity.\n */\npublic class MetricsEntity {\n\n    private String name;\n    private Map<String, String> tags;\n    private MetricsCategory category;\n    private Object value;\n\n    public MetricsEntity() {}\n\n    public MetricsEntity(String name, Map<String, String> tags, MetricsCategory category, Object value) {\n        this.name = name;\n        this.tags = tags;\n        this.category = category;\n        this.value = value;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Map<String, String> getTags() {\n        return tags;\n    }\n\n    public void setTags(Map<String, String> tags) {\n        this.tags = tags;\n    }\n\n    public MetricsCategory getCategory() {\n        return category;\n    }\n\n    public void setCategory(MetricsCategory category) {\n        this.category = category;\n    }\n\n    public Object getValue() {\n        return value;\n    }\n\n    public void setValue(Object value) {\n        this.value = value;\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        MetricsEntity entity = (MetricsEntity) o;\n        return Objects.equals(name, entity.name)\n                && Objects.equals(tags, entity.tags)\n                && Objects.equals(category, entity.category)\n                && Objects.equals(value, entity.value);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name, tags, category, value);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/service/MetricsService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.service;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.metrics.collector.MetricsCollector;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.apache.dubbo.metrics.service.MetricsService.DEFAULT_EXTENSION_NAME;\n\n/**\n * Metrics Service.\n * Provide an interface to get metrics from {@link MetricsCollector}\n */\n@SPI(value = DEFAULT_EXTENSION_NAME, scope = ExtensionScope.APPLICATION)\npublic interface MetricsService {\n\n    /**\n     * Default {@link MetricsService} extension name.\n     */\n    String DEFAULT_EXTENSION_NAME = \"default\";\n\n    /**\n     * The contract version of {@link MetricsService}, the future update must make sure compatible.\n     */\n    String VERSION = \"1.0.0\";\n\n    /**\n     * Get metrics by prefixes\n     *\n     * @param categories categories\n     * @return metrics - key=MetricCategory value=MetricsEntityList\n     */\n    Map<MetricsCategory, List<MetricsEntity>> getMetricsByCategories(List<MetricsCategory> categories);\n\n    /**\n     * Get metrics by interface and prefixes\n     *\n     * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version)\n     * @param categories categories\n     * @return metrics - key=MetricCategory value=MetricsEntityList\n     */\n    Map<MetricsCategory, List<MetricsEntity>> getMetricsByCategories(\n            String serviceUniqueName, List<MetricsCategory> categories);\n\n    /**\n     * Get metrics by interface、method and prefixes\n     *\n     * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version)\n     * @param methodName methodName\n     * @param parameterTypes method parameter types\n     * @param categories categories\n     * @return metrics - key=MetricCategory value=MetricsEntityList\n     */\n    Map<MetricsCategory, List<MetricsEntity>> getMetricsByCategories(\n            String serviceUniqueName, String methodName, Class<?>[] parameterTypes, List<MetricsCategory> categories);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/service/MetricsServiceExporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.service;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * The exporter of {@link MetricsService}\n */\n@SPI(value = \"default\", scope = ExtensionScope.APPLICATION)\npublic interface MetricsServiceExporter {\n\n    /**\n     * Initialize exporter\n     */\n    void init();\n\n    /**\n     * Exports the {@link MetricsService} as a Dubbo service\n     *\n     * @return {@link MetricsServiceExporter itself}\n     */\n    MetricsServiceExporter export();\n\n    /**\n     * Unexports the {@link MetricsService}\n     *\n     * @return {@link MetricsServiceExporter itself}\n     */\n    MetricsServiceExporter unexport();\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/utils/MetricsSupportUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.utils;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\n\npublic class MetricsSupportUtil {\n\n    public static boolean isSupportMetrics() {\n        return isClassPresent(\"io.micrometer.core.instrument.MeterRegistry\");\n    }\n\n    public static boolean isSupportPrometheus() {\n        return isClassPresent(\"io.micrometer.prometheus.PrometheusConfig\")\n                && isClassPresent(\"io.prometheus.client.exporter.BasicAuthHttpConnectionFactory\")\n                && isClassPresent(\"io.prometheus.client.exporter.HttpConnectionFactory\")\n                && isClassPresent(\"io.prometheus.client.exporter.PushGateway\");\n    }\n\n    private static boolean isClassPresent(String className) {\n        return ClassUtils.isPresent(className, MetricsSupportUtil.class.getClassLoader());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/monitor/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.monitor;\n\n@Deprecated\npublic interface Constants {\n    String DUBBO_PROVIDER = \"dubbo.provider\";\n\n    String DUBBO_CONSUMER = \"dubbo.consumer\";\n\n    String DUBBO_PROVIDER_METHOD = \"dubbo.provider.method\";\n\n    String DUBBO_CONSUMER_METHOD = \"dubbo.consumer.method\";\n\n    String SERVICE = \"service\";\n\n    String DUBBO_GROUP = \"dubbo\";\n\n    String LOGSTAT_PROTOCOL = \"logstat\";\n\n    String COUNT_PROTOCOL = \"count\";\n\n    String MONITOR_SEND_DATA_INTERVAL_KEY = \"interval\";\n\n    int DEFAULT_MONITOR_SEND_DATA_INTERVAL = 60000;\n\n    String SUCCESS_KEY = \"success\";\n\n    String FAILURE_KEY = \"failure\";\n\n    String INPUT_KEY = \"input\";\n\n    String OUTPUT_KEY = \"output\";\n\n    String ELAPSED_KEY = \"elapsed\";\n\n    String CONCURRENT_KEY = \"concurrent\";\n\n    String MAX_INPUT_KEY = \"max.input\";\n\n    String MAX_OUTPUT_KEY = \"max.output\";\n\n    String MAX_ELAPSED_KEY = \"max.elapsed\";\n\n    String MAX_CONCURRENT_KEY = \"max.concurrent\";\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/monitor/Monitor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.monitor;\n\nimport org.apache.dubbo.common.Node;\n\n/**\n * Monitor. (SPI, Prototype, ThreadSafe)\n *\n * @see org.apache.dubbo.monitor.MonitorFactory#getMonitor(org.apache.dubbo.common.URL)\n */\n@Deprecated\npublic interface Monitor extends Node, MonitorService {}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/monitor/MonitorFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.monitor;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * MonitorFactory. (SPI, Singleton, ThreadSafe)\n */\n@Deprecated\n@SPI\npublic interface MonitorFactory {\n\n    /**\n     * Create monitor.\n     *\n     * @param url\n     * @return monitor\n     */\n    @Adaptive(CommonConstants.PROTOCOL_KEY)\n    Monitor getMonitor(URL url);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/monitor/MonitorService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.monitor;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.List;\n\n/**\n * MonitorService. (SPI, Prototype, ThreadSafe)\n */\n@Deprecated\npublic interface MonitorService {\n\n    /**\n     * Collect monitor data\n     * 1. support invocation count: count://host/interface?application=foo&method=foo&provider=10.20.153.11:20880&success=12&failure=2&elapsed=135423423\n     * 1.1 host,application,interface,group,version,method: record source host/application/interface/method\n     * 1.2 add provider address parameter if it's data sent from consumer, otherwise, add source consumer's address in parameters\n     * 1.3 success,failure,elapsed: record success count, failure count, and total cost for success invocations, average cost (total cost/success calls)\n     *\n     * @param statistics\n     */\n    void collect(URL statistics);\n\n    /**\n     * Lookup monitor data\n     * 1. support lookup by day: count://host/interface?application=foo&method=foo&side=provider&view=chart&date=2012-07-03\n     * 1.1 host,application,interface,group,version,method: query criteria for looking up by host, application, interface, method. When one criterion is not present, it means ALL will be accepted, but 0.0.0.0 is ALL for host\n     * 1.2 side=consumer,provider: decide the data from which side, both provider and consumer are returned by default\n     * 1.3 default value is view=summary, to return the summarized data for the whole day. view=chart will return the URL address showing the whole day trend which is convenient for embedding in other web page\n     * 1.4 date=2012-07-03: specify the date to collect the data, today is the default value\n     *\n     * @param query\n     * @return statistics\n     */\n    List<URL> lookup(URL query);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/MetricsSupportTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.ServiceKeyMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;\n\npublic class MetricsSupportTest {\n\n    @AfterEach\n    public void destroy() {\n        ApplicationModel.defaultModel().destroy();\n    }\n\n    @Test\n    void testFillZero() {\n        ApplicationModel applicationModel = FrameworkModel.defaultModel().newApplication();\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n        applicationModel.getApplicationConfigManager().setApplication(config);\n\n        ConcurrentHashMap<MetricsKeyWrapper, ConcurrentHashMap<ServiceKeyMetric, AtomicLong>> data =\n                new ConcurrentHashMap<>();\n        MetricsKeyWrapper key1 = new MetricsKeyWrapper(\n                METRIC_REQUESTS, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD));\n        MetricsKeyWrapper key2 = new MetricsKeyWrapper(\n                METRIC_REQUESTS, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD));\n        ServiceKeyMetric sm1 = new ServiceKeyMetric(applicationModel, \"a.b.c\");\n        ServiceKeyMetric sm2 = new ServiceKeyMetric(applicationModel, \"a.b.d\");\n        data.computeIfAbsent(key1, k -> new ConcurrentHashMap<>()).put(sm1, new AtomicLong(1));\n        data.computeIfAbsent(key1, k -> new ConcurrentHashMap<>()).put(sm2, new AtomicLong(1));\n        data.put(key2, new ConcurrentHashMap<>());\n        Assertions.assertEquals(\n                2, data.values().stream().mapToLong(map -> map.values().size()).sum());\n        MetricsSupport.fillZero(data);\n        Assertions.assertEquals(\n                4, data.values().stream().mapToLong(map -> map.values().size()).sum());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/aggregate/PaneTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\nimport java.util.concurrent.atomic.LongAdder;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass PaneTest {\n\n    @Test\n    void testIntervalInMs() {\n        Pane<?> pane = mock(Pane.class);\n        when(pane.getIntervalInMs()).thenReturn(100L);\n        assertEquals(100L, pane.getIntervalInMs());\n    }\n\n    @Test\n    void testStartInMs() {\n        Pane<?> pane = mock(Pane.class);\n        long startTime = System.currentTimeMillis();\n        when(pane.getStartInMs()).thenReturn(startTime);\n        assertEquals(startTime, pane.getStartInMs());\n    }\n\n    @Test\n    void testEndInMs() {\n        long startTime = System.currentTimeMillis();\n        Pane<?> pane = new Pane<>(10, startTime, new Object());\n        assertEquals(startTime + 10, pane.getEndInMs());\n    }\n\n    @Test\n    @SuppressWarnings(\"unchecked\")\n    void testValue() {\n        Pane<LongAdder> pane = mock(Pane.class);\n        LongAdder count = new LongAdder();\n        when(pane.getValue()).thenReturn(count);\n        assertEquals(count, pane.getValue());\n        when(pane.getValue()).thenReturn(null);\n        assertNotEquals(count, pane.getValue());\n    }\n\n    @Test\n    void testIsTimeInWindow() {\n        Pane<?> pane = new Pane<>(10, System.currentTimeMillis(), new Object());\n        assertTrue(pane.isTimeInWindow(System.currentTimeMillis()));\n        assertFalse(pane.isTimeInWindow(System.currentTimeMillis() + 10));\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/aggregate/SlidingWindowTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\nimport java.util.concurrent.atomic.LongAdder;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.RepeatedTest;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass SlidingWindowTest {\n\n    static final int paneCount = 10;\n\n    static final long intervalInMs = 2000;\n\n    TestSlidingWindow window;\n\n    @BeforeEach\n    void setup() {\n        window = new TestSlidingWindow(paneCount, intervalInMs);\n    }\n\n    @RepeatedTest(1000)\n    void testCurrentPane() {\n        assertNull(window.currentPane(/* invalid time*/ -1L));\n        long timeInMs = System.currentTimeMillis();\n        Pane<LongAdder> currentPane = window.currentPane(timeInMs);\n        assertNotNull(currentPane);\n        // reuse test\n        assertEquals(currentPane, window.currentPane(timeInMs + window.getPaneIntervalInMs() * paneCount));\n    }\n\n    @Test\n    void testGetPaneData() {\n        assertNull(window.getPaneValue(/* invalid time*/ -1L));\n        long time = System.currentTimeMillis();\n        window.currentPane(time);\n        assertNotNull(window.getPaneValue(time));\n        assertNull(window.getPaneValue(time + window.getPaneIntervalInMs()));\n    }\n\n    @Test\n    void testNewEmptyValue() {\n        assertEquals(0L, window.newEmptyValue(System.currentTimeMillis()).sum());\n    }\n\n    @Test\n    void testResetPaneTo() {\n        Pane<LongAdder> currentPane = window.currentPane();\n        currentPane.getValue().add(2);\n        currentPane.getValue().add(1);\n        assertEquals(3, currentPane.getValue().sum());\n        window.resetPaneTo(currentPane, System.currentTimeMillis());\n        assertEquals(0, currentPane.getValue().sum());\n        currentPane.getValue().add(1);\n        assertEquals(1, currentPane.getValue().sum());\n    }\n\n    @Test\n    void testCalculatePaneStart() {\n        long time = System.currentTimeMillis();\n        assertTrue(window.calculatePaneStart(time) <= time);\n        assertTrue(time < window.calculatePaneStart(time) + window.getPaneIntervalInMs());\n    }\n\n    @Test\n    void testIsPaneDeprecated() {\n        Pane<LongAdder> currentPane = window.currentPane();\n        currentPane.setStartInMs(1000000L);\n        assertTrue(window.isPaneDeprecated(currentPane));\n    }\n\n    @Test\n    void testList() {\n        window.currentPane();\n        assertTrue(0 < window.list().size());\n    }\n\n    @Test\n    void testValues() {\n        window.currentPane().getValue().add(10);\n        long sum = 0;\n        for (LongAdder value : window.values()) {\n            sum += value.sum();\n        }\n        assertEquals(10, sum);\n    }\n\n    @Test\n    void testGetIntervalInMs() {\n        assertEquals(intervalInMs, window.getIntervalInMs());\n    }\n\n    @Test\n    void testGetPaneIntervalInMs() {\n        assertEquals(intervalInMs / paneCount, window.getPaneIntervalInMs());\n    }\n\n    private static class TestSlidingWindow extends SlidingWindow<LongAdder> {\n\n        public TestSlidingWindow(int paneCount, long intervalInMs) {\n            super(paneCount, intervalInMs);\n        }\n\n        @Override\n        public LongAdder newEmptyValue(long timeMillis) {\n            return new LongAdder();\n        }\n\n        @Override\n        protected Pane<LongAdder> resetPaneTo(Pane<LongAdder> pane, long startInMs) {\n            pane.setStartInMs(startInMs);\n            pane.getValue().reset();\n            return pane;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/aggregate/TimeWindowAggregatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\npublic class TimeWindowAggregatorTest {\n    @Test\n    public void testTimeWindowAggregator() {\n        TimeWindowAggregator aggregator = new TimeWindowAggregator(5, 5);\n\n        // First time window, time range: 0 - 5 seconds\n\n        aggregator.add(10);\n        aggregator.add(20);\n        aggregator.add(30);\n\n        SampleAggregatedEntry entry1 = aggregator.get();\n        Assertions.assertEquals(20, entry1.getAvg());\n        Assertions.assertEquals(60, entry1.getTotal());\n        Assertions.assertEquals(3, entry1.getCount());\n        Assertions.assertEquals(30, entry1.getMax());\n        Assertions.assertEquals(10, entry1.getMin());\n\n        // Second time window, time range: 5 - 10 seconds\n        try {\n            TimeUnit.SECONDS.sleep(5);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n\n        aggregator.add(15);\n        aggregator.add(25);\n        aggregator.add(35);\n\n        SampleAggregatedEntry entry2 = aggregator.get();\n        Assertions.assertEquals(25, entry2.getAvg());\n        Assertions.assertEquals(75, entry2.getTotal());\n        Assertions.assertEquals(3, entry2.getCount());\n        Assertions.assertEquals(35, entry2.getMax());\n        Assertions.assertEquals(15, entry2.getMin());\n\n        // Third time window, time range: 10 - 15 seconds\n\n        try {\n            TimeUnit.SECONDS.sleep(5);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        aggregator.add(12);\n        aggregator.add(22);\n        aggregator.add(32);\n\n        SampleAggregatedEntry entry3 = aggregator.get();\n        Assertions.assertEquals(22, entry3.getAvg());\n        Assertions.assertEquals(66, entry3.getTotal());\n        Assertions.assertEquals(3, entry3.getCount());\n        Assertions.assertEquals(32, entry3.getMax());\n        Assertions.assertEquals(12, entry3.getMin());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/aggregate/TimeWindowCounterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass TimeWindowCounterTest {\n\n    @Test\n    void test() {\n        TimeWindowCounter counter = new TimeWindowCounter(10, 1);\n        counter.increment();\n        Assertions.assertEquals(1, counter.get());\n        counter.decrement();\n        Assertions.assertEquals(0, counter.get());\n        counter.increment();\n        counter.increment();\n        Assertions.assertEquals(2, counter.get());\n        Assertions.assertTrue(counter.bucketLivedSeconds() <= 1);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/aggregate/TimeWindowQuantileTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aggregate;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.RepeatedTest;\nimport org.junit.jupiter.api.Test;\n\nclass TimeWindowQuantileTest {\n\n    @Test\n    void test() {\n        TimeWindowQuantile quantile = new TimeWindowQuantile(100, 10, 1);\n        for (int i = 1; i <= 100; i++) {\n            quantile.add(i);\n        }\n\n        Assertions.assertEquals(quantile.quantile(0.01), 2);\n        Assertions.assertEquals(quantile.quantile(0.99), 100);\n    }\n\n    @Test\n    @RepeatedTest(100)\n    void testMulti() {\n\n        ExecutorService executorService = Executors.newFixedThreadPool(200);\n\n        TimeWindowQuantile quantile = new TimeWindowQuantile(100, 10, 120);\n        int index = 0;\n        while (index < 100) {\n            for (int i = 0; i < 100; i++) {\n                int finalI = i;\n                Assertions.assertDoesNotThrow(() -> quantile.add(finalI));\n                executorService.execute(() -> quantile.add(finalI));\n            }\n            index++;\n            //            try {\n            //                Thread.sleep(1);\n            //            } catch (InterruptedException e) {\n            //                e.printStackTrace();\n            //            }\n        }\n\n        executorService.shutdown();\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticasterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.event;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.metrics.listener.AbstractMetricsListener;\nimport org.apache.dubbo.metrics.listener.MetricsLifeListener;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_DEFAULT;\n\npublic class SimpleMetricsEventMulticasterTest {\n\n    private SimpleMetricsEventMulticaster eventMulticaster;\n    private Object[] objects;\n    private final Object obj = new Object();\n    private TimeCounterEvent requestEvent;\n\n    @BeforeEach\n    public void setup() {\n        eventMulticaster = new SimpleMetricsEventMulticaster();\n        objects = new Object[] {obj};\n        eventMulticaster.addListener(new AbstractMetricsListener<MetricsEvent>() {\n            @Override\n            public void onEvent(MetricsEvent event) {\n                objects[0] = new Object();\n            }\n        });\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"provider-app\");\n        applicationConfig.setExecutorManagementMode(EXECUTOR_MANAGEMENT_MODE_DEFAULT);\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n        ConfigManager configManager = new ConfigManager(applicationModel);\n        configManager.setApplication(applicationConfig);\n        applicationModel.setConfigManager(configManager);\n        requestEvent = new TimeCounterEvent(applicationModel, null) {};\n    }\n\n    @AfterEach\n    public void destroy() {\n        ApplicationModel.defaultModel().destroy();\n    }\n\n    @Test\n    void testPublishFinishEvent() {\n\n        // do nothing with no MetricsLifeListener\n        eventMulticaster.publishFinishEvent(requestEvent);\n        Assertions.assertSame(obj, objects[0]);\n\n        // do onEventFinish with MetricsLifeListener\n        eventMulticaster.addListener((new MetricsLifeListener<TimeCounterEvent>() {\n\n            @Override\n            public boolean isSupport(MetricsEvent event) {\n                return event instanceof TimeCounterEvent;\n            }\n\n            @Override\n            public void onEvent(TimeCounterEvent event) {}\n\n            @Override\n            public void onEventFinish(TimeCounterEvent event) {\n                objects[0] = new Object();\n            }\n\n            @Override\n            public void onEventError(TimeCounterEvent event) {}\n        }));\n        eventMulticaster.publishFinishEvent(requestEvent);\n        Assertions.assertNotSame(obj, objects[0]);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/model/ApplicationMetricTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.*;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHost;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHostName;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_GIT_COMMITID_METRIC;\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass ApplicationMetricTest {\n\n    @Test\n    void getApplicationModel() {\n        ApplicationMetric applicationMetric = new ApplicationMetric(ApplicationModel.defaultModel());\n        Assertions.assertNotNull(applicationMetric.getApplicationModel());\n    }\n\n    @Test\n    void getApplicationName() {\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        String mockMetrics = \"MockMetrics\";\n        applicationModel\n                .getApplicationConfigManager()\n                .setApplication(new org.apache.dubbo.config.ApplicationConfig(mockMetrics));\n        ApplicationMetric applicationMetric = new ApplicationMetric(applicationModel);\n        Assertions.assertNotNull(applicationMetric);\n        Assertions.assertEquals(mockMetrics, applicationMetric.getApplicationName());\n    }\n\n    @Test\n    void getTags() {\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        String mockMetrics = \"MockMetrics\";\n        applicationModel\n                .getApplicationConfigManager()\n                .setApplication(new org.apache.dubbo.config.ApplicationConfig(mockMetrics));\n        ApplicationMetric applicationMetric = new ApplicationMetric(applicationModel);\n        Map<String, String> tags = applicationMetric.getTags();\n        Assertions.assertEquals(tags.get(TAG_IP), getLocalHost());\n        Assertions.assertEquals(tags.get(TAG_HOSTNAME), getLocalHostName());\n        Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());\n        Assertions.assertEquals(tags.get(METADATA_GIT_COMMITID_METRIC.getName()), Version.getLastCommitId());\n    }\n\n    @Test\n    void gitTags() {\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        String mockMetrics = \"MockMetrics\";\n        applicationModel\n                .getApplicationConfigManager()\n                .setApplication(new org.apache.dubbo.config.ApplicationConfig(mockMetrics));\n        ApplicationMetric applicationMetric = new ApplicationMetric(applicationModel);\n        Map<String, String> tags = applicationMetric.getTags();\n        Assertions.assertEquals(tags.get(METADATA_GIT_COMMITID_METRIC.getName()), Version.getLastCommitId());\n    }\n\n    @Test\n    void hostTags() {\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        String mockMetrics = \"MockMetrics\";\n        applicationModel\n                .getApplicationConfigManager()\n                .setApplication(new org.apache.dubbo.config.ApplicationConfig(mockMetrics));\n        ApplicationMetric applicationMetric = new ApplicationMetric(applicationModel);\n        Map<String, String> tags = applicationMetric.getTags();\n        Assertions.assertEquals(tags.get(TAG_IP), getLocalHost());\n        Assertions.assertEquals(tags.get(TAG_HOSTNAME), getLocalHostName());\n    }\n\n    @Test\n    void getExtraInfo() {}\n\n    @Test\n    void setExtraInfo() {}\n\n    @Test\n    void testEquals() {}\n\n    @Test\n    void testHashCode() {}\n\n    @AfterEach\n    public void destroy() {\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        applicationModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-api/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-config-center/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n      http://www.apache.org/licenses/LICENSE-2.0\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metrics</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-metrics-config-center</artifactId>\n  <name>${project.artifactId}</name>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-config-center/src/main/java/org/apache/dubbo/metrics/config/ConfigCenterMetricsConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.config;\n\npublic interface ConfigCenterMetricsConstants {\n\n    String ATTACHMENT_KEY_CONFIG_FILE = \"configFileKey\";\n    String ATTACHMENT_KEY_CONFIG_GROUP = \"configGroup\";\n    String ATTACHMENT_KEY_CONFIG_PROTOCOL = \"configProtocol\";\n    String ATTACHMENT_KEY_CHANGE_TYPE = \"configChangeType\";\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-config-center/src/main/java/org/apache/dubbo/metrics/config/collector/ConfigCenterMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.config.collector;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.metrics.collector.CombMetricsCollector;\nimport org.apache.dubbo.metrics.collector.MetricsCollector;\nimport org.apache.dubbo.metrics.config.event.ConfigCenterEvent;\nimport org.apache.dubbo.metrics.config.event.ConfigCenterSubDispatcher;\nimport org.apache.dubbo.metrics.model.ConfigCenterMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport static org.apache.dubbo.metrics.model.MetricsCategory.CONFIGCENTER;\n\n/**\n * Config center implementation of {@link MetricsCollector}\n */\n@Activate\npublic class ConfigCenterMetricsCollector extends CombMetricsCollector<ConfigCenterEvent> {\n\n    private Boolean collectEnabled = null;\n    private final ApplicationModel applicationModel;\n    private final AtomicBoolean samplesChanged = new AtomicBoolean(true);\n\n    private final ConcurrentHashMap<ConfigCenterMetric, AtomicLong> updatedMetrics = new ConcurrentHashMap<>();\n\n    public ConfigCenterMetricsCollector(ApplicationModel applicationModel) {\n        super(null);\n        this.applicationModel = applicationModel;\n        super.setEventMulticaster(new ConfigCenterSubDispatcher(this));\n    }\n\n    public void setCollectEnabled(Boolean collectEnabled) {\n        if (collectEnabled != null) {\n            this.collectEnabled = collectEnabled;\n        }\n    }\n\n    @Override\n    public boolean isCollectEnabled() {\n        if (collectEnabled == null) {\n            ConfigManager configManager = applicationModel.getApplicationConfigManager();\n            configManager.getMetrics().ifPresent(metricsConfig -> setCollectEnabled(metricsConfig.getEnableMetadata()));\n        }\n        return Optional.ofNullable(collectEnabled).orElse(false);\n    }\n\n    public void increase(String key, String group, String protocol, String changeTypeName, int size) {\n        if (!isCollectEnabled()) {\n            return;\n        }\n        ConfigCenterMetric metric =\n                new ConfigCenterMetric(applicationModel.getApplicationName(), key, group, protocol, changeTypeName);\n        AtomicLong metrics = updatedMetrics.get(metric);\n        if (metrics == null) {\n            metrics = ConcurrentHashMapUtils.computeIfAbsent(updatedMetrics, metric, k -> new AtomicLong(0L));\n            samplesChanged.set(true);\n        }\n        metrics.addAndGet(size);\n    }\n\n    @Override\n    public List<MetricSample> collect() {\n        // Add metrics to reporter\n        List<MetricSample> list = new ArrayList<>();\n        if (!isCollectEnabled()) {\n            return list;\n        }\n        updatedMetrics.forEach((k, v) -> list.add(new GaugeMetricSample<>(\n                MetricsKey.CONFIGCENTER_METRIC_TOTAL, k.getTags(), CONFIGCENTER, v, AtomicLong::get)));\n        return list;\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // CAS to get and reset the flag in an atomic operation\n        return samplesChanged.compareAndSet(true, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-config-center/src/main/java/org/apache/dubbo/metrics/config/event/ConfigCenterEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.config.event;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.metrics.config.collector.ConfigCenterMetricsCollector;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.TypeWrapper;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SIZE;\nimport static org.apache.dubbo.metrics.config.ConfigCenterMetricsConstants.ATTACHMENT_KEY_CHANGE_TYPE;\nimport static org.apache.dubbo.metrics.config.ConfigCenterMetricsConstants.ATTACHMENT_KEY_CONFIG_FILE;\nimport static org.apache.dubbo.metrics.config.ConfigCenterMetricsConstants.ATTACHMENT_KEY_CONFIG_GROUP;\nimport static org.apache.dubbo.metrics.config.ConfigCenterMetricsConstants.ATTACHMENT_KEY_CONFIG_PROTOCOL;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.CONFIGCENTER_METRIC_TOTAL;\n\n/**\n * Registry related events\n * Triggered in three types of configuration centers (apollo, zk, nacos)\n */\npublic class ConfigCenterEvent extends TimeCounterEvent {\n\n    public static final String NACOS_PROTOCOL = \"nacos\";\n    public static final String APOLLO_PROTOCOL = \"apollo\";\n    public static final String ZK_PROTOCOL = \"zookeeper\";\n\n    public ConfigCenterEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) {\n        super(applicationModel, typeWrapper);\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        ConfigCenterMetricsCollector collector;\n        if (!beanFactory.isDestroyed()) {\n            collector = beanFactory.getBean(ConfigCenterMetricsCollector.class);\n            super.setAvailable(collector != null && collector.isCollectEnabled());\n        }\n    }\n\n    public static ConfigCenterEvent toChangeEvent(\n            ApplicationModel applicationModel,\n            String key,\n            String group,\n            String protocol,\n            String changeType,\n            int count) {\n        ConfigCenterEvent configCenterEvent = new ConfigCenterEvent(\n                applicationModel, new TypeWrapper(MetricsLevel.CONFIG, CONFIGCENTER_METRIC_TOTAL));\n        configCenterEvent.putAttachment(ATTACHMENT_KEY_CONFIG_FILE, key);\n        configCenterEvent.putAttachment(ATTACHMENT_KEY_CONFIG_GROUP, group);\n        configCenterEvent.putAttachment(ATTACHMENT_KEY_CONFIG_PROTOCOL, protocol);\n        configCenterEvent.putAttachment(ATTACHMENT_KEY_CHANGE_TYPE, changeType);\n        configCenterEvent.putAttachment(ATTACHMENT_KEY_SIZE, count);\n        return configCenterEvent;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-config-center/src/main/java/org/apache/dubbo/metrics/config/event/ConfigCenterSubDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.config.event;\n\nimport org.apache.dubbo.metrics.config.collector.ConfigCenterMetricsCollector;\nimport org.apache.dubbo.metrics.event.MetricsEvent;\nimport org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SIZE;\nimport static org.apache.dubbo.metrics.config.ConfigCenterMetricsConstants.ATTACHMENT_KEY_CHANGE_TYPE;\nimport static org.apache.dubbo.metrics.config.ConfigCenterMetricsConstants.ATTACHMENT_KEY_CONFIG_FILE;\nimport static org.apache.dubbo.metrics.config.ConfigCenterMetricsConstants.ATTACHMENT_KEY_CONFIG_GROUP;\nimport static org.apache.dubbo.metrics.config.ConfigCenterMetricsConstants.ATTACHMENT_KEY_CONFIG_PROTOCOL;\n\npublic final class ConfigCenterSubDispatcher extends SimpleMetricsEventMulticaster {\n\n    public ConfigCenterSubDispatcher(ConfigCenterMetricsCollector collector) {\n\n        super.addListener(new AbstractMetricsKeyListener(MetricsKey.CONFIGCENTER_METRIC_TOTAL) {\n            @Override\n            public boolean isSupport(MetricsEvent event) {\n                return event instanceof ConfigCenterEvent;\n            }\n\n            @Override\n            public void onEvent(TimeCounterEvent event) {\n                collector.increase(\n                        event.getAttachmentValue(ATTACHMENT_KEY_CONFIG_FILE),\n                        event.getAttachmentValue(ATTACHMENT_KEY_CONFIG_GROUP),\n                        event.getAttachmentValue(ATTACHMENT_KEY_CONFIG_PROTOCOL),\n                        event.getAttachmentValue(ATTACHMENT_KEY_CHANGE_TYPE),\n                        event.getAttachmentValue(ATTACHMENT_KEY_SIZE));\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-config-center/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector",
    "content": "config-collector=org.apache.dubbo.metrics.config.collector.ConfigCenterMetricsCollector\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-config-center/src/test/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollectorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metrics.config.collector.ConfigCenterMetricsCollector;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE;\n\nclass ConfigCenterMetricsCollectorTest {\n\n    private FrameworkModel frameworkModel;\n    private ApplicationModel applicationModel;\n\n    @BeforeEach\n    public void setup() {\n        frameworkModel = FrameworkModel.defaultModel();\n        applicationModel = frameworkModel.newApplication();\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n\n        applicationModel.getApplicationConfigManager().setApplication(config);\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    @Test\n    void increase4Initialized() {\n        ConfigCenterMetricsCollector collector = new ConfigCenterMetricsCollector(applicationModel);\n        collector.setCollectEnabled(true);\n        String applicationName = applicationModel.getApplicationName();\n        collector.increase(\"key\", \"group\", \"nacos\", ConfigChangeType.ADDED.name(), 1);\n        collector.increase(\"key\", \"group\", \"nacos\", ConfigChangeType.ADDED.name(), 1);\n\n        List<MetricSample> samples = collector.collect();\n        for (MetricSample sample : samples) {\n            Assertions.assertTrue(sample instanceof GaugeMetricSample);\n            GaugeMetricSample<Long> gaugeSample = (GaugeMetricSample) sample;\n            Map<String, String> tags = gaugeSample.getTags();\n\n            Assertions.assertEquals(gaugeSample.applyAsLong(), 2);\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationName);\n        }\n    }\n\n    @Test\n    void increaseUpdated() {\n        ConfigCenterMetricsCollector collector = new ConfigCenterMetricsCollector(applicationModel);\n        collector.setCollectEnabled(true);\n        String applicationName = applicationModel.getApplicationName();\n\n        ConfigChangedEvent event = new ConfigChangedEvent(\"key\", \"group\", null, ConfigChangeType.ADDED);\n\n        collector.increase(\n                event.getKey(), event.getGroup(), \"apollo\", ConfigChangeType.ADDED.name(), SELF_INCREMENT_SIZE);\n\n        collector.increase(\n                event.getKey(), event.getGroup(), \"apollo\", ConfigChangeType.ADDED.name(), SELF_INCREMENT_SIZE);\n\n        List<MetricSample> samples = collector.collect();\n        for (MetricSample sample : samples) {\n            Assertions.assertTrue(sample instanceof GaugeMetricSample);\n            GaugeMetricSample<Long> gaugeSample = (GaugeMetricSample) sample;\n            Map<String, String> tags = gaugeSample.getTags();\n\n            Assertions.assertEquals(gaugeSample.applyAsLong(), 2);\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationName);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-config-center/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metrics</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-metrics-default</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The metrics module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-native</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DefaultConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_CODEC_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_LIMIT;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_NETWORK_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_PROCESSING;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SUCCEED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_TIMEOUT;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_TOTAL_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUEST_BUSINESS_FAILED;\n\npublic interface DefaultConstants {\n\n    String METRIC_FILTER_EVENT = \"metric_filter_event\";\n\n    String METRIC_THROWABLE = \"metric_filter_throwable\";\n\n    List<MetricsKeyWrapper> METHOD_LEVEL_KEYS = Arrays.asList(\n            new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),\n            // METRIC_REQUESTS_PROCESSING use GAUGE\n            new MetricsKeyWrapper(\n                            METRIC_REQUESTS_PROCESSING,\n                            MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD))\n                    .setSampleType(MetricSample.Type.GAUGE),\n            new MetricsKeyWrapper(\n                            METRIC_REQUESTS_PROCESSING,\n                            MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD))\n                    .setSampleType(MetricSample.Type.GAUGE),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_SUCCEED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_SUCCEED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUEST_BUSINESS_FAILED,\n                    MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUEST_BUSINESS_FAILED,\n                    MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_TIMEOUT, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_TIMEOUT, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_LIMIT, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_LIMIT, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_FAILED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_TOTAL_FAILED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_TOTAL_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_NETWORK_FAILED,\n                    MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_NETWORK_FAILED,\n                    MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED,\n                    MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED,\n                    MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_CODEC_FAILED, MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD)),\n            new MetricsKeyWrapper(\n                    METRIC_REQUESTS_CODEC_FAILED, MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD)));\n\n    List<MetricsKey> INIT_AGG_METHOD_KEYS = Arrays.asList(\n            MetricsKey.METRIC_REQUESTS_TOTAL_AGG,\n            MetricsKey.METRIC_REQUESTS_SUCCEED_AGG,\n            MetricsKey.METRIC_REQUESTS_FAILED_AGG,\n            MetricsKey.METRIC_REQUEST_BUSINESS_FAILED_AGG,\n            MetricsKey.METRIC_REQUESTS_TIMEOUT_AGG,\n            MetricsKey.METRIC_REQUESTS_LIMIT_AGG,\n            MetricsKey.METRIC_REQUESTS_TOTAL_FAILED_AGG,\n            MetricsKey.METRIC_REQUESTS_NETWORK_FAILED_AGG,\n            MetricsKey.METRIC_REQUESTS_CODEC_FAILED_AGG,\n            MetricsKey.METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG);\n\n    List<MetricsKey> INIT_DEFAULT_METHOD_KEYS = Arrays.asList(\n            MetricsKey.METRIC_REQUESTS,\n            MetricsKey.METRIC_REQUESTS_PROCESSING,\n            MetricsKey.METRIC_REQUESTS_FAILED_AGG,\n            MetricsKey.METRIC_REQUESTS_SUCCEED,\n            MetricsKey.METRIC_REQUESTS_TOTAL_FAILED,\n            MetricsKey.METRIC_REQUEST_BUSINESS_FAILED);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsGlobalRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics;\n\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Optional;\n\nimport io.micrometer.core.instrument.Metrics;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\n\n/**\n * Get the micrometer meter registry, can choose spring, micrometer, dubbo\n */\npublic class MetricsGlobalRegistry {\n\n    private static CompositeMeterRegistry compositeRegistry = new CompositeMeterRegistry();\n\n    /**\n     * Use CompositeMeterRegistry according to the following priority\n     * 1. If useGlobalRegistry is configured, use the micrometer global CompositeMeterRegistry\n     * 2. If there is a spring actuator, use spring's CompositeMeterRegistry\n     * 3. Dubbo's own CompositeMeterRegistry is used by default\n     */\n    public static CompositeMeterRegistry getCompositeRegistry(ApplicationModel applicationModel) {\n        Optional<MetricsConfig> configOptional =\n                applicationModel.getApplicationConfigManager().getMetrics();\n        if (configOptional.isPresent()\n                && configOptional.get().getUseGlobalRegistry() != null\n                && configOptional.get().getUseGlobalRegistry()) {\n            return Metrics.globalRegistry;\n        } else {\n            return compositeRegistry;\n        }\n    }\n\n    public static CompositeMeterRegistry getCompositeRegistry() {\n        return getCompositeRegistry(ApplicationModel.defaultModel());\n    }\n\n    public static void setCompositeRegistry(CompositeMeterRegistry compositeRegistry) {\n        MetricsGlobalRegistry.compositeRegistry = compositeRegistry;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\npublic class MetricsScopeModelInitializer implements ScopeModelInitializer {\n\n    @Override\n    public void initializeApplicationModel(ApplicationModel applicationModel) {\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        beanFactory.registerBean(MetricsDispatcher.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/aot/DefaultMetricsReflectionTypeDescriberRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.aot;\n\nimport org.apache.dubbo.aot.api.MemberCategory;\nimport org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;\nimport org.apache.dubbo.aot.api.TypeDescriber;\nimport org.apache.dubbo.metrics.collector.HistogramMetricsCollector;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class DefaultMetricsReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {\n\n    @Override\n    public List<TypeDescriber> getTypeDescribers() {\n        List<TypeDescriber> typeDescribers = new ArrayList<>();\n        typeDescribers.add(buildTypeDescriberWithDeclaredConstructors(HistogramMetricsCollector.class));\n        return typeDescribers;\n    }\n\n    private TypeDescriber buildTypeDescriberWithDeclaredConstructors(Class<?> cl) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n        return new TypeDescriber(\n                cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.nested.AggregationConfig;\nimport org.apache.dubbo.metrics.MetricsConstants;\nimport org.apache.dubbo.metrics.aggregate.TimeWindowAggregator;\nimport org.apache.dubbo.metrics.aggregate.TimeWindowCounter;\nimport org.apache.dubbo.metrics.aggregate.TimeWindowQuantile;\nimport org.apache.dubbo.metrics.event.MetricsEvent;\nimport org.apache.dubbo.metrics.event.RequestEvent;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;\nimport static org.apache.dubbo.metrics.DefaultConstants.INIT_AGG_METHOD_KEYS;\nimport static org.apache.dubbo.metrics.DefaultConstants.METRIC_THROWABLE;\nimport static org.apache.dubbo.metrics.model.MetricsCategory.QPS;\nimport static org.apache.dubbo.metrics.model.MetricsCategory.REQUESTS;\nimport static org.apache.dubbo.metrics.model.MetricsCategory.RT;\n\n/**\n * Aggregation metrics collector implementation of {@link MetricsCollector}.\n * This collector only enabled when metrics aggregation config is enabled.\n */\npublic class AggregateMetricsCollector implements MetricsCollector<RequestEvent> {\n    private int bucketNum = DEFAULT_BUCKET_NUM;\n    private int timeWindowSeconds = DEFAULT_TIME_WINDOW_SECONDS;\n    private int qpsTimeWindowMillSeconds = DEFAULT_QPS_TIME_WINDOW_MILL_SECONDS;\n    private final ConcurrentHashMap<MetricsKeyWrapper, ConcurrentHashMap<MethodMetric, TimeWindowCounter>>\n            methodTypeCounter = new ConcurrentHashMap<>();\n    private final ConcurrentMap<MethodMetric, TimeWindowQuantile> rt = new ConcurrentHashMap<>();\n    private final ConcurrentHashMap<MethodMetric, TimeWindowCounter> qps = new ConcurrentHashMap<>();\n    private final ApplicationModel applicationModel;\n    private static final Integer DEFAULT_COMPRESSION = 100;\n    private static final Integer DEFAULT_BUCKET_NUM = 10;\n    private static final Integer DEFAULT_TIME_WINDOW_SECONDS = 120;\n    private static final Integer DEFAULT_QPS_TIME_WINDOW_MILL_SECONDS = 3000;\n    private Boolean collectEnabled = null;\n    private boolean enableQps;\n    private boolean enableRtPxx;\n    private boolean enableRt;\n    private boolean enableRequest;\n    private final AtomicBoolean samplesChanged = new AtomicBoolean(true);\n\n    private final ConcurrentMap<MethodMetric, TimeWindowAggregator> rtAgr = new ConcurrentHashMap<>();\n\n    private boolean serviceLevel;\n\n    public AggregateMetricsCollector(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        ConfigManager configManager = applicationModel.getApplicationConfigManager();\n        if (isCollectEnabled()) {\n            // only registered when aggregation is enabled.\n            Optional<MetricsConfig> optional = configManager.getMetrics();\n            if (optional.isPresent()) {\n                registerListener();\n                AggregationConfig aggregation = optional.get().getAggregation();\n                this.bucketNum = Optional.ofNullable(aggregation.getBucketNum()).orElse(DEFAULT_BUCKET_NUM);\n                this.timeWindowSeconds =\n                        Optional.ofNullable(aggregation.getTimeWindowSeconds()).orElse(DEFAULT_TIME_WINDOW_SECONDS);\n                this.qpsTimeWindowMillSeconds = Optional.ofNullable(aggregation.getQpsTimeWindowMillSeconds())\n                        .orElse(DEFAULT_QPS_TIME_WINDOW_MILL_SECONDS);\n                this.enableQps = Optional.ofNullable(aggregation.getEnableQps()).orElse(true);\n                this.enableRtPxx =\n                        Optional.ofNullable(aggregation.getEnableRtPxx()).orElse(true);\n                this.enableRt = Optional.ofNullable(aggregation.getEnableRt()).orElse(true);\n                this.enableRequest =\n                        Optional.ofNullable(aggregation.getEnableRequest()).orElse(true);\n            }\n            this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);\n        }\n    }\n\n    public void setCollectEnabled(Boolean collectEnabled) {\n        if (collectEnabled != null) {\n            this.collectEnabled = collectEnabled;\n        }\n    }\n\n    @Override\n    public boolean isCollectEnabled() {\n        if (collectEnabled == null) {\n            ConfigManager configManager = applicationModel.getApplicationConfigManager();\n            configManager\n                    .getMetrics()\n                    .ifPresent(metricsConfig ->\n                            setCollectEnabled(metricsConfig.getAggregation().getEnabled()));\n        }\n        return Optional.ofNullable(collectEnabled).orElse(false);\n    }\n\n    @Override\n    public boolean isSupport(MetricsEvent event) {\n        return event instanceof RequestEvent;\n    }\n\n    @Override\n    public void onEvent(RequestEvent event) {\n        if (enableQps) {\n            MethodMetric metric = calcWindowCounter(event, MetricsKey.METRIC_REQUESTS);\n            TimeWindowCounter qpsCounter = qps.get(metric);\n            if (qpsCounter == null) {\n                qpsCounter = ConcurrentHashMapUtils.computeIfAbsent(\n                        qps,\n                        metric,\n                        methodMetric -> new TimeWindowCounter(\n                                bucketNum, TimeUnit.MILLISECONDS.toSeconds(qpsTimeWindowMillSeconds)));\n                samplesChanged.set(true);\n            }\n            qpsCounter.increment();\n        }\n    }\n\n    @Override\n    public void onEventFinish(RequestEvent event) {\n        MetricsKey targetKey = MetricsKey.METRIC_REQUESTS_SUCCEED;\n        Object throwableObj = event.getAttachmentValue(METRIC_THROWABLE);\n        if (throwableObj != null) {\n            targetKey = MetricsSupport.getAggMetricsKey((Throwable) throwableObj);\n        }\n        calcWindowCounter(event, targetKey);\n        onRTEvent(event);\n    }\n\n    @Override\n    public void onEventError(RequestEvent event) {\n        if (enableRequest) {\n            MetricsKey targetKey = MetricsKey.METRIC_REQUESTS_FAILED;\n            Object throwableObj = event.getAttachmentValue(METRIC_THROWABLE);\n            if (throwableObj != null) {\n                targetKey = MetricsSupport.getAggMetricsKey((Throwable) throwableObj);\n            }\n            calcWindowCounter(event, targetKey);\n        }\n        if (enableRt || enableRtPxx) {\n            onRTEvent(event);\n        }\n    }\n\n    private void onRTEvent(RequestEvent event) {\n        MethodMetric metric =\n                new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);\n        long responseTime = event.getTimePair().calc();\n        if (enableRt) {\n            TimeWindowQuantile quantile = rt.get(metric);\n            if (quantile == null) {\n                quantile = ConcurrentHashMapUtils.computeIfAbsent(\n                        rt, metric, k -> new TimeWindowQuantile(DEFAULT_COMPRESSION, bucketNum, timeWindowSeconds));\n                samplesChanged.set(true);\n            }\n            quantile.add(responseTime);\n        }\n\n        if (enableRtPxx) {\n            TimeWindowAggregator timeWindowAggregator = rtAgr.get(metric);\n            if (timeWindowAggregator == null) {\n                timeWindowAggregator = ConcurrentHashMapUtils.computeIfAbsent(\n                        rtAgr, metric, methodMetric -> new TimeWindowAggregator(bucketNum, timeWindowSeconds));\n                samplesChanged.set(true);\n            }\n            timeWindowAggregator.add(responseTime);\n        }\n    }\n\n    private MethodMetric calcWindowCounter(RequestEvent event, MetricsKey targetKey) {\n        MetricsPlaceValue placeType =\n                MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.SERVICE);\n        MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(targetKey, placeType);\n        MethodMetric metric =\n                new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);\n\n        ConcurrentMap<MethodMetric, TimeWindowCounter> counter = ConcurrentHashMapUtils.computeIfAbsent(\n                methodTypeCounter, metricsKeyWrapper, k -> new ConcurrentHashMap<>());\n\n        TimeWindowCounter windowCounter = counter.get(metric);\n        if (windowCounter == null) {\n            windowCounter = ConcurrentHashMapUtils.computeIfAbsent(\n                    counter, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds));\n            samplesChanged.set(true);\n        }\n        windowCounter.increment();\n        return metric;\n    }\n\n    @Override\n    public List<MetricSample> collect() {\n        List<MetricSample> list = new ArrayList<>();\n        if (!isCollectEnabled()) {\n            return list;\n        }\n        collectRequests(list);\n        collectQPS(list);\n        collectRT(list);\n\n        return list;\n    }\n\n    private void collectRequests(List<MetricSample> list) {\n        collectBySide(list, PROVIDER_SIDE);\n        collectBySide(list, CONSUMER_SIDE);\n    }\n\n    private void collectBySide(List<MetricSample> list, String side) {\n        collectMethod(list, side, MetricsKey.METRIC_REQUESTS_TOTAL_AGG);\n        collectMethod(list, side, MetricsKey.METRIC_REQUESTS_SUCCEED_AGG);\n        collectMethod(list, side, MetricsKey.METRIC_REQUESTS_FAILED_AGG);\n        collectMethod(list, side, MetricsKey.METRIC_REQUEST_BUSINESS_FAILED_AGG);\n        collectMethod(list, side, MetricsKey.METRIC_REQUESTS_TIMEOUT_AGG);\n        collectMethod(list, side, MetricsKey.METRIC_REQUESTS_LIMIT_AGG);\n        collectMethod(list, side, MetricsKey.METRIC_REQUESTS_TOTAL_FAILED_AGG);\n        collectMethod(list, side, MetricsKey.METRIC_REQUESTS_NETWORK_FAILED_AGG);\n        collectMethod(list, side, MetricsKey.METRIC_REQUESTS_CODEC_FAILED_AGG);\n        collectMethod(list, side, MetricsKey.METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG);\n    }\n\n    private void collectMethod(List<MetricSample> list, String side, MetricsKey metricsKey) {\n        MetricsKeyWrapper metricsKeyWrapper =\n                new MetricsKeyWrapper(metricsKey, MetricsPlaceValue.of(side, MetricsLevel.SERVICE));\n        ConcurrentHashMap<MethodMetric, TimeWindowCounter> windowCounter = methodTypeCounter.get(metricsKeyWrapper);\n        if (windowCounter != null) {\n            windowCounter.forEach((k, v) -> list.add(new GaugeMetricSample<>(\n                    metricsKey.getNameByType(k.getSide()),\n                    metricsKey.getDescription(),\n                    k.getTags(),\n                    REQUESTS,\n                    v,\n                    TimeWindowCounter::get)));\n        }\n    }\n\n    private void collectQPS(List<MetricSample> list) {\n        qps.forEach((k, v) -> list.add(new GaugeMetricSample<>(\n                MetricsKey.METRIC_QPS.getNameByType(k.getSide()),\n                MetricsKey.METRIC_QPS.getDescription(),\n                k.getTags(),\n                QPS,\n                v,\n                value -> {\n                    double total = value.get();\n                    long millSeconds = value.bucketLivedMillSeconds();\n                    return total / millSeconds * 1000;\n                })));\n    }\n\n    private void collectRT(List<MetricSample> list) {\n        rt.forEach((k, v) -> {\n            list.add(new GaugeMetricSample<>(\n                    MetricsKey.METRIC_RT_P99.getNameByType(k.getSide()),\n                    MetricsKey.METRIC_RT_P99.getDescription(),\n                    k.getTags(),\n                    RT,\n                    v,\n                    value -> value.quantile(0.99)));\n            list.add(new GaugeMetricSample<>(\n                    MetricsKey.METRIC_RT_P95.getNameByType(k.getSide()),\n                    MetricsKey.METRIC_RT_P95.getDescription(),\n                    k.getTags(),\n                    RT,\n                    v,\n                    value -> value.quantile(0.95)));\n            list.add(new GaugeMetricSample<>(\n                    MetricsKey.METRIC_RT_P90.getNameByType(k.getSide()),\n                    MetricsKey.METRIC_RT_P90.getDescription(),\n                    k.getTags(),\n                    RT,\n                    v,\n                    value -> value.quantile(0.90)));\n            list.add(new GaugeMetricSample<>(\n                    MetricsKey.METRIC_RT_P50.getNameByType(k.getSide()),\n                    MetricsKey.METRIC_RT_P50.getDescription(),\n                    k.getTags(),\n                    RT,\n                    v,\n                    value -> value.quantile(0.50)));\n        });\n\n        rtAgr.forEach((k, v) -> {\n            list.add(new GaugeMetricSample<>(\n                    MetricsKey.METRIC_RT_MIN_AGG.getNameByType(k.getSide()),\n                    MetricsKey.METRIC_RT_MIN_AGG.getDescription(),\n                    k.getTags(),\n                    RT,\n                    v,\n                    value -> v.get().getMin()));\n\n            list.add(new GaugeMetricSample<>(\n                    MetricsKey.METRIC_RT_MAX_AGG.getNameByType(k.getSide()),\n                    MetricsKey.METRIC_RT_MAX_AGG.getDescription(),\n                    k.getTags(),\n                    RT,\n                    v,\n                    value -> v.get().getMax()));\n\n            list.add(new GaugeMetricSample<>(\n                    MetricsKey.METRIC_RT_AVG_AGG.getNameByType(k.getSide()),\n                    MetricsKey.METRIC_RT_AVG_AGG.getDescription(),\n                    k.getTags(),\n                    RT,\n                    v,\n                    value -> v.get().getAvg()));\n        });\n    }\n\n    private void registerListener() {\n        applicationModel\n                .getBeanFactory()\n                .getBean(DefaultMetricsCollector.class)\n                .getEventMulticaster()\n                .addListener(this);\n    }\n\n    @Override\n    public void initMetrics(MetricsEvent event) {\n        MethodMetric metric =\n                new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);\n        if (enableQps) {\n            initMethodMetric(event);\n            initQpsMetric(metric);\n        }\n        if (enableRt) {\n            initRtMetric(metric);\n        }\n        if (enableRtPxx) {\n            initRtAgrMetric(metric);\n        }\n    }\n\n    public void initMethodMetric(MetricsEvent event) {\n        INIT_AGG_METHOD_KEYS.stream().forEach(key -> initWindowCounter(event, key));\n    }\n\n    public void initQpsMetric(MethodMetric metric) {\n        ConcurrentHashMapUtils.computeIfAbsent(\n                qps, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds));\n        samplesChanged.set(true);\n    }\n\n    public void initRtMetric(MethodMetric metric) {\n        ConcurrentHashMapUtils.computeIfAbsent(\n                rt, metric, k -> new TimeWindowQuantile(DEFAULT_COMPRESSION, bucketNum, timeWindowSeconds));\n        samplesChanged.set(true);\n    }\n\n    public void initRtAgrMetric(MethodMetric metric) {\n        ConcurrentHashMapUtils.computeIfAbsent(\n                rtAgr, metric, k -> new TimeWindowAggregator(bucketNum, timeWindowSeconds));\n        samplesChanged.set(true);\n    }\n\n    public void initWindowCounter(MetricsEvent event, MetricsKey targetKey) {\n\n        MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(\n                targetKey,\n                MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.SERVICE));\n\n        MethodMetric metric =\n                new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);\n\n        ConcurrentMap<MethodMetric, TimeWindowCounter> counter = ConcurrentHashMapUtils.computeIfAbsent(\n                methodTypeCounter, metricsKeyWrapper, k -> new ConcurrentHashMap<>());\n\n        ConcurrentHashMapUtils.computeIfAbsent(\n                counter, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds));\n        samplesChanged.set(true);\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // CAS to get and reset the flag in an atomic operation\n        return samplesChanged.compareAndSet(true, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/DefaultMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.metrics.DefaultConstants;\nimport org.apache.dubbo.metrics.MetricsConstants;\nimport org.apache.dubbo.metrics.collector.sample.ErrorCodeSampler;\nimport org.apache.dubbo.metrics.collector.sample.MetricsCountSampleConfigurer;\nimport org.apache.dubbo.metrics.collector.sample.MetricsSampler;\nimport org.apache.dubbo.metrics.collector.sample.SimpleMetricsCountSampler;\nimport org.apache.dubbo.metrics.collector.sample.ThreadPoolMetricsSampler;\nimport org.apache.dubbo.metrics.data.BaseStatComposite;\nimport org.apache.dubbo.metrics.data.MethodStatComposite;\nimport org.apache.dubbo.metrics.data.RtStatComposite;\nimport org.apache.dubbo.metrics.event.DefaultSubDispatcher;\nimport org.apache.dubbo.metrics.event.MetricsEvent;\nimport org.apache.dubbo.metrics.event.MetricsInitEvent;\nimport org.apache.dubbo.metrics.event.RequestEvent;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.model.ApplicationMetric;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\nimport org.apache.dubbo.metrics.model.sample.CounterMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.metrics.DefaultConstants.INIT_DEFAULT_METHOD_KEYS;\nimport static org.apache.dubbo.metrics.model.MetricsCategory.APPLICATION;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.APPLICATION_METRIC_INFO;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED;\n\n/**\n * Default implementation of {@link MetricsCollector}\n */\n@Activate\npublic class DefaultMetricsCollector extends CombMetricsCollector<RequestEvent> {\n\n    private boolean collectEnabled = false;\n\n    private volatile boolean threadpoolCollectEnabled = false;\n\n    private volatile boolean metricsInitEnabled = true;\n\n    private final ThreadPoolMetricsSampler threadPoolSampler = new ThreadPoolMetricsSampler(this);\n\n    private final ErrorCodeSampler errorCodeSampler;\n\n    private String applicationName;\n\n    private final ApplicationModel applicationModel;\n\n    private final List<MetricsSampler> samplers = new ArrayList<>();\n\n    private final List<MetricsCollector> collectors = new ArrayList<>();\n\n    private final AtomicBoolean initialized = new AtomicBoolean();\n\n    private final AtomicBoolean samplesChanged = new AtomicBoolean();\n\n    public DefaultMetricsCollector(ApplicationModel applicationModel) {\n        super(new BaseStatComposite(applicationModel) {\n            @Override\n            protected void init(MethodStatComposite methodStatComposite) {\n                super.init(methodStatComposite);\n                methodStatComposite.initWrapper(DefaultConstants.METHOD_LEVEL_KEYS);\n            }\n\n            @Override\n            protected void init(RtStatComposite rtStatComposite) {\n                super.init(rtStatComposite);\n                rtStatComposite.init(\n                        MetricsPlaceValue.of(CommonConstants.PROVIDER, MetricsLevel.METHOD),\n                        MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD));\n            }\n        });\n        super.setEventMulticaster(new DefaultSubDispatcher(this));\n        this.samplers.add(applicationSampler);\n        this.samplers.add(threadPoolSampler);\n        this.samplesChanged.set(true);\n        this.errorCodeSampler = new ErrorCodeSampler(this);\n        this.applicationModel = applicationModel;\n    }\n\n    public void addSampler(MetricsSampler sampler) {\n        samplers.add(sampler);\n        samplesChanged.set(true);\n    }\n\n    public void setApplicationName(String applicationName) {\n        this.applicationName = applicationName;\n    }\n\n    public String getApplicationName() {\n        return this.applicationName;\n    }\n\n    public ApplicationModel getApplicationModel() {\n        return this.applicationModel;\n    }\n\n    public void setCollectEnabled(Boolean collectEnabled) {\n        this.collectEnabled = collectEnabled;\n    }\n\n    @Override\n    public boolean isCollectEnabled() {\n        return collectEnabled;\n    }\n\n    public boolean isThreadpoolCollectEnabled() {\n        return threadpoolCollectEnabled;\n    }\n\n    public void setThreadpoolCollectEnabled(boolean threadpoolCollectEnabled) {\n        this.threadpoolCollectEnabled = threadpoolCollectEnabled;\n    }\n\n    public boolean isMetricsInitEnabled() {\n        return metricsInitEnabled;\n    }\n\n    public void setMetricsInitEnabled(boolean metricsInitEnabled) {\n        this.metricsInitEnabled = metricsInitEnabled;\n    }\n\n    public void collectApplication() {\n        this.setApplicationName(applicationModel.getApplicationName());\n        applicationSampler.inc(applicationName, MetricsEvent.Type.APPLICATION_INFO);\n    }\n\n    public void registryDefaultSample() {\n        this.threadPoolSampler.registryDefaultSampleThreadPoolExecutor();\n    }\n\n    @Override\n    public List<MetricSample> collect() {\n        List<MetricSample> list = new ArrayList<>();\n        if (!isCollectEnabled()) {\n            return list;\n        }\n\n        for (MetricsSampler sampler : samplers) {\n            List<MetricSample> sample = sampler.sample();\n            list.addAll(sample);\n        }\n        list.addAll(super.export(MetricsCategory.REQUESTS));\n        return list;\n    }\n\n    @Override\n    public boolean isSupport(MetricsEvent event) {\n        return event instanceof RequestEvent || event instanceof MetricsInitEvent;\n    }\n\n    @Override\n    public void onEvent(TimeCounterEvent event) {\n        if (event instanceof MetricsInitEvent) {\n            if (!metricsInitEnabled) {\n                return;\n            }\n            if (initialized.compareAndSet(false, true)) {\n                collectors.addAll(applicationModel.getBeanFactory().getBeansOfType(MetricsCollector.class));\n            }\n            collectors.stream().forEach(collector -> collector.initMetrics(event));\n            return;\n        }\n        super.onEvent(event);\n    }\n\n    @Override\n    public void initMetrics(MetricsEvent event) {\n        MetricsPlaceValue dynamicPlaceType =\n                MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.METHOD);\n        INIT_DEFAULT_METHOD_KEYS.stream()\n                .forEach(key -> MetricsSupport.init(key, dynamicPlaceType, (MethodMetricsCollector) this, event));\n        MetricsSupport.init(\n                METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED,\n                MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD),\n                (MethodMetricsCollector) this,\n                event);\n    }\n\n    public SimpleMetricsCountSampler<String, MetricsEvent.Type, ApplicationMetric> applicationSampler =\n            new SimpleMetricsCountSampler<String, MetricsEvent.Type, ApplicationMetric>() {\n                @Override\n                public List<MetricSample> sample() {\n                    List<MetricSample> samples = new ArrayList<>();\n                    this.getCount(MetricsEvent.Type.APPLICATION_INFO)\n                            .filter(e -> !e.isEmpty())\n                            .ifPresent(map -> map.forEach((k, v) -> samples.add(new CounterMetricSample<>(\n                                    APPLICATION_METRIC_INFO.getName(),\n                                    APPLICATION_METRIC_INFO.getDescription(),\n                                    k.getTags(),\n                                    APPLICATION,\n                                    v))));\n                    return samples;\n                }\n\n                @Override\n                protected void countConfigure(\n                        MetricsCountSampleConfigurer<String, MetricsEvent.Type, ApplicationMetric> sampleConfigure) {\n                    sampleConfigure.configureMetrics(configure -> new ApplicationMetric(applicationModel));\n                }\n\n                @Override\n                public boolean calSamplesChanged() {\n                    return false;\n                }\n            };\n\n    @Override\n    public boolean calSamplesChanged() {\n        // CAS to get and reset the flag in an atomic operation\n        boolean changed = samplesChanged.compareAndSet(true, false);\n        // Should ensure that all the sampler's samplesChanged have been compareAndSet, and cannot flip the `or` logic\n        changed = stats.calSamplesChanged() || changed;\n        for (MetricsSampler sampler : samplers) {\n            changed = sampler.calSamplesChanged() || changed;\n        }\n        return changed;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/HistogramMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.nested.HistogramConfig;\nimport org.apache.dubbo.metrics.MetricsConstants;\nimport org.apache.dubbo.metrics.MetricsGlobalRegistry;\nimport org.apache.dubbo.metrics.event.RequestEvent;\nimport org.apache.dubbo.metrics.listener.AbstractMetricsListener;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.register.HistogramMetricRegister;\nimport org.apache.dubbo.metrics.sample.HistogramMetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.core.instrument.Timer;\n\nimport static org.apache.dubbo.metrics.model.MetricsCategory.RT;\n\npublic class HistogramMetricsCollector extends AbstractMetricsListener<RequestEvent>\n        implements MetricsCollector<RequestEvent> {\n\n    private final ConcurrentHashMap<MethodMetric, Timer> rt = new ConcurrentHashMap<>();\n    private HistogramMetricRegister metricRegister;\n    private final ApplicationModel applicationModel;\n\n    private static final Integer[] DEFAULT_BUCKETS_MS = new Integer[] {100, 300, 500, 1000, 3000, 5000, 10000};\n\n    private boolean serviceLevel;\n\n    public HistogramMetricsCollector(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n\n        ConfigManager configManager = applicationModel.getApplicationConfigManager();\n        MetricsConfig config = configManager.getMetrics().orElse(null);\n        if (config == null\n                || config.getHistogram() == null\n                || config.getHistogram().getEnabled() == null\n                || Boolean.TRUE.equals(config.getHistogram().getEnabled())) {\n            registerListener();\n\n            HistogramConfig histogram;\n            if (config == null || config.getHistogram() == null) {\n                histogram = new HistogramConfig();\n            } else {\n                histogram = config.getHistogram();\n            }\n\n            if (!Boolean.TRUE.equals(histogram.getEnabledPercentiles()) && histogram.getBucketsMs() == null) {\n                histogram.setBucketsMs(DEFAULT_BUCKETS_MS);\n            }\n\n            metricRegister = new HistogramMetricRegister(\n                    MetricsGlobalRegistry.getCompositeRegistry(applicationModel), histogram);\n            this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);\n        }\n    }\n\n    private void registerListener() {\n        applicationModel\n                .getBeanFactory()\n                .getBean(DefaultMetricsCollector.class)\n                .getEventMulticaster()\n                .addListener(this);\n    }\n\n    @Override\n    public void onEvent(RequestEvent event) {}\n\n    @Override\n    public void onEventFinish(RequestEvent event) {\n        onRTEvent(event);\n    }\n\n    @Override\n    public void onEventError(RequestEvent event) {\n        onRTEvent(event);\n    }\n\n    private void onRTEvent(RequestEvent event) {\n        if (metricRegister != null) {\n            MethodMetric metric = new MethodMetric(\n                    applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);\n            long responseTime = event.getTimePair().calc();\n\n            HistogramMetricSample sample = new HistogramMetricSample(\n                    MetricsKey.METRIC_RT_HISTOGRAM.getNameByType(metric.getSide()),\n                    MetricsKey.METRIC_RT_HISTOGRAM.getDescription(),\n                    metric.getTags(),\n                    RT);\n\n            Timer timer = ConcurrentHashMapUtils.computeIfAbsent(rt, metric, k -> metricRegister.register(sample));\n            timer.record(responseTime, TimeUnit.MILLISECONDS);\n        }\n    }\n\n    @Override\n    public List<MetricSample> collect() {\n        return new ArrayList<>();\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // Histogram is directly register micrometer\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeMetricsListenRegister.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.common.logger.LogListener;\nimport org.apache.dubbo.common.logger.support.FailsafeErrorTypeAwareLogger;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\n\n/**\n * Listen the log of all {@link FailsafeErrorTypeAwareLogger} instances, and add error code count to {@link ErrorCodeSampler}.\n */\npublic class ErrorCodeMetricsListenRegister implements LogListener {\n\n    private final ErrorCodeSampler errorCodeSampler;\n\n    public ErrorCodeMetricsListenRegister(ErrorCodeSampler errorCodeSampler) {\n        FailsafeErrorTypeAwareLogger.registerGlobalListen(this);\n        this.errorCodeSampler = errorCodeSampler;\n        this.errorCodeSampler.addMetricName(MetricsKey.ERROR_CODE_COUNT.getName());\n    }\n\n    @Override\n    public void onMessage(String code, String msg) {\n        errorCodeSampler.inc(code, MetricsKey.ERROR_CODE_COUNT.getName());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeSampler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.model.ErrorCodeMetric;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.sample.CounterMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * This sampler is used to count the number of occurrences of each error code.\n */\npublic class ErrorCodeSampler extends MetricsNameCountSampler<String, String, ErrorCodeMetric> {\n\n    private final ErrorCodeMetricsListenRegister register;\n\n    /**\n     * Map<ErrorCode,Metric>\n     */\n    private final Map<String, ErrorCodeMetric> errorCodeMetrics;\n\n    public ErrorCodeSampler(DefaultMetricsCollector collector) {\n        super(collector, MetricsCategory.ERROR_CODE, MetricsKey.ERROR_CODE_COUNT);\n        this.register = new ErrorCodeMetricsListenRegister(this);\n        this.errorCodeMetrics = new ConcurrentHashMap<>();\n    }\n\n    @Override\n    protected MetricSample provideMetricsSample(\n            ErrorCodeMetric metric, AtomicLong count, MetricsKey metricsKey, MetricsCategory metricsCategory) {\n        return new CounterMetricSample<>(\n                metricsKey.getNameByType(metric.getErrorCode()),\n                metricsKey.getDescription(),\n                metric.getTags(),\n                metricsCategory,\n                count);\n    }\n\n    @Override\n    protected void countConfigure(MetricsCountSampleConfigurer<String, String, ErrorCodeMetric> sampleConfigure) {\n        sampleConfigure.configureMetrics(configure -> {\n            String errorCode = configure.getSource();\n            ErrorCodeMetric metric = errorCodeMetrics.get(errorCode);\n\n            if (metric == null) {\n                metric = new ErrorCodeMetric(collector.getApplicationModel().getApplicationName(), errorCode);\n                errorCodeMetrics.put(errorCode, metric);\n            }\n            return metric;\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricThreadPoolExhaustedListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedEvent;\nimport org.apache.dubbo.common.threadpool.event.ThreadPoolExhaustedListener;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\n\npublic class MetricThreadPoolExhaustedListener implements ThreadPoolExhaustedListener {\n\n    private final ThreadRejectMetricsCountSampler threadRejectMetricsCountSampler;\n\n    private final String threadPoolExecutorName;\n\n    public MetricThreadPoolExhaustedListener(String threadPoolExecutorName, DefaultMetricsCollector collector) {\n        this.threadPoolExecutorName = threadPoolExecutorName;\n        this.threadRejectMetricsCountSampler = new ThreadRejectMetricsCountSampler(collector);\n    }\n\n    public MetricThreadPoolExhaustedListener(String threadPoolExecutorName, ThreadRejectMetricsCountSampler sampler) {\n        this.threadPoolExecutorName = threadPoolExecutorName;\n        this.threadRejectMetricsCountSampler = sampler;\n        this.threadRejectMetricsCountSampler.addMetricName(threadPoolExecutorName);\n    }\n\n    @Override\n    public void onEvent(ThreadPoolExhaustedEvent event) {\n        threadRejectMetricsCountSampler.inc(threadPoolExecutorName, threadPoolExecutorName);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricsCountSampleConfigurer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.metrics.model.Metric;\n\nimport java.util.function.Function;\n\npublic class MetricsCountSampleConfigurer<S, K, M extends Metric> {\n\n    public S source;\n\n    public K metricName;\n\n    public M metric;\n\n    public void setSource(S source) {\n        this.source = source;\n    }\n\n    public MetricsCountSampleConfigurer<S, K, M> setMetricsName(K metricName) {\n        this.metricName = metricName;\n        return this;\n    }\n\n    public MetricsCountSampleConfigurer<S, K, M> configureMetrics(\n            Function<MetricsCountSampleConfigurer<S, K, M>, M> builder) {\n        this.metric = builder.apply(this);\n        return this;\n    }\n\n    public S getSource() {\n        return source;\n    }\n\n    public M getMetric() {\n        return metric;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricsCountSampler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.metrics.model.Metric;\n\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic interface MetricsCountSampler<S, K, M extends Metric> extends MetricsSampler {\n\n    void inc(S source, K metricName);\n\n    Optional<ConcurrentHashMap<M, AtomicLong>> getCount(K metricName);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricsNameCountSampler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.model.Metric;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic abstract class MetricsNameCountSampler<S, K, M extends Metric> extends SimpleMetricsCountSampler<S, K, M> {\n\n    protected final DefaultMetricsCollector collector;\n\n    private final AtomicBoolean samplesChanged = new AtomicBoolean(true);\n\n    protected final Set<K> metricNames = new ConcurrentHashSet<>();\n\n    protected final MetricsCategory metricsCategory;\n\n    protected final MetricsKey metricsKey;\n\n    public MetricsNameCountSampler(\n            DefaultMetricsCollector collector, MetricsCategory metricsCategory, MetricsKey metricsKey) {\n        this.metricsCategory = metricsCategory;\n        this.metricsKey = metricsKey;\n        this.collector = collector;\n        this.collector.addSampler(this);\n    }\n\n    public void addMetricName(K name) {\n        this.metricNames.add(name);\n        this.samplesChanged.set(true);\n    }\n\n    @Override\n    public List<MetricSample> sample() {\n        List<MetricSample> metricSamples = new ArrayList<>();\n        metricNames.forEach(name -> collect(metricSamples, name));\n        return metricSamples;\n    }\n\n    private void collect(List<MetricSample> samples, K metricName) {\n        getCount(metricName)\n                .filter(e -> !e.isEmpty())\n                .ifPresent(map ->\n                        map.forEach((k, v) -> samples.add(provideMetricsSample(k, v, metricsKey, metricsCategory))));\n    }\n\n    protected abstract MetricSample provideMetricsSample(\n            M metric, AtomicLong count, MetricsKey metricsKey, MetricsCategory metricsCategory);\n\n    @Override\n    public boolean calSamplesChanged() {\n        // CAS to get and reset the flag in an atomic operation\n        return samplesChanged.compareAndSet(true, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricsSampler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.List;\n\npublic interface MetricsSampler {\n\n    List<MetricSample> sample();\n\n    /**\n     * Check if samples have been changed.\n     * Note that this method will reset the changed flag to false using CAS.\n     *\n     * @return true if samples have been changed\n     */\n    boolean calSamplesChanged();\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/SimpleMetricsCountSampler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.metrics.model.Metric;\n\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * @param <S> request source\n * @param <K> metricsName\n * @param <M> metric\n */\npublic abstract class SimpleMetricsCountSampler<S, K, M extends Metric> implements MetricsCountSampler<S, K, M> {\n\n    private final ConcurrentHashMap<M, AtomicLong> EMPTY_COUNT = new ConcurrentHashMap<>();\n\n    private final ConcurrentHashMap<K, ConcurrentHashMap<M, AtomicLong>> metricCounter = new ConcurrentHashMap<>();\n\n    @Override\n    public void inc(S source, K metricName) {\n        getAtomicCounter(source, metricName).incrementAndGet();\n    }\n\n    @Override\n    public Optional<ConcurrentHashMap<M, AtomicLong>> getCount(K metricName) {\n        return Optional.ofNullable(metricCounter.get(metricName) == null ? EMPTY_COUNT : metricCounter.get(metricName));\n    }\n\n    protected abstract void countConfigure(MetricsCountSampleConfigurer<S, K, M> sampleConfigure);\n\n    private AtomicLong getAtomicCounter(S source, K metricsName) {\n        MetricsCountSampleConfigurer<S, K, M> sampleConfigure = new MetricsCountSampleConfigurer<>();\n        sampleConfigure.setSource(source);\n        sampleConfigure.setMetricsName(metricsName);\n\n        this.countConfigure(sampleConfigure);\n\n        ConcurrentHashMap<M, AtomicLong> metricAtomic = metricCounter.get(metricsName);\n\n        if (metricAtomic == null) {\n            metricAtomic =\n                    ConcurrentHashMapUtils.computeIfAbsent(metricCounter, metricsName, k -> new ConcurrentHashMap<>());\n        }\n\n        Assert.notNull(sampleConfigure.getMetric(), \"metrics is null\");\n\n        AtomicLong atomicCounter = metricAtomic.get(sampleConfigure.getMetric());\n\n        if (atomicCounter == null) {\n            atomicCounter = ConcurrentHashMapUtils.computeIfAbsent(\n                    metricAtomic, sampleConfigure.getMetric(), k -> new AtomicLong());\n        }\n        return atomicCounter;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ThreadPoolMetricsSampler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.store.DataStore;\nimport org.apache.dubbo.common.store.DataStoreUpdateListener;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.model.ThreadPoolMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_SERVICE_COMPONENT_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION;\nimport static org.apache.dubbo.config.Constants.CLIENT_THREAD_POOL_PREFIX;\nimport static org.apache.dubbo.config.Constants.SERVER_THREAD_POOL_NAME;\nimport static org.apache.dubbo.config.Constants.SERVER_THREAD_POOL_PREFIX;\nimport static org.apache.dubbo.metrics.model.MetricsCategory.THREAD_POOL;\n\npublic class ThreadPoolMetricsSampler implements MetricsSampler, DataStoreUpdateListener {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ThreadPoolMetricsSampler.class);\n\n    private final DefaultMetricsCollector collector;\n    private FrameworkExecutorRepository frameworkExecutorRepository;\n    private DataStore dataStore;\n    private final Map<String, ThreadPoolExecutor> sampleThreadPoolExecutor = new ConcurrentHashMap<>();\n    private final ConcurrentHashMap<String, ThreadPoolMetric> threadPoolMetricMap = new ConcurrentHashMap<>();\n    private final AtomicBoolean samplesChanged = new AtomicBoolean(true);\n\n    public ThreadPoolMetricsSampler(DefaultMetricsCollector collector) {\n        this.collector = collector;\n    }\n\n    @Override\n    public void onUpdate(String componentName, String key, Object value) {\n        if (EXECUTOR_SERVICE_COMPONENT_KEY.equals(componentName)) {\n            if (value instanceof ThreadPoolExecutor) {\n                addExecutors(SERVER_THREAD_POOL_PREFIX + key, (ThreadPoolExecutor) value);\n            }\n        } else if (CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY.equals(componentName)) {\n            if (value instanceof ThreadPoolExecutor) {\n                addExecutors(CLIENT_THREAD_POOL_PREFIX + key, (ThreadPoolExecutor) value);\n            }\n        }\n    }\n\n    public void addExecutors(String name, ExecutorService executorService) {\n        Optional.ofNullable(executorService)\n                .filter(Objects::nonNull)\n                .filter(e -> e instanceof ThreadPoolExecutor)\n                .map(e -> (ThreadPoolExecutor) e)\n                .ifPresent(threadPoolExecutor -> {\n                    if (sampleThreadPoolExecutor.put(name, threadPoolExecutor) == null) {\n                        samplesChanged.set(true);\n                    }\n                });\n    }\n\n    @Override\n    public List<MetricSample> sample() {\n        List<MetricSample> metricSamples = new ArrayList<>();\n\n        sampleThreadPoolExecutor.forEach((name, executor) -> {\n            metricSamples.addAll(createMetricsSample(name, executor));\n        });\n\n        return metricSamples;\n    }\n\n    private List<MetricSample> createMetricsSample(String name, ThreadPoolExecutor executor) {\n        List<MetricSample> list = new ArrayList<>();\n        ThreadPoolMetric threadPoolMetric = ConcurrentHashMapUtils.computeIfAbsent(\n                threadPoolMetricMap, name, v -> new ThreadPoolMetric(collector.getApplicationName(), name, executor));\n        list.add(new GaugeMetricSample<>(\n                MetricsKey.THREAD_POOL_CORE_SIZE,\n                threadPoolMetric.getTags(),\n                THREAD_POOL,\n                threadPoolMetric,\n                ThreadPoolMetric::getCorePoolSize));\n        list.add(new GaugeMetricSample<>(\n                MetricsKey.THREAD_POOL_LARGEST_SIZE,\n                threadPoolMetric.getTags(),\n                THREAD_POOL,\n                threadPoolMetric,\n                ThreadPoolMetric::getLargestPoolSize));\n        list.add(new GaugeMetricSample<>(\n                MetricsKey.THREAD_POOL_MAX_SIZE,\n                threadPoolMetric.getTags(),\n                THREAD_POOL,\n                threadPoolMetric,\n                ThreadPoolMetric::getMaximumPoolSize));\n        list.add(new GaugeMetricSample<>(\n                MetricsKey.THREAD_POOL_ACTIVE_SIZE,\n                threadPoolMetric.getTags(),\n                THREAD_POOL,\n                threadPoolMetric,\n                ThreadPoolMetric::getActiveCount));\n        list.add(new GaugeMetricSample<>(\n                MetricsKey.THREAD_POOL_THREAD_COUNT,\n                threadPoolMetric.getTags(),\n                THREAD_POOL,\n                threadPoolMetric,\n                ThreadPoolMetric::getPoolSize));\n        list.add(new GaugeMetricSample<>(\n                MetricsKey.THREAD_POOL_QUEUE_SIZE,\n                threadPoolMetric.getTags(),\n                THREAD_POOL,\n                threadPoolMetric,\n                ThreadPoolMetric::getQueueSize));\n        return list;\n    }\n\n    public void registryDefaultSampleThreadPoolExecutor() {\n        ApplicationModel applicationModel = collector.getApplicationModel();\n        if (applicationModel == null) {\n            return;\n        }\n        addRpcExecutors();\n        addFrameworkExecutors();\n        addExecutorRejectMetrics();\n    }\n\n    private void addExecutorRejectMetrics() {\n        ThreadRejectMetricsCountSampler threadRejectMetricsCountSampler =\n                new ThreadRejectMetricsCountSampler(collector);\n        this.sampleThreadPoolExecutor.entrySet().stream()\n                .filter(entry -> entry.getKey().startsWith(SERVER_THREAD_POOL_NAME))\n                .forEach(entry -> {\n                    if (entry.getValue().getRejectedExecutionHandler() instanceof AbortPolicyWithReport) {\n                        MetricThreadPoolExhaustedListener metricThreadPoolExhaustedListener =\n                                new MetricThreadPoolExhaustedListener(entry.getKey(), threadRejectMetricsCountSampler);\n                        ((AbortPolicyWithReport) entry.getValue().getRejectedExecutionHandler())\n                                .addThreadPoolExhaustedEventListener(metricThreadPoolExhaustedListener);\n                    }\n                });\n    }\n\n    private void addRpcExecutors() {\n        if (this.dataStore == null) {\n            this.dataStore = collector\n                    .getApplicationModel()\n                    .getExtensionLoader(DataStore.class)\n                    .getDefaultExtension();\n        }\n\n        if (dataStore != null) {\n            dataStore.addListener(this);\n\n            Map<String, Object> executors = dataStore.get(EXECUTOR_SERVICE_COMPONENT_KEY);\n            for (Map.Entry<String, Object> entry : executors.entrySet()) {\n                ExecutorService executor = (ExecutorService) entry.getValue();\n                if (executor instanceof ThreadPoolExecutor) {\n                    this.addExecutors(SERVER_THREAD_POOL_PREFIX + entry.getKey(), executor);\n                }\n            }\n            executors = dataStore.get(CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY);\n            for (Map.Entry<String, Object> entry : executors.entrySet()) {\n                ExecutorService executor = (ExecutorService) entry.getValue();\n                if (executor instanceof ThreadPoolExecutor) {\n                    this.addExecutors(CLIENT_THREAD_POOL_PREFIX + entry.getKey(), executor);\n                }\n            }\n        }\n    }\n\n    private void addFrameworkExecutors() {\n        try {\n            if (this.frameworkExecutorRepository == null) {\n                this.frameworkExecutorRepository =\n                        collector.getApplicationModel().getBeanFactory().getBean(FrameworkExecutorRepository.class);\n            }\n        } catch (Exception ex) {\n            logger.warn(\n                    COMMON_METRICS_COLLECTOR_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"ThreadPoolMetricsSampler! frameworkExecutorRepository non-init\");\n        }\n        if (this.frameworkExecutorRepository == null) {\n            return;\n        }\n        this.addExecutors(\"poolRouterExecutor\", frameworkExecutorRepository.getPoolRouterExecutor());\n        this.addExecutors(\"metadataRetryExecutor\", frameworkExecutorRepository.getMetadataRetryExecutor());\n        this.addExecutors(\"internalServiceExecutor\", frameworkExecutorRepository.getInternalServiceExecutor());\n        this.addExecutors(\n                \"connectivityScheduledExecutor\", frameworkExecutorRepository.getConnectivityScheduledExecutor());\n        this.addExecutors(\n                \"cacheRefreshingScheduledExecutor\", frameworkExecutorRepository.getCacheRefreshingScheduledExecutor());\n        this.addExecutors(\"sharedExecutor\", frameworkExecutorRepository.getSharedExecutor());\n        this.addExecutors(\"sharedScheduledExecutor\", frameworkExecutorRepository.getSharedScheduledExecutor());\n        this.addExecutors(\"mappingRefreshingExecutor\", frameworkExecutorRepository.getMappingRefreshingExecutor());\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // CAS to get and reset the flag in an atomic operation\n        return samplesChanged.compareAndSet(true, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ThreadRejectMetricsCountSampler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.ThreadPoolRejectMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport static org.apache.dubbo.metrics.model.MetricsCategory.THREAD_POOL;\n\npublic class ThreadRejectMetricsCountSampler extends MetricsNameCountSampler<String, String, ThreadPoolRejectMetric> {\n\n    public ThreadRejectMetricsCountSampler(DefaultMetricsCollector collector) {\n        super(collector, THREAD_POOL, MetricsKey.THREAD_POOL_THREAD_REJECT_COUNT);\n    }\n\n    @Override\n    protected MetricSample provideMetricsSample(\n            ThreadPoolRejectMetric metric, AtomicLong count, MetricsKey metricsKey, MetricsCategory metricsCategory) {\n        return new GaugeMetricSample<>(\n                metricsKey.getNameByType(metric.getThreadPoolName()),\n                metricsKey.getDescription(),\n                metric.getTags(),\n                metricsCategory,\n                count,\n                AtomicLong::get);\n    }\n\n    @Override\n    protected void countConfigure(\n            MetricsCountSampleConfigurer<String, String, ThreadPoolRejectMetric> sampleConfigure) {\n        sampleConfigure.configureMetrics(\n                configure -> new ThreadPoolRejectMetric(collector.getApplicationName(), configure.getSource()));\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/DefaultSubDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.event;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.metrics.MetricsConstants;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.collector.MethodMetricsCollector;\nimport org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener;\nimport org.apache.dubbo.metrics.listener.MetricsListener;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.key.CategoryOverall;\nimport org.apache.dubbo.metrics.model.key.MetricsCat;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\n\nimport static org.apache.dubbo.metrics.DefaultConstants.METRIC_THROWABLE;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED;\n\n@SuppressWarnings({\"unchecked\", \"rawtypes\"})\npublic final class DefaultSubDispatcher extends SimpleMetricsEventMulticaster {\n\n    public DefaultSubDispatcher(DefaultMetricsCollector collector) {\n\n        CategoryOverall categoryOverall = initMethodRequest();\n        super.addListener(categoryOverall.getPost().getEventFunc().apply(collector));\n        super.addListener(categoryOverall.getFinish().getEventFunc().apply(collector));\n        super.addListener(categoryOverall.getError().getEventFunc().apply(collector));\n\n        super.addListener(new MetricsListener<RequestEvent>() {\n\n            @Override\n            public boolean isSupport(MetricsEvent event) {\n                return event instanceof RequestEvent && ((RequestEvent) event).isRequestErrorEvent();\n            }\n\n            private final MetricsPlaceValue dynamicPlaceType =\n                    MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD);\n\n            @Override\n            public void onEvent(RequestEvent event) {\n                MetricsSupport.increment(\n                        METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED,\n                        dynamicPlaceType,\n                        (MethodMetricsCollector) collector,\n                        event);\n            }\n        });\n    }\n\n    private CategoryOverall initMethodRequest() {\n\n        return new CategoryOverall(\n                null,\n                new MetricsCat(\n                        MetricsKey.METRIC_REQUESTS,\n                        (key, placeType, collector) -> AbstractMetricsKeyListener.onEvent(key, event -> {\n                            MetricsPlaceValue dynamicPlaceType = MetricsPlaceValue.of(\n                                    event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.METHOD);\n                            MetricsSupport.increment(key, dynamicPlaceType, (MethodMetricsCollector) collector, event);\n                            MetricsSupport.increment(\n                                    MetricsKey.METRIC_REQUESTS_PROCESSING,\n                                    dynamicPlaceType,\n                                    (MethodMetricsCollector) collector,\n                                    event);\n                        })),\n                new MetricsCat(\n                        MetricsKey.METRIC_REQUESTS_SUCCEED,\n                        (key, placeType, collector) -> AbstractMetricsKeyListener.onFinish(key, event -> {\n                            MetricsPlaceValue dynamicPlaceType = MetricsPlaceValue.of(\n                                    event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.METHOD);\n                            MetricsSupport.dec(\n                                    MetricsKey.METRIC_REQUESTS_PROCESSING, dynamicPlaceType, collector, event);\n\n                            Object throwableObj = event.getAttachmentValue(METRIC_THROWABLE);\n                            MetricsKey targetKey;\n                            if (throwableObj == null) {\n                                targetKey = key;\n                            } else {\n                                targetKey = MetricsSupport.getMetricsKey((Throwable) throwableObj);\n                                MetricsSupport.increment(\n                                        MetricsKey.METRIC_REQUESTS_TOTAL_FAILED,\n                                        dynamicPlaceType,\n                                        (MethodMetricsCollector) collector,\n                                        event);\n                            }\n                            MetricsSupport.incrAndAddRt(\n                                    targetKey, dynamicPlaceType, (MethodMetricsCollector) collector, event);\n                        })),\n                new MetricsCat(\n                        MetricsKey.METRIC_REQUEST_BUSINESS_FAILED,\n                        (key, placeType, collector) -> AbstractMetricsKeyListener.onError(key, event -> {\n                            MetricsKey targetKey =\n                                    MetricsSupport.getMetricsKey(event.getAttachmentValue(METRIC_THROWABLE));\n                            // Dynamic metricsKey && dynamicPlaceType\n                            MetricsPlaceValue dynamicPlaceType = MetricsPlaceValue.of(\n                                    event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.METHOD);\n                            MetricsSupport.increment(\n                                    MetricsKey.METRIC_REQUESTS_TOTAL_FAILED,\n                                    dynamicPlaceType,\n                                    (MethodMetricsCollector) collector,\n                                    event);\n                            MetricsSupport.dec(\n                                    MetricsKey.METRIC_REQUESTS_PROCESSING, dynamicPlaceType, collector, event);\n                            MetricsSupport.incrAndAddRt(\n                                    targetKey, dynamicPlaceType, (MethodMetricsCollector) collector, event);\n                        })));\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.event;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.metrics.MetricsConstants;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.exception.MetricsNeverHappenException;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.TypeWrapper;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport static org.apache.dubbo.metrics.DefaultConstants.METRIC_THROWABLE;\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SUCCEED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUEST_BUSINESS_FAILED;\n\n/**\n * Request related events\n */\npublic class RequestEvent extends TimeCounterEvent {\n    private static final TypeWrapper REQUEST_EVENT = new TypeWrapper(\n            MetricsLevel.SERVICE, METRIC_REQUESTS, METRIC_REQUESTS_SUCCEED, METRIC_REQUEST_BUSINESS_FAILED);\n    private static final TypeWrapper REQUEST_ERROR_EVENT =\n            new TypeWrapper(MetricsLevel.METHOD, MetricsKey.METRIC_REQUESTS);\n\n    public RequestEvent(\n            ApplicationModel applicationModel,\n            String appName,\n            MetricsDispatcher metricsDispatcher,\n            DefaultMetricsCollector collector,\n            TypeWrapper TYPE_WRAPPER) {\n        super(applicationModel, appName, metricsDispatcher, TYPE_WRAPPER);\n        if (collector == null) {\n            ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n            if (!beanFactory.isDestroyed()) {\n                collector = beanFactory.getBean(DefaultMetricsCollector.class);\n            }\n        }\n        super.setAvailable(collector != null && collector.isCollectEnabled());\n    }\n\n    public static RequestEvent toRequestEvent(\n            ApplicationModel applicationModel,\n            String appName,\n            MetricsDispatcher metricsDispatcher,\n            DefaultMetricsCollector collector,\n            Invocation invocation,\n            String side,\n            boolean serviceLevel) {\n        MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, serviceLevel);\n        RequestEvent requestEvent =\n                new RequestEvent(applicationModel, appName, metricsDispatcher, collector, REQUEST_EVENT);\n        requestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);\n        requestEvent.putAttachment(MetricsConstants.METHOD_METRICS, methodMetric);\n        requestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));\n        requestEvent.putAttachment(MetricsConstants.INVOCATION_SIDE, side);\n        return requestEvent;\n    }\n\n    @Override\n    public void customAfterPost(Object postResult) {\n        if (postResult == null) {\n            return;\n        }\n        if (!(postResult instanceof Result)) {\n            throw new MetricsNeverHappenException(\n                    \"Result type error, postResult:\" + postResult.getClass().getName());\n        }\n        super.putAttachment(METRIC_THROWABLE, ((Result) postResult).getException());\n    }\n\n    /**\n     * Acts on MetricsClusterFilter to monitor exceptions that occur before request execution\n     */\n    public static RequestEvent toRequestErrorEvent(\n            ApplicationModel applicationModel,\n            String appName,\n            MetricsDispatcher metricsDispatcher,\n            Invocation invocation,\n            String side,\n            int code,\n            boolean serviceLevel) {\n        RequestEvent event = new RequestEvent(applicationModel, appName, metricsDispatcher, null, REQUEST_ERROR_EVENT);\n        event.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));\n        event.putAttachment(MetricsConstants.INVOCATION_SIDE, side);\n        event.putAttachment(MetricsConstants.INVOCATION, invocation);\n        event.putAttachment(MetricsConstants.INVOCATION_REQUEST_ERROR, code);\n        event.putAttachment(\n                MetricsConstants.METHOD_METRICS, new MethodMetric(applicationModel, invocation, serviceLevel));\n        return event;\n    }\n\n    public boolean isRequestErrorEvent() {\n        return super.getAttachmentValue(MetricsConstants.INVOCATION_REQUEST_ERROR) != null;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/filter/MetricsFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.filter;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.event.RequestEvent;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.metrics.DefaultConstants.METRIC_FILTER_EVENT;\nimport static org.apache.dubbo.metrics.DefaultConstants.METRIC_THROWABLE;\n\npublic class MetricsFilter implements ScopeModelAware {\n\n    private ApplicationModel applicationModel;\n    private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(MetricsFilter.class);\n    private boolean rpcMetricsEnable;\n    private String appName;\n    private MetricsDispatcher metricsDispatcher;\n    private DefaultMetricsCollector defaultMetricsCollector;\n    private boolean serviceLevel;\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        this.rpcMetricsEnable = applicationModel\n                .getApplicationConfigManager()\n                .getMetrics()\n                .map(MetricsConfig::getEnableRpc)\n                .orElse(false);\n        this.appName = applicationModel.tryGetApplicationName();\n        this.metricsDispatcher = applicationModel.getBeanFactory().getBean(MetricsDispatcher.class);\n        this.defaultMetricsCollector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);\n        serviceLevel = MethodMetric.isServiceLevel(applicationModel);\n    }\n\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        return invoke(invoker, invocation, PROVIDER.equals(MetricsSupport.getSide(invocation)));\n    }\n\n    public Result invoke(Invoker<?> invoker, Invocation invocation, boolean isProvider) throws RpcException {\n        if (rpcMetricsEnable) {\n            try {\n                RequestEvent requestEvent = RequestEvent.toRequestEvent(\n                        applicationModel,\n                        appName,\n                        metricsDispatcher,\n                        defaultMetricsCollector,\n                        invocation,\n                        isProvider ? PROVIDER : CONSUMER,\n                        serviceLevel);\n                MetricsEventBus.before(requestEvent);\n                invocation.put(METRIC_FILTER_EVENT, requestEvent);\n            } catch (Throwable t) {\n                LOGGER.warn(INTERNAL_ERROR, \"\", \"\", \"Error occurred when invoke.\", t);\n            }\n        }\n        return invoker.invoke(invocation);\n    }\n\n    public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) {\n        if (rpcMetricsEnable) {\n            onResponse(result, invoker, invocation, PROVIDER.equals(MetricsSupport.getSide(invocation)));\n        }\n    }\n\n    public void onResponse(Result result, Invoker<?> invoker, Invocation invocation, boolean isProvider) {\n        Object eventObj = invocation.get(METRIC_FILTER_EVENT);\n        if (eventObj != null) {\n            try {\n                MetricsEventBus.after((RequestEvent) eventObj, result);\n            } catch (Throwable t) {\n                LOGGER.warn(INTERNAL_ERROR, \"\", \"\", \"Error occurred when onResponse.\", t);\n            }\n        }\n    }\n\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        if (rpcMetricsEnable) {\n            onError(t, invoker, invocation, PROVIDER.equals(MetricsSupport.getSide(invocation)));\n        }\n    }\n\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation, boolean isProvider) {\n        Object eventObj = invocation.get(METRIC_FILTER_EVENT);\n        if (eventObj != null) {\n            try {\n                RequestEvent requestEvent = (RequestEvent) eventObj;\n                requestEvent.putAttachment(METRIC_THROWABLE, t);\n                MetricsEventBus.error(requestEvent);\n            } catch (Throwable throwable) {\n                LOGGER.warn(INTERNAL_ERROR, \"\", \"\", \"Error occurred when onResponse.\", throwable);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/filter/MetricsProviderFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.BaseFilter;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;\n\n@Activate(\n        group = {PROVIDER},\n        order = Integer.MIN_VALUE + 100)\npublic class MetricsProviderFilter extends MetricsFilter implements Filter, BaseFilter.Listener {\n    public MetricsProviderFilter() {}\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        return super.invoke(invoker, invocation, true);\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {\n        super.onResponse(appResponse, invoker, invocation, true);\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        super.onError(t, invoker, invocation, true);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/register/HistogramMetricRegister.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.register;\n\nimport org.apache.dubbo.config.nested.HistogramConfig;\nimport org.apache.dubbo.metrics.sample.HistogramMetricSample;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.Timer;\n\npublic class HistogramMetricRegister implements MetricRegister<HistogramMetricSample, Timer> {\n\n    private final MeterRegistry registry;\n    private final HistogramConfig config;\n\n    public HistogramMetricRegister(MeterRegistry registry, HistogramConfig config) {\n        this.registry = registry;\n        this.config = config;\n    }\n\n    @Override\n    public Timer register(HistogramMetricSample sample) {\n        List<Tag> tags = new ArrayList<>();\n        sample.getTags().forEach((k, v) -> {\n            if (v == null) {\n                v = \"\";\n            }\n\n            tags.add(Tag.of(k, v));\n        });\n\n        Timer.Builder builder = Timer.builder(sample.getName())\n                .description(sample.getDescription())\n                .tags(tags);\n\n        if (Boolean.TRUE.equals(config.getEnabledPercentiles())) {\n            builder.publishPercentileHistogram(true);\n        }\n\n        if (config.getPercentiles() != null) {\n            builder.publishPercentiles(config.getPercentiles());\n        }\n\n        if (config.getBucketsMs() != null) {\n            builder.serviceLevelObjectives(\n                    Arrays.stream(config.getBucketsMs()).map(Duration::ofMillis).toArray(Duration[]::new));\n        }\n\n        if (config.getMinExpectedMs() != null) {\n            builder.minimumExpectedValue(Duration.ofMillis(config.getMinExpectedMs()));\n        }\n\n        if (config.getMaxExpectedMs() != null) {\n            builder.maximumExpectedValue(Duration.ofMillis(config.getMaxExpectedMs()));\n        }\n\n        if (config.getDistributionStatisticExpiryMin() != null) {\n            builder.distributionStatisticExpiry(Duration.ofMinutes(config.getDistributionStatisticExpiryMin()));\n        }\n\n        return builder.register(registry);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/register/MetricRegister.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.register;\n\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport io.micrometer.core.instrument.Meter;\n\npublic interface MetricRegister<S extends MetricSample, M extends Meter> {\n\n    M register(S sample);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsReporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.report;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.lang.ShutdownHookCallbacks;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.metrics.MetricsGlobalRegistry;\nimport org.apache.dubbo.metrics.collector.AggregateMetricsCollector;\nimport org.apache.dubbo.metrics.collector.HistogramMetricsCollector;\nimport org.apache.dubbo.metrics.collector.MetricsCollector;\nimport org.apache.dubbo.metrics.model.sample.CounterMetricSample;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport io.micrometer.core.instrument.FunctionCounter;\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;\nimport io.micrometer.core.instrument.binder.system.ProcessorMetrics;\nimport io.micrometer.core.instrument.binder.system.UptimeMetrics;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION;\nimport static org.apache.dubbo.common.constants.MetricsConstants.COLLECTOR_SYNC_PERIOD_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.ENABLE_COLLECTOR_SYNC_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.ENABLE_JVM_METRICS_KEY;\n\n/**\n * AbstractMetricsReporter.\n */\npublic abstract class AbstractMetricsReporter implements MetricsReporter {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractMetricsReporter.class);\n\n    private final AtomicBoolean initialized = new AtomicBoolean(false);\n\n    protected final URL url;\n\n    @SuppressWarnings(\"rawtypes\")\n    protected final List<MetricsCollector> collectors = new ArrayList<>();\n    // Avoid instances being gc due to weak references\n    protected final List<MeterBinder> instanceHolder = new ArrayList<>();\n    protected final CompositeMeterRegistry compositeRegistry;\n\n    private final ApplicationModel applicationModel;\n\n    private ScheduledExecutorService collectorSyncJobExecutor = null;\n\n    private static final int DEFAULT_SCHEDULE_INITIAL_DELAY = 5;\n    private static final int DEFAULT_SCHEDULE_PERIOD = 60;\n\n    protected AbstractMetricsReporter(URL url, ApplicationModel applicationModel) {\n        this.url = url;\n        this.applicationModel = applicationModel;\n        this.compositeRegistry = MetricsGlobalRegistry.getCompositeRegistry(applicationModel);\n    }\n\n    @Override\n    public void init() {\n        if (initialized.compareAndSet(false, true)) {\n            addJvmMetrics();\n            initCollectors();\n            scheduleMetricsCollectorSyncJob();\n\n            doInit();\n\n            registerDubboShutdownHook();\n        }\n    }\n\n    protected void addMeterRegistry(MeterRegistry registry) {\n        compositeRegistry.add(registry);\n    }\n\n    protected ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    private void addJvmMetrics() {\n        boolean enableJvmMetrics = url.getParameter(ENABLE_JVM_METRICS_KEY, false);\n        if (enableJvmMetrics) {\n            new ClassLoaderMetrics().bindTo(compositeRegistry);\n            new JvmMemoryMetrics().bindTo(compositeRegistry);\n\n            @SuppressWarnings(\"java:S2095\")\n            // Do not change JvmGcMetrics to try-with-resources as the JvmGcMetrics will not be available after\n            // (auto-)closing.\n            // See https://github.com/micrometer-metrics/micrometer/issues/1492\n            JvmGcMetrics jvmGcMetrics = new JvmGcMetrics();\n            jvmGcMetrics.bindTo(compositeRegistry);\n            Runtime.getRuntime().addShutdownHook(new Thread(jvmGcMetrics::close));\n\n            bindTo(new ProcessorMetrics());\n            new JvmThreadMetrics().bindTo(compositeRegistry);\n            bindTo(new UptimeMetrics());\n        }\n    }\n\n    private void bindTo(MeterBinder binder) {\n        binder.bindTo(compositeRegistry);\n        instanceHolder.add(binder);\n    }\n\n    @SuppressWarnings(\"rawtypes\")\n    private void initCollectors() {\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        beanFactory.getOrRegisterBean(AggregateMetricsCollector.class);\n        beanFactory.getOrRegisterBean(HistogramMetricsCollector.class);\n        List<MetricsCollector> otherCollectors = beanFactory.getBeansOfType(MetricsCollector.class);\n        collectors.addAll(otherCollectors);\n    }\n\n    private void scheduleMetricsCollectorSyncJob() {\n        boolean enableCollectorSync = url.getParameter(ENABLE_COLLECTOR_SYNC_KEY, true);\n        if (enableCollectorSync) {\n            int collectSyncPeriod = url.getParameter(COLLECTOR_SYNC_PERIOD_KEY, DEFAULT_SCHEDULE_PERIOD);\n\n            NamedThreadFactory threadFactory = new NamedThreadFactory(\"metrics-collector-sync-job\", true);\n            collectorSyncJobExecutor = Executors.newScheduledThreadPool(1, threadFactory);\n            collectorSyncJobExecutor.scheduleWithFixedDelay(\n                    this::resetIfSamplesChanged, DEFAULT_SCHEDULE_INITIAL_DELAY, collectSyncPeriod, TimeUnit.SECONDS);\n        }\n    }\n\n    @SuppressWarnings({\"unchecked\"})\n    public void resetIfSamplesChanged() {\n        collectors.forEach(collector -> {\n            if (!collector.calSamplesChanged()) {\n                // Metrics has not been changed since last time, no need to reload\n                return;\n            }\n            // Collect all the samples and register them to the micrometer registry\n            List<MetricSample> samples = collector.collect();\n            for (MetricSample sample : samples) {\n                try {\n                    registerSample(sample);\n                } catch (Exception e) {\n                    logger.error(\n                            COMMON_METRICS_COLLECTOR_EXCEPTION,\n                            \"\",\n                            \"\",\n                            \"error occurred when synchronize metrics collector.\",\n                            e);\n                }\n            }\n        });\n    }\n\n    @SuppressWarnings({\"rawtypes\"})\n    private void registerSample(MetricSample sample) {\n        switch (sample.getType()) {\n            case GAUGE:\n                registerGaugeSample((GaugeMetricSample) sample);\n                break;\n            case COUNTER:\n                registerCounterSample((CounterMetricSample) sample);\n            case TIMER:\n            case LONG_TASK_TIMER:\n            case DISTRIBUTION_SUMMARY:\n                // TODO\n                break;\n            default:\n                break;\n        }\n    }\n\n    @SuppressWarnings({\"rawtypes\"})\n    private void registerCounterSample(CounterMetricSample sample) {\n        FunctionCounter.builder(sample.getName(), sample.getValue(), Number::doubleValue)\n                .description(sample.getDescription())\n                .tags(getTags(sample))\n                .register(compositeRegistry);\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private void registerGaugeSample(GaugeMetricSample sample) {\n        Gauge.builder(sample.getName(), sample.getValue(), sample.getApply())\n                .description(sample.getDescription())\n                .tags(getTags(sample))\n                .register(compositeRegistry);\n    }\n\n    private static List<Tag> getTags(MetricSample gaugeSample) {\n        List<Tag> tags = new ArrayList<>();\n        gaugeSample.getTags().forEach((k, v) -> {\n            if (v == null) {\n                v = \"\";\n            }\n\n            tags.add(Tag.of(k, v));\n        });\n        return tags;\n    }\n\n    private void registerDubboShutdownHook() {\n        applicationModel.getBeanFactory().getBean(ShutdownHookCallbacks.class).addCallback(this::destroy);\n    }\n\n    public void destroy() {\n        if (collectorSyncJobExecutor != null) {\n            collectorSyncJobExecutor.shutdownNow();\n        }\n        doDestroy();\n    }\n\n    protected abstract void doInit();\n\n    protected abstract void doDestroy();\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/DefaultMetricsReporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.report;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.core.instrument.Counter;\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.Timer;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\n\npublic class DefaultMetricsReporter extends AbstractMetricsReporter {\n\n    SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry();\n\n    protected DefaultMetricsReporter(URL url, ApplicationModel applicationModel) {\n        super(url, applicationModel);\n    }\n\n    @Override\n    public String getResponse() {\n        return null;\n    }\n\n    @Override\n    public String getResponseWithName(String metricsName) {\n        Map<String, List<Tag>> metricsTags = new HashMap<>();\n        Map<String, Object> metricsValue = new HashMap<>();\n        StringBuilder sb = new StringBuilder();\n        meterRegistry.getMeters().stream()\n                .filter(meter -> {\n                    if (meter == null || meter.getId() == null || meter.getId().getName() == null) {\n                        return false;\n                    }\n                    if (metricsName != null) {\n                        return meter.getId().getName().contains(metricsName);\n                    }\n                    return true;\n                })\n                .forEach(meter -> {\n                    Object value = null;\n                    if (meter instanceof Counter) {\n                        Counter counter = (Counter) meter;\n                        value = counter.count();\n                    }\n                    if (meter instanceof Gauge) {\n                        Gauge gauge = (Gauge) meter;\n                        value = gauge.value();\n                    }\n                    if (meter instanceof Timer) {\n                        Timer timer = (Timer) meter;\n                        value = timer.totalTime(TimeUnit.MILLISECONDS);\n                    }\n                    metricsTags.put(meter.getId().getName(), meter.getId().getTags());\n                    metricsValue.put(meter.getId().getName(), value);\n                });\n        metricsValue.forEach((key, value) -> {\n            sb.append(key).append(\"{\");\n            List<Tag> tags = metricsTags.get(key);\n            if (tags != null && tags.size() > 0) {\n                tags.forEach(tag -> {\n                    sb.append(tag.getKey()).append(\"=\").append(tag.getValue()).append(\",\");\n                });\n            }\n            sb.append(\"} \").append(value).append(System.lineSeparator());\n        });\n        return sb.toString();\n    }\n\n    @Override\n    protected void doInit() {\n        addMeterRegistry(meterRegistry);\n    }\n\n    @Override\n    protected void doDestroy() {}\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/DefaultMetricsReporterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.report;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\npublic class DefaultMetricsReporterFactory extends AbstractMetricsReporterFactory {\n    private final ApplicationModel applicationModel;\n\n    public DefaultMetricsReporterFactory(ApplicationModel applicationModel) {\n        super(applicationModel);\n        this.applicationModel = applicationModel;\n    }\n\n    @Override\n    public MetricsReporter createMetricsReporter(URL url) {\n        return new DefaultMetricsReporter(url, applicationModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/nop/NopMetricsReporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.report.nop;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metrics.report.MetricsReporter;\n\n/**\n * Metrics reporter without any operations.\n */\npublic class NopMetricsReporter implements MetricsReporter {\n\n    public NopMetricsReporter(URL url) {}\n\n    @Override\n    public void init() {}\n\n    @Override\n    public void resetIfSamplesChanged() {}\n\n    @Override\n    public String getResponse() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/nop/NopMetricsReporterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.report.nop;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metrics.report.MetricsReporter;\nimport org.apache.dubbo.metrics.report.MetricsReporterFactory;\n\n/**\n * MetricsReporterFactory to create NopMetricsReporter.\n */\npublic class NopMetricsReporterFactory implements MetricsReporterFactory {\n\n    @Override\n    public MetricsReporter createMetricsReporter(URL url) {\n        return new NopMetricsReporter(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/sample/HistogramMetricSample.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.sample;\n\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.Map;\n\npublic class HistogramMetricSample extends MetricSample {\n\n    public HistogramMetricSample(String name, String description, Map<String, String> tags, MetricsCategory category) {\n        super(name, description, tags, Type.TIMER, category);\n    }\n\n    public HistogramMetricSample(\n            String name,\n            String description,\n            Map<String, String> tags,\n            Type type,\n            MetricsCategory category,\n            String baseUnit) {\n        super(name, description, tags, type, category, baseUnit);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/service/DefaultMetricsService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.service;\n\nimport org.apache.dubbo.metrics.collector.MetricsCollector;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Default implementation of {@link MetricsService}\n */\npublic class DefaultMetricsService implements MetricsService {\n\n    @SuppressWarnings(\"rawtypes\")\n    protected final List<MetricsCollector> collectors = new ArrayList<>();\n\n    public DefaultMetricsService(ApplicationModel applicationModel) {\n        collectors.addAll(applicationModel.getBeanFactory().getBeansOfType(MetricsCollector.class));\n    }\n\n    @Override\n    public Map<MetricsCategory, List<MetricsEntity>> getMetricsByCategories(List<MetricsCategory> categories) {\n        return getMetricsByCategories(null, categories);\n    }\n\n    @Override\n    public Map<MetricsCategory, List<MetricsEntity>> getMetricsByCategories(\n            String serviceUniqueName, List<MetricsCategory> categories) {\n        return getMetricsByCategories(serviceUniqueName, null, null, categories);\n    }\n\n    @Override\n    public Map<MetricsCategory, List<MetricsEntity>> getMetricsByCategories(\n            String serviceUniqueName, String methodName, Class<?>[] parameterTypes, List<MetricsCategory> categories) {\n        Map<MetricsCategory, List<MetricsEntity>> result = new HashMap<>();\n        for (MetricsCollector<?> collector : collectors) {\n            List<MetricSample> samples = collector.collect();\n            for (MetricSample sample : samples) {\n                if (categories.contains(sample.getCategory())) {\n                    List<MetricsEntity> entities = result.computeIfAbsent(sample.getCategory(), k -> new ArrayList<>());\n                    entities.add(sampleToEntity(sample));\n                }\n            }\n        }\n\n        return result;\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private MetricsEntity sampleToEntity(MetricSample sample) {\n        MetricsEntity entity = new MetricsEntity();\n\n        entity.setName(sample.getName());\n        entity.setTags(sample.getTags());\n        entity.setCategory(sample.getCategory());\n        switch (sample.getType()) {\n            case GAUGE:\n                GaugeMetricSample gaugeSample = (GaugeMetricSample) sample;\n                entity.setValue(gaugeSample.getApply().applyAsDouble(gaugeSample.getValue()));\n                break;\n            case COUNTER:\n            case LONG_TASK_TIMER:\n            case TIMER:\n            case DISTRIBUTION_SUMMARY:\n            default:\n                break;\n        }\n\n        return entity;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/monitor/support/MonitorClusterFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.monitor.support;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\n\n@Deprecated\n@Activate(group = {CONSUMER})\npublic class MonitorClusterFilter extends MonitorFilter implements ClusterFilter {}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/monitor/support/MonitorFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.monitor.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.monitor.Monitor;\nimport org.apache.dubbo.monitor.MonitorFactory;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceModel;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_MONITOR_EXCEPTION;\nimport static org.apache.dubbo.monitor.Constants.CONCURRENT_KEY;\nimport static org.apache.dubbo.monitor.Constants.COUNT_PROTOCOL;\nimport static org.apache.dubbo.monitor.Constants.ELAPSED_KEY;\nimport static org.apache.dubbo.monitor.Constants.FAILURE_KEY;\nimport static org.apache.dubbo.monitor.Constants.SUCCESS_KEY;\nimport static org.apache.dubbo.rpc.Constants.INPUT_KEY;\nimport static org.apache.dubbo.rpc.Constants.OUTPUT_KEY;\n\n/**\n * MonitorFilter. (SPI, Singleton, ThreadSafe)\n */\n@Deprecated\n@Activate(group = {PROVIDER})\npublic class MonitorFilter implements Filter, Filter.Listener {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MonitorFilter.class);\n    private static final String MONITOR_FILTER_START_TIME = \"monitor_filter_start_time\";\n    private static final String MONITOR_REMOTE_HOST_STORE = \"monitor_remote_host_store\";\n\n    /**\n     * The Concurrent counter\n     */\n    private final ConcurrentMap<String, AtomicInteger> concurrents = new ConcurrentHashMap<>();\n\n    /**\n     * The MonitorFactory\n     */\n    private MonitorFactory monitorFactory;\n\n    public void setMonitorFactory(MonitorFactory monitorFactory) {\n        this.monitorFactory = monitorFactory;\n    }\n\n    /**\n     * The invocation interceptor,it will collect the invoke data about this invocation and send it to monitor center\n     *\n     * @param invoker    service\n     * @param invocation invocation.\n     * @return {@link Result} the invoke result\n     * @throws RpcException\n     */\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        if (invoker.getUrl().hasAttribute(MONITOR_KEY)) {\n            invocation.put(MONITOR_FILTER_START_TIME, System.currentTimeMillis());\n            invocation.put(\n                    MONITOR_REMOTE_HOST_STORE, RpcContext.getServiceContext().getRemoteHost());\n            // count up\n            getConcurrent(invoker, invocation).incrementAndGet();\n        }\n        ServiceModel serviceModel = invoker.getUrl().getServiceModel();\n        if (serviceModel instanceof ProviderModel) {\n            ((ProviderModel) serviceModel).updateLastInvokeTime();\n        }\n\n        // proceed invocation chain\n        return invoker.invoke(invocation);\n    }\n\n    /**\n     * concurrent counter\n     *\n     * @param invoker\n     * @param invocation\n     * @return\n     */\n    private AtomicInteger getConcurrent(Invoker<?> invoker, Invocation invocation) {\n        String key = invoker.getInterface().getName() + \".\" + RpcUtils.getMethodName(invocation);\n        return ConcurrentHashMapUtils.computeIfAbsent(concurrents, key, k -> new AtomicInteger());\n    }\n\n    @Override\n    public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) {\n        if (invoker.getUrl().hasAttribute(MONITOR_KEY)) {\n            Long startTime = (Long) invocation.get(MONITOR_FILTER_START_TIME);\n            if (startTime != null) {\n                collect(\n                        invoker,\n                        invocation,\n                        result,\n                        (String) invocation.get(MONITOR_REMOTE_HOST_STORE),\n                        startTime,\n                        false);\n            }\n            // count down\n            getConcurrent(invoker, invocation).decrementAndGet();\n        }\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        if (invoker.getUrl().hasAttribute(MONITOR_KEY)) {\n            Long startTime = (Long) invocation.get(MONITOR_FILTER_START_TIME);\n            if (startTime != null) {\n                collect(invoker, invocation, null, (String) invocation.get(MONITOR_REMOTE_HOST_STORE), startTime, true);\n            }\n            // count down\n            getConcurrent(invoker, invocation).decrementAndGet();\n        }\n    }\n\n    /**\n     * The collector logic, it will be handled by the default monitor\n     *\n     * @param invoker\n     * @param invocation\n     * @param result     the invocation result\n     * @param remoteHost the remote host address\n     * @param start      the timestamp the invocation begin\n     * @param error      if there is an error on the invocation\n     */\n    private void collect(\n            Invoker<?> invoker, Invocation invocation, Result result, String remoteHost, long start, boolean error) {\n        try {\n            Object monitorUrl;\n            monitorUrl = invoker.getUrl().getAttribute(MONITOR_KEY);\n            if (monitorUrl instanceof URL) {\n                Monitor monitor = monitorFactory.getMonitor((URL) monitorUrl);\n                if (monitor == null) {\n                    return;\n                }\n                URL statisticsUrl = createStatisticsUrl(invoker, invocation, result, remoteHost, start, error);\n                monitor.collect(statisticsUrl.toSerializableURL());\n            }\n        } catch (Throwable t) {\n            logger.warn(\n                    COMMON_MONITOR_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to monitor count service \" + invoker.getUrl() + \", cause: \" + t.getMessage(),\n                    t);\n        }\n    }\n\n    /**\n     * Create statistics url\n     *\n     * @param invoker\n     * @param invocation\n     * @param result\n     * @param remoteHost\n     * @param start\n     * @param error\n     * @return\n     */\n    private URL createStatisticsUrl(\n            Invoker<?> invoker, Invocation invocation, Result result, String remoteHost, long start, boolean error) {\n        // ---- service statistics ----\n        // invocation cost\n        long elapsed = System.currentTimeMillis() - start;\n        // current concurrent count\n        int concurrent = getConcurrent(invoker, invocation).get();\n        String application = invoker.getUrl().getApplication();\n        // service name\n        String service = invoker.getInterface().getName();\n        // method name\n        String method = RpcUtils.getMethodName(invocation);\n        String group = invoker.getUrl().getGroup();\n        String version = invoker.getUrl().getVersion();\n\n        int localPort;\n        String remoteKey, remoteValue;\n        if (CONSUMER_SIDE.equals(invoker.getUrl().getSide())) {\n            // ---- for service consumer ----\n            localPort = 0;\n            remoteKey = PROVIDER;\n            remoteValue = invoker.getUrl().getAddress();\n        } else {\n            // ---- for service provider ----\n            localPort = invoker.getUrl().getPort();\n            remoteKey = CONSUMER;\n            remoteValue = remoteHost;\n        }\n        String input = \"\", output = \"\";\n        if (invocation.getAttachment(INPUT_KEY) != null) {\n            input = invocation.getAttachment(INPUT_KEY);\n        }\n        if (result != null && result.getAttachment(OUTPUT_KEY) != null) {\n            output = result.getAttachment(OUTPUT_KEY);\n        }\n\n        return new ServiceConfigURL(\n                COUNT_PROTOCOL,\n                NetUtils.getLocalHost(),\n                localPort,\n                service + PATH_SEPARATOR + method,\n                APPLICATION_KEY,\n                application,\n                INTERFACE_KEY,\n                service,\n                METHOD_KEY,\n                method,\n                remoteKey,\n                remoteValue,\n                error ? FAILURE_KEY : SUCCESS_KEY,\n                \"1\",\n                ELAPSED_KEY,\n                String.valueOf(elapsed),\n                CONCURRENT_KEY,\n                String.valueOf(concurrent),\n                INPUT_KEY,\n                input,\n                OUTPUT_KEY,\n                output,\n                GROUP_KEY,\n                group,\n                VERSION_KEY,\n                version);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter.support;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.event.RequestEvent;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.rpc.BaseFilter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\n\n@Activate(group = CONSUMER, onClass = \"org.apache.dubbo.metrics.collector.DefaultMetricsCollector\")\npublic class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener, ScopeModelAware {\n\n    private ApplicationModel applicationModel;\n    private DefaultMetricsCollector collector;\n    private String appName;\n    private MetricsDispatcher metricsDispatcher;\n    private boolean serviceLevel;\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        this.collector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);\n        this.appName = applicationModel.tryGetApplicationName();\n        this.metricsDispatcher = applicationModel.getBeanFactory().getBean(MetricsDispatcher.class);\n        this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);\n    }\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        return invoker.invoke(invocation);\n    }\n\n    @Override\n    public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) {\n        handleMethodException(result.getException(), invocation);\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        handleMethodException(t, invocation);\n    }\n\n    private void handleMethodException(Throwable t, Invocation invocation) {\n        if (collector == null || !collector.isCollectEnabled()) {\n            return;\n        }\n        if (t instanceof RpcException) {\n            RpcException e = (RpcException) t;\n            if (e.isForbidden()) {\n                MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(\n                        applicationModel,\n                        appName,\n                        metricsDispatcher,\n                        invocation,\n                        CONSUMER_SIDE,\n                        e.getCode(),\n                        serviceLevel));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar",
    "content": "defaultMetrics=org.apache.dubbo.metrics.aot.DefaultMetricsReflectionTypeDescriberRegistrar\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector",
    "content": "default-collector=org.apache.dubbo.metrics.collector.DefaultMetricsCollector\naggregateMetricsCollector=org.apache.dubbo.metrics.collector.AggregateMetricsCollector\nconfigCenterMetricsCollector=org.apache.dubbo.metrics.collector.ConfigCenterMetricsCollector\nhistogramMetricsCollector=org.apache.dubbo.metrics.collector.HistogramMetricsCollector\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.report.MetricsReporterFactory",
    "content": "default=org.apache.dubbo.metrics.report.DefaultMetricsReporterFactory\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.service.MetricsService",
    "content": "default=org.apache.dubbo.metrics.service.DefaultMetricsService\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter",
    "content": "metrics-provider=org.apache.dubbo.metrics.filter.MetricsProviderFilter\nmonitor=org.apache.dubbo.monitor.support.MonitorFilter\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.ClusterFilter",
    "content": "metricsClusterFilter=org.apache.dubbo.rpc.cluster.filter.support.MetricsClusterFilter\nmonitor=org.apache.dubbo.monitor.support.MonitorClusterFilter\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "dubbo-metrics-init=org.apache.dubbo.metrics.MetricsScopeModelInitializer\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/DefaultMetricsServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.metrics.collector.MetricsCollector;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.service.DefaultMetricsService;\nimport org.apache.dubbo.metrics.service.MetricsEntity;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.mockito.Mockito.when;\n\n@SuppressWarnings(\"rawtypes\")\npublic class DefaultMetricsServiceTest {\n\n    private MetricsCollector metricsCollector;\n\n    private DefaultMetricsService defaultMetricsService;\n\n    @BeforeEach\n    public void setUp() {\n        ApplicationModel applicationModel = Mockito.mock(ApplicationModel.class);\n        ScopeBeanFactory beanFactory = Mockito.mock(ScopeBeanFactory.class);\n        metricsCollector = Mockito.mock(MetricsCollector.class);\n\n        when(applicationModel.getBeanFactory()).thenReturn(beanFactory);\n        when(beanFactory.getBeansOfType(MetricsCollector.class))\n                .thenReturn(Collections.singletonList(metricsCollector));\n\n        defaultMetricsService = new DefaultMetricsService(applicationModel);\n    }\n\n    @Test\n    public void testGetMetricsByCategories() {\n        MetricSample sample = new GaugeMetricSample<>(\n                \"testMetric\", \"testDescription\", null, MetricsCategory.REQUESTS, 42, value -> 42.0);\n        when(metricsCollector.collect()).thenReturn(Collections.singletonList(sample));\n        List<MetricsCategory> categories = Collections.singletonList(MetricsCategory.REQUESTS);\n\n        Map<MetricsCategory, List<MetricsEntity>> result = defaultMetricsService.getMetricsByCategories(categories);\n\n        Assertions.assertNotNull(result);\n        Assertions.assertEquals(1, result.size());\n        List<MetricsEntity> entities = result.get(MetricsCategory.REQUESTS);\n        Assertions.assertNotNull(entities);\n        Assertions.assertEquals(1, entities.size());\n\n        MetricsEntity entity = entities.get(0);\n        Assertions.assertEquals(\"testMetric\", entity.getName());\n        Assertions.assertEquals(42.0, entity.getValue());\n        Assertions.assertEquals(MetricsCategory.REQUESTS, entity.getCategory());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/TestMetricsInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\npublic class TestMetricsInvoker implements Invoker {\n\n    private String side;\n\n    public TestMetricsInvoker(String side) {\n        this.side = side;\n    }\n\n    @Override\n    public Class getInterface() {\n        return null;\n    }\n\n    @Override\n    public Result invoke(Invocation invocation) throws RpcException {\n        return null;\n    }\n\n    @Override\n    public URL getUrl() {\n        return URL.valueOf(\"test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=\" + side);\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return true;\n    }\n\n    @Override\n    public void destroy() {}\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ReflectionUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.nested.AggregationConfig;\nimport org.apache.dubbo.metrics.MetricsConstants;\nimport org.apache.dubbo.metrics.TestMetricsInvoker;\nimport org.apache.dubbo.metrics.aggregate.TimeWindowCounter;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.event.RequestEvent;\nimport org.apache.dubbo.metrics.filter.MetricsFilter;\nimport org.apache.dubbo.metrics.listener.MetricsListener;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.TimePair;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.TypeWrapper;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;\nimport static org.apache.dubbo.metrics.model.MetricsCategory.QPS;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass AggregateMetricsCollectorTest {\n\n    private ApplicationModel applicationModel;\n    private DefaultMetricsCollector defaultCollector;\n    private String interfaceName;\n    private String methodName;\n    private String group;\n    private String version;\n    private RpcInvocation invocation;\n    private String side;\n    private MetricsDispatcher metricsDispatcher;\n    private AggregateMetricsCollector collector;\n    private MetricsFilter metricsFilter;\n\n    public MethodMetric getTestMethodMetric() {\n\n        MethodMetric methodMetric =\n                new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));\n        methodMetric.setGroup(\"TestGroup\");\n        methodMetric.setVersion(\"1.0.0\");\n        methodMetric.setSide(\"PROVIDER\");\n\n        return methodMetric;\n    }\n\n    @BeforeEach\n    public void setup() {\n        applicationModel = ApplicationModel.defaultModel();\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n        applicationModel.getApplicationConfigManager().setApplication(config);\n\n        MetricsConfig metricsConfig = new MetricsConfig();\n        AggregationConfig aggregationConfig = new AggregationConfig();\n        aggregationConfig.setEnabled(true);\n        aggregationConfig.setBucketNum(12);\n        aggregationConfig.setTimeWindowSeconds(120);\n        metricsConfig.setAggregation(aggregationConfig);\n        metricsConfig.setEnableRpc(true);\n        applicationModel.getApplicationConfigManager().setMetrics(metricsConfig);\n        metricsDispatcher = applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);\n        defaultCollector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);\n        collector = applicationModel.getBeanFactory().getOrRegisterBean(AggregateMetricsCollector.class);\n        collector.setCollectEnabled(true);\n\n        defaultCollector = new DefaultMetricsCollector(applicationModel);\n        defaultCollector.setCollectEnabled(true);\n\n        metricsFilter = new MetricsFilter();\n        metricsFilter.setApplicationModel(applicationModel);\n\n        interfaceName = \"org.apache.dubbo.MockInterface\";\n        methodName = \"mockMethod\";\n        group = \"mockGroup\";\n        version = \"1.0.0\";\n        invocation = new RpcInvocation(methodName, interfaceName, \"serviceKey\", null, null);\n        invocation.setTargetServiceUniqueName(group + \"/\" + interfaceName + \":\" + version);\n        invocation.setAttachment(GROUP_KEY, group);\n        invocation.setAttachment(VERSION_KEY, version);\n        side = CommonConstants.CONSUMER;\n        invocation.setInvoker(new TestMetricsInvoker(side));\n        invocation.setTargetServiceUniqueName(group + \"/\" + interfaceName + \":\" + version);\n        RpcContext.getServiceContext()\n                .setUrl(URL.valueOf(\"test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=\" + side));\n    }\n\n    @Test\n    void testListener() {\n        AggregateMetricsCollector metricsCollector = new AggregateMetricsCollector(applicationModel);\n        RequestEvent event = RequestEvent.toRequestEvent(\n                applicationModel,\n                null,\n                null,\n                null,\n                invocation,\n                MetricsSupport.getSide(invocation),\n                MethodMetric.isServiceLevel(applicationModel));\n        RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(\n                applicationModel,\n                null,\n                null,\n                invocation,\n                MetricsSupport.getSide(invocation),\n                RpcException.FORBIDDEN_EXCEPTION,\n                MethodMetric.isServiceLevel(applicationModel));\n\n        Assertions.assertTrue(metricsCollector.isSupport(event));\n        Assertions.assertTrue(metricsCollector.isSupport(beforeEvent));\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    @Test\n    void testRequestsMetrics() {\n        String applicationName = applicationModel.getApplicationName();\n\n        defaultCollector.setApplicationName(applicationName);\n\n        metricsFilter.invoke(new TestMetricsInvoker(side), invocation);\n        try {\n            Thread.sleep(50);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        AppResponse mockRpcResult = new AppResponse();\n        mockRpcResult.setException(new RpcException(RpcException.NETWORK_EXCEPTION));\n        Result result = AsyncRpcResult.newDefaultAsyncResult(mockRpcResult, invocation);\n        metricsFilter.onResponse(result, new TestMetricsInvoker(side), invocation);\n\n        List<MetricSample> samples = collector.collect();\n        for (MetricSample sample : samples) {\n            Map<String, String> tags = sample.getTags();\n\n            Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName);\n            Assertions.assertEquals(tags.get(TAG_METHOD_KEY), methodName);\n            Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);\n            Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);\n        }\n\n        samples = collector.collect();\n\n        @SuppressWarnings(\"rawtypes\")\n        Map<String, Long> sampleMap = samples.stream()\n                .collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));\n\n        Assertions.assertEquals(sampleMap.get(MetricsKey.METRIC_REQUESTS_NETWORK_FAILED_AGG.getNameByType(side)), 1L);\n        Assertions.assertTrue(sampleMap.containsKey(MetricsKey.METRIC_QPS.getNameByType(side)));\n    }\n\n    @Test\n    public void testQPS() {\n        ApplicationModel applicationModel = mock(ApplicationModel.class);\n        ConfigManager configManager = mock(ConfigManager.class);\n        MetricsConfig metricsConfig = mock(MetricsConfig.class);\n        ScopeBeanFactory beanFactory = mock(ScopeBeanFactory.class);\n        AggregationConfig aggregationConfig = mock(AggregationConfig.class);\n\n        when(applicationModel.getApplicationConfigManager()).thenReturn(configManager);\n        when(applicationModel.getBeanFactory()).thenReturn(beanFactory);\n        DefaultMetricsCollector defaultMetricsCollector = new DefaultMetricsCollector(applicationModel);\n        when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(defaultMetricsCollector);\n        when(configManager.getMetrics()).thenReturn(Optional.of(metricsConfig));\n        when(metricsConfig.getAggregation()).thenReturn(aggregationConfig);\n        when(aggregationConfig.getEnabled()).thenReturn(Boolean.TRUE);\n\n        AggregateMetricsCollector collector = new AggregateMetricsCollector(applicationModel);\n\n        MethodMetric methodMetric = getTestMethodMetric();\n\n        TimeWindowCounter qpsCounter = new TimeWindowCounter(10, 120);\n\n        for (int i = 0; i < 10000; i++) {\n            qpsCounter.increment();\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        ConcurrentHashMap<MethodMetric, TimeWindowCounter> qps =\n                (ConcurrentHashMap<MethodMetric, TimeWindowCounter>) ReflectionUtils.getField(collector, \"qps\");\n        qps.put(methodMetric, qpsCounter);\n\n        List<MetricSample> collectedQPS = new ArrayList<>();\n        ReflectionUtils.invoke(collector, \"collectQPS\", collectedQPS);\n\n        Assertions.assertFalse(collectedQPS.isEmpty());\n        Assertions.assertEquals(1, collectedQPS.size());\n\n        MetricSample sample = collectedQPS.get(0);\n        Assertions.assertEquals(MetricsKey.METRIC_QPS.getNameByType(\"PROVIDER\"), sample.getName());\n        Assertions.assertEquals(MetricsKey.METRIC_QPS.getDescription(), sample.getDescription());\n\n        Assertions.assertEquals(QPS, sample.getCategory());\n        Assertions.assertEquals(10000, ((TimeWindowCounter) ((GaugeMetricSample<?>) sample).getValue()).get());\n    }\n\n    @Test\n    public void testRtAggregation() {\n        metricsDispatcher.addListener(collector);\n        ConfigManager configManager = applicationModel.getApplicationConfigManager();\n        MetricsConfig config = configManager.getMetrics().orElse(null);\n        AggregationConfig aggregationConfig = new AggregationConfig();\n        aggregationConfig.setEnabled(true);\n        config.setAggregation(aggregationConfig);\n\n        List<Long> rtList = new ArrayList<>();\n        rtList.add(10L);\n        rtList.add(20L);\n        rtList.add(30L);\n\n        for (Long requestTime : rtList) {\n            RequestEvent requestEvent = RequestEvent.toRequestEvent(\n                    applicationModel,\n                    null,\n                    null,\n                    null,\n                    invocation,\n                    MetricsSupport.getSide(invocation),\n                    MethodMetric.isServiceLevel(applicationModel));\n            TestRequestEvent testRequestEvent =\n                    new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper());\n            testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);\n            testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));\n            testRequestEvent.putAttachment(MetricsConstants.INVOCATION_SIDE, MetricsSupport.getSide(invocation));\n            testRequestEvent.setRt(requestTime);\n            MetricsEventBus.post(testRequestEvent, () -> null);\n        }\n\n        List<MetricSample> samples = collector.collect();\n        for (MetricSample sample : samples) {\n            GaugeMetricSample gaugeMetricSample = (GaugeMetricSample<?>) sample;\n\n            if (gaugeMetricSample.getName().endsWith(\"max.milliseconds.aggregate\")) {\n                Assertions.assertEquals(30, gaugeMetricSample.applyAsDouble());\n            }\n            if (gaugeMetricSample.getName().endsWith(\"min.milliseconds.aggregate\")) {\n                Assertions.assertEquals(10L, gaugeMetricSample.applyAsDouble());\n            }\n\n            if (gaugeMetricSample.getName().endsWith(\"avg.milliseconds.aggregate\")) {\n                Assertions.assertEquals(20L, gaugeMetricSample.applyAsDouble());\n            }\n        }\n    }\n\n    @Test\n    void testP95AndP99() throws InterruptedException {\n\n        metricsDispatcher.addListener(collector);\n        ConfigManager configManager = applicationModel.getApplicationConfigManager();\n        MetricsConfig config = configManager.getMetrics().orElse(null);\n        AggregationConfig aggregationConfig = new AggregationConfig();\n        aggregationConfig.setEnabled(true);\n        config.setAggregation(aggregationConfig);\n\n        List<Long> requestTimes = new ArrayList<>(10000);\n\n        for (int i = 0; i < 300; i++) {\n            requestTimes.add(Double.valueOf(1000 * Math.random()).longValue());\n        }\n\n        Collections.sort(requestTimes);\n        double p95Index = 0.95 * (requestTimes.size() - 1);\n        double p99Index = 0.99 * (requestTimes.size() - 1);\n\n        double manualP95 = requestTimes.get((int) Math.round(p95Index));\n        double manualP99 = requestTimes.get((int) Math.round(p99Index));\n\n        for (Long requestTime : requestTimes) {\n            RequestEvent requestEvent = RequestEvent.toRequestEvent(\n                    applicationModel,\n                    null,\n                    null,\n                    null,\n                    invocation,\n                    MetricsSupport.getSide(invocation),\n                    MethodMetric.isServiceLevel(applicationModel));\n            TestRequestEvent testRequestEvent =\n                    new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper());\n            testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);\n            testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));\n            testRequestEvent.putAttachment(MetricsConstants.INVOCATION_SIDE, MetricsSupport.getSide(invocation));\n            testRequestEvent.setRt(requestTime);\n            MetricsEventBus.post(testRequestEvent, () -> null);\n        }\n        Thread.sleep(4000L);\n\n        List<MetricSample> samples = collector.collect();\n\n        GaugeMetricSample<?> p95Sample = samples.stream()\n                .filter(sample -> sample.getName().endsWith(\"p95\"))\n                .map(sample -> (GaugeMetricSample<?>) sample)\n                .findFirst()\n                .orElse(null);\n\n        GaugeMetricSample<?> p99Sample = samples.stream()\n                .filter(sample -> sample.getName().endsWith(\"p99\"))\n                .map(sample -> (GaugeMetricSample<?>) sample)\n                .findFirst()\n                .orElse(null);\n\n        Assertions.assertNotNull(p95Sample);\n        Assertions.assertNotNull(p99Sample);\n\n        double p95 = p95Sample.applyAsDouble();\n        double p99 = p99Sample.applyAsDouble();\n\n        // An error of less than 5% is allowed\n        Assertions.assertTrue(Math.abs(1 - p95 / manualP95) < 0.05);\n        Assertions.assertTrue(Math.abs(1 - p99 / manualP99) < 0.05);\n    }\n\n    @Test\n    void testGenericCache() {\n        List<Class<?>> classGenerics =\n                ReflectionUtils.getClassGenerics(AggregateMetricsCollector.class, MetricsListener.class);\n        Assertions.assertTrue(CollectionUtils.isNotEmpty(classGenerics));\n        Assertions.assertEquals(RequestEvent.class, classGenerics.get(0));\n    }\n\n    public static class TestRequestEvent extends RequestEvent {\n        private long rt;\n\n        public TestRequestEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) {\n            super(applicationModel, null, null, null, typeWrapper);\n        }\n\n        public void setRt(long rt) {\n            this.rt = rt;\n        }\n\n        @Override\n        public TimePair getTimePair() {\n            return new TestTimePair(rt);\n        }\n    }\n\n    public static class TestTimePair extends TimePair {\n\n        long rt;\n\n        public TestTimePair(long rt) {\n            super(rt);\n            this.rt = rt;\n        }\n\n        @Override\n        public long calc() {\n            return this.rt;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.metrics.TestMetricsInvoker;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.metrics.event.RequestEvent;\nimport org.apache.dubbo.metrics.filter.MetricsFilter;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.ServiceKeyMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\nimport org.apache.dubbo.metrics.model.sample.CounterMetricSample;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.metrics.DefaultConstants.METRIC_FILTER_EVENT;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_PROCESSING;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_SUCCEED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_TIMEOUT;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_TOTAL_FAILED;\n\nclass DefaultCollectorTest {\n\n    private ApplicationModel applicationModel;\n\n    private String interfaceName;\n    private String methodName;\n    private String group;\n    private String version;\n    private RpcInvocation invocation;\n    private String side;\n\n    MetricsDispatcher metricsDispatcher;\n    DefaultMetricsCollector defaultCollector;\n\n    MetricsFilter metricsFilter;\n\n    @BeforeEach\n    public void setup() {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        applicationModel = frameworkModel.newApplication();\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n\n        MetricsConfig metricsConfig = new MetricsConfig();\n        metricsConfig.setEnableRpc(true);\n\n        applicationModel.getApplicationConfigManager().setApplication(config);\n        applicationModel.getApplicationConfigManager().setMetrics(metricsConfig);\n        metricsDispatcher = applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);\n        defaultCollector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);\n        defaultCollector.setCollectEnabled(true);\n\n        interfaceName = \"org.apache.dubbo.MockInterface\";\n        methodName = \"mockMethod\";\n        group = \"mockGroup\";\n        version = \"1.0.0\";\n        invocation = new RpcInvocation(methodName, interfaceName, \"serviceKey\", null, null);\n        invocation.setTargetServiceUniqueName(group + \"/\" + interfaceName + \":\" + version);\n        invocation.setAttachment(GROUP_KEY, group);\n        invocation.setAttachment(VERSION_KEY, version);\n        side = CommonConstants.CONSUMER;\n        invocation.setInvoker(new TestMetricsInvoker(side));\n        invocation.setTargetServiceUniqueName(group + \"/\" + interfaceName + \":\" + version);\n        RpcContext.getServiceContext()\n                .setUrl(URL.valueOf(\"test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=\" + side));\n\n        metricsFilter = new MetricsFilter();\n        metricsFilter.setApplicationModel(applicationModel);\n    }\n\n    @Test\n    void testListener() {\n        DefaultMetricsCollector metricsCollector = new DefaultMetricsCollector(applicationModel);\n        RequestEvent event = RequestEvent.toRequestEvent(\n                applicationModel,\n                null,\n                null,\n                null,\n                invocation,\n                MetricsSupport.getSide(invocation),\n                MethodMetric.isServiceLevel(applicationModel));\n        RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(\n                applicationModel,\n                null,\n                null,\n                invocation,\n                MetricsSupport.getSide(invocation),\n                RpcException.FORBIDDEN_EXCEPTION,\n                MethodMetric.isServiceLevel(applicationModel));\n\n        Assertions.assertTrue(metricsCollector.isSupport(event));\n        Assertions.assertTrue(metricsCollector.isSupport(beforeEvent));\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    /**\n     * No rt metrics because Aggregate calc\n     */\n    @Test\n    void testRequestEventNoRt() {\n\n        applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);\n        DefaultMetricsCollector collector =\n                applicationModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);\n        collector.setCollectEnabled(true);\n\n        ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DefaultCollectorTest.class);\n        logger.warn(\"0-99\", \"\", \"\", \"Test error code message.\");\n\n        metricsFilter.invoke(new TestMetricsInvoker(side), invocation);\n        try {\n            Thread.sleep(50);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        AppResponse mockRpcResult = new AppResponse();\n        //        mockRpcResult.setException(new RpcException(\"hessian\"));\n        Result result = AsyncRpcResult.newDefaultAsyncResult(mockRpcResult, invocation);\n        metricsFilter.onResponse(result, new TestMetricsInvoker(side), invocation);\n\n        RequestEvent eventObj = (RequestEvent) invocation.get(METRIC_FILTER_EVENT);\n        long c1 = eventObj.getTimePair().calc();\n\n        // push finish rt +1\n        List<MetricSample> metricSamples = collector.collect();\n        // num(total+success+processing) + rt(5) + error code = 9\n        Assertions.assertEquals(metricSamples.size(), 9);\n        List<String> metricsNames =\n                metricSamples.stream().map(MetricSample::getName).collect(Collectors.toList());\n        // No error will contain total+success+processing\n        String REQUESTS =\n                new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();\n        String SUCCEED = new MetricsKeyWrapper(\n                        METRIC_REQUESTS_SUCCEED, MetricsPlaceValue.of(side, MetricsLevel.SERVICE))\n                .targetKey();\n        String PROCESSING = new MetricsKeyWrapper(\n                        METRIC_REQUESTS_PROCESSING, MetricsPlaceValue.of(side, MetricsLevel.SERVICE))\n                .targetKey();\n        Assertions.assertTrue(metricsNames.contains(REQUESTS));\n        Assertions.assertTrue(metricsNames.contains(SUCCEED));\n        Assertions.assertTrue(metricsNames.contains(PROCESSING));\n        for (MetricSample metricSample : metricSamples) {\n            if (metricSample instanceof GaugeMetricSample) {\n                GaugeMetricSample<?> gaugeMetricSample = (GaugeMetricSample<?>) metricSample;\n                Object objVal = gaugeMetricSample.getValue();\n                if (objVal instanceof Map) {\n                    Map<ServiceKeyMetric, AtomicLong> value = (Map<ServiceKeyMetric, AtomicLong>) objVal;\n                    if (metricSample.getName().equals(REQUESTS)) {\n                        Assertions.assertTrue(\n                                value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 1));\n                    }\n                    if (metricSample.getName().equals(PROCESSING)) {\n                        Assertions.assertTrue(\n                                value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 0));\n                    }\n                }\n            } else {\n                AtomicLong value = (AtomicLong) ((CounterMetricSample<?>) metricSample).getValue();\n                if (metricSample.getName().equals(SUCCEED)) {\n                    Assertions.assertEquals(1, value.intValue());\n                }\n            }\n        }\n\n        metricsFilter.invoke(new TestMetricsInvoker(side), invocation);\n        try {\n            Thread.sleep(50);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        metricsFilter.onError(\n                new RpcException(RpcException.TIMEOUT_EXCEPTION, \"timeout\"), new TestMetricsInvoker(side), invocation);\n        eventObj = (RequestEvent) invocation.get(METRIC_FILTER_EVENT);\n        long c2 = eventObj.getTimePair().calc();\n        metricSamples = collector.collect();\n\n        // num(total+success+error+total_error+processing) + rt(5) + error code = 11\n        Assertions.assertEquals(11, metricSamples.size());\n\n        String TIMEOUT = new MetricsKeyWrapper(\n                        METRIC_REQUESTS_TIMEOUT, MetricsPlaceValue.of(side, MetricsLevel.SERVICE))\n                .targetKey();\n        String TOTAL_FAILED = new MetricsKeyWrapper(\n                        METRIC_REQUESTS_TOTAL_FAILED, MetricsPlaceValue.of(side, MetricsLevel.SERVICE))\n                .targetKey();\n        for (MetricSample metricSample : metricSamples) {\n            if (metricSample instanceof GaugeMetricSample) {\n                GaugeMetricSample<?> gaugeMetricSample = (GaugeMetricSample<?>) metricSample;\n                Object objVal = gaugeMetricSample.getValue();\n                if (objVal instanceof Map) {\n                    Map<ServiceKeyMetric, AtomicLong> value =\n                            (Map<ServiceKeyMetric, AtomicLong>) ((GaugeMetricSample<?>) metricSample).getValue();\n                    if (metricSample.getName().equals(REQUESTS)) {\n                        Assertions.assertTrue(\n                                value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 2));\n                    }\n                    if (metricSample.getName().equals(REQUESTS)) {\n                        Assertions.assertTrue(\n                                value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 2));\n                    }\n                    if (metricSample.getName().equals(PROCESSING)) {\n                        Assertions.assertTrue(\n                                value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 0));\n                    }\n                    if (metricSample.getName().equals(TIMEOUT)) {\n                        Assertions.assertTrue(\n                                value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 1));\n                    }\n                    if (metricSample.getName().equals(TOTAL_FAILED)) {\n                        Assertions.assertTrue(\n                                value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 1));\n                    }\n                }\n            } else {\n                AtomicLong value = (AtomicLong) ((CounterMetricSample<?>) metricSample).getValue();\n                if (metricSample.getName().equals(SUCCEED)) {\n                    Assertions.assertEquals(1, value.intValue());\n                }\n            }\n        }\n\n        // calc rt\n        for (MetricSample sample : metricSamples) {\n            Map<String, String> tags = sample.getTags();\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());\n        }\n\n        Map<String, Long> sampleMap = metricSamples.stream()\n                .filter(metricSample -> metricSample instanceof GaugeMetricSample)\n                .collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));\n\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(\n                                MetricsKey.METRIC_RT_LAST, MetricsPlaceValue.of(side, MetricsLevel.SERVICE))\n                        .targetKey()),\n                c2);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(\n                                MetricsKey.METRIC_RT_MIN, MetricsPlaceValue.of(side, MetricsLevel.SERVICE))\n                        .targetKey()),\n                Math.min(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(\n                                MetricsKey.METRIC_RT_MAX, MetricsPlaceValue.of(side, MetricsLevel.SERVICE))\n                        .targetKey()),\n                Math.max(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(\n                                MetricsKey.METRIC_RT_AVG, MetricsPlaceValue.of(side, MetricsLevel.SERVICE))\n                        .targetKey()),\n                (c1 + c2) / 2);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(\n                                MetricsKey.METRIC_RT_SUM, MetricsPlaceValue.of(side, MetricsLevel.SERVICE))\n                        .targetKey()),\n                c1 + c2);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/InitServiceMetricsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.nested.AggregationConfig;\nimport org.apache.dubbo.metrics.aggregate.TimeWindowCounter;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.event.MetricsInitEvent;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.ServiceKeyMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\nimport org.apache.dubbo.metrics.model.sample.CounterMetricSample;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metrics.DefaultConstants.INIT_AGG_METHOD_KEYS;\nimport static org.apache.dubbo.metrics.DefaultConstants.INIT_DEFAULT_METHOD_KEYS;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUESTS_PROCESSING;\n\nclass InitServiceMetricsTest {\n\n    private ApplicationModel applicationModel;\n\n    private String interfaceName;\n    private String methodName;\n    private String group;\n    private String version;\n\n    private String side;\n\n    private DefaultMetricsCollector defaultCollector;\n\n    private AggregateMetricsCollector aggregateMetricsCollector;\n\n    @BeforeEach\n    public void setup() {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        applicationModel = frameworkModel.newApplication();\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n\n        MetricsConfig metricsConfig = new MetricsConfig();\n        AggregationConfig aggregationConfig = new AggregationConfig();\n        aggregationConfig.setEnabled(true);\n        aggregationConfig.setBucketNum(12);\n        aggregationConfig.setTimeWindowSeconds(120);\n        metricsConfig.setAggregation(aggregationConfig);\n\n        applicationModel.getApplicationConfigManager().setMetrics(metricsConfig);\n        applicationModel.getApplicationConfigManager().setApplication(config);\n\n        defaultCollector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);\n        defaultCollector.setCollectEnabled(true);\n\n        aggregateMetricsCollector =\n                applicationModel.getBeanFactory().getOrRegisterBean(AggregateMetricsCollector.class);\n        aggregateMetricsCollector.setCollectEnabled(true);\n\n        interfaceName = \"org.apache.dubbo.MockInterface\";\n        methodName = \"mockMethod\";\n        group = \"mockGroup\";\n        version = \"1.0.0\";\n        side = CommonConstants.PROVIDER_SIDE;\n\n        String serviceKey = group + \"/\" + interfaceName + \":\" + version;\n\n        String protocolServiceKey = serviceKey + \":dubbo\";\n\n        RpcInvocation invocation = new RpcInvocation(\n                serviceKey, null, methodName, interfaceName, protocolServiceKey, null, null, null, null, null, null);\n        MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(\n                applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel)));\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    @Test\n    void testMetricsInitEvent() {\n\n        List<MetricSample> metricSamples = defaultCollector.collect();\n        // INIT_DEFAULT_METHOD_KEYS.size() = 6\n        Assertions.assertEquals(INIT_DEFAULT_METHOD_KEYS.size(), metricSamples.size());\n        List<String> metricsNames =\n                metricSamples.stream().map(MetricSample::getName).collect(Collectors.toList());\n\n        String REQUESTS =\n                new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();\n        String PROCESSING = new MetricsKeyWrapper(\n                        METRIC_REQUESTS_PROCESSING, MetricsPlaceValue.of(side, MetricsLevel.SERVICE))\n                .targetKey();\n        Assertions.assertTrue(metricsNames.contains(REQUESTS));\n        Assertions.assertTrue(metricsNames.contains(PROCESSING));\n        for (MetricSample metricSample : metricSamples) {\n            if (metricSample instanceof GaugeMetricSample) {\n                GaugeMetricSample<?> gaugeMetricSample = (GaugeMetricSample<?>) metricSample;\n                Object objVal = gaugeMetricSample.getValue();\n                if (objVal instanceof Map) {\n                    Map<ServiceKeyMetric, AtomicLong> value = (Map<ServiceKeyMetric, AtomicLong>) objVal;\n                    Assertions.assertTrue(value.values().stream().allMatch(atomicLong -> atomicLong.intValue() == 0));\n                }\n            } else {\n                AtomicLong value = (AtomicLong) ((CounterMetricSample<?>) metricSample).getValue();\n                Assertions.assertEquals(0, value.intValue());\n            }\n        }\n\n        List<MetricSample> samples = aggregateMetricsCollector.collect();\n        // INIT_AGG_METHOD_KEYS.size(10) + qps(1) + rt(4) +rtAgr(3)= 18\n        Assertions.assertEquals(INIT_AGG_METHOD_KEYS.size() + 1 + 4 + 3, samples.size());\n\n        for (MetricSample metricSample : samples) {\n            if (metricSample instanceof GaugeMetricSample) {\n                GaugeMetricSample<?> gaugeMetricSample = (GaugeMetricSample<?>) metricSample;\n                Object objVal = gaugeMetricSample.getValue();\n                if (objVal instanceof TimeWindowCounter) {\n                    Assertions.assertEquals(0.0, ((TimeWindowCounter) objVal).get());\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/sample/ThreadPoolMetricsSamplerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.collector.sample;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.store.DataStore;\nimport org.apache.dubbo.common.store.DataStoreUpdateListener;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.model.ThreadPoolMetric;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_SERVICE_COMPONENT_KEY;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@SuppressWarnings(\"all\")\npublic class ThreadPoolMetricsSamplerTest {\n\n    ThreadPoolMetricsSampler sampler;\n\n    @BeforeEach\n    void setUp() {\n        DefaultMetricsCollector collector = new DefaultMetricsCollector(applicationModel);\n        sampler = new ThreadPoolMetricsSampler(collector);\n    }\n\n    @Test\n    void testSample() {\n\n        ExecutorService executorService = java.util.concurrent.Executors.newFixedThreadPool(5);\n        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;\n        sampler.addExecutors(\"testPool\", executorService);\n\n        List<MetricSample> metricSamples = sampler.sample();\n\n        Assertions.assertEquals(6, metricSamples.size());\n\n        boolean coreSizeFound = false;\n        boolean maxSizeFound = false;\n        boolean activeSizeFound = false;\n        boolean threadCountFound = false;\n        boolean queueSizeFound = false;\n        boolean largestSizeFound = false;\n\n        for (MetricSample sample : metricSamples) {\n            ThreadPoolMetric threadPoolMetric = ((ThreadPoolMetric) ((GaugeMetricSample) sample).getValue());\n            switch (sample.getName()) {\n                case \"dubbo.thread.pool.core.size\":\n                    coreSizeFound = true;\n                    Assertions.assertEquals(5, threadPoolMetric.getCorePoolSize());\n                    break;\n                case \"dubbo.thread.pool.largest.size\":\n                    largestSizeFound = true;\n                    Assertions.assertEquals(0, threadPoolMetric.getLargestPoolSize());\n                    break;\n                case \"dubbo.thread.pool.max.size\":\n                    maxSizeFound = true;\n                    Assertions.assertEquals(5, threadPoolMetric.getMaximumPoolSize());\n                    break;\n                case \"dubbo.thread.pool.active.size\":\n                    activeSizeFound = true;\n                    Assertions.assertEquals(0, threadPoolMetric.getActiveCount());\n                    break;\n                case \"dubbo.thread.pool.thread.count\":\n                    threadCountFound = true;\n                    Assertions.assertEquals(0, threadPoolMetric.getPoolSize());\n                    break;\n                case \"dubbo.thread.pool.queue.size\":\n                    queueSizeFound = true;\n                    Assertions.assertEquals(0, threadPoolMetric.getQueueSize());\n                    break;\n            }\n        }\n\n        Assertions.assertTrue(coreSizeFound);\n        Assertions.assertTrue(maxSizeFound);\n        Assertions.assertTrue(activeSizeFound);\n        Assertions.assertTrue(threadCountFound);\n        Assertions.assertTrue(queueSizeFound);\n        Assertions.assertTrue(largestSizeFound);\n\n        executorService.shutdown();\n    }\n\n    private DefaultMetricsCollector collector;\n\n    private ThreadPoolMetricsSampler sampler2;\n\n    @Mock\n    private ApplicationModel applicationModel;\n\n    @Mock\n    ScopeBeanFactory scopeBeanFactory;\n\n    @Mock\n    private DataStore dataStore;\n\n    @Mock\n    private FrameworkExecutorRepository frameworkExecutorRepository;\n\n    @Mock\n    private ExtensionLoader<DataStore> extensionLoader;\n\n    @BeforeEach\n    public void setUp2() {\n        MockitoAnnotations.openMocks(this);\n\n        collector = new DefaultMetricsCollector(applicationModel);\n        sampler2 = new ThreadPoolMetricsSampler(collector);\n\n        when(scopeBeanFactory.getBean(FrameworkExecutorRepository.class)).thenReturn(new FrameworkExecutorRepository());\n\n        collector.collectApplication();\n        when(applicationModel.getBeanFactory()).thenReturn(scopeBeanFactory);\n        when(applicationModel.getExtensionLoader(DataStore.class)).thenReturn(extensionLoader);\n        when(extensionLoader.getDefaultExtension()).thenReturn(dataStore);\n    }\n\n    @Test\n    public void testRegistryDefaultSampleThreadPoolExecutor() throws NoSuchFieldException, IllegalAccessException {\n\n        Map<String, Object> serverExecutors = new HashMap<>();\n        Map<String, Object> clientExecutors = new HashMap<>();\n\n        ExecutorService serverExecutor = Executors.newFixedThreadPool(5);\n        ExecutorService clientExecutor = Executors.newFixedThreadPool(5);\n\n        serverExecutors.put(\"server1\", serverExecutor);\n        clientExecutors.put(\"client1\", clientExecutor);\n\n        when(dataStore.get(EXECUTOR_SERVICE_COMPONENT_KEY)).thenReturn(serverExecutors);\n        when(dataStore.get(CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY)).thenReturn(clientExecutors);\n\n        when(frameworkExecutorRepository.getSharedExecutor()).thenReturn(Executors.newFixedThreadPool(5));\n\n        sampler2.registryDefaultSampleThreadPoolExecutor();\n\n        Field f = ThreadPoolMetricsSampler.class.getDeclaredField(\"sampleThreadPoolExecutor\");\n        f.setAccessible(true);\n        Map<String, ThreadPoolExecutor> executors = (Map<String, ThreadPoolExecutor>) f.get(sampler2);\n\n        Assertions.assertEquals(8, executors.size());\n        Assertions.assertTrue(executors.containsKey(\"DubboServerHandler-server1\"));\n        Assertions.assertTrue(executors.containsKey(\"DubboClientHandler-client1\"));\n        Assertions.assertTrue(executors.containsKey(\"sharedExecutor\"));\n\n        serverExecutor.shutdown();\n        clientExecutor.shutdown();\n    }\n\n    @Test\n    void testDataSourceNotify() throws Exception {\n        ArgumentCaptor<DataStoreUpdateListener> captor = ArgumentCaptor.forClass(DataStoreUpdateListener.class);\n        when(scopeBeanFactory.getBean(FrameworkExecutorRepository.class)).thenReturn(frameworkExecutorRepository);\n        when(frameworkExecutorRepository.getSharedExecutor()).thenReturn(null);\n        sampler2.registryDefaultSampleThreadPoolExecutor();\n\n        Field f = ThreadPoolMetricsSampler.class.getDeclaredField(\"sampleThreadPoolExecutor\");\n        f.setAccessible(true);\n        Map<String, ThreadPoolExecutor> executors = (Map<String, ThreadPoolExecutor>) f.get(sampler2);\n\n        Assertions.assertEquals(0, executors.size());\n\n        verify(dataStore).addListener(captor.capture());\n        Assertions.assertEquals(sampler2, captor.getValue());\n\n        ExecutorService executorService = Executors.newFixedThreadPool(5);\n        sampler2.onUpdate(EXECUTOR_SERVICE_COMPONENT_KEY, \"20880\", executorService);\n\n        executors = (Map<String, ThreadPoolExecutor>) f.get(sampler2);\n        Assertions.assertEquals(1, executors.size());\n        Assertions.assertTrue(executors.containsKey(\"DubboServerHandler-20880\"));\n\n        sampler2.onUpdate(CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY, \"client\", executorService);\n        Assertions.assertEquals(2, executors.size());\n        Assertions.assertTrue(executors.containsKey(\"DubboClientHandler-client\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/filter/MetricsFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.filter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.metrics.TestMetricsInvoker;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.event.RequestEvent;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\nimport org.apache.dubbo.metrics.model.sample.CounterMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.$INVOKE;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_PARAMETER_DESC;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;\nimport static org.apache.dubbo.metrics.DefaultConstants.METRIC_FILTER_EVENT;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\nclass MetricsFilterTest {\n\n    private ApplicationModel applicationModel;\n    private MetricsFilter filter;\n    private DefaultMetricsCollector collector;\n    private RpcInvocation invocation;\n    private final Invoker<?> invoker = mock(Invoker.class);\n\n    private static final String INTERFACE_NAME = \"org.apache.dubbo.MockInterface\";\n    private static final String METHOD_NAME = \"mockMethod\";\n    private static final String GROUP = \"mockGroup\";\n    private static final String VERSION = \"1.0.0_BETA\";\n    private String side;\n\n    private AtomicBoolean initApplication = new AtomicBoolean(false);\n\n    @BeforeEach\n    public void setup() {\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n        applicationModel = ApplicationModel.defaultModel();\n        MetricsConfig metricsConfig = new MetricsConfig();\n        metricsConfig.setEnableRpc(true);\n        applicationModel.getApplicationConfigManager().setApplication(config);\n        applicationModel.getApplicationConfigManager().setMetrics(metricsConfig);\n        invocation = new RpcInvocation();\n        filter = new MetricsFilter();\n\n        collector = applicationModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);\n        if (!initApplication.get()) {\n            collector.collectApplication();\n            initApplication.set(true);\n        }\n        filter.setApplicationModel(applicationModel);\n        side = CommonConstants.CONSUMER;\n        invocation.setInvoker(new TestMetricsInvoker(side));\n        RpcContext.getServiceContext()\n                .setUrl(URL.valueOf(\"test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=\" + side));\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    @Test\n    void testCollectDisabled() {\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n\n        filter.invoke(invoker, invocation);\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n        metricsMap.remove(MetricsKey.APPLICATION_METRIC_INFO.getName());\n        Assertions.assertTrue(metricsMap.isEmpty());\n    }\n\n    @Test\n    void testUnknownFailedRequests() {\n        collector.setCollectEnabled(true);\n        given(invoker.invoke(invocation)).willThrow(new RpcException(\"failed\"));\n        initParam();\n\n        try {\n            filter.invoke(invoker, invocation);\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof RpcException);\n            filter.onError(e, invoker, invocation);\n        }\n\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n        Assertions.assertTrue(metricsMap.containsKey(MetricsKey.METRIC_REQUESTS_FAILED.getNameByType(side)));\n        Assertions.assertFalse(metricsMap.containsKey(MetricsKey.METRIC_REQUESTS_SUCCEED.getNameByType(side)));\n\n        MetricSample sample = metricsMap.get(MetricsKey.METRIC_REQUESTS_FAILED.getNameByType(side));\n        Map<String, String> tags = sample.getTags();\n\n        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), INTERFACE_NAME);\n        Assertions.assertEquals(tags.get(TAG_METHOD_KEY), METHOD_NAME);\n        Assertions.assertEquals(tags.get(TAG_GROUP_KEY), GROUP);\n        Assertions.assertEquals(tags.get(TAG_VERSION_KEY), VERSION);\n    }\n\n    @Test\n    void testBusinessFailedRequests() {\n        collector.setCollectEnabled(true);\n\n        given(invoker.invoke(invocation)).willThrow(new RpcException(RpcException.BIZ_EXCEPTION));\n        initParam();\n\n        try {\n            filter.invoke(invoker, invocation);\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof RpcException);\n            filter.onError(e, invoker, invocation);\n        }\n\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n        Assertions.assertTrue(metricsMap.containsKey(MetricsKey.METRIC_REQUEST_BUSINESS_FAILED.getNameByType(side)));\n        Assertions.assertFalse(metricsMap.containsKey(MetricsKey.METRIC_REQUESTS_SUCCEED.getNameByType(side)));\n\n        MetricSample sample = metricsMap.get(MetricsKey.METRIC_REQUEST_BUSINESS_FAILED.getNameByType(side));\n\n        Map<String, String> tags = sample.getTags();\n\n        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), INTERFACE_NAME);\n        Assertions.assertEquals(tags.get(TAG_METHOD_KEY), METHOD_NAME);\n        Assertions.assertEquals(tags.get(TAG_GROUP_KEY), GROUP);\n        Assertions.assertEquals(tags.get(TAG_VERSION_KEY), VERSION);\n    }\n\n    @Test\n    void testTimeoutRequests() {\n        collector.setCollectEnabled(true);\n\n        given(invoker.invoke(invocation)).willThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION));\n        initParam();\n\n        Long count = 2L;\n\n        for (int i = 0; i < count; i++) {\n            try {\n                filter.invoke(invoker, invocation);\n            } catch (Exception e) {\n                Assertions.assertTrue(e instanceof RpcException);\n                filter.onError(e, invoker, invocation);\n            }\n        }\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n        Assertions.assertTrue(metricsMap.containsKey(MetricsKey.METRIC_REQUESTS_TIMEOUT.getNameByType(side)));\n        Assertions.assertTrue(metricsMap.containsKey(MetricsKey.METRIC_REQUESTS_TOTAL_FAILED.getNameByType(side)));\n\n        MetricSample timeoutSample = metricsMap.get(MetricsKey.METRIC_REQUESTS_TIMEOUT.getNameByType(side));\n        Assertions.assertSame(((CounterMetricSample) timeoutSample).getValue().longValue(), count);\n\n        CounterMetricSample failedSample =\n                (CounterMetricSample) metricsMap.get(MetricsKey.METRIC_REQUESTS_TOTAL_FAILED.getNameByType(side));\n        Assertions.assertSame(failedSample.getValue().longValue(), count);\n    }\n\n    @Test\n    void testLimitRequests() {\n        collector.setCollectEnabled(true);\n\n        given(invoker.invoke(invocation)).willThrow(new RpcException(RpcException.LIMIT_EXCEEDED_EXCEPTION));\n        initParam();\n\n        Long count = 3L;\n\n        for (int i = 0; i < count; i++) {\n            try {\n                filter.invoke(invoker, invocation);\n            } catch (Exception e) {\n                Assertions.assertTrue(e instanceof RpcException);\n                filter.onError(e, invoker, invocation);\n            }\n        }\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n        Assertions.assertTrue(metricsMap.containsKey(MetricsKey.METRIC_REQUESTS_LIMIT.getNameByType(side)));\n\n        MetricSample sample = metricsMap.get(MetricsKey.METRIC_REQUESTS_LIMIT.getNameByType(side));\n\n        Assertions.assertSame(((CounterMetricSample) sample).getValue().longValue(), count);\n    }\n\n    @Test\n    void testSucceedRequests() {\n        collector.setCollectEnabled(true);\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n        initParam();\n\n        Result result = filter.invoke(invoker, invocation);\n\n        filter.onResponse(result, invoker, invocation);\n\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n        Assertions.assertFalse(metricsMap.containsKey(MetricsKey.METRIC_REQUEST_BUSINESS_FAILED.getNameByType(side)));\n        Assertions.assertTrue(metricsMap.containsKey(MetricsKey.METRIC_REQUESTS_SUCCEED.getNameByType(side)));\n\n        MetricSample sample = metricsMap.get(MetricsKey.METRIC_REQUESTS_SUCCEED.getNameByType(side));\n        Map<String, String> tags = sample.getTags();\n\n        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), INTERFACE_NAME);\n        Assertions.assertEquals(tags.get(TAG_METHOD_KEY), METHOD_NAME);\n        Assertions.assertEquals(tags.get(TAG_GROUP_KEY), GROUP);\n        Assertions.assertEquals(tags.get(TAG_VERSION_KEY), VERSION);\n    }\n\n    @Test\n    void testMissingGroup() {\n        collector.setCollectEnabled(true);\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n        invocation.setTargetServiceUniqueName(INTERFACE_NAME + \":\" + VERSION);\n        invocation.setMethodName(METHOD_NAME);\n        invocation.setParameterTypes(new Class[] {String.class});\n\n        Result result = filter.invoke(invoker, invocation);\n\n        filter.onResponse(result, invoker, invocation);\n\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n\n        MetricSample sample = metricsMap.get(MetricsKey.METRIC_REQUESTS_SUCCEED.getNameByType(side));\n        Map<String, String> tags = sample.getTags();\n\n        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), INTERFACE_NAME);\n        Assertions.assertEquals(tags.get(TAG_METHOD_KEY), METHOD_NAME);\n        Assertions.assertNull(tags.get(TAG_GROUP_KEY));\n        Assertions.assertEquals(tags.get(TAG_VERSION_KEY), VERSION);\n    }\n\n    @Test\n    public void testErrors() {\n        testFilterError(RpcException.SERIALIZATION_EXCEPTION, MetricsKey.METRIC_REQUESTS_CODEC_FAILED);\n        testFilterError(RpcException.NETWORK_EXCEPTION, MetricsKey.METRIC_REQUESTS_NETWORK_FAILED);\n    }\n\n    private void testFilterError(int errorCode, MetricsKey metricsKey) {\n        String targetKey =\n                new MetricsKeyWrapper(metricsKey, MetricsPlaceValue.of(side, MetricsLevel.METHOD)).targetKey();\n        setup();\n        collector.setCollectEnabled(true);\n        given(invoker.invoke(invocation)).willThrow(new RpcException(errorCode));\n        initParam();\n\n        Long count = 1L;\n\n        for (int i = 0; i < count; i++) {\n            try {\n                filter.invoke(invoker, invocation);\n            } catch (Exception e) {\n                Assertions.assertTrue(e instanceof RpcException);\n                filter.onError(e, invoker, invocation);\n            }\n        }\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n        Assertions.assertFalse(metricsMap.containsKey(metricsKey.getName()));\n\n        MetricSample sample = metricsMap.get(targetKey);\n\n        Assertions.assertSame(((CounterMetricSample<?>) sample).getValue().longValue(), count);\n\n        Assertions.assertFalse(metricsMap.containsKey(metricsKey.getName()));\n        Map<String, String> tags = sample.getTags();\n\n        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), INTERFACE_NAME);\n        Assertions.assertEquals(tags.get(TAG_METHOD_KEY), METHOD_NAME);\n        Assertions.assertEquals(tags.get(TAG_GROUP_KEY), GROUP);\n        Assertions.assertEquals(tags.get(TAG_VERSION_KEY), VERSION);\n\n        teardown();\n    }\n\n    @Test\n    void testMissingVersion() {\n        collector.setCollectEnabled(true);\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n        invocation.setTargetServiceUniqueName(GROUP + \"/\" + INTERFACE_NAME);\n        invocation.setMethodName(METHOD_NAME);\n        invocation.setParameterTypes(new Class[] {String.class});\n\n        Result result = filter.invoke(invoker, invocation);\n\n        filter.onResponse(result, invoker, invocation);\n\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n\n        MetricSample sample = metricsMap.get(MetricsKey.METRIC_REQUESTS_SUCCEED.getNameByType(side));\n        Map<String, String> tags = sample.getTags();\n\n        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), INTERFACE_NAME);\n        Assertions.assertEquals(tags.get(TAG_METHOD_KEY), METHOD_NAME);\n        Assertions.assertEquals(tags.get(TAG_GROUP_KEY), GROUP);\n        Assertions.assertNull(tags.get(TAG_VERSION_KEY));\n    }\n\n    @Test\n    void testMissingGroupAndVersion() {\n        collector.setCollectEnabled(true);\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n        invocation.setTargetServiceUniqueName(INTERFACE_NAME);\n        invocation.setMethodName(METHOD_NAME);\n        invocation.setParameterTypes(new Class[] {String.class});\n\n        Result result = filter.invoke(invoker, invocation);\n\n        filter.onResponse(result, invoker, invocation);\n\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n\n        MetricSample sample = metricsMap.get(MetricsKey.METRIC_REQUESTS_SUCCEED.getNameByType(side));\n        Map<String, String> tags = sample.getTags();\n\n        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), INTERFACE_NAME);\n        Assertions.assertEquals(tags.get(TAG_METHOD_KEY), METHOD_NAME);\n        Assertions.assertNull(tags.get(TAG_GROUP_KEY));\n        Assertions.assertNull(tags.get(TAG_VERSION_KEY));\n    }\n\n    @Test\n    void testGenericCall() {\n        collector.setCollectEnabled(true);\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n        invocation.setTargetServiceUniqueName(INTERFACE_NAME);\n        invocation.setMethodName(METHOD_NAME);\n        invocation.setParameterTypes(new Class[] {String.class});\n\n        Result result = filter.invoke(invoker, invocation);\n\n        invocation.setMethodName($INVOKE);\n        invocation.setParameterTypesDesc(GENERIC_PARAMETER_DESC);\n        invocation.setArguments(new Object[] {METHOD_NAME, new String[] {\"java.lang.String\"}, new Object[] {\"mock\"}});\n\n        filter.onResponse(result, invoker, invocation);\n\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n\n        MetricSample sample = metricsMap.get(MetricsKey.METRIC_REQUESTS_PROCESSING.getNameByType(side));\n        Map<String, String> tags = sample.getTags();\n\n        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), INTERFACE_NAME);\n        Assertions.assertEquals(tags.get(TAG_METHOD_KEY), METHOD_NAME);\n    }\n\n    private void initParam() {\n        invocation.setTargetServiceUniqueName(GROUP + \"/\" + INTERFACE_NAME + \":\" + VERSION);\n        invocation.setMethodName(METHOD_NAME);\n        invocation.setParameterTypes(new Class[] {String.class});\n    }\n\n    private Map<String, MetricSample> getMetricsMap() {\n        List<MetricSample> samples = collector.collect();\n        List<MetricSample> samples1 = new ArrayList<>();\n        for (MetricSample sample : samples) {\n            if (sample.getName().contains(\"dubbo.thread.pool\")) {\n                continue;\n            }\n            samples1.add(sample);\n        }\n        return samples1.stream().collect(Collectors.toMap(MetricSample::getName, Function.identity()));\n    }\n\n    @Test\n    void testThrowable() {\n        invocation.setTargetServiceUniqueName(INTERFACE_NAME);\n        invocation.setMethodName(METHOD_NAME);\n        invocation.setParameterTypes(new Class[] {String.class});\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n        Result result = filter.invoke(invoker, invocation);\n        result.setException(new RuntimeException(\"failed\"));\n        Object eventObj = invocation.get(METRIC_FILTER_EVENT);\n        if (eventObj != null) {\n            Assertions.assertDoesNotThrow(() -> MetricsEventBus.after((RequestEvent) eventObj, result));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/MethodMetricTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metrics.model;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.metrics.model.MethodMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;\n\nclass MethodMetricTest {\n\n    private static ApplicationModel applicationModel;\n    private static String interfaceName;\n    private static String methodName;\n    private static String group;\n    private static String version;\n    private static RpcInvocation invocation;\n\n    @BeforeAll\n    public static void setup() {\n\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n        applicationModel = ApplicationModel.defaultModel();\n        applicationModel.getApplicationConfigManager().setApplication(config);\n\n        interfaceName = \"org.apache.dubbo.MockInterface\";\n        methodName = \"mockMethod\";\n        group = \"mockGroup\";\n        version = \"1.0.0\";\n        invocation = new RpcInvocation(methodName, interfaceName, \"serviceKey\", null, null);\n\n        invocation.setTargetServiceUniqueName(group + \"/\" + interfaceName + \":\" + version);\n        invocation.setAttachment(GROUP_KEY, group);\n        invocation.setAttachment(VERSION_KEY, version);\n        RpcContext.getServiceContext()\n                .setUrl(URL.valueOf(\"test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=consumer\"));\n    }\n\n    @AfterAll\n    public static void destroy() {\n        ApplicationModel.defaultModel().destroy();\n    }\n\n    @Test\n    void test() {\n        MethodMetric metric =\n                new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));\n        Assertions.assertEquals(metric.getServiceKey(), interfaceName);\n        Assertions.assertEquals(metric.getMethodName(), methodName);\n        Assertions.assertEquals(metric.getGroup(), group);\n        Assertions.assertEquals(metric.getVersion(), version);\n\n        Map<String, String> tags = metric.getTags();\n        Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());\n\n        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName);\n        Assertions.assertEquals(tags.get(TAG_METHOD_KEY), methodName);\n        Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);\n        Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);\n    }\n\n    @Test\n    void testServiceMetrics() {\n        MetricsConfig metricConfig = new MetricsConfig();\n        applicationModel.getApplicationConfigManager().setMetrics(metricConfig);\n        metricConfig.setRpcLevel(MetricsLevel.SERVICE.name());\n        MethodMetric metric =\n                new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));\n        Assertions.assertEquals(metric.getServiceKey(), interfaceName);\n        Assertions.assertNull(metric.getMethodName(), methodName);\n        Assertions.assertEquals(metric.getGroup(), group);\n        Assertions.assertEquals(metric.getVersion(), version);\n\n        Map<String, String> tags = metric.getTags();\n        Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());\n\n        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName);\n        Assertions.assertNull(tags.get(TAG_METHOD_KEY));\n        Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);\n        Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/sample/ErrorCodeSampleTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metrics.model.sample;\n\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.ReflectionUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.collector.sample.ErrorCodeMetricsListenRegister;\nimport org.apache.dubbo.metrics.collector.sample.ErrorCodeSampler;\nimport org.apache.dubbo.metrics.model.sample.CounterMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\npublic class ErrorCodeSampleTest {\n\n    @Test\n    void testErrorCodeMetric() {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"MyApplication1\");\n\n        applicationModel.getApplicationConfigManager().setApplication(applicationConfig);\n\n        DefaultMetricsCollector defaultMetricsCollector = new DefaultMetricsCollector(applicationModel);\n        defaultMetricsCollector.setCollectEnabled(true);\n\n        ErrorCodeSampler sampler =\n                (ErrorCodeSampler) ReflectionUtils.getField(defaultMetricsCollector, \"errorCodeSampler\");\n\n        ErrorCodeMetricsListenRegister register =\n                (ErrorCodeMetricsListenRegister) ReflectionUtils.getField(sampler, \"register\");\n\n        register.onMessage(\"0-1\", null);\n        register.onMessage(\"0-1\", null);\n        register.onMessage(\"0-2\", null);\n        register.onMessage(\"0-2\", null);\n        register.onMessage(\"1-2\", null);\n        register.onMessage(\"1-2\", null);\n        register.onMessage(\"1-3\", null);\n        register.onMessage(\"1-3\", null);\n\n        List<MetricSample> samples = defaultMetricsCollector.collect();\n\n        Assert.assertTrue(samples.size() == 4, \"Wrong number of samples.\");\n        samples.forEach(metricSample -> Assert.assertTrue(\n                ((AtomicLong) ((CounterMetricSample<?>) metricSample).getValue()).get() == 2L, \"Sample count error.\"));\n    }\n\n    @AfterEach\n    public void tearDown() {\n        FrameworkModel.defaultModel().destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/sample/GaugeMetricSampleTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metrics.model.sample;\n\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.function.ToDoubleFunction;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nclass GaugeMetricSampleTest {\n\n    private static String name;\n    private static String description;\n    private static Map<String, String> tags;\n    private static MetricsCategory category;\n    private static String baseUnit;\n    private static AtomicLong value;\n    private static ToDoubleFunction<AtomicLong> apply;\n\n    @BeforeAll\n    public static void setup() {\n        name = \"test\";\n        description = \"test\";\n        tags = new HashMap<>();\n        category = MetricsCategory.REQUESTS;\n        baseUnit = \"byte\";\n        value = new AtomicLong(1);\n        apply = AtomicLong::longValue;\n    }\n\n    @Test\n    void test() {\n        GaugeMetricSample<?> sample =\n                new GaugeMetricSample<>(name, description, tags, category, baseUnit, value, apply);\n        Assertions.assertEquals(sample.getName(), name);\n        Assertions.assertEquals(sample.getDescription(), description);\n        Assertions.assertEquals(sample.getTags(), tags);\n        Assertions.assertEquals(sample.getType(), MetricSample.Type.GAUGE);\n        Assertions.assertEquals(sample.getCategory(), category);\n        Assertions.assertEquals(sample.getBaseUnit(), baseUnit);\n        Assertions.assertEquals(1, sample.applyAsLong());\n        value.set(2);\n        Assertions.assertEquals(2, sample.applyAsLong());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/sample/MetricSampleTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metrics.model.sample;\n\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nclass MetricSampleTest {\n\n    private static String name;\n    private static String description;\n    private static Map<String, String> tags;\n    private static MetricSample.Type type;\n    private static MetricsCategory category;\n    private static String baseUnit;\n\n    @BeforeAll\n    public static void setup() {\n        name = \"test\";\n        description = \"test\";\n        tags = new HashMap<>();\n        type = MetricSample.Type.GAUGE;\n        category = MetricsCategory.REQUESTS;\n        baseUnit = \"byte\";\n    }\n\n    @Test\n    void test() {\n        MetricSample sample = new MetricSample(name, description, tags, type, category, baseUnit);\n        Assertions.assertEquals(sample.getName(), name);\n        Assertions.assertEquals(sample.getDescription(), description);\n        Assertions.assertEquals(sample.getTags(), tags);\n        Assertions.assertEquals(sample.getType(), type);\n        Assertions.assertEquals(sample.getCategory(), category);\n        Assertions.assertEquals(sample.getBaseUnit(), baseUnit);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/service/MetricsEntityTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metrics.service;\n\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.service.MetricsEntity;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nclass MetricsEntityTest {\n\n    private static String name;\n    private static Map<String, String> tags;\n    private static MetricsCategory category;\n    private static Object value;\n\n    @BeforeAll\n    public static void setup() {\n        name = \"test\";\n        tags = new HashMap<>();\n        category = MetricsCategory.REQUESTS;\n        value = 1;\n    }\n\n    @Test\n    void test() {\n        MetricsEntity entity = new MetricsEntity(name, tags, category, value);\n        Assertions.assertEquals(entity.getName(), name);\n        Assertions.assertEquals(entity.getTags(), tags);\n        Assertions.assertEquals(entity.getCategory(), category);\n        Assertions.assertEquals(entity.getValue(), value);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/monitor/support/MonitorFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.monitor.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.monitor.Monitor;\nimport org.apache.dubbo.monitor.MonitorFactory;\nimport org.apache.dubbo.monitor.MonitorService;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.monitor.Constants.CONCURRENT_KEY;\nimport static org.apache.dubbo.monitor.Constants.FAILURE_KEY;\nimport static org.apache.dubbo.monitor.Constants.SUCCESS_KEY;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.verify;\n\nclass MonitorFilterTest {\n\n    private volatile URL lastStatistics;\n\n    private volatile Invocation lastInvocation;\n\n    private final Invoker<MonitorService> serviceInvoker = new Invoker<MonitorService>() {\n        @Override\n        public Class<MonitorService> getInterface() {\n            return MonitorService.class;\n        }\n\n        public URL getUrl() {\n            return URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":20880?\" + APPLICATION_KEY + \"=abc&\" + SIDE_KEY\n                            + \"=\" + CONSUMER_SIDE)\n                    .putAttribute(MONITOR_KEY, URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":7070\"));\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return false;\n        }\n\n        @Override\n        public Result invoke(Invocation invocation) throws RpcException {\n            lastInvocation = invocation;\n            return AsyncRpcResult.newDefaultAsyncResult(invocation);\n        }\n\n        @Override\n        public void destroy() {}\n    };\n\n    private MonitorFactory monitorFactory = url -> new Monitor() {\n        public URL getUrl() {\n            return url;\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return true;\n        }\n\n        @Override\n        public void destroy() {}\n\n        public void collect(URL statistics) {\n            MonitorFilterTest.this.lastStatistics = statistics;\n        }\n\n        public List<URL> lookup(URL query) {\n            return Arrays.asList(MonitorFilterTest.this.lastStatistics);\n        }\n    };\n\n    @Test\n    void testFilter() throws Exception {\n        MonitorFilter monitorFilter = new MonitorFilter();\n        monitorFilter.setMonitorFactory(monitorFactory);\n        Invocation invocation =\n                new RpcInvocation(\"aaa\", MonitorService.class.getName(), \"\", new Class<?>[0], new Object[0]);\n        RpcContext.getServiceContext()\n                .setRemoteAddress(NetUtils.getLocalHost(), 20880)\n                .setLocalAddress(NetUtils.getLocalHost(), 2345);\n        Result result = monitorFilter.invoke(serviceInvoker, invocation);\n        result.whenCompleteWithContext((r, t) -> {\n            if (t == null) {\n                monitorFilter.onResponse(r, serviceInvoker, invocation);\n            } else {\n                monitorFilter.onError(t, serviceInvoker, invocation);\n            }\n        });\n        while (lastStatistics == null) {\n            Thread.sleep(10);\n        }\n        Assertions.assertEquals(\"abc\", lastStatistics.getParameter(APPLICATION_KEY));\n        Assertions.assertEquals(MonitorService.class.getName(), lastStatistics.getParameter(INTERFACE_KEY));\n        Assertions.assertEquals(\"aaa\", lastStatistics.getParameter(METHOD_KEY));\n        Assertions.assertEquals(NetUtils.getLocalHost() + \":20880\", lastStatistics.getParameter(PROVIDER));\n        Assertions.assertEquals(NetUtils.getLocalHost(), lastStatistics.getAddress());\n        Assertions.assertNull(lastStatistics.getParameter(CONSUMER));\n        Assertions.assertEquals(1, lastStatistics.getParameter(SUCCESS_KEY, 0));\n        Assertions.assertEquals(0, lastStatistics.getParameter(FAILURE_KEY, 0));\n        Assertions.assertEquals(1, lastStatistics.getParameter(CONCURRENT_KEY, 0));\n        Assertions.assertEquals(invocation, lastInvocation);\n    }\n\n    @Test\n    void testSkipMonitorIfNotHasKey() {\n        MonitorFilter monitorFilter = new MonitorFilter();\n        MonitorFactory mockMonitorFactory = mock(MonitorFactory.class);\n        monitorFilter.setMonitorFactory(mockMonitorFactory);\n        Invocation invocation =\n                new RpcInvocation(\"aaa\", MonitorService.class.getName(), \"\", new Class<?>[0], new Object[0]);\n        Invoker invoker = mock(Invoker.class);\n        given(invoker.getUrl())\n                .willReturn(URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":20880?\" + APPLICATION_KEY + \"=abc&\"\n                        + SIDE_KEY + \"=\" + CONSUMER_SIDE));\n\n        monitorFilter.invoke(invoker, invocation);\n\n        verify(mockMonitorFactory, never()).getMonitor(any(URL.class));\n    }\n\n    @Test\n    void testGenericFilter() throws Exception {\n        MonitorFilter monitorFilter = new MonitorFilter();\n        monitorFilter.setMonitorFactory(monitorFactory);\n        Invocation invocation = new RpcInvocation(\n                \"$invoke\",\n                MonitorService.class.getName(),\n                \"\",\n                new Class<?>[] {String.class, String[].class, Object[].class},\n                new Object[] {\"xxx\", new String[] {}, new Object[] {}});\n        RpcContext.getServiceContext()\n                .setRemoteAddress(NetUtils.getLocalHost(), 20880)\n                .setLocalAddress(NetUtils.getLocalHost(), 2345);\n        Result result = monitorFilter.invoke(serviceInvoker, invocation);\n        result.whenCompleteWithContext((r, t) -> {\n            if (t == null) {\n                monitorFilter.onResponse(r, serviceInvoker, invocation);\n            } else {\n                monitorFilter.onError(t, serviceInvoker, invocation);\n            }\n        });\n        while (lastStatistics == null) {\n            Thread.sleep(10);\n        }\n        Assertions.assertEquals(\"abc\", lastStatistics.getParameter(APPLICATION_KEY));\n        Assertions.assertEquals(MonitorService.class.getName(), lastStatistics.getParameter(INTERFACE_KEY));\n        Assertions.assertEquals(\"xxx\", lastStatistics.getParameter(METHOD_KEY));\n        Assertions.assertEquals(NetUtils.getLocalHost() + \":20880\", lastStatistics.getParameter(PROVIDER));\n        Assertions.assertEquals(NetUtils.getLocalHost(), lastStatistics.getAddress());\n        Assertions.assertNull(lastStatistics.getParameter(CONSUMER));\n        Assertions.assertEquals(1, lastStatistics.getParameter(SUCCESS_KEY, 0));\n        Assertions.assertEquals(0, lastStatistics.getParameter(FAILURE_KEY, 0));\n        Assertions.assertEquals(1, lastStatistics.getParameter(CONCURRENT_KEY, 0));\n        Assertions.assertEquals(invocation, lastInvocation);\n    }\n\n    @Test\n    void testSafeFailForMonitorCollectFail() {\n        MonitorFilter monitorFilter = new MonitorFilter();\n        MonitorFactory mockMonitorFactory = mock(MonitorFactory.class);\n        Monitor mockMonitor = mock(Monitor.class);\n        Mockito.doThrow(new RuntimeException()).when(mockMonitor).collect(any(URL.class));\n\n        monitorFilter.setMonitorFactory(mockMonitorFactory);\n        given(mockMonitorFactory.getMonitor(any(URL.class))).willReturn(mockMonitor);\n        Invocation invocation =\n                new RpcInvocation(\"aaa\", MonitorService.class.getName(), \"\", new Class<?>[0], new Object[0]);\n\n        monitorFilter.invoke(serviceInvoker, invocation);\n    }\n\n    @Test\n    void testOnResponseWithoutStartTime() {\n        MonitorFilter monitorFilter = new MonitorFilter();\n        MonitorFactory mockMonitorFactory = mock(MonitorFactory.class);\n        Monitor mockMonitor = mock(Monitor.class);\n        monitorFilter.setMonitorFactory(mockMonitorFactory);\n        given(mockMonitorFactory.getMonitor(any(URL.class))).willReturn(mockMonitor);\n        Invocation invocation =\n                new RpcInvocation(\"aaa\", MonitorService.class.getName(), \"\", new Class<?>[0], new Object[0]);\n\n        Result result = monitorFilter.invoke(serviceInvoker, invocation);\n        invocation.getAttributes().remove(\"monitor_filter_start_time\");\n\n        monitorFilter.onResponse(result, serviceInvoker, invocation);\n    }\n\n    @Test\n    void testOnErrorWithoutStartTime() {\n        MonitorFilter monitorFilter = new MonitorFilter();\n        MonitorFactory mockMonitorFactory = mock(MonitorFactory.class);\n        Monitor mockMonitor = mock(Monitor.class);\n        monitorFilter.setMonitorFactory(mockMonitorFactory);\n        given(mockMonitorFactory.getMonitor(any(URL.class))).willReturn(mockMonitor);\n        Invocation invocation =\n                new RpcInvocation(\"aaa\", MonitorService.class.getName(), \"\", new Class<?>[0], new Object[0]);\n\n        Throwable rpcException = new RpcException();\n        monitorFilter.onError(rpcException, serviceInvoker, invocation);\n    }\n\n    @AfterEach\n    public void destroy() {\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        applicationModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/rpc/cluster/filter/MetricsClusterFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.filter.MetricsFilter;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.sample.CounterMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.cluster.filter.support.MetricsClusterFilter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\nclass MetricsClusterFilterTest {\n\n    private ApplicationModel applicationModel;\n    private MetricsFilter filter;\n    private MetricsClusterFilter metricsClusterFilter;\n    private DefaultMetricsCollector collector;\n    private RpcInvocation invocation;\n    private final Invoker<?> invoker = mock(Invoker.class);\n\n    private static final String INTERFACE_NAME = \"org.apache.dubbo.MockInterface\";\n    private static final String METHOD_NAME = \"mockMethod\";\n    private static final String GROUP = \"mockGroup\";\n    private static final String VERSION = \"1.0.0\";\n    private String side;\n\n    private AtomicBoolean initApplication = new AtomicBoolean(false);\n\n    @BeforeEach\n    public void setup() {\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n        // RpcContext.getContext().setAttachment(\"MockMetrics\",\"MockMetrics\");\n\n        applicationModel = ApplicationModel.defaultModel();\n        applicationModel.getApplicationConfigManager().setApplication(config);\n\n        invocation = new RpcInvocation();\n        filter = new MetricsFilter();\n\n        collector = applicationModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);\n        if (!initApplication.get()) {\n            collector.collectApplication();\n            initApplication.set(true);\n        }\n        filter.setApplicationModel(applicationModel);\n        side = CommonConstants.CONSUMER;\n        invocation.setInvoker(new TestMetricsInvoker(side));\n        RpcContext.getServiceContext()\n                .setUrl(URL.valueOf(\"test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=\" + side));\n\n        metricsClusterFilter = new MetricsClusterFilter();\n        metricsClusterFilter.setApplicationModel(applicationModel);\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    @Test\n    public void testNoProvider() {\n        testClusterFilterError(\n                RpcException.FORBIDDEN_EXCEPTION,\n                MetricsKey.METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED.getNameByType(CommonConstants.CONSUMER));\n    }\n\n    private void testClusterFilterError(int errorCode, String name) {\n        collector.setCollectEnabled(true);\n        given(invoker.invoke(invocation)).willThrow(new RpcException(errorCode));\n        initParam();\n\n        Long count = 1L;\n\n        for (int i = 0; i < count; i++) {\n            try {\n                metricsClusterFilter.invoke(invoker, invocation);\n            } catch (Exception e) {\n                Assertions.assertTrue(e instanceof RpcException);\n                metricsClusterFilter.onError(e, invoker, invocation);\n            }\n        }\n        Map<String, MetricSample> metricsMap = getMetricsMap();\n        Assertions.assertTrue(metricsMap.containsKey(name));\n\n        MetricSample sample = metricsMap.get(name);\n\n        Assertions.assertSame(((CounterMetricSample) sample).getValue().longValue(), count);\n        teardown();\n    }\n\n    private void initParam() {\n        invocation.setTargetServiceUniqueName(GROUP + \"/\" + INTERFACE_NAME + \":\" + VERSION);\n        invocation.setMethodName(METHOD_NAME);\n        invocation.setParameterTypes(new Class[] {String.class});\n    }\n\n    private Map<String, MetricSample> getMetricsMap() {\n        List<MetricSample> samples = collector.collect();\n        List<MetricSample> samples1 = new ArrayList<>();\n        for (MetricSample sample : samples) {\n            if (sample.getName().contains(\"dubbo.thread.pool\")) {\n                continue;\n            }\n            samples1.add(sample);\n        }\n        return samples1.stream().collect(Collectors.toMap(MetricSample::getName, Function.identity()));\n    }\n\n    public class TestMetricsInvoker implements Invoker {\n\n        private String side;\n\n        public TestMetricsInvoker(String side) {\n            this.side = side;\n        }\n\n        @Override\n        public Class getInterface() {\n            return null;\n        }\n\n        @Override\n        public Result invoke(Invocation invocation) throws RpcException {\n            return null;\n        }\n\n        @Override\n        public URL getUrl() {\n            return URL.valueOf(\"test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=\" + side);\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return true;\n        }\n\n        @Override\n        public void destroy() {}\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/rpc/cluster/filter/MockInvocation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.cluster.filter;\n\nimport org.apache.dubbo.rpc.AttachmentsAdapter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.rpc.Constants.TOKEN_KEY;\n\n/**\n * MockInvocation.java\n */\npublic class MockInvocation extends RpcInvocation {\n\n    private Map<String, Object> attachments;\n\n    public MockInvocation() {\n        attachments = new HashMap<>();\n        attachments.put(PATH_KEY, \"dubbo\");\n        attachments.put(GROUP_KEY, \"dubbo\");\n        attachments.put(VERSION_KEY, \"1.0.0\");\n        attachments.put(DUBBO_VERSION_KEY, \"1.0.0\");\n        attachments.put(TOKEN_KEY, \"sfag\");\n        attachments.put(TIMEOUT_KEY, \"1000\");\n    }\n\n    @Override\n    public String getTargetServiceUniqueName() {\n        return null;\n    }\n\n    @Override\n    public String getProtocolServiceKey() {\n        return null;\n    }\n\n    public String getMethodName() {\n        return \"echo\";\n    }\n\n    @Override\n    public String getServiceName() {\n        return \"DemoService\";\n    }\n\n    public Class<?>[] getParameterTypes() {\n        return new Class[] {String.class};\n    }\n\n    public Object[] getArguments() {\n        return new Object[] {\"aa\"};\n    }\n\n    public Map<String, String> getAttachments() {\n        return new AttachmentsAdapter.ObjectToStringMap(attachments);\n    }\n\n    @Override\n    public Map<String, Object> getObjectAttachments() {\n        return attachments;\n    }\n\n    @Override\n    public void setAttachment(String key, String value) {\n        setObjectAttachment(key, value);\n    }\n\n    @Override\n    public void setAttachment(String key, Object value) {\n        setObjectAttachment(key, value);\n    }\n\n    @Override\n    public void setObjectAttachment(String key, Object value) {\n        attachments.put(key, value);\n    }\n\n    @Override\n    public void setAttachmentIfAbsent(String key, String value) {\n        setObjectAttachmentIfAbsent(key, value);\n    }\n\n    @Override\n    public void setAttachmentIfAbsent(String key, Object value) {\n        setObjectAttachmentIfAbsent(key, value);\n    }\n\n    @Override\n    public void setObjectAttachmentIfAbsent(String key, Object value) {\n        attachments.put(key, value);\n    }\n\n    public Invoker<?> getInvoker() {\n        return null;\n    }\n\n    @Override\n    public void setServiceModel(ServiceModel serviceModel) {}\n\n    @Override\n    public ServiceModel getServiceModel() {\n        return null;\n    }\n\n    @Override\n    public Object put(Object key, Object value) {\n        return null;\n    }\n\n    @Override\n    public Object get(Object key) {\n        return null;\n    }\n\n    @Override\n    public Map<Object, Object> getAttributes() {\n        return null;\n    }\n\n    public String getAttachment(String key) {\n        return (String) getObjectAttachments().get(key);\n    }\n\n    @Override\n    public Object getObjectAttachment(String key) {\n        return attachments.get(key);\n    }\n\n    public String getAttachment(String key, String defaultValue) {\n        return (String) getObjectAttachments().get(key);\n    }\n\n    @Override\n    public Object getObjectAttachment(String key, Object defaultValue) {\n        Object result = attachments.get(key);\n        if (result == null) {\n            return defaultValue;\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-default/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metrics</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-metrics-event</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The metrics event-related api module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/MetricsConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics;\n\npublic interface MetricsConstants {\n\n    String INVOCATION = \"metric_filter_invocation\";\n    String METHOD_METRICS = \"metric_filter_method_metrics\";\n    String INVOCATION_METRICS_COUNTER = \"metric_filter_invocation_counter\";\n    String INVOCATION_SIDE = \"metric_filter_side\";\n    String INVOCATION_REQUEST_ERROR = \"metric_request_error\";\n\n    String ATTACHMENT_KEY_SERVICE = \"serviceKey\";\n    String ATTACHMENT_KEY_SIZE = \"size\";\n    String ATTACHMENT_KEY_LAST_NUM_MAP = \"lastNumMap\";\n    String ATTACHMENT_DIRECTORY_MAP = \"dirNum\";\n\n    int SELF_INCREMENT_SIZE = 1;\n\n    String NETTY_METRICS_MAP = \"nettyMetricsMap\";\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/event/MetricsEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.event;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.metrics.exception.MetricsNeverHappenException;\nimport org.apache.dubbo.metrics.model.key.TypeWrapper;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\n/**\n * BaseMetricsEvent.\n */\npublic abstract class MetricsEvent {\n\n    /**\n     * Metric object. (eg. MethodMetric)\n     */\n    protected final transient ApplicationModel source;\n\n    private boolean available = true;\n    private final TypeWrapper typeWrapper;\n    private final String appName;\n    private final MetricsEventMulticaster metricsEventMulticaster;\n\n    private final Map<String, Object> attachments = new IdentityHashMap<>(8);\n\n    public MetricsEvent(ApplicationModel source, TypeWrapper typeWrapper) {\n        this(source, null, null, typeWrapper);\n    }\n\n    public MetricsEvent(\n            ApplicationModel source,\n            String appName,\n            MetricsEventMulticaster metricsEventMulticaster,\n            TypeWrapper typeWrapper) {\n        this.typeWrapper = typeWrapper;\n        if (source == null) {\n            this.source = ApplicationModel.defaultModel();\n            // Appears only in unit tests\n            this.available = false;\n        } else {\n            this.source = source;\n        }\n        if (metricsEventMulticaster == null) {\n            if (this.source.isDestroyed()) {\n                this.metricsEventMulticaster = null;\n            } else {\n                ScopeBeanFactory beanFactory = this.source.getBeanFactory();\n                if (beanFactory.isDestroyed()) {\n                    this.metricsEventMulticaster = null;\n                } else {\n                    MetricsEventMulticaster dispatcher = beanFactory.getBean(MetricsEventMulticaster.class);\n                    this.metricsEventMulticaster = dispatcher;\n                }\n            }\n        } else {\n            this.metricsEventMulticaster = metricsEventMulticaster;\n        }\n        if (appName == null) {\n            this.appName = this.source.tryGetApplicationName();\n        } else {\n            this.appName = appName;\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> T getAttachmentValue(String key) {\n        if (key == null) {\n            throw new MetricsNeverHappenException(\"Attachment key is null\");\n        }\n        return (T) attachments.get(key);\n    }\n\n    public Map<String, Object> getAttachments() {\n        return Collections.unmodifiableMap(attachments);\n    }\n\n    public void putAttachment(String key, Object value) {\n        attachments.put(key, value);\n    }\n\n    public void putAttachments(Map<String, String> attachments) {\n        this.attachments.putAll(attachments);\n    }\n\n    public void setAvailable(boolean available) {\n        this.available = available;\n    }\n\n    public boolean isAvailable() {\n        return available;\n    }\n\n    public void customAfterPost(Object postResult) {}\n\n    public ApplicationModel getSource() {\n        return source;\n    }\n\n    public MetricsEventMulticaster getMetricsEventMulticaster() {\n        return metricsEventMulticaster;\n    }\n\n    public String appName() {\n        return appName;\n    }\n\n    public TypeWrapper getTypeWrapper() {\n        return typeWrapper;\n    }\n\n    public boolean isAssignableFrom(Object type) {\n        return typeWrapper.isAssignableFrom(type);\n    }\n\n    public String toString() {\n        return getClass().getName() + \"[source=\" + source + \"]\";\n    }\n\n    public enum Type {\n        TOTAL(\"TOTAL_%s\"),\n        SUCCEED(\"SUCCEED_%s\"),\n        BUSINESS_FAILED(\"BUSINESS_FAILED_%s\"),\n        REQUEST_TIMEOUT(\"REQUEST_TIMEOUT_%s\"),\n        REQUEST_LIMIT(\"REQUEST_LIMIT_%s\"),\n        PROCESSING(\"PROCESSING_%s\"),\n        UNKNOWN_FAILED(\"UNKNOWN_FAILED_%s\"),\n        TOTAL_FAILED(\"TOTAL_FAILED_%s\"),\n        APPLICATION_INFO(\"APPLICATION_INFO_%s\"),\n        NETWORK_EXCEPTION(\"NETWORK_EXCEPTION_%s\"),\n        SERVICE_UNAVAILABLE(\"SERVICE_UNAVAILABLE_%s\"),\n        CODEC_EXCEPTION(\"CODEC_EXCEPTION_%s\"),\n        NO_INVOKER_AVAILABLE(\"NO_INVOKER_AVAILABLE_%s\"),\n        ;\n\n        private final String name;\n\n        public final String getName() {\n            return this.name;\n        }\n\n        public final String getNameByType(String type) {\n            return String.format(name, type);\n        }\n\n        Type(String name) {\n            this.name = name;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/event/MetricsEventBus.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.event;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport java.util.Optional;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION;\n\n/**\n * Dispatches events to listeners, and provides ways for listeners to register themselves.\n */\npublic class MetricsEventBus {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MetricsEventBus.class);\n\n    /**\n     * Posts an event to all registered subscribers and only once.\n     *\n     * @param event event to post.\n     */\n    public static void publish(MetricsEvent event) {\n        if (event == null || event.getSource() == null) {\n            return;\n        }\n        MetricsEventMulticaster dispatcher = event.getMetricsEventMulticaster();\n        Optional.ofNullable(dispatcher).ifPresent(d -> {\n            tryInvoke(() -> d.publishEvent(event));\n        });\n    }\n\n    /**\n     * Posts an event to all registered subscribers.\n     * Full lifecycle post, judging success or failure by whether there is an exception\n     * Loop around the event target and return the original processing result\n     *\n     * @param event          event to post.\n     * @param targetSupplier original processing result targetSupplier\n     */\n    public static <T> T post(MetricsEvent event, Supplier<T> targetSupplier) {\n        return post(event, targetSupplier, null);\n    }\n\n    /**\n     * Full lifecycle post, success and failure conditions can be customized\n     *\n     * @param event          event to post.\n     * @param targetSupplier original processing result supplier\n     * @param trFunction     Custom event success criteria, judged according to the returned boolean type\n     * @param <T>            Biz result type\n     * @return Biz result\n     */\n    public static <T> T post(MetricsEvent event, Supplier<T> targetSupplier, Function<T, Boolean> trFunction) {\n        T result;\n        tryInvoke(() -> before(event));\n        if (trFunction == null) {\n            try {\n                result = targetSupplier.get();\n            } catch (Throwable e) {\n                tryInvoke(() -> error(event));\n                throw e;\n            }\n            tryInvoke(() -> after(event, result));\n        } else {\n            // Custom failure status\n            result = targetSupplier.get();\n            if (trFunction.apply(result)) {\n                tryInvoke(() -> after(event, result));\n            } else {\n                tryInvoke(() -> error(event));\n            }\n        }\n        return result;\n    }\n\n    public static void tryInvoke(Runnable runnable) {\n        if (runnable == null) {\n            return;\n        }\n        try {\n            runnable.run();\n        } catch (Throwable e) {\n            logger.warn(COMMON_METRICS_COLLECTOR_EXCEPTION, \"\", \"\", \"invoke metric event error\" + e.getMessage());\n        }\n    }\n\n    /**\n     * Applicable to the scene where execution and return are separated,\n     * eventSaveRunner saves the event, so that the calculation rt is introverted\n     */\n    public static void before(MetricsEvent event) {\n        MetricsEventMulticaster dispatcher = validate(event);\n\n        if (dispatcher == null) return;\n        tryInvoke(() -> dispatcher.publishEvent(event));\n    }\n\n    public static void after(MetricsEvent event, Object result) {\n        MetricsEventMulticaster dispatcher = validate(event);\n        if (dispatcher == null) return;\n        tryInvoke(() -> {\n            event.customAfterPost(result);\n            if (event instanceof TimeCounterEvent) {\n                dispatcher.publishFinishEvent((TimeCounterEvent) event);\n            }\n        });\n    }\n\n    public static void error(MetricsEvent event) {\n        MetricsEventMulticaster dispatcher = validate(event);\n        if (dispatcher == null) return;\n        tryInvoke(() -> {\n            if (event instanceof TimeCounterEvent) {\n                dispatcher.publishErrorEvent((TimeCounterEvent) event);\n            }\n        });\n    }\n\n    private static MetricsEventMulticaster validate(MetricsEvent event) {\n        MetricsEventMulticaster dispatcher = event.getMetricsEventMulticaster();\n        if (dispatcher == null) {\n            return null;\n        }\n        if (!(event instanceof TimeCounterEvent)) {\n            return null;\n        }\n        return dispatcher;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/event/MetricsEventMulticaster.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.event;\n\nimport org.apache.dubbo.metrics.listener.MetricsListener;\n\npublic interface MetricsEventMulticaster {\n\n    void addListener(MetricsListener<?> listener);\n\n    void publishEvent(MetricsEvent event);\n\n    void publishFinishEvent(TimeCounterEvent event);\n\n    void publishErrorEvent(TimeCounterEvent event);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/event/TimeCounterEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.event;\n\nimport org.apache.dubbo.metrics.model.TimePair;\nimport org.apache.dubbo.metrics.model.key.TypeWrapper;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\n/**\n * Mark certain types of events, allow automatic recording of start and end times, and provide time pairs\n */\npublic abstract class TimeCounterEvent extends MetricsEvent {\n\n    private final TimePair timePair;\n\n    public TimeCounterEvent(ApplicationModel source, TypeWrapper typeWrapper) {\n        super(source, typeWrapper);\n        this.timePair = TimePair.start();\n    }\n\n    public TimeCounterEvent(\n            ApplicationModel source,\n            String appName,\n            MetricsEventMulticaster metricsDispatcher,\n            TypeWrapper typeWrapper) {\n        super(source, appName, metricsDispatcher, typeWrapper);\n        this.timePair = TimePair.start();\n    }\n\n    public TimePair getTimePair() {\n        return timePair;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/exception/MetricsNeverHappenException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.exception;\n\npublic class MetricsNeverHappenException extends RuntimeException {\n\n    public MetricsNeverHappenException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/listener/MetricsListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.listener;\n\nimport org.apache.dubbo.metrics.event.MetricsEvent;\n\n/**\n * Metrics Listener.\n */\npublic interface MetricsListener<E extends MetricsEvent> {\n\n    boolean isSupport(MetricsEvent event);\n\n    /**\n     * notify event.\n     *\n     * @param event BaseMetricsEvent\n     */\n    void onEvent(E event);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/model/TimePair.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model;\n\npublic class TimePair {\n\n    private final long begin;\n    private long end;\n    private static final TimePair empty = new TimePair(0L);\n\n    public TimePair(long currentTimeMillis) {\n        this.begin = currentTimeMillis;\n    }\n\n    public static TimePair start() {\n        return new TimePair(System.currentTimeMillis());\n    }\n\n    public void end() {\n        this.end = System.currentTimeMillis();\n    }\n\n    public long calc() {\n        return end - begin;\n    }\n\n    public static TimePair empty() {\n        return empty;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKey.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.key;\n\npublic enum MetricsKey {\n    APPLICATION_METRIC_INFO(\"dubbo.application.info.total\", \"Total Application Info\"),\n\n    CONFIGCENTER_METRIC_TOTAL(\"dubbo.configcenter.total\", \"Config Changed Total\"),\n\n    // provider metrics key\n    METRIC_REQUESTS(\"dubbo.%s.requests.total\", \"Total Requests\"),\n    METRIC_REQUESTS_SUCCEED(\"dubbo.%s.requests.succeed.total\", \"Total Succeed Requests\"),\n    METRIC_REQUEST_BUSINESS_FAILED(\"dubbo.%s.requests.business.failed.total\", \"Total Failed Business Requests\"),\n\n    METRIC_REQUESTS_PROCESSING(\"dubbo.%s.requests.processing.total\", \"Processing Requests\"),\n    METRIC_REQUESTS_TIMEOUT(\"dubbo.%s.requests.timeout.total\", \"Total Timeout Failed Requests\"),\n    METRIC_REQUESTS_LIMIT(\"dubbo.%s.requests.limit.total\", \"Total Limit Failed Requests\"),\n    METRIC_REQUESTS_FAILED(\"dubbo.%s.requests.unknown.failed.total\", \"Total Unknown Failed Requests\"),\n    METRIC_REQUESTS_TOTAL_FAILED(\"dubbo.%s.requests.failed.total\", \"Total Failed Requests\"),\n    METRIC_REQUESTS_NETWORK_FAILED(\"dubbo.%s.requests.failed.network.total\", \"Total network Failed Requests\"),\n    METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED(\n            \"dubbo.%s.requests.failed.service.unavailable.total\", \"Total Service Unavailable Failed Requests\"),\n    METRIC_REQUESTS_CODEC_FAILED(\"dubbo.%s.requests.failed.codec.total\", \"Total Codec Failed Requests\"),\n\n    METRIC_REQUESTS_TOTAL_AGG(\"dubbo.%s.requests.total.aggregate\", \"Aggregated Total Requests\"),\n    METRIC_REQUESTS_SUCCEED_AGG(\"dubbo.%s.requests.succeed.aggregate\", \"Aggregated Succeed Requests\"),\n    METRIC_REQUESTS_FAILED_AGG(\"dubbo.%s.requests.failed.aggregate\", \"Aggregated Failed Requests\"),\n    METRIC_REQUEST_BUSINESS_FAILED_AGG(\n            \"dubbo.%s.requests.business.failed.aggregate\", \"Aggregated Business Failed Requests\"),\n    METRIC_REQUESTS_TIMEOUT_AGG(\"dubbo.%s.requests.timeout.failed.aggregate\", \"Aggregated timeout Failed Requests\"),\n    METRIC_REQUESTS_LIMIT_AGG(\"dubbo.%s.requests.limit.aggregate\", \"Aggregated limit Requests\"),\n    METRIC_REQUESTS_TOTAL_FAILED_AGG(\"dubbo.%s.requests.failed.total.aggregate\", \"Aggregated failed total Requests\"),\n    METRIC_REQUESTS_NETWORK_FAILED_AGG(\n            \"dubbo.%s.requests.failed.network.total.aggregate\", \"Aggregated failed network total Requests\"),\n    METRIC_REQUESTS_CODEC_FAILED_AGG(\n            \"dubbo.%s.requests.failed.codec.total.aggregate\", \"Aggregated failed codec total Requests\"),\n    METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG(\n            \"dubbo.%s.requests.failed.service.unavailable.total.aggregate\", \"Aggregated failed codec total Requests\"),\n\n    METRIC_QPS(\"dubbo.%s.qps.total\", \"Query Per Seconds\"),\n    METRIC_RT_LAST(\"dubbo.%s.rt.milliseconds.last\", \"Last Response Time\"),\n    METRIC_RT_MIN(\"dubbo.%s.rt.milliseconds.min\", \"Min Response Time\"),\n    METRIC_RT_MAX(\"dubbo.%s.rt.milliseconds.max\", \"Max Response Time\"),\n    METRIC_RT_SUM(\"dubbo.%s.rt.milliseconds.sum\", \"Sum Response Time\"),\n    METRIC_RT_AVG(\"dubbo.%s.rt.milliseconds.avg\", \"Average Response Time\"),\n    METRIC_RT_P99(\"dubbo.%s.rt.milliseconds.p99\", \"Response Time P99\"),\n    METRIC_RT_P95(\"dubbo.%s.rt.milliseconds.p95\", \"Response Time P95\"),\n    METRIC_RT_P90(\"dubbo.%s.rt.milliseconds.p90\", \"Response Time P90\"),\n    METRIC_RT_P50(\"dubbo.%s.rt.milliseconds.p50\", \"Response Time P50\"),\n    METRIC_RT_MIN_AGG(\"dubbo.%s.rt.min.milliseconds.aggregate\", \"Aggregated Min Response\"),\n    METRIC_RT_MAX_AGG(\"dubbo.%s.rt.max.milliseconds.aggregate\", \"Aggregated Max Response\"),\n    METRIC_RT_AVG_AGG(\"dubbo.%s.rt.avg.milliseconds.aggregate\", \"Aggregated Avg Response\"),\n\n    // register metrics key\n    REGISTER_METRIC_REQUESTS(\"dubbo.registry.register.requests.total\", \"Total Register Requests\"),\n    REGISTER_METRIC_REQUESTS_SUCCEED(\"dubbo.registry.register.requests.succeed.total\", \"Succeed Register Requests\"),\n    REGISTER_METRIC_REQUESTS_FAILED(\"dubbo.registry.register.requests.failed.total\", \"Failed Register Requests\"),\n    METRIC_RT_HISTOGRAM(\"dubbo.%s.rt.milliseconds.histogram\", \"Response Time Histogram\"),\n\n    GENERIC_METRIC_REQUESTS(\"dubbo.%s.requests.total\", \"Total %s Requests\"),\n    GENERIC_METRIC_REQUESTS_SUCCEED(\"dubbo.%s.requests.succeed.total\", \"Succeed %s Requests\"),\n    GENERIC_METRIC_REQUESTS_FAILED(\"dubbo.%s.requests.failed.total\", \"Failed %s Requests\"),\n\n    // subscribe metrics key\n    SUBSCRIBE_METRIC_NUM(\"dubbo.registry.subscribe.num.total\", \"Total Subscribe Num\"),\n    SUBSCRIBE_METRIC_NUM_SUCCEED(\"dubbo.registry.subscribe.num.succeed.total\", \"Succeed Subscribe Num\"),\n    SUBSCRIBE_METRIC_NUM_FAILED(\"dubbo.registry.subscribe.num.failed.total\", \"Failed Subscribe Num\"),\n\n    // directory metrics key\n    DIRECTORY_METRIC_NUM_ALL(\"dubbo.registry.directory.num.all\", \"All Directory Urls\"),\n    DIRECTORY_METRIC_NUM_VALID(\"dubbo.registry.directory.num.valid.total\", \"Valid Directory Urls\"),\n    DIRECTORY_METRIC_NUM_TO_RECONNECT(\"dubbo.registry.directory.num.to_reconnect.total\", \"ToReconnect Directory Urls\"),\n    DIRECTORY_METRIC_NUM_DISABLE(\"dubbo.registry.directory.num.disable.total\", \"Disable Directory Urls\"),\n\n    NOTIFY_METRIC_REQUESTS(\"dubbo.registry.notify.requests.total\", \"Total Notify Requests\"),\n    NOTIFY_METRIC_NUM_LAST(\"dubbo.registry.notify.num.last\", \"Last Notify Nums\"),\n\n    THREAD_POOL_CORE_SIZE(\"dubbo.thread.pool.core.size\", \"Thread Pool Core Size\"),\n    THREAD_POOL_LARGEST_SIZE(\"dubbo.thread.pool.largest.size\", \"Thread Pool Largest Size\"),\n    THREAD_POOL_MAX_SIZE(\"dubbo.thread.pool.max.size\", \"Thread Pool Max Size\"),\n    THREAD_POOL_ACTIVE_SIZE(\"dubbo.thread.pool.active.size\", \"Thread Pool Active Size\"),\n    THREAD_POOL_THREAD_COUNT(\"dubbo.thread.pool.thread.count\", \"Thread Pool Thread Count\"),\n    THREAD_POOL_QUEUE_SIZE(\"dubbo.thread.pool.queue.size\", \"Thread Pool Queue Size\"),\n    THREAD_POOL_THREAD_REJECT_COUNT(\"dubbo.thread.pool.reject.thread.count\", \"Thread Pool Reject Thread Count\"),\n\n    // metadata push metrics key\n    METADATA_PUSH_METRIC_NUM(\"dubbo.metadata.push.num.total\", \"Total Push Num\"),\n    METADATA_PUSH_METRIC_NUM_SUCCEED(\"dubbo.metadata.push.num.succeed.total\", \"Succeed Push Num\"),\n    METADATA_PUSH_METRIC_NUM_FAILED(\"dubbo.metadata.push.num.failed.total\", \"Failed Push Num\"),\n\n    // metadata subscribe metrics key\n    METADATA_SUBSCRIBE_METRIC_NUM(\"dubbo.metadata.subscribe.num.total\", \"Total Metadata Subscribe Num\"),\n    METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED(\n            \"dubbo.metadata.subscribe.num.succeed.total\", \"Succeed Metadata Subscribe Num\"),\n    METADATA_SUBSCRIBE_METRIC_NUM_FAILED(\"dubbo.metadata.subscribe.num.failed.total\", \"Failed Metadata Subscribe Num\"),\n\n    // register service metrics key\n    SERVICE_REGISTER_METRIC_REQUESTS(\"dubbo.registry.register.service.total\", \"Total Service-Level Register Requests\"),\n    SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED(\n            \"dubbo.registry.register.service.succeed.total\", \"Succeed Service-Level Register Requests\"),\n    SERVICE_REGISTER_METRIC_REQUESTS_FAILED(\n            \"dubbo.registry.register.service.failed.total\", \"Failed Service-Level Register Requests\"),\n\n    // subscribe metrics key\n    SERVICE_SUBSCRIBE_METRIC_NUM(\"dubbo.registry.subscribe.service.num.total\", \"Total Service-Level Subscribe Num\"),\n    SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED(\n            \"dubbo.registry.subscribe.service.num.succeed.total\", \"Succeed Service-Level Num\"),\n    SERVICE_SUBSCRIBE_METRIC_NUM_FAILED(\n            \"dubbo.registry.subscribe.service.num.failed.total\", \"Failed Service-Level Num\"),\n    // store provider metadata service key\n    STORE_PROVIDER_METADATA(\"dubbo.metadata.store.provider.total\", \"Store Provider Metadata\"),\n\n    STORE_PROVIDER_METADATA_SUCCEED(\"dubbo.metadata.store.provider.succeed.total\", \"Succeed Store Provider Metadata\"),\n\n    STORE_PROVIDER_METADATA_FAILED(\"dubbo.metadata.store.provider.failed.total\", \"Failed Store Provider Metadata\"),\n    METADATA_GIT_COMMITID_METRIC(\"git.commit.id\", \"Git Commit Id Metrics\"),\n\n    // consumer metrics key\n    INVOKER_NO_AVAILABLE_COUNT(\n            \"dubbo.consumer.invoker.no.available.count\", \"Request Throw No Invoker Available Exception Count\"),\n\n    // count the number of occurrences of each error code\n    ERROR_CODE_COUNT(\"dubbo.error.code.count\", \"The Count Of Occurrences for Each Error Code\"),\n\n    // netty metrics key\n    NETTY_ALLOCATOR_HEAP_MEMORY_USED(\"netty.allocator.memory.used\", \"Netty Allocator Memory Used\"),\n    NETTY_ALLOCATOR_DIRECT_MEMORY_USED(\"netty.allocator.direct.memory.used\", \"Netty Allocator Direct Memory Used\"),\n    NETTY_ALLOCATOR_PINNED_DIRECT_MEMORY(\n            \"netty.allocator.pinned.direct.memory\", \"Netty Allocator Pinned Direct Memory\"),\n    NETTY_ALLOCATOR_PINNED_HEAP_MEMORY(\"netty.allocator.pinned.heap.memory\", \"Netty Allocator Pinned Heap Memory\"),\n    NETTY_ALLOCATOR_HEAP_ARENAS_NUM(\"netty.allocator.heap.arenas.num\", \"Netty Allocator Heap Arenas Num\"),\n    NETTY_ALLOCATOR_DIRECT_ARENAS_NUM(\"netty.allocator.direct.arenas.num\", \"Netty Allocator Direct Arenas Num\"),\n    NETTY_ALLOCATOR_NORMAL_CACHE_SIZE(\"netty.allocator.normal.cache.size\", \"Netty Allocator Normal Cache Size\"),\n    NETTY_ALLOCATOR_SMALL_CACHE_SIZE(\"netty.allocator.small.cache.size\", \"Netty Allocator Small Cache Size\"),\n    NETTY_ALLOCATOR_THREAD_LOCAL_CACHES_NUM(\n            \"netty.allocator.thread.local.caches.num\", \"Netty Allocator Thread Local Caches Num\"),\n    NETTY_ALLOCATOR_CHUNK_SIZE(\"netty.allocator.chunk.size\", \"Netty Allocator Chunk Size\"),\n    ;\n\n    private String name;\n    private String description;\n\n    public final String getName() {\n        return this.name;\n    }\n\n    public final String getNameByType(String type) {\n        return String.format(name, type);\n    }\n\n    public static MetricsKey getMetricsByName(String name) {\n        for (MetricsKey metricsKey : MetricsKey.values()) {\n            if (metricsKey.getName().equals(name)) {\n                return metricsKey;\n            }\n        }\n        return null;\n    }\n\n    public final String getDescription() {\n        return this.description;\n    }\n\n    MetricsKey(String name, String description) {\n        this.name = name;\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/model/key/MetricsLevel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.key;\n\npublic enum MetricsLevel {\n    APP,\n    SERVICE,\n    METHOD,\n    CONFIG,\n    REGISTRY\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-event/src/main/java/org/apache/dubbo/metrics/model/key/TypeWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.model.key;\n\nimport org.apache.dubbo.common.utils.Assert;\n\npublic class TypeWrapper {\n    private final MetricsLevel level;\n    private final MetricsKey postType;\n    private final MetricsKey finishType;\n    private final MetricsKey errorType;\n\n    public TypeWrapper(MetricsLevel level, MetricsKey postType) {\n        this(level, postType, null, null);\n    }\n\n    public TypeWrapper(MetricsLevel level, MetricsKey postType, MetricsKey finishType, MetricsKey errorType) {\n        this.level = level;\n        this.postType = postType;\n        this.finishType = finishType;\n        this.errorType = errorType;\n    }\n\n    public MetricsLevel getLevel() {\n        return level;\n    }\n\n    public boolean isAssignableFrom(Object type) {\n        Assert.notNull(type, \"Type can not be null\");\n        return type.equals(postType) || type.equals(finishType) || type.equals(errorType);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-metadata/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metrics</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-metrics-metadata</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The metrics module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/MetadataMetricsConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metadata;\n\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_PUSH_METRIC_NUM;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_PUSH_METRIC_NUM_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_PUSH_METRIC_NUM_SUCCEED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.STORE_PROVIDER_METADATA;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.STORE_PROVIDER_METADATA_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.STORE_PROVIDER_METADATA_SUCCEED;\n\npublic interface MetadataMetricsConstants {\n\n    MetricsPlaceValue OP_TYPE_PUSH = MetricsPlaceValue.of(\"push\", MetricsLevel.APP);\n    MetricsPlaceValue OP_TYPE_SUBSCRIBE = MetricsPlaceValue.of(\"subscribe\", MetricsLevel.APP);\n    MetricsPlaceValue OP_TYPE_STORE_PROVIDER_INTERFACE =\n            MetricsPlaceValue.of(\"store.provider.interface\", MetricsLevel.SERVICE);\n\n    // App-level\n    List<MetricsKey> APP_LEVEL_KEYS = Arrays.asList(\n            METADATA_PUSH_METRIC_NUM,\n            METADATA_PUSH_METRIC_NUM_SUCCEED,\n            METADATA_PUSH_METRIC_NUM_FAILED,\n            METADATA_SUBSCRIBE_METRIC_NUM,\n            METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED,\n            METADATA_SUBSCRIBE_METRIC_NUM_FAILED);\n\n    // Service-level\n    List<MetricsKeyWrapper> SERVICE_LEVEL_KEYS = Arrays.asList(\n            new MetricsKeyWrapper(STORE_PROVIDER_METADATA, OP_TYPE_STORE_PROVIDER_INTERFACE),\n            new MetricsKeyWrapper(STORE_PROVIDER_METADATA_SUCCEED, OP_TYPE_STORE_PROVIDER_INTERFACE),\n            new MetricsKeyWrapper(STORE_PROVIDER_METADATA_FAILED, OP_TYPE_STORE_PROVIDER_INTERFACE));\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/collector/MetadataMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metadata.collector;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.metrics.collector.CombMetricsCollector;\nimport org.apache.dubbo.metrics.collector.MetricsCollector;\nimport org.apache.dubbo.metrics.data.ApplicationStatComposite;\nimport org.apache.dubbo.metrics.data.BaseStatComposite;\nimport org.apache.dubbo.metrics.data.RtStatComposite;\nimport org.apache.dubbo.metrics.data.ServiceStatComposite;\nimport org.apache.dubbo.metrics.metadata.MetadataMetricsConstants;\nimport org.apache.dubbo.metrics.metadata.event.MetadataEvent;\nimport org.apache.dubbo.metrics.metadata.event.MetadataSubDispatcher;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_PUSH;\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_STORE_PROVIDER_INTERFACE;\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_SUBSCRIBE;\n\n/**\n * Registry implementation of {@link MetricsCollector}\n */\n@Activate\npublic class MetadataMetricsCollector extends CombMetricsCollector<MetadataEvent> {\n\n    private Boolean collectEnabled = null;\n    private final ApplicationModel applicationModel;\n\n    public MetadataMetricsCollector(ApplicationModel applicationModel) {\n        super(new BaseStatComposite(applicationModel) {\n            @Override\n            protected void init(ApplicationStatComposite applicationStatComposite) {\n                super.init(applicationStatComposite);\n                applicationStatComposite.init(MetadataMetricsConstants.APP_LEVEL_KEYS);\n            }\n\n            @Override\n            protected void init(ServiceStatComposite serviceStatComposite) {\n                super.init(serviceStatComposite);\n                serviceStatComposite.initWrapper(MetadataMetricsConstants.SERVICE_LEVEL_KEYS);\n            }\n\n            @Override\n            protected void init(RtStatComposite rtStatComposite) {\n                super.init(rtStatComposite);\n                rtStatComposite.init(OP_TYPE_PUSH, OP_TYPE_SUBSCRIBE, OP_TYPE_STORE_PROVIDER_INTERFACE);\n            }\n        });\n        super.setEventMulticaster(new MetadataSubDispatcher(this));\n        this.applicationModel = applicationModel;\n    }\n\n    public void setCollectEnabled(Boolean collectEnabled) {\n        if (collectEnabled != null) {\n            this.collectEnabled = collectEnabled;\n        }\n    }\n\n    @Override\n    public boolean isCollectEnabled() {\n        if (collectEnabled == null) {\n            ConfigManager configManager = applicationModel.getApplicationConfigManager();\n            configManager.getMetrics().ifPresent(metricsConfig -> setCollectEnabled(metricsConfig.getEnableMetadata()));\n        }\n        return Optional.ofNullable(collectEnabled).orElse(false);\n    }\n\n    @Override\n    public List<MetricSample> collect() {\n        List<MetricSample> list = new ArrayList<>();\n        if (!isCollectEnabled()) {\n            return list;\n        }\n        list.addAll(super.export(MetricsCategory.METADATA));\n        return list;\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        return stats.calSamplesChanged();\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetadataEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metadata.event;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.metadata.collector.MetadataMetricsCollector;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.TypeWrapper;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_PUSH_METRIC_NUM;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_PUSH_METRIC_NUM_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_PUSH_METRIC_NUM_SUCCEED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.STORE_PROVIDER_METADATA;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.STORE_PROVIDER_METADATA_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.STORE_PROVIDER_METADATA_SUCCEED;\n\n/**\n * Registry related events\n */\npublic class MetadataEvent extends TimeCounterEvent {\n    public MetadataEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) {\n        super(applicationModel, typeWrapper);\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        MetadataMetricsCollector collector;\n        if (!beanFactory.isDestroyed()) {\n            collector = beanFactory.getBean(MetadataMetricsCollector.class);\n            super.setAvailable(collector != null && collector.isCollectEnabled());\n        }\n    }\n\n    public static MetadataEvent toPushEvent(ApplicationModel applicationModel) {\n        return new MetadataEvent(\n                applicationModel,\n                new TypeWrapper(\n                        MetricsLevel.APP,\n                        METADATA_PUSH_METRIC_NUM,\n                        METADATA_PUSH_METRIC_NUM_SUCCEED,\n                        METADATA_PUSH_METRIC_NUM_FAILED));\n    }\n\n    public static MetadataEvent toSubscribeEvent(ApplicationModel applicationModel) {\n        return new MetadataEvent(\n                applicationModel,\n                new TypeWrapper(\n                        MetricsLevel.APP,\n                        METADATA_SUBSCRIBE_METRIC_NUM,\n                        METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED,\n                        METADATA_SUBSCRIBE_METRIC_NUM_FAILED));\n    }\n\n    public static MetadataEvent toServiceSubscribeEvent(ApplicationModel applicationModel, String serviceKey) {\n        MetadataEvent metadataEvent = new MetadataEvent(\n                applicationModel,\n                new TypeWrapper(\n                        MetricsLevel.APP,\n                        STORE_PROVIDER_METADATA,\n                        STORE_PROVIDER_METADATA_SUCCEED,\n                        STORE_PROVIDER_METADATA_FAILED));\n        metadataEvent.putAttachment(ATTACHMENT_KEY_SERVICE, serviceKey);\n        return metadataEvent;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetadataSubDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metadata.event;\n\nimport org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster;\nimport org.apache.dubbo.metrics.listener.MetricsApplicationListener;\nimport org.apache.dubbo.metrics.listener.MetricsServiceListener;\nimport org.apache.dubbo.metrics.metadata.collector.MetadataMetricsCollector;\nimport org.apache.dubbo.metrics.model.key.CategoryOverall;\nimport org.apache.dubbo.metrics.model.key.MetricsCat;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_PUSH;\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_STORE_PROVIDER_INTERFACE;\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_SUBSCRIBE;\n\npublic final class MetadataSubDispatcher extends SimpleMetricsEventMulticaster {\n\n    public MetadataSubDispatcher(MetadataMetricsCollector collector) {\n\n        CategorySet.ALL.forEach(categorySet -> {\n            super.addListener(categorySet.getPost().getEventFunc().apply(collector));\n            if (categorySet.getFinish() != null) {\n                super.addListener(categorySet.getFinish().getEventFunc().apply(collector));\n            }\n            if (categorySet.getError() != null) {\n                super.addListener(categorySet.getError().getEventFunc().apply(collector));\n            }\n        });\n    }\n\n    /**\n     * A closer aggregation of MetricsCat, a summary collection of certain types of events\n     */\n    interface CategorySet {\n        CategoryOverall APPLICATION_PUSH = new CategoryOverall(\n                OP_TYPE_PUSH, MCat.APPLICATION_PUSH_POST, MCat.APPLICATION_PUSH_FINISH, MCat.APPLICATION_PUSH_ERROR);\n        CategoryOverall APPLICATION_SUBSCRIBE = new CategoryOverall(\n                OP_TYPE_SUBSCRIBE,\n                MCat.APPLICATION_SUBSCRIBE_POST,\n                MCat.APPLICATION_SUBSCRIBE_FINISH,\n                MCat.APPLICATION_SUBSCRIBE_ERROR);\n        CategoryOverall SERVICE_SUBSCRIBE = new CategoryOverall(\n                OP_TYPE_STORE_PROVIDER_INTERFACE,\n                MCat.SERVICE_SUBSCRIBE_POST,\n                MCat.SERVICE_SUBSCRIBE_FINISH,\n                MCat.SERVICE_SUBSCRIBE_ERROR);\n\n        List<CategoryOverall> ALL = Arrays.asList(APPLICATION_PUSH, APPLICATION_SUBSCRIBE, SERVICE_SUBSCRIBE);\n    }\n\n    /**\n     *  {@link MetricsCat} MetricsCat collection, for better classification processing\n     *  Except for a few custom functions, most of them can build standard event listening functions through the static methods of MetricsApplicationListener\n     */\n    interface MCat {\n        // MetricsPushListener\n        MetricsCat APPLICATION_PUSH_POST =\n                new MetricsCat(MetricsKey.METADATA_PUSH_METRIC_NUM, MetricsApplicationListener::onPostEventBuild);\n        MetricsCat APPLICATION_PUSH_FINISH = new MetricsCat(\n                MetricsKey.METADATA_PUSH_METRIC_NUM_SUCCEED, MetricsApplicationListener::onFinishEventBuild);\n        MetricsCat APPLICATION_PUSH_ERROR = new MetricsCat(\n                MetricsKey.METADATA_PUSH_METRIC_NUM_FAILED, MetricsApplicationListener::onErrorEventBuild);\n\n        // MetricsSubscribeListener\n        MetricsCat APPLICATION_SUBSCRIBE_POST =\n                new MetricsCat(MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM, MetricsApplicationListener::onPostEventBuild);\n        MetricsCat APPLICATION_SUBSCRIBE_FINISH = new MetricsCat(\n                MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED, MetricsApplicationListener::onFinishEventBuild);\n        MetricsCat APPLICATION_SUBSCRIBE_ERROR = new MetricsCat(\n                MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM_FAILED, MetricsApplicationListener::onErrorEventBuild);\n\n        // MetricsSubscribeListener\n        MetricsCat SERVICE_SUBSCRIBE_POST =\n                new MetricsCat(MetricsKey.STORE_PROVIDER_METADATA, MetricsServiceListener::onPostEventBuild);\n        MetricsCat SERVICE_SUBSCRIBE_FINISH =\n                new MetricsCat(MetricsKey.STORE_PROVIDER_METADATA_SUCCEED, MetricsServiceListener::onFinishEventBuild);\n        MetricsCat SERVICE_SUBSCRIBE_ERROR =\n                new MetricsCat(MetricsKey.STORE_PROVIDER_METADATA_FAILED, MetricsServiceListener::onErrorEventBuild);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-metadata/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector",
    "content": "metadata-collector=org.apache.dubbo.metrics.metadata.collector.MetadataMetricsCollector\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-metadata/src/test/java/org/apache/dubbo/metrics/metadata/MetadataMetricsCollectorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metadata;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.metrics.event.MetricsEvent;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.metadata.collector.MetadataMetricsCollector;\nimport org.apache.dubbo.metrics.metadata.event.MetadataEvent;\nimport org.apache.dubbo.metrics.model.TimePair;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_PUSH;\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_STORE_PROVIDER_INTERFACE;\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_SUBSCRIBE;\n\nclass MetadataMetricsCollectorTest {\n\n    private ApplicationModel applicationModel;\n\n    private MetadataMetricsCollector collector;\n\n    @BeforeEach\n    public void setup() {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        applicationModel = frameworkModel.newApplication();\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n\n        applicationModel.getApplicationConfigManager().setApplication(config);\n        applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);\n\n        collector = applicationModel.getBeanFactory().getOrRegisterBean(MetadataMetricsCollector.class);\n        collector.setCollectEnabled(true);\n    }\n\n    @Test\n    void testListener() {\n        MetadataEvent event = MetadataEvent.toPushEvent(applicationModel);\n        MetricsEvent otherEvent = new MetricsEvent(applicationModel, null, null, null) {};\n        Assertions.assertTrue(collector.isSupport(event));\n        Assertions.assertFalse(collector.isSupport(otherEvent));\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    @Test\n    void testPushMetrics() {\n        //        MetadataMetricsCollector collector = getCollector();\n\n        MetadataEvent pushEvent = MetadataEvent.toPushEvent(applicationModel);\n        MetricsEventBus.post(pushEvent, () -> {\n            List<MetricSample> metricSamples = collector.collect();\n\n            // push success +1\n            Assertions.assertEquals(MetadataMetricsConstants.APP_LEVEL_KEYS.size(), metricSamples.size());\n            Assertions.assertTrue(\n                    metricSamples.stream().allMatch(metricSample -> metricSample instanceof GaugeMetricSample));\n            Assertions.assertTrue(metricSamples.stream()\n                    .anyMatch(metricSample -> ((GaugeMetricSample) metricSample).applyAsDouble() == 1));\n            return null;\n        });\n\n        // push finish rt +1\n        List<MetricSample> metricSamples = collector.collect();\n        // App(6) + rt(5) = 7\n        Assertions.assertEquals(MetadataMetricsConstants.APP_LEVEL_KEYS.size() + 5, metricSamples.size());\n        long c1 = pushEvent.getTimePair().calc();\n\n        pushEvent = MetadataEvent.toPushEvent(applicationModel);\n        TimePair lastTimePair = pushEvent.getTimePair();\n        MetricsEventBus.post(\n                pushEvent,\n                () -> {\n                    try {\n                        Thread.sleep(50);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    return null;\n                },\n                Objects::nonNull);\n        // push error rt +1\n        long c2 = lastTimePair.calc();\n        metricSamples = collector.collect();\n\n        // App(6) + rt(5)\n        Assertions.assertEquals(MetadataMetricsConstants.APP_LEVEL_KEYS.size() + 5, metricSamples.size());\n\n        // calc rt\n        for (MetricSample sample : metricSamples) {\n            Map<String, String> tags = sample.getTags();\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());\n        }\n\n        @SuppressWarnings(\"rawtypes\")\n        Map<String, Long> sampleMap = metricSamples.stream()\n                .collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));\n\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_LAST, OP_TYPE_PUSH).targetKey()),\n                lastTimePair.calc());\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MIN, OP_TYPE_PUSH).targetKey()),\n                Math.min(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MAX, OP_TYPE_PUSH).targetKey()),\n                Math.max(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_AVG, OP_TYPE_PUSH).targetKey()),\n                (c1 + c2) / 2);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_SUM, OP_TYPE_PUSH).targetKey()), c1 + c2);\n    }\n\n    @Test\n    void testSubscribeMetrics() {\n        //        MetadataMetricsCollector collector = getCollector();\n\n        MetadataEvent subscribeEvent = MetadataEvent.toSubscribeEvent(applicationModel);\n        MetricsEventBus.post(subscribeEvent, () -> {\n            List<MetricSample> metricSamples = collector.collect();\n\n            // push success +1\n            Assertions.assertEquals(MetadataMetricsConstants.APP_LEVEL_KEYS.size(), metricSamples.size());\n            Assertions.assertTrue(\n                    metricSamples.stream().allMatch(metricSample -> metricSample instanceof GaugeMetricSample));\n            Assertions.assertTrue(metricSamples.stream()\n                    .anyMatch(metricSample -> ((GaugeMetricSample) metricSample).applyAsDouble() == 1));\n            return null;\n        });\n        long c1 = subscribeEvent.getTimePair().calc();\n\n        // push finish rt +1\n        List<MetricSample> metricSamples = collector.collect();\n        // App(6) + rt(5) = 7\n        Assertions.assertEquals(MetadataMetricsConstants.APP_LEVEL_KEYS.size() + 5, metricSamples.size());\n\n        subscribeEvent = MetadataEvent.toSubscribeEvent(applicationModel);\n        TimePair lastTimePair = subscribeEvent.getTimePair();\n        MetricsEventBus.post(\n                subscribeEvent,\n                () -> {\n                    try {\n                        Thread.sleep(50);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    return null;\n                },\n                Objects::nonNull);\n\n        // push error rt +1\n        long c2 = lastTimePair.calc();\n        metricSamples = collector.collect();\n\n        // App(6) + rt(5)\n        Assertions.assertEquals(MetadataMetricsConstants.APP_LEVEL_KEYS.size() + 5, metricSamples.size());\n\n        // calc rt\n        for (MetricSample sample : metricSamples) {\n            Map<String, String> tags = sample.getTags();\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());\n        }\n\n        @SuppressWarnings(\"rawtypes\")\n        Map<String, Long> sampleMap = metricSamples.stream()\n                .collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));\n\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_LAST, OP_TYPE_SUBSCRIBE).targetKey()),\n                lastTimePair.calc());\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MIN, OP_TYPE_SUBSCRIBE).targetKey()),\n                Math.min(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MAX, OP_TYPE_SUBSCRIBE).targetKey()),\n                Math.max(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_AVG, OP_TYPE_SUBSCRIBE).targetKey()),\n                (c1 + c2) / 2);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_SUM, OP_TYPE_SUBSCRIBE).targetKey()), c1 + c2);\n    }\n\n    @Test\n    void testStoreProviderMetadataMetrics() {\n        //        MetadataMetricsCollector collector = getCollector();\n\n        String serviceKey = \"store.provider.test\";\n        MetadataEvent metadataEvent = MetadataEvent.toServiceSubscribeEvent(applicationModel, serviceKey);\n        MetricsEventBus.post(metadataEvent, () -> {\n            List<MetricSample> metricSamples = collector.collect();\n\n            // App(6) + service success(1)\n            Assertions.assertEquals(MetadataMetricsConstants.APP_LEVEL_KEYS.size() + 1, metricSamples.size());\n            Assertions.assertTrue(\n                    metricSamples.stream().allMatch(metricSample -> metricSample instanceof GaugeMetricSample));\n            Assertions.assertTrue(metricSamples.stream()\n                    .anyMatch(metricSample -> ((GaugeMetricSample) metricSample).applyAsDouble() == 1));\n            return null;\n        });\n\n        // push finish rt +1\n        List<MetricSample> metricSamples = collector.collect();\n        // App(6) + service total/success(2) + rt(5) = 7\n        Assertions.assertEquals(MetadataMetricsConstants.APP_LEVEL_KEYS.size() + 2 + 5, metricSamples.size());\n\n        long c1 = metadataEvent.getTimePair().calc();\n        metadataEvent = MetadataEvent.toServiceSubscribeEvent(applicationModel, serviceKey);\n        TimePair lastTimePair = metadataEvent.getTimePair();\n        MetricsEventBus.post(\n                metadataEvent,\n                () -> {\n                    try {\n                        Thread.sleep(50);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    return null;\n                },\n                Objects::nonNull);\n        // push error rt +1\n        long c2 = lastTimePair.calc();\n\n        metricSamples = collector.collect();\n\n        // App(6) + service total/success/failed(3) + rt(5)\n        Assertions.assertEquals(MetadataMetricsConstants.APP_LEVEL_KEYS.size() + 3 + 5, metricSamples.size());\n\n        // calc rt\n        for (MetricSample sample : metricSamples) {\n            Map<String, String> tags = sample.getTags();\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());\n        }\n\n        @SuppressWarnings(\"rawtypes\")\n        Map<String, Long> sampleMap = metricSamples.stream()\n                .collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));\n\n        Assertions.assertEquals(\n                sampleMap.get(\n                        new MetricsKeyWrapper(MetricsKey.METRIC_RT_LAST, OP_TYPE_STORE_PROVIDER_INTERFACE).targetKey()),\n                lastTimePair.calc());\n        Assertions.assertEquals(\n                sampleMap.get(\n                        new MetricsKeyWrapper(MetricsKey.METRIC_RT_MIN, OP_TYPE_STORE_PROVIDER_INTERFACE).targetKey()),\n                Math.min(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(\n                        new MetricsKeyWrapper(MetricsKey.METRIC_RT_MAX, OP_TYPE_STORE_PROVIDER_INTERFACE).targetKey()),\n                Math.max(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(\n                        new MetricsKeyWrapper(MetricsKey.METRIC_RT_AVG, OP_TYPE_STORE_PROVIDER_INTERFACE).targetKey()),\n                (c1 + c2) / 2);\n        Assertions.assertEquals(\n                sampleMap.get(\n                        new MetricsKeyWrapper(MetricsKey.METRIC_RT_SUM, OP_TYPE_STORE_PROVIDER_INTERFACE).targetKey()),\n                c1 + c2);\n    }\n\n    @Test\n    void testMetadataPushNum() {\n\n        for (int i = 0; i < 10; i++) {\n            MetadataEvent event = MetadataEvent.toPushEvent(applicationModel);\n            if (i % 2 == 0) {\n                MetricsEventBus.post(event, () -> true, r -> r);\n            } else {\n                MetricsEventBus.post(event, () -> false, r -> r);\n            }\n        }\n\n        List<MetricSample> samples = collector.collect();\n\n        GaugeMetricSample<?> totalNum = getSample(MetricsKey.METADATA_PUSH_METRIC_NUM.getName(), samples);\n        GaugeMetricSample<?> succeedNum = getSample(MetricsKey.METADATA_PUSH_METRIC_NUM_SUCCEED.getName(), samples);\n        GaugeMetricSample<?> failedNum = getSample(MetricsKey.METADATA_PUSH_METRIC_NUM_FAILED.getName(), samples);\n\n        Assertions.assertEquals(10, totalNum.applyAsLong());\n        Assertions.assertEquals(5, succeedNum.applyAsLong());\n        Assertions.assertEquals(5, failedNum.applyAsLong());\n    }\n\n    @Test\n    void testSubscribeSum() {\n\n        for (int i = 0; i < 10; i++) {\n            MetadataEvent event = MetadataEvent.toSubscribeEvent(applicationModel);\n            if (i % 2 == 0) {\n                MetricsEventBus.post(event, () -> true, r -> r);\n            } else {\n                MetricsEventBus.post(event, () -> false, r -> r);\n            }\n        }\n\n        List<MetricSample> samples = collector.collect();\n\n        GaugeMetricSample<?> totalNum = getSample(MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM.getName(), samples);\n        GaugeMetricSample<?> succeedNum =\n                getSample(MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED.getName(), samples);\n        GaugeMetricSample<?> failedNum = getSample(MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM_FAILED.getName(), samples);\n\n        Assertions.assertEquals(10, totalNum.applyAsLong());\n        Assertions.assertEquals(5, succeedNum.applyAsLong());\n        Assertions.assertEquals(5, failedNum.applyAsLong());\n    }\n\n    GaugeMetricSample<?> getSample(String name, List<MetricSample> samples) {\n        return (GaugeMetricSample<?>) samples.stream()\n                .filter(metricSample -> metricSample.getName().equals(name))\n                .findFirst()\n                .orElseThrow(NoSuchElementException::new);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-metadata/src/test/java/org/apache/dubbo/metrics/metadata/MetadataStatCompositeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.metadata;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metrics.data.ApplicationStatComposite;\nimport org.apache.dubbo.metrics.data.BaseStatComposite;\nimport org.apache.dubbo.metrics.data.RtStatComposite;\nimport org.apache.dubbo.metrics.data.ServiceStatComposite;\nimport org.apache.dubbo.metrics.model.ApplicationMetric;\nimport org.apache.dubbo.metrics.model.Metric;\nimport org.apache.dubbo.metrics.model.container.LongContainer;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_PUSH;\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_STORE_PROVIDER_INTERFACE;\nimport static org.apache.dubbo.metrics.metadata.MetadataMetricsConstants.OP_TYPE_SUBSCRIBE;\n\npublic class MetadataStatCompositeTest {\n    private ApplicationModel applicationModel;\n    private BaseStatComposite statComposite;\n\n    @BeforeEach\n    public void setup() {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        applicationModel = frameworkModel.newApplication();\n        ApplicationConfig application = new ApplicationConfig();\n        application.setName(\"App1\");\n        applicationModel.getApplicationConfigManager().setApplication(application);\n        statComposite = new BaseStatComposite(applicationModel) {\n            @Override\n            protected void init(ApplicationStatComposite applicationStatComposite) {\n                super.init(applicationStatComposite);\n                applicationStatComposite.init(MetadataMetricsConstants.APP_LEVEL_KEYS);\n            }\n\n            @Override\n            protected void init(ServiceStatComposite serviceStatComposite) {\n                super.init(serviceStatComposite);\n                serviceStatComposite.initWrapper(MetadataMetricsConstants.SERVICE_LEVEL_KEYS);\n            }\n\n            @Override\n            protected void init(RtStatComposite rtStatComposite) {\n                super.init(rtStatComposite);\n                rtStatComposite.init(OP_TYPE_PUSH, OP_TYPE_SUBSCRIBE, OP_TYPE_STORE_PROVIDER_INTERFACE);\n            }\n        };\n    }\n\n    @Test\n    void testInit() {\n        Assertions.assertEquals(\n                statComposite\n                        .getApplicationStatComposite()\n                        .getApplicationNumStats()\n                        .size(),\n                MetadataMetricsConstants.APP_LEVEL_KEYS.size());\n\n        // (rt)5 * (push,subscribe,service)3\n        Assertions.assertEquals(\n                5 * 3, statComposite.getRtStatComposite().getRtStats().size());\n        statComposite\n                .getApplicationStatComposite()\n                .getApplicationNumStats()\n                .values()\n                .forEach((v -> Assertions.assertEquals(v.get(), new AtomicLong(0L).get())));\n        statComposite.getRtStatComposite().getRtStats().forEach(rtContainer -> {\n            for (Map.Entry<Metric, ? extends Number> entry : rtContainer.entrySet()) {\n                Assertions.assertEquals(0L, rtContainer.getValueSupplier().apply(entry.getKey()));\n            }\n        });\n    }\n\n    @Test\n    void testIncrement() {\n        statComposite.incrementApp(MetricsKey.METADATA_PUSH_METRIC_NUM, 1);\n\n        Assertions.assertEquals(\n                1L,\n                statComposite\n                        .getApplicationStatComposite()\n                        .getApplicationNumStats()\n                        .get(MetricsKey.METADATA_PUSH_METRIC_NUM)\n                        .get());\n    }\n\n    @Test\n    void testCalcRt() {\n        statComposite.calcApplicationRt(OP_TYPE_SUBSCRIBE.getType(), 10L);\n        Assertions.assertTrue(statComposite.getRtStatComposite().getRtStats().stream()\n                .anyMatch(longContainer -> longContainer.specifyType(OP_TYPE_SUBSCRIBE.getType())));\n        Optional<LongContainer<? extends Number>> subContainer =\n                statComposite.getRtStatComposite().getRtStats().stream()\n                        .filter(longContainer -> longContainer.specifyType(OP_TYPE_SUBSCRIBE.getType()))\n                        .findFirst();\n        subContainer.ifPresent(v -> Assertions.assertEquals(\n                10L, v.get(new ApplicationMetric(applicationModel)).longValue()));\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-metadata/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-netty/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metrics</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-metrics-netty</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The metrics module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/NettyMetricsConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry;\n\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_CHUNK_SIZE;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_DIRECT_ARENAS_NUM;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_DIRECT_MEMORY_USED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_HEAP_ARENAS_NUM;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_HEAP_MEMORY_USED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_NORMAL_CACHE_SIZE;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_PINNED_DIRECT_MEMORY;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_PINNED_HEAP_MEMORY;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_SMALL_CACHE_SIZE;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_THREAD_LOCAL_CACHES_NUM;\n\npublic interface NettyMetricsConstants {\n\n    // App-level\n    List<MetricsKey> APP_LEVEL_KEYS = Arrays.asList(\n            NETTY_ALLOCATOR_HEAP_MEMORY_USED,\n            NETTY_ALLOCATOR_DIRECT_MEMORY_USED,\n            NETTY_ALLOCATOR_PINNED_DIRECT_MEMORY,\n            NETTY_ALLOCATOR_PINNED_HEAP_MEMORY,\n            NETTY_ALLOCATOR_HEAP_ARENAS_NUM,\n            NETTY_ALLOCATOR_DIRECT_ARENAS_NUM,\n            NETTY_ALLOCATOR_NORMAL_CACHE_SIZE,\n            NETTY_ALLOCATOR_SMALL_CACHE_SIZE,\n            NETTY_ALLOCATOR_THREAD_LOCAL_CACHES_NUM,\n            NETTY_ALLOCATOR_CHUNK_SIZE);\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/collector/NettyMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.collector;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.metrics.collector.CombMetricsCollector;\nimport org.apache.dubbo.metrics.collector.MetricsCollector;\nimport org.apache.dubbo.metrics.data.ApplicationStatComposite;\nimport org.apache.dubbo.metrics.data.BaseStatComposite;\nimport org.apache.dubbo.metrics.data.RtStatComposite;\nimport org.apache.dubbo.metrics.data.ServiceStatComposite;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.registry.NettyMetricsConstants;\nimport org.apache.dubbo.metrics.registry.event.NettyEvent;\nimport org.apache.dubbo.metrics.registry.event.NettySubDispatcher;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * Netty implementation of {@link MetricsCollector}\n */\n@Activate\npublic class NettyMetricsCollector extends CombMetricsCollector<NettyEvent> {\n\n    private Boolean collectEnabled = null;\n    private final ApplicationModel applicationModel;\n\n    public NettyMetricsCollector(ApplicationModel applicationModel) {\n        super(new BaseStatComposite(applicationModel) {\n            @Override\n            protected void init(ApplicationStatComposite applicationStatComposite) {\n                super.init(applicationStatComposite);\n                applicationStatComposite.init(NettyMetricsConstants.APP_LEVEL_KEYS);\n            }\n\n            @Override\n            protected void init(ServiceStatComposite serviceStatComposite) {\n                super.init(serviceStatComposite);\n            }\n\n            @Override\n            protected void init(RtStatComposite rtStatComposite) {\n                super.init(rtStatComposite);\n            }\n        });\n        super.setEventMulticaster(new NettySubDispatcher(this));\n        this.applicationModel = applicationModel;\n    }\n\n    public void setCollectEnabled(Boolean collectEnabled) {\n        if (collectEnabled != null) {\n            this.collectEnabled = collectEnabled;\n        }\n    }\n\n    @Override\n    public boolean isCollectEnabled() {\n        if (collectEnabled == null) {\n            ConfigManager configManager = applicationModel.getApplicationConfigManager();\n            configManager.getMetrics().ifPresent(metricsConfig -> setCollectEnabled(metricsConfig.getEnableNetty()));\n        }\n        return Optional.ofNullable(collectEnabled).orElse(false);\n    }\n\n    @Override\n    public List<MetricSample> collect() {\n        List<MetricSample> list = new ArrayList<>();\n        if (!isCollectEnabled()) {\n            return list;\n        }\n        list.addAll(super.export(MetricsCategory.NETTY));\n        return list;\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        return stats.calSamplesChanged();\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/event/NettyEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.event;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.TypeWrapper;\nimport org.apache.dubbo.metrics.registry.collector.NettyMetricsCollector;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.NETTY_METRICS_MAP;\n\n/**\n * Netty related events\n */\npublic class NettyEvent extends TimeCounterEvent {\n    public NettyEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) {\n        super(applicationModel, typeWrapper);\n        ScopeBeanFactory beanFactory = getSource().getBeanFactory();\n        NettyMetricsCollector collector;\n        if (!beanFactory.isDestroyed()) {\n            collector = beanFactory.getBean(NettyMetricsCollector.class);\n            super.setAvailable(collector != null && collector.isCollectEnabled());\n        }\n    }\n\n    public static NettyEvent toNettyEvent(ApplicationModel applicationModel) {\n        return new NettyEvent(applicationModel, new TypeWrapper(MetricsLevel.APP, null, null, null)) {\n            @Override\n            public void customAfterPost(Object postResult) {\n                super.putAttachment(NETTY_METRICS_MAP, postResult);\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/event/NettySubDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.event;\n\nimport org.apache.dubbo.metrics.event.MetricsEvent;\nimport org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.registry.collector.NettyMetricsCollector;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.NETTY_METRICS_MAP;\n\npublic final class NettySubDispatcher extends SimpleMetricsEventMulticaster {\n\n    public NettySubDispatcher(NettyMetricsCollector collector) {\n        super.addListener(new AbstractMetricsKeyListener(null) {\n            @Override\n            public boolean isSupport(MetricsEvent event) {\n                return true;\n            }\n\n            @Override\n            public void onEventFinish(TimeCounterEvent event) {\n                Map<String, Long> lastNumMap = Collections.unmodifiableMap(event.getAttachmentValue(NETTY_METRICS_MAP));\n                lastNumMap.forEach((k, v) -> {\n                    MetricsKey metricsKey = MetricsKey.getMetricsByName(k);\n                    collector.setAppNum(metricsKey, v);\n                });\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-netty/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector",
    "content": "org.apache.dubbo.metrics.registry.collector.NettyMetricsCollector\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-otlp/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metrics</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-metrics-otlp</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The otlp metrics module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.httpcomponents</groupId>\n      <artifactId>httpclient</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos-api</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>compile</scope>\n    </dependency>\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-registry-otlp</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>com.squareup.okhttp3</groupId>\n      <artifactId>mockwebserver</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-otlp/src/main/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.otlp;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.MetricsConstants;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.nested.OtlpMetricConfig;\nimport org.apache.dubbo.metrics.report.AbstractMetricsReporter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.time.Duration;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.registry.otlp.AggregationTemporality;\nimport io.micrometer.registry.otlp.OtlpConfig;\nimport io.micrometer.registry.otlp.OtlpMeterRegistry;\n\n/**\n * Metrics reporter for Otlp.\n */\npublic class OtlpMetricsReporter extends AbstractMetricsReporter {\n\n    private final OtlpMeterRegistry otlpMeterRegistry;\n\n    public OtlpMetricsReporter(final URL url, ApplicationModel applicationModel) {\n        super(url, applicationModel);\n        Optional<MetricsConfig> configOptional =\n                applicationModel.getApplicationConfigManager().getMetrics();\n        // If no specific metrics type is configured and there is no Prometheus dependency in the dependencies.\n        MetricsConfig metricsConfig = configOptional.orElse(new MetricsConfig(applicationModel));\n        OtlpMetricConfig otlpMetricConfig = metricsConfig.getOtlp();\n        // check protocol whether is otlp\n        if (otlpMetricConfig == null || !MetricsConstants.PROTOCOL_OTLP.equals(metricsConfig.getProtocol())) {\n            throw new IllegalStateException(\n                    \"Otlp metrics reporter config is required oltp protocol but real does not match.\");\n        }\n\n        OtlpConfig config = new OtlpWrapperConfig(otlpMetricConfig, applicationModel);\n        this.otlpMeterRegistry = new OtlpMeterRegistry(config, Clock.SYSTEM);\n    }\n\n    @Override\n    public void doInit() {\n        addMeterRegistry(this.otlpMeterRegistry);\n    }\n\n    @Override\n    public String getResponse() {\n        return null;\n    }\n\n    @Override\n    public void doDestroy() {\n        if (this.otlpMeterRegistry != null) {\n            this.otlpMeterRegistry.close();\n        }\n    }\n\n    public static class OtlpWrapperConfig implements OtlpConfig {\n\n        private final OtlpMetricConfig otlpMetricConfig;\n        private final ApplicationModel applicationModel;\n\n        public OtlpWrapperConfig(OtlpMetricConfig otlpMetricConfig, ApplicationModel applicationModel) {\n            this.otlpMetricConfig = otlpMetricConfig;\n            this.applicationModel = applicationModel;\n        }\n\n        @Override\n        public String get(String key) {\n            // just use default value\n            return OtlpConfig.DEFAULT.get(key);\n        }\n\n        @Override\n        public String url() {\n            if (this.otlpMetricConfig.getEndpoint() == null) {\n                return OtlpConfig.super.url();\n            }\n            return this.otlpMetricConfig.getEndpoint();\n        }\n\n        @Override\n        public Duration step() {\n            if (this.otlpMetricConfig.getStep() == null) {\n                return OtlpConfig.super.step();\n            }\n            return this.otlpMetricConfig.getStep();\n        }\n\n        @Override\n        public Map<String, String> resourceAttributes() {\n            Map<String, String> resourceAttributes = this.otlpMetricConfig.getResourceAttributes();\n            if (resourceAttributes == null) {\n                resourceAttributes = OtlpConfig.super.resourceAttributes();\n            }\n            // set service.name\n            resourceAttributes.computeIfAbsent(\"service.name\", (key) -> getApplicationName());\n            return resourceAttributes;\n        }\n\n        @Override\n        public AggregationTemporality aggregationTemporality() {\n            return OtlpConfig.super.aggregationTemporality();\n        }\n\n        @Override\n        public Map<String, String> headers() {\n            Map<String, String> headers = this.otlpMetricConfig.getHeaders();\n            if (headers == null) {\n                headers = OtlpConfig.super.headers();\n            }\n            return headers;\n        }\n\n        @Override\n        public TimeUnit baseTimeUnit() {\n            return this.otlpMetricConfig.getBaseTimeUnit();\n        }\n\n        private String getApplicationName() {\n            return this.applicationModel.getApplicationName();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-otlp/src/main/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.otlp;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metrics.report.AbstractMetricsReporterFactory;\nimport org.apache.dubbo.metrics.report.MetricsReporter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\npublic class OtlpMetricsReporterFactory extends AbstractMetricsReporterFactory {\n\n    public OtlpMetricsReporterFactory(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    @Override\n    public MetricsReporter createMetricsReporter(URL url) {\n        return new OtlpMetricsReporter(url, getApplicationModel());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-otlp/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.report.MetricsReporterFactory",
    "content": "otlp=org.apache.dubbo.metrics.otlp.OtlpMetricsReporterFactory\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-otlp/src/test/java/org/apache/dubbo/metrics/otlp/OtlpMetricsReporterFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.otlp;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.nested.AggregationConfig;\nimport org.apache.dubbo.config.nested.OtlpMetricConfig;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.report.MetricsReporter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.TimeUnit;\n\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport okhttp3.mockwebserver.RecordedRequest;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_OTLP;\n\npublic class OtlpMetricsReporterFactoryTest {\n\n    private MockWebServer otlpMockServer;\n    private CopyOnWriteArrayList<byte[]> capturedRequests;\n    private ApplicationModel applicationModel;\n    private MetricsConfig metricsConfig;\n    private FrameworkModel frameworkModel;\n\n    @BeforeEach\n    public void setup() {\n        otlpMockServer = new MockWebServer();\n        for (int i = 0; i < 100; i++) {\n            otlpMockServer.enqueue(new MockResponse()\n                    .setResponseCode(200)\n                    .setBody(\"{}\")\n                    .addHeader(\"Content-Type\", \"application/json\"));\n        }\n        applicationModel = ApplicationModel.defaultModel();\n        ConfigManager applicationConfigManager = applicationModel.getApplicationConfigManager();\n        metricsConfig = new MetricsConfig();\n        metricsConfig.setEnableJvm(true);\n        metricsConfig.setProtocol(PROTOCOL_OTLP);\n        AggregationConfig aggregationConfig = new AggregationConfig();\n        aggregationConfig.setEnabled(false);\n        metricsConfig.setAggregation(aggregationConfig);\n        OtlpMetricConfig otlpMetricsConfig = new OtlpMetricConfig();\n        otlpMetricsConfig.setStep(Duration.ofSeconds(1));\n        metricsConfig.setOtlp(otlpMetricsConfig);\n        otlpMetricsConfig.setUrl(otlpMockServer.url(\"/v1/metrics\").toString());\n        applicationConfigManager.setMetrics(metricsConfig);\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"test_app_name\");\n        applicationConfigManager.setApplication(applicationConfig);\n        frameworkModel = FrameworkModel.defaultModel();\n        frameworkModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);\n    }\n\n    @AfterEach\n    public void teardown() throws IOException {\n        applicationModel.destroy();\n        if (otlpMockServer != null) {\n            otlpMockServer.shutdown();\n        }\n    }\n\n    @Test\n    public void test_MetricsReporter() {\n\n        OtlpMetricsReporterFactory factory = new OtlpMetricsReporterFactory(applicationModel);\n        MetricsReporter reporter = factory.createMetricsReporter(metricsConfig.toUrl());\n        Assertions.assertTrue(reporter instanceof OtlpMetricsReporter);\n        applicationModel.destroy();\n    }\n\n    @Test\n    public void test_MetricsReporter_with_not_match_protocol() {\n        OtlpMetricsReporterFactory factory = new OtlpMetricsReporterFactory(applicationModel);\n        try {\n            factory.createMetricsReporter(metricsConfig.toUrl());\n        } catch (Exception ex) {\n            Assertions.assertInstanceOf(IllegalStateException.class, ex);\n        }\n    }\n\n    @Test\n    public void export_Test() throws IOException, InterruptedException {\n\n        OtlpMetricsReporter reporter = new OtlpMetricsReporter(metricsConfig.toUrl(), applicationModel);\n        reporter.init();\n        try {\n\n            List<String> requestBodies = new ArrayList<>();\n\n            long endTime = System.currentTimeMillis() + 3000;\n            while (System.currentTimeMillis() < endTime) {\n                RecordedRequest request = otlpMockServer.takeRequest(500, TimeUnit.MILLISECONDS);\n                if (request != null) {\n                    String body = request.getBody().readString(StandardCharsets.UTF_8);\n                    requestBodies.add(body);\n                }\n            }\n\n            Assertions.assertFalse(requestBodies.isEmpty(), \"Expected OTLP metrics to be pushed\");\n\n            boolean hasJvmMetrics = requestBodies.stream()\n                    .anyMatch(body -> body.contains(\"jvm\")\n                            || body.contains(\"JVM\")\n                            || body.contains(\"memory\")\n                            || body.contains(\"gc\")\n                            || body.contains(\"threads\"));\n\n            Assertions.assertTrue(\n                    hasJvmMetrics,\n                    \"Expected JVM metrics to be present in OTLP export.  Captured bodies: \" + requestBodies.size());\n\n        } finally {\n            reporter.destroy();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metrics</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-metrics-prometheus</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The prometheus metrics module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-registry-prometheus-simpleclient</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.prometheus</groupId>\n      <artifactId>simpleclient_pushgateway</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.httpcomponents</groupId>\n      <artifactId>httpclient</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos-api</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>compile</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/src/main/java/org/apache/dubbo/metrics/prometheus/NopPrometheusMetricsReporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.prometheus;\n\nimport org.apache.dubbo.metrics.report.MetricsReporter;\n\n/**\n * NopMetricsReporter is a trivial implementation of MetricsReporter\n * which do nothing when micro-meter package is not exist.\n */\npublic class NopPrometheusMetricsReporter implements MetricsReporter {\n\n    @Override\n    public void init() {}\n\n    @Override\n    public void resetIfSamplesChanged() {}\n\n    @Override\n    public String getResponse() {\n        return \"\";\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/src/main/java/org/apache/dubbo/metrics/prometheus/PrometheusMetricsReporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.prometheus;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metrics.report.AbstractMetricsReporter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.io.IOException;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.prometheus.PrometheusConfig;\nimport io.micrometer.prometheus.PrometheusMeterRegistry;\nimport io.prometheus.client.exporter.BasicAuthHttpConnectionFactory;\nimport io.prometheus.client.exporter.PushGateway;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROMETHEUS_DEFAULT_JOB_NAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROMETHEUS_DEFAULT_PUSH_INTERVAL;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROMETHEUS_PUSHGATEWAY_BASE_URL_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROMETHEUS_PUSHGATEWAY_ENABLED_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROMETHEUS_PUSHGATEWAY_JOB_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROMETHEUS_PUSHGATEWAY_PASSWORD_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROMETHEUS_PUSHGATEWAY_PUSH_INTERVAL_KEY;\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROMETHEUS_PUSHGATEWAY_USERNAME_KEY;\n\n/**\n * Metrics reporter for prometheus.\n */\npublic class PrometheusMetricsReporter extends AbstractMetricsReporter {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(PrometheusMetricsReporter.class);\n\n    private final PrometheusMeterRegistry prometheusRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);\n    private ScheduledExecutorService pushJobExecutor = null;\n\n    public PrometheusMetricsReporter(URL url, ApplicationModel applicationModel) {\n        super(url, applicationModel);\n    }\n\n    @Override\n    public void doInit() {\n        addMeterRegistry(prometheusRegistry);\n        schedulePushJob();\n    }\n\n    public String getResponse() {\n        return prometheusRegistry.scrape();\n    }\n\n    private void schedulePushJob() {\n        boolean pushEnabled = url.getParameter(PROMETHEUS_PUSHGATEWAY_ENABLED_KEY, false);\n        if (pushEnabled) {\n            String baseUrl = url.getParameter(PROMETHEUS_PUSHGATEWAY_BASE_URL_KEY);\n            String job = url.getParameter(PROMETHEUS_PUSHGATEWAY_JOB_KEY, PROMETHEUS_DEFAULT_JOB_NAME);\n            int pushInterval =\n                    url.getParameter(PROMETHEUS_PUSHGATEWAY_PUSH_INTERVAL_KEY, PROMETHEUS_DEFAULT_PUSH_INTERVAL);\n            String username = url.getParameter(PROMETHEUS_PUSHGATEWAY_USERNAME_KEY);\n            String password = url.getParameter(PROMETHEUS_PUSHGATEWAY_PASSWORD_KEY);\n\n            NamedThreadFactory threadFactory = new NamedThreadFactory(\"prometheus-push-job\", true);\n            pushJobExecutor = Executors.newScheduledThreadPool(1, threadFactory);\n            PushGateway pushGateway = new PushGateway(baseUrl);\n            if (!StringUtils.isBlank(username)) {\n                pushGateway.setConnectionFactory(new BasicAuthHttpConnectionFactory(username, password));\n            }\n\n            pushJobExecutor.scheduleWithFixedDelay(\n                    () -> push(pushGateway, job), pushInterval, pushInterval, TimeUnit.SECONDS);\n        }\n    }\n\n    protected void push(PushGateway pushGateway, String job) {\n        try {\n            resetIfSamplesChanged();\n            pushGateway.pushAdd(prometheusRegistry.getPrometheusRegistry(), job);\n        } catch (IOException e) {\n            logger.error(\n                    COMMON_METRICS_COLLECTOR_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Error occurred when pushing metrics to prometheus: \",\n                    e);\n        }\n    }\n\n    @Override\n    public void doDestroy() {\n\n        if (pushJobExecutor != null) {\n            pushJobExecutor.shutdownNow();\n        }\n    }\n\n    /**\n     * ut only\n     */\n    @Deprecated\n    public ScheduledExecutorService getPushJobExecutor() {\n        return pushJobExecutor;\n    }\n\n    /**\n     * ut only\n     */\n    @Deprecated\n    public PrometheusMeterRegistry getPrometheusRegistry() {\n        return prometheusRegistry;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/src/main/java/org/apache/dubbo/metrics/prometheus/PrometheusMetricsReporterCmd.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.prometheus;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.metrics.report.MetricsReporter;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.CharArrayReader;\nimport java.io.IOException;\nimport java.io.LineNumberReader;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n@Cmd(name = \"metrics\", summary = \"reuse qos report\")\npublic class PrometheusMetricsReporterCmd implements BaseCommand {\n\n    private final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(PrometheusMetricsReporterCmd.class);\n\n    public FrameworkModel frameworkModel;\n\n    public PrometheusMetricsReporterCmd(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n\n        List<ApplicationModel> models = frameworkModel.getApplicationModels();\n        String result = \"There is no application with data\";\n\n        if (notSpecifyApplication(args)) {\n            result = useFirst(models, result);\n        } else {\n            result = specifyApplication(args[0], models);\n        }\n        return result;\n    }\n\n    private boolean notSpecifyApplication(String[] args) {\n        return args == null || args.length == 0;\n    }\n\n    private String useFirst(List<ApplicationModel> models, String result) {\n        for (ApplicationModel model : models) {\n            String current = getResponseByApplication(model);\n            // Contains at least one line \"text/plain; version=0.0.4; charset=utf-8\"\n            if (getLineNumber(current) > 1) {\n                result = current;\n                break;\n            }\n        }\n        return result;\n    }\n\n    private String specifyApplication(String appName, List<ApplicationModel> models) {\n        if (\"application_all\".equals(appName)) {\n            return allApplication(models);\n        } else {\n            return specifySingleApplication(appName, models);\n        }\n    }\n\n    private String specifySingleApplication(String appName, List<ApplicationModel> models) {\n        Optional<ApplicationModel> modelOptional = models.stream()\n                .filter(applicationModel -> appName.equals(applicationModel.getApplicationName()))\n                .findFirst();\n        if (modelOptional.isPresent()) {\n            return getResponseByApplication(modelOptional.get());\n        } else {\n            return \"Not exist application: \" + appName;\n        }\n    }\n\n    private String allApplication(List<ApplicationModel> models) {\n        Map<String, String> appResultMap = new HashMap<>();\n        for (ApplicationModel model : models) {\n            appResultMap.put(model.getApplicationName(), getResponseByApplication(model));\n        }\n        return JsonUtils.toJson(appResultMap);\n    }\n\n    @Override\n    public boolean logResult() {\n        return false;\n    }\n\n    private String getResponseByApplication(ApplicationModel applicationModel) {\n\n        String response = \"MetricsReporter not init\";\n        MetricsReporter metricsReporter = applicationModel.getBeanFactory().getBean(PrometheusMetricsReporter.class);\n        if (metricsReporter != null) {\n            long begin = System.currentTimeMillis();\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"scrape begin\");\n            }\n\n            metricsReporter.resetIfSamplesChanged();\n\n            if (logger.isDebugEnabled()) {\n                logger.debug(String.format(\"scrape end,Elapsed Time：%s\", System.currentTimeMillis() - begin));\n            }\n            response = metricsReporter.getResponse();\n        }\n        return response;\n    }\n\n    private static long getLineNumber(String content) {\n\n        LineNumberReader lnr = new LineNumberReader(new CharArrayReader(content.toCharArray()));\n        try {\n            lnr.skip(Long.MAX_VALUE);\n            lnr.close();\n        } catch (IOException ignore) {\n        }\n        return lnr.getLineNumber();\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/src/main/java/org/apache/dubbo/metrics/prometheus/PrometheusMetricsReporterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.prometheus;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.metrics.report.AbstractMetricsReporterFactory;\nimport org.apache.dubbo.metrics.report.MetricsReporter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\n\n/**\n * MetricsReporterFactory to create PrometheusMetricsReporter.\n */\npublic class PrometheusMetricsReporterFactory extends AbstractMetricsReporterFactory {\n\n    private final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(PrometheusMetricsReporterFactory.class);\n\n    public PrometheusMetricsReporterFactory(ApplicationModel applicationModel) {\n        super(applicationModel);\n    }\n\n    @Override\n    public MetricsReporter createMetricsReporter(URL url) {\n        try {\n            return new PrometheusMetricsReporter(url, getApplicationModel());\n        } catch (NoClassDefFoundError ncde) {\n            String msg = ncde.getMessage();\n            if (dependenciesNotFound(msg)) {\n                logger.error(\n                        INTERNAL_ERROR,\n                        \"\",\n                        \"\",\n                        \"Failed to load class \\\"org.apache.dubbo.metrics.prometheus.PrometheusMetricsReporter\\\".\",\n                        ncde);\n                logger.error(\n                        INTERNAL_ERROR,\n                        \"\",\n                        \"\",\n                        \"Defaulting to no-operation (NOP) metricsReporter implementation\",\n                        ncde);\n                logger.error(\n                        INTERNAL_ERROR,\n                        \"\",\n                        \"\",\n                        \"Introduce the micrometer-core package to use the ability of metrics\",\n                        ncde);\n                return new NopPrometheusMetricsReporter();\n            } else {\n                logger.error(INTERNAL_ERROR, \"\", \"\", \"Failed to instantiate PrometheusMetricsReporter\", ncde);\n                throw ncde;\n            }\n        }\n    }\n\n    private static boolean dependenciesNotFound(String msg) {\n        if (msg == null) {\n            return false;\n        }\n        if (msg.contains(\"io/micrometer/core/instrument/composite/CompositeMeterRegistry\")) {\n            return true;\n        }\n        return msg.contains(\"io.micrometer.core.instrument.composite.CompositeMeterRegistry\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.report.MetricsReporterFactory",
    "content": "prometheus=org.apache.dubbo.metrics.prometheus.PrometheusMetricsReporterFactory\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand",
    "content": "metrics=org.apache.dubbo.metrics.prometheus.PrometheusMetricsReporterCmd\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/src/test/java/org/apache/dubbo/metrics/prometheus/PrometheusMetricsReporterFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.prometheus;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metrics.report.MetricsReporter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass PrometheusMetricsReporterFactoryTest {\n\n    @Test\n    void test() {\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        PrometheusMetricsReporterFactory factory = new PrometheusMetricsReporterFactory(applicationModel);\n        MetricsReporter reporter = factory.createMetricsReporter(URL.valueOf(\"prometheus://localhost:9090/\"));\n\n        Assertions.assertTrue(reporter instanceof PrometheusMetricsReporter);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/src/test/java/org/apache/dubbo/metrics/prometheus/PrometheusMetricsReporterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.prometheus;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.nested.PrometheusConfig;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.net.InetSocketAddress;\nimport java.nio.charset.StandardCharsets;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.stream.Collectors;\n\nimport com.sun.net.httpserver.HttpServer;\nimport io.micrometer.prometheus.PrometheusMeterRegistry;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\n\nclass PrometheusMetricsReporterTest {\n\n    private MetricsConfig metricsConfig;\n    private ApplicationModel applicationModel;\n    private FrameworkModel frameworkModel;\n    HttpServer prometheusExporterHttpServer;\n\n    @BeforeEach\n    public void setup() {\n        metricsConfig = new MetricsConfig();\n        applicationModel = ApplicationModel.defaultModel();\n        metricsConfig.setProtocol(PROTOCOL_PROMETHEUS);\n        frameworkModel = FrameworkModel.defaultModel();\n        frameworkModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n        if (prometheusExporterHttpServer != null) {\n            prometheusExporterHttpServer.stop(0);\n        }\n    }\n\n    @Test\n    void testJvmMetrics() {\n        metricsConfig.setEnableJvm(true);\n        String name = \"metrics-test\";\n        ApplicationModel.defaultModel().getApplicationConfigManager().setApplication(new ApplicationConfig(name));\n\n        PrometheusMetricsReporter reporter = new PrometheusMetricsReporter(metricsConfig.toUrl(), applicationModel);\n        reporter.init();\n\n        PrometheusMeterRegistry prometheusRegistry = reporter.getPrometheusRegistry();\n        Double d1 = prometheusRegistry.getPrometheusRegistry().getSampleValue(\"none_exist_metric\");\n        Double d2 = prometheusRegistry\n                .getPrometheusRegistry()\n                .getSampleValue(\n                        \"jvm_gc_memory_promoted_bytes_total\", new String[] {\"application_name\"}, new String[] {name});\n        Assertions.assertNull(d1);\n        Assertions.assertNull(d2);\n    }\n\n    @Test\n    void testExporter() {\n        int port = 31539;\n        //            NetUtils.getAvailablePort();\n        PrometheusConfig prometheusConfig = new PrometheusConfig();\n        PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();\n        exporter.setEnabled(true);\n        prometheusConfig.setExporter(exporter);\n        metricsConfig.setPrometheus(prometheusConfig);\n        metricsConfig.setEnableJvm(true);\n\n        ApplicationModel.defaultModel()\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(\"metrics-test\"));\n        PrometheusMetricsReporter reporter = new PrometheusMetricsReporter(metricsConfig.toUrl(), applicationModel);\n        reporter.init();\n        exportHttpServer(reporter, port);\n        try {\n            Thread.sleep(5000);\n        } catch (InterruptedException e) {\n            throw new RuntimeException(e);\n        }\n        try (CloseableHttpClient client = HttpClients.createDefault()) {\n            HttpGet request = new HttpGet(\"http://localhost:\" + port + \"/metrics\");\n            CloseableHttpResponse response = client.execute(request);\n            InputStream inputStream = response.getEntity().getContent();\n            String text = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))\n                    .lines()\n                    .collect(Collectors.joining(\"\\n\"));\n            Assertions.assertTrue(text.contains(\"jvm_gc_memory_promoted_bytes_total\"));\n        } catch (Exception e) {\n            Assertions.fail(e);\n        } finally {\n            reporter.destroy();\n        }\n    }\n\n    @Test\n    void testPushgateway() {\n        PrometheusConfig prometheusConfig = new PrometheusConfig();\n        PrometheusConfig.Pushgateway pushgateway = new PrometheusConfig.Pushgateway();\n        pushgateway.setJob(\"mock\");\n        pushgateway.setBaseUrl(\"localhost:9091\");\n        pushgateway.setEnabled(true);\n        pushgateway.setPushInterval(1);\n        prometheusConfig.setPushgateway(pushgateway);\n        metricsConfig.setPrometheus(prometheusConfig);\n\n        PrometheusMetricsReporter reporter = new PrometheusMetricsReporter(metricsConfig.toUrl(), applicationModel);\n        reporter.init();\n\n        ScheduledExecutorService executor = reporter.getPushJobExecutor();\n        Assertions.assertTrue(executor != null && !executor.isTerminated() && !executor.isShutdown());\n\n        reporter.destroy();\n        Assertions.assertTrue(executor.isTerminated() || executor.isShutdown());\n    }\n\n    private void exportHttpServer(PrometheusMetricsReporter reporter, int port) {\n\n        try {\n            prometheusExporterHttpServer = HttpServer.create(new InetSocketAddress(port), 0);\n            prometheusExporterHttpServer.createContext(\"/metrics\", httpExchange -> {\n                reporter.resetIfSamplesChanged();\n                String response = reporter.getPrometheusRegistry().scrape();\n                httpExchange.sendResponseHeaders(200, response.getBytes().length);\n                try (OutputStream os = httpExchange.getResponseBody()) {\n                    os.write(response.getBytes());\n                }\n            });\n\n            Thread httpServerThread = new Thread(prometheusExporterHttpServer::start);\n            httpServerThread.start();\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/src/test/java/org/apache/dubbo/metrics/prometheus/PrometheusMetricsThreadPoolTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.prometheus;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.nested.PrometheusConfig;\nimport org.apache.dubbo.metrics.collector.DefaultMetricsCollector;\nimport org.apache.dubbo.metrics.collector.sample.ThreadRejectMetricsCountSampler;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.net.InetSocketAddress;\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport com.sun.net.httpserver.HttpServer;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP;\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_THREAD_NAME;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHost;\nimport static org.apache.dubbo.common.utils.NetUtils.getLocalHostName;\n\npublic class PrometheusMetricsThreadPoolTest {\n\n    private ApplicationModel applicationModel;\n\n    private MetricsConfig metricsConfig;\n\n    DefaultMetricsCollector metricsCollector;\n\n    HttpServer prometheusExporterHttpServer;\n\n    @BeforeEach\n    public void setup() {\n        applicationModel = ApplicationModel.defaultModel();\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n\n        applicationModel.getApplicationConfigManager().setApplication(config);\n        metricsConfig = new MetricsConfig();\n        metricsConfig.setProtocol(PROTOCOL_PROMETHEUS);\n        metricsCollector = applicationModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n        if (prometheusExporterHttpServer != null) {\n            prometheusExporterHttpServer.stop(0);\n        }\n    }\n\n    @Test\n    void testExporterThreadpoolName() {\n        int port = 30899;\n        PrometheusConfig prometheusConfig = new PrometheusConfig();\n        PrometheusConfig.Exporter exporter = new PrometheusConfig.Exporter();\n        exporter.setEnabled(true);\n\n        prometheusConfig.setExporter(exporter);\n        metricsConfig.setPrometheus(prometheusConfig);\n        metricsConfig.setEnableJvm(false);\n        metricsCollector.setCollectEnabled(true);\n        metricsConfig.setEnableThreadpool(true);\n        metricsCollector.collectApplication();\n        PrometheusMetricsReporter reporter = new PrometheusMetricsReporter(metricsConfig.toUrl(), applicationModel);\n        reporter.init();\n        exportHttpServer(reporter, port);\n        if (metricsConfig.getEnableThreadpool()) {\n            metricsCollector.registryDefaultSample();\n        }\n        try (CloseableHttpClient client = HttpClients.createDefault()) {\n            HttpGet request = new HttpGet(\"http://localhost:\" + port + \"/metrics\");\n            CloseableHttpResponse response = client.execute(request);\n            InputStream inputStream = response.getEntity().getContent();\n            String text = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))\n                    .lines()\n                    .collect(Collectors.joining(\"\\n\"));\n            Assertions.assertTrue(text.contains(\"dubbo_thread_pool_core_size\"));\n            Assertions.assertTrue(text.contains(\"dubbo_thread_pool_thread_count\"));\n        } catch (Exception e) {\n            Assertions.fail(e);\n        } finally {\n            reporter.destroy();\n        }\n    }\n\n    private void exportHttpServer(PrometheusMetricsReporter reporter, int port) {\n        try {\n            prometheusExporterHttpServer = HttpServer.create(new InetSocketAddress(port), 0);\n            prometheusExporterHttpServer.createContext(\"/metrics\", httpExchange -> {\n                reporter.resetIfSamplesChanged();\n                String response = reporter.getPrometheusRegistry().scrape();\n                httpExchange.sendResponseHeaders(200, response.getBytes().length);\n                try (OutputStream os = httpExchange.getResponseBody()) {\n                    os.write(response.getBytes());\n                }\n            });\n            // start ServerImpl dispatcher thread.\n            prometheusExporterHttpServer.start();\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Test\n    @SuppressWarnings(\"rawtypes\")\n    void testThreadPoolRejectMetrics() {\n        DefaultMetricsCollector collector = new DefaultMetricsCollector(applicationModel);\n        collector.setCollectEnabled(true);\n        collector.setApplicationName(applicationModel.getApplicationName());\n        String threadPoolExecutorName = \"DubboServerHandler-20816\";\n        ThreadRejectMetricsCountSampler threadRejectMetricsCountSampler =\n                new ThreadRejectMetricsCountSampler(collector);\n        threadRejectMetricsCountSampler.inc(threadPoolExecutorName, threadPoolExecutorName);\n        threadRejectMetricsCountSampler.addMetricName(threadPoolExecutorName);\n        List<MetricSample> samples = collector.collect();\n        for (MetricSample sample : samples) {\n            Assertions.assertTrue(sample instanceof GaugeMetricSample);\n            GaugeMetricSample gaugeSample = (GaugeMetricSample) sample;\n            Map<String, String> tags = gaugeSample.getTags();\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), \"MockMetrics\");\n            Assertions.assertEquals(tags.get(TAG_THREAD_NAME), threadPoolExecutorName);\n            Assertions.assertEquals(tags.get(TAG_IP), getLocalHost());\n            Assertions.assertEquals(tags.get(TAG_HOSTNAME), getLocalHostName());\n            Assertions.assertEquals(gaugeSample.applyAsLong(), 1);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-prometheus/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metrics</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-metrics-registry</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The metrics module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/RegistryMetricsConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry;\n\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.DIRECTORY_METRIC_NUM_ALL;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.DIRECTORY_METRIC_NUM_DISABLE;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.DIRECTORY_METRIC_NUM_TO_RECONNECT;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.DIRECTORY_METRIC_NUM_VALID;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NOTIFY_METRIC_NUM_LAST;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.NOTIFY_METRIC_REQUESTS;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.REGISTER_METRIC_REQUESTS;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.REGISTER_METRIC_REQUESTS_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.REGISTER_METRIC_REQUESTS_SUCCEED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.SUBSCRIBE_METRIC_NUM;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.SUBSCRIBE_METRIC_NUM_FAILED;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.SUBSCRIBE_METRIC_NUM_SUCCEED;\n\npublic interface RegistryMetricsConstants {\n\n    String ATTACHMENT_REGISTRY_KEY = \"registryKey\";\n    String ATTACHMENT_REGISTRY_SINGLE_KEY = \"registrySingleKey\";\n\n    MetricsPlaceValue OP_TYPE_REGISTER = MetricsPlaceValue.of(\"register\", MetricsLevel.APP);\n    MetricsPlaceValue OP_TYPE_SUBSCRIBE = MetricsPlaceValue.of(\"subscribe\", MetricsLevel.APP);\n    MetricsPlaceValue OP_TYPE_NOTIFY = MetricsPlaceValue.of(\"notify\", MetricsLevel.APP);\n    MetricsPlaceValue OP_TYPE_DIRECTORY = MetricsPlaceValue.of(\"directory\", MetricsLevel.APP);\n    MetricsPlaceValue OP_TYPE_REGISTER_SERVICE = MetricsPlaceValue.of(\"register.service\", MetricsLevel.REGISTRY);\n    MetricsPlaceValue OP_TYPE_SUBSCRIBE_SERVICE = MetricsPlaceValue.of(\"subscribe.service\", MetricsLevel.SERVICE);\n\n    // App-level\n    List<MetricsKey> APP_LEVEL_KEYS = Collections.singletonList(NOTIFY_METRIC_REQUESTS);\n\n    // Registry-level\n    List<MetricsKey> REGISTER_LEVEL_KEYS = Arrays.asList(\n            REGISTER_METRIC_REQUESTS,\n            REGISTER_METRIC_REQUESTS_SUCCEED,\n            REGISTER_METRIC_REQUESTS_FAILED,\n            SUBSCRIBE_METRIC_NUM,\n            SUBSCRIBE_METRIC_NUM_SUCCEED,\n            SUBSCRIBE_METRIC_NUM_FAILED);\n\n    // Service-level\n    List<MetricsKeyWrapper> SERVICE_LEVEL_KEYS = Arrays.asList(\n            new MetricsKeyWrapper(NOTIFY_METRIC_NUM_LAST, OP_TYPE_NOTIFY),\n            new MetricsKeyWrapper(SERVICE_REGISTER_METRIC_REQUESTS, OP_TYPE_REGISTER_SERVICE),\n            new MetricsKeyWrapper(SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED, OP_TYPE_REGISTER_SERVICE),\n            new MetricsKeyWrapper(SERVICE_REGISTER_METRIC_REQUESTS_FAILED, OP_TYPE_REGISTER_SERVICE),\n            new MetricsKeyWrapper(SERVICE_SUBSCRIBE_METRIC_NUM, OP_TYPE_SUBSCRIBE_SERVICE),\n            new MetricsKeyWrapper(SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED, OP_TYPE_SUBSCRIBE_SERVICE),\n            new MetricsKeyWrapper(SERVICE_SUBSCRIBE_METRIC_NUM_FAILED, OP_TYPE_SUBSCRIBE_SERVICE),\n            new MetricsKeyWrapper(DIRECTORY_METRIC_NUM_VALID, OP_TYPE_DIRECTORY),\n            new MetricsKeyWrapper(DIRECTORY_METRIC_NUM_TO_RECONNECT, OP_TYPE_DIRECTORY),\n            new MetricsKeyWrapper(DIRECTORY_METRIC_NUM_DISABLE, OP_TYPE_DIRECTORY),\n            new MetricsKeyWrapper(DIRECTORY_METRIC_NUM_ALL, OP_TYPE_DIRECTORY));\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.collector;\n\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.metrics.collector.CombMetricsCollector;\nimport org.apache.dubbo.metrics.collector.MetricsCollector;\nimport org.apache.dubbo.metrics.data.ApplicationStatComposite;\nimport org.apache.dubbo.metrics.data.BaseStatComposite;\nimport org.apache.dubbo.metrics.data.RtStatComposite;\nimport org.apache.dubbo.metrics.data.ServiceStatComposite;\nimport org.apache.dubbo.metrics.model.ApplicationMetric;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.ServiceKeyMetric;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.registry.RegistryMetricsConstants;\nimport org.apache.dubbo.metrics.registry.event.RegistryEvent;\nimport org.apache.dubbo.metrics.registry.event.RegistrySubDispatcher;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_NOTIFY;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE_SERVICE;\n\n/**\n * Registry implementation of {@link MetricsCollector}\n */\n@Activate\npublic class RegistryMetricsCollector extends CombMetricsCollector<RegistryEvent> {\n\n    private Boolean collectEnabled = null;\n    private final ApplicationModel applicationModel;\n    private final RegistryStatComposite internalStat;\n\n    public RegistryMetricsCollector(ApplicationModel applicationModel) {\n        super(new BaseStatComposite(applicationModel) {\n            @Override\n            protected void init(ApplicationStatComposite applicationStatComposite) {\n                super.init(applicationStatComposite);\n                applicationStatComposite.init(RegistryMetricsConstants.APP_LEVEL_KEYS);\n            }\n\n            @Override\n            protected void init(ServiceStatComposite serviceStatComposite) {\n                super.init(serviceStatComposite);\n                serviceStatComposite.initWrapper(RegistryMetricsConstants.SERVICE_LEVEL_KEYS);\n            }\n\n            @Override\n            protected void init(RtStatComposite rtStatComposite) {\n                super.init(rtStatComposite);\n                rtStatComposite.init(\n                        OP_TYPE_REGISTER,\n                        OP_TYPE_SUBSCRIBE,\n                        OP_TYPE_NOTIFY,\n                        OP_TYPE_REGISTER_SERVICE,\n                        OP_TYPE_SUBSCRIBE_SERVICE);\n            }\n        });\n        super.setEventMulticaster(new RegistrySubDispatcher(this));\n        internalStat = new RegistryStatComposite(applicationModel);\n        this.applicationModel = applicationModel;\n    }\n\n    public void setCollectEnabled(Boolean collectEnabled) {\n        if (collectEnabled != null) {\n            this.collectEnabled = collectEnabled;\n        }\n    }\n\n    @Override\n    public boolean isCollectEnabled() {\n        if (collectEnabled == null) {\n            ConfigManager configManager = applicationModel.getApplicationConfigManager();\n            configManager.getMetrics().ifPresent(metricsConfig -> setCollectEnabled(metricsConfig.getEnableRegistry()));\n        }\n        return Optional.ofNullable(collectEnabled).orElse(false);\n    }\n\n    @Override\n    public List<MetricSample> collect() {\n        List<MetricSample> list = new ArrayList<>();\n        if (!isCollectEnabled()) {\n            return list;\n        }\n        list.addAll(super.export(MetricsCategory.REGISTRY));\n        list.addAll(internalStat.export(MetricsCategory.REGISTRY));\n        return list;\n    }\n\n    public void incrMetricsNum(MetricsKey metricsKey, List<String> registryClusterNames) {\n        registryClusterNames.forEach(name -> internalStat.incrMetricsNum(metricsKey, name));\n    }\n\n    public void incrRegisterFinishNum(\n            MetricsKey metricsKey, String registryOpType, List<String> registryClusterNames, Long responseTime) {\n        registryClusterNames.forEach(name -> {\n            ApplicationMetric applicationMetric = new ApplicationMetric(applicationModel);\n            applicationMetric.setExtraInfo(\n                    Collections.singletonMap(RegistryConstants.REGISTRY_CLUSTER_KEY.toLowerCase(), name));\n            internalStat.incrMetricsNum(metricsKey, name);\n            getStats().getRtStatComposite().calcServiceKeyRt(registryOpType, responseTime, applicationMetric);\n        });\n    }\n\n    public void incrServiceRegisterNum(\n            MetricsKeyWrapper wrapper, String serviceKey, List<String> registryClusterNames, int size) {\n        registryClusterNames.forEach(name -> stats.incrementServiceKey(\n                wrapper,\n                serviceKey,\n                Collections.singletonMap(RegistryConstants.REGISTRY_CLUSTER_KEY.toLowerCase(), name),\n                size));\n    }\n\n    public void incrServiceRegisterFinishNum(\n            MetricsKeyWrapper wrapper,\n            String serviceKey,\n            List<String> registryClusterNames,\n            int size,\n            Long responseTime) {\n        registryClusterNames.forEach(name -> {\n            Map<String, String> extraInfo =\n                    Collections.singletonMap(RegistryConstants.REGISTRY_CLUSTER_KEY.toLowerCase(), name);\n            ServiceKeyMetric serviceKeyMetric = new ServiceKeyMetric(applicationModel, serviceKey);\n            serviceKeyMetric.setExtraInfo(extraInfo);\n            stats.incrementServiceKey(wrapper, serviceKey, extraInfo, size);\n            getStats().getRtStatComposite().calcServiceKeyRt(wrapper.getType(), responseTime, serviceKeyMetric);\n        });\n    }\n\n    public void setNum(MetricsKeyWrapper metricsKey, String serviceKey, int num, Map<String, String> attachments) {\n        this.stats.setServiceKey(metricsKey, serviceKey, num, attachments);\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // Should ensure that all the stat's samplesChanged have been compareAndSet, and cannot flip the `or` logic\n        boolean changed = stats.calSamplesChanged();\n        changed = internalStat.calSamplesChanged() || changed;\n        return changed;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryStatComposite.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.collector;\n\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.metrics.model.ApplicationMetric;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.MetricsSupport;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.registry.RegistryMetricsConstants;\nimport org.apache.dubbo.metrics.report.AbstractMetricsExport;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE;\n\npublic class RegistryStatComposite extends AbstractMetricsExport {\n\n    private final ConcurrentHashMap<MetricsKey, ConcurrentHashMap<ApplicationMetric, AtomicLong>> appStats =\n            new ConcurrentHashMap<>();\n\n    private final AtomicBoolean samplesChanged = new AtomicBoolean(true);\n\n    public RegistryStatComposite(ApplicationModel applicationModel) {\n        super(applicationModel);\n        init(RegistryMetricsConstants.REGISTER_LEVEL_KEYS);\n    }\n\n    public void init(List<MetricsKey> appKeys) {\n        if (CollectionUtils.isEmpty(appKeys)) {\n            return;\n        }\n        appKeys.forEach(appKey -> {\n            appStats.put(appKey, new ConcurrentHashMap<>());\n        });\n        samplesChanged.set(true);\n    }\n\n    @Override\n    public List<MetricSample> export(MetricsCategory category) {\n        List<MetricSample> list = new ArrayList<>();\n        for (MetricsKey metricsKey : appStats.keySet()) {\n            Map<ApplicationMetric, AtomicLong> stringAtomicLongMap = appStats.get(metricsKey);\n            for (ApplicationMetric registerKeyMetric : stringAtomicLongMap.keySet()) {\n                list.add(new GaugeMetricSample<>(\n                        metricsKey, registerKeyMetric.getTags(), category, stringAtomicLongMap, value -> value.get(\n                                        registerKeyMetric)\n                                .get()));\n            }\n        }\n        return list;\n    }\n\n    public void incrMetricsNum(MetricsKey metricsKey, String name) {\n        if (!appStats.containsKey(metricsKey)) {\n            return;\n        }\n        ApplicationMetric applicationMetric = new ApplicationMetric(getApplicationModel());\n        applicationMetric.setExtraInfo(\n                Collections.singletonMap(RegistryConstants.REGISTRY_CLUSTER_KEY.toLowerCase(), name));\n        ConcurrentHashMap<ApplicationMetric, AtomicLong> stats = appStats.get(metricsKey);\n        AtomicLong metrics = stats.get(applicationMetric);\n        if (metrics == null) {\n            metrics = ConcurrentHashMapUtils.computeIfAbsent(stats, applicationMetric, k -> new AtomicLong(0L));\n            samplesChanged.set(true);\n        }\n        metrics.getAndAdd(SELF_INCREMENT_SIZE);\n        MetricsSupport.fillZero(appStats);\n    }\n\n    public ConcurrentHashMap<MetricsKey, ConcurrentHashMap<ApplicationMetric, AtomicLong>> getAppStats() {\n        return appStats;\n    }\n\n    @Override\n    public boolean calSamplesChanged() {\n        // CAS to get and reset the flag in an atomic operation\n        return samplesChanged.compareAndSet(true, false);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.event;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.metrics.event.TimeCounterEvent;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsLevel;\nimport org.apache.dubbo.metrics.model.key.TypeWrapper;\nimport org.apache.dubbo.metrics.registry.RegistryMetricsConstants;\nimport org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_DIRECTORY_MAP;\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_LAST_NUM_MAP;\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SIZE;\n\n/**\n * Registry related events\n */\npublic class RegistryEvent extends TimeCounterEvent {\n    public RegistryEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) {\n        super(applicationModel, typeWrapper);\n        ScopeBeanFactory beanFactory = getSource().getBeanFactory();\n        RegistryMetricsCollector collector;\n        if (!beanFactory.isDestroyed()) {\n            collector = beanFactory.getBean(RegistryMetricsCollector.class);\n            super.setAvailable(collector != null && collector.isCollectEnabled());\n        }\n    }\n\n    private static final TypeWrapper REGISTER_EVENT = new TypeWrapper(\n            MetricsLevel.APP,\n            MetricsKey.REGISTER_METRIC_REQUESTS,\n            MetricsKey.REGISTER_METRIC_REQUESTS_SUCCEED,\n            MetricsKey.REGISTER_METRIC_REQUESTS_FAILED);\n\n    public static RegistryEvent toRegisterEvent(ApplicationModel applicationModel, List<String> registryClusterNames) {\n        RegistryEvent registryEvent = new RegistryEvent(applicationModel, REGISTER_EVENT);\n        registryEvent.putAttachment(RegistryMetricsConstants.ATTACHMENT_REGISTRY_KEY, registryClusterNames);\n        return registryEvent;\n    }\n\n    private static final TypeWrapper SUBSCRIBE_EVENT = new TypeWrapper(\n            MetricsLevel.APP,\n            MetricsKey.SUBSCRIBE_METRIC_NUM,\n            MetricsKey.SUBSCRIBE_METRIC_NUM_SUCCEED,\n            MetricsKey.SUBSCRIBE_METRIC_NUM_FAILED);\n\n    public static RegistryEvent toSubscribeEvent(ApplicationModel applicationModel, String registryClusterName) {\n        RegistryEvent ddEvent = new RegistryEvent(applicationModel, SUBSCRIBE_EVENT);\n        ddEvent.putAttachment(\n                RegistryMetricsConstants.ATTACHMENT_REGISTRY_KEY, Collections.singletonList(registryClusterName));\n        return ddEvent;\n    }\n\n    private static final TypeWrapper NOTIFY_EVENT = new TypeWrapper(\n            MetricsLevel.APP, MetricsKey.NOTIFY_METRIC_REQUESTS, MetricsKey.NOTIFY_METRIC_NUM_LAST, (MetricsKey) null);\n\n    public static RegistryEvent toNotifyEvent(ApplicationModel applicationModel) {\n        return new RegistryEvent(applicationModel, NOTIFY_EVENT) {\n            @Override\n            public void customAfterPost(Object postResult) {\n                super.putAttachment(ATTACHMENT_KEY_LAST_NUM_MAP, postResult);\n            }\n        };\n    }\n\n    private static final TypeWrapper RS_EVENT = new TypeWrapper(\n            MetricsLevel.SERVICE,\n            MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS,\n            MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED,\n            MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED);\n\n    public static RegistryEvent toRsEvent(\n            ApplicationModel applicationModel, String serviceKey, int size, List<String> serviceDiscoveryNames) {\n        RegistryEvent ddEvent = new RegistryEvent(applicationModel, RS_EVENT);\n        ddEvent.putAttachment(ATTACHMENT_KEY_SERVICE, serviceKey);\n        ddEvent.putAttachment(ATTACHMENT_KEY_SIZE, size);\n        ddEvent.putAttachment(RegistryMetricsConstants.ATTACHMENT_REGISTRY_KEY, serviceDiscoveryNames);\n        return ddEvent;\n    }\n\n    private static final TypeWrapper SS_EVENT = new TypeWrapper(\n            MetricsLevel.SERVICE,\n            MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM,\n            MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED,\n            MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_FAILED);\n\n    public static RegistryEvent toSsEvent(\n            ApplicationModel applicationModel, String serviceKey, List<String> serviceDiscoveryNames) {\n        RegistryEvent ddEvent = new RegistryEvent(applicationModel, SS_EVENT);\n        ddEvent.putAttachment(ATTACHMENT_KEY_SERVICE, serviceKey);\n        ddEvent.putAttachment(ATTACHMENT_KEY_SIZE, 1);\n        ddEvent.putAttachment(RegistryMetricsConstants.ATTACHMENT_REGISTRY_KEY, serviceDiscoveryNames);\n        return ddEvent;\n    }\n\n    private static final TypeWrapper DIRECTORY_EVENT =\n            new TypeWrapper(MetricsLevel.APP, MetricsKey.DIRECTORY_METRIC_NUM_VALID, null, null);\n\n    public static RegistryEvent refreshDirectoryEvent(\n            ApplicationModel applicationModel,\n            Map<MetricsKey, Map<String, Integer>> summaryMap,\n            Map<String, String> attachments) {\n        RegistryEvent registryEvent = new RegistryEvent(applicationModel, DIRECTORY_EVENT);\n        registryEvent.putAttachment(ATTACHMENT_DIRECTORY_MAP, summaryMap);\n        registryEvent.putAttachments(attachments);\n        return registryEvent;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistrySpecListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.event;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metrics.collector.CombMetricsCollector;\nimport org.apache.dubbo.metrics.event.MetricsEvent;\nimport org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener;\nimport org.apache.dubbo.metrics.listener.MetricsApplicationListener;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.key.MetricsPlaceValue;\nimport org.apache.dubbo.metrics.registry.RegistryMetricsConstants;\nimport org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_DIRECTORY_MAP;\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_LAST_NUM_MAP;\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE;\nimport static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SIZE;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_DIRECTORY;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_NOTIFY;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER;\n\n/**\n * Different from the general-purpose listener constructor {@link MetricsApplicationListener} ,\n * it provides registry custom listeners\n */\npublic class RegistrySpecListener {\n\n    /**\n     * Perform auto-increment on the monitored key,\n     * Can use a custom listener instead of this generic operation\n     */\n    public static AbstractMetricsKeyListener onPost(MetricsKey metricsKey, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onEvent(\n                metricsKey, event -> ((RegistryMetricsCollector) collector).incrMetricsNum(metricsKey, getRgs(event)));\n    }\n\n    public static AbstractMetricsKeyListener onFinish(MetricsKey metricsKey, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onFinish(metricsKey, event -> ((RegistryMetricsCollector) collector)\n                .incrRegisterFinishNum(\n                        metricsKey,\n                        OP_TYPE_REGISTER.getType(),\n                        getRgs(event),\n                        event.getTimePair().calc()));\n    }\n\n    public static AbstractMetricsKeyListener onError(MetricsKey metricsKey, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onError(metricsKey, event -> ((RegistryMetricsCollector) collector)\n                .incrRegisterFinishNum(\n                        metricsKey,\n                        OP_TYPE_REGISTER.getType(),\n                        getRgs(event),\n                        event.getTimePair().calc()));\n    }\n\n    public static AbstractMetricsKeyListener onPostOfService(\n            MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onEvent(metricsKey, event -> ((RegistryMetricsCollector) collector)\n                .incrServiceRegisterNum(\n                        new MetricsKeyWrapper(metricsKey, placeType),\n                        getServiceKey(event),\n                        getRgs(event),\n                        getSize(event)));\n    }\n\n    public static AbstractMetricsKeyListener onFinishOfService(\n            MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onFinish(metricsKey, event -> ((RegistryMetricsCollector) collector)\n                .incrServiceRegisterFinishNum(\n                        new MetricsKeyWrapper(metricsKey, placeType),\n                        getServiceKey(event),\n                        getRgs(event),\n                        getSize(event),\n                        event.getTimePair().calc()));\n    }\n\n    public static AbstractMetricsKeyListener onErrorOfService(\n            MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onError(metricsKey, event -> ((RegistryMetricsCollector) collector)\n                .incrServiceRegisterFinishNum(\n                        new MetricsKeyWrapper(metricsKey, placeType),\n                        getServiceKey(event),\n                        getRgs(event),\n                        getSize(event),\n                        event.getTimePair().calc()));\n    }\n\n    /**\n     * Every time an event is triggered, multiple serviceKey related to notify are increment\n     */\n    public static AbstractMetricsKeyListener onFinishOfNotify(\n            MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onFinish(metricsKey, event -> {\n            collector.addServiceRt(\n                    event.appName(), placeType.getType(), event.getTimePair().calc());\n            Map<String, Integer> lastNumMap =\n                    Collections.unmodifiableMap(event.getAttachmentValue(ATTACHMENT_KEY_LAST_NUM_MAP));\n            lastNumMap.forEach((k, v) -> collector.setNum(new MetricsKeyWrapper(metricsKey, OP_TYPE_NOTIFY), k, v));\n        });\n    }\n\n    /**\n     * Every time an event is triggered, multiple fixed key related to directory are increment, which has nothing to do with the monitored key\n     */\n    public static AbstractMetricsKeyListener onPostOfDirectory(\n            MetricsKey metricsKey, CombMetricsCollector<?> collector) {\n        return AbstractMetricsKeyListener.onEvent(metricsKey, event -> {\n            Map<MetricsKey, Map<String, Integer>> summaryMap = event.getAttachmentValue(ATTACHMENT_DIRECTORY_MAP);\n            Map<String, String> otherAttachments = new HashMap<>();\n            for (Map.Entry<String, Object> entry : event.getAttachments().entrySet()) {\n                if (entry.getValue() instanceof String) {\n                    otherAttachments.put(entry.getKey().toLowerCase(Locale.ROOT), (String) entry.getValue());\n                }\n            }\n            summaryMap.forEach((summaryKey, map) -> map.forEach((k, v) -> {\n                if (CollectionUtils.isEmptyMap(otherAttachments)) {\n                    collector.setNum(new MetricsKeyWrapper(summaryKey, OP_TYPE_DIRECTORY), k, v);\n                } else {\n                    ((RegistryMetricsCollector) collector)\n                            .setNum(new MetricsKeyWrapper(summaryKey, OP_TYPE_DIRECTORY), k, v, otherAttachments);\n                }\n            }));\n        });\n    }\n\n    /**\n     * Get the number of multiple registries\n     */\n    public static List<String> getRgs(MetricsEvent event) {\n        return event.getAttachmentValue(RegistryMetricsConstants.ATTACHMENT_REGISTRY_KEY);\n    }\n\n    /**\n     * Get the exposed number of the protocol\n     */\n    public static int getSize(MetricsEvent event) {\n        return event.getAttachmentValue(ATTACHMENT_KEY_SIZE);\n    }\n\n    public static String getServiceKey(MetricsEvent event) {\n        return event.getAttachmentValue(ATTACHMENT_KEY_SERVICE);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistrySubDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.event;\n\nimport org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster;\nimport org.apache.dubbo.metrics.listener.MetricsApplicationListener;\nimport org.apache.dubbo.metrics.model.key.CategoryOverall;\nimport org.apache.dubbo.metrics.model.key.MetricsCat;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_DIRECTORY;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_NOTIFY;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE_SERVICE;\n\npublic final class RegistrySubDispatcher extends SimpleMetricsEventMulticaster {\n\n    public RegistrySubDispatcher(RegistryMetricsCollector collector) {\n\n        CategorySet.ALL.forEach(categorySet -> {\n            super.addListener(categorySet.getPost().getEventFunc().apply(collector));\n            if (categorySet.getFinish() != null) {\n                super.addListener(categorySet.getFinish().getEventFunc().apply(collector));\n            }\n            if (categorySet.getError() != null) {\n                super.addListener(categorySet.getError().getEventFunc().apply(collector));\n            }\n        });\n    }\n\n    /**\n     * A closer aggregation of MetricsCat, a summary collection of certain types of events\n     */\n    interface CategorySet {\n        CategoryOverall APPLICATION_REGISTER = new CategoryOverall(\n                OP_TYPE_REGISTER,\n                MCat.APPLICATION_REGISTER_POST,\n                MCat.APPLICATION_REGISTER_FINISH,\n                MCat.APPLICATION_REGISTER_ERROR);\n        CategoryOverall APPLICATION_SUBSCRIBE = new CategoryOverall(\n                OP_TYPE_SUBSCRIBE,\n                MCat.APPLICATION_SUBSCRIBE_POST,\n                MCat.APPLICATION_SUBSCRIBE_FINISH,\n                MCat.APPLICATION_SUBSCRIBE_ERROR);\n        CategoryOverall APPLICATION_NOTIFY =\n                new CategoryOverall(OP_TYPE_NOTIFY, MCat.APPLICATION_NOTIFY_POST, MCat.APPLICATION_NOTIFY_FINISH, null);\n        CategoryOverall SERVICE_DIRECTORY =\n                new CategoryOverall(OP_TYPE_DIRECTORY, MCat.APPLICATION_DIRECTORY_POST, null, null);\n        CategoryOverall SERVICE_REGISTER = new CategoryOverall(\n                OP_TYPE_REGISTER_SERVICE,\n                MCat.SERVICE_REGISTER_POST,\n                MCat.SERVICE_REGISTER_FINISH,\n                MCat.SERVICE_REGISTER_ERROR);\n        CategoryOverall SERVICE_SUBSCRIBE = new CategoryOverall(\n                OP_TYPE_SUBSCRIBE_SERVICE,\n                MCat.SERVICE_SUBSCRIBE_POST,\n                MCat.SERVICE_SUBSCRIBE_FINISH,\n                MCat.SERVICE_SUBSCRIBE_ERROR);\n\n        List<CategoryOverall> ALL = Arrays.asList(\n                APPLICATION_REGISTER,\n                APPLICATION_SUBSCRIBE,\n                APPLICATION_NOTIFY,\n                SERVICE_DIRECTORY,\n                SERVICE_REGISTER,\n                SERVICE_SUBSCRIBE);\n    }\n\n    /**\n     * {@link MetricsCat} MetricsCat collection, for better classification processing\n     * Except for a few custom functions, most of them can build standard event listening functions through the static methods of MetricsApplicationListener\n     */\n    interface MCat {\n        // MetricsRegisterListener\n        MetricsCat APPLICATION_REGISTER_POST =\n                new MetricsCat(MetricsKey.REGISTER_METRIC_REQUESTS, RegistrySpecListener::onPost);\n        MetricsCat APPLICATION_REGISTER_FINISH =\n                new MetricsCat(MetricsKey.REGISTER_METRIC_REQUESTS_SUCCEED, RegistrySpecListener::onFinish);\n        MetricsCat APPLICATION_REGISTER_ERROR =\n                new MetricsCat(MetricsKey.REGISTER_METRIC_REQUESTS_FAILED, RegistrySpecListener::onError);\n\n        // MetricsSubscribeListener\n        MetricsCat APPLICATION_SUBSCRIBE_POST =\n                new MetricsCat(MetricsKey.SUBSCRIBE_METRIC_NUM, RegistrySpecListener::onPost);\n        MetricsCat APPLICATION_SUBSCRIBE_FINISH =\n                new MetricsCat(MetricsKey.SUBSCRIBE_METRIC_NUM_SUCCEED, RegistrySpecListener::onFinish);\n        MetricsCat APPLICATION_SUBSCRIBE_ERROR =\n                new MetricsCat(MetricsKey.SUBSCRIBE_METRIC_NUM_FAILED, RegistrySpecListener::onError);\n\n        // MetricsNotifyListener\n        MetricsCat APPLICATION_NOTIFY_POST =\n                new MetricsCat(MetricsKey.NOTIFY_METRIC_REQUESTS, MetricsApplicationListener::onPostEventBuild);\n        MetricsCat APPLICATION_NOTIFY_FINISH =\n                new MetricsCat(MetricsKey.NOTIFY_METRIC_NUM_LAST, RegistrySpecListener::onFinishOfNotify);\n\n        MetricsCat APPLICATION_DIRECTORY_POST =\n                new MetricsCat(MetricsKey.DIRECTORY_METRIC_NUM_VALID, RegistrySpecListener::onPostOfDirectory);\n\n        // MetricsServiceRegisterListener\n        MetricsCat SERVICE_REGISTER_POST =\n                new MetricsCat(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS, RegistrySpecListener::onPostOfService);\n        MetricsCat SERVICE_REGISTER_FINISH = new MetricsCat(\n                MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED, RegistrySpecListener::onFinishOfService);\n        MetricsCat SERVICE_REGISTER_ERROR = new MetricsCat(\n                MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED, RegistrySpecListener::onErrorOfService);\n\n        // MetricsServiceSubscribeListener\n        MetricsCat SERVICE_SUBSCRIBE_POST =\n                new MetricsCat(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM, RegistrySpecListener::onPostOfService);\n        MetricsCat SERVICE_SUBSCRIBE_FINISH = new MetricsCat(\n                MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED, RegistrySpecListener::onFinishOfService);\n        MetricsCat SERVICE_SUBSCRIBE_ERROR =\n                new MetricsCat(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_FAILED, RegistrySpecListener::onErrorOfService);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector",
    "content": "registry-collector=org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.metrics.collector;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metrics.event.MetricsDispatcher;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.model.TimePair;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.registry.RegistryMetricsConstants;\nimport org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector;\nimport org.apache.dubbo.metrics.registry.event.RegistryEvent;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.APP_LEVEL_KEYS;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE_SERVICE;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.REGISTER_LEVEL_KEYS;\n\nclass RegistryMetricsCollectorTest {\n\n    private ApplicationModel applicationModel;\n    private RegistryMetricsCollector collector;\n\n    @BeforeEach\n    public void setup() {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        applicationModel = frameworkModel.newApplication();\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n\n        applicationModel.getApplicationConfigManager().setApplication(config);\n        applicationModel.getBeanFactory().getOrRegisterBean(MetricsDispatcher.class);\n        collector = applicationModel.getBeanFactory().getOrRegisterBean(RegistryMetricsCollector.class);\n        collector.setCollectEnabled(true);\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    @Test\n    void testRegisterMetrics() {\n        List<String> registryClusterNames = new ArrayList<>();\n        registryClusterNames.add(\"reg1\");\n        RegistryEvent registryEvent = RegistryEvent.toRegisterEvent(applicationModel, registryClusterNames);\n        MetricsEventBus.post(registryEvent, () -> {\n            List<MetricSample> metricSamples = collector.collect();\n            // push success +1 -> other default 0 = APP_LEVEL_KEYS.size()\n            Assertions.assertEquals(APP_LEVEL_KEYS.size() + REGISTER_LEVEL_KEYS.size(), metricSamples.size());\n            Assertions.assertTrue(\n                    metricSamples.stream().allMatch(metricSample -> metricSample instanceof GaugeMetricSample));\n            Assertions.assertTrue(metricSamples.stream()\n                    .anyMatch(metricSample -> ((GaugeMetricSample) metricSample).applyAsDouble() == 1));\n            return null;\n        });\n\n        // push finish rt +1\n        List<MetricSample> metricSamples = collector.collect();\n        // APP_LEVEL_KEYS.size() + rt(5) = 12\n        Assertions.assertEquals(APP_LEVEL_KEYS.size() + REGISTER_LEVEL_KEYS.size() + 5, metricSamples.size());\n        long c1 = registryEvent.getTimePair().calc();\n\n        registryEvent = RegistryEvent.toRegisterEvent(applicationModel, registryClusterNames);\n        TimePair lastTimePair = registryEvent.getTimePair();\n        MetricsEventBus.post(\n                registryEvent,\n                () -> {\n                    try {\n                        Thread.sleep(50);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    return null;\n                },\n                Objects::nonNull);\n        // push error rt +1\n        long c2 = lastTimePair.calc();\n\n        metricSamples = collector.collect();\n\n        // num(total+success+error) + rt(5)\n        Assertions.assertEquals(APP_LEVEL_KEYS.size() + REGISTER_LEVEL_KEYS.size() + 5, metricSamples.size());\n\n        // calc rt\n        for (MetricSample sample : metricSamples) {\n            Map<String, String> tags = sample.getTags();\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());\n        }\n\n        @SuppressWarnings(\"rawtypes\")\n        Map<String, Long> sampleMap = metricSamples.stream()\n                .collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));\n\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_LAST, OP_TYPE_REGISTER).targetKey()),\n                lastTimePair.calc());\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MIN, OP_TYPE_REGISTER).targetKey()),\n                Math.min(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MAX, OP_TYPE_REGISTER).targetKey()),\n                Math.max(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_AVG, OP_TYPE_REGISTER).targetKey()),\n                (c1 + c2) / 2);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_SUM, OP_TYPE_REGISTER).targetKey()), c1 + c2);\n    }\n\n    @Test\n    void testServicePushMetrics() {\n\n        String serviceName = \"demo.gameService\";\n        List<String> rcNames = new ArrayList<>();\n        rcNames.add(\"demo1\");\n\n        RegistryEvent registryEvent = RegistryEvent.toRsEvent(applicationModel, serviceName, 2, rcNames);\n        MetricsEventBus.post(registryEvent, () -> {\n            List<MetricSample> metricSamples = collector.collect();\n\n            // push success +1\n            Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 1, metricSamples.size());\n            // Service num only 1 and contains tag of interface\n            Assertions.assertEquals(\n                    1,\n                    metricSamples.stream()\n                            .filter(metricSample ->\n                                    serviceName.equals(metricSample.getTags().get(\"interface\")))\n                            .count());\n            return null;\n        });\n\n        // push finish rt +1\n        List<MetricSample> metricSamples = collector.collect();\n        // App(7) + rt(5) + service(total/success) = 14\n        Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 5 + 2, metricSamples.size());\n\n        long c1 = registryEvent.getTimePair().calc();\n        registryEvent = RegistryEvent.toRsEvent(applicationModel, serviceName, 2, rcNames);\n        TimePair lastTimePair = registryEvent.getTimePair();\n        MetricsEventBus.post(\n                registryEvent,\n                () -> {\n                    try {\n                        Thread.sleep(50);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    return null;\n                },\n                Objects::nonNull);\n        // push error rt +1\n        long c2 = lastTimePair.calc();\n\n        metricSamples = collector.collect();\n\n        // App(7) + rt(5) + service(total/success/failed) = 15\n        Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 5 + 3, metricSamples.size());\n\n        // calc rt\n        for (MetricSample sample : metricSamples) {\n            Map<String, String> tags = sample.getTags();\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());\n        }\n\n        @SuppressWarnings(\"rawtypes\")\n        Map<String, Long> sampleMap = metricSamples.stream()\n                .collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));\n\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_LAST, OP_TYPE_REGISTER_SERVICE).targetKey()),\n                lastTimePair.calc());\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MIN, OP_TYPE_REGISTER_SERVICE).targetKey()),\n                Math.min(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MAX, OP_TYPE_REGISTER_SERVICE).targetKey()),\n                Math.max(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_AVG, OP_TYPE_REGISTER_SERVICE).targetKey()),\n                (c1 + c2) / 2);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_SUM, OP_TYPE_REGISTER_SERVICE).targetKey()),\n                c1 + c2);\n    }\n\n    @Test\n    void testServiceSubscribeMetrics() {\n\n        String serviceName = \"demo.gameService\";\n\n        RegistryEvent subscribeEvent =\n                RegistryEvent.toSsEvent(applicationModel, serviceName, Collections.singletonList(\"demo1\"));\n        MetricsEventBus.post(subscribeEvent, () -> {\n            List<MetricSample> metricSamples = collector.collect();\n            Assertions.assertTrue(\n                    metricSamples.stream().allMatch(metricSample -> metricSample instanceof GaugeMetricSample));\n            Assertions.assertTrue(metricSamples.stream()\n                    .anyMatch(metricSample -> ((GaugeMetricSample) metricSample).applyAsDouble() == 1));\n            // App(default=7) + (service success +1)\n            Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 1, metricSamples.size());\n            // Service num only 1 and contains tag of interface\n            Assertions.assertEquals(\n                    1,\n                    metricSamples.stream()\n                            .filter(metricSample ->\n                                    serviceName.equals(metricSample.getTags().get(\"interface\")))\n                            .count());\n            return null;\n        });\n\n        // push finish rt +1\n        List<MetricSample> metricSamples = collector.collect();\n        // App(7) + rt(5) + service(total/success) = 14\n        Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 5 + 2, metricSamples.size());\n\n        long c1 = subscribeEvent.getTimePair().calc();\n        subscribeEvent = RegistryEvent.toSsEvent(applicationModel, serviceName, Collections.singletonList(\"demo1\"));\n        TimePair lastTimePair = subscribeEvent.getTimePair();\n        MetricsEventBus.post(\n                subscribeEvent,\n                () -> {\n                    try {\n                        Thread.sleep(50);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    return null;\n                },\n                Objects::nonNull);\n        // push error rt +1\n        long c2 = lastTimePair.calc();\n\n        metricSamples = collector.collect();\n\n        // App(7) + rt(5) + service(total/success/failed) = 15\n        Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 5 + 3, metricSamples.size());\n\n        // calc rt\n        for (MetricSample sample : metricSamples) {\n            Map<String, String> tags = sample.getTags();\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());\n        }\n\n        @SuppressWarnings(\"rawtypes\")\n        Map<String, Long> sampleMap = metricSamples.stream()\n                .collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));\n\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_LAST, OP_TYPE_SUBSCRIBE_SERVICE).targetKey()),\n                lastTimePair.calc());\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MIN, OP_TYPE_SUBSCRIBE_SERVICE).targetKey()),\n                Math.min(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MAX, OP_TYPE_SUBSCRIBE_SERVICE).targetKey()),\n                Math.max(c1, c2));\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_AVG, OP_TYPE_SUBSCRIBE_SERVICE).targetKey()),\n                (c1 + c2) / 2);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_SUM, OP_TYPE_SUBSCRIBE_SERVICE).targetKey()),\n                c1 + c2);\n    }\n\n    @Test\n    public void testNotify() {\n        Map<String, Integer> lastNumMap = new HashMap<>();\n        MetricsEventBus.post(RegistryEvent.toNotifyEvent(applicationModel), () -> {\n            try {\n                Thread.sleep(50L);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            // 1 different services\n            lastNumMap.put(\"demo.service1\", 3);\n            lastNumMap.put(\"demo.service2\", 4);\n            lastNumMap.put(\"demo.service3\", 5);\n            return lastNumMap;\n        });\n        List<MetricSample> metricSamples = collector.collect();\n        // App(7) + num(service*3) + rt(5) = 9\n        Assertions.assertEquals((RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 3 + 5), metricSamples.size());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsSampleTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.metrics.collector;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER;\n\nclass RegistryMetricsSampleTest {\n\n    private ApplicationModel applicationModel;\n\n    @BeforeEach\n    public void setup() {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        applicationModel = frameworkModel.newApplication();\n        ApplicationConfig config = new ApplicationConfig();\n        config.setName(\"MockMetrics\");\n        applicationModel.getApplicationConfigManager().setApplication(config);\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    @Test\n    void testRegisterMetrics() {}\n\n    @Test\n    void testRTMetrics() {\n        RegistryMetricsCollector collector = new RegistryMetricsCollector(applicationModel);\n        collector.setCollectEnabled(true);\n        String applicationName = applicationModel.getApplicationName();\n        collector.addServiceRt(applicationName, OP_TYPE_REGISTER.getType(), 10L);\n        collector.addServiceRt(applicationName, OP_TYPE_REGISTER.getType(), 0L);\n\n        List<MetricSample> samples = collector.collect();\n        for (MetricSample sample : samples) {\n            Map<String, String> tags = sample.getTags();\n            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationName);\n        }\n\n        @SuppressWarnings(\"rawtypes\")\n        Map<String, Long> sampleMap = samples.stream()\n                .collect(Collectors.toMap(MetricSample::getName, k -> ((GaugeMetricSample) k).applyAsLong()));\n\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_LAST, OP_TYPE_REGISTER).targetKey()), 0L);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MIN, OP_TYPE_REGISTER).targetKey()), 0L);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_MAX, OP_TYPE_REGISTER).targetKey()), 10L);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_AVG, OP_TYPE_REGISTER).targetKey()), 5L);\n        Assertions.assertEquals(\n                sampleMap.get(new MetricsKeyWrapper(MetricsKey.METRIC_RT_SUM, OP_TYPE_REGISTER).targetKey()), 10L);\n    }\n\n    @Test\n    void testListener() {\n        RegistryMetricsCollector collector = new RegistryMetricsCollector(applicationModel);\n        collector.setCollectEnabled(true);\n        collector.increment(MetricsKey.REGISTER_METRIC_REQUESTS);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.metrics.collector;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.nested.AggregationConfig;\nimport org.apache.dubbo.metrics.model.key.MetricsKey;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector;\nimport org.apache.dubbo.metrics.registry.event.RegistryEvent;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.NoSuchElementException;\nimport java.util.Optional;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.when;\n\npublic class RegistryMetricsTest {\n\n    ApplicationModel applicationModel;\n\n    RegistryMetricsCollector collector;\n\n    String REGISTER = \"register\";\n\n    @BeforeEach\n    void setUp() {\n        this.applicationModel = getApplicationModel();\n        this.collector = getTestCollector(this.applicationModel);\n        this.collector.setCollectEnabled(true);\n    }\n\n    @Test\n    void testRegisterRequestsCount() {\n\n        for (int i = 0; i < 10; i++) {\n            RegistryEvent event = applicationRegister();\n            if (i % 2 == 0) {\n                eventSuccess(event);\n            } else {\n                eventFailed(event);\n            }\n        }\n        List<MetricSample> samples = collector.collect();\n\n        GaugeMetricSample<?> succeedRequests =\n                getSample(MetricsKey.REGISTER_METRIC_REQUESTS_SUCCEED.getName(), samples);\n        GaugeMetricSample<?> failedRequests = getSample(MetricsKey.REGISTER_METRIC_REQUESTS_FAILED.getName(), samples);\n        GaugeMetricSample<?> totalRequests = getSample(MetricsKey.REGISTER_METRIC_REQUESTS.getName(), samples);\n\n        Assertions.assertEquals(5L, succeedRequests.applyAsLong());\n        Assertions.assertEquals(5L, failedRequests.applyAsLong());\n        Assertions.assertEquals(10L, totalRequests.applyAsLong());\n    }\n\n    @Test\n    void testLastResponseTime() {\n        long waitTime = 2000;\n\n        RegistryEvent event = applicationRegister();\n        await(waitTime);\n        eventSuccess(event);\n\n        GaugeMetricSample<?> sample = getSample(MetricsKey.METRIC_RT_LAST.getNameByType(REGISTER), collector.collect());\n        // 20% deviation is allowed\n        Assertions.assertTrue(considerEquals(waitTime, sample.applyAsLong(), 0.2));\n\n        RegistryEvent event1 = applicationRegister();\n        await(waitTime / 2);\n        eventSuccess(event1);\n\n        sample = getSample(MetricsKey.METRIC_RT_LAST.getNameByType(REGISTER), collector.collect());\n        Assertions.assertTrue(considerEquals((double) waitTime / 2, sample.applyAsLong(), 0.2));\n\n        RegistryEvent event2 = applicationRegister();\n        await(waitTime);\n        eventFailed(event2);\n\n        sample = getSample(MetricsKey.METRIC_RT_LAST.getNameByType(REGISTER), collector.collect());\n        Assertions.assertTrue(considerEquals((double) waitTime, sample.applyAsLong(), 0.2));\n    }\n\n    @Test\n    void testMinResponseTime() throws InterruptedException {\n        long waitTime = 2000L;\n\n        RegistryEvent event = applicationRegister();\n        await(waitTime);\n        eventSuccess(event);\n\n        RegistryEvent event1 = applicationRegister();\n        await(waitTime);\n\n        RegistryEvent event2 = applicationRegister();\n        await(waitTime);\n\n        eventSuccess(event1);\n        eventSuccess(event2);\n\n        GaugeMetricSample<?> sample = getSample(MetricsKey.METRIC_RT_MIN.getNameByType(REGISTER), collector.collect());\n        Assertions.assertTrue(considerEquals(waitTime, sample.applyAsLong(), 0.2));\n\n        RegistryEvent event3 = applicationRegister();\n        Thread.sleep(waitTime / 2);\n        eventSuccess(event3);\n\n        sample = getSample(MetricsKey.METRIC_RT_MIN.getNameByType(REGISTER), collector.collect());\n        Assertions.assertTrue(considerEquals((double) waitTime / 2, sample.applyAsLong(), 0.2));\n    }\n\n    @Test\n    void testMaxResponseTime() {\n        long waitTime = 1000L;\n\n        RegistryEvent event = applicationRegister();\n        await(waitTime);\n        eventSuccess(event);\n\n        GaugeMetricSample<?> sample = getSample(MetricsKey.METRIC_RT_MAX.getNameByType(REGISTER), collector.collect());\n        Assertions.assertTrue(considerEquals(waitTime, sample.applyAsLong(), 0.2));\n\n        RegistryEvent event1 = applicationRegister();\n        await(waitTime * 2);\n        eventSuccess(event1);\n\n        sample = getSample(MetricsKey.METRIC_RT_MAX.getNameByType(REGISTER), collector.collect());\n        Assertions.assertTrue(considerEquals(waitTime * 2, sample.applyAsLong(), 0.2));\n\n        sample = getSample(MetricsKey.METRIC_RT_MAX.getNameByType(REGISTER), collector.collect());\n        RegistryEvent event2 = applicationRegister();\n        eventSuccess(event2);\n        Assertions.assertTrue(considerEquals(waitTime * 2, sample.applyAsLong(), 0.2));\n    }\n\n    @Test\n    void testSumResponseTime() {\n        long waitTime = 1000;\n\n        RegistryEvent event = applicationRegister();\n        RegistryEvent event1 = applicationRegister();\n        RegistryEvent event2 = applicationRegister();\n\n        await(waitTime);\n\n        eventSuccess(event);\n        eventFailed(event1);\n\n        GaugeMetricSample<?> sample = getSample(MetricsKey.METRIC_RT_SUM.getNameByType(REGISTER), collector.collect());\n        Assertions.assertTrue(considerEquals(waitTime * 2, sample.applyAsLong(), 0.2));\n\n        await(waitTime);\n        eventSuccess(event2);\n\n        sample = getSample(MetricsKey.METRIC_RT_SUM.getNameByType(REGISTER), collector.collect());\n        Assertions.assertTrue(considerEquals(waitTime * 4, sample.applyAsLong(), 0.2));\n    }\n\n    @Test\n    void testAvgResponseTime() {\n        long waitTime = 1000;\n\n        RegistryEvent event = applicationRegister();\n        RegistryEvent event1 = applicationRegister();\n        RegistryEvent event2 = applicationRegister();\n\n        await(waitTime);\n\n        eventSuccess(event);\n        eventFailed(event1);\n\n        GaugeMetricSample<?> sample = getSample(MetricsKey.METRIC_RT_AVG.getNameByType(REGISTER), collector.collect());\n        Assertions.assertTrue(considerEquals(waitTime, sample.applyAsLong(), 0.2));\n\n        await(waitTime);\n        eventSuccess(event2);\n\n        sample = getSample(MetricsKey.METRIC_RT_AVG.getNameByType(REGISTER), collector.collect());\n        Assertions.assertTrue(considerEquals((double) waitTime * 4 / 3, sample.applyAsLong(), 0.2));\n    }\n\n    @Test\n    void testServiceRegisterCount() {\n\n        for (int i = 0; i < 10; i++) {\n            RegistryEvent event = serviceRegister();\n            if (i % 2 == 0) {\n                eventSuccess(event);\n            } else {\n                eventFailed(event);\n            }\n        }\n        List<MetricSample> samples = collector.collect();\n\n        GaugeMetricSample<?> succeedRequests =\n                getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED.getName(), samples);\n        GaugeMetricSample<?> failedRequests =\n                getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED.getName(), samples);\n        GaugeMetricSample<?> totalRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS.getName(), samples);\n\n        Assertions.assertEquals(5L, succeedRequests.applyAsLong());\n        Assertions.assertEquals(5L, failedRequests.applyAsLong());\n        Assertions.assertEquals(10L, totalRequests.applyAsLong());\n    }\n\n    @Test\n    void testServiceSubscribeCount() {\n\n        for (int i = 0; i < 10; i++) {\n            RegistryEvent event = serviceSubscribe();\n            if (i % 2 == 0) {\n                eventSuccess(event);\n            } else {\n                eventFailed(event);\n            }\n        }\n        List<MetricSample> samples = collector.collect();\n\n        GaugeMetricSample<?> succeedRequests = getSample(MetricsKey.SUBSCRIBE_METRIC_NUM_SUCCEED.getName(), samples);\n        GaugeMetricSample<?> failedRequests = getSample(MetricsKey.SUBSCRIBE_METRIC_NUM_FAILED.getName(), samples);\n        GaugeMetricSample<?> totalRequests = getSample(MetricsKey.SUBSCRIBE_METRIC_NUM.getName(), samples);\n\n        Assertions.assertEquals(5L, succeedRequests.applyAsLong());\n        Assertions.assertEquals(5L, failedRequests.applyAsLong());\n        Assertions.assertEquals(10L, totalRequests.applyAsLong());\n    }\n\n    GaugeMetricSample<?> getSample(String name, List<MetricSample> samples) {\n        return (GaugeMetricSample<?>) samples.stream()\n                .filter(metricSample -> metricSample.getName().equals(name))\n                .findFirst()\n                .orElseThrow(NoSuchElementException::new);\n    }\n\n    RegistryEvent applicationRegister() {\n        RegistryEvent event = registerEvent();\n        collector.onEvent(event);\n        return event;\n    }\n\n    RegistryEvent serviceRegister() {\n        RegistryEvent event = rsEvent();\n        collector.onEvent(event);\n        return event;\n    }\n\n    RegistryEvent serviceSubscribe() {\n        RegistryEvent event = subscribeEvent();\n        collector.onEvent(event);\n        return event;\n    }\n\n    boolean considerEquals(double expected, double trueValue, double allowedErrorRatio) {\n        return Math.abs(1 - expected / trueValue) <= allowedErrorRatio;\n    }\n\n    void eventSuccess(RegistryEvent event) {\n        collector.onEventFinish(event);\n    }\n\n    void eventFailed(RegistryEvent event) {\n        collector.onEventError(event);\n    }\n\n    RegistryEvent registerEvent() {\n        List<String> registryClusterNames = new ArrayList<>();\n        registryClusterNames.add(\"reg1\");\n        RegistryEvent event = RegistryEvent.toRegisterEvent(applicationModel, registryClusterNames);\n        event.setAvailable(true);\n        return event;\n    }\n\n    RegistryEvent rsEvent() {\n        List<String> rcNames = new ArrayList<>();\n        rcNames.add(\"demo1\");\n        RegistryEvent event = RegistryEvent.toRsEvent(applicationModel, \"TestServiceInterface1\", 1, rcNames);\n        event.setAvailable(true);\n        return event;\n    }\n\n    RegistryEvent subscribeEvent() {\n        RegistryEvent event = RegistryEvent.toSubscribeEvent(applicationModel, \"registryClusterName_test\");\n        event.setAvailable(true);\n        return event;\n    }\n\n    ApplicationModel getApplicationModel() {\n        return spy(new FrameworkModel().newApplication());\n    }\n\n    void await(long millis) {\n\n        CountDownLatch latch = new CountDownLatch(1);\n\n        ScheduledFuture<?> future = TimeController.executor.schedule(latch::countDown, millis, TimeUnit.MILLISECONDS);\n        try {\n            latch.await();\n        } catch (InterruptedException e) {\n            future.cancel(true);\n            Thread.currentThread().interrupt();\n        }\n    }\n\n    RegistryMetricsCollector getTestCollector(ApplicationModel applicationModel) {\n\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"TestApp\");\n        ConfigManager configManager = spy(new ConfigManager(applicationModel));\n        MetricsConfig metricsConfig = spy(new MetricsConfig());\n\n        configManager.setApplication(applicationConfig);\n        configManager.setMetrics(metricsConfig);\n\n        when(metricsConfig.getAggregation()).thenReturn(new AggregationConfig());\n        when(applicationModel.getApplicationConfigManager()).thenReturn(configManager);\n        when(applicationModel.NotExistApplicationConfig()).thenReturn(false);\n        when(configManager.getApplication()).thenReturn(Optional.of(applicationConfig));\n\n        return new RegistryMetricsCollector(applicationModel);\n    }\n\n    /**\n     * make the control of thread sleep time more precise\n     */\n    static class TimeController {\n\n        private static final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);\n\n        public static void sleep(long milliseconds) {\n            CountDownLatch latch = new CountDownLatch(1);\n            ScheduledFuture<?> future = executor.schedule(latch::countDown, milliseconds, TimeUnit.MILLISECONDS);\n            try {\n                latch.await();\n            } catch (InterruptedException e) {\n                future.cancel(true);\n                Thread.currentThread().interrupt();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.metrics.registry.metrics.collector;\n\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metrics.data.ApplicationStatComposite;\nimport org.apache.dubbo.metrics.data.BaseStatComposite;\nimport org.apache.dubbo.metrics.data.RtStatComposite;\nimport org.apache.dubbo.metrics.data.ServiceStatComposite;\nimport org.apache.dubbo.metrics.model.ApplicationMetric;\nimport org.apache.dubbo.metrics.model.Metric;\nimport org.apache.dubbo.metrics.model.MetricsCategory;\nimport org.apache.dubbo.metrics.model.container.LongContainer;\nimport org.apache.dubbo.metrics.model.sample.GaugeMetricSample;\nimport org.apache.dubbo.metrics.model.sample.MetricSample;\nimport org.apache.dubbo.metrics.registry.RegistryMetricsConstants;\nimport org.apache.dubbo.metrics.registry.collector.RegistryStatComposite;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_RT_AVG;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_RT_MAX;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_RT_MIN;\nimport static org.apache.dubbo.metrics.model.key.MetricsKey.REGISTER_METRIC_REQUESTS;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_NOTIFY;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE;\nimport static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE_SERVICE;\n\npublic class RegistryStatCompositeTest {\n    private ApplicationModel applicationModel;\n    private String applicationName;\n    private BaseStatComposite statComposite;\n    private RegistryStatComposite regStatComposite;\n\n    @BeforeEach\n    public void setup() {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        applicationModel = frameworkModel.newApplication();\n        ApplicationConfig application = new ApplicationConfig();\n        application.setName(\"App1\");\n        applicationModel.getApplicationConfigManager().setApplication(application);\n        applicationName = applicationModel.getApplicationName();\n        statComposite = new BaseStatComposite(applicationModel) {\n            @Override\n            protected void init(ApplicationStatComposite applicationStatComposite) {\n                super.init(applicationStatComposite);\n                applicationStatComposite.init(RegistryMetricsConstants.APP_LEVEL_KEYS);\n            }\n\n            @Override\n            protected void init(ServiceStatComposite serviceStatComposite) {\n                super.init(serviceStatComposite);\n                serviceStatComposite.initWrapper(RegistryMetricsConstants.SERVICE_LEVEL_KEYS);\n            }\n\n            @Override\n            protected void init(RtStatComposite rtStatComposite) {\n                super.init(rtStatComposite);\n                rtStatComposite.init(\n                        OP_TYPE_REGISTER,\n                        OP_TYPE_SUBSCRIBE,\n                        OP_TYPE_NOTIFY,\n                        OP_TYPE_REGISTER_SERVICE,\n                        OP_TYPE_SUBSCRIBE_SERVICE);\n            }\n        };\n        regStatComposite = new RegistryStatComposite(applicationModel);\n    }\n\n    @Test\n    void testInit() {\n        Assertions.assertEquals(\n                statComposite\n                        .getApplicationStatComposite()\n                        .getApplicationNumStats()\n                        .size(),\n                RegistryMetricsConstants.APP_LEVEL_KEYS.size());\n        // (rt)5 * (applicationRegister,subscribe,notify,applicationRegister.service,subscribe.service)\n        Assertions.assertEquals(\n                5 * 5, statComposite.getRtStatComposite().getRtStats().size());\n        statComposite\n                .getApplicationStatComposite()\n                .getApplicationNumStats()\n                .values()\n                .forEach((v -> Assertions.assertEquals(v.get(), new AtomicLong(0L).get())));\n        statComposite.getRtStatComposite().getRtStats().forEach(rtContainer -> {\n            for (Map.Entry<Metric, ? extends Number> entry : rtContainer.entrySet()) {\n                Assertions.assertEquals(0L, rtContainer.getValueSupplier().apply(entry.getKey()));\n            }\n        });\n    }\n\n    @Test\n    void testIncrement() {\n        regStatComposite.incrMetricsNum(REGISTER_METRIC_REQUESTS, \"beijing\");\n        ApplicationMetric applicationMetric = new ApplicationMetric(applicationModel);\n        applicationMetric.setExtraInfo(\n                Collections.singletonMap(RegistryConstants.REGISTRY_CLUSTER_KEY.toLowerCase(), \"beijing\"));\n        Assertions.assertEquals(\n                1L,\n                regStatComposite\n                        .getAppStats()\n                        .get(REGISTER_METRIC_REQUESTS)\n                        .get(applicationMetric)\n                        .get());\n    }\n\n    @Test\n    void testCalcRt() {\n        statComposite.calcApplicationRt(OP_TYPE_NOTIFY.getType(), 10L);\n        Assertions.assertTrue(statComposite.getRtStatComposite().getRtStats().stream()\n                .anyMatch(longContainer -> longContainer.specifyType(OP_TYPE_NOTIFY.getType())));\n        Optional<LongContainer<? extends Number>> subContainer =\n                statComposite.getRtStatComposite().getRtStats().stream()\n                        .filter(longContainer -> longContainer.specifyType(OP_TYPE_NOTIFY.getType()))\n                        .findFirst();\n        subContainer.ifPresent(v -> Assertions.assertEquals(\n                10L, v.get(new ApplicationMetric(applicationModel)).longValue()));\n    }\n\n    @Test\n    @SuppressWarnings(\"rawtypes\")\n    void testCalcServiceKeyRt() {\n        String serviceKey = \"TestService\";\n        String registryOpType = OP_TYPE_REGISTER_SERVICE.getType();\n        Long responseTime1 = 100L;\n        Long responseTime2 = 200L;\n\n        statComposite.calcServiceKeyRt(serviceKey, registryOpType, responseTime1);\n        statComposite.calcServiceKeyRt(serviceKey, registryOpType, responseTime2);\n\n        List<MetricSample> exportedRtMetrics = statComposite.export(MetricsCategory.RT);\n\n        GaugeMetricSample minSample = (GaugeMetricSample) exportedRtMetrics.stream()\n                .filter(sample -> sample.getTags().containsValue(applicationName))\n                .filter(sample -> sample.getName().equals(METRIC_RT_MIN.getNameByType(\"register.service\")))\n                .findFirst()\n                .orElse(null);\n        GaugeMetricSample maxSample = (GaugeMetricSample) exportedRtMetrics.stream()\n                .filter(sample -> sample.getTags().containsValue(applicationName))\n                .filter(sample -> sample.getName().equals(METRIC_RT_MAX.getNameByType(\"register.service\")))\n                .findFirst()\n                .orElse(null);\n        GaugeMetricSample avgSample = (GaugeMetricSample) exportedRtMetrics.stream()\n                .filter(sample -> sample.getTags().containsValue(applicationName))\n                .filter(sample -> sample.getName().equals(METRIC_RT_AVG.getNameByType(\"register.service\")))\n                .findFirst()\n                .orElse(null);\n\n        Assertions.assertNotNull(minSample);\n        Assertions.assertNotNull(maxSample);\n        Assertions.assertNotNull(avgSample);\n\n        Assertions.assertEquals(responseTime1, minSample.applyAsLong());\n        Assertions.assertEquals(responseTime2, maxSample.applyAsLong());\n        Assertions.assertEquals((responseTime1 + responseTime2) / 2, avgSample.applyAsLong());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-metrics-registry/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-metrics</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-tracing</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The tracing module of dubbo project</description>\n\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-cluster</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <!-- micrometer -->\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-core</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-tracing</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-tracing-integration-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- bridge -->\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-tracing-bridge-otel</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>io.micrometer</groupId>\n      <artifactId>micrometer-tracing-bridge-brave</artifactId>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- exporter -->\n    <dependency>\n      <groupId>io.opentelemetry</groupId>\n      <artifactId>opentelemetry-exporter-zipkin</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>io.opentelemetry</groupId>\n      <artifactId>opentelemetry-exporter-otlp</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>io.zipkin.reporter2</groupId>\n      <artifactId>zipkin-reporter-brave</artifactId>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- sender -->\n    <dependency>\n      <groupId>io.zipkin.reporter2</groupId>\n      <artifactId>zipkin-sender-urlconnection</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>io.zipkin.reporter2</groupId>\n      <artifactId>zipkin-reporter</artifactId>\n      <optional>true</optional>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/AbstractDefaultDubboObservationConvention.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\nimport io.micrometer.common.KeyValues;\nimport io.micrometer.common.docs.KeyName;\nimport io.micrometer.common.lang.Nullable;\n\nimport static org.apache.dubbo.tracing.DubboObservationDocumentation.LowCardinalityKeyNames.RPC_METHOD;\nimport static org.apache.dubbo.tracing.DubboObservationDocumentation.LowCardinalityKeyNames.RPC_SERVICE;\nimport static org.apache.dubbo.tracing.DubboObservationDocumentation.LowCardinalityKeyNames.RPC_SYSTEM;\n\nclass AbstractDefaultDubboObservationConvention {\n    KeyValues getLowCardinalityKeyValues(Invocation invocation) {\n        KeyValues keyValues = KeyValues.of(RPC_SYSTEM.withValue(\"apache_dubbo\"));\n        String serviceName = StringUtils.hasText(invocation.getServiceName())\n                ? invocation.getServiceName()\n                : readServiceName(invocation.getTargetServiceUniqueName());\n        keyValues = appendNonNull(keyValues, RPC_SERVICE, serviceName);\n        return appendNonNull(keyValues, RPC_METHOD, RpcUtils.getMethodName(invocation));\n    }\n\n    protected KeyValues appendNonNull(KeyValues keyValues, KeyName keyName, @Nullable String value) {\n        if (value != null) {\n            return keyValues.and(keyName.withValue(value));\n        }\n        return keyValues;\n    }\n\n    String getContextualName(Invocation invocation) {\n        String serviceName = StringUtils.hasText(invocation.getServiceName())\n                ? invocation.getServiceName()\n                : readServiceName(invocation.getTargetServiceUniqueName());\n        String methodName = RpcUtils.getMethodName(invocation);\n        String method = StringUtils.hasText(methodName) ? methodName : \"\";\n        return serviceName + CommonConstants.PATH_SEPARATOR + method;\n    }\n\n    private String readServiceName(String targetServiceUniqueName) {\n        String[] splitByHyphen = targetServiceUniqueName.split(\n                CommonConstants.PATH_SEPARATOR); // foo-provider/a.b.c:1.0.0 or a.b.c:1.0.0\n        String withVersion = splitByHyphen.length == 1 ? targetServiceUniqueName : splitByHyphen[1];\n        String[] splitByVersion = withVersion.split(CommonConstants.GROUP_CHAR_SEPARATOR); // a.b.c:1.0.0\n        if (splitByVersion.length == 1) {\n            return withVersion;\n        }\n        return splitByVersion[0]; // a.b.c\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/DefaultDubboClientObservationConvention.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcContextAttachment;\nimport org.apache.dubbo.tracing.context.DubboClientContext;\n\nimport java.util.List;\n\nimport io.micrometer.common.KeyValues;\n\nimport static org.apache.dubbo.tracing.DubboObservationDocumentation.LowCardinalityKeyNames.NET_PEER_NAME;\nimport static org.apache.dubbo.tracing.DubboObservationDocumentation.LowCardinalityKeyNames.NET_PEER_PORT;\n\n/**\n * Default implementation of the {@link DubboClientObservationConvention}.\n */\npublic class DefaultDubboClientObservationConvention extends AbstractDefaultDubboObservationConvention\n        implements DubboClientObservationConvention {\n    /**\n     * Singleton instance of {@link DefaultDubboClientObservationConvention}.\n     */\n    private static final DubboClientObservationConvention INSTANCE = new DefaultDubboClientObservationConvention();\n\n    public static DubboClientObservationConvention getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public String getName() {\n        return \"rpc.client.duration\";\n    }\n\n    @Override\n    public KeyValues getLowCardinalityKeyValues(DubboClientContext context) {\n        KeyValues keyValues = super.getLowCardinalityKeyValues(context.getInvocation());\n        return withRemoteHostPort(keyValues, context);\n    }\n\n    private KeyValues withRemoteHostPort(KeyValues keyValues, DubboClientContext context) {\n        List<Invoker<?>> invokedInvokers = context.getInvocation().getInvokedInvokers();\n        if (invokedInvokers.isEmpty()) {\n            return keyValues;\n        }\n        // We'll attach tags only from the first invoker\n        Invoker<?> invoker = invokedInvokers.get(0);\n        URL url = invoker.getUrl();\n        RpcContextAttachment rpcContextAttachment = RpcContext.getClientAttachment();\n        String remoteHost = remoteHost(rpcContextAttachment, url);\n        int remotePort = remotePort(rpcContextAttachment, url);\n        return withRemoteHostPort(keyValues, remoteHost, remotePort);\n    }\n\n    private String remoteHost(RpcContextAttachment rpcContextAttachment, URL url) {\n        String remoteHost = url != null ? url.getHost() : null;\n        return remoteHost != null ? remoteHost : rpcContextAttachment.getRemoteHost();\n    }\n\n    private int remotePort(RpcContextAttachment rpcContextAttachment, URL url) {\n        Integer remotePort = url != null ? url.getPort() : null;\n        if (remotePort != null) {\n            return remotePort;\n        }\n        return rpcContextAttachment.getRemotePort() != 0\n                ? rpcContextAttachment.getRemotePort()\n                : rpcContextAttachment.getLocalPort();\n    }\n\n    private KeyValues withRemoteHostPort(KeyValues keyValues, String remoteHostName, int remotePort) {\n        keyValues = appendNonNull(keyValues, NET_PEER_NAME, remoteHostName);\n        if (remotePort == 0) {\n            return keyValues;\n        }\n        return appendNonNull(keyValues, NET_PEER_PORT, String.valueOf(remotePort));\n    }\n\n    @Override\n    public String getContextualName(DubboClientContext context) {\n        return super.getContextualName(context.getInvocation());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/DefaultDubboServerObservationConvention.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing;\n\nimport org.apache.dubbo.tracing.context.DubboServerContext;\n\nimport io.micrometer.common.KeyValues;\n\n/**\n * Default implementation of the {@link DubboServerObservationConvention}.\n */\npublic class DefaultDubboServerObservationConvention extends AbstractDefaultDubboObservationConvention\n        implements DubboServerObservationConvention {\n\n    /**\n     * Singleton instance of {@link DefaultDubboServerObservationConvention}.\n     */\n    private static final DubboServerObservationConvention INSTANCE = new DefaultDubboServerObservationConvention();\n\n    public static DubboServerObservationConvention getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public String getName() {\n        return \"rpc.server.duration\";\n    }\n\n    @Override\n    public KeyValues getLowCardinalityKeyValues(DubboServerContext context) {\n        return super.getLowCardinalityKeyValues(context.getInvocation());\n    }\n\n    @Override\n    public String getContextualName(DubboServerContext context) {\n        return super.getContextualName(context.getInvocation());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/DubboClientObservationConvention.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing;\n\nimport org.apache.dubbo.tracing.context.DubboClientContext;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationConvention;\n\n/**\n * {@link ObservationConvention} for a {@link DubboClientContext}.\n */\npublic interface DubboClientObservationConvention extends ObservationConvention<DubboClientContext> {\n    @Override\n    default boolean supportsContext(Observation.Context context) {\n        return context instanceof DubboClientContext;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/DubboObservationDocumentation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing;\n\nimport io.micrometer.common.docs.KeyName;\nimport io.micrometer.common.lang.NonNullApi;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationConvention;\nimport io.micrometer.observation.docs.ObservationDocumentation;\n\n/**\n * Documentation of Dubbo observations.\n */\npublic enum DubboObservationDocumentation implements ObservationDocumentation {\n\n    /**\n     * Server side Dubbo RPC Observation.\n     */\n    SERVER {\n        @Override\n        public Class<? extends ObservationConvention<? extends Observation.Context>> getDefaultConvention() {\n            return DefaultDubboServerObservationConvention.class;\n        }\n\n        @Override\n        public KeyName[] getLowCardinalityKeyNames() {\n            return LowCardinalityKeyNames.values();\n        }\n    },\n\n    /**\n     * Client side Dubbo RPC Observation.\n     */\n    CLIENT {\n        @Override\n        public Class<? extends ObservationConvention<? extends Observation.Context>> getDefaultConvention() {\n            return DefaultDubboClientObservationConvention.class;\n        }\n\n        @Override\n        public KeyName[] getLowCardinalityKeyNames() {\n            return LowCardinalityKeyNames.values();\n        }\n    };\n\n    @NonNullApi\n    enum LowCardinalityKeyNames implements KeyName {\n\n        /**\n         * A string identifying the remoting system.\n         * Must be \"apache_dubbo\".\n         */\n        RPC_SYSTEM {\n            @Override\n            public String asString() {\n                return \"rpc.system\";\n            }\n        },\n\n        /**\n         * The full (logical) name of the service being called, including its package name, if applicable.\n         * Example: \"myservice.EchoService\".\n         */\n        RPC_SERVICE {\n            @Override\n            public String asString() {\n                return \"rpc.service\";\n            }\n        },\n\n        /**\n         * The name of the (logical) method being called, must be equal to the $method part in the span name.\n         * Example: \"exampleMethod\".\n         */\n        RPC_METHOD {\n            @Override\n            public String asString() {\n                return \"rpc.method\";\n            }\n        },\n\n        /**\n         * RPC server host name.\n         * Example: \"example.com\".\n         */\n        NET_PEER_NAME {\n            @Override\n            public String asString() {\n                return \"net.peer.name\";\n            }\n        },\n\n        /**\n         * Logical remote port number.\n         * Example: 80; 8080; 443.\n         */\n        NET_PEER_PORT {\n            @Override\n            public String asString() {\n                return \"net.peer.port\";\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/DubboObservationRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.metrics.utils.MetricsSupportUtil;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.tracing.handler.DubboClientTracingObservationHandler;\nimport org.apache.dubbo.tracing.handler.DubboServerTracingObservationHandler;\nimport org.apache.dubbo.tracing.metrics.ObservationMeter;\nimport org.apache.dubbo.tracing.tracer.PropagatorProvider;\nimport org.apache.dubbo.tracing.tracer.PropagatorProviderFactory;\nimport org.apache.dubbo.tracing.tracer.TracerProvider;\nimport org.apache.dubbo.tracing.tracer.TracerProviderFactory;\n\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.handler.DefaultTracingObservationHandler;\nimport io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;\nimport io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;\nimport io.micrometer.tracing.propagation.Propagator;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_NOT_FOUND_TRACER_DEPENDENCY;\n\npublic class DubboObservationRegistry {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DubboObservationRegistry.class);\n\n    private final ApplicationModel applicationModel;\n\n    private final TracingConfig tracingConfig;\n\n    public DubboObservationRegistry(ApplicationModel applicationModel, TracingConfig tracingConfig) {\n        this.applicationModel = applicationModel;\n        this.tracingConfig = tracingConfig;\n    }\n\n    public void initObservationRegistry() {\n        // If get ObservationRegistry.class from external(eg Spring.), use external.\n        ObservationRegistry externalObservationRegistry =\n                applicationModel.getBeanFactory().getBean(ObservationRegistry.class);\n        if (externalObservationRegistry != null) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"ObservationRegistry.class from external is existed.\");\n            }\n            return;\n        }\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Tracing config is: \" + JsonUtils.toJson(tracingConfig));\n        }\n\n        TracerProvider tracerProvider = TracerProviderFactory.getProvider(applicationModel, tracingConfig);\n        if (tracerProvider == null) {\n            logger.warn(\n                    COMMON_NOT_FOUND_TRACER_DEPENDENCY,\n                    \"\",\n                    \"\",\n                    \"Can not found OpenTelemetry/Brave tracer dependencies, skip init ObservationRegistry.\");\n            return;\n        }\n        // The real tracer will come from tracer implementation (OTel / Brave)\n        Tracer tracer = tracerProvider.getTracer();\n\n        // The real propagator will come from tracer implementation (OTel / Brave)\n        PropagatorProvider propagatorProvider = PropagatorProviderFactory.getPropagatorProvider();\n        Propagator propagator = propagatorProvider != null ? propagatorProvider.getPropagator() : Propagator.NOOP;\n\n        ObservationRegistry registry = ObservationRegistry.create();\n        registry.observationConfig()\n                // set up a first matching handler that creates spans - it comes from Micrometer Tracing.\n                // set up spans for sending and receiving data over the wire and a default one.\n                .observationHandler(new ObservationHandler.FirstMatchingCompositeObservationHandler(\n                        new PropagatingSenderTracingObservationHandler<>(tracer, propagator),\n                        new PropagatingReceiverTracingObservationHandler<>(tracer, propagator),\n                        new DefaultTracingObservationHandler(tracer)))\n                .observationHandler(new ObservationHandler.FirstMatchingCompositeObservationHandler(\n                        new DubboClientTracingObservationHandler<>(tracer),\n                        new DubboServerTracingObservationHandler<>(tracer)));\n\n        if (MetricsSupportUtil.isSupportMetrics()) {\n            ObservationMeter.addMeterRegistry(registry, applicationModel);\n        }\n\n        applicationModel.getBeanFactory().registerBean(registry);\n        applicationModel.getBeanFactory().registerBean(tracer);\n        applicationModel.getBeanFactory().registerBean(propagator);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/DubboServerObservationConvention.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing;\n\nimport org.apache.dubbo.tracing.context.DubboServerContext;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationConvention;\n\n/**\n * {@link ObservationConvention} for a {@link DubboServerContext}.\n */\npublic interface DubboServerObservationConvention extends ObservationConvention<DubboServerContext> {\n    @Override\n    default boolean supportsContext(Observation.Context context) {\n        return context instanceof DubboServerContext;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/context/DubboClientContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.context;\n\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\n\nimport java.util.Objects;\n\nimport io.micrometer.observation.transport.Kind;\nimport io.micrometer.observation.transport.SenderContext;\n\n/**\n * Provider context for RPC.\n */\npublic class DubboClientContext extends SenderContext<Invocation> {\n\n    private final Invoker<?> invoker;\n\n    private final Invocation invocation;\n\n    public DubboClientContext(Invoker<?> invoker, Invocation invocation) {\n        super((carrier, key, value) -> Objects.requireNonNull(carrier).setAttachment(key, value), Kind.CLIENT);\n        this.invoker = invoker;\n        this.invocation = invocation;\n        setCarrier(invocation);\n    }\n\n    public Invoker<?> getInvoker() {\n        return invoker;\n    }\n\n    public Invocation getInvocation() {\n        return invocation;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/context/DubboServerContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.context;\n\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\n\nimport io.micrometer.observation.transport.Kind;\nimport io.micrometer.observation.transport.ReceiverContext;\n\n/**\n * Consumer context for RPC.\n */\npublic class DubboServerContext extends ReceiverContext<Invocation> {\n\n    private final Invoker<?> invoker;\n\n    private final Invocation invocation;\n\n    public DubboServerContext(Invoker<?> invoker, Invocation invocation) {\n        super((carrier, s) -> carrier.getAttachment(s), Kind.SERVER);\n        this.invoker = invoker;\n        this.invocation = invocation;\n        setCarrier(invocation);\n    }\n\n    public Invoker<?> getInvoker() {\n        return invoker;\n    }\n\n    public Invocation getInvocation() {\n        return invocation;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/otlp/OTlpSpanExporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.exporter.otlp;\n\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Map;\n\nimport io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;\nimport io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;\nimport io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;\nimport io.opentelemetry.sdk.trace.export.SpanExporter;\n\n/**\n * OTlp span exporter for OTel.\n */\npublic class OTlpSpanExporter {\n\n    public static SpanExporter getSpanExporter(\n            ApplicationModel applicationModel, ExporterConfig.OtlpConfig otlpConfig) {\n        OtlpGrpcSpanExporter externalOTlpGrpcSpanExporter =\n                applicationModel.getBeanFactory().getBean(OtlpGrpcSpanExporter.class);\n        if (externalOTlpGrpcSpanExporter != null) {\n            return externalOTlpGrpcSpanExporter;\n        }\n        OtlpHttpSpanExporter externalOtlpHttpSpanExporter =\n                applicationModel.getBeanFactory().getBean(OtlpHttpSpanExporter.class);\n        if (externalOtlpHttpSpanExporter != null) {\n            return externalOtlpHttpSpanExporter;\n        }\n        OtlpGrpcSpanExporterBuilder builder = OtlpGrpcSpanExporter.builder()\n                .setEndpoint(otlpConfig.getEndpoint())\n                .setTimeout(otlpConfig.getTimeout())\n                .setCompression(otlpConfig.getCompressionMethod());\n        for (Map.Entry<String, String> entry : otlpConfig.getHeaders().entrySet()) {\n            builder.addHeader(entry.getKey(), entry.getValue());\n        }\n        return builder.build();\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanExporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.exporter.zipkin;\n\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport zipkin2.Span;\nimport zipkin2.reporter.BytesEncoder;\nimport zipkin2.reporter.SpanBytesEncoder;\n\n/**\n * Zipkin span exporter for OTel.\n */\npublic class ZipkinSpanExporter {\n\n    public static io.opentelemetry.sdk.trace.export.SpanExporter getSpanExporter(\n            ApplicationModel applicationModel, ExporterConfig.ZipkinConfig zipkinConfig) {\n        BytesEncoder<Span> spanBytesEncoder = getSpanBytesEncoder(applicationModel);\n        return io.opentelemetry.exporter.zipkin.ZipkinSpanExporter.builder()\n                .setEncoder(spanBytesEncoder)\n                .setEndpoint(zipkinConfig.getEndpoint())\n                .setReadTimeout(zipkinConfig.getReadTimeout())\n                .build();\n    }\n\n    private static BytesEncoder<Span> getSpanBytesEncoder(ApplicationModel applicationModel) {\n        BytesEncoder<zipkin2.Span> encoder = applicationModel.getBeanFactory().getBean(BytesEncoder.class);\n        return encoder == null ? SpanBytesEncoder.JSON_V2 : encoder;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.exporter.zipkin;\n\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport brave.handler.SpanHandler;\nimport zipkin2.Span;\nimport zipkin2.reporter.AsyncReporter;\nimport zipkin2.reporter.BytesEncoder;\nimport zipkin2.reporter.SpanBytesEncoder;\nimport zipkin2.reporter.urlconnection.URLConnectionSender;\n\n/**\n * Zipkin span handler for Brave.\n */\npublic class ZipkinSpanHandler {\n\n    public static SpanHandler getSpanHandler(\n            ApplicationModel applicationModel, ExporterConfig.ZipkinConfig zipkinConfig) {\n        URLConnectionSender sender = applicationModel.getBeanFactory().getBean(URLConnectionSender.class);\n        if (sender == null) {\n            URLConnectionSender.Builder builder = URLConnectionSender.newBuilder();\n            builder.connectTimeout((int) zipkinConfig.getConnectTimeout().toMillis());\n            builder.readTimeout((int) zipkinConfig.getReadTimeout().toMillis());\n            builder.endpoint(zipkinConfig.getEndpoint());\n\n            sender = builder.build();\n        }\n\n        BytesEncoder<Span> spanBytesEncoder = getSpanBytesEncoder(applicationModel);\n        AsyncReporter<Span> spanReporter = AsyncReporter.builder(sender).build(spanBytesEncoder);\n        return zipkin2.reporter.brave.ZipkinSpanHandler.newBuilder(spanReporter).build();\n    }\n\n    private static BytesEncoder<zipkin2.Span> getSpanBytesEncoder(ApplicationModel applicationModel) {\n        BytesEncoder<zipkin2.Span> encoder = applicationModel.getBeanFactory().getBean(BytesEncoder.class);\n        return encoder == null ? SpanBytesEncoder.JSON_V2 : encoder;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/filter/ObservationReceiverFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.BaseFilter;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\nimport org.apache.dubbo.tracing.DefaultDubboServerObservationConvention;\nimport org.apache.dubbo.tracing.DubboObservationDocumentation;\nimport org.apache.dubbo.tracing.DubboServerObservationConvention;\nimport org.apache.dubbo.tracing.context.DubboServerContext;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;\n\n/**\n * A {@link Filter} that creates an {@link Observation} around the incoming message.\n */\n@Activate(\n        group = PROVIDER,\n        order = Integer.MIN_VALUE + 50,\n        onClass = \"io.micrometer.observation.NoopObservationRegistry\")\npublic class ObservationReceiverFilter implements Filter, BaseFilter.Listener, ScopeModelAware {\n\n    private final ObservationRegistry observationRegistry;\n\n    private final DubboServerObservationConvention serverObservationConvention;\n\n    public ObservationReceiverFilter(ApplicationModel applicationModel) {\n        observationRegistry = applicationModel.getBeanFactory().getBean(ObservationRegistry.class);\n        serverObservationConvention = applicationModel.getBeanFactory().getBean(DubboServerObservationConvention.class);\n    }\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        if (observationRegistry == null) {\n            return invoker.invoke(invocation);\n        }\n        final DubboServerContext receiverContext = new DubboServerContext(invoker, invocation);\n        final Observation observation = DubboObservationDocumentation.SERVER.observation(\n                this.serverObservationConvention,\n                DefaultDubboServerObservationConvention.getInstance(),\n                () -> receiverContext,\n                observationRegistry);\n        invocation.put(Observation.class, observation.start());\n        return observation.scoped(() -> invoker.invoke(invocation));\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {\n        final Observation observation = getObservation(invocation);\n        if (observation == null) {\n            return;\n        }\n        if (appResponse != null && appResponse.hasException()) {\n            observation.error(appResponse.getException());\n        }\n        observation.stop();\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        final Observation observation = getObservation(invocation);\n        if (observation == null) {\n            return;\n        }\n        observation.error(t);\n        observation.stop();\n    }\n\n    private Observation getObservation(Invocation invocation) {\n        return (Observation) invocation.get(Observation.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/filter/ObservationSenderFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.BaseFilter;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\nimport org.apache.dubbo.tracing.DefaultDubboClientObservationConvention;\nimport org.apache.dubbo.tracing.DubboClientObservationConvention;\nimport org.apache.dubbo.tracing.DubboObservationDocumentation;\nimport org.apache.dubbo.tracing.context.DubboClientContext;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\n\n/**\n * A {@link Filter} that creates an {@link Observation} around the outgoing message.\n */\n@Activate(\n        group = CONSUMER,\n        order = Integer.MIN_VALUE + 50,\n        onClass = \"io.micrometer.observation.NoopObservationRegistry\")\npublic class ObservationSenderFilter implements ClusterFilter, BaseFilter.Listener, ScopeModelAware {\n\n    private final ObservationRegistry observationRegistry;\n\n    private final DubboClientObservationConvention clientObservationConvention;\n\n    public ObservationSenderFilter(ApplicationModel applicationModel) {\n        observationRegistry = applicationModel.getBeanFactory().getBean(ObservationRegistry.class);\n        clientObservationConvention = applicationModel.getBeanFactory().getBean(DubboClientObservationConvention.class);\n    }\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        if (observationRegistry == null) {\n            return invoker.invoke(invocation);\n        }\n        final DubboClientContext senderContext = new DubboClientContext(invoker, invocation);\n        final Observation observation = DubboObservationDocumentation.CLIENT.observation(\n                this.clientObservationConvention,\n                DefaultDubboClientObservationConvention.getInstance(),\n                () -> senderContext,\n                observationRegistry);\n        invocation.put(Observation.class, observation.start());\n        return observation.scoped(() -> invoker.invoke(invocation));\n    }\n\n    @Override\n    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {\n        final Observation observation = getObservation(invocation);\n        if (observation == null) {\n            return;\n        }\n        if (appResponse != null && appResponse.hasException()) {\n            observation.error(appResponse.getException());\n        }\n        observation.stop();\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {\n        final Observation observation = getObservation(invocation);\n        if (observation == null) {\n            return;\n        }\n        observation.error(t);\n        observation.stop();\n    }\n\n    private Observation getObservation(Invocation invocation) {\n        return (Observation) invocation.get(Observation.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/handler/DubboClientTracingObservationHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.handler;\n\nimport org.apache.dubbo.tracing.context.DubboClientContext;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.tracing.Tracer;\n\npublic class DubboClientTracingObservationHandler<T extends DubboClientContext> implements ObservationHandler<T> {\n    private final Tracer tracer;\n\n    public DubboClientTracingObservationHandler(Tracer tracer) {\n        this.tracer = tracer;\n    }\n\n    @Override\n    public void onScopeOpened(T context) {}\n\n    @Override\n    public boolean supportsContext(Observation.Context context) {\n        return context instanceof DubboClientContext;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/handler/DubboServerTracingObservationHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.handler;\n\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.tracing.context.DubboServerContext;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.tracing.TraceContext;\nimport io.micrometer.tracing.Tracer;\n\npublic class DubboServerTracingObservationHandler<T extends DubboServerContext> implements ObservationHandler<T> {\n\n    private static final String DEFAULT_TRACE_ID_KEY = \"traceId\";\n\n    private final Tracer tracer;\n\n    public DubboServerTracingObservationHandler(Tracer tracer) {\n        this.tracer = tracer;\n    }\n\n    @Override\n    public void onScopeOpened(T context) {\n        TraceContext traceContext = tracer.currentTraceContext().context();\n        if (traceContext == null) {\n            return;\n        }\n        RpcContext.getServerContext().setAttachment(DEFAULT_TRACE_ID_KEY, traceContext.traceId());\n    }\n\n    @Override\n    public boolean supportsContext(Observation.Context context) {\n        return context instanceof DubboServerContext;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/metrics/ObservationMeter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.metrics;\n\nimport org.apache.dubbo.metrics.MetricsGlobalRegistry;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.observation.ObservationRegistry;\n\npublic class ObservationMeter {\n\n    public static void addMeterRegistry(ObservationRegistry registry, ApplicationModel applicationModel) {\n        MeterRegistry meterRegistry = MetricsGlobalRegistry.getCompositeRegistry(applicationModel);\n        registry.observationConfig()\n                .observationHandler(\n                        new io.micrometer.core.instrument.observation.DefaultMeterObservationHandler(meterRegistry));\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/PropagatorProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer;\n\nimport io.micrometer.tracing.propagation.Propagator;\n\npublic interface PropagatorProvider {\n\n    /**\n     * The real propagator will come from tracer implementation (OTel / Brave)\n     *\n     * @return Propagator\n     */\n    Propagator getPropagator();\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/PropagatorProviderFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer;\n\nimport org.apache.dubbo.tracing.tracer.brave.BravePropagatorProvider;\nimport org.apache.dubbo.tracing.tracer.otel.OTelPropagatorProvider;\nimport org.apache.dubbo.tracing.utils.ObservationSupportUtil;\n\npublic class PropagatorProviderFactory {\n\n    public static PropagatorProvider getPropagatorProvider() {\n        // If support OTel firstly, return OTel, then Brave.\n        if (ObservationSupportUtil.isSupportOTelTracer()) {\n            return new OTelPropagatorProvider();\n        }\n\n        if (ObservationSupportUtil.isSupportBraveTracer()) {\n            return new BravePropagatorProvider();\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/TracerProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer;\n\nimport io.micrometer.tracing.Tracer;\n\npublic interface TracerProvider {\n\n    /**\n     * Tracer of Micrometer. The real tracer will come from tracer implementation (OTel / Brave)\n     *\n     * @return Tracer\n     */\n    Tracer getTracer();\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/TracerProviderFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer;\n\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.tracing.tracer.brave.BraveProvider;\nimport org.apache.dubbo.tracing.tracer.otel.OpenTelemetryProvider;\nimport org.apache.dubbo.tracing.utils.ObservationSupportUtil;\n\npublic class TracerProviderFactory {\n\n    public static TracerProvider getProvider(ApplicationModel applicationModel, TracingConfig tracingConfig) {\n        // If support OTel firstly, return OTel, then Brave.\n        if (ObservationSupportUtil.isSupportOTelTracer()) {\n            return new OpenTelemetryProvider(applicationModel, tracingConfig);\n        }\n\n        if (ObservationSupportUtil.isSupportBraveTracer()) {\n            return new BraveProvider(applicationModel, tracingConfig);\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/brave/BravePropagatorProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer.brave;\n\nimport org.apache.dubbo.tracing.tracer.PropagatorProvider;\n\nimport io.micrometer.tracing.brave.bridge.BravePropagator;\nimport io.micrometer.tracing.propagation.Propagator;\n\npublic class BravePropagatorProvider implements PropagatorProvider {\n\n    private static Propagator propagator;\n\n    @Override\n    public Propagator getPropagator() {\n        return propagator;\n    }\n\n    protected static void createMicrometerPropagator(brave.Tracing tracing) {\n        propagator = new BravePropagator(tracing);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/brave/BraveProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer.brave;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.nested.BaggageConfig;\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.tracing.exporter.zipkin.ZipkinSpanHandler;\nimport org.apache.dubbo.tracing.tracer.TracerProvider;\nimport org.apache.dubbo.tracing.utils.PropagationType;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\n\nimport io.micrometer.tracing.CurrentTraceContext;\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.brave.bridge.BraveBaggageManager;\nimport io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext;\nimport io.micrometer.tracing.brave.bridge.BraveTracer;\nimport io.micrometer.tracing.brave.bridge.W3CPropagation;\n\nimport static org.apache.dubbo.tracing.utils.ObservationConstants.DEFAULT_APPLICATION_NAME;\nimport static org.apache.dubbo.tracing.utils.ObservationSupportUtil.isSupportBraveURLSender;\n\npublic class BraveProvider implements TracerProvider {\n\n    private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(BraveProvider.class);\n\n    private static final BraveBaggageManager BRAVE_BAGGAGE_MANAGER = new BraveBaggageManager();\n\n    private final ApplicationModel applicationModel;\n    private final TracingConfig tracingConfig;\n\n    public BraveProvider(ApplicationModel applicationModel, TracingConfig tracingConfig) {\n        this.applicationModel = applicationModel;\n        this.tracingConfig = tracingConfig;\n    }\n\n    @Override\n    public Tracer getTracer() {\n        // [Brave component] SpanHandler is a component that gets called when a span is finished.\n        List<brave.handler.SpanHandler> spanHandlerList = getSpanHandlers();\n\n        String applicationName = applicationModel\n                .getApplicationConfigManager()\n                .getApplication()\n                .map(ApplicationConfig::getName)\n                .orElse(DEFAULT_APPLICATION_NAME);\n\n        // [Brave component] CurrentTraceContext is a Brave component that allows you to\n        // retrieve the current TraceContext.\n        brave.propagation.ThreadLocalCurrentTraceContext braveCurrentTraceContext =\n                brave.propagation.ThreadLocalCurrentTraceContext.newBuilder()\n                        .addScopeDecorator(correlationScopeDecorator()) // Brave's automatic MDC setup\n                        .build();\n\n        // [Micrometer Tracing component] A Micrometer Tracing wrapper for Brave's CurrentTraceContext\n        CurrentTraceContext bridgeContext = new BraveCurrentTraceContext(braveCurrentTraceContext);\n\n        // [Brave component] Tracing is the root component that allows to configure the\n        // tracer, handlers, context propagation etc.\n        brave.Tracing.Builder builder = brave.Tracing.newBuilder()\n                .currentTraceContext(braveCurrentTraceContext)\n                .supportsJoin(false)\n                .traceId128Bit(true)\n                .localServiceName(applicationName)\n                // For Baggage to work you need to provide a list of fields to propagate\n                .propagationFactory(PropagatorFactory.getPropagationFactory(tracingConfig))\n                .sampler(getSampler());\n        spanHandlerList.forEach(builder::addSpanHandler);\n\n        brave.Tracing tracing = builder.build();\n\n        BravePropagatorProvider.createMicrometerPropagator(tracing);\n\n        // [Brave component] Tracer is a component that handles the life-cycle of a span\n        brave.Tracer braveTracer = tracing.tracer();\n\n        // [Micrometer Tracing component] A Micrometer Tracing wrapper for Brave's Tracer\n        return new BraveTracer(braveTracer, bridgeContext, BRAVE_BAGGAGE_MANAGER);\n    }\n\n    private List<brave.handler.SpanHandler> getSpanHandlers() {\n        ExporterConfig exporterConfig = tracingConfig.getTracingExporter();\n        List<brave.handler.SpanHandler> res = new ArrayList<>();\n        if (!isSupportBraveURLSender()) {\n            return res;\n        }\n        ExporterConfig.ZipkinConfig zipkinConfig = exporterConfig.getZipkinConfig();\n        if (zipkinConfig != null && StringUtils.isNotEmpty(zipkinConfig.getEndpoint())) {\n            LOGGER.info(\"Create zipkin span handler.\");\n            res.add(ZipkinSpanHandler.getSpanHandler(applicationModel, zipkinConfig));\n        }\n        return res;\n    }\n\n    private brave.sampler.Sampler getSampler() {\n        return brave.sampler.Sampler.create(tracingConfig.getSampling().getProbability());\n    }\n\n    private Optional<brave.baggage.CorrelationScopeCustomizer> correlationFieldsCorrelationScopeCustomizer() {\n        BaggageConfig.Correlation correlation = tracingConfig.getBaggage().getCorrelation();\n        boolean enabled = correlation.isEnabled();\n        if (!enabled) {\n            return Optional.empty();\n        }\n        return Optional.of((builder) -> {\n            List<String> correlationFields = correlation.getFields();\n            for (String field : correlationFields) {\n                builder.add(brave.baggage.CorrelationScopeConfig.SingleCorrelationField.newBuilder(\n                                brave.baggage.BaggageField.create(field))\n                        .flushOnUpdate()\n                        .build());\n            }\n        });\n    }\n\n    private brave.propagation.CurrentTraceContext.ScopeDecorator correlationScopeDecorator() {\n        brave.baggage.CorrelationScopeDecorator.Builder builder = brave.context.slf4j.MDCScopeDecorator.newBuilder();\n        correlationFieldsCorrelationScopeCustomizer().ifPresent((customizer) -> customizer.customize(builder));\n        return builder.build();\n    }\n\n    static class PropagatorFactory {\n\n        public static brave.propagation.Propagation.Factory getPropagationFactory(TracingConfig tracingConfig) {\n            BaggageConfig baggageConfig = tracingConfig.getBaggage();\n            if (baggageConfig == null || !baggageConfig.getEnabled()) {\n                return getPropagationFactoryWithoutBaggage(tracingConfig);\n            }\n            return getPropagationFactoryWithBaggage(tracingConfig);\n        }\n\n        private static brave.propagation.Propagation.Factory getPropagationFactoryWithoutBaggage(\n                TracingConfig tracingConfig) {\n            PropagationType propagationType =\n                    PropagationType.forValue(tracingConfig.getPropagation().getType());\n            if (PropagationType.W3C == propagationType) {\n                return new io.micrometer.tracing.brave.bridge.W3CPropagation();\n            } else {\n                // Brave default propagation is B3\n                return brave.propagation.B3Propagation.newFactoryBuilder()\n                        .injectFormat(brave.propagation.B3Propagation.Format.SINGLE_NO_PARENT)\n                        .build();\n            }\n        }\n\n        private static brave.propagation.Propagation.Factory getPropagationFactoryWithBaggage(\n                TracingConfig tracingConfig) {\n            PropagationType propagationType =\n                    PropagationType.forValue(tracingConfig.getPropagation().getType());\n            brave.propagation.Propagation.Factory delegate;\n            if (PropagationType.W3C == propagationType) {\n                delegate = new W3CPropagation(BRAVE_BAGGAGE_MANAGER, Collections.emptyList());\n            } else {\n                // Brave default propagation is B3\n                delegate = brave.propagation.B3Propagation.newFactoryBuilder()\n                        .injectFormat(brave.propagation.B3Propagation.Format.SINGLE_NO_PARENT)\n                        .build();\n            }\n            return getBaggageFactoryBuilder(delegate, tracingConfig).build();\n        }\n\n        private static brave.baggage.BaggagePropagation.FactoryBuilder getBaggageFactoryBuilder(\n                brave.propagation.Propagation.Factory delegate, TracingConfig tracingConfig) {\n            brave.baggage.BaggagePropagation.FactoryBuilder builder =\n                    brave.baggage.BaggagePropagation.newFactoryBuilder(delegate);\n\n            getBaggagePropagationCustomizers(tracingConfig).forEach((customizer) -> customizer.customize(builder));\n            return builder;\n        }\n\n        private static List<brave.baggage.BaggagePropagationCustomizer> getBaggagePropagationCustomizers(\n                TracingConfig tracingConfig) {\n            List<brave.baggage.BaggagePropagationCustomizer> res = new ArrayList<>();\n            if (tracingConfig.getBaggage().getCorrelation().isEnabled()) {\n                res.add(remoteFieldsBaggagePropagationCustomizer(tracingConfig));\n            }\n            return res;\n        }\n\n        private static brave.baggage.BaggagePropagationCustomizer remoteFieldsBaggagePropagationCustomizer(\n                TracingConfig tracingConfig) {\n            return (builder) -> {\n                List<String> remoteFields = tracingConfig.getBaggage().getRemoteFields();\n                for (String fieldName : remoteFields) {\n                    builder.add(brave.baggage.BaggagePropagationConfig.SingleBaggageField.remote(\n                            brave.baggage.BaggageField.create(fieldName)));\n                }\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/otel/OTelPropagatorProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer.otel;\n\nimport org.apache.dubbo.tracing.tracer.PropagatorProvider;\n\nimport io.micrometer.tracing.otel.bridge.OtelPropagator;\nimport io.micrometer.tracing.propagation.Propagator;\nimport io.opentelemetry.api.trace.Tracer;\nimport io.opentelemetry.context.propagation.ContextPropagators;\n\npublic class OTelPropagatorProvider implements PropagatorProvider {\n\n    private static Propagator propagator;\n\n    @Override\n    public Propagator getPropagator() {\n        return propagator;\n    }\n\n    protected static void createMicrometerPropagator(ContextPropagators contextPropagators, Tracer tracer) {\n        propagator = new OtelPropagator(contextPropagators, tracer);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/otel/OpenTelemetryProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer.otel;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.lang.Nullable;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.nested.BaggageConfig;\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.config.nested.PropagationConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.tracing.exporter.otlp.OTlpSpanExporter;\nimport org.apache.dubbo.tracing.exporter.zipkin.ZipkinSpanExporter;\nimport org.apache.dubbo.tracing.tracer.TracerProvider;\nimport org.apache.dubbo.tracing.utils.PropagationType;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.otel.bridge.CompositeSpanExporter;\nimport io.micrometer.tracing.otel.bridge.EventListener;\nimport io.micrometer.tracing.otel.bridge.EventPublishingContextWrapper;\nimport io.micrometer.tracing.otel.bridge.OtelBaggageManager;\nimport io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;\nimport io.micrometer.tracing.otel.bridge.OtelTracer;\nimport io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;\nimport io.micrometer.tracing.otel.bridge.Slf4JEventListener;\nimport io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator;\nimport io.opentelemetry.api.common.AttributeKey;\n\nimport static org.apache.dubbo.tracing.utils.ObservationConstants.DEFAULT_APPLICATION_NAME;\n\npublic class OpenTelemetryProvider implements TracerProvider {\n\n    private static final ErrorTypeAwareLogger LOGGER =\n            LoggerFactory.getErrorTypeAwareLogger(OpenTelemetryProvider.class);\n\n    private final ApplicationModel applicationModel;\n    private final TracingConfig tracingConfig;\n\n    private OTelEventPublisher publisher;\n    private OtelCurrentTraceContext otelCurrentTraceContext;\n\n    public OpenTelemetryProvider(ApplicationModel applicationModel, TracingConfig tracingConfig) {\n        this.applicationModel = applicationModel;\n        this.tracingConfig = tracingConfig;\n    }\n\n    @Override\n    public Tracer getTracer() {\n        // [OTel component] SpanExporter is a component that gets called when a span is finished.\n        List<io.opentelemetry.sdk.trace.export.SpanExporter> spanExporters = getSpanExporters();\n\n        String applicationName = applicationModel\n                .getApplicationConfigManager()\n                .getApplication()\n                .map(ApplicationConfig::getName)\n                .orElse(DEFAULT_APPLICATION_NAME);\n\n        this.publisher = new OTelEventPublisher(getEventListeners());\n\n        // [Micrometer Tracing component] A Micrometer Tracing wrapper for OTel\n        this.otelCurrentTraceContext = createCurrentTraceContext();\n\n        // Due to https://github.com/micrometer-metrics/tracing/issues/343\n        String RESOURCE_ATTRIBUTES_CLASS_NAME = \"io.opentelemetry.semconv.ResourceAttributes\";\n        boolean isLowVersion = !ClassUtils.isPresent(\n                RESOURCE_ATTRIBUTES_CLASS_NAME, Thread.currentThread().getContextClassLoader());\n        AttributeKey<String> serviceNameAttributeKey = AttributeKey.stringKey(\"service.name\");\n        String SERVICE_NAME = \"SERVICE_NAME\";\n\n        if (isLowVersion) {\n            RESOURCE_ATTRIBUTES_CLASS_NAME = \"io.opentelemetry.semconv.resource.attributes.ResourceAttributes\";\n        }\n        try {\n            serviceNameAttributeKey = (AttributeKey<String>) ClassUtils.resolveClass(\n                            RESOURCE_ATTRIBUTES_CLASS_NAME,\n                            Thread.currentThread().getContextClassLoader())\n                    .getDeclaredField(SERVICE_NAME)\n                    .get(null);\n        } catch (Throwable ignored) {\n        }\n        // [OTel component] SdkTracerProvider is an SDK implementation for TracerProvider\n        io.opentelemetry.sdk.trace.SdkTracerProvider sdkTracerProvider =\n                io.opentelemetry.sdk.trace.SdkTracerProvider.builder()\n                        .setSampler(getSampler())\n                        .setResource(io.opentelemetry.sdk.resources.Resource.create(\n                                io.opentelemetry.api.common.Attributes.of(serviceNameAttributeKey, applicationName)))\n                        .addSpanProcessor(io.opentelemetry.sdk.trace.export.BatchSpanProcessor.builder(\n                                        new CompositeSpanExporter(spanExporters, null, null, null))\n                                .build())\n                        .build();\n\n        io.opentelemetry.context.propagation.ContextPropagators otelContextPropagators = createOtelContextPropagators();\n\n        // [OTel component] The SDK implementation of OpenTelemetry\n        io.opentelemetry.sdk.OpenTelemetrySdk openTelemetrySdk = io.opentelemetry.sdk.OpenTelemetrySdk.builder()\n                .setTracerProvider(sdkTracerProvider)\n                .setPropagators(otelContextPropagators)\n                .build();\n\n        // [OTel component] Tracer is a component that handles the life-cycle of a span\n        io.opentelemetry.api.trace.Tracer otelTracer =\n                openTelemetrySdk.getTracerProvider().get(\"org.apache.dubbo\", Version.getVersion());\n\n        OTelPropagatorProvider.createMicrometerPropagator(otelContextPropagators, otelTracer);\n\n        // [Micrometer Tracing component] A Micrometer Tracing wrapper for OTel's Tracer.\n        return new OtelTracer(\n                otelTracer,\n                otelCurrentTraceContext,\n                publisher,\n                new OtelBaggageManager(\n                        otelCurrentTraceContext,\n                        tracingConfig.getBaggage().getRemoteFields(),\n                        Collections.emptyList()));\n    }\n\n    private List<io.opentelemetry.sdk.trace.export.SpanExporter> getSpanExporters() {\n        ExporterConfig exporterConfig = tracingConfig.getTracingExporter();\n        ExporterConfig.ZipkinConfig zipkinConfig = exporterConfig.getZipkinConfig();\n        ExporterConfig.OtlpConfig otlpConfig = exporterConfig.getOtlpConfig();\n        List<io.opentelemetry.sdk.trace.export.SpanExporter> res = new ArrayList<>();\n        if (zipkinConfig != null && StringUtils.isNotEmpty(zipkinConfig.getEndpoint())) {\n            LOGGER.info(\"Create zipkin span exporter.\");\n            res.add(ZipkinSpanExporter.getSpanExporter(applicationModel, zipkinConfig));\n        }\n        if (otlpConfig != null && StringUtils.isNotEmpty(otlpConfig.getEndpoint())) {\n            LOGGER.info(\"Create OTlp span exporter.\");\n            res.add(OTlpSpanExporter.getSpanExporter(applicationModel, otlpConfig));\n        }\n\n        return res;\n    }\n\n    /**\n     * sampler with probability\n     *\n     * @return sampler\n     */\n    private io.opentelemetry.sdk.trace.samplers.Sampler getSampler() {\n        io.opentelemetry.sdk.trace.samplers.Sampler rootSampler =\n                io.opentelemetry.sdk.trace.samplers.Sampler.traceIdRatioBased(\n                        tracingConfig.getSampling().getProbability());\n        return io.opentelemetry.sdk.trace.samplers.Sampler.parentBased(rootSampler);\n    }\n\n    private List<EventListener> getEventListeners() {\n        List<EventListener> listeners = new ArrayList<>();\n\n        // [Micrometer Tracing component] A Micrometer Tracing listener for setting up MDC.\n        Slf4JEventListener slf4JEventListener = new Slf4JEventListener();\n        listeners.add(slf4JEventListener);\n\n        if (tracingConfig.getBaggage().getEnabled()) {\n            // [Micrometer Tracing component] A Micrometer Tracing listener for setting Baggage in MDC.\n            // Customizable with correlation fields.\n            Slf4JBaggageEventListener slf4JBaggageEventListener = new Slf4JBaggageEventListener(\n                    tracingConfig.getBaggage().getCorrelation().getFields());\n            listeners.add(slf4JBaggageEventListener);\n        }\n\n        return listeners;\n    }\n\n    private OtelCurrentTraceContext createCurrentTraceContext() {\n        io.opentelemetry.context.ContextStorage.addWrapper(new EventPublishingContextWrapper(publisher));\n        return new OtelCurrentTraceContext();\n    }\n\n    private io.opentelemetry.context.propagation.ContextPropagators createOtelContextPropagators() {\n        return io.opentelemetry.context.propagation.ContextPropagators.create(\n                io.opentelemetry.context.propagation.TextMapPropagator.composite(PropagatorFactory.getPropagator(\n                        tracingConfig.getPropagation(), tracingConfig.getBaggage(), otelCurrentTraceContext)));\n    }\n\n    static class OTelEventPublisher implements OtelTracer.EventPublisher {\n\n        private final List<EventListener> listeners;\n\n        OTelEventPublisher(List<EventListener> listeners) {\n            this.listeners = listeners;\n        }\n\n        @Override\n        public void publishEvent(Object event) {\n            for (EventListener listener : this.listeners) {\n                listener.onEvent(event);\n            }\n        }\n    }\n\n    static class PropagatorFactory {\n\n        public static io.opentelemetry.context.propagation.TextMapPropagator getPropagator(\n                PropagationConfig propagationConfig,\n                @Nullable BaggageConfig baggageConfig,\n                @Nullable OtelCurrentTraceContext currentTraceContext) {\n            if (baggageConfig == null || !baggageConfig.getEnabled()) {\n                return getPropagatorWithoutBaggage(propagationConfig);\n            }\n            return getPropagatorWithBaggage(propagationConfig, baggageConfig, currentTraceContext);\n        }\n\n        private static io.opentelemetry.context.propagation.TextMapPropagator getPropagatorWithoutBaggage(\n                PropagationConfig propagationConfig) {\n            String type = propagationConfig.getType();\n            PropagationType propagationType = PropagationType.forValue(type);\n\n            if (PropagationType.B3 == propagationType) {\n                return io.opentelemetry.extension.trace.propagation.B3Propagator.injectingSingleHeader();\n            } else if (PropagationType.W3C == propagationType) {\n                return io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator.getInstance();\n            }\n            return io.opentelemetry.context.propagation.TextMapPropagator.noop();\n        }\n\n        private static io.opentelemetry.context.propagation.TextMapPropagator getPropagatorWithBaggage(\n                PropagationConfig propagationConfig,\n                BaggageConfig baggageConfig,\n                OtelCurrentTraceContext currentTraceContext) {\n            String type = propagationConfig.getType();\n            PropagationType propagationType = PropagationType.forValue(type);\n            if (PropagationType.B3 == propagationType) {\n                List<String> remoteFields = baggageConfig.getRemoteFields();\n                return io.opentelemetry.context.propagation.TextMapPropagator.composite(\n                        io.opentelemetry.extension.trace.propagation.B3Propagator.injectingSingleHeader(),\n                        new BaggageTextMapPropagator(\n                                remoteFields,\n                                new OtelBaggageManager(currentTraceContext, remoteFields, Collections.emptyList())));\n            } else if (PropagationType.W3C == propagationType) {\n                List<String> remoteFields = baggageConfig.getRemoteFields();\n                return io.opentelemetry.context.propagation.TextMapPropagator.composite(\n                        io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator.getInstance(),\n                        io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator.getInstance(),\n                        new BaggageTextMapPropagator(\n                                remoteFields,\n                                new OtelBaggageManager(currentTraceContext, remoteFields, Collections.emptyList())));\n            }\n            return io.opentelemetry.context.propagation.TextMapPropagator.noop();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/ObservationConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.utils;\n\npublic class ObservationConstants {\n\n    public static final String DEFAULT_APPLICATION_NAME = \"dubbo-application\";\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/ObservationSupportUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.utils;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\n\npublic class ObservationSupportUtil {\n\n    public static boolean isSupportObservation() {\n        return isClassPresent(\"io.micrometer.observation.Observation\")\n                && isClassPresent(\"io.micrometer.observation.ObservationRegistry\")\n                && isClassPresent(\"io.micrometer.observation.ObservationHandler\");\n    }\n\n    public static boolean isSupportTracing() {\n        return isClassPresent(\"io.micrometer.tracing.Tracer\")\n                && isClassPresent(\"io.micrometer.tracing.propagation.Propagator\");\n    }\n\n    public static boolean isSupportOTelTracer() {\n        return isClassPresent(\"io.micrometer.tracing.otel.bridge.OtelTracer\")\n                && isClassPresent(\"io.opentelemetry.sdk.trace.SdkTracerProvider\")\n                && isClassPresent(\"io.opentelemetry.api.OpenTelemetry\");\n    }\n\n    public static boolean isSupportBraveTracer() {\n        return isClassPresent(\"io.micrometer.tracing.Tracer\")\n                && isClassPresent(\"io.micrometer.tracing.brave.bridge.BraveTracer\")\n                && isClassPresent(\"brave.Tracing\");\n    }\n\n    public static boolean isSupportBraveURLSender() {\n        return isClassPresent(\"zipkin2.reporter.urlconnection.URLConnectionSender\");\n    }\n\n    private static boolean isClassPresent(String className) {\n        return ClassUtils.isPresent(className, ObservationSupportUtil.class.getClassLoader());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/PropagationType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.utils;\n\npublic enum PropagationType {\n    W3C(\"W3C\"),\n    B3(\"B3\");\n\n    private final String value;\n\n    PropagationType(String type) {\n        this.value = type;\n    }\n\n    public String getValue() {\n        return value;\n    }\n\n    public static PropagationType forValue(String value) {\n        PropagationType[] values = values();\n        for (PropagationType type : values) {\n            if (type.getValue().equals(value)) {\n                return type;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter",
    "content": "observationreceiver=org.apache.dubbo.tracing.filter.ObservationReceiverFilter"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.ClusterFilter",
    "content": "observationsender=org.apache.dubbo.tracing.filter.ObservationSenderFilter"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/DefaultDubboClientObservationConventionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing;\n\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.tracing.context.DubboClientContext;\nimport org.apache.dubbo.tracing.utils.ObservationConventionUtils;\n\nimport io.micrometer.common.KeyValues;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\npublic class DefaultDubboClientObservationConventionTest {\n\n    static DubboClientObservationConvention dubboClientObservationConvention =\n            DefaultDubboClientObservationConvention.getInstance();\n\n    @Test\n    void testGetName() {\n        Assertions.assertEquals(\"rpc.client.duration\", dubboClientObservationConvention.getName());\n    }\n\n    @Test\n    void testGetLowCardinalityKeyValues() throws NoSuchFieldException, IllegalAccessException {\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"testMethod\");\n        invocation.setAttachment(\"interface\", \"com.example.TestService\");\n        invocation.setTargetServiceUniqueName(\"targetServiceName1\");\n\n        Invoker<?> invoker = ObservationConventionUtils.getMockInvokerWithUrl();\n        invocation.setInvoker(invoker);\n\n        DubboClientContext context = new DubboClientContext(invoker, invocation);\n\n        KeyValues keyValues = dubboClientObservationConvention.getLowCardinalityKeyValues(context);\n\n        Assertions.assertEquals(\"testMethod\", ObservationConventionUtils.getValueForKey(keyValues, \"rpc.method\"));\n        Assertions.assertEquals(\n                \"targetServiceName1\", ObservationConventionUtils.getValueForKey(keyValues, \"rpc.service\"));\n        Assertions.assertEquals(\"apache_dubbo\", ObservationConventionUtils.getValueForKey(keyValues, \"rpc.system\"));\n    }\n\n    @Test\n    void testGetContextualName() {\n        RpcInvocation invocation = new RpcInvocation();\n        Invoker<?> invoker = ObservationConventionUtils.getMockInvokerWithUrl();\n        invocation.setMethodName(\"testMethod\");\n        invocation.setServiceName(\"com.example.TestService\");\n\n        DubboClientContext context = new DubboClientContext(invoker, invocation);\n\n        DefaultDubboClientObservationConvention convention = new DefaultDubboClientObservationConvention();\n\n        String contextualName = convention.getContextualName(context);\n        Assertions.assertEquals(\"com.example.TestService/testMethod\", contextualName);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/DefaultDubboServerObservationConventionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing;\n\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.tracing.context.DubboClientContext;\nimport org.apache.dubbo.tracing.context.DubboServerContext;\nimport org.apache.dubbo.tracing.utils.ObservationConventionUtils;\n\nimport io.micrometer.common.KeyValues;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n@SuppressWarnings(\"deprecation\")\npublic class DefaultDubboServerObservationConventionTest {\n\n    static DubboServerObservationConvention dubboServerObservationConvention =\n            DefaultDubboServerObservationConvention.getInstance();\n\n    @Test\n    void testGetName() {\n        Assertions.assertEquals(\"rpc.server.duration\", dubboServerObservationConvention.getName());\n    }\n\n    @Test\n    void testGetLowCardinalityKeyValues() throws NoSuchFieldException, IllegalAccessException {\n        RpcInvocation invocation = new RpcInvocation();\n        invocation.setMethodName(\"testMethod\");\n        invocation.setAttachment(\"interface\", \"com.example.TestService\");\n        invocation.setTargetServiceUniqueName(\"targetServiceName1\");\n\n        Invoker<?> invoker = ObservationConventionUtils.getMockInvokerWithUrl();\n        invocation.setInvoker(invoker);\n\n        DubboServerContext context = new DubboServerContext(invoker, invocation);\n\n        KeyValues keyValues = dubboServerObservationConvention.getLowCardinalityKeyValues(context);\n\n        Assertions.assertEquals(\"testMethod\", ObservationConventionUtils.getValueForKey(keyValues, \"rpc.method\"));\n        Assertions.assertEquals(\n                \"targetServiceName1\", ObservationConventionUtils.getValueForKey(keyValues, \"rpc.service\"));\n        Assertions.assertEquals(\"apache_dubbo\", ObservationConventionUtils.getValueForKey(keyValues, \"rpc.system\"));\n    }\n\n    @Test\n    void testGetContextualName() {\n        RpcInvocation invocation = new RpcInvocation();\n        Invoker<?> invoker = ObservationConventionUtils.getMockInvokerWithUrl();\n        invocation.setMethodName(\"testMethod\");\n        invocation.setServiceName(\"com.example.TestService\");\n\n        DubboClientContext context = new DubboClientContext(invoker, invocation);\n\n        DefaultDubboClientObservationConvention convention = new DefaultDubboClientObservationConvention();\n\n        String contextualName = convention.getContextualName(context);\n        Assertions.assertEquals(\"com.example.TestService/testMethod\", contextualName);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/MockInvocation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing;\n\nimport org.apache.dubbo.rpc.AttachmentsAdapter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.rpc.Constants.TOKEN_KEY;\n\n/**\n * MockInvocation.java\n */\npublic class MockInvocation extends RpcInvocation {\n\n    private Map<String, Object> attachments;\n\n    public MockInvocation() {\n        attachments = new HashMap<>();\n        attachments.put(PATH_KEY, \"dubbo\");\n        attachments.put(GROUP_KEY, \"dubbo\");\n        attachments.put(VERSION_KEY, \"1.0.0\");\n        attachments.put(DUBBO_VERSION_KEY, \"1.0.0\");\n        attachments.put(TOKEN_KEY, \"sfag\");\n        attachments.put(TIMEOUT_KEY, \"1000\");\n    }\n\n    @Override\n    public String getTargetServiceUniqueName() {\n        return null;\n    }\n\n    @Override\n    public String getProtocolServiceKey() {\n        return null;\n    }\n\n    public String getMethodName() {\n        return \"echo\";\n    }\n\n    @Override\n    public String getServiceName() {\n        return \"DemoService\";\n    }\n\n    public Class<?>[] getParameterTypes() {\n        return new Class[] {String.class};\n    }\n\n    public Object[] getArguments() {\n        return new Object[] {\"aa\"};\n    }\n\n    public Map<String, String> getAttachments() {\n        return new AttachmentsAdapter.ObjectToStringMap(attachments);\n    }\n\n    @Override\n    public Map<String, Object> getObjectAttachments() {\n        return attachments;\n    }\n\n    @Override\n    public void setAttachment(String key, String value) {\n        setObjectAttachment(key, value);\n    }\n\n    @Override\n    public void setAttachment(String key, Object value) {\n        setObjectAttachment(key, value);\n    }\n\n    @Override\n    public void setObjectAttachment(String key, Object value) {\n        attachments.put(key, value);\n    }\n\n    @Override\n    public void setAttachmentIfAbsent(String key, String value) {\n        setObjectAttachmentIfAbsent(key, value);\n    }\n\n    @Override\n    public void setAttachmentIfAbsent(String key, Object value) {\n        setObjectAttachmentIfAbsent(key, value);\n    }\n\n    @Override\n    public void setObjectAttachmentIfAbsent(String key, Object value) {\n        attachments.put(key, value);\n    }\n\n    public Invoker<?> getInvoker() {\n        return null;\n    }\n\n    @Override\n    public void setServiceModel(ServiceModel serviceModel) {}\n\n    @Override\n    public ServiceModel getServiceModel() {\n        return null;\n    }\n\n    @Override\n    public Object put(Object key, Object value) {\n        return null;\n    }\n\n    @Override\n    public Object get(Object key) {\n        return null;\n    }\n\n    @Override\n    public Map<Object, Object> getAttributes() {\n        return null;\n    }\n\n    public String getAttachment(String key) {\n        return (String) getObjectAttachments().get(key);\n    }\n\n    @Override\n    public Object getObjectAttachment(String key) {\n        return attachments.get(key);\n    }\n\n    public String getAttachment(String key, String defaultValue) {\n        return (String) getObjectAttachments().get(key);\n    }\n\n    @Override\n    public Object getObjectAttachment(String key, Object defaultValue) {\n        Object result = attachments.get(key);\n        if (result == null) {\n            return defaultValue;\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/otlp/OTlpSpanExporterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.exporter.otlp;\n\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.time.Duration;\n\nimport io.opentelemetry.sdk.trace.export.SpanExporter;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass OTlpSpanExporterTest {\n\n    @Test\n    void getSpanExporter() {\n        ExporterConfig.OtlpConfig otlpConfig = mock(ExporterConfig.OtlpConfig.class);\n        when(otlpConfig.getEndpoint()).thenReturn(\"http://localhost:9411/api/v2/spans\");\n        when(otlpConfig.getTimeout()).thenReturn(Duration.ofSeconds(5));\n        when(otlpConfig.getCompressionMethod()).thenReturn(\"gzip\");\n\n        SpanExporter spanExporter = OTlpSpanExporter.getSpanExporter(ApplicationModel.defaultModel(), otlpConfig);\n        Assertions.assertNotNull(spanExporter);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanExporterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.exporter.zipkin;\n\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.time.Duration;\n\nimport io.opentelemetry.sdk.trace.export.SpanExporter;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass ZipkinSpanExporterTest {\n\n    @Test\n    void getSpanExporter() {\n        ExporterConfig.ZipkinConfig zipkinConfig = mock(ExporterConfig.ZipkinConfig.class);\n        when(zipkinConfig.getEndpoint()).thenReturn(\"http://localhost:9411/api/v2/spans\");\n        when(zipkinConfig.getConnectTimeout()).thenReturn(Duration.ofSeconds(5));\n        when(zipkinConfig.getReadTimeout()).thenReturn(Duration.ofSeconds(5));\n\n        SpanExporter spanExporter = ZipkinSpanExporter.getSpanExporter(ApplicationModel.defaultModel(), zipkinConfig);\n        Assertions.assertNotNull(spanExporter);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.exporter.zipkin;\n\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.time.Duration;\n\nimport brave.handler.SpanHandler;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass ZipkinSpanHandlerTest {\n\n    @Test\n    void getSpanHandler() {\n        ExporterConfig.ZipkinConfig zipkinConfig = mock(ExporterConfig.ZipkinConfig.class);\n        when(zipkinConfig.getEndpoint()).thenReturn(\"http://localhost:9411/api/v2/spans\");\n        when(zipkinConfig.getConnectTimeout()).thenReturn(Duration.ofSeconds(5));\n\n        SpanHandler spanHandler = ZipkinSpanHandler.getSpanHandler(ApplicationModel.defaultModel(), zipkinConfig);\n        Assertions.assertNotNull(spanHandler);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/PropagatorProviderFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer;\n\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.tracing.tracer.otel.OTelPropagatorProvider;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass PropagatorProviderFactoryTest {\n\n    @Test\n    void testPropagatorProviderFactory() {\n        PropagatorProvider propagatorProvider = PropagatorProviderFactory.getPropagatorProvider();\n        Assert.notNull(propagatorProvider, \"PropagatorProvider should not be null\");\n        assertEquals(OTelPropagatorProvider.class, propagatorProvider.getClass());\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/brave/BravePropagatorProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer.brave;\n\nimport org.apache.dubbo.common.utils.Assert;\n\nimport brave.Tracing;\nimport io.micrometer.tracing.propagation.Propagator;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.mock;\n\nclass BravePropagatorProviderTest {\n\n    @Test\n    void testBravePropagatorProvider() {\n        Tracing tracing = mock(Tracing.class);\n        BravePropagatorProvider.createMicrometerPropagator(tracing);\n\n        BravePropagatorProvider bravePropagatorProvider = new BravePropagatorProvider();\n        Propagator propagator = bravePropagatorProvider.getPropagator();\n        Assert.notNull(propagator, \"Propagator don't be null.\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/brave/BraveProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer.brave;\n\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.nested.BaggageConfig;\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.config.nested.PropagationConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.tracing.utils.PropagationType;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport brave.propagation.Propagation;\nimport io.micrometer.tracing.Tracer;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass BraveProviderTest {\n\n    @Test\n    void testGetTracer() {\n        TracingConfig tracingConfig = new TracingConfig();\n        tracingConfig.setEnabled(true);\n        ExporterConfig exporterConfig = new ExporterConfig();\n        exporterConfig.setZipkinConfig(new ExporterConfig.ZipkinConfig(\"\"));\n        tracingConfig.setTracingExporter(exporterConfig);\n\n        BraveProvider braveProvider = new BraveProvider(ApplicationModel.defaultModel(), tracingConfig);\n        Tracer tracer = braveProvider.getTracer();\n        Assert.notNull(tracer, \"Tracer should not be null.\");\n        assertEquals(io.micrometer.tracing.brave.bridge.BraveTracer.class, tracer.getClass());\n    }\n\n    @Test\n    void testGetPropagator() {\n        TracingConfig tracingConfig = mock(TracingConfig.class);\n        PropagationConfig propagationConfig = mock(PropagationConfig.class);\n        when(tracingConfig.getPropagation()).thenReturn(propagationConfig);\n        BaggageConfig baggageConfig = mock(BaggageConfig.class);\n        when(tracingConfig.getBaggage()).thenReturn(baggageConfig);\n\n        // no baggage\n        when(baggageConfig.getEnabled()).thenReturn(Boolean.FALSE);\n\n        when(propagationConfig.getType()).thenReturn(PropagationType.W3C.getValue());\n        Propagation.Factory w3cPropagationFactoryWithoutBaggage =\n                BraveProvider.PropagatorFactory.getPropagationFactory(tracingConfig);\n        assertEquals(\n                io.micrometer.tracing.brave.bridge.W3CPropagation.class,\n                w3cPropagationFactoryWithoutBaggage.getClass());\n\n        when(propagationConfig.getType()).thenReturn(PropagationType.B3.getValue());\n        Propagation.Factory b3PropagationFactoryWithoutBaggage =\n                BraveProvider.PropagatorFactory.getPropagationFactory(tracingConfig);\n        Assert.notNull(b3PropagationFactoryWithoutBaggage, \"b3PropagationFactoryWithoutBaggage should not be null.\");\n\n        // with baggage\n        when(baggageConfig.getEnabled()).thenReturn(Boolean.TRUE);\n        BaggageConfig.Correlation correlation = mock(BaggageConfig.Correlation.class);\n        when(correlation.isEnabled()).thenReturn(Boolean.TRUE);\n        when(baggageConfig.getCorrelation()).thenReturn(correlation);\n        List<String> remoteFields = new ArrayList<>();\n        for (int i = 0; i < 10; i++) {\n            remoteFields.add(\"test-hd-\" + i);\n        }\n        when(baggageConfig.getRemoteFields()).thenReturn(remoteFields);\n        Propagation.Factory propagationFactoryWithBaggage =\n                BraveProvider.PropagatorFactory.getPropagationFactory(tracingConfig);\n        Assert.notNull(propagationFactoryWithBaggage, \"propagationFactoryWithBaggage should not be null.\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/otel/OTelPropagatorProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer.otel;\n\nimport org.apache.dubbo.common.utils.Assert;\n\nimport io.micrometer.tracing.propagation.Propagator;\nimport io.opentelemetry.api.trace.Tracer;\nimport io.opentelemetry.context.propagation.ContextPropagators;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.mock;\n\nclass OTelPropagatorProviderTest {\n\n    @Test\n    void testOTelPropagatorProvider() {\n        ContextPropagators contextPropagators = mock(ContextPropagators.class);\n        Tracer tracer = mock(Tracer.class);\n        OTelPropagatorProvider.createMicrometerPropagator(contextPropagators, tracer);\n        OTelPropagatorProvider oTelPropagatorProvider = new OTelPropagatorProvider();\n        Propagator propagator = oTelPropagatorProvider.getPropagator();\n        Assert.notNull(propagator, \"Propagator don't be null.\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/otel/OpenTelemetryProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.tracer.otel;\n\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.nested.BaggageConfig;\nimport org.apache.dubbo.config.nested.ExporterConfig;\nimport org.apache.dubbo.config.nested.PropagationConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.tracing.tracer.TracerProvider;\nimport org.apache.dubbo.tracing.tracer.TracerProviderFactory;\nimport org.apache.dubbo.tracing.utils.PropagationType;\n\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;\nimport io.micrometer.tracing.otel.bridge.OtelTracer;\nimport io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;\nimport io.opentelemetry.context.propagation.TextMapPropagator;\nimport io.opentelemetry.extension.trace.propagation.B3Propagator;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass OpenTelemetryProviderTest {\n\n    @Test\n    void testGetTracer() {\n        TracingConfig tracingConfig = new TracingConfig();\n        tracingConfig.setEnabled(true);\n        ExporterConfig exporterConfig = new ExporterConfig();\n        exporterConfig.setZipkinConfig(new ExporterConfig.ZipkinConfig(\"\"));\n        tracingConfig.setTracingExporter(exporterConfig);\n        TracerProvider tracerProvider1 =\n                TracerProviderFactory.getProvider(ApplicationModel.defaultModel(), tracingConfig);\n        Assert.notNull(tracerProvider1, \"TracerProvider should not be null.\");\n        Tracer tracer1 = tracerProvider1.getTracer();\n        assertEquals(OtelTracer.class, tracer1.getClass());\n\n        tracingConfig.setBaggage(new BaggageConfig(false));\n        TracerProvider tracerProvider2 =\n                TracerProviderFactory.getProvider(ApplicationModel.defaultModel(), tracingConfig);\n        Assert.notNull(tracerProvider2, \"TracerProvider should not be null.\");\n        Tracer tracer2 = tracerProvider2.getTracer();\n        assertEquals(OtelTracer.class, tracer2.getClass());\n    }\n\n    @Test\n    void testGetPropagator() {\n        PropagationConfig propagationConfig = mock(PropagationConfig.class);\n        BaggageConfig baggageConfig = mock(BaggageConfig.class);\n        OtelCurrentTraceContext otelCurrentTraceContext = mock(OtelCurrentTraceContext.class);\n\n        when(baggageConfig.getEnabled()).thenReturn(Boolean.FALSE);\n\n        when(propagationConfig.getType()).thenReturn(PropagationType.B3.getValue());\n        TextMapPropagator b3PropagatorWithoutBaggage = OpenTelemetryProvider.PropagatorFactory.getPropagator(\n                propagationConfig, baggageConfig, otelCurrentTraceContext);\n        assertEquals(B3Propagator.class, b3PropagatorWithoutBaggage.getClass());\n\n        when(propagationConfig.getType()).thenReturn(PropagationType.W3C.getValue());\n        TextMapPropagator w3cPropagatorWithoutBaggage = OpenTelemetryProvider.PropagatorFactory.getPropagator(\n                propagationConfig, baggageConfig, otelCurrentTraceContext);\n        assertEquals(W3CTraceContextPropagator.class, w3cPropagatorWithoutBaggage.getClass());\n\n        when(baggageConfig.getEnabled()).thenReturn(Boolean.TRUE);\n        TextMapPropagator propagatorWithBaggage = OpenTelemetryProvider.PropagatorFactory.getPropagator(\n                propagationConfig, baggageConfig, otelCurrentTraceContext);\n        Assert.notNull(propagatorWithBaggage, \"PropagatorWithBaggage should not be null\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/utils/ObservationConventionUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.utils;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invoker;\n\nimport java.lang.reflect.Field;\n\nimport io.micrometer.common.KeyValue;\nimport io.micrometer.common.KeyValues;\nimport org.mockito.Mockito;\n\npublic class ObservationConventionUtils {\n\n    public static Invoker<?> getMockInvokerWithUrl() {\n        URL url = URL.valueOf(\n                \"dubbo://127.0.0.1:12345/com.example.TestService?anyhost=true&application=test&category=providers&dubbo=2.0.2&generic=false&interface=com.example.TestService&methods=testMethod&pid=26716&side=provider&timestamp=1633863896653\");\n        Invoker<?> invoker = Mockito.mock(Invoker.class);\n        Mockito.when(invoker.getUrl()).thenReturn(url);\n        return invoker;\n    }\n\n    public static String getValueForKey(KeyValues keyValues, Object key)\n            throws NoSuchFieldException, IllegalAccessException {\n        Field f = KeyValues.class.getDeclaredField(\"sortedSet\");\n        f.setAccessible(true);\n        KeyValue[] kv = (KeyValue[]) f.get(keyValues);\n        for (KeyValue keyValue : kv) {\n            if (keyValue.getKey().equals(key)) {\n                return keyValue.getValue();\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/utils/ObservationSupportUtilTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.utils;\n\nimport org.apache.dubbo.common.utils.Assert;\n\nimport org.junit.jupiter.api.Test;\n\npublic class ObservationSupportUtilTest {\n\n    @Test\n    void testIsSupportObservation() {\n        boolean supportObservation = ObservationSupportUtil.isSupportObservation();\n        Assert.assertTrue(supportObservation, \"ObservationSupportUtil.isSupportObservation() should return true\");\n    }\n\n    @Test\n    void testIsSupportTracing() {\n        boolean supportTracing = ObservationSupportUtil.isSupportTracing();\n        Assert.assertTrue(supportTracing, \"ObservationSupportUtil.isSupportTracing() should return true\");\n    }\n\n    @Test\n    void testIsSupportOTelTracer() {\n        boolean supportOTelTracer = ObservationSupportUtil.isSupportOTelTracer();\n        Assert.assertTrue(supportOTelTracer, \"ObservationSupportUtil.isSupportOTelTracer() should return true\");\n    }\n\n    @Test\n    void testIsSupportBraveTracer() {\n        boolean supportBraveTracer = ObservationSupportUtil.isSupportBraveTracer();\n        Assert.assertTrue(supportBraveTracer, \"ObservationSupportUtil.isSupportOTelTracer() should return true\");\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/utils/PropagationTypeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.tracing.utils;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass PropagationTypeTest {\n\n    @Test\n    void forValue() {\n        PropagationType propagationType1 = PropagationType.forValue(\"W3C\");\n        assertEquals(PropagationType.W3C, propagationType1);\n\n        PropagationType propagationType2 = PropagationType.forValue(\"B3\");\n        assertEquals(PropagationType.B3, propagationType2);\n\n        PropagationType propagationType3 = PropagationType.forValue(\"B33\");\n        assertNull(propagationType3);\n    }\n}\n"
  },
  {
    "path": "dubbo-metrics/dubbo-tracing/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-metrics/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-metrics</artifactId>\n  <packaging>pom</packaging>\n  <name>${project.artifactId}</name>\n  <description>The metrics module of dubbo project</description>\n  <modules>\n    <module>dubbo-metrics-api</module>\n    <module>dubbo-metrics-event</module>\n    <module>dubbo-metrics-default</module>\n    <module>dubbo-metrics-registry</module>\n    <module>dubbo-metrics-metadata</module>\n    <module>dubbo-metrics-prometheus</module>\n    <module>dubbo-metrics-config-center</module>\n    <module>dubbo-tracing</module>\n    <module>dubbo-metrics-netty</module>\n    <module>dubbo-metrics-otlp</module>\n  </modules>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-auth</artifactId>\n  <packaging>jar</packaging>\n\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/AccessKeyAuthenticator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth;\n\nimport org.apache.dubbo.auth.exception.AccessKeyNotFoundException;\nimport org.apache.dubbo.auth.exception.RpcAuthenticationException;\nimport org.apache.dubbo.auth.model.AccessKeyPair;\nimport org.apache.dubbo.auth.spi.AccessKeyStorage;\nimport org.apache.dubbo.auth.spi.Authenticator;\nimport org.apache.dubbo.auth.utils.SignatureUtils;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.support.RpcUtils;\n\npublic class AccessKeyAuthenticator implements Authenticator {\n    private final FrameworkModel frameworkModel;\n\n    public AccessKeyAuthenticator(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public void sign(Invocation invocation, URL url) {\n        String currentTime = String.valueOf(System.currentTimeMillis());\n        AccessKeyPair accessKeyPair = getAccessKeyPair(invocation, url);\n        invocation.setAttachment(\n                Constants.REQUEST_SIGNATURE_KEY,\n                getSignature(url, invocation, accessKeyPair.getSecretKey(), currentTime));\n        invocation.setAttachment(Constants.REQUEST_TIMESTAMP_KEY, currentTime);\n        invocation.setAttachment(Constants.AK_KEY, accessKeyPair.getAccessKey());\n        invocation.setAttachment(CommonConstants.CONSUMER, url.getApplication());\n    }\n\n    @Override\n    public void authenticate(Invocation invocation, URL url) throws RpcAuthenticationException {\n        String accessKeyId = String.valueOf(invocation.getAttachment(Constants.AK_KEY));\n        String requestTimestamp = String.valueOf(invocation.getAttachment(Constants.REQUEST_TIMESTAMP_KEY));\n        String originSignature = String.valueOf(invocation.getAttachment(Constants.REQUEST_SIGNATURE_KEY));\n        String consumer = String.valueOf(invocation.getAttachment(CommonConstants.CONSUMER));\n        if (StringUtils.isAnyEmpty(accessKeyId, consumer, requestTimestamp, originSignature)) {\n            throw new RpcAuthenticationException(\"Failed to authenticate, maybe consumer side did not enable the auth\");\n        }\n\n        AccessKeyPair accessKeyPair;\n        try {\n            accessKeyPair = getAccessKeyPair(invocation, url);\n        } catch (Exception e) {\n            throw new RpcAuthenticationException(\"Failed to authenticate , can't load the accessKeyPair\");\n        }\n\n        String computeSignature = getSignature(url, invocation, accessKeyPair.getSecretKey(), requestTimestamp);\n        boolean success = computeSignature.equals(originSignature);\n        if (!success) {\n            throw new RpcAuthenticationException(\"Failed to authenticate, signature is not correct\");\n        }\n    }\n\n    AccessKeyPair getAccessKeyPair(Invocation invocation, URL url) {\n        AccessKeyStorage accessKeyStorage = frameworkModel\n                .getExtensionLoader(AccessKeyStorage.class)\n                .getExtension(url.getParameter(Constants.ACCESS_KEY_STORAGE_KEY, Constants.DEFAULT_ACCESS_KEY_STORAGE));\n\n        AccessKeyPair accessKeyPair;\n        try {\n            accessKeyPair = accessKeyStorage.getAccessKey(url, invocation);\n            if (accessKeyPair == null\n                    || StringUtils.isAnyEmpty(accessKeyPair.getAccessKey(), accessKeyPair.getSecretKey())) {\n                throw new AccessKeyNotFoundException(\"AccessKeyId or secretAccessKey not found\");\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(\"Can't load the AccessKeyPair from accessKeyStorage\");\n        }\n        return accessKeyPair;\n    }\n\n    String getSignature(URL url, Invocation invocation, String secretKey, String time) {\n        String requestString = String.format(\n                Constants.SIGNATURE_STRING_FORMAT,\n                url.getColonSeparatedKey(),\n                RpcUtils.getMethodName(invocation),\n                secretKey,\n                time);\n        return SignatureUtils.sign(requestString, secretKey);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/BasicAuthenticator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth;\n\nimport org.apache.dubbo.auth.exception.RpcAuthenticationException;\nimport org.apache.dubbo.auth.spi.Authenticator;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\nimport java.util.Objects;\n\npublic class BasicAuthenticator implements Authenticator {\n\n    @Override\n    public void sign(Invocation invocation, URL url) {\n        String username = url.getParameter(Constants.USERNAME_KEY);\n        String password = url.getParameter(Constants.PASSWORD_KEY);\n        String auth = username + \":\" + password;\n        String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));\n        String authHeaderValue = \"Basic \" + encodedAuth;\n\n        invocation.setAttachment(Constants.AUTHORIZATION_HEADER_LOWER, authHeaderValue);\n    }\n\n    @Override\n    public void authenticate(Invocation invocation, URL url) throws RpcAuthenticationException {\n        String username = url.getParameter(Constants.USERNAME_KEY);\n        String password = url.getParameter(Constants.PASSWORD_KEY);\n        String auth = username + \":\" + password;\n        String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));\n        String authHeaderValue = \"Basic \" + encodedAuth;\n\n        if (!Objects.equals(authHeaderValue, invocation.getAttachment(Constants.AUTHORIZATION_HEADER))\n                && !Objects.equals(authHeaderValue, invocation.getAttachment(Constants.AUTHORIZATION_HEADER_LOWER))) {\n            throw new RpcAuthenticationException(\"Failed to authenticate, maybe consumer side did not enable the auth\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth;\n\npublic interface Constants {\n\n    String AUTH_KEY = \"auth\";\n\n    String AUTHENTICATOR_KEY = \"authenticator\";\n\n    String USERNAME_KEY = \"username\";\n\n    String PASSWORD_KEY = \"password\";\n\n    String DEFAULT_AUTHENTICATOR = \"basic\";\n\n    String DEFAULT_ACCESS_KEY_STORAGE = \"urlstorage\";\n\n    String ACCESS_KEY_STORAGE_KEY = \"accessKey.storage\";\n    // the key starting  with \".\" shouldn't be output\n    String ACCESS_KEY_ID_KEY = \".accessKeyId\";\n    // the key starting  with \".\" shouldn't be output\n    String SECRET_ACCESS_KEY_KEY = \".secretAccessKey\";\n\n    String REQUEST_TIMESTAMP_KEY = \"timestamp\";\n\n    String REQUEST_SIGNATURE_KEY = \"signature\";\n\n    String AK_KEY = \"ak\";\n\n    String SIGNATURE_STRING_FORMAT = \"%s#%s#%s#%s\";\n\n    String PARAMETER_SIGNATURE_ENABLE_KEY = \"param.sign\";\n\n    String AUTH_SUCCESS = \"auth.success\";\n\n    String AUTHORIZATION_HEADER_LOWER = \"authorization\";\n\n    String AUTHORIZATION_HEADER = \"Authorization\";\n    String REMOTE_ADDRESS_KEY = \"tri.remote.address\";\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/DefaultAccessKeyStorage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth;\n\nimport org.apache.dubbo.auth.model.AccessKeyPair;\nimport org.apache.dubbo.auth.spi.AccessKeyStorage;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\n\n/**\n *  The default implementation of {@link AccessKeyStorage}\n */\npublic class DefaultAccessKeyStorage implements AccessKeyStorage {\n    @Override\n    public AccessKeyPair getAccessKey(URL url, Invocation invocation) {\n        AccessKeyPair accessKeyPair = new AccessKeyPair();\n        String accessKeyId = url.getParameter(Constants.ACCESS_KEY_ID_KEY);\n        String secretAccessKey = url.getParameter(Constants.SECRET_ACCESS_KEY_KEY);\n        accessKeyPair.setAccessKey(accessKeyId);\n        accessKeyPair.setSecretKey(secretAccessKey);\n        return accessKeyPair;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/exception/AccessKeyNotFoundException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.exception;\n\nimport org.apache.dubbo.auth.model.AccessKeyPair;\n\n/**\n * Signals that an attempt to get the {@link AccessKeyPair} has failed.\n */\npublic class AccessKeyNotFoundException extends Exception {\n    private static final long serialVersionUID = 7106108446396804404L;\n\n    public AccessKeyNotFoundException() {}\n\n    public AccessKeyNotFoundException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/exception/RpcAuthenticationException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.exception;\n\npublic class RpcAuthenticationException extends Exception {\n    public RpcAuthenticationException() {}\n\n    public RpcAuthenticationException(String message) {\n        super(message);\n    }\n\n    public RpcAuthenticationException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/filter/ConsumerSignFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.filter;\n\nimport org.apache.dubbo.auth.Constants;\nimport org.apache.dubbo.auth.spi.Authenticator;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\n/**\n * The ConsumerSignFilter\n *\n * @see org.apache.dubbo.rpc.Filter\n */\n@Activate(group = CommonConstants.CONSUMER, value = Constants.AUTH_KEY, order = -10000)\npublic class ConsumerSignFilter implements Filter {\n    private final FrameworkModel frameworkModel;\n\n    public ConsumerSignFilter(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        URL url = invoker.getUrl();\n        boolean shouldAuth = url.getParameter(Constants.AUTH_KEY, false);\n        if (shouldAuth) {\n            Authenticator authenticator = frameworkModel\n                    .getExtensionLoader(Authenticator.class)\n                    .getExtension(url.getParameter(Constants.AUTHENTICATOR_KEY, Constants.DEFAULT_AUTHENTICATOR));\n            authenticator.sign(invocation, url);\n        }\n        return invoker.invoke(invocation);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/filter/ProviderAuthFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.filter;\n\nimport org.apache.dubbo.auth.Constants;\nimport org.apache.dubbo.auth.spi.Authenticator;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\n@Activate(group = CommonConstants.PROVIDER, value = Constants.AUTH_KEY, order = -10000)\npublic class ProviderAuthFilter implements Filter {\n    private final FrameworkModel frameworkModel;\n\n    public ProviderAuthFilter(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        URL url = invoker.getUrl();\n        boolean shouldAuth = url.getParameter(Constants.AUTH_KEY, false);\n        if (shouldAuth) {\n            if (Boolean.TRUE.equals(invocation.getAttributes().get(Constants.AUTH_SUCCESS))) {\n                return invoker.invoke(invocation);\n            }\n            Authenticator authenticator = frameworkModel\n                    .getExtensionLoader(Authenticator.class)\n                    .getExtension(url.getParameter(Constants.AUTHENTICATOR_KEY, Constants.DEFAULT_AUTHENTICATOR));\n            try {\n                authenticator.authenticate(invocation, url);\n            } catch (Exception e) {\n                return AsyncRpcResult.newDefaultAsyncResult(e, invocation);\n            }\n        }\n        return invoker.invoke(invocation);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/filter/ProviderAuthHeaderFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.filter;\n\nimport org.apache.dubbo.auth.Constants;\nimport org.apache.dubbo.auth.spi.Authenticator;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.HeaderFilter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport static org.apache.dubbo.rpc.RpcException.AUTHORIZATION_EXCEPTION;\n\n@Activate(value = Constants.AUTH_KEY, order = -20000)\npublic class ProviderAuthHeaderFilter implements HeaderFilter {\n    private final FrameworkModel frameworkModel;\n\n    public ProviderAuthHeaderFilter(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public RpcInvocation invoke(Invoker<?> invoker, RpcInvocation invocation) throws RpcException {\n        URL url = invoker.getUrl();\n        boolean shouldAuth = url.getParameter(Constants.AUTH_KEY, false);\n        if (shouldAuth) {\n            Authenticator authenticator = frameworkModel\n                    .getExtensionLoader(Authenticator.class)\n                    .getExtension(url.getParameter(Constants.AUTHENTICATOR_KEY, Constants.DEFAULT_AUTHENTICATOR));\n            try {\n                authenticator.authenticate(invocation, url);\n            } catch (Exception e) {\n                throw new RpcException(AUTHORIZATION_EXCEPTION, \"No Auth.\");\n            }\n            invocation.getAttributes().put(Constants.AUTH_SUCCESS, Boolean.TRUE);\n        }\n        return invocation;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/model/AccessKeyPair.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.model;\n\n/**\n * The model of AK/SK pair\n */\npublic class AccessKeyPair {\n    private String accessKey;\n    private String secretKey;\n    private String consumerSide;\n    private String providerSide;\n    private String creator;\n    private String options;\n\n    public String getAccessKey() {\n        return accessKey;\n    }\n\n    public void setAccessKey(String accessKey) {\n        this.accessKey = accessKey;\n    }\n\n    public String getSecretKey() {\n        return secretKey;\n    }\n\n    public void setSecretKey(String secretKey) {\n        this.secretKey = secretKey;\n    }\n\n    public String getConsumerSide() {\n        return consumerSide;\n    }\n\n    public void setConsumerSide(String consumerSide) {\n        this.consumerSide = consumerSide;\n    }\n\n    public String getProviderSide() {\n        return providerSide;\n    }\n\n    public void setProviderSide(String providerSide) {\n        this.providerSide = providerSide;\n    }\n\n    public String getCreator() {\n        return creator;\n    }\n\n    public void setCreator(String creator) {\n        this.creator = creator;\n    }\n\n    public String getOptions() {\n        return options;\n    }\n\n    public void setOptions(String options) {\n        this.options = options;\n    }\n\n    @Override\n    public String toString() {\n        return \"AccessKeyPair{\" + \"accessKey='\"\n                + accessKey + '\\'' + \", secretKey='\"\n                + secretKey + '\\'' + \", consumerSide='\"\n                + consumerSide + '\\'' + \", providerSide='\"\n                + providerSide + '\\'' + \", creator='\"\n                + creator + '\\'' + \", options='\"\n                + options + '\\'' + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/spi/AccessKeyStorage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.spi;\n\nimport org.apache.dubbo.auth.model.AccessKeyPair;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.Invocation;\n\n/**\n * This SPI Extension support us to store our {@link AccessKeyPair} or load {@link AccessKeyPair} from other\n * storage, such as filesystem.\n */\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface AccessKeyStorage {\n\n    /**\n     * get AccessKeyPair of this request\n     *\n     * @param url\n     * @param invocation\n     * @return\n     */\n    AccessKeyPair getAccessKey(URL url, Invocation invocation);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/spi/Authenticator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.spi;\n\nimport org.apache.dubbo.auth.exception.RpcAuthenticationException;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.Invocation;\n\n@SPI(scope = ExtensionScope.FRAMEWORK, value = \"basic\")\npublic interface Authenticator {\n\n    /**\n     * give a sign to request\n     *\n     * @param invocation\n     * @param url\n     */\n    void sign(Invocation invocation, URL url);\n\n    /**\n     * verify the signature of the request is valid or not\n     * @param invocation\n     * @param url\n     * @throws RpcAuthenticationException when failed to authenticate current invocation\n     */\n    void authenticate(Invocation invocation, URL url) throws RpcAuthenticationException;\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/utils/SignatureUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.utils;\n\nimport javax.crypto.Mac;\nimport javax.crypto.spec.SecretKeySpec;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectOutput;\nimport java.io.ObjectOutputStream;\nimport java.io.Serializable;\nimport java.nio.charset.StandardCharsets;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Base64;\n\npublic class SignatureUtils {\n    private static final String HMAC_SHA256_ALGORITHM = \"HmacSHA256\";\n\n    public static String sign(String metadata, String key) throws RuntimeException {\n        return sign(metadata.getBytes(StandardCharsets.UTF_8), key);\n    }\n\n    public static String sign(Object[] parameters, String metadata, String key) throws RuntimeException {\n        if (parameters == null) {\n            return sign(metadata, key);\n        }\n        for (int i = 0; i < parameters.length; i++) {\n            if (!(parameters[i] instanceof Serializable)) {\n                throw new IllegalArgumentException(\"The parameter [\" + i + \"] to be signed was not serializable.\");\n            }\n        }\n        Object[] includeMetadata = new Object[parameters.length + 1];\n        System.arraycopy(parameters, 0, includeMetadata, 0, parameters.length);\n        includeMetadata[parameters.length] = metadata;\n        byte[] includeMetadataBytes;\n        try {\n            includeMetadataBytes = toByteArray(includeMetadata);\n        } catch (IOException e) {\n            throw new RuntimeException(\"Failed to generate HMAC: \" + e.getMessage());\n        }\n        return sign(includeMetadataBytes, key);\n    }\n\n    private static String sign(byte[] data, String key) throws RuntimeException {\n        Mac mac;\n        try {\n            mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);\n        } catch (NoSuchAlgorithmException e) {\n            throw new RuntimeException(\"Failed to generate HMAC: no such algorithm exception \" + HMAC_SHA256_ALGORITHM);\n        }\n        SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), HMAC_SHA256_ALGORITHM);\n        try {\n            mac.init(signingKey);\n        } catch (InvalidKeyException e) {\n            throw new RuntimeException(\"Failed to generate HMAC: invalid key exception\");\n        }\n        byte[] rawHmac;\n        try {\n            // compute the hmac on input data bytes\n            rawHmac = mac.doFinal(data);\n        } catch (IllegalStateException e) {\n            throw new RuntimeException(\"Failed to generate HMAC: \" + e.getMessage());\n        }\n        // base64-encode the hmac\n        return Base64.getEncoder().encodeToString(rawHmac);\n    }\n\n    private static byte[] toByteArray(Object[] parameters) throws IOException {\n        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();\n                ObjectOutput out = new ObjectOutputStream(bos)) {\n            out.writeObject(parameters);\n            out.flush();\n            return bos.toByteArray();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.auth.spi.AccessKeyStorage",
    "content": "urlstorage=org.apache.dubbo.auth.DefaultAccessKeyStorage"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.auth.spi.Authenticator",
    "content": "accesskey=org.apache.dubbo.auth.AccessKeyAuthenticator\nbasic=org.apache.dubbo.auth.BasicAuthenticator\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter",
    "content": "consumersign=org.apache.dubbo.auth.filter.ConsumerSignFilter\nproviderauth=org.apache.dubbo.auth.filter.ProviderAuthFilter"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.HeaderFilter",
    "content": "auth=org.apache.dubbo.auth.filter.ProviderAuthHeaderFilter\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/test/java/org/apache/dubbo/auth/AccessKeyAuthenticatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth;\n\nimport org.apache.dubbo.auth.exception.RpcAuthenticationException;\nimport org.apache.dubbo.auth.model.AccessKeyPair;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertDoesNotThrow;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doCallRealMethod;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass AccessKeyAuthenticatorTest {\n\n    @Test\n    void testSignForRequest() {\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\")\n                .addParameter(CommonConstants.APPLICATION_KEY, \"test\")\n                .addParameter(Constants.SECRET_ACCESS_KEY_KEY, \"sk\");\n        Invocation invocation = new RpcInvocation();\n\n        AccessKeyAuthenticator helper = mock(AccessKeyAuthenticator.class);\n        doCallRealMethod().when(helper).sign(invocation, url);\n        when(helper.getSignature(eq(url), eq(invocation), eq(\"sk\"), anyString()))\n                .thenReturn(\"dubbo\");\n\n        AccessKeyPair accessKeyPair = mock(AccessKeyPair.class);\n        when(accessKeyPair.getSecretKey()).thenReturn(\"sk\");\n        when(helper.getAccessKeyPair(invocation, url)).thenReturn(accessKeyPair);\n\n        helper.sign(invocation, url);\n        assertEquals(String.valueOf(invocation.getAttachment(CommonConstants.CONSUMER)), url.getApplication());\n        assertNotNull(invocation.getAttachments().get(Constants.REQUEST_SIGNATURE_KEY));\n        assertEquals(invocation.getAttachments().get(Constants.REQUEST_SIGNATURE_KEY), \"dubbo\");\n    }\n\n    @Test\n    void testAuthenticateRequest() throws RpcAuthenticationException {\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\")\n                .addParameter(CommonConstants.APPLICATION_KEY, \"test\")\n                .addParameter(Constants.SECRET_ACCESS_KEY_KEY, \"sk\");\n        Invocation invocation = new RpcInvocation();\n        invocation.setAttachment(Constants.ACCESS_KEY_ID_KEY, \"ak\");\n        invocation.setAttachment(Constants.REQUEST_SIGNATURE_KEY, \"dubbo\");\n        invocation.setAttachment(Constants.REQUEST_TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));\n        invocation.setAttachment(CommonConstants.CONSUMER, \"test\");\n\n        AccessKeyAuthenticator helper = mock(AccessKeyAuthenticator.class);\n        doCallRealMethod().when(helper).authenticate(invocation, url);\n        when(helper.getSignature(eq(url), eq(invocation), eq(\"sk\"), anyString()))\n                .thenReturn(\"dubbo\");\n\n        AccessKeyPair accessKeyPair = mock(AccessKeyPair.class);\n        when(accessKeyPair.getSecretKey()).thenReturn(\"sk\");\n        when(helper.getAccessKeyPair(invocation, url)).thenReturn(accessKeyPair);\n\n        assertDoesNotThrow(() -> helper.authenticate(invocation, url));\n    }\n\n    @Test\n    void testAuthenticateRequestNoSignature() {\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\")\n                .addParameter(CommonConstants.APPLICATION_KEY, \"test\")\n                .addParameter(Constants.SECRET_ACCESS_KEY_KEY, \"sk\");\n        Invocation invocation = new RpcInvocation();\n        AccessKeyAuthenticator helper = new AccessKeyAuthenticator(FrameworkModel.defaultModel());\n        assertThrows(RpcAuthenticationException.class, () -> helper.authenticate(invocation, url));\n    }\n\n    @Test\n    void testGetAccessKeyPairFailed() {\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\").addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\");\n        AccessKeyAuthenticator helper = new AccessKeyAuthenticator(FrameworkModel.defaultModel());\n        Invocation invocation = mock(Invocation.class);\n        assertThrows(RuntimeException.class, () -> helper.getAccessKeyPair(invocation, url));\n    }\n\n    @Test\n    void testGetSignatureNoParameter() {\n        URL url = mock(URL.class);\n        Invocation invocation = mock(Invocation.class);\n        String secretKey = \"123456\";\n        AccessKeyAuthenticator helper = new AccessKeyAuthenticator(FrameworkModel.defaultModel());\n        String signature = helper.getSignature(url, invocation, secretKey, String.valueOf(System.currentTimeMillis()));\n        assertNotNull(signature);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/test/java/org/apache/dubbo/auth/DefaultAccessKeyStorageTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth;\n\nimport org.apache.dubbo.auth.model.AccessKeyPair;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.mockito.Mockito.mock;\n\nclass DefaultAccessKeyStorageTest {\n\n    @Test\n    void testGetAccessKey() {\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\")\n                .addParameter(Constants.SECRET_ACCESS_KEY_KEY, \"sk\");\n        DefaultAccessKeyStorage defaultAccessKeyStorage = new DefaultAccessKeyStorage();\n        AccessKeyPair accessKey = defaultAccessKeyStorage.getAccessKey(url, mock(Invocation.class));\n        assertNotNull(accessKey);\n        assertEquals(accessKey.getAccessKey(), \"ak\");\n        assertEquals(accessKey.getSecretKey(), \"sk\");\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/test/java/org/apache/dubbo/auth/filter/ConsumerSignFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.filter;\n\nimport org.apache.dubbo.auth.Constants;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass ConsumerSignFilterTest {\n\n    @Test\n    void testAuthDisabled() {\n        URL url = mock(URL.class);\n        Invoker invoker = mock(Invoker.class);\n        Invocation invocation = mock(Invocation.class);\n        when(invoker.getUrl()).thenReturn(url);\n        ConsumerSignFilter consumerSignFilter = new ConsumerSignFilter(FrameworkModel.defaultModel());\n        consumerSignFilter.invoke(invoker, invocation);\n        verify(invocation, never()).setAttachment(eq(Constants.REQUEST_SIGNATURE_KEY), anyString());\n    }\n\n    @Test\n    void testAuthEnabled() {\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\")\n                .addParameter(Constants.SECRET_ACCESS_KEY_KEY, \"sk\")\n                .addParameter(CommonConstants.APPLICATION_KEY, \"test\")\n                .addParameter(Constants.AUTHENTICATOR_KEY, \"accesskey\")\n                .addParameter(Constants.AUTH_KEY, true);\n        Invoker invoker = mock(Invoker.class);\n        Invocation invocation = mock(Invocation.class);\n        when(invoker.getUrl()).thenReturn(url);\n        ConsumerSignFilter consumerSignFilter = new ConsumerSignFilter(FrameworkModel.defaultModel());\n        consumerSignFilter.invoke(invoker, invocation);\n        verify(invocation, times(1)).setAttachment(eq(Constants.REQUEST_SIGNATURE_KEY), anyString());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/test/java/org/apache/dubbo/auth/filter/ProviderAuthFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.filter;\n\nimport org.apache.dubbo.auth.Constants;\nimport org.apache.dubbo.auth.exception.RpcAuthenticationException;\nimport org.apache.dubbo.auth.utils.SignatureUtils;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass ProviderAuthFilterTest {\n    @Test\n    void testAuthDisabled() {\n        URL url = mock(URL.class);\n        Invoker invoker = mock(Invoker.class);\n        Invocation invocation = mock(RpcInvocation.class);\n        when(invoker.getUrl()).thenReturn(url);\n        ProviderAuthFilter providerAuthFilter = new ProviderAuthFilter(FrameworkModel.defaultModel());\n        providerAuthFilter.invoke(invoker, invocation);\n        verify(url, never()).getParameter(eq(Constants.AUTHENTICATOR_KEY), eq(Constants.DEFAULT_AUTHENTICATOR));\n    }\n\n    @Test\n    void testAuthEnabled() {\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\")\n                .addParameter(Constants.SECRET_ACCESS_KEY_KEY, \"sk\")\n                .addParameter(CommonConstants.APPLICATION_KEY, \"test\")\n                .addParameter(Constants.AUTHENTICATOR_KEY, \"accesskey\")\n                .addParameter(Constants.AUTH_KEY, true);\n        Invoker invoker = mock(Invoker.class);\n        Invocation invocation = mock(RpcInvocation.class);\n        when(invoker.getUrl()).thenReturn(url);\n        ProviderAuthFilter providerAuthFilter = new ProviderAuthFilter(FrameworkModel.defaultModel());\n        providerAuthFilter.invoke(invoker, invocation);\n        verify(invocation, atLeastOnce()).getAttachment(anyString());\n    }\n\n    @Test\n    void testAuthFailed() {\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\")\n                .addParameter(Constants.SECRET_ACCESS_KEY_KEY, \"sk\")\n                .addParameter(CommonConstants.APPLICATION_KEY, \"test\")\n                .addParameter(Constants.AUTHENTICATOR_KEY, \"accesskey\")\n                .addParameter(Constants.AUTH_KEY, true);\n        Invoker invoker = mock(Invoker.class);\n        Invocation invocation = mock(RpcInvocation.class);\n        when(invocation.getAttachment(Constants.REQUEST_SIGNATURE_KEY)).thenReturn(null);\n        when(invoker.getUrl()).thenReturn(url);\n\n        ProviderAuthFilter providerAuthFilter = new ProviderAuthFilter(FrameworkModel.defaultModel());\n        Result result = providerAuthFilter.invoke(invoker, invocation);\n        assertTrue(result.hasException());\n    }\n\n    @Test\n    void testAuthFailedWhenNoSignature() {\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\")\n                .addParameter(Constants.SECRET_ACCESS_KEY_KEY, \"sk\")\n                .addParameter(CommonConstants.APPLICATION_KEY, \"test\")\n                .addParameter(Constants.AUTHENTICATOR_KEY, \"accesskey\")\n                .addParameter(Constants.AUTH_KEY, true);\n        Invoker invoker = mock(Invoker.class);\n        Invocation invocation = mock(RpcInvocation.class);\n        when(invocation.getAttachment(Constants.REQUEST_SIGNATURE_KEY)).thenReturn(null);\n        when(invoker.getUrl()).thenReturn(url);\n\n        ProviderAuthFilter providerAuthFilter = new ProviderAuthFilter(FrameworkModel.defaultModel());\n        Result result = providerAuthFilter.invoke(invoker, invocation);\n        assertTrue(result.hasException());\n    }\n\n    @Test\n    void testAuthFailedWhenNoAccessKeyPair() {\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .addParameter(CommonConstants.APPLICATION_KEY, \"test-provider\")\n                .addParameter(Constants.AUTHENTICATOR_KEY, \"accesskey\")\n                .addParameter(Constants.AUTH_KEY, true);\n        Invoker invoker = mock(Invoker.class);\n        Invocation invocation = mock(RpcInvocation.class);\n        when(invocation.getObjectAttachment(Constants.REQUEST_SIGNATURE_KEY)).thenReturn(\"dubbo\");\n        when(invocation.getObjectAttachment(Constants.AK_KEY)).thenReturn(\"ak\");\n        when(invocation.getObjectAttachment(CommonConstants.CONSUMER)).thenReturn(\"test-consumer\");\n        when(invocation.getObjectAttachment(Constants.REQUEST_TIMESTAMP_KEY)).thenReturn(System.currentTimeMillis());\n        when(invoker.getUrl()).thenReturn(url);\n\n        ProviderAuthFilter providerAuthFilter = new ProviderAuthFilter(FrameworkModel.defaultModel());\n        Result result = providerAuthFilter.invoke(invoker, invocation);\n        assertTrue(result.hasException());\n        assertTrue(result.getException() instanceof RpcAuthenticationException);\n    }\n\n    @Test\n    void testAuthFailedWhenParameterError() {\n        String service = \"org.apache.dubbo.DemoService\";\n        String method = \"test\";\n        Object[] originalParams = new Object[] {\"dubbo1\", \"dubbo2\"};\n        long currentTimeMillis = System.currentTimeMillis();\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .setServiceInterface(service)\n                .addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\")\n                .addParameter(Constants.SECRET_ACCESS_KEY_KEY, \"sk\")\n                .addParameter(CommonConstants.APPLICATION_KEY, \"test-provider\")\n                .addParameter(Constants.PARAMETER_SIGNATURE_ENABLE_KEY, true)\n                .addParameter(Constants.AUTHENTICATOR_KEY, \"accesskey\")\n                .addParameter(Constants.AUTH_KEY, true);\n\n        Invoker invoker = mock(Invoker.class);\n        Invocation invocation = mock(RpcInvocation.class);\n        when(invocation.getObjectAttachment(Constants.AK_KEY)).thenReturn(\"ak\");\n        when(invocation.getObjectAttachment(CommonConstants.CONSUMER)).thenReturn(\"test-consumer\");\n        when(invocation.getObjectAttachment(Constants.REQUEST_TIMESTAMP_KEY)).thenReturn(currentTimeMillis);\n        when(invocation.getMethodName()).thenReturn(method);\n        Object[] fakeParams = new Object[] {\"dubbo1\", \"dubbo3\"};\n        when(invocation.getArguments()).thenReturn(fakeParams);\n        when(invoker.getUrl()).thenReturn(url);\n\n        String requestString = String.format(\n                Constants.SIGNATURE_STRING_FORMAT,\n                url.getColonSeparatedKey(),\n                invocation.getMethodName(),\n                \"sk\",\n                currentTimeMillis);\n        String sign = SignatureUtils.sign(originalParams, requestString, \"sk\");\n        when(invocation.getObjectAttachment(Constants.REQUEST_SIGNATURE_KEY)).thenReturn(sign);\n\n        ProviderAuthFilter providerAuthFilter = new ProviderAuthFilter(FrameworkModel.defaultModel());\n        Result result = providerAuthFilter.invoke(invoker, invocation);\n        assertTrue(result.hasException());\n        assertTrue(result.getException() instanceof RpcAuthenticationException);\n    }\n\n    @Test\n    void testAuthSuccessfully() {\n        String service = \"org.apache.dubbo.DemoService\";\n        String method = \"test\";\n        long currentTimeMillis = System.currentTimeMillis();\n        URL url = URL.valueOf(\"dubbo://10.10.10.10:2181\")\n                .setServiceInterface(service)\n                .addParameter(Constants.ACCESS_KEY_ID_KEY, \"ak\")\n                .addParameter(Constants.SECRET_ACCESS_KEY_KEY, \"sk\")\n                .addParameter(CommonConstants.APPLICATION_KEY, \"test-provider\")\n                .addParameter(Constants.AUTHENTICATOR_KEY, \"accesskey\")\n                .addParameter(Constants.AUTH_KEY, true);\n        Invoker invoker = mock(Invoker.class);\n        Invocation invocation = mock(RpcInvocation.class);\n        when(invocation.getAttachment(Constants.AK_KEY)).thenReturn(\"ak\");\n        when(invocation.getAttachment(CommonConstants.CONSUMER)).thenReturn(\"test-consumer\");\n        when(invocation.getAttachment(Constants.REQUEST_TIMESTAMP_KEY)).thenReturn(String.valueOf(currentTimeMillis));\n        when(invocation.getMethodName()).thenReturn(method);\n        when(invoker.getUrl()).thenReturn(url);\n\n        String requestString = String.format(\n                Constants.SIGNATURE_STRING_FORMAT,\n                url.getColonSeparatedKey(),\n                invocation.getMethodName(),\n                \"sk\",\n                currentTimeMillis);\n        String sign = SignatureUtils.sign(requestString, \"sk\");\n        when(invocation.getAttachment(Constants.REQUEST_SIGNATURE_KEY)).thenReturn(sign);\n\n        ProviderAuthFilter providerAuthFilter = new ProviderAuthFilter(FrameworkModel.defaultModel());\n        Result result = providerAuthFilter.invoke(invoker, invocation);\n        assertNull(result);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/test/java/org/apache/dubbo/auth/utils/SignatureUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.auth.utils;\n\nimport java.util.ArrayList;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass SignatureUtilsTest {\n\n    @Test\n    void testEncryptWithObject() {\n        Object[] objects = new Object[] {new ArrayList<>(), \"temp\"};\n        String encryptWithObject = SignatureUtils.sign(objects, \"TestMethod#hello\", \"TOKEN\");\n        Assertions.assertEquals(encryptWithObject, \"t6c7PasKguovqSrVRcTQU4wTZt/ybl0jBCUMgAt/zQw=\");\n    }\n\n    @Test\n    void testEncryptWithNoParameters() {\n        String encryptWithNoParams = SignatureUtils.sign(null, \"TestMethod#hello\", \"TOKEN\");\n        Assertions.assertEquals(encryptWithNoParams, \"2DGkTcyXg4plU24rY8MZkEJwOMRW3o+wUP3HssRc3EE=\");\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-auth/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/README.md",
    "content": "## dubbo-complier\n\n> dubbo-complier supports generating code based on .proto files\n\n### How to use \n\n#### 1.Define Proto file\n\ngreeter.proto\n```protobuf\nsyntax = \"proto3\";\n\noption java_multiple_files = true;\noption java_package = \"org.apache.dubbo.demo\";\noption java_outer_classname = \"DemoServiceProto\";\noption objc_class_prefix = \"DEMOSRV\";\n\npackage demoservice;\n\n// The demo service definition.\nservice DemoService {\n  rpc SayHello (HelloRequest) returns (HelloReply) {}\n}\n\n// The request message containing the user's name.\nmessage HelloRequest {\n  string name = 1;\n}\n\n// The response message containing the greetings\nmessage HelloReply {\n  string message = 1;\n}\n\n```\n\n#### 2.Use dubbo-maven-plugin,rather than ```protobuf-maven-plugin```\n\n    now dubbo support his own protoc plugin base on dubbo-maven-plugin\n\n```xml\n<plugin>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-maven-plugin</artifactId>\n    <version>${dubbo.version}</version>\n    <executions>\n        <execution>\n            <goals>\n                <goal>compile</goal>\n            </goals>\n        </execution>\n    </executions>\n</plugin>\n```\n\n#### 3.generate file\n\n```java\n/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n\n    package org.apache.dubbo.demo;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic final class DemoServiceDubbo {\nprivate static final AtomicBoolean registered = new AtomicBoolean();\n\nprivate static Class<?> init() {\nClass<?> clazz = null;\ntry {\nclazz = Class.forName(DemoServiceDubbo.class.getName());\nif (registered.compareAndSet(false, true)) {\n    org.apache.dubbo.common.serialize.protobuf.support.ProtobufUtils.marshaller(\n    org.apache.dubbo.demo.HelloReply.getDefaultInstance());\n    org.apache.dubbo.common.serialize.protobuf.support.ProtobufUtils.marshaller(\n    org.apache.dubbo.demo.HelloRequest.getDefaultInstance());\n}\n} catch (ClassNotFoundException e) {\n// ignore\n}\nreturn clazz;\n}\n\nprivate DemoServiceDubbo() {}\n\npublic static final String SERVICE_NAME = \"org.apache.dubbo.demo.DemoService\";\n\n/**\n* Code generated for Dubbo\n*/\npublic interface IDemoService extends org.apache.dubbo.rpc.model.DubboStub {\n\nstatic Class<?> clazz = init();\n\n    org.apache.dubbo.demo.HelloReply sayHello(org.apache.dubbo.demo.HelloRequest request);\n\n    CompletableFuture<org.apache.dubbo.demo.HelloReply> sayHelloAsync(org.apache.dubbo.demo.HelloRequest request);\n\n\n}\n\n}\n\n```\n\n#### 4.others\n\ndubbo-maven-plugin protoc mojo supported configurations\n\n| configuration params  | isRequired | explain                                        | default                                                    | eg                                                                         |\n|:----------------------|------------|------------------------------------------------|------------------------------------------------------------|----------------------------------------------------------------------------|\n| dubboVersion          | true       | dubbo version ,use for find Generator          | ${dubbo.version}                                           | 3.3.0                                                                      |\n| dubboGenerateType     | true       | dubbo generator type                           | dubbo3                                                     | grpc                                                                       |\n| protocExecutable      | false      | protoc executable,you can use local protoc.exe |                                                            | protoc                                                                     |\n| protocArtifact        | false      | download protoc from maven artifact            |                                                            | com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} |\n| protoSourceDir        | true       | .proto files dir                               | ${basedir}/src/main/proto                                  | ./proto                                                                    |\n| outputDir             | true       | generated file output dir                      | ${project.build.directory}/generated-sources/protobuf/java | ${basedir}/src/main/java                                                   |\n| protocPluginDirectory | false      | protoc plugin dir                              | ${project.build.directory}/protoc-plugins                  | ./target/protoc-plugins                                                    |\n\n\n​    \n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-compiler</artifactId>\n  <packaging>jar</packaging>\n\n  <name>${project.artifactId}</name>\n  <description>Dubbo customized RPC stub compiler.</description>\n\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>com.github.spullara.mustache.java</groupId>\n      <artifactId>compiler</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.grpc</groupId>\n      <artifactId>grpc-core</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.grpc</groupId>\n      <artifactId>grpc-stub</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.grpc</groupId>\n      <artifactId>grpc-protobuf</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.grpc</groupId>\n      <artifactId>grpc-context</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.salesforce.servicelibs</groupId>\n      <artifactId>grpc-contrib</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <configuration>\n          <compilerArgument>-proc:none</compilerArgument>\n        </configuration>\n      </plugin>\n\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-jar-plugin</artifactId>\n        <configuration>\n          <archive>\n            <manifest>\n              <addClasspath>true</addClasspath>\n              <mainClass>org.apache.dubbo.gen.tri.Dubbo3TripleGenerator</mainClass>\n            </manifest>\n          </archive>\n        </configuration>\n      </plugin>\n\n      <!-- Optional, used to build directly executable packages (without using 'java -jar'),\n            for example 'artifactId-1.0.0-osx-x86_64.exe', 'artifactId-1.0.0-osx-x86_64.exe' -->\n      <plugin>\n        <groupId>com.salesforce.servicelibs</groupId>\n        <artifactId>canteen-maven-plugin</artifactId>\n        <version>1.1.0</version>\n        <executions>\n          <execution>\n            <goals>\n              <goal>bootstrap</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/AbstractGenerator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.gen;\n\nimport org.apache.dubbo.gen.utils.ProtoTypeMap;\n\nimport javax.annotation.Nonnull;\n\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport com.github.mustachejava.DefaultMustacheFactory;\nimport com.github.mustachejava.Mustache;\nimport com.github.mustachejava.MustacheFactory;\nimport com.google.api.AnnotationsProto;\nimport com.google.api.HttpRule;\nimport com.google.api.HttpRule.PatternCase;\nimport com.google.common.base.Charsets;\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport com.google.common.html.HtmlEscapers;\nimport com.google.protobuf.DescriptorProtos.FileDescriptorProto;\nimport com.google.protobuf.DescriptorProtos.FileOptions;\nimport com.google.protobuf.DescriptorProtos.MethodDescriptorProto;\nimport com.google.protobuf.DescriptorProtos.ServiceDescriptorProto;\nimport com.google.protobuf.DescriptorProtos.SourceCodeInfo.Location;\nimport com.google.protobuf.ExtensionRegistry;\nimport com.google.protobuf.compiler.PluginProtos;\n\npublic abstract class AbstractGenerator {\n\n    private static final MustacheFactory MUSTACHE_FACTORY = new DefaultMustacheFactory();\n    private static final int SERVICE_NUMBER_OF_PATHS = 2;\n    private static final int METHOD_NUMBER_OF_PATHS = 4;\n\n    protected abstract String getClassPrefix();\n\n    protected abstract String getClassSuffix();\n\n    protected String getSingleTemplateFileName() {\n        return getTemplateFileName();\n    }\n\n    protected String getTemplateFileName() {\n        return getClassPrefix() + getClassSuffix() + \"Stub.mustache\";\n    }\n\n    protected String getInterfaceTemplateFileName() {\n        return getClassPrefix() + getClassSuffix() + \"InterfaceStub.mustache\";\n    }\n\n    private String getServiceJavaDocPrefix() {\n        return \"\";\n    }\n\n    private String getMethodJavaDocPrefix() {\n        return \"    \";\n    }\n\n    public List<PluginProtos.CodeGeneratorResponse.File> generateFiles(PluginProtos.CodeGeneratorRequest request) {\n        // 1. build ExtensionRegistry and registry\n        ExtensionRegistry registry = ExtensionRegistry.newInstance();\n        AnnotationsProto.registerAllExtensions(registry);\n\n        // 2. compile proto file\n        List<FileDescriptorProto> protosToGenerate = request.getProtoFileList().stream()\n                .filter(protoFile -> request.getFileToGenerateList().contains(protoFile.getName()))\n                .map(protoFile -> parseWithExtensions(protoFile, registry))\n                .collect(Collectors.toList());\n\n        // 3. use compiled proto file build ProtoTypeMap\n        final ProtoTypeMap typeMap = ProtoTypeMap.of(protosToGenerate);\n\n        // 4. find and generate serviceContext\n        List<ServiceContext> services = findServices(protosToGenerate, typeMap);\n        return generateFiles(services);\n    }\n\n    private FileDescriptorProto parseWithExtensions(FileDescriptorProto protoFile, ExtensionRegistry registry) {\n        try {\n            return FileDescriptorProto.parseFrom(protoFile.toByteString(), registry);\n        } catch (Exception e) {\n            return protoFile;\n        }\n    }\n\n    private List<ServiceContext> findServices(List<FileDescriptorProto> protos, ProtoTypeMap typeMap) {\n        List<ServiceContext> contexts = new ArrayList<>();\n\n        protos.forEach(fileProto -> {\n            for (int serviceNumber = 0; serviceNumber < fileProto.getServiceCount(); serviceNumber++) {\n                ServiceContext serviceContext = buildServiceContext(\n                        fileProto.getService(serviceNumber),\n                        typeMap,\n                        fileProto.getSourceCodeInfo().getLocationList(),\n                        serviceNumber);\n                serviceContext.protoName = fileProto.getName();\n                serviceContext.packageName = extractPackageName(fileProto);\n                if (!Strings.isNullOrEmpty(fileProto.getOptions().getJavaOuterClassname())) {\n                    serviceContext.outerClassName = fileProto.getOptions().getJavaOuterClassname();\n                } else {\n                    serviceContext.outerClassName =\n                            ProtoTypeMap.getJavaOuterClassname(fileProto, fileProto.getOptions());\n                }\n                serviceContext.commonPackageName = extractCommonPackageName(fileProto);\n                serviceContext.multipleFiles = fileProto.getOptions().getJavaMultipleFiles();\n                contexts.add(serviceContext);\n            }\n        });\n\n        return contexts;\n    }\n\n    private String extractPackageName(FileDescriptorProto proto) {\n        FileOptions options = proto.getOptions();\n        String javaPackage = options.getJavaPackage();\n        if (!Strings.isNullOrEmpty(javaPackage)) {\n            return javaPackage;\n        }\n\n        return Strings.nullToEmpty(proto.getPackage());\n    }\n\n    private String extractCommonPackageName(FileDescriptorProto proto) {\n        return Strings.nullToEmpty(proto.getPackage());\n    }\n\n    private ServiceContext buildServiceContext(\n            ServiceDescriptorProto serviceProto, ProtoTypeMap typeMap, List<Location> locations, int serviceNumber) {\n        ServiceContext serviceContext = new ServiceContext();\n        serviceContext.fileName = getClassPrefix() + serviceProto.getName() + getClassSuffix() + \".java\";\n        serviceContext.className = getClassPrefix() + serviceProto.getName() + getClassSuffix();\n        serviceContext.interfaceFileName = serviceProto.getName() + \".java\";\n        serviceContext.interfaceClassName = serviceProto.getName();\n        serviceContext.serviceName = serviceProto.getName();\n        serviceContext.deprecated = serviceProto.getOptions().getDeprecated();\n\n        List<Location> allLocationsForService = locations.stream()\n                .filter(location -> location.getPathCount() >= 2\n                        && location.getPath(0) == FileDescriptorProto.SERVICE_FIELD_NUMBER\n                        && location.getPath(1) == serviceNumber)\n                .collect(Collectors.toList());\n\n        Location serviceLocation = allLocationsForService.stream()\n                .filter(location -> location.getPathCount() == SERVICE_NUMBER_OF_PATHS)\n                .findFirst()\n                .orElseGet(Location::getDefaultInstance);\n        serviceContext.javaDoc = getJavaDoc(getComments(serviceLocation), getServiceJavaDocPrefix());\n\n        for (int methodNumber = 0; methodNumber < serviceProto.getMethodCount(); methodNumber++) {\n            MethodContext methodContext =\n                    buildMethodContext(serviceProto.getMethod(methodNumber), typeMap, locations, methodNumber);\n\n            serviceContext.methods.add(methodContext);\n            serviceContext.methodTypes.add(methodContext.inputType);\n            serviceContext.methodTypes.add(methodContext.outputType);\n        }\n        return serviceContext;\n    }\n\n    private MethodContext buildMethodContext(\n            MethodDescriptorProto methodProto, ProtoTypeMap typeMap, List<Location> locations, int methodNumber) {\n        MethodContext methodContext = new MethodContext();\n        methodContext.originMethodName = methodProto.getName();\n        methodContext.methodName = lowerCaseFirst(methodProto.getName());\n        methodContext.inputType = typeMap.toJavaTypeName(methodProto.getInputType());\n        methodContext.outputType = typeMap.toJavaTypeName(methodProto.getOutputType());\n        methodContext.deprecated = methodProto.getOptions().getDeprecated();\n        methodContext.isManyInput = methodProto.getClientStreaming();\n        methodContext.isManyOutput = methodProto.getServerStreaming();\n        methodContext.methodNumber = methodNumber;\n\n        // compile google.api.http option\n        HttpRule httpRule = parseHttpRule(methodProto);\n        if (httpRule != null) {\n            PatternCase patternCase = httpRule.getPatternCase();\n            String path;\n            switch (patternCase) {\n                case GET:\n                    path = httpRule.getGet();\n                    break;\n                case PUT:\n                    path = httpRule.getPut();\n                    break;\n                case POST:\n                    path = httpRule.getPost();\n                    break;\n                case DELETE:\n                    path = httpRule.getDelete();\n                    break;\n                case PATCH:\n                    path = httpRule.getPatch();\n                    break;\n                default:\n                    path = \"\";\n                    break;\n            }\n            if (!path.isEmpty()) {\n                methodContext.httpMethod = patternCase.name();\n                methodContext.path = path;\n                methodContext.body = httpRule.getBody();\n                methodContext.hasMapping = true;\n                methodContext.needRequestAnnotation = !methodContext.body.isEmpty() || path.contains(\"{\");\n            }\n        }\n\n        Location methodLocation = locations.stream()\n                .filter(location -> location.getPathCount() == METHOD_NUMBER_OF_PATHS\n                        && location.getPath(METHOD_NUMBER_OF_PATHS - 1) == methodNumber)\n                .findFirst()\n                .orElseGet(Location::getDefaultInstance);\n        methodContext.javaDoc = getJavaDoc(getComments(methodLocation), getMethodJavaDocPrefix());\n\n        if (!methodProto.getClientStreaming() && !methodProto.getServerStreaming()) {\n            methodContext.reactiveCallsMethodName = \"oneToOne\";\n            methodContext.grpcCallsMethodName = \"asyncUnaryCall\";\n        }\n        if (!methodProto.getClientStreaming() && methodProto.getServerStreaming()) {\n            methodContext.reactiveCallsMethodName = \"oneToMany\";\n            methodContext.grpcCallsMethodName = \"asyncServerStreamingCall\";\n        }\n        if (methodProto.getClientStreaming() && !methodProto.getServerStreaming()) {\n            methodContext.reactiveCallsMethodName = \"manyToOne\";\n            methodContext.grpcCallsMethodName = \"asyncClientStreamingCall\";\n        }\n        if (methodProto.getClientStreaming() && methodProto.getServerStreaming()) {\n            methodContext.reactiveCallsMethodName = \"manyToMany\";\n            methodContext.grpcCallsMethodName = \"asyncBidiStreamingCall\";\n        }\n        return methodContext;\n    }\n\n    private HttpRule parseHttpRule(MethodDescriptorProto methodProto) {\n        HttpRule rule = null;\n        // check methodProto have options\n        if (methodProto.hasOptions()) {\n            if (methodProto.getOptions().hasExtension(AnnotationsProto.http)) {\n                rule = methodProto.getOptions().getExtension(AnnotationsProto.http);\n            }\n        }\n        return rule;\n    }\n\n    private String lowerCaseFirst(String s) {\n        return Character.toLowerCase(s.charAt(0)) + s.substring(1);\n    }\n\n    private List<PluginProtos.CodeGeneratorResponse.File> generateFiles(List<ServiceContext> services) {\n        List<PluginProtos.CodeGeneratorResponse.File> allServiceFiles = new ArrayList<>();\n        for (ServiceContext context : services) {\n            List<PluginProtos.CodeGeneratorResponse.File> files = buildFile(context);\n            allServiceFiles.addAll(files);\n        }\n        return allServiceFiles;\n    }\n\n    protected boolean useMultipleTemplate(boolean multipleFiles) {\n        return false;\n    }\n\n    private List<PluginProtos.CodeGeneratorResponse.File> buildFile(ServiceContext context) {\n        List<PluginProtos.CodeGeneratorResponse.File> files = new ArrayList<>();\n\n        if (useMultipleTemplate(context.multipleFiles)) {\n            String content = applyTemplate(getTemplateFileName(), context);\n            String dir = absoluteDir(context);\n\n            files.add(PluginProtos.CodeGeneratorResponse.File.newBuilder()\n                    .setName(getFileName(dir, context.fileName))\n                    .setContent(content)\n                    .build());\n\n            content = applyTemplate(getInterfaceTemplateFileName(), context);\n            files.add(PluginProtos.CodeGeneratorResponse.File.newBuilder()\n                    .setName(getFileName(dir, context.interfaceFileName))\n                    .setContent(content)\n                    .build());\n        } else {\n            String content = applyTemplate(getSingleTemplateFileName(), context);\n            String dir = absoluteDir(context);\n\n            files.add(PluginProtos.CodeGeneratorResponse.File.newBuilder()\n                    .setName(getFileName(dir, context.fileName))\n                    .setContent(content)\n                    .build());\n        }\n\n        return files;\n    }\n\n    protected String applyTemplate(@Nonnull String resourcePath, @Nonnull Object generatorContext) {\n        Preconditions.checkNotNull(resourcePath, \"resourcePath\");\n        Preconditions.checkNotNull(generatorContext, \"generatorContext\");\n        InputStream resource = MustacheFactory.class.getClassLoader().getResourceAsStream(resourcePath);\n        if (resource == null) {\n            throw new RuntimeException(\"Could not find resource \" + resourcePath);\n        } else {\n            InputStreamReader resourceReader = new InputStreamReader(resource, Charsets.UTF_8);\n            Mustache template = MUSTACHE_FACTORY.compile(resourceReader, resourcePath);\n            return template.execute(new StringWriter(), generatorContext).toString();\n        }\n    }\n\n    private String absoluteDir(ServiceContext ctx) {\n        return ctx.packageName.replace('.', '/');\n    }\n\n    private String getFileName(String dir, String fileName) {\n        if (Strings.isNullOrEmpty(dir)) {\n            return fileName;\n        }\n        return dir + \"/\" + fileName;\n    }\n\n    private String getComments(Location location) {\n        return location.getLeadingComments().isEmpty() ? location.getTrailingComments() : location.getLeadingComments();\n    }\n\n    private String getJavaDoc(String comments, String prefix) {\n        if (!comments.isEmpty()) {\n            StringBuilder builder = new StringBuilder(\"/**\\n\").append(prefix).append(\" * <pre>\\n\");\n            Arrays.stream(HtmlEscapers.htmlEscaper().escape(comments).split(\"\\n\"))\n                    .map(line -> line.replace(\"*/\", \"&#42;&#47;\").replace(\"*\", \"&#42;\"))\n                    .forEach(line ->\n                            builder.append(prefix).append(\" * \").append(line).append(\"\\n\"));\n            builder.append(prefix).append(\" * </pre>\\n\").append(prefix).append(\" */\");\n            return builder.toString();\n        }\n        return null;\n    }\n\n    /**\n     * Template class for proto Service objects.\n     */\n    private class ServiceContext {\n\n        // CHECKSTYLE DISABLE VisibilityModifier FOR 8 LINES\n        public String fileName;\n        public String interfaceFileName;\n        public String protoName;\n        public String packageName;\n        public String commonPackageName;\n        public String className;\n        public String interfaceClassName;\n        public String serviceName;\n        public boolean deprecated;\n        public String javaDoc;\n        public boolean multipleFiles;\n\n        public String outerClassName;\n        public List<MethodContext> methods = new ArrayList<>();\n\n        public Set<String> methodTypes = new HashSet<>();\n\n        public List<MethodContext> unaryRequestMethods() {\n            return methods.stream().filter(m -> !m.isManyInput).collect(Collectors.toList());\n        }\n\n        public List<MethodContext> unaryMethods() {\n            return methods.stream()\n                    .filter(m -> (!m.isManyInput && !m.isManyOutput))\n                    .collect(Collectors.toList());\n        }\n\n        public List<MethodContext> serverStreamingMethods() {\n            return methods.stream()\n                    .filter(m -> !m.isManyInput && m.isManyOutput)\n                    .collect(Collectors.toList());\n        }\n\n        public List<MethodContext> biStreamingMethods() {\n            return methods.stream().filter(m -> m.isManyInput).collect(Collectors.toList());\n        }\n\n        public List<MethodContext> biStreamingWithoutClientStreamMethods() {\n            return methods.stream().filter(m -> m.isManyInput && m.isManyOutput).collect(Collectors.toList());\n        }\n\n        public List<MethodContext> clientStreamingMethods() {\n            return methods.stream()\n                    .filter(m -> m.isManyInput && !m.isManyOutput)\n                    .collect(Collectors.toList());\n        }\n\n        public List<MethodContext> methods() {\n            return methods;\n        }\n    }\n\n    /**\n     * Template class for proto RPC objects.\n     */\n    private static class MethodContext {\n\n        // CHECKSTYLE DISABLE VisibilityModifier FOR 10 LINES\n        public String originMethodName;\n        public String methodName;\n        public String inputType;\n        public String outputType;\n        public boolean deprecated;\n        public boolean isManyInput;\n        public boolean isManyOutput;\n        public String reactiveCallsMethodName;\n        public String grpcCallsMethodName;\n        public int methodNumber;\n        public String javaDoc;\n        /**\n         * The HTTP request method\n         */\n        public String httpMethod;\n        /**\n         * The HTTP request path\n         */\n        public String path;\n        /**\n         * The message field that the HTTP request body mapping to\n         */\n        public String body;\n        /**\n         * Whether the method has HTTP mapping\n         */\n        public boolean hasMapping;\n        /**\n         * Whether the request body parameter need @GRequest annotation\n         */\n        public boolean needRequestAnnotation;\n\n        // This method mimics the upper-casing method ogf gRPC to ensure compatibility\n        // See https://github.com/grpc/grpc-java/blob/v1.8.0/compiler/src/java_plugin/cpp/java_generator.cpp#L58\n        public String methodNameUpperUnderscore() {\n            StringBuilder s = new StringBuilder();\n            for (int i = 0; i < methodName.length(); i++) {\n                char c = methodName.charAt(i);\n                s.append(Character.toUpperCase(c));\n                if ((i < methodName.length() - 1)\n                        && Character.isLowerCase(c)\n                        && Character.isUpperCase(methodName.charAt(i + 1))) {\n                    s.append('_');\n                }\n            }\n            return s.toString();\n        }\n\n        public String methodNamePascalCase() {\n            String mn = methodName.replace(\"_\", \"\");\n            return String.valueOf(Character.toUpperCase(mn.charAt(0))) + mn.substring(1);\n        }\n\n        public String methodNameCamelCase() {\n            String mn = methodName.replace(\"_\", \"\");\n            return String.valueOf(Character.toLowerCase(mn.charAt(0))) + mn.substring(1);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/DubboGeneratorPlugin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.gen;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport com.google.protobuf.compiler.PluginProtos;\n\npublic class DubboGeneratorPlugin {\n\n    public static void generate(AbstractGenerator generator) {\n        try {\n            PluginProtos.CodeGeneratorRequest request = PluginProtos.CodeGeneratorRequest.parseFrom(System.in);\n            List<PluginProtos.CodeGeneratorResponse.File> files = generator.generateFiles(request);\n            PluginProtos.CodeGeneratorResponse.newBuilder()\n                    .addAllFile(files)\n                    .setSupportedFeatures(\n                            PluginProtos.CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL.getNumber())\n                    .build()\n                    .writeTo(System.out);\n        } catch (Exception e) {\n            try {\n                PluginProtos.CodeGeneratorResponse.newBuilder()\n                        .setError(e.getMessage())\n                        .build()\n                        .writeTo(System.out);\n            } catch (IOException var6) {\n                exit(e);\n            }\n        } catch (Throwable var8) {\n            exit(var8);\n        }\n    }\n\n    public static void exit(Throwable e) {\n        e.printStackTrace(System.err);\n        System.exit(1);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/tri/Dubbo3TripleGenerator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.gen.tri;\n\nimport org.apache.dubbo.gen.AbstractGenerator;\nimport org.apache.dubbo.gen.DubboGeneratorPlugin;\n\npublic class Dubbo3TripleGenerator extends AbstractGenerator {\n\n    public static void main(String[] args) {\n        DubboGeneratorPlugin.generate(new Dubbo3TripleGenerator());\n    }\n\n    @Override\n    protected String getClassPrefix() {\n        return \"Dubbo\";\n    }\n\n    @Override\n    protected String getClassSuffix() {\n        return \"Triple\";\n    }\n\n    @Override\n    protected String getTemplateFileName() {\n        return \"Dubbo3TripleStub.mustache\";\n    }\n\n    @Override\n    protected String getInterfaceTemplateFileName() {\n        return \"Dubbo3TripleInterfaceStub.mustache\";\n    }\n\n    @Override\n    protected String getSingleTemplateFileName() {\n        throw new IllegalStateException(\"Do not support single template!\");\n    }\n\n    @Override\n    protected boolean useMultipleTemplate(boolean multipleFiles) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/tri/mutiny/MutinyDubbo3TripleGenerator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.gen.tri.mutiny;\n\nimport org.apache.dubbo.gen.AbstractGenerator;\nimport org.apache.dubbo.gen.DubboGeneratorPlugin;\n\npublic class MutinyDubbo3TripleGenerator extends AbstractGenerator {\n\n    public static void main(String[] args) {\n        DubboGeneratorPlugin.generate(new MutinyDubbo3TripleGenerator());\n    }\n\n    @Override\n    protected String getClassPrefix() {\n        return \"Dubbo\";\n    }\n\n    @Override\n    protected String getClassSuffix() {\n        return \"Triple\";\n    }\n\n    @Override\n    protected String getTemplateFileName() {\n        return \"MutinyDubbo3TripleStub.mustache\";\n    }\n\n    @Override\n    protected String getInterfaceTemplateFileName() {\n        return \"MutinyDubbo3TripleInterfaceStub.mustache\";\n    }\n\n    @Override\n    protected String getSingleTemplateFileName() {\n        throw new IllegalStateException(\"Do not support single template!\");\n    }\n\n    @Override\n    protected boolean useMultipleTemplate(boolean multipleFiles) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/tri/reactive/ReactorDubbo3TripleGenerator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.gen.tri.reactive;\n\nimport org.apache.dubbo.gen.AbstractGenerator;\nimport org.apache.dubbo.gen.DubboGeneratorPlugin;\n\npublic class ReactorDubbo3TripleGenerator extends AbstractGenerator {\n\n    public static void main(String[] args) {\n        DubboGeneratorPlugin.generate(new ReactorDubbo3TripleGenerator());\n    }\n\n    @Override\n    protected String getClassPrefix() {\n        return \"Dubbo\";\n    }\n\n    @Override\n    protected String getClassSuffix() {\n        return \"Triple\";\n    }\n\n    @Override\n    protected String getTemplateFileName() {\n        return \"ReactorDubbo3TripleStub.mustache\";\n    }\n\n    @Override\n    protected String getInterfaceTemplateFileName() {\n        return \"ReactorDubbo3TripleInterfaceStub.mustache\";\n    }\n\n    @Override\n    protected String getSingleTemplateFileName() {\n        throw new IllegalStateException(\"Do not support single template!\");\n    }\n\n    @Override\n    protected boolean useMultipleTemplate(boolean multipleFiles) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/utils/ProtoTypeMap.java",
    "content": "/*\n *  Copyright (c) 2019, Salesforce.com, Inc.\n *  All rights reserved.\n *  Licensed under the BSD 3-Clause license.\n *  For full license text, see LICENSE.txt file in the repo root  or https://opensource.org/licenses/BSD-3-Clause\n */\npackage org.apache.dubbo.gen.utils;\n\nimport com.google.common.base.CharMatcher;\nimport com.google.common.base.Joiner;\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport com.google.common.collect.ImmutableMap;\nimport com.google.protobuf.DescriptorProtos;\n\nimport javax.annotation.Nonnull;\nimport java.util.Collection;\n\npublic final class ProtoTypeMap {\n    private static final Joiner DOT_JOINER = Joiner.on('.').skipNulls();\n    private final ImmutableMap<String, String> types;\n\n    private ProtoTypeMap(@Nonnull ImmutableMap<String, String> types) {\n        Preconditions.checkNotNull(types, \"types\");\n        this.types = types;\n    }\n\n    public static ProtoTypeMap of(@Nonnull Collection<DescriptorProtos.FileDescriptorProto> fileDescriptorProtos) {\n        Preconditions.checkNotNull(fileDescriptorProtos, \"fileDescriptorProtos\");\n        Preconditions.checkArgument(!fileDescriptorProtos.isEmpty(), \"fileDescriptorProtos.isEmpty()\");\n        ImmutableMap.Builder<String, String> types = ImmutableMap.builder();\n\n        for (DescriptorProtos.FileDescriptorProto fileDescriptor : fileDescriptorProtos) {\n            DescriptorProtos.FileOptions fileOptions = fileDescriptor.getOptions();\n            String protoPackage = fileDescriptor.hasPackage() ? \".\" + fileDescriptor.getPackage() : \"\";\n            String javaPackage = Strings.emptyToNull(fileOptions.hasJavaPackage() ? fileOptions.getJavaPackage() : fileDescriptor.getPackage());\n            String enclosingClassName = fileOptions.getJavaMultipleFiles() ? null : getJavaOuterClassname(fileDescriptor, fileOptions);\n            fileDescriptor.getEnumTypeList().forEach((e) -> {\n                types.put(protoPackage + \".\" + e.getName(), DOT_JOINER.join(javaPackage, enclosingClassName, new Object[]{e.getName()}));\n            });\n            fileDescriptor.getMessageTypeList().forEach((m) -> {\n                recursivelyAddTypes(types, m, protoPackage, enclosingClassName, javaPackage);\n            });\n        }\n\n        return new ProtoTypeMap(types.build());\n    }\n\n    private static void recursivelyAddTypes(ImmutableMap.Builder<String, String> types, DescriptorProtos.DescriptorProto m, String protoPackage, String enclosingClassName, String javaPackage) {\n        String protoTypeName = protoPackage + \".\" + m.getName();\n        types.put(protoTypeName, DOT_JOINER.join(javaPackage, enclosingClassName, new Object[]{m.getName()}));\n        m.getEnumTypeList().forEach((e) -> {\n            types.put(protoPackage + \".\" + m.getName() + \".\" + e.getName(), DOT_JOINER.join(javaPackage, enclosingClassName, new Object[]{m.getName(), e.getName()}));\n        });\n        m.getNestedTypeList().forEach((n) -> {\n            recursivelyAddTypes(types, n, protoPackage + \".\" + m.getName(), DOT_JOINER.join(enclosingClassName, m.getName(), new Object[0]), javaPackage);\n        });\n    }\n\n    public String toJavaTypeName(@Nonnull String protoTypeName) {\n        Preconditions.checkNotNull(protoTypeName, \"protoTypeName\");\n        return (String)this.types.get(protoTypeName);\n    }\n\n    public static String getJavaOuterClassname(DescriptorProtos.FileDescriptorProto fileDescriptor, DescriptorProtos.FileOptions fileOptions) {\n        if (fileOptions.hasJavaOuterClassname()) {\n            return fileOptions.getJavaOuterClassname();\n        } else {\n            String filename = fileDescriptor.getName().substring(0, fileDescriptor.getName().length() - \".proto\".length());\n            if (filename.contains(\"/\")) {\n                filename = filename.substring(filename.lastIndexOf(47) + 1);\n            }\n\n            filename = makeInvalidCharactersUnderscores(filename);\n            filename = convertToCamelCase(filename);\n            filename = appendOuterClassSuffix(filename, fileDescriptor);\n            return filename;\n        }\n    }\n\n    private static String appendOuterClassSuffix(String enclosingClassName, DescriptorProtos.FileDescriptorProto fd) {\n        return !fd.getEnumTypeList().stream().anyMatch((enumProto) -> {\n            return enumProto.getName().equals(enclosingClassName);\n        }) && !fd.getMessageTypeList().stream().anyMatch((messageProto) -> {\n            return messageProto.getName().equals(enclosingClassName);\n        }) && !fd.getServiceList().stream().anyMatch((serviceProto) -> {\n            return serviceProto.getName().equals(enclosingClassName);\n        }) ? enclosingClassName : enclosingClassName + \"OuterClass\";\n    }\n\n    private static String makeInvalidCharactersUnderscores(String filename) {\n        char[] filechars = filename.toCharArray();\n\n        for(int i = 0; i < filechars.length; ++i) {\n            char c = filechars[i];\n            if (!CharMatcher.inRange('0', '9').or(CharMatcher.inRange('A', 'Z')).or(CharMatcher.inRange('a', 'z')).matches(c)) {\n                filechars[i] = '_';\n            }\n        }\n\n        return new String(filechars);\n    }\n\n    private static String convertToCamelCase(String name) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(Character.toUpperCase(name.charAt(0)));\n\n        for(int i = 1; i < name.length(); ++i) {\n            char c = name.charAt(i);\n            char prev = name.charAt(i - 1);\n            if (c != '_') {\n                if (prev != '_' && !CharMatcher.inRange('0', '9').matches(prev)) {\n                    sb.append(c);\n                } else {\n                    sb.append(Character.toUpperCase(c));\n                }\n            }\n        }\n\n        return sb.toString();\n    }\n}\n\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleInterfaceStub.mustache",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n{{#packageName}}\npackage {{packageName}};\n{{/packageName}}\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.rest.Mapping;\nimport org.apache.dubbo.rpc.stub.annotations.GRequest;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.concurrent.CompletableFuture;\n\npublic interface {{interfaceClassName}} extends org.apache.dubbo.rpc.model.DubboStub {\n\n{{#packageName}}\n    String JAVA_SERVICE_NAME = \"{{packageName}}.{{serviceName}}\";\n{{/packageName}}\n{{^packageName}}\n    String JAVA_SERVICE_NAME = \"{{serviceName}}\";\n{{/packageName}}\n{{#commonPackageName}}\n    String SERVICE_NAME = \"{{commonPackageName}}.{{serviceName}}\";\n{{/commonPackageName}}\n{{^commonPackageName}}\n    String SERVICE_NAME = \"{{serviceName}}\";\n{{/commonPackageName}}\n{{#unaryMethods}}\n\n    {{#javaDoc}}\n    {{{javaDoc}}}\n    {{/javaDoc}}\n    {{#hasMapping}}\n    @Mapping(method = HttpMethods.{{httpMethod}}, path = \"{{path}}\")\n    {{/hasMapping}}\n    {{outputType}} {{methodName}}({{#needRequestAnnotation}}@GRequest{{#body}}(\"{{body}}\"){{/body}} {{/needRequestAnnotation}}{{inputType}} request);\n\n    CompletableFuture<{{outputType}}> {{methodName}}Async({{#needRequestAnnotation}}@GRequest {{/needRequestAnnotation}}{{inputType}} request);\n{{/unaryMethods}}\n{{#serverStreamingMethods}}\n\n    {{#javaDoc}}\n    {{{javaDoc}}}\n    {{/javaDoc}}\n    {{#hasMapping}}\n    @Mapping(method = HttpMethods.{{httpMethod}}, path = \"{{path}}\")\n    {{/hasMapping}}\n    void {{methodName}}({{#needRequestAnnotation}}@GRequest{{#body}}(\"{{body}}\"){{/body}} {{/needRequestAnnotation}}{{inputType}} request, StreamObserver<{{outputType}}> responseObserver);\n{{/serverStreamingMethods}}\n{{#biStreamingWithoutClientStreamMethods}}\n\n    {{#javaDoc}}\n    {{{javaDoc}}}\n    {{/javaDoc}}\n    StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver);\n{{/biStreamingWithoutClientStreamMethods}}\n{{#clientStreamingMethods}}\n\n    {{#javaDoc}}\n    {{{javaDoc}}}\n    {{/javaDoc}}\n    StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver);\n{{/clientStreamingMethods}}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleStub.mustache",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n{{#packageName}}\npackage {{packageName}};\n{{/packageName}}\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.PathResolver;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.ServerService;\nimport org.apache.dubbo.rpc.TriRpcStatus;\nimport org.apache.dubbo.rpc.model.MethodDescriptor;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.model.StubMethodDescriptor;\nimport org.apache.dubbo.rpc.model.StubServiceDescriptor;\nimport org.apache.dubbo.rpc.service.Destroyable;\nimport org.apache.dubbo.rpc.stub.BiStreamMethodHandler;\nimport org.apache.dubbo.rpc.stub.ServerStreamMethodHandler;\nimport org.apache.dubbo.rpc.stub.StubInvocationUtil;\nimport org.apache.dubbo.rpc.stub.StubInvoker;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\nimport org.apache.dubbo.rpc.stub.StubSuppliers;\nimport org.apache.dubbo.rpc.stub.UnaryStubMethodHandler;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.concurrent.CompletableFuture;\n\npublic final class {{className}} {\n\n    public static final String SERVICE_NAME = {{interfaceClassName}}.SERVICE_NAME;\n\n    private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME, {{interfaceClassName}}.class);\n\n    static {\n        org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME, {{outerClassName}}.getDescriptor());\n        StubSuppliers.addSupplier(SERVICE_NAME, {{className}}::newStub);\n        StubSuppliers.addSupplier({{interfaceClassName}}.JAVA_SERVICE_NAME,  {{className}}::newStub);\n        StubSuppliers.addDescriptor(SERVICE_NAME, serviceDescriptor);\n        StubSuppliers.addDescriptor({{interfaceClassName}}.JAVA_SERVICE_NAME, serviceDescriptor);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static {{interfaceClassName}} newStub(Invoker<?> invoker) {\n        return new {{interfaceClassName}}Stub((Invoker<{{interfaceClassName}}>)invoker);\n    }\n{{#unaryMethods}}\n\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n    {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.UNARY,\n    obj -> ((com.google.protobuf.Message) obj).toByteArray(),obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n    {{outputType}}::parseFrom);\n\n    private static final StubMethodDescriptor {{methodName}}AsyncMethod = new StubMethodDescriptor(\"{{originMethodName}}\",\n    {{inputType}}.class, java.util.concurrent.CompletableFuture.class, MethodDescriptor.RpcType.UNARY,\n    obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n    {{outputType}}::parseFrom);\n\n    private static final StubMethodDescriptor {{methodName}}ProxyAsyncMethod = new StubMethodDescriptor(\"{{originMethodName}}Async\",\n    {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.UNARY,\n    obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n    {{outputType}}::parseFrom);\n{{/unaryMethods}}\n{{#serverStreamingMethods}}\n\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n    {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.SERVER_STREAM,\n    obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n    {{outputType}}::parseFrom);\n{{/serverStreamingMethods}}\n{{#clientStreamingMethods}}\n\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n    {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.CLIENT_STREAM,\n    obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n    {{outputType}}::parseFrom);\n{{/clientStreamingMethods}}\n{{#biStreamingWithoutClientStreamMethods}}\n\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n    {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.BI_STREAM,\n    obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n    {{outputType}}::parseFrom);\n{{/biStreamingWithoutClientStreamMethods}}\n\n    static{\n    {{#unaryMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n        serviceDescriptor.addMethod({{methodName}}ProxyAsyncMethod);\n    {{/unaryMethods}}\n    {{#serverStreamingMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/serverStreamingMethods}}\n    {{#clientStreamingMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/clientStreamingMethods}}\n    {{#biStreamingWithoutClientStreamMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/biStreamingWithoutClientStreamMethods}}\n    }\n\n    public static class {{interfaceClassName}}Stub implements {{interfaceClassName}}, Destroyable {\n        private final Invoker<{{interfaceClassName}}> invoker;\n\n        public {{interfaceClassName}}Stub(Invoker<{{interfaceClassName}}> invoker) {\n            this.invoker = invoker;\n        }\n\n        @Override\n        public void $destroy() {\n              invoker.destroy();\n         }\n    {{#unaryMethods}}\n\n        @Override\n        public {{outputType}} {{methodName}}({{inputType}} request){\n            return StubInvocationUtil.unaryCall(invoker, {{methodName}}Method, request);\n        }\n\n        public CompletableFuture<{{outputType}}> {{methodName}}Async({{inputType}} request){\n            return StubInvocationUtil.unaryCall(invoker, {{methodName}}AsyncMethod, request);\n        }\n\n        public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){\n            StubInvocationUtil.unaryCall(invoker, {{methodName}}Method , request, responseObserver);\n        }\n    {{/unaryMethods}}\n    {{#serverStreamingMethods}}\n\n        @Override\n        public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){\n            StubInvocationUtil.serverStreamCall(invoker, {{methodName}}Method , request, responseObserver);\n        }\n    {{/serverStreamingMethods}}\n    {{#biStreamingWithoutClientStreamMethods}}\n\n        @Override\n        public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){\n            return StubInvocationUtil.biOrClientStreamCall(invoker, {{methodName}}Method , responseObserver);\n        }\n    {{/biStreamingWithoutClientStreamMethods}}\n    {{#clientStreamingMethods}}\n\n        @Override\n        public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){\n        return StubInvocationUtil.biOrClientStreamCall(invoker, {{methodName}}Method , responseObserver);\n        }\n    {{/clientStreamingMethods}}\n    }\n\n    public static abstract class {{interfaceClassName}}ImplBase implements {{interfaceClassName}}, ServerService<{{interfaceClassName}}> {\n        private <T, R> BiConsumer<T, StreamObserver<R>> syncToAsync(java.util.function.Function<T, R> syncFun) {\n            return new BiConsumer<T, StreamObserver<R>>() {\n                @Override\n                public void accept(T t, StreamObserver<R> observer) {\n                    try {\n                        R ret = syncFun.apply(t);\n                        observer.onNext(ret);\n                        observer.onCompleted();\n                    } catch (Throwable e) {\n                        observer.onError(e);\n                    }\n                }\n            };\n        }\n        {{#unaryMethods}}\n\n        @Override\n        public CompletableFuture<{{outputType}}> {{methodName}}Async({{inputType}} request){\n                return CompletableFuture.completedFuture({{methodName}}(request));\n        }\n        {{/unaryMethods}}\n\n        // This server stream type unary method is <b>only</b> used for generated stub to support async unary method.\n        // It will not be called if you are NOT using Dubbo3 generated triple stub and <b>DO NOT</b> implement this method.\n        {{#unaryMethods}}\n\n        public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){\n            {{methodName}}Async(request).whenComplete((r, t) -> {\n                if (t != null) {\n                    responseObserver.onError(t);\n                } else {\n                    responseObserver.onNext(r);\n                    responseObserver.onCompleted();\n                }\n            });\n        }\n        {{/unaryMethods}}\n\n        @Override\n        public final Invoker<{{interfaceClassName}}> getInvoker(URL url) {\n            PathResolver pathResolver = url.getOrDefaultFrameworkModel()\n            .getExtensionLoader(PathResolver.class)\n            .getDefaultExtension();\n            Map<String, StubMethodHandler<?, ?>> handlers = new HashMap<>();\n        {{#methods}}\n            pathResolver.addNativeStub( \"/\" + SERVICE_NAME + \"/{{originMethodName}}\");\n            pathResolver.addNativeStub( \"/\" + SERVICE_NAME + \"/{{originMethodName}}Async\");\n            // for compatibility\n            pathResolver.addNativeStub( \"/\" + JAVA_SERVICE_NAME + \"/{{originMethodName}}\");\n            pathResolver.addNativeStub( \"/\" + JAVA_SERVICE_NAME + \"/{{originMethodName}}Async\");\n        {{/methods}}\n        {{#unaryMethods}}\n            BiConsumer<{{inputType}}, StreamObserver<{{outputType}}>> {{methodName}}Func = this::{{methodName}};\n            handlers.put({{methodName}}Method.getMethodName(), new UnaryStubMethodHandler<>({{methodName}}Func));\n            BiConsumer<{{inputType}}, StreamObserver<{{outputType}}>> {{methodName}}AsyncFunc = syncToAsync(this::{{methodName}});\n            handlers.put({{methodName}}ProxyAsyncMethod.getMethodName(), new UnaryStubMethodHandler<>({{methodName}}AsyncFunc));\n        {{/unaryMethods}}\n        {{#serverStreamingMethods}}\n            handlers.put({{methodName}}Method.getMethodName(), new ServerStreamMethodHandler<>(this::{{methodName}}));\n        {{/serverStreamingMethods}}\n        {{#clientStreamingMethods}}\n            handlers.put({{methodName}}Method.getMethodName(), new BiStreamMethodHandler<>(this::{{methodName}}));\n        {{/clientStreamingMethods}}\n        {{#biStreamingWithoutClientStreamMethods}}\n            handlers.put({{methodName}}Method.getMethodName(), new BiStreamMethodHandler<>(this::{{methodName}}));\n        {{/biStreamingWithoutClientStreamMethods}}\n\n            return new StubInvoker<>(this, url, {{interfaceClassName}}.class, handlers);\n        }\n    {{#unaryMethods}}\n\n        @Override\n        public {{outputType}} {{methodName}}({{inputType}} request){\n            throw unimplementedMethodException({{methodName}}Method);\n        }\n    {{/unaryMethods}}\n    {{#serverStreamingMethods}}\n\n        @Override\n        public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){\n            throw unimplementedMethodException({{methodName}}Method);\n        }\n    {{/serverStreamingMethods}}\n    {{#biStreamingWithoutClientStreamMethods}}\n\n        @Override\n        public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){\n            throw unimplementedMethodException({{methodName}}Method);\n        }\n    {{/biStreamingWithoutClientStreamMethods}}\n    {{#clientStreamingMethods}}\n\n        @Override\n        public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){\n            throw unimplementedMethodException({{methodName}}Method);\n        }\n    {{/clientStreamingMethods}}\n\n        @Override\n        public final ServiceDescriptor getServiceDescriptor() {\n            return serviceDescriptor;\n        }\n        private RpcException unimplementedMethodException(StubMethodDescriptor methodDescriptor) {\n            return TriRpcStatus.UNIMPLEMENTED.withDescription(String.format(\"Method %s is unimplemented\",\n                \"/\" + serviceDescriptor.getInterfaceName() + \"/\" + methodDescriptor.getMethodName())).asException();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/resources/MutinyDubbo3TripleInterfaceStub.mustache",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n\n{{#packageName}}\npackage {{packageName}};\n{{/packageName}}\n\nimport io.smallrye.mutiny.Multi;\nimport io.smallrye.mutiny.Uni;\n\npublic interface {{interfaceClassName}} extends org.apache.dubbo.rpc.model.DubboStub {\n\n{{#packageName}}\n    String JAVA_SERVICE_NAME = \"{{packageName}}.{{serviceName}}\";\n{{/packageName}}\n{{^packageName}}\n    String JAVA_SERVICE_NAME = \"{{serviceName}}\";\n{{/packageName}}\n{{#commonPackageName}}\n    String SERVICE_NAME = \"{{commonPackageName}}.{{serviceName}}\";\n{{/commonPackageName}}\n{{^commonPackageName}}\n    String SERVICE_NAME = \"{{serviceName}}\";\n{{/commonPackageName}}\n{{#methods}}\n    {{#javaDoc}}\n        {{{javaDoc}}}\n    {{/javaDoc}}\n    {{#deprecated}}\n        @java.lang.Deprecated\n    {{/deprecated}}\n    {{#isManyOutput}}Multi{{/isManyOutput}}{{^isManyOutput}}Uni{{/isManyOutput}}<{{outputType}}> {{methodName}}({{#isManyInput}}Multi{{/isManyInput}}{{^isManyInput}}Uni{{/isManyInput}}<{{inputType}}> mutinyRequest) ;\n\n{{/methods}}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/resources/MutinyDubbo3TripleStub.mustache",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n\n{{#packageName}}\npackage {{packageName}};\n{{/packageName}}\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.PathResolver;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.ServerService;\nimport org.apache.dubbo.rpc.TriRpcStatus;\nimport org.apache.dubbo.rpc.model.MethodDescriptor;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.model.StubMethodDescriptor;\nimport org.apache.dubbo.rpc.model.StubServiceDescriptor;\nimport org.apache.dubbo.mutiny.calls.MutinyClientCalls;\nimport org.apache.dubbo.mutiny.handler.ManyToManyMethodHandler;\nimport org.apache.dubbo.mutiny.handler.ManyToOneMethodHandler;\nimport org.apache.dubbo.mutiny.handler.OneToManyMethodHandler;\nimport org.apache.dubbo.mutiny.handler.OneToOneMethodHandler;\n\nimport org.apache.dubbo.rpc.stub.StubInvoker;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\nimport org.apache.dubbo.rpc.stub.StubSuppliers;\nimport io.smallrye.mutiny.Multi;\nimport io.smallrye.mutiny.Uni;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic final class {{className}} {\n\n    private {{className}}() {}\n\n    public static final String SERVICE_NAME = {{interfaceClassName}}.SERVICE_NAME;\n\n    private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME, {{interfaceClassName}}.class);\n\n    static {\n        org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME, {{outerClassName}}.getDescriptor());\n        StubSuppliers.addSupplier(SERVICE_NAME, {{className}}::newStub);\n        StubSuppliers.addSupplier({{interfaceClassName}}.JAVA_SERVICE_NAME, {{className}}::newStub);\n        StubSuppliers.addDescriptor(SERVICE_NAME, serviceDescriptor);\n        StubSuppliers.addDescriptor({{interfaceClassName}}.JAVA_SERVICE_NAME, serviceDescriptor);\n    }\n\n    @SuppressWarnings(\"all\")\n    public static {{interfaceClassName}} newStub(Invoker<?> invoker) {\n        return new {{interfaceClassName}}Stub((Invoker<{{interfaceClassName}}>)invoker);\n    }\n\n{{#unaryMethods}}\n    {{#javaDoc}}\n        {{{javaDoc}}}\n    {{/javaDoc}}\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n        {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.UNARY,\n        obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n        {{outputType}}::parseFrom);\n{{/unaryMethods}}\n\n{{#serverStreamingMethods}}\n    {{#javaDoc}}\n        {{{javaDoc}}}\n    {{/javaDoc}}\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n        {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.SERVER_STREAM,\n        obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n        {{outputType}}::parseFrom);\n{{/serverStreamingMethods}}\n\n{{#clientStreamingMethods}}\n    {{#javaDoc}}\n        {{{javaDoc}}}\n    {{/javaDoc}}\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n        {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.CLIENT_STREAM,\n        obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n        {{outputType}}::parseFrom);\n{{/clientStreamingMethods}}\n\n{{#biStreamingWithoutClientStreamMethods}}\n    {{#javaDoc}}\n        {{{javaDoc}}}\n    {{/javaDoc}}\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n        {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.BI_STREAM,\n        obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n        {{outputType}}::parseFrom);\n{{/biStreamingWithoutClientStreamMethods}}\n\n    static{\n    {{#unaryMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/unaryMethods}}\n    {{#serverStreamingMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/serverStreamingMethods}}\n    {{#clientStreamingMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/clientStreamingMethods}}\n    {{#biStreamingWithoutClientStreamMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/biStreamingWithoutClientStreamMethods}}\n    }\n\n    public static class {{interfaceClassName}}Stub implements {{interfaceClassName}}{\n\n        private final Invoker<{{interfaceClassName}}> invoker;\n\n        public {{interfaceClassName}}Stub(Invoker<{{interfaceClassName}}> invoker) {\n            this.invoker = invoker;\n        }\n\n    {{#methods}}\n        {{#javaDoc}}\n            {{{javaDoc}}}\n        {{/javaDoc}}\n        {{#deprecated}}\n            @java.lang.Deprecated\n        {{/deprecated}}\n        public {{#isManyOutput}}Multi{{/isManyOutput}}{{^isManyOutput}}Uni{{/isManyOutput}}<{{outputType}}> {{methodName}}({{#isManyInput}}Multi{{/isManyInput}}{{^isManyInput}}Uni{{/isManyInput}}<{{inputType}}> request) {\n            return MutinyClientCalls.{{reactiveCallsMethodName}}(invoker, request, {{methodNameCamelCase}}Method);\n        }\n    {{/methods}}\n    }\n\n    public static abstract class {{interfaceClassName}}ImplBase implements {{interfaceClassName}}, ServerService<{{interfaceClassName}}> {\n\n        @Override\n        public final Invoker<{{interfaceClassName}}> getInvoker(URL url) {\n            PathResolver pathResolver = url.getOrDefaultFrameworkModel()\n            .getExtensionLoader(PathResolver.class)\n            .getDefaultExtension();\n            Map<String, StubMethodHandler<?, ?>> handlers = new HashMap<>();\n\n            {{#methods}}\n                pathResolver.addNativeStub( \"/\" + SERVICE_NAME + \"/{{originMethodName}}\");\n                // for compatibility\n                pathResolver.addNativeStub( \"/\" + JAVA_SERVICE_NAME + \"/{{originMethodName}}\");\n            {{/methods}}\n\n            {{#unaryMethods}}\n                handlers.put({{methodName}}Method.getMethodName(), new OneToOneMethodHandler<>(this::{{methodName}}));\n            {{/unaryMethods}}\n            {{#serverStreamingMethods}}\n                handlers.put({{methodName}}Method.getMethodName(), new OneToManyMethodHandler<>(this::{{methodName}}));\n            {{/serverStreamingMethods}}\n            {{#clientStreamingMethods}}\n                handlers.put({{methodName}}Method.getMethodName(), new ManyToOneMethodHandler<>(this::{{methodName}}));\n            {{/clientStreamingMethods}}\n            {{#biStreamingWithoutClientStreamMethods}}\n                handlers.put({{methodName}}Method.getMethodName(), new ManyToManyMethodHandler<>(this::{{methodName}}));\n            {{/biStreamingWithoutClientStreamMethods}}\n\n            return new StubInvoker<>(this, url, {{interfaceClassName}}.class, handlers);\n        }\n\n    {{#methods}}\n        {{#javaDoc}}\n            {{{javaDoc}}}\n        {{/javaDoc}}\n        {{#deprecated}}\n            @java.lang.Deprecated\n        {{/deprecated}}\n        public {{#isManyOutput}}Multi{{/isManyOutput}}{{^isManyOutput}}Uni{{/isManyOutput}}<{{outputType}}> {{methodName}}({{#isManyInput}}Multi{{/isManyInput}}{{^isManyInput}}Uni{{/isManyInput}}<{{inputType}}> request) {\n            throw unimplementedMethodException({{methodName}}Method);\n        }\n    {{/methods}}\n\n        @Override\n        public final ServiceDescriptor getServiceDescriptor() {\n            return serviceDescriptor;\n        }\n\n        private RpcException unimplementedMethodException(StubMethodDescriptor methodDescriptor) {\n            return TriRpcStatus.UNIMPLEMENTED.withDescription(String.format(\"Method %s is unimplemented\",\n            \"/\" + serviceDescriptor.getInterfaceName() + \"/\" + methodDescriptor.getMethodName())).asException();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/resources/ReactorDubbo3TripleInterfaceStub.mustache",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n\n{{#packageName}}\npackage {{packageName}};\n{{/packageName}}\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\npublic interface {{interfaceClassName}} extends org.apache.dubbo.rpc.model.DubboStub {\n\n{{#packageName}}\n    String JAVA_SERVICE_NAME = \"{{packageName}}.{{serviceName}}\";\n{{/packageName}}\n{{^packageName}}\n    String JAVA_SERVICE_NAME = \"{{serviceName}}\";\n{{/packageName}}\n{{#commonPackageName}}\n    String SERVICE_NAME = \"{{commonPackageName}}.{{serviceName}}\";\n{{/commonPackageName}}\n{{^commonPackageName}}\n    String SERVICE_NAME = \"{{serviceName}}\";\n{{/commonPackageName}}\n{{#methods}}\n    {{#javaDoc}}\n        {{{javaDoc}}}\n    {{/javaDoc}}\n    {{#deprecated}}\n        @java.lang.Deprecated\n    {{/deprecated}}\n    {{#isManyOutput}}Flux{{/isManyOutput}}{{^isManyOutput}}Mono{{/isManyOutput}}<{{outputType}}> {{methodName}}({{#isManyInput}}Flux{{/isManyInput}}{{^isManyInput}}Mono{{/isManyInput}}<{{inputType}}> reactorRequest) ;\n\n{{/methods}}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-compiler/src/main/resources/ReactorDubbo3TripleStub.mustache",
    "content": "/*\n* Licensed to the Apache Software Foundation (ASF) under one or more\n* contributor license agreements.  See the NOTICE file distributed with\n* this work for additional information regarding copyright ownership.\n* The ASF licenses this file to You under the Apache License, Version 2.0\n* (the \"License\"); you may not use this file except in compliance with\n* the License.  You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n\n{{#packageName}}\npackage {{packageName}};\n{{/packageName}}\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.PathResolver;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.ServerService;\nimport org.apache.dubbo.rpc.TriRpcStatus;\nimport org.apache.dubbo.rpc.model.MethodDescriptor;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.model.StubMethodDescriptor;\nimport org.apache.dubbo.rpc.model.StubServiceDescriptor;\nimport org.apache.dubbo.reactive.handler.ManyToManyMethodHandler;\nimport org.apache.dubbo.reactive.handler.ManyToOneMethodHandler;\nimport org.apache.dubbo.reactive.handler.OneToManyMethodHandler;\nimport org.apache.dubbo.reactive.calls.ReactorClientCalls;\nimport org.apache.dubbo.reactive.handler.OneToOneMethodHandler;\n\nimport org.apache.dubbo.rpc.stub.StubInvoker;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\nimport org.apache.dubbo.rpc.stub.StubSuppliers;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic final class {{className}} {\n\n    private {{className}}() {}\n\n    public static final String SERVICE_NAME = {{interfaceClassName}}.SERVICE_NAME;\n\n    private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME, {{interfaceClassName}}.class);\n\n    static {\n        org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME, {{outerClassName}}.getDescriptor());\n        StubSuppliers.addSupplier(SERVICE_NAME, {{className}}::newStub);\n        StubSuppliers.addSupplier({{interfaceClassName}}.JAVA_SERVICE_NAME,  {{className}}::newStub);\n        StubSuppliers.addDescriptor(SERVICE_NAME, serviceDescriptor);\n        StubSuppliers.addDescriptor({{interfaceClassName}}.JAVA_SERVICE_NAME, serviceDescriptor);\n    }\n\n    @SuppressWarnings(\"all\")\n    public static {{interfaceClassName}} newStub(Invoker<?> invoker) {\n        return new {{interfaceClassName}}Stub((Invoker<{{interfaceClassName}}>)invoker);\n    }\n\n{{#unaryMethods}}\n    {{#javaDoc}}\n        {{{javaDoc}}}\n    {{/javaDoc}}\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n        {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.UNARY,\n        obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n        {{outputType}}::parseFrom);\n{{/unaryMethods}}\n\n{{#serverStreamingMethods}}\n    {{#javaDoc}}\n        {{{javaDoc}}}\n    {{/javaDoc}}\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n        {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.SERVER_STREAM,\n        obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n        {{outputType}}::parseFrom);\n{{/serverStreamingMethods}}\n\n{{#clientStreamingMethods}}\n    {{#javaDoc}}\n        {{{javaDoc}}}\n    {{/javaDoc}}\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n        {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.CLIENT_STREAM,\n        obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n        {{outputType}}::parseFrom);\n{{/clientStreamingMethods}}\n\n{{#biStreamingWithoutClientStreamMethods}}\n    {{#javaDoc}}\n        {{{javaDoc}}}\n    {{/javaDoc}}\n    private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor(\"{{originMethodName}}\",\n        {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.BI_STREAM,\n        obj -> ((com.google.protobuf.Message) obj).toByteArray(), obj -> ((com.google.protobuf.Message) obj).toByteArray(), {{inputType}}::parseFrom,\n        {{outputType}}::parseFrom);\n{{/biStreamingWithoutClientStreamMethods}}\n\n    static{\n    {{#unaryMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/unaryMethods}}\n    {{#serverStreamingMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/serverStreamingMethods}}\n    {{#clientStreamingMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/clientStreamingMethods}}\n    {{#biStreamingWithoutClientStreamMethods}}\n        serviceDescriptor.addMethod({{methodName}}Method);\n    {{/biStreamingWithoutClientStreamMethods}}\n    }\n\n    public static class {{interfaceClassName}}Stub implements {{interfaceClassName}}{\n\n        private final Invoker<{{interfaceClassName}}> invoker;\n\n        public {{interfaceClassName}}Stub(Invoker<{{interfaceClassName}}> invoker) {\n            this.invoker = invoker;\n        }\n\n    {{#methods}}\n        {{#javaDoc}}\n            {{{javaDoc}}}\n        {{/javaDoc}}\n        {{#deprecated}}\n            @java.lang.Deprecated\n        {{/deprecated}}\n        public {{#isManyOutput}}Flux{{/isManyOutput}}{{^isManyOutput}}Mono{{/isManyOutput}}<{{outputType}}> {{methodName}}({{#isManyInput}}Flux{{/isManyInput}}{{^isManyInput}}Mono{{/isManyInput}}<{{inputType}}> request) {\n            return ReactorClientCalls.{{reactiveCallsMethodName}}(invoker, request, {{methodNameCamelCase}}Method);\n        }\n    {{/methods}}\n    }\n\n    public static abstract class {{interfaceClassName}}ImplBase implements {{interfaceClassName}}, ServerService<{{interfaceClassName}}> {\n\n        @Override\n        public final Invoker<{{interfaceClassName}}> getInvoker(URL url) {\n            PathResolver pathResolver = url.getOrDefaultFrameworkModel()\n            .getExtensionLoader(PathResolver.class)\n            .getDefaultExtension();\n            Map<String, StubMethodHandler<?, ?>> handlers = new HashMap<>();\n\n            {{#methods}}\n                pathResolver.addNativeStub( \"/\" + SERVICE_NAME + \"/{{originMethodName}}\");\n                // for compatibility\n                pathResolver.addNativeStub( \"/\" + JAVA_SERVICE_NAME + \"/{{originMethodName}}\");\n            {{/methods}}\n\n            {{#unaryMethods}}\n                handlers.put({{methodName}}Method.getMethodName(), new OneToOneMethodHandler<>(this::{{methodName}}));\n            {{/unaryMethods}}\n            {{#serverStreamingMethods}}\n                handlers.put({{methodName}}Method.getMethodName(), new OneToManyMethodHandler<>(this::{{methodName}}));\n            {{/serverStreamingMethods}}\n            {{#clientStreamingMethods}}\n                handlers.put({{methodName}}Method.getMethodName(), new ManyToOneMethodHandler<>(this::{{methodName}}));\n            {{/clientStreamingMethods}}\n            {{#biStreamingWithoutClientStreamMethods}}\n                handlers.put({{methodName}}Method.getMethodName(), new ManyToManyMethodHandler<>(this::{{methodName}}));\n            {{/biStreamingWithoutClientStreamMethods}}\n\n            return new StubInvoker<>(this, url, {{interfaceClassName}}.class, handlers);\n        }\n\n    {{#methods}}\n        {{#javaDoc}}\n            {{{javaDoc}}}\n        {{/javaDoc}}\n        {{#deprecated}}\n            @java.lang.Deprecated\n        {{/deprecated}}\n        public {{#isManyOutput}}Flux{{/isManyOutput}}{{^isManyOutput}}Mono{{/isManyOutput}}<{{outputType}}> {{methodName}}({{#isManyInput}}Flux{{/isManyInput}}{{^isManyInput}}Mono{{/isManyInput}}<{{inputType}}> request) {\n            throw unimplementedMethodException({{methodName}}Method);\n        }\n    {{/methods}}\n\n        @Override\n        public final ServiceDescriptor getServiceDescriptor() {\n            return serviceDescriptor;\n        }\n\n        private RpcException unimplementedMethodException(StubMethodDescriptor methodDescriptor) {\n            return TriRpcStatus.UNIMPLEMENTED.withDescription(String.format(\"Method %s is unimplemented\",\n            \"/\" + serviceDescriptor.getInterfaceName() + \"/\" + methodDescriptor.getMethodName())).asException();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-filter-cache</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The cache module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n    <hazelcast_version>3.12.13</hazelcast_version>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>javax.cache</groupId>\n      <artifactId>cache-api</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.hazelcast</groupId>\n      <artifactId>hazelcast</artifactId>\n      <version>${hazelcast_version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/Cache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache;\n\n/**\n * Cache interface to support storing and retrieval of value against a lookup key. It has two operation <b>get</b> and <b>put</b>.\n * <li><b>put</b>-Storing value against a key.</li>\n * <li><b>get</b>-Retrieval of object.</li>\n * @see org.apache.dubbo.cache.support.lru.LruCache\n * @see org.apache.dubbo.cache.support.jcache.JCache\n * @see org.apache.dubbo.cache.support.expiring.ExpiringCache\n * @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCache\n */\npublic interface Cache {\n    /**\n     * API to store value against a key\n     * @param key  Unique identifier for the object being store.\n     * @param value Value getting store\n     */\n    void put(Object key, Object value);\n\n    /**\n     * API to return stored value using a key.\n     * @param key Unique identifier for cache lookup\n     * @return Return stored object against key\n     */\n    Object get(Object key);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/CacheFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.Invocation;\n\n/**\n * Interface needs to be implemented by all the cache store provider.Along with implementing <b>CacheFactory</b> interface\n * entry needs to be added in org.apache.dubbo.cache.CacheFactory file in a classpath META-INF sub directories.\n *\n * @see Cache\n */\n@SPI(\"lru\")\npublic interface CacheFactory {\n\n    /**\n     * CacheFactory implementation class needs to implement this return underlying cache instance for method against\n     * url and invocation.\n     * @param url\n     * @param invocation\n     * @return Instance of Cache containing cached value against method url and invocation.\n     */\n    @Adaptive(\"cache\")\n    Cache getCache(URL url, Invocation invocation);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/filter/CacheFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.filter;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.CacheFactory;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport java.io.Serializable;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;\nimport static org.apache.dubbo.common.constants.FilterConstants.CACHE_KEY;\n\n/**\n * CacheFilter is a core component of dubbo.Enabling <b>cache</b> key of service,method,consumer or provider dubbo will cache method return value.\n * Along with cache key we need to configure cache type. Dubbo default implemented cache types are\n * <li>lru</li>\n * <li>threadlocal</li>\n * <li>jcache</li>\n * <li>expiring</li>\n *\n * <pre>\n *   e.g. 1)&lt;dubbo:service cache=\"lru\" /&gt;\n *        2)&lt;dubbo:service /&gt; &lt;dubbo:method name=\"method2\" cache=\"threadlocal\" /&gt; &lt;dubbo:service/&gt;\n *        3)&lt;dubbo:provider cache=\"expiring\" /&gt;\n *        4)&lt;dubbo:consumer cache=\"jcache\" /&gt;\n *\n *If cache type is defined in method level then method level type will get precedence. According to above provided\n *example, if service has two method, method1 and method2, method2 will have cache type as <b>threadlocal</b> where others will\n *be backed by <b>lru</b>\n *</pre>\n *\n * @see org.apache.dubbo.rpc.Filter\n * @see org.apache.dubbo.cache.support.lru.LruCacheFactory\n * @see org.apache.dubbo.cache.support.lru.LruCache\n * @see org.apache.dubbo.cache.support.jcache.JCacheFactory\n * @see org.apache.dubbo.cache.support.jcache.JCache\n * @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory\n * @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCache\n * @see org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory\n * @see org.apache.dubbo.cache.support.expiring.ExpiringCache\n *\n */\n@Activate(\n        group = {CONSUMER, PROVIDER},\n        value = CACHE_KEY)\npublic class CacheFilter implements Filter {\n\n    private CacheFactory cacheFactory;\n\n    /**\n     * Dubbo will populate and set the cache factory instance based on service/method/consumer/provider configured\n     * cache attribute value. Dubbo will search for the class name implementing configured <b>cache</b> in file org.apache.dubbo.cache.CacheFactory\n     * under META-INF sub folders.\n     *\n     * @param cacheFactory instance of CacheFactory based on <b>cache</b> type\n     */\n    public void setCacheFactory(CacheFactory cacheFactory) {\n        this.cacheFactory = cacheFactory;\n    }\n\n    /**\n     * If cache is configured, dubbo will invoke method on each method call. If cache value is returned by cache store\n     * then it will return otherwise call the remote method and return value. If remote method's return value has error\n     * then it will not cache the value.\n     * @param invoker    service\n     * @param invocation invocation.\n     * @return Cache returned value if found by the underlying cache store. If cache miss it will call target method.\n     * @throws RpcException\n     */\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        if (cacheFactory == null\n                || ConfigUtils.isEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), CACHE_KEY))) {\n            return invoker.invoke(invocation);\n        }\n        Cache cache = cacheFactory.getCache(invoker.getUrl(), invocation);\n        if (cache == null) {\n            return invoker.invoke(invocation);\n        }\n        String key = StringUtils.toArgumentString(invocation.getArguments());\n        Object value = cache.get(key);\n        return (value != null)\n                ? onCacheValuePresent(invocation, value)\n                : onCacheValueNotPresent(invoker, invocation, cache, key);\n    }\n\n    private Result onCacheValuePresent(Invocation invocation, Object value) {\n        if (value instanceof ValueWrapper) {\n            return AsyncRpcResult.newDefaultAsyncResult(((ValueWrapper) value).get(), invocation);\n        }\n        return AsyncRpcResult.newDefaultAsyncResult(value, invocation);\n    }\n\n    private Result onCacheValueNotPresent(Invoker<?> invoker, Invocation invocation, Cache cache, String key) {\n        Result result = invoker.invoke(invocation);\n        if (!result.hasException()) {\n            cache.put(key, new ValueWrapper(result.getValue()));\n        }\n        return result;\n    }\n\n    /**\n     * Cache value wrapper.\n     */\n    static class ValueWrapper implements Serializable {\n\n        private static final long serialVersionUID = -1777337318019193256L;\n\n        private final Object value;\n\n        public ValueWrapper(Object value) {\n            this.value = value;\n        }\n\n        public Object get() {\n            return this.value;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/AbstractCacheFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.CacheFactory;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;\n\n/**\n * AbstractCacheFactory is a default implementation of {@link CacheFactory}. It abstract out the key formation from URL along with\n * invocation method. It initially check if the value for key already present in own local in-memory store then it won't check underlying storage cache {@link Cache}.\n * Internally it used {@link ConcurrentHashMap} to store do level-1 caching.\n *\n * @see CacheFactory\n * @see org.apache.dubbo.cache.support.jcache.JCacheFactory\n * @see org.apache.dubbo.cache.support.lru.LruCacheFactory\n * @see org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory\n * @see org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory\n */\npublic abstract class AbstractCacheFactory implements CacheFactory {\n\n    /**\n     * This is used to store factory level-1 cached data.\n     */\n    private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<>();\n\n    private final Object MONITOR = new Object();\n\n    /**\n     * Takes URL and invocation instance and return cache instance for a given url.\n     *\n     * @param url        url of the method\n     * @param invocation invocation context.\n     * @return Instance of cache store used as storage for caching return values.\n     */\n    @Override\n    public Cache getCache(URL url, Invocation invocation) {\n        url = url.addParameter(METHOD_KEY, invocation.getMethodName());\n        String key = url.getServiceKey() + invocation.getMethodName();\n        Cache cache = caches.get(key);\n\n        // get from cache first.\n        if (null != cache) {\n            return cache;\n        }\n\n        synchronized (MONITOR) {\n            // double check.\n            cache = caches.get(key);\n            if (null != cache) {\n                return cache;\n            }\n\n            cache = createCache(url);\n            caches.put(key, cache);\n        }\n\n        return cache;\n    }\n\n    /**\n     * Takes url as an method argument and return new instance of cache store implemented by AbstractCacheFactory subclass.\n     *\n     * @param url url of the method\n     * @return Create and return new instance of cache store used as storage for caching return values.\n     */\n    protected abstract Cache createCache(URL url);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/expiring/ExpiringCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.expiring;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.common.URL;\n\nimport java.util.Map;\n\n/**\n * ExpiringCache - With the characteristic of expiration time.\n */\n\n/**\n * This class store the cache value with the characteristic of expiration time. If a service,method,consumer or provided is configured with key <b>cache</b>\n * with value <b>expiring</b>, dubbo initialize the instance of this class using {@link ExpiringCacheFactory} to store method's returns value\n * to server from store without making method call.\n * <pre>\n *     e.g. 1) &lt;dubbo:service cache=\"expiring\" cache.seconds=\"60\" cache.interval=\"10\"/&gt;\n *          2) &lt;dubbo:consumer cache=\"expiring\" /&gt;\n * </pre>\n * <li>It used constructor argument url instance <b>cache.seconds</b> value to decide time to live of cached object.Default value of it is 180 second.</li>\n * <li>It used constructor argument url instance <b>cache.interval</b> value for cache value expiration interval.Default value of this is 4 second</li>\n * @see Cache\n * @see ExpiringCacheFactory\n * @see org.apache.dubbo.cache.support.AbstractCacheFactory\n * @see org.apache.dubbo.cache.filter.CacheFilter\n */\npublic class ExpiringCache implements Cache {\n    private final Map<Object, Object> store;\n\n    public ExpiringCache(URL url) {\n        // cache time (second)\n        final int secondsToLive = url.getParameter(\"cache.seconds\", 180);\n        // Cache check interval (second)\n        final int intervalSeconds = url.getParameter(\"cache.interval\", 4);\n        ExpiringMap<Object, Object> expiringMap = new ExpiringMap<>(secondsToLive, intervalSeconds);\n        expiringMap.getExpireThread().startExpiryIfNotStarted();\n        this.store = expiringMap;\n    }\n\n    /**\n     * API to store value against a key in the calling thread scope.\n     * @param key  Unique identifier for the object being store.\n     * @param value Value getting store\n     */\n    @Override\n    public void put(Object key, Object value) {\n        store.put(key, value);\n    }\n\n    /**\n     * API to return stored value using a key against the calling thread specific store.\n     * @param key Unique identifier for cache lookup\n     * @return Return stored object against key\n     */\n    @Override\n    public Object get(Object key) {\n        return store.get(key);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/expiring/ExpiringCacheFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.expiring;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.support.AbstractCacheFactory;\nimport org.apache.dubbo.common.URL;\n\n/**\n * Implement {@link org.apache.dubbo.cache.CacheFactory} by extending {@link AbstractCacheFactory} and provide\n * instance of new {@link ExpiringCache}.\n *\n * @see AbstractCacheFactory\n * @see ExpiringCache\n * @see Cache\n */\npublic class ExpiringCacheFactory extends AbstractCacheFactory {\n\n    /**\n     * Takes url as an method argument and return new instance of cache store implemented by JCache.\n     * @param url url of the method\n     * @return ExpiringCache instance of cache\n     */\n    @Override\n    protected Cache createCache(URL url) {\n        return new ExpiringCache(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/expiring/ExpiringMap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.expiring;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * can be expired map\n * Contains a background thread that periodically checks if the data is out of date\n */\npublic class ExpiringMap<K, V> implements Map<K, V> {\n\n    /**\n     * default time to live (second)\n     */\n    private static final int DEFAULT_TIME_TO_LIVE = 180;\n\n    /**\n     * default expire check interval (second)\n     */\n    private static final int DEFAULT_EXPIRATION_INTERVAL = 1;\n\n    private static final AtomicInteger expireCount = new AtomicInteger(1);\n\n    private final ConcurrentHashMap<K, ExpiryObject> delegateMap;\n\n    private final ExpireThread expireThread;\n\n    public ExpiringMap() {\n        this(DEFAULT_TIME_TO_LIVE, DEFAULT_EXPIRATION_INTERVAL);\n    }\n\n    /**\n     * Constructor\n     *\n     * @param timeToLive time to live (second)\n     */\n    public ExpiringMap(int timeToLive) {\n        this(timeToLive, DEFAULT_EXPIRATION_INTERVAL);\n    }\n\n    public ExpiringMap(int timeToLive, int expirationInterval) {\n        this(new ConcurrentHashMap<>(), timeToLive, expirationInterval);\n    }\n\n    private ExpiringMap(ConcurrentHashMap<K, ExpiryObject> delegateMap, int timeToLive, int expirationInterval) {\n        this.delegateMap = delegateMap;\n        this.expireThread = new ExpireThread();\n        expireThread.setTimeToLive(timeToLive);\n        expireThread.setExpirationInterval(expirationInterval);\n    }\n\n    @Override\n    public V put(K key, V value) {\n        ExpiryObject answer = delegateMap.put(key, new ExpiryObject(key, value, System.currentTimeMillis()));\n        if (answer == null) {\n            return null;\n        }\n        return answer.getValue();\n    }\n\n    @Override\n    public V get(Object key) {\n        ExpiryObject object = delegateMap.get(key);\n        if (object != null) {\n            long timeIdle = System.currentTimeMillis() - object.getLastAccessTime();\n            int timeToLive = expireThread.getTimeToLive();\n            if (timeToLive > 0 && timeIdle >= timeToLive * 1000L) {\n                delegateMap.remove(object.getKey());\n                return null;\n            }\n            object.setLastAccessTime(System.currentTimeMillis());\n            return object.getValue();\n        }\n        return null;\n    }\n\n    @Override\n    public V remove(Object key) {\n        ExpiryObject answer = delegateMap.remove(key);\n        if (answer == null) {\n            return null;\n        }\n        return answer.getValue();\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        return delegateMap.containsKey(key);\n    }\n\n    @Override\n    public boolean containsValue(Object value) {\n        return delegateMap.containsValue(value);\n    }\n\n    @Override\n    public int size() {\n        return delegateMap.size();\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return delegateMap.isEmpty();\n    }\n\n    @Override\n    public void clear() {\n        delegateMap.clear();\n        expireThread.stopExpiring();\n    }\n\n    @Override\n    public int hashCode() {\n        return delegateMap.hashCode();\n    }\n\n    @Override\n    public Set<K> keySet() {\n        return delegateMap.keySet();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        return delegateMap.equals(obj);\n    }\n\n    @Override\n    public void putAll(Map<? extends K, ? extends V> inMap) {\n        for (Entry<? extends K, ? extends V> e : inMap.entrySet()) {\n            this.put(e.getKey(), e.getValue());\n        }\n    }\n\n    @Override\n    public Collection<V> values() {\n        List<V> list = new ArrayList<>();\n        Set<Entry<K, ExpiryObject>> delegatedSet = delegateMap.entrySet();\n        for (Entry<K, ExpiryObject> entry : delegatedSet) {\n            ExpiryObject value = entry.getValue();\n            list.add(value.getValue());\n        }\n        return list;\n    }\n\n    @Override\n    public Set<Entry<K, V>> entrySet() {\n        throw new UnsupportedOperationException();\n    }\n\n    public ExpireThread getExpireThread() {\n        return expireThread;\n    }\n\n    public int getExpirationInterval() {\n        return expireThread.getExpirationInterval();\n    }\n\n    public void setExpirationInterval(int expirationInterval) {\n        expireThread.setExpirationInterval(expirationInterval);\n    }\n\n    public int getTimeToLive() {\n        return expireThread.getTimeToLive();\n    }\n\n    public void setTimeToLive(int timeToLive) {\n        expireThread.setTimeToLive(timeToLive);\n    }\n\n    @Override\n    public String toString() {\n        return \"ExpiringMap{\" + \"delegateMap=\"\n                + delegateMap.toString() + \", expireThread=\"\n                + expireThread.toString() + '}';\n    }\n\n    /**\n     * can be expired object\n     */\n    private class ExpiryObject {\n        private K key;\n        private V value;\n        private AtomicLong lastAccessTime;\n\n        ExpiryObject(K key, V value, long lastAccessTime) {\n            if (value == null) {\n                throw new IllegalArgumentException(\"An expiring object cannot be null.\");\n            }\n            this.key = key;\n            this.value = value;\n            this.lastAccessTime = new AtomicLong(lastAccessTime);\n        }\n\n        public long getLastAccessTime() {\n            return lastAccessTime.get();\n        }\n\n        public void setLastAccessTime(long lastAccessTime) {\n            this.lastAccessTime.set(lastAccessTime);\n        }\n\n        public K getKey() {\n            return key;\n        }\n\n        public V getValue() {\n            return value;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            return value.equals(obj);\n        }\n\n        @Override\n        public int hashCode() {\n            return value.hashCode();\n        }\n\n        @Override\n        public String toString() {\n            return \"ExpiryObject{\" + \"key=\" + key + \", value=\" + value + \", lastAccessTime=\" + lastAccessTime + '}';\n        }\n    }\n\n    /**\n     * Background thread, periodically checking if the data is out of date\n     */\n    public class ExpireThread implements Runnable {\n        private long timeToLiveMillis;\n        private long expirationIntervalMillis;\n        private volatile boolean running = false;\n        private final Thread expirerThread;\n\n        @Override\n        public String toString() {\n            return \"ExpireThread{\" + \", timeToLiveMillis=\"\n                    + timeToLiveMillis + \", expirationIntervalMillis=\"\n                    + expirationIntervalMillis + \", running=\"\n                    + running + \", expirerThread=\"\n                    + expirerThread + '}';\n        }\n\n        public ExpireThread() {\n            expirerThread = new Thread(this, \"ExpiryMapExpire-\" + expireCount.getAndIncrement());\n            expirerThread.setDaemon(true);\n        }\n\n        @Override\n        public void run() {\n            while (running) {\n                processExpires();\n                try {\n                    Thread.sleep(expirationIntervalMillis);\n                } catch (InterruptedException e) {\n                    running = false;\n                }\n            }\n        }\n\n        private void processExpires() {\n            long timeNow = System.currentTimeMillis();\n            if (timeToLiveMillis <= 0) {\n                return;\n            }\n            for (ExpiryObject o : delegateMap.values()) {\n                long timeIdle = timeNow - o.getLastAccessTime();\n                if (timeIdle >= timeToLiveMillis) {\n                    delegateMap.remove(o.getKey());\n                }\n            }\n        }\n\n        /**\n         * start expiring Thread\n         */\n        public void startExpiring() {\n            if (!running) {\n                running = true;\n                expirerThread.start();\n            }\n        }\n\n        /**\n         * start thread\n         */\n        public void startExpiryIfNotStarted() {\n            if (running && timeToLiveMillis <= 0) {\n                return;\n            }\n            startExpiring();\n        }\n\n        /**\n         * stop thread\n         */\n        public void stopExpiring() {\n            if (running) {\n                running = false;\n                expirerThread.interrupt();\n            }\n        }\n\n        /**\n         * get thread state\n         *\n         * @return thread state\n         */\n        public boolean isRunning() {\n            return running;\n        }\n\n        /**\n         * get time to live\n         *\n         * @return time to live\n         */\n        public int getTimeToLive() {\n            return (int) timeToLiveMillis / 1000;\n        }\n\n        /**\n         * update time to live\n         *\n         * @param timeToLive time to live\n         */\n        public void setTimeToLive(long timeToLive) {\n            this.timeToLiveMillis = timeToLive * 1000;\n        }\n\n        /**\n         * get expiration interval\n         *\n         * @return expiration interval (second)\n         */\n        public int getExpirationInterval() {\n            return (int) expirationIntervalMillis / 1000;\n        }\n\n        /**\n         * set expiration interval\n         *\n         * @param expirationInterval expiration interval (second)\n         */\n        public void setExpirationInterval(long expirationInterval) {\n            this.expirationIntervalMillis = expirationInterval * 1000;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/jcache/JCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.jcache;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport javax.cache.Cache;\nimport javax.cache.CacheException;\nimport javax.cache.CacheManager;\nimport javax.cache.Caching;\nimport javax.cache.configuration.MutableConfiguration;\nimport javax.cache.expiry.CreatedExpiryPolicy;\nimport javax.cache.expiry.Duration;\nimport javax.cache.spi.CachingProvider;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;\n\n/**\n * This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>\n * with value <b>jcache</b>, dubbo initialize the instance of this class using {@link JCacheFactory} to store method's returns value\n * to server from store without making method call.\n *\n * @see Cache\n * @see JCacheFactory\n * @see org.apache.dubbo.cache.support.AbstractCacheFactory\n * @see org.apache.dubbo.cache.filter.CacheFilter\n */\npublic class JCache implements org.apache.dubbo.cache.Cache {\n\n    private final Cache<Object, Object> store;\n\n    public JCache(URL url) {\n        String method = url.getParameter(METHOD_KEY, \"\");\n        String key = url.getAddress() + \".\" + url.getServiceKey() + \".\" + method;\n        // jcache parameter is the full-qualified class name of SPI implementation\n        String type = url.getParameter(\"jcache\");\n\n        CachingProvider provider =\n                StringUtils.isEmpty(type) ? Caching.getCachingProvider() : Caching.getCachingProvider(type);\n        CacheManager cacheManager = provider.getCacheManager();\n        Cache<Object, Object> cache = cacheManager.getCache(key);\n        if (cache == null) {\n            try {\n                // configure the cache\n                MutableConfiguration config = new MutableConfiguration<>()\n                        .setTypes(Object.class, Object.class)\n                        .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(\n                                TimeUnit.MILLISECONDS,\n                                url.getMethodParameter(method, \"cache.write.expire\", 60 * 1000))))\n                        .setStoreByValue(false)\n                        .setManagementEnabled(true)\n                        .setStatisticsEnabled(true);\n                cache = cacheManager.createCache(key, config);\n            } catch (CacheException e) {\n                // concurrent cache initialization\n                cache = cacheManager.getCache(key);\n            }\n        }\n\n        this.store = cache;\n    }\n\n    @Override\n    public void put(Object key, Object value) {\n        store.put(key, value);\n    }\n\n    @Override\n    public Object get(Object key) {\n        return store.get(key);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/jcache/JCacheFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.jcache;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.support.AbstractCacheFactory;\nimport org.apache.dubbo.common.URL;\n\nimport javax.cache.spi.CachingProvider;\n\n/**\n * JCacheFactory is factory class to provide instance of javax spi cache.Implement {@link org.apache.dubbo.cache.CacheFactory} by\n * extending {@link AbstractCacheFactory} and provide\n * @see AbstractCacheFactory\n * @see JCache\n * @see org.apache.dubbo.cache.filter.CacheFilter\n * @see Cache\n * @see CachingProvider\n * @see javax.cache.Cache\n * @see javax.cache.CacheManager\n */\npublic class JCacheFactory extends AbstractCacheFactory {\n\n    /**\n     * Takes url as an method argument and return new instance of cache store implemented by JCache.\n     * @param url url of the method\n     * @return JCache instance of cache\n     */\n    @Override\n    protected Cache createCache(URL url) {\n        return new JCache(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/lfu/LfuCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.lfu;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.LFUCache;\n\n/**\n * This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>\n * with value <b>lfu</b>, dubbo initialize the instance of this class using {@link LfuCacheFactory} to store method's returns value\n * to server from store without making method call.\n * <pre>\n *     e.g. 1) &lt;dubbo:service cache=\"lfu\" cache.size=\"5000\" cache.evictionFactor=\"0.3\"/&gt;\n *          2) &lt;dubbo:consumer cache=\"lfu\" /&gt;\n * </pre>\n * <pre>\n * LfuCache uses url's <b>cache.size</b> value for its max store size, url's <b>cache.evictionFactor</b> value for its eviction factor,\n * default store size value will be 1000, default eviction factor will be 0.3\n * </pre>\n *\n * @see Cache\n * @see LfuCacheFactory\n * @see org.apache.dubbo.cache.support.AbstractCacheFactory\n * @see org.apache.dubbo.cache.filter.CacheFilter\n */\npublic class LfuCache implements Cache {\n\n    /**\n     * This is used to store cache records\n     */\n    @SuppressWarnings(\"rawtypes\")\n    private final LFUCache store;\n\n    /**\n     *  Initialize LfuCache, it uses constructor argument <b>cache.size</b> value as its storage max size.\n     *  If nothing is provided then it will use 1000 as default size value. <b>cache.evictionFactor</b> value as its eviction factor.\n     *  If nothing is provided then it will use 0.3 as default value.\n     * @param url A valid URL instance\n     */\n    @SuppressWarnings(\"rawtypes\")\n    public LfuCache(URL url) {\n        final int max = url.getParameter(\"cache.size\", 1000);\n        final float factor = url.getParameter(\"cache.evictionFactor\", 0.75f);\n        this.store = new LFUCache(max, factor);\n    }\n\n    /**\n     * API to store value against a key in the calling thread scope.\n     * @param key  Unique identifier for the object being store.\n     * @param value Value getting store\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public void put(Object key, Object value) {\n        store.put(key, value);\n    }\n\n    /**\n     * API to return stored value using a key against the calling thread specific store.\n     * @param key Unique identifier for cache lookup\n     * @return Return stored object against key\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public Object get(Object key) {\n        return store.get(key);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/lfu/LfuCacheFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.lfu;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.support.AbstractCacheFactory;\nimport org.apache.dubbo.common.URL;\n\n/**\n * Implement {@link org.apache.dubbo.cache.CacheFactory} by extending {@link AbstractCacheFactory} and provide\n * instance of new {@link LfuCache}.\n *\n * @see AbstractCacheFactory\n * @see LfuCache\n * @see Cache\n */\npublic class LfuCacheFactory extends AbstractCacheFactory {\n\n    /**\n     * Takes url as an method argument and return new instance of cache store implemented by LfuCache.\n     * @param url url of the method\n     * @return ThreadLocalCache instance of cache\n     */\n    @Override\n    protected Cache createCache(URL url) {\n        return new LfuCache(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/lru/LruCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.lru;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.LRU2Cache;\n\nimport java.util.Map;\n\n/**\n * This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>\n * with value <b>lru</b>, dubbo initialize the instance of this class using {@link LruCacheFactory} to store method's returns value\n * to server from store without making method call.\n * <pre>\n *     e.g. 1) &lt;dubbo:service cache=\"lru\" cache.size=\"5000\"/&gt;\n *          2) &lt;dubbo:consumer cache=\"lru\" /&gt;\n * </pre>\n * <pre>\n * LruCache uses url's <b>cache.size</b> value for its max store size, if nothing is provided then\n * default value will be 1000\n * </pre>\n *\n * @see Cache\n * @see LruCacheFactory\n * @see org.apache.dubbo.cache.support.AbstractCacheFactory\n * @see org.apache.dubbo.cache.filter.CacheFilter\n */\npublic class LruCache implements Cache {\n\n    /**\n     * This is used to store cache records\n     */\n    private final Map<Object, Object> store;\n\n    /**\n     * Initialize LruCache, it uses constructor argument <b>cache.size</b> value as its storage max size.\n     *  If nothing is provided then it will use 1000 as default value.\n     * @param url A valid URL instance\n     */\n    public LruCache(URL url) {\n        final int max = url.getParameter(\"cache.size\", 1000);\n        this.store = new LRU2Cache<>(max);\n    }\n\n    /**\n     * API to store value against a key in the calling thread scope.\n     * @param key  Unique identifier for the object being store.\n     * @param value Value getting store\n     */\n    @Override\n    public void put(Object key, Object value) {\n        store.put(key, value);\n    }\n\n    /**\n     * API to return stored value using a key against the calling thread specific store.\n     * @param key Unique identifier for cache lookup\n     * @return Return stored object against key\n     */\n    @Override\n    public Object get(Object key) {\n        return store.get(key);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/lru/LruCacheFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.lru;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.support.AbstractCacheFactory;\nimport org.apache.dubbo.common.URL;\n\n/**\n * Implement {@link org.apache.dubbo.cache.CacheFactory} by extending {@link AbstractCacheFactory} and provide\n * instance of new {@link LruCache}.\n *\n * @see AbstractCacheFactory\n * @see LruCache\n * @see Cache\n */\npublic class LruCacheFactory extends AbstractCacheFactory {\n\n    /**\n     * Takes url as an method argument and return new instance of cache store implemented by LruCache.\n     * @param url url of the method\n     * @return ThreadLocalCache instance of cache\n     */\n    @Override\n    protected Cache createCache(URL url) {\n        return new LruCache(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/threadlocal/ThreadLocalCache.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.threadlocal;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.common.URL;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>\n * with value <b>threadlocal</b>, dubbo initialize the instance of this class using {@link ThreadLocalCacheFactory} to store method's returns value\n * to server from store without making method call.\n *  <pre>\n *      e.g. &lt;dubbo:service cache=\"threadlocal\" /&gt;\n *  </pre>\n * <pre>\n * As this ThreadLocalCache stores key-value in memory without any expiry or delete support per thread wise, if number threads and number of key-value are high then jvm should be\n * configured with appropriate memory.\n * </pre>\n *\n * @see org.apache.dubbo.cache.support.AbstractCacheFactory\n * @see org.apache.dubbo.cache.filter.CacheFilter\n * @see Cache\n */\npublic class ThreadLocalCache implements Cache {\n\n    /**\n     * Thread local variable to store cached data.\n     */\n    private final ThreadLocal<Map<Object, Object>> store;\n\n    /**\n     * Taken URL as an argument to create an instance of ThreadLocalCache. In this version of implementation constructor\n     * argument is not getting used in the scope of this class.\n     * @param url\n     */\n    public ThreadLocalCache(URL url) {\n        this.store = ThreadLocal.withInitial(HashMap::new);\n    }\n\n    /**\n     * API to store value against a key in the calling thread scope.\n     * @param key  Unique identifier for the object being store.\n     * @param value Value getting store\n     */\n    @Override\n    public void put(Object key, Object value) {\n        store.get().put(key, value);\n    }\n\n    /**\n     * API to return stored value using a key against the calling thread specific store.\n     * @param key Unique identifier for cache lookup\n     * @return Return stored object against key\n     */\n    @Override\n    public Object get(Object key) {\n        return store.get().get(key);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/java/org/apache/dubbo/cache/support/threadlocal/ThreadLocalCacheFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.threadlocal;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.support.AbstractCacheFactory;\nimport org.apache.dubbo.common.URL;\n\n/**\n * Implement {@link org.apache.dubbo.cache.CacheFactory} by extending {@link AbstractCacheFactory} and provide\n * instance of new {@link ThreadLocalCache}. Note about this class is, each thread does not have a local copy of factory.\n *\n * @see AbstractCacheFactory\n * @see ThreadLocalCache\n * @see Cache\n */\npublic class ThreadLocalCacheFactory extends AbstractCacheFactory {\n\n    /**\n     * Takes url as an method argument and return new instance of cache store implemented by ThreadLocalCache.\n     * @param url url of the method\n     * @return ThreadLocalCache instance of cache\n     */\n    @Override\n    protected Cache createCache(URL url) {\n        return new ThreadLocalCache(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory",
    "content": "threadlocal=org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory\nlru=org.apache.dubbo.cache.support.lru.LruCacheFactory\njcache=org.apache.dubbo.cache.support.jcache.JCacheFactory\nexpiring=org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory\nlfu=org.apache.dubbo.cache.support.lfu.LfuCacheFactory\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter",
    "content": "cache=org.apache.dubbo.cache.filter.CacheFilter"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/test/java/org/apache/dubbo/cache/filter/CacheFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.filter;\n\nimport org.apache.dubbo.cache.CacheFactory;\nimport org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory;\nimport org.apache.dubbo.cache.support.jcache.JCacheFactory;\nimport org.apache.dubbo.cache.support.lru.LruCacheFactory;\nimport org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcInvocation;\n\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\nclass CacheFilterTest {\n    private RpcInvocation invocation;\n    private CacheFilter cacheFilter = new CacheFilter();\n    private Invoker<?> invoker = mock(Invoker.class);\n    private Invoker<?> invoker1 = mock(Invoker.class);\n    private Invoker<?> invoker2 = mock(Invoker.class);\n    private Invoker<?> invoker3 = mock(Invoker.class);\n    private Invoker<?> invoker4 = mock(Invoker.class);\n\n    static Stream<Arguments> cacheFactories() {\n        return Stream.of(\n                Arguments.of(\"lru\", new LruCacheFactory()),\n                Arguments.of(\"jcache\", new JCacheFactory()),\n                Arguments.of(\"threadlocal\", new ThreadLocalCacheFactory()),\n                Arguments.of(\"expiring\", new ExpiringCacheFactory()));\n    }\n\n    public void setUp(String cacheType, CacheFactory cacheFactory) {\n        invocation = new RpcInvocation();\n        cacheFilter.setCacheFactory(cacheFactory);\n\n        URL url = URL.valueOf(\"test://test:11/test?cache=\" + cacheType);\n\n        given(invoker.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult(\"value\", invocation));\n        given(invoker.getUrl()).willReturn(url);\n\n        given(invoker1.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult(\"value1\", invocation));\n        given(invoker1.getUrl()).willReturn(url);\n\n        given(invoker2.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult(\"value2\", invocation));\n        given(invoker2.getUrl()).willReturn(url);\n\n        given(invoker3.invoke(invocation))\n                .willReturn(AsyncRpcResult.newDefaultAsyncResult(new RuntimeException(), invocation));\n        given(invoker3.getUrl()).willReturn(url);\n\n        given(invoker4.invoke(invocation)).willReturn(AsyncRpcResult.newDefaultAsyncResult(invocation));\n        given(invoker4.getUrl()).willReturn(url);\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"cacheFactories\")\n    public void testNonArgsMethod(String cacheType, CacheFactory cacheFactory) {\n        setUp(cacheType, cacheFactory);\n        invocation.setMethodName(\"echo\");\n        invocation.setParameterTypes(new Class<?>[] {});\n        invocation.setArguments(new Object[] {});\n\n        cacheFilter.invoke(invoker, invocation);\n        cacheFilter.invoke(invoker, invocation);\n        Result rpcResult1 = cacheFilter.invoke(invoker1, invocation);\n        Result rpcResult2 = cacheFilter.invoke(invoker2, invocation);\n        Assertions.assertEquals(rpcResult1.getValue(), rpcResult2.getValue());\n        Assertions.assertEquals(rpcResult1.getValue(), \"value\");\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"cacheFactories\")\n    public void testMethodWithArgs(String cacheType, CacheFactory cacheFactory) {\n        setUp(cacheType, cacheFactory);\n        invocation.setMethodName(\"echo1\");\n        invocation.setParameterTypes(new Class<?>[] {String.class});\n        invocation.setArguments(new Object[] {\"arg1\"});\n\n        cacheFilter.invoke(invoker, invocation);\n        cacheFilter.invoke(invoker, invocation);\n        Result rpcResult1 = cacheFilter.invoke(invoker1, invocation);\n        Result rpcResult2 = cacheFilter.invoke(invoker2, invocation);\n        Assertions.assertEquals(rpcResult1.getValue(), rpcResult2.getValue());\n        Assertions.assertEquals(rpcResult1.getValue(), \"value\");\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"cacheFactories\")\n    public void testException(String cacheType, CacheFactory cacheFactory) {\n        setUp(cacheType, cacheFactory);\n        invocation.setMethodName(\"echo1\");\n        invocation.setParameterTypes(new Class<?>[] {String.class});\n        invocation.setArguments(new Object[] {\"arg2\"});\n\n        cacheFilter.invoke(invoker3, invocation);\n        cacheFilter.invoke(invoker3, invocation);\n        Result rpcResult = cacheFilter.invoke(invoker2, invocation);\n        Assertions.assertEquals(rpcResult.getValue(), \"value2\");\n    }\n\n    @ParameterizedTest\n    @MethodSource(\"cacheFactories\")\n    public void testNull(String cacheType, CacheFactory cacheFactory) {\n        setUp(cacheType, cacheFactory);\n        invocation.setMethodName(\"echo1\");\n        invocation.setParameterTypes(new Class<?>[] {String.class});\n        invocation.setArguments(new Object[] {\"arg3\"});\n\n        cacheFilter.invoke(invoker4, invocation);\n        cacheFilter.invoke(invoker4, invocation);\n        Result result1 = cacheFilter.invoke(invoker1, invocation);\n        Result result2 = cacheFilter.invoke(invoker2, invocation);\n        Assertions.assertNull(result1.getValue());\n        Assertions.assertNull(result2.getValue());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/test/java/org/apache/dubbo/cache/support/AbstractCacheFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.RpcInvocation;\n\npublic abstract class AbstractCacheFactoryTest {\n\n    protected Cache constructCache() {\n        URL url = URL.valueOf(\"test://test:11/test?cache=lru\");\n        Invocation invocation = new RpcInvocation();\n        return getCacheFactory().getCache(url, invocation);\n    }\n\n    protected abstract AbstractCacheFactory getCacheFactory();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/test/java/org/apache/dubbo/cache/support/expiring/ExpiringCacheFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.expiring;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.support.AbstractCacheFactory;\nimport org.apache.dubbo.cache.support.AbstractCacheFactoryTest;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.RpcInvocation;\n\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass ExpiringCacheFactoryTest extends AbstractCacheFactoryTest {\n\n    private static final String EXPIRING_CACHE_URL =\n            \"test://test:12/test?cache=expiring&cache.seconds=1&cache.interval=1\";\n\n    @Test\n    void testExpiringCacheFactory() throws Exception {\n        Cache cache = super.constructCache();\n        assertThat(cache instanceof ExpiringCache, is(true));\n    }\n\n    @Test\n    void testExpiringCacheGetExpired() throws Exception {\n        URL url = URL.valueOf(\"test://test:12/test?cache=expiring&cache.seconds=1&cache.interval=1\");\n        AbstractCacheFactory cacheFactory = getCacheFactory();\n        Invocation invocation = new RpcInvocation();\n        Cache cache = cacheFactory.getCache(url, invocation);\n        cache.put(\"testKey\", \"testValue\");\n        Thread.sleep(2100);\n        assertNull(cache.get(\"testKey\"));\n    }\n\n    @Test\n    void testExpiringCacheUnExpired() throws Exception {\n        URL url = URL.valueOf(\"test://test:12/test?cache=expiring&cache.seconds=0&cache.interval=1\");\n        AbstractCacheFactory cacheFactory = getCacheFactory();\n        Invocation invocation = new RpcInvocation();\n        Cache cache = cacheFactory.getCache(url, invocation);\n        cache.put(\"testKey\", \"testValue\");\n        Thread.sleep(1100);\n        assertNotNull(cache.get(\"testKey\"));\n    }\n\n    @Test\n    void testExpiringCache() throws Exception {\n        Cache cache = constructCache();\n        assertThat(cache instanceof ExpiringCache, is(true));\n\n        // 500ms\n        TimeUnit.MILLISECONDS.sleep(500);\n        cache.put(\"testKey\", \"testValue\");\n        // 800ms\n        TimeUnit.MILLISECONDS.sleep(300);\n        assertNotNull(cache.get(\"testKey\"));\n        // 1300ms\n        TimeUnit.MILLISECONDS.sleep(500);\n        assertNotNull(cache.get(\"testKey\"));\n    }\n\n    @Test\n    void testExpiringCacheExpired() throws Exception {\n        Cache cache = constructCache();\n        assertThat(cache instanceof ExpiringCache, is(true));\n\n        // 500ms\n        TimeUnit.MILLISECONDS.sleep(500);\n        cache.put(\"testKey\", \"testValue\");\n        // 1000ms ExpireThread clear all expire cache\n        TimeUnit.MILLISECONDS.sleep(500);\n        // 1700ms  get should be null\n        TimeUnit.MILLISECONDS.sleep(700);\n        assertNull(cache.get(\"testKey\"));\n    }\n\n    @Override\n    protected Cache constructCache() {\n        URL url = URL.valueOf(EXPIRING_CACHE_URL);\n        Invocation invocation = new RpcInvocation();\n        return getCacheFactory().getCache(url, invocation);\n    }\n\n    @Override\n    protected AbstractCacheFactory getCacheFactory() {\n        return new ExpiringCacheFactory();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/test/java/org/apache/dubbo/cache/support/jcache/JCacheFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.jcache;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.support.AbstractCacheFactory;\nimport org.apache.dubbo.cache.support.AbstractCacheFactoryTest;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.RpcInvocation;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass JCacheFactoryTest extends AbstractCacheFactoryTest {\n\n    @Test\n    void testJCacheFactory() {\n        Cache cache = super.constructCache();\n        assertThat(cache instanceof JCache, is(true));\n    }\n\n    @Test\n    void testJCacheGetExpired() throws Exception {\n        URL url = URL.valueOf(\"test://test:12/test?cache=jacache&cache.write.expire=1\");\n        AbstractCacheFactory cacheFactory = getCacheFactory();\n        Invocation invocation = new RpcInvocation();\n        Cache cache = cacheFactory.getCache(url, invocation);\n        cache.put(\"testKey\", \"testValue\");\n        Thread.sleep(10);\n        assertNull(cache.get(\"testKey\"));\n    }\n\n    @Override\n    protected AbstractCacheFactory getCacheFactory() {\n        return new JCacheFactory();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/test/java/org/apache/dubbo/cache/support/lru/LruCacheFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.lru;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.support.AbstractCacheFactory;\nimport org.apache.dubbo.cache.support.AbstractCacheFactoryTest;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\n\nclass LruCacheFactoryTest extends AbstractCacheFactoryTest {\n    @Test\n    void testLruCacheFactory() throws Exception {\n        Cache cache = super.constructCache();\n        assertThat(cache instanceof LruCache, is(true));\n    }\n\n    @Override\n    protected AbstractCacheFactory getCacheFactory() {\n        return new LruCacheFactory();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/test/java/org/apache/dubbo/cache/support/threadlocal/ThreadLocalCacheFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.cache.support.threadlocal;\n\nimport org.apache.dubbo.cache.Cache;\nimport org.apache.dubbo.cache.support.AbstractCacheFactory;\nimport org.apache.dubbo.cache.support.AbstractCacheFactoryTest;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\n\nclass ThreadLocalCacheFactoryTest extends AbstractCacheFactoryTest {\n    @Test\n    void testThreadLocalCacheFactory() throws Exception {\n        Cache cache = super.constructCache();\n        assertThat(cache instanceof ThreadLocalCache, is(true));\n    }\n\n    @Override\n    protected AbstractCacheFactory getCacheFactory() {\n        return new ThreadLocalCacheFactory();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/test/resources/dubbo.properties",
    "content": "dubbo.application.enable-file-cache=false\ndubbo.service.shutdown.wait=200\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-cache/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-filter-validation</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The validation module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n    <el_api_version>2.2.5</el_api_version>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>jakarta.validation</groupId>\n      <artifactId>jakarta.validation-api</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>javax.validation</groupId>\n      <artifactId>validation-api</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.hibernate</groupId>\n      <artifactId>hibernate-validator</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>javax.el</groupId>\n      <artifactId>javax.el-api</artifactId>\n      <version>${el_api_version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>javax.xml.bind</groupId>\n      <artifactId>jaxb-api</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.sun.xml.bind</groupId>\n      <artifactId>jaxb-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.sun.xml.bind</groupId>\n      <artifactId>jaxb-core</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/MethodValidated.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Method grouping validation.\n * <p>\n * Scenario: this annotation can be used on interface's method when need to check against group before invoke the method\n * For example: <pre> @MethodValidated({Save.class, Update.class})\n * void relatedQuery(ValidationParameter parameter);\n * </pre>\n * It means both Save group and Update group are needed to check when method relatedQuery is invoked.\n * </p>\n */\n@Target({ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface MethodValidated {\n    Class<?>[] value() default {};\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/Validation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport static org.apache.dubbo.common.constants.FilterConstants.VALIDATION_KEY;\n\n/**\n * Instance of Validation interface provide instance of {@link Validator} based on the value of <b>validation</b> attribute.\n */\n@SPI(\"jvalidation\")\npublic interface Validation {\n\n    /**\n     * Return the instance of {@link Validator} for a given url.\n     * @param url Invocation url\n     * @return Instance of {@link Validator}\n     */\n    @Adaptive(VALIDATION_KEY)\n    Validator getValidator(URL url);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/Validator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation;\n\n/**\n * Instance of validator class is an extension to perform validation on method input parameter before the actual method invocation.\n *\n */\npublic interface Validator {\n\n    void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception;\n\n    boolean isSupport();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/filter/ValidationFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.filter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.rpc.AsyncRpcResult;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.validation.Validation;\nimport org.apache.dubbo.validation.Validator;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;\nimport static org.apache.dubbo.common.constants.FilterConstants.VALIDATION_KEY;\n\n/**\n * ValidationFilter invoke the validation by finding the right {@link Validator} instance based on the\n * configured <b>validation</b> attribute value of invoker url before the actual method invocation.\n *\n * <pre>\n *     e.g. &lt;dubbo:method name=\"save\" validation=\"jvalidation\" /&gt;\n *     In the above configuration a validation has been configured of type jvalidation. On invocation of method <b>save</b>\n *     dubbo will invoke {@link org.apache.dubbo.validation.support.jvalidation.JValidator}\n * </pre>\n * <p>\n * To add a new type of validation\n * <pre>\n *     e.g. &lt;dubbo:method name=\"save\" validation=\"special\" /&gt;\n *     where \"special\" is representing a validator for special character.\n * </pre>\n * <p>\n * developer needs to do\n * <br/>\n * 1)Implement a SpecialValidation.java class (package name xxx.yyy.zzz) either by implementing {@link Validation} or extending {@link org.apache.dubbo.validation.support.AbstractValidation} <br/>\n * 2)Implement a SpecialValidator.java class (package name xxx.yyy.zzz) <br/>\n * 3)Add an entry <b>special</b>=<b>xxx.yyy.zzz.SpecialValidation</b> under <b>META-INF folders org.apache.dubbo.validation.Validation file</b>.\n *\n * @see Validation\n * @see Validator\n * @see Filter\n * @see org.apache.dubbo.validation.support.AbstractValidation\n */\n@Activate(\n        group = {CONSUMER, PROVIDER},\n        value = VALIDATION_KEY,\n        order = 10000)\npublic class ValidationFilter implements Filter {\n\n    private Validation validation;\n\n    /**\n     * Sets the validation instance for ValidationFilter\n     *\n     * @param validation Validation instance injected by dubbo framework based on \"validation\" attribute value.\n     */\n    public void setValidation(Validation validation) {\n        this.validation = validation;\n    }\n\n    /**\n     * Perform the validation of before invoking the actual method based on <b>validation</b> attribute value.\n     *\n     * @param invoker    service\n     * @param invocation invocation.\n     * @return Method invocation result\n     * @throws RpcException Throws RpcException if  validation failed or any other runtime exception occurred.\n     */\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        if (needValidate(invoker.getUrl(), invocation.getMethodName())) {\n            try {\n                Validator validator = validation.getValidator(invoker.getUrl());\n                if (validator != null) {\n                    validator.validate(\n                            invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());\n                }\n            } catch (RpcException e) {\n                throw e;\n            } catch (Throwable t) {\n                return AsyncRpcResult.newDefaultAsyncResult(t, invocation);\n            }\n        }\n        return invoker.invoke(invocation);\n    }\n\n    private boolean needValidate(URL url, String methodName) {\n        return validation != null\n                && !methodName.startsWith(\"$\")\n                && ConfigUtils.isNotEmpty(url.getMethodParameter(methodName, VALIDATION_KEY))\n                && !\"false\".equalsIgnoreCase(url.getParameter(VALIDATION_KEY));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/AbstractValidation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.validation.Validation;\nimport org.apache.dubbo.validation.Validator;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * AbstractValidation is abstract class for Validation interface. It helps low level Validation implementation classes\n * by performing common task e.g. key formation, storing instance of validation class to avoid creation of unnecessary\n * copy of validation instance and faster execution.\n *\n * @see Validation\n * @see Validator\n */\npublic abstract class AbstractValidation implements Validation {\n\n    private final ConcurrentMap<String, Validator> validators = new ConcurrentHashMap<>();\n\n    @Override\n    public Validator getValidator(URL url) {\n        String key = url.toFullString();\n        Validator validator = validators.get(key);\n        if (validator == null) {\n            validators.put(key, createValidator(url));\n            validator = validators.get(key);\n        }\n        return validator;\n    }\n\n    protected abstract Validator createValidator(URL url);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/AdapterValidation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.support.jvalidation;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.validation.Validator;\nimport org.apache.dubbo.validation.support.AbstractValidation;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class AdapterValidation extends AbstractValidation {\n\n    @Override\n    protected Validator createValidator(URL url) {\n        List<Class<? extends Validator>> validatorList = Arrays.asList(JValidator.class, JValidatorNew.class);\n        for (Class<? extends Validator> instance : validatorList) {\n            try {\n                Validator validator = instance.getConstructor(URL.class).newInstance(url);\n                if (validator.isSupport()) {\n                    return validator;\n                }\n            } catch (Throwable ignore) {\n            }\n        }\n        throw new IllegalArgumentException(\n                \"Failed to load jakarta.validation.Validation or javax.validation.Validation from env. \"\n                        + \"Please import at least one validator\");\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.support.jvalidation;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.validation.Validator;\nimport org.apache.dubbo.validation.support.AbstractValidation;\n\n/**\n * Creates a new instance of {@link Validator} using input argument url.\n * @see AbstractValidation\n * @see Validator\n */\n@Activate(onClass = \"javax.validation.Validation\")\npublic class JValidation extends AbstractValidation {\n\n    /**\n     * Return new instance of {@link JValidator}\n     * @param url Valid URL instance\n     * @return Instance of JValidator\n     */\n    @Override\n    protected Validator createValidator(URL url) {\n        return new JValidator(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidationNew.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.support.jvalidation;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.validation.Validator;\nimport org.apache.dubbo.validation.support.AbstractValidation;\n\n/**\n * Creates a new instance of {@link Validator} using input argument url.\n * @see AbstractValidation\n * @see Validator\n */\n@Activate(onClass = \"jakarta.validation.Validation\")\npublic class JValidationNew extends AbstractValidation {\n\n    /**\n     * Return new instance of {@link JValidator}\n     * @param url Valid URL instance\n     * @return Instance of JValidator\n     */\n    @Override\n    protected Validator createValidator(URL url) {\n        return new JValidatorNew(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.support.jvalidation;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.bytecode.ClassGenerator;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.validation.MethodValidated;\nimport org.apache.dubbo.validation.Validator;\n\nimport javax.validation.Constraint;\nimport javax.validation.ConstraintViolation;\nimport javax.validation.ConstraintViolationException;\nimport javax.validation.MessageInterpolator;\nimport javax.validation.Validation;\nimport javax.validation.ValidatorFactory;\nimport javax.validation.groups.Default;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Parameter;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport javassist.ClassPool;\nimport javassist.CtClass;\nimport javassist.CtField;\nimport javassist.CtNewConstructor;\nimport javassist.Modifier;\nimport javassist.NotFoundException;\nimport javassist.bytecode.AnnotationsAttribute;\nimport javassist.bytecode.ClassFile;\nimport javassist.bytecode.ConstPool;\nimport javassist.bytecode.annotation.ArrayMemberValue;\nimport javassist.bytecode.annotation.BooleanMemberValue;\nimport javassist.bytecode.annotation.ByteMemberValue;\nimport javassist.bytecode.annotation.CharMemberValue;\nimport javassist.bytecode.annotation.ClassMemberValue;\nimport javassist.bytecode.annotation.DoubleMemberValue;\nimport javassist.bytecode.annotation.EnumMemberValue;\nimport javassist.bytecode.annotation.FloatMemberValue;\nimport javassist.bytecode.annotation.IntegerMemberValue;\nimport javassist.bytecode.annotation.LongMemberValue;\nimport javassist.bytecode.annotation.MemberValue;\nimport javassist.bytecode.annotation.ShortMemberValue;\nimport javassist.bytecode.annotation.StringMemberValue;\n\nimport org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FILTER_VALIDATION_EXCEPTION;\n\n/**\n * Implementation of JValidation. JValidation is invoked if configuration validation attribute value is 'jvalidation'.\n * <pre>\n *     e.g. &lt;dubbo:method name=\"save\" validation=\"jvalidation\" /&gt;\n * </pre>\n */\npublic class JValidator implements Validator {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(JValidator.class);\n\n    private final Class<?> clazz;\n\n    private final Map<String, Class<?>> methodClassMap;\n\n    private final javax.validation.Validator validator;\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public JValidator(URL url) {\n        this.clazz = ReflectUtils.forName(url.getServiceInterface());\n        String jvalidation = url.getParameter(\"jvalidation\");\n        ValidatorFactory factory;\n        if (StringUtils.isNotEmpty(jvalidation)) {\n            factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation))\n                    .configure()\n                    .buildValidatorFactory();\n        } else {\n            MessageInterpolator messageInterpolator = new ParameterMessageInterpolator();\n            factory = Validation.byDefaultProvider()\n                    .configure()\n                    .messageInterpolator(messageInterpolator)\n                    .buildValidatorFactory();\n        }\n        this.validator = factory.getValidator();\n        this.methodClassMap = new ConcurrentHashMap<>();\n    }\n\n    private static Object getMethodParameterBean(Class<?> clazz, Method method, Object[] args) {\n        if (!hasConstraintParameter(method)) {\n            return null;\n        }\n        try {\n            String parameterClassName = generateMethodParameterClassName(clazz, method);\n            Class<?> parameterClass;\n            try {\n                parameterClass = Class.forName(parameterClassName, true, clazz.getClassLoader());\n            } catch (ClassNotFoundException e) {\n                parameterClass = generateMethodParameterClass(clazz, method, parameterClassName);\n            }\n            Object parameterBean = parameterClass.getDeclaredConstructor().newInstance();\n            Parameter[] parameters = method.getParameters();\n            for (int i = 0; i < parameters.length; i++) {\n                Field field = parameterClass.getField(parameters[i].getName());\n                field.set(parameterBean, args[i]);\n            }\n            return parameterBean;\n        } catch (Throwable e) {\n            logger.warn(CONFIG_FILTER_VALIDATION_EXCEPTION, \"\", \"\", e.getMessage(), e);\n            return null;\n        }\n    }\n\n    /**\n     * try to generate methodParameterClass.\n     *\n     * @param clazz              interface class\n     * @param method             invoke method\n     * @param parameterClassName generated parameterClassName\n     * @return Class<?> generated methodParameterClass\n     */\n    private static Class<?> generateMethodParameterClass(Class<?> clazz, Method method, String parameterClassName)\n            throws Exception {\n        ClassPool pool = ClassGenerator.getClassPool(clazz.getClassLoader());\n        synchronized (parameterClassName.intern()) {\n            CtClass ctClass = null;\n            try {\n                ctClass = pool.getCtClass(parameterClassName);\n            } catch (NotFoundException ignore) {\n            }\n\n            if (null == ctClass) {\n                ctClass = pool.makeClass(parameterClassName);\n                ClassFile classFile = ctClass.getClassFile();\n                ctClass.addConstructor(CtNewConstructor.defaultConstructor(pool.getCtClass(parameterClassName)));\n                // parameter fields\n                Parameter[] parameters = method.getParameters();\n                Annotation[][] parameterAnnotations = method.getParameterAnnotations();\n                for (int i = 0; i < parameters.length; i++) {\n                    Annotation[] annotations = parameterAnnotations[i];\n                    AnnotationsAttribute attribute =\n                            new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag);\n                    for (Annotation annotation : annotations) {\n                        if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {\n                            javassist.bytecode.annotation.Annotation ja = new javassist.bytecode.annotation.Annotation(\n                                    classFile.getConstPool(),\n                                    pool.getCtClass(annotation.annotationType().getName()));\n                            Method[] members = annotation.annotationType().getMethods();\n                            for (Method member : members) {\n                                if (Modifier.isPublic(member.getModifiers())\n                                        && member.getParameterTypes().length == 0\n                                        && member.getDeclaringClass() == annotation.annotationType()) {\n                                    Object value = member.invoke(annotation);\n                                    if (null != value) {\n                                        MemberValue memberValue = createMemberValue(\n                                                classFile.getConstPool(),\n                                                pool.get(member.getReturnType().getName()),\n                                                value);\n                                        ja.addMemberValue(member.getName(), memberValue);\n                                    }\n                                }\n                            }\n                            attribute.addAnnotation(ja);\n                        }\n                    }\n                    Parameter parameter = parameters[i];\n                    Class<?> type = parameter.getType();\n                    String fieldName = parameter.getName();\n                    CtField ctField = CtField.make(\n                            \"public \" + type.getCanonicalName() + \" \" + fieldName + \";\",\n                            pool.getCtClass(parameterClassName));\n                    ctField.getFieldInfo().addAttribute(attribute);\n                    ctClass.addField(ctField);\n                }\n                return pool.toClass(ctClass, clazz, clazz.getClassLoader(), clazz.getProtectionDomain());\n            } else {\n                return Class.forName(parameterClassName, true, clazz.getClassLoader());\n            }\n        }\n    }\n\n    private static String generateMethodParameterClassName(Class<?> clazz, Method method) {\n        StringBuilder builder = new StringBuilder()\n                .append(clazz.getName())\n                .append('_')\n                .append(toUpperMethodName(method.getName()))\n                .append(\"Parameter\");\n\n        Class<?>[] parameterTypes = method.getParameterTypes();\n        for (Class<?> parameterType : parameterTypes) {\n            // In order to ensure that the parameter class can be generated correctly,\n            // replace \".\" with \"_\" to make the package name of the generated parameter class\n            // consistent with the package name of the actual parameter class.\n            builder.append('_').append(parameterType.getName().replace(\".\", \"_\"));\n        }\n\n        return builder.toString();\n    }\n\n    private static boolean hasConstraintParameter(Method method) {\n        Annotation[][] parameterAnnotations = method.getParameterAnnotations();\n        for (Annotation[] annotations : parameterAnnotations) {\n            for (Annotation annotation : annotations) {\n                if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    private static String toUpperMethodName(String methodName) {\n        return methodName.substring(0, 1).toUpperCase() + methodName.substring(1);\n    }\n\n    // Copy from javassist.bytecode.annotation.Annotation.createMemberValue(ConstPool, CtClass);\n    private static MemberValue createMemberValue(ConstPool cp, CtClass type, Object value) throws NotFoundException {\n        MemberValue memberValue = javassist.bytecode.annotation.Annotation.createMemberValue(cp, type);\n        if (memberValue instanceof BooleanMemberValue) {\n            ((BooleanMemberValue) memberValue).setValue((Boolean) value);\n        } else if (memberValue instanceof ByteMemberValue) {\n            ((ByteMemberValue) memberValue).setValue((Byte) value);\n        } else if (memberValue instanceof CharMemberValue) {\n            ((CharMemberValue) memberValue).setValue((Character) value);\n        } else if (memberValue instanceof ShortMemberValue) {\n            ((ShortMemberValue) memberValue).setValue((Short) value);\n        } else if (memberValue instanceof IntegerMemberValue) {\n            ((IntegerMemberValue) memberValue).setValue((Integer) value);\n        } else if (memberValue instanceof LongMemberValue) {\n            ((LongMemberValue) memberValue).setValue((Long) value);\n        } else if (memberValue instanceof FloatMemberValue) {\n            ((FloatMemberValue) memberValue).setValue((Float) value);\n        } else if (memberValue instanceof DoubleMemberValue) {\n            ((DoubleMemberValue) memberValue).setValue((Double) value);\n        } else if (memberValue instanceof ClassMemberValue) {\n            ((ClassMemberValue) memberValue).setValue(((Class<?>) value).getName());\n        } else if (memberValue instanceof StringMemberValue) {\n            ((StringMemberValue) memberValue).setValue((String) value);\n        } else if (memberValue instanceof EnumMemberValue) {\n            ((EnumMemberValue) memberValue).setValue(((Enum<?>) value).name());\n        }\n        /* else if (memberValue instanceof AnnotationMemberValue) */\n        else if (memberValue instanceof ArrayMemberValue) {\n            CtClass arrayType = type.getComponentType();\n            int len = Array.getLength(value);\n            MemberValue[] members = new MemberValue[len];\n            for (int i = 0; i < len; i++) {\n                members[i] = createMemberValue(cp, arrayType, Array.get(value, i));\n            }\n            ((ArrayMemberValue) memberValue).setValue(members);\n        }\n        return memberValue;\n    }\n\n    @Override\n    public void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception {\n        List<Class<?>> groups = new ArrayList<>();\n        Class<?> methodClass = methodClass(methodName);\n        if (methodClass != null) {\n            groups.add(methodClass);\n        }\n\n        Method method = clazz.getMethod(methodName, parameterTypes);\n        Class<?>[] methodClasses;\n        if (method.isAnnotationPresent(MethodValidated.class)) {\n            methodClasses = method.getAnnotation(MethodValidated.class).value();\n            groups.addAll(Arrays.asList(methodClasses));\n        }\n        // add into default group\n        groups.add(0, Default.class);\n        groups.add(1, clazz);\n\n        // convert list to array\n        Class<?>[] classGroups = groups.toArray(new Class[0]);\n\n        Set<ConstraintViolation<?>> violations = new HashSet<>();\n        Object parameterBean = getMethodParameterBean(clazz, method, arguments);\n        if (parameterBean != null) {\n            violations.addAll(validator.validate(parameterBean, classGroups));\n        }\n\n        for (Object arg : arguments) {\n            validate(violations, arg, classGroups);\n        }\n\n        if (!violations.isEmpty()) {\n            logger.info(\"Failed to validate service: \" + clazz.getName() + \", method: \" + methodName + \", cause: \"\n                    + violations);\n            throw new ConstraintViolationException(\n                    \"Failed to validate service: \" + clazz.getName() + \", method: \" + methodName + \", cause: \"\n                            + violations,\n                    violations);\n        }\n    }\n\n    @Override\n    public boolean isSupport() {\n        Class<?> cls = null;\n        try {\n            cls = javax.validation.Validation.class;\n        } catch (Throwable ignore) {\n        }\n        return cls != null;\n    }\n\n    private Class<?> methodClass(String methodName) {\n        Class<?> methodClass = null;\n        String methodClassName = clazz.getName() + \"$\" + toUpperMethodName(methodName);\n        Class<?> cached = methodClassMap.get(methodClassName);\n        if (cached != null) {\n            return cached == clazz ? null : cached;\n        }\n        try {\n            methodClass =\n                    Class.forName(methodClassName, false, Thread.currentThread().getContextClassLoader());\n            methodClassMap.put(methodClassName, methodClass);\n        } catch (ClassNotFoundException e) {\n            methodClassMap.put(methodClassName, clazz);\n        }\n        return methodClass;\n    }\n\n    private void validate(Set<ConstraintViolation<?>> violations, Object arg, Class<?>... groups) {\n        if (arg != null && !ReflectUtils.isPrimitives(arg.getClass())) {\n            if (arg instanceof Object[]) {\n                for (Object item : (Object[]) arg) {\n                    validate(violations, item, groups);\n                }\n            } else if (arg instanceof Collection) {\n                for (Object item : (Collection<?>) arg) {\n                    validate(violations, item, groups);\n                }\n            } else if (arg instanceof Map) {\n                for (Map.Entry<?, ?> entry : ((Map<?, ?>) arg).entrySet()) {\n                    validate(violations, entry.getKey(), groups);\n                    validate(violations, entry.getValue(), groups);\n                }\n            } else {\n                violations.addAll(validator.validate(arg, groups));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/java/org/apache/dubbo/validation/support/jvalidation/JValidatorNew.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.support.jvalidation;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.bytecode.ClassGenerator;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.validation.MethodValidated;\nimport org.apache.dubbo.validation.Validator;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Parameter;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport javassist.ClassPool;\nimport javassist.CtClass;\nimport javassist.CtField;\nimport javassist.CtNewConstructor;\nimport javassist.Modifier;\nimport javassist.NotFoundException;\nimport javassist.bytecode.AnnotationsAttribute;\nimport javassist.bytecode.ClassFile;\nimport javassist.bytecode.ConstPool;\nimport javassist.bytecode.annotation.ArrayMemberValue;\nimport javassist.bytecode.annotation.BooleanMemberValue;\nimport javassist.bytecode.annotation.ByteMemberValue;\nimport javassist.bytecode.annotation.CharMemberValue;\nimport javassist.bytecode.annotation.ClassMemberValue;\nimport javassist.bytecode.annotation.DoubleMemberValue;\nimport javassist.bytecode.annotation.EnumMemberValue;\nimport javassist.bytecode.annotation.FloatMemberValue;\nimport javassist.bytecode.annotation.IntegerMemberValue;\nimport javassist.bytecode.annotation.LongMemberValue;\nimport javassist.bytecode.annotation.MemberValue;\nimport javassist.bytecode.annotation.ShortMemberValue;\nimport javassist.bytecode.annotation.StringMemberValue;\n\nimport jakarta.validation.Constraint;\nimport jakarta.validation.ConstraintViolation;\nimport jakarta.validation.ConstraintViolationException;\nimport jakarta.validation.Validation;\nimport jakarta.validation.ValidatorFactory;\nimport jakarta.validation.groups.Default;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FILTER_VALIDATION_EXCEPTION;\n\n/**\n * Implementation of JValidationNew. JValidationNew is invoked if configuration validation attribute value is 'jvalidationNew'.\n * <pre>\n *     e.g. &lt;dubbo:method name=\"save\" validation=\"jvalidationNew\" /&gt;\n * </pre>\n */\npublic class JValidatorNew implements Validator {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(JValidatorNew.class);\n\n    private final Class<?> clazz;\n\n    private final Map<String, Class<?>> methodClassMap;\n\n    private final jakarta.validation.Validator validator;\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public JValidatorNew(URL url) {\n        this.clazz = ReflectUtils.forName(url.getServiceInterface());\n        String jvalidation = url.getParameter(\"jvalidationNew\");\n        ValidatorFactory factory;\n        if (StringUtils.isNotEmpty(jvalidation)) {\n            factory = Validation.byProvider((Class) ReflectUtils.forName(jvalidation))\n                    .configure()\n                    .buildValidatorFactory();\n        } else {\n            factory = Validation.buildDefaultValidatorFactory();\n        }\n        this.validator = factory.getValidator();\n        this.methodClassMap = new ConcurrentHashMap<>();\n    }\n\n    private static Object getMethodParameterBean(Class<?> clazz, Method method, Object[] args) {\n        if (!hasConstraintParameter(method)) {\n            return null;\n        }\n        try {\n            String parameterClassName = generateMethodParameterClassName(clazz, method);\n            Class<?> parameterClass;\n            try {\n                parameterClass = Class.forName(parameterClassName, true, clazz.getClassLoader());\n            } catch (ClassNotFoundException e) {\n                parameterClass = generateMethodParameterClass(clazz, method, parameterClassName);\n            }\n            Object parameterBean = parameterClass.getDeclaredConstructor().newInstance();\n            Parameter[] parameters = method.getParameters();\n            for (int i = 0; i < parameters.length; i++) {\n                Field field = parameterClass.getField(parameters[i].getName());\n                field.set(parameterBean, args[i]);\n            }\n            return parameterBean;\n        } catch (Throwable e) {\n            logger.warn(CONFIG_FILTER_VALIDATION_EXCEPTION, \"\", \"\", e.getMessage(), e);\n            return null;\n        }\n    }\n\n    /**\n     * try to generate methodParameterClass.\n     *\n     * @param clazz              interface class\n     * @param method             invoke method\n     * @param parameterClassName generated parameterClassName\n     * @return Class<?> generated methodParameterClass\n     */\n    private static Class<?> generateMethodParameterClass(Class<?> clazz, Method method, String parameterClassName)\n            throws Exception {\n        ClassPool pool = ClassGenerator.getClassPool(clazz.getClassLoader());\n        synchronized (parameterClassName.intern()) {\n            CtClass ctClass = null;\n            try {\n                ctClass = pool.getCtClass(parameterClassName);\n            } catch (NotFoundException ignore) {\n            }\n\n            if (null == ctClass) {\n                ctClass = pool.makeClass(parameterClassName);\n                ClassFile classFile = ctClass.getClassFile();\n                ctClass.addConstructor(CtNewConstructor.defaultConstructor(pool.getCtClass(parameterClassName)));\n                // parameter fields\n                Parameter[] parameters = method.getParameters();\n                Annotation[][] parameterAnnotations = method.getParameterAnnotations();\n                for (int i = 0; i < parameters.length; i++) {\n                    Annotation[] annotations = parameterAnnotations[i];\n                    AnnotationsAttribute attribute =\n                            new AnnotationsAttribute(classFile.getConstPool(), AnnotationsAttribute.visibleTag);\n                    for (Annotation annotation : annotations) {\n                        if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {\n                            javassist.bytecode.annotation.Annotation ja = new javassist.bytecode.annotation.Annotation(\n                                    classFile.getConstPool(),\n                                    pool.getCtClass(annotation.annotationType().getName()));\n                            Method[] members = annotation.annotationType().getMethods();\n                            for (Method member : members) {\n                                if (Modifier.isPublic(member.getModifiers())\n                                        && member.getParameterTypes().length == 0\n                                        && member.getDeclaringClass() == annotation.annotationType()) {\n                                    Object value = member.invoke(annotation);\n                                    if (null != value) {\n                                        MemberValue memberValue = createMemberValue(\n                                                classFile.getConstPool(),\n                                                pool.get(member.getReturnType().getName()),\n                                                value);\n                                        ja.addMemberValue(member.getName(), memberValue);\n                                    }\n                                }\n                            }\n                            attribute.addAnnotation(ja);\n                        }\n                    }\n                    Parameter parameter = parameters[i];\n                    Class<?> type = parameter.getType();\n                    String fieldName = parameter.getName();\n                    CtField ctField = CtField.make(\n                            \"public \" + type.getCanonicalName() + \" \" + fieldName + \";\",\n                            pool.getCtClass(parameterClassName));\n                    ctField.getFieldInfo().addAttribute(attribute);\n                    ctClass.addField(ctField);\n                }\n                return pool.toClass(ctClass, clazz, clazz.getClassLoader(), clazz.getProtectionDomain());\n            } else {\n                return Class.forName(parameterClassName, true, clazz.getClassLoader());\n            }\n        }\n    }\n\n    private static String generateMethodParameterClassName(Class<?> clazz, Method method) {\n        StringBuilder builder = new StringBuilder()\n                .append(clazz.getName())\n                .append('_')\n                .append(toUpperMethodName(method.getName()))\n                .append(\"Parameter\");\n\n        Class<?>[] parameterTypes = method.getParameterTypes();\n        for (Class<?> parameterType : parameterTypes) {\n            // In order to ensure that the parameter class can be generated correctly,\n            // replace \".\" with \"_\" to make the package name of the generated parameter class\n            // consistent with the package name of the actual parameter class.\n            builder.append('_').append(parameterType.getName().replace(\".\", \"_\"));\n        }\n\n        return builder.toString();\n    }\n\n    private static boolean hasConstraintParameter(Method method) {\n        Annotation[][] parameterAnnotations = method.getParameterAnnotations();\n        for (Annotation[] annotations : parameterAnnotations) {\n            for (Annotation annotation : annotations) {\n                if (annotation.annotationType().isAnnotationPresent(Constraint.class)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    private static String toUpperMethodName(String methodName) {\n        return methodName.substring(0, 1).toUpperCase() + methodName.substring(1);\n    }\n\n    // Copy from javassist.bytecode.annotation.Annotation.createMemberValue(ConstPool, CtClass);\n    private static MemberValue createMemberValue(ConstPool cp, CtClass type, Object value) throws NotFoundException {\n        MemberValue memberValue = javassist.bytecode.annotation.Annotation.createMemberValue(cp, type);\n        if (memberValue instanceof BooleanMemberValue) {\n            ((BooleanMemberValue) memberValue).setValue((Boolean) value);\n        } else if (memberValue instanceof ByteMemberValue) {\n            ((ByteMemberValue) memberValue).setValue((Byte) value);\n        } else if (memberValue instanceof CharMemberValue) {\n            ((CharMemberValue) memberValue).setValue((Character) value);\n        } else if (memberValue instanceof ShortMemberValue) {\n            ((ShortMemberValue) memberValue).setValue((Short) value);\n        } else if (memberValue instanceof IntegerMemberValue) {\n            ((IntegerMemberValue) memberValue).setValue((Integer) value);\n        } else if (memberValue instanceof LongMemberValue) {\n            ((LongMemberValue) memberValue).setValue((Long) value);\n        } else if (memberValue instanceof FloatMemberValue) {\n            ((FloatMemberValue) memberValue).setValue((Float) value);\n        } else if (memberValue instanceof DoubleMemberValue) {\n            ((DoubleMemberValue) memberValue).setValue((Double) value);\n        } else if (memberValue instanceof ClassMemberValue) {\n            ((ClassMemberValue) memberValue).setValue(((Class<?>) value).getName());\n        } else if (memberValue instanceof StringMemberValue) {\n            ((StringMemberValue) memberValue).setValue((String) value);\n        } else if (memberValue instanceof EnumMemberValue) {\n            ((EnumMemberValue) memberValue).setValue(((Enum<?>) value).name());\n        }\n        /* else if (memberValue instanceof AnnotationMemberValue) */\n        else if (memberValue instanceof ArrayMemberValue) {\n            CtClass arrayType = type.getComponentType();\n            int len = Array.getLength(value);\n            MemberValue[] members = new MemberValue[len];\n            for (int i = 0; i < len; i++) {\n                members[i] = createMemberValue(cp, arrayType, Array.get(value, i));\n            }\n            ((ArrayMemberValue) memberValue).setValue(members);\n        }\n        return memberValue;\n    }\n\n    @Override\n    public void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception {\n        List<Class<?>> groups = new ArrayList<>();\n        Class<?> methodClass = methodClass(methodName);\n        if (methodClass != null) {\n            groups.add(methodClass);\n        }\n\n        Method method = clazz.getMethod(methodName, parameterTypes);\n        Class<?>[] methodClasses;\n        if (method.isAnnotationPresent(MethodValidated.class)) {\n            methodClasses = method.getAnnotation(MethodValidated.class).value();\n            groups.addAll(Arrays.asList(methodClasses));\n        }\n        // add into default group\n        groups.add(0, Default.class);\n        groups.add(1, clazz);\n\n        // convert list to array\n        Class<?>[] classGroups = groups.toArray(new Class[0]);\n\n        Set<ConstraintViolation<?>> violations = new HashSet<>();\n        Object parameterBean = getMethodParameterBean(clazz, method, arguments);\n        if (parameterBean != null) {\n            violations.addAll(validator.validate(parameterBean, classGroups));\n        }\n\n        for (Object arg : arguments) {\n            validate(violations, arg, classGroups);\n        }\n\n        if (!violations.isEmpty()) {\n            logger.info(\"Failed to validate service: \" + clazz.getName() + \", method: \" + methodName + \", cause: \"\n                    + violations);\n            throw new ConstraintViolationException(\n                    \"Failed to validate service: \" + clazz.getName() + \", method: \" + methodName + \", cause: \"\n                            + violations,\n                    violations);\n        }\n    }\n\n    @Override\n    public boolean isSupport() {\n        Class<?> cls = null;\n        try {\n            cls = jakarta.validation.Validation.class;\n        } catch (Throwable ignore) {\n        }\n        return cls != null;\n    }\n\n    private Class<?> methodClass(String methodName) {\n        Class<?> methodClass = null;\n        String methodClassName = clazz.getName() + \"$\" + toUpperMethodName(methodName);\n        Class<?> cached = methodClassMap.get(methodClassName);\n        if (cached != null) {\n            return cached == clazz ? null : cached;\n        }\n        try {\n            methodClass =\n                    Class.forName(methodClassName, false, Thread.currentThread().getContextClassLoader());\n            methodClassMap.put(methodClassName, methodClass);\n        } catch (ClassNotFoundException e) {\n            methodClassMap.put(methodClassName, clazz);\n        }\n        return methodClass;\n    }\n\n    private void validate(Set<ConstraintViolation<?>> violations, Object arg, Class<?>... groups) {\n        if (arg != null && !ReflectUtils.isPrimitives(arg.getClass())) {\n            if (arg instanceof Object[]) {\n                for (Object item : (Object[]) arg) {\n                    validate(violations, item, groups);\n                }\n            } else if (arg instanceof Collection) {\n                for (Object item : (Collection<?>) arg) {\n                    validate(violations, item, groups);\n                }\n            } else if (arg instanceof Map) {\n                for (Map.Entry<?, ?> entry : ((Map<?, ?>) arg).entrySet()) {\n                    validate(violations, entry.getKey(), groups);\n                    validate(violations, entry.getValue(), groups);\n                }\n            } else {\n                violations.addAll(validator.validate(arg, groups));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter",
    "content": "validation=org.apache.dubbo.validation.filter.ValidationFilter"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.validation.Validation",
    "content": "jvalidation=org.apache.dubbo.validation.support.jvalidation.AdapterValidation\njvalidationNew=org.apache.dubbo.validation.support.jvalidation.AdapterValidation\njvalidation-javax=org.apache.dubbo.validation.support.jvalidation.JValidation\njvalidation-jakarta=org.apache.dubbo.validation.support.jvalidation.JValidationNew\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/filter/ValidationFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.filter;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.validation.Validation;\nimport org.apache.dubbo.validation.Validator;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\nclass ValidationFilterTest {\n    private Invoker<?> invoker = mock(Invoker.class);\n    private Validation validation = mock(Validation.class);\n    private Validator validator = mock(Validator.class);\n    private RpcInvocation invocation = mock(RpcInvocation.class);\n\n    private ValidationFilter validationFilter;\n\n    @BeforeEach\n    public void setUp() {\n        this.validationFilter = new ValidationFilter();\n    }\n\n    @Test\n    void testItWithNotExistClass() {\n        URL url = URL.valueOf(\"test://test:11/test?validation=true\");\n\n        given(validation.getValidator(url)).willThrow(new IllegalStateException(\"Not found class test, cause: test\"));\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n        given(invoker.getUrl()).willReturn(url);\n        given(invocation.getMethodName()).willReturn(\"echo1\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {String.class});\n        given(invocation.getArguments()).willReturn(new Object[] {\"arg1\"});\n\n        validationFilter.setValidation(validation);\n        Result result = validationFilter.invoke(invoker, invocation);\n\n        assertThat(result.getException().getMessage(), is(\"Not found class test, cause: test\"));\n    }\n\n    @Test\n    void testItWithExistClass() {\n        URL url = URL.valueOf(\"test://test:11/test?validation=true\");\n\n        given(validation.getValidator(url)).willReturn(validator);\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n        given(invoker.getUrl()).willReturn(url);\n        given(invocation.getMethodName()).willReturn(\"echo1\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {String.class});\n        given(invocation.getArguments()).willReturn(new Object[] {\"arg1\"});\n\n        validationFilter.setValidation(validation);\n        Result result = validationFilter.invoke(invoker, invocation);\n\n        assertThat(String.valueOf(result.getValue()), is(\"success\"));\n    }\n\n    @Test\n    void testItWithoutUrlParameters() {\n        URL url = URL.valueOf(\"test://test:11/test\");\n\n        given(validation.getValidator(url)).willReturn(validator);\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n        given(invoker.getUrl()).willReturn(url);\n        given(invocation.getMethodName()).willReturn(\"echo1\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {String.class});\n        given(invocation.getArguments()).willReturn(new Object[] {\"arg1\"});\n\n        validationFilter.setValidation(validation);\n        Result result = validationFilter.invoke(invoker, invocation);\n\n        assertThat(String.valueOf(result.getValue()), is(\"success\"));\n    }\n\n    @Test\n    void testItWhileMethodNameStartWithDollar() {\n        URL url = URL.valueOf(\"test://test:11/test\");\n\n        given(validation.getValidator(url)).willReturn(validator);\n        given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n        given(invoker.getUrl()).willReturn(url);\n        given(invocation.getMethodName()).willReturn(\"$echo1\");\n        given(invocation.getParameterTypes()).willReturn(new Class<?>[] {String.class});\n        given(invocation.getArguments()).willReturn(new Object[] {\"arg1\"});\n\n        validationFilter.setValidation(validation);\n        Result result = validationFilter.invoke(invoker, invocation);\n\n        assertThat(String.valueOf(result.getValue()), is(\"success\"));\n    }\n\n    @Test\n    void testItWhileThrowoutRpcException() {\n        Assertions.assertThrows(RpcException.class, () -> {\n            URL url = URL.valueOf(\"test://test:11/test?validation=true\");\n\n            given(validation.getValidator(url)).willThrow(new RpcException(\"rpc exception\"));\n            given(invoker.invoke(invocation)).willReturn(new AppResponse(\"success\"));\n            given(invoker.getUrl()).willReturn(url);\n            given(invocation.getMethodName()).willReturn(\"echo1\");\n            given(invocation.getParameterTypes()).willReturn(new Class<?>[] {String.class});\n            given(invocation.getArguments()).willReturn(new Object[] {\"arg1\"});\n\n            validationFilter.setValidation(validation);\n            validationFilter.invoke(invoker, invocation);\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/JValidationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.support.jvalidation;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.validation.Validation;\nimport org.apache.dubbo.validation.Validator;\n\nimport javax.validation.ValidationException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.core.Is.is;\n\nclass JValidationTest {\n    @Test\n    void testReturnTypeWithInvalidValidationProvider() {\n        Assertions.assertThrows(ValidationException.class, () -> {\n            Validation jValidation = new JValidation();\n            URL url = URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.JValidation?\"\n                    + \"jvalidation=org.apache.dubbo.validation.Validation\");\n            jValidation.getValidator(url);\n        });\n    }\n\n    @Test\n    void testReturnTypeWithDefaultValidatorProvider() {\n        Validation jValidation = new JValidation();\n        URL url = URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.JValidation\");\n        Validator validator = jValidation.getValidator(url);\n        assertThat(validator instanceof JValidator, is(true));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/JValidatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.support.jvalidation;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget;\nimport org.apache.dubbo.validation.support.jvalidation.mock.ValidationParameter;\n\nimport javax.validation.ConstraintViolationException;\nimport javax.validation.ValidationException;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.hamcrest.Matchers.instanceOf;\nimport static org.hamcrest.Matchers.is;\n\nclass JValidatorTest {\n    @Test\n    void testItWithNonExistMethod() {\n        Assertions.assertThrows(NoSuchMethodException.class, () -> {\n            URL url = URL.valueOf(\n                    \"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n            JValidator jValidator = new JValidator(url);\n            jValidator.validate(\"nonExistingMethod\", new Class<?>[] {String.class}, new Object[] {\"arg1\"});\n        });\n    }\n\n    @Test\n    void testItWithExistMethod() throws Exception {\n        URL url =\n                URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n        JValidator jValidator = new JValidator(url);\n        jValidator.validate(\"someMethod1\", new Class<?>[] {String.class}, new Object[] {\"anything\"});\n    }\n\n    @Test\n    void testItWhenItViolatedConstraint() {\n        Assertions.assertThrows(ValidationException.class, () -> {\n            URL url = URL.valueOf(\n                    \"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n            JValidator jValidator = new JValidator(url);\n            jValidator.validate(\n                    \"someMethod2\", new Class<?>[] {ValidationParameter.class}, new Object[] {new ValidationParameter()\n                    });\n        });\n    }\n\n    @Test\n    void testItWhenItMeetsConstraint() throws Exception {\n        URL url =\n                URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n        JValidator jValidator = new JValidator(url);\n        jValidator.validate(\"someMethod2\", new Class<?>[] {ValidationParameter.class}, new Object[] {\n            new ValidationParameter(\"NotBeNull\")\n        });\n    }\n\n    @Test\n    void testItWithArrayArg() throws Exception {\n        URL url =\n                URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n        JValidator jValidator = new JValidator(url);\n        jValidator.validate(\"someMethod3\", new Class<?>[] {ValidationParameter[].class}, new Object[] {\n            new ValidationParameter[] {new ValidationParameter(\"parameter\")}\n        });\n    }\n\n    @Test\n    void testItWithCollectionArg() throws Exception {\n        URL url =\n                URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n        JValidator jValidator = new JValidator(url);\n        jValidator.validate(\n                \"someMethod4\", new Class<?>[] {List.class}, new Object[] {Collections.singletonList(\"parameter\")});\n    }\n\n    @Test\n    void testItWithMapArg() throws Exception {\n        URL url =\n                URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n        JValidator jValidator = new JValidator(url);\n        Map<String, String> map = new HashMap<>();\n        map.put(\"key\", \"value\");\n        jValidator.validate(\"someMethod5\", new Class<?>[] {Map.class}, new Object[] {map});\n    }\n\n    @Test\n    void testItWithPrimitiveArg() {\n        Assertions.assertThrows(ValidationException.class, () -> {\n            URL url = URL.valueOf(\n                    \"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n            JValidator jValidator = new JValidator(url);\n            jValidator.validate(\"someMethod6\", new Class<?>[] {Integer.class, String.class, Long.class}, new Object[] {\n                null, null, null\n            });\n        });\n    }\n\n    @Test\n    void testItWithPrimitiveArgWithProvidedMessage() {\n        URL url =\n                URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n        JValidator jValidator = new JValidator(url);\n        try {\n            jValidator.validate(\"someMethod6\", new Class<?>[] {Integer.class, String.class, Long.class}, new Object[] {\n                null, \"\", null\n            });\n            Assertions.fail();\n        } catch (Exception e) {\n            assertThat(e.getMessage(), containsString(\"string must not be blank\"));\n            assertThat(e.getMessage(), containsString(\"longValue must not be null\"));\n        }\n    }\n\n    @Test\n    void testItWithPartialParameterValidation() {\n        URL url =\n                URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n        JValidator jValidator = new JValidator(url);\n        try {\n            jValidator.validate(\"someMethod6\", new Class<?>[] {Integer.class, String.class, Long.class}, new Object[] {\n                null, \"\", null\n            });\n            Assertions.fail();\n        } catch (Exception e) {\n            assertThat(e, instanceOf(ConstraintViolationException.class));\n            ConstraintViolationException e1 = (ConstraintViolationException) e;\n            assertThat(e1.getConstraintViolations().size(), is(2));\n        }\n    }\n\n    @Test\n    void testItWithNestedParameterValidationWithNullParam() {\n        Assertions.assertThrows(ValidationException.class, () -> {\n            URL url = URL.valueOf(\n                    \"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n            JValidator jValidator = new JValidator(url);\n            jValidator.validate(\n                    \"someMethod7\", new Class<?>[] {JValidatorTestTarget.BaseParam.class}, new Object[] {null});\n        });\n    }\n\n    @Test\n    void testItWithNestedParameterValidationWithNullNestedParam() {\n        URL url =\n                URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n        JValidator jValidator = new JValidator(url);\n        try {\n            JValidatorTestTarget.BaseParam<JValidatorTestTarget.Param> param = new JValidatorTestTarget.BaseParam<>();\n            jValidator.validate(\n                    \"someMethod7\", new Class<?>[] {JValidatorTestTarget.BaseParam.class}, new Object[] {param});\n            Assertions.fail();\n        } catch (Exception e) {\n            assertThat(e, instanceOf(ConstraintViolationException.class));\n            ConstraintViolationException e1 = (ConstraintViolationException) e;\n            assertThat(e1.getConstraintViolations().size(), is(1));\n            assertThat(e1.getMessage(), containsString(\"body must not be null\"));\n        }\n    }\n\n    @Test\n    void testItWithNestedParameterValidationWithNullNestedParams() {\n        URL url =\n                URL.valueOf(\"test://test:11/org.apache.dubbo.validation.support.jvalidation.mock.JValidatorTestTarget\");\n        JValidator jValidator = new JValidator(url);\n        try {\n            JValidatorTestTarget.BaseParam<JValidatorTestTarget.Param> param = new JValidatorTestTarget.BaseParam<>();\n            param.setBody(new JValidatorTestTarget.Param());\n            jValidator.validate(\n                    \"someMethod7\", new Class<?>[] {JValidatorTestTarget.BaseParam.class}, new Object[] {param});\n            Assertions.fail();\n        } catch (Exception e) {\n            assertThat(e, instanceOf(ConstraintViolationException.class));\n            ConstraintViolationException e1 = (ConstraintViolationException) e;\n            assertThat(e1.getConstraintViolations().size(), is(1));\n            assertThat(e1.getMessage(), containsString(\"name must not be null\"));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/mock/JValidatorTestTarget.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.support.jvalidation.mock;\n\nimport org.apache.dubbo.validation.MethodValidated;\n\nimport javax.validation.Valid;\nimport javax.validation.constraints.NotNull;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.hibernate.validator.constraints.NotBlank;\n\npublic interface JValidatorTestTarget {\n    @MethodValidated\n    void someMethod1(String anything);\n\n    @MethodValidated(Test2.class)\n    void someMethod2(@NotNull ValidationParameter validationParameter);\n\n    void someMethod3(ValidationParameter[] parameters);\n\n    void someMethod4(List<String> strings);\n\n    void someMethod5(Map<String, String> map);\n\n    void someMethod6(\n            Integer intValue,\n            @NotBlank(message = \"string must not be blank\") String string,\n            @NotNull(message = \"longValue must not be null\") Long longValue);\n\n    void someMethod7(@NotNull BaseParam<Param> baseParam);\n\n    @interface Test2 {}\n\n    class BaseParam<T> {\n\n        @Valid\n        @NotNull(message = \"body must not be null\")\n        private T body;\n\n        public T getBody() {\n            return body;\n        }\n\n        public void setBody(T body) {\n            this.body = body;\n        }\n    }\n\n    class Param {\n\n        @NotNull(message = \"name must not be null\")\n        private String name;\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/test/java/org/apache/dubbo/validation/support/jvalidation/mock/ValidationParameter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.validation.support.jvalidation.mock;\n\nimport javax.validation.constraints.NotNull;\n\npublic class ValidationParameter {\n    @NotNull\n    private String parameter;\n\n    public ValidationParameter() {}\n\n    public ValidationParameter(String parameter) {\n        this.parameter = parameter;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-filter-validation/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-mcp</artifactId>\n  <properties>\n    <mcp.version>0.11.2</mcp.version>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rest-openapi</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-filter-cache</artifactId>\n      <version>${revision}</version>\n    </dependency>\n    <dependency>\n      <groupId>io.modelcontextprotocol.sdk</groupId>\n      <artifactId>mcp</artifactId>\n      <version>${mcp.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <!--test-->\n    <dependency>\n      <groupId>org.mockito</groupId>\n      <artifactId>mockito-junit-jupiter</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <configuration>\n          <compilerArgs>\n            <arg>-parameters</arg>\n          </compilerArgs>\n          <source>17</source>\n          <target>17</target>\n          <release>17</release>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/JsonSchemaType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic enum JsonSchemaType {\n    BOOLEAN(boolean.class, \"boolean\", null),\n    BOOLEAN_OBJ(Boolean.class, \"boolean\", null),\n\n    BYTE(byte.class, \"integer\", null),\n    BYTE_OBJ(Byte.class, \"integer\", null),\n    SHORT(short.class, \"integer\", null),\n    SHORT_OBJ(Short.class, \"integer\", null),\n    INT(int.class, \"integer\", null),\n    INTEGER_OBJ(Integer.class, \"integer\", null),\n    LONG(long.class, \"integer\", \"int64\"),\n    LONG_OBJ(Long.class, \"integer\", \"int64\"),\n    BIG_INTEGER(BigInteger.class, \"integer\", \"int64\"),\n\n    FLOAT(float.class, \"number\", \"float\"),\n    FLOAT_OBJ(Float.class, \"number\", \"float\"),\n    DOUBLE(double.class, \"number\", \"double\"),\n    DOUBLE_OBJ(Double.class, \"number\", \"double\"),\n    BIG_DECIMAL(BigDecimal.class, \"number\", null), // BigDecimal often without specific format\n\n    CHAR(char.class, \"string\", null),\n    CHARACTER_OBJ(Character.class, \"string\", null),\n    STRING(String.class, \"string\", null),\n    CHAR_SEQUENCE(CharSequence.class, \"string\", null),\n    STRING_BUFFER(StringBuffer.class, \"string\", null),\n    STRING_BUILDER(StringBuilder.class, \"string\", null),\n    BYTE_ARRAY(byte[].class, \"string\", \"byte\"),\n\n    // Generic JSON Schema Types\n    OBJECT_SCHEMA(null, \"object\", null),\n    ARRAY_SCHEMA(null, \"array\", null),\n    STRING_SCHEMA(null, \"string\", null),\n    NUMBER_SCHEMA(null, \"number\", null),\n    INTEGER_SCHEMA(null, \"integer\", null),\n    BOOLEAN_SCHEMA(null, \"boolean\", null),\n\n    // Date/Time Formats\n    DATE_FORMAT(null, null, \"date\"),\n    TIME_FORMAT(null, null, \"time\"),\n    DATE_TIME_FORMAT(null, null, \"date-time\");\n\n    private final Class<?> javaType;\n    private final String jsonSchemaType;\n    private final String jsonSchemaFormat;\n\n    private static final Map<Class<?>, JsonSchemaType> javaTypeLookup = new HashMap<>();\n\n    static {\n        for (JsonSchemaType mapping : values()) {\n            javaTypeLookup.put(mapping.javaType, mapping);\n        }\n    }\n\n    JsonSchemaType(Class<?> javaType, String jsonSchemaType, String jsonSchemaFormat) {\n        this.javaType = javaType;\n        this.jsonSchemaType = jsonSchemaType;\n        this.jsonSchemaFormat = jsonSchemaFormat;\n    }\n\n    public Class<?> getJavaType() {\n        return javaType;\n    }\n\n    public String getJsonSchemaType() {\n        return jsonSchemaType;\n    }\n\n    public String getJsonSchemaFormat() {\n        return jsonSchemaFormat;\n    }\n\n    public static JsonSchemaType fromJavaType(Class<?> type) {\n        return javaTypeLookup.get(type);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/McpConstant.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp;\n\n/**\n * Constants for MCP (Model Context Protocol) integration\n */\npublic interface McpConstant {\n\n    String SETTINGS_MCP_PREFIX = \"dubbo.protocol.triple.rest.mcp\";\n    String SETTINGS_MCP_ENABLE = \"dubbo.protocol.triple.rest.mcp.enabled\";\n    String SETTINGS_MCP_PORT = \"dubbo.protocol.triple.rest.mcp.port\";\n    String SETTINGS_MCP_PROTOCOL = \"dubbo.protocol.triple.rest.mcp.protocol\";\n    String SETTINGS_MCP_SESSION_TIMEOUT = \"dubbo.protocol.triple.rest.mcp.session-timeout\";\n    String SETTINGS_MCP_DEFAULT_ENABLED = \"dubbo.protocol.triple.rest.mcp.default.enabled\";\n    String SETTINGS_MCP_INCLUDE_PATTERNS = \"dubbo.protocol.triple.rest.mcp.include-patterns\";\n    String SETTINGS_MCP_EXCLUDE_PATTERNS = \"dubbo.protocol.triple.rest.mcp.exclude-patterns\";\n    String SETTINGS_MCP_PATHS_SSE = \"dubbo.protocol.triple.rest.mcp.path.sse\";\n    String SETTINGS_MCP_PATHS_MESSAGE = \"dubbo.protocol.triple.rest.mcp.path.message\";\n\n    Integer DEFAULT_SESSION_TIMEOUT = 60;\n\n    // MCP service control-related configuration\n    String SETTINGS_MCP_SERVICE_PREFIX = \"dubbo.protocol.triple.rest.mcp.service\";\n    String SETTINGS_MCP_SERVICE_ENABLED_SUFFIX = \"enabled\";\n    String SETTINGS_MCP_SERVICE_NAME_SUFFIX = \"tool-name\";\n    String SETTINGS_MCP_SERVICE_DESCRIPTION_SUFFIX = \"description\";\n    String SETTINGS_MCP_SERVICE_TAGS_SUFFIX = \"tags\";\n\n    String MCP_SERVICE_PROTOCOL = \"tri\";\n    int MCP_SERVICE_PORT = 8081;\n\n    String DEFAULT_TOOL_NAME_PREFIX = \"arg\";\n    String DEFAULT_TOOL_DESCRIPTION_TEMPLATE = \"Execute method '%s' from service '%s'\";\n    String DEFAULT_PARAMETER_DESCRIPTION_TEMPLATE = \"Parameter %d of type %s\";\n\n    String SCHEMA_PROPERTY_TYPE = \"type\";\n    String SCHEMA_PROPERTY_DESCRIPTION = \"description\";\n    String SCHEMA_PROPERTY_PROPERTIES = \"properties\";\n\n    // Common JSON Schema property names\n    String SCHEMA_PROPERTY_FORMAT = \"format\";\n    String SCHEMA_PROPERTY_ENUM = \"enum\";\n    String SCHEMA_PROPERTY_DEFAULT = \"default\";\n    String SCHEMA_PROPERTY_REF = \"$ref\";\n    String SCHEMA_PROPERTY_ITEMS = \"items\";\n    String SCHEMA_PROPERTY_ADDITIONAL_PROPERTIES = \"additionalProperties\";\n    String SCHEMA_PROPERTY_REQUIRED = \"required\";\n\n    // Specific parameter names\n    String PARAM_TRIPLE_SERVICE_GROUP = \"tri-service-group\";\n    String PARAM_REQUEST_BODY_PAYLOAD = \"requestBodyPayload\";\n\n    // URL parameter names for MCP configuration\n    String PARAM_MCP_ENABLED = \"mcp.enabled\";\n    String PARAM_MCP_TOOL_NAME = \"mcp.tool-name\";\n    String PARAM_MCP_DESCRIPTION = \"mcp.description\";\n    String PARAM_MCP_TAGS = \"mcp.tags\";\n    String PARAM_MCP_PRIORITY = \"mcp.priority\";\n\n    // Default parameter descriptions\n    String PARAM_DESCRIPTION_DOUBLE = \"A numeric value of type Double\";\n    String PARAM_DESCRIPTION_INTEGER = \"An integer value\";\n    String PARAM_DESCRIPTION_STRING = \"A string value\";\n    String PARAM_DESCRIPTION_BOOLEAN = \"A boolean value\";\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/annotations/McpTool.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.annotations;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotation to expose a Dubbo service method as an MCP tool.\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface McpTool {\n\n    /**\n     * Specifies whether this method should be exposed as an MCP tool.\n     * Default is true.\n     */\n    boolean enabled() default true;\n\n    /**\n     * The unique name of the MCP tool. If not specified, the method name will be used.\n     */\n    String name() default \"\";\n\n    /**\n     * A description of the tool's functionality. This will be visible to AI models.\n     * If not specified, a default description will be generated.\n     */\n    String description() default \"\";\n\n    /**\n     * A list of tags for categorizing the tool.\n     */\n    String[] tags() default {};\n\n    /**\n     * The priority of this tool. Higher values indicate higher priority.\n     */\n    int priority() default 0;\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/annotations/McpToolParam.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.annotations;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.PARAMETER, ElementType.FIELD})\npublic @interface McpToolParam {\n\n    /**\n     * The name of the parameter. This will be the key in the JSON schema properties.\n     * If not specified, the parameter name will be inferred from the method signature\n     * or a default name like \"arg0\", \"arg1\", etc.\n     */\n    String name() default \"\";\n\n    /**\n     * A description of the parameter. This will be used in the JSON schema for clarity.\n     * If not specified, a default description will be generated.\n     */\n    String description() default \"\";\n\n    /**\n     * Specifies whether the parameter is required.\n     */\n    boolean required() default false;\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/core/McpApplicationDeployListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.core;\n\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.deploy.ApplicationDeployListener;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.bootstrap.builders.InternalServiceConfigBuilder;\nimport org.apache.dubbo.mcp.McpConstant;\nimport org.apache.dubbo.mcp.tool.DubboMcpGenericCaller;\nimport org.apache.dubbo.mcp.tool.DubboOpenApiToolConverter;\nimport org.apache.dubbo.mcp.tool.DubboServiceToolRegistry;\nimport org.apache.dubbo.mcp.transport.DubboMcpSseTransportProvider;\nimport org.apache.dubbo.mcp.transport.DubboMcpStreamableTransportProvider;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPIService;\n\nimport java.util.Collection;\nimport java.util.concurrent.ExecutorService;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.modelcontextprotocol.server.McpAsyncServer;\nimport io.modelcontextprotocol.server.McpServer;\nimport io.modelcontextprotocol.spec.McpSchema;\n\nimport static org.apache.dubbo.metadata.util.MetadataServiceVersionUtils.V1;\n\npublic class McpApplicationDeployListener implements ApplicationDeployListener {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(McpApplicationDeployListener.class);\n    private DubboServiceToolRegistry toolRegistry;\n\n    private boolean mcpEnable = true;\n\n    private volatile ServiceConfig<McpSseService> sseServiceConfig;\n\n    private volatile ServiceConfig<McpStreamableService> streamableServiceConfig;\n\n    private static DubboMcpSseTransportProvider dubboMcpSseTransportProvider;\n\n    private static DubboMcpStreamableTransportProvider dubboMcpStreamableTransportProvider;\n\n    private McpAsyncServer mcpAsyncServer;\n\n    @Override\n    public void onInitialize(ApplicationModel scopeModel) {}\n\n    @Override\n    public void onStarting(ApplicationModel applicationModel) {}\n\n    public static DubboMcpSseTransportProvider getDubboMcpSseTransportProvider() {\n        return dubboMcpSseTransportProvider;\n    }\n\n    public static DubboMcpStreamableTransportProvider getDubboMcpStreamableTransportProvider() {\n        return dubboMcpStreamableTransportProvider;\n    }\n\n    @Override\n    public void onStarted(ApplicationModel applicationModel) {\n        Configuration globalConf = ConfigurationUtils.getGlobalConfiguration(applicationModel);\n        mcpEnable = globalConf.getBoolean(McpConstant.SETTINGS_MCP_ENABLE, false);\n        if (!mcpEnable) {\n            logger.info(\"MCP service is disabled, skipping initialization\");\n            return;\n        }\n        try {\n            logger.info(\"Initializing MCP server and dynamic service registration\");\n\n            // Initialize service filter\n            McpServiceFilter mcpServiceFilter = new McpServiceFilter(applicationModel);\n\n            String protocol = globalConf.getString(McpConstant.SETTINGS_MCP_PROTOCOL, \"streamable\");\n            McpSchema.ServerCapabilities.ToolCapabilities toolCapabilities =\n                    new McpSchema.ServerCapabilities.ToolCapabilities(true);\n            McpSchema.ServerCapabilities serverCapabilities =\n                    new McpSchema.ServerCapabilities(null, null, null, null, null, toolCapabilities);\n\n            Integer sessionTimeout =\n                    globalConf.getInt(McpConstant.SETTINGS_MCP_SESSION_TIMEOUT, McpConstant.DEFAULT_SESSION_TIMEOUT);\n            if (\"streamable\".equals(protocol)) {\n                dubboMcpStreamableTransportProvider =\n                        new DubboMcpStreamableTransportProvider(new ObjectMapper(), sessionTimeout);\n                mcpAsyncServer = McpServer.async(getDubboMcpStreamableTransportProvider())\n                        .capabilities(serverCapabilities)\n                        .build();\n            } else if (\"sse\".equals(protocol)) {\n                dubboMcpSseTransportProvider = new DubboMcpSseTransportProvider(new ObjectMapper(), sessionTimeout);\n                mcpAsyncServer = McpServer.async(getDubboMcpSseTransportProvider())\n                        .capabilities(serverCapabilities)\n                        .build();\n            } else {\n                logger.error(\n                        LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"not support protocol \" + protocol);\n            }\n\n            FrameworkModel frameworkModel = applicationModel.getFrameworkModel();\n            DefaultOpenAPIService defaultOpenAPIService = new DefaultOpenAPIService(frameworkModel);\n\n            DubboOpenApiToolConverter toolConverter = new DubboOpenApiToolConverter(defaultOpenAPIService);\n\n            DubboMcpGenericCaller genericCaller = new DubboMcpGenericCaller(applicationModel);\n\n            toolRegistry = new DubboServiceToolRegistry(mcpAsyncServer, toolConverter, genericCaller, mcpServiceFilter);\n\n            applicationModel.getBeanFactory().registerBean(toolRegistry);\n\n            Collection<ProviderModel> providerModels =\n                    applicationModel.getApplicationServiceRepository().allProviderModels();\n\n            int registeredCount = 0;\n            for (ProviderModel pm : providerModels) {\n                int serviceRegisteredCount = toolRegistry.registerService(pm);\n                registeredCount += serviceRegisteredCount;\n            }\n\n            if (\"streamable\".equals(protocol)) {\n                exportMcpStreamableService(applicationModel);\n            } else {\n                exportMcpSSEService(applicationModel);\n            }\n            logger.info(\n                    \"MCP server initialized successfully, {} existing tools registered, dynamic registration enabled\",\n                    registeredCount);\n        } catch (Exception e) {\n            logger.error(\n                    LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"MCP service initialization failed: \" + e.getMessage(),\n                    e);\n        }\n    }\n\n    @Override\n    public void onStopping(ApplicationModel applicationModel) {\n        if (toolRegistry != null) {\n            logger.info(\"MCP server stopping, clearing tool registry\");\n            toolRegistry.clearRegistry();\n        }\n    }\n\n    @Override\n    public void onStopped(ApplicationModel applicationModel) {\n        if (mcpEnable && mcpAsyncServer != null) {\n            mcpAsyncServer.close();\n        }\n    }\n\n    @Override\n    public void onFailure(ApplicationModel applicationModel, Throwable cause) {}\n\n    private void exportMcpSSEService(ApplicationModel applicationModel) {\n        McpSseServiceImpl mcpSseServiceImpl =\n                applicationModel.getBeanFactory().getOrRegisterBean(McpSseServiceImpl.class);\n\n        ExecutorService internalServiceExecutor = applicationModel\n                .getFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getInternalServiceExecutor();\n\n        this.sseServiceConfig = InternalServiceConfigBuilder.<McpSseService>newBuilder(applicationModel)\n                .interfaceClass(McpSseService.class)\n                .protocol(CommonConstants.TRIPLE, McpConstant.MCP_SERVICE_PROTOCOL)\n                .port(getRegisterPort(), String.valueOf(McpConstant.MCP_SERVICE_PORT))\n                .registryId(\"internal-mcp-registry\")\n                .executor(internalServiceExecutor)\n                .ref(mcpSseServiceImpl)\n                .version(V1)\n                .build();\n        sseServiceConfig.export();\n        logger.info(\"MCP service exported on: {}\", sseServiceConfig.getExportedUrls());\n    }\n\n    private void exportMcpStreamableService(ApplicationModel applicationModel) {\n        McpStreamableServiceImpl mcpStreamableServiceImpl =\n                applicationModel.getBeanFactory().getOrRegisterBean(McpStreamableServiceImpl.class);\n\n        ExecutorService internalServiceExecutor = applicationModel\n                .getFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getInternalServiceExecutor();\n\n        this.streamableServiceConfig = InternalServiceConfigBuilder.<McpStreamableService>newBuilder(applicationModel)\n                .interfaceClass(McpStreamableService.class)\n                .protocol(CommonConstants.TRIPLE, McpConstant.MCP_SERVICE_PROTOCOL)\n                .port(getRegisterPort(), String.valueOf(McpConstant.MCP_SERVICE_PORT))\n                .registryId(\"internal-mcp-registry\")\n                .executor(internalServiceExecutor)\n                .ref(mcpStreamableServiceImpl)\n                .version(V1)\n                .build();\n        streamableServiceConfig.export();\n        logger.info(\"MCP service exported on: {}\", streamableServiceConfig.getExportedUrls());\n    }\n\n    /**\n     * Get the Mcp service register port.\n     * First, try to get config from user configuration, if not found, get from protocol config.\n     * Second, try to get config from protocol config, if not found, get a random available port.\n     */\n    private int getRegisterPort() {\n        Configuration globalConf = ConfigurationUtils.getGlobalConfiguration(ApplicationModel.defaultModel());\n        int mcpPort = globalConf.getInt(McpConstant.SETTINGS_MCP_PORT, -1);\n        if (mcpPort != -1) {\n            return mcpPort;\n        }\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        Collection<ProtocolConfig> protocolConfigs =\n                applicationModel.getApplicationConfigManager().getProtocols();\n        if (CollectionUtils.isNotEmpty(protocolConfigs)) {\n            for (ProtocolConfig protocolConfig : protocolConfigs) {\n                if (CommonConstants.TRIPLE.equals(protocolConfig.getName())) {\n                    return protocolConfig.getPort();\n                }\n            }\n        }\n        return NetUtils.getAvailablePort();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/core/McpServiceExportListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.core;\n\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.ServiceListener;\nimport org.apache.dubbo.mcp.tool.DubboServiceToolRegistry;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class McpServiceExportListener implements ServiceListener {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(McpServiceExportListener.class);\n\n    private final Map<String, RegisteredServiceInfo> registeredServiceTools = new ConcurrentHashMap<>();\n\n    private static class RegisteredServiceInfo {\n        final int toolCount;\n        final String interfaceName;\n        final ProviderModel providerModel;\n\n        RegisteredServiceInfo(int toolCount, String interfaceName, ProviderModel providerModel) {\n            this.toolCount = toolCount;\n            this.interfaceName = interfaceName;\n            this.providerModel = providerModel;\n        }\n    }\n\n    @Override\n    public void exported(ServiceConfig sc) {\n        try {\n            if (sc.getRef() == null) {\n                return;\n            }\n\n            String serviceKey = sc.getUniqueServiceName();\n            ProviderModel providerModel =\n                    sc.getScopeModel().getServiceRepository().lookupExportedService(serviceKey);\n\n            if (providerModel == null) {\n                logger.warn(\n                        LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"ProviderModel not found for service: \" + sc.getInterface() + \" with key: \" + serviceKey);\n                return;\n            }\n\n            DubboServiceToolRegistry toolRegistry = getToolRegistry(sc);\n            if (toolRegistry == null) {\n                return;\n            }\n\n            int registeredCount = toolRegistry.registerService(providerModel);\n\n            if (registeredCount > 0) {\n                registeredServiceTools.put(\n                        serviceKey,\n                        new RegisteredServiceInfo(\n                                registeredCount, providerModel.getServiceModel().getInterfaceName(), providerModel));\n                logger.info(\n                        \"Dynamically registered {} MCP tools for exported service: {}\",\n                        registeredCount,\n                        providerModel.getServiceModel().getInterfaceName());\n            }\n        } catch (Exception e) {\n            logger.error(\n                    LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to register MCP tools for exported service: \" + sc.getInterface(),\n                    e);\n        }\n    }\n\n    @Override\n    public void unexported(ServiceConfig sc) {\n        try {\n            if (sc.getRef() == null) {\n                return;\n            }\n\n            String serviceKey = sc.getUniqueServiceName();\n            RegisteredServiceInfo serviceInfo = registeredServiceTools.remove(serviceKey);\n\n            if (serviceInfo != null && serviceInfo.toolCount > 0) {\n                DubboServiceToolRegistry toolRegistry = getToolRegistry(sc);\n                if (toolRegistry == null) {\n                    return;\n                }\n\n                toolRegistry.unregisterService(serviceInfo.providerModel);\n                logger.info(\n                        \"Dynamically unregistered {} MCP tools for unexported service: {}\",\n                        serviceInfo.toolCount,\n                        serviceInfo.interfaceName);\n            }\n\n        } catch (Exception e) {\n            logger.error(\n                    LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to unregister MCP tools for unexported service: \" + sc.getInterface(),\n                    e);\n        }\n    }\n\n    private DubboServiceToolRegistry getToolRegistry(ServiceConfig sc) {\n        try {\n            ApplicationModel applicationModel = sc.getScopeModel().getApplicationModel();\n            return applicationModel.getBeanFactory().getBean(DubboServiceToolRegistry.class);\n        } catch (Exception e) {\n            logger.warn(\n                    LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to get DubboServiceToolRegistry from application context\",\n                    e);\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/core/McpServiceFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.core;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.mcp.McpConstant;\nimport org.apache.dubbo.mcp.annotations.McpTool;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\npublic class McpServiceFilter {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(McpServiceFilter.class);\n\n    private final Configuration configuration;\n    private final Pattern[] includePatterns;\n    private final Pattern[] excludePatterns;\n    private final boolean defaultEnabled;\n\n    public McpServiceFilter(ApplicationModel applicationModel) {\n        this.configuration = ConfigurationUtils.getGlobalConfiguration(applicationModel);\n        this.defaultEnabled = configuration.getBoolean(McpConstant.SETTINGS_MCP_DEFAULT_ENABLED, true);\n\n        String includeStr = configuration.getString(McpConstant.SETTINGS_MCP_INCLUDE_PATTERNS, \"\");\n        String excludeStr = configuration.getString(McpConstant.SETTINGS_MCP_EXCLUDE_PATTERNS, \"\");\n\n        this.includePatterns = parsePatterns(includeStr);\n        this.excludePatterns = parsePatterns(excludeStr);\n    }\n\n    /**\n     * Check if service should be exposed as MCP tool.\n     * Priority: URL Parameters > Annotations > Configuration File > Default\n     */\n    public boolean shouldExposeAsMcpTool(ProviderModel providerModel) {\n        String interfaceName = providerModel.getServiceModel().getInterfaceName();\n\n        if (isMatchedByPatterns(interfaceName, excludePatterns)) {\n            return false;\n        }\n\n        URL serviceUrl = getServiceUrl(providerModel);\n        if (serviceUrl != null) {\n            String urlValue = serviceUrl.getParameter(McpConstant.PARAM_MCP_ENABLED);\n            if (urlValue != null && StringUtils.isNotEmpty(urlValue)) {\n                return Boolean.parseBoolean(urlValue);\n            }\n        }\n\n        Object serviceBean = providerModel.getServiceInstance();\n        if (serviceBean != null) {\n            DubboService dubboService = serviceBean.getClass().getAnnotation(DubboService.class);\n            if (dubboService != null && dubboService.mcpEnabled()) {\n                return true;\n            }\n        }\n\n        String serviceSpecificKey = McpConstant.SETTINGS_MCP_SERVICE_PREFIX + \".\" + interfaceName + \".enabled\";\n        if (configuration.containsKey(serviceSpecificKey)) {\n            return configuration.getBoolean(serviceSpecificKey, false);\n        }\n\n        if (configuration.containsKey(McpConstant.PARAM_MCP_ENABLED)) {\n            return configuration.getBoolean(McpConstant.PARAM_MCP_ENABLED, false);\n        }\n\n        if (includePatterns.length > 0) {\n            return isMatchedByPatterns(interfaceName, includePatterns);\n        }\n\n        return defaultEnabled;\n    }\n\n    /**\n     * Check if specific method should be exposed as MCP tool.\n     * Priority: @McpTool(enabled=false) > URL Parameters > @McpTool(enabled=true) > Configuration > Service-level\n     */\n    public boolean shouldExposeMethodAsMcpTool(ProviderModel providerModel, Method method) {\n        String interfaceName = providerModel.getServiceModel().getInterfaceName();\n        String methodName = method.getName();\n\n        if (isMatchedByPatterns(interfaceName, excludePatterns)) {\n            return false;\n        }\n\n        McpTool methodMcpTool = getMethodMcpTool(providerModel, method);\n\n        if (methodMcpTool != null && !methodMcpTool.enabled()) {\n            return false;\n        }\n\n        URL serviceUrl = getServiceUrl(providerModel);\n        if (serviceUrl != null) {\n            String methodUrlValue = serviceUrl.getMethodParameter(methodName, McpConstant.PARAM_MCP_ENABLED);\n\n            if (methodUrlValue != null && StringUtils.isNotEmpty(methodUrlValue)) {\n                return Boolean.parseBoolean(methodUrlValue);\n            }\n\n            String serviceLevelValue = serviceUrl.getParameter(McpConstant.PARAM_MCP_ENABLED);\n\n            if (serviceLevelValue != null && StringUtils.isNotEmpty(serviceLevelValue)) {\n                return Boolean.parseBoolean(serviceLevelValue);\n            }\n        }\n\n        if (methodMcpTool != null && methodMcpTool.enabled()) {\n            return true;\n        }\n\n        String methodConfigKey =\n                McpConstant.SETTINGS_MCP_SERVICE_PREFIX + \".\" + interfaceName + \".methods.\" + methodName + \".enabled\";\n        if (configuration.containsKey(methodConfigKey)) {\n            return configuration.getBoolean(methodConfigKey, false);\n        }\n\n        if (shouldExposeAsMcpTool(providerModel)) {\n            return Modifier.isPublic(method.getModifiers());\n        }\n\n        return false;\n    }\n\n    /**\n     * Get @McpTool annotation from method, checking both interface and implementation class.\n     */\n    private McpTool getMethodMcpTool(ProviderModel providerModel, Method method) {\n        String methodName = method.getName();\n        Class<?>[] paramTypes = method.getParameterTypes();\n\n        Object serviceBean = providerModel.getServiceInstance();\n        if (serviceBean != null) {\n            try {\n                Method implMethod = serviceBean.getClass().getMethod(methodName, paramTypes);\n                McpTool implMcpTool = implMethod.getAnnotation(McpTool.class);\n                if (implMcpTool != null) {\n                    return implMcpTool;\n                }\n            } catch (NoSuchMethodException e) {\n                // Method not found in implementation class\n                logger.error(\n                        LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Method not found in implementation class: \" + methodName + \" with parameters: \"\n                                + Arrays.toString(paramTypes),\n                        e);\n            }\n        }\n\n        McpTool interfaceMcpTool = method.getAnnotation(McpTool.class);\n        if (interfaceMcpTool != null) {\n            return interfaceMcpTool;\n        }\n\n        Class<?> serviceInterface = providerModel.getServiceModel().getServiceInterfaceClass();\n        if (serviceInterface != null) {\n            try {\n                Method interfaceMethod = serviceInterface.getMethod(methodName, paramTypes);\n                return interfaceMethod.getAnnotation(McpTool.class);\n            } catch (NoSuchMethodException e) {\n                // Method not found in service interface\n            }\n        }\n\n        return null;\n    }\n\n    public McpToolConfig getMcpToolConfig(ProviderModel providerModel, Method method) {\n        String interfaceName = providerModel.getServiceModel().getInterfaceName();\n        McpToolConfig config = new McpToolConfig();\n\n        config.setToolName(method.getName());\n\n        McpTool mcpTool = getMethodMcpTool(providerModel, method);\n        if (mcpTool != null) {\n            if (StringUtils.isNotEmpty(mcpTool.name())) {\n                config.setToolName(mcpTool.name());\n            }\n            if (StringUtils.isNotEmpty(mcpTool.description())) {\n                config.setDescription(mcpTool.description());\n            }\n            if (mcpTool.tags().length > 0) {\n                config.setTags(Arrays.asList(mcpTool.tags()));\n            }\n            config.setPriority(mcpTool.priority());\n        }\n\n        String methodPrefix =\n                McpConstant.SETTINGS_MCP_SERVICE_PREFIX + \".\" + interfaceName + \".methods.\" + method.getName() + \".\";\n\n        String configToolName = configuration.getString(methodPrefix + \"name\");\n        if (StringUtils.isNotEmpty(configToolName)) {\n            config.setToolName(configToolName);\n        }\n\n        String configDescription = configuration.getString(methodPrefix + \"description\");\n        if (StringUtils.isNotEmpty(configDescription)) {\n            config.setDescription(configDescription);\n        }\n\n        String configTags = configuration.getString(methodPrefix + \"tags\");\n        if (StringUtils.isNotEmpty(configTags)) {\n            config.setTags(Arrays.asList(configTags.split(\",\")));\n        }\n\n        URL serviceUrl = getServiceUrl(providerModel);\n        if (serviceUrl != null) {\n            String urlToolName = serviceUrl.getMethodParameter(method.getName(), McpConstant.PARAM_MCP_TOOL_NAME);\n            if (urlToolName != null && StringUtils.isNotEmpty(urlToolName)) {\n                config.setToolName(urlToolName);\n            }\n\n            String urlDescription = serviceUrl.getMethodParameter(method.getName(), McpConstant.PARAM_MCP_DESCRIPTION);\n            if (urlDescription != null && StringUtils.isNotEmpty(urlDescription)) {\n                config.setDescription(urlDescription);\n            }\n\n            String urlTags = serviceUrl.getMethodParameter(method.getName(), McpConstant.PARAM_MCP_TAGS);\n            if (urlTags != null && StringUtils.isNotEmpty(urlTags)) {\n                config.setTags(Arrays.asList(urlTags.split(\",\")));\n            }\n\n            String urlPriority = serviceUrl.getMethodParameter(method.getName(), McpConstant.PARAM_MCP_PRIORITY);\n            if (urlPriority != null && StringUtils.isNotEmpty(urlPriority)) {\n                try {\n                    config.setPriority(Integer.parseInt(urlPriority));\n                } catch (NumberFormatException e) {\n                    logger.warn(\n                            LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                            \"\",\n                            \"\",\n                            \"Invalid URL priority value: \" + urlPriority + \" for method: \" + method.getName());\n                }\n            }\n        }\n\n        return config;\n    }\n\n    public McpToolConfig getMcpToolConfig(ProviderModel providerModel) {\n        String interfaceName = providerModel.getServiceModel().getInterfaceName();\n        McpToolConfig config = new McpToolConfig();\n\n        String servicePrefix = McpConstant.SETTINGS_MCP_SERVICE_PREFIX + \".\" + interfaceName + \".\";\n\n        String configToolName = configuration.getString(servicePrefix + \"name\");\n        if (StringUtils.isNotEmpty(configToolName)) {\n            config.setToolName(configToolName);\n        }\n\n        String configDescription = configuration.getString(servicePrefix + \"description\");\n        if (StringUtils.isNotEmpty(configDescription)) {\n            config.setDescription(configDescription);\n        }\n\n        String configTags = configuration.getString(servicePrefix + \"tags\");\n        if (StringUtils.isNotEmpty(configTags)) {\n            config.setTags(Arrays.asList(configTags.split(\",\")));\n        }\n\n        URL serviceUrl = getServiceUrl(providerModel);\n        if (serviceUrl != null) {\n            String urlToolName = serviceUrl.getParameter(McpConstant.PARAM_MCP_TOOL_NAME);\n            if (urlToolName != null && StringUtils.isNotEmpty(urlToolName)) {\n                config.setToolName(urlToolName);\n            }\n\n            String urlDescription = serviceUrl.getParameter(McpConstant.PARAM_MCP_DESCRIPTION);\n            if (urlDescription != null && StringUtils.isNotEmpty(urlDescription)) {\n                config.setDescription(urlDescription);\n            }\n\n            String urlTags = serviceUrl.getParameter(McpConstant.PARAM_MCP_TAGS);\n            if (urlTags != null && StringUtils.isNotEmpty(urlTags)) {\n                config.setTags(Arrays.asList(urlTags.split(\",\")));\n            }\n\n            String urlPriority = serviceUrl.getParameter(McpConstant.PARAM_MCP_PRIORITY);\n            if (urlPriority != null && StringUtils.isNotEmpty(urlPriority)) {\n                try {\n                    config.setPriority(Integer.parseInt(urlPriority));\n                } catch (NumberFormatException e) {\n                    logger.warn(\n                            LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                            \"\",\n                            \"\",\n                            \"Invalid URL priority value: \" + urlPriority + \" for service: \" + interfaceName);\n                }\n            }\n        }\n\n        return config;\n    }\n\n    private URL getServiceUrl(ProviderModel providerModel) {\n        List<URL> serviceUrls = providerModel.getServiceUrls();\n        if (serviceUrls != null && !serviceUrls.isEmpty()) {\n            return serviceUrls.get(0);\n        }\n        return null;\n    }\n\n    private Pattern[] parsePatterns(String patternStr) {\n        if (StringUtils.isEmpty(patternStr)) {\n            return new Pattern[0];\n        }\n\n        return Arrays.stream(patternStr.split(\",\"))\n                .map(String::trim)\n                .filter(StringUtils::isNotEmpty)\n                .map(pattern -> Pattern.compile(pattern.replace(\"*\", \".*\")))\n                .toArray(Pattern[]::new);\n    }\n\n    private boolean isMatchedByPatterns(String text, Pattern[] patterns) {\n        for (Pattern pattern : patterns) {\n            if (pattern.matcher(text).matches()) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static class McpToolConfig {\n        private String toolName;\n        private String description;\n        private List<String> tags;\n        private int priority = 0;\n\n        public String getToolName() {\n            return toolName;\n        }\n\n        public void setToolName(String toolName) {\n            this.toolName = toolName;\n        }\n\n        public String getDescription() {\n            return description;\n        }\n\n        public void setDescription(String description) {\n            this.description = description;\n        }\n\n        public List<String> getTags() {\n            return tags;\n        }\n\n        public void setTags(List<String> tags) {\n            this.tags = tags;\n        }\n\n        public int getPriority() {\n            return priority;\n        }\n\n        public void setPriority(int priority) {\n            this.priority = priority;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/core/McpSseService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.core;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.message.ServerSentEvent;\nimport org.apache.dubbo.remoting.http12.rest.Mapping;\n\nimport static org.apache.dubbo.mcp.McpConstant.SETTINGS_MCP_PATHS_MESSAGE;\nimport static org.apache.dubbo.mcp.McpConstant.SETTINGS_MCP_PATHS_SSE;\n\n@Mapping(\"\")\npublic interface McpSseService {\n\n    @Mapping(value = \"//${\" + SETTINGS_MCP_PATHS_SSE + \":/mcp/sse}\", method = HttpMethods.GET)\n    void get(StreamObserver<ServerSentEvent<String>> responseObserver);\n\n    @Mapping(value = \"//${\" + SETTINGS_MCP_PATHS_MESSAGE + \":/mcp/message}\", method = HttpMethods.POST)\n    void post();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/core/McpSseServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.core;\n\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mcp.transport.DubboMcpSseTransportProvider;\nimport org.apache.dubbo.remoting.http12.message.ServerSentEvent;\n\npublic class McpSseServiceImpl implements McpSseService, Disposable {\n\n    private volatile DubboMcpSseTransportProvider transportProvider = null;\n\n    @Override\n    public void get(StreamObserver<ServerSentEvent<String>> responseObserver) {\n        if (transportProvider == null) {\n            synchronized (this) {\n                if (transportProvider == null) {\n                    transportProvider = getTransportProvider();\n                }\n            }\n        }\n        transportProvider.handleRequest(responseObserver);\n    }\n\n    @Override\n    public void post() {\n        if (transportProvider == null) {\n            synchronized (this) {\n                if (transportProvider == null) {\n                    transportProvider = getTransportProvider();\n                }\n            }\n        }\n        transportProvider.handleRequest(null);\n    }\n\n    private DubboMcpSseTransportProvider getTransportProvider() {\n        return McpApplicationDeployListener.getDubboMcpSseTransportProvider();\n    }\n\n    @Override\n    public void destroy() {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/core/McpStreamableService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.core;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.remoting.http12.message.ServerSentEvent;\nimport org.apache.dubbo.remoting.http12.rest.Mapping;\n\nimport static org.apache.dubbo.mcp.McpConstant.SETTINGS_MCP_PATHS_MESSAGE;\n\n@Mapping(\"\")\npublic interface McpStreamableService {\n\n    @Mapping(value = \"//${\" + SETTINGS_MCP_PATHS_MESSAGE + \":/mcp/streamable/message}\")\n    void streamable(StreamObserver<ServerSentEvent<byte[]>> responseObserver);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/core/McpStreamableServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.core;\n\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mcp.transport.DubboMcpStreamableTransportProvider;\nimport org.apache.dubbo.remoting.http12.message.ServerSentEvent;\n\npublic class McpStreamableServiceImpl implements McpStreamableService, Disposable {\n\n    private volatile DubboMcpStreamableTransportProvider transportProvider = null;\n\n    @Override\n    public void streamable(StreamObserver<ServerSentEvent<byte[]>> responseObserver) {\n        if (transportProvider == null) {\n            synchronized (this) {\n                if (transportProvider == null) {\n                    transportProvider = getTransportProvider();\n                }\n            }\n        }\n        transportProvider.handleRequest(responseObserver);\n    }\n\n    public DubboMcpStreamableTransportProvider getTransportProvider() {\n        return McpApplicationDeployListener.getDubboMcpStreamableTransportProvider();\n    }\n\n    @Override\n    public void destroy() {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/tool/DubboMcpGenericCaller.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.tool;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\npublic class DubboMcpGenericCaller {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DubboMcpGenericCaller.class);\n\n    private final ApplicationConfig applicationConfig;\n\n    private final Map<String, GenericService> serviceCache = new ConcurrentHashMap<>();\n\n    public DubboMcpGenericCaller(ApplicationModel applicationModel) {\n        if (applicationModel == null) {\n            logger.error(\n                    COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", \"ApplicationModel cannot be null for DubboMcpGenericCaller.\");\n            throw new IllegalArgumentException(\"ApplicationModel cannot be null.\");\n        }\n        this.applicationConfig = applicationModel.getCurrentConfig();\n        if (this.applicationConfig == null) {\n\n            String errMsg = \"ApplicationConfig is null in the provided ApplicationModel. Application Name: \"\n                    + (applicationModel.getApplicationName() != null ? applicationModel.getApplicationName() : \"N/A\");\n            logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", errMsg);\n            throw new IllegalStateException(errMsg);\n        }\n    }\n\n    public Object execute(\n            String interfaceName,\n            String methodName,\n            List<String> orderedJavaParameterNames,\n            Class<?>[] parameterJavaTypes,\n            Map<String, Object> mcpProvidedParameters,\n            String group,\n            String version) {\n        String cacheKey = interfaceName + \":\" + (group == null ? \"\" : group) + \":\" + (version == null ? \"\" : version);\n        GenericService genericService = serviceCache.get(cacheKey);\n        if (genericService == null) {\n            ReferenceConfig<GenericService> reference = new ReferenceConfig<>();\n            reference.setApplication(this.applicationConfig);\n            reference.setInterface(interfaceName);\n            reference.setGeneric(\"true\"); // Defaults to 'bean' or 'true' for POJO generalization.\n            reference.setScope(\"local\");\n            if (group != null && !group.isEmpty()) {\n                reference.setGroup(group);\n            }\n            if (version != null && !version.isEmpty()) {\n                reference.setVersion(version);\n            }\n\n            try {\n                genericService = reference.get();\n                if (genericService != null) {\n                    serviceCache.put(cacheKey, genericService);\n                } else {\n                    String errorMessage = \"Failed to obtain GenericService instance for \" + interfaceName\n                            + (group != null ? \" group \" + group : \"\") + (version != null ? \" version \" + version : \"\");\n                    logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", errorMessage);\n                    throw new IllegalStateException(errorMessage);\n                }\n            } catch (Exception e) {\n                String errorMessage = \"Error obtaining GenericService for \" + interfaceName + \": \" + e.getMessage();\n                logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", errorMessage, e);\n                throw new RuntimeException(errorMessage, e);\n            }\n        }\n\n        String[] invokeParameterTypes = new String[parameterJavaTypes.length];\n        for (int i = 0; i < parameterJavaTypes.length; i++) {\n            invokeParameterTypes[i] = parameterJavaTypes[i].getName();\n        }\n\n        Object[] invokeArgs = new Object[orderedJavaParameterNames.size()];\n        for (int i = 0; i < orderedJavaParameterNames.size(); i++) {\n            String paramName = orderedJavaParameterNames.get(i);\n            if (mcpProvidedParameters.containsKey(paramName)) {\n                invokeArgs[i] = mcpProvidedParameters.get(paramName);\n            } else {\n                invokeArgs[i] = null;\n                logger.warn(\n                        COMMON_UNEXPECTED_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Parameter '\" + paramName + \"' not found in MCP provided parameters for method '\" + methodName\n                                + \"' of interface '\" + interfaceName + \"'. Will use null.\");\n            }\n        }\n\n        try {\n            return genericService.$invoke(methodName, invokeParameterTypes, invokeArgs);\n        } catch (Exception e) {\n            String errorMessage = \"GenericService $invoke failed for method '\" + methodName + \"' on interface '\"\n                    + interfaceName + \"': \" + e.getMessage();\n            logger.error(COMMON_UNEXPECTED_EXCEPTION, \"\", \"\", errorMessage, e);\n            throw new RuntimeException(errorMessage, e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/tool/DubboOpenApiToolConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.tool;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.PojoUtils;\nimport org.apache.dubbo.mcp.JsonSchemaType;\nimport org.apache.dubbo.mcp.McpConstant;\nimport org.apache.dubbo.mcp.core.McpServiceFilter;\nimport org.apache.dubbo.mcp.util.TypeSchemaUtils;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPIService;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.modelcontextprotocol.spec.McpSchema;\n\npublic class DubboOpenApiToolConverter {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DubboOpenApiToolConverter.class);\n    private final DefaultOpenAPIService openApiService;\n    private final ObjectMapper objectMapper = new ObjectMapper();\n    private final Map<String, Operation> opCache = new ConcurrentHashMap<>();\n\n    public DubboOpenApiToolConverter(DefaultOpenAPIService openApiService) {\n        this.openApiService = openApiService;\n    }\n\n    public Map<String, McpSchema.Tool> convertToTools(\n            ServiceDescriptor svcDesc, URL svcUrl, McpServiceFilter.McpToolConfig toolConfig) {\n        opCache.clear();\n\n        OpenAPIRequest req = new OpenAPIRequest();\n        String intfName = svcDesc.getInterfaceName();\n        req.setService(new String[] {intfName});\n\n        OpenAPI openApiDef = openApiService.getOpenAPI(req);\n\n        if (openApiDef == null || openApiDef.getPaths() == null) {\n            return new HashMap<>();\n        }\n\n        Map<String, McpSchema.Tool> mcpTools = new HashMap<>();\n        for (Map.Entry<String, PathItem> pathEntry : openApiDef.getPaths().entrySet()) {\n            String path = pathEntry.getKey();\n            PathItem item = pathEntry.getValue();\n            if (item.getOperations() != null) {\n                for (Map.Entry<HttpMethods, Operation> opEntry :\n                        item.getOperations().entrySet()) {\n                    HttpMethods httpMethod = opEntry.getKey();\n                    Operation op = opEntry.getValue();\n                    if (op == null || op.getOperationId() == null) {\n                        continue;\n                    }\n                    String opId = op.getOperationId();\n\n                    McpServiceFilter.McpToolConfig methodConfig = getMethodConfig(op, toolConfig);\n\n                    McpSchema.Tool mcpTool = convertOperationToMcpTool(path, httpMethod, op, methodConfig);\n                    mcpTools.put(opId, mcpTool);\n                    opCache.put(opId, op);\n                }\n            }\n        }\n        return mcpTools;\n    }\n\n    public Operation getOperationByToolName(String toolName) {\n        return opCache.get(toolName);\n    }\n\n    private McpSchema.Tool convertOperationToMcpTool(\n            String path, HttpMethods method, Operation op, McpServiceFilter.McpToolConfig toolConfig) {\n        String opId = op.getOperationId();\n\n        String toolName = generateToolName(op, toolConfig);\n        String desc = generateToolDescription(op, toolConfig, path, method);\n\n        Map<String, Object> paramsSchemaMap = extractParameterSchema(op);\n        String schemaJson;\n        try {\n            schemaJson = objectMapper.writeValueAsString(paramsSchemaMap);\n        } catch (Exception e) {\n            logger.error(\n                    LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                    \"Failed to serialize parameter schema for tool {}: {}\",\n                    opId,\n                    e.getMessage(),\n                    e);\n            schemaJson = \"{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{}}\";\n        }\n        return new McpSchema.Tool(toolName, desc, schemaJson);\n    }\n\n    private String generateToolName(Operation op, McpServiceFilter.McpToolConfig toolConfig) {\n        String opId = op.getOperationId();\n\n        if (toolConfig != null\n                && toolConfig.getToolName() != null\n                && !toolConfig.getToolName().isEmpty()) {\n            return toolConfig.getToolName();\n        }\n\n        return opId;\n    }\n\n    private String generateToolDescription(\n            Operation op, McpServiceFilter.McpToolConfig toolConfig, String path, HttpMethods method) {\n        if (toolConfig != null\n                && toolConfig.getDescription() != null\n                && !toolConfig.getDescription().isEmpty()) {\n            return toolConfig.getDescription();\n        }\n\n        String desc = op.getSummary();\n        if (desc == null || desc.isEmpty()) {\n            desc = op.getDescription();\n        }\n        if (desc == null || desc.isEmpty()) {\n            desc = \"Executes operation '\" + op.getOperationId() + \"' which corresponds to a \" + method.name()\n                    + \" request on path \" + path + \".\";\n        }\n\n        return desc;\n    }\n\n    private Map<String, Object> extractParameterSchema(Operation op) {\n        Map<String, Object> schema = new HashMap<>();\n        Map<String, Object> props = new HashMap<>();\n        schema.put(McpConstant.SCHEMA_PROPERTY_TYPE, JsonSchemaType.OBJECT_SCHEMA.getJsonSchemaType());\n\n        if (op.getParameters() != null) {\n            for (Parameter apiParam : op.getParameters()) {\n                if (McpConstant.PARAM_TRIPLE_SERVICE_GROUP.equals(apiParam.getName())) {\n                    continue;\n                }\n                if (apiParam.getSchema() != null) {\n                    props.put(\n                            apiParam.getName(), convertOpenApiSchemaToMcpMap(apiParam.getSchema(), apiParam.getName()));\n                }\n            }\n        }\n\n        if (op.getRequestBody() != null && op.getRequestBody().getContents() != null) {\n            op.getRequestBody().getContents().values().stream().findFirst().ifPresent(mediaType -> {\n                if (mediaType.getSchema() != null) {\n                    Schema bodySchema = mediaType.getSchema();\n                    MethodMeta methodMeta = op.getMeta();\n\n                    if (methodMeta != null && methodMeta.getParameters() != null) {\n                        ParameterMeta[] methodParams = methodMeta.getParameters();\n\n                        boolean shouldCreateIndividualParams =\n                                methodParams.length > 1 && allParamsArePrimitive(methodParams);\n\n                        if (shouldCreateIndividualParams) {\n                            for (int i = 0; i < methodParams.length; i++) {\n                                ParameterMeta param = methodParams[i];\n                                String paramName = param.getName();\n\n                                if (paramName == null || paramName.startsWith(McpConstant.DEFAULT_TOOL_NAME_PREFIX)) {\n                                    paramName = param.getType().getSimpleName().toLowerCase() + \"_\" + (i + 1);\n                                    logger.warn(\n                                            LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                                            \"\",\n                                            \"\",\n                                            \"Operation '\" + op.getOperationId()\n                                                    + \"': Parameter \" + i + \" has default name '\" + param.getName()\n                                                    + \"', using generated name '\" + paramName\n                                                    + \"'. Ensure '-parameters' compiler flag is enabled.\");\n                                }\n\n                                Map<String, Object> paramSchema = new HashMap<>();\n                                Class<?> paramType = param.getType();\n\n                                if (paramType == Double.class || paramType == double.class) {\n                                    paramSchema.put(\n                                            McpConstant.SCHEMA_PROPERTY_TYPE,\n                                            JsonSchemaType.NUMBER_SCHEMA.getJsonSchemaType());\n                                    paramSchema.put(\n                                            McpConstant.SCHEMA_PROPERTY_DESCRIPTION,\n                                            McpConstant.PARAM_DESCRIPTION_DOUBLE);\n                                } else if (paramType == Integer.class || paramType == int.class) {\n                                    paramSchema.put(\n                                            McpConstant.SCHEMA_PROPERTY_TYPE,\n                                            JsonSchemaType.INTEGER_SCHEMA.getJsonSchemaType());\n                                    paramSchema.put(\n                                            McpConstant.SCHEMA_PROPERTY_DESCRIPTION,\n                                            McpConstant.PARAM_DESCRIPTION_INTEGER);\n                                } else if (paramType == String.class) {\n                                    paramSchema.put(\n                                            McpConstant.SCHEMA_PROPERTY_TYPE,\n                                            JsonSchemaType.STRING_SCHEMA.getJsonSchemaType());\n                                    paramSchema.put(\n                                            McpConstant.SCHEMA_PROPERTY_DESCRIPTION,\n                                            McpConstant.PARAM_DESCRIPTION_STRING);\n                                } else if (paramType == Boolean.class || paramType == boolean.class) {\n                                    paramSchema.put(\n                                            McpConstant.SCHEMA_PROPERTY_TYPE,\n                                            JsonSchemaType.BOOLEAN_SCHEMA.getJsonSchemaType());\n                                    paramSchema.put(\n                                            McpConstant.SCHEMA_PROPERTY_DESCRIPTION,\n                                            McpConstant.PARAM_DESCRIPTION_BOOLEAN);\n                                } else {\n                                    paramSchema = convertOpenApiSchemaToMcpMap(bodySchema.getItems(), paramName);\n                                }\n\n                                props.put(paramName, paramSchema);\n                            }\n                        } else {\n                            String inferredBodyParamName = McpConstant.PARAM_REQUEST_BODY_PAYLOAD;\n                            ParameterMeta requestBodyJavaParam = null;\n\n                            if (methodParams.length == 1) {\n                                ParameterMeta singleParam = methodParams[0];\n                                if (singleParam.getNamedValueMeta().paramType() == null\n                                        || singleParam.getNamedValueMeta().paramType() == ParamType.Body) {\n                                    requestBodyJavaParam = singleParam;\n                                }\n                            } else {\n                                for (ParameterMeta pMeta : methodParams) {\n                                    if (pMeta.getNamedValueMeta().paramType() == ParamType.Body) {\n                                        requestBodyJavaParam = pMeta;\n                                        break;\n                                    }\n                                }\n                                if (requestBodyJavaParam == null) {\n                                    for (ParameterMeta pMeta : methodParams) {\n                                        if (pMeta.getNamedValueMeta().paramType() == null\n                                                && PojoUtils.isPojo(pMeta.getType())) {\n                                            requestBodyJavaParam = pMeta;\n                                            break;\n                                        }\n                                    }\n                                }\n                            }\n\n                            if (requestBodyJavaParam != null) {\n                                String actualParamName = requestBodyJavaParam.getName();\n                                if (actualParamName != null\n                                        && !actualParamName.startsWith(McpConstant.DEFAULT_TOOL_NAME_PREFIX)\n                                        && !actualParamName.isEmpty()) {\n                                    inferredBodyParamName = actualParamName;\n\n                                } else {\n                                    logger.warn(\n                                            LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                                            \"\",\n                                            \"\",\n                                            \"Operation '\" + op.getOperationId()\n                                                    + \"': Could not get a meaningful name for request body param from MethodMeta (actual name was '\"\n                                                    + (actualParamName != null ? actualParamName : \"null\")\n                                                    + \"'). Using default '\" + inferredBodyParamName\n                                                    + \"'. Ensure '-parameters' compiler flag is enabled.\");\n                                }\n                            } else {\n                                logger.warn(\n                                        LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                                        \"\",\n                                        \"\",\n                                        \"Operation '\" + op.getOperationId()\n                                                + \"': Could not identify a specific method parameter for the request body via MethodMeta. Using default name '\"\n                                                + inferredBodyParamName + \" ' for schema type '\" + bodySchema.getType()\n                                                + \"'\");\n                            }\n                            props.put(\n                                    inferredBodyParamName,\n                                    convertOpenApiSchemaToMcpMap(bodySchema, inferredBodyParamName));\n                        }\n                    } else {\n                        logger.warn(\n                                LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                                \"\",\n                                \"\",\n                                \"Operation '\" + op.getOperationId()\n                                        + \"': MethodMeta not available for request body parameter name inference. Using default name 'requestBodyPayload' for schema type '\"\n                                        + bodySchema.getType() + \"'.\");\n                        props.put(\n                                McpConstant.PARAM_REQUEST_BODY_PAYLOAD,\n                                convertOpenApiSchemaToMcpMap(bodySchema, McpConstant.PARAM_REQUEST_BODY_PAYLOAD));\n                    }\n                }\n            });\n        }\n        schema.put(McpConstant.SCHEMA_PROPERTY_PROPERTIES, props);\n        return schema;\n    }\n\n    private Map<String, Object> convertOpenApiSchemaToMcpMap(Schema openApiSchema) {\n        return convertOpenApiSchemaToMcpMap(openApiSchema, null);\n    }\n\n    private Map<String, Object> convertOpenApiSchemaToMcpMap(Schema openApiSchema, String propertyName) {\n        Map<String, Object> mcpMap = new HashMap<>();\n        if (openApiSchema == null) {\n            return mcpMap;\n        }\n\n        if (openApiSchema.getRef() != null) {\n            mcpMap.put(McpConstant.SCHEMA_PROPERTY_REF, openApiSchema.getRef());\n        }\n        if (openApiSchema.getType() != null) {\n            mcpMap.put(\n                    McpConstant.SCHEMA_PROPERTY_TYPE,\n                    openApiSchema.getType().toString().toLowerCase());\n        }\n        if (openApiSchema.getFormat() != null) {\n            mcpMap.put(McpConstant.SCHEMA_PROPERTY_FORMAT, openApiSchema.getFormat());\n        }\n\n        if (openApiSchema.getDescription() != null\n                && !openApiSchema.getDescription().isEmpty()) {\n            mcpMap.put(McpConstant.SCHEMA_PROPERTY_DESCRIPTION, openApiSchema.getDescription());\n        } else {\n            String defaultParamDesc = getParamDesc(openApiSchema, propertyName);\n            mcpMap.put(McpConstant.SCHEMA_PROPERTY_DESCRIPTION, defaultParamDesc);\n        }\n\n        if (openApiSchema.getEnumeration() != null\n                && !openApiSchema.getEnumeration().isEmpty()) {\n            mcpMap.put(McpConstant.SCHEMA_PROPERTY_ENUM, openApiSchema.getEnumeration());\n        }\n        if (openApiSchema.getDefaultValue() != null) {\n            mcpMap.put(McpConstant.SCHEMA_PROPERTY_DEFAULT, openApiSchema.getDefaultValue());\n        }\n\n        if (Schema.Type.OBJECT.equals(openApiSchema.getType()) && openApiSchema.getProperties() != null) {\n            Map<String, Object> nestedProps = new HashMap<>();\n            openApiSchema\n                    .getProperties()\n                    .forEach((name, propSchema) ->\n                            nestedProps.put(name, convertOpenApiSchemaToMcpMap(propSchema, name)));\n            mcpMap.put(McpConstant.SCHEMA_PROPERTY_PROPERTIES, nestedProps);\n        }\n\n        if (Schema.Type.ARRAY.equals(openApiSchema.getType()) && openApiSchema.getItems() != null) {\n            mcpMap.put(\n                    McpConstant.SCHEMA_PROPERTY_ITEMS,\n                    convertOpenApiSchemaToMcpMap(\n                            openApiSchema.getItems(), propertyName != null ? propertyName + \"_item\" : null));\n        }\n        return mcpMap;\n    }\n\n    private static String getParamDesc(Schema openApiSchema, String propertyName) {\n        String typeOrRefString = \"\";\n        if (openApiSchema.getRef() != null && !openApiSchema.getRef().isEmpty()) {\n            String ref = openApiSchema.getRef();\n            String componentName = ref.substring(ref.lastIndexOf('/') + 1);\n            typeOrRefString = \" referencing '\" + componentName + \"';\"; // Indicates it's a reference\n            if (openApiSchema.getType() != null) {\n                typeOrRefString += \" (which is of type '\"\n                        + openApiSchema.getType().toString().toLowerCase() + \"')\";\n            }\n\n        } else if (openApiSchema.getType() != null) {\n            typeOrRefString = \" of type '\" + openApiSchema.getType().toString().toLowerCase() + \"';\";\n            if (openApiSchema.getFormat() != null) {\n                typeOrRefString += \" with format '\" + openApiSchema.getFormat() + \"';\";\n            }\n        }\n\n        String namePrefix;\n        if (propertyName != null && !propertyName.isEmpty()) {\n            namePrefix = \"Parameter '\" + propertyName + \"';\";\n        } else {\n            namePrefix = typeOrRefString.isEmpty() ? \"Parameter\" : \"Schema\";\n        }\n\n        return namePrefix + typeOrRefString + \".\";\n    }\n\n    private boolean allParamsArePrimitive(ParameterMeta[] methodParams) {\n        for (ParameterMeta param : methodParams) {\n            Class<?> paramType = param.getType();\n            if (!TypeSchemaUtils.isPrimitiveOrWrapper(paramType)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private McpServiceFilter.McpToolConfig getMethodConfig(Operation op, McpServiceFilter.McpToolConfig defaultConfig) {\n        // Try to get method-specific configuration from operation metadata\n        // This would need integration with the service filter to get method-level config\n        // For now, return the default config\n        return defaultConfig;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/tool/DubboServiceToolRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.tool;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.mcp.JsonSchemaType;\nimport org.apache.dubbo.mcp.McpConstant;\nimport org.apache.dubbo.mcp.annotations.McpToolParam;\nimport org.apache.dubbo.mcp.core.McpServiceFilter;\nimport org.apache.dubbo.mcp.util.TypeSchemaUtils;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.BiFunction;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.modelcontextprotocol.server.McpAsyncServer;\nimport io.modelcontextprotocol.server.McpAsyncServerExchange;\nimport io.modelcontextprotocol.server.McpServerFeatures;\nimport io.modelcontextprotocol.spec.McpSchema;\nimport reactor.core.publisher.Mono;\n\npublic class DubboServiceToolRegistry {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DubboServiceToolRegistry.class);\n\n    private final McpAsyncServer mcpServer;\n    private final DubboOpenApiToolConverter toolConverter;\n    private final DubboMcpGenericCaller genericCaller;\n    private final McpServiceFilter mcpServiceFilter;\n    private final Map<String, McpServerFeatures.AsyncToolSpecification> registeredTools = new ConcurrentHashMap<>();\n    private final Map<String, Set<String>> serviceToToolsMapping = new ConcurrentHashMap<>();\n    private final ObjectMapper objectMapper;\n\n    public DubboServiceToolRegistry(\n            McpAsyncServer mcpServer,\n            DubboOpenApiToolConverter toolConverter,\n            DubboMcpGenericCaller genericCaller,\n            McpServiceFilter mcpServiceFilter) {\n        this.mcpServer = mcpServer;\n        this.toolConverter = toolConverter;\n        this.genericCaller = genericCaller;\n        this.mcpServiceFilter = mcpServiceFilter;\n        this.objectMapper = new ObjectMapper();\n    }\n\n    public int registerService(ProviderModel providerModel) {\n        ServiceDescriptor serviceDescriptor = providerModel.getServiceModel();\n        List<URL> statedURLs = providerModel.getServiceUrls();\n\n        if (statedURLs == null || statedURLs.isEmpty()) {\n            return 0;\n        }\n\n        try {\n            URL url = statedURLs.get(0);\n            int registeredCount = 0;\n            String serviceKey = getServiceKey(providerModel);\n            Set<String> toolNames = new HashSet<>();\n\n            Class<?> serviceInterface = serviceDescriptor.getServiceInterfaceClass();\n            if (serviceInterface == null) {\n                return 0;\n            }\n\n            Method[] methods = serviceInterface.getDeclaredMethods();\n            boolean shouldRegisterServiceLevel = mcpServiceFilter.shouldExposeAsMcpTool(providerModel);\n\n            for (Method method : methods) {\n                if (mcpServiceFilter.shouldExposeMethodAsMcpTool(providerModel, method)) {\n                    McpServiceFilter.McpToolConfig toolConfig =\n                            mcpServiceFilter.getMcpToolConfig(providerModel, method);\n\n                    String toolName = registerMethodAsTool(providerModel, method, url, toolConfig);\n                    if (toolName != null) {\n                        toolNames.add(toolName);\n                        registeredCount++;\n                    }\n                }\n            }\n\n            if (registeredCount == 0 && shouldRegisterServiceLevel) {\n                Set<String> serviceToolNames = registerServiceLevelTools(providerModel, url);\n                toolNames.addAll(serviceToolNames);\n                registeredCount = serviceToolNames.size();\n            }\n\n            if (registeredCount > 0) {\n                serviceToToolsMapping.put(serviceKey, toolNames);\n                logger.info(\n                        \"Registered {} MCP tools for service: {}\",\n                        registeredCount,\n                        serviceDescriptor.getInterfaceName());\n            }\n\n            return registeredCount;\n\n        } catch (Exception e) {\n            logger.error(\n                    LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to register service as MCP tools: \" + serviceDescriptor.getInterfaceName(),\n                    e);\n            return 0;\n        }\n    }\n\n    public void unregisterService(ProviderModel providerModel) {\n        String serviceKey = getServiceKey(providerModel);\n        Set<String> toolNames = serviceToToolsMapping.remove(serviceKey);\n\n        if (toolNames == null || toolNames.isEmpty()) {\n            return;\n        }\n\n        int unregisteredCount = 0;\n        for (String toolName : toolNames) {\n            try {\n                McpServerFeatures.AsyncToolSpecification toolSpec = registeredTools.remove(toolName);\n                if (toolSpec != null) {\n                    mcpServer.removeTool(toolName).block();\n                    unregisteredCount++;\n                }\n            } catch (Exception e) {\n                logger.error(\n                        LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Failed to unregister MCP tool: \" + toolName,\n                        e);\n            }\n        }\n\n        if (unregisteredCount > 0) {\n            logger.info(\n                    \"Unregistered {} MCP tools for service: {}\",\n                    unregisteredCount,\n                    providerModel.getServiceModel().getInterfaceName());\n        }\n    }\n\n    private String getServiceKey(ProviderModel providerModel) {\n        return providerModel.getServiceKey();\n    }\n\n    private String registerMethodAsTool(\n            ProviderModel providerModel, Method method, URL url, McpServiceFilter.McpToolConfig toolConfig) {\n        try {\n            String toolName = toolConfig.getToolName();\n            if (toolName == null || toolName.isEmpty()) {\n                toolName = method.getName();\n            }\n\n            if (registeredTools.containsKey(toolName)) {\n                return null;\n            }\n\n            String description = toolConfig.getDescription();\n            if (description == null || description.isEmpty()) {\n                description = generateDefaultDescription(method, providerModel);\n            }\n\n            McpSchema.Tool mcpTool = new McpSchema.Tool(toolName, description, generateToolSchema(method));\n\n            McpServerFeatures.AsyncToolSpecification toolSpec =\n                    createMethodToolSpecification(mcpTool, providerModel, method, url);\n\n            mcpServer.addTool(toolSpec).block();\n            registeredTools.put(toolName, toolSpec);\n\n            return toolName;\n\n        } catch (Exception e) {\n            logger.error(\n                    LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to register method as MCP tool: \" + method.getName(),\n                    e);\n            return null;\n        }\n    }\n\n    private Set<String> registerServiceLevelTools(ProviderModel providerModel, URL url) {\n        ServiceDescriptor serviceDescriptor = providerModel.getServiceModel();\n        Set<String> toolNames = new HashSet<>();\n\n        McpServiceFilter.McpToolConfig serviceConfig = mcpServiceFilter.getMcpToolConfig(providerModel);\n\n        Map<String, McpSchema.Tool> tools = toolConverter.convertToTools(serviceDescriptor, url, serviceConfig);\n\n        if (tools.isEmpty()) {\n            return toolNames;\n        }\n\n        for (Map.Entry<String, McpSchema.Tool> entry : tools.entrySet()) {\n            McpSchema.Tool tool = entry.getValue();\n            String toolId = tool.name();\n\n            if (registeredTools.containsKey(toolId)) {\n                continue;\n            }\n\n            try {\n                Operation operation = toolConverter.getOperationByToolName(toolId);\n                if (operation == null) {\n                    logger.error(\n                            LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                            \"\",\n                            \"\",\n                            \"Could not find Operation metadata for tool: \" + tool + \". Skipping registration\");\n                    continue;\n                }\n\n                McpServerFeatures.AsyncToolSpecification toolSpec =\n                        createServiceToolSpecification(tool, operation, url);\n                mcpServer.addTool(toolSpec).block();\n                registeredTools.put(toolId, toolSpec);\n                toolNames.add(toolId);\n\n            } catch (Exception e) {\n                logger.error(\n                        LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Failed to register MCP tool: \" + toolId,\n                        e);\n            }\n        }\n\n        return toolNames;\n    }\n\n    private McpServerFeatures.AsyncToolSpecification createMethodToolSpecification(\n            McpSchema.Tool mcpTool, ProviderModel providerModel, Method method, URL url) {\n\n        final String interfaceName = providerModel.getServiceModel().getInterfaceName();\n        final String methodName = method.getName();\n        final Class<?>[] parameterClasses = method.getParameterTypes();\n        final List<String> orderedJavaParameterNames = getStrings(method);\n        final String group = url.getGroup();\n        final String version = url.getVersion();\n\n        return getAsyncToolSpecification(\n                mcpTool, interfaceName, methodName, parameterClasses, orderedJavaParameterNames, group, version);\n    }\n\n    private McpServerFeatures.AsyncToolSpecification getAsyncToolSpecification(\n            McpSchema.Tool mcpTool,\n            String interfaceName,\n            String methodName,\n            Class<?>[] parameterClasses,\n            List<String> orderedJavaParameterNames,\n            String group,\n            String version) {\n        BiFunction<McpAsyncServerExchange, Map<String, Object>, Mono<McpSchema.CallToolResult>> callFunction =\n                (exchange, mcpProvidedParameters) -> {\n                    try {\n                        Object result = genericCaller.execute(\n                                interfaceName,\n                                methodName,\n                                orderedJavaParameterNames,\n                                parameterClasses,\n                                mcpProvidedParameters,\n                                group,\n                                version);\n                        String resultJson = (result != null) ? result.toString() : \"null\";\n                        return Mono.just(new McpSchema.CallToolResult(resultJson, true));\n                    } catch (Exception e) {\n                        logger.error(\n                                LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                                \"\",\n                                \"\",\n                                String.format(\n                                        \"Error executing tool %s (interface: %s, method: %s): %s\",\n                                        mcpTool.name(), interfaceName, methodName, e.getMessage()),\n                                e);\n                        return Mono.just(\n                                new McpSchema.CallToolResult(\"Tool execution failed: \" + e.getMessage(), false));\n                    }\n                };\n\n        return new McpServerFeatures.AsyncToolSpecification(mcpTool, callFunction);\n    }\n\n    private static List<String> getStrings(Method method) {\n        final List<String> orderedJavaParameterNames = new ArrayList<>();\n        java.lang.reflect.Parameter[] parameters = method.getParameters();\n        for (int i = 0; i < parameters.length; i++) {\n            java.lang.reflect.Parameter parameter = parameters[i];\n            String paramName;\n            McpToolParam mcpToolParam = parameter.getAnnotation(McpToolParam.class);\n            if (mcpToolParam != null && !mcpToolParam.name().isEmpty()) {\n                paramName = mcpToolParam.name();\n            } else if (parameter.isNamePresent()) {\n                paramName = parameter.getName();\n            } else {\n                paramName = McpConstant.DEFAULT_TOOL_NAME_PREFIX + i;\n            }\n            orderedJavaParameterNames.add(paramName);\n        }\n        return orderedJavaParameterNames;\n    }\n\n    private McpServerFeatures.AsyncToolSpecification createServiceToolSpecification(\n            McpSchema.Tool mcpTool, Operation operation, URL url) {\n\n        final MethodMeta methodMeta = operation.getMeta();\n        if (methodMeta == null) {\n            throw new IllegalStateException(\"MethodMeta not found in Operation for tool: \" + mcpTool.name());\n        }\n        final ServiceMeta serviceMeta = methodMeta.getServiceMeta();\n        final String interfaceName = serviceMeta.getServiceInterface();\n        final String methodName = methodMeta.getMethod().getName();\n        final Class<?>[] parameterClasses = methodMeta.getMethod().getParameterTypes();\n\n        final List<String> orderedJavaParameterNames = new ArrayList<>();\n        if (methodMeta.getParameters() != null) {\n            for (ParameterMeta javaParamMeta : methodMeta.getParameters()) {\n                orderedJavaParameterNames.add(javaParamMeta.getName());\n            }\n        }\n\n        final String group =\n                serviceMeta.getUrl() != null ? serviceMeta.getUrl().getGroup() : (url != null ? url.getGroup() : null);\n        final String version = serviceMeta.getUrl() != null\n                ? serviceMeta.getUrl().getVersion()\n                : (url != null ? url.getVersion() : null);\n\n        return getAsyncToolSpecification(\n                mcpTool, interfaceName, methodName, parameterClasses, orderedJavaParameterNames, group, version);\n    }\n\n    private String generateDefaultDescription(Method method, ProviderModel providerModel) {\n        return String.format(\n                McpConstant.DEFAULT_TOOL_DESCRIPTION_TEMPLATE,\n                method.getName(),\n                providerModel.getServiceModel().getInterfaceName());\n    }\n\n    private String generateToolSchema(Method method) {\n        Map<String, Object> schemaMap = new HashMap<>();\n        schemaMap.put(McpConstant.SCHEMA_PROPERTY_TYPE, JsonSchemaType.OBJECT_SCHEMA.getJsonSchemaType());\n\n        Map<String, Object> properties = new HashMap<>();\n        List<String> requiredParams = new ArrayList<>();\n\n        generateSchemaFromMethodSignature(method, properties, requiredParams);\n\n        schemaMap.put(McpConstant.SCHEMA_PROPERTY_PROPERTIES, properties);\n\n        if (!requiredParams.isEmpty()) {\n            schemaMap.put(McpConstant.SCHEMA_PROPERTY_REQUIRED, requiredParams);\n        }\n\n        try {\n            return objectMapper.writeValueAsString(schemaMap);\n        } catch (Exception e) {\n            logger.error(\n                    LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to generate tool schema for method \" + method.getName() + \": \" + e.getMessage(),\n                    e);\n            return \"{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{}}\";\n        }\n    }\n\n    private void generateSchemaFromMethodSignature(\n            Method method, Map<String, Object> properties, List<String> requiredParams) {\n        Class<?>[] paramTypes = method.getParameterTypes();\n        java.lang.reflect.Type[] genericTypes = method.getGenericParameterTypes();\n        java.lang.annotation.Annotation[][] parameterAnnotations = method.getParameterAnnotations();\n\n        for (int i = 0; i < paramTypes.length; i++) {\n            String paramName = null;\n            String paramDescription = null;\n            boolean isRequired = false;\n\n            for (java.lang.annotation.Annotation annotation : parameterAnnotations[i]) {\n                if (annotation instanceof McpToolParam mcpToolParam) {\n                    if (!mcpToolParam.name().isEmpty()) {\n                        paramName = mcpToolParam.name();\n                    }\n                    if (!mcpToolParam.description().isEmpty()) {\n                        paramDescription = mcpToolParam.description();\n                    }\n                    isRequired = mcpToolParam.required();\n                    break;\n                }\n            }\n\n            if (paramName == null) {\n                paramName = getParameterName(method, i);\n                if (paramName == null || paramName.isEmpty()) {\n                    paramName = McpConstant.DEFAULT_TOOL_NAME_PREFIX + i;\n                }\n            }\n\n            if (paramDescription == null) {\n                paramDescription = String.format(\n                        McpConstant.DEFAULT_PARAMETER_DESCRIPTION_TEMPLATE, i, paramTypes[i].getSimpleName());\n            }\n\n            TypeSchemaUtils.TypeSchemaInfo schemaInfo =\n                    TypeSchemaUtils.resolveTypeSchema(paramTypes[i], genericTypes[i], paramDescription);\n\n            properties.put(paramName, TypeSchemaUtils.toSchemaMap(schemaInfo));\n\n            if (isRequired) {\n                requiredParams.add(paramName);\n            }\n        }\n    }\n\n    private String getParameterName(Method method, int index) {\n        if (method.getParameters().length > index) {\n            return method.getParameters()[index].getName();\n        }\n        return null;\n    }\n\n    public void clearRegistry() {\n        for (String toolId : registeredTools.keySet()) {\n            try {\n                mcpServer.removeTool(toolId).block();\n            } catch (Exception e) {\n                logger.error(\n                        LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Failed to unregister MCP tool: \" + toolId,\n                        e);\n            }\n        }\n        registeredTools.clear();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/transport/DubboMcpSseTransportProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.transport;\n\nimport org.apache.dubbo.cache.support.expiring.ExpiringMap;\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.common.utils.IOUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.mcp.McpConstant;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.HttpResult;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.message.ServerSentEvent;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.modelcontextprotocol.spec.McpError;\nimport io.modelcontextprotocol.spec.McpSchema;\nimport io.modelcontextprotocol.spec.McpServerSession;\nimport io.modelcontextprotocol.spec.McpServerTransport;\nimport io.modelcontextprotocol.spec.McpServerTransportProvider;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\npublic class DubboMcpSseTransportProvider implements McpServerTransportProvider {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DubboMcpSseTransportProvider.class);\n\n    /**\n     * Event type for JSON-RPC messages sent through the SSE connection.\n     */\n    public static final String MESSAGE_EVENT_TYPE = \"message\";\n\n    /**\n     * Event type for sending the message endpoint URI to clients.\n     */\n    public static final String ENDPOINT_EVENT_TYPE = \"endpoint\";\n\n    private McpServerSession.Factory sessionFactory;\n\n    private final ObjectMapper objectMapper;\n\n    /**\n     * session cache, default expire time is 60 seconds\n     */\n    private final ExpiringMap<String, McpServerSession> sessions;\n\n    public DubboMcpSseTransportProvider(ObjectMapper objectMapper, Integer expireSeconds) {\n        if (expireSeconds != null) {\n            if (expireSeconds < 60) {\n                expireSeconds = 60;\n            }\n        } else {\n            expireSeconds = 60;\n        }\n        sessions = new ExpiringMap<>(expireSeconds, 30);\n        this.objectMapper = objectMapper;\n        sessions.getExpireThread().startExpiryIfNotStarted();\n    }\n\n    public DubboMcpSseTransportProvider(ObjectMapper objectMapper) {\n        this(objectMapper, 60);\n    }\n\n    @Override\n    public void setSessionFactory(McpServerSession.Factory sessionFactory) {\n        this.sessionFactory = sessionFactory;\n    }\n\n    @Override\n    public Mono<Void> notifyClients(String method, Object params) {\n        if (sessions.isEmpty()) {\n            return Mono.empty();\n        }\n        return Flux.fromIterable(sessions.values())\n                .flatMap(session -> session.sendNotification(method, params)\n                        .doOnError(e -> logger.error(\n                                COMMON_UNEXPECTED_EXCEPTION,\n                                \"\",\n                                \"\",\n                                String.format(\n                                        \"Failed to send message to session %s: %s\", session.getId(), e.getMessage()),\n                                e))\n                        .onErrorComplete())\n                .then();\n    }\n\n    @Override\n    public Mono<Void> closeGracefully() {\n        return Flux.fromIterable(sessions.values())\n                .flatMap(McpServerSession::closeGracefully)\n                .then();\n    }\n\n    public void handleRequest(StreamObserver<ServerSentEvent<String>> responseObserver) {\n        // Handle the request and return the response\n        HttpRequest request = RpcContext.getServiceContext().getRequest(HttpRequest.class);\n        if (HttpMethods.isGet(request.method())) {\n            handleSseConnection(responseObserver);\n        } else if (HttpMethods.isPost(request.method())) {\n            handleMessage();\n        }\n    }\n\n    public void handleMessage() {\n        HttpRequest request = RpcContext.getServiceContext().getRequest(HttpRequest.class);\n        String sessionId = request.parameter(\"sessionId\");\n        HttpResponse response = RpcContext.getServiceContext().getResponse(HttpResponse.class);\n        if (StringUtils.isBlank(sessionId)) {\n            throw HttpResult.of(HttpStatus.BAD_REQUEST, new McpError(\"Session ID missing in message endpoint\"))\n                    .toPayload();\n        }\n\n        McpServerSession session = sessions.get(sessionId);\n        if (session == null) {\n            throw HttpResult.of(HttpStatus.NOT_FOUND, \"Unknown sessionId: \" + sessionId)\n                    .toPayload();\n        }\n        refreshSessionExpire(session);\n        try {\n            McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(\n                    objectMapper, IOUtils.read(request.inputStream(), String.valueOf(StandardCharsets.UTF_8)));\n            session.handle(message).block();\n            response.setStatus(HttpStatus.OK.getCode());\n        } catch (IOException e) {\n            throw HttpResult.of(HttpStatus.INTERNAL_SERVER_ERROR, new McpError(\"Invalid message format\"))\n                    .toPayload();\n        }\n    }\n\n    private void handleSseConnection(StreamObserver<ServerSentEvent<String>> responseObserver) {\n        // Handle the SSE connection\n        // This is where you would set up the SSE stream and send events to the client\n        DubboMcpSessionTransport dubboMcpSessionTransport =\n                new DubboMcpSessionTransport(responseObserver, objectMapper);\n        McpServerSession mcpServerSession = sessionFactory.create(dubboMcpSessionTransport);\n        sessions.put(mcpServerSession.getId(), mcpServerSession);\n        Configuration conf = ConfigurationUtils.getGlobalConfiguration(ApplicationModel.defaultModel());\n        String messagePath = conf.getString(McpConstant.SETTINGS_MCP_PATHS_MESSAGE, \"/mcp/message\");\n        sendEvent(responseObserver, ENDPOINT_EVENT_TYPE, messagePath + \"?sessionId=\" + mcpServerSession.getId());\n    }\n\n    private void refreshSessionExpire(McpServerSession session) {\n        sessions.put(session.getId(), session);\n    }\n\n    private void sendEvent(StreamObserver<ServerSentEvent<String>> responseObserver, String eventType, String data) {\n        responseObserver.onNext(\n                ServerSentEvent.<String>builder().event(eventType).data(data).build());\n    }\n\n    private static class DubboMcpSessionTransport implements McpServerTransport {\n\n        private final ObjectMapper JSON;\n\n        private final StreamObserver<ServerSentEvent<String>> responseObserver;\n\n        public DubboMcpSessionTransport(\n                StreamObserver<ServerSentEvent<String>> responseObserver, ObjectMapper objectMapper) {\n            this.responseObserver = responseObserver;\n            this.JSON = objectMapper;\n        }\n\n        @Override\n        public void close() {\n            responseObserver.onCompleted();\n        }\n\n        @Override\n        public Mono<Void> closeGracefully() {\n            return Mono.fromRunnable(responseObserver::onCompleted);\n        }\n\n        @Override\n        public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {\n            return Mono.fromRunnable(() -> {\n                try {\n                    String jsonText = JSON.writeValueAsString(message);\n                    responseObserver.onNext(ServerSentEvent.<String>builder()\n                            .event(MESSAGE_EVENT_TYPE)\n                            .data(jsonText)\n                            .build());\n                } catch (Exception e) {\n                    responseObserver.onError(e);\n                }\n            });\n        }\n\n        @Override\n        public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {\n            return JSON.convertValue(data, typeRef);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/transport/DubboMcpStreamableTransportProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.transport;\n\nimport org.apache.dubbo.cache.support.expiring.ExpiringMap;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.IOUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.mcp.McpConstant;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.HttpResult;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.HttpUtils;\nimport org.apache.dubbo.remoting.http12.message.MediaType;\nimport org.apache.dubbo.remoting.http12.message.ServerSentEvent;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.modelcontextprotocol.spec.McpError;\nimport io.modelcontextprotocol.spec.McpSchema;\nimport io.modelcontextprotocol.spec.McpStreamableServerSession;\nimport io.modelcontextprotocol.spec.McpStreamableServerSession.Factory;\nimport io.modelcontextprotocol.spec.McpStreamableServerTransport;\nimport io.modelcontextprotocol.spec.McpStreamableServerTransportProvider;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;\n\n/**\n * Implementation of {@link McpStreamableServerTransportProvider} for the Dubbo MCP transport.\n * This class provides methods to manage streamable server sessions and notify clients.\n */\npublic class DubboMcpStreamableTransportProvider implements McpStreamableServerTransportProvider {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DubboMcpStreamableTransportProvider.class);\n\n    private Factory sessionFactory;\n\n    private final ObjectMapper objectMapper;\n\n    public static final String SESSION_ID_HEADER = \"mcp-session-id\";\n\n    private static final String LAST_EVENT_ID_HEADER = \"Last-Event-ID\";\n\n    /**\n     * TODO: This design is suboptimal. A mechanism should be implemented to remove the session object upon connection closure or timeout.\n     */\n    private final ExpiringMap<String, McpStreamableServerSession> sessions;\n\n    public DubboMcpStreamableTransportProvider(ObjectMapper objectMapper) {\n        this(objectMapper, McpConstant.DEFAULT_SESSION_TIMEOUT);\n    }\n\n    public DubboMcpStreamableTransportProvider(ObjectMapper objectMapper, Integer expireSeconds) {\n        // Minimum expiration time is 60 seconds\n        if (expireSeconds != null) {\n            if (expireSeconds < 60) {\n                expireSeconds = 60;\n            }\n        } else {\n            expireSeconds = 60;\n        }\n        sessions = new ExpiringMap<>(expireSeconds, 30);\n        this.objectMapper = objectMapper;\n        sessions.getExpireThread().startExpiryIfNotStarted();\n    }\n\n    @Override\n    public void setSessionFactory(Factory sessionFactory) {\n        this.sessionFactory = sessionFactory;\n    }\n\n    @Override\n    public Mono<Void> notifyClients(String method, Object params) {\n        if (sessions.isEmpty()) {\n            return Mono.empty();\n        }\n        return Flux.fromIterable(sessions.values())\n                .flatMap(session -> session.sendNotification(method, params)\n                        .doOnError(e -> logger.error(\n                                COMMON_UNEXPECTED_EXCEPTION,\n                                \"\",\n                                \"\",\n                                String.format(\n                                        \"Failed to send message to session %s: %s\", session.getId(), e.getMessage()),\n                                e))\n                        .onErrorComplete())\n                .then();\n    }\n\n    @Override\n    public Mono<Void> closeGracefully() {\n        return Flux.fromIterable(sessions.values())\n                .flatMap(McpStreamableServerSession::closeGracefully)\n                .then();\n    }\n\n    public void handleRequest(StreamObserver<ServerSentEvent<byte[]>> responseObserver) {\n        HttpRequest request = RpcContext.getServiceContext().getRequest(HttpRequest.class);\n        HttpResponse response = RpcContext.getServiceContext().getResponse(HttpResponse.class);\n\n        if (HttpMethods.isGet(request.method())) {\n            handleGet(responseObserver);\n        } else if (HttpMethods.isPost(request.method())) {\n            handlePost(responseObserver);\n        } else if (HttpMethods.DELETE.name().equals(request.method())) {\n            handleDelete(responseObserver);\n        } else {\n            // unSupport method\n            response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.getCode());\n            response.setBody(new McpError(\"Method not allowed: \" + request.method()).getJsonRpcError());\n            if (responseObserver != null) {\n                responseObserver.onError(HttpResult.builder()\n                        .status(HttpStatus.METHOD_NOT_ALLOWED.getCode())\n                        .body(new McpError(\"Method not allowed: \" + request.method()).getJsonRpcError())\n                        .build()\n                        .toPayload());\n                responseObserver.onCompleted();\n            }\n        }\n    }\n\n    private void handleGet(StreamObserver<ServerSentEvent<byte[]>> responseObserver) {\n        HttpRequest request = RpcContext.getServiceContext().getRequest(HttpRequest.class);\n        HttpResponse response = RpcContext.getServiceContext().getResponse(HttpResponse.class);\n\n        List<String> badRequestErrors = new ArrayList<>();\n\n        // check Accept header\n        List<String> accepts = HttpUtils.parseAccept(request.accept());\n        if (CollectionUtils.isEmpty(accepts)\n                || (!accepts.contains(MediaType.TEXT_EVENT_STREAM.getName())\n                        && !accepts.contains(MediaType.APPLICATION_JSON.getName()))) {\n            badRequestErrors.add(\"text/event-stream or application/json required in Accept header\");\n        }\n\n        // check sessionId\n        String sessionId = request.header(SESSION_ID_HEADER);\n        if (StringUtils.isBlank(sessionId)) {\n            badRequestErrors.add(\"Session ID required in mcp-session-id header\");\n        }\n\n        if (!badRequestErrors.isEmpty()) {\n            String combinedMessage = String.join(\"; \", badRequestErrors);\n            response.setStatus(HttpStatus.BAD_REQUEST.getCode());\n            response.setBody(new McpError(combinedMessage).getJsonRpcError());\n            if (responseObserver != null) {\n                responseObserver.onError(HttpResult.builder()\n                        .status(HttpStatus.BAD_REQUEST.getCode())\n                        .body(new McpError(combinedMessage).getJsonRpcError())\n                        .build()\n                        .toPayload());\n                responseObserver.onCompleted();\n            }\n            return;\n        }\n\n        // Find existing session\n        McpStreamableServerSession session = sessions.get(sessionId);\n        if (session == null) {\n            response.setStatus(HttpStatus.NOT_FOUND.getCode());\n            response.setBody(new McpError(\"Session not found\").getJsonRpcError());\n            if (responseObserver != null) {\n                responseObserver.onError(HttpResult.builder()\n                        .status(HttpStatus.NOT_FOUND.getCode())\n                        .body(new McpError(\"Session not found\").getJsonRpcError())\n                        .build()\n                        .toPayload());\n                responseObserver.onCompleted();\n            }\n            return;\n        }\n\n        // Check if this is a replay request\n        String lastEventId = request.header(LAST_EVENT_ID_HEADER);\n        if (StringUtils.isNotBlank(lastEventId)) {\n            // Handle replay request by calling session.replay()\n            try {\n                session.replay(lastEventId)\n                        .subscribe(\n                                message -> {\n                                    if (responseObserver != null) {\n                                        try {\n                                            String jsonData = objectMapper.writeValueAsString(message);\n                                            responseObserver.onNext(ServerSentEvent.<byte[]>builder()\n                                                    .event(\"message\")\n                                                    .data(jsonData.getBytes(StandardCharsets.UTF_8))\n                                                    .build());\n                                        } catch (Exception e) {\n                                            logger.error(\n                                                    COMMON_UNEXPECTED_EXCEPTION,\n                                                    \"\",\n                                                    \"\",\n                                                    String.format(\n                                                            \"Failed to serialize replay message for session %s: %s\",\n                                                            sessionId, e.getMessage()),\n                                                    e);\n                                        }\n                                    }\n                                },\n                                error -> {\n                                    logger.error(\n                                            COMMON_UNEXPECTED_EXCEPTION,\n                                            \"\",\n                                            \"\",\n                                            String.format(\n                                                    \"Failed to replay messages for session %s with lastEventId %s: %s\",\n                                                    sessionId, lastEventId, error.getMessage()),\n                                            error);\n                                    response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.getCode());\n                                    response.setBody(new McpError(\"Failed to replay messages: \" + error.getMessage())\n                                            .getJsonRpcError());\n                                    if (responseObserver != null) {\n                                        responseObserver.onError(HttpResult.builder()\n                                                .status(HttpStatus.INTERNAL_SERVER_ERROR.getCode())\n                                                .body(new McpError(\"Failed to replay messages: \" + error.getMessage())\n                                                        .getJsonRpcError())\n                                                .build()\n                                                .toPayload());\n                                        responseObserver.onCompleted();\n                                    }\n                                },\n                                () -> {\n                                    if (responseObserver != null) {\n                                        responseObserver.onCompleted();\n                                    }\n                                });\n            } catch (Exception e) {\n                logger.error(\n                        COMMON_UNEXPECTED_EXCEPTION,\n                        \"\",\n                        \"\",\n                        String.format(\n                                \"Failed to handle replay for session %s with lastEventId %s: %s\",\n                                sessionId, lastEventId, e.getMessage()),\n                        e);\n                response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.getCode());\n                response.setBody(new McpError(\"Failed to handle replay: \" + e.getMessage()).getJsonRpcError());\n                if (responseObserver != null) {\n                    responseObserver.onError(HttpResult.builder()\n                            .status(HttpStatus.INTERNAL_SERVER_ERROR.getCode())\n                            .body(new McpError(\"Failed to handle replay: \" + e.getMessage()).getJsonRpcError())\n                            .build()\n                            .toPayload());\n                    responseObserver.onCompleted();\n                }\n            }\n        } else {\n            // Send initial notification for new connection\n            session.sendNotification(\"tools\").subscribe();\n        }\n    }\n\n    private void handlePost(StreamObserver<ServerSentEvent<byte[]>> responseObserver) {\n        HttpRequest request = RpcContext.getServiceContext().getRequest(HttpRequest.class);\n        HttpResponse response = RpcContext.getServiceContext().getResponse(HttpResponse.class);\n\n        List<String> badRequestErrors = new ArrayList<>();\n        McpStreamableServerSession session = null;\n\n        try {\n            // Check Accept header\n            List<String> accepts = HttpUtils.parseAccept(request.accept());\n            if (CollectionUtils.isEmpty(accepts)\n                    || (!accepts.contains(MediaType.TEXT_EVENT_STREAM.getName())\n                            && !accepts.contains(MediaType.APPLICATION_JSON.getName()))) {\n                badRequestErrors.add(\"text/event-stream or application/json required in Accept header\");\n            }\n\n            // Read and deserialize JSON-RPC message from request body\n            String requestBody = IOUtils.read(request.inputStream(), StandardCharsets.UTF_8.name());\n            McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, requestBody);\n\n            // Check if it's an initialization request\n            if (message instanceof McpSchema.JSONRPCRequest\n                    && McpSchema.METHOD_INITIALIZE.equals(((McpSchema.JSONRPCRequest) message).method())) {\n                // New initialization request\n                if (!badRequestErrors.isEmpty()) {\n                    String combinedMessage = String.join(\"; \", badRequestErrors);\n                    response.setStatus(HttpStatus.BAD_REQUEST.getCode());\n                    response.setBody(new McpError(combinedMessage).getJsonRpcError());\n                    if (responseObserver != null) {\n                        responseObserver.onError(HttpResult.builder()\n                                .status(HttpStatus.BAD_REQUEST.getCode())\n                                .body(new McpError(combinedMessage).getJsonRpcError())\n                                .build()\n                                .toPayload());\n                        responseObserver.onCompleted();\n                    }\n                    return;\n                }\n\n                // Create new session\n                McpSchema.InitializeRequest initializeRequest = objectMapper.convertValue(\n                        ((McpSchema.JSONRPCRequest) message).params(), new TypeReference<>() {});\n\n                McpStreamableServerSession.McpStreamableServerSessionInit init =\n                        sessionFactory.startSession(initializeRequest);\n                session = init.session();\n                sessions.put(session.getId(), session);\n\n                try {\n                    McpSchema.InitializeResult initResult = init.initResult().block();\n\n                    response.setHeader(\"Content-Type\", MediaType.APPLICATION_JSON.getName());\n                    response.setHeader(SESSION_ID_HEADER, session.getId());\n                    response.setStatus(HttpStatus.OK.getCode());\n\n                    String jsonResponse = objectMapper.writeValueAsString(new McpSchema.JSONRPCResponse(\n                            McpSchema.JSONRPC_VERSION, ((McpSchema.JSONRPCRequest) message).id(), initResult, null));\n\n                    if (responseObserver != null) {\n                        responseObserver.onNext(ServerSentEvent.<byte[]>builder()\n                                .event(\"message\")\n                                .data(jsonResponse.getBytes(StandardCharsets.UTF_8))\n                                .build());\n                        responseObserver.onCompleted();\n                    }\n                    return;\n                } catch (Exception e) {\n                    response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.getCode());\n                    response.setBody(new McpError(\"Failed to initialize session: \" + e.getMessage()).getJsonRpcError());\n                    if (responseObserver != null) {\n                        responseObserver.onError(HttpResult.builder()\n                                .status(HttpStatus.INTERNAL_SERVER_ERROR.getCode())\n                                .body(new McpError(\"Failed to initialize session: \" + e.getMessage()).getJsonRpcError())\n                                .build()\n                                .toPayload());\n                        responseObserver.onCompleted();\n                    }\n                    return;\n                }\n            }\n\n            // Non-initialization request requires sessionId\n            String sessionId = request.header(SESSION_ID_HEADER);\n            if (StringUtils.isBlank(sessionId)) {\n                badRequestErrors.add(\"Session ID required in mcp-session-id header\");\n            }\n\n            if (!badRequestErrors.isEmpty()) {\n                String combinedMessage = String.join(\"; \", badRequestErrors);\n                response.setStatus(HttpStatus.BAD_REQUEST.getCode());\n                response.setBody(new McpError(combinedMessage).getJsonRpcError());\n                if (responseObserver != null) {\n                    responseObserver.onError(HttpResult.builder()\n                            .status(HttpStatus.BAD_REQUEST.getCode())\n                            .body(new McpError(combinedMessage).getJsonRpcError())\n                            .build()\n                            .toPayload());\n                    responseObserver.onCompleted();\n                }\n                return;\n            }\n\n            // Find existing session\n            session = sessions.get(sessionId);\n            if (session == null) {\n                response.setStatus(HttpStatus.NOT_FOUND.getCode());\n                response.setBody(new McpError(\"Unknown sessionId: \" + sessionId).getJsonRpcError());\n                if (responseObserver != null) {\n                    responseObserver.onError(HttpResult.builder()\n                            .status(HttpStatus.NOT_FOUND.getCode())\n                            .body(new McpError(\"Unknown sessionId: \" + sessionId).getJsonRpcError())\n                            .build()\n                            .toPayload());\n                    responseObserver.onCompleted();\n                }\n                return;\n            }\n\n            // Refresh session expiration time\n            refreshSessionExpire(session);\n\n            if (message instanceof McpSchema.JSONRPCResponse) {\n                session.accept((McpSchema.JSONRPCResponse) message).block();\n                response.setStatus(HttpStatus.ACCEPTED.getCode());\n                if (responseObserver != null) {\n                    responseObserver.onNext(ServerSentEvent.<byte[]>builder()\n                            .event(\"response\")\n                            .data(\"{\\\"status\\\":\\\"accepted\\\"}\".getBytes(StandardCharsets.UTF_8))\n                            .build());\n                    responseObserver.onCompleted();\n                }\n            } else if (message instanceof McpSchema.JSONRPCNotification) {\n                session.accept((McpSchema.JSONRPCNotification) message).block();\n                response.setStatus(HttpStatus.ACCEPTED.getCode());\n                if (responseObserver != null) {\n                    responseObserver.onNext(ServerSentEvent.<byte[]>builder()\n                            .event(\"response\")\n                            .data(\"{\\\"status\\\":\\\"accepted\\\"}\".getBytes(StandardCharsets.UTF_8))\n                            .build());\n                    responseObserver.onCompleted();\n                }\n            } else if (message instanceof McpSchema.JSONRPCRequest) {\n                // For streaming responses, we need to return SSE\n                response.setHeader(\"Content-Type\", MediaType.TEXT_EVENT_STREAM.getName());\n                response.setHeader(\"Cache-Control\", \"no-cache\");\n                response.setHeader(\"Connection\", \"keep-alive\");\n                response.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n\n                // Handle request stream\n                DubboMcpSessionTransport sessionTransport =\n                        new DubboMcpSessionTransport(responseObserver, objectMapper);\n                session.responseStream((McpSchema.JSONRPCRequest) message, sessionTransport)\n                        .block();\n            } else {\n                response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.getCode());\n                response.setBody(new McpError(\"Unknown message type\").getJsonRpcError());\n                if (responseObserver != null) {\n                    responseObserver.onError(HttpResult.builder()\n                            .status(HttpStatus.INTERNAL_SERVER_ERROR.getCode())\n                            .body(new McpError(\"Unknown message type\").getJsonRpcError())\n                            .build()\n                            .toPayload());\n                    responseObserver.onCompleted();\n                }\n            }\n\n        } catch (IOException e) {\n            response.setStatus(HttpStatus.BAD_REQUEST.getCode());\n            response.setBody(new McpError(\"Invalid message format: \" + e.getMessage()).getJsonRpcError());\n            if (responseObserver != null) {\n                responseObserver.onError(HttpResult.builder()\n                        .status(HttpStatus.BAD_REQUEST.getCode())\n                        .body(new McpError(\"Invalid message format: \" + e.getMessage()).getJsonRpcError())\n                        .build()\n                        .toPayload());\n                responseObserver.onCompleted();\n            }\n        } catch (Exception e) {\n            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.getCode());\n            response.setBody(new McpError(\"Internal server error: \" + e.getMessage()).getJsonRpcError());\n            if (responseObserver != null) {\n                responseObserver.onError(HttpResult.builder()\n                        .status(HttpStatus.INTERNAL_SERVER_ERROR.getCode())\n                        .body(new McpError(\"Internal server error: \" + e.getMessage()).getJsonRpcError())\n                        .build()\n                        .toPayload());\n                responseObserver.onCompleted();\n            }\n        }\n    }\n\n    private void handleDelete(StreamObserver<ServerSentEvent<byte[]>> responseObserver) {\n        HttpRequest request = RpcContext.getServiceContext().getRequest(HttpRequest.class);\n        HttpResponse response = RpcContext.getServiceContext().getResponse(HttpResponse.class);\n\n        String sessionId = request.header(SESSION_ID_HEADER);\n        if (StringUtils.isBlank(sessionId)) {\n            response.setStatus(HttpStatus.BAD_REQUEST.getCode());\n            response.setBody(new McpError(\"Session ID required in mcp-session-id header\").getJsonRpcError());\n            if (responseObserver != null) {\n                responseObserver.onError(HttpResult.builder()\n                        .status(HttpStatus.BAD_REQUEST.getCode())\n                        .body(new McpError(\"Session ID required in mcp-session-id header\").getJsonRpcError())\n                        .build()\n                        .toPayload());\n                responseObserver.onCompleted();\n            }\n            return;\n        }\n\n        McpStreamableServerSession session = sessions.get(sessionId);\n        if (session == null) {\n            response.setStatus(HttpStatus.NOT_FOUND.getCode());\n            if (responseObserver != null) {\n                responseObserver.onCompleted();\n            }\n            return;\n        }\n\n        try {\n            session.delete().block();\n            sessions.remove(sessionId);\n            response.setStatus(HttpStatus.OK.getCode());\n            if (responseObserver != null) {\n                responseObserver.onNext(ServerSentEvent.<byte[]>builder()\n                        .event(\"response\")\n                        .data(\"{\\\"status\\\":\\\"deleted\\\"}\".getBytes(StandardCharsets.UTF_8))\n                        .build());\n                responseObserver.onCompleted();\n            }\n        } catch (Exception e) {\n            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.getCode());\n            response.setBody(new McpError(e.getMessage()).getJsonRpcError());\n            if (responseObserver != null) {\n                responseObserver.onError(HttpResult.builder()\n                        .status(HttpStatus.INTERNAL_SERVER_ERROR.getCode())\n                        .body(new McpError(e.getMessage()).getJsonRpcError())\n                        .build()\n                        .toPayload());\n                responseObserver.onCompleted();\n            }\n        }\n    }\n\n    private void refreshSessionExpire(McpStreamableServerSession session) {\n        sessions.put(session.getId(), session);\n    }\n\n    private static class DubboMcpSessionTransport implements McpStreamableServerTransport {\n\n        private final ObjectMapper JSON;\n\n        private final StreamObserver<ServerSentEvent<byte[]>> responseObserver;\n\n        public DubboMcpSessionTransport(\n                StreamObserver<ServerSentEvent<byte[]>> responseObserver, ObjectMapper objectMapper) {\n            this.responseObserver = responseObserver;\n            this.JSON = objectMapper;\n        }\n\n        @Override\n        public void close() {\n            if (responseObserver != null) {\n                responseObserver.onCompleted();\n            }\n        }\n\n        @Override\n        public Mono<Void> closeGracefully() {\n            return Mono.fromRunnable(this::close);\n        }\n\n        @Override\n        public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {\n            return Mono.fromRunnable(() -> {\n                try {\n                    if (responseObserver != null) {\n                        String jsonText = JSON.writeValueAsString(message);\n                        responseObserver.onNext(ServerSentEvent.<byte[]>builder()\n                                .event(\"message\")\n                                .data(jsonText.getBytes(StandardCharsets.UTF_8))\n                                .build());\n                    }\n                } catch (Exception e) {\n                    responseObserver.onError(e);\n                }\n            });\n        }\n\n        @Override\n        public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message, String messageId) {\n            return Mono.fromRunnable(() -> {\n                try {\n                    if (responseObserver != null) {\n                        String jsonText = JSON.writeValueAsString(message);\n                        ServerSentEvent<byte[]> event = ServerSentEvent.<byte[]>builder()\n                                .event(\"message\")\n                                .data(jsonText.getBytes(StandardCharsets.UTF_8))\n                                .id(messageId)\n                                .build();\n                        responseObserver.onNext(event);\n                    }\n                } catch (Exception e) {\n                    responseObserver.onError(e);\n                }\n            });\n        }\n\n        @Override\n        public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {\n            return JSON.convertValue(data, typeRef);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/java/org/apache/dubbo/mcp/util/TypeSchemaUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.util;\n\nimport org.apache.dubbo.mcp.JsonSchemaType;\nimport org.apache.dubbo.mcp.McpConstant;\n\nimport java.lang.reflect.GenericArrayType;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.lang.reflect.WildcardType;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic final class TypeSchemaUtils {\n\n    public static TypeSchemaInfo resolveTypeSchema(Class<?> javaType, Type genericType, String description) {\n        TypeSchemaInfo.Builder builder =\n                TypeSchemaInfo.builder().description(description).javaType(javaType.getName());\n\n        if (isPrimitiveType(javaType)) {\n            return builder.type(getPrimitiveJsonSchemaType(javaType))\n                    .format(getFormatForType(javaType))\n                    .build();\n        }\n\n        if (javaType.isArray()) {\n            TypeSchemaInfo itemSchema =\n                    resolveTypeSchema(javaType.getComponentType(), javaType.getComponentType(), \"Array item\");\n            return builder.type(JsonSchemaType.ARRAY_SCHEMA.getJsonSchemaType())\n                    .items(itemSchema)\n                    .build();\n        }\n\n        if (genericType instanceof ParameterizedType) {\n            return resolveParameterizedType((ParameterizedType) genericType, javaType, description, builder);\n        }\n\n        if (java.util.Collection.class.isAssignableFrom(javaType)) {\n            return builder.type(JsonSchemaType.ARRAY_SCHEMA.getJsonSchemaType())\n                    .items(TypeSchemaInfo.builder()\n                            .type(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType())\n                            .description(\"Collection item\")\n                            .build())\n                    .build();\n        }\n\n        if (java.util.Map.class.isAssignableFrom(javaType)) {\n            return builder.type(JsonSchemaType.OBJECT_SCHEMA.getJsonSchemaType())\n                    .additionalProperties(TypeSchemaInfo.builder()\n                            .type(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType())\n                            .description(\"Map value\")\n                            .build())\n                    .build();\n        }\n\n        if (javaType.isEnum()) {\n            Object[] enumConstants = javaType.getEnumConstants();\n            List<String> enumValues = new ArrayList<>();\n            if (enumConstants != null) {\n                for (Object enumConstant : enumConstants) {\n                    enumValues.add(enumConstant.toString());\n                }\n            }\n            return builder.type(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType())\n                    .enumValues(enumValues)\n                    .build();\n        }\n\n        if (isDateTimeType(javaType)) {\n            return builder.type(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType())\n                    .format(getDateTimeFormat(javaType))\n                    .build();\n        }\n\n        return builder.type(JsonSchemaType.OBJECT_SCHEMA.getJsonSchemaType())\n                .description(\n                        description != null\n                                ? description + \" (POJO type: \" + javaType.getSimpleName() + \")\"\n                                : \"Complex object of type \" + javaType.getSimpleName())\n                .build();\n    }\n\n    private static TypeSchemaInfo resolveParameterizedType(\n            ParameterizedType paramType, Class<?> rawType, String description, TypeSchemaInfo.Builder builder) {\n\n        Type[] typeArgs = paramType.getActualTypeArguments();\n\n        if (java.util.Collection.class.isAssignableFrom(rawType)) {\n            TypeSchemaInfo itemSchema;\n            if (typeArgs.length > 0) {\n                Class<?> itemType = getClassFromType(typeArgs[0]);\n                itemSchema = resolveTypeSchema(itemType, typeArgs[0], \"Collection item\");\n            } else {\n                itemSchema = TypeSchemaInfo.builder()\n                        .type(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType())\n                        .description(\"Collection item\")\n                        .build();\n            }\n            return builder.type(JsonSchemaType.ARRAY_SCHEMA.getJsonSchemaType())\n                    .items(itemSchema)\n                    .build();\n        }\n\n        if (java.util.Map.class.isAssignableFrom(rawType)) {\n            TypeSchemaInfo valueSchema;\n            if (typeArgs.length > 1) {\n                Class<?> valueType = getClassFromType(typeArgs[1]);\n                valueSchema = resolveTypeSchema(valueType, typeArgs[1], \"Map value\");\n            } else {\n                valueSchema = TypeSchemaInfo.builder()\n                        .type(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType())\n                        .description(\"Map value\")\n                        .build();\n            }\n            return builder.type(JsonSchemaType.OBJECT_SCHEMA.getJsonSchemaType())\n                    .additionalProperties(valueSchema)\n                    .build();\n        }\n\n        return builder.type(JsonSchemaType.OBJECT_SCHEMA.getJsonSchemaType())\n                .description(\n                        description != null\n                                ? description + \" (Generic type: \" + rawType.getSimpleName() + \")\"\n                                : \"Complex generic object of type \" + rawType.getSimpleName())\n                .build();\n    }\n\n    public static Map<String, Object> toSchemaMap(TypeSchemaInfo schemaInfo) {\n        Map<String, Object> schemaMap = new HashMap<>();\n\n        schemaMap.put(McpConstant.SCHEMA_PROPERTY_TYPE, schemaInfo.getType());\n\n        if (schemaInfo.getFormat() != null) {\n            schemaMap.put(McpConstant.SCHEMA_PROPERTY_FORMAT, schemaInfo.getFormat());\n        }\n\n        if (schemaInfo.getDescription() != null) {\n            schemaMap.put(McpConstant.SCHEMA_PROPERTY_DESCRIPTION, schemaInfo.getDescription());\n        }\n\n        if (schemaInfo.getEnumValues() != null && !schemaInfo.getEnumValues().isEmpty()) {\n            schemaMap.put(McpConstant.SCHEMA_PROPERTY_ENUM, schemaInfo.getEnumValues());\n        }\n\n        if (schemaInfo.getItems() != null) {\n            schemaMap.put(McpConstant.SCHEMA_PROPERTY_ITEMS, toSchemaMap(schemaInfo.getItems()));\n        }\n\n        if (schemaInfo.getAdditionalProperties() != null) {\n            schemaMap.put(\n                    McpConstant.SCHEMA_PROPERTY_ADDITIONAL_PROPERTIES,\n                    toSchemaMap(schemaInfo.getAdditionalProperties()));\n        }\n\n        return schemaMap;\n    }\n\n    public static TypeSchemaInfo resolveNestedType(Type type, String description) {\n        if (type instanceof Class) {\n            return resolveTypeSchema((Class<?>) type, type, description);\n        }\n\n        if (type instanceof ParameterizedType paramType) {\n            Class<?> rawType = (Class<?>) paramType.getRawType();\n            return resolveTypeSchema(rawType, type, description);\n        }\n\n        if (type instanceof TypeVariable) {\n            Type[] bounds = ((TypeVariable<?>) type).getBounds();\n            if (bounds.length > 0) {\n                return resolveNestedType(bounds[0], description);\n            }\n        }\n\n        if (type instanceof WildcardType) {\n            Type[] upperBounds = ((WildcardType) type).getUpperBounds();\n            if (upperBounds.length > 0) {\n                return resolveNestedType(upperBounds[0], description);\n            }\n        }\n\n        if (type instanceof GenericArrayType) {\n            Type componentType = ((GenericArrayType) type).getGenericComponentType();\n            TypeSchemaInfo itemSchema = resolveNestedType(componentType, \"Array item\");\n            return TypeSchemaInfo.builder()\n                    .type(JsonSchemaType.ARRAY_SCHEMA.getJsonSchemaType())\n                    .items(itemSchema)\n                    .description(description)\n                    .build();\n        }\n\n        // Fallback to object type\n        return TypeSchemaInfo.builder()\n                .type(JsonSchemaType.OBJECT_SCHEMA.getJsonSchemaType())\n                .description(description != null ? description : \"Unknown type\")\n                .build();\n    }\n\n    public static boolean isPrimitiveType(Class<?> type) {\n        return JsonSchemaType.fromJavaType(type) != null;\n    }\n\n    public static String getPrimitiveJsonSchemaType(Class<?> javaType) {\n        JsonSchemaType mapping = JsonSchemaType.fromJavaType(javaType);\n        return mapping != null ? mapping.getJsonSchemaType() : JsonSchemaType.STRING_SCHEMA.getJsonSchemaType();\n    }\n\n    public static String getFormatForType(Class<?> javaType) {\n        JsonSchemaType mapping = JsonSchemaType.fromJavaType(javaType);\n        return mapping != null ? mapping.getJsonSchemaFormat() : null;\n    }\n\n    public static boolean isDateTimeType(Class<?> type) {\n        return java.util.Date.class.isAssignableFrom(type)\n                || java.time.temporal.Temporal.class.isAssignableFrom(type)\n                || java.util.Calendar.class.isAssignableFrom(type);\n    }\n\n    public static String getDateTimeFormat(Class<?> type) {\n        if (java.time.LocalDate.class.isAssignableFrom(type)) {\n            return JsonSchemaType.DATE_FORMAT.getJsonSchemaFormat();\n        }\n        if (java.time.LocalTime.class.isAssignableFrom(type) || java.time.OffsetTime.class.isAssignableFrom(type)) {\n            return JsonSchemaType.TIME_FORMAT.getJsonSchemaFormat();\n        }\n        return JsonSchemaType.DATE_TIME_FORMAT.getJsonSchemaFormat();\n    }\n\n    public static Class<?> getClassFromType(Type type) {\n        if (type instanceof Class) {\n            return (Class<?>) type;\n        }\n        if (type instanceof ParameterizedType) {\n            return (Class<?>) ((ParameterizedType) type).getRawType();\n        }\n        if (type instanceof GenericArrayType) {\n            Type componentType = ((GenericArrayType) type).getGenericComponentType();\n            Class<?> componentClass = getClassFromType(componentType);\n            return java.lang.reflect.Array.newInstance(componentClass, 0).getClass();\n        }\n        if (type instanceof TypeVariable) {\n            Type[] bounds = ((TypeVariable<?>) type).getBounds();\n            if (bounds.length > 0) {\n                return getClassFromType(bounds[0]);\n            }\n        }\n        if (type instanceof WildcardType) {\n            Type[] upperBounds = ((WildcardType) type).getUpperBounds();\n            if (upperBounds.length > 0) {\n                return getClassFromType(upperBounds[0]);\n            }\n        }\n        return Object.class;\n    }\n\n    public static boolean isPrimitiveOrWrapper(Class<?> type) {\n        return isPrimitiveType(type);\n    }\n\n    public static class TypeSchemaInfo {\n        private final String type;\n        private final String format;\n        private final String description;\n        private final String javaType;\n        private final List<String> enumValues;\n        private final TypeSchemaInfo items;\n        private final TypeSchemaInfo additionalProperties;\n\n        private TypeSchemaInfo(Builder builder) {\n            this.type = builder.type;\n            this.format = builder.format;\n            this.description = builder.description;\n            this.javaType = builder.javaType;\n            this.enumValues = builder.enumValues;\n            this.items = builder.items;\n            this.additionalProperties = builder.additionalProperties;\n        }\n\n        public static Builder builder() {\n            return new Builder();\n        }\n\n        public String getType() {\n            return type;\n        }\n\n        public String getFormat() {\n            return format;\n        }\n\n        public String getDescription() {\n            return description;\n        }\n\n        public String getJavaType() {\n            return javaType;\n        }\n\n        public List<String> getEnumValues() {\n            return enumValues;\n        }\n\n        public TypeSchemaInfo getItems() {\n            return items;\n        }\n\n        public TypeSchemaInfo getAdditionalProperties() {\n            return additionalProperties;\n        }\n\n        public static class Builder {\n            private String type;\n            private String format;\n            private String description;\n            private String javaType;\n            private List<String> enumValues;\n            private TypeSchemaInfo items;\n            private TypeSchemaInfo additionalProperties;\n\n            public Builder type(String type) {\n                this.type = type;\n                return this;\n            }\n\n            public Builder format(String format) {\n                this.format = format;\n                return this;\n            }\n\n            public Builder description(String description) {\n                this.description = description;\n                return this;\n            }\n\n            public Builder javaType(String javaType) {\n                this.javaType = javaType;\n                return this;\n            }\n\n            public Builder enumValues(List<String> enumValues) {\n                this.enumValues = enumValues;\n                return this;\n            }\n\n            public Builder items(TypeSchemaInfo items) {\n                this.items = items;\n                return this;\n            }\n\n            public Builder additionalProperties(TypeSchemaInfo additionalProperties) {\n                this.additionalProperties = additionalProperties;\n                return this;\n            }\n\n            public TypeSchemaInfo build() {\n                return new TypeSchemaInfo(this);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.deploy.ApplicationDeployListener",
    "content": "mcpToolRegister=org.apache.dubbo.mcp.core.McpApplicationDeployListener\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.ServiceListener",
    "content": "mcpServiceExportListener=org.apache.dubbo.mcp.core.McpServiceExportListener "
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/JsonSchemaTypeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass JsonSchemaTypeTest {\n\n    @Test\n    void testBooleanTypes() {\n        assertEquals(\"boolean\", JsonSchemaType.BOOLEAN.getJsonSchemaType());\n        assertEquals(boolean.class, JsonSchemaType.BOOLEAN.getJavaType());\n        assertNull(JsonSchemaType.BOOLEAN.getJsonSchemaFormat());\n\n        assertEquals(\"boolean\", JsonSchemaType.BOOLEAN_OBJ.getJsonSchemaType());\n        assertEquals(Boolean.class, JsonSchemaType.BOOLEAN_OBJ.getJavaType());\n    }\n\n    @Test\n    void testIntegerTypes() {\n        assertEquals(\"integer\", JsonSchemaType.INT.getJsonSchemaType());\n        assertEquals(int.class, JsonSchemaType.INT.getJavaType());\n        assertNull(JsonSchemaType.INT.getJsonSchemaFormat());\n\n        assertEquals(\"integer\", JsonSchemaType.LONG.getJsonSchemaType());\n        assertEquals(long.class, JsonSchemaType.LONG.getJavaType());\n        assertEquals(\"int64\", JsonSchemaType.LONG.getJsonSchemaFormat());\n\n        assertEquals(\"integer\", JsonSchemaType.BIG_INTEGER.getJsonSchemaType());\n        assertEquals(BigInteger.class, JsonSchemaType.BIG_INTEGER.getJavaType());\n        assertEquals(\"int64\", JsonSchemaType.BIG_INTEGER.getJsonSchemaFormat());\n    }\n\n    @Test\n    void testNumberTypes() {\n        assertEquals(\"number\", JsonSchemaType.FLOAT.getJsonSchemaType());\n        assertEquals(float.class, JsonSchemaType.FLOAT.getJavaType());\n        assertEquals(\"float\", JsonSchemaType.FLOAT.getJsonSchemaFormat());\n\n        assertEquals(\"number\", JsonSchemaType.DOUBLE.getJsonSchemaType());\n        assertEquals(double.class, JsonSchemaType.DOUBLE.getJavaType());\n        assertEquals(\"double\", JsonSchemaType.DOUBLE.getJsonSchemaFormat());\n\n        assertEquals(\"number\", JsonSchemaType.BIG_DECIMAL.getJsonSchemaType());\n        assertEquals(BigDecimal.class, JsonSchemaType.BIG_DECIMAL.getJavaType());\n        assertNull(JsonSchemaType.BIG_DECIMAL.getJsonSchemaFormat());\n    }\n\n    @Test\n    void testStringTypes() {\n        assertEquals(\"string\", JsonSchemaType.STRING.getJsonSchemaType());\n        assertEquals(String.class, JsonSchemaType.STRING.getJavaType());\n        assertNull(JsonSchemaType.STRING.getJsonSchemaFormat());\n\n        assertEquals(\"string\", JsonSchemaType.CHAR.getJsonSchemaType());\n        assertEquals(char.class, JsonSchemaType.CHAR.getJavaType());\n\n        assertEquals(\"string\", JsonSchemaType.BYTE_ARRAY.getJsonSchemaType());\n        assertEquals(byte[].class, JsonSchemaType.BYTE_ARRAY.getJavaType());\n        assertEquals(\"byte\", JsonSchemaType.BYTE_ARRAY.getJsonSchemaFormat());\n    }\n\n    @Test\n    void testGenericSchemaTypes() {\n        assertEquals(\"object\", JsonSchemaType.OBJECT_SCHEMA.getJsonSchemaType());\n        assertNull(JsonSchemaType.OBJECT_SCHEMA.getJavaType());\n\n        assertEquals(\"array\", JsonSchemaType.ARRAY_SCHEMA.getJsonSchemaType());\n        assertNull(JsonSchemaType.ARRAY_SCHEMA.getJavaType());\n\n        assertEquals(\"string\", JsonSchemaType.STRING_SCHEMA.getJsonSchemaType());\n        assertNull(JsonSchemaType.STRING_SCHEMA.getJavaType());\n    }\n\n    @Test\n    void testDateTimeFormats() {\n        assertEquals(\"date\", JsonSchemaType.DATE_FORMAT.getJsonSchemaFormat());\n        assertNull(JsonSchemaType.DATE_FORMAT.getJsonSchemaType());\n\n        assertEquals(\"time\", JsonSchemaType.TIME_FORMAT.getJsonSchemaFormat());\n        assertNull(JsonSchemaType.TIME_FORMAT.getJsonSchemaType());\n\n        assertEquals(\"date-time\", JsonSchemaType.DATE_TIME_FORMAT.getJsonSchemaFormat());\n        assertNull(JsonSchemaType.DATE_TIME_FORMAT.getJsonSchemaType());\n    }\n\n    @Test\n    void testFromJavaType() {\n        assertEquals(JsonSchemaType.STRING, JsonSchemaType.fromJavaType(String.class));\n        assertEquals(JsonSchemaType.INT, JsonSchemaType.fromJavaType(int.class));\n        assertEquals(JsonSchemaType.INTEGER_OBJ, JsonSchemaType.fromJavaType(Integer.class));\n        assertEquals(JsonSchemaType.BOOLEAN, JsonSchemaType.fromJavaType(boolean.class));\n        assertEquals(JsonSchemaType.DOUBLE, JsonSchemaType.fromJavaType(double.class));\n        assertEquals(JsonSchemaType.BIG_DECIMAL, JsonSchemaType.fromJavaType(BigDecimal.class));\n\n        assertNull(JsonSchemaType.fromJavaType(Object.class));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/annotations/McpToolTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.annotations;\n\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass McpToolTest {\n\n    static class TestService {\n        @McpTool\n        public void defaultMethod() {}\n\n        @McpTool(\n                enabled = false,\n                name = \"customTool\",\n                description = \"Test description\",\n                tags = {\"tag1\", \"tag2\"},\n                priority = 10)\n        public void customMethod() {}\n\n        @McpTool(enabled = true)\n        public void enabledMethod() {}\n\n        public void normalMethod(\n                @McpToolParam String param1,\n                @McpToolParam(name = \"customParam\", description = \"Custom param\", required = true) String param2) {}\n    }\n\n    @Test\n    void testMcpToolDefaultValues() throws NoSuchMethodException {\n        Method method = TestService.class.getMethod(\"defaultMethod\");\n        McpTool annotation = method.getAnnotation(McpTool.class);\n\n        assertNotNull(annotation);\n        assertTrue(annotation.enabled());\n        assertEquals(\"\", annotation.name());\n        assertEquals(\"\", annotation.description());\n        assertEquals(0, annotation.tags().length);\n        assertEquals(0, annotation.priority());\n    }\n\n    @Test\n    void testMcpToolCustomValues() throws NoSuchMethodException {\n        Method method = TestService.class.getMethod(\"customMethod\");\n        McpTool annotation = method.getAnnotation(McpTool.class);\n\n        assertNotNull(annotation);\n        assertFalse(annotation.enabled());\n        assertEquals(\"customTool\", annotation.name());\n        assertEquals(\"Test description\", annotation.description());\n        assertEquals(2, annotation.tags().length);\n        assertEquals(\"tag1\", annotation.tags()[0]);\n        assertEquals(\"tag2\", annotation.tags()[1]);\n        assertEquals(10, annotation.priority());\n    }\n\n    @Test\n    void testMcpToolEnabledTrue() throws NoSuchMethodException {\n        Method method = TestService.class.getMethod(\"enabledMethod\");\n        McpTool annotation = method.getAnnotation(McpTool.class);\n\n        assertNotNull(annotation);\n        assertTrue(annotation.enabled());\n    }\n\n    @Test\n    void testMcpToolParamDefaultValues() throws NoSuchMethodException {\n        Method method = TestService.class.getMethod(\"normalMethod\", String.class, String.class);\n        McpToolParam[] paramAnnotations = method.getParameters()[0].getAnnotationsByType(McpToolParam.class);\n\n        assertEquals(1, paramAnnotations.length);\n        McpToolParam annotation = paramAnnotations[0];\n\n        assertEquals(\"\", annotation.name());\n        assertEquals(\"\", annotation.description());\n        assertFalse(annotation.required());\n    }\n\n    @Test\n    void testMcpToolParamCustomValues() throws NoSuchMethodException {\n        Method method = TestService.class.getMethod(\"normalMethod\", String.class, String.class);\n        McpToolParam[] paramAnnotations = method.getParameters()[1].getAnnotationsByType(McpToolParam.class);\n\n        assertEquals(1, paramAnnotations.length);\n        McpToolParam annotation = paramAnnotations[0];\n\n        assertEquals(\"customParam\", annotation.name());\n        assertEquals(\"Custom param\", annotation.description());\n        assertTrue(annotation.required());\n    }\n\n    @Test\n    void testMethodWithoutAnnotation() throws NoSuchMethodException {\n        Method method = TestService.class.getMethod(\"normalMethod\", String.class, String.class);\n        McpTool annotation = method.getAnnotation(McpTool.class);\n\n        assertNull(annotation);\n    }\n\n    @Test\n    void testAnnotationPresence() {\n        assertTrue(McpTool.class.isAnnotationPresent(java.lang.annotation.Documented.class));\n        assertTrue(McpTool.class.isAnnotationPresent(java.lang.annotation.Retention.class));\n        assertTrue(McpTool.class.isAnnotationPresent(java.lang.annotation.Target.class));\n\n        assertTrue(McpToolParam.class.isAnnotationPresent(java.lang.annotation.Documented.class));\n        assertTrue(McpToolParam.class.isAnnotationPresent(java.lang.annotation.Retention.class));\n        assertTrue(McpToolParam.class.isAnnotationPresent(java.lang.annotation.Target.class));\n    }\n\n    @Test\n    void testAnnotationRetentionAndTarget() {\n        java.lang.annotation.Retention retention = McpTool.class.getAnnotation(java.lang.annotation.Retention.class);\n        assertEquals(java.lang.annotation.RetentionPolicy.RUNTIME, retention.value());\n\n        java.lang.annotation.Target target = McpTool.class.getAnnotation(java.lang.annotation.Target.class);\n        assertEquals(1, target.value().length);\n        assertEquals(java.lang.annotation.ElementType.METHOD, target.value()[0]);\n\n        java.lang.annotation.Retention paramRetention =\n                McpToolParam.class.getAnnotation(java.lang.annotation.Retention.class);\n        assertEquals(java.lang.annotation.RetentionPolicy.RUNTIME, paramRetention.value());\n\n        java.lang.annotation.Target paramTarget = McpToolParam.class.getAnnotation(java.lang.annotation.Target.class);\n        assertEquals(2, paramTarget.value().length);\n        assertTrue(java.util.Arrays.asList(paramTarget.value()).contains(java.lang.annotation.ElementType.PARAMETER));\n        assertTrue(java.util.Arrays.asList(paramTarget.value()).contains(java.lang.annotation.ElementType.FIELD));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/core/McpApplicationDeployListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.core;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass McpApplicationDeployListenerTest {\n\n    @Mock\n    private ApplicationModel applicationModel;\n\n    private McpApplicationDeployListener listener;\n\n    @BeforeEach\n    void setUp() {\n        MockitoAnnotations.openMocks(this);\n        listener = new McpApplicationDeployListener();\n    }\n\n    @Test\n    void testOnInitialize() {\n        assertDoesNotThrow(() -> listener.onInitialize(applicationModel));\n    }\n\n    @Test\n    void testOnStarting() {\n        assertDoesNotThrow(() -> listener.onStarting(applicationModel));\n    }\n\n    @Test\n    void testOnStarted_WithNullModel() {\n\n        assertDoesNotThrow(() -> listener.onStarted(null));\n    }\n\n    @Test\n    void testOnStarted_WithMockModel() {\n        assertThrows(NullPointerException.class, () -> listener.onStarted(applicationModel));\n    }\n\n    @Test\n    void testOnStopping() {\n\n        assertDoesNotThrow(() -> listener.onStopping(applicationModel));\n    }\n\n    @Test\n    void testOnStopped() {\n\n        assertDoesNotThrow(() -> listener.onStopped(applicationModel));\n    }\n\n    @Test\n    void testOnFailure() {\n        Throwable cause = new RuntimeException(\"Test failure\");\n\n        assertDoesNotThrow(() -> listener.onFailure(applicationModel, cause));\n    }\n\n    @Test\n    void testGetDubboMcpSseTransportProvider() {\n\n        assertDoesNotThrow(() -> McpApplicationDeployListener.getDubboMcpSseTransportProvider());\n    }\n\n    @Test\n    void testListenerCreation() {\n\n        McpApplicationDeployListener newListener = new McpApplicationDeployListener();\n        assertNotNull(newListener);\n    }\n\n    @Test\n    void testBasicLifecycleMethods() {\n\n        assertDoesNotThrow(() -> {\n            listener.onInitialize(applicationModel);\n            listener.onStarting(applicationModel);\n            listener.onStopping(applicationModel);\n            listener.onStopped(applicationModel);\n            listener.onFailure(applicationModel, new Exception(\"test\"));\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/core/McpServiceExportListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.core;\n\nimport org.apache.dubbo.config.ServiceConfig;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.junit.jupiter.api.Assertions.*;\nimport static org.mockito.Mockito.*;\n\nclass McpServiceExportListenerTest {\n\n    @Mock\n    private ServiceConfig serviceConfig;\n\n    private McpServiceExportListener listener;\n\n    @BeforeEach\n    void setUp() {\n        MockitoAnnotations.openMocks(this);\n        listener = new McpServiceExportListener();\n    }\n\n    @Test\n    void testExported_WithNullRef() {\n        when(serviceConfig.getRef()).thenReturn(null);\n\n        listener.exported(serviceConfig);\n\n        verify(serviceConfig).getRef();\n        verify(serviceConfig, never()).getUniqueServiceName();\n    }\n\n    @Test\n    void testUnexported_WithNullRef() {\n        when(serviceConfig.getRef()).thenReturn(null);\n\n        listener.unexported(serviceConfig);\n\n        verify(serviceConfig).getRef();\n        verify(serviceConfig, never()).getUniqueServiceName();\n    }\n\n    @Test\n    void testExported_WithValidRef() {\n        Object serviceRef = new TestService();\n        when(serviceConfig.getRef()).thenReturn(serviceRef);\n        when(serviceConfig.getUniqueServiceName()).thenReturn(\"test.service\");\n\n        assertDoesNotThrow(() -> listener.exported(serviceConfig));\n\n        verify(serviceConfig).getRef();\n        verify(serviceConfig).getUniqueServiceName();\n    }\n\n    @Test\n    void testUnexported_WithValidRef() {\n        Object serviceRef = new TestService();\n        when(serviceConfig.getRef()).thenReturn(serviceRef);\n        when(serviceConfig.getUniqueServiceName()).thenReturn(\"test.service\");\n\n        assertDoesNotThrow(() -> listener.unexported(serviceConfig));\n\n        verify(serviceConfig).getRef();\n        verify(serviceConfig).getUniqueServiceName();\n    }\n\n    @Test\n    void testExported_WithException() {\n        when(serviceConfig.getRef()).thenReturn(new TestService());\n        when(serviceConfig.getUniqueServiceName()).thenThrow(new RuntimeException(\"Test exception\"));\n\n        assertDoesNotThrow(() -> listener.exported(serviceConfig));\n\n        verify(serviceConfig).getRef();\n        verify(serviceConfig).getUniqueServiceName();\n    }\n\n    @Test\n    void testUnexported_WithException() {\n        when(serviceConfig.getRef()).thenReturn(new TestService());\n        when(serviceConfig.getUniqueServiceName()).thenThrow(new RuntimeException(\"Test exception\"));\n\n        assertDoesNotThrow(() -> listener.unexported(serviceConfig));\n\n        verify(serviceConfig).getRef();\n        verify(serviceConfig).getUniqueServiceName();\n    }\n\n    @Test\n    void testListenerCreation() {\n\n        McpServiceExportListener newListener = new McpServiceExportListener();\n        assertNotNull(newListener);\n    }\n\n    public static class TestService {\n        public void testMethod() {\n            // Test method\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/core/McpServiceFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.core;\n\nimport org.apache.dubbo.config.annotation.DubboService;\nimport org.apache.dubbo.mcp.annotations.McpTool;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass McpServiceFilterTest {\n\n    @Mock\n    private ApplicationModel applicationModel;\n\n    private McpServiceFilter mcpServiceFilter;\n\n    @BeforeEach\n    void setUp() {\n        MockitoAnnotations.openMocks(this);\n        try {\n            mcpServiceFilter = new McpServiceFilter(ApplicationModel.defaultModel());\n        } catch (Exception e) {\n            mcpServiceFilter = null;\n        }\n    }\n\n    @Test\n    void testMcpToolConfig_SettersAndGetters() {\n        McpServiceFilter.McpToolConfig config = new McpServiceFilter.McpToolConfig();\n\n        config.setToolName(\"testTool\");\n        assertEquals(\"testTool\", config.getToolName());\n\n        config.setDescription(\"Test description\");\n        assertEquals(\"Test description\", config.getDescription());\n\n        config.setPriority(10);\n        assertEquals(10, config.getPriority());\n    }\n\n    @Test\n    void testMcpToolConfig_DefaultValues() {\n        McpServiceFilter.McpToolConfig config = new McpServiceFilter.McpToolConfig();\n\n        assertNull(config.getToolName());\n        assertNull(config.getDescription());\n        assertEquals(0, config.getPriority());\n    }\n\n    @Test\n    void testTestServiceAnnotations() throws NoSuchMethodException {\n\n        Class<?> testServiceClass = TestServiceImpl.class;\n        assertTrue(testServiceClass.isAnnotationPresent(DubboService.class));\n\n        Method annotatedMethod = testServiceClass.getMethod(\"annotatedMethod\");\n        assertTrue(annotatedMethod.isAnnotationPresent(McpTool.class));\n\n        McpTool mcpTool = annotatedMethod.getAnnotation(McpTool.class);\n        assertEquals(\"customTool\", mcpTool.name());\n        assertEquals(\"Custom tool description\", mcpTool.description());\n        assertEquals(5, mcpTool.priority());\n    }\n\n    @Test\n    void testDisabledMethodAnnotation() throws NoSuchMethodException {\n        Method disabledMethod = TestServiceImpl.class.getMethod(\"disabledMethod\");\n        assertTrue(disabledMethod.isAnnotationPresent(McpTool.class));\n\n        McpTool mcpTool = disabledMethod.getAnnotation(McpTool.class);\n        assertFalse(mcpTool.enabled());\n    }\n\n    @Test\n    void testPublicMethodExists() throws NoSuchMethodException {\n        Method publicMethod = TestServiceImpl.class.getMethod(\"publicMethod\");\n        assertNotNull(publicMethod);\n        assertTrue(java.lang.reflect.Modifier.isPublic(publicMethod.getModifiers()));\n    }\n\n    @Test\n    void testServiceImplementsInterface() {\n        TestServiceImpl impl = new TestServiceImpl();\n        assertTrue(impl instanceof TestService);\n    }\n\n    @DubboService\n    public static class TestServiceImpl implements TestService {\n\n        public void publicMethod() {}\n\n        @McpTool(name = \"customTool\", description = \"Custom tool description\", priority = 5)\n        public void annotatedMethod() {}\n\n        @McpTool(enabled = false)\n        public void disabledMethod() {}\n\n        private void privateMethod() {}\n    }\n\n    public interface TestService {\n        void publicMethod();\n\n        void annotatedMethod();\n\n        void disabledMethod();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/tool/DubboMcpGenericCallerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.tool;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.junit.jupiter.api.Assertions.*;\nimport static org.mockito.Mockito.*;\n\nclass DubboMcpGenericCallerTest {\n\n    @Mock\n    private ApplicationModel applicationModel;\n\n    @Mock\n    private ApplicationConfig applicationConfig;\n\n    private DubboMcpGenericCaller genericCaller;\n\n    @BeforeEach\n    void setUp() {\n        MockitoAnnotations.openMocks(this);\n    }\n\n    @Test\n    void testConstructor_WithValidApplicationModel() {\n        when(applicationModel.getCurrentConfig()).thenReturn(applicationConfig);\n\n        assertDoesNotThrow(() -> {\n            genericCaller = new DubboMcpGenericCaller(applicationModel);\n        });\n    }\n\n    @Test\n    void testConstructor_WithNullApplicationModel() {\n        assertThrows(IllegalArgumentException.class, () -> {\n            new DubboMcpGenericCaller(null);\n        });\n    }\n\n    @Test\n    void testConstructor_WithNullApplicationConfig() {\n        when(applicationModel.getCurrentConfig()).thenReturn(null);\n        when(applicationModel.getApplicationName()).thenReturn(\"TestApp\");\n\n        assertThrows(IllegalStateException.class, () -> {\n            new DubboMcpGenericCaller(applicationModel);\n        });\n    }\n\n    @Test\n    void testConstructor_WithNullApplicationName() {\n        when(applicationModel.getCurrentConfig()).thenReturn(null);\n        when(applicationModel.getApplicationName()).thenReturn(null);\n\n        assertThrows(IllegalStateException.class, () -> {\n            new DubboMcpGenericCaller(applicationModel);\n        });\n    }\n\n    @Test\n    void testExecute_WithValidParameters() {\n        when(applicationModel.getCurrentConfig()).thenReturn(applicationConfig);\n        genericCaller = new DubboMcpGenericCaller(applicationModel);\n\n        String interfaceName = \"TestInterface\";\n        String methodName = \"testMethod\";\n        List<String> orderedJavaParameterNames = createParameterNames();\n        Class<?>[] parameterJavaTypes = createParameterTypes();\n        Map<String, Object> mcpProvidedParameters = createMcpParameters();\n        String group = \"testGroup\";\n        String version = \"1.0.0\";\n\n        assertThrows(RuntimeException.class, () -> {\n            genericCaller.execute(\n                    interfaceName,\n                    methodName,\n                    orderedJavaParameterNames,\n                    parameterJavaTypes,\n                    mcpProvidedParameters,\n                    group,\n                    version);\n        });\n    }\n\n    @Test\n    void testExecute_WithNullGroup() {\n        when(applicationModel.getCurrentConfig()).thenReturn(applicationConfig);\n        genericCaller = new DubboMcpGenericCaller(applicationModel);\n\n        String interfaceName = \"TestInterface\";\n        String methodName = \"testMethod\";\n        List<String> orderedJavaParameterNames = createParameterNames();\n        Class<?>[] parameterJavaTypes = createParameterTypes();\n        Map<String, Object> mcpProvidedParameters = createMcpParameters();\n        String version = \"1.0.0\";\n\n        assertThrows(RuntimeException.class, () -> {\n            genericCaller.execute(\n                    interfaceName,\n                    methodName,\n                    orderedJavaParameterNames,\n                    parameterJavaTypes,\n                    mcpProvidedParameters,\n                    null,\n                    version);\n        });\n    }\n\n    @Test\n    void testExecute_WithNullVersion() {\n        when(applicationModel.getCurrentConfig()).thenReturn(applicationConfig);\n        genericCaller = new DubboMcpGenericCaller(applicationModel);\n\n        String interfaceName = \"TestInterface\";\n        String methodName = \"testMethod\";\n        List<String> orderedJavaParameterNames = createParameterNames();\n        Class<?>[] parameterJavaTypes = createParameterTypes();\n        Map<String, Object> mcpProvidedParameters = createMcpParameters();\n        String group = \"testGroup\";\n\n        assertThrows(RuntimeException.class, () -> {\n            genericCaller.execute(\n                    interfaceName,\n                    methodName,\n                    orderedJavaParameterNames,\n                    parameterJavaTypes,\n                    mcpProvidedParameters,\n                    group,\n                    null);\n        });\n    }\n\n    @Test\n    void testExecute_WithMissingParameters() {\n        when(applicationModel.getCurrentConfig()).thenReturn(applicationConfig);\n        genericCaller = new DubboMcpGenericCaller(applicationModel);\n\n        String interfaceName = \"TestInterface\";\n        String methodName = \"testMethod\";\n        List<String> orderedJavaParameterNames = createParameterNames();\n        Class<?>[] parameterJavaTypes = createParameterTypes();\n        Map<String, Object> mcpProvidedParameters = new HashMap<>();\n        String group = \"testGroup\";\n        String version = \"1.0.0\";\n\n        assertThrows(RuntimeException.class, () -> {\n            genericCaller.execute(\n                    interfaceName,\n                    methodName,\n                    orderedJavaParameterNames,\n                    parameterJavaTypes,\n                    mcpProvidedParameters,\n                    group,\n                    version);\n        });\n    }\n\n    @Test\n    void testExecute_WithEmptyStrings() {\n        when(applicationModel.getCurrentConfig()).thenReturn(applicationConfig);\n        genericCaller = new DubboMcpGenericCaller(applicationModel);\n\n        String interfaceName = \"TestInterface\";\n        String methodName = \"testMethod\";\n        List<String> orderedJavaParameterNames = createParameterNames();\n        Class<?>[] parameterJavaTypes = createParameterTypes();\n        Map<String, Object> mcpProvidedParameters = createMcpParameters();\n\n        assertThrows(RuntimeException.class, () -> {\n            genericCaller.execute(\n                    interfaceName,\n                    methodName,\n                    orderedJavaParameterNames,\n                    parameterJavaTypes,\n                    mcpProvidedParameters,\n                    \"\",\n                    \"\");\n        });\n    }\n\n    private List<String> createParameterNames() {\n        List<String> names = new ArrayList<>();\n        names.add(\"param1\");\n        names.add(\"param2\");\n        return names;\n    }\n\n    private Class<?>[] createParameterTypes() {\n        return new Class<?>[] {String.class, Integer.class};\n    }\n\n    private Map<String, Object> createMcpParameters() {\n        Map<String, Object> parameters = new HashMap<>();\n        parameters.put(\"param1\", \"value1\");\n        parameters.put(\"param2\", 42);\n        return parameters;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/tool/DubboOpenApiToolConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.tool;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.mcp.core.McpServiceFilter;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPIService;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.modelcontextprotocol.spec.McpSchema;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.junit.jupiter.api.Assertions.*;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.*;\n\nclass DubboOpenApiToolConverterTest {\n\n    @Mock\n    private DefaultOpenAPIService openApiService;\n\n    @Mock\n    private ServiceDescriptor serviceDescriptor;\n\n    @Mock\n    private URL serviceUrl;\n\n    private DubboOpenApiToolConverter converter;\n\n    @BeforeEach\n    void setUp() {\n        MockitoAnnotations.openMocks(this);\n        converter = new DubboOpenApiToolConverter(openApiService);\n    }\n\n    @Test\n    void testConverterConstruction() {\n        assertNotNull(converter);\n    }\n\n    @Test\n    void testConvertToTools_WithNullOpenAPI() {\n        when(serviceDescriptor.getInterfaceName()).thenReturn(\"TestService\");\n        when(openApiService.getOpenAPI(any(OpenAPIRequest.class))).thenReturn(null);\n\n        Map<String, McpSchema.Tool> result = converter.convertToTools(serviceDescriptor, serviceUrl, null);\n\n        assertTrue(result.isEmpty());\n    }\n\n    @Test\n    void testConvertToTools_WithEmptyPaths() {\n        when(serviceDescriptor.getInterfaceName()).thenReturn(\"TestService\");\n\n        OpenAPI openAPI = new OpenAPI();\n        openAPI.setPaths(new HashMap<>());\n        when(openApiService.getOpenAPI(any(OpenAPIRequest.class))).thenReturn(openAPI);\n\n        Map<String, McpSchema.Tool> result = converter.convertToTools(serviceDescriptor, serviceUrl, null);\n\n        assertTrue(result.isEmpty());\n    }\n\n    @Test\n    void testConvertToTools_WithValidOperation() {\n        when(serviceDescriptor.getInterfaceName()).thenReturn(\"TestService\");\n\n        OpenAPI openAPI = createMockOpenAPI();\n        when(openApiService.getOpenAPI(any(OpenAPIRequest.class))).thenReturn(openAPI);\n\n        Map<String, McpSchema.Tool> result = converter.convertToTools(serviceDescriptor, serviceUrl, null);\n\n        assertFalse(result.isEmpty());\n        assertTrue(result.containsKey(\"testOperation\"));\n\n        McpSchema.Tool tool = result.get(\"testOperation\");\n        assertEquals(\"testOperation\", tool.name());\n        assertNotNull(tool.description());\n        assertNotNull(tool.inputSchema());\n    }\n\n    @Test\n    void testConvertToTools_WithCustomToolConfig() {\n        when(serviceDescriptor.getInterfaceName()).thenReturn(\"TestService\");\n\n        OpenAPI openAPI = createMockOpenAPI();\n        when(openApiService.getOpenAPI(any(OpenAPIRequest.class))).thenReturn(openAPI);\n\n        McpServiceFilter.McpToolConfig toolConfig = new McpServiceFilter.McpToolConfig();\n        toolConfig.setToolName(\"customTool\");\n        toolConfig.setDescription(\"Custom description\");\n\n        Map<String, McpSchema.Tool> result = converter.convertToTools(serviceDescriptor, serviceUrl, toolConfig);\n\n        assertFalse(result.isEmpty());\n        McpSchema.Tool tool = result.values().iterator().next();\n        assertEquals(\"customTool\", tool.name());\n        assertEquals(\"Custom description\", tool.description());\n    }\n\n    @Test\n    void testGetOperationByToolName_WithExistingTool() {\n        when(serviceDescriptor.getInterfaceName()).thenReturn(\"TestService\");\n\n        OpenAPI openAPI = createMockOpenAPI();\n        when(openApiService.getOpenAPI(any(OpenAPIRequest.class))).thenReturn(openAPI);\n\n        converter.convertToTools(serviceDescriptor, serviceUrl, null);\n\n        Operation operation = converter.getOperationByToolName(\"testOperation\");\n        assertNotNull(operation);\n        assertEquals(\"testOperation\", operation.getOperationId());\n    }\n\n    @Test\n    void testGetOperationByToolName_WithNonExistentTool() {\n        Operation operation = converter.getOperationByToolName(\"nonExistent\");\n        assertNull(operation);\n    }\n\n    @Test\n    void testConvertToTools_WithParameter() {\n        when(serviceDescriptor.getInterfaceName()).thenReturn(\"TestService\");\n\n        OpenAPI openAPI = createMockOpenAPIWithParameters();\n        when(openApiService.getOpenAPI(any(OpenAPIRequest.class))).thenReturn(openAPI);\n\n        Map<String, McpSchema.Tool> result = converter.convertToTools(serviceDescriptor, serviceUrl, null);\n\n        assertFalse(result.isEmpty());\n        McpSchema.Tool tool = result.get(\"testOperation\");\n        assertNotNull(tool);\n        assertNotNull(tool.inputSchema());\n    }\n\n    @Test\n    void testConvertToTools_WithException() {\n        when(serviceDescriptor.getInterfaceName()).thenReturn(\"TestService\");\n        when(openApiService.getOpenAPI(any(OpenAPIRequest.class))).thenThrow(new RuntimeException(\"Test exception\"));\n\n        assertThrows(RuntimeException.class, () -> {\n            converter.convertToTools(serviceDescriptor, serviceUrl, null);\n        });\n    }\n\n    private OpenAPI createMockOpenAPI() {\n        OpenAPI openAPI = new OpenAPI();\n        Map<String, PathItem> paths = new HashMap<>();\n\n        PathItem pathItem = new PathItem();\n        Map<HttpMethods, Operation> operations = new HashMap<>();\n\n        Operation operation = new Operation();\n        operation.setOperationId(\"testOperation\");\n        operation.setSummary(\"Test operation summary\");\n        operation.setDescription(\"Test operation description\");\n\n        operations.put(HttpMethods.GET, operation);\n        pathItem.setOperations(operations);\n\n        paths.put(\"/test\", pathItem);\n        openAPI.setPaths(paths);\n\n        return openAPI;\n    }\n\n    private OpenAPI createMockOpenAPIWithParameters() {\n        OpenAPI openAPI = createMockOpenAPI();\n\n        PathItem pathItem = openAPI.getPaths().get(\"/test\");\n        Operation operation = pathItem.getOperations().get(HttpMethods.GET);\n\n        Parameter parameter = new Parameter(\"testParam\", Parameter.In.QUERY);\n        parameter.setSchema(new Schema());\n\n        operation.setParameters(java.util.Arrays.asList(parameter));\n\n        return openAPI;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/tool/DubboServiceToolRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.tool;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.mcp.core.McpServiceFilter;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.modelcontextprotocol.server.McpAsyncServer;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\nimport reactor.core.publisher.Mono;\n\nimport static org.junit.jupiter.api.Assertions.*;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.*;\n\nclass DubboServiceToolRegistryTest {\n\n    @Mock\n    private McpAsyncServer mcpServer;\n\n    @Mock\n    private DubboOpenApiToolConverter toolConverter;\n\n    @Mock\n    private DubboMcpGenericCaller genericCaller;\n\n    @Mock\n    private McpServiceFilter mcpServiceFilter;\n\n    @Mock\n    private ProviderModel providerModel;\n\n    @Mock\n    private ServiceDescriptor serviceDescriptor;\n\n    private DubboServiceToolRegistry registry;\n\n    @BeforeEach\n    void setUp() {\n        MockitoAnnotations.openMocks(this);\n        registry = new DubboServiceToolRegistry(mcpServer, toolConverter, genericCaller, mcpServiceFilter);\n    }\n\n    @Test\n    void testRegistryConstruction() {\n        assertNotNull(registry);\n    }\n\n    @Test\n    void testRegisterService_WithNullUrls() {\n        when(providerModel.getServiceModel()).thenReturn(serviceDescriptor);\n        when(providerModel.getServiceUrls()).thenReturn(null);\n\n        int result = registry.registerService(providerModel);\n\n        assertEquals(0, result);\n    }\n\n    @Test\n    void testRegisterService_WithEmptyUrls() {\n        when(providerModel.getServiceModel()).thenReturn(serviceDescriptor);\n        when(providerModel.getServiceUrls()).thenReturn(new ArrayList<>());\n\n        int result = registry.registerService(providerModel);\n\n        assertEquals(0, result);\n    }\n\n    @Test\n    void testRegisterService_WithNullServiceInterface() {\n        List<URL> urls = createMockUrls();\n        when(providerModel.getServiceModel()).thenReturn(serviceDescriptor);\n        when(providerModel.getServiceUrls()).thenReturn(urls);\n        when(serviceDescriptor.getServiceInterfaceClass()).thenReturn(null);\n\n        int result = registry.registerService(providerModel);\n\n        assertEquals(0, result);\n    }\n\n    @Test\n    void testRegisterService_WithValidService() {\n        setupValidProviderModel();\n        when(mcpServiceFilter.shouldExposeMethodAsMcpTool(any(), any())).thenReturn(true);\n        when(mcpServiceFilter.getMcpToolConfig(any(), any())).thenReturn(createMockToolConfig());\n        when(mcpServer.addTool(any())).thenReturn(Mono.empty());\n\n        int result = registry.registerService(providerModel);\n\n        assertTrue(result > 0);\n        verify(mcpServer, atLeastOnce()).addTool(any());\n    }\n\n    @Test\n    void testRegisterService_WithServiceLevelTools() {\n        setupValidProviderModel();\n        when(mcpServiceFilter.shouldExposeMethodAsMcpTool(any(), any())).thenReturn(false);\n        when(mcpServiceFilter.shouldExposeAsMcpTool(any())).thenReturn(true);\n        when(toolConverter.convertToTools(any(), any(), any())).thenReturn(createMockTools());\n        when(mcpServer.addTool(any())).thenReturn(Mono.empty());\n\n        int result = registry.registerService(providerModel);\n\n        assertTrue(result >= 0);\n    }\n\n    @Test\n    void testRegisterService_WithException() {\n        when(providerModel.getServiceModel()).thenThrow(new RuntimeException(\"Test exception\"));\n\n        assertThrows(RuntimeException.class, () -> {\n            registry.registerService(providerModel);\n        });\n    }\n\n    @Test\n    void testUnregisterService_WithExistingService() {\n        setupValidProviderModel();\n        when(mcpServiceFilter.shouldExposeMethodAsMcpTool(any(), any())).thenReturn(true);\n        when(mcpServiceFilter.getMcpToolConfig(any(), any())).thenReturn(createMockToolConfig());\n        when(mcpServer.addTool(any())).thenReturn(Mono.empty());\n        when(mcpServer.removeTool(anyString())).thenReturn(Mono.empty());\n\n        registry.registerService(providerModel);\n\n        assertDoesNotThrow(() -> registry.unregisterService(providerModel));\n    }\n\n    @Test\n    void testUnregisterService_WithNonExistentService() {\n        when(providerModel.getServiceKey()).thenReturn(\"nonExistentService\");\n\n        assertDoesNotThrow(() -> registry.unregisterService(providerModel));\n    }\n\n    @Test\n    void testUnregisterService_WithException() {\n        setupValidProviderModel();\n        when(mcpServiceFilter.shouldExposeMethodAsMcpTool(any(), any())).thenReturn(true);\n        when(mcpServiceFilter.getMcpToolConfig(any(), any())).thenReturn(createMockToolConfig());\n        when(mcpServer.addTool(any())).thenReturn(Mono.empty());\n        when(mcpServer.removeTool(anyString())).thenThrow(new RuntimeException(\"Test exception\"));\n\n        registry.registerService(providerModel);\n\n        assertDoesNotThrow(() -> registry.unregisterService(providerModel));\n    }\n\n    @Test\n    void testClearRegistry() {\n        assertDoesNotThrow(() -> registry.clearRegistry());\n    }\n\n    private void setupValidProviderModel() {\n        List<URL> urls = createMockUrls();\n        Class<?> mockInterface = TestInterface.class;\n\n        when(providerModel.getServiceModel()).thenReturn(serviceDescriptor);\n        when(providerModel.getServiceUrls()).thenReturn(urls);\n        when(providerModel.getServiceKey()).thenReturn(\"testService\");\n        when(serviceDescriptor.getServiceInterfaceClass()).thenReturn((Class) mockInterface);\n        when(serviceDescriptor.getInterfaceName()).thenReturn(\"TestInterface\");\n    }\n\n    private List<URL> createMockUrls() {\n        List<URL> urls = new ArrayList<>();\n        URL url = URL.valueOf(\"dubbo://localhost:20880/TestInterface\");\n        urls.add(url);\n        return urls;\n    }\n\n    private McpServiceFilter.McpToolConfig createMockToolConfig() {\n        McpServiceFilter.McpToolConfig config = new McpServiceFilter.McpToolConfig();\n        config.setToolName(\"testTool\");\n        config.setDescription(\"Test tool description\");\n        return config;\n    }\n\n    private java.util.Map<String, io.modelcontextprotocol.spec.McpSchema.Tool> createMockTools() {\n        java.util.Map<String, io.modelcontextprotocol.spec.McpSchema.Tool> tools = new java.util.HashMap<>();\n        io.modelcontextprotocol.spec.McpSchema.Tool tool =\n                new io.modelcontextprotocol.spec.McpSchema.Tool(\"testTool\", \"Test description\", \"{}\");\n        tools.put(\"testTool\", tool);\n        return tools;\n    }\n\n    public interface TestInterface {\n        String testMethod(String param);\n\n        void anotherMethod(int value);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/transport/DubboMcpSseTransportProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.transport;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException;\nimport org.apache.dubbo.remoting.http12.message.ServerSentEvent;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcServiceContext;\n\nimport java.io.ByteArrayInputStream;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.modelcontextprotocol.spec.McpSchema;\nimport io.modelcontextprotocol.spec.McpServerSession;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.InjectMocks;\nimport org.mockito.Mock;\nimport org.mockito.MockedStatic;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport org.mockito.junit.jupiter.MockitoSettings;\nimport org.mockito.quality.Strictness;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.mockStatic;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.verifyNoInteractions;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\n@MockitoSettings(strictness = Strictness.LENIENT)\nclass DubboMcpSseTransportProviderTest {\n\n    @Mock\n    private StreamObserver<ServerSentEvent<String>> responseObserver;\n\n    @Mock\n    private HttpRequest httpRequest;\n\n    @Mock\n    private HttpResponse httpResponse;\n\n    @Mock\n    private McpServerSession.Factory sessionFactory;\n\n    @Mock\n    private RpcServiceContext rpcServiceContext;\n\n    @Mock\n    private McpServerSession mockSession;\n\n    private MockedStatic<RpcContext> rpcContextMockedStatic;\n\n    @InjectMocks\n    private DubboMcpSseTransportProvider transportProvider;\n\n    private final ObjectMapper objectMapper = new ObjectMapper();\n\n    @BeforeEach\n    void setUp() {\n        rpcContextMockedStatic = mockStatic(RpcContext.class);\n        rpcContextMockedStatic.when(RpcContext::getServiceContext).thenReturn(rpcServiceContext);\n        when(rpcServiceContext.getRequest(HttpRequest.class)).thenReturn(httpRequest);\n        when(rpcServiceContext.getResponse(HttpResponse.class)).thenReturn(httpResponse);\n        transportProvider = new DubboMcpSseTransportProvider(objectMapper);\n        transportProvider.setSessionFactory(sessionFactory);\n    }\n\n    @Test\n    void handleRequestHandlesGetRequest() {\n        when(httpRequest.method()).thenReturn(HttpMethods.GET.name());\n        when(sessionFactory.create(any())).thenReturn(mockSession);\n        when(mockSession.getId()).thenReturn(\"1\");\n\n        transportProvider.handleRequest(responseObserver);\n\n        verify(httpRequest, times(1)).method();\n        ArgumentCaptor<ServerSentEvent> captor = ArgumentCaptor.forClass(ServerSentEvent.class);\n        verify(responseObserver, times(1)).onNext(captor.capture());\n        ServerSentEvent evt = captor.getValue();\n        Assertions.assertEquals(\"endpoint\", evt.getEvent());\n        Assertions.assertTrue(((String) evt.getData()).startsWith(\"/mcp/message?sessionId=\"));\n    }\n\n    @Test\n    void handleRequestHandlesPostRequest() {\n        when(httpRequest.method()).thenReturn(HttpMethods.GET.name());\n        when(sessionFactory.create(any())).thenReturn(mockSession);\n        when(mockSession.getId()).thenReturn(\"1\");\n        when(httpRequest.parameter(\"sessionId\")).thenReturn(\"1\");\n        when(httpRequest.inputStream())\n                .thenReturn(new ByteArrayInputStream(\"{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"method\\\":\\\"test\\\"}\".getBytes()));\n        when(mockSession.handle(any(McpSchema.JSONRPCMessage.class))).thenReturn(mock());\n        transportProvider.handleRequest(responseObserver);\n        when(httpRequest.method()).thenReturn(HttpMethods.POST.name());\n        transportProvider.handleRequest(responseObserver);\n        verify(httpRequest, times(3)).method();\n        verify(httpResponse).setStatus(HttpStatus.OK.getCode());\n    }\n\n    @Test\n    void handleRequestIgnoresUnsupportedMethods() {\n        when(httpRequest.method()).thenReturn(HttpMethods.PUT.name());\n\n        transportProvider.handleRequest(responseObserver);\n\n        verify(httpRequest, times(2)).method();\n        verifyNoInteractions(responseObserver);\n        verifyNoInteractions(httpResponse);\n    }\n\n    @Test\n    void handleMessageReturnsBadRequestWhenSessionIdIsMissing() {\n        when(httpRequest.parameter(\"sessionId\")).thenReturn(null);\n\n        try {\n            transportProvider.handleMessage();\n        } catch (Exception e) {\n            Assertions.assertInstanceOf(HttpResultPayloadException.class, e);\n            HttpResultPayloadException httpResultPayloadException = (HttpResultPayloadException) e;\n            Assertions.assertEquals(\n                    HttpStatus.BAD_REQUEST.getCode(),\n                    httpResultPayloadException.getResult().getStatus());\n        }\n    }\n\n    @Test\n    void handleMessageReturnsNotFoundForUnknownSessionId() {\n        when(httpRequest.parameter(\"sessionId\")).thenReturn(\"unknownSessionId\");\n\n        try {\n            transportProvider.handleMessage();\n        } catch (Exception e) {\n            Assertions.assertInstanceOf(HttpResultPayloadException.class, e);\n            HttpResultPayloadException httpResultPayloadException = (HttpResultPayloadException) e;\n            Assertions.assertEquals(\n                    HttpStatus.NOT_FOUND.getCode(),\n                    httpResultPayloadException.getResult().getStatus());\n        }\n    }\n\n    @AfterEach\n    public void tearDown() {\n        if (rpcContextMockedStatic != null) {\n            rpcContextMockedStatic.close();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/transport/DubboMcpStreamableTransportProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.transport;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.message.ServerSentEvent;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcServiceContext;\n\nimport java.io.ByteArrayInputStream;\nimport java.util.Collections;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.modelcontextprotocol.spec.McpSchema;\nimport io.modelcontextprotocol.spec.McpStreamableServerSession;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.MockedStatic;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport org.mockito.junit.jupiter.MockitoSettings;\nimport org.mockito.quality.Strictness;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.*;\n\n@ExtendWith(MockitoExtension.class)\n@MockitoSettings(strictness = Strictness.LENIENT)\nclass DubboMcpStreamableTransportProviderTest {\n\n    @Mock\n    private StreamObserver<ServerSentEvent<byte[]>> responseObserver;\n\n    @Mock\n    private HttpRequest httpRequest;\n\n    @Mock\n    private HttpResponse httpResponse;\n\n    @Mock\n    private McpStreamableServerSession.Factory sessionFactory;\n\n    @Mock\n    private RpcServiceContext rpcServiceContext;\n\n    @Mock\n    private McpStreamableServerSession mockSession;\n\n    private MockedStatic<RpcContext> rpcContextMockedStatic;\n\n    private DubboMcpStreamableTransportProvider transportProvider;\n\n    private final ObjectMapper objectMapper = new ObjectMapper();\n\n    @BeforeEach\n    void setUp() {\n        rpcContextMockedStatic = mockStatic(RpcContext.class);\n        rpcContextMockedStatic.when(RpcContext::getServiceContext).thenReturn(rpcServiceContext);\n        when(rpcServiceContext.getRequest(HttpRequest.class)).thenReturn(httpRequest);\n        when(rpcServiceContext.getResponse(HttpResponse.class)).thenReturn(httpResponse);\n        transportProvider = new DubboMcpStreamableTransportProvider(objectMapper);\n        transportProvider.setSessionFactory(sessionFactory);\n    }\n\n    @Test\n    void handleRequestHandlesGetRequest() {\n        when(httpRequest.method()).thenReturn(HttpMethods.GET.name());\n        when(httpRequest.accept()).thenReturn(\"text/event-stream\");\n        when(httpRequest.header(DubboMcpStreamableTransportProvider.SESSION_ID_HEADER))\n                .thenReturn(\"test-session-id\");\n\n        transportProvider.handleRequest(responseObserver);\n\n        verify(httpRequest, times(1)).method();\n        // For GET requests, we don't verify onNext because the implementation calls\n        // session.sendNotification().subscribe() directly\n    }\n\n    @Test\n    void handleRequestHandlesPostRequest() {\n        when(httpRequest.method()).thenReturn(HttpMethods.POST.name());\n        when(httpRequest.accept()).thenReturn(\"application/json\");\n        when(httpRequest.header(DubboMcpStreamableTransportProvider.SESSION_ID_HEADER))\n                .thenReturn(\"test-session-id\");\n        when(httpRequest.inputStream())\n                .thenReturn(new ByteArrayInputStream(\n                        \"{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"method\\\":\\\"initialize\\\",\\\"id\\\":\\\"1\\\"}\".getBytes()));\n\n        transportProvider.handleRequest(responseObserver);\n\n        verify(httpRequest, times(2)).method();\n        verify(httpResponse).setStatus(anyInt());\n    }\n\n    @Test\n    void handleRequestHandlesDeleteRequest() {\n        when(httpRequest.method()).thenReturn(HttpMethods.DELETE.name());\n        when(httpRequest.header(DubboMcpStreamableTransportProvider.SESSION_ID_HEADER))\n                .thenReturn(\"test-session-id\");\n\n        transportProvider.handleRequest(responseObserver);\n\n        verify(httpRequest, times(3)).method();\n        verify(httpResponse).setStatus(HttpStatus.NOT_FOUND.getCode());\n        verify(responseObserver).onCompleted();\n    }\n\n    @Test\n    void handleRequestIgnoresUnsupportedMethods() {\n        when(httpRequest.method()).thenReturn(HttpMethods.PUT.name());\n\n        transportProvider.handleRequest(responseObserver);\n\n        verify(httpRequest, times(5)).method();\n        verify(httpResponse).setStatus(HttpStatus.METHOD_NOT_ALLOWED.getCode());\n        verify(responseObserver).onError(any());\n        verify(responseObserver).onCompleted();\n    }\n\n    @Test\n    void handleGetReturnsBadRequestWhenSessionIdIsMissing() {\n        when(httpRequest.method()).thenReturn(HttpMethods.GET.name());\n        when(httpRequest.accept()).thenReturn(\"text/event-stream\");\n        when(httpRequest.header(DubboMcpStreamableTransportProvider.SESSION_ID_HEADER))\n                .thenReturn(null);\n\n        transportProvider.handleRequest(responseObserver);\n\n        verify(httpRequest, times(1)).method();\n        verify(httpResponse).setStatus(HttpStatus.BAD_REQUEST.getCode());\n        verify(responseObserver).onError(any());\n        verify(responseObserver).onCompleted();\n    }\n\n    @Test\n    void handleGetReturnsNotFoundForUnknownSessionId() {\n        when(httpRequest.method()).thenReturn(HttpMethods.GET.name());\n        when(httpRequest.accept()).thenReturn(\"text/event-stream\");\n        when(httpRequest.header(DubboMcpStreamableTransportProvider.SESSION_ID_HEADER))\n                .thenReturn(\"unknownSessionId\");\n\n        transportProvider.handleRequest(responseObserver);\n\n        verify(httpRequest, times(1)).method();\n        verify(httpResponse).setStatus(HttpStatus.NOT_FOUND.getCode());\n        verify(responseObserver).onError(any());\n        verify(responseObserver).onCompleted();\n    }\n\n    @Test\n    void handleGetWithReplayRequestCallsSessionReplay() throws Exception {\n        // Create a transport provider subclass for testing to access private methods and fields\n        DubboMcpStreamableTransportProvider transportProviderUnderTest =\n                new DubboMcpStreamableTransportProvider(objectMapper);\n        transportProviderUnderTest.setSessionFactory(sessionFactory);\n\n        // Use reflection to put mockSession into the sessions map\n        java.lang.reflect.Field sessionsField = DubboMcpStreamableTransportProvider.class.getDeclaredField(\"sessions\");\n        sessionsField.setAccessible(true);\n        Object sessionsMap = sessionsField.get(transportProviderUnderTest);\n\n        // Use reflection to call the put method\n        java.lang.reflect.Method putMethod = sessionsMap.getClass().getMethod(\"put\", Object.class, Object.class);\n        putMethod.invoke(sessionsMap, \"test-session-id\", mockSession);\n\n        // Set up mock behavior\n        when(httpRequest.method()).thenReturn(HttpMethods.GET.name());\n        when(httpRequest.accept()).thenReturn(\"text/event-stream\");\n        when(httpRequest.header(DubboMcpStreamableTransportProvider.SESSION_ID_HEADER))\n                .thenReturn(\"test-session-id\");\n        when(httpRequest.header(\"Last-Event-ID\")).thenReturn(\"12345\");\n\n        // Mock the replay method to return a Flux that emits a test message\n        McpSchema.JSONRPCNotification testNotification =\n                new McpSchema.JSONRPCNotification(\"2.0\", \"test_method\", Collections.singletonMap(\"key\", \"value\"));\n\n        when(mockSession.replay(\"12345\")).thenReturn(reactor.core.publisher.Flux.just(testNotification));\n\n        transportProviderUnderTest.handleRequest(responseObserver);\n\n        // Verify that the replay method is called\n        verify(mockSession).replay(\"12345\");\n        // Verify that the message is sent\n        verify(responseObserver).onNext(any());\n        verify(responseObserver).onCompleted();\n    }\n\n    @AfterEach\n    public void tearDown() {\n        if (rpcContextMockedStatic != null) {\n            rpcContextMockedStatic.close();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mcp/src/test/java/org/apache/dubbo/mcp/util/TypeSchemaUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mcp.util;\n\nimport org.apache.dubbo.mcp.JsonSchemaType;\nimport org.apache.dubbo.mcp.McpConstant;\n\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass TypeSchemaUtilsTest {\n\n    enum TestEnum {\n        VALUE1,\n        VALUE2,\n        VALUE3\n    }\n\n    @Test\n    void testResolvePrimitiveTypes() {\n        TypeSchemaUtils.TypeSchemaInfo intSchema = TypeSchemaUtils.resolveTypeSchema(int.class, int.class, \"test int\");\n        assertEquals(JsonSchemaType.INTEGER_SCHEMA.getJsonSchemaType(), intSchema.getType());\n        assertNull(intSchema.getFormat());\n        assertEquals(\"test int\", intSchema.getDescription());\n\n        TypeSchemaUtils.TypeSchemaInfo longSchema =\n                TypeSchemaUtils.resolveTypeSchema(long.class, long.class, \"test long\");\n        assertEquals(JsonSchemaType.INTEGER_SCHEMA.getJsonSchemaType(), longSchema.getType());\n        assertEquals(\"int64\", longSchema.getFormat());\n\n        TypeSchemaUtils.TypeSchemaInfo doubleSchema =\n                TypeSchemaUtils.resolveTypeSchema(double.class, double.class, \"test double\");\n        assertEquals(JsonSchemaType.NUMBER_SCHEMA.getJsonSchemaType(), doubleSchema.getType());\n        assertEquals(\"double\", doubleSchema.getFormat());\n\n        TypeSchemaUtils.TypeSchemaInfo stringSchema =\n                TypeSchemaUtils.resolveTypeSchema(String.class, String.class, \"test string\");\n        assertEquals(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(), stringSchema.getType());\n        assertNull(stringSchema.getFormat());\n\n        TypeSchemaUtils.TypeSchemaInfo booleanSchema =\n                TypeSchemaUtils.resolveTypeSchema(boolean.class, boolean.class, \"test boolean\");\n        assertEquals(JsonSchemaType.BOOLEAN_SCHEMA.getJsonSchemaType(), booleanSchema.getType());\n    }\n\n    @Test\n    void testResolveArrayTypes() {\n        TypeSchemaUtils.TypeSchemaInfo arraySchema =\n                TypeSchemaUtils.resolveTypeSchema(int[].class, int[].class, \"test array\");\n        assertEquals(JsonSchemaType.ARRAY_SCHEMA.getJsonSchemaType(), arraySchema.getType());\n        assertNotNull(arraySchema.getItems());\n        assertEquals(\n                JsonSchemaType.INTEGER_SCHEMA.getJsonSchemaType(),\n                arraySchema.getItems().getType());\n    }\n\n    @Test\n    void testResolveEnumTypes() {\n        TypeSchemaUtils.TypeSchemaInfo enumSchema =\n                TypeSchemaUtils.resolveTypeSchema(TestEnum.class, TestEnum.class, \"test enum\");\n        assertEquals(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(), enumSchema.getType());\n        assertNotNull(enumSchema.getEnumValues());\n        assertEquals(3, enumSchema.getEnumValues().size());\n        assertTrue(enumSchema.getEnumValues().contains(\"VALUE1\"));\n        assertTrue(enumSchema.getEnumValues().contains(\"VALUE2\"));\n        assertTrue(enumSchema.getEnumValues().contains(\"VALUE3\"));\n    }\n\n    @Test\n    void testResolveDateTimeTypes() {\n        TypeSchemaUtils.TypeSchemaInfo dateSchema =\n                TypeSchemaUtils.resolveTypeSchema(Date.class, Date.class, \"test date\");\n        assertEquals(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(), dateSchema.getType());\n        assertEquals(JsonSchemaType.DATE_TIME_FORMAT.getJsonSchemaFormat(), dateSchema.getFormat());\n\n        TypeSchemaUtils.TypeSchemaInfo localDateSchema =\n                TypeSchemaUtils.resolveTypeSchema(LocalDate.class, LocalDate.class, \"test local date\");\n        assertEquals(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(), localDateSchema.getType());\n        assertEquals(JsonSchemaType.DATE_FORMAT.getJsonSchemaFormat(), localDateSchema.getFormat());\n\n        TypeSchemaUtils.TypeSchemaInfo localTimeSchema =\n                TypeSchemaUtils.resolveTypeSchema(LocalTime.class, LocalTime.class, \"test local time\");\n        assertEquals(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(), localTimeSchema.getType());\n        assertEquals(JsonSchemaType.TIME_FORMAT.getJsonSchemaFormat(), localTimeSchema.getFormat());\n\n        TypeSchemaUtils.TypeSchemaInfo localDateTimeSchema =\n                TypeSchemaUtils.resolveTypeSchema(LocalDateTime.class, LocalDateTime.class, \"test local datetime\");\n        assertEquals(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(), localDateTimeSchema.getType());\n        assertEquals(JsonSchemaType.DATE_TIME_FORMAT.getJsonSchemaFormat(), localDateTimeSchema.getFormat());\n    }\n\n    @Test\n    void testResolveCollectionTypes() {\n        TypeSchemaUtils.TypeSchemaInfo listSchema =\n                TypeSchemaUtils.resolveTypeSchema(List.class, List.class, \"test list\");\n        assertEquals(JsonSchemaType.ARRAY_SCHEMA.getJsonSchemaType(), listSchema.getType());\n        assertNotNull(listSchema.getItems());\n        assertEquals(\n                JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(),\n                listSchema.getItems().getType());\n\n        TypeSchemaUtils.TypeSchemaInfo mapSchema = TypeSchemaUtils.resolveTypeSchema(Map.class, Map.class, \"test map\");\n        assertEquals(JsonSchemaType.OBJECT_SCHEMA.getJsonSchemaType(), mapSchema.getType());\n        assertNotNull(mapSchema.getAdditionalProperties());\n        assertEquals(\n                JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(),\n                mapSchema.getAdditionalProperties().getType());\n    }\n\n    @Test\n    void testResolveComplexObjectTypes() {\n        TypeSchemaUtils.TypeSchemaInfo objectSchema =\n                TypeSchemaUtils.resolveTypeSchema(Object.class, Object.class, \"test object\");\n        assertEquals(JsonSchemaType.OBJECT_SCHEMA.getJsonSchemaType(), objectSchema.getType());\n        // The description includes the provided description plus type information\n        assertEquals(\"test object (POJO type: Object)\", objectSchema.getDescription());\n    }\n\n    @Test\n    void testToSchemaMap() {\n        TypeSchemaUtils.TypeSchemaInfo schemaInfo = TypeSchemaUtils.TypeSchemaInfo.builder()\n                .type(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType())\n                .format(\"email\")\n                .description(\"Email address\")\n                .build();\n\n        Map<String, Object> schemaMap = TypeSchemaUtils.toSchemaMap(schemaInfo);\n\n        assertEquals(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(), schemaMap.get(McpConstant.SCHEMA_PROPERTY_TYPE));\n        assertEquals(\"email\", schemaMap.get(McpConstant.SCHEMA_PROPERTY_FORMAT));\n        assertEquals(\"Email address\", schemaMap.get(McpConstant.SCHEMA_PROPERTY_DESCRIPTION));\n    }\n\n    @Test\n    void testToSchemaMapWithEnumValues() {\n        List<String> enumValues = new ArrayList<>();\n        enumValues.add(\"OPTION1\");\n        enumValues.add(\"OPTION2\");\n\n        TypeSchemaUtils.TypeSchemaInfo schemaInfo = TypeSchemaUtils.TypeSchemaInfo.builder()\n                .type(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType())\n                .enumValues(enumValues)\n                .description(\"Enum field\")\n                .build();\n\n        Map<String, Object> schemaMap = TypeSchemaUtils.toSchemaMap(schemaInfo);\n\n        assertEquals(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(), schemaMap.get(McpConstant.SCHEMA_PROPERTY_TYPE));\n        assertEquals(enumValues, schemaMap.get(McpConstant.SCHEMA_PROPERTY_ENUM));\n        assertEquals(\"Enum field\", schemaMap.get(McpConstant.SCHEMA_PROPERTY_DESCRIPTION));\n    }\n\n    @Test\n    void testToSchemaMapWithArrayItems() {\n        TypeSchemaUtils.TypeSchemaInfo itemSchema = TypeSchemaUtils.TypeSchemaInfo.builder()\n                .type(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType())\n                .description(\"Array item\")\n                .build();\n\n        TypeSchemaUtils.TypeSchemaInfo arraySchema = TypeSchemaUtils.TypeSchemaInfo.builder()\n                .type(JsonSchemaType.ARRAY_SCHEMA.getJsonSchemaType())\n                .items(itemSchema)\n                .description(\"Array field\")\n                .build();\n\n        Map<String, Object> schemaMap = TypeSchemaUtils.toSchemaMap(arraySchema);\n\n        assertEquals(JsonSchemaType.ARRAY_SCHEMA.getJsonSchemaType(), schemaMap.get(McpConstant.SCHEMA_PROPERTY_TYPE));\n        assertEquals(\"Array field\", schemaMap.get(McpConstant.SCHEMA_PROPERTY_DESCRIPTION));\n\n        @SuppressWarnings(\"unchecked\")\n        Map<String, Object> itemsMap = (Map<String, Object>) schemaMap.get(McpConstant.SCHEMA_PROPERTY_ITEMS);\n        assertNotNull(itemsMap);\n        assertEquals(JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(), itemsMap.get(McpConstant.SCHEMA_PROPERTY_TYPE));\n    }\n\n    @Test\n    void testUtilityMethods() {\n        assertTrue(TypeSchemaUtils.isPrimitiveType(int.class));\n        assertTrue(TypeSchemaUtils.isPrimitiveType(String.class));\n        assertFalse(TypeSchemaUtils.isPrimitiveType(Object.class));\n\n        assertEquals(\n                JsonSchemaType.INTEGER_SCHEMA.getJsonSchemaType(),\n                TypeSchemaUtils.getPrimitiveJsonSchemaType(int.class));\n        assertEquals(\n                JsonSchemaType.STRING_SCHEMA.getJsonSchemaType(),\n                TypeSchemaUtils.getPrimitiveJsonSchemaType(String.class));\n\n        assertEquals(\"int64\", TypeSchemaUtils.getFormatForType(long.class));\n        assertNull(TypeSchemaUtils.getFormatForType(int.class));\n\n        assertTrue(TypeSchemaUtils.isDateTimeType(Date.class));\n        assertTrue(TypeSchemaUtils.isDateTimeType(LocalDate.class));\n        assertFalse(TypeSchemaUtils.isDateTimeType(String.class));\n\n        assertEquals(\n                JsonSchemaType.DATE_FORMAT.getJsonSchemaFormat(), TypeSchemaUtils.getDateTimeFormat(LocalDate.class));\n        assertEquals(\n                JsonSchemaType.TIME_FORMAT.getJsonSchemaFormat(), TypeSchemaUtils.getDateTimeFormat(LocalTime.class));\n        assertEquals(\n                JsonSchemaType.DATE_TIME_FORMAT.getJsonSchemaFormat(),\n                TypeSchemaUtils.getDateTimeFormat(LocalDateTime.class));\n\n        assertEquals(String.class, TypeSchemaUtils.getClassFromType(String.class));\n        assertEquals(Object.class, TypeSchemaUtils.getClassFromType(Object.class));\n\n        assertTrue(TypeSchemaUtils.isPrimitiveOrWrapper(int.class));\n        assertTrue(TypeSchemaUtils.isPrimitiveOrWrapper(Integer.class));\n        assertFalse(TypeSchemaUtils.isPrimitiveOrWrapper(Object.class));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-mutiny</artifactId>\n  <packaging>jar</packaging>\n\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>io.smallrye.reactive</groupId>\n      <artifactId>mutiny</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <configuration>\n          <source>17</source>\n          <target>17</target>\n          <release>17</release>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/AbstractTripleMutinyPublisher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.rpc.protocol.tri.CancelableStreamObserver;\n\nimport java.util.concurrent.Flow;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Consumer;\n\n/**\n * The middle layer between {@link org.apache.dubbo.common.stream.CallStreamObserver} and Mutiny API. <p>\n * 1. passing the data received by CallStreamObserver to Mutiny consumer <br>\n * 2. passing the request of Mutiny API to CallStreamObserver\n */\npublic abstract class AbstractTripleMutinyPublisher<T> extends CancelableStreamObserver<T>\n        implements Flow.Publisher<T>, Flow.Subscription {\n\n    private boolean canRequest;\n\n    private long requested;\n\n    // whether publisher has been subscribed\n    private final AtomicBoolean subscribed = new AtomicBoolean();\n\n    private volatile Flow.Subscriber<? super T> downstream;\n\n    protected volatile CallStreamObserver<?> subscription;\n\n    private final AtomicBoolean hasSub = new AtomicBoolean();\n\n    // cancel status\n    private volatile boolean cancelled;\n\n    // complete status\n    private volatile boolean done;\n\n    // to help bind TripleSubscriber\n    private volatile Consumer<CallStreamObserver<?>> onSubscribe;\n\n    private volatile Runnable shutdownHook;\n\n    private final AtomicBoolean calledShutdown = new AtomicBoolean();\n\n    public AbstractTripleMutinyPublisher() {}\n\n    public AbstractTripleMutinyPublisher(Consumer<CallStreamObserver<?>> onSubscribe, Runnable shutdownHook) {\n        this.onSubscribe = onSubscribe;\n        this.shutdownHook = shutdownHook;\n    }\n\n    protected void onSubscribe(CallStreamObserver<?> subscription) {\n        if (subscription != null && this.subscription == null && hasSub.compareAndSet(false, true)) {\n            this.subscription = subscription;\n            subscription.disableAutoFlowControl();\n            if (onSubscribe != null) {\n                onSubscribe.accept(subscription);\n            }\n            return;\n        }\n        throw new IllegalStateException(getClass().getSimpleName() + \" supports only a single subscription\");\n    }\n\n    @Override\n    public void subscribe(Flow.Subscriber<? super T> s) {\n        if (s == null) {\n            throw new NullPointerException();\n        }\n        if (subscribed.compareAndSet(false, true)) {\n            this.downstream = s;\n            s.onSubscribe(this);\n            if (cancelled) this.downstream = null;\n        }\n    }\n\n    @Override\n    public void request(long n) {\n        synchronized (this) {\n            if (subscribed.get() && canRequest) {\n                subscription.request(n >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) n);\n            } else {\n                requested += n;\n            }\n        }\n    }\n\n    @Override\n    public void startRequest() {\n        synchronized (this) {\n            if (!canRequest) {\n                canRequest = true;\n                long n = requested;\n                subscription.request(n >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) n);\n            }\n        }\n    }\n\n    @Override\n    public void cancel() {\n        if (!cancelled) {\n            cancelled = true;\n            doShutdown();\n        }\n    }\n\n    @Override\n    public void onNext(T item) {\n        if (done || cancelled) {\n            return;\n        }\n        downstream.onNext(item);\n    }\n\n    @Override\n    public void onError(Throwable t) {\n        if (done || cancelled) {\n            return;\n        }\n        done = true;\n        downstream.onError(t);\n        doShutdown();\n    }\n\n    @Override\n    public void onCompleted() {\n        if (done || cancelled) {\n            return;\n        }\n        done = true;\n        downstream.onComplete();\n        doShutdown();\n    }\n\n    private void doShutdown() {\n        Runnable r = shutdownHook;\n        // CAS to confirm shutdownHook will be run only once.\n        if (r != null && calledShutdown.compareAndSet(false, true)) {\n            shutdownHook = null;\n            r.run();\n        }\n    }\n\n    public boolean isCancelled() {\n        return cancelled;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/AbstractTripleMutinySubscriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\n\nimport java.util.concurrent.Flow;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * The middle layer between {@link CallStreamObserver} and Reactive API. <br>\n * Passing the data from Reactive producer to CallStreamObserver.\n */\npublic abstract class AbstractTripleMutinySubscriber<T> implements Flow.Subscriber<T> {\n\n    private volatile boolean cancelled;\n\n    protected volatile CallStreamObserver<T> downstream;\n\n    private final AtomicBoolean subscribed = new AtomicBoolean();\n\n    private final AtomicBoolean hasSubscribed = new AtomicBoolean();\n\n    private volatile Flow.Subscription subscription;\n\n    // complete status\n    private volatile boolean done;\n\n    /**\n     * Binding the downstream, and call subscription#request(1).\n     *\n     * @param downstream downstream\n     */\n    public void subscribe(CallStreamObserver<T> downstream) {\n        if (downstream == null) {\n            throw new NullPointerException();\n        }\n        if (subscribed.compareAndSet(false, true)) {\n            this.downstream = downstream;\n            if (subscription != null) subscription.request(1);\n        }\n    }\n\n    @Override\n    public void onSubscribe(Flow.Subscription sub) {\n        if (this.subscription == null && hasSubscribed.compareAndSet(false, true)) {\n            this.subscription = sub;\n            return;\n        }\n        sub.cancel();\n    }\n\n    @Override\n    public void onNext(T item) {\n        if (!done && !cancelled) {\n            downstream.onNext(item);\n            subscription.request(1);\n        }\n    }\n\n    @Override\n    public void onError(Throwable t) {\n        if (!cancelled) {\n            done = true;\n            downstream.onError(t);\n        }\n    }\n\n    @Override\n    public void onComplete() {\n        if (!cancelled) {\n            done = true;\n            downstream.onCompleted();\n        }\n    }\n\n    public void cancel() {\n        if (!cancelled && subscription != null) {\n            cancelled = true;\n            subscription.cancel();\n        }\n    }\n\n    public boolean isCancelled() {\n        return cancelled;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/ClientTripleMutinyPublisher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.rpc.protocol.tri.observer.ClientCallToObserverAdapter;\n\nimport java.util.function.Consumer;\n\n/**\n * Used in OneToMany & ManyToOne & ManyToMany in client. <br>\n * It is a Publisher for user subscriber to subscribe. <br>\n * It is a StreamObserver for responseStream. <br>\n * It is a Subscription for user subscriber to request and pass request to requestStream.\n */\npublic class ClientTripleMutinyPublisher<T> extends AbstractTripleMutinyPublisher<T> {\n\n    public ClientTripleMutinyPublisher() {}\n\n    public ClientTripleMutinyPublisher(Consumer<CallStreamObserver<?>> onSubscribe, Runnable shutdownHook) {\n        super(onSubscribe, shutdownHook);\n    }\n\n    @Override\n    public void beforeStart(ClientCallToObserverAdapter<T> clientCallToObserverAdapter) {\n        super.onSubscribe(clientCallToObserverAdapter);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/ClientTripleMutinySubscriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny;\n\nimport org.apache.dubbo.rpc.protocol.tri.observer.ClientCallToObserverAdapter;\n\n/**\n * The subscriber in client to subscribe user publisher and is subscribed by ClientStreamObserver.\n */\npublic class ClientTripleMutinySubscriber<T> extends AbstractTripleMutinySubscriber<T> {\n\n    @Override\n    public void cancel() {\n        if (!isCancelled()) {\n            super.cancel();\n            ((ClientCallToObserverAdapter<T>) downstream).cancel(new Exception(\"Cancelled\"));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/ServerTripleMutinyPublisher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\n\n/**\n * Used in ManyToOne and ManyToMany in server. <br>\n * It is a Publisher for user subscriber to subscribe. <br>\n * It is a StreamObserver for requestStream. <br>\n * It is a Subscription for user subscriber to request and pass request to responseStream.\n */\npublic class ServerTripleMutinyPublisher<T> extends AbstractTripleMutinyPublisher<T> {\n\n    public ServerTripleMutinyPublisher(CallStreamObserver<?> callStreamObserver) {\n        super.onSubscribe(callStreamObserver);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/ServerTripleMutinySubscriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.rpc.CancellationContext;\nimport org.apache.dubbo.rpc.protocol.tri.CancelableStreamObserver;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\n\n/**\n * The Subscriber in server to passing the data produced by user publisher to responseStream.\n */\npublic class ServerTripleMutinySubscriber<T> extends AbstractTripleMutinySubscriber<T> {\n\n    /**\n     * The execution future of the current task, in order to be returned to stubInvoker\n     */\n    private final CompletableFuture<List<T>> executionFuture = new CompletableFuture<>();\n\n    /**\n     * The result elements collected by the current task.\n     * This class is a multi subscriber, which usually means there will be multiple elements, so it is declared as a list type.\n     */\n    private final List<T> collectedData = new ArrayList<>();\n\n    public ServerTripleMutinySubscriber() {}\n\n    public ServerTripleMutinySubscriber(CallStreamObserver<T> streamObserver) {\n        this.downstream = streamObserver;\n    }\n\n    @Override\n    public void subscribe(CallStreamObserver<T> downstream) {\n        super.subscribe(downstream);\n        if (downstream instanceof CancelableStreamObserver<?>) {\n            final CancelableStreamObserver<?> observer = (CancelableStreamObserver<?>) downstream;\n            final CancellationContext context;\n            if (observer.getCancellationContext() == null) {\n                context = new CancellationContext();\n                observer.setCancellationContext(context);\n            } else {\n                context = observer.getCancellationContext();\n            }\n            context.addListener(ctx -> super.cancel());\n        }\n    }\n\n    @Override\n    public void onNext(T t) {\n        super.onNext(t);\n        collectedData.add(t);\n    }\n\n    @Override\n    public void onError(Throwable throwable) {\n        super.onError(throwable);\n        executionFuture.completeExceptionally(throwable);\n    }\n\n    @Override\n    public void onComplete() {\n        super.onComplete();\n        executionFuture.complete(this.collectedData);\n    }\n\n    public CompletableFuture<List<T>> getExecutionFuture() {\n        return executionFuture;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/calls/MutinyClientCalls.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny.calls;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mutiny.ClientTripleMutinyPublisher;\nimport org.apache.dubbo.mutiny.ClientTripleMutinySubscriber;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.model.StubMethodDescriptor;\nimport org.apache.dubbo.rpc.stub.StubInvocationUtil;\n\nimport io.smallrye.mutiny.Multi;\nimport io.smallrye.mutiny.Uni;\nimport io.smallrye.mutiny.subscription.UniEmitter;\n\n/**\n * A collection of methods to convert client-side Mutiny calls to stream calls.\n */\npublic class MutinyClientCalls {\n\n    private MutinyClientCalls() {}\n\n    /**\n     * Implements a unary -> unary call as Uni -> Uni\n     *\n     * @param invoker invoker\n     * @param uniRequest the uni with request\n     * @param methodDescriptor the method descriptor\n     * @return the uni with response\n     */\n    public static <TRequest, TResponse, TInvoker> Uni<TResponse> oneToOne(\n            Invoker<TInvoker> invoker, Uni<TRequest> uniRequest, StubMethodDescriptor methodDescriptor) {\n        try {\n            return uniRequest.onItem().transformToUni(request -> Uni.createFrom()\n                    .emitter((UniEmitter<? super TResponse> emitter) -> {\n                        StubInvocationUtil.unaryCall(\n                                invoker, methodDescriptor, request, new StreamObserver<TResponse>() {\n                                    @Override\n                                    public void onNext(TResponse value) {\n                                        emitter.complete(value);\n                                    }\n\n                                    @Override\n                                    public void onError(Throwable t) {\n                                        emitter.fail(t);\n                                    }\n\n                                    @Override\n                                    public void onCompleted() {\n                                        // No-op\n                                    }\n                                });\n                    }));\n        } catch (Throwable throwable) {\n            return Uni.createFrom().failure(throwable);\n        }\n    }\n\n    /**\n     * Implements a unary -> stream call as Uni -> Multi\n     *\n     * @param invoker invoker\n     * @param uniRequest the uni with request\n     * @param methodDescriptor the method descriptor\n     * @return the multi with response\n     */\n    public static <TRequest, TResponse, TInvoker> Multi<TResponse> oneToMany(\n            Invoker<TInvoker> invoker, Uni<TRequest> uniRequest, StubMethodDescriptor methodDescriptor) {\n        try {\n            return uniRequest.onItem().transformToMulti(request -> {\n                ClientTripleMutinyPublisher<TResponse> clientPublisher = new ClientTripleMutinyPublisher<>();\n                StubInvocationUtil.serverStreamCall(invoker, methodDescriptor, request, clientPublisher);\n                return clientPublisher;\n            });\n        } catch (Throwable throwable) {\n            return Multi.createFrom().failure(throwable);\n        }\n    }\n\n    /**\n     * Implements a stream -> unary call as Multi -> Uni\n     *\n     * @param invoker invoker\n     * @param multiRequest the multi with request\n     * @param methodDescriptor the method descriptor\n     * @return the uni with response\n     */\n    public static <TRequest, TResponse, TInvoker> Uni<TResponse> manyToOne(\n            Invoker<TInvoker> invoker, Multi<TRequest> multiRequest, StubMethodDescriptor methodDescriptor) {\n        try {\n            ClientTripleMutinySubscriber<TRequest> clientSubscriber =\n                    multiRequest.subscribe().withSubscriber(new ClientTripleMutinySubscriber<>());\n            ClientTripleMutinyPublisher<TResponse> clientPublisher = new ClientTripleMutinyPublisher<>(\n                    s -> clientSubscriber.subscribe((CallStreamObserver<TRequest>) s), clientSubscriber::cancel);\n            return Uni.createFrom()\n                    .publisher(clientPublisher)\n                    .onSubscription()\n                    .invoke(() -> StubInvocationUtil.biOrClientStreamCall(invoker, methodDescriptor, clientPublisher));\n        } catch (Throwable err) {\n            return Uni.createFrom().failure(err);\n        }\n    }\n\n    /**\n     * Implements a stream -> stream call as Multi -> Multi\n     *\n     * @param invoker invoker\n     * @param multiRequest the multi with request\n     * @param methodDescriptor the method descriptor\n     * @return the multi with response\n     */\n    public static <TRequest, TResponse, TInvoker> Multi<TResponse> manyToMany(\n            Invoker<TInvoker> invoker, Multi<TRequest> multiRequest, StubMethodDescriptor methodDescriptor) {\n        try {\n            ClientTripleMutinySubscriber<TRequest> clientSubscriber =\n                    multiRequest.subscribe().withSubscriber(new ClientTripleMutinySubscriber<>());\n            ClientTripleMutinyPublisher<TResponse> clientPublisher = new ClientTripleMutinyPublisher<>(\n                    s -> clientSubscriber.subscribe((CallStreamObserver<TRequest>) s), clientSubscriber::cancel);\n            return Multi.createFrom()\n                    .publisher(clientPublisher)\n                    .onSubscription()\n                    .invoke(() -> StubInvocationUtil.biOrClientStreamCall(invoker, methodDescriptor, clientPublisher));\n        } catch (Throwable err) {\n            return Multi.createFrom().failure(err);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/calls/MutinyServerCalls.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny.calls;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mutiny.ServerTripleMutinyPublisher;\nimport org.apache.dubbo.mutiny.ServerTripleMutinySubscriber;\nimport org.apache.dubbo.rpc.StatusRpcException;\nimport org.apache.dubbo.rpc.TriRpcStatus;\n\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\nimport io.smallrye.mutiny.Multi;\nimport io.smallrye.mutiny.Uni;\n\n/**\n * A collection of methods to convert server-side stream calls to Mutiny calls.\n */\npublic class MutinyServerCalls {\n\n    private MutinyServerCalls() {}\n\n    /**\n     * Implements a unary -> unary call as Uni -> Uni\n     *\n     * @param request request\n     * @param responseObserver response StreamObserver\n     * @param func service implementation\n     */\n    public static <T, R> void oneToOne(T request, StreamObserver<R> responseObserver, Function<Uni<T>, Uni<R>> func) {\n        try {\n            func.apply(Uni.createFrom().item(request))\n                    .onItem()\n                    .ifNull()\n                    .failWith(TriRpcStatus.NOT_FOUND.asException())\n                    .subscribe()\n                    .with(\n                            item -> {\n                                responseObserver.onNext(item);\n                                responseObserver.onCompleted();\n                            },\n                            throwable -> doOnResponseHasException(throwable, responseObserver));\n        } catch (Throwable throwable) {\n            doOnResponseHasException(throwable, responseObserver);\n        }\n    }\n\n    /**\n     * Implements a unary -> stream call as Uni -> Multi\n     *\n     * @param request request\n     * @param responseObserver response StreamObserver\n     * @param func service implementation\n     */\n    public static <T, R> CompletableFuture<List<R>> oneToMany(\n            T request, StreamObserver<R> responseObserver, Function<Uni<T>, Multi<R>> func) {\n        try {\n            CallStreamObserver<R> callStreamObserver = (CallStreamObserver<R>) responseObserver;\n            Multi<R> response = func.apply(Uni.createFrom().item(request));\n            ServerTripleMutinySubscriber<R> mutinySubscriber = new ServerTripleMutinySubscriber<>(callStreamObserver);\n            response.subscribe().withSubscriber(mutinySubscriber).subscribe(callStreamObserver);\n            return mutinySubscriber.getExecutionFuture();\n        } catch (Throwable throwable) {\n            doOnResponseHasException(throwable, responseObserver);\n            CompletableFuture<List<R>> failed = new CompletableFuture<>();\n            failed.completeExceptionally(throwable);\n            return failed;\n        }\n    }\n\n    /**\n     * Implements a stream -> unary call as Multi -> Uni\n     *\n     * @param responseObserver response StreamObserver\n     * @param func service implementation\n     * @return request StreamObserver\n     */\n    public static <T, R> StreamObserver<T> manyToOne(\n            StreamObserver<R> responseObserver, Function<Multi<T>, Uni<R>> func) {\n        CallStreamObserver<R> callStreamObserver = (CallStreamObserver<R>) responseObserver;\n        ServerTripleMutinyPublisher<T> serverPublisher = new ServerTripleMutinyPublisher<>(callStreamObserver);\n        try {\n            Uni<R> responseUni = func.apply(Multi.createFrom().publisher(serverPublisher))\n                    .onItem()\n                    .ifNull()\n                    .failWith(TriRpcStatus.NOT_FOUND.asException());\n            responseUni\n                    .subscribe()\n                    .with(\n                            value -> {\n                                if (!serverPublisher.isCancelled()) {\n                                    callStreamObserver.onNext(value);\n                                    callStreamObserver.onCompleted();\n                                }\n                            },\n                            throwable -> {\n                                if (!serverPublisher.isCancelled()) {\n                                    callStreamObserver.onError(throwable);\n                                }\n                            });\n            serverPublisher.startRequest();\n        } catch (Throwable throwable) {\n            responseObserver.onError(throwable);\n        }\n        return serverPublisher;\n    }\n\n    /**\n     * Implements a stream -> stream call as Multi -> Multi\n     *\n     * @param responseObserver response StreamObserver\n     * @param func service implementation\n     * @return request StreamObserver\n     */\n    public static <T, R> StreamObserver<T> manyToMany(\n            StreamObserver<R> responseObserver, Function<Multi<T>, Multi<R>> func) {\n        CallStreamObserver<R> callStreamObserver = (CallStreamObserver<R>) responseObserver;\n        ServerTripleMutinyPublisher<T> serverPublisher = new ServerTripleMutinyPublisher<>(callStreamObserver);\n        try {\n            Multi<R> responseMulti = func.apply(Multi.createFrom().publisher(serverPublisher));\n            ServerTripleMutinySubscriber<R> serverSubscriber =\n                    responseMulti.subscribe().withSubscriber(new ServerTripleMutinySubscriber<>());\n            serverSubscriber.subscribe(callStreamObserver);\n            serverPublisher.startRequest();\n        } catch (Throwable throwable) {\n            responseObserver.onError(throwable);\n        }\n        return serverPublisher;\n    }\n\n    private static void doOnResponseHasException(Throwable throwable, StreamObserver<?> responseObserver) {\n        StatusRpcException statusRpcException =\n                TriRpcStatus.getStatus(throwable).asException();\n        responseObserver.onError(statusRpcException);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/handler/ManyToManyMethodHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny.handler;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mutiny.calls.MutinyServerCalls;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\nimport io.smallrye.mutiny.Multi;\n\n/**\n * The handler of ManyToMany() method for stub invocation.\n */\npublic class ManyToManyMethodHandler<T, R> implements StubMethodHandler<T, R> {\n\n    private final Function<Multi<T>, Multi<R>> func;\n\n    public ManyToManyMethodHandler(Function<Multi<T>, Multi<R>> func) {\n        this.func = func;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public CompletableFuture<StreamObserver<T>> invoke(Object[] arguments) {\n        CallStreamObserver<R> responseObserver = (CallStreamObserver<R>) arguments[0];\n        StreamObserver<T> requestObserver = MutinyServerCalls.manyToMany(responseObserver, func);\n        return CompletableFuture.completedFuture(requestObserver);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/handler/ManyToOneMethodHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny.handler;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mutiny.calls.MutinyServerCalls;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\nimport io.smallrye.mutiny.Multi;\nimport io.smallrye.mutiny.Uni;\n\n/**\n * The handler of ManyToOne() method for stub invocation.\n */\npublic class ManyToOneMethodHandler<T, R> implements StubMethodHandler<T, R> {\n\n    private final Function<Multi<T>, Uni<R>> func;\n\n    public ManyToOneMethodHandler(Function<Multi<T>, Uni<R>> func) {\n        this.func = func;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public CompletableFuture<StreamObserver<T>> invoke(Object[] arguments) {\n        CallStreamObserver<R> responseObserver = (CallStreamObserver<R>) arguments[0];\n        StreamObserver<T> requestObserver = MutinyServerCalls.manyToOne(responseObserver, func);\n        return CompletableFuture.completedFuture(requestObserver);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/handler/OneToManyMethodHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny.handler;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mutiny.calls.MutinyServerCalls;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\nimport io.smallrye.mutiny.Multi;\nimport io.smallrye.mutiny.Uni;\n\n/**\n * The handler of OneToMany() method for stub invocation.\n */\npublic class OneToManyMethodHandler<T, R> implements StubMethodHandler<T, R> {\n\n    private final Function<Uni<T>, Multi<R>> func;\n\n    public OneToManyMethodHandler(Function<Uni<T>, Multi<R>> func) {\n        this.func = func;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public CompletableFuture<?> invoke(Object[] arguments) {\n        T request = (T) arguments[0];\n        StreamObserver<R> responseObserver = (StreamObserver<R>) arguments[1];\n        return MutinyServerCalls.oneToMany(request, responseObserver, func);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/main/java/org/apache/dubbo/mutiny/handler/OneToOneMethodHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny.handler;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mutiny.calls.MutinyServerCalls;\nimport org.apache.dubbo.rpc.stub.FutureToObserverAdaptor;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\nimport io.smallrye.mutiny.Uni;\n\n/**\n * The handler of OneToOne() method for stub invocation.\n */\npublic class OneToOneMethodHandler<T, R> implements StubMethodHandler<T, R> {\n\n    private final Function<Uni<T>, Uni<R>> func;\n\n    public OneToOneMethodHandler(Function<Uni<T>, Uni<R>> func) {\n        this.func = func;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public CompletableFuture<R> invoke(Object[] arguments) {\n        T request = (T) arguments[0];\n        CompletableFuture<R> future = new CompletableFuture<>();\n        StreamObserver<R> responseObserver = new FutureToObserverAdaptor<>(future);\n        MutinyServerCalls.oneToOne(request, responseObserver, func);\n        return future;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/test/java/CreateObserverAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport org.apache.dubbo.rpc.protocol.tri.ServerStreamObserver;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.mockito.Mockito;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.doAnswer;\n\npublic class CreateObserverAdapter {\n\n    private ServerStreamObserver<String> responseObserver;\n    private AtomicInteger nextCounter;\n    private AtomicInteger completeCounter;\n    private AtomicInteger errorCounter;\n\n    CreateObserverAdapter() {\n\n        nextCounter = new AtomicInteger();\n        completeCounter = new AtomicInteger();\n        errorCounter = new AtomicInteger();\n\n        responseObserver = Mockito.mock(ServerStreamObserver.class);\n        doAnswer(o -> nextCounter.incrementAndGet()).when(responseObserver).onNext(anyString());\n        doAnswer(o -> completeCounter.incrementAndGet()).when(responseObserver).onCompleted();\n        doAnswer(o -> errorCounter.incrementAndGet()).when(responseObserver).onError(any(Throwable.class));\n    }\n\n    public AtomicInteger getCompleteCounter() {\n        return completeCounter;\n    }\n\n    public AtomicInteger getNextCounter() {\n        return nextCounter;\n    }\n\n    public AtomicInteger getErrorCounter() {\n        return errorCounter;\n    }\n\n    public ServerStreamObserver<String> getResponseObserver() {\n        return this.responseObserver;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/test/java/ManyToManyMethodHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mutiny.handler.ManyToManyMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * Unit test for ManyToManyMethodHandler\n */\npublic final class ManyToManyMethodHandlerTest {\n    @Test\n    void testInvoke() throws ExecutionException, InterruptedException {\n        CreateObserverAdapter creator = new CreateObserverAdapter();\n\n        ManyToManyMethodHandler<String, String> handler =\n                new ManyToManyMethodHandler<>(requestFlux -> requestFlux.map(r -> r + \"0\"));\n        CompletableFuture<StreamObserver<String>> future = handler.invoke(new Object[] {creator.getResponseObserver()});\n        StreamObserver<String> requestObserver = future.get();\n        for (int i = 0; i < 10; i++) {\n            requestObserver.onNext(String.valueOf(i));\n        }\n        requestObserver.onCompleted();\n        Assertions.assertEquals(10, creator.getNextCounter().get());\n        Assertions.assertEquals(0, creator.getErrorCounter().get());\n        Assertions.assertEquals(1, creator.getCompleteCounter().get());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/test/java/ManyToOneMethodHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mutiny.handler.ManyToOneMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * Unit test for ManyToOneMethodHandler\n */\npublic final class ManyToOneMethodHandlerTest {\n\n    private StreamObserver<String> requestObserver;\n    private CreateObserverAdapter creator;\n\n    @BeforeEach\n    void init() throws ExecutionException, InterruptedException {\n        creator = new CreateObserverAdapter();\n        ManyToOneMethodHandler<String, String> handler = new ManyToOneMethodHandler<>(requestMulti -> requestMulti\n                .map(Integer::valueOf)\n                .collect()\n                .asList()\n                .map(list -> list.stream().reduce(Integer::sum))\n                .map(String::valueOf));\n        CompletableFuture<StreamObserver<String>> future = handler.invoke(new Object[] {creator.getResponseObserver()});\n        requestObserver = future.get();\n    }\n\n    @Test\n    void testInvoker() {\n        for (int i = 0; i < 10; i++) {\n            requestObserver.onNext(String.valueOf(i));\n        }\n        requestObserver.onCompleted();\n        Assertions.assertEquals(1, creator.getNextCounter().get());\n        Assertions.assertEquals(0, creator.getErrorCounter().get());\n        Assertions.assertEquals(1, creator.getCompleteCounter().get());\n    }\n\n    @Test\n    void testError() {\n        for (int i = 0; i < 10; i++) {\n            if (i == 6) {\n                requestObserver.onError(new Throwable());\n            }\n            requestObserver.onNext(String.valueOf(i));\n        }\n        requestObserver.onCompleted();\n        Assertions.assertEquals(0, creator.getNextCounter().get());\n        Assertions.assertEquals(1, creator.getErrorCounter().get());\n        Assertions.assertEquals(0, creator.getCompleteCounter().get());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/test/java/OneToManyMethodHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport org.apache.dubbo.mutiny.handler.OneToManyMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\n\nimport io.smallrye.mutiny.Multi;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * Unit test for OneToManyMethodHandler\n */\npublic final class OneToManyMethodHandlerTest {\n\n    private CreateObserverAdapter creator;\n\n    @BeforeEach\n    void init() {\n        creator = new CreateObserverAdapter();\n    }\n\n    @Test\n    void testInvoke() {\n        String request = \"1,2,3,4,5,6,7\";\n        OneToManyMethodHandler<String, String> handler = new OneToManyMethodHandler<>(requestUni ->\n                requestUni.onItem().transformToMulti(r -> Multi.createFrom().items(r.split(\",\"))));\n        CompletableFuture<?> future = handler.invoke(new Object[] {request, creator.getResponseObserver()});\n        Assertions.assertTrue(future.isDone());\n        Assertions.assertEquals(7, creator.getNextCounter().get());\n        Assertions.assertEquals(0, creator.getErrorCounter().get());\n        Assertions.assertEquals(1, creator.getCompleteCounter().get());\n    }\n\n    @Test\n    void testError() {\n        String request = \"1,2,3,4,5,6,7\";\n        OneToManyMethodHandler<String, String> handler =\n                new OneToManyMethodHandler<>(requestUni -> Multi.createFrom().emitter(emitter -> {\n                    for (int i = 0; i < 10; i++) {\n                        if (i == 6) {\n                            emitter.fail(new Throwable());\n                            return;\n                        } else {\n                            emitter.emit(String.valueOf(i));\n                        }\n                    }\n                    emitter.complete();\n                }));\n        CompletableFuture<?> future = handler.invoke(new Object[] {request, creator.getResponseObserver()});\n        Assertions.assertTrue(future.isDone());\n        Assertions.assertEquals(6, creator.getNextCounter().get());\n        Assertions.assertEquals(1, creator.getErrorCounter().get());\n        Assertions.assertEquals(0, creator.getCompleteCounter().get());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/test/java/OneToOneMethodHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport org.apache.dubbo.mutiny.handler.OneToOneMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * Unit test for OneToOneMethodHandler\n */\npublic final class OneToOneMethodHandlerTest {\n\n    @Test\n    void testInvoke() throws ExecutionException, InterruptedException {\n        String request = \"request\";\n        OneToOneMethodHandler<String, String> handler =\n                new OneToOneMethodHandler<>(requestUni -> requestUni.map(r -> r + \"Test\"));\n        CompletableFuture<?> future = handler.invoke(new Object[] {request});\n        assertEquals(\"requestTest\", future.get());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/test/java/org/apache/dubbo/mutiny/MutinyClientCallsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mutiny.calls.MutinyClientCalls;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.model.StubMethodDescriptor;\nimport org.apache.dubbo.rpc.stub.StubInvocationUtil;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.smallrye.mutiny.Multi;\nimport io.smallrye.mutiny.Uni;\nimport io.smallrye.mutiny.helpers.test.AssertSubscriber;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\n/**\n * Unit test for MutinyClientCalls\n */\npublic class MutinyClientCallsTest {\n\n    @Test\n    void testOneToOneSuccess() {\n        Invoker<Object> invoker = Mockito.mock(Invoker.class);\n        StubMethodDescriptor method = Mockito.mock(StubMethodDescriptor.class);\n\n        try (MockedStatic<StubInvocationUtil> mocked = Mockito.mockStatic(StubInvocationUtil.class)) {\n            mocked.when(() -> StubInvocationUtil.unaryCall(\n                            Mockito.eq(invoker), Mockito.eq(method), Mockito.eq(\"req\"), Mockito.any()))\n                    .thenAnswer(invocation -> {\n                        StreamObserver<String> observer = invocation.getArgument(3);\n                        observer.onNext(\"resp\");\n                        observer.onCompleted();\n                        return null;\n                    });\n\n            Uni<String> request = Uni.createFrom().item(\"req\");\n            Uni<String> response = MutinyClientCalls.oneToOne(invoker, request, method);\n\n            String result = response.await().indefinitely();\n\n            Assertions.assertEquals(\"resp\", result);\n        }\n    }\n\n    @Test\n    void testOneToOneThrowsErrorWithMutinyAwait() {\n        Invoker<Object> invoker = Mockito.mock(Invoker.class);\n        StubMethodDescriptor method = Mockito.mock(StubMethodDescriptor.class);\n\n        try (MockedStatic<StubInvocationUtil> mocked = Mockito.mockStatic(StubInvocationUtil.class)) {\n            mocked.when(() -> StubInvocationUtil.unaryCall(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))\n                    .thenThrow(new RuntimeException(\"boom\"));\n\n            Uni<String> request = Uni.createFrom().item(\"req\");\n            Uni<String> response = MutinyClientCalls.oneToOne(invoker, request, method);\n\n            RuntimeException ex = Assertions.assertThrows(RuntimeException.class, () -> {\n                response.await().indefinitely();\n            });\n            Assertions.assertTrue(ex.getMessage().contains(\"boom\"));\n        }\n    }\n\n    @Test\n    void testOneToManyReturnsMultiAndEmitsItems() {\n        Invoker<Object> invoker = Mockito.mock(Invoker.class);\n        StubMethodDescriptor method = Mockito.mock(StubMethodDescriptor.class);\n\n        try (MockedStatic<StubInvocationUtil> mocked = Mockito.mockStatic(StubInvocationUtil.class)) {\n            AtomicBoolean stubCalled = new AtomicBoolean(false);\n            CountDownLatch subscribed = new CountDownLatch(1);\n\n            mocked.when(() -> StubInvocationUtil.serverStreamCall(\n                            Mockito.eq(invoker), Mockito.eq(method), Mockito.eq(\"testRequest\"), Mockito.any()))\n                    .thenAnswer(invocation -> {\n                        stubCalled.set(true);\n                        ClientTripleMutinyPublisher<String> publisher = invocation.getArgument(3);\n\n                        CallStreamObserver<String> fakeSubscription = new CallStreamObserver<>() {\n                            @Override\n                            public void request(int n) {\n                                /* no-op */\n                            }\n\n                            @Override\n                            public void setCompression(String compression) {}\n\n                            @Override\n                            public void disableAutoFlowControl() {}\n\n                            @Override\n                            public boolean isReady() {\n                                return true;\n                            }\n\n                            @Override\n                            public void setOnReadyHandler(Runnable onReadyHandler) {\n                                /* no-op for test */\n                            }\n\n                            @Override\n                            public void onNext(String v) {\n                                publisher.onNext(v);\n                            }\n\n                            @Override\n                            public void onError(Throwable t) {\n                                publisher.onError(t);\n                            }\n\n                            @Override\n                            public void onCompleted() {\n                                publisher.onCompleted();\n                            }\n                        };\n                        publisher.onSubscribe(fakeSubscription);\n\n                        // Wait for downstream subscription to complete before emitting data\n                        new Thread(() -> {\n                                    try {\n                                        if (subscribed.await(5, TimeUnit.SECONDS)) {\n                                            publisher.onNext(\"item1\");\n                                            publisher.onNext(\"item2\");\n                                            publisher.onCompleted();\n                                        } else {\n                                            publisher.onError(\n                                                    new IllegalStateException(\"Downstream subscription timeout\"));\n                                        }\n                                    } catch (InterruptedException e) {\n                                        Thread.currentThread().interrupt();\n                                        publisher.onError(e);\n                                    }\n                                })\n                                .start();\n\n                        return null;\n                    });\n\n            Uni<String> uniRequest = Uni.createFrom().item(\"testRequest\");\n            Multi<String> multiResponse = MutinyClientCalls.oneToMany(invoker, uniRequest, method);\n\n            // Use AssertSubscriber to ensure proper subscription timing\n            AssertSubscriber<String> subscriber = AssertSubscriber.create(Long.MAX_VALUE);\n            multiResponse.subscribe().withSubscriber(subscriber);\n\n            // Wait for subscription to be established\n            subscriber.awaitSubscription();\n            subscribed.countDown(); // Signal that data emission can begin\n\n            // Wait for completion\n            subscriber.awaitCompletion(Duration.ofSeconds(5));\n\n            // Verify results\n            Assertions.assertTrue(stubCalled.get(), \"StubInvocationUtil.serverStreamCall should be called\");\n            Assertions.assertEquals(List.of(\"item1\", \"item2\"), subscriber.getItems());\n            subscriber.assertCompleted();\n        }\n    }\n\n    @Test\n    void testManyToOneSuccess() {\n        Invoker<Object> invoker = Mockito.mock(Invoker.class);\n        StubMethodDescriptor method = Mockito.mock(StubMethodDescriptor.class);\n\n        Multi<String> multiRequest = Multi.createFrom().items(\"a\", \"b\", \"c\");\n\n        try (MockedStatic<StubInvocationUtil> mocked = Mockito.mockStatic(StubInvocationUtil.class)) {\n            AtomicBoolean stubCalled = new AtomicBoolean(false);\n\n            mocked.when(() -> StubInvocationUtil.biOrClientStreamCall(\n                            Mockito.eq(invoker), Mockito.eq(method), Mockito.any()))\n                    .thenAnswer(invocation -> {\n                        stubCalled.set(true);\n                        return null;\n                    });\n\n            Uni<String> uniResponse = MutinyClientCalls.manyToOne(invoker, multiRequest, method);\n\n            AtomicReference<String> resultHolder = new AtomicReference<>();\n            AtomicReference<Throwable> errorHolder = new AtomicReference<>();\n\n            CountDownLatch latch = new CountDownLatch(1);\n\n            uniResponse\n                    .subscribe()\n                    .with(\n                            item -> {\n                                resultHolder.set(item);\n                                latch.countDown();\n                            },\n                            failure -> {\n                                errorHolder.set(failure);\n                                latch.countDown();\n                            });\n\n            try {\n                latch.await(3, TimeUnit.SECONDS);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n\n            Assertions.assertTrue(stubCalled.get(), \"StubInvocationUtil.biOrClientStreamCall should be called\");\n            Assertions.assertNull(errorHolder.get(), \"No error expected\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/test/java/org/apache/dubbo/mutiny/MutinyServerCallsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.mutiny.calls.MutinyServerCalls;\n\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.function.Function;\n\nimport io.smallrye.mutiny.Multi;\nimport io.smallrye.mutiny.Uni;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\n/**\n * Unit test for MutinyServerCalls\n */\npublic class MutinyServerCallsTest {\n\n    @Test\n    void testOneToOne_success() {\n        StreamObserver<String> responseObserver = mock(StreamObserver.class);\n\n        Function<Uni<String>, Uni<String>> func = reqUni -> reqUni.onItem().transform(i -> i + \"-resp\");\n\n        MutinyServerCalls.oneToOne(\"req\", responseObserver, func);\n\n        // responseObserver\n        verify(responseObserver, times(1)).onNext(\"req-resp\");\n        verify(responseObserver, times(1)).onCompleted();\n        verify(responseObserver, never()).onError(any());\n    }\n\n    @Test\n    void testOneToOne_exception() {\n        StreamObserver<String> responseObserver = mock(StreamObserver.class);\n\n        // mock func error\n        Function<Uni<String>, Uni<String>> func = reqUni -> {\n            throw new RuntimeException(\"fail\");\n        };\n\n        MutinyServerCalls.oneToOne(\"req\", responseObserver, func);\n\n        verify(responseObserver, times(1)).onError(any());\n        verify(responseObserver, never()).onNext(any());\n        verify(responseObserver, never()).onCompleted();\n    }\n\n    @Test\n    void testOneToMany_success() throws ExecutionException, InterruptedException {\n        CallStreamObserver<String> responseObserver = mock(CallStreamObserver.class);\n\n        // multi results\n        Function<Uni<String>, Multi<String>> func = reqUni -> Multi.createFrom().items(\"a\", \"b\", \"c\");\n\n        CompletableFuture<List<String>> future = MutinyServerCalls.oneToMany(\"req\", responseObserver, func);\n\n        List<String> results = future.get();\n\n        assertEquals(3, results.size());\n\n        // test responseObserver\n        verify(responseObserver, atLeastOnce()).onNext(any());\n        verify(responseObserver, times(1)).onCompleted();\n        verify(responseObserver, never()).onError(any());\n    }\n\n    @Test\n    void testOneToMany_exception() {\n        CallStreamObserver<String> responseObserver = mock(CallStreamObserver.class);\n\n        Function<Uni<String>, Multi<String>> func = reqUni -> {\n            throw new RuntimeException(\"fail\");\n        };\n\n        CompletableFuture<List<String>> future = MutinyServerCalls.oneToMany(\"req\", responseObserver, func);\n\n        assertTrue(future.isCompletedExceptionally());\n\n        verify(responseObserver, times(1)).onError(any());\n    }\n\n    @Test\n    void testManyToOne_success() throws InterruptedException {\n        CallStreamObserver<String> responseObserver = mock(CallStreamObserver.class);\n\n        // return uni\n        Function<Multi<String>, Uni<String>> func =\n                multi -> multi.collect().asList().onItem().transform(list -> \"size:\" + list.size());\n\n        StreamObserver<String> requestObserver = MutinyServerCalls.manyToOne(responseObserver, func);\n\n        // mock onNext/onCompleted\n        requestObserver.onNext(\"a\");\n        requestObserver.onNext(\"b\");\n        requestObserver.onNext(\"c\");\n        requestObserver.onCompleted();\n\n        Thread.sleep(200);\n\n        verify(responseObserver, times(1)).onNext(\"size:3\");\n        verify(responseObserver, times(1)).onCompleted();\n        verify(responseObserver, never()).onError(any());\n    }\n\n    @Test\n    void testManyToOne_funcThrows() {\n        CallStreamObserver<String> responseObserver = mock(CallStreamObserver.class);\n\n        Function<Multi<String>, Uni<String>> func = multi -> {\n            throw new RuntimeException(\"fail\");\n        };\n\n        StreamObserver<String> requestObserver = MutinyServerCalls.manyToOne(responseObserver, func);\n\n        verify(responseObserver, times(1)).onError(any());\n    }\n\n    @Test\n    void testManyToMany_success() throws InterruptedException {\n        CallStreamObserver<String> responseObserver = mock(CallStreamObserver.class);\n\n        Function<Multi<String>, Multi<String>> func = multi -> multi.map(s -> s + \"-resp\");\n\n        StreamObserver<String> requestObserver = MutinyServerCalls.manyToMany(responseObserver, func);\n\n        // mock onNext/onCompleted\n        requestObserver.onNext(\"x\");\n        requestObserver.onNext(\"y\");\n        requestObserver.onCompleted();\n\n        Thread.sleep(200);\n\n        verify(responseObserver, atLeastOnce()).onNext(any());\n        verify(responseObserver, times(1)).onCompleted();\n        verify(responseObserver, never()).onError(any());\n    }\n\n    @Test\n    void testManyToMany_funcThrows() {\n        CallStreamObserver<String> responseObserver = mock(CallStreamObserver.class);\n\n        Function<Multi<String>, Multi<String>> func = multi -> {\n            throw new RuntimeException(\"fail\");\n        };\n\n        StreamObserver<String> requestObserver = MutinyServerCalls.manyToMany(responseObserver, func);\n\n        verify(responseObserver, times(1)).onError(any());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/test/java/org/apache/dubbo/mutiny/TripleMutinyPublisherTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Flow;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * Unit test for AbstractTripleMutinyPublisher\n */\npublic class TripleMutinyPublisherTest {\n\n    @Test\n    public void testSubscribeAndRequest() {\n        AtomicBoolean subscribed = new AtomicBoolean(false);\n\n        AbstractTripleMutinyPublisher<String> publisher = new AbstractTripleMutinyPublisher<>() {\n            @Override\n            protected void onSubscribe(CallStreamObserver<?> subscription) {\n                subscribed.set(true);\n                this.subscription = Mockito.mock(CallStreamObserver.class);\n            }\n        };\n\n        publisher.onSubscribe(Mockito.mock(CallStreamObserver.class));\n\n        Flow.Subscriber<String> subscriber = new Flow.Subscriber<>() {\n            @Override\n            public void onSubscribe(Flow.Subscription s) {\n                s.request(1);\n            }\n\n            @Override\n            public void onNext(String item) {}\n\n            @Override\n            public void onError(Throwable t) {}\n\n            @Override\n            public void onComplete() {}\n        };\n\n        publisher.subscribe(subscriber);\n        assertTrue(subscribed.get());\n    }\n\n    @Test\n    public void testRequestBeforeStartRequest() {\n        CallStreamObserver<?> mockObserver = Mockito.mock(CallStreamObserver.class);\n\n        AbstractTripleMutinyPublisher<String> publisher = new AbstractTripleMutinyPublisher<>() {};\n        publisher.onSubscribe(mockObserver);\n        publisher.request(5L); // should accumulate, not call request()\n        Mockito.verify(mockObserver, Mockito.never()).request(Mockito.anyInt());\n\n        publisher.startRequest(); // now should flush request\n        Mockito.verify(mockObserver).request(5);\n    }\n\n    @Test\n    public void testCancelTriggersShutdownHook() {\n        AtomicBoolean shutdown = new AtomicBoolean(false);\n\n        AbstractTripleMutinyPublisher<String> publisher =\n                new AbstractTripleMutinyPublisher<>(null, () -> shutdown.set(true)) {};\n\n        publisher.cancel();\n        assertTrue(publisher.isCancelled());\n        assertTrue(shutdown.get());\n    }\n\n    @Test\n    public void testOnNextAndComplete() {\n        List<String> received = new ArrayList<>();\n        AtomicBoolean completed = new AtomicBoolean();\n\n        AbstractTripleMutinyPublisher<String> publisher = new AbstractTripleMutinyPublisher<>() {};\n\n        publisher.subscribe(new Flow.Subscriber<>() {\n            @Override\n            public void onSubscribe(Flow.Subscription s) {}\n\n            @Override\n            public void onNext(String item) {\n                received.add(item);\n            }\n\n            @Override\n            public void onError(Throwable t) {}\n\n            @Override\n            public void onComplete() {\n                completed.set(true);\n            }\n        });\n\n        publisher.onNext(\"hello\");\n        publisher.onNext(\"world\");\n        publisher.onCompleted();\n\n        assertEquals(List.of(\"hello\", \"world\"), received);\n        assertTrue(completed.get());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/test/java/org/apache/dubbo/mutiny/TripleMutinySubscriberTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.mutiny;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\n\nimport java.util.concurrent.Flow;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * Unit test for AbstractTripleMutinySubscriber\n */\npublic class TripleMutinySubscriberTest {\n\n    @Test\n    void testSubscribeBindsDownstreamAndRequests() {\n        TestingSubscriber<String> subscriber = new TestingSubscriber<>();\n        Flow.Subscription subscription = Mockito.mock(Flow.Subscription.class);\n        CallStreamObserver<String> downstream = Mockito.mock(CallStreamObserver.class);\n\n        subscriber.onSubscribe(subscription); // bind subscription\n        subscriber.subscribe(downstream); // bind downstream\n\n        Mockito.verify(subscription).request(1);\n    }\n\n    @Test\n    void testOnNextPassesItemAndRequestsNext() {\n        TestingSubscriber<String> subscriber = new TestingSubscriber<>();\n        Flow.Subscription subscription = Mockito.mock(Flow.Subscription.class);\n        CallStreamObserver<String> downstream = Mockito.mock(CallStreamObserver.class);\n\n        subscriber.onSubscribe(subscription);\n        subscriber.subscribe(downstream);\n\n        subscriber.onNext(\"hello\");\n\n        Mockito.verify(downstream).onNext(\"hello\");\n        Mockito.verify(subscription, Mockito.times(2)).request(1); // 1st in subscribe, 2nd in onNext\n    }\n\n    @Test\n    void testOnErrorMarksDoneAndPropagates() {\n        TestingSubscriber<String> subscriber = new TestingSubscriber<>();\n        Flow.Subscription subscription = Mockito.mock(Flow.Subscription.class);\n        CallStreamObserver<String> downstream = Mockito.mock(CallStreamObserver.class);\n        RuntimeException error = new RuntimeException(\"boom\");\n\n        subscriber.onSubscribe(subscription);\n        subscriber.subscribe(downstream);\n\n        subscriber.onError(error);\n\n        Mockito.verify(downstream).onError(error);\n    }\n\n    @Test\n    void testOnCompleteMarksDoneAndNotifies() {\n        TestingSubscriber<String> subscriber = new TestingSubscriber<>();\n        Flow.Subscription subscription = Mockito.mock(Flow.Subscription.class);\n        CallStreamObserver<String> downstream = Mockito.mock(CallStreamObserver.class);\n\n        subscriber.onSubscribe(subscription);\n        subscriber.subscribe(downstream);\n\n        subscriber.onComplete();\n\n        Mockito.verify(downstream).onCompleted();\n    }\n\n    @Test\n    void testCancelCancelsSubscription() {\n        TestingSubscriber<String> subscriber = new TestingSubscriber<>();\n        Flow.Subscription subscription = Mockito.mock(Flow.Subscription.class);\n\n        subscriber.onSubscribe(subscription);\n        subscriber.cancel();\n\n        assertTrue(subscriber.isCancelled());\n        Mockito.verify(subscription).cancel();\n    }\n\n    @Test\n    void testSubscribeTwiceDoesNotRebind() {\n        TestingSubscriber<String> subscriber = new TestingSubscriber<>();\n        Flow.Subscription subscription = Mockito.mock(Flow.Subscription.class);\n        CallStreamObserver<String> downstream1 = Mockito.mock(CallStreamObserver.class);\n        CallStreamObserver<String> downstream2 = Mockito.mock(CallStreamObserver.class);\n\n        subscriber.onSubscribe(subscription);\n        subscriber.subscribe(downstream1);\n        subscriber.subscribe(downstream2);\n\n        subscriber.onNext(\"test\");\n        Mockito.verify(downstream1).onNext(\"test\");\n        Mockito.verify(downstream2, Mockito.never()).onNext(Mockito.any());\n    }\n\n    @Test\n    void testOnSubscribeTwiceCancelsSecond() {\n        TestingSubscriber<String> subscriber = new TestingSubscriber<>();\n        Flow.Subscription sub1 = Mockito.mock(Flow.Subscription.class);\n        Flow.Subscription sub2 = Mockito.mock(Flow.Subscription.class);\n\n        subscriber.onSubscribe(sub1);\n        subscriber.onSubscribe(sub2); // should cancel sub2\n\n        Mockito.verify(sub2).cancel();\n        Mockito.verify(sub1, Mockito.never()).cancel();\n    }\n\n    @Test\n    void testOnNextAfterDoneDoesNothing() {\n        TestingSubscriber<String> subscriber = new TestingSubscriber<>();\n        Flow.Subscription subscription = Mockito.mock(Flow.Subscription.class);\n        CallStreamObserver<String> downstream = Mockito.mock(CallStreamObserver.class);\n\n        subscriber.onSubscribe(subscription);\n        subscriber.subscribe(downstream);\n        subscriber.onComplete();\n\n        subscriber.onNext(\"after-done\"); // should be ignored\n\n        Mockito.verify(downstream, Mockito.never()).onNext(\"after-done\");\n    }\n\n    static class TestingSubscriber<T> extends AbstractTripleMutinySubscriber<T> {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-mutiny/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-native</artifactId>\n  <packaging>jar</packaging>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/ConditionalDescriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\n/**\n * A describer that describes the conditions for the configuration to take effect.\n */\npublic interface ConditionalDescriber {\n\n    String getReachableType();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/ExecutableDescriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Executable;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\n/**\n * A describer that describes the need for reflection on a {@link Executable}.\n */\npublic class ExecutableDescriber extends MemberDescriber {\n\n    private final List<String> parameterTypes;\n\n    private final ExecutableMode mode;\n\n    public ExecutableDescriber(Constructor<?> constructor, ExecutableMode mode) {\n        this(\n                \"<init>\",\n                Arrays.stream(constructor.getParameterTypes())\n                        .map(Class::getName)\n                        .collect(Collectors.toList()),\n                mode);\n    }\n\n    public ExecutableDescriber(String name, List<String> parameterTypes, ExecutableMode mode) {\n        super(name);\n        this.parameterTypes = parameterTypes;\n        this.mode = mode;\n    }\n\n    public List<String> getParameterTypes() {\n        return parameterTypes;\n    }\n\n    public ExecutableMode getMode() {\n        return mode;\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        ExecutableDescriber that = (ExecutableDescriber) o;\n        return Objects.equals(parameterTypes, that.parameterTypes) && mode == that.mode;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(parameterTypes, mode);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/ExecutableMode.java",
    "content": "/*\n * Copyright 2002-2022 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport java.lang.reflect.Executable;\n\n/**\n * Represent the need of reflection for a given {@link Executable}.\n */\npublic enum ExecutableMode {\n\n    /**\n     * Only retrieving the {@link Executable} and its metadata is required.\n     */\n    INTROSPECT,\n\n    /**\n     * Full reflection support is required, including the ability to invoke\n     * the {@link Executable}.\n     */\n    INVOKE;\n\n    /**\n     * Specify if this mode already includes the specified {@code other} mode.\n     * @param other the other mode to check\n     * @return {@code true} if this mode includes the other mode\n     */\n    boolean includes(ExecutableMode other) {\n        return (other == null || this.ordinal() >= other.ordinal());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/FieldDescriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport java.lang.reflect.Field;\n\n/**\n * A describer that describes the need for reflection on a {@link Field}.\n */\npublic class FieldDescriber extends MemberDescriber {\n    protected FieldDescriber(String name) {\n        super(name);\n    }\n\n    @Override\n    public int hashCode() {\n        return super.hashCode();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        return super.equals(obj);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/JdkProxyDescriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * A describer that describes the need for a JDK interface-based {@link java.lang.reflect.Proxy}.\n */\npublic class JdkProxyDescriber implements ConditionalDescriber {\n\n    private final List<String> proxiedInterfaces;\n\n    private final String reachableType;\n\n    public JdkProxyDescriber(List<String> proxiedInterfaces, String reachableType) {\n        this.proxiedInterfaces = proxiedInterfaces;\n        this.reachableType = reachableType;\n    }\n\n    public List<String> getProxiedInterfaces() {\n        return proxiedInterfaces;\n    }\n\n    @Override\n    public String getReachableType() {\n        return reachableType;\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        JdkProxyDescriber that = (JdkProxyDescriber) o;\n        return Objects.equals(proxiedInterfaces, that.proxiedInterfaces)\n                && Objects.equals(reachableType, that.reachableType);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(proxiedInterfaces, reachableType);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/MemberCategory.java",
    "content": "/*\n * Copyright 2002-2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Member;\nimport java.lang.reflect.Method;\n\n/**\n * Represent predefined {@linkplain Member members} groups.\n */\npublic enum MemberCategory {\n\n    /**\n     * A category that represents public {@linkplain Field fields}.\n     * @see Class#getFields()\n     */\n    PUBLIC_FIELDS,\n\n    /**\n     * A category that represents {@linkplain Class#getDeclaredFields() declared\n     * fields}, that is all fields defined by the class, but not inherited ones.\n     * @see Class#getDeclaredFields()\n     */\n    DECLARED_FIELDS,\n\n    /**\n     * A category that defines public {@linkplain Constructor constructors} can\n     * be introspected, but not invoked.\n     * @see Class#getConstructors()\n     * @see ExecutableMode#INTROSPECT\n     */\n    INTROSPECT_PUBLIC_CONSTRUCTORS,\n\n    /**\n     * A category that defines {@linkplain Class#getDeclaredConstructors() all\n     * constructors} can be introspected, but not invoked.\n     * @see Class#getDeclaredConstructors()\n     * @see ExecutableMode#INTROSPECT\n     */\n    INTROSPECT_DECLARED_CONSTRUCTORS,\n\n    /**\n     * A category that defines public {@linkplain Constructor constructors} can\n     * be invoked.\n     * @see Class#getConstructors()\n     * @see ExecutableMode#INVOKE\n     */\n    INVOKE_PUBLIC_CONSTRUCTORS,\n\n    /**\n     * A category that defines {@linkplain Class#getDeclaredConstructors() all\n     * constructors} can be invoked.\n     * @see Class#getDeclaredConstructors()\n     * @see ExecutableMode#INVOKE\n     */\n    INVOKE_DECLARED_CONSTRUCTORS,\n\n    /**\n     * A category that defines public {@linkplain Method methods}, including\n     * inherited ones can be introspect, but not invoked.\n     * @see Class#getMethods()\n     * @see ExecutableMode#INTROSPECT\n     */\n    INTROSPECT_PUBLIC_METHODS,\n\n    /**\n     * A category that defines {@linkplain Class#getDeclaredMethods() all\n     * methods}, excluding inherited ones can be introspected, but not invoked.\n     * @see Class#getDeclaredMethods()\n     * @see ExecutableMode#INTROSPECT\n     */\n    INTROSPECT_DECLARED_METHODS,\n\n    /**\n     * A category that defines public {@linkplain Method methods}, including\n     * inherited ones can be invoked.\n     * @see Class#getMethods()\n     * @see ExecutableMode#INVOKE\n     */\n    INVOKE_PUBLIC_METHODS,\n\n    /**\n     * A category that defines {@linkplain Class#getDeclaredMethods() all\n     * methods}, excluding inherited ones can be invoked.\n     * @see Class#getDeclaredMethods()\n     * @see ExecutableMode#INVOKE\n     */\n    INVOKE_DECLARED_METHODS,\n\n    /**\n     * A category that represents public {@linkplain Class#getClasses() inner\n     * classes}. Contrary to other categories, this does not register any\n     * particular reflection for them but rather make sure they are available\n     * via a call to {@link Class#getClasses}.\n     */\n    PUBLIC_CLASSES,\n\n    /**\n     * A category that represents all {@linkplain Class#getDeclaredClasses()\n     * inner classes}. Contrary to other categories, this does not register any\n     * particular reflection for them but rather make sure they are available\n     * via a call to {@link Class#getDeclaredClasses}.\n     */\n    DECLARED_CLASSES;\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/MemberDescriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport java.lang.reflect.Member;\n\n/**\n * Base describer that describes the need for reflection on a {@link Member}.\n *\n */\npublic class MemberDescriber {\n\n    private final String name;\n\n    protected MemberDescriber(String name) {\n        this.name = name;\n    }\n\n    /**\n     * Return the name of the member.\n     * @return the name\n     */\n    public String getName() {\n        return this.name;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/ProxyDescriberRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.List;\n\n@SPI\npublic interface ProxyDescriberRegistrar {\n    List<JdkProxyDescriber> getJdkProxyDescribers();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/ReflectionTypeDescriberRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.List;\n\n@SPI\npublic interface ReflectionTypeDescriberRegistrar {\n    List<TypeDescriber> getTypeDescribers();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/ResourceBundleDescriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.ResourceBundle;\n\n/**\n * A describer that describes the need to access a {@link ResourceBundle}.\n */\npublic class ResourceBundleDescriber implements ConditionalDescriber {\n\n    private final String name;\n\n    private final List<String> locales;\n\n    private final String reachableType;\n\n    public ResourceBundleDescriber(String name, List<String> locales, String reachableType) {\n        this.name = name;\n        this.locales = locales;\n        this.reachableType = reachableType;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public List<String> getLocales() {\n        return locales;\n    }\n\n    @Override\n    public String getReachableType() {\n        return reachableType;\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        ResourceBundleDescriber that = (ResourceBundleDescriber) o;\n        return name.equals(that.name) && locales.equals(that.locales) && reachableType.equals(that.reachableType);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name, locales, reachableType);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/ResourceDescriberRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.List;\n\n@SPI\npublic interface ResourceDescriberRegistrar {\n    List<ResourcePatternDescriber> getResourcePatternDescribers();\n\n    List<ResourceBundleDescriber> getResourceBundleDescribers();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/ResourcePatternDescriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport java.util.Arrays;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\n/**\n * A describer that describes resources that should be made available at runtime.\n */\npublic class ResourcePatternDescriber implements ConditionalDescriber {\n\n    private final String pattern;\n\n    private final String reachableType;\n\n    public ResourcePatternDescriber(String pattern, String reachableType) {\n        this.pattern = pattern;\n        this.reachableType = reachableType;\n    }\n\n    public String getPattern() {\n        return pattern;\n    }\n\n    @Override\n    public String getReachableType() {\n        return reachableType;\n    }\n\n    public Pattern toRegex() {\n        String prefix = (this.pattern.startsWith(\"*\") ? \".*\" : \"\");\n        String suffix = (this.pattern.endsWith(\"*\") ? \".*\" : \"\");\n        String regex = Arrays.stream(this.pattern.split(\"\\\\*\"))\n                .filter(s -> !s.isEmpty())\n                .map(Pattern::quote)\n                .collect(Collectors.joining(\".*\", prefix, suffix));\n        return Pattern.compile(regex);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/api/TypeDescriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.api;\n\nimport java.util.Set;\n\n/**\n * A describer that describes the need for reflection on a type.\n */\npublic class TypeDescriber implements ConditionalDescriber {\n\n    private final String name;\n\n    private final String reachableType;\n\n    private final Set<FieldDescriber> fields;\n\n    private final Set<ExecutableDescriber> constructors;\n\n    private final Set<ExecutableDescriber> methods;\n\n    private final Set<MemberCategory> memberCategories;\n\n    public TypeDescriber(\n            String name,\n            String reachableType,\n            Set<FieldDescriber> fields,\n            Set<ExecutableDescriber> constructors,\n            Set<ExecutableDescriber> methods,\n            Set<MemberCategory> memberCategories) {\n        this.name = name;\n        this.reachableType = reachableType;\n        this.fields = fields;\n        this.constructors = constructors;\n        this.methods = methods;\n        this.memberCategories = memberCategories;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public Set<MemberCategory> getMemberCategories() {\n        return memberCategories;\n    }\n\n    public Set<FieldDescriber> getFields() {\n        return fields;\n    }\n\n    public Set<ExecutableDescriber> getConstructors() {\n        return constructors;\n    }\n\n    public Set<ExecutableDescriber> getMethods() {\n        return methods;\n    }\n\n    @Override\n    public String getReachableType() {\n        return reachableType;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/AotProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport org.apache.dubbo.aot.api.JdkProxyDescriber;\nimport org.apache.dubbo.aot.api.ProxyDescriberRegistrar;\nimport org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;\nimport org.apache.dubbo.aot.api.ResourceBundleDescriber;\nimport org.apache.dubbo.aot.api.ResourceDescriberRegistrar;\nimport org.apache.dubbo.aot.api.ResourcePatternDescriber;\nimport org.apache.dubbo.aot.api.TypeDescriber;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * generate related self-adaptive code (native image does not support dynamic code generation. Therefore, code needs to be generated before compilation)\n */\npublic class AotProcessor {\n\n    public static void main(String[] args) {\n        String generatedSources = args[1];\n\n        List<Class<?>> classes = ClassSourceScanner.INSTANCE.spiClassesWithAdaptive();\n        NativeClassSourceWriter.INSTANCE.writeTo(classes, generatedSources);\n\n        NativeConfigurationWriter writer = new NativeConfigurationWriter(Paths.get(args[2]), args[4], args[5]);\n\n        ResourceConfigMetadataRepository resourceRepository = new ResourceConfigMetadataRepository();\n        resourceRepository.registerIncludesPatterns(\n                ResourceScanner.INSTANCE.distinctSpiResource().toArray(new String[] {}));\n        resourceRepository.registerIncludesPatterns(\n                ResourceScanner.INSTANCE.distinctSecurityResource().toArray(new String[] {}));\n        for (ResourcePatternDescriber resourcePatternDescriber : getResourcePatternDescribers()) {\n            resourceRepository.registerIncludesPattern(resourcePatternDescriber);\n        }\n        for (ResourceBundleDescriber resourceBundleDescriber : getResourceBundleDescribers()) {\n            resourceRepository.registerBundles(resourceBundleDescriber);\n        }\n        writer.writeResourceConfig(resourceRepository);\n\n        ReflectConfigMetadataRepository reflectRepository = new ReflectConfigMetadataRepository();\n        reflectRepository\n                .registerSpiExtensionType(new ArrayList<>(ClassSourceScanner.INSTANCE\n                        .distinctSpiExtensionClasses(ResourceScanner.INSTANCE.distinctSpiResource())\n                        .values()))\n                .registerAdaptiveType(new ArrayList<>(\n                        ClassSourceScanner.INSTANCE.adaptiveClasses().values()))\n                .registerBeanType(ClassSourceScanner.INSTANCE.scopeModelInitializer())\n                .registerConfigType(ClassSourceScanner.INSTANCE.configClasses())\n                .registerFieldType(getCustomClasses())\n                .registerTypeDescriber(getTypes());\n        writer.writeReflectionConfig(reflectRepository);\n\n        ProxyConfigMetadataRepository proxyRepository = new ProxyConfigMetadataRepository();\n        proxyRepository.registerProxyDescribers(getProxyDescribers());\n        writer.writeProxyConfig(proxyRepository);\n    }\n\n    private static List<TypeDescriber> getTypes() {\n        List<TypeDescriber> typeDescribers = new ArrayList<>();\n        FrameworkModel.defaultModel()\n                .defaultApplication()\n                .getExtensionLoader(ReflectionTypeDescriberRegistrar.class)\n                .getSupportedExtensionInstances()\n                .forEach(reflectionTypeDescriberRegistrar -> {\n                    List<TypeDescriber> describers = new ArrayList<>();\n                    try {\n                        describers = reflectionTypeDescriberRegistrar.getTypeDescribers();\n                    } catch (Throwable e) {\n                        // The ReflectionTypeDescriberRegistrar implementation classes are shaded, causing some unused\n                        // classes to be loaded.\n                        // When loading a dependent class may appear that cannot be found, it does not affect.\n                        // ignore\n                    }\n\n                    typeDescribers.addAll(describers);\n                });\n\n        return typeDescribers;\n    }\n\n    private static List<ResourcePatternDescriber> getResourcePatternDescribers() {\n        List<ResourcePatternDescriber> resourcePatternDescribers = new ArrayList<>();\n        FrameworkModel.defaultModel()\n                .defaultApplication()\n                .getExtensionLoader(ResourceDescriberRegistrar.class)\n                .getSupportedExtensionInstances()\n                .forEach(reflectionTypeDescriberRegistrar -> {\n                    List<ResourcePatternDescriber> describers = new ArrayList<>();\n                    try {\n                        describers = reflectionTypeDescriberRegistrar.getResourcePatternDescribers();\n                    } catch (Throwable e) {\n                        // The ResourceDescriberRegistrar implementation classes are shaded, causing some unused\n                        // classes to be loaded.\n                        // When loading a dependent class may appear that cannot be found, it does not affect.\n                        // ignore\n                    }\n\n                    resourcePatternDescribers.addAll(describers);\n                });\n\n        return resourcePatternDescribers;\n    }\n\n    private static List<ResourceBundleDescriber> getResourceBundleDescribers() {\n        List<ResourceBundleDescriber> resourceBundleDescribers = new ArrayList<>();\n        FrameworkModel.defaultModel()\n                .defaultApplication()\n                .getExtensionLoader(ResourceDescriberRegistrar.class)\n                .getSupportedExtensionInstances()\n                .forEach(reflectionTypeDescriberRegistrar -> {\n                    List<ResourceBundleDescriber> describers = new ArrayList<>();\n                    try {\n                        describers = reflectionTypeDescriberRegistrar.getResourceBundleDescribers();\n                    } catch (Throwable e) {\n                        // The ResourceDescriberRegistrar implementation classes are shaded, causing some unused\n                        // classes to be loaded.\n                        // When loading a dependent class may appear that cannot be found, it does not affect.\n                        // ignore\n                    }\n\n                    resourceBundleDescribers.addAll(describers);\n                });\n\n        return resourceBundleDescribers;\n    }\n\n    private static List<JdkProxyDescriber> getProxyDescribers() {\n        List<JdkProxyDescriber> jdkProxyDescribers = new ArrayList<>();\n        FrameworkModel.defaultModel()\n                .defaultApplication()\n                .getExtensionLoader(ProxyDescriberRegistrar.class)\n                .getSupportedExtensionInstances()\n                .forEach(reflectionTypeDescriberRegistrar -> {\n                    jdkProxyDescribers.addAll(reflectionTypeDescriberRegistrar.getJdkProxyDescribers());\n                });\n\n        return jdkProxyDescribers;\n    }\n\n    private static List<Class<?>> getCustomClasses() {\n        Class<?>[] configClasses = new Class[] {\n            CommonConstants.SystemProperty.class,\n            CommonConstants.ThirdPartyProperty.class,\n            CommonConstants.DubboProperty.class\n        };\n        return new ArrayList<>(Arrays.asList(configClasses));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/BasicJsonWriter.java",
    "content": "/*\n * Copyright 2002-2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.aot.generate;\n\n\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\n\n/**\n * Very basic json writer for the purposes of translating runtime hints to native\n * configuration.\n */\nclass BasicJsonWriter {\n\n    private final IndentingWriter writer;\n\n    /**\n     * Create a new instance with the specified indent value.\n     *\n     * @param writer       the writer to use\n     * @param singleIndent the value of one indent\n     */\n    public BasicJsonWriter(Writer writer, String singleIndent) {\n        this.writer = new IndentingWriter(writer, singleIndent);\n    }\n\n    /**\n     * Create a new instance using two whitespaces for the indent.\n     *\n     * @param writer the writer to use\n     */\n    public BasicJsonWriter(Writer writer) {\n        this(writer, \"  \");\n    }\n\n\n    /**\n     * Write an object with the specified attributes. Each attribute is\n     * written according to its value type:\n     * <ul>\n     * <li>Map: write the value as a nested object</li>\n     * <li>List: write the value as a nested array</li>\n     * <li>Otherwise, write a single value</li>\n     * </ul>\n     *\n     * @param attributes the attributes of the object\n     */\n    public void writeObject(Map<String, Object> attributes) {\n        writeObject(attributes, true);\n    }\n\n    /**\n     * Write an array with the specified items. Each item in the\n     * list is written either as a nested object or as an attribute\n     * depending on its type.\n     *\n     * @param items the items to write\n     * @see #writeObject(Map)\n     */\n    public void writeArray(List<?> items) {\n        writeArray(items, true);\n    }\n\n    private void writeObject(Map<String, Object> attributes, boolean newLine) {\n        if (attributes.isEmpty()) {\n            this.writer.print(\"{ }\");\n        } else {\n            this.writer.println(\"{\").indented(writeAll(attributes.entrySet().iterator(),\n                entry -> writeAttribute(entry.getKey(), entry.getValue()))).print(\"}\");\n        }\n        if (newLine) {\n            this.writer.println();\n        }\n    }\n\n    private void writeArray(List<?> items, boolean newLine) {\n        if (items.isEmpty()) {\n            this.writer.print(\"[ ]\");\n        } else {\n            this.writer.println(\"[\")\n                .indented(writeAll(items.iterator(), this::writeValue)).print(\"]\");\n        }\n        if (newLine) {\n            this.writer.println();\n        }\n    }\n\n    private <T> Runnable writeAll(Iterator<T> it, Consumer<T> writer) {\n        return () -> {\n            while (it.hasNext()) {\n                writer.accept(it.next());\n                if (it.hasNext()) {\n                    this.writer.println(\",\");\n                } else {\n                    this.writer.println();\n                }\n            }\n        };\n    }\n\n    private void writeAttribute(String name, Object value) {\n        this.writer.print(quote(name) + \": \");\n        writeValue(value);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void writeValue(Object value) {\n        if (value instanceof Map<?, ?>) {\n            writeObject((Map<String, Object>) value, false);\n        } else if (value instanceof List<?>) {\n            writeArray((List<?>) value, false);\n        } else if (value instanceof CharSequence) {\n            this.writer.print(quote(escape((CharSequence) value)));\n        } else if (value instanceof Boolean) {\n            this.writer.print(Boolean.toString((Boolean) value));\n        } else {\n            throw new IllegalStateException(\"unsupported type: \" + value.getClass());\n        }\n    }\n\n    private String quote(String name) {\n        return \"\\\"\" + name + \"\\\"\";\n    }\n\n\n    private static String escape(CharSequence input) {\n        StringBuilder builder = new StringBuilder();\n        input.chars().forEach(c -> {\n            if (c == '\"') {\n                builder.append(\"\\\\\\\"\");\n            } else if (c == '\\\\') {\n                builder.append(\"\\\\\\\\\");\n            } else if (c == '\\b') {\n                builder.append(\"\\\\b\");\n            } else if (c == '\\f') {\n                builder.append(\"\\\\f\");\n            } else if (c == '\\n') {\n                builder.append(\"\\\\n\");\n            } else if (c == '\\r') {\n                builder.append(\"\\\\r\");\n            } else if (c == '\\t') {\n                builder.append(\"\\\\t\");\n            } else if (c <= 0x1F) {\n                builder.append(String.format(\"\\\\u%04x\", c));\n            } else {\n                builder.append((char) c);\n            }\n        });\n        return builder.toString();\n    }\n\n\n    static class IndentingWriter extends Writer {\n\n        private final Writer out;\n\n        private final String singleIndent;\n\n        private int level = 0;\n\n        private String currentIndent = \"\";\n\n        private boolean prependIndent = false;\n\n        IndentingWriter(Writer out, String singleIndent) {\n            this.out = out;\n            this.singleIndent = singleIndent;\n        }\n\n        /**\n         * Write the specified text.\n         *\n         * @param string the content to write\n         */\n        public IndentingWriter print(String string) {\n            write(string.toCharArray(), 0, string.length());\n            return this;\n        }\n\n        /**\n         * Write the specified text and append a new line.\n         *\n         * @param string the content to write\n         */\n        public IndentingWriter println(String string) {\n            write(string.toCharArray(), 0, string.length());\n            return println();\n        }\n\n        /**\n         * Write a new line.\n         */\n        public IndentingWriter println() {\n            String separator = System.lineSeparator();\n            try {\n                this.out.write(separator.toCharArray(), 0, separator.length());\n            } catch (IOException ex) {\n                throw new IllegalStateException(ex);\n            }\n            this.prependIndent = true;\n            return this;\n        }\n\n        /**\n         * Increase the indentation level and execute the {@link Runnable}. Decrease the\n         * indentation level on completion.\n         *\n         * @param runnable the code to execute within an extra indentation level\n         */\n        public IndentingWriter indented(Runnable runnable) {\n            indent();\n            runnable.run();\n            return outdent();\n        }\n\n        /**\n         * Increase the indentation level.\n         */\n        private IndentingWriter indent() {\n            this.level++;\n            return refreshIndent();\n        }\n\n        /**\n         * Decrease the indentation level.\n         */\n        private IndentingWriter outdent() {\n            this.level--;\n            return refreshIndent();\n        }\n\n        private IndentingWriter refreshIndent() {\n            int count = Math.max(0, this.level);\n            StringBuilder str = new StringBuilder();\n            for (int i = 0; i < count; i++) {\n                str.append(this.singleIndent);\n            }\n            this.currentIndent = str.toString();\n            return this;\n        }\n\n        @Override\n        public void write(char[] chars, int offset, int length) {\n            try {\n                if (this.prependIndent) {\n                    this.out.write(this.currentIndent.toCharArray(), 0, this.currentIndent.length());\n                    this.prependIndent = false;\n                }\n                this.out.write(chars, offset, length);\n            } catch (IOException ex) {\n                throw new IllegalStateException(ex);\n            }\n        }\n\n        @Override\n        public void flush() throws IOException {\n            this.out.flush();\n        }\n\n        @Override\n        public void close() throws IOException {\n            this.out.close();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ClassSourceScanner.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.AbstractConfig;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n * A scanner for processing and filtering specific types of classes\n */\npublic class ClassSourceScanner extends JarScanner {\n\n    public static final ClassSourceScanner INSTANCE = new ClassSourceScanner();\n\n    /**\n     *  Filter out the spi classes with adaptive annotations\n     *  from all the class collections that can be loaded.\n     * @return All spi classes with adaptive annotations\n     */\n    public List<Class<?>> spiClassesWithAdaptive() {\n        Map<String, Class<?>> allClasses = getClasses();\n        List<Class<?>> spiClasses = new ArrayList<>(allClasses.values())\n                .stream()\n                        .filter(it -> {\n                            if (null == it) {\n                                return false;\n                            }\n                            Annotation anno = it.getAnnotation(SPI.class);\n                            if (null == anno) {\n                                return false;\n                            }\n                            Optional<Method> optional = Arrays.stream(it.getMethods())\n                                    .filter(it2 -> it2.getAnnotation(Adaptive.class) != null)\n                                    .findAny();\n                            return optional.isPresent();\n                        })\n                        .collect(Collectors.toList());\n\n        return spiClasses;\n    }\n\n    /**\n     * The required adaptive class.\n     * For example: LoadBalance$Adaptive.class\n     * @return adaptive class\n     */\n    public Map<String, Class<?>> adaptiveClasses() {\n        List<String> res = spiClassesWithAdaptive().stream()\n                .map((c) -> c.getName() + \"$Adaptive\")\n                .collect(Collectors.toList());\n        return forNames(res);\n    }\n\n    /**\n     * The required configuration class, which is a subclass of AbstractConfig,\n     * but which excludes abstract classes.\n     * @return configuration class\n     */\n    public List<Class<?>> configClasses() {\n        return getClasses().values().stream()\n                .filter(c -> AbstractConfig.class.isAssignableFrom(c) && !Modifier.isAbstract(c.getModifiers()))\n                .collect(Collectors.toList());\n    }\n\n    public Map<String, Class<?>> distinctSpiExtensionClasses(Set<String> spiResource) {\n\n        Map<String, Class<?>> extensionClasses = new HashMap<>();\n        spiResource.forEach((fileName) -> {\n            Enumeration<URL> resources;\n            try {\n                resources = ClassLoader.getSystemResources(fileName);\n                if (resources != null) {\n                    while (resources.hasMoreElements()) {\n                        extensionClasses.putAll(loadResource(resources.nextElement()));\n                    }\n                }\n            } catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        });\n\n        return extensionClasses;\n    }\n\n    /**\n     * Beans that need to be injected in advance in different ScopeModels.\n     * For example, the RouterSnapshotSwitcher that needs to be injected when ClusterScopeModelInitializer executes initializeFrameworkModel\n     * @return Beans that need to be injected in advance\n     */\n    public List<Class<?>> scopeModelInitializer() {\n        List<Class<?>> classes = new ArrayList<>();\n        classes.addAll(FrameworkModel.defaultModel().getBeanFactory().getRegisteredClasses());\n        classes.addAll(FrameworkModel.defaultModel()\n                .defaultApplication()\n                .getBeanFactory()\n                .getRegisteredClasses());\n        classes.addAll(FrameworkModel.defaultModel()\n                .defaultApplication()\n                .getDefaultModule()\n                .getBeanFactory()\n                .getRegisteredClasses());\n        return classes.stream().distinct().collect(Collectors.toList());\n    }\n\n    private Map<String, Class<?>> loadResource(URL resourceUrl) {\n        Map<String, Class<?>> extensionClasses = new HashMap<>();\n        try {\n            List<String> newContentList = getResourceContent(resourceUrl);\n            String clazz;\n            for (String line : newContentList) {\n                try {\n                    int i = line.indexOf('=');\n                    if (i > 0) {\n                        clazz = line.substring(i + 1).trim();\n                    } else {\n                        clazz = line;\n                    }\n                    if (StringUtils.isNotEmpty(clazz)) {\n                        extensionClasses.put(clazz, getClasses().get(clazz));\n                    }\n                } catch (Throwable t) {\n                }\n            }\n        } catch (Throwable t) {\n        }\n\n        return extensionClasses;\n    }\n\n    private List<String> getResourceContent(URL resourceUrl) throws IOException {\n        List<String> newContentList = new ArrayList<>();\n\n        try (BufferedReader reader =\n                new BufferedReader(new InputStreamReader(resourceUrl.openStream(), StandardCharsets.UTF_8))) {\n            String line;\n            while ((line = reader.readLine()) != null) {\n                final int ci = line.indexOf('#');\n                if (ci >= 0) {\n                    line = line.substring(0, ci);\n                }\n                line = line.trim();\n                if (line.length() > 0) {\n                    newContentList.add(line);\n                }\n            }\n        } catch (IOException e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n        return newContentList;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/JarScanner.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport java.io.File;\nimport java.net.JarURLConnection;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\n/**\n * A scanner that scan the dependent jar packages\n * to obtain the classes source and resources in them.\n */\npublic class JarScanner {\n\n    private static final String PACKAGE_NAME_PREFIX = \"org/apache/dubbo\";\n\n    private final Map<String, String> classNameCache;\n\n    private Map<String, Class<?>> classesCache;\n\n    private final List<String> resourcePathCache;\n\n    protected Map<String, Class<?>> getClasses() {\n        if (classesCache == null || classesCache.size() == 0) {\n            this.classesCache = forNames(classNameCache.values());\n        }\n        return classesCache;\n    }\n\n    public JarScanner() {\n        classNameCache = new HashMap<>();\n        resourcePathCache = new ArrayList<>();\n        scanURL(PACKAGE_NAME_PREFIX);\n    }\n\n    protected Map<String, Class<?>> forNames(Collection<String> classNames) {\n        Map<String, Class<?>> classes = new HashMap<>();\n        classNames.forEach((it) -> {\n            try {\n                Class<?> c = Class.forName(it);\n                classes.put(it, c);\n            } catch (Throwable ignored) {\n            }\n        });\n        return classes;\n    }\n\n    private void scanURL(String prefixName) {\n        try {\n            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n            Enumeration<URL> resources = classLoader.getResources(prefixName);\n            while (resources.hasMoreElements()) {\n                URL resource = resources.nextElement();\n                String protocol = resource.getProtocol();\n                if (\"file\".equals(protocol)) {\n                    scanFile(resource.getPath());\n                } else if (\"jar\".equals(protocol)) {\n                    try (JarFile jar = ((JarURLConnection) resource.openConnection()).getJarFile()) {\n                        scanJar(jar);\n                    }\n                }\n            }\n        } catch (Throwable ex) {\n            throw new RuntimeException(ex);\n        }\n    }\n\n    private void scanFile(String resource) {\n        File directory = new File(resource);\n        File[] listFiles = directory.listFiles();\n        if (listFiles != null) {\n            for (File file : listFiles) {\n                if (file.isDirectory()) {\n                    scanFile(file.getPath());\n                } else {\n                    String path = file.getPath();\n                    if (matchedDubboClasses(path)) {\n                        classNameCache.put(path, toClassName(path));\n                    }\n                }\n            }\n        }\n    }\n\n    private void scanJar(JarFile jar) {\n        Enumeration<JarEntry> entry = jar.entries();\n        JarEntry jarEntry;\n        String name;\n        while (entry.hasMoreElements()) {\n            jarEntry = entry.nextElement();\n            name = jarEntry.getName();\n\n            if (name.charAt(0) == '/') {\n                name = name.substring(1);\n            }\n\n            if (jarEntry.isDirectory()) {\n                continue;\n            }\n\n            if (matchedDubboClasses(name)) {\n                classNameCache.put(name, toClassName(name));\n            } else {\n                resourcePathCache.add(name);\n            }\n        }\n    }\n\n    protected List<String> getResourcePath() {\n        return resourcePathCache;\n    }\n\n    private boolean matchedDubboClasses(String path) {\n        return path.startsWith(PACKAGE_NAME_PREFIX) && path.endsWith(\".class\");\n    }\n\n    private String toClassName(String path) {\n        return path.contains(File.separator)\n                ? path.substring(0, path.length() - 6).replace(File.separator, \".\")\n                : path.substring(0, path.length() - 6).replace(\"/\", \".\");\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/NativeClassSourceWriter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport org.apache.dubbo.common.extension.AdaptiveClassCodeGenerator;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.nio.file.Paths;\nimport java.util.List;\nimport java.util.regex.Matcher;\n\nimport org.apache.commons.io.FileUtils;\n\n/**\n * Write the Adaptive bytecode class dynamically generated.\n */\npublic class NativeClassSourceWriter {\n\n    public static final NativeClassSourceWriter INSTANCE = new NativeClassSourceWriter();\n\n    public void writeTo(List<Class<?>> classes, String generatedSources) {\n        classes.forEach(it -> {\n            SPI spi = it.getAnnotation(SPI.class);\n            String value = spi.value();\n            if (StringUtils.isEmpty(value)) {\n                value = \"adaptive\";\n            }\n            AdaptiveClassCodeGenerator codeGenerator = new AdaptiveClassCodeGenerator(it, value);\n            String code = codeGenerator.generate(true);\n            try {\n                String file = generatedSources\n                        + File.separator\n                        + it.getName().replaceAll(\"\\\\.\", Matcher.quoteReplacement(File.separator));\n                String dir = Paths.get(file).getParent().toString();\n                FileUtils.forceMkdir(new File(dir));\n                code = LICENSED_STR + code + \"\\n\";\n                String fileName = file + \"$Adaptive.java\";\n                FileUtils.write(new File(fileName), code, Charset.defaultCharset());\n            } catch (IOException e) {\n                throw new IllegalStateException(\"Failed to generated adaptive class sources\", e);\n            }\n        });\n    }\n\n    private static final String LICENSED_STR =\n            \"/*\\n\" + \" * Licensed to the Apache Software Foundation (ASF) under one or more\\n\"\n                    + \" * contributor license agreements.  See the NOTICE file distributed with\\n\"\n                    + \" * this work for additional information regarding copyright ownership.\\n\"\n                    + \" * The ASF licenses this file to You under the Apache License, Version 2.0\\n\"\n                    + \" * (the \\\"License\\\"); you may not use this file except in compliance with\\n\"\n                    + \" * the License.  You may obtain a copy of the License at\\n\"\n                    + \" *\\n\"\n                    + \" *     http://www.apache.org/licenses/LICENSE-2.0\\n\"\n                    + \" *\\n\"\n                    + \" * Unless required by applicable law or agreed to in writing, software\\n\"\n                    + \" * distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n\"\n                    + \" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n\"\n                    + \" * See the License for the specific language governing permissions and\\n\"\n                    + \" * limitations under the License.\\n\"\n                    + \" */\\n\";\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/NativeConfigurationWriter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.nio.file.Path;\nimport java.util.function.Consumer;\n\n/**\n * Write Write configuration metadata information in\n * {@link ResourceConfigMetadataRepository} and {@link ReflectConfigMetadataRepository}\n * as GraalVM native configuration.\n *\n * @see <a href=\"https://www.graalvm.org/latest/reference-manual/native-image/overview/BuildConfiguration/\">Native Image Build Configuration</a>\n */\npublic class NativeConfigurationWriter {\n\n    private final Path basePath;\n\n    private final String groupId;\n\n    private final String artifactId;\n\n    public NativeConfigurationWriter(Path basePath, String groupId, String artifactId) {\n        this.basePath = basePath;\n        this.groupId = groupId;\n        this.artifactId = artifactId;\n    }\n\n    protected void writeTo(String fileName, Consumer<BasicJsonWriter> writer) {\n        try {\n            File file = createIfNecessary(fileName);\n            try (FileWriter out = new FileWriter(file)) {\n                writer.accept(createJsonWriter(out));\n            }\n        } catch (IOException ex) {\n            throw new IllegalStateException(\"Failed to write native configuration for \" + fileName, ex);\n        }\n    }\n\n    private File createIfNecessary(String filename) throws IOException {\n        Path outputDirectory = this.basePath.resolve(\"META-INF\").resolve(\"native-image\");\n        if (this.groupId != null && this.artifactId != null) {\n            outputDirectory = outputDirectory\n                    .resolve(this.groupId)\n                    .resolve(this.artifactId)\n                    .resolve(\"dubbo\");\n        }\n        outputDirectory.toFile().mkdirs();\n        File file = outputDirectory.resolve(filename).toFile();\n        file.createNewFile();\n        return file;\n    }\n\n    public void writeReflectionConfig(ReflectConfigMetadataRepository repository) {\n        writeTo(\"reflect-config.json\", writer -> ReflectionConfigWriter.INSTANCE.write(writer, repository));\n    }\n\n    public void writeResourceConfig(ResourceConfigMetadataRepository repository) {\n        writeTo(\"resource-config.json\", writer -> ResourceConfigWriter.INSTANCE.write(writer, repository));\n    }\n\n    public void writeProxyConfig(ProxyConfigMetadataRepository repository) {\n        writeTo(\"proxy-config.json\", writer -> ProxyConfigWriter.INSTANCE.write(writer, repository));\n    }\n\n    private BasicJsonWriter createJsonWriter(Writer out) {\n        return new BasicJsonWriter(out);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ProxyConfigMetadataRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport org.apache.dubbo.aot.api.JdkProxyDescriber;\n\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\npublic class ProxyConfigMetadataRepository {\n\n    private final Set<JdkProxyDescriber> jdkProxyDescribers;\n\n    public ProxyConfigMetadataRepository() {\n        this.jdkProxyDescribers = new LinkedHashSet<>();\n    }\n\n    public ProxyConfigMetadataRepository registerProxyDescriber(JdkProxyDescriber describer) {\n        this.jdkProxyDescribers.add(describer);\n        return this;\n    }\n\n    public ProxyConfigMetadataRepository registerProxyDescribers(List<JdkProxyDescriber> describers) {\n        this.jdkProxyDescribers.addAll(\n                describers.stream().filter(Objects::nonNull).collect(Collectors.toList()));\n        return this;\n    }\n\n    public Set<JdkProxyDescriber> getProxyDescribers() {\n        return jdkProxyDescribers;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ProxyConfigWriter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport org.apache.dubbo.aot.api.JdkProxyDescriber;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n/**\n * Write a {@link ProxyConfigMetadataRepository} to the JSON output expected by the GraalVM\n * {@code native-image} compiler, typically named {@code proxy-config.json}.\n */\npublic class ProxyConfigWriter {\n\n    public static final ProxyConfigWriter INSTANCE = new ProxyConfigWriter();\n\n    public void write(BasicJsonWriter writer, ProxyConfigMetadataRepository repository) {\n        writer.writeArray(\n                repository.getProxyDescribers().stream().map(this::toAttributes).collect(Collectors.toList()));\n    }\n\n    private Map<String, Object> toAttributes(JdkProxyDescriber describer) {\n        Map<String, Object> attributes = new LinkedHashMap<>();\n        handleCondition(attributes, describer);\n        attributes.put(\"interfaces\", describer.getProxiedInterfaces());\n        return attributes;\n    }\n\n    private void handleCondition(Map<String, Object> attributes, JdkProxyDescriber describer) {\n        if (describer.getReachableType() != null) {\n            Map<String, Object> conditionAttributes = new LinkedHashMap<>();\n            conditionAttributes.put(\"typeReachable\", describer.getReachableType());\n            attributes.put(\"condition\", conditionAttributes);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ReflectConfigMetadataRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport org.apache.dubbo.aot.api.ExecutableDescriber;\nimport org.apache.dubbo.aot.api.MemberCategory;\nimport org.apache.dubbo.aot.api.TypeDescriber;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.aot.api.ExecutableMode.INVOKE;\n\npublic class ReflectConfigMetadataRepository {\n\n    List<TypeDescriber> types;\n\n    public ReflectConfigMetadataRepository() {\n        this.types = new ArrayList<>();\n    }\n\n    protected ReflectConfigMetadataRepository registerSpiExtensionType(List<Class<?>> classes) {\n        types.addAll(classes.stream()\n                .filter(Objects::nonNull)\n                .map(this::buildTypeDescriberWithConstructor)\n                .collect(Collectors.toList()));\n        return this;\n    }\n\n    protected ReflectConfigMetadataRepository registerAdaptiveType(List<Class<?>> classes) {\n        types.addAll(classes.stream()\n                .filter(Objects::nonNull)\n                .map(this::buildTypeDescriberWithConstructor)\n                .collect(Collectors.toList()));\n        return this;\n    }\n\n    protected ReflectConfigMetadataRepository registerBeanType(List<Class<?>> classes) {\n        types.addAll(classes.stream()\n                .filter(Objects::nonNull)\n                .map(this::buildTypeDescriberWithConstructor)\n                .collect(Collectors.toList()));\n        return this;\n    }\n\n    protected ReflectConfigMetadataRepository registerConfigType(List<Class<?>> classes) {\n        types.addAll(classes.stream()\n                .filter(Objects::nonNull)\n                .map(this::buildTypeDescriberWithConstructor)\n                .collect(Collectors.toList()));\n        return this;\n    }\n\n    private TypeDescriber buildTypeDescriberWithConstructor(Class<?> c) {\n        Set<ExecutableDescriber> constructors = Arrays.stream(c.getConstructors())\n                .map((constructor) -> new ExecutableDescriber(constructor, INVOKE))\n                .collect(Collectors.toSet());\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_PUBLIC_METHODS);\n        return new TypeDescriber(c.getName(), null, new HashSet<>(), constructors, new HashSet<>(), memberCategories);\n    }\n\n    protected ReflectConfigMetadataRepository registerFieldType(List<Class<?>> classes) {\n        types.addAll(classes.stream()\n                .filter(Objects::nonNull)\n                .map(this::buildTypeDescriberWithField)\n                .collect(Collectors.toList()));\n        return this;\n    }\n\n    private TypeDescriber buildTypeDescriberWithField(Class<?> c) {\n        Set<ExecutableDescriber> constructors = Arrays.stream(c.getConstructors())\n                .map((constructor) -> new ExecutableDescriber(constructor, INVOKE))\n                .collect(Collectors.toSet());\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.PUBLIC_FIELDS);\n        return new TypeDescriber(c.getName(), null, new HashSet<>(), constructors, new HashSet<>(), memberCategories);\n    }\n\n    public void registerTypeDescriber(List<TypeDescriber> typeDescribers) {\n        types.addAll(typeDescribers.stream().filter(Objects::nonNull).collect(Collectors.toList()));\n    }\n\n    public List<TypeDescriber> getTypes() {\n        return types;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ReflectionConfigWriter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport org.apache.dubbo.aot.api.ExecutableDescriber;\nimport org.apache.dubbo.aot.api.ExecutableMode;\nimport org.apache.dubbo.aot.api.FieldDescriber;\nimport org.apache.dubbo.aot.api.MemberCategory;\nimport org.apache.dubbo.aot.api.TypeDescriber;\n\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n * Write {@link ReflectConfigMetadataRepository} to the JSON output expected by the GraalVM\n * {@code native-image} compiler, typically named {@code reflect-config.json}\n * or {@code jni-config.json}.\n */\npublic class ReflectionConfigWriter {\n\n    public static final ReflectionConfigWriter INSTANCE = new ReflectionConfigWriter();\n\n    public void write(BasicJsonWriter writer, ReflectConfigMetadataRepository repository) {\n        writer.writeArray(repository.getTypes().stream().map(this::toAttributes).collect(Collectors.toList()));\n    }\n\n    private Map<String, Object> toAttributes(TypeDescriber describer) {\n        Map<String, Object> attributes = new LinkedHashMap<>();\n        attributes.put(\"name\", describer.getName());\n        handleCondition(attributes, describer);\n        handleCategories(attributes, describer.getMemberCategories());\n        handleFields(attributes, describer.getFields());\n        handleExecutables(attributes, describer.getConstructors());\n        handleExecutables(attributes, describer.getMethods());\n        return attributes;\n    }\n\n    private void handleCondition(Map<String, Object> attributes, TypeDescriber describer) {\n        if (describer.getReachableType() != null) {\n            Map<String, Object> conditionAttributes = new LinkedHashMap<>();\n            conditionAttributes.put(\"typeReachable\", describer.getReachableType());\n            attributes.put(\"condition\", conditionAttributes);\n        }\n    }\n\n    private void handleFields(Map<String, Object> attributes, Set<FieldDescriber> fieldDescribers) {\n        addIfNotEmpty(\n                attributes,\n                \"fields\",\n                fieldDescribers.stream().map(this::toAttributes).collect(Collectors.toList()));\n    }\n\n    private Map<String, Object> toAttributes(FieldDescriber describer) {\n        Map<String, Object> attributes = new LinkedHashMap<>();\n        attributes.put(\"name\", describer.getName());\n        return attributes;\n    }\n\n    private void handleExecutables(Map<String, Object> attributes, Set<ExecutableDescriber> executableDescribers) {\n        addIfNotEmpty(\n                attributes,\n                \"methods\",\n                executableDescribers.stream()\n                        .filter(h -> h.getMode().equals(ExecutableMode.INVOKE))\n                        .map(this::toAttributes)\n                        .collect(Collectors.toList()));\n        addIfNotEmpty(\n                attributes,\n                \"queriedMethods\",\n                executableDescribers.stream()\n                        .filter(h -> h.getMode().equals(ExecutableMode.INTROSPECT))\n                        .map(this::toAttributes)\n                        .collect(Collectors.toList()));\n    }\n\n    private Map<String, Object> toAttributes(ExecutableDescriber describer) {\n        Map<String, Object> attributes = new LinkedHashMap<>();\n        attributes.put(\"name\", describer.getName());\n        attributes.put(\"parameterTypes\", describer.getParameterTypes());\n        return attributes;\n    }\n\n    private void handleCategories(Map<String, Object> attributes, Set<MemberCategory> categories) {\n        categories.forEach(category -> {\n            switch (category) {\n                case PUBLIC_FIELDS:\n                    attributes.put(\"allPublicFields\", true);\n                    break;\n                case DECLARED_FIELDS:\n                    attributes.put(\"allDeclaredFields\", true);\n                    break;\n                case INTROSPECT_PUBLIC_CONSTRUCTORS:\n                    attributes.put(\"queryAllPublicConstructors\", true);\n                    break;\n                case INTROSPECT_DECLARED_CONSTRUCTORS:\n                    attributes.put(\"queryAllDeclaredConstructors\", true);\n                    break;\n                case INVOKE_PUBLIC_CONSTRUCTORS:\n                    attributes.put(\"allPublicConstructors\", true);\n                    break;\n                case INVOKE_DECLARED_CONSTRUCTORS:\n                    attributes.put(\"allDeclaredConstructors\", true);\n                    break;\n                case INTROSPECT_PUBLIC_METHODS:\n                    attributes.put(\"queryAllPublicMethods\", true);\n                    break;\n                case INTROSPECT_DECLARED_METHODS:\n                    attributes.put(\"queryAllDeclaredMethods\", true);\n                    break;\n                case INVOKE_PUBLIC_METHODS:\n                    attributes.put(\"allPublicMethods\", true);\n                    break;\n                case INVOKE_DECLARED_METHODS:\n                    attributes.put(\"allDeclaredMethods\", true);\n                    break;\n                case PUBLIC_CLASSES:\n                    attributes.put(\"allPublicClasses\", true);\n                    break;\n                case DECLARED_CLASSES:\n                    attributes.put(\"allDeclaredClasses\", true);\n                    break;\n                default:\n                    break;\n            }\n        });\n    }\n\n    private void addIfNotEmpty(Map<String, Object> attributes, String name, Object value) {\n        if ((value instanceof Collection<?> && ((Collection<?>) value).size() != 0)) {\n            attributes.put(name, value);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ResourceConfigMetadataRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport org.apache.dubbo.aot.api.ResourceBundleDescriber;\nimport org.apache.dubbo.aot.api.ResourcePatternDescriber;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class ResourceConfigMetadataRepository {\n\n    private final List<ResourcePatternDescriber> includes;\n\n    private final List<ResourcePatternDescriber> excludes;\n\n    private final Set<ResourceBundleDescriber> resourceBundles;\n\n    public ResourceConfigMetadataRepository() {\n        this.includes = new ArrayList<>();\n        this.excludes = new ArrayList<>();\n        this.resourceBundles = new LinkedHashSet<>();\n    }\n\n    public ResourceConfigMetadataRepository registerIncludesPatterns(String... patterns) {\n        for (String pattern : patterns) {\n            registerIncludesPattern(new ResourcePatternDescriber(pattern, null));\n        }\n        return this;\n    }\n\n    public ResourceConfigMetadataRepository registerIncludesPattern(ResourcePatternDescriber describer) {\n        this.includes.add(describer);\n        return this;\n    }\n\n    public ResourceConfigMetadataRepository registerExcludesPattern(ResourcePatternDescriber describer) {\n        this.excludes.add(describer);\n        return this;\n    }\n\n    public ResourceConfigMetadataRepository registerBundles(ResourceBundleDescriber describer) {\n        this.resourceBundles.add(describer);\n        return this;\n    }\n\n    public List<ResourcePatternDescriber> getIncludes() {\n        return includes;\n    }\n\n    public List<ResourcePatternDescriber> getExcludes() {\n        return excludes;\n    }\n\n    public Set<ResourceBundleDescriber> getResourceBundles() {\n        return resourceBundles;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ResourceConfigWriter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport org.apache.dubbo.aot.api.ConditionalDescriber;\nimport org.apache.dubbo.aot.api.ResourceBundleDescriber;\nimport org.apache.dubbo.aot.api.ResourcePatternDescriber;\n\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n * Write a {@link ResourceConfigMetadataRepository} to the JSON output expected by the GraalVM\n * {@code native-image} compiler, typically named {@code resource-config.json}.\n */\npublic class ResourceConfigWriter {\n\n    public static final ResourceConfigWriter INSTANCE = new ResourceConfigWriter();\n\n    public void write(BasicJsonWriter writer, ResourceConfigMetadataRepository repository) {\n        Map<String, Object> attributes = new LinkedHashMap<>();\n        addIfNotEmpty(attributes, \"resources\", toAttributes(repository.getIncludes(), repository.getExcludes()));\n        handleResourceBundles(attributes, repository.getResourceBundles());\n        writer.writeObject(attributes);\n    }\n\n    private Map<String, Object> toAttributes(\n            List<ResourcePatternDescriber> includes, List<ResourcePatternDescriber> excludes) {\n        Map<String, Object> attributes = new LinkedHashMap<>();\n        addIfNotEmpty(\n                attributes,\n                \"includes\",\n                includes.stream().distinct().map(this::toAttributes).collect(Collectors.toList()));\n        addIfNotEmpty(\n                attributes,\n                \"excludes\",\n                excludes.stream().distinct().map(this::toAttributes).collect(Collectors.toList()));\n        return attributes;\n    }\n\n    private void handleResourceBundles(\n            Map<String, Object> attributes, Set<ResourceBundleDescriber> resourceBundleDescribers) {\n        addIfNotEmpty(\n                attributes,\n                \"bundles\",\n                resourceBundleDescribers.stream().map(this::toAttributes).collect(Collectors.toList()));\n    }\n\n    private Map<String, Object> toAttributes(ResourceBundleDescriber describer) {\n        Map<String, Object> attributes = new LinkedHashMap<>();\n        handleCondition(attributes, describer);\n        attributes.put(\"name\", describer.getName());\n        return attributes;\n    }\n\n    private Map<String, Object> toAttributes(ResourcePatternDescriber describer) {\n        Map<String, Object> attributes = new LinkedHashMap<>();\n        handleCondition(attributes, describer);\n        attributes.put(\"pattern\", describer.toRegex().toString());\n        return attributes;\n    }\n\n    private void addIfNotEmpty(Map<String, Object> attributes, String name, Object value) {\n        if (value instanceof Collection<?>) {\n            if (!((Collection<?>) value).isEmpty()) {\n                attributes.put(name, value);\n            }\n        } else if (value instanceof Map<?, ?>) {\n            if (!((Map<?, ?>) value).isEmpty()) {\n                attributes.put(name, value);\n            }\n        } else if (value != null) {\n            attributes.put(name, value);\n        }\n    }\n\n    private void handleCondition(Map<String, Object> attributes, ConditionalDescriber conditionalDescriber) {\n        if (conditionalDescriber.getReachableType() != null) {\n            Map<String, Object> conditionAttributes = new LinkedHashMap<>();\n            conditionAttributes.put(\"typeReachable\", conditionalDescriber.getReachableType());\n            attributes.put(\"condition\", conditionAttributes);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ResourceScanner.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n * A scanner for processing and filtering specific resource.\n */\npublic class ResourceScanner extends JarScanner {\n\n    private static final String DUBBO_INTERNAL_RESOURCE_DIRECTORY = \"META-INF/dubbo/internal/\";\n\n    private static final String DUBBO_RESOURCE_DIRECTORY = \"META-INF/dubbo/\";\n\n    private static final String SERVICES_RESOURCE_DIRECTORY = \"META-INF/services/\";\n\n    private static final String SECURITY_RESOURCE_DIRECTORY = \"security/\";\n\n    public static final ResourceScanner INSTANCE = new ResourceScanner();\n\n    public Set<String> distinctSpiResource() {\n        return getResourcePath().stream()\n                .distinct()\n                .filter(this::matchedSpiResource)\n                .collect(Collectors.toSet());\n    }\n\n    public Set<String> distinctSecurityResource() {\n        return getResourcePath().stream()\n                .distinct()\n                .filter(this::matchedSecurityResource)\n                .collect(Collectors.toSet());\n    }\n\n    private boolean matchedSecurityResource(String path) {\n        return path.startsWith(SECURITY_RESOURCE_DIRECTORY);\n    }\n\n    private boolean matchedSpiResource(String path) {\n        return path.startsWith(DUBBO_INTERNAL_RESOURCE_DIRECTORY)\n                || path.startsWith(DUBBO_RESOURCE_DIRECTORY)\n                || path.startsWith(SERVICES_RESOURCE_DIRECTORY);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/main/resources/Dockerfile",
    "content": "#  Licensed to the Apache Software Foundation (ASF) under one or more\n#  contributor license agreements.  See the NOTICE file distributed with\n#  this work for additional information regarding copyright ownership.\n#  The ASF licenses this file to You under the Apache License, Version 2.0\n#  (the \"License\"); you may not use this file except in compliance with\n#  the License.  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n\n# Create graalvm environment for running dubbo native projects\n\nFROM maven:3-jdk-11-slim\n\nWORKDIR /opt\n\nRUN apt-get update \\\n    && apt-get install -y gcc zlib1g-dev libstdc++-10-dev \\\n    && curl -L -o /opt/graalvm-ce.tar.gz \"https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.1.0/graalvm-ce-java11-linux-amd64-21.1.0.tar.gz\" \\\n    && tar -xf graalvm-ce.tar.gz \\\n    && /opt/graalvm-ce-java11-21.1.0/bin/gu install native-image \\\n    && rm graalvm-ce.tar.gz\n\nENV PATH=/opt/graalvm-ce-java11-21.1.0/bin/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\nENV JAVA_HOME=/opt/graalvm-ce-java11-21.1.0\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/test/java/org/apache/dubbo/aot/generate/ResourcePatternDescriberTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.aot.generate;\n\nimport org.apache.dubbo.aot.api.ResourcePatternDescriber;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\npublic class ResourcePatternDescriberTest {\n    @Test\n    public void testToRegex() {\n        ResourcePatternDescriber describer = new ResourcePatternDescriber(\n                \"META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector\", null);\n        Assertions.assertEquals(\n                \"\\\\QMETA-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector\\\\E\",\n                describer.toRegex().toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-native/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-plugin-loom/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-plugin-loom</artifactId>\n\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n      <optional>true</optional>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <configuration>\n          <source>21</source>\n          <target>21</target>\n          <release>21</release>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-plugin-loom/src/main/java/org/apache/dubbo/common/threadpool/support/loom/VirtualThreadPool.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.loom;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\n\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREAD_NAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_VIRTUAL_CORE;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\n\n/**\n * Creates a thread pool that use virtual thread\n *\n * @see Executors#newVirtualThreadPerTaskExecutor()\n */\npublic class VirtualThreadPool implements ThreadPool {\n    @Override\n    public Executor getExecutor(URL url) {\n        String name =\n                url.getParameter(THREAD_NAME_KEY, (String) url.getAttribute(THREAD_NAME_KEY, DEFAULT_THREAD_NAME));\n        int threads = url.getParameter(THREADS_VIRTUAL_CORE, 0);\n        if (threads > 0) {\n            return new ThreadPoolExecutor(\n                    threads,\n                    Integer.MAX_VALUE,\n                    0L,\n                    java.util.concurrent.TimeUnit.MILLISECONDS,\n                    new SynchronousQueue<>(),\n                    Thread.ofVirtual().name(name, 1).factory());\n        } else {\n            return Executors.newThreadPerTaskExecutor(\n                    Thread.ofVirtual().name(name, 1).factory());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-plugin-loom/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.ThreadPool",
    "content": "virtual=org.apache.dubbo.common.threadpool.support.loom.VirtualThreadPool\n"
  },
  {
    "path": "dubbo-plugin/dubbo-plugin-loom/src/test/java/org/apache/dubbo/common/threadpool/support/loom/VirtualThreadPoolTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.common.threadpool.support.loom;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadpool.ThreadPool;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_VIRTUAL_CORE;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.instanceOf;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.startsWith;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\npublic class VirtualThreadPoolTest {\n\n    @Test\n    @EnabledForJreRange(min = JRE.JAVA_21)\n    void getExecutor1() throws Exception {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + THREAD_NAME_KEY + \"=demo\");\n        ThreadPool threadPool = new VirtualThreadPool();\n        Executor executor = threadPool.getExecutor(url);\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        executor.execute(() -> {\n            Thread thread = Thread.currentThread();\n            assertTrue(thread.isVirtual());\n            assertThat(thread.getName(), startsWith(\"demo\"));\n            latch.countDown();\n        });\n\n        latch.await();\n        assertThat(latch.getCount(), is(0L));\n    }\n\n    @Test\n    @EnabledForJreRange(min = JRE.JAVA_21)\n    void getExecutor2() {\n        URL url = URL.valueOf(\"dubbo://10.20.130.230:20880/context/path?\" + QUEUES_KEY + \"=1\");\n        ThreadPool threadPool = new VirtualThreadPool();\n        assertThat(\n                threadPool.getExecutor(url).getClass().getName(),\n                Matchers.is(\"java.util.concurrent.ThreadPerTaskExecutor\"));\n    }\n\n    @Test\n    @EnabledForJreRange(min = JRE.JAVA_21)\n    void getExecutor3() throws Exception {\n        URL url = URL.valueOf(\n                \"dubbo://10.20.130.230:20880/context/path?\" + THREADS_VIRTUAL_CORE + \"=2&\" + THREAD_NAME_KEY + \"=demo\");\n        ThreadPool threadPool = new VirtualThreadPool();\n        Executor executor = threadPool.getExecutor(url);\n\n        assertThat(executor, instanceOf(ThreadPoolExecutor.class));\n        ThreadPoolExecutor tpe = (ThreadPoolExecutor) executor;\n        assertThat(tpe.getCorePoolSize(), is(2));\n        assertThat(tpe.getMaximumPoolSize(), is(Integer.MAX_VALUE));\n        assertThat(tpe.getQueue(), instanceOf(SynchronousQueue.class));\n\n        final CountDownLatch latch = new CountDownLatch(1);\n        executor.execute(() -> {\n            Thread thread = Thread.currentThread();\n            assertTrue(thread.isVirtual());\n            assertThat(thread.getName(), startsWith(\"demo\"));\n            latch.countDown();\n        });\n\n        latch.await();\n        assertThat(latch.getCount(), is(0L));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-qos</artifactId>\n  <packaging>jar</packaging>\n\n  <name>dubbo-qos</name>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-api</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-dubbo</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-fastjson2</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-qos-api</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-native</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-api</artifactId>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.qos.command.ActuatorCommandExecutor;\nimport org.apache.dubbo.qos.command.util.SerializeCheckUtils;\nimport org.apache.dubbo.qos.server.Server;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\npublic class QosScopeModelInitializer implements ScopeModelInitializer {\n\n    @Override\n    public void initializeFrameworkModel(FrameworkModel frameworkModel) {\n        ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();\n        beanFactory.registerBean(Server.class);\n        beanFactory.registerBean(SerializeCheckUtils.class);\n    }\n\n    @Override\n    public void initializeApplicationModel(ApplicationModel applicationModel) {\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        beanFactory.registerBean(ActuatorCommandExecutor.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/aot/QosReflectionTypeDescriberRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.aot;\n\nimport org.apache.dubbo.aot.api.MemberCategory;\nimport org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;\nimport org.apache.dubbo.aot.api.TypeDescriber;\nimport org.apache.dubbo.qos.server.handler.ForeignHostPermitHandler;\nimport org.apache.dubbo.qos.server.handler.QosProcessHandler;\nimport org.apache.dubbo.qos.server.handler.TelnetIdleEventHandler;\n\nimport java.nio.channels.spi.SelectorProvider;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class QosReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {\n\n    @Override\n    public List<TypeDescriber> getTypeDescribers() {\n        List<TypeDescriber> typeDescribers = new ArrayList<>();\n        typeDescribers.add(buildTypeDescriberWithPublicMethod(SelectorProvider.class));\n        typeDescribers.add(buildTypeDescriberWithPublicMethod(ForeignHostPermitHandler.class));\n        typeDescribers.add(buildTypeDescriberWithPublicMethod(QosProcessHandler.class));\n        typeDescribers.add(buildTypeDescriberWithPublicMethod(TelnetIdleEventHandler.class));\n        return typeDescribers;\n    }\n\n    private TypeDescriber buildTypeDescriberWithPublicMethod(Class<?> cl) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_PUBLIC_METHODS);\n        return new TypeDescriber(\n                cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/ActuatorCommandExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Arrays;\n\npublic class ActuatorCommandExecutor implements ActuatorExecutor {\n    private static final Logger logger = LoggerFactory.getLogger(ActuatorCommandExecutor.class);\n    private final ApplicationModel applicationModel;\n\n    public ActuatorCommandExecutor(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    @Override\n    public String execute(String commandName, String[] parameters) {\n        CommandContext commandContext;\n\n        if (parameters == null || parameters.length == 0) {\n            commandContext = CommandContextFactory.newInstance(commandName);\n            commandContext.setHttp(true);\n        } else {\n            commandContext = CommandContextFactory.newInstance(commandName, parameters, true);\n        }\n\n        logger.info(\"[Dubbo Actuator QoS] Command Process start. Command: \" + commandContext.getCommandName()\n                + \", Args: \" + Arrays.toString(commandContext.getArgs()));\n\n        BaseCommand command;\n        try {\n            command = applicationModel\n                    .getExtensionLoader(BaseCommand.class)\n                    .getExtension(commandContext.getCommandName());\n            return command.execute(commandContext, commandContext.getArgs());\n        } catch (Throwable t) {\n            logger.info(\n                    \"[Dubbo Actuator QoS] Command Process Failed. Command: \" + commandContext.getCommandName()\n                            + \", Args: \" + Arrays.toString(commandContext.getArgs()),\n                    t);\n            throw t;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/ActuatorExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command;\n\npublic interface ActuatorExecutor {\n\n    String execute(String command, String[] args);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandContextFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command;\n\nimport org.apache.dubbo.qos.api.CommandContext;\n\npublic class CommandContextFactory {\n    public static CommandContext newInstance(String commandName) {\n        return new CommandContext(commandName);\n    }\n\n    public static CommandContext newInstance(String commandName, String[] args, boolean isHttp) {\n        return new CommandContext(commandName, args, isHttp);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/CommandExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command;\n\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.command.exception.NoSuchCommandException;\nimport org.apache.dubbo.qos.command.exception.PermissionDenyException;\n\npublic interface CommandExecutor {\n    /**\n     * Execute one command and return the execution result\n     *\n     * @param commandContext command context\n     * @return command execution result\n     * @throws NoSuchCommandException\n     */\n    String execute(CommandContext commandContext) throws NoSuchCommandException, PermissionDenyException;\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/DefaultCommandExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.command.exception.NoSuchCommandException;\nimport org.apache.dubbo.qos.command.exception.PermissionDenyException;\nimport org.apache.dubbo.qos.common.QosConstants;\nimport org.apache.dubbo.qos.permission.DefaultAnonymousAccessPermissionChecker;\nimport org.apache.dubbo.qos.permission.PermissionChecker;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Arrays;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport io.netty.channel.Channel;\n\npublic class DefaultCommandExecutor implements CommandExecutor {\n    private static final Logger logger = LoggerFactory.getLogger(DefaultCommandExecutor.class);\n    private final FrameworkModel frameworkModel;\n\n    public DefaultCommandExecutor(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext) throws NoSuchCommandException, PermissionDenyException {\n        String remoteAddress = Optional.ofNullable(commandContext.getRemote())\n                .map(Channel::remoteAddress)\n                .map(Objects::toString)\n                .orElse(\"unknown\");\n\n        logger.info(\"[Dubbo QoS] Command Process start. Command: \" + commandContext.getCommandName() + \", Args: \"\n                + Arrays.toString(commandContext.getArgs()) + \", Remote Address: \" + remoteAddress);\n\n        BaseCommand command = null;\n        try {\n            command =\n                    frameworkModel.getExtensionLoader(BaseCommand.class).getExtension(commandContext.getCommandName());\n        } catch (Throwable throwable) {\n            // can't find command\n        }\n        if (command == null) {\n            logger.info(\"[Dubbo QoS] Command Not found. Command: \" + commandContext.getCommandName()\n                    + \", Remote Address: \" + remoteAddress);\n            throw new NoSuchCommandException(commandContext.getCommandName());\n        }\n\n        // check permission when configs allow anonymous access\n        if (commandContext.isAllowAnonymousAccess()) {\n            PermissionChecker permissionChecker = DefaultAnonymousAccessPermissionChecker.INSTANCE;\n            try {\n                permissionChecker = frameworkModel\n                        .getExtensionLoader(PermissionChecker.class)\n                        .getExtension(QosConstants.QOS_PERMISSION_CHECKER);\n            } catch (Throwable throwable) {\n                // can't find valid custom permissionChecker\n            }\n\n            final Cmd cmd = command.getClass().getAnnotation(Cmd.class);\n            final PermissionLevel cmdRequiredPermissionLevel = cmd.requiredPermissionLevel();\n\n            if (!permissionChecker.access(commandContext, cmdRequiredPermissionLevel)) {\n                logger.info(\n                        \"[Dubbo QoS] Command Deny to access. Command: \" + commandContext.getCommandName() + \", Args: \"\n                                + Arrays.toString(commandContext.getArgs()) + \", Required Permission Level: \"\n                                + cmdRequiredPermissionLevel + \", Remote Address: \"\n                                + remoteAddress);\n                throw new PermissionDenyException(commandContext.getCommandName());\n            }\n        }\n\n        try {\n            String result = command.execute(commandContext, commandContext.getArgs());\n            if (command.logResult()) {\n                logger.info(\"[Dubbo QoS] Command Process success. Command: \" + commandContext.getCommandName()\n                        + \", Args: \"\n                        + Arrays.toString(commandContext.getArgs()) + \", Result: \" + result + \", Remote Address: \"\n                        + remoteAddress);\n            }\n            return result;\n        } catch (Throwable t) {\n            logger.info(\n                    \"[Dubbo QoS] Command Process Failed. Command: \" + commandContext.getCommandName() + \", Args: \"\n                            + Arrays.toString(commandContext.getArgs()) + \", Remote Address: \"\n                            + remoteAddress,\n                    t);\n            throw t;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/decoder/HttpCommandDecoder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.decoder;\n\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.command.CommandContextFactory;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpRequest;\nimport io.netty.handler.codec.http.QueryStringDecoder;\nimport io.netty.handler.codec.http.multipart.Attribute;\nimport io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;\nimport io.netty.handler.codec.http.multipart.InterfaceHttpData;\n\npublic class HttpCommandDecoder {\n    public static CommandContext decode(HttpRequest request) {\n        CommandContext commandContext = null;\n        if (request != null) {\n            QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri());\n            String path = queryStringDecoder.path();\n            String[] array = path.split(\"/\");\n            if (array.length == 2) {\n                String name = array[1];\n\n                // process GET request and POST request separately. Check url for GET, and check body for POST\n                if (request.method() == HttpMethod.GET) {\n                    if (queryStringDecoder.parameters().isEmpty()) {\n                        commandContext = CommandContextFactory.newInstance(name);\n                        commandContext.setHttp(true);\n                    } else {\n                        List<String> valueList = new ArrayList<>();\n                        for (List<String> values :\n                                queryStringDecoder.parameters().values()) {\n                            valueList.addAll(values);\n                        }\n                        commandContext =\n                                CommandContextFactory.newInstance(name, valueList.toArray(new String[] {}), true);\n                    }\n                } else if (request.method() == HttpMethod.POST) {\n                    HttpPostRequestDecoder httpPostRequestDecoder = null;\n                    try {\n                        httpPostRequestDecoder = new HttpPostRequestDecoder(request);\n                        List<String> valueList = new ArrayList<>();\n                        for (InterfaceHttpData interfaceHttpData : httpPostRequestDecoder.getBodyHttpDatas()) {\n                            if (interfaceHttpData.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {\n                                Attribute attribute = (Attribute) interfaceHttpData;\n                                try {\n                                    valueList.add(attribute.getValue());\n                                } catch (IOException ex) {\n                                    throw new RuntimeException(ex);\n                                }\n                            }\n                        }\n                        if (valueList.isEmpty()) {\n                            commandContext = CommandContextFactory.newInstance(name);\n                            commandContext.setHttp(true);\n                        } else {\n                            commandContext =\n                                    CommandContextFactory.newInstance(name, valueList.toArray(new String[] {}), true);\n                        }\n                    } finally {\n                        if (httpPostRequestDecoder != null) {\n                            httpPostRequestDecoder.destroy();\n                        }\n                    }\n                }\n            } else if (array.length == 3) {\n                String name = array[1];\n                String appName = array[2];\n                if (request.method() == HttpMethod.GET) {\n                    commandContext = CommandContextFactory.newInstance(name, new String[] {appName}, true);\n                    commandContext.setHttp(true);\n                }\n            }\n        }\n\n        return commandContext;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/decoder/TelnetCommandDecoder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.decoder;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.command.CommandContextFactory;\n\npublic class TelnetCommandDecoder {\n    public static final CommandContext decode(String str) {\n        CommandContext commandContext = null;\n        if (!StringUtils.isBlank(str)) {\n            str = str.trim();\n            String[] array = str.split(\"(?<![\\\\\\\\]) \");\n            if (array.length > 0) {\n                String[] targetArgs = new String[array.length - 1];\n                System.arraycopy(array, 1, targetArgs, 0, array.length - 1);\n                String name = array[0].trim();\n                if (name.equals(\"invoke\") && array.length > 2) {\n                    targetArgs = reBuildInvokeCmdArgs(str);\n                }\n                commandContext = CommandContextFactory.newInstance(name, targetArgs, false);\n                commandContext.setOriginRequest(str);\n            }\n        }\n\n        return commandContext;\n    }\n\n    private static String[] reBuildInvokeCmdArgs(String cmd) {\n        return new String[] {cmd.substring(cmd.indexOf(\" \") + 1).trim()};\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/CommandException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.exception;\n\npublic class CommandException extends Exception {\n    public CommandException(String msg) {\n        super(msg);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/NoSuchCommandException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.exception;\n\npublic class NoSuchCommandException extends CommandException {\n    public NoSuchCommandException(String msg) {\n        super(\"NoSuchCommandException:\" + msg);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/exception/PermissionDenyException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.exception;\n\npublic class PermissionDenyException extends CommandException {\n    public PermissionDenyException(String msg) {\n        super(\"Permission Deny On Operation: \" + msg);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/BaseOffline.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.FrameworkServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\n\nimport java.util.Collection;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\npublic class BaseOffline implements BaseCommand {\n    private static final Logger logger = LoggerFactory.getLogger(BaseOffline.class);\n    public FrameworkServiceRepository serviceRepository;\n\n    public BaseOffline(FrameworkModel frameworkModel) {\n        this.serviceRepository = frameworkModel.getServiceRepository();\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        logger.info(\"receive offline command\");\n        String servicePattern = \".*\";\n        if (ArrayUtils.isNotEmpty(args)) {\n            servicePattern = args[0];\n        }\n\n        boolean hasService = doExecute(servicePattern);\n\n        if (hasService) {\n            return \"OK\";\n        } else {\n            return \"service not found\";\n        }\n    }\n\n    protected boolean doExecute(String servicePattern) {\n        return this.offline(servicePattern);\n    }\n\n    public boolean offline(String servicePattern) {\n        boolean hasService = false;\n\n        ExecutorService executorService = Executors.newFixedThreadPool(\n                Math.min(Runtime.getRuntime().availableProcessors(), 4), new NamedThreadFactory(\"Dubbo-Offline\"));\n        try {\n            List<CompletableFuture<Void>> futures = new LinkedList<>();\n            Collection<ProviderModel> providerModelList = serviceRepository.allProviderModels();\n            for (ProviderModel providerModel : providerModelList) {\n                ServiceMetadata metadata = providerModel.getServiceMetadata();\n                if (metadata.getServiceKey().matches(servicePattern)\n                        || metadata.getDisplayServiceKey().matches(servicePattern)) {\n                    hasService = true;\n                    List<ProviderModel.RegisterStatedURL> statedUrls = providerModel.getStatedUrl();\n                    for (ProviderModel.RegisterStatedURL statedURL : statedUrls) {\n                        if (statedURL.isRegistered()) {\n                            futures.add(CompletableFuture.runAsync(\n                                    () -> {\n                                        doUnexport(statedURL);\n                                    },\n                                    executorService));\n                        }\n                    }\n                }\n            }\n            for (CompletableFuture<Void> future : futures) {\n                future.get();\n            }\n        } catch (ExecutionException | InterruptedException e) {\n            throw new RuntimeException(e);\n        } finally {\n            executorService.shutdown();\n        }\n\n        return hasService;\n    }\n\n    protected void doUnexport(ProviderModel.RegisterStatedURL statedURL) {\n        RegistryFactory registryFactory = statedURL\n                .getRegistryUrl()\n                .getOrDefaultApplicationModel()\n                .getExtensionLoader(RegistryFactory.class)\n                .getAdaptiveExtension();\n        Registry registry = registryFactory.getRegistry(statedURL.getRegistryUrl());\n        registry.unregister(statedURL.getProviderUrl());\n        statedURL.setRegistered(false);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/BaseOnline.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.FrameworkServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\n\nimport java.util.Collection;\nimport java.util.List;\n\npublic class BaseOnline implements BaseCommand {\n    private static final Logger logger = LoggerFactory.getLogger(BaseOnline.class);\n    public FrameworkServiceRepository serviceRepository;\n\n    public BaseOnline(FrameworkModel frameworkModel) {\n        this.serviceRepository = frameworkModel.getServiceRepository();\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        logger.info(\"receive online command\");\n        String servicePattern = \".*\";\n        if (ArrayUtils.isNotEmpty(args)) {\n            servicePattern = \"\" + args[0];\n        }\n\n        boolean hasService = doExecute(servicePattern);\n        if (hasService) {\n            return \"OK\";\n        } else {\n            return \"service not found\";\n        }\n    }\n\n    public boolean online(String servicePattern) {\n        boolean hasService = false;\n\n        Collection<ProviderModel> providerModelList = serviceRepository.allProviderModels();\n        for (ProviderModel providerModel : providerModelList) {\n            ServiceMetadata metadata = providerModel.getServiceMetadata();\n            if (metadata.getServiceKey().matches(servicePattern)\n                    || metadata.getDisplayServiceKey().matches(servicePattern)) {\n                hasService = true;\n                List<ProviderModel.RegisterStatedURL> statedUrls = providerModel.getStatedUrl();\n                for (ProviderModel.RegisterStatedURL statedURL : statedUrls) {\n                    if (!statedURL.isRegistered()) {\n                        doExport(statedURL);\n                    }\n                }\n            }\n        }\n\n        return hasService;\n    }\n\n    protected boolean doExecute(String servicePattern) {\n        return this.online(servicePattern);\n    }\n\n    protected void doExport(ProviderModel.RegisterStatedURL statedURL) {\n        RegistryFactory registryFactory = statedURL\n                .getRegistryUrl()\n                .getOrDefaultApplicationModel()\n                .getExtensionLoader(RegistryFactory.class)\n                .getAdaptiveExtension();\n        Registry registry = registryFactory.getRegistry(statedURL.getRegistryUrl());\n        registry.register(statedURL.getProviderUrl());\n        statedURL.setRegistered(true);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/ChangeTelnet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\n\nimport io.netty.channel.Channel;\nimport io.netty.util.AttributeKey;\n\n@Cmd(\n        name = \"cd\",\n        summary = \"Change default service.\",\n        example = {\"cd [service]\"})\npublic class ChangeTelnet implements BaseCommand {\n\n    public static final AttributeKey<String> SERVICE_KEY = AttributeKey.valueOf(\"telnet.service\");\n\n    private final DubboProtocol dubboProtocol;\n\n    public ChangeTelnet(FrameworkModel frameworkModel) {\n        this.dubboProtocol = DubboProtocol.getDubboProtocol(frameworkModel);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        Channel channel = commandContext.getRemote();\n\n        if (ArrayUtils.isEmpty(args)) {\n            return \"Please input service name, eg: \\r\\ncd XxxService\\r\\ncd com.xxx.XxxService\";\n        }\n        String message = args[0];\n        StringBuilder buf = new StringBuilder();\n        if (\"/\".equals(message) || \"..\".equals(message)) {\n            String service = channel.attr(SERVICE_KEY).getAndRemove();\n            buf.append(\"Cancelled default service \").append(service).append('.');\n        } else {\n            boolean found = false;\n            for (Exporter<?> exporter : dubboProtocol.getExporters()) {\n                if (message.equals(exporter.getInvoker().getInterface().getSimpleName())\n                        || message.equals(exporter.getInvoker().getInterface().getName())\n                        || message.equals(exporter.getInvoker().getUrl().getPath())\n                        || message.equals(exporter.getInvoker().getUrl().getServiceKey())) {\n                    found = true;\n                    break;\n                }\n            }\n            if (found) {\n                channel.attr(SERVICE_KEY).set(message);\n                buf.append(\"Used the \")\n                        .append(message)\n                        .append(\" as default.\\r\\nYou can cancel default service by command: cd /\");\n            } else {\n                buf.append(\"No such service \").append(message);\n            }\n        }\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/CountTelnet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.telnet.support.TelnetUtils;\nimport org.apache.dubbo.remoting.utils.PayloadDropper;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.RpcStatus;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\n\nimport java.lang.reflect.Method;\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelFuture;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;\nimport static org.apache.dubbo.qos.server.handler.QosProcessHandler.PROMPT;\n\n@Cmd(\n        name = \"count\",\n        summary = \"Count the service.\",\n        example = {\"count [service] [method] [times]\"})\npublic class CountTelnet implements BaseCommand {\n    private final DubboProtocol dubboProtocol;\n\n    public CountTelnet(FrameworkModel frameworkModel) {\n        this.dubboProtocol = DubboProtocol.getDubboProtocol(frameworkModel);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        Channel channel = commandContext.getRemote();\n        String service = channel.attr(ChangeTelnet.SERVICE_KEY).get();\n        if ((service == null || service.length() == 0) && (args == null || args.length == 0)) {\n            return \"Please input service name, eg: \\r\\ncount XxxService\\r\\ncount XxxService xxxMethod\\r\\ncount XxxService xxxMethod 10\\r\\nor \\\"cd XxxService\\\" firstly.\";\n        }\n        StringBuilder buf = new StringBuilder();\n        if (service != null && service.length() > 0) {\n            buf.append(\"Use default service \").append(service).append(\".\\r\\n\");\n        }\n        String method;\n        String times;\n        if (service == null || service.length() == 0) {\n            service = args[0];\n            method = args.length > 1 ? args[1] : null;\n        } else {\n            method = args.length > 0 ? args[0] : null;\n        }\n        if (StringUtils.isNumber(method)) {\n            times = method;\n            method = null;\n        } else {\n            times = args.length > 2 ? args[2] : \"1\";\n        }\n        if (!StringUtils.isNumber(times)) {\n            return \"Illegal times \" + times + \", must be integer.\";\n        }\n        final int t = Integer.parseInt(times);\n        Invoker<?> invoker = null;\n        for (Exporter<?> exporter : dubboProtocol.getExporters()) {\n            if (service.equals(exporter.getInvoker().getInterface().getSimpleName())\n                    || service.equals(exporter.getInvoker().getInterface().getName())\n                    || service.equals(exporter.getInvoker().getUrl().getPath())\n                    || service.equals(exporter.getInvoker().getUrl().getServiceKey())) {\n                invoker = exporter.getInvoker();\n                break;\n            }\n        }\n        if (invoker != null) {\n            if (t > 0) {\n                final String mtd = method;\n                final Invoker<?> inv = invoker;\n                Thread thread = new Thread(\n                        () -> {\n                            for (int i = 0; i < t; i++) {\n                                String result = count(inv, mtd);\n                                try {\n                                    send(channel, \"\\r\\n\" + result);\n                                } catch (RemotingException e1) {\n                                    return;\n                                }\n                                if (i < t - 1) {\n                                    try {\n                                        Thread.sleep(1000);\n                                    } catch (InterruptedException ignored) {\n                                    }\n                                }\n                            }\n                            try {\n                                send(channel, \"\\r\\n\" + PROMPT);\n                            } catch (RemotingException ignored) {\n                            }\n                        },\n                        \"TelnetCount\");\n                thread.setDaemon(true);\n                thread.start();\n            }\n        } else {\n            buf.append(\"No such service \").append(service);\n        }\n        return buf.toString();\n    }\n\n    public void send(Channel channel, Object message) throws RemotingException {\n        boolean success;\n        int timeout = 0;\n        try {\n            ChannelFuture future = channel.writeAndFlush(message);\n            success = future.await(DEFAULT_TIMEOUT);\n            Throwable cause = future.cause();\n            if (cause != null) {\n                throw cause;\n            }\n        } catch (Throwable e) {\n            throw new RemotingException(\n                    (InetSocketAddress) channel.localAddress(),\n                    (InetSocketAddress) channel.remoteAddress(),\n                    \"Failed to send message \" + PayloadDropper.getRequestWithoutData(message) + \" to \"\n                            + channel.remoteAddress().toString() + \", cause: \" + e.getMessage(),\n                    e);\n        }\n        if (!success) {\n            throw new RemotingException(\n                    (InetSocketAddress) channel.localAddress(),\n                    (InetSocketAddress) channel.remoteAddress(),\n                    \"Failed to send message \" + PayloadDropper.getRequestWithoutData(message) + \" to \"\n                            + channel.remoteAddress().toString() + \"in timeout(\" + timeout + \"ms) limit\");\n        }\n    }\n\n    private String count(Invoker<?> invoker, String method) {\n        URL url = invoker.getUrl();\n        List<List<String>> table = new ArrayList<>();\n        List<String> header = new ArrayList<>();\n        header.add(\"method\");\n        header.add(\"total\");\n        header.add(\"failed\");\n        header.add(\"active\");\n        header.add(\"average\");\n        header.add(\"max\");\n        if (method == null || method.length() == 0) {\n            for (Method m : invoker.getInterface().getMethods()) {\n                RpcStatus count = RpcStatus.getStatus(url, m.getName());\n                table.add(createRow(m.getName(), count));\n            }\n        } else {\n            boolean found = false;\n            for (Method m : invoker.getInterface().getMethods()) {\n                if (m.getName().equals(method)) {\n                    found = true;\n                    break;\n                }\n            }\n            if (found) {\n                RpcStatus count = RpcStatus.getStatus(url, method);\n                table.add(createRow(method, count));\n            } else {\n                return \"No such method \" + method + \" in class \"\n                        + invoker.getInterface().getName();\n            }\n        }\n        return TelnetUtils.toTable(header, table);\n    }\n\n    private List<String> createRow(String methodName, RpcStatus count) {\n        List<String> row = new ArrayList<>();\n        row.add(methodName);\n        row.add(String.valueOf(count.getTotal()));\n        row.add(String.valueOf(count.getFailed()));\n        row.add(String.valueOf(count.getActive()));\n        row.add(count.getSucceededAverageElapsed() + \"ms\");\n        row.add(count.getSucceededMaxElapsed() + \"ms\");\n        return row;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DefaultMetricsReporterCmd.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.metrics.report.DefaultMetricsReporter;\nimport org.apache.dubbo.metrics.report.MetricsReporter;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.CharArrayReader;\nimport java.io.IOException;\nimport java.io.LineNumberReader;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n@Cmd(name = \"metrics_default\", summary = \"display metrics information\")\npublic class DefaultMetricsReporterCmd implements BaseCommand {\n\n    public FrameworkModel frameworkModel;\n\n    public DefaultMetricsReporterCmd(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        List<ApplicationModel> models = frameworkModel.getApplicationModels();\n        String result = \"There is no application with data\";\n        if (notSpecifyApplication(args)) {\n            result = useFirst(models, result, null);\n        } else if (args.length == 1) {\n            result = specifyApplication(args[0], models, null);\n        } else if (args.length == 2) {\n            result = specifyApplication(args[0], models, args[1]);\n        }\n        return result;\n    }\n\n    private boolean notSpecifyApplication(String[] args) {\n        return args == null || args.length == 0;\n    }\n\n    private String useFirst(List<ApplicationModel> models, String result, String metricsName) {\n        for (ApplicationModel model : models) {\n            String current = getResponseByApplication(model, metricsName);\n            if (current != null && getLineNumber(current) > 0) {\n                result = current;\n                break;\n            }\n        }\n        return result;\n    }\n\n    private String specifyApplication(String appName, List<ApplicationModel> models, String metricsName) {\n        if (\"application_all\".equals(appName)) {\n            return allApplication(models);\n        } else {\n            return specifySingleApplication(appName, models, metricsName);\n        }\n    }\n\n    private String specifySingleApplication(String appName, List<ApplicationModel> models, String metricsName) {\n        Optional<ApplicationModel> modelOptional = models.stream()\n                .filter(applicationModel -> appName.equals(applicationModel.getApplicationName()))\n                .findFirst();\n        if (modelOptional.isPresent()) {\n            return getResponseByApplication(modelOptional.get(), metricsName);\n        } else {\n            return \"Not exist application: \" + appName;\n        }\n    }\n\n    private String allApplication(List<ApplicationModel> models) {\n        Map<String, String> appResultMap = new HashMap<>();\n        for (ApplicationModel model : models) {\n            appResultMap.put(model.getApplicationName(), getResponseByApplication(model, null));\n        }\n        return JsonUtils.toJson(appResultMap);\n    }\n\n    private String getResponseByApplication(ApplicationModel applicationModel, String metricsName) {\n        String response = \"DefaultMetricsReporter not init\";\n        MetricsReporter metricsReporter = applicationModel.getBeanFactory().getBean(DefaultMetricsReporter.class);\n        if (metricsReporter != null) {\n            metricsReporter.resetIfSamplesChanged();\n            response = metricsReporter.getResponseWithName(metricsName);\n        }\n        return response;\n    }\n\n    private static long getLineNumber(String content) {\n        LineNumberReader lnr = new LineNumberReader(new CharArrayReader(content.toCharArray()));\n        try {\n            lnr.skip(Long.MAX_VALUE);\n            lnr.close();\n        } catch (IOException ignore) {\n        }\n        return lnr.getLineNumber();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DisableDetailProfiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.profiler.ProfilerSwitch;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_PROFILER_DISABLED;\n\n@Cmd(name = \"disableDetailProfiler\", summary = \"Disable Dubbo Invocation Profiler.\")\npublic class DisableDetailProfiler implements BaseCommand {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DisableDetailProfiler.class);\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        ProfilerSwitch.disableDetailProfiler();\n        logger.warn(QOS_PROFILER_DISABLED, \"\", \"\", \"Dubbo Invocation Profiler has been disabled.\");\n        return \"OK\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DisableRouterSnapshot.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\n\n@Cmd(\n        name = \"disableRouterSnapshot\",\n        summary = \"Disable Dubbo Invocation Level Router Snapshot Print\",\n        example = \"disableRouterSnapshot xx.xx.xxx.service\")\npublic class DisableRouterSnapshot implements BaseCommand {\n    private final RouterSnapshotSwitcher routerSnapshotSwitcher;\n    private final FrameworkModel frameworkModel;\n\n    public DisableRouterSnapshot(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n        this.routerSnapshotSwitcher = frameworkModel.getBeanFactory().getBean(RouterSnapshotSwitcher.class);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (args.length != 1) {\n            return \"args count should be 1. example disableRouterSnapshot xx.xx.xxx.service\";\n        }\n        String servicePattern = args[0];\n        int count = 0;\n        for (ConsumerModel consumerModel : frameworkModel.getServiceRepository().allConsumerModels()) {\n            try {\n                ServiceMetadata metadata = consumerModel.getServiceMetadata();\n                if (metadata.getServiceKey().matches(servicePattern)\n                        || metadata.getDisplayServiceKey().matches(servicePattern)) {\n                    routerSnapshotSwitcher.removeEnabledService(metadata.getServiceKey());\n                    count += 1;\n                }\n            } catch (Throwable ignore) {\n\n            }\n        }\n        return \"OK. Found service count: \" + count;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DisableSimpleProfiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.profiler.ProfilerSwitch;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_PROFILER_DISABLED;\n\n@Cmd(name = \"disableSimpleProfiler\", summary = \"Disable Dubbo Invocation Profiler.\")\npublic class DisableSimpleProfiler implements BaseCommand {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DisableSimpleProfiler.class);\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        ProfilerSwitch.disableSimpleProfiler();\n        logger.warn(QOS_PROFILER_DISABLED, \"\", \"\", \"Dubbo Invocation Profiler has been disabled.\");\n        return \"OK\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/EnableDetailProfiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.profiler.ProfilerSwitch;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_PROFILER_ENABLED;\n\n@Cmd(name = \"enableDetailProfiler\", summary = \"Enable Dubbo Invocation Profiler.\")\npublic class EnableDetailProfiler implements BaseCommand {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(EnableDetailProfiler.class);\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        ProfilerSwitch.enableDetailProfiler();\n        logger.warn(QOS_PROFILER_ENABLED, \"\", \"\", \"Dubbo Invocation Profiler has been enabled.\");\n        return \"OK. This will cause performance degradation, please be careful!\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/EnableRouterSnapshot.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\n\n@Cmd(\n        name = \"enableRouterSnapshot\",\n        summary = \"Enable Dubbo Invocation Level Router Snapshot Print\",\n        example = \"enableRouterSnapshot xx.xx.xxx.service\")\npublic class EnableRouterSnapshot implements BaseCommand {\n    private final RouterSnapshotSwitcher routerSnapshotSwitcher;\n    private final FrameworkModel frameworkModel;\n\n    public EnableRouterSnapshot(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n        this.routerSnapshotSwitcher = frameworkModel.getBeanFactory().getBean(RouterSnapshotSwitcher.class);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (args.length != 1) {\n            return \"args count should be 1. example enableRouterSnapshot xx.xx.xxx.service\";\n        }\n        String servicePattern = args[0];\n        int count = 0;\n        for (ConsumerModel consumerModel : frameworkModel.getServiceRepository().allConsumerModels()) {\n            try {\n                ServiceMetadata metadata = consumerModel.getServiceMetadata();\n                if (metadata.getServiceKey().matches(servicePattern)\n                        || metadata.getDisplayServiceKey().matches(servicePattern)) {\n                    routerSnapshotSwitcher.addEnabledService(metadata.getServiceKey());\n                    count += 1;\n                }\n            } catch (Throwable ignore) {\n\n            }\n        }\n        return \"OK. Found service count: \" + count + \". This will cause performance degradation, please be careful!\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/EnableSimpleProfiler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.profiler.ProfilerSwitch;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_PROFILER_ENABLED;\n\n@Cmd(name = \"enableSimpleProfiler\", summary = \"Enable Dubbo Invocation Profiler.\")\npublic class EnableSimpleProfiler implements BaseCommand {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(EnableSimpleProfiler.class);\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        ProfilerSwitch.enableSimpleProfiler();\n        logger.warn(QOS_PROFILER_ENABLED, \"\", \"\", \"Dubbo Invocation Profiler has been enabled.\");\n        return \"OK\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetAddress.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.client.migration.MigrationInvoker;\nimport org.apache.dubbo.registry.client.migration.model.MigrationStep;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.directory.AbstractDirectory;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.FrameworkServiceRepository;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n@Cmd(\n        name = \"getAddress\",\n        summary = \"Get service available address \",\n        example = {\"getAddress com.example.DemoService\", \"getAddress group/com.example.DemoService\"},\n        requiredPermissionLevel = PermissionLevel.PRIVATE)\npublic class GetAddress implements BaseCommand {\n    public final FrameworkServiceRepository serviceRepository;\n\n    public GetAddress(FrameworkModel frameworkModel) {\n        this.serviceRepository = frameworkModel.getServiceRepository();\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public String execute(CommandContext commandContext, String[] args) {\n        if (args == null || args.length != 1) {\n            return \"Invalid parameters, please input like getAddress com.example.DemoService\";\n        }\n\n        String serviceName = args[0];\n\n        StringBuilder plainOutput = new StringBuilder();\n        Map<String, Object> jsonOutput = new HashMap<>();\n\n        for (ConsumerModel consumerModel : serviceRepository.allConsumerModels()) {\n            if (serviceName.equals(consumerModel.getServiceKey())) {\n                appendConsumer(plainOutput, jsonOutput, consumerModel);\n            }\n        }\n\n        if (commandContext.isHttp()) {\n            return JsonUtils.toJson(jsonOutput);\n        } else {\n            return plainOutput.toString();\n        }\n    }\n\n    private static void appendConsumer(\n            StringBuilder plainOutput, Map<String, Object> jsonOutput, ConsumerModel consumerModel) {\n        plainOutput\n                .append(\"ConsumerModel: \")\n                .append(consumerModel.getServiceKey())\n                .append(\"@\")\n                .append(Integer.toHexString(System.identityHashCode(consumerModel)))\n                .append(\"\\n\\n\");\n        Map<String, Object> consumerMap = new HashMap<>();\n        jsonOutput.put(\n                consumerModel.getServiceKey() + \"@\" + Integer.toHexString(System.identityHashCode(consumerModel)),\n                consumerMap);\n\n        Object object = consumerModel.getServiceMetadata().getAttribute(CommonConstants.CURRENT_CLUSTER_INVOKER_KEY);\n        Map<Registry, MigrationInvoker<?>> invokerMap;\n        if (object instanceof Map) {\n            invokerMap = (Map<Registry, MigrationInvoker<?>>) object;\n            for (Map.Entry<Registry, MigrationInvoker<?>> entry : invokerMap.entrySet()) {\n                appendInvokers(plainOutput, consumerMap, entry);\n            }\n        }\n    }\n\n    private static void appendInvokers(\n            StringBuilder plainOutput,\n            Map<String, Object> consumerMap,\n            Map.Entry<Registry, MigrationInvoker<?>> entry) {\n        URL registryUrl = entry.getKey().getUrl();\n\n        plainOutput.append(\"Registry: \").append(registryUrl).append(\"\\n\");\n        Map<String, Object> registryMap = new HashMap<>();\n        consumerMap.put(registryUrl.toString(), registryMap);\n\n        MigrationInvoker<?> migrationInvoker = entry.getValue();\n\n        MigrationStep migrationStep = migrationInvoker.getMigrationStep();\n        plainOutput.append(\"MigrationStep: \").append(migrationStep).append(\"\\n\\n\");\n        registryMap.put(\"MigrationStep\", migrationStep);\n\n        Map<String, Object> invokersMap = new HashMap<>();\n        registryMap.put(\"Invokers\", invokersMap);\n\n        URL originConsumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n        RpcContext.getServiceContext().setConsumerUrl(migrationInvoker.getConsumerUrl());\n\n        appendInterfaceLevel(plainOutput, migrationInvoker, invokersMap);\n        appendAppLevel(plainOutput, migrationInvoker, invokersMap);\n\n        RpcContext.getServiceContext().setConsumerUrl(originConsumerUrl);\n    }\n\n    private static void appendAppLevel(\n            StringBuilder plainOutput, MigrationInvoker<?> migrationInvoker, Map<String, Object> invokersMap) {\n        Map<String, Object> appMap = new HashMap<>();\n        invokersMap.put(\"Application-Level\", appMap);\n        Optional.ofNullable(migrationInvoker.getServiceDiscoveryInvoker())\n                .ifPresent(i -> plainOutput.append(\"Application-Level: \\n\"));\n        Optional.ofNullable(migrationInvoker.getServiceDiscoveryInvoker())\n                .map(ClusterInvoker::getDirectory)\n                .map(Directory::getAllInvokers)\n                .ifPresent(invokers -> {\n                    List<String> invokerUrls = new LinkedList<>();\n                    plainOutput.append(\"All Invokers: \\n\");\n                    for (org.apache.dubbo.rpc.Invoker<?> invoker : invokers) {\n                        invokerUrls.add(invoker.getUrl().toFullString());\n                        plainOutput.append(invoker.getUrl().toFullString()).append(\"\\n\");\n                    }\n                    plainOutput.append(\"\\n\");\n                    appMap.put(\"All\", invokerUrls);\n                });\n        Optional.ofNullable(migrationInvoker.getServiceDiscoveryInvoker())\n                .map(ClusterInvoker::getDirectory)\n                .map(s -> (AbstractDirectory<?>) s)\n                .map(AbstractDirectory::getValidInvokers)\n                .ifPresent(invokers -> {\n                    List<String> invokerUrls = new LinkedList<>();\n                    plainOutput.append(\"Valid Invokers: \\n\");\n                    for (org.apache.dubbo.rpc.Invoker<?> invoker : invokers) {\n                        invokerUrls.add(invoker.getUrl().toFullString());\n                        plainOutput.append(invoker.getUrl().toFullString()).append(\"\\n\");\n                    }\n                    plainOutput.append(\"\\n\");\n                    appMap.put(\"Valid\", invokerUrls);\n                });\n        Optional.ofNullable(migrationInvoker.getServiceDiscoveryInvoker())\n                .map(ClusterInvoker::getDirectory)\n                .map(s -> (AbstractDirectory<?>) s)\n                .map(AbstractDirectory::getDisabledInvokers)\n                .ifPresent(invokers -> {\n                    List<String> invokerUrls = new LinkedList<>();\n                    plainOutput.append(\"Disabled Invokers: \\n\");\n                    for (org.apache.dubbo.rpc.Invoker<?> invoker : invokers) {\n                        invokerUrls.add(invoker.getUrl().toFullString());\n                        plainOutput.append(invoker.getUrl().toFullString()).append(\"\\n\");\n                    }\n                    plainOutput.append(\"\\n\");\n                    appMap.put(\"Disabled\", invokerUrls);\n                });\n    }\n\n    private static void appendInterfaceLevel(\n            StringBuilder plainOutput, MigrationInvoker<?> migrationInvoker, Map<String, Object> invokersMap) {\n        Map<String, Object> interfaceMap = new HashMap<>();\n        invokersMap.put(\"Interface-Level\", interfaceMap);\n        Optional.ofNullable(migrationInvoker.getInvoker()).ifPresent(i -> plainOutput.append(\"Interface-Level: \\n\"));\n        Optional.ofNullable(migrationInvoker.getInvoker())\n                .map(ClusterInvoker::getDirectory)\n                .map(Directory::getAllInvokers)\n                .ifPresent(invokers -> {\n                    List<String> invokerUrls = new LinkedList<>();\n                    plainOutput.append(\"All Invokers: \\n\");\n                    for (org.apache.dubbo.rpc.Invoker<?> invoker : invokers) {\n                        invokerUrls.add(invoker.getUrl().toFullString());\n                        plainOutput.append(invoker.getUrl().toFullString()).append(\"\\n\");\n                    }\n                    plainOutput.append(\"\\n\");\n                    interfaceMap.put(\"All\", invokerUrls);\n                });\n        Optional.ofNullable(migrationInvoker.getInvoker())\n                .map(ClusterInvoker::getDirectory)\n                .map(s -> (AbstractDirectory<?>) s)\n                .map(AbstractDirectory::getValidInvokers)\n                .ifPresent(invokers -> {\n                    List<String> invokerUrls = new LinkedList<>();\n                    plainOutput.append(\"Valid Invokers: \\n\");\n                    for (org.apache.dubbo.rpc.Invoker<?> invoker : invokers) {\n                        invokerUrls.add(invoker.getUrl().toFullString());\n                        plainOutput.append(invoker.getUrl().toFullString()).append(\"\\n\");\n                    }\n                    plainOutput.append(\"\\n\");\n                    interfaceMap.put(\"Valid\", invokerUrls);\n                });\n        Optional.ofNullable(migrationInvoker.getInvoker())\n                .map(ClusterInvoker::getDirectory)\n                .map(s -> (AbstractDirectory<?>) s)\n                .map(AbstractDirectory::getDisabledInvokers)\n                .ifPresent(invokers -> {\n                    List<String> invokerUrls = new LinkedList<>();\n                    plainOutput.append(\"Disabled Invokers: \\n\");\n                    for (org.apache.dubbo.rpc.Invoker<?> invoker : invokers) {\n                        invokerUrls.add(invoker.getUrl().toFullString());\n                        plainOutput.append(invoker.getUrl().toFullString()).append(\"\\n\");\n                    }\n                    plainOutput.append(\"\\n\");\n                    interfaceMap.put(\"Disabled\", invokerUrls);\n                });\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.ReferenceConfigBase;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfigBase;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.config.TracingConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.context.ModuleConfigManager;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\n\n@Cmd(\n        name = \"getConfig\",\n        summary = \"Get current running config.\",\n        example = {\"getConfig ReferenceConfig com.example.DemoService\", \"getConfig ApplicationConfig\"},\n        requiredPermissionLevel = PermissionLevel.PRIVATE)\npublic class GetConfig implements BaseCommand {\n    private final FrameworkModel frameworkModel;\n\n    public GetConfig(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        boolean http = commandContext.isHttp();\n        StringBuilder plainOutput = new StringBuilder();\n        Map<String, Object> frameworkMap = new HashMap<>();\n\n        appendFrameworkConfig(args, plainOutput, frameworkMap);\n\n        if (http) {\n            return JsonUtils.toJson(frameworkMap);\n        } else {\n            return plainOutput.toString();\n        }\n    }\n\n    private void appendFrameworkConfig(String[] args, StringBuilder plainOutput, Map<String, Object> frameworkMap) {\n        for (ApplicationModel applicationModel : frameworkModel.getApplicationModels()) {\n            Map<String, Object> applicationMap = new HashMap<>();\n            frameworkMap.put(applicationModel.getDesc(), applicationMap);\n            plainOutput\n                    .append(\"ApplicationModel: \")\n                    .append(applicationModel.getDesc())\n                    .append(\"\\n\");\n\n            ConfigManager configManager = applicationModel.getApplicationConfigManager();\n\n            appendApplicationConfigs(args, plainOutput, applicationModel, applicationMap, configManager);\n        }\n    }\n\n    private static void appendApplicationConfigs(\n            String[] args,\n            StringBuilder plainOutput,\n            ApplicationModel applicationModel,\n            Map<String, Object> applicationMap,\n            ConfigManager configManager) {\n        Optional<ApplicationConfig> applicationConfig = configManager.getApplication();\n        applicationConfig.ifPresent(config ->\n                appendConfig(\"ApplicationConfig\", config.getName(), config, plainOutput, applicationMap, args));\n\n        for (ProtocolConfig protocol : configManager.getProtocols()) {\n            appendConfigs(\"ProtocolConfig\", protocol.getName(), protocol, plainOutput, applicationMap, args);\n        }\n\n        for (RegistryConfig registry : configManager.getRegistries()) {\n            appendConfigs(\"RegistryConfig\", registry.getId(), registry, plainOutput, applicationMap, args);\n        }\n\n        for (MetadataReportConfig metadataConfig : configManager.getMetadataConfigs()) {\n            appendConfigs(\n                    \"MetadataReportConfig\", metadataConfig.getId(), metadataConfig, plainOutput, applicationMap, args);\n        }\n\n        for (ConfigCenterConfig configCenter : configManager.getConfigCenters()) {\n            appendConfigs(\"ConfigCenterConfig\", configCenter.getId(), configCenter, plainOutput, applicationMap, args);\n        }\n\n        Optional<MetricsConfig> metricsConfig = configManager.getMetrics();\n        metricsConfig.ifPresent(\n                config -> appendConfig(\"MetricsConfig\", config.getId(), config, plainOutput, applicationMap, args));\n\n        Optional<TracingConfig> tracingConfig = configManager.getTracing();\n        tracingConfig.ifPresent(\n                config -> appendConfig(\"TracingConfig\", config.getId(), config, plainOutput, applicationMap, args));\n\n        Optional<MonitorConfig> monitorConfig = configManager.getMonitor();\n        monitorConfig.ifPresent(\n                config -> appendConfig(\"MonitorConfig\", config.getId(), config, plainOutput, applicationMap, args));\n\n        Optional<SslConfig> sslConfig = configManager.getSsl();\n        sslConfig.ifPresent(\n                config -> appendConfig(\"SslConfig\", config.getId(), config, plainOutput, applicationMap, args));\n\n        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n            Map<String, Object> moduleMap = new HashMap<>();\n            applicationMap.put(moduleModel.getDesc(), moduleMap);\n            plainOutput.append(\"ModuleModel: \").append(moduleModel.getDesc()).append(\"\\n\");\n\n            ModuleConfigManager moduleConfigManager = moduleModel.getConfigManager();\n\n            appendModuleConfigs(args, plainOutput, moduleMap, moduleConfigManager);\n        }\n    }\n\n    private static void appendModuleConfigs(\n            String[] args,\n            StringBuilder plainOutput,\n            Map<String, Object> moduleMap,\n            ModuleConfigManager moduleConfigManager) {\n        for (ProviderConfig provider : moduleConfigManager.getProviders()) {\n            appendConfigs(\"ProviderConfig\", provider.getId(), provider, plainOutput, moduleMap, args);\n        }\n\n        for (ConsumerConfig consumer : moduleConfigManager.getConsumers()) {\n            appendConfigs(\"ConsumerConfig\", consumer.getId(), consumer, plainOutput, moduleMap, args);\n        }\n\n        Optional<ModuleConfig> moduleConfig = moduleConfigManager.getModule();\n        moduleConfig.ifPresent(\n                config -> appendConfig(\"ModuleConfig\", config.getId(), config, plainOutput, moduleMap, args));\n\n        for (ServiceConfigBase<?> service : moduleConfigManager.getServices()) {\n            appendConfigs(\"ServiceConfig\", service.getUniqueServiceName(), service, plainOutput, moduleMap, args);\n        }\n\n        for (ReferenceConfigBase<?> reference : moduleConfigManager.getReferences()) {\n            appendConfigs(\"ReferenceConfig\", reference.getUniqueServiceName(), reference, plainOutput, moduleMap, args);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static void appendConfigs(\n            String type, String id, Object config, StringBuilder plainOutput, Map<String, Object> map, String[] args) {\n        if (!isMatch(type, id, args)) {\n            return;\n        }\n\n        id = id == null ? \"(empty)\" : id;\n\n        plainOutput\n                .append(type)\n                .append(\": \")\n                .append(id)\n                .append(\"\\n\")\n                .append(config)\n                .append(\"\\n\\n\");\n\n        Map<String, Object> typeMap =\n                (Map<String, Object>) map.computeIfAbsent(type, k -> new HashMap<String, Object>());\n        typeMap.put(id, config);\n    }\n\n    private static void appendConfig(\n            String type, String id, Object config, StringBuilder plainOutput, Map<String, Object> map, String[] args) {\n        if (!isMatch(type, id, args)) {\n            return;\n        }\n\n        id = id == null ? \"(empty)\" : id;\n\n        plainOutput\n                .append(type)\n                .append(\": \")\n                .append(id)\n                .append(\"\\n\")\n                .append(config)\n                .append(\"\\n\\n\");\n\n        map.put(type, config);\n    }\n\n    private static boolean isMatch(String type, String id, String[] args) {\n        if (args == null) {\n            return true;\n        }\n        switch (args.length) {\n            case 1:\n                if (!Objects.equals(args[0], type)) {\n                    return false;\n                }\n                break;\n            case 2:\n                if (!Objects.equals(args[0], type) || !Objects.equals(args[1], id)) {\n                    return false;\n                }\n                break;\n            default:\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetEnabledRouterSnapshot.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\n@Cmd(\n        name = \"getEnabledRouterSnapshot\",\n        summary = \"Get enabled Dubbo invocation level router snapshot print service list\")\npublic class GetEnabledRouterSnapshot implements BaseCommand {\n    private final RouterSnapshotSwitcher routerSnapshotSwitcher;\n\n    public GetEnabledRouterSnapshot(FrameworkModel frameworkModel) {\n        this.routerSnapshotSwitcher = frameworkModel.getBeanFactory().getBean(RouterSnapshotSwitcher.class);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        return String.join(\"\\n\", routerSnapshotSwitcher.getEnabledService());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIService;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\n@Cmd(\n        name = \"getOpenAPI\",\n        summary = \"Get the openapi descriptor for specified services.\",\n        example = {\n            \"getOpenAPI\",\n            \"getOpenAPI groupA\",\n            \"getOpenAPI com.example.DemoService\",\n            \"getOpenAPI --group groupA --version 1.1.0 --tag tagA --service com.example. --openapi 3.0.0 --format yaml\",\n        },\n        requiredPermissionLevel = PermissionLevel.PRIVATE)\npublic class GetOpenAPI implements BaseCommand {\n\n    private final FrameworkModel frameworkModel;\n\n    public GetOpenAPI(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        OpenAPIService openAPIService = frameworkModel.getBean(OpenAPIService.class);\n        if (openAPIService == null) {\n            return \"OpenAPI is not available\";\n        }\n\n        OpenAPIRequest request = new OpenAPIRequest();\n\n        int len = args.length;\n        if (len > 0) {\n            if (len == 1) {\n                String arg0 = args[0];\n                if (arg0.indexOf('.') > 0) {\n                    request.setService(new String[] {arg0});\n                } else {\n                    request.setGroup(arg0);\n                }\n            } else {\n                for (int i = 0; i < len; i += 2) {\n                    String value = args[i + 1];\n                    switch (StringUtils.substringAfterLast(args[i], '-')) {\n                        case \"group\":\n                            request.setGroup(value);\n                            break;\n                        case \"version\":\n                            request.setVersion(value);\n                            break;\n                        case \"tag\":\n                            request.setTag(StringUtils.tokenize(value));\n                            break;\n                        case \"service\":\n                            request.setService(StringUtils.tokenize(value));\n                            break;\n                        case \"openapi\":\n                            request.setOpenapi(value);\n                            break;\n                        case \"format\":\n                            request.setFormat(value);\n                            break;\n                        default:\n                            break;\n                    }\n                }\n            }\n        }\n\n        return openAPIService.getDocument(request);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetRecentRouterSnapshot.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Arrays;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\n@Cmd(name = \"getRecentRouterSnapshot\", summary = \"Get recent (32) router snapshot message\")\npublic class GetRecentRouterSnapshot implements BaseCommand {\n\n    private final RouterSnapshotSwitcher routerSnapshotSwitcher;\n\n    public GetRecentRouterSnapshot(FrameworkModel frameworkModel) {\n        this.routerSnapshotSwitcher = frameworkModel.getBeanFactory().getBean(RouterSnapshotSwitcher.class);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        return Arrays.stream(routerSnapshotSwitcher.cloneSnapshot())\n                .filter(Objects::nonNull)\n                .sorted()\n                .collect(Collectors.joining(\"\\n\\n\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetRouterSnapshot.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.client.migration.MigrationInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.cluster.directory.AbstractDirectory;\nimport org.apache.dubbo.rpc.cluster.router.state.StateRouter;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\n\nimport java.util.Map;\n\n@Cmd(\n        name = \"getRouterSnapshot\",\n        summary = \"Get State Router Snapshot.\",\n        example = \"getRouterSnapshot xx.xx.xxx.service\")\npublic class GetRouterSnapshot implements BaseCommand {\n    private final FrameworkModel frameworkModel;\n\n    public GetRouterSnapshot(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (args.length != 1) {\n            return \"args count should be 1. example getRouterSnapshot xx.xx.xxx.service\";\n        }\n        String servicePattern = args[0];\n        StringBuilder stringBuilder = new StringBuilder();\n        for (ConsumerModel consumerModel : frameworkModel.getServiceRepository().allConsumerModels()) {\n            try {\n                ServiceMetadata metadata = consumerModel.getServiceMetadata();\n                if (metadata.getServiceKey().matches(servicePattern)\n                        || metadata.getDisplayServiceKey().matches(servicePattern)) {\n                    Object object = metadata.getAttribute(CommonConstants.CURRENT_CLUSTER_INVOKER_KEY);\n                    Map<Registry, MigrationInvoker<?>> invokerMap;\n                    if (object instanceof Map) {\n                        invokerMap = (Map<Registry, MigrationInvoker<?>>) object;\n                        for (Map.Entry<Registry, MigrationInvoker<?>> invokerEntry : invokerMap.entrySet()) {\n                            Directory<?> directory = invokerEntry.getValue().getDirectory();\n                            StateRouter<?> headStateRouter =\n                                    directory.getRouterChain().getHeadStateRouter();\n                            stringBuilder\n                                    .append(metadata.getServiceKey())\n                                    .append('@')\n                                    .append(Integer.toHexString(System.identityHashCode(metadata)))\n                                    .append(\"\\n\")\n                                    .append(\"[ All Invokers:\")\n                                    .append(directory.getAllInvokers().size())\n                                    .append(\" ] \")\n                                    .append(\"[ Valid Invokers: \")\n                                    .append(((AbstractDirectory<?>) directory)\n                                            .getValidInvokers()\n                                            .size())\n                                    .append(\" ]\\n\")\n                                    .append(\"\\n\")\n                                    .append(headStateRouter.buildSnapshot())\n                                    .append(\"\\n\\n\");\n                        }\n                    }\n                }\n            } catch (Throwable ignore) {\n\n            }\n        }\n        return stringBuilder.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GracefulShutdown.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\n@Cmd(\n        name = \"gracefulShutdown\",\n        summary = \"Gracefully shutdown servers\",\n        example = {\"gracefulShutdown\"},\n        requiredPermissionLevel = PermissionLevel.PRIVATE)\npublic class GracefulShutdown implements BaseCommand {\n    private final Offline offline;\n    private final FrameworkModel frameworkModel;\n\n    public GracefulShutdown(FrameworkModel frameworkModel) {\n        this.offline = new Offline(frameworkModel);\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        for (org.apache.dubbo.rpc.GracefulShutdown gracefulShutdown :\n                org.apache.dubbo.rpc.GracefulShutdown.getGracefulShutdowns(frameworkModel)) {\n            gracefulShutdown.readonly();\n        }\n        offline.execute(commandContext, new String[0]);\n        return \"OK\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Help.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.command.util.CommandHelper;\nimport org.apache.dubbo.qos.textui.TTable;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.WeakHashMap;\n\n@Cmd(\n        name = \"help\",\n        summary = \"help command\",\n        example = {\"help\", \"help online\"})\npublic class Help implements BaseCommand {\n\n    private final CommandHelper commandHelper;\n\n    private static final String MAIN_HELP = \"mainHelp\";\n\n    private static final Map<String, String> processedTable = new WeakHashMap<>();\n\n    public Help(FrameworkModel frameworkModel) {\n        this.commandHelper = new CommandHelper(frameworkModel);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (ArrayUtils.isNotEmpty(args)) {\n            return processedTable.computeIfAbsent(args[0], this::commandHelp);\n        } else {\n            return processedTable.computeIfAbsent(MAIN_HELP, commandName -> mainHelp());\n        }\n    }\n\n    private String commandHelp(String commandName) {\n\n        if (!commandHelper.hasCommand(commandName)) {\n            return \"no such command:\" + commandName;\n        }\n\n        Class<?> clazz = commandHelper.getCommandClass(commandName);\n\n        final Cmd cmd = clazz.getAnnotation(Cmd.class);\n        final TTable tTable = new TTable(new TTable.ColumnDefine[] {\n            new TTable.ColumnDefine(TTable.Align.RIGHT), new TTable.ColumnDefine(80, false, TTable.Align.LEFT)\n        });\n\n        tTable.addRow(\"COMMAND NAME\", commandName);\n\n        if (null != cmd.example()) {\n            tTable.addRow(\"EXAMPLE\", drawExample(cmd));\n        }\n\n        return tTable.padding(1).rendering();\n    }\n\n    private String drawExample(Cmd cmd) {\n        final StringBuilder drawExampleStringBuilder = new StringBuilder();\n        for (String example : cmd.example()) {\n            drawExampleStringBuilder.append(example).append('\\n');\n        }\n        return drawExampleStringBuilder.toString();\n    }\n\n    /*\n     * output main help\n     */\n    private String mainHelp() {\n\n        final TTable tTable = new TTable(new TTable.ColumnDefine[] {\n            new TTable.ColumnDefine(TTable.Align.RIGHT), new TTable.ColumnDefine(80, false, TTable.Align.LEFT)\n        });\n\n        final List<Class<?>> classes = commandHelper.getAllCommandClass();\n\n        Collections.sort(classes, new Comparator<Class<?>>() {\n\n            @Override\n            public int compare(Class<?> o1, Class<?> o2) {\n                final Integer o1s = o1.getAnnotation(Cmd.class).sort();\n                final Integer o2s = o2.getAnnotation(Cmd.class).sort();\n                return o1s.compareTo(o2s);\n            }\n        });\n        for (Class<?> clazz : classes) {\n\n            if (clazz.isAnnotationPresent(Cmd.class)) {\n                final Cmd cmd = clazz.getAnnotation(Cmd.class);\n                tTable.addRow(cmd.name(), cmd.summary());\n            }\n        }\n\n        return tTable.padding(1).rendering();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/InvokeTelnet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.AsyncContext;\nimport org.apache.dubbo.rpc.AsyncContextImpl;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.MethodDescriptor;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\n\nimport io.netty.channel.Channel;\nimport io.netty.util.AttributeKey;\n\nimport static org.apache.dubbo.common.utils.PojoUtils.realize;\n\n@Cmd(\n        name = \"invoke\",\n        summary = \"Invoke the service method.\",\n        example = {\"invoke IHelloService.sayHello(\\\"xxxx\\\")\", \"invoke sayHello(\\\"xxxx\\\")\"})\npublic class InvokeTelnet implements BaseCommand {\n    public static final AttributeKey<String> INVOKE_MESSAGE_KEY = AttributeKey.valueOf(\"telnet.invoke.method.message\");\n    public static final AttributeKey<List<Method>> INVOKE_METHOD_LIST_KEY =\n            AttributeKey.valueOf(\"telnet.invoke.method.list\");\n    public static final AttributeKey<ProviderModel> INVOKE_METHOD_PROVIDER_KEY =\n            AttributeKey.valueOf(\"telnet.invoke.method.provider\");\n\n    private final FrameworkModel frameworkModel;\n\n    public InvokeTelnet(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (ArrayUtils.isEmpty(args)) {\n            return \"Please input method name, eg: \\r\\ninvoke xxxMethod(1234, \\\"abcd\\\", {\\\"prop\\\" : \\\"value\\\"})\\r\\n\"\n                    + \"invoke XxxService.xxxMethod(1234, \\\"abcd\\\", {\\\"prop\\\" : \\\"value\\\"})\\r\\n\"\n                    + \"invoke com.xxx.XxxService.xxxMethod(1234, \\\"abcd\\\", {\\\"prop\\\" : \\\"value\\\"})\";\n        }\n        Channel channel = commandContext.getRemote();\n        String service = channel.attr(ChangeTelnet.SERVICE_KEY) != null\n                ? channel.attr(ChangeTelnet.SERVICE_KEY).get()\n                : null;\n\n        String message = args[0];\n        int i = message.indexOf(\"(\");\n\n        if (i < 0 || !message.endsWith(\")\")) {\n            return \"Invalid parameters, format: service.method(args)\";\n        }\n\n        String method = message.substring(0, i).trim();\n        String param = message.substring(i + 1, message.length() - 1).trim();\n        i = method.lastIndexOf(\".\");\n        if (i >= 0) {\n            service = method.substring(0, i).trim();\n            method = method.substring(i + 1).trim();\n        }\n\n        if (StringUtils.isEmpty(service)) {\n            return \"If you want to invoke like [invoke sayHello(\\\"xxxx\\\")], please execute cd command first,\"\n                    + \" or you can execute it like [invoke IHelloService.sayHello(\\\"xxxx\\\")]\";\n        }\n\n        List<Object> list;\n        try {\n            list = JsonUtils.toJavaList(\"[\" + param + \"]\", Object.class);\n        } catch (Throwable t) {\n            return \"Invalid json argument, cause: \" + t.getMessage();\n        }\n        StringBuilder buf = new StringBuilder();\n        Method invokeMethod = null;\n        ProviderModel selectedProvider = null;\n        if (isInvokedSelectCommand(channel)) {\n            selectedProvider = channel.attr(INVOKE_METHOD_PROVIDER_KEY).get();\n            invokeMethod = channel.attr(SelectTelnet.SELECT_METHOD_KEY).get();\n        } else {\n            for (ProviderModel provider : frameworkModel.getServiceRepository().allProviderModels()) {\n                if (!isServiceMatch(service, provider)) {\n                    continue;\n                }\n\n                selectedProvider = provider;\n                List<Method> methodList = findSameSignatureMethod(provider.getAllMethods(), method, list);\n                if (CollectionUtils.isEmpty(methodList)) {\n                    break;\n                }\n\n                if (methodList.size() == 1) {\n                    invokeMethod = methodList.get(0);\n                } else {\n                    List<Method> matchMethods = findMatchMethods(methodList, list);\n                    if (CollectionUtils.isEmpty(matchMethods)) {\n                        break;\n                    }\n                    if (matchMethods.size() == 1) {\n                        invokeMethod = matchMethods.get(0);\n                    } else { // exist overridden method\n                        channel.attr(INVOKE_METHOD_PROVIDER_KEY).set(provider);\n                        channel.attr(INVOKE_METHOD_LIST_KEY).set(matchMethods);\n                        channel.attr(INVOKE_MESSAGE_KEY).set(message);\n                        printSelectMessage(buf, matchMethods);\n                        return buf.toString();\n                    }\n                }\n                break;\n            }\n        }\n\n        if (!StringUtils.isEmpty(service)) {\n            buf.append(\"Use default service \").append(service).append('.');\n        }\n        if (selectedProvider == null) {\n            buf.append(\"\\r\\nNo such service \").append(service);\n            return buf.toString();\n        }\n        if (invokeMethod == null) {\n            buf.append(\"\\r\\nNo such method \")\n                    .append(method)\n                    .append(\" in service \")\n                    .append(service);\n            return buf.toString();\n        }\n        try {\n            Object[] array =\n                    realize(list.toArray(), invokeMethod.getParameterTypes(), invokeMethod.getGenericParameterTypes());\n            long start = System.currentTimeMillis();\n            AppResponse result = new AppResponse();\n            try {\n                Object o = invokeMethod.invoke(selectedProvider.getServiceInstance(), array);\n                boolean setValueDone = false;\n                if (RpcContext.getServerAttachment().isAsyncStarted()) {\n                    AsyncContext asyncContext = RpcContext.getServerAttachment().getAsyncContext();\n                    if (asyncContext instanceof AsyncContextImpl) {\n                        CompletableFuture<Object> internalFuture =\n                                ((AsyncContextImpl) asyncContext).getInternalFuture();\n                        result.setValue(internalFuture.get());\n                        setValueDone = true;\n                    }\n                }\n                if (!setValueDone) {\n                    result.setValue(o);\n                }\n            } catch (Throwable t) {\n                result.setException(t);\n                if (t instanceof InterruptedException) {\n                    Thread.currentThread().interrupt();\n                }\n            } finally {\n                RpcContext.removeContext();\n            }\n            long end = System.currentTimeMillis();\n            buf.append(\"\\r\\nresult: \");\n            buf.append(JsonUtils.toJson(result.recreate()));\n            buf.append(\"\\r\\nelapsed: \");\n            buf.append(end - start);\n            buf.append(\" ms.\");\n        } catch (Throwable t) {\n            return \"Failed to invoke method \" + invokeMethod.getName() + \", cause: \" + StringUtils.toString(t);\n        }\n        return buf.toString();\n    }\n\n    private boolean isServiceMatch(String service, ProviderModel provider) {\n        return provider.getServiceKey().equalsIgnoreCase(service)\n                || provider.getServiceInterfaceClass().getSimpleName().equalsIgnoreCase(service)\n                || provider.getServiceInterfaceClass().getName().equalsIgnoreCase(service)\n                || StringUtils.isEmpty(service);\n    }\n\n    private List<Method> findSameSignatureMethod(\n            Set<MethodDescriptor> methods, String lookupMethodName, List<Object> args) {\n        List<Method> sameSignatureMethods = new ArrayList<>();\n        for (MethodDescriptor model : methods) {\n            Method method = model.getMethod();\n            if (method.getName().equals(lookupMethodName) && method.getParameterTypes().length == args.size()) {\n                sameSignatureMethods.add(method);\n            }\n        }\n        return sameSignatureMethods;\n    }\n\n    private List<Method> findMatchMethods(List<Method> methods, List<Object> args) {\n        List<Method> matchMethod = new ArrayList<>();\n        for (Method method : methods) {\n            if (isMatch(method, args)) {\n                matchMethod.add(method);\n            }\n        }\n        return matchMethod;\n    }\n\n    private static boolean isMatch(Method method, List<Object> args) {\n        Class<?>[] types = method.getParameterTypes();\n        if (types.length != args.size()) {\n            return false;\n        }\n        for (int i = 0; i < types.length; i++) {\n            Class<?> type = types[i];\n            Object arg = args.get(i);\n\n            if (arg == null) {\n                if (type.isPrimitive()) {\n                    return false;\n                }\n\n                // if the type is not primitive, we choose to believe what the invoker want is a null value\n                continue;\n            }\n\n            if (ReflectUtils.isPrimitive(arg.getClass())) {\n                // allow string arg to enum type, @see PojoUtils.realize0()\n                if (arg instanceof String && type.isEnum()) {\n                    continue;\n                }\n\n                if (!ReflectUtils.isPrimitive(type)) {\n                    return false;\n                }\n\n                if (!ReflectUtils.isCompatible(type, arg)) {\n                    return false;\n                }\n            } else if (arg instanceof Map) {\n                String name = (String) ((Map<?, ?>) arg).get(\"class\");\n                if (StringUtils.isNotEmpty(name)) {\n                    Class<?> cls = ReflectUtils.forName(name);\n                    if (!type.isAssignableFrom(cls)) {\n                        return false;\n                    }\n                } else {\n                    return true;\n                }\n            } else if (arg instanceof Collection) {\n                if (!type.isArray() && !type.isAssignableFrom(arg.getClass())) {\n                    return false;\n                }\n            } else {\n                if (!type.isAssignableFrom(arg.getClass())) {\n                    return false;\n                }\n            }\n        }\n        return true;\n    }\n\n    private void printSelectMessage(StringBuilder buf, List<Method> methods) {\n        buf.append(\"Methods:\\r\\n\");\n        for (int i = 0; i < methods.size(); i++) {\n            Method method = methods.get(i);\n            buf.append(i + 1).append(\". \").append(method.getName()).append('(');\n            Class<?>[] parameterTypes = method.getParameterTypes();\n            for (int n = 0; n < parameterTypes.length; n++) {\n                buf.append(parameterTypes[n].getSimpleName());\n                if (n != parameterTypes.length - 1) {\n                    buf.append(',');\n                }\n            }\n            buf.append(\")\\r\\n\");\n        }\n        buf.append(\"Please use the select command to select the method you want to invoke. eg: select 1\");\n    }\n\n    private boolean isInvokedSelectCommand(Channel channel) {\n        if (channel.attr(SelectTelnet.SELECT_KEY).get() != null) {\n            channel.attr(SelectTelnet.SELECT_KEY).remove();\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Live.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.probe.LivenessProbe;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\n@Cmd(name = \"live\", summary = \"Judge if service is alive? \", requiredPermissionLevel = PermissionLevel.PUBLIC)\npublic class Live implements BaseCommand {\n    private final FrameworkModel frameworkModel;\n\n    public Live(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        String config = frameworkModel.getApplicationModels().stream()\n                .map(applicationModel ->\n                        applicationModel.getApplicationConfigManager().getApplication())\n                .map(o -> o.orElse(null))\n                .filter(Objects::nonNull)\n                .map(ApplicationConfig::getLivenessProbe)\n                .filter(Objects::nonNull)\n                .collect(Collectors.joining(\",\"));\n        URL url = URL.valueOf(\"application://\").addParameter(CommonConstants.QOS_LIVE_PROBE_EXTENSION, config);\n        List<LivenessProbe> livenessProbes = frameworkModel\n                .getExtensionLoader(LivenessProbe.class)\n                .getActivateExtension(url, CommonConstants.QOS_LIVE_PROBE_EXTENSION);\n        if (!livenessProbes.isEmpty()) {\n            for (LivenessProbe livenessProbe : livenessProbes) {\n                if (!livenessProbe.check()) {\n                    // 503 Service Unavailable\n                    commandContext.setHttpCode(503);\n                    return \"false\";\n                }\n            }\n        }\n        // 200 OK\n        commandContext.setHttpCode(200);\n        return \"true\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/LoggerInfo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\n\n@Cmd(\n        name = \"loggerInfo\",\n        summary = \"Print logger info\",\n        example = {\"loggerInfo\"})\npublic class LoggerInfo implements BaseCommand {\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        String availableAdapters =\n                String.join(\", \", LoggerFactory.getAvailableAdapter().toArray(new String[0]));\n        String currentAdapter = LoggerFactory.getCurrentAdapter();\n        Level level = LoggerFactory.getLevel();\n\n        return \"Available logger adapters: [\" + availableAdapters + \"]. Current Adapter: [\" + currentAdapter\n                + \"]. Log level: \" + level.name();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Ls.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.command.util.ServiceCheckUtils;\nimport org.apache.dubbo.qos.textui.TTable;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\nimport java.util.Collection;\nimport java.util.Comparator;\nimport java.util.stream.Collectors;\n\n@Cmd(\n        name = \"ls\",\n        summary = \"ls service\",\n        example = {\"ls\"})\npublic class Ls implements BaseCommand {\n    private final FrameworkModel frameworkModel;\n\n    public Ls(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        StringBuilder result = new StringBuilder();\n        result.append(listProvider());\n        result.append(listConsumer());\n\n        return result.toString();\n    }\n\n    public String listProvider() {\n        StringBuilder stringBuilder = new StringBuilder();\n        stringBuilder.append(\"As Provider side:\" + System.lineSeparator());\n        Collection<ProviderModel> providerModelList =\n                frameworkModel.getServiceRepository().allProviderModels();\n\n        // Fix: Originally, providers were stored in ConcurrentHashMap, Disordered display of servicekey list\n        providerModelList = providerModelList.stream()\n                .sorted(Comparator.comparing(ProviderModel::getServiceKey))\n                .collect(Collectors.toList());\n\n        TTable tTable = new TTable(new TTable.ColumnDefine[] {\n            new TTable.ColumnDefine(TTable.Align.MIDDLE), new TTable.ColumnDefine(TTable.Align.MIDDLE)\n        });\n\n        // Header\n        tTable.addRow(\"Provider Service Name\", \"PUB\");\n\n        // Content\n        for (ProviderModel providerModel : providerModelList) {\n            if (providerModel.getModuleModel().isInternal()) {\n                tTable.addRow(\n                        \"DubboInternal - \" + providerModel.getServiceKey(),\n                        ServiceCheckUtils.getRegisterStatus(providerModel));\n            } else {\n                tTable.addRow(providerModel.getServiceKey(), ServiceCheckUtils.getRegisterStatus(providerModel));\n            }\n        }\n        stringBuilder.append(tTable.rendering());\n\n        return stringBuilder.toString();\n    }\n\n    public String listConsumer() {\n        StringBuilder stringBuilder = new StringBuilder();\n        stringBuilder.append(\"As Consumer side:\" + System.lineSeparator());\n        Collection<ConsumerModel> consumerModelList =\n                frameworkModel.getServiceRepository().allConsumerModels();\n\n        // Fix: Originally, consumers were stored in ConcurrentHashMap, Disordered display of servicekey list\n        consumerModelList = consumerModelList.stream()\n                .sorted(Comparator.comparing(ConsumerModel::getServiceKey))\n                .collect(Collectors.toList());\n\n        TTable tTable = new TTable(new TTable.ColumnDefine[] {\n            new TTable.ColumnDefine(TTable.Align.MIDDLE), new TTable.ColumnDefine(TTable.Align.MIDDLE)\n        });\n\n        // Header\n        tTable.addRow(\"Consumer Service Name\", \"NUM\");\n\n        // Content\n        // TODO to calculate consumerAddressNum\n        for (ConsumerModel consumerModel : consumerModelList) {\n            tTable.addRow(consumerModel.getServiceKey(), ServiceCheckUtils.getConsumerAddressNum(consumerModel));\n        }\n\n        stringBuilder.append(tTable.rendering());\n\n        return stringBuilder.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Offline.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\n@Cmd(\n        name = \"offline\",\n        summary = \"offline dubbo\",\n        example = {\"offline dubbo\", \"offline xx.xx.xxx.service\"})\npublic class Offline extends BaseOffline {\n\n    public Offline(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected void doUnexport(ProviderModel.RegisterStatedURL statedURL) {\n        super.doUnexport(statedURL);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/OfflineApp.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\n@Cmd(\n        name = \"offlineApp\",\n        summary = \"offline app addresses\",\n        example = {\"offlineApp\", \"offlineApp xx.xx.xxx.service\"})\npublic class OfflineApp extends BaseOffline {\n\n    public OfflineApp(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected void doUnexport(ProviderModel.RegisterStatedURL statedURL) {\n        if (UrlUtils.isServiceDiscoveryURL(statedURL.getRegistryUrl())) {\n            super.doUnexport(statedURL);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/OfflineInterface.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\n@Cmd(\n        name = \"offlineInterface\",\n        summary = \"offline dubbo\",\n        example = {\"offlineInterface dubbo\", \"offlineInterface xx.xx.xxx.service\"})\npublic class OfflineInterface extends BaseOffline {\n    public OfflineInterface(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected void doUnexport(ProviderModel.RegisterStatedURL statedURL) {\n        if (!UrlUtils.isServiceDiscoveryURL(statedURL.getRegistryUrl())) {\n            super.doUnexport(statedURL);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Online.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\n@Cmd(\n        name = \"online\",\n        summary = \"online app addresses\",\n        example = {\"online dubbo\", \"online xx.xx.xxx.service\"})\npublic class Online extends BaseOnline {\n    public Online(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/OnlineApp.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\n@Cmd(\n        name = \"onlineApp\",\n        summary = \"online app addresses\",\n        example = {\"onlineApp\", \"onlineApp xx.xx.xxx.service\"})\npublic class OnlineApp extends BaseOnline {\n    public OnlineApp(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected void doExport(ProviderModel.RegisterStatedURL statedURL) {\n        if (UrlUtils.isServiceDiscoveryURL(statedURL.getRegistryUrl())) {\n            super.doExport(statedURL);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/OnlineInterface.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\n@Cmd(\n        name = \"onlineInterface\",\n        summary = \"online dubbo\",\n        example = {\"onlineInterface dubbo\", \"onlineInterface xx.xx.xxx.service\"})\npublic class OnlineInterface extends BaseOnline {\n    public OnlineInterface(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    protected void doExport(ProviderModel.RegisterStatedURL statedURL) {\n        if (!UrlUtils.isServiceDiscoveryURL(statedURL.getRegistryUrl())) {\n            super.doExport(statedURL);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/PortTelnet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.exchange.ExchangeServer;\nimport org.apache.dubbo.rpc.ProtocolServer;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\n\nimport java.util.Collection;\n\n@Cmd(\n        name = \"ps\",\n        summary = \"Print server ports and connections.\",\n        example = {\"ps -l [port]\", \"ps\", \"ps -l\", \"ps -l 20880\"})\npublic class PortTelnet implements BaseCommand {\n    private final DubboProtocol dubboProtocol;\n\n    public PortTelnet(FrameworkModel frameworkModel) {\n        this.dubboProtocol = DubboProtocol.getDubboProtocol(frameworkModel);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        StringBuilder buf = new StringBuilder();\n        String port = null;\n        boolean detail = false;\n        if (args.length > 0) {\n            for (String part : args) {\n                if (\"-l\".equals(part)) {\n                    detail = true;\n                } else {\n                    if (!StringUtils.isNumber(part)) {\n                        return \"Illegal port \" + part + \", must be integer.\";\n                    }\n                    port = part;\n                }\n            }\n        }\n        if (StringUtils.isEmpty(port)) {\n            for (ProtocolServer server : dubboProtocol.getServers()) {\n                if (buf.length() > 0) {\n                    buf.append(\"\\r\\n\");\n                }\n                if (detail) {\n                    buf.append(server.getUrl().getProtocol())\n                            .append(\"://\")\n                            .append(server.getUrl().getAddress());\n                } else {\n                    buf.append(server.getUrl().getPort());\n                }\n            }\n        } else {\n            int p = Integer.parseInt(port);\n            ProtocolServer protocolServer = null;\n            for (ProtocolServer s : dubboProtocol.getServers()) {\n                if (p == s.getUrl().getPort()) {\n                    protocolServer = s;\n                    break;\n                }\n            }\n            if (protocolServer != null) {\n                ExchangeServer server = (ExchangeServer) protocolServer.getRemotingServer();\n                Collection<ExchangeChannel> channels = server.getExchangeChannels();\n                for (ExchangeChannel c : channels) {\n                    if (buf.length() > 0) {\n                        buf.append(\"\\r\\n\");\n                    }\n                    if (detail) {\n                        buf.append(c.getRemoteAddress()).append(\" -> \").append(c.getLocalAddress());\n                    } else {\n                        buf.append(c.getRemoteAddress());\n                    }\n                }\n            } else {\n                buf.append(\"No such port \").append(port);\n            }\n        }\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/PublishMetadata.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_PARAMETER_FORMAT_ERROR;\n\n@Cmd(\n        name = \"publishMetadata\",\n        summary = \"update service metadata and service instance\",\n        example = {\"publishMetadata\", \"publishMetadata 5\"})\npublic class PublishMetadata implements BaseCommand {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(PublishMetadata.class);\n    private final FrameworkModel frameworkModel;\n\n    public PublishMetadata(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        logger.info(\"received publishMetadata command.\");\n\n        StringBuilder stringBuilder = new StringBuilder();\n        List<ApplicationModel> applicationModels = frameworkModel.getApplicationModels();\n\n        for (ApplicationModel applicationModel : applicationModels) {\n            if (ArrayUtils.isEmpty(args)) {\n                ServiceInstanceMetadataUtils.refreshMetadataAndInstance(applicationModel);\n                stringBuilder\n                        .append(\"publish metadata succeeded. App:\")\n                        .append(applicationModel.getApplicationName())\n                        .append(\"\\n\");\n            } else {\n                try {\n                    int delay = Integer.parseInt(args[0]);\n                    FrameworkExecutorRepository frameworkExecutorRepository = applicationModel\n                            .getFrameworkModel()\n                            .getBeanFactory()\n                            .getBean(FrameworkExecutorRepository.class);\n                    frameworkExecutorRepository\n                            .nextScheduledExecutor()\n                            .schedule(\n                                    () -> ServiceInstanceMetadataUtils.refreshMetadataAndInstance(applicationModel),\n                                    delay,\n                                    TimeUnit.SECONDS);\n                } catch (NumberFormatException e) {\n                    logger.error(CONFIG_PARAMETER_FORMAT_ERROR, \"\", \"\", \"Wrong delay param\", e);\n                    return \"publishMetadata failed! Wrong delay param!\";\n                }\n                stringBuilder\n                        .append(\"publish task submitted, will publish in \")\n                        .append(args[0])\n                        .append(\" seconds. App:\")\n                        .append(applicationModel.getApplicationName())\n                        .append(\"\\n\");\n            }\n        }\n        return stringBuilder.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/PwdTelnet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport java.util.Arrays;\n\n@Cmd(\n        name = \"pwd\",\n        summary = \"Print working default service.\",\n        example = {\"pwd\"})\npublic class PwdTelnet implements BaseCommand {\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (args.length > 0) {\n            return \"Unsupported parameter \" + Arrays.toString(args) + \" for pwd.\";\n        }\n        String service =\n                commandContext.getRemote().attr(ChangeTelnet.SERVICE_KEY).get();\n        StringBuilder buf = new StringBuilder();\n        if (StringUtils.isEmpty(service)) {\n            buf.append('/');\n        } else {\n            buf.append(service);\n        }\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Quit.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.common.QosConstants;\n\n@Cmd(name = \"quit\", summary = \"quit telnet console\", requiredPermissionLevel = PermissionLevel.PUBLIC)\npublic class Quit implements BaseCommand {\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        return QosConstants.CLOSE;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Ready.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.probe.ReadinessProbe;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\n@Cmd(name = \"ready\", summary = \"Judge if service is ready to work? \", requiredPermissionLevel = PermissionLevel.PUBLIC)\npublic class Ready implements BaseCommand {\n    private final FrameworkModel frameworkModel;\n\n    public Ready(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        String config = frameworkModel.getApplicationModels().stream()\n                .map(applicationModel ->\n                        applicationModel.getApplicationConfigManager().getApplication())\n                .map(o -> o.orElse(null))\n                .filter(Objects::nonNull)\n                .map(ApplicationConfig::getReadinessProbe)\n                .filter(Objects::nonNull)\n                .collect(Collectors.joining(\",\"));\n\n        URL url = URL.valueOf(\"application://\").addParameter(CommonConstants.QOS_READY_PROBE_EXTENSION, config);\n        List<ReadinessProbe> readinessProbes = frameworkModel\n                .getExtensionLoader(ReadinessProbe.class)\n                .getActivateExtension(url, CommonConstants.QOS_READY_PROBE_EXTENSION);\n        if (!readinessProbes.isEmpty()) {\n            for (ReadinessProbe readinessProbe : readinessProbes) {\n                if (!readinessProbe.check()) {\n                    // 503 Service Unavailable\n                    commandContext.setHttpCode(503);\n                    return \"false\";\n                }\n            }\n        }\n        // 200 OK\n        commandContext.setHttpCode(200);\n        return \"true\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SelectTelnet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\n\nimport io.netty.channel.Channel;\nimport io.netty.util.AttributeKey;\n\n@Cmd(\n        name = \"select\",\n        summary = \"Select the index of the method you want to invoke\",\n        example = {\"select [index]\"})\npublic class SelectTelnet implements BaseCommand {\n    public static final AttributeKey<Boolean> SELECT_KEY = AttributeKey.valueOf(\"telnet.select\");\n    public static final AttributeKey<Method> SELECT_METHOD_KEY = AttributeKey.valueOf(\"telnet.select.method\");\n\n    private final InvokeTelnet invokeTelnet;\n\n    public SelectTelnet(FrameworkModel frameworkModel) {\n        this.invokeTelnet = new InvokeTelnet(frameworkModel);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (ArrayUtils.isEmpty(args)) {\n            return \"Please input the index of the method you want to invoke, eg: \\r\\n select 1\";\n        }\n        Channel channel = commandContext.getRemote();\n        String message = args[0];\n        List<Method> methodList =\n                channel.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY).get();\n        if (CollectionUtils.isEmpty(methodList)) {\n            return \"Please use the invoke command first.\";\n        }\n        if (!StringUtils.isNumber(message)\n                || Integer.parseInt(message) < 1\n                || Integer.parseInt(message) > methodList.size()) {\n            return \"Illegal index ,please input select 1~\" + methodList.size();\n        }\n        Method method = methodList.get(Integer.parseInt(message) - 1);\n        channel.attr(SELECT_METHOD_KEY).set(method);\n        channel.attr(SELECT_KEY).set(Boolean.TRUE);\n        String invokeMessage = channel.attr(InvokeTelnet.INVOKE_MESSAGE_KEY).get();\n        return invokeTelnet.execute(commandContext, new String[] {invokeMessage});\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SerializeCheckStatus.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.command.util.SerializeCheckUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n@Cmd(name = \"serializeCheckStatus\", summary = \"get serialize check status\")\npublic class SerializeCheckStatus implements BaseCommand {\n\n    private final SerializeCheckUtils serializeCheckUtils;\n\n    public SerializeCheckStatus(FrameworkModel frameworkModel) {\n        serializeCheckUtils = frameworkModel.getBeanFactory().getBean(SerializeCheckUtils.class);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (commandContext.isHttp()) {\n            Map<String, Object> result = new HashMap<>();\n            result.put(\"checkStatus\", serializeCheckUtils.getStatus());\n            result.put(\"checkSerializable\", serializeCheckUtils.isCheckSerializable());\n            result.put(\"allowedPrefix\", serializeCheckUtils.getAllowedList());\n            result.put(\"disAllowedPrefix\", serializeCheckUtils.getDisAllowedList());\n\n            return JsonUtils.toJson(result);\n        } else {\n            return \"CheckStatus: \" + serializeCheckUtils.getStatus() + \"\\n\\n\" + \"CheckSerializable: \"\n                    + serializeCheckUtils.isCheckSerializable() + \"\\n\\n\" + \"AllowedPrefix:\"\n                    + \"\\n\"\n                    + serializeCheckUtils.getAllowedList().stream().sorted().collect(Collectors.joining(\"\\n\"))\n                    + \"\\n\\n\"\n                    + \"DisAllowedPrefix:\"\n                    + \"\\n\"\n                    + serializeCheckUtils.getDisAllowedList().stream().sorted().collect(Collectors.joining(\"\\n\"))\n                    + \"\\n\\n\";\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SerializeWarnedClasses.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.command.util.SerializeCheckUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n@Cmd(name = \"serializeWarnedClasses\", summary = \"get serialize warned classes\")\npublic class SerializeWarnedClasses implements BaseCommand {\n\n    private final SerializeCheckUtils serializeCheckUtils;\n\n    public SerializeWarnedClasses(FrameworkModel frameworkModel) {\n        serializeCheckUtils = frameworkModel.getBeanFactory().getBean(SerializeCheckUtils.class);\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (commandContext.isHttp()) {\n            Map<String, Object> result = new HashMap<>();\n            result.put(\"warnedClasses\", serializeCheckUtils.getWarnedClasses());\n            return JsonUtils.toJson(result);\n        } else {\n            return \"WarnedClasses: \\n\"\n                    + serializeCheckUtils.getWarnedClasses().stream().sorted().collect(Collectors.joining(\"\\n\"))\n                    + \"\\n\\n\";\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SetProfilerWarnPercent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.profiler.ProfilerSwitch;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_PROFILER_WARN_PERCENT;\n\n@Cmd(\n        name = \"setProfilerWarnPercent\",\n        example = \"setProfilerWarnPercent 0.75\",\n        summary = \"Disable Dubbo Invocation Profiler.\")\npublic class SetProfilerWarnPercent implements BaseCommand {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(SetProfilerWarnPercent.class);\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (args == null || args.length != 1) {\n            return \"args error. example: setProfilerWarnPercent 0.75\";\n        }\n        ProfilerSwitch.setWarnPercent(Double.parseDouble(args[0]));\n        logger.warn(\n                QOS_PROFILER_WARN_PERCENT, \"\", \"\", \"Dubbo Invocation Profiler warn percent has been set to \" + args[0]);\n        return \"OK\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/ShutdownTelnet.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Cmd(\n        name = \"shutdown\",\n        summary = \"Shutdown Dubbo Application.\",\n        example = {\"shutdown -t <milliseconds>\"})\npublic class ShutdownTelnet implements BaseCommand {\n\n    private final FrameworkModel frameworkModel;\n\n    public ShutdownTelnet(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n\n        int sleepMilliseconds = 0;\n        if (args != null && args.length > 0) {\n            if (args.length == 2 && \"-t\".equals(args[0]) && StringUtils.isNumber(args[1])) {\n                sleepMilliseconds = Integer.parseInt(args[1]);\n            } else {\n                return \"Invalid parameter,please input like shutdown -t 10000\";\n            }\n        }\n        long start = System.currentTimeMillis();\n        if (sleepMilliseconds > 0) {\n            try {\n                Thread.sleep(sleepMilliseconds);\n            } catch (InterruptedException e) {\n                return \"Failed to invoke shutdown command, cause: \" + e.getMessage();\n            }\n        }\n        StringBuilder buf = new StringBuilder();\n        List<ApplicationModel> applicationModels = frameworkModel.getApplicationModels();\n        for (ApplicationModel applicationModel : new ArrayList<>(applicationModels)) {\n            applicationModel.destroy();\n        }\n        // TODO change to ApplicationDeployer.destroy() or ApplicationModel.destroy()\n        //        DubboShutdownHook.getDubboShutdownHook().unregister();\n        //        DubboShutdownHook.getDubboShutdownHook().doDestroy();\n        long end = System.currentTimeMillis();\n        buf.append(\"Application has shutdown successfully\");\n        buf.append(\"\\r\\nelapsed: \");\n        buf.append(end - start);\n        buf.append(\" ms.\");\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Startup.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.probe.StartupProbe;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\n@Cmd(name = \"startup\", summary = \"Judge if service has started? \", requiredPermissionLevel = PermissionLevel.PUBLIC)\npublic class Startup implements BaseCommand {\n\n    private final FrameworkModel frameworkModel;\n\n    public Startup(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        String config = frameworkModel.getApplicationModels().stream()\n                .map(applicationModel ->\n                        applicationModel.getApplicationConfigManager().getApplication())\n                .map(o -> o.orElse(null))\n                .filter(Objects::nonNull)\n                .map(ApplicationConfig::getStartupProbe)\n                .filter(Objects::nonNull)\n                .collect(Collectors.joining(\",\"));\n\n        URL url = URL.valueOf(\"application://\").addParameter(CommonConstants.QOS_STARTUP_PROBE_EXTENSION, config);\n        List<StartupProbe> startupProbes = frameworkModel\n                .getExtensionLoader(StartupProbe.class)\n                .getActivateExtension(url, CommonConstants.QOS_STARTUP_PROBE_EXTENSION);\n        if (!startupProbes.isEmpty()) {\n            for (StartupProbe startupProbe : startupProbes) {\n                if (!startupProbe.check()) {\n                    // 503 Service Unavailable\n                    commandContext.setHttpCode(503);\n                    return \"false\";\n                }\n            }\n        }\n        // 200 OK\n        commandContext.setHttpCode(200);\n        return \"true\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SwitchLogLevel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport java.util.Locale;\n\n@Cmd(\n        name = \"switchLogLevel\",\n        summary = \"Switch log level\",\n        example = {\"switchLogLevel info\"})\npublic class SwitchLogLevel implements BaseCommand {\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (args.length != 1) {\n            return \"Unexpected argument length.\";\n        }\n        Level level;\n        switch (args[0]) {\n            case \"0\":\n                level = Level.ALL;\n                break;\n            case \"1\":\n                level = Level.TRACE;\n                break;\n            case \"2\":\n                level = Level.DEBUG;\n                break;\n            case \"3\":\n                level = Level.INFO;\n                break;\n            case \"4\":\n                level = Level.WARN;\n                break;\n            case \"5\":\n                level = Level.ERROR;\n                break;\n            case \"6\":\n                level = Level.OFF;\n                break;\n            default:\n                level = Level.valueOf(args[0].toUpperCase(Locale.ROOT));\n                break;\n        }\n        LoggerFactory.setLevel(level);\n        return \"OK\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SwitchLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\n@Cmd(\n        name = \"switchLogger\",\n        summary = \"Switch logger\",\n        example = {\"switchLogger slf4j\"})\npublic class SwitchLogger implements BaseCommand {\n    private final FrameworkModel frameworkModel;\n\n    public SwitchLogger(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        if (args.length != 1) {\n            return \"Unexpected argument length.\";\n        }\n        Level level = LoggerFactory.getLevel();\n        LoggerFactory.setLoggerAdapter(frameworkModel, args[0]);\n        LoggerFactory.setLevel(level);\n        return \"OK\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/Version.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\n\n@Cmd(\n        name = \"version\",\n        summary = \"version command(show dubbo version)\",\n        example = {\"version\"})\npublic class Version implements BaseCommand {\n\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        StringBuilder versionDescBuilder = new StringBuilder();\n        versionDescBuilder.append(\"dubbo version \\\"\");\n        versionDescBuilder.append(org.apache.dubbo.common.Version.getVersion());\n        versionDescBuilder.append('\\\"');\n        return versionDescBuilder.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/util/CommandHelper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.util;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\npublic class CommandHelper {\n\n    private final FrameworkModel frameworkModel;\n\n    public CommandHelper(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    public boolean hasCommand(String commandName) {\n\n        BaseCommand command;\n        try {\n            command = frameworkModel.getExtensionLoader(BaseCommand.class).getExtension(commandName);\n        } catch (Throwable throwable) {\n            return false;\n        }\n\n        return command != null;\n    }\n\n    public List<Class<?>> getAllCommandClass() {\n        final Set<String> commandList =\n                frameworkModel.getExtensionLoader(BaseCommand.class).getSupportedExtensions();\n        final List<Class<?>> classes = new ArrayList<>();\n\n        for (String commandName : commandList) {\n            BaseCommand command =\n                    frameworkModel.getExtensionLoader(BaseCommand.class).getExtension(commandName);\n            classes.add(command.getClass());\n        }\n\n        return classes;\n    }\n\n    public Class<?> getCommandClass(String commandName) {\n        if (hasCommand(commandName)) {\n            return frameworkModel\n                    .getExtensionLoader(BaseCommand.class)\n                    .getExtension(commandName)\n                    .getClass();\n        } else {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/util/SerializeCheckUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.util;\n\nimport org.apache.dubbo.common.utils.AllowClassNotifyListener;\nimport org.apache.dubbo.common.utils.SerializeCheckStatus;\nimport org.apache.dubbo.common.utils.SerializeSecurityManager;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Collections;\nimport java.util.Set;\n\npublic class SerializeCheckUtils implements AllowClassNotifyListener {\n    private final SerializeSecurityManager manager;\n    private volatile Set<String> allowedList = Collections.emptySet();\n    private volatile Set<String> disAllowedList = Collections.emptySet();\n    private volatile SerializeCheckStatus status = AllowClassNotifyListener.DEFAULT_STATUS;\n    private volatile boolean checkSerializable = true;\n\n    public SerializeCheckUtils(FrameworkModel frameworkModel) {\n        manager = frameworkModel.getBeanFactory().getOrRegisterBean(SerializeSecurityManager.class);\n        manager.registerListener(this);\n    }\n\n    @Override\n    public void notifyPrefix(Set<String> allowedList, Set<String> disAllowedList) {\n        this.allowedList = allowedList;\n        this.disAllowedList = disAllowedList;\n    }\n\n    @Override\n    public void notifyCheckStatus(SerializeCheckStatus status) {\n        this.status = status;\n    }\n\n    @Override\n    public void notifyCheckSerializable(boolean checkSerializable) {\n        this.checkSerializable = checkSerializable;\n    }\n\n    public Set<String> getAllowedList() {\n        return allowedList;\n    }\n\n    public Set<String> getDisAllowedList() {\n        return disAllowedList;\n    }\n\n    public SerializeCheckStatus getStatus() {\n        return status;\n    }\n\n    public boolean isCheckSerializable() {\n        return checkSerializable;\n    }\n\n    public Set<String> getWarnedClasses() {\n        return manager.getWarnedClasses();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/util/ServiceCheckUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.util;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.client.migration.MigrationInvoker;\nimport org.apache.dubbo.registry.client.migration.model.MigrationStep;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\npublic class ServiceCheckUtils {\n\n    public static String getRegisterStatus(ProviderModel providerModel) {\n        // check all registries status\n        List<String> statuses = new LinkedList<>();\n        for (ProviderModel.RegisterStatedURL registerStatedURL : providerModel.getStatedUrl()) {\n            URL registryUrl = registerStatedURL.getRegistryUrl();\n            boolean isServiceDiscovery = UrlUtils.isServiceDiscoveryURL(registryUrl);\n            String protocol = isServiceDiscovery\n                    ? registryUrl.getParameter(RegistryConstants.REGISTRY_KEY)\n                    : registryUrl.getProtocol();\n            // e.g. zookeeper-A(Y)\n            statuses.add(protocol + \"-\" + (isServiceDiscovery ? \"A\" : \"I\") + \"(\"\n                    + (registerStatedURL.isRegistered() ? \"Y\" : \"N\") + \")\");\n        }\n        // e.g. zookeeper-A(Y)/zookeeper-I(Y)\n        return String.join(\"/\", statuses.toArray(new String[0]));\n    }\n\n    public static String getConsumerAddressNum(ConsumerModel consumerModel) {\n        int num = 0;\n        Object object = consumerModel.getServiceMetadata().getAttribute(CommonConstants.CURRENT_CLUSTER_INVOKER_KEY);\n        Map<Registry, MigrationInvoker<?>> invokerMap;\n        List<String> nums = new LinkedList<>();\n        if (object instanceof Map) {\n            invokerMap = (Map<Registry, MigrationInvoker<?>>) object;\n            for (Map.Entry<Registry, MigrationInvoker<?>> entry : invokerMap.entrySet()) {\n                URL registryUrl = entry.getKey().getUrl();\n                boolean isServiceDiscovery = UrlUtils.isServiceDiscoveryURL(registryUrl);\n                String protocol = isServiceDiscovery\n                        ? registryUrl.getParameter(RegistryConstants.REGISTRY_KEY)\n                        : registryUrl.getProtocol();\n                MigrationInvoker<?> migrationInvoker = entry.getValue();\n                MigrationStep migrationStep = migrationInvoker.getMigrationStep();\n                String interfaceSize = Optional.ofNullable(migrationInvoker.getInvoker())\n                        .map(ClusterInvoker::getDirectory)\n                        .map(Directory::getAllInvokers)\n                        .map(List::size)\n                        .map(String::valueOf)\n                        .orElse(\"-\");\n                String applicationSize = Optional.ofNullable(migrationInvoker.getServiceDiscoveryInvoker())\n                        .map(ClusterInvoker::getDirectory)\n                        .map(Directory::getAllInvokers)\n                        .map(List::size)\n                        .map(String::valueOf)\n                        .orElse(\"-\");\n                String step;\n                String size;\n                switch (migrationStep) {\n                    case APPLICATION_FIRST:\n                        step = \"AF\";\n                        size = \"I-\" + interfaceSize + \",A-\" + applicationSize;\n                        break;\n                    case FORCE_INTERFACE:\n                        step = \"I\";\n                        size = interfaceSize;\n                        break;\n                    default:\n                        step = \"A\";\n                        size = applicationSize;\n                        break;\n                }\n                // zookeeper-AF(I-10,A-0)\n                // zookeeper-I(10)\n                // zookeeper-A(10)\n                nums.add(protocol + \"-\" + step + \"(\" + size + \")\");\n            }\n        }\n        // zookeeper-AF(I-10,A-0)/nacos-I(10)\n        return String.join(\"/\", nums.toArray(new String[0]));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/common/QosConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.common;\n\npublic interface QosConstants {\n\n    int DEFAULT_PORT = 22222;\n\n    String BR_STR = \"\\r\\n\";\n    String CLOSE = \"close!\";\n\n    String QOS_PERMISSION_CHECKER = \"qosPermissionChecker\";\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/ChangeTelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.remoting.telnet.support.Help;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\n\n/**\n * ChangeServiceTelnetHandler\n */\n@Activate\n@Help(parameter = \"[service]\", summary = \"Change default service.\", detail = \"Change default service.\")\npublic class ChangeTelnetHandler implements TelnetHandler {\n\n    public static final String SERVICE_KEY = \"telnet.service\";\n\n    @Override\n    public String telnet(Channel channel, String message) {\n        if (StringUtils.isEmpty(message)) {\n            return \"Please input service name, eg: \\r\\ncd XxxService\\r\\ncd com.xxx.XxxService\";\n        }\n        StringBuilder buf = new StringBuilder();\n        if (\"/\".equals(message) || \"..\".equals(message)) {\n            String service = (String) channel.getAttribute(SERVICE_KEY);\n            channel.removeAttribute(SERVICE_KEY);\n            buf.append(\"Cancelled default service \").append(service).append('.');\n        } else {\n            boolean found = false;\n            for (Exporter<?> exporter : DubboProtocol.getDubboProtocol().getExporters()) {\n                if (message.equals(exporter.getInvoker().getInterface().getSimpleName())\n                        || message.equals(exporter.getInvoker().getInterface().getName())\n                        || message.equals(exporter.getInvoker().getUrl().getPath())) {\n                    found = true;\n                    break;\n                }\n            }\n            if (found) {\n                channel.setAttribute(SERVICE_KEY, message);\n                buf.append(\"Used the \")\n                        .append(message)\n                        .append(\" as default.\\r\\nYou can cancel default service by command: cd /\");\n            } else {\n                buf.append(\"No such service \").append(message);\n            }\n        }\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/LogTelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.remoting.telnet.support.Help;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n@Activate\n@Help(parameter = \"level\", summary = \"Change log level or show log \", detail = \"Change log level or show log\")\npublic class LogTelnetHandler implements TelnetHandler {\n\n    public static final String SERVICE_KEY = \"telnet.log\";\n\n    @Override\n    public String telnet(Channel channel, String message) {\n        long size;\n        File file = LoggerFactory.getFile();\n        StringBuilder buf = new StringBuilder();\n        if (message == null || message.trim().length() == 0) {\n            buf.append(\"EXAMPLE: log error / log 100\");\n        } else {\n            String[] str = message.split(\" \");\n            if (!StringUtils.isNumber(str[0])) {\n                LoggerFactory.setLevel(Level.valueOf(message.toUpperCase()));\n            } else {\n                int showLogLength = Integer.parseInt(str[0]);\n\n                if (file != null && file.exists()) {\n                    try (FileInputStream fis = new FileInputStream(file)) {\n                        FileChannel filechannel = fis.getChannel();\n                        size = filechannel.size();\n                        ByteBuffer bb;\n                        if (size <= showLogLength) {\n                            bb = ByteBuffer.allocate((int) size);\n                            filechannel.read(bb, 0);\n                        } else {\n                            int pos = (int) (size - showLogLength);\n                            bb = ByteBuffer.allocate(showLogLength);\n                            filechannel.read(bb, pos);\n                        }\n                        bb.flip();\n                        String content = new String(bb.array())\n                                .replace(\"<\", \"&lt;\")\n                                .replace(\">\", \"&gt;\")\n                                .replace(\"\\n\", \"<br/><br/>\");\n                        buf.append(\"\\r\\ncontent:\").append(content);\n\n                        buf.append(\"\\r\\nmodified:\")\n                                .append(new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\")\n                                        .format(new Date(file.lastModified())));\n                        buf.append(\"\\r\\nsize:\").append(size).append(\"\\r\\n\");\n                    } catch (Exception e) {\n                        buf.append(e.getMessage());\n                    }\n                } else {\n                    buf.append(\"\\r\\nMESSAGE: log file not exists or log appender is console .\");\n                }\n            }\n        }\n        buf.append(\"\\r\\nCURRENT LOG LEVEL:\")\n                .append(LoggerFactory.getLevel())\n                .append(\"\\r\\nCURRENT LOG APPENDER:\")\n                .append(file == null ? \"console\" : file.getAbsolutePath());\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/TraceTelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.remoting.telnet.support.Help;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\nimport org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter;\n\nimport java.lang.reflect.Method;\n\n@Activate\n@Help(parameter = \"[service] [method] [times]\", summary = \"Trace the service.\", detail = \"Trace the service.\")\npublic class TraceTelnetHandler implements TelnetHandler {\n\n    @Override\n    public String telnet(Channel channel, String message) {\n        String service = (String) channel.getAttribute(ChangeTelnetHandler.SERVICE_KEY);\n        if ((StringUtils.isEmpty(service)) && (StringUtils.isEmpty(message))) {\n            return \"Please input service name, eg: \\r\\ntrace XxxService\\r\\ntrace XxxService xxxMethod\\r\\ntrace XxxService xxxMethod 10\\r\\nor \\\"cd XxxService\\\" firstly.\";\n        }\n        String[] parts = message.split(\"\\\\s+\");\n        String method;\n        String times;\n        // message like : XxxService , XxxService 10 , XxxService xxxMethod , XxxService xxxMethod 10\n        if (StringUtils.isEmpty(service)) {\n            service = parts.length > 0 ? parts[0] : null;\n            method = parts.length > 1 ? parts[1] : null;\n            times = parts.length > 2 ? parts[2] : \"1\";\n        } else { // message like : xxxMethod, xxxMethod 10\n            method = parts.length > 0 ? parts[0] : null;\n            times = parts.length > 1 ? parts[1] : \"1\";\n        }\n        if (StringUtils.isNumber(method)) {\n            times = method;\n            method = null;\n        }\n        if (!StringUtils.isNumber(times)) {\n            return \"Illegal times \" + times + \", must be integer.\";\n        }\n        Invoker<?> invoker = null;\n        for (Exporter<?> exporter : DubboProtocol.getDubboProtocol().getExporters()) {\n            if (service.equals(exporter.getInvoker().getInterface().getSimpleName())\n                    || service.equals(exporter.getInvoker().getInterface().getName())\n                    || service.equals(exporter.getInvoker().getUrl().getPath())) {\n                invoker = exporter.getInvoker();\n                break;\n            }\n        }\n        if (invoker != null) {\n            if (StringUtils.isNotEmpty(method)) {\n                boolean found = false;\n                for (Method m : invoker.getInterface().getMethods()) {\n                    if (m.getName().equals(method)) {\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) {\n                    return \"No such method \" + method + \" in class \"\n                            + invoker.getInterface().getName();\n                }\n            }\n            TraceFilter.addTracer(invoker.getInterface(), method, channel, Integer.parseInt(times));\n        } else {\n            return \"No such service \" + service;\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/DefaultAnonymousAccessPermissionChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.permission;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.api.QosConfiguration;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\nimport java.util.Optional;\n\nimport io.netty.channel.Channel;\n\npublic class DefaultAnonymousAccessPermissionChecker implements PermissionChecker {\n    public static final DefaultAnonymousAccessPermissionChecker INSTANCE =\n            new DefaultAnonymousAccessPermissionChecker();\n\n    @Override\n    public boolean access(CommandContext commandContext, PermissionLevel defaultCmdRequiredPermissionLevel) {\n        final InetAddress inetAddress = Optional.ofNullable(commandContext.getRemote())\n                .map(Channel::remoteAddress)\n                .map(InetSocketAddress.class::cast)\n                .map(InetSocketAddress::getAddress)\n                .orElse(null);\n\n        QosConfiguration qosConfiguration = commandContext.getQosConfiguration();\n        String anonymousAllowCommands = qosConfiguration.getAnonymousAllowCommands();\n        if (StringUtils.isNotEmpty(anonymousAllowCommands)\n                && Arrays.stream(anonymousAllowCommands.split(\",\"))\n                        .filter(StringUtils::isNotEmpty)\n                        .map(String::trim)\n                        .anyMatch(cmd -> cmd.equals(commandContext.getCommandName()))) {\n            return true;\n        }\n\n        PermissionLevel currentLevel = qosConfiguration.getAnonymousAccessPermissionLevel();\n\n        // Local has private permission\n        if (inetAddress != null && inetAddress.isLoopbackAddress()) {\n            currentLevel = PermissionLevel.PRIVATE;\n        } else if (inetAddress != null\n                && qosConfiguration.getAcceptForeignIpWhitelistPredicate().test(inetAddress.getHostAddress())) {\n            currentLevel = PermissionLevel.PROTECTED;\n        }\n\n        return currentLevel.getLevel() >= defaultCmdRequiredPermissionLevel.getLevel();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/permission/PermissionChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.permission;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\n\n// qosPermissionChecker=xxx.xxx.xxxPermissionChecker\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface PermissionChecker {\n    boolean access(CommandContext commandContext, PermissionLevel defaultCmdPermissionLevel);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/probe/LivenessProbe.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.probe;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * A probe to indicate whether program is alive\n * </p>\n * If one or more spi return false, 'live' command in dubbo-qos\n * will return false. This can be extended with custom program and developers\n * can implement this to customize life cycle.\n *\n * @since 3.0\n */\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface LivenessProbe {\n    /**\n     * Check if program is alive\n     *\n     * @return {@link boolean} result of probe\n     */\n    boolean check();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/probe/ReadinessProbe.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.probe;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * A probe to indicate whether program is ready\n * </p>\n * If one or more spi return false, 'ready' command in dubbo-qos\n * will return false. This can be extended with custom program and developers\n * can implement this to customize life cycle.\n *\n * @since 3.0\n */\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface ReadinessProbe {\n    /**\n     * Check if program is Ready\n     *\n     * @return {@link boolean} result of probe\n     */\n    boolean check();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/probe/StartupProbe.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.probe;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * A probe to indicate whether program is startup\n * </p>\n * If one or more spi return false, 'startup' command in dubbo-qos\n * will return false. This can be extended with custom program and developers\n * can implement this to customize life cycle.\n *\n * @since 3.0\n */\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface StartupProbe {\n    /**\n     * Check if program has been startup\n     *\n     * @return {@link boolean} result of probe\n     */\n    boolean check();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/probe/impl/DeployerReadinessProbe.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.probe.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.qos.probe.ReadinessProbe;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.List;\n\n@Activate\npublic class DeployerReadinessProbe implements ReadinessProbe {\n    private FrameworkModel frameworkModel;\n\n    public DeployerReadinessProbe(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public boolean check() {\n        if (this.frameworkModel == null) {\n            this.frameworkModel = FrameworkModel.defaultModel();\n        }\n        List<ApplicationModel> applicationModels = frameworkModel.getApplicationModels();\n        for (ApplicationModel applicationModel : applicationModels) {\n            for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n                if (!moduleModel.getDeployer().isCompletion()) {\n                    return false;\n                }\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/probe/impl/DeployerStartupProbe.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.probe.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.qos.probe.StartupProbe;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.List;\n\n@Activate\npublic class DeployerStartupProbe implements StartupProbe {\n    private FrameworkModel frameworkModel;\n\n    public DeployerStartupProbe(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public boolean check() {\n        if (this.frameworkModel == null) {\n            this.frameworkModel = FrameworkModel.defaultModel();\n        }\n        List<ApplicationModel> applicationModels = frameworkModel.getApplicationModels();\n        for (ApplicationModel applicationModel : applicationModels) {\n            for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n                if (moduleModel.getDeployer().isRunning()) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/probe/impl/ProviderReadinessProbe.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.probe.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.qos.probe.ReadinessProbe;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.FrameworkServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\n\nimport java.util.Collection;\n\n@Activate\npublic class ProviderReadinessProbe implements ReadinessProbe {\n    private final FrameworkModel frameworkModel;\n    private final FrameworkServiceRepository serviceRepository;\n\n    public ProviderReadinessProbe(FrameworkModel frameworkModel) {\n        if (frameworkModel != null) {\n            this.frameworkModel = frameworkModel;\n        } else {\n            this.frameworkModel = FrameworkModel.defaultModel();\n        }\n        this.serviceRepository = this.frameworkModel.getServiceRepository();\n    }\n\n    @Override\n    public boolean check() {\n        Collection<ProviderModel> providerModelList = serviceRepository.allProviderModels();\n        if (providerModelList.isEmpty()) {\n            return true;\n        }\n\n        boolean hasService = false, anyOnline = false;\n        for (ProviderModel providerModel : providerModelList) {\n            if (providerModel.getModuleModel().isInternal()) {\n                continue;\n            }\n            hasService = true;\n            anyOnline = anyOnline\n                    || providerModel.getStatedUrl().isEmpty()\n                    || providerModel.getStatedUrl().stream().anyMatch(ProviderModel.RegisterStatedURL::isRegistered);\n        }\n\n        // no service => check pass\n        // has service and any online => check pass\n        // has service and none online => check fail\n        return !(hasService && !anyOnline);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/protocol/QosProtocolWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.protocol;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.common.QosConstants;\nimport org.apache.dubbo.qos.server.Server;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProtocolServer;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_FAILED_START_SERVER;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_WHITELIST;\nimport static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_ALLOW_COMMANDS;\nimport static org.apache.dubbo.common.constants.QosConstants.ANONYMOUS_ACCESS_PERMISSION_LEVEL;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_CHECK;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;\n\n@Activate(order = 200)\npublic class QosProtocolWrapper implements Protocol, ScopeModelAware {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(QosProtocolWrapper.class);\n\n    private final AtomicBoolean hasStarted = new AtomicBoolean(false);\n\n    private final Protocol protocol;\n\n    private FrameworkModel frameworkModel;\n\n    public QosProtocolWrapper(Protocol protocol) {\n        if (protocol == null) {\n            throw new IllegalArgumentException(\"protocol == null\");\n        }\n        this.protocol = protocol;\n    }\n\n    @Override\n    public void setFrameworkModel(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public int getDefaultPort() {\n        return protocol.getDefaultPort();\n    }\n\n    @Override\n    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {\n        startQosServer(invoker.getUrl(), true);\n        return protocol.export(invoker);\n    }\n\n    @Override\n    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {\n        startQosServer(url, false);\n        return protocol.refer(type, url);\n    }\n\n    @Override\n    public void destroy() {\n        protocol.destroy();\n        stopServer();\n    }\n\n    @Override\n    public List<ProtocolServer> getServers() {\n        return protocol.getServers();\n    }\n\n    private void startQosServer(URL url, boolean isServer) throws RpcException {\n        boolean qosCheck = url.getParameter(QOS_CHECK, false);\n\n        try {\n            if (!hasStarted.compareAndSet(false, true)) {\n                return;\n            }\n\n            boolean qosEnable = url.getParameter(QOS_ENABLE, true);\n            if (!qosEnable) {\n                logger.info(\"qos won't be started because it is disabled. \"\n                        + \"Please check dubbo.application.qos.enable is configured either in system property, \"\n                        + \"dubbo.properties or XML/spring-boot configuration.\");\n                return;\n            }\n\n            String host = url.getParameter(QOS_HOST);\n            int port = url.getParameter(QOS_PORT, QosConstants.DEFAULT_PORT);\n            boolean acceptForeignIp = Boolean.parseBoolean(url.getParameter(ACCEPT_FOREIGN_IP, \"false\"));\n            String acceptForeignIpWhitelist = url.getParameter(ACCEPT_FOREIGN_IP_WHITELIST, StringUtils.EMPTY_STRING);\n            String anonymousAccessPermissionLevel =\n                    url.getParameter(ANONYMOUS_ACCESS_PERMISSION_LEVEL, PermissionLevel.PUBLIC.name());\n            String anonymousAllowCommands = url.getParameter(ANONYMOUS_ACCESS_ALLOW_COMMANDS, StringUtils.EMPTY_STRING);\n            Server server = frameworkModel.getBeanFactory().getBean(Server.class);\n\n            if (server.isStarted()) {\n                return;\n            }\n\n            server.setHost(host);\n            server.setPort(port);\n            server.setAcceptForeignIp(acceptForeignIp);\n            server.setAcceptForeignIpWhitelist(acceptForeignIpWhitelist);\n            server.setAnonymousAccessPermissionLevel(anonymousAccessPermissionLevel);\n            server.setAnonymousAllowCommands(anonymousAllowCommands);\n            server.start();\n\n        } catch (Throwable throwable) {\n            logger.warn(QOS_FAILED_START_SERVER, \"\", \"\", \"Fail to start qos server: \", throwable);\n\n            if (qosCheck) {\n                try {\n                    // Stop QoS Server to support re-start if Qos-Check is enabled\n                    stopServer();\n                } catch (Throwable stop) {\n                    logger.warn(QOS_FAILED_START_SERVER, \"\", \"\", \"Fail to stop qos server: \", stop);\n                }\n                if (isServer) {\n                    // Only throws exception when export services\n                    throw new RpcException(throwable);\n                }\n            }\n        }\n    }\n\n    /*package*/ void stopServer() {\n        if (hasStarted.compareAndSet(true, false)) {\n            Server server = frameworkModel.getBeanFactory().getBean(Server.class);\n            if (server.isStarted()) {\n                server.stop();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/DubboLogo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server;\n\npublic class DubboLogo {\n    public static final String DUBBO =\n            \"   ___   __  __ ___   ___   ____     \" + System.lineSeparator() + \"  / _ \\\\ / / / // _ ) / _ ) / __ \\\\  \"\n                    + System.lineSeparator() + \" / // // /_/ // _  |/ _  |/ /_/ /    \"\n                    + System.lineSeparator() + \"/____/ \\\\____//____//____/ \\\\____/   \"\n                    + System.lineSeparator();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/QosBindException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server;\n\n/**\n * Indicate that if Qos Start failed\n */\npublic class QosBindException extends RuntimeException {\n    public QosBindException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/Server.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.api.QosConfiguration;\nimport org.apache.dubbo.qos.server.handler.QosProcessHandler;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.util.concurrent.DefaultThreadFactory;\n\n/**\n * A server serves for both telnet access and http access\n * <ul>\n * <li>static initialize server</li>\n * <li>start server and bind port</li>\n * <li>close server</li>\n * </ul>\n */\npublic class Server {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(Server.class);\n\n    private String host;\n\n    private int port;\n\n    private boolean acceptForeignIp = true;\n    private String acceptForeignIpWhitelist = StringUtils.EMPTY_STRING;\n\n    private String anonymousAccessPermissionLevel = PermissionLevel.NONE.name();\n\n    private String anonymousAllowCommands = StringUtils.EMPTY_STRING;\n\n    private EventLoopGroup boss;\n\n    private EventLoopGroup worker;\n\n    private FrameworkModel frameworkModel;\n\n    public Server(FrameworkModel frameworkModel) {\n        this.welcome = DubboLogo.DUBBO;\n        this.frameworkModel = frameworkModel;\n    }\n\n    private String welcome;\n\n    private AtomicBoolean started = new AtomicBoolean();\n\n    /**\n     * welcome message\n     */\n    public void setWelcome(String welcome) {\n        this.welcome = welcome;\n    }\n\n    public int getPort() {\n        return port;\n    }\n\n    /**\n     * start server, bind port\n     */\n    public void start() throws Throwable {\n        if (!started.compareAndSet(false, true)) {\n            return;\n        }\n        boss = new NioEventLoopGroup(1, new DefaultThreadFactory(\"qos-boss\", true));\n        worker = new NioEventLoopGroup(0, new DefaultThreadFactory(\"qos-worker\", true));\n        ServerBootstrap serverBootstrap = new ServerBootstrap();\n        serverBootstrap.group(boss, worker);\n        serverBootstrap.channel(NioServerSocketChannel.class);\n        serverBootstrap.option(ChannelOption.SO_REUSEADDR, true);\n        serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);\n        serverBootstrap.childHandler(new ChannelInitializer<Channel>() {\n\n            @Override\n            protected void initChannel(Channel ch) throws Exception {\n                ch.pipeline()\n                        .addLast(new QosProcessHandler(\n                                frameworkModel,\n                                QosConfiguration.builder()\n                                        .welcome(welcome)\n                                        .acceptForeignIp(acceptForeignIp)\n                                        .acceptForeignIpWhitelist(acceptForeignIpWhitelist)\n                                        .anonymousAccessPermissionLevel(anonymousAccessPermissionLevel)\n                                        .anonymousAllowCommands(anonymousAllowCommands)\n                                        .build()));\n            }\n        });\n        try {\n            if (StringUtils.isBlank(host)) {\n                serverBootstrap.bind(port).sync();\n            } else {\n                serverBootstrap.bind(host, port).sync();\n            }\n\n            logger.info(\"qos-server bind localhost:\" + port);\n        } catch (Throwable throwable) {\n            throw new QosBindException(\"qos-server can not bind localhost:\" + port, throwable);\n        }\n    }\n\n    /**\n     * close server\n     */\n    public void stop() {\n        logger.info(\"qos-server stopped.\");\n        if (boss != null) {\n            boss.shutdownGracefully();\n        }\n        if (worker != null) {\n            worker.shutdownGracefully();\n        }\n        started.set(false);\n    }\n\n    public String getHost() {\n        return host;\n    }\n\n    public void setHost(String host) {\n        this.host = host;\n    }\n\n    public void setPort(int port) {\n        this.port = port;\n    }\n\n    public boolean isAcceptForeignIp() {\n        return acceptForeignIp;\n    }\n\n    public void setAcceptForeignIp(boolean acceptForeignIp) {\n        this.acceptForeignIp = acceptForeignIp;\n    }\n\n    public void setAcceptForeignIpWhitelist(String acceptForeignIpWhitelist) {\n        this.acceptForeignIpWhitelist = acceptForeignIpWhitelist;\n    }\n\n    public void setAnonymousAccessPermissionLevel(String anonymousAccessPermissionLevel) {\n        this.anonymousAccessPermissionLevel = anonymousAccessPermissionLevel;\n    }\n\n    public void setAnonymousAllowCommands(String anonymousAllowCommands) {\n        this.anonymousAllowCommands = anonymousAllowCommands;\n    }\n\n    public String getWelcome() {\n        return welcome;\n    }\n\n    public boolean isStarted() {\n        return started.get();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/CtrlCHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.qos.common.QosConstants;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.util.CharsetUtil;\nimport io.netty.util.ReferenceCountUtil;\n\npublic class CtrlCHandler extends SimpleChannelInboundHandler<ByteBuf> {\n    /**\n     * When type 'Ctrl+C', telnet client will send the following sequence:\n     * 'FF F4 FF FD 06', it can be divided into two parts:\n     * <p>\n     * 1. 'FF F4' is telnet interrupt process command.\n     * <p>\n     * 2. 'FF FD 06' is  to suppress the output of the process that is to be\n     *    interrupted by the  interrupt process command.\n     * <p>\n     * We need to response with 'FF FC 06' to ignore it and tell the client continue\n     * display output.\n     */\n    private byte[] CTRLC_BYTES_SEQUENCE = new byte[] {(byte) 0xff, (byte) 0xf4, (byte) 0xff, (byte) 0xfd, (byte) 0x06};\n\n    private byte[] RESPONSE_SEQUENCE = new byte[] {(byte) 0xff, (byte) 0xfc, 0x06};\n\n    public CtrlCHandler() {\n        super(false);\n    }\n\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {\n        // find ctrl+c\n        final int readerIndex = buffer.readerIndex();\n        for (int i = readerIndex; i < buffer.writerIndex(); i++) {\n            if (buffer.readableBytes() - i < CTRLC_BYTES_SEQUENCE.length) {\n                break;\n            }\n            boolean match = true;\n            for (int j = 0; j < CTRLC_BYTES_SEQUENCE.length; j++) {\n                if (CTRLC_BYTES_SEQUENCE[j] != buffer.getByte(i + j)) {\n                    match = false;\n                    break;\n                }\n            }\n\n            if (match) {\n                buffer.readerIndex(readerIndex + buffer.readableBytes());\n                ctx.writeAndFlush(Unpooled.wrappedBuffer(RESPONSE_SEQUENCE));\n                ctx.writeAndFlush(Unpooled.wrappedBuffer(\n                        (QosConstants.BR_STR + QosProcessHandler.PROMPT).getBytes(CharsetUtil.UTF_8)));\n\n                ReferenceCountUtil.release(buffer);\n                return;\n            }\n        }\n        ctx.fireChannelRead(buffer);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/ForeignHostPermitHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.QosConfiguration;\nimport org.apache.dubbo.qos.common.QosConstants;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.nio.charset.StandardCharsets;\nimport java.util.function.Predicate;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandlerAdapter;\nimport io.netty.channel.ChannelHandlerContext;\n\npublic class ForeignHostPermitHandler extends ChannelHandlerAdapter {\n\n    // true means to accept foreign IP\n    private final boolean acceptForeignIp;\n\n    // the whitelist of foreign IP when acceptForeignIp = false, the delimiter is colon(,)\n    // support specific ip and an ip range from CIDR specification\n    private final String acceptForeignIpWhitelist;\n    private final Predicate<String> whitelistPredicate;\n\n    private final QosConfiguration qosConfiguration;\n\n    public ForeignHostPermitHandler(QosConfiguration qosConfiguration) {\n        this.qosConfiguration = qosConfiguration;\n        this.acceptForeignIp = qosConfiguration.isAcceptForeignIp();\n        this.acceptForeignIpWhitelist = qosConfiguration.getAcceptForeignIpWhitelist();\n        this.whitelistPredicate = qosConfiguration.getAcceptForeignIpWhitelistPredicate();\n    }\n\n    @Override\n    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {\n        if (acceptForeignIp) {\n            return;\n        }\n\n        // the anonymous access is enabled by default, permission level is PUBLIC\n        // if allow anonymous access, return\n        if (qosConfiguration.isAllowAnonymousAccess()) {\n            return;\n        }\n\n        final InetAddress inetAddress = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress();\n        // loopback address, return\n        if (inetAddress.isLoopbackAddress()) {\n            return;\n        }\n\n        // the ip is in the whitelist, return\n        if (checkForeignIpInWhiteList(inetAddress)) {\n            return;\n        }\n\n        ByteBuf cb = Unpooled.wrappedBuffer((QosConstants.BR_STR\n                        + \"Foreign Ip Not Permitted, Consider Config It In Whitelist.\" + QosConstants.BR_STR)\n                .getBytes(StandardCharsets.UTF_8));\n        ctx.writeAndFlush(cb).addListener(ChannelFutureListener.CLOSE);\n    }\n\n    private boolean checkForeignIpInWhiteList(InetAddress inetAddress) {\n        if (StringUtils.isEmpty(acceptForeignIpWhitelist)) {\n            return false;\n        }\n\n        final String foreignIp = inetAddress.getHostAddress();\n        return whitelistPredicate.test(foreignIp);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/HttpProcessHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.QosConfiguration;\nimport org.apache.dubbo.qos.command.CommandExecutor;\nimport org.apache.dubbo.qos.command.DefaultCommandExecutor;\nimport org.apache.dubbo.qos.command.decoder.HttpCommandDecoder;\nimport org.apache.dubbo.qos.command.exception.NoSuchCommandException;\nimport org.apache.dubbo.qos.command.exception.PermissionDenyException;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.nio.charset.StandardCharsets;\n\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.handler.codec.http.DefaultFullHttpResponse;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport io.netty.handler.codec.http.HttpHeaderNames;\nimport io.netty.handler.codec.http.HttpHeaders;\nimport io.netty.handler.codec.http.HttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.handler.codec.http.HttpVersion;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_COMMAND_NOT_FOUND;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_PERMISSION_DENY_EXCEPTION;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_UNEXPECTED_EXCEPTION;\n\n/**\n * Parse HttpRequest for uri and parameters\n * <p>\n * <ul>\n * <li>if command not found, return 404</li>\n * <li>if execution fails, return 500</li>\n * <li>if succeed, return 200</li>\n * </ul>\n * <p>\n * will disconnect after execution finishes\n */\npublic class HttpProcessHandler extends SimpleChannelInboundHandler<HttpRequest> {\n\n    private static final ErrorTypeAwareLogger log = LoggerFactory.getErrorTypeAwareLogger(HttpProcessHandler.class);\n    private final CommandExecutor commandExecutor;\n\n    private final QosConfiguration qosConfiguration;\n\n    public HttpProcessHandler(FrameworkModel frameworkModel, QosConfiguration qosConfiguration) {\n        this.commandExecutor = new DefaultCommandExecutor(frameworkModel);\n        this.qosConfiguration = qosConfiguration;\n    }\n\n    private static FullHttpResponse http(int httpCode, String result) {\n        FullHttpResponse response = new DefaultFullHttpResponse(\n                HttpVersion.HTTP_1_1,\n                HttpResponseStatus.valueOf(httpCode),\n                Unpooled.wrappedBuffer(result.getBytes(StandardCharsets.UTF_8)));\n        HttpHeaders httpHeaders = response.headers();\n        httpHeaders.set(HttpHeaderNames.CONTENT_TYPE, \"text/plain; charset=utf-8\");\n        httpHeaders.set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());\n        return response;\n    }\n\n    private static FullHttpResponse http(int httpCode) {\n        FullHttpResponse response =\n                new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(httpCode));\n        HttpHeaders httpHeaders = response.headers();\n        httpHeaders.set(HttpHeaderNames.CONTENT_TYPE, \"text/plain\");\n        httpHeaders.set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());\n        return response;\n    }\n\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception {\n        CommandContext commandContext = HttpCommandDecoder.decode(msg);\n        // return 404 when fail to construct command context\n        if (commandContext == null) {\n            log.warn(QOS_UNEXPECTED_EXCEPTION, \"\", \"\", \"can not found commandContext, url: \" + msg.uri());\n            FullHttpResponse response = http(404);\n            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);\n        } else {\n            commandContext.setRemote(ctx.channel());\n            commandContext.setQosConfiguration(qosConfiguration);\n            try {\n                String result = commandExecutor.execute(commandContext);\n                int httpCode = commandContext.getHttpCode();\n                FullHttpResponse response = http(httpCode, result);\n                ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);\n            } catch (NoSuchCommandException ex) {\n                log.error(QOS_COMMAND_NOT_FOUND, \"\", \"\", \"can not find command: \" + commandContext, ex);\n                FullHttpResponse response = http(404);\n                ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);\n            } catch (PermissionDenyException ex) {\n                log.error(\n                        QOS_PERMISSION_DENY_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"permission deny to access command: \" + commandContext,\n                        ex);\n                FullHttpResponse response = http(403);\n                ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);\n            } catch (Exception qosEx) {\n                log.error(\n                        QOS_UNEXPECTED_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"execute commandContext: \" + commandContext + \" got exception\",\n                        qosEx);\n                FullHttpResponse response = http(500, qosEx.getMessage());\n                ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/QosProcessHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.common.utils.ExecutorUtil;\nimport org.apache.dubbo.qos.api.QosConfiguration;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.handler.codec.ByteToMessageDecoder;\nimport io.netty.handler.codec.LineBasedFrameDecoder;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport io.netty.handler.codec.http.HttpServerCodec;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\nimport io.netty.handler.timeout.IdleStateEvent;\nimport io.netty.handler.timeout.IdleStateHandler;\nimport io.netty.util.CharsetUtil;\nimport io.netty.util.concurrent.ScheduledFuture;\n\npublic class QosProcessHandler extends ByteToMessageDecoder {\n\n    private ScheduledFuture<?> welcomeFuture;\n\n    private final FrameworkModel frameworkModel;\n\n    public static final String PROMPT = \"dubbo>\";\n\n    private final QosConfiguration qosConfiguration;\n\n    public QosProcessHandler(FrameworkModel frameworkModel, QosConfiguration qosConfiguration) {\n        this.frameworkModel = frameworkModel;\n        this.qosConfiguration = qosConfiguration;\n    }\n\n    @Override\n    public void channelActive(final ChannelHandlerContext ctx) throws Exception {\n        welcomeFuture = ctx.executor()\n                .schedule(\n                        () -> {\n                            final String welcome = qosConfiguration.getWelcome();\n                            if (welcome != null) {\n                                ctx.write(Unpooled.wrappedBuffer(welcome.getBytes(StandardCharsets.UTF_8)));\n                                ctx.writeAndFlush(Unpooled.wrappedBuffer(PROMPT.getBytes(StandardCharsets.UTF_8)));\n                            }\n                        },\n                        500,\n                        TimeUnit.MILLISECONDS);\n    }\n\n    @Override\n    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {\n        if (in.readableBytes() < 1) {\n            return;\n        }\n\n        // read one byte to guess protocol\n        final int magic = in.getByte(in.readerIndex());\n\n        ChannelPipeline p = ctx.pipeline();\n        p.addLast(new ForeignHostPermitHandler(qosConfiguration));\n        if (isHttp(magic)) {\n            // no welcome output for http protocol\n            if (welcomeFuture != null && welcomeFuture.isCancellable()) {\n                welcomeFuture.cancel(false);\n            }\n            p.addLast(new HttpServerCodec());\n            p.addLast(new HttpObjectAggregator(1048576));\n            p.addLast(new HttpProcessHandler(frameworkModel, qosConfiguration));\n            p.remove(this);\n        } else {\n            p.addLast(new CtrlCHandler());\n            p.addLast(new LineBasedFrameDecoder(2048));\n            p.addLast(new StringDecoder(CharsetUtil.UTF_8));\n            p.addLast(new StringEncoder(CharsetUtil.UTF_8));\n            p.addLast(new IdleStateHandler(0, 0, 5 * 60));\n            p.addLast(new TelnetIdleEventHandler());\n            p.addLast(new TelnetProcessHandler(frameworkModel, qosConfiguration));\n            p.remove(this);\n        }\n    }\n\n    @Override\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\n        if (evt instanceof IdleStateEvent) {\n            ExecutorUtil.cancelScheduledFuture(welcomeFuture);\n            ctx.close();\n        }\n    }\n\n    // G for GET, and P for POST\n    private static boolean isHttp(int magic) {\n        return magic == 'G' || magic == 'P';\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/TelnetIdleEventHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\n\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelDuplexHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.timeout.IdleStateEvent;\n\npublic class TelnetIdleEventHandler extends ChannelDuplexHandler {\n    private static final Logger log = LoggerFactory.getLogger(TelnetIdleEventHandler.class);\n\n    @Override\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\n        // server will close channel when server don't receive any request from client util timeout.\n        if (evt instanceof IdleStateEvent) {\n            Channel channel = ctx.channel();\n            log.info(\"IdleStateEvent triggered, close channel \" + channel);\n            channel.close();\n        } else {\n            super.userEventTriggered(ctx, evt);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/server/handler/TelnetProcessHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.QosConfiguration;\nimport org.apache.dubbo.qos.command.CommandExecutor;\nimport org.apache.dubbo.qos.command.DefaultCommandExecutor;\nimport org.apache.dubbo.qos.command.decoder.TelnetCommandDecoder;\nimport org.apache.dubbo.qos.command.exception.NoSuchCommandException;\nimport org.apache.dubbo.qos.command.exception.PermissionDenyException;\nimport org.apache.dubbo.qos.common.QosConstants;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_COMMAND_NOT_FOUND;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_PERMISSION_DENY_EXCEPTION;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.QOS_UNEXPECTED_EXCEPTION;\n\n/**\n * Telnet process handler\n */\npublic class TelnetProcessHandler extends SimpleChannelInboundHandler<String> {\n\n    private static final ErrorTypeAwareLogger log = LoggerFactory.getErrorTypeAwareLogger(TelnetProcessHandler.class);\n    private final CommandExecutor commandExecutor;\n\n    private final QosConfiguration qosConfiguration;\n\n    public TelnetProcessHandler(FrameworkModel frameworkModel, QosConfiguration qosConfiguration) {\n        this.commandExecutor = new DefaultCommandExecutor(frameworkModel);\n        this.qosConfiguration = qosConfiguration;\n    }\n\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {\n\n        if (StringUtils.isBlank(msg)) {\n            ctx.writeAndFlush(QosProcessHandler.PROMPT);\n        } else {\n            CommandContext commandContext = TelnetCommandDecoder.decode(msg);\n            commandContext.setQosConfiguration(qosConfiguration);\n            commandContext.setRemote(ctx.channel());\n\n            try {\n                String result = commandExecutor.execute(commandContext);\n                if (StringUtils.isEquals(QosConstants.CLOSE, result)) {\n                    ctx.writeAndFlush(getByeLabel()).addListener(ChannelFutureListener.CLOSE);\n                } else {\n                    ctx.writeAndFlush(result + QosConstants.BR_STR + QosProcessHandler.PROMPT);\n                }\n            } catch (NoSuchCommandException ex) {\n                ctx.writeAndFlush(msg + \" :no such command\");\n                ctx.writeAndFlush(QosConstants.BR_STR + QosProcessHandler.PROMPT);\n                log.error(QOS_COMMAND_NOT_FOUND, \"\", \"\", \"can not found command \" + commandContext, ex);\n            } catch (PermissionDenyException ex) {\n                ctx.writeAndFlush(msg + \" :permission deny\");\n                ctx.writeAndFlush(QosConstants.BR_STR + QosProcessHandler.PROMPT);\n                log.error(\n                        QOS_PERMISSION_DENY_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"permission deny to access command \" + commandContext,\n                        ex);\n            } catch (Exception ex) {\n                ctx.writeAndFlush(msg + \" :fail to execute commandContext by \" + ex.getMessage());\n                ctx.writeAndFlush(QosConstants.BR_STR + QosProcessHandler.PROMPT);\n                log.error(\n                        QOS_UNEXPECTED_EXCEPTION, \"\", \"\", \"execute commandContext got exception \" + commandContext, ex);\n            }\n        }\n    }\n\n    private String getByeLabel() {\n        return \"BYE!\\n\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TComponent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.textui;\n\n/**\n * render component\n */\npublic interface TComponent {\n\n    /**\n     * render\n     */\n    String rendering();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TKv.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.textui;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Scanner;\n\n/**\n * KV\n */\npublic class TKv implements TComponent {\n\n    private final TTable tTable;\n\n    public TKv() {\n        this.tTable = new TTable(new TTable.ColumnDefine[] {\n                    new TTable.ColumnDefine(TTable.Align.RIGHT),\n                    new TTable.ColumnDefine(TTable.Align.RIGHT),\n                    new TTable.ColumnDefine(TTable.Align.LEFT)\n                })\n                .padding(0);\n        this.tTable.getBorder().set(TTable.Border.BORDER_NON);\n    }\n\n    public TKv(TTable.ColumnDefine keyColumnDefine, TTable.ColumnDefine valueColumnDefine) {\n        this.tTable = new TTable(new TTable.ColumnDefine[] {\n                    keyColumnDefine, new TTable.ColumnDefine(TTable.Align.RIGHT), valueColumnDefine\n                })\n                .padding(0);\n        this.tTable.getBorder().set(TTable.Border.BORDER_NON);\n    }\n\n    public TKv add(final Object key, final Object value) {\n        tTable.addRow(key, \" : \", value);\n        return this;\n    }\n\n    @Override\n    public String rendering() {\n        return filterEmptyLine(tTable.rendering());\n    }\n\n    private String filterEmptyLine(String content) {\n        final StringBuilder sb = new StringBuilder();\n        try (Scanner scanner = new Scanner(content)) {\n            while (scanner.hasNextLine()) {\n                String line = scanner.nextLine();\n                if (line != null) {\n                    // remove extra space at line's end\n                    line = StringUtils.stripEnd(line, \" \");\n                    if (line.isEmpty()) {\n                        line = \" \";\n                    }\n                }\n                sb.append(line).append(System.lineSeparator());\n            }\n        }\n\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TLadder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.textui;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport static org.apache.dubbo.common.utils.StringUtils.repeat;\n\n/**\n * Ladder\n */\npublic class TLadder implements TComponent {\n\n    // separator\n    private static final String LADDER_CHAR = \"`-\";\n\n    // tab\n    private static final String STEP_CHAR = \" \";\n\n    // indent length\n    private static final int INDENT_STEP = 2;\n\n    private final List<String> items = new LinkedList<>();\n\n    @Override\n    public String rendering() {\n        final StringBuilder ladderSB = new StringBuilder();\n        int deep = 0;\n        for (String item : items) {\n\n            // no separator is required for the first item\n            if (deep == 0) {\n                ladderSB.append(item).append(System.lineSeparator());\n            }\n\n            // need separator for others\n            else {\n                ladderSB.append(repeat(STEP_CHAR, deep * INDENT_STEP))\n                        .append(LADDER_CHAR)\n                        .append(item)\n                        .append(System.lineSeparator());\n            }\n\n            deep++;\n        }\n        return ladderSB.toString();\n    }\n\n    /**\n     * add one item\n     */\n    public TLadder addItem(String item) {\n        items.add(item);\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TTable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.textui;\n\nimport java.io.StringReader;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Scanner;\n\nimport static java.lang.Math.abs;\nimport static java.lang.Math.max;\nimport static java.lang.String.format;\nimport static org.apache.dubbo.common.utils.StringUtils.EMPTY_STRING;\nimport static org.apache.dubbo.common.utils.StringUtils.length;\nimport static org.apache.dubbo.common.utils.StringUtils.repeat;\nimport static org.apache.dubbo.common.utils.StringUtils.replace;\n\n/**\n * Table\n */\npublic class TTable implements TComponent {\n\n    // column definition\n    private final ColumnDefine[] columnDefineArray;\n\n    // border\n    private final Border border = new Border();\n\n    // padding\n    private int padding;\n\n    public TTable(ColumnDefine[] columnDefineArray) {\n        this.columnDefineArray = null == columnDefineArray ? new ColumnDefine[0] : columnDefineArray;\n    }\n\n    public TTable(int columnNum) {\n        this.columnDefineArray = new ColumnDefine[columnNum];\n        for (int index = 0; index < this.columnDefineArray.length; index++) {\n            columnDefineArray[index] = new ColumnDefine();\n        }\n    }\n\n    @Override\n    public String rendering() {\n        final StringBuilder tableSB = new StringBuilder();\n\n        // process width cache\n        final int[] widthCacheArray = new int[getColumnCount()];\n        for (int index = 0; index < widthCacheArray.length; index++) {\n            widthCacheArray[index] = abs(columnDefineArray[index].getWidth());\n        }\n\n        final int rowCount = getRowCount();\n        for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {\n\n            final boolean isFirstRow = rowIndex == 0;\n            final boolean isLastRow = rowIndex == rowCount - 1;\n\n            // print first separation line\n            if (isFirstRow && border.has(Border.BORDER_OUTER_TOP)) {\n                tableSB.append(drawSeparationLine(widthCacheArray)).append(System.lineSeparator());\n            }\n\n            // print inner separation lines\n            if (!isFirstRow && border.has(Border.BORDER_INNER_H)) {\n                tableSB.append(drawSeparationLine(widthCacheArray)).append(System.lineSeparator());\n            }\n\n            // draw one line\n            tableSB.append(drawRow(widthCacheArray, rowIndex));\n\n            // print ending separation line\n            if (isLastRow && border.has(Border.BORDER_OUTER_BOTTOM)) {\n                tableSB.append(drawSeparationLine(widthCacheArray)).append(System.lineSeparator());\n            }\n        }\n\n        return tableSB.toString();\n    }\n\n    private String drawRow(int[] widthCacheArray, int rowIndex) {\n\n        final StringBuilder rowSB = new StringBuilder();\n        final Scanner[] scannerArray = new Scanner[getColumnCount()];\n        try {\n            boolean hasNextLine;\n            do {\n\n                hasNextLine = false;\n                final StringBuilder segmentSB = new StringBuilder();\n\n                for (int colIndex = 0; colIndex < getColumnCount(); colIndex++) {\n\n                    final int width = widthCacheArray[colIndex];\n                    final boolean isFirstColOfRow = colIndex == 0;\n                    final boolean isLastColOfRow = colIndex == widthCacheArray.length - 1;\n\n                    final String borderChar;\n                    if (isFirstColOfRow && border.has(Border.BORDER_OUTER_LEFT)) {\n                        borderChar = \"|\";\n                    } else if (!isFirstColOfRow && border.has(Border.BORDER_INNER_V)) {\n                        borderChar = \"|\";\n                    } else {\n                        borderChar = EMPTY_STRING;\n                    }\n\n                    if (null == scannerArray[colIndex]) {\n                        scannerArray[colIndex] = new Scanner(\n                                new StringReader(wrap(getData(rowIndex, columnDefineArray[colIndex]), width)));\n                    }\n                    final Scanner scanner = scannerArray[colIndex];\n\n                    final String data;\n                    if (scanner.hasNextLine()) {\n                        data = scanner.nextLine();\n                        hasNextLine = true;\n                    } else {\n                        data = EMPTY_STRING;\n                    }\n\n                    if (width > 0) {\n                        final ColumnDefine columnDefine = columnDefineArray[colIndex];\n                        final String dataFormat = getDataFormat(columnDefine, width, data);\n                        final String paddingChar = repeat(\" \", padding);\n                        segmentSB.append(format(borderChar + paddingChar + dataFormat + paddingChar, data));\n                    }\n\n                    if (isLastColOfRow) {\n                        if (border.has(Border.BORDER_OUTER_RIGHT)) {\n                            segmentSB.append('|');\n                        }\n                        segmentSB.append(System.lineSeparator());\n                    }\n                }\n\n                if (hasNextLine) {\n                    rowSB.append(segmentSB);\n                }\n\n            } while (hasNextLine);\n\n            return rowSB.toString();\n        } finally {\n            for (Scanner scanner : scannerArray) {\n                if (null != scanner) {\n                    scanner.close();\n                }\n            }\n        }\n    }\n\n    private String getData(int rowIndex, ColumnDefine columnDefine) {\n        return columnDefine.getRowCount() <= rowIndex ? EMPTY_STRING : columnDefine.rows.get(rowIndex);\n    }\n\n    private String getDataFormat(ColumnDefine columnDefine, int width, String data) {\n        switch (columnDefine.align) {\n            case MIDDLE: {\n                final int length = length(data);\n                final int diff = width - length;\n                final int left = diff / 2;\n                return repeat(\" \", diff - left) + \"%s\" + repeat(\" \", left);\n            }\n            case RIGHT: {\n                return \"%\" + width + \"s\";\n            }\n            case LEFT:\n            default: {\n                return \"%-\" + width + \"s\";\n            }\n        }\n    }\n\n    /**\n     * get row count\n     */\n    private int getRowCount() {\n        int rowCount = 0;\n        for (ColumnDefine columnDefine : columnDefineArray) {\n            rowCount = max(rowCount, columnDefine.getRowCount());\n        }\n        return rowCount;\n    }\n\n    /**\n     * position to last column\n     */\n    private int indexLastCol(final int[] widthCacheArray) {\n        for (int colIndex = widthCacheArray.length - 1; colIndex >= 0; colIndex--) {\n            final int width = widthCacheArray[colIndex];\n            if (width <= 0) {\n                continue;\n            }\n            return colIndex;\n        }\n        return 0;\n    }\n\n    /**\n     * draw separation line\n     */\n    private String drawSeparationLine(final int[] widthCacheArray) {\n        final StringBuilder separationLineSB = new StringBuilder();\n\n        final int lastCol = indexLastCol(widthCacheArray);\n        final int colCount = widthCacheArray.length;\n        for (int colIndex = 0; colIndex < colCount; colIndex++) {\n            final int width = widthCacheArray[colIndex];\n            if (width <= 0) {\n                continue;\n            }\n\n            final boolean isFirstCol = colIndex == 0;\n            final boolean isLastCol = colIndex == lastCol;\n\n            if (isFirstCol && border.has(Border.BORDER_OUTER_LEFT)) {\n                separationLineSB.append('+');\n            }\n\n            if (!isFirstCol && border.has(Border.BORDER_INNER_V)) {\n                separationLineSB.append('+');\n            }\n\n            separationLineSB.append(repeat(\"-\", width + 2 * padding));\n\n            if (isLastCol && border.has(Border.BORDER_OUTER_RIGHT)) {\n                separationLineSB.append('+');\n            }\n        }\n        return separationLineSB.toString();\n    }\n\n    /**\n     * Add a row\n     */\n    public TTable addRow(Object... columnDataArray) {\n\n        if (null != columnDataArray) {\n            for (int index = 0; index < columnDefineArray.length; index++) {\n                final ColumnDefine columnDefine = columnDefineArray[index];\n                if (index < columnDataArray.length && null != columnDataArray[index]) {\n                    columnDefine.rows.add(replaceTab(columnDataArray[index].toString()));\n                } else {\n                    columnDefine.rows.add(EMPTY_STRING);\n                }\n            }\n        }\n\n        return this;\n    }\n\n    /**\n     * alignment\n     */\n    public enum Align {\n\n        /**\n         * left-alignment\n         */\n        LEFT,\n\n        /**\n         * right-alignment\n         */\n        RIGHT,\n\n        /**\n         * middle-alignment\n         */\n        MIDDLE\n    }\n\n    /**\n     * column definition\n     */\n    public static class ColumnDefine {\n\n        // column width\n        private final int width;\n\n        // whether to auto resize\n        private final boolean isAutoResize;\n\n        // alignment\n        private final Align align;\n\n        // data rows\n        private final List<String> rows = new ArrayList<>();\n\n        public ColumnDefine(int width, boolean isAutoResize, Align align) {\n            this.width = width;\n            this.isAutoResize = isAutoResize;\n            this.align = align;\n        }\n\n        public ColumnDefine(Align align) {\n            this(0, true, align);\n        }\n\n        public ColumnDefine(int width) {\n            this(width, false, Align.LEFT);\n        }\n\n        public ColumnDefine(int width, Align align) {\n            this(width, false, align);\n        }\n\n        public ColumnDefine() {\n            this(Align.LEFT);\n        }\n\n        /**\n         * get current width\n         *\n         * @return width\n         */\n        public int getWidth() {\n\n            // if not auto resize, return preset width\n            if (!isAutoResize) {\n                return width;\n            }\n\n            // if it's auto resize, then calculate the possible max width\n            int maxWidth = 0;\n            for (String data : rows) {\n                maxWidth = max(width(data), maxWidth);\n            }\n\n            return maxWidth;\n        }\n\n        /**\n         * get rows for the current column\n         *\n         * @return current column's rows\n         */\n        public int getRowCount() {\n            return rows.size();\n        }\n    }\n\n    /**\n     * set padding\n     *\n     * @param padding padding\n     */\n    public TTable padding(int padding) {\n        this.padding = padding;\n        return this;\n    }\n\n    /**\n     * get column count\n     *\n     * @return column count\n     */\n    public int getColumnCount() {\n        return columnDefineArray.length;\n    }\n\n    /**\n     * replace tab to four spaces\n     *\n     * @param string the original string\n     * @return the replaced string\n     */\n    private static String replaceTab(String string) {\n        return replace(string, \"\\t\", \"    \");\n    }\n\n    /**\n     * visible width for the given string.\n     *\n     * for example: \"abc\\n1234\"'s width is 4.\n     *\n     * @param string the given string\n     * @return visible width\n     */\n    private static int width(String string) {\n        int maxWidth = 0;\n        try (Scanner scanner = new Scanner(new StringReader(string))) {\n            while (scanner.hasNextLine()) {\n                maxWidth = max(length(scanner.nextLine()), maxWidth);\n            }\n        }\n        return maxWidth;\n    }\n\n    /**\n     * get border\n     *\n     * @return table border\n     */\n    public Border getBorder() {\n        return border;\n    }\n\n    /**\n     * border style\n     */\n    public class Border {\n\n        private int borders = BORDER_OUTER | BORDER_INNER;\n\n        /**\n         * border outer top\n         */\n        public static final int BORDER_OUTER_TOP = 1 << 0;\n\n        /**\n         * border outer right\n         */\n        public static final int BORDER_OUTER_RIGHT = 1 << 1;\n\n        /**\n         * border outer bottom\n         */\n        public static final int BORDER_OUTER_BOTTOM = 1 << 2;\n\n        /**\n         * border outer left\n         */\n        public static final int BORDER_OUTER_LEFT = 1 << 3;\n\n        /**\n         * inner border: horizon\n         */\n        public static final int BORDER_INNER_H = 1 << 4;\n\n        /**\n         * inner border: vertical\n         */\n        public static final int BORDER_INNER_V = 1 << 5;\n\n        /**\n         * outer border\n         */\n        public static final int BORDER_OUTER =\n                BORDER_OUTER_TOP | BORDER_OUTER_BOTTOM | BORDER_OUTER_LEFT | BORDER_OUTER_RIGHT;\n\n        /**\n         * inner border\n         */\n        public static final int BORDER_INNER = BORDER_INNER_H | BORDER_INNER_V;\n\n        /**\n         * no border\n         */\n        public static final int BORDER_NON = 0;\n\n        /**\n         * whether has one of the specified border styles\n         *\n         * @param borderArray border styles\n         * @return whether has one of the specified border styles\n         */\n        public boolean has(int... borderArray) {\n            if (null == borderArray) {\n                return false;\n            }\n            for (int b : borderArray) {\n                if ((this.borders & b) == b) {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        /**\n         * get border style\n         *\n         * @return border style\n         */\n        public int get() {\n            return borders;\n        }\n\n        /**\n         * set border style\n         *\n         * @param border border style\n         * @return this\n         */\n        public Border set(int border) {\n            this.borders = border;\n            return this;\n        }\n\n        public Border add(int border) {\n            return set(get() | border);\n        }\n\n        public Border remove(int border) {\n            return set(get() ^ border);\n        }\n    }\n\n    public static String wrap(String string, int width) {\n        final StringBuilder sb = new StringBuilder();\n        final char[] buffer = string.toCharArray();\n        int count = 0;\n        for (char c : buffer) {\n\n            if (count == width) {\n                count = 0;\n                sb.append('\\n');\n                if (c == '\\n') {\n                    continue;\n                }\n            }\n\n            if (c == '\\n') {\n                count = 0;\n            } else {\n                count++;\n            }\n\n            sb.append(c);\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TTree.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.textui;\n\nimport java.io.StringReader;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Scanner;\n\nimport static java.lang.System.currentTimeMillis;\nimport static org.apache.dubbo.common.utils.StringUtils.EMPTY_STRING;\nimport static org.apache.dubbo.common.utils.StringUtils.length;\nimport static org.apache.dubbo.common.utils.StringUtils.repeat;\n\n/**\n * tree\n */\npublic class TTree implements TComponent {\n\n    private static final String STEP_FIRST_CHAR = \"`---\";\n    private static final String STEP_NORMAL_CHAR = \"+---\";\n    private static final String STEP_HAS_BOARD = \"|   \";\n    private static final String STEP_EMPTY_BOARD = \"    \";\n\n    // should output cost or not\n    private final boolean isPrintCost;\n\n    // tree node\n    private final Node root;\n\n    // current node\n    private Node current;\n\n    public TTree(boolean isPrintCost, String title) {\n        this.root = new Node(title).markBegin().markEnd();\n        this.current = root;\n        this.isPrintCost = isPrintCost;\n    }\n\n    @Override\n    public String rendering() {\n\n        final StringBuilder treeSB = new StringBuilder();\n        recursive(0, true, \"\", root, new Callback() {\n\n            @Override\n            public void callback(int deep, boolean isLast, String prefix, Node node) {\n\n                final boolean hasChild = !node.children.isEmpty();\n                final String stepString = isLast ? STEP_FIRST_CHAR : STEP_NORMAL_CHAR;\n                final int stepStringLength = length(stepString);\n                treeSB.append(prefix).append(stepString);\n\n                int costPrefixLength = 0;\n                if (hasChild) {\n                    treeSB.append('+');\n                }\n                if (isPrintCost && !node.isRoot()) {\n                    final String costPrefix = String.format(\n                            \"[%s,%sms]\",\n                            (node.endTimestamp - root.beginTimestamp), (node.endTimestamp - node.beginTimestamp));\n                    costPrefixLength = length(costPrefix);\n                    treeSB.append(costPrefix);\n                }\n\n                try (Scanner scanner = new Scanner(new StringReader(node.data.toString()))) {\n                    boolean isFirst = true;\n                    while (scanner.hasNextLine()) {\n                        if (isFirst) {\n                            treeSB.append(scanner.nextLine()).append('\\n');\n                            isFirst = false;\n                        } else {\n                            treeSB.append(prefix)\n                                    .append(repeat(' ', stepStringLength))\n                                    .append(hasChild ? \"|\" : EMPTY_STRING)\n                                    .append(repeat(' ', costPrefixLength))\n                                    .append(scanner.nextLine())\n                                    .append(System.lineSeparator());\n                        }\n                    }\n                }\n            }\n        });\n\n        return treeSB.toString();\n    }\n\n    /**\n     * recursive visit\n     */\n    private void recursive(int deep, boolean isLast, String prefix, Node node, Callback callback) {\n        callback.callback(deep, isLast, prefix, node);\n        if (!node.isLeaf()) {\n            final int size = node.children.size();\n            for (int index = 0; index < size; index++) {\n                final boolean isLastFlag = index == size - 1;\n                final String currentPrefix = isLast ? prefix + STEP_EMPTY_BOARD : prefix + STEP_HAS_BOARD;\n                recursive(deep + 1, isLastFlag, currentPrefix, node.children.get(index), callback);\n            }\n        }\n    }\n\n    public boolean isTop() {\n        return current.isRoot();\n    }\n\n    /**\n     * create a branch node\n     *\n     * @param data node data\n     * @return this\n     */\n    public TTree begin(Object data) {\n        current = new Node(current, data);\n        current.markBegin();\n        return this;\n    }\n\n    public TTree begin() {\n        return begin(null);\n    }\n\n    public Object get() {\n        if (current.isRoot()) {\n            throw new IllegalStateException(\"current node is root.\");\n        }\n        return current.data;\n    }\n\n    public TTree set(Object data) {\n        if (current.isRoot()) {\n            throw new IllegalStateException(\"current node is root.\");\n        }\n        current.data = data;\n        return this;\n    }\n\n    /**\n     * end a branch node\n     *\n     * @return this\n     */\n    public TTree end() {\n        if (current.isRoot()) {\n            throw new IllegalStateException(\"current node is root.\");\n        }\n        current.markEnd();\n        current = current.parent;\n        return this;\n    }\n\n    /**\n     * tree node\n     */\n    private static class Node {\n\n        /**\n         * parent node\n         */\n        final Node parent;\n\n        /**\n         * node data\n         */\n        Object data;\n\n        /**\n         * child nodes\n         */\n        final List<Node> children = new ArrayList<>();\n\n        /**\n         * begin timestamp\n         */\n        private long beginTimestamp;\n\n        /**\n         * end timestamp\n         */\n        private long endTimestamp;\n\n        /**\n         * construct root node\n         */\n        private Node(Object data) {\n            this.parent = null;\n            this.data = data;\n        }\n\n        /**\n         * construct a regular node\n         *\n         * @param parent parent node\n         * @param data   node data\n         */\n        private Node(Node parent, Object data) {\n            this.parent = parent;\n            this.data = data;\n            parent.children.add(this);\n        }\n\n        /**\n         * is the current node the root node\n         *\n         * @return true / false\n         */\n        boolean isRoot() {\n            return null == parent;\n        }\n\n        /**\n         * if the current node the leaf node\n         *\n         * @return true / false\n         */\n        boolean isLeaf() {\n            return children.isEmpty();\n        }\n\n        Node markBegin() {\n            beginTimestamp = currentTimeMillis();\n            return this;\n        }\n\n        Node markEnd() {\n            endTimestamp = currentTimeMillis();\n            return this;\n        }\n    }\n\n    /**\n     * callback interface for recursive visit\n     */\n    private interface Callback {\n\n        void callback(int deep, boolean isLast, String prefix, Node node);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar",
    "content": "qos=org.apache.dubbo.qos.aot.QosReflectionTypeDescriberRegistrar\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand",
    "content": "online=org.apache.dubbo.qos.command.impl.Online\nonlineApp=org.apache.dubbo.qos.command.impl.OnlineApp\nonlineInterface=org.apache.dubbo.qos.command.impl.OnlineInterface\nhelp=org.apache.dubbo.qos.command.impl.Help\nquit=org.apache.dubbo.qos.command.impl.Quit\nls=org.apache.dubbo.qos.command.impl.Ls\noffline=org.apache.dubbo.qos.command.impl.Offline\nofflineApp=org.apache.dubbo.qos.command.impl.OfflineApp\nofflineInterface=org.apache.dubbo.qos.command.impl.OfflineInterface\nready=org.apache.dubbo.qos.command.impl.Ready\nstartup=org.apache.dubbo.qos.command.impl.Startup\nlive=org.apache.dubbo.qos.command.impl.Live\nversion=org.apache.dubbo.qos.command.impl.Version\npublishMetadata=org.apache.dubbo.qos.command.impl.PublishMetadata\ncd=org.apache.dubbo.qos.command.impl.ChangeTelnet\ncount=org.apache.dubbo.qos.command.impl.CountTelnet\npwd=org.apache.dubbo.qos.command.impl.PwdTelnet\ninvoke=org.apache.dubbo.qos.command.impl.InvokeTelnet\nselect=org.apache.dubbo.qos.command.impl.SelectTelnet\nps=org.apache.dubbo.qos.command.impl.PortTelnet\nshutdown=org.apache.dubbo.qos.command.impl.ShutdownTelnet\nenableDetailProfiler=org.apache.dubbo.qos.command.impl.EnableDetailProfiler\ndisableDetailProfiler=org.apache.dubbo.qos.command.impl.DisableDetailProfiler\nenableSimpleProfiler=org.apache.dubbo.qos.command.impl.EnableSimpleProfiler\ndisableSimpleProfiler=org.apache.dubbo.qos.command.impl.DisableSimpleProfiler\nsetProfilerWarnPercent=org.apache.dubbo.qos.command.impl.SetProfilerWarnPercent\ngetRouterSnapshot=org.apache.dubbo.qos.command.impl.GetRouterSnapshot\ngetEnabledRouterSnapshot=org.apache.dubbo.qos.command.impl.GetEnabledRouterSnapshot\nenableRouterSnapshot=org.apache.dubbo.qos.command.impl.EnableRouterSnapshot\ndisableRouterSnapshot=org.apache.dubbo.qos.command.impl.DisableRouterSnapshot\ngetRecentRouterSnapshot=org.apache.dubbo.qos.command.impl.GetRecentRouterSnapshot\nloggerInfo=org.apache.dubbo.qos.command.impl.LoggerInfo\nswitchLogger=org.apache.dubbo.qos.command.impl.SwitchLogger\nswitchLogLevel=org.apache.dubbo.qos.command.impl.SwitchLogLevel\nserializeCheckStatus=org.apache.dubbo.qos.command.impl.SerializeCheckStatus\nserializeWarnedClasses=org.apache.dubbo.qos.command.impl.SerializeWarnedClasses\ngetConfig=org.apache.dubbo.qos.command.impl.GetConfig\ngetAddress=org.apache.dubbo.qos.command.impl.GetAddress\ngracefulShutdown=org.apache.dubbo.qos.command.impl.GracefulShutdown\nmetrics_default=org.apache.dubbo.qos.command.impl.DefaultMetricsReporterCmd\ngetOpenAPI=org.apache.dubbo.qos.command.impl.GetOpenAPI\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.probe.ReadinessProbe",
    "content": "deployer = org.apache.dubbo.qos.probe.impl.DeployerReadinessProbe\nprovider = org.apache.dubbo.qos.probe.impl.ProviderReadinessProbe\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.probe.StartupProbe",
    "content": "bootstrap = org.apache.dubbo.qos.probe.impl.DeployerStartupProbe\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler",
    "content": "trace=org.apache.dubbo.qos.legacy.TraceTelnetHandler\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol",
    "content": "qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "qos=org.apache.dubbo.qos.QosScopeModelInitializer\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos;\n\npublic interface DemoService {\n\n    String echo(String str);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos;\n\npublic class DemoServiceImpl implements DemoService {\n\n    @Override\n    public String echo(String str) {\n        return \"hello world\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/CommandContextFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command;\n\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass CommandContextFactoryTest {\n    @Test\n    void testNewInstance() {\n        CommandContext context = CommandContextFactory.newInstance(\"test\");\n        assertThat(context.getCommandName(), equalTo(\"test\"));\n        context = CommandContextFactory.newInstance(\"command\", new String[] {\"hello\"}, true);\n        assertThat(context.getCommandName(), equalTo(\"command\"));\n        assertThat(context.getArgs(), Matchers.arrayContaining(\"hello\"));\n        assertTrue(context.isHttp());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/CommandContextTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command;\n\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport io.netty.channel.Channel;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.arrayContaining;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass CommandContextTest {\n    @Test\n    void test() {\n        CommandContext context = new CommandContext(\"test\", new String[] {\"hello\"}, true);\n        Object request = new Object();\n        context.setOriginRequest(request);\n        Channel channel = Mockito.mock(Channel.class);\n        context.setRemote(channel);\n        assertThat(context.getCommandName(), equalTo(\"test\"));\n        assertThat(context.getArgs(), arrayContaining(\"hello\"));\n        assertThat(context.getOriginRequest(), is(request));\n        assertTrue(context.isHttp());\n        assertThat(context.getRemote(), is(channel));\n\n        context = new CommandContext(\"command\");\n        context.setRemote(channel);\n        context.setOriginRequest(request);\n        context.setArgs(new String[] {\"world\"});\n        context.setHttp(false);\n        assertThat(context.getCommandName(), equalTo(\"command\"));\n        assertThat(context.getArgs(), arrayContaining(\"world\"));\n        assertThat(context.getOriginRequest(), is(request));\n        assertFalse(context.isHttp());\n        assertThat(context.getRemote(), is(channel));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/DefaultCommandExecutorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command;\n\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.api.QosConfiguration;\nimport org.apache.dubbo.qos.command.exception.NoSuchCommandException;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass DefaultCommandExecutorTest {\n    @Test\n    void testExecute1() {\n        Assertions.assertThrows(NoSuchCommandException.class, () -> {\n            DefaultCommandExecutor executor = new DefaultCommandExecutor(FrameworkModel.defaultModel());\n            executor.execute(CommandContextFactory.newInstance(\"not-exit\"));\n        });\n    }\n\n    @Test\n    void testExecute2() throws Exception {\n        DefaultCommandExecutor executor = new DefaultCommandExecutor(FrameworkModel.defaultModel());\n        final CommandContext commandContext =\n                CommandContextFactory.newInstance(\"greeting\", new String[] {\"dubbo\"}, false);\n        commandContext.setQosConfiguration(QosConfiguration.builder()\n                .anonymousAccessPermissionLevel(PermissionLevel.PROTECTED.name())\n                .build());\n        String result = executor.execute(commandContext);\n        assertThat(result, equalTo(\"greeting dubbo\"));\n    }\n\n    @Test\n    void shouldNotThrowPermissionDenyException_GivenPermissionConfigAndMatchDefaultPUBLICCmdPermissionLevel() {\n        DefaultCommandExecutor executor = new DefaultCommandExecutor(FrameworkModel.defaultModel());\n        final CommandContext commandContext = CommandContextFactory.newInstance(\"live\", new String[] {\"dubbo\"}, false);\n        commandContext.setQosConfiguration(QosConfiguration.builder().build());\n        Assertions.assertDoesNotThrow(() -> executor.execute(commandContext));\n    }\n\n    @Test\n    void shouldNotThrowPermissionDenyException_GivenPermissionConfigAndNotMatchCmdPermissionLevel() {\n        DefaultCommandExecutor executor = new DefaultCommandExecutor(FrameworkModel.defaultModel());\n        final CommandContext commandContext = CommandContextFactory.newInstance(\"live\", new String[] {\"dubbo\"}, false);\n        // 1 PROTECTED\n        commandContext.setQosConfiguration(\n                QosConfiguration.builder().anonymousAccessPermissionLevel(\"1\").build());\n        Assertions.assertDoesNotThrow(() -> executor.execute(commandContext));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/GreetingCommand.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command;\n\nimport org.apache.dubbo.common.utils.ArrayUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.Cmd;\nimport org.apache.dubbo.qos.api.CommandContext;\n\n@Cmd(\n        name = \"greeting\",\n        summary = \"greeting message\",\n        example = {\n            \"greeting dubbo\",\n        })\npublic class GreetingCommand implements BaseCommand {\n    @Override\n    public String execute(CommandContext commandContext, String[] args) {\n        return ArrayUtils.isNotEmpty(args) ? \"greeting \" + args[0] : \"greeting\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/decoder/HttpCommandDecoderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.decoder;\n\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport java.nio.charset.StandardCharsets;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpHeaders;\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpRequest;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.arrayContaining;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass HttpCommandDecoderTest {\n    @Test\n    void decodeGet() {\n        HttpRequest request = mock(HttpRequest.class);\n        when(request.uri()).thenReturn(\"localhost:80/test\");\n        when(request.method()).thenReturn(HttpMethod.GET);\n        CommandContext context = HttpCommandDecoder.decode(request);\n        assertThat(context.getCommandName(), equalTo(\"test\"));\n        assertThat(context.isHttp(), is(true));\n        when(request.uri()).thenReturn(\"localhost:80/test?a=b&c=d\");\n        context = HttpCommandDecoder.decode(request);\n        assertThat(context.getArgs(), arrayContaining(\"b\", \"d\"));\n    }\n\n    @Test\n    void decodePost() {\n        FullHttpRequest request = mock(FullHttpRequest.class);\n        when(request.uri()).thenReturn(\"localhost:80/test\");\n        when(request.method()).thenReturn(HttpMethod.POST);\n        when(request.headers()).thenReturn(HttpHeaders.EMPTY_HEADERS);\n        ByteBuf buf = Unpooled.copiedBuffer(\"a=b&c=d\", StandardCharsets.UTF_8);\n        when(request.content()).thenReturn(buf);\n        CommandContext context = HttpCommandDecoder.decode(request);\n        assertThat(context.getCommandName(), equalTo(\"test\"));\n        assertThat(context.isHttp(), is(true));\n        assertThat(context.getArgs(), arrayContaining(\"b\", \"d\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/decoder/TelnetCommandDecoderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.decoder;\n\nimport org.apache.dubbo.qos.api.CommandContext;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.arrayContaining;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.is;\n\nclass TelnetCommandDecoderTest {\n    @Test\n    void testDecode() throws Exception {\n        CommandContext context = TelnetCommandDecoder.decode(\"test a b\");\n        assertThat(context.getCommandName(), equalTo(\"test\"));\n        assertThat(context.isHttp(), is(false));\n        assertThat(context.getArgs(), arrayContaining(\"a\", \"b\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/ChangeTelnetTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.legacy.service.DemoService;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\n\nimport io.netty.channel.Channel;\nimport io.netty.util.DefaultAttributeMap;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\nclass ChangeTelnetTest {\n    private final DefaultAttributeMap defaultAttributeMap = new DefaultAttributeMap();\n    private BaseCommand change;\n\n    private Channel mockChannel;\n    private CommandContext mockCommandContext;\n    private Invoker<DemoService> mockInvoker;\n\n    @AfterAll\n    public static void tearDown() {\n        FrameworkModel.destroyAll();\n    }\n\n    @BeforeAll\n    public static void setUp() {\n        FrameworkModel.destroyAll();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @BeforeEach\n    public void beforeEach() {\n        change = new ChangeTelnet(FrameworkModel.defaultModel());\n\n        mockCommandContext = mock(CommandContext.class);\n        mockChannel = mock(Channel.class);\n        mockInvoker = mock(Invoker.class);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        mockChannel.attr(ChangeTelnet.SERVICE_KEY).set(\"org.apache.dubbo.rpc.protocol.dubbo.support.DemoService\");\n        given(mockCommandContext.getRemote()).willReturn(mockChannel);\n        given(mockInvoker.getInterface()).willReturn(DemoService.class);\n        given(mockInvoker.getUrl()).willReturn(URL.valueOf(\"dubbo://127.0.0.1:20884/demo?group=g&version=1.0.0\"));\n    }\n\n    @AfterEach\n    public void afterEach() {\n        FrameworkModel.destroyAll();\n        reset(mockCommandContext, mockChannel, mockInvoker);\n    }\n\n    @Test\n    void testChangeSimpleName() {\n        ExtensionLoader.getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n        String result = change.execute(mockCommandContext, new String[] {\"DemoService\"});\n        assertEquals(\"Used the DemoService as default.\\r\\nYou can cancel default service by command: cd /\", result);\n    }\n\n    @Test\n    void testChangeName() {\n        ExtensionLoader.getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n        String result =\n                change.execute(mockCommandContext, new String[] {\"org.apache.dubbo.qos.legacy.service.DemoService\"});\n        assertEquals(\n                \"Used the org.apache.dubbo.qos.legacy.service.DemoService as default.\\r\\nYou can cancel default service by command: cd /\",\n                result);\n    }\n\n    @Test\n    void testChangePath() {\n        ExtensionLoader.getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n        String result = change.execute(mockCommandContext, new String[] {\"demo\"});\n        assertEquals(\"Used the demo as default.\\r\\nYou can cancel default service by command: cd /\", result);\n    }\n\n    @Test\n    void testChangeServiceKey() {\n        ExtensionLoader.getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n        String result = change.execute(mockCommandContext, new String[] {\"g/demo:1.0.0\"});\n        assertEquals(\"Used the g/demo:1.0.0 as default.\\r\\nYou can cancel default service by command: cd /\", result);\n    }\n\n    @Test\n    void testChangeMessageNull() {\n        String result = change.execute(mockCommandContext, null);\n        assertEquals(\"Please input service name, eg: \\r\\ncd XxxService\\r\\ncd com.xxx.XxxService\", result);\n    }\n\n    @Test\n    void testChangeServiceNotExport() {\n        String result = change.execute(mockCommandContext, new String[] {\"demo\"});\n        assertEquals(\"No such service demo\", result);\n    }\n\n    @Test\n    void testChangeCancel() {\n        String result = change.execute(mockCommandContext, new String[] {\"..\"});\n        assertEquals(\"Cancelled default service org.apache.dubbo.rpc.protocol.dubbo.support.DemoService.\", result);\n    }\n\n    @Test\n    void testChangeCancel2() {\n        String result = change.execute(mockCommandContext, new String[] {\"/\"});\n        assertEquals(\"Cancelled default service org.apache.dubbo.rpc.protocol.dubbo.support.DemoService.\", result);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/CountTelnetTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.command.impl.channel.MockNettyChannel;\nimport org.apache.dubbo.qos.legacy.service.DemoService;\nimport org.apache.dubbo.remoting.telnet.support.TelnetUtils;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.RpcStatus;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.containsString;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\nclass CountTelnetTest {\n    private BaseCommand count;\n\n    private MockNettyChannel mockChannel;\n    private Invoker<DemoService> mockInvoker;\n\n    private CommandContext mockCommandContext;\n\n    private CountDownLatch latch;\n    private final URL url = URL.valueOf(\"dubbo://127.0.0.1:20884/demo?group=g&version=1.0.0\");\n\n    @BeforeEach\n    public void setUp() {\n        count = new CountTelnet(FrameworkModel.defaultModel());\n        latch = new CountDownLatch(2);\n        mockInvoker = mock(Invoker.class);\n        mockCommandContext = mock(CommandContext.class);\n        mockChannel = new MockNettyChannel(url, latch);\n        given(mockCommandContext.getRemote()).willReturn(mockChannel);\n        given(mockInvoker.getInterface()).willReturn(DemoService.class);\n        given(mockInvoker.getUrl()).willReturn(url);\n    }\n\n    @AfterEach\n    public void tearDown() {\n        FrameworkModel.destroyAll();\n        mockChannel.close();\n        RpcStatus.removeStatus(url);\n        reset(mockInvoker, mockCommandContext);\n    }\n\n    @Test\n    void test() throws Exception {\n        String methodName = \"sayHello\";\n        RpcStatus.removeStatus(url, methodName);\n        String[] args = new String[] {\"org.apache.dubbo.qos.legacy.service.DemoService\", \"sayHello\", \"1\"};\n\n        ExtensionLoader.getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n        RpcStatus.beginCount(url, methodName);\n        RpcStatus.endCount(url, methodName, 10L, true);\n        count.execute(mockCommandContext, args);\n        latch.await();\n\n        StringBuilder sb = new StringBuilder();\n        for (Object o : mockChannel.getReceivedObjects()) {\n            sb.append(o.toString());\n        }\n\n        assertThat(sb.toString(), containsString(buildTable(methodName, 10, 10, \"1\", \"0\", \"0\")));\n    }\n\n    @Test\n    void testCountByServiceKey() throws Exception {\n        String methodName = \"sayHello\";\n        RpcStatus.removeStatus(url, methodName);\n        String[] args = new String[] {\"g/demo:1.0.0\", \"sayHello\", \"1\"};\n\n        ExtensionLoader.getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n        RpcStatus.beginCount(url, methodName);\n        RpcStatus.endCount(url, methodName, 10L, true);\n        count.execute(mockCommandContext, args);\n        latch.await();\n\n        StringBuilder sb = new StringBuilder();\n        for (Object o : mockChannel.getReceivedObjects()) {\n            sb.append(o.toString());\n        }\n\n        assertThat(sb.toString(), containsString(buildTable(methodName, 10, 10, \"1\", \"0\", \"0\")));\n    }\n\n    public static String buildTable(\n            String methodName, long averageElapsed, long maxElapsed, String total, String failed, String active) {\n        List<String> header = new LinkedList<>();\n        header.add(\"method\");\n        header.add(\"total\");\n        header.add(\"failed\");\n        header.add(\"active\");\n        header.add(\"average\");\n        header.add(\"max\");\n\n        List<List<String>> table = new LinkedList<>();\n        List<String> row = new LinkedList<String>();\n        row.add(methodName);\n        row.add(total);\n        row.add(failed);\n        row.add(active);\n        row.add(averageElapsed + \"ms\");\n        row.add(maxElapsed + \"ms\");\n\n        table.add(row);\n\n        return TelnetUtils.toTable(header, table);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/GetConfigTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ConfigCenterConfig;\nimport org.apache.dubbo.config.ConsumerConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.MetricsConfig;\nimport org.apache.dubbo.config.ModuleConfig;\nimport org.apache.dubbo.config.MonitorConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ProviderConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass GetConfigTest {\n    @Test\n    void testAll() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel1 = frameworkModel.newApplication();\n\n        applicationModel1.getApplicationConfigManager().setApplication(new ApplicationConfig(\"app1\"));\n        applicationModel1.getApplicationConfigManager().addProtocol(new ProtocolConfig(\"dubbo\", 12345));\n        applicationModel1.getApplicationConfigManager().addRegistry(new RegistryConfig(\"zookeeper://127.0.0.1:2181\"));\n        applicationModel1\n                .getApplicationConfigManager()\n                .addMetadataReport(new MetadataReportConfig(\"zookeeper://127.0.0.1:2181\"));\n        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();\n        configCenterConfig.setAddress(\"zookeeper://127.0.0.1:2181\");\n        applicationModel1.getApplicationConfigManager().addConfigCenter(configCenterConfig);\n        applicationModel1.getApplicationConfigManager().setMetrics(new MetricsConfig());\n        applicationModel1.getApplicationConfigManager().setMonitor(new MonitorConfig());\n        applicationModel1.getApplicationConfigManager().setSsl(new SslConfig());\n\n        ModuleModel moduleModel = applicationModel1.newModule();\n        moduleModel.getConfigManager().setModule(new ModuleConfig());\n        moduleModel.getConfigManager().addConsumer(new ConsumerConfig());\n        moduleModel.getConfigManager().addProvider(new ProviderConfig());\n        ReferenceConfig<Object> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(MetadataService.class);\n        moduleModel.getConfigManager().addReference(referenceConfig);\n        ServiceConfig<Object> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(MetadataService.class);\n        moduleModel.getConfigManager().addService(serviceConfig);\n\n        CommandContext commandContext = new CommandContext(\"getConfig\");\n        commandContext.setHttp(true);\n\n        Assertions.assertNotNull(new GetConfig(frameworkModel).execute(commandContext, null));\n    }\n\n    @Test\n    void testEmptyId() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel1 = frameworkModel.newApplication();\n\n        applicationModel1.getApplicationConfigManager().setApplication(new ApplicationConfig(\"app1\"));\n\n        ModuleModel moduleModel = applicationModel1.newModule();\n        ProviderConfig providerConfig1 = new ProviderConfig();\n        providerConfig1.setThreadname(\"test\");\n        moduleModel.getConfigManager().addProvider(providerConfig1);\n\n        CommandContext commandContext = new CommandContext(\"getConfig\");\n        commandContext.setHttp(true);\n\n        Assertions.assertNotNull(new GetConfig(frameworkModel).execute(commandContext, null));\n    }\n\n    @Test\n    void testFilter1() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel1 = frameworkModel.newApplication();\n\n        applicationModel1.getApplicationConfigManager().setApplication(new ApplicationConfig(\"app1\"));\n        applicationModel1.getApplicationConfigManager().addProtocol(new ProtocolConfig(\"dubbo\", 12345));\n        applicationModel1.getApplicationConfigManager().addRegistry(new RegistryConfig(\"zookeeper://127.0.0.1:2181\"));\n        applicationModel1\n                .getApplicationConfigManager()\n                .addMetadataReport(new MetadataReportConfig(\"zookeeper://127.0.0.1:2181\"));\n        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();\n        configCenterConfig.setAddress(\"zookeeper://127.0.0.1:2181\");\n        applicationModel1.getApplicationConfigManager().addConfigCenter(configCenterConfig);\n        applicationModel1.getApplicationConfigManager().setMetrics(new MetricsConfig());\n        applicationModel1.getApplicationConfigManager().setMonitor(new MonitorConfig());\n        applicationModel1.getApplicationConfigManager().setSsl(new SslConfig());\n\n        ModuleModel moduleModel = applicationModel1.newModule();\n        moduleModel.getConfigManager().setModule(new ModuleConfig());\n        moduleModel.getConfigManager().addConsumer(new ConsumerConfig());\n        moduleModel.getConfigManager().addProvider(new ProviderConfig());\n        ReferenceConfig<Object> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(MetadataService.class);\n        moduleModel.getConfigManager().addReference(referenceConfig);\n        ServiceConfig<Object> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(MetadataService.class);\n        moduleModel.getConfigManager().addService(serviceConfig);\n\n        CommandContext commandContext = new CommandContext(\"getConfig\");\n        commandContext.setHttp(true);\n\n        Assertions.assertNotNull(\n                new GetConfig(frameworkModel).execute(commandContext, new String[] {\"ApplicationConfig\"}));\n    }\n\n    @Test\n    void testFilter2() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        ApplicationModel applicationModel1 = frameworkModel.newApplication();\n\n        applicationModel1.getApplicationConfigManager().setApplication(new ApplicationConfig(\"app1\"));\n        applicationModel1.getApplicationConfigManager().addProtocol(new ProtocolConfig(\"dubbo\", 12345));\n        applicationModel1.getApplicationConfigManager().addRegistry(new RegistryConfig(\"zookeeper://127.0.0.1:2181\"));\n        applicationModel1\n                .getApplicationConfigManager()\n                .addMetadataReport(new MetadataReportConfig(\"zookeeper://127.0.0.1:2181\"));\n        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();\n        configCenterConfig.setAddress(\"zookeeper://127.0.0.1:2181\");\n        applicationModel1.getApplicationConfigManager().addConfigCenter(configCenterConfig);\n        applicationModel1.getApplicationConfigManager().setMetrics(new MetricsConfig());\n        applicationModel1.getApplicationConfigManager().setMonitor(new MonitorConfig());\n        applicationModel1.getApplicationConfigManager().setSsl(new SslConfig());\n\n        ModuleModel moduleModel = applicationModel1.newModule();\n        moduleModel.getConfigManager().setModule(new ModuleConfig());\n        moduleModel.getConfigManager().addConsumer(new ConsumerConfig());\n        moduleModel.getConfigManager().addProvider(new ProviderConfig());\n        ReferenceConfig<Object> referenceConfig = new ReferenceConfig<>();\n        referenceConfig.setInterface(MetadataService.class);\n        moduleModel.getConfigManager().addReference(referenceConfig);\n        ServiceConfig<Object> serviceConfig = new ServiceConfig<>();\n        serviceConfig.setInterface(MetadataService.class);\n        moduleModel.getConfigManager().addService(serviceConfig);\n\n        CommandContext commandContext = new CommandContext(\"getConfig\");\n        commandContext.setHttp(true);\n\n        Assertions.assertNotNull(\n                new GetConfig(frameworkModel).execute(commandContext, new String[] {\"ProtocolConfig\", \"dubbo\"}));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/HelpTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\n\nclass HelpTest {\n    @Test\n    void testMainHelp() {\n        Help help = new Help(FrameworkModel.defaultModel());\n        String output = help.execute(Mockito.mock(CommandContext.class), null);\n        assertThat(output, containsString(\"greeting\"));\n        assertThat(output, containsString(\"help\"));\n        assertThat(output, containsString(\"ls\"));\n        assertThat(output, containsString(\"online\"));\n        assertThat(output, containsString(\"offline\"));\n        assertThat(output, containsString(\"quit\"));\n    }\n\n    @Test\n    void testGreeting() {\n        Help help = new Help(FrameworkModel.defaultModel());\n        String output = help.execute(Mockito.mock(CommandContext.class), new String[] {\"greeting\"});\n        assertThat(output, containsString(\"COMMAND NAME\"));\n        assertThat(output, containsString(\"greeting\"));\n        assertThat(output, containsString(\"EXAMPLE\"));\n        assertThat(output, containsString(\"greeting dubbo\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/InvokeTelnetTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.legacy.service.DemoService;\nimport org.apache.dubbo.qos.legacy.service.DemoServiceImpl;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\n\nimport io.netty.channel.Channel;\nimport io.netty.util.DefaultAttributeMap;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\nclass InvokeTelnetTest {\n\n    private FrameworkModel frameworkModel;\n    private BaseCommand invoke;\n    private BaseCommand select;\n    private Channel mockChannel;\n    private CommandContext mockCommandContext;\n    private final DefaultAttributeMap defaultAttributeMap = new DefaultAttributeMap();\n    private ModuleServiceRepository repository;\n\n    @BeforeEach\n    public void setup() {\n        DubboBootstrap.reset();\n        frameworkModel = new FrameworkModel();\n        invoke = new InvokeTelnet(frameworkModel);\n        select = new SelectTelnet(frameworkModel);\n        mockChannel = mock(Channel.class);\n        mockCommandContext = mock(CommandContext.class);\n        given(mockCommandContext.getRemote()).willReturn(mockChannel);\n        ApplicationModel applicationModel = frameworkModel.newApplication();\n        repository = applicationModel.getDefaultModule().getServiceRepository();\n    }\n\n    @AfterEach\n    public void after() {\n        frameworkModel.destroy();\n        reset(mockChannel, mockCommandContext);\n    }\n\n    @Test\n    void testInvokeWithoutServicePrefixAndWithoutDefaultService() throws RemotingException {\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n        String result = invoke.execute(mockCommandContext, new String[] {\"echo(\\\"ok\\\")\"});\n        assertTrue(result.contains(\n                \"If you want to invoke like [invoke sayHello(\\\"xxxx\\\")], please execute cd command first,\"\n                        + \" or you can execute it like [invoke IHelloService.sayHello(\\\"xxxx\\\")]\"));\n    }\n\n    @Test\n    void testInvokeDefaultService() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(DemoService.class.getName());\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).set(null);\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_KEY)).willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_KEY));\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n        String result = invoke.execute(mockCommandContext, new String[] {\"echo(\\\"ok\\\")\"});\n        assertTrue(result.contains(\"result: \\\"ok\\\"\"));\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).remove();\n    }\n\n    @Test\n    void testInvokeWithSpecifyService() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(null);\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).set(null);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_KEY)).willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_KEY));\n\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n        String result = invoke.execute(mockCommandContext, new String[] {\"DemoService.echo(\\\"ok\\\")\"});\n        assertTrue(result.contains(\"result: \\\"ok\\\"\"));\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).remove();\n    }\n\n    @Test\n    void testInvokeByPassingNullValue() {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(DemoService.class.getName());\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).set(null);\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_KEY)).willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_KEY));\n\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n        try {\n            invoke.execute(mockCommandContext, new String[] {\"sayHello(null)\"});\n        } catch (Exception ex) {\n            assertTrue(ex instanceof NullPointerException);\n        }\n\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).remove();\n    }\n\n    @Test\n    void testInvokeByPassingEnumValue() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(DemoService.class.getName());\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).set(null);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_KEY)).willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_KEY));\n\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n\n        String result = invoke.execute(mockCommandContext, new String[] {\"getType(\\\"High\\\")\"});\n        assertTrue(result.contains(\"result: \\\"High\\\"\"));\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).remove();\n    }\n\n    @Test\n    void testOverriddenMethodWithSpecifyParamType() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(DemoService.class.getName());\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).set(null);\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_KEY)).willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_KEY));\n\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n\n        String result = invoke.execute(mockCommandContext, new String[] {\n            \"getPerson({\\\"name\\\":\\\"zhangsan\\\",\\\"age\\\":12,\\\"class\\\":\\\"org.apache.dubbo.qos.legacy.service.Person\\\"})\"\n        });\n        assertTrue(result.contains(\"result: 12\"));\n\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).remove();\n    }\n\n    @Test\n    void testInvokeOverriddenMethodBySelect() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(DemoService.class.getName());\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).set(null);\n        defaultAttributeMap.attr(SelectTelnet.SELECT_METHOD_KEY).set(null);\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_PROVIDER_KEY).set(null);\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY).set(null);\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_MESSAGE_KEY).set(null);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_KEY)).willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_METHOD_KEY))\n                .willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_METHOD_KEY));\n        given(mockChannel.attr(InvokeTelnet.INVOKE_METHOD_PROVIDER_KEY))\n                .willReturn(defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_PROVIDER_KEY));\n        given(mockChannel.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY))\n                .willReturn(defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY));\n        given(mockChannel.attr(InvokeTelnet.INVOKE_MESSAGE_KEY))\n                .willReturn(defaultAttributeMap.attr(InvokeTelnet.INVOKE_MESSAGE_KEY));\n\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n\n        String param = \"{\\\"name\\\":\\\"Dubbo\\\",\\\"age\\\":8}\";\n        String result = invoke.execute(mockCommandContext, new String[] {\"getPerson(\" + param + \")\"});\n        assertTrue(\n                result.contains(\"Please use the select command to select the method you want to invoke. eg: select 1\"));\n        result = select.execute(mockCommandContext, new String[] {\"1\"});\n        // result dependent on method order.\n        assertTrue(result.contains(\"result: 8\") || result.contains(\"result: \\\"Dubbo\\\"\"));\n        result = select.execute(mockCommandContext, new String[] {\"2\"});\n        assertTrue(result.contains(\"result: 8\") || result.contains(\"result: \\\"Dubbo\\\"\"));\n\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_METHOD_KEY).remove();\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_PROVIDER_KEY).remove();\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY).remove();\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_MESSAGE_KEY).remove();\n    }\n\n    @Test\n    void testInvokeMethodWithMapParameter() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(DemoService.class.getName());\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).set(null);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_KEY)).willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_KEY));\n\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n\n        String param = \"{1:\\\"Dubbo\\\",2:\\\"test\\\"}\";\n        String result = invoke.execute(mockCommandContext, new String[] {\"getMap(\" + param + \")\"});\n        assertTrue(result.contains(\"result: {1:\\\"Dubbo\\\",2:\\\"test\\\"}\"));\n\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).remove();\n    }\n\n    @Test\n    void testInvokeMultiJsonParamMethod() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(DemoService.class.getName());\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).set(null);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_KEY)).willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_KEY));\n\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n\n        String param = \"{\\\"name\\\":\\\"Dubbo\\\",\\\"age\\\":8},{\\\"name\\\":\\\"Apache\\\",\\\"age\\\":20}\";\n        String result = invoke.execute(mockCommandContext, new String[] {\"getPerson(\" + param + \")\"});\n        assertTrue(result.contains(\"result: 28\"));\n\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).remove();\n    }\n\n    @Test\n    void testMessageNull() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(null);\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).set(null);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_KEY)).willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_KEY));\n\n        String result = invoke.execute(mockCommandContext, new String[0]);\n        assertEquals(\n                \"Please input method name, eg: \\r\\ninvoke xxxMethod(1234, \\\"abcd\\\", {\\\"prop\\\" : \\\"value\\\"})\\r\\ninvoke XxxService.xxxMethod(1234, \\\"abcd\\\", {\\\"prop\\\" : \\\"value\\\"})\\r\\ninvoke com.xxx.XxxService.xxxMethod(1234, \\\"abcd\\\", {\\\"prop\\\" : \\\"value\\\"})\",\n                result);\n\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).remove();\n    }\n\n    @Test\n    void testInvalidMessage() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(null);\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).set(null);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(SelectTelnet.SELECT_KEY)).willReturn(defaultAttributeMap.attr(SelectTelnet.SELECT_KEY));\n\n        String result = invoke.execute(mockCommandContext, new String[] {\"(\"});\n        assertEquals(\"Invalid parameters, format: service.method(args)\", result);\n\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(SelectTelnet.SELECT_KEY).remove();\n    }\n\n    private void registerProvider(String key, Object impl, Class<?> interfaceClass) {\n        ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);\n        repository.registerProvider(key, impl, serviceDescriptor, null, null);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/LiveTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass LiveTest {\n    private FrameworkModel frameworkModel;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n        MockLivenessProbe.setCheckReturnValue(false);\n    }\n\n    @Test\n    void testExecute() {\n        Live live = new Live(frameworkModel);\n        CommandContext commandContext = new CommandContext(\"live\");\n        String result = live.execute(commandContext, new String[0]);\n        Assertions.assertEquals(result, \"false\");\n        Assertions.assertEquals(commandContext.getHttpCode(), 503);\n\n        MockLivenessProbe.setCheckReturnValue(true);\n        result = live.execute(commandContext, new String[0]);\n        Assertions.assertEquals(result, \"true\");\n        Assertions.assertEquals(commandContext.getHttpCode(), 200);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/LsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.qos.DemoService;\nimport org.apache.dubbo.qos.DemoServiceImpl;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.AsyncMethodInfo;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nclass LsTest {\n    private static final Logger logger = LoggerFactory.getLogger(LsTest.class);\n    private FrameworkModel frameworkModel;\n    private ModuleServiceRepository repository;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n        repository = frameworkModel.newApplication().getDefaultModule().getServiceRepository();\n        registerProvider();\n        registerConsumer();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testExecute() {\n        Ls ls = new Ls(frameworkModel);\n        String result = ls.execute(Mockito.mock(CommandContext.class), new String[0]);\n        logger.info(result);\n        /**\n         * As Provider side:\n         * +--------------------------------+---+\n         * |      Provider Service Name     |PUB|\n         * +--------------------------------+---+\n         * |org.apache.dubbo.qos.DemoService| N |\n         * +--------------------------------+---+\n         * As Consumer side:\n         * +--------------------------------+---+\n         * |      Consumer Service Name     |NUM|\n         * +--------------------------------+---+\n         * |org.apache.dubbo.qos.DemoService| 0 |\n         * +--------------------------------+---+\n         */\n    }\n\n    private void registerProvider() {\n        ServiceDescriptor serviceDescriptor = repository.registerService(DemoService.class);\n        ServiceMetadata serviceMetadata = new ServiceMetadata();\n        serviceMetadata.setServiceKey(DemoService.class.getName());\n        ProviderModel providerModel = new ProviderModel(\n                DemoService.class.getName(),\n                new DemoServiceImpl(),\n                serviceDescriptor,\n                null,\n                serviceMetadata,\n                ClassUtils.getClassLoader(DemoService.class));\n        repository.registerProvider(providerModel);\n    }\n\n    private void registerConsumer() {\n        ServiceDescriptor serviceDescriptor = repository.registerService(DemoService.class);\n        ReferenceConfig referenceConfig = new ReferenceConfig();\n        referenceConfig.setInterface(DemoService.class);\n        ServiceMetadata serviceMetadata = new ServiceMetadata();\n        serviceMetadata.setServiceKey(DemoService.class.getName());\n        Map<String, AsyncMethodInfo> methodConfigs = new HashMap<>();\n        ConsumerModel consumerModel = new ConsumerModel(\n                serviceMetadata.getServiceKey(),\n                null,\n                serviceDescriptor,\n                serviceMetadata,\n                methodConfigs,\n                referenceConfig.getInterfaceClassLoader());\n        repository.registerConsumer(consumerModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/MockLivenessProbe.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.qos.probe.LivenessProbe;\n\n@Activate\npublic class MockLivenessProbe implements LivenessProbe {\n    private static boolean checkReturnValue = false;\n\n    @Override\n    public boolean check() {\n        return checkReturnValue;\n    }\n\n    public static void setCheckReturnValue(boolean checkReturnValue) {\n        MockLivenessProbe.checkReturnValue = checkReturnValue;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/OfflineTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.qos.DemoService;\nimport org.apache.dubbo.qos.DemoServiceImpl;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.registry.RegistryService;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE;\nimport static org.mockito.Mockito.mock;\n\n/**\n * {@link BaseOffline}\n * {@link Offline}\n * {@link OfflineApp}\n * {@link OfflineInterface}\n */\nclass OfflineTest {\n    private FrameworkModel frameworkModel;\n    private ModuleServiceRepository repository;\n    private ProviderModel.RegisterStatedURL registerStatedURL;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n        repository = frameworkModel.newApplication().getDefaultModule().getServiceRepository();\n        registerProvider();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testExecute() {\n        Offline offline = new Offline(frameworkModel);\n        String result = offline.execute(mock(CommandContext.class), new String[] {DemoService.class.getName()});\n        Assertions.assertEquals(result, \"OK\");\n        Assertions.assertFalse(registerStatedURL.isRegistered());\n\n        OfflineInterface offlineInterface = new OfflineInterface(frameworkModel);\n        registerStatedURL.setRegistered(true);\n        result = offlineInterface.execute(mock(CommandContext.class), new String[] {DemoService.class.getName()});\n        Assertions.assertEquals(result, \"OK\");\n        Assertions.assertFalse(registerStatedURL.isRegistered());\n\n        registerStatedURL.setRegistered(true);\n        registerStatedURL.setRegistryUrl(URL.valueOf(\"test://127.0.0.1:2181/\" + RegistryService.class.getName())\n                .addParameter(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE));\n        OfflineApp offlineApp = new OfflineApp(frameworkModel);\n        result = offlineApp.execute(mock(CommandContext.class), new String[] {DemoService.class.getName()});\n        Assertions.assertEquals(result, \"OK\");\n        Assertions.assertFalse(registerStatedURL.isRegistered());\n    }\n\n    private void registerProvider() {\n        ServiceDescriptor serviceDescriptor = repository.registerService(DemoService.class);\n        ServiceMetadata serviceMetadata = new ServiceMetadata();\n        serviceMetadata.setServiceKey(DemoService.class.getName());\n        ProviderModel providerModel = new ProviderModel(\n                DemoService.class.getName(),\n                new DemoServiceImpl(),\n                serviceDescriptor,\n                serviceMetadata,\n                ClassUtils.getClassLoader(DemoService.class));\n        registerStatedURL = new ProviderModel.RegisterStatedURL(\n                URL.valueOf(\"dubbo://127.0.0.1:20880/\" + DemoService.class.getName()),\n                URL.valueOf(\"test://127.0.0.1:2181/\" + RegistryService.class.getName()),\n                true);\n        providerModel.addStatedUrl(registerStatedURL);\n        repository.registerProvider(providerModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/OnlineTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.qos.DemoService;\nimport org.apache.dubbo.qos.DemoServiceImpl;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.registry.RegistryService;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE;\nimport static org.mockito.Mockito.mock;\n\n/**\n * {@link BaseOnline}\n * {@link Online}\n * {@link OnlineApp}\n * {@link OnlineInterface}\n */\nclass OnlineTest {\n    private FrameworkModel frameworkModel;\n    private ModuleServiceRepository repository;\n    private ProviderModel.RegisterStatedURL registerStatedURL;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = new FrameworkModel();\n        repository = frameworkModel.newApplication().getDefaultModule().getServiceRepository();\n        registerProvider();\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testExecute() {\n        Online online = new Online(frameworkModel);\n        String result = online.execute(mock(CommandContext.class), new String[] {DemoService.class.getName()});\n        Assertions.assertEquals(result, \"OK\");\n        Assertions.assertTrue(registerStatedURL.isRegistered());\n\n        OnlineInterface onlineInterface = new OnlineInterface(frameworkModel);\n        registerStatedURL.setRegistered(false);\n        result = onlineInterface.execute(mock(CommandContext.class), new String[] {DemoService.class.getName()});\n        Assertions.assertEquals(result, \"OK\");\n        Assertions.assertTrue(registerStatedURL.isRegistered());\n\n        registerStatedURL.setRegistered(false);\n        registerStatedURL.setRegistryUrl(URL.valueOf(\"test://127.0.0.1:2181/\" + RegistryService.class.getName())\n                .addParameter(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE));\n        OnlineApp onlineApp = new OnlineApp(frameworkModel);\n        result = onlineApp.execute(mock(CommandContext.class), new String[] {DemoService.class.getName()});\n        Assertions.assertEquals(result, \"OK\");\n        Assertions.assertTrue(registerStatedURL.isRegistered());\n    }\n\n    private void registerProvider() {\n        ServiceDescriptor serviceDescriptor = repository.registerService(DemoService.class);\n        ServiceMetadata serviceMetadata = new ServiceMetadata();\n        serviceMetadata.setServiceKey(DemoService.class.getName());\n        ProviderModel providerModel = new ProviderModel(\n                DemoService.class.getName(),\n                new DemoServiceImpl(),\n                serviceDescriptor,\n                serviceMetadata,\n                ClassUtils.getClassLoader(DemoService.class));\n        registerStatedURL = new ProviderModel.RegisterStatedURL(\n                URL.valueOf(\"dubbo://127.0.0.1:20880/\" + DemoService.class.getName()),\n                URL.valueOf(\"test://127.0.0.1:2181/\" + RegistryService.class.getName()),\n                false);\n        providerModel.addStatedUrl(registerStatedURL);\n        repository.registerProvider(providerModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/PortTelnetTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.legacy.service.DemoService;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeClient;\nimport org.apache.dubbo.remoting.exchange.Exchangers;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\nclass PortTelnetTest {\n    private static final Logger logger = LoggerFactory.getLogger(PortTelnetTest.class);\n    private BaseCommand port;\n\n    private Invoker<DemoService> mockInvoker;\n    private CommandContext mockCommandContext;\n\n    private static final int availablePort = NetUtils.getAvailablePort();\n\n    @SuppressWarnings(\"unchecked\")\n    @BeforeEach\n    public void before() {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        port = new PortTelnet(frameworkModel);\n        mockCommandContext = mock(CommandContext.class);\n        mockInvoker = mock(Invoker.class);\n        given(mockInvoker.getInterface()).willReturn(DemoService.class);\n        given(mockInvoker.getUrl()).willReturn(URL.valueOf(\"dubbo://127.0.0.1:\" + availablePort + \"/demo\"));\n\n        frameworkModel\n                .getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n    }\n\n    @AfterEach\n    public void afterEach() {\n        FrameworkModel.destroyAll();\n        reset(mockInvoker, mockCommandContext);\n    }\n\n    /**\n     * In NAT network scenario, server's channel.getRemoteAddress() possibly get the address of network gateway, or\n     * the address converted by NAT. In this case, check port only.\n     */\n    @Test\n    void testListClient() throws Exception {\n        ExchangeClient client1 = Exchangers.connect(\"dubbo://127.0.0.1:\" + availablePort + \"/demo\");\n        ExchangeClient client2 = Exchangers.connect(\"dubbo://127.0.0.1:\" + availablePort + \"/demo\");\n        Thread.sleep(100);\n        String result = port.execute(mockCommandContext, new String[] {\"-l\", availablePort + \"\"});\n        String client1Addr = client1.getLocalAddress().toString();\n        String client2Addr = client2.getLocalAddress().toString();\n        logger.info(\"Result: {}}\", result);\n        logger.info(\"Client 1 Address {}\", client1Addr);\n        logger.info(\"Client 2 Address {}\", client2Addr);\n        assertTrue(result.contains(String.valueOf(client1.getLocalAddress().getPort())));\n        assertTrue(result.contains(String.valueOf(client2.getLocalAddress().getPort())));\n    }\n\n    @Test\n    void testListDetail() throws RemotingException {\n        String result = port.execute(mockCommandContext, new String[] {\"-l\"});\n        assertEquals(\"dubbo://127.0.0.1:\" + availablePort + \"\", result);\n    }\n\n    @Test\n    void testListAllPort() throws RemotingException {\n        String result = port.execute(mockCommandContext, new String[0]);\n        assertEquals(\"\" + availablePort + \"\", result);\n    }\n\n    @Test\n    void testErrorMessage() throws RemotingException {\n        String result = port.execute(mockCommandContext, new String[] {\"a\"});\n        assertEquals(\"Illegal port a, must be integer.\", result);\n    }\n\n    @Test\n    void testNoPort() throws RemotingException {\n        String result = port.execute(mockCommandContext, new String[] {\"-l\", \"20880\"});\n        assertEquals(\"No such port 20880\", result);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/PublishMetadataTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass PublishMetadataTest {\n    private FrameworkModel frameworkModel;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        frameworkModel = new FrameworkModel();\n        for (int i = 0; i < 3; i++) {\n            ApplicationModel applicationModel = frameworkModel.newApplication();\n            applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"APP_\" + i));\n        }\n    }\n\n    @AfterEach\n    public void reset() {\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testExecute() {\n        PublishMetadata publishMetadata = new PublishMetadata(frameworkModel);\n\n        String result = publishMetadata.execute(Mockito.mock(CommandContext.class), new String[0]);\n        String expectResult = \"publish metadata succeeded. App:APP_0\\n\" + \"publish metadata succeeded. App:APP_1\\n\"\n                + \"publish metadata succeeded. App:APP_2\\n\";\n        Assertions.assertEquals(result, expectResult);\n\n        // delay 5s\n        result = publishMetadata.execute(Mockito.mock(CommandContext.class), new String[] {\"5\"});\n        expectResult = \"publish task submitted, will publish in 5 seconds. App:APP_0\\n\"\n                + \"publish task submitted, will publish in 5 seconds. App:APP_1\\n\"\n                + \"publish task submitted, will publish in 5 seconds. App:APP_2\\n\";\n        Assertions.assertEquals(result, expectResult);\n\n        // wrong delay param\n        result = publishMetadata.execute(Mockito.mock(CommandContext.class), new String[] {\"A\"});\n        expectResult = \"publishMetadata failed! Wrong delay param!\";\n        Assertions.assertEquals(result, expectResult);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/PwdTelnetTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport io.netty.channel.Channel;\nimport io.netty.util.DefaultAttributeMap;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\nclass PwdTelnetTest {\n    private static final BaseCommand pwdTelnet = new PwdTelnet();\n    private Channel mockChannel;\n    private CommandContext mockCommandContext;\n\n    private final DefaultAttributeMap defaultAttributeMap = new DefaultAttributeMap();\n\n    @BeforeEach\n    public void setUp() {\n        mockChannel = mock(Channel.class);\n        mockCommandContext = mock(CommandContext.class);\n        given(mockCommandContext.getRemote()).willReturn(mockChannel);\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n    }\n\n    @AfterEach\n    public void tearDown() {\n        FrameworkModel.destroyAll();\n        mockChannel.close();\n        reset(mockChannel, mockCommandContext);\n    }\n\n    @Test\n    void testService() throws RemotingException {\n        defaultAttributeMap\n                .attr(ChangeTelnet.SERVICE_KEY)\n                .set(\"org.apache.dubbo.rpc.protocol.dubbo.support.DemoService\");\n        String result = pwdTelnet.execute(mockCommandContext, new String[0]);\n        assertEquals(\"org.apache.dubbo.rpc.protocol.dubbo.support.DemoService\", result);\n    }\n\n    @Test\n    void testSlash() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(null);\n        String result = pwdTelnet.execute(mockCommandContext, new String[0]);\n        assertEquals(\"/\", result);\n    }\n\n    @Test\n    void testMessageError() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(null);\n        String result = pwdTelnet.execute(mockCommandContext, new String[] {\"test\"});\n        assertEquals(\"Unsupported parameter [test] for pwd.\", result);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/QuitTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.common.QosConstants;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass QuitTest {\n    @Test\n    void testExecute() throws Exception {\n        Quit quit = new Quit();\n        String output = quit.execute(Mockito.mock(CommandContext.class), null);\n        assertThat(output, equalTo(QosConstants.CLOSE));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/ReadyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.deploy.ModuleDeployer;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.probe.ReadinessProbe;\nimport org.apache.dubbo.qos.probe.impl.DeployerReadinessProbe;\nimport org.apache.dubbo.qos.probe.impl.ProviderReadinessProbe;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.FrameworkServiceRepository;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass ReadyTest {\n\n    private FrameworkModel frameworkModel;\n    private ModuleDeployer moduleDeployer;\n    private FrameworkServiceRepository frameworkServiceRepository;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = Mockito.mock(FrameworkModel.class);\n        frameworkServiceRepository = Mockito.mock(FrameworkServiceRepository.class);\n        ConfigManager manager = Mockito.mock(ConfigManager.class);\n        Mockito.when(manager.getApplication()).thenReturn(Optional.of(new ApplicationConfig(\"ReadyTest\")));\n        ApplicationModel applicationModel = Mockito.mock(ApplicationModel.class);\n        ModuleModel moduleModel = Mockito.mock(ModuleModel.class);\n        moduleDeployer = Mockito.mock(ModuleDeployer.class);\n        Mockito.when(frameworkServiceRepository.allProviderModels()).thenReturn(Collections.emptyList());\n        Mockito.when(frameworkModel.newApplication()).thenReturn(applicationModel);\n        Mockito.when(frameworkModel.getApplicationModels()).thenReturn(Arrays.asList(applicationModel));\n        Mockito.when(frameworkModel.getServiceRepository()).thenReturn(frameworkServiceRepository);\n        Mockito.when(applicationModel.getModuleModels()).thenReturn(Arrays.asList(moduleModel));\n        Mockito.when(applicationModel.getApplicationConfigManager()).thenReturn(manager);\n        Mockito.when(moduleModel.getDeployer()).thenReturn(moduleDeployer);\n        Mockito.when(moduleDeployer.isCompletion()).thenReturn(true);\n\n        ExtensionLoader loader = Mockito.mock(ExtensionLoader.class);\n        Mockito.when(frameworkModel.getExtensionLoader(ReadinessProbe.class)).thenReturn(loader);\n        URL url = URL.valueOf(\"application://\").addParameter(CommonConstants.QOS_READY_PROBE_EXTENSION, \"\");\n        List<ReadinessProbe> readinessProbes =\n                Arrays.asList(new DeployerReadinessProbe(frameworkModel), new ProviderReadinessProbe(frameworkModel));\n        Mockito.when(loader.getActivateExtension(url, CommonConstants.QOS_READY_PROBE_EXTENSION))\n                .thenReturn(readinessProbes);\n    }\n\n    @Test\n    void testExecute() {\n        Ready ready = new Ready(frameworkModel);\n        CommandContext commandContext = new CommandContext(\"ready\");\n\n        String result = ready.execute(commandContext, new String[0]);\n        Assertions.assertEquals(\"true\", result);\n        Assertions.assertEquals(commandContext.getHttpCode(), 200);\n\n        Mockito.when(moduleDeployer.isCompletion()).thenReturn(false);\n        result = ready.execute(commandContext, new String[0]);\n        Assertions.assertEquals(\"false\", result);\n        Assertions.assertEquals(commandContext.getHttpCode(), 503);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/SelectTelnetTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.legacy.service.DemoService;\nimport org.apache.dubbo.qos.legacy.service.DemoServiceImpl;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.netty.channel.Channel;\nimport io.netty.util.DefaultAttributeMap;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\nclass SelectTelnetTest {\n\n    private BaseCommand select;\n\n    private Channel mockChannel;\n    private CommandContext mockCommandContext;\n\n    private ModuleServiceRepository repository;\n    private final DefaultAttributeMap defaultAttributeMap = new DefaultAttributeMap();\n    private List<Method> methods;\n\n    @BeforeEach\n    public void setup() {\n        repository = ApplicationModel.defaultModel().getDefaultModule().getServiceRepository();\n        select = new SelectTelnet(FrameworkModel.defaultModel());\n        String methodName = \"getPerson\";\n        methods = new ArrayList<>();\n        for (Method method : DemoService.class.getMethods()) {\n            if (method.getName().equals(methodName)) {\n                methods.add(method);\n            }\n        }\n\n        DubboBootstrap.reset();\n        mockChannel = mock(Channel.class);\n        mockCommandContext = mock(CommandContext.class);\n        given(mockCommandContext.getRemote()).willReturn(mockChannel);\n    }\n\n    @AfterEach\n    public void after() {\n        FrameworkModel.destroyAll();\n        reset(mockChannel, mockCommandContext);\n    }\n\n    @Test\n    void testInvokeWithoutMethodList() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(DemoService.class.getName());\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY).set(null);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY))\n                .willReturn(defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY));\n\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n\n        String result = select.execute(mockCommandContext, new String[] {\"1\"});\n        assertTrue(result.contains(\"Please use the invoke command first.\"));\n\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY).remove();\n    }\n\n    @Test\n    void testInvokeWithIllegalMessage() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(DemoService.class.getName());\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY).set(methods);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY))\n                .willReturn(defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY));\n\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n\n        String result = select.execute(mockCommandContext, new String[] {\"index\"});\n        assertTrue(result.contains(\"Illegal index ,please input select 1\"));\n\n        result = select.execute(mockCommandContext, new String[] {\"0\"});\n        assertTrue(result.contains(\"Illegal index ,please input select 1\"));\n\n        result = select.execute(mockCommandContext, new String[] {\"1000\"});\n        assertTrue(result.contains(\"Illegal index ,please input select 1\"));\n\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY).remove();\n    }\n\n    @Test\n    void testInvokeWithNull() throws RemotingException {\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).set(DemoService.class.getName());\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY).set(methods);\n\n        given(mockChannel.attr(ChangeTelnet.SERVICE_KEY))\n                .willReturn(defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY));\n        given(mockChannel.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY))\n                .willReturn(defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY));\n\n        registerProvider(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);\n\n        String result = select.execute(mockCommandContext, new String[0]);\n        assertTrue(result.contains(\"Please input the index of the method you want to invoke\"));\n\n        defaultAttributeMap.attr(ChangeTelnet.SERVICE_KEY).remove();\n        defaultAttributeMap.attr(InvokeTelnet.INVOKE_METHOD_LIST_KEY).remove();\n    }\n\n    private void registerProvider(String key, Object impl, Class<?> interfaceClass) {\n        ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);\n        repository.registerProvider(key, impl, serviceDescriptor, null, null);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/SerializeCheckStatusTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.SerializeSecurityManager;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass SerializeCheckStatusTest {\n    @Test\n    void testNotify() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeCheckStatus serializeCheckStatus = new SerializeCheckStatus(frameworkModel);\n\n        CommandContext commandContext1 = Mockito.mock(CommandContext.class);\n        Mockito.when(commandContext1.isHttp()).thenReturn(false);\n        CommandContext commandContext2 = Mockito.mock(CommandContext.class);\n        Mockito.when(commandContext2.isHttp()).thenReturn(true);\n\n        Assertions.assertFalse(\n                serializeCheckStatus.execute(commandContext1, null).contains(\"Test1234\"));\n        Assertions.assertFalse(\n                serializeCheckStatus.execute(commandContext2, null).contains(\"Test1234\"));\n        ssm.addToAllowed(\"Test1234\");\n        Assertions.assertTrue(\n                serializeCheckStatus.execute(commandContext1, null).contains(\"Test1234\"));\n        Assertions.assertTrue(\n                serializeCheckStatus.execute(commandContext2, null).contains(\"Test1234\"));\n\n        Assertions.assertFalse(\n                serializeCheckStatus.execute(commandContext1, null).contains(\"Test4321\"));\n        Assertions.assertFalse(\n                serializeCheckStatus.execute(commandContext2, null).contains(\"Test4321\"));\n        ssm.addToDisAllowed(\"Test4321\");\n        Assertions.assertTrue(\n                serializeCheckStatus.execute(commandContext1, null).contains(\"Test4321\"));\n        Assertions.assertTrue(\n                serializeCheckStatus.execute(commandContext2, null).contains(\"Test4321\"));\n\n        Assertions.assertFalse(\n                serializeCheckStatus.execute(commandContext1, null).contains(\"CheckSerializable: false\"));\n        Assertions.assertFalse(\n                serializeCheckStatus.execute(commandContext2, null).contains(\"\\\"checkSerializable\\\":false\"));\n        ssm.setCheckSerializable(false);\n        Assertions.assertTrue(\n                serializeCheckStatus.execute(commandContext1, null).contains(\"CheckSerializable: false\"));\n        Assertions.assertTrue(\n                serializeCheckStatus.execute(commandContext2, null).contains(\"\\\"checkSerializable\\\":false\"));\n\n        Assertions.assertFalse(\n                serializeCheckStatus.execute(commandContext1, null).contains(\"CheckStatus: DISABLE\"));\n        Assertions.assertFalse(\n                serializeCheckStatus.execute(commandContext2, null).contains(\"\\\"checkStatus\\\":\\\"DISABLE\\\"\"));\n        ssm.setCheckStatus(org.apache.dubbo.common.utils.SerializeCheckStatus.DISABLE);\n        Assertions.assertTrue(\n                serializeCheckStatus.execute(commandContext1, null).contains(\"CheckStatus: DISABLE\"));\n        Assertions.assertTrue(\n                serializeCheckStatus.execute(commandContext2, null).contains(\"\\\"checkStatus\\\":\\\"DISABLE\\\"\"));\n\n        frameworkModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/SerializeWarnedClassesTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.utils.SerializeSecurityManager;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass SerializeWarnedClassesTest {\n    @Test\n    void test() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeWarnedClasses serializeWarnedClasses = new SerializeWarnedClasses(frameworkModel);\n\n        CommandContext commandContext1 = Mockito.mock(CommandContext.class);\n        Mockito.when(commandContext1.isHttp()).thenReturn(false);\n        CommandContext commandContext2 = Mockito.mock(CommandContext.class);\n        Mockito.when(commandContext2.isHttp()).thenReturn(true);\n\n        Assertions.assertFalse(\n                serializeWarnedClasses.execute(commandContext1, null).contains(\"Test1234\"));\n        Assertions.assertFalse(\n                serializeWarnedClasses.execute(commandContext2, null).contains(\"Test1234\"));\n        ssm.getWarnedClasses().add(\"Test1234\");\n        Assertions.assertTrue(\n                serializeWarnedClasses.execute(commandContext1, null).contains(\"Test1234\"));\n        Assertions.assertTrue(\n                serializeWarnedClasses.execute(commandContext2, null).contains(\"Test1234\"));\n\n        Assertions.assertFalse(\n                serializeWarnedClasses.execute(commandContext1, null).contains(\"Test4321\"));\n        Assertions.assertFalse(\n                serializeWarnedClasses.execute(commandContext2, null).contains(\"Test4321\"));\n        ssm.getWarnedClasses().add(\"Test4321\");\n        Assertions.assertTrue(\n                serializeWarnedClasses.execute(commandContext1, null).contains(\"Test4321\"));\n        Assertions.assertTrue(\n                serializeWarnedClasses.execute(commandContext2, null).contains(\"Test4321\"));\n\n        frameworkModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/ShutdownTelnetTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport io.netty.channel.Channel;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\nclass ShutdownTelnetTest {\n\n    private BaseCommand shutdown;\n    private Channel mockChannel;\n    private CommandContext mockCommandContext;\n\n    @BeforeEach\n    public void setUp() {\n        shutdown = new ShutdownTelnet(FrameworkModel.defaultModel());\n        mockCommandContext = mock(CommandContext.class);\n        mockChannel = mock(Channel.class);\n        given(mockCommandContext.getRemote()).willReturn(mockChannel);\n    }\n\n    @AfterEach\n    public void after() {\n        FrameworkModel.destroyAll();\n        reset(mockChannel, mockCommandContext);\n    }\n\n    @Test\n    void testInvoke() throws RemotingException {\n        String result = shutdown.execute(mockCommandContext, new String[0]);\n        assertTrue(result.contains(\"Application has shutdown successfully\"));\n    }\n\n    @Test\n    void testInvokeWithTimeParameter() throws RemotingException {\n        int sleepTime = 2000;\n        long start = System.currentTimeMillis();\n        String result = shutdown.execute(mockCommandContext, new String[] {\"-t\", \"\" + sleepTime});\n        long end = System.currentTimeMillis();\n        assertTrue(result.contains(\"Application has shutdown successfully\"), result);\n        assertTrue((end - start) >= sleepTime, \"sleepTime: \" + sleepTime + \", execTime: \" + (end - start));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/StartupTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.deploy.ModuleDeployer;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.probe.StartupProbe;\nimport org.apache.dubbo.qos.probe.impl.DeployerStartupProbe;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass StartupTest {\n    private FrameworkModel frameworkModel;\n    private ModuleDeployer moduleDeployer;\n\n    @BeforeEach\n    public void setUp() {\n        frameworkModel = Mockito.mock(FrameworkModel.class);\n        ApplicationModel applicationModel = Mockito.mock(ApplicationModel.class);\n        ModuleModel moduleModel = Mockito.mock(ModuleModel.class);\n        ConfigManager manager = Mockito.mock(ConfigManager.class);\n        Mockito.when(manager.getApplication()).thenReturn(Optional.of(new ApplicationConfig(\"ReadyTest\")));\n        moduleDeployer = Mockito.mock(ModuleDeployer.class);\n        Mockito.when(frameworkModel.newApplication()).thenReturn(applicationModel);\n        Mockito.when(frameworkModel.getApplicationModels()).thenReturn(Arrays.asList(applicationModel));\n        Mockito.when(applicationModel.getModuleModels()).thenReturn(Arrays.asList(moduleModel));\n        Mockito.when(applicationModel.getApplicationConfigManager()).thenReturn(manager);\n        Mockito.when(moduleModel.getDeployer()).thenReturn(moduleDeployer);\n        Mockito.when(moduleDeployer.isRunning()).thenReturn(true);\n\n        ExtensionLoader loader = Mockito.mock(ExtensionLoader.class);\n        Mockito.when(frameworkModel.getExtensionLoader(StartupProbe.class)).thenReturn(loader);\n        URL url = URL.valueOf(\"application://\").addParameter(CommonConstants.QOS_STARTUP_PROBE_EXTENSION, \"\");\n        List<StartupProbe> readinessProbes = Arrays.asList(new DeployerStartupProbe(frameworkModel));\n        Mockito.when(loader.getActivateExtension(url, CommonConstants.QOS_STARTUP_PROBE_EXTENSION))\n                .thenReturn(readinessProbes);\n    }\n\n    @Test\n    void testExecute() {\n        Startup startup = new Startup(frameworkModel);\n        CommandContext commandContext = new CommandContext(\"startup\");\n\n        String result = startup.execute(commandContext, new String[0]);\n        Assertions.assertEquals(\"true\", result);\n        Assertions.assertEquals(commandContext.getHttpCode(), 200);\n\n        Mockito.when(moduleDeployer.isRunning()).thenReturn(false);\n        result = startup.execute(commandContext, new String[0]);\n        Assertions.assertEquals(\"false\", result);\n        Assertions.assertEquals(commandContext.getHttpCode(), 503);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/TestInterface.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\npublic interface TestInterface {\n\n    String sayHello();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/TestInterface2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\npublic interface TestInterface2 {\n\n    String sayHello();\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/TestRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\n\npublic class TestRegistryFactory implements RegistryFactory {\n    static Registry registry;\n\n    @Override\n    public Registry getRegistry(URL url) {\n        return registry;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/channel/MockNettyChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.impl.channel;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport io.netty.buffer.ByteBufAllocator;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelConfig;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelId;\nimport io.netty.channel.ChannelMetadata;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.ChannelProgressivePromise;\nimport io.netty.channel.ChannelPromise;\nimport io.netty.channel.EventLoop;\nimport io.netty.util.Attribute;\nimport io.netty.util.AttributeKey;\nimport io.netty.util.AttributeMap;\nimport io.netty.util.DefaultAttributeMap;\nimport io.netty.util.concurrent.Future;\nimport io.netty.util.concurrent.GenericFutureListener;\n\npublic class MockNettyChannel implements Channel {\n\n    InetSocketAddress localAddress;\n    InetSocketAddress remoteAddress;\n    private URL remoteUrl;\n    private List<Object> receivedObjects = new LinkedList<>();\n    public static final String ERROR_WHEN_SEND = \"error_when_send\";\n    private CountDownLatch latch;\n    private AttributeMap attributeMap = new DefaultAttributeMap();\n\n    public MockNettyChannel(URL remoteUrl, CountDownLatch latch) {\n        this.remoteUrl = remoteUrl;\n        this.latch = latch;\n    }\n\n    @Override\n    public ChannelFuture writeAndFlush(Object msg) {\n        receivedObjects.add(msg);\n        if (latch != null) {\n            latch.countDown();\n        }\n        return newPromise();\n    }\n\n    @Override\n    public ChannelPromise newPromise() {\n        return new ChannelPromise() {\n            @Override\n            public Channel channel() {\n                return null;\n            }\n\n            @Override\n            public ChannelPromise setSuccess(Void result) {\n                return null;\n            }\n\n            @Override\n            public ChannelPromise setSuccess() {\n                return null;\n            }\n\n            @Override\n            public boolean trySuccess() {\n                return false;\n            }\n\n            @Override\n            public ChannelPromise setFailure(Throwable cause) {\n                return null;\n            }\n\n            @Override\n            public ChannelPromise addListener(GenericFutureListener<? extends Future<? super Void>> listener) {\n                return null;\n            }\n\n            @Override\n            public ChannelPromise addListeners(GenericFutureListener<? extends Future<? super Void>>... listeners) {\n                return null;\n            }\n\n            @Override\n            public ChannelPromise removeListener(GenericFutureListener<? extends Future<? super Void>> listener) {\n                return null;\n            }\n\n            @Override\n            public ChannelPromise removeListeners(GenericFutureListener<? extends Future<? super Void>>... listeners) {\n                return null;\n            }\n\n            @Override\n            public ChannelPromise sync() throws InterruptedException {\n                return null;\n            }\n\n            @Override\n            public ChannelPromise syncUninterruptibly() {\n                return null;\n            }\n\n            @Override\n            public ChannelPromise await() throws InterruptedException {\n                return this;\n            }\n\n            @Override\n            public ChannelPromise awaitUninterruptibly() {\n                return null;\n            }\n\n            @Override\n            public ChannelPromise unvoid() {\n                return null;\n            }\n\n            @Override\n            public boolean isVoid() {\n                return false;\n            }\n\n            @Override\n            public boolean trySuccess(Void result) {\n                return false;\n            }\n\n            @Override\n            public boolean tryFailure(Throwable cause) {\n                return false;\n            }\n\n            @Override\n            public boolean setUncancellable() {\n                return false;\n            }\n\n            @Override\n            public boolean isSuccess() {\n                return false;\n            }\n\n            @Override\n            public boolean isCancellable() {\n                return false;\n            }\n\n            @Override\n            public Throwable cause() {\n                return null;\n            }\n\n            @Override\n            public boolean await(long timeout, TimeUnit unit) throws InterruptedException {\n                return true;\n            }\n\n            @Override\n            public boolean await(long timeoutMillis) throws InterruptedException {\n                return true;\n            }\n\n            @Override\n            public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {\n                return true;\n            }\n\n            @Override\n            public boolean awaitUninterruptibly(long timeoutMillis) {\n                return false;\n            }\n\n            @Override\n            public Void getNow() {\n                return null;\n            }\n\n            @Override\n            public boolean cancel(boolean mayInterruptIfRunning) {\n                return false;\n            }\n\n            @Override\n            public boolean isCancelled() {\n                return false;\n            }\n\n            @Override\n            public boolean isDone() {\n                return false;\n            }\n\n            @Override\n            public Void get() throws InterruptedException, ExecutionException {\n                return null;\n            }\n\n            @Override\n            public Void get(long timeout, TimeUnit unit)\n                    throws InterruptedException, ExecutionException, TimeoutException {\n                return null;\n            }\n        };\n    }\n\n    @Override\n    public ChannelProgressivePromise newProgressivePromise() {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture newSucceededFuture() {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture newFailedFuture(Throwable cause) {\n        return null;\n    }\n\n    @Override\n    public ChannelPromise voidPromise() {\n        return null;\n    }\n\n    @Override\n    public ChannelId id() {\n        return null;\n    }\n\n    @Override\n    public EventLoop eventLoop() {\n        return null;\n    }\n\n    @Override\n    public Channel parent() {\n        return null;\n    }\n\n    @Override\n    public ChannelConfig config() {\n        return null;\n    }\n\n    @Override\n    public boolean isOpen() {\n        return false;\n    }\n\n    @Override\n    public boolean isRegistered() {\n        return false;\n    }\n\n    @Override\n    public boolean isActive() {\n        return false;\n    }\n\n    @Override\n    public ChannelMetadata metadata() {\n        return null;\n    }\n\n    @Override\n    public SocketAddress localAddress() {\n        return null;\n    }\n\n    @Override\n    public SocketAddress remoteAddress() {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture closeFuture() {\n        return null;\n    }\n\n    @Override\n    public boolean isWritable() {\n        return false;\n    }\n\n    @Override\n    public long bytesBeforeUnwritable() {\n        return 0;\n    }\n\n    @Override\n    public long bytesBeforeWritable() {\n        return 0;\n    }\n\n    @Override\n    public Unsafe unsafe() {\n        return null;\n    }\n\n    @Override\n    public ChannelPipeline pipeline() {\n        return null;\n    }\n\n    @Override\n    public ByteBufAllocator alloc() {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture bind(SocketAddress localAddress) {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture connect(SocketAddress remoteAddress) {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture disconnect() {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture close() {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture deregister() {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture disconnect(ChannelPromise promise) {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture close(ChannelPromise promise) {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture deregister(ChannelPromise promise) {\n        return null;\n    }\n\n    @Override\n    public Channel read() {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture write(Object msg) {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture write(Object msg, ChannelPromise promise) {\n        return null;\n    }\n\n    @Override\n    public Channel flush() {\n        return null;\n    }\n\n    @Override\n    public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {\n        return null;\n    }\n\n    @Override\n    public <T> Attribute<T> attr(AttributeKey<T> key) {\n        return attributeMap.attr(key);\n    }\n\n    @Override\n    public <T> boolean hasAttr(AttributeKey<T> key) {\n        return attributeMap.hasAttr(key);\n    }\n\n    @Override\n    public int compareTo(Channel o) {\n        return 0;\n    }\n\n    public List<Object> getReceivedObjects() {\n        return receivedObjects;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.util;\n\nimport org.apache.dubbo.qos.command.GreetingCommand;\nimport org.apache.dubbo.qos.command.impl.ChangeTelnet;\nimport org.apache.dubbo.qos.command.impl.CountTelnet;\nimport org.apache.dubbo.qos.command.impl.DefaultMetricsReporterCmd;\nimport org.apache.dubbo.qos.command.impl.DisableDetailProfiler;\nimport org.apache.dubbo.qos.command.impl.DisableRouterSnapshot;\nimport org.apache.dubbo.qos.command.impl.DisableSimpleProfiler;\nimport org.apache.dubbo.qos.command.impl.EnableDetailProfiler;\nimport org.apache.dubbo.qos.command.impl.EnableRouterSnapshot;\nimport org.apache.dubbo.qos.command.impl.EnableSimpleProfiler;\nimport org.apache.dubbo.qos.command.impl.GetAddress;\nimport org.apache.dubbo.qos.command.impl.GetConfig;\nimport org.apache.dubbo.qos.command.impl.GetEnabledRouterSnapshot;\nimport org.apache.dubbo.qos.command.impl.GetOpenAPI;\nimport org.apache.dubbo.qos.command.impl.GetRecentRouterSnapshot;\nimport org.apache.dubbo.qos.command.impl.GetRouterSnapshot;\nimport org.apache.dubbo.qos.command.impl.GracefulShutdown;\nimport org.apache.dubbo.qos.command.impl.Help;\nimport org.apache.dubbo.qos.command.impl.InvokeTelnet;\nimport org.apache.dubbo.qos.command.impl.Live;\nimport org.apache.dubbo.qos.command.impl.LoggerInfo;\nimport org.apache.dubbo.qos.command.impl.Ls;\nimport org.apache.dubbo.qos.command.impl.Offline;\nimport org.apache.dubbo.qos.command.impl.OfflineApp;\nimport org.apache.dubbo.qos.command.impl.OfflineInterface;\nimport org.apache.dubbo.qos.command.impl.Online;\nimport org.apache.dubbo.qos.command.impl.OnlineApp;\nimport org.apache.dubbo.qos.command.impl.OnlineInterface;\nimport org.apache.dubbo.qos.command.impl.PortTelnet;\nimport org.apache.dubbo.qos.command.impl.PublishMetadata;\nimport org.apache.dubbo.qos.command.impl.PwdTelnet;\nimport org.apache.dubbo.qos.command.impl.Quit;\nimport org.apache.dubbo.qos.command.impl.Ready;\nimport org.apache.dubbo.qos.command.impl.SelectTelnet;\nimport org.apache.dubbo.qos.command.impl.SerializeCheckStatus;\nimport org.apache.dubbo.qos.command.impl.SerializeWarnedClasses;\nimport org.apache.dubbo.qos.command.impl.SetProfilerWarnPercent;\nimport org.apache.dubbo.qos.command.impl.ShutdownTelnet;\nimport org.apache.dubbo.qos.command.impl.Startup;\nimport org.apache.dubbo.qos.command.impl.SwitchLogLevel;\nimport org.apache.dubbo.qos.command.impl.SwitchLogger;\nimport org.apache.dubbo.qos.command.impl.Version;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsInAnyOrder;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass CommandHelperTest {\n    private CommandHelper commandHelper = new CommandHelper(FrameworkModel.defaultModel());\n\n    @Test\n    void testHasCommand() {\n        assertTrue(commandHelper.hasCommand(\"greeting\"));\n        assertFalse(commandHelper.hasCommand(\"not-exiting\"));\n    }\n\n    @Test\n    void testGetAllCommandClass() {\n        List<Class<?>> classes = commandHelper.getAllCommandClass();\n\n        // update this list when introduce a new command\n        List<Class<?>> expectedClasses = new LinkedList<>();\n        expectedClasses.add(GreetingCommand.class);\n        expectedClasses.add(Help.class);\n        expectedClasses.add(Live.class);\n        expectedClasses.add(Ls.class);\n        expectedClasses.add(Offline.class);\n        expectedClasses.add(OfflineApp.class);\n        expectedClasses.add(OfflineInterface.class);\n        expectedClasses.add(Online.class);\n        expectedClasses.add(OnlineApp.class);\n        expectedClasses.add(OnlineInterface.class);\n        expectedClasses.add(PublishMetadata.class);\n        expectedClasses.add(Quit.class);\n        expectedClasses.add(Ready.class);\n        expectedClasses.add(Startup.class);\n        expectedClasses.add(Version.class);\n        expectedClasses.add(ChangeTelnet.class);\n        expectedClasses.add(CountTelnet.class);\n        expectedClasses.add(InvokeTelnet.class);\n        expectedClasses.add(SelectTelnet.class);\n        expectedClasses.add(PortTelnet.class);\n        expectedClasses.add(PwdTelnet.class);\n        expectedClasses.add(ShutdownTelnet.class);\n        expectedClasses.add(EnableDetailProfiler.class);\n        expectedClasses.add(DisableDetailProfiler.class);\n        expectedClasses.add(EnableSimpleProfiler.class);\n        expectedClasses.add(DisableSimpleProfiler.class);\n        expectedClasses.add(SetProfilerWarnPercent.class);\n        expectedClasses.add(GetRouterSnapshot.class);\n        expectedClasses.add(GetEnabledRouterSnapshot.class);\n        expectedClasses.add(EnableRouterSnapshot.class);\n        expectedClasses.add(DisableRouterSnapshot.class);\n        expectedClasses.add(GetRecentRouterSnapshot.class);\n        expectedClasses.add(LoggerInfo.class);\n        expectedClasses.add(SwitchLogger.class);\n        expectedClasses.add(SwitchLogLevel.class);\n        expectedClasses.add(SerializeCheckStatus.class);\n        expectedClasses.add(SerializeWarnedClasses.class);\n        expectedClasses.add(GetConfig.class);\n        expectedClasses.add(GetAddress.class);\n        expectedClasses.add(GracefulShutdown.class);\n        expectedClasses.add(DefaultMetricsReporterCmd.class);\n        expectedClasses.add(GetOpenAPI.class);\n        assertThat(classes, containsInAnyOrder(expectedClasses.toArray(new Class<?>[0])));\n    }\n\n    @Test\n    void testGetCommandClass() {\n        assertThat(commandHelper.getCommandClass(\"greeting\"), equalTo(GreetingCommand.class));\n        assertNull(commandHelper.getCommandClass(\"not-exiting\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/SerializeCheckUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.util;\n\nimport org.apache.dubbo.common.utils.SerializeCheckStatus;\nimport org.apache.dubbo.common.utils.SerializeSecurityManager;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass SerializeCheckUtilsTest {\n    @Test\n    void testNotify() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n\n        SerializeSecurityManager ssm = frameworkModel.getBeanFactory().getBean(SerializeSecurityManager.class);\n\n        SerializeCheckUtils serializeCheckUtils = new SerializeCheckUtils(frameworkModel);\n\n        ssm.addToAllowed(\"Test1234\");\n        Assertions.assertTrue(serializeCheckUtils.getAllowedList().contains(\"Test1234\"));\n\n        ssm.addToDisAllowed(\"Test4321\");\n        Assertions.assertTrue(serializeCheckUtils.getDisAllowedList().contains(\"Test4321\"));\n\n        ssm.setCheckSerializable(false);\n        Assertions.assertFalse(serializeCheckUtils.isCheckSerializable());\n\n        ssm.setCheckStatus(SerializeCheckStatus.DISABLE);\n        Assertions.assertEquals(SerializeCheckStatus.DISABLE, serializeCheckUtils.getStatus());\n\n        frameworkModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/ServiceCheckUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.command.util;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.qos.DemoService;\nimport org.apache.dubbo.qos.DemoServiceImpl;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.client.migration.MigrationInvoker;\nimport org.apache.dubbo.registry.client.migration.model.MigrationStep;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.model.ServiceMetadata;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * Test for ServiceCheckUtils\n */\nclass ServiceCheckUtilsTest {\n\n    private final ModuleServiceRepository repository =\n            ApplicationModel.defaultModel().getDefaultModule().getServiceRepository();\n\n    @Test\n    void testIsRegistered() {\n        DemoService demoServiceImpl = new DemoServiceImpl();\n\n        int availablePort = NetUtils.getAvailablePort();\n\n        URL url = URL.valueOf(\"tri://127.0.0.1:\" + availablePort + \"/\" + DemoService.class.getName());\n\n        ServiceDescriptor serviceDescriptor = repository.registerService(DemoService.class);\n\n        ProviderModel providerModel = new ProviderModel(\n                url.getServiceKey(),\n                demoServiceImpl,\n                serviceDescriptor,\n                new ServiceMetadata(),\n                ClassUtils.getClassLoader(DemoService.class));\n        repository.registerProvider(providerModel);\n\n        String url1 =\n                \"service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=66099&registry=zookeeper&timestamp=1654588337653\";\n        String url2 =\n                \"zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=66099&timestamp=1654588337653\";\n        providerModel.getStatedUrl().add(new ProviderModel.RegisterStatedURL(url, URL.valueOf(url1), true));\n        providerModel.getStatedUrl().add(new ProviderModel.RegisterStatedURL(url, URL.valueOf(url2), false));\n\n        Assertions.assertEquals(\"zookeeper-A(Y)/zookeeper-I(N)\", ServiceCheckUtils.getRegisterStatus(providerModel));\n    }\n\n    @Test\n    void testGetConsumerAddressNum() {\n        ConsumerModel consumerModel = Mockito.mock(ConsumerModel.class);\n        ServiceMetadata serviceMetadata = Mockito.mock(ServiceMetadata.class);\n        Mockito.when(consumerModel.getServiceMetadata()).thenReturn(serviceMetadata);\n        String registry1 =\n                \"service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=66099&registry=zookeeper&timestamp=1654588337653\";\n        String registry2 =\n                \"zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=66099&timestamp=1654588337653\";\n        String registry3 =\n                \"nacos://127.0.0.1:8848/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=66099&timestamp=1654588337653\";\n        Map<Registry, MigrationInvoker<?>> invokerMap = new LinkedHashMap<>();\n        {\n            Registry registry = Mockito.mock(Registry.class);\n            Mockito.when(registry.getUrl()).thenReturn(URL.valueOf(registry1));\n            MigrationInvoker<?> migrationInvoker = Mockito.mock(MigrationInvoker.class);\n            Mockito.when(migrationInvoker.getMigrationStep()).thenReturn(MigrationStep.FORCE_APPLICATION);\n            ClusterInvoker serviceDiscoveryInvoker = Mockito.mock(ClusterInvoker.class);\n            Mockito.when(migrationInvoker.getServiceDiscoveryInvoker()).thenReturn(serviceDiscoveryInvoker);\n            Directory<?> sdDirectory = Mockito.mock(Directory.class);\n            Mockito.when(serviceDiscoveryInvoker.getDirectory()).thenReturn(sdDirectory);\n            List sdInvokers = Mockito.mock(List.class);\n            Mockito.when(sdDirectory.getAllInvokers()).thenReturn(sdInvokers);\n            Mockito.when(sdInvokers.size()).thenReturn(5);\n            invokerMap.put(registry, migrationInvoker);\n        }\n\n        {\n            Registry registry = Mockito.mock(Registry.class);\n            Mockito.when(registry.getUrl()).thenReturn(URL.valueOf(registry2));\n            MigrationInvoker<?> migrationInvoker = Mockito.mock(MigrationInvoker.class);\n            Mockito.when(migrationInvoker.getMigrationStep()).thenReturn(MigrationStep.APPLICATION_FIRST);\n            ClusterInvoker serviceDiscoveryInvoker = Mockito.mock(ClusterInvoker.class);\n            Mockito.when(migrationInvoker.getServiceDiscoveryInvoker()).thenReturn(serviceDiscoveryInvoker);\n            Directory<?> sdDirectory = Mockito.mock(Directory.class);\n            Mockito.when(serviceDiscoveryInvoker.getDirectory()).thenReturn(sdDirectory);\n            List sdInvokers = Mockito.mock(List.class);\n            Mockito.when(sdDirectory.getAllInvokers()).thenReturn(sdInvokers);\n            Mockito.when(sdInvokers.size()).thenReturn(0);\n\n            ClusterInvoker invoker = Mockito.mock(ClusterInvoker.class);\n            Mockito.when(migrationInvoker.getInvoker()).thenReturn(invoker);\n            Directory<?> directory = Mockito.mock(Directory.class);\n            Mockito.when(invoker.getDirectory()).thenReturn(directory);\n            List invokers = Mockito.mock(List.class);\n            Mockito.when(directory.getAllInvokers()).thenReturn(invokers);\n            Mockito.when(invokers.size()).thenReturn(10);\n            invokerMap.put(registry, migrationInvoker);\n        }\n\n        {\n            Registry registry = Mockito.mock(Registry.class);\n            Mockito.when(registry.getUrl()).thenReturn(URL.valueOf(registry3));\n            MigrationInvoker<?> migrationInvoker = Mockito.mock(MigrationInvoker.class);\n            Mockito.when(migrationInvoker.getMigrationStep()).thenReturn(MigrationStep.FORCE_INTERFACE);\n            ClusterInvoker invoker = Mockito.mock(ClusterInvoker.class);\n            Mockito.when(migrationInvoker.getInvoker()).thenReturn(invoker);\n            Directory<?> directory = Mockito.mock(Directory.class);\n            Mockito.when(invoker.getDirectory()).thenReturn(directory);\n            List invokers = Mockito.mock(List.class);\n            Mockito.when(directory.getAllInvokers()).thenReturn(invokers);\n            Mockito.when(invokers.size()).thenReturn(10);\n            invokerMap.put(registry, migrationInvoker);\n        }\n\n        Mockito.when(serviceMetadata.getAttribute(\"currentClusterInvoker\")).thenReturn(invokerMap);\n\n        assertEquals(\n                \"zookeeper-A(5)/zookeeper-AF(I-10,A-0)/nacos-I(10)\",\n                ServiceCheckUtils.getConsumerAddressNum(consumerModel));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/ChangeTelnetHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.qos.legacy.service.DemoService;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\n/**\n * ChangeTelnetHandlerTest.java\n */\nclass ChangeTelnetHandlerTest {\n\n    private static TelnetHandler change = new ChangeTelnetHandler();\n    private Channel mockChannel;\n    private Invoker<DemoService> mockInvoker;\n\n    private static int portIncrease;\n\n    @AfterAll\n    public static void tearDown() {}\n\n    @SuppressWarnings(\"unchecked\")\n    @BeforeEach\n    public void setUp() {\n        mockChannel = mock(Channel.class);\n        mockInvoker = mock(Invoker.class);\n        given(mockChannel.getAttribute(\"telnet.service\"))\n                .willReturn(\"org.apache.dubbo.rpc.protocol.dubbo.support.DemoService\");\n        mockChannel.setAttribute(\"telnet.service\", \"DemoService\");\n        givenLastCall();\n        mockChannel.setAttribute(\"telnet.service\", \"org.apache.dubbo.rpc.protocol.dubbo.support.DemoService\");\n        givenLastCall();\n        mockChannel.setAttribute(\"telnet.service\", \"demo\");\n        givenLastCall();\n        mockChannel.removeAttribute(\"telnet.service\");\n        givenLastCall();\n        given(mockInvoker.getInterface()).willReturn(DemoService.class);\n        given(mockInvoker.getUrl()).willReturn(URL.valueOf(\"dubbo://127.0.0.1:\" + (20994 + portIncrease++) + \"/demo\"));\n    }\n\n    private void givenLastCall() {}\n\n    @AfterEach\n    public void after() {\n        FrameworkModel.destroyAll();\n        reset(mockChannel, mockInvoker);\n    }\n\n    @Test\n    void testChangeSimpleName() throws RemotingException {\n        ExtensionLoader.getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n        String result = change.telnet(mockChannel, \"DemoService\");\n        assertEquals(\"Used the DemoService as default.\\r\\nYou can cancel default service by command: cd /\", result);\n    }\n\n    @Test\n    void testChangeName() throws RemotingException {\n        ExtensionLoader.getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n        String result = change.telnet(mockChannel, \"org.apache.dubbo.qos.legacy.service.DemoService\");\n        assertEquals(\n                \"Used the org.apache.dubbo.qos.legacy.service.DemoService as default.\\r\\nYou can cancel default service by command: cd /\",\n                result);\n    }\n\n    @Test\n    void testChangePath() throws RemotingException {\n        ExtensionLoader.getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n        String result = change.telnet(mockChannel, \"demo\");\n        assertEquals(\"Used the demo as default.\\r\\nYou can cancel default service by command: cd /\", result);\n    }\n\n    @Test\n    void testChangeMessageNull() throws RemotingException {\n        String result = change.telnet(mockChannel, null);\n        assertEquals(\"Please input service name, eg: \\r\\ncd XxxService\\r\\ncd com.xxx.XxxService\", result);\n    }\n\n    @Test\n    void testChangeServiceNotExport() throws RemotingException {\n        String result = change.telnet(mockChannel, \"demo\");\n        assertEquals(\"No such service demo\", result);\n    }\n\n    @Test\n    void testChangeCancel() throws RemotingException {\n        String result = change.telnet(mockChannel, \"..\");\n        assertEquals(\"Cancelled default service org.apache.dubbo.rpc.protocol.dubbo.support.DemoService.\", result);\n    }\n\n    @Test\n    void testChangeCancel2() throws RemotingException {\n        String result = change.telnet(mockChannel, \"/\");\n        assertEquals(\"Cancelled default service org.apache.dubbo.rpc.protocol.dubbo.support.DemoService.\", result);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/LogTelnetHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.mock;\n\n/**\n * LogTelnetHandlerTest.java\n */\nclass LogTelnetHandlerTest {\n\n    private static TelnetHandler log = new LogTelnetHandler();\n    private Channel mockChannel;\n\n    @Test\n    void testChangeLogLevel() throws RemotingException {\n        mockChannel = mock(Channel.class);\n\n        String result = log.telnet(mockChannel, \"error\");\n        assertTrue(result.contains(\"\\r\\nCURRENT LOG LEVEL:ERROR\"));\n        String result2 = log.telnet(mockChannel, \"warn\");\n        assertTrue(result2.contains(\"\\r\\nCURRENT LOG LEVEL:WARN\"));\n    }\n\n    @Test\n    void testPrintLog() throws RemotingException {\n        mockChannel = mock(Channel.class);\n\n        String result = log.telnet(mockChannel, \"100\");\n        assertTrue(result.contains(\"CURRENT LOG APPENDER\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/ProtocolUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\n\n/**\n * TODO Comment of ProtocolUtils\n */\npublic class ProtocolUtils {\n\n    public static <T> T refer(Class<T> type, String url) {\n        return refer(type, URL.valueOf(url));\n    }\n\n    public static <T> T refer(Class<T> type, URL url) {\n        Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n        ProxyFactory proxy =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n        return proxy.getProxy(protocol.refer(type, url));\n    }\n\n    public static <T> Exporter<T> export(T instance, Class<T> type, String url) {\n        return export(instance, type, URL.valueOf(url));\n    }\n\n    public static <T> Exporter<T> export(T instance, Class<T> type, URL url) {\n        Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();\n        ProxyFactory proxy =\n                ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n        return protocol.export(proxy.getInvoker(instance, type, url));\n    }\n\n    public static void closeAll() {\n        DubboProtocol.getDubboProtocol().destroy();\n        ExtensionLoader.getExtensionLoader(Protocol.class).destroy();\n        FrameworkModel.destroyAll();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/TraceTelnetHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.qos.legacy.service.DemoService;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;\nimport org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter;\n\nimport java.lang.reflect.Field;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\nclass TraceTelnetHandlerTest {\n\n    private TelnetHandler handler;\n    private Channel mockChannel;\n    private Invoker<DemoService> mockInvoker;\n    private URL url = URL.valueOf(\"dubbo://127.0.0.1:20884/demo\");\n\n    @BeforeEach\n    public void setUp() {\n        handler = new TraceTelnetHandler();\n        mockChannel = mock(Channel.class);\n        mockInvoker = mock(Invoker.class);\n        given(mockInvoker.getInterface()).willReturn(DemoService.class);\n        given(mockInvoker.getUrl()).willReturn(url);\n    }\n\n    @AfterEach\n    public void tearDown() {\n        reset(mockChannel, mockInvoker);\n        FrameworkModel.destroyAll();\n    }\n\n    @Test\n    void testTraceTelnetAddTracer() throws Exception {\n        String method = \"sayHello\";\n        String message = \"org.apache.dubbo.qos.legacy.service.DemoService sayHello 1\";\n        Class<?> type = DemoService.class;\n\n        ExtensionLoader.getExtensionLoader(Protocol.class)\n                .getExtension(DubboProtocol.NAME)\n                .export(mockInvoker);\n        handler.telnet(mockChannel, message);\n\n        String key = type.getName() + \".\" + method;\n        Field tracers = TraceFilter.class.getDeclaredField(\"TRACERS\");\n        tracers.setAccessible(true);\n        ConcurrentHashMap<String, Set<Channel>> map =\n                (ConcurrentHashMap<String, Set<Channel>>) tracers.get(new ConcurrentHashMap<String, Set<Channel>>());\n\n        Set<Channel> channels = map.getOrDefault(key, null);\n        Assertions.assertNotNull(channels);\n\n        Assertions.assertTrue(channels.contains(mockChannel));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/channel/MockChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.channel;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\n\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\n\npublic class MockChannel implements Channel {\n    public static final String ERROR_WHEN_SEND = \"error_when_send\";\n    InetSocketAddress localAddress;\n    InetSocketAddress remoteAddress;\n    private URL remoteUrl;\n    private ChannelHandler handler;\n    private boolean isClosed;\n    private volatile boolean closing;\n    private Map<String, Object> attributes = new HashMap<String, Object>(1);\n    private List<Object> receivedObjects = new LinkedList<>();\n    private CountDownLatch latch;\n\n    public MockChannel() {}\n\n    public MockChannel(URL remoteUrl) {\n        this.remoteUrl = remoteUrl;\n    }\n\n    public MockChannel(URL remoteUrl, CountDownLatch latch) {\n        this.remoteUrl = remoteUrl;\n        this.latch = latch;\n    }\n\n    public MockChannel(ChannelHandler handler) {\n        this.handler = handler;\n    }\n\n    @Override\n    public URL getUrl() {\n        return remoteUrl;\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        return handler;\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return localAddress;\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        if (remoteUrl.getParameter(ERROR_WHEN_SEND, Boolean.FALSE)) {\n            throw new RemotingException(localAddress, remoteAddress, \"mock error\");\n        } else {\n            receivedObjects.add(message);\n            if (latch != null) {\n                latch.countDown();\n            }\n        }\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        send(message);\n    }\n\n    @Override\n    public void close() {\n        close(0);\n    }\n\n    @Override\n    public void close(int timeout) {\n        isClosed = true;\n    }\n\n    @Override\n    public void startClose() {\n        closing = true;\n    }\n\n    @Override\n    public boolean isClosed() {\n        return isClosed;\n    }\n\n    @Override\n    public InetSocketAddress getRemoteAddress() {\n        return remoteAddress;\n    }\n\n    @Override\n    public boolean isConnected() {\n        return isClosed;\n    }\n\n    @Override\n    public boolean hasAttribute(String key) {\n        return attributes.containsKey(key);\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        return attributes.get(key);\n    }\n\n    @Override\n    public void setAttribute(String key, Object value) {\n        attributes.put(key, value);\n    }\n\n    @Override\n    public void removeAttribute(String key) {\n        attributes.remove(key);\n    }\n\n    public List<Object> getReceivedObjects() {\n        return receivedObjects;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/CustomArgument.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service;\n\nimport java.io.Serializable;\n\n@SuppressWarnings(\"serial\")\npublic class CustomArgument implements Serializable {\n\n    Type type;\n    String name;\n\n    public CustomArgument() {}\n\n    public CustomArgument(Type type, String name) {\n        super();\n        this.type = type;\n        this.name = name;\n    }\n\n    public Type getType() {\n        return type;\n    }\n\n    public void setType(Type type) {\n        this.type = type;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service;\n\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * <code>TestService</code>\n */\npublic interface DemoService {\n    void sayHello(String name);\n\n    Set<String> keys(Map<String, String> map);\n\n    String echo(String text);\n\n    Map echo(Map map);\n\n    long timestamp();\n\n    String getThreadName();\n\n    int getSize(String[] strs);\n\n    int getSize(Object[] os);\n\n    Object invoke(String service, String method) throws Exception;\n\n    int stringLength(String str);\n\n    Type enumlength(Type... types);\n\n    Type getType(Type type);\n\n    String get(CustomArgument arg1);\n\n    byte getbyte(byte arg);\n\n    void nonSerializedParameter(NonSerialized ns);\n\n    NonSerialized returnNonSerialized();\n\n    long add(int a, long b);\n\n    int getPerson(Person person);\n\n    int getPerson(Person person1, Person perso2);\n\n    String getPerson(Man man);\n\n    String getRemoteApplicationName();\n\n    Map<Integer, Object> getMap(Map<Integer, Object> map);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service;\n\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class DemoServiceImpl implements DemoService {\n    private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);\n\n    public DemoServiceImpl() {\n        super();\n    }\n\n    public void sayHello(String name) {\n        logger.info(\"hello {}\", name);\n    }\n\n    public String echo(String text) {\n        return text;\n    }\n\n    public Map echo(Map map) {\n        return map;\n    }\n\n    public long timestamp() {\n        return System.currentTimeMillis();\n    }\n\n    public String getThreadName() {\n        return Thread.currentThread().getName();\n    }\n\n    public int getSize(String[] strs) {\n        if (strs == null) return -1;\n        return strs.length;\n    }\n\n    public int getSize(Object[] os) {\n        if (os == null) return -1;\n        return os.length;\n    }\n\n    public Object invoke(String service, String method) throws Exception {\n        logger.info(\n                \"RpcContext.getServerAttachment().getRemoteHost()={}\",\n                RpcContext.getServiceContext().getRemoteHost());\n        return service + \":\" + method;\n    }\n\n    public Type enumlength(Type... types) {\n        if (types.length == 0) return Type.Lower;\n        return types[0];\n    }\n\n    public Type getType(Type type) {\n        return type;\n    }\n\n    public int stringLength(String str) {\n        return str.length();\n    }\n\n    public String get(CustomArgument arg1) {\n        return arg1.toString();\n    }\n\n    public byte getbyte(byte arg) {\n        return arg;\n    }\n\n    public Person gerPerson(Person person) {\n        return person;\n    }\n\n    public Set<String> keys(Map<String, String> map) {\n        return map == null ? null : map.keySet();\n    }\n\n    public void nonSerializedParameter(NonSerialized ns) {}\n\n    public NonSerialized returnNonSerialized() {\n        return new NonSerialized();\n    }\n\n    public long add(int a, long b) {\n        return a + b;\n    }\n\n    @Override\n    public int getPerson(Person person) {\n        return person.getAge();\n    }\n\n    @Override\n    public int getPerson(Person person1, Person person2) {\n        return person1.getAge() + person2.getAge();\n    }\n\n    @Override\n    public String getPerson(Man man) {\n        return man.getName();\n    }\n\n    @Override\n    public String getRemoteApplicationName() {\n        return RpcContext.getServiceContext().getRemoteApplicationName();\n    }\n\n    @Override\n    public Map<Integer, Object> getMap(Map<Integer, Object> map) {\n        return map;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/Man.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service;\n\nimport java.io.Serializable;\n\n/**\n * Man.java\n */\npublic class Man implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n    private String name;\n    private int age;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/NonSerialized.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service;\n\npublic class NonSerialized {}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/Person.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service;\n\nimport java.io.Serializable;\n\n/**\n * Person.java\n */\npublic class Person implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n    private String name;\n    private int age;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/Type.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service;\n\npublic enum Type {\n    High,\n    Normal,\n    Lower\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/generic/DemoException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service.generic;\n\npublic class DemoException extends Exception {\n\n    private static final long serialVersionUID = -8213943026163641747L;\n\n    public DemoException() {\n        super();\n    }\n\n    public DemoException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public DemoException(String message) {\n        super(message);\n    }\n\n    public DemoException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/generic/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service.generic;\n\nimport java.util.List;\n\npublic interface DemoService {\n\n    String sayName(String name);\n\n    void throwDemoException() throws DemoException;\n\n    List<User> getUsers(List<User> users);\n\n    int echo(int i);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/generic/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service.generic;\n\nimport java.util.List;\n\npublic class DemoServiceImpl implements DemoService {\n\n    public String sayName(String name) {\n        return \"say:\" + name;\n    }\n\n    public void throwDemoException() throws DemoException {\n        throw new DemoException(\"DemoServiceImpl\");\n    }\n\n    public List<User> getUsers(List<User> users) {\n        return users;\n    }\n\n    public int echo(int i) {\n        return i;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/generic/GenericServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service.generic;\n\nimport org.apache.dubbo.common.beanutil.JavaBeanAccessor;\nimport org.apache.dubbo.common.beanutil.JavaBeanDescriptor;\nimport org.apache.dubbo.common.beanutil.JavaBeanSerializeUtil;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.serialize.Serialization;\nimport org.apache.dubbo.common.utils.ReflectUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.ProtocolConfig;\nimport org.apache.dubbo.config.ReferenceConfig;\nimport org.apache.dubbo.config.RegistryConfig;\nimport org.apache.dubbo.config.ServiceConfig;\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.rpc.service.GenericException;\nimport org.apache.dubbo.rpc.service.GenericService;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_BEAN;\nimport static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;\n\n@Disabled(\"Keeps failing on Travis, but can not be reproduced locally.\")\nclass GenericServiceTest {\n\n    @Test\n    void testGenericServiceException() {\n        ServiceConfig<GenericService> service = new ServiceConfig<GenericService>();\n        service.setInterface(DemoService.class.getName());\n        service.setRef(new GenericService() {\n\n            public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException {\n                if (\"sayName\".equals(method)) {\n                    return \"Generic \" + args[0];\n                }\n                if (\"throwDemoException\".equals(method)) {\n                    throw new GenericException(DemoException.class.getName(), \"Generic\");\n                }\n                if (\"getUsers\".equals(method)) {\n                    return args[0];\n                }\n                return null;\n            }\n        });\n\n        ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>();\n        reference.setInterface(DemoService.class);\n        reference.setUrl(\"dubbo://127.0.0.1:29581?generic=true&timeout=3000\");\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(\"generic-test\"))\n                .registry(new RegistryConfig(\"N/A\"))\n                .protocol(new ProtocolConfig(\"dubbo\", 29581))\n                .service(service)\n                .reference(reference);\n\n        bootstrap.start();\n\n        try {\n            DemoService demoService = bootstrap.getCache().get(reference);\n            // say name\n            Assertions.assertEquals(\"Generic Haha\", demoService.sayName(\"Haha\"));\n            // get users\n            List<User> users = new ArrayList<User>();\n            users.add(new User(\"Aaa\"));\n            users = demoService.getUsers(users);\n            Assertions.assertEquals(\"Aaa\", users.get(0).getName());\n            // throw demo exception\n            try {\n                demoService.throwDemoException();\n                Assertions.fail();\n            } catch (DemoException e) {\n                Assertions.assertEquals(\"Generic\", e.getMessage());\n            }\n        } finally {\n            bootstrap.stop();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void testGenericReferenceException() {\n        ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();\n        service.setInterface(DemoService.class.getName());\n        service.setRef(new DemoServiceImpl());\n\n        ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();\n        reference.setInterface(DemoService.class);\n        reference.setUrl(\"dubbo://127.0.0.1:29581?scope=remote&timeout=3000\");\n        reference.setGeneric(true);\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(\"generic-test\"))\n                .registry(new RegistryConfig(\"N/A\"))\n                .protocol(new ProtocolConfig(\"dubbo\", 29581))\n                .service(service)\n                .reference(reference);\n\n        bootstrap.start();\n\n        try {\n            GenericService genericService = bootstrap.getCache().get(reference);\n\n            List<Map<String, Object>> users = new ArrayList<Map<String, Object>>();\n            Map<String, Object> user = new HashMap<String, Object>();\n            user.put(\"class\", \"org.apache.dubbo.config.api.User\");\n            user.put(\"name\", \"actual.provider\");\n            users.add(user);\n            users = (List<Map<String, Object>>)\n                    genericService.$invoke(\"getUsers\", new String[] {List.class.getName()}, new Object[] {users});\n            Assertions.assertEquals(1, users.size());\n            Assertions.assertEquals(\"actual.provider\", users.get(0).get(\"name\"));\n\n        } finally {\n            bootstrap.stop();\n        }\n    }\n\n    @Test\n    void testGenericSerializationJava() throws Exception {\n        ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();\n        service.setInterface(DemoService.class.getName());\n        DemoServiceImpl ref = new DemoServiceImpl();\n        service.setRef(ref);\n\n        ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();\n        reference.setInterface(DemoService.class);\n        reference.setUrl(\"dubbo://127.0.0.1:29581?scope=remote&timeout=3000\");\n        reference.setGeneric(GENERIC_SERIALIZATION_NATIVE_JAVA);\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(\"generic-test\"))\n                .registry(new RegistryConfig(\"N/A\"))\n                .protocol(new ProtocolConfig(\"dubbo\", 29581))\n                .service(service)\n                .reference(reference);\n\n        bootstrap.start();\n\n        try {\n            GenericService genericService = bootstrap.getCache().get(reference);\n            String name = \"kimi\";\n            ByteArrayOutputStream bos = new ByteArrayOutputStream(512);\n            ExtensionLoader.getExtensionLoader(Serialization.class)\n                    .getExtension(\"nativejava\")\n                    .serialize(null, bos)\n                    .writeObject(name);\n            byte[] arg = bos.toByteArray();\n            Object obj = genericService.$invoke(\"sayName\", new String[] {String.class.getName()}, new Object[] {arg});\n            Assertions.assertTrue(obj instanceof byte[]);\n            byte[] result = (byte[]) obj;\n            Assertions.assertEquals(\n                    ref.sayName(name),\n                    ExtensionLoader.getExtensionLoader(Serialization.class)\n                            .getExtension(\"nativejava\")\n                            .deserialize(null, new ByteArrayInputStream(result))\n                            .readObject()\n                            .toString());\n\n            // getUsers\n            List<User> users = new ArrayList<User>();\n            User user = new User();\n            user.setName(name);\n            users.add(user);\n            bos = new ByteArrayOutputStream(512);\n            ExtensionLoader.getExtensionLoader(Serialization.class)\n                    .getExtension(\"nativejava\")\n                    .serialize(null, bos)\n                    .writeObject(users);\n            obj = genericService.$invoke(\n                    \"getUsers\", new String[] {List.class.getName()}, new Object[] {bos.toByteArray()});\n            Assertions.assertTrue(obj instanceof byte[]);\n            result = (byte[]) obj;\n            Assertions.assertEquals(\n                    users,\n                    ExtensionLoader.getExtensionLoader(Serialization.class)\n                            .getExtension(\"nativejava\")\n                            .deserialize(null, new ByteArrayInputStream(result))\n                            .readObject());\n\n            // echo(int)\n            bos = new ByteArrayOutputStream(512);\n            ExtensionLoader.getExtensionLoader(Serialization.class)\n                    .getExtension(\"nativejava\")\n                    .serialize(null, bos)\n                    .writeObject(Integer.MAX_VALUE);\n            obj = genericService.$invoke(\"echo\", new String[] {int.class.getName()}, new Object[] {bos.toByteArray()});\n            Assertions.assertTrue(obj instanceof byte[]);\n            Assertions.assertEquals(\n                    Integer.MAX_VALUE,\n                    ExtensionLoader.getExtensionLoader(Serialization.class)\n                            .getExtension(\"nativejava\")\n                            .deserialize(null, new ByteArrayInputStream((byte[]) obj))\n                            .readObject());\n\n        } finally {\n            bootstrap.stop();\n        }\n    }\n\n    @Test\n    void testGenericInvokeWithBeanSerialization() {\n        ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();\n        service.setInterface(DemoService.class);\n        DemoServiceImpl impl = new DemoServiceImpl();\n        service.setRef(impl);\n\n        ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();\n        reference.setInterface(DemoService.class);\n        reference.setUrl(\"dubbo://127.0.0.1:29581?scope=remote&timeout=3000\");\n        reference.setGeneric(GENERIC_SERIALIZATION_BEAN);\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(\"generic-test\"))\n                .registry(new RegistryConfig(\"N/A\"))\n                .protocol(new ProtocolConfig(\"dubbo\", 29581))\n                .service(service)\n                .reference(reference);\n\n        bootstrap.start();\n\n        try {\n            GenericService genericService = bootstrap.getCache().get(reference);\n            User user = new User();\n            user.setName(\"zhangsan\");\n            List<User> users = new ArrayList<User>();\n            users.add(user);\n            Object result =\n                    genericService.$invoke(\"getUsers\", new String[] {ReflectUtils.getName(List.class)}, new Object[] {\n                        JavaBeanSerializeUtil.serialize(users, JavaBeanAccessor.METHOD)\n                    });\n            Assertions.assertTrue(result instanceof JavaBeanDescriptor);\n            JavaBeanDescriptor descriptor = (JavaBeanDescriptor) result;\n            Assertions.assertTrue(descriptor.isCollectionType());\n            Assertions.assertEquals(1, descriptor.propertySize());\n            descriptor = (JavaBeanDescriptor) descriptor.getProperty(0);\n            Assertions.assertTrue(descriptor.isBeanType());\n            Assertions.assertEquals(\n                    user.getName(), ((JavaBeanDescriptor) descriptor.getProperty(\"name\")).getPrimitiveProperty());\n        } finally {\n            bootstrap.stop();\n        }\n    }\n\n    @Test\n    void testGenericImplementationWithBeanSerialization() {\n        final AtomicReference reference = new AtomicReference();\n\n        ServiceConfig<GenericService> service = new ServiceConfig<GenericService>();\n        service.setInterface(DemoService.class.getName());\n        service.setRef(new GenericService() {\n\n            public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException {\n                if (\"getUsers\".equals(method)) {\n                    GenericParameter arg = new GenericParameter();\n                    arg.method = method;\n                    arg.parameterTypes = parameterTypes;\n                    arg.arguments = args;\n                    reference.set(arg);\n                    return args[0];\n                }\n                if (\"sayName\".equals(method)) {\n                    return null;\n                }\n                return args;\n            }\n        });\n\n        ReferenceConfig<DemoService> ref = null;\n        ref = new ReferenceConfig<DemoService>();\n        ref.setInterface(DemoService.class);\n        ref.setUrl(\"dubbo://127.0.0.1:29581?scope=remote&generic=bean&timeout=3000\");\n\n        DubboBootstrap bootstrap = DubboBootstrap.getInstance()\n                .application(new ApplicationConfig(\"generic-test\"))\n                .registry(new RegistryConfig(\"N/A\"))\n                .protocol(new ProtocolConfig(\"dubbo\", 29581))\n                .service(service)\n                .reference(ref);\n\n        bootstrap.start();\n\n        try {\n            DemoService demoService = bootstrap.getCache().get(ref);\n            User user = new User();\n            user.setName(\"zhangsan\");\n            List<User> users = new ArrayList<User>();\n            users.add(user);\n            List<User> result = demoService.getUsers(users);\n            Assertions.assertEquals(users.size(), result.size());\n            Assertions.assertEquals(user.getName(), result.get(0).getName());\n\n            GenericParameter gp = (GenericParameter) reference.get();\n            Assertions.assertEquals(\"getUsers\", gp.method);\n            Assertions.assertEquals(1, gp.parameterTypes.length);\n            Assertions.assertEquals(ReflectUtils.getName(List.class), gp.parameterTypes[0]);\n            Assertions.assertEquals(1, gp.arguments.length);\n            Assertions.assertTrue(gp.arguments[0] instanceof JavaBeanDescriptor);\n            JavaBeanDescriptor descriptor = (JavaBeanDescriptor) gp.arguments[0];\n            Assertions.assertTrue(descriptor.isCollectionType());\n            Assertions.assertEquals(ArrayList.class.getName(), descriptor.getClassName());\n            Assertions.assertEquals(1, descriptor.propertySize());\n            descriptor = (JavaBeanDescriptor) descriptor.getProperty(0);\n            Assertions.assertTrue(descriptor.isBeanType());\n            Assertions.assertEquals(User.class.getName(), descriptor.getClassName());\n            Assertions.assertEquals(\n                    user.getName(), ((JavaBeanDescriptor) descriptor.getProperty(\"name\")).getPrimitiveProperty());\n            Assertions.assertNull(demoService.sayName(\"zhangsan\"));\n        } finally {\n            bootstrap.stop();\n        }\n    }\n\n    protected static class GenericParameter {\n\n        String method;\n\n        String[] parameterTypes;\n\n        Object[] arguments;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/service/generic/User.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.legacy.service.generic;\n\nimport java.io.Serializable;\n\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private String name;\n\n    public User() {}\n\n    public User(String name) {\n        this.name = name;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public int hashCode() {\n        return name == null ? -1 : name.hashCode();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof User)) {\n            return false;\n        }\n        User other = (User) obj;\n        if (this == other) {\n            return true;\n        }\n        if (name != null && other.name != null) {\n            return name.equals(other.name);\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/permission/DefaultAnonymousAccessPermissionCheckerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.permission;\n\nimport org.apache.dubbo.qos.api.CommandContext;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.api.QosConfiguration;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.UnknownHostException;\n\nimport io.netty.channel.Channel;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass DefaultAnonymousAccessPermissionCheckerTest {\n    @Test\n    void testPermission() throws UnknownHostException {\n        InetAddress inetAddress = InetAddress.getByName(\"127.0.0.1\");\n\n        InetSocketAddress socketAddress = Mockito.mock(InetSocketAddress.class);\n        Mockito.when(socketAddress.getAddress()).thenReturn(inetAddress);\n        Channel channel = Mockito.mock(Channel.class);\n        Mockito.when(channel.remoteAddress()).thenReturn(socketAddress);\n        CommandContext commandContext = Mockito.mock(CommandContext.class);\n        Mockito.when(commandContext.getRemote()).thenReturn(channel);\n\n        QosConfiguration qosConfiguration = Mockito.mock(QosConfiguration.class);\n        Mockito.when(qosConfiguration.getAnonymousAccessPermissionLevel()).thenReturn(PermissionLevel.PUBLIC);\n        Mockito.when(qosConfiguration.getAcceptForeignIpWhitelistPredicate()).thenReturn(ip -> false);\n\n        Mockito.when(commandContext.getQosConfiguration()).thenReturn(qosConfiguration);\n\n        DefaultAnonymousAccessPermissionChecker checker = new DefaultAnonymousAccessPermissionChecker();\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PUBLIC));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PROTECTED));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PRIVATE));\n\n        inetAddress = InetAddress.getByName(\"1.1.1.1\");\n        Mockito.when(socketAddress.getAddress()).thenReturn(inetAddress);\n\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PUBLIC));\n        Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PROTECTED));\n        Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PRIVATE));\n\n        Mockito.when(qosConfiguration.getAnonymousAccessPermissionLevel()).thenReturn(PermissionLevel.PROTECTED);\n\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PUBLIC));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PROTECTED));\n        Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PRIVATE));\n\n        Mockito.when(qosConfiguration.getAnonymousAccessPermissionLevel()).thenReturn(PermissionLevel.NONE);\n\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));\n        Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PUBLIC));\n        Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PROTECTED));\n        Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PRIVATE));\n\n        Mockito.when(qosConfiguration.getAcceptForeignIpWhitelistPredicate()).thenReturn(ip -> true);\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PUBLIC));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PROTECTED));\n        Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PRIVATE));\n\n        Mockito.when(qosConfiguration.getAcceptForeignIpWhitelistPredicate()).thenReturn(ip -> false);\n        Mockito.when(qosConfiguration.getAnonymousAllowCommands()).thenReturn(\"test1,test2\");\n\n        Mockito.when(commandContext.getCommandName()).thenReturn(\"test1\");\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PUBLIC));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PROTECTED));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PRIVATE));\n\n        Mockito.when(commandContext.getCommandName()).thenReturn(\"test2\");\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PUBLIC));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PROTECTED));\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PRIVATE));\n\n        Mockito.when(commandContext.getCommandName()).thenReturn(\"test\");\n        Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));\n        Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PUBLIC));\n        Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PROTECTED));\n        Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PRIVATE));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/protocol/QosProtocolWrapperTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.protocol;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.qos.api.BaseCommand;\nimport org.apache.dubbo.qos.server.Server;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass QosProtocolWrapperTest {\n    private URL url = Mockito.mock(URL.class);\n    private Invoker invoker = mock(Invoker.class);\n    private Protocol protocol = mock(Protocol.class);\n    private QosProtocolWrapper wrapper;\n\n    private URL triUrl = Mockito.mock(URL.class);\n    private Invoker triInvoker = mock(Invoker.class);\n    private Protocol triProtocol = mock(Protocol.class);\n    private QosProtocolWrapper triWrapper;\n\n    private Server server;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        when(url.getParameter(QOS_ENABLE, true)).thenReturn(true);\n        when(url.getParameter(QOS_HOST)).thenReturn(\"localhost\");\n        when(url.getParameter(QOS_PORT, 22222)).thenReturn(12345);\n        when(url.getParameter(ACCEPT_FOREIGN_IP, \"false\")).thenReturn(\"false\");\n        when(url.getProtocol()).thenReturn(REGISTRY_PROTOCOL);\n        when(invoker.getUrl()).thenReturn(url);\n\n        wrapper = new QosProtocolWrapper(protocol);\n        wrapper.setFrameworkModel(FrameworkModel.defaultModel());\n\n        // url2 use tri protocol and qos.accept.foreign.ip=true\n        when(triUrl.getParameter(QOS_ENABLE, true)).thenReturn(true);\n        when(triUrl.getParameter(QOS_HOST)).thenReturn(\"localhost\");\n        when(triUrl.getParameter(QOS_PORT, 22222)).thenReturn(12345);\n        when(triUrl.getParameter(ACCEPT_FOREIGN_IP, \"false\")).thenReturn(\"true\");\n        when(triUrl.getProtocol()).thenReturn(CommonConstants.TRIPLE);\n        when(triInvoker.getUrl()).thenReturn(triUrl);\n\n        triWrapper = new QosProtocolWrapper(triProtocol);\n        triWrapper.setFrameworkModel(FrameworkModel.defaultModel());\n\n        server = FrameworkModel.defaultModel().getBeanFactory().getBean(Server.class);\n    }\n\n    @AfterEach\n    public void tearDown() throws Exception {\n        if (server.isStarted()) {\n            server.stop();\n        }\n        FrameworkModel.defaultModel().destroy();\n    }\n\n    @Test\n    void testExport() throws Exception {\n        wrapper.export(invoker);\n        assertThat(server.isStarted(), is(true));\n        assertThat(server.getHost(), is(\"localhost\"));\n        assertThat(server.getPort(), is(12345));\n        assertThat(server.isAcceptForeignIp(), is(false));\n        verify(protocol).export(invoker);\n    }\n\n    @Test\n    void testRefer() throws Exception {\n        wrapper.refer(BaseCommand.class, url);\n        assertThat(server.isStarted(), is(true));\n        assertThat(server.getHost(), is(\"localhost\"));\n        assertThat(server.getPort(), is(12345));\n        assertThat(server.isAcceptForeignIp(), is(false));\n        verify(protocol).refer(BaseCommand.class, url);\n    }\n\n    @Test\n    void testMultiProtocol() throws Exception {\n        // tri protocol start first, acceptForeignIp = true\n        triWrapper.export(triInvoker);\n        assertThat(server.isStarted(), is(true));\n        assertThat(server.getHost(), is(\"localhost\"));\n        assertThat(server.getPort(), is(12345));\n        assertThat(server.isAcceptForeignIp(), is(true));\n        verify(triProtocol).export(triInvoker);\n\n        // next registry protocol server still acceptForeignIp=true even though wrapper invoker url set false\n        wrapper.export(invoker);\n        assertThat(server.isStarted(), is(true));\n        assertThat(server.getHost(), is(\"localhost\"));\n        assertThat(server.getPort(), is(12345));\n        assertThat(server.isAcceptForeignIp(), is(true));\n        verify(protocol).export(invoker);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/CtrlCHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.qos.common.QosConstants;\n\nimport java.nio.charset.StandardCharsets;\n\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.util.CharsetUtil;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.verify;\n\npublic class CtrlCHandlerTest {\n    private byte[] CTRLC_BYTES_SEQUENCE = new byte[] {(byte) 0xff, (byte) 0xf4, (byte) 0xff, (byte) 0xfd, (byte) 0x06};\n\n    private byte[] RESPONSE_SEQUENCE = new byte[] {(byte) 0xff, (byte) 0xfc, 0x06};\n\n    @Test\n    void testMatchedExactly() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        CtrlCHandler ctrlCHandler = new CtrlCHandler();\n        ctrlCHandler.channelRead(context, Unpooled.wrappedBuffer(CTRLC_BYTES_SEQUENCE));\n        verify(context).writeAndFlush(Unpooled.wrappedBuffer(RESPONSE_SEQUENCE));\n        verify(context)\n                .writeAndFlush(Unpooled.wrappedBuffer(\n                        (QosConstants.BR_STR + QosProcessHandler.PROMPT).getBytes(CharsetUtil.UTF_8)));\n    }\n\n    @Test\n    void testMatchedNotExactly() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        CtrlCHandler ctrlCHandler = new CtrlCHandler();\n        // before 'ctrl c', user typed other command like 'help'\n        String arbitraryCommand = \"help\";\n        byte[] commandBytes = arbitraryCommand.getBytes(StandardCharsets.UTF_8);\n        ctrlCHandler.channelRead(context, Unpooled.wrappedBuffer(commandBytes, CTRLC_BYTES_SEQUENCE));\n        verify(context).writeAndFlush(Unpooled.wrappedBuffer(RESPONSE_SEQUENCE));\n        verify(context)\n                .writeAndFlush(Unpooled.wrappedBuffer(\n                        (QosConstants.BR_STR + QosProcessHandler.PROMPT).getBytes(CharsetUtil.UTF_8)));\n    }\n\n    @Test\n    void testNotMatched() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        CtrlCHandler ctrlCHandler = new CtrlCHandler();\n        String arbitraryCommand = \"help\" + QosConstants.BR_STR;\n        byte[] commandBytes = arbitraryCommand.getBytes(StandardCharsets.UTF_8);\n        ctrlCHandler.channelRead(context, Unpooled.wrappedBuffer(commandBytes));\n        verify(context, never()).writeAndFlush(Unpooled.wrappedBuffer(RESPONSE_SEQUENCE));\n        verify(context, never())\n                .writeAndFlush(Unpooled.wrappedBuffer(\n                        (QosConstants.BR_STR + QosProcessHandler.PROMPT).getBytes(CharsetUtil.UTF_8)));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/ForeignHostPermitHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.api.QosConfiguration;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandlerContext;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass ForeignHostPermitHandlerTest {\n    @Test\n    void shouldShowIpNotPermittedMsg_GivenAcceptForeignIpFalseAndEmptyWhiteList() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        Channel channel = mock(Channel.class);\n        when(context.channel()).thenReturn(channel);\n        InetAddress addr = mock(InetAddress.class);\n        when(addr.isLoopbackAddress()).thenReturn(false);\n        InetSocketAddress address = new InetSocketAddress(addr, 12345);\n        when(channel.remoteAddress()).thenReturn(address);\n        ChannelFuture future = mock(ChannelFuture.class);\n        when(context.writeAndFlush(any(ByteBuf.class))).thenReturn(future);\n        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(QosConfiguration.builder()\n                .acceptForeignIp(false)\n                .acceptForeignIpWhitelist(StringUtils.EMPTY_STRING)\n                .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())\n                .build());\n        handler.handlerAdded(context);\n        ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);\n        verify(context).writeAndFlush(captor.capture());\n        assertThat(\n                new String(captor.getValue().array()),\n                containsString(\"Foreign Ip Not Permitted, Consider Config It In Whitelist\"));\n        verify(future).addListener(ChannelFutureListener.CLOSE);\n    }\n\n    @Test\n    void shouldShowIpNotPermittedMsg_GivenAcceptForeignIpFalseAndNotMatchWhiteList() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        Channel channel = mock(Channel.class);\n        when(context.channel()).thenReturn(channel);\n        InetAddress addr = mock(InetAddress.class);\n        when(addr.isLoopbackAddress()).thenReturn(false);\n        when(addr.getHostAddress()).thenReturn(\"179.23.44.1\");\n        InetSocketAddress address = new InetSocketAddress(addr, 12345);\n        when(channel.remoteAddress()).thenReturn(address);\n        ChannelFuture future = mock(ChannelFuture.class);\n        when(context.writeAndFlush(any(ByteBuf.class))).thenReturn(future);\n        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(QosConfiguration.builder()\n                .acceptForeignIp(false)\n                .acceptForeignIpWhitelist(\"175.23.44.1 ,  192.168.1.192/26\")\n                .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())\n                .build());\n\n        handler.handlerAdded(context);\n        ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);\n        verify(context).writeAndFlush(captor.capture());\n        assertThat(\n                new String(captor.getValue().array()),\n                containsString(\"Foreign Ip Not Permitted, Consider Config It In Whitelist\"));\n        verify(future).addListener(ChannelFutureListener.CLOSE);\n    }\n\n    @Test\n    void shouldNotShowIpNotPermittedMsg_GivenAcceptForeignIpFalseAndMatchWhiteList() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        Channel channel = mock(Channel.class);\n        when(context.channel()).thenReturn(channel);\n        InetAddress addr = mock(InetAddress.class);\n        when(addr.isLoopbackAddress()).thenReturn(false);\n        when(addr.getHostAddress()).thenReturn(\"175.23.44.1\");\n        InetSocketAddress address = new InetSocketAddress(addr, 12345);\n        when(channel.remoteAddress()).thenReturn(address);\n\n        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(QosConfiguration.builder()\n                .acceptForeignIp(false)\n                .acceptForeignIpWhitelist(\"175.23.44.1, 192.168.1.192/26  \")\n                .build());\n        handler.handlerAdded(context);\n        verify(context, never()).writeAndFlush(any());\n    }\n\n    @Test\n    void shouldNotShowIpNotPermittedMsg_GivenAcceptForeignIpFalseAndMatchWhiteListRange() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        Channel channel = mock(Channel.class);\n        when(context.channel()).thenReturn(channel);\n        InetAddress addr = mock(InetAddress.class);\n        when(addr.isLoopbackAddress()).thenReturn(false);\n        when(addr.getHostAddress()).thenReturn(\"192.168.1.199\");\n        InetSocketAddress address = new InetSocketAddress(addr, 12345);\n        when(channel.remoteAddress()).thenReturn(address);\n\n        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(QosConfiguration.builder()\n                .acceptForeignIp(false)\n                .acceptForeignIpWhitelist(\"175.23.44.1, 192.168.1.192/26\")\n                .build());\n        handler.handlerAdded(context);\n        verify(context, never()).writeAndFlush(any());\n    }\n\n    @Test\n    void shouldNotShowIpNotPermittedMsg_GivenAcceptForeignIpFalseAndNotMatchWhiteListAndPermissionConfig()\n            throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        Channel channel = mock(Channel.class);\n        when(context.channel()).thenReturn(channel);\n        ChannelFuture future = mock(ChannelFuture.class);\n        when(context.writeAndFlush(any(ByteBuf.class))).thenReturn(future);\n        ForeignHostPermitHandler handler = new ForeignHostPermitHandler(QosConfiguration.builder()\n                .acceptForeignIp(false)\n                .acceptForeignIpWhitelist(\"175.23.44.1 ,  192.168.1.192/26\")\n                .anonymousAccessPermissionLevel(PermissionLevel.PROTECTED.name())\n                .build());\n\n        handler.handlerAdded(context);\n        verify(future, never()).addListener(ChannelFutureListener.CLOSE);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/HttpProcessHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.api.QosConfiguration;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpRequest;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass HttpProcessHandlerTest {\n    @Test\n    void test1() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        ChannelFuture future = mock(ChannelFuture.class);\n        when(context.writeAndFlush(any(FullHttpResponse.class))).thenReturn(future);\n        HttpRequest message = Mockito.mock(HttpRequest.class);\n        when(message.uri()).thenReturn(\"test\");\n        HttpProcessHandler handler = new HttpProcessHandler(\n                FrameworkModel.defaultModel(), QosConfiguration.builder().build());\n        handler.channelRead0(context, message);\n        verify(future).addListener(ChannelFutureListener.CLOSE);\n        ArgumentCaptor<FullHttpResponse> captor = ArgumentCaptor.forClass(FullHttpResponse.class);\n        verify(context).writeAndFlush(captor.capture());\n        FullHttpResponse response = captor.getValue();\n        assertThat(response.status().code(), equalTo(404));\n    }\n\n    @Test\n    void test2() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        ChannelFuture future = mock(ChannelFuture.class);\n        when(context.writeAndFlush(any(FullHttpResponse.class))).thenReturn(future);\n        HttpRequest message = Mockito.mock(HttpRequest.class);\n        when(message.uri()).thenReturn(\"localhost:80/greeting\");\n        when(message.method()).thenReturn(HttpMethod.GET);\n        HttpProcessHandler handler = new HttpProcessHandler(\n                FrameworkModel.defaultModel(),\n                QosConfiguration.builder()\n                        .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())\n                        .build());\n        handler.channelRead0(context, message);\n        verify(future).addListener(ChannelFutureListener.CLOSE);\n        ArgumentCaptor<FullHttpResponse> captor = ArgumentCaptor.forClass(FullHttpResponse.class);\n        verify(context).writeAndFlush(captor.capture());\n        FullHttpResponse response = captor.getValue();\n        assertThat(response.status().code(), equalTo(200));\n    }\n\n    @Test\n    void test3() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        ChannelFuture future = mock(ChannelFuture.class);\n        when(context.writeAndFlush(any(FullHttpResponse.class))).thenReturn(future);\n        HttpRequest message = Mockito.mock(HttpRequest.class);\n        when(message.uri()).thenReturn(\"localhost:80/test\");\n        when(message.method()).thenReturn(HttpMethod.GET);\n        HttpProcessHandler handler = new HttpProcessHandler(\n                FrameworkModel.defaultModel(),\n                QosConfiguration.builder()\n                        .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())\n                        .build());\n        handler.channelRead0(context, message);\n        verify(future).addListener(ChannelFutureListener.CLOSE);\n        ArgumentCaptor<FullHttpResponse> captor = ArgumentCaptor.forClass(FullHttpResponse.class);\n        verify(context).writeAndFlush(captor.capture());\n        FullHttpResponse response = captor.getValue();\n        assertThat(response.status().code(), equalTo(404));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/QosProcessHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.qos.api.QosConfiguration;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Collections;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.handler.codec.LineBasedFrameDecoder;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport io.netty.handler.codec.http.HttpServerCodec;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.verify;\n\nclass QosProcessHandlerTest {\n    @Test\n    void testDecodeHttp() throws Exception {\n        ByteBuf buf = Unpooled.wrappedBuffer(new byte[] {'G'});\n        ChannelHandlerContext context = Mockito.mock(ChannelHandlerContext.class);\n        ChannelPipeline pipeline = Mockito.mock(ChannelPipeline.class);\n        Mockito.when(context.pipeline()).thenReturn(pipeline);\n        QosProcessHandler handler = new QosProcessHandler(\n                FrameworkModel.defaultModel(),\n                QosConfiguration.builder()\n                        .welcome(\"welcome\")\n                        .acceptForeignIp(false)\n                        .acceptForeignIpWhitelist(StringUtils.EMPTY_STRING)\n                        .build());\n        handler.decode(context, buf, Collections.emptyList());\n        verify(pipeline).addLast(any(HttpServerCodec.class));\n        verify(pipeline).addLast(any(HttpObjectAggregator.class));\n        verify(pipeline).addLast(any(HttpProcessHandler.class));\n        verify(pipeline).remove(handler);\n    }\n\n    @Test\n    void testDecodeTelnet() throws Exception {\n        ByteBuf buf = Unpooled.wrappedBuffer(new byte[] {'A'});\n        ChannelHandlerContext context = Mockito.mock(ChannelHandlerContext.class);\n        ChannelPipeline pipeline = Mockito.mock(ChannelPipeline.class);\n        Mockito.when(context.pipeline()).thenReturn(pipeline);\n        QosProcessHandler handler = new QosProcessHandler(\n                FrameworkModel.defaultModel(),\n                QosConfiguration.builder()\n                        .welcome(\"welcome\")\n                        .acceptForeignIp(false)\n                        .acceptForeignIpWhitelist(StringUtils.EMPTY_STRING)\n                        .build());\n        handler.decode(context, buf, Collections.emptyList());\n        verify(pipeline).addLast(any(LineBasedFrameDecoder.class));\n        verify(pipeline).addLast(any(StringDecoder.class));\n        verify(pipeline).addLast(any(StringEncoder.class));\n        verify(pipeline).addLast(any(TelnetProcessHandler.class));\n        verify(pipeline).remove(handler);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/server/handler/TelnetProcessHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.server.handler;\n\nimport org.apache.dubbo.qos.api.PermissionLevel;\nimport org.apache.dubbo.qos.api.QosConfiguration;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandlerContext;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.contains;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass TelnetProcessHandlerTest {\n    @Test\n    void testPrompt() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        TelnetProcessHandler handler = new TelnetProcessHandler(\n                FrameworkModel.defaultModel(),\n                QosConfiguration.builder()\n                        .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())\n                        .build());\n        handler.channelRead0(context, \"\");\n        verify(context).writeAndFlush(QosProcessHandler.PROMPT);\n    }\n\n    @Test\n    void testBye() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        TelnetProcessHandler handler = new TelnetProcessHandler(\n                FrameworkModel.defaultModel(), QosConfiguration.builder().build());\n        ChannelFuture future = mock(ChannelFuture.class);\n        when(context.writeAndFlush(\"BYE!\\n\")).thenReturn(future);\n        handler.channelRead0(context, \"quit\");\n        verify(future).addListener(ChannelFutureListener.CLOSE);\n    }\n\n    @Test\n    void testUnknownCommand() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        TelnetProcessHandler handler = new TelnetProcessHandler(\n                FrameworkModel.defaultModel(), QosConfiguration.builder().build());\n        handler.channelRead0(context, \"unknown\");\n        ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);\n        verify(context, Mockito.atLeastOnce()).writeAndFlush(captor.capture());\n        assertThat(captor.getAllValues(), contains(\"unknown :no such command\", \"\\r\\ndubbo>\"));\n    }\n\n    @Test\n    void testGreeting() throws Exception {\n        ChannelHandlerContext context = mock(ChannelHandlerContext.class);\n        TelnetProcessHandler handler = new TelnetProcessHandler(\n                FrameworkModel.defaultModel(),\n                QosConfiguration.builder()\n                        .anonymousAccessPermissionLevel(PermissionLevel.NONE.name())\n                        .build());\n        handler.channelRead0(context, \"greeting\");\n        ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);\n        verify(context).writeAndFlush(captor.capture());\n        assertThat(captor.getValue(), containsString(\"greeting\"));\n        assertThat(captor.getValue(), containsString(\"dubbo>\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TKvTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.textui;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\n\nclass TKvTest {\n    @Test\n    void test1() {\n        TKv tKv = new TKv(\n                new TTable.ColumnDefine(TTable.Align.RIGHT), new TTable.ColumnDefine(10, false, TTable.Align.LEFT));\n        tKv.add(\"KEY-1\", \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\");\n        tKv.add(\"KEY-2\", \"1234567890\");\n        tKv.add(\"KEY-3\", \"1234567890\");\n\n        TTable tTable = new TTable(new TTable.ColumnDefine[] {\n            new TTable.ColumnDefine(), new TTable.ColumnDefine(20, false, TTable.Align.LEFT)\n        });\n\n        String kv = tKv.rendering();\n        assertThat(kv, containsString(\"ABCDEFGHIJ\" + System.lineSeparator()));\n        assertThat(kv, containsString(\"KLMNOPQRST\" + System.lineSeparator()));\n        assertThat(kv, containsString(\"UVWXYZ\" + System.lineSeparator()));\n\n        tTable.addRow(\"OPTIONS\", kv);\n        String table = tTable.rendering();\n        assertThat(table, containsString(\"|OPTIONS|\"));\n        assertThat(table, containsString(\"|KEY-3\"));\n    }\n\n    @Test\n    void test2() throws Exception {\n        TKv tKv = new TKv();\n        tKv.add(\"KEY-1\", \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\");\n        tKv.add(\"KEY-2\", \"1234567890\");\n        tKv.add(\"KEY-3\", \"1234567890\");\n        String kv = tKv.rendering();\n        assertThat(kv, containsString(\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TLadderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.textui;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass TLadderTest {\n    @Test\n    void testRendering() throws Exception {\n        TLadder ladder = new TLadder();\n        ladder.addItem(\"1\");\n        ladder.addItem(\"2\");\n        ladder.addItem(\"3\");\n        ladder.addItem(\"4\");\n        String result = ladder.rendering();\n        String expected = \"1\" + System.lineSeparator() + \"  `-2\"\n                + System.lineSeparator() + \"    `-3\"\n                + System.lineSeparator() + \"      `-4\"\n                + System.lineSeparator();\n        assertThat(result, equalTo(expected));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TTableTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.textui;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass TTableTest {\n    @Test\n    void test1() throws Exception {\n        TTable table = new TTable(4);\n        table.addRow(1, \"one\", \"uno\", \"un\");\n        table.addRow(2, \"two\", \"dos\", \"deux\");\n        String result = table.rendering();\n        String expected = \"+-+---+---+----+\" + System.lineSeparator() + \"|1|one|uno|un  |\"\n                + System.lineSeparator() + \"+-+---+---+----+\"\n                + System.lineSeparator() + \"|2|two|dos|deux|\"\n                + System.lineSeparator() + \"+-+---+---+----+\"\n                + System.lineSeparator();\n        assertThat(result, equalTo(expected));\n    }\n\n    @Test\n    void test2() throws Exception {\n        TTable table = new TTable(new TTable.ColumnDefine[] {\n            new TTable.ColumnDefine(5, true, TTable.Align.LEFT),\n            new TTable.ColumnDefine(10, false, TTable.Align.MIDDLE),\n            new TTable.ColumnDefine(10, false, TTable.Align.RIGHT)\n        });\n        table.addRow(1, \"abcde\", \"ABCDE\");\n        String result = table.rendering();\n        String expected = \"+-+----------+----------+\" + System.lineSeparator() + \"|1|   abcde  |     ABCDE|\"\n                + System.lineSeparator() + \"+-+----------+----------+\"\n                + System.lineSeparator();\n        assertThat(result, equalTo(expected));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TTreeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.textui;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\n\nclass TTreeTest {\n    @Test\n    void test() throws Exception {\n        TTree tree = new TTree(false, \"root\");\n        tree.begin(\"one\").begin(\"ONE\").end().end();\n        tree.begin(\"two\").begin(\"TWO\").end().begin(\"2\").end().end();\n        tree.begin(\"three\").end();\n        String result = tree.rendering();\n        String expected = \"`---+root\\n\" + \"    +---+one\\n\"\n                + \"    |   `---ONE\\n\"\n                + \"    +---+two\\n\"\n                + \"    |   +---TWO\\n\"\n                + \"    |   `---2\\n\"\n                + \"    `---three\\n\";\n        assertThat(result, equalTo(expected));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/resources/META-INF/services/org.apache.dubbo.qos.api.BaseCommand",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ngreeting=org.apache.dubbo.qos.command.GreetingCommand"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/resources/META-INF/services/org.apache.dubbo.qos.permission.PermissionChecker",
    "content": "qosPermissionChecker=not.exist.mock.permissionChecker\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/resources/META-INF/services/org.apache.dubbo.qos.probe.LivenessProbe",
    "content": "mock=org.apache.dubbo.qos.command.impl.MockLivenessProbe\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryFactory",
    "content": "test=org.apache.dubbo.qos.command.impl.TestRegistryFactory"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/resources/dubbo.properties",
    "content": "dubbo.application.enable-file-cache=false\ndubbo.service.shutdown.wait=200\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos/src/test/resources/security/serialize.allowlist",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\norg.apache.dubbo\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos-api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-qos-api</artifactId>\n  <name>dubbo-qos-api</name>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos-api/src/main/java/org/apache/dubbo/qos/api/BaseCommand.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.api;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface BaseCommand {\n\n    default boolean logResult() {\n        return true;\n    }\n\n    String execute(CommandContext commandContext, String[] args);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos-api/src/main/java/org/apache/dubbo/qos/api/Cmd.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.api;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Command\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface Cmd {\n\n    /**\n     * Command name\n     *\n     * @return command name\n     */\n    String name();\n\n    /**\n     * Command description\n     *\n     * @return command description\n     */\n    String summary();\n\n    /**\n     * Command example\n     *\n     * @return command example\n     */\n    String[] example() default {};\n\n    /**\n     * Command order in help\n     *\n     * @return command order in help\n     */\n    int sort() default 0;\n\n    /**\n     * Command required access permission level\n     *\n     * @return command permission level\n     */\n    PermissionLevel requiredPermissionLevel() default PermissionLevel.PROTECTED;\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos-api/src/main/java/org/apache/dubbo/qos/api/CommandContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.api;\n\nimport java.util.Arrays;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport io.netty.channel.Channel;\n\npublic class CommandContext {\n\n    private String commandName;\n    private String[] args;\n    private Channel remote;\n    private boolean isHttp;\n    private Object originRequest;\n    private int httpCode = 200;\n\n    private QosConfiguration qosConfiguration;\n\n    public CommandContext(String commandName) {\n        this.commandName = commandName;\n    }\n\n    public CommandContext(String commandName, String[] args, boolean isHttp) {\n        this.commandName = commandName;\n        this.args = args;\n        this.isHttp = isHttp;\n    }\n\n    public String getCommandName() {\n        return commandName;\n    }\n\n    public void setCommandName(String commandName) {\n        this.commandName = commandName;\n    }\n\n    public String[] getArgs() {\n        return args;\n    }\n\n    public void setArgs(String[] args) {\n        this.args = args;\n    }\n\n    public Channel getRemote() {\n        return remote;\n    }\n\n    public void setRemote(Channel remote) {\n        this.remote = remote;\n    }\n\n    public boolean isHttp() {\n        return isHttp;\n    }\n\n    public void setHttp(boolean http) {\n        isHttp = http;\n    }\n\n    public Object getOriginRequest() {\n        return originRequest;\n    }\n\n    public void setOriginRequest(Object originRequest) {\n        this.originRequest = originRequest;\n    }\n\n    public int getHttpCode() {\n        return httpCode;\n    }\n\n    public void setHttpCode(int httpCode) {\n        this.httpCode = httpCode;\n    }\n\n    public void setQosConfiguration(QosConfiguration qosConfiguration) {\n        this.qosConfiguration = qosConfiguration;\n    }\n\n    public QosConfiguration getQosConfiguration() {\n        return qosConfiguration;\n    }\n\n    public boolean isAllowAnonymousAccess() {\n        return this.qosConfiguration.isAllowAnonymousAccess();\n    }\n\n    @Override\n    public String toString() {\n        return \"CommandContext{\" + \"commandName='\"\n                + commandName + '\\'' + \", args=\"\n                + Arrays.toString(args) + \", remote=\"\n                + Optional.ofNullable(remote)\n                        .map(Channel::remoteAddress)\n                        .map(Objects::toString)\n                        .orElse(\"unknown\") + \", local=\"\n                + Optional.ofNullable(remote)\n                        .map(Channel::localAddress)\n                        .map(Objects::toString)\n                        .orElse(\"unknown\") + \", isHttp=\"\n                + isHttp + \", httpCode=\"\n                + httpCode + \", qosConfiguration=\"\n                + qosConfiguration + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos-api/src/main/java/org/apache/dubbo/qos/api/PermissionLevel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.api;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Arrays;\n\npublic enum PermissionLevel {\n    /**\n     * the lowest permission level (default), can access with\n     * anonymousAccessPermissionLevel=PUBLIC / anonymousAccessPermissionLevel=1 or higher\n     */\n    PUBLIC(1),\n    /**\n     * the middle permission level, default permission for each cmd\n     */\n    PROTECTED(2),\n    /**\n     * the highest permission level, suppose only the localhost can access this command\n     */\n    PRIVATE(3),\n\n    /**\n     * It is the reserved  anonymous permission level, can not access any command\n     */\n    NONE(Integer.MIN_VALUE),\n    ;\n    private final int level;\n\n    PermissionLevel(int level) {\n        this.level = level;\n    }\n\n    public int getLevel() {\n        return level;\n    }\n\n    // find the permission level by the level value, if not found, return default PUBLIC level\n    public static PermissionLevel from(String permissionLevel) {\n        if (StringUtils.isNumber(permissionLevel)) {\n            return Arrays.stream(values())\n                    .filter(p -> String.valueOf(p.getLevel()).equals(permissionLevel.trim()))\n                    .findFirst()\n                    .orElse(PUBLIC);\n        }\n        return Arrays.stream(values())\n                .filter(p -> p.name()\n                        .equalsIgnoreCase(String.valueOf(permissionLevel).trim()))\n                .findFirst()\n                .orElse(PUBLIC);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-qos-api/src/main/java/org/apache/dubbo/qos/api/QosConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.qos.api;\n\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.net.UnknownHostException;\nimport java.util.Arrays;\nimport java.util.function.Predicate;\n\npublic class QosConfiguration {\n    private String welcome;\n    private boolean acceptForeignIp;\n\n    // the whitelist of foreign IP when acceptForeignIp = false, the delimiter is colon(,)\n    // support specific ip and an ip range from CIDR specification\n    private String acceptForeignIpWhitelist;\n\n    private Predicate<String> acceptForeignIpWhitelistPredicate;\n\n    // this permission level for anonymous access, it will ignore the acceptForeignIp and acceptForeignIpWhitelist\n    // configurations\n    // Access permission depends on the config anonymousAccessPermissionLevel and the cmd required permission level\n    // the default value is Cmd.PermissionLevel.PUBLIC, can only access PUBLIC level cmd\n    private PermissionLevel anonymousAccessPermissionLevel = PermissionLevel.PUBLIC;\n\n    // the allow commands for anonymous access, the delimiter is colon(,)\n    private String anonymousAllowCommands;\n\n    private QosConfiguration() {}\n\n    public QosConfiguration(Builder builder) {\n        this.welcome = builder.getWelcome();\n        this.acceptForeignIp = builder.isAcceptForeignIp();\n        this.acceptForeignIpWhitelist = builder.getAcceptForeignIpWhitelist();\n        this.anonymousAccessPermissionLevel = builder.getAnonymousAccessPermissionLevel();\n        this.anonymousAllowCommands = builder.getAnonymousAllowCommands();\n        buildPredicate();\n    }\n\n    private void buildPredicate() {\n        if (StringUtils.isNotEmpty(acceptForeignIpWhitelist)) {\n            this.acceptForeignIpWhitelistPredicate = Arrays.stream(acceptForeignIpWhitelist.split(\",\"))\n                    .map(String::trim)\n                    .filter(StringUtils::isNotEmpty)\n                    .map(foreignIpPattern -> (Predicate<String>) foreignIp -> {\n                        try {\n                            // hard code port to -1\n                            return NetUtils.matchIpExpression(foreignIpPattern, foreignIp, -1);\n                        } catch (UnknownHostException ignore) {\n                            // ignore illegal CIDR specification\n                        }\n                        return false;\n                    })\n                    .reduce(Predicate::or)\n                    .orElse(s -> false);\n        } else {\n            this.acceptForeignIpWhitelistPredicate = foreignIp -> false;\n        }\n    }\n\n    public boolean isAllowAnonymousAccess() {\n        return PermissionLevel.NONE != anonymousAccessPermissionLevel;\n    }\n\n    public String getWelcome() {\n        return welcome;\n    }\n\n    public PermissionLevel getAnonymousAccessPermissionLevel() {\n        return anonymousAccessPermissionLevel;\n    }\n\n    public String getAcceptForeignIpWhitelist() {\n        return acceptForeignIpWhitelist;\n    }\n\n    public Predicate<String> getAcceptForeignIpWhitelistPredicate() {\n        return acceptForeignIpWhitelistPredicate;\n    }\n\n    public boolean isAcceptForeignIp() {\n        return acceptForeignIp;\n    }\n\n    public String getAnonymousAllowCommands() {\n        return anonymousAllowCommands;\n    }\n\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    public static class Builder {\n        private String welcome;\n        private boolean acceptForeignIp;\n        private String acceptForeignIpWhitelist;\n        private PermissionLevel anonymousAccessPermissionLevel = PermissionLevel.PUBLIC;\n        private String anonymousAllowCommands;\n\n        private Builder() {}\n\n        public Builder welcome(String welcome) {\n            this.welcome = welcome;\n            return this;\n        }\n\n        public Builder acceptForeignIp(boolean acceptForeignIp) {\n            this.acceptForeignIp = acceptForeignIp;\n            return this;\n        }\n\n        public Builder acceptForeignIpWhitelist(String acceptForeignIpWhitelist) {\n            this.acceptForeignIpWhitelist = acceptForeignIpWhitelist;\n            return this;\n        }\n\n        public Builder anonymousAccessPermissionLevel(String anonymousAccessPermissionLevel) {\n            this.anonymousAccessPermissionLevel = PermissionLevel.from(anonymousAccessPermissionLevel);\n            return this;\n        }\n\n        public Builder anonymousAllowCommands(String anonymousAllowCommands) {\n            this.anonymousAllowCommands = anonymousAllowCommands;\n            return this;\n        }\n\n        public QosConfiguration build() {\n            return new QosConfiguration(this);\n        }\n\n        public String getWelcome() {\n            return welcome;\n        }\n\n        public boolean isAcceptForeignIp() {\n            return acceptForeignIp;\n        }\n\n        public String getAcceptForeignIpWhitelist() {\n            return acceptForeignIpWhitelist;\n        }\n\n        public PermissionLevel getAnonymousAccessPermissionLevel() {\n            return anonymousAccessPermissionLevel;\n        }\n\n        public String getAnonymousAllowCommands() {\n            return anonymousAllowCommands;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-reactive</artifactId>\n  <packaging>jar</packaging>\n\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.reactivestreams</groupId>\n      <artifactId>reactive-streams</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.projectreactor</groupId>\n      <artifactId>reactor-core</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/AbstractTripleReactorPublisher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.rpc.protocol.tri.CancelableStreamObserver;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Consumer;\n\nimport org.reactivestreams.Publisher;\nimport org.reactivestreams.Subscriber;\nimport org.reactivestreams.Subscription;\n\n/**\n * The middle layer between {@link CallStreamObserver} and Reactive API. <p>\n * 1. passing the data received by CallStreamObserver to Reactive consumer <br>\n * 2. passing the request of Reactive API to CallStreamObserver\n */\npublic abstract class AbstractTripleReactorPublisher<T> extends CancelableStreamObserver<T>\n        implements Publisher<T>, Subscription {\n\n    private boolean canRequest;\n\n    private long requested;\n\n    // weather publisher has been subscribed\n    private final AtomicBoolean SUBSCRIBED = new AtomicBoolean();\n\n    private volatile Subscriber<? super T> downstream;\n\n    protected volatile CallStreamObserver<?> subscription;\n\n    private final AtomicBoolean HAS_SUBSCRIPTION = new AtomicBoolean();\n\n    // cancel status\n    private volatile boolean isCancelled;\n\n    // complete status\n    private volatile boolean isDone;\n\n    // to help bind TripleSubscriber\n    private volatile Consumer<CallStreamObserver<?>> onSubscribe;\n\n    private volatile Runnable shutdownHook;\n\n    private final AtomicBoolean CALLED_SHUT_DOWN_HOOK = new AtomicBoolean();\n\n    public AbstractTripleReactorPublisher() {}\n\n    public AbstractTripleReactorPublisher(Consumer<CallStreamObserver<?>> onSubscribe, Runnable shutdownHook) {\n        this.onSubscribe = onSubscribe;\n        this.shutdownHook = shutdownHook;\n    }\n\n    protected void onSubscribe(final CallStreamObserver<?> subscription) {\n        if (subscription != null && this.subscription == null && HAS_SUBSCRIPTION.compareAndSet(false, true)) {\n            this.subscription = subscription;\n            subscription.disableAutoFlowControl();\n\n            // Set up onReadyHandler to trigger onSubscribe callback when stream becomes ready.\n            // This is called AFTER call.start() via InitOnReadyQueueCommand, ensuring the stream\n            // is created before any data is sent\n            // is triggered by onReady, not by onStart (which requires server headers).\n            if (onSubscribe != null) {\n                subscription.setOnReadyHandler(() -> {\n                    // Only execute the callback once (on first onReady)\n                    Consumer<CallStreamObserver<?>> callback = onSubscribe;\n                    if (callback != null && subscription.isReady()) {\n                        onSubscribe = null; // Clear to prevent re-execution\n                        callback.accept(subscription);\n                    }\n                });\n            }\n            return;\n        }\n\n        throw new IllegalStateException(getClass().getSimpleName() + \" supports only a single subscription\");\n    }\n\n    @Override\n    public void onNext(T data) {\n        if (isDone || isCancelled) {\n            return;\n        }\n        downstream.onNext(data);\n    }\n\n    @Override\n    public void onError(Throwable throwable) {\n        if (isDone || isCancelled) {\n            return;\n        }\n        isDone = true;\n        downstream.onError(throwable);\n        doPostShutdown();\n    }\n\n    @Override\n    public void onCompleted() {\n        if (isDone || isCancelled) {\n            return;\n        }\n        isDone = true;\n        downstream.onComplete();\n        doPostShutdown();\n    }\n\n    private void doPostShutdown() {\n        Runnable r = shutdownHook;\n        // CAS to confirm shutdownHook will be run only once.\n        if (r != null && CALLED_SHUT_DOWN_HOOK.compareAndSet(false, true)) {\n            shutdownHook = null;\n            r.run();\n        }\n    }\n\n    @Override\n    public void subscribe(Subscriber<? super T> subscriber) {\n        if (subscriber == null) {\n            throw new NullPointerException();\n        }\n\n        if (SUBSCRIBED.compareAndSet(false, true)) {\n            subscriber.onSubscribe(this);\n            this.downstream = subscriber;\n            if (isCancelled) {\n                this.downstream = null;\n            }\n        }\n    }\n\n    @Override\n    public void request(long l) {\n        synchronized (this) {\n            if (SUBSCRIBED.get() && canRequest) {\n                subscription.request(l >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) l);\n            } else {\n                requested += l;\n            }\n        }\n    }\n\n    @Override\n    public void startRequest() {\n        synchronized (this) {\n            if (!canRequest) {\n                canRequest = true;\n                // Request buffered messages from the server.\n                // Note: onSubscribe callback is now triggered by onReadyHandler (set in onSubscribe()),\n                // not here, because onReady is triggered earlier than onStart.\n                long count = requested;\n                subscription.request(count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) count);\n            }\n        }\n    }\n\n    @Override\n    public void cancel() {\n        if (isCancelled) {\n            return;\n        }\n        isCancelled = true;\n        doPostShutdown();\n    }\n\n    public boolean isCancelled() {\n        return isCancelled;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/AbstractTripleReactorSubscriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.reactivestreams.Subscriber;\nimport org.reactivestreams.Subscription;\nimport reactor.core.CoreSubscriber;\nimport reactor.util.annotation.NonNull;\n\n/**\n * The middle layer between {@link CallStreamObserver} and Reactive API. <br>\n * Passing the data from Reactive producer to CallStreamObserver.\n */\npublic abstract class AbstractTripleReactorSubscriber<T> implements Subscriber<T>, CoreSubscriber<T> {\n\n    private volatile boolean isCancelled;\n\n    protected volatile CallStreamObserver<T> downstream;\n\n    private final AtomicBoolean SUBSCRIBED = new AtomicBoolean();\n\n    private volatile Subscription subscription;\n\n    private final AtomicBoolean HAS_SUBSCRIBED = new AtomicBoolean();\n\n    // complete status\n    private volatile boolean isDone;\n\n    /**\n     * Binding the downstream, and call subscription#request(1).\n     *\n     * @param downstream downstream\n     */\n    public void subscribe(final CallStreamObserver<T> downstream) {\n        if (downstream == null) {\n            throw new NullPointerException();\n        }\n        if (SUBSCRIBED.compareAndSet(false, true)) {\n            this.downstream = downstream;\n            subscription.request(1);\n        }\n    }\n\n    @Override\n    public void onSubscribe(@NonNull final Subscription subscription) {\n        if (this.subscription == null && HAS_SUBSCRIBED.compareAndSet(false, true)) {\n            this.subscription = subscription;\n            return;\n        }\n        // onSubscribe cannot be called repeatedly\n        subscription.cancel();\n    }\n\n    @Override\n    public void onNext(T t) {\n        if (!isDone && !isCanceled()) {\n            downstream.onNext(t);\n            subscription.request(1);\n        }\n    }\n\n    @Override\n    public void onError(Throwable throwable) {\n        if (!isCanceled()) {\n            isDone = true;\n            downstream.onError(throwable);\n        }\n    }\n\n    @Override\n    public void onComplete() {\n        if (!isCanceled()) {\n            isDone = true;\n            downstream.onCompleted();\n        }\n    }\n\n    public void cancel() {\n        if (!isCancelled && subscription != null) {\n            isCancelled = true;\n            subscription.cancel();\n        }\n    }\n\n    public boolean isCanceled() {\n        return isCancelled;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/ClientTripleReactorPublisher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.ClientCallStreamObserver;\nimport org.apache.dubbo.common.stream.ClientResponseObserver;\n\nimport java.util.function.Consumer;\n\n/**\n * Used in OneToMany & ManyToOne & ManyToMany in client. <br>\n * It is a Publisher for user subscriber to subscribe. <br>\n * It is a StreamObserver for responseStream. <br>\n * It is a Subscription for user subscriber to request and pass request to requestStream.\n * <p>\n * Implements {@link ClientResponseObserver} following gRPC's pattern where\n * {@link #beforeStart(ClientCallStreamObserver)} is called before the stream starts,\n * allowing configuration of flow control before any messages are sent.\n */\npublic class ClientTripleReactorPublisher<T> extends AbstractTripleReactorPublisher<T>\n        implements ClientResponseObserver<Object, T> {\n\n    public ClientTripleReactorPublisher() {}\n\n    public ClientTripleReactorPublisher(Consumer<CallStreamObserver<?>> onSubscribe, Runnable shutdownHook) {\n        super(onSubscribe, shutdownHook);\n    }\n\n    /**\n     * Called by the runtime prior to the start of a call to provide a reference to the\n     * {@link ClientCallStreamObserver} for the outbound stream.\n     * <p>\n     * Following gRPC's pattern, this method is called BEFORE {@code call.start()},\n     * allowing configuration of onReadyHandler and flow control settings.\n     */\n    @Override\n    public void beforeStart(ClientCallStreamObserver<Object> requestStream) {\n        super.onSubscribe(requestStream);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/ClientTripleReactorSubscriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.rpc.protocol.tri.observer.ClientCallToObserverAdapter;\n\n/**\n * The subscriber in client to subscribe user publisher and is subscribed by ClientStreamObserver.\n */\npublic class ClientTripleReactorSubscriber<T> extends AbstractTripleReactorSubscriber<T> {\n\n    @Override\n    public void cancel() {\n        if (!isCanceled()) {\n            super.cancel();\n            ((ClientCallToObserverAdapter<T>) downstream).cancel(new Exception(\"Cancelled\"));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/ServerTripleReactorPublisher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\n\n/**\n * Used in ManyToOne and ManyToMany in server. <br>\n * It is a Publisher for user subscriber to subscribe. <br>\n * It is a StreamObserver for requestStream. <br>\n * It is a Subscription for user subscriber to request and pass request to responseStream.\n */\npublic class ServerTripleReactorPublisher<T> extends AbstractTripleReactorPublisher<T> {\n\n    public ServerTripleReactorPublisher(CallStreamObserver<?> callStreamObserver) {\n        super.onSubscribe(callStreamObserver);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/ServerTripleReactorSubscriber.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.rpc.CancellationContext;\nimport org.apache.dubbo.rpc.protocol.tri.CancelableStreamObserver;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\n\n/**\n * The Subscriber in server to passing the data produced by user publisher to responseStream.\n */\npublic class ServerTripleReactorSubscriber<T> extends AbstractTripleReactorSubscriber<T> {\n\n    /**\n     * The execution future of the current task, in order to be returned to stubInvoker\n     */\n    private final CompletableFuture<List<T>> executionFuture = new CompletableFuture<>();\n    /**\n     * The result elements collected by the current task.\n     * This class is a flux subscriber, which usually means there will be multiple elements, so it is declared as a list type.\n     */\n    private final List<T> collectedData = new ArrayList<>();\n\n    public ServerTripleReactorSubscriber() {}\n\n    public ServerTripleReactorSubscriber(CallStreamObserver<T> streamObserver) {\n        this.downstream = streamObserver;\n    }\n\n    @Override\n    public void subscribe(CallStreamObserver<T> downstream) {\n        super.subscribe(downstream);\n        if (downstream instanceof CancelableStreamObserver) {\n            CancelableStreamObserver<?> observer = (CancelableStreamObserver<?>) downstream;\n            final CancellationContext context;\n            if (observer.getCancellationContext() == null) {\n                context = new CancellationContext();\n                observer.setCancellationContext(context);\n            } else {\n                context = observer.getCancellationContext();\n            }\n            context.addListener(ctx -> super.cancel());\n        }\n    }\n\n    @Override\n    public void onNext(T t) {\n        super.onNext(t);\n        collectedData.add(t);\n    }\n\n    @Override\n    public void onError(Throwable throwable) {\n        super.onError(throwable);\n        executionFuture.completeExceptionally(throwable);\n    }\n\n    @Override\n    public void onComplete() {\n        super.onComplete();\n        executionFuture.complete(this.collectedData);\n    }\n\n    public CompletableFuture<List<T>> getExecutionFuture() {\n        return executionFuture;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/calls/ReactorClientCalls.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive.calls;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.reactive.ClientTripleReactorPublisher;\nimport org.apache.dubbo.reactive.ClientTripleReactorSubscriber;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.model.StubMethodDescriptor;\nimport org.apache.dubbo.rpc.stub.StubInvocationUtil;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n/**\n * A collection of methods to convert client-side Reactor calls to stream calls.\n */\npublic final class ReactorClientCalls {\n\n    private ReactorClientCalls() {}\n\n    /**\n     * Implements a unary -> unary call as Mono -> Mono\n     *\n     * @param invoker invoker\n     * @param monoRequest the mono with request\n     * @param methodDescriptor the method descriptor\n     * @return the mono with response\n     */\n    public static <TRequest, TResponse, TInvoker> Mono<TResponse> oneToOne(\n            Invoker<TInvoker> invoker, Mono<TRequest> monoRequest, StubMethodDescriptor methodDescriptor) {\n        try {\n            return Mono.create(emitter -> monoRequest.subscribe(\n                    request -> StubInvocationUtil.unaryCall(\n                            invoker, methodDescriptor, request, new StreamObserver<TResponse>() {\n                                @Override\n                                public void onNext(TResponse tResponse) {\n                                    emitter.success(tResponse);\n                                }\n\n                                @Override\n                                public void onError(Throwable throwable) {\n                                    emitter.error(throwable);\n                                }\n\n                                @Override\n                                public void onCompleted() {\n                                    // Do nothing\n                                }\n                            }),\n                    emitter::error));\n        } catch (Throwable throwable) {\n            return Mono.error(throwable);\n        }\n    }\n\n    /**\n     * Implements a unary -> stream call as Mono -> Flux\n     *\n     * @param invoker invoker\n     * @param monoRequest the mono with request\n     * @param methodDescriptor the method descriptor\n     * @return the flux with response\n     */\n    public static <TRequest, TResponse, TInvoker> Flux<TResponse> oneToMany(\n            Invoker<TInvoker> invoker, Mono<TRequest> monoRequest, StubMethodDescriptor methodDescriptor) {\n        try {\n            return monoRequest.flatMapMany(request -> {\n                ClientTripleReactorPublisher<TResponse> clientPublisher = new ClientTripleReactorPublisher<>();\n                StubInvocationUtil.serverStreamCall(invoker, methodDescriptor, request, clientPublisher);\n                return clientPublisher;\n            });\n        } catch (Throwable throwable) {\n            return Flux.error(throwable);\n        }\n    }\n\n    /**\n     * Implements a stream -> unary call as Flux -> Mono\n     *\n     * @param invoker invoker\n     * @param requestFlux the flux with request\n     * @param methodDescriptor the method descriptor\n     * @return the mono with response\n     */\n    public static <TRequest, TResponse, TInvoker> Mono<TResponse> manyToOne(\n            Invoker<TInvoker> invoker, Flux<TRequest> requestFlux, StubMethodDescriptor methodDescriptor) {\n        try {\n            ClientTripleReactorSubscriber<TRequest> clientSubscriber =\n                    requestFlux.subscribeWith(new ClientTripleReactorSubscriber<>());\n            ClientTripleReactorPublisher<TResponse> clientPublisher = new ClientTripleReactorPublisher<>(\n                    s -> clientSubscriber.subscribe((CallStreamObserver<TRequest>) s), clientSubscriber::cancel);\n            return Mono.from(clientPublisher)\n                    .doOnSubscribe(dummy ->\n                            StubInvocationUtil.biOrClientStreamCall(invoker, methodDescriptor, clientPublisher));\n        } catch (Throwable throwable) {\n            return Mono.error(throwable);\n        }\n    }\n\n    /**\n     * Implements a stream -> stream call as Flux -> Flux\n     *\n     * @param invoker invoker\n     * @param requestFlux the flux with request\n     * @param methodDescriptor the method descriptor\n     * @return the flux with response\n     */\n    public static <TRequest, TResponse, TInvoker> Flux<TResponse> manyToMany(\n            Invoker<TInvoker> invoker, Flux<TRequest> requestFlux, StubMethodDescriptor methodDescriptor) {\n        try {\n            ClientTripleReactorSubscriber<TRequest> clientSubscriber =\n                    requestFlux.subscribeWith(new ClientTripleReactorSubscriber<>());\n            ClientTripleReactorPublisher<TResponse> clientPublisher = new ClientTripleReactorPublisher<>(\n                    s -> clientSubscriber.subscribe((CallStreamObserver<TRequest>) s), clientSubscriber::cancel);\n            return Flux.from(clientPublisher)\n                    .doOnSubscribe(dummy ->\n                            StubInvocationUtil.biOrClientStreamCall(invoker, methodDescriptor, clientPublisher));\n        } catch (Throwable throwable) {\n            return Flux.error(throwable);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/calls/ReactorServerCalls.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive.calls;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.reactive.ServerTripleReactorPublisher;\nimport org.apache.dubbo.reactive.ServerTripleReactorSubscriber;\nimport org.apache.dubbo.rpc.StatusRpcException;\nimport org.apache.dubbo.rpc.TriRpcStatus;\n\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n/**\n * A collection of methods to convert server-side stream calls to Reactor calls.\n */\npublic final class ReactorServerCalls {\n\n    private ReactorServerCalls() {}\n\n    /**\n     * Implements a unary -> unary call as Mono -> Mono\n     *\n     * @param request request\n     * @param responseObserver response StreamObserver\n     * @param func service implementation\n     */\n    public static <T, R> void oneToOne(T request, StreamObserver<R> responseObserver, Function<Mono<T>, Mono<R>> func) {\n        try {\n            func.apply(Mono.just(request))\n                    .switchIfEmpty(Mono.error(TriRpcStatus.NOT_FOUND.asException()))\n                    .subscribe(\n                            responseObserver::onNext,\n                            throwable -> doOnResponseHasException(throwable, responseObserver),\n                            responseObserver::onCompleted);\n        } catch (Throwable throwable) {\n            doOnResponseHasException(throwable, responseObserver);\n        }\n    }\n\n    /**\n     * Implements a unary -> stream call as Mono -> Flux\n     *\n     * @param request request\n     * @param responseObserver response StreamObserver\n     * @param func service implementation\n     */\n    public static <T, R> CompletableFuture<List<R>> oneToMany(\n            T request, StreamObserver<R> responseObserver, Function<Mono<T>, Flux<R>> func) {\n        try {\n            CallStreamObserver<R> callStreamObserver = (CallStreamObserver<R>) responseObserver;\n            Flux<R> response = func.apply(Mono.just(request));\n            ServerTripleReactorSubscriber<R> reactorSubscriber =\n                    new ServerTripleReactorSubscriber<>(callStreamObserver);\n            response.subscribeWith(reactorSubscriber).subscribe(callStreamObserver);\n            return reactorSubscriber.getExecutionFuture();\n        } catch (Throwable throwable) {\n            doOnResponseHasException(throwable, responseObserver);\n            CompletableFuture<List<R>> future = new CompletableFuture<>();\n            future.completeExceptionally(throwable);\n            return future;\n        }\n    }\n\n    /**\n     * Implements a stream -> unary call as Flux -> Mono\n     *\n     * @param responseObserver response StreamObserver\n     * @param func service implementation\n     * @return request StreamObserver\n     */\n    public static <T, R> StreamObserver<T> manyToOne(\n            StreamObserver<R> responseObserver, Function<Flux<T>, Mono<R>> func) {\n        ServerTripleReactorPublisher<T> serverPublisher =\n                new ServerTripleReactorPublisher<>((CallStreamObserver<R>) responseObserver);\n        try {\n            Mono<R> responseMono = func.apply(Flux.from(serverPublisher));\n            responseMono.subscribe(\n                    value -> {\n                        // Don't try to respond if the server has already canceled the request\n                        if (!serverPublisher.isCancelled()) {\n                            responseObserver.onNext(value);\n                        }\n                    },\n                    throwable -> {\n                        // Don't try to respond if the server has already canceled the request\n                        if (!serverPublisher.isCancelled()) {\n                            responseObserver.onError(throwable);\n                        }\n                    },\n                    responseObserver::onCompleted);\n            serverPublisher.startRequest();\n        } catch (Throwable throwable) {\n            responseObserver.onError(throwable);\n        }\n        return serverPublisher;\n    }\n\n    /**\n     * Implements a stream -> stream call as Flux -> Flux\n     *\n     * @param responseObserver response StreamObserver\n     * @param func service implementation\n     * @return request StreamObserver\n     */\n    public static <T, R> StreamObserver<T> manyToMany(\n            StreamObserver<R> responseObserver, Function<Flux<T>, Flux<R>> func) {\n        // responseObserver is also a subscription of publisher, we can use it to request more data\n        ServerTripleReactorPublisher<T> serverPublisher =\n                new ServerTripleReactorPublisher<>((CallStreamObserver<R>) responseObserver);\n        try {\n            Flux<R> responseFlux = func.apply(Flux.from(serverPublisher));\n            ServerTripleReactorSubscriber<R> serverSubscriber =\n                    responseFlux.subscribeWith(new ServerTripleReactorSubscriber<>());\n            serverSubscriber.subscribe((CallStreamObserver<R>) responseObserver);\n            serverPublisher.startRequest();\n        } catch (Throwable throwable) {\n            responseObserver.onError(throwable);\n        }\n\n        return serverPublisher;\n    }\n\n    private static void doOnResponseHasException(Throwable throwable, StreamObserver<?> responseObserver) {\n        StatusRpcException statusRpcException =\n                TriRpcStatus.getStatus(throwable).asException();\n        responseObserver.onError(statusRpcException);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/handler/ManyToManyMethodHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive.handler;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.reactive.calls.ReactorServerCalls;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\nimport reactor.core.publisher.Flux;\n\n/**\n * The handler of ManyToMany() method for stub invocation.\n */\npublic class ManyToManyMethodHandler<T, R> implements StubMethodHandler<T, R> {\n\n    private final Function<Flux<T>, Flux<R>> func;\n\n    public ManyToManyMethodHandler(Function<Flux<T>, Flux<R>> func) {\n        this.func = func;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public CompletableFuture<StreamObserver<T>> invoke(Object[] arguments) {\n        CallStreamObserver<R> responseObserver = (CallStreamObserver<R>) arguments[0];\n        StreamObserver<T> requestObserver = ReactorServerCalls.manyToMany(responseObserver, func);\n        return CompletableFuture.completedFuture(requestObserver);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/handler/ManyToOneMethodHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive.handler;\n\nimport org.apache.dubbo.common.stream.CallStreamObserver;\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.reactive.calls.ReactorServerCalls;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n/**\n * The handler of ManyToOne() method for stub invocation.\n */\npublic class ManyToOneMethodHandler<T, R> implements StubMethodHandler<T, R> {\n\n    private final Function<Flux<T>, Mono<R>> func;\n\n    public ManyToOneMethodHandler(Function<Flux<T>, Mono<R>> func) {\n        this.func = func;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public CompletableFuture<StreamObserver<T>> invoke(Object[] arguments) {\n        CallStreamObserver<R> responseObserver = (CallStreamObserver<R>) arguments[0];\n        StreamObserver<T> requestObserver = ReactorServerCalls.manyToOne(responseObserver, func);\n        return CompletableFuture.completedFuture(requestObserver);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/handler/OneToManyMethodHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive.handler;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.reactive.calls.ReactorServerCalls;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n/**\n * The handler of OneToMany() method for stub invocation.\n */\npublic class OneToManyMethodHandler<T, R> implements StubMethodHandler<T, R> {\n\n    private final Function<Mono<T>, Flux<R>> func;\n\n    public OneToManyMethodHandler(Function<Mono<T>, Flux<R>> func) {\n        this.func = func;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public CompletableFuture<?> invoke(Object[] arguments) {\n        T request = (T) arguments[0];\n        StreamObserver<R> responseObserver = (StreamObserver<R>) arguments[1];\n        return ReactorServerCalls.oneToMany(request, responseObserver, func);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/main/java/org/apache/dubbo/reactive/handler/OneToOneMethodHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive.handler;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.reactive.calls.ReactorServerCalls;\nimport org.apache.dubbo.rpc.stub.FutureToObserverAdaptor;\nimport org.apache.dubbo.rpc.stub.StubMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\nimport reactor.core.publisher.Mono;\n\n/**\n * The handler of OneToOne() method for stub invocation.\n */\npublic class OneToOneMethodHandler<T, R> implements StubMethodHandler<T, R> {\n\n    private final Function<Mono<T>, Mono<R>> func;\n\n    public OneToOneMethodHandler(Function<Mono<T>, Mono<R>> func) {\n        this.func = func;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public CompletableFuture<R> invoke(Object[] arguments) {\n        T request = (T) arguments[0];\n        CompletableFuture<R> future = new CompletableFuture<>();\n        StreamObserver<R> responseObserver = new FutureToObserverAdaptor<>(future);\n        ReactorServerCalls.oneToOne(request, responseObserver, func);\n        return future;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/CreateObserverAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.common.stream.ServerCallStreamObserver;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.mockito.Mockito;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.doAnswer;\n\npublic class CreateObserverAdapter {\n\n    private ServerCallStreamObserver<String> responseObserver;\n    private AtomicInteger nextCounter;\n    private AtomicInteger completeCounter;\n    private AtomicInteger errorCounter;\n\n    CreateObserverAdapter() {\n\n        nextCounter = new AtomicInteger();\n        completeCounter = new AtomicInteger();\n        errorCounter = new AtomicInteger();\n\n        responseObserver = Mockito.mock(ServerCallStreamObserver.class);\n        doAnswer(o -> nextCounter.incrementAndGet()).when(responseObserver).onNext(anyString());\n        doAnswer(o -> completeCounter.incrementAndGet()).when(responseObserver).onCompleted();\n        doAnswer(o -> errorCounter.incrementAndGet()).when(responseObserver).onError(any(Throwable.class));\n    }\n\n    public AtomicInteger getCompleteCounter() {\n        return completeCounter;\n    }\n\n    public AtomicInteger getNextCounter() {\n        return nextCounter;\n    }\n\n    public AtomicInteger getErrorCounter() {\n        return errorCounter;\n    }\n\n    public ServerCallStreamObserver<String> getResponseObserver() {\n        return this.responseObserver;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/ManyToManyMethodHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.reactive.handler.ManyToManyMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * Unit test for ManyToManyMethodHandler\n */\npublic final class ManyToManyMethodHandlerTest {\n    @Test\n    void testInvoke() throws ExecutionException, InterruptedException {\n        CreateObserverAdapter creator = new CreateObserverAdapter();\n\n        ManyToManyMethodHandler<String, String> handler =\n                new ManyToManyMethodHandler<>(requestFlux -> requestFlux.map(r -> r + \"0\"));\n        CompletableFuture<StreamObserver<String>> future = handler.invoke(new Object[] {creator.getResponseObserver()});\n        StreamObserver<String> requestObserver = future.get();\n        for (int i = 0; i < 10; i++) {\n            requestObserver.onNext(String.valueOf(i));\n        }\n        requestObserver.onCompleted();\n        Assertions.assertEquals(10, creator.getNextCounter().get());\n        Assertions.assertEquals(0, creator.getErrorCounter().get());\n        Assertions.assertEquals(1, creator.getCompleteCounter().get());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/ManyToOneMethodHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.reactive.handler.ManyToOneMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * Unit test for ManyToOneMethodHandler\n */\npublic final class ManyToOneMethodHandlerTest {\n\n    private StreamObserver<String> requestObserver;\n    private CreateObserverAdapter creator;\n\n    @BeforeEach\n    void init() throws ExecutionException, InterruptedException {\n        creator = new CreateObserverAdapter();\n        ManyToOneMethodHandler<String, String> handler = new ManyToOneMethodHandler<>(requestFlux ->\n                requestFlux.map(Integer::valueOf).reduce(Integer::sum).map(String::valueOf));\n        CompletableFuture<StreamObserver<String>> future = handler.invoke(new Object[] {creator.getResponseObserver()});\n        requestObserver = future.get();\n    }\n\n    @Test\n    void testInvoker() {\n        for (int i = 0; i < 10; i++) {\n            requestObserver.onNext(String.valueOf(i));\n        }\n        requestObserver.onCompleted();\n        Assertions.assertEquals(1, creator.getNextCounter().get());\n        Assertions.assertEquals(0, creator.getErrorCounter().get());\n        Assertions.assertEquals(1, creator.getCompleteCounter().get());\n    }\n\n    @Test\n    void testError() {\n        for (int i = 0; i < 10; i++) {\n            if (i == 6) {\n                requestObserver.onError(new Throwable());\n            }\n            requestObserver.onNext(String.valueOf(i));\n        }\n        requestObserver.onCompleted();\n        Assertions.assertEquals(0, creator.getNextCounter().get());\n        Assertions.assertEquals(1, creator.getErrorCounter().get());\n        Assertions.assertEquals(0, creator.getCompleteCounter().get());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/OneToManyMethodHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.reactive.handler.OneToManyMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Flux;\n\n/**\n * Unit test for OneToManyMethodHandler\n */\npublic final class OneToManyMethodHandlerTest {\n\n    private CreateObserverAdapter creator;\n\n    @BeforeEach\n    void init() {\n        creator = new CreateObserverAdapter();\n    }\n\n    @Test\n    void testInvoke() {\n        String request = \"1,2,3,4,5,6,7\";\n        OneToManyMethodHandler<String, String> handler =\n                new OneToManyMethodHandler<>(requestMono -> requestMono.flatMapMany(r -> Flux.fromArray(r.split(\",\"))));\n        CompletableFuture<?> future = handler.invoke(new Object[] {request, creator.getResponseObserver()});\n        Assertions.assertTrue(future.isDone());\n        Assertions.assertEquals(7, creator.getNextCounter().get());\n        Assertions.assertEquals(0, creator.getErrorCounter().get());\n        Assertions.assertEquals(1, creator.getCompleteCounter().get());\n    }\n\n    @Test\n    void testError() {\n        String request = \"1,2,3,4,5,6,7\";\n        OneToManyMethodHandler<String, String> handler =\n                new OneToManyMethodHandler<>(requestMono -> Flux.create(emitter -> {\n                    for (int i = 0; i < 10; i++) {\n                        if (i == 6) {\n                            emitter.error(new Throwable());\n                        } else {\n                            emitter.next(String.valueOf(i));\n                        }\n                    }\n                }));\n        CompletableFuture<?> future = handler.invoke(new Object[] {request, creator.getResponseObserver()});\n        Assertions.assertTrue(future.isDone());\n        Assertions.assertEquals(6, creator.getNextCounter().get());\n        Assertions.assertEquals(1, creator.getErrorCounter().get());\n        Assertions.assertEquals(0, creator.getCompleteCounter().get());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/test/java/org/apache/dubbo/reactive/OneToOneMethodHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.reactive;\n\nimport org.apache.dubbo.reactive.handler.OneToOneMethodHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * Unit test for OneToOneMethodHandler\n */\npublic final class OneToOneMethodHandlerTest {\n\n    @Test\n    void testInvoke() throws ExecutionException, InterruptedException {\n        String request = \"request\";\n        OneToOneMethodHandler<String, String> handler =\n                new OneToOneMethodHandler<>(requestMono -> requestMono.map(r -> r + \"Test\"));\n        CompletableFuture<?> future = handler.invoke(new Object[] {request});\n        assertEquals(\"requestTest\", future.get());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-reactive/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-rest-jaxrs</artifactId>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>javax.ws.rs</groupId>\n      <artifactId>javax.ws.rs-api</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.jboss.resteasy</groupId>\n      <artifactId>resteasy-jaxrs</artifactId>\n      <exclusions>\n        <exclusion>\n          <groupId>*</groupId>\n          <artifactId>*</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>javax.xml.bind</groupId>\n      <artifactId>jaxb-api</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.glassfish.jaxb</groupId>\n      <artifactId>jaxb-runtime</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.yaml</groupId>\n      <artifactId>snakeyaml</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n      <type>test-jar</type>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java-util</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.spockframework</groupId>\n      <artifactId>spock-core</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.codehaus.gmavenplus</groupId>\n        <artifactId>gmavenplus-plugin</artifactId>\n        <executions>\n          <execution>\n            <goals>\n              <goal>compileTests</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>rpc-rest-test</id>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo.extensions</groupId>\n          <artifactId>dubbo-rpc-rest</artifactId>\n          <version>3.3.1</version>\n          <scope>test</scope>\n        </dependency>\n      </dependencies>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/AbstractJaxrsArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractAnnotationBaseArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\nimport java.lang.annotation.Annotation;\n\npublic abstract class AbstractJaxrsArgumentResolver extends AbstractAnnotationBaseArgumentResolver {\n\n    @Override\n    protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta<Annotation> anno) {\n        return new NamedValueMeta(anno.getValue(), Helper.isRequired(param), Helper.defaultValue(param));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/Annotations.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationEnum;\n\nimport java.lang.annotation.Annotation;\n\npublic enum Annotations implements AnnotationEnum {\n    Path,\n    HttpMethod,\n    Produces,\n    Consumes,\n    PathParam,\n    MatrixParam,\n    QueryParam,\n    HeaderParam,\n    CookieParam,\n    FormParam,\n    BeanParam,\n    Body(\"org.jboss.resteasy.annotations.Body\"),\n    Form(\"org.jboss.resteasy.annotations.Form\"),\n    Context(\"javax.ws.rs.core.Context\"),\n    Suspended(\"javax.ws.rs.container.Suspended\"),\n    DefaultValue,\n    Encoded,\n    Nonnull(\"javax.annotation.Nonnull\");\n\n    private final String className;\n    private Class<Annotation> type;\n\n    Annotations(String className) {\n        this.className = className;\n    }\n\n    Annotations() {\n        className = \"javax.ws.rs.\" + name();\n    }\n\n    public String className() {\n        return className;\n    }\n\n    @Override\n    public Class<Annotation> type() {\n        if (type == null) {\n            type = loadType();\n        }\n        return type;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Pair;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.Messages;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.ConstructorMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;\n\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nfinal class BeanArgumentBinder {\n\n    private static final ThreadLocal<Set<Class<?>>> LOCAL = new ThreadLocal<>();\n\n    private final Map<Pair<Class<?>, String>, BeanMeta> cache = CollectionUtils.newConcurrentHashMap();\n    private final ArgumentResolver argumentResolver;\n\n    BeanArgumentBinder(CompositeArgumentResolver argumentResolver) {\n        this.argumentResolver = argumentResolver;\n    }\n\n    public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) {\n        Set<Class<?>> walked = LOCAL.get();\n        if (walked == null) {\n            LOCAL.set(new HashSet<>());\n        }\n        try {\n            return resolveArgument(paramMeta, request, response);\n        } catch (Exception e) {\n            throw new RestException(e, Messages.ARGUMENT_BIND_ERROR, paramMeta.getName(), paramMeta.getType());\n        } finally {\n            if (walked == null) {\n                LOCAL.remove();\n            }\n        }\n    }\n\n    private Object resolveArgument(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) {\n        if (paramMeta.isSimple()) {\n            return argumentResolver.resolve(paramMeta, request, response);\n        }\n\n        // Prevent infinite loops\n        if (LOCAL.get().add(paramMeta.getActualType())) {\n            AnnotationMeta<?> form = paramMeta.findAnnotation(Annotations.Form);\n            if (form != null || paramMeta.isHierarchyAnnotated(Annotations.BeanParam)) {\n                String prefix = form == null ? null : form.getString(\"prefix\");\n                BeanMeta beanMeta = cache.computeIfAbsent(\n                        Pair.of(paramMeta.getActualType(), prefix),\n                        k -> new BeanMeta(paramMeta.getToolKit(), k.getValue(), k.getKey()));\n\n                ConstructorMeta constructor = beanMeta.getConstructor();\n                ParameterMeta[] parameters = constructor.getParameters();\n                Object bean;\n                int len = parameters.length;\n                if (len == 0) {\n                    bean = constructor.newInstance();\n                } else {\n                    Object[] args = new Object[len];\n                    for (int i = 0; i < len; i++) {\n                        args[i] = resolveArgument(parameters[i], request, response);\n                    }\n                    bean = constructor.newInstance(args);\n                }\n\n                for (PropertyMeta propertyMeta : beanMeta.getProperties()) {\n                    if (propertyMeta.canSetValue()) {\n                        propertyMeta.setValue(bean, resolveArgument(propertyMeta, request, response));\n                    }\n                }\n\n                return bean;\n            }\n        }\n\n        return TypeUtils.nullDefault(paramMeta.getType());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanParamArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"javax.ws.rs.BeanParam\")\npublic class BeanParamArgumentResolver implements AnnotationBaseArgumentResolver<Annotation> {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.BeanParam.type();\n    }\n\n    @Override\n    public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta<Annotation> annotation) {\n        return null;\n    }\n\n    @Override\n    public Object resolve(\n            ParameterMeta parameter,\n            AnnotationMeta<Annotation> annotation,\n            HttpRequest request,\n            HttpResponse response) {\n        return parameter.bind(request, response);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.io.IOException;\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"org.jboss.resteasy.annotations.Body\")\npublic class BodyArgumentResolver implements AnnotationBaseArgumentResolver<Annotation> {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.Body.type();\n    }\n\n    @Override\n    public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta<Annotation> annotation) {\n        return new NamedValueMeta().setParamType(ParamType.Body);\n    }\n\n    @Override\n    public Object resolve(\n            ParameterMeta parameter,\n            AnnotationMeta<Annotation> annotation,\n            HttpRequest request,\n            HttpResponse response) {\n        Class<?> type = parameter.getActualType();\n        if (type == byte[].class) {\n            try {\n                return StreamUtils.readBytes(request.inputStream());\n            } catch (IOException e) {\n                throw new RestException(e);\n            }\n        }\n        return RequestUtils.decodeBody(request, parameter.getActualGenericType());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/CookieParamArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.http12.HttpCookie;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\n\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\n@Activate(onClass = \"javax.ws.rs.CookieParam\")\npublic class CookieParamArgumentResolver extends AbstractJaxrsArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.CookieParam.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Cookie;\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.cookie(meta.name());\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        Collection<HttpCookie> cookies = request.cookies();\n        if (cookies.isEmpty()) {\n            return Collections.emptyList();\n        }\n        String name = meta.name();\n        List<HttpCookie> result = new ArrayList<>(cookies.size());\n        for (HttpCookie cookie : cookies) {\n            if (name.equals(cookie.name())) {\n                result.add(cookie);\n            }\n        }\n        return result;\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        Collection<HttpCookie> cookies = request.cookies();\n        if (cookies.isEmpty()) {\n            return Collections.emptyMap();\n        }\n        Map<String, List<HttpCookie>> mapValue = CollectionUtils.newLinkedHashMap(cookies.size());\n        for (HttpCookie cookie : cookies) {\n            mapValue.computeIfAbsent(cookie.name(), k -> new ArrayList<>()).add(cookie);\n        }\n        return mapValue;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;\n\nimport java.io.IOException;\n\n@Activate(order = Integer.MAX_VALUE - 10000, onClass = \"javax.ws.rs.Path\")\npublic class FallbackArgumentResolver extends AbstractArgumentResolver {\n\n    @Override\n    public boolean accept(ParameterMeta param) {\n        return param.getToolKit().getDialect() == RestConstants.DIALECT_JAXRS;\n    }\n\n    @Override\n    protected NamedValueMeta createNamedValueMeta(ParameterMeta param) {\n        return new NamedValueMeta(null, param.isAnnotated(Annotations.Nonnull), Helper.defaultValue(param))\n                .setParamType(param.isSimple() ? null : ParamType.Body);\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        Object value = RequestUtils.decodeBody(request, meta.genericType());\n        if (value != null) {\n            return value;\n        }\n        if (meta.parameter().isStream()) {\n            return null;\n        }\n        if (meta.parameter().isSimple()) {\n            return request.parameter(meta.name());\n        }\n        return null;\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        Class<?> type = meta.type();\n        if (type == byte[].class) {\n            try {\n                return StreamUtils.readBytes(request.inputStream());\n            } catch (IOException e) {\n                throw new RestException(e);\n            }\n        }\n        Object value = RequestUtils.decodeBody(request, meta.genericType());\n        if (value != null) {\n            return value;\n        }\n        if (TypeUtils.isSimpleProperty(meta.nestedType(0))) {\n            return request.parameterValues(meta.name());\n        }\n        return null;\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        Object value = RequestUtils.decodeBody(request, meta.genericType());\n        if (value != null) {\n            return value;\n        }\n        if (TypeUtils.isSimpleProperty(meta.nestedType(1))) {\n            return RequestUtils.getParametersMap(request);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"org.jboss.resteasy.annotations.Form\")\npublic class FormArgumentResolver implements AnnotationBaseArgumentResolver<Annotation> {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.Form.type();\n    }\n\n    @Override\n    public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta<Annotation> annotation) {\n        return new NamedValueMeta().setParamType(ParamType.Body);\n    }\n\n    @Override\n    public Object resolve(\n            ParameterMeta parameter,\n            AnnotationMeta<Annotation> annotation,\n            HttpRequest request,\n            HttpResponse response) {\n        return parameter.bind(request, response);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormParamArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\n\nimport java.lang.annotation.Annotation;\n\n/**\n * TODO: support nested values: (e.g., 'telephoneNumbers[0].countryCode' 'address[INVOICE].street')\n */\n@Activate(onClass = \"javax.ws.rs.FormParam\")\npublic class FormParamArgumentResolver extends AbstractJaxrsArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.FormParam.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Form;\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return CollectionUtils.first(request.formParameterValues(getFullName(meta)));\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.formParameterValues(getFullName(meta));\n    }\n\n    private String getFullName(NamedValueMeta meta) {\n        String prefix = meta.parameter().getPrefix();\n        return prefix == null ? meta.name() : prefix + '.' + meta.name();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/HeaderParamArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\n\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"javax.ws.rs.HeaderParam\")\npublic class HeaderParamArgumentResolver extends AbstractJaxrsArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.HeaderParam.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Header;\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.header(meta.name());\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.headerValues(meta.name());\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.headers().asMap();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/Helper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.remoting.http12.HttpCookie;\nimport org.apache.dubbo.remoting.http12.HttpResult;\nimport org.apache.dubbo.remoting.http12.HttpUtils;\nimport org.apache.dubbo.remoting.http12.message.DefaultHttpResult.Builder;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.NewCookie;\nimport javax.ws.rs.core.Response;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\npublic final class Helper {\n\n    private Helper() {}\n\n    public static boolean isRequired(ParameterMeta parameter) {\n        return parameter.isHierarchyAnnotated(Annotations.Nonnull);\n    }\n\n    public static String defaultValue(ParameterMeta parameter) {\n        AnnotationMeta<?> meta = parameter.findAnnotation(Annotations.DefaultValue);\n        return meta == null ? null : meta.getValue();\n    }\n\n    public static HttpResult<Object> toBody(Response response) {\n        Builder<Object> builder = HttpResult.builder().status(response.getStatus());\n        if (response.hasEntity()) {\n            builder.body(response.getEntity());\n        }\n        builder.headers(response.getStringHeaders());\n        return builder.build();\n    }\n\n    public static MediaType toMediaType(String mediaType) {\n        if (mediaType == null) {\n            return null;\n        }\n        int index = mediaType.indexOf('/');\n        if (index == -1) {\n            return null;\n        }\n        return new MediaType(mediaType.substring(0, index), mediaType.substring(index + 1));\n    }\n\n    public static String toString(MediaType mediaType) {\n        return mediaType.getType() + '/' + mediaType.getSubtype();\n    }\n\n    public static List<MediaType> toMediaTypes(String accept) {\n        return HttpUtils.parseAccept(accept).stream().map(Helper::toMediaType).collect(Collectors.toList());\n    }\n\n    public static NewCookie convert(HttpCookie cookie) {\n        return new NewCookie(\n                cookie.name(),\n                cookie.value(),\n                cookie.path(),\n                cookie.domain(),\n                null,\n                (int) cookie.maxAge(),\n                cookie.secure(),\n                cookie.httpOnly());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsHttpRequestAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport javax.ws.rs.core.HttpHeaders;\nimport javax.ws.rs.core.MultivaluedHashMap;\nimport javax.ws.rs.core.MultivaluedMap;\n\nimport java.io.InputStream;\nimport java.net.URI;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.List;\n\nimport org.jboss.resteasy.specimpl.ResteasyHttpHeaders;\nimport org.jboss.resteasy.spi.ResteasyAsynchronousContext;\nimport org.jboss.resteasy.spi.ResteasyUriInfo;\n\npublic final class JaxrsHttpRequestAdapter implements org.jboss.resteasy.spi.HttpRequest {\n\n    private final HttpRequest request;\n\n    private HttpHeaders headers;\n    private ResteasyUriInfo uriInfo;\n\n    public JaxrsHttpRequestAdapter(HttpRequest request) {\n        this.request = request;\n    }\n\n    @Override\n    public HttpHeaders getHttpHeaders() {\n        HttpHeaders headers = this.headers;\n        if (headers == null) {\n            headers = new ResteasyHttpHeaders(new MultivaluedMapWrapper<>(request.headers()));\n            this.headers = headers;\n        }\n        return headers;\n    }\n\n    @Override\n    public MultivaluedMap<String, String> getMutableHeaders() {\n        return headers.getRequestHeaders();\n    }\n\n    @Override\n    public InputStream getInputStream() {\n        return request.inputStream();\n    }\n\n    @Override\n    public void setInputStream(InputStream stream) {\n        request.setInputStream(stream);\n    }\n\n    @Override\n    public ResteasyUriInfo getUri() {\n        ResteasyUriInfo uriInfo = this.uriInfo;\n        if (uriInfo == null) {\n            uriInfo = new ResteasyUriInfo(request.rawPath(), request.query(), \"/\");\n            this.uriInfo = uriInfo;\n        }\n        return uriInfo;\n    }\n\n    @Override\n    public String getHttpMethod() {\n        return request.method();\n    }\n\n    @Override\n    public void setHttpMethod(String method) {\n        request.setMethod(method);\n    }\n\n    @Override\n    public void setRequestUri(URI requestUri) throws IllegalStateException {\n        String query = requestUri.getRawQuery();\n        request.setUri(requestUri.getRawPath() + (query == null ? \"\" : '?' + query));\n    }\n\n    @Override\n    public void setRequestUri(URI baseUri, URI requestUri) throws IllegalStateException {\n        String query = requestUri.getRawQuery();\n        request.setUri(baseUri.getRawPath() + requestUri.getRawPath() + (query == null ? \"\" : '?' + query));\n    }\n\n    @Override\n    public MultivaluedMap<String, String> getFormParameters() {\n        MultivaluedMap<String, String> result = new MultivaluedHashMap<>();\n        for (String name : request.formParameterNames()) {\n            List<String> values = request.formParameterValues(name);\n            if (values == null) {\n                continue;\n            }\n            for (String value : values) {\n                result.add(name, RequestUtils.encodeURL(value));\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public MultivaluedMap<String, String> getDecodedFormParameters() {\n        return new MultivaluedMapWrapper<>(RequestUtils.getFormParametersMap(request));\n    }\n\n    @Override\n    public Object getAttribute(String attribute) {\n        return request.attribute(attribute);\n    }\n\n    @Override\n    public void setAttribute(String name, Object value) {\n        request.setAttribute(name, value);\n    }\n\n    @Override\n    public void removeAttribute(String name) {\n        request.removeAttribute(name);\n    }\n\n    @Override\n    public Enumeration<String> getAttributeNames() {\n        return Collections.enumeration(request.attributeNames());\n    }\n\n    @Override\n    public ResteasyAsynchronousContext getAsyncContext() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean isInitial() {\n        return false;\n    }\n\n    @Override\n    public void forward(String path) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean wasForwarded() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsHttpResponseAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.remoting.http12.HttpCookie;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\n\nimport javax.ws.rs.core.MultivaluedMap;\nimport javax.ws.rs.core.NewCookie;\n\nimport java.io.OutputStream;\n\npublic final class JaxrsHttpResponseAdapter implements org.jboss.resteasy.spi.HttpResponse {\n\n    private final HttpResponse response;\n\n    private MultivaluedMap<String, Object> headers;\n\n    public JaxrsHttpResponseAdapter(HttpResponse response) {\n        this.response = response;\n    }\n\n    @Override\n    public int getStatus() {\n        return response.status();\n    }\n\n    @Override\n    public void setStatus(int status) {\n        response.setStatus(status);\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public MultivaluedMap<String, Object> getOutputHeaders() {\n        MultivaluedMap<String, Object> headers = this.headers;\n        if (headers == null) {\n            headers = new MultivaluedMapWrapper(response.headers());\n            this.headers = headers;\n        }\n        return headers;\n    }\n\n    @Override\n    public OutputStream getOutputStream() {\n        return response.outputStream();\n    }\n\n    @Override\n    public void setOutputStream(OutputStream os) {\n        response.setOutputStream(os);\n    }\n\n    @Override\n    public void addNewCookie(NewCookie cookie) {\n        HttpCookie hCookie = new HttpCookie(cookie.getName(), cookie.getValue());\n        hCookie.setDomain(cookie.getDomain());\n        hCookie.setPath(cookie.getPath());\n        hCookie.setMaxAge(cookie.getMaxAge());\n        hCookie.setSecure(cookie.isSecure());\n        hCookie.setHttpOnly(cookie.isHttpOnly());\n        response.addCookie(hCookie);\n    }\n\n    @Override\n    public void sendError(int status) {\n        response.sendError(status);\n    }\n\n    @Override\n    public void sendError(int status, String message) {\n        response.sendError(status, message);\n    }\n\n    @Override\n    public boolean isCommitted() {\n        return response.isCommitted();\n    }\n\n    @Override\n    public void reset() {\n        response.reset();\n    }\n\n    @Override\n    public void flushBuffer() {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsMiscArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport javax.ws.rs.core.Cookie;\nimport javax.ws.rs.core.Form;\nimport javax.ws.rs.core.HttpHeaders;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.MultivaluedMap;\nimport javax.ws.rs.core.UriInfo;\n\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jboss.resteasy.specimpl.ResteasyHttpHeaders;\nimport org.jboss.resteasy.spi.ResteasyUriInfo;\n\n@Activate(onClass = \"javax.ws.rs.Path\")\npublic class JaxrsMiscArgumentResolver implements ArgumentResolver {\n\n    private static final Set<Class<?>> SUPPORTED_TYPES = new HashSet<>();\n\n    static {\n        SUPPORTED_TYPES.add(Cookie.class);\n        SUPPORTED_TYPES.add(Form.class);\n        SUPPORTED_TYPES.add(HttpHeaders.class);\n        SUPPORTED_TYPES.add(MediaType.class);\n        SUPPORTED_TYPES.add(MultivaluedMap.class);\n        SUPPORTED_TYPES.add(UriInfo.class);\n    }\n\n    @Override\n    public boolean accept(ParameterMeta parameter) {\n        return SUPPORTED_TYPES.contains(parameter.getActualType());\n    }\n\n    @Override\n    @SuppressWarnings({\"rawtypes\", \"unchecked\"})\n    public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse response) {\n        Class<?> type = parameter.getActualType();\n        if (Cookie.class.isAssignableFrom(type)) {\n            return Helper.convert(request.cookie(parameter.getRequiredName()));\n        }\n        if (Form.class.isAssignableFrom(type)) {\n            return RequestUtils.getFormParametersMap(request);\n        }\n        if (HttpHeaders.class.isAssignableFrom(type)) {\n            return new ResteasyHttpHeaders(new MultivaluedMapWrapper<>(request.headers()));\n        }\n        if (MediaType.class.isAssignableFrom(type)) {\n            return Helper.toMediaType(request.mediaType());\n        }\n        if (MultivaluedMap.class.isAssignableFrom(type)) {\n            return new MultivaluedMapWrapper<>((Map) RequestUtils.getParametersMap(request));\n        }\n        if (UriInfo.class.isAssignableFrom(type)) {\n            return new ResteasyUriInfo(request.rawPath(), request.query(), \"/\");\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRequestMappingResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.config.nested.RestConfig;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.cors.CorsUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping.Builder;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationSupport;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.CorsMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit;\n\n@Activate(onClass = {\"javax.ws.rs.Path\", \"javax.ws.rs.container.ContainerRequestContext\"})\npublic class JaxrsRequestMappingResolver implements RequestMappingResolver {\n\n    private final RestToolKit toolKit;\n    private RestConfig restConfig;\n    private CorsMeta globalCorsMeta;\n\n    public JaxrsRequestMappingResolver(FrameworkModel frameworkModel) {\n        toolKit = new JaxrsRestToolKit(frameworkModel);\n    }\n\n    @Override\n    public RestToolKit getRestToolKit() {\n        return toolKit;\n    }\n\n    @Override\n    public void setRestConfig(RestConfig restConfig) {\n        this.restConfig = restConfig;\n    }\n\n    @Override\n    public RequestMapping resolve(ServiceMeta serviceMeta) {\n        AnnotationMeta<?> path = serviceMeta.findAnnotation(Annotations.Path);\n        if (path == null) {\n            return null;\n        }\n        return builder(serviceMeta, path, null)\n                .name(serviceMeta.getType().getSimpleName())\n                .contextPath(serviceMeta.getContextPath())\n                .build();\n    }\n\n    @Override\n    public RequestMapping resolve(MethodMeta methodMeta) {\n        AnnotationMeta<?> path = methodMeta.findAnnotation(Annotations.Path);\n        if (path == null) {\n            return null;\n        }\n        AnnotationMeta<?> httpMethod = methodMeta.findMergedAnnotation(Annotations.HttpMethod);\n        if (httpMethod == null) {\n            return null;\n        }\n        ServiceMeta serviceMeta = methodMeta.getServiceMeta();\n        if (globalCorsMeta == null) {\n            globalCorsMeta = CorsUtils.getGlobalCorsMeta(restConfig);\n        }\n        return builder(methodMeta, path, httpMethod)\n                .name(methodMeta.getMethodName())\n                .contextPath(methodMeta.getServiceMeta().getContextPath())\n                .service(serviceMeta.getServiceGroup(), serviceMeta.getServiceVersion())\n                .cors(globalCorsMeta)\n                .build();\n    }\n\n    private Builder builder(AnnotationSupport meta, AnnotationMeta<?> path, AnnotationMeta<?> httpMethod) {\n        Builder builder = RequestMapping.builder().path(path.getValue());\n        if (httpMethod == null) {\n            httpMethod = meta.findMergedAnnotation(Annotations.HttpMethod);\n        }\n        if (httpMethod != null) {\n            builder.method(httpMethod.getValue());\n        }\n        AnnotationMeta<?> produces = meta.findAnnotation(Annotations.Produces);\n        if (produces != null) {\n            builder.produce(produces.getValueArray());\n        }\n        AnnotationMeta<?> consumes = meta.findAnnotation(Annotations.Consumes);\n        if (consumes != null) {\n            builder.consume(consumes.getValueArray());\n        }\n        return builder;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsResponseRestFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.Listener;\n\nimport javax.ws.rs.core.Response;\n\n@Activate(order = -10000, onClass = \"javax.ws.rs.Path\")\npublic class JaxrsResponseRestFilter implements RestFilter, Listener {\n\n    @Override\n    public void onResponse(Result result, HttpRequest request, HttpResponse response) {\n        if (result.hasException()) {\n            return;\n        }\n\n        Object value = result.getValue();\n        if (value instanceof Response) {\n            result.setValue(Helper.toBody((Response) value));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.AbstractRestToolKit;\n\nimport javax.ws.rs.ext.ParamConverter;\n\nfinal class JaxrsRestToolKit extends AbstractRestToolKit {\n\n    private final BeanArgumentBinder binder;\n    private final ParamConverterFactory paramConverterFactory;\n\n    public JaxrsRestToolKit(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n        binder = new BeanArgumentBinder(argumentResolver);\n        paramConverterFactory = new ParamConverterFactory();\n    }\n\n    @Override\n    public int getDialect() {\n        return RestConstants.DIALECT_JAXRS;\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public Object convert(Object value, ParameterMeta parameter) {\n        ParamConverter converter = paramConverterFactory.getParamConverter(\n                parameter.getType(), parameter.getGenericType(), parameter.getRawAnnotations());\n        if (converter != null) {\n            return value instanceof String ? converter.fromString((String) value) : converter.toString(value);\n        }\n        return super.convert(value, parameter);\n    }\n\n    @Override\n    public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) {\n        return binder.bind(parameter, request, response);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MatrixParamArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.lang.annotation.Annotation;\nimport java.util.List;\nimport java.util.Map;\n\n@Activate(onClass = \"javax.ws.rs.MatrixParam\")\npublic class MatrixParamArgumentResolver extends AbstractJaxrsArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.MatrixParam.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.MatrixVariable;\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return CollectionUtils.first(doResolveCollectionValue(meta, request));\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return doResolveCollectionValue(meta, request);\n    }\n\n    private static List<String> doResolveCollectionValue(NamedValueMeta meta, HttpRequest request) {\n        Map<String, String> variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE);\n        return RequestUtils.parseMatrixVariableValues(variableMap, meta.name());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MultivaluedMapCreator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\nimport javax.ws.rs.core.MultivaluedHashMap;\nimport javax.ws.rs.core.MultivaluedMap;\n\n@Activate(onClass = \"javax.ws.rs.core.MultivaluedMap\")\npublic class MultivaluedMapCreator implements ArgumentConverter<Integer, MultivaluedMap<?, ?>> {\n\n    @Override\n    public MultivaluedMap<?, ?> convert(Integer value, ParameterMeta parameter) {\n        return new MultivaluedHashMap<>(value);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MultivaluedMapWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\n\nimport javax.ws.rs.core.AbstractMultivaluedMap;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic final class MultivaluedMapWrapper<K, V> extends AbstractMultivaluedMap<K, V> {\n\n    public MultivaluedMapWrapper(Map<K, List<V>> store) {\n        super(store);\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public MultivaluedMapWrapper(HttpHeaders headers) {\n        super((Map) headers.asMap());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/ParamConverterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.utils.CollectionUtils;\n\nimport javax.ws.rs.ext.ParamConverter;\nimport javax.ws.rs.ext.ParamConverterProvider;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.ServiceLoader;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_ERROR_LOAD_EXTENSION;\nimport static org.apache.dubbo.common.logger.LoggerFactory.getErrorTypeAwareLogger;\n\nfinal class ParamConverterFactory {\n\n    private static final ErrorTypeAwareLogger logger = getErrorTypeAwareLogger(ParamConverterFactory.class);\n    private final Map<List<Object>, Optional<ParamConverter<?>>> cache = CollectionUtils.newConcurrentHashMap();\n    private final List<ParamConverterProvider> providers = new ArrayList<>();\n\n    ParamConverterFactory() {\n        Iterator<ParamConverterProvider> it =\n                ServiceLoader.load(ParamConverterProvider.class).iterator();\n        while (it.hasNext()) {\n            try {\n                providers.add(it.next());\n            } catch (Throwable t) {\n                logger.error(COMMON_ERROR_LOAD_EXTENSION, \"\", \"\", \"Failed to load ParamConverterProvider\", t);\n            }\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> ParamConverter<T> getParamConverter(Class<T> type, Type genericType, Annotation[] annotations) {\n        if (providers.isEmpty()) {\n            return null;\n        }\n        List<Object> key = new ArrayList<>(annotations.length + 2);\n        key.add(type);\n        key.add(genericType);\n        Collections.addAll(key, annotations);\n        return (ParamConverter<T>) cache.computeIfAbsent(key, k -> {\n                    for (ParamConverterProvider provider : providers) {\n                        ParamConverter<T> converter = provider.getConverter(type, genericType, annotations);\n                        if (converter != null) {\n                            return Optional.of(converter);\n                        }\n                    }\n                    return Optional.empty();\n                })\n                .orElse(null);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.Messages;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestParameterException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Map;\n\n@Activate(onClass = \"javax.ws.rs.PathParam\")\npublic class PathParamArgumentResolver implements AnnotationBaseArgumentResolver<Annotation> {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.PathParam.type();\n    }\n\n    @Override\n    public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta<Annotation> annotation) {\n        return new NamedValueMeta(annotation.getValue(), true).setParamType(ParamType.PathVariable);\n    }\n\n    @Override\n    public Object resolve(\n            ParameterMeta parameter,\n            AnnotationMeta<Annotation> annotation,\n            HttpRequest request,\n            HttpResponse response) {\n        Map<String, String> variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE);\n        String name = annotation.getValue();\n        if (StringUtils.isEmpty(name)) {\n            name = parameter.getRequiredName();\n        }\n        if (variableMap == null) {\n            if (Helper.isRequired(parameter)) {\n                throw new RestParameterException(Messages.ARGUMENT_VALUE_MISSING, name, parameter.getType());\n            }\n            return null;\n        }\n        String value = variableMap.get(name);\n        if (value == null) {\n            return null;\n        }\n        int index = value.indexOf(';');\n        if (index != -1) {\n            value = value.substring(0, index);\n        }\n        return parameter.isAnnotated(Annotations.Encoded) ? value : RequestUtils.decodeURL(value);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/QueryParamArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"javax.ws.rs.QueryParam\")\npublic class QueryParamArgumentResolver extends AbstractJaxrsArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.QueryParam.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Param;\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.parameter(meta.name());\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.parameterValues(meta.name());\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return RequestUtils.getParametersMap(request);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/filter/ContainerRequestContextImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;\n\nimport org.apache.dubbo.remoting.http12.HttpCookie;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.Helper;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.JaxrsHttpRequestAdapter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.JaxrsHttpResponseAdapter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MultivaluedMapWrapper;\n\nimport javax.ws.rs.container.ContainerRequestContext;\nimport javax.ws.rs.core.Cookie;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.MultivaluedMap;\nimport javax.ws.rs.core.Request;\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.core.SecurityContext;\nimport javax.ws.rs.core.UriInfo;\n\nimport java.io.InputStream;\nimport java.net.URI;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.jboss.resteasy.specimpl.RequestImpl;\nimport org.jboss.resteasy.spi.ResteasyUriInfo;\n\nfinal class ContainerRequestContextImpl implements ContainerRequestContext {\n\n    private final HttpRequest request;\n    private final HttpResponse response;\n\n    private Request req;\n    private MultivaluedMap<String, String> headers;\n    private UriInfo uriInfo;\n\n    private boolean aborted;\n\n    public ContainerRequestContextImpl(HttpRequest request, HttpResponse response) {\n        this.request = request;\n        this.response = response;\n    }\n\n    @Override\n    public Object getProperty(String name) {\n        return request.attribute(name);\n    }\n\n    @Override\n    public Collection<String> getPropertyNames() {\n        return request.parameterNames();\n    }\n\n    @Override\n    public void setProperty(String name, Object object) {\n        request.setAttribute(name, object);\n    }\n\n    @Override\n    public void removeProperty(String name) {\n        request.removeAttribute(name);\n    }\n\n    @Override\n    public UriInfo getUriInfo() {\n        UriInfo uriInfo = this.uriInfo;\n        if (uriInfo == null) {\n            uriInfo = new ResteasyUriInfo(request.rawPath(), request.query(), \"/\");\n            this.uriInfo = uriInfo;\n        }\n        return uriInfo;\n    }\n\n    @Override\n    public void setRequestUri(URI requestUri) {\n        String query = requestUri.getRawQuery();\n        request.setUri(requestUri.getRawPath() + (query == null ? \"\" : '?' + query));\n    }\n\n    @Override\n    public void setRequestUri(URI baseUri, URI requestUri) {\n        String query = requestUri.getRawQuery();\n        request.setUri(baseUri.getRawPath() + requestUri.getRawPath() + (query == null ? \"\" : '?' + query));\n    }\n\n    @Override\n    public Request getRequest() {\n        Request req = this.req;\n        if (req == null) {\n            req = new RequestImpl(new JaxrsHttpRequestAdapter(request), new JaxrsHttpResponseAdapter(response));\n            this.req = req;\n        }\n        return req;\n    }\n\n    @Override\n    public String getMethod() {\n        return request.method();\n    }\n\n    @Override\n    public void setMethod(String method) {\n        request.setMethod(method);\n    }\n\n    @Override\n    public MultivaluedMap<String, String> getHeaders() {\n        MultivaluedMap<String, String> headers = this.headers;\n        if (headers == null) {\n            headers = new MultivaluedMapWrapper<>(request.headers());\n            this.headers = headers;\n        }\n        return headers;\n    }\n\n    @Override\n    public String getHeaderString(String name) {\n        return request.header(name);\n    }\n\n    @Override\n    public Date getDate() {\n        return null;\n    }\n\n    @Override\n    public Locale getLanguage() {\n        return request.locale();\n    }\n\n    @Override\n    public int getLength() {\n        return request.contentLength();\n    }\n\n    @Override\n    public MediaType getMediaType() {\n        return Helper.toMediaType(request.mediaType());\n    }\n\n    @Override\n    public List<MediaType> getAcceptableMediaTypes() {\n        return Helper.toMediaTypes(request.accept());\n    }\n\n    @Override\n    public List<Locale> getAcceptableLanguages() {\n        return request.locales();\n    }\n\n    @Override\n    public Map<String, Cookie> getCookies() {\n        Collection<HttpCookie> cookies = request.cookies();\n        Map<String, Cookie> result = new HashMap<>(cookies.size());\n        for (HttpCookie cookie : cookies) {\n            result.put(cookie.name(), Helper.convert(cookie));\n        }\n        return result;\n    }\n\n    @Override\n    @SuppressWarnings(\"resource\")\n    public boolean hasEntity() {\n        return request.inputStream() != null;\n    }\n\n    @Override\n    public InputStream getEntityStream() {\n        return request.inputStream();\n    }\n\n    @Override\n    public void setEntityStream(InputStream input) {\n        request.setInputStream(input);\n    }\n\n    @Override\n    public SecurityContext getSecurityContext() {\n        return null;\n    }\n\n    @Override\n    public void setSecurityContext(SecurityContext context) {}\n\n    @Override\n    public void abortWith(Response response) {\n        this.response.setBody(Helper.toBody(response));\n        aborted = true;\n    }\n\n    public boolean isAborted() {\n        return aborted;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/filter/ContainerRequestFilterAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.AbstractRestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;\n\nimport javax.ws.rs.container.ContainerRequestFilter;\n\n@Activate(onClass = \"javax.ws.rs.container.ContainerResponseFilter\")\npublic class ContainerRequestFilterAdapter implements RestExtensionAdapter<ContainerRequestFilter> {\n\n    @Override\n    public boolean accept(Object extension) {\n        return extension instanceof ContainerRequestFilter;\n    }\n\n    @Override\n    public RestFilter adapt(ContainerRequestFilter extension) {\n        return new Filter(extension);\n    }\n\n    private static final class Filter extends AbstractRestFilter<ContainerRequestFilter> {\n\n        public Filter(ContainerRequestFilter extension) {\n            super(extension);\n        }\n\n        @Override\n        public void doFilter(HttpRequest request, HttpResponse response, FilterChain chain) throws Exception {\n            ContainerRequestContextImpl context = new ContainerRequestContextImpl(request, response);\n            extension.filter(context);\n            if (context.isAborted()) {\n                return;\n            }\n            chain.doFilter(request, response);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/filter/ContainerResponseContextImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;\n\nimport org.apache.dubbo.remoting.http12.HttpCookie;\nimport org.apache.dubbo.remoting.http12.HttpHeaderNames;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.HttpUtils;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.Helper;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MultivaluedMapWrapper;\n\nimport javax.ws.rs.container.ContainerResponseContext;\nimport javax.ws.rs.core.EntityTag;\nimport javax.ws.rs.core.Link;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.MultivaluedMap;\nimport javax.ws.rs.core.NewCookie;\nimport javax.ws.rs.core.Response.Status;\nimport javax.ws.rs.core.Response.StatusType;\n\nimport java.io.OutputStream;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Type;\nimport java.net.URI;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.netty.handler.codec.DateFormatter;\n\nfinal class ContainerResponseContextImpl implements ContainerResponseContext {\n\n    private final HttpRequest request;\n    private final HttpResponse response;\n    private final Result result;\n\n    private MultivaluedMap<String, String> headers;\n\n    public ContainerResponseContextImpl(HttpRequest request, HttpResponse response, Result result) {\n        this.request = request;\n        this.response = response;\n        this.result = result;\n    }\n\n    @Override\n    public int getStatus() {\n        return response.status();\n    }\n\n    @Override\n    public void setStatus(int code) {\n        response.setStatus(code);\n    }\n\n    @Override\n    public StatusType getStatusInfo() {\n        return Status.fromStatusCode(response.status());\n    }\n\n    @Override\n    public void setStatusInfo(StatusType statusInfo) {\n        response.setStatus(statusInfo.getStatusCode());\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public MultivaluedMap<String, Object> getHeaders() {\n        return (MultivaluedMap) getStringHeaders();\n    }\n\n    @Override\n    public MultivaluedMap<String, String> getStringHeaders() {\n        MultivaluedMap<String, String> headers = this.headers;\n        if (headers == null) {\n            headers = new MultivaluedMapWrapper<>(response.headers());\n            this.headers = headers;\n        }\n        return headers;\n    }\n\n    @Override\n    public String getHeaderString(String name) {\n        return response.header(name);\n    }\n\n    @Override\n    public Set<String> getAllowedMethods() {\n        return Collections.singleton(request.method());\n    }\n\n    @Override\n    public Date getDate() {\n        return null;\n    }\n\n    @Override\n    public Locale getLanguage() {\n        return HttpUtils.parseLocale(response.locale());\n    }\n\n    @Override\n    public int getLength() {\n        return -1;\n    }\n\n    @Override\n    public MediaType getMediaType() {\n        return Helper.toMediaType(response.mediaType());\n    }\n\n    @Override\n    public Map<String, NewCookie> getCookies() {\n        Collection<HttpCookie> cookies = request.cookies();\n        Map<String, NewCookie> result = new HashMap<>(cookies.size());\n        for (HttpCookie cookie : cookies) {\n            result.put(cookie.name(), Helper.convert(cookie));\n        }\n        return result;\n    }\n\n    @Override\n    public EntityTag getEntityTag() {\n        return null;\n    }\n\n    @Override\n    public Date getLastModified() {\n        String value = response.header(HttpHeaderNames.LAST_MODIFIED.getKey());\n        return value == null ? null : DateFormatter.parseHttpDate(value);\n    }\n\n    @Override\n    public URI getLocation() {\n        String location = response.header(HttpHeaderNames.LOCATION.getKey());\n        return location == null ? null : URI.create(location);\n    }\n\n    @Override\n    public Set<Link> getLinks() {\n        return null;\n    }\n\n    @Override\n    public boolean hasLink(String relation) {\n        return false;\n    }\n\n    @Override\n    public Link getLink(String relation) {\n        return null;\n    }\n\n    @Override\n    public Link.Builder getLinkBuilder(String relation) {\n        return null;\n    }\n\n    @Override\n    public boolean hasEntity() {\n        return getEntity() != null;\n    }\n\n    @Override\n    public Object getEntity() {\n        return result.getValue();\n    }\n\n    @Override\n    public Class<?> getEntityClass() {\n        return getHandler().getMethod().getReturnType();\n    }\n\n    @Override\n    public Type getEntityType() {\n        return getHandler().getMethod().getGenericReturnType();\n    }\n\n    @Override\n    public void setEntity(Object entity) {\n        result.setValue(entity);\n    }\n\n    @Override\n    public void setEntity(Object entity, Annotation[] annotations, MediaType mediaType) {\n        result.setValue(entity);\n        response.setContentType(Helper.toString(mediaType));\n    }\n\n    @Override\n    public Annotation[] getEntityAnnotations() {\n        return new Annotation[0];\n    }\n\n    @Override\n    public OutputStream getEntityStream() {\n        return response.outputStream();\n    }\n\n    @Override\n    public void setEntityStream(OutputStream outputStream) {\n        response.setOutputStream(outputStream);\n    }\n\n    private HandlerMeta getHandler() {\n        return request.attribute(RestConstants.HANDLER_ATTRIBUTE);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/filter/ContainerResponseFilterAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.AbstractRestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.Listener;\n\nimport javax.ws.rs.container.ContainerResponseFilter;\n\n@Activate(onClass = \"javax.ws.rs.container.ContainerResponseFilter\")\npublic class ContainerResponseFilterAdapter implements RestExtensionAdapter<ContainerResponseFilter> {\n\n    @Override\n    public boolean accept(Object extension) {\n        return extension instanceof ContainerResponseFilter;\n    }\n\n    @Override\n    public RestFilter adapt(ContainerResponseFilter extension) {\n        return new Filter(extension);\n    }\n\n    private static final class Filter extends AbstractRestFilter<ContainerResponseFilter> implements Listener {\n\n        public Filter(ContainerResponseFilter extension) {\n            super(extension);\n        }\n\n        @Override\n        public void onResponse(Result result, HttpRequest request, HttpResponse response) throws Exception {\n            extension.filter(\n                    new ContainerRequestContextImpl(request, response),\n                    new ContainerResponseContextImpl(request, response, result));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/filter/ExceptionMapperAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.AbstractRestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.Listener;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.Helper;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;\n\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.ext.ExceptionMapper;\n\nimport java.util.Objects;\n\n@Activate(onClass = \"javax.ws.rs.ext.ExceptionMapper\")\npublic final class ExceptionMapperAdapter implements RestExtensionAdapter<ExceptionMapper<Throwable>> {\n\n    @Override\n    public boolean accept(Object extension) {\n        return extension instanceof ExceptionMapper;\n    }\n\n    @Override\n    public RestFilter adapt(ExceptionMapper<Throwable> extension) {\n        return new Filter(extension);\n    }\n\n    private static final class Filter extends AbstractRestFilter<ExceptionMapper<Throwable>> implements Listener {\n\n        private final Class<?> exceptionType;\n\n        public Filter(ExceptionMapper<Throwable> extension) {\n            super(extension);\n            exceptionType = Objects.requireNonNull(TypeUtils.getSuperGenericType(extension.getClass()));\n        }\n\n        @Override\n        public void onResponse(Result result, HttpRequest request, HttpResponse response) throws Exception {\n            if (result.hasException()) {\n                Throwable t = result.getException();\n                if (exceptionType.isInstance(t)) {\n                    try (Response r = extension.toResponse(t)) {\n                        response.setBody(Helper.toBody(r));\n                    }\n                }\n            }\n        }\n\n        @Override\n        public void onError(Throwable t, HttpRequest request, HttpResponse response) {\n            if (exceptionType.isInstance(t)) {\n                try (Response r = extension.toResponse(t)) {\n                    response.setBody(Helper.toBody(r));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/filter/InterceptorContextImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;\n\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta;\n\nimport javax.ws.rs.ext.InterceptorContext;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Type;\nimport java.util.Collection;\n\npublic abstract class InterceptorContextImpl implements InterceptorContext {\n\n    protected final HttpRequest request;\n\n    public InterceptorContextImpl(HttpRequest request) {\n        this.request = request;\n    }\n\n    @Override\n    public Object getProperty(String name) {\n        return request.attribute(name);\n    }\n\n    @Override\n    public Collection<String> getPropertyNames() {\n        return request.parameterNames();\n    }\n\n    @Override\n    public void setProperty(String name, Object object) {\n        request.setAttribute(name, object);\n    }\n\n    @Override\n    public void removeProperty(String name) {\n        request.removeAttribute(name);\n    }\n\n    @Override\n    public Annotation[] getAnnotations() {\n        return getHandler().getMethod().getRawAnnotations();\n    }\n\n    @Override\n    public void setAnnotations(Annotation[] annotations) {}\n\n    @Override\n    public Class<?> getType() {\n        return getHandler().getMethod().getReturnType();\n    }\n\n    @Override\n    public void setType(Class<?> type) {}\n\n    @Override\n    public Type getGenericType() {\n        return getHandler().getMethod().getGenericReturnType();\n    }\n\n    @Override\n    public void setGenericType(Type genericType) {}\n\n    private HandlerMeta getHandler() {\n        return request.attribute(RestConstants.HANDLER_ATTRIBUTE);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/filter/ReadInterceptorAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.AbstractRestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;\n\nimport javax.ws.rs.ext.ReaderInterceptor;\n\n@Activate(onClass = \"javax.ws.rs.ext.ReaderInterceptor\")\npublic final class ReadInterceptorAdapter implements RestExtensionAdapter<ReaderInterceptor> {\n\n    @Override\n    public boolean accept(Object extension) {\n        return extension instanceof ReaderInterceptor;\n    }\n\n    @Override\n    public RestFilter adapt(ReaderInterceptor extension) {\n        return new Filter(extension);\n    }\n\n    private static final class Filter extends AbstractRestFilter<ReaderInterceptor> {\n\n        public Filter(ReaderInterceptor extension) {\n            super(extension);\n        }\n\n        @Override\n        public void doFilter(HttpRequest request, HttpResponse response, FilterChain chain) throws Exception {\n            extension.aroundReadFrom(new ReaderInterceptorContextImpl(request, response, chain));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/filter/ReaderInterceptorContextImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;\n\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.FilterChain;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.Helper;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MultivaluedMapWrapper;\n\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.MultivaluedMap;\nimport javax.ws.rs.ext.ReaderInterceptorContext;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nfinal class ReaderInterceptorContextImpl extends InterceptorContextImpl implements ReaderInterceptorContext {\n\n    private final HttpResponse response;\n    private final FilterChain chain;\n\n    private MultivaluedMap<String, String> headers;\n\n    public ReaderInterceptorContextImpl(HttpRequest request, HttpResponse response, FilterChain chain) {\n        super(request);\n        this.response = response;\n        this.chain = chain;\n        headers = new MultivaluedMapWrapper<>(request.headers());\n    }\n\n    @Override\n    public Object proceed() throws IOException, WebApplicationException {\n        try {\n            chain.doFilter(request, response);\n        } catch (RuntimeException | IOException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new WebApplicationException(e);\n        }\n        return null;\n    }\n\n    @Override\n    public InputStream getInputStream() {\n        return request.inputStream();\n    }\n\n    @Override\n    public void setInputStream(InputStream is) {\n        request.setInputStream(is);\n    }\n\n    @Override\n    public MultivaluedMap<String, String> getHeaders() {\n        MultivaluedMap<String, String> headers = this.headers;\n        if (headers == null) {\n            headers = new MultivaluedMapWrapper<>(request.headers());\n            this.headers = headers;\n        }\n        return headers;\n    }\n\n    @Override\n    public MediaType getMediaType() {\n        return Helper.toMediaType(request.mediaType());\n    }\n\n    @Override\n    public void setMediaType(MediaType mediaType) {\n        request.setContentType(Helper.toString(mediaType));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/filter/WriterInterceptorAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.AbstractRestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.Listener;\n\nimport javax.ws.rs.ext.WriterInterceptor;\n\n@Activate(onClass = \"javax.ws.rs.ext.WriterInterceptor\")\npublic final class WriterInterceptorAdapter implements RestExtensionAdapter<WriterInterceptor> {\n\n    @Override\n    public boolean accept(Object extension) {\n        return extension instanceof WriterInterceptor;\n    }\n\n    @Override\n    public RestFilter adapt(WriterInterceptor extension) {\n        return new Filter(extension);\n    }\n\n    private static final class Filter extends AbstractRestFilter<WriterInterceptor> implements Listener {\n\n        public Filter(WriterInterceptor extension) {\n            super(extension);\n        }\n\n        @Override\n        public void onResponse(Result result, HttpRequest request, HttpResponse response) throws Exception {\n            extension.aroundWriteTo(new WriterInterceptorContextImpl(request, response, result));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/filter/WriterInterceptorContextImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;\n\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.Helper;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MultivaluedMapWrapper;\n\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.MultivaluedMap;\nimport javax.ws.rs.ext.WriterInterceptorContext;\n\nimport java.io.OutputStream;\n\nfinal class WriterInterceptorContextImpl extends InterceptorContextImpl implements WriterInterceptorContext {\n\n    private final HttpResponse response;\n    private final Result result;\n\n    private MultivaluedMap<String, Object> headers;\n\n    public WriterInterceptorContextImpl(HttpRequest request, HttpResponse response, Result result) {\n        super(request);\n        this.response = response;\n        this.result = result;\n    }\n\n    @Override\n    public void proceed() throws WebApplicationException {}\n\n    @Override\n    public Object getEntity() {\n        return result.getValue();\n    }\n\n    @Override\n    public void setEntity(Object entity) {\n        result.setValue(entity);\n    }\n\n    @Override\n    public OutputStream getOutputStream() {\n        return response.outputStream();\n    }\n\n    @Override\n    public void setOutputStream(OutputStream os) {\n        response.setOutputStream(os);\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public MultivaluedMap<String, Object> getHeaders() {\n        MultivaluedMap<String, Object> headers = this.headers;\n        if (headers == null) {\n            headers = new MultivaluedMapWrapper(response.headers());\n            this.headers = headers;\n        }\n        return headers;\n    }\n\n    @Override\n    public MediaType getMediaType() {\n        return Helper.toMediaType(response.mediaType());\n    }\n\n    @Override\n    public void setMediaType(MediaType mediaType) {\n        response.setContentType(Helper.toString(mediaType));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter",
    "content": "multivalued-map-creator=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MultivaluedMapCreator\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver",
    "content": "jaxrs-path-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.PathParamArgumentResolver\njaxrs-matrix-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MatrixParamArgumentResolver\njaxrs-query-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.QueryParamArgumentResolver\njaxrs-header-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.HeaderParamArgumentResolver\njaxrs-cookie-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.CookieParamArgumentResolver\njaxrs-form-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.FormParamArgumentResolver\njaxrs-bean-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.BeanParamArgumentResolver\njaxrs-body=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.BodyArgumentResolver\njaxrs-form=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.FormArgumentResolver\njaxrs-misc=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.JaxrsMiscArgumentResolver\njaxrs-fallback=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.FallbackArgumentResolver\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension",
    "content": "jaxrs-response=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.JaxrsResponseRestFilter\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter",
    "content": "jaxrs-request-filter=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter.ContainerRequestFilterAdapter\njaxrs-response-filter=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter.ContainerResponseFilterAdapter\njaxrs-read-interceptor=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter.ReadInterceptorAdapter\njaxrs-writer-interceptor=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter.WriterInterceptorAdapter\njaxrs-exception-mapper=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter.ExceptionMapperAdapter\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver",
    "content": "jaxrs=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.JaxrsRequestMappingResolver\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/RestProtocolTest.groovy",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs\n\nimport org.apache.dubbo.remoting.http12.message.MediaType\nimport org.apache.dubbo.rpc.protocol.tri.rest.service.DemoServiceImpl\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.service.JaxrsDemoServiceImpl\nimport org.apache.dubbo.rpc.protocol.tri.rest.test.BaseServiceTest\nimport org.apache.dubbo.rpc.protocol.tri.test.TestRequest\nimport org.apache.dubbo.rpc.protocol.tri.test.TestRunnerBuilder\n\nclass RestProtocolTest extends BaseServiceTest {\n\n    @Override\n    void setupService(TestRunnerBuilder builder) {\n        builder.provider(new DemoServiceImpl())\n        builder.provider(new JaxrsDemoServiceImpl())\n    }\n\n    def \"hello world\"() {\n        expect:\n            runner.get(path) == output\n        where:\n            path                    | output\n            '/hello?name=world'     | 'hello world'\n            '/hello/?name=world'    | 'hello world'\n            '/hello.yml?name=world' | 'hello world'\n    }\n\n    def \"form param test\"() {\n        expect:\n            TestRequest request = new TestRequest(\n                path: path,\n                contentType: MediaType.APPLICATION_FROM_URLENCODED,\n                body: body\n            )\n            runner.post(request) == output\n        where:\n            path        | body                                      | output\n            '/formTest' | ['user.first': 'sam', 'user.last': 'lee'] | '{\"contentType\":\"application/x-www-form-urlencoded\",\"firstName\":\"sam\",\"lastName\":\"lee\"}'\n    }\n\n    def \"bean param test\"() {\n        expect:\n            TestRequest request = new TestRequest(\n                path: path,\n                contentType: MediaType.APPLICATION_FROM_URLENCODED,\n                body: body\n            )\n            runner.post(request) == output\n        where:\n            path                   | body                            | output\n            '/beanTest/2?name=sam' | ['first': 'sam', 'last': 'lee'] | '{\"form\":{\"contentType\":\"application/x-www-form-urlencoded\",\"firstName\":\"sam\",\"lastName\":\"lee\"},\"id\":2,\"name\":\"sam\"}'\n    }\n\n    def \"param converter test\"() {\n        expect:\n            runner.get(path) == output\n        where:\n            path                      | output\n            '/convertTest?user=3,sam' | '{\"id\":3,\"name\":\"sam\"}'\n    }\n\n    def \"MultivaluedMap test\"() {\n        expect:\n            TestRequest request = new TestRequest(\n                path: path,\n                contentType: MediaType.APPLICATION_FROM_URLENCODED,\n                body: body\n            )\n            def actual = runner.post(request)\n            actual.contains('\"name\":[1,2]') && actual.contains('\"age\":[8]')\n        where:\n            path                  | body                  | output\n            '/multivaluedMapTest' | 'name=1&name=2&age=8' | '{\"name\":[1,2],\"age\":[8]}'\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible;\n\nimport javax.ws.rs.Consumes;\nimport javax.ws.rs.FormParam;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.HeaderParam;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.Produces;\nimport javax.ws.rs.QueryParam;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.MultivaluedMap;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.netty.handler.codec.http.DefaultFullHttpRequest;\nimport org.jboss.resteasy.annotations.Form;\n\n@Path(\"/demoService\")\npublic interface DemoService {\n    @GET\n    @Path(\"/hello\")\n    Integer hello(@QueryParam(\"a\") Integer a, @QueryParam(\"b\") Integer b);\n\n    @GET\n    @Path(\"/error\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    @Produces({MediaType.TEXT_PLAIN})\n    String error();\n\n    @POST\n    @Path(\"/say\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    String sayHello(String name);\n\n    @POST\n    @Path(\"number\")\n    Long testFormBody(@FormParam(\"number\") Long number);\n\n    boolean isCalled();\n\n    @GET\n    @Path(\"/primitive\")\n    int primitiveInt(@QueryParam(\"a\") int a, @QueryParam(\"b\") int b);\n\n    @GET\n    @Path(\"/primitiveLong\")\n    long primitiveLong(@QueryParam(\"a\") long a, @QueryParam(\"b\") Long b);\n\n    @GET\n    @Path(\"/primitiveByte\")\n    long primitiveByte(@QueryParam(\"a\") byte a, @QueryParam(\"b\") Long b);\n\n    @POST\n    @Path(\"/primitiveShort\")\n    long primitiveShort(@QueryParam(\"a\") short a, @QueryParam(\"b\") Long b, int c);\n\n    @GET\n    @Path(\"/request\")\n    void request(DefaultFullHttpRequest defaultFullHttpRequest);\n\n    @GET\n    @Path(\"testMapParam\")\n    @Produces({MediaType.TEXT_PLAIN})\n    @Consumes({MediaType.TEXT_PLAIN})\n    String testMapParam(@QueryParam(\"test\") Map<String, String> params);\n\n    @GET\n    @Path(\"testMapHeader\")\n    @Produces({MediaType.TEXT_PLAIN})\n    @Consumes({MediaType.TEXT_PLAIN})\n    String testMapHeader(@HeaderParam(\"test\") Map<String, String> headers);\n\n    @POST\n    @Path(\"testMapForm\")\n    @Produces({MediaType.APPLICATION_JSON})\n    @Consumes({MediaType.APPLICATION_FORM_URLENCODED})\n    List<String> testMapForm(MultivaluedMap<String, String> params);\n\n    @POST\n    @Path(\"/header\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    String header(@HeaderParam(\"header\") String header);\n\n    @POST\n    @Path(\"/headerInt\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    int headerInt(@HeaderParam(\"header\") int header);\n\n    @POST\n    @Path(\"/noStringParam\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    String noStringParam(@QueryParam(\"param\") String param);\n\n    @POST\n    @Path(\"/noStringHeader\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    String noStringHeader(@HeaderParam(\"header\") String header);\n\n    @POST\n    @Path(\"/noIntHeader\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    int noIntHeader(int header);\n\n    @POST\n    @Path(\"/noIntParam\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    int noIntParam(int header);\n\n    @POST\n    @Path(\"/noBodyArg\")\n    @Consumes({MediaType.APPLICATION_JSON})\n    User noBodyArg(User user);\n\n    @POST\n    @Path(\"/list\")\n    List<User> list(List<User> users);\n\n    @POST\n    @Path(\"/set\")\n    Set<User> set(Set<User> users);\n\n    @POST\n    @Path(\"/array\")\n    User[] array(User[] users);\n\n    @POST\n    @Path(\"/stringMap\")\n    Map<String, User> stringMap(Map<String, User> userMap);\n\n    @POST\n    @Path(\"/map\")\n    Map<User, User> userMap(Map<User, User> userMap);\n\n    @POST\n    @Path(\"/formBody\")\n    User formBody(@Form User user);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/DemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible;\n\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport javax.ws.rs.Consumes;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.HeaderParam;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.QueryParam;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.MultivaluedMap;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.netty.handler.codec.http.DefaultFullHttpRequest;\n\n@Path(\"/demoService\")\npublic class DemoServiceImpl implements DemoService {\n    private static Map<String, Object> context;\n    private boolean called;\n\n    @POST\n    @Path(\"/say\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    @Override\n    public String sayHello(String name) {\n        called = true;\n        return \"Hello, \" + name;\n    }\n\n    @Override\n    public Long testFormBody(Long number) {\n        return number;\n    }\n\n    public boolean isCalled() {\n        return called;\n    }\n\n    @Override\n    public int primitiveInt(int a, int b) {\n        return a + b;\n    }\n\n    @Override\n    public long primitiveLong(long a, Long b) {\n        return a + b;\n    }\n\n    @Override\n    public long primitiveByte(byte a, Long b) {\n        return a + b;\n    }\n\n    @Override\n    public long primitiveShort(short a, Long b, int c) {\n        return a + b;\n    }\n\n    @Override\n    public void request(DefaultFullHttpRequest defaultFullHttpRequest) {}\n\n    @Override\n    public String testMapParam(Map<String, String> params) {\n        return params.get(\"param\");\n    }\n\n    @Override\n    public String testMapHeader(Map<String, String> headers) {\n        return headers.get(\"header\");\n    }\n\n    @Override\n    public List<String> testMapForm(MultivaluedMap<String, String> params) {\n        return params.get(\"form\");\n    }\n\n    @Override\n    public String header(String header) {\n        return header;\n    }\n\n    @Override\n    public int headerInt(int header) {\n        return header;\n    }\n\n    @Override\n    public String noStringParam(String param) {\n        return param;\n    }\n\n    @Override\n    public String noStringHeader(String header) {\n        return header;\n    }\n\n    @POST\n    @Path(\"/noIntHeader\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    @Override\n    public int noIntHeader(@HeaderParam(\"header\") int header) {\n        return header;\n    }\n\n    @POST\n    @Path(\"/noIntParam\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    @Override\n    public int noIntParam(@QueryParam(\"header\") int header) {\n        return header;\n    }\n\n    @Override\n    public User noBodyArg(User user) {\n        return user;\n    }\n\n    @GET\n    @Path(\"/hello\")\n    @Override\n    public Integer hello(@QueryParam(\"a\") Integer a, @QueryParam(\"b\") Integer b) {\n        context = RpcContext.getServerAttachment().getObjectAttachments();\n        return a + b;\n    }\n\n    @GET\n    @Path(\"/error\")\n    @Override\n    public String error() {\n        throw new RuntimeException(\"test error\");\n    }\n\n    public static Map<String, Object> getAttachments() {\n        return context;\n    }\n\n    @Override\n    public List<User> list(List<User> users) {\n        return users;\n    }\n\n    @Override\n    public Set<User> set(Set<User> users) {\n        return users;\n    }\n\n    @Override\n    public User[] array(User[] users) {\n        return users;\n    }\n\n    @Override\n    public Map<String, User> stringMap(Map<String, User> userMap) {\n        return userMap;\n    }\n\n    @Override\n    public Map<User, User> userMap(Map<User, User> userMap) {\n        return userMap;\n    }\n\n    @Override\n    public User formBody(User user) {\n        user.setName(\"formBody\");\n        return user;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/JaxrsRestProtocolTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter.TestContainerRequestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter.TraceFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter.TraceRequestAndResponseFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.intercept.DynamicTraceInterceptor;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.AnotherUserRestService;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.AnotherUserRestServiceImpl;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.HttpMethodService;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.HttpMethodServiceImpl;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.RestDemoForTestException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.RestDemoService;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.RestDemoServiceImpl;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\n\nimport org.hamcrest.CoreMatchers;\nimport org.jboss.resteasy.specimpl.MultivaluedMapImpl;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.remoting.Constants.SERVER_KEY;\nimport static org.apache.dubbo.rpc.protocol.tri.rest.RestConstants.EXTENSION_KEY;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Disabled\nclass JaxrsRestProtocolTest {\n    private final Protocol tProtocol =\n            ApplicationModel.defaultModel().getExtensionLoader(Protocol.class).getExtension(\"tri\");\n    private final Protocol protocol =\n            ApplicationModel.defaultModel().getExtensionLoader(Protocol.class).getExtension(\"rest\");\n    private final ProxyFactory proxy = ApplicationModel.defaultModel()\n            .getExtensionLoader(ProxyFactory.class)\n            .getAdaptiveExtension();\n\n    private final int availablePort = NetUtils.getAvailablePort();\n    private final URL exportUrl =\n            URL.valueOf(\"tri://127.0.0.1:\" + availablePort + \"/rest?interface=\" + DemoService.class.getName());\n\n    private static final String SERVER = \"netty4\";\n\n    private final ModuleServiceRepository repository =\n            ApplicationModel.defaultModel().getDefaultModule().getServiceRepository();\n\n    @AfterEach\n    public void tearDown() {\n        tProtocol.destroy();\n        protocol.destroy();\n        FrameworkModel.destroyAll();\n    }\n\n    @Test\n    void testRestProtocol() {\n        URL url = URL.valueOf(\"tri://127.0.0.1:\" + NetUtils.getAvailablePort() + \"/?version=1.0.0&interface=\"\n                + DemoService.class.getName());\n\n        DemoServiceImpl server = new DemoServiceImpl();\n\n        url = registerProvider(url, server, DemoService.class);\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, url));\n\n        Invoker<DemoService> invoker = protocol.refer(DemoService.class, url);\n        Assertions.assertFalse(server.isCalled());\n\n        DemoService client = proxy.getProxy(invoker);\n        String result = client.sayHello(\"haha\");\n        Assertions.assertTrue(server.isCalled());\n        Assertions.assertEquals(\"Hello, haha\", result);\n\n        String header = client.header(\"header test\");\n        Assertions.assertEquals(\"header test\", header);\n\n        Assertions.assertEquals(1, client.headerInt(1));\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    @Test\n    void testAnotherUserRestProtocolByDifferentRestClient() {\n        testAnotherUserRestProtocol(org.apache.dubbo.remoting.Constants.OK_HTTP);\n        testAnotherUserRestProtocol(org.apache.dubbo.remoting.Constants.APACHE_HTTP_CLIENT);\n        testAnotherUserRestProtocol(org.apache.dubbo.remoting.Constants.URL_CONNECTION);\n    }\n\n    void testAnotherUserRestProtocol(String restClient) {\n        URL url = URL.valueOf(\"tri://127.0.0.1:\" + NetUtils.getAvailablePort() + \"/?version=1.0.0&interface=\"\n                + AnotherUserRestService.class.getName() + \"&\" + org.apache.dubbo.remoting.Constants.CLIENT_KEY + \"=\"\n                + restClient);\n\n        AnotherUserRestServiceImpl server = new AnotherUserRestServiceImpl();\n\n        url = this.registerProvider(url, server, AnotherUserRestService.class);\n\n        Exporter<AnotherUserRestService> exporter =\n                tProtocol.export(proxy.getInvoker(server, AnotherUserRestService.class, url));\n        Invoker<AnotherUserRestService> invoker = protocol.refer(AnotherUserRestService.class, url);\n\n        AnotherUserRestService client = proxy.getProxy(invoker);\n        User result = client.getUser(123l);\n\n        Assertions.assertEquals(123l, result.getId());\n\n        result.setName(\"dubbo\");\n        Assertions.assertEquals(123l, client.registerUser(result).getId());\n\n        Assertions.assertEquals(\"context\", client.getContext());\n\n        byte[] bytes = {1, 2, 3, 4};\n        Assertions.assertTrue(Arrays.equals(bytes, client.bytes(bytes)));\n\n        Assertions.assertEquals(1l, client.number(1l));\n\n        HashMap<String, String> map = new HashMap<>();\n        map.put(\"headers\", \"h1\");\n        Assertions.assertEquals(\"h1\", client.headerMap(map));\n        Assertions.assertEquals(null, client.headerMap(null));\n\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    @Test\n    void testRestProtocolWithContextPath() {\n        DemoServiceImpl server = new DemoServiceImpl();\n        Assertions.assertFalse(server.isCalled());\n        int port = NetUtils.getAvailablePort();\n        URL url = URL.valueOf(\n                \"tri://127.0.0.1:\" + port + \"/a/b/c?version=1.0.0&interface=\" + DemoService.class.getName());\n\n        url = this.registerProvider(url, server, DemoService.class);\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, url));\n\n        url = URL.valueOf(\n                \"rest://127.0.0.1:\" + port + \"/a/b/c/?version=1.0.0&interface=\" + DemoService.class.getName());\n        Invoker<DemoService> invoker = protocol.refer(DemoService.class, url);\n        DemoService client = proxy.getProxy(invoker);\n        String result = client.sayHello(\"haha\");\n        Assertions.assertTrue(server.isCalled());\n        Assertions.assertEquals(\"Hello, haha\", result);\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    @Test\n    void testExport() {\n        DemoService server = new DemoServiceImpl();\n\n        URL url = this.registerProvider(exportUrl, server, DemoService.class);\n\n        RpcContext.getClientAttachment().setAttachment(\"timeout\", \"20000\");\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, url));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, url));\n\n        Integer echoString = demoService.hello(1, 2);\n        assertThat(echoString, is(3));\n\n        exporter.unexport();\n    }\n\n    @Test\n    void testNettyServer() {\n        DemoService server = new DemoServiceImpl();\n\n        URL url = this.registerProvider(exportUrl, server, DemoService.class);\n\n        URL nettyUrl = url.addParameter(SERVER_KEY, SERVER);\n        Exporter<DemoService> exporter =\n                tProtocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        Integer echoString = demoService.hello(10, 10);\n        assertThat(echoString, is(20));\n\n        exporter.unexport();\n    }\n\n    @Test\n    void testInvoke() {\n        DemoService server = new DemoServiceImpl();\n\n        URL url = this.registerProvider(exportUrl, server, DemoService.class);\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, url));\n\n        RpcInvocation rpcInvocation = new RpcInvocation(\n                \"hello\", DemoService.class.getName(), \"\", new Class[] {Integer.class, Integer.class}, new Integer[] {\n                    2, 3\n                });\n        rpcInvocation.setTargetServiceUniqueName(url.getServiceKey());\n\n        Result result = exporter.getInvoker().invoke(rpcInvocation);\n        assertThat(result.getValue(), CoreMatchers.<Object>is(5));\n    }\n\n    @Test\n    void testDefaultPort() {\n        assertThat(protocol.getDefaultPort(), is(80));\n    }\n\n    @Test\n    void testRestExceptionMapper() {\n\n        DemoService server = new DemoServiceImpl();\n\n        URL url = this.registerProvider(exportUrl, server, DemoService.class);\n\n        URL exceptionUrl = url.addParameter(EXTENSION_KEY, ResteasyExceptionMapper.class.getName());\n\n        tProtocol.export(proxy.getInvoker(server, DemoService.class, exceptionUrl));\n\n        DemoService referDemoService = this.proxy.getProxy(protocol.refer(DemoService.class, exceptionUrl));\n\n        Assertions.assertEquals(\"test-exception\", referDemoService.error());\n    }\n\n    @Test\n    void testFormConsumerParser() {\n        DemoService server = new DemoServiceImpl();\n        URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        Long number = demoService.testFormBody(18l);\n        Assertions.assertEquals(18l, number);\n\n        exporter.unexport();\n    }\n\n    @Test\n    void test404() {\n        Assertions.assertThrows(RpcException.class, () -> {\n            DemoService server = new DemoServiceImpl();\n            URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);\n\n            Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n            URL referUrl = URL.valueOf(\n                    \"tri://127.0.0.1:\" + availablePort + \"/rest?interface=\" + RestDemoForTestException.class.getName());\n\n            RestDemoForTestException restDemoForTestException =\n                    this.proxy.getProxy(protocol.refer(RestDemoForTestException.class, referUrl));\n\n            restDemoForTestException.test404();\n\n            exporter.unexport();\n        });\n    }\n\n    @Test\n    void test400() {\n        Assertions.assertThrows(RpcException.class, () -> {\n            DemoService server = new DemoServiceImpl();\n            URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);\n\n            Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n            URL referUrl = URL.valueOf(\n                    \"tri://127.0.0.1:\" + availablePort + \"/rest?interface=\" + RestDemoForTestException.class.getName());\n\n            RestDemoForTestException restDemoForTestException =\n                    this.proxy.getProxy(protocol.refer(RestDemoForTestException.class, referUrl));\n\n            restDemoForTestException.test400(\"abc\", \"edf\");\n\n            exporter.unexport();\n        });\n    }\n\n    @Test\n    void testPrimitive() {\n        DemoService server = new DemoServiceImpl();\n\n        URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        Integer result = demoService.primitiveInt(1, 2);\n        Long resultLong = demoService.primitiveLong(1, 2l);\n        long resultByte = demoService.primitiveByte((byte) 1, 2l);\n        long resultShort = demoService.primitiveShort((short) 1, 2l, 1);\n\n        assertThat(result, is(3));\n        assertThat(resultShort, is(3l));\n        assertThat(resultLong, is(3l));\n        assertThat(resultByte, is(3l));\n\n        exporter.unexport();\n    }\n\n    @Test\n    void testMapParam() {\n        DemoService server = new DemoServiceImpl();\n\n        URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        Map<String, String> params = new HashMap<>();\n        params.put(\"param\", \"P1\");\n        ;\n\n        Map<String, String> headers = new HashMap<>();\n        headers.put(\"header\", \"H1\");\n\n        Assertions.assertEquals(\"P1\", demoService.testMapParam(params));\n        Assertions.assertEquals(\"H1\", demoService.testMapHeader(headers));\n\n        MultivaluedMapImpl<String, String> forms = new MultivaluedMapImpl<>();\n        forms.put(\"form\", Arrays.asList(\"F1\"));\n\n        Assertions.assertEquals(Arrays.asList(\"F1\"), demoService.testMapForm(forms));\n        exporter.unexport();\n    }\n\n    @Test\n    void testNoArgParam() {\n        DemoService server = new DemoServiceImpl();\n\n        URL url = this.registerProvider(exportUrl, server, DemoService.class);\n\n        URL nettyUrl = url.addParameter(SERVER_KEY, SERVER);\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        Assertions.assertEquals(null, demoService.noStringHeader(null));\n        Assertions.assertEquals(null, demoService.noStringParam(null));\n        /*        Assertions.assertThrows(RpcException.class, () -> {\n            demoService.noIntHeader(1);\n        });\n\n        Assertions.assertThrows(RpcException.class, () -> {\n            demoService.noIntParam(1);\n        });*/\n\n        Assertions.assertEquals(null, demoService.noBodyArg(null));\n        exporter.unexport();\n    }\n\n    @Test\n    void testHttpMethods() {\n        testHttpMethod(org.apache.dubbo.remoting.Constants.OK_HTTP);\n        testHttpMethod(org.apache.dubbo.remoting.Constants.APACHE_HTTP_CLIENT);\n        testHttpMethod(org.apache.dubbo.remoting.Constants.URL_CONNECTION);\n    }\n\n    void testHttpMethod(String restClient) {\n        HttpMethodService server = new HttpMethodServiceImpl();\n\n        URL url = URL.valueOf(\"tri://127.0.0.1:\" + NetUtils.getAvailablePort() + \"/?version=1.0.0&interface=\"\n                + HttpMethodService.class.getName() + \"&\"\n                + org.apache.dubbo.remoting.Constants.CLIENT_KEY + \"=\" + restClient);\n        url = this.registerProvider(url, server, HttpMethodService.class);\n        Exporter<HttpMethodService> exporter = tProtocol.export(proxy.getInvoker(server, HttpMethodService.class, url));\n\n        HttpMethodService demoService = this.proxy.getProxy(protocol.refer(HttpMethodService.class, url));\n\n        String expect = \"hello\";\n        Assertions.assertEquals(null, demoService.sayHelloHead());\n        Assertions.assertEquals(expect, demoService.sayHelloDelete(\"hello\"));\n        Assertions.assertEquals(expect, demoService.sayHelloGet(\"hello\"));\n        Assertions.assertEquals(expect, demoService.sayHelloOptions(\"hello\"));\n        //        Assertions.assertEquals(expect, demoService.sayHelloPatch(\"hello\"));\n        Assertions.assertEquals(expect, demoService.sayHelloPost(\"hello\"));\n        Assertions.assertEquals(expect, demoService.sayHelloPut(\"hello\"));\n        exporter.unexport();\n    }\n\n    @Test\n    void test405() {\n        int availablePort = NetUtils.getAvailablePort();\n        URL url = URL.valueOf(\"tri://127.0.0.1:\" + availablePort\n                + \"/?version=1.0.0&interface=org.apache.dubbo.rpc.protocol.rest.rest.RestDemoService&\");\n\n        RestDemoServiceImpl server = new RestDemoServiceImpl();\n\n        url = this.registerProvider(url, server, RestDemoService.class);\n\n        Exporter<RestDemoService> exporter = tProtocol.export(proxy.getInvoker(server, RestDemoService.class, url));\n\n        URL consumer = URL.valueOf(\"rest://127.0.0.1:\" + availablePort + \"/?version=1.0.0&interface=\"\n                + RestDemoForTestException.class.getName());\n\n        consumer = this.registerProvider(consumer, server, RestDemoForTestException.class);\n\n        Invoker<RestDemoForTestException> invoker = protocol.refer(RestDemoForTestException.class, consumer);\n\n        RestDemoForTestException client = proxy.getProxy(invoker);\n\n        Assertions.assertThrows(RpcException.class, () -> {\n            client.testMethodDisallowed(\"aaa\");\n        });\n\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    @Test\n    void testContainerRequestFilter() {\n        DemoService server = new DemoServiceImpl();\n\n        URL url = this.registerProvider(exportUrl, server, DemoService.class);\n\n        URL nettyUrl = url.addParameter(EXTENSION_KEY, TestContainerRequestFilter.class.getName());\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        Assertions.assertEquals(\"return-success\", demoService.sayHello(\"hello\"));\n        exporter.unexport();\n    }\n\n    @Test\n    void testIntercept() {\n        DemoService server = new DemoServiceImpl();\n\n        URL url = this.registerProvider(exportUrl, server, DemoService.class);\n\n        URL nettyUrl = url.addParameter(EXTENSION_KEY, DynamicTraceInterceptor.class.getName());\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        Assertions.assertEquals(\"intercept\", demoService.sayHello(\"hello\"));\n        exporter.unexport();\n    }\n\n    @Test\n    void testResponseFilter() {\n        DemoService server = new DemoServiceImpl();\n\n        URL url = this.registerProvider(exportUrl, server, DemoService.class);\n\n        URL nettyUrl = url.addParameter(EXTENSION_KEY, TraceFilter.class.getName());\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        Assertions.assertEquals(\"response-filter\", demoService.sayHello(\"hello\"));\n        exporter.unexport();\n    }\n\n    @Test\n    void testCollectionResult() {\n        DemoService server = new DemoServiceImpl();\n\n        URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        Assertions.assertEquals(\n                User.getInstance(),\n                demoService.list(Arrays.asList(User.getInstance())).get(0));\n\n        HashSet<User> objects = new HashSet<>();\n        objects.add(User.getInstance());\n        Assertions.assertEquals(User.getInstance(), new ArrayList<>(demoService.set(objects)).get(0));\n\n        Assertions.assertEquals(User.getInstance(), demoService.array(objects.toArray(new User[0]))[0]);\n\n        Map<String, User> map = new HashMap<>();\n        map.put(\"map\", User.getInstance());\n        Assertions.assertEquals(User.getInstance(), demoService.stringMap(map).get(\"map\"));\n\n        // Map<User, User> maps = new HashMap<>();\n        // maps.put(User.getInstance(), User.getInstance());\n        // Assertions.assertEquals(User.getInstance(), demoService.userMap(maps).get(User.getInstance()));\n        exporter.unexport();\n    }\n\n    @Test\n    void testRequestAndResponseFilter() {\n        DemoService server = new DemoServiceImpl();\n\n        URL exportUrl = URL.valueOf(\"tri://127.0.0.1:\" + availablePort + \"/rest?interface=\"\n                + DemoService.class.getName() + \"&extension=\" + TraceRequestAndResponseFilter.class.getName());\n\n        URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        Assertions.assertEquals(\"header-result\", demoService.sayHello(\"hello\"));\n        exporter.unexport();\n    }\n\n    @Test\n    void testFormBody() {\n        DemoService server = new DemoServiceImpl();\n\n        URL url = this.registerProvider(exportUrl, server, DemoService.class);\n\n        URL nettyUrl = url.addParameter(SERVER_KEY, SERVER);\n\n        Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));\n\n        DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));\n\n        User user = demoService.formBody(User.getInstance());\n\n        Assertions.assertEquals(\"formBody\", user.getName());\n        exporter.unexport();\n    }\n\n    private URL registerProvider(URL url, Object impl, Class<?> interfaceClass) {\n        ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);\n        ProviderModel providerModel = new ProviderModel(url.getServiceKey(), impl, serviceDescriptor, null, null);\n        repository.registerProvider(providerModel);\n        return url.setServiceModel(providerModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/ResteasyExceptionMapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible;\n\nimport javax.ws.rs.core.Response;\nimport javax.ws.rs.ext.ExceptionMapper;\n\npublic class ResteasyExceptionMapper implements ExceptionMapper<RuntimeException> {\n    @Override\n    public Response toResponse(RuntimeException exception) {\n        return Response.status(200).entity(\"test-exception\").build();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/User.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible;\n\nimport java.io.Serializable;\nimport java.util.Objects;\n\n/**\n * User Entity\n *\n * @since 2.7.6\n */\npublic class User implements Serializable {\n\n    private Long id;\n\n    private String name;\n\n    private Integer age;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n\n    public static User getInstance() {\n        User user = new User();\n        user.setAge(18);\n        user.setName(\"dubbo\");\n        user.setId(404l);\n        return user;\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        User user = (User) o;\n        return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(age, user.age);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(id, name, age);\n    }\n\n    @Override\n    public String toString() {\n        return \"User{\" + \"id=\" + id + \", name='\" + name + '\\'' + \", age=\" + age + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/filter/TestContainerRequestFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter;\n\nimport javax.annotation.Priority;\nimport javax.ws.rs.Priorities;\nimport javax.ws.rs.container.ContainerRequestContext;\nimport javax.ws.rs.container.ContainerRequestFilter;\nimport javax.ws.rs.core.Response;\n\nimport java.io.IOException;\n\n@Priority(Priorities.USER)\npublic class TestContainerRequestFilter implements ContainerRequestFilter {\n    @Override\n    public void filter(ContainerRequestContext requestContext) throws IOException {\n\n        requestContext.abortWith(Response.status(200).entity(\"return-success\").build());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/filter/TraceFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter;\n\nimport javax.annotation.Priority;\nimport javax.ws.rs.Priorities;\nimport javax.ws.rs.container.ContainerRequestContext;\nimport javax.ws.rs.container.ContainerRequestFilter;\nimport javax.ws.rs.container.ContainerResponseContext;\nimport javax.ws.rs.container.ContainerResponseFilter;\n\nimport java.io.IOException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@Priority(Priorities.USER)\npublic class TraceFilter implements ContainerRequestFilter, ContainerResponseFilter {\n    private static final Logger logger = LoggerFactory.getLogger(TraceFilter.class);\n\n    @Override\n    public void filter(ContainerRequestContext requestContext) throws IOException {\n        logger.info(\"Request filter invoked: {}\", requestContext.getUriInfo().getAbsolutePath());\n    }\n\n    @Override\n    public void filter(\n            ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext)\n            throws IOException {\n        containerResponseContext.setEntity(\"response-filter\");\n        logger.info(\"Response filter invoked.\");\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/filter/TraceRequestAndResponseFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter;\n\nimport javax.annotation.Priority;\nimport javax.ws.rs.Priorities;\nimport javax.ws.rs.container.ContainerRequestContext;\nimport javax.ws.rs.container.ContainerRequestFilter;\nimport javax.ws.rs.container.ContainerResponseContext;\nimport javax.ws.rs.container.ContainerResponseFilter;\n\nimport java.io.IOException;\n\n@Priority(Priorities.USER)\npublic class TraceRequestAndResponseFilter implements ContainerRequestFilter, ContainerResponseFilter {\n\n    @Override\n    public void filter(ContainerRequestContext requestContext) throws IOException {\n\n        requestContext.getHeaders().add(\"test-response\", \"header-result\");\n    }\n\n    @Override\n    public void filter(\n            ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext)\n            throws IOException {\n\n        String headerString = containerRequestContext.getHeaderString(\"test-response\");\n        containerResponseContext.setEntity(headerString);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/intercept/DynamicTraceInterceptor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.intercept;\n\nimport javax.annotation.Priority;\nimport javax.ws.rs.Priorities;\nimport javax.ws.rs.WebApplicationException;\nimport javax.ws.rs.ext.ReaderInterceptor;\nimport javax.ws.rs.ext.ReaderInterceptorContext;\nimport javax.ws.rs.ext.WriterInterceptor;\nimport javax.ws.rs.ext.WriterInterceptorContext;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\n@Priority(Priorities.USER)\npublic class DynamicTraceInterceptor implements ReaderInterceptor, WriterInterceptor {\n\n    public DynamicTraceInterceptor() {}\n\n    @Override\n    public Object aroundReadFrom(ReaderInterceptorContext readerInterceptorContext)\n            throws IOException, WebApplicationException {\n        return readerInterceptorContext.proceed();\n    }\n\n    @Override\n    public void aroundWriteTo(WriterInterceptorContext writerInterceptorContext)\n            throws IOException, WebApplicationException {\n        writerInterceptorContext.getOutputStream().write(\"intercept\".getBytes(StandardCharsets.UTF_8));\n        writerInterceptorContext.proceed();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/rest/AnotherUserRestService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.User;\n\nimport javax.ws.rs.Consumes;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.HeaderParam;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.PathParam;\nimport javax.ws.rs.Produces;\nimport javax.ws.rs.core.MediaType;\n\nimport java.util.Map;\n\n@Path(\"u\")\n@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})\npublic interface AnotherUserRestService {\n\n    @GET\n    @Path(\"{id : \\\\d+}\")\n    @Produces({MediaType.APPLICATION_JSON})\n    User getUser(@PathParam(\"id\") Long id);\n\n    @POST\n    @Path(\"register\")\n    @Produces(\"text/xml; charset=UTF-8\")\n    RegistrationResult registerUser(User user);\n\n    @GET\n    @Path(\"context\")\n    @Produces({MediaType.TEXT_PLAIN})\n    String getContext();\n\n    @POST\n    @Path(\"bytes\")\n    @Produces({MediaType.APPLICATION_JSON})\n    byte[] bytes(byte[] bytes);\n\n    @POST\n    @Path(\"number\")\n    @Produces({MediaType.APPLICATION_JSON})\n    Long number(Long number);\n\n    @POST\n    @Path(\"headerMap\")\n    @Produces({MediaType.TEXT_PLAIN})\n    String headerMap(@HeaderParam(\"headers\") Map<String, String> headers);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/rest/AnotherUserRestServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.User;\n\nimport java.util.Map;\n\npublic class AnotherUserRestServiceImpl implements AnotherUserRestService {\n\n    @Override\n    public User getUser(Long id) {\n\n        User user = new User();\n        user.setId(id);\n        return user;\n    }\n\n    @Override\n    public RegistrationResult registerUser(User user) {\n        return new RegistrationResult(user.getId());\n    }\n\n    @Override\n    public String getContext() {\n\n        return \"context\";\n    }\n\n    @Override\n    public byte[] bytes(byte[] bytes) {\n        return bytes;\n    }\n\n    @Override\n    public Long number(Long number) {\n        return number;\n    }\n\n    @Override\n    public String headerMap(Map<String, String> headers) {\n        return headers.get(\"headers\");\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/rest/HttpMethodService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;\n\nimport javax.ws.rs.Consumes;\nimport javax.ws.rs.DELETE;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.HEAD;\nimport javax.ws.rs.OPTIONS;\nimport javax.ws.rs.PATCH;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.PUT;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.QueryParam;\n\n@Path(\"/demoService\")\npublic interface HttpMethodService {\n\n    @POST\n    @Path(\"/sayPost\")\n    @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})\n    String sayHelloPost(@QueryParam(\"name\") String name);\n\n    @DELETE\n    @Path(\"/sayDelete\")\n    @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})\n    String sayHelloDelete(@QueryParam(\"name\") String name);\n\n    @HEAD\n    @Path(\"/sayHead\")\n    @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})\n    String sayHelloHead();\n\n    @GET\n    @Path(\"/sayGet\")\n    @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})\n    String sayHelloGet(@QueryParam(\"name\") String name);\n\n    @PUT\n    @Path(\"/sayPut\")\n    @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})\n    String sayHelloPut(@QueryParam(\"name\") String name);\n\n    @PATCH\n    @Path(\"/sayPatch\")\n    @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})\n    String sayHelloPatch(@QueryParam(\"name\") String name);\n\n    @OPTIONS\n    @Path(\"/sayOptions\")\n    @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})\n    String sayHelloOptions(@QueryParam(\"name\") String name);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/rest/HttpMethodServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;\n\npublic class HttpMethodServiceImpl implements HttpMethodService {\n\n    @Override\n    public String sayHelloPost(String name) {\n        return name;\n    }\n\n    @Override\n    public String sayHelloDelete(String name) {\n        return name;\n    }\n\n    @Override\n    public String sayHelloHead() {\n        return \"hello\";\n    }\n\n    @Override\n    public String sayHelloGet(String name) {\n        return name;\n    }\n\n    @Override\n    public String sayHelloPut(String name) {\n        return name;\n    }\n\n    @Override\n    public String sayHelloPatch(String name) {\n        return name;\n    }\n\n    @Override\n    public String sayHelloOptions(String name) {\n        return name;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/rest/RegistrationResult.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;\n\nimport javax.xml.bind.annotation.XmlRootElement;\n\nimport java.io.Serializable;\nimport java.util.Objects;\n\n/**\n * DTO to customize the returned message\n */\n@XmlRootElement\npublic class RegistrationResult implements Serializable {\n\n    private Long id;\n\n    public RegistrationResult() {}\n\n    public RegistrationResult(Long id) {\n        this.id = id;\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\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        RegistrationResult that = (RegistrationResult) o;\n        return Objects.equals(id, that.id);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(id);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/rest/RestDemoForTestException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;\n\nimport javax.ws.rs.Consumes;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.PathParam;\nimport javax.ws.rs.Produces;\nimport javax.ws.rs.QueryParam;\nimport javax.ws.rs.core.MediaType;\n\n@Path(\"/demoService\")\npublic interface RestDemoForTestException {\n\n    @POST\n    @Path(\"/noFound\")\n    @Produces(MediaType.TEXT_PLAIN)\n    String test404();\n\n    @GET\n    @Consumes({MediaType.TEXT_PLAIN})\n    @Path(\"/hello\")\n    Integer test400(@QueryParam(\"a\") String a, @QueryParam(\"b\") String b);\n\n    @POST\n    @Path(\"{uid}\")\n    String testMethodDisallowed(@PathParam(\"uid\") String uid);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/rest/RestDemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;\n\nimport javax.ws.rs.Consumes;\nimport javax.ws.rs.DELETE;\nimport javax.ws.rs.FormParam;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.PathParam;\nimport javax.ws.rs.Produces;\nimport javax.ws.rs.QueryParam;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.Response;\n\n@Path(\"/demoService\")\npublic interface RestDemoService {\n    @GET\n    @Path(\"/hello\")\n    Integer hello(@QueryParam(\"a\") Integer a, @QueryParam(\"b\") Integer b);\n\n    @GET\n    @Path(\"/findUserById\")\n    Response findUserById(@QueryParam(\"id\") Integer id);\n\n    @GET\n    @Path(\"/error\")\n    String error();\n\n    @POST\n    @Path(\"/say\")\n    @Consumes({MediaType.TEXT_PLAIN})\n    String sayHello(String name);\n\n    @POST\n    @Path(\"number\")\n    @Produces({MediaType.APPLICATION_FORM_URLENCODED})\n    @Consumes({MediaType.APPLICATION_FORM_URLENCODED})\n    Long testFormBody(@FormParam(\"number\") Long number);\n\n    boolean isCalled();\n\n    @DELETE\n    @Path(\"{uid}\")\n    String deleteUserByUid(@PathParam(\"uid\") String uid);\n\n    @DELETE\n    @Path(\"/deleteUserById/{uid}\")\n    public Response deleteUserById(@PathParam(\"uid\") String uid);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/compatible/rest/RestDemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;\n\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport javax.ws.rs.core.Response;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jboss.resteasy.specimpl.BuiltResponse;\n\npublic class RestDemoServiceImpl implements RestDemoService {\n    private static Map<String, Object> context;\n    private boolean called;\n\n    @Override\n    public String sayHello(String name) {\n        called = true;\n        return \"Hello, \" + name;\n    }\n\n    @Override\n    public Long testFormBody(Long number) {\n        return number;\n    }\n\n    public boolean isCalled() {\n        return called;\n    }\n\n    @Override\n    public String deleteUserByUid(String uid) {\n        return uid;\n    }\n\n    @Override\n    public Integer hello(Integer a, Integer b) {\n        context = RpcContext.getServerAttachment().getObjectAttachments();\n        return a + b;\n    }\n\n    @Override\n    public Response findUserById(Integer id) {\n        Map<String, Object> content = new HashMap<>();\n        content.put(\"username\", \"jack\");\n        content.put(\"id\", id);\n\n        return BuiltResponse.ok(content).build();\n    }\n\n    @Override\n    public String error() {\n        throw new RuntimeException();\n    }\n\n    @Override\n    public Response deleteUserById(String uid) {\n        return Response.status(300).entity(\"deleted\").build();\n    }\n\n    public static Map<String, Object> getAttachments() {\n        return context;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/service/JaxrsDemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.service;\n\nimport javax.ws.rs.BeanParam;\nimport javax.ws.rs.GET;\nimport javax.ws.rs.POST;\nimport javax.ws.rs.Path;\nimport javax.ws.rs.QueryParam;\nimport javax.ws.rs.core.MultivaluedMap;\n\nimport org.jboss.resteasy.annotations.Form;\n\npublic interface JaxrsDemoService {\n\n    @POST\n    @Path(\"/formTest\")\n    UserForm formTest(@Form(prefix = \"user\") UserForm userForm);\n\n    @POST\n    @Path(\"/beanTest/{id}\")\n    User getTest(@BeanParam User user);\n\n    @GET\n    @Path(\"/convertTest\")\n    User convertTest(@QueryParam(\"user\") User user);\n\n    @POST\n    @Path(\"/multivaluedMapTest\")\n    MultivaluedMap<String, Integer> multiValueMapTest(MultivaluedMap<String, Integer> params);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/service/JaxrsDemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.service;\n\nimport javax.ws.rs.core.MultivaluedMap;\n\npublic class JaxrsDemoServiceImpl implements JaxrsDemoService {\n\n    @Override\n    public UserForm formTest(UserForm userForm) {\n        return userForm;\n    }\n\n    @Override\n    public User getTest(User user) {\n        return user;\n    }\n\n    @Override\n    public User convertTest(User user) {\n        return user;\n    }\n\n    @Override\n    public MultivaluedMap<String, Integer> multiValueMapTest(MultivaluedMap<String, Integer> params) {\n        return params;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/service/ParamConverterProviderImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.service;\n\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport javax.ws.rs.ext.ParamConverter;\nimport javax.ws.rs.ext.ParamConverterProvider;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Type;\n\npublic class ParamConverterProviderImpl implements ParamConverterProvider {\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {\n        if (rawType.isAssignableFrom(User.class)) {\n            return (ParamConverter<T>) new UserParamConverter();\n        }\n        return null;\n    }\n\n    static final class UserParamConverter implements ParamConverter<User> {\n        @Override\n        public User fromString(String value) {\n            String[] arr = StringUtils.tokenize(value, ',');\n            User user = new User();\n            if (arr.length > 1) {\n                user.setId(Long.valueOf(arr[0]));\n                user.setName(arr[1]);\n            }\n            return user;\n        }\n\n        @Override\n        public String toString(User user) {\n            return \"User{\" + \"id=\" + user.getId() + \", name='\" + user.getName() + \"\\\"}\";\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/service/User.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.service;\n\nimport javax.ws.rs.BeanParam;\nimport javax.ws.rs.PathParam;\nimport javax.ws.rs.QueryParam;\n\npublic class User {\n\n    @PathParam(\"id\")\n    private Long id;\n\n    @QueryParam(\"name\")\n    private String name;\n\n    @BeanParam\n    private User owner;\n\n    @BeanParam\n    private UserForm form;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public User getOwner() {\n        return owner;\n    }\n\n    public void setOwner(User owner) {\n        this.owner = owner;\n    }\n\n    public UserForm getForm() {\n        return form;\n    }\n\n    public void setForm(UserForm form) {\n        this.form = form;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/service/UserForm.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.service;\n\nimport javax.ws.rs.FormParam;\nimport javax.ws.rs.HeaderParam;\n\npublic class UserForm {\n\n    @FormParam(\"first\")\n    String firstName;\n\n    @FormParam(\"last\")\n    String lastName;\n\n    @HeaderParam(\"Content-Type\")\n    String contentType;\n\n    public String getFirstName() {\n        return firstName;\n    }\n\n    public void setFirstName(String firstName) {\n        this.firstName = firstName;\n    }\n\n    public String getLastName() {\n        return lastName;\n    }\n\n    public void setLastName(String lastName) {\n        this.lastName = lastName;\n    }\n\n    public String getContentType() {\n        return contentType;\n    }\n\n    public void setContentType(String contentType) {\n        this.contentType = contentType;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/resources/META-INF/services/javax.ws.rs.ext.ParamConverterProvider",
    "content": "org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.service.ParamConverterProviderImpl\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-jaxrs/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Logger name=\"org.apache.dubbo.rpc.protocol.tri.h12\" level=\"debug\"/>\n        <Logger name=\"org.apache.dubbo.rpc.protocol.tri.rest\" level=\"debug\"/>\n        <Logger name=\"org.apache.dubbo.remoting.http12\" level=\"debug\"/>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-rest-openapi</artifactId>\n\n  <properties>\n    <swagger-annotations.version>2.2.45</swagger-annotations.version>\n    <swagger-ui.version>5.32.0</swagger-ui.version>\n    <redoc.version>2.5.1</redoc.version>\n    <webjars-locator.version>1.1.3</webjars-locator.version>\n    <therapi.version>0.15.0</therapi.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>io.swagger.core.v3</groupId>\n      <artifactId>swagger-annotations</artifactId>\n      <version>${swagger-annotations.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.webjars</groupId>\n      <artifactId>swagger-ui</artifactId>\n      <version>${swagger-ui.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.webjars</groupId>\n      <artifactId>redoc</artifactId>\n      <version>${redoc.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.webjars</groupId>\n      <artifactId>webjars-locator-lite</artifactId>\n      <version>${webjars-locator.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>com.github.therapi</groupId>\n      <artifactId>therapi-runtime-javadoc</artifactId>\n      <version>${therapi.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.spockframework</groupId>\n      <artifactId>spock-core</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.codehaus.gmavenplus</groupId>\n        <artifactId>gmavenplus-plugin</artifactId>\n        <executions>\n          <execution>\n            <goals>\n              <goal>compileTests</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic abstract class AbstractContext {\n\n    private final OpenAPI openAPI;\n    private final SchemaResolver schemaResolver;\n    private final ExtensionFactory extensionFactory;\n\n    private Map<String, Object> attributes;\n\n    AbstractContext(OpenAPI openAPI, SchemaResolver schemaResolver, ExtensionFactory extensionFactory) {\n        this.openAPI = openAPI;\n        this.schemaResolver = schemaResolver;\n        this.extensionFactory = extensionFactory;\n    }\n\n    public final String getGroup() {\n        return openAPI.getGroup();\n    }\n\n    public final OpenAPI getOpenAPI() {\n        return openAPI;\n    }\n\n    public final SchemaResolver getSchemaResolver() {\n        return schemaResolver;\n    }\n\n    public final ExtensionFactory getExtensionFactory() {\n        return extensionFactory;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public final <T> T getAttribute(String name) {\n        return attributes == null ? null : (T) attributes.get(name);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public final <T> T removeAttribute(String name) {\n        return attributes == null ? null : (T) attributes.remove(name);\n    }\n\n    public final void setAttribute(String name, Object value) {\n        if (attributes == null) {\n            attributes = new HashMap<>();\n        }\n        attributes.put(name, value);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.Environment;\nimport org.apache.dubbo.common.utils.Pair;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.nested.OpenAPIConfig;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\n\nimport static org.apache.dubbo.rpc.Constants.H2_SETTINGS_OPENAPI_PREFIX;\n\npublic final class ConfigFactory {\n\n    private static Map<String, Method> CONFIG_METHODS;\n\n    private final FrameworkModel frameworkModel;\n    private volatile Map<String, OpenAPIConfig> configMap;\n\n    public ConfigFactory(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    private static Environment getEnvironment(FrameworkModel frameworkModel) {\n        return frameworkModel.defaultApplication().modelEnvironment();\n    }\n\n    public OpenAPIConfig getConfig(String group) {\n        return getConfigMap().get(group);\n    }\n\n    public OpenAPIConfig getGlobalConfig() {\n        return getConfigMap().get(Constants.GLOBAL_GROUP);\n    }\n\n    private Map<String, OpenAPIConfig> getConfigMap() {\n        if (configMap == null) {\n            synchronized (this) {\n                if (configMap == null) {\n                    configMap = readConfigMap();\n                }\n            }\n        }\n        return configMap;\n    }\n\n    private Map<String, OpenAPIConfig> readConfigMap() {\n        Map<String, OpenAPIConfig> map = new HashMap<>();\n\n        Environment environment = getEnvironment(frameworkModel);\n        Configuration configuration = environment.getConfiguration();\n        List<Map<String, String>> configMaps = environment.getConfigurationMaps();\n\n        Set<String> allKeys = new HashSet<>();\n        for (Map<String, String> configMap : configMaps) {\n            for (String key : configMap.keySet()) {\n                if (key.startsWith(H2_SETTINGS_OPENAPI_PREFIX)) {\n                    allKeys.add(key);\n                }\n            }\n        }\n\n        int len = H2_SETTINGS_OPENAPI_PREFIX.length();\n        Map<Pair<String, String>, TreeMap<Integer, String>> valuesMap = new HashMap<>();\n        for (String fullKey : allKeys) {\n            if (fullKey.length() > len) {\n                char c = fullKey.charAt(len);\n                String group, key;\n                if (c == '.') {\n                    group = StringUtils.EMPTY_STRING;\n                    key = fullKey.substring(len + 1);\n                } else if (c == 's') {\n                    int end = fullKey.indexOf('.', len + 1);\n                    group = fullKey.substring(len + 1, end);\n                    key = fullKey.substring(end + 1);\n                } else {\n                    continue;\n                }\n\n                int brkStart = key.lastIndexOf('[');\n                if (brkStart > 0) {\n                    try {\n                        String value = configuration.getString(fullKey);\n                        if (StringUtils.isEmpty(value)) {\n                            continue;\n                        }\n                        int index = Integer.parseInt(key.substring(brkStart + 1, key.length() - 1));\n                        valuesMap\n                                .computeIfAbsent(Pair.of(group, key.substring(0, brkStart)), k -> new TreeMap<>())\n                                .put(index, value);\n                    } catch (NumberFormatException ignored) {\n                    }\n                    continue;\n                }\n\n                applyConfigValue(map, group, key, configuration.getString(fullKey));\n            }\n        }\n        for (Map.Entry<Pair<String, String>, TreeMap<Integer, String>> entry : valuesMap.entrySet()) {\n            Pair<String, String> pair = entry.getKey();\n            String value = StringUtils.join(entry.getValue().values(), \",\");\n            applyConfigValue(map, pair.getKey(), pair.getValue(), value);\n        }\n        map.computeIfAbsent(Constants.GLOBAL_GROUP, k -> new OpenAPIConfig());\n        return map;\n    }\n\n    private static void applyConfigValue(Map<String, OpenAPIConfig> map, String group, String key, String value) {\n        if (value == null || value.isEmpty()) {\n            return;\n        }\n\n        OpenAPIConfig config = map.computeIfAbsent(group, k -> new OpenAPIConfig());\n        int index = key.indexOf(\"settings.\");\n        if (index == 0) {\n            Map<String, String> settings = config.getSettings();\n            if (settings == null) {\n                config.setSettings(settings = new HashMap<>());\n            }\n            settings.put(key.substring(9), value);\n            return;\n        }\n\n        Map<String, Method> configMethods = CONFIG_METHODS;\n        if (configMethods == null) {\n            configMethods = new HashMap<>();\n            for (Method method : OpenAPIConfig.class.getMethods()) {\n                String name = toConfigName(method);\n                if (name != null) {\n                    configMethods.put(name, method);\n                }\n            }\n            CONFIG_METHODS = configMethods;\n        }\n\n        Method method = configMethods.get(key);\n        if (method == null) {\n            return;\n        }\n\n        Class<?> valueType = method.getParameterTypes()[0];\n        try {\n            if (valueType == String.class) {\n                method.invoke(config, value);\n            } else if (valueType == Boolean.class) {\n                method.invoke(config, StringUtils.toBoolean(value, false));\n            } else if (valueType.isArray()) {\n                method.invoke(config, new Object[] {StringUtils.tokenize(value)});\n            }\n        } catch (Throwable ignored) {\n        }\n    }\n\n    private static String toConfigName(Method method) {\n        if (method.getParameterCount() != 1) {\n            return null;\n        }\n        String name = method.getName();\n        if (!name.startsWith(\"set\")) {\n            return null;\n        }\n        int len = name.length();\n        StringBuilder sb = new StringBuilder(len);\n        for (int i = 3; i < len; i++) {\n            char c = name.charAt(i);\n            if (Character.isUpperCase(c)) {\n                if (i > 3) {\n                    sb.append('-');\n                }\n                sb.append(Character.toLowerCase(c));\n            } else {\n                sb.append(c);\n            }\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\npublic final class Constants {\n\n    public static final String VERSION_30 = \"3.0.1\";\n    public static final String VERSION_31 = \"3.1.0\";\n\n    public static final String ALL_GROUP = \"all\";\n    public static final String DEFAULT_GROUP = \"default\";\n    public static final String GLOBAL_GROUP = \"\";\n\n    public static final String X_API_GROUP = \"x-api-group\";\n    public static final String X_API_VERSION = \"x-api-version\";\n\n    public static final String X_JAVA_CLASS = \"x-java-class\";\n    public static final String X_JAVA_METHOD = \"x-java-method\";\n    public static final String X_JAVA_METHOD_DESCRIPTOR = \"x-java-method-descriptor\";\n\n    public static final String DUBBO_DEFAULT_SERVER = \"Dubbo Default Server\";\n    public static final String REFERER = \"referer\";\n\n    private Constants() {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\n\npublic interface Context {\n\n    OpenAPIRequest getRequest();\n\n    HttpRequest getHttpRequest();\n\n    HttpResponse getHttpResponse();\n\n    String getGroup();\n\n    OpenAPI getOpenAPI();\n\n    boolean isOpenAPI31();\n\n    SchemaResolver getSchemaResolver();\n\n    ExtensionFactory getExtensionFactory();\n\n    <T> T getAttribute(String name);\n\n    <T> T removeAttribute(String name);\n\n    void setAttribute(String name, Object value);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.utils.Holder;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\n\nfinal class ContextImpl extends AbstractContext implements Context {\n\n    private final OpenAPIRequest request;\n\n    private Boolean openAPI31;\n    private Holder<HttpRequest> httpRequest;\n    private Holder<HttpResponse> httpResponse;\n\n    ContextImpl(OpenAPI openAPI, SchemaResolver schemaResolver, ExtensionFactory extFactory, OpenAPIRequest request) {\n        super(openAPI, schemaResolver, extFactory);\n        this.request = request;\n    }\n\n    @Override\n    public boolean isOpenAPI31() {\n        if (openAPI31 == null) {\n            String v = request.getOpenapi();\n            openAPI31 = v != null && v.startsWith(\"3.1.\");\n        }\n        return openAPI31;\n    }\n\n    @Override\n    public OpenAPIRequest getRequest() {\n        return request;\n    }\n\n    @Override\n    public HttpRequest getHttpRequest() {\n        Holder<HttpRequest> holder = httpRequest;\n        if (holder == null) {\n            holder = new Holder<>();\n            holder.set(RpcContext.getServiceContext().getRequest(HttpRequest.class));\n            httpRequest = holder;\n        }\n        return holder.get();\n    }\n\n    @Override\n    public HttpResponse getHttpResponse() {\n        Holder<HttpResponse> holder = httpResponse;\n        if (holder == null) {\n            holder = new Holder<>();\n            holder.set(RpcContext.getServiceContext().getResponse(HttpResponse.class));\n            httpResponse = holder;\n        }\n        return holder.get();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.io.Bytes;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;\n\nimport java.lang.reflect.Method;\nimport java.util.concurrent.ThreadLocalRandom;\n\npublic class DefaultOpenAPINamingStrategy implements OpenAPINamingStrategy {\n\n    @Override\n    public String generateOperationId(MethodMeta methodMeta, OpenAPI openAPI) {\n        return methodMeta.getMethod().getName();\n    }\n\n    @Override\n    public String resolveOperationIdConflict(int attempt, String operationId, MethodMeta methodMeta, OpenAPI openAPI) {\n        Method method = methodMeta.getMethod();\n        if (attempt == 1) {\n            String sig = TypeUtils.buildSig(method);\n            if (sig != null) {\n                return method.getName() + '_' + sig;\n            }\n        }\n        return method.getName() + '_' + buildPostfix(attempt, method.toString());\n    }\n\n    @Override\n    public String generateSchemaName(Class<?> clazz, OpenAPI openAPI) {\n        return clazz.getSimpleName();\n    }\n\n    @Override\n    public String resolveSchemaNameConflict(int attempt, String schemaName, Class<?> clazz, OpenAPI openAPI) {\n        return clazz.getSimpleName() + '_' + buildPostfix(attempt, clazz.getName());\n    }\n\n    private static String buildPostfix(int attempt, String str) {\n        if (attempt > 4) {\n            str += ThreadLocalRandom.current().nextInt(10000);\n        }\n        return Bytes.bytes2hex(Bytes.getMD5(str), 0, Math.min(4, attempt));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.logger.FluentLogger;\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.LRUCache;\nimport org.apache.dubbo.common.utils.Pair;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.HttpResult;\nimport org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException;\nimport org.apache.dubbo.remoting.http12.message.MediaType;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIService;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.ExceptionUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree.Match;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingRegistry;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.lang.ref.SoftReference;\nimport java.lang.reflect.Method;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.IdentityHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\npublic class DefaultOpenAPIService implements OpenAPIRequestHandler, OpenAPIService {\n\n    private static final FluentLogger LOG = FluentLogger.of(DefaultOpenAPIService.class);\n    private static final String API_DOCS = \"/api-docs\";\n\n    private final LRUCache<String, SoftReference<String>> cache = new LRUCache<>(64);\n    private final FrameworkModel frameworkModel;\n    private final ConfigFactory configFactory;\n    private final ExtensionFactory extensionFactory;\n    private final DefinitionResolver definitionResolver;\n    private final DefinitionMerger definitionMerger;\n    private final DefinitionFilter definitionFilter;\n    private final DefinitionEncoder definitionEncoder;\n    private final RadixTree<OpenAPIRequestHandler> tree;\n\n    private volatile List<OpenAPI> openAPIs;\n    private boolean exported;\n    private ScheduledFuture<?> exportFuture;\n\n    public DefaultOpenAPIService(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n        configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class);\n        extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class);\n        definitionResolver = new DefinitionResolver(frameworkModel);\n        definitionMerger = new DefinitionMerger(frameworkModel);\n        definitionFilter = new DefinitionFilter(frameworkModel);\n        definitionEncoder = new DefinitionEncoder(frameworkModel);\n        tree = initRequestHandlers();\n    }\n\n    private RadixTree<OpenAPIRequestHandler> initRequestHandlers() {\n        RadixTree<OpenAPIRequestHandler> tree = new RadixTree<>(false);\n        for (OpenAPIRequestHandler handler : extensionFactory.getExtensions(OpenAPIRequestHandler.class)) {\n            for (String path : handler.getPaths()) {\n                tree.addPath(path, handler);\n            }\n        }\n        tree.addPath(this, API_DOCS, API_DOCS + \"/{group}\");\n        return tree;\n    }\n\n    @Override\n    public HttpResult<?> handle(String path, HttpRequest httpRequest, HttpResponse httpResponse) {\n        OpenAPIRequest request = httpRequest.attribute(OpenAPIRequest.class.getName());\n        String group = RequestUtils.getPathVariable(httpRequest, \"group\");\n        if (group != null) {\n            request.setGroup(StringUtils.substringBeforeLast(group, '.'));\n        }\n        return HttpResult.builder()\n                .contentType(MediaType.APPLICATION + '/' + request.getFormat())\n                .body(handleDocument(request, httpRequest).getBytes(StandardCharsets.UTF_8))\n                .build();\n    }\n\n    @Override\n    public Collection<String> getOpenAPIGroups() {\n        Set<String> groups = new LinkedHashSet<>();\n        groups.add(Constants.DEFAULT_GROUP);\n        for (OpenAPI openAPI : getOpenAPIs()) {\n            groups.add(openAPI.getGroup());\n            openAPI.walkOperations(operation -> {\n                String group = operation.getGroup();\n                if (StringUtils.isNotEmpty(group)) {\n                    groups.add(group);\n                }\n            });\n        }\n        return groups;\n    }\n\n    public OpenAPI getOpenAPI(OpenAPIRequest request) {\n        return definitionFilter.filter(definitionMerger.merge(getOpenAPIs(), request), request);\n    }\n\n    private List<OpenAPI> getOpenAPIs() {\n        if (openAPIs == null) {\n            synchronized (this) {\n                if (openAPIs == null) {\n                    openAPIs = resolveOpenAPIs();\n                }\n            }\n        }\n        return openAPIs;\n    }\n\n    private List<OpenAPI> resolveOpenAPIs() {\n        RequestMappingRegistry registry = frameworkModel.getBean(RequestMappingRegistry.class);\n        if (registry == null) {\n            return Collections.emptyList();\n        }\n\n        Map<Key, Map<Method, List<Registration>>> byClassMap = new HashMap<>();\n        for (Registration registration : registry.getRegistrations()) {\n            HandlerMeta meta = registration.getMeta();\n            byClassMap\n                    .computeIfAbsent(new Key(meta.getService()), k -> new IdentityHashMap<>())\n                    .computeIfAbsent(meta.getMethod().getMethod(), k -> new ArrayList<>(1))\n                    .add(registration);\n        }\n\n        List<OpenAPI> openAPIs = new ArrayList<>(byClassMap.size());\n        for (Map.Entry<Key, Map<Method, List<Registration>>> entry : byClassMap.entrySet()) {\n            OpenAPI openAPI = definitionResolver.resolve(\n                    entry.getKey().serviceMeta, entry.getValue().values());\n            if (openAPI != null) {\n                openAPIs.add(openAPI);\n            }\n        }\n        openAPIs.sort(Comparator.comparingInt(OpenAPI::getPriority));\n\n        return openAPIs;\n    }\n\n    @Override\n    public String getDocument(OpenAPIRequest request) {\n        String path = null;\n        try {\n            request = Helper.formatRequest(request);\n\n            HttpRequest httpRequest = RpcContext.getServiceContext().getRequest(HttpRequest.class);\n            if (!RequestUtils.isRestRequest(httpRequest)) {\n                return handleDocument(request, null);\n            }\n\n            path = RequestUtils.getPathVariable(httpRequest, \"path\");\n            if (StringUtils.isEmpty(path)) {\n                String url = PathUtils.join(httpRequest.path(), \"swagger-ui/index.html\");\n                throw HttpResult.found(url).toPayload();\n            }\n\n            path = '/' + path;\n            List<Match<OpenAPIRequestHandler>> matches = tree.matchRelaxed(path);\n            if (matches.isEmpty()) {\n                throw HttpResult.notFound().toPayload();\n            }\n\n            Collections.sort(matches);\n            Match<OpenAPIRequestHandler> match = matches.get(0);\n            HttpResponse httpResponse = RpcContext.getServiceContext().getResponse(HttpResponse.class);\n            if (request.getFormat() == null) {\n                request.setFormat(Helper.parseFormat(httpResponse.contentType()));\n            }\n            httpRequest.setAttribute(OpenAPIRequest.class.getName(), request);\n            httpRequest.setAttribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE, match.getVariableMap());\n            throw match.getValue().handle(path, httpRequest, httpResponse).toPayload();\n        } catch (HttpResultPayloadException e) {\n            throw e;\n        } catch (Throwable t) {\n            Level level = ExceptionUtils.resolveLogLevel(ExceptionUtils.unwrap(t));\n            LOG.log(level, \"Failed to processing OpenAPI request {} for path: '{}'\", request, path, t);\n            throw t;\n        }\n    }\n\n    private String handleDocument(OpenAPIRequest request, HttpRequest httpRequest) {\n        if (Boolean.FALSE.equals(configFactory.getGlobalConfig().getCache())) {\n            return definitionEncoder.encode(getOpenAPI(request), request);\n        }\n\n        StringBuilder sb = new StringBuilder();\n        if (httpRequest != null) {\n            String host = httpRequest.serverHost();\n            if (host != null) {\n                String referer = httpRequest.header(Constants.REFERER);\n                sb.append(referer != null && referer.contains(host) ? '/' : host);\n            }\n        }\n        sb.append('|').append(request.toString());\n\n        String cacheKey = sb.toString();\n        SoftReference<String> ref = cache.get(cacheKey);\n        if (ref != null) {\n            String value = ref.get();\n            if (value != null) {\n                return value;\n            }\n        }\n        String value = definitionEncoder.encode(getOpenAPI(request), request);\n        cache.put(cacheKey, new SoftReference<>(value));\n        return value;\n    }\n\n    @Override\n    public void refresh() {\n        LOG.debug(\"Refreshing OpenAPI documents\");\n        openAPIs = null;\n        cache.clear();\n        if (exported) {\n            export();\n        }\n    }\n\n    @Override\n    public void export() {\n        if (!extensionFactory.hasExtensions(OpenAPIDocumentPublisher.class)) {\n            return;\n        }\n\n        try {\n            if (exportFuture != null) {\n                exportFuture.cancel(false);\n            }\n            exportFuture = frameworkModel\n                    .getBean(FrameworkExecutorRepository.class)\n                    .getMetadataRetryExecutor()\n                    .schedule(this::doExport, 30, TimeUnit.SECONDS);\n            exported = true;\n        } catch (Throwable t) {\n            LOG.internalWarn(\"Failed to export OpenAPI documents\", t);\n        }\n    }\n\n    private void doExport() {\n        for (OpenAPIDocumentPublisher publisher : extensionFactory.getExtensions(OpenAPIDocumentPublisher.class)) {\n            try {\n                publisher.publish(request -> {\n                    OpenAPI openAPI = getOpenAPI(request);\n                    String document = definitionEncoder.encode(openAPI, request);\n                    return Pair.of(openAPI, document);\n                });\n            } catch (Throwable t) {\n                LOG.internalWarn(\"Failed to publish OpenAPI document by {}\", publisher, t);\n            }\n        }\n        exportFuture = null;\n    }\n\n    private static final class Key {\n\n        private final ServiceMeta serviceMeta;\n\n        public Key(ServiceMeta serviceMeta) {\n            this.serviceMeta = serviceMeta;\n        }\n\n        @SuppressWarnings({\"EqualsWhichDoesntCheckParameterClass\", \"EqualsDoesntCheckParameterClass\"})\n        @Override\n        public boolean equals(Object obj) {\n            return serviceMeta.getType() == ((Key) obj).serviceMeta.getType();\n        }\n\n        @Override\n        public int hashCode() {\n            return serviceMeta.getType().hashCode();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException;\nimport org.apache.dubbo.remoting.http12.message.MediaType;\nimport org.apache.dubbo.remoting.http12.message.codec.YamlCodec;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\n\nimport java.io.ByteArrayOutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nfinal class DefinitionEncoder {\n\n    private final ExtensionFactory extensionFactory;\n    private final SchemaResolver schemaResolver;\n\n    private ProtoEncoder protoEncoder;\n\n    DefinitionEncoder(FrameworkModel frameworkModel) {\n        extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class);\n        schemaResolver = frameworkModel.getOrRegisterBean(SchemaResolver.class);\n    }\n\n    public String encode(OpenAPI openAPI, OpenAPIRequest request) {\n        if (openAPI == null) {\n            openAPI = new OpenAPI();\n        }\n        Map<String, Object> root = new LinkedHashMap<>();\n        ContextImpl context = new ContextImpl(openAPI, schemaResolver, extensionFactory, request);\n        openAPI.writeTo(root, context);\n\n        String format = request.getFormat();\n        format = format == null ? MediaType.JSON : format.toLowerCase();\n        switch (format) {\n            case MediaType.JSON:\n                if (Boolean.TRUE.equals(request.getPretty())) {\n                    return JsonUtils.toPrettyJson(root);\n                }\n                return JsonUtils.toJson(root);\n            case \"yml\":\n            case \"yaml\":\n                ByteArrayOutputStream os = new ByteArrayOutputStream(4096);\n                YamlCodec.INSTANCE.encode(os, root, StandardCharsets.UTF_8);\n                return new String(os.toByteArray(), StandardCharsets.UTF_8);\n            case \"proto\":\n                if (protoEncoder == null) {\n                    protoEncoder = new ProtoEncoder();\n                }\n                return protoEncoder.encode(openAPI);\n            default:\n                throw new UnsupportedMediaTypeException(\"text/\" + format);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Components;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Header;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Node;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server;\n\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nfinal class DefinitionFilter {\n\n    private final ExtensionFactory extensionFactory;\n    private final SchemaResolver schemaResolver;\n\n    public DefinitionFilter(FrameworkModel frameworkModel) {\n        extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class);\n        schemaResolver = frameworkModel.getOrRegisterBean(SchemaResolver.class);\n    }\n\n    public OpenAPI filter(OpenAPI openAPI, OpenAPIRequest request) {\n        OpenAPIFilter[] filters = extensionFactory.getExtensions(OpenAPIFilter.class, request.getGroup());\n        Context context = new ContextImpl(openAPI, schemaResolver, extensionFactory, request);\n\n        if (filters.length > 0) {\n            for (OpenAPIFilter filter : filters) {\n                openAPI = filter.filterOpenAPI(openAPI, context);\n                if (openAPI == null) {\n                    return null;\n                }\n            }\n\n            filterPaths(openAPI, filters, context);\n\n            filterComponents(openAPI, filters, context);\n\n            for (OpenAPIFilter filter : filters) {\n                openAPI = filter.filterOpenAPICompletion(openAPI, context);\n                if (openAPI == null) {\n                    return null;\n                }\n            }\n        }\n\n        filterServer(openAPI, context);\n\n        return openAPI;\n    }\n\n    private static void filterServer(OpenAPI openAPI, Context context) {\n        List<Server> servers = openAPI.getServers();\n        if (servers == null || servers.size() != 1) {\n            return;\n        }\n        Server server = servers.get(0);\n        if (!Constants.DUBBO_DEFAULT_SERVER.equals(server.getDescription())) {\n            return;\n        }\n        HttpRequest httpRequest = context.getHttpRequest();\n        if (httpRequest == null) {\n            return;\n        }\n        String host = httpRequest.serverHost();\n        if (host == null) {\n            return;\n        }\n        String referer = httpRequest.header(Constants.REFERER);\n        if (referer != null && referer.contains(host)) {\n            servers.clear();\n        } else {\n            server.setUrl(httpRequest.scheme() + \"://\" + host);\n        }\n    }\n\n    private void filterPaths(OpenAPI openAPI, OpenAPIFilter[] filters, Context context) {\n        Map<String, PathItem> paths = openAPI.getPaths();\n        if (paths == null) {\n            return;\n        }\n\n        Iterator<Entry<String, PathItem>> it = paths.entrySet().iterator();\n        out:\n        while (it.hasNext()) {\n            Entry<String, PathItem> entry = it.next();\n            PathItem pathItem = entry.getValue();\n            PathItem initialPathItem = pathItem;\n            for (OpenAPIFilter filter : filters) {\n                pathItem = filter.filterPathItem(entry.getKey(), pathItem, context);\n                if (pathItem == null) {\n                    it.remove();\n                    continue out;\n                }\n            }\n            if (pathItem != initialPathItem) {\n                entry.setValue(pathItem);\n            }\n\n            filterOperation(pathItem, filters, context);\n        }\n    }\n\n    private void filterOperation(PathItem pathItem, OpenAPIFilter[] filters, Context context) {\n        Map<HttpMethods, Operation> operations = pathItem.getOperations();\n        if (operations == null) {\n            return;\n        }\n\n        Iterator<Entry<HttpMethods, Operation>> it = operations.entrySet().iterator();\n        out:\n        while (it.hasNext()) {\n            Entry<HttpMethods, Operation> entry = it.next();\n            HttpMethods httpMethod = entry.getKey();\n            Operation operation = entry.getValue();\n            Operation initialOperation = operation;\n            for (OpenAPIFilter filter : filters) {\n                operation = filter.filterOperation(httpMethod, operation, pathItem, context);\n                if (operation == null) {\n                    it.remove();\n                    continue out;\n                }\n            }\n            if (operation != initialOperation) {\n                entry.setValue(operation);\n            }\n\n            filterParameter(operation, filters, context);\n            filterRequestBody(operation, filters, context);\n            filterResponse(operation, filters, context);\n        }\n    }\n\n    private void filterParameter(Operation operation, OpenAPIFilter[] filters, Context context) {\n        List<Parameter> parameters = operation.getParameters();\n        if (parameters == null) {\n            return;\n        }\n\n        ListIterator<Parameter> it = parameters.listIterator();\n        out:\n        while (it.hasNext()) {\n            Parameter parameter = it.next();\n            Parameter initialParameter = parameter;\n            for (OpenAPIFilter filter : filters) {\n                parameter = filter.filterParameter(parameter, operation, context);\n                if (parameter == null) {\n                    it.remove();\n                    continue out;\n                }\n            }\n            if (parameter != initialParameter) {\n                it.set(parameter);\n            }\n\n            filterContext(parameter.getContents(), filters, context);\n        }\n    }\n\n    private void filterRequestBody(Operation operation, OpenAPIFilter[] filters, Context context) {\n        RequestBody body = operation.getRequestBody();\n        if (body == null) {\n            return;\n        }\n\n        RequestBody initialRequestBody = body;\n        for (OpenAPIFilter filter : filters) {\n            body = filter.filterRequestBody(body, operation, context);\n            if (body == null) {\n                operation.setRequestBody(null);\n                return;\n            }\n        }\n        if (body != initialRequestBody) {\n            operation.setRequestBody(body);\n        }\n\n        filterContext(body.getContents(), filters, context);\n    }\n\n    private void filterResponse(Operation operation, OpenAPIFilter[] filters, Context context) {\n        Map<String, ApiResponse> responses = operation.getResponses();\n        if (responses == null) {\n            return;\n        }\n\n        Iterator<Entry<String, ApiResponse>> it = responses.entrySet().iterator();\n        out:\n        while (it.hasNext()) {\n            Entry<String, ApiResponse> entry = it.next();\n            ApiResponse response = entry.getValue();\n            ApiResponse initialApiResponse = response;\n            for (OpenAPIFilter filter : filters) {\n                response = filter.filterResponse(response, operation, context);\n                if (response == null) {\n                    it.remove();\n                    continue out;\n                }\n            }\n            if (response != initialApiResponse) {\n                entry.setValue(response);\n            }\n\n            filterHeader(response, operation, filters, context);\n            filterContext(response.getContents(), filters, context);\n        }\n    }\n\n    private void filterHeader(ApiResponse response, Operation operation, OpenAPIFilter[] filters, Context context) {\n        Map<String, Header> headers = response.getHeaders();\n        if (headers == null) {\n            return;\n        }\n\n        Iterator<Entry<String, Header>> it = headers.entrySet().iterator();\n        out:\n        while (it.hasNext()) {\n            Entry<String, Header> entry = it.next();\n            Header header = entry.getValue();\n            Header initialHeader = header;\n            for (OpenAPIFilter filter : filters) {\n                header = filter.filterHeader(header, response, operation, context);\n                if (header == null) {\n                    it.remove();\n                    continue out;\n                }\n            }\n            if (header != initialHeader) {\n                entry.setValue(header);\n            }\n\n            filterSchema(header::getSchema, header::setSchema, header, filters, context);\n\n            Map<String, MediaType> contents = header.getContents();\n            if (contents == null) {\n                continue;\n            }\n\n            for (MediaType content : contents.values()) {\n                filterSchema(content::getSchema, content::setSchema, content, filters, context);\n            }\n        }\n    }\n\n    private boolean filterContext(Map<String, MediaType> contents, OpenAPIFilter[] filters, Context context) {\n        if (contents == null) {\n            return true;\n        }\n\n        for (MediaType content : contents.values()) {\n            filterSchema(content::getSchema, content::setSchema, content, filters, context);\n        }\n        return false;\n    }\n\n    private void filterComponents(OpenAPI openAPI, OpenAPIFilter[] filters, Context context) {\n        Components components = openAPI.getComponents();\n        if (components == null) {\n            return;\n        }\n\n        filterSchemas(components, filters, context);\n        filterSecuritySchemes(components, filters, context);\n    }\n\n    private void filterSchemas(Components components, OpenAPIFilter[] filters, Context context) {\n        if (components == null) {\n            return;\n        }\n\n        Map<String, Schema> schemas = components.getSchemas();\n        if (schemas == null) {\n            return;\n        }\n\n        for (Entry<String, Schema> entry : schemas.entrySet()) {\n            filterSchema(entry::getValue, entry::setValue, components, filters, context);\n        }\n    }\n\n    private void filterSchema(\n            Supplier<Schema> getter, Consumer<Schema> setter, Node<?> owner, OpenAPIFilter[] filters, Context context) {\n        Schema schema = getter.get();\n        if (schema == null) {\n            return;\n        }\n\n        Schema initialSchema = schema;\n        for (OpenAPIFilter filter : filters) {\n            schema = filter.filterSchema(schema, owner, context);\n            if (schema == null) {\n                setter.accept(null);\n                return;\n            }\n        }\n        if (schema != initialSchema) {\n            setter.accept(schema);\n        }\n\n        filterSchema(schema::getItems, schema::setItems, schema, filters, context);\n\n        Map<String, Schema> properties = schema.getProperties();\n        if (properties != null) {\n            out:\n            for (Entry<String, Schema> entry : properties.entrySet()) {\n                String name = entry.getKey();\n                Schema valueSchema = entry.getValue();\n                for (OpenAPIFilter filter : filters) {\n                    valueSchema = filter.filterSchemaProperty(name, valueSchema, schema, context);\n                    if (valueSchema == null) {\n                        entry.setValue(null);\n                        continue out;\n                    }\n                }\n\n                filterSchema(entry::getValue, entry::setValue, schema, filters, context);\n            }\n        }\n\n        filterSchema(\n                schema::getAdditionalPropertiesSchema, schema::setAdditionalPropertiesSchema, schema, filters, context);\n\n        List<Schema> allOf = schema.getAllOf();\n        if (allOf != null) {\n            ListIterator<Schema> it = allOf.listIterator();\n            while (it.hasNext()) {\n                filterSchema(it::next, it::set, schema, filters, context);\n            }\n        }\n\n        List<Schema> oneOf = schema.getOneOf();\n        if (oneOf != null) {\n            ListIterator<Schema> it = oneOf.listIterator();\n            while (it.hasNext()) {\n                filterSchema(it::next, it::set, schema, filters, context);\n            }\n        }\n\n        List<Schema> anyOf = schema.getAnyOf();\n        if (anyOf != null) {\n            ListIterator<Schema> it = anyOf.listIterator();\n            while (it.hasNext()) {\n                filterSchema(it::next, it::set, schema, filters, context);\n            }\n        }\n\n        filterSchema(schema::getNot, schema::setNot, schema, filters, context);\n    }\n\n    private void filterSecuritySchemes(Components components, OpenAPIFilter[] filters, Context context) {\n        if (components == null) {\n            return;\n        }\n\n        Map<String, SecurityScheme> securitySchemes = components.getSecuritySchemes();\n        if (securitySchemes == null) {\n            return;\n        }\n\n        Iterator<Entry<String, SecurityScheme>> it = securitySchemes.entrySet().iterator();\n        out:\n        while (it.hasNext()) {\n            Entry<String, SecurityScheme> entry = it.next();\n            SecurityScheme securityScheme = entry.getValue();\n            SecurityScheme initialSecurityScheme = securityScheme;\n            for (OpenAPIFilter filter : filters) {\n                securityScheme = filter.filterSecurityScheme(securityScheme, context);\n                if (securityScheme == null) {\n                    it.remove();\n                    continue out;\n                }\n            }\n            if (securityScheme != initialSecurityScheme) {\n                entry.setValue(securityScheme);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.logger.FluentLogger;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.config.nested.OpenAPIConfig;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Components;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Contact;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Header;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.License;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Node;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityRequirement;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag;\n\nimport java.lang.reflect.Type;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.IdentityHashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setValue;\n\nfinal class DefinitionMerger {\n\n    private static final FluentLogger LOG = FluentLogger.of(DefinitionMerger.class);\n    private static final String NAMING_STRATEGY_PREFIX = \"naming-strategy-\";\n    private static final String NAMING_STRATEGY_DEFAULT = \"default\";\n    private static Type SECURITY_SCHEMES_TYPE;\n    private static Type SECURITY_TYPE;\n\n    private final ExtensionFactory extensionFactory;\n    private final ConfigFactory configFactory;\n    private OpenAPINamingStrategy openAPINamingStrategy;\n\n    DefinitionMerger(FrameworkModel frameworkModel) {\n        extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class);\n        configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class);\n    }\n\n    private OpenAPINamingStrategy getNamingStrategy() {\n        if (openAPINamingStrategy == null) {\n            String strategy = configFactory.getGlobalConfig().getNameStrategy();\n            String name = NAMING_STRATEGY_PREFIX + (strategy == null ? NAMING_STRATEGY_DEFAULT : strategy);\n            openAPINamingStrategy = extensionFactory.getExtension(OpenAPINamingStrategy.class, name);\n            Objects.requireNonNull(openAPINamingStrategy, \"Can't find OpenAPINamingStrategy with name: \" + name);\n        }\n        return openAPINamingStrategy;\n    }\n\n    public OpenAPI merge(List<OpenAPI> openAPIs, OpenAPIRequest request) {\n        Info info = new Info();\n        OpenAPI target = new OpenAPI().setInfo(info);\n\n        OpenAPIConfig globalConfig = configFactory.getGlobalConfig();\n        target.setGlobalConfig(globalConfig);\n        applyConfig(target, globalConfig);\n        if (openAPIs.isEmpty()) {\n            return target;\n        }\n\n        String group = request.getGroup();\n        if (group == null) {\n            group = Constants.DEFAULT_GROUP;\n        }\n        target.setGroup(group);\n\n        String version = request.getVersion();\n        if (version != null) {\n            info.setVersion(version);\n        }\n        target.setOpenapi(Helper.formatSpecVersion(request.getOpenapi()));\n\n        OpenAPIConfig config = configFactory.getConfig(group);\n        target.setConfig(config);\n\n        String[] tags = request.getTag();\n        String[] services = request.getService();\n        for (int i = openAPIs.size() - 1; i >= 0; i--) {\n            OpenAPI source = openAPIs.get(i);\n            if (isServiceNotMatch(source.getMeta().getServiceInterface(), services)) {\n                continue;\n            }\n\n            if (group.equals(source.getGroup())) {\n                mergeBasic(target, source);\n            }\n\n            mergePaths(target, source, group, version, tags);\n\n            mergeSecuritySchemes(target, source);\n\n            mergeTags(target, source);\n        }\n\n        applyConfig(target, config);\n\n        addSchemas(target, version, group);\n\n        completeOperations(target);\n\n        completeModel(target);\n\n        return target;\n    }\n\n    private void applyConfig(OpenAPI target, OpenAPIConfig config) {\n        if (config == null) {\n            return;\n        }\n\n        Info info = target.getInfo();\n        setValue(config::getInfoTitle, info::setTitle);\n        setValue(config::getInfoDescription, info::setDescription);\n        setValue(config::getInfoVersion, info::setVersion);\n\n        Contact contact = info.getContact();\n        if (contact == null) {\n            info.setContact(contact = new Contact());\n        }\n        setValue(config::getInfoContactName, contact::setName);\n        setValue(config::getInfoContactUrl, contact::setUrl);\n        setValue(config::getInfoContactEmail, contact::setEmail);\n\n        ExternalDocs externalDocs = target.getExternalDocs();\n        if (externalDocs == null) {\n            target.setExternalDocs(externalDocs = new ExternalDocs());\n        }\n        setValue(config::getExternalDocsDescription, externalDocs::setDescription);\n        setValue(config::getExternalDocsUrl, externalDocs::setUrl);\n\n        String[] servers = config.getServers();\n        if (servers != null) {\n            target.setServers(Arrays.stream(servers).map(Helper::parseServer).collect(Collectors.toList()));\n        }\n\n        Components components = target.getComponents();\n        if (target.getComponents() == null) {\n            target.setComponents(components = new Components());\n        }\n\n        String securityScheme = config.getSecurityScheme();\n        if (securityScheme != null) {\n            try {\n                if (SECURITY_SCHEMES_TYPE == null) {\n                    SECURITY_SCHEMES_TYPE =\n                            Components.class.getDeclaredField(\"securitySchemes\").getGenericType();\n                }\n                components.setSecuritySchemes(JsonUtils.toJavaObject(securityScheme, SECURITY_SCHEMES_TYPE));\n            } catch (NoSuchFieldException ignored) {\n            }\n        }\n\n        String security = config.getSecurity();\n        if (security != null) {\n            try {\n                if (SECURITY_TYPE == null) {\n                    SECURITY_TYPE = OpenAPI.class.getDeclaredField(\"security\").getGenericType();\n                }\n                target.setSecurity(JsonUtils.toJavaObject(securityScheme, SECURITY_TYPE));\n            } catch (NoSuchFieldException ignored) {\n            }\n        }\n    }\n\n    private void mergeBasic(OpenAPI target, OpenAPI source) {\n        mergeInfo(target, source);\n\n        if (target.getServers() == null) {\n            target.setServers(Node.clone(source.getServers()));\n        }\n\n        List<SecurityRequirement> sourceSecurity = source.getSecurity();\n        if (target.getSecurity() == null) {\n            target.setSecurity(Node.clone(sourceSecurity));\n        }\n\n        ExternalDocs sourceExternalDocs = source.getExternalDocs();\n        if (sourceExternalDocs != null) {\n            ExternalDocs targetExternalDocs = target.getExternalDocs();\n            setValue(sourceExternalDocs::getDescription, targetExternalDocs::setDescription);\n            setValue(sourceExternalDocs::getUrl, targetExternalDocs::setUrl);\n            targetExternalDocs.addExtensions(sourceExternalDocs.getExtensions());\n        }\n\n        target.addExtensions(source.getExtensions());\n    }\n\n    private void mergeInfo(OpenAPI target, OpenAPI source) {\n        Info sourceInfo = source.getInfo();\n        if (sourceInfo == null) {\n            return;\n        }\n\n        Info info = target.getInfo();\n        setValue(sourceInfo::getTitle, info::setTitle);\n        setValue(sourceInfo::getSummary, info::setSummary);\n        setValue(sourceInfo::getDescription, info::setDescription);\n        setValue(sourceInfo::getTermsOfService, info::setTermsOfService);\n        setValue(sourceInfo::getVersion, info::setVersion);\n\n        Contact sourceContact = sourceInfo.getContact();\n        if (sourceContact != null) {\n            Contact contact = info.getContact();\n            setValue(sourceContact::getName, contact::setName);\n            setValue(sourceContact::getUrl, contact::setUrl);\n            setValue(sourceContact::getEmail, contact::setEmail);\n\n            contact.addExtensions(sourceContact.getExtensions());\n        }\n\n        License sourceLicense = sourceInfo.getLicense();\n        if (sourceLicense != null) {\n            License license = info.getLicense();\n            if (license == null) {\n                info.setLicense(license = new License());\n            }\n            setValue(sourceLicense::getName, license::setName);\n            setValue(sourceLicense::getUrl, license::setUrl);\n            license.addExtensions(sourceLicense.getExtensions());\n        }\n\n        info.addExtensions(sourceInfo.getExtensions());\n    }\n\n    private void mergePaths(OpenAPI target, OpenAPI source, String group, String version, String[] tags) {\n        Map<String, PathItem> sourcePaths = source.getPaths();\n        if (sourcePaths == null) {\n            return;\n        }\n\n        Map<String, PathItem> paths = target.getPaths();\n        if (paths == null) {\n            target.setPaths(paths = new TreeMap<>());\n        }\n\n        for (Entry<String, PathItem> entry : sourcePaths.entrySet()) {\n            String path = entry.getKey();\n            PathItem sourcePathItem = entry.getValue();\n            PathItem pathItem = paths.get(path);\n            if (pathItem != null) {\n                String ref = sourcePathItem.getRef();\n                if (ref != null) {\n                    pathItem = paths.get(ref);\n                }\n            }\n            if (pathItem == null) {\n                paths.put(path, pathItem = new PathItem());\n            }\n            mergePath(path, pathItem, sourcePathItem, group, version, tags);\n        }\n    }\n\n    private void mergePath(String path, PathItem target, PathItem source, String group, String version, String[] tags) {\n        if (target.getRef() == null) {\n            target.setRef(source.getRef());\n        }\n        if (target.getSummary() == null) {\n            target.setSummary(source.getSummary());\n        }\n        if (target.getDescription() == null) {\n            target.setDescription(source.getDescription());\n        }\n\n        Map<HttpMethods, Operation> sourceOperations = source.getOperations();\n        if (sourceOperations != null) {\n            for (Entry<HttpMethods, Operation> entry : sourceOperations.entrySet()) {\n                HttpMethods httpMethod = entry.getKey();\n                Operation sourceOperation = entry.getValue();\n                if (isGroupNotMatch(group, sourceOperation.getGroup())\n                        || isVersionNotMatch(version, sourceOperation.getVersion())\n                        || isTagNotMatch(tags, sourceOperation.getTags())) {\n                    continue;\n                }\n\n                Operation operation = target.getOperation(httpMethod);\n                if (operation == null) {\n                    target.addOperation(httpMethod, sourceOperation.clone());\n                } else if (operation.getMeta() != null) {\n                    LOG.internalWarn(\n                            \"Operation already exists, path='{}', httpMethod='{}', method={}\",\n                            path,\n                            httpMethod,\n                            sourceOperation.getMeta());\n                }\n            }\n        }\n\n        if (target.getServers() == null) {\n            List<Server> sourceServers = source.getServers();\n            if (sourceServers != null) {\n                target.setServers(Node.clone(sourceServers));\n            }\n        }\n\n        List<Parameter> sourceParameters = source.getParameters();\n        if (sourceParameters != null) {\n            if (target.getParameters() == null) {\n                target.setParameters(Node.clone(sourceParameters));\n            } else {\n                for (Parameter parameter : sourceParameters) {\n                    target.addParameter(parameter.clone());\n                }\n            }\n        }\n\n        target.addExtensions(source.getExtensions());\n    }\n\n    private static boolean isServiceNotMatch(String apiService, String[] services) {\n        if (apiService == null || services == null) {\n            return false;\n        }\n        for (String service : services) {\n            if (apiService.regionMatches(true, 0, service, 0, service.length())) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private static boolean isGroupNotMatch(String group, String sourceGroup) {\n        return !(sourceGroup == null && Constants.DEFAULT_GROUP.equals(group)\n                || Constants.ALL_GROUP.equals(group)\n                || group.equals(sourceGroup));\n    }\n\n    private static boolean isVersionNotMatch(String version, String sourceVersion) {\n        return !(version == null || sourceVersion == null || Helper.isVersionGreaterOrEqual(sourceVersion, version));\n    }\n\n    private static boolean isTagNotMatch(String[] tags, Set<String> operationTags) {\n        if (tags == null || operationTags == null) {\n            return false;\n        }\n        for (String tag : tags) {\n            if (operationTags.contains(tag)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private void mergeSecuritySchemes(OpenAPI target, OpenAPI source) {\n        Components sourceComponents = source.getComponents();\n        if (sourceComponents == null) {\n            return;\n        }\n\n        Map<String, SecurityScheme> sourceSecuritySchemes = sourceComponents.getSecuritySchemes();\n        if (sourceSecuritySchemes == null) {\n            return;\n        }\n\n        Components components = target.getComponents();\n        Map<String, SecurityScheme> securitySchemes = components.getSecuritySchemes();\n        if (securitySchemes == null) {\n            components.setSecuritySchemes(Node.clone(sourceSecuritySchemes));\n        } else {\n            for (Entry<String, SecurityScheme> entry : sourceSecuritySchemes.entrySet()) {\n                securitySchemes.computeIfAbsent(\n                        entry.getKey(), k -> entry.getValue().clone());\n            }\n        }\n    }\n\n    private void mergeTags(OpenAPI target, OpenAPI source) {\n        List<Tag> sourceTags = source.getTags();\n        if (sourceTags == null) {\n            return;\n        }\n\n        if (target.getTags() == null) {\n            target.setTags(Node.clone(sourceTags));\n        } else {\n            for (Tag tag : sourceTags) {\n                target.addTag(tag.clone());\n            }\n        }\n    }\n\n    private void addSchemas(OpenAPI target, String version, String group) {\n        Map<String, PathItem> paths = target.getPaths();\n        if (paths == null) {\n            return;\n        }\n        Map<Schema, Schema> schemas = new IdentityHashMap<>();\n        for (PathItem pathItem : paths.values()) {\n            Map<HttpMethods, Operation> operations = pathItem.getOperations();\n            if (operations == null) {\n                continue;\n            }\n            for (Operation operation : operations.values()) {\n                List<Parameter> parameters = operation.getParameters();\n                if (parameters != null) {\n                    for (Parameter parameter : parameters) {\n                        addSchema(parameter.getSchema(), schemas, group, version);\n                        Map<String, MediaType> contents = parameter.getContents();\n                        if (contents == null) {\n                            continue;\n                        }\n                        for (MediaType content : contents.values()) {\n                            addSchema(content.getSchema(), schemas, group, version);\n                        }\n                    }\n                }\n                RequestBody requestBody = operation.getRequestBody();\n                if (requestBody != null) {\n                    Map<String, MediaType> contents = requestBody.getContents();\n                    if (contents == null) {\n                        continue;\n                    }\n                    for (MediaType content : contents.values()) {\n                        addSchema(content.getSchema(), schemas, group, version);\n                    }\n                }\n                Map<String, ApiResponse> responses = operation.getResponses();\n                if (responses != null) {\n                    for (ApiResponse response : responses.values()) {\n                        Map<String, Header> headers = response.getHeaders();\n                        if (headers != null) {\n                            for (Header header : headers.values()) {\n                                addSchema(header.getSchema(), schemas, group, version);\n                            }\n                        }\n\n                        Map<String, MediaType> contents = response.getContents();\n                        if (contents == null) {\n                            continue;\n                        }\n                        for (MediaType content : contents.values()) {\n                            addSchema(content.getSchema(), schemas, group, version);\n                        }\n                    }\n                }\n            }\n        }\n\n        Components components = target.getComponents();\n        if (components == null) {\n            target.setComponents(components = new Components());\n        }\n\n        Set<String> names = CollectionUtils.newHashSet(schemas.size());\n        for (Schema schema : schemas.keySet()) {\n            String name = schema.getName();\n            if (name != null) {\n                names.add(name);\n            }\n        }\n\n        OpenAPINamingStrategy strategy = getNamingStrategy();\n        for (Schema schema : schemas.values()) {\n            String name = schema.getName();\n            if (name == null) {\n                Class<?> clazz = schema.getJavaType();\n                name = strategy.generateSchemaName(clazz, target);\n                for (int i = 1; i < 100; i++) {\n                    if (names.contains(name)) {\n                        name = strategy.resolveSchemaNameConflict(i, name, clazz, target);\n                    } else {\n                        names.add(name);\n                        break;\n                    }\n                }\n                schema.setName(name);\n            }\n\n            for (Schema sourceSchema : schema.getSourceSchemas()) {\n                sourceSchema.setTargetSchema(schema);\n                sourceSchema.setRef(\"#/components/schemas/\" + name);\n            }\n            schema.setSourceSchemas(null);\n            components.addSchema(name, schema);\n        }\n    }\n\n    private void addSchema(Schema schema, Map<Schema, Schema> schemas, String group, String version) {\n        if (schema == null) {\n            return;\n        }\n\n        addSchema(schema.getItems(), schemas, group, version);\n\n        Map<String, Schema> properties = schema.getProperties();\n        if (properties != null) {\n            Iterator<Entry<String, Schema>> it = properties.entrySet().iterator();\n            while (it.hasNext()) {\n                Entry<String, Schema> entry = it.next();\n                Schema property = entry.getValue();\n                if (isGroupNotMatch(group, property.getGroup()) || isVersionNotMatch(version, property.getVersion())) {\n                    it.remove();\n                    continue;\n                }\n                addSchema(property, schemas, group, version);\n            }\n        }\n\n        addSchema(schema.getAdditionalPropertiesSchema(), schemas, group, version);\n\n        List<Schema> allOf = schema.getAllOf();\n        if (allOf != null) {\n            for (Schema item : allOf) {\n                addSchema(item, schemas, group, version);\n            }\n        }\n\n        List<Schema> oneOf = schema.getOneOf();\n        if (oneOf != null) {\n            for (Schema item : oneOf) {\n                addSchema(item, schemas, group, version);\n            }\n        }\n\n        List<Schema> anyOf = schema.getAnyOf();\n        if (anyOf != null) {\n            for (Schema item : anyOf) {\n                addSchema(item, schemas, group, version);\n            }\n        }\n\n        addSchema(schema.getNot(), schemas, group, version);\n\n        Schema targetSchema = schema.getTargetSchema();\n        if (targetSchema == null) {\n            return;\n        }\n\n        targetSchema.addSourceSchema(schema);\n\n        Schema newSchema = schemas.get(targetSchema);\n        if (newSchema == null) {\n            newSchema = targetSchema.clone();\n            schemas.put(targetSchema, newSchema);\n            addSchema(newSchema, schemas, group, version);\n        }\n    }\n\n    private void completeOperations(OpenAPI target) {\n        Map<String, PathItem> paths = target.getPaths();\n        if (paths == null) {\n            return;\n        }\n\n        Set<String> allOperationIds = new HashSet<>(32);\n        Set<String> allTags = new HashSet<>(32);\n        target.walkOperations(operation -> {\n            String operationId = operation.getOperationId();\n            if (operationId != null) {\n                allOperationIds.add(operationId);\n            }\n            Set<String> tags = operation.getTags();\n            if (tags != null) {\n                allTags.addAll(tags);\n            }\n        });\n\n        OpenAPINamingStrategy strategy = getNamingStrategy();\n        target.walkOperations(operation -> {\n            String id = operation.getOperationId();\n            if (id != null) {\n                return;\n            }\n            id = strategy.generateOperationId(operation.getMeta(), target);\n            for (int i = 1; i < 100; i++) {\n                if (allOperationIds.contains(id)) {\n                    id = strategy.resolveOperationIdConflict(i, id, operation.getMeta(), target);\n                } else {\n                    allOperationIds.add(id);\n                    break;\n                }\n            }\n            operation.setOperationId(id);\n        });\n\n        List<Tag> tags = target.getTags();\n        if (tags != null) {\n            ListIterator<Tag> it = tags.listIterator();\n            while (it.hasNext()) {\n                if (allTags.contains(it.next().getName())) {\n                    continue;\n                }\n                it.remove();\n            }\n        }\n    }\n\n    private void completeModel(OpenAPI target) {\n        Info info = target.getInfo();\n        if (info.getTitle() == null) {\n            info.setTitle(\"Dubbo OpenAPI\");\n        }\n        if (info.getVersion() == null) {\n            info.setVersion(\"v1\");\n        }\n        if (CollectionUtils.isEmptyMap(target.getPaths())) {\n            return;\n        }\n        ExternalDocs docs = target.getExternalDocs();\n        if (docs.getUrl() == null && docs.getDescription() == null) {\n            docs.setUrl(\"../redoc/index.html?group=\" + target.getGroup()).setDescription(\"ReDoc\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.FluentLogger;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.nested.OpenAPIConfig;\nimport org.apache.dubbo.remoting.http12.ErrorResponse;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.HttpUtils;\nimport org.apache.dubbo.remoting.http12.message.MediaType;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.MethodsCondition;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathCondition;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver.OpenAPIChain;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver.OperationChain;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver.OperationContext;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nfinal class DefinitionResolver {\n\n    private static final FluentLogger LOG = FluentLogger.of(DefinitionResolver.class);\n\n    private final ExtensionFactory extensionFactory;\n    private final ConfigFactory configFactory;\n    private final SchemaResolver schemaResolver;\n    private final OpenAPIDefinitionResolver[] resolvers;\n\n    DefinitionResolver(FrameworkModel frameworkModel) {\n        extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class);\n        configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class);\n        schemaResolver = frameworkModel.getOrRegisterBean(SchemaResolver.class);\n        resolvers = extensionFactory.getExtensions(OpenAPIDefinitionResolver.class);\n    }\n\n    public OpenAPI resolve(ServiceMeta serviceMeta, Collection<List<Registration>> registrationsByMethod) {\n        OpenAPI definition = new OpenAPIChainImpl(resolvers, openAPI -> {\n                    if (StringUtils.isEmpty(openAPI.getGroup())) {\n                        openAPI.setGroup(Constants.DEFAULT_GROUP);\n                    }\n                    openAPI.setConfig(configFactory.getConfig(openAPI.getGroup()));\n                    String service = serviceMeta.getServiceInterface();\n                    int index = service.lastIndexOf('.');\n                    String tagName = index == -1 ? service : service.substring(index + 1);\n                    openAPI.addTag(new Tag().setName(tagName).setDescription(service));\n                    return openAPI;\n                })\n                .resolve(\n                        new OpenAPI().setMeta(serviceMeta).setGlobalConfig(configFactory.getGlobalConfig()),\n                        serviceMeta);\n        if (definition == null) {\n            return null;\n        }\n        if (definition.getConfig() == null) {\n            definition.setConfig(configFactory.getConfig(definition.getGroup()));\n        }\n\n        if (CollectionUtils.isEmpty(definition.getServers())) {\n            URL url = serviceMeta.getUrl();\n            definition.addServer(new Server()\n                    .setUrl(\"http://\" + url.getHost() + ':' + url.getPort())\n                    .setDescription(Constants.DUBBO_DEFAULT_SERVER));\n        }\n\n        OperationContext context = new OperationContextImpl(definition, schemaResolver, extensionFactory);\n        for (List<Registration> registrations : registrationsByMethod) {\n            String mainPath = null;\n            for (Registration registration : registrations) {\n                RequestMapping mapping = registration.getMapping();\n                PathCondition pathCondition = mapping.getPathCondition();\n                if (pathCondition == null) {\n                    continue;\n                }\n                for (PathExpression expression : pathCondition.getExpressions()) {\n                    String path = expression.toString();\n                    PathItem pathItem = definition.getOrAddPath(path);\n                    String ref = pathItem.getRef();\n                    if (ref != null) {\n                        path = ref;\n                        pathItem = definition.getOrAddPath(path);\n                    }\n                    if (mainPath != null && expression.isDirect()) {\n                        pathItem.setRef(mainPath);\n                        continue;\n                    }\n                    MethodMeta methodMeta = registration.getMeta().getMethod();\n                    if (resolvePath(path, pathItem, definition, methodMeta, mapping, context)) {\n                        mainPath = path;\n                    }\n                }\n            }\n        }\n\n        return definition;\n    }\n\n    private boolean resolvePath(\n            String path,\n            PathItem pathItem,\n            OpenAPI openAPI,\n            MethodMeta methodMeta,\n            RequestMapping mapping,\n            OperationContext context) {\n        Collection<HttpMethods> httpMethods = null;\n        for (OpenAPIDefinitionResolver resolver : resolvers) {\n            httpMethods = resolver.resolve(pathItem, methodMeta, context);\n            if (httpMethods != null) {\n                break;\n            }\n        }\n        if (httpMethods == null) {\n            httpMethods = new LinkedList<>();\n            for (String method : determineHttpMethods(openAPI, methodMeta, mapping)) {\n                httpMethods.add(HttpMethods.of(method.toUpperCase()));\n            }\n        }\n\n        boolean added = false;\n        for (HttpMethods httpMethod : httpMethods) {\n            Operation operation = new Operation().setMeta(methodMeta);\n            Operation existingOperation = pathItem.getOperation(httpMethod);\n            if (existingOperation != null && existingOperation.getMeta() != null) {\n                LOG.internalWarn(\n                        \"Operation already exists, path='{}', httpMethod='{}', method={}\",\n                        path,\n                        httpMethod,\n                        methodMeta);\n                continue;\n            }\n            operation = new OperationChainImpl(\n                            resolvers, op -> resolveOperation(path, httpMethod, op, openAPI, methodMeta, mapping))\n                    .resolve(operation, methodMeta, context);\n            if (operation != null) {\n                pathItem.addOperation(httpMethod, operation);\n                added = true;\n            }\n        }\n        return added;\n    }\n\n    private Collection<String> determineHttpMethods(OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) {\n        Collection<String> httpMethods = null;\n        MethodsCondition condition = mapping.getMethodsCondition();\n        if (condition != null) {\n            httpMethods = condition.getMethods();\n        }\n        if (httpMethods == null) {\n            String[] defaultHttpMethods = openAPI.getConfigValue(OpenAPIConfig::getDefaultHttpMethods);\n            if (defaultHttpMethods == null) {\n                httpMethods = Helper.guessHttpMethod(meta);\n            } else {\n                httpMethods = Arrays.asList(defaultHttpMethods);\n            }\n        }\n        return httpMethods;\n    }\n\n    private Operation resolveOperation(\n            String path,\n            HttpMethods httpMethod,\n            Operation operation,\n            OpenAPI openAPI,\n            MethodMeta meta,\n            RequestMapping mapping) {\n        if (operation.getGroup() == null) {\n            operation.setGroup(openAPI.getGroup());\n        }\n        for (Tag tag : openAPI.getTags()) {\n            operation.addTag(tag.getName());\n        }\n        if (operation.getDeprecated() == null && meta.isHierarchyAnnotated(Deprecated.class)) {\n            operation.setDeprecated(true);\n        }\n\n        ServiceMeta serviceMeta = meta.getServiceMeta();\n        if (serviceMeta.getServiceVersion() != null) {\n            operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_GROUP.getName(), In.HEADER)\n                    .setSchema(PrimitiveSchema.STRING.newSchema()));\n        }\n        if (serviceMeta.getServiceGroup() != null) {\n            operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_VERSION.getName(), In.HEADER)\n                    .setSchema(PrimitiveSchema.STRING.newSchema()));\n        }\n\n        List<String> variables = Helper.extractVariables(path);\n        if (variables != null) {\n            for (String variable : variables) {\n                Parameter parameter = operation.getParameter(variable, In.PATH);\n                if (parameter == null) {\n                    parameter = new Parameter(variable, In.PATH);\n                    operation.addParameter(parameter);\n                }\n                parameter.setRequired(true);\n                if (parameter.getSchema() == null) {\n                    parameter.setSchema(PrimitiveSchema.STRING.newSchema());\n                }\n            }\n        }\n\n        for (ParameterMeta paramMeta : meta.getParameters()) {\n            resolveParameter(httpMethod, operation, paramMeta, true);\n        }\n\n        if (httpMethod.supportBody()) {\n            RequestBody body = operation.getRequestBody();\n            if (body == null) {\n                body = new RequestBody();\n                operation.setRequestBody(body);\n            }\n            if (CollectionUtils.isEmptyMap(body.getContents())) {\n                resolveRequestBody(body, openAPI, meta, mapping);\n            }\n        }\n\n        if (CollectionUtils.isEmptyMap(operation.getResponses())) {\n            String[] httpStatusCodes = openAPI.getConfigValue(OpenAPIConfig::getDefaultHttpStatusCodes);\n            if (httpStatusCodes == null) {\n                httpStatusCodes = new String[] {\"200\", \"400\", \"500\"};\n            }\n            for (String httpStatusCode : httpStatusCodes) {\n                ApiResponse response = operation.getOrAddResponse(httpStatusCode);\n                resolveResponse(httpStatusCode, response, openAPI, meta, mapping);\n            }\n        }\n        return operation;\n    }\n\n    private void resolveParameter(HttpMethods httpMethod, Operation operation, ParameterMeta meta, boolean traverse) {\n        String name = meta.getName();\n        if (name == null) {\n            return;\n        }\n\n        NamedValueMeta valueMeta = meta.getNamedValueMeta();\n        ParamType paramType = valueMeta.paramType();\n        if (paramType == null) {\n            if (httpMethod.supportBody()) {\n                return;\n            }\n            paramType = ParamType.Param;\n        }\n        In in = Helper.toIn(paramType);\n        if (in == null) {\n            return;\n        }\n\n        boolean simple = meta.isSimple();\n        if (in != In.QUERY && !simple) {\n            return;\n        }\n        if (simple) {\n            Parameter parameter = operation.getParameter(name, in);\n            if (parameter == null) {\n                parameter = new Parameter(name, in);\n                operation.addParameter(parameter);\n            }\n            if (parameter.getRequired() == null) {\n                parameter.setRequired(valueMeta.required());\n            }\n            Schema schema = parameter.getSchema();\n            if (schema == null) {\n                parameter.setSchema(schema = schemaResolver.resolve(meta));\n            }\n            if (schema.getDefaultValue() == null) {\n                schema.setDefaultValue(valueMeta.defaultValue());\n            }\n            parameter.setMeta(meta);\n            return;\n        }\n        if (!traverse) {\n            return;\n        }\n\n        BeanMeta beanMeta = meta.getBeanMeta();\n        try {\n            for (ParameterMeta ctorParam : beanMeta.getConstructor().getParameters()) {\n                resolveParameter(httpMethod, operation, ctorParam, false);\n            }\n        } catch (Throwable ignored) {\n        }\n        for (PropertyMeta property : beanMeta.getProperties()) {\n            if ((property.getVisibility() & 0b001) == 0) {\n                continue;\n            }\n            resolveParameter(httpMethod, operation, property, false);\n        }\n    }\n\n    private void resolveRequestBody(RequestBody body, OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) {\n        Collection<MediaType> mediaTypes = null;\n        if (mapping.getConsumesCondition() != null) {\n            mediaTypes = mapping.getConsumesCondition().getMediaTypes();\n        }\n        if (mediaTypes == null) {\n            String[] defaultMediaTypes = openAPI.getConfigValue(OpenAPIConfig::getDefaultConsumesMediaTypes);\n            if (defaultMediaTypes == null) {\n                mediaTypes = Collections.singletonList(MediaType.APPLICATION_JSON);\n            } else {\n                mediaTypes = Arrays.stream(defaultMediaTypes).map(MediaType::of).collect(Collectors.toList());\n            }\n        }\n        out:\n        for (MediaType mediaType : mediaTypes) {\n            org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType content =\n                    body.getOrAddContent(mediaType.getName());\n            if (content.getSchema() == null) {\n                for (ParameterMeta paramMeta : meta.getParameters()) {\n                    ParamType paramType = paramMeta.getNamedValueMeta().paramType();\n                    if (paramType == ParamType.Body) {\n                        content.setSchema(schemaResolver.resolve(paramMeta));\n                        continue out;\n                    }\n                }\n\n                List<ParameterMeta> paramMetas = new ArrayList<>();\n                for (ParameterMeta paramMeta : meta.getParameters()) {\n                    if (paramMeta.getNamedValueMeta().paramType() == null) {\n                        paramMetas.add(paramMeta);\n                    }\n                }\n                int size = paramMetas.size();\n                if (size == 0) {\n                    continue;\n                }\n                if (size == 1) {\n                    content.setSchema(schemaResolver.resolve(paramMetas.get(0)));\n                } else {\n                    content.setSchema(schemaResolver.resolve(paramMetas));\n                }\n            }\n        }\n    }\n\n    private void resolveResponse(\n            String httpStatusCode, ApiResponse response, OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) {\n        int httpStatus = Integer.parseInt(httpStatusCode);\n        if (response.getDescription() == null) {\n            response.setDescription(HttpUtils.getStatusMessage(httpStatus));\n        }\n        if (httpStatus > 201 && httpStatus < 400) {\n            return;\n        }\n        if (meta.getActualReturnType() == void.class) {\n            return;\n        }\n\n        Collection<MediaType> mediaTypes = null;\n        if (mapping.getProducesCondition() != null) {\n            mediaTypes = mapping.getProducesCondition().getMediaTypes();\n        }\n        if (mediaTypes == null) {\n            String[] defaultMediaTypes = openAPI.getConfigValue(OpenAPIConfig::getDefaultProducesMediaTypes);\n            if (defaultMediaTypes == null) {\n                mediaTypes = Collections.singletonList(MediaType.APPLICATION_JSON);\n            } else {\n                mediaTypes = Arrays.stream(defaultMediaTypes).map(MediaType::of).collect(Collectors.toList());\n            }\n        }\n        for (MediaType mediaType : mediaTypes) {\n            org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType content =\n                    response.getOrAddContent(mediaType.getName());\n            if (content.getSchema() == null) {\n                if (httpStatus >= 400) {\n                    content.setSchema(schemaResolver.resolve(ErrorResponse.class));\n                } else {\n                    content.setSchema(schemaResolver.resolve(meta.getReturnParameter()));\n                }\n            }\n        }\n    }\n\n    private static final class OperationContextImpl extends AbstractContext implements OperationContext {\n\n        OperationContextImpl(OpenAPI openAPI, SchemaResolver schemaResolver, ExtensionFactory extensionFactory) {\n            super(openAPI, schemaResolver, extensionFactory);\n        }\n    }\n\n    private static final class OpenAPIChainImpl implements OpenAPIChain {\n\n        private final OpenAPIDefinitionResolver[] resolvers;\n        private final Function<OpenAPI, OpenAPI> fallback;\n        private int cursor;\n\n        OpenAPIChainImpl(OpenAPIDefinitionResolver[] resolvers, Function<OpenAPI, OpenAPI> fallback) {\n            this.resolvers = resolvers;\n            this.fallback = fallback;\n        }\n\n        @Override\n        public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta) {\n            if (cursor < resolvers.length) {\n                return resolvers[cursor++].resolve(openAPI, serviceMeta, this);\n            }\n            return fallback.apply(openAPI);\n        }\n    }\n\n    private static final class OperationChainImpl implements OperationChain {\n\n        private final OpenAPIDefinitionResolver[] resolvers;\n        private final Function<Operation, Operation> fallback;\n        private int cursor;\n\n        OperationChainImpl(OpenAPIDefinitionResolver[] resolvers, Function<Operation, Operation> fallback) {\n            this.resolvers = resolvers;\n            this.fallback = fallback;\n        }\n\n        @Override\n        public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext chain) {\n            if (cursor < resolvers.length) {\n                return resolvers[cursor++].resolve(operation, methodMeta, chain, this);\n            }\n            return fallback.apply(operation);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Pair;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\n@SuppressWarnings(\"unchecked\")\npublic final class ExtensionFactory {\n\n    private final ExtensionLoader<OpenAPIExtension> extensionLoader;\n    private final List<OpenAPIExtension> extensions;\n    private final Map<Object, Object> cache;\n\n    public ExtensionFactory(FrameworkModel frameworkModel) {\n        extensionLoader = frameworkModel.getExtensionLoader(OpenAPIExtension.class);\n        extensions = extensionLoader.getActivateExtensions();\n        cache = CollectionUtils.newConcurrentHashMap();\n    }\n\n    public <T extends OpenAPIExtension> boolean hasExtensions(Class<T> type) {\n        return getExtensions(type).length > 0;\n    }\n\n    public <T extends OpenAPIExtension> T[] getExtensions(Class<T> type) {\n        return (T[]) cache.computeIfAbsent(type, k -> {\n            List<OpenAPIExtension> list = new ArrayList<>();\n            for (OpenAPIExtension extension : extensions) {\n                if (extension instanceof Supplier) {\n                    extension = ((Supplier<T>) extension).get();\n                }\n                if (type.isInstance(extension)) {\n                    list.add(extension);\n                }\n            }\n            return list.toArray((T[]) Array.newInstance(type, list.size()));\n        });\n    }\n\n    public <T extends OpenAPIExtension> T[] getExtensions(Class<T> type, String group) {\n        if (group == null) {\n            return getExtensions(type);\n        }\n        return (T[]) cache.computeIfAbsent(Pair.of(type, group), k -> {\n            List<OpenAPIExtension> list = new ArrayList<>();\n            for (OpenAPIExtension extension : extensions) {\n                if (extension instanceof Supplier) {\n                    extension = ((Supplier<T>) extension).get();\n                }\n                if (type.isInstance(extension) && accept(extension, group)) {\n                    list.add(extension);\n                }\n            }\n            return list.toArray((T[]) Array.newInstance(type, list.size()));\n        });\n    }\n\n    public <T extends OpenAPIExtension> T getExtension(Class<T> type, String name) {\n        OpenAPIExtension extension = extensionLoader.getExtension(name, true);\n        if (extension instanceof Supplier) {\n            extension = ((Supplier<T>) extension).get();\n        }\n        return type.isInstance(extension) ? (T) extension : null;\n    }\n\n    private static boolean accept(OpenAPIExtension extension, String group) {\n        String[] groups = extension.getGroups();\n        return groups == null || groups.length == 0 || Arrays.asList(groups).contains(group);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport static org.apache.dubbo.remoting.http12.HttpMethods.DELETE;\nimport static org.apache.dubbo.remoting.http12.HttpMethods.GET;\nimport static org.apache.dubbo.remoting.http12.HttpMethods.PATCH;\nimport static org.apache.dubbo.remoting.http12.HttpMethods.POST;\nimport static org.apache.dubbo.remoting.http12.HttpMethods.PUT;\n\npublic final class Helper {\n\n    private static final String[][] VERBS_TABLE = {\n        {\n            GET.name(),\n            \"get\",\n            \"load\",\n            \"fetch\",\n            \"read\",\n            \"retrieve\",\n            \"obtain\",\n            \"list\",\n            \"find\",\n            \"query\",\n            \"search\",\n            \"is\",\n            \"are\",\n            \"was\",\n            \"has\",\n            \"check\",\n            \"verify\",\n            \"test\",\n            \"can\",\n            \"should\",\n            \"need\",\n            \"allow\",\n            \"support\",\n            \"accept\"\n        },\n        {PUT.name(), \"put\", \"replace\"},\n        {PATCH.name(), \"patch\", \"update\", \"modify\", \"edit\", \"change\", \"set\"},\n        {DELETE.name(), \"delete\", \"remove\", \"erase\", \"destroy\", \"drop\"}\n    };\n\n    private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile(\"\\\\{\\\\{([\\\\w.-]+)}}\");\n\n    private Helper() {}\n\n    public static Collection<String> guessHttpMethod(MethodMeta method) {\n        String name = method.getMethod().getName();\n        for (String[] verbs : VERBS_TABLE) {\n            for (int i = 1, len = verbs.length; i < len; i++) {\n                if (name.startsWith(verbs[i])) {\n                    String httpMethod = verbs[0];\n                    if (GET.name().equals(httpMethod)) {\n                        for (ParameterMeta parameter : method.getParameters()) {\n                            ParamType paramType = parameter.getNamedValueMeta().paramType();\n                            if (paramType == null) {\n                                if (parameter.isSimple()) {\n                                    continue;\n                                }\n                                return Arrays.asList(GET.name(), POST.name());\n                            } else {\n                                switch (paramType) {\n                                    case Form:\n                                    case Part:\n                                    case Body:\n                                        return Collections.singletonList(POST.name());\n                                    default:\n                                }\n                            }\n                        }\n                    }\n                    return Collections.singletonList(httpMethod);\n                }\n            }\n        }\n        return Collections.singletonList(POST.name());\n    }\n\n    public static List<String> extractVariables(String path) {\n        List<String> variables = null;\n        for (int i = 0, len = path.length(), start = 0; i < len; i++) {\n            char c = path.charAt(i);\n            if (c == '{') {\n                start = i + 1;\n            } else if (start > 0 && c == '}') {\n                if (variables == null) {\n                    variables = new ArrayList<>();\n                }\n                variables.add(path.substring(start, i));\n                start = 0;\n            }\n        }\n        return variables;\n    }\n\n    public static In toIn(ParamType paramType) {\n        switch (paramType) {\n            case PathVariable:\n                return In.PATH;\n            case Param:\n                return In.QUERY;\n            case Header:\n                return In.HEADER;\n            case Cookie:\n                return In.COOKIE;\n            default:\n                return null;\n        }\n    }\n\n    public static String formatSpecVersion(String version) {\n        if (version == null) {\n            return null;\n        }\n        if (version.startsWith(\"3.1\")) {\n            return Constants.VERSION_31;\n        }\n        return Constants.VERSION_30;\n    }\n\n    public static OpenAPIRequest formatRequest(OpenAPIRequest request) {\n        if (request == null) {\n            return new OpenAPIRequest();\n        }\n        request.setGroup(trim(request.getGroup()));\n        request.setVersion(trim(request.getVersion()));\n\n        String[] tag = trim(request.getTag());\n        if (tag != null) {\n            Arrays.sort(tag);\n        }\n        request.setTag(tag);\n\n        String[] service = trim(request.getService());\n        if (service != null) {\n            Arrays.sort(service);\n        }\n        request.setService(service);\n\n        request.setOpenapi(trim(request.getOpenapi()));\n        request.setFormat(trim(request.getFormat()));\n        return request;\n    }\n\n    public static String parseFormat(String contentType) {\n        if (contentType != null) {\n            int index = contentType.indexOf('/');\n            if (index > 0 && contentType.indexOf(\"htm\", index) == -1) {\n                return contentType.substring(index + 1);\n            }\n        }\n        return \"json\";\n    }\n\n    public static String trim(String str) {\n        if (str == null || str.isEmpty()) {\n            return null;\n        }\n        str = str.trim();\n        return str.isEmpty() ? null : str;\n    }\n\n    public static String[] trim(String[] array) {\n        if (array == null) {\n            return null;\n        }\n        int len = array.length;\n        if (len == 0) {\n            return null;\n        }\n        int p = 0;\n        for (int i = 0; i < len; i++) {\n            String value = trim(array[i]);\n            if (value != null) {\n                array[p++] = value;\n            }\n        }\n        int newLen = p;\n        return newLen == len ? array : Arrays.copyOf(array, newLen);\n    }\n\n    public static Map<String, String> toProperties(String[] array) {\n        if (array == null) {\n            return Collections.emptyMap();\n        }\n        int len = array.length;\n        if (len == 0) {\n            return Collections.emptyMap();\n        }\n        Map<String, String> properties = CollectionUtils.newLinkedHashMap(len);\n        for (String item : array) {\n            int index = item.indexOf('=');\n            if (index > 0) {\n                properties.put(trim(item.substring(0, index)), trim(item.substring(index + 1)));\n            } else {\n                properties.put(trim(item), null);\n            }\n        }\n        return properties;\n    }\n\n    public static Server parseServer(String server) {\n        String url = null;\n        String description = null;\n        int equalIndex = server.indexOf('=');\n        if (equalIndex > 0) {\n            int index = server.indexOf(\"://\");\n            if (index == -1 || index > equalIndex) {\n                url = trim(server.substring(equalIndex + 1));\n                description = trim(server.substring(0, equalIndex));\n            }\n        }\n        if (url == null) {\n            url = trim(server);\n        }\n        return new Server().setDescription(description).setUrl(url);\n    }\n\n    public static void setValue(Supplier<String> getter, Consumer<String> setter) {\n        String value = trim(getter.get());\n        if (value != null) {\n            setter.accept(value);\n        }\n    }\n\n    public static void setBoolValue(Supplier<String> getter, Consumer<Boolean> setter) {\n        String value = trim(getter.get());\n        if (value != null) {\n            setter.accept(StringUtils.toBoolean(value));\n        }\n    }\n\n    public static void setValue(AnnotationMeta<?> schema, String key, Consumer<String> setter) {\n        String value = trim(schema.getString(key));\n        if (value != null) {\n            setter.accept(value);\n        }\n    }\n\n    public static void setBoolValue(AnnotationMeta<?> schema, String key, Consumer<Boolean> setter) {\n        Boolean value = schema.getBoolean(key);\n        if (Boolean.TRUE.equals(value)) {\n            setter.accept(true);\n        }\n    }\n\n    public static String pathToRef(String path) {\n        StringBuilder sb = new StringBuilder(path.length() + 16);\n        sb.append(\"#/paths/\");\n        for (int i = 0, len = path.length(); i < len; i++) {\n            char c = path.charAt(i);\n            if (c == '/') {\n                sb.append('~').append('1');\n            } else if (c == '~') {\n                sb.append('~').append('0');\n            } else {\n                sb.append(c);\n            }\n        }\n        return sb.toString();\n    }\n\n    public static boolean isVersionGreaterOrEqual(String version1, String version2) {\n        int i = 0, j = 0, len1 = version1.length(), len2 = version2.length();\n        while (i < len1 || j < len2) {\n            int num1 = 0;\n            while (i < len1) {\n                char c = version1.charAt(i);\n                if (Character.isDigit(c)) {\n                    num1 = num1 * 10 + (c - '0');\n                } else if (c == '.' || c == '-' || c == '_') {\n                    i++;\n                    break;\n                }\n                i++;\n            }\n\n            int num2 = 0;\n            while (j < len2) {\n                char c = version2.charAt(j);\n                if (Character.isDigit(c)) {\n                    num2 = num2 * 10 + (c - '0');\n                } else if (c == '.' || c == '-' || c == '_') {\n                    j++;\n                    break;\n                }\n                j++;\n            }\n\n            if (num1 < num2) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public static String render(String text, Function<String, String> fn) {\n        if (text == null) {\n            return null;\n        }\n        Matcher matcher = PLACEHOLDER_PATTERN.matcher(text);\n        StringBuffer result = new StringBuffer(text.length());\n        while (matcher.find()) {\n            String value = fn.apply(matcher.group(1));\n            matcher.appendReplacement(result, value == null ? StringUtils.EMPTY_STRING : value);\n        }\n        matcher.appendTail(result);\n        return result.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem;\n\nimport java.util.Collection;\n\npublic interface OpenAPIDefinitionResolver extends OpenAPIExtension {\n\n    OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain);\n\n    Collection<HttpMethods> resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context);\n\n    Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext context, OperationChain chain);\n\n    interface OpenAPIChain {\n\n        OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta);\n    }\n\n    interface OperationChain {\n\n        Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext context);\n    }\n\n    interface OperationContext {\n\n        String getGroup();\n\n        OpenAPI getOpenAPI();\n\n        SchemaResolver getSchemaResolver();\n\n        ExtensionFactory getExtensionFactory();\n\n        <T> T getAttribute(String name);\n\n        <T> T removeAttribute(String name);\n\n        void setAttribute(String name, Object value);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.utils.Pair;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\n\nimport java.util.function.Function;\n\npublic interface OpenAPIDocumentPublisher extends OpenAPIExtension {\n\n    void publish(Function<OpenAPIRequest, Pair<OpenAPI, String>> fn);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface OpenAPIExtension {\n\n    default String[] getGroups() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Header;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Node;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme;\n\npublic interface OpenAPIFilter extends OpenAPIExtension {\n\n    default OpenAPI filterOpenAPI(OpenAPI openAPI, Context context) {\n        return openAPI;\n    }\n\n    default PathItem filterPathItem(String key, PathItem pathItem, Context context) {\n        return pathItem;\n    }\n\n    default Operation filterOperation(HttpMethods key, Operation operation, PathItem pathItem, Context context) {\n        return operation;\n    }\n\n    default Parameter filterParameter(Parameter parameter, Operation operation, Context context) {\n        return parameter;\n    }\n\n    default RequestBody filterRequestBody(RequestBody body, Operation operation, Context context) {\n        return body;\n    }\n\n    default ApiResponse filterResponse(ApiResponse response, Operation operation, Context context) {\n        return response;\n    }\n\n    default Header filterHeader(Header header, ApiResponse response, Operation operation, Context context) {\n        return header;\n    }\n\n    default Schema filterSchema(Schema schema, Node<?> node, Context context) {\n        return schema;\n    }\n\n    default Schema filterSchemaProperty(String name, Schema schema, Schema owner, Context context) {\n        return schema;\n    }\n\n    default SecurityScheme filterSecurityScheme(SecurityScheme securityScheme, Context context) {\n        return securityScheme;\n    }\n\n    default OpenAPI filterOpenAPICompletion(OpenAPI openAPI, Context context) {\n        return openAPI;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\n\npublic interface OpenAPINamingStrategy extends OpenAPIExtension {\n\n    String generateOperationId(MethodMeta methodMeta, OpenAPI openAPI);\n\n    String resolveOperationIdConflict(int attempt, String operationId, MethodMeta methodMeta, OpenAPI openAPI);\n\n    String generateSchemaName(Class<?> clazz, OpenAPI openAPI);\n\n    String resolveSchemaNameConflict(int attempt, String schemaName, Class<?> clazz, OpenAPI openAPI);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.HttpResult;\n\npublic interface OpenAPIRequestHandler extends OpenAPIExtension {\n\n    default String[] getPaths() {\n        return StringUtils.EMPTY_STRING_ARRAY;\n    }\n\n    HttpResult<?> handle(String path, HttpRequest request, HttpResponse response);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\npublic interface OpenAPISchemaPredicate extends OpenAPIExtension {\n\n    default Boolean acceptClass(Class<?> clazz, ParameterMeta parameter) {\n        return null;\n    }\n\n    default Boolean acceptProperty(BeanMeta bean, PropertyMeta property) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\n\nimport java.lang.reflect.Type;\n\npublic interface OpenAPISchemaResolver extends OpenAPIExtension {\n\n    Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain);\n\n    interface SchemaChain {\n\n        Schema resolve(ParameterMeta parameter, SchemaContext context);\n    }\n\n    interface SchemaContext {\n\n        void defineSchema(Class<?> type, Schema schema);\n\n        Schema resolve(ParameterMeta parameter);\n\n        Schema resolve(Type type);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\n@Activate\npublic class OpenAPIScopeModelInitializer implements ScopeModelInitializer {\n\n    @Override\n    public void initializeFrameworkModel(FrameworkModel frameworkModel) {\n        frameworkModel.getBeanFactory().registerBeanDefinition(DefaultOpenAPIService.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Primitive Schema\n * Format: <a href=\"https://spec.openapis.org/registry/format/\">Formats Registry</a>\n */\npublic enum PrimitiveSchema {\n    STRING(String.class, Type.STRING),\n    BOOLEAN(Boolean.class, Type.BOOLEAN),\n    BYTE(Byte.class, Type.STRING, \"byte\"),\n    BINARY(Byte.class, Type.STRING, \"binary\"),\n    URI(java.net.URI.class, Type.STRING, \"uri\"),\n    URL(java.net.URL.class, Type.STRING, \"url\"),\n    EMAIL(String.class, Type.STRING, \"email\"),\n    PASSWORD(String.class, Type.STRING, \"password\"),\n    UUID(java.util.UUID.class, Type.STRING, \"uuid\"),\n    INT(Integer.class, Type.INTEGER, \"int32\"),\n    LONG(Long.class, Type.INTEGER, \"int64\"),\n    FLOAT(Float.class, Type.NUMBER, \"float\"),\n    DOUBLE(Double.class, Type.NUMBER, \"double\"),\n    INTEGER(java.math.BigInteger.class, Type.INTEGER),\n    DECIMAL(java.math.BigDecimal.class, Type.NUMBER, \"number\"),\n    NUMBER(Number.class, Type.NUMBER),\n    IP_V4(java.net.Inet4Address.class, Type.STRING, \"ipv4\"),\n    IP_V6(java.net.Inet6Address.class, Type.STRING, \"ipv6\"),\n    DATE_TIME(java.util.Date.class, Type.STRING, \"date-time\"),\n    DATE(java.time.LocalDate.class, Type.STRING, \"date\"),\n    TIME(java.time.LocalTime.class, Type.STRING, \"time\"),\n    DURATION(java.time.Duration.class, Type.STRING, \"duration\"),\n    FILE(java.io.File.class, Type.STRING, \"binary\"),\n    OBJECT(Object.class, Type.OBJECT),\n    ARRAY(Object[].class, Type.ARRAY);\n\n    private static final Map<Object, PrimitiveSchema> TYPE_MAPPING = new ConcurrentHashMap<>();\n\n    static {\n        for (PrimitiveSchema schema : values()) {\n            TYPE_MAPPING.putIfAbsent(schema.keyClass, schema);\n        }\n        TYPE_MAPPING.put(boolean.class, BOOLEAN);\n        TYPE_MAPPING.put(byte.class, BYTE);\n        TYPE_MAPPING.put(char.class, STRING);\n        TYPE_MAPPING.put(Character.class, STRING);\n        TYPE_MAPPING.put(short.class, INT);\n        TYPE_MAPPING.put(Short.class, INT);\n        TYPE_MAPPING.put(int.class, INT);\n        TYPE_MAPPING.put(long.class, LONG);\n        TYPE_MAPPING.put(float.class, FLOAT);\n        TYPE_MAPPING.put(double.class, DOUBLE);\n        TYPE_MAPPING.put(byte[].class, BYTE);\n\n        TYPE_MAPPING.put(java.util.Calendar.class, DATE_TIME);\n        TYPE_MAPPING.put(java.sql.Date.class, DATE_TIME);\n        TYPE_MAPPING.put(java.time.Instant.class, DATE_TIME);\n        TYPE_MAPPING.put(java.time.LocalDateTime.class, DATE_TIME);\n        TYPE_MAPPING.put(java.time.ZonedDateTime.class, DATE_TIME);\n        TYPE_MAPPING.put(java.time.OffsetDateTime.class, DATE_TIME);\n        TYPE_MAPPING.put(java.time.OffsetTime.class, TIME);\n        TYPE_MAPPING.put(java.time.Period.class, DURATION);\n        TYPE_MAPPING.put(\"javax.xml.datatype.XMLGregorianCalendar\", DATE_TIME);\n        TYPE_MAPPING.put(\"org.joda.time.LocalDateTime\", DATE_TIME);\n        TYPE_MAPPING.put(\"org.joda.time.ReadableDateTime\", DATE_TIME);\n        TYPE_MAPPING.put(\"org.joda.time.DateTime\", DATE_TIME);\n        TYPE_MAPPING.put(\"org.joda.time.LocalTime\", TIME);\n\n        TYPE_MAPPING.put(CharSequence.class, STRING);\n        TYPE_MAPPING.put(StringBuffer.class, STRING);\n        TYPE_MAPPING.put(StringBuilder.class, STRING);\n        TYPE_MAPPING.put(java.nio.charset.Charset.class, STRING);\n        TYPE_MAPPING.put(java.time.ZoneId.class, STRING);\n        TYPE_MAPPING.put(java.util.Currency.class, STRING);\n        TYPE_MAPPING.put(java.util.Locale.class, STRING);\n        TYPE_MAPPING.put(java.util.TimeZone.class, STRING);\n        TYPE_MAPPING.put(java.util.regex.Pattern.class, STRING);\n\n        TYPE_MAPPING.put(java.io.InputStream.class, BYTE);\n        TYPE_MAPPING.put(java.net.InetAddress.class, IP_V4);\n\n        TYPE_MAPPING.put(\"object\", OBJECT);\n    }\n\n    private final Class<?> keyClass;\n    private final Type type;\n    private final String format;\n\n    PrimitiveSchema(Class<?> keyClass, Type type, String format) {\n        this.keyClass = keyClass;\n        this.type = type;\n        this.format = format;\n    }\n\n    PrimitiveSchema(Class<?> keyClass, Type type) {\n        this.keyClass = keyClass;\n        this.type = type;\n        format = null;\n    }\n\n    public Schema newSchema() {\n        return new Schema().setType(type).setFormat(format);\n    }\n\n    public static Schema newSchemaOf(Class<?> type) {\n        PrimitiveSchema schema = TYPE_MAPPING.get(type);\n        if (schema == null) {\n            schema = TYPE_MAPPING.get(type.getName());\n        }\n        return schema == null ? null : schema.newSchema();\n    }\n\n    public static boolean isPrimitive(Class<?> type) {\n        return TYPE_MAPPING.containsKey(type);\n    }\n\n    public static void addTypeMapping(Object key, PrimitiveSchema schema) {\n        TYPE_MAPPING.put(key, schema);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\n\npublic final class ProtoEncoder {\n\n    public String encode(OpenAPI openAPI) {\n        return \"\";\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree.Match;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.TypeParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.SchemaChain;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.SchemaContext;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.basic.Annotations;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;\n\nimport java.lang.reflect.GenericArrayType;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.lang.reflect.WildcardType;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport static org.apache.dubbo.rpc.protocol.tri.rest.openapi.PrimitiveSchema.ARRAY;\nimport static org.apache.dubbo.rpc.protocol.tri.rest.openapi.PrimitiveSchema.OBJECT;\n\npublic final class SchemaResolver {\n\n    private final ConfigFactory configFactory;\n    private final OpenAPISchemaResolver[] resolvers;\n    private final OpenAPISchemaPredicate[] predicates;\n    private final Map<Class<?>, Schema> schemaMap = CollectionUtils.newConcurrentHashMap();\n\n    private volatile RadixTree<Boolean> classFilter;\n\n    public SchemaResolver(FrameworkModel frameworkModel) {\n        configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class);\n        ExtensionFactory extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class);\n        resolvers = extensionFactory.getExtensions(OpenAPISchemaResolver.class);\n        predicates = extensionFactory.getExtensions(OpenAPISchemaPredicate.class);\n    }\n\n    public Schema resolve(Type type) {\n        return resolve(new TypeParameterMeta(type));\n    }\n\n    public Schema resolve(ParameterMeta parameter) {\n        return new SchemaChainImpl(resolvers, this::fallbackResolve).resolve(parameter, new SchemaContextImpl());\n    }\n\n    public Schema resolve(List<ParameterMeta> parameters) {\n        Schema schema = OBJECT.newSchema();\n        for (ParameterMeta parameter : parameters) {\n            String name = parameter.getName();\n            if (name == null) {\n                return ARRAY.newSchema();\n            }\n            schema.addProperty(name, resolve(parameter));\n        }\n        return schema;\n    }\n\n    private Schema fallbackResolve(ParameterMeta parameter) {\n        return doResolveType(parameter.getActualGenericType(), parameter);\n    }\n\n    private Schema doResolveNestedType(Type nestedType, ParameterMeta parameter) {\n        return doResolveType(nestedType, new TypeParameterMeta(parameter.getToolKit(), nestedType));\n    }\n\n    private Schema doResolveType(Type type, ParameterMeta parameter) {\n        if (type instanceof Class) {\n            return doResolveClass((Class<?>) type, parameter);\n        }\n        if (type instanceof ParameterizedType) {\n            ParameterizedType pType = (ParameterizedType) type;\n            Type rawType = pType.getRawType();\n            if (rawType instanceof Class) {\n                Class<?> clazz = (Class<?>) rawType;\n                Type[] argTypes = pType.getActualTypeArguments();\n                if (Iterable.class.isAssignableFrom(clazz)) {\n                    Type itemType = TypeUtils.getActualGenericType(argTypes[0]);\n                    return ARRAY.newSchema()\n                            .addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(type))\n                            .setItems(doResolveNestedType(itemType, parameter));\n                }\n\n                if (Map.class.isAssignableFrom(clazz)) {\n                    return OBJECT.newSchema()\n                            .addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(type))\n                            .setAdditionalPropertiesSchema(doResolveNestedType(argTypes[1], parameter));\n                }\n\n                return doResolveClass(clazz, parameter);\n            }\n        }\n        if (type instanceof TypeVariable) {\n            return doResolveNestedType(((TypeVariable<?>) type).getBounds()[0], parameter);\n        }\n        if (type instanceof WildcardType) {\n            return doResolveNestedType(((WildcardType) type).getUpperBounds()[0], parameter);\n        }\n        if (type instanceof GenericArrayType) {\n            return ARRAY.newSchema()\n                    .addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(type))\n                    .setItems(doResolveNestedType(((GenericArrayType) type).getGenericComponentType(), parameter));\n        }\n        return OBJECT.newSchema();\n    }\n\n    private Schema doResolveClass(Class<?> clazz, ParameterMeta parameter) {\n        Schema schema = PrimitiveSchema.newSchemaOf(clazz);\n        if (schema != null) {\n            return schema;\n        }\n\n        if (clazz.isArray()) {\n            schema = ARRAY.newSchema();\n            if (!PrimitiveSchema.isPrimitive(clazz.getComponentType())) {\n                schema.addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(clazz));\n            }\n            return schema.setItems(doResolveNestedType(clazz.getComponentType(), parameter));\n        }\n\n        Schema existingSchema = schemaMap.get(clazz);\n        if (existingSchema != null) {\n            return new Schema().setTargetSchema(existingSchema);\n        }\n\n        if (isClassExcluded(clazz)) {\n            schema = OBJECT.newSchema().addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(clazz));\n            schemaMap.put(clazz, schema);\n            return schema;\n        }\n\n        TypeParameterMeta typeParameter = new TypeParameterMeta(clazz);\n        for (OpenAPISchemaPredicate predicate : predicates) {\n            Boolean accepted = predicate.acceptClass(clazz, typeParameter);\n            if (accepted == null) {\n                continue;\n            }\n            if (accepted) {\n                break;\n            } else {\n                schema = OBJECT.newSchema().addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(clazz));\n                schemaMap.put(clazz, schema);\n                return schema;\n            }\n        }\n\n        if (clazz.isEnum()) {\n            schema = PrimitiveSchema.STRING.newSchema().setJavaType(clazz);\n            for (Object value : clazz.getEnumConstants()) {\n                schema.addEnumeration(value);\n            }\n            schemaMap.put(clazz, schema);\n            return schema.clone();\n        }\n\n        Boolean flatten = configFactory.getGlobalConfig().getSchemaFlatten();\n        if (flatten == null) {\n            AnnotationMeta<?> anno = typeParameter.getAnnotation(Annotations.Schema);\n            flatten = anno != null && anno.getBoolean(\"flatten\");\n        }\n\n        return new Schema().setTargetSchema(doResolveBeanClass(parameter.getToolKit(), clazz, flatten));\n    }\n\n    private Schema doResolveBeanClass(RestToolKit toolKit, Class<?> clazz, boolean flatten) {\n        Schema beanSchema = OBJECT.newSchema().setJavaType(clazz);\n        schemaMap.put(clazz, beanSchema);\n        BeanMeta beanMeta = new BeanMeta(toolKit, clazz, flatten);\n        out:\n        for (PropertyMeta property : beanMeta.getProperties()) {\n            boolean fallback = true;\n            for (OpenAPISchemaPredicate predicate : predicates) {\n                Boolean accepted = predicate.acceptProperty(beanMeta, property);\n                if (accepted == null) {\n                    continue;\n                }\n                if (accepted) {\n                    fallback = false;\n                    break;\n                } else {\n                    continue out;\n                }\n            }\n\n            if (fallback) {\n                int visibility = property.getVisibility();\n                if ((visibility & 0b001) == 0 || (visibility & 0b110) == 0) {\n                    continue;\n                }\n            }\n            beanSchema.addProperty(property.getName(), resolve(property));\n        }\n\n        if (flatten) {\n            return beanSchema;\n        }\n        Class<?> superClass = clazz.getSuperclass();\n        if (superClass == null || superClass == Object.class || TypeUtils.isSystemType(superClass)) {\n            return beanSchema;\n        }\n\n        return beanSchema.addAllOf(resolve(superClass));\n    }\n\n    private boolean isClassExcluded(Class<?> clazz) {\n        RadixTree<Boolean> classFilter = this.classFilter;\n        if (classFilter == null) {\n            synchronized (this) {\n                classFilter = this.classFilter;\n                if (classFilter == null) {\n                    classFilter = new RadixTree<>('.');\n                    for (String prefix : TypeUtils.getSystemPrefixes()) {\n                        addPath(classFilter, prefix);\n                    }\n                    String[] excludes = configFactory.getGlobalConfig().getSchemaClassExcludes();\n                    if (excludes != null) {\n                        for (String exclude : excludes) {\n                            addPath(classFilter, exclude);\n                        }\n                    }\n                    this.classFilter = classFilter;\n                }\n            }\n        }\n\n        List<Match<Boolean>> matches = classFilter.match('.' + clazz.getName());\n        int size = matches.size();\n        if (size == 0) {\n            return false;\n        } else if (size > 1) {\n            Collections.sort(matches);\n        }\n        return matches.get(0).getValue();\n    }\n\n    public static void addPath(RadixTree<Boolean> tree, String path) {\n        if (path == null) {\n            return;\n        }\n        int size = path.length();\n        if (size == 0) {\n            return;\n        }\n        boolean value = true;\n        if (path.charAt(0) == '!') {\n            path = path.substring(1);\n            size--;\n            value = false;\n        }\n        if (path.charAt(size - 1) == '.') {\n            path += \"**\";\n        }\n        tree.addPath(path, value);\n    }\n\n    private static final class SchemaChainImpl implements SchemaChain {\n\n        private final OpenAPISchemaResolver[] resolvers;\n        private final Function<ParameterMeta, Schema> fallback;\n        private int cursor;\n\n        SchemaChainImpl(OpenAPISchemaResolver[] resolvers, Function<ParameterMeta, Schema> fallback) {\n            this.resolvers = resolvers;\n            this.fallback = fallback;\n        }\n\n        @Override\n        public Schema resolve(ParameterMeta parameter, SchemaContext context) {\n            if (cursor < resolvers.length) {\n                return resolvers[cursor++].resolve(parameter, context, this);\n            }\n            return fallback.apply(parameter);\n        }\n    }\n\n    private final class SchemaContextImpl implements SchemaContext {\n\n        @Override\n        public void defineSchema(Class<?> type, Schema schema) {\n            schemaMap.putIfAbsent(type, schema);\n        }\n\n        @Override\n        public Schema resolve(ParameterMeta parameter) {\n            return SchemaResolver.this.resolve(parameter);\n        }\n\n        @Override\n        public Schema resolve(Type type) {\n            return SchemaResolver.this.resolve(type);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\npublic final class ApiResponse extends Node<ApiResponse> {\n\n    private String ref;\n    private String description;\n    private Map<String, Header> headers;\n    private Map<String, MediaType> contents;\n\n    public String getRef() {\n        return ref;\n    }\n\n    public ApiResponse setRef(String ref) {\n        this.ref = ref;\n        return this;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public ApiResponse setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public Map<String, Header> getHeaders() {\n        return headers;\n    }\n\n    public Header getHeader(String name) {\n        return headers == null ? null : headers.get(name);\n    }\n\n    public ApiResponse setHeaders(Map<String, Header> headers) {\n        this.headers = headers;\n        return this;\n    }\n\n    public ApiResponse addHeader(String name, Header header) {\n        if (headers == null) {\n            headers = new LinkedHashMap<>();\n        }\n        headers.put(name, header);\n        return this;\n    }\n\n    public ApiResponse removeHeader(String name) {\n        if (headers != null) {\n            headers.remove(name);\n        }\n        return this;\n    }\n\n    public Map<String, MediaType> getContents() {\n        return contents;\n    }\n\n    public MediaType getContent(String name) {\n        return contents == null ? null : contents.get(name);\n    }\n\n    public MediaType getOrAddContent(String name) {\n        if (contents == null) {\n            contents = new LinkedHashMap<>();\n        }\n        return contents.computeIfAbsent(name, k -> new MediaType());\n    }\n\n    public ApiResponse setContents(Map<String, MediaType> contents) {\n        this.contents = contents;\n        return this;\n    }\n\n    public ApiResponse addContent(String name, MediaType content) {\n        if (contents == null) {\n            contents = new LinkedHashMap<>();\n        }\n        contents.put(name, content);\n        return this;\n    }\n\n    public ApiResponse removeContent(String name) {\n        if (contents != null) {\n            contents.remove(name);\n        }\n        return this;\n    }\n\n    @Override\n    public ApiResponse clone() {\n        ApiResponse clone = super.clone();\n        clone.contents = clone(contents);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"description\", description);\n        write(node, \"content\", contents, context);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.TreeMap;\n\npublic final class Components extends Node<Components> {\n\n    private Map<String, Schema> schemas;\n    private Map<String, SecurityScheme> securitySchemes;\n\n    public Map<String, Schema> getSchemas() {\n        return schemas;\n    }\n\n    public Components setSchemas(Map<String, Schema> schemas) {\n        this.schemas = schemas;\n        return this;\n    }\n\n    public Components addSchema(String name, Schema schema) {\n        if (schemas == null) {\n            schemas = new TreeMap<>();\n        }\n        schemas.put(name, schema);\n        return this;\n    }\n\n    public Components removeSchema(String name) {\n        if (schemas != null) {\n            schemas.remove(name);\n        }\n        return this;\n    }\n\n    public Map<String, SecurityScheme> getSecuritySchemes() {\n        return securitySchemes;\n    }\n\n    public Components setSecuritySchemes(Map<String, SecurityScheme> securitySchemes) {\n        this.securitySchemes = securitySchemes;\n        return this;\n    }\n\n    public Components addSecurityScheme(String name, SecurityScheme securityScheme) {\n        if (securitySchemes == null) {\n            securitySchemes = new LinkedHashMap<>();\n        }\n        securitySchemes.put(name, securityScheme);\n        return this;\n    }\n\n    public Components removeSecurityScheme(String name) {\n        if (securitySchemes != null) {\n            securitySchemes.remove(name);\n        }\n        return this;\n    }\n\n    @Override\n    public Components clone() {\n        Components clone = super.clone();\n        clone.schemas = clone(schemas);\n        clone.securitySchemes = clone(securitySchemes);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"schemas\", schemas, context);\n        write(node, \"securitySchemes\", securitySchemes, context);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.Map;\n\npublic final class Contact extends Node<Contact> {\n\n    private String name;\n    private String url;\n    private String email;\n\n    public String getName() {\n        return name;\n    }\n\n    public Contact setName(String name) {\n        this.name = name;\n        return this;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public Contact setUrl(String url) {\n        this.url = url;\n        return this;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public Contact setEmail(String email) {\n        this.email = email;\n        return this;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"name\", name);\n        write(node, \"url\", url);\n        write(node, \"email\", email);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\npublic final class Discriminator extends Node<Discriminator> {\n\n    private String propertyName;\n    private Map<String, String> mapping;\n\n    public String getPropertyName() {\n        return propertyName;\n    }\n\n    public Discriminator setPropertyName(String propertyName) {\n        this.propertyName = propertyName;\n        return this;\n    }\n\n    public Map<String, String> getMapping() {\n        return mapping;\n    }\n\n    public Discriminator setMapping(Map<String, String> mapping) {\n        this.mapping = mapping;\n        return this;\n    }\n\n    public Discriminator addMapping(String key, String value) {\n        if (mapping == null) {\n            mapping = new LinkedHashMap<>();\n        }\n        mapping.put(key, value);\n        return this;\n    }\n\n    public Discriminator removeMapping(String key) {\n        if (mapping != null) {\n            mapping.remove(key);\n        }\n        return this;\n    }\n\n    @Override\n    public Discriminator clone() {\n        Discriminator clone = super.clone();\n        if (mapping != null) {\n            clone.setMapping(new LinkedHashMap<>(mapping));\n        }\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"propertyName\", propertyName);\n        write(node, \"mapping\", mapping);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\npublic final class Encoding extends Node<Encoding> {\n\n    public enum Style {\n        FORM(\"form\"),\n        SPACE_DELIMITED(\"spaceDelimited\"),\n        PIPE_DELIMITED(\"pipeDelimited\"),\n        DEEP_OBJECT(\"deepObject\");\n\n        private final String value;\n\n        Style(String value) {\n            this.value = value;\n        }\n\n        @Override\n        public String toString() {\n            return value;\n        }\n    }\n\n    private String contentType;\n    private Map<String, Parameter> headers;\n    private Style style;\n    private Boolean explode;\n    private Boolean allowReserved;\n\n    public String getContentType() {\n        return contentType;\n    }\n\n    public Encoding setContentType(String contentType) {\n        this.contentType = contentType;\n        return this;\n    }\n\n    public Map<String, Parameter> getHeaders() {\n        return headers;\n    }\n\n    public Parameter getHeader(String name) {\n        return headers == null ? null : headers.get(name);\n    }\n\n    public Encoding setHeaders(Map<String, Parameter> headers) {\n        this.headers = headers;\n        return this;\n    }\n\n    public Encoding addHeader(String name, Parameter header) {\n        if (headers == null) {\n            headers = new LinkedHashMap<>();\n        }\n        headers.put(name, header);\n        return this;\n    }\n\n    public Encoding removeHeader(String name) {\n        if (headers != null) {\n            headers.remove(name);\n        }\n        return this;\n    }\n\n    public Style getStyle() {\n        return style;\n    }\n\n    public Encoding setStyle(Style style) {\n        this.style = style;\n        return this;\n    }\n\n    public Boolean getExplode() {\n        return explode;\n    }\n\n    public Encoding setExplode(Boolean explode) {\n        this.explode = explode;\n        return this;\n    }\n\n    public Boolean getAllowReserved() {\n        return allowReserved;\n    }\n\n    public Encoding setAllowReserved(Boolean allowReserved) {\n        this.allowReserved = allowReserved;\n        return this;\n    }\n\n    @Override\n    public Encoding clone() {\n        Encoding clone = super.clone();\n        clone.headers = clone(headers);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> encoding, Context context) {\n        write(encoding, \"contentType\", contentType);\n        write(encoding, \"headers\", headers, context);\n        write(encoding, \"style\", style);\n        write(encoding, \"explode\", explode);\n        write(encoding, \"allowReserved\", allowReserved);\n        writeExtensions(encoding);\n        return encoding;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.Map;\n\npublic final class Example extends Node<Example> {\n\n    private String summary;\n    private String description;\n    private Object value;\n    private String externalValue;\n\n    public String getSummary() {\n        return summary;\n    }\n\n    public Example setSummary(String summary) {\n        this.summary = summary;\n        return this;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public Example setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public Object getValue() {\n        return value;\n    }\n\n    public Example setValue(Object value) {\n        this.value = value;\n        return this;\n    }\n\n    public String getExternalValue() {\n        return externalValue;\n    }\n\n    public Example setExternalValue(String externalValue) {\n        this.externalValue = externalValue;\n        return this;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> exampleNode, Context context) {\n        write(exampleNode, \"summary\", summary);\n        write(exampleNode, \"description\", description);\n        write(exampleNode, \"value\", value);\n        write(exampleNode, \"externalValue\", externalValue);\n        writeExtensions(exampleNode);\n        return exampleNode;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.Map;\n\npublic final class ExternalDocs extends Node<ExternalDocs> {\n\n    private String description;\n    private String url;\n\n    public String getDescription() {\n        return description;\n    }\n\n    public ExternalDocs setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public ExternalDocs setUrl(String url) {\n        this.url = url;\n        return this;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"description\", description);\n        write(node, \"url\", url);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\npublic final class Header extends Node<Header> {\n\n    public enum Style {\n        SIMPLE(\"simple\");\n\n        private final String value;\n\n        Style(String value) {\n            this.value = value;\n        }\n\n        @Override\n        public String toString() {\n            return value;\n        }\n    }\n\n    private String description;\n    private Boolean required;\n    private Boolean deprecated;\n    private Boolean allowEmptyValue;\n    private final Style style = Style.SIMPLE;\n    private Boolean explode;\n    private Schema schema;\n    private Object example;\n    private Map<String, Example> examples;\n    private Map<String, MediaType> contents;\n\n    public String getDescription() {\n        return description;\n    }\n\n    public Header setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public Boolean getRequired() {\n        return required;\n    }\n\n    public Header setRequired(Boolean required) {\n        this.required = required;\n        return this;\n    }\n\n    public Boolean getDeprecated() {\n        return deprecated;\n    }\n\n    public Header setDeprecated(Boolean deprecated) {\n        this.deprecated = deprecated;\n        return this;\n    }\n\n    public Boolean getAllowEmptyValue() {\n        return allowEmptyValue;\n    }\n\n    public Header setAllowEmptyValue(Boolean allowEmptyValue) {\n        this.allowEmptyValue = allowEmptyValue;\n        return this;\n    }\n\n    public Style getStyle() {\n        return style;\n    }\n\n    public Boolean getExplode() {\n        return explode;\n    }\n\n    public Header setExplode(Boolean explode) {\n        this.explode = explode;\n        return this;\n    }\n\n    public Schema getSchema() {\n        return schema;\n    }\n\n    public Header setSchema(Schema schema) {\n        this.schema = schema;\n        return this;\n    }\n\n    public Object getExample() {\n        return example;\n    }\n\n    public Header setExample(Object example) {\n        this.example = example;\n        return this;\n    }\n\n    public Map<String, Example> getExamples() {\n        return examples;\n    }\n\n    public Header setExamples(Map<String, Example> examples) {\n        this.examples = examples;\n        return this;\n    }\n\n    public Header addExample(String name, Example example) {\n        if (examples == null) {\n            examples = new LinkedHashMap<>();\n        }\n        examples.put(name, example);\n        return this;\n    }\n\n    public Header removeExample(String name) {\n        if (examples != null) {\n            examples.remove(name);\n        }\n        return this;\n    }\n\n    public Map<String, MediaType> getContents() {\n        return contents;\n    }\n\n    public MediaType getContent(String name) {\n        return contents == null ? null : contents.get(name);\n    }\n\n    public Header setContents(Map<String, MediaType> contents) {\n        this.contents = contents;\n        return this;\n    }\n\n    public Header addContent(String name, MediaType content) {\n        if (contents == null) {\n            contents = new LinkedHashMap<>();\n        }\n        contents.put(name, content);\n        return this;\n    }\n\n    public Header removeContent(String name) {\n        if (contents != null) {\n            contents.remove(name);\n        }\n        return this;\n    }\n\n    @Override\n    public Header clone() {\n        Header clone = super.clone();\n        clone.schema = clone(schema);\n        clone.examples = clone(examples);\n        clone.contents = clone(contents);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"description\", description);\n        write(node, \"required\", required);\n        write(node, \"deprecated\", deprecated);\n        write(node, \"allowEmptyValue\", allowEmptyValue);\n        write(node, \"style\", style);\n        write(node, \"explode\", explode);\n        write(node, \"schema\", schema, context);\n        write(node, \"example\", example);\n        write(node, \"examples\", examples, context);\n        write(node, \"content\", contents, context);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.Map;\n\npublic final class Info extends Node<Info> {\n\n    private String title;\n    private String summary;\n    private String description;\n    private String termsOfService;\n    private Contact contact;\n    private License license;\n    private String version;\n\n    public String getTitle() {\n        return title;\n    }\n\n    public Info setTitle(String title) {\n        this.title = title;\n        return this;\n    }\n\n    public String getSummary() {\n        return summary;\n    }\n\n    public Info setSummary(String summary) {\n        this.summary = summary;\n        return this;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public Info setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public String getTermsOfService() {\n        return termsOfService;\n    }\n\n    public Info setTermsOfService(String termsOfService) {\n        this.termsOfService = termsOfService;\n        return this;\n    }\n\n    public Contact getContact() {\n        return contact;\n    }\n\n    public Info setContact(Contact contact) {\n        this.contact = contact;\n        return this;\n    }\n\n    public License getLicense() {\n        return license;\n    }\n\n    public Info setLicense(License license) {\n        this.license = license;\n        return this;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public Info setVersion(String version) {\n        this.version = version;\n        return this;\n    }\n\n    @Override\n    public Info clone() {\n        Info clone = super.clone();\n        clone.contact = clone(contact);\n        clone.license = clone(license);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"title\", title);\n        write(node, \"summary\", summary);\n        write(node, \"description\", description);\n        write(node, \"termsOfService\", termsOfService);\n        write(node, \"contact\", contact, context);\n        write(node, \"license\", license, context);\n        write(node, \"version\", version);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.Map;\n\npublic final class License extends Node<License> {\n\n    private String name;\n    private String url;\n\n    public String getName() {\n        return name;\n    }\n\n    public License setName(String name) {\n        this.name = name;\n        return this;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public License setUrl(String url) {\n        this.url = url;\n        return this;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"name\", name);\n        write(node, \"url\", url);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\npublic final class MediaType extends Node<MediaType> {\n\n    private Schema schema;\n    private Object example;\n    private Map<String, Example> examples;\n    private Map<String, Encoding> encoding;\n\n    public Schema getSchema() {\n        return schema;\n    }\n\n    public MediaType setSchema(Schema schema) {\n        this.schema = schema;\n        return this;\n    }\n\n    public Object getExample() {\n        return example;\n    }\n\n    public MediaType setExample(Object example) {\n        this.example = example;\n        return this;\n    }\n\n    public Map<String, Example> getExamples() {\n        return examples;\n    }\n\n    public MediaType setExamples(Map<String, Example> examples) {\n        this.examples = examples;\n        return this;\n    }\n\n    public MediaType addExample(String name, Example example) {\n        if (examples == null) {\n            examples = new LinkedHashMap<>();\n        }\n        examples.put(name, example);\n        return this;\n    }\n\n    public MediaType removeExample(String name) {\n        if (examples != null) {\n            examples.remove(name);\n        }\n        return this;\n    }\n\n    public Map<String, Encoding> getEncoding() {\n        return encoding;\n    }\n\n    public MediaType setEncoding(Map<String, Encoding> encoding) {\n        this.encoding = encoding;\n        return this;\n    }\n\n    public MediaType addEncoding(String name, Encoding encoding) {\n        if (this.encoding == null) {\n            this.encoding = new LinkedHashMap<>();\n        }\n        this.encoding.put(name, encoding);\n        return this;\n    }\n\n    public MediaType removeEncoding(String name) {\n        if (encoding != null) {\n            encoding.remove(name);\n        }\n        return this;\n    }\n\n    @Override\n    public MediaType clone() {\n        MediaType clone = super.clone();\n        clone.schema = clone(schema);\n        clone.examples = clone(examples);\n        clone.encoding = clone(encoding);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"schema\", schema, context);\n        write(node, \"example\", example);\n        write(node, \"examples\", examples, context);\n        write(node, \"encoding\", encoding, context);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.common.utils.ToStringUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic abstract class Node<T extends Node<T>> implements Cloneable {\n\n    private Map<String, Object> extensions;\n\n    public Map<String, Object> getExtensions() {\n        return extensions;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T addExtension(String name, Object value) {\n        Map<String, Object> extensions = this.extensions;\n        if (extensions == null) {\n            this.extensions = extensions = new LinkedHashMap<>();\n        }\n        extensions.put(name, value);\n        return (T) this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T addExtensions(Map<String, ?> extensions) {\n        if (extensions == null || extensions.isEmpty()) {\n            return (T) this;\n        }\n\n        Map<String, Object> thisExtensions = this.extensions;\n        if (thisExtensions == null) {\n            this.extensions = new LinkedHashMap<>(extensions);\n        } else {\n            for (Map.Entry<String, ?> entry : extensions.entrySet()) {\n                thisExtensions.putIfAbsent(entry.getKey(), entry.getValue());\n            }\n        }\n        return (T) this;\n    }\n\n    public void removeExtension(String name) {\n        if (extensions != null) {\n            extensions.remove(name);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T setExtensions(Map<String, ?> extensions) {\n        if (extensions != null) {\n            this.extensions = new LinkedHashMap<>(extensions);\n        }\n        return (T) this;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public T clone() {\n        try {\n            T clone = (T) super.clone();\n            if (extensions != null) {\n                clone.setExtensions(extensions);\n            }\n            return clone;\n        } catch (CloneNotSupportedException e) {\n            throw new UnsupportedOperationException(e);\n        }\n    }\n\n    @Override\n    public String toString() {\n        return ToStringUtils.printToString(this);\n    }\n\n    public static <T extends Node<T>> T clone(T node) {\n        return node == null ? null : node.clone();\n    }\n\n    public static <T extends Node<T>> List<T> clone(List<T> list) {\n        if (list == null) {\n            return null;\n        }\n        int size = list.size();\n        if (size == 0) {\n            return new ArrayList<>();\n        }\n        List<T> clone = new ArrayList<>(size);\n        for (int i = 0; i < size; i++) {\n            clone.add(list.get(i).clone());\n        }\n        return clone;\n    }\n\n    public static <K, V extends Node<V>> Map<K, V> clone(Map<K, V> map) {\n        if (map == null) {\n            return null;\n        }\n        int size = map.size();\n        if (size == 0) {\n            return new LinkedHashMap<>();\n        }\n        Map<K, V> clone = newMap(size);\n        for (Map.Entry<K, V> entry : map.entrySet()) {\n            clone.put(entry.getKey(), entry.getValue().clone());\n        }\n        return clone;\n    }\n\n    protected static void write(Map<String, Object> node, String name, Object value) {\n        if (value == null || \"\".equals(value)) {\n            return;\n        }\n        node.put(name, value instanceof Set ? ((Set<?>) value).toArray() : value);\n    }\n\n    protected static void write(Map<String, Object> node, String name, Node<?> value, Context context) {\n        if (value == null) {\n            return;\n        }\n        Map<String, Object> valueMap = value.writeTo(new LinkedHashMap<>(), context);\n        if (valueMap == null || valueMap.isEmpty()) {\n            return;\n        }\n        node.put(name, valueMap);\n    }\n\n    protected static void write(Map<String, Object> node, String name, List<? extends Node<?>> value, Context context) {\n        if (value == null) {\n            return;\n        }\n        int size = value.size();\n        if (size > 0) {\n            List<Map<String, Object>> list = new ArrayList<>(size);\n            for (int i = 0; i < size; i++) {\n                Map<String, Object> valueMap = value.get(i).writeTo(new LinkedHashMap<>(), context);\n                if (valueMap == null || valueMap.isEmpty()) {\n                    continue;\n                }\n                list.add(valueMap);\n            }\n            node.put(name, list);\n        }\n    }\n\n    protected static void write(\n            Map<String, Object> node, String name, Map<?, ? extends Node<?>> value, Context context) {\n        if (value == null) {\n            return;\n        }\n        int size = value.size();\n        if (size > 0) {\n            Map<Object, Map<String, Object>> map = newMap(size);\n            for (Map.Entry<?, ? extends Node<?>> entry : value.entrySet()) {\n                Map<String, Object> valueMap = entry.getValue().writeTo(new LinkedHashMap<>(), context);\n                if (valueMap == null || valueMap.isEmpty()) {\n                    continue;\n                }\n                map.put(entry.getKey(), valueMap);\n            }\n            node.put(name, map);\n        }\n    }\n\n    protected static <K, V> Map<K, V> newMap(int capacity) {\n        return new LinkedHashMap<>(capacity < 3 ? capacity + 1 : (int) (capacity / 0.75F + 1.0F));\n    }\n\n    protected final void writeExtensions(Map<String, Object> node) {\n        if (extensions == null) {\n            return;\n        }\n        node.putAll(extensions);\n    }\n\n    public abstract Map<String, Object> writeTo(Map<String, Object> node, Context context);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\npublic final class OAuthFlow extends Node<OAuthFlow> {\n\n    private String authorizationUrl;\n    private String tokenUrl;\n    private String refreshUrl;\n    private Map<String, String> scopes;\n\n    public String getAuthorizationUrl() {\n        return authorizationUrl;\n    }\n\n    public OAuthFlow setAuthorizationUrl(String authorizationUrl) {\n        this.authorizationUrl = authorizationUrl;\n        return this;\n    }\n\n    public String getTokenUrl() {\n        return tokenUrl;\n    }\n\n    public OAuthFlow setTokenUrl(String tokenUrl) {\n        this.tokenUrl = tokenUrl;\n        return this;\n    }\n\n    public String getRefreshUrl() {\n        return refreshUrl;\n    }\n\n    public OAuthFlow setRefreshUrl(String refreshUrl) {\n        this.refreshUrl = refreshUrl;\n        return this;\n    }\n\n    public Map<String, String> getScopes() {\n        return scopes;\n    }\n\n    public OAuthFlow setScopes(Map<String, String> scopes) {\n        this.scopes = scopes;\n        return this;\n    }\n\n    public OAuthFlow addScope(String name, String description) {\n        if (scopes == null) {\n            scopes = new LinkedHashMap<>();\n        }\n        scopes.put(name, description);\n        return this;\n    }\n\n    public void removeScope(String name) {\n        if (scopes != null) {\n            scopes.remove(name);\n        }\n    }\n\n    @Override\n    public OAuthFlow clone() {\n        OAuthFlow clone = super.clone();\n        if (scopes != null) {\n            clone.scopes = new LinkedHashMap<>(scopes);\n        }\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"authorizationUrl\", authorizationUrl);\n        write(node, \"tokenUrl\", tokenUrl);\n        write(node, \"refreshUrl\", refreshUrl);\n        write(node, \"scopes\", scopes);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.Map;\n\npublic final class OAuthFlows extends Node<OAuthFlows> {\n\n    private OAuthFlow implicit;\n    private OAuthFlow password;\n    private OAuthFlow clientCredentials;\n    private OAuthFlow authorizationCode;\n\n    public OAuthFlow getImplicit() {\n        return implicit;\n    }\n\n    public OAuthFlows setImplicit(OAuthFlow implicit) {\n        this.implicit = implicit;\n        return this;\n    }\n\n    public OAuthFlow getPassword() {\n        return password;\n    }\n\n    public OAuthFlows setPassword(OAuthFlow password) {\n        this.password = password;\n        return this;\n    }\n\n    public OAuthFlow getClientCredentials() {\n        return clientCredentials;\n    }\n\n    public OAuthFlows setClientCredentials(OAuthFlow clientCredentials) {\n        this.clientCredentials = clientCredentials;\n        return this;\n    }\n\n    public OAuthFlow getAuthorizationCode() {\n        return authorizationCode;\n    }\n\n    public OAuthFlows setAuthorizationCode(OAuthFlow authorizationCode) {\n        this.authorizationCode = authorizationCode;\n        return this;\n    }\n\n    @Override\n    public OAuthFlows clone() {\n        OAuthFlows clone = super.clone();\n        clone.implicit = clone(implicit);\n        clone.password = clone(password);\n        clone.clientCredentials = clone(clientCredentials);\n        clone.authorizationCode = clone(authorizationCode);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"implicit\", implicit);\n        write(node, \"password\", password);\n        write(node, \"clientCredentials\", clientCredentials);\n        write(node, \"authorizationCode\", authorizationCode);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.config.nested.OpenAPIConfig;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\npublic final class OpenAPI extends Node<OpenAPI> {\n\n    private String openapi;\n    private Info info;\n    private List<Server> servers;\n    private Map<String, PathItem> paths;\n    private Components components;\n    private List<SecurityRequirement> security;\n    private List<Tag> tags;\n    private ExternalDocs externalDocs;\n\n    private String group;\n    private int priority;\n\n    private transient OpenAPIConfig globalConfig;\n    private transient OpenAPIConfig config;\n    private transient ServiceMeta meta;\n\n    public String getOpenapi() {\n        return openapi;\n    }\n\n    public OpenAPI setOpenapi(String openapi) {\n        this.openapi = openapi;\n        return this;\n    }\n\n    public Info getInfo() {\n        return info;\n    }\n\n    public OpenAPI setInfo(Info info) {\n        this.info = info;\n        return this;\n    }\n\n    public List<Server> getServers() {\n        return servers;\n    }\n\n    public OpenAPI setServers(List<Server> servers) {\n        this.servers = servers;\n        return this;\n    }\n\n    public OpenAPI addServer(Server server) {\n        List<Server> thisServers = servers;\n        if (thisServers == null) {\n            servers = thisServers = new ArrayList<>();\n        } else {\n            for (int i = 0, size = thisServers.size(); i < size; i++) {\n                if (thisServers.get(i).getUrl().equals(server.getUrl())) {\n                    return this;\n                }\n            }\n        }\n        thisServers.add(server);\n        return this;\n    }\n\n    public OpenAPI removeServer(Server server) {\n        if (servers != null) {\n            servers.remove(server);\n        }\n        return this;\n    }\n\n    public Map<String, PathItem> getPaths() {\n        return paths;\n    }\n\n    public PathItem getPath(String path) {\n        return paths == null ? null : paths.get(path);\n    }\n\n    public PathItem getOrAddPath(String path) {\n        if (paths == null) {\n            paths = new LinkedHashMap<>();\n        }\n        return paths.computeIfAbsent(path, k -> new PathItem());\n    }\n\n    public OpenAPI setPaths(Map<String, PathItem> paths) {\n        this.paths = paths;\n        return this;\n    }\n\n    public OpenAPI addPath(String path, PathItem pathItem) {\n        if (paths == null) {\n            paths = new LinkedHashMap<>();\n        }\n        paths.put(path, pathItem);\n        return this;\n    }\n\n    public OpenAPI removePath(String path) {\n        if (paths != null) {\n            paths.remove(path);\n        }\n        return this;\n    }\n\n    public Components getComponents() {\n        return components;\n    }\n\n    public OpenAPI setComponents(Components components) {\n        this.components = components;\n        return this;\n    }\n\n    public List<SecurityRequirement> getSecurity() {\n        return security;\n    }\n\n    public OpenAPI setSecurity(List<SecurityRequirement> security) {\n        this.security = security;\n        return this;\n    }\n\n    public OpenAPI addSecurity(SecurityRequirement securityRequirement) {\n        if (security == null) {\n            security = new ArrayList<>();\n        }\n        security.add(securityRequirement);\n        return this;\n    }\n\n    public List<Tag> getTags() {\n        return tags;\n    }\n\n    public OpenAPI setTags(List<Tag> tags) {\n        this.tags = tags;\n        return this;\n    }\n\n    public OpenAPI addTag(Tag tag) {\n        List<Tag> thisTags = tags;\n        if (thisTags == null) {\n            tags = thisTags = new ArrayList<>();\n        } else {\n            for (int i = 0, size = thisTags.size(); i < size; i++) {\n                if (thisTags.get(i).getName().equals(tag.getName())) {\n                    return this;\n                }\n            }\n        }\n        thisTags.add(tag);\n        return this;\n    }\n\n    public OpenAPI removeTag(Tag tag) {\n        if (tags != null) {\n            tags.remove(tag);\n        }\n        return this;\n    }\n\n    public ExternalDocs getExternalDocs() {\n        return externalDocs;\n    }\n\n    public OpenAPI setExternalDocs(ExternalDocs externalDocs) {\n        this.externalDocs = externalDocs;\n        return this;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public OpenAPI setGroup(String group) {\n        this.group = group;\n        return this;\n    }\n\n    public int getPriority() {\n        return priority;\n    }\n\n    public OpenAPI setPriority(int priority) {\n        this.priority = priority;\n        return this;\n    }\n\n    public OpenAPIConfig getGlobalConfig() {\n        return globalConfig;\n    }\n\n    public OpenAPI setGlobalConfig(OpenAPIConfig globalConfig) {\n        this.globalConfig = globalConfig;\n        return this;\n    }\n\n    public OpenAPIConfig getConfig() {\n        return config;\n    }\n\n    public OpenAPI setConfig(OpenAPIConfig config) {\n        this.config = config;\n        return this;\n    }\n\n    public <T> T getConfigValue(Function<OpenAPIConfig, T> fn) {\n        if (config != null) {\n            T value = fn.apply(config);\n            if (value != null) {\n                return value;\n            }\n        }\n        return globalConfig == null ? null : fn.apply(globalConfig);\n    }\n\n    public String getConfigSetting(String key) {\n        return getConfigValue(config -> config == null ? null : config.getSetting(key));\n    }\n\n    public void walkOperations(Consumer<Operation> consumer) {\n        Map<String, PathItem> paths = this.paths;\n        if (paths == null) {\n            return;\n        }\n\n        for (PathItem pathItem : paths.values()) {\n            Map<HttpMethods, Operation> operations = pathItem.getOperations();\n            if (operations != null) {\n                for (Operation operation : operations.values()) {\n                    consumer.accept(operation);\n                }\n            }\n        }\n    }\n\n    public ServiceMeta getMeta() {\n        return meta;\n    }\n\n    public OpenAPI setMeta(ServiceMeta meta) {\n        this.meta = meta;\n        return this;\n    }\n\n    @Override\n    public OpenAPI clone() {\n        OpenAPI clone = super.clone();\n        clone.info = clone(info);\n        clone.servers = clone(servers);\n        clone.paths = clone(paths);\n        clone.components = clone(components);\n        clone.security = clone(security);\n        clone.tags = clone(tags);\n        clone.externalDocs = clone(externalDocs);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        node.put(\"openapi\", openapi == null ? Constants.VERSION_30 : openapi);\n        write(node, \"info\", info, context);\n        write(node, \"servers\", servers, context);\n        write(node, \"paths\", paths, context);\n        write(node, \"components\", components, context);\n        write(node, \"security\", security, context);\n        write(node, \"tags\", tags, context);\n        write(node, \"externalDocs\", externalDocs, context);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic final class Operation extends Node<Operation> {\n\n    private Set<String> tags;\n    private String summary;\n    private String description;\n    private ExternalDocs externalDocs;\n    private String operationId;\n    private List<Parameter> parameters;\n    private RequestBody requestBody;\n    private Map<String, ApiResponse> responses;\n    private Boolean deprecated;\n    private List<SecurityRequirement> security;\n    private List<Server> servers;\n\n    private String group;\n    private String version;\n    private HttpMethods httpMethod;\n    private transient MethodMeta meta;\n\n    public Set<String> getTags() {\n        return tags;\n    }\n\n    public Operation setTags(Set<String> tags) {\n        this.tags = tags;\n        return this;\n    }\n\n    public Operation addTag(String tag) {\n        if (tags == null) {\n            tags = new LinkedHashSet<>();\n        }\n        tags.add(tag);\n        return this;\n    }\n\n    public Operation removeTag(String tag) {\n        if (tags != null) {\n            tags.remove(tag);\n        }\n        return this;\n    }\n\n    public String getSummary() {\n        return summary;\n    }\n\n    public Operation setSummary(String summary) {\n        this.summary = summary;\n        return this;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public Operation setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public ExternalDocs getExternalDocs() {\n        return externalDocs;\n    }\n\n    public Operation setExternalDocs(ExternalDocs externalDocs) {\n        this.externalDocs = externalDocs;\n        return this;\n    }\n\n    public String getOperationId() {\n        return operationId;\n    }\n\n    public Operation setOperationId(String operationId) {\n        this.operationId = operationId;\n        return this;\n    }\n\n    public List<Parameter> getParameters() {\n        return parameters;\n    }\n\n    public Parameter getParameter(String name, In in) {\n        if (parameters == null || name == null || in == null) {\n            return null;\n        }\n        for (int i = 0, size = parameters.size(); i < size; i++) {\n            Parameter parameter = parameters.get(i);\n            if (name.equals(parameter.getName()) && in == parameter.getIn()) {\n                return parameter;\n            }\n        }\n        return null;\n    }\n\n    public Operation setParameters(List<Parameter> parameters) {\n        this.parameters = parameters;\n        return this;\n    }\n\n    public Operation addParameter(Parameter parameter) {\n        if (parameters == null) {\n            parameters = new ArrayList<>();\n        }\n        parameters.add(parameter);\n        return this;\n    }\n\n    public Operation removeParameter(Parameter parameter) {\n        if (parameters != null) {\n            parameters.remove(parameter);\n        }\n        return this;\n    }\n\n    public RequestBody getRequestBody() {\n        return requestBody;\n    }\n\n    public Operation setRequestBody(RequestBody requestBody) {\n        this.requestBody = requestBody;\n        return this;\n    }\n\n    public Map<String, ApiResponse> getResponses() {\n        return responses;\n    }\n\n    public ApiResponse getResponse(String httpStatusCode) {\n        return responses == null ? null : responses.get(httpStatusCode);\n    }\n\n    public ApiResponse getOrAddResponse(String httpStatusCode) {\n        if (responses == null) {\n            responses = new LinkedHashMap<>();\n        }\n        return responses.computeIfAbsent(httpStatusCode, k -> new ApiResponse());\n    }\n\n    public Operation setResponses(Map<String, ApiResponse> responses) {\n        this.responses = responses;\n        return this;\n    }\n\n    public Operation addResponse(String name, ApiResponse response) {\n        if (responses == null) {\n            responses = new LinkedHashMap<>();\n        }\n        responses.put(name, response);\n        return this;\n    }\n\n    public Operation removeResponse(String name) {\n        if (responses != null) {\n            responses.remove(name);\n        }\n        return this;\n    }\n\n    public Boolean getDeprecated() {\n        return deprecated;\n    }\n\n    public Operation setDeprecated(Boolean deprecated) {\n        this.deprecated = deprecated;\n        return this;\n    }\n\n    public List<SecurityRequirement> getSecurity() {\n        return security;\n    }\n\n    public Operation setSecurity(List<SecurityRequirement> security) {\n        this.security = security;\n        return this;\n    }\n\n    public Operation addSecurity(SecurityRequirement security) {\n        if (this.security == null) {\n            this.security = new ArrayList<>();\n        }\n        this.security.add(security);\n        return this;\n    }\n\n    public Operation removeSecurity(SecurityRequirement security) {\n        if (this.security != null) {\n            this.security.remove(security);\n        }\n        return this;\n    }\n\n    public List<Server> getServers() {\n        return servers;\n    }\n\n    public Operation setServers(List<Server> servers) {\n        this.servers = servers;\n        return this;\n    }\n\n    public Operation addServer(Server server) {\n        if (servers == null) {\n            servers = new ArrayList<>();\n        }\n        servers.add(server);\n        return this;\n    }\n\n    public Operation removeServer(Server server) {\n        if (servers != null) {\n            servers.remove(server);\n        }\n        return this;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public Operation setGroup(String group) {\n        this.group = group;\n        return this;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public Operation setVersion(String version) {\n        this.version = version;\n        return this;\n    }\n\n    public HttpMethods getHttpMethod() {\n        return httpMethod;\n    }\n\n    public Operation setHttpMethod(HttpMethods httpMethod) {\n        this.httpMethod = httpMethod;\n        return this;\n    }\n\n    public MethodMeta getMeta() {\n        return meta;\n    }\n\n    public Operation setMeta(MethodMeta meta) {\n        this.meta = meta;\n        return this;\n    }\n\n    @Override\n    public Operation clone() {\n        Operation clone = super.clone();\n        if (tags != null) {\n            clone.tags = new LinkedHashSet<>(tags);\n        }\n        clone.externalDocs = clone(externalDocs);\n        clone.parameters = clone(parameters);\n        clone.requestBody = clone(requestBody);\n        clone.responses = clone(responses);\n        clone.security = clone(security);\n        clone.servers = clone(servers);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"tags\", tags);\n        write(node, \"summary\", summary);\n        write(node, \"description\", description);\n        write(node, \"externalDocs\", externalDocs, context);\n        write(node, \"operationId\", operationId);\n        write(node, \"parameters\", parameters, context);\n        write(node, \"requestBody\", requestBody, context);\n        write(node, \"responses\", responses, context);\n        write(node, \"deprecated\", deprecated);\n        write(node, \"security\", security, context);\n        write(node, \"servers\", servers, context);\n        writeExtensions(node);\n        write(node, Constants.X_JAVA_CLASS, meta.getServiceMeta().getServiceInterface());\n        write(node, Constants.X_JAVA_METHOD, meta.getMethod().getName());\n        write(node, Constants.X_JAVA_METHOD_DESCRIPTOR, TypeUtils.getMethodDescriptor(meta));\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\npublic final class Parameter extends Node<Parameter> {\n\n    public enum In {\n        PATH(\"path\"),\n        QUERY(\"query\"),\n        HEADER(\"header\"),\n        COOKIE(\"cookie\");\n\n        private final String value;\n\n        In(String value) {\n            this.value = value;\n        }\n\n        @Override\n        public String toString() {\n            return value;\n        }\n    }\n\n    public enum Style {\n        MATRIX(\"matrix\"),\n        LABEL(\"label\"),\n        FORM(\"form\"),\n        SIMPLE(\"simple\"),\n        SPACE_DELIMITED(\"spaceDelimited\"),\n        PIPE_DELIMITED(\"pipeDelimited\"),\n        DEEP_OBJECT(\"deepObject\");\n\n        private final String value;\n\n        Style(String value) {\n            this.value = value;\n        }\n\n        @Override\n        public String toString() {\n            return value;\n        }\n    }\n\n    private final String name;\n    private final In in;\n    private String description;\n    private Boolean required;\n    private Boolean deprecated;\n    private Boolean allowEmptyValue;\n    private Style style;\n    private Boolean explode;\n    private Boolean allowReserved;\n    private Schema schema;\n    private Object example;\n    private Map<String, Example> examples;\n    private Map<String, MediaType> contents;\n\n    private transient ParameterMeta meta;\n\n    public Parameter(String name, In in) {\n        this.name = Objects.requireNonNull(name);\n        this.in = Objects.requireNonNull(in);\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public In getIn() {\n        return in;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public Parameter setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public Boolean getRequired() {\n        return required;\n    }\n\n    public Parameter setRequired(Boolean required) {\n        this.required = required;\n        return this;\n    }\n\n    public Boolean getDeprecated() {\n        return deprecated;\n    }\n\n    public Parameter setDeprecated(Boolean deprecated) {\n        this.deprecated = deprecated;\n        return this;\n    }\n\n    public Boolean getAllowEmptyValue() {\n        return allowEmptyValue;\n    }\n\n    public Parameter setAllowEmptyValue(Boolean allowEmptyValue) {\n        this.allowEmptyValue = allowEmptyValue;\n        return this;\n    }\n\n    public Style getStyle() {\n        return style;\n    }\n\n    public Parameter setStyle(Style style) {\n        this.style = style;\n        return this;\n    }\n\n    public Boolean getExplode() {\n        return explode;\n    }\n\n    public Parameter setExplode(Boolean explode) {\n        this.explode = explode;\n        return this;\n    }\n\n    public Boolean getAllowReserved() {\n        return allowReserved;\n    }\n\n    public Parameter setAllowReserved(Boolean allowReserved) {\n        this.allowReserved = allowReserved;\n        return this;\n    }\n\n    public Schema getSchema() {\n        return schema;\n    }\n\n    public Parameter setSchema(Schema schema) {\n        this.schema = schema;\n        return this;\n    }\n\n    public Object getExample() {\n        return example;\n    }\n\n    public Parameter setExample(Object example) {\n        this.example = example;\n        return this;\n    }\n\n    public Map<String, Example> getExamples() {\n        return examples;\n    }\n\n    public Parameter setExamples(Map<String, Example> examples) {\n        this.examples = examples;\n        return this;\n    }\n\n    public Parameter addExample(String name, Example example) {\n        if (examples == null) {\n            examples = new LinkedHashMap<>();\n        }\n        examples.put(name, example);\n        return this;\n    }\n\n    public Parameter removeExample(String name) {\n        if (examples != null) {\n            examples.remove(name);\n        }\n        return this;\n    }\n\n    public Map<String, MediaType> getContents() {\n        return contents;\n    }\n\n    public Parameter setContents(Map<String, MediaType> contents) {\n        this.contents = contents;\n        return this;\n    }\n\n    public Parameter addContent(String name, MediaType content) {\n        if (contents == null) {\n            contents = new LinkedHashMap<>();\n        }\n        contents.put(name, content);\n        return this;\n    }\n\n    public Parameter removeContent(String name) {\n        if (contents != null) {\n            contents.remove(name);\n        }\n        return this;\n    }\n\n    public ParameterMeta getMeta() {\n        return meta;\n    }\n\n    public Parameter setMeta(ParameterMeta meta) {\n        this.meta = meta;\n        return this;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || obj.getClass() != Parameter.class) {\n            return false;\n        }\n        Parameter other = (Parameter) obj;\n        return name.equals(other.name) && in == other.in;\n    }\n\n    @Override\n    public int hashCode() {\n        return 31 * name.hashCode() + in.hashCode();\n    }\n\n    @Override\n    public Parameter clone() {\n        Parameter clone = super.clone();\n        clone.schema = clone(schema);\n        clone.examples = clone(examples);\n        clone.contents = clone(contents);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"name\", name);\n        write(node, \"in\", in.toString());\n        write(node, \"description\", description);\n        write(node, \"required\", required);\n        write(node, \"deprecated\", deprecated);\n        write(node, \"allowEmptyValue\", allowEmptyValue);\n        write(node, \"style\", style);\n        write(node, \"explode\", explode);\n        write(node, \"allowReserved\", allowReserved);\n        write(node, \"schema\", schema, context);\n        write(node, \"example\", example);\n        write(node, \"examples\", examples, context);\n        write(node, \"content\", contents, context);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic final class PathItem extends Node<PathItem> {\n\n    private String ref;\n    private String summary;\n    private String description;\n    private Map<HttpMethods, Operation> operations;\n    private List<Server> servers;\n    private List<Parameter> parameters;\n\n    public String getRef() {\n        return ref;\n    }\n\n    public PathItem setRef(String ref) {\n        this.ref = ref;\n        return this;\n    }\n\n    public String getSummary() {\n        return summary;\n    }\n\n    public PathItem setSummary(String summary) {\n        this.summary = summary;\n        return this;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public PathItem setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public Map<HttpMethods, Operation> getOperations() {\n        return operations;\n    }\n\n    public Operation getOperation(HttpMethods method) {\n        return operations == null ? null : operations.get(method);\n    }\n\n    public PathItem setOperations(Map<HttpMethods, Operation> operations) {\n        this.operations = operations;\n        return this;\n    }\n\n    public PathItem addOperation(HttpMethods method, Operation operation) {\n        if (operations == null) {\n            operations = new LinkedHashMap<>();\n        }\n        operations.put(method, operation);\n        return this;\n    }\n\n    public PathItem removeOperation(HttpMethods method) {\n        if (operations != null) {\n            operations.remove(method);\n        }\n        return this;\n    }\n\n    public List<Server> getServers() {\n        return servers;\n    }\n\n    public PathItem setServers(List<Server> servers) {\n        this.servers = servers;\n        return this;\n    }\n\n    public PathItem addServer(Server server) {\n        if (servers == null) {\n            servers = new ArrayList<>();\n        }\n        servers.add(server);\n        return this;\n    }\n\n    public PathItem removeServer(Server server) {\n        if (servers != null) {\n            servers.remove(server);\n        }\n        return this;\n    }\n\n    public List<Parameter> getParameters() {\n        return parameters;\n    }\n\n    public PathItem setParameters(List<Parameter> parameters) {\n        this.parameters = parameters;\n        return this;\n    }\n\n    public PathItem addParameter(Parameter parameter) {\n        List<Parameter> thisParameters = parameters;\n        if (thisParameters == null) {\n            parameters = thisParameters = new ArrayList<>();\n        } else {\n            for (int i = 0, size = thisParameters.size(); i < size; i++) {\n                Parameter tParameter = thisParameters.get(i);\n                if (tParameter.getName().equals(parameter.getName())) {\n                    return this;\n                }\n            }\n        }\n        thisParameters.add(parameter);\n        return this;\n    }\n\n    public PathItem removeParameter(Parameter parameter) {\n        if (parameters != null) {\n            parameters.remove(parameter);\n        }\n        return this;\n    }\n\n    @Override\n    public PathItem clone() {\n        PathItem clone = super.clone();\n        clone.operations = clone(operations);\n        clone.servers = clone(servers);\n        clone.parameters = clone(parameters);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        if (ref != null) {\n            write(node, \"$ref\", Helper.pathToRef(ref));\n        } else if (operations != null) {\n            write(node, \"summary\", summary);\n            write(node, \"description\", description);\n            for (Map.Entry<HttpMethods, Operation> entry : operations.entrySet()) {\n                write(node, entry.getKey().name().toLowerCase(), entry.getValue(), context);\n            }\n            write(node, \"servers\", servers, context);\n            write(node, \"parameters\", parameters, context);\n        }\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\npublic final class RequestBody extends Node<RequestBody> {\n\n    private String description;\n    private Map<String, MediaType> contents;\n    private boolean required;\n\n    public String getDescription() {\n        return description;\n    }\n\n    public RequestBody setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public Map<String, MediaType> getContents() {\n        return contents;\n    }\n\n    public MediaType getContent(String content) {\n        return contents == null ? null : contents.get(content);\n    }\n\n    public MediaType getOrAddContent(String content) {\n        if (contents == null) {\n            contents = new LinkedHashMap<>();\n        }\n        return contents.computeIfAbsent(content, k -> new MediaType());\n    }\n\n    public RequestBody setContents(Map<String, MediaType> contents) {\n        this.contents = contents;\n        return this;\n    }\n\n    public RequestBody addContent(String name, MediaType content) {\n        if (contents == null) {\n            contents = new LinkedHashMap<>();\n        }\n        contents.put(name, content);\n        return this;\n    }\n\n    public RequestBody removeContent(String name) {\n        if (contents != null) {\n            contents.remove(name);\n        }\n        return this;\n    }\n\n    public boolean isRequired() {\n        return required;\n    }\n\n    public RequestBody setRequired(boolean required) {\n        this.required = required;\n        return this;\n    }\n\n    @Override\n    public RequestBody clone() {\n        RequestBody clone = super.clone();\n        clone.contents = clone(contents);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"description\", description);\n        write(node, \"required\", required);\n        write(node, \"content\", contents, context);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\npublic final class Schema extends Node<Schema> {\n\n    public enum Type {\n        STRING(\"string\"),\n        INTEGER(\"integer\"),\n        NUMBER(\"number\"),\n        BOOLEAN(\"boolean\"),\n        OBJECT(\"object\"),\n        ARRAY(\"array\");\n\n        private final String value;\n\n        Type(String value) {\n            this.value = value;\n        }\n\n        @Override\n        public String toString() {\n            return value;\n        }\n\n        public Type of(String value) {\n            for (Type type : values()) {\n                if (type.value.equals(value)) {\n                    return type;\n                }\n            }\n            return STRING;\n        }\n    }\n\n    private String ref;\n    private String format;\n    private String name;\n    private String title;\n    private String description;\n    private Object defaultValue;\n    private BigDecimal multipleOf;\n    private BigDecimal maximum;\n    private Boolean exclusiveMaximum;\n    private BigDecimal minimum;\n    private Boolean exclusiveMinimum;\n    private Integer maxLength;\n    private Integer minLength;\n    private String pattern;\n    private Integer maxItems;\n    private Integer minItems;\n    private Boolean uniqueItems;\n    private Integer maxProperties;\n    private Integer minProperties;\n    private Boolean required;\n    private List<Object> enumeration;\n    private Type type;\n    private Schema items;\n    private Map<String, Schema> properties;\n    private Schema additionalPropertiesSchema;\n    private Boolean additionalPropertiesBoolean;\n    private Boolean readOnly;\n    private XML xml;\n    private ExternalDocs externalDocs;\n    private Object example;\n    private List<Schema> allOf;\n    private List<Schema> oneOf;\n    private List<Schema> anyOf;\n    private Schema not;\n    private Discriminator discriminator;\n    private Boolean nullable;\n    private Boolean writeOnly;\n    private Boolean deprecated;\n\n    private String group;\n    private String version;\n    private Class<?> javaType;\n    private transient Schema targetSchema;\n    private transient List<Schema> sourceSchemas;\n\n    public String getRef() {\n        return ref;\n    }\n\n    public Schema setRef(String ref) {\n        this.ref = ref;\n        return this;\n    }\n\n    public String getFormat() {\n        return format;\n    }\n\n    public Schema setFormat(String format) {\n        this.format = format;\n        return this;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public Schema setName(String name) {\n        this.name = name;\n        return this;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public Schema setTitle(String title) {\n        this.title = title;\n        return this;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public Schema setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public Object getDefaultValue() {\n        return defaultValue;\n    }\n\n    public Schema setDefaultValue(Object defaultValue) {\n        this.defaultValue = defaultValue;\n        return this;\n    }\n\n    public BigDecimal getMultipleOf() {\n        return multipleOf;\n    }\n\n    public Schema setMultipleOf(BigDecimal multipleOf) {\n        this.multipleOf = multipleOf;\n        return this;\n    }\n\n    public BigDecimal getMaximum() {\n        return maximum;\n    }\n\n    public Schema setMaximum(BigDecimal maximum) {\n        this.maximum = maximum;\n        return this;\n    }\n\n    public Boolean getExclusiveMaximum() {\n        return exclusiveMaximum;\n    }\n\n    public Schema setExclusiveMaximum(Boolean exclusiveMaximum) {\n        this.exclusiveMaximum = exclusiveMaximum;\n        return this;\n    }\n\n    public BigDecimal getMinimum() {\n        return minimum;\n    }\n\n    public Schema setMinimum(BigDecimal minimum) {\n        this.minimum = minimum;\n        return this;\n    }\n\n    public Boolean getExclusiveMinimum() {\n        return exclusiveMinimum;\n    }\n\n    public Schema setExclusiveMinimum(Boolean exclusiveMinimum) {\n        this.exclusiveMinimum = exclusiveMinimum;\n        return this;\n    }\n\n    public Integer getMaxLength() {\n        return maxLength;\n    }\n\n    public Schema setMaxLength(Integer maxLength) {\n        this.maxLength = maxLength;\n        return this;\n    }\n\n    public Integer getMinLength() {\n        return minLength;\n    }\n\n    public Schema setMinLength(Integer minLength) {\n        this.minLength = minLength;\n        return this;\n    }\n\n    public String getPattern() {\n        return pattern;\n    }\n\n    public Schema setPattern(String pattern) {\n        this.pattern = pattern;\n        return this;\n    }\n\n    public Integer getMaxItems() {\n        return maxItems;\n    }\n\n    public Schema setMaxItems(Integer maxItems) {\n        this.maxItems = maxItems;\n        return this;\n    }\n\n    public Integer getMinItems() {\n        return minItems;\n    }\n\n    public Schema setMinItems(Integer minItems) {\n        this.minItems = minItems;\n        return this;\n    }\n\n    public Boolean getUniqueItems() {\n        return uniqueItems;\n    }\n\n    public Schema setUniqueItems(Boolean uniqueItems) {\n        this.uniqueItems = uniqueItems;\n        return this;\n    }\n\n    public Integer getMaxProperties() {\n        return maxProperties;\n    }\n\n    public Schema setMaxProperties(Integer maxProperties) {\n        this.maxProperties = maxProperties;\n        return this;\n    }\n\n    public Integer getMinProperties() {\n        return minProperties;\n    }\n\n    public Schema setMinProperties(Integer minProperties) {\n        this.minProperties = minProperties;\n        return this;\n    }\n\n    public Boolean getRequired() {\n        return required;\n    }\n\n    public Schema setRequired(Boolean required) {\n        this.required = required;\n        return this;\n    }\n\n    public List<Object> getEnumeration() {\n        return enumeration;\n    }\n\n    public Schema setEnumeration(List<Object> enumeration) {\n        this.enumeration = enumeration;\n        return this;\n    }\n\n    public Schema addEnumeration(Object enumeration) {\n        if (this.enumeration == null) {\n            this.enumeration = new ArrayList<>();\n        }\n        this.enumeration.add(enumeration);\n        return this;\n    }\n\n    public Schema removeEnumeration(Object enumeration) {\n        if (this.enumeration != null) {\n            this.enumeration.remove(enumeration);\n        }\n        return this;\n    }\n\n    public Type getType() {\n        return type;\n    }\n\n    public Schema setType(Type type) {\n        this.type = type;\n        return this;\n    }\n\n    public Schema getItems() {\n        return items;\n    }\n\n    public Schema setItems(Schema items) {\n        this.items = items;\n        return this;\n    }\n\n    public Map<String, Schema> getProperties() {\n        return properties;\n    }\n\n    public Schema getProperty(String name) {\n        return properties == null ? null : properties.get(name);\n    }\n\n    public Schema setProperties(Map<String, Schema> properties) {\n        this.properties = properties;\n        return this;\n    }\n\n    public Schema addProperty(String name, Schema schema) {\n        if (schema == null) {\n            return this;\n        }\n        if (properties == null) {\n            properties = new LinkedHashMap<>();\n        }\n        properties.put(name, schema);\n        return this;\n    }\n\n    public Schema removeProperty(String name) {\n        if (properties != null) {\n            properties.remove(name);\n        }\n        return this;\n    }\n\n    public Schema getAdditionalPropertiesSchema() {\n        return additionalPropertiesSchema;\n    }\n\n    public Schema setAdditionalPropertiesSchema(Schema additionalPropertiesSchema) {\n        this.additionalPropertiesSchema = additionalPropertiesSchema;\n        return this;\n    }\n\n    public Boolean getAdditionalPropertiesBoolean() {\n        return additionalPropertiesBoolean;\n    }\n\n    public Schema setAdditionalPropertiesBoolean(Boolean additionalPropertiesBoolean) {\n        this.additionalPropertiesBoolean = additionalPropertiesBoolean;\n        return this;\n    }\n\n    public Boolean getReadOnly() {\n        return readOnly;\n    }\n\n    public Schema setReadOnly(Boolean readOnly) {\n        this.readOnly = readOnly;\n        return this;\n    }\n\n    public XML getXml() {\n        return xml;\n    }\n\n    public Schema setXml(XML xml) {\n        this.xml = xml;\n        return this;\n    }\n\n    public ExternalDocs getExternalDocs() {\n        return externalDocs;\n    }\n\n    public Schema setExternalDocs(ExternalDocs externalDocs) {\n        this.externalDocs = externalDocs;\n        return this;\n    }\n\n    public Object getExample() {\n        return example;\n    }\n\n    public Schema setExample(Object example) {\n        this.example = example;\n        return this;\n    }\n\n    public List<Schema> getAllOf() {\n        return allOf;\n    }\n\n    public Schema setAllOf(List<Schema> allOf) {\n        this.allOf = allOf;\n        return this;\n    }\n\n    public Schema addAllOf(Schema schema) {\n        if (allOf == null) {\n            allOf = new ArrayList<>();\n        }\n        allOf.add(schema);\n        return this;\n    }\n\n    public List<Schema> getOneOf() {\n        return oneOf;\n    }\n\n    public Schema setOneOf(List<Schema> oneOf) {\n        this.oneOf = oneOf;\n        return this;\n    }\n\n    public Schema addOneOf(Schema schema) {\n        if (oneOf == null) {\n            oneOf = new ArrayList<>();\n        }\n        oneOf.add(schema);\n        return this;\n    }\n\n    public List<Schema> getAnyOf() {\n        return anyOf;\n    }\n\n    public Schema setAnyOf(List<Schema> anyOf) {\n        this.anyOf = anyOf;\n        return this;\n    }\n\n    public Schema addAnyOf(Schema schema) {\n        if (anyOf == null) {\n            anyOf = new ArrayList<>();\n        }\n        anyOf.add(schema);\n        return this;\n    }\n\n    public Schema getNot() {\n        return not;\n    }\n\n    public Schema setNot(Schema not) {\n        this.not = not;\n        return this;\n    }\n\n    public Discriminator getDiscriminator() {\n        return discriminator;\n    }\n\n    public Schema setDiscriminator(Discriminator discriminator) {\n        this.discriminator = discriminator;\n        return this;\n    }\n\n    public Boolean getNullable() {\n        return nullable;\n    }\n\n    public Schema setNullable(Boolean nullable) {\n        this.nullable = nullable;\n        return this;\n    }\n\n    public Boolean getWriteOnly() {\n        return writeOnly;\n    }\n\n    public Schema setWriteOnly(Boolean writeOnly) {\n        this.writeOnly = writeOnly;\n        return this;\n    }\n\n    public Boolean getDeprecated() {\n        return deprecated;\n    }\n\n    public Schema setDeprecated(Boolean deprecated) {\n        this.deprecated = deprecated;\n        return this;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public Schema setGroup(String group) {\n        this.group = group;\n        return this;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public Schema setVersion(String version) {\n        this.version = version;\n        return this;\n    }\n\n    public Class<?> getJavaType() {\n        return javaType;\n    }\n\n    public Schema setJavaType(Class<?> javaType) {\n        this.javaType = javaType;\n        return this;\n    }\n\n    public Schema getTargetSchema() {\n        return targetSchema;\n    }\n\n    public Schema setTargetSchema(Schema targetSchema) {\n        this.targetSchema = targetSchema;\n        return this;\n    }\n\n    public List<Schema> getSourceSchemas() {\n        return sourceSchemas;\n    }\n\n    public Schema setSourceSchemas(List<Schema> sourceSchemas) {\n        this.sourceSchemas = sourceSchemas;\n        return this;\n    }\n\n    public void addSourceSchema(Schema sourceSchema) {\n        if (sourceSchemas == null) {\n            sourceSchemas = new LinkedList<>();\n        }\n        sourceSchemas.add(sourceSchema);\n    }\n\n    @Override\n    public Schema clone() {\n        Schema clone = super.clone();\n        if (enumeration != null) {\n            clone.enumeration = new ArrayList<>(enumeration);\n        }\n        clone.items = clone(items);\n        clone.properties = clone(properties);\n        clone.additionalPropertiesSchema = clone(additionalPropertiesSchema);\n        clone.xml = clone(xml);\n        clone.externalDocs = clone(externalDocs);\n        clone.allOf = clone(allOf);\n        clone.oneOf = clone(oneOf);\n        clone.anyOf = clone(anyOf);\n        clone.not = clone(not);\n        clone.discriminator = clone(discriminator);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> schema, Context context) {\n        if (ref != null) {\n            schema.put(\"$ref\", ref);\n        }\n        write(schema, \"format\", format);\n        write(schema, \"title\", title);\n        write(schema, \"description\", description);\n        write(schema, \"default\", defaultValue);\n        write(schema, \"multipleOf\", multipleOf);\n        write(schema, \"maximum\", maximum);\n        write(schema, \"exclusiveMaximum\", exclusiveMaximum);\n        write(schema, \"minimum\", minimum);\n        write(schema, \"exclusiveMinimum\", exclusiveMinimum);\n        write(schema, \"maxLength\", maxLength);\n        write(schema, \"minLength\", minLength);\n        write(schema, \"pattern\", pattern);\n        write(schema, \"maxItems\", maxItems);\n        write(schema, \"minItems\", minItems);\n        write(schema, \"uniqueItems\", uniqueItems);\n        write(schema, \"maxProperties\", maxProperties);\n        write(schema, \"minProperties\", minProperties);\n        write(schema, \"required\", required);\n        write(schema, \"enum\", enumeration);\n        if (type != null) {\n            if (context.isOpenAPI31()) {\n                if (nullable == null || !nullable) {\n                    write(schema, \"type\", type.toString());\n                } else {\n                    write(schema, \"type\", new String[] {type.toString(), \"null\"});\n                }\n            } else {\n                write(schema, \"type\", type.toString());\n                write(schema, \"nullable\", nullable);\n            }\n        }\n        write(schema, \"items\", items, context);\n        write(schema, \"properties\", properties, context);\n        if (additionalPropertiesBoolean == null) {\n            write(schema, \"additionalProperties\", additionalPropertiesSchema, context);\n        } else {\n            schema.put(\"additionalProperties\", additionalPropertiesBoolean);\n        }\n        write(schema, \"readOnly\", readOnly);\n        write(schema, \"xml\", xml, context);\n        write(schema, \"externalDocs\", externalDocs, context);\n        write(schema, \"example\", example);\n        write(schema, \"allOf\", allOf, context);\n        write(schema, \"oneOf\", oneOf, context);\n        write(schema, \"anyOf\", anyOf, context);\n        write(schema, \"not\", not, context);\n        write(schema, \"discriminator\", discriminator, context);\n        write(schema, \"writeOnly\", writeOnly);\n        write(schema, \"deprecated\", deprecated);\n        writeExtensions(schema);\n        if (javaType != null) {\n            schema.put(Constants.X_JAVA_CLASS, javaType.getName());\n        }\n        return schema;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic final class SecurityRequirement extends Node<SecurityRequirement> {\n\n    private Map<String, List<String>> requirements;\n\n    public Map<String, List<String>> getRequirements() {\n        return requirements;\n    }\n\n    public void setRequirements(Map<String, List<String>> requirements) {\n        this.requirements = requirements;\n    }\n\n    public SecurityRequirement addRequirement(String name, String... scope) {\n        return addRequirement(name, scope == null ? Collections.emptyList() : Arrays.asList(scope));\n    }\n\n    public SecurityRequirement addRequirement(String name, List<String> scopes) {\n        if (requirements == null) {\n            requirements = new LinkedHashMap<>();\n        }\n        if (scopes == null) {\n            scopes = Collections.emptyList();\n        }\n        requirements.put(name, scopes);\n        return this;\n    }\n\n    public void removeRequirement(String name) {\n        if (requirements != null) {\n            requirements.remove(name);\n        }\n    }\n\n    @Override\n    public SecurityRequirement clone() {\n        SecurityRequirement clone = super.clone();\n        if (requirements != null) {\n            Map<String, List<String>> requirements = newMap(this.requirements.size());\n            for (Map.Entry<String, List<String>> entry : this.requirements.entrySet()) {\n                requirements.put(entry.getKey(), new ArrayList<>(entry.getValue()));\n            }\n            clone.requirements = requirements;\n        }\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"requirements\", requirements);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.Map;\n\npublic final class SecurityScheme extends Node<SecurityScheme> {\n\n    public enum Type {\n        APIKEY(\"apiKey\"),\n        HTTP(\"http\"),\n        OAUTH2(\"oauth2\"),\n        MUTUAL_TLS(\"mutualTLS\"),\n        OPEN_ID_CONNECT(\"openIdConnect\");\n\n        private final String value;\n\n        Type(String value) {\n            this.value = value;\n        }\n\n        @Override\n        public String toString() {\n            return value;\n        }\n    }\n\n    public enum In {\n        COOKIE(\"cookie\"),\n        HEADER(\"header\"),\n        QUERY(\"query\");\n\n        private final String value;\n\n        In(String value) {\n            this.value = value;\n        }\n\n        @Override\n        public String toString() {\n            return value;\n        }\n    }\n\n    private Type type;\n    private String description;\n    private String name;\n    private In in;\n    private String scheme;\n    private String bearerFormat;\n    private OAuthFlows flows;\n    private String openIdConnectUrl;\n\n    public Type getType() {\n        return type;\n    }\n\n    public SecurityScheme setType(Type type) {\n        this.type = type;\n        return this;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public SecurityScheme setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public SecurityScheme setName(String name) {\n        this.name = name;\n        return this;\n    }\n\n    public In getIn() {\n        return in;\n    }\n\n    public SecurityScheme setIn(In in) {\n        this.in = in;\n        return this;\n    }\n\n    public String getScheme() {\n        return scheme;\n    }\n\n    public SecurityScheme setScheme(String scheme) {\n        this.scheme = scheme;\n        return this;\n    }\n\n    public String getBearerFormat() {\n        return bearerFormat;\n    }\n\n    public SecurityScheme setBearerFormat(String bearerFormat) {\n        this.bearerFormat = bearerFormat;\n        return this;\n    }\n\n    public OAuthFlows getFlows() {\n        return flows;\n    }\n\n    public SecurityScheme setFlows(OAuthFlows flows) {\n        this.flows = flows;\n        return this;\n    }\n\n    public String getOpenIdConnectUrl() {\n        return openIdConnectUrl;\n    }\n\n    public SecurityScheme setOpenIdConnectUrl(String openIdConnectUrl) {\n        this.openIdConnectUrl = openIdConnectUrl;\n        return this;\n    }\n\n    @Override\n    public SecurityScheme clone() {\n        SecurityScheme clone = super.clone();\n        clone.flows = clone(flows);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        if (type == null) {\n            return node;\n        }\n        write(node, \"type\", type.toString());\n        write(node, \"description\", description);\n        write(node, \"name\", name);\n        if (in != null) {\n            write(node, \"in\", in.toString());\n        }\n        write(node, \"scheme\", scheme);\n        write(node, \"bearerFormat\", bearerFormat);\n        write(node, \"flows\", flows, context);\n        write(node, \"openIdConnectUrl\", openIdConnectUrl);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\npublic final class Server extends Node<Server> {\n\n    private String url;\n    private String description;\n    private Map<String, ServerVariable> variables;\n\n    public String getUrl() {\n        return url;\n    }\n\n    public Server setUrl(String url) {\n        this.url = url;\n        return this;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public Server setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public Map<String, ServerVariable> getVariables() {\n        return variables;\n    }\n\n    public Server setVariables(Map<String, ServerVariable> variables) {\n        this.variables = variables;\n        return this;\n    }\n\n    public Server addVariable(String name, ServerVariable variable) {\n        if (variables == null) {\n            variables = new LinkedHashMap<>();\n        }\n        variables.put(name, variable);\n        return this;\n    }\n\n    public Server removeVariable(String name) {\n        if (variables != null) {\n            variables.remove(name);\n        }\n        return this;\n    }\n\n    @Override\n    public Server clone() {\n        Server clone = super.clone();\n        clone.variables = clone(variables);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"url\", url);\n        write(node, \"description\", description);\n        write(node, \"variables\", variables, context);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\npublic final class ServerVariable extends Node<ServerVariable> {\n\n    private List<String> enumeration;\n    private String defaultValue;\n    private String description;\n\n    public List<String> getEnumeration() {\n        return enumeration;\n    }\n\n    public ServerVariable setEnumeration(List<String> enumeration) {\n        this.enumeration = enumeration;\n        return this;\n    }\n\n    public ServerVariable addEnumeration(String value) {\n        if (enumeration == null) {\n            enumeration = new ArrayList<>();\n        }\n        enumeration.add(value);\n        return this;\n    }\n\n    public ServerVariable removeEnumeration(String value) {\n        if (enumeration != null) {\n            enumeration.remove(value);\n        }\n        return this;\n    }\n\n    public String getDefaultValue() {\n        return defaultValue;\n    }\n\n    public ServerVariable setDefaultValue(String defaultValue) {\n        this.defaultValue = defaultValue;\n        return this;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public ServerVariable setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    @Override\n    public ServerVariable clone() {\n        ServerVariable clone = super.clone();\n        if (enumeration != null) {\n            clone.enumeration = new ArrayList<>(enumeration);\n        }\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        write(node, \"enum\", enumeration);\n        write(node, \"default\", defaultValue);\n        write(node, \"description\", description);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.Map;\n\npublic final class Tag extends Node<Tag> {\n\n    private String name;\n    private String description;\n    private ExternalDocs externalDocs;\n\n    public String getName() {\n        return name;\n    }\n\n    public Tag setName(String name) {\n        this.name = name;\n        return this;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public Tag setDescription(String description) {\n        this.description = description;\n        return this;\n    }\n\n    public ExternalDocs getExternalDocs() {\n        return externalDocs;\n    }\n\n    public Tag setExternalDocs(ExternalDocs externalDocs) {\n        this.externalDocs = externalDocs;\n        return this;\n    }\n\n    @Override\n    public Tag clone() {\n        Tag clone = super.clone();\n        clone.externalDocs = clone(externalDocs);\n        return clone;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        node.put(\"name\", name);\n        node.put(\"description\", description);\n        write(node, \"externalDocs\", externalDocs, context);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.openapi.model;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context;\n\nimport java.util.Map;\n\npublic final class XML extends Node<XML> {\n\n    private String name;\n    private String namespace;\n    private String prefix;\n    private Boolean attribute;\n    private Boolean wrapped;\n\n    public String getName() {\n        return name;\n    }\n\n    public XML setName(String name) {\n        this.name = name;\n        return this;\n    }\n\n    public String getNamespace() {\n        return namespace;\n    }\n\n    public XML setNamespace(String namespace) {\n        this.namespace = namespace;\n        return this;\n    }\n\n    public String getPrefix() {\n        return prefix;\n    }\n\n    public XML setPrefix(String prefix) {\n        this.prefix = prefix;\n        return this;\n    }\n\n    public Boolean getAttribute() {\n        return attribute;\n    }\n\n    public XML setAttribute(Boolean attribute) {\n        this.attribute = attribute;\n        return this;\n    }\n\n    public Boolean getWrapped() {\n        return wrapped;\n    }\n\n    public XML setWrapped(Boolean wrapped) {\n        this.wrapped = wrapped;\n        return this;\n    }\n\n    @Override\n    public Map<String, Object> writeTo(Map<String, Object> node, Context context) {\n        node.put(\"name\", name);\n        writeExtensions(node);\n        return node;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.basic;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaPredicate;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\n\nimport static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setBoolValue;\nimport static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setValue;\nimport static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim;\n\n@Activate(order = 100)\npublic final class BasicOpenAPIDefinitionResolver\n        implements OpenAPIDefinitionResolver, OpenAPISchemaResolver, OpenAPISchemaPredicate {\n\n    private static final String HIDDEN = \"hidden\";\n\n    @Override\n    public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain) {\n        AnnotationMeta<?> annoMeta = serviceMeta.findAnnotation(Annotations.OpenAPI);\n        if (annoMeta == null) {\n            return chain.resolve(openAPI, serviceMeta);\n        }\n        if (annoMeta.getBoolean(HIDDEN)) {\n            return null;\n        }\n\n        Info info = openAPI.getInfo();\n        if (info == null) {\n            openAPI.setInfo(info = new Info());\n        }\n\n        Map<String, String> tags = Helper.toProperties(annoMeta.getStringArray(\"tags\"));\n        for (Map.Entry<String, String> entry : tags.entrySet()) {\n            openAPI.addTag(new Tag().setName(entry.getKey()).setDescription(entry.getValue()));\n        }\n\n        String group = trim(annoMeta.getString(\"group\"));\n        if (group != null) {\n            openAPI.setGroup(group);\n        }\n\n        String title = trim(annoMeta.getString(\"infoTitle\"));\n        if (title != null) {\n            info.setTitle(title);\n        }\n        String description = trim(annoMeta.getString(\"infoDescription\"));\n        if (description != null) {\n            info.setDescription(description);\n        }\n        String version = trim(annoMeta.getString(\"infoVersion\"));\n        if (version != null) {\n            info.setVersion(version);\n        }\n\n        String docDescription = trim(annoMeta.getString(\"docDescription\"));\n        String docUrl = trim(annoMeta.getString(\"docUrl\"));\n        if (docDescription != null || docUrl != null) {\n            openAPI.setExternalDocs(\n                    new ExternalDocs().setDescription(docDescription).setUrl(docUrl));\n        }\n\n        openAPI.setPriority(annoMeta.getNumber(\"order\"));\n        openAPI.setExtensions(Helper.toProperties(annoMeta.getStringArray(\"extensions\")));\n\n        return chain.resolve(openAPI, serviceMeta);\n    }\n\n    @Override\n    public Collection<HttpMethods> resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context) {\n        AnnotationMeta<?> annoMeta = methodMeta.findAnnotation(Annotations.Operation);\n        if (annoMeta == null) {\n            return null;\n        }\n        String method = trim(annoMeta.getString(\"method\"));\n        if (method == null) {\n            return null;\n        }\n        return Collections.singletonList(HttpMethods.of(method.toUpperCase()));\n    }\n\n    @Override\n    public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) {\n        AnnotationMeta<?> annoMeta = methodMeta.findAnnotation(Annotations.Operation);\n        if (annoMeta == null) {\n            return chain.resolve(operation, methodMeta, ctx);\n        }\n        if (annoMeta.getBoolean(HIDDEN)) {\n            return null;\n        }\n\n        String[] tags = trim(annoMeta.getStringArray(\"tags\"));\n        if (tags != null) {\n            operation.setTags(new LinkedHashSet<>(Arrays.asList(tags)));\n        }\n\n        String summary = trim(annoMeta.getValue());\n        if (summary == null) {\n            summary = trim(annoMeta.getString(\"summary\"));\n        }\n        operation\n                .setGroup(trim(annoMeta.getString(\"group\")))\n                .setVersion(trim(annoMeta.getString(\"version\")))\n                .setOperationId(trim(annoMeta.getString(\"id\")))\n                .setSummary(summary)\n                .setDescription(trim(annoMeta.getString(\"description\")))\n                .setDeprecated(annoMeta.getBoolean(\"deprecated\"))\n                .setExtensions(Helper.toProperties(annoMeta.getStringArray(\"extensions\")));\n\n        return chain.resolve(operation, methodMeta, ctx);\n    }\n\n    @Override\n    public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain) {\n        AnnotationMeta<?> annoMeta = parameter.getAnnotation(Annotations.Schema);\n        if (annoMeta == null) {\n            return chain.resolve(parameter, context);\n        }\n        if (annoMeta.getBoolean(HIDDEN)) {\n            return null;\n        }\n\n        Class<?> impl = annoMeta.getClass(\"implementation\");\n        Schema schema = impl == Void.class ? chain.resolve(parameter, context) : context.resolve(impl);\n\n        setValue(annoMeta, \"group\", schema::setGroup);\n        setValue(annoMeta, \"version\", schema::setVersion);\n        setValue(annoMeta, \"type\", v -> schema.setType(Type.valueOf(v)));\n        setValue(annoMeta, \"format\", schema::setFormat);\n        setValue(annoMeta, \"name\", schema::setName);\n        String title = trim(annoMeta.getValue());\n        schema.setTitle(title == null ? trim(annoMeta.getString(\"title\")) : title);\n        setValue(annoMeta, \"description\", schema::setDescription);\n        setValue(annoMeta, \"defaultValue\", schema::setDefaultValue);\n        setValue(annoMeta, \"max\", v -> schema.setMaxLength(Integer.parseInt(v)));\n        setValue(annoMeta, \"min\", v -> schema.setMinLength(Integer.parseInt(v)));\n        setValue(annoMeta, \"pattern\", schema::setPattern);\n        setValue(annoMeta, \"example\", schema::setExample);\n        String[] enumItems = trim(annoMeta.getStringArray(\"enumeration\"));\n        if (enumItems != null) {\n            schema.setEnumeration(Arrays.asList(enumItems));\n        }\n        setBoolValue(annoMeta, \"required\", schema::setRequired);\n        setBoolValue(annoMeta, \"readOnly\", schema::setReadOnly);\n        setBoolValue(annoMeta, \"writeOnly\", schema::setWriteOnly);\n        setBoolValue(annoMeta, \"nullable\", schema::setNullable);\n        setBoolValue(annoMeta, \"deprecated\", schema::setDeprecated);\n        schema.setExtensions(Helper.toProperties(annoMeta.getStringArray(\"extensions\")));\n\n        return chain.resolve(parameter, context);\n    }\n\n    @Override\n    public Boolean acceptProperty(BeanMeta bean, PropertyMeta property) {\n        AnnotationMeta<?> annoMeta = property.getAnnotation(Annotations.Schema);\n        return annoMeta == null ? null : annoMeta.getBoolean(HIDDEN);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.swagger;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.LRUCache;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta.ReturnParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\n\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.AnnotatedElement;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport com.github.therapi.runtimejavadoc.ClassJavadoc;\nimport com.github.therapi.runtimejavadoc.Comment;\nimport com.github.therapi.runtimejavadoc.CommentFormatter;\nimport com.github.therapi.runtimejavadoc.FieldJavadoc;\nimport com.github.therapi.runtimejavadoc.MethodJavadoc;\nimport com.github.therapi.runtimejavadoc.ParamJavadoc;\nimport com.github.therapi.runtimejavadoc.RuntimeJavadoc;\nimport com.github.therapi.runtimejavadoc.internal.MethodSignature;\nimport com.github.therapi.runtimejavadoc.internal.RuntimeJavadocHelper;\n\n@Activate(order = -10000, onClass = \"com.github.therapi.runtimejavadoc.RuntimeJavadoc\")\npublic class JavadocOpenAPIDefinitionResolver implements OpenAPIDefinitionResolver, OpenAPISchemaResolver {\n\n    private final LRUCache<Class<?>, WeakReference<ClassJavadocWrapper>> cache = new LRUCache<>(128);\n    private final CommentFormatter formatter = new CommentFormatter();\n\n    @Override\n    public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain) {\n        openAPI = chain.resolve(openAPI, serviceMeta);\n        if (openAPI == null) {\n            return null;\n        }\n\n        Info info = openAPI.getInfo();\n        if (info == null) {\n            openAPI.setInfo(info = new Info());\n        }\n\n        if (info.getSummary() != null || info.getDescription() != null) {\n            return openAPI;\n        }\n\n        ClassJavadoc javadoc = getClassJavadoc(serviceMeta.getType()).javadoc;\n        if (javadoc.isEmpty()) {\n            return openAPI;\n        }\n\n        populateComment(javadoc.getComment(), info::setSummary, info::setDescription);\n        return openAPI;\n    }\n\n    @Override\n    public Collection<HttpMethods> resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context) {\n        return null;\n    }\n\n    @Override\n    public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) {\n        operation = chain.resolve(operation, methodMeta, ctx);\n        if (operation == null) {\n            return null;\n        }\n\n        Method method = methodMeta.getMethod();\n        ClassJavadocWrapper javadoc = getClassJavadoc(method.getDeclaringClass());\n        if (javadoc.isEmpty()) {\n            return operation;\n        }\n\n        if (operation.getSummary() == null && operation.getDescription() == null) {\n            MethodJavadoc methodJavadoc = javadoc.getMethod(method);\n            if (methodJavadoc != null) {\n                populateComment(methodJavadoc.getComment(), operation::setSummary, operation::setDescription);\n            }\n        }\n\n        List<Parameter> parameters = operation.getParameters();\n        if (parameters != null) {\n            for (Parameter parameter : parameters) {\n                if (parameter.getDescription() != null) {\n                    continue;\n                }\n\n                ParameterMeta meta = parameter.getMeta();\n                if (!(meta instanceof MethodParameterMeta)) {\n                    continue;\n                }\n\n                populateComment(javadoc.getParameter(method, parameter.getName()), null, parameter::setDescription);\n            }\n        }\n\n        return operation;\n    }\n\n    @Override\n    public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain) {\n        Schema schema = chain.resolve(parameter, context);\n        if (schema == null) {\n            return null;\n        }\n\n        if (schema.getTitle() != null || schema.getDescription() != null) {\n            return schema;\n        }\n\n        Comment comment = null;\n        if (parameter instanceof MethodParameterMeta) {\n            MethodParameterMeta meta = (MethodParameterMeta) parameter;\n            Method method = meta.getMethod();\n            comment = getClassJavadoc(method.getDeclaringClass()).getParameter(method, parameter.getName());\n        } else if (parameter instanceof ReturnParameterMeta) {\n            ReturnParameterMeta meta = (ReturnParameterMeta) parameter;\n            Method method = meta.getMethod();\n            MethodJavadoc methodJavadoc =\n                    getClassJavadoc(method.getDeclaringClass()).getMethod(method);\n            if (methodJavadoc != null) {\n                comment = methodJavadoc.getReturns();\n            }\n        } else {\n            for (AnnotatedElement element : parameter.getAnnotatedElements()) {\n                if (element instanceof Class) {\n                    comment = getClassJavadoc((Class<?>) element).getClassComment();\n                } else if (element instanceof Field) {\n                    Field field = (Field) element;\n\n                    ClassJavadocWrapper javadoc = getClassJavadoc(field.getDeclaringClass());\n                    FieldJavadoc fieldJavadoc = javadoc.getField(field);\n                    if (fieldJavadoc != null) {\n                        comment = fieldJavadoc.getComment();\n                        break;\n                    }\n\n                    ParamJavadoc paramJavadoc = javadoc.getRecordComponent(field.getName());\n                    if (paramJavadoc != null) {\n                        comment = paramJavadoc.getComment();\n                        break;\n                    }\n                } else if (element instanceof Method) {\n                    Method method = (Method) element;\n\n                    ClassJavadocWrapper javadoc = getClassJavadoc(method.getDeclaringClass());\n                    MethodJavadoc methodJavadoc = javadoc.getMethod(method);\n\n                    if (methodJavadoc != null) {\n                        comment = methodJavadoc.getReturns();\n                        break;\n                    }\n                }\n            }\n        }\n\n        populateComment(comment, schema::setTitle, schema::setDescription);\n        return schema;\n    }\n\n    private ClassJavadocWrapper getClassJavadoc(Class<?> clazz) {\n        WeakReference<ClassJavadocWrapper> ref = cache.get(clazz);\n        ClassJavadocWrapper javadoc = ref == null ? null : ref.get();\n        if (javadoc == null) {\n            javadoc = new ClassJavadocWrapper(RuntimeJavadoc.getJavadoc(clazz));\n            cache.put(clazz, new WeakReference<>(javadoc));\n        }\n        return javadoc;\n    }\n\n    private void populateComment(Comment comment, Consumer<String> sConsumer, Consumer<String> dConsumer) {\n        if (comment == null) {\n            return;\n        }\n\n        String description = formatter.format(comment);\n        if (sConsumer == null) {\n            dConsumer.accept(description);\n            return;\n        }\n\n        String summary = getFirstSentence(description);\n        sConsumer.accept(summary);\n        if (description.equals(summary)) {\n            return;\n        }\n        dConsumer.accept(description);\n    }\n\n    private static String getFirstSentence(String text) {\n        if (StringUtils.isEmpty(text)) {\n            return text;\n        }\n        int pOpenIndex = text.indexOf(\"<p>\");\n        int pCloseIndex = text.indexOf(\"</p>\");\n        int dotIndex = text.indexOf(\".\");\n        if (pOpenIndex != -1) {\n            if (pOpenIndex == 0 && pCloseIndex != -1) {\n                if (dotIndex != -1) {\n                    return text.substring(3, Math.min(pCloseIndex, dotIndex));\n                }\n                return text.substring(3, pCloseIndex);\n            }\n            if (dotIndex != -1) {\n                return text.substring(0, Math.min(pOpenIndex, dotIndex));\n            }\n            return text.substring(0, pOpenIndex);\n        }\n        if (dotIndex != -1 && text.length() != dotIndex + 1 && Character.isWhitespace(text.charAt(dotIndex + 1))) {\n            return text.substring(0, dotIndex + 1);\n        }\n        return text;\n    }\n\n    private static final class ClassJavadocWrapper {\n\n        private static final Map<Field, Field> MAPPING = new LinkedHashMap<>();\n        private static Field PARAMS;\n\n        public final ClassJavadoc javadoc;\n        public Map<String, FieldJavadoc> fields;\n        public Map<MethodSignature, MethodJavadoc> methods;\n        public Map<String, ParamJavadoc> recordComponents;\n\n        static {\n            try {\n                Field[] fields = ClassJavadoc.class.getDeclaredFields();\n                Field[] wFields = ClassJavadocWrapper.class.getFields();\n                for (Field field : fields) {\n                    field.setAccessible(true);\n                    for (Field wField : wFields) {\n                        if (wField.getName().equals(field.getName())) {\n                            MAPPING.put(field, wField);\n                            break;\n                        }\n                    }\n                }\n                PARAMS = MethodJavadoc.class.getDeclaredField(\"params\");\n                PARAMS.setAccessible(true);\n            } catch (Throwable ignored) {\n            }\n        }\n\n        public ClassJavadocWrapper(ClassJavadoc javadoc) {\n            this.javadoc = javadoc;\n            try {\n                for (Map.Entry<Field, Field> entry : MAPPING.entrySet()) {\n                    entry.getValue().set(this, entry.getKey().get(javadoc));\n                }\n            } catch (Throwable ignored) {\n            }\n        }\n\n        public boolean isEmpty() {\n            return javadoc.isEmpty();\n        }\n\n        public Comment getClassComment() {\n            return javadoc.getComment();\n        }\n\n        public FieldJavadoc getField(Field field) {\n            if (fields == null) {\n                return null;\n            }\n            FieldJavadoc fieldJavadoc = fields.get(field.getName());\n            return fieldJavadoc == null || fieldJavadoc.isEmpty() ? null : fieldJavadoc;\n        }\n\n        public MethodJavadoc getMethod(Method method) {\n            if (methods == null) {\n                return null;\n            }\n            MethodJavadoc methodJavadoc = methods.get(MethodSignature.from(method));\n            if (methodJavadoc != null && !methodJavadoc.isEmpty()) {\n                return methodJavadoc;\n            }\n            Method bridgeMethod = RuntimeJavadocHelper.findBridgeMethod(method);\n            if (bridgeMethod != null && bridgeMethod != method) {\n                methodJavadoc = methods.get(MethodSignature.from(bridgeMethod));\n                if (methodJavadoc != null && !methodJavadoc.isEmpty()) {\n                    return methodJavadoc;\n                }\n            }\n            return null;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public Comment getParameter(Method method, String name) {\n            if (methods == null) {\n                return null;\n            }\n            MethodJavadoc methodJavadoc = methods.get(MethodSignature.from(method));\n            if (methodJavadoc == null || PARAMS == null) {\n                return null;\n            }\n            try {\n                Map<String, ParamJavadoc> params = (Map<String, ParamJavadoc>) PARAMS.get(methodJavadoc);\n                ParamJavadoc paramJavadoc = params.get(name);\n                if (paramJavadoc != null) {\n                    return paramJavadoc.getComment();\n                }\n            } catch (Throwable ignored) {\n            }\n            return null;\n        }\n\n        public ParamJavadoc getRecordComponent(String name) {\n            return recordComponents == null ? null : recordComponents.get(name);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.swagger;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.nested.OpenAPIConfig;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.HttpResult;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.exception.HttpStatusException;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.ConfigFactory;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequestHandler;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\n@Activate\npublic class RedocRequestHandler implements OpenAPIRequestHandler {\n\n    private static final String DEFAULT_CDN = \"https://cdn.redoc.ly/redoc/latest/bundles\";\n    private static final String INDEX_PATH = \"/META-INF/resources/redoc/index.html\";\n\n    private final ConfigFactory configFactory;\n\n    private OpenAPIConfig config;\n\n    public RedocRequestHandler(FrameworkModel frameworkModel) {\n        configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class);\n    }\n\n    private OpenAPIConfig getConfig() {\n        if (config == null) {\n            config = configFactory.getGlobalConfig();\n        }\n        return config;\n    }\n\n    @Override\n    public String[] getPaths() {\n        return new String[] {\"/redoc/{*path}\"};\n    }\n\n    @Override\n    public HttpResult<?> handle(String path, HttpRequest request, HttpResponse response) {\n        String resPath = RequestUtils.getPathVariable(request, \"path\");\n        if (StringUtils.isEmpty(resPath)) {\n            throw HttpResult.found(PathUtils.join(request.path(), \"index.html\")).toPayload();\n        }\n        String requestPath = StringUtils.substringBeforeLast(resPath, '.');\n        if (requestPath.equals(\"index\")) {\n            return handleIndex(request.parameter(\"group\", Constants.DEFAULT_GROUP));\n        } else if (WebjarHelper.ENABLED && requestPath.startsWith(\"assets/\")) {\n            return WebjarHelper.getInstance().handleAssets(\"redoc\", resPath.substring(7));\n        }\n        throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode());\n    }\n\n    private HttpResult<?> handleIndex(String group) {\n        Map<String, String> variables = new HashMap<>(4);\n\n        OpenAPIConfig config = getConfig();\n        String cdn = config.getSetting(\"redoc.cdn\");\n        if (cdn == null) {\n            if (WebjarHelper.ENABLED && WebjarHelper.getInstance().hasWebjar(\"redoc\")) {\n                cdn = \"./assets\";\n            } else {\n                cdn = DEFAULT_CDN;\n            }\n        }\n        variables.put(\"redoc.cdn\", cdn);\n        variables.put(\"group\", group);\n        try {\n            String content = StreamUtils.toString(getClass().getResourceAsStream(INDEX_PATH));\n            return HttpResult.of(Helper.render(content, variables::get).getBytes(UTF_8));\n        } catch (IOException e) {\n            throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR.getCode(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.swagger;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaPredicate;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Contact;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.License;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport io.swagger.v3.oas.annotations.ExternalDocumentation;\nimport io.swagger.v3.oas.annotations.Hidden;\nimport io.swagger.v3.oas.annotations.OpenAPIDefinition;\nimport io.swagger.v3.oas.annotations.extensions.ExtensionProperty;\nimport io.swagger.v3.oas.annotations.media.Schema.AccessMode;\nimport io.swagger.v3.oas.annotations.media.Schema.RequiredMode;\n\nimport static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setValue;\nimport static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim;\n\n@Activate(order = 50, onClass = \"io.swagger.v3.oas.annotations.OpenAPIDefinition\")\npublic final class SwaggerOpenAPIDefinitionResolver\n        implements OpenAPIDefinitionResolver, OpenAPISchemaResolver, OpenAPISchemaPredicate {\n\n    @Override\n    public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain) {\n        AnnotationMeta<OpenAPIDefinition> annoMeta = serviceMeta.findAnnotation(OpenAPIDefinition.class);\n        if (annoMeta == null) {\n            return chain.resolve(openAPI, serviceMeta);\n        }\n        if (serviceMeta.isHierarchyAnnotated(Hidden.class)) {\n            return null;\n        }\n\n        OpenAPIDefinition anno = annoMeta.getAnnotation();\n\n        Info info = openAPI.getInfo();\n        if (info == null) {\n            openAPI.setInfo(info = new Info());\n        }\n\n        io.swagger.v3.oas.annotations.info.Info infoAnn = anno.info();\n        info.setTitle(trim(infoAnn.title()))\n                .setDescription(trim(infoAnn.description()))\n                .setVersion(trim(infoAnn.version()))\n                .setExtensions(toProperties(infoAnn.extensions()));\n\n        Contact contact = new Contact();\n        info.setContact(contact);\n        io.swagger.v3.oas.annotations.info.Contact contactAnn = infoAnn.contact();\n        contact.setName(trim(contactAnn.name()))\n                .setEmail(trim(contactAnn.email()))\n                .setUrl(trim(contactAnn.url()))\n                .setExtensions(toProperties(contactAnn.extensions()));\n\n        License license = new License();\n        info.setLicense(license);\n        io.swagger.v3.oas.annotations.info.License licenseAnn = infoAnn.license();\n        license.setName(trim(licenseAnn.name()))\n                .setUrl(trim(licenseAnn.url()))\n                .setExtensions(toProperties(licenseAnn.extensions()));\n\n        for (io.swagger.v3.oas.annotations.tags.Tag tagAnn : anno.tags()) {\n            openAPI.addTag(new Tag()\n                    .setName(trim(tagAnn.name()))\n                    .setDescription(trim(tagAnn.description()))\n                    .setExternalDocs(toExternalDocs(tagAnn.externalDocs()))\n                    .setExtensions(toProperties(tagAnn.extensions())));\n        }\n\n        openAPI.setExternalDocs(toExternalDocs(anno.externalDocs()));\n\n        Map<String, String> properties = toProperties(anno.extensions());\n        if (properties != null) {\n            String group = properties.remove(Constants.X_API_GROUP);\n            if (group != null) {\n                openAPI.setGroup(group);\n            }\n            openAPI.setExtensions(properties);\n        }\n\n        return chain.resolve(openAPI, serviceMeta);\n    }\n\n    private static Map<String, String> toProperties(io.swagger.v3.oas.annotations.extensions.Extension[] extensions) {\n        int len = extensions.length;\n        if (len == 0) {\n            return null;\n        }\n        Map<String, String> properties = CollectionUtils.newLinkedHashMap(extensions.length);\n        for (io.swagger.v3.oas.annotations.extensions.Extension extension : extensions) {\n            for (ExtensionProperty property : extension.properties()) {\n                properties.put(property.name(), property.value());\n            }\n        }\n        return properties;\n    }\n\n    private static ExternalDocs toExternalDocs(ExternalDocumentation anno) {\n        return new ExternalDocs()\n                .setDescription(trim(anno.description()))\n                .setUrl(trim(anno.url()))\n                .setExtensions(toProperties(anno.extensions()));\n    }\n\n    @Override\n    public Collection<HttpMethods> resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context) {\n        AnnotationMeta<io.swagger.v3.oas.annotations.Operation> annoMeta =\n                methodMeta.findAnnotation(io.swagger.v3.oas.annotations.Operation.class);\n        if (annoMeta == null) {\n            return null;\n        }\n        String method = trim(annoMeta.getAnnotation().method());\n        if (method == null) {\n            return null;\n        }\n        return Collections.singletonList(HttpMethods.of(method.toUpperCase()));\n    }\n\n    @Override\n    public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) {\n        AnnotationMeta<io.swagger.v3.oas.annotations.Operation> annoMeta =\n                methodMeta.findAnnotation(io.swagger.v3.oas.annotations.Operation.class);\n        if (annoMeta == null) {\n            return chain.resolve(operation, methodMeta, ctx);\n        }\n        io.swagger.v3.oas.annotations.Operation anno = annoMeta.getAnnotation();\n        if (anno.hidden() || methodMeta.isHierarchyAnnotated(Hidden.class)) {\n            return null;\n        }\n\n        String method = trim(anno.method());\n        if (method != null) {\n            operation.setHttpMethod(HttpMethods.of(method.toUpperCase()));\n        }\n        for (String tag : anno.tags()) {\n            operation.addTag(tag);\n        }\n        Map<String, String> properties = toProperties(anno.extensions());\n        if (properties != null) {\n            String group = properties.remove(Constants.X_API_GROUP);\n            if (group != null) {\n                operation.setGroup(group);\n            }\n            String version = properties.remove(Constants.X_API_VERSION);\n            if (version != null) {\n                operation.setVersion(version);\n            }\n            operation.setExtensions(properties);\n        }\n        operation\n                .setSummary(trim(anno.summary()))\n                .setDescription(trim(anno.description()))\n                .setExternalDocs(toExternalDocs(anno.externalDocs()))\n                .setOperationId(trim(anno.operationId()))\n                .setDeprecated(anno.deprecated() ? Boolean.TRUE : null);\n\n        return chain.resolve(operation, methodMeta, ctx);\n    }\n\n    @Override\n    public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain) {\n        AnnotationMeta<io.swagger.v3.oas.annotations.media.Schema> annoMeta =\n                parameter.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class);\n        if (annoMeta == null) {\n            return chain.resolve(parameter, context);\n        }\n        io.swagger.v3.oas.annotations.media.Schema anno = annoMeta.getAnnotation();\n        if (anno.hidden() || parameter.isHierarchyAnnotated(Hidden.class)) {\n            return null;\n        }\n        Schema schema = chain.resolve(parameter, context);\n        if (schema == null) {\n            return null;\n        }\n\n        Map<String, String> properties = toProperties(anno.extensions());\n        if (properties != null) {\n            String group = properties.remove(Constants.X_API_GROUP);\n            if (group != null) {\n                schema.setGroup(group);\n            }\n            String version = properties.remove(Constants.X_API_VERSION);\n            if (version != null) {\n                schema.setVersion(version);\n            }\n            schema.setExtensions(properties);\n        }\n\n        setValue(anno::type, v -> schema.setType(Type.valueOf(v)));\n        setValue(anno::format, schema::setFormat);\n        setValue(anno::name, schema::setName);\n        setValue(anno::title, schema::setTitle);\n        setValue(anno::description, schema::setDescription);\n        setValue(anno::defaultValue, schema::setDefaultValue);\n        setValue(anno::pattern, schema::setPattern);\n        setValue(anno::example, schema::setExample);\n        String[] enumItems = trim(anno.allowableValues());\n        if (enumItems != null) {\n            schema.setEnumeration(Arrays.asList(enumItems));\n        }\n        schema.setRequired(anno.requiredMode() == RequiredMode.REQUIRED ? Boolean.TRUE : null);\n        schema.setReadOnly(anno.accessMode() == AccessMode.READ_ONLY ? Boolean.TRUE : null);\n        schema.setWriteOnly(anno.accessMode() == AccessMode.WRITE_ONLY ? Boolean.TRUE : null);\n        schema.setNullable(anno.nullable() ? Boolean.TRUE : null);\n        schema.setDeprecated(anno.deprecated() ? Boolean.TRUE : null);\n\n        return chain.resolve(parameter, context);\n    }\n\n    @Override\n    public Boolean acceptProperty(BeanMeta bean, PropertyMeta property) {\n        AnnotationMeta<io.swagger.v3.oas.annotations.media.Schema> meta =\n                bean.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class);\n        if (meta == null) {\n            return null;\n        }\n        io.swagger.v3.oas.annotations.media.Schema schema = meta.getAnnotation();\n        return schema.hidden() || bean.isHierarchyAnnotated(Hidden.class) ? false : null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.swagger;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.nested.OpenAPIConfig;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.HttpResult;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.exception.HttpStatusException;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIService;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.ConfigFactory;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper;\nimport org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequestHandler;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\n@Activate\npublic class SwaggerUIRequestHandler implements OpenAPIRequestHandler {\n\n    private static final String DEFAULT_CDN = \"https://unpkg.com/swagger-ui-dist@5.18.2\";\n    private static final String INDEX_PATH = \"/META-INF/resources/swagger-ui/index.html\";\n\n    private final FrameworkModel frameworkModel;\n    private final ConfigFactory configFactory;\n\n    private OpenAPIConfig config;\n\n    public SwaggerUIRequestHandler(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n        configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class);\n    }\n\n    private OpenAPIConfig getConfig() {\n        if (config == null) {\n            config = configFactory.getGlobalConfig();\n        }\n        return config;\n    }\n\n    @Override\n    public String[] getPaths() {\n        return new String[] {\"/swagger-ui/{*path}\"};\n    }\n\n    @Override\n    public HttpResult<?> handle(String path, HttpRequest request, HttpResponse response) {\n        String resPath = RequestUtils.getPathVariable(request, \"path\");\n        if (StringUtils.isEmpty(resPath)) {\n            throw HttpResult.found(PathUtils.join(request.uri(), \"index.html\")).toPayload();\n        }\n        String requestPath = StringUtils.substringBeforeLast(resPath, '.');\n        switch (requestPath) {\n            case \"index\":\n                return handleIndex();\n            case \"swagger-config\":\n                return handleSwaggerConfig();\n            default:\n                if (WebjarHelper.ENABLED && requestPath.startsWith(\"assets/\")) {\n                    return WebjarHelper.getInstance().handleAssets(\"swagger-ui\", resPath.substring(7));\n                }\n        }\n        throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode());\n    }\n\n    private HttpResult<?> handleIndex() {\n        Map<String, String> variables = new HashMap<>(4);\n\n        OpenAPIConfig config = getConfig();\n        String cdn = config.getSetting(\"swagger-ui.cdn\");\n        if (cdn == null) {\n            if (WebjarHelper.ENABLED && WebjarHelper.getInstance().hasWebjar(\"swagger-ui\")) {\n                cdn = \"./assets\";\n            } else {\n                cdn = DEFAULT_CDN;\n            }\n        }\n        variables.put(\"swagger-ui.cdn\", cdn);\n\n        Map<String, String> settings = config.getSettings();\n        if (settings != null) {\n            StringBuilder sb = new StringBuilder();\n            for (Map.Entry<String, String> entry : settings.entrySet()) {\n                String key = entry.getKey();\n                if (key.startsWith(\"swagger-ui.settings.\")) {\n                    sb.append(\",\\n            \\\"\")\n                            .append(key.substring(20))\n                            .append(\"\\\": \")\n                            .append(entry.getValue());\n                }\n            }\n            if (sb.length() > 0) {\n                variables.put(\"swagger-ui.settings\", sb.toString());\n            }\n        }\n\n        try {\n            String content = StreamUtils.toString(getClass().getResourceAsStream(INDEX_PATH));\n            return HttpResult.of(Helper.render(content, variables::get).getBytes(UTF_8));\n        } catch (IOException e) {\n            throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR.getCode(), e);\n        }\n    }\n\n    private HttpResult<?> handleSwaggerConfig() {\n        OpenAPIService openAPIService = frameworkModel.getBean(OpenAPIService.class);\n        if (openAPIService == null) {\n            return HttpResult.notFound();\n        }\n        Collection<String> groups = openAPIService.getOpenAPIGroups();\n        List<Map<String, String>> urls = new ArrayList<>();\n        for (String group : groups) {\n            Map<String, String> url = new LinkedHashMap<>(4);\n            url.put(\"name\", group);\n            url.put(\"url\", \"../api-docs/\" + group);\n            urls.add(url);\n        }\n\n        Map<String, Object> configMap = new LinkedHashMap<>();\n        configMap.put(\"urls\", urls);\n        return HttpResult.of(JsonUtils.toJson(configMap).getBytes(UTF_8));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.swagger;\n\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.remoting.http12.HttpResult;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.exception.HttpStatusException;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.webjars.WebJarVersionLocator;\n\npublic class WebjarHelper {\n\n    public static final boolean ENABLED = ClassUtils.isPresent(\"org.webjars.WebJarVersionLocator\");\n    private static volatile WebjarHelper INSTANCE;\n    private final WebJarVersionLocator locator = new WebJarVersionLocator();\n\n    public static WebjarHelper getInstance() {\n        if (INSTANCE == null) {\n            synchronized (WebjarHelper.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new WebjarHelper();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n\n    public HttpResult<?> handleAssets(String webjar, String path) {\n        try {\n            byte[] bytes = getWebjarResource(webjar, path);\n            if (bytes != null) {\n                return HttpResult.builder()\n                        .header(\"Cache-Control\", \"public, max-age=604800\")\n                        .body(bytes)\n                        .build();\n            }\n        } catch (IOException ignored) {\n        }\n        throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode());\n    }\n\n    public boolean hasWebjar(String webjar) {\n        return locator.version(webjar) != null;\n    }\n\n    private byte[] getWebjarResource(String webjar, String exactPath) throws IOException {\n        String fullPath = locator.fullPath(webjar, exactPath);\n        if (fullPath != null) {\n            InputStream is = WebJarVersionLocator.class.getClassLoader().getResourceAsStream(fullPath);\n            if (is != null) {\n                return StreamUtils.readBytes(is);\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "openapi=org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIScopeModelInitializer\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension",
    "content": "resolver-basic=org.apache.dubbo.rpc.protocol.tri.rest.support.basic.BasicOpenAPIDefinitionResolver\nresolver-swagger=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerOpenAPIDefinitionResolver\nresolver-javadoc=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.JavadocOpenAPIDefinitionResolver\nnaming-strategy-default=org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPINamingStrategy\nhandler-swagger-ui=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerUIRequestHandler\nhandler-redoc=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.RedocRequestHandler\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/redoc/index.html",
    "content": "<!-- Under a \"MIT License\" license, see https://github.com/Redocly/redoc/blob/main/LICENSE -->\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <title>Redoc</title>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link href=\"https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700\" rel=\"stylesheet\">\n    <style>\n        body {\n            margin: 0;\n            padding: 0;\n        }\n    </style>\n</head>\n<body>\n<redoc spec-url=\"../api-docs/{{group}}.json\"></redoc>\n<script src=\"{{redoc.cdn}}/redoc.standalone.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/swagger-ui/index.html",
    "content": "<!-- Under an \"Apache License 2.0\" license, see https://github.com/swagger-api/swagger-ui/blob/master/LICENSE -->\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Swagger UI</title>\n    <link rel=\"icon\" type=\"image/png\" href=\"{{swagger-ui.cdn}}/favicon-32x32.png\" sizes=\"32x32\" />\n    <link rel=\"icon\" type=\"image/png\" href=\"{{swagger-ui.cdn}}/favicon-16x16.png\" sizes=\"16x16\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{swagger-ui.cdn}}/swagger-ui.css\"/>\n    <style>\n        html {\n            box-sizing: border-box;\n            overflow: -moz-scrollbars-vertical;\n            overflow-y: scroll;\n        }\n        *, *:before, *:after {\n            box-sizing: inherit;\n        }\n        body {\n            margin: 0;\n            background: #fafafa;\n        }\n    </style>\n</head>\n\n<body>\n<div id=\"swagger-ui\"></div>\n<script src=\"{{swagger-ui.cdn}}/swagger-ui-bundle.js\" charset=\"UTF-8\"></script>\n<script src=\"{{swagger-ui.cdn}}/swagger-ui-standalone-preset.js\" charset=\"UTF-8\"></script>\n<script src=\"{{swagger-ui.cdn}}/swagger-initializer.js\" charset=\"UTF-8\"></script>\n<script>\n    window.onload = function () {\n        window.ui = SwaggerUIBundle({\n            url: \"\",\n            dom_id: '#swagger-ui',\n            deepLinking: true,\n            presets: [\n                SwaggerUIBundle.presets.apis,\n                SwaggerUIStandalonePreset\n            ],\n            plugins: [\n                SwaggerUIBundle.plugins.DownloadUrl\n            ],\n            layout: \"StandaloneLayout\",\n            \"configUrl\": \"./swagger-config\",\n            \"displayRequestDuration\": true,\n            \"operationsSorter\": \"method\"{{swagger-ui.settings}}\n        });\n    };\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-rest-spring</artifactId>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-triple-servlet</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>javax.servlet</groupId>\n      <artifactId>javax.servlet-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-context</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-web</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-webmvc</artifactId>\n      <optional>true</optional>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>javax.xml.bind</groupId>\n      <artifactId>jaxb-api</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.glassfish.jaxb</groupId>\n      <artifactId>jaxb-runtime</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n      <type>test-jar</type>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java-util</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.spockframework</groupId>\n      <artifactId>spock-core</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.codehaus.gmavenplus</groupId>\n        <artifactId>gmavenplus-plugin</artifactId>\n        <executions>\n          <execution>\n            <goals>\n              <goal>compileTests</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n\n  <profiles>\n    <profile>\n      <id>rpc-rest-test</id>\n      <dependencies>\n        <dependency>\n          <groupId>org.apache.dubbo.extensions</groupId>\n          <artifactId>dubbo-rpc-rest</artifactId>\n          <version>3.3.1</version>\n          <scope>test</scope>\n        </dependency>\n      </dependencies>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/AbstractSpringArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractAnnotationBaseArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Optional;\n\npublic abstract class AbstractSpringArgumentResolver extends AbstractAnnotationBaseArgumentResolver {\n\n    @Override\n    protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta<Annotation> anno) {\n        return new NamedValueMeta(\n                anno.getValue(),\n                param.getType() != Optional.class && Helper.isRequired(anno),\n                Helper.defaultValue(anno));\n    }\n\n    @Override\n    protected Object filterValue(Object value, NamedValueMeta meta) {\n        return StringUtils.EMPTY_STRING.equals(value) ? meta.defaultValue() : value;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/Annotations.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationEnum;\n\nimport java.lang.annotation.Annotation;\n\npublic enum Annotations implements AnnotationEnum {\n    RequestMapping,\n    PathVariable,\n    MatrixVariable,\n    RequestParam,\n    RequestHeader,\n    CookieValue,\n    RequestAttribute,\n    RequestPart,\n    RequestBody,\n    ModelAttribute,\n    BindParam,\n    ResponseStatus,\n    CrossOrigin,\n    ExceptionHandler,\n    HttpExchange(\"org.springframework.web.service.annotation.HttpExchange\"),\n    Nonnull(\"javax.annotation.Nonnull\");\n\n    private final String className;\n    private Class<Annotation> type;\n\n    Annotations() {\n        className = \"org.springframework.web.bind.annotation.\" + name();\n    }\n\n    Annotations(String className) {\n        this.className = className;\n    }\n\n    @Override\n    public String className() {\n        return className;\n    }\n\n    @Override\n    public Class<Annotation> type() {\n        if (type == null) {\n            type = loadType();\n        }\n        return type;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.Messages;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.ConstructorMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.lang.reflect.Modifier;\nimport java.util.Map;\n\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.validation.BindException;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.validation.DataBinder;\nimport org.springframework.web.bind.WebDataBinder;\n\nimport static org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.resolveConstructor;\n\nfinal class BeanArgumentBinder {\n\n    private static final Map<Class<?>, ConstructorMeta> CACHE = CollectionUtils.newConcurrentHashMap();\n\n    private final ArgumentResolver argumentResolver;\n    private final ConversionService conversionService;\n\n    BeanArgumentBinder(CompositeArgumentResolver argumentResolver, ConversionService conversionService) {\n        this.argumentResolver = argumentResolver;\n        this.conversionService = conversionService;\n    }\n\n    public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) {\n        String name = StringUtils.defaultIf(paramMeta.getName(), DataBinder.DEFAULT_OBJECT_NAME);\n        try {\n            Object bean = createBean(paramMeta, request, response);\n            WebDataBinder binder = new WebDataBinder(bean, name);\n            binder.setConversionService(conversionService);\n            binder.bind(new MutablePropertyValues(RequestUtils.getParametersMap(request)));\n            BindingResult result = binder.getBindingResult();\n            if (result.hasErrors()) {\n                throw new BindException(result);\n            }\n            return binder.getTarget();\n        } catch (Exception e) {\n            throw new RestException(e, Messages.ARGUMENT_BIND_ERROR, name, paramMeta.getType());\n        }\n    }\n\n    private Object createBean(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) {\n        Class<?> type = paramMeta.getActualType();\n        if (Modifier.isAbstract(type.getModifiers())) {\n            throw new IllegalStateException(Messages.ARGUMENT_COULD_NOT_RESOLVED.format(paramMeta.getDescription()));\n        }\n        ConstructorMeta ct = CACHE.computeIfAbsent(type, k -> {\n            try {\n                return resolveConstructor(paramMeta.getToolKit(), null, type);\n            } catch (IllegalArgumentException e) {\n                throw new IllegalStateException(Messages.ARGUMENT_COULD_NOT_RESOLVED.format(paramMeta.getDescription())\n                        + \", \" + e.getMessage());\n            }\n        });\n        ParameterMeta[] parameters = ct.getParameters();\n        int len = parameters.length;\n        if (len == 0) {\n            return ct.newInstance();\n        }\n        Object[] args = new Object[len];\n        for (int i = 0; i < len; i++) {\n            ParameterMeta parameter = parameters[i];\n            args[i] = parameter.isSimple() ? argumentResolver.resolve(parameter, request, response) : null;\n        }\n        return ct.newInstance(args);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractAnnotationBaseArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.BindParam\")\npublic final class BindParamArgumentResolver extends AbstractAnnotationBaseArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.BindParam.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Param;\n    }\n\n    @Override\n    protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta<Annotation> anno) {\n        return new NamedValueMeta(anno.getValue(), param.isAnnotated(Annotations.Nonnull));\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.parameter(meta.name());\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.parameterValues(meta.name());\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return RequestUtils.getParametersMap(request);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/ConfigurationWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Properties;\n\n@SuppressWarnings(\"serial\")\npublic final class ConfigurationWrapper extends Properties {\n\n    private final Configuration configuration;\n\n    ConfigurationWrapper(ApplicationModel applicationModel) {\n        configuration = applicationModel.modelEnvironment().getConfiguration();\n    }\n\n    @Override\n    public String getProperty(String key) {\n        Object value = configuration.getProperty(key);\n        return value == null ? null : value.toString();\n    }\n\n    @Override\n    public Object get(Object key) {\n        return configuration.getProperty(key == null ? null : key.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/CookieValueArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.http12.HttpCookie;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\n\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.CookieValue\")\npublic class CookieValueArgumentResolver extends AbstractSpringArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.CookieValue.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Cookie;\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.cookie(meta.name());\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        Collection<HttpCookie> cookies = request.cookies();\n        if (cookies.isEmpty()) {\n            return Collections.emptyList();\n        }\n        String name = meta.name();\n        List<HttpCookie> result = new ArrayList<>(cookies.size());\n        for (HttpCookie cookie : cookies) {\n            if (name.equals(cookie.name())) {\n                result.add(cookie);\n            }\n        }\n        return result;\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        Collection<HttpCookie> cookies = request.cookies();\n        if (cookies.isEmpty()) {\n            return Collections.emptyMap();\n        }\n        Map<String, List<HttpCookie>> mapValue = CollectionUtils.newLinkedHashMap(cookies.size());\n        for (HttpCookie cookie : cookies) {\n            mapValue.computeIfAbsent(cookie.name(), k -> new ArrayList<>()).add(cookie);\n        }\n        return mapValue;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;\n\n@Activate(order = Integer.MAX_VALUE - 10000, onClass = \"org.springframework.web.bind.annotation.RequestMapping\")\npublic class FallbackArgumentResolver extends AbstractArgumentResolver {\n\n    @Override\n    public boolean accept(ParameterMeta param) {\n        return param.getToolKit().getDialect() == RestConstants.DIALECT_SPRING_MVC;\n    }\n\n    @Override\n    protected NamedValueMeta createNamedValueMeta(ParameterMeta param) {\n        return new NamedValueMeta(null, param.isAnnotated(Annotations.Nonnull));\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        ParameterMeta parameter = meta.parameter();\n        if (parameter.isStream()) {\n            return null;\n        }\n        if (parameter.isSimple()) {\n            return request.parameter(meta.name());\n        }\n        return parameter.bind(request, response);\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        if (TypeUtils.isSimpleProperty(meta.nestedType(0))) {\n            return request.parameterValues(meta.name());\n        }\n        return null;\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        if (TypeUtils.isSimpleProperty(meta.nestedType(1))) {\n            return RequestUtils.getParametersMap(request);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/HandlerInterceptorAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.Listener;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RestUtils;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.util.Arrays;\n\nimport org.springframework.web.servlet.HandlerInterceptor;\nimport org.springframework.web.servlet.ModelAndView;\n\n@Activate(onClass = \"org.springframework.web.servlet.HandlerInterceptor\")\npublic final class HandlerInterceptorAdapter implements RestExtensionAdapter<HandlerInterceptor> {\n    @Override\n    public boolean accept(Object extension) {\n        return extension instanceof HandlerInterceptor;\n    }\n\n    @Override\n    public RestFilter adapt(HandlerInterceptor extension) {\n        return new HandlerInterceptorRestFilter(extension);\n    }\n\n    private static final class HandlerInterceptorRestFilter implements RestFilter, Listener {\n\n        private final HandlerInterceptor interceptor;\n\n        @Override\n        public int getPriority() {\n            return RestUtils.getPriority(interceptor);\n        }\n\n        @Override\n        public String[] getPatterns() {\n            return RestUtils.getPattens(interceptor);\n        }\n\n        public HandlerInterceptorRestFilter(HandlerInterceptor interceptor) {\n            this.interceptor = interceptor;\n        }\n\n        @Override\n        public void doFilter(HttpRequest request, HttpResponse response, FilterChain chain) throws Exception {\n            Object handler = request.attribute(RestConstants.HANDLER_ATTRIBUTE);\n            if (interceptor.preHandle((HttpServletRequest) request, (HttpServletResponse) response, handler)) {\n                chain.doFilter(request, response);\n            }\n        }\n\n        @Override\n        public void onResponse(Result result, HttpRequest request, HttpResponse response) throws Exception {\n            if (result.hasException()) {\n                onError(result.getException(), request, response);\n                return;\n            }\n            Object handler = request.attribute(RestConstants.HANDLER_ATTRIBUTE);\n            ModelAndView mv = new ModelAndView();\n            mv.addObject(\"result\", result);\n            interceptor.postHandle((HttpServletRequest) request, (HttpServletResponse) response, handler, mv);\n        }\n\n        @Override\n        public void onError(Throwable t, HttpRequest request, HttpResponse response) throws Exception {\n            Object handler = request.attribute(RestConstants.HANDLER_ATTRIBUTE);\n            Exception ex = t instanceof Exception ? (Exception) t : new RpcException(t);\n            interceptor.afterCompletion((HttpServletRequest) request, (HttpServletResponse) response, handler, ex);\n        }\n\n        @Override\n        public String toString() {\n            StringBuilder sb = new StringBuilder(\"RestFilter{interceptor=\");\n            sb.append(interceptor);\n            int priority = getPriority();\n            if (priority != 0) {\n                sb.append(\", priority=\").append(priority);\n            }\n            String[] patterns = getPatterns();\n            if (patterns != null) {\n                sb.append(\", patterns=\").append(Arrays.toString(patterns));\n            }\n            return sb.append('}').toString();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/Helper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\n\nimport org.springframework.core.SpringVersion;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.ValueConstants;\n\nfinal class Helper {\n\n    public static boolean IS_SPRING_6;\n\n    private static Method getStatusCode;\n    private static Method value;\n\n    private Helper() {}\n\n    static {\n        try {\n            String version = SpringVersion.getVersion();\n            IS_SPRING_6 = StringUtils.hasLength(version) && version.charAt(0) >= '6';\n        } catch (Throwable ignored) {\n        }\n    }\n\n    public static boolean isRequired(AnnotationMeta<Annotation> annotation) {\n        return annotation.getBoolean(\"required\");\n    }\n\n    public static String defaultValue(AnnotationMeta<Annotation> annotation) {\n        return defaultValue(annotation, \"defaultValue\");\n    }\n\n    public static String defaultValue(AnnotationMeta<Annotation> annotation, String name) {\n        return defaultValue(annotation.getString(name));\n    }\n\n    public static String defaultValue(String value) {\n        return ValueConstants.DEFAULT_NONE.equals(value) ? null : value;\n    }\n\n    public static int getStatusCode(ResponseEntity<?> entity) {\n        if (IS_SPRING_6) {\n            try {\n                if (getStatusCode == null) {\n                    getStatusCode = ResponseEntity.class.getMethod(\"getStatusCode\");\n                    value = getStatusCode.getReturnType().getMethod(\"value\");\n                }\n                return (Integer) value.invoke(getStatusCode.invoke(entity));\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return entity.getStatusCode().value();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.MatrixVariable\")\npublic class MatrixVariableArgumentResolver extends AbstractSpringArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.MatrixVariable.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.MatrixVariable;\n    }\n\n    @Override\n    protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta<Annotation> anno) {\n        return new MatrixNamedValueMeta(\n                anno.getValue(),\n                Helper.isRequired(anno),\n                Helper.defaultValue(anno),\n                Helper.defaultValue(anno, \"pathVar\"));\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return CollectionUtils.first(doResolveCollectionValue(meta, request));\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return doResolveCollectionValue(meta, request);\n    }\n\n    private static List<String> doResolveCollectionValue(NamedValueMeta meta, HttpRequest request) {\n        String name = meta.name();\n        Map<String, String> variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE);\n        if (variableMap == null) {\n            return Collections.emptyList();\n        }\n        List<String> result = null;\n        String pathVar = ((MatrixNamedValueMeta) meta).pathVar;\n        if (pathVar == null) {\n            result = RequestUtils.parseMatrixVariableValues(variableMap, name);\n        } else {\n            String value = variableMap.get(pathVar);\n            if (value != null) {\n                Map<String, List<String>> matrixVariables = RequestUtils.parseMatrixVariables(value);\n                if (matrixVariables != null) {\n                    List<String> values = matrixVariables.get(name);\n                    if (values != null) {\n                        return values;\n                    }\n                }\n            }\n        }\n        return result == null ? Collections.emptyList() : result;\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        Map<String, String> variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE);\n        if (variableMap == null) {\n            return Collections.emptyMap();\n        }\n        Map<String, List<String>> result = null;\n        String pathVar = ((MatrixNamedValueMeta) meta).pathVar;\n        if (pathVar == null) {\n            for (Map.Entry<String, String> entry : variableMap.entrySet()) {\n                Map<String, List<String>> matrixVariables = RequestUtils.parseMatrixVariables(entry.getValue());\n                if (matrixVariables == null) {\n                    continue;\n                }\n                if (result == null) {\n                    result = new HashMap<>();\n                }\n                for (Map.Entry<String, List<String>> matrixEntry : matrixVariables.entrySet()) {\n                    result.computeIfAbsent(matrixEntry.getKey(), k -> new ArrayList<>())\n                            .addAll(matrixEntry.getValue());\n                }\n            }\n        } else {\n            String value = variableMap.get(pathVar);\n            if (value != null) {\n                result = RequestUtils.parseMatrixVariables(value);\n            }\n        }\n        return result == null ? Collections.emptyMap() : result;\n    }\n\n    private static class MatrixNamedValueMeta extends NamedValueMeta {\n\n        private final String pathVar;\n\n        MatrixNamedValueMeta(String name, boolean required, String defaultValue, String pathVar) {\n            super(name, required, defaultValue);\n            this.pathVar = pathVar;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/ModelAttributeArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;\n\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.ModelAttribute\")\npublic final class ModelAttributeArgumentResolver extends AbstractSpringArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.ModelAttribute.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Param;\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        if (meta.parameter().isSimple()) {\n            return request.parameter(meta.name());\n        }\n        return meta.parameter().bind(request, response);\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        if (meta.parameter().isSimple()) {\n            return request.parameterValues(meta.name());\n        }\n        return meta.parameter().bind(request, response);\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        if (TypeUtils.isSimpleProperty(meta.nestedType(1))) {\n            return RequestUtils.getParametersMap(request);\n        }\n        return meta.parameter().bind(request, response);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MultiValueMapCreator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\n@Activate(onClass = \"org.springframework.util.MultiValueMap\")\npublic class MultiValueMapCreator implements ArgumentConverter<Integer, MultiValueMap<?, ?>> {\n\n    @Override\n    public MultiValueMap<?, ?> convert(Integer value, ParameterMeta parameter) {\n        return new LinkedMultiValueMap<>(value);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.Messages;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestParameterException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Map;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.PathVariable\")\npublic class PathVariableArgumentResolver implements AnnotationBaseArgumentResolver<Annotation> {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.PathVariable.type();\n    }\n\n    @Override\n    public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta<Annotation> annotation) {\n        return new NamedValueMeta(annotation.getValue(), true).setParamType(ParamType.PathVariable);\n    }\n\n    @Override\n    public Object resolve(\n            ParameterMeta parameter,\n            AnnotationMeta<Annotation> annotation,\n            HttpRequest request,\n            HttpResponse response) {\n        Map<String, String> variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE);\n        String name = annotation.getValue();\n        if (StringUtils.isEmpty(name)) {\n            name = parameter.getRequiredName();\n        }\n        if (variableMap == null) {\n            if (Helper.isRequired(annotation)) {\n                throw new RestParameterException(Messages.ARGUMENT_VALUE_MISSING, name, parameter.getType());\n            }\n            return null;\n        }\n        String value = variableMap.get(name);\n        if (value == null) {\n            return null;\n        }\n        int index = value.indexOf(';');\n        return RequestUtils.decodeURL(index == -1 ? value : value.substring(0, index));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestAttributeArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\n\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.RequestAttribute\")\npublic class RequestAttributeArgumentResolver extends AbstractSpringArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.RequestAttribute.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Attribute;\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.attribute(meta.name());\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.attributes();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.io.IOException;\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.RequestBody\")\npublic class RequestBodyArgumentResolver extends AbstractSpringArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.RequestBody.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Body;\n    }\n\n    @Override\n    protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta<Annotation> anno) {\n        return new NamedValueMeta(null, Helper.isRequired(anno));\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        if (RequestUtils.isFormOrMultiPart(request)) {\n            if (meta.parameter().isSimple()) {\n                return request.formParameter(meta.name());\n            }\n            return meta.parameter().bind(request, response);\n        }\n        return RequestUtils.decodeBody(request, meta.genericType());\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        Class<?> type = meta.type();\n        if (type == byte[].class) {\n            try {\n                return StreamUtils.readBytes(request.inputStream());\n            } catch (IOException e) {\n                throw new RestException(e);\n            }\n        }\n        if (RequestUtils.isFormOrMultiPart(request)) {\n            return request.formParameterValues(meta.name());\n        }\n        return RequestUtils.decodeBody(request, meta.genericType());\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        if (RequestUtils.isFormOrMultiPart(request)) {\n            return RequestUtils.getFormParametersMap(request);\n        }\n        return RequestUtils.decodeBody(request, meta.genericType());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestHeaderArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\n\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.RequestHeader\")\npublic final class RequestHeaderArgumentResolver extends AbstractSpringArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.RequestHeader.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Header;\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.header(meta.name());\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.headerValues(meta.name());\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.headers().asMap();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestParamArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport java.lang.annotation.Annotation;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.RequestParam\")\npublic final class RequestParamArgumentResolver extends AbstractSpringArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.RequestParam.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Param;\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.parameter(meta.name());\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.parameterValues(meta.name());\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return RequestUtils.getParametersMap(request);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpRequest.FileUpload;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.rest.ParamType;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.RequestPart\")\npublic class RequestPartArgumentResolver extends AbstractSpringArgumentResolver {\n\n    @Override\n    public Class<Annotation> accept() {\n        return Annotations.RequestPart.type();\n    }\n\n    @Override\n    protected ParamType getParamType(NamedValueMeta meta) {\n        return ParamType.Part;\n    }\n\n    @Override\n    protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta<Annotation> anno) {\n        return new NamedValueMeta(anno.getValue(), Helper.isRequired(anno));\n    }\n\n    @Override\n    protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return request.part(meta.name());\n    }\n\n    @Override\n    protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        return meta.type() == byte[].class ? request.part(meta.name()) : request.parts();\n    }\n\n    @Override\n    protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {\n        Collection<FileUpload> parts = request.parts();\n        if (parts.isEmpty()) {\n            return Collections.emptyMap();\n        }\n        Map<String, FileUpload> result = new LinkedHashMap<>(parts.size());\n        for (FileUpload part : parts) {\n            result.put(part.name(), part);\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RestSpringScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.utils.DefaultParameterNameReader;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.GeneralTypeConverter;\n\npublic class RestSpringScopeModelInitializer implements ScopeModelInitializer {\n    @Override\n    public void initializeFrameworkModel(FrameworkModel frameworkModel) {\n        ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();\n        beanFactory.registerBean(GeneralTypeConverter.class);\n        beanFactory.registerBean(DefaultParameterNameReader.class);\n        beanFactory.registerBean(CompositeArgumentResolver.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringMiscArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.context.request.NativeWebRequest;\nimport org.springframework.web.context.request.ServletWebRequest;\nimport org.springframework.web.context.request.WebRequest;\n\n@Activate(onClass = \"org.springframework.web.context.request.WebRequest\")\npublic class SpringMiscArgumentResolver implements ArgumentResolver {\n\n    private static final Set<Class<?>> SUPPORTED_TYPES = new HashSet<>();\n\n    static {\n        SUPPORTED_TYPES.add(WebRequest.class);\n        SUPPORTED_TYPES.add(NativeWebRequest.class);\n        SUPPORTED_TYPES.add(HttpEntity.class);\n        SUPPORTED_TYPES.add(HttpHeaders.class);\n    }\n\n    @Override\n    public boolean accept(ParameterMeta parameter) {\n        return SUPPORTED_TYPES.contains(parameter.getActualType());\n    }\n\n    @Override\n    public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse response) {\n        Class<?> type = parameter.getActualType();\n        if (type == WebRequest.class || type == NativeWebRequest.class) {\n            return new ServletWebRequest((HttpServletRequest) request);\n        }\n        if (type == HttpEntity.class) {\n            return new HttpEntity<>(\n                    CollectionUtils.toMultiValueMap(request.headers().asMap()));\n        }\n        if (type == HttpHeaders.class) {\n            return new HttpHeaders(\n                    CollectionUtils.toMultiValueMap(request.headers().asMap()));\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringMvcRequestMappingResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.nested.RestConfig;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.cors.CorsUtils;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping.Builder;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.CorsMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit;\n\nimport org.springframework.http.HttpStatus;\n\n@Activate(onClass = \"org.springframework.web.bind.annotation.RequestMapping\")\npublic class SpringMvcRequestMappingResolver implements RequestMappingResolver {\n\n    private final RestToolKit toolKit;\n    private RestConfig restConfig;\n    private CorsMeta globalCorsMeta;\n\n    public SpringMvcRequestMappingResolver(FrameworkModel frameworkModel) {\n        toolKit = new SpringRestToolKit(frameworkModel);\n    }\n\n    @Override\n    public void setRestConfig(RestConfig restConfig) {\n        this.restConfig = restConfig;\n    }\n\n    @Override\n    public RestToolKit getRestToolKit() {\n        return toolKit;\n    }\n\n    @Override\n    public RequestMapping resolve(ServiceMeta serviceMeta) {\n        AnnotationMeta<?> requestMapping = serviceMeta.findMergedAnnotation(Annotations.RequestMapping);\n        AnnotationMeta<?> httpExchange = serviceMeta.findMergedAnnotation(Annotations.HttpExchange);\n        if (requestMapping == null && httpExchange == null) {\n            return null;\n        }\n\n        String[] methods = requestMapping == null\n                ? httpExchange.getStringArray(\"method\")\n                : requestMapping.getStringArray(\"method\");\n        String[] paths = requestMapping == null ? httpExchange.getValueArray() : requestMapping.getValueArray();\n        return builder(requestMapping, httpExchange, serviceMeta.findMergedAnnotation(Annotations.ResponseStatus))\n                .method(methods)\n                .name(serviceMeta.getType().getSimpleName())\n                .path(paths)\n                .contextPath(serviceMeta.getContextPath())\n                .cors(buildCorsMeta(serviceMeta.findMergedAnnotation(Annotations.CrossOrigin), methods))\n                .build();\n    }\n\n    @Override\n    public RequestMapping resolve(MethodMeta methodMeta) {\n        AnnotationMeta<?> requestMapping = methodMeta.findMergedAnnotation(Annotations.RequestMapping);\n        AnnotationMeta<?> httpExchange = methodMeta.findMergedAnnotation(Annotations.HttpExchange);\n        if (requestMapping == null && httpExchange == null) {\n            AnnotationMeta<?> exceptionHandler = methodMeta.getAnnotation(Annotations.ExceptionHandler);\n            if (exceptionHandler != null) {\n                methodMeta.initParameters();\n                methodMeta.getServiceMeta().addExceptionHandler(methodMeta);\n            }\n            return null;\n        }\n\n        ServiceMeta serviceMeta = methodMeta.getServiceMeta();\n        String name = methodMeta.getMethodName();\n        String[] methods = requestMapping == null\n                ? httpExchange.getStringArray(\"method\")\n                : requestMapping.getStringArray(\"method\");\n        String[] paths = requestMapping == null ? httpExchange.getValueArray() : requestMapping.getValueArray();\n        if (paths.length == 0) {\n            paths = new String[] {'/' + name};\n        }\n        return builder(requestMapping, httpExchange, methodMeta.findMergedAnnotation(Annotations.ResponseStatus))\n                .method(methods)\n                .name(name)\n                .path(paths)\n                .contextPath(serviceMeta.getContextPath())\n                .service(serviceMeta.getServiceGroup(), serviceMeta.getServiceVersion())\n                .cors(buildCorsMeta(methodMeta.findMergedAnnotation(Annotations.CrossOrigin), methods))\n                .build();\n    }\n\n    private Builder builder(\n            AnnotationMeta<?> requestMapping, AnnotationMeta<?> httpExchange, AnnotationMeta<?> responseStatus) {\n        Builder builder = RequestMapping.builder();\n        if (responseStatus != null) {\n            HttpStatus value = responseStatus.getEnum(\"value\");\n            builder.responseStatus(value.value());\n            String reason = responseStatus.getString(\"reason\");\n            if (StringUtils.isNotEmpty(reason)) {\n                builder.responseReason(reason);\n            }\n        }\n        if (requestMapping == null) {\n            return builder.consume(httpExchange.getStringArray(\"contentType\"))\n                    .produce(httpExchange.getStringArray(\"accept\"));\n        }\n        return builder.param(requestMapping.getStringArray(\"params\"))\n                .header(requestMapping.getStringArray(\"headers\"))\n                .consume(requestMapping.getStringArray(\"consumes\"))\n                .produce(requestMapping.getStringArray(\"produces\"));\n    }\n\n    private CorsMeta buildCorsMeta(AnnotationMeta<?> crossOrigin, String[] methods) {\n        if (globalCorsMeta == null) {\n            globalCorsMeta = CorsUtils.getGlobalCorsMeta(restConfig);\n        }\n        if (crossOrigin == null) {\n            return globalCorsMeta;\n        }\n        String[] allowedMethods = crossOrigin.getStringArray(\"methods\");\n        if (allowedMethods.length == 0) {\n            allowedMethods = methods;\n            if (allowedMethods.length == 0) {\n                allowedMethods = new String[] {CommonConstants.ANY_VALUE};\n            }\n        }\n        CorsMeta corsMeta = CorsMeta.builder()\n                .allowedOrigins(crossOrigin.getStringArray(\"origins\"))\n                .allowedMethods(allowedMethods)\n                .allowedHeaders(crossOrigin.getStringArray(\"allowedHeaders\"))\n                .exposedHeaders(crossOrigin.getStringArray(\"exposedHeaders\"))\n                .allowCredentials(crossOrigin.getString(\"allowCredentials\"))\n                .maxAge(crossOrigin.getNumber(\"maxAge\"))\n                .build();\n        return globalCorsMeta.combine(corsMeta);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.Pair;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.HttpResult;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.Listener;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ResponseMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseStatus;\n\n@Activate(order = -10000, onClass = \"org.springframework.http.ResponseEntity\")\npublic class SpringResponseRestFilter implements RestFilter, Listener {\n\n    private final ArgumentResolver argumentResolver;\n    private final Map<Key, Optional<MethodMeta>> cache = CollectionUtils.newConcurrentHashMap();\n\n    public SpringResponseRestFilter(FrameworkModel frameworkModel) {\n        argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class);\n    }\n\n    @Override\n    public void onResponse(Result result, HttpRequest request, HttpResponse response) {\n        if (result.hasException()) {\n            HandlerMeta handler = request.attribute(RestConstants.HANDLER_ATTRIBUTE);\n            if (handler == null) {\n                return;\n            }\n\n            Throwable t = result.getException();\n            Key key = new Key(handler.getMethod().getMethod(), t.getClass());\n            cache.computeIfAbsent(key, k -> findSuitableExceptionHandler(handler.getService(), k.type))\n                    .ifPresent(m -> {\n                        try {\n                            result.setValue(invokeExceptionHandler(m, t, request, response));\n                            result.setException(null);\n                        } catch (Throwable th) {\n                            result.setException(th);\n                        }\n                    });\n            return;\n        }\n\n        Object value = result.getValue();\n        if (value instanceof ResponseEntity) {\n            ResponseEntity<?> entity = (ResponseEntity<?>) value;\n            result.setValue(HttpResult.builder()\n                    .body(entity.getBody())\n                    .status(Helper.getStatusCode(entity))\n                    .headers(entity.getHeaders())\n                    .build());\n            return;\n        }\n\n        RequestMapping mapping = request.attribute(RestConstants.MAPPING_ATTRIBUTE);\n        if (mapping == null) {\n            return;\n        }\n        ResponseMeta responseMeta = mapping.getResponse();\n        if (responseMeta == null) {\n            return;\n        }\n        String reason = responseMeta.getReason();\n        result.setValue(HttpResult.builder()\n                .body(reason == null ? result.getValue() : reason)\n                .status(responseMeta.getStatus())\n                .build());\n    }\n\n    private Optional<MethodMeta> findSuitableExceptionHandler(ServiceMeta serviceMeta, Class<?> exType) {\n        if (serviceMeta.getExceptionHandlers() == null) {\n            return Optional.empty();\n        }\n        List<Pair<Class<?>, MethodMeta>> candidates = new ArrayList<>();\n        for (MethodMeta methodMeta : serviceMeta.getExceptionHandlers()) {\n            ExceptionHandler anno = methodMeta.getMethod().getAnnotation(ExceptionHandler.class);\n            if (anno == null) {\n                continue;\n            }\n            for (Class<?> type : anno.value()) {\n                if (type.isAssignableFrom(exType)) {\n                    candidates.add(Pair.of(type, methodMeta));\n                }\n            }\n        }\n        int size = candidates.size();\n        if (size == 0) {\n            return Optional.empty();\n        }\n        if (size > 1) {\n            candidates.sort((o1, o2) -> {\n                Class<?> c1 = o1.getLeft();\n                Class<?> c2 = o2.getLeft();\n                if (c1.equals(c2)) {\n                    return 0;\n                }\n                return c1.isAssignableFrom(c2) ? 1 : -1;\n            });\n        }\n        return Optional.of(candidates.get(0).getRight());\n    }\n\n    private Object invokeExceptionHandler(MethodMeta meta, Throwable t, HttpRequest request, HttpResponse response) {\n        ParameterMeta[] parameters = meta.getParameters();\n        int len = parameters.length;\n        Object[] args = new Object[len];\n        for (int i = 0; i < len; i++) {\n            ParameterMeta parameter = parameters[i];\n            if (parameter.getType().isInstance(t)) {\n                args[i] = t;\n            } else {\n                args[i] = argumentResolver.resolve(parameter, request, response);\n            }\n        }\n        Object value;\n        try {\n            value = meta.getMethod().invoke(meta.getServiceMeta().getService(), args);\n        } catch (Exception e) {\n            throw new RestException(\"Failed to invoke exception handler method: \" + meta.getMethod(), e);\n        }\n        AnnotationMeta<?> rs = meta.getAnnotation(ResponseStatus.class);\n        if (rs == null) {\n            return value;\n        }\n        HttpStatus status = rs.getEnum(\"value\");\n        String reason = rs.getString(\"reason\");\n        return HttpResult.builder()\n                .body(StringUtils.isEmpty(reason) ? value : reason)\n                .status(status.value())\n                .build();\n    }\n\n    private static final class Key {\n        private final Method method;\n        private final Class<?> type;\n\n        Key(Method method, Class<?> type) {\n            this.method = method;\n            this.type = type;\n        }\n\n        @Override\n        @SuppressWarnings({\"EqualsWhichDoesntCheckParameterClass\", \"EqualsDoesntCheckParameterClass\"})\n        public boolean equals(Object obj) {\n            Key other = (Key) obj;\n            return method.equals(other.method) && type.equals(other.type);\n        }\n\n        @Override\n        public int hashCode() {\n            return method.hashCode() * 31 + type.hashCode();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.DefaultParameterNameReader;\nimport org.apache.dubbo.common.utils.ParameterNameReader;\nimport org.apache.dubbo.config.spring.extension.SpringExtensionInjector;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.Messages;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.GeneralTypeConverter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.TypeConverter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RestUtils;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.AnnotatedElement;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.util.PropertyPlaceholderHelper;\n\nfinal class SpringRestToolKit implements RestToolKit {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(SpringRestToolKit.class);\n\n    private final Map<MethodParameterMeta, TypeDescriptor> cache = CollectionUtils.newConcurrentHashMap();\n    private final ConfigurableBeanFactory beanFactory;\n    private final PropertyPlaceholderHelper placeholderHelper;\n    private final ConfigurationWrapper configuration;\n    private final ConversionService conversionService;\n    private final TypeConverter typeConverter;\n    private final BeanArgumentBinder argumentBinder;\n    private final ParameterNameReader parameterNameReader;\n    private final CompositeArgumentResolver argumentResolver;\n\n    public SpringRestToolKit(FrameworkModel frameworkModel) {\n        ApplicationModel applicationModel = frameworkModel.defaultApplication();\n        SpringExtensionInjector injector = SpringExtensionInjector.get(applicationModel);\n        ApplicationContext context = injector.getContext();\n        if (context instanceof ConfigurableApplicationContext) {\n            beanFactory = ((ConfigurableApplicationContext) context).getBeanFactory();\n            placeholderHelper = null;\n            configuration = null;\n        } else {\n            beanFactory = null;\n            placeholderHelper = new PropertyPlaceholderHelper(\"${\", \"}\", \":\", true);\n            configuration = new ConfigurationWrapper(applicationModel);\n        }\n        if (context != null && context.containsBean(\"mvcConversionService\")) {\n            conversionService = context.getBean(\"mvcConversionService\", ConversionService.class);\n        } else {\n            conversionService = DefaultConversionService.getSharedInstance();\n        }\n        typeConverter = frameworkModel.getOrRegisterBean(GeneralTypeConverter.class);\n        parameterNameReader = frameworkModel.getOrRegisterBean(DefaultParameterNameReader.class);\n        argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class);\n        argumentBinder = new BeanArgumentBinder(argumentResolver, conversionService);\n    }\n\n    @Override\n    public int getDialect() {\n        return RestConstants.DIALECT_SPRING_MVC;\n    }\n\n    @Override\n    public String resolvePlaceholders(String text) {\n        if (!RestUtils.hasPlaceholder(text)) {\n            return text;\n        }\n        if (beanFactory != null) {\n            return beanFactory.resolveEmbeddedValue(text);\n        }\n        return placeholderHelper.replacePlaceholders(text, configuration);\n    }\n\n    @Override\n    public Object convert(Object value, ParameterMeta parameter) {\n        boolean tried = false;\n        if (value instanceof Collection || value instanceof Map) {\n            tried = true;\n            Object target = typeConverter.convert(value, parameter.getGenericType());\n            if (target != null) {\n                return target;\n            }\n        }\n        if (parameter instanceof MethodParameterMeta) {\n            TypeDescriptor targetType = cache.computeIfAbsent(\n                    (MethodParameterMeta) parameter,\n                    k -> new TypeDescriptor(new MethodParameter(k.getMethod(), k.getIndex())));\n            TypeDescriptor sourceType = TypeDescriptor.forObject(value);\n            if (conversionService.canConvert(sourceType, targetType)) {\n                try {\n                    return conversionService.convert(value, sourceType, targetType);\n                } catch (Throwable t) {\n                    LOGGER.debug(\n                            \"Spring convert value '{}' from type [{}] to type [{}] failed\",\n                            value,\n                            value.getClass(),\n                            parameter.getGenericType(),\n                            t);\n                }\n            }\n        }\n        Object target = tried ? null : typeConverter.convert(value, parameter.getGenericType());\n        if (target == null && value != null) {\n            throw new RestException(\n                    Messages.ARGUMENT_CONVERT_ERROR,\n                    parameter.getName(),\n                    value,\n                    value.getClass(),\n                    parameter.getGenericType());\n        }\n        return target;\n    }\n\n    @Override\n    public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) {\n        return argumentBinder.bind(parameter, request, response);\n    }\n\n    @Override\n    public NamedValueMeta getNamedValueMeta(ParameterMeta parameter) {\n        return argumentResolver.getNamedValueMeta(parameter);\n    }\n\n    @Override\n    public String[] getParameterNames(Method method) {\n        return parameterNameReader.readParameterNames(method);\n    }\n\n    @Override\n    public String[] getParameterNames(Constructor<?> ctor) {\n        return parameterNameReader.readParameterNames(ctor);\n    }\n\n    @Override\n    public Map<String, Object> getAttributes(AnnotatedElement element, Annotation annotation) {\n        return AnnotatedElementUtils.getMergedAnnotationAttributes(element, annotation.annotationType());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "rest-spring=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.RestSpringScopeModelInitializer\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter",
    "content": "multi-value-map-creator=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.MultiValueMapCreator\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver",
    "content": "spring-path-variable=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.PathVariableArgumentResolver\nspring-matrix-variable=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.MatrixVariableArgumentResolver\nspring-request-param=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.RequestParamArgumentResolver\nspring-request-header=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.RequestHeaderArgumentResolver\nspring-cookie-value=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.CookieValueArgumentResolver\nspring-request-attribute=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.RequestAttributeArgumentResolver\nspring-request-part=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.RequestPartArgumentResolver\nspring-request-body=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.RequestBodyArgumentResolver\nspring-model-attribute=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.ModelAttributeArgumentResolver\nspring-bind-param=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.BindParamArgumentResolver\nspring-misc=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.SpringMiscArgumentResolver\nspring-fallback=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.FallbackArgumentResolver\n\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension",
    "content": "spring-response=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.SpringResponseRestFilter\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter",
    "content": "spring-interceptor=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.HandlerInterceptorAdapter\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver",
    "content": "spring=org.apache.dubbo.rpc.protocol.tri.rest.support.spring.SpringMvcRequestMappingResolver\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RestProtocolTest.groovy",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring\n\nimport org.apache.dubbo.remoting.http12.message.MediaType\nimport org.apache.dubbo.rpc.protocol.tri.rest.service.Book\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.spring.service.SpringDemoServiceImpl\nimport org.apache.dubbo.rpc.protocol.tri.rest.support.spring.service.SpringDemoService\nimport org.apache.dubbo.rpc.protocol.tri.rest.test.BaseServiceTest\nimport org.apache.dubbo.rpc.protocol.tri.test.TestRequest\nimport org.apache.dubbo.rpc.protocol.tri.test.TestRunnerBuilder\n\nclass RestProtocolTest extends BaseServiceTest {\n\n    @Override\n    void setupService(TestRunnerBuilder builder) {\n        builder.provider(SpringDemoService.class, new SpringDemoServiceImpl())\n    }\n\n    def \"hello world\"() {\n        expect:\n            runner.get(path) == output\n        where:\n            path                           | output\n            '/spring/hello?name=world'     | 'hello world'\n            '/spring/hello/?name=world'    | 'hello world'\n            '/spring/hello.yml?name=world' | 'hello world'\n    }\n\n    def \"list argument body test\"() {\n        expect:\n            runner.post(path, body) contains output\n        where:\n            path                            | body    | output\n            '/spring/listArgBodyTest?age=2' | '[1,2]' | '[1,2]'\n    }\n\n    def \"map argument body test\"() {\n        expect:\n            def actual = runner.post(path, body)\n            actual.contains('1:[2,3]') && actual.contains('4:[5,6]')\n        where:\n            path                           | body                        | output\n            '/spring/mapArgBodyTest?age=2' | '{\"1\":[\"2\",3],\"4\":[5,\"6\"]}' | '{4:[5,6],1:[2,3]}'\n    }\n\n    def \"bean argument get test\"() {\n        expect:\n            runner.get(path, Book.class).price == output\n        where:\n            path                          | output\n            '/spring/beanArgTest'         | 0\n            '/spring/beanArgTest?quote=5' | 5\n    }\n\n    def \"bean argument post test\"() {\n        expect:\n            runner.post(path, body, Book.class).price == output\n        where:\n            path                   | body           | output\n            '/spring/beanArgTest'  | [:]            | 0\n            '/spring/beanArgTest'  | [price: 6]     | 6\n            '/spring/beanArgTest2' | '{\"price\": 5}' | 5\n    }\n\n    def \"spring bean argument test\"() {\n        expect:\n            runner.get(path) contains output\n        where:\n            path                                                                             | output\n            '/spring/bean?id=1&name=sam'                                                     | '\"id\":1,\"name\":\"sam\"'\n            '/spring/bean?name=sam&phone=123&email=a@b.com'                                  | '\"email\":\"a@b.com\",\"name\":\"sam\",\"phone\":\"123\"'\n            '/spring/bean?group.name=g1&group.owner.name=jack'                               | '\"group\":{\"id\":0,\"name\":\"g1\",\"owner\":{\"name\":\"jack\"'\n            '/spring/bean?group.parent.parent.children[0].name=xx'                           | '\"group\":{\"id\":0,\"parent\":{\"id\":0,\"parent\":{\"children\":[{\"id\":0,\"name\":\"xx\"}],\"id\":0}}}'\n            '/spring/bean?ids=3&ids=4'                                                       | '\"ids\":[3,4]'\n            '/spring/bean?ids[]=3&ids[]=4'                                                   | '\"ids\":[3,4]'\n            '/spring/bean?ids[1]=3&ids[2]=4'                                                 | '\"ids\":[0,3,4]'\n            '/spring/bean?scores=3&scores=4'                                                 | '\"scores\":[3,4]'\n            '/spring/bean?scores[]=3&scores[]=4'                                             | '\"scores\":[3,4]'\n            '/spring/bean?scores[1]=3&scores[2]=4'                                           | '\"scores\":[null,3,4]'\n            '/spring/bean?tags[0].name=a&tags[0].value=b&tags[1].name=c&tags[1].value=d'     | '\"tags\":[{\"name\":\"a\",\"value\":\"b\"},{\"name\":\"c\",\"value\":\"d\"}]'\n            '/spring/bean?tagsA[0].name=a&tagsA[0].value=b&tagsA[1].name=c&tagsA[1].value=d' | '\"tagsA\":[{\"name\":\"a\",\"value\":\"b\"},{\"name\":\"c\",\"value\":\"d\"}]'\n            '/spring/bean?tagsB[0].name=e&tagsB[1].name=c&tagsB[1].value=d'                  | '\"tagsB\":[{\"name\":\"e\",\"value\":\"b\"},{\"name\":\"c\",\"value\":\"d\"}]'\n            '/spring/bean?tagsC[0].name=e&tagsC[1].name=c&tagsC[1].value=d'                  | '\"tagsC\":[{\"name\":\"e\",\"value\":\"b\"},{\"name\":\"c\",\"value\":\"d\"}]'\n            '/spring/bean?id=1&features[a]=xx&features[b]=2'                                 | '\"features\":{\"a\":\"xx\",\"b\":\"2\"}'\n            '/spring/bean?tagMapB[2].name=a&tagMapB[2].value=b&tagMapB[3].name=c'            | '\"tagMapB\":{2:{\"name\":\"a\",\"value\":\"b\"},3:{\"name\":\"c\"}}'\n    }\n\n    def \"bean body test\"() {\n        expect:\n            runner.post(path, body) contains output\n        where:\n            path                         | body                                          | output\n            '/spring/beanBodyTest?age=2' | '[{\"id\":1,\"name\":\"g1\"},{\"id\":2,\"name\":\"g2\"}]' | '[{\"id\":1,\"name\":\"g1\"},{\"id\":2,\"name\":\"g2\"}]'\n    }\n\n    def \"multiValueMap test\"() {\n        expect:\n            runner.get(path) contains output\n        where:\n            path                                            | output\n            '/spring/multiValueMapTest?name=1&name=2&age=8' | '{\"name\":[1,2],\"age\":[8]}'\n    }\n\n    def \"urlEncodeForm test\"() {\n        given:\n            def request = new TestRequest(\n                path: path,\n                contentType: MediaType.APPLICATION_FROM_URLENCODED,\n                params: [\n                    'name': 'Sam',\n                    'age' : 8\n                ]\n            )\n        expect:\n            runner.post(request) == output\n        where:\n            path              | output\n            '/spring/argTest' | 'Sam is 8 years old'\n    }\n\n    def \"no interface method test\"() {\n        expect:\n            runner.get(path) contains output\n        where:\n            path                            | output\n            '/spring/noInterface'           | 'ok'\n            '/spring/noInterfaceAndMapping' | '404'\n    }\n\n    def \"use interface argument name test\"() {\n        expect:\n            runner.get(path) contains output\n        where:\n            path                           | output\n            '/spring/argNameTest?name=Sam' | 'Sam'\n    }\n\n    def \"pb server stream test\"() {\n        expect:\n            runner.posts(path, body).size() == output\n        where:\n            path                     | body               | output\n            '/spring/pbServerStream' | '{\"service\": \"3\"}' | 3\n            '/spring/pbServerStream' | '{}'               | 0\n    }\n\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/compatible/SpringDemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring.compatible;\n\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.web.bind.annotation.CrossOrigin;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\n\n@CrossOrigin\npublic class SpringDemoServiceImpl implements SpringRestDemoService {\n    private static Map<String, Object> context;\n    private boolean called;\n\n    @Override\n    public String sayHello(String name) {\n        called = true;\n        return \"Hello, \" + name;\n    }\n\n    @Override\n    public boolean isCalled() {\n        return called;\n    }\n\n    @Override\n    public String testFormBody(User user) {\n        return user.getName();\n    }\n\n    @Override\n    public List<String> testFormMapBody(LinkedMultiValueMap map) {\n        return map.get(\"form\");\n    }\n\n    @Override\n    public String testHeader(String header) {\n        return header;\n    }\n\n    @Override\n    public String testHeaderInt(int header) {\n        return String.valueOf(header);\n    }\n\n    @Override\n    public Integer hello(Integer a, Integer b) {\n        context = RpcContext.getServerAttachment().getObjectAttachments();\n        return a + b;\n    }\n\n    @Override\n    public String error() {\n        throw new RuntimeException();\n    }\n\n    @ExceptionHandler(RuntimeException.class)\n    public String onError(HttpRequest request, Throwable t) {\n        return \"ok\";\n    }\n\n    @ExceptionHandler(Exception.class)\n    public String onError1() {\n        return \"ok1\";\n    }\n\n    public static Map<String, Object> getAttachments() {\n        return context;\n    }\n\n    @Override\n    public int primitiveInt(int a, int b) {\n        return a + b;\n    }\n\n    @Override\n    public long primitiveLong(long a, Long b) {\n        return a + b;\n    }\n\n    @Override\n    public long primitiveByte(byte a, Long b) {\n        return a + b;\n    }\n\n    @Override\n    public long primitiveShort(short a, Long b, int c) {\n        return a + b;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/compatible/SpringMvcRestProtocolTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring.compatible;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleServiceRepository;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\n\nimport java.util.Arrays;\n\nimport org.hamcrest.CoreMatchers;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.aop.framework.AdvisedSupport;\nimport org.springframework.aop.framework.AopProxy;\nimport org.springframework.aop.framework.ProxyCreatorSupport;\nimport org.springframework.util.LinkedMultiValueMap;\n\nimport static org.apache.dubbo.remoting.Constants.SERVER_KEY;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Disabled\npublic class SpringMvcRestProtocolTest {\n    private final Protocol tProtocol =\n            ApplicationModel.defaultModel().getExtensionLoader(Protocol.class).getExtension(\"tri\");\n    private final Protocol protocol =\n            ApplicationModel.defaultModel().getExtensionLoader(Protocol.class).getExtension(\"rest\");\n    private final ProxyFactory proxy = ApplicationModel.defaultModel()\n            .getExtensionLoader(ProxyFactory.class)\n            .getAdaptiveExtension();\n\n    private static URL getUrl() {\n        return URL.valueOf(\"tri://127.0.0.1:\" + NetUtils.getAvailablePort() + \"/rest?interface=\"\n                + SpringRestDemoService.class.getName());\n    }\n\n    private static final String SERVER = \"netty4\";\n\n    private final ModuleServiceRepository repository =\n            ApplicationModel.defaultModel().getDefaultModule().getServiceRepository();\n\n    @AfterEach\n    public void tearDown() {\n        tProtocol.destroy();\n        protocol.destroy();\n        FrameworkModel.destroyAll();\n    }\n\n    public SpringRestDemoService getServerImpl() {\n        return new SpringDemoServiceImpl();\n    }\n\n    public Class<SpringRestDemoService> getServerClass() {\n        return SpringRestDemoService.class;\n    }\n\n    public Exporter<SpringRestDemoService> getExport(URL url, SpringRestDemoService server) {\n        url = url.addParameter(SERVER_KEY, SERVER);\n        return tProtocol.export(proxy.getInvoker(server, getServerClass(), url));\n    }\n\n    @Test\n    void testRestProtocol() {\n        int port = NetUtils.getAvailablePort();\n        URL url = URL.valueOf(\n                \"tri://127.0.0.1:\" + port + \"/?version=1.0.0&interface=\" + SpringRestDemoService.class.getName());\n\n        SpringRestDemoService server = getServerImpl();\n\n        url = this.registerProvider(url, server, getServerClass());\n\n        Exporter<SpringRestDemoService> exporter = getExport(url, server);\n\n        Invoker<SpringRestDemoService> invoker = protocol.refer(SpringRestDemoService.class, url);\n        Assertions.assertFalse(server.isCalled());\n\n        SpringRestDemoService client = proxy.getProxy(invoker);\n        String result = client.sayHello(\"haha\");\n        Assertions.assertTrue(server.isCalled());\n        Assertions.assertEquals(\"Hello, haha\", result);\n\n        String header = client.testHeader(\"header\");\n        Assertions.assertEquals(\"header\", header);\n\n        String headerInt = client.testHeaderInt(1);\n        Assertions.assertEquals(\"1\", headerInt);\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    @Test\n    void testRestProtocolWithContextPath() {\n        SpringRestDemoService server = getServerImpl();\n        Assertions.assertFalse(server.isCalled());\n        int port = NetUtils.getAvailablePort();\n        URL url = URL.valueOf(\n                \"tri://127.0.0.1:\" + port + \"/a/b/c?version=1.0.0&interface=\" + SpringRestDemoService.class.getName());\n\n        url = this.registerProvider(url, server, SpringRestDemoService.class);\n\n        Exporter<SpringRestDemoService> exporter = getExport(url, server);\n\n        url = URL.valueOf(\"rest://127.0.0.1:\" + port + \"/a/b/c/?version=1.0.0&interface=\"\n                + SpringRestDemoService.class.getName());\n        Invoker<SpringRestDemoService> invoker = protocol.refer(SpringRestDemoService.class, url);\n        SpringRestDemoService client = proxy.getProxy(invoker);\n        String result = client.sayHello(\"haha\");\n        Assertions.assertTrue(server.isCalled());\n        Assertions.assertEquals(\"Hello, haha\", result);\n        invoker.destroy();\n        exporter.unexport();\n    }\n\n    @Test\n    void testExport() {\n        SpringRestDemoService server = getServerImpl();\n\n        URL url = this.registerProvider(getUrl(), server, SpringRestDemoService.class);\n\n        RpcContext.getClientAttachment().setAttachment(\"timeout\", \"200\");\n        Exporter<SpringRestDemoService> exporter = getExport(url, server);\n\n        SpringRestDemoService demoService = this.proxy.getProxy(protocol.refer(SpringRestDemoService.class, url));\n\n        Integer echoString = demoService.hello(1, 2);\n        assertThat(echoString, is(3));\n\n        exporter.unexport();\n    }\n\n    @Test\n    void testNettyServer() {\n        SpringRestDemoService server = getServerImpl();\n\n        URL nettyUrl = this.registerProvider(getUrl(), server, SpringRestDemoService.class);\n\n        Exporter<SpringRestDemoService> exporter = getExport(nettyUrl, server);\n\n        SpringRestDemoService demoService = this.proxy.getProxy(protocol.refer(SpringRestDemoService.class, nettyUrl));\n\n        Integer echoString = demoService.hello(10, 10);\n        assertThat(echoString, is(20));\n\n        exporter.unexport();\n    }\n\n    @Test\n    void testInvoke() {\n        SpringRestDemoService server = getServerImpl();\n\n        URL url = this.registerProvider(getUrl(), server, SpringRestDemoService.class);\n\n        Exporter<SpringRestDemoService> exporter = getExport(url, server);\n\n        RpcInvocation rpcInvocation = new RpcInvocation(\n                \"hello\",\n                SpringRestDemoService.class.getName(),\n                \"\",\n                new Class[] {Integer.class, Integer.class},\n                new Integer[] {2, 3});\n\n        Result result = exporter.getInvoker().invoke(rpcInvocation);\n        assertThat(result.getValue(), CoreMatchers.<Object>is(5));\n    }\n\n    @Test\n    void testFilter() {\n        SpringRestDemoService server = getServerImpl();\n\n        URL url = this.registerProvider(getUrl(), server, SpringRestDemoService.class);\n\n        Exporter<SpringRestDemoService> exporter = getExport(url, server);\n\n        SpringRestDemoService demoService = this.proxy.getProxy(protocol.refer(SpringRestDemoService.class, url));\n\n        Integer result = demoService.hello(1, 2);\n\n        assertThat(result, is(3));\n\n        exporter.unexport();\n    }\n\n    @Test\n    void testDefaultPort() {\n        assertThat(protocol.getDefaultPort(), is(80));\n    }\n\n    @Test\n    void testFormConsumerParser() {\n        SpringRestDemoService server = getServerImpl();\n\n        URL nettyUrl = this.registerProvider(getUrl(), server, SpringRestDemoService.class);\n\n        Exporter<SpringRestDemoService> exporter = getExport(nettyUrl, server);\n\n        SpringRestDemoService demoService = this.proxy.getProxy(protocol.refer(SpringRestDemoService.class, nettyUrl));\n\n        User user = new User();\n        user.setAge(18);\n        user.setName(\"dubbo\");\n        user.setId(404l);\n        String name = demoService.testFormBody(user);\n        Assertions.assertEquals(\"dubbo\", name);\n\n        LinkedMultiValueMap<String, String> forms = new LinkedMultiValueMap<>();\n        forms.put(\"form\", Arrays.asList(\"F1\"));\n\n        Assertions.assertEquals(Arrays.asList(\"F1\"), demoService.testFormMapBody(forms));\n\n        exporter.unexport();\n    }\n\n    @Test\n    void testPrimitive() {\n        SpringRestDemoService server = getServerImpl();\n\n        URL nettyUrl = this.registerProvider(getUrl(), server, SpringRestDemoService.class);\n\n        Exporter<SpringRestDemoService> exporter = getExport(nettyUrl, server);\n\n        SpringRestDemoService demoService = this.proxy.getProxy(protocol.refer(SpringRestDemoService.class, nettyUrl));\n\n        Integer result = demoService.primitiveInt(1, 2);\n        Long resultLong = demoService.primitiveLong(1, 2l);\n        long resultByte = demoService.primitiveByte((byte) 1, 2l);\n        long resultShort = demoService.primitiveShort((short) 1, 2l, 1);\n\n        assertThat(result, is(3));\n        assertThat(resultShort, is(3l));\n        assertThat(resultLong, is(3l));\n        assertThat(resultByte, is(3l));\n\n        exporter.unexport();\n    }\n\n    @Test\n    void testExceptionHandler() {\n        SpringRestDemoService server = getServerImpl();\n\n        URL nettyUrl = registerProvider(getUrl(), server, SpringRestDemoService.class);\n        Exporter<SpringRestDemoService> exporter = getExport(nettyUrl, server);\n        SpringRestDemoService demoService = proxy.getProxy(protocol.refer(SpringRestDemoService.class, nettyUrl));\n\n        String result = demoService.error();\n\n        assertThat(result, is(\"ok\"));\n\n        exporter.unexport();\n    }\n\n    @Test\n    void testProxyDoubleCheck() {\n\n        ProxyCreatorSupport proxyCreatorSupport = new ProxyCreatorSupport();\n        AdvisedSupport advisedSupport = new AdvisedSupport();\n        advisedSupport.setTarget(getServerImpl());\n        AopProxy aopProxy = proxyCreatorSupport.getAopProxyFactory().createAopProxy(advisedSupport);\n        Object proxy = aopProxy.getProxy();\n        SpringRestDemoService server = (SpringRestDemoService) proxy;\n\n        URL nettyUrl = this.registerProvider(getUrl(), server, SpringRestDemoService.class);\n\n        Exporter<SpringRestDemoService> exporter = getExport(nettyUrl, server);\n\n        SpringRestDemoService demoService = this.proxy.getProxy(protocol.refer(SpringRestDemoService.class, nettyUrl));\n\n        Integer result = demoService.primitiveInt(1, 2);\n        Long resultLong = demoService.primitiveLong(1, 2l);\n        long resultByte = demoService.primitiveByte((byte) 1, 2l);\n        long resultShort = demoService.primitiveShort((short) 1, 2l, 1);\n\n        assertThat(result, is(3));\n        assertThat(resultShort, is(3l));\n        assertThat(resultLong, is(3l));\n        assertThat(resultByte, is(3l));\n\n        exporter.unexport();\n    }\n\n    private URL registerProvider(URL url, Object impl, Class<?> interfaceClass) {\n        ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);\n        ProviderModel providerModel = new ProviderModel(url.getServiceKey(), impl, serviceDescriptor, null, null);\n        repository.registerProvider(providerModel);\n        return url.setServiceModel(providerModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/compatible/SpringRestDemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring.compatible;\n\nimport java.util.List;\n\nimport org.springframework.http.MediaType;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestHeader;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\n\n@RequestMapping(\"/demoService\")\npublic interface SpringRestDemoService {\n    @RequestMapping(value = \"/hello\", method = RequestMethod.GET)\n    Integer hello(@RequestParam Integer a, @RequestParam Integer b);\n\n    @RequestMapping(value = \"/error\", method = RequestMethod.GET, consumes = MediaType.TEXT_PLAIN_VALUE)\n    String error();\n\n    @RequestMapping(value = \"/sayHello\", method = RequestMethod.POST, consumes = MediaType.TEXT_PLAIN_VALUE)\n    String sayHello(String name);\n\n    boolean isCalled();\n\n    @RequestMapping(\n            value = \"/testFormBody\",\n            method = RequestMethod.POST,\n            consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,\n            produces = MediaType.TEXT_PLAIN_VALUE)\n    String testFormBody(@RequestBody User user);\n\n    @RequestMapping(\n            value = \"/testFormMapBody\",\n            method = RequestMethod.POST,\n            consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)\n    List<String> testFormMapBody(@RequestBody LinkedMultiValueMap map);\n\n    @RequestMapping(value = \"/testHeader\", method = RequestMethod.POST, consumes = MediaType.TEXT_PLAIN_VALUE)\n    String testHeader(@RequestHeader String header);\n\n    @RequestMapping(value = \"/testHeaderInt\", method = RequestMethod.GET, consumes = MediaType.TEXT_PLAIN_VALUE)\n    String testHeaderInt(@RequestHeader int header);\n\n    @RequestMapping(method = RequestMethod.GET, value = \"/primitive\")\n    int primitiveInt(@RequestParam(\"a\") int a, @RequestParam(\"b\") int b);\n\n    @RequestMapping(method = RequestMethod.GET, value = \"/primitiveLong\")\n    long primitiveLong(@RequestParam(\"a\") long a, @RequestParam(\"b\") Long b);\n\n    @RequestMapping(method = RequestMethod.GET, value = \"/primitiveByte\")\n    long primitiveByte(@RequestParam(\"a\") byte a, @RequestParam(\"b\") Long b);\n\n    @RequestMapping(method = RequestMethod.POST, value = \"/primitiveShort\")\n    long primitiveShort(@RequestParam(\"a\") short a, @RequestParam(\"b\") Long b, @RequestBody int c);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/compatible/User.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring.compatible;\n\nimport java.io.Serializable;\nimport java.util.Objects;\n\n/**\n * User Entity\n *\n * @since 2.7.6\n */\npublic class User implements Serializable {\n\n    private Long id;\n\n    private String name;\n\n    private Integer age;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n\n    public static User getInstance() {\n        User user = new User();\n        user.setAge(18);\n        user.setName(\"dubbo\");\n        user.setId(404l);\n        return user;\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        User user = (User) o;\n        return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(age, user.age);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(id, name, age);\n    }\n\n    @Override\n    public String toString() {\n        return \"User{\" + \"id=\" + id + \", name='\" + name + '\\'' + \", age=\" + age + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/service/SpringDemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring.service;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.service.Book;\nimport org.apache.dubbo.rpc.protocol.tri.rest.service.User.Group;\nimport org.apache.dubbo.rpc.protocol.tri.rest.service.User.UserEx;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport io.grpc.health.v1.HealthCheckRequest;\nimport io.grpc.health.v1.HealthCheckResponse;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n@RequestMapping(\"/spring\")\npublic interface SpringDemoService {\n\n    @RequestMapping\n    String hello(String name);\n\n    @RequestMapping\n    String argTest(String name, int age);\n\n    @RequestMapping\n    Book beanArgTest(@RequestBody(required = false) Book book, Integer quote);\n\n    @RequestMapping\n    Book beanArgTest2(@RequestBody Book book);\n\n    @RequestMapping(\"/bean\")\n    UserEx advanceBeanArgTest(UserEx user);\n\n    @RequestMapping\n    List<Integer> listArgBodyTest(@RequestBody List<Integer> list, int age);\n\n    @RequestMapping\n    List<Integer> listArgBodyTest2(List<Integer> list, int age);\n\n    @RequestMapping\n    Map<Integer, List<Long>> mapArgBodyTest(@RequestBody Map<Integer, List<Long>> map, int age);\n\n    @RequestMapping\n    Map<Integer, List<Long>> mapArgBodyTest2(Map<Integer, List<Long>> map, int age);\n\n    @RequestMapping\n    List<Group> beanBodyTest(@RequestBody List<Group> groups, int age);\n\n    @RequestMapping\n    List<Group> beanBodyTest2(List<Group> groups, int age);\n\n    @RequestMapping\n    MultiValueMap<String, Integer> multiValueMapTest(MultiValueMap<String, Integer> params);\n\n    @RequestMapping\n    Book buy(Book book);\n\n    @RequestMapping(\"/buy2\")\n    Book buy(Book book, int count);\n\n    @RequestMapping\n    String say(String name, Long count);\n\n    @RequestMapping\n    String say(String name);\n\n    @RequestMapping\n    String argNameTest(String name);\n\n    @RequestMapping\n    void pbServerStream(@RequestBody HealthCheckRequest request, StreamObserver<HealthCheckResponse> responseObserver);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/service/SpringDemoServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.spring.service;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.service.DemoServiceImpl;\n\nimport org.springframework.util.MultiValueMap;\n\npublic class SpringDemoServiceImpl extends DemoServiceImpl implements SpringDemoService {\n\n    @Override\n    public MultiValueMap<String, Integer> multiValueMapTest(MultiValueMap<String, Integer> params) {\n        return params;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-rest-spring/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Logger name=\"org.apache.dubbo.rpc.protocol.tri.h12\" level=\"debug\"/>\n        <Logger name=\"org.apache.dubbo.rpc.protocol.tri.rest\" level=\"debug\"/>\n        <Logger name=\"org.apache.dubbo.remoting.http12\" level=\"debug\"/>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-security</artifactId>\n  <packaging>jar</packaging>\n\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <!-- dubbo -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <!-- dubbo -->\n\n    <dependency>\n      <groupId>io.grpc</groupId>\n      <artifactId>grpc-protobuf</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.grpc</groupId>\n      <artifactId>grpc-stub</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.grpc</groupId>\n      <artifactId>grpc-netty-shaded</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java-util</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.bouncycastle</groupId>\n      <artifactId>bcprov-jdk18on</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.bouncycastle</groupId>\n      <artifactId>bcpkix-jdk18on</artifactId>\n    </dependency>\n\n    <!-- test -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-api</artifactId>\n      <version>${project.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.xolstice.maven.plugins</groupId>\n        <artifactId>protobuf-maven-plugin</artifactId>\n        <version>${maven_protobuf_plugin_version}</version>\n        <configuration>\n          <protocArtifact>com.google.protobuf:protoc:${protobuf-java_version}:exe:${os.detected.classifier}</protocArtifact>\n          <pluginId>grpc-java</pluginId>\n          <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc_version}:exe:${os.detected.classifier}</pluginArtifact>\n        </configuration>\n        <executions>\n          <execution>\n            <goals>\n              <goal>compile</goal>\n              <goal>compile-custom</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n      <!-- Override the maven-javadoc-plugin configuration that depends on the pass -->\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-javadoc-plugin</artifactId>\n        <configuration>\n          <skip>true</skip>\n        </configuration>\n      </plugin>\n      <!-- add os-maven-plugin to plugins just for Eclipse m2e, not for `mvn install` -->\n      <plugin>\n        <groupId>kr.motd.maven</groupId>\n        <artifactId>os-maven-plugin</artifactId>\n        <version>${maven_os_plugin_version}</version>\n        <executions>\n          <execution>\n            <goals>\n              <goal>detect</goal>\n            </goals>\n            <phase>initialize</phase>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n    <extensions>\n      <!-- add os-maven-plugin to extensions for `mvn install` -->\n      <extension>\n        <groupId>kr.motd.maven</groupId>\n        <artifactId>os-maven-plugin</artifactId>\n        <version>${maven_os_plugin_version}</version>\n      </extension>\n    </extensions>\n  </build>\n\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/CertConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.security.cert;\n\nimport java.util.Objects;\n\nimport static org.apache.dubbo.security.cert.Constants.DEFAULT_REFRESH_INTERVAL;\n\npublic class CertConfig {\n    private final String remoteAddress;\n    private final String envType;\n    private final String caCertPath;\n    /**\n     * Path to OpenID Connect Token file\n     */\n    private final String oidcTokenPath;\n\n    private final int refreshInterval;\n\n    public CertConfig(String remoteAddress, String envType, String caCertPath, String oidcTokenPath) {\n        this(remoteAddress, envType, caCertPath, oidcTokenPath, DEFAULT_REFRESH_INTERVAL);\n    }\n\n    public CertConfig(\n            String remoteAddress, String envType, String caCertPath, String oidcTokenPath, int refreshInterval) {\n        this.remoteAddress = remoteAddress;\n        this.envType = envType;\n        this.caCertPath = caCertPath;\n        this.oidcTokenPath = oidcTokenPath;\n        this.refreshInterval = refreshInterval;\n    }\n\n    public String getRemoteAddress() {\n        return remoteAddress;\n    }\n\n    public String getEnvType() {\n        return envType;\n    }\n\n    public String getCaCertPath() {\n        return caCertPath;\n    }\n\n    public String getOidcTokenPath() {\n        return oidcTokenPath;\n    }\n\n    public int getRefreshInterval() {\n        return refreshInterval;\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        CertConfig that = (CertConfig) o;\n        return Objects.equals(remoteAddress, that.remoteAddress)\n                && Objects.equals(envType, that.envType)\n                && Objects.equals(caCertPath, that.caCertPath)\n                && Objects.equals(oidcTokenPath, that.oidcTokenPath);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(remoteAddress, envType, caCertPath, oidcTokenPath);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/CertDeployerListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.security.cert;\n\nimport org.apache.dubbo.common.deploy.ApplicationDeployListener;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.Objects;\n\npublic class CertDeployerListener implements ApplicationDeployListener {\n    private final DubboCertManager dubboCertManager;\n\n    public CertDeployerListener(FrameworkModel frameworkModel) {\n        dubboCertManager = frameworkModel.getBeanFactory().getBean(DubboCertManager.class);\n    }\n\n    @Override\n    public void onInitialize(ApplicationModel scopeModel) {}\n\n    @Override\n    public void onStarting(ApplicationModel scopeModel) {\n        scopeModel.getApplicationConfigManager().getSsl().ifPresent(sslConfig -> {\n            if (Objects.nonNull(sslConfig.getCaAddress()) && dubboCertManager != null) {\n                CertConfig certConfig = new CertConfig(\n                        sslConfig.getCaAddress(),\n                        sslConfig.getEnvType(),\n                        sslConfig.getCaCertPath(),\n                        sslConfig.getOidcTokenPath());\n                dubboCertManager.connect(certConfig);\n            }\n        });\n    }\n\n    @Override\n    public void onStarted(ApplicationModel scopeModel) {}\n\n    @Override\n    public void onCompletion(ApplicationModel scopeModel) {}\n\n    @Override\n    public void onStopping(ApplicationModel scopeModel) {\n        if (dubboCertManager != null) {\n            dubboCertManager.disConnect();\n        }\n    }\n\n    @Override\n    public void onStopped(ApplicationModel scopeModel) {}\n\n    @Override\n    public void onFailure(ApplicationModel scopeModel, Throwable cause) {\n        if (dubboCertManager != null) {\n            dubboCertManager.disConnect();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/CertPair.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.security.cert;\n\nimport java.util.Objects;\n\npublic class CertPair {\n    private final String privateKey;\n    private final String certificate;\n    private final String trustCerts;\n    private final long expireTime;\n\n    public CertPair(String privateKey, String certificate, String trustCerts, long expireTime) {\n        this.privateKey = privateKey;\n        this.certificate = certificate;\n        this.trustCerts = trustCerts;\n        this.expireTime = expireTime;\n    }\n\n    public String getPrivateKey() {\n        return privateKey;\n    }\n\n    public String getCertificate() {\n        return certificate;\n    }\n\n    public String getTrustCerts() {\n        return trustCerts;\n    }\n\n    public long getExpireTime() {\n        return expireTime;\n    }\n\n    public boolean isExpire() {\n        return System.currentTimeMillis() > expireTime;\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        CertPair certPair = (CertPair) o;\n        return expireTime == certPair.expireTime\n                && Objects.equals(privateKey, certPair.privateKey)\n                && Objects.equals(certificate, certPair.certificate)\n                && Objects.equals(trustCerts, certPair.trustCerts);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(privateKey, certificate, trustCerts, expireTime);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/CertScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.security.cert;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\npublic class CertScopeModelInitializer implements ScopeModelInitializer {\n    public static boolean isSupported() {\n        try {\n            ClassUtils.forName(\"io.grpc.Channel\");\n            ClassUtils.forName(\"org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder\");\n            return true;\n        } catch (Throwable t) {\n            return false;\n        }\n    }\n\n    @Override\n    public void initializeFrameworkModel(FrameworkModel frameworkModel) {\n        ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();\n        if (isSupported()) {\n            beanFactory.registerBean(DubboCertManager.class);\n        }\n    }\n\n    @Override\n    public void initializeApplicationModel(ApplicationModel applicationModel) {}\n\n    @Override\n    public void initializeModuleModel(ModuleModel moduleModel) {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.security.cert;\n\npublic interface Constants {\n    int DEFAULT_REFRESH_INTERVAL = 30_000;\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/DubboCertManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.security.cert;\n\nimport org.apache.dubbo.auth.v1alpha1.DubboCertificateRequest;\nimport org.apache.dubbo.auth.v1alpha1.DubboCertificateResponse;\nimport org.apache.dubbo.auth.v1alpha1.DubboCertificateServiceGrpc;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.IOUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.KeyPairGenerator;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.PublicKey;\nimport java.security.SecureRandom;\nimport java.security.spec.ECGenParameterSpec;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport io.grpc.Channel;\nimport io.grpc.Metadata;\nimport io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;\nimport io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;\nimport io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory;\nimport org.bouncycastle.asn1.x500.X500Name;\nimport org.bouncycastle.openssl.jcajce.JcaPEMWriter;\nimport org.bouncycastle.operator.ContentSigner;\nimport org.bouncycastle.operator.OperatorCreationException;\nimport org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;\nimport org.bouncycastle.pkcs.PKCS10CertificationRequest;\nimport org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;\nimport org.bouncycastle.util.io.pem.PemObject;\n\nimport static io.grpc.stub.MetadataUtils.newAttachHeadersInterceptor;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_SSL_CERT_GENERATE_FAILED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_SSL_CONNECT_INSECURE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_GENERATE_CERT_ISTIO;\n\npublic class DubboCertManager {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DubboCertManager.class);\n\n    private final FrameworkModel frameworkModel;\n    /**\n     * gRPC channel to Dubbo Cert Authority server\n     */\n    protected volatile Channel channel;\n    /**\n     * Cert pair for current Dubbo instance\n     */\n    protected volatile CertPair certPair;\n    /**\n     * Path to OpenID Connect Token file\n     */\n    protected volatile CertConfig certConfig;\n    /**\n     * Refresh cert pair for current Dubbo instance\n     */\n    protected volatile ScheduledFuture<?> refreshFuture;\n\n    public DubboCertManager(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    public synchronized void connect(CertConfig certConfig) {\n        if (channel != null) {\n            logger.error(INTERNAL_ERROR, \"\", \"\", \"Dubbo Cert Authority server is already connected.\");\n            return;\n        }\n        if (certConfig == null) {\n            // No cert config, return\n            return;\n        }\n        if (StringUtils.isEmpty(certConfig.getRemoteAddress())) {\n            // No remote address configured, return\n            return;\n        }\n        if (StringUtils.isNotEmpty(certConfig.getEnvType())\n                && !\"Kubernetes\".equalsIgnoreCase(certConfig.getEnvType())) {\n            throw new IllegalArgumentException(\"Only support Kubernetes env now.\");\n        }\n        // Create gRPC connection\n        connect0(certConfig);\n\n        this.certConfig = certConfig;\n\n        // Try to generate cert from remote\n        generateCert();\n        // Schedule refresh task\n        scheduleRefresh();\n    }\n\n    /**\n     * Create task to refresh cert pair for current Dubbo instance\n     */\n    protected void scheduleRefresh() {\n        FrameworkExecutorRepository repository =\n                frameworkModel.getBeanFactory().getBean(FrameworkExecutorRepository.class);\n        refreshFuture = repository\n                .getSharedScheduledExecutor()\n                .scheduleAtFixedRate(\n                        this::generateCert,\n                        certConfig.getRefreshInterval(),\n                        certConfig.getRefreshInterval(),\n                        TimeUnit.MILLISECONDS);\n    }\n\n    /**\n     * Try to connect to remote certificate authorization\n     *\n     * @param certConfig certificate authorization address\n     */\n    protected void connect0(CertConfig certConfig) {\n        String caCertPath = certConfig.getCaCertPath();\n        String remoteAddress = certConfig.getRemoteAddress();\n        logger.info(\n                \"Try to connect to Dubbo Cert Authority server: \" + remoteAddress + \", caCertPath: \" + remoteAddress);\n        try {\n            if (StringUtils.isNotEmpty(caCertPath)) {\n                channel = NettyChannelBuilder.forTarget(remoteAddress)\n                        .sslContext(GrpcSslContexts.forClient()\n                                .trustManager(new File(caCertPath))\n                                .build())\n                        .build();\n            } else {\n                logger.warn(\n                        CONFIG_SSL_CONNECT_INSECURE,\n                        \"\",\n                        \"\",\n                        \"No caCertPath is provided, will use insecure connection.\");\n                channel = NettyChannelBuilder.forTarget(remoteAddress)\n                        .sslContext(GrpcSslContexts.forClient()\n                                .trustManager(InsecureTrustManagerFactory.INSTANCE)\n                                .build())\n                        .build();\n            }\n        } catch (Exception e) {\n            logger.error(LoggerCodeConstants.CONFIG_SSL_PATH_LOAD_FAILED, \"\", \"\", \"Failed to load SSL cert file.\", e);\n            throw new RuntimeException(e);\n        }\n    }\n\n    public synchronized void disConnect() {\n        if (refreshFuture != null) {\n            refreshFuture.cancel(true);\n            refreshFuture = null;\n        }\n        if (channel != null) {\n            channel = null;\n        }\n    }\n\n    public boolean isConnected() {\n        return certConfig != null && channel != null && certPair != null;\n    }\n\n    protected CertPair generateCert() {\n        if (certPair != null && !certPair.isExpire()) {\n            return certPair;\n        }\n        synchronized (this) {\n            if (certPair == null || certPair.isExpire()) {\n                try {\n                    logger.info(\"Try to generate cert from Dubbo Certificate Authority.\");\n                    CertPair certFromRemote = refreshCert();\n                    if (certFromRemote != null) {\n                        certPair = certFromRemote;\n                    } else {\n                        logger.error(\n                                CONFIG_SSL_CERT_GENERATE_FAILED,\n                                \"\",\n                                \"\",\n                                \"Generate Cert from Dubbo Certificate Authority failed.\");\n                    }\n                } catch (Exception e) {\n                    logger.error(REGISTRY_FAILED_GENERATE_CERT_ISTIO, \"\", \"\", \"Generate Cert from Istio failed.\", e);\n                }\n            }\n        }\n        return certPair;\n    }\n\n    /**\n     * Request remote certificate authorization to generate cert pair for current Dubbo instance\n     *\n     * @return cert pair\n     * @throws IOException ioException\n     */\n    protected CertPair refreshCert() throws IOException {\n        KeyPair keyPair = signWithEcdsa();\n\n        if (keyPair == null) {\n            keyPair = signWithRsa();\n        }\n\n        if (keyPair == null) {\n            logger.error(\n                    CONFIG_SSL_CERT_GENERATE_FAILED,\n                    \"\",\n                    \"\",\n                    \"Generate Key failed. Please check if your system support.\");\n            return null;\n        }\n\n        String csr = generateCsr(keyPair);\n        DubboCertificateServiceGrpc.DubboCertificateServiceBlockingStub stub =\n                DubboCertificateServiceGrpc.newBlockingStub(channel);\n        stub = setHeaderIfNeed(stub);\n\n        String privateKeyPem = generatePrivatePemKey(keyPair);\n        DubboCertificateResponse certificateResponse = stub.createCertificate(generateRequest(csr));\n\n        if (certificateResponse == null || !certificateResponse.getSuccess()) {\n            logger.error(\n                    CONFIG_SSL_CERT_GENERATE_FAILED,\n                    \"\",\n                    \"\",\n                    \"Failed to generate cert from Dubbo Certificate Authority. \" + \"Message: \"\n                            + (certificateResponse == null ? \"null\" : certificateResponse.getMessage()));\n            return null;\n        }\n        logger.info(\"Successfully generate cert from Dubbo Certificate Authority. Cert expire time: \"\n                + certificateResponse.getExpireTime());\n\n        return new CertPair(\n                privateKeyPem,\n                certificateResponse.getCertPem(),\n                String.join(\"\\n\", certificateResponse.getTrustCertsList()),\n                certificateResponse.getExpireTime());\n    }\n\n    private DubboCertificateServiceGrpc.DubboCertificateServiceBlockingStub setHeaderIfNeed(\n            DubboCertificateServiceGrpc.DubboCertificateServiceBlockingStub stub) throws IOException {\n        String oidcTokenPath = certConfig.getOidcTokenPath();\n        if (StringUtils.isNotEmpty(oidcTokenPath)) {\n            Metadata header = new Metadata();\n            Metadata.Key<String> key = Metadata.Key.of(\"authorization\", Metadata.ASCII_STRING_MARSHALLER);\n            header.put(\n                    key,\n                    \"Bearer \"\n                            + IOUtils.read(new FileReader(oidcTokenPath))\n                                    .replace(\"\\n\", \"\")\n                                    .replace(\"\\t\", \"\")\n                                    .replace(\"\\r\", \"\")\n                                    .trim());\n\n            stub = stub.withInterceptors(newAttachHeadersInterceptor(header));\n            logger.info(\"Use oidc token from \" + oidcTokenPath + \" to connect to Dubbo Certificate Authority.\");\n        } else {\n            logger.warn(\n                    CONFIG_SSL_CONNECT_INSECURE,\n                    \"\",\n                    \"\",\n                    \"Use insecure connection to connect to Dubbo Certificate Authority. Reason: No oidc token is provided.\");\n        }\n        return stub;\n    }\n\n    /**\n     * Generate key pair with RSA\n     *\n     * @return key pair\n     */\n    protected static KeyPair signWithRsa() {\n        KeyPair keyPair = null;\n        try {\n            KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance(\"RSA\");\n            kpGenerator.initialize(4096);\n            java.security.KeyPair keypair = kpGenerator.generateKeyPair();\n            PublicKey publicKey = keypair.getPublic();\n            PrivateKey privateKey = keypair.getPrivate();\n            ContentSigner signer = new JcaContentSignerBuilder(\"SHA256WithRSA\").build(keypair.getPrivate());\n            keyPair = new KeyPair(publicKey, privateKey, signer);\n        } catch (NoSuchAlgorithmException | OperatorCreationException e) {\n            logger.error(\n                    CONFIG_SSL_CERT_GENERATE_FAILED,\n                    \"\",\n                    \"\",\n                    \"Generate Key with SHA256WithRSA algorithm failed. Please check if your system support.\",\n                    e);\n        }\n        return keyPair;\n    }\n\n    /**\n     * Generate key pair with ECDSA\n     *\n     * @return key pair\n     */\n    protected static KeyPair signWithEcdsa() {\n        KeyPair keyPair = null;\n        try {\n            ECGenParameterSpec ecSpec = new ECGenParameterSpec(\"secp256r1\");\n            KeyPairGenerator g = KeyPairGenerator.getInstance(\"EC\");\n            g.initialize(ecSpec, new SecureRandom());\n            java.security.KeyPair keypair = g.generateKeyPair();\n            PublicKey publicKey = keypair.getPublic();\n            PrivateKey privateKey = keypair.getPrivate();\n            ContentSigner signer = new JcaContentSignerBuilder(\"SHA256withECDSA\").build(privateKey);\n            keyPair = new KeyPair(publicKey, privateKey, signer);\n        } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | OperatorCreationException e) {\n            logger.error(\n                    CONFIG_SSL_CERT_GENERATE_FAILED,\n                    \"\",\n                    \"\",\n                    \"Generate Key with secp256r1 algorithm failed. Please check if your system support. \"\n                            + \"Will attempt to generate with RSA2048.\",\n                    e);\n        }\n        return keyPair;\n    }\n\n    private DubboCertificateRequest generateRequest(String csr) {\n        return DubboCertificateRequest.newBuilder()\n                .setCsr(csr)\n                .setType(\"CONNECTION\")\n                .build();\n    }\n\n    /**\n     * Generate private key in pem encoded\n     *\n     * @param keyPair key pair\n     * @return private key\n     * @throws IOException ioException\n     */\n    private String generatePrivatePemKey(KeyPair keyPair) throws IOException {\n        String key = generatePemKey(\"RSA PRIVATE KEY\", keyPair.getPrivateKey().getEncoded());\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Generated Private Key. \\n\" + key);\n        }\n        return key;\n    }\n\n    /**\n     * Generate content in pem encoded\n     *\n     * @param type    content type\n     * @param content content\n     * @return encoded data\n     * @throws IOException ioException\n     */\n    private String generatePemKey(String type, byte[] content) throws IOException {\n        PemObject pemObject = new PemObject(type, content);\n        StringWriter str = new StringWriter();\n        JcaPEMWriter jcaPEMWriter = new JcaPEMWriter(str);\n        jcaPEMWriter.writeObject(pemObject);\n        jcaPEMWriter.close();\n        str.close();\n        return str.toString();\n    }\n\n    /**\n     * Generate CSR (Certificate Sign Request)\n     *\n     * @param keyPair key pair to request\n     * @return csr\n     * @throws IOException ioException\n     */\n    private String generateCsr(KeyPair keyPair) throws IOException {\n        PKCS10CertificationRequest request = new JcaPKCS10CertificationRequestBuilder(\n                        new X500Name(\"O=\" + \"cluster.domain\"), keyPair.getPublicKey())\n                .build(keyPair.getSigner());\n\n        String csr = generatePemKey(\"CERTIFICATE REQUEST\", request.getEncoded());\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"CSR Request to Dubbo Certificate Authorization. \\n\" + csr);\n        }\n        return csr;\n    }\n\n    protected static class KeyPair {\n        private final PublicKey publicKey;\n        private final PrivateKey privateKey;\n        private final ContentSigner signer;\n\n        public KeyPair(PublicKey publicKey, PrivateKey privateKey, ContentSigner signer) {\n            this.publicKey = publicKey;\n            this.privateKey = privateKey;\n            this.signer = signer;\n        }\n\n        public PublicKey getPublicKey() {\n            return publicKey;\n        }\n\n        public PrivateKey getPrivateKey() {\n            return privateKey;\n        }\n\n        public ContentSigner getSigner() {\n            return signer;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/java/org/apache/dubbo/security/cert/DubboCertProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.security.cert;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.ssl.AuthPolicy;\nimport org.apache.dubbo.common.ssl.Cert;\nimport org.apache.dubbo.common.ssl.CertProvider;\nimport org.apache.dubbo.common.ssl.ProviderCert;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.nio.charset.StandardCharsets;\n\n@Activate\npublic class DubboCertProvider implements CertProvider {\n    private final DubboCertManager dubboCertManager;\n\n    public DubboCertProvider(FrameworkModel frameworkModel) {\n        dubboCertManager = frameworkModel.getBeanFactory().getBean(DubboCertManager.class);\n    }\n\n    @Override\n    public boolean isSupport(URL address) {\n        return dubboCertManager != null && dubboCertManager.isConnected();\n    }\n\n    @Override\n    public ProviderCert getProviderConnectionConfig(URL localAddress) {\n        CertPair certPair = dubboCertManager.generateCert();\n        if (certPair == null) {\n            return null;\n        }\n        return new ProviderCert(\n                certPair.getCertificate().getBytes(StandardCharsets.UTF_8),\n                certPair.getPrivateKey().getBytes(StandardCharsets.UTF_8),\n                certPair.getTrustCerts().getBytes(StandardCharsets.UTF_8),\n                AuthPolicy.NONE);\n    }\n\n    @Override\n    public Cert getConsumerConnectionConfig(URL remoteAddress) {\n        CertPair certPair = dubboCertManager.generateCert();\n        if (certPair == null) {\n            return null;\n        }\n        return new Cert(\n                certPair.getCertificate().getBytes(StandardCharsets.UTF_8),\n                certPair.getPrivateKey().getBytes(StandardCharsets.UTF_8),\n                certPair.getTrustCerts().getBytes(StandardCharsets.UTF_8));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/proto/ca.proto",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nsyntax = \"proto3\";\n\nimport \"google/protobuf/struct.proto\";\n\npackage org.apache.dubbo.auth.v1alpha1;\n\noption go_package = \"github.com/apache/dubbo-admin/ca/v1alpha1\";\noption java_multiple_files = true;\n\n\nmessage DubboCertificateRequest {\n  string csr = 1;\n  string type = 2;\n\n  google.protobuf.Struct metadata = 3;\n}\n\nmessage DubboCertificateResponse {\n  bool success = 1;\n  string cert_pem = 2;\n  repeated string trust_certs = 3;\n  int64 expire_time = 4;\n  string message = 5;\n}\n\nservice DubboCertificateService {\n  rpc CreateCertificate(DubboCertificateRequest)\n      returns (DubboCertificateResponse) {\n  }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.deploy.ApplicationDeployListener",
    "content": "cert=org.apache.dubbo.security.cert.CertDeployerListener\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.ssl.CertProvider",
    "content": "dubbo=org.apache.dubbo.security.cert.DubboCertProvider\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "cert=org.apache.dubbo.security.cert.CertScopeModelInitializer\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/CertDeployerListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.security.cert;\n\nimport org.apache.dubbo.common.deploy.ApplicationDeployer;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.SslConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedConstruction;\nimport org.mockito.Mockito;\n\nclass CertDeployerListenerTest {\n    @Test\n    void testEmpty1() {\n        AtomicReference<DubboCertManager> reference = new AtomicReference<>();\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    reference.set(mock);\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            ApplicationModel applicationModel = frameworkModel.newApplication();\n            applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"test\"));\n            applicationModel.getDeployer().start();\n            Mockito.verify(reference.get(), Mockito.times(0)).connect(Mockito.any());\n            applicationModel.getDeployer().stop();\n            Mockito.verify(reference.get(), Mockito.atLeast(1)).disConnect();\n            frameworkModel.destroy();\n        }\n    }\n\n    @Test\n    void testEmpty2() {\n        AtomicReference<DubboCertManager> reference = new AtomicReference<>();\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    reference.set(mock);\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            ApplicationModel applicationModel = frameworkModel.newApplication();\n            applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"test\"));\n            applicationModel.getApplicationConfigManager().setSsl(new SslConfig());\n            applicationModel.getDeployer().start();\n            Mockito.verify(reference.get(), Mockito.times(0)).connect(Mockito.any());\n            applicationModel.getDeployer().stop();\n            Mockito.verify(reference.get(), Mockito.atLeast(1)).disConnect();\n            frameworkModel.destroy();\n        }\n    }\n\n    @Test\n    void testCreate() {\n        AtomicReference<DubboCertManager> reference = new AtomicReference<>();\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    reference.set(mock);\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            ApplicationModel applicationModel = frameworkModel.newApplication();\n            applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"test\"));\n            SslConfig sslConfig = new SslConfig();\n            sslConfig.setCaAddress(\"127.0.0.1:30060\");\n            applicationModel.getApplicationConfigManager().setSsl(sslConfig);\n\n            applicationModel.getDeployer().start();\n            Mockito.verify(reference.get(), Mockito.times(1)).connect(Mockito.any());\n            applicationModel.getDeployer().stop();\n            Mockito.verify(reference.get(), Mockito.atLeast(1)).disConnect();\n            frameworkModel.destroy();\n        }\n    }\n\n    @Test\n    void testFailure() {\n        AtomicReference<DubboCertManager> reference = new AtomicReference<>();\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    reference.set(mock);\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            ApplicationModel applicationModel = frameworkModel.newApplication();\n            applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"test\"));\n            SslConfig sslConfig = new SslConfig();\n            sslConfig.setCaAddress(\"127.0.0.1:30060\");\n            applicationModel.getApplicationConfigManager().setSsl(sslConfig);\n            applicationModel.getApplicationConfigManager().addMetadataReport(new MetadataReportConfig(\"absent\"));\n\n            ApplicationDeployer deployer = applicationModel.getDeployer();\n            Assertions.assertThrows(IllegalArgumentException.class, deployer::start);\n            Mockito.verify(reference.get(), Mockito.times(1)).connect(Mockito.any());\n            Mockito.verify(reference.get(), Mockito.atLeast(1)).disConnect();\n            frameworkModel.destroy();\n        }\n    }\n\n    @Test\n    void testNotFound1() {\n        ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();\n        ClassLoader newClassLoader = new ClassLoader(originClassLoader) {\n            @Override\n            public Class<?> loadClass(String name) throws ClassNotFoundException {\n                if (name.startsWith(\"io.grpc.Channel\")) {\n                    throw new ClassNotFoundException(\"Test\");\n                }\n                return super.loadClass(name);\n            }\n        };\n        Thread.currentThread().setContextClassLoader(newClassLoader);\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    // ignore\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            ApplicationModel applicationModel = frameworkModel.newApplication();\n            applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"test\"));\n            SslConfig sslConfig = new SslConfig();\n            sslConfig.setCaAddress(\"127.0.0.1:30060\");\n            applicationModel.getApplicationConfigManager().setSsl(sslConfig);\n\n            applicationModel.getDeployer().start();\n            applicationModel.getDeployer().stop();\n            Assertions.assertEquals(0, construction.constructed().size());\n            frameworkModel.destroy();\n        }\n        Thread.currentThread().setContextClassLoader(originClassLoader);\n    }\n\n    @Test\n    void testNotFound2() {\n        ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();\n        ClassLoader newClassLoader = new ClassLoader(originClassLoader) {\n            @Override\n            public Class<?> loadClass(String name) throws ClassNotFoundException {\n                if (name.startsWith(\"org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder\")) {\n                    throw new ClassNotFoundException(\"Test\");\n                }\n                return super.loadClass(name);\n            }\n        };\n        Thread.currentThread().setContextClassLoader(newClassLoader);\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    // ignore\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            ApplicationModel applicationModel = frameworkModel.newApplication();\n            applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"test\"));\n            SslConfig sslConfig = new SslConfig();\n            sslConfig.setCaAddress(\"127.0.0.1:30060\");\n            applicationModel.getApplicationConfigManager().setSsl(sslConfig);\n\n            applicationModel.getDeployer().start();\n            applicationModel.getDeployer().stop();\n            Assertions.assertEquals(0, construction.constructed().size());\n            frameworkModel.destroy();\n        }\n        Thread.currentThread().setContextClassLoader(originClassLoader);\n    }\n\n    @Test\n    void testParams1() {\n        AtomicReference<DubboCertManager> reference = new AtomicReference<>();\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    reference.set(mock);\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            ApplicationModel applicationModel = frameworkModel.newApplication();\n            applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"test\"));\n            SslConfig sslConfig = new SslConfig();\n            sslConfig.setCaAddress(\"127.0.0.1:30060\");\n            sslConfig.setCaCertPath(\"certs/ca.crt\");\n            sslConfig.setOidcTokenPath(\"token\");\n            sslConfig.setEnvType(\"test\");\n            applicationModel.getApplicationConfigManager().setSsl(sslConfig);\n\n            applicationModel.getDeployer().start();\n            Mockito.verify(reference.get(), Mockito.times(1))\n                    .connect(new CertConfig(\"127.0.0.1:30060\", \"test\", \"certs/ca.crt\", \"token\"));\n            applicationModel.getDeployer().stop();\n            Mockito.verify(reference.get(), Mockito.atLeast(1)).disConnect();\n            frameworkModel.destroy();\n        }\n    }\n\n    @Disabled(\"Enable me until properties from envs work.\")\n    @Test\n    void testParams2() {\n        AtomicReference<DubboCertManager> reference = new AtomicReference<>();\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    reference.set(mock);\n                })) {\n            System.setProperty(\"dubbo.ssl.ca-address\", \"127.0.0.1:30060\");\n            System.setProperty(\"dubbo.ssl.ca-cert-path\", \"certs/ca.crt\");\n            System.setProperty(\"dubbo.ssl.oidc-token-path\", \"token\");\n            System.setProperty(\"dubbo.ssl.env-type\", \"test\");\n            FrameworkModel frameworkModel = new FrameworkModel();\n            ApplicationModel applicationModel = frameworkModel.newApplication();\n            applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"test\"));\n\n            applicationModel.getDeployer().start();\n            Mockito.verify(reference.get(), Mockito.times(1))\n                    .connect(new CertConfig(\"127.0.0.1:30060\", \"test\", \"certs/ca.crt\", \"token\"));\n            applicationModel.getDeployer().stop();\n            Mockito.verify(reference.get(), Mockito.atLeast(1)).disConnect();\n            frameworkModel.destroy();\n            System.clearProperty(\"dubbo.ssl.ca-address\");\n            System.clearProperty(\"dubbo.ssl.ca-cert-path\");\n            System.clearProperty(\"dubbo.ssl.oidc-token-path\");\n            System.clearProperty(\"dubbo.ssl.env-type\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/DubboCertManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.security.cert;\n\nimport org.apache.dubbo.auth.v1alpha1.DubboCertificateResponse;\nimport org.apache.dubbo.auth.v1alpha1.DubboCertificateServiceGrpc;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.IOException;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.grpc.Channel;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\nimport static org.awaitility.Awaitility.await;\nimport static org.mockito.Answers.CALLS_REAL_METHODS;\n\nclass DubboCertManagerTest {\n    @Test\n    void test1() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        DubboCertManager certManager = new DubboCertManager(frameworkModel) {\n            @Override\n            protected void connect0(CertConfig certConfig) {\n                Assertions.assertEquals(\"127.0.0.1:30060\", certConfig.getRemoteAddress());\n                Assertions.assertEquals(\"caCertPath\", certConfig.getCaCertPath());\n            }\n\n            @Override\n            protected CertPair generateCert() {\n                return null;\n            }\n\n            @Override\n            protected void scheduleRefresh() {}\n        };\n        certManager.connect(new CertConfig(\"127.0.0.1:30060\", null, \"caCertPath\", \"oidc\"));\n        Assertions.assertEquals(new CertConfig(\"127.0.0.1:30060\", null, \"caCertPath\", \"oidc\"), certManager.certConfig);\n\n        certManager.connect(new CertConfig(\"127.0.0.1:30060\", \"Kubernetes\", \"caCertPath\", \"oidc123\"));\n        Assertions.assertEquals(\n                new CertConfig(\"127.0.0.1:30060\", \"Kubernetes\", \"caCertPath\", \"oidc123\"), certManager.certConfig);\n\n        certManager.connect(new CertConfig(\"127.0.0.1:30060\", \"kubernetes\", \"caCertPath\", \"oidc345\"));\n        Assertions.assertEquals(\n                new CertConfig(\"127.0.0.1:30060\", \"kubernetes\", \"caCertPath\", \"oidc345\"), certManager.certConfig);\n\n        CertConfig certConfig = new CertConfig(\"127.0.0.1:30060\", \"vm\", \"caCertPath\", \"oidc\");\n        Assertions.assertThrows(IllegalArgumentException.class, () -> certManager.connect(certConfig));\n        Assertions.assertEquals(\n                new CertConfig(\"127.0.0.1:30060\", \"kubernetes\", \"caCertPath\", \"oidc345\"), certManager.certConfig);\n\n        certManager.connect(null);\n        Assertions.assertEquals(\n                new CertConfig(\"127.0.0.1:30060\", \"kubernetes\", \"caCertPath\", \"oidc345\"), certManager.certConfig);\n\n        certManager.connect(new CertConfig(null, null, null, null));\n        Assertions.assertEquals(\n                new CertConfig(\"127.0.0.1:30060\", \"kubernetes\", \"caCertPath\", \"oidc345\"), certManager.certConfig);\n\n        certManager.channel = Mockito.mock(Channel.class);\n        certManager.connect(new CertConfig(\"error\", null, \"error\", \"error\"));\n        Assertions.assertEquals(\n                new CertConfig(\"127.0.0.1:30060\", \"kubernetes\", \"caCertPath\", \"oidc345\"), certManager.certConfig);\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testRefresh() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        AtomicInteger count = new AtomicInteger(0);\n        DubboCertManager certManager = new DubboCertManager(frameworkModel) {\n            @Override\n            protected CertPair generateCert() {\n                count.incrementAndGet();\n                return null;\n            }\n        };\n\n        certManager.certConfig = new CertConfig(null, null, null, null, 10);\n        certManager.scheduleRefresh();\n\n        Assertions.assertNotNull(certManager.refreshFuture);\n        await().until(() -> count.get() > 1);\n        certManager.refreshFuture.cancel(false);\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testConnect1() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        DubboCertManager certManager = new DubboCertManager(frameworkModel);\n        CertConfig certConfig = new CertConfig(\"127.0.0.1:30062\", null, null, null);\n        certManager.connect0(certConfig);\n        Assertions.assertNotNull(certManager.channel);\n        Assertions.assertEquals(\"127.0.0.1:30062\", certManager.channel.authority());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testConnect2() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        DubboCertManager certManager = new DubboCertManager(frameworkModel);\n        String file =\n                this.getClass().getClassLoader().getResource(\"certs/ca.crt\").getFile();\n        CertConfig certConfig = new CertConfig(\"127.0.0.1:30062\", null, file, null);\n        certManager.connect0(certConfig);\n        Assertions.assertNotNull(certManager.channel);\n        Assertions.assertEquals(\"127.0.0.1:30062\", certManager.channel.authority());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testConnect3() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        DubboCertManager certManager = new DubboCertManager(frameworkModel);\n        String file = this.getClass()\n                .getClassLoader()\n                .getResource(\"certs/broken-ca.crt\")\n                .getFile();\n        CertConfig certConfig = new CertConfig(\"127.0.0.1:30062\", null, file, null);\n        Assertions.assertThrows(RuntimeException.class, () -> certManager.connect0(certConfig));\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testDisconnect() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        DubboCertManager certManager = new DubboCertManager(frameworkModel);\n        ScheduledFuture scheduledFuture = Mockito.mock(ScheduledFuture.class);\n        certManager.refreshFuture = scheduledFuture;\n        certManager.disConnect();\n        Assertions.assertNull(certManager.refreshFuture);\n        Mockito.verify(scheduledFuture, Mockito.times(1)).cancel(true);\n\n        certManager.channel = Mockito.mock(Channel.class);\n        certManager.disConnect();\n        Assertions.assertNull(certManager.channel);\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testConnected() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n        DubboCertManager certManager = new DubboCertManager(frameworkModel);\n\n        Assertions.assertFalse(certManager.isConnected());\n\n        certManager.certConfig = Mockito.mock(CertConfig.class);\n        Assertions.assertFalse(certManager.isConnected());\n\n        certManager.channel = Mockito.mock(Channel.class);\n        Assertions.assertFalse(certManager.isConnected());\n\n        certManager.certPair = Mockito.mock(CertPair.class);\n        Assertions.assertTrue(certManager.isConnected());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testGenerateCert() {\n        FrameworkModel frameworkModel = new FrameworkModel();\n\n        AtomicBoolean exception = new AtomicBoolean(false);\n        AtomicReference<CertPair> certPairReference = new AtomicReference<>();\n        DubboCertManager certManager = new DubboCertManager(frameworkModel) {\n            @Override\n            protected CertPair refreshCert() throws IOException {\n                if (exception.get()) {\n                    throw new IOException(\"test\");\n                }\n                return certPairReference.get();\n            }\n        };\n\n        CertPair certPair = new CertPair(\"\", \"\", \"\", Long.MAX_VALUE);\n        certPairReference.set(certPair);\n\n        Assertions.assertEquals(certPair, certManager.generateCert());\n\n        certManager.certPair = new CertPair(\"\", \"\", \"\", Long.MAX_VALUE - 10000);\n        Assertions.assertEquals(new CertPair(\"\", \"\", \"\", Long.MAX_VALUE - 10000), certManager.generateCert());\n\n        certManager.certPair = new CertPair(\"\", \"\", \"\", 0);\n        Assertions.assertEquals(certPair, certManager.generateCert());\n\n        certManager.certPair = new CertPair(\"\", \"\", \"\", 0);\n        certPairReference.set(null);\n        Assertions.assertEquals(new CertPair(\"\", \"\", \"\", 0), certManager.generateCert());\n\n        exception.set(true);\n        Assertions.assertEquals(new CertPair(\"\", \"\", \"\", 0), certManager.generateCert());\n\n        frameworkModel.destroy();\n    }\n\n    @Test\n    void testSignWithRsa() {\n        DubboCertManager.KeyPair keyPair = DubboCertManager.signWithRsa();\n        Assertions.assertNotNull(keyPair);\n        Assertions.assertNotNull(keyPair.getPrivateKey());\n        Assertions.assertNotNull(keyPair.getPublicKey());\n        Assertions.assertNotNull(keyPair.getSigner());\n    }\n\n    @Test\n    void testSignWithEcdsa() {\n        DubboCertManager.KeyPair keyPair = DubboCertManager.signWithEcdsa();\n        Assertions.assertNotNull(keyPair);\n        Assertions.assertNotNull(keyPair.getPrivateKey());\n        Assertions.assertNotNull(keyPair.getPublicKey());\n        Assertions.assertNotNull(keyPair.getSigner());\n    }\n\n    @Test\n    void testRefreshCert() throws IOException {\n        try (MockedStatic<DubboCertManager> managerMock =\n                Mockito.mockStatic(DubboCertManager.class, CALLS_REAL_METHODS)) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            DubboCertManager certManager = new DubboCertManager(frameworkModel);\n            managerMock.when(DubboCertManager::signWithEcdsa).thenReturn(null);\n            managerMock.when(DubboCertManager::signWithRsa).thenReturn(null);\n\n            Assertions.assertNull(certManager.refreshCert());\n\n            managerMock.when(DubboCertManager::signWithEcdsa).thenCallRealMethod();\n\n            certManager.channel = Mockito.mock(Channel.class);\n            try (MockedStatic<DubboCertificateServiceGrpc> mockGrpc =\n                    Mockito.mockStatic(DubboCertificateServiceGrpc.class, CALLS_REAL_METHODS)) {\n                DubboCertificateServiceGrpc.DubboCertificateServiceBlockingStub stub =\n                        Mockito.mock(DubboCertificateServiceGrpc.DubboCertificateServiceBlockingStub.class);\n                mockGrpc.when(() -> DubboCertificateServiceGrpc.newBlockingStub(Mockito.any(Channel.class)))\n                        .thenReturn(stub);\n                Mockito.when(stub.createCertificate(Mockito.any()))\n                        .thenReturn(DubboCertificateResponse.newBuilder()\n                                .setSuccess(false)\n                                .build());\n\n                certManager.certConfig = new CertConfig(null, null, null, null);\n                Assertions.assertNull(certManager.refreshCert());\n\n                String file = this.getClass()\n                        .getClassLoader()\n                        .getResource(\"certs/token\")\n                        .getFile();\n                Mockito.when(stub.withInterceptors(Mockito.any())).thenReturn(stub);\n                certManager.certConfig = new CertConfig(null, null, null, file);\n\n                Assertions.assertNull(certManager.refreshCert());\n                Mockito.verify(stub, Mockito.times(1)).withInterceptors(Mockito.any());\n\n                Mockito.when(stub.createCertificate(Mockito.any()))\n                        .thenReturn(DubboCertificateResponse.newBuilder()\n                                .setSuccess(true)\n                                .setCertPem(\"certPem\")\n                                .addTrustCerts(\"trustCerts\")\n                                .setExpireTime(123456)\n                                .build());\n                CertPair certPair = certManager.refreshCert();\n                Assertions.assertNotNull(certPair);\n                Assertions.assertEquals(\"certPem\", certPair.getCertificate());\n                Assertions.assertEquals(\"trustCerts\", certPair.getTrustCerts());\n                Assertions.assertEquals(123456, certPair.getExpireTime());\n\n                Mockito.when(stub.createCertificate(Mockito.any())).thenReturn(null);\n                Assertions.assertNull(certManager.refreshCert());\n            }\n\n            frameworkModel.destroy();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/DubboCertProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.security.cert;\n\nimport org.apache.dubbo.common.ssl.AuthPolicy;\nimport org.apache.dubbo.common.ssl.Cert;\nimport org.apache.dubbo.common.ssl.ProviderCert;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedConstruction;\nimport org.mockito.Mockito;\n\nclass DubboCertProviderTest {\n    @Test\n    void testEnable() {\n        AtomicReference<DubboCertManager> reference = new AtomicReference<>();\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    reference.set(mock);\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            DubboCertProvider provider = new DubboCertProvider(frameworkModel);\n\n            Mockito.when(reference.get().isConnected()).thenReturn(true);\n            Assertions.assertTrue(provider.isSupport(null));\n\n            Mockito.when(reference.get().isConnected()).thenReturn(false);\n            Assertions.assertFalse(provider.isSupport(null));\n\n            frameworkModel.destroy();\n        }\n    }\n\n    @Test\n    void testEnable1() {\n        ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();\n        ClassLoader newClassLoader = new ClassLoader(originClassLoader) {\n            @Override\n            public Class<?> loadClass(String name) throws ClassNotFoundException {\n                if (name.startsWith(\"io.grpc.Channel\")) {\n                    throw new ClassNotFoundException(\"Test\");\n                }\n                return super.loadClass(name);\n            }\n        };\n        Thread.currentThread().setContextClassLoader(newClassLoader);\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    // ignore\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            DubboCertProvider provider = new DubboCertProvider(frameworkModel);\n\n            Assertions.assertFalse(provider.isSupport(null));\n\n            frameworkModel.destroy();\n        }\n        Thread.currentThread().setContextClassLoader(originClassLoader);\n    }\n\n    @Test\n    void testEnable2() {\n        ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();\n        ClassLoader newClassLoader = new ClassLoader(originClassLoader) {\n            @Override\n            public Class<?> loadClass(String name) throws ClassNotFoundException {\n                if (name.startsWith(\"org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder\")) {\n                    throw new ClassNotFoundException(\"Test\");\n                }\n                return super.loadClass(name);\n            }\n        };\n        Thread.currentThread().setContextClassLoader(newClassLoader);\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    // ignore\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            DubboCertProvider provider = new DubboCertProvider(frameworkModel);\n\n            Assertions.assertFalse(provider.isSupport(null));\n\n            frameworkModel.destroy();\n        }\n        Thread.currentThread().setContextClassLoader(originClassLoader);\n    }\n\n    @Test\n    void getProviderConnectionConfigTest() {\n        AtomicReference<DubboCertManager> reference = new AtomicReference<>();\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    reference.set(mock);\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            DubboCertProvider provider = new DubboCertProvider(frameworkModel);\n            Assertions.assertNull(provider.getProviderConnectionConfig(null));\n\n            CertPair certPair = new CertPair(\"privateKey\", \"publicKey\", \"trustCerts\", 12345);\n            Mockito.when(reference.get().generateCert()).thenReturn(certPair);\n            ProviderCert providerConnectionConfig = provider.getProviderConnectionConfig(null);\n            Assertions.assertArrayEquals(\"privateKey\".getBytes(), providerConnectionConfig.getPrivateKey());\n            Assertions.assertArrayEquals(\"publicKey\".getBytes(), providerConnectionConfig.getKeyCertChain());\n            Assertions.assertArrayEquals(\"trustCerts\".getBytes(), providerConnectionConfig.getTrustCert());\n            Assertions.assertEquals(AuthPolicy.NONE, providerConnectionConfig.getAuthPolicy());\n\n            frameworkModel.destroy();\n        }\n    }\n\n    @Test\n    void getConsumerConnectionConfigTest() {\n        AtomicReference<DubboCertManager> reference = new AtomicReference<>();\n        try (MockedConstruction<DubboCertManager> construction =\n                Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {\n                    reference.set(mock);\n                })) {\n            FrameworkModel frameworkModel = new FrameworkModel();\n            DubboCertProvider provider = new DubboCertProvider(frameworkModel);\n            Assertions.assertNull(provider.getConsumerConnectionConfig(null));\n\n            CertPair certPair = new CertPair(\"privateKey\", \"publicKey\", \"trustCerts\", 12345);\n            Mockito.when(reference.get().generateCert()).thenReturn(certPair);\n            Cert connectionConfig = provider.getConsumerConnectionConfig(null);\n            Assertions.assertArrayEquals(\"privateKey\".getBytes(), connectionConfig.getPrivateKey());\n            Assertions.assertArrayEquals(\"publicKey\".getBytes(), connectionConfig.getKeyCertChain());\n            Assertions.assertArrayEquals(\"trustCerts\".getBytes(), connectionConfig.getTrustCert());\n\n            frameworkModel.destroy();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/test/resources/certs/broken-ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV\nHQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau\nsPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m\noIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG\nDfcog5wrJytaQ6UA0wE=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/test/resources/certs/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla\nFw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0\nYXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT\nBnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7\n+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu\ng1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd\nQah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV\nHQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau\nsPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m\noIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG\nDfcog5wrJytaQ6UA0wE=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/test/resources/certs/token",
    "content": "tokentokentoken\n"
  },
  {
    "path": "dubbo-plugin/dubbo-security/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-spring-security</artifactId>\n  <packaging>jar</packaging>\n\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n\n  <dependencies>\n    <!-- dubbo -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-cluster</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <!-- dubbo -->\n\n    <!-- spring security -->\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-core</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-oauth2-client</artifactId>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n    <!-- spring security -->\n\n    <!-- jackson -->\n    <dependency>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <artifactId>jackson-core</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>com.fasterxml.jackson.datatype</groupId>\n      <artifactId>jackson-datatype-jsr310</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <artifactId>jackson-databind</artifactId>\n    </dependency>\n    <!-- jackson -->\n\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/filter/AuthenticationExceptionTranslatorFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.filter;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport org.springframework.security.access.AccessDeniedException;\nimport org.springframework.security.core.AuthenticationException;\n\nimport static org.apache.dubbo.rpc.RpcException.AUTHORIZATION_EXCEPTION;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.CORE_JACKSON_2_MODULE_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.JAVA_TIME_MODULE_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.OBJECT_MAPPER_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.SECURITY_CONTEXT_HOLDER_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.SIMPLE_MODULE_CLASS_NAME;\n\n@Activate(\n        group = CommonConstants.PROVIDER,\n        order = Integer.MAX_VALUE,\n        onClass = {\n            SECURITY_CONTEXT_HOLDER_CLASS_NAME,\n            CORE_JACKSON_2_MODULE_CLASS_NAME,\n            OBJECT_MAPPER_CLASS_NAME,\n            JAVA_TIME_MODULE_CLASS_NAME,\n            SIMPLE_MODULE_CLASS_NAME\n        })\npublic class AuthenticationExceptionTranslatorFilter implements Filter, Filter.Listener {\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        return invoker.invoke(invocation);\n    }\n\n    @Override\n    public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) {\n        if (this.isTranslate(result)) {\n            RpcException rpcException = new RpcException(result.getException().getMessage());\n\n            rpcException.setCode(AUTHORIZATION_EXCEPTION);\n\n            result.setException(rpcException);\n        }\n    }\n\n    @Override\n    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {}\n\n    private boolean isTranslate(Result result) {\n\n        Throwable exception = result.getException();\n\n        return result.hasException()\n                && (exception instanceof AuthenticationException || exception instanceof AccessDeniedException);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/filter/ContextHolderAuthenticationPrepareFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.filter;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.spring.security.jackson.ObjectMapperCodec;\nimport org.apache.dubbo.spring.security.utils.SecurityNames;\n\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.context.SecurityContext;\nimport org.springframework.security.core.context.SecurityContextHolder;\n\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.CORE_JACKSON_2_MODULE_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.JAVA_TIME_MODULE_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.OBJECT_MAPPER_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.SECURITY_CONTEXT_HOLDER_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.SIMPLE_MODULE_CLASS_NAME;\n\n@Activate(\n        group = CommonConstants.CONSUMER,\n        order = -10000,\n        onClass = {\n            SECURITY_CONTEXT_HOLDER_CLASS_NAME,\n            CORE_JACKSON_2_MODULE_CLASS_NAME,\n            OBJECT_MAPPER_CLASS_NAME,\n            JAVA_TIME_MODULE_CLASS_NAME,\n            SIMPLE_MODULE_CLASS_NAME\n        })\npublic class ContextHolderAuthenticationPrepareFilter implements ClusterFilter {\n\n    private final Logger logger = LoggerFactory.getLogger(getClass());\n    private final ObjectMapperCodec mapper;\n\n    public ContextHolderAuthenticationPrepareFilter(ApplicationModel applicationModel) {\n        this.mapper = applicationModel.getBeanFactory().getBean(ObjectMapperCodec.class);\n    }\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        if (this.mapper != null) {\n            setSecurityContext(invocation);\n        }\n\n        return invoker.invoke(invocation);\n    }\n\n    private void setSecurityContext(Invocation invocation) {\n        SecurityContext context = SecurityContextHolder.getContext();\n\n        Authentication authentication = context.getAuthentication();\n\n        String content = mapper.serialize(authentication);\n\n        if (StringUtils.isBlank(content)) {\n            return;\n        }\n\n        invocation.setObjectAttachment(SecurityNames.SECURITY_AUTHENTICATION_CONTEXT_KEY, content);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/filter/ContextHolderAuthenticationResolverFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.filter;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.Filter;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.spring.security.jackson.ObjectMapperCodec;\nimport org.apache.dubbo.spring.security.utils.SecurityNames;\n\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.context.SecurityContextHolder;\n\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.CORE_JACKSON_2_MODULE_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.JAVA_TIME_MODULE_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.OBJECT_MAPPER_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.SECURITY_CONTEXT_HOLDER_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.SIMPLE_MODULE_CLASS_NAME;\n\n@Activate(\n        group = CommonConstants.PROVIDER,\n        order = -10000,\n        onClass = {\n            SECURITY_CONTEXT_HOLDER_CLASS_NAME,\n            CORE_JACKSON_2_MODULE_CLASS_NAME,\n            OBJECT_MAPPER_CLASS_NAME,\n            JAVA_TIME_MODULE_CLASS_NAME,\n            SIMPLE_MODULE_CLASS_NAME\n        })\npublic class ContextHolderAuthenticationResolverFilter implements Filter {\n\n    private final ObjectMapperCodec mapper;\n\n    public ContextHolderAuthenticationResolverFilter(ApplicationModel applicationModel) {\n        this.mapper = applicationModel.getBeanFactory().getBean(ObjectMapperCodec.class);\n    }\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {\n        if (this.mapper != null) {\n            getSecurityContext(invocation);\n        }\n\n        try {\n            return invoker.invoke(invocation);\n        } finally {\n            if (this.mapper != null) {\n                SecurityContextHolder.clearContext();\n            }\n        }\n    }\n\n    private void getSecurityContext(Invocation invocation) {\n        String authenticationJSON = invocation.getAttachment(SecurityNames.SECURITY_AUTHENTICATION_CONTEXT_KEY);\n\n        if (StringUtils.isBlank(authenticationJSON)) {\n            return;\n        }\n\n        Authentication authentication = mapper.deserialize(authenticationJSON, Authentication.class);\n\n        if (authentication == null) {\n            return;\n        }\n\n        SecurityContextHolder.getContext().setAuthentication(authentication);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/filter/ContextHolderParametersSelectedTransferFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.filter;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.cluster.filter.ClusterFilter;\nimport org.apache.dubbo.spring.security.utils.SecurityNames;\n\nimport java.util.Map;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.SECURITY_AUTHENTICATION_CONTEXT_KEY;\n\n@Activate(group = CommonConstants.CONSUMER, order = -1)\npublic class ContextHolderParametersSelectedTransferFilter implements ClusterFilter {\n\n    @Override\n    public Result invoke(Invoker<?> invoker, Invocation invocation) {\n        this.setSecurityContextIfExists(invocation);\n\n        return invoker.invoke(invocation);\n    }\n\n    private void setSecurityContextIfExists(Invocation invocation) {\n        Map<String, Object> resultMap = RpcContext.getServerAttachment().getObjectAttachments();\n\n        Object authentication = resultMap.get(SECURITY_AUTHENTICATION_CONTEXT_KEY);\n\n        if (Objects.isNull(authentication)) {\n            return;\n        }\n\n        invocation.setObjectAttachment(SecurityNames.SECURITY_AUTHENTICATION_CONTEXT_KEY, authentication);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/jackson/ObjectMapperCodec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.jackson;\n\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ClassUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.module.SimpleModule;\nimport com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;\nimport org.springframework.security.jackson2.CoreJackson2Module;\n\npublic class ObjectMapperCodec {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ObjectMapperCodec.class);\n\n    private final ObjectMapper mapper = new ObjectMapper();\n\n    public ObjectMapperCodec() {\n        registerDefaultModule();\n    }\n\n    public <T> T deserialize(byte[] bytes, Class<T> clazz) {\n        try {\n            if (bytes == null || bytes.length == 0) {\n                return null;\n            }\n\n            return mapper.readValue(bytes, clazz);\n\n        } catch (Exception exception) {\n            logger.warn(\n                    LoggerCodeConstants.COMMON_JSON_CONVERT_EXCEPTION,\n                    \"objectMapper! deserialize error, you can try to customize the ObjectMapperCodecCustomer.\",\n                    \"\",\n                    \"\",\n                    exception);\n        }\n        return null;\n    }\n\n    public <T> T deserialize(String content, Class<T> clazz) {\n        if (StringUtils.isBlank(content)) {\n            return null;\n        }\n        return deserialize(content.getBytes(StandardCharsets.UTF_8), clazz);\n    }\n\n    public String serialize(Object object) {\n        try {\n\n            if (object == null) {\n                return null;\n            }\n\n            return mapper.writeValueAsString(object);\n\n        } catch (Exception ex) {\n            logger.warn(\n                    LoggerCodeConstants.COMMON_JSON_CONVERT_EXCEPTION,\n                    \"objectMapper! serialize error, you can try to customize the ObjectMapperCodecCustomer.\",\n                    \"\",\n                    \"\",\n                    ex);\n        }\n        return null;\n    }\n\n    public ObjectMapperCodec addModule(SimpleModule simpleModule) {\n        mapper.registerModule(simpleModule);\n        return this;\n    }\n\n    public ObjectMapperCodec configureMapper(Consumer<ObjectMapper> objectMapperConfigure) {\n        objectMapperConfigure.accept(this.mapper);\n        return this;\n    }\n\n    private void registerDefaultModule() {\n        mapper.registerModule(new CoreJackson2Module());\n        mapper.registerModule(new JavaTimeModule());\n\n        List<String> jacksonModuleClassNameList = new ArrayList<>();\n        jacksonModuleClassNameList.add(\n                \"org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module\");\n        jacksonModuleClassNameList.add(\n                \"org.springframework.security.oauth2.client.jackson2.OAuth2ClientJackson2Module\");\n        jacksonModuleClassNameList.add(\"org.springframework.security.web.server.jackson2.WebServerJackson2Module\");\n        jacksonModuleClassNameList.add(\"com.fasterxml.jackson.module.paramnames.ParameterNamesModule\");\n        jacksonModuleClassNameList.add(\"org.springframework.security.web.jackson2.WebServletJackson2Module\");\n        jacksonModuleClassNameList.add(\"org.springframework.security.web.jackson2.WebJackson2Module\");\n        jacksonModuleClassNameList.add(\"org.springframework.boot.jackson.JsonMixinModule\");\n        jacksonModuleClassNameList.add(\"org.springframework.security.ldap.jackson2.LdapJackson2Module\");\n        loadModuleIfPresent(jacksonModuleClassNameList);\n    }\n\n    private void loadModuleIfPresent(List<String> jacksonModuleClassNameList) {\n        for (String moduleClassName : jacksonModuleClassNameList) {\n            try {\n                SimpleModule objectMapperModule =\n                        (SimpleModule) ClassUtils.forName(moduleClassName, ObjectMapperCodec.class.getClassLoader())\n                                .getDeclaredConstructor()\n                                .newInstance();\n                mapper.registerModule(objectMapperModule);\n\n            } catch (Throwable ex) {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/jackson/ObjectMapperCodecCustomer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.jackson;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface ObjectMapperCodecCustomer {\n\n    void customize(ObjectMapperCodec objectMapperCodec);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/model/SecurityScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.model;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\nimport org.apache.dubbo.spring.security.jackson.ObjectMapperCodec;\nimport org.apache.dubbo.spring.security.jackson.ObjectMapperCodecCustomer;\n\nimport java.util.Set;\n\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.CORE_JACKSON_2_MODULE_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.JAVA_TIME_MODULE_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.OBJECT_MAPPER_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.SECURITY_CONTEXT_HOLDER_CLASS_NAME;\nimport static org.apache.dubbo.spring.security.utils.SecurityNames.SIMPLE_MODULE_CLASS_NAME;\n\n@Activate(\n        onClass = {\n            SECURITY_CONTEXT_HOLDER_CLASS_NAME,\n            CORE_JACKSON_2_MODULE_CLASS_NAME,\n            OBJECT_MAPPER_CLASS_NAME,\n            JAVA_TIME_MODULE_CLASS_NAME,\n            SIMPLE_MODULE_CLASS_NAME\n        })\npublic class SecurityScopeModelInitializer implements ScopeModelInitializer {\n\n    private final Logger logger = LoggerFactory.getLogger(getClass());\n\n    @Override\n    public void initializeFrameworkModel(FrameworkModel frameworkModel) {\n        ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();\n\n        try {\n            ObjectMapperCodec objectMapperCodec = new ObjectMapperCodec();\n\n            Set<ObjectMapperCodecCustomer> objectMapperCodecCustomerList = frameworkModel\n                    .getExtensionLoader(ObjectMapperCodecCustomer.class)\n                    .getSupportedExtensionInstances();\n\n            for (ObjectMapperCodecCustomer objectMapperCodecCustomer : objectMapperCodecCustomerList) {\n                objectMapperCodecCustomer.customize(objectMapperCodec);\n            }\n\n            beanFactory.registerBean(objectMapperCodec);\n        } catch (Throwable t) {\n            logger.info(\n                    \"Failed to initialize ObjectMapperCodecCustomer and spring security related features are disabled.\",\n                    t);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/utils/SecurityNames.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.utils;\n\npublic final class SecurityNames {\n\n    public static final String SECURITY_AUTHENTICATION_CONTEXT_KEY = \"security_authentication_context\";\n\n    public static final String SECURITY_CONTEXT_HOLDER_CLASS_NAME =\n            \"org.springframework.security.core.context.SecurityContextHolder\";\n    public static final String CORE_JACKSON_2_MODULE_CLASS_NAME =\n            \"org.springframework.security.jackson2.CoreJackson2Module\";\n    public static final String OBJECT_MAPPER_CLASS_NAME = \"com.fasterxml.jackson.databind.ObjectMapper\";\n    public static final String JAVA_TIME_MODULE_CLASS_NAME = \"com.fasterxml.jackson.datatype.jsr310.JavaTimeModule\";\n    public static final String SIMPLE_MODULE_CLASS_NAME = \"com.fasterxml.jackson.databind.module.SimpleModule\";\n\n    private SecurityNames() {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter",
    "content": "authenticationResolver=org.apache.dubbo.spring.security.filter.ContextHolderAuthenticationResolverFilter\nauthenticationExceptionTranslator=org.apache.dubbo.spring.security.filter.AuthenticationExceptionTranslatorFilter\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.filter.ClusterFilter",
    "content": "authenticationPrepare=org.apache.dubbo.spring.security.filter.ContextHolderAuthenticationPrepareFilter\ncontextHolderParametersSelectedTransfer=org.apache.dubbo.spring.security.filter.ContextHolderParametersSelectedTransferFilter\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "securityApplicationScopeModelInitializer = org.apache.dubbo.spring.security.model.SecurityScopeModelInitializer\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/test/java/org/apache/dubbo/spring/security/filter/ContextHolderAuthenticationResolverFilterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.filter;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.rpc.AppResponse;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.spring.security.jackson.ObjectMapperCodec;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.context.SecurityContextHolder;\n\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass ContextHolderAuthenticationResolverFilterTest {\n\n    @AfterEach\n    public void cleanup() {\n        SecurityContextHolder.clearContext();\n    }\n\n    @Test\n    void testSecurityContextIsClearedAfterInvoke() {\n        ApplicationModel applicationModel = mock(ApplicationModel.class);\n        ScopeBeanFactory beanFactory = mock(ScopeBeanFactory.class);\n        ObjectMapperCodec codec = mock(ObjectMapperCodec.class);\n\n        when(applicationModel.getBeanFactory()).thenReturn(beanFactory);\n        when(beanFactory.getBean(ObjectMapperCodec.class)).thenReturn(codec);\n\n        ContextHolderAuthenticationResolverFilter filter =\n                new ContextHolderAuthenticationResolverFilter(applicationModel);\n\n        Invocation invocation = mock(Invocation.class);\n        Invoker<?> invoker = mock(Invoker.class);\n\n        when(invoker.invoke(any(Invocation.class))).thenReturn(new AppResponse());\n        SecurityContextHolder.getContext()\n                .setAuthentication(new UsernamePasswordAuthenticationToken(\"user\", \"password\"));\n        filter.invoke(invoker, invocation);\n        Authentication auth = SecurityContextHolder.getContext().getAuthentication();\n\n        assertNull(\n                auth, \"SecurityContext must be cleared after the filter chain completes to prevent thread pollution.\");\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/test/java/org/apache/dubbo/spring/security/jackson/ObjectMapperCodecTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.jackson;\n\nimport java.time.Duration;\nimport java.time.Instant;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClient;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\nimport org.springframework.security.oauth2.core.OAuth2AccessToken;\n\npublic class ObjectMapperCodecTest {\n\n    private final ObjectMapperCodec mapper = new ObjectMapperCodec();\n\n    @Test\n    public void testOAuth2AuthorizedClientCodec() {\n        ClientRegistration clientRegistration = clientRegistration().build();\n        OAuth2AuthorizedClient authorizedClient =\n                new OAuth2AuthorizedClient(clientRegistration, \"principal-name\", noScopes());\n\n        String content = mapper.serialize(authorizedClient);\n\n        OAuth2AuthorizedClient deserialize = mapper.deserialize(content.getBytes(), OAuth2AuthorizedClient.class);\n\n        Assertions.assertNotNull(deserialize);\n    }\n\n    public static ClientRegistration.Builder clientRegistration() {\n        // @formatter:off\n        return ClientRegistration.withRegistrationId(\"registration-id\")\n                .redirectUri(\"http://localhost/uua/oauth2/code/{registrationId}\")\n                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)\n                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)\n                .scope(\"read:user\")\n                .authorizationUri(\"https://example.com/login/oauth/authorize\")\n                .tokenUri(\"https://example.com/login/oauth/access_token\")\n                .jwkSetUri(\"https://example.com/oauth2/jwk\")\n                .issuerUri(\"https://example.com\")\n                .userInfoUri(\"https://api.example.com/user\")\n                .userNameAttributeName(\"id\")\n                .clientName(\"Client Name\")\n                .clientId(\"client-id\")\n                .clientSecret(\"client-secret\");\n        // @formatter:on\n    }\n\n    public static OAuth2AccessToken noScopes() {\n        return new OAuth2AccessToken(\n                OAuth2AccessToken.TokenType.BEARER,\n                \"no-scopes\",\n                Instant.now(),\n                Instant.now().plus(Duration.ofDays(1)));\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring-security/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-spring6-security</artifactId>\n  <packaging>jar</packaging>\n\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n    <spring.oauth2.server>1.5.6</spring.oauth2.server>\n  </properties>\n\n  <dependencies>\n    <!-- spring6 -->\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-core</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-beans</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-context</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-aop</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-web</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-jcl</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-expression</artifactId>\n      <version>${spring-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-test</artifactId>\n      <version>${spring-6.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n    <!-- spring6 -->\n\n    <!-- dubbo spring security -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-spring-security</artifactId>\n      <version>${project.version}</version>\n      <exclusions>\n        <exclusion>\n          <groupId>org.springframework.security</groupId>\n          <artifactId>spring-security-core</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <!-- dubbo spring security -->\n\n    <!-- spring6 security -->\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-config</artifactId>\n      <version>${spring-security-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-core</artifactId>\n      <version>${spring-security-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-web</artifactId>\n      <version>${spring-security-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-crypto</artifactId>\n      <version>${spring-security-6.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-oauth2-core</artifactId>\n      <version>${spring-security-6.version}</version>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-oauth2-jose</artifactId>\n      <version>${spring-security-6.version}</version>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-oauth2-resource-server</artifactId>\n      <version>${spring-security-6.version}</version>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-oauth2-authorization-server</artifactId>\n      <version>${spring.oauth2.server}</version>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.security</groupId>\n      <artifactId>spring-security-oauth2-client</artifactId>\n      <version>${spring-security-6.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n    <!-- spring security -->\n\n    <!-- spring boot 3 for test -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter</artifactId>\n      <version>${spring-boot-3.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot</artifactId>\n      <version>${spring-boot-3.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-autoconfigure</artifactId>\n      <version>${spring-boot-3.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-logging</artifactId>\n      <version>${spring-boot-3.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-test</artifactId>\n      <version>${spring-boot-3.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-test-autoconfigure</artifactId>\n      <version>${spring-boot-3.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <version>${spring-boot-3.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n      <exclusions>\n        <exclusion>\n          <groupId>ch.qos.logback</groupId>\n          <artifactId>logback-classic</artifactId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <!-- spring boot 3 for test -->\n\n    <!-- dubbo-config-spring6 for test -->\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-config-spring6</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n      <optional>true</optional>\n    </dependency>\n    <!-- dubbo-config-spring6 for test -->\n\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <configuration>\n          <source>17</source>\n          <target>17</target>\n          <release>17</release>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/AuthorizationGrantTypeMixin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\n\n@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)\n@JsonAutoDetect(\n        fieldVisibility = JsonAutoDetect.Visibility.ANY,\n        getterVisibility = JsonAutoDetect.Visibility.NONE,\n        isGetterVisibility = JsonAutoDetect.Visibility.NONE,\n        creatorVisibility = JsonAutoDetect.Visibility.NONE)\n@JsonIgnoreProperties(ignoreUnknown = true)\nabstract class AuthorizationGrantTypeMixin {\n\n    @JsonCreator\n    public AuthorizationGrantTypeMixin(@JsonProperty(\"value\") String value) {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/BearerTokenAuthenticationMixin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport java.util.Collection;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.oauth2.core.OAuth2AccessToken;\nimport org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;\n\n@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)\n@JsonAutoDetect(\n        fieldVisibility = JsonAutoDetect.Visibility.ANY,\n        getterVisibility = JsonAutoDetect.Visibility.NONE,\n        isGetterVisibility = JsonAutoDetect.Visibility.NONE,\n        creatorVisibility = JsonAutoDetect.Visibility.NONE)\n@JsonIgnoreProperties(ignoreUnknown = true)\nabstract class BearerTokenAuthenticationMixin {\n\n    @JsonCreator\n    public BearerTokenAuthenticationMixin(\n            @JsonProperty(\"principal\") OAuth2AuthenticatedPrincipal principal,\n            @JsonProperty(\"credentials\") OAuth2AccessToken credentials,\n            @JsonProperty(\"authorities\") Collection<? extends GrantedAuthority> authorities) {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/ClientAuthenticationMethodMixin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\n\n@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)\n@JsonAutoDetect(\n        fieldVisibility = JsonAutoDetect.Visibility.ANY,\n        getterVisibility = JsonAutoDetect.Visibility.NONE,\n        isGetterVisibility = JsonAutoDetect.Visibility.NONE,\n        creatorVisibility = JsonAutoDetect.Visibility.NONE)\n@JsonIgnoreProperties(ignoreUnknown = true)\nabstract class ClientAuthenticationMethodMixin {\n\n    @JsonCreator\n    public ClientAuthenticationMethodMixin(@JsonProperty(\"value\") String value) {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/ClientSettingsMixin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport java.util.Map;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\n\n@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)\n@JsonAutoDetect(\n        fieldVisibility = JsonAutoDetect.Visibility.ANY,\n        getterVisibility = JsonAutoDetect.Visibility.NONE,\n        isGetterVisibility = JsonAutoDetect.Visibility.NONE,\n        creatorVisibility = JsonAutoDetect.Visibility.NONE)\n@JsonIgnoreProperties(ignoreUnknown = true)\nabstract class ClientSettingsMixin {\n\n    @JsonCreator\n    public ClientSettingsMixin(@JsonProperty(\"settings\") Map<String, Object> settings) {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/OAuth2AuthenticatedPrincipalMixin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport java.util.Collection;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\nimport org.springframework.security.core.GrantedAuthority;\n\n@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)\n@JsonAutoDetect(\n        fieldVisibility = JsonAutoDetect.Visibility.ANY,\n        getterVisibility = JsonAutoDetect.Visibility.NONE,\n        isGetterVisibility = JsonAutoDetect.Visibility.NONE,\n        creatorVisibility = JsonAutoDetect.Visibility.NONE)\n@JsonIgnoreProperties(ignoreUnknown = true)\nabstract class OAuth2AuthenticatedPrincipalMixin {\n\n    @JsonCreator\n    public OAuth2AuthenticatedPrincipalMixin(\n            @JsonProperty(\"name\") String name,\n            @JsonProperty(\"attributes\") Map<String, Object> attributes,\n            @JsonProperty(\"authorities\") Collection<? extends GrantedAuthority> authorities) {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/OAuth2ClientAuthenticationTokenMixin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport java.util.Map;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\nimport org.springframework.lang.Nullable;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\n\n@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)\n@JsonAutoDetect(\n        fieldVisibility = JsonAutoDetect.Visibility.ANY,\n        getterVisibility = JsonAutoDetect.Visibility.NONE,\n        isGetterVisibility = JsonAutoDetect.Visibility.NONE,\n        creatorVisibility = JsonAutoDetect.Visibility.NONE)\n@JsonIgnoreProperties(ignoreUnknown = true)\nabstract class OAuth2ClientAuthenticationTokenMixin {\n\n    @JsonCreator\n    public OAuth2ClientAuthenticationTokenMixin(\n            @JsonProperty(\"clientId\") String clientId,\n            @JsonProperty(\"clientAuthenticationMethod\") ClientAuthenticationMethod clientAuthenticationMethod,\n            @JsonProperty(\"credentials\") @Nullable Object credentials,\n            @JsonProperty(\"additionalParameters\") @Nullable Map<String, Object> additionalParameters) {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/OAuth2SecurityModule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\n\nimport com.fasterxml.jackson.databind.module.SimpleModule;\n\npublic class OAuth2SecurityModule extends SimpleModule {\n\n    public OAuth2SecurityModule() {\n        super(OAuth2SecurityModule.class.getName());\n    }\n\n    @Override\n    public void setupModule(SetupContext context) {\n        setMixInAnnotations(\n                context,\n                \"org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal\",\n                \"org.apache.dubbo.spring.security.oauth2.OAuth2AuthenticatedPrincipalMixin\");\n        setMixInAnnotations(\n                context,\n                \"org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal\",\n                \"org.apache.dubbo.spring.security.oauth2.OAuth2AuthenticatedPrincipalMixin\");\n        setMixInAnnotations(\n                context,\n                \"org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication\",\n                \"org.apache.dubbo.spring.security.oauth2.BearerTokenAuthenticationMixin\");\n        setMixInAnnotations(\n                context,\n                \"org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken\",\n                \"org.apache.dubbo.spring.security.oauth2.OAuth2ClientAuthenticationTokenMixin\");\n        setMixInAnnotations(\n                context,\n                \"org.springframework.security.oauth2.core.ClientAuthenticationMethod\",\n                ClientAuthenticationMethodMixin.class);\n        setMixInAnnotations(\n                context,\n                \"org.springframework.security.oauth2.server.authorization.client.RegisteredClient\",\n                \"org.apache.dubbo.spring.security.oauth2.RegisteredClientMixin\");\n        setMixInAnnotations(\n                context,\n                \"org.springframework.security.oauth2.core.AuthorizationGrantType\",\n                AuthorizationGrantTypeMixin.class);\n        setMixInAnnotations(\n                context,\n                \"org.springframework.security.oauth2.server.authorization.settings.ClientSettings\",\n                ClientSettingsMixin.class);\n        setMixInAnnotations(\n                context,\n                \"org.springframework.security.oauth2.server.authorization.settings.TokenSettings\",\n                TokenSettingsMixin.class);\n        context.setMixInAnnotations(\n                Collections.unmodifiableCollection(new ArrayList<>()).getClass(), UnmodifiableCollectionMixin.class);\n    }\n\n    private void setMixInAnnotations(SetupContext context, String oauth2ClassName, String mixinClassName) {\n        Class<?> oauth2Class = loadClassIfPresent(oauth2ClassName);\n        if (oauth2Class != null) {\n            context.setMixInAnnotations(oauth2Class, loadClassIfPresent(mixinClassName));\n        }\n    }\n\n    private void setMixInAnnotations(SetupContext context, String oauth2ClassName, Class<?> mixinClass) {\n        Class<?> oauth2Class = loadClassIfPresent(oauth2ClassName);\n        if (oauth2Class != null) {\n            context.setMixInAnnotations(oauth2Class, mixinClass);\n        }\n    }\n\n    private Class<?> loadClassIfPresent(String oauth2ClassName) {\n        try {\n            return ClassUtils.forName(oauth2ClassName, OAuth2SecurityModule.class.getClassLoader());\n\n        } catch (Throwable ignored) {\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/RegisteredClientMixin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport java.time.Instant;\nimport java.util.Set;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\nimport org.springframework.security.oauth2.server.authorization.settings.ClientSettings;\nimport org.springframework.security.oauth2.server.authorization.settings.TokenSettings;\n\n@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)\n@JsonAutoDetect(\n        fieldVisibility = JsonAutoDetect.Visibility.ANY,\n        getterVisibility = JsonAutoDetect.Visibility.NONE,\n        isGetterVisibility = JsonAutoDetect.Visibility.NONE,\n        creatorVisibility = JsonAutoDetect.Visibility.NONE)\n@JsonIgnoreProperties(ignoreUnknown = true)\nabstract class RegisteredClientMixin {\n\n    @JsonCreator\n    public RegisteredClientMixin(\n            @JsonProperty(\"id\") String id,\n            @JsonProperty(\"clientId\") String clientId,\n            @JsonProperty(\"clientIdIssuedAt\") Instant clientIdIssuedAt,\n            @JsonProperty(\"clientSecret\") String clientSecret,\n            @JsonProperty(\"clientSecretExpiresAt\") Instant clientSecretExpiresAt,\n            @JsonProperty(\"clientName\") String clientName,\n            @JsonProperty(\"clientAuthenticationMethods\") Set<ClientAuthenticationMethod> clientAuthenticationMethods,\n            @JsonProperty(\"authorizationGrantTypes\") Set<AuthorizationGrantType> authorizationGrantTypes,\n            @JsonProperty(\"redirectUris\") Set<String> redirectUris,\n            @JsonProperty(\"postLogoutRedirectUris\") Set<String> postLogoutRedirectUris,\n            @JsonProperty(\"scopes\") Set<String> scopes,\n            @JsonProperty(\"clientSettings\") ClientSettings clientSettings,\n            @JsonProperty(\"tokenSettings\") TokenSettings tokenSettings) {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/TokenSettingsMixin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport java.util.Map;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\n\n@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)\n@JsonAutoDetect(\n        fieldVisibility = JsonAutoDetect.Visibility.ANY,\n        getterVisibility = JsonAutoDetect.Visibility.NONE,\n        isGetterVisibility = JsonAutoDetect.Visibility.NONE,\n        creatorVisibility = JsonAutoDetect.Visibility.NONE)\n@JsonIgnoreProperties(ignoreUnknown = true)\nabstract class TokenSettingsMixin {\n\n    @JsonCreator\n    public TokenSettingsMixin(@JsonProperty(\"settings\") Map<String, Object> settings) {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/UnmodifiableCollectionMixin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport org.apache.dubbo.spring.security.oauth2.UnmodifiableCollectionMixin.UnmodifiableCollectionConverter;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport com.fasterxml.jackson.databind.annotation.JsonDeserialize;\nimport com.fasterxml.jackson.databind.util.StdConverter;\n\n@JsonDeserialize(converter = UnmodifiableCollectionConverter.class)\nabstract class UnmodifiableCollectionMixin {\n\n    public static class UnmodifiableCollectionConverter extends StdConverter<Collection<Object>, Collection<Object>> {\n\n        @Override\n        public Collection<Object> convert(Collection<Object> value) {\n            return Collections.unmodifiableCollection(value);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/java/org/apache/dubbo/spring/security/oauth2/jackson/OAuth2ObjectMapperCodecCustomer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2.jackson;\n\nimport org.apache.dubbo.spring.security.jackson.ObjectMapperCodec;\nimport org.apache.dubbo.spring.security.jackson.ObjectMapperCodecCustomer;\nimport org.apache.dubbo.spring.security.oauth2.OAuth2SecurityModule;\n\nimport java.util.List;\n\nimport com.fasterxml.jackson.databind.Module;\nimport org.springframework.security.jackson2.SecurityJackson2Modules;\n\npublic class OAuth2ObjectMapperCodecCustomer implements ObjectMapperCodecCustomer {\n\n    @Override\n    public void customize(ObjectMapperCodec objectMapperCodec) {\n        objectMapperCodec.configureMapper(mapper -> {\n            mapper.registerModule(new OAuth2SecurityModule());\n            List<Module> securityModules =\n                    SecurityJackson2Modules.getModules(this.getClass().getClassLoader());\n            mapper.registerModules(securityModules);\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.spring.security.jackson.ObjectMapperCodecCustomer",
    "content": "oauth2Customer=org.apache.dubbo.spring.security.oauth2.jackson.OAuth2ObjectMapperCodecCustomer\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/test/java/org/apache/dubbo/spring/security/oauth2/DeserializationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.spring.security.oauth2;\n\nimport org.apache.dubbo.config.bootstrap.DubboBootstrap;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.spring.security.jackson.ObjectMapperCodec;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\nimport org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;\nimport org.springframework.security.oauth2.core.OAuth2AccessToken;\nimport org.springframework.security.oauth2.core.OAuth2AccessToken.TokenType;\nimport org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClient;\nimport org.springframework.security.oauth2.server.authorization.settings.ClientSettings;\nimport org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;\nimport org.springframework.security.oauth2.server.authorization.settings.TokenSettings;\nimport org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;\n\n@SpringBootTest(\n        properties = {\"dubbo.registry.address=N/A\"},\n        classes = {DeserializationTest.class})\n@Configuration\npublic class DeserializationTest {\n\n    private static ObjectMapperCodec mapper;\n\n    @BeforeAll\n    public static void beforeAll() {\n        DubboBootstrap.reset();\n        mapper = ApplicationModel.defaultModel().getDefaultModule().getBean(ObjectMapperCodec.class);\n    }\n\n    @AfterAll\n    public static void afterAll() {\n        DubboBootstrap.reset();\n    }\n\n    @Test\n    public void bearerTokenAuthenticationTest() {\n        BearerTokenAuthentication bearerTokenAuthentication = new BearerTokenAuthentication(\n                new DefaultOAuth2AuthenticatedPrincipal(\n                        \"principal-name\",\n                        Collections.singletonMap(\"name\", \"kali\"),\n                        Collections.singleton(new SimpleGrantedAuthority(\"1\"))),\n                new OAuth2AccessToken(TokenType.BEARER, \"111\", Instant.MIN, Instant.MAX),\n                Collections.emptyList());\n        String content = mapper.serialize(bearerTokenAuthentication);\n\n        BearerTokenAuthentication deserialize = mapper.deserialize(content.getBytes(), BearerTokenAuthentication.class);\n\n        Assertions.assertNotNull(deserialize);\n    }\n\n    @Test\n    public void oauth2ClientAuthenticationTokenTest() {\n        OAuth2ClientAuthenticationToken oAuth2ClientAuthenticationToken = new OAuth2ClientAuthenticationToken(\n                \"client-id\", ClientAuthenticationMethod.CLIENT_SECRET_POST, \"111\", Collections.emptyMap());\n\n        String content = mapper.serialize(oAuth2ClientAuthenticationToken);\n\n        OAuth2ClientAuthenticationToken deserialize =\n                mapper.deserialize(content.getBytes(), OAuth2ClientAuthenticationToken.class);\n\n        Assertions.assertNotNull(deserialize);\n    }\n\n    @Test\n    public void registeredClientTest() {\n        RegisteredClient registeredClient = RegisteredClient.withId(\"id\")\n                .clientId(\"client-id\")\n                .clientName(\"client-name\")\n                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)\n                .redirectUri(\"https://example.com\")\n                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT)\n                .clientSecret(\"client-secret\")\n                .clientIdIssuedAt(Instant.MIN)\n                .clientSecretExpiresAt(Instant.MAX)\n                .tokenSettings(TokenSettings.builder()\n                        .accessTokenFormat(OAuth2TokenFormat.REFERENCE)\n                        .accessTokenTimeToLive(Duration.ofSeconds(1000))\n                        .build())\n                .clientSettings(ClientSettings.builder()\n                        .setting(\"name\", \"value\")\n                        .requireProofKey(true)\n                        .build())\n                .build();\n\n        String content = mapper.serialize(registeredClient);\n\n        RegisteredClient deserialize = mapper.deserialize(content.getBytes(), RegisteredClient.class);\n\n        Assertions.assertEquals(registeredClient, deserialize);\n    }\n\n    @Configuration\n    @ImportResource(\"classpath:/dubbo-test.xml\")\n    public static class OAuth2SecurityTestConfiguration {}\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/test/resources/dubbo-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~\n  ~   Licensed to the Apache Software Foundation (ASF) under one or more\n  ~   contributor license agreements.  See the NOTICE file distributed with\n  ~   this work for additional information regarding copyright ownership.\n  ~   The ASF licenses this file to You under the Apache License, Version 2.0\n  ~   (the \"License\"); you may not use this file except in compliance with\n  ~   the License.  You may obtain a copy of the License at\n  ~\n  ~       http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~   Unless required by applicable law or agreed to in writing, software\n  ~   distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~   See the License for the specific language governing permissions and\n  ~   limitations under the License.\n  ~\n  -->\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:dubbo=\"http://code.alibabatech.com/schema/dubbo\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans\n\t\thttp://www.springframework.org/schema/beans/spring-beans.xsd\n\t\thttp://code.alibabatech.com/schema/dubbo\n\t\thttp://code.alibabatech.com/schema/dubbo/dubbo.xsd\" default-lazy-init =\"false\">\n\n\t<dubbo:application name=\"oauth2-security-test-app\"/>\n\n\t<dubbo:registry client=\"curator\" address=\"${dubbo.registry.address}\"/>\n\n\t<dubbo:protocol name=\"dubbo\" port=\"20880\"/>\n</beans>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-spring6-security/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-triple-servlet</artifactId>\n\n  <properties>\n    <servlet4_version>4.0.1</servlet4_version>\n    <sources_directory>${project.build.directory}/generated-sources/java/org/apache/dubbo/rpc/protocol/tri</sources_directory>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>javax.servlet</groupId>\n      <artifactId>javax.servlet-api</artifactId>\n      <version>${servlet4_version}</version>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>jakarta.servlet</groupId>\n      <artifactId>jakarta.servlet-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <profiles>\n    <profile>\n      <id>jdk-version-ge-17</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-antrun-plugin</artifactId>\n            <executions>\n              <execution>\n                <id>generate-jakarta</id>\n                <goals>\n                  <goal>run</goal>\n                </goals>\n                <phase>generate-sources</phase>\n                <configuration>\n                  <target>\n                    <copy overwrite=\"true\" todir=\"${sources_directory}/servlet/jakarta\">\n                      <fileset dir=\"src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet\" />\n                    </copy>\n                    <copy overwrite=\"true\" todir=\"${sources_directory}/rest/support/servlet/jakarta\">\n                      <fileset dir=\"src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet\" />\n                    </copy>\n                    <replace token=\".servlet;\" value=\".servlet.jakarta;\">\n                      <fileset dir=\"${sources_directory}\" />\n                    </replace>\n                    <replace token=\"javax.servlet\" value=\"jakarta.servlet\">\n                      <fileset dir=\"${sources_directory}\" />\n                    </replace>\n                    <replace file=\"${sources_directory}/rest/support/servlet/jakarta/ServletHttpRequestAdapter.java\">\n                      <replacetoken>/* jakarta placeholder */</replacetoken>\n                      <replacevalue><![CDATA[@Override\n    public String getRequestId() {\n        return \"\";\n    }\n\n    @Override\n    public String getProtocolRequestId() {\n        return \"\";\n    }\n\n    @Override\n    public jakarta.servlet.ServletConnection getServletConnection() {\n        return null;\n    }]]></replacevalue>\n                    </replace>\n                    <replace file=\"${sources_directory}/rest/support/servlet/jakarta/ServletHttpMessageAdapterFactory.java\" token=\"-100\" value=\"-200\" />\n                    <replace file=\"${sources_directory}/rest/support/servlet/jakarta/FilterAdapter.java\" token=\"&quot;servlet\" value=\"&quot;jakarta-servlet\" />\n                  </target>\n                </configuration>\n              </execution>\n            </executions>\n          </plugin>\n          <plugin>\n            <groupId>org.codehaus.mojo</groupId>\n            <artifactId>build-helper-maven-plugin</artifactId>\n            <executions>\n              <execution>\n                <id>add-sources</id>\n                <goals>\n                  <goal>add-source</goal>\n                </goals>\n                <phase>generate-sources</phase>\n                <configuration>\n                  <sources>\n                    <source>${project.build.directory}/generated-sources/java</source>\n                  </sources>\n                </configuration>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n    <profile>\n      <id>release</id>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-enforcer-plugin</artifactId>\n            <executions>\n              <execution>\n                <id>enforce-generate-jakarta</id>\n                <goals>\n                  <goal>enforce</goal>\n                </goals>\n                <phase>prepare-package</phase>\n                <configuration>\n                  <rules>\n                    <requireFilesExist>\n                      <files>\n                        <file>${sources_directory}/servlet/jakarta/TripleFilter.java</file>\n                      </files>\n                    </requireFilesExist>\n                  </rules>\n                  <fail>true</fail>\n                </configuration>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/DummyFilterConfig.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;\n\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\n\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletContext;\n\nimport java.util.Collections;\nimport java.util.Enumeration;\n\nfinal class DummyFilterConfig implements FilterConfig {\n\n    private final String filterName;\n    private final FrameworkModel frameworkModel;\n    private final ServletContext servletContext;\n\n    public DummyFilterConfig(String filterName, FrameworkModel frameworkModel, ServletContext servletContext) {\n        this.filterName = filterName;\n        this.frameworkModel = frameworkModel;\n        this.servletContext = servletContext;\n    }\n\n    @Override\n    public String getFilterName() {\n        return filterName;\n    }\n\n    @Override\n    public ServletContext getServletContext() {\n        return servletContext;\n    }\n\n    @Override\n    public String getInitParameter(String name) {\n        String prefix = RestConstants.CONFIG_PREFIX + \"filter-config.\";\n        Configuration conf = ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication());\n        String value = conf.getString(prefix + filterName + \".\" + name);\n        if (value == null) {\n            value = conf.getString(prefix + name);\n        }\n        return value;\n    }\n\n    @Override\n    public Enumeration<String> getInitParameterNames() {\n        return Collections.emptyEnumeration();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/DummyServletContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;\n\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;\n\nimport javax.servlet.Filter;\nimport javax.servlet.FilterRegistration;\nimport javax.servlet.RequestDispatcher;\nimport javax.servlet.Servlet;\nimport javax.servlet.ServletContext;\nimport javax.servlet.ServletRegistration;\nimport javax.servlet.ServletRegistration.Dynamic;\nimport javax.servlet.SessionCookieConfig;\nimport javax.servlet.SessionTrackingMode;\nimport javax.servlet.descriptor.JspConfigDescriptor;\n\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.EventListener;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nfinal class DummyServletContext implements ServletContext {\n\n    private final FrameworkModel frameworkModel;\n    private final Map<String, Object> attributes = new HashMap<>();\n    private final Map<String, String> initParameters = new HashMap<>();\n\n    public DummyServletContext(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public String getContextPath() {\n        return \"/\";\n    }\n\n    @Override\n    public ServletContext getContext(String uripath) {\n        return this;\n    }\n\n    @Override\n    public int getMajorVersion() {\n        return 3;\n    }\n\n    @Override\n    public int getMinorVersion() {\n        return 1;\n    }\n\n    @Override\n    public int getEffectiveMajorVersion() {\n        return 3;\n    }\n\n    @Override\n    public int getEffectiveMinorVersion() {\n        return 1;\n    }\n\n    @Override\n    public String getMimeType(String file) {\n        return null;\n    }\n\n    @Override\n    public Set<String> getResourcePaths(String path) {\n        return null;\n    }\n\n    @Override\n    public URL getResource(String path) {\n        return null;\n    }\n\n    @Override\n    public InputStream getResourceAsStream(String path) {\n        return null;\n    }\n\n    @Override\n    public RequestDispatcher getRequestDispatcher(String path) {\n        return null;\n    }\n\n    @Override\n    public RequestDispatcher getNamedDispatcher(String name) {\n        return null;\n    }\n\n    public Servlet getServlet(String name) {\n        throw new UnsupportedOperationException();\n    }\n\n    public Enumeration<Servlet> getServlets() {\n        throw new UnsupportedOperationException();\n    }\n\n    public Enumeration<String> getServletNames() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void log(String msg) {\n        LoggerFactory.getLogger(DummyServletContext.class).info(msg);\n    }\n\n    public void log(Exception exception, String msg) {\n        LoggerFactory.getLogger(DummyServletContext.class).info(msg, exception);\n    }\n\n    @Override\n    public void log(String message, Throwable throwable) {\n        LoggerFactory.getLogger(DummyServletContext.class).info(message, throwable);\n    }\n\n    @Override\n    public String getRealPath(String path) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getServerInfo() {\n        return \"Dubbo Rest Server/1.0\";\n    }\n\n    @Override\n    public String getInitParameter(String name) {\n        String value = initParameters.get(name);\n        if (value != null) {\n            return value;\n        }\n        Configuration conf = ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication());\n        return conf.getString(RestConstants.CONFIG_PREFIX + \"servlet-context.\" + name);\n    }\n\n    @Override\n    public Enumeration<String> getInitParameterNames() {\n        return Collections.enumeration(initParameters.keySet());\n    }\n\n    @Override\n    public boolean setInitParameter(String name, String value) {\n        return initParameters.putIfAbsent(name, value) == null;\n    }\n\n    @Override\n    public Object getAttribute(String name) {\n        return attributes.get(name);\n    }\n\n    @Override\n    public Enumeration<String> getAttributeNames() {\n        return Collections.enumeration(attributes.keySet());\n    }\n\n    @Override\n    public void setAttribute(String name, Object object) {\n        attributes.put(name, object);\n    }\n\n    @Override\n    public void removeAttribute(String name) {\n        attributes.remove(name);\n    }\n\n    @Override\n    public String getServletContextName() {\n        return \"\";\n    }\n\n    @Override\n    public ServletRegistration.Dynamic addServlet(String servletName, String className) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Dynamic addJspFile(String servletName, String jspFile) {\n        return null;\n    }\n\n    @Override\n    public <T extends Servlet> T createServlet(Class<T> clazz) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public ServletRegistration getServletRegistration(String servletName) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Map<String, ? extends ServletRegistration> getServletRegistrations() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public FilterRegistration.Dynamic addFilter(String filterName, String className) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public <T extends Filter> T createFilter(Class<T> clazz) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public FilterRegistration getFilterRegistration(String filterName) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Map<String, ? extends FilterRegistration> getFilterRegistrations() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public SessionCookieConfig getSessionCookieConfig() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void addListener(String className) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public <T extends EventListener> void addListener(T t) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void addListener(Class<? extends EventListener> listenerClass) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public <T extends EventListener> T createListener(Class<T> clazz) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public JspConfigDescriptor getJspConfigDescriptor() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public ClassLoader getClassLoader() {\n        return getClass().getClassLoader();\n    }\n\n    @Override\n    public void declareRoles(String... roleNames) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getVirtualServerName() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int getSessionTimeout() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setSessionTimeout(int i) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getRequestCharacterEncoding() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setRequestCharacterEncoding(String encoding) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getResponseCharacterEncoding() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setResponseCharacterEncoding(String encoding) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/FileUploadPart.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;\n\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestException;\n\nimport javax.servlet.http.Part;\n\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Collection;\nimport java.util.Collections;\n\npublic final class FileUploadPart implements Part {\n\n    private final HttpRequest.FileUpload fileUpload;\n\n    public FileUploadPart(HttpRequest.FileUpload fileUpload) {\n        this.fileUpload = fileUpload;\n    }\n\n    @Override\n    public InputStream getInputStream() {\n        return fileUpload.inputStream();\n    }\n\n    @Override\n    public String getContentType() {\n        return fileUpload.contentType();\n    }\n\n    @Override\n    public String getName() {\n        return fileUpload.name();\n    }\n\n    @Override\n    public String getSubmittedFileName() {\n        return fileUpload.filename();\n    }\n\n    @Override\n    public long getSize() {\n        return fileUpload.size();\n    }\n\n    @Override\n    public void write(String fileName) {\n        try (FileOutputStream fos = new FileOutputStream(fileName)) {\n            StreamUtils.copy(fileUpload.inputStream(), fos);\n        } catch (IOException e) {\n            throw new RestException(e);\n        }\n    }\n\n    @Override\n    public void delete() {}\n\n    @Override\n    public String getHeader(String name) {\n        return null;\n    }\n\n    @Override\n    public Collection<String> getHeaders(String name) {\n        return null;\n    }\n\n    @Override\n    public Collection<String> getHeaderNames() {\n        return Collections.emptyList();\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/FilterAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RestUtils;\n\nimport javax.servlet.Filter;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\n\nimport java.io.IOException;\nimport java.util.Arrays;\n\n@Activate(onClass = \"javax.servlet.Filter\")\npublic final class FilterAdapter implements RestExtensionAdapter<Filter> {\n\n    private final ServletHttpMessageAdapterFactory adapterFactory;\n\n    public FilterAdapter(FrameworkModel frameworkModel) {\n        adapterFactory = (ServletHttpMessageAdapterFactory)\n                frameworkModel.getExtension(HttpMessageAdapterFactory.class, \"servlet\");\n    }\n\n    @Override\n    public boolean accept(Object extension) {\n        return extension instanceof Filter;\n    }\n\n    @Override\n    public RestFilter adapt(Filter extension) {\n        try {\n            String filterName = extension.getClass().getSimpleName();\n            extension.init((FilterConfig) adapterFactory.adaptFilterConfig(filterName));\n        } catch (ServletException e) {\n            throw new RestException(e);\n        }\n        return new FilterRestFilter(extension);\n    }\n\n    private static final class FilterRestFilter implements RestFilter {\n\n        private final Filter filter;\n\n        @Override\n        public int getPriority() {\n            return RestUtils.getPriority(filter);\n        }\n\n        @Override\n        public String[] getPatterns() {\n            return RestUtils.getPattens(filter);\n        }\n\n        public FilterRestFilter(Filter filter) {\n            this.filter = filter;\n        }\n\n        @Override\n        public void doFilter(HttpRequest request, HttpResponse response, FilterChain chain) throws Exception {\n            filter.doFilter((ServletRequest) request, (ServletResponse) response, (q, p) -> {\n                try {\n                    chain.doFilter(request, response);\n                } catch (RuntimeException | IOException | ServletException e) {\n                    throw e;\n                } catch (Exception e) {\n                    throw new ServletException(e);\n                }\n            });\n        }\n\n        @Override\n        public String toString() {\n            StringBuilder sb = new StringBuilder(\"RestFilter{filter=\");\n            sb.append(filter);\n            int priority = getPriority();\n            if (priority != 0) {\n                sb.append(\", priority=\").append(priority);\n            }\n            String[] patterns = getPatterns();\n            if (patterns != null) {\n                sb.append(\", patterns=\").append(Arrays.toString(patterns));\n            }\n            return sb.append('}').toString();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/Helper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.http12.HttpCookie;\nimport org.apache.dubbo.remoting.http12.HttpRequest.FileUpload;\n\nimport javax.servlet.http.Part;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nfinal class Helper {\n\n    private Helper() {}\n\n    static javax.servlet.http.Cookie[] convertCookies(Collection<HttpCookie> hCookies) {\n        javax.servlet.http.Cookie[] cookies = new javax.servlet.http.Cookie[hCookies.size()];\n        int i = 0;\n        for (HttpCookie cookie : hCookies) {\n            cookies[i++] = convert(cookie);\n        }\n        return cookies;\n    }\n\n    static javax.servlet.http.Cookie convert(HttpCookie hCookie) {\n        javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie(hCookie.name(), hCookie.value());\n        if (hCookie.domain() != null) {\n            cookie.setDomain(hCookie.domain());\n        }\n        cookie.setMaxAge((int) hCookie.maxAge());\n        cookie.setHttpOnly(hCookie.httpOnly());\n        cookie.setPath(hCookie.path());\n        cookie.setSecure(hCookie.secure());\n        return cookie;\n    }\n\n    static HttpCookie convert(javax.servlet.http.Cookie sCookie) {\n        HttpCookie cookie = new HttpCookie(sCookie.getName(), sCookie.getValue());\n        cookie.setDomain(sCookie.getDomain());\n        cookie.setMaxAge(sCookie.getMaxAge());\n        cookie.setHttpOnly(sCookie.isHttpOnly());\n        cookie.setPath(sCookie.getPath());\n        cookie.setSecure(sCookie.getSecure());\n        return cookie;\n    }\n\n    public static FileUploadPart convert(FileUpload part) {\n        return new FileUploadPart(part);\n    }\n\n    public static Collection<Part> convertParts(Collection<FileUpload> parts) {\n        if (CollectionUtils.isEmpty(parts)) {\n            return Collections.emptyList();\n        }\n        List<Part> result = new ArrayList<>(parts.size());\n        for (FileUpload part : parts) {\n            result.add(convert(part));\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/HttpSessionFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;\n\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpSession;\n\npublic interface HttpSessionFactory extends RestExtension {\n\n    HttpSession getSession(HttpServletRequest request, boolean create);\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletArgumentResolver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.RestException;\nimport org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.Writer;\nimport java.util.HashSet;\nimport java.util.Set;\n\n@Activate(onClass = \"javax.servlet.http.HttpServletRequest\")\npublic class ServletArgumentResolver implements ArgumentResolver {\n\n    private static final Set<Class<?>> SUPPORTED_TYPES = new HashSet<>();\n\n    static {\n        SUPPORTED_TYPES.add(ServletRequest.class);\n        SUPPORTED_TYPES.add(HttpServletRequest.class);\n        SUPPORTED_TYPES.add(ServletResponse.class);\n        SUPPORTED_TYPES.add(HttpServletResponse.class);\n        SUPPORTED_TYPES.add(HttpSession.class);\n        SUPPORTED_TYPES.add(Cookie.class);\n        SUPPORTED_TYPES.add(Cookie[].class);\n        SUPPORTED_TYPES.add(Reader.class);\n        SUPPORTED_TYPES.add(Writer.class);\n    }\n\n    @Override\n    public boolean accept(ParameterMeta parameter) {\n        return SUPPORTED_TYPES.contains(parameter.getActualType());\n    }\n\n    @Override\n    public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse response) {\n        Class<?> type = parameter.getActualType();\n        if (type == ServletRequest.class || type == HttpServletRequest.class) {\n            return request;\n        }\n        if (type == ServletResponse.class || type == HttpServletResponse.class) {\n            return response;\n        }\n        if (type == HttpSession.class) {\n            return ((HttpServletRequest) request).getSession();\n        }\n        if (type == Cookie.class) {\n            return Helper.convert(request.cookie(parameter.getRequiredName()));\n        }\n        if (type == Cookie[].class) {\n            return ((HttpServletRequest) request).getCookies();\n        }\n        if (type == Reader.class) {\n            try {\n                return ((HttpServletRequest) request).getReader();\n            } catch (IOException e) {\n                throw new RestException(e);\n            }\n        }\n        if (type == Writer.class) {\n            try {\n                return ((HttpServletResponse) response).getWriter();\n            } catch (IOException e) {\n                throw new RestException(e);\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpMessageAdapterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.http12.HttpChannel;\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\nimport org.apache.dubbo.remoting.http12.HttpResponse;\nimport org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension;\n\nimport javax.servlet.ServletContext;\n\n@Activate(order = -100, onClass = \"javax.servlet.http.HttpServletRequest\")\npublic final class ServletHttpMessageAdapterFactory\n        implements HttpMessageAdapterFactory<ServletHttpRequestAdapter, HttpMetadata, Void> {\n\n    private final FrameworkModel frameworkModel;\n    private final ServletContext servletContext;\n    private final HttpSessionFactory httpSessionFactory;\n\n    public ServletHttpMessageAdapterFactory(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n        servletContext = (ServletContext) createDummyServletContext(frameworkModel);\n        httpSessionFactory = getHttpSessionFactory(frameworkModel);\n    }\n\n    private HttpSessionFactory getHttpSessionFactory(FrameworkModel frameworkModel) {\n        for (RestExtension extension : frameworkModel.getActivateExtensions(RestExtension.class)) {\n            if (extension instanceof HttpSessionFactory) {\n                return (HttpSessionFactory) extension;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public ServletHttpRequestAdapter adaptRequest(HttpMetadata rawRequest, HttpChannel channel) {\n        return new ServletHttpRequestAdapter(rawRequest, channel, servletContext, httpSessionFactory);\n    }\n\n    @Override\n    public HttpResponse adaptResponse(ServletHttpRequestAdapter request, HttpMetadata rawRequest, Void rawResponse) {\n        return new ServletHttpResponseAdapter();\n    }\n\n    public Object adaptFilterConfig(String filterName) {\n        return new DummyFilterConfig(filterName, frameworkModel, servletContext);\n    }\n\n    private Object createDummyServletContext(FrameworkModel frameworkModel) {\n        return new DummyServletContext(frameworkModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpRequestAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.http12.HttpChannel;\nimport org.apache.dubbo.remoting.http12.HttpConstants;\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\nimport org.apache.dubbo.remoting.http12.HttpVersion;\nimport org.apache.dubbo.remoting.http12.message.DefaultHttpRequest;\n\nimport javax.servlet.AsyncContext;\nimport javax.servlet.DispatcherType;\nimport javax.servlet.ReadListener;\nimport javax.servlet.RequestDispatcher;\nimport javax.servlet.ServletContext;\nimport javax.servlet.ServletInputStream;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport javax.servlet.http.HttpUpgradeHandler;\nimport javax.servlet.http.Part;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.security.Principal;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class ServletHttpRequestAdapter extends DefaultHttpRequest implements HttpServletRequest {\n\n    private final ServletContext servletContext;\n    private final HttpSessionFactory sessionFactory;\n\n    private ServletInputStream sis;\n    private BufferedReader reader;\n\n    public ServletHttpRequestAdapter(\n            HttpMetadata metadata,\n            HttpChannel channel,\n            ServletContext servletContext,\n            HttpSessionFactory sessionFactory) {\n        super(metadata, channel);\n        this.servletContext = servletContext;\n        this.sessionFactory = sessionFactory;\n    }\n\n    @Override\n    public String getAuthType() {\n        return header(\"www-authenticate\");\n    }\n\n    @Override\n    public Cookie[] getCookies() {\n        return Helper.convertCookies(cookies());\n    }\n\n    @Override\n    public long getDateHeader(String name) {\n        Date date = dateHeader(name);\n        return date == null ? -1L : date.getTime();\n    }\n\n    @Override\n    public String getHeader(String name) {\n        return header(name);\n    }\n\n    @Override\n    public Enumeration<String> getHeaders(String name) {\n        return Collections.enumeration(headerValues(name));\n    }\n\n    @Override\n    public Enumeration<String> getHeaderNames() {\n        return Collections.enumeration(headerNames());\n    }\n\n    @Override\n    public int getIntHeader(String name) {\n        String headerValue = getHeader(name);\n        try {\n            return Integer.parseInt(headerValue);\n        } catch (NumberFormatException e) {\n            return -1;\n        }\n    }\n\n    @Override\n    public String getMethod() {\n        return method();\n    }\n\n    @Override\n    public String getPathInfo() {\n        return null;\n    }\n\n    @Override\n    public String getPathTranslated() {\n        return null;\n    }\n\n    @Override\n    public String getContextPath() {\n        return \"/\";\n    }\n\n    @Override\n    public String getQueryString() {\n        return query();\n    }\n\n    @Override\n    public String getRemoteUser() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean isUserInRole(String role) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Principal getUserPrincipal() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getRequestedSessionId() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getRequestURI() {\n        return path();\n    }\n\n    @Override\n    public StringBuffer getRequestURL() {\n        StringBuffer url = new StringBuffer(32);\n        String scheme = getScheme();\n        int port = getServerPort();\n        url.append(scheme).append(\"://\").append(getServerName());\n        if (HttpConstants.HTTP.equals(scheme) && port != 80 || HttpConstants.HTTPS.equals(scheme) && port != 443) {\n            url.append(':');\n            url.append(port);\n        }\n        url.append(path());\n        return url;\n    }\n\n    @Override\n    public String getServletPath() {\n        return path();\n    }\n\n    @Override\n    public HttpSession getSession(boolean create) {\n        if (sessionFactory == null) {\n            throw new UnsupportedOperationException(\"No HttpSessionFactory found\");\n        }\n        return sessionFactory.getSession(this, create);\n    }\n\n    @Override\n    public HttpSession getSession() {\n        return getSession(true);\n    }\n\n    @Override\n    public String changeSessionId() {\n        return null;\n    }\n\n    @Override\n    public boolean isRequestedSessionIdValid() {\n        return true;\n    }\n\n    @Override\n    public boolean isRequestedSessionIdFromCookie() {\n        return true;\n    }\n\n    @Override\n    public boolean isRequestedSessionIdFromURL() {\n        return false;\n    }\n\n    public boolean isRequestedSessionIdFromUrl() {\n        return false;\n    }\n\n    @Override\n    public boolean authenticate(HttpServletResponse response) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void login(String username, String password) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void logout() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Collection<Part> getParts() {\n        return Helper.convertParts(parts());\n    }\n\n    @Override\n    public FileUploadPart getPart(String name) {\n        return Helper.convert(part(name));\n    }\n\n    @Override\n    public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Object getAttribute(String name) {\n        return attribute(name);\n    }\n\n    @Override\n    public Enumeration<String> getAttributeNames() {\n        return Collections.enumeration(attributeNames());\n    }\n\n    @Override\n    public String getCharacterEncoding() {\n        return charset();\n    }\n\n    @Override\n    public void setCharacterEncoding(String env) {\n        setCharset(env);\n    }\n\n    @Override\n    public int getContentLength() {\n        return contentLength();\n    }\n\n    @Override\n    public long getContentLengthLong() {\n        return contentLength();\n    }\n\n    @Override\n    public String getContentType() {\n        return contentType();\n    }\n\n    @Override\n    public ServletInputStream getInputStream() {\n        if (sis == null) {\n            sis = new HttpInputStream(inputStream());\n        }\n        return sis;\n    }\n\n    @Override\n    public String getParameter(String name) {\n        return parameter(name);\n    }\n\n    @Override\n    public Enumeration<String> getParameterNames() {\n        return Collections.enumeration(parameterNames());\n    }\n\n    @Override\n    public String[] getParameterValues(String name) {\n        List<String> values = parameterValues(name);\n        return values == null ? null : values.toArray(new String[0]);\n    }\n\n    @Override\n    public Map<String, String[]> getParameterMap() {\n        Collection<String> paramNames = parameterNames();\n        if (paramNames.isEmpty()) {\n            return Collections.emptyMap();\n        }\n        Map<String, String[]> result = CollectionUtils.newLinkedHashMap(paramNames.size());\n        for (String paramName : paramNames) {\n            result.put(paramName, getParameterValues(paramName));\n        }\n        return result;\n    }\n\n    @Override\n    public String getProtocol() {\n        return isHttp2() ? HttpVersion.HTTP2.getProtocol() : HttpVersion.HTTP1.getProtocol();\n    }\n\n    @Override\n    public String getScheme() {\n        return scheme();\n    }\n\n    @Override\n    public String getServerName() {\n        return serverName();\n    }\n\n    @Override\n    public int getServerPort() {\n        return serverPort();\n    }\n\n    @Override\n    public BufferedReader getReader() {\n        if (reader == null) {\n            reader = new BufferedReader(new InputStreamReader(inputStream(), charsetOrDefault()));\n        }\n        return reader;\n    }\n\n    @Override\n    public String getRemoteAddr() {\n        return remoteAddr();\n    }\n\n    @Override\n    public String getRemoteHost() {\n        return String.valueOf(remotePort());\n    }\n\n    @Override\n    public Locale getLocale() {\n        return locale();\n    }\n\n    @Override\n    public Enumeration<Locale> getLocales() {\n        return Collections.enumeration(locales());\n    }\n\n    @Override\n    public boolean isSecure() {\n        return HttpConstants.HTTPS.equals(scheme());\n    }\n\n    @Override\n    public RequestDispatcher getRequestDispatcher(String path) {\n        throw new UnsupportedOperationException();\n    }\n\n    public String getRealPath(String path) {\n        return null;\n    }\n\n    @Override\n    public int getRemotePort() {\n        return remotePort();\n    }\n\n    @Override\n    public String getLocalName() {\n        return localHost();\n    }\n\n    @Override\n    public String getLocalAddr() {\n        return localAddr();\n    }\n\n    @Override\n    public int getLocalPort() {\n        return localPort();\n    }\n\n    @Override\n    public ServletContext getServletContext() {\n        return servletContext;\n    }\n\n    @Override\n    public AsyncContext startAsync() throws IllegalStateException {\n        throw new IllegalStateException();\n    }\n\n    @Override\n    public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)\n            throws IllegalStateException {\n        throw new IllegalStateException();\n    }\n\n    @Override\n    public boolean isAsyncStarted() {\n        return false;\n    }\n\n    @Override\n    public boolean isAsyncSupported() {\n        return false;\n    }\n\n    @Override\n    public AsyncContext getAsyncContext() {\n        throw new IllegalStateException();\n    }\n\n    @Override\n    public DispatcherType getDispatcherType() {\n        return DispatcherType.REQUEST;\n    }\n\n    /* jakarta placeholder */\n\n    @Override\n    public String toString() {\n        return \"ServletHttpRequestAdapter{\" + fieldToString() + '}';\n    }\n\n    private static final class HttpInputStream extends ServletInputStream {\n\n        private final InputStream is;\n\n        HttpInputStream(InputStream is) {\n            this.is = is;\n        }\n\n        @Override\n        public int read() throws IOException {\n            return is.read();\n        }\n\n        @Override\n        public int read(byte[] b) throws IOException {\n            return is.read(b);\n        }\n\n        @Override\n        public void close() throws IOException {\n            is.close();\n        }\n\n        @Override\n        public int readLine(byte[] b, int off, int len) throws IOException {\n            return is.read(b, off, len);\n        }\n\n        @Override\n        public boolean isFinished() {\n            try {\n                return is.available() == 0;\n            } catch (IOException e) {\n                return false;\n            }\n        }\n\n        @Override\n        public boolean isReady() {\n            return true;\n        }\n\n        @Override\n        public void setReadListener(ReadListener readListener) {\n            throw new UnsupportedOperationException();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpResponseAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.http12.HttpUtils;\nimport org.apache.dubbo.remoting.http12.message.DefaultHttpResponse;\nimport org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;\n\nimport javax.servlet.ServletOutputStream;\nimport javax.servlet.WriteListener;\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.BufferedOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.PrintWriter;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.Locale;\n\npublic class ServletHttpResponseAdapter extends DefaultHttpResponse implements HttpServletResponse {\n\n    private ServletOutputStream sos;\n    private PrintWriter writer;\n\n    @Override\n    public void addCookie(Cookie cookie) {\n        addCookie(Helper.convert(cookie));\n    }\n\n    @Override\n    public boolean containsHeader(String name) {\n        return hasHeader(name);\n    }\n\n    @Override\n    public String encodeURL(String url) {\n        return RequestUtils.encodeURL(url);\n    }\n\n    @Override\n    public String encodeRedirectURL(String url) {\n        return RequestUtils.encodeURL(url);\n    }\n\n    public String encodeUrl(String url) {\n        return RequestUtils.encodeURL(url);\n    }\n\n    public String encodeRedirectUrl(String url) {\n        return RequestUtils.encodeURL(url);\n    }\n\n    public void sendRedirect(String location, int sc, boolean clearBuffer) {\n        sendRedirect(location);\n    }\n\n    @Override\n    public void setDateHeader(String name, long date) {\n        setHeader(name, new Date(date));\n    }\n\n    @Override\n    public void addDateHeader(String name, long date) {\n        addHeader(name, new Date(date));\n    }\n\n    @Override\n    public void setHeader(String name, String value) {\n        super.setHeader(name, value);\n    }\n\n    @Override\n    public void addHeader(String name, String value) {\n        super.addHeader(name, value);\n    }\n\n    @Override\n    public void setIntHeader(String name, int value) {\n        setHeader(name, String.valueOf(value));\n    }\n\n    @Override\n    public void addIntHeader(String name, int value) {\n        addHeader(name, String.valueOf(value));\n    }\n\n    public void setStatus(int sc, String sm) {\n        setStatus(sc);\n        setBody(sm);\n    }\n\n    @Override\n    public int getStatus() {\n        return status();\n    }\n\n    @Override\n    public String getHeader(String name) {\n        return header(name);\n    }\n\n    @Override\n    public Collection<String> getHeaders(String name) {\n        return headerValues(name);\n    }\n\n    @Override\n    public Collection<String> getHeaderNames() {\n        return headerNames();\n    }\n\n    @Override\n    public String getCharacterEncoding() {\n        return charset();\n    }\n\n    @Override\n    public String getContentType() {\n        return contentType();\n    }\n\n    @Override\n    public ServletOutputStream getOutputStream() {\n        if (sos == null) {\n            sos = new HttpOutputStream(outputStream());\n        }\n        return sos;\n    }\n\n    @Override\n    public PrintWriter getWriter() {\n        if (writer == null) {\n            String ce = getCharacterEncoding();\n            Charset charset = ce == null ? StandardCharsets.UTF_8 : Charset.forName(ce);\n            writer = new PrintWriter(new OutputStreamWriter(outputStream(), charset), true);\n        }\n        return writer;\n    }\n\n    @Override\n    public void setCharacterEncoding(String charset) {\n        setCharset(charset);\n    }\n\n    @Override\n    public void setContentLength(int len) {}\n\n    @Override\n    public void setContentLengthLong(long len) {}\n\n    @Override\n    public void setBufferSize(int size) {}\n\n    @Override\n    public int getBufferSize() {\n        return 0;\n    }\n\n    @Override\n    public void flushBuffer() throws IOException {\n        //noinspection resource\n        OutputStream os = outputStream();\n        if (os instanceof BufferedOutputStream) {\n            os.flush();\n        }\n    }\n\n    @Override\n    public void setLocale(Locale loc) {\n        setLocale(loc.toLanguageTag());\n    }\n\n    @Override\n    public Locale getLocale() {\n        Locale locale = CollectionUtils.first(HttpUtils.parseContentLanguage(locale()));\n        return locale == null ? Locale.getDefault() : locale;\n    }\n\n    @Override\n    public String toString() {\n        return \"ServletHttpResponseAdapter{\" + fieldToString() + '}';\n    }\n\n    private static final class HttpOutputStream extends ServletOutputStream {\n\n        private final OutputStream outputStream;\n\n        private HttpOutputStream(OutputStream outputStream) {\n            this.outputStream = outputStream;\n        }\n\n        @Override\n        public void write(int b) throws IOException {\n            outputStream.write(b);\n        }\n\n        @Override\n        public void write(byte[] b) throws IOException {\n            outputStream.write(b);\n        }\n\n        @Override\n        public void write(byte[] b, int off, int len) throws IOException {\n            outputStream.write(b, off, len);\n        }\n\n        @Override\n        public boolean isReady() {\n            return true;\n        }\n\n        @Override\n        public void setWriteListener(WriteListener writeListener) {\n            throw new UnsupportedOperationException();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.servlet;\n\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.h2.Http2Header;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport java.util.Enumeration;\n\nimport io.netty.handler.codec.http2.Http2Headers.PseudoHeaderName;\n\npublic final class HttpMetadataAdapter implements Http2Header {\n\n    private final HttpServletRequest request;\n\n    private HttpHeaders headers;\n\n    HttpMetadataAdapter(HttpServletRequest request) {\n        this.request = request;\n    }\n\n    public HttpServletRequest getRequest() {\n        return request;\n    }\n\n    @Override\n    public HttpHeaders headers() {\n        HttpHeaders headers = this.headers;\n        if (headers == null) {\n            headers = HttpHeaders.create();\n            Enumeration<String> en = request.getHeaderNames();\n            while (en.hasMoreElements()) {\n                String key = en.nextElement();\n                Enumeration<String> ven = request.getHeaders(key);\n                while (ven.hasMoreElements()) {\n                    headers.add(key, ven.nextElement());\n                }\n            }\n            headers.add(PseudoHeaderName.METHOD.value(), method());\n            headers.add(PseudoHeaderName.SCHEME.value(), request.getScheme());\n            headers.add(PseudoHeaderName.AUTHORITY.value(), request.getServerName());\n            headers.add(PseudoHeaderName.PROTOCOL.value(), request.getProtocol());\n            this.headers = headers;\n        }\n        return headers;\n    }\n\n    @Override\n    public String method() {\n        return request.getMethod();\n    }\n\n    @Override\n    public String path() {\n        String query = request.getQueryString();\n        return query == null ? request.getRequestURI() : request.getRequestURI() + '?' + query;\n    }\n\n    @Override\n    public long id() {\n        return -1L;\n    }\n\n    @Override\n    public boolean isEndStream() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/ServletStreamChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.servlet;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.remoting.http12.HttpConstants;\nimport org.apache.dubbo.remoting.http12.HttpHeaderNames;\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\nimport org.apache.dubbo.remoting.http12.HttpOutputMessage;\nimport org.apache.dubbo.remoting.http12.exception.HttpStatusException;\nimport org.apache.dubbo.remoting.http12.h2.H2StreamChannel;\nimport org.apache.dubbo.remoting.http12.h2.Http2Header;\nimport org.apache.dubbo.remoting.http12.h2.Http2OutputMessage;\nimport org.apache.dubbo.remoting.http12.h2.Http2OutputMessageFrame;\nimport org.apache.dubbo.rpc.TriRpcStatus;\nimport org.apache.dubbo.rpc.TriRpcStatus.Code;\nimport org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;\n\nimport javax.servlet.AsyncContext;\nimport javax.servlet.ServletOutputStream;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.ByteArrayOutputStream;\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Queue;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nfinal class ServletStreamChannel implements H2StreamChannel {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(ServletStreamChannel.class);\n\n    private final Queue<Object> writeQueue = new ConcurrentLinkedQueue<>();\n    private final AtomicBoolean writeable = new AtomicBoolean();\n    private final HttpServletRequest request;\n    private final HttpServletResponse response;\n    private final AsyncContext context;\n\n    private boolean isGrpc;\n\n    ServletStreamChannel(HttpServletRequest request, HttpServletResponse response, AsyncContext context) {\n        this.request = request;\n        this.response = response;\n        this.context = context;\n    }\n\n    public void setGrpc(boolean isGrpc) {\n        this.isGrpc = isGrpc;\n    }\n\n    public void writeError(int code, Throwable throwable) {\n        if (response.isCommitted() && code == Code.DEADLINE_EXCEEDED.code) {\n            return;\n        }\n        try {\n            if (isGrpc) {\n                response.setTrailerFields(() -> {\n                    Map<String, String> map = new HashMap<>();\n                    map.put(TripleHeaderEnum.STATUS_KEY.getName(), String.valueOf(code));\n                    return map;\n                });\n                return;\n            }\n            try {\n                if (throwable instanceof HttpStatusException) {\n                    response.setStatus(((HttpStatusException) throwable).getStatusCode());\n                    response.getOutputStream().close();\n                } else {\n                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\n                }\n            } catch (Throwable t) {\n                LOGGER.info(\"Failed to send response\", t);\n            }\n        } finally {\n            context.complete();\n        }\n    }\n\n    public void onWritePossible() {\n        if (writeable.compareAndSet(false, true)) {\n            flushQueue();\n        }\n    }\n\n    private void flushQueue() {\n        if (writeQueue.isEmpty()) {\n            return;\n        }\n        synchronized (writeQueue) {\n            Object obj;\n            while ((obj = writeQueue.poll()) != null) {\n                if (obj instanceof HttpMetadata) {\n                    writeHeaderInternal((HttpMetadata) obj);\n                } else if (obj instanceof HttpOutputMessage) {\n                    writeMessageInternal((HttpOutputMessage) obj);\n                }\n            }\n        }\n    }\n\n    @Override\n    public CompletableFuture<Void> writeResetFrame(long errorCode) {\n        if (isGrpc) {\n            writeError(TriRpcStatus.httpStatusToGrpcCode((int) errorCode).code, null);\n            return completed();\n        }\n\n        try {\n            if (errorCode == 0L) {\n                response.getOutputStream().close();\n                return completed();\n            }\n            if (response.isCommitted()) {\n                return completed();\n            }\n            if (errorCode >= 300 && errorCode < 600) {\n                response.sendError((int) errorCode);\n            } else {\n                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\n            }\n        } catch (Throwable t) {\n            LOGGER.info(\"Failed to close response\", t);\n        } finally {\n            context.complete();\n        }\n\n        return completed();\n    }\n\n    @Override\n    public Http2OutputMessage newOutputMessage(boolean endStream) {\n        return new Http2OutputMessageFrame(new ByteArrayOutputStream(256), endStream);\n    }\n\n    @Override\n    public void consumeBytes(int numBytes) throws Exception {\n        // No flow control for servlet\n    }\n\n    @Override\n    public CompletableFuture<Void> writeHeader(HttpMetadata httpMetadata) {\n        if (writeable.get()) {\n            flushQueue();\n            writeHeaderInternal(httpMetadata);\n        } else {\n            writeQueue.add(httpMetadata);\n        }\n        return completed();\n    }\n\n    private void writeHeaderInternal(HttpMetadata httpMetadata) {\n        boolean endStream = false;\n        boolean isHttp1 = true;\n        if (httpMetadata instanceof Http2Header) {\n            endStream = ((Http2Header) httpMetadata).isEndStream();\n            isHttp1 = false;\n        }\n        try {\n            HttpHeaders headers = httpMetadata.headers();\n            if (endStream) {\n                response.setTrailerFields(() -> {\n                    Map<String, String> map = new HashMap<>();\n                    for (Entry<CharSequence, String> entry : headers) {\n                        map.put(entry.getKey().toString(), entry.getValue());\n                    }\n                    return map;\n                });\n                return;\n            }\n\n            if (response.isCommitted()) {\n                return;\n            }\n\n            for (Entry<CharSequence, String> entry : headers) {\n                String key = entry.getKey().toString();\n                String value = entry.getValue();\n                if (HttpHeaderNames.STATUS.getName().equals(key)) {\n                    response.setStatus(Integer.parseInt(value));\n                    continue;\n                }\n                if (isHttp1\n                        && HttpHeaderNames.TRANSFER_ENCODING.getName().equals(key)\n                        && HttpConstants.CHUNKED.equals(value)) {\n                    continue;\n                }\n                response.addHeader(key, value);\n            }\n        } catch (Throwable t) {\n            LOGGER.info(\"Failed to write header\", t);\n        } finally {\n            if (endStream) {\n                context.complete();\n            }\n        }\n    }\n\n    @Override\n    public CompletableFuture<Void> writeMessage(HttpOutputMessage httpOutputMessage) {\n        if (writeable.get()) {\n            flushQueue();\n            writeMessageInternal(httpOutputMessage);\n        } else {\n            writeQueue.add(httpOutputMessage);\n        }\n        return completed();\n    }\n\n    private void writeMessageInternal(HttpOutputMessage httpOutputMessage) {\n        boolean endStream = false;\n        if (httpOutputMessage instanceof Http2OutputMessage) {\n            endStream = ((Http2OutputMessage) httpOutputMessage).isEndStream();\n        } else if (httpOutputMessage == HttpOutputMessage.EMPTY_MESSAGE) {\n            endStream = true;\n        }\n        try {\n            ByteArrayOutputStream bos = (ByteArrayOutputStream) httpOutputMessage.getBody();\n            ServletOutputStream out = response.getOutputStream();\n            bos.writeTo(out);\n            out.flush();\n        } catch (Throwable t) {\n            LOGGER.info(\"Failed to write message\", t);\n        } finally {\n            if (endStream) {\n                context.complete();\n            }\n        }\n    }\n\n    @Override\n    public SocketAddress remoteAddress() {\n        return InetSocketAddress.createUnresolved(request.getRemoteAddr(), request.getRemotePort());\n    }\n\n    @Override\n    public SocketAddress localAddress() {\n        return InetSocketAddress.createUnresolved(request.getLocalAddr(), request.getLocalPort());\n    }\n\n    @Override\n    public void flush() {}\n\n    @Override\n    public boolean isReady() {\n        return writeable.get();\n    }\n\n    private static CompletableFuture<Void> completed() {\n        return CompletableFuture.completedFuture(null);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.servlet;\n\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.remoting.http12.HttpVersion;\nimport org.apache.dubbo.remoting.http12.h1.Http1InputMessage;\nimport org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListener;\nimport org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame;\nimport org.apache.dubbo.remoting.http12.h2.Http2ServerTransportListenerFactory;\nimport org.apache.dubbo.remoting.http12.h2.Http2TransportListener;\nimport org.apache.dubbo.rpc.PathResolver;\nimport org.apache.dubbo.rpc.TriRpcStatus.Code;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.RequestPath;\nimport org.apache.dubbo.rpc.protocol.tri.ServletExchanger;\nimport org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;\nimport org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcHeaderNames;\nimport org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcHttp2ServerTransportListener;\nimport org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcUtils;\nimport org.apache.dubbo.rpc.protocol.tri.h12.http1.DefaultHttp11ServerTransportListenerFactory;\nimport org.apache.dubbo.rpc.protocol.tri.h12.http2.GenericHttp2ServerTransportListenerFactory;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.DefaultRequestMappingRegistry;\nimport org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingRegistry;\n\nimport javax.servlet.AsyncContext;\nimport javax.servlet.AsyncEvent;\nimport javax.servlet.AsyncListener;\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ReadListener;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletInputStream;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.WriteListener;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Set;\n\nimport static org.apache.dubbo.rpc.protocol.tri.TripleConstants.UPGRADE_HEADER_KEY;\n\npublic class TripleFilter implements Filter {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(TripleFilter.class);\n\n    private PathResolver pathResolver;\n    private RequestMappingRegistry mappingRegistry;\n\n    @Override\n    public void init(FilterConfig config) {\n        FrameworkModel frameworkModel = FrameworkModel.defaultModel();\n        pathResolver = frameworkModel.getDefaultExtension(PathResolver.class);\n        mappingRegistry = frameworkModel.getOrRegisterBean(DefaultRequestMappingRegistry.class);\n    }\n\n    @Override\n    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)\n            throws ServletException, IOException {\n        HttpServletRequest request = (HttpServletRequest) servletRequest;\n        HttpServletResponse response = (HttpServletResponse) servletResponse;\n\n        boolean isHttp2 = HttpVersion.HTTP2.getProtocol().equals(request.getProtocol());\n        if (isHttp2) {\n            if (hasGrpcMapping(request) || mappingRegistry.exists(request.getRequestURI(), request.getMethod())) {\n                handleHttp2(request, response);\n                return;\n            }\n        } else {\n            if (notUpgradeRequest(request) && mappingRegistry.exists(request.getRequestURI(), request.getMethod())) {\n                handleHttp1(request, response);\n                return;\n            }\n        }\n\n        chain.doFilter(request, response);\n    }\n\n    private void handleHttp2(HttpServletRequest request, HttpServletResponse response) {\n        AsyncContext context = request.startAsync(request, response);\n        ServletStreamChannel channel = new ServletStreamChannel(request, response, context);\n        try {\n            Http2TransportListener listener = determineHttp2ServerTransportListenerFactory(request.getContentType())\n                    .newInstance(channel, ServletExchanger.getUrl(), FrameworkModel.defaultModel());\n\n            boolean isGrpc = listener instanceof GrpcHttp2ServerTransportListener;\n            channel.setGrpc(isGrpc);\n            context.setTimeout(resolveTimeout(request, isGrpc));\n            context.addListener(new TripleAsyncListener(channel));\n            ServletInputStream is = request.getInputStream();\n            is.setReadListener(new TripleReadListener(listener, channel, is));\n            response.getOutputStream().setWriteListener(new TripleWriteListener(channel));\n\n            listener.onMetadata(new HttpMetadataAdapter(request));\n        } catch (Throwable t) {\n            LOGGER.info(\"Failed to process request\", t);\n            channel.writeError(Code.UNKNOWN.code, t);\n        }\n    }\n\n    private void handleHttp1(HttpServletRequest request, HttpServletResponse response) {\n        AsyncContext context = request.startAsync(request, response);\n        ServletStreamChannel channel = new ServletStreamChannel(request, response, context);\n        try {\n            Http1ServerTransportListener listener = DefaultHttp11ServerTransportListenerFactory.INSTANCE.newInstance(\n                    channel, ServletExchanger.getUrl(), FrameworkModel.defaultModel());\n            channel.setGrpc(false);\n            context.setTimeout(resolveTimeout(request, false));\n            ServletInputStream is = request.getInputStream();\n            response.getOutputStream().setWriteListener(new TripleWriteListener(channel));\n\n            listener.onMetadata(new HttpMetadataAdapter(request));\n            listener.onData(new Http1InputMessage(\n                    is.available() == 0 ? StreamUtils.EMPTY : new ByteArrayInputStream(StreamUtils.readBytes(is))));\n        } catch (Throwable t) {\n            LOGGER.info(\"Failed to process request\", t);\n            channel.writeError(Code.UNKNOWN.code, t);\n        }\n    }\n\n    @Override\n    public void destroy() {}\n\n    private boolean hasGrpcMapping(HttpServletRequest request) {\n        if (!GrpcUtils.isGrpcRequest(request.getContentType())) {\n            return false;\n        }\n\n        RequestPath path = RequestPath.parse(request.getRequestURI());\n        if (path == null) {\n            return false;\n        }\n\n        String group = request.getHeader(TripleHeaderEnum.SERVICE_GROUP.getName());\n        String version = request.getHeader(TripleHeaderEnum.SERVICE_VERSION.getName());\n        return pathResolver.resolve(path.getPath(), group, version) != null;\n    }\n\n    private boolean notUpgradeRequest(HttpServletRequest request) {\n        return request.getHeader(UPGRADE_HEADER_KEY) == null;\n    }\n\n    private Http2ServerTransportListenerFactory determineHttp2ServerTransportListenerFactory(String contentType) {\n        Set<Http2ServerTransportListenerFactory> http2ServerTransportListenerFactories = FrameworkModel.defaultModel()\n                .getExtensionLoader(Http2ServerTransportListenerFactory.class)\n                .getSupportedExtensionInstances();\n        for (Http2ServerTransportListenerFactory factory : http2ServerTransportListenerFactories) {\n            if (factory.supportContentType(contentType)) {\n                return factory;\n            }\n        }\n        return GenericHttp2ServerTransportListenerFactory.INSTANCE;\n    }\n\n    private static int resolveTimeout(HttpServletRequest request, boolean isGrpc) {\n        try {\n            if (isGrpc) {\n                String timeoutString = request.getHeader(GrpcHeaderNames.GRPC_TIMEOUT.getName());\n                if (timeoutString != null) {\n                    Long timeout = GrpcUtils.parseTimeoutToMills(timeoutString);\n                    if (timeout != null) {\n                        return timeout.intValue() + 2000;\n                    }\n                }\n            } else {\n                String timeoutString = request.getHeader(TripleHeaderEnum.SERVICE_TIMEOUT.getName());\n                if (timeoutString != null) {\n                    return Integer.parseInt(timeoutString) + 2000;\n                }\n            }\n        } catch (Throwable ignored) {\n        }\n        return 0;\n    }\n\n    private static final class TripleAsyncListener implements AsyncListener {\n\n        private final ServletStreamChannel streamChannel;\n\n        TripleAsyncListener(ServletStreamChannel streamChannel) {\n            this.streamChannel = streamChannel;\n        }\n\n        @Override\n        public void onComplete(AsyncEvent event) {}\n\n        @Override\n        public void onTimeout(AsyncEvent event) {\n            streamChannel.writeError(Code.DEADLINE_EXCEEDED.code, event.getThrowable());\n        }\n\n        @Override\n        public void onError(AsyncEvent event) {\n            streamChannel.writeError(Code.CANCELLED.code, event.getThrowable());\n        }\n\n        @Override\n        public void onStartAsync(AsyncEvent event) {}\n    }\n\n    private static final class TripleReadListener implements ReadListener {\n\n        private final Http2TransportListener listener;\n        private final ServletStreamChannel channel;\n        private final ServletInputStream input;\n        private final byte[] buffer = new byte[4 * 1024];\n\n        TripleReadListener(Http2TransportListener listener, ServletStreamChannel channel, ServletInputStream input) {\n            this.listener = listener;\n            this.channel = channel;\n            this.input = input;\n        }\n\n        @Override\n        public void onDataAvailable() throws IOException {\n            while (input.isReady()) {\n                int length = input.read(buffer);\n                if (length == -1) {\n                    return;\n                }\n                byte[] copy = Arrays.copyOf(buffer, length);\n                listener.onData(new Http2InputMessageFrame(new ByteArrayInputStream(copy), false));\n            }\n        }\n\n        @Override\n        public void onAllDataRead() {\n            listener.onData(new Http2InputMessageFrame(StreamUtils.EMPTY, true));\n        }\n\n        @Override\n        public void onError(Throwable t) {\n            channel.writeError(Code.CANCELLED.code, t);\n        }\n    }\n\n    private static final class TripleWriteListener implements WriteListener {\n\n        private final ServletStreamChannel channel;\n\n        TripleWriteListener(ServletStreamChannel channel) {\n            this.channel = channel;\n        }\n\n        @Override\n        public void onWritePossible() {\n            channel.onWritePossible();\n        }\n\n        @Override\n        public void onError(Throwable t) {\n            channel.writeError(Code.CANCELLED.code, t);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory",
    "content": "servlet=org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.ServletHttpMessageAdapterFactory\njakarta-servlet=org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.jakarta.ServletHttpMessageAdapterFactory\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver",
    "content": "servlet=org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.ServletArgumentResolver\njakarta-servlet=org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.jakarta.ServletArgumentResolver\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-servlet/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter",
    "content": "servlet-filter=org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.FilterAdapter\njakarta-servlet-filter=org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.jakarta.FilterAdapter\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-websocket/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../../pom.xml</relativePath>\n  </parent>\n\n  <artifactId>dubbo-triple-websocket</artifactId>\n\n  <properties>\n    <servlet4_version>4.0.1</servlet4_version>\n    <websocket_version>1.1</websocket_version>\n    <sources_directory>${project.build.directory}/generated-sources/java/org/apache/dubbo/rpc/protocol/tri</sources_directory>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-triple</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-websocket</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>javax.servlet</groupId>\n      <artifactId>javax.servlet-api</artifactId>\n      <version>${servlet4_version}</version>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>jakarta.servlet</groupId>\n      <artifactId>jakarta.servlet-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>javax.websocket</groupId>\n      <artifactId>javax.websocket-api</artifactId>\n      <version>${websocket_version}</version>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>jakarta.websocket</groupId>\n      <artifactId>jakarta.websocket-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>jakarta.websocket</groupId>\n      <artifactId>jakarta.websocket-client-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <profiles>\n    <profile>\n      <id>jdk-version-ge-17</id>\n      <activation>\n        <jdk>[17,)</jdk>\n      </activation>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-antrun-plugin</artifactId>\n            <executions>\n              <execution>\n                <id>copy-sources</id>\n                <goals>\n                  <goal>run</goal>\n                </goals>\n                <phase>generate-sources</phase>\n                <configuration>\n                  <target>\n                    <copy overwrite=\"true\" todir=\"${sources_directory}/websocket/jakarta\">\n                      <fileset dir=\"src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket\" excludes=\"WebSocketConstants.java\" />\n                    </copy>\n                    <replace token=\"tri.websocket;\" value=\"tri.websocket.jakarta;\">\n                      <fileset dir=\"${sources_directory}\" />\n                    </replace>\n                    <replace token=\"javax.servlet\" value=\"jakarta.servlet\">\n                      <fileset dir=\"${sources_directory}\" />\n                    </replace>\n                    <replace token=\"javax.websocket\" value=\"jakarta.websocket\">\n                      <fileset dir=\"${sources_directory}\" />\n                    </replace>\n                    <replace file=\"${sources_directory}/websocket/jakarta/TripleEndpoint.java\">\n                      <replacetoken>import org.apache.dubbo.rpc.protocol.tri.ServletExchanger;</replacetoken>\n                      <replacevalue><![CDATA[import org.apache.dubbo.rpc.protocol.tri.ServletExchanger;\nimport org.apache.dubbo.rpc.protocol.tri.websocket.DefaultWebSocketServerTransportListenerFactory;]]></replacevalue>\n                    </replace>\n                  </target>\n                </configuration>\n              </execution>\n            </executions>\n          </plugin>\n          <plugin>\n            <groupId>org.codehaus.mojo</groupId>\n            <artifactId>build-helper-maven-plugin</artifactId>\n            <executions>\n              <execution>\n                <id>add-sources</id>\n                <goals>\n                  <goal>add-source</goal>\n                </goals>\n                <phase>generate-sources</phase>\n                <configuration>\n                  <sources>\n                    <source>${project.build.directory}/generated-sources/java</source>\n                  </sources>\n                </configuration>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleBinaryMessageHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.websocket;\n\nimport org.apache.dubbo.remoting.http12.h2.Http2InputMessage;\nimport org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame;\nimport org.apache.dubbo.remoting.websocket.FinalFragmentByteArrayInputStream;\nimport org.apache.dubbo.remoting.websocket.WebSocketTransportListener;\n\nimport javax.websocket.MessageHandler;\n\nimport java.nio.ByteBuffer;\n\npublic class TripleBinaryMessageHandler implements MessageHandler.Partial<ByteBuffer> {\n\n    private final WebSocketTransportListener webSocketTransportListener;\n\n    public TripleBinaryMessageHandler(WebSocketTransportListener webSocketTransportListener) {\n        this.webSocketTransportListener = webSocketTransportListener;\n    }\n\n    @Override\n    public void onMessage(ByteBuffer messagePart, boolean last) {\n        Http2InputMessage http2InputMessage =\n                new Http2InputMessageFrame(new FinalFragmentByteArrayInputStream(messagePart.array(), last), false);\n        webSocketTransportListener.onData(http2InputMessage);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleEndpoint.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.websocket;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.config.nested.TripleConfig;\nimport org.apache.dubbo.remoting.http12.HttpHeaderNames;\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.h2.Http2Header;\nimport org.apache.dubbo.remoting.http12.h2.Http2InputMessage;\nimport org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame;\nimport org.apache.dubbo.remoting.http12.h2.Http2MetadataFrame;\nimport org.apache.dubbo.remoting.http12.message.DefaultHttpHeaders;\nimport org.apache.dubbo.remoting.websocket.WebSocketTransportListener;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.ServletExchanger;\n\nimport javax.websocket.CloseReason;\nimport javax.websocket.CloseReason.CloseCodes;\nimport javax.websocket.Endpoint;\nimport javax.websocket.EndpointConfig;\nimport javax.websocket.Session;\n\nimport static org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketConstants.TRIPLE_WEBSOCKET_LISTENER;\n\npublic class TripleEndpoint extends Endpoint {\n\n    @Override\n    public void onOpen(Session session, EndpointConfig config) {\n        String path = session.getRequestURI().getPath();\n        HttpHeaders httpHeaders = new DefaultHttpHeaders();\n        httpHeaders.set(HttpHeaderNames.PATH.getName(), path);\n        httpHeaders.set(HttpHeaderNames.METHOD.getName(), HttpMethods.POST.name());\n        Http2Header http2Header = new Http2MetadataFrame(httpHeaders);\n\n        URL url = ServletExchanger.getUrl();\n        TripleConfig tripleConfig = ConfigManager.getProtocolOrDefault(url).getTripleOrDefault();\n\n        WebSocketStreamChannel webSocketStreamChannel = new WebSocketStreamChannel(session, tripleConfig);\n        WebSocketTransportListener webSocketTransportListener =\n                DefaultWebSocketServerTransportListenerFactory.INSTANCE.newInstance(\n                        webSocketStreamChannel, url, FrameworkModel.defaultModel());\n        webSocketTransportListener.onMetadata(http2Header);\n        session.addMessageHandler(new TripleTextMessageHandler(webSocketTransportListener));\n        session.addMessageHandler(new TripleBinaryMessageHandler(webSocketTransportListener));\n        session.getUserProperties().put(TRIPLE_WEBSOCKET_LISTENER, webSocketTransportListener);\n    }\n\n    @Override\n    public void onClose(Session session, CloseReason closeReason) {\n        super.onClose(session, closeReason);\n        WebSocketTransportListener webSocketTransportListener =\n                (WebSocketTransportListener) session.getUserProperties().get(TRIPLE_WEBSOCKET_LISTENER);\n        if (webSocketTransportListener == null) {\n            return;\n        }\n        if (closeReason.getCloseCode().getCode() == CloseCodes.NORMAL_CLOSURE.getCode()) {\n            Http2InputMessage http2InputMessage = new Http2InputMessageFrame(StreamUtils.EMPTY, true);\n            webSocketTransportListener.onData(http2InputMessage);\n            return;\n        }\n        webSocketTransportListener.cancelByRemote(closeReason.getCloseCode().getCode());\n    }\n\n    @Override\n    public void onError(Session session, Throwable thr) {\n        super.onError(session, thr);\n        WebSocketTransportListener webSocketTransportListener =\n                (WebSocketTransportListener) session.getUserProperties().get(TRIPLE_WEBSOCKET_LISTENER);\n        if (webSocketTransportListener == null) {\n            return;\n        }\n        webSocketTransportListener.cancelByRemote(HttpStatus.INTERNAL_SERVER_ERROR.getCode());\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleTextMessageHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.websocket;\n\nimport org.apache.dubbo.remoting.http12.h2.Http2InputMessage;\nimport org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame;\nimport org.apache.dubbo.remoting.websocket.FinalFragmentByteArrayInputStream;\nimport org.apache.dubbo.remoting.websocket.WebSocketTransportListener;\n\nimport javax.websocket.MessageHandler;\n\nimport java.nio.charset.StandardCharsets;\n\npublic class TripleTextMessageHandler implements MessageHandler.Partial<String> {\n\n    private final WebSocketTransportListener webSocketTransportListener;\n\n    public TripleTextMessageHandler(WebSocketTransportListener webSocketTransportListener) {\n        this.webSocketTransportListener = webSocketTransportListener;\n    }\n\n    @Override\n    public void onMessage(String messagePart, boolean last) {\n        Http2InputMessage http2InputMessage = new Http2InputMessageFrame(\n                new FinalFragmentByteArrayInputStream(messagePart.getBytes(StandardCharsets.UTF_8), last), false);\n        webSocketTransportListener.onData(http2InputMessage);\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleWebSocketFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.websocket;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\n\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletRequestWrapper;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.websocket.server.ServerContainer;\nimport javax.websocket.server.ServerEndpointConfig;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_REQUEST;\nimport static org.apache.dubbo.rpc.protocol.tri.TripleConstants.UPGRADE_HEADER_KEY;\nimport static org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketConstants.TRIPLE_WEBSOCKET_REMOTE_ADDRESS;\nimport static org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketConstants.TRIPLE_WEBSOCKET_UPGRADE_HEADER_VALUE;\n\npublic class TripleWebSocketFilter implements Filter {\n\n    private static final ErrorTypeAwareLogger LOG = LoggerFactory.getErrorTypeAwareLogger(TripleWebSocketFilter.class);\n\n    private transient ServerContainer sc;\n\n    private final Set<String> existed = new ConcurrentHashSet<>();\n\n    @Override\n    public void init(FilterConfig filterConfig) {\n        sc = (ServerContainer) filterConfig.getServletContext().getAttribute(ServerContainer.class.getName());\n    }\n\n    @Override\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n            throws IOException, ServletException {\n        if (!isWebSocketUpgradeRequest(request, response)) {\n            chain.doFilter(request, response);\n            return;\n        }\n        HttpServletRequest hRequest = (HttpServletRequest) request;\n        HttpServletResponse hResponse = (HttpServletResponse) response;\n        String path;\n        String pathInfo = hRequest.getPathInfo();\n        if (pathInfo == null) {\n            path = hRequest.getServletPath();\n        } else {\n            path = hRequest.getServletPath() + pathInfo;\n        }\n        Map<String, String[]> copiedMap = new HashMap<>(hRequest.getParameterMap());\n        copiedMap.put(\n                TRIPLE_WEBSOCKET_REMOTE_ADDRESS,\n                new String[] {hRequest.getRemoteHost(), String.valueOf(hRequest.getRemotePort())});\n        HttpServletRequestWrapper wrappedRequest = new HttpServletRequestWrapper(hRequest) {\n            @Override\n            public Map<String, String[]> getParameterMap() {\n                return copiedMap;\n            }\n        };\n        if (existed.contains(path)) {\n            chain.doFilter(wrappedRequest, hResponse);\n            return;\n        }\n        ServerEndpointConfig serverEndpointConfig =\n                ServerEndpointConfig.Builder.create(TripleEndpoint.class, path).build();\n        try {\n            sc.addEndpoint(serverEndpointConfig);\n            existed.add(path);\n        } catch (Exception e) {\n            LOG.error(PROTOCOL_FAILED_REQUEST, \"\", \"\", \"Failed to add endpoint\", e);\n            hResponse.sendError(HttpServletResponse.SC_BAD_REQUEST);\n            return;\n        }\n        chain.doFilter(wrappedRequest, hResponse);\n    }\n\n    @Override\n    public void destroy() {}\n\n    public boolean isWebSocketUpgradeRequest(ServletRequest request, ServletResponse response) {\n        return ((request instanceof HttpServletRequest)\n                && (response instanceof HttpServletResponse)\n                && headerContainsToken(\n                        (HttpServletRequest) request, UPGRADE_HEADER_KEY, TRIPLE_WEBSOCKET_UPGRADE_HEADER_VALUE)\n                && HttpMethods.GET.name().equals(((HttpServletRequest) request).getMethod()));\n    }\n\n    private boolean headerContainsToken(HttpServletRequest req, String headerName, String target) {\n        Enumeration<String> headers = req.getHeaders(headerName);\n        while (headers.hasMoreElements()) {\n            String header = headers.nextElement();\n            String[] tokens = header.split(\",\");\n            for (String token : tokens) {\n                if (target.equalsIgnoreCase(token.trim())) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.websocket;\n\npublic interface WebSocketConstants {\n\n    String TRIPLE_WEBSOCKET_UPGRADE_HEADER_VALUE = \"websocket\";\n\n    String TRIPLE_WEBSOCKET_REMOTE_ADDRESS = \"tri.websocket.remote.address\";\n\n    String TRIPLE_WEBSOCKET_LISTENER = \"tri.websocket.listener\";\n}\n"
  },
  {
    "path": "dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketStreamChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.rpc.protocol.tri.websocket;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.config.nested.TripleConfig;\nimport org.apache.dubbo.remoting.http12.HttpHeaderNames;\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\nimport org.apache.dubbo.remoting.http12.HttpOutputMessage;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.LimitedByteArrayOutputStream;\nimport org.apache.dubbo.remoting.http12.h2.H2StreamChannel;\nimport org.apache.dubbo.remoting.http12.h2.Http2Header;\nimport org.apache.dubbo.remoting.http12.h2.Http2OutputMessage;\nimport org.apache.dubbo.remoting.http12.h2.Http2OutputMessageFrame;\nimport org.apache.dubbo.remoting.websocket.WebSocketHeaderNames;\n\nimport javax.websocket.CloseReason;\nimport javax.websocket.Session;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.nio.ByteBuffer;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\n\nimport static org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketConstants.TRIPLE_WEBSOCKET_REMOTE_ADDRESS;\n\npublic class WebSocketStreamChannel implements H2StreamChannel {\n\n    private final Session session;\n\n    private final TripleConfig tripleConfig;\n\n    private final InetSocketAddress remoteAddress;\n\n    private final InetSocketAddress localAddress;\n\n    public WebSocketStreamChannel(Session session, TripleConfig tripleConfig) {\n        this.session = session;\n        this.tripleConfig = tripleConfig;\n        Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();\n        List<String> remoteAddressData = requestParameterMap.get(TRIPLE_WEBSOCKET_REMOTE_ADDRESS);\n        this.remoteAddress = InetSocketAddress.createUnresolved(\n                remoteAddressData.get(0), Integer.parseInt(remoteAddressData.get(1)));\n        this.localAddress = InetSocketAddress.createUnresolved(\n                session.getRequestURI().getHost(), session.getRequestURI().getPort());\n    }\n\n    @Override\n    public CompletableFuture<Void> writeResetFrame(long errorCode) {\n        CompletableFuture<Void> completableFuture = new CompletableFuture<>();\n        try {\n            session.close();\n            completableFuture.complete(null);\n        } catch (IOException e) {\n            completableFuture.completeExceptionally(e);\n        }\n        return completableFuture;\n    }\n\n    @Override\n    public Http2OutputMessage newOutputMessage(boolean endStream) {\n        return new Http2OutputMessageFrame(\n                new LimitedByteArrayOutputStream(256, tripleConfig.getMaxResponseBodySizeOrDefault()), endStream);\n    }\n\n    @Override\n    public void consumeBytes(int numBytes) throws Exception {\n        // do nothing\n    }\n\n    @Override\n    public CompletableFuture<Void> writeHeader(HttpMetadata httpMetadata) {\n        Http2Header http2Header = (Http2Header) httpMetadata;\n        CompletableFuture<Void> completableFuture = new CompletableFuture<>();\n        if (http2Header.isEndStream()) {\n            try {\n                session.close(encodeCloseReason(http2Header));\n                completableFuture.complete(null);\n            } catch (IOException e) {\n                completableFuture.completeExceptionally(e);\n            }\n        }\n        return completableFuture;\n    }\n\n    @Override\n    public CompletableFuture<Void> writeMessage(HttpOutputMessage httpOutputMessage) {\n        ByteArrayOutputStream body = (ByteArrayOutputStream) httpOutputMessage.getBody();\n        CompletableFuture<Void> completableFuture = new CompletableFuture<>();\n        try {\n            session.getBasicRemote().sendBinary(ByteBuffer.wrap(body.toByteArray()));\n            completableFuture.complete(null);\n        } catch (IOException e) {\n            completableFuture.completeExceptionally(e);\n        }\n        return completableFuture;\n    }\n\n    @Override\n    public SocketAddress remoteAddress() {\n        return remoteAddress;\n    }\n\n    @Override\n    public SocketAddress localAddress() {\n        return localAddress;\n    }\n\n    @Override\n    public void flush() {}\n\n    @Override\n    public boolean isReady() {\n        return session.isOpen();\n    }\n\n    private CloseReason encodeCloseReason(Http2Header http2Header) {\n        HttpHeaders headers = http2Header.headers();\n        List<String> statusHeaders = headers.remove(HttpHeaderNames.STATUS.getName());\n        CloseReason closeReason;\n        if (CollectionUtils.isNotEmpty(statusHeaders)\n                && !HttpStatus.OK.getStatusString().equals(statusHeaders.get(0))) {\n            List<String> messageHeaders = headers.remove(WebSocketHeaderNames.WEBSOCKET_MESSAGE.getName());\n            closeReason = new CloseReason(\n                    CloseReason.CloseCodes.UNEXPECTED_CONDITION,\n                    CollectionUtils.isNotEmpty(messageHeaders) ? messageHeaders.get(0) : \"Internal server error\");\n        } else {\n            closeReason = new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, \"Bye\");\n        }\n        return closeReason;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-registry</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-registry-api</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The registry module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-cluster</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metadata-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-framework</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-recipes</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.zookeeper</groupId>\n      <artifactId>zookeeper</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-api</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>compile</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-default</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>compile</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-metadata</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>compile</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-metrics-registry</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>compile</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-native</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\npublic interface Constants {\n    String REGISTER_IP_KEY = \"register.ip\";\n\n    String REGISTER_KEY = \"register\";\n\n    String SUBSCRIBE_KEY = \"subscribe\";\n\n    String DEFAULT_REGISTRY = \"dubbo\";\n\n    String REGISTER = \"register\";\n\n    String UNREGISTER = \"unregister\";\n\n    String SUBSCRIBE = \"subscribe\";\n\n    String UNSUBSCRIBE = \"unsubscribe\";\n\n    String CONFIGURATORS_SUFFIX = \".configurators\";\n\n    String ADMIN_PROTOCOL = \"admin\";\n\n    String PROVIDER_PROTOCOL = \"provider\";\n\n    String CONSUMER_PROTOCOL = \"consumer\";\n\n    String SCRIPT_PROTOCOL = \"script\";\n\n    String CONDITION_PROTOCOL = \"condition\";\n    String TRACE_PROTOCOL = \"trace\";\n    /**\n     * simple the registry for provider.\n     *\n     * @since 2.7.0\n     */\n    String SIMPLIFIED_KEY = \"simplified\";\n\n    /**\n     * To decide whether register center saves file synchronously, the default value is asynchronously\n     */\n    String REGISTRY_FILESAVE_SYNC_KEY = \"save.file\";\n\n    /**\n     * Reconnection period in milliseconds for register center\n     */\n    String REGISTRY_RECONNECT_PERIOD_KEY = \"reconnect.period\";\n\n    int DEFAULT_SESSION_TIMEOUT = 60 * 1000;\n\n    /**\n     * Default value for the times of retry: -1 (forever)\n     */\n    int DEFAULT_REGISTRY_RETRY_TIMES = -1;\n\n    int DEFAULT_REGISTRY_RECONNECT_PERIOD = 3 * 1000;\n\n    /**\n     * Default value for the period of retry interval in milliseconds: 5000\n     */\n    int DEFAULT_REGISTRY_RETRY_PERIOD = 5 * 1000;\n\n    /**\n     * Most retry times\n     */\n    String REGISTRY_RETRY_TIMES_KEY = \"retry.times\";\n\n    /**\n     * Period of registry center's retry interval\n     */\n    String REGISTRY_RETRY_PERIOD_KEY = \"retry.period\";\n\n    String SESSION_TIMEOUT_KEY = \"session\";\n\n    /**\n     * To decide the frequency of checking Distributed Service Discovery Registry callback hook (in ms)\n     */\n    String ECHO_POLLING_CYCLE_KEY = \"echoPollingCycle\";\n\n    /**\n     * Default value for check frequency: 60000 (ms)\n     */\n    int DEFAULT_ECHO_POLLING_CYCLE = 60000;\n\n    String MIGRATION_STEP_KEY = \"migration.step\";\n\n    String MIGRATION_DELAY_KEY = \"migration.delay\";\n\n    String MIGRATION_FORCE_KEY = \"migration.force\";\n\n    String MIGRATION_PROMOTION_KEY = \"migration.promotion\";\n\n    String MIGRATION_THRESHOLD_KEY = \"migration.threshold\";\n\n    String ENABLE_26X_CONFIGURATION_LISTEN = \"enable-26x-configuration-listen\";\n\n    String ENABLE_CONFIGURATION_LISTEN = \"enable-configuration-listen\";\n\n    /**\n     * MIGRATION_RULE_XXX from remote configuration\n     */\n    String MIGRATION_RULE_KEY = \"key\";\n\n    String MIGRATION_RULE_STEP_KEY = \"step\";\n\n    String MIGRATION_RULE_THRESHOLD_KEY = \"threshold\";\n\n    String MIGRATION_RULE_PROPORTION_KEY = \"proportion\";\n\n    String MIGRATION_RULE_DELAY_KEY = \"delay\";\n\n    String MIGRATION_RULE_FORCE_KEY = \"force\";\n\n    String MIGRATION_RULE_INTERFACES_KEY = \"interfaces\";\n\n    String MIGRATION_RULE_APPLICATIONS_KEY = \"applications\";\n\n    String USER_HOME = \"user.home\";\n\n    String DUBBO_REGISTRY = \"/.dubbo/dubbo-registry-\";\n\n    String CACHE = \".cache\";\n\n    int DEFAULT_CAS_RETRY_TIMES = 10;\n\n    String CAS_RETRY_TIMES_KEY = \"dubbo.metadata-report.cas-retry-times\";\n\n    int DEFAULT_CAS_RETRY_WAIT_TIME = 100;\n\n    String CAS_RETRY_WAIT_TIME_KEY = \"dubbo.metadata-report.cas-retry-wait-time\";\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/ListenerRegistryWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\n\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\n\npublic class ListenerRegistryWrapper implements Registry {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ListenerRegistryWrapper.class);\n\n    private final Registry registry;\n    private final List<RegistryServiceListener> listeners;\n\n    public ListenerRegistryWrapper(Registry registry, List<RegistryServiceListener> listeners) {\n        this.registry = registry;\n        this.listeners = listeners;\n    }\n\n    @Override\n    public URL getUrl() {\n        return registry.getUrl();\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return registry.isAvailable();\n    }\n\n    @Override\n    public void destroy() {\n        registry.destroy();\n    }\n\n    @Override\n    public void register(URL url) {\n        try {\n            if (registry != null) {\n                registry.register(url);\n            }\n        } finally {\n            if (!UrlUtils.isConsumer(url)) {\n                listenerEvent(serviceListener -> serviceListener.onRegister(url, registry));\n            }\n        }\n    }\n\n    @Override\n    public void unregister(URL url) {\n        try {\n            if (registry != null) {\n                registry.unregister(url);\n            }\n        } finally {\n            if (!UrlUtils.isConsumer(url)) {\n                listenerEvent(serviceListener -> serviceListener.onUnregister(url, registry));\n            }\n        }\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        try {\n            if (registry != null) {\n                registry.subscribe(url, listener);\n            }\n        } finally {\n            listenerEvent(serviceListener -> serviceListener.onSubscribe(url, registry));\n        }\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        try {\n            registry.unsubscribe(url, listener);\n        } finally {\n            listenerEvent(serviceListener -> serviceListener.onUnsubscribe(url, registry));\n        }\n    }\n\n    @Override\n    public boolean isServiceDiscovery() {\n        return registry.isServiceDiscovery();\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        return registry.lookup(url);\n    }\n\n    public Registry getRegistry() {\n        return registry;\n    }\n\n    private void listenerEvent(Consumer<RegistryServiceListener> consumer) {\n        if (CollectionUtils.isNotEmpty(listeners)) {\n            RuntimeException exception = null;\n            for (RegistryServiceListener listener : listeners) {\n                if (listener != null) {\n                    try {\n                        consumer.accept(listener);\n                    } catch (RuntimeException t) {\n                        logger.error(INTERNAL_ERROR, \"unknown error in registry module\", \"\", t.getMessage(), t);\n                        exception = t;\n                    }\n                }\n            }\n            if (exception != null) {\n                throw exception;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/NotifyListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\n\nimport java.util.List;\n\n/**\n * NotifyListener. (API, Prototype, ThreadSafe)\n *\n * @see org.apache.dubbo.registry.RegistryService#subscribe(URL, NotifyListener)\n */\npublic interface NotifyListener {\n\n    /**\n     * Triggered when a service change notification is received.\n     * <p>\n     * Notify needs to support the contract: <br>\n     * 1. Always notifications on the service interface and the dimension of the data type. that is, won't notify part of the same type data belonging to one service. Users do not need to compare the results of the previous notification.<br>\n     * 2. The first notification at a subscription must be a full notification of all types of data of a service.<br>\n     * 3. At the time of change, different types of data are allowed to be notified separately, e.g.: providers, consumers, routers, overrides. It allows only one of these types to be notified, but the data of this type must be full, not incremental.<br>\n     * 4. If a data type is empty, need to notify a empty protocol with category parameter identification of url data.<br>\n     * 5. The order of notifications to be guaranteed by the notifications(That is, the implementation of the registry). Such as: single thread push, queue serialization, and version comparison.<br>\n     *\n     * @param urls The list of registered information , is always not empty. The meaning is the same as the return value of {@link org.apache.dubbo.registry.RegistryService#lookup(URL)}.\n     */\n    void notify(List<URL> urls);\n\n    default void addServiceListener(ServiceInstancesChangedListener instanceListener) {}\n\n    default ServiceInstancesChangedListener getServiceListener() {\n        return null;\n    }\n\n    default URL getConsumerUrl() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/ProviderFirstParams.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.util.Set;\n\n@SPI\npublic interface ProviderFirstParams {\n    Set<String> params();\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Registry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.Node;\nimport org.apache.dubbo.common.URL;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_DELAY_NOTIFICATION_TIME;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_DELAY_NOTIFICATION_KEY;\n\n/**\n * Registry. (SPI, Prototype, ThreadSafe)\n *\n * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(URL)\n * @see org.apache.dubbo.registry.support.AbstractRegistry\n */\npublic interface Registry extends Node, RegistryService {\n    default int getDelay() {\n        return getUrl().getParameter(REGISTRY_DELAY_NOTIFICATION_KEY, DEFAULT_DELAY_NOTIFICATION_TIME);\n    }\n\n    default boolean isServiceDiscovery() {\n        return false;\n    }\n\n    default void reExportRegister(URL url) {\n        register(url);\n    }\n\n    default void reExportUnregister(URL url) {\n        unregister(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.extension.ExtensionScope.APPLICATION;\n\n/**\n * RegistryFactory. (SPI, Singleton, ThreadSafe)\n *\n * @see org.apache.dubbo.registry.support.AbstractRegistryFactory\n */\n@SPI(scope = APPLICATION)\npublic interface RegistryFactory {\n\n    /**\n     * Connect to the registry\n     * <p>\n     * Connecting the registry needs to support the contract: <br>\n     * 1. When the check=false is set, the connection is not checked, otherwise the exception is thrown when disconnection <br>\n     * 2. Support username:password authority authentication on URL.<br>\n     * 3. Support the backup=10.20.153.10 candidate registry cluster address.<br>\n     * 4. Support file=registry.cache local disk file cache.<br>\n     * 5. Support the timeout=1000 request timeout setting.<br>\n     * 6. Support session=60000 session timeout or expiration settings.<br>\n     *\n     * @param url Registry address, is not allowed to be empty\n     * @return Registry reference, never return empty value\n     */\n    @Adaptive({PROTOCOL_KEY})\n    Registry getRegistry(URL url);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryFactoryWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.Collections;\n\npublic class RegistryFactoryWrapper implements RegistryFactory {\n    private RegistryFactory registryFactory;\n\n    public RegistryFactoryWrapper(RegistryFactory registryFactory) {\n        this.registryFactory = registryFactory;\n    }\n\n    @Override\n    public Registry getRegistry(URL url) {\n        return new ListenerRegistryWrapper(\n                registryFactory.getRegistry(url),\n                Collections.unmodifiableList(url.getOrDefaultApplicationModel()\n                        .getExtensionLoader(RegistryServiceListener.class)\n                        .getActivateExtension(url, \"registry.listeners\")));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryNotifier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\n\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_DELAY_EXECUTE_TIMES;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_FAILED_NOTIFY_EVENT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_NOTIFY_EVENT;\n\npublic abstract class RegistryNotifier {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(RegistryNotifier.class);\n    private volatile long lastExecuteTime;\n    private volatile long lastEventTime;\n    private final URL url;\n    private Object rawAddresses;\n    private long delayTime;\n\n    // should delay notify or not\n    private final AtomicBoolean shouldDelay = new AtomicBoolean(false);\n    // for the first 10 notification will be notified immediately\n    private final AtomicInteger executeTime = new AtomicInteger(0);\n\n    private ScheduledExecutorService scheduler;\n\n    public RegistryNotifier(URL registryUrl, long delayTime) {\n        this(registryUrl, delayTime, null);\n    }\n\n    public RegistryNotifier(URL registryUrl, long delayTime, ScheduledExecutorService scheduler) {\n        this.url = registryUrl;\n        this.delayTime = delayTime;\n        if (scheduler == null) {\n            this.scheduler = registryUrl\n                    .getOrDefaultFrameworkModel()\n                    .getBeanFactory()\n                    .getBean(FrameworkExecutorRepository.class)\n                    .getRegistryNotificationExecutor();\n        } else {\n            this.scheduler = scheduler;\n        }\n    }\n\n    public synchronized void notify(Object rawAddresses) {\n        this.rawAddresses = rawAddresses;\n        long notifyTime = System.currentTimeMillis();\n        this.lastEventTime = notifyTime;\n\n        long delta = (System.currentTimeMillis() - lastExecuteTime) - delayTime;\n\n        // more than 10 calls && next execute time is in the future\n        boolean delay = shouldDelay.get() && delta < 0;\n        // when the scheduler is shutdown, no notification is sent\n        if (scheduler.isShutdown()) {\n            if (logger.isWarnEnabled()) {\n                logger.warn(\n                        COMMON_FAILED_NOTIFY_EVENT,\n                        \"\",\n                        \"\",\n                        \"Notification scheduler is off, no notifications are sent. Registry URL:  \" + url);\n            }\n            return;\n        } else if (delay) {\n            scheduler.schedule(new NotificationTask(this, notifyTime), -delta, TimeUnit.MILLISECONDS);\n        } else {\n            // check if more than 10 calls\n            if (!shouldDelay.get() && executeTime.incrementAndGet() > DEFAULT_DELAY_EXECUTE_TIMES) {\n                shouldDelay.set(true);\n            }\n            scheduler.submit(new NotificationTask(this, notifyTime));\n        }\n        try {\n            while (this.lastEventTime == System.currentTimeMillis()) {\n                // wait to let event time refresh\n                Thread.sleep(1);\n            }\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n        }\n    }\n\n    public long getDelayTime() {\n        return delayTime;\n    }\n\n    /**\n     * notification of instance addresses (aka providers).\n     *\n     * @param rawAddresses data.\n     */\n    protected abstract void doNotify(Object rawAddresses);\n\n    public static class NotificationTask implements Runnable {\n        private final RegistryNotifier listener;\n        private final long time;\n\n        public NotificationTask(RegistryNotifier listener, long time) {\n            this.listener = listener;\n            this.time = time;\n        }\n\n        @Override\n        public void run() {\n            try {\n                if (this.time == listener.lastEventTime) {\n                    listener.doNotify(listener.rawAddresses);\n                    listener.lastExecuteTime = System.currentTimeMillis();\n                    synchronized (listener) {\n                        if (this.time == listener.lastEventTime) {\n                            listener.rawAddresses = null;\n                        }\n                    }\n                }\n            } catch (Throwable t) {\n                logger.error(REGISTRY_FAILED_NOTIFY_EVENT, \"\", \"\", \"Error occurred when notify directory. \", t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegationV2;\nimport org.apache.dubbo.registry.integration.ExporterFactory;\nimport org.apache.dubbo.registry.support.RegistryManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModelInitializer;\n\npublic class RegistryScopeModelInitializer implements ScopeModelInitializer {\n\n    @Override\n    public void initializeFrameworkModel(FrameworkModel frameworkModel) {\n        ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();\n        beanFactory.registerBean(ExporterFactory.class);\n    }\n\n    @Override\n    public void initializeApplicationModel(ApplicationModel applicationModel) {\n        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();\n        beanFactory.registerBean(RegistryManager.class);\n        beanFactory.registerBean(MetadataServiceDelegation.class);\n        beanFactory.registerBean(MetadataServiceDelegationV2.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.List;\n\n/**\n * RegistryService. (SPI, Prototype, ThreadSafe)\n *\n * @see org.apache.dubbo.registry.Registry\n * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(URL)\n */\npublic interface RegistryService {\n\n    /**\n     * Register data, such as : provider service, consumer address, route rule, override rule and other data.\n     * <p>\n     * Registering is required to support the contract:<br>\n     * 1. When the URL sets the check=false parameter. When the registration fails, the exception is not thrown and retried in the background. Otherwise, the exception will be thrown.<br>\n     * 2. When URL sets the dynamic=false parameter, it needs to be stored persistently, otherwise, it should be deleted automatically when the registrant has an abnormal exit.<br>\n     * 3. When the URL sets category=routers, it means classified storage, the default category is providers, and the data can be notified by the classified section. <br>\n     * 4. When the registry is restarted, network jitter, data can not be lost, including automatically deleting data from the broken line.<br>\n     * 5. Allow URLs which have the same URL but different parameters to coexist,they can't cover each other.<br>\n     *\n     * @param url  Registration information , is not allowed to be empty, e.g: dubbo://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin\n     */\n    void register(URL url);\n\n    /**\n     * Unregister\n     * <p>\n     * Unregistering is required to support the contract:<br>\n     * 1. If it is the persistent stored data of dynamic=false, the registration data can not be found, then the IllegalStateException is thrown, otherwise it is ignored.<br>\n     * 2. Unregister according to the full url match.<br>\n     *\n     * @param url Registration information , is not allowed to be empty, e.g: dubbo://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin\n     */\n    void unregister(URL url);\n\n    /**\n     * Subscribe to eligible registered data and automatically push when the registered data is changed.\n     * <p>\n     * Subscribing need to support contracts:<br>\n     * 1. When the URL sets the check=false parameter. When the registration fails, the exception is not thrown and retried in the background. <br>\n     * 2. When URL sets category=routers, it only notifies the specified classification data. Multiple classifications are separated by commas, and allows asterisk to match, which indicates that all categorical data are subscribed.<br>\n     * 3. Allow interface, group, version, and classifier as a conditional query, e.g.: interface=org.apache.dubbo.foo.BarService&version=1.0.0<br>\n     * 4. And the query conditions allow the asterisk to be matched, subscribe to all versions of all the packets of all interfaces, e.g. :interface=*&group=*&version=*&classifier=*<br>\n     * 5. When the registry is restarted and network jitter, it is necessary to automatically restore the subscription request.<br>\n     * 6. Allow URLs which have the same URL but different parameters to coexist,they can't cover each other.<br>\n     * 7. The subscription process must be blocked, when the first notice is finished and then returned.<br>\n     *\n     * @param url      Subscription condition, not allowed to be empty, e.g. consumer://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin\n     * @param listener A listener of the change event, not allowed to be empty\n     */\n    void subscribe(URL url, NotifyListener listener);\n\n    /**\n     * Unsubscribe\n     * <p>\n     * Unsubscribing is required to support the contract:<br>\n     * 1. If you don't subscribe, ignore it directly.<br>\n     * 2. Unsubscribe by full URL match.<br>\n     *\n     * @param url      Subscription condition, not allowed to be empty, e.g. consumer://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin\n     * @param listener A listener of the change event, not allowed to be empty\n     */\n    void unsubscribe(URL url, NotifyListener listener);\n\n    /**\n     * Query the registered data that matches the conditions. Corresponding to the push mode of the subscription, this is the pull mode and returns only one result.\n     *\n     * @param url Query condition, is not allowed to be empty, e.g. consumer://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin\n     * @return The registered information list, which may be empty, the meaning is the same as the parameters of {@link org.apache.dubbo.registry.NotifyListener#notify(List<URL>)}.\n     * @see org.apache.dubbo.registry.NotifyListener#notify(List)\n     */\n    List<URL> lookup(URL url);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryServiceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface RegistryServiceListener {\n    default void onRegister(URL url, Registry registry) {}\n\n    default void onUnregister(URL url, Registry registry) {}\n\n    default void onSubscribe(URL url, Registry registry) {}\n\n    default void onUnsubscribe(URL url, Registry registry) {}\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/aot/RegistryReflectionTypeDescriberRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.aot;\n\nimport org.apache.dubbo.aot.api.MemberCategory;\nimport org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;\nimport org.apache.dubbo.aot.api.TypeDescriber;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class RegistryReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {\n\n    @Override\n    public List<TypeDescriber> getTypeDescribers() {\n        List<TypeDescriber> typeDescribers = new ArrayList<>();\n        typeDescribers.add(buildTypeDescriberWithDeclaredMethod(MetadataServiceDelegation.class));\n\n        return typeDescribers;\n    }\n\n    private TypeDescriber buildTypeDescriberWithDeclaredMethod(Class<?> cl) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_PUBLIC_METHODS);\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n        return new TypeDescriber(\n                cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.MetadataReportInstance;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.metadata.event.MetadataEvent;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.registry.client.metadata.MetadataUtils;\nimport org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils;\nimport org.apache.dubbo.registry.client.metadata.store.MetaCacheManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_INFO_CACHE_EXPIRE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_INFO_CACHE_SIZE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_INFO_CACHE_EXPIRE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_INFO_CACHE_SIZE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_LOAD_METADATA;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_KEY;\nimport static org.apache.dubbo.metadata.RevisionResolver.EMPTY_REVISION;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getExportedServicesRevision;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.isValidInstance;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.setMetadataStorageType;\n\n/**\n * Each service discovery is bond to one application.\n */\npublic abstract class AbstractServiceDiscovery implements ServiceDiscovery {\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractServiceDiscovery.class);\n    private volatile boolean isDestroy;\n\n    protected final String serviceName;\n    protected volatile ServiceInstance serviceInstance;\n    protected volatile MetadataInfo metadataInfo;\n    protected final ConcurrentHashMap<String, MetadataInfoStat> metadataInfos = new ConcurrentHashMap<>();\n    protected volatile ScheduledFuture<?> refreshCacheFuture;\n    protected MetadataReport metadataReport;\n    protected String metadataType;\n    protected final MetaCacheManager metaCacheManager;\n    protected URL registryURL;\n\n    protected Set<ServiceInstancesChangedListener> instanceListeners = new ConcurrentHashSet<>();\n\n    protected ApplicationModel applicationModel;\n\n    public AbstractServiceDiscovery(ApplicationModel applicationModel, URL registryURL) {\n        this(applicationModel, applicationModel.getApplicationName(), registryURL);\n        MetadataReportInstance metadataReportInstance =\n                applicationModel.getBeanFactory().getBean(MetadataReportInstance.class);\n        this.metadataType = metadataReportInstance.getMetadataType();\n        this.metadataReport = metadataReportInstance.getMetadataReport(registryURL.getParameter(REGISTRY_CLUSTER_KEY));\n    }\n\n    public AbstractServiceDiscovery(String serviceName, URL registryURL) {\n        this(ApplicationModel.defaultModel(), serviceName, registryURL);\n    }\n\n    private AbstractServiceDiscovery(ApplicationModel applicationModel, String serviceName, URL registryURL) {\n        this.applicationModel = applicationModel;\n        this.serviceName = serviceName;\n        this.registryURL = registryURL;\n        this.metadataInfo = new MetadataInfo(serviceName);\n        boolean localCacheEnabled = registryURL.getParameter(REGISTRY_LOCAL_FILE_CACHE_ENABLED, true);\n        this.metaCacheManager = new MetaCacheManager(\n                localCacheEnabled,\n                getCacheNameSuffix(),\n                applicationModel\n                        .getFrameworkModel()\n                        .getBeanFactory()\n                        .getBean(FrameworkExecutorRepository.class)\n                        .getCacheRefreshingScheduledExecutor());\n        int metadataInfoCacheExpireTime =\n                registryURL.getParameter(METADATA_INFO_CACHE_EXPIRE_KEY, DEFAULT_METADATA_INFO_CACHE_EXPIRE);\n        int metadataInfoCacheSize =\n                registryURL.getParameter(METADATA_INFO_CACHE_SIZE_KEY, DEFAULT_METADATA_INFO_CACHE_SIZE);\n        startRefreshCache(metadataInfoCacheExpireTime / 2, metadataInfoCacheSize, metadataInfoCacheExpireTime);\n    }\n\n    private void removeExpiredMetadataInfo(int metadataInfoCacheSize, int metadataInfoCacheExpireTime) {\n        Long nextTime = null;\n        // Cache cleanup is only required when the cache size exceeds the cache limit.\n        if (metadataInfos.size() > metadataInfoCacheSize) {\n            List<MetadataInfoStat> values = new ArrayList<>(metadataInfos.values());\n            // Place the earliest data at the front\n            values.sort(Comparator.comparingLong(MetadataInfoStat::getUpdateTime));\n            for (MetadataInfoStat v : values) {\n                long time = System.currentTimeMillis() - v.getUpdateTime();\n                if (time > metadataInfoCacheExpireTime) {\n                    metadataInfos.remove(v.metadataInfo.getRevision(), v);\n                } else {\n                    // Calculate how long it will take for the next task to start\n                    nextTime = metadataInfoCacheExpireTime - time;\n                    break;\n                }\n            }\n        }\n        // If there is no metadata to clean up this time, the next task will start within half of the cache expiration\n        // time.\n        startRefreshCache(\n                nextTime == null ? metadataInfoCacheExpireTime / 2 : nextTime,\n                metadataInfoCacheSize,\n                metadataInfoCacheExpireTime);\n    }\n\n    private void startRefreshCache(long nextTime, int metadataInfoCacheSize, int metadataInfoCacheExpireTime) {\n        this.refreshCacheFuture = applicationModel\n                .getFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getSharedScheduledExecutor()\n                .schedule(\n                        () -> removeExpiredMetadataInfo(metadataInfoCacheSize, metadataInfoCacheExpireTime),\n                        nextTime,\n                        TimeUnit.MILLISECONDS);\n    }\n\n    @Override\n    public synchronized void register() throws RuntimeException {\n        if (isDestroy) {\n            return;\n        }\n        if (this.serviceInstance == null) {\n            ServiceInstance serviceInstance = createServiceInstance(this.metadataInfo);\n            if (!isValidInstance(serviceInstance)) {\n                return;\n            }\n            this.serviceInstance = serviceInstance;\n        }\n        boolean revisionUpdated = calOrUpdateInstanceRevision(this.serviceInstance);\n        if (revisionUpdated) {\n            try {\n                reportMetadata(this.metadataInfo);\n                doRegister(this.serviceInstance);\n            } catch (Exception e) {\n                this.serviceInstance = null;\n                throw e;\n            }\n        }\n    }\n\n    /**\n     * Update assumes that DefaultServiceInstance and its attributes will never get updated once created.\n     * Checking hasExportedServices() before registration guarantees that at least one service is ready for creating the\n     * instance.\n     */\n    @Override\n    public synchronized void update() throws RuntimeException {\n        if (isDestroy) {\n            return;\n        }\n\n        if (this.serviceInstance == null) {\n            register();\n        }\n\n        if (!isValidInstance(this.serviceInstance)) {\n            return;\n        }\n        ServiceInstance oldServiceInstance = this.serviceInstance;\n        DefaultServiceInstance newServiceInstance =\n                new DefaultServiceInstance((DefaultServiceInstance) oldServiceInstance);\n        boolean revisionUpdated = calOrUpdateInstanceRevision(newServiceInstance);\n        if (revisionUpdated) {\n            logger.info(String.format(\n                    \"Metadata of instance changed, updating instance with revision %s.\",\n                    newServiceInstance.getServiceMetadata().getRevision()));\n            doUpdate(oldServiceInstance, newServiceInstance);\n            this.serviceInstance = newServiceInstance;\n        }\n    }\n\n    @Override\n    public synchronized void unregister() throws RuntimeException {\n        if (isDestroy) {\n            return;\n        }\n        // fixme, this metadata info might still being shared by other instances\n        //        unReportMetadata(this.metadataInfo);\n        if (!isValidInstance(this.serviceInstance)) {\n            return;\n        }\n        doUnregister(this.serviceInstance);\n    }\n\n    @Override\n    public final ServiceInstance getLocalInstance() {\n        return this.serviceInstance;\n    }\n\n    @Override\n    public MetadataInfo getLocalMetadata() {\n        return this.metadataInfo;\n    }\n\n    @Override\n    public MetadataInfo getLocalMetadata(String revision) {\n        MetadataInfoStat metadataInfoStat = metadataInfos.get(revision);\n        if (metadataInfoStat != null) {\n            return metadataInfoStat.getMetadataInfo();\n        } else {\n            return null;\n        }\n    }\n\n    @Override\n    public MetadataInfo getRemoteMetadata(String revision, List<ServiceInstance> instances) {\n        MetadataInfo metadata = metaCacheManager.get(revision);\n\n        if (metadata != null && metadata != MetadataInfo.EMPTY) {\n            metadata.init();\n            // metadata loaded from cache\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"MetadataInfo for revision=\" + revision + \", \" + metadata);\n            }\n            return metadata;\n        }\n\n        synchronized (metaCacheManager) {\n            // try to load metadata from remote.\n            int triedTimes = 0;\n            while (triedTimes < 3) {\n\n                metadata = MetricsEventBus.post(\n                        MetadataEvent.toSubscribeEvent(applicationModel),\n                        () -> MetadataUtils.getRemoteMetadata(revision, instances, metadataReport),\n                        result -> result != MetadataInfo.EMPTY);\n\n                if (metadata != MetadataInfo.EMPTY) { // succeeded\n                    metadata.init();\n                    break;\n                } else { // failed\n                    if (triedTimes > 0) {\n                        if (logger.isDebugEnabled()) {\n                            logger.debug(\"Retry the \" + triedTimes + \" times to get metadata for revision=\" + revision);\n                        }\n                    }\n                    triedTimes++;\n                    try {\n                        Thread.sleep(1000);\n                    } catch (InterruptedException e) {\n                    }\n                }\n            }\n\n            if (metadata == MetadataInfo.EMPTY) {\n                logger.error(\n                        REGISTRY_FAILED_LOAD_METADATA,\n                        \"\",\n                        \"\",\n                        \"Failed to get metadata for revision after 3 retries, revision=\" + revision);\n            } else {\n                metaCacheManager.put(revision, metadata);\n            }\n        }\n        return metadata;\n    }\n\n    @Override\n    public MetadataInfo getRemoteMetadata(String revision) {\n        return metaCacheManager.get(revision);\n    }\n\n    @Override\n    public final void destroy() throws Exception {\n        isDestroy = true;\n        metaCacheManager.destroy();\n        refreshCacheFuture.cancel(true);\n        doDestroy();\n    }\n\n    @Override\n    public final boolean isDestroy() {\n        return isDestroy;\n    }\n\n    @Override\n    public void register(URL url) {\n        metadataInfo.addService(url);\n    }\n\n    @Override\n    public void unregister(URL url) {\n        metadataInfo.removeService(url);\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        metadataInfo.addSubscribedURL(url);\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        metadataInfo.removeSubscribedURL(url);\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        throw new UnsupportedOperationException(\n                \"Service discovery implementation does not support lookup of url list.\");\n    }\n\n    /**\n     * Update Service Instance. Unregister and then register by default.\n     * Can be override if registry support update instance directly.\n     * <br/>\n     * NOTICE: Remind to update {@link AbstractServiceDiscovery#serviceInstance}'s reference if updated\n     * and report metadata by {@link AbstractServiceDiscovery#reportMetadata(MetadataInfo)}\n     *\n     * @param oldServiceInstance origin service instance\n     * @param newServiceInstance new service instance\n     */\n    protected void doUpdate(ServiceInstance oldServiceInstance, ServiceInstance newServiceInstance) {\n        this.doUnregister(oldServiceInstance);\n\n        this.serviceInstance = newServiceInstance;\n\n        if (!EMPTY_REVISION.equals(getExportedServicesRevision(newServiceInstance))) {\n            reportMetadata(newServiceInstance.getServiceMetadata());\n            this.doRegister(newServiceInstance);\n        }\n    }\n\n    @Override\n    public URL getUrl() {\n        return registryURL;\n    }\n\n    protected abstract void doRegister(ServiceInstance serviceInstance) throws RuntimeException;\n\n    protected abstract void doUnregister(ServiceInstance serviceInstance);\n\n    protected abstract void doDestroy() throws Exception;\n\n    protected ServiceInstance createServiceInstance(MetadataInfo metadataInfo) {\n        DefaultServiceInstance instance = new DefaultServiceInstance(serviceName, applicationModel);\n        instance.setServiceMetadata(metadataInfo);\n        setMetadataStorageType(instance, metadataType);\n        ServiceInstanceMetadataUtils.customizeInstance(instance, applicationModel);\n        return instance;\n    }\n\n    protected boolean calOrUpdateInstanceRevision(ServiceInstance instance) {\n        String existingInstanceRevision = getExportedServicesRevision(instance);\n        MetadataInfo metadataInfo = instance.getServiceMetadata();\n        String newRevision = metadataInfo.calAndGetRevision();\n        if (!newRevision.equals(existingInstanceRevision)) {\n            instance.getMetadata().put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, metadataInfo.getRevision());\n            return true;\n        }\n        return false;\n    }\n\n    protected void reportMetadata(MetadataInfo metadataInfo) {\n        if (metadataInfo == null) {\n            return;\n        }\n        if (metadataReport != null) {\n            SubscriberMetadataIdentifier identifier =\n                    new SubscriberMetadataIdentifier(serviceName, metadataInfo.getRevision());\n            if ((DEFAULT_METADATA_STORAGE_TYPE.equals(metadataType) && metadataReport.shouldReportMetadata())\n                    || REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {\n                MetricsEventBus.post(MetadataEvent.toPushEvent(applicationModel), () -> {\n                    metadataReport.publishAppMetadata(identifier, metadataInfo);\n                    return null;\n                });\n            }\n        }\n        MetadataInfo clonedMetadataInfo = metadataInfo.clone();\n        metadataInfos.put(metadataInfo.getRevision(), new MetadataInfoStat(clonedMetadataInfo));\n    }\n\n    protected void unReportMetadata(MetadataInfo metadataInfo) {\n        if (metadataReport != null) {\n            SubscriberMetadataIdentifier identifier =\n                    new SubscriberMetadataIdentifier(serviceName, metadataInfo.getRevision());\n            if ((DEFAULT_METADATA_STORAGE_TYPE.equals(metadataType) && metadataReport.shouldReportMetadata())\n                    || REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {\n                metadataReport.unPublishAppMetadata(identifier, metadataInfo);\n            }\n        }\n    }\n\n    private String getCacheNameSuffix() {\n        String name = this.getClass().getSimpleName();\n        int i = name.indexOf(ServiceDiscovery.class.getSimpleName());\n        if (i != -1) {\n            name = name.substring(0, i);\n        }\n        StringBuilder stringBuilder = new StringBuilder(128);\n        Optional<ApplicationConfig> application =\n                applicationModel.getApplicationConfigManager().getApplication();\n        if (application.isPresent()) {\n            stringBuilder.append(application.get().getName());\n            stringBuilder.append(\".\");\n        }\n        stringBuilder.append(name.toLowerCase());\n        URL url = this.getUrl();\n        if (url != null) {\n            stringBuilder.append(\".\");\n            stringBuilder.append(url.getBackupAddress());\n        }\n        return stringBuilder.toString();\n    }\n\n    private static class MetadataInfoStat {\n        private final MetadataInfo metadataInfo;\n        private final long updateTime = System.currentTimeMillis();\n\n        public MetadataInfoStat(MetadataInfo metadataInfo) {\n            this.metadataInfo = metadataInfo;\n        }\n\n        public MetadataInfo getMetadataInfo() {\n            return metadataInfo;\n        }\n\n        public long getUpdateTime() {\n            return updateTime;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscoveryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Abstract {@link ServiceDiscoveryFactory} implementation with cache, the subclass\n * should implement {@link #createDiscovery(URL)} method to create an instance of {@link ServiceDiscovery}\n *\n * @see ServiceDiscoveryFactory\n * @since 2.7.5\n */\npublic abstract class AbstractServiceDiscoveryFactory implements ServiceDiscoveryFactory, ScopeModelAware {\n\n    protected ApplicationModel applicationModel;\n    private final ConcurrentMap<String, ServiceDiscovery> discoveries = new ConcurrentHashMap<>();\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    public List<ServiceDiscovery> getAllServiceDiscoveries() {\n        return Collections.unmodifiableList(new LinkedList<>(discoveries.values()));\n    }\n\n    @Override\n    public ServiceDiscovery getServiceDiscovery(URL registryURL) {\n        String key = createRegistryCacheKey(registryURL);\n        return ConcurrentHashMapUtils.computeIfAbsent(discoveries, key, k -> createDiscovery(registryURL));\n    }\n\n    protected String createRegistryCacheKey(URL url) {\n        return url.toServiceStringWithoutResolving();\n    }\n\n    protected abstract ServiceDiscovery createDiscovery(URL registryURL);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultRegistryClusterIdentifier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_KEY;\n\npublic class DefaultRegistryClusterIdentifier implements RegistryClusterIdentifier {\n    @Override\n    public String providerKey(URL url) {\n        return url.getParameter(REGISTRY_CLUSTER_KEY);\n    }\n\n    @Override\n    public String consumerKey(URL url) {\n        return url.getParameter(REGISTRY_CLUSTER_KEY);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceDiscoveryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\n\n/**\n * This class is designed for compatibility purpose. When a specific registry type does not have counterpart service discovery provided,\n * the nop instance will be returned.\n */\npublic class DefaultServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory {\n    @Override\n    protected ServiceDiscovery createDiscovery(URL registryURL) {\n        return new NopServiceDiscovery(registryURL.getApplicationModel(), registryURL);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceInstance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.beans.Transient;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.ENDPOINTS;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;\n\n/**\n * The default implementation of {@link ServiceInstance}.\n *\n * @since 2.7.5\n */\npublic class DefaultServiceInstance implements ServiceInstance {\n\n    private static final long serialVersionUID = 1149677083747278100L;\n\n    private String rawAddress;\n\n    private String serviceName;\n\n    private String host;\n\n    private int port;\n\n    private boolean enabled = true;\n\n    private boolean healthy = true;\n\n    private Map<String, String> metadata = new HashMap<>();\n\n    private transient String address;\n    private transient MetadataInfo serviceMetadata;\n\n    /**\n     * used at runtime\n     */\n    private transient String registryCluster;\n\n    /**\n     * extendParams can be more flexible, but one single property uses less space\n     */\n    private transient Map<String, String> extendParams;\n\n    private transient List<Endpoint> endpoints;\n    private transient ApplicationModel applicationModel;\n    private transient ConcurrentHashMap<String, InstanceAddressURL> instanceAddressURL = new ConcurrentHashMap<>();\n\n    public DefaultServiceInstance() {}\n\n    public DefaultServiceInstance(DefaultServiceInstance other) {\n        this.serviceName = other.serviceName;\n        this.host = other.host;\n        this.port = other.port;\n        this.enabled = other.enabled;\n        this.healthy = other.healthy;\n        this.serviceMetadata = other.serviceMetadata;\n        this.registryCluster = other.registryCluster;\n        this.address = null;\n        this.metadata = new HashMap<>(other.metadata);\n        this.applicationModel = other.applicationModel;\n        this.extendParams = other.extendParams != null ? new HashMap<>(other.extendParams) : other.extendParams;\n        this.endpoints = other.endpoints != null ? new ArrayList<>(other.endpoints) : other.endpoints;\n    }\n\n    public DefaultServiceInstance(String serviceName, String host, Integer port, ApplicationModel applicationModel) {\n        if (port == null || port < 1) {\n            throw new IllegalArgumentException(\"The port value is illegal, the value is \" + port);\n        }\n        this.serviceName = serviceName;\n        this.host = host;\n        this.port = port;\n        setApplicationModel(applicationModel);\n    }\n\n    public DefaultServiceInstance(String serviceName, ApplicationModel applicationModel) {\n        this.serviceName = serviceName;\n        setApplicationModel(applicationModel);\n    }\n\n    public void setRawAddress(String rawAddress) {\n        this.rawAddress = rawAddress;\n    }\n\n    public void setServiceName(String serviceName) {\n        this.serviceName = serviceName;\n    }\n\n    public void setHost(String host) {\n        this.host = host;\n    }\n\n    @Override\n    public String getServiceName() {\n        return serviceName;\n    }\n\n    @Override\n    public String getHost() {\n        return host;\n    }\n\n    public void setPort(int port) {\n        this.port = port;\n    }\n\n    @Override\n    public int getPort() {\n        return port;\n    }\n\n    @Override\n    public String getAddress() {\n        if (address == null) {\n            address = getAddress(host, port);\n        }\n        return address;\n    }\n\n    private static String getAddress(String host, Integer port) {\n        return port != null && port <= 0 ? host : host + ':' + port;\n    }\n\n    @Override\n    public boolean isEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    @Override\n    public boolean isHealthy() {\n        return healthy;\n    }\n\n    public void setHealthy(boolean healthy) {\n        this.healthy = healthy;\n    }\n\n    @Override\n    public Map<String, String> getMetadata() {\n        return metadata;\n    }\n\n    @Override\n    public SortedMap<String, String> getSortedMetadata() {\n        return new TreeMap<>(getMetadata());\n    }\n\n    @Override\n    public String getRegistryCluster() {\n        return registryCluster;\n    }\n\n    @Override\n    public void setRegistryCluster(String registryCluster) {\n        this.registryCluster = registryCluster;\n    }\n\n    @Override\n    public Map<String, String> getExtendParams() {\n        if (extendParams == null) {\n            return Collections.emptyMap();\n        }\n        return extendParams;\n    }\n\n    @Override\n    public String getExtendParam(String key) {\n        if (extendParams == null) {\n            return null;\n        }\n        return extendParams.get(key);\n    }\n\n    @Override\n    public String putExtendParam(String key, String value) {\n        if (extendParams == null) {\n            extendParams = new HashMap<>();\n        }\n        return extendParams.put(key, value);\n    }\n\n    @Override\n    public String putExtendParamIfAbsent(String key, String value) {\n        if (extendParams == null) {\n            extendParams = new HashMap<>();\n        }\n        return extendParams.putIfAbsent(key, value);\n    }\n\n    @Override\n    public String removeExtendParam(String key) {\n        if (extendParams == null) {\n            return null;\n        }\n        return extendParams.remove(key);\n    }\n\n    public void setEndpoints(List<Endpoint> endpoints) {\n        this.endpoints = endpoints;\n    }\n\n    public List<Endpoint> getEndpoints() {\n        if (endpoints == null) {\n            endpoints = new LinkedList<>(JsonUtils.toJavaList(metadata.get(ENDPOINTS), Endpoint.class));\n        }\n        return endpoints;\n    }\n\n    public DefaultServiceInstance copyFrom(Endpoint endpoint) {\n        DefaultServiceInstance copyOfInstance = new DefaultServiceInstance(this);\n        copyOfInstance.setPort(endpoint.getPort());\n        return copyOfInstance;\n    }\n\n    public DefaultServiceInstance copyFrom(int port) {\n        DefaultServiceInstance copyOfInstance = new DefaultServiceInstance(this);\n        copyOfInstance.setPort(port);\n        return copyOfInstance;\n    }\n\n    @Override\n    public Map<String, String> getAllParams() {\n        if (extendParams == null) {\n            return metadata;\n        } else {\n            Map<String, String> allParams = new HashMap<>((int) ((metadata.size() + extendParams.size()) / 0.75f + 1));\n            allParams.putAll(metadata);\n            allParams.putAll(extendParams);\n            return allParams;\n        }\n    }\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    @Override\n    @Transient\n    public ApplicationModel getApplicationModel() {\n        return applicationModel;\n    }\n\n    public void setMetadata(Map<String, String> metadata) {\n        this.metadata = metadata;\n    }\n\n    @Override\n    public MetadataInfo getServiceMetadata() {\n        return serviceMetadata;\n    }\n\n    @Override\n    public void setServiceMetadata(MetadataInfo serviceMetadata) {\n        this.serviceMetadata = serviceMetadata;\n        this.instanceAddressURL.clear();\n    }\n\n    @Override\n    public InstanceAddressURL toURL(String protocol) {\n        return ConcurrentHashMapUtils.computeIfAbsent(\n                instanceAddressURL, protocol, key -> new InstanceAddressURL(this, serviceMetadata, protocol));\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (!(o instanceof DefaultServiceInstance)) {\n            return false;\n        }\n        DefaultServiceInstance that = (DefaultServiceInstance) o;\n        boolean equals = Objects.equals(getServiceName(), that.getServiceName())\n                && Objects.equals(getHost(), that.getHost())\n                && Objects.equals(getPort(), that.getPort());\n        for (Map.Entry<String, String> entry : this.getMetadata().entrySet()) {\n            if (entry.getKey().equals(EXPORTED_SERVICES_REVISION_PROPERTY_NAME)) {\n                continue;\n            }\n            if (entry.getValue() == null) {\n                equals = equals && (entry.getValue() == that.getMetadata().get(entry.getKey()));\n            } else {\n                equals = equals && entry.getValue().equals(that.getMetadata().get(entry.getKey()));\n            }\n        }\n\n        return equals;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = Objects.hash(getServiceName(), getHost(), getPort());\n        for (Map.Entry<String, String> entry : this.getMetadata().entrySet()) {\n            if (entry.getKey().equals(EXPORTED_SERVICES_REVISION_PROPERTY_NAME)) {\n                continue;\n            }\n            result = 31 * result\n                    + (entry.getValue() == null ? 0 : entry.getValue().hashCode());\n        }\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return rawAddress == null ? toFullString() : rawAddress;\n    }\n\n    public String toFullString() {\n        return \"DefaultServiceInstance{\" + \"serviceName='\"\n                + serviceName + '\\'' + \", host='\"\n                + host + '\\'' + \", port=\"\n                + port + \", enabled=\"\n                + enabled + \", healthy=\"\n                + healthy + \", metadata=\"\n                + metadata + '}';\n    }\n\n    public static class Endpoint {\n        int port;\n        String protocol;\n\n        public Endpoint() {}\n\n        public Endpoint(int port, String protocol) {\n            this.port = port;\n            this.protocol = protocol;\n        }\n\n        public int getPort() {\n            return port;\n        }\n\n        public void setPort(int port) {\n            this.port = port;\n        }\n\n        public String getProtocol() {\n            return protocol;\n        }\n\n        public void setProtocol(String protocol) {\n            this.protocol = protocol;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/InstanceAddressURL.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.url.component.URLAddress;\nimport org.apache.dubbo.common.url.component.URLParam;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\nimport static org.apache.dubbo.common.utils.StringUtils.isEquals;\n\npublic class InstanceAddressURL extends URL {\n    private final ServiceInstance instance;\n    private final MetadataInfo metadataInfo;\n\n    // cached numbers\n    private transient volatile Set<String> providerFirstParams;\n    // one instance address url serves only one protocol.\n    private final transient String protocol;\n\n    protected InstanceAddressURL() {\n        this(null, null, null);\n    }\n\n    public InstanceAddressURL(ServiceInstance instance, MetadataInfo metadataInfo) {\n        this.instance = instance;\n        this.metadataInfo = metadataInfo;\n        this.protocol = DUBBO;\n    }\n\n    public InstanceAddressURL(ServiceInstance instance, MetadataInfo metadataInfo, String protocol) {\n        this.instance = instance;\n        this.metadataInfo = metadataInfo;\n        this.protocol = protocol;\n    }\n\n    public ServiceInstance getInstance() {\n        return instance;\n    }\n\n    public MetadataInfo getMetadataInfo() {\n        return metadataInfo;\n    }\n\n    @Override\n    public String getServiceInterface() {\n        return RpcContext.getServiceContext().getInterfaceName();\n    }\n\n    @Override\n    public String getGroup() {\n        return RpcContext.getServiceContext().getGroup();\n    }\n\n    @Override\n    public String getVersion() {\n        return RpcContext.getServiceContext().getVersion();\n    }\n\n    @Override\n    public String getProtocol() {\n        return protocol;\n    }\n\n    @Override\n    public String getProtocolServiceKey() {\n        // if protocol is not specified on consumer side, return serviceKey.\n        URL consumerURL = RpcContext.getServiceContext().getConsumerUrl();\n        String consumerProtocol = consumerURL == null ? null : consumerURL.getProtocol();\n        if (isEquals(consumerProtocol, CONSUMER)) {\n            return RpcContext.getServiceContext().getServiceKey();\n        }\n        // if protocol is specified on consumer side, return accurate protocolServiceKey\n        else {\n            return RpcContext.getServiceContext().getProtocolServiceKey();\n        }\n    }\n\n    @Override\n    public String getServiceKey() {\n        return RpcContext.getServiceContext().getServiceKey();\n    }\n\n    @Override\n    public URL setProtocol(String protocol) {\n        return new ServiceConfigURL(\n                protocol, getUsername(), getPassword(), getHost(), getPort(), getPath(), getParameters(), attributes);\n    }\n\n    @Override\n    public URL setHost(String host) {\n        return new ServiceConfigURL(\n                getProtocol(), getUsername(), getPassword(), host, getPort(), getPath(), getParameters(), attributes);\n    }\n\n    @Override\n    public URL setPort(int port) {\n        return new ServiceConfigURL(\n                getProtocol(), getUsername(), getPassword(), getHost(), port, getPath(), getParameters(), attributes);\n    }\n\n    @Override\n    public URL setPath(String path) {\n        return new ServiceConfigURL(\n                getProtocol(), getUsername(), getPassword(), getHost(), getPort(), path, getParameters(), attributes);\n    }\n\n    @Override\n    public String getAddress() {\n        return instance.getAddress();\n    }\n\n    @Override\n    public String getHost() {\n        return instance.getHost();\n    }\n\n    @Override\n    public int getPort() {\n        return instance.getPort();\n    }\n\n    @Override\n    public String getIp() {\n        return instance.getHost();\n    }\n\n    @Override\n    public String getRemoteApplication() {\n        return instance.getServiceName();\n    }\n\n    @Override\n    public String getSide() {\n        return CONSUMER_SIDE;\n    }\n\n    @Override\n    public String getPath() {\n        MetadataInfo.ServiceInfo serviceInfo = null;\n        String protocolServiceKey = getProtocolServiceKey();\n        if (StringUtils.isNotEmpty(protocolServiceKey)) {\n            serviceInfo = getServiceInfo(protocolServiceKey);\n        }\n        if (serviceInfo == null) {\n            return getServiceInterface();\n        }\n        return serviceInfo.getPath();\n    }\n\n    @Override\n    public String getOriginalParameter(String key) {\n        if (VERSION_KEY.equals(key)) {\n            return getVersion();\n        } else if (GROUP_KEY.equals(key)) {\n            return getGroup();\n        } else if (INTERFACE_KEY.equals(key)) {\n            return getServiceInterface();\n        } else if (REMOTE_APPLICATION_KEY.equals(key)) {\n            return instance.getServiceName();\n        } else if (SIDE_KEY.equals(key)) {\n            return getSide();\n        }\n\n        String protocolServiceKey = getProtocolServiceKey();\n        if (isEmpty(protocolServiceKey)) {\n            return getInstanceParameter(key);\n        }\n        return getServiceParameter(protocolServiceKey, key);\n    }\n\n    @Override\n    public String getParameter(String key) {\n        if (VERSION_KEY.equals(key)) {\n            return getVersion();\n        } else if (GROUP_KEY.equals(key)) {\n            return getGroup();\n        } else if (INTERFACE_KEY.equals(key)) {\n            return getServiceInterface();\n        } else if (REMOTE_APPLICATION_KEY.equals(key)) {\n            return instance.getServiceName();\n        } else if (SIDE_KEY.equals(key)) {\n            return getSide();\n        }\n\n        if (consumerParamFirst(key)) {\n            URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n            if (consumerUrl != null) {\n                String v = consumerUrl.getParameter(key);\n                if (StringUtils.isNotEmpty(v)) {\n                    return v;\n                }\n            }\n        }\n\n        String protocolServiceKey = getProtocolServiceKey();\n        if (isEmpty(protocolServiceKey)) {\n            return getInstanceParameter(key);\n        }\n        return getServiceParameter(protocolServiceKey, key);\n    }\n\n    @Override\n    public String getOriginalServiceParameter(String service, String key) {\n        if (metadataInfo != null) {\n            String value = metadataInfo.getParameter(key, service);\n            if (StringUtils.isNotEmpty(value)) {\n                return value;\n            }\n        }\n\n        return getInstanceParameter(key);\n    }\n\n    @Override\n    public String getServiceParameter(String service, String key) {\n        if (consumerParamFirst(key)) {\n            URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n            if (consumerUrl != null) {\n                String v = consumerUrl.getServiceParameter(service, key);\n                if (StringUtils.isNotEmpty(v)) {\n                    return v;\n                }\n            }\n        }\n\n        if (metadataInfo != null) {\n            String value = metadataInfo.getParameter(key, service);\n            if (StringUtils.isNotEmpty(value)) {\n                return value;\n            }\n        }\n\n        return getInstanceParameter(key);\n    }\n\n    /**\n     * method parameter only exists in ServiceInfo\n     *\n     * @param method\n     * @param key\n     * @return\n     */\n    @Override\n    public String getServiceMethodParameter(String protocolServiceKey, String method, String key) {\n        if (consumerParamFirst(key)) {\n            URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n            if (consumerUrl != null) {\n                String v = consumerUrl.getServiceMethodParameter(protocolServiceKey, method, key);\n                if (StringUtils.isNotEmpty(v)) {\n                    return v;\n                }\n            }\n        }\n\n        MetadataInfo.ServiceInfo serviceInfo = getServiceInfo(protocolServiceKey);\n        if (null == serviceInfo) {\n            return getParameter(key);\n        }\n\n        String value = serviceInfo.getMethodParameter(method, key, null);\n        if (StringUtils.isNotEmpty(value)) {\n            return value;\n        }\n        return getParameter(key);\n    }\n\n    @Override\n    public String getMethodParameter(String method, String key) {\n        if (consumerParamFirst(key)) {\n            URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n            if (consumerUrl != null) {\n                String v = consumerUrl.getMethodParameter(method, key);\n                if (StringUtils.isNotEmpty(v)) {\n                    return v;\n                }\n            }\n        }\n\n        String protocolServiceKey = getProtocolServiceKey();\n        if (isEmpty(protocolServiceKey)) {\n            return null;\n        }\n        return getServiceMethodParameter(protocolServiceKey, method, key);\n    }\n\n    /**\n     * method parameter only exists in ServiceInfo\n     *\n     * @param method\n     * @param key\n     * @return\n     */\n    @Override\n    public boolean hasServiceMethodParameter(String protocolServiceKey, String method, String key) {\n        if (consumerParamFirst(key)) {\n            URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n            if (consumerUrl != null) {\n                if (consumerUrl.hasServiceMethodParameter(protocolServiceKey, method, key)) {\n                    return true;\n                }\n            }\n        }\n\n        MetadataInfo.ServiceInfo serviceInfo = getServiceInfo(protocolServiceKey);\n\n        if (isEmpty(method)) {\n            String suffix = \".\" + key;\n            for (String fullKey : getParameters().keySet()) {\n                if (fullKey.endsWith(suffix)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n        if (isEmpty(key)) {\n            String prefix = method + \".\";\n            for (String fullKey : getParameters().keySet()) {\n                if (fullKey.startsWith(prefix)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        if (null == serviceInfo) {\n            return false;\n        }\n\n        return serviceInfo.hasMethodParameter(method, key);\n    }\n\n    @Override\n    public boolean hasMethodParameter(String method, String key) {\n        if (consumerParamFirst(key)) {\n            URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n            if (consumerUrl != null) {\n                if (consumerUrl.hasMethodParameter(method, key)) {\n                    return true;\n                }\n            }\n        }\n\n        String protocolServiceKey = getProtocolServiceKey();\n        if (isEmpty(protocolServiceKey)) {\n            return false;\n        }\n        return hasServiceMethodParameter(protocolServiceKey, method, key);\n    }\n\n    /**\n     * method parameter only exists in ServiceInfo\n     *\n     * @param method\n     * @return\n     */\n    @Override\n    public boolean hasServiceMethodParameter(String protocolServiceKey, String method) {\n        URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n        if (consumerUrl != null) {\n            if (consumerUrl.hasServiceMethodParameter(protocolServiceKey, method)) {\n                return true;\n            }\n        }\n\n        MetadataInfo.ServiceInfo serviceInfo = getServiceInfo(protocolServiceKey);\n        if (null == serviceInfo) {\n            return false;\n        }\n\n        return serviceInfo.hasMethodParameter(method);\n    }\n\n    @Override\n    public boolean hasMethodParameter(String method) {\n        URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n        if (consumerUrl != null) {\n            if (consumerUrl.hasMethodParameter(method)) {\n                return true;\n            }\n        }\n\n        String protocolServiceKey = getProtocolServiceKey();\n        if (isEmpty(protocolServiceKey)) {\n            return false;\n        }\n        return hasServiceMethodParameter(protocolServiceKey, method);\n    }\n\n    @Override\n    public Map<String, String> getOriginalServiceParameters(String protocolServiceKey) {\n        Map<String, String> instanceParams = getInstance().getAllParams();\n        Map<String, String> metadataParams =\n                (metadataInfo == null ? new HashMap<>() : metadataInfo.getParameters(protocolServiceKey));\n        int i = instanceParams == null ? 0 : instanceParams.size();\n        int j = metadataParams == null ? 0 : metadataParams.size();\n        Map<String, String> params = new HashMap<>((int) ((i + j) / 0.75) + 1);\n        if (instanceParams != null) {\n            params.putAll(instanceParams);\n        }\n        if (metadataParams != null) {\n            params.putAll(metadataParams);\n        }\n\n        return params;\n    }\n\n    /**\n     * Avoid calling this method in RPC call.\n     *\n     * @return\n     */\n    @Override\n    public Map<String, String> getServiceParameters(String protocolServiceKey) {\n        Map<String, String> instanceParams = getInstance().getAllParams();\n        Map<String, String> metadataParams =\n                (metadataInfo == null ? new HashMap<>() : metadataInfo.getParameters(protocolServiceKey));\n        int i = instanceParams == null ? 0 : instanceParams.size();\n        int j = metadataParams == null ? 0 : metadataParams.size();\n        Map<String, String> params = new HashMap<>((int) ((i + j) / 0.75) + 1);\n        if (instanceParams != null) {\n            params.putAll(instanceParams);\n        }\n        if (metadataParams != null) {\n            params.putAll(metadataParams);\n        }\n\n        URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n        if (consumerUrl != null) {\n            Map<String, String> consumerParams = new HashMap<>(consumerUrl.getParameters());\n            if (CollectionUtils.isNotEmpty(providerFirstParams)) {\n                providerFirstParams.forEach(consumerParams::remove);\n            }\n            params.putAll(consumerParams);\n        }\n        return params;\n    }\n\n    @Override\n    public Map<String, String> getOriginalParameters() {\n        String protocolServiceKey = getProtocolServiceKey();\n        if (isEmpty(protocolServiceKey)) {\n            return getInstance().getAllParams();\n        }\n        return getOriginalServiceParameters(protocolServiceKey);\n    }\n\n    @Override\n    public Map<String, String> getParameters() {\n        String protocolServiceKey = getProtocolServiceKey();\n        if (isEmpty(protocolServiceKey)) {\n            return getInstance().getAllParams();\n        }\n        return getServiceParameters(protocolServiceKey);\n    }\n\n    @Override\n    public URL addParameter(String key, String value) {\n        if (isEmpty(key) || isEmpty(value)) {\n            return this;\n        }\n\n        getInstance().putExtendParam(key, value);\n        return this;\n    }\n\n    @Override\n    public URL addParameterIfAbsent(String key, String value) {\n        if (isEmpty(key) || isEmpty(value)) {\n            return this;\n        }\n\n        getInstance().putExtendParamIfAbsent(key, value);\n        return this;\n    }\n\n    public URL addServiceParameter(String protocolServiceKey, String key, String value) {\n        if (isEmpty(key) || isEmpty(value)) {\n            return this;\n        }\n\n        MetadataInfo.ServiceInfo serviceInfo = getServiceInfo(protocolServiceKey);\n        if (null != serviceInfo) {\n            serviceInfo.addParameter(key, value);\n        }\n\n        return this;\n    }\n\n    public URL addServiceParameterIfAbsent(String protocolServiceKey, String key, String value) {\n        if (isEmpty(key) || isEmpty(value)) {\n            return this;\n        }\n\n        MetadataInfo.ServiceInfo serviceInfo = getServiceInfo(protocolServiceKey);\n        if (null != serviceInfo) {\n            serviceInfo.addParameterIfAbsent(key, value);\n        }\n\n        return this;\n    }\n\n    public URL addConsumerParams(String protocolServiceKey, Map<String, String> params) {\n        MetadataInfo.ServiceInfo serviceInfo = getServiceInfo(protocolServiceKey);\n        if (null != serviceInfo) {\n            serviceInfo.addConsumerParams(params);\n        }\n\n        return this;\n    }\n\n    /**\n     * Gets method level value of the specified key.\n     *\n     * @param key\n     * @return\n     */\n    @Override\n    public String getAnyMethodParameter(String key) {\n        if (consumerParamFirst(key)) {\n            URL consumerUrl = RpcContext.getServiceContext().getConsumerUrl();\n            if (consumerUrl != null) {\n                String v = consumerUrl.getAnyMethodParameter(key);\n                if (StringUtils.isNotEmpty(v)) {\n                    return v;\n                }\n            }\n        }\n\n        String suffix = \".\" + key;\n        String protocolServiceKey = getProtocolServiceKey();\n        if (StringUtils.isNotEmpty(protocolServiceKey)) {\n            MetadataInfo.ServiceInfo serviceInfo = getServiceInfo(protocolServiceKey);\n            if (null == serviceInfo) {\n                return null;\n            }\n\n            for (String fullKey : serviceInfo.getAllParams().keySet()) {\n                if (fullKey.endsWith(suffix)) {\n                    return getParameter(fullKey);\n                }\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public URLParam getUrlParam() {\n        throw new UnsupportedOperationException(\"URLParam is replaced with MetadataInfo in instance url\");\n    }\n\n    @Override\n    public URLAddress getUrlAddress() {\n        throw new UnsupportedOperationException(\"URLAddress is replaced with ServiceInstance in instance url\");\n    }\n\n    private MetadataInfo.ServiceInfo getServiceInfo(String protocolServiceKey) {\n        return metadataInfo.getValidServiceInfo(protocolServiceKey);\n    }\n\n    private String getInstanceParameter(String key) {\n        String value = this.instance.getMetadata().get(key);\n        if (StringUtils.isNotEmpty(value)) {\n            return value;\n        }\n        return this.instance.getExtendParam(key);\n    }\n\n    private Map<String, String> getInstanceMetadata() {\n        return this.instance.getMetadata();\n    }\n\n    @Override\n    public FrameworkModel getOrDefaultFrameworkModel() {\n        return instance.getOrDefaultApplicationModel().getFrameworkModel();\n    }\n\n    @Override\n    public ApplicationModel getOrDefaultApplicationModel() {\n        return instance.getOrDefaultApplicationModel();\n    }\n\n    @Override\n    public ApplicationModel getApplicationModel() {\n        return instance.getApplicationModel();\n    }\n\n    @Override\n    public ScopeModel getScopeModel() {\n        return Optional.ofNullable(RpcContext.getServiceContext().getConsumerUrl())\n                .map(URL::getScopeModel)\n                .orElse(super.getScopeModel());\n    }\n\n    @Override\n    public ServiceModel getServiceModel() {\n        return RpcContext.getServiceContext().getConsumerUrl().getServiceModel();\n    }\n\n    public Set<String> getProviderFirstParams() {\n        return providerFirstParams;\n    }\n\n    public void setProviderFirstParams(Set<String> providerFirstParams) {\n        this.providerFirstParams = providerFirstParams;\n    }\n\n    private boolean consumerParamFirst(String key) {\n        if (CollectionUtils.isNotEmpty(providerFirstParams)) {\n            return !providerFirstParams.contains(key);\n        } else {\n            return true;\n        }\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        // instance metadata equals\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof InstanceAddressURL)) {\n            return false;\n        }\n\n        InstanceAddressURL that = (InstanceAddressURL) obj;\n\n        return this.getInstance().equals(that.getInstance());\n    }\n\n    @Override\n    public int hashCode() {\n        return getInstance().hashCode();\n    }\n\n    @Override\n    public String toString() {\n        if (instance == null) {\n            return \"{}\";\n        }\n        if (metadataInfo == null) {\n            return instance.toString();\n        }\n\n        String protocolServiceKey = getProtocolServiceKey();\n        if (StringUtils.isNotEmpty(protocolServiceKey)) {\n            return instance.toString() + \", \" + metadataInfo.getServiceString(protocolServiceKey);\n        }\n\n        return instance.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/NopServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.List;\nimport java.util.Set;\n\npublic class NopServiceDiscovery extends AbstractServiceDiscovery {\n    public NopServiceDiscovery(String serviceName, URL registryURL) {\n        super(serviceName, registryURL);\n    }\n\n    public NopServiceDiscovery(ApplicationModel applicationModel, URL registryURL) {\n        super(applicationModel, registryURL);\n    }\n\n    @Override\n    public void doRegister(ServiceInstance serviceInstance) throws RuntimeException {}\n\n    @Override\n    public void doUnregister(ServiceInstance serviceInstance) {}\n\n    @Override\n    public void doDestroy() throws Exception {}\n\n    @Override\n    public Set<String> getServices() {\n        return null;\n    }\n\n    @Override\n    public List<ServiceInstance> getInstances(String serviceName) throws NullPointerException {\n        return null;\n    }\n\n    @Override\n    public boolean isAvailable() {\n        // NopServiceDiscovery is designed for compatibility, check availability is meaningless, just return true\n        return true;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/OverrideInstanceAddressURL.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.URLAddress;\nimport org.apache.dubbo.common.url.component.URLParam;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ServiceModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\npublic class OverrideInstanceAddressURL extends InstanceAddressURL {\n    private static final long serialVersionUID = 1373220432794558426L;\n\n    private final URLParam overrideParams;\n    private final InstanceAddressURL originUrl;\n\n    public OverrideInstanceAddressURL(InstanceAddressURL originUrl) {\n        this.originUrl = originUrl;\n        this.overrideParams = URLParam.parse(\"\");\n    }\n\n    public OverrideInstanceAddressURL(InstanceAddressURL originUrl, URLParam overrideParams) {\n        this.originUrl = originUrl;\n        this.overrideParams = overrideParams;\n    }\n\n    @Override\n    public ServiceInstance getInstance() {\n        return originUrl.getInstance();\n    }\n\n    @Override\n    public MetadataInfo getMetadataInfo() {\n        return originUrl.getMetadataInfo();\n    }\n\n    @Override\n    public String getServiceInterface() {\n        return originUrl.getServiceInterface();\n    }\n\n    @Override\n    public String getGroup() {\n        return originUrl.getGroup();\n    }\n\n    @Override\n    public String getVersion() {\n        return originUrl.getVersion();\n    }\n\n    @Override\n    public String getProtocol() {\n        return originUrl.getProtocol();\n    }\n\n    @Override\n    public String getProtocolServiceKey() {\n        return originUrl.getProtocolServiceKey();\n    }\n\n    @Override\n    public String getServiceKey() {\n        return originUrl.getServiceKey();\n    }\n\n    @Override\n    public String getAddress() {\n        return originUrl.getAddress();\n    }\n\n    @Override\n    public String getHost() {\n        return originUrl.getHost();\n    }\n\n    @Override\n    public int getPort() {\n        return originUrl.getPort();\n    }\n\n    @Override\n    public String getIp() {\n        return originUrl.getIp();\n    }\n\n    @Override\n    public String getPath() {\n        return originUrl.getPath();\n    }\n\n    @Override\n    public String getParameter(String key) {\n        String overrideParam = overrideParams.getParameter(key);\n        return StringUtils.isNotEmpty(overrideParam) ? overrideParam : originUrl.getParameter(key);\n    }\n\n    @Override\n    public String getServiceParameter(String service, String key) {\n        String overrideParam = overrideParams.getParameter(key);\n        return StringUtils.isNotEmpty(overrideParam) ? overrideParam : originUrl.getServiceParameter(service, key);\n    }\n\n    @Override\n    public String getServiceMethodParameter(String protocolServiceKey, String method, String key) {\n        String overrideParam = overrideParams.getMethodParameter(method, key);\n        return StringUtils.isNotEmpty(overrideParam)\n                ? overrideParam\n                : originUrl.getServiceMethodParameter(protocolServiceKey, method, key);\n    }\n\n    @Override\n    public String getMethodParameter(String method, String key) {\n        String overrideParam = overrideParams.getMethodParameter(method, key);\n        return StringUtils.isNotEmpty(overrideParam) ? overrideParam : originUrl.getMethodParameter(method, key);\n    }\n\n    @Override\n    public boolean hasServiceMethodParameter(String protocolServiceKey, String method, String key) {\n        return StringUtils.isNotEmpty(overrideParams.getMethodParameter(method, key))\n                || originUrl.hasServiceMethodParameter(protocolServiceKey, method, key);\n    }\n\n    @Override\n    public boolean hasMethodParameter(String method, String key) {\n        return StringUtils.isNotEmpty(overrideParams.getMethodParameter(method, key))\n                || originUrl.hasMethodParameter(method, key);\n    }\n\n    @Override\n    public boolean hasServiceMethodParameter(String protocolServiceKey, String method) {\n        return overrideParams.hasMethodParameter(method)\n                || originUrl.hasServiceMethodParameter(protocolServiceKey, method);\n    }\n\n    @Override\n    public boolean hasMethodParameter(String method) {\n        return overrideParams.hasMethodParameter(method) || originUrl.hasMethodParameter(method);\n    }\n\n    @Override\n    public Map<String, String> getServiceParameters(String protocolServiceKey) {\n        Map<String, String> parameters = originUrl.getServiceParameters(protocolServiceKey);\n        Map<String, String> overrideParameters = overrideParams.getParameters();\n        Map<String, String> result = new HashMap<>((int) (parameters.size() + overrideParameters.size() / 0.75f) + 1);\n        result.putAll(parameters);\n        result.putAll(overrideParameters);\n        return result;\n    }\n\n    @Override\n    public Map<String, String> getParameters() {\n        Map<String, String> parameters = originUrl.getParameters();\n        Map<String, String> overrideParameters = overrideParams.getParameters();\n        Map<String, String> result = new HashMap<>((int) (parameters.size() + overrideParameters.size() / 0.75f) + 1);\n        result.putAll(parameters);\n        result.putAll(overrideParameters);\n        return result;\n    }\n\n    @Override\n    public URL addParameter(String key, String value) {\n        return new OverrideInstanceAddressURL(originUrl, overrideParams.addParameter(key, value));\n    }\n\n    @Override\n    public URL addParameterIfAbsent(String key, String value) {\n        return new OverrideInstanceAddressURL(originUrl, overrideParams.addParameterIfAbsent(key, value));\n    }\n\n    @Override\n    public URL addServiceParameter(String protocolServiceKey, String key, String value) {\n        return originUrl.addServiceParameter(protocolServiceKey, key, value);\n    }\n\n    @Override\n    public URL addServiceParameterIfAbsent(String protocolServiceKey, String key, String value) {\n        return originUrl.addServiceParameterIfAbsent(protocolServiceKey, key, value);\n    }\n\n    @Override\n    public URL addConsumerParams(String protocolServiceKey, Map<String, String> params) {\n        return originUrl.addConsumerParams(protocolServiceKey, params);\n    }\n\n    @Override\n    public String getAnyMethodParameter(String key) {\n        String overrideParam = overrideParams.getAnyMethodParameter(key);\n        return StringUtils.isNotEmpty(overrideParam) ? overrideParam : originUrl.getAnyMethodParameter(key);\n    }\n\n    @Override\n    public URL addParameters(Map<String, String> parameters) {\n        return new OverrideInstanceAddressURL(originUrl, overrideParams.addParameters(parameters));\n    }\n\n    @Override\n    public URL addParametersIfAbsent(Map<String, String> parameters) {\n        return new OverrideInstanceAddressURL(originUrl, overrideParams.addParametersIfAbsent(parameters));\n    }\n\n    @Override\n    public URLParam getUrlParam() {\n        return originUrl.getUrlParam();\n    }\n\n    @Override\n    public URLAddress getUrlAddress() {\n        return originUrl.getUrlAddress();\n    }\n\n    public URLParam getOverrideParams() {\n        return overrideParams;\n    }\n\n    @Override\n    public String getRemoteApplication() {\n        return originUrl.getRemoteApplication();\n    }\n\n    @Override\n    public String getSide() {\n        return originUrl.getSide();\n    }\n\n    @Override\n    public ScopeModel getScopeModel() {\n        return originUrl.getScopeModel();\n    }\n\n    @Override\n    public FrameworkModel getOrDefaultFrameworkModel() {\n        return originUrl.getOrDefaultFrameworkModel();\n    }\n\n    @Override\n    public ApplicationModel getOrDefaultApplicationModel() {\n        return originUrl.getOrDefaultApplicationModel();\n    }\n\n    @Override\n    public ApplicationModel getApplicationModel() {\n        return originUrl.getApplicationModel();\n    }\n\n    @Override\n    public ModuleModel getOrDefaultModuleModel() {\n        return originUrl.getOrDefaultModuleModel();\n    }\n\n    @Override\n    public ServiceModel getServiceModel() {\n        return originUrl.getServiceModel();\n    }\n\n    @Override\n    public Set<String> getProviderFirstParams() {\n        return originUrl.getProviderFirstParams();\n    }\n\n    @Override\n    public void setProviderFirstParams(Set<String> providerFirstParams) {\n        originUrl.setProviderFirstParams(providerFirstParams);\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        if (!super.equals(o)) return false;\n        OverrideInstanceAddressURL that = (OverrideInstanceAddressURL) o;\n        return Objects.equals(overrideParams, that.overrideParams) && Objects.equals(originUrl, that.originUrl);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), overrideParams, originUrl);\n    }\n\n    @Override\n    public String toString() {\n        return originUrl.toString() + \", overrideParams: \" + overrideParams.toString();\n    }\n\n    private Object readResolve() {\n        // create a new object from the deserialized one\n        return new OverrideInstanceAddressURL(this.originUrl, this.overrideParams);\n    }\n\n    @Override\n    protected OverrideInstanceAddressURL newURL(URLAddress urlAddress, URLParam urlParam) {\n        return new OverrideInstanceAddressURL(originUrl, overrideParams);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ReflectionBasedServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.InstanceMetadataChangedListener;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.metadata.RevisionResolver;\nimport org.apache.dubbo.registry.Constants;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.registry.client.metadata.MetadataServiceDelegation;\nimport org.apache.dubbo.registry.client.metadata.MetadataUtils;\nimport org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\nimport org.apache.dubbo.rpc.service.Destroyable;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_NOTIFY_EVENT;\n\npublic class ReflectionBasedServiceDiscovery extends AbstractServiceDiscovery {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    /**\n     * Echo check if consumer is still work\n     * echo task may take a lot of time when consumer offline, create a new ScheduledThreadPool\n     */\n    private final ScheduledExecutorService echoCheckExecutor =\n            Executors.newScheduledThreadPool(1, new NamedThreadFactory(\"Dubbo-Registry-EchoCheck-Consumer\"));\n\n    // =================================== Provider side =================================== //\n    /**\n     * Local {@link ServiceInstance} Metadata's revision\n     */\n    private String lastMetadataRevision;\n\n    // =================================== Consumer side =================================== //\n\n    /**\n     * Local Cache of {@link ServiceInstance} Metadata\n     * <p>\n     * Key - {@link ServiceInstance} ID ( usually ip + port )\n     * Value - Json processed metadata string\n     */\n    private final ConcurrentHashMap<String, String> metadataMap = new ConcurrentHashMap<>();\n\n    /**\n     * Local Cache of {@link ServiceInstance}\n     * <p>\n     * Key - Service Name\n     * Value - List {@link ServiceInstance}\n     */\n    private final ConcurrentHashMap<String, List<ServiceInstance>> cachedServiceInstances = new ConcurrentHashMap<>();\n\n    private final MetadataServiceDelegation metadataService;\n\n    public ConcurrentMap<String, MetadataService> metadataServiceProxies = new ConcurrentHashMap<>();\n\n    /**\n     * Local Cache of Service's {@link ServiceInstance} list revision,\n     * used to check if {@link ServiceInstance} list has been updated\n     * <p>\n     * Key - ServiceName\n     * Value - a revision calculate from {@link List} of {@link ServiceInstance}\n     */\n    private final ConcurrentHashMap<String, String> serviceInstanceRevisionMap = new ConcurrentHashMap<>();\n\n    public ReflectionBasedServiceDiscovery(ApplicationModel applicationModel, URL registryURL) {\n        super(applicationModel, registryURL);\n        long echoPollingCycle =\n                registryURL.getParameter(Constants.ECHO_POLLING_CYCLE_KEY, Constants.DEFAULT_ECHO_POLLING_CYCLE);\n\n        this.metadataService = applicationModel.getBeanFactory().getOrRegisterBean(MetadataServiceDelegation.class);\n\n        // Echo check: test if consumer is offline, remove MetadataChangeListener,\n        // reduce the probability of failure when metadata update\n        echoCheckExecutor.scheduleAtFixedRate(\n                () -> {\n                    Map<String, InstanceMetadataChangedListener> listenerMap =\n                            metadataService.getInstanceMetadataChangedListenerMap();\n                    Iterator<Map.Entry<String, InstanceMetadataChangedListener>> iterator =\n                            listenerMap.entrySet().iterator();\n\n                    while (iterator.hasNext()) {\n                        Map.Entry<String, InstanceMetadataChangedListener> entry = iterator.next();\n                        try {\n                            entry.getValue().echo(CommonConstants.DUBBO);\n                        } catch (RpcException e) {\n                            if (logger.isInfoEnabled()) {\n                                logger.info(\n                                        \"Send echo message to consumer error. Possible cause: consumer is offline.\");\n                            }\n                            iterator.remove();\n                        }\n                    }\n                },\n                echoPollingCycle,\n                echoPollingCycle,\n                TimeUnit.MILLISECONDS);\n    }\n\n    public void doInitialize(URL registryURL) {}\n\n    @Override\n    public void doDestroy() throws Exception {\n        metadataMap.clear();\n        serviceInstanceRevisionMap.clear();\n        echoCheckExecutor.shutdown();\n    }\n\n    private void updateInstanceMetadata(ServiceInstance serviceInstance) {\n        String metadataString = JsonUtils.toJson(serviceInstance.getMetadata());\n        String metadataRevision = RevisionResolver.calRevision(metadataString);\n\n        // check if metadata updated\n        if (!metadataRevision.equalsIgnoreCase(lastMetadataRevision)) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Update Service Instance Metadata of DNS registry. Newer metadata: \" + metadataString);\n            }\n\n            lastMetadataRevision = metadataRevision;\n\n            // save the newest metadata to local\n            metadataService.exportInstanceMetadata(metadataString);\n\n            // notify to consumer\n            Map<String, InstanceMetadataChangedListener> listenerMap =\n                    metadataService.getInstanceMetadataChangedListenerMap();\n            Iterator<Map.Entry<String, InstanceMetadataChangedListener>> iterator =\n                    listenerMap.entrySet().iterator();\n\n            while (iterator.hasNext()) {\n                Map.Entry<String, InstanceMetadataChangedListener> entry = iterator.next();\n                try {\n                    entry.getValue().onEvent(metadataString);\n                } catch (RpcException e) {\n                    // 1-7 - Failed to notify registry event.\n                    // The updating of metadata to consumer is a type of registry event.\n\n                    logger.warn(\n                            REGISTRY_FAILED_NOTIFY_EVENT,\n                            \"consumer is offline\",\n                            \"\",\n                            \"Notify to consumer error, removing listener.\");\n\n                    // remove listener if consumer is offline\n                    iterator.remove();\n                }\n            }\n        }\n    }\n\n    @Override\n    public void doRegister(ServiceInstance serviceInstance) throws RuntimeException {\n        updateInstanceMetadata(serviceInstance);\n    }\n\n    @Override\n    public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException {\n        // notify empty message to consumer\n        metadataService.exportInstanceMetadata(\"\");\n        metadataService.getInstanceMetadataChangedListenerMap().forEach((consumerId, listener) -> listener.onEvent(\"\"));\n        metadataService.getInstanceMetadataChangedListenerMap().clear();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public final void fillServiceInstance(DefaultServiceInstance serviceInstance) {\n        String hostId = serviceInstance.getAddress();\n        if (metadataMap.containsKey(hostId)) {\n            // Use cached metadata.\n            // Metadata will be updated by provider callback\n\n            String metadataString = metadataMap.get(hostId);\n            serviceInstance.setMetadata(JsonUtils.toJavaObject(metadataString, Map.class));\n        } else {\n            // refer from MetadataUtils, this proxy is different from the one used to refer exportedURL\n            MetadataService metadataService = getMetadataServiceProxy(serviceInstance);\n\n            String consumerId = ScopeModelUtil.getApplicationModel(registryURL.getScopeModel())\n                            .getApplicationName()\n                    + NetUtils.getLocalHost();\n            String metadata = metadataService.getAndListenInstanceMetadata(consumerId, metadataString -> {\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"Receive callback: \" + metadataString + serviceInstance);\n                }\n                if (StringUtils.isEmpty(metadataString)) {\n                    // provider is shutdown\n                    metadataMap.remove(hostId);\n                } else {\n                    metadataMap.put(hostId, metadataString);\n                }\n            });\n            metadataMap.put(hostId, metadata);\n            serviceInstance.setMetadata(JsonUtils.toJavaObject(metadata, Map.class));\n        }\n    }\n\n    public final void notifyListener(\n            String serviceName, ServiceInstancesChangedListener listener, List<ServiceInstance> instances) {\n        String serviceInstanceRevision = RevisionResolver.calRevision(JsonUtils.toJson(instances));\n        boolean changed = !serviceInstanceRevision.equalsIgnoreCase(\n                serviceInstanceRevisionMap.put(serviceName, serviceInstanceRevision));\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Service changed event received (possibly because of DNS polling). \"\n                    + \"Service Instance changed: \" + changed + \" Service Name: \" + serviceName);\n        }\n\n        if (changed) {\n            List<ServiceInstance> oldServiceInstances =\n                    cachedServiceInstances.getOrDefault(serviceName, new LinkedList<>());\n\n            // remove expired invoker\n            Set<ServiceInstance> allServiceInstances = new HashSet<>(oldServiceInstances.size() + instances.size());\n            allServiceInstances.addAll(oldServiceInstances);\n            allServiceInstances.addAll(instances);\n\n            oldServiceInstances.forEach(allServiceInstances::remove);\n\n            allServiceInstances.forEach(this::destroyMetadataServiceProxy);\n\n            cachedServiceInstances.put(serviceName, instances);\n            listener.onEvent(new ServiceInstancesChangedEvent(serviceName, instances));\n        }\n    }\n\n    @Override\n    public Set<String> getServices() {\n        return Collections.emptySet();\n    }\n\n    @Override\n    public List<ServiceInstance> getInstances(String serviceName) throws NullPointerException {\n        return Collections.emptyList();\n    }\n\n    private String computeKey(ServiceInstance serviceInstance) {\n        return serviceInstance.getServiceName() + \"##\" + serviceInstance.getAddress() + \"##\"\n                + ServiceInstanceMetadataUtils.getExportedServicesRevision(serviceInstance);\n    }\n\n    private synchronized MetadataService getMetadataServiceProxy(ServiceInstance instance) {\n        Object internalProxy = MetadataUtils.referMetadataService(instance).getInternalProxy();\n\n        if (internalProxy instanceof MetadataService) {\n            return ConcurrentHashMapUtils.computeIfAbsent(\n                    metadataServiceProxies, computeKey(instance), k -> (MetadataService) internalProxy);\n        }\n        throw new RuntimeException(\"Service \" + instance.getServiceName() + \" at \" + instance.getHost() + \":\"\n                + instance.getPort() + \"are using MetadataServiceV2, which is not support \");\n    }\n\n    private synchronized void destroyMetadataServiceProxy(ServiceInstance instance) {\n        String key = computeKey(instance);\n        if (metadataServiceProxies.containsKey(key)) {\n            Object metadataServiceProxy = metadataServiceProxies.remove(key);\n            if (metadataServiceProxy instanceof Destroyable) {\n                ((Destroyable) metadataServiceProxy).$destroy();\n            }\n        }\n    }\n\n    /**\n     * UT used only\n     */\n    @Deprecated\n    public final ConcurrentHashMap<String, List<ServiceInstance>> getCachedServiceInstances() {\n        return cachedServiceInstances;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/RegistryClusterIdentifier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_TYPE_KEY;\n\n@SPI\npublic interface RegistryClusterIdentifier {\n    String providerKey(URL url);\n\n    String consumerKey(URL url);\n\n    static RegistryClusterIdentifier getExtension(URL url) {\n        ExtensionLoader<RegistryClusterIdentifier> loader =\n                ScopeModelUtil.getExtensionLoader(RegistryClusterIdentifier.class, url.getScopeModel());\n        return loader.getExtension(url.getParameter(REGISTRY_CLUSTER_TYPE_KEY, \"default\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.registry.RegistryService;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_DELAY_NOTIFICATION_KEY;\n\n/**\n * Defines the common operations of Service Discovery, extended and loaded by ServiceDiscoveryFactory\n */\npublic interface ServiceDiscovery extends RegistryService, Prioritized {\n\n    void register() throws RuntimeException;\n\n    void update() throws RuntimeException;\n\n    void unregister() throws RuntimeException;\n\n    /**\n     * Gets all service names\n     *\n     * @return non-null read-only {@link Set}\n     */\n    Set<String> getServices();\n\n    List<ServiceInstance> getInstances(String serviceName) throws NullPointerException;\n\n    default void addServiceInstancesChangedListener(ServiceInstancesChangedListener listener)\n            throws NullPointerException, IllegalArgumentException {}\n\n    /**\n     * unsubscribe to instance change event.\n     *\n     * @param listener\n     * @throws IllegalArgumentException\n     */\n    default void removeServiceInstancesChangedListener(ServiceInstancesChangedListener listener)\n            throws IllegalArgumentException {}\n\n    default ServiceInstancesChangedListener createListener(Set<String> serviceNames) {\n        return new ServiceInstancesChangedListener(serviceNames, this);\n    }\n\n    ServiceInstance getLocalInstance();\n\n    MetadataInfo getLocalMetadata();\n\n    default MetadataInfo getLocalMetadata(String revision) {\n        return getLocalMetadata();\n    }\n\n    MetadataInfo getRemoteMetadata(String revision);\n\n    MetadataInfo getRemoteMetadata(String revision, List<ServiceInstance> instances);\n\n    /**\n     * Destroy the {@link ServiceDiscovery}\n     *\n     * @throws Exception If met with error\n     */\n    void destroy() throws Exception;\n\n    boolean isDestroy();\n\n    default URL getUrl() {\n        return null;\n    }\n\n    default long getDelay() {\n        return getUrl().getParameter(REGISTRY_DELAY_NOTIFICATION_KEY, 5000);\n    }\n\n    /**\n     * Get services is the default way for service discovery to be available\n     */\n    default boolean isAvailable() {\n        return !isDestroy() && CollectionUtils.isNotEmpty(getServices());\n    }\n\n    /**\n     * A human-readable description of the implementation\n     *\n     * @return The description.\n     */\n    @Override\n    String toString();\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport static org.apache.dubbo.common.extension.ExtensionScope.APPLICATION;\n\n/**\n * The factory to create {@link ServiceDiscovery}\n *\n * @see ServiceDiscovery\n * @since 2.7.5\n */\n@SPI(value = \"default\", scope = APPLICATION)\npublic interface ServiceDiscoveryFactory {\n\n    /**\n     * Get the instance of {@link ServiceDiscovery}\n     *\n     * @param registryURL the {@link URL} to connect the registry\n     * @return non-null\n     */\n    ServiceDiscovery getServiceDiscovery(URL registryURL);\n\n    /**\n     * Get the extension instance of {@link ServiceDiscoveryFactory} by {@link URL#getProtocol() the protocol}\n     *\n     * @param registryURL the {@link URL} to connect the registry\n     * @return non-null\n     */\n    static ServiceDiscoveryFactory getExtension(URL registryURL) {\n        String protocol = registryURL.getProtocol();\n        ExtensionLoader<ServiceDiscoveryFactory> loader =\n                registryURL.getOrDefaultApplicationModel().getExtensionLoader(ServiceDiscoveryFactory.class);\n        return loader.getOrDefaultExtension(protocol);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.metadata.AbstractServiceNameMapping;\nimport org.apache.dubbo.metadata.MappingChangedEvent;\nimport org.apache.dubbo.metadata.MappingListener;\nimport org.apache.dubbo.metadata.ServiceNameMapping;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.registry.event.RegistryEvent;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.registry.support.FailbackRegistry;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE;\nimport static org.apache.dubbo.common.function.ThrowableAction.execute;\nimport static org.apache.dubbo.common.utils.CollectionUtils.toTreeSet;\nimport static org.apache.dubbo.metadata.ServiceNameMapping.toStringKeys;\nimport static org.apache.dubbo.registry.client.ServiceDiscoveryFactory.getExtension;\n\n/**\n * TODO, this bridge implementation is not necessary now, protocol can interact with service discovery directly.\n * <p>\n * ServiceDiscoveryRegistry is a very special Registry implementation, which is used to bridge the old interface-level service discovery model\n * with the new service discovery model introduced in 3.0 in a compatible manner.\n * <p>\n * It fully complies with the extension specification of the Registry SPI, but is different from the specific implementation of zookeeper and Nacos,\n * because it does not interact with any real third-party registry, but only with the relevant components of ServiceDiscovery in the process.\n * In short, it bridges the old interface model and the new service discovery model:\n * <p>\n * - register() aggregates interface level data into MetadataInfo by mainly interacting with MetadataService.\n * - subscribe() triggers the whole subscribe process of the application level service discovery model.\n * - Maps interface to applications depending on ServiceNameMapping.\n * - Starts the new service discovery listener (InstanceListener) and makes NotifierListeners part of the InstanceListener.\n */\npublic class ServiceDiscoveryRegistry extends FailbackRegistry {\n\n    protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private final ServiceDiscovery serviceDiscovery;\n\n    private final AbstractServiceNameMapping serviceNameMapping;\n\n    /* apps - listener */\n    private final Map<String, ServiceInstancesChangedListener> serviceListeners = new ConcurrentHashMap<>();\n    private final ConcurrentHashMap<String, Set<MappingListener>> mappingListeners = new ConcurrentHashMap<>();\n    /* This lock has the same scope and lifecycle as its corresponding instance listener.\n    It's used to make sure that only one interface mapping to the same app list can do subscribe or unsubscribe at the same moment.\n    And the lock should be destroyed when listener destroying its corresponding instance listener.\n    * */\n    private final ConcurrentMap<String, Lock> appSubscriptionLocks = new ConcurrentHashMap<>();\n\n    public ServiceDiscoveryRegistry(URL registryURL, ApplicationModel applicationModel) {\n        super(registryURL);\n        this.serviceDiscovery = createServiceDiscovery(registryURL);\n        this.serviceNameMapping =\n                (AbstractServiceNameMapping) ServiceNameMapping.getDefaultExtension(registryURL.getScopeModel());\n        super.applicationModel = applicationModel;\n    }\n\n    // Currently, for test purpose\n    protected ServiceDiscoveryRegistry(\n            URL registryURL, ServiceDiscovery serviceDiscovery, ServiceNameMapping serviceNameMapping) {\n        super(registryURL);\n        this.serviceDiscovery = serviceDiscovery;\n        this.serviceNameMapping = (AbstractServiceNameMapping) serviceNameMapping;\n    }\n\n    public ServiceDiscovery getServiceDiscovery() {\n        return serviceDiscovery;\n    }\n\n    /**\n     * Create the {@link ServiceDiscovery} from the registry {@link URL}\n     *\n     * @param registryURL the {@link URL} to connect the registry\n     * @return non-null\n     */\n    protected ServiceDiscovery createServiceDiscovery(URL registryURL) {\n        return getServiceDiscovery(registryURL\n                .addParameter(INTERFACE_KEY, ServiceDiscovery.class.getName())\n                .removeParameter(REGISTRY_TYPE_KEY));\n    }\n\n    /**\n     * Get the instance {@link ServiceDiscovery} from the registry {@link URL} using\n     * {@link ServiceDiscoveryFactory} SPI\n     *\n     * @param registryURL the {@link URL} to connect the registry\n     * @return\n     */\n    private ServiceDiscovery getServiceDiscovery(URL registryURL) {\n        ServiceDiscoveryFactory factory = getExtension(registryURL);\n        return factory.getServiceDiscovery(registryURL);\n    }\n\n    @Override\n    protected boolean shouldRegister(URL providerURL) {\n\n        String side = providerURL.getSide();\n\n        boolean should = PROVIDER_SIDE.equals(side); // Only register the Provider.\n\n        if (!should && logger.isDebugEnabled()) {\n            logger.debug(String.format(\"The URL[%s] should not be registered.\", providerURL));\n        }\n\n        if (!acceptable(providerURL)) {\n            logger.info(\"URL \" + providerURL + \" will not be registered to Registry. Registry \" + this.getUrl()\n                    + \" does not accept service of this protocol type.\");\n            return false;\n        }\n\n        return should;\n    }\n\n    protected boolean shouldSubscribe(URL subscribedURL) {\n        return !shouldRegister(subscribedURL);\n    }\n\n    @Override\n    public final void register(URL url) {\n        if (!shouldRegister(url)) { // Should Not Register\n            return;\n        }\n        doRegister(url);\n    }\n\n    @Override\n    public void doRegister(URL url) {\n        // fixme, add registry-cluster is not necessary anymore\n        url = addRegistryClusterKey(url);\n        serviceDiscovery.register(url);\n    }\n\n    @Override\n    public final void unregister(URL url) {\n        if (!shouldRegister(url)) {\n            return;\n        }\n        doUnregister(url);\n    }\n\n    @Override\n    public void doUnregister(URL url) {\n        // fixme, add registry-cluster is not necessary anymore\n        url = addRegistryClusterKey(url);\n        serviceDiscovery.unregister(url);\n    }\n\n    @Override\n    public final void subscribe(URL url, NotifyListener listener) {\n        if (!shouldSubscribe(url)) { // Should Not Subscribe\n            return;\n        }\n        doSubscribe(url, listener);\n    }\n\n    @Override\n    public void doSubscribe(URL url, NotifyListener listener) {\n        url = addRegistryClusterKey(url);\n\n        serviceDiscovery.subscribe(url, listener);\n\n        Set<String> mappingByUrl = ServiceNameMapping.getMappingByUrl(url);\n\n        String key = ServiceNameMapping.buildMappingKey(url);\n\n        if (mappingByUrl == null) {\n            Lock mappingLock = serviceNameMapping.getMappingLock(key);\n            try {\n                mappingLock.lock();\n                mappingByUrl = serviceNameMapping.getMapping(url);\n                try {\n                    DefaultMappingListener mappingListener = new DefaultMappingListener(url, mappingByUrl, listener);\n                    mappingByUrl = serviceNameMapping.getAndListen(this.getUrl(), url, mappingListener);\n                    // update the initial mapping apps we started to listen, to make sure it reflects the real value\n                    // used do subscription before any event.\n                    // it's protected by the mapping lock, so it won't override the event value.\n                    mappingListener.updateInitialApps(mappingByUrl);\n                    synchronized (mappingListeners) {\n                        ConcurrentHashMapUtils.computeIfAbsent(\n                                        mappingListeners, url.getProtocolServiceKey(), (k) -> new ConcurrentHashSet<>())\n                                .add(mappingListener);\n                    }\n                } catch (Exception e) {\n                    logger.warn(\n                            INTERNAL_ERROR,\n                            \"\",\n                            \"\",\n                            \"Cannot find app mapping for service \" + url.getServiceInterface() + \", will not migrate.\",\n                            e);\n                }\n\n                if (CollectionUtils.isEmpty(mappingByUrl)) {\n                    logger.info(\n                            \"[METADATA_REGISTER] No interface-apps mapping found in local cache, stop subscribing, will automatically wait for mapping listener callback: \"\n                                    + url);\n                    //                if (check) {\n                    //                    throw new IllegalStateException(\"Should has at least one way to know which\n                    // services this interface belongs to, subscription url: \" + url);\n                    //                }\n                    return;\n                }\n            } finally {\n                mappingLock.unlock();\n            }\n        }\n        subscribeURLs(url, listener, mappingByUrl);\n    }\n\n    @Override\n    public final void unsubscribe(URL url, NotifyListener listener) {\n        if (!shouldSubscribe(url)) { // Should Not Subscribe\n            return;\n        }\n        url = addRegistryClusterKey(url);\n        doUnsubscribe(url, listener);\n    }\n\n    private URL addRegistryClusterKey(URL url) {\n        String registryCluster = serviceDiscovery.getUrl().getParameter(REGISTRY_CLUSTER_KEY);\n        if (registryCluster != null && url.getParameter(REGISTRY_CLUSTER_KEY) == null) {\n            url = url.addParameter(REGISTRY_CLUSTER_KEY, registryCluster);\n        }\n        return url;\n    }\n\n    @Override\n    public void doUnsubscribe(URL url, NotifyListener listener) {\n        // TODO: remove service name mapping listener\n        serviceDiscovery.unsubscribe(url, listener);\n        String protocolServiceKey = url.getProtocolServiceKey();\n        Set<String> serviceNames = serviceNameMapping.getMapping(url);\n\n        synchronized (mappingListeners) {\n            Set<MappingListener> keyedListeners = mappingListeners.get(protocolServiceKey);\n            if (keyedListeners != null) {\n                List<MappingListener> matched = keyedListeners.stream()\n                        .filter(mappingListener -> mappingListener instanceof DefaultMappingListener\n                                && (Objects.equals(((DefaultMappingListener) mappingListener).getListener(), listener)))\n                        .collect(Collectors.toList());\n                for (MappingListener mappingListener : matched) {\n                    serviceNameMapping.stopListen(url, mappingListener);\n                    keyedListeners.remove(mappingListener);\n                }\n                if (keyedListeners.isEmpty()) {\n                    mappingListeners.remove(protocolServiceKey, Collections.emptySet());\n                }\n            }\n        }\n        if (CollectionUtils.isNotEmpty(serviceNames)) {\n            String serviceNamesKey = toStringKeys(serviceNames);\n            Lock appSubscriptionLock = getAppSubscription(serviceNamesKey);\n            try {\n                appSubscriptionLock.lock();\n                ServiceInstancesChangedListener instancesChangedListener = serviceListeners.get(serviceNamesKey);\n                if (instancesChangedListener != null) {\n                    instancesChangedListener.removeListener(url.getServiceKey(), listener);\n                    if (!instancesChangedListener.hasListeners()) {\n                        instancesChangedListener.destroy();\n                        serviceListeners.remove(serviceNamesKey);\n                        removeAppSubscriptionLock(serviceNamesKey);\n                    }\n                }\n            } finally {\n                appSubscriptionLock.unlock();\n            }\n        }\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        throw new UnsupportedOperationException(\"\");\n    }\n\n    @Override\n    public boolean isAvailable() {\n        // serviceDiscovery isAvailable has a default method, which can be used as a reference when implementing\n        return serviceDiscovery.isAvailable();\n    }\n\n    @Override\n    public void destroy() {\n        registryManager.removeDestroyedRegistry(this);\n        // stop ServiceDiscovery\n        execute(serviceDiscovery::destroy);\n        // destroy all event listener\n        for (ServiceInstancesChangedListener listener : serviceListeners.values()) {\n            listener.destroy();\n        }\n        appSubscriptionLocks.clear();\n        serviceListeners.clear();\n        mappingListeners.clear();\n    }\n\n    @Override\n    public boolean isServiceDiscovery() {\n        return true;\n    }\n\n    protected void subscribeURLs(URL url, NotifyListener listener, Set<String> serviceNames) {\n        serviceNames = toTreeSet(serviceNames);\n        String serviceNamesKey = toStringKeys(serviceNames);\n        String serviceKey = url.getServiceKey();\n        logger.info(\n                String.format(\"Trying to subscribe from apps %s for service key %s, \", serviceNamesKey, serviceKey));\n\n        // register ServiceInstancesChangedListener\n        Lock appSubscriptionLock = getAppSubscription(serviceNamesKey);\n        try {\n            appSubscriptionLock.lock();\n            ServiceInstancesChangedListener serviceInstancesChangedListener = serviceListeners.get(serviceNamesKey);\n            if (serviceInstancesChangedListener == null) {\n                serviceInstancesChangedListener = serviceDiscovery.createListener(serviceNames);\n                for (String serviceName : serviceNames) {\n                    List<ServiceInstance> serviceInstances = serviceDiscovery.getInstances(serviceName);\n                    if (CollectionUtils.isNotEmpty(serviceInstances)) {\n                        serviceInstancesChangedListener.onEvent(\n                                new ServiceInstancesChangedEvent(serviceName, serviceInstances));\n                    }\n                }\n                serviceListeners.put(serviceNamesKey, serviceInstancesChangedListener);\n            }\n\n            if (!serviceInstancesChangedListener.isDestroyed()) {\n                listener.addServiceListener(serviceInstancesChangedListener);\n                serviceInstancesChangedListener.addListenerAndNotify(url, listener);\n                ServiceInstancesChangedListener finalServiceInstancesChangedListener = serviceInstancesChangedListener;\n\n                String serviceDiscoveryName =\n                        url.getParameter(RegistryConstants.REGISTRY_CLUSTER_KEY, url.getProtocol());\n\n                MetricsEventBus.post(\n                        RegistryEvent.toSsEvent(\n                                url.getApplicationModel(), serviceKey, Collections.singletonList(serviceDiscoveryName)),\n                        () -> {\n                            serviceDiscovery.addServiceInstancesChangedListener(finalServiceInstancesChangedListener);\n                            return null;\n                        });\n            } else {\n                logger.info(String.format(\"Listener of %s has been destroyed by another thread.\", serviceNamesKey));\n                serviceListeners.remove(serviceNamesKey);\n            }\n        } finally {\n            appSubscriptionLock.unlock();\n        }\n    }\n\n    /**\n     * Supports or not ?\n     *\n     * @param registryURL the {@link URL url} of registry\n     * @return if supported, return <code>true</code>, or <code>false</code>\n     */\n    public static boolean supports(URL registryURL) {\n        return SERVICE_REGISTRY_TYPE.equalsIgnoreCase(registryURL.getParameter(REGISTRY_TYPE_KEY));\n    }\n\n    public Map<String, ServiceInstancesChangedListener> getServiceListeners() {\n        return serviceListeners;\n    }\n\n    private class DefaultMappingListener implements MappingListener {\n        private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DefaultMappingListener.class);\n        private final URL url;\n        private final NotifyListener listener;\n        private volatile Set<String> oldApps;\n        private volatile boolean stopped;\n\n        public DefaultMappingListener(URL subscribedURL, Set<String> serviceNames, NotifyListener listener) {\n            this.url = subscribedURL;\n            this.oldApps = serviceNames;\n            this.listener = listener;\n        }\n\n        @Override\n        public synchronized void onEvent(MappingChangedEvent event) {\n            logger.info(\"Received mapping notification from meta server, \" + event);\n\n            if (stopped) {\n                logger.warn(\n                        INTERNAL_ERROR,\n                        \"\",\n                        \"\",\n                        \"Listener has been stopped, ignore mapping notification, check why listener is not removed.\");\n                return;\n            }\n            Set<String> newApps = event.getApps();\n            Set<String> tempOldApps = oldApps;\n\n            Lock mappingLock = serviceNameMapping.getMappingLock(event.getServiceKey());\n            try {\n                mappingLock.lock();\n                if (CollectionUtils.isEmpty(newApps) || CollectionUtils.equals(newApps, tempOldApps)) {\n                    return;\n                }\n                logger.info(\"Mapping of service \" + event.getServiceKey() + \"changed from \" + tempOldApps + \" to \"\n                        + newApps);\n\n                if (CollectionUtils.isEmpty(tempOldApps) && !newApps.isEmpty()) {\n                    serviceNameMapping.putCachedMapping(ServiceNameMapping.buildMappingKey(url), newApps);\n                    subscribeURLs(url, listener, newApps);\n                    oldApps = newApps;\n                    return;\n                }\n\n                for (String newAppName : newApps) {\n                    if (!tempOldApps.contains(newAppName)) {\n                        serviceNameMapping.removeCachedMapping(ServiceNameMapping.buildMappingKey(url));\n                        serviceNameMapping.putCachedMapping(ServiceNameMapping.buildMappingKey(url), newApps);\n                        // old instance listener related to old app list that needs to be destroyed after subscribe\n                        // refresh.\n                        ServiceInstancesChangedListener oldListener = listener.getServiceListener();\n                        if (oldListener != null) {\n                            String appKey = toStringKeys(toTreeSet(tempOldApps));\n                            Lock appSubscriptionLock = getAppSubscription(appKey);\n                            try {\n                                appSubscriptionLock.lock();\n                                oldListener.removeListener(url.getServiceKey(), listener);\n                                if (!oldListener.hasListeners()) {\n                                    oldListener.destroy();\n                                    serviceListeners.remove(appKey);\n                                    removeAppSubscriptionLock(appKey);\n                                }\n                            } finally {\n                                appSubscriptionLock.unlock();\n                            }\n                        }\n\n                        subscribeURLs(url, listener, newApps);\n                        oldApps = newApps;\n                        return;\n                    }\n                }\n            } finally {\n                mappingLock.unlock();\n            }\n        }\n\n        protected NotifyListener getListener() {\n            return listener;\n        }\n\n        // writing of oldApps is protected by mapping lock to guarantee sequence consistency.\n        public void updateInitialApps(Set<String> oldApps) {\n            if (oldApps != null && !CollectionUtils.equals(oldApps, this.oldApps)) {\n                this.oldApps = oldApps;\n                logger.info(\"Update initial mapping apps from \" + this.oldApps + \" to \" + oldApps);\n            }\n        }\n\n        @Override\n        public void stop() {\n            stopped = true;\n        }\n    }\n\n    public Lock getAppSubscription(String key) {\n        return ConcurrentHashMapUtils.computeIfAbsent(appSubscriptionLocks, key, _k -> new ReentrantLock());\n    }\n\n    public void removeAppSubscriptionLock(String key) {\n        Lock lock = appSubscriptionLocks.get(key);\n        if (lock != null) {\n            try {\n                lock.lock();\n                appSubscriptionLocks.remove(key);\n            } finally {\n                lock.unlock();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.ProtocolServiceKey;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.url.component.DubboServiceAddressURL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.registry.AddressListener;\nimport org.apache.dubbo.registry.Constants;\nimport org.apache.dubbo.registry.ProviderFirstParams;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.integration.AbstractConfiguratorListener;\nimport org.apache.dubbo.registry.integration.DynamicDirectory;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcContext;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.RpcInvocation;\nimport org.apache.dubbo.rpc.RpcServiceContext;\nimport org.apache.dubbo.rpc.cluster.Configurator;\nimport org.apache.dubbo.rpc.cluster.RouterChain;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DISABLED_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INSTANCE_REGISTER_MODE;\nimport static org.apache.dubbo.common.constants.CommonConstants.IS_EXTRA;\nimport static org.apache.dubbo.common.constants.CommonConstants.PREFERRED_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_DESTROY_INVOKER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_REFER_INVOKER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNSUPPORTED;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_HASHMAP_LOAD_FACTOR;\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE;\nimport static org.apache.dubbo.registry.Constants.CONFIGURATORS_SUFFIX;\nimport static org.apache.dubbo.rpc.model.ScopeModelUtil.getModuleModel;\n\npublic class ServiceDiscoveryRegistryDirectory<T> extends DynamicDirectory<T> {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ServiceDiscoveryRegistryDirectory.class);\n\n    /**\n     * instance address to invoker mapping.\n     * The initial value is null and the midway may be assigned to null, please use the local variable reference\n     */\n    private volatile Map<ProtocolServiceKeyWithAddress, Invoker<T>> urlInvokerMap;\n\n    private volatile ReferenceConfigurationListener referenceConfigurationListener;\n    private volatile boolean enableConfigurationListen = true;\n    private volatile List<URL> originalUrls = null;\n    private volatile Map<String, String> overrideQueryMap;\n    private final Set<String> providerFirstParams;\n    private final ModuleModel moduleModel;\n    private final ProtocolServiceKey consumerProtocolServiceKey;\n    private final ConcurrentMap<ProtocolServiceKey, URL> customizedConsumerUrlMap = new ConcurrentHashMap<>();\n\n    public ServiceDiscoveryRegistryDirectory(Class<T> serviceType, URL url) {\n        super(serviceType, url);\n        moduleModel = getModuleModel(url.getScopeModel());\n\n        Set<ProviderFirstParams> providerFirstParams = url.getOrDefaultApplicationModel()\n                .getExtensionLoader(ProviderFirstParams.class)\n                .getSupportedExtensionInstances();\n        if (CollectionUtils.isEmpty(providerFirstParams)) {\n            this.providerFirstParams = null;\n        } else {\n            if (providerFirstParams.size() == 1) {\n                this.providerFirstParams = Collections.unmodifiableSet(\n                        providerFirstParams.iterator().next().params());\n            } else {\n                Set<String> params = new HashSet<>();\n                for (ProviderFirstParams paramsFilter : providerFirstParams) {\n                    if (paramsFilter.params() == null) {\n                        break;\n                    }\n                    params.addAll(paramsFilter.params());\n                }\n                this.providerFirstParams = Collections.unmodifiableSet(params);\n            }\n        }\n\n        String protocol = consumerUrl.getParameter(PROTOCOL_KEY, consumerUrl.getProtocol());\n        consumerProtocolServiceKey = new ProtocolServiceKey(\n                consumerUrl.getServiceInterface(),\n                consumerUrl.getVersion(),\n                consumerUrl.getGroup(),\n                !CommonConstants.CONSUMER.equals(protocol) ? protocol : null);\n    }\n\n    @Override\n    public void subscribe(URL url) {\n        if (moduleModel\n                .modelEnvironment()\n                .getConfiguration()\n                .convert(Boolean.class, Constants.ENABLE_CONFIGURATION_LISTEN, true)) {\n            enableConfigurationListen = true;\n            getConsumerConfigurationListener(moduleModel).addNotifyListener(this);\n            referenceConfigurationListener = new ReferenceConfigurationListener(this.moduleModel, this, url);\n        } else {\n            enableConfigurationListen = false;\n        }\n        super.subscribe(url);\n    }\n\n    private ConsumerConfigurationListener getConsumerConfigurationListener(ModuleModel moduleModel) {\n        return moduleModel\n                .getBeanFactory()\n                .getOrRegisterBean(\n                        ConsumerConfigurationListener.class, type -> new ConsumerConfigurationListener(moduleModel));\n    }\n\n    @Override\n    public void unSubscribe(URL url) {\n        super.unSubscribe(url);\n        this.originalUrls = null;\n        if (moduleModel\n                .modelEnvironment()\n                .getConfiguration()\n                .convert(Boolean.class, Constants.ENABLE_CONFIGURATION_LISTEN, true)) {\n            getConsumerConfigurationListener(moduleModel).removeNotifyListener(this);\n            referenceConfigurationListener.stop();\n        }\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n        if (moduleModel\n                .modelEnvironment()\n                .getConfiguration()\n                .convert(Boolean.class, Constants.ENABLE_CONFIGURATION_LISTEN, true)) {\n            getConsumerConfigurationListener(moduleModel).removeNotifyListener(this);\n            referenceConfigurationListener.stop();\n        }\n    }\n\n    @Override\n    public void buildRouterChain(URL url) {\n        this.setRouterChain(\n                RouterChain.buildChain(getInterface(), url.addParameter(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE)));\n    }\n\n    @Override\n    public synchronized void notify(List<URL> instanceUrls) {\n        if (isDestroyed()) {\n            return;\n        }\n        // Set the context of the address notification thread.\n        RpcServiceContext.getServiceContext().setConsumerUrl(getConsumerUrl());\n\n        //  3.x added for extend URL address\n        ExtensionLoader<AddressListener> addressListenerExtensionLoader =\n                getUrl().getOrDefaultModuleModel().getExtensionLoader(AddressListener.class);\n        List<AddressListener> supportedListeners =\n                addressListenerExtensionLoader.getActivateExtension(getUrl(), (String[]) null);\n        if (supportedListeners != null && !supportedListeners.isEmpty()) {\n            for (AddressListener addressListener : supportedListeners) {\n                instanceUrls = addressListener.notify(instanceUrls, getConsumerUrl(), this);\n            }\n        }\n\n        refreshOverrideAndInvoker(instanceUrls);\n    }\n\n    // RefreshOverrideAndInvoker will be executed by registryCenter and configCenter, so it should be synchronized.\n    @Override\n    protected synchronized void refreshOverrideAndInvoker(List<URL> instanceUrls) {\n        // mock zookeeper://xxx?mock=return null\n        this.directoryUrl = overrideDirectoryWithConfigurator(getOriginalConsumerUrl());\n        refreshInvoker(instanceUrls);\n    }\n\n    protected URL overrideDirectoryWithConfigurator(URL url) {\n        // override url with configurator from \"app-name.configurators\"\n        url = overrideWithConfigurators(\n                getConsumerConfigurationListener(moduleModel).getConfigurators(), url);\n\n        // override url with configurator from configurators from \"service-name.configurators\"\n        if (referenceConfigurationListener != null) {\n            url = overrideWithConfigurators(referenceConfigurationListener.getConfigurators(), url);\n        }\n\n        return url;\n    }\n\n    private URL overrideWithConfigurators(List<Configurator> configurators, URL url) {\n        if (CollectionUtils.isNotEmpty(configurators)) {\n            if (url instanceof DubboServiceAddressURL) {\n                DubboServiceAddressURL interfaceAddressURL = (DubboServiceAddressURL) url;\n                URL overriddenURL = interfaceAddressURL.getOverrideURL();\n                if (overriddenURL == null) {\n                    String appName = interfaceAddressURL.getApplication();\n                    String side = interfaceAddressURL.getSide();\n                    overriddenURL = URLBuilder.from(interfaceAddressURL)\n                            .clearParameters()\n                            .addParameter(APPLICATION_KEY, appName)\n                            .addParameter(SIDE_KEY, side)\n                            .build();\n                }\n                for (Configurator configurator : configurators) {\n                    overriddenURL = configurator.configure(overriddenURL);\n                }\n                url = new DubboServiceAddressURL(\n                        interfaceAddressURL.getUrlAddress(),\n                        interfaceAddressURL.getUrlParam(),\n                        interfaceAddressURL.getConsumerURL(),\n                        (ServiceConfigURL) overriddenURL);\n            } else {\n                for (Configurator configurator : configurators) {\n                    url = configurator.configure(url);\n                }\n            }\n        }\n        return url;\n    }\n\n    protected InstanceAddressURL overrideWithConfigurator(InstanceAddressURL providerUrl) {\n        // override url with configurator from \"app-name.configurators\"\n        providerUrl = overrideWithConfigurators(\n                getConsumerConfigurationListener(moduleModel).getConfigurators(), providerUrl);\n\n        // override url with configurator from configurators from \"service-name.configurators\"\n        if (referenceConfigurationListener != null) {\n            providerUrl = overrideWithConfigurators(referenceConfigurationListener.getConfigurators(), providerUrl);\n        }\n\n        return providerUrl;\n    }\n\n    private InstanceAddressURL overrideWithConfigurators(List<Configurator> configurators, InstanceAddressURL url) {\n        if (CollectionUtils.isNotEmpty(configurators)) {\n            // wrap url\n            OverrideInstanceAddressURL overrideInstanceAddressURL = new OverrideInstanceAddressURL(url);\n            if (overrideQueryMap != null) {\n                // override app-level configs\n                overrideInstanceAddressURL =\n                        (OverrideInstanceAddressURL) overrideInstanceAddressURL.addParameters(overrideQueryMap);\n            }\n            for (Configurator configurator : configurators) {\n                overrideInstanceAddressURL =\n                        (OverrideInstanceAddressURL) configurator.configure(overrideInstanceAddressURL);\n            }\n            return overrideInstanceAddressURL;\n        }\n        return url;\n    }\n\n    @Override\n    public boolean isServiceDiscovery() {\n        return true;\n    }\n\n    /**\n     * This implementation makes sure all application names related to serviceListener received address notification.\n     * <p>\n     * FIXME, make sure deprecated \"interface-application\" mapping item be cleared in time.\n     */\n    @Override\n    public boolean isNotificationReceived() {\n        return serviceListener == null\n                || serviceListener.isDestroyed()\n                || serviceListener.getAllInstances().size()\n                        == serviceListener.getServiceNames().size();\n    }\n\n    private void refreshInvoker(List<URL> invokerUrls) {\n        Assert.notNull(invokerUrls, \"invokerUrls should not be null, use EMPTY url to clear current addresses.\");\n        this.originalUrls = invokerUrls;\n\n        if (invokerUrls.size() == 1 && EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {\n            logger.warn(\n                    PROTOCOL_UNSUPPORTED,\n                    \"\",\n                    \"\",\n                    String.format(\n                            \"Received url with EMPTY protocol from registry %s, will clear all available addresses.\",\n                            this));\n            refreshRouter(\n                    BitList.emptyList(), () -> this.forbidden = true // Forbid to access\n                    );\n            destroyAllInvokers(); // Close all invokers\n        } else {\n            this.forbidden = false; // Allow accessing\n            if (CollectionUtils.isEmpty(invokerUrls)) {\n                logger.warn(\n                        PROTOCOL_UNSUPPORTED,\n                        \"\",\n                        \"\",\n                        String.format(\n                                \"Received empty url list from registry %s, will ignore for protection purpose.\", this));\n                return;\n            }\n\n            int originSize = invokerUrls.size();\n            invokerUrls = invokerUrls.stream().distinct().collect(Collectors.toList());\n            if (invokerUrls.size() != originSize) {\n                logger.info(\"Received duplicated invoker urls changed event from registry. \"\n                        + \"Registry type: instance. \"\n                        + \"Service Key: \"\n                        + getConsumerUrl().getServiceKey() + \". \"\n                        + \"Notify Urls Size : \" + originSize + \". \"\n                        + \"Distinct Urls Size: \" + invokerUrls.size() + \".\");\n            }\n\n            // use local reference to avoid NPE as this.urlInvokerMap will be set null concurrently at\n            // destroyAllInvokers().\n            Map<ProtocolServiceKeyWithAddress, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap;\n            // can't use local reference as oldUrlInvokerMap's mappings might be removed directly at toInvokers().\n            Map<ProtocolServiceKeyWithAddress, Invoker<T>> oldUrlInvokerMap = null;\n            if (localUrlInvokerMap != null) {\n                // the initial capacity should be set greater than the maximum number of entries divided by the load\n                // factor to avoid resizing.\n                oldUrlInvokerMap =\n                        new LinkedHashMap<>(Math.round(1 + localUrlInvokerMap.size() / DEFAULT_HASHMAP_LOAD_FACTOR));\n                localUrlInvokerMap.forEach(oldUrlInvokerMap::put);\n            }\n            Map<ProtocolServiceKeyWithAddress, Invoker<T>> newUrlInvokerMap =\n                    toInvokers(oldUrlInvokerMap, invokerUrls); // Translate url list to Invoker map\n            logger.info(String.format(\"Refreshed invoker size %s from registry %s\", newUrlInvokerMap.size(), this));\n\n            if (CollectionUtils.isEmptyMap(newUrlInvokerMap)) {\n                logger.error(\n                        PROTOCOL_UNSUPPORTED,\n                        \"\",\n                        \"\",\n                        \"Unsupported protocol.\",\n                        new IllegalStateException(String.format(\n                                \"Cannot create invokers from url address list (total %s)\", invokerUrls.size())));\n                return;\n            }\n            List<Invoker<T>> newInvokers = Collections.unmodifiableList(new ArrayList<>(newUrlInvokerMap.values()));\n            BitList<Invoker<T>> finalInvokers =\n                    multiGroup ? new BitList<>(toMergeInvokerList(newInvokers)) : new BitList<>(newInvokers);\n            // pre-route and build cache\n            refreshRouter(finalInvokers.clone(), () -> this.setInvokers(finalInvokers));\n            this.urlInvokerMap = newUrlInvokerMap;\n\n            if (oldUrlInvokerMap != null) {\n                try {\n                    destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); // Close the unused Invoker\n                } catch (Exception e) {\n                    logger.warn(PROTOCOL_FAILED_DESTROY_INVOKER, \"\", \"\", \"destroyUnusedInvokers error. \", e);\n                }\n            }\n        }\n\n        // notify invokers refreshed\n        this.invokersChanged();\n\n        logger.info(\"Received invokers changed event from registry. \" + \"Registry type: instance. \"\n                + \"Service Key: \"\n                + getConsumerUrl().getServiceKey() + \". \" + \"Urls Size : \"\n                + invokerUrls.size() + \". \" + \"Invokers Size : \"\n                + getInvokers().size() + \". \" + \"Available Size: \"\n                + getValidInvokers().size() + \". \" + \"Available Invokers : \"\n                + joinValidInvokerAddresses());\n    }\n\n    /**\n     * Turn urls into invokers, and if url has been refer, will not re-reference.\n     * the items that will be put into newUrlInvokeMap will be removed from oldUrlInvokerMap.\n     *\n     * @param oldUrlInvokerMap it might be modified during the process.\n     * @param urls\n     * @return invokers\n     */\n    private Map<ProtocolServiceKeyWithAddress, Invoker<T>> toInvokers(\n            Map<ProtocolServiceKeyWithAddress, Invoker<T>> oldUrlInvokerMap, List<URL> urls) {\n        Map<ProtocolServiceKeyWithAddress, Invoker<T>> newUrlInvokerMap =\n                new ConcurrentHashMap<>(urls == null ? 1 : (int) (urls.size() / 0.75f + 1));\n        if (urls == null || urls.isEmpty()) {\n            return newUrlInvokerMap;\n        }\n\n        for (URL url : urls) {\n            InstanceAddressURL instanceAddressURL = (InstanceAddressURL) url;\n            if (EMPTY_PROTOCOL.equals(instanceAddressURL.getProtocol())) {\n                continue;\n            }\n            if (!getUrl().getOrDefaultFrameworkModel()\n                    .getExtensionLoader(Protocol.class)\n                    .hasExtension(instanceAddressURL.getProtocol())) {\n\n                // 4-1 - Unsupported protocol\n\n                logger.error(\n                        PROTOCOL_UNSUPPORTED,\n                        \"protocol extension does not installed\",\n                        \"\",\n                        \"Unsupported protocol.\",\n                        new IllegalStateException(\"Unsupported protocol \" + instanceAddressURL.getProtocol()\n                                + \" in notified url: \"\n                                + instanceAddressURL + \" from registry \" + getUrl().getAddress() + \" to consumer \"\n                                + NetUtils.getLocalHost() + \", supported protocol: \"\n                                + getUrl().getOrDefaultFrameworkModel()\n                                        .getExtensionLoader(Protocol.class)\n                                        .getSupportedExtensions()));\n\n                continue;\n            }\n\n            instanceAddressURL.setProviderFirstParams(providerFirstParams);\n\n            // Override provider urls if needed\n            if (enableConfigurationListen) {\n                instanceAddressURL = overrideWithConfigurator(instanceAddressURL);\n            }\n\n            // filter all the service available (version wildcard, group wildcard, protocol wildcard)\n            List<ProtocolServiceKey> matchedProtocolServiceKeys =\n                    getMatchedProtocolServiceKeys(instanceAddressURL, true);\n            if (CollectionUtils.isEmpty(matchedProtocolServiceKeys)) {\n                // if preferred protocol is not specified, use the default main protocol\n                matchedProtocolServiceKeys = getMatchedProtocolServiceKeys(instanceAddressURL, false);\n            }\n\n            // see org.apache.dubbo.common.ProtocolServiceKey.isSameWith\n            // check if needed to override the consumer url\n            boolean shouldWrap = matchedProtocolServiceKeys.size() != 1\n                    || !consumerProtocolServiceKey.isSameWith(matchedProtocolServiceKeys.get(0));\n\n            for (ProtocolServiceKey matchedProtocolServiceKey : matchedProtocolServiceKeys) {\n                ProtocolServiceKeyWithAddress protocolServiceKeyWithAddress =\n                        new ProtocolServiceKeyWithAddress(matchedProtocolServiceKey, instanceAddressURL.getAddress());\n                Invoker<T> invoker =\n                        oldUrlInvokerMap == null ? null : oldUrlInvokerMap.get(protocolServiceKeyWithAddress);\n                if (invoker == null\n                        || urlChanged(\n                                invoker,\n                                instanceAddressURL,\n                                matchedProtocolServiceKey)) { // Not in the cache, refer again\n                    try {\n                        boolean enabled;\n                        if (instanceAddressURL.hasParameter(DISABLED_KEY)) {\n                            enabled = !instanceAddressURL.getParameter(DISABLED_KEY, false);\n                        } else {\n                            enabled = instanceAddressURL.getParameter(ENABLED_KEY, true);\n                        }\n                        if (enabled) {\n                            if (shouldWrap) {\n                                URL newConsumerUrl = ConcurrentHashMapUtils.computeIfAbsent(\n                                        customizedConsumerUrlMap, matchedProtocolServiceKey, k -> consumerUrl\n                                                .setProtocol(k.getProtocol())\n                                                .addParameter(CommonConstants.GROUP_KEY, k.getGroup())\n                                                .addParameter(CommonConstants.VERSION_KEY, k.getVersion()));\n                                RpcContext.getServiceContext().setConsumerUrl(newConsumerUrl);\n                                invoker = new InstanceWrappedInvoker<>(\n                                        protocol.refer(serviceType, instanceAddressURL),\n                                        newConsumerUrl,\n                                        matchedProtocolServiceKey);\n                            } else {\n                                invoker = protocol.refer(serviceType, instanceAddressURL);\n                            }\n                        }\n                    } catch (Throwable t) {\n                        logger.error(\n                                PROTOCOL_FAILED_REFER_INVOKER,\n                                \"\",\n                                \"\",\n                                \"Failed to refer invoker for interface:\" + serviceType + \",url:(\" + instanceAddressURL\n                                        + \")\" + t.getMessage(),\n                                t);\n                    }\n                    if (invoker != null) { // Put new invoker in cache\n                        newUrlInvokerMap.put(protocolServiceKeyWithAddress, invoker);\n                    }\n                } else {\n                    newUrlInvokerMap.put(protocolServiceKeyWithAddress, invoker);\n                    oldUrlInvokerMap.remove(protocolServiceKeyWithAddress, invoker);\n                }\n            }\n        }\n        return newUrlInvokerMap;\n    }\n\n    private List<ProtocolServiceKey> getMatchedProtocolServiceKeys(\n            InstanceAddressURL instanceAddressURL, boolean needPreferred) {\n        int port = instanceAddressURL.getPort();\n        return instanceAddressURL.getMetadataInfo().getMatchedServiceInfos(consumerProtocolServiceKey).stream()\n                .filter(serviceInfo -> serviceInfo.getPort() <= 0 || serviceInfo.getPort() == port)\n                // special filter for extra protocols.\n                .filter(serviceInfo -> {\n                    if (StringUtils.isNotEmpty(\n                            consumerProtocolServiceKey\n                                    .getProtocol())) { // if consumer side protocol is specified, use all\n                        // the protocols we got in hand now directly\n                        return true;\n                    } else {\n                        // if consumer side protocol is not specified, choose the preferred or default main protocol\n                        if (needPreferred) {\n                            return serviceInfo.getProtocol().equals(serviceInfo.getParameter(PREFERRED_PROTOCOL));\n                        } else {\n                            return StringUtils.isEmpty(serviceInfo.getParameter(IS_EXTRA));\n                        }\n                    }\n                })\n                .map(MetadataInfo.ServiceInfo::getProtocolServiceKey)\n                .collect(Collectors.toList());\n    }\n\n    private boolean urlChanged(Invoker<T> invoker, InstanceAddressURL newURL, ProtocolServiceKey protocolServiceKey) {\n        InstanceAddressURL oldURL = (InstanceAddressURL) invoker.getUrl();\n\n        if (!newURL.getInstance().equals(oldURL.getInstance())) {\n            return true;\n        }\n\n        if (oldURL instanceof OverrideInstanceAddressURL || newURL instanceof OverrideInstanceAddressURL) {\n            if (!(oldURL instanceof OverrideInstanceAddressURL && newURL instanceof OverrideInstanceAddressURL)) {\n                // sub-class changed\n                return true;\n            } else {\n                if (!((OverrideInstanceAddressURL) oldURL)\n                        .getOverrideParams()\n                        .equals(((OverrideInstanceAddressURL) newURL).getOverrideParams())) {\n                    return true;\n                }\n            }\n        }\n\n        MetadataInfo.ServiceInfo oldServiceInfo =\n                oldURL.getMetadataInfo().getValidServiceInfo(protocolServiceKey.toString());\n        if (null == oldServiceInfo) {\n            return false;\n        }\n\n        return !oldServiceInfo.equals(newURL.getMetadataInfo().getValidServiceInfo(protocolServiceKey.toString()));\n    }\n\n    private List<Invoker<T>> toMergeInvokerList(List<Invoker<T>> invokers) {\n        List<Invoker<T>> mergedInvokers = new ArrayList<>();\n        Map<String, List<Invoker<T>>> groupMap = new HashMap<>();\n        for (Invoker<T> invoker : invokers) {\n            String group = invoker.getUrl().getGroup(\"\");\n            groupMap.computeIfAbsent(group, k -> new ArrayList<>());\n            groupMap.get(group).add(invoker);\n        }\n\n        if (groupMap.size() == 1) {\n            mergedInvokers.addAll(groupMap.values().iterator().next());\n        } else if (groupMap.size() > 1) {\n            for (List<Invoker<T>> groupList : groupMap.values()) {\n                StaticDirectory<T> staticDirectory = new StaticDirectory<>(groupList);\n                staticDirectory.buildRouterChain();\n                mergedInvokers.add(cluster.join(staticDirectory, false));\n            }\n        } else {\n            mergedInvokers = invokers;\n        }\n        return mergedInvokers;\n    }\n\n    /**\n     * Close all invokers\n     */\n    @Override\n    protected void destroyAllInvokers() {\n        Map<ProtocolServiceKeyWithAddress, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap; // local reference\n        if (localUrlInvokerMap != null) {\n            for (Invoker<T> invoker : new ArrayList<>(localUrlInvokerMap.values())) {\n                try {\n                    invoker.destroy();\n                } catch (Throwable t) {\n                    logger.warn(\n                            PROTOCOL_FAILED_DESTROY_INVOKER,\n                            \"\",\n                            \"\",\n                            \"Failed to destroy service \" + serviceKey + \" to provider \" + invoker.getUrl(),\n                            t);\n                }\n            }\n            localUrlInvokerMap.clear();\n        }\n\n        this.urlInvokerMap = null;\n        this.destroyInvokers();\n    }\n\n    @Override\n    protected Map<String, String> getDirectoryMeta() {\n        String registryKey = Optional.ofNullable(getRegistry())\n                .map(Registry::getUrl)\n                .map(url -> url.getParameter(\n                        RegistryConstants.REGISTRY_CLUSTER_KEY,\n                        url.getParameter(RegistryConstants.REGISTRY_KEY, url.getProtocol())))\n                .orElse(\"unknown\");\n        Map<String, String> metas = new HashMap<>();\n        metas.put(REGISTRY_KEY, registryKey);\n        metas.put(REGISTER_MODE_KEY, INSTANCE_REGISTER_MODE);\n        return metas;\n    }\n\n    /**\n     * Check whether the invoker in the cache needs to be destroyed\n     * If set attribute of url: refer.autodestroy=false, the invokers will only increase without decreasing,there may be a refer leak\n     *\n     * @param oldUrlInvokerMap\n     * @param newUrlInvokerMap\n     */\n    private void destroyUnusedInvokers(\n            Map<ProtocolServiceKeyWithAddress, Invoker<T>> oldUrlInvokerMap,\n            Map<ProtocolServiceKeyWithAddress, Invoker<T>> newUrlInvokerMap) {\n        if (newUrlInvokerMap == null || newUrlInvokerMap.size() == 0) {\n            destroyAllInvokers();\n            return;\n        }\n\n        if (oldUrlInvokerMap == null || oldUrlInvokerMap.size() == 0) {\n            return;\n        }\n\n        for (Map.Entry<ProtocolServiceKeyWithAddress, Invoker<T>> entry : oldUrlInvokerMap.entrySet()) {\n            Invoker<T> invoker = entry.getValue();\n            if (invoker != null) {\n                try {\n                    invoker.destroy();\n                    if (logger.isDebugEnabled()) {\n                        logger.debug(\"destroy invoker[\" + invoker.getUrl() + \"] success. \");\n                    }\n                } catch (Exception e) {\n                    logger.warn(\n                            PROTOCOL_FAILED_DESTROY_INVOKER,\n                            \"\",\n                            \"\",\n                            \"destroy invoker[\" + invoker.getUrl() + \"]failed.\" + e.getMessage(),\n                            e);\n                }\n            }\n        }\n        logger.info(oldUrlInvokerMap.size() + \" deprecated invokers deleted.\");\n    }\n\n    private class ReferenceConfigurationListener extends AbstractConfiguratorListener {\n        private final ServiceDiscoveryRegistryDirectory<?> directory;\n        private final URL url;\n\n        ReferenceConfigurationListener(\n                ModuleModel moduleModel, ServiceDiscoveryRegistryDirectory<?> directory, URL url) {\n            super(moduleModel);\n            this.directory = directory;\n            this.url = url;\n            this.initWith(DynamicConfiguration.getRuleKey(url) + CONFIGURATORS_SUFFIX);\n        }\n\n        void stop() {\n            this.stopListen(DynamicConfiguration.getRuleKey(url) + CONFIGURATORS_SUFFIX);\n        }\n\n        @Override\n        protected void notifyOverrides() {\n            // to notify configurator/router changes\n            if (directory.originalUrls != null) {\n                URL backup = RpcContext.getServiceContext().getConsumerUrl();\n                RpcContext.getServiceContext().setConsumerUrl(directory.getConsumerUrl());\n                directory.refreshOverrideAndInvoker(directory.originalUrls);\n                RpcContext.getServiceContext().setConsumerUrl(backup);\n            }\n        }\n    }\n\n    private static class ConsumerConfigurationListener extends AbstractConfiguratorListener {\n        private final List<ServiceDiscoveryRegistryDirectory<?>> listeners = new CopyOnWriteArrayList<>();\n\n        ConsumerConfigurationListener(ModuleModel moduleModel) {\n            super(moduleModel);\n        }\n\n        void addNotifyListener(ServiceDiscoveryRegistryDirectory<?> listener) {\n            if (listeners.isEmpty()) {\n                this.initWith(moduleModel.getApplicationModel().getApplicationName() + CONFIGURATORS_SUFFIX);\n            }\n            this.listeners.add(listener);\n        }\n\n        void removeNotifyListener(ServiceDiscoveryRegistryDirectory<?> listener) {\n            this.listeners.remove(listener);\n            if (listeners.isEmpty()) {\n                this.stopListen(moduleModel.getApplicationModel().getApplicationName() + CONFIGURATORS_SUFFIX);\n            }\n        }\n\n        @Override\n        protected void notifyOverrides() {\n            listeners.forEach(listener -> {\n                if (listener.originalUrls != null) {\n                    URL backup = RpcContext.getServiceContext().getConsumerUrl();\n                    RpcContext.getServiceContext().setConsumerUrl(listener.getConsumerUrl());\n                    listener.refreshOverrideAndInvoker(listener.originalUrls);\n                    RpcContext.getServiceContext().setConsumerUrl(backup);\n                }\n            });\n        }\n    }\n\n    public static final class ProtocolServiceKeyWithAddress extends ProtocolServiceKey {\n        private final String address;\n\n        public ProtocolServiceKeyWithAddress(ProtocolServiceKey protocolServiceKey, String address) {\n            super(\n                    protocolServiceKey.getInterfaceName(),\n                    protocolServiceKey.getVersion(),\n                    protocolServiceKey.getGroup(),\n                    protocolServiceKey.getProtocol());\n            this.address = address;\n        }\n\n        public String getAddress() {\n            return address;\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            if (!super.equals(o)) {\n                return false;\n            }\n            ProtocolServiceKeyWithAddress that = (ProtocolServiceKeyWithAddress) o;\n            return Objects.equals(address, that.address);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(super.hashCode(), address);\n        }\n    }\n\n    public static final class InstanceWrappedInvoker<T> implements Invoker<T> {\n        private final Invoker<T> originInvoker;\n        private final URL newConsumerUrl;\n        private final ProtocolServiceKey protocolServiceKey;\n\n        public InstanceWrappedInvoker(\n                Invoker<T> originInvoker, URL newConsumerUrl, ProtocolServiceKey protocolServiceKey) {\n            this.originInvoker = originInvoker;\n            this.newConsumerUrl = newConsumerUrl;\n            this.protocolServiceKey = protocolServiceKey;\n        }\n\n        @Override\n        public Class<T> getInterface() {\n            return originInvoker.getInterface();\n        }\n\n        @Override\n        public Result invoke(Invocation invocation) throws RpcException {\n            // override consumer url with real protocol service key\n            RpcContext.getServiceContext().setConsumerUrl(newConsumerUrl);\n            // recreate invocation due to the protocol service key changed\n            RpcInvocation copiedInvocation = new RpcInvocation(\n                    invocation.getTargetServiceUniqueName(),\n                    invocation.getServiceModel(),\n                    invocation.getMethodName(),\n                    invocation.getServiceName(),\n                    protocolServiceKey.toString(),\n                    invocation.getParameterTypes(),\n                    invocation.getArguments(),\n                    invocation.getObjectAttachments(),\n                    invocation.getInvoker(),\n                    invocation.getAttributes(),\n                    invocation instanceof RpcInvocation ? ((RpcInvocation) invocation).getInvokeMode() : null);\n            copiedInvocation.setObjectAttachment(CommonConstants.GROUP_KEY, protocolServiceKey.getGroup());\n            copiedInvocation.setObjectAttachment(CommonConstants.VERSION_KEY, protocolServiceKey.getVersion());\n            // When there are multiple MethodDescriptors with the same method name, the return type will be wrong\n            // same with org.apache.dubbo.rpc.stub.StubInvocationUtil.call\n            // fix https://github.com/apache/dubbo/issues/13931\n            if (invocation instanceof RpcInvocation) {\n                copiedInvocation.setReturnType(((RpcInvocation) invocation).getReturnType());\n            }\n            return originInvoker.invoke(copiedInvocation);\n        }\n\n        @Override\n        public URL getUrl() {\n            RpcContext.getServiceContext().setConsumerUrl(newConsumerUrl);\n            return originInvoker.getUrl();\n        }\n\n        @Override\n        public boolean isAvailable() {\n            RpcContext.getServiceContext().setConsumerUrl(newConsumerUrl);\n            return originInvoker.isAvailable();\n        }\n\n        @Override\n        public void destroy() {\n            RpcContext.getServiceContext().setConsumerUrl(newConsumerUrl);\n            originInvoker.destroy();\n        }\n    }\n\n    @Override\n    public String toString() {\n        return \"ServiceDiscoveryRegistryDirectory(\" + \"registry: \"\n                + getUrl().getAddress() + \", subscribed key: \"\n                + (serviceListener == null || CollectionUtils.isEmpty(serviceListener.getServiceNames())\n                        ? getConsumerUrl().getServiceKey()\n                        : serviceListener.getServiceNames().toString())\n                + \")-\"\n                + super.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.support.AbstractRegistryFactory;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;\nimport static org.apache.dubbo.registry.Constants.DEFAULT_REGISTRY;\n\npublic class ServiceDiscoveryRegistryFactory extends AbstractRegistryFactory {\n\n    @Override\n    protected String createRegistryCacheKey(URL url) {\n        return url.toFullString();\n    }\n\n    @Override\n    protected Registry createRegistry(URL url) {\n        if (UrlUtils.hasServiceDiscoveryRegistryProtocol(url)) {\n            String protocol = url.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY);\n            url = url.setProtocol(protocol).removeParameter(REGISTRY_KEY);\n        }\n        return new ServiceDiscoveryRegistry(url, applicationModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\npublic interface ServiceDiscoveryService {\n    void register() throws RuntimeException;\n\n    void update() throws RuntimeException;\n\n    void unregister() throws RuntimeException;\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceInstance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.beans.Transient;\nimport java.io.Serializable;\nimport java.util.Map;\nimport java.util.SortedMap;\n\n/**\n * The model class of an instance of a service, which is used for service registration and discovery.\n * <p>\n *\n * @since 2.7.5\n */\npublic interface ServiceInstance extends Serializable {\n\n    /**\n     * The name of service that current instance belongs to.\n     *\n     * @return non-null\n     */\n    String getServiceName();\n\n    /**\n     * The hostname of the registered service instance.\n     *\n     * @return non-null\n     */\n    String getHost();\n\n    /**\n     * The port of the registered service instance.\n     *\n     * @return the positive integer if present\n     */\n    int getPort();\n\n    String getAddress();\n\n    /**\n     * The enabled status of the registered service instance.\n     *\n     * @return if <code>true</code>, indicates current instance is enabled, or disable, the client should remove this one.\n     * The default value is <code>true</code>\n     */\n    default boolean isEnabled() {\n        return true;\n    }\n\n    /**\n     * The registered service instance is health or not.\n     *\n     * @return if <code>true</code>, indicates current instance is healthy, or unhealthy, the client may ignore this one.\n     * The default value is <code>true</code>\n     */\n    default boolean isHealthy() {\n        return true;\n    }\n\n    /**\n     * The key / value pair metadata associated with the service instance.\n     *\n     * @return non-null, mutable and unsorted {@link Map}\n     */\n    Map<String, String> getMetadata();\n\n    SortedMap<String, String> getSortedMetadata();\n\n    String getRegistryCluster();\n\n    void setRegistryCluster(String registryCluster);\n\n    Map<String, String> getExtendParams();\n\n    String getExtendParam(String key);\n\n    String putExtendParam(String key, String value);\n\n    String putExtendParamIfAbsent(String key, String value);\n\n    String removeExtendParam(String key);\n\n    Map<String, String> getAllParams();\n\n    void setApplicationModel(ApplicationModel applicationModel);\n\n    @Transient\n    ApplicationModel getApplicationModel();\n\n    @Transient\n    default ApplicationModel getOrDefaultApplicationModel() {\n        return ScopeModelUtil.getApplicationModel(getApplicationModel());\n    }\n\n    /**\n     * Get the value of metadata by the specified name\n     *\n     * @param name the specified name\n     * @return the value of metadata if found, or <code>null</code>\n     * @since 2.7.8\n     */\n    default String getMetadata(String name) {\n        return getMetadata(name, null);\n    }\n\n    /**\n     * Get the value of metadata by the specified name\n     *\n     * @param name the specified name\n     * @return the value of metadata if found, or <code>defaultValue</code>\n     * @since 2.7.8\n     */\n    default String getMetadata(String name, String defaultValue) {\n        return getMetadata().getOrDefault(name, defaultValue);\n    }\n\n    MetadataInfo getServiceMetadata();\n\n    void setServiceMetadata(MetadataInfo serviceMetadata);\n\n    InstanceAddressURL toURL(String protocol);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceInstanceCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport static org.apache.dubbo.common.extension.ExtensionScope.APPLICATION;\n\n/**\n * The interface to customize {@link ServiceInstance the service instance}\n *\n * @see ServiceInstance#getMetadata()\n * @since 2.7.5\n */\n@SPI(scope = APPLICATION)\npublic interface ServiceInstanceCustomizer extends Prioritized {\n\n    /**\n     * Customizes {@link ServiceInstance the service instance}\n     *\n     * @param serviceInstance {@link ServiceInstance the service instance}\n     */\n    void customize(ServiceInstance serviceInstance, ApplicationModel applicationModel);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/RetryServiceInstancesChangedEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.event;\n\nimport java.util.Collections;\n\n/**\n * A retry task when is failed.\n */\npublic class RetryServiceInstancesChangedEvent extends ServiceInstancesChangedEvent {\n\n    private volatile long failureRecordTime;\n\n    public RetryServiceInstancesChangedEvent(String serviceName) {\n        super(serviceName, Collections.emptyList()); // instance list has been stored by ServiceInstancesChangedListener\n        this.failureRecordTime = System.currentTimeMillis();\n    }\n\n    public long getFailureRecordTime() {\n        return failureRecordTime;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/ServiceInstancesChangedEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.event;\n\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport static java.util.Collections.unmodifiableList;\n\n/**\n * An event raised after the {@link ServiceInstance instances} of one service has been changed.\n *\n * @see ServiceInstancesChangedListener\n * @since 2.7.5\n */\npublic class ServiceInstancesChangedEvent {\n\n    private final String serviceName;\n\n    private final List<ServiceInstance> serviceInstances;\n\n    /**\n     * @param serviceName      The name of service that was changed\n     * @param serviceInstances all {@link ServiceInstance service instances}\n     * @throws IllegalArgumentException if source is null.\n     */\n    public ServiceInstancesChangedEvent(String serviceName, List<ServiceInstance> serviceInstances) {\n        this.serviceName = serviceName;\n        this.serviceInstances = unmodifiableList(serviceInstances);\n    }\n\n    protected ServiceInstancesChangedEvent() {\n        this.serviceInstances = Collections.emptyList();\n        this.serviceName = \"\";\n    }\n\n    /**\n     * @return The name of service that was changed\n     */\n    public String getServiceName() {\n        return serviceName;\n    }\n\n    /**\n     * @return all {@link ServiceInstance service instances}\n     */\n    public List<ServiceInstance> getServiceInstances() {\n        return serviceInstances;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.event.listener;\n\nimport org.apache.dubbo.common.ProtocolServiceKey;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataInfo.ServiceInfo;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.registry.event.RegistryEvent;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.RetryServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils;\nimport org.apache.dubbo.registry.client.metadata.ServiceInstanceNotificationCustomizer;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_REFRESH_ADDRESS;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_ENABLE_EMPTY_PROTECTION;\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;\nimport static org.apache.dubbo.metadata.RevisionResolver.EMPTY_REVISION;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getExportedServicesRevision;\n\n/**\n * TODO, refactor to move revision-metadata mapping to ServiceDiscovery. Instances should have already been mapped with metadata when reached here.\n * <p>\n * The operations of ServiceInstancesChangedListener should be synchronized.\n */\npublic class ServiceInstancesChangedListener {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ServiceInstancesChangedListener.class);\n\n    protected final Set<String> serviceNames;\n    protected final ServiceDiscovery serviceDiscovery;\n    protected ConcurrentHashMap<String, Set<NotifyListenerWithKey>> listeners;\n\n    protected AtomicBoolean destroyed = new AtomicBoolean(false);\n\n    protected Map<String, List<ServiceInstance>> allInstances;\n    protected Map<String, List<ProtocolServiceKeyWithUrls>> serviceUrls;\n\n    private volatile long lastRefreshTime;\n    private final Semaphore retryPermission;\n    private volatile ScheduledFuture<?> retryFuture;\n    private final ScheduledExecutorService scheduler;\n    private volatile boolean hasEmptyMetadata;\n    private final Set<ServiceInstanceNotificationCustomizer> serviceInstanceNotificationCustomizers;\n    private final ApplicationModel applicationModel;\n\n    public ServiceInstancesChangedListener(Set<String> serviceNames, ServiceDiscovery serviceDiscovery) {\n        this.serviceNames = serviceNames;\n        this.serviceDiscovery = serviceDiscovery;\n        this.listeners = new ConcurrentHashMap<>();\n        this.allInstances = new HashMap<>();\n        this.serviceUrls = new HashMap<>();\n        retryPermission = new Semaphore(1);\n        ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(\n                serviceDiscovery == null || serviceDiscovery.getUrl() == null\n                        ? null\n                        : serviceDiscovery.getUrl().getScopeModel());\n        this.scheduler = applicationModel\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getMetadataRetryExecutor();\n        this.serviceInstanceNotificationCustomizers = applicationModel\n                .getExtensionLoader(ServiceInstanceNotificationCustomizer.class)\n                .getSupportedExtensionInstances();\n        this.applicationModel = applicationModel;\n    }\n\n    /**\n     * On {@link ServiceInstancesChangedEvent the service instances change event}\n     *\n     * @param event {@link ServiceInstancesChangedEvent}\n     */\n    public void onEvent(ServiceInstancesChangedEvent event) {\n        if (destroyed.get() || !accept(event) || isRetryAndExpired(event)) {\n            return;\n        }\n        doOnEvent(event);\n    }\n\n    /**\n     * @param event\n     */\n    private synchronized void doOnEvent(ServiceInstancesChangedEvent event) {\n        if (destroyed.get() || !accept(event) || isRetryAndExpired(event)) {\n            return;\n        }\n\n        refreshInstance(event);\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(event.getServiceInstances().toString());\n        }\n\n        Map<String, List<ServiceInstance>> revisionToInstances = new HashMap<>();\n        Map<ServiceInfo, Set<String>> localServiceToRevisions = new HashMap<>();\n\n        // grouping all instances of this app(service name) by revision\n        for (Map.Entry<String, List<ServiceInstance>> entry : allInstances.entrySet()) {\n            List<ServiceInstance> instances = entry.getValue();\n            for (ServiceInstance instance : instances) {\n                String revision = getExportedServicesRevision(instance);\n                if (revision == null || EMPTY_REVISION.equals(revision)) {\n                    if (logger.isDebugEnabled()) {\n                        logger.debug(\"Find instance without valid service metadata: \" + instance.getAddress());\n                    }\n                    continue;\n                }\n                List<ServiceInstance> subInstances =\n                        revisionToInstances.computeIfAbsent(revision, r -> new LinkedList<>());\n                subInstances.add(instance);\n            }\n        }\n\n        // get MetadataInfo with revision\n        for (Map.Entry<String, List<ServiceInstance>> entry : revisionToInstances.entrySet()) {\n            String revision = entry.getKey();\n            List<ServiceInstance> subInstances = entry.getValue();\n\n            MetadataInfo metadata = subInstances.stream()\n                    .map(ServiceInstance::getServiceMetadata)\n                    .filter(Objects::nonNull)\n                    .filter(m -> revision.equals(m.getRevision()))\n                    .findFirst()\n                    .orElseGet(() -> serviceDiscovery.getRemoteMetadata(revision, subInstances));\n\n            parseMetadata(revision, metadata, localServiceToRevisions);\n            // update metadata into each instance, in case new instance created.\n            for (ServiceInstance tmpInstance : subInstances) {\n                MetadataInfo originMetadata = tmpInstance.getServiceMetadata();\n                if (originMetadata == null || !Objects.equals(originMetadata.getRevision(), metadata.getRevision())) {\n                    tmpInstance.setServiceMetadata(metadata);\n                }\n            }\n        }\n\n        int emptyNum = hasEmptyMetadata(revisionToInstances);\n        if (emptyNum != 0) {\n            hasEmptyMetadata = true;\n\n            // return if all metadata is empty, this notification will not take effect.\n            if (emptyNum == revisionToInstances.size()) {\n                // 1-17 - Address refresh failed.\n                logger.error(\n                        REGISTRY_FAILED_REFRESH_ADDRESS,\n                        \"metadata Server failure\",\n                        \"\",\n                        \"Address refresh failed because of Metadata Server failure, wait for retry or new address refresh event.\");\n\n                submitRetryTask(event);\n                return;\n            }\n        } else {\n            hasEmptyMetadata = false;\n        }\n\n        Map<String, Map<Integer, Map<Set<String>, Object>>> protocolRevisionsToUrls = new HashMap<>();\n        Map<String, List<ProtocolServiceKeyWithUrls>> newServiceUrls = new HashMap<>();\n        for (Map.Entry<ServiceInfo, Set<String>> entry : localServiceToRevisions.entrySet()) {\n            ServiceInfo serviceInfo = entry.getKey();\n            Set<String> revisions = entry.getValue();\n\n            Map<Integer, Map<Set<String>, Object>> portToRevisions =\n                    protocolRevisionsToUrls.computeIfAbsent(serviceInfo.getProtocol(), k -> new HashMap<>());\n            Map<Set<String>, Object> revisionsToUrls =\n                    portToRevisions.computeIfAbsent(serviceInfo.getPort(), k -> new HashMap<>());\n            Object urls = revisionsToUrls.computeIfAbsent(\n                    revisions,\n                    k -> getServiceUrlsCache(\n                            revisionToInstances, revisions, serviceInfo.getProtocol(), serviceInfo.getPort()));\n\n            List<ProtocolServiceKeyWithUrls> list =\n                    newServiceUrls.computeIfAbsent(serviceInfo.getPath(), k -> new LinkedList<>());\n            list.add(new ProtocolServiceKeyWithUrls(serviceInfo.getProtocolServiceKey(), (List<URL>) urls));\n        }\n\n        this.serviceUrls = newServiceUrls;\n        this.notifyAddressChanged();\n\n        if (hasEmptyMetadata) {\n            submitRetryTask(event);\n        }\n    }\n\n    private void submitRetryTask(ServiceInstancesChangedEvent event) {\n        // retry every 10 seconds\n        if (retryPermission.tryAcquire()) {\n            if (retryFuture != null && !retryFuture.isDone()) {\n                // cancel last retryFuture because only one retryFuture will be canceled at destroy().\n                retryFuture.cancel(true);\n            }\n            try {\n                retryFuture = scheduler.schedule(\n                        new AddressRefreshRetryTask(retryPermission, event.getServiceName()),\n                        10_000L,\n                        TimeUnit.MILLISECONDS);\n            } catch (Exception e) {\n                logger.error(\n                        INTERNAL_ERROR, \"unknown error in registry module\", \"\", \"Error submitting async retry task.\");\n            }\n            logger.warn(INTERNAL_ERROR, \"unknown error in registry module\", \"\", \"Address refresh try task submitted\");\n        }\n    }\n\n    public synchronized void addListenerAndNotify(URL url, NotifyListener listener) {\n        if (destroyed.get()) {\n            return;\n        }\n\n        Set<NotifyListenerWithKey> notifyListeners = ConcurrentHashMapUtils.computeIfAbsent(\n                this.listeners, url.getServiceKey(), _k -> new ConcurrentHashSet<>());\n        String protocol = listener.getConsumerUrl().getParameter(PROTOCOL_KEY, url.getProtocol());\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(\n                url.getServiceInterface(),\n                url.getVersion(),\n                url.getGroup(),\n                !CommonConstants.CONSUMER.equals(protocol) ? protocol : null);\n        NotifyListenerWithKey listenerWithKey = new NotifyListenerWithKey(protocolServiceKey, listener);\n        notifyListeners.add(listenerWithKey);\n\n        // Aggregate address and notify on subscription.\n        List<URL> urls = getAddresses(protocolServiceKey, listener.getConsumerUrl());\n\n        if (CollectionUtils.isNotEmpty(urls)) {\n            logger.info(String.format(\n                    \"Notify serviceKey: %s, listener: %s with %s urls on subscription\",\n                    protocolServiceKey, listener, urls.size()));\n            listener.notify(urls);\n        }\n    }\n\n    public synchronized void removeListener(String serviceKey, NotifyListener notifyListener) {\n        if (destroyed.get()) {\n            return;\n        }\n\n        // synchronized method, no need to use DCL\n        Set<NotifyListenerWithKey> notifyListeners = this.listeners.get(serviceKey);\n        if (notifyListeners != null) {\n            notifyListeners.removeIf(listener -> listener.getNotifyListener().equals(notifyListener));\n\n            // ServiceKey has no listener, remove set\n            if (notifyListeners.isEmpty()) {\n                this.listeners.remove(serviceKey);\n            }\n        }\n    }\n\n    public boolean hasListeners() {\n        return CollectionUtils.isNotEmptyMap(listeners);\n    }\n\n    /**\n     * Get the correlative service name\n     *\n     * @return the correlative service name\n     */\n    public final Set<String> getServiceNames() {\n        return serviceNames;\n    }\n\n    public Map<String, List<ServiceInstance>> getAllInstances() {\n        return allInstances;\n    }\n\n    /**\n     * @param event {@link ServiceInstancesChangedEvent event}\n     * @return If service name matches, return <code>true</code>, or <code>false</code>\n     */\n    private boolean accept(ServiceInstancesChangedEvent event) {\n        return serviceNames.contains(event.getServiceName());\n    }\n\n    protected boolean isRetryAndExpired(ServiceInstancesChangedEvent event) {\n        if (event instanceof RetryServiceInstancesChangedEvent) {\n            RetryServiceInstancesChangedEvent retryEvent = (RetryServiceInstancesChangedEvent) event;\n            logger.warn(\n                    INTERNAL_ERROR,\n                    \"unknown error in registry module\",\n                    \"\",\n                    \"Received address refresh retry event, \" + retryEvent.getFailureRecordTime());\n            if (retryEvent.getFailureRecordTime() < lastRefreshTime && !hasEmptyMetadata) {\n                logger.warn(\n                        INTERNAL_ERROR,\n                        \"unknown error in registry module\",\n                        \"\",\n                        \"Ignore retry event, event time: \" + retryEvent.getFailureRecordTime() + \", last refresh time: \"\n                                + lastRefreshTime);\n                return true;\n            }\n            logger.warn(INTERNAL_ERROR, \"unknown error in registry module\", \"\", \"Retrying address notification...\");\n        }\n        return false;\n    }\n\n    private void refreshInstance(ServiceInstancesChangedEvent event) {\n        if (event instanceof RetryServiceInstancesChangedEvent) {\n            return;\n        }\n        String appName = event.getServiceName();\n        List<ServiceInstance> appInstances = event.getServiceInstances();\n        logger.info(\"Received instance notification, serviceName: \" + appName + \", instances: \" + appInstances.size());\n        for (ServiceInstanceNotificationCustomizer serviceInstanceNotificationCustomizer :\n                serviceInstanceNotificationCustomizers) {\n            serviceInstanceNotificationCustomizer.customize(appInstances);\n        }\n        allInstances.put(appName, appInstances);\n        lastRefreshTime = System.currentTimeMillis();\n    }\n\n    /**\n     * Calculate the number of revisions that failed to find metadata info.\n     *\n     * @param revisionToInstances instance list classified by revisions\n     * @return the number of revisions that failed at fetching MetadataInfo\n     */\n    protected int hasEmptyMetadata(Map<String, List<ServiceInstance>> revisionToInstances) {\n        if (revisionToInstances == null) {\n            return 0;\n        }\n\n        StringBuilder builder = new StringBuilder();\n        int emptyMetadataNum = 0;\n        for (Map.Entry<String, List<ServiceInstance>> entry : revisionToInstances.entrySet()) {\n            DefaultServiceInstance serviceInstance =\n                    (DefaultServiceInstance) entry.getValue().get(0);\n            if (serviceInstance == null || serviceInstance.getServiceMetadata() == MetadataInfo.EMPTY) {\n                emptyMetadataNum++;\n            }\n\n            builder.append(entry.getKey());\n            builder.append(' ');\n        }\n\n        if (emptyMetadataNum > 0) {\n            builder.insert(\n                    0,\n                    emptyMetadataNum + \"/\" + revisionToInstances.size()\n                            + \" revisions failed to get metadata from remote: \");\n            logger.error(INTERNAL_ERROR, \"unknown error in registry module\", \"\", builder.toString());\n        } else {\n            builder.insert(0, revisionToInstances.size() + \" unique working revisions: \");\n            logger.info(builder.toString());\n        }\n        return emptyMetadataNum;\n    }\n\n    protected Map<ServiceInfo, Set<String>> parseMetadata(\n            String revision, MetadataInfo metadata, Map<ServiceInfo, Set<String>> localServiceToRevisions) {\n        Map<String, ServiceInfo> serviceInfos = metadata.getServices();\n        for (Map.Entry<String, ServiceInfo> entry : serviceInfos.entrySet()) {\n            Set<String> set = localServiceToRevisions.computeIfAbsent(entry.getValue(), _k -> new TreeSet<>());\n            set.add(revision);\n        }\n\n        return localServiceToRevisions;\n    }\n\n    protected Object getServiceUrlsCache(\n            Map<String, List<ServiceInstance>> revisionToInstances, Set<String> revisions, String protocol, int port) {\n        List<URL> urls = new ArrayList<>();\n        for (String r : revisions) {\n            for (ServiceInstance i : revisionToInstances.get(r)) {\n                if (port > 0) {\n                    if (i.getPort() == port) {\n                        urls.add(i.toURL(protocol).setScopeModel(i.getApplicationModel()));\n                    } else {\n                        urls.add(((DefaultServiceInstance) i)\n                                .copyFrom(port)\n                                .toURL(protocol)\n                                .setScopeModel(i.getApplicationModel()));\n                    }\n                    continue;\n                }\n                // different protocols may have ports specified in meta\n                if (ServiceInstanceMetadataUtils.hasEndpoints(i)) {\n                    DefaultServiceInstance.Endpoint endpoint = ServiceInstanceMetadataUtils.getEndpoint(i, protocol);\n                    if (endpoint != null && endpoint.getPort() != i.getPort()) {\n                        urls.add(((DefaultServiceInstance) i).copyFrom(endpoint).toURL(endpoint.getProtocol()));\n                        continue;\n                    }\n                }\n                urls.add(i.toURL(protocol).setScopeModel(i.getApplicationModel()));\n            }\n        }\n        return urls;\n    }\n\n    protected List<URL> getAddresses(ProtocolServiceKey protocolServiceKey, URL consumerURL) {\n        List<ProtocolServiceKeyWithUrls> protocolServiceKeyWithUrlsList =\n                serviceUrls.get(protocolServiceKey.getInterfaceName());\n        List<URL> urls = new ArrayList<>();\n        if (protocolServiceKeyWithUrlsList != null) {\n            for (ProtocolServiceKeyWithUrls protocolServiceKeyWithUrls : protocolServiceKeyWithUrlsList) {\n                if (ProtocolServiceKey.Matcher.isMatch(\n                        protocolServiceKey, protocolServiceKeyWithUrls.getProtocolServiceKey())) {\n                    urls.addAll(protocolServiceKeyWithUrls.getUrls());\n                }\n            }\n        }\n        if (serviceUrls.containsKey(CommonConstants.ANY_VALUE)) {\n            for (ProtocolServiceKeyWithUrls protocolServiceKeyWithUrls : serviceUrls.get(CommonConstants.ANY_VALUE)) {\n                urls.addAll(protocolServiceKeyWithUrls.getUrls());\n            }\n        }\n        return urls;\n    }\n\n    /**\n     * race condition is protected by onEvent/doOnEvent\n     */\n    protected void notifyAddressChanged() {\n\n        MetricsEventBus.post(RegistryEvent.toNotifyEvent(applicationModel), () -> {\n            Map<String, Integer> lastNumMap = new HashMap<>();\n            // 1 different services\n            listeners.forEach((serviceKey, listenerSet) -> {\n                // 2 multiple subscription listener of the same service\n                for (NotifyListenerWithKey listenerWithKey : listenerSet) {\n                    NotifyListener notifyListener = listenerWithKey.getNotifyListener();\n\n                    List<URL> urls = toUrlsWithEmpty(\n                            getAddresses(listenerWithKey.getProtocolServiceKey(), notifyListener.getConsumerUrl()));\n                    logger.info(\n                            \"Notify service \" + listenerWithKey.getProtocolServiceKey() + \" with urls \" + urls.size());\n                    notifyListener.notify(urls);\n                    lastNumMap.put(serviceKey, urls.size());\n                }\n            });\n            return lastNumMap;\n        });\n    }\n\n    protected List<URL> toUrlsWithEmpty(List<URL> urls) {\n        boolean emptyProtectionEnabled =\n                serviceDiscovery.getUrl().getParameter(ENABLE_EMPTY_PROTECTION_KEY, DEFAULT_ENABLE_EMPTY_PROTECTION);\n        if (!emptyProtectionEnabled && urls == null) {\n            urls = new ArrayList<>();\n        } else if (emptyProtectionEnabled && urls == null) {\n            urls = Collections.emptyList();\n        }\n\n        if (CollectionUtils.isEmpty(urls) && !emptyProtectionEnabled) {\n            // notice that the service of this.url may not be the same as notify listener.\n            URL empty = URLBuilder.from(serviceDiscovery.getUrl())\n                    .setProtocol(EMPTY_PROTOCOL)\n                    .build();\n            urls.add(empty);\n        }\n        return urls;\n    }\n\n    /**\n     * Since this listener is shared among interfaces, destroy this listener only when all interface listener are unsubscribed\n     */\n    public void destroy() {\n        if (destroyed.compareAndSet(false, true)) {\n            logger.info(\"Destroying instance listener of  \" + this.getServiceNames());\n            serviceDiscovery.removeServiceInstancesChangedListener(this);\n            synchronized (this) {\n                allInstances.clear();\n                serviceUrls.clear();\n                listeners.clear();\n                if (retryFuture != null && !retryFuture.isDone()) {\n                    retryFuture.cancel(true);\n                }\n            }\n        }\n    }\n\n    public boolean isDestroyed() {\n        return destroyed.get();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (!(o instanceof ServiceInstancesChangedListener)) {\n            return false;\n        }\n        ServiceInstancesChangedListener that = (ServiceInstancesChangedListener) o;\n        return Objects.equals(getServiceNames(), that.getServiceNames()) && Objects.equals(listeners, that.listeners);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(getClass(), getServiceNames());\n    }\n\n    protected class AddressRefreshRetryTask implements Runnable {\n        private final RetryServiceInstancesChangedEvent retryEvent;\n        private final Semaphore retryPermission;\n\n        public AddressRefreshRetryTask(Semaphore semaphore, String serviceName) {\n            this.retryEvent = new RetryServiceInstancesChangedEvent(serviceName);\n            this.retryPermission = semaphore;\n        }\n\n        @Override\n        public void run() {\n            retryPermission.release();\n            ServiceInstancesChangedListener.this.onEvent(retryEvent);\n        }\n    }\n\n    public static class NotifyListenerWithKey {\n        private final ProtocolServiceKey protocolServiceKey;\n        private final NotifyListener notifyListener;\n\n        public NotifyListenerWithKey(ProtocolServiceKey protocolServiceKey, NotifyListener notifyListener) {\n            this.protocolServiceKey = protocolServiceKey;\n            this.notifyListener = notifyListener;\n        }\n\n        public ProtocolServiceKey getProtocolServiceKey() {\n            return protocolServiceKey;\n        }\n\n        public NotifyListener getNotifyListener() {\n            return notifyListener;\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            NotifyListenerWithKey that = (NotifyListenerWithKey) o;\n            return Objects.equals(protocolServiceKey, that.protocolServiceKey)\n                    && Objects.equals(notifyListener, that.notifyListener);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(protocolServiceKey, notifyListener);\n        }\n    }\n\n    public static class ProtocolServiceKeyWithUrls {\n        private final ProtocolServiceKey protocolServiceKey;\n        private final List<URL> urls;\n\n        public ProtocolServiceKeyWithUrls(ProtocolServiceKey protocolServiceKey, List<URL> urls) {\n            this.protocolServiceKey = protocolServiceKey;\n            this.urls = urls;\n        }\n\n        public ProtocolServiceKey getProtocolServiceKey() {\n            return protocolServiceKey;\n        }\n\n        public List<URL> getUrls() {\n            return urls;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.resource.Disposable;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.InstanceMetadataChangedListener;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.support.RegistryManager;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.exception.HttpStatusException;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIService;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.protocol.tri.TripleProtocol;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static java.util.Collections.emptySortedSet;\nimport static java.util.Collections.unmodifiableSortedSet;\nimport static org.apache.dubbo.common.URL.buildKey;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_LOAD_METADATA;\nimport static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;\n\n/**\n * Implementation providing remote RPC service to facilitate the query of metadata information.\n */\npublic class MetadataServiceDelegation implements MetadataService, Disposable {\n    ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private final ApplicationModel applicationModel;\n    private final RegistryManager registryManager;\n    private final ConcurrentMap<String, InstanceMetadataChangedListener> instanceMetadataChangedListenerMap =\n            new ConcurrentHashMap<>();\n    private URL url;\n    // works only for DNS service discovery\n    private String instanceMetadata;\n\n    public static final String VERSION = \"1.0.0\";\n\n    public MetadataServiceDelegation(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        registryManager = RegistryManager.getInstance(applicationModel);\n    }\n\n    /**\n     * Gets the current Dubbo Service name\n     *\n     * @return non-null\n     */\n    @Override\n    public String serviceName() {\n        return ApplicationModel.ofNullable(applicationModel).getApplicationName();\n    }\n\n    @Override\n    public URL getMetadataURL() {\n        return url;\n    }\n\n    public void setMetadataURL(URL url) {\n        this.url = url;\n    }\n\n    @Override\n    public SortedSet<String> getSubscribedURLs() {\n        return getAllUnmodifiableSubscribedURLs();\n    }\n\n    private SortedSet<String> getAllUnmodifiableServiceURLs() {\n        SortedSet<URL> bizURLs = new TreeSet<>(URLComparator.INSTANCE);\n        List<ServiceDiscovery> serviceDiscoveries = registryManager.getServiceDiscoveries();\n        for (ServiceDiscovery sd : serviceDiscoveries) {\n            MetadataInfo metadataInfo = sd.getLocalMetadata();\n            Map<String, SortedSet<URL>> serviceURLs = metadataInfo.getExportedServiceURLs();\n            joinNonMetadataServiceUrls(bizURLs, serviceURLs);\n        }\n        return MetadataService.toSortedStrings(bizURLs);\n    }\n\n    private void joinNonMetadataServiceUrls(SortedSet<URL> bizURLs, Map<String, SortedSet<URL>> serviceURLs) {\n        if (serviceURLs == null) {\n            return;\n        }\n        for (Map.Entry<String, SortedSet<URL>> entry : serviceURLs.entrySet()) {\n            SortedSet<URL> urls = entry.getValue();\n            if (urls != null) {\n                for (URL url : urls) {\n                    if (!MetadataService.class.getName().equals(url.getServiceInterface())) {\n                        bizURLs.add(url);\n                    }\n                }\n            }\n        }\n    }\n\n    private SortedSet<String> getAllUnmodifiableSubscribedURLs() {\n        SortedSet<URL> bizURLs = new TreeSet<>(URLComparator.INSTANCE);\n        List<ServiceDiscovery> serviceDiscoveries = registryManager.getServiceDiscoveries();\n        for (ServiceDiscovery sd : serviceDiscoveries) {\n            MetadataInfo metadataInfo = sd.getLocalMetadata();\n            Map<String, SortedSet<URL>> serviceURLs = metadataInfo.getSubscribedServiceURLs();\n            joinNonMetadataServiceUrls(bizURLs, serviceURLs);\n        }\n        return MetadataService.toSortedStrings(bizURLs);\n    }\n\n    @Override\n    public SortedSet<String> getExportedURLs(String serviceInterface, String group, String version, String protocol) {\n        if (ALL_SERVICE_INTERFACES.equals(serviceInterface)) {\n            return getAllUnmodifiableServiceURLs();\n        }\n        String serviceKey = buildKey(serviceInterface, group, version);\n        return unmodifiableSortedSet(getServiceURLs(getAllServiceURLs(), serviceKey, protocol));\n    }\n\n    private Map<String, SortedSet<URL>> getAllServiceURLs() {\n        List<ServiceDiscovery> serviceDiscoveries = registryManager.getServiceDiscoveries();\n        Map<String, SortedSet<URL>> allServiceURLs = new HashMap<>();\n        for (ServiceDiscovery sd : serviceDiscoveries) {\n            MetadataInfo metadataInfo = sd.getLocalMetadata();\n            Map<String, SortedSet<URL>> serviceURLs = metadataInfo.getExportedServiceURLs();\n            allServiceURLs.putAll(serviceURLs);\n        }\n        return allServiceURLs;\n    }\n\n    @Override\n    public Set<URL> getExportedServiceURLs() {\n        Set<URL> set = new HashSet<>();\n        registryManager.getRegistries();\n        for (Map.Entry<String, SortedSet<URL>> entry : getAllServiceURLs().entrySet()) {\n            set.addAll(entry.getValue());\n        }\n        return set;\n    }\n\n    @Override\n    public String getServiceDefinition(String interfaceName, String version, String group) {\n        return \"\";\n    }\n\n    @Override\n    public String getServiceDefinition(String serviceKey) {\n        return \"\";\n    }\n\n    @Override\n    public MetadataInfo getMetadataInfo(String revision) {\n        if (StringUtils.isEmpty(revision)) {\n            return null;\n        }\n\n        for (ServiceDiscovery sd : registryManager.getServiceDiscoveries()) {\n            MetadataInfo metadataInfo = sd.getLocalMetadata(revision);\n            if (metadataInfo != null && revision.equals(metadataInfo.getRevision())) {\n                return metadataInfo;\n            }\n        }\n\n        if (logger.isWarnEnabled()) {\n            logger.warn(REGISTRY_FAILED_LOAD_METADATA, \"\", \"\", \"metadata not found for revision: \" + revision);\n        }\n        return null;\n    }\n\n    @Override\n    public List<MetadataInfo> getMetadataInfos() {\n        List<MetadataInfo> metadataInfos = new ArrayList<>();\n        for (ServiceDiscovery sd : registryManager.getServiceDiscoveries()) {\n            metadataInfos.add(sd.getLocalMetadata());\n        }\n        return metadataInfos;\n    }\n\n    @Override\n    public void exportInstanceMetadata(String instanceMetadata) {\n        this.instanceMetadata = instanceMetadata;\n    }\n\n    @Override\n    public Map<String, InstanceMetadataChangedListener> getInstanceMetadataChangedListenerMap() {\n        return instanceMetadataChangedListenerMap;\n    }\n\n    @Override\n    public String getAndListenInstanceMetadata(String consumerId, InstanceMetadataChangedListener listener) {\n        instanceMetadataChangedListenerMap.put(consumerId, listener);\n        return instanceMetadata;\n    }\n\n    @Override\n    public String getOpenAPI(OpenAPIRequest request) {\n        if (TripleProtocol.OPENAPI_ENABLED) {\n            OpenAPIService openAPIService = applicationModel.getBean(OpenAPIService.class);\n            if (openAPIService != null) {\n                return openAPIService.getDocument(request);\n            }\n        }\n\n        throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode(), \"OpenAPI is not available\");\n    }\n\n    private SortedSet<String> getServiceURLs(\n            Map<String, SortedSet<URL>> exportedServiceURLs, String serviceKey, String protocol) {\n\n        SortedSet<URL> serviceURLs = exportedServiceURLs.get(serviceKey);\n\n        if (isEmpty(serviceURLs)) {\n            return emptySortedSet();\n        }\n\n        return MetadataService.toSortedStrings(serviceURLs.stream().filter(url -> isAcceptableProtocol(protocol, url)));\n    }\n\n    private boolean isAcceptableProtocol(String protocol, URL url) {\n        return protocol == null\n                || protocol.equals(url.getParameter(PROTOCOL_KEY))\n                || protocol.equals(url.getProtocol());\n    }\n\n    @Override\n    public void destroy() {}\n\n    static class URLComparator implements Comparator<URL> {\n\n        public static final URLComparator INSTANCE = new URLComparator();\n\n        @Override\n        public int compare(URL o1, URL o2) {\n            return o1.toFullString().compareTo(o2.toFullString());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.DubboMetadataServiceV2Triple.MetadataServiceV2ImplBase;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataRequest;\nimport org.apache.dubbo.metadata.OpenAPIFormat;\nimport org.apache.dubbo.metadata.OpenAPIInfo;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.support.RegistryManager;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\nimport org.apache.dubbo.remoting.http12.exception.HttpStatusException;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIRequest;\nimport org.apache.dubbo.remoting.http12.rest.OpenAPIService;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.protocol.tri.TripleProtocol;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_LOAD_METADATA;\nimport static org.apache.dubbo.metadata.util.MetadataServiceVersionUtils.toV2;\n\npublic class MetadataServiceDelegationV2 extends MetadataServiceV2ImplBase {\n\n    ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private final FrameworkModel frameworkModel;\n    private final RegistryManager registryManager;\n\n    private URL metadataUrl;\n\n    public static final String VERSION = \"2.0.0\";\n\n    public MetadataServiceDelegationV2(ApplicationModel applicationModel) {\n        frameworkModel = applicationModel.getFrameworkModel();\n        registryManager = RegistryManager.getInstance(applicationModel);\n    }\n\n    @Override\n    public org.apache.dubbo.metadata.MetadataInfoV2 getMetadataInfo(MetadataRequest metadataRequestV2) {\n        String revision = metadataRequestV2.getRevision();\n        MetadataInfo info;\n        if (StringUtils.isEmpty(revision)) {\n            return null;\n        }\n\n        for (ServiceDiscovery sd : registryManager.getServiceDiscoveries()) {\n            info = sd.getLocalMetadata(revision);\n\n            if (info != null && revision.equals(info.getRevision())) {\n                return toV2(info);\n            }\n        }\n\n        if (logger.isWarnEnabled()) {\n            logger.warn(\n                    REGISTRY_FAILED_LOAD_METADATA, \"\", \"\", \"metadataV2 not found for revision: \" + metadataRequestV2);\n        }\n        return null;\n    }\n\n    @Override\n    public OpenAPIInfo getOpenAPIInfo(org.apache.dubbo.metadata.OpenAPIRequest request) {\n        if (TripleProtocol.OPENAPI_ENABLED) {\n            OpenAPIService openAPIService = frameworkModel.getBean(OpenAPIService.class);\n            if (openAPIService != null) {\n                OpenAPIRequest oRequest = new OpenAPIRequest();\n                oRequest.setGroup(request.getGroup());\n                oRequest.setVersion(request.getVersion());\n                oRequest.setTag(request.getTagList().toArray(StringUtils.EMPTY_STRING_ARRAY));\n                oRequest.setService(request.getServiceList().toArray(StringUtils.EMPTY_STRING_ARRAY));\n                oRequest.setOpenapi(request.getOpenapi());\n                OpenAPIFormat format = request.getFormat();\n                if (request.hasFormat()) {\n                    oRequest.setFormat(format.name());\n                }\n                if (request.hasPretty()) {\n                    oRequest.setPretty(request.getPretty());\n                }\n                String document = openAPIService.getDocument(oRequest);\n                return OpenAPIInfo.newBuilder().setDefinition(document).build();\n            }\n        }\n\n        throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode(), \"OpenAPI is not available\");\n    }\n\n    public URL getMetadataUrl() {\n        return metadataUrl;\n    }\n\n    public void setMetadataUrl(URL metadataUrl) {\n        this.metadataUrl = metadataUrl;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.AbstractServiceNameMapping;\nimport org.apache.dubbo.metadata.MappingListener;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.MetadataReportInstance;\nimport org.apache.dubbo.registry.client.RegistryClusterIdentifier;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ThreadLocalRandom;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_PROPERTY_TYPE_MISMATCH;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.registry.Constants.CAS_RETRY_TIMES_KEY;\nimport static org.apache.dubbo.registry.Constants.CAS_RETRY_WAIT_TIME_KEY;\nimport static org.apache.dubbo.registry.Constants.DEFAULT_CAS_RETRY_TIMES;\nimport static org.apache.dubbo.registry.Constants.DEFAULT_CAS_RETRY_WAIT_TIME;\n\npublic class MetadataServiceNameMapping extends AbstractServiceNameMapping {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private static final List<String> IGNORED_SERVICE_INTERFACES =\n            Collections.singletonList(MetadataService.class.getName());\n\n    private final int casRetryTimes;\n    private final int casRetryWaitTime;\n    protected MetadataReportInstance metadataReportInstance;\n\n    public MetadataServiceNameMapping(ApplicationModel applicationModel) {\n        super(applicationModel);\n        metadataReportInstance = applicationModel.getBeanFactory().getBean(MetadataReportInstance.class);\n        casRetryTimes = ConfigurationUtils.getGlobalConfiguration(applicationModel)\n                .getInt(CAS_RETRY_TIMES_KEY, DEFAULT_CAS_RETRY_TIMES);\n        casRetryWaitTime = ConfigurationUtils.getGlobalConfiguration(applicationModel)\n                .getInt(CAS_RETRY_WAIT_TIME_KEY, DEFAULT_CAS_RETRY_WAIT_TIME);\n    }\n\n    @Override\n    public boolean hasValidMetadataCenter() {\n        return !CollectionUtils.isEmpty(\n                applicationModel.getApplicationConfigManager().getMetadataConfigs());\n    }\n\n    /**\n     * Simply register to all metadata center\n     */\n    @Override\n    public boolean map(URL url) {\n        if (CollectionUtils.isEmpty(\n                applicationModel.getApplicationConfigManager().getMetadataConfigs())) {\n            logger.warn(\n                    COMMON_PROPERTY_TYPE_MISMATCH,\n                    \"\",\n                    \"\",\n                    \"[METADATA_REGISTER] No valid metadata config center found for mapping report.\");\n            return false;\n        }\n        String serviceInterface = url.getServiceInterface();\n        if (IGNORED_SERVICE_INTERFACES.contains(serviceInterface)) {\n            return true;\n        }\n\n        boolean result = true;\n        for (Map.Entry<String, MetadataReport> entry :\n                metadataReportInstance.getMetadataReports(true).entrySet()) {\n            MetadataReport metadataReport = entry.getValue();\n            String appName = applicationModel.getApplicationName();\n            try {\n                if (metadataReport.registerServiceAppMapping(serviceInterface, appName, url)) {\n                    // MetadataReport support directly register service-app mapping\n                    continue;\n                }\n\n                boolean succeeded = false;\n                int currentRetryTimes = 1;\n                String newConfigContent = appName;\n                do {\n                    ConfigItem configItem = metadataReport.getConfigItem(serviceInterface, DEFAULT_MAPPING_GROUP);\n                    String oldConfigContent = configItem.getContent();\n                    if (StringUtils.isNotEmpty(oldConfigContent)) {\n                        String[] oldAppNames = oldConfigContent.split(\",\");\n                        if (oldAppNames.length > 0) {\n                            for (String oldAppName : oldAppNames) {\n                                if (StringUtils.trim(oldAppName).equals(appName)) {\n                                    succeeded = true;\n                                    break;\n                                }\n                            }\n                        }\n                        if (succeeded) {\n                            break;\n                        }\n                        newConfigContent = oldConfigContent + COMMA_SEPARATOR + appName;\n                    }\n                    succeeded = metadataReport.registerServiceAppMapping(\n                            serviceInterface, DEFAULT_MAPPING_GROUP, newConfigContent, configItem.getTicket());\n                    if (!succeeded) {\n                        int waitTime = ThreadLocalRandom.current().nextInt(casRetryWaitTime);\n                        logger.info(\"Failed to publish service name mapping to metadata center by cas operation. \"\n                                + \"Times: \"\n                                + currentRetryTimes + \". \" + \"Next retry delay: \"\n                                + waitTime + \". \" + \"Service Interface: \"\n                                + serviceInterface + \". \" + \"Origin Content: \"\n                                + oldConfigContent + \". \" + \"Ticket: \"\n                                + configItem.getTicket() + \". \" + \"Expected Content: \"\n                                + newConfigContent);\n                        Thread.sleep(waitTime);\n                    }\n                } while (!succeeded && currentRetryTimes++ <= casRetryTimes);\n\n                if (!succeeded) {\n                    result = false;\n                }\n            } catch (Exception e) {\n                result = false;\n                logger.warn(\n                        INTERNAL_ERROR,\n                        \"unknown error in registry module\",\n                        \"\",\n                        \"Failed registering mapping to remote.\" + metadataReport,\n                        e);\n            }\n        }\n\n        return result;\n    }\n\n    @Override\n    public Set<String> get(URL url) {\n        String serviceInterface = url.getServiceInterface();\n        String registryCluster = getRegistryCluster(url);\n        MetadataReport metadataReport = metadataReportInstance.getMetadataReport(registryCluster);\n        if (metadataReport == null) {\n            return Collections.emptySet();\n        }\n        return metadataReport.getServiceAppMapping(serviceInterface, url);\n    }\n\n    @Override\n    public Set<String> getAndListen(URL url, MappingListener mappingListener) {\n        String serviceInterface = url.getServiceInterface();\n        // randomly pick one metadata report is ok for it's guaranteed all metadata report will have the same mapping\n        // data.\n        String registryCluster = getRegistryCluster(url);\n        MetadataReport metadataReport = metadataReportInstance.getMetadataReport(registryCluster);\n        if (metadataReport == null) {\n            return Collections.emptySet();\n        }\n        return metadataReport.getServiceAppMapping(serviceInterface, mappingListener, url);\n    }\n\n    @Override\n    protected void removeListener(URL url, MappingListener mappingListener) {\n        String serviceInterface = url.getServiceInterface();\n        // randomly pick one metadata report is ok for it's guaranteed each metadata report will have the same mapping\n        // content.\n        String registryCluster = getRegistryCluster(url);\n        MetadataReport metadataReport = metadataReportInstance.getMetadataReport(registryCluster);\n        if (metadataReport == null) {\n            return;\n        }\n        metadataReport.removeServiceAppMappingListener(serviceInterface, mappingListener);\n    }\n\n    protected String getRegistryCluster(URL url) {\n        String registryCluster = RegistryClusterIdentifier.getExtension(url).providerKey(url);\n        if (registryCluster == null) {\n            registryCluster = DEFAULT_KEY;\n        }\n        int i = registryCluster.indexOf(\",\");\n        if (i > 0) {\n            registryCluster = registryCluster.substring(0, i);\n        }\n        return registryCluster;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceURLBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.registry.client.ServiceInstance;\n\nimport java.util.List;\n\n/**\n * Used to build metadata service url from ServiceInstance.\n *\n * @since 2.7.5\n */\n@SPI\npublic interface MetadataServiceURLBuilder {\n\n    /**\n     * Build the {@link URL URLs} from the specified {@link ServiceInstance}\n     *\n     * @param serviceInstance {@link ServiceInstance}\n     * @return TODO, usually, we generate one metadata url from one instance. There's no scenario to return a metadata url list.\n     */\n    List<URL> build(ServiceInstance serviceInstance);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.aot.NativeDetector;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataRequest;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.metadata.MetadataServiceV2;\nimport org.apache.dubbo.metadata.MetadataServiceV2Detector;\nimport org.apache.dubbo.metadata.definition.model.FullServiceDefinition;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.MetadataReportInstance;\nimport org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;\nimport org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;\nimport org.apache.dubbo.metadata.util.MetadataServiceVersionUtils;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\nimport org.apache.dubbo.rpc.model.ServiceDescriptor;\nimport org.apache.dubbo.rpc.service.Destroyable;\nimport org.apache.dubbo.rpc.stub.StubSuppliers;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ThreadLocalRandom;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.FILTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.NATIVE_STUB;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROXY_CLASS_REF;\nimport static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_CREATE_INSTANCE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_LOAD_METADATA;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_KEY;\nimport static org.apache.dubbo.metadata.util.MetadataServiceVersionUtils.V2;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_URLS_PROPERTY_NAME;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_VERSION_NAME;\nimport static org.apache.dubbo.rpc.Constants.AUTH_KEY;\nimport static org.apache.dubbo.rpc.Constants.PROXY_KEY;\n\npublic class MetadataUtils {\n    public static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MetadataUtils.class);\n\n    public static void publishServiceDefinition(\n            URL url, ServiceDescriptor serviceDescriptor, ApplicationModel applicationModel) {\n        if (getMetadataReports(applicationModel).isEmpty()) {\n            logger.info(\"[METADATA_REGISTER] Remote Metadata Report Server is not provided or unavailable, \"\n                    + \"will stop registering service definition to remote center!\");\n            return;\n        }\n\n        try {\n            String side = url.getSide();\n            if (PROVIDER_SIDE.equalsIgnoreCase(side)) {\n                String serviceKey = url.getServiceKey();\n                FullServiceDefinition serviceDefinition = serviceDescriptor.getFullServiceDefinition(serviceKey);\n\n                if (StringUtils.isNotEmpty(serviceKey) && serviceDefinition != null) {\n                    serviceDefinition.setParameters(url.getParameters());\n                    for (Map.Entry<String, MetadataReport> entry :\n                            getMetadataReports(applicationModel).entrySet()) {\n                        MetadataReport metadataReport = entry.getValue();\n                        if (!metadataReport.shouldReportDefinition()) {\n                            logger.info(\"Report of service definition is disabled for \" + entry.getKey());\n                            continue;\n                        }\n                        metadataReport.storeProviderMetadata(\n                                new MetadataIdentifier(\n                                        url.getServiceInterface(),\n                                        url.getVersion() == null ? \"\" : url.getVersion(),\n                                        url.getGroup() == null ? \"\" : url.getGroup(),\n                                        PROVIDER_SIDE,\n                                        applicationModel.getApplicationName()),\n                                serviceDefinition);\n                    }\n                }\n            } else {\n                for (Map.Entry<String, MetadataReport> entry :\n                        getMetadataReports(applicationModel).entrySet()) {\n                    MetadataReport metadataReport = entry.getValue();\n                    if (!metadataReport.shouldReportDefinition()) {\n                        logger.info(\"Report of service definition is disabled for \" + entry.getKey());\n                        continue;\n                    }\n                    metadataReport.storeConsumerMetadata(\n                            new MetadataIdentifier(\n                                    url.getServiceInterface(),\n                                    url.getVersion() == null ? \"\" : url.getVersion(),\n                                    url.getGroup() == null ? \"\" : url.getGroup(),\n                                    CONSUMER_SIDE,\n                                    applicationModel.getApplicationName()),\n                            url.getParameters());\n                }\n            }\n        } catch (Exception e) {\n            // ignore error\n            logger.error(REGISTRY_FAILED_CREATE_INSTANCE, \"\", \"\", \"publish service definition metadata error.\", e);\n        }\n    }\n\n    public static RemoteMetadataService referMetadataService(ServiceInstance instance) {\n        URL url = buildMetadataUrl(instance);\n\n        // Simply rely on the first metadata url, as stated in MetadataServiceURLBuilder.\n        ApplicationModel applicationModel = instance.getApplicationModel();\n        ModuleModel internalModel = applicationModel.getInternalModule();\n\n        ConsumerModel consumerModel;\n\n        boolean useV2 = MetadataServiceDelegationV2.VERSION.equals(url.getAttribute(METADATA_SERVICE_VERSION_NAME));\n        if (!MetadataServiceV2Detector.support()) {\n            useV2 = false;\n        }\n        boolean inNativeImage = NativeDetector.inNativeImage();\n\n        if (useV2 && !inNativeImage) {\n            // If provider supports, we use MetadataServiceV2 in priority\n            url = url.addParameter(PROXY_KEY, NATIVE_STUB);\n            url = url.setPath(MetadataServiceV2.class.getName());\n            url = url.addParameter(VERSION_KEY, V2);\n\n            consumerModel = applicationModel\n                    .getInternalModule()\n                    .registerInternalConsumer(\n                            MetadataServiceV2.class,\n                            url,\n                            StubSuppliers.getServiceDescriptor(MetadataServiceV2.class.getName()));\n        } else {\n            consumerModel = applicationModel.getInternalModule().registerInternalConsumer(MetadataService.class, url);\n        }\n\n        if (inNativeImage) {\n            url = url.addParameter(PROXY_KEY, \"jdk\");\n        }\n\n        Protocol protocol = applicationModel.getExtensionLoader(Protocol.class).getExtension(url.getProtocol(), false);\n\n        url = url.setServiceModel(consumerModel);\n        if (url.getParameter(AUTH_KEY, false)) {\n            url = url.addParameter(FILTER_KEY, \"-default,consumersign\");\n        }\n\n        RemoteMetadataService remoteMetadataService;\n        ProxyFactory proxyFactory =\n                applicationModel.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();\n        if (useV2 && !inNativeImage) {\n            Invoker<MetadataServiceV2> invoker = protocol.refer(MetadataServiceV2.class, url);\n\n            if (url.getParameter(AUTH_KEY, false)) {\n                FilterChainBuilder filterChainBuilder = ScopeModelUtil.getExtensionLoader(\n                                FilterChainBuilder.class, url.getScopeModel())\n                        .getDefaultExtension();\n                invoker = filterChainBuilder.buildInvokerChain(invoker, REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);\n            }\n\n            remoteMetadataService =\n                    new RemoteMetadataService(consumerModel, proxyFactory.getProxy(invoker), internalModel);\n        } else {\n            Invoker<MetadataService> invoker = protocol.refer(MetadataService.class, url);\n\n            if (url.getParameter(AUTH_KEY, false)) {\n                FilterChainBuilder filterChainBuilder = ScopeModelUtil.getExtensionLoader(\n                                FilterChainBuilder.class, url.getScopeModel())\n                        .getDefaultExtension();\n                invoker = filterChainBuilder.buildInvokerChain(invoker, REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);\n            }\n\n            remoteMetadataService =\n                    new RemoteMetadataService(consumerModel, proxyFactory.getProxy(invoker), internalModel);\n        }\n\n        Object metadataServiceProxy = remoteMetadataService.getInternalProxy();\n        consumerModel.getServiceMetadata().setTarget(metadataServiceProxy);\n        consumerModel.getServiceMetadata().addAttribute(PROXY_CLASS_REF, metadataServiceProxy);\n        consumerModel.setProxyObject(metadataServiceProxy);\n        consumerModel.initMethodModels();\n\n        return remoteMetadataService;\n    }\n\n    private static URL buildMetadataUrl(ServiceInstance instance) {\n        MetadataServiceURLBuilder builder;\n        ExtensionLoader<MetadataServiceURLBuilder> loader =\n                instance.getApplicationModel().getExtensionLoader(MetadataServiceURLBuilder.class);\n\n        Map<String, String> metadata = instance.getMetadata();\n        // METADATA_SERVICE_URLS_PROPERTY_NAME is a unique key exists only on instances of spring-cloud-alibaba.\n        String dubboUrlsForJson = metadata.get(METADATA_SERVICE_URLS_PROPERTY_NAME);\n        if (metadata.isEmpty() || StringUtils.isEmpty(dubboUrlsForJson)) {\n            builder = loader.getExtension(StandardMetadataServiceURLBuilder.NAME);\n        } else {\n            builder = loader.getExtension(SpringCloudMetadataServiceURLBuilder.NAME);\n        }\n\n        List<URL> urls = builder.build(instance);\n        if (CollectionUtils.isEmpty(urls)) {\n            throw new IllegalStateException(\"Introspection service discovery mode is enabled \" + instance\n                    + \", but no metadata service can build from it.\");\n        }\n        URL url = urls.get(0);\n\n        String version = metadata.get(METADATA_SERVICE_VERSION_NAME);\n        url = url.putAttribute(METADATA_SERVICE_VERSION_NAME, version);\n        url = url.addParameter(CHECK_KEY, false);\n\n        return url;\n    }\n\n    public static MetadataInfo getRemoteMetadata(\n            String revision, List<ServiceInstance> instances, MetadataReport metadataReport) {\n        ServiceInstance instance = selectInstance(instances);\n        String metadataType = ServiceInstanceMetadataUtils.getMetadataStorageType(instance);\n        MetadataInfo metadataInfo;\n        try {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Instance \" + instance.getAddress() + \" is using metadata type \" + metadataType);\n            }\n            if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {\n                metadataInfo = MetadataUtils.getMetadata(revision, instance, metadataReport);\n            } else {\n                // change the instance used to communicate to avoid all requests route to the same instance\n                RemoteMetadataService remoteMetadataService = null;\n                try {\n                    remoteMetadataService = MetadataUtils.referMetadataService(instance);\n                    metadataInfo = remoteMetadataService.getRemoteMetadata(\n                            ServiceInstanceMetadataUtils.getExportedServicesRevision(instance));\n                } finally {\n                    MetadataUtils.destroyProxy(remoteMetadataService);\n                }\n            }\n        } catch (Exception e) {\n            logger.error(\n                    REGISTRY_FAILED_LOAD_METADATA,\n                    \"\",\n                    \"\",\n                    \"Failed to get app metadata for revision \" + revision + \" for type \" + metadataType\n                            + \" from instance \" + instance.getAddress(),\n                    e);\n            metadataInfo = null;\n        }\n\n        if (metadataInfo == null) {\n            metadataInfo = MetadataInfo.EMPTY;\n        }\n        return metadataInfo;\n    }\n\n    public static void destroyProxy(RemoteMetadataService remoteMetadataService) {\n        if (remoteMetadataService != null) {\n            remoteMetadataService.destroy();\n        }\n    }\n\n    public static MetadataInfo getMetadata(String revision, ServiceInstance instance, MetadataReport metadataReport) {\n        SubscriberMetadataIdentifier identifier = new SubscriberMetadataIdentifier(instance.getServiceName(), revision);\n\n        if (metadataReport == null) {\n            throw new IllegalStateException(\"No valid remote metadata report specified.\");\n        }\n\n        String registryCluster = instance.getRegistryCluster();\n        Map<String, String> params = new HashMap<>(instance.getExtendParams());\n        if (registryCluster != null && !registryCluster.equalsIgnoreCase(params.get(REGISTRY_CLUSTER_KEY))) {\n            params.put(REGISTRY_CLUSTER_KEY, registryCluster);\n        }\n\n        return metadataReport.getAppMetadata(identifier, params);\n    }\n\n    private static Map<String, MetadataReport> getMetadataReports(ApplicationModel applicationModel) {\n        return applicationModel\n                .getBeanFactory()\n                .getBean(MetadataReportInstance.class)\n                .getMetadataReports(false);\n    }\n\n    private static ServiceInstance selectInstance(List<ServiceInstance> instances) {\n        if (instances.size() == 1) {\n            return instances.get(0);\n        }\n        return instances.get(ThreadLocalRandom.current().nextInt(0, instances.size()));\n    }\n\n    public static class RemoteMetadataService {\n        private final ConsumerModel consumerModel;\n\n        @Deprecated\n        private MetadataService proxy;\n\n        private MetadataServiceV2 proxyV2;\n\n        private final ModuleModel internalModel;\n\n        public RemoteMetadataService(ConsumerModel consumerModel, MetadataService proxy, ModuleModel internalModel) {\n            this.consumerModel = consumerModel;\n            this.proxy = proxy;\n            this.internalModel = internalModel;\n        }\n\n        public RemoteMetadataService(\n                ConsumerModel consumerModel, MetadataServiceV2 proxyV2, ModuleModel internalModel) {\n            this.consumerModel = consumerModel;\n            this.proxyV2 = proxyV2;\n            this.internalModel = internalModel;\n        }\n\n        public void destroy() {\n            if (proxy instanceof Destroyable) {\n                ((Destroyable) proxy).$destroy();\n            }\n\n            if (proxyV2 instanceof Destroyable) {\n                ((Destroyable) proxyV2).$destroy();\n            }\n\n            internalModel.getServiceRepository().unregisterConsumer(consumerModel);\n        }\n\n        public ConsumerModel getConsumerModel() {\n            return consumerModel;\n        }\n\n        public Object getInternalProxy() {\n            return proxy == null ? proxyV2 : proxy;\n        }\n\n        public ModuleModel getInternalModel() {\n            return internalModel;\n        }\n\n        public MetadataInfo getRemoteMetadata(String revision) {\n            Object existProxy = getInternalProxy();\n            if (existProxy instanceof MetadataService) {\n                return ((MetadataService) existProxy).getMetadataInfo(revision);\n            } else {\n                return MetadataServiceVersionUtils.toV1(((MetadataServiceV2) existProxy)\n                        .getMetadataInfo(MetadataRequest.newBuilder()\n                                .setRevision(revision)\n                                .build()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ProtocolPortsMetadataCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstanceCustomizer;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.setEndpoints;\n\n/**\n * A Class to customize the ports of {@link Protocol protocols} into\n * {@link ServiceInstance#getMetadata() the metadata of service instance}\n *\n * @since 2.7.5\n */\npublic class ProtocolPortsMetadataCustomizer implements ServiceInstanceCustomizer {\n    private static final ErrorTypeAwareLogger LOGGER =\n            LoggerFactory.getErrorTypeAwareLogger(ProtocolPortsMetadataCustomizer.class);\n\n    @Override\n    public void customize(ServiceInstance serviceInstance, ApplicationModel applicationModel) {\n        MetadataInfo metadataInfo = serviceInstance.getServiceMetadata();\n        if (metadataInfo == null || CollectionUtils.isEmptyMap(metadataInfo.getExportedServiceURLs())) {\n            return;\n        }\n\n        Map<String, Integer> protocols = new HashMap<>();\n        Set<URL> urls = metadataInfo.collectExportedURLSet();\n        urls.forEach(url -> {\n            // TODO, same protocol listen on different ports will override with each other.\n            String protocol = url.getProtocol();\n            Integer oldPort = protocols.get(protocol);\n            int newPort = url.getPort();\n            if (oldPort != null && oldPort != newPort) {\n                LOGGER.warn(\n                        LoggerCodeConstants.PROTOCOL_INCORRECT_PARAMETER_VALUES,\n                        \"the protocol is listening multiple ports\",\n                        \"\",\n                        \"Same protocol \" + \"[\" + protocol + \"]\" + \" listens on different ports \" + \"[\" + oldPort + \",\"\n                                + newPort + \"]\" + \" will override with each other\" + \". The port [\" + oldPort\n                                + \"] is overridden with port [\" + newPort + \"].\");\n            }\n            protocols.put(protocol, newPort);\n        });\n\n        if (protocols.size() > 0) { // set endpoints only for multi-protocol scenario\n            setEndpoints(serviceInstance, protocols);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceHostPortCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstanceCustomizer;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_INIT_SERIALIZATION_OPTIMIZER;\n\n/**\n * The {@link ServiceInstanceCustomizer} to customize the {@link ServiceInstance#getPort() port} of service instance.\n */\npublic class ServiceInstanceHostPortCustomizer implements ServiceInstanceCustomizer {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ServiceInstanceHostPortCustomizer.class);\n\n    @Override\n    public void customize(ServiceInstance serviceInstance, ApplicationModel applicationModel) {\n        if (serviceInstance.getPort() > 0) {\n            return;\n        }\n\n        MetadataInfo metadataInfo = serviceInstance.getServiceMetadata();\n        if (metadataInfo == null || CollectionUtils.isEmptyMap(metadataInfo.getExportedServiceURLs())) {\n            return;\n        }\n\n        String host = null;\n        int port = -1;\n        Set<URL> urls = metadataInfo.collectExportedURLSet();\n\n        if (CollectionUtils.isNotEmpty(urls)) {\n            String preferredProtocol = applicationModel.getCurrentConfig().getProtocol();\n            if (preferredProtocol != null) {\n                for (URL exportedURL : urls) {\n                    if (preferredProtocol.equals(exportedURL.getProtocol())) {\n                        host = exportedURL.getHost();\n                        port = exportedURL.getPort();\n                        break;\n                    }\n                }\n\n                if (host == null || port == -1) {\n\n                    // 4-2 - Can't find an instance URL using the default preferredProtocol.\n\n                    logger.warn(\n                            PROTOCOL_FAILED_INIT_SERIALIZATION_OPTIMIZER,\n                            \"typo in preferred protocol\",\n                            \"\",\n                            \"Can't find an instance URL using the default preferredProtocol \\\"\" + preferredProtocol\n                                    + \"\\\", \" + \"falling back to the strategy that pick the first found protocol. \"\n                                    + \"Please try modifying the config of dubbo.application.protocol\");\n\n                    URL url = urls.iterator().next();\n                    host = url.getHost();\n                    port = url.getPort();\n                }\n            } else {\n                URL url = urls.iterator().next();\n                host = url.getHost();\n                port = url.getPort();\n            }\n\n            if (serviceInstance instanceof DefaultServiceInstance) {\n                DefaultServiceInstance instance = (DefaultServiceInstance) serviceInstance;\n                instance.setHost(host);\n                instance.setPort(port);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.infra.InfraAdapter;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstanceCustomizer;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\n\n/**\n * <p>Intercepting instance to load instance-level params from different sources before being registered into registry.</p>\n *\n * The sources can be one or both of the following:\n * <ul>\n *  <li>os environment</li>\n *  <li>vm options</li>\n * </ul>\n *\n * So, finally, the keys left in order will be:\n * <ul>\n *  <li>all keys specified by sources above</li>\n *  <li>keys found in metadata info</li>\n * </ul>\n *\n *\n */\npublic class ServiceInstanceMetadataCustomizer implements ServiceInstanceCustomizer {\n\n    @Override\n    public void customize(ServiceInstance serviceInstance, ApplicationModel applicationModel) {\n        MetadataInfo metadataInfo = serviceInstance.getServiceMetadata();\n        if (metadataInfo == null || CollectionUtils.isEmptyMap(metadataInfo.getServices())) {\n            return;\n        }\n\n        // try to load instance params that do not appear in service urls\n        // TODO, duplicate snippet in ApplicationConfig\n        Map<String, String> extraParameters = Collections.emptyMap();\n        Set<InfraAdapter> adapters =\n                applicationModel.getExtensionLoader(InfraAdapter.class).getSupportedExtensionInstances();\n        if (CollectionUtils.isNotEmpty(adapters)) {\n            Map<String, String> inputParameters = new HashMap<>();\n            inputParameters.put(APPLICATION_KEY, applicationModel.getApplicationName());\n            for (InfraAdapter adapter : adapters) {\n                extraParameters = adapter.getExtraAttributes(inputParameters);\n            }\n        }\n\n        serviceInstance.getMetadata().putAll(extraParameters);\n        if (CollectionUtils.isNotEmptyMap(metadataInfo.getInstanceParams())) {\n            serviceInstance.getMetadata().putAll(metadataInfo.getInstanceParams());\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.registry.event.RegistryEvent;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance.Endpoint;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstanceCustomizer;\nimport org.apache.dubbo.registry.support.RegistryManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;\nimport static org.apache.dubbo.common.utils.StringUtils.isBlank;\nimport static org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol.DEFAULT_REGISTER_PROVIDER_KEYS;\nimport static org.apache.dubbo.rpc.Constants.DEPRECATED_KEY;\n\n/**\n * The Utilities class for the {@link ServiceInstance#getMetadata() metadata of the service instance}\n *\n * @see StandardMetadataServiceURLBuilder\n * @see ServiceInstance#getMetadata()\n * @see MetadataService\n * @see URL\n * @since 2.7.5\n */\npublic class ServiceInstanceMetadataUtils {\n    private static final ErrorTypeAwareLogger LOGGER =\n            LoggerFactory.getErrorTypeAwareLogger(ServiceInstanceMetadataUtils.class);\n\n    /**\n     * The prefix of {@link MetadataService} : \"dubbo.metadata-service.\"\n     */\n    public static final String METADATA_SERVICE_PREFIX = \"dubbo.metadata-service.\";\n\n    public static final String ENDPOINTS = \"dubbo.endpoints\";\n\n    /**\n     * The property name of metadata JSON of {@link MetadataService}'s {@link URL}\n     */\n    public static final String METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME = METADATA_SERVICE_PREFIX + \"url-params\";\n\n    /**\n     * The {@link URL URLs} property name of {@link MetadataService} :\n     * \"dubbo.metadata-service.urls\", which is used to be compatible with Dubbo Spring Cloud and\n     * discovery the metadata of instance\n     */\n    public static final String METADATA_SERVICE_URLS_PROPERTY_NAME = METADATA_SERVICE_PREFIX + \"urls\";\n\n    /**\n     * The property name of The revision for all exported Dubbo services.\n     */\n    public static final String EXPORTED_SERVICES_REVISION_PROPERTY_NAME = \"dubbo.metadata.revision\";\n\n    /**\n     * The property name of metadata storage type.\n     */\n    public static final String METADATA_STORAGE_TYPE_PROPERTY_NAME = \"dubbo.metadata.storage-type\";\n\n    public static final String METADATA_SERVICE_VERSION_NAME = \"meta-v\";\n\n    public static final String METADATA_CLUSTER_PROPERTY_NAME = \"dubbo.metadata.cluster\";\n\n    public static String getMetadataServiceParameter(URL url) {\n        if (url == null) {\n            return \"\";\n        }\n        url = url.removeParameters(APPLICATION_KEY, GROUP_KEY, DEPRECATED_KEY, TIMESTAMP_KEY);\n        Map<String, String> params = getParams(url);\n\n        if (params.isEmpty()) {\n            return null;\n        }\n\n        return JsonUtils.toJson(params);\n    }\n\n    private static Map<String, String> getParams(URL providerURL) {\n        Map<String, String> params = new LinkedHashMap<>();\n        setDefaultParams(params, providerURL);\n        params.put(PORT_KEY, String.valueOf(providerURL.getPort()));\n        params.put(PROTOCOL_KEY, providerURL.getProtocol());\n        return params;\n    }\n\n    /**\n     * The revision for all exported Dubbo services from the specified {@link ServiceInstance}.\n     *\n     * @param serviceInstance the specified {@link ServiceInstance}\n     * @return <code>null</code> if not exits\n     */\n    public static String getExportedServicesRevision(ServiceInstance serviceInstance) {\n        return Optional.ofNullable(serviceInstance.getServiceMetadata())\n                .map(MetadataInfo::getRevision)\n                .filter(StringUtils::isNotEmpty)\n                .orElse(serviceInstance.getMetadata(EXPORTED_SERVICES_REVISION_PROPERTY_NAME));\n    }\n\n    /**\n     * Get metadata's storage type\n     *\n     * @param registryURL the {@link URL} to connect the registry\n     * @return if not found in {@link URL#getParameters() parameters} of {@link URL registry URL}, return\n     */\n    public static String getMetadataStorageType(URL registryURL) {\n        return registryURL.getParameter(METADATA_STORAGE_TYPE_PROPERTY_NAME, DEFAULT_METADATA_STORAGE_TYPE);\n    }\n\n    /**\n     * Get the metadata storage type specified by the peer instance.\n     *\n     * @return storage type, remote or local\n     */\n    public static String getMetadataStorageType(ServiceInstance serviceInstance) {\n        Map<String, String> metadata = serviceInstance.getMetadata();\n        return metadata.getOrDefault(METADATA_STORAGE_TYPE_PROPERTY_NAME, DEFAULT_METADATA_STORAGE_TYPE);\n    }\n\n    /**\n     * Set the metadata storage type in specified {@link ServiceInstance service instance}\n     *\n     * @param serviceInstance {@link ServiceInstance service instance}\n     * @param metadataType    remote or local\n     */\n    public static void setMetadataStorageType(ServiceInstance serviceInstance, String metadataType) {\n        Map<String, String> metadata = serviceInstance.getMetadata();\n        metadata.put(METADATA_STORAGE_TYPE_PROPERTY_NAME, metadataType);\n    }\n\n    public static String getRemoteCluster(ServiceInstance serviceInstance) {\n        Map<String, String> metadata = serviceInstance.getMetadata();\n        return metadata.get(METADATA_CLUSTER_PROPERTY_NAME);\n    }\n\n    public static boolean hasEndpoints(ServiceInstance serviceInstance) {\n        return StringUtils.isNotEmpty(serviceInstance.getMetadata().get(ENDPOINTS));\n    }\n\n    public static void setEndpoints(ServiceInstance serviceInstance, Map<String, Integer> protocolPorts) {\n        Map<String, String> metadata = serviceInstance.getMetadata();\n        List<Endpoint> endpoints = new ArrayList<>();\n        protocolPorts.forEach((k, v) -> {\n            Endpoint endpoint = new Endpoint(v, k);\n            endpoints.add(endpoint);\n        });\n\n        metadata.put(ENDPOINTS, JsonUtils.toJson(endpoints));\n    }\n\n    /**\n     * Get the property value of port by the specified {@link ServiceInstance#getMetadata() the metadata of\n     * service instance} and protocol\n     *\n     * @param serviceInstance {@link ServiceInstance service instance}\n     * @param protocol        the name of protocol, e.g, dubbo, rest, and so on\n     * @return if not found, return <code>null</code>\n     */\n    public static Endpoint getEndpoint(ServiceInstance serviceInstance, String protocol) {\n        List<Endpoint> endpoints = ((DefaultServiceInstance) serviceInstance).getEndpoints();\n        if (endpoints != null) {\n            for (Endpoint endpoint : endpoints) {\n                if (endpoint.getProtocol().equals(protocol)) {\n                    return endpoint;\n                }\n            }\n        }\n        return null;\n    }\n\n    public static void registerMetadataAndInstance(ApplicationModel applicationModel) {\n        RegistryManager registryManager = applicationModel.getBeanFactory().getBean(RegistryManager.class);\n        // register service instance\n        if (CollectionUtils.isNotEmpty(registryManager.getServiceDiscoveries())) {\n            LOGGER.info(\"[METADATA_REGISTER] Start registering instance address to registry.\");\n            List<ServiceDiscovery> serviceDiscoveries = registryManager.getServiceDiscoveries();\n            for (ServiceDiscovery serviceDiscovery : serviceDiscoveries) {\n                MetricsEventBus.post(\n                        RegistryEvent.toRegisterEvent(\n                                applicationModel, Collections.singletonList(getServiceDiscoveryName(serviceDiscovery))),\n                        () -> {\n                            // register service instance\n                            serviceDiscovery.register();\n                            return null;\n                        });\n            }\n        }\n    }\n\n    private static String getServiceDiscoveryName(ServiceDiscovery serviceDiscovery) {\n        return serviceDiscovery\n                .getUrl()\n                .getParameter(\n                        RegistryConstants.REGISTRY_CLUSTER_KEY,\n                        serviceDiscovery.getUrl().getParameter(REGISTRY_KEY));\n    }\n\n    public static void refreshMetadataAndInstance(ApplicationModel applicationModel) {\n        RegistryManager registryManager = applicationModel.getBeanFactory().getBean(RegistryManager.class);\n        // update service instance revision\n        registryManager.getServiceDiscoveries().forEach(ServiceDiscovery::update);\n    }\n\n    public static void unregisterMetadataAndInstance(ApplicationModel applicationModel) {\n        RegistryManager registryManager = applicationModel.getBeanFactory().getBean(RegistryManager.class);\n        registryManager.getServiceDiscoveries().forEach(serviceDiscovery -> {\n            try {\n                serviceDiscovery.unregister();\n            } catch (Exception ignored) {\n                // ignored\n            }\n        });\n    }\n\n    public static void customizeInstance(ServiceInstance instance, ApplicationModel applicationModel) {\n        ExtensionLoader<ServiceInstanceCustomizer> loader =\n                instance.getOrDefaultApplicationModel().getExtensionLoader(ServiceInstanceCustomizer.class);\n        // FIXME, sort customizer before apply\n        loader.getSupportedExtensionInstances().forEach(customizer -> {\n            // customize\n            customizer.customize(instance, applicationModel);\n        });\n    }\n\n    public static boolean isValidInstance(ServiceInstance instance) {\n        return instance != null && instance.getHost() != null && instance.getPort() != 0;\n    }\n\n    /**\n     * Set the default parameters via the specified {@link URL providerURL}\n     *\n     * @param params      the parameters\n     * @param providerURL the provider's {@link URL}\n     */\n    private static void setDefaultParams(Map<String, String> params, URL providerURL) {\n        for (String parameterName : DEFAULT_REGISTER_PROVIDER_KEYS) {\n            String parameterValue = providerURL.getParameter(parameterName);\n            if (!isBlank(parameterValue)) {\n                params.put(parameterName, parameterValue);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceNotificationCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.registry.client.ServiceInstance;\n\nimport java.util.List;\n\n@SPI\npublic interface ServiceInstanceNotificationCustomizer {\n\n    void customize(List<ServiceInstance> serviceInstance);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/SpringCloudMetadataServiceURLBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.client.ServiceInstance;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_URLS_PROPERTY_NAME;\n\n/**\n * Supporting interaction with Dubbo Spring Cloud at https://github.com/alibaba/spring-cloud-alibaba\n * Dubbo Spring Cloud is a Dubbo extension that favours a per instance registry model and exposes metadata service.\n *\n * @since 2.7.5\n */\npublic class SpringCloudMetadataServiceURLBuilder implements MetadataServiceURLBuilder {\n    public static final String NAME = \"spring-cloud\";\n\n    @Override\n    public List<URL> build(ServiceInstance serviceInstance) {\n        Map<String, String> metadata = serviceInstance.getMetadata();\n        String dubboUrlsForJson = metadata.get(METADATA_SERVICE_URLS_PROPERTY_NAME);\n        if (StringUtils.isBlank(dubboUrlsForJson)) {\n            return Collections.emptyList();\n        }\n        List<String> urlStrings = JsonUtils.toJavaList(dubboUrlsForJson, String.class);\n        return urlStrings.stream().map(URL::valueOf).collect(Collectors.toList());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/StandardMetadataServiceURLBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport static java.util.Collections.emptyMap;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_MISSING_METADATA_CONFIG_PORT;\nimport static org.apache.dubbo.common.utils.StringUtils.isBlank;\nimport static org.apache.dubbo.metadata.MetadataConstants.DEFAULT_METADATA_TIMEOUT_VALUE;\nimport static org.apache.dubbo.metadata.MetadataConstants.METADATA_PROXY_TIMEOUT_KEY;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME;\nimport static org.apache.dubbo.remoting.Constants.CONNECTIONS_KEY;\n\n/**\n * Standard Dubbo provider enabling introspection service discovery mode.\n *\n * @see MetadataService\n * @since 2.7.5\n */\npublic class StandardMetadataServiceURLBuilder implements MetadataServiceURLBuilder {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    public static final String NAME = \"standard\";\n\n    private ApplicationModel applicationModel;\n    private Integer metadataServicePort;\n\n    public StandardMetadataServiceURLBuilder(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        metadataServicePort = applicationModel.getCurrentConfig().getMetadataServicePort();\n    }\n\n    /**\n     * Build the {@link URL urls} from {@link ServiceInstance#getMetadata() the metadata} of {@link ServiceInstance}\n     *\n     * @param serviceInstance {@link ServiceInstance}\n     * @return the not-null {@link List}\n     */\n    @Override\n    public List<URL> build(ServiceInstance serviceInstance) {\n        Map<String, String> paramsMap = getMetadataServiceURLsParams(serviceInstance);\n\n        String serviceName = serviceInstance.getServiceName();\n\n        String host = serviceInstance.getHost();\n\n        URL url;\n        if (paramsMap.isEmpty()) {\n            // ServiceInstance Metadata is empty. Happened when registry not support metadata write.\n            url = generateUrlWithoutMetadata(serviceName, host, serviceInstance.getPort());\n        } else {\n            url = generateWithMetadata(serviceName, host, paramsMap);\n        }\n\n        url = url.setScopeModel(serviceInstance.getApplicationModel().getInternalModule());\n\n        return Collections.singletonList(url);\n    }\n\n    private URL generateWithMetadata(String serviceName, String host, Map<String, String> params) {\n        String protocol = params.get(PROTOCOL_KEY);\n        int port = Integer.parseInt(params.get(PORT_KEY));\n        URLBuilder urlBuilder = new URLBuilder()\n                .setHost(host)\n                .setPort(port)\n                .setProtocol(protocol)\n                .setPath(MetadataService.class.getName())\n                .addParameter(\n                        TIMEOUT_KEY,\n                        ConfigurationUtils.get(\n                                applicationModel, METADATA_PROXY_TIMEOUT_KEY, DEFAULT_METADATA_TIMEOUT_VALUE))\n                .addParameter(CONNECTIONS_KEY, 1)\n                .addParameter(THREADPOOL_KEY, \"cached\")\n                .addParameter(THREADS_KEY, \"100\")\n                .addParameter(CORE_THREADS_KEY, \"2\")\n                .addParameter(RETRIES_KEY, 0);\n\n        // add parameters\n        params.forEach(urlBuilder::addParameter);\n\n        // add the default parameters\n        urlBuilder.addParameter(GROUP_KEY, serviceName);\n        urlBuilder.addParameter(SIDE_KEY, CONSUMER);\n        return urlBuilder.build();\n    }\n\n    private URL generateUrlWithoutMetadata(String serviceName, String host, Integer instancePort) {\n        Integer port = metadataServicePort;\n        if (port == null || port < 1) {\n\n            // 1-18 - Metadata Service Port should be specified for consumer.\n\n            logger.warn(\n                    REGISTRY_MISSING_METADATA_CONFIG_PORT,\n                    \"missing configuration of metadata service port\",\n                    \"\",\n                    \"Metadata Service Port is not provided. Since DNS is not able to negotiate the metadata port \"\n                            + \"between Provider and Consumer, Dubbo will try using instance port as the default metadata port.\");\n\n            port = instancePort;\n        }\n\n        if (port == null || port < 1) {\n\n            // 1-18 - Metadata Service Port should be specified for consumer.\n\n            String message = \"Metadata Service Port should be specified for consumer. \"\n                    + \"Please set dubbo.application.metadataServicePort and \"\n                    + \"make sure it has been set on provider side. \"\n                    + \"ServiceName: \"\n                    + serviceName + \" Host: \" + host;\n\n            IllegalStateException illegalStateException = new IllegalStateException(message);\n\n            logger.error(\n                    REGISTRY_MISSING_METADATA_CONFIG_PORT,\n                    \"missing configuration of metadata service port\",\n                    \"\",\n                    message,\n                    illegalStateException);\n\n            throw illegalStateException;\n        }\n\n        URLBuilder urlBuilder = new URLBuilder()\n                .setHost(host)\n                .setPort(port)\n                .setProtocol(DUBBO_PROTOCOL)\n                .setPath(MetadataService.class.getName())\n                .addParameter(\n                        TIMEOUT_KEY,\n                        ConfigurationUtils.get(\n                                applicationModel, METADATA_PROXY_TIMEOUT_KEY, DEFAULT_METADATA_TIMEOUT_VALUE))\n                .addParameter(Constants.RECONNECT_KEY, false)\n                .addParameter(SIDE_KEY, CONSUMER)\n                .addParameter(GROUP_KEY, serviceName)\n                .addParameter(VERSION_KEY, MetadataService.VERSION)\n                .addParameter(RETRIES_KEY, 0);\n\n        // add ServiceInstance Metadata notify support\n        urlBuilder.addParameter(\"getAndListenInstanceMetadata.1.callback\", true);\n\n        return urlBuilder.build();\n    }\n\n    /**\n     * Get the multiple {@link URL urls'} parameters of {@link MetadataService MetadataService's} Metadata\n     *\n     * @param serviceInstance the instance of {@link ServiceInstance}\n     * @return non-null {@link Map}, the key is {@link URL#getProtocol() the protocol of URL}, the value is\n     */\n    private Map<String, String> getMetadataServiceURLsParams(ServiceInstance serviceInstance) {\n        Map<String, String> metadata = serviceInstance.getMetadata();\n        String param = metadata.get(METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME);\n        return isBlank(param) ? emptyMap() : (Map) JsonUtils.toJavaObject(param, Map.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/MetaCacheManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata.store;\n\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.metadata.AbstractCacheManager;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.Objects;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_META_CACHE_ENTRYSIZE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_META_CACHE_FILENAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_META_CACHE_FILEPATH;\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_META_CACHE_MAXFILESIZE;\n\n/**\n * Metadata cache with limited size that uses LRU expiry policy.\n */\npublic class MetaCacheManager extends AbstractCacheManager<MetadataInfo> {\n    private static final String DEFAULT_FILE_NAME = \".metadata\";\n    private static final int DEFAULT_ENTRY_SIZE = 100;\n\n    public static MetaCacheManager getInstance(ScopeModel scopeModel) {\n        return scopeModel.getBeanFactory().getOrRegisterBean(MetaCacheManager.class);\n    }\n\n    public MetaCacheManager(boolean enableFileCache, String registryName, ScheduledExecutorService executorService) {\n        String filePath = SystemPropertyConfigUtils.getSystemProperty(DUBBO_META_CACHE_FILEPATH);\n        String fileName = SystemPropertyConfigUtils.getSystemProperty(DUBBO_META_CACHE_FILENAME);\n        if (StringUtils.isEmpty(fileName)) {\n            fileName = DEFAULT_FILE_NAME;\n        }\n\n        if (StringUtils.isNotEmpty(registryName)) {\n            fileName = fileName + \".\" + registryName;\n        }\n\n        String rawEntrySize = SystemPropertyConfigUtils.getSystemProperty(DUBBO_META_CACHE_ENTRYSIZE);\n        int entrySize = StringUtils.parseInteger(rawEntrySize);\n        entrySize = (entrySize == 0 ? DEFAULT_ENTRY_SIZE : entrySize);\n\n        String rawMaxFileSize = SystemPropertyConfigUtils.getSystemProperty(DUBBO_META_CACHE_MAXFILESIZE);\n        long maxFileSize = StringUtils.parseLong(rawMaxFileSize);\n\n        init(enableFileCache, filePath, fileName, entrySize, maxFileSize, 60, executorService);\n    }\n\n    // for unit test only\n    public MetaCacheManager() {\n        this(true, \"\", null);\n    }\n\n    @Override\n    protected MetadataInfo toValueType(String value) {\n        return JsonUtils.toJavaObject(value, MetadataInfo.class);\n    }\n\n    @Override\n    protected String getName() {\n        return \"meta\";\n    }\n\n    @Override\n    protected boolean validate(String key, MetadataInfo value) {\n        if (!super.validate(key, value)) {\n            return false;\n        }\n        String revision = value.calRevision();\n        return Objects.equals(key, revision);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/DefaultMigrationAddressComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_PROPERTY_TYPE_MISMATCH;\n\npublic class DefaultMigrationAddressComparator implements MigrationAddressComparator {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DefaultMigrationAddressComparator.class);\n    private static final String MIGRATION_THRESHOLD = \"dubbo.application.migration.threshold\";\n    private static final String DEFAULT_THRESHOLD_STRING = \"0.0\";\n    private static final float DEFAULT_THREAD = 0f;\n\n    public static final String OLD_ADDRESS_SIZE = \"OLD_ADDRESS_SIZE\";\n    public static final String NEW_ADDRESS_SIZE = \"NEW_ADDRESS_SIZE\";\n\n    private final ConcurrentMap<String, Map<String, Integer>> serviceMigrationData = new ConcurrentHashMap<>();\n\n    @Override\n    public <T> boolean shouldMigrate(ClusterInvoker<T> newInvoker, ClusterInvoker<T> oldInvoker, MigrationRule rule) {\n        Map<String, Integer> migrationData = ConcurrentHashMapUtils.computeIfAbsent(\n                serviceMigrationData, oldInvoker.getUrl().getDisplayServiceKey(), _k -> new ConcurrentHashMap<>());\n\n        if (!newInvoker.hasProxyInvokers()) {\n            migrationData.put(OLD_ADDRESS_SIZE, getAddressSize(oldInvoker));\n            migrationData.put(NEW_ADDRESS_SIZE, -1);\n            logger.info(\"No \" + getInvokerType(newInvoker) + \" address available, stop compare.\");\n            return false;\n        }\n        if (!oldInvoker.hasProxyInvokers()) {\n            migrationData.put(OLD_ADDRESS_SIZE, -1);\n            migrationData.put(NEW_ADDRESS_SIZE, getAddressSize(newInvoker));\n            logger.info(\"No \" + getInvokerType(oldInvoker) + \" address available, stop compare.\");\n            return true;\n        }\n\n        int newAddressSize = getAddressSize(newInvoker);\n        int oldAddressSize = getAddressSize(oldInvoker);\n\n        migrationData.put(OLD_ADDRESS_SIZE, oldAddressSize);\n        migrationData.put(NEW_ADDRESS_SIZE, newAddressSize);\n\n        String rawThreshold = null;\n        Float configuredThreshold = rule == null ? null : rule.getThreshold(oldInvoker.getUrl());\n        if (configuredThreshold != null && configuredThreshold >= 0) {\n            rawThreshold = String.valueOf(configuredThreshold);\n        }\n        rawThreshold = StringUtils.isNotEmpty(rawThreshold)\n                ? rawThreshold\n                : ConfigurationUtils.getCachedDynamicProperty(\n                        newInvoker.getUrl().getScopeModel(), MIGRATION_THRESHOLD, DEFAULT_THRESHOLD_STRING);\n        float threshold;\n        try {\n            threshold = Float.parseFloat(rawThreshold);\n        } catch (Exception e) {\n            logger.error(COMMON_PROPERTY_TYPE_MISMATCH, \"\", \"\", \"Invalid migration threshold \" + rawThreshold);\n            threshold = DEFAULT_THREAD;\n        }\n\n        logger.info(\"serviceKey:\" + oldInvoker.getUrl().getServiceKey() + \" Instance address size \" + newAddressSize\n                + \", interface address size \" + oldAddressSize + \", threshold \" + threshold);\n\n        if (newAddressSize != 0 && oldAddressSize == 0) {\n            return true;\n        }\n        if (newAddressSize == 0 && oldAddressSize == 0) {\n            return false;\n        }\n\n        return ((float) newAddressSize / (float) oldAddressSize) >= threshold;\n    }\n\n    private <T> int getAddressSize(ClusterInvoker<T> invoker) {\n        if (invoker == null) {\n            return -1;\n        }\n        List<Invoker<T>> invokers = invoker.getDirectory().getAllInvokers();\n        return CollectionUtils.isNotEmpty(invokers) ? invokers.size() : 0;\n    }\n\n    @Override\n    public Map<String, Integer> getAddressSize(String displayServiceKey) {\n        return serviceMigrationData.get(displayServiceKey);\n    }\n\n    private String getInvokerType(ClusterInvoker<?> invoker) {\n        if (invoker.isServiceDiscovery()) {\n            return \"instance\";\n        }\n        return \"interface\";\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/InvokersChangedListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\npublic interface InvokersChangedListener {\n    void onChange();\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationAddressComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\nimport java.util.Map;\n\n@SPI\npublic interface MigrationAddressComparator {\n\n    <T> boolean shouldMigrate(ClusterInvoker<T> newInvoker, ClusterInvoker<T> oldInvoker, MigrationRule rule);\n\n    Map<String, Integer> getAddressSize(String displayServiceKey);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationClusterInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.registry.client.migration.model.MigrationStep;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\n/**\n * FIXME, some methods need to be further optimized.\n *\n * @param <T>\n */\npublic interface MigrationClusterInvoker<T> extends ClusterInvoker<T> {\n\n    @Override\n    boolean isServiceDiscovery();\n\n    MigrationStep getMigrationStep();\n\n    void setMigrationStep(MigrationStep step);\n\n    MigrationRule getMigrationRule();\n\n    void setMigrationRule(MigrationRule rule);\n\n    boolean migrateToForceInterfaceInvoker(MigrationRule newRule);\n\n    boolean migrateToForceApplicationInvoker(MigrationRule newRule);\n\n    void migrateToApplicationFirstInvoker(MigrationRule newRule);\n\n    void reRefer(URL newSubscribeUrl);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.registry.client.migration.model.MigrationStep;\nimport org.apache.dubbo.registry.integration.DynamicDirectory;\nimport org.apache.dubbo.registry.integration.RegistryProtocol;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\nimport org.apache.dubbo.rpc.model.ConsumerModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_NOTIFY_EVENT;\nimport static org.apache.dubbo.registry.client.migration.model.MigrationStep.APPLICATION_FIRST;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\n\npublic class MigrationInvoker<T> implements MigrationClusterInvoker<T> {\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MigrationInvoker.class);\n\n    private URL url;\n    private final URL consumerUrl;\n    private final Cluster cluster;\n    private final Registry registry;\n    private final Class<T> type;\n    private final RegistryProtocol registryProtocol;\n    private MigrationRuleListener migrationRuleListener;\n    private final ConsumerModel consumerModel;\n    private final FrameworkStatusReportService reportService;\n\n    private volatile ClusterInvoker<T> invoker;\n    private volatile ClusterInvoker<T> serviceDiscoveryInvoker;\n    private volatile ClusterInvoker<T> currentAvailableInvoker;\n    private volatile MigrationStep step;\n    private volatile MigrationRule rule;\n    private volatile int promotion = 100;\n\n    public MigrationInvoker(\n            RegistryProtocol registryProtocol,\n            Cluster cluster,\n            Registry registry,\n            Class<T> type,\n            URL url,\n            URL consumerUrl) {\n        this(null, null, registryProtocol, cluster, registry, type, url, consumerUrl);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public MigrationInvoker(\n            ClusterInvoker<T> invoker,\n            ClusterInvoker<T> serviceDiscoveryInvoker,\n            RegistryProtocol registryProtocol,\n            Cluster cluster,\n            Registry registry,\n            Class<T> type,\n            URL url,\n            URL consumerUrl) {\n        this.invoker = invoker;\n        this.serviceDiscoveryInvoker = serviceDiscoveryInvoker;\n        this.registryProtocol = registryProtocol;\n        this.cluster = cluster;\n        this.registry = registry;\n        this.type = type;\n        this.url = url;\n        this.consumerUrl = consumerUrl;\n        this.consumerModel = (ConsumerModel) consumerUrl.getServiceModel();\n        this.reportService =\n                consumerUrl.getOrDefaultApplicationModel().getBeanFactory().getBean(FrameworkStatusReportService.class);\n\n        if (consumerModel != null) {\n            Object object =\n                    consumerModel.getServiceMetadata().getAttribute(CommonConstants.CURRENT_CLUSTER_INVOKER_KEY);\n            Map<Registry, MigrationInvoker<?>> invokerMap;\n            if (object instanceof Map) {\n                invokerMap = (Map<Registry, MigrationInvoker<?>>) object;\n            } else {\n                invokerMap = new ConcurrentHashMap<>();\n            }\n            invokerMap.put(registry, this);\n            consumerModel.getServiceMetadata().addAttribute(CommonConstants.CURRENT_CLUSTER_INVOKER_KEY, invokerMap);\n        }\n    }\n\n    public ClusterInvoker<T> getInvoker() {\n        return invoker;\n    }\n\n    public void setInvoker(ClusterInvoker<T> invoker) {\n        this.invoker = invoker;\n    }\n\n    public ClusterInvoker<T> getServiceDiscoveryInvoker() {\n        return serviceDiscoveryInvoker;\n    }\n\n    public void setServiceDiscoveryInvoker(ClusterInvoker<T> serviceDiscoveryInvoker) {\n        this.serviceDiscoveryInvoker = serviceDiscoveryInvoker;\n    }\n\n    public ClusterInvoker<T> getCurrentAvailableInvoker() {\n        return currentAvailableInvoker;\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return type;\n    }\n\n    @Override\n    public void reRefer(URL newSubscribeUrl) {\n        // update url to prepare for migration refresh\n        this.url = url.addParameter(REFER_KEY, StringUtils.toQueryString(newSubscribeUrl.getParameters()));\n\n        // re-subscribe immediately\n        if (invoker != null && !invoker.isDestroyed()) {\n            doReSubscribe(invoker, newSubscribeUrl);\n        }\n        if (serviceDiscoveryInvoker != null && !serviceDiscoveryInvoker.isDestroyed()) {\n            doReSubscribe(serviceDiscoveryInvoker, newSubscribeUrl);\n        }\n    }\n\n    private void doReSubscribe(ClusterInvoker<T> invoker, URL newSubscribeUrl) {\n        DynamicDirectory<T> directory = (DynamicDirectory<T>) invoker.getDirectory();\n        URL oldSubscribeUrl = directory.getRegisteredConsumerUrl();\n        Registry registry = directory.getRegistry();\n        registry.unregister(directory.getRegisteredConsumerUrl());\n        directory.unSubscribe(RegistryProtocol.toSubscribeUrl(oldSubscribeUrl));\n        if (directory.isShouldRegister()) {\n            registry.register(directory.getRegisteredConsumerUrl());\n            directory.setRegisteredConsumerUrl(newSubscribeUrl);\n        }\n        directory.buildRouterChain(newSubscribeUrl);\n        directory.subscribe(RegistryProtocol.toSubscribeUrl(newSubscribeUrl));\n    }\n\n    @Override\n    public boolean migrateToForceInterfaceInvoker(MigrationRule newRule) {\n        CountDownLatch latch = new CountDownLatch(1);\n        refreshInterfaceInvoker(latch);\n\n        if (serviceDiscoveryInvoker == null) {\n            // serviceDiscoveryInvoker is absent, ignore threshold check\n            this.currentAvailableInvoker = invoker;\n            return true;\n        }\n\n        // wait and compare threshold\n        waitAddressNotify(newRule, latch);\n\n        if (newRule.getForce(consumerUrl)) {\n            // force migrate, ignore threshold check\n            this.currentAvailableInvoker = invoker;\n            this.destroyServiceDiscoveryInvoker();\n            return true;\n        }\n\n        Set<MigrationAddressComparator> detectors = ScopeModelUtil.getApplicationModel(\n                        consumerUrl == null ? null : consumerUrl.getScopeModel())\n                .getExtensionLoader(MigrationAddressComparator.class)\n                .getSupportedExtensionInstances();\n        if (CollectionUtils.isNotEmpty(detectors)) {\n            if (detectors.stream()\n                    .allMatch(comparator -> comparator.shouldMigrate(invoker, serviceDiscoveryInvoker, newRule))) {\n                this.currentAvailableInvoker = invoker;\n                this.destroyServiceDiscoveryInvoker();\n                return true;\n            }\n        }\n\n        // compare failed, will not change state\n        if (step == MigrationStep.FORCE_APPLICATION) {\n            destroyInterfaceInvoker();\n        }\n        return false;\n    }\n\n    @Override\n    public boolean migrateToForceApplicationInvoker(MigrationRule newRule) {\n        CountDownLatch latch = new CountDownLatch(1);\n        refreshServiceDiscoveryInvoker(latch);\n\n        if (invoker == null) {\n            // invoker is absent, ignore threshold check\n            this.currentAvailableInvoker = serviceDiscoveryInvoker;\n            return true;\n        }\n\n        // wait and compare threshold\n        waitAddressNotify(newRule, latch);\n\n        if (newRule.getForce(consumerUrl)) {\n            // force migrate, ignore threshold check\n            this.currentAvailableInvoker = serviceDiscoveryInvoker;\n            this.destroyInterfaceInvoker();\n            return true;\n        }\n\n        Set<MigrationAddressComparator> detectors = ScopeModelUtil.getApplicationModel(\n                        consumerUrl == null ? null : consumerUrl.getScopeModel())\n                .getExtensionLoader(MigrationAddressComparator.class)\n                .getSupportedExtensionInstances();\n        if (CollectionUtils.isNotEmpty(detectors)) {\n            if (detectors.stream()\n                    .allMatch(comparator -> comparator.shouldMigrate(serviceDiscoveryInvoker, invoker, newRule))) {\n                this.currentAvailableInvoker = serviceDiscoveryInvoker;\n                this.destroyInterfaceInvoker();\n                return true;\n            }\n        }\n\n        // compare failed, will not change state\n        if (step == MigrationStep.FORCE_INTERFACE) {\n            destroyServiceDiscoveryInvoker();\n        }\n        return false;\n    }\n\n    @Override\n    public void migrateToApplicationFirstInvoker(MigrationRule newRule) {\n        CountDownLatch latch = new CountDownLatch(0);\n        refreshInterfaceInvoker(latch);\n        refreshServiceDiscoveryInvoker(latch);\n\n        // directly calculate preferred invoker, will not wait until address notify\n        // calculation will re-occurred when address notify later\n        calcPreferredInvoker(newRule);\n    }\n\n    @SuppressWarnings(\"all\")\n    private void waitAddressNotify(MigrationRule newRule, CountDownLatch latch) {\n        // wait and compare threshold\n        int delay = newRule.getDelay(consumerUrl);\n        if (delay > 0) {\n            try {\n                Thread.sleep(delay * 1000L);\n            } catch (InterruptedException e) {\n                logger.error(REGISTRY_FAILED_NOTIFY_EVENT, \"\", \"\", \"Interrupted when waiting for address notify!\" + e);\n            }\n        } else {\n            // do not wait address notify by default\n            delay = 0;\n        }\n        try {\n            latch.await(delay, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            logger.error(REGISTRY_FAILED_NOTIFY_EVENT, \"\", \"\", \"Interrupted when waiting for address notify!\" + e);\n        }\n    }\n\n    @Override\n    public Result invoke(Invocation invocation) throws RpcException {\n        if (currentAvailableInvoker != null) {\n            if (step == APPLICATION_FIRST) {\n                // call ratio calculation based on random value\n                if (promotion < 100 && ThreadLocalRandom.current().nextDouble(100) > promotion) {\n                    // fall back to interface mode\n                    return invoker.invoke(invocation);\n                }\n                // check if invoker available for each time\n                return decideInvoker().invoke(invocation);\n            }\n            return currentAvailableInvoker.invoke(invocation);\n        }\n\n        switch (step) {\n            case APPLICATION_FIRST:\n                currentAvailableInvoker = decideInvoker();\n                break;\n            case FORCE_APPLICATION:\n                currentAvailableInvoker = serviceDiscoveryInvoker;\n                break;\n            case FORCE_INTERFACE:\n            default:\n                currentAvailableInvoker = invoker;\n        }\n\n        return currentAvailableInvoker.invoke(invocation);\n    }\n\n    private ClusterInvoker<T> decideInvoker() {\n        if (currentAvailableInvoker == serviceDiscoveryInvoker) {\n            if (checkInvokerAvailable(serviceDiscoveryInvoker)) {\n                return serviceDiscoveryInvoker;\n            }\n            return invoker;\n        } else {\n            return currentAvailableInvoker;\n        }\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return currentAvailableInvoker != null\n                ? currentAvailableInvoker.isAvailable()\n                : (invoker != null && invoker.isAvailable())\n                        || (serviceDiscoveryInvoker != null && serviceDiscoveryInvoker.isAvailable());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public void destroy() {\n        if (migrationRuleListener != null) {\n            migrationRuleListener.removeMigrationInvoker(this);\n        }\n        if (invoker != null) {\n            invoker.destroy();\n        }\n        if (serviceDiscoveryInvoker != null) {\n            serviceDiscoveryInvoker.destroy();\n        }\n        if (consumerModel != null) {\n            Object object =\n                    consumerModel.getServiceMetadata().getAttribute(CommonConstants.CURRENT_CLUSTER_INVOKER_KEY);\n            Map<Registry, MigrationInvoker<?>> invokerMap;\n            if (object instanceof Map) {\n                invokerMap = (Map<Registry, MigrationInvoker<?>>) object;\n                invokerMap.remove(registry);\n                if (invokerMap.isEmpty()) {\n                    consumerModel\n                            .getServiceMetadata()\n                            .getAttributeMap()\n                            .remove(CommonConstants.CURRENT_CLUSTER_INVOKER_KEY);\n                }\n            }\n        }\n    }\n\n    @Override\n    public URL getUrl() {\n        if (currentAvailableInvoker != null) {\n            return currentAvailableInvoker.getUrl();\n        } else if (invoker != null) {\n            return invoker.getUrl();\n        } else if (serviceDiscoveryInvoker != null) {\n            return serviceDiscoveryInvoker.getUrl();\n        }\n\n        return consumerUrl;\n    }\n\n    @Override\n    public URL getRegistryUrl() {\n        if (currentAvailableInvoker != null) {\n            return currentAvailableInvoker.getRegistryUrl();\n        } else if (invoker != null) {\n            return invoker.getRegistryUrl();\n        } else if (serviceDiscoveryInvoker != null) {\n            return serviceDiscoveryInvoker.getRegistryUrl();\n        }\n        return url;\n    }\n\n    @Override\n    public Directory<T> getDirectory() {\n        if (currentAvailableInvoker != null) {\n            return currentAvailableInvoker.getDirectory();\n        } else if (invoker != null) {\n            return invoker.getDirectory();\n        } else if (serviceDiscoveryInvoker != null) {\n            return serviceDiscoveryInvoker.getDirectory();\n        }\n        return null;\n    }\n\n    @Override\n    public boolean isDestroyed() {\n        return currentAvailableInvoker != null\n                ? currentAvailableInvoker.isDestroyed()\n                : (invoker == null || invoker.isDestroyed())\n                        && (serviceDiscoveryInvoker == null || serviceDiscoveryInvoker.isDestroyed());\n    }\n\n    @Override\n    public boolean isServiceDiscovery() {\n        return false;\n    }\n\n    @Override\n    public MigrationStep getMigrationStep() {\n        return step;\n    }\n\n    @Override\n    public void setMigrationStep(MigrationStep step) {\n        this.step = step;\n    }\n\n    @Override\n    public MigrationRule getMigrationRule() {\n        return rule;\n    }\n\n    @Override\n    public void setMigrationRule(MigrationRule rule) {\n        this.rule = rule;\n        promotion = rule.getProportion(consumerUrl);\n    }\n\n    protected void destroyServiceDiscoveryInvoker() {\n        if (this.invoker != null) {\n            this.currentAvailableInvoker = this.invoker;\n        }\n        if (serviceDiscoveryInvoker != null && !serviceDiscoveryInvoker.isDestroyed()) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\n                        \"Destroying instance address invokers, will not listen for address changes until re-subscribed, \"\n                                + type.getName());\n            }\n            serviceDiscoveryInvoker.destroy();\n            serviceDiscoveryInvoker = null;\n        }\n    }\n\n    protected void refreshServiceDiscoveryInvoker(CountDownLatch latch) {\n        clearListener(serviceDiscoveryInvoker);\n        if (needRefresh(serviceDiscoveryInvoker)) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Re-subscribing instance addresses, current interface \" + type.getName());\n            }\n\n            if (serviceDiscoveryInvoker != null) {\n                serviceDiscoveryInvoker.destroy();\n            }\n            serviceDiscoveryInvoker = registryProtocol.getServiceDiscoveryInvoker(cluster, registry, type, url);\n        }\n        setListener(serviceDiscoveryInvoker, () -> {\n            latch.countDown();\n            if (reportService.hasReporter()) {\n                reportService.reportConsumptionStatus(reportService.createConsumptionReport(\n                        consumerUrl.getServiceInterface(), consumerUrl.getVersion(), consumerUrl.getGroup(), \"app\"));\n            }\n            if (step == APPLICATION_FIRST) {\n                calcPreferredInvoker(rule);\n            }\n        });\n    }\n\n    protected void refreshInterfaceInvoker(CountDownLatch latch) {\n        clearListener(invoker);\n        if (needRefresh(invoker)) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Re-subscribing interface addresses for interface \" + type.getName());\n            }\n\n            if (invoker != null) {\n                invoker.destroy();\n            }\n            invoker = registryProtocol.getInvoker(cluster, registry, type, url);\n        }\n        setListener(invoker, () -> {\n            latch.countDown();\n            if (reportService.hasReporter()) {\n                reportService.reportConsumptionStatus(reportService.createConsumptionReport(\n                        consumerUrl.getServiceInterface(),\n                        consumerUrl.getVersion(),\n                        consumerUrl.getGroup(),\n                        \"interface\"));\n            }\n            if (step == APPLICATION_FIRST) {\n                calcPreferredInvoker(rule);\n            }\n        });\n    }\n\n    private synchronized void calcPreferredInvoker(MigrationRule migrationRule) {\n        if (serviceDiscoveryInvoker == null || invoker == null) {\n            return;\n        }\n        Set<MigrationAddressComparator> detectors = ScopeModelUtil.getApplicationModel(\n                        consumerUrl == null ? null : consumerUrl.getScopeModel())\n                .getExtensionLoader(MigrationAddressComparator.class)\n                .getSupportedExtensionInstances();\n        if (CollectionUtils.isNotEmpty(detectors)) {\n            // pick preferred invoker\n            // the real invoker choice in invocation will be affected by promotion\n            if (detectors.stream()\n                    .allMatch(\n                            comparator -> comparator.shouldMigrate(serviceDiscoveryInvoker, invoker, migrationRule))) {\n                this.currentAvailableInvoker = serviceDiscoveryInvoker;\n            } else {\n                this.currentAvailableInvoker = invoker;\n            }\n        }\n    }\n\n    protected void destroyInterfaceInvoker() {\n        if (this.serviceDiscoveryInvoker != null) {\n            this.currentAvailableInvoker = this.serviceDiscoveryInvoker;\n        }\n        if (invoker != null && !invoker.isDestroyed()) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\n                        \"Destroying interface address invokers, will not listen for address changes until re-subscribed, \"\n                                + type.getName());\n            }\n            invoker.destroy();\n            invoker = null;\n        }\n    }\n\n    private void clearListener(ClusterInvoker<T> invoker) {\n        if (invoker == null) {\n            return;\n        }\n        DynamicDirectory<T> directory = (DynamicDirectory<T>) invoker.getDirectory();\n        directory.setInvokersChangedListener(null);\n    }\n\n    private void setListener(ClusterInvoker<T> invoker, InvokersChangedListener listener) {\n        if (invoker == null) {\n            return;\n        }\n        DynamicDirectory<T> directory = (DynamicDirectory<T>) invoker.getDirectory();\n        directory.setInvokersChangedListener(listener);\n    }\n\n    private boolean needRefresh(ClusterInvoker<T> invoker) {\n        return invoker == null || invoker.isDestroyed() || !invoker.hasProxyInvokers();\n    }\n\n    public boolean checkInvokerAvailable(ClusterInvoker<T> invoker) {\n        return invoker != null && !invoker.isDestroyed() && invoker.isAvailable();\n    }\n\n    protected void setCurrentAvailableInvoker(ClusterInvoker<T> currentAvailableInvoker) {\n        this.currentAvailableInvoker = currentAvailableInvoker;\n    }\n\n    protected void setMigrationRuleListener(MigrationRuleListener migrationRuleListener) {\n        this.migrationRuleListener = migrationRuleListener;\n    }\n\n    public Cluster getCluster() {\n        return cluster;\n    }\n\n    public URL getConsumerUrl() {\n        return consumerUrl;\n    }\n\n    @Override\n    public String toString() {\n        return \"MigrationInvoker{\" + \"serviceKey=\"\n                + consumerUrl.getServiceKey() + \", invoker=\"\n                + decideInvoker() + \", step=\"\n                + step + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationRuleHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.registry.client.migration.model.MigrationStep;\n\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_NO_PARAMETERS_URL;\n\npublic class MigrationRuleHandler<T> {\n    public static final String DUBBO_SERVICEDISCOVERY_MIGRATION = \"dubbo.application.migration.step\";\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(MigrationRuleHandler.class);\n\n    private final MigrationClusterInvoker<T> migrationInvoker;\n    private volatile MigrationStep currentStep;\n    private volatile Float currentThreshold = 0f;\n    private final URL consumerURL;\n    private final ReentrantLock lock = new ReentrantLock();\n\n    public MigrationRuleHandler(MigrationClusterInvoker<T> invoker, URL url) {\n        this.migrationInvoker = invoker;\n        this.consumerURL = url;\n    }\n\n    public void doMigrate(MigrationRule rule) {\n        lock.lock();\n        try {\n            if (migrationInvoker instanceof ServiceDiscoveryMigrationInvoker) {\n                refreshInvoker(MigrationStep.FORCE_APPLICATION, 1.0f, rule);\n                return;\n            }\n\n            // initial step : APPLICATION_FIRST\n            MigrationStep step = MigrationStep.APPLICATION_FIRST;\n            float threshold = -1f;\n\n            try {\n                step = rule.getStep(consumerURL);\n                threshold = rule.getThreshold(consumerURL);\n            } catch (Exception e) {\n                logger.error(\n                        REGISTRY_NO_PARAMETERS_URL,\n                        \"\",\n                        \"\",\n                        \"Failed to get step and threshold info from rule: \" + rule,\n                        e);\n            }\n\n            if (refreshInvoker(step, threshold, rule)) {\n                // refresh success, update rule\n                setMigrationRule(rule);\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    private boolean refreshInvoker(MigrationStep step, Float threshold, MigrationRule newRule) {\n        if (step == null || threshold == null) {\n            throw new IllegalStateException(\"Step or threshold of migration rule cannot be null\");\n        }\n        MigrationStep originStep = currentStep;\n\n        if ((currentStep == null || currentStep != step) || !currentThreshold.equals(threshold)) {\n            boolean success = true;\n            switch (step) {\n                case APPLICATION_FIRST:\n                    migrationInvoker.migrateToApplicationFirstInvoker(newRule);\n                    break;\n                case FORCE_APPLICATION:\n                    success = migrationInvoker.migrateToForceApplicationInvoker(newRule);\n                    break;\n                case FORCE_INTERFACE:\n                default:\n                    success = migrationInvoker.migrateToForceInterfaceInvoker(newRule);\n            }\n\n            if (success) {\n                setCurrentStepAndThreshold(step, threshold);\n                logger.info(\n                        \"Succeed Migrated to \" + step + \" mode. Service Name: \" + consumerURL.getDisplayServiceKey());\n                report(step, originStep, \"true\");\n            } else {\n                // migrate failed, do not save new step and rule\n                logger.warn(\n                        INTERNAL_ERROR,\n                        \"unknown error in registry module\",\n                        \"\",\n                        \"Migrate to \" + step + \" mode failed. Probably not satisfy the threshold you set \" + threshold\n                                + \". Please try re-publish configuration if you still after check.\");\n                report(step, originStep, \"false\");\n            }\n\n            return success;\n        }\n        // ignore if step is same with previous, will continue override rule for MigrationInvoker\n        return true;\n    }\n\n    private void report(MigrationStep step, MigrationStep originStep, String success) {\n        FrameworkStatusReportService reportService =\n                consumerURL.getOrDefaultApplicationModel().getBeanFactory().getBean(FrameworkStatusReportService.class);\n\n        if (reportService.hasReporter()) {\n            reportService.reportMigrationStepStatus(reportService.createMigrationStepReport(\n                    consumerURL.getServiceInterface(),\n                    consumerURL.getVersion(),\n                    consumerURL.getGroup(),\n                    String.valueOf(originStep),\n                    String.valueOf(step),\n                    success));\n        }\n    }\n\n    private void setMigrationRule(MigrationRule rule) {\n        this.migrationInvoker.setMigrationRule(rule);\n    }\n\n    private void setCurrentStepAndThreshold(MigrationStep currentStep, Float currentThreshold) {\n        if (currentThreshold != null) {\n            this.currentThreshold = currentThreshold;\n        }\n        if (currentStep != null) {\n            this.currentStep = currentStep;\n            this.migrationInvoker.setMigrationStep(currentStep);\n        }\n    }\n\n    // for test purpose\n    public MigrationStep getMigrationStep() {\n        return currentStep;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationRuleListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.registry.integration.RegistryProtocol;\nimport org.apache.dubbo.registry.integration.RegistryProtocolListener;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_PROPERTY_TYPE_MISMATCH;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_THREAD_INTERRUPTED_EXCEPTION;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_EMPTY_ADDRESS;\nimport static org.apache.dubbo.common.constants.RegistryConstants.INIT;\n\n/**\n * Listens to {@MigrationRule} from Config Center.\n * <p>\n * - Migration rule is of consumer application scope.\n * - Listener is shared among all invokers (interfaces), it keeps the relation between interface and handler.\n * <p>\n * There are two execution points:\n * - Refer, invoker behaviour is determined with default rule.\n * - Rule change, invoker behaviour is changed according to the newly received rule.\n */\n@Activate\npublic class MigrationRuleListener implements RegistryProtocolListener, ConfigurationListener {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(MigrationRuleListener.class);\n    private static final String DUBBO_SERVICEDISCOVERY_MIGRATION = \"DUBBO_SERVICEDISCOVERY_MIGRATION\";\n    private static final String MIGRATION_DELAY_KEY = \"dubbo.application.migration.delay\";\n    private static final int MIGRATION_DEFAULT_DELAY_TIME = 60000;\n    private String ruleKey;\n\n    protected final ConcurrentMap<MigrationInvoker<?>, MigrationRuleHandler<?>> handlers = new ConcurrentHashMap<>();\n    protected final LinkedBlockingQueue<String> ruleQueue = new LinkedBlockingQueue<>();\n\n    private final AtomicBoolean executorSubmit = new AtomicBoolean(false);\n    private final ExecutorService ruleManageExecutor =\n            Executors.newFixedThreadPool(1, new NamedThreadFactory(\"Dubbo-Migration-Listener\"));\n\n    protected ScheduledFuture<?> localRuleMigrationFuture;\n    protected Future<?> ruleMigrationFuture;\n\n    private DynamicConfiguration configuration;\n\n    private volatile String rawRule;\n    private volatile MigrationRule rule;\n    private final ModuleModel moduleModel;\n\n    public MigrationRuleListener(ModuleModel moduleModel) {\n        this.moduleModel = moduleModel;\n        init();\n    }\n\n    private void init() {\n        this.ruleKey = moduleModel.getApplicationModel().getApplicationName() + \".migration\";\n        this.configuration =\n                moduleModel.modelEnvironment().getDynamicConfiguration().orElse(null);\n\n        if (this.configuration != null) {\n            logger.info(\"Listening for migration rules on dataId \" + ruleKey + \", group \"\n                    + DUBBO_SERVICEDISCOVERY_MIGRATION);\n            configuration.addListener(ruleKey, DUBBO_SERVICEDISCOVERY_MIGRATION, this);\n\n            String rawRule = configuration.getConfig(ruleKey, DUBBO_SERVICEDISCOVERY_MIGRATION);\n            if (StringUtils.isEmpty(rawRule)) {\n                rawRule = INIT;\n            }\n            setRawRule(rawRule);\n        } else {\n            if (logger.isWarnEnabled()) {\n                logger.warn(\n                        REGISTRY_EMPTY_ADDRESS,\n                        \"\",\n                        \"\",\n                        \"Using default configuration rule because config center is not configured!\");\n            }\n            setRawRule(INIT);\n        }\n\n        String localRawRule = moduleModel.modelEnvironment().getLocalMigrationRule();\n        if (!StringUtils.isEmpty(localRawRule)) {\n            localRuleMigrationFuture = moduleModel\n                    .getApplicationModel()\n                    .getFrameworkModel()\n                    .getBeanFactory()\n                    .getBean(FrameworkExecutorRepository.class)\n                    .getSharedScheduledExecutor()\n                    .schedule(\n                            () -> {\n                                if (this.rawRule.equals(INIT)) {\n                                    this.process(new ConfigChangedEvent(null, null, localRawRule));\n                                }\n                            },\n                            getDelay(),\n                            TimeUnit.MILLISECONDS);\n        }\n    }\n\n    private int getDelay() {\n        int delay = MIGRATION_DEFAULT_DELAY_TIME;\n        String delayStr = ConfigurationUtils.getProperty(moduleModel, MIGRATION_DELAY_KEY);\n        if (StringUtils.isEmpty(delayStr)) {\n            return delay;\n        }\n\n        try {\n            delay = Integer.parseInt(delayStr);\n        } catch (Exception e) {\n            logger.warn(COMMON_PROPERTY_TYPE_MISMATCH, \"\", \"\", \"Invalid migration delay param \" + delayStr);\n        }\n        return delay;\n    }\n\n    @Override\n    public synchronized void process(ConfigChangedEvent event) {\n        String rawRule = event.getContent();\n        if (StringUtils.isEmpty(rawRule)) {\n            // fail back to startup status\n            rawRule = INIT;\n            // logger.warn(COMMON_PROPERTY_TYPE_MISMATCH, \"\", \"\", \"Received empty migration rule, will ignore.\");\n        }\n        try {\n            ruleQueue.put(rawRule);\n        } catch (InterruptedException e) {\n            logger.error(\n                    COMMON_THREAD_INTERRUPTED_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Put rawRule to rule management queue failed. rawRule: \" + rawRule,\n                    e);\n        }\n\n        if (executorSubmit.compareAndSet(false, true)) {\n            ruleMigrationFuture = ruleManageExecutor.submit(() -> {\n                while (true) {\n                    String rule = \"\";\n                    try {\n                        rule = ruleQueue.take();\n                        if (StringUtils.isEmpty(rule)) {\n                            Thread.sleep(1000);\n                        }\n                    } catch (InterruptedException e) {\n                        logger.error(\n                                COMMON_THREAD_INTERRUPTED_EXCEPTION, \"\", \"\", \"Poll Rule from config center failed.\", e);\n                    }\n                    if (StringUtils.isEmpty(rule)) {\n                        continue;\n                    }\n                    if (Objects.equals(this.rawRule, rule)) {\n                        logger.info(\"Ignore duplicated rule\");\n                        continue;\n                    }\n\n                    logger.info(\"Using the following migration rule to migrate:\");\n                    logger.info(rule);\n\n                    setRawRule(rule);\n\n                    if (CollectionUtils.isEmptyMap(handlers)) {\n                        continue;\n                    }\n\n                    ExecutorService executorService = null;\n                    try {\n                        executorService = Executors.newFixedThreadPool(\n                                Math.min(handlers.size(), 100), new NamedThreadFactory(\"Dubbo-Invoker-Migrate\"));\n                        List<Future<?>> migrationFutures = new ArrayList<>(handlers.size());\n                        for (MigrationRuleHandler<?> handler : handlers.values()) {\n                            Future<?> future = executorService.submit(() -> handler.doMigrate(this.rule));\n                            migrationFutures.add(future);\n                        }\n\n                        for (Future<?> future : migrationFutures) {\n                            try {\n                                future.get();\n                            } catch (InterruptedException ie) {\n                                logger.warn(\n                                        INTERNAL_ERROR,\n                                        \"unknown error in registry module\",\n                                        \"\",\n                                        \"Interrupted while waiting for migration async task to finish.\");\n                            } catch (ExecutionException ee) {\n                                logger.error(\n                                        INTERNAL_ERROR,\n                                        \"unknown error in registry module\",\n                                        \"\",\n                                        \"Migration async task failed.\",\n                                        ee.getCause());\n                            }\n                        }\n                    } catch (Throwable t) {\n                        logger.error(\n                                INTERNAL_ERROR,\n                                \"unknown error in registry module\",\n                                \"\",\n                                \"Error occurred when migration.\",\n                                t);\n                    } finally {\n                        if (executorService != null) {\n                            executorService.shutdown();\n                        }\n                    }\n                }\n            });\n        }\n    }\n\n    public void setRawRule(String rawRule) {\n        this.rawRule = rawRule;\n        this.rule = parseRule(this.rawRule);\n    }\n\n    private MigrationRule parseRule(String rawRule) {\n        MigrationRule tmpRule = rule == null ? MigrationRule.getInitRule() : rule;\n        if (INIT.equals(rawRule)) {\n            tmpRule = MigrationRule.getInitRule();\n        } else {\n            try {\n                tmpRule = MigrationRule.parse(rawRule);\n            } catch (Exception e) {\n                logger.error(COMMON_PROPERTY_TYPE_MISMATCH, \"\", \"\", \"Failed to parse migration rule...\", e);\n            }\n        }\n        return tmpRule;\n    }\n\n    @Override\n    public void onExport(RegistryProtocol registryProtocol, Exporter<?> exporter) {}\n\n    @Override\n    public void onRefer(\n            RegistryProtocol registryProtocol, ClusterInvoker<?> invoker, URL consumerUrl, URL registryURL) {\n        MigrationRuleHandler<?> migrationRuleHandler =\n                ConcurrentHashMapUtils.computeIfAbsent(handlers, (MigrationInvoker<?>) invoker, _key -> {\n                    ((MigrationInvoker<?>) invoker).setMigrationRuleListener(this);\n                    return new MigrationRuleHandler<>((MigrationInvoker<?>) invoker, consumerUrl);\n                });\n\n        migrationRuleHandler.doMigrate(rule);\n    }\n\n    @Override\n    public void onDestroy() {\n        if (configuration != null) {\n            configuration.removeListener(ruleKey, DUBBO_SERVICEDISCOVERY_MIGRATION, this);\n        }\n        if (ruleMigrationFuture != null) {\n            ruleMigrationFuture.cancel(true);\n        }\n        if (localRuleMigrationFuture != null) {\n            localRuleMigrationFuture.cancel(true);\n        }\n        ruleManageExecutor.shutdown();\n        ruleQueue.clear();\n    }\n\n    public Map<MigrationInvoker<?>, MigrationRuleHandler<?>> getHandlers() {\n        return handlers;\n    }\n\n    protected void removeMigrationInvoker(MigrationInvoker<?> migrationInvoker) {\n        handlers.remove(migrationInvoker);\n    }\n\n    public MigrationRule getRule() {\n        return rule;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/PreMigratingConditionChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\n\n@SPI\npublic interface PreMigratingConditionChecker {\n    boolean checkCondition(URL consumerUrl);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/ServiceDiscoveryMigrationInvoker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.registry.integration.RegistryProtocol;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Result;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\nimport java.util.concurrent.CountDownLatch;\n\npublic class ServiceDiscoveryMigrationInvoker<T> extends MigrationInvoker<T> {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ServiceDiscoveryMigrationInvoker.class);\n\n    public ServiceDiscoveryMigrationInvoker(\n            RegistryProtocol registryProtocol,\n            Cluster cluster,\n            Registry registry,\n            Class<T> type,\n            URL url,\n            URL consumerUrl) {\n        super(registryProtocol, cluster, registry, type, url, consumerUrl);\n    }\n\n    @Override\n    public boolean isServiceDiscovery() {\n        return true;\n    }\n\n    @Override\n    public boolean migrateToForceInterfaceInvoker(MigrationRule newRule) {\n        CountDownLatch latch = new CountDownLatch(0);\n        refreshServiceDiscoveryInvoker(latch);\n\n        setCurrentAvailableInvoker(getServiceDiscoveryInvoker());\n        return true;\n    }\n\n    @Override\n    public void migrateToApplicationFirstInvoker(MigrationRule newRule) {\n        CountDownLatch latch = new CountDownLatch(0);\n        refreshServiceDiscoveryInvoker(latch);\n\n        setCurrentAvailableInvoker(getServiceDiscoveryInvoker());\n    }\n\n    @Override\n    public Result invoke(Invocation invocation) throws RpcException {\n        ClusterInvoker<T> invoker = getServiceDiscoveryInvoker();\n        if (invoker == null) {\n            throw new IllegalStateException(\n                    \"There's no service discovery invoker available for service \" + invocation.getServiceName());\n        }\n        return invoker.invoke(invocation);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/model/MigrationRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration.model;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.ServiceNameMapping;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.Constructor;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\n\nimport static org.apache.dubbo.registry.Constants.MIGRATION_DELAY_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_FORCE_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_PROMOTION_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_APPLICATIONS_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_DELAY_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_FORCE_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_INTERFACES_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_PROPORTION_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_STEP_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_THRESHOLD_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_STEP_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_THRESHOLD_KEY;\nimport static org.apache.dubbo.registry.client.migration.MigrationRuleHandler.DUBBO_SERVICEDISCOVERY_MIGRATION;\n\n/**\n * # key = demo-consumer.migration\n * # group = DUBBO_SERVICEDISCOVERY_MIGRATION\n * # content\n * key: demo-consumer\n * step: APPLICATION_FIRST\n * threshold: 1.0\n * proportion: 60\n * delay: 60\n * force: false\n * interfaces:\n *   - serviceKey: DemoService:1.0.0\n *     threshold: 0.5\n *     proportion: 30\n *     delay: 30\n *     force: true\n *     step: APPLICATION_FIRST\n *   - serviceKey: GreetingService:1.0.0\n *     step: FORCE_APPLICATION\n * applications:\n *  - serviceKey: TestApplication\n *    threshold: 0.3\n *    proportion: 20\n *    delay: 10\n *    force: false\n *    step: FORCE_INTERFACE\n */\npublic class MigrationRule {\n\n    private String key;\n    private MigrationStep step;\n    private Float threshold;\n    private Integer proportion;\n    private Integer delay;\n    private Boolean force;\n    private List<SubMigrationRule> interfaces;\n    private List<SubMigrationRule> applications;\n\n    private transient Map<String, SubMigrationRule> interfaceRules;\n    private transient Map<String, SubMigrationRule> applicationRules;\n\n    public static MigrationRule getInitRule() {\n        return new MigrationRule();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static MigrationRule parseFromMap(Map<String, Object> map) {\n        MigrationRule migrationRule = new MigrationRule();\n        migrationRule.setKey((String) map.get(MIGRATION_RULE_KEY));\n\n        Object step = map.get(MIGRATION_RULE_STEP_KEY);\n        if (step != null) {\n            migrationRule.setStep(MigrationStep.valueOf(step.toString()));\n        }\n\n        Object threshold = map.get(MIGRATION_RULE_THRESHOLD_KEY);\n        if (threshold != null) {\n            migrationRule.setThreshold(Float.valueOf(threshold.toString()));\n        }\n\n        Object proportion = map.get(MIGRATION_RULE_PROPORTION_KEY);\n        if (proportion != null) {\n            migrationRule.setProportion(Integer.valueOf(proportion.toString()));\n        }\n\n        Object delay = map.get(MIGRATION_RULE_DELAY_KEY);\n        if (delay != null) {\n            migrationRule.setDelay(Integer.valueOf(delay.toString()));\n        }\n\n        Object force = map.get(MIGRATION_RULE_FORCE_KEY);\n        if (force != null) {\n            migrationRule.setForce(Boolean.valueOf(force.toString()));\n        }\n\n        Object interfaces = map.get(MIGRATION_RULE_INTERFACES_KEY);\n        if (interfaces != null && List.class.isAssignableFrom(interfaces.getClass())) {\n            migrationRule.setInterfaces(((List<Map<String, Object>>) interfaces)\n                    .stream().map(SubMigrationRule::parseFromMap).collect(Collectors.toList()));\n        }\n\n        Object applications = map.get(MIGRATION_RULE_APPLICATIONS_KEY);\n        if (applications != null && List.class.isAssignableFrom(applications.getClass())) {\n            migrationRule.setApplications(((List<Map<String, Object>>) applications)\n                    .stream().map(SubMigrationRule::parseFromMap).collect(Collectors.toList()));\n        }\n\n        return migrationRule;\n    }\n\n    public MigrationRule() {}\n\n    public MigrationRule(String key) {\n        this.key = key;\n    }\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public MigrationStep getStep(URL consumerURL) {\n        MigrationStep value = getValue(consumerURL, SubMigrationRule::getStep);\n        if (value != null) {\n            return value;\n        }\n\n        /**\n         * FIXME, it's really hard to follow setting default values here.\n         */\n        if (step == null) {\n            // initial step : APPLICATION_FIRST\n            return Enum.valueOf(\n                    MigrationStep.class,\n                    consumerURL.getParameter(\n                            MIGRATION_STEP_KEY, getDefaultStep(consumerURL, MigrationStep.APPLICATION_FIRST.name())));\n        }\n\n        return step;\n    }\n\n    private String getDefaultStep(URL consumerURL, String defaultStep) {\n        String globalDefaultStep = ConfigurationUtils.getCachedDynamicProperty(\n                consumerURL.getScopeModel(), DUBBO_SERVICEDISCOVERY_MIGRATION, null);\n        if (StringUtils.isEmpty(globalDefaultStep)) {\n            // check 'dubbo.application.service-discovery.migration' for compatibility\n            globalDefaultStep = ConfigurationUtils.getCachedDynamicProperty(\n                    consumerURL.getScopeModel(), \"dubbo.application.service-discovery.migration\", defaultStep);\n        }\n        return globalDefaultStep;\n    }\n\n    public MigrationStep getStep() {\n        return step;\n    }\n\n    public float getThreshold(URL consumerURL) {\n        Float value = getValue(consumerURL, SubMigrationRule::getThreshold);\n        if (value != null) {\n            return value;\n        }\n\n        return threshold == null ? consumerURL.getParameter(MIGRATION_THRESHOLD_KEY, -1f) : threshold;\n    }\n\n    public Float getThreshold() {\n        return threshold;\n    }\n\n    public void setThreshold(Float threshold) {\n        this.threshold = threshold;\n    }\n\n    public Integer getProportion() {\n        return proportion;\n    }\n\n    public int getProportion(URL consumerURL) {\n        Integer value = getValue(consumerURL, SubMigrationRule::getProportion);\n        if (value != null) {\n            return value;\n        }\n\n        return proportion == null ? consumerURL.getParameter(MIGRATION_PROMOTION_KEY, 100) : proportion;\n    }\n\n    public void setProportion(Integer proportion) {\n        this.proportion = proportion;\n    }\n\n    public Integer getDelay() {\n        return delay;\n    }\n\n    public int getDelay(URL consumerURL) {\n        Integer value = getValue(consumerURL, SubMigrationRule::getDelay);\n        if (value != null) {\n            return value;\n        }\n\n        return delay == null ? consumerURL.getParameter(MIGRATION_DELAY_KEY, 0) : delay;\n    }\n\n    public void setDelay(Integer delay) {\n        this.delay = delay;\n    }\n\n    public void setStep(MigrationStep step) {\n        this.step = step;\n    }\n\n    public Boolean getForce() {\n        return force;\n    }\n\n    public boolean getForce(URL consumerURL) {\n        Boolean value = getValue(consumerURL, SubMigrationRule::getForce);\n        if (value != null) {\n            return value;\n        }\n\n        return force == null ? consumerURL.getParameter(MIGRATION_FORCE_KEY, false) : force;\n    }\n\n    public <T> T getValue(URL consumerURL, Function<SubMigrationRule, T> function) {\n        if (interfaceRules != null) {\n            SubMigrationRule rule = interfaceRules.get(consumerURL.getDisplayServiceKey());\n            if (rule != null) {\n                T value = function.apply(rule);\n                if (value != null) {\n                    return value;\n                }\n            }\n        }\n\n        if (applications != null) {\n            ServiceNameMapping serviceNameMapping = ServiceNameMapping.getDefaultExtension(consumerURL.getScopeModel());\n            Set<String> services = serviceNameMapping.getRemoteMapping(consumerURL);\n            if (CollectionUtils.isNotEmpty(services)) {\n                for (String service : services) {\n                    SubMigrationRule rule = applicationRules.get(service);\n                    if (rule != null) {\n                        T value = function.apply(rule);\n                        if (value != null) {\n                            return value;\n                        }\n                    }\n                }\n            }\n        }\n        return null;\n    }\n\n    public void setForce(Boolean force) {\n        this.force = force;\n    }\n\n    public List<SubMigrationRule> getInterfaces() {\n        return interfaces;\n    }\n\n    public void setInterfaces(List<SubMigrationRule> interfaces) {\n        this.interfaces = interfaces;\n        if (interfaces != null) {\n            this.interfaceRules = new HashMap<>();\n            interfaces.forEach(rule -> {\n                interfaceRules.put(rule.getServiceKey(), rule);\n            });\n        }\n    }\n\n    public List<SubMigrationRule> getApplications() {\n        return applications;\n    }\n\n    public void setApplications(List<SubMigrationRule> applications) {\n        this.applications = applications;\n        if (applications != null) {\n            this.applicationRules = new HashMap<>();\n            applications.forEach(rule -> {\n                applicationRules.put(rule.getServiceKey(), rule);\n            });\n        }\n    }\n\n    public static MigrationRule parse(String rawRule) {\n        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));\n        Map<String, Object> map = yaml.load(rawRule);\n        return parseFromMap(map);\n    }\n\n    public static String toYaml(MigrationRule rule) {\n        Constructor constructor = new Constructor(MigrationRule.class, new LoaderOptions());\n        Yaml yaml = new Yaml(constructor);\n        return yaml.dump(rule);\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        MigrationRule that = (MigrationRule) o;\n        return Objects.equals(key, that.key)\n                && step == that.step\n                && Objects.equals(threshold, that.threshold)\n                && Objects.equals(proportion, that.proportion)\n                && Objects.equals(delay, that.delay)\n                && Objects.equals(force, that.force)\n                && Objects.equals(interfaces, that.interfaces)\n                && Objects.equals(applications, that.applications)\n                && Objects.equals(interfaceRules, that.interfaceRules)\n                && Objects.equals(applicationRules, that.applicationRules);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(\n                key,\n                step,\n                threshold,\n                proportion,\n                delay,\n                force,\n                interfaces,\n                applications,\n                interfaceRules,\n                applicationRules);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/model/MigrationStep.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration.model;\n\npublic enum MigrationStep {\n    FORCE_INTERFACE,\n    APPLICATION_FIRST,\n    FORCE_APPLICATION\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/model/SubMigrationRule.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration.model;\n\nimport java.util.Map;\n\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_DELAY_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_FORCE_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_PROPORTION_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_STEP_KEY;\nimport static org.apache.dubbo.registry.Constants.MIGRATION_RULE_THRESHOLD_KEY;\n\npublic class SubMigrationRule {\n    private String serviceKey;\n    private MigrationStep step;\n    private Float threshold;\n    private Integer proportion;\n    private Integer delay;\n    private Boolean force;\n\n    public static SubMigrationRule parseFromMap(Map<String, Object> map) {\n        SubMigrationRule interfaceMigrationRule = new SubMigrationRule();\n        interfaceMigrationRule.setServiceKey((String) map.get(\"serviceKey\"));\n\n        Object step = map.get(MIGRATION_RULE_STEP_KEY);\n        if (step != null) {\n            interfaceMigrationRule.setStep(MigrationStep.valueOf(step.toString()));\n        }\n\n        Object threshold = map.get(MIGRATION_RULE_THRESHOLD_KEY);\n        if (threshold != null) {\n            interfaceMigrationRule.setThreshold(Float.valueOf(threshold.toString()));\n        }\n\n        Object proportion = map.get(MIGRATION_RULE_PROPORTION_KEY);\n        if (proportion != null) {\n            interfaceMigrationRule.setProportion(Integer.valueOf(proportion.toString()));\n        }\n\n        Object delay = map.get(MIGRATION_RULE_DELAY_KEY);\n        if (delay != null) {\n            interfaceMigrationRule.setDelay(Integer.valueOf(delay.toString()));\n        }\n\n        Object force = map.get(MIGRATION_RULE_FORCE_KEY);\n        if (force != null) {\n            interfaceMigrationRule.setForce(Boolean.valueOf(force.toString()));\n        }\n\n        return interfaceMigrationRule;\n    }\n\n    public SubMigrationRule() {}\n\n    public SubMigrationRule(String serviceKey, MigrationStep step, Float threshold, Integer proportion) {\n        this.serviceKey = serviceKey;\n        this.step = step;\n        this.threshold = threshold;\n        this.proportion = proportion;\n    }\n\n    public String getServiceKey() {\n        return serviceKey;\n    }\n\n    public void setServiceKey(String serviceKey) {\n        this.serviceKey = serviceKey;\n    }\n\n    public MigrationStep getStep() {\n        return step;\n    }\n\n    public void setStep(MigrationStep step) {\n        this.step = step;\n    }\n\n    public Float getThreshold() {\n        return threshold;\n    }\n\n    public void setThreshold(Float threshold) {\n        this.threshold = threshold;\n    }\n\n    public Integer getProportion() {\n        return proportion;\n    }\n\n    public void setProportion(Integer proportion) {\n        this.proportion = proportion;\n    }\n\n    public Integer getDelay() {\n        return delay;\n    }\n\n    public void setDelay(Integer delay) {\n        this.delay = delay;\n    }\n\n    public Boolean getForce() {\n        return force;\n    }\n\n    public void setForce(Boolean force) {\n        this.force = force;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/package-info.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * * The inspiration of service registration and discovery comes from\n * <a href=\"https://spring.io/projects/spring-cloud-commons\">Spring Cloud Commons</a>.\n *\n * @since 2.7.5\n */\npackage org.apache.dubbo.registry.client;\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/AbstractConfiguratorListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangeType;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.ConfigurationListener;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.cluster.Configurator;\nimport org.apache.dubbo.rpc.cluster.configurator.parser.ConfigParser;\nimport org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_PARSE_DYNAMIC_CONFIG;\nimport static org.apache.dubbo.rpc.Constants.ACCESS_LOG_FIXED_PATH_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.TYPE_KEY;\n\npublic abstract class AbstractConfiguratorListener implements ConfigurationListener {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(AbstractConfiguratorListener.class);\n\n    protected List<Configurator> configurators = Collections.emptyList();\n    protected GovernanceRuleRepository ruleRepository;\n\n    protected Set<String> securityKey = new HashSet<>();\n    protected ModuleModel moduleModel;\n\n    public AbstractConfiguratorListener(ModuleModel moduleModel) {\n        this.moduleModel = moduleModel;\n\n        ruleRepository =\n                moduleModel.getExtensionLoader(GovernanceRuleRepository.class).getDefaultExtension();\n\n        initSecurityKey();\n    }\n\n    private void initSecurityKey() {\n        // FileRouterFactory key\n        securityKey.add(ACCESS_LOG_FIXED_PATH_KEY);\n        securityKey.add(ROUTER_KEY);\n        securityKey.add(RULE_KEY);\n        securityKey.add(RUNTIME_KEY);\n        securityKey.add(TYPE_KEY);\n    }\n\n    protected final void initWith(String key) {\n        ruleRepository.addListener(key, this);\n        String rawConfig = ruleRepository.getRule(key, DynamicConfiguration.DEFAULT_GROUP);\n        if (!StringUtils.isEmpty(rawConfig)) {\n            genConfiguratorsFromRawRule(rawConfig);\n        }\n    }\n\n    protected final void stopListen(String key) {\n        ruleRepository.removeListener(key, this);\n    }\n\n    @Override\n    public void process(ConfigChangedEvent event) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Notification of overriding rule, change type is: \" + event.getChangeType()\n                    + \", raw config content is:\\n \" + event.getContent());\n        }\n\n        if (event.getChangeType().equals(ConfigChangeType.DELETED)) {\n            configurators.clear();\n        } else {\n            // ADDED or MODIFIED\n            if (!genConfiguratorsFromRawRule(event.getContent())) {\n                return;\n            }\n        }\n\n        notifyOverrides();\n    }\n\n    private boolean genConfiguratorsFromRawRule(String rawConfig) {\n        List<URL> urls;\n        try {\n            // parseConfigurators will recognize app/service config automatically.\n            urls = ConfigParser.parseConfigurators(rawConfig);\n        } catch (Exception e) {\n            // 1-14 - Failed to parse raw dynamic config.\n\n            logger.warn(\n                    REGISTRY_FAILED_PARSE_DYNAMIC_CONFIG,\n                    \"\",\n                    \"\",\n                    \"Failed to parse raw dynamic config and it will not take effect, the raw config is: \" + rawConfig\n                            + \", cause: \" + e.getMessage());\n\n            return false;\n        }\n        List<URL> safeUrls = urls.stream()\n                .map(url -> url.removeParameters(securityKey))\n                .map(url -> url.setScopeModel(moduleModel))\n                .collect(Collectors.toList());\n        configurators = Configurator.toConfigurators(safeUrls).orElse(configurators);\n        return true;\n    }\n\n    protected abstract void notifyOverrides();\n\n    public List<Configurator> getConfigurators() {\n        return configurators;\n    }\n\n    public void setConfigurators(List<Configurator> configurators) {\n        this.configurators = configurators;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DefaultServiceURLCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.BACKGROUND_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXTRA_KEYS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.HIDE_KEY_PREFIX;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TRIPLE_PREFIX;\nimport static org.apache.dubbo.common.constants.FilterConstants.VALIDATION_KEY;\nimport static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_HOST;\nimport static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;\nimport static org.apache.dubbo.registry.Constants.SIMPLIFIED_KEY;\nimport static org.apache.dubbo.registry.integration.RegistryProtocol.DEFAULT_REGISTER_PROVIDER_KEYS;\nimport static org.apache.dubbo.remoting.Constants.BIND_IP_KEY;\nimport static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY;\nimport static org.apache.dubbo.rpc.Constants.INTERFACES;\n\npublic class DefaultServiceURLCustomizer implements ServiceURLCustomizer {\n\n    private static final String[] excludedParameters = new String[] {\n        MONITOR_KEY,\n        BIND_IP_KEY,\n        BIND_PORT_KEY,\n        QOS_ENABLE,\n        QOS_HOST,\n        QOS_PORT,\n        ACCEPT_FOREIGN_IP,\n        VALIDATION_KEY,\n        INTERFACES,\n        REGISTER_MODE_KEY,\n        PID_KEY,\n        REGISTRY_LOCAL_FILE_CACHE_ENABLED,\n        EXECUTOR_MANAGEMENT_MODE,\n        BACKGROUND_KEY,\n        ANYHOST_KEY,\n        THREAD_NAME_KEY,\n        THREADPOOL_KEY,\n        ALIVE_KEY,\n        QUEUES_KEY,\n        CORE_THREADS_KEY,\n        THREADS_KEY\n    };\n\n    private static final String[] excludedPrefixes = new String[] {HIDE_KEY_PREFIX, TRIPLE_PREFIX};\n\n    @Override\n    public URL customize(URL serviceURL, ApplicationModel applicationModel) {\n        boolean simplified = (boolean) serviceURL.getAttribute(SIMPLIFIED_KEY, false);\n        if (simplified) {\n            String extraKeys = (String) serviceURL.getAttribute(EXTRA_KEYS_KEY, \"\");\n            // if path is not the same as interface name then we should keep INTERFACE_KEY,\n            // otherwise, the registry structure of zookeeper would be '/dubbo/path/providers',\n            // but what we expect is '/dubbo/interface/providers'\n            if (!serviceURL.getPath().equals(serviceURL.getParameter(INTERFACE_KEY))) {\n                if (StringUtils.isNotEmpty(extraKeys)) {\n                    extraKeys += \",\";\n                }\n                extraKeys += INTERFACE_KEY;\n            }\n            String[] paramsToRegistry = Stream.concat(\n                            Arrays.stream(DEFAULT_REGISTER_PROVIDER_KEYS),\n                            Arrays.stream(COMMA_SPLIT_PATTERN.split(extraKeys)))\n                    .toArray(String[]::new);\n            return URL.valueOf(serviceURL, paramsToRegistry, serviceURL.getParameter(METHODS_KEY, (String[]) null));\n        }\n        return serviceURL.removeParameters(getFilteredKeys(serviceURL)).removeParameters(excludedParameters);\n    }\n\n    @Override\n    public int getPriority() {\n        return MAX_PRIORITY;\n    }\n\n    private String[] getFilteredKeys(URL url) {\n        Map<String, String> params = url.getParameters();\n        if (CollectionUtils.isNotEmptyMap(params)) {\n            return params.keySet().stream()\n                    .filter(k -> {\n                        for (String excludedPrefix : excludedPrefixes) {\n                            if (k.startsWith(excludedPrefix)) {\n                                return true;\n                            }\n                        }\n                        return false;\n                    })\n                    .toArray(String[]::new);\n        }\n        return new String[0];\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.AddressListener;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.registry.client.migration.InvokersChangedListener;\nimport org.apache.dubbo.rpc.Invocation;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.Configurator;\nimport org.apache.dubbo.rpc.cluster.Constants;\nimport org.apache.dubbo.rpc.cluster.RouterChain;\nimport org.apache.dubbo.rpc.cluster.RouterFactory;\nimport org.apache.dubbo.rpc.cluster.SingleRouterChain;\nimport org.apache.dubbo.rpc.cluster.directory.AbstractDirectory;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_SITE_SELECTION;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_DESTROY_SERVICE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_DESTROY_UNREGISTER_URL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;\nimport static org.apache.dubbo.registry.Constants.REGISTER_KEY;\nimport static org.apache.dubbo.registry.Constants.SIMPLIFIED_KEY;\nimport static org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol.DEFAULT_REGISTER_CONSUMER_KEYS;\nimport static org.apache.dubbo.remoting.Constants.CHECK_KEY;\n\n/**\n * DynamicDirectory\n */\npublic abstract class DynamicDirectory<T> extends AbstractDirectory<T> implements NotifyListener {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DynamicDirectory.class);\n\n    protected final Cluster cluster;\n\n    protected final RouterFactory routerFactory;\n\n    /**\n     * Initialization at construction time, assertion not null\n     */\n    protected final String serviceKey;\n\n    /**\n     * Initialization at construction time, assertion not null\n     */\n    protected final Class<T> serviceType;\n\n    /**\n     * Initialization at construction time, assertion not null, and always assign non-null value\n     */\n    protected volatile URL directoryUrl;\n\n    protected final boolean multiGroup;\n\n    /**\n     * Initialization at the time of injection, the assertion is not null\n     */\n    protected Protocol protocol;\n\n    /**\n     * Initialization at the time of injection, the assertion is not null\n     */\n    protected Registry registry;\n\n    protected volatile boolean forbidden = false;\n    protected boolean shouldRegister;\n    protected boolean shouldSimplified;\n\n    /**\n     * Initialization at construction time, assertion not null, and always assign not null value\n     */\n    protected volatile URL subscribeUrl;\n\n    protected volatile URL registeredConsumerUrl;\n\n    /**\n     * The initial value is null and the midway may be assigned to null, please use the local variable reference\n     * override rules\n     * Priority: override>-D>consumer>provider\n     * Rule one: for a certain provider <ip:port,timeout=100>\n     * Rule two: for all providers <* ,timeout=5000>\n     */\n    protected volatile List<Configurator> configurators;\n\n    protected ServiceInstancesChangedListener serviceListener;\n\n    /**\n     * Should continue route if directory is empty\n     */\n    private final boolean shouldFailFast;\n\n    private volatile InvokersChangedListener invokersChangedListener;\n    private volatile boolean invokersChanged;\n\n    public DynamicDirectory(Class<T> serviceType, URL url) {\n        super(url, true);\n\n        ModuleModel moduleModel = url.getOrDefaultModuleModel();\n\n        this.cluster = moduleModel.getExtensionLoader(Cluster.class).getAdaptiveExtension();\n        this.routerFactory = moduleModel.getExtensionLoader(RouterFactory.class).getAdaptiveExtension();\n\n        if (serviceType == null) {\n            throw new IllegalArgumentException(\"service type is null.\");\n        }\n\n        if (StringUtils.isEmpty(url.getServiceKey())) {\n            throw new IllegalArgumentException(\"registry serviceKey is null.\");\n        }\n\n        this.shouldRegister = !ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(REGISTER_KEY, true);\n        this.shouldSimplified = url.getParameter(SIMPLIFIED_KEY, false);\n\n        this.serviceType = serviceType;\n        this.serviceKey = super.getConsumerUrl().getServiceKey();\n\n        this.directoryUrl = consumerUrl;\n        String group = directoryUrl.getGroup(\"\");\n        this.multiGroup = group != null && (ANY_VALUE.equals(group) || group.contains(\",\"));\n\n        this.shouldFailFast = Boolean.parseBoolean(\n                ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, \"true\"));\n    }\n\n    @Override\n    public void addServiceListener(ServiceInstancesChangedListener instanceListener) {\n        this.serviceListener = instanceListener;\n    }\n\n    @Override\n    public ServiceInstancesChangedListener getServiceListener() {\n        return this.serviceListener;\n    }\n\n    public void setProtocol(Protocol protocol) {\n        this.protocol = protocol;\n    }\n\n    public void setRegistry(Registry registry) {\n        this.registry = registry;\n    }\n\n    public Registry getRegistry() {\n        return registry;\n    }\n\n    public boolean isShouldRegister() {\n        return shouldRegister;\n    }\n\n    public void subscribe(URL url) {\n        setSubscribeUrl(url);\n        registry.subscribe(url, this);\n    }\n\n    public void unSubscribe(URL url) {\n        setSubscribeUrl(null);\n        registry.unsubscribe(url, this);\n    }\n\n    @Override\n    public List<Invoker<T>> doList(\n            SingleRouterChain<T> singleRouterChain, BitList<Invoker<T>> invokers, Invocation invocation) {\n        if (forbidden && shouldFailFast) {\n            // 1. No service provider 2. Service providers are disabled\n            throw new RpcException(\n                    RpcException.FORBIDDEN_EXCEPTION,\n                    \"No provider available from registry \" + this\n                            + \" for service \" + getConsumerUrl().getServiceKey() + \" on consumer \"\n                            + NetUtils.getLocalHost()\n                            + \" use dubbo version \" + Version.getVersion()\n                            + \", please check status of providers(disabled, not registered or in blocklist).\");\n        }\n\n        if (multiGroup) {\n            return this.getInvokers();\n        }\n\n        try {\n            // Get invokers from cache, only runtime routers will be executed.\n            List<Invoker<T>> result = singleRouterChain.route(getConsumerUrl(), invokers, invocation);\n            return result == null ? BitList.emptyList() : result;\n        } catch (Throwable t) {\n            // 2-1 - Failed to execute routing.\n            logger.error(\n                    CLUSTER_FAILED_SITE_SELECTION,\n                    \"\",\n                    \"\",\n                    \"Failed to execute router: \" + getUrl() + \", cause: \" + t.getMessage(),\n                    t);\n\n            return BitList.emptyList();\n        }\n    }\n\n    @Override\n    public Class<T> getInterface() {\n        return serviceType;\n    }\n\n    @Override\n    public List<Invoker<T>> getAllInvokers() {\n        return this.getInvokers();\n    }\n\n    /**\n     * The currently effective consumer url\n     *\n     * @return URL\n     */\n    @Override\n    public URL getConsumerUrl() {\n        return this.directoryUrl;\n    }\n\n    /**\n     * The original consumer url\n     *\n     * @return URL\n     */\n    public URL getOriginalConsumerUrl() {\n        return this.consumerUrl;\n    }\n\n    /**\n     * The url registered to registry or metadata center\n     *\n     * @return URL\n     */\n    public URL getRegisteredConsumerUrl() {\n        return registeredConsumerUrl;\n    }\n\n    /**\n     * The url used to subscribe from registry\n     *\n     * @return URL\n     */\n    public URL getSubscribeUrl() {\n        return subscribeUrl;\n    }\n\n    public void setSubscribeUrl(URL subscribeUrl) {\n        this.subscribeUrl = subscribeUrl;\n    }\n\n    public void setRegisteredConsumerUrl(URL url) {\n        if (!shouldSimplified) {\n            this.registeredConsumerUrl =\n                    url.addParameters(CATEGORY_KEY, CONSUMERS_CATEGORY, CHECK_KEY, String.valueOf(false));\n        } else {\n            this.registeredConsumerUrl = URL.valueOf(url, DEFAULT_REGISTER_CONSUMER_KEYS, null)\n                    .addParameters(CATEGORY_KEY, CONSUMERS_CATEGORY, CHECK_KEY, String.valueOf(false));\n        }\n    }\n\n    public void buildRouterChain(URL url) {\n        this.setRouterChain(RouterChain.buildChain(getInterface(), url));\n    }\n\n    @Override\n    public boolean isAvailable() {\n        if (isDestroyed() || this.forbidden) {\n            return false;\n        }\n        for (Invoker<T> validInvoker : getValidInvokers()) {\n            if (validInvoker.isAvailable()) {\n                return true;\n            } else {\n                addInvalidateInvoker(validInvoker);\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public void destroy() {\n        if (isDestroyed()) {\n            return;\n        }\n\n        // unregister.\n        try {\n            if (getRegisteredConsumerUrl() != null && registry != null && registry.isAvailable()) {\n                registry.unregister(getRegisteredConsumerUrl());\n            }\n        } catch (Throwable t) {\n            // 1-8: Failed to unregister / unsubscribe url on destroy.\n            logger.warn(\n                    REGISTRY_FAILED_DESTROY_UNREGISTER_URL,\n                    \"\",\n                    \"\",\n                    \"unexpected error when unregister service \" + serviceKey + \" from registry: \" + registry.getUrl(),\n                    t);\n        }\n\n        // unsubscribe.\n        try {\n            if (getSubscribeUrl() != null && registry != null && registry.isAvailable()) {\n                registry.unsubscribe(getSubscribeUrl(), this);\n            }\n        } catch (Throwable t) {\n            // 1-8: Failed to unregister / unsubscribe url on destroy.\n            logger.warn(\n                    REGISTRY_FAILED_DESTROY_UNREGISTER_URL,\n                    \"\",\n                    \"\",\n                    \"unexpected error when unsubscribe service \" + serviceKey + \" from registry: \" + registry.getUrl(),\n                    t);\n        }\n\n        ExtensionLoader<AddressListener> addressListenerExtensionLoader =\n                getUrl().getOrDefaultModuleModel().getExtensionLoader(AddressListener.class);\n        List<AddressListener> supportedListeners =\n                addressListenerExtensionLoader.getActivateExtension(getUrl(), (String[]) null);\n        if (CollectionUtils.isNotEmpty(supportedListeners)) {\n            for (AddressListener addressListener : supportedListeners) {\n                addressListener.destroy(getConsumerUrl(), this);\n            }\n        }\n\n        synchronized (this) {\n            try {\n                destroyAllInvokers();\n            } catch (Throwable t) {\n                // 1-15 - Failed to destroy service.\n                logger.warn(REGISTRY_FAILED_DESTROY_SERVICE, \"\", \"\", \"Failed to destroy service \" + serviceKey, t);\n            }\n            routerChain.destroy();\n            invokersChangedListener = null;\n            serviceListener = null;\n\n            super.destroy(); // must be executed after unsubscribing\n        }\n    }\n\n    @Override\n    public void discordAddresses() {\n        try {\n            destroyAllInvokers();\n        } catch (Throwable t) {\n            // 1-15 - Failed to destroy service.\n            logger.warn(REGISTRY_FAILED_DESTROY_SERVICE, \"\", \"\", \"Failed to destroy service \" + serviceKey, t);\n        }\n    }\n\n    public synchronized void setInvokersChangedListener(InvokersChangedListener listener) {\n        this.invokersChangedListener = listener;\n        if (invokersChangedListener != null && invokersChanged) {\n            invokersChangedListener.onChange();\n        }\n    }\n\n    protected synchronized void invokersChanged() {\n        refreshInvoker();\n        invokersChanged = true;\n        if (invokersChangedListener != null) {\n            invokersChangedListener.onChange();\n            invokersChanged = false;\n        }\n    }\n\n    @Override\n    public boolean isNotificationReceived() {\n        return invokersChanged;\n    }\n\n    protected abstract void destroyAllInvokers();\n\n    protected abstract void refreshOverrideAndInvoker(List<URL> urls);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/ExporterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.rpc.Exporter;\n\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class ExporterFactory {\n    private final ConcurrentHashMap<String, ReferenceCountExporter<?>> exporters = new ConcurrentHashMap<>();\n\n    protected ReferenceCountExporter<?> createExporter(String providerKey, Callable<Exporter<?>> exporterProducer) {\n        return ConcurrentHashMapUtils.computeIfAbsent(exporters, providerKey, key -> {\n            try {\n                return new ReferenceCountExporter<>(exporterProducer.call(), key, this);\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        });\n    }\n\n    protected void remove(String key, ReferenceCountExporter<?> exporter) {\n        exporters.remove(key, exporter);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/InterfaceCompatibleRegistryProtocol.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.client.ServiceDiscoveryRegistryDirectory;\nimport org.apache.dubbo.registry.client.migration.MigrationInvoker;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;\nimport static org.apache.dubbo.registry.Constants.DEFAULT_REGISTRY;\n\n/**\n * RegistryProtocol\n */\npublic class InterfaceCompatibleRegistryProtocol extends RegistryProtocol {\n\n    @Override\n    protected URL getRegistryUrl(Invoker<?> originInvoker) {\n        URL registryUrl = originInvoker.getUrl();\n        if (REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) {\n            String protocol = registryUrl.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY);\n            registryUrl = registryUrl.setProtocol(protocol).removeParameter(REGISTRY_KEY);\n        }\n        return registryUrl;\n    }\n\n    @Override\n    protected URL getRegistryUrl(URL url) {\n        return URLBuilder.from(url)\n                .setProtocol(url.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY))\n                .removeParameter(REGISTRY_KEY)\n                .build();\n    }\n\n    @Override\n    public <T> ClusterInvoker<T> getInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {\n        DynamicDirectory<T> directory = new RegistryDirectory<>(type, url);\n        return doCreateInvoker(directory, cluster, registry, type);\n    }\n\n    @Override\n    public <T> ClusterInvoker<T> getServiceDiscoveryInvoker(\n            Cluster cluster, Registry registry, Class<T> type, URL url) {\n        registry = getRegistry(super.getRegistryUrl(url));\n        DynamicDirectory<T> directory = new ServiceDiscoveryRegistryDirectory<>(type, url);\n        return doCreateInvoker(directory, cluster, registry, type);\n    }\n\n    @Override\n    protected <T> ClusterInvoker<T> getMigrationInvoker(\n            RegistryProtocol registryProtocol,\n            Cluster cluster,\n            Registry registry,\n            Class<T> type,\n            URL url,\n            URL consumerUrl) {\n        //        ClusterInvoker<T> invoker = getInvoker(cluster, registry, type, url);\n        return new MigrationInvoker<>(registryProtocol, cluster, registry, type, url, consumerUrl);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/ReferenceCountExporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\npublic class ReferenceCountExporter<T> implements Exporter<T> {\n    private final Exporter<T> exporter;\n    private final String providerKey;\n    private final ExporterFactory exporterFactory;\n    private final AtomicInteger count = new AtomicInteger(0);\n\n    public ReferenceCountExporter(Exporter<T> exporter, String providerKey, ExporterFactory exporterFactory) {\n        this.exporter = exporter;\n        this.providerKey = providerKey;\n        this.exporterFactory = exporterFactory;\n    }\n\n    @Override\n    public Invoker<T> getInvoker() {\n        return exporter.getInvoker();\n    }\n\n    public void increaseCount() {\n        count.incrementAndGet();\n    }\n\n    @Override\n    public void unexport() {\n        if (count.decrementAndGet() == 0) {\n            exporter.unexport();\n        }\n        exporterFactory.remove(providerKey, this);\n    }\n\n    @Override\n    public void register() {}\n\n    @Override\n    public void unregister() {}\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.url.component.DubboServiceAddressURL;\nimport org.apache.dubbo.common.url.component.ServiceAddressURL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.registry.event.RegistryEvent;\nimport org.apache.dubbo.registry.AddressListener;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Configurator;\nimport org.apache.dubbo.rpc.cluster.Router;\nimport org.apache.dubbo.rpc.cluster.directory.StaticDirectory;\nimport org.apache.dubbo.rpc.cluster.router.state.BitList;\nimport org.apache.dubbo.rpc.cluster.support.ClusterUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.DISABLED_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXT_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_REGISTER_MODE;\nimport static org.apache.dubbo.common.constants.CommonConstants.PREFERRED_PROTOCOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_INIT_SERIALIZATION_OPTIMIZER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_REFER_INVOKER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNSUPPORTED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROXY_FAILED_CONVERT_URL;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_EMPTY_ADDRESS;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_DESTROY_SERVICE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_UNSUPPORTED_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CONFIG_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_HASHMAP_LOAD_FACTOR;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ROUTE_PROTOCOL;\nimport static org.apache.dubbo.registry.Constants.CONFIGURATORS_SUFFIX;\nimport static org.apache.dubbo.registry.Constants.ENABLE_26X_CONFIGURATION_LISTEN;\nimport static org.apache.dubbo.rpc.Constants.MOCK_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;\nimport static org.apache.dubbo.rpc.model.ScopeModelUtil.getModuleModel;\n\n/**\n * RegistryDirectory\n */\npublic class RegistryDirectory<T> extends DynamicDirectory<T> {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(RegistryDirectory.class);\n\n    private final ConsumerConfigurationListener consumerConfigurationListener;\n    private ReferenceConfigurationListener referenceConfigurationListener;\n\n    /**\n     * Map<url, Invoker> cache service url to invoker mapping.\n     * The initial value is null and the midway may be assigned to null, please use the local variable reference\n     */\n    protected volatile Map<URL, Invoker<T>> urlInvokerMap;\n\n    /**\n     * The initial value is null and the midway may be assigned to null, please use the local variable reference\n     */\n    protected volatile Set<URL> cachedInvokerUrls;\n\n    private final ModuleModel moduleModel;\n\n    public RegistryDirectory(Class<T> serviceType, URL url) {\n        super(serviceType, url);\n        moduleModel = getModuleModel(url.getScopeModel());\n        consumerConfigurationListener = getConsumerConfigurationListener(moduleModel);\n    }\n\n    @Override\n    public void subscribe(URL url) {\n\n        // Fail-fast detection protocol spi\n        String queryProtocols = this.queryMap.get(PROTOCOL_KEY);\n        if (StringUtils.isNotBlank(queryProtocols)) {\n            String[] acceptProtocols = queryProtocols.split(\",\");\n            for (String acceptProtocol : acceptProtocols) {\n                if (!moduleModel\n                        .getApplicationModel()\n                        .getExtensionLoader(Protocol.class)\n                        .hasExtension(acceptProtocol)) {\n                    throw new IllegalStateException(\"No such extension org.apache.dubbo.rpc.Protocol by name \"\n                            + acceptProtocol + \",  please check whether related SPI module is missing\");\n                }\n            }\n        }\n\n        ApplicationModel applicationModel = url.getApplicationModel();\n        if (moduleModel\n                .modelEnvironment()\n                .getConfiguration()\n                .convert(Boolean.class, org.apache.dubbo.registry.Constants.ENABLE_CONFIGURATION_LISTEN, true)) {\n            consumerConfigurationListener.addNotifyListener(this);\n            referenceConfigurationListener = new ReferenceConfigurationListener(moduleModel, this, url);\n        }\n        String registryClusterName = registry.getUrl()\n                .getParameter(\n                        RegistryConstants.REGISTRY_CLUSTER_KEY,\n                        registry.getUrl().getParameter(PROTOCOL_KEY));\n        MetricsEventBus.post(RegistryEvent.toSubscribeEvent(applicationModel, registryClusterName), () -> {\n            super.subscribe(url);\n            return null;\n        });\n    }\n\n    private ConsumerConfigurationListener getConsumerConfigurationListener(ModuleModel moduleModel) {\n        return moduleModel\n                .getBeanFactory()\n                .getOrRegisterBean(\n                        ConsumerConfigurationListener.class, type -> new ConsumerConfigurationListener(moduleModel));\n    }\n\n    @Override\n    public void unSubscribe(URL url) {\n        super.unSubscribe(url);\n        if (moduleModel\n                .modelEnvironment()\n                .getConfiguration()\n                .convert(Boolean.class, org.apache.dubbo.registry.Constants.ENABLE_CONFIGURATION_LISTEN, true)) {\n            consumerConfigurationListener.removeNotifyListener(this);\n            if (referenceConfigurationListener != null) {\n                referenceConfigurationListener.stop();\n            }\n        }\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n        if (moduleModel\n                .modelEnvironment()\n                .getConfiguration()\n                .convert(Boolean.class, org.apache.dubbo.registry.Constants.ENABLE_CONFIGURATION_LISTEN, true)) {\n            consumerConfigurationListener.removeNotifyListener(this);\n            if (referenceConfigurationListener != null) {\n                referenceConfigurationListener.stop();\n            }\n        }\n    }\n\n    @Override\n    public synchronized void notify(List<URL> urls) {\n        if (isDestroyed()) {\n            return;\n        }\n\n        Map<String, List<URL>> categoryUrls = urls.stream()\n                .filter(Objects::nonNull)\n                .filter(this::isValidCategory)\n                .filter(this::isNotCompatibleFor26x)\n                .collect(Collectors.groupingBy(this::judgeCategory));\n\n        if (moduleModel\n                .modelEnvironment()\n                .getConfiguration()\n                .convert(Boolean.class, ENABLE_26X_CONFIGURATION_LISTEN, true)) {\n            List<URL> configuratorURLs = categoryUrls.getOrDefault(CONFIGURATORS_CATEGORY, Collections.emptyList());\n            this.configurators = Configurator.toConfigurators(configuratorURLs).orElse(this.configurators);\n\n            List<URL> routerURLs = categoryUrls.getOrDefault(ROUTERS_CATEGORY, Collections.emptyList());\n            toRouters(routerURLs).ifPresent(this::addRouters);\n        }\n\n        // providers\n        List<URL> providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY, Collections.emptyList());\n\n        // 3.x added for extend URL address\n        ExtensionLoader<AddressListener> addressListenerExtensionLoader =\n                getUrl().getOrDefaultModuleModel().getExtensionLoader(AddressListener.class);\n        List<AddressListener> supportedListeners =\n                addressListenerExtensionLoader.getActivateExtension(getUrl(), (String[]) null);\n        if (supportedListeners != null && !supportedListeners.isEmpty()) {\n            for (AddressListener addressListener : supportedListeners) {\n                providerURLs = addressListener.notify(providerURLs, getConsumerUrl(), this);\n            }\n        }\n        refreshOverrideAndInvoker(providerURLs);\n    }\n\n    @Override\n    public boolean isServiceDiscovery() {\n        return false;\n    }\n\n    private String judgeCategory(URL url) {\n        if (UrlUtils.isConfigurator(url)) {\n            return CONFIGURATORS_CATEGORY;\n        } else if (UrlUtils.isRoute(url)) {\n            return ROUTERS_CATEGORY;\n        } else if (UrlUtils.isProvider(url)) {\n            return PROVIDERS_CATEGORY;\n        }\n        return \"\";\n    }\n\n    // RefreshOverrideAndInvoker will be executed by registryCenter and configCenter, so it should be synchronized.\n    @Override\n    protected synchronized void refreshOverrideAndInvoker(List<URL> urls) {\n        // mock zookeeper://xxx?mock=return null\n        this.directoryUrl = overrideWithConfigurator(getOriginalConsumerUrl());\n        refreshInvoker(urls);\n    }\n\n    /**\n     * Convert the invokerURL list to the Invoker Map. The rules of the conversion are as follows:\n     * <ol>\n     * <li> If URL has been converted to invoker, it is no longer re-referenced and obtained directly from the cache,\n     * and notice that any parameter changes in the URL will be re-referenced.</li>\n     * <li>If the incoming invoker list is not empty, it means that it is the latest invoker list.</li>\n     * <li>If the list of incoming invokerUrl is empty, It means that the rule is only a override rule or a route\n     * rule, which needs to be re-contrasted to decide whether to re-reference.</li>\n     * </ol>\n     *\n     * @param invokerUrls this parameter can't be null\n     */\n    private void refreshInvoker(List<URL> invokerUrls) {\n        Assert.notNull(invokerUrls, \"invokerUrls should not be null\");\n\n        if (invokerUrls.size() == 1\n                && invokerUrls.get(0) != null\n                && EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {\n            refreshRouter(\n                    BitList.emptyList(), () -> this.forbidden = true // Forbid to access\n                    );\n            destroyAllInvokers(); // Close all invokers\n        } else {\n            this.forbidden = false; // Allow to access\n\n            if (invokerUrls == Collections.<URL>emptyList()) {\n                invokerUrls = new ArrayList<>();\n            }\n            // use local reference to avoid NPE as this.cachedInvokerUrls will be set null by destroyAllInvokers().\n            Set<URL> localCachedInvokerUrls = this.cachedInvokerUrls;\n            if (invokerUrls.isEmpty()) {\n                if (CollectionUtils.isNotEmpty(localCachedInvokerUrls)) {\n                    // 1-4 Empty address.\n                    logger.warn(\n                            REGISTRY_EMPTY_ADDRESS,\n                            \"configuration \",\n                            \"\",\n                            \"Service\" + serviceKey\n                                    + \" received empty address list with no EMPTY protocol set, trigger empty protection.\");\n\n                    invokerUrls.addAll(localCachedInvokerUrls);\n                }\n            } else {\n                localCachedInvokerUrls = new HashSet<>();\n                localCachedInvokerUrls.addAll(invokerUrls); // Cached invoker urls, convenient for comparison\n                this.cachedInvokerUrls = localCachedInvokerUrls;\n            }\n            if (invokerUrls.isEmpty()) {\n                return;\n            }\n\n            int originSize = invokerUrls.size();\n            invokerUrls = invokerUrls.stream().distinct().collect(Collectors.toList());\n            if (invokerUrls.size() != originSize) {\n                logger.info(\"Received duplicated invoker urls changed event from registry. \"\n                        + \"Registry type: interface. \"\n                        + \"Service Key: \"\n                        + getConsumerUrl().getServiceKey() + \". \"\n                        + \"Notify Urls Size : \" + originSize + \". \"\n                        + \"Distinct Urls Size: \" + invokerUrls.size() + \".\");\n            }\n\n            // use local reference to avoid NPE as this.urlInvokerMap will be set null concurrently at\n            // destroyAllInvokers().\n            Map<URL, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap;\n            // can't use local reference as oldUrlInvokerMap's mappings might be removed directly at toInvokers().\n            Map<URL, Invoker<T>> oldUrlInvokerMap = null;\n            if (localUrlInvokerMap != null) {\n                // the initial capacity should be set greater than the maximum number of entries divided by the load\n                // factor to avoid resizing.\n                oldUrlInvokerMap =\n                        new LinkedHashMap<>(Math.round(1 + localUrlInvokerMap.size() / DEFAULT_HASHMAP_LOAD_FACTOR));\n                localUrlInvokerMap.forEach(oldUrlInvokerMap::put);\n            }\n            Map<URL, Invoker<T>> newUrlInvokerMap =\n                    toInvokers(oldUrlInvokerMap, invokerUrls); // Translate url list to Invoker map\n\n            /*\n             * If the calculation is wrong, it is not processed.\n             *\n             * 1. The protocol configured by the client is inconsistent with the protocol of the server.\n             *    eg: consumer protocol = dubbo, provider only has other protocol services(rest).\n             * 2. The registration center is not robust and pushes illegal specification data.\n             *\n             */\n            if (CollectionUtils.isEmptyMap(newUrlInvokerMap)) {\n\n                // 3-1 - Failed to convert the URL address into Invokers.\n\n                logger.error(\n                        PROXY_FAILED_CONVERT_URL,\n                        \"inconsistency between the client protocol and the protocol of the server\",\n                        \"\",\n                        \"urls to invokers error\",\n                        new IllegalStateException(\"urls to invokers error. invokerUrls.size :\" + invokerUrls.size()\n                                + \", invoker.size :0. urls :\" + invokerUrls.toString()));\n\n                return;\n            }\n\n            List<Invoker<T>> newInvokers = Collections.unmodifiableList(new ArrayList<>(newUrlInvokerMap.values()));\n            BitList<Invoker<T>> finalInvokers =\n                    multiGroup ? new BitList<>(toMergeInvokerList(newInvokers)) : new BitList<>(newInvokers);\n            // pre-route and build cache\n            refreshRouter(finalInvokers.clone(), () -> this.setInvokers(finalInvokers));\n            this.urlInvokerMap = newUrlInvokerMap;\n\n            try {\n                destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); // Close the unused Invoker\n            } catch (Exception e) {\n                logger.warn(REGISTRY_FAILED_DESTROY_SERVICE, \"\", \"\", \"destroyUnusedInvokers error. \", e);\n            }\n\n            // notify invokers refreshed\n            this.invokersChanged();\n        }\n\n        logger.info(\"Received invokers changed event from registry. \" + \"Registry type: interface. \"\n                + \"Service Key: \"\n                + getConsumerUrl().getServiceKey() + \". \" + \"Urls Size : \"\n                + invokerUrls.size() + \". \" + \"Invokers Size : \"\n                + getInvokers().size() + \". \" + \"Available Size: \"\n                + getValidInvokers().size() + \". \" + \"Available Invokers : \"\n                + joinValidInvokerAddresses());\n    }\n\n    private List<Invoker<T>> toMergeInvokerList(List<Invoker<T>> invokers) {\n        List<Invoker<T>> mergedInvokers = new ArrayList<>();\n        Map<String, List<Invoker<T>>> groupMap = new HashMap<>();\n        for (Invoker<T> invoker : invokers) {\n            String group = invoker.getUrl().getGroup(\"\");\n            groupMap.computeIfAbsent(group, k -> new ArrayList<>());\n            groupMap.get(group).add(invoker);\n        }\n\n        if (groupMap.size() == 1) {\n            mergedInvokers.addAll(groupMap.values().iterator().next());\n        } else if (groupMap.size() > 1) {\n            for (List<Invoker<T>> groupList : groupMap.values()) {\n                StaticDirectory<T> staticDirectory = new StaticDirectory<>(groupList);\n                staticDirectory.buildRouterChain();\n                mergedInvokers.add(cluster.join(staticDirectory, false));\n            }\n        } else {\n            mergedInvokers = invokers;\n        }\n        return mergedInvokers;\n    }\n\n    /**\n     * @param urls\n     * @return null : no routers ,do nothing\n     * else :routers list\n     */\n    private Optional<List<Router>> toRouters(List<URL> urls) {\n        if (urls == null || urls.isEmpty()) {\n            return Optional.empty();\n        }\n\n        List<Router> routers = new ArrayList<>();\n        for (URL url : urls) {\n            if (EMPTY_PROTOCOL.equals(url.getProtocol())) {\n                continue;\n            }\n            String routerType = url.getParameter(ROUTER_KEY);\n            if (routerType != null && routerType.length() > 0) {\n                url = url.setProtocol(routerType);\n            }\n            try {\n                Router router = routerFactory.getRouter(url);\n                if (!routers.contains(router)) {\n                    routers.add(router);\n                }\n            } catch (Throwable t) {\n                logger.error(PROXY_FAILED_CONVERT_URL, \"\", \"\", \"convert router url to router error, url:\" + url, t);\n            }\n        }\n\n        return Optional.of(routers);\n    }\n\n    /**\n     * Turn urls into invokers, and if url has been referred, will not re-reference.\n     * the items that will be put into newUrlInvokeMap will be removed from oldUrlInvokerMap.\n     *\n     * @param oldUrlInvokerMap it might be modified during the process.\n     * @param urls\n     * @return invokers\n     */\n    private Map<URL, Invoker<T>> toInvokers(Map<URL, Invoker<T>> oldUrlInvokerMap, List<URL> urls) {\n        Map<URL, Invoker<T>> newUrlInvokerMap =\n                new ConcurrentHashMap<>(urls == null ? 1 : (int) (urls.size() / 0.75f + 1));\n        if (urls == null || urls.isEmpty()) {\n            return newUrlInvokerMap;\n        }\n        String queryProtocols = this.queryMap.get(PROTOCOL_KEY);\n        for (URL providerUrl : urls) {\n            if (!checkProtocolValid(queryProtocols, providerUrl)) {\n                continue;\n            }\n\n            URL url = mergeUrl(providerUrl);\n            // get the effective protocol that this consumer should consume based on consumer side protocol\n            // configuration and available protocols in address pool.\n            String effectiveProtocol = getEffectiveProtocol(queryProtocols, url);\n            if (!effectiveProtocol.equals(url.getProtocol())) {\n                url = url.setProtocol(effectiveProtocol);\n            }\n\n            // Cache key is url that does not merge with consumer side parameters,\n            // regardless of how the consumer combines parameters,\n            // if the server url changes, then refer again\n            Invoker<T> invoker = oldUrlInvokerMap == null ? null : oldUrlInvokerMap.remove(url);\n            if (invoker == null) { // Not in the cache, refer again\n                try {\n                    boolean enabled = true;\n                    if (url.hasParameter(DISABLED_KEY)) {\n                        enabled = !url.getParameter(DISABLED_KEY, false);\n                    } else {\n                        enabled = url.getParameter(ENABLED_KEY, true);\n                    }\n                    if (enabled) {\n                        invoker = protocol.refer(serviceType, url);\n                    }\n                } catch (Throwable t) {\n\n                    // Thrown by AbstractProtocol.optimizeSerialization()\n                    if (t instanceof RpcException && t.getMessage().contains(\"serialization optimizer\")) {\n                        // 4-2 - serialization optimizer class initialization failed.\n                        logger.error(\n                                PROTOCOL_FAILED_INIT_SERIALIZATION_OPTIMIZER,\n                                \"typo in optimizer class\",\n                                \"\",\n                                \"Failed to refer invoker for interface:\" + serviceType + \",url:(\" + url + \")\"\n                                        + t.getMessage(),\n                                t);\n\n                    } else {\n                        // 4-3 - Failed to refer invoker by other reason.\n                        logger.error(\n                                PROTOCOL_FAILED_REFER_INVOKER,\n                                \"\",\n                                \"\",\n                                \"Failed to refer invoker for interface:\" + serviceType + \",url:(\" + url + \")\"\n                                        + t.getMessage(),\n                                t);\n                    }\n                }\n                if (invoker != null) { // Put new invoker in cache\n                    newUrlInvokerMap.put(url, invoker);\n                }\n            } else {\n                newUrlInvokerMap.put(url, invoker);\n            }\n        }\n        return newUrlInvokerMap;\n    }\n\n    /**\n     * Get the protocol to consume by matching the consumer acceptable protocols and the available provider protocols.\n     * <p>\n     * Only the first protocol that can match with the provider protocols will be used if consumer set to accept multiple protocols.\n     * For example, if dubbo.consumer.protocol='tri,rest' is set and provider provides tri protocol, then consumer will use tri protocol to communicate with provider.\n     *\n     * @param queryProtocols consumer side protocols.\n     * @param url            provider url that have extra protocols specified.\n     * @return the protocol to consume.\n     */\n    private String getEffectiveProtocol(String queryProtocols, URL url) {\n        String protocol = url.getProtocol();\n        String prioritizedProtocol = url.getParameter(PREFERRED_PROTOCOL, protocol);\n\n        String effectiveProtocol = prioritizedProtocol;\n\n        if (StringUtils.isNotEmpty(queryProtocols)) {\n            String[] acceptProtocols = queryProtocols.split(COMMA_SEPARATOR);\n            String acceptedProtocol = acceptProtocols[0];\n            if (!acceptedProtocol.equals(prioritizedProtocol)) {\n                if (!acceptedProtocol.equals(protocol)) {\n                    String extProtocols = url.getParameter(EXT_PROTOCOL);\n                    if (StringUtils.isNotEmpty(extProtocols)) {\n                        String[] extProtocolsArr = extProtocols.split(COMMA_SEPARATOR);\n                        for (String p : extProtocolsArr) {\n                            if (p.equalsIgnoreCase(acceptedProtocol)) {\n                                effectiveProtocol = acceptedProtocol;\n                                break;\n                            }\n                        }\n                    }\n                } else {\n                    effectiveProtocol = protocol;\n                }\n            }\n        }\n        return effectiveProtocol;\n    }\n\n    private boolean checkProtocolValid(String queryProtocols, URL providerUrl) {\n        // If protocol is configured at the reference side, only the matching protocol is selected\n        if (queryProtocols != null && queryProtocols.length() > 0) {\n            boolean accept = false;\n\n            String[] acceptProtocols = queryProtocols.split(\",\");\n            for (String acceptProtocol : acceptProtocols) {\n                if (providerUrl.getProtocol().equals(acceptProtocol)) {\n                    accept = true;\n                    break;\n                }\n            }\n\n            if (!accept) {\n                return false;\n            }\n        }\n\n        if (EMPTY_PROTOCOL.equals(providerUrl.getProtocol())) {\n            return false;\n        }\n\n        if (!getUrl().getOrDefaultFrameworkModel()\n                .getExtensionLoader(Protocol.class)\n                .hasExtension(providerUrl.getProtocol())) {\n\n            // 4-1 - Unsupported protocol\n\n            logger.error(\n                    PROTOCOL_UNSUPPORTED,\n                    \"protocol extension does not installed\",\n                    \"\",\n                    \"Unsupported protocol.\",\n                    new IllegalStateException(\"Unsupported protocol \" + providerUrl.getProtocol() + \" in notified url: \"\n                            + providerUrl + \" from registry \" + getUrl().getAddress() + \" to consumer \"\n                            + NetUtils.getLocalHost() + \", supported protocol: \"\n                            + getUrl().getOrDefaultFrameworkModel()\n                                    .getExtensionLoader(Protocol.class)\n                                    .getSupportedExtensions()));\n\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Merge url parameters. the order is: override > -D >Consumer > Provider\n     *\n     * @param providerUrl\n     * @return\n     */\n    private URL mergeUrl(URL providerUrl) {\n        if (providerUrl instanceof ServiceAddressURL) {\n            providerUrl = overrideWithConfigurator(providerUrl);\n        } else {\n            providerUrl = moduleModel\n                    .getApplicationModel()\n                    .getBeanFactory()\n                    .getBean(ClusterUtils.class)\n                    .mergeUrl(providerUrl, queryMap); // Merge the consumer side parameters\n            providerUrl = overrideWithConfigurator(providerUrl);\n            providerUrl = providerUrl.addParameter(\n                    Constants.CHECK_KEY,\n                    String.valueOf(\n                            false)); // Do not check whether the connection is successful or not, always create Invoker!\n        }\n\n        // FIXME, kept for mock\n        if (providerUrl.hasParameter(MOCK_KEY) || providerUrl.getAnyMethodParameter(MOCK_KEY) != null) {\n            providerUrl = providerUrl.removeParameter(MOCK_KEY);\n        }\n\n        if ((providerUrl.getPath() == null || providerUrl.getPath().length() == 0)\n                && DUBBO_PROTOCOL.equals(providerUrl.getProtocol())) { // Compatible version 1.0\n            // fix by tony.chenl DUBBO-44\n            String path = directoryUrl.getServiceInterface();\n            if (path != null) {\n                int i = path.indexOf('/');\n                if (i >= 0) {\n                    path = path.substring(i + 1);\n                }\n                i = path.lastIndexOf(':');\n                if (i >= 0) {\n                    path = path.substring(0, i);\n                }\n                providerUrl = providerUrl.setPath(path);\n            }\n        }\n        return providerUrl;\n    }\n\n    protected URL overrideWithConfigurator(URL providerUrl) {\n        // override url with configurator from \"override://\" URL for dubbo 2.6 and before\n        providerUrl = overrideWithConfigurators(this.configurators, providerUrl);\n\n        // override url with configurator from \"app-name.configurators\"\n        providerUrl = overrideWithConfigurators(consumerConfigurationListener.getConfigurators(), providerUrl);\n\n        // override url with configurator from configurators from \"service-name.configurators\"\n        if (referenceConfigurationListener != null) {\n            providerUrl = overrideWithConfigurators(referenceConfigurationListener.getConfigurators(), providerUrl);\n        }\n\n        return providerUrl;\n    }\n\n    private URL overrideWithConfigurators(List<Configurator> configurators, URL url) {\n        if (CollectionUtils.isNotEmpty(configurators)) {\n            if (url instanceof DubboServiceAddressURL) {\n                DubboServiceAddressURL interfaceAddressURL = (DubboServiceAddressURL) url;\n                URL overriddenURL = interfaceAddressURL.getOverrideURL();\n                if (overriddenURL == null) {\n                    String appName = interfaceAddressURL.getApplication();\n                    String side = interfaceAddressURL.getSide();\n                    String group = interfaceAddressURL.getGroup();\n                    String version = interfaceAddressURL.getVersion();\n                    overriddenURL = URLBuilder.from(interfaceAddressURL)\n                            .clearParameters()\n                            .addParameter(APPLICATION_KEY, appName)\n                            .addParameter(SIDE_KEY, side)\n                            .addParameter(GROUP_KEY, group)\n                            .addParameter(VERSION_KEY, version)\n                            .build();\n                }\n                for (Configurator configurator : configurators) {\n                    overriddenURL = configurator.configure(overriddenURL);\n                }\n                url = new DubboServiceAddressURL(\n                        interfaceAddressURL.getUrlAddress(),\n                        interfaceAddressURL.getUrlParam(),\n                        interfaceAddressURL.getConsumerURL(),\n                        (ServiceConfigURL) overriddenURL);\n            } else {\n                for (Configurator configurator : configurators) {\n                    url = configurator.configure(url);\n                }\n            }\n        }\n        return url;\n    }\n\n    /**\n     * Close all invokers\n     */\n    @Override\n    protected void destroyAllInvokers() {\n        Map<URL, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap; // local reference\n        if (!CollectionUtils.isEmptyMap(localUrlInvokerMap)) {\n            for (Invoker<T> invoker : new ArrayList<>(localUrlInvokerMap.values())) {\n                try {\n                    invoker.destroy();\n                } catch (Throwable t) {\n                    // 1-15 - Failed to destroy service\n                    logger.warn(\n                            REGISTRY_FAILED_DESTROY_SERVICE,\n                            \"\",\n                            \"\",\n                            \"Failed to destroy service \" + serviceKey + \" to provider \" + invoker.getUrl(),\n                            t);\n                }\n            }\n            localUrlInvokerMap.clear();\n        }\n\n        this.urlInvokerMap = null;\n        this.cachedInvokerUrls = null;\n        destroyInvokers();\n    }\n\n    private void destroyUnusedInvokers(Map<URL, Invoker<T>> oldUrlInvokerMap, Map<URL, Invoker<T>> newUrlInvokerMap) {\n        if (CollectionUtils.isEmptyMap(newUrlInvokerMap)) {\n            destroyAllInvokers();\n            return;\n        }\n\n        if (CollectionUtils.isEmptyMap(oldUrlInvokerMap)) {\n            return;\n        }\n\n        for (Map.Entry<URL, Invoker<T>> entry : oldUrlInvokerMap.entrySet()) {\n            Invoker<T> invoker = entry.getValue();\n            if (invoker != null) {\n                try {\n                    invoker.destroy();\n                    if (logger.isDebugEnabled()) {\n                        logger.debug(\"destroy invoker[\" + invoker.getUrl() + \"] success. \");\n                    }\n                } catch (Exception e) {\n                    logger.warn(\n                            REGISTRY_FAILED_DESTROY_SERVICE,\n                            \"\",\n                            \"\",\n                            \"destroy invoker[\" + invoker.getUrl() + \"] failed. \" + e.getMessage(),\n                            e);\n                }\n            }\n        }\n\n        logger.info(\n                \"New url total size, \" + newUrlInvokerMap.size() + \", destroyed total size \" + oldUrlInvokerMap.size());\n    }\n\n    /**\n     * Haomin: added for test purpose\n     */\n    public Map<URL, Invoker<T>> getUrlInvokerMap() {\n        return urlInvokerMap;\n    }\n\n    private boolean isValidCategory(URL url) {\n        String category = url.getCategory(DEFAULT_CATEGORY);\n        if ((ROUTERS_CATEGORY.equals(category) || ROUTE_PROTOCOL.equals(url.getProtocol()))\n                || PROVIDERS_CATEGORY.equals(category)\n                || CONFIGURATORS_CATEGORY.equals(category)\n                || DYNAMIC_CONFIGURATORS_CATEGORY.equals(category)\n                || APP_DYNAMIC_CONFIGURATORS_CATEGORY.equals(category)) {\n            return true;\n        }\n\n        // 1-16 - Unsupported category in NotifyListener\n        logger.warn(\n                REGISTRY_UNSUPPORTED_CATEGORY,\n                \"\",\n                \"\",\n                \"Unsupported category \" + category + \" in notified url: \" + url + \" from registry \"\n                        + getUrl().getAddress() + \" to consumer \" + NetUtils.getLocalHost());\n\n        return false;\n    }\n\n    @Override\n    protected Map<String, String> getDirectoryMeta() {\n        String registryKey = Optional.ofNullable(getRegistry())\n                .map(Registry::getUrl)\n                .map(url -> url.getParameter(RegistryConstants.REGISTRY_CLUSTER_KEY, url.getProtocol()))\n                .orElse(\"unknown\");\n        Map<String, String> metas = new HashMap<>();\n        metas.put(REGISTRY_KEY, registryKey);\n        metas.put(REGISTER_MODE_KEY, INTERFACE_REGISTER_MODE);\n        return metas;\n    }\n\n    private boolean isNotCompatibleFor26x(URL url) {\n        return StringUtils.isEmpty(url.getParameter(COMPATIBLE_CONFIG_KEY));\n    }\n\n    private static class ReferenceConfigurationListener extends AbstractConfiguratorListener {\n        private RegistryDirectory directory;\n        private URL url;\n\n        ReferenceConfigurationListener(ModuleModel moduleModel, RegistryDirectory directory, URL url) {\n            super(moduleModel);\n            this.directory = directory;\n            this.url = url;\n            this.initWith(DynamicConfiguration.getRuleKey(url) + CONFIGURATORS_SUFFIX);\n        }\n\n        void stop() {\n            this.stopListen(DynamicConfiguration.getRuleKey(url) + CONFIGURATORS_SUFFIX);\n        }\n\n        @Override\n        protected void notifyOverrides() {\n            // to notify configurator/router changes\n            directory.refreshOverrideAndInvoker(Collections.emptyList());\n        }\n    }\n\n    private static class ConsumerConfigurationListener extends AbstractConfiguratorListener {\n        List<RegistryDirectory> listeners = new CopyOnWriteArrayList<>();\n\n        ConsumerConfigurationListener(ModuleModel moduleModel) {\n            super(moduleModel);\n            this.initWith(moduleModel.getApplicationModel().getApplicationName() + CONFIGURATORS_SUFFIX);\n        }\n\n        void addNotifyListener(RegistryDirectory listener) {\n            this.listeners.add(listener);\n        }\n\n        void removeNotifyListener(RegistryDirectory listener) {\n            this.listeners.remove(listener);\n        }\n\n        @Override\n        protected void notifyOverrides() {\n            listeners.forEach(listener -> listener.refreshOverrideAndInvoker(Collections.emptyList()));\n        }\n    }\n\n    @Override\n    public String toString() {\n        return \"RegistryDirectory(\" + \"registry: \" + getUrl().getAddress() + \")-\" + super.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.common.constants.RegistryConstants;\nimport org.apache.dubbo.common.deploy.ApplicationDeployer;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.metrics.event.MetricsEventBus;\nimport org.apache.dubbo.metrics.registry.event.RegistryEvent;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\nimport org.apache.dubbo.registry.RegistryService;\nimport org.apache.dubbo.registry.client.ServiceDiscoveryRegistryDirectory;\nimport org.apache.dubbo.registry.client.migration.MigrationClusterInvoker;\nimport org.apache.dubbo.registry.client.migration.ServiceDiscoveryMigrationInvoker;\nimport org.apache.dubbo.registry.retry.ReExportTask;\nimport org.apache.dubbo.registry.support.SkipFailbackWrapperException;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.Protocol;\nimport org.apache.dubbo.rpc.ProtocolServer;\nimport org.apache.dubbo.rpc.ProxyFactory;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Configurator;\nimport org.apache.dubbo.rpc.cluster.Constants;\nimport org.apache.dubbo.rpc.cluster.governance.GovernanceRuleRepository;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\nimport org.apache.dubbo.rpc.model.ProviderModel;\nimport org.apache.dubbo.rpc.model.ScopeModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\nimport org.apache.dubbo.rpc.protocol.InvokerWrapper;\nimport org.apache.dubbo.rpc.support.ProtocolUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXTRA_KEYS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.IPV6_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.MERGEABLE_CLUSTER_NAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.PACKABLE_METHOD_FACTORY_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_PROTOCOL_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_UNSUPPORTED_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ALL_CATEGORIES;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.OVERRIDE_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL;\nimport static org.apache.dubbo.common.utils.StringUtils.isEmpty;\nimport static org.apache.dubbo.common.utils.UrlUtils.classifyUrls;\nimport static org.apache.dubbo.registry.Constants.CONFIGURATORS_SUFFIX;\nimport static org.apache.dubbo.registry.Constants.DEFAULT_REGISTRY_RETRY_PERIOD;\nimport static org.apache.dubbo.registry.Constants.ENABLE_26X_CONFIGURATION_LISTEN;\nimport static org.apache.dubbo.registry.Constants.ENABLE_CONFIGURATION_LISTEN;\nimport static org.apache.dubbo.registry.Constants.PROVIDER_PROTOCOL;\nimport static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;\nimport static org.apache.dubbo.registry.Constants.REGISTER_KEY;\nimport static org.apache.dubbo.registry.Constants.REGISTRY_RETRY_PERIOD_KEY;\nimport static org.apache.dubbo.registry.Constants.SIMPLIFIED_KEY;\nimport static org.apache.dubbo.remoting.Constants.CHECK_KEY;\nimport static org.apache.dubbo.remoting.Constants.CODEC_KEY;\nimport static org.apache.dubbo.remoting.Constants.CONNECTIONS_KEY;\nimport static org.apache.dubbo.remoting.Constants.EXCHANGER_KEY;\nimport static org.apache.dubbo.remoting.Constants.PREFER_SERIALIZATION_KEY;\nimport static org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY;\nimport static org.apache.dubbo.rpc.Constants.AUTHENTICATOR_KEY;\nimport static org.apache.dubbo.rpc.Constants.AUTH_KEY;\nimport static org.apache.dubbo.rpc.Constants.DEPRECATED_KEY;\nimport static org.apache.dubbo.rpc.Constants.GENERIC_KEY;\nimport static org.apache.dubbo.rpc.Constants.MOCK_KEY;\nimport static org.apache.dubbo.rpc.Constants.TOKEN_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.CONSUMER_URL_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.WARMUP_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY;\nimport static org.apache.dubbo.rpc.model.ScopeModelUtil.getApplicationModel;\n\n/**\n * TODO, replace RegistryProtocol completely in the future.\n */\npublic class RegistryProtocol implements Protocol, ScopeModelAware {\n    public static final String[] DEFAULT_REGISTER_PROVIDER_KEYS = {\n        APPLICATION_KEY,\n        CODEC_KEY,\n        EXCHANGER_KEY,\n        SERIALIZATION_KEY,\n        PREFER_SERIALIZATION_KEY,\n        CLUSTER_KEY,\n        CONNECTIONS_KEY,\n        DEPRECATED_KEY,\n        GROUP_KEY,\n        LOADBALANCE_KEY,\n        MOCK_KEY,\n        PATH_KEY,\n        TIMEOUT_KEY,\n        TOKEN_KEY,\n        VERSION_KEY,\n        WARMUP_KEY,\n        WEIGHT_KEY,\n        DUBBO_VERSION_KEY,\n        RELEASE_KEY,\n        SIDE_KEY,\n        IPV6_KEY,\n        PACKABLE_METHOD_FACTORY_KEY,\n        AUTH_KEY,\n        AUTHENTICATOR_KEY,\n        USERNAME_KEY,\n        PASSWORD_KEY\n    };\n\n    public static final String[] DEFAULT_REGISTER_CONSUMER_KEYS = {\n        APPLICATION_KEY, VERSION_KEY, GROUP_KEY, DUBBO_VERSION_KEY, RELEASE_KEY\n    };\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(RegistryProtocol.class);\n\n    private final Map<String, ServiceConfigurationListener> serviceConfigurationListeners = new ConcurrentHashMap<>();\n    // To solve the problem of RMI repeated exposure port conflicts, the services that have been exposed are no longer\n    // exposed.\n    // provider url <--> registry url <--> exporter\n    private final ConcurrentHashMap<String, ConcurrentHashMap<String, ExporterChangeableWrapper<?>>> bounds =\n            new ConcurrentHashMap<>();\n    protected Protocol protocol;\n    protected ProxyFactory proxyFactory;\n\n    private ConcurrentMap<URL, ReExportTask> reExportFailedTasks = new ConcurrentHashMap<>();\n    private HashedWheelTimer retryTimer = new HashedWheelTimer(\n            new NamedThreadFactory(\"DubboReexportTimer\", true),\n            DEFAULT_REGISTRY_RETRY_PERIOD,\n            TimeUnit.MILLISECONDS,\n            128);\n    private FrameworkModel frameworkModel;\n    private ExporterFactory exporterFactory;\n\n    public RegistryProtocol() {}\n\n    @Override\n    public void setFrameworkModel(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n        this.exporterFactory = frameworkModel.getBeanFactory().getBean(ExporterFactory.class);\n    }\n\n    public void setProtocol(Protocol protocol) {\n        this.protocol = protocol;\n    }\n\n    public void setProxyFactory(ProxyFactory proxyFactory) {\n        this.proxyFactory = proxyFactory;\n    }\n\n    @Override\n    public int getDefaultPort() {\n        return 9090;\n    }\n\n    public Map<URL, Set<NotifyListener>> getOverrideListeners() {\n        Map<URL, Set<NotifyListener>> map = new HashMap<>();\n        List<ApplicationModel> applicationModels = frameworkModel.getApplicationModels();\n        if (applicationModels.size() == 1) {\n            return applicationModels\n                    .get(0)\n                    .getBeanFactory()\n                    .getBean(ProviderConfigurationListener.class)\n                    .getOverrideListeners();\n        } else {\n            for (ApplicationModel applicationModel : applicationModels) {\n                map.putAll(applicationModel\n                        .getBeanFactory()\n                        .getBean(ProviderConfigurationListener.class)\n                        .getOverrideListeners());\n            }\n        }\n        return map;\n    }\n\n    private static void register(Registry registry, URL registeredProviderUrl) {\n        ApplicationDeployer deployer =\n                registeredProviderUrl.getOrDefaultApplicationModel().getDeployer();\n        try {\n            deployer.increaseServiceRefreshCount();\n            String registryName = Optional.ofNullable(registry.getUrl())\n                    .map(u -> u.getParameter(\n                            RegistryConstants.REGISTRY_CLUSTER_KEY,\n                            UrlUtils.isServiceDiscoveryURL(u) ? u.getParameter(REGISTRY_KEY) : u.getProtocol()))\n                    .filter(StringUtils::isNotEmpty)\n                    .orElse(\"unknown\");\n            MetricsEventBus.post(\n                    RegistryEvent.toRsEvent(\n                            registeredProviderUrl.getApplicationModel(),\n                            registeredProviderUrl.getServiceKey(),\n                            1,\n                            Collections.singletonList(registryName)),\n                    () -> {\n                        registry.register(registeredProviderUrl);\n                        return null;\n                    });\n        } finally {\n            deployer.decreaseServiceRefreshCount();\n        }\n    }\n\n    private void registerStatedUrl(URL registryUrl, URL registeredProviderUrl, boolean registered) {\n        ProviderModel model = (ProviderModel) registeredProviderUrl.getServiceModel();\n        model.addStatedUrl(new ProviderModel.RegisterStatedURL(registeredProviderUrl, registryUrl, registered));\n    }\n\n    @Override\n    public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {\n        URL registryUrl = getRegistryUrl(originInvoker);\n        // url to export locally\n        URL providerUrl = getProviderUrl(originInvoker);\n\n        // Subscribe the override data\n        // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call\n        //  the same service. Because the subscribed is cached key with the name of the service, it causes the\n        //  subscription information to cover.\n        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);\n        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);\n        ConcurrentHashMap<URL, Set<NotifyListener>> overrideListeners =\n                getProviderConfigurationListener(overrideSubscribeUrl).getOverrideListeners();\n        ConcurrentHashMapUtils.computeIfAbsent(overrideListeners, overrideSubscribeUrl, k -> new ConcurrentHashSet<>())\n                .add(overrideSubscribeListener);\n\n        providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);\n        // export invoker\n        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);\n\n        // url to registry\n        final Registry registry = getRegistry(registryUrl);\n        final URL registeredProviderUrl = customizeURL(providerUrl, registryUrl);\n\n        // decide if we need to delay publish (provider itself and registry should both need to register)\n        boolean register = providerUrl.getParameter(REGISTER_KEY, true) && registryUrl.getParameter(REGISTER_KEY, true);\n        if (register) {\n            register(registry, registeredProviderUrl);\n        }\n\n        // register stated url on provider model\n        registerStatedUrl(registryUrl, registeredProviderUrl, register);\n\n        exporter.setRegisterUrl(registeredProviderUrl);\n        exporter.setSubscribeUrl(overrideSubscribeUrl);\n        exporter.setNotifyListener(overrideSubscribeListener);\n        exporter.setRegistered(register);\n\n        ApplicationModel applicationModel = getApplicationModel(providerUrl.getScopeModel());\n        if (applicationModel\n                .modelEnvironment()\n                .getConfiguration()\n                .convert(Boolean.class, ENABLE_26X_CONFIGURATION_LISTEN, true)) {\n            if (!registry.isServiceDiscovery()) {\n                // Deprecated! Subscribe to override rules in 2.6.x or before.\n                registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);\n            }\n        }\n\n        notifyExport(exporter);\n        // Ensure that a new exporter instance is returned every time export\n        return new DestroyableExporter<>(exporter);\n    }\n\n    private <T> void notifyExport(ExporterChangeableWrapper<T> exporter) {\n        ScopeModel scopeModel = exporter.getRegisterUrl().getScopeModel();\n        List<RegistryProtocolListener> listeners = ScopeModelUtil.getExtensionLoader(\n                        RegistryProtocolListener.class, scopeModel)\n                .getActivateExtension(exporter.getOriginInvoker().getUrl(), REGISTRY_PROTOCOL_LISTENER_KEY);\n        if (CollectionUtils.isNotEmpty(listeners)) {\n            for (RegistryProtocolListener listener : listeners) {\n                listener.onExport(this, exporter);\n            }\n        }\n    }\n\n    private URL overrideUrlWithConfig(URL providerUrl, OverrideListener listener) {\n        ProviderConfigurationListener providerConfigurationListener = getProviderConfigurationListener(providerUrl);\n        providerUrl = providerConfigurationListener.overrideUrl(providerUrl);\n\n        ServiceConfigurationListener serviceConfigurationListener =\n                new ServiceConfigurationListener(providerUrl.getOrDefaultModuleModel(), providerUrl, listener);\n        serviceConfigurationListeners.put(providerUrl.getServiceKey(), serviceConfigurationListener);\n        return serviceConfigurationListener.overrideUrl(providerUrl);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {\n        String providerUrlKey = getProviderUrlKey(originInvoker);\n        String registryUrlKey = getRegistryUrlKey(originInvoker);\n        Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);\n\n        ReferenceCountExporter<?> exporter =\n                exporterFactory.createExporter(providerUrlKey, () -> protocol.export(invokerDelegate));\n        return (ExporterChangeableWrapper<T>) ConcurrentHashMapUtils.computeIfAbsent(\n                ConcurrentHashMapUtils.computeIfAbsent(bounds, providerUrlKey, k -> new ConcurrentHashMap<>()),\n                registryUrlKey,\n                s -> new ExporterChangeableWrapper<>((ReferenceCountExporter<T>) exporter, originInvoker));\n    }\n\n    public <T> void reExport(Exporter<T> exporter, URL newInvokerUrl) {\n        if (exporter instanceof ExporterChangeableWrapper) {\n            ExporterChangeableWrapper<T> exporterWrapper = (ExporterChangeableWrapper<T>) exporter;\n            Invoker<T> originInvoker = exporterWrapper.getOriginInvoker();\n            reExport(originInvoker, newInvokerUrl);\n        }\n    }\n\n    /**\n     * Reexport the invoker of the modified url\n     *\n     * @param originInvoker\n     * @param newInvokerUrl\n     * @param <T>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <T> void reExport(final Invoker<T> originInvoker, URL newInvokerUrl) {\n        String providerUrlKey = getProviderUrlKey(originInvoker);\n        String registryUrlKey = getRegistryUrlKey(originInvoker);\n        Map<String, ExporterChangeableWrapper<?>> registryMap = bounds.get(providerUrlKey);\n        if (registryMap == null) {\n            logger.warn(\n                    INTERNAL_ERROR,\n                    \"error state, exporterMap can not be null\",\n                    \"\",\n                    \"error state, exporterMap can not be null\",\n                    new IllegalStateException(\"error state, exporterMap can not be null\"));\n            return;\n        }\n        ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) registryMap.get(registryUrlKey);\n        if (exporter == null) {\n            logger.warn(\n                    INTERNAL_ERROR,\n                    \"error state, exporterMap can not be null\",\n                    \"\",\n                    \"error state, exporterMap can not be null\",\n                    new IllegalStateException(\"error state, exporterMap can not be null\"));\n            return;\n        }\n        URL registeredUrl = exporter.getRegisterUrl();\n\n        URL registryUrl = getRegistryUrl(originInvoker);\n        URL newProviderUrl = customizeURL(newInvokerUrl, registryUrl);\n\n        // update local exporter\n        Invoker<T> invokerDelegate = new InvokerDelegate<>(originInvoker, newInvokerUrl);\n        exporter.setExporter(protocol.export(invokerDelegate));\n\n        // update registry\n        if (!newProviderUrl.equals(registeredUrl)) {\n            try {\n                doReExport(originInvoker, exporter, registryUrl, registeredUrl, newProviderUrl);\n            } catch (Exception e) {\n                ReExportTask oldTask = reExportFailedTasks.get(registeredUrl);\n                if (oldTask != null) {\n                    return;\n                }\n                ReExportTask task = new ReExportTask(\n                        () -> doReExport(originInvoker, exporter, registryUrl, registeredUrl, newProviderUrl),\n                        registeredUrl,\n                        null);\n                oldTask = reExportFailedTasks.putIfAbsent(registeredUrl, task);\n                if (oldTask == null) {\n                    // never has a retry task. then start a new task for retry.\n                    retryTimer.newTimeout(\n                            task,\n                            registryUrl.getParameter(REGISTRY_RETRY_PERIOD_KEY, DEFAULT_REGISTRY_RETRY_PERIOD),\n                            TimeUnit.MILLISECONDS);\n                }\n            }\n        }\n    }\n\n    private <T> void doReExport(\n            final Invoker<T> originInvoker,\n            ExporterChangeableWrapper<T> exporter,\n            URL registryUrl,\n            URL oldProviderUrl,\n            URL newProviderUrl) {\n        if (exporter.isRegistered()) {\n            Registry registry;\n            try {\n                registry = getRegistry(getRegistryUrl(originInvoker));\n            } catch (Exception e) {\n                throw new SkipFailbackWrapperException(e);\n            }\n\n            logger.info(\"Try to unregister old url: \" + oldProviderUrl);\n            registry.reExportUnregister(oldProviderUrl);\n\n            logger.info(\"Try to register new url: \" + newProviderUrl);\n            registry.reExportRegister(newProviderUrl);\n        }\n        try {\n            ProviderModel.RegisterStatedURL statedUrl = getStatedUrl(registryUrl, newProviderUrl);\n            statedUrl.setProviderUrl(newProviderUrl);\n            exporter.setRegisterUrl(newProviderUrl);\n        } catch (Exception e) {\n            throw new SkipFailbackWrapperException(e);\n        }\n    }\n\n    private ProviderModel.RegisterStatedURL getStatedUrl(URL registryUrl, URL providerUrl) {\n        ProviderModel providerModel =\n                frameworkModel.getServiceRepository().lookupExportedService(providerUrl.getServiceKey());\n\n        List<ProviderModel.RegisterStatedURL> statedUrls = providerModel.getStatedUrl();\n        return statedUrls.stream()\n                .filter(u -> u.getRegistryUrl().equals(registryUrl)\n                        && u.getProviderUrl().getProtocol().equals(providerUrl.getProtocol()))\n                .findFirst()\n                .orElseThrow(() -> new IllegalStateException(\"There should have at least one registered url.\"));\n    }\n\n    /**\n     * Get an instance of registry based on the address of invoker\n     *\n     * @param registryUrl\n     * @return\n     */\n    protected Registry getRegistry(final URL registryUrl) {\n        RegistryFactory registryFactory = ScopeModelUtil.getExtensionLoader(\n                        RegistryFactory.class, registryUrl.getScopeModel())\n                .getAdaptiveExtension();\n        return registryFactory.getRegistry(registryUrl);\n    }\n\n    protected URL getRegistryUrl(Invoker<?> originInvoker) {\n        return originInvoker.getUrl();\n    }\n\n    protected URL getRegistryUrl(URL url) {\n        if (SERVICE_REGISTRY_PROTOCOL.equals(url.getProtocol())) {\n            return url;\n        }\n        return url.addParameter(REGISTRY_KEY, url.getProtocol()).setProtocol(SERVICE_REGISTRY_PROTOCOL);\n    }\n\n    /**\n     * Return the url that is registered to the registry and filter the url parameter once\n     *\n     * @param providerUrl provider service url\n     * @param registryUrl registry center url\n     * @return url to registry.\n     */\n    private URL customizeURL(final URL providerUrl, final URL registryUrl) {\n        URL newProviderURL = providerUrl.putAttribute(SIMPLIFIED_KEY, registryUrl.getParameter(SIMPLIFIED_KEY, false));\n        newProviderURL = newProviderURL.putAttribute(EXTRA_KEYS_KEY, registryUrl.getParameter(EXTRA_KEYS_KEY, \"\"));\n        ApplicationModel applicationModel = providerUrl.getOrDefaultApplicationModel();\n        ExtensionLoader<ServiceURLCustomizer> loader = applicationModel.getExtensionLoader(ServiceURLCustomizer.class);\n        for (ServiceURLCustomizer customizer : loader.getSupportedExtensionInstances()) {\n            newProviderURL = customizer.customize(newProviderURL, applicationModel);\n        }\n        return newProviderURL;\n    }\n\n    private URL getSubscribedOverrideUrl(URL registeredProviderUrl) {\n        return registeredProviderUrl\n                .setProtocol(PROVIDER_PROTOCOL)\n                .addParameters(CATEGORY_KEY, CONFIGURATORS_CATEGORY, CHECK_KEY, String.valueOf(false));\n    }\n\n    /**\n     * Get the address of the providerUrl through the url of the invoker\n     *\n     * @param originInvoker\n     * @return\n     */\n    private URL getProviderUrl(final Invoker<?> originInvoker) {\n        Object providerURL = originInvoker.getUrl().getAttribute(EXPORT_KEY);\n        if (!(providerURL instanceof URL)) {\n            throw new IllegalArgumentException(\"The registry export url is null! registry: \"\n                    + originInvoker.getUrl().getAddress());\n        }\n        return (URL) providerURL;\n    }\n\n    /**\n     * Get the key cached in bounds by invoker\n     *\n     * @param originInvoker\n     * @return\n     */\n    private String getProviderUrlKey(final Invoker<?> originInvoker) {\n        URL providerUrl = getProviderUrl(originInvoker);\n        return providerUrl.removeParameters(DYNAMIC_KEY, ENABLED_KEY).toFullString();\n    }\n\n    private String getRegistryUrlKey(final Invoker<?> originInvoker) {\n        URL registryUrl = getRegistryUrl(originInvoker);\n        return registryUrl.removeParameters(DYNAMIC_KEY, ENABLED_KEY).toFullString();\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {\n        url = getRegistryUrl(url);\n        Registry registry = getRegistry(url);\n        if (RegistryService.class.equals(type)) {\n            return proxyFactory.getInvoker((T) registry, type, url);\n        }\n\n        // group=\"a,b\" or group=\"*\"\n        Map<String, String> qs = (Map<String, String>) url.getAttribute(REFER_KEY);\n        String group = qs.get(GROUP_KEY);\n        if (StringUtils.isNotEmpty(group)) {\n            if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || \"*\".equals(group)) {\n                return doRefer(\n                        Cluster.getCluster(url.getScopeModel(), MERGEABLE_CLUSTER_NAME), registry, type, url, qs);\n            }\n        }\n\n        Cluster cluster = Cluster.getCluster(url.getScopeModel(), qs.get(CLUSTER_KEY));\n        return doRefer(cluster, registry, type, url, qs);\n    }\n\n    protected <T> Invoker<T> doRefer(\n            Cluster cluster, Registry registry, Class<T> type, URL url, Map<String, String> parameters) {\n        Map<String, Object> consumerAttribute = new HashMap<>(url.getAttributes());\n        consumerAttribute.remove(REFER_KEY);\n        String p = isEmpty(parameters.get(PROTOCOL_KEY)) ? CONSUMER : parameters.get(PROTOCOL_KEY);\n        URL consumerUrl = new ServiceConfigURL(\n                p,\n                null,\n                null,\n                parameters.get(REGISTER_IP_KEY),\n                0,\n                getPath(parameters, type),\n                parameters,\n                consumerAttribute);\n        url = url.putAttribute(CONSUMER_URL_KEY, consumerUrl);\n        ClusterInvoker<T> migrationInvoker = getMigrationInvoker(this, cluster, registry, type, url, consumerUrl);\n        return interceptInvoker(migrationInvoker, url, consumerUrl);\n    }\n\n    private String getPath(Map<String, String> parameters, Class<?> type) {\n        return !ProtocolUtils.isGeneric(parameters.get(GENERIC_KEY)) ? type.getName() : parameters.get(INTERFACE_KEY);\n    }\n\n    protected <T> ClusterInvoker<T> getMigrationInvoker(\n            RegistryProtocol registryProtocol,\n            Cluster cluster,\n            Registry registry,\n            Class<T> type,\n            URL url,\n            URL consumerUrl) {\n        return new ServiceDiscoveryMigrationInvoker<>(registryProtocol, cluster, registry, type, url, consumerUrl);\n    }\n\n    /**\n     * This method tries to load all RegistryProtocolListener definitions, which are used to control the behaviour of invoker by interacting with defined, then uses those listeners to\n     * change the status and behaviour of the MigrationInvoker.\n     * <p>\n     * Currently available Listener is MigrationRuleListener, one used to control the Migration behaviour with dynamically changing rules.\n     *\n     * @param invoker     MigrationInvoker that determines which type of invoker list to use\n     * @param url         The original url generated during refer, more like a registry:// style url\n     * @param consumerUrl Consumer url representing current interface and its config\n     * @param <T>         The service definition\n     * @return The @param MigrationInvoker passed in\n     */\n    protected <T> Invoker<T> interceptInvoker(ClusterInvoker<T> invoker, URL url, URL consumerUrl) {\n        List<RegistryProtocolListener> listeners = findRegistryProtocolListeners(url);\n        if (CollectionUtils.isEmpty(listeners)) {\n            return invoker;\n        }\n\n        for (RegistryProtocolListener listener : listeners) {\n            listener.onRefer(this, invoker, consumerUrl, url);\n        }\n        return invoker;\n    }\n\n    public <T> ClusterInvoker<T> getServiceDiscoveryInvoker(\n            Cluster cluster, Registry registry, Class<T> type, URL url) {\n        DynamicDirectory<T> directory = new ServiceDiscoveryRegistryDirectory<>(type, url);\n        return doCreateInvoker(directory, cluster, registry, type);\n    }\n\n    public <T> ClusterInvoker<T> getInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {\n        // FIXME, this method is currently not used, create the right registry before enable.\n        DynamicDirectory<T> directory = new RegistryDirectory<>(type, url);\n        return doCreateInvoker(directory, cluster, registry, type);\n    }\n\n    protected <T> ClusterInvoker<T> doCreateInvoker(\n            DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {\n        directory.setRegistry(registry);\n        directory.setProtocol(protocol);\n        // all attributes of REFER_KEY\n        Map<String, String> parameters =\n                new HashMap<>(directory.getConsumerUrl().getParameters());\n        URL urlToRegistry = new ServiceConfigURL(\n                parameters.get(PROTOCOL_KEY) == null ? CONSUMER : parameters.get(PROTOCOL_KEY),\n                parameters.remove(REGISTER_IP_KEY),\n                0,\n                getPath(parameters, type),\n                parameters);\n        urlToRegistry = urlToRegistry.setScopeModel(directory.getConsumerUrl().getScopeModel());\n        urlToRegistry = urlToRegistry.setServiceModel(directory.getConsumerUrl().getServiceModel());\n        if (directory.isShouldRegister()) {\n            directory.setRegisteredConsumerUrl(urlToRegistry);\n            registry.register(directory.getRegisteredConsumerUrl());\n        }\n        directory.buildRouterChain(urlToRegistry);\n        directory.subscribe(toSubscribeUrl(urlToRegistry));\n\n        return (ClusterInvoker<T>) cluster.join(directory, true);\n    }\n\n    public <T> void reRefer(ClusterInvoker<?> invoker, URL newSubscribeUrl) {\n        if (!(invoker instanceof MigrationClusterInvoker)) {\n            logger.error(\n                    REGISTRY_UNSUPPORTED_CATEGORY,\n                    \"\",\n                    \"\",\n                    \"Only invoker type of MigrationClusterInvoker supports reRefer, current invoker is \"\n                            + invoker.getClass());\n            return;\n        }\n\n        MigrationClusterInvoker<?> migrationClusterInvoker = (MigrationClusterInvoker<?>) invoker;\n        migrationClusterInvoker.reRefer(newSubscribeUrl);\n    }\n\n    public static URL toSubscribeUrl(URL url) {\n        return url.addParameter(CATEGORY_KEY, ALL_CATEGORIES);\n    }\n\n    protected List<RegistryProtocolListener> findRegistryProtocolListeners(URL url) {\n        return ScopeModelUtil.getExtensionLoader(RegistryProtocolListener.class, url.getScopeModel())\n                .getActivateExtension(url, REGISTRY_PROTOCOL_LISTENER_KEY);\n    }\n\n    @Override\n    public void destroy() {\n        // FIXME all application models in framework are removed at this moment\n        for (ApplicationModel applicationModel : frameworkModel.getApplicationModels()) {\n            for (ModuleModel moduleModel : applicationModel.getModuleModels()) {\n                List<RegistryProtocolListener> listeners = moduleModel\n                        .getExtensionLoader(RegistryProtocolListener.class)\n                        .getLoadedExtensionInstances();\n                if (CollectionUtils.isNotEmpty(listeners)) {\n                    for (RegistryProtocolListener listener : listeners) {\n                        listener.onDestroy();\n                    }\n                }\n            }\n        }\n\n        for (ApplicationModel applicationModel : frameworkModel.getApplicationModels()) {\n            if (applicationModel\n                    .modelEnvironment()\n                    .getConfiguration()\n                    .convert(Boolean.class, org.apache.dubbo.registry.Constants.ENABLE_CONFIGURATION_LISTEN, true)) {\n                for (ModuleModel moduleModel : applicationModel.getPubModuleModels()) {\n                    String applicationName = applicationModel.tryGetApplicationName();\n                    if (applicationName == null) {\n                        // already removed\n                        continue;\n                    }\n                    if (!moduleModel\n                            .getServiceRepository()\n                            .getExportedServices()\n                            .isEmpty()) {\n                        moduleModel\n                                .getExtensionLoader(GovernanceRuleRepository.class)\n                                .getDefaultExtension()\n                                .removeListener(\n                                        applicationName + CONFIGURATORS_SUFFIX,\n                                        getProviderConfigurationListener(moduleModel));\n                    }\n                }\n            }\n        }\n\n        List<Exporter<?>> exporters =\n                bounds.values().stream().flatMap(e -> e.values().stream()).collect(Collectors.toList());\n        for (Exporter<?> exporter : exporters) {\n            exporter.unexport();\n        }\n        bounds.clear();\n    }\n\n    @Override\n    public List<ProtocolServer> getServers() {\n        return protocol.getServers();\n    }\n\n    // Merge the urls of configurators\n    private static URL getConfiguredInvokerUrl(List<Configurator> configurators, URL url) {\n        if (CollectionUtils.isNotEmpty(configurators)) {\n            for (Configurator configurator : configurators) {\n                url = configurator.configure(url);\n            }\n        }\n        return url;\n    }\n\n    public static class InvokerDelegate<T> extends InvokerWrapper<T> {\n\n        /**\n         * @param invoker\n         * @param url     invoker.getUrl return this value\n         */\n        public InvokerDelegate(Invoker<T> invoker, URL url) {\n            super(invoker, url);\n        }\n\n        public Invoker<T> getInvoker() {\n            if (invoker instanceof InvokerDelegate) {\n                return ((InvokerDelegate<T>) invoker).getInvoker();\n            } else {\n                return invoker;\n            }\n        }\n    }\n\n    private static class DestroyableExporter<T> implements Exporter<T> {\n\n        private Exporter<T> exporter;\n\n        public DestroyableExporter(Exporter<T> exporter) {\n            this.exporter = exporter;\n        }\n\n        @Override\n        public Invoker<T> getInvoker() {\n            return exporter.getInvoker();\n        }\n\n        @Override\n        public void unexport() {\n            exporter.unexport();\n        }\n\n        @Override\n        public void register() {\n            exporter.register();\n        }\n\n        @Override\n        public void unregister() {\n            exporter.unregister();\n        }\n    }\n\n    /**\n     * Reexport: the exporter destroy problem in protocol\n     * 1.Ensure that the exporter returned by registry protocol can be normal destroyed\n     * 2.No need to re-register to the registry after notify\n     * 3.The invoker passed by the export method , would better to be the invoker of exporter\n     */\n    private class OverrideListener implements NotifyListener {\n        private final URL subscribeUrl;\n        private final Invoker originInvoker;\n\n        private List<Configurator> configurators;\n\n        public OverrideListener(URL subscribeUrl, Invoker originalInvoker) {\n            this.subscribeUrl = subscribeUrl;\n            this.originInvoker = originalInvoker;\n        }\n\n        /**\n         * @param urls The list of registered information, is always not empty, The meaning is the same as the\n         *             return value of {@link org.apache.dubbo.registry.RegistryService#lookup(URL)}.\n         */\n        @Override\n        public synchronized void notify(List<URL> urls) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"original override urls: \" + urls);\n            }\n\n            List<URL> matchedUrls = getMatchedUrls(urls, subscribeUrl);\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"subscribe url: \" + subscribeUrl + \", override urls: \" + matchedUrls);\n            }\n\n            // No matching results\n            if (matchedUrls.isEmpty()) {\n                return;\n            }\n\n            this.configurators = Configurator.toConfigurators(classifyUrls(matchedUrls, UrlUtils::isConfigurator))\n                    .orElse(configurators);\n\n            ApplicationDeployer deployer =\n                    subscribeUrl.getOrDefaultApplicationModel().getDeployer();\n\n            try {\n                deployer.increaseServiceRefreshCount();\n                doOverrideIfNecessary();\n            } finally {\n                deployer.decreaseServiceRefreshCount();\n            }\n        }\n\n        public synchronized void doOverrideIfNecessary() {\n            final Invoker<?> invoker;\n            if (originInvoker instanceof InvokerDelegate) {\n                invoker = ((InvokerDelegate<?>) originInvoker).getInvoker();\n            } else {\n                invoker = originInvoker;\n            }\n            // The origin invoker\n            URL originUrl = RegistryProtocol.this.getProviderUrl(invoker);\n            String providerUrlKey = getProviderUrlKey(originInvoker);\n            String registryUrlKey = getRegistryUrlKey(originInvoker);\n            Map<String, ExporterChangeableWrapper<?>> exporterMap = bounds.get(providerUrlKey);\n            if (exporterMap == null) {\n                logger.warn(\n                        INTERNAL_ERROR,\n                        \"error state, exporterMap can not be null\",\n                        \"\",\n                        \"error state, exporterMap can not be null\",\n                        new IllegalStateException(\"error state, exporterMap can not be null\"));\n                return;\n            }\n            ExporterChangeableWrapper<?> exporter = exporterMap.get(registryUrlKey);\n            if (exporter == null) {\n                logger.warn(\n                        INTERNAL_ERROR,\n                        \"unknown error in registry module\",\n                        \"\",\n                        \"error state, exporter should not be null\",\n                        new IllegalStateException(\"error state, exporter should not be null\"));\n                return;\n            }\n            // The current, may have been merged many times\n            Invoker<?> exporterInvoker = exporter.getInvoker();\n            URL currentUrl = exporterInvoker == null ? null : exporterInvoker.getUrl();\n            // Merged with this configuration\n            URL newUrl = getConfiguredInvokerUrl(configurators, originUrl);\n            newUrl = getConfiguredInvokerUrl(\n                    getProviderConfigurationListener(originUrl).getConfigurators(), newUrl);\n            newUrl = getConfiguredInvokerUrl(\n                    serviceConfigurationListeners.get(originUrl.getServiceKey()).getConfigurators(), newUrl);\n            if (!newUrl.equals(currentUrl)) {\n                if (newUrl.getParameter(Constants.NEED_REEXPORT, true)) {\n                    RegistryProtocol.this.reExport(originInvoker, newUrl);\n                }\n                logger.info(\"exported provider url changed, origin url: \" + originUrl + \", old export url: \"\n                        + currentUrl + \", new export url: \" + newUrl);\n            }\n        }\n\n        private List<URL> getMatchedUrls(List<URL> configuratorUrls, URL currentSubscribe) {\n            List<URL> result = new ArrayList<>();\n            for (URL url : configuratorUrls) {\n                URL overrideUrl = url;\n                // Compatible with the old version\n                if (url.getCategory() == null && OVERRIDE_PROTOCOL.equals(url.getProtocol())) {\n                    overrideUrl = url.addParameter(CATEGORY_KEY, CONFIGURATORS_CATEGORY);\n                }\n\n                // Check whether url is to be applied to the current service\n                if (UrlUtils.isMatch(currentSubscribe, overrideUrl)) {\n                    result.add(url);\n                }\n            }\n            return result;\n        }\n    }\n\n    private ProviderConfigurationListener getProviderConfigurationListener(URL url) {\n        return getProviderConfigurationListener(url.getOrDefaultModuleModel());\n    }\n\n    private ProviderConfigurationListener getProviderConfigurationListener(ModuleModel moduleModel) {\n        return moduleModel\n                .getBeanFactory()\n                .getOrRegisterBean(\n                        ProviderConfigurationListener.class, type -> new ProviderConfigurationListener(moduleModel));\n    }\n\n    private class ServiceConfigurationListener extends AbstractConfiguratorListener {\n        private URL providerUrl;\n        private OverrideListener notifyListener;\n\n        private final ModuleModel moduleModel;\n\n        public ServiceConfigurationListener(ModuleModel moduleModel, URL providerUrl, OverrideListener notifyListener) {\n            super(moduleModel);\n            this.providerUrl = providerUrl;\n            this.notifyListener = notifyListener;\n            this.moduleModel = moduleModel;\n            if (moduleModel\n                    .modelEnvironment()\n                    .getConfiguration()\n                    .convert(Boolean.class, ENABLE_CONFIGURATION_LISTEN, true)) {\n                this.initWith(DynamicConfiguration.getRuleKey(providerUrl) + CONFIGURATORS_SUFFIX);\n            }\n        }\n\n        private <T> URL overrideUrl(URL providerUrl) {\n            return RegistryProtocol.getConfiguredInvokerUrl(configurators, providerUrl);\n        }\n\n        @Override\n        protected void notifyOverrides() {\n            ApplicationDeployer deployer =\n                    this.moduleModel.getApplicationModel().getDeployer();\n            try {\n                deployer.increaseServiceRefreshCount();\n                notifyListener.doOverrideIfNecessary();\n            } finally {\n                deployer.decreaseServiceRefreshCount();\n            }\n        }\n    }\n\n    private class ProviderConfigurationListener extends AbstractConfiguratorListener {\n\n        private final ConcurrentHashMap<URL, Set<NotifyListener>> overrideListeners = new ConcurrentHashMap<>();\n\n        private final ModuleModel moduleModel;\n\n        public ProviderConfigurationListener(ModuleModel moduleModel) {\n            super(moduleModel);\n            this.moduleModel = moduleModel;\n            if (moduleModel.modelEnvironment().getConfiguration().getBoolean(ENABLE_CONFIGURATION_LISTEN, true)) {\n                this.initWith(moduleModel.getApplicationModel().getApplicationName() + CONFIGURATORS_SUFFIX);\n            }\n        }\n\n        /**\n         * Get existing configuration rule and override provider url before exporting.\n         *\n         * @param providerUrl\n         * @param <T>\n         * @return\n         */\n        private <T> URL overrideUrl(URL providerUrl) {\n            return RegistryProtocol.getConfiguredInvokerUrl(configurators, providerUrl);\n        }\n\n        @Override\n        protected void notifyOverrides() {\n            ApplicationDeployer deployer =\n                    this.moduleModel.getApplicationModel().getDeployer();\n            try {\n                deployer.increaseServiceRefreshCount();\n                overrideListeners.values().forEach(listeners -> {\n                    for (NotifyListener listener : listeners) {\n                        ((OverrideListener) listener).doOverrideIfNecessary();\n                    }\n                });\n            } finally {\n                deployer.decreaseServiceRefreshCount();\n            }\n        }\n\n        public ConcurrentHashMap<URL, Set<NotifyListener>> getOverrideListeners() {\n            return overrideListeners;\n        }\n    }\n\n    /**\n     * exporter proxy, establish the corresponding relationship between the returned exporter and the exporter\n     * exported by the protocol, and can modify the relationship at the time of override.\n     *\n     * @param <T>\n     */\n    private class ExporterChangeableWrapper<T> implements Exporter<T> {\n\n        private final ScheduledExecutorService executor;\n\n        private final Invoker<T> originInvoker;\n        private Exporter<T> exporter;\n        private URL subscribeUrl;\n        private URL registerUrl;\n\n        private NotifyListener notifyListener;\n        private final AtomicBoolean registered = new AtomicBoolean(false);\n\n        public ExporterChangeableWrapper(ReferenceCountExporter<T> exporter, Invoker<T> originInvoker) {\n            this.exporter = exporter;\n            exporter.increaseCount();\n            this.originInvoker = originInvoker;\n            FrameworkExecutorRepository frameworkExecutorRepository = originInvoker\n                    .getUrl()\n                    .getOrDefaultFrameworkModel()\n                    .getBeanFactory()\n                    .getBean(FrameworkExecutorRepository.class);\n            this.executor = frameworkExecutorRepository.getSharedScheduledExecutor();\n        }\n\n        public Invoker<T> getOriginInvoker() {\n            return originInvoker;\n        }\n\n        @Override\n        public Invoker<T> getInvoker() {\n            return exporter.getInvoker();\n        }\n\n        public void setExporter(Exporter<T> exporter) {\n            this.exporter = exporter;\n        }\n\n        @Override\n        public void register() {\n            if (registered.compareAndSet(false, true)) {\n                URL registryUrl = getRegistryUrl(originInvoker);\n                Registry registry = getRegistry(registryUrl);\n                RegistryProtocol.register(registry, getRegisterUrl());\n\n                ProviderModel providerModel = frameworkModel\n                        .getServiceRepository()\n                        .lookupExportedService(getRegisterUrl().getServiceKey());\n\n                List<ProviderModel.RegisterStatedURL> statedUrls = providerModel.getStatedUrl();\n                statedUrls.stream()\n                        .filter(u -> u.getRegistryUrl().equals(registryUrl)\n                                && u.getProviderUrl()\n                                        .getProtocol()\n                                        .equals(getRegisterUrl().getProtocol()))\n                        .forEach(u -> u.setRegistered(true));\n                logger.info(\"[INSTANCE_REGISTER] Registered dubbo service \"\n                        + getRegisterUrl().getServiceKey() + \" url \" + getRegisterUrl() + \" to registry \"\n                        + registryUrl);\n            }\n        }\n\n        @Override\n        public synchronized void unregister() {\n            if (registered.compareAndSet(true, false)) {\n                URL registryUrl = getRegistryUrl(originInvoker);\n                Registry registry = RegistryProtocol.this.getRegistry(registryUrl);\n\n                ProviderModel providerModel = frameworkModel\n                        .getServiceRepository()\n                        .lookupExportedService(getRegisterUrl().getServiceKey());\n\n                List<ProviderModel.RegisterStatedURL> statedURLs = providerModel.getStatedUrl().stream()\n                        .filter(u -> u.getRegistryUrl().equals(registryUrl)\n                                && u.getProviderUrl()\n                                        .getProtocol()\n                                        .equals(getRegisterUrl().getProtocol()))\n                        .collect(Collectors.toList());\n                if (statedURLs.isEmpty()\n                        || statedURLs.stream().anyMatch(ProviderModel.RegisterStatedURL::isRegistered)) {\n                    try {\n                        registry.unregister(registerUrl);\n                    } catch (Throwable t) {\n                        logger.warn(INTERNAL_ERROR, \"unknown error in registry module\", \"\", t.getMessage(), t);\n                    }\n                }\n\n                try {\n                    if (subscribeUrl != null) {\n                        Map<URL, Set<NotifyListener>> overrideListeners =\n                                getProviderConfigurationListener(subscribeUrl).getOverrideListeners();\n                        Set<NotifyListener> listeners = overrideListeners.get(subscribeUrl);\n                        if (listeners != null) {\n                            if (listeners.remove(notifyListener)) {\n                                ApplicationModel applicationModel = getApplicationModel(registerUrl.getScopeModel());\n                                if (applicationModel\n                                        .modelEnvironment()\n                                        .getConfiguration()\n                                        .convert(Boolean.class, ENABLE_26X_CONFIGURATION_LISTEN, true)) {\n                                    if (!registry.isServiceDiscovery()) {\n                                        registry.unsubscribe(subscribeUrl, notifyListener);\n                                    }\n                                }\n                                if (applicationModel\n                                        .modelEnvironment()\n                                        .getConfiguration()\n                                        .convert(Boolean.class, ENABLE_CONFIGURATION_LISTEN, true)) {\n                                    for (ModuleModel moduleModel : applicationModel.getPubModuleModels()) {\n                                        if (null != moduleModel.getServiceRepository()\n                                                && !moduleModel\n                                                        .getServiceRepository()\n                                                        .getExportedServices()\n                                                        .isEmpty()) {\n                                            moduleModel\n                                                    .getExtensionLoader(GovernanceRuleRepository.class)\n                                                    .getDefaultExtension()\n                                                    .removeListener(\n                                                            subscribeUrl.getServiceKey() + CONFIGURATORS_SUFFIX,\n                                                            serviceConfigurationListeners.remove(\n                                                                    subscribeUrl.getServiceKey()));\n                                        }\n                                    }\n                                }\n                            }\n                            if (listeners.isEmpty()) {\n                                overrideListeners.remove(subscribeUrl);\n                            }\n                        }\n                    }\n                } catch (Throwable t) {\n                    logger.warn(INTERNAL_ERROR, \"unknown error in registry module\", \"\", t.getMessage(), t);\n                }\n            }\n        }\n\n        @Override\n        public synchronized void unexport() {\n            String providerUrlKey = getProviderUrlKey(this.originInvoker);\n            String registryUrlKey = getRegistryUrlKey(this.originInvoker);\n            Map<String, ExporterChangeableWrapper<?>> exporterMap = bounds.remove(providerUrlKey);\n            if (exporterMap != null) {\n                exporterMap.remove(registryUrlKey);\n            }\n\n            unregister();\n            doUnExport();\n        }\n\n        public void setRegistered(boolean registered) {\n            this.registered.set(registered);\n        }\n\n        public boolean isRegistered() {\n            return registered.get();\n        }\n\n        private void doUnExport() {\n            try {\n                exporter.unexport();\n            } catch (Throwable t) {\n                logger.warn(INTERNAL_ERROR, \"unknown error in registry module\", \"\", t.getMessage(), t);\n            }\n        }\n\n        public void setSubscribeUrl(URL subscribeUrl) {\n            this.subscribeUrl = subscribeUrl;\n        }\n\n        public void setRegisterUrl(URL registerUrl) {\n            this.registerUrl = registerUrl;\n        }\n\n        public void setNotifyListener(NotifyListener notifyListener) {\n            this.notifyListener = notifyListener;\n        }\n\n        public URL getRegisterUrl() {\n            return registerUrl;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocolListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\nimport static org.apache.dubbo.common.extension.ExtensionScope.MODULE;\n\n/**\n * RegistryProtocol listener is introduced to provide a chance to user to customize or change export and refer behavior\n * of RegistryProtocol. For example: re-export or re-refer on the fly when certain condition meets.\n */\n@SPI(scope = MODULE)\npublic interface RegistryProtocolListener {\n    /**\n     * Notify RegistryProtocol's listeners when a service is registered\n     *\n     * @param registryProtocol RegistryProtocol instance\n     * @param exporter         exporter\n     * @see RegistryProtocol#export(org.apache.dubbo.rpc.Invoker)\n     */\n    void onExport(RegistryProtocol registryProtocol, Exporter<?> exporter);\n\n    /**\n     * Notify RegistryProtocol's listeners when a service is subscribed\n     *\n     * @param registryProtocol RegistryProtocol instance\n     * @param invoker          invoker\n     * @param url\n     * @see RegistryProtocol#refer(Class, URL)\n     */\n    void onRefer(RegistryProtocol registryProtocol, ClusterInvoker<?> invoker, URL url, URL registryURL);\n\n    /**\n     * Notify RegistryProtocol's listeners when the protocol is destroyed\n     */\n    void onDestroy();\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/ServiceURLCustomizer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.lang.Prioritized;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport static org.apache.dubbo.common.extension.ExtensionScope.APPLICATION;\n\n/**\n * Customize parameters for interface-level registration\n */\n@SPI(scope = APPLICATION)\npublic interface ServiceURLCustomizer extends Prioritized {\n\n    /**\n     * Customizes {@link URL the service url}\n     *\n     * @param serviceURL {@link URL the service url}\n     * @return new service url\n     */\n    URL customize(URL serviceURL, ApplicationModel applicationModel);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/retry/AbstractRetryTask.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.retry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.timer.Timeout;\nimport org.apache.dubbo.common.timer.Timer;\nimport org.apache.dubbo.common.timer.TimerTask;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.support.FailbackRegistry;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_EXECUTE_RETRYING_TASK;\nimport static org.apache.dubbo.registry.Constants.DEFAULT_REGISTRY_RETRY_PERIOD;\nimport static org.apache.dubbo.registry.Constants.DEFAULT_REGISTRY_RETRY_TIMES;\nimport static org.apache.dubbo.registry.Constants.REGISTRY_RETRY_PERIOD_KEY;\nimport static org.apache.dubbo.registry.Constants.REGISTRY_RETRY_TIMES_KEY;\n\npublic abstract class AbstractRetryTask implements TimerTask {\n\n    protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    /**\n     * url for retry task\n     */\n    protected final URL url;\n\n    /**\n     * registry for this task\n     */\n    protected final FailbackRegistry registry;\n\n    /**\n     * retry period\n     */\n    private final long retryPeriod;\n\n    /**\n     * define the most retry times\n     */\n    private final int retryTimes;\n\n    /**\n     * task name for this task\n     */\n    private final String taskName;\n\n    /**\n     * times of retry.\n     * retry task is execute in single thread so that the times is not need volatile.\n     */\n    private int times = 1;\n\n    private volatile boolean cancel;\n\n    AbstractRetryTask(URL url, FailbackRegistry registry, String taskName) {\n        if (url == null || StringUtils.isBlank(taskName)) {\n            throw new IllegalArgumentException();\n        }\n        this.url = url;\n        this.registry = registry;\n        this.taskName = taskName;\n        this.cancel = false;\n        this.retryPeriod = url.getParameter(REGISTRY_RETRY_PERIOD_KEY, DEFAULT_REGISTRY_RETRY_PERIOD);\n        this.retryTimes = url.getParameter(REGISTRY_RETRY_TIMES_KEY, DEFAULT_REGISTRY_RETRY_TIMES);\n    }\n\n    public void cancel() {\n        cancel = true;\n    }\n\n    public boolean isCancel() {\n        return cancel;\n    }\n\n    protected void reput(Timeout timeout, long tick) {\n        if (timeout == null) {\n            throw new IllegalArgumentException();\n        }\n\n        Timer timer = timeout.timer();\n        if (timer.isStop() || timeout.isCancelled() || isCancel()) {\n            return;\n        }\n        times++;\n        timer.newTimeout(timeout.task(), tick, TimeUnit.MILLISECONDS);\n    }\n\n    @Override\n    public void run(Timeout timeout) throws Exception {\n        if (timeout.isCancelled() || timeout.timer().isStop() || isCancel()) {\n            // other thread cancel this timeout or stop the timer.\n            return;\n        }\n        if (retryTimes > 0 && times > retryTimes) {\n            // 1-13 - failed to execute the retrying task.\n\n            logger.warn(\n                    REGISTRY_EXECUTE_RETRYING_TASK,\n                    \"registry center offline\",\n                    \"Check the registry server.\",\n                    \"Final failed to execute task \" + taskName + \", url: \" + url + \", retry \" + retryTimes + \" times.\");\n\n            return;\n        }\n        if (logger.isInfoEnabled()) {\n            logger.info(taskName + \" : \" + url);\n        }\n        try {\n            if (!registry.isAvailable()) {\n                throw new IllegalStateException(\"Registry is not available.\");\n            }\n            doRetry(url, registry, timeout);\n        } catch (Throwable t) { // Ignore all the exceptions and wait for the next retry\n\n            // 1-13 - failed to execute the retrying task.\n\n            logger.warn(\n                    REGISTRY_EXECUTE_RETRYING_TASK,\n                    \"registry center offline\",\n                    \"Check the registry server.\",\n                    \"Failed to execute task \" + taskName + \", url: \" + url + \", waiting for again, cause:\"\n                            + t.getMessage(),\n                    t);\n\n            // reput this task when catch exception.\n            reput(timeout, retryPeriod);\n        }\n    }\n\n    protected abstract void doRetry(URL url, FailbackRegistry registry, Timeout timeout);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/retry/FailedRegisteredTask.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.retry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.timer.Timeout;\nimport org.apache.dubbo.registry.support.FailbackRegistry;\n\npublic final class FailedRegisteredTask extends AbstractRetryTask {\n\n    private static final String NAME = \"retry register\";\n\n    public FailedRegisteredTask(URL url, FailbackRegistry registry) {\n        super(url, registry, NAME);\n    }\n\n    @Override\n    protected void doRetry(URL url, FailbackRegistry registry, Timeout timeout) {\n        registry.doRegister(url);\n        registry.removeFailedRegisteredTask(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/retry/FailedSubscribedTask.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.retry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.timer.Timeout;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.support.FailbackRegistry;\n\npublic final class FailedSubscribedTask extends AbstractRetryTask {\n\n    private static final String NAME = \"retry subscribe\";\n\n    private final NotifyListener listener;\n\n    public FailedSubscribedTask(URL url, FailbackRegistry registry, NotifyListener listener) {\n        super(url, registry, NAME);\n        if (listener == null) {\n            throw new IllegalArgumentException();\n        }\n        this.listener = listener;\n    }\n\n    @Override\n    protected void doRetry(URL url, FailbackRegistry registry, Timeout timeout) {\n        registry.doSubscribe(url, listener);\n        registry.removeFailedSubscribedTask(url, listener);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/retry/FailedUnregisteredTask.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.retry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.timer.Timeout;\nimport org.apache.dubbo.registry.support.FailbackRegistry;\n\npublic final class FailedUnregisteredTask extends AbstractRetryTask {\n\n    private static final String NAME = \"retry unregister\";\n\n    public FailedUnregisteredTask(URL url, FailbackRegistry registry) {\n        super(url, registry, NAME);\n    }\n\n    @Override\n    protected void doRetry(URL url, FailbackRegistry registry, Timeout timeout) {\n        registry.doUnregister(url);\n        registry.removeFailedUnregisteredTask(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/retry/FailedUnsubscribedTask.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.retry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.timer.Timeout;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.support.FailbackRegistry;\n\npublic final class FailedUnsubscribedTask extends AbstractRetryTask {\n\n    private static final String NAME = \"retry unsubscribe\";\n\n    private final NotifyListener listener;\n\n    public FailedUnsubscribedTask(URL url, FailbackRegistry registry, NotifyListener listener) {\n        super(url, registry, NAME);\n        if (listener == null) {\n            throw new IllegalArgumentException();\n        }\n        this.listener = listener;\n    }\n\n    @Override\n    protected void doRetry(URL url, FailbackRegistry registry, Timeout timeout) {\n        registry.doUnsubscribe(url, listener);\n        registry.removeFailedUnsubscribedTask(url, listener);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/retry/ReExportTask.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.retry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.timer.Timeout;\nimport org.apache.dubbo.registry.support.FailbackRegistry;\n\npublic class ReExportTask extends AbstractRetryTask {\n\n    private static final String NAME = \"retry re-export\";\n\n    private Runnable runnable;\n\n    public ReExportTask(Runnable runnable, URL oldUrl, FailbackRegistry registry) {\n        super(oldUrl, registry, NAME);\n        this.runnable = runnable;\n    }\n\n    @Override\n    protected void doRetry(URL oldUrl, FailbackRegistry registry, Timeout timeout) {\n        runnable.run();\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/status/RegistryStatusChecker.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.status;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.status.Status;\nimport org.apache.dubbo.common.status.StatusChecker;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.support.RegistryManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\n\n/**\n * RegistryStatusChecker\n *\n */\n@Activate\npublic class RegistryStatusChecker implements StatusChecker {\n\n    private ApplicationModel applicationModel;\n\n    public RegistryStatusChecker(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    @Override\n    public Status check() {\n        RegistryManager registryManager = applicationModel.getBeanFactory().getBean(RegistryManager.class);\n        Collection<Registry> registries = registryManager.getRegistries();\n        if (registries.isEmpty()) {\n            return new Status(Status.Level.UNKNOWN);\n        }\n        Status.Level level = Status.Level.OK;\n        StringBuilder buf = new StringBuilder();\n        for (Registry registry : registries) {\n            if (buf.length() > 0) {\n                buf.append(',');\n            }\n            buf.append(registry.getUrl().getAddress());\n            if (!registry.isAvailable()) {\n                level = Status.Level.ERROR;\n                buf.append(\"(disconnected)\");\n            } else {\n                buf.append(\"(connected)\");\n            }\n        }\n        return new Status(level, buf.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.ConfigUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileLock;\nimport java.nio.channels.OverlappingFileLockException;\nimport java.nio.file.Files;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED;\nimport static org.apache.dubbo.common.constants.CommonConstants.SystemProperty.USER_HOME;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_EMPTY_ADDRESS;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_DELETE_LOCKFILE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_DESTROY_UNREGISTER_URL;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_NOTIFY_EVENT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_READ_WRITE_CACHE_FILE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ACCEPTS_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.apache.dubbo.registry.Constants.CACHE;\nimport static org.apache.dubbo.registry.Constants.DUBBO_REGISTRY;\nimport static org.apache.dubbo.registry.Constants.REGISTRY_FILESAVE_SYNC_KEY;\n\n/**\n * <p>\n * Provides a fail-safe registry service backed by cache file. The consumer/provider can still find each other when registry center crashed.\n * <p>\n * (SPI, Prototype, ThreadSafe)\n */\npublic abstract class AbstractRegistry implements Registry {\n\n    // URL address separator, used in file cache, service provider URL separation\n    private static final char URL_SEPARATOR = ' ';\n    // URL address separated regular expression for parsing the service provider URL list in the file cache\n    private static final String URL_SPLIT = \"\\\\s+\";\n    // Max times to retry to save properties to local cache file\n    private static final int MAX_RETRY_TIMES_SAVE_PROPERTIES = 3;\n    // Default interval in millisecond for saving properties to local cache file\n    private static final long DEFAULT_INTERVAL_SAVE_PROPERTIES = 500L;\n\n    // Log output\n    protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    // Local disk cache, where the special key value.registries records the list of registry centers, and the others are\n    // the list of notified service providers\n    private final Properties properties = new Properties();\n    // File cache timing writing\n    private final ScheduledExecutorService registryCacheExecutor;\n    private final AtomicLong lastCacheChanged = new AtomicLong();\n    private final AtomicInteger savePropertiesRetryTimes = new AtomicInteger();\n    private final Set<URL> registered = new ConcurrentHashSet<>();\n    private final ConcurrentMap<URL, Set<NotifyListener>> subscribed = new ConcurrentHashMap<>();\n    private final ConcurrentMap<URL, Map<String, List<URL>>> notified = new ConcurrentHashMap<>();\n    // Is it synchronized to save the file\n    private boolean syncSaveFile;\n    private URL registryUrl;\n    // Local disk cache file\n    private File file;\n    private final boolean localCacheEnabled;\n    protected RegistryManager registryManager;\n    protected ApplicationModel applicationModel;\n\n    private static final String CAUSE_MULTI_DUBBO_USING_SAME_FILE = \"multiple Dubbo instance are using the same file\";\n\n    protected AbstractRegistry(URL url) {\n        setUrl(url);\n        registryManager = url.getOrDefaultApplicationModel().getBeanFactory().getBean(RegistryManager.class);\n        localCacheEnabled = url.getParameter(REGISTRY_LOCAL_FILE_CACHE_ENABLED, true);\n        registryCacheExecutor = url.getOrDefaultFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getSharedScheduledExecutor();\n        if (localCacheEnabled) {\n            // Start file save timer\n            syncSaveFile = url.getParameter(REGISTRY_FILESAVE_SYNC_KEY, false);\n\n            String defaultFilename = SystemPropertyConfigUtils.getSystemProperty(USER_HOME) + DUBBO_REGISTRY\n                    + url.getApplication() + \"-\" + url.getAddress().replaceAll(\":\", \"-\") + CACHE;\n\n            String filename = url.getParameter(FILE_KEY, defaultFilename);\n            File file = null;\n\n            if (ConfigUtils.isNotEmpty(filename)) {\n                file = new File(filename);\n                if (!file.exists()\n                        && file.getParentFile() != null\n                        && !file.getParentFile().exists()) {\n                    if (!file.getParentFile().mkdirs()) {\n\n                        IllegalArgumentException illegalArgumentException =\n                                new IllegalArgumentException(\"Invalid registry cache file \" + file\n                                        + \", cause: Failed to create directory \" + file.getParentFile() + \"!\");\n\n                        if (logger != null) {\n                            // 1-9 failed to read / save registry cache file.\n\n                            logger.error(\n                                    REGISTRY_FAILED_READ_WRITE_CACHE_FILE,\n                                    \"cache directory inaccessible\",\n                                    \"Try adjusting permission of the directory.\",\n                                    \"failed to create directory\",\n                                    illegalArgumentException);\n                        }\n\n                        throw illegalArgumentException;\n                    }\n                }\n            }\n\n            this.file = file;\n\n            // When starting the subscription center,\n            // we need to read the local cache file for future Registry fault tolerance processing.\n            loadProperties();\n            notify(url.getBackupUrls());\n        }\n    }\n\n    protected static List<URL> filterEmpty(URL url, List<URL> urls) {\n        if (CollectionUtils.isEmpty(urls)) {\n            List<URL> result = new ArrayList<>(1);\n            result.add(url.setProtocol(EMPTY_PROTOCOL));\n            return result;\n        }\n        return urls;\n    }\n\n    @Override\n    public URL getUrl() {\n        return registryUrl;\n    }\n\n    protected void setUrl(URL url) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"registry url == null\");\n        }\n        this.registryUrl = url;\n    }\n\n    public Set<URL> getRegistered() {\n        return Collections.unmodifiableSet(registered);\n    }\n\n    public Map<URL, Set<NotifyListener>> getSubscribed() {\n        return Collections.unmodifiableMap(subscribed);\n    }\n\n    public Map<URL, Map<String, List<URL>>> getNotified() {\n        return Collections.unmodifiableMap(notified);\n    }\n\n    public File getCacheFile() {\n        return file;\n    }\n\n    public Properties getCacheProperties() {\n        return properties;\n    }\n\n    public AtomicLong getLastCacheChanged() {\n        return lastCacheChanged;\n    }\n\n    public void doSaveProperties(long version) {\n        if (version < lastCacheChanged.get()) {\n            return;\n        }\n        if (file == null) {\n            return;\n        }\n        // Save\n        File lockfile = null;\n        try {\n            lockfile = new File(file.getAbsolutePath() + \".lock\");\n            if (!lockfile.exists()) {\n                lockfile.createNewFile();\n            }\n\n            try (RandomAccessFile raf = new RandomAccessFile(lockfile, \"rw\");\n                    FileChannel channel = raf.getChannel()) {\n                FileLock lock = channel.tryLock();\n                if (lock == null) {\n\n                    IOException ioException = new IOException(\n                            \"Can not lock the registry cache file \" + file.getAbsolutePath() + \", \"\n                                    + \"ignore and retry later, maybe multi java process use the file, please config: dubbo.registry.file=xxx.properties\");\n\n                    // 1-9 failed to read / save registry cache file.\n                    logger.warn(\n                            REGISTRY_FAILED_READ_WRITE_CACHE_FILE,\n                            CAUSE_MULTI_DUBBO_USING_SAME_FILE,\n                            \"\",\n                            \"Adjust dubbo.registry.file.\",\n                            ioException);\n\n                    throw ioException;\n                }\n\n                // Save\n                try {\n                    if (!file.exists()) {\n                        file.createNewFile();\n                    }\n\n                    Properties tmpProperties;\n                    if (syncSaveFile) {\n                        // When syncReport = true, properties.setProperty and properties.store are called from the same\n                        // thread(reportCacheExecutor), so deep copy is not required\n                        tmpProperties = properties;\n                    } else {\n                        // Using properties.setProperty and properties.store method will cause lock contention\n                        // under multi-threading, so deep copy a new container\n                        tmpProperties = new Properties();\n                        Set<Map.Entry<Object, Object>> entries = properties.entrySet();\n                        for (Map.Entry<Object, Object> entry : entries) {\n                            tmpProperties.setProperty((String) entry.getKey(), (String) entry.getValue());\n                        }\n                    }\n\n                    try (FileOutputStream outputFile = new FileOutputStream(file)) {\n                        tmpProperties.store(outputFile, \"Dubbo Registry Cache\");\n                    }\n                } finally {\n                    lock.release();\n                }\n            }\n        } catch (Throwable e) {\n            savePropertiesRetryTimes.incrementAndGet();\n\n            if (savePropertiesRetryTimes.get() >= MAX_RETRY_TIMES_SAVE_PROPERTIES) {\n                if (e instanceof OverlappingFileLockException) {\n                    // fix #9341, ignore OverlappingFileLockException\n                    logger.info(\"Failed to save registry cache file for file overlapping lock exception, file name \"\n                            + file.getName());\n                } else {\n                    // 1-9 failed to read / save registry cache file.\n                    logger.warn(\n                            REGISTRY_FAILED_READ_WRITE_CACHE_FILE,\n                            CAUSE_MULTI_DUBBO_USING_SAME_FILE,\n                            \"\",\n                            \"Failed to save registry cache file after retrying \" + MAX_RETRY_TIMES_SAVE_PROPERTIES\n                                    + \" times, cause: \" + e.getMessage(),\n                            e);\n                }\n\n                savePropertiesRetryTimes.set(0);\n                return;\n            }\n\n            if (version < lastCacheChanged.get()) {\n                savePropertiesRetryTimes.set(0);\n                return;\n            } else {\n                registryCacheExecutor.schedule(\n                        () -> doSaveProperties(lastCacheChanged.incrementAndGet()),\n                        DEFAULT_INTERVAL_SAVE_PROPERTIES,\n                        TimeUnit.MILLISECONDS);\n            }\n\n            if (!(e instanceof OverlappingFileLockException)) {\n                logger.warn(\n                        REGISTRY_FAILED_READ_WRITE_CACHE_FILE,\n                        CAUSE_MULTI_DUBBO_USING_SAME_FILE,\n                        \"However, the retrying count limit is not exceeded. Dubbo will still try.\",\n                        \"Failed to save registry cache file, will retry, cause: \" + e.getMessage(),\n                        e);\n            }\n        } finally {\n            if (lockfile != null) {\n                if (!lockfile.delete()) {\n                    // 1-10 Failed to delete lock file.\n                    logger.warn(\n                            REGISTRY_FAILED_DELETE_LOCKFILE,\n                            \"\",\n                            \"\",\n                            String.format(\"Failed to delete lock file [%s]\", lockfile.getName()));\n                }\n            }\n        }\n    }\n\n    private void loadProperties() {\n        if (file == null || !file.exists()) {\n            return;\n        }\n        try (InputStream in = Files.newInputStream(file.toPath())) {\n            properties.load(in);\n            if (logger.isInfoEnabled()) {\n                logger.info(\"Loaded registry cache file \" + file);\n            }\n        } catch (IOException e) {\n            // 1-9 failed to read / save registry cache file.\n            logger.warn(\n                    REGISTRY_FAILED_READ_WRITE_CACHE_FILE, CAUSE_MULTI_DUBBO_USING_SAME_FILE, \"\", e.getMessage(), e);\n\n        } catch (Throwable e) {\n            // 1-9 failed to read / save registry cache file.\n            logger.warn(\n                    REGISTRY_FAILED_READ_WRITE_CACHE_FILE,\n                    CAUSE_MULTI_DUBBO_USING_SAME_FILE,\n                    \"\",\n                    \"Failed to load registry cache file \" + file,\n                    e);\n        }\n    }\n\n    public List<URL> getCacheUrls(URL url) {\n        Map<String, List<URL>> categoryNotified = notified.get(url);\n        if (CollectionUtils.isNotEmptyMap(categoryNotified)) {\n            List<URL> urls = categoryNotified.values().stream()\n                    .flatMap(Collection::stream)\n                    .collect(Collectors.toList());\n            return urls;\n        }\n\n        for (Map.Entry<Object, Object> entry : properties.entrySet()) {\n            String key = (String) entry.getKey();\n            String value = (String) entry.getValue();\n            if (StringUtils.isNotEmpty(key)\n                    && key.equals(url.getServiceKey())\n                    && (Character.isLetter(key.charAt(0)) || key.charAt(0) == '_')\n                    && StringUtils.isNotEmpty(value)) {\n                String[] arr = value.trim().split(URL_SPLIT);\n                List<URL> urls = new ArrayList<>();\n                for (String u : arr) {\n                    urls.add(URL.valueOf(u));\n                }\n                return urls;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        List<URL> result = new ArrayList<>();\n        Map<String, List<URL>> notifiedUrls = getNotified().get(url);\n        if (CollectionUtils.isNotEmptyMap(notifiedUrls)) {\n            for (List<URL> urls : notifiedUrls.values()) {\n                for (URL u : urls) {\n                    if (!EMPTY_PROTOCOL.equals(u.getProtocol())) {\n                        result.add(u);\n                    }\n                }\n            }\n        } else {\n            final AtomicReference<List<URL>> reference = new AtomicReference<>();\n            NotifyListener listener = reference::set;\n            subscribe(url, listener); // Subscribe logic guarantees the first notify to return\n            List<URL> urls = reference.get();\n            if (CollectionUtils.isNotEmpty(urls)) {\n                for (URL u : urls) {\n                    if (!EMPTY_PROTOCOL.equals(u.getProtocol())) {\n                        result.add(u);\n                    }\n                }\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public void register(URL url) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"register url == null\");\n        }\n        if (url.getPort() != 0) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"Register: \" + url);\n            }\n        }\n        registered.add(url);\n    }\n\n    @Override\n    public void unregister(URL url) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"unregister url == null\");\n        }\n        if (url.getPort() != 0) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"Unregister: \" + url);\n            }\n        }\n        registered.remove(url);\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"subscribe url == null\");\n        }\n        if (listener == null) {\n            throw new IllegalArgumentException(\"subscribe listener == null\");\n        }\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Subscribe: \" + url);\n        }\n        Set<NotifyListener> listeners =\n                ConcurrentHashMapUtils.computeIfAbsent(subscribed, url, n -> new ConcurrentHashSet<>());\n        listeners.add(listener);\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"unsubscribe url == null\");\n        }\n        if (listener == null) {\n            throw new IllegalArgumentException(\"unsubscribe listener == null\");\n        }\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Unsubscribe: \" + url);\n        }\n        Set<NotifyListener> listeners = subscribed.get(url);\n        if (listeners != null) {\n            listeners.remove(listener);\n        }\n\n        // do not forget remove notified\n        notified.remove(url);\n    }\n\n    protected void recover() throws Exception {\n        // register\n        Set<URL> recoverRegistered = new HashSet<>(getRegistered());\n        if (!recoverRegistered.isEmpty()) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"Recover register url \" + recoverRegistered);\n            }\n            for (URL url : recoverRegistered) {\n                register(url);\n            }\n        }\n        // subscribe\n        Map<URL, Set<NotifyListener>> recoverSubscribed = new HashMap<>(getSubscribed());\n        if (!recoverSubscribed.isEmpty()) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"Recover subscribe url \" + recoverSubscribed.keySet());\n            }\n            for (Map.Entry<URL, Set<NotifyListener>> entry : recoverSubscribed.entrySet()) {\n                URL url = entry.getKey();\n                for (NotifyListener listener : entry.getValue()) {\n                    subscribe(url, listener);\n                }\n            }\n        }\n    }\n\n    protected void notify(List<URL> urls) {\n        if (CollectionUtils.isEmpty(urls)) {\n            return;\n        }\n\n        for (Map.Entry<URL, Set<NotifyListener>> entry : getSubscribed().entrySet()) {\n            URL url = entry.getKey();\n\n            if (!UrlUtils.isMatch(url, urls.get(0))) {\n                continue;\n            }\n\n            Set<NotifyListener> listeners = entry.getValue();\n            if (listeners != null) {\n                for (NotifyListener listener : listeners) {\n                    try {\n                        notify(url, listener, filterEmpty(url, urls));\n                    } catch (Throwable t) {\n                        // 1-7: Failed to notify registry event.\n                        logger.error(\n                                REGISTRY_FAILED_NOTIFY_EVENT,\n                                \"consumer is offline\",\n                                \"\",\n                                \"Failed to notify registry event, urls: \" + urls + \", cause: \" + t.getMessage(),\n                                t);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Notify changes from the provider side.\n     *\n     * @param url      consumer side url\n     * @param listener listener\n     * @param urls     provider latest urls\n     */\n    protected void notify(URL url, NotifyListener listener, List<URL> urls) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"notify url == null\");\n        }\n        if (listener == null) {\n            throw new IllegalArgumentException(\"notify listener == null\");\n        }\n        if ((CollectionUtils.isEmpty(urls)) && !ANY_VALUE.equals(url.getServiceInterface())) {\n            // 1-4 Empty address.\n            logger.warn(REGISTRY_EMPTY_ADDRESS, \"\", \"\", \"Ignore empty notify urls for subscribe url \" + url);\n            return;\n        }\n        if (logger.isInfoEnabled()) {\n            logger.info(\"[INSTANCE_REGISTER] Notify urls for subscribe url \" + url + \", url size: \" + urls.size());\n        }\n        // keep every provider's category.\n        Map<String, List<URL>> result = new HashMap<>();\n        for (URL u : urls) {\n            if (UrlUtils.isMatch(url, u)) {\n                String category = u.getCategory(DEFAULT_CATEGORY);\n                List<URL> categoryList = result.computeIfAbsent(category, k -> new ArrayList<>());\n                categoryList.add(u);\n            }\n        }\n        if (result.size() == 0) {\n            return;\n        }\n        Map<String, List<URL>> categoryNotified =\n                ConcurrentHashMapUtils.computeIfAbsent(notified, url, u -> new ConcurrentHashMap<>());\n        for (Map.Entry<String, List<URL>> entry : result.entrySet()) {\n            String category = entry.getKey();\n            List<URL> categoryList = entry.getValue();\n            categoryNotified.put(category, categoryList);\n            listener.notify(categoryList);\n\n            // We will update our cache file after each notification.\n            // When our Registry has a subscribed failure due to network jitter, we can return at least the existing\n            // cache URL.\n            if (localCacheEnabled) {\n                saveProperties(url);\n            }\n        }\n    }\n\n    private void saveProperties(URL url) {\n        if (file == null) {\n            return;\n        }\n\n        try {\n            StringBuilder buf = new StringBuilder();\n            Map<String, List<URL>> categoryNotified = notified.get(url);\n            if (categoryNotified != null) {\n                for (List<URL> us : categoryNotified.values()) {\n                    for (URL u : us) {\n                        if (buf.length() > 0) {\n                            buf.append(URL_SEPARATOR);\n                        }\n                        buf.append(u.toFullString());\n                    }\n                }\n            }\n            properties.setProperty(url.getServiceKey(), buf.toString());\n            long version = lastCacheChanged.incrementAndGet();\n            if (syncSaveFile) {\n                doSaveProperties(version);\n            } else {\n                registryCacheExecutor.schedule(\n                        () -> doSaveProperties(version), DEFAULT_INTERVAL_SAVE_PROPERTIES, TimeUnit.MILLISECONDS);\n            }\n        } catch (Throwable t) {\n            logger.warn(INTERNAL_ERROR, \"unknown error in registry module\", \"\", t.getMessage(), t);\n        }\n    }\n\n    @Override\n    public void destroy() {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Destroy registry:\" + getUrl());\n        }\n        Set<URL> destroyRegistered = new HashSet<>(getRegistered());\n        if (!destroyRegistered.isEmpty()) {\n            for (URL url : new HashSet<>(destroyRegistered)) {\n                if (url.getParameter(DYNAMIC_KEY, true)) {\n                    try {\n                        unregister(url);\n                        if (logger.isInfoEnabled()) {\n                            logger.info(\"Destroy unregister url \" + url);\n                        }\n                    } catch (Throwable t) {\n                        // 1-8: Failed to unregister / unsubscribe url on destroy.\n                        logger.warn(\n                                REGISTRY_FAILED_DESTROY_UNREGISTER_URL,\n                                \"\",\n                                \"\",\n                                \"Failed to unregister url \" + url + \" to registry \" + getUrl() + \" on destroy, cause: \"\n                                        + t.getMessage(),\n                                t);\n                    }\n                }\n            }\n        }\n        Map<URL, Set<NotifyListener>> destroySubscribed = new HashMap<>(getSubscribed());\n        if (!destroySubscribed.isEmpty()) {\n            for (Map.Entry<URL, Set<NotifyListener>> entry : destroySubscribed.entrySet()) {\n                URL url = entry.getKey();\n                for (NotifyListener listener : entry.getValue()) {\n                    try {\n                        unsubscribe(url, listener);\n                        if (logger.isInfoEnabled()) {\n                            logger.info(\"Destroy unsubscribe url \" + url);\n                        }\n                    } catch (Throwable t) {\n                        // 1-8: Failed to unregister / unsubscribe url on destroy.\n                        logger.warn(\n                                REGISTRY_FAILED_DESTROY_UNREGISTER_URL,\n                                \"\",\n                                \"\",\n                                \"Failed to unsubscribe url \" + url + \" to registry \" + getUrl() + \" on destroy, cause: \"\n                                        + t.getMessage(),\n                                t);\n                    }\n                }\n            }\n        }\n        registryManager.removeDestroyedRegistry(this);\n    }\n\n    protected boolean acceptable(URL urlToRegistry) {\n        String pattern = registryUrl.getParameter(ACCEPTS_KEY);\n        if (StringUtils.isEmpty(pattern)) {\n            return true;\n        }\n\n        String[] accepts = COMMA_SPLIT_PATTERN.split(pattern);\n\n        Set<String> allow =\n                Arrays.stream(accepts).filter(p -> !p.startsWith(\"-\")).collect(Collectors.toSet());\n        Set<String> disAllow = Arrays.stream(accepts)\n                .filter(p -> p.startsWith(\"-\"))\n                .map(p -> p.substring(1))\n                .collect(Collectors.toSet());\n\n        if (CollectionUtils.isNotEmpty(allow)) {\n            // allow first\n            return allow.contains(urlToRegistry.getProtocol());\n        } else if (CollectionUtils.isNotEmpty(disAllow)) {\n            // contains disAllow, deny\n            return !disAllow.contains(urlToRegistry.getProtocol());\n        } else {\n            // default allow\n            return true;\n        }\n    }\n\n    @Override\n    public String toString() {\n        return getUrl().toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\nimport org.apache.dubbo.registry.RegistryService;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_CREATE_INSTANCE;\nimport static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\n\n/**\n * AbstractRegistryFactory. (SPI, Singleton, ThreadSafe)\n *\n * @see org.apache.dubbo.registry.RegistryFactory\n */\npublic abstract class AbstractRegistryFactory implements RegistryFactory, ScopeModelAware {\n\n    private static final ErrorTypeAwareLogger LOGGER =\n            LoggerFactory.getErrorTypeAwareLogger(AbstractRegistryFactory.class);\n\n    private RegistryManager registryManager;\n    protected ApplicationModel applicationModel;\n\n    @Override\n    public void setApplicationModel(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        this.registryManager = applicationModel.getBeanFactory().getBean(RegistryManager.class);\n    }\n\n    @Override\n    public Registry getRegistry(URL url) {\n        if (registryManager == null) {\n            throw new IllegalStateException(\"Unable to fetch RegistryManager from ApplicationModel BeanFactory. \"\n                    + \"Please check if `setApplicationModel` has been override.\");\n        }\n\n        Registry defaultNopRegistry = registryManager.getDefaultNopRegistryIfDestroyed();\n        if (null != defaultNopRegistry) {\n            return defaultNopRegistry;\n        }\n\n        url = URLBuilder.from(url)\n                .setPath(RegistryService.class.getName())\n                .addParameter(INTERFACE_KEY, RegistryService.class.getName())\n                .removeParameter(TIMESTAMP_KEY)\n                .removeAttribute(EXPORT_KEY)\n                .removeAttribute(REFER_KEY)\n                .build();\n\n        String key = createRegistryCacheKey(url);\n        Registry registry = null;\n        boolean check = UrlUtils.isCheck(url);\n\n        // Lock the registry access process to ensure a single instance of the registry\n        registryManager.getRegistryLock().lock();\n        try {\n            // double check\n            // fix https://github.com/apache/dubbo/issues/7265.\n            defaultNopRegistry = registryManager.getDefaultNopRegistryIfDestroyed();\n            if (null != defaultNopRegistry) {\n                return defaultNopRegistry;\n            }\n\n            registry = registryManager.getRegistry(key);\n            if (registry != null) {\n                return registry;\n            }\n\n            // create registry by spi/ioc\n            registry = createRegistry(url);\n            if (check && registry == null) {\n                throw new IllegalStateException(\"Can not create registry \" + url);\n            }\n\n            if (registry != null) {\n                registryManager.putRegistry(key, registry);\n            }\n        } catch (Exception e) {\n            if (check) {\n                throw new RuntimeException(\"Can not create registry \" + url, e);\n            } else {\n                // 1-11 Failed to obtain or create registry (service) object.\n                LOGGER.warn(REGISTRY_FAILED_CREATE_INSTANCE, \"\", \"\", \"Failed to obtain or create registry \", e);\n            }\n        } finally {\n            // Release the lock\n            registryManager.getRegistryLock().unlock();\n        }\n\n        return registry;\n    }\n\n    /**\n     * Create the key for the registries cache.\n     * This method may be overridden by the sub-class.\n     *\n     * @param url the registration {@link URL url}\n     * @return non-null\n     */\n    protected String createRegistryCacheKey(URL url) {\n        return url.toServiceStringWithoutResolving();\n    }\n\n    protected abstract Registry createRegistry(URL url);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/CacheableFailbackRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.URLStrParser;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.url.component.DubboServiceAddressURL;\nimport org.apache.dubbo.common.url.component.ServiceAddressURL;\nimport org.apache.dubbo.common.url.component.URLAddress;\nimport org.apache.dubbo.common.url.component.URLParam;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.rpc.model.ScopeModel;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.URLStrParser.ENCODED_AND_MARK;\nimport static org.apache.dubbo.common.URLStrParser.ENCODED_PID_KEY;\nimport static org.apache.dubbo.common.URLStrParser.ENCODED_QUESTION_MARK;\nimport static org.apache.dubbo.common.URLStrParser.ENCODED_TIMESTAMP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.CACHE_CLEAR_TASK_INTERVAL;\nimport static org.apache.dubbo.common.constants.CommonConstants.CACHE_CLEAR_WAITING_THRESHOLD;\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_SEPARATOR_ENCODED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_PROPERTY_TYPE_MISMATCH;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_EMPTY_ADDRESS;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_CLEAR_CACHED_URLS;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_URL_EVICTING;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_NO_PARAMETERS_URL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_ENABLE_EMPTY_PROTECTION;\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;\n\n/**\n * <p>\n * Based on FailbackRegistry, it adds a URLAddress and URLParam cache to save RAM space.\n *\n * <p>\n * It's useful for registries whose sdk returns raw string as provider instance. For example, Zookeeper and etcd.\n *\n * @see org.apache.dubbo.registry.support.FailbackRegistry\n * @see org.apache.dubbo.registry.support.AbstractRegistry\n */\npublic abstract class CacheableFailbackRegistry extends FailbackRegistry {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(CacheableFailbackRegistry.class);\n\n    private static String[] VARIABLE_KEYS = new String[] {ENCODED_TIMESTAMP_KEY, ENCODED_PID_KEY};\n\n    protected ConcurrentMap<String, URLAddress> stringAddress = new ConcurrentHashMap<>();\n    protected ConcurrentMap<String, URLParam> stringParam = new ConcurrentHashMap<>();\n\n    private ScheduledExecutorService cacheRemovalScheduler;\n    private int cacheRemovalTaskIntervalInMillis;\n    private int cacheClearWaitingThresholdInMillis;\n\n    private Map<ServiceAddressURL, Long> waitForRemove = new ConcurrentHashMap<>();\n    private Semaphore semaphore = new Semaphore(1);\n\n    private final Map<String, String> extraParameters;\n    protected final Map<URL, Map<String, ServiceAddressURL>> stringUrls = new ConcurrentHashMap<>();\n\n    protected CacheableFailbackRegistry(URL url) {\n        super(url);\n        extraParameters = new HashMap<>(8);\n        extraParameters.put(CHECK_KEY, String.valueOf(false));\n\n        cacheRemovalScheduler = url.getOrDefaultFrameworkModel()\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .nextScheduledExecutor();\n        cacheRemovalTaskIntervalInMillis = getIntConfig(url.getScopeModel(), CACHE_CLEAR_TASK_INTERVAL, 2 * 60 * 1000);\n        cacheClearWaitingThresholdInMillis =\n                getIntConfig(url.getScopeModel(), CACHE_CLEAR_WAITING_THRESHOLD, 5 * 60 * 1000);\n    }\n\n    protected static int getIntConfig(ScopeModel scopeModel, String key, int def) {\n        String str = ConfigurationUtils.getProperty(scopeModel, key);\n        int result = def;\n        if (StringUtils.isNotEmpty(str)) {\n            try {\n                result = Integer.parseInt(str);\n            } catch (NumberFormatException e) {\n                // 0-2 Property type mismatch.\n\n                logger.warn(\n                        COMMON_PROPERTY_TYPE_MISMATCH,\n                        \"typo in property value\",\n                        \"This property requires an integer value.\",\n                        \"Invalid registry properties configuration key \" + key + \", value \" + str);\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public void doUnsubscribe(URL url, NotifyListener listener) {\n        this.evictURLCache(url);\n    }\n\n    protected void evictURLCache(URL url) {\n        Map<String, ServiceAddressURL> oldURLs = stringUrls.remove(url);\n        try {\n            if (CollectionUtils.isNotEmptyMap(oldURLs)) {\n                logger.info(\"Evicting urls for service \" + url.getServiceKey() + \", size \" + oldURLs.size());\n                Long currentTimestamp = System.currentTimeMillis();\n                for (Map.Entry<String, ServiceAddressURL> entry : oldURLs.entrySet()) {\n                    waitForRemove.put(entry.getValue(), currentTimestamp);\n                }\n                if (CollectionUtils.isNotEmptyMap(waitForRemove)) {\n                    if (semaphore.tryAcquire()) {\n                        cacheRemovalScheduler.schedule(\n                                new RemovalTask(), cacheRemovalTaskIntervalInMillis, TimeUnit.MILLISECONDS);\n                    }\n                }\n            }\n        } catch (Exception e) {\n            // It seems that the most possible statement that causes exception is the 'schedule()' method.\n\n            // The executor that FrameworkExecutorRepository.nextScheduledExecutor() method returns\n            // is made by Executors.newSingleThreadScheduledExecutor().\n\n            // After observing the code of ScheduledThreadPoolExecutor.delayedExecute,\n            // it seems that it only throws RejectedExecutionException when the thread pool is shutdown.\n\n            // When? FrameworkExecutorRepository gets destroyed.\n\n            // 1-3: URL evicting failed.\n            logger.warn(\n                    REGISTRY_FAILED_URL_EVICTING,\n                    \"thread pool getting destroyed\",\n                    \"\",\n                    \"Failed to evict url for \" + url.getServiceKey(),\n                    e);\n        }\n    }\n\n    protected List<URL> toUrlsWithoutEmpty(URL consumer, Collection<String> providers) {\n        // keep old urls\n        Map<String, ServiceAddressURL> oldURLs = stringUrls.get(consumer);\n\n        // create new urls\n        // The key of newURLs is the normalized rawProvider (variable keys removed for deduplication),\n        // but the cached ServiceAddressURL is built from the original rawProvider (with all parameters preserved).\n        Map<String, ServiceAddressURL> newURLs = new HashMap<>((int) (providers.size() / 0.75f + 1));\n\n        // remove 'release', 'dubbo', 'methods', timestamp, 'dubbo.tag' parameter\n        // in consumer URL.\n        URL copyOfConsumer = removeParamsFromConsumer(consumer);\n\n        if (oldURLs == null) {\n            for (String rawProvider : providers) {\n                // Normalize the rawProvider by removing VARIABLE_KEYS(timestamp, pid..) for deduplication purposes.\n                // The normalized key is used to avoid duplicate instances of the same provider.\n                String normalizedKey = stripOffVariableKeys(rawProvider);\n\n                // Create DubboServiceAddress object using the ORIGINAL rawProvider (with all parameters intact),\n                // so that timestamp and other parameters are preserved for correct parameter parsing.\n                // This ensures that when multiple providers normalize to the same key (e.g., different timestamps),\n                // the latest one's timestamp will be used.\n                ServiceAddressURL cachedURL = createURL(rawProvider, copyOfConsumer, getExtraParameters());\n                if (cachedURL == null) {\n                    continue;\n                }\n\n                // Use normalized key for deduplication: if multiple providers normalize to the same key,\n                // the last one (with the latest timestamp) will be kept.\n                newURLs.put(normalizedKey, cachedURL);\n            }\n        } else {\n            // Reuse or create URLs based on both normalized key and original rawProvider.\n            // The normalized key is used to find potential cache entries for reuse (deduplication),\n            // but we always create a new ServiceAddressURL from the original rawProvider to ensure\n            // the timestamp and other parameters are up-to-date.\n            for (String rawProvider : providers) {\n                // Normalize the rawProvider for cache key matching and deduplication.\n                String normalizedKey = stripOffVariableKeys(rawProvider);\n                ServiceAddressURL cachedURL = oldURLs.remove(normalizedKey);\n                if (cachedURL == null) {\n                    // Create new URL using the original rawProvider (all parameters preserved including timestamp).\n                    cachedURL = createURL(rawProvider, copyOfConsumer, getExtraParameters());\n                    if (cachedURL == null) {\n                        continue;\n                    }\n                }\n                // Use normalized key for storage: if multiple providers normalize to the same key,\n                // the last one will be kept, ensuring no duplicate instances with outdated timestamps.\n                newURLs.put(normalizedKey, cachedURL);\n            }\n        }\n\n        evictURLCache(consumer);\n        stringUrls.put(consumer, newURLs);\n\n        return new ArrayList<>(newURLs.values());\n    }\n\n    protected List<URL> toUrlsWithEmpty(URL consumer, String path, Collection<String> providers) {\n        List<URL> urls = new ArrayList<>(1);\n        boolean isProviderPath = path.endsWith(PROVIDERS_CATEGORY);\n\n        if (isProviderPath) {\n            if (CollectionUtils.isNotEmpty(providers)) {\n                urls = toUrlsWithoutEmpty(consumer, providers);\n            } else {\n                // clear cache on empty notification: unsubscribe or provider offline\n                evictURLCache(consumer);\n            }\n        } else {\n            if (CollectionUtils.isNotEmpty(providers)) {\n                urls = toConfiguratorsWithoutEmpty(consumer, providers);\n            }\n        }\n\n        if (urls.isEmpty()) {\n            int i = path.lastIndexOf(PATH_SEPARATOR);\n            String category = i < 0 ? path : path.substring(i + 1);\n            if (!PROVIDERS_CATEGORY.equals(category)\n                    || !getUrl().getParameter(ENABLE_EMPTY_PROTECTION_KEY, DEFAULT_ENABLE_EMPTY_PROTECTION)) {\n                if (PROVIDERS_CATEGORY.equals(category)) {\n                    logger.warn(\n                            REGISTRY_EMPTY_ADDRESS,\n                            \"\",\n                            \"\",\n                            \"Service \" + consumer.getServiceKey()\n                                    + \" received empty address list and empty protection is disabled, will clear current available addresses\");\n                }\n                URL empty = URLBuilder.from(consumer)\n                        .setProtocol(EMPTY_PROTOCOL)\n                        .addParameter(CATEGORY_KEY, category)\n                        .build();\n                urls.add(empty);\n            }\n        }\n\n        return urls;\n    }\n\n    /**\n     * Create DubboServiceAddress object using provider url, consumer url, and extra parameters.\n     *\n     * @param rawProvider     provider url string\n     * @param consumerURL     URL object of consumer\n     * @param extraParameters extra parameters\n     * @return created DubboServiceAddressURL object\n     */\n    protected ServiceAddressURL createURL(String rawProvider, URL consumerURL, Map<String, String> extraParameters) {\n\n        boolean encoded = true;\n\n        // use encoded value directly to avoid URLDecoder.decode allocation.\n        int paramStartIdx = rawProvider.indexOf(ENCODED_QUESTION_MARK);\n\n        if (paramStartIdx == -1) {\n            // if ENCODED_QUESTION_MARK does not show, mark as not encoded.\n            encoded = false;\n        }\n\n        // split by (encoded) question mark.\n        // part[0] => protocol + ip address + interface.\n        // part[1] => parameters (metadata).\n        String[] parts = URLStrParser.parseRawURLToArrays(rawProvider, paramStartIdx);\n\n        if (parts.length <= 1) {\n            // 1-5 Received URL without any parameters.\n            logger.warn(REGISTRY_NO_PARAMETERS_URL, \"\", \"\", \"Received url without any parameters \" + rawProvider);\n\n            return DubboServiceAddressURL.valueOf(rawProvider, consumerURL);\n        }\n\n        String rawAddress = parts[0];\n        String rawParams = parts[1];\n\n        // Workaround for 'effectively final': duplicate the encoded variable.\n        boolean isEncoded = encoded;\n\n        // PathURLAddress if it's using dubbo protocol.\n        URLAddress address = ConcurrentHashMapUtils.computeIfAbsent(\n                stringAddress, rawAddress, k -> URLAddress.parse(k, getDefaultURLProtocol(), isEncoded));\n        address.setTimestamp(System.currentTimeMillis());\n\n        URLParam param = ConcurrentHashMapUtils.computeIfAbsent(\n                stringParam, rawParams, k -> URLParam.parse(k, isEncoded, extraParameters));\n        param.setTimestamp(System.currentTimeMillis());\n\n        // create service URL using cached address, param, and consumer URL.\n        ServiceAddressURL cachedServiceAddressURL = createServiceURL(address, param, consumerURL);\n\n        if (isMatch(consumerURL, cachedServiceAddressURL)) {\n            return cachedServiceAddressURL;\n        }\n\n        return null;\n    }\n\n    protected ServiceAddressURL createServiceURL(URLAddress address, URLParam param, URL consumerURL) {\n        return new DubboServiceAddressURL(address, param, consumerURL, null);\n    }\n\n    private String stripOffVariableKeys(String rawProvider) {\n        String[] keys = getVariableKeys();\n        if (keys == null || keys.length == 0) {\n            return rawProvider;\n        }\n\n        int encodedIdx = rawProvider.indexOf(ENCODED_QUESTION_MARK);\n        int plainIdx = rawProvider.indexOf('?');\n        boolean encoded;\n        int questionIdx;\n        if (encodedIdx >= 0 && (plainIdx < 0 || encodedIdx < plainIdx)) {\n            encoded = true;\n            questionIdx = encodedIdx;\n        } else if (plainIdx >= 0) {\n            encoded = false;\n            questionIdx = plainIdx;\n        } else {\n            return rawProvider;\n        }\n\n        String prefix = rawProvider.substring(0, questionIdx);\n        String params = rawProvider.substring(questionIdx + (encoded ? ENCODED_QUESTION_MARK.length() : 1));\n        if (params.isEmpty()) {\n            return rawProvider;\n        }\n\n        String andMark = encoded ? ENCODED_AND_MARK : \"&\";\n        String eqMark = encoded ? \"%3D\" : \"=\";\n\n        // Build a set of normalized variable names for efficient matching.\n        HashSet<String> variableNames = new HashSet<>(keys.length);\n        for (String key : keys) {\n            if (key != null) {\n                variableNames.add(normalizeVariableName(key));\n            }\n        }\n\n        List<String> remaining = new ArrayList<>();\n        boolean removed = false;\n        for (String param : params.split(andMark)) {\n            if (param.isEmpty()) {\n                continue;\n            }\n            int eqIdx = param.indexOf(eqMark);\n            if (eqIdx < 0) {\n                remaining.add(param);\n                continue;\n            }\n            String name = param.substring(0, eqIdx);\n            String normalizedName = normalizeVariableName(name);\n\n            // Check if this parameter name exactly matches a variable key that should be removed.\n            // Only exact match is performed (e.g., \"timestamp\" matches \"timestamp\", but not \"remote.timestamp\").\n            if (variableNames.contains(normalizedName)) {\n                removed = true;\n                continue;\n            }\n            remaining.add(param);\n        }\n\n        if (!removed) {\n            return rawProvider;\n        }\n        if (remaining.isEmpty()) {\n            return prefix;\n        }\n\n        return prefix + (encoded ? ENCODED_QUESTION_MARK : \"?\") + String.join(andMark, remaining);\n    }\n\n    private String normalizeVariableName(String key) {\n        if (key == null) {\n            return null;\n        }\n        if (key.endsWith(\"%3D\")) {\n            return key.substring(0, key.length() - 3);\n        }\n        if (key.endsWith(\"=\")) {\n            return key.substring(0, key.length() - 1);\n        }\n        return key;\n    }\n\n    private List<URL> toConfiguratorsWithoutEmpty(URL consumer, Collection<String> configurators) {\n        List<URL> urls = new ArrayList<>();\n        if (CollectionUtils.isNotEmpty(configurators)) {\n            for (String provider : configurators) {\n                if (provider.contains(PROTOCOL_SEPARATOR_ENCODED)) {\n                    URL url = URLStrParser.parseEncodedStr(provider);\n                    if (UrlUtils.isMatch(consumer, url)) {\n                        urls.add(url);\n                    }\n                }\n            }\n        }\n        return urls;\n    }\n\n    protected Map<String, String> getExtraParameters() {\n        return extraParameters;\n    }\n\n    protected String[] getVariableKeys() {\n        return VARIABLE_KEYS;\n    }\n\n    protected String getDefaultURLProtocol() {\n        return DUBBO;\n    }\n\n    /**\n     * This method is for unit test to see if the RemovalTask has completed or not.<br />\n     * <strong>Please do not call this method in other places.</strong>\n     */\n    @Deprecated\n    protected Semaphore getSemaphore() {\n        return semaphore;\n    }\n\n    protected abstract boolean isMatch(URL subscribeUrl, URL providerUrl);\n\n    /**\n     * The cached URL removal task, which will be run on a scheduled thread pool. (It will be run after a delay.)\n     */\n    private class RemovalTask implements Runnable {\n        @Override\n        public void run() {\n            logger.info(\"Clearing cached URLs, waiting to clear size \" + waitForRemove.size());\n            int clearCount = 0;\n            try {\n                Iterator<Map.Entry<ServiceAddressURL, Long>> it =\n                        waitForRemove.entrySet().iterator();\n                while (it.hasNext()) {\n                    Map.Entry<ServiceAddressURL, Long> entry = it.next();\n                    ServiceAddressURL removeURL = entry.getKey();\n                    long removeTime = entry.getValue();\n                    long current = System.currentTimeMillis();\n                    if (current - removeTime >= cacheClearWaitingThresholdInMillis) {\n                        URLAddress urlAddress = removeURL.getUrlAddress();\n                        URLParam urlParam = removeURL.getUrlParam();\n                        if (current - urlAddress.getTimestamp() >= cacheClearWaitingThresholdInMillis) {\n                            stringAddress.remove(urlAddress.getRawAddress());\n                        }\n                        if (current - urlParam.getTimestamp() >= cacheClearWaitingThresholdInMillis) {\n                            stringParam.remove(urlParam.getRawParam());\n                        }\n                        it.remove();\n                        clearCount++;\n                    }\n                }\n            } catch (Throwable t) {\n                // 1-6 Error when clearing cached URLs.\n\n                logger.error(REGISTRY_FAILED_CLEAR_CACHED_URLS, \"\", \"\", \"Error occurred when clearing cached URLs\", t);\n\n            } finally {\n                semaphore.release();\n            }\n            logger.info(\"Clear cached URLs, size \" + clearCount);\n\n            if (CollectionUtils.isNotEmptyMap(waitForRemove)) {\n                // move to next schedule\n                if (semaphore.tryAcquire()) {\n                    cacheRemovalScheduler.schedule(\n                            new RemovalTask(), cacheRemovalTaskIntervalInMillis, TimeUnit.MILLISECONDS);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/DefaultProviderFirstParams.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\nimport org.apache.dubbo.registry.ProviderFirstParams;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;\n\npublic class DefaultProviderFirstParams implements ProviderFirstParams {\n    private static final Set<String> PARAMS = Collections.unmodifiableSet(new HashSet<String>() {\n        {\n            addAll(Arrays.asList(RELEASE_KEY, DUBBO_VERSION_KEY, METHODS_KEY, TIMESTAMP_KEY, TAG_KEY));\n        }\n    });\n\n    @Override\n    public Set<String> params() {\n        return PARAMS;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/FailbackRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.ProviderFirstParams;\nimport org.apache.dubbo.registry.retry.FailedRegisteredTask;\nimport org.apache.dubbo.registry.retry.FailedSubscribedTask;\nimport org.apache.dubbo.registry.retry.FailedUnregisteredTask;\nimport org.apache.dubbo.registry.retry.FailedUnsubscribedTask;\nimport org.apache.dubbo.remoting.Constants;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.IS_EXTRA;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_NOTIFY_EVENT;\nimport static org.apache.dubbo.registry.Constants.DEFAULT_REGISTRY_RETRY_PERIOD;\nimport static org.apache.dubbo.registry.Constants.REGISTRY_RETRY_PERIOD_KEY;\n\n/**\n * A template implementation of registry service that provides auto-retry ability.\n * (SPI, Prototype, ThreadSafe)\n */\npublic abstract class FailbackRegistry extends AbstractRegistry {\n\n    /*  retry task map */\n\n    private final ConcurrentMap<URL, FailedRegisteredTask> failedRegistered = new ConcurrentHashMap<>();\n\n    private final ConcurrentMap<URL, FailedUnregisteredTask> failedUnregistered = new ConcurrentHashMap<>();\n\n    private final ConcurrentMap<Holder, FailedSubscribedTask> failedSubscribed = new ConcurrentHashMap<>();\n\n    private final ConcurrentMap<Holder, FailedUnsubscribedTask> failedUnsubscribed = new ConcurrentHashMap<>();\n\n    /**\n     * The time in milliseconds the retryExecutor will wait\n     */\n    private final int retryPeriod;\n\n    // Timer for failure retry, regular check if there is a request for failure, and if there is, an unlimited retry\n    private final HashedWheelTimer retryTimer;\n\n    public FailbackRegistry(URL url) {\n        super(url);\n        this.retryPeriod = url.getParameter(REGISTRY_RETRY_PERIOD_KEY, DEFAULT_REGISTRY_RETRY_PERIOD);\n\n        // since the retry task will not be very much. 128 ticks is enough.\n        retryTimer = new HashedWheelTimer(\n                new NamedThreadFactory(\"DubboRegistryRetryTimer\", true), retryPeriod, TimeUnit.MILLISECONDS, 128);\n    }\n\n    public void removeFailedRegisteredTask(URL url) {\n        failedRegistered.remove(url);\n    }\n\n    public void removeFailedUnregisteredTask(URL url) {\n        failedUnregistered.remove(url);\n    }\n\n    public void removeFailedSubscribedTask(URL url, NotifyListener listener) {\n        Holder h = new Holder(url, listener);\n        failedSubscribed.remove(h);\n    }\n\n    public void removeFailedUnsubscribedTask(URL url, NotifyListener listener) {\n        Holder h = new Holder(url, listener);\n        failedUnsubscribed.remove(h);\n    }\n\n    private void addFailedRegistered(URL url) {\n        FailedRegisteredTask oldOne = failedRegistered.get(url);\n        if (oldOne != null) {\n            return;\n        }\n        FailedRegisteredTask newTask = new FailedRegisteredTask(url, this);\n        oldOne = failedRegistered.putIfAbsent(url, newTask);\n        if (oldOne == null) {\n            // never has a retry task. then start a new task for retry.\n            retryTimer.newTimeout(newTask, retryPeriod, TimeUnit.MILLISECONDS);\n        }\n    }\n\n    private void removeFailedRegistered(URL url) {\n        FailedRegisteredTask f = failedRegistered.remove(url);\n        if (f != null) {\n            f.cancel();\n        }\n    }\n\n    private void addFailedUnregistered(URL url) {\n        FailedUnregisteredTask oldOne = failedUnregistered.get(url);\n        if (oldOne != null) {\n            return;\n        }\n        FailedUnregisteredTask newTask = new FailedUnregisteredTask(url, this);\n        oldOne = failedUnregistered.putIfAbsent(url, newTask);\n        if (oldOne == null) {\n            // never has a retry task. then start a new task for retry.\n            retryTimer.newTimeout(newTask, retryPeriod, TimeUnit.MILLISECONDS);\n        }\n    }\n\n    private void removeFailedUnregistered(URL url) {\n        FailedUnregisteredTask f = failedUnregistered.remove(url);\n        if (f != null) {\n            f.cancel();\n        }\n    }\n\n    protected void addFailedSubscribed(URL url, NotifyListener listener) {\n        Holder h = new Holder(url, listener);\n        FailedSubscribedTask oldOne = failedSubscribed.get(h);\n        if (oldOne != null) {\n            return;\n        }\n        FailedSubscribedTask newTask = new FailedSubscribedTask(url, this, listener);\n        oldOne = failedSubscribed.putIfAbsent(h, newTask);\n        if (oldOne == null) {\n            // never has a retry task. then start a new task for retry.\n            retryTimer.newTimeout(newTask, retryPeriod, TimeUnit.MILLISECONDS);\n        }\n    }\n\n    public void removeFailedSubscribed(URL url, NotifyListener listener) {\n        Holder h = new Holder(url, listener);\n        FailedSubscribedTask f = failedSubscribed.remove(h);\n        if (f != null) {\n            f.cancel();\n        }\n        removeFailedUnsubscribed(url, listener);\n    }\n\n    private void addFailedUnsubscribed(URL url, NotifyListener listener) {\n        Holder h = new Holder(url, listener);\n        FailedUnsubscribedTask oldOne = failedUnsubscribed.get(h);\n        if (oldOne != null) {\n            return;\n        }\n        FailedUnsubscribedTask newTask = new FailedUnsubscribedTask(url, this, listener);\n        oldOne = failedUnsubscribed.putIfAbsent(h, newTask);\n        if (oldOne == null) {\n            // never has a retry task. then start a new task for retry.\n            retryTimer.newTimeout(newTask, retryPeriod, TimeUnit.MILLISECONDS);\n        }\n    }\n\n    private void removeFailedUnsubscribed(URL url, NotifyListener listener) {\n        Holder h = new Holder(url, listener);\n        FailedUnsubscribedTask f = failedUnsubscribed.remove(h);\n        if (f != null) {\n            f.cancel();\n        }\n    }\n\n    protected URL removeParamsFromConsumer(URL consumer) {\n        Set<ProviderFirstParams> providerFirstParams = consumer.getOrDefaultApplicationModel()\n                .getExtensionLoader(ProviderFirstParams.class)\n                .getSupportedExtensionInstances();\n        if (CollectionUtils.isEmpty(providerFirstParams)) {\n            return consumer;\n        }\n\n        for (ProviderFirstParams paramsFilter : providerFirstParams) {\n            consumer = consumer.removeParameters(paramsFilter.params());\n        }\n        return consumer;\n    }\n\n    ConcurrentMap<URL, FailedRegisteredTask> getFailedRegistered() {\n        return failedRegistered;\n    }\n\n    ConcurrentMap<URL, FailedUnregisteredTask> getFailedUnregistered() {\n        return failedUnregistered;\n    }\n\n    ConcurrentMap<Holder, FailedSubscribedTask> getFailedSubscribed() {\n        return failedSubscribed;\n    }\n\n    ConcurrentMap<Holder, FailedUnsubscribedTask> getFailedUnsubscribed() {\n        return failedUnsubscribed;\n    }\n\n    @Override\n    public void register(URL url) {\n        if (!shouldRegister(url)) {\n            return;\n        }\n        super.register(url);\n        removeFailedRegistered(url);\n        removeFailedUnregistered(url);\n        try {\n            // Sending a registration request to the server side\n            doRegister(url);\n        } catch (Exception e) {\n            Throwable t = e;\n\n            // If the startup detection is opened, the Exception is thrown directly.\n            boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)\n                    && url.getParameter(Constants.CHECK_KEY, true)\n                    && (url.getPort() != 0);\n            boolean skipFailback = t instanceof SkipFailbackWrapperException;\n            if (check || skipFailback) {\n                if (skipFailback) {\n                    t = t.getCause();\n                }\n                throw new IllegalStateException(\n                        \"Failed to register \" + url + \" to registry \" + getUrl().getAddress() + \", cause: \"\n                                + t.getMessage(),\n                        t);\n            } else {\n                logger.error(\n                        INTERNAL_ERROR,\n                        \"unknown error in registry module\",\n                        \"\",\n                        \"Failed to register \" + url + \", waiting for retry, cause: \" + t.getMessage(),\n                        t);\n            }\n\n            // Record a failed registration request to a failed list, retry regularly\n            addFailedRegistered(url);\n        }\n    }\n\n    protected boolean shouldRegister(URL providerURL) {\n        // extra protocol url must not be registered for interface based service discovery\n        if (providerURL.getParameter(IS_EXTRA, false)) {\n            return false;\n        }\n        if (!acceptable(providerURL)) {\n            logger.info(\"URL \" + providerURL + \" will not be registered to Registry. Registry \" + this.getUrl()\n                    + \" does not accept service of this protocol type.\");\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public void reExportRegister(URL url) {\n        if (!acceptable(url)) {\n            logger.info(\"URL \" + url + \" will not be registered to Registry. Registry \" + url\n                    + \" does not accept service of this protocol type.\");\n            return;\n        }\n        super.register(url);\n        removeFailedRegistered(url);\n        removeFailedUnregistered(url);\n        try {\n            // Sending a registration request to the server side\n            doRegister(url);\n        } catch (Exception e) {\n            if (!(e instanceof SkipFailbackWrapperException)) {\n                throw new IllegalStateException(\n                        \"Failed to register (re-export) \" + url + \" to registry \" + getUrl().getAddress() + \", cause: \"\n                                + e.getMessage(),\n                        e);\n            }\n        }\n    }\n\n    @Override\n    public void unregister(URL url) {\n        super.unregister(url);\n        removeFailedRegistered(url);\n        removeFailedUnregistered(url);\n        try {\n            // Sending a cancellation request to the server side\n            doUnregister(url);\n        } catch (Exception e) {\n            Throwable t = e;\n\n            // If the startup detection is opened, the Exception is thrown directly.\n            boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)\n                    && url.getParameter(Constants.CHECK_KEY, true)\n                    && (url.getPort() != 0);\n            boolean skipFailback = t instanceof SkipFailbackWrapperException;\n            if (check || skipFailback) {\n                if (skipFailback) {\n                    t = t.getCause();\n                }\n                throw new IllegalStateException(\n                        \"Failed to unregister \" + url + \" to registry \" + getUrl().getAddress() + \", cause: \"\n                                + t.getMessage(),\n                        t);\n            } else {\n                logger.error(\n                        INTERNAL_ERROR,\n                        \"unknown error in registry module\",\n                        \"\",\n                        \"Failed to unregister \" + url + \", waiting for retry, cause: \" + t.getMessage(),\n                        t);\n            }\n\n            // Record a failed registration request to a failed list, retry regularly\n            addFailedUnregistered(url);\n        }\n    }\n\n    @Override\n    public void reExportUnregister(URL url) {\n        super.unregister(url);\n        removeFailedRegistered(url);\n        removeFailedUnregistered(url);\n        try {\n            // Sending a cancellation request to the server side\n            doUnregister(url);\n        } catch (Exception e) {\n            if (!(e instanceof SkipFailbackWrapperException)) {\n                throw new IllegalStateException(\n                        \"Failed to unregister(re-export) \" + url + \" to registry \" + getUrl().getAddress() + \", cause: \"\n                                + e.getMessage(),\n                        e);\n            }\n        }\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        super.subscribe(url, listener);\n        removeFailedSubscribed(url, listener);\n        try {\n            // Sending a subscription request to the server side\n            doSubscribe(url, listener);\n        } catch (Exception e) {\n            Throwable t = e;\n\n            List<URL> urls = getCacheUrls(url);\n            if (CollectionUtils.isNotEmpty(urls)) {\n                notify(url, listener, urls);\n                logger.error(\n                        REGISTRY_FAILED_NOTIFY_EVENT,\n                        \"\",\n                        \"\",\n                        \"Failed to subscribe \" + url + \", Using cached list: \" + urls + \" from cache file: \"\n                                + getCacheFile().getName() + \", cause: \" + t.getMessage(),\n                        t);\n            } else {\n                // If the startup detection is opened, the Exception is thrown directly.\n                boolean check =\n                        getUrl().getParameter(Constants.CHECK_KEY, true) && url.getParameter(Constants.CHECK_KEY, true);\n                boolean skipFailback = t instanceof SkipFailbackWrapperException;\n                if (check || skipFailback) {\n                    if (skipFailback) {\n                        t = t.getCause();\n                    }\n                    throw new IllegalStateException(\"Failed to subscribe \" + url + \", cause: \" + t.getMessage(), t);\n                } else {\n                    logger.error(\n                            REGISTRY_FAILED_NOTIFY_EVENT,\n                            \"\",\n                            \"\",\n                            \"Failed to subscribe \" + url + \", waiting for retry, cause: \" + t.getMessage(),\n                            t);\n                }\n            }\n\n            // Record a failed registration request to a failed list, retry regularly\n            addFailedSubscribed(url, listener);\n        }\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        super.unsubscribe(url, listener);\n        removeFailedSubscribed(url, listener);\n        try {\n            // Sending a canceling subscription request to the server side\n            doUnsubscribe(url, listener);\n        } catch (Exception e) {\n            Throwable t = e;\n\n            // If the startup detection is opened, the Exception is thrown directly.\n            boolean check =\n                    getUrl().getParameter(Constants.CHECK_KEY, true) && url.getParameter(Constants.CHECK_KEY, true);\n            boolean skipFailback = t instanceof SkipFailbackWrapperException;\n            if (check || skipFailback) {\n                if (skipFailback) {\n                    t = t.getCause();\n                }\n                throw new IllegalStateException(\n                        \"Failed to unsubscribe \" + url + \" to registry \" + getUrl().getAddress() + \", cause: \"\n                                + t.getMessage(),\n                        t);\n            } else {\n                logger.error(\n                        REGISTRY_FAILED_NOTIFY_EVENT,\n                        \"\",\n                        \"\",\n                        \"Failed to unsubscribe \" + url + \", waiting for retry, cause: \" + t.getMessage(),\n                        t);\n            }\n\n            // Record a failed registration request to a failed list, retry regularly\n            addFailedUnsubscribed(url, listener);\n        }\n    }\n\n    @Override\n    protected void notify(URL url, NotifyListener listener, List<URL> urls) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"notify url == null\");\n        }\n        if (listener == null) {\n            throw new IllegalArgumentException(\"notify listener == null\");\n        }\n        try {\n            doNotify(url, listener, urls);\n        } catch (Exception t) {\n            // Record a failed registration request to a failed list\n            logger.error(\n                    REGISTRY_FAILED_NOTIFY_EVENT,\n                    \"\",\n                    \"\",\n                    \"Failed to notify addresses for subscribe \" + url + \", cause: \" + t.getMessage(),\n                    t);\n        }\n    }\n\n    protected void doNotify(URL url, NotifyListener listener, List<URL> urls) {\n        super.notify(url, listener, urls);\n    }\n\n    @Override\n    protected void recover() throws Exception {\n        // register\n        Set<URL> recoverRegistered = new HashSet<>(getRegistered());\n        if (!recoverRegistered.isEmpty()) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"Recover register url \" + recoverRegistered);\n            }\n            for (URL url : recoverRegistered) {\n                // remove fail registry or unRegistry task first.\n                removeFailedRegistered(url);\n                removeFailedUnregistered(url);\n                addFailedRegistered(url);\n            }\n        }\n        // subscribe\n        Map<URL, Set<NotifyListener>> recoverSubscribed = new HashMap<>(getSubscribed());\n        if (!recoverSubscribed.isEmpty()) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"Recover subscribe url \" + recoverSubscribed.keySet());\n            }\n            for (Map.Entry<URL, Set<NotifyListener>> entry : recoverSubscribed.entrySet()) {\n                URL url = entry.getKey();\n                for (NotifyListener listener : entry.getValue()) {\n                    // First remove other tasks to ensure that addFailedSubscribed can succeed.\n                    removeFailedSubscribed(url, listener);\n                    addFailedSubscribed(url, listener);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n        retryTimer.stop();\n    }\n\n    // ==== Template method ====\n\n    public abstract void doRegister(URL url);\n\n    public abstract void doUnregister(URL url);\n\n    public abstract void doSubscribe(URL url, NotifyListener listener);\n\n    public abstract void doUnsubscribe(URL url, NotifyListener listener);\n\n    static class Holder {\n\n        private final URL url;\n\n        private final NotifyListener notifyListener;\n\n        Holder(URL url, NotifyListener notifyListener) {\n            if (url == null || notifyListener == null) {\n                throw new IllegalArgumentException();\n            }\n            this.url = url;\n            this.notifyListener = notifyListener;\n        }\n\n        @Override\n        public int hashCode() {\n            return url.hashCode() + notifyListener.hashCode();\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (obj instanceof Holder) {\n                Holder h = (Holder) obj;\n                return this.url.equals(h.url) && this.notifyListener.equals(h.notifyListener);\n            } else {\n                return false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/RegistryManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceDiscoveryRegistry;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_FETCH_INSTANCE;\n\n/**\n * Application Level, used to collect Registries\n */\npublic class RegistryManager {\n    private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(RegistryManager.class);\n\n    private ApplicationModel applicationModel;\n\n    /**\n     * Registry Collection Map<RegistryAddress, Registry>\n     */\n    private final Map<String, Registry> registries = new ConcurrentHashMap<>();\n\n    /**\n     * The lock for the acquisition process of the registry\n     */\n    protected final ReentrantLock lock = new ReentrantLock();\n\n    private final AtomicBoolean destroyed = new AtomicBoolean(false);\n\n    public RegistryManager(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n    }\n\n    /**\n     * Get all registries\n     *\n     * @return all registries\n     */\n    public Collection<Registry> getRegistries() {\n        return Collections.unmodifiableCollection(new LinkedList<>(registries.values()));\n    }\n\n    public Registry getRegistry(String key) {\n        return registries.get(key);\n    }\n\n    public void putRegistry(String key, Registry registry) {\n        registries.put(key, registry);\n    }\n\n    public List<ServiceDiscovery> getServiceDiscoveries() {\n        return getRegistries().stream()\n                .filter(registry -> registry instanceof ServiceDiscoveryRegistry)\n                .map(registry -> (ServiceDiscoveryRegistry) registry)\n                .map(ServiceDiscoveryRegistry::getServiceDiscovery)\n                .collect(Collectors.toList());\n    }\n\n    /**\n     * Close all created registries\n     */\n    public void destroyAll() {\n        if (!destroyed.compareAndSet(false, true)) {\n            return;\n        }\n\n        if (LOGGER.isInfoEnabled()) {\n            LOGGER.info(\"Close all registries \" + getRegistries());\n        }\n        // Lock up the registry shutdown process\n        lock.lock();\n        try {\n            for (Registry registry : getRegistries()) {\n                try {\n                    registry.destroy();\n                } catch (Throwable e) {\n                    LOGGER.warn(INTERNAL_ERROR, \"unknown error in registry module\", \"\", e.getMessage(), e);\n                }\n            }\n            registries.clear();\n        } finally {\n            // Release the lock\n            lock.unlock();\n        }\n    }\n\n    /**\n     * Reset state of AbstractRegistryFactory\n     */\n    public void reset() {\n        destroyed.set(false);\n        registries.clear();\n    }\n\n    protected Registry getDefaultNopRegistryIfDestroyed() {\n        if (destroyed.get()) {\n            // 1-12 Failed to fetch (server) instance since the registry instances have been destroyed.\n            LOGGER.warn(\n                    REGISTRY_FAILED_FETCH_INSTANCE,\n                    \"misuse of the methods\",\n                    \"\",\n                    \"All registry instances have been destroyed, failed to fetch any instance. \"\n                            + \"Usually, this means no need to try to do unnecessary redundant resource clearance, all registries has been taken care of.\");\n\n            return DEFAULT_NOP_REGISTRY;\n        }\n        return null;\n    }\n\n    protected Lock getRegistryLock() {\n        return lock;\n    }\n\n    public void removeDestroyedRegistry(Registry toRm) {\n        lock.lock();\n        try {\n            registries.entrySet().removeIf(entry -> entry.getValue().equals(toRm));\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    // for unit test\n    public void clearRegistryNotDestroy() {\n        registries.clear();\n    }\n\n    public static RegistryManager getInstance(ApplicationModel applicationModel) {\n        return applicationModel.getBeanFactory().getBean(RegistryManager.class);\n    }\n\n    private static final Registry DEFAULT_NOP_REGISTRY = new Registry() {\n        @Override\n        public URL getUrl() {\n            return null;\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return false;\n        }\n\n        @Override\n        public void destroy() {}\n\n        @Override\n        public void register(URL url) {}\n\n        @Override\n        public void unregister(URL url) {}\n\n        @Override\n        public void subscribe(URL url, NotifyListener listener) {}\n\n        @Override\n        public void unsubscribe(URL url, NotifyListener listener) {}\n\n        @Override\n        public List<URL> lookup(URL url) {\n            return null;\n        }\n    };\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/SkipFailbackWrapperException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\n/**\n * Wrapper Exception, it is used to indicate that {@link FailbackRegistry} skips Failback.\n * <p>\n * NOTE: Expect to find other more conventional ways of instruction.\n *\n * @see FailbackRegistry\n */\npublic class SkipFailbackWrapperException extends RuntimeException {\n    public SkipFailbackWrapperException(Throwable cause) {\n        super(cause);\n    }\n\n    @Override\n    public synchronized Throwable fillInStackTrace() {\n        // do nothing\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar",
    "content": "registry=org.apache.dubbo.registry.aot.RegistryReflectionTypeDescriberRegistrar\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.status.StatusChecker",
    "content": "registry=org.apache.dubbo.registry.status.RegistryStatusChecker"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping",
    "content": "metadata=org.apache.dubbo.registry.client.metadata.MetadataServiceNameMapping"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.ProviderFirstParams",
    "content": "default=org.apache.dubbo.registry.support.DefaultProviderFirstParams\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory",
    "content": "service-discovery-registry=org.apache.dubbo.registry.client.ServiceDiscoveryRegistryFactory\nwrapper=org.apache.dubbo.registry.RegistryFactoryWrapper"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.RegistryClusterIdentifier",
    "content": "default=org.apache.dubbo.registry.client.DefaultRegistryClusterIdentifier"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory",
    "content": "default=org.apache.dubbo.registry.client.DefaultServiceDiscoveryFactory\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer",
    "content": "protocol-ports=org.apache.dubbo.registry.client.metadata.ProtocolPortsMetadataCustomizer\ninstance-metadata=org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataCustomizer\nport=org.apache.dubbo.registry.client.metadata.ServiceInstanceHostPortCustomizer\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.MetadataServiceURLBuilder",
    "content": "standard=org.apache.dubbo.registry.client.metadata.StandardMetadataServiceURLBuilder\nspring-cloud=org.apache.dubbo.registry.client.metadata.SpringCloudMetadataServiceURLBuilder"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.migration.MigrationAddressComparator",
    "content": "default=org.apache.dubbo.registry.client.migration.DefaultMigrationAddressComparator"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.integration.RegistryProtocolListener",
    "content": "migration=org.apache.dubbo.registry.client.migration.MigrationRuleListener"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.integration.ServiceURLCustomizer",
    "content": "default=org.apache.dubbo.registry.integration.DefaultServiceURLCustomizer\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol",
    "content": "registry=org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol\nservice-discovery-registry=org.apache.dubbo.registry.integration.RegistryProtocol"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer",
    "content": "dubbo-registry-api=org.apache.dubbo.registry.RegistryScopeModelInitializer\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/CacheableFailbackRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLStrParser;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass CacheableFailbackRegistryTest {\n\n    static String service;\n    static URL serviceUrl;\n    static URL registryUrl;\n    static String urlStr;\n    static String urlStr2;\n    static String urlStr3;\n\n    MockCacheableRegistryImpl registry;\n\n    @BeforeAll\n    static void setProperty() {\n        System.setProperty(\"dubbo.application.url.cache.task.interval\", \"0\");\n        System.setProperty(\"dubbo.application.url.cache.clear.waiting\", \"0\");\n        FrameworkModel.destroyAll();\n    }\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        service = \"org.apache.dubbo.test.DemoService\";\n        serviceUrl = URL.valueOf(\"dubbo://127.0.0.1/org.apache.dubbo.test.DemoService?category=providers\");\n        registryUrl = URL.valueOf(\"http://1.2.3.4:9090/registry?check=false&file=N/A\");\n        urlStr =\n                \"dubbo%3A%2F%2F172.19.4.113%3A20880%2Forg.apache.dubbo.demo.DemoService%3Fside%3Dprovider%26timeout%3D3000\";\n        urlStr2 =\n                \"dubbo%3A%2F%2F172.19.4.114%3A20880%2Forg.apache.dubbo.demo.DemoService%3Fside%3Dprovider%26timeout%3D3000\";\n        urlStr3 =\n                \"dubbo%3A%2F%2F172.19.4.115%3A20880%2Forg.apache.dubbo.demo.DemoService%3Fside%3Dprovider%26timeout%3D3000\";\n    }\n\n    @AfterEach\n    public void tearDown() {\n        registry.getStringUrls().clear();\n        registry.getStringAddress().clear();\n        registry.getStringParam().clear();\n    }\n\n    @Test\n    void testFullURLCache() {\n        final AtomicReference<Integer> resCount = new AtomicReference<>(0);\n        registry = new MockCacheableRegistryImpl(registryUrl);\n        URL url = URLStrParser.parseEncodedStr(urlStr);\n\n        NotifyListener listener = urls -> resCount.set(urls.size());\n\n        registry.addChildren(url);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(1, registry.getStringUrls().get(serviceUrl).size());\n        assertEquals(1, resCount.get());\n\n        registry.addChildren(url);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(1, registry.getStringUrls().get(serviceUrl).size());\n        assertEquals(1, resCount.get());\n\n        URL url1 = url.addParameter(\"k1\", \"v1\");\n        registry.addChildren(url1);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(2, registry.getStringUrls().get(serviceUrl).size());\n        assertEquals(2, resCount.get());\n\n        URL url2 = url1.setHost(\"192.168.1.1\");\n        registry.addChildren(url2);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(3, registry.getStringUrls().get(serviceUrl).size());\n        assertEquals(3, resCount.get());\n    }\n\n    @Test\n    void testURLAddressCache() {\n        final AtomicReference<Integer> resCount = new AtomicReference<>(0);\n        registry = new MockCacheableRegistryImpl(registryUrl);\n        URL url = URLStrParser.parseEncodedStr(urlStr);\n\n        NotifyListener listener = urls -> resCount.set(urls.size());\n\n        registry.addChildren(url);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(1, registry.getStringAddress().size());\n        assertEquals(1, resCount.get());\n\n        URL url1 = url.addParameter(\"k1\", \"v1\");\n        registry.addChildren(url1);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(1, registry.getStringAddress().size());\n        assertEquals(2, resCount.get());\n\n        URL url2 = url1.setHost(\"192.168.1.1\");\n        registry.addChildren(url2);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(2, registry.getStringAddress().size());\n        assertEquals(3, resCount.get());\n    }\n\n    @Test\n    void testURLParamCache() {\n        final AtomicReference<Integer> resCount = new AtomicReference<>(0);\n        registry = new MockCacheableRegistryImpl(registryUrl);\n        URL url = URLStrParser.parseEncodedStr(urlStr);\n\n        NotifyListener listener = urls -> resCount.set(urls.size());\n\n        registry.addChildren(url);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(1, registry.getStringParam().size());\n        assertEquals(1, resCount.get());\n\n        URL url1 = url.addParameter(\"k1\", \"v1\");\n        registry.addChildren(url1);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(2, registry.getStringParam().size());\n        assertEquals(2, resCount.get());\n\n        URL url2 = url1.setHost(\"192.168.1.1\");\n        registry.addChildren(url2);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(2, registry.getStringParam().size());\n        assertEquals(3, resCount.get());\n    }\n\n    @Test\n    void testRemove() {\n        final AtomicReference<Integer> resCount = new AtomicReference<>(0);\n        registry = new MockCacheableRegistryImpl(registryUrl);\n        URL url = URLStrParser.parseEncodedStr(urlStr);\n\n        NotifyListener listener = urls -> resCount.set(urls.size());\n\n        registry.addChildren(url);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(1, registry.getStringUrls().get(serviceUrl).size());\n        assertEquals(1, registry.getStringAddress().size());\n        assertEquals(1, registry.getStringParam().size());\n        assertEquals(1, resCount.get());\n\n        registry.clearChildren();\n        URL url1 = url.addParameter(\"k1\", \"v1\");\n        registry.addChildren(url1);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(1, registry.getStringUrls().get(serviceUrl).size());\n        assertEquals(1, resCount.get());\n\n        // After RemovalTask\n        assertEquals(1, registry.getStringParam().size());\n        // StringAddress will be deleted because the related stringUrls cache has been deleted.\n        assertEquals(0, registry.getStringAddress().size());\n\n        registry.clearChildren();\n        URL url2 = url1.setHost(\"192.168.1.1\");\n        registry.addChildren(url2);\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(1, registry.getStringUrls().get(serviceUrl).size());\n        assertEquals(1, resCount.get());\n\n        // After RemovalTask\n        assertEquals(1, registry.getStringAddress().size());\n        // StringParam will be deleted because the related stringUrls cache has been deleted.\n        assertEquals(0, registry.getStringParam().size());\n    }\n\n    @Test\n    void testEmptyProtection() {\n        final AtomicReference<Integer> resCount = new AtomicReference<>(0);\n        final AtomicReference<List<URL>> currentUrls = new AtomicReference<>();\n        final List<URL> EMPTY_LIST = new ArrayList<>();\n\n        registry = new MockCacheableRegistryImpl(registryUrl.addParameter(ENABLE_EMPTY_PROTECTION_KEY, true));\n        URL url = URLStrParser.parseEncodedStr(urlStr);\n        URL url2 = URLStrParser.parseEncodedStr(urlStr2);\n        URL url3 = URLStrParser.parseEncodedStr(urlStr3);\n\n        NotifyListener listener = urls -> {\n            if (CollectionUtils.isEmpty(urls)) {\n                // do nothing\n            } else if (urls.size() == 1 && urls.get(0).getProtocol().equals(EMPTY_PROTOCOL)) {\n                resCount.set(0);\n                currentUrls.set(EMPTY_LIST);\n            } else {\n                resCount.set(urls.size());\n                currentUrls.set(urls);\n            }\n        };\n\n        registry.addChildren(url);\n        registry.addChildren(url2);\n        registry.addChildren(url3);\n\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(3, resCount.get());\n        registry.removeChildren(url);\n        assertEquals(2, resCount.get());\n        registry.clearChildren();\n        assertEquals(2, resCount.get());\n\n        URL emptyRegistryURL = registryUrl.addParameter(ENABLE_EMPTY_PROTECTION_KEY, false);\n        MockCacheableRegistryImpl emptyRegistry = new MockCacheableRegistryImpl(emptyRegistryURL);\n\n        emptyRegistry.addChildren(url);\n        emptyRegistry.addChildren(url2);\n\n        emptyRegistry.subscribe(serviceUrl, listener);\n        assertEquals(2, resCount.get());\n        emptyRegistry.clearChildren();\n        assertEquals(0, currentUrls.get().size());\n        assertEquals(EMPTY_LIST, currentUrls.get());\n    }\n\n    @Test\n    void testNoEmptyProtection() {\n        final AtomicReference<Integer> resCount = new AtomicReference<>(0);\n        final AtomicReference<List<URL>> currentUrls = new AtomicReference<>();\n        final List<URL> EMPTY_LIST = new ArrayList<>();\n\n        registry = new MockCacheableRegistryImpl(registryUrl);\n        URL url = URLStrParser.parseEncodedStr(urlStr);\n        URL url2 = URLStrParser.parseEncodedStr(urlStr2);\n        URL url3 = URLStrParser.parseEncodedStr(urlStr3);\n\n        NotifyListener listener = urls -> {\n            if (CollectionUtils.isEmpty(urls)) {\n                // do nothing\n            } else if (urls.size() == 1 && urls.get(0).getProtocol().equals(EMPTY_PROTOCOL)) {\n                resCount.set(0);\n                currentUrls.set(EMPTY_LIST);\n            } else {\n                resCount.set(urls.size());\n                currentUrls.set(urls);\n            }\n        };\n\n        registry.addChildren(url);\n        registry.addChildren(url2);\n        registry.addChildren(url3);\n\n        registry.subscribe(serviceUrl, listener);\n        assertEquals(3, resCount.get());\n        registry.removeChildren(url);\n        assertEquals(2, resCount.get());\n        registry.clearChildren();\n        assertEquals(0, resCount.get());\n\n        URL emptyRegistryURL = registryUrl.addParameter(ENABLE_EMPTY_PROTECTION_KEY, true);\n        MockCacheableRegistryImpl emptyRegistry = new MockCacheableRegistryImpl(emptyRegistryURL);\n\n        emptyRegistry.addChildren(url);\n        emptyRegistry.addChildren(url2);\n\n        emptyRegistry.subscribe(serviceUrl, listener);\n        assertEquals(2, resCount.get());\n        emptyRegistry.clearChildren();\n        assertEquals(2, currentUrls.get().size());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ListenerRegistryWrapperTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.registry.integration.DemoService;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass ListenerRegistryWrapperTest {\n\n    @Test\n    void testSubscribe() {\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(\"register\", \"true\");\n        parameters.put(REGISTER_IP_KEY, \"172.23.236.180\");\n        parameters.put(\"registry.listeners\", \"listener-one\");\n\n        Map<String, Object> attributes = new HashMap<>();\n        ServiceConfigURL serviceConfigURL = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        Map<String, String> refer = new HashMap<>();\n        attributes.put(REFER_KEY, refer);\n        attributes.put(\"key1\", \"value1\");\n        URL url = serviceConfigURL.addAttributes(attributes);\n\n        RegistryFactory registryFactory = mock(RegistryFactory.class);\n        Registry registry = mock(Registry.class);\n        NotifyListener notifyListener = mock(NotifyListener.class);\n        when(registryFactory.getRegistry(url)).thenReturn(registry);\n\n        RegistryFactoryWrapper registryFactoryWrapper = new RegistryFactoryWrapper(registryFactory);\n        Registry registryWrapper = registryFactoryWrapper.getRegistry(url);\n\n        Assertions.assertTrue(registryWrapper instanceof ListenerRegistryWrapper);\n\n        URL subscribeUrl = new ServiceConfigURL(\"dubbo\", \"127.0.0.1\", 20881, DemoService.class.getName(), parameters);\n\n        RegistryServiceListener listener = Mockito.mock(RegistryServiceListener.class);\n        RegistryServiceListener1.delegate = listener;\n\n        registryWrapper.subscribe(subscribeUrl, notifyListener);\n        verify(listener, times(1)).onSubscribe(subscribeUrl, registry);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/MockCacheableRegistryImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceAddressURL;\nimport org.apache.dubbo.common.url.component.URLAddress;\nimport org.apache.dubbo.common.url.component.URLParam;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.support.CacheableFailbackRegistry;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Semaphore;\n\npublic class MockCacheableRegistryImpl extends CacheableFailbackRegistry {\n\n    private final List<String> children = new ArrayList<>();\n    NotifyListener listener;\n\n    public MockCacheableRegistryImpl(URL url) {\n        super(url);\n    }\n\n    @Override\n    public int getDelay() {\n        return 0;\n    }\n\n    @Override\n    protected boolean isMatch(URL subscribeUrl, URL providerUrl) {\n        return UrlUtils.isMatch(subscribeUrl, providerUrl);\n    }\n\n    @Override\n    public void doRegister(URL url) {}\n\n    @Override\n    public void doUnregister(URL url) {}\n\n    @Override\n    public void doSubscribe(URL url, NotifyListener listener) {\n        List<URL> res = toUrlsWithoutEmpty(url, children);\n        Semaphore semaphore = getSemaphore();\n        while (semaphore.availablePermits() != 1) {\n            try {\n                Thread.sleep(100);\n            } catch (InterruptedException e) {\n                // ignore\n            }\n        }\n        listener.notify(res);\n        this.listener = listener;\n    }\n\n    @Override\n    public void doUnsubscribe(URL url, NotifyListener listener) {\n        super.doUnsubscribe(url, listener);\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return false;\n    }\n\n    public void addChildren(URL url) {\n        children.add(URL.encode(url.toFullString()));\n    }\n\n    public void removeChildren(URL url) {\n        children.remove(URL.encode(url.toFullString()));\n        if (listener != null) {\n            listener.notify(toUrlsWithEmpty(getUrl(), \"providers\", children));\n        }\n    }\n\n    public List<String> getChildren() {\n        return children;\n    }\n\n    public void clearChildren() {\n        children.clear();\n        if (listener != null) {\n            listener.notify(toUrlsWithEmpty(getUrl(), \"providers\", children));\n        }\n    }\n\n    public Map<URL, Map<String, ServiceAddressURL>> getStringUrls() {\n        return stringUrls;\n    }\n\n    public Map<String, URLAddress> getStringAddress() {\n        return stringAddress;\n    }\n\n    public Map<String, URLParam> getStringParam() {\n        return stringParam;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/MockLogger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.logger.Logger;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class MockLogger implements Logger {\n    public Set<String> printedLogs = new HashSet<>();\n\n    public boolean checkLogHappened(String msgPrefix) {\n        for (String printedLog : printedLogs) {\n            if (printedLog.contains(msgPrefix)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public void trace(String msg) {}\n\n    @Override\n    public void trace(String msg, Object... arguments) {}\n\n    @Override\n    public void trace(Throwable e) {}\n\n    @Override\n    public void trace(String msg, Throwable e) {}\n\n    @Override\n    public void debug(String msg) {}\n\n    @Override\n    public void debug(String msg, Object... arguments) {}\n\n    @Override\n    public void debug(Throwable e) {}\n\n    @Override\n    public void debug(String msg, Throwable e) {}\n\n    @Override\n    public void info(String msg) {}\n\n    @Override\n    public void info(String msg, Object... arguments) {}\n\n    @Override\n    public void info(Throwable e) {}\n\n    @Override\n    public void info(String msg, Throwable e) {}\n\n    @Override\n    public void warn(String msg) {}\n\n    @Override\n    public void warn(String msg, Object... arguments) {}\n\n    @Override\n    public void warn(Throwable e) {}\n\n    @Override\n    public void warn(String msg, Throwable e) {\n        printedLogs.add(msg);\n    }\n\n    @Override\n    public void error(String msg) {}\n\n    @Override\n    public void error(String msg, Object... arguments) {}\n\n    @Override\n    public void error(Throwable e) {}\n\n    @Override\n    public void error(String msg, Throwable e) {}\n\n    @Override\n    public boolean isTraceEnabled() {\n        return false;\n    }\n\n    @Override\n    public boolean isDebugEnabled() {\n        return false;\n    }\n\n    @Override\n    public boolean isInfoEnabled() {\n        return false;\n    }\n\n    @Override\n    public boolean isWarnEnabled() {\n        return false;\n    }\n\n    @Override\n    public boolean isErrorEnabled() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/PerformanceRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.NetUtils;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNDEFINED_ARGUMENT;\n\n/**\n * RegistryPerformanceTest\n */\nclass PerformanceRegistryTest {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(PerformanceRegistryTest.class);\n\n    @Test\n    void testRegistry() {\n        // read server info from property\n        if (PerformanceUtils.getProperty(\"server\", null) == null) {\n            logger.warn(CONFIG_UNDEFINED_ARGUMENT, \"\", \"\", \"Please set -Dserver=127.0.0.1:9090\");\n            return;\n        }\n        final int base = PerformanceUtils.getIntProperty(\"base\", 0);\n        final int concurrent = PerformanceUtils.getIntProperty(\"concurrent\", 100);\n        int r = PerformanceUtils.getIntProperty(\"runs\", 1000);\n        final int runs = r > 0 ? r : Integer.MAX_VALUE;\n        final Registry registry = ExtensionLoader.getExtensionLoader(RegistryFactory.class)\n                .getAdaptiveExtension()\n                .getRegistry(URL.valueOf(\n                        \"remote://admin:hello1234@\" + PerformanceUtils.getProperty(\"server\", \"10.20.153.28:9090\")));\n        for (int i = 0; i < concurrent; i++) {\n            final int t = i;\n            new Thread(new Runnable() {\n                        public void run() {\n                            for (int j = 0; j < runs; j++) {\n                                registry.register(\n                                        URL.valueOf(\"remote://\" + NetUtils.getLocalHost() + \":8080/demoService\" + t\n                                                + \"_\" + j + \"?version=1.0.0&application=demo&dubbo=2.0&interface=\"\n                                                + \"org.apache.dubbo.demo.DemoService\" + (base + t) + \"_\" + (base + j)));\n                            }\n                        }\n                    })\n                    .start();\n        }\n        synchronized (PerformanceRegistryTest.class) {\n            while (true) {\n                try {\n                    PerformanceRegistryTest.class.wait();\n                } catch (InterruptedException e) {\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/PerformanceUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.text.DecimalFormat;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\n\npublic class PerformanceUtils {\n\n    private static final int WIDTH = 64;\n\n    public static String getProperty(String key, String defaultValue) {\n        String value = System.getProperty(key);\n        if (value == null || value.trim().length() == 0 || value.startsWith(\"$\")) {\n            return defaultValue;\n        }\n        return value.trim();\n    }\n\n    public static int getIntProperty(String key, int defaultValue) {\n        String value = System.getProperty(key);\n        if (value == null || value.trim().length() == 0 || value.startsWith(\"$\")) {\n            return defaultValue;\n        }\n        return Integer.parseInt(value.trim());\n    }\n\n    public static boolean getBooleanProperty(String key, boolean defaultValue) {\n        String value = System.getProperty(key);\n        if (value == null || value.trim().length() == 0 || value.startsWith(\"$\")) {\n            return defaultValue;\n        }\n        return Boolean.parseBoolean(value.trim());\n    }\n\n    public static List<String> getEnvironment() {\n        List<String> environment = new ArrayList<String>();\n        environment.add(\"OS: \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.SYSTEM_OS_NAME) + \" \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.SYSTEM_OS_VERSION) + \" \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.OS_ARCH, \"\"));\n        environment.add(\"CPU: \" + Runtime.getRuntime().availableProcessors() + \" cores\");\n        environment.add(\"JVM: \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_VM_NAME) + \" \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_RUNTIME_VERSION));\n        environment.add(\"Memory: \"\n                + DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().totalMemory()) + \" bytes (Max: \"\n                + DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().maxMemory()) + \" bytes)\");\n        NetworkInterface ni = PerformanceUtils.getNetworkInterface();\n        if (ni != null) {\n            environment.add(\"Network: \" + ni.getDisplayName());\n        }\n        return environment;\n    }\n\n    public static void printSeparator() {\n        StringBuilder pad = new StringBuilder();\n        for (int i = 0; i < WIDTH; i++) {\n            pad.append('-');\n        }\n    }\n\n    public static void printBorder() {\n        StringBuilder pad = new StringBuilder();\n        for (int i = 0; i < WIDTH; i++) {\n            pad.append('=');\n        }\n    }\n\n    public static void printBody(String msg) {\n        StringBuilder pad = new StringBuilder();\n        int len = WIDTH - msg.length() - 1;\n        if (len > 0) {\n            for (int i = 0; i < len; i++) {\n                pad.append(' ');\n            }\n        }\n    }\n\n    public static void printHeader(String msg) {\n        StringBuilder pad = new StringBuilder();\n        int len = WIDTH - msg.length();\n        if (len > 0) {\n            int half = len / 2;\n            for (int i = 0; i < half; i++) {\n                pad.append(' ');\n            }\n        }\n    }\n\n    public static NetworkInterface getNetworkInterface() {\n        try {\n            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();\n            if (interfaces != null) {\n                while (interfaces.hasMoreElements()) {\n                    try {\n                        return interfaces.nextElement();\n                    } catch (Throwable e) {\n                    }\n                }\n            }\n        } catch (SocketException e) {\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/RegistryFactoryWrapperTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass RegistryFactoryWrapperTest {\n    private RegistryFactory registryFactory =\n            ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();\n\n    @Test\n    void test() throws Exception {\n        RegistryServiceListener listener1 = Mockito.mock(RegistryServiceListener.class);\n        RegistryServiceListener1.delegate = listener1;\n        RegistryServiceListener listener2 = Mockito.mock(RegistryServiceListener.class);\n        RegistryServiceListener2.delegate = listener2;\n\n        Registry registry = registryFactory.getRegistry(\n                URL.valueOf(\"simple://localhost:8080/registry-service?registry.listeners=listener-one,listener-two\"));\n        URL url = URL.valueOf(\"dubbo://localhost:8081/simple.service\");\n        registry.register(url);\n\n        Mockito.verify(listener1, Mockito.times(1)).onRegister(url, SimpleRegistryFactory.registry);\n        Mockito.verify(listener2, Mockito.times(1)).onRegister(url, SimpleRegistryFactory.registry);\n\n        registry.unregister(url);\n        Mockito.verify(listener1, Mockito.times(1)).onUnregister(url, SimpleRegistryFactory.registry);\n        Mockito.verify(listener2, Mockito.times(1)).onUnregister(url, SimpleRegistryFactory.registry);\n\n        registry.subscribe(url, Mockito.mock(NotifyListener.class));\n        Mockito.verify(listener1, Mockito.times(1)).onSubscribe(url, SimpleRegistryFactory.registry);\n        Mockito.verify(listener2, Mockito.times(1)).onSubscribe(url, SimpleRegistryFactory.registry);\n\n        registry.unsubscribe(url, Mockito.mock(NotifyListener.class));\n        Mockito.verify(listener1, Mockito.times(1)).onUnsubscribe(url, SimpleRegistryFactory.registry);\n        Mockito.verify(listener2, Mockito.times(1)).onUnsubscribe(url, SimpleRegistryFactory.registry);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/RegistryServiceListener1.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate(order = 1, value = \"listener-one\")\npublic class RegistryServiceListener1 implements RegistryServiceListener {\n    static RegistryServiceListener delegate;\n\n    @Override\n    public void onRegister(URL url, Registry registry) {\n        delegate.onRegister(url, registry);\n    }\n\n    @Override\n    public void onUnregister(URL url, Registry registry) {\n        delegate.onUnregister(url, registry);\n    }\n\n    @Override\n    public void onSubscribe(URL url, Registry registry) {\n        delegate.onSubscribe(url, registry);\n    }\n\n    @Override\n    public void onUnsubscribe(URL url, Registry registry) {\n        delegate.onUnsubscribe(url, registry);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/RegistryServiceListener2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Activate;\n\n@Activate(order = 2, value = \"listener-two\")\npublic class RegistryServiceListener2 implements RegistryServiceListener {\n    static RegistryServiceListener delegate;\n\n    @Override\n    public void onRegister(URL url, Registry registry) {\n        delegate.onRegister(url, registry);\n    }\n\n    @Override\n    public void onUnregister(URL url, Registry registry) {\n        delegate.onUnregister(url, registry);\n    }\n\n    @Override\n    public void onSubscribe(URL url, Registry registry) {\n        delegate.onSubscribe(url, registry);\n    }\n\n    @Override\n    public void onUnsubscribe(URL url, Registry registry) {\n        delegate.onUnsubscribe(url, registry);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/SimpleRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.URL;\n\nimport org.mockito.Mockito;\n\npublic class SimpleRegistryFactory implements RegistryFactory {\n    static Registry registry = Mockito.mock(Registry.class);\n\n    @Override\n    public Registry getRegistry(URL url) {\n        return registry;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry;\n\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.framework.api.CuratorEvent;\nimport org.apache.curator.framework.api.CuratorListener;\nimport org.apache.curator.framework.recipes.cache.ChildData;\nimport org.apache.curator.framework.recipes.cache.PathChildrenCache;\nimport org.apache.curator.framework.recipes.cache.TreeCache;\nimport org.apache.curator.framework.recipes.cache.TreeCacheEvent;\nimport org.apache.curator.framework.recipes.cache.TreeCacheListener;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ZKTools {\n    private static final Logger logger = LoggerFactory.getLogger(ZKTools.class);\n    private static CuratorFramework client;\n    private static ExecutorService executor =\n            Executors.newFixedThreadPool(1, new NamedThreadFactory(\"ZKTools-test\", true));\n\n    public static void main(String[] args) throws Exception {\n        client = CuratorFrameworkFactory.newClient(\n                \"127.0.0.1:2181\", 60 * 1000, 60 * 1000, new ExponentialBackoffRetry(1000, 3));\n        client.start();\n\n        client.getCuratorListenable()\n                .addListener(\n                        new CuratorListener() {\n                            @Override\n                            public void eventReceived(CuratorFramework client, CuratorEvent event) throws Exception {\n                                logger.info(\"event notification: {}\", event.getPath());\n                                logger.info(String.valueOf(event));\n                            }\n                        },\n                        executor);\n\n        //        testMigrationRule();\n        testAppMigrationRule();\n        //        tesConditionRule();\n        //        testStartupConfig();\n        //        testProviderConfig();\n        //        testPathCache();\n        //        testTreeCache();\n        //        testCuratorListener();\n        //       Thread.sleep(100000);\n    }\n\n    public static void testMigrationRule() {\n        String serviceStr = \"key: demo-consumer\\n\" + \"interfaces:\\n\"\n                + \"  - serviceKey: org.apache.dubbo.demo.DemoService:1.0.0\\n\"\n                + \"    threshold: 1.0\\n\"\n                + \"    step: FORCE_APPLICATION\";\n        try {\n            String servicePath = \"/dubbo/config/DUBBO_SERVICEDISCOVERY_MIGRATION/demo-consumer.migration\";\n            if (client.checkExists().forPath(servicePath) == null) {\n                client.create().creatingParentsIfNeeded().forPath(servicePath);\n            }\n            setData(servicePath, serviceStr);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void testAppMigrationRule() {\n        String serviceStr = \"key: demo-consumer\\n\" + \"applications:\\n\"\n                + \"  - name: demo-provider\\n\"\n                + \"    step: FORCE_APPLICATION\\n\"\n                + \"    threshold: 0.8\\n\"\n                + \"interfaces:\\n\"\n                + \"  - serviceKey: org.apache.dubbo.demo.DemoService\\n\"\n                + \"    threshold: 1.0\\n\"\n                + \"    step: FORCE_APPLICATION\";\n        try {\n            String servicePath = \"/dubbo/config/DUBBO_SERVICEDISCOVERY_MIGRATION/demo-consumer.migration\";\n            if (client.checkExists().forPath(servicePath) == null) {\n                client.create().creatingParentsIfNeeded().forPath(servicePath);\n            }\n            setData(servicePath, serviceStr);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void testStartupConfig() {\n        String str =\n                \"dubbo.registry.address=zookeeper://127.0.0.1:2181\\n\" + \"dubbo.registry.group=dubboregistrygroup1\\n\"\n                        + \"dubbo.metadata-report.address=zookeeper://127.0.0.1:2181\\n\"\n                        + \"dubbo.protocol.port=20990\\n\"\n                        + \"dubbo.service.org.apache.dubbo.demo.DemoService.timeout=9999\\n\";\n\n        try {\n            String path = \"/dubboregistrygroup1/config/dubbo/dubbo.properties\";\n            if (client.checkExists().forPath(path) == null) {\n                client.create().creatingParentsIfNeeded().forPath(path);\n            }\n            setData(path, str);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void testProviderConfig() {\n        String str = \"---\\n\" + \"apiVersion: v2.7\\n\"\n                + \"scope: service\\n\"\n                + \"key: dd-test/org.apache.dubbo.demo.DemoService:1.0.4\\n\"\n                + \"enabled: true\\n\"\n                + \"configs:\\n\"\n                + \"- addresses: ['0.0.0.0:20880']\\n\"\n                + \"  side: provider\\n\"\n                + \"  parameters:\\n\"\n                + \"    timeout: 6000\\n\"\n                + \"...\";\n\n        try {\n            String path = \"/dubbo/config/dd-test*org.apache.dubbo.demo.DemoService:1.0.4/configurators\";\n            if (client.checkExists().forPath(path) == null) {\n                client.create().creatingParentsIfNeeded().inBackground().forPath(path);\n            }\n            setData(path, str);\n\n            String pathaa = \"/dubboregistrygroup1/config/aaa/dubbo.properties\";\n            if (client.checkExists().forPath(pathaa) == null) {\n                client.create().creatingParentsIfNeeded().forPath(pathaa);\n            }\n            setData(pathaa, \"aaaa\");\n\n            String pathaaa = \"/dubboregistrygroup1/config/aaa\";\n            if (client.checkExists().forPath(pathaaa) == null) {\n                client.create().creatingParentsIfNeeded().inBackground().forPath(pathaaa);\n            }\n            setData(pathaaa, \"aaaa\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void testConsumerConfig() {\n        String serviceStr = \"---\\n\" + \"scope: service\\n\"\n                + \"key: org.apache.dubbo.demo.DemoService\\n\"\n                + \"configs:\\n\"\n                + \" - addresses: [30.5.121.156]\\n\"\n                + \"   side: consumer\\n\"\n                + \"   rules:\\n\"\n                + \"    cluster:\\n\"\n                + \"     loadbalance: random\\n\"\n                + \"     cluster: failfast\\n\"\n                + \"    config:\\n\"\n                + \"     timeout: 9999\\n\"\n                + \"     weight: 222\\n\"\n                + \"...\";\n        String appStr = \"---\\n\" + \"scope: application\\n\"\n                + \"key: demo-consumer\\n\"\n                + \"configs:\\n\"\n                + \" - addresses: [30.5.121.156]\\n\"\n                + \"   services: [org.apache.dubbo.demo.DemoService]\\n\"\n                + \"   side: consumer\\n\"\n                + \"   rules:\\n\"\n                + \"    cluster:\\n\"\n                + \"     loadbalance: random\\n\"\n                + \"     cluster: failfast\\n\"\n                + \"    config:\\n\"\n                + \"     timeout: 4444\\n\"\n                + \"     weight: 222\\n\"\n                + \"...\";\n        try {\n            String servicePath = \"/dubbo/config/org.apache.dubbo.demo.DemoService/configurators\";\n            if (client.checkExists().forPath(servicePath) == null) {\n                client.create().creatingParentsIfNeeded().forPath(servicePath);\n            }\n            setData(servicePath, serviceStr);\n\n            String appPath = \"/dubbo/config/demo-consumer/configurators\";\n            if (client.checkExists().forPath(appPath) == null) {\n                client.create().creatingParentsIfNeeded().forPath(appPath);\n            }\n            setData(appPath, appStr);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void tesConditionRule() {\n        String serviceStr = \"---\\n\" + \"scope: application\\n\"\n                + \"force: true\\n\"\n                + \"runtime: false\\n\"\n                + \"conditions:\\n\"\n                + \"  - method!=sayHello =>\\n\"\n                + \"  - method=routeMethod1 => 30.5.121.156:20880\\n\"\n                + \"...\";\n        try {\n            String servicePath = \"/dubbo/config/demo-consumer/routers\";\n            if (client.checkExists().forPath(servicePath) == null) {\n                client.create().creatingParentsIfNeeded().forPath(servicePath);\n            }\n            setData(servicePath, serviceStr);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void setData(String path, String data) throws Exception {\n        client.setData().inBackground().forPath(path, data.getBytes(StandardCharsets.UTF_8));\n    }\n\n    public static void testPathCache() throws Exception {\n        CuratorFramework client = CuratorFrameworkFactory.newClient(\n                \"127.0.0.1:2181\", 60 * 1000, 60 * 1000, new ExponentialBackoffRetry(1000, 3));\n        client.start();\n        PathChildrenCache pathChildrenCache = new PathChildrenCache(client, \"/dubbo/config\", true);\n        pathChildrenCache.start(true);\n        pathChildrenCache\n                .getListenable()\n                .addListener(\n                        (zkClient, event) -> {\n                            logger.info(event.getData().getPath());\n                        },\n                        Executors.newFixedThreadPool(1));\n        List<ChildData> dataList = pathChildrenCache.getCurrentData();\n        dataList.stream().map(ChildData::getPath).forEach(logger::info);\n    }\n\n    public static void testTreeCache() throws Exception {\n        CuratorFramework client = CuratorFrameworkFactory.newClient(\n                \"127.0.0.1:2181\", 60 * 1000, 60 * 1000, new ExponentialBackoffRetry(1000, 3));\n        client.start();\n\n        CountDownLatch latch = new CountDownLatch(1);\n\n        TreeCache treeCache =\n                TreeCache.newBuilder(client, \"/dubbo/config\").setCacheData(true).build();\n        treeCache.start();\n        treeCache.getListenable().addListener(new TreeCacheListener() {\n            @Override\n            public void childEvent(CuratorFramework client, TreeCacheEvent event) {\n\n                TreeCacheEvent.Type type = event.getType();\n                ChildData data = event.getData();\n\n                if (type == TreeCacheEvent.Type.INITIALIZED) {\n                    latch.countDown();\n                }\n\n                logger.info(\"{}\\n\", data.getPath());\n\n                if (data.getPath().split(\"/\").length == 5) {\n                    byte[] value = data.getData();\n                    String stringValue = new String(value, StandardCharsets.UTF_8);\n\n                    // fire event to all listeners\n                    Map<String, Object> added = null;\n                    Map<String, Object> changed = null;\n                    Map<String, Object> deleted = null;\n\n                    switch (type) {\n                        case NODE_ADDED:\n                            added = new HashMap<>(1);\n                            added.put(pathToKey(data.getPath()), stringValue);\n                            added.forEach((k, v) -> logger.info(\"{}  {}\", k, v));\n                            break;\n                        case NODE_REMOVED:\n                            deleted = new HashMap<>(1);\n                            deleted.put(pathToKey(data.getPath()), stringValue);\n                            deleted.forEach((k, v) -> logger.info(\"{}  {}\", k, v));\n                            break;\n                        case NODE_UPDATED:\n                            changed = new HashMap<>(1);\n                            changed.put(pathToKey(data.getPath()), stringValue);\n                            changed.forEach((k, v) -> logger.info(\"{}  {}\", k, v));\n                    }\n                }\n            }\n        });\n\n        latch.await();\n\n        /* Map<String, ChildData> dataMap = treeCache.getCurrentChildren(\"/dubbo/config\");\n        dataMap.forEach((k, v) -> {\n            System.out.println(k);\n            treeCache.getCurrentChildren(\"/dubbo/config/\" + k).forEach((ck, cv) -> {\n                System.out.println(ck);\n            });\n        });*/\n    }\n\n    private static String pathToKey(String path) {\n        if (StringUtils.isEmpty(path)) {\n            return path;\n        }\n        return path.replace(\"/dubbo/config/\", \"\").replaceAll(\"/\", \".\");\n    }\n\n    public static void testCuratorListener() throws Exception {\n        CuratorFramework client = CuratorFrameworkFactory.newClient(\n                \"127.0.0.1:2181\", 60 * 1000, 60 * 1000, new ExponentialBackoffRetry(1000, 3));\n        client.start();\n\n        List<String> children = client.getChildren().forPath(\"/dubbo/config\");\n        children.forEach(logger::info);\n        /*\n\n                client.getCuratorListenable().addListener(new CuratorListener() {\n                    @Override\n                    public void eventReceived(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {\n                        curatorEvent.get\n                    }\n                });\n        */\n\n        /*client.getChildren().usingWatcher(new CuratorWatcher() {\n            @Override\n            public void process(WatchedEvent watchedEvent) throws Exception {\n                System.out.println(watchedEvent.getPath());\n                client.getChildren().usingWatcher(this).forPath(\"/dubbo/config\");\n                System.out.println(watchedEvent.getWrapper().getPath());\n            }\n        }).forPath(\"/dubbo/config\");*/\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/AbstractServiceDiscoveryFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link AbstractServiceDiscoveryFactory}\n */\nclass AbstractServiceDiscoveryFactoryTest {\n\n    @Test\n    void testGetServiceDiscoveryWithCache() {\n        ApplicationModel.defaultModel()\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(\"AbstractServiceDiscoveryFactoryTest\"));\n        URL url = URL.valueOf(\"mock://127.0.0.1:8888\");\n        ServiceDiscoveryFactory factory = ServiceDiscoveryFactory.getExtension(url);\n        ServiceDiscovery serviceDiscovery1 = factory.getServiceDiscovery(url);\n        ServiceDiscovery serviceDiscovery2 = factory.getServiceDiscovery(url);\n        Assertions.assertEquals(serviceDiscovery1, serviceDiscovery2);\n\n        url = url.setPath(\"test\");\n        ServiceDiscovery serviceDiscovery3 = factory.getServiceDiscovery(url);\n        Assertions.assertNotEquals(serviceDiscovery2, serviceDiscovery3);\n\n        AbstractServiceDiscoveryFactory abstractServiceDiscoveryFactory = (AbstractServiceDiscoveryFactory) factory;\n        List<ServiceDiscovery> allServiceDiscoveries = abstractServiceDiscoveryFactory.getAllServiceDiscoveries();\n        Assertions.assertEquals(2, allServiceDiscoveries.size());\n        Assertions.assertTrue(allServiceDiscoveries.contains(serviceDiscovery1));\n        Assertions.assertTrue(allServiceDiscoveries.contains(serviceDiscovery3));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/DefaultServiceInstanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_STORAGE_TYPE_PROPERTY_NAME;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getEndpoint;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.setEndpoints;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotSame;\n\n/**\n * {@link DefaultServiceInstance} Test\n *\n * @since 2.7.5\n */\nclass DefaultServiceInstanceTest {\n\n    public DefaultServiceInstance instance;\n\n    public static DefaultServiceInstance createInstance() {\n        DefaultServiceInstance instance =\n                new DefaultServiceInstance(\"A\", \"127.0.0.1\", 20880, ApplicationModel.defaultModel());\n        Map<String, String> metadata = instance.getMetadata();\n        metadata.put(METADATA_STORAGE_TYPE_PROPERTY_NAME, \"remote\");\n        metadata.put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, \"111\");\n        metadata.put(\"site\", \"dubbo\");\n\n        Map<String, Integer> protocolPorts = new HashMap<>();\n        protocolPorts.put(\"rest\", 8080);\n        protocolPorts.put(\"dubbo\", 20880);\n        setEndpoints(instance, protocolPorts);\n        return instance;\n    }\n\n    @BeforeEach\n    public void init() {\n        instance = createInstance();\n    }\n\n    @Test\n    void testSetAndGetValues() {\n        instance.setEnabled(false);\n        instance.setHealthy(false);\n\n        assertEquals(\"A\", instance.getServiceName());\n        assertEquals(\"127.0.0.1\", instance.getHost());\n        assertEquals(20880, instance.getPort());\n        assertFalse(instance.isEnabled());\n        assertFalse(instance.isHealthy());\n        assertFalse(instance.getMetadata().isEmpty());\n    }\n\n    @Test\n    void testInstanceOperations() {\n        // test multiple protocols\n        assertEquals(2, instance.getEndpoints().size());\n        DefaultServiceInstance.Endpoint endpoint = getEndpoint(instance, \"rest\");\n        DefaultServiceInstance copyInstance = instance.copyFrom(endpoint);\n        assertEquals(8080, endpoint.getPort());\n        assertEquals(\"rest\", endpoint.getProtocol());\n        assertEquals(endpoint.getPort(), copyInstance.getPort());\n\n        // test all params\n        Map<String, String> allParams = instance.getAllParams();\n        assertEquals(instance.getMetadata().size(), allParams.size());\n        assertEquals(\"dubbo\", allParams.get(\"site\"));\n        instance.putExtendParam(\"key\", \"value\");\n        Map<String, String> allParams2 = instance.getAllParams();\n        assertNotSame(allParams, allParams2);\n        assertEquals(instance.getMetadata().size() + instance.getExtendParams().size(), allParams2.size());\n        assertEquals(\"value\", allParams2.get(\"key\"));\n\n        // test equals\n        DefaultServiceInstance instance2 =\n                new DefaultServiceInstance(\"A\", \"127.0.0.1\", 20880, ApplicationModel.defaultModel());\n        instance2.setMetadata(new HashMap<>(instance.getMetadata()));\n        instance2.getMetadata().put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, \"222\");\n        // assert instances with different revision and extend params are equal\n        assertEquals(instance, instance2);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/InstanceAddressURLTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.registry.ProviderFirstParams;\nimport org.apache.dubbo.rpc.RpcServiceContext;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.in;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass InstanceAddressURLTest {\n    private static URL url = URL.valueOf(\n            \"dubbo://30.225.21.30:20880/org.apache.dubbo.registry.service.DemoService?\"\n                    + \"REGISTRY_CLUSTER=registry1&anyhost=true&application=demo-provider2&delay=1000&deprecated=false&dubbo=2.0.2\"\n                    + \"&dynamic=true&generic=false&group=greeting&interface=org.apache.dubbo.registry.service.DemoService\"\n                    + \"&metadata-type=remote&methods=sayHello&sayHello.timeout=7000&a.timeout=7777&pid=66666&release=&revision=1.0.0&service-name-mapping=true\"\n                    + \"&side=provider&timeout=1000&timestamp=1629970909999&version=1.0.0&dubbo.tag=provider&params-filter=-default\");\n\n    private static URL url2 = URL.valueOf(\n            \"dubbo://30.225.21.30:20880/org.apache.dubbo.registry.service.DemoService2?\"\n                    + \"REGISTRY_CLUSTER=registry1&anyhost=true&application=demo-provider2&delay=5000&deprecated=false&dubbo=2.0.2\"\n                    + \"&dynamic=true&generic=false&group=greeting&interface=org.apache.dubbo.registry.service.DemoService2\"\n                    + \"&metadata-type=remote&methods=sayHello&sayHello.timeout=7000&pid=36621&release=&revision=1.0.0&service-name-mapping=true\"\n                    + \"&side=provider&timeout=5000&timestamp=1629970068002&version=1.0.0&dubbo.tag=provider2&uniqueKey=unique&params-filter=-default\");\n\n    private static URL consumerURL = URL.valueOf(\"dubbo://30.225.21.30/org.apache.dubbo.registry.service.DemoService?\"\n            + \"REGISTRY_CLUSTER=registry1&application=demo-consumer&dubbo=2.0.2\"\n            + \"&group=greeting&interface=org.apache.dubbo.registry.service.DemoService\"\n            + \"&version=1.0.0&timeout=9000&a.timeout=8888&dubbo.tag=consumer&protocol=dubbo\");\n\n    private DefaultServiceInstance createInstance() {\n        DefaultServiceInstance instance =\n                new DefaultServiceInstance(\"demo-provider\", \"127.0.0.1\", 8080, ApplicationModel.defaultModel());\n        Map<String, String> metadata = instance.getMetadata();\n        metadata.put(\"key1\", \"value1\");\n        metadata.put(\"key2\", \"value2\");\n        return instance;\n    }\n\n    private MetadataInfo createMetaDataInfo() {\n        MetadataInfo metadataInfo = new MetadataInfo(\"demo\");\n        // export normal url again\n        metadataInfo.addService(url);\n        metadataInfo.addService(url2);\n        return metadataInfo;\n    }\n\n    private InstanceAddressURL instanceURL;\n    private transient volatile Set<String> providerFirstParams;\n\n    @BeforeEach\n    public void setUp() {\n        DefaultServiceInstance instance = createInstance();\n        MetadataInfo metadataInfo = createMetaDataInfo();\n        instanceURL = new InstanceAddressURL(instance, metadataInfo);\n        Set<ProviderFirstParams> providerFirstParams = ApplicationModel.defaultModel()\n                .getExtensionLoader(ProviderFirstParams.class)\n                .getSupportedExtensionInstances();\n        if (CollectionUtils.isEmpty(providerFirstParams)) {\n            this.providerFirstParams = null;\n        } else {\n            if (providerFirstParams.size() == 1) {\n                this.providerFirstParams = Collections.unmodifiableSet(\n                        providerFirstParams.iterator().next().params());\n            } else {\n                Set<String> params = new HashSet<>();\n                for (ProviderFirstParams paramsFilter : providerFirstParams) {\n                    if (paramsFilter.params() == null) {\n                        break;\n                    }\n                    params.addAll(paramsFilter.params());\n                }\n                this.providerFirstParams = Collections.unmodifiableSet(params);\n            }\n        }\n        instanceURL.setProviderFirstParams(this.providerFirstParams);\n    }\n\n    @Test\n    void test1() {\n        // test reading of keys in instance and metadata work fine\n        assertEquals(\"value1\", instanceURL.getParameter(\"key1\")); // return instance key\n        assertNull(instanceURL.getParameter(\"delay\")); // no service key specified\n        RpcServiceContext.getServiceContext().setConsumerUrl(consumerURL);\n        assertEquals(\"1000\", instanceURL.getParameter(\"delay\"));\n        assertEquals(\"1000\", instanceURL.getServiceParameter(consumerURL.getProtocolServiceKey(), \"delay\"));\n        assertEquals(\"9000\", instanceURL.getMethodParameter(\"sayHello\", \"timeout\"));\n        assertEquals(\n                \"9000\",\n                instanceURL.getServiceMethodParameter(consumerURL.getProtocolServiceKey(), \"sayHello\", \"timeout\"));\n        assertNull(instanceURL.getParameter(\"uniqueKey\"));\n        assertNull(instanceURL.getServiceParameter(consumerURL.getProtocolServiceKey(), \"uniqueKey\"));\n        assertEquals(\"unique\", instanceURL.getServiceParameter(url2.getProtocolServiceKey(), \"uniqueKey\"));\n\n        // test some consumer keys have higher priority\n        assertEquals(\n                \"8888\", instanceURL.getServiceMethodParameter(consumerURL.getProtocolServiceKey(), \"a\", \"timeout\"));\n        assertEquals(\"9000\", instanceURL.getParameter(\"timeout\"));\n\n        // test some provider keys have higher priority\n        assertEquals(\"provider\", instanceURL.getParameter(TAG_KEY));\n\n        assertEquals(instanceURL.getVersion(), instanceURL.getParameter(VERSION_KEY));\n        assertEquals(instanceURL.getGroup(), instanceURL.getParameter(GROUP_KEY));\n        assertEquals(instanceURL.getApplication(), instanceURL.getParameter(APPLICATION_KEY));\n        assertEquals(\"demo-consumer\", instanceURL.getParameter(APPLICATION_KEY));\n        assertEquals(instanceURL.getRemoteApplication(), instanceURL.getParameter(REMOTE_APPLICATION_KEY));\n        assertEquals(\"demo-provider\", instanceURL.getParameter(REMOTE_APPLICATION_KEY));\n        assertEquals(instanceURL.getSide(), instanceURL.getParameter(SIDE_KEY));\n        //        assertThat(Arrays.asList(\"7000\", \"8888\"), hasItem(instanceURL.getAnyMethodParameter(\"timeout\")));\n        assertThat(instanceURL.getAnyMethodParameter(\"timeout\"), in(Arrays.asList(\"7000\", \"8888\")));\n        Map<String, String> expectedAllParams = new HashMap<>();\n        expectedAllParams.putAll(instanceURL.getInstance().getMetadata());\n        expectedAllParams.putAll(instanceURL\n                .getMetadataInfo()\n                .getServiceInfo(consumerURL.getProtocolServiceKey())\n                .getAllParams());\n        Map<String, String> consumerURLParameters = consumerURL.getParameters();\n        providerFirstParams.forEach(consumerURLParameters::remove);\n        expectedAllParams.putAll(consumerURLParameters);\n\n        assertEquals(expectedAllParams.size(), instanceURL.getParameters().size());\n        assertEquals(url.getParameter(TAG_KEY), instanceURL.getParameters().get(TAG_KEY));\n        assertEquals(\n                consumerURL.getParameter(TIMEOUT_KEY),\n                instanceURL.getParameters().get(TIMEOUT_KEY));\n        assertTrue(instanceURL.hasServiceMethodParameter(url.getProtocolServiceKey(), \"a\"));\n        assertTrue(instanceURL.hasServiceMethodParameter(url.getProtocolServiceKey(), \"sayHello\"));\n        assertTrue(instanceURL.hasMethodParameter(\"a\", TIMEOUT_KEY));\n        assertTrue(instanceURL.hasMethodParameter(null, TIMEOUT_KEY));\n        assertEquals(\"8888\", instanceURL.getMethodParameter(\"a\", TIMEOUT_KEY));\n        assertTrue(instanceURL.hasMethodParameter(\"a\", null));\n        assertFalse(instanceURL.hasMethodParameter(\"notExistMethod\", null));\n\n        // keys added to instance url are shared among services.\n        instanceURL.addParameter(\"newKey\", \"newValue\");\n        assertEquals(\"newValue\", instanceURL.getParameter(\"newKey\"));\n        assertEquals(\"newValue\", instanceURL.getParameters().get(\"newKey\"));\n        assertEquals(\n                \"newValue\",\n                instanceURL.getServiceParameters(url.getProtocolServiceKey()).get(\"newKey\"));\n    }\n\n    @Test\n    void test2() {\n        RpcServiceContext.getServiceContext().setConsumerUrl(null);\n        Assertions.assertNull(instanceURL.getScopeModel());\n\n        ModuleModel moduleModel = Mockito.mock(ModuleModel.class);\n        RpcServiceContext.getServiceContext().setConsumerUrl(URL.valueOf(\"\").setScopeModel(moduleModel));\n        Assertions.assertEquals(moduleModel, instanceURL.getScopeModel());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/ServiceDiscoveryCacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.registry.client.support.MockServiceDiscovery;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.METADATA_INFO_CACHE_EXPIRE_KEY;\nimport static org.awaitility.Awaitility.await;\n\nclass ServiceDiscoveryCacheTest {\n\n    @Test\n    void test() throws InterruptedException {\n        ApplicationModel applicationModel = FrameworkModel.defaultModel().newApplication();\n        applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"Test\"));\n\n        URL registryUrl = URL.valueOf(\"mock://127.0.0.1:12345\").addParameter(METADATA_INFO_CACHE_EXPIRE_KEY, 10);\n        MockServiceDiscovery mockServiceDiscovery =\n                Mockito.spy(new MockServiceDiscovery(applicationModel, registryUrl));\n\n        mockServiceDiscovery.register(URL.valueOf(\"mock://127.0.0.1:12345\")\n                .setServiceInterface(\"org.apache.dubbo.registry.service.DemoService\"));\n        mockServiceDiscovery.register();\n\n        ServiceInstance localInstance = mockServiceDiscovery.getLocalInstance();\n\n        Assertions.assertEquals(\n                localInstance.getServiceMetadata(),\n                mockServiceDiscovery.getLocalMetadata(\n                        localInstance.getServiceMetadata().getRevision()));\n\n        List<MetadataInfo> instances = new LinkedList<>();\n        instances.add(localInstance.getServiceMetadata().clone());\n\n        for (int i = 0; i < 15; i++) {\n            Thread.sleep(1);\n            mockServiceDiscovery.register(URL.valueOf(\"mock://127.0.0.1:12345\")\n                    .setServiceInterface(\"org.apache.dubbo.registry.service.DemoService\" + i));\n            mockServiceDiscovery.update();\n            instances.add(\n                    mockServiceDiscovery.getLocalInstance().getServiceMetadata().clone());\n        }\n\n        for (MetadataInfo instance : instances) {\n            Assertions.assertEquals(instance, mockServiceDiscovery.getLocalMetadata(instance.getRevision()));\n        }\n\n        for (int i = 0; i < 5; i++) {\n            Thread.sleep(1);\n            mockServiceDiscovery.register(URL.valueOf(\"mock://127.0.0.1:12345\")\n                    .setServiceInterface(\"org.apache.dubbo.registry.service.DemoService-new\" + i));\n            mockServiceDiscovery.update();\n            instances.add(\n                    mockServiceDiscovery.getLocalInstance().getServiceMetadata().clone());\n        }\n\n        await().until(() -> Objects.isNull(\n                mockServiceDiscovery.getLocalMetadata(instances.get(4).getRevision())));\n\n        for (int i = 0; i < 5; i++) {\n            Assertions.assertNull(\n                    mockServiceDiscovery.getLocalMetadata(instances.get(i).getRevision()));\n        }\n\n        applicationModel.destroy();\n    }\n\n    /**\n     * to fix #14126\n     */\n    @Test\n    void testUpdateWhenFirstDoRegisterFail() throws InterruptedException {\n        ApplicationModel applicationModel = FrameworkModel.defaultModel().newApplication();\n        applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"Test\"));\n\n        URL registryUrl = URL.valueOf(\"mock://127.0.0.1:12345\").addParameter(METADATA_INFO_CACHE_EXPIRE_KEY, 10);\n        MockServiceDiscovery mockServiceDiscovery =\n                Mockito.spy(new MockServiceDiscovery(applicationModel, registryUrl));\n\n        mockServiceDiscovery.register(URL.valueOf(\"mock://127.0.0.1:12345\")\n                .setServiceInterface(\"org.apache.dubbo.registry.service.DemoService\"));\n\n        Thread.sleep(100);\n        Mockito.doThrow(new RuntimeException())\n                .when(mockServiceDiscovery)\n                .doRegister(Mockito.any(ServiceInstance.class));\n        Assertions.assertThrows(RuntimeException.class, mockServiceDiscovery::update);\n\n        Thread.sleep(100);\n        Mockito.doNothing().when(mockServiceDiscovery).doRegister(Mockito.any(ServiceInstance.class));\n        Assertions.assertDoesNotThrow(mockServiceDiscovery::update);\n\n        Thread.sleep(100);\n        Assertions.assertDoesNotThrow(mockServiceDiscovery::update);\n\n        applicationModel.destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client;\n\nimport org.apache.dubbo.common.ProtocolServiceKey;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metadata.AbstractServiceNameMapping;\nimport org.apache.dubbo.metadata.ServiceNameMapping;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.client.event.listener.MockServiceInstancesChangedListener;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDED_BY;\nimport static org.apache.dubbo.metadata.ServiceNameMapping.toStringKeys;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doNothing;\nimport static org.mockito.Mockito.doReturn;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass ServiceDiscoveryRegistryTest {\n    public static final String APP_NAME1 = \"app1\";\n    public static final String APP_NAME2 = \"app2\";\n    public static final String APP_NAME3 = \"app3\";\n\n    private static AbstractServiceNameMapping mapping = mock(AbstractServiceNameMapping.class);\n    private static Lock lock = new ReentrantLock();\n\n    private static URL registryURL =\n            URL.valueOf(\"zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService\");\n    private static URL url =\n            URL.valueOf(\"consumer://127.0.0.1/TestService?interface=TestService1&check=false&protocol=dubbo\");\n    private static NotifyListener testServiceListener = mock(NotifyListener.class);\n\n    private static List<ServiceInstance> instanceList1 = new ArrayList<>();\n    private static List<ServiceInstance> instanceList2 = new ArrayList<>();\n\n    private ServiceDiscoveryRegistry serviceDiscoveryRegistry;\n    private ServiceDiscovery serviceDiscovery;\n    private MockServiceInstancesChangedListener instanceListener;\n    private ServiceNameMapping serviceNameMapping;\n\n    @BeforeAll\n    public static void setUp() {\n        instanceList1.add(new DefaultServiceInstance());\n        instanceList1.add(new DefaultServiceInstance());\n        instanceList1.add(new DefaultServiceInstance());\n\n        instanceList2.add(new DefaultServiceInstance());\n        instanceList2.add(new DefaultServiceInstance());\n    }\n\n    @AfterEach\n    public void teardown() {\n        FrameworkModel.destroyAll();\n    }\n\n    @BeforeEach\n    public void init() {\n        serviceDiscovery = mock(ServiceDiscovery.class);\n        instanceListener = spy(new MockServiceInstancesChangedListener(Collections.emptySet(), serviceDiscovery));\n        doNothing().when(instanceListener).onEvent(any());\n        when(serviceDiscovery.createListener(any())).thenReturn(instanceListener);\n        when(serviceDiscovery.getInstances(any())).thenReturn(Collections.emptyList());\n        when(serviceDiscovery.getUrl()).thenReturn(url);\n        ApplicationModel applicationModel = spy(ApplicationModel.defaultModel());\n        when(applicationModel.getDefaultExtension(ServiceNameMapping.class)).thenReturn(mapping);\n        registryURL = registryURL.setScopeModel(applicationModel);\n\n        serviceDiscoveryRegistry = new ServiceDiscoveryRegistry(registryURL, serviceDiscovery, mapping);\n        when(mapping.getMappingLock(any())).thenReturn(lock);\n        when(testServiceListener.getConsumerUrl()).thenReturn(url);\n    }\n\n    /**\n     * Test subscribe\n     * - Normal case\n     * - Exceptional case\n     *   - check=true\n     *   - check=false\n     */\n    @Test\n    void testDoSubscribe() {\n        ApplicationModel applicationModel = spy(ApplicationModel.defaultModel());\n        when(applicationModel.getDefaultExtension(ServiceNameMapping.class)).thenReturn(mapping);\n        // Exceptional case, no interface-app mapping found\n        when(mapping.getAndListen(any(), any(), any())).thenReturn(Collections.emptySet());\n        // when check = false\n        try {\n            registryURL = registryURL.setScopeModel(applicationModel);\n            serviceDiscoveryRegistry = new ServiceDiscoveryRegistry(registryURL, serviceDiscovery, mapping);\n            serviceDiscoveryRegistry.doSubscribe(url, testServiceListener);\n        } finally {\n            registryURL = registryURL.setScopeModel(null);\n            serviceDiscoveryRegistry.unsubscribe(url, testServiceListener);\n        }\n        //        // when check = true\n        URL checkURL = url.addParameter(CHECK_KEY, true);\n        checkURL.setScopeModel(url.getApplicationModel());\n        //        Exception exceptionShouldHappen = null;\n        //        try {\n        //            serviceDiscoveryRegistry.doSubscribe(checkURL, testServiceListener);\n        //        } catch (IllegalStateException e) {\n        //            exceptionShouldHappen = e;\n        //        } finally {\n        //            serviceDiscoveryRegistry.unsubscribe(checkURL, testServiceListener);\n        //        }\n        //        if (exceptionShouldHappen == null) {\n        //            fail();\n        //        }\n\n        // Normal case\n        Set<String> singleApp = new HashSet<>();\n        singleApp.add(APP_NAME1);\n        when(mapping.getAndListen(any(), any(), any())).thenReturn(singleApp);\n        try {\n            serviceDiscoveryRegistry.doSubscribe(checkURL, testServiceListener);\n        } finally {\n            serviceDiscoveryRegistry.unsubscribe(checkURL, testServiceListener);\n        }\n\n        // test provider case\n        checkURL = url.addParameter(PROVIDED_BY, APP_NAME1);\n\n        try {\n            serviceDiscoveryRegistry.doSubscribe(checkURL, testServiceListener);\n        } finally {\n            serviceDiscoveryRegistry.unsubscribe(checkURL, testServiceListener);\n        }\n    }\n\n    /**\n     * Test instance listener registration\n     * - one app\n     * - multi apps\n     * - repeat same multi apps, instance listener shared\n     * - protocol included in key\n     * - instance listener gets notified\n     * - instance listener and service listener rightly mapped\n     */\n    @Test\n    void testSubscribeURLs() {\n        // interface to single app mapping\n        Set<String> singleApp = new TreeSet<>();\n        singleApp.add(APP_NAME1);\n        serviceDiscoveryRegistry.subscribeURLs(url, testServiceListener, singleApp);\n\n        assertEquals(1, serviceDiscoveryRegistry.getServiceListeners().size());\n        verify(testServiceListener, times(1)).addServiceListener(instanceListener);\n        verify(instanceListener, never()).onEvent(any());\n        verify(serviceDiscovery, times(1)).addServiceInstancesChangedListener(instanceListener);\n\n        // interface to multiple apps mapping\n        Set<String> multiApps = new TreeSet<>();\n        multiApps.add(APP_NAME1);\n        multiApps.add(APP_NAME2);\n        MockServiceInstancesChangedListener multiAppsInstanceListener =\n                spy(new MockServiceInstancesChangedListener(multiApps, serviceDiscovery));\n        doNothing().when(multiAppsInstanceListener).onEvent(any());\n        List<URL> urls = new ArrayList<>();\n        urls.add(URL.valueOf(\"dubbo://127.0.0.1:20880/TestService\"));\n        doReturn(urls).when(multiAppsInstanceListener).getAddresses(any(), any());\n        when(serviceDiscovery.createListener(multiApps)).thenReturn(multiAppsInstanceListener);\n        when(serviceDiscovery.getInstances(APP_NAME1)).thenReturn(instanceList1);\n        when(serviceDiscovery.getInstances(APP_NAME2)).thenReturn(instanceList2);\n        serviceDiscoveryRegistry.subscribeURLs(url, testServiceListener, multiApps);\n\n        assertEquals(2, serviceDiscoveryRegistry.getServiceListeners().size());\n        assertEquals(\n                instanceListener, serviceDiscoveryRegistry.getServiceListeners().get(toStringKeys(singleApp)));\n        assertEquals(\n                multiAppsInstanceListener,\n                serviceDiscoveryRegistry.getServiceListeners().get(toStringKeys(multiApps)));\n        verify(testServiceListener, times(1)).addServiceListener(multiAppsInstanceListener);\n        verify(multiAppsInstanceListener, times(2)).onEvent(any());\n        verify(multiAppsInstanceListener, times(1)).addListenerAndNotify(any(), eq(testServiceListener));\n        verify(serviceDiscovery, times(1)).addServiceInstancesChangedListener(multiAppsInstanceListener);\n        ArgumentCaptor<List<URL>> captor = ArgumentCaptor.forClass(List.class);\n        verify(testServiceListener).notify(captor.capture());\n        assertEquals(urls, captor.getValue());\n\n        // different interface mapping to the same apps\n        NotifyListener testServiceListener2 = mock(NotifyListener.class);\n        URL url2 = URL.valueOf(\"tri://127.0.0.1/TestService2?interface=TestService2&check=false&protocol=tri\");\n        when(testServiceListener2.getConsumerUrl()).thenReturn(url2);\n        serviceDiscoveryRegistry.subscribeURLs(url2, testServiceListener2, multiApps);\n        // check instance listeners not changed, methods not called\n        assertEquals(2, serviceDiscoveryRegistry.getServiceListeners().size());\n        assertEquals(\n                multiAppsInstanceListener,\n                serviceDiscoveryRegistry.getServiceListeners().get(toStringKeys(multiApps)));\n        verify(multiAppsInstanceListener, times(1)).addListenerAndNotify(any(), eq(testServiceListener));\n        // still called once, not executed this time\n        verify(serviceDiscovery, times(2)).addServiceInstancesChangedListener(multiAppsInstanceListener);\n        // check different protocol\n        Map<String, Set<ServiceInstancesChangedListener.NotifyListenerWithKey>> serviceListeners =\n                multiAppsInstanceListener.getServiceListeners();\n        assertEquals(2, serviceListeners.size());\n        assertEquals(1, serviceListeners.get(url.getServiceKey()).size());\n        assertEquals(1, serviceListeners.get(url2.getServiceKey()).size());\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(\n                url2.getServiceInterface(), url2.getVersion(), url2.getGroup(), url2.getParameter(PROTOCOL_KEY, DUBBO));\n        assertTrue(serviceListeners\n                .get(url2.getServiceKey())\n                .contains(new ServiceInstancesChangedListener.NotifyListenerWithKey(\n                        protocolServiceKey, testServiceListener2)));\n    }\n\n    /**\n     * repeat of {@link this#testSubscribeURLs()} with multi threads\n     */\n    @Test\n    void testConcurrencySubscribe() {\n        // TODO\n    }\n\n    @Test\n    void testUnsubscribe() {\n        // do subscribe to prepare for unsubscribe verification\n        Set<String> multiApps = new TreeSet<>();\n        multiApps.add(APP_NAME1);\n        multiApps.add(APP_NAME2);\n        NotifyListener testServiceListener2 = mock(NotifyListener.class);\n        URL url2 = URL.valueOf(\"consumer://127.0.0.1/TestService2?interface=TestService1&check=false&protocol=tri\");\n        when(testServiceListener2.getConsumerUrl()).thenReturn(url2);\n        serviceDiscoveryRegistry.subscribeURLs(url, testServiceListener, multiApps);\n        serviceDiscoveryRegistry.subscribeURLs(url2, testServiceListener2, multiApps);\n        assertEquals(1, serviceDiscoveryRegistry.getServiceListeners().size());\n\n        // do unsubscribe\n        when(mapping.getMapping(url2)).thenReturn(multiApps);\n        serviceDiscoveryRegistry.doUnsubscribe(url2, testServiceListener2);\n        assertEquals(1, serviceDiscoveryRegistry.getServiceListeners().size());\n        ServiceInstancesChangedListener instancesChangedListener = serviceDiscoveryRegistry\n                .getServiceListeners()\n                .entrySet()\n                .iterator()\n                .next()\n                .getValue();\n        assertTrue(instancesChangedListener.hasListeners());\n        when(mapping.getMapping(url)).thenReturn(multiApps);\n        serviceDiscoveryRegistry.doUnsubscribe(url, testServiceListener);\n        assertEquals(0, serviceDiscoveryRegistry.getServiceListeners().size());\n        assertFalse(instancesChangedListener.hasListeners());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/MockServiceInstancesChangedListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.event.listener;\n\nimport org.apache.dubbo.common.ProtocolServiceKey;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class MockServiceInstancesChangedListener extends ServiceInstancesChangedListener {\n    public MockServiceInstancesChangedListener(Set<String> serviceNames, ServiceDiscovery serviceDiscovery) {\n        super(serviceNames, serviceDiscovery);\n    }\n\n    @Override\n    public synchronized void onEvent(ServiceInstancesChangedEvent event) {\n        // do nothing\n    }\n\n    @Override\n    public List<URL> getAddresses(ProtocolServiceKey protocolServiceKey, URL consumerURL) {\n        return super.getAddresses(protocolServiceKey, consumerURL);\n    }\n\n    public Map<String, Set<NotifyListenerWithKey>> getServiceListeners() {\n        return listeners;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.event.listener;\n\nimport org.apache.dubbo.common.ProtocolServiceKey;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.LRUCache;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.InstanceAddressURL;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.metadata.store.MetaCacheManager;\nimport org.apache.dubbo.registry.client.support.MockServiceDiscovery;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.MethodOrderer;\nimport org.junit.jupiter.api.Order;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestMethodOrder;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;\nimport static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;\nimport static org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.anyList;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.when;\n\n/**\n * {@link ServiceInstancesChangedListener} Test\n *\n * @since 2.7.5\n */\n@TestMethodOrder(MethodOrderer.OrderAnnotation.class)\nclass ServiceInstancesChangedListenerTest {\n\n    static List<ServiceInstance> app1Instances;\n    static List<ServiceInstance> app2Instances;\n    static List<ServiceInstance> app1FailedInstances;\n    static List<ServiceInstance> app1FailedInstances2;\n    static List<ServiceInstance> app1InstancesWithNoRevision;\n    static List<ServiceInstance> app1InstancesMultipleProtocols;\n\n    static String metadata_111 = \"{\\\"app\\\":\\\"app1\\\",\\\"revision\\\":\\\"111\\\",\\\"services\\\":{\"\n            + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app1\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n            + \"}}\";\n    static String metadata_222 = \"{\\\"app\\\":\\\"app2\\\",\\\"revision\\\":\\\"222\\\",\\\"services\\\":{\"\n            + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}},\"\n            + \"\\\"org.apache.dubbo.demo.DemoService2:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n            + \"}}\";\n    static String metadata_333 = \"{\\\"app\\\":\\\"app2\\\",\\\"revision\\\":\\\"333\\\",\\\"services\\\":{\"\n            + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}},\"\n            + \"\\\"org.apache.dubbo.demo.DemoService2:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}},\"\n            + \"\\\"org.apache.dubbo.demo.DemoService3:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService3\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService3\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService3\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n            + \"}}\";\n    // failed\n    static String metadata_444 = \"{\\\"app\\\":\\\"app1\\\",\\\"revision\\\":\\\"444\\\",\\\"services\\\":{\"\n            + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n            + \"}}\";\n    // only triple protocol enabled\n    static String metadata_555_triple = \"{\\\"app\\\":\\\"app1\\\",\\\"revision\\\":\\\"555\\\",\\\"services\\\":{\"\n            + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"tri\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n            + \"}}\";\n\n    static String service1 = \"org.apache.dubbo.demo.DemoService\";\n    static String service2 = \"org.apache.dubbo.demo.DemoService2\";\n    static String service3 = \"org.apache.dubbo.demo.DemoService3\";\n\n    static URL consumerURL = URL.valueOf(\n            \"dubbo://127.0.0.1/org.apache.dubbo.demo.DemoService?interface=org.apache.dubbo.demo.DemoService&protocol=dubbo&registry_cluster=default\");\n    static URL consumerURL2 = URL.valueOf(\n            \"dubbo://127.0.0.1/org.apache.dubbo.demo.DemoService2?interface=org.apache.dubbo.demo.DemoService2&protocol=dubbo&registry_cluster=default\");\n    static URL consumerURL3 = URL.valueOf(\n            \"dubbo://127.0.0.1/org.apache.dubbo.demo.DemoService3?interface=org.apache.dubbo.demo.DemoService3&protocol=dubbo&registry_cluster=default\");\n    static URL multipleProtocolsConsumerURL = URL.valueOf(\n            \"dubbo,tri://127.0.0.1/org.apache.dubbo.demo.DemoService?interface=org.apache.dubbo.demo.DemoService&protocol=dubbo,tri&registry_cluster=default\");\n    static URL noProtocolConsumerURL = URL.valueOf(\n            \"consumer://127.0.0.1/org.apache.dubbo.demo.DemoService?interface=org.apache.dubbo.demo.DemoService&registry_cluster=default\");\n    static URL singleProtocolsConsumerURL = URL.valueOf(\n            \"tri://127.0.0.1/org.apache.dubbo.demo.DemoService?interface=org.apache.dubbo.demo.DemoService&protocol=tri&registry_cluster=default\");\n    static URL registryURL =\n            URL.valueOf(\"dubbo://127.0.0.1:2181/org.apache.dubbo.demo.RegistryService?enable-empty-protection=true\");\n\n    static MetadataInfo metadataInfo_111;\n    static MetadataInfo metadataInfo_222;\n    static MetadataInfo metadataInfo_333;\n    static MetadataInfo metadataInfo_444;\n    static MetadataInfo metadataInfo_555_tri;\n\n    static MetadataService metadataService;\n\n    static ServiceDiscovery serviceDiscovery;\n\n    static ServiceInstancesChangedListener listener = null;\n\n    @BeforeAll\n    public static void setUp() {\n\n        metadataService = Mockito.mock(MetadataService.class);\n\n        List<Object> urlsSameRevision = new ArrayList<>();\n        urlsSameRevision.add(\"127.0.0.1:20880?revision=111\");\n        urlsSameRevision.add(\"127.0.0.2:20880?revision=111\");\n        urlsSameRevision.add(\"127.0.0.3:20880?revision=111\");\n\n        List<Object> urlsDifferentRevision = new ArrayList<>();\n        urlsDifferentRevision.add(\"30.10.0.1:20880?revision=222\");\n        urlsDifferentRevision.add(\"30.10.0.2:20880?revision=222\");\n        urlsDifferentRevision.add(\"30.10.0.3:20880?revision=333\");\n        urlsDifferentRevision.add(\"30.10.0.4:20880?revision=333\");\n\n        List<Object> urlsFailedRevision = new ArrayList<>();\n        urlsFailedRevision.add(\"30.10.0.5:20880?revision=222\");\n        urlsFailedRevision.add(\"30.10.0.6:20880?revision=222\");\n        urlsFailedRevision.add(\"30.10.0.7:20880?revision=444\"); // revision will fail\n        urlsFailedRevision.add(\"30.10.0.8:20880?revision=444\"); // revision will fail\n\n        List<Object> urlsFailedRevision2 = new ArrayList<>();\n        urlsFailedRevision2.add(\"30.10.0.1:20880?revision=222\");\n        urlsFailedRevision2.add(\"30.10.0.2:20880?revision=222\");\n\n        List<Object> urlsWithoutRevision = new ArrayList<>();\n        urlsWithoutRevision.add(\"30.10.0.1:20880\");\n\n        List<Object> urlsMultipleProtocols = new ArrayList<>();\n        urlsMultipleProtocols.add(\"30.10.0.1:20880?revision=555\"); // triple\n        urlsMultipleProtocols.addAll(urlsSameRevision); // dubbo\n\n        app1Instances = buildInstances(urlsSameRevision);\n        app2Instances = buildInstances(urlsDifferentRevision);\n        app1FailedInstances = buildInstances(urlsFailedRevision);\n        app1FailedInstances2 = buildInstances(urlsFailedRevision2);\n        app1InstancesWithNoRevision = buildInstances(urlsWithoutRevision);\n        app1InstancesMultipleProtocols = buildInstances(urlsMultipleProtocols);\n\n        metadataInfo_111 = JsonUtils.toJavaObject(metadata_111, MetadataInfo.class);\n        metadataInfo_222 = JsonUtils.toJavaObject(metadata_222, MetadataInfo.class);\n        metadataInfo_333 = JsonUtils.toJavaObject(metadata_333, MetadataInfo.class);\n        metadataInfo_444 = JsonUtils.toJavaObject(metadata_444, MetadataInfo.class);\n        metadataInfo_555_tri = JsonUtils.toJavaObject(metadata_555_triple, MetadataInfo.class);\n\n        serviceDiscovery = Mockito.mock(ServiceDiscovery.class);\n        when(serviceDiscovery.getUrl()).thenReturn(registryURL);\n\n        when(serviceDiscovery.getRemoteMetadata(eq(\"111\"), anyList())).thenReturn(metadataInfo_111);\n        when(serviceDiscovery.getRemoteMetadata(eq(\"222\"), anyList())).thenReturn(metadataInfo_222);\n        when(serviceDiscovery.getRemoteMetadata(eq(\"333\"), anyList())).thenReturn(metadataInfo_333);\n        when(serviceDiscovery.getRemoteMetadata(eq(\"444\"), anyList())).thenReturn(MetadataInfo.EMPTY);\n        when(serviceDiscovery.getRemoteMetadata(eq(\"555\"), anyList())).thenReturn(metadataInfo_555_tri);\n    }\n\n    @BeforeEach\n    public void init() {\n        // Because all tests use the same ServiceDiscovery, the previous metadataCache should be cleared before next\n        // unit test\n        // to avoid contaminating next unit test.\n        clearMetadataCache();\n    }\n\n    @AfterEach\n    public void tearDown() throws Exception {\n        if (listener != null) {\n            listener.destroy();\n            listener = null;\n        }\n    }\n\n    @AfterAll\n    public static void destroy() throws Exception {\n        serviceDiscovery.destroy();\n    }\n\n    // 正常场景。单应用app1 通知地址基本流程，只做instance-metadata关联，没有metadata内容的解析\n    @Test\n    @Order(1)\n    public void testInstanceNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(event);\n\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(1, allInstances.size());\n        Assertions.assertEquals(3, allInstances.get(\"app1\").size());\n\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n    }\n\n    // 正常场景。单应用app1，进一步检查 metadata service 是否正确映射\n    @Test\n    @Order(2)\n    public void testInstanceNotificationAndMetadataParse() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify instance change\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(event);\n\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(1, allInstances.size());\n        Assertions.assertEquals(3, allInstances.get(\"app1\").size());\n\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        assertThat(serviceUrls, Matchers.hasItem(Matchers.hasProperty(\"instance\", Matchers.notNullValue())));\n        assertThat(serviceUrls, Matchers.hasItem(Matchers.hasProperty(\"metadataInfo\", Matchers.notNullValue())));\n    }\n\n    // 正常场景。多应用，app1 app2 分别通知地址\n    @Test\n    @Order(3)\n    public void testMultipleAppNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        serviceNames.add(\"app2\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify app1 instance change\n        ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(app1_event);\n\n        // notify app2 instance change\n        ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent(\"app2\", app2Instances);\n        listener.onEvent(app2_event);\n\n        // check\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(2, allInstances.size());\n        Assertions.assertEquals(3, allInstances.get(\"app1\").size());\n        Assertions.assertEquals(4, allInstances.get(\"app2\").size());\n\n        ProtocolServiceKey protocolServiceKey1 = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey2 = new ProtocolServiceKey(service2, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey3 = new ProtocolServiceKey(service3, null, null, \"dubbo\");\n\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey1, consumerURL);\n        Assertions.assertEquals(7, serviceUrls.size());\n        List<URL> serviceUrls2 = listener.getAddresses(protocolServiceKey2, consumerURL);\n        Assertions.assertEquals(4, serviceUrls2.size());\n        assertTrue(serviceUrls2.get(0).getIp().contains(\"30.10.\"));\n        List<URL> serviceUrls3 = listener.getAddresses(protocolServiceKey3, consumerURL);\n        Assertions.assertEquals(2, serviceUrls3.size());\n        assertTrue(serviceUrls3.get(0).getIp().contains(\"30.10.\"));\n    }\n\n    // 正常场景。多应用，app1 app2，空地址通知（边界条件）能否解析出正确的空地址列表\n    @Test\n    @Order(4)\n    public void testMultipleAppEmptyNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        serviceNames.add(\"app2\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify app1 instance change\n        ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(app1_event);\n\n        // notify app2 instance change\n        ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent(\"app2\", app2Instances);\n        listener.onEvent(app2_event);\n\n        // empty notification\n        ServiceInstancesChangedEvent app1_event_again =\n                new ServiceInstancesChangedEvent(\"app1\", Collections.EMPTY_LIST);\n        listener.onEvent(app1_event_again);\n\n        // check app1 cleared\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(2, allInstances.size());\n        Assertions.assertEquals(0, allInstances.get(\"app1\").size());\n        Assertions.assertEquals(4, allInstances.get(\"app2\").size());\n\n        ProtocolServiceKey protocolServiceKey1 = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey2 = new ProtocolServiceKey(service2, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey3 = new ProtocolServiceKey(service3, null, null, \"dubbo\");\n\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey1, consumerURL);\n        Assertions.assertEquals(4, serviceUrls.size());\n        assertTrue(serviceUrls.get(0).getIp().contains(\"30.10.\"));\n        List<URL> serviceUrls2 = listener.getAddresses(protocolServiceKey2, consumerURL);\n        Assertions.assertEquals(4, serviceUrls2.size());\n        assertTrue(serviceUrls2.get(0).getIp().contains(\"30.10.\"));\n        List<URL> serviceUrls3 = listener.getAddresses(protocolServiceKey3, consumerURL);\n        Assertions.assertEquals(2, serviceUrls3.size());\n        assertTrue(serviceUrls3.get(0).getIp().contains(\"30.10.\"));\n\n        // app2 empty notification\n        ServiceInstancesChangedEvent app2_event_again =\n                new ServiceInstancesChangedEvent(\"app2\", Collections.EMPTY_LIST);\n        listener.onEvent(app2_event_again);\n\n        // check app2 cleared\n        Map<String, List<ServiceInstance>> allInstances_app2 = listener.getAllInstances();\n        Assertions.assertEquals(2, allInstances_app2.size());\n        Assertions.assertEquals(0, allInstances_app2.get(\"app1\").size());\n        Assertions.assertEquals(0, allInstances_app2.get(\"app2\").size());\n\n        assertTrue(isEmpty(listener.getAddresses(protocolServiceKey1, consumerURL)));\n        assertTrue(isEmpty(listener.getAddresses(protocolServiceKey2, consumerURL)));\n        assertTrue(isEmpty(listener.getAddresses(protocolServiceKey3, consumerURL)));\n    }\n\n    // 正常场景。检查instance listener -> service listener(Directory)地址推送流程\n    @Test\n    @Order(5)\n    public void testServiceListenerNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        serviceNames.add(\"app2\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        NotifyListener demoServiceListener = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener.getConsumerUrl()).thenReturn(consumerURL);\n        NotifyListener demoService2Listener = Mockito.mock(NotifyListener.class);\n        when(demoService2Listener.getConsumerUrl()).thenReturn(consumerURL2);\n        listener.addListenerAndNotify(consumerURL, demoServiceListener);\n        listener.addListenerAndNotify(consumerURL2, demoService2Listener);\n        // notify app1 instance change\n        ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(app1_event);\n\n        // check\n        ArgumentCaptor<List<URL>> captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener, Mockito.times(1)).notify(captor.capture());\n        List<URL> notifiedUrls = captor.getValue();\n        Assertions.assertEquals(3, notifiedUrls.size());\n        ArgumentCaptor<List<URL>> captor2 = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoService2Listener, Mockito.times(1)).notify(captor2.capture());\n        List<URL> notifiedUrls2 = captor2.getValue();\n        Assertions.assertEquals(0, notifiedUrls2.size());\n\n        // notify app2 instance change\n        ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent(\"app2\", app2Instances);\n        listener.onEvent(app2_event);\n\n        // check\n        ArgumentCaptor<List<URL>> app2_captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener, Mockito.times(2)).notify(app2_captor.capture());\n        List<URL> app2_notifiedUrls = app2_captor.getValue();\n        Assertions.assertEquals(7, app2_notifiedUrls.size());\n        ArgumentCaptor<List<URL>> app2_captor2 = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoService2Listener, Mockito.times(2)).notify(app2_captor2.capture());\n        List<URL> app2_notifiedUrls2 = app2_captor2.getValue();\n        Assertions.assertEquals(4, app2_notifiedUrls2.size());\n\n        // test service listener still get notified when added after instance notification.\n        NotifyListener demoService3Listener = Mockito.mock(NotifyListener.class);\n        when(demoService3Listener.getConsumerUrl()).thenReturn(consumerURL3);\n        listener.addListenerAndNotify(consumerURL3, demoService3Listener);\n        Mockito.verify(demoService3Listener, Mockito.times(1)).notify(Mockito.anyList());\n    }\n\n    @Test\n    @Order(6)\n    public void testMultiServiceListenerNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        serviceNames.add(\"app2\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        NotifyListener demoServiceListener1 = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener1.getConsumerUrl()).thenReturn(consumerURL);\n        NotifyListener demoServiceListener2 = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener2.getConsumerUrl()).thenReturn(consumerURL);\n        NotifyListener demoService2Listener1 = Mockito.mock(NotifyListener.class);\n        when(demoService2Listener1.getConsumerUrl()).thenReturn(consumerURL2);\n        NotifyListener demoService2Listener2 = Mockito.mock(NotifyListener.class);\n        when(demoService2Listener2.getConsumerUrl()).thenReturn(consumerURL2);\n        listener.addListenerAndNotify(consumerURL, demoServiceListener1);\n        listener.addListenerAndNotify(consumerURL, demoServiceListener2);\n        listener.addListenerAndNotify(consumerURL2, demoService2Listener1);\n        listener.addListenerAndNotify(consumerURL2, demoService2Listener2);\n        // notify app1 instance change\n        ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(app1_event);\n\n        // check\n        ArgumentCaptor<List<URL>> captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener1, Mockito.times(1)).notify(captor.capture());\n        List<URL> notifiedUrls = captor.getValue();\n        Assertions.assertEquals(3, notifiedUrls.size());\n        ArgumentCaptor<List<URL>> captor2 = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoService2Listener1, Mockito.times(1)).notify(captor2.capture());\n        List<URL> notifiedUrls2 = captor2.getValue();\n        Assertions.assertEquals(0, notifiedUrls2.size());\n\n        // notify app2 instance change\n        ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent(\"app2\", app2Instances);\n        listener.onEvent(app2_event);\n\n        // check\n        ArgumentCaptor<List<URL>> app2_captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener1, Mockito.times(2)).notify(app2_captor.capture());\n        List<URL> app2_notifiedUrls = app2_captor.getValue();\n        Assertions.assertEquals(7, app2_notifiedUrls.size());\n        ArgumentCaptor<List<URL>> app2_captor2 = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoService2Listener1, Mockito.times(2)).notify(app2_captor2.capture());\n        List<URL> app2_notifiedUrls2 = app2_captor2.getValue();\n        Assertions.assertEquals(4, app2_notifiedUrls2.size());\n\n        // test service listener still get notified when added after instance notification.\n        NotifyListener demoService3Listener = Mockito.mock(NotifyListener.class);\n        when(demoService3Listener.getConsumerUrl()).thenReturn(consumerURL3);\n        listener.addListenerAndNotify(consumerURL3, demoService3Listener);\n        Mockito.verify(demoService3Listener, Mockito.times(1)).notify(Mockito.anyList());\n    }\n\n    /**\n     * Test subscribe multiple protocols\n     */\n    @Test\n    @Order(7)\n    public void testSubscribeMultipleProtocols() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        // no protocol specified, consume all instances\n        NotifyListener demoServiceListener1 = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener1.getConsumerUrl()).thenReturn(noProtocolConsumerURL);\n        listener.addListenerAndNotify(noProtocolConsumerURL, demoServiceListener1);\n        // multiple protocols specified\n        NotifyListener demoServiceListener2 = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener2.getConsumerUrl()).thenReturn(multipleProtocolsConsumerURL);\n        listener.addListenerAndNotify(multipleProtocolsConsumerURL, demoServiceListener2);\n        // one protocol specified\n        NotifyListener demoServiceListener3 = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener3.getConsumerUrl()).thenReturn(singleProtocolsConsumerURL);\n        listener.addListenerAndNotify(singleProtocolsConsumerURL, demoServiceListener3);\n\n        // notify app1 instance change\n        ServiceInstancesChangedEvent app1_event =\n                new ServiceInstancesChangedEvent(\"app1\", app1InstancesMultipleProtocols);\n        listener.onEvent(app1_event);\n\n        // check instances expose framework supported default protocols(currently dubbo, triple and rest) are notified\n        ArgumentCaptor<List<URL>> default_protocol_captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener1, Mockito.times(1)).notify(default_protocol_captor.capture());\n        List<URL> default_protocol_notifiedUrls = default_protocol_captor.getValue();\n        Assertions.assertEquals(4, default_protocol_notifiedUrls.size());\n        // check instances expose protocols in consuming list(dubbo and triple) are notified\n        ArgumentCaptor<List<URL>> multi_protocols_captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener2, Mockito.times(1)).notify(multi_protocols_captor.capture());\n        List<URL> multi_protocol_notifiedUrls = multi_protocols_captor.getValue();\n        Assertions.assertEquals(4, multi_protocol_notifiedUrls.size());\n        // check instances expose protocols in consuming list(only triple) are notified\n        ArgumentCaptor<List<URL>> single_protocols_captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener3, Mockito.times(1)).notify(single_protocols_captor.capture());\n        List<URL> single_protocol_notifiedUrls = single_protocols_captor.getValue();\n        Assertions.assertEquals(1, single_protocol_notifiedUrls.size());\n    }\n\n    /**\n     * Test subscribe multiple groups\n     */\n    @Test\n    @Order(8)\n    public void testSubscribeMultipleGroups() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify instance change\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(event);\n\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(1, allInstances.size());\n        Assertions.assertEquals(3, allInstances.get(\"app1\").size());\n\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \",group1\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"group1,\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"*\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"group1\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(0, serviceUrls.size());\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"group1,group2\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(0, serviceUrls.size());\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"group1,,group2\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n    }\n\n    /**\n     * Test subscribe multiple versions\n     */\n    @Test\n    @Order(9)\n    public void testSubscribeMultipleVersions() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify instance change\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(event);\n\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(1, allInstances.size());\n        Assertions.assertEquals(3, allInstances.get(\"app1\").size());\n\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \"\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \"*\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \",1.0.0\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \"1.0.0,\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \"1.0.0,,1.0.1\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \"1.0.1,1.0.0\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(0, serviceUrls.size());\n    }\n\n    // revision 异常场景。第一次启动，完全拿不到metadata，只能通知部分地址\n    @Test\n    @Order(10)\n    public void testRevisionFailureOnStartup() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        // notify app1 instance change\n        ServiceInstancesChangedEvent failed_revision_event =\n                new ServiceInstancesChangedEvent(\"app1\", app1FailedInstances);\n        listener.onEvent(failed_revision_event);\n\n        ProtocolServiceKey protocolServiceKey1 = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey2 = new ProtocolServiceKey(service2, null, null, \"dubbo\");\n\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey1, consumerURL);\n        List<URL> serviceUrls2 = listener.getAddresses(protocolServiceKey2, consumerURL);\n\n        assertTrue(isNotEmpty(serviceUrls));\n        assertTrue(isNotEmpty(serviceUrls2));\n    }\n\n    // revision 异常场景。运行中地址通知，拿不到revision就用老版本revision\n    @Test\n    @Order(11)\n    public void testRevisionFailureOnNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        serviceNames.add(\"app2\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify app1 instance change\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(event);\n\n        when(serviceDiscovery.getRemoteMetadata(eq(\"222\"), anyList())).thenAnswer(new Answer<MetadataInfo>() {\n            @Override\n            public MetadataInfo answer(InvocationOnMock invocationOnMock) throws Throwable {\n                if (Thread.currentThread().getName().contains(\"Dubbo-framework-metadata-retry\")) {\n                    return metadataInfo_222;\n                }\n                return MetadataInfo.EMPTY;\n            }\n        });\n\n        ServiceInstancesChangedEvent event2 = new ServiceInstancesChangedEvent(\"app2\", app1FailedInstances2);\n        listener.onEvent(event2);\n\n        // event2 did not really take effect\n        ProtocolServiceKey protocolServiceKey1 = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey2 = new ProtocolServiceKey(service2, null, null, \"dubbo\");\n\n        Assertions.assertEquals(\n                3, listener.getAddresses(protocolServiceKey1, consumerURL).size());\n        assertTrue(isEmpty(listener.getAddresses(protocolServiceKey2, consumerURL)));\n\n        //\n        init();\n\n        try {\n            Thread.sleep(15000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        // check recovered after retry.\n        List<URL> serviceUrls_after_retry = listener.getAddresses(protocolServiceKey1, consumerURL);\n        Assertions.assertEquals(5, serviceUrls_after_retry.size());\n        List<URL> serviceUrls2_after_retry = listener.getAddresses(protocolServiceKey2, consumerURL);\n        Assertions.assertEquals(2, serviceUrls2_after_retry.size());\n    }\n\n    // Abnormal case. Instance does not have revision\n    @Test\n    @Order(12)\n    public void testInstanceWithoutRevision() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        ServiceDiscovery serviceDiscovery = Mockito.mock(ServiceDiscovery.class);\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        ServiceInstancesChangedListener spyListener = Mockito.spy(listener);\n        Mockito.doReturn(null).when(metadataService).getMetadataInfo(eq(null));\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1InstancesWithNoRevision);\n        spyListener.onEvent(event);\n        // notification succeeded\n        assertTrue(true);\n    }\n\n    Set<String> getExpectedSet(List<String> list) {\n        return new HashSet<>(list);\n    }\n\n    static List<ServiceInstance> buildInstances(List<Object> rawURls) {\n        List<ServiceInstance> instances = new ArrayList<>();\n\n        for (Object obj : rawURls) {\n            String rawURL = (String) obj;\n            DefaultServiceInstance instance = new DefaultServiceInstance();\n            final URL dubboUrl = URL.valueOf(rawURL);\n            instance.setRawAddress(rawURL);\n            instance.setHost(dubboUrl.getHost());\n            instance.setEnabled(true);\n            instance.setHealthy(true);\n            instance.setPort(dubboUrl.getPort());\n            instance.setRegistryCluster(\"default\");\n            instance.setApplicationModel(ApplicationModel.defaultModel());\n\n            Map<String, String> metadata = new HashMap<>();\n            if (StringUtils.isNotEmpty(dubboUrl.getParameter(REVISION_KEY))) {\n                metadata.put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, dubboUrl.getParameter(REVISION_KEY));\n            }\n            instance.setMetadata(metadata);\n\n            instances.add(instance);\n        }\n\n        return instances;\n    }\n\n    private void clearMetadataCache() {\n        try {\n            MockServiceDiscovery mockServiceDiscovery =\n                    (MockServiceDiscovery) ServiceInstancesChangedListenerTest.serviceDiscovery;\n            MetaCacheManager metaCacheManager = mockServiceDiscovery.getMetaCacheManager();\n            Field cacheField = metaCacheManager.getClass().getDeclaredField(\"cache\");\n            cacheField.setAccessible(true);\n            LRUCache<String, MetadataInfo> cache = (LRUCache<String, MetadataInfo>) cacheField.get(metaCacheManager);\n            cache.clear();\n            cacheField.setAccessible(false);\n        } catch (Exception e) {\n            // ignore\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListenerWithoutEmptyProtectTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.event.listener;\n\nimport org.apache.dubbo.common.ProtocolServiceKey;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.LRUCache;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.InstanceAddressURL;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.metadata.store.MetaCacheManager;\nimport org.apache.dubbo.registry.client.support.MockServiceDiscovery;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.MethodOrderer;\nimport org.junit.jupiter.api.Order;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestMethodOrder;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;\nimport static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;\nimport static org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.anyList;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.when;\n\n/**\n * {@link ServiceInstancesChangedListener} Test\n *\n * @since 2.7.5\n */\n@TestMethodOrder(MethodOrderer.OrderAnnotation.class)\npublic class ServiceInstancesChangedListenerWithoutEmptyProtectTest {\n\n    static List<ServiceInstance> app1Instances;\n    static List<ServiceInstance> app2Instances;\n    static List<ServiceInstance> app1FailedInstances;\n    static List<ServiceInstance> app1FailedInstances2;\n    static List<ServiceInstance> app1InstancesWithNoRevision;\n    static List<ServiceInstance> app1InstancesMultipleProtocols;\n\n    static String metadata_111 = \"{\\\"app\\\":\\\"app1\\\",\\\"revision\\\":\\\"111\\\",\\\"services\\\":{\"\n            + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app1\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n            + \"}}\";\n    static String metadata_222 = \"{\\\"app\\\":\\\"app2\\\",\\\"revision\\\":\\\"222\\\",\\\"services\\\":{\"\n            + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}},\"\n            + \"\\\"org.apache.dubbo.demo.DemoService2:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n            + \"}}\";\n    static String metadata_333 = \"{\\\"app\\\":\\\"app2\\\",\\\"revision\\\":\\\"333\\\",\\\"services\\\":{\"\n            + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}},\"\n            + \"\\\"org.apache.dubbo.demo.DemoService2:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService2\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}},\"\n            + \"\\\"org.apache.dubbo.demo.DemoService3:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService3\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService3\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService3\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n            + \"}}\";\n    // failed\n    static String metadata_444 = \"{\\\"app\\\":\\\"app1\\\",\\\"revision\\\":\\\"444\\\",\\\"services\\\":{\"\n            + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n            + \"}}\";\n    // only triple protocol enabled\n    static String metadata_555_triple = \"{\\\"app\\\":\\\"app1\\\",\\\"revision\\\":\\\"555\\\",\\\"services\\\":{\"\n            + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"tri\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app2\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n            + \"}}\";\n\n    static String service1 = \"org.apache.dubbo.demo.DemoService\";\n    static String service2 = \"org.apache.dubbo.demo.DemoService2\";\n    static String service3 = \"org.apache.dubbo.demo.DemoService3\";\n\n    static URL consumerURL = URL.valueOf(\n            \"dubbo://127.0.0.1/org.apache.dubbo.demo.DemoService?interface=org.apache.dubbo.demo.DemoService&protocol=dubbo&registry_cluster=default\");\n    static URL consumerURL2 = URL.valueOf(\n            \"dubbo://127.0.0.1/org.apache.dubbo.demo.DemoService2?interface=org.apache.dubbo.demo.DemoService2&protocol=dubbo&registry_cluster=default\");\n    static URL consumerURL3 = URL.valueOf(\n            \"dubbo://127.0.0.1/org.apache.dubbo.demo.DemoService3?interface=org.apache.dubbo.demo.DemoService3&protocol=dubbo&registry_cluster=default\");\n    static URL multipleProtocolsConsumerURL = URL.valueOf(\n            \"dubbo,tri://127.0.0.1/org.apache.dubbo.demo.DemoService?interface=org.apache.dubbo.demo.DemoService&protocol=dubbo,tri&registry_cluster=default\");\n    static URL noProtocolConsumerURL = URL.valueOf(\n            \"consumer://127.0.0.1/org.apache.dubbo.demo.DemoService?interface=org.apache.dubbo.demo.DemoService&registry_cluster=default\");\n    static URL singleProtocolsConsumerURL = URL.valueOf(\n            \"tri://127.0.0.1/org.apache.dubbo.demo.DemoService?interface=org.apache.dubbo.demo.DemoService&protocol=tri&registry_cluster=default\");\n    static URL registryURL = URL.valueOf(\"dubbo://127.0.0.1:2181/org.apache.dubbo.demo.RegistryService\");\n\n    static MetadataInfo metadataInfo_111;\n    static MetadataInfo metadataInfo_222;\n    static MetadataInfo metadataInfo_333;\n    static MetadataInfo metadataInfo_444;\n    static MetadataInfo metadataInfo_555_tri;\n\n    static MetadataService metadataService;\n\n    static ServiceDiscovery serviceDiscovery;\n\n    static ServiceInstancesChangedListener listener = null;\n\n    @BeforeAll\n    public static void setUp() {\n\n        metadataService = Mockito.mock(MetadataService.class);\n\n        List<Object> urlsSameRevision = new ArrayList<>();\n        urlsSameRevision.add(\"127.0.0.1:20880?revision=111\");\n        urlsSameRevision.add(\"127.0.0.2:20880?revision=111\");\n        urlsSameRevision.add(\"127.0.0.3:20880?revision=111\");\n\n        List<Object> urlsDifferentRevision = new ArrayList<>();\n        urlsDifferentRevision.add(\"30.10.0.1:20880?revision=222\");\n        urlsDifferentRevision.add(\"30.10.0.2:20880?revision=222\");\n        urlsDifferentRevision.add(\"30.10.0.3:20880?revision=333\");\n        urlsDifferentRevision.add(\"30.10.0.4:20880?revision=333\");\n\n        List<Object> urlsFailedRevision = new ArrayList<>();\n        urlsFailedRevision.add(\"30.10.0.5:20880?revision=222\");\n        urlsFailedRevision.add(\"30.10.0.6:20880?revision=222\");\n        urlsFailedRevision.add(\"30.10.0.7:20880?revision=444\"); // revision will fail\n        urlsFailedRevision.add(\"30.10.0.8:20880?revision=444\"); // revision will fail\n\n        List<Object> urlsFailedRevision2 = new ArrayList<>();\n        urlsFailedRevision2.add(\"30.10.0.1:20880?revision=222\");\n        urlsFailedRevision2.add(\"30.10.0.2:20880?revision=222\");\n\n        List<Object> urlsWithoutRevision = new ArrayList<>();\n        urlsWithoutRevision.add(\"30.10.0.1:20880\");\n\n        List<Object> urlsMultipleProtocols = new ArrayList<>();\n        urlsMultipleProtocols.add(\"30.10.0.1:20880?revision=555\"); // triple\n        urlsMultipleProtocols.addAll(urlsSameRevision); // dubbo\n\n        app1Instances = buildInstances(urlsSameRevision);\n        app2Instances = buildInstances(urlsDifferentRevision);\n        app1FailedInstances = buildInstances(urlsFailedRevision);\n        app1FailedInstances2 = buildInstances(urlsFailedRevision2);\n        app1InstancesWithNoRevision = buildInstances(urlsWithoutRevision);\n        app1InstancesMultipleProtocols = buildInstances(urlsMultipleProtocols);\n\n        metadataInfo_111 = JsonUtils.toJavaObject(metadata_111, MetadataInfo.class);\n        metadataInfo_222 = JsonUtils.toJavaObject(metadata_222, MetadataInfo.class);\n        metadataInfo_333 = JsonUtils.toJavaObject(metadata_333, MetadataInfo.class);\n        metadataInfo_444 = JsonUtils.toJavaObject(metadata_444, MetadataInfo.class);\n        metadataInfo_555_tri = JsonUtils.toJavaObject(metadata_555_triple, MetadataInfo.class);\n\n        serviceDiscovery = Mockito.mock(ServiceDiscovery.class);\n        when(serviceDiscovery.getUrl()).thenReturn(registryURL);\n\n        when(serviceDiscovery.getRemoteMetadata(eq(\"111\"), anyList())).thenReturn(metadataInfo_111);\n        when(serviceDiscovery.getRemoteMetadata(eq(\"222\"), anyList())).thenReturn(metadataInfo_222);\n        when(serviceDiscovery.getRemoteMetadata(eq(\"333\"), anyList())).thenReturn(metadataInfo_333);\n        when(serviceDiscovery.getRemoteMetadata(eq(\"444\"), anyList())).thenReturn(MetadataInfo.EMPTY);\n        when(serviceDiscovery.getRemoteMetadata(eq(\"555\"), anyList())).thenReturn(metadataInfo_555_tri);\n    }\n\n    @BeforeEach\n    public void init() {\n        // Because all tests use the same ServiceDiscovery, the previous metadataCache should be cleared before next\n        // unit test\n        // to avoid contaminating next unit test.\n        clearMetadataCache();\n    }\n\n    @AfterEach\n    public void tearDown() throws Exception {\n        if (listener != null) {\n            listener.destroy();\n            listener = null;\n        }\n    }\n\n    @AfterAll\n    public static void destroy() throws Exception {\n        serviceDiscovery.destroy();\n    }\n\n    // 正常场景。单应用app1 通知地址基本流程，只做instance-metadata关联，没有metadata内容的解析\n    @Test\n    @Order(1)\n    public void testInstanceNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(event);\n\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(1, allInstances.size());\n        Assertions.assertEquals(3, allInstances.get(\"app1\").size());\n\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n    }\n\n    // 正常场景。单应用app1，进一步检查 metadata service 是否正确映射\n    @Test\n    @Order(2)\n    public void testInstanceNotificationAndMetadataParse() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify instance change\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(event);\n\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(1, allInstances.size());\n        Assertions.assertEquals(3, allInstances.get(\"app1\").size());\n\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        assertThat(serviceUrls, Matchers.hasItem(Matchers.hasProperty(\"instance\", Matchers.notNullValue())));\n        assertThat(serviceUrls, Matchers.hasItem(Matchers.hasProperty(\"metadataInfo\", Matchers.notNullValue())));\n    }\n\n    // 正常场景。多应用，app1 app2 分别通知地址\n    @Test\n    @Order(3)\n    public void testMultipleAppNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        serviceNames.add(\"app2\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify app1 instance change\n        ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(app1_event);\n\n        // notify app2 instance change\n        ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent(\"app2\", app2Instances);\n        listener.onEvent(app2_event);\n\n        // check\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(2, allInstances.size());\n        Assertions.assertEquals(3, allInstances.get(\"app1\").size());\n        Assertions.assertEquals(4, allInstances.get(\"app2\").size());\n\n        ProtocolServiceKey protocolServiceKey1 = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey2 = new ProtocolServiceKey(service2, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey3 = new ProtocolServiceKey(service3, null, null, \"dubbo\");\n\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey1, consumerURL);\n        Assertions.assertEquals(7, serviceUrls.size());\n        List<URL> serviceUrls2 = listener.getAddresses(protocolServiceKey2, consumerURL);\n        Assertions.assertEquals(4, serviceUrls2.size());\n        assertTrue(serviceUrls2.get(0).getIp().contains(\"30.10.\"));\n        List<URL> serviceUrls3 = listener.getAddresses(protocolServiceKey3, consumerURL);\n        Assertions.assertEquals(2, serviceUrls3.size());\n        assertTrue(serviceUrls3.get(0).getIp().contains(\"30.10.\"));\n    }\n\n    // 正常场景。多应用，app1 app2，空地址通知（边界条件）能否解析出正确的空地址列表\n    @Test\n    @Order(4)\n    public void testMultipleAppEmptyNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        serviceNames.add(\"app2\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify app1 instance change\n        ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(app1_event);\n\n        // notify app2 instance change\n        ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent(\"app2\", app2Instances);\n        listener.onEvent(app2_event);\n\n        // empty notification\n        ServiceInstancesChangedEvent app1_event_again =\n                new ServiceInstancesChangedEvent(\"app1\", Collections.EMPTY_LIST);\n        listener.onEvent(app1_event_again);\n\n        // check app1 cleared\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(2, allInstances.size());\n        Assertions.assertEquals(0, allInstances.get(\"app1\").size());\n        Assertions.assertEquals(4, allInstances.get(\"app2\").size());\n\n        ProtocolServiceKey protocolServiceKey1 = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey2 = new ProtocolServiceKey(service2, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey3 = new ProtocolServiceKey(service3, null, null, \"dubbo\");\n\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey1, consumerURL);\n        Assertions.assertEquals(4, serviceUrls.size());\n        assertTrue(serviceUrls.get(0).getIp().contains(\"30.10.\"));\n        List<URL> serviceUrls2 = listener.getAddresses(protocolServiceKey2, consumerURL);\n        Assertions.assertEquals(4, serviceUrls2.size());\n        assertTrue(serviceUrls2.get(0).getIp().contains(\"30.10.\"));\n        List<URL> serviceUrls3 = listener.getAddresses(protocolServiceKey3, consumerURL);\n        Assertions.assertEquals(2, serviceUrls3.size());\n        assertTrue(serviceUrls3.get(0).getIp().contains(\"30.10.\"));\n\n        // app2 empty notification\n        ServiceInstancesChangedEvent app2_event_again =\n                new ServiceInstancesChangedEvent(\"app2\", Collections.EMPTY_LIST);\n        listener.onEvent(app2_event_again);\n\n        // check app2 cleared\n        Map<String, List<ServiceInstance>> allInstances_app2 = listener.getAllInstances();\n        Assertions.assertEquals(2, allInstances_app2.size());\n        Assertions.assertEquals(0, allInstances_app2.get(\"app1\").size());\n        Assertions.assertEquals(0, allInstances_app2.get(\"app2\").size());\n\n        assertTrue(isEmpty(listener.getAddresses(protocolServiceKey1, consumerURL)));\n        assertTrue(isEmpty(listener.getAddresses(protocolServiceKey2, consumerURL)));\n        assertTrue(isEmpty(listener.getAddresses(protocolServiceKey3, consumerURL)));\n    }\n\n    // 正常场景。检查instance listener -> service listener(Directory)地址推送流程\n    @Test\n    @Order(5)\n    public void testServiceListenerNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        serviceNames.add(\"app2\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        NotifyListener demoServiceListener = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener.getConsumerUrl()).thenReturn(consumerURL);\n        NotifyListener demoService2Listener = Mockito.mock(NotifyListener.class);\n        when(demoService2Listener.getConsumerUrl()).thenReturn(consumerURL2);\n        listener.addListenerAndNotify(consumerURL, demoServiceListener);\n        listener.addListenerAndNotify(consumerURL2, demoService2Listener);\n        // notify app1 instance change\n        ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(app1_event);\n\n        // check\n        ArgumentCaptor<List<URL>> captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener, Mockito.times(1)).notify(captor.capture());\n        List<URL> notifiedUrls = captor.getValue();\n        Assertions.assertEquals(3, notifiedUrls.size());\n        ArgumentCaptor<List<URL>> captor2 = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoService2Listener, Mockito.times(1)).notify(captor2.capture());\n        List<URL> notifiedUrls2 = captor2.getValue();\n        Assertions.assertEquals(1, notifiedUrls2.size());\n\n        // notify app2 instance change\n        ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent(\"app2\", app2Instances);\n        listener.onEvent(app2_event);\n\n        // check\n        ArgumentCaptor<List<URL>> app2_captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener, Mockito.times(2)).notify(app2_captor.capture());\n        List<URL> app2_notifiedUrls = app2_captor.getValue();\n        Assertions.assertEquals(7, app2_notifiedUrls.size());\n        ArgumentCaptor<List<URL>> app2_captor2 = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoService2Listener, Mockito.times(2)).notify(app2_captor2.capture());\n        List<URL> app2_notifiedUrls2 = app2_captor2.getValue();\n        Assertions.assertEquals(4, app2_notifiedUrls2.size());\n\n        // test service listener still get notified when added after instance notification.\n        NotifyListener demoService3Listener = Mockito.mock(NotifyListener.class);\n        when(demoService3Listener.getConsumerUrl()).thenReturn(consumerURL3);\n        listener.addListenerAndNotify(consumerURL3, demoService3Listener);\n        Mockito.verify(demoService3Listener, Mockito.times(1)).notify(Mockito.anyList());\n    }\n\n    @Test\n    @Order(6)\n    public void testMultiServiceListenerNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        serviceNames.add(\"app2\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        NotifyListener demoServiceListener1 = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener1.getConsumerUrl()).thenReturn(consumerURL);\n        NotifyListener demoServiceListener2 = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener2.getConsumerUrl()).thenReturn(consumerURL);\n        NotifyListener demoService2Listener1 = Mockito.mock(NotifyListener.class);\n        when(demoService2Listener1.getConsumerUrl()).thenReturn(consumerURL2);\n        NotifyListener demoService2Listener2 = Mockito.mock(NotifyListener.class);\n        when(demoService2Listener2.getConsumerUrl()).thenReturn(consumerURL2);\n        listener.addListenerAndNotify(consumerURL, demoServiceListener1);\n        listener.addListenerAndNotify(consumerURL, demoServiceListener2);\n        listener.addListenerAndNotify(consumerURL2, demoService2Listener1);\n        listener.addListenerAndNotify(consumerURL2, demoService2Listener2);\n        // notify app1 instance change\n        ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(app1_event);\n\n        // check\n        ArgumentCaptor<List<URL>> captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener1, Mockito.times(1)).notify(captor.capture());\n        List<URL> notifiedUrls = captor.getValue();\n        Assertions.assertEquals(3, notifiedUrls.size());\n        ArgumentCaptor<List<URL>> captor2 = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoService2Listener1, Mockito.times(1)).notify(captor2.capture());\n        List<URL> notifiedUrls2 = captor2.getValue();\n        Assertions.assertEquals(1, notifiedUrls2.size());\n\n        // notify app2 instance change\n        ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent(\"app2\", app2Instances);\n        listener.onEvent(app2_event);\n\n        // check\n        ArgumentCaptor<List<URL>> app2_captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener1, Mockito.times(2)).notify(app2_captor.capture());\n        List<URL> app2_notifiedUrls = app2_captor.getValue();\n        Assertions.assertEquals(7, app2_notifiedUrls.size());\n        ArgumentCaptor<List<URL>> app2_captor2 = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoService2Listener1, Mockito.times(2)).notify(app2_captor2.capture());\n        List<URL> app2_notifiedUrls2 = app2_captor2.getValue();\n        Assertions.assertEquals(4, app2_notifiedUrls2.size());\n\n        // test service listener still get notified when added after instance notification.\n        NotifyListener demoService3Listener = Mockito.mock(NotifyListener.class);\n        when(demoService3Listener.getConsumerUrl()).thenReturn(consumerURL3);\n        listener.addListenerAndNotify(consumerURL3, demoService3Listener);\n        Mockito.verify(demoService3Listener, Mockito.times(1)).notify(Mockito.anyList());\n    }\n\n    /**\n     * Test subscribe multiple protocols\n     */\n    @Test\n    @Order(7)\n    public void testSubscribeMultipleProtocols() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        // no protocol specified, consume all instances\n        NotifyListener demoServiceListener1 = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener1.getConsumerUrl()).thenReturn(noProtocolConsumerURL);\n        listener.addListenerAndNotify(noProtocolConsumerURL, demoServiceListener1);\n        // multiple protocols specified\n        NotifyListener demoServiceListener2 = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener2.getConsumerUrl()).thenReturn(multipleProtocolsConsumerURL);\n        listener.addListenerAndNotify(multipleProtocolsConsumerURL, demoServiceListener2);\n        // one protocol specified\n        NotifyListener demoServiceListener3 = Mockito.mock(NotifyListener.class);\n        when(demoServiceListener3.getConsumerUrl()).thenReturn(singleProtocolsConsumerURL);\n        listener.addListenerAndNotify(singleProtocolsConsumerURL, demoServiceListener3);\n\n        // notify app1 instance change\n        ServiceInstancesChangedEvent app1_event =\n                new ServiceInstancesChangedEvent(\"app1\", app1InstancesMultipleProtocols);\n        listener.onEvent(app1_event);\n\n        // check instances expose framework supported default protocols(currently dubbo, triple and rest) are notified\n        ArgumentCaptor<List<URL>> default_protocol_captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener1, Mockito.times(1)).notify(default_protocol_captor.capture());\n        List<URL> default_protocol_notifiedUrls = default_protocol_captor.getValue();\n        Assertions.assertEquals(4, default_protocol_notifiedUrls.size());\n        // check instances expose protocols in consuming list(dubbo and triple) are notified\n        ArgumentCaptor<List<URL>> multi_protocols_captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener2, Mockito.times(1)).notify(multi_protocols_captor.capture());\n        List<URL> multi_protocol_notifiedUrls = multi_protocols_captor.getValue();\n        Assertions.assertEquals(4, multi_protocol_notifiedUrls.size());\n        // check instances expose protocols in consuming list(only triple) are notified\n        ArgumentCaptor<List<URL>> single_protocols_captor = ArgumentCaptor.forClass(List.class);\n        Mockito.verify(demoServiceListener3, Mockito.times(1)).notify(single_protocols_captor.capture());\n        List<URL> single_protocol_notifiedUrls = single_protocols_captor.getValue();\n        Assertions.assertEquals(1, single_protocol_notifiedUrls.size());\n    }\n\n    /**\n     * Test subscribe multiple groups\n     */\n    @Test\n    @Order(8)\n    public void testSubscribeMultipleGroups() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify instance change\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(event);\n\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(1, allInstances.size());\n        Assertions.assertEquals(3, allInstances.get(\"app1\").size());\n\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \",group1\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"group1,\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"*\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"group1\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(0, serviceUrls.size());\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"group1,group2\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(0, serviceUrls.size());\n\n        protocolServiceKey = new ProtocolServiceKey(service1, null, \"group1,,group2\", \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n    }\n\n    /**\n     * Test subscribe multiple versions\n     */\n    @Test\n    @Order(9)\n    public void testSubscribeMultipleVersions() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify instance change\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(event);\n\n        Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();\n        Assertions.assertEquals(1, allInstances.size());\n        Assertions.assertEquals(3, allInstances.get(\"app1\").size());\n\n        ProtocolServiceKey protocolServiceKey = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \"\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \"*\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \",1.0.0\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \"1.0.0,\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \"1.0.0,,1.0.1\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(3, serviceUrls.size());\n        assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);\n\n        protocolServiceKey = new ProtocolServiceKey(service1, \"1.0.1,1.0.0\", null, \"dubbo\");\n        serviceUrls = listener.getAddresses(protocolServiceKey, consumerURL);\n        Assertions.assertEquals(0, serviceUrls.size());\n    }\n\n    // revision 异常场景。第一次启动，完全拿不到metadata，只能通知部分地址\n    @Test\n    @Order(10)\n    public void testRevisionFailureOnStartup() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        // notify app1 instance change\n        ServiceInstancesChangedEvent failed_revision_event =\n                new ServiceInstancesChangedEvent(\"app1\", app1FailedInstances);\n        listener.onEvent(failed_revision_event);\n\n        ProtocolServiceKey protocolServiceKey1 = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey2 = new ProtocolServiceKey(service2, null, null, \"dubbo\");\n\n        List<URL> serviceUrls = listener.getAddresses(protocolServiceKey1, consumerURL);\n        List<URL> serviceUrls2 = listener.getAddresses(protocolServiceKey2, consumerURL);\n\n        assertTrue(isNotEmpty(serviceUrls));\n        assertTrue(isNotEmpty(serviceUrls2));\n    }\n\n    // revision 异常场景。运行中地址通知，拿不到revision就用老版本revision\n    @Test\n    @Order(11)\n    public void testRevisionFailureOnNotification() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        serviceNames.add(\"app2\");\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n\n        // notify app1 instance change\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1Instances);\n        listener.onEvent(event);\n\n        when(serviceDiscovery.getRemoteMetadata(eq(\"222\"), anyList())).thenAnswer(new Answer<MetadataInfo>() {\n            @Override\n            public MetadataInfo answer(InvocationOnMock invocationOnMock) throws Throwable {\n                if (Thread.currentThread().getName().contains(\"Dubbo-framework-metadata-retry\")) {\n                    return metadataInfo_222;\n                }\n                return MetadataInfo.EMPTY;\n            }\n        });\n\n        ServiceInstancesChangedEvent event2 = new ServiceInstancesChangedEvent(\"app2\", app1FailedInstances2);\n        listener.onEvent(event2);\n\n        // event2 did not really take effect\n        ProtocolServiceKey protocolServiceKey1 = new ProtocolServiceKey(service1, null, null, \"dubbo\");\n        ProtocolServiceKey protocolServiceKey2 = new ProtocolServiceKey(service2, null, null, \"dubbo\");\n\n        Assertions.assertEquals(\n                3, listener.getAddresses(protocolServiceKey1, consumerURL).size());\n        assertTrue(isEmpty(listener.getAddresses(protocolServiceKey2, consumerURL)));\n\n        //\n        init();\n\n        try {\n            Thread.sleep(15000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        // check recovered after retry.\n        List<URL> serviceUrls_after_retry = listener.getAddresses(protocolServiceKey1, consumerURL);\n        Assertions.assertEquals(5, serviceUrls_after_retry.size());\n        List<URL> serviceUrls2_after_retry = listener.getAddresses(protocolServiceKey2, consumerURL);\n        Assertions.assertEquals(2, serviceUrls2_after_retry.size());\n    }\n\n    // Abnormal case. Instance does not have revision\n    @Test\n    @Order(12)\n    public void testInstanceWithoutRevision() {\n        Set<String> serviceNames = new HashSet<>();\n        serviceNames.add(\"app1\");\n        ServiceDiscovery serviceDiscovery = Mockito.mock(ServiceDiscovery.class);\n        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);\n        ServiceInstancesChangedListener spyListener = Mockito.spy(listener);\n        Mockito.doReturn(null).when(metadataService).getMetadataInfo(eq(null));\n        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(\"app1\", app1InstancesWithNoRevision);\n        spyListener.onEvent(event);\n        // notification succeeded\n        assertTrue(true);\n    }\n\n    Set<String> getExpectedSet(List<String> list) {\n        return new HashSet<>(list);\n    }\n\n    static List<ServiceInstance> buildInstances(List<Object> rawURls) {\n        List<ServiceInstance> instances = new ArrayList<>();\n\n        for (Object obj : rawURls) {\n            String rawURL = (String) obj;\n            DefaultServiceInstance instance = new DefaultServiceInstance();\n            final URL dubboUrl = URL.valueOf(rawURL);\n            instance.setRawAddress(rawURL);\n            instance.setHost(dubboUrl.getHost());\n            instance.setEnabled(true);\n            instance.setHealthy(true);\n            instance.setPort(dubboUrl.getPort());\n            instance.setRegistryCluster(\"default\");\n            instance.setApplicationModel(ApplicationModel.defaultModel());\n\n            Map<String, String> metadata = new HashMap<>();\n            if (StringUtils.isNotEmpty(dubboUrl.getParameter(REVISION_KEY))) {\n                metadata.put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, dubboUrl.getParameter(REVISION_KEY));\n            }\n            instance.setMetadata(metadata);\n\n            instances.add(instance);\n        }\n\n        return instances;\n    }\n\n    private void clearMetadataCache() {\n        try {\n            MockServiceDiscovery mockServiceDiscovery =\n                    (MockServiceDiscovery) ServiceInstancesChangedListenerWithoutEmptyProtectTest.serviceDiscovery;\n            MetaCacheManager metaCacheManager = mockServiceDiscovery.getMetaCacheManager();\n            Field cacheField = metaCacheManager.getClass().getDeclaredField(\"cache\");\n            cacheField.setAccessible(true);\n            LRUCache<String, MetadataInfo> cache = (LRUCache<String, MetadataInfo>) cacheField.get(metaCacheManager);\n            cache.clear();\n            cacheField.setAccessible(false);\n        } catch (Exception e) {\n            // ignore\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMappingTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigItem;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.MetadataReportConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.metadata.report.MetadataReportInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.when;\n\nclass MetadataServiceNameMappingTest {\n\n    private MetadataServiceNameMapping mapping;\n    private URL url;\n    private ConfigManager configManager;\n    private MetadataReport metadataReport;\n    private ApplicationModel applicationModel;\n    private Map<String, MetadataReport> metadataReportList = new HashMap<>();\n\n    @BeforeEach\n    public void setUp() {\n        applicationModel = ApplicationModel.defaultModel();\n        configManager = mock(ConfigManager.class);\n        metadataReport = mock(MetadataReport.class);\n        metadataReportList.put(\"default\", metadataReport);\n        mapping = new MetadataServiceNameMapping(applicationModel);\n        mapping.setApplicationModel(applicationModel);\n        url = URL.valueOf(\"dubbo://127.0.0.1:20880/TestService?version=1.0.0\");\n    }\n\n    @AfterEach\n    public void teardown() {\n        applicationModel.destroy();\n    }\n\n    @Test\n    void testMap() {\n        ApplicationModel mockedApplicationModel = spy(applicationModel);\n\n        when(configManager.getMetadataConfigs()).thenReturn(Collections.emptyList());\n        Mockito.when(mockedApplicationModel.getApplicationConfigManager()).thenReturn(configManager);\n        Mockito.when(mockedApplicationModel.getCurrentConfig()).thenReturn(new ApplicationConfig(\"test\"));\n\n        // metadata report config not found\n        mapping.setApplicationModel(mockedApplicationModel);\n        boolean result = mapping.map(url);\n        assertFalse(result);\n\n        when(configManager.getMetadataConfigs()).thenReturn(Arrays.asList(new MetadataReportConfig()));\n        MetadataReportInstance reportInstance = mock(MetadataReportInstance.class);\n        Mockito.when(reportInstance.getMetadataReports(true)).thenReturn(metadataReportList);\n        mapping.metadataReportInstance = reportInstance;\n\n        when(metadataReport.registerServiceAppMapping(any(), any(), any())).thenReturn(true);\n\n        // metadata report directly\n        result = mapping.map(url);\n        assertTrue(result);\n\n        // metadata report using cas and retry, succeeded after retried 10 times\n        when(metadataReport.registerServiceAppMapping(any(), any(), any())).thenReturn(false);\n        when(metadataReport.getConfigItem(any(), any())).thenReturn(new ConfigItem());\n        when(metadataReport.registerServiceAppMapping(any(), any(), any(), any()))\n                .thenAnswer(new Answer<Boolean>() {\n                    private int counter = 0;\n\n                    @Override\n                    public Boolean answer(InvocationOnMock invocationOnMock) {\n                        if (++counter == 10) {\n                            return true;\n                        }\n                        return false;\n                    }\n                });\n        assertTrue(mapping.map(url));\n\n        // metadata report using cas and retry, failed after 11 times retry\n        when(metadataReport.registerServiceAppMapping(any(), any(), any(), any()))\n                .thenReturn(false);\n        Exception exceptionExpected = null;\n        assertFalse(mapping.map(url));\n    }\n\n    /**\n     * This test currently doesn't make any sense\n     */\n    @Test\n    void testGet() {\n        Set<String> set = new HashSet<>();\n        set.add(\"app1\");\n\n        MetadataReportInstance reportInstance = mock(MetadataReportInstance.class);\n        Mockito.when(reportInstance.getMetadataReport(any())).thenReturn(metadataReport);\n        when(metadataReport.getServiceAppMapping(any(), any())).thenReturn(set);\n\n        mapping.metadataReportInstance = reportInstance;\n        Set<String> result = mapping.get(url);\n        assertEquals(set, result);\n    }\n\n    /**\n     * Same situation as testGet, so left empty.\n     */\n    @Test\n    void testGetAndListen() {\n        // TODO\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/MetadataServiceURLBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\n/**\n * {@link MetadataServiceURLBuilder} Test\n *\n * @since 2.7.5\n */\nclass MetadataServiceURLBuilderTest {\n\n    static ServiceInstance serviceInstance =\n            new DefaultServiceInstance(\"test\", \"127.0.0.1\", 8080, ApplicationModel.defaultModel());\n\n    static {\n        serviceInstance\n                .getMetadata()\n                .put(\n                        \"dubbo.metadata-service.urls\",\n                        \"[ \\\"dubbo://192.168.0.102:20881/com.alibaba.cloud.dubbo.service.DubboMetadataService?anyhost=true&application=spring-cloud-alibaba-dubbo-provider&bind.ip=192.168.0.102&bind.port=20881&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&group=spring-cloud-alibaba-dubbo-provider&interface=com.alibaba.cloud.dubbo.service.DubboMetadataService&methods=getAllServiceKeys,getServiceRestMetadata,getExportedURLs,getAllExportedURLs&pid=17134&qos.enable=false&register=true&release=2.7.3&revision=1.0.0&side=provider&timestamp=1564826098503&version=1.0.0\\\" ]\");\n        serviceInstance\n                .getMetadata()\n                .put(\n                        \"dubbo.metadata-service.url-params\",\n                        \"{\\\"application\\\":\\\"dubbo-provider-demo\\\",\\\"protocol\\\":\\\"rest\\\",\\\"group\\\":\\\"dubbo-provider-demo\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":\\\"1564845042651\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"host\\\":\\\"192.168.0.102\\\",\\\"port\\\":\\\"20880\\\"}\");\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/ProtocolPortsMetadataCustomizerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.hamcrest.MatcherAssert;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.ENDPOINTS;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasItem;\nimport static org.hamcrest.Matchers.hasProperty;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\n\nclass ProtocolPortsMetadataCustomizerTest {\n\n    public DefaultServiceInstance instance;\n    private MetadataService mockedMetadataService;\n    private ApplicationModel mockedApplicationModel;\n    private ScopeBeanFactory mockedBeanFactory;\n\n    public static DefaultServiceInstance createInstance() {\n        return new DefaultServiceInstance(\"A\", \"127.0.0.1\", 20880, ApplicationModel.defaultModel());\n    }\n\n    @AfterAll\n    public static void clearUp() {\n        ApplicationModel.reset();\n    }\n\n    @BeforeEach\n    public void init() {\n        instance = createInstance();\n\n        URL dubboUrl = URL.valueOf(\n                \"dubbo://30.10.104.63:20880/org.apache.dubbo.demo.GreetingService?\"\n                        + \"REGISTRY_CLUSTER=registry1&anyhost=true&application=demo-provider2&delay=5000&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&group=greeting&interface=org.apache.dubbo.demo.GreetingService&metadata-type=remote&methods=hello&pid=55805&release=&revision=1.0.0&service-name-mapping=true&side=provider&timeout=5000&timestamp=1630229110058&version=1.0.0\");\n        URL triURL = URL.valueOf(\n                \"tri://30.10.104.63:50332/org.apache.dubbo.demo.GreetingService?\"\n                        + \"REGISTRY_CLUSTER=registry1&anyhost=true&application=demo-provider2&delay=5000&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&group=greeting&interface=org.apache.dubbo.demo.GreetingService&metadata-type=remote&methods=hello&pid=55805&release=&revision=1.0.0&service-name-mapping=true&side=provider&timeout=5000&timestamp=1630229110058&version=1.0.0\");\n\n        MetadataInfo metadataInfo = new MetadataInfo();\n        metadataInfo.addService(dubboUrl);\n        metadataInfo.addService(triURL);\n        instance.setServiceMetadata(metadataInfo);\n\n        mockedMetadataService = Mockito.mock(MetadataService.class);\n    }\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        Mockito.framework().clearInlineMocks();\n    }\n\n    @Test\n    void test() {\n        ProtocolPortsMetadataCustomizer customizer = new ProtocolPortsMetadataCustomizer();\n        customizer.customize(instance, ApplicationModel.defaultModel());\n        String endpoints = instance.getMetadata().get(ENDPOINTS);\n        assertNotNull(endpoints);\n        List<DefaultServiceInstance.Endpoint> endpointList =\n                JsonUtils.toJavaList(endpoints, DefaultServiceInstance.Endpoint.class);\n        assertEquals(2, endpointList.size());\n        MatcherAssert.assertThat(endpointList, hasItem(hasProperty(\"protocol\", equalTo(\"dubbo\"))));\n        MatcherAssert.assertThat(endpointList, hasItem(hasProperty(\"port\", equalTo(20880))));\n        MatcherAssert.assertThat(endpointList, hasItem(hasProperty(\"protocol\", equalTo(\"tri\"))));\n        MatcherAssert.assertThat(endpointList, hasItem(hasProperty(\"port\", equalTo(50332))));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceHostPortCustomizerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.beans.factory.ScopeBeanFactory;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.concurrent.ExecutionException;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.doReturn;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.when;\n\n/**\n * Test for https://github.com/apache/dubbo/issues/8698\n */\nclass ServiceInstanceHostPortCustomizerTest {\n    private static ServiceInstanceHostPortCustomizer serviceInstanceHostPortCustomizer;\n\n    @BeforeAll\n    public static void setUp() {\n        serviceInstanceHostPortCustomizer = new ServiceInstanceHostPortCustomizer();\n    }\n\n    @AfterAll\n    public static void clearUp() {\n        ApplicationModel.reset();\n    }\n\n    @Test\n    void customizePreferredProtocol() throws ExecutionException, InterruptedException {\n        ScopeBeanFactory beanFactory = mock(ScopeBeanFactory.class);\n        MetadataService metadataService = mock(MetadataService.class);\n        when(beanFactory.getBean(MetadataService.class)).thenReturn(metadataService);\n        ApplicationModel applicationModel = spy(ApplicationModel.defaultModel());\n        when(applicationModel.getBeanFactory()).thenReturn(beanFactory);\n\n        // test protocol set\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"aa\");\n        // when(applicationModel.getCurrentConfig()).thenReturn(applicationConfig);\n        doReturn(applicationConfig).when(applicationModel).getCurrentConfig();\n        DefaultServiceInstance serviceInstance1 =\n                new DefaultServiceInstance(\"without-preferredProtocol\", applicationModel);\n        MetadataInfo metadataInfo = new MetadataInfo();\n        metadataInfo.addService(URL.valueOf(\"tri://127.1.1.1:50052/org.apache.dubbo.demo.GreetingService\"));\n        serviceInstance1.setServiceMetadata(metadataInfo);\n        serviceInstanceHostPortCustomizer.customize(serviceInstance1, applicationModel);\n        Assertions.assertEquals(\"127.1.1.1\", serviceInstance1.getHost());\n        Assertions.assertEquals(50052, serviceInstance1.getPort());\n\n        // pick the preferredProtocol\n        applicationConfig.setProtocol(\"tri\");\n        metadataInfo.addService(URL.valueOf(\"dubbo://127.1.2.3:20889/org.apache.dubbo.demo.HelloService\"));\n        serviceInstanceHostPortCustomizer.customize(serviceInstance1, applicationModel);\n        Assertions.assertEquals(\"127.1.1.1\", serviceInstance1.getHost());\n        Assertions.assertEquals(50052, serviceInstance1.getPort());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataCustomizerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.mockito.Mockito.doReturn;\nimport static org.mockito.Mockito.spy;\n\nclass ServiceInstanceMetadataCustomizerTest {\n    private static ServiceInstanceMetadataCustomizer serviceInstanceMetadataCustomizer;\n\n    @BeforeAll\n    public static void setUp() {\n        serviceInstanceMetadataCustomizer = new ServiceInstanceMetadataCustomizer();\n    }\n\n    @AfterAll\n    public static void clearUp() {\n        ApplicationModel.reset();\n    }\n\n    /**\n     * Only 'include' policy spicified in Customized Filter will take effect\n     */\n    @Test\n    void testCustomizeWithIncludeFilters() {\n        ApplicationModel applicationModel = spy(ApplicationModel.defaultModel());\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"aa\");\n        doReturn(applicationConfig).when(applicationModel).getCurrentConfig();\n\n        DefaultServiceInstance serviceInstance1 =\n                new DefaultServiceInstance(\"ServiceInstanceMetadataCustomizerTest\", applicationModel);\n        MetadataInfo metadataInfo = new MetadataInfo();\n        metadataInfo.addService(\n                URL.valueOf(\n                        \"tri://127.1.1.1:50052/org.apache.dubbo.demo.GreetingService?application=ServiceInstanceMetadataCustomizerTest&env=test&side=provider&group=test\"));\n        serviceInstance1.setServiceMetadata(metadataInfo);\n        serviceInstanceMetadataCustomizer.customize(serviceInstance1, applicationModel);\n        Assertions.assertEquals(1, serviceInstance1.getMetadata().size());\n        Assertions.assertEquals(\"provider\", serviceInstance1.getMetadata(SIDE_KEY));\n        Assertions.assertNull(serviceInstance1.getMetadata(\"env\"));\n        Assertions.assertNull(serviceInstance1.getMetadata(\"application\"));\n    }\n\n    /**\n     * Only 'exclude' policies specified in Exclude Filters will take effect\n     */\n    @Test\n    void testCustomizeWithExcludeFilters() {\n        ApplicationModel applicationModel = spy(ApplicationModel.defaultModel());\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"aa\");\n        doReturn(applicationConfig).when(applicationModel).getCurrentConfig();\n\n        DefaultServiceInstance serviceInstance1 =\n                new DefaultServiceInstance(\"ServiceInstanceMetadataCustomizerTest\", applicationModel);\n        MetadataInfo metadataInfo = new MetadataInfo();\n        metadataInfo.addService(\n                URL.valueOf(\n                        \"tri://127.1.1.1:50052/org.apache.dubbo.demo.GreetingService?application=ServiceInstanceMetadataCustomizerTest&env=test&side=provider&group=test&params-filter=-customized,-dubbo\"));\n        serviceInstance1.setServiceMetadata(metadataInfo);\n        serviceInstanceMetadataCustomizer.customize(serviceInstance1, applicationModel);\n        Assertions.assertEquals(2, serviceInstance1.getMetadata().size());\n        Assertions.assertEquals(\"ServiceInstanceMetadataCustomizerTest\", serviceInstance1.getMetadata(\"application\"));\n        Assertions.assertEquals(\"test\", serviceInstance1.getMetadata(\"env\"));\n\n        Assertions.assertNull(serviceInstance1.getMetadata(\"side\"));\n        Assertions.assertNull(serviceInstance1.getMetadata(\"group\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/SpringCloudMetadataServiceURLBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.registry.client.metadata.MetadataServiceURLBuilderTest.serviceInstance;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link SpringCloudMetadataServiceURLBuilder} Test\n *\n * @since 2.7.5\n */\nclass SpringCloudMetadataServiceURLBuilderTest {\n\n    private SpringCloudMetadataServiceURLBuilder builder = new SpringCloudMetadataServiceURLBuilder();\n\n    @Test\n    void testBuild() {\n        List<URL> urls =\n                builder.build(new DefaultServiceInstance(\"127.0.0.1\", \"test\", 8080, ApplicationModel.defaultModel()));\n        assertEquals(0, urls.size());\n\n        urls = builder.build(serviceInstance);\n        assertEquals(1, urls.size());\n        URL url = urls.get(0);\n        assertEquals(\"192.168.0.102\", url.getHost());\n        assertEquals(20881, url.getPort());\n        assertEquals(\"com.alibaba.cloud.dubbo.service.DubboMetadataService\", url.getServiceInterface());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/StandardMetadataServiceURLBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metadata.MetadataService;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.registry.client.metadata.MetadataServiceURLBuilderTest.serviceInstance;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\n/**\n * {@link StandardMetadataServiceURLBuilder} Test\n */\nclass StandardMetadataServiceURLBuilderTest {\n\n    @BeforeAll\n    public static void setUp() {\n        ApplicationConfig applicationConfig = new ApplicationConfig(\"demo\");\n        applicationConfig.setMetadataServicePort(7001);\n        ApplicationModel.defaultModel().getApplicationConfigManager().setApplication(applicationConfig);\n    }\n\n    @AfterAll\n    public static void clearUp() {\n        ApplicationModel.reset();\n    }\n\n    @Test\n    void testBuild() {\n        ExtensionLoader<MetadataServiceURLBuilder> loader =\n                ApplicationModel.defaultModel().getExtensionLoader(MetadataServiceURLBuilder.class);\n        MetadataServiceURLBuilder builder = loader.getExtension(StandardMetadataServiceURLBuilder.NAME);\n\n        // test generateUrlWithoutMetadata\n        List<URL> urls =\n                builder.build(new DefaultServiceInstance(\"test\", \"127.0.0.1\", 8080, ApplicationModel.defaultModel()));\n        assertEquals(1, urls.size());\n        URL url = urls.get(0);\n        assertEquals(\"dubbo\", url.getProtocol());\n        assertEquals(\"127.0.0.1\", url.getHost());\n        assertEquals(7001, url.getPort());\n        assertEquals(MetadataService.class.getName(), url.getServiceInterface());\n        assertEquals(\"test\", url.getGroup());\n        assertEquals(\"consumer\", url.getSide());\n        assertEquals(\"1.0.0\", url.getVersion());\n        //        assertEquals(url.getParameters().get(\"getAndListenInstanceMetadata.1.callback\"), \"true\");\n        assertEquals(\"false\", url.getParameters().get(\"reconnect\"));\n        assertEquals(\"5000\", url.getParameters().get(\"timeout\"));\n        assertEquals(ApplicationModel.defaultModel(), url.getApplicationModel());\n\n        // test generateWithMetadata\n        urls = builder.build(serviceInstance);\n        assertEquals(1, urls.size());\n        url = urls.get(0);\n        assertEquals(\"rest\", url.getProtocol());\n        assertEquals(\"127.0.0.1\", url.getHost());\n        assertEquals(20880, url.getPort());\n        assertEquals(MetadataService.class.getName(), url.getServiceInterface());\n        assertEquals(\"test\", url.getGroup());\n        assertEquals(\"consumer\", url.getSide());\n        assertEquals(\"1.0.0\", url.getVersion());\n        assertEquals(\"dubbo-provider-demo\", url.getApplication());\n        assertEquals(\"5000\", url.getParameters().get(\"timeout\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/store/CustomizedParamsFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata.store;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.metadata.MetadataParamsFilter;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\n\n@Activate\npublic class CustomizedParamsFilter implements MetadataParamsFilter {\n\n    @Override\n    public String[] serviceParamsIncluded() {\n        return new String[] {APPLICATION_KEY, TIMEOUT_KEY, GROUP_KEY, VERSION_KEY};\n    }\n\n    @Override\n    public String[] serviceParamsExcluded() {\n        return new String[0];\n    }\n\n    /**\n     * Not included in this test\n     */\n    @Override\n    public String[] instanceParamsIncluded() {\n        return new String[] {SIDE_KEY};\n    }\n\n    @Override\n    public String[] instanceParamsExcluded() {\n        return new String[0];\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/store/ExcludedParamsFilter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata.store;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.metadata.MetadataParamsFilter;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\n\n@Activate\npublic class ExcludedParamsFilter implements MetadataParamsFilter {\n\n    @Override\n    public String[] serviceParamsIncluded() {\n        return new String[0];\n    }\n\n    @Override\n    public String[] serviceParamsExcluded() {\n        return new String[0];\n    }\n\n    /**\n     * Not included in this test\n     */\n    @Override\n    public String[] instanceParamsIncluded() {\n        return new String[0];\n    }\n\n    @Override\n    public String[] instanceParamsExcluded() {\n        return new String[] {SIDE_KEY};\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/store/ExcludedParamsFilter2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata.store;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.metadata.MetadataParamsFilter;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\n\n@Activate\npublic class ExcludedParamsFilter2 implements MetadataParamsFilter {\n\n    @Override\n    public String[] serviceParamsIncluded() {\n        return new String[0];\n    }\n\n    @Override\n    public String[] serviceParamsExcluded() {\n        return new String[0];\n    }\n\n    /**\n     * Not included in this test\n     */\n    @Override\n    public String[] instanceParamsIncluded() {\n        return new String[0];\n    }\n\n    @Override\n    public String[] instanceParamsExcluded() {\n        return new String[] {GROUP_KEY, \"params-filter\"};\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/store/MetaCacheManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.metadata.store;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\n\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.file.Paths;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\n\nclass MetaCacheManagerTest {\n\n    @BeforeEach\n    public void setup() throws URISyntaxException {\n        String directory = getDirectoryOfClassPath();\n        SystemPropertyConfigUtils.setSystemProperty(CommonConstants.DubboProperty.DUBBO_META_CACHE_FILEPATH, directory);\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_META_CACHE_FILENAME, \"test-metadata.dubbo.cache\");\n    }\n\n    @AfterEach\n    public void clear() throws URISyntaxException {\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_META_CACHE_FILEPATH);\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_META_CACHE_FILENAME);\n    }\n\n    @Test\n    void testCache() {\n        //        ScheduledExecutorService cacheRefreshExecutor = Executors.newSingleThreadScheduledExecutor(new\n        // NamedThreadFactory(\"Dubbo-cache-refresh\"));\n        //        ExecutorRepository executorRepository = Mockito.mock(ExecutorRepository.class);\n        //        when(executorRepository.getCacheRefreshExecutor()).thenReturn(cacheRefreshExecutor);\n        //        ExtensionAccessor extensionAccessor = Mockito.mock(ExtensionAccessor.class);\n        //        when(extensionAccessor.getDefaultExtension(ExecutorRepository.class)).thenReturn(executorRepository);\n\n        MetaCacheManager cacheManager = new MetaCacheManager();\n        try {\n            //        cacheManager.setExtensionAccessor(extensionAccessor);\n\n            MetadataInfo metadataInfo = cacheManager.get(\"1\");\n            assertNull(metadataInfo);\n            metadataInfo = cacheManager.get(\"2\");\n            assertNull(metadataInfo);\n\n            metadataInfo = cacheManager.get(\"065787862412c2cc0a1b9577bc194c9a\");\n            assertNotNull(metadataInfo);\n            assertEquals(\"demo\", metadataInfo.getApp());\n\n            Map<String, MetadataInfo> newMetadatas = new HashMap<>();\n            MetadataInfo metadataInfo2 = JsonUtils.toJavaObject(\n                    \"{\\\"app\\\":\\\"demo2\\\",\\\"services\\\":{\\\"greeting/org.apache.dubbo.registry.service.DemoService2:1.0.0:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.registry.service.DemoService2\\\",\\\"group\\\":\\\"greeting\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.registry.service.DemoService2\\\",\\\"params\\\":{\\\"application\\\":\\\"demo-provider2\\\",\\\"sayHello.timeout\\\":\\\"7000\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"timeout\\\":\\\"5000\\\",\\\"group\\\":\\\"greeting\\\"}},\\\"greeting/org.apache.dubbo.registry.service.DemoService:1.0.0:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.registry.service.DemoService\\\",\\\"group\\\":\\\"greeting\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.registry.service.DemoService\\\",\\\"params\\\":{\\\"application\\\":\\\"demo-provider2\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"timeout\\\":\\\"5000\\\",\\\"group\\\":\\\"greeting\\\"}}}}\\n\",\n                    MetadataInfo.class);\n            assertNotEquals(\"2\", metadataInfo2.calRevision());\n            newMetadatas.put(\"2\", metadataInfo2);\n\n            MetadataInfo metadataInfo3 = JsonUtils.toJavaObject(\n                    \"{\\\"app\\\":\\\"demo3\\\",\\\"services\\\":{\\\"greeting/org.apache.dubbo.registry.service.DemoService3:1.0.0:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.registry.service.DemoService3\\\",\\\"group\\\":\\\"greeting\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.registry.service.DemoService3\\\",\\\"params\\\":{\\\"application\\\":\\\"demo-provider3\\\",\\\"sayHello.timeout\\\":\\\"7000\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"timeout\\\":\\\"5000\\\",\\\"group\\\":\\\"greeting\\\"}},\\\"greeting/org.apache.dubbo.registry.service.DemoService:1.0.0:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.registry.service.DemoService\\\",\\\"group\\\":\\\"greeting\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.registry.service.DemoService\\\",\\\"params\\\":{\\\"application\\\":\\\"demo-provider3\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"timeout\\\":\\\"5000\\\",\\\"group\\\":\\\"greeting\\\"}}}}\\n\",\n                    MetadataInfo.class);\n            assertEquals(\"84f10ebf1226b496c9ff102f311918e4\", metadataInfo3.calRevision());\n            newMetadatas.put(\"84f10ebf1226b496c9ff102f311918e4\", metadataInfo3);\n\n            cacheManager.update(newMetadatas);\n            metadataInfo = cacheManager.get(\"1\");\n            assertNull(metadataInfo);\n\n            metadataInfo = cacheManager.get(\"065787862412c2cc0a1b9577bc194c9a\");\n            assertNotNull(metadataInfo);\n            assertEquals(\"demo\", metadataInfo.getApp());\n\n            metadataInfo = cacheManager.get(\"2\");\n            assertNull(metadataInfo);\n\n            metadataInfo = cacheManager.get(\"84f10ebf1226b496c9ff102f311918e4\");\n            assertNotNull(metadataInfo);\n            assertEquals(\"demo3\", metadataInfo.getApp());\n            assertTrue(metadataInfo\n                    .getServices()\n                    .containsKey(\"greeting/org.apache.dubbo.registry.service.DemoService3:1.0.0:dubbo\"));\n        } finally {\n            cacheManager.destroy();\n        }\n    }\n\n    @Test\n    void testCacheDump() {\n        System.setProperty(\"dubbo.meta.cache.fileName\", \"not-exist.dubbo.cache\");\n        MetadataInfo metadataInfo3 = JsonUtils.toJavaObject(\n                \"{\\\"app\\\":\\\"demo3\\\",\\\"services\\\":{\\\"greeting/org.apache.dubbo.registry.service.DemoService2:1.0.0:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.registry.service.DemoService2\\\",\\\"group\\\":\\\"greeting\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.registry.service.DemoService2\\\",\\\"params\\\":{\\\"application\\\":\\\"demo-provider2\\\",\\\"sayHello.timeout\\\":\\\"7000\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"timeout\\\":\\\"5000\\\",\\\"group\\\":\\\"greeting\\\"}},\\\"greeting/org.apache.dubbo.registry.service.DemoService:1.0.0:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.registry.service.DemoService\\\",\\\"group\\\":\\\"greeting\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.registry.service.DemoService\\\",\\\"params\\\":{\\\"application\\\":\\\"demo-provider2\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"timeout\\\":\\\"5000\\\",\\\"group\\\":\\\"greeting\\\"}}}}\\n\",\n                MetadataInfo.class);\n        MetaCacheManager cacheManager = new MetaCacheManager();\n        try {\n            assertEquals(\"97370ff779b6b6ebb7012bae61710de2\", metadataInfo3.calRevision());\n            cacheManager.put(\"97370ff779b6b6ebb7012bae61710de2\", metadataInfo3);\n\n            try {\n                MetaCacheManager.CacheRefreshTask<MetadataInfo> task = new MetaCacheManager.CacheRefreshTask<>(\n                        cacheManager.getCacheStore(), cacheManager.getCache(), cacheManager, 0);\n                task.run();\n            } catch (Exception e) {\n                fail();\n            } finally {\n                cacheManager.destroy();\n            }\n\n            MetaCacheManager newCacheManager = null;\n            try {\n                newCacheManager = new MetaCacheManager();\n                MetadataInfo metadataInfo = newCacheManager.get(\"97370ff779b6b6ebb7012bae61710de2\");\n                assertNotNull(metadataInfo);\n                assertEquals(\"demo3\", metadataInfo.getApp());\n            } finally {\n                newCacheManager.destroy();\n            }\n        } finally {\n            cacheManager.destroy();\n        }\n    }\n\n    private String getDirectoryOfClassPath() throws URISyntaxException {\n        URL resource = this.getClass().getResource(\"/log4j2-test.xml\");\n        String path = Paths.get(resource.toURI()).toFile().getAbsolutePath();\n        int index = path.indexOf(\"log4j2-test.xml\");\n        String directoryPath = path.substring(0, index);\n        return directoryPath;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/migration/DefaultMigrationAddressComparatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.cluster.Directory;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.registry.client.migration.DefaultMigrationAddressComparator.NEW_ADDRESS_SIZE;\nimport static org.apache.dubbo.registry.client.migration.DefaultMigrationAddressComparator.OLD_ADDRESS_SIZE;\n\nclass DefaultMigrationAddressComparatorTest {\n\n    @SuppressWarnings(\"all\")\n    @Test\n    void test() {\n        DefaultMigrationAddressComparator comparator = new DefaultMigrationAddressComparator();\n\n        ClusterInvoker newInvoker = Mockito.mock(ClusterInvoker.class);\n        ClusterInvoker oldInvoker = Mockito.mock(ClusterInvoker.class);\n        Directory newDirectory = Mockito.mock(Directory.class);\n        Directory oldDirectory = Mockito.mock(Directory.class);\n        MigrationRule rule = Mockito.mock(MigrationRule.class);\n        URL url = Mockito.mock(URL.class);\n\n        Mockito.when(url.getDisplayServiceKey()).thenReturn(\"test\");\n        Mockito.when(newInvoker.getDirectory()).thenReturn(newDirectory);\n        Mockito.when(oldInvoker.getDirectory()).thenReturn(oldDirectory);\n        Mockito.when(newInvoker.getUrl()).thenReturn(url);\n        Mockito.when(oldInvoker.getUrl()).thenReturn(url);\n\n        Mockito.when(newInvoker.hasProxyInvokers()).thenReturn(false);\n        Mockito.when(newDirectory.getAllInvokers()).thenReturn(Collections.emptyList());\n\n        Assertions.assertFalse(comparator.shouldMigrate(newInvoker, oldInvoker, rule));\n        Assertions.assertEquals(-1, comparator.getAddressSize(\"test\").get(NEW_ADDRESS_SIZE));\n        Assertions.assertEquals(0, comparator.getAddressSize(\"test\").get(OLD_ADDRESS_SIZE));\n\n        Mockito.when(newInvoker.hasProxyInvokers()).thenReturn(true);\n        Mockito.when(oldInvoker.hasProxyInvokers()).thenReturn(false);\n        Mockito.when(oldDirectory.getAllInvokers()).thenReturn(Collections.emptyList());\n\n        Assertions.assertTrue(comparator.shouldMigrate(newInvoker, oldInvoker, rule));\n        Assertions.assertEquals(0, comparator.getAddressSize(\"test\").get(NEW_ADDRESS_SIZE));\n        Assertions.assertEquals(-1, comparator.getAddressSize(\"test\").get(OLD_ADDRESS_SIZE));\n\n        Mockito.when(oldInvoker.hasProxyInvokers()).thenReturn(true);\n\n        List<Invoker<?>> newInvokerList = new LinkedList<>();\n        newInvokerList.add(Mockito.mock(Invoker.class));\n        newInvokerList.add(Mockito.mock(Invoker.class));\n        newInvokerList.add(Mockito.mock(Invoker.class));\n        Mockito.when(newDirectory.getAllInvokers()).thenReturn(newInvokerList);\n\n        List<Invoker<?>> oldInvokerList = new LinkedList<>();\n        oldInvokerList.add(Mockito.mock(Invoker.class));\n        oldInvokerList.add(Mockito.mock(Invoker.class));\n        Mockito.when(oldDirectory.getAllInvokers()).thenReturn(oldInvokerList);\n\n        Assertions.assertTrue(comparator.shouldMigrate(newInvoker, oldInvoker, null));\n\n        Mockito.when(rule.getThreshold(url)).thenReturn(0.5f);\n        newInvokerList.clear();\n        newInvokerList.add(Mockito.mock(Invoker.class));\n        Assertions.assertTrue(comparator.shouldMigrate(newInvoker, oldInvoker, rule));\n\n        newInvokerList.clear();\n        // hasProxyInvokers will check if invokers list is empty\n        // if hasProxyInvokers return true, comparator will directly because default threshold is 0.0\n        Assertions.assertTrue(comparator.shouldMigrate(newInvoker, oldInvoker, null));\n        Assertions.assertFalse(comparator.shouldMigrate(newInvoker, oldInvoker, rule));\n\n        Assertions.assertEquals(0, comparator.getAddressSize(\"test\").get(NEW_ADDRESS_SIZE));\n        Assertions.assertEquals(2, comparator.getAddressSize(\"test\").get(OLD_ADDRESS_SIZE));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/migration/MigrationInvokerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.registry.client.migration.model.MigrationStep;\nimport org.apache.dubbo.registry.integration.DemoService;\nimport org.apache.dubbo.registry.integration.DynamicDirectory;\nimport org.apache.dubbo.registry.integration.RegistryProtocol;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\n\nclass MigrationInvokerTest {\n    @BeforeEach\n    public void before() {\n        FrameworkModel.destroyAll();\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"Test\");\n        ApplicationModel.defaultModel().getApplicationConfigManager().setApplication(applicationConfig);\n        ApplicationModel.defaultModel().getBeanFactory().registerBean(FrameworkStatusReportService.class);\n    }\n\n    @AfterEach\n    public void after() {\n        FrameworkModel.destroyAll();\n    }\n\n    @SuppressWarnings(\"all\")\n    @Test\n    void test() {\n        RegistryProtocol registryProtocol = Mockito.mock(RegistryProtocol.class);\n\n        ClusterInvoker invoker = Mockito.mock(ClusterInvoker.class);\n        ClusterInvoker serviceDiscoveryInvoker = Mockito.mock(ClusterInvoker.class);\n\n        DynamicDirectory directory = Mockito.mock(DynamicDirectory.class);\n        DynamicDirectory serviceDiscoveryDirectory = Mockito.mock(DynamicDirectory.class);\n\n        Mockito.when(invoker.getDirectory()).thenReturn(directory);\n        Mockito.when(serviceDiscoveryInvoker.getDirectory()).thenReturn(serviceDiscoveryDirectory);\n\n        Mockito.when(invoker.isAvailable()).thenReturn(true);\n        Mockito.when(serviceDiscoveryInvoker.isAvailable()).thenReturn(true);\n\n        Mockito.when(invoker.hasProxyInvokers()).thenReturn(true);\n        Mockito.when(serviceDiscoveryInvoker.hasProxyInvokers()).thenReturn(true);\n\n        List<Invoker<?>> invokers = new LinkedList<>();\n        invokers.add(Mockito.mock(Invoker.class));\n        invokers.add(Mockito.mock(Invoker.class));\n        List<Invoker<?>> serviceDiscoveryInvokers = new LinkedList<>();\n        serviceDiscoveryInvokers.add(Mockito.mock(Invoker.class));\n        serviceDiscoveryInvokers.add(Mockito.mock(Invoker.class));\n        Mockito.when(directory.getAllInvokers()).thenReturn(invokers);\n        Mockito.when(serviceDiscoveryDirectory.getAllInvokers()).thenReturn(serviceDiscoveryInvokers);\n\n        Mockito.when(registryProtocol.getInvoker(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))\n                .thenReturn(invoker);\n        Mockito.when(registryProtocol.getServiceDiscoveryInvoker(\n                        Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))\n                .thenReturn(serviceDiscoveryInvoker);\n\n        URL consumerURL = Mockito.mock(URL.class);\n        Mockito.when(consumerURL.getServiceInterface()).thenReturn(\"Test\");\n        Mockito.when(consumerURL.getGroup()).thenReturn(\"Group\");\n        Mockito.when(consumerURL.getVersion()).thenReturn(\"0.0.0\");\n        Mockito.when(consumerURL.getServiceKey()).thenReturn(\"Group/Test:0.0.0\");\n        Mockito.when(consumerURL.getDisplayServiceKey()).thenReturn(\"Test:0.0.0\");\n        Mockito.when(consumerURL.getOrDefaultApplicationModel()).thenReturn(ApplicationModel.defaultModel());\n\n        Mockito.when(invoker.getUrl()).thenReturn(consumerURL);\n        Mockito.when(serviceDiscoveryInvoker.getUrl()).thenReturn(consumerURL);\n\n        MigrationInvoker<?> migrationInvoker =\n                new MigrationInvoker<>(registryProtocol, null, null, DemoService.class, null, consumerURL);\n\n        MigrationRule migrationRule = Mockito.mock(MigrationRule.class);\n        Mockito.when(migrationRule.getForce(Mockito.any())).thenReturn(true);\n        migrationInvoker.migrateToForceInterfaceInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_INTERFACE);\n        migrationInvoker.invoke(null);\n        Mockito.verify(invoker, Mockito.times(1)).invoke(null);\n\n        migrationInvoker.migrateToForceApplicationInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_APPLICATION);\n        migrationInvoker.invoke(null);\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.times(1)).invoke(null);\n\n        Mockito.when(migrationRule.getThreshold(Mockito.any())).thenReturn(1.0f);\n        migrationInvoker.migrateToApplicationFirstInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.APPLICATION_FIRST);\n        migrationInvoker.invoke(null);\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.times(2)).invoke(null);\n\n        Mockito.when(migrationRule.getThreshold(Mockito.any())).thenReturn(2.0f);\n        migrationInvoker.migrateToApplicationFirstInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.APPLICATION_FIRST);\n        migrationInvoker.invoke(null);\n        Mockito.verify(invoker, Mockito.times(2)).invoke(null);\n\n        Mockito.when(migrationRule.getForce(Mockito.any())).thenReturn(false);\n        Mockito.when(migrationRule.getThreshold(Mockito.any())).thenReturn(1.0f);\n        migrationInvoker.migrateToForceInterfaceInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_INTERFACE);\n        migrationInvoker.invoke(null);\n        Mockito.verify(invoker, Mockito.times(3)).invoke(null);\n\n        migrationInvoker.migrateToForceInterfaceInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_INTERFACE);\n        migrationInvoker.invoke(null);\n        Mockito.verify(invoker, Mockito.times(4)).invoke(null);\n\n        Mockito.when(migrationRule.getThreshold(Mockito.any())).thenReturn(2.0f);\n        migrationInvoker.migrateToForceApplicationInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_APPLICATION);\n        migrationInvoker.invoke(null);\n        Mockito.verify(invoker, Mockito.times(5)).invoke(null);\n\n        Mockito.when(migrationRule.getThreshold(Mockito.any())).thenReturn(1.0f);\n        migrationInvoker.migrateToForceApplicationInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_APPLICATION);\n        migrationInvoker.invoke(null);\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.times(3)).invoke(null);\n\n        migrationInvoker.migrateToForceApplicationInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_APPLICATION);\n        migrationInvoker.invoke(null);\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.times(4)).invoke(null);\n\n        Mockito.when(migrationRule.getThreshold(Mockito.any())).thenReturn(2.0f);\n        migrationInvoker.migrateToForceInterfaceInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_INTERFACE);\n        migrationInvoker.invoke(null);\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.times(5)).invoke(null);\n\n        Mockito.when(migrationRule.getThreshold(Mockito.any())).thenReturn(2.0f);\n        Mockito.when(migrationRule.getForce(Mockito.any())).thenReturn(true);\n        migrationInvoker.migrateToForceInterfaceInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_INTERFACE);\n        migrationInvoker.invoke(null);\n        Mockito.verify(invoker, Mockito.times(6)).invoke(null);\n\n        migrationInvoker.migrateToForceApplicationInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_APPLICATION);\n        migrationInvoker.invoke(null);\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.times(6)).invoke(null);\n\n        Mockito.when(migrationRule.getForce(Mockito.any())).thenReturn(false);\n        migrationInvoker.migrateToForceInterfaceInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_INTERFACE);\n        migrationInvoker.invoke(null);\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.times(7)).invoke(null);\n        Assertions.assertNull(migrationInvoker.getInvoker());\n\n        Mockito.when(migrationRule.getForce(Mockito.any())).thenReturn(true);\n        migrationInvoker.migrateToForceInterfaceInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_INTERFACE);\n\n        Mockito.when(migrationRule.getForce(Mockito.any())).thenReturn(false);\n        migrationInvoker.migrateToForceApplicationInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.FORCE_APPLICATION);\n        migrationInvoker.invoke(null);\n        Mockito.verify(invoker, Mockito.times(7)).invoke(null);\n        Assertions.assertNull(migrationInvoker.getServiceDiscoveryInvoker());\n\n        ArgumentCaptor<InvokersChangedListener> argument = ArgumentCaptor.forClass(InvokersChangedListener.class);\n        Mockito.verify(serviceDiscoveryDirectory, Mockito.atLeastOnce()).setInvokersChangedListener(argument.capture());\n\n        Mockito.when(migrationRule.getThreshold(Mockito.any())).thenReturn(1.0f);\n        migrationInvoker.migrateToApplicationFirstInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.APPLICATION_FIRST);\n        for (int i = 0; i < 20; i++) {\n            migrationInvoker.invoke(null);\n        }\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.times(27)).invoke(null);\n\n        serviceDiscoveryInvokers.remove(1);\n        Mockito.when(serviceDiscoveryInvoker.hasProxyInvokers()).thenReturn(false);\n        argument.getAllValues().get(argument.getAllValues().size() - 1).onChange();\n\n        for (int i = 0; i < 20; i++) {\n            migrationInvoker.invoke(null);\n        }\n        Mockito.verify(invoker, Mockito.times(27)).invoke(null);\n\n        serviceDiscoveryInvokers.add(Mockito.mock(Invoker.class));\n        Mockito.when(serviceDiscoveryInvoker.hasProxyInvokers()).thenReturn(true);\n        argument.getAllValues().get(argument.getAllValues().size() - 1).onChange();\n\n        Mockito.when(migrationRule.getProportion(Mockito.any())).thenReturn(50);\n        migrationInvoker.setMigrationRule(migrationRule);\n        for (int i = 0; i < 1000; i++) {\n            migrationInvoker.invoke(null);\n        }\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.atMost(1026)).invoke(null);\n        Mockito.verify(invoker, Mockito.atLeast(28)).invoke(null);\n\n        Mockito.when(migrationRule.getDelay(Mockito.any())).thenReturn(1);\n        long currentTimeMillis = System.currentTimeMillis();\n        migrationInvoker.migrateToForceApplicationInvoker(migrationRule);\n        Assertions.assertTrue(System.currentTimeMillis() - currentTimeMillis >= 2000);\n    }\n\n    @SuppressWarnings(\"all\")\n    @Test\n    void testDecide() {\n        RegistryProtocol registryProtocol = Mockito.mock(RegistryProtocol.class);\n\n        ClusterInvoker invoker = Mockito.mock(ClusterInvoker.class);\n        ClusterInvoker serviceDiscoveryInvoker = Mockito.mock(ClusterInvoker.class);\n\n        DynamicDirectory directory = Mockito.mock(DynamicDirectory.class);\n        DynamicDirectory serviceDiscoveryDirectory = Mockito.mock(DynamicDirectory.class);\n\n        Mockito.when(invoker.getDirectory()).thenReturn(directory);\n        Mockito.when(serviceDiscoveryInvoker.getDirectory()).thenReturn(serviceDiscoveryDirectory);\n\n        Mockito.when(invoker.isAvailable()).thenReturn(true);\n        Mockito.when(serviceDiscoveryInvoker.isAvailable()).thenReturn(true);\n\n        Mockito.when(invoker.hasProxyInvokers()).thenReturn(true);\n        Mockito.when(serviceDiscoveryInvoker.hasProxyInvokers()).thenReturn(true);\n\n        List<Invoker<?>> invokers = new LinkedList<>();\n        invokers.add(Mockito.mock(Invoker.class));\n        invokers.add(Mockito.mock(Invoker.class));\n        List<Invoker<?>> serviceDiscoveryInvokers = new LinkedList<>();\n        serviceDiscoveryInvokers.add(Mockito.mock(Invoker.class));\n        serviceDiscoveryInvokers.add(Mockito.mock(Invoker.class));\n        Mockito.when(directory.getAllInvokers()).thenReturn(invokers);\n        Mockito.when(serviceDiscoveryDirectory.getAllInvokers()).thenReturn(serviceDiscoveryInvokers);\n\n        Mockito.when(registryProtocol.getInvoker(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))\n                .thenReturn(invoker);\n        Mockito.when(registryProtocol.getServiceDiscoveryInvoker(\n                        Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))\n                .thenReturn(serviceDiscoveryInvoker);\n\n        URL consumerURL = Mockito.mock(URL.class);\n        Mockito.when(consumerURL.getServiceInterface()).thenReturn(\"Test\");\n        Mockito.when(consumerURL.getGroup()).thenReturn(\"Group\");\n        Mockito.when(consumerURL.getVersion()).thenReturn(\"0.0.0\");\n        Mockito.when(consumerURL.getServiceKey()).thenReturn(\"Group/Test:0.0.0\");\n        Mockito.when(consumerURL.getDisplayServiceKey()).thenReturn(\"Test:0.0.0\");\n        Mockito.when(consumerURL.getOrDefaultApplicationModel()).thenReturn(ApplicationModel.defaultModel());\n\n        Mockito.when(invoker.getUrl()).thenReturn(consumerURL);\n        Mockito.when(serviceDiscoveryInvoker.getUrl()).thenReturn(consumerURL);\n\n        MigrationInvoker<?> migrationInvoker =\n                new MigrationInvoker<>(registryProtocol, null, null, DemoService.class, null, consumerURL);\n\n        MigrationRule migrationRule = Mockito.mock(MigrationRule.class);\n        Mockito.when(migrationRule.getForce(Mockito.any())).thenReturn(true);\n        migrationInvoker.migrateToApplicationFirstInvoker(migrationRule);\n        migrationInvoker.setMigrationStep(MigrationStep.APPLICATION_FIRST);\n        migrationInvoker.invoke(null);\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.times(1)).invoke(null);\n\n        Mockito.when(serviceDiscoveryInvoker.isAvailable()).thenReturn(false);\n        migrationInvoker.invoke(null);\n        Mockito.verify(invoker, Mockito.times(1)).invoke(null);\n\n        Mockito.when(serviceDiscoveryInvoker.isAvailable()).thenReturn(true);\n        migrationInvoker.invoke(null);\n        Mockito.verify(serviceDiscoveryInvoker, Mockito.times(2)).invoke(null);\n    }\n\n    @Test\n    void testConcurrency() {\n        // 独立线程\n\n        // 独立线程invoker状态切换\n\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/migration/MigrationRuleHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.registry.client.migration.model.MigrationStep;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass MigrationRuleHandlerTest {\n    @Test\n    void test() {\n        MigrationClusterInvoker<?> invoker = Mockito.mock(MigrationClusterInvoker.class);\n        URL url = Mockito.mock(URL.class);\n        Mockito.when(url.getDisplayServiceKey()).thenReturn(\"test\");\n        Mockito.when(url.getParameter(Mockito.any(), (String) Mockito.any())).thenAnswer(i -> i.getArgument(1));\n        Mockito.when(url.getOrDefaultApplicationModel()).thenReturn(ApplicationModel.defaultModel());\n        MigrationRuleHandler<?> handler = new MigrationRuleHandler<>(invoker, url);\n\n        Mockito.when(invoker.migrateToForceApplicationInvoker(Mockito.any())).thenReturn(true);\n        Mockito.when(invoker.migrateToForceInterfaceInvoker(Mockito.any())).thenReturn(true);\n\n        MigrationRule initRule = MigrationRule.getInitRule();\n        handler.doMigrate(initRule);\n        Mockito.verify(invoker, Mockito.times(1)).migrateToApplicationFirstInvoker(initRule);\n\n        MigrationRule rule = Mockito.mock(MigrationRule.class);\n        Mockito.when(rule.getStep(url)).thenReturn(MigrationStep.FORCE_APPLICATION);\n        handler.doMigrate(rule);\n        Mockito.verify(invoker, Mockito.times(1)).migrateToForceApplicationInvoker(rule);\n\n        Mockito.when(rule.getStep(url)).thenReturn(MigrationStep.APPLICATION_FIRST);\n        handler.doMigrate(rule);\n        Mockito.verify(invoker, Mockito.times(1)).migrateToApplicationFirstInvoker(rule);\n\n        Mockito.when(rule.getStep(url)).thenReturn(MigrationStep.FORCE_INTERFACE);\n        handler.doMigrate(rule);\n        Mockito.verify(invoker, Mockito.times(1)).migrateToForceInterfaceInvoker(rule);\n\n        // migration failed, current rule not changed\n        testMigrationFailed(rule, url, handler, invoker);\n        // rule not changed, check migration not actually executed\n        testMigrationWithStepUnchanged(rule, url, handler, invoker);\n    }\n\n    private void testMigrationFailed(\n            MigrationRule rule, URL url, MigrationRuleHandler<?> handler, MigrationClusterInvoker<?> invoker) {\n        Assertions.assertEquals(MigrationStep.FORCE_INTERFACE, handler.getMigrationStep());\n\n        Mockito.when(invoker.migrateToForceApplicationInvoker(Mockito.any())).thenReturn(false);\n\n        Mockito.when(rule.getStep(url)).thenReturn(MigrationStep.FORCE_APPLICATION);\n        handler.doMigrate(rule);\n        Mockito.verify(invoker, Mockito.times(2)).migrateToForceApplicationInvoker(rule);\n        Assertions.assertEquals(MigrationStep.FORCE_INTERFACE, handler.getMigrationStep());\n    }\n\n    private void testMigrationWithStepUnchanged(\n            MigrationRule rule, URL url, MigrationRuleHandler<?> handler, MigrationClusterInvoker<?> invoker) {\n        // set the same as\n        Mockito.when(rule.getStep(url)).thenReturn(handler.getMigrationStep());\n        handler.doMigrate(rule);\n        // no interaction\n        Mockito.verify(invoker, Mockito.times(1)).migrateToForceInterfaceInvoker(rule);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/migration/MigrationRuleListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;\nimport org.apache.dubbo.common.config.configcenter.DynamicConfiguration;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.registry.client.migration.model.MigrationRule;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\n\nimport static org.awaitility.Awaitility.await;\n\nclass MigrationRuleListenerTest {\n\n    private String localRule = \"key: demo-consumer\\n\" + \"step: APPLICATION_FIRST\\n\"\n            + \"threshold: 1.0\\n\"\n            + \"proportion: 60\\n\"\n            + \"delay: 60\\n\"\n            + \"force: false\\n\"\n            + \"interfaces:\\n\"\n            + \"  - serviceKey: DemoService:1.0.0\\n\"\n            + \"    threshold: 0.5\\n\"\n            + \"    proportion: 30\\n\"\n            + \"    delay: 30\\n\"\n            + \"    force: true\\n\"\n            + \"    step: APPLICATION_FIRST\\n\"\n            + \"  - serviceKey: GreetingService:1.0.0\\n\"\n            + \"    step: FORCE_APPLICATION\";\n\n    private String remoteRule = \"key: demo-consumer\\n\" + \"step: FORCE_APPLICATION\\n\"\n            + \"threshold: 1.0\\n\"\n            + \"proportion: 60\\n\"\n            + \"delay: 60\\n\"\n            + \"force: false\\n\"\n            + \"interfaces:\\n\"\n            + \"  - serviceKey: DemoService:1.0.0\\n\"\n            + \"    threshold: 0.5\\n\"\n            + \"    proportion: 30\\n\"\n            + \"    delay: 30\\n\"\n            + \"    force: true\\n\"\n            + \"    step: FORCE_APPLICATION\\n\"\n            + \"  - serviceKey: GreetingService:1.0.0\\n\"\n            + \"    step: FORCE_INTERFACE\";\n\n    private String dynamicRemoteRule = \"key: demo-consumer\\n\" + \"step: APPLICATION_FIRST\\n\"\n            + \"threshold: 1.0\\n\"\n            + \"proportion: 60\\n\"\n            + \"delay: 60\\n\"\n            + \"force: false\\n\"\n            + \"interfaces:\\n\";\n\n    @AfterEach\n    public void tearDown() {\n        ApplicationModel.reset();\n        System.clearProperty(\"dubbo.application.migration.delay\");\n    }\n\n    /**\n     * Listener started with config center and local rule, no initial remote rule.\n     * Check local rule take effect\n     */\n    @Test\n    void test() {\n        DynamicConfiguration dynamicConfiguration = Mockito.mock(DynamicConfiguration.class);\n\n        ApplicationModel.reset();\n        ApplicationModel.defaultModel()\n                .getDefaultModule()\n                .modelEnvironment()\n                .setDynamicConfiguration(dynamicConfiguration);\n        ApplicationModel.defaultModel().getDefaultModule().modelEnvironment().setLocalMigrationRule(localRule);\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"demo-consumer\");\n        ApplicationModel.defaultModel().getApplicationConfigManager().setApplication(applicationConfig);\n\n        URL consumerURL = Mockito.mock(URL.class);\n        Mockito.when(consumerURL.getServiceKey()).thenReturn(\"Test\");\n        Mockito.when(consumerURL.getParameter(\"timestamp\")).thenReturn(\"1\");\n\n        System.setProperty(\"dubbo.application.migration.delay\", \"1\");\n        MigrationRuleHandler<?> handler =\n                Mockito.mock(MigrationRuleHandler.class, Mockito.withSettings().verboseLogging());\n\n        CountDownLatch countDownLatch = new CountDownLatch(1);\n        MigrationRuleListener migrationRuleListener =\n                new MigrationRuleListener(ApplicationModel.defaultModel().getDefaultModule()) {\n                    @Override\n                    public synchronized void process(ConfigChangedEvent event) {\n                        try {\n                            countDownLatch.await();\n                        } catch (InterruptedException e) {\n                            throw new RuntimeException(e);\n                        }\n                        super.process(event);\n                    }\n                };\n\n        MigrationInvoker<?> migrationInvoker = Mockito.mock(MigrationInvoker.class);\n        migrationRuleListener.getHandlers().put(migrationInvoker, handler);\n\n        countDownLatch.countDown();\n        await().untilAsserted(() -> {\n            Mockito.verify(handler).doMigrate(Mockito.any());\n        });\n        //        Mockito.verify(handler, Mockito.timeout(5000)).doMigrate(Mockito.any());\n\n        migrationRuleListener.onRefer(null, migrationInvoker, consumerURL, null);\n        Mockito.verify(handler, Mockito.times(2)).doMigrate(Mockito.any());\n    }\n\n    /**\n     * Test listener started without local rule and config center, INIT should be used and no scheduled task should be started.\n     */\n    @Test\n    void testWithInitAndNoLocalRule() {\n        ApplicationModel.defaultModel().getDefaultModule().modelEnvironment().setDynamicConfiguration(null);\n        ApplicationModel.defaultModel().getDefaultModule().modelEnvironment().setLocalMigrationRule(\"\");\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"demo-consumer\");\n        ApplicationModel.defaultModel().getApplicationConfigManager().setApplication(applicationConfig);\n\n        URL consumerURL = Mockito.mock(URL.class);\n        Mockito.when(consumerURL.getServiceKey()).thenReturn(\"Test\");\n        Mockito.when(consumerURL.getParameter(\"timestamp\")).thenReturn(\"1\");\n\n        System.setProperty(\"dubbo.application.migration.delay\", \"1000\");\n        MigrationRuleHandler<?> handler =\n                Mockito.mock(MigrationRuleHandler.class, Mockito.withSettings().verboseLogging());\n\n        MigrationRuleListener migrationRuleListener =\n                new MigrationRuleListener(ApplicationModel.defaultModel().getDefaultModule());\n        MigrationInvoker<?> migrationInvoker = Mockito.mock(MigrationInvoker.class);\n        migrationRuleListener.getHandlers().put(migrationInvoker, handler);\n        migrationRuleListener.onRefer(null, migrationInvoker, consumerURL, null);\n        // check migration happened after invoker referred\n        Mockito.verify(handler, Mockito.times(1)).doMigrate(MigrationRule.getInitRule());\n\n        // check no delay tasks created for there's no local rule and no config center\n        Assertions.assertNull(migrationRuleListener.localRuleMigrationFuture);\n        Assertions.assertNull(migrationRuleListener.ruleMigrationFuture);\n        Assertions.assertEquals(0, migrationRuleListener.ruleQueue.size());\n    }\n\n    /**\n     * Listener with config center， initial remote rule and local rule, check\n     * 1. initial remote rule other than local rule take effect\n     * 2. remote rule change and all invokers gets notified\n     */\n    @Test\n    void testWithConfigurationListenerAndLocalRule() {\n        DynamicConfiguration dynamicConfiguration = Mockito.mock(DynamicConfiguration.class);\n        Mockito.doReturn(remoteRule).when(dynamicConfiguration).getConfig(Mockito.anyString(), Mockito.anyString());\n\n        ApplicationModel.defaultModel()\n                .getDefaultModule()\n                .modelEnvironment()\n                .setDynamicConfiguration(dynamicConfiguration);\n        ApplicationModel.defaultModel().getDefaultModule().modelEnvironment().setLocalMigrationRule(localRule);\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"demo-consumer\");\n        ApplicationModel.defaultModel().getApplicationConfigManager().setApplication(applicationConfig);\n\n        URL consumerURL = Mockito.mock(URL.class);\n        Mockito.when(consumerURL.getServiceKey()).thenReturn(\"Test\");\n        Mockito.when(consumerURL.getParameter(\"timestamp\")).thenReturn(\"1\");\n\n        URL consumerURL2 = Mockito.mock(URL.class);\n        Mockito.when(consumerURL2.getServiceKey()).thenReturn(\"Test2\");\n        Mockito.when(consumerURL2.getParameter(\"timestamp\")).thenReturn(\"2\");\n\n        System.setProperty(\"dubbo.application.migration.delay\", \"10\");\n        MigrationRuleHandler<?> handler =\n                Mockito.mock(MigrationRuleHandler.class, Mockito.withSettings().verboseLogging());\n        MigrationRuleHandler<?> handler2 =\n                Mockito.mock(MigrationRuleHandler.class, Mockito.withSettings().verboseLogging());\n\n        // Both local rule and remote rule are here\n        // Local rule with one delayed task started to apply\n        MigrationRuleListener migrationRuleListener =\n                new MigrationRuleListener(ApplicationModel.defaultModel().getDefaultModule());\n        Assertions.assertNotNull(migrationRuleListener.localRuleMigrationFuture);\n        Assertions.assertNull(migrationRuleListener.ruleMigrationFuture);\n        MigrationInvoker<?> migrationInvoker = Mockito.mock(MigrationInvoker.class);\n        MigrationInvoker<?> migrationInvoker2 = Mockito.mock(MigrationInvoker.class);\n\n        // Remote rule will be applied when onRefer gets executed\n        migrationRuleListener.getHandlers().put(migrationInvoker, handler);\n        migrationRuleListener.onRefer(null, migrationInvoker, consumerURL, null);\n\n        MigrationRule tmpRemoteRule = migrationRuleListener.getRule();\n        ArgumentCaptor<MigrationRule> captor = ArgumentCaptor.forClass(MigrationRule.class);\n        Mockito.verify(handler, Mockito.times(1)).doMigrate(captor.capture());\n        Assertions.assertEquals(tmpRemoteRule, captor.getValue());\n\n        await().until(() -> migrationRuleListener.localRuleMigrationFuture.isDone());\n        Assertions.assertNull(migrationRuleListener.ruleMigrationFuture);\n        Assertions.assertEquals(tmpRemoteRule, migrationRuleListener.getRule());\n        Mockito.verify(handler, Mockito.times(1)).doMigrate(Mockito.any());\n\n        ArgumentCaptor<MigrationRule> captor2 = ArgumentCaptor.forClass(MigrationRule.class);\n        migrationRuleListener.getHandlers().put(migrationInvoker2, handler2);\n        migrationRuleListener.onRefer(null, migrationInvoker2, consumerURL2, null);\n        Mockito.verify(handler2, Mockito.times(1)).doMigrate(captor2.capture());\n        Assertions.assertEquals(tmpRemoteRule, captor2.getValue());\n\n        migrationRuleListener.process(new ConfigChangedEvent(\"key\", \"group\", dynamicRemoteRule));\n\n        await().until(migrationRuleListener.ruleQueue::isEmpty);\n        await().untilAsserted(() -> {\n            Mockito.verify(handler, Mockito.times(2)).doMigrate(Mockito.any());\n            Mockito.verify(handler2, Mockito.times(2)).doMigrate(Mockito.any());\n        });\n\n        Assertions.assertNotNull(migrationRuleListener.ruleMigrationFuture);\n        ArgumentCaptor<MigrationRule> captor_event = ArgumentCaptor.forClass(MigrationRule.class);\n        Mockito.verify(handler, Mockito.times(2)).doMigrate(captor_event.capture());\n        Assertions.assertEquals(\n                \"APPLICATION_FIRST\", captor_event.getValue().getStep().toString());\n        Mockito.verify(handler2, Mockito.times(2)).doMigrate(captor_event.capture());\n        Assertions.assertEquals(\n                \"APPLICATION_FIRST\", captor_event.getValue().getStep().toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/migration/model/MigrationRuleTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.migration.model;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metadata.ServiceNameMapping;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_CLUSTER_TYPE_KEY;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass MigrationRuleTest {\n    private static final ServiceNameMapping mapping = mock(ServiceNameMapping.class);\n\n    @Test\n    void test_parse() {\n        when(mapping.getMapping(any(URL.class))).thenReturn(Collections.emptySet());\n\n        String rule = \"key: demo-consumer\\n\" + \"step: APPLICATION_FIRST\\n\"\n                + \"threshold: 1.0\\n\"\n                + \"proportion: 60\\n\"\n                + \"delay: 60\\n\"\n                + \"force: false\\n\"\n                + \"interfaces:\\n\"\n                + \"  - serviceKey: DemoService:1.0.0\\n\"\n                + \"    threshold: 0.5\\n\"\n                + \"    proportion: 30\\n\"\n                + \"    delay: 30\\n\"\n                + \"    force: true\\n\"\n                + \"    step: APPLICATION_FIRST\\n\"\n                + \"  - serviceKey: GreetingService:1.0.0\\n\"\n                + \"    step: FORCE_APPLICATION\\n\"\n                + \"applications:\\n\"\n                + \"  - serviceKey: TestApplication\\n\"\n                + \"    threshold: 0.3\\n\"\n                + \"    proportion: 20\\n\"\n                + \"    delay: 10\\n\"\n                + \"    force: false\\n\"\n                + \"    step: FORCE_INTERFACE\\n\";\n\n        MigrationRule migrationRule = MigrationRule.parse(rule);\n        assertEquals(\"demo-consumer\", migrationRule.getKey());\n        assertEquals(MigrationStep.APPLICATION_FIRST, migrationRule.getStep());\n        assertEquals(1.0f, migrationRule.getThreshold());\n        assertEquals(60, migrationRule.getProportion());\n        assertEquals(60, migrationRule.getDelay());\n        assertEquals(false, migrationRule.getForce());\n\n        URL url = Mockito.mock(URL.class);\n        ApplicationModel defaultModel = Mockito.spy(ApplicationModel.defaultModel());\n        Mockito.when(defaultModel.getDefaultExtension(ServiceNameMapping.class)).thenReturn(mapping);\n\n        Mockito.when(url.getScopeModel()).thenReturn(defaultModel);\n        Mockito.when(url.getDisplayServiceKey()).thenReturn(\"DemoService:1.0.0\");\n        Mockito.when(url.getParameter(ArgumentMatchers.eq(REGISTRY_CLUSTER_TYPE_KEY), anyString()))\n                .thenReturn(\"default\");\n        Mockito.when(url.getParameter(ArgumentMatchers.eq(REGISTRY_CLUSTER_TYPE_KEY), anyString()))\n                .thenReturn(\"default\");\n\n        assertEquals(2, migrationRule.getInterfaces().size());\n\n        assertEquals(0.5f, migrationRule.getThreshold(url));\n        assertEquals(30, migrationRule.getProportion(url));\n        assertEquals(30, migrationRule.getDelay(url));\n        assertTrue(migrationRule.getForce(url));\n        assertEquals(MigrationStep.APPLICATION_FIRST, migrationRule.getStep(url));\n\n        Mockito.when(url.getDisplayServiceKey()).thenReturn(\"GreetingService:1.0.0\");\n        assertEquals(1.0f, migrationRule.getThreshold(url));\n        assertEquals(60, migrationRule.getProportion(url));\n        assertEquals(60, migrationRule.getDelay(url));\n        assertFalse(migrationRule.getForce(url));\n        assertEquals(MigrationStep.FORCE_APPLICATION, migrationRule.getStep(url));\n\n        Mockito.when(url.getDisplayServiceKey()).thenReturn(\"GreetingService:1.0.1\");\n        Mockito.when(url.getServiceInterface()).thenReturn(\"GreetingService\");\n        when(mapping.getRemoteMapping(any(URL.class))).thenReturn(Collections.singleton(\"TestApplication\"));\n\n        Set<String> services = new HashSet<>();\n        services.add(\"TestApplication\");\n        when(mapping.getMapping(any(URL.class))).thenReturn(services);\n        assertEquals(0.3f, migrationRule.getThreshold(url));\n        assertEquals(20, migrationRule.getProportion(url));\n        assertEquals(10, migrationRule.getDelay(url));\n        assertFalse(migrationRule.getForce(url));\n        assertEquals(MigrationStep.FORCE_INTERFACE, migrationRule.getStep(url));\n        when(mapping.getMapping(any(URL.class))).thenReturn(Collections.emptySet());\n\n        ApplicationModel.defaultModel().destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/support/MockServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.metadata.store.MetaCacheManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\npublic class MockServiceDiscovery extends AbstractServiceDiscovery {\n    public MockServiceDiscovery(ApplicationModel applicationModel, URL registryURL) {\n        super(applicationModel, registryURL);\n    }\n\n    public MockServiceDiscovery(String serviceName, URL registryURL) {\n        super(serviceName, registryURL);\n    }\n\n    @Override\n    public void doRegister(ServiceInstance serviceInstance) throws RuntimeException {}\n\n    @Override\n    public void doUnregister(ServiceInstance serviceInstance) {}\n\n    @Override\n    public void doDestroy() throws Exception {}\n\n    @Override\n    public Set<String> getServices() {\n        return null;\n    }\n\n    @Override\n    public List<ServiceInstance> getInstances(String serviceName) throws NullPointerException {\n        return Collections.emptyList();\n    }\n\n    public MetaCacheManager getMetaCacheManager() {\n        return metaCacheManager;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/support/MockServiceDiscoveryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.client.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscoveryFactory;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\n\npublic class MockServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory {\n    @Override\n    protected ServiceDiscovery createDiscovery(URL registryURL) {\n        return new MockServiceDiscovery(applicationModel, registryURL);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/integration/CountRegistryProtocolListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.rpc.Exporter;\nimport org.apache.dubbo.rpc.cluster.ClusterInvoker;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\npublic class CountRegistryProtocolListener implements RegistryProtocolListener {\n\n    private static final AtomicInteger referCounter = new AtomicInteger(0);\n\n    @Override\n    public void onExport(RegistryProtocol registryProtocol, Exporter<?> exporter) {}\n\n    @Override\n    public void onRefer(RegistryProtocol registryProtocol, ClusterInvoker<?> invoker, URL url, URL registryURL) {\n        referCounter.incrementAndGet();\n    }\n\n    @Override\n    public void onDestroy() {}\n\n    public static AtomicInteger getReferCounter() {\n        return referCounter;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/integration/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\npublic interface DemoService {}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/integration/DynamicDirectoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.registry.Registry;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;\nimport static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;\nimport static org.apache.dubbo.registry.Constants.SIMPLIFIED_KEY;\nimport static org.apache.dubbo.registry.integration.RegistryProtocol.DEFAULT_REGISTER_CONSUMER_KEYS;\nimport static org.apache.dubbo.remoting.Constants.CHECK_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nclass DynamicDirectoryTest {\n\n    /**\n     * verify simplified consumer url information that needs to be registered\n     */\n    @Test\n    void testSimplifiedUrl() {\n\n        // verify that the consumer url information that needs to be registered is not simplified by default\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(\"register\", \"true\");\n        parameters.put(REGISTER_IP_KEY, \"172.23.236.180\");\n\n        Map<String, Object> attributes = new HashMap<>();\n        ServiceConfigURL serviceConfigURLWithoutSimplified = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        Map<String, String> refer = new HashMap<>();\n        attributes.put(REFER_KEY, refer);\n        attributes.put(\"key1\", \"value1\");\n        URL urlWithoutSimplified = serviceConfigURLWithoutSimplified.addAttributes(attributes);\n\n        DemoDynamicDirectory<DemoService> dynamicDirectoryWithoutSimplified =\n                new DemoDynamicDirectory<>(DemoService.class, urlWithoutSimplified);\n\n        URL registeredConsumerUrlWithoutSimplified =\n                new ServiceConfigURL(\"dubbo\", \"127.0.0.1\", 2181, DemoService.class.getName(), parameters);\n\n        dynamicDirectoryWithoutSimplified.setRegisteredConsumerUrl(registeredConsumerUrlWithoutSimplified);\n\n        URL urlForNotSimplified = registeredConsumerUrlWithoutSimplified.addParameters(\n                CATEGORY_KEY, CONSUMERS_CATEGORY, CHECK_KEY, String.valueOf(false));\n\n        Assertions.assertEquals(urlForNotSimplified, dynamicDirectoryWithoutSimplified.getRegisteredConsumerUrl());\n\n        // verify simplified consumer url information that needs to be registered\n        parameters.put(SIMPLIFIED_KEY, \"true\");\n        ServiceConfigURL serviceConfigURLWithSimplified = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        URL urlWithSimplified = serviceConfigURLWithSimplified.addAttributes(attributes);\n        DemoDynamicDirectory<DemoService> dynamicDirectoryWithSimplified =\n                new DemoDynamicDirectory<>(DemoService.class, urlWithSimplified);\n\n        URL registeredConsumerUrlWithSimplified =\n                new ServiceConfigURL(\"dubbo\", \"127.0.0.1\", 2181, DemoService.class.getName(), parameters);\n\n        dynamicDirectoryWithSimplified.setRegisteredConsumerUrl(registeredConsumerUrlWithSimplified);\n\n        URL urlForSimplified = URL.valueOf(registeredConsumerUrlWithSimplified, DEFAULT_REGISTER_CONSUMER_KEYS, null)\n                .addParameters(CATEGORY_KEY, CONSUMERS_CATEGORY, CHECK_KEY, String.valueOf(false));\n\n        Assertions.assertEquals(urlForSimplified, dynamicDirectoryWithSimplified.getRegisteredConsumerUrl());\n    }\n\n    @Test\n    void testSubscribe() {\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(\"register\", \"true\");\n        parameters.put(REGISTER_IP_KEY, \"172.23.236.180\");\n\n        Map<String, Object> attributes = new HashMap<>();\n        ServiceConfigURL serviceConfigUrl = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        Map<String, String> refer = new HashMap<>();\n        attributes.put(REFER_KEY, refer);\n        attributes.put(\"key1\", \"value1\");\n        URL url = serviceConfigUrl.addAttributes(attributes);\n\n        DemoDynamicDirectory<DemoService> demoDynamicDirectory = new DemoDynamicDirectory<>(DemoService.class, url);\n\n        URL subscribeUrl = new ServiceConfigURL(\"dubbo\", \"127.0.0.1\", 20881, DemoService.class.getName(), parameters);\n\n        Registry registry = mock(Registry.class);\n        demoDynamicDirectory.setRegistry(registry);\n\n        demoDynamicDirectory.subscribe(subscribeUrl);\n\n        verify(registry, times(1)).subscribe(subscribeUrl, demoDynamicDirectory);\n        Assertions.assertEquals(subscribeUrl, demoDynamicDirectory.getSubscribeUrl());\n    }\n\n    static class DemoDynamicDirectory<T> extends DynamicDirectory<T> {\n\n        public DemoDynamicDirectory(Class<T> serviceType, URL url) {\n            super(serviceType, url);\n        }\n\n        @Override\n        protected void destroyAllInvokers() {}\n\n        @Override\n        protected void refreshOverrideAndInvoker(List<URL> urls) {}\n\n        @Override\n        public boolean isAvailable() {\n            return false;\n        }\n\n        @Override\n        public void notify(List<URL> urls) {}\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/integration/RegistryProtocolTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.integration;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.CompositeConfiguration;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.config.context.ConfigManager;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\nimport org.apache.dubbo.registry.client.migration.MigrationInvoker;\nimport org.apache.dubbo.registry.client.migration.MigrationRuleListener;\nimport org.apache.dubbo.rpc.Invoker;\nimport org.apache.dubbo.rpc.cluster.Cluster;\nimport org.apache.dubbo.rpc.cluster.support.FailoverCluster;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper;\nimport org.apache.dubbo.rpc.cluster.support.wrapper.ScopeClusterWrapper;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ModuleModel;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_PROTOCOL_LISTENER_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;\nimport static org.apache.dubbo.registry.Constants.ENABLE_CONFIGURATION_LISTEN;\nimport static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;\nimport static org.apache.dubbo.remoting.Constants.CHECK_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.CONSUMER_URL_KEY;\nimport static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass RegistryProtocolTest {\n\n    @AfterEach\n    public void tearDown() throws IOException {\n        Mockito.framework().clearInlineMocks();\n        ApplicationModel.defaultModel().destroy();\n    }\n\n    /**\n     * verify the generated consumer url information\n     */\n    @Test\n    void testConsumerUrlWithoutProtocol() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n\n        ConfigManager configManager = mock(ConfigManager.class);\n        when(configManager.getApplicationOrElseThrow()).thenReturn(applicationConfig);\n\n        CompositeConfiguration compositeConfiguration = mock(CompositeConfiguration.class);\n        when(compositeConfiguration.convert(Boolean.class, ENABLE_CONFIGURATION_LISTEN, true))\n                .thenReturn(true);\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(\"register\", \"false\");\n        parameters.put(REGISTER_IP_KEY, \"172.23.236.180\");\n\n        Map<String, Object> attributes = new HashMap<>();\n        ServiceConfigURL serviceConfigURL = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        Map<String, String> refer = new HashMap<>();\n        attributes.put(REFER_KEY, refer);\n        attributes.put(\"key1\", \"value1\");\n        URL url = serviceConfigURL.addAttributes(attributes);\n\n        RegistryFactory registryFactory = mock(RegistryFactory.class);\n        Registry registry = mock(Registry.class);\n\n        RegistryProtocol registryProtocol = new RegistryProtocol();\n\n        MigrationRuleListener migrationRuleListener = mock(MigrationRuleListener.class);\n        List<RegistryProtocolListener> registryProtocolListeners = new ArrayList<>();\n        registryProtocolListeners.add(migrationRuleListener);\n\n        ModuleModel moduleModel = Mockito.spy(ApplicationModel.defaultModel().getDefaultModule());\n        moduleModel\n                .getApplicationModel()\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(\"application1\"));\n        ExtensionLoader<RegistryProtocolListener> extensionLoaderMock = mock(ExtensionLoader.class);\n        Mockito.when(moduleModel.getExtensionLoader(RegistryProtocolListener.class))\n                .thenReturn(extensionLoaderMock);\n        Mockito.when(extensionLoaderMock.getActivateExtension(url, REGISTRY_PROTOCOL_LISTENER_KEY))\n                .thenReturn(registryProtocolListeners);\n        url = url.setScopeModel(moduleModel);\n\n        when(registryFactory.getRegistry(registryProtocol.getRegistryUrl(url))).thenReturn(registry);\n\n        Cluster cluster = mock(Cluster.class);\n\n        Invoker<?> invoker = registryProtocol.doRefer(cluster, registry, DemoService.class, url, parameters);\n\n        Assertions.assertTrue(invoker instanceof MigrationInvoker);\n\n        URL consumerUrl = ((MigrationInvoker<?>) invoker).getConsumerUrl();\n        Assertions.assertTrue((consumerUrl != null));\n\n        // verify that the protocol header of consumerUrl is set to \"consumer\"\n        Assertions.assertEquals(\"consumer\", consumerUrl.getProtocol());\n        Assertions.assertEquals(parameters.get(REGISTER_IP_KEY), consumerUrl.getHost());\n        Assertions.assertFalse(consumerUrl.getAttributes().containsKey(REFER_KEY));\n        Assertions.assertEquals(\"value1\", consumerUrl.getAttribute(\"key1\"));\n    }\n\n    /**\n     * verify that when the protocol is configured, the protocol of consumer url is the configured protocol\n     */\n    @Test\n    void testConsumerUrlWithProtocol() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n\n        ConfigManager configManager = mock(ConfigManager.class);\n        when(configManager.getApplicationOrElseThrow()).thenReturn(applicationConfig);\n\n        CompositeConfiguration compositeConfiguration = mock(CompositeConfiguration.class);\n        when(compositeConfiguration.convert(Boolean.class, ENABLE_CONFIGURATION_LISTEN, true))\n                .thenReturn(true);\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(\"register\", \"false\");\n        parameters.put(REGISTER_IP_KEY, \"172.23.236.180\");\n        parameters.put(PROTOCOL_KEY, \"tri\");\n        Map<String, Object> attributes = new HashMap<>();\n        ServiceConfigURL serviceConfigURL = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        Map<String, String> refer = new HashMap<>();\n        attributes.put(REFER_KEY, refer);\n        attributes.put(\"key1\", \"value1\");\n        URL url = serviceConfigURL.addAttributes(attributes);\n\n        RegistryFactory registryFactory = mock(RegistryFactory.class);\n\n        RegistryProtocol registryProtocol = new RegistryProtocol();\n        Registry registry = mock(Registry.class);\n\n        MigrationRuleListener migrationRuleListener = mock(MigrationRuleListener.class);\n        List<RegistryProtocolListener> registryProtocolListeners = new ArrayList<>();\n        registryProtocolListeners.add(migrationRuleListener);\n\n        ModuleModel moduleModel = Mockito.spy(ApplicationModel.defaultModel().getDefaultModule());\n        moduleModel\n                .getApplicationModel()\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(\"application1\"));\n        ExtensionLoader<RegistryProtocolListener> extensionLoaderMock = mock(ExtensionLoader.class);\n        Mockito.when(moduleModel.getExtensionLoader(RegistryProtocolListener.class))\n                .thenReturn(extensionLoaderMock);\n        Mockito.when(extensionLoaderMock.getActivateExtension(url, REGISTRY_PROTOCOL_LISTENER_KEY))\n                .thenReturn(registryProtocolListeners);\n        url = url.setScopeModel(moduleModel);\n\n        when(registryFactory.getRegistry(registryProtocol.getRegistryUrl(url))).thenReturn(registry);\n\n        Cluster cluster = mock(Cluster.class);\n\n        Invoker<?> invoker = registryProtocol.doRefer(cluster, registry, DemoService.class, url, parameters);\n\n        Assertions.assertTrue(invoker instanceof MigrationInvoker);\n\n        URL consumerUrl = ((MigrationInvoker<?>) invoker).getConsumerUrl();\n        Assertions.assertTrue((consumerUrl != null));\n\n        // verify that the protocol of consumer url\n        Assertions.assertEquals(\"tri\", consumerUrl.getProtocol());\n        Assertions.assertEquals(parameters.get(REGISTER_IP_KEY), consumerUrl.getHost());\n        Assertions.assertFalse(consumerUrl.getAttributes().containsKey(REFER_KEY));\n        Assertions.assertEquals(\"value1\", consumerUrl.getAttribute(\"key1\"));\n    }\n\n    /**\n     * verify that if multiple groups are not configured, the service reference of the registration center\n     * the default is FailoverCluster\n     *\n     * @see FailoverCluster\n     */\n    @Test\n    void testReferWithoutGroup() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n\n        ConfigManager configManager = mock(ConfigManager.class);\n        when(configManager.getApplicationOrElseThrow()).thenReturn(applicationConfig);\n\n        CompositeConfiguration compositeConfiguration = mock(CompositeConfiguration.class);\n        when(compositeConfiguration.convert(Boolean.class, ENABLE_CONFIGURATION_LISTEN, true))\n                .thenReturn(true);\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(\"register\", \"false\");\n\n        Map<String, Object> attributes = new HashMap<>();\n        ServiceConfigURL serviceConfigURL = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        Map<String, String> refer = new HashMap<>();\n        attributes.put(REFER_KEY, refer);\n        URL url = serviceConfigURL.addAttributes(attributes);\n\n        RegistryFactory registryFactory = mock(RegistryFactory.class);\n        Registry registry = mock(Registry.class);\n\n        MigrationRuleListener migrationRuleListener = mock(MigrationRuleListener.class);\n        List<RegistryProtocolListener> registryProtocolListeners = new ArrayList<>();\n        registryProtocolListeners.add(migrationRuleListener);\n\n        RegistryProtocol registryProtocol = new RegistryProtocol();\n        ModuleModel moduleModel = Mockito.spy(ApplicationModel.defaultModel().getDefaultModule());\n        moduleModel\n                .getApplicationModel()\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(\"application1\"));\n        ExtensionLoader extensionLoaderMock = mock(ExtensionLoader.class);\n        Mockito.when(moduleModel.getExtensionLoader(RegistryProtocolListener.class))\n                .thenReturn(extensionLoaderMock);\n        Mockito.when(extensionLoaderMock.getActivateExtension(url, REGISTRY_PROTOCOL_LISTENER_KEY))\n                .thenReturn(registryProtocolListeners);\n        Mockito.when(moduleModel.getExtensionLoader(RegistryFactory.class)).thenReturn(extensionLoaderMock);\n        Mockito.when(extensionLoaderMock.getAdaptiveExtension()).thenReturn(registryFactory);\n        url = url.setScopeModel(moduleModel);\n\n        when(registryFactory.getRegistry(registryProtocol.getRegistryUrl(url))).thenReturn(registry);\n\n        Invoker<?> invoker = registryProtocol.refer(DemoService.class, url);\n\n        Assertions.assertTrue(invoker instanceof MigrationInvoker);\n        Assertions.assertTrue(((MigrationInvoker<?>) invoker).getCluster() instanceof ScopeClusterWrapper);\n        Assertions.assertTrue(\n                ((ScopeClusterWrapper) ((MigrationInvoker<?>) invoker).getCluster()).getCluster()\n                        instanceof MockClusterWrapper);\n        Assertions.assertTrue(\n                ((MockClusterWrapper) ((ScopeClusterWrapper) ((MigrationInvoker<?>) invoker).getCluster()).getCluster())\n                                .getCluster()\n                        instanceof FailoverCluster);\n    }\n\n    /**\n     * verify that if multiple groups are configured, the service reference of the registration center\n     *\n     * @see MergeableCluster\n     */\n    @Test\n    void testReferWithGroup() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n\n        ConfigManager configManager = mock(ConfigManager.class);\n        when(configManager.getApplicationOrElseThrow()).thenReturn(applicationConfig);\n\n        CompositeConfiguration compositeConfiguration = mock(CompositeConfiguration.class);\n        when(compositeConfiguration.convert(Boolean.class, ENABLE_CONFIGURATION_LISTEN, true))\n                .thenReturn(true);\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(\"register\", \"false\");\n\n        Map<String, Object> attributes = new HashMap<>();\n        ServiceConfigURL serviceConfigURL = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        Map<String, String> refer = new HashMap<>();\n        refer.put(GROUP_KEY, \"group1,group2\");\n        attributes.put(REFER_KEY, refer);\n        URL url = serviceConfigURL.addAttributes(attributes);\n\n        RegistryFactory registryFactory = mock(RegistryFactory.class);\n        Registry registry = mock(Registry.class);\n\n        MigrationRuleListener migrationRuleListener = mock(MigrationRuleListener.class);\n        List<RegistryProtocolListener> registryProtocolListeners = new ArrayList<>();\n        registryProtocolListeners.add(migrationRuleListener);\n\n        RegistryProtocol registryProtocol = new RegistryProtocol();\n        ModuleModel moduleModel = Mockito.spy(ApplicationModel.defaultModel().getDefaultModule());\n        moduleModel\n                .getApplicationModel()\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(\"application1\"));\n        ExtensionLoader extensionLoaderMock = mock(ExtensionLoader.class);\n        Mockito.when(moduleModel.getExtensionLoader(RegistryProtocolListener.class))\n                .thenReturn(extensionLoaderMock);\n        Mockito.when(extensionLoaderMock.getActivateExtension(url, REGISTRY_PROTOCOL_LISTENER_KEY))\n                .thenReturn(registryProtocolListeners);\n        Mockito.when(moduleModel.getExtensionLoader(RegistryFactory.class)).thenReturn(extensionLoaderMock);\n        Mockito.when(extensionLoaderMock.getAdaptiveExtension()).thenReturn(registryFactory);\n        url = url.setScopeModel(moduleModel);\n\n        when(registryFactory.getRegistry(registryProtocol.getRegistryUrl(url))).thenReturn(registry);\n\n        Invoker<?> invoker = registryProtocol.refer(DemoService.class, url);\n\n        Assertions.assertTrue(invoker instanceof MigrationInvoker);\n\n        Assertions.assertTrue(((MigrationInvoker<?>) invoker).getCluster() instanceof ScopeClusterWrapper);\n        //        Assertions.assertTrue(((ScopeClusterWrapper) ((MigrationInvoker<?>)\n        // invoker).getCluster()).getCluster() instanceof MockClusterWrapper);\n\n        //        Assertions.assertTrue(((MockClusterWrapper) ((ScopeClusterWrapper) ((MigrationInvoker<?>)\n        // invoker).getCluster()).getCluster()).getCluster() instanceof MergeableCluster);\n\n    }\n\n    /**\n     * verify that the default RegistryProtocolListener will be executed\n     *\n     * @see MigrationRuleListener\n     */\n    @Test\n    void testInterceptInvokerForMigrationRuleListener() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n\n        ConfigManager configManager = mock(ConfigManager.class);\n        when(configManager.getApplicationOrElseThrow()).thenReturn(applicationConfig);\n\n        CompositeConfiguration compositeConfiguration = mock(CompositeConfiguration.class);\n        when(compositeConfiguration.convert(Boolean.class, ENABLE_CONFIGURATION_LISTEN, true))\n                .thenReturn(true);\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(\"register\", \"false\");\n\n        Map<String, Object> attributes = new HashMap<>();\n        ServiceConfigURL serviceConfigURL = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        Map<String, String> refer = new HashMap<>();\n        refer.put(GROUP_KEY, \"group1,group2\");\n        attributes.put(REFER_KEY, refer);\n        URL url = serviceConfigURL.addAttributes(attributes);\n\n        MigrationInvoker<?> clusterInvoker = mock(MigrationInvoker.class);\n\n        Map<String, Object> consumerAttribute = new HashMap<>(url.getAttributes());\n        consumerAttribute.remove(REFER_KEY);\n        URL consumerUrl = new ServiceConfigURL(\n                parameters.get(PROTOCOL_KEY) == null ? DUBBO : parameters.get(PROTOCOL_KEY),\n                null,\n                null,\n                parameters.get(REGISTER_IP_KEY),\n                0,\n                url.getPath(),\n                parameters,\n                consumerAttribute);\n        url = url.putAttribute(CONSUMER_URL_KEY, consumerUrl);\n        MigrationRuleListener migrationRuleListener = mock(MigrationRuleListener.class);\n        List<RegistryProtocolListener> registryProtocolListeners = new ArrayList<>();\n        registryProtocolListeners.add(migrationRuleListener);\n\n        RegistryProtocol registryProtocol = new RegistryProtocol();\n        ModuleModel moduleModel = Mockito.spy(ApplicationModel.defaultModel().getDefaultModule());\n        moduleModel\n                .getApplicationModel()\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(\"application1\"));\n        ExtensionLoader<RegistryProtocolListener> extensionLoaderMock = mock(ExtensionLoader.class);\n        Mockito.when(moduleModel.getExtensionLoader(RegistryProtocolListener.class))\n                .thenReturn(extensionLoaderMock);\n        Mockito.when(extensionLoaderMock.getActivateExtension(url, REGISTRY_PROTOCOL_LISTENER_KEY))\n                .thenReturn(registryProtocolListeners);\n        url = url.setScopeModel(moduleModel);\n\n        registryProtocol.interceptInvoker(clusterInvoker, url, consumerUrl);\n        verify(migrationRuleListener, times(1)).onRefer(registryProtocol, clusterInvoker, consumerUrl, url);\n    }\n\n    /**\n     * Verify that if registry.protocol.listener is configured,\n     * whether the corresponding RegistryProtocolListener will be executed normally\n     *\n     * @see CountRegistryProtocolListener\n     */\n    @Test\n    void testInterceptInvokerForCustomRegistryProtocolListener() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n\n        ConfigManager configManager = mock(ConfigManager.class);\n        when(configManager.getApplicationOrElseThrow()).thenReturn(applicationConfig);\n\n        CompositeConfiguration compositeConfiguration = mock(CompositeConfiguration.class);\n        when(compositeConfiguration.convert(Boolean.class, ENABLE_CONFIGURATION_LISTEN, true))\n                .thenReturn(true);\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(\"register\", \"false\");\n        parameters.put(REGISTRY_PROTOCOL_LISTENER_KEY, \"count\");\n\n        Map<String, Object> attributes = new HashMap<>();\n        ServiceConfigURL serviceConfigURL = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        Map<String, String> refer = new HashMap<>();\n        refer.put(GROUP_KEY, \"group1,group2\");\n        attributes.put(REFER_KEY, refer);\n        URL url = serviceConfigURL.addAttributes(attributes);\n\n        RegistryProtocol registryProtocol = new RegistryProtocol();\n        MigrationInvoker<?> clusterInvoker = mock(MigrationInvoker.class);\n\n        Map<String, Object> consumerAttribute = new HashMap<>(url.getAttributes());\n        consumerAttribute.remove(REFER_KEY);\n        URL consumerUrl = new ServiceConfigURL(\n                parameters.get(PROTOCOL_KEY) == null ? DUBBO : parameters.get(PROTOCOL_KEY),\n                null,\n                null,\n                parameters.get(REGISTER_IP_KEY),\n                0,\n                url.getPath(),\n                parameters,\n                consumerAttribute);\n        url = url.putAttribute(CONSUMER_URL_KEY, consumerUrl);\n\n        List<RegistryProtocolListener> registryProtocolListeners = new ArrayList<>();\n        registryProtocolListeners.add(new CountRegistryProtocolListener());\n\n        ModuleModel moduleModel = Mockito.spy(ApplicationModel.defaultModel().getDefaultModule());\n        moduleModel\n                .getApplicationModel()\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(\"application1\"));\n        ExtensionLoader<RegistryProtocolListener> extensionLoaderMock = mock(ExtensionLoader.class);\n        Mockito.when(moduleModel.getExtensionLoader(RegistryProtocolListener.class))\n                .thenReturn(extensionLoaderMock);\n        Mockito.when(extensionLoaderMock.getActivateExtension(url, REGISTRY_PROTOCOL_LISTENER_KEY))\n                .thenReturn(registryProtocolListeners);\n        url = url.setScopeModel(moduleModel);\n\n        registryProtocol.interceptInvoker(clusterInvoker, url, consumerUrl);\n\n        Assertions.assertEquals(\n                1, CountRegistryProtocolListener.getReferCounter().get());\n    }\n\n    /**\n     * verify the registered consumer url\n     */\n    @Test\n    void testRegisterConsumerUrl() {\n        ApplicationConfig applicationConfig = new ApplicationConfig();\n        applicationConfig.setName(\"application1\");\n\n        ConfigManager configManager = mock(ConfigManager.class);\n        when(configManager.getApplicationOrElseThrow()).thenReturn(applicationConfig);\n\n        CompositeConfiguration compositeConfiguration = mock(CompositeConfiguration.class);\n        when(compositeConfiguration.convert(Boolean.class, ENABLE_CONFIGURATION_LISTEN, true))\n                .thenReturn(true);\n\n        Map<String, String> parameters = new HashMap<>();\n        parameters.put(INTERFACE_KEY, DemoService.class.getName());\n        parameters.put(\"registry\", \"zookeeper\");\n        parameters.put(\"register\", \"true\");\n        parameters.put(REGISTER_IP_KEY, \"172.23.236.180\");\n\n        Map<String, Object> attributes = new HashMap<>();\n        ServiceConfigURL serviceConfigURL = new ServiceConfigURL(\n                \"registry\", \"127.0.0.1\", 2181, \"org.apache.dubbo.registry.RegistryService\", parameters);\n        Map<String, String> refer = new HashMap<>();\n        attributes.put(REFER_KEY, refer);\n        attributes.put(\"key1\", \"value1\");\n        URL url = serviceConfigURL.addAttributes(attributes);\n\n        RegistryFactory registryFactory = mock(RegistryFactory.class);\n        Registry registry = mock(Registry.class);\n\n        ModuleModel moduleModel = Mockito.spy(ApplicationModel.defaultModel().getDefaultModule());\n        moduleModel\n                .getApplicationModel()\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(\"application1\"));\n        ExtensionLoader extensionLoaderMock = mock(ExtensionLoader.class);\n        Mockito.when(moduleModel.getExtensionLoader(RegistryFactory.class)).thenReturn(extensionLoaderMock);\n        Mockito.when(extensionLoaderMock.getAdaptiveExtension()).thenReturn(registryFactory);\n        url = url.setScopeModel(moduleModel);\n\n        RegistryProtocol registryProtocol = new RegistryProtocol();\n\n        when(registryFactory.getRegistry(registryProtocol.getRegistryUrl(url))).thenReturn(registry);\n\n        Cluster cluster = mock(Cluster.class);\n\n        Invoker<?> invoker = registryProtocol.doRefer(cluster, registry, DemoService.class, url, parameters);\n\n        Assertions.assertTrue(invoker instanceof MigrationInvoker);\n\n        URL consumerUrl = ((MigrationInvoker<?>) invoker).getConsumerUrl();\n        Assertions.assertTrue((consumerUrl != null));\n\n        Map<String, String> urlParameters = consumerUrl.getParameters();\n        URL urlToRegistry = new ServiceConfigURL(\n                urlParameters.get(PROTOCOL_KEY) == null ? CONSUMER : urlParameters.get(PROTOCOL_KEY),\n                urlParameters.remove(REGISTER_IP_KEY),\n                0,\n                consumerUrl.getPath(),\n                urlParameters);\n\n        URL registeredConsumerUrl = urlToRegistry\n                .addParameters(CATEGORY_KEY, CONSUMERS_CATEGORY, CHECK_KEY, String.valueOf(false))\n                .setScopeModel(moduleModel);\n\n        verify(registry, times(1)).register(registeredConsumerUrl);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/service/DemoService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.service;\n\npublic interface DemoService {\n    String sayHello(String str);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/service/DemoService2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.service;\n\npublic interface DemoService2 {\n    String sayHello(String str);\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/support/AbstractRegistryFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass AbstractRegistryFactoryTest {\n\n    private AbstractRegistryFactory registryFactory;\n\n    @BeforeEach\n    public void setup() {\n        registryFactory = new AbstractRegistryFactory() {\n\n            @Override\n            protected Registry createRegistry(final URL url) {\n                return new Registry() {\n\n                    public URL getUrl() {\n                        return url;\n                    }\n\n                    @Override\n                    public boolean isAvailable() {\n                        return false;\n                    }\n\n                    @Override\n                    public void destroy() {}\n\n                    @Override\n                    public void register(URL url) {}\n\n                    @Override\n                    public void unregister(URL url) {}\n\n                    @Override\n                    public void subscribe(URL url, NotifyListener listener) {}\n\n                    @Override\n                    public void unsubscribe(URL url, NotifyListener listener) {}\n\n                    @Override\n                    public List<URL> lookup(URL url) {\n                        return null;\n                    }\n                };\n            }\n        };\n        registryFactory.setApplicationModel(ApplicationModel.defaultModel());\n    }\n\n    @AfterEach\n    public void teardown() {\n        ApplicationModel.defaultModel().destroy();\n    }\n\n    @Test\n    void testRegistryFactoryCache() {\n        URL url = URL.valueOf(\"dubbo://\" + NetUtils.getLocalAddress().getHostAddress() + \":2233\");\n        Registry registry1 = registryFactory.getRegistry(url);\n        Registry registry2 = registryFactory.getRegistry(url);\n        Assertions.assertEquals(registry1, registry2);\n    }\n\n    /**\n     * Registration center address `dubbo` does not resolve\n     */\n    // @Test\n    public void testRegistryFactoryIpCache() {\n        Registry registry1 = registryFactory.getRegistry(\n                URL.valueOf(\"dubbo://\" + NetUtils.getLocalAddress().getHostName() + \":2233\"));\n        Registry registry2 = registryFactory.getRegistry(\n                URL.valueOf(\"dubbo://\" + NetUtils.getLocalAddress().getHostAddress() + \":2233\"));\n        Assertions.assertEquals(registry1, registry2);\n    }\n\n    @Test\n    void testRegistryFactoryGroupCache() {\n        Registry registry1 =\n                registryFactory.getRegistry(URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":2233?group=aaa\"));\n        Registry registry2 =\n                registryFactory.getRegistry(URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":2233?group=bbb\"));\n        Assertions.assertNotSame(registry1, registry2);\n    }\n\n    @Test\n    void testDestroyAllRegistries() {\n        Registry registry1 =\n                registryFactory.getRegistry(URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":8888?group=xxx\"));\n        Registry registry2 =\n                registryFactory.getRegistry(URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":9999?group=yyy\"));\n        Registry registry3 =\n                new AbstractRegistry(URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \":2020?group=yyy\")) {\n                    @Override\n                    public boolean isAvailable() {\n                        return true;\n                    }\n                };\n\n        RegistryManager registryManager =\n                ApplicationModel.defaultModel().getBeanFactory().getBean(RegistryManager.class);\n\n        Collection<Registry> registries = registryManager.getRegistries();\n        Assertions.assertTrue(registries.contains(registry1));\n        Assertions.assertTrue(registries.contains(registry2));\n        registry3.destroy();\n        registries = registryManager.getRegistries();\n        Assertions.assertFalse(registries.contains(registry3));\n        registryManager.destroyAll();\n        registries = registryManager.getRegistries();\n        Assertions.assertFalse(registries.contains(registry1));\n        Assertions.assertFalse(registries.contains(registry2));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/support/AbstractRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.registry.NotifyListener;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.hamcrest.MatcherAssert;\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\n\nclass AbstractRegistryTest {\n\n    private URL testUrl;\n    private URL mockUrl;\n    private NotifyListener listener;\n    private AbstractRegistry abstractRegistry;\n    private boolean notifySuccess;\n    private Map<String, String> parametersConsumer = new LinkedHashMap<>();\n\n    @BeforeEach\n    public void init() {\n        URL url = URL.valueOf(\"dubbo://192.168.0.2:2233\");\n        // sync update cache file\n        url = url.addParameter(\"save.file\", true);\n        testUrl = URL.valueOf(\"http://192.168.0.3:9090/registry?check=false&file=N/A&interface=com.test\");\n        mockUrl = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 2200);\n\n        parametersConsumer.put(\"application\", \"demo-consumer\");\n        parametersConsumer.put(\"category\", \"consumer\");\n        parametersConsumer.put(\"check\", \"false\");\n        parametersConsumer.put(\"dubbo\", \"2.0.2\");\n        parametersConsumer.put(\"interface\", \"org.apache.dubbo.demo.DemoService\");\n        parametersConsumer.put(\"methods\", \"sayHello\");\n        parametersConsumer.put(\"pid\", \"1676\");\n        parametersConsumer.put(\"qos.port\", \"333333\");\n        parametersConsumer.put(\"side\", \"consumer\");\n        parametersConsumer.put(\"timestamp\", String.valueOf(System.currentTimeMillis()));\n\n        // init the object\n        abstractRegistry = new AbstractRegistry(url) {\n            @Override\n            public boolean isAvailable() {\n                return false;\n            }\n        };\n        // init notify listener\n        listener = urls -> notifySuccess = true;\n        // notify flag\n        notifySuccess = false;\n    }\n\n    @AfterEach\n    public void after() {\n        abstractRegistry.destroy();\n    }\n\n    /**\n     * Test method for\n     * {@link org.apache.dubbo.registry.support.AbstractRegistry#register(URL)}.\n     *\n     */\n    @Test\n    void testRegister() {\n        // test one url\n        abstractRegistry.register(mockUrl);\n        assert abstractRegistry.getRegistered().contains(mockUrl);\n        // test multiple urls\n        for (URL url : abstractRegistry.getRegistered()) {\n            abstractRegistry.unregister(url);\n        }\n        List<URL> urlList = getList();\n        for (URL url : urlList) {\n            abstractRegistry.register(url);\n        }\n        MatcherAssert.assertThat(abstractRegistry.getRegistered().size(), Matchers.equalTo(urlList.size()));\n    }\n\n    @Test\n    void testRegisterIfURLNULL() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            abstractRegistry.register(null);\n            Assertions.fail(\"register url == null\");\n        });\n    }\n\n    /**\n     * Test method for\n     * {@link org.apache.dubbo.registry.support.AbstractRegistry#unregister(URL)}.\n     *\n     */\n    @Test\n    void testUnregister() {\n        // test one unregister\n        URL url = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 2200);\n        abstractRegistry.register(url);\n        abstractRegistry.unregister(url);\n        MatcherAssert.assertThat(\n                false, Matchers.equalTo(abstractRegistry.getRegistered().contains(url)));\n        // test multiple unregisters\n        for (URL u : abstractRegistry.getRegistered()) {\n            abstractRegistry.unregister(u);\n        }\n        List<URL> urlList = getList();\n        for (URL urlSub : urlList) {\n            abstractRegistry.register(urlSub);\n        }\n        for (URL urlSub : urlList) {\n            abstractRegistry.unregister(urlSub);\n        }\n        MatcherAssert.assertThat(\n                0, Matchers.equalTo(abstractRegistry.getRegistered().size()));\n    }\n\n    @Test\n    void testUnregisterIfUrlNull() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            abstractRegistry.unregister(null);\n            Assertions.fail(\"unregister url == null\");\n        });\n    }\n\n    /**\n     * test subscribe and unsubscribe\n     */\n    @Test\n    void testSubscribeAndUnsubscribe() {\n        // test subscribe\n        final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n        NotifyListener listener = urls -> notified.set(Boolean.TRUE);\n        URL url = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 2200);\n        abstractRegistry.subscribe(url, listener);\n        Set<NotifyListener> subscribeListeners =\n                abstractRegistry.getSubscribed().get(url);\n        MatcherAssert.assertThat(true, Matchers.equalTo(subscribeListeners.contains(listener)));\n        // test unsubscribe\n        abstractRegistry.unsubscribe(url, listener);\n        Set<NotifyListener> unsubscribeListeners =\n                abstractRegistry.getSubscribed().get(url);\n        MatcherAssert.assertThat(false, Matchers.equalTo(unsubscribeListeners.contains(listener)));\n    }\n\n    @Test\n    void testSubscribeIfUrlNull() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n            NotifyListener listener = urls -> notified.set(Boolean.TRUE);\n            URL url = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 2200);\n            abstractRegistry.subscribe(null, listener);\n            Assertions.fail(\"subscribe url == null\");\n        });\n    }\n\n    @Test\n    void testSubscribeIfListenerNull() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n            NotifyListener listener = urls -> notified.set(Boolean.TRUE);\n            URL url = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 2200);\n            abstractRegistry.subscribe(url, null);\n            Assertions.fail(\"listener url == null\");\n        });\n    }\n\n    @Test\n    void testUnsubscribeIfUrlNull() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n            NotifyListener listener = urls -> notified.set(Boolean.TRUE);\n            abstractRegistry.unsubscribe(null, listener);\n            Assertions.fail(\"unsubscribe url == null\");\n        });\n    }\n\n    @Test\n    void testUnsubscribeIfNotifyNull() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n            URL url = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 2200);\n            abstractRegistry.unsubscribe(url, null);\n            Assertions.fail(\"unsubscribe listener == null\");\n        });\n    }\n\n    /**\n     * Test method for\n     * {@link org.apache.dubbo.registry.support.AbstractRegistry#subscribe(URL, NotifyListener)}.\n     *\n     */\n    @Test\n    void testSubscribe() {\n        // check parameters\n        try {\n            abstractRegistry.subscribe(testUrl, null);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof IllegalArgumentException);\n        }\n        // check parameters\n        try {\n            abstractRegistry.subscribe(null, null);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof IllegalArgumentException);\n        }\n        // check if subscribe successfully\n        Assertions.assertNull(abstractRegistry.getSubscribed().get(testUrl));\n        abstractRegistry.subscribe(testUrl, listener);\n        Assertions.assertNotNull(abstractRegistry.getSubscribed().get(testUrl));\n        Assertions.assertTrue(abstractRegistry.getSubscribed().get(testUrl).contains(listener));\n    }\n\n    /**\n     * Test method for\n     * {@link org.apache.dubbo.registry.support.AbstractRegistry#unsubscribe(URL, NotifyListener)}.\n     *\n     */\n    @Test\n    void testUnsubscribe() {\n        // check parameters\n        try {\n            abstractRegistry.unsubscribe(testUrl, null);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof IllegalArgumentException);\n        }\n        // check parameters\n        try {\n            abstractRegistry.unsubscribe(null, null);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof IllegalArgumentException);\n        }\n\n        Assertions.assertNull(abstractRegistry.getSubscribed().get(testUrl));\n        // check if unsubscribe successfully\n        abstractRegistry.subscribe(testUrl, listener);\n        abstractRegistry.unsubscribe(testUrl, listener);\n        // Since we have subscribed testUrl, here should return a empty set instead of null\n        Assertions.assertNotNull(abstractRegistry.getSubscribed().get(testUrl));\n        Assertions.assertFalse(abstractRegistry.getSubscribed().get(testUrl).contains(listener));\n    }\n\n    /**\n     * Test method for\n     * {@link org.apache.dubbo.registry.support.AbstractRegistry#recover()}.\n     */\n    @Test\n    void testRecover() throws Exception {\n        // test recover nothing\n        abstractRegistry.recover();\n        Assertions.assertFalse(abstractRegistry.getRegistered().contains(testUrl));\n        Assertions.assertNull(abstractRegistry.getSubscribed().get(testUrl));\n\n        // test recover\n        abstractRegistry.register(testUrl);\n        abstractRegistry.subscribe(testUrl, listener);\n        abstractRegistry.recover();\n        // check if recover successfully\n        Assertions.assertTrue(abstractRegistry.getRegistered().contains(testUrl));\n        Assertions.assertNotNull(abstractRegistry.getSubscribed().get(testUrl));\n        Assertions.assertTrue(abstractRegistry.getSubscribed().get(testUrl).contains(listener));\n    }\n\n    @Test\n    void testRecover2() throws Exception {\n        List<URL> list = getList();\n        abstractRegistry.recover();\n        Assertions.assertEquals(0, abstractRegistry.getRegistered().size());\n        for (URL url : list) {\n            abstractRegistry.register(url);\n        }\n        Assertions.assertEquals(3, abstractRegistry.getRegistered().size());\n        abstractRegistry.recover();\n        Assertions.assertEquals(3, abstractRegistry.getRegistered().size());\n    }\n\n    /**\n     * Test method for\n     * {@link org.apache.dubbo.registry.support.AbstractRegistry#notify(List)}.\n     */\n    @Test\n    void testNotify() {\n        final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n        NotifyListener listener1 = urls -> notified.set(Boolean.TRUE);\n        URL url1 = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 2200, parametersConsumer);\n        abstractRegistry.subscribe(url1, listener1);\n        NotifyListener listener2 = urls -> notified.set(Boolean.TRUE);\n        URL url2 = new ServiceConfigURL(\"dubbo\", \"192.168.0.2\", 2201, parametersConsumer);\n        abstractRegistry.subscribe(url2, listener2);\n        NotifyListener listener3 = urls -> notified.set(Boolean.TRUE);\n        URL url3 = new ServiceConfigURL(\"dubbo\", \"192.168.0.3\", 2202, parametersConsumer);\n        abstractRegistry.subscribe(url3, listener3);\n        List<URL> urls = new ArrayList<>();\n        urls.add(url1);\n        urls.add(url2);\n        urls.add(url3);\n        abstractRegistry.notify(url1, listener1, urls);\n        Map<URL, Map<String, List<URL>>> map = abstractRegistry.getNotified();\n        MatcherAssert.assertThat(true, Matchers.equalTo(map.containsKey(url1)));\n        MatcherAssert.assertThat(false, Matchers.equalTo(map.containsKey(url2)));\n        MatcherAssert.assertThat(false, Matchers.equalTo(map.containsKey(url3)));\n    }\n\n    /**\n     * test notifyList\n     */\n    @Test\n    void testNotifyList() {\n        final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n        NotifyListener listener1 = urls -> notified.set(Boolean.TRUE);\n        URL url1 = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 2200, parametersConsumer);\n        abstractRegistry.subscribe(url1, listener1);\n        NotifyListener listener2 = urls -> notified.set(Boolean.TRUE);\n        URL url2 = new ServiceConfigURL(\"dubbo\", \"192.168.0.2\", 2201, parametersConsumer);\n        abstractRegistry.subscribe(url2, listener2);\n        NotifyListener listener3 = urls -> notified.set(Boolean.TRUE);\n        URL url3 = new ServiceConfigURL(\"dubbo\", \"192.168.0.3\", 2202, parametersConsumer);\n        abstractRegistry.subscribe(url3, listener3);\n        List<URL> urls = new ArrayList<>();\n        urls.add(url1);\n        urls.add(url2);\n        urls.add(url3);\n        abstractRegistry.notify(urls);\n        Map<URL, Map<String, List<URL>>> map = abstractRegistry.getNotified();\n        MatcherAssert.assertThat(true, Matchers.equalTo(map.containsKey(url1)));\n        MatcherAssert.assertThat(true, Matchers.equalTo(map.containsKey(url2)));\n        MatcherAssert.assertThat(true, Matchers.equalTo(map.containsKey(url3)));\n    }\n\n    @Test\n    void testNotifyIfURLNull() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n            NotifyListener listener1 = urls -> notified.set(Boolean.TRUE);\n            URL url1 = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 2200, parametersConsumer);\n            abstractRegistry.subscribe(url1, listener1);\n            NotifyListener listener2 = urls -> notified.set(Boolean.TRUE);\n            URL url2 = new ServiceConfigURL(\"dubbo\", \"192.168.0.2\", 2201, parametersConsumer);\n            abstractRegistry.subscribe(url2, listener2);\n            NotifyListener listener3 = urls -> notified.set(Boolean.TRUE);\n            URL url3 = new ServiceConfigURL(\"dubbo\", \"192.168.0.3\", 2202, parametersConsumer);\n            abstractRegistry.subscribe(url3, listener3);\n            List<URL> urls = new ArrayList<>();\n            urls.add(url1);\n            urls.add(url2);\n            urls.add(url3);\n            abstractRegistry.notify(null, listener1, urls);\n            Assertions.fail(\"notify url == null\");\n        });\n    }\n\n    @Test\n    void testNotifyIfNotifyNull() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n            NotifyListener listener1 = urls -> notified.set(Boolean.TRUE);\n            URL url1 = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 2200, parametersConsumer);\n            abstractRegistry.subscribe(url1, listener1);\n            NotifyListener listener2 = urls -> notified.set(Boolean.TRUE);\n            URL url2 = new ServiceConfigURL(\"dubbo\", \"192.168.0.2\", 2201, parametersConsumer);\n            abstractRegistry.subscribe(url2, listener2);\n            NotifyListener listener3 = urls -> notified.set(Boolean.TRUE);\n            URL url3 = new ServiceConfigURL(\"dubbo\", \"192.168.0.3\", 2202, parametersConsumer);\n            abstractRegistry.subscribe(url3, listener3);\n            List<URL> urls = new ArrayList<>();\n            urls.add(url1);\n            urls.add(url2);\n            urls.add(url3);\n            abstractRegistry.notify(url1, null, urls);\n            Assertions.fail(\"notify listener == null\");\n        });\n    }\n\n    /**\n     * Test method for\n     * {@link org.apache.dubbo.registry.support.AbstractRegistry#notify(URL, NotifyListener, List)}.\n     *\n     */\n    @Test\n    void testNotifyArgs() {\n        // check parameters\n        try {\n            abstractRegistry.notify(null, null, null);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof IllegalArgumentException);\n        }\n        // check parameters\n        try {\n            abstractRegistry.notify(testUrl, null, null);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof IllegalArgumentException);\n        }\n        // check parameters\n        try {\n            abstractRegistry.notify(null, listener, null);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof IllegalArgumentException);\n        }\n\n        Assertions.assertFalse(notifySuccess);\n        abstractRegistry.notify(testUrl, listener, null);\n        Assertions.assertFalse(notifySuccess);\n\n        List<URL> urls = new ArrayList<>();\n        urls.add(testUrl);\n        // check if notify successfully\n        Assertions.assertFalse(notifySuccess);\n        abstractRegistry.notify(testUrl, listener, urls);\n        Assertions.assertTrue(notifySuccess);\n    }\n\n    @Test\n    void filterEmptyTest() {\n        // check parameters\n        try {\n            AbstractRegistry.filterEmpty(null, null);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof NullPointerException);\n        }\n\n        // check parameters\n        List<URL> urls = new ArrayList<>();\n        try {\n            AbstractRegistry.filterEmpty(null, urls);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof NullPointerException);\n        }\n\n        // check if the output is generated by a fixed way\n        urls.add(testUrl.setProtocol(EMPTY_PROTOCOL));\n        Assertions.assertEquals(AbstractRegistry.filterEmpty(testUrl, null), urls);\n\n        List<URL> testUrls = new ArrayList<>();\n        Assertions.assertEquals(AbstractRegistry.filterEmpty(testUrl, testUrls), urls);\n\n        // check if the output equals the input urls\n        testUrls.add(testUrl);\n        Assertions.assertEquals(AbstractRegistry.filterEmpty(testUrl, testUrls), testUrls);\n    }\n\n    @Test\n    void lookupTest() {\n        // loop up before registry\n        try {\n            abstractRegistry.lookup(null);\n            Assertions.fail();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof NullPointerException);\n        }\n        List<URL> urlList1 = abstractRegistry.lookup(testUrl);\n        Assertions.assertFalse(urlList1.contains(testUrl));\n        // loop up after registry\n        List<URL> urls = new ArrayList<>();\n        urls.add(testUrl);\n        abstractRegistry.notify(urls);\n        List<URL> urlList2 = abstractRegistry.lookup(testUrl);\n        Assertions.assertTrue(urlList2.contains(testUrl));\n    }\n\n    @Test\n    void destroyTest() {\n        abstractRegistry.register(testUrl);\n        abstractRegistry.subscribe(testUrl, listener);\n        Assertions.assertEquals(1, abstractRegistry.getRegistered().size());\n        Assertions.assertEquals(1, abstractRegistry.getSubscribed().get(testUrl).size());\n        // delete listener and register\n        abstractRegistry.destroy();\n        Assertions.assertEquals(0, abstractRegistry.getRegistered().size());\n        Assertions.assertEquals(0, abstractRegistry.getSubscribed().get(testUrl).size());\n    }\n\n    @Test\n    void allTest() {\n        // test all methods\n        List<URL> urls = new ArrayList<>();\n        urls.add(testUrl);\n        // register, subscribe, notify, unsubscribe, unregister\n        abstractRegistry.register(testUrl);\n        Assertions.assertTrue(abstractRegistry.getRegistered().contains(testUrl));\n        abstractRegistry.subscribe(testUrl, listener);\n        Assertions.assertTrue(abstractRegistry.getSubscribed().containsKey(testUrl));\n        Assertions.assertFalse(notifySuccess);\n        abstractRegistry.notify(urls);\n        Assertions.assertTrue(notifySuccess);\n        abstractRegistry.unsubscribe(testUrl, listener);\n        Assertions.assertFalse(abstractRegistry.getSubscribed().containsKey(listener));\n        abstractRegistry.unregister(testUrl);\n        Assertions.assertFalse(abstractRegistry.getRegistered().contains(testUrl));\n    }\n\n    private List<URL> getList() {\n        List<URL> list = new ArrayList<>();\n        URL url1 = new ServiceConfigURL(\"dubbo\", \"192.168.0.1\", 1000);\n        URL url2 = new ServiceConfigURL(\"dubbo\", \"192.168.0.2\", 1001);\n        URL url3 = new ServiceConfigURL(\"dubbo\", \"192.168.0.3\", 1002);\n        list.add(url1);\n        list.add(url2);\n        list.add(url3);\n        return list;\n    }\n\n    @Test\n    void getCacheUrlsTest() {\n        List<URL> urls = new ArrayList<>();\n        urls.add(testUrl);\n        // check if notify successfully\n        Assertions.assertFalse(notifySuccess);\n        abstractRegistry.notify(testUrl, listener, urls);\n        Assertions.assertTrue(notifySuccess);\n        List<URL> cacheUrl = abstractRegistry.getCacheUrls(testUrl);\n        Assertions.assertEquals(1, cacheUrl.size());\n        URL nullUrl = URL.valueOf(\"http://1.2.3.4:9090/registry?check=false&file=N/A&interface=com.testa\");\n        cacheUrl = abstractRegistry.getCacheUrls(nullUrl);\n        Assertions.assertTrue(Objects.isNull(cacheUrl));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/support/CacheableFailbackRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceAddressURL;\nimport org.apache.dubbo.registry.NotifyListener;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.URLStrParser.ENCODED_AND_MARK;\nimport static org.apache.dubbo.common.URLStrParser.ENCODED_QUESTION_MARK;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass CacheableFailbackRegistryTest {\n\n    private StubCacheableFailbackRegistry registry;\n\n    @BeforeEach\n    void setUp() {\n        registry = new StubCacheableFailbackRegistry(URL.valueOf(\"mock://127.0.0.1\"));\n    }\n\n    @Test\n    void shouldRemoveExactTimestamp() throws Exception {\n        // Test removing exact \"timestamp\" parameter\n        String rawProvider = \"dubbo://127.0.0.1:20880/demo.Service?timestamp=100&revision=v1\";\n        String result = strip(rawProvider);\n        // After removing timestamp, only revision should remain\n        assertTrue(result.contains(\"revision=v1\"), \"Result should contain revision\");\n        assertFalse(result.contains(\"timestamp\"), \"Result should not contain timestamp\");\n    }\n\n    @Test\n    void shouldRemoveExactPid() throws Exception {\n        // Test removing exact \"pid\" parameter\n        String rawProvider = \"dubbo://127.0.0.1:20880/demo.Service?pid=9999&revision=v1\";\n        String result = strip(rawProvider);\n        assertTrue(result.contains(\"revision=v1\"), \"Result should contain revision\");\n        assertFalse(result.contains(\"pid\"), \"Result should not contain pid\");\n    }\n\n    @Test\n    void shouldRemoveTimestampAndPid() throws Exception {\n        // Test removing both timestamp and pid\n        String rawProvider = \"dubbo://127.0.0.1:20880/demo.Service?timestamp=100&pid=1234&revision=abc\";\n        String result = strip(rawProvider);\n        assertTrue(result.contains(\"revision=abc\"), \"Result should contain revision\");\n        assertFalse(result.contains(\"timestamp\"), \"Result should not contain timestamp\");\n        assertFalse(result.contains(\"pid\"), \"Result should not contain pid\");\n    }\n\n    @Test\n    void shouldKeepRemoteTimestamp() throws Exception {\n        // remote.timestamp should NOT be removed (only exact \"timestamp\" is removed)\n        String rawProvider = \"dubbo://127.0.0.1:20880/demo.Service?remote.timestamp=200&revision=v1\";\n        String result = strip(rawProvider);\n        assertTrue(result.contains(\"remote.timestamp=200\"), \"Result should keep remote.timestamp\");\n        assertTrue(result.contains(\"revision=v1\"), \"Result should contain revision\");\n    }\n\n    @Test\n    void shouldRemoveEncodedTimestampAndPid() throws Exception {\n        // Test with encoded format\n        String base = \"dubbo%3A%2F%2F127.0.0.1%3A20880%2Fdemo.Service\";\n        String rawProvider = base + ENCODED_QUESTION_MARK\n                + \"timestamp%3D123\" + ENCODED_AND_MARK\n                + \"pid%3D9999\" + ENCODED_AND_MARK\n                + \"revision%3Dv1\";\n        String result = strip(rawProvider);\n        assertTrue(result.contains(\"revision%3Dv1\"), \"Result should contain revision\");\n        assertFalse(result.contains(\"timestamp%3D\"), \"Result should not contain timestamp\");\n        assertFalse(result.contains(\"pid%3D\"), \"Result should not contain pid\");\n    }\n\n    @Test\n    void toUrlsWithoutEmptyPreservesTimestampInCachedURL() throws Exception {\n        // This test verifies the fix: normalized key for cache, but original rawProvider for URL building.\n        String consumerUrl = \"mock://127.0.0.1/demo.Service\";\n        String provider1 = \"dubbo://provider1.example.com:20880/demo.Service?timestamp=100&revision=v1\";\n        String provider2 = \"dubbo://provider1.example.com:20880/demo.Service?timestamp=200&revision=v1\";\n        // Both providers have same address and revision but different timestamp values.\n        // After normalization (removing timestamp), they should produce the same cache key.\n\n        URL consumerURL = URL.valueOf(consumerUrl);\n        Collection<String> providers = new ArrayList<>();\n        providers.add(provider1);\n        providers.add(provider2);\n\n        // First call: build cache with both providers\n        List<URL> urls1 = registry.toUrlsWithoutEmpty(consumerURL, providers);\n        assertNotNull(urls1);\n        assertEquals(1, urls1.size());\n\n        // Get the normalized key that should be used\n        String normalizedKey1 = strip(provider1); // Should have timestamp removed\n        String normalizedKey2 = strip(provider2); // Should be same as normalizedKey1\n\n        assertEquals(normalizedKey1, normalizedKey2, \"Normalized keys should be identical after removing timestamp\");\n\n        // Verify the cached URL map uses normalized key\n        Map<String, ServiceAddressURL> stringUrls = registry.stringUrls.get(consumerURL);\n        assertNotNull(stringUrls);\n        assertTrue(stringUrls.containsKey(normalizedKey1), \"Cache should use normalized key\");\n        assertEquals(1, stringUrls.size(), \"Should have exactly one cache entry for deduplicated provider\");\n    }\n\n    private String strip(String rawProvider) throws Exception {\n        Method method = CacheableFailbackRegistry.class.getDeclaredMethod(\"stripOffVariableKeys\", String.class);\n        method.setAccessible(true);\n        return (String) method.invoke(registry, rawProvider);\n    }\n\n    private static final class StubCacheableFailbackRegistry extends CacheableFailbackRegistry {\n        StubCacheableFailbackRegistry(URL url) {\n            super(url);\n        }\n\n        @Override\n        public void doRegister(URL url) {}\n\n        @Override\n        public void doUnregister(URL url) {}\n\n        @Override\n        public void doSubscribe(URL url, NotifyListener listener) {}\n\n        @Override\n        protected boolean isMatch(URL subscribeUrl, URL providerUrl) {\n            return true;\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/support/FailbackRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.registry.NotifyListener;\n\nimport java.util.Arrays;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL;\nimport static org.apache.dubbo.registry.Constants.REGISTRY_RETRY_PERIOD_KEY;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass FailbackRegistryTest {\n    protected final Logger logger = LoggerFactory.getLogger(getClass());\n\n    private URL serviceUrl;\n    private URL registryUrl;\n    private MockRegistry registry;\n    private final int FAILED_PERIOD = 200;\n    private final int sleepTime = 100;\n    private final int tryTimes = 5;\n\n    /**\n     * @throws java.lang.Exception\n     */\n    @BeforeEach\n    public void setUp() throws Exception {\n        String failedPeriod = String.valueOf(FAILED_PERIOD);\n        serviceUrl = URL.valueOf(\"remote://127.0.0.1/demoservice?method=get\")\n                .addParameter(REGISTRY_RETRY_PERIOD_KEY, failedPeriod);\n        registryUrl = URL.valueOf(\"http://1.2.3.4:9090/registry?check=false&file=N/A\")\n                .addParameter(REGISTRY_RETRY_PERIOD_KEY, failedPeriod);\n    }\n\n    /**\n     * Test method for retry\n     *\n     * @throws Exception\n     */\n    @Test\n    void testDoRetry() throws Exception {\n\n        final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n\n        // the latest latch just for 3. Because retry method has been removed.\n        final CountDownLatch latch = new CountDownLatch(2);\n\n        NotifyListener listener = urls -> notified.set(Boolean.TRUE);\n        URL subscribeUrl =\n                serviceUrl.setProtocol(CONSUMER_PROTOCOL).addParameters(CollectionUtils.toStringMap(\"check\", \"false\"));\n        registry = new MockRegistry(registryUrl, serviceUrl, latch);\n        registry.setBad(true);\n        registry.register(serviceUrl);\n        registry.unregister(serviceUrl);\n        registry.subscribe(subscribeUrl, listener);\n        registry.unsubscribe(subscribeUrl, listener);\n\n        // Failure can not be called to listener.\n        assertEquals(false, notified.get());\n        assertEquals(2, latch.getCount());\n\n        registry.setBad(false);\n\n        for (int i = 0; i < 20; i++) {\n            logger.info(\"failback registry retry, times:\" + i);\n            if (latch.getCount() == 0) break;\n            Thread.sleep(sleepTime);\n        }\n        assertEquals(0, latch.getCount());\n        // The failed subscribe corresponding key will be cleared when unsubscribing\n        assertEquals(false, notified.get());\n    }\n\n    @Test\n    void testDoRetryRegister() throws Exception {\n\n        final CountDownLatch latch = new CountDownLatch(\n                1); // All of them are called 4 times. A successful attempt to lose 1. subscribe will not be done\n\n        registry = new MockRegistry(registryUrl, serviceUrl, latch);\n        registry.setBad(true);\n        registry.register(serviceUrl);\n\n        registry.setBad(false);\n\n        for (int i = 0; i < tryTimes; i++) {\n            if (latch.getCount() == 0) break;\n            Thread.sleep(sleepTime);\n        }\n        assertEquals(0, latch.getCount());\n    }\n\n    @Test\n    void testDoRetrySubscribe() throws Exception {\n\n        final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n        final CountDownLatch latch = new CountDownLatch(\n                1); // All of them are called 4 times. A successful attempt to lose 1. subscribe will not be done\n\n        NotifyListener listener = urls -> notified.set(Boolean.TRUE);\n        registry = new MockRegistry(registryUrl, serviceUrl, latch);\n        registry.setBad(true);\n        registry.subscribe(\n                serviceUrl.setProtocol(CONSUMER_PROTOCOL).addParameters(CollectionUtils.toStringMap(\"check\", \"false\")),\n                listener);\n\n        // Failure can not be called to listener.\n        assertEquals(false, notified.get());\n        assertEquals(1, latch.getCount());\n\n        registry.setBad(false);\n\n        for (int i = 0; i < tryTimes; i++) {\n            if (latch.getCount() == 0) break;\n            Thread.sleep(sleepTime);\n        }\n        assertEquals(0, latch.getCount());\n        // The failed subscribe corresponding key will be cleared when unsubscribing\n        assertEquals(true, notified.get());\n    }\n\n    @Test\n    void testRecover() throws Exception {\n        CountDownLatch countDownLatch = new CountDownLatch(6);\n        final AtomicReference<Boolean> notified = new AtomicReference<Boolean>(false);\n        NotifyListener listener = urls -> notified.set(Boolean.TRUE);\n\n        MockRegistry mockRegistry = new MockRegistry(registryUrl, serviceUrl, countDownLatch);\n        mockRegistry.register(serviceUrl);\n        mockRegistry.subscribe(serviceUrl, listener);\n        Assertions.assertEquals(1, mockRegistry.getRegistered().size());\n        Assertions.assertEquals(1, mockRegistry.getSubscribed().size());\n        mockRegistry.recover();\n        countDownLatch.await();\n        Assertions.assertEquals(0, mockRegistry.getFailedRegistered().size());\n        FailbackRegistry.Holder h = new FailbackRegistry.Holder(registryUrl, listener);\n        Assertions.assertNull(mockRegistry.getFailedSubscribed().get(h));\n        Assertions.assertEquals(countDownLatch.getCount(), 0);\n    }\n\n    private static class MockRegistry extends FailbackRegistry {\n        private final URL serviceUrl;\n        CountDownLatch latch;\n        private volatile boolean bad = false;\n\n        /**\n         * @param url\n         * @param serviceUrl\n         */\n        public MockRegistry(URL url, URL serviceUrl, CountDownLatch latch) {\n            super(url);\n            this.serviceUrl = serviceUrl;\n            this.latch = latch;\n        }\n\n        /**\n         * @param bad the bad to set\n         */\n        public void setBad(boolean bad) {\n            this.bad = bad;\n        }\n\n        @Override\n        public void doRegister(URL url) {\n            if (bad) {\n                throw new RuntimeException(\"can not invoke!\");\n            }\n            latch.countDown();\n        }\n\n        @Override\n        public void doUnregister(URL url) {\n            if (bad) {\n                throw new RuntimeException(\"can not invoke!\");\n            }\n            latch.countDown();\n        }\n\n        @Override\n        public void doSubscribe(URL url, NotifyListener listener) {\n            if (bad) {\n                throw new RuntimeException(\"can not invoke!\");\n            }\n            super.notify(url, listener, Arrays.asList(new URL[] {serviceUrl}));\n            latch.countDown();\n        }\n\n        @Override\n        public void doUnsubscribe(URL url, NotifyListener listener) {\n            if (bad) {\n                throw new RuntimeException(\"can not invoke!\");\n            }\n            latch.countDown();\n        }\n\n        @Override\n        public boolean isAvailable() {\n            return true;\n        }\n\n        @Override\n        public void removeFailedRegisteredTask(URL url) {\n            if (bad) {\n                throw new RuntimeException(\"can not invoke!\");\n            }\n            super.removeFailedRegisteredTask(url);\n            latch.countDown();\n        }\n\n        @Override\n        public void removeFailedSubscribedTask(URL url, NotifyListener listener) {\n            if (bad) {\n                throw new RuntimeException(\"can not invoke!\");\n            }\n            super.removeFailedSubscribedTask(url, listener);\n            latch.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/resources/META-INF/dubbo/org.apache.dubbo.metadata.MetadataParamsFilter",
    "content": "customized=org.apache.dubbo.registry.client.metadata.store.CustomizedParamsFilter\nexcluded=org.apache.dubbo.registry.client.metadata.store.ExcludedParamsFilter\nexcluded2=org.apache.dubbo.registry.client.metadata.store.ExcludedParamsFilter2\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/resources/META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory",
    "content": "simple=org.apache.dubbo.registry.SimpleRegistryFactory"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/resources/META-INF/dubbo/org.apache.dubbo.registry.RegistryServiceListener",
    "content": "listener-one=org.apache.dubbo.registry.RegistryServiceListener1\nlistener-two=org.apache.dubbo.registry.RegistryServiceListener2"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/resources/META-INF/dubbo/org.apache.dubbo.registry.client.ServiceDiscoveryFactory",
    "content": "mock=org.apache.dubbo.registry.client.support.MockServiceDiscoveryFactory\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/resources/META-INF/dubbo/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory",
    "content": "# Override \"local\" implementation\nlocal=org.apache.dubbo.registry.client.metadata.proxy.MyMetadataServiceProxyFactory"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/resources/META-INF/dubbo/org.apache.dubbo.registry.integration.RegistryProtocolListener",
    "content": "count=org.apache.dubbo.registry.integration.CountRegistryProtocolListener\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/resources/dubbo.properties",
    "content": "dubbo.application.enable-file-cache=false\ndubbo.service.shutdown.wait=200\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-api/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multicast/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-registry</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-registry-multicast</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The multicast registry module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multicast;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.ExecutorUtil;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.support.FailbackRegistry;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.io.IOException;\nimport java.net.DatagramPacket;\nimport java.net.Inet4Address;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.MulticastSocket;\nimport java.net.Socket;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_SOCKET_EXCEPTION;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.OVERRIDE_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ROUTE_PROTOCOL;\nimport static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL;\nimport static org.apache.dubbo.registry.Constants.DEFAULT_SESSION_TIMEOUT;\nimport static org.apache.dubbo.registry.Constants.REGISTER;\nimport static org.apache.dubbo.registry.Constants.REGISTER_KEY;\nimport static org.apache.dubbo.registry.Constants.SESSION_TIMEOUT_KEY;\nimport static org.apache.dubbo.registry.Constants.SUBSCRIBE;\nimport static org.apache.dubbo.registry.Constants.UNREGISTER;\nimport static org.apache.dubbo.registry.Constants.UNSUBSCRIBE;\n\npublic class MulticastRegistry extends FailbackRegistry {\n\n    // logging output\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MulticastRegistry.class);\n\n    private static final int DEFAULT_MULTICAST_PORT = 1234;\n\n    private final InetAddress multicastAddress;\n\n    private final MulticastSocket multicastSocket;\n\n    private final int multicastPort;\n\n    private final ConcurrentMap<URL, Set<URL>> received = new ConcurrentHashMap<>();\n\n    private final ScheduledExecutorService cleanExecutor =\n            Executors.newScheduledThreadPool(1, new NamedThreadFactory(\"DubboMulticastRegistryCleanTimer\", true));\n\n    private final ScheduledFuture<?> cleanFuture;\n\n    private final int cleanPeriod;\n\n    private final ApplicationModel applicationModel;\n\n    private volatile boolean admin = false;\n\n    public MulticastRegistry(URL url, ApplicationModel applicationModel) {\n        super(url);\n        this.applicationModel = applicationModel;\n        if (url.isAnyHost()) {\n            throw new IllegalStateException(\"registry address == null\");\n        }\n        try {\n            multicastAddress = InetAddress.getByName(url.getHost());\n            checkMulticastAddress(multicastAddress);\n\n            multicastPort = url.getPort() <= 0 ? DEFAULT_MULTICAST_PORT : url.getPort();\n            multicastSocket = new MulticastSocket(multicastPort);\n            NetUtils.joinMulticastGroup(multicastSocket, multicastAddress);\n            Thread thread = new Thread(\n                    () -> {\n                        byte[] buf = new byte[2048];\n                        DatagramPacket recv = new DatagramPacket(buf, buf.length);\n                        while (!multicastSocket.isClosed()) {\n                            try {\n                                multicastSocket.receive(recv);\n                                String msg = new String(recv.getData()).trim();\n                                int i = msg.indexOf('\\n');\n                                if (i > 0) {\n                                    msg = msg.substring(0, i).trim();\n                                }\n                                receive(msg, (InetSocketAddress) recv.getSocketAddress());\n                                Arrays.fill(buf, (byte) 0);\n                            } catch (Throwable e) {\n                                if (!multicastSocket.isClosed()) {\n                                    logger.error(REGISTRY_SOCKET_EXCEPTION, \"\", \"\", e.getMessage(), e);\n                                }\n                            }\n                        }\n                    },\n                    \"DubboMulticastRegistryReceiver\");\n            thread.setDaemon(true);\n            thread.start();\n        } catch (IOException e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n        this.cleanPeriod = url.getParameter(SESSION_TIMEOUT_KEY, DEFAULT_SESSION_TIMEOUT);\n        if (url.getParameter(\"clean\", true)) {\n            this.cleanFuture = cleanExecutor.scheduleWithFixedDelay(\n                    () -> {\n                        try {\n                            clean(); // Remove the expired\n                        } catch (Throwable t) { // Defensive fault tolerance\n                            logger.error(\n                                    REGISTRY_SOCKET_EXCEPTION,\n                                    \"\",\n                                    \"\",\n                                    \"Unexpected exception occur at clean expired provider, cause: \" + t.getMessage(),\n                                    t);\n                        }\n                    },\n                    cleanPeriod,\n                    cleanPeriod,\n                    TimeUnit.MILLISECONDS);\n        } else {\n            this.cleanFuture = null;\n        }\n    }\n\n    public MulticastRegistry(URL url) {\n        this(url, url.getOrDefaultApplicationModel());\n    }\n\n    private void checkMulticastAddress(InetAddress multicastAddress) {\n        if (!multicastAddress.isMulticastAddress()) {\n            String message = \"Invalid multicast address \" + multicastAddress;\n            if (multicastAddress instanceof Inet4Address) {\n                throw new IllegalArgumentException(\n                        message + \", \" + \"ipv4 multicast address scope: 224.0.0.0 - 239.255.255.255.\");\n            } else {\n                throw new IllegalArgumentException(\n                        message + \", \" + \"ipv6 multicast address must start with ff, \" + \"for example: ff01::1\");\n            }\n        }\n    }\n\n    /**\n     * Remove the expired providers, only when \"clean\" parameter is true.\n     */\n    private void clean() {\n        if (admin) {\n            for (Set<URL> providers : new HashSet<Set<URL>>(received.values())) {\n                for (URL url : new HashSet<URL>(providers)) {\n                    if (isExpired(url)) {\n                        if (logger.isWarnEnabled()) {\n                            logger.warn(REGISTRY_SOCKET_EXCEPTION, \"\", \"\", \"Clean expired provider \" + url);\n                        }\n                        doUnregister(url);\n                    }\n                }\n            }\n        }\n    }\n\n    private boolean isExpired(URL url) {\n        if (!url.getParameter(DYNAMIC_KEY, true)\n                || url.getPort() <= 0\n                || CONSUMER_PROTOCOL.equals(url.getProtocol())\n                || ROUTE_PROTOCOL.equals(url.getProtocol())\n                || OVERRIDE_PROTOCOL.equals(url.getProtocol())) {\n            return false;\n        }\n        try (Socket socket = new Socket(url.getHost(), url.getPort())) {\n        } catch (Throwable e) {\n            try {\n                Thread.sleep(100);\n            } catch (Throwable e2) {\n            }\n            try (Socket socket2 = new Socket(url.getHost(), url.getPort())) {\n            } catch (Throwable e2) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private void receive(String msg, InetSocketAddress remoteAddress) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Receive multicast message: \" + msg + \" from \" + remoteAddress);\n        }\n        if (applicationModel.isDestroyed()) {\n            logger.info(\"The applicationModel is destroyed, skip\");\n            return;\n        }\n        if (msg.startsWith(REGISTER)) {\n            URL url = URL.valueOf(msg.substring(REGISTER.length()).trim());\n            registered(url);\n        } else if (msg.startsWith(UNREGISTER)) {\n            URL url = URL.valueOf(msg.substring(UNREGISTER.length()).trim());\n            unregistered(url);\n        } else if (msg.startsWith(SUBSCRIBE)) {\n            URL url = URL.valueOf(msg.substring(SUBSCRIBE.length()).trim());\n            Set<URL> urls = getRegistered();\n            if (CollectionUtils.isNotEmpty(urls)) {\n                for (URL u : urls) {\n                    if (UrlUtils.isMatch(url, u)) {\n                        String host = remoteAddress != null && remoteAddress.getAddress() != null\n                                ? remoteAddress.getAddress().getHostAddress()\n                                : url.getIp();\n                        if (url.getParameter(\"unicast\", true) // Whether the consumer's machine has only one process\n                                && !NetUtils.getLocalHost()\n                                        .equals(host)) { // Multiple processes in the same machine cannot be unicast\n                            // with unicast or there will be only one process receiving\n                            // information\n                            unicast(REGISTER + \" \" + u.toFullString(), host);\n                        } else {\n                            multicast(REGISTER + \" \" + u.toFullString());\n                        }\n                    }\n                }\n            }\n        } /* else if (msg.startsWith(UNSUBSCRIBE)) {\n          }*/\n    }\n\n    private void multicast(String msg) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Send multicast message: \" + msg + \" to \" + multicastAddress + \":\" + multicastPort);\n        }\n        try {\n            byte[] data = (msg + \"\\n\").getBytes(StandardCharsets.UTF_8);\n            DatagramPacket hi = new DatagramPacket(data, data.length, multicastAddress, multicastPort);\n            multicastSocket.send(hi);\n        } catch (Exception e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    private void unicast(String msg, String host) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Send unicast message: \" + msg + \" to \" + host + \":\" + multicastPort);\n        }\n        try {\n            byte[] data = (msg + \"\\n\").getBytes(StandardCharsets.UTF_8);\n            DatagramPacket hi = new DatagramPacket(data, data.length, InetAddress.getByName(host), multicastPort);\n            multicastSocket.send(hi);\n        } catch (Exception e) {\n            throw new IllegalStateException(e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public void doRegister(URL url) {\n        multicast(REGISTER + \" \" + url.toFullString());\n    }\n\n    @Override\n    public void doUnregister(URL url) {\n        multicast(UNREGISTER + \" \" + url.toFullString());\n    }\n\n    @Override\n    public void doSubscribe(URL url, final NotifyListener listener) {\n        if (ANY_VALUE.equals(url.getServiceInterface())) {\n            admin = true;\n        }\n        multicast(SUBSCRIBE + \" \" + url.toFullString());\n        synchronized (listener) {\n            try {\n                listener.wait(url.getParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT));\n            } catch (InterruptedException e) {\n            }\n        }\n    }\n\n    @Override\n    public void doUnsubscribe(URL url, NotifyListener listener) {\n        if (!ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(REGISTER_KEY, true)) {\n            unregister(url);\n        }\n        multicast(UNSUBSCRIBE + \" \" + url.toFullString());\n    }\n\n    @Override\n    public boolean isAvailable() {\n        try {\n            return multicastSocket != null;\n        } catch (Throwable t) {\n            return false;\n        }\n    }\n\n    /**\n     * Remove the expired providers(if clean is true), leave the multicast group and close the multicast socket.\n     */\n    @Override\n    public void destroy() {\n        super.destroy();\n        try {\n            ExecutorUtil.cancelScheduledFuture(cleanFuture);\n        } catch (Throwable t) {\n            logger.warn(REGISTRY_SOCKET_EXCEPTION, \"\", \"\", t.getMessage(), t);\n        }\n        try {\n            multicastSocket.leaveGroup(multicastAddress);\n            multicastSocket.close();\n        } catch (Throwable t) {\n            logger.warn(REGISTRY_SOCKET_EXCEPTION, \"\", \"\", t.getMessage(), t);\n        }\n        ExecutorUtil.gracefulShutdown(cleanExecutor, cleanPeriod);\n    }\n\n    protected void registered(URL url) {\n        for (Map.Entry<URL, Set<NotifyListener>> entry : getSubscribed().entrySet()) {\n            URL key = entry.getKey();\n            if (UrlUtils.isMatch(key, url)) {\n                Set<URL> urls = ConcurrentHashMapUtils.computeIfAbsent(received, key, k -> new ConcurrentHashSet<>());\n                urls.add(url);\n                List<URL> list = toList(urls);\n                for (final NotifyListener listener : entry.getValue()) {\n                    notify(key, listener, list);\n                    synchronized (listener) {\n                        listener.notify();\n                    }\n                }\n            }\n        }\n    }\n\n    protected void unregistered(URL url) {\n        for (Map.Entry<URL, Set<NotifyListener>> entry : getSubscribed().entrySet()) {\n            URL key = entry.getKey();\n            if (UrlUtils.isMatch(key, url)) {\n                Set<URL> urls = received.get(key);\n                if (urls != null) {\n                    urls.remove(url);\n                }\n                if (urls == null || urls.isEmpty()) {\n                    if (urls == null) {\n                        urls = new ConcurrentHashSet<>();\n                    }\n                    URL empty = url.setProtocol(EMPTY_PROTOCOL);\n                    urls.add(empty);\n                }\n                List<URL> list = toList(urls);\n                for (NotifyListener listener : entry.getValue()) {\n                    notify(key, listener, list);\n                }\n            }\n        }\n    }\n\n    protected void subscribed(URL url, NotifyListener listener) {\n        List<URL> urls = lookup(url);\n        notify(url, listener, urls);\n    }\n\n    private List<URL> toList(Set<URL> urls) {\n        List<URL> list = new ArrayList<>();\n        if (CollectionUtils.isNotEmpty(urls)) {\n            list.addAll(urls);\n        }\n        return list;\n    }\n\n    @Override\n    public void register(URL url) {\n        super.register(url);\n        registered(url);\n    }\n\n    @Override\n    public void unregister(URL url) {\n        super.unregister(url);\n        unregistered(url);\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        super.subscribe(url, listener);\n        subscribed(url, listener);\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        super.unsubscribe(url, listener);\n        received.remove(url);\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        List<URL> urls = new ArrayList<>();\n        Map<String, List<URL>> notifiedUrls = getNotified().get(url);\n        if (notifiedUrls != null && notifiedUrls.size() > 0) {\n            for (List<URL> values : notifiedUrls.values()) {\n                urls.addAll(values);\n            }\n        }\n        if (urls.isEmpty()) {\n            List<URL> cacheUrls = getCacheUrls(url);\n            if (CollectionUtils.isNotEmpty(cacheUrls)) {\n                urls.addAll(cacheUrls);\n            }\n        }\n        if (urls.isEmpty()) {\n            for (URL u : getRegistered()) {\n                if (UrlUtils.isMatch(url, u)) {\n                    urls.add(u);\n                }\n            }\n        }\n        if (ANY_VALUE.equals(url.getServiceInterface())) {\n            for (URL u : getSubscribed().keySet()) {\n                if (UrlUtils.isMatch(url, u)) {\n                    urls.add(u);\n                }\n            }\n        }\n        return urls;\n    }\n\n    public MulticastSocket getMulticastSocket() {\n        return multicastSocket;\n    }\n\n    public Map<URL, Set<URL>> getReceived() {\n        return received;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multicast;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.support.AbstractRegistryFactory;\n\n/**\n * MulticastRegistryLocator\n *\n */\npublic class MulticastRegistryFactory extends AbstractRegistryFactory {\n\n    @Override\n    public Registry createRegistry(URL url) {\n        return new MulticastRegistry(url, applicationModel);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multicast;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * TODO: make multicast protocol support Service Discovery\n */\npublic class MulticastServiceDiscovery extends AbstractServiceDiscovery {\n    public MulticastServiceDiscovery(ApplicationModel applicationModel, URL registryURL) {\n        super(applicationModel, registryURL);\n    }\n\n    public MulticastServiceDiscovery(String serviceName, URL registryURL) {\n        super(serviceName, registryURL);\n    }\n\n    @Override\n    public void doDestroy() throws Exception {}\n\n    @Override\n    public void doRegister(ServiceInstance serviceInstance) throws RuntimeException {}\n\n    @Override\n    public void doUpdate(ServiceInstance oldServiceInstance, ServiceInstance newServiceInstance)\n            throws RuntimeException {}\n\n    @Override\n    public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException {\n        this.serviceInstance = null;\n    }\n\n    @Override\n    public Set<String> getServices() {\n        return Collections.singleton(\"Unsupported Operation\");\n    }\n\n    @Override\n    public List<ServiceInstance> getInstances(String serviceName) throws NullPointerException {\n        return null;\n    }\n\n    @Override\n    public URL getUrl() {\n        return registryURL;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscoveryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multicast;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscoveryFactory;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\n\npublic class MulticastServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory {\n    @Override\n    protected ServiceDiscovery createDiscovery(URL registryURL) {\n        return new MulticastServiceDiscovery(applicationModel, registryURL);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multicast/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory",
    "content": "multicast=org.apache.dubbo.registry.multicast.MulticastRegistryFactory"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multicast/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory",
    "content": "multicast=org.apache.dubbo.registry.multicast.MulticastServiceDiscoveryFactory"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multicast/src/test/java/org/apache/dubbo/registry/multicast/MulticastRegistryFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multicast;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.Registry;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.not;\nimport static org.hamcrest.CoreMatchers.nullValue;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass MulticastRegistryFactoryTest {\n    @Test\n    void shouldCreateRegistry() {\n        Registry registry = new MulticastRegistryFactory().createRegistry(URL.valueOf(\"multicast://239.255.255.255/\"));\n        assertThat(registry, not(nullValue()));\n        assertThat(registry.isAvailable(), is(true));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multicast/src/test/java/org/apache/dubbo/registry/multicast/MulticastRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multicast;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.registry.NotifyListener;\n\nimport java.net.InetAddress;\nimport java.net.MulticastSocket;\nimport java.net.UnknownHostException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass MulticastRegistryTest {\n\n    private String service = \"org.apache.dubbo.test.injvmServie\";\n    private URL registryUrl = URL.valueOf(\"multicast://239.239.239.239/\");\n    private URL serviceUrl = URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \"/\" + service + \"?methods=test1,test2\");\n    private URL adminUrl = URL.valueOf(\"dubbo://\" + NetUtils.getLocalHost() + \"/*\");\n    private URL consumerUrl = URL.valueOf(\"subscribe://\" + NetUtils.getLocalHost() + \"/\" + service + \"?arg1=1&arg2=2\");\n    private MulticastRegistry registry = new MulticastRegistry(registryUrl);\n\n    @BeforeEach\n    void setUp() {\n        registry.register(serviceUrl);\n    }\n\n    /**\n     * Test method for {@link org.apache.dubbo.registry.multicast.MulticastRegistry#MulticastRegistry(URL)}.\n     */\n    @Test\n    void testUrlError() {\n        Assertions.assertThrows(UnknownHostException.class, () -> {\n            try {\n                URL errorUrl = URL.valueOf(\"multicast://mullticast.local/\");\n                new MulticastRegistry(errorUrl);\n            } catch (IllegalStateException e) {\n                throw e.getCause();\n            }\n        });\n    }\n\n    /**\n     * Test method for {@link org.apache.dubbo.registry.multicast.MulticastRegistry#MulticastRegistry(URL)}.\n     */\n    @Test\n    void testAnyHost() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            URL errorUrl = URL.valueOf(\"multicast://0.0.0.0/\");\n            new MulticastRegistry(errorUrl);\n        });\n    }\n\n    /**\n     * Test method for {@link org.apache.dubbo.registry.multicast.MulticastRegistry#MulticastRegistry(URL)}.\n     */\n    @Test\n    void testGetCustomPort() {\n        int port = NetUtils.getAvailablePort(20880 + new Random().nextInt(10000));\n        URL customPortUrl = URL.valueOf(\"multicast://239.239.239.239:\" + port);\n        MulticastRegistry multicastRegistry = new MulticastRegistry(customPortUrl);\n        assertThat(multicastRegistry.getUrl().getPort(), is(port));\n    }\n\n    /**\n     * Test method for {@link org.apache.dubbo.registry.multicast.MulticastRegistry#getRegistered()}.\n     */\n    @Test\n    void testRegister() {\n        Set<URL> registered;\n        // clear first\n        registered = registry.getRegistered();\n        for (URL url : registered) {\n            registry.unregister(url);\n        }\n\n        for (int i = 0; i < 2; i++) {\n            registry.register(serviceUrl);\n            registered = registry.getRegistered();\n            assertTrue(registered.contains(serviceUrl));\n        }\n        // confirm only 1 register success\n        registered = registry.getRegistered();\n        assertEquals(1, registered.size());\n    }\n\n    /**\n     * Test method for {@link org.apache.dubbo.registry.multicast.MulticastRegistry#unregister(URL)}.\n     */\n    @Test\n    void testUnregister() {\n        Set<URL> registered;\n\n        // register first\n        registry.register(serviceUrl);\n        registered = registry.getRegistered();\n        assertTrue(registered.contains(serviceUrl));\n\n        // then unregister\n        registered = registry.getRegistered();\n        registry.unregister(serviceUrl);\n        assertFalse(registered.contains(serviceUrl));\n    }\n\n    /**\n     * Test method for\n     * {@link org.apache.dubbo.registry.multicast.MulticastRegistry#subscribe(URL url, org.apache.dubbo.registry.NotifyListener)}\n     * .\n     */\n    @Test\n    void testSubscribe() {\n        // verify listener\n        final URL[] notifyUrl = new URL[1];\n        for (int i = 0; i < 10; i++) {\n            registry.register(serviceUrl);\n            registry.subscribe(consumerUrl, urls -> {\n                notifyUrl[0] = urls.get(0);\n\n                Map<URL, Set<NotifyListener>> subscribed = registry.getSubscribed();\n                assertEquals(consumerUrl, subscribed.keySet().iterator().next());\n            });\n            if (!EMPTY_PROTOCOL.equalsIgnoreCase(notifyUrl[0].getProtocol())) {\n                break;\n            }\n        }\n        assertEquals(serviceUrl.toFullString(), notifyUrl[0].toFullString());\n    }\n\n    /**\n     * Test method for {@link org.apache.dubbo.registry.multicast.MulticastRegistry#unsubscribe(URL, NotifyListener)}\n     */\n    @Test\n    void testUnsubscribe() {\n        // subscribe first\n        registry.subscribe(consumerUrl, new NotifyListener() {\n            @Override\n            public void notify(List<URL> urls) {\n                // do nothing\n            }\n        });\n\n        // then unsubscribe\n        registry.unsubscribe(consumerUrl, new NotifyListener() {\n            @Override\n            public void notify(List<URL> urls) {\n                Map<URL, Set<NotifyListener>> subscribed = registry.getSubscribed();\n                Set<NotifyListener> listeners = subscribed.get(consumerUrl);\n                assertTrue(listeners.isEmpty());\n\n                Map<URL, Set<URL>> received = registry.getReceived();\n                assertTrue(received.get(consumerUrl).isEmpty());\n            }\n        });\n    }\n\n    /**\n     * Test method for {@link MulticastRegistry#isAvailable()}\n     */\n    @Test\n    void testAvailability() {\n        int port = NetUtils.getAvailablePort(20880 + new Random().nextInt(10000));\n        MulticastRegistry registry = new MulticastRegistry(URL.valueOf(\"multicast://224.5.6.8:\" + port));\n        assertTrue(registry.isAvailable());\n    }\n\n    /**\n     * Test method for {@link MulticastRegistry#destroy()}\n     */\n    @Test\n    void testDestroy() {\n        MulticastSocket socket = registry.getMulticastSocket();\n        assertFalse(socket.isClosed());\n\n        // then destroy, the multicast socket will be closed\n        registry.destroy();\n        socket = registry.getMulticastSocket();\n        assertTrue(socket.isClosed());\n    }\n\n    /**\n     * Test method for {@link org.apache.dubbo.registry.multicast.MulticastRegistry#MulticastRegistry(URL)}\n     */\n    @Test\n    void testDefaultPort() {\n        MulticastRegistry multicastRegistry = new MulticastRegistry(URL.valueOf(\"multicast://224.5.6.7\"));\n        try {\n            MulticastSocket multicastSocket = multicastRegistry.getMulticastSocket();\n            Assertions.assertEquals(1234, multicastSocket.getLocalPort());\n        } finally {\n            multicastRegistry.destroy();\n        }\n    }\n\n    /**\n     * Test method for {@link org.apache.dubbo.registry.multicast.MulticastRegistry#MulticastRegistry(URL)}\n     */\n    @Test\n    void testCustomedPort() {\n        int port = NetUtils.getAvailablePort(20880 + new Random().nextInt(10000));\n        MulticastRegistry multicastRegistry = new MulticastRegistry(URL.valueOf(\"multicast://224.5.6.7:\" + port));\n        try {\n            MulticastSocket multicastSocket = multicastRegistry.getMulticastSocket();\n            assertEquals(port, multicastSocket.getLocalPort());\n        } finally {\n            multicastRegistry.destroy();\n        }\n    }\n\n    @Test\n    void testMulticastAddress() {\n        InetAddress multicastAddress = null;\n        MulticastSocket multicastSocket = null;\n        try {\n            // ipv4 multicast address\n            multicastAddress = InetAddress.getByName(\"224.55.66.77\");\n            multicastSocket = new MulticastSocket(2345);\n            multicastSocket.setLoopbackMode(false);\n            NetUtils.setInterface(multicastSocket, false);\n            multicastSocket.joinGroup(multicastAddress);\n        } catch (Exception e) {\n            Assertions.fail(e);\n        } finally {\n            if (multicastSocket != null) {\n                multicastSocket.close();\n            }\n        }\n\n        // multicast ipv6 address,\n        try {\n            multicastAddress = InetAddress.getByName(\"ff01::1\");\n\n            multicastSocket = new MulticastSocket();\n            multicastSocket.setLoopbackMode(false);\n            NetUtils.setInterface(multicastSocket, true);\n            multicastSocket.joinGroup(multicastAddress);\n        } catch (Throwable t) {\n            t.printStackTrace();\n        } finally {\n            if (multicastSocket != null) {\n                multicastSocket.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multicast/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multiple/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-registry</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-registry-multiple</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The multiple registry module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-zookeeper</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.commons</groupId>\n      <artifactId>commons-lang3</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-framework</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-recipes</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.zookeeper</groupId>\n      <artifactId>zookeeper</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multiple;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\nimport org.apache.dubbo.registry.support.AbstractRegistry;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\n\npublic class MultipleRegistry extends AbstractRegistry {\n    public static final Logger LOGGER = LoggerFactory.getLogger(MultipleRegistry.class);\n\n    public static final String REGISTRY_FOR_SERVICE = \"service-registry\";\n    public static final String REGISTRY_FOR_REFERENCE = \"reference-registry\";\n    public static final String REGISTRY_SEPARATOR = \"separator\";\n    private final Map<String, Registry> serviceRegistries = new ConcurrentHashMap<>(4);\n    private final Map<String, Registry> referenceRegistries = new ConcurrentHashMap<>(4);\n    private final Map<NotifyListener, MultipleNotifyListenerWrapper> multipleNotifyListenerMap =\n            new ConcurrentHashMap<>(32);\n    private final URL registryUrl;\n    private final String applicationName;\n    protected RegistryFactory registryFactory;\n    protected List<String> origServiceRegistryURLs;\n    protected List<String> origReferenceRegistryURLs;\n    protected List<String> effectServiceRegistryURLs;\n    protected List<String> effectReferenceRegistryURLs;\n\n    public MultipleRegistry(URL url) {\n        this(url, true, true);\n        boolean defaultRegistry = url.getParameter(CommonConstants.DEFAULT_KEY, true);\n        if (defaultRegistry && effectServiceRegistryURLs.isEmpty() && effectReferenceRegistryURLs.isEmpty()) {\n            throw new IllegalArgumentException(\"Illegal registry url. You need to configure parameter \"\n                    + REGISTRY_FOR_SERVICE + \" or \" + REGISTRY_FOR_REFERENCE);\n        }\n    }\n\n    public MultipleRegistry(URL url, boolean initServiceRegistry, boolean initReferenceRegistry) {\n        super(url);\n        this.registryUrl = url;\n        this.applicationName = url.getApplication();\n        this.registryFactory = url.getOrDefaultApplicationModel()\n                .getExtensionLoader(RegistryFactory.class)\n                .getAdaptiveExtension();\n\n        init();\n        checkApplicationName(this.applicationName);\n        // This urls contain parameter, and it does not inherit from the parameter of url in MultipleRegistry\n\n        Map<String, Registry> registryMap = new HashMap<>();\n        if (initServiceRegistry) {\n            initServiceRegistry(url, registryMap);\n        }\n        if (initReferenceRegistry) {\n            initReferenceRegistry(url, registryMap);\n        }\n    }\n\n    protected void initServiceRegistry(URL url, Map<String, Registry> registryMap) {\n        String serviceRegistryString = url.getParameter(REGISTRY_FOR_SERVICE);\n        char separator = url.getParameter(REGISTRY_SEPARATOR, COMMA_SEPARATOR).charAt(0);\n        origServiceRegistryURLs = StringUtils.splitToList(serviceRegistryString, separator);\n        effectServiceRegistryURLs = this.filterServiceRegistry(origServiceRegistryURLs);\n        for (String tmpUrl : effectServiceRegistryURLs) {\n            if (registryMap.get(tmpUrl) != null) {\n                serviceRegistries.put(tmpUrl, registryMap.get(tmpUrl));\n                continue;\n            }\n            final URL registryUrl = URL.valueOf(tmpUrl)\n                    .addParametersIfAbsent(url.getParameters())\n                    .addParameterIfAbsent(CHECK_KEY, url.getParameter(CHECK_KEY, \"true\"));\n            Registry registry = registryFactory.getRegistry(registryUrl);\n            registryMap.put(tmpUrl, registry);\n            serviceRegistries.put(tmpUrl, registry);\n        }\n    }\n\n    protected void initReferenceRegistry(URL url, Map<String, Registry> registryMap) {\n        String serviceRegistryString = url.getParameter(REGISTRY_FOR_REFERENCE);\n        char separator = url.getParameter(REGISTRY_SEPARATOR, COMMA_SEPARATOR).charAt(0);\n        origReferenceRegistryURLs = StringUtils.splitToList(serviceRegistryString, separator);\n        effectReferenceRegistryURLs = this.filterReferenceRegistry(origReferenceRegistryURLs);\n        for (String tmpUrl : effectReferenceRegistryURLs) {\n            if (registryMap.get(tmpUrl) != null) {\n                referenceRegistries.put(tmpUrl, registryMap.get(tmpUrl));\n                continue;\n            }\n            final URL registryUrl = URL.valueOf(tmpUrl)\n                    .addParametersIfAbsent(url.getParameters())\n                    .addParameterIfAbsent(CHECK_KEY, url.getParameter(CHECK_KEY, \"true\"));\n            Registry registry = registryFactory.getRegistry(registryUrl);\n            registryMap.put(tmpUrl, registry);\n            referenceRegistries.put(tmpUrl, registry);\n        }\n    }\n\n    @Override\n    public URL getUrl() {\n        return registryUrl;\n    }\n\n    @Override\n    public boolean isAvailable() {\n        boolean available = serviceRegistries.isEmpty();\n        for (Registry serviceRegistry : serviceRegistries.values()) {\n            if (serviceRegistry.isAvailable()) {\n                available = true;\n            }\n        }\n        if (!available) {\n            return false;\n        }\n\n        available = referenceRegistries.isEmpty();\n        for (Registry referenceRegistry : referenceRegistries.values()) {\n            if (referenceRegistry.isAvailable()) {\n                available = true;\n            }\n        }\n        if (!available) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public void destroy() {\n        Set<Registry> registries = new HashSet<>(serviceRegistries.values());\n        registries.addAll(referenceRegistries.values());\n        for (Registry registry : registries) {\n            registry.destroy();\n        }\n    }\n\n    @Override\n    public void register(URL url) {\n        super.register(url);\n        for (Registry registry : serviceRegistries.values()) {\n            registry.register(url);\n        }\n    }\n\n    @Override\n    public void unregister(URL url) {\n        super.unregister(url);\n        for (Registry registry : serviceRegistries.values()) {\n            registry.unregister(url);\n        }\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        MultipleNotifyListenerWrapper multipleNotifyListenerWrapper = new MultipleNotifyListenerWrapper(listener);\n        multipleNotifyListenerMap.put(listener, multipleNotifyListenerWrapper);\n        for (Registry registry : referenceRegistries.values()) {\n            SingleNotifyListener singleNotifyListener =\n                    new SingleNotifyListener(multipleNotifyListenerWrapper, registry);\n            multipleNotifyListenerWrapper.putRegistryMap(registry.getUrl(), singleNotifyListener);\n            registry.subscribe(url, singleNotifyListener);\n        }\n        super.subscribe(url, multipleNotifyListenerWrapper);\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        MultipleNotifyListenerWrapper notifyListener = multipleNotifyListenerMap.remove(listener);\n        for (Registry registry : referenceRegistries.values()) {\n            SingleNotifyListener singleNotifyListener = notifyListener.registryMap.get(registry.getUrl());\n            registry.unsubscribe(url, singleNotifyListener);\n        }\n\n        if (notifyListener != null) {\n            super.unsubscribe(url, notifyListener);\n            notifyListener.destroy();\n        }\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        List<URL> urls = new ArrayList<>();\n        for (Registry registry : referenceRegistries.values()) {\n            List<URL> tmpUrls = registry.lookup(url);\n            if (!CollectionUtils.isEmpty(tmpUrls)) {\n                urls.addAll(tmpUrls);\n            }\n        }\n        return urls.stream().distinct().collect(Collectors.toList());\n    }\n\n    protected void init() {}\n\n    protected List<String> filterServiceRegistry(List<String> serviceRegistryURLs) {\n        return serviceRegistryURLs;\n    }\n\n    protected List<String> filterReferenceRegistry(List<String> referenceRegistryURLs) {\n        return referenceRegistryURLs;\n    }\n\n    protected void checkApplicationName(String applicationName) {}\n\n    protected String getApplicationName() {\n        return applicationName;\n    }\n\n    public Map<String, Registry> getServiceRegistries() {\n        return serviceRegistries;\n    }\n\n    public Map<String, Registry> getReferenceRegistries() {\n        return referenceRegistries;\n    }\n\n    public List<String> getOrigServiceRegistryURLs() {\n        return origServiceRegistryURLs;\n    }\n\n    public List<String> getOrigReferenceRegistryURLs() {\n        return origReferenceRegistryURLs;\n    }\n\n    public List<String> getEffectServiceRegistryURLs() {\n        return effectServiceRegistryURLs;\n    }\n\n    public List<String> getEffectReferenceRegistryURLs() {\n        return effectReferenceRegistryURLs;\n    }\n\n    protected static class MultipleNotifyListenerWrapper implements NotifyListener {\n\n        Map<URL, SingleNotifyListener> registryMap = new ConcurrentHashMap<>(4);\n        NotifyListener sourceNotifyListener;\n\n        public MultipleNotifyListenerWrapper(NotifyListener sourceNotifyListener) {\n            this.sourceNotifyListener = sourceNotifyListener;\n        }\n\n        public void putRegistryMap(URL registryURL, SingleNotifyListener singleNotifyListener) {\n            this.registryMap.put(registryURL, singleNotifyListener);\n        }\n\n        public void destroy() {\n            for (SingleNotifyListener singleNotifyListener : registryMap.values()) {\n                if (singleNotifyListener != null) {\n                    singleNotifyListener.destroy();\n                }\n            }\n            registryMap.clear();\n            sourceNotifyListener = null;\n        }\n\n        public synchronized void notifySourceListener() {\n            List<URL> notifyURLs = new ArrayList<>();\n            URL emptyURL = null;\n            for (SingleNotifyListener singleNotifyListener : registryMap.values()) {\n                List<URL> tmpUrls = singleNotifyListener.getUrlList();\n                if (CollectionUtils.isEmpty(tmpUrls)) {\n                    continue;\n                }\n                // empty protocol\n                if (tmpUrls.size() == 1\n                        && tmpUrls.get(0) != null\n                        && EMPTY_PROTOCOL.equals(tmpUrls.get(0).getProtocol())) {\n                    // if only one empty\n                    if (emptyURL == null) {\n                        emptyURL = tmpUrls.get(0);\n                    }\n                    continue;\n                }\n                URL registryURL = singleNotifyListener.getRegistry().getUrl();\n                aggregateRegistryUrls(notifyURLs, tmpUrls, registryURL);\n            }\n            // if no notify URL, add empty protocol URL\n            if (emptyURL != null && notifyURLs.isEmpty()) {\n                notifyURLs.add(emptyURL);\n                LOGGER.info(\"No provider after aggregation, notify url with EMPTY protocol.\");\n            } else {\n                LOGGER.info(\"Aggregated provider url size \" + notifyURLs.size());\n            }\n\n            this.notify(notifyURLs);\n        }\n\n        /**\n         * Aggregate urls from different registries into one unified list while appending registry specific 'attachments' into each url.\n         *\n         * These 'attachments' can be very useful for traffic management among registries.\n         *\n         * @param notifyURLs unified url list\n         * @param singleURLs single registry url list\n         * @param registryURL single registry configuration url\n         */\n        public static void aggregateRegistryUrls(List<URL> notifyURLs, List<URL> singleURLs, URL registryURL) {\n            String registryAttachments = registryURL.getParameter(\"attachments\");\n            if (StringUtils.isNotBlank(registryAttachments)) {\n                LOGGER.info(\"Registry attachments \" + registryAttachments\n                        + \" found, will append to provider urls, urls size \" + singleURLs.size());\n                String[] pairs = registryAttachments.split(COMMA_SEPARATOR);\n                Map<String, String> attachments = new HashMap<>(pairs.length);\n                for (String rawPair : pairs) {\n                    String[] keyValuePair = rawPair.split(\"=\");\n                    if (keyValuePair.length == 2) {\n                        String key = keyValuePair[0];\n                        String value = keyValuePair[1];\n                        attachments.put(key, value);\n                    }\n                }\n\n                for (URL tmpUrl : singleURLs) {\n                    for (Map.Entry<String, String> entry : attachments.entrySet()) {\n                        tmpUrl = tmpUrl.addParameterIfAbsent(entry.getKey(), entry.getValue());\n                    }\n                    notifyURLs.add(tmpUrl);\n                }\n            } else {\n                LOGGER.info(\"Single registry \" + registryURL + \" has url size \" + singleURLs.size());\n                notifyURLs.addAll(singleURLs);\n            }\n        }\n\n        @Override\n        public void notify(List<URL> urls) {\n            sourceNotifyListener.notify(urls);\n        }\n\n        public Map<URL, SingleNotifyListener> getRegistryMap() {\n            return registryMap;\n        }\n    }\n\n    protected static class SingleNotifyListener implements NotifyListener {\n\n        MultipleNotifyListenerWrapper multipleNotifyListenerWrapper;\n        Registry registry;\n        volatile List<URL> urlList;\n\n        public SingleNotifyListener(MultipleNotifyListenerWrapper multipleNotifyListenerWrapper, Registry registry) {\n            this.registry = registry;\n            this.multipleNotifyListenerWrapper = multipleNotifyListenerWrapper;\n        }\n\n        @Override\n        public synchronized void notify(List<URL> urls) {\n            this.urlList = urls;\n            if (multipleNotifyListenerWrapper != null) {\n                this.multipleNotifyListenerWrapper.notifySourceListener();\n            }\n        }\n\n        public void destroy() {\n            this.multipleNotifyListenerWrapper = null;\n            this.registry = null;\n        }\n\n        public List<URL> getUrlList() {\n            return urlList;\n        }\n\n        public Registry getRegistry() {\n            return registry;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multiple;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.support.AbstractRegistryFactory;\n\npublic class MultipleRegistryFactory extends AbstractRegistryFactory {\n\n    @Override\n    protected Registry createRegistry(URL url) {\n        return new MultipleRegistry(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multiple;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceDiscoveryFactory;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.function.Function;\n\npublic class MultipleServiceDiscovery implements ServiceDiscovery {\n    public static final String REGISTRY_PREFIX_KEY = \"child.\";\n    private static final String REGISTRY_TYPE = \"registry-type\";\n    private static final String SERVICE = \"service\";\n    private final Map<String, ServiceDiscovery> serviceDiscoveries = new ConcurrentHashMap<>();\n    private URL registryURL;\n    private String applicationName;\n    private volatile boolean isDestroy;\n\n    public MultipleServiceDiscovery(URL registryURL) {\n        this.registryURL = registryURL;\n        this.applicationName = registryURL.getApplication();\n\n        Map<String, String> parameters = registryURL.getParameters();\n        for (String key : parameters.keySet()) {\n            if (key.startsWith(REGISTRY_PREFIX_KEY)) {\n                URL url = URL.valueOf(registryURL.getParameter(key))\n                        .addParameter(CommonConstants.APPLICATION_KEY, applicationName)\n                        .addParameter(REGISTRY_TYPE, SERVICE);\n                ServiceDiscovery serviceDiscovery =\n                        ServiceDiscoveryFactory.getExtension(url).getServiceDiscovery(url);\n                serviceDiscoveries.put(key, serviceDiscovery);\n            }\n        }\n    }\n\n    @Override\n    public URL getUrl() {\n        return registryURL;\n    }\n\n    @Override\n    public void destroy() throws Exception {\n        this.isDestroy = true;\n        for (ServiceDiscovery serviceDiscovery : serviceDiscoveries.values()) {\n            serviceDiscovery.destroy();\n        }\n    }\n\n    @Override\n    public boolean isDestroy() {\n        return isDestroy;\n    }\n\n    @Override\n    public void register() throws RuntimeException {\n        serviceDiscoveries.values().forEach(serviceDiscovery -> serviceDiscovery.register());\n    }\n\n    @Override\n    public void update() throws RuntimeException {\n        serviceDiscoveries.values().forEach(serviceDiscovery -> serviceDiscovery.update());\n    }\n\n    @Override\n    public void unregister() throws RuntimeException {\n        serviceDiscoveries.values().forEach(serviceDiscovery -> serviceDiscovery.unregister());\n    }\n\n    @Override\n    public void addServiceInstancesChangedListener(ServiceInstancesChangedListener listener)\n            throws NullPointerException, IllegalArgumentException {\n        MultiServiceInstancesChangedListener multiListener = (MultiServiceInstancesChangedListener) listener;\n\n        for (String registryKey : serviceDiscoveries.keySet()) {\n            ServiceDiscovery serviceDiscovery = serviceDiscoveries.get(registryKey);\n            SingleServiceInstancesChangedListener singleListener = multiListener.getAndComputeIfAbsent(\n                    registryKey,\n                    k -> new SingleServiceInstancesChangedListener(\n                            listener.getServiceNames(), serviceDiscovery, multiListener));\n            serviceDiscovery.addServiceInstancesChangedListener(singleListener);\n        }\n    }\n\n    @Override\n    public ServiceInstancesChangedListener createListener(Set<String> serviceNames) {\n        return new MultiServiceInstancesChangedListener(serviceNames, this);\n    }\n\n    @Override\n    public List<ServiceInstance> getInstances(String serviceName) {\n        List<ServiceInstance> serviceInstanceList = new ArrayList<>();\n        for (ServiceDiscovery serviceDiscovery : serviceDiscoveries.values()) {\n            serviceInstanceList.addAll(serviceDiscovery.getInstances(serviceName));\n        }\n        return serviceInstanceList;\n    }\n\n    @Override\n    public Set<String> getServices() {\n        Set<String> services = new HashSet<>();\n        for (ServiceDiscovery serviceDiscovery : serviceDiscoveries.values()) {\n            services.addAll(serviceDiscovery.getServices());\n        }\n        return services;\n    }\n\n    @Override\n    public ServiceInstance getLocalInstance() {\n        return null;\n    }\n\n    @Override\n    public MetadataInfo getLocalMetadata() {\n        throw new UnsupportedOperationException(\n                \"Multiple registry implementation does not support getMetadata() method.\");\n    }\n\n    @Override\n    public MetadataInfo getLocalMetadata(String revision) {\n        MetadataInfo metadataInfo = MetadataInfo.EMPTY;\n        for (ServiceDiscovery serviceDiscovery : serviceDiscoveries.values()) {\n            MetadataInfo remoteMetadata = serviceDiscovery.getLocalMetadata(revision);\n            if (!Objects.equals(MetadataInfo.EMPTY, remoteMetadata)) {\n                metadataInfo = remoteMetadata;\n                break;\n            }\n        }\n        return metadataInfo;\n    }\n\n    @Override\n    public MetadataInfo getRemoteMetadata(String revision) {\n        throw new UnsupportedOperationException(\n                \"Multiple registry implementation does not support getMetadata() method.\");\n    }\n\n    @Override\n    public MetadataInfo getRemoteMetadata(String revision, List<ServiceInstance> instances) {\n        MetadataInfo metadataInfo = MetadataInfo.EMPTY;\n        for (ServiceDiscovery serviceDiscovery : serviceDiscoveries.values()) {\n            MetadataInfo remoteMetadata = serviceDiscovery.getRemoteMetadata(revision, instances);\n            if (!Objects.equals(MetadataInfo.EMPTY, remoteMetadata)) {\n                metadataInfo = remoteMetadata;\n                break;\n            }\n        }\n        return metadataInfo;\n    }\n\n    @Override\n    public void register(URL url) {\n        serviceDiscoveries.values().forEach(serviceDiscovery -> serviceDiscovery.register(url));\n    }\n\n    @Override\n    public void unregister(URL url) {\n        serviceDiscoveries.values().forEach(serviceDiscovery -> serviceDiscovery.unregister(url));\n    }\n\n    @Override\n    public void subscribe(URL url, NotifyListener listener) {\n        serviceDiscoveries.values().forEach(serviceDiscovery -> serviceDiscovery.subscribe(url, listener));\n    }\n\n    @Override\n    public void unsubscribe(URL url, NotifyListener listener) {\n        serviceDiscoveries.values().forEach(serviceDiscovery -> serviceDiscovery.unsubscribe(url, listener));\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        throw new UnsupportedOperationException(\"Multiple registry implementation does not support lookup() method.\");\n    }\n\n    protected static class MultiServiceInstancesChangedListener extends ServiceInstancesChangedListener {\n        private final ConcurrentMap<String, SingleServiceInstancesChangedListener> singleListenerMap;\n\n        public MultiServiceInstancesChangedListener(Set<String> serviceNames, ServiceDiscovery serviceDiscovery) {\n            super(serviceNames, serviceDiscovery);\n            this.singleListenerMap = new ConcurrentHashMap<>();\n        }\n\n        @Override\n        public void onEvent(ServiceInstancesChangedEvent event) {\n            List<ServiceInstance> serviceInstances = new ArrayList<>();\n            for (SingleServiceInstancesChangedListener singleListener : singleListenerMap.values()) {\n                if (null != singleListener.event && null != singleListener.event.getServiceInstances()) {\n                    for (ServiceInstance serviceInstance : singleListener.event.getServiceInstances()) {\n                        if (!serviceInstances.contains(serviceInstance)) {\n                            serviceInstances.add(serviceInstance);\n                        }\n                    }\n                }\n            }\n\n            super.onEvent(new ServiceInstancesChangedEvent(event.getServiceName(), serviceInstances));\n        }\n\n        public void putSingleListener(String registryKey, SingleServiceInstancesChangedListener singleListener) {\n            singleListenerMap.put(registryKey, singleListener);\n        }\n\n        public SingleServiceInstancesChangedListener getAndComputeIfAbsent(\n                String registryKey, Function<String, SingleServiceInstancesChangedListener> func) {\n            return ConcurrentHashMapUtils.computeIfAbsent(singleListenerMap, registryKey, func);\n        }\n    }\n\n    protected static class SingleServiceInstancesChangedListener extends ServiceInstancesChangedListener {\n        private final MultiServiceInstancesChangedListener multiListener;\n        volatile ServiceInstancesChangedEvent event;\n\n        public SingleServiceInstancesChangedListener(\n                Set<String> serviceNames,\n                ServiceDiscovery serviceDiscovery,\n                MultiServiceInstancesChangedListener multiListener) {\n            super(serviceNames, serviceDiscovery);\n            this.multiListener = multiListener;\n        }\n\n        @Override\n        public void onEvent(ServiceInstancesChangedEvent event) {\n            this.event = event;\n            if (multiListener != null) {\n                multiListener.onEvent(event);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscoveryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multiple;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscoveryFactory;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\n\npublic class MultipleServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory {\n    @Override\n    protected ServiceDiscovery createDiscovery(URL registryURL) {\n        return new MultipleServiceDiscovery(registryURL);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory",
    "content": "multiple=org.apache.dubbo.registry.multiple.MultipleRegistryFactory\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory",
    "content": "multiple=org.apache.dubbo.registry.multiple.MultipleServiceDiscoveryFactory"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistry2S2RTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multiple;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.zookeeper.ZookeeperRegistry;\nimport org.apache.dubbo.registry.zookeeper.ZookeeperRegistryFactory;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClient;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Assumptions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.MockedConstruction;\nimport org.mockito.Mockito;\n\n/**\n * 2019-04-30\n */\nclass MultipleRegistry2S2RTest {\n\n    private static final String SERVICE_NAME = \"org.apache.dubbo.registry.MultipleService2S2R\";\n    private static final String SERVICE2_NAME = \"org.apache.dubbo.registry.MultipleService2S2R2\";\n    private static final String MOCK_ZK_ADDR_1 = \"zookeeper://127.0.0.1:2181?check=false\";\n    private static final String MOCK_ZK_ADDR_2 = \"zookeeper://127.0.0.1:2182?check=false\";\n    private static final URL MOCK_ZK_URL_1 = URL.valueOf(MOCK_ZK_ADDR_1);\n    private static final URL MOCK_ZK_URL_2 = URL.valueOf(MOCK_ZK_ADDR_2);\n\n    private MultipleRegistry multipleRegistry;\n\n    private ZookeeperClient mockZkClient1;\n    private ZookeeperClient mockZkClient2;\n    private ZookeeperRegistry mockZkRegistry1;\n    private ZookeeperRegistry mockZkRegistry2;\n\n    @BeforeEach\n    void setUp() {\n        mockZkClient1 = Mockito.mock(ZookeeperClient.class);\n        mockZkClient2 = Mockito.mock(ZookeeperClient.class);\n        mockZkRegistry1 = Mockito.mock(ZookeeperRegistry.class);\n        mockZkRegistry2 = Mockito.mock(ZookeeperRegistry.class);\n\n        try (MockedConstruction<ZookeeperRegistryFactory> zkFactoryConstruction =\n                Mockito.mockConstruction(ZookeeperRegistryFactory.class, (mockFactory, context) -> {\n                    Mockito.lenient()\n                            .when(mockFactory.getRegistry(MOCK_ZK_URL_1))\n                            .thenReturn(mockZkRegistry1);\n                    Mockito.lenient()\n                            .when(mockFactory.getRegistry(MOCK_ZK_URL_2))\n                            .thenReturn(mockZkRegistry2);\n                })) {\n            Mockito.lenient().when(mockZkRegistry1.isAvailable()).thenReturn(true);\n            Mockito.lenient().when(mockZkRegistry2.isAvailable()).thenReturn(true);\n            Mockito.lenient().when(mockZkRegistry1.getUrl()).thenReturn(MOCK_ZK_URL_1);\n            Mockito.lenient().when(mockZkRegistry2.getUrl()).thenReturn(MOCK_ZK_URL_2);\n\n            URL multipleUrl =\n                    URL.valueOf(\"multiple://127.0.0.1?application=vic&enable-empty-protection=false&check=false&\"\n                            + MultipleRegistry.REGISTRY_FOR_SERVICE + \"=\" + MOCK_ZK_ADDR_1 + \",\" + MOCK_ZK_ADDR_2 + \"&\"\n                            + MultipleRegistry.REGISTRY_FOR_REFERENCE + \"=\" + MOCK_ZK_ADDR_1 + \",\" + MOCK_ZK_ADDR_2);\n\n            multipleRegistry = (MultipleRegistry) new MultipleRegistryFactory().createRegistry(multipleUrl);\n\n            Map<URL, Registry> serviceRegistries = new HashMap<>();\n            serviceRegistries.put(MOCK_ZK_URL_1, mockZkRegistry1);\n            serviceRegistries.put(MOCK_ZK_URL_2, mockZkRegistry2);\n            setPrivateField(multipleRegistry, \"serviceRegistries\", serviceRegistries);\n            setPrivateField(multipleRegistry, \"referenceRegistries\", serviceRegistries);\n        } catch (Exception e) {\n            throw new RuntimeException(\"Failed to initialize MultipleRegistry\", e);\n        }\n    }\n\n    private void setPrivateField(Object targetObj, String fieldName, Object fieldValue) {\n        try {\n            Field field = targetObj.getClass().getDeclaredField(fieldName);\n            field.setAccessible(true);\n            field.set(targetObj, fieldValue);\n        } catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(\"Failed to set private field via Reflection:\" + fieldName, e);\n        }\n    }\n\n    @Test\n    void testParamConfig() {\n        Assertions.assertEquals(2, multipleRegistry.origReferenceRegistryURLs.size());\n        Assertions.assertTrue(multipleRegistry.origReferenceRegistryURLs.contains(MOCK_ZK_ADDR_1));\n        Assertions.assertTrue(multipleRegistry.origReferenceRegistryURLs.contains(MOCK_ZK_ADDR_2));\n\n        Assertions.assertEquals(2, multipleRegistry.origServiceRegistryURLs.size());\n        Assertions.assertTrue(multipleRegistry.origServiceRegistryURLs.contains(MOCK_ZK_ADDR_1));\n        Assertions.assertTrue(multipleRegistry.origServiceRegistryURLs.contains(MOCK_ZK_ADDR_2));\n\n        Assertions.assertEquals(2, multipleRegistry.effectReferenceRegistryURLs.size());\n        Assertions.assertTrue(multipleRegistry.effectReferenceRegistryURLs.contains(MOCK_ZK_ADDR_1));\n        Assertions.assertTrue(multipleRegistry.effectReferenceRegistryURLs.contains(MOCK_ZK_ADDR_2));\n\n        Assertions.assertEquals(2, multipleRegistry.effectServiceRegistryURLs.size());\n        Assertions.assertTrue(multipleRegistry.effectServiceRegistryURLs.contains(MOCK_ZK_ADDR_1));\n        Assertions.assertTrue(multipleRegistry.effectServiceRegistryURLs.contains(MOCK_ZK_ADDR_2));\n\n        Assertions.assertTrue(multipleRegistry.getServiceRegistries().containsKey(MOCK_ZK_URL_1));\n        Assertions.assertTrue(multipleRegistry.getServiceRegistries().containsKey(MOCK_ZK_URL_2));\n        Assertions.assertEquals(\n                2, multipleRegistry.getServiceRegistries().values().size());\n        //        java.util.Iterator<Registry> registryIterable =\n        // multipleRegistry.getServiceRegistries().values().iterator();\n        //        Registry firstRegistry = registryIterable.next();\n        //        Registry secondRegistry = registryIterable.next();\n        Assertions.assertNotNull(MultipleRegistryTestUtil.getZookeeperRegistry(\n                multipleRegistry.getServiceRegistries().values()));\n        Assertions.assertNotNull(MultipleRegistryTestUtil.getZookeeperRegistry(\n                multipleRegistry.getReferenceRegistries().values()));\n\n        Assertions.assertEquals(\n                MultipleRegistryTestUtil.getZookeeperRegistry(\n                        multipleRegistry.getServiceRegistries().values()),\n                MultipleRegistryTestUtil.getZookeeperRegistry(\n                        multipleRegistry.getReferenceRegistries().values()));\n\n        Assertions.assertEquals(\n                MultipleRegistryTestUtil.getZookeeperRegistry(\n                        multipleRegistry.getServiceRegistries().values()),\n                MultipleRegistryTestUtil.getZookeeperRegistry(\n                        multipleRegistry.getReferenceRegistries().values()));\n\n        Assertions.assertEquals(multipleRegistry.getApplicationName(), \"vic\");\n\n        Assertions.assertTrue(multipleRegistry.isAvailable());\n    }\n\n    @Test\n    void testRegistryAndUnRegistry() throws InterruptedException {\n        URL serviceUrl = URL.valueOf(\"http2://multiple/\" + SERVICE_NAME\n                + \"?notify=false&methods=test1,test2&category=providers&application=vic\");\n\n        multipleRegistry.register(serviceUrl);\n        Mockito.verify(mockZkRegistry1, Mockito.times(1)).register(serviceUrl);\n        Mockito.verify(mockZkRegistry2, Mockito.times(1)).register(serviceUrl);\n\n        String path = \"/dubbo/\" + SERVICE_NAME + \"/providers\";\n        Mockito.when(mockZkClient1.getChildren(path)).thenReturn(Arrays.asList(\"provider1\"));\n        List<String> providerList = mockZkClient1.getChildren(path);\n        Assertions.assertTrue(!providerList.isEmpty());\n\n        final List<URL> list = new ArrayList<>();\n        multipleRegistry.subscribe(serviceUrl, new NotifyListener() {\n            @Override\n            public void notify(List<URL> urls) {\n                list.clear();\n                list.addAll(urls);\n            }\n        });\n\n        ArgumentCaptor<NotifyListener> captor1 = ArgumentCaptor.forClass(NotifyListener.class);\n        ArgumentCaptor<NotifyListener> captor2 = ArgumentCaptor.forClass(NotifyListener.class);\n        Mockito.verify(mockZkRegistry1, Mockito.times(1)).subscribe(Mockito.eq(serviceUrl), captor1.capture());\n        Mockito.verify(mockZkRegistry2, Mockito.times(1)).subscribe(Mockito.eq(serviceUrl), captor2.capture());\n\n        List<URL> mockUrls1 = Arrays.asList(URL.valueOf(\"http2://127.0.0.1:20880/\" + SERVICE_NAME));\n        List<URL> mockUrls2 = Arrays.asList(URL.valueOf(\"http2://127.0.0.1:20881/\" + SERVICE_NAME));\n        captor1.getValue().notify(mockUrls1);\n        captor2.getValue().notify(mockUrls2);\n\n        Thread.sleep(1500);\n        Assertions.assertEquals(2, list.size());\n\n        multipleRegistry.unregister(serviceUrl);\n        Mockito.verify(mockZkRegistry1, Mockito.times(1)).unregister(serviceUrl);\n        Mockito.verify(mockZkRegistry2, Mockito.times(1)).unregister(serviceUrl);\n\n        List<URL> unregisterUrls = Arrays.asList(URL.valueOf(\"empty://127.0.0.1:20880/\" + SERVICE_NAME));\n        captor1.getValue().notify(unregisterUrls);\n        captor2.getValue().notify(unregisterUrls);\n\n        Thread.sleep(1500);\n        Assertions.assertEquals(1, list.size());\n\n        List<URL> urls = MultipleRegistryTestUtil.getProviderURLsFromNotifyURLS(list);\n        Assertions.assertEquals(1, list.size());\n        Assertions.assertEquals(\"empty\", list.get(0).getProtocol());\n    }\n\n    @Test\n    void testSubscription() throws InterruptedException {\n        URL serviceUrl = URL.valueOf(\"http2://multiple/\" + SERVICE2_NAME\n                + \"?notify=false&methods=test1,test2&category=providers&application=vic\");\n\n        multipleRegistry.register(serviceUrl);\n        Mockito.verify(mockZkRegistry1, Mockito.times(1)).register(serviceUrl);\n        Mockito.verify(mockZkRegistry2, Mockito.times(1)).register(serviceUrl);\n\n        String path = \"/dubbo/\" + SERVICE2_NAME + \"/providers\";\n        Mockito.when(mockZkClient1.getChildren(path)).thenReturn(Arrays.asList(\"provider1\"));\n        List<String> providerList = mockZkClient1.getChildren(path);\n        Assumptions.assumeTrue(!providerList.isEmpty());\n\n        final List<URL> list = new ArrayList<>();\n        multipleRegistry.subscribe(serviceUrl, new NotifyListener() {\n            @Override\n            public void notify(List<URL> urls) {\n                list.clear();\n                list.addAll(urls);\n            }\n        });\n\n        ArgumentCaptor<NotifyListener> captor1 = ArgumentCaptor.forClass(NotifyListener.class);\n        ArgumentCaptor<NotifyListener> captor2 = ArgumentCaptor.forClass(NotifyListener.class);\n        Mockito.verify(mockZkRegistry1, Mockito.times(1)).subscribe(Mockito.eq(serviceUrl), captor1.capture());\n        Mockito.verify(mockZkRegistry2, Mockito.times(1)).subscribe(Mockito.eq(serviceUrl), captor2.capture());\n\n        List<URL> mockUrls1 = Arrays.asList(URL.valueOf(\"http2://127.0.0.1:20880/\" + SERVICE2_NAME));\n        List<URL> mockUrls2 = Arrays.asList(URL.valueOf(\"http2://127.0.0.1:20881/\" + SERVICE2_NAME));\n        captor1.getValue().notify(mockUrls1);\n        captor2.getValue().notify(mockUrls2);\n\n        Thread.sleep(1500);\n        Assertions.assertEquals(2, list.size());\n\n        List<Registry> serviceRegistries =\n                new ArrayList<>(multipleRegistry.getServiceRegistries().values());\n        serviceRegistries.get(0).unregister(serviceUrl);\n        Mockito.verify(mockZkRegistry1, Mockito.times(1)).unregister(serviceUrl);\n\n        List<URL> unregisterUrls1 = Arrays.asList(URL.valueOf(\"empty://127.0.0.1:20880/\" + SERVICE2_NAME));\n        captor1.getValue().notify(unregisterUrls1);\n\n        Thread.sleep(1500);\n        Assertions.assertEquals(1, list.size());\n        List<URL> urls1 = MultipleRegistryTestUtil.getProviderURLsFromNotifyURLS(list);\n        Assertions.assertEquals(1, list.size());\n        Assertions.assertTrue(!\"empty\".equals(list.get(0).getProtocol()));\n\n        serviceRegistries.get(1).unregister(serviceUrl);\n        Mockito.verify(mockZkRegistry2, Mockito.times(1)).unregister(serviceUrl);\n        List<URL> unregisterUrls2 = Arrays.asList(URL.valueOf(\"empty://127.0.0.1:20881/\" + SERVICE2_NAME));\n        captor2.getValue().notify(unregisterUrls2);\n        Thread.sleep(1500);\n        Assertions.assertEquals(1, list.size());\n        List<URL> urls2 = MultipleRegistryTestUtil.getProviderURLsFromNotifyURLS(list);\n        Assertions.assertEquals(1, list.size());\n        Assertions.assertEquals(\"empty\", list.get(0).getProtocol());\n    }\n\n    @Test\n    void testAggregation() {\n        List<URL> result = new ArrayList<URL>();\n        List<URL> listToAggregate = new ArrayList<URL>();\n        URL url1 = URL.valueOf(\"dubbo://127.0.0.1:20880/service1\");\n        URL url2 = URL.valueOf(\"dubbo://127.0.0.1:20880/service1\");\n        listToAggregate.add(url1);\n        listToAggregate.add(url2);\n\n        URL registryURL = URL.valueOf(\n                \"mock://127.0.0.1/RegistryService?attachments=zone=hangzhou,tag=middleware&enable-empty-protection=false\");\n\n        MultipleRegistry.MultipleNotifyListenerWrapper.aggregateRegistryUrls(result, listToAggregate, registryURL);\n\n        Assertions.assertEquals(2, result.size());\n        Assertions.assertEquals(2, result.get(0).getParameters().size());\n        Assertions.assertEquals(\"hangzhou\", result.get(0).getParameter(\"zone\"));\n        Assertions.assertEquals(\"middleware\", result.get(1).getParameter(\"tag\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistryTestUtil.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multiple;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.ListenerRegistryWrapper;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.zookeeper.ZookeeperRegistry;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CONFIG_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ROUTE_PROTOCOL;\n\n/**\n * 2019-05-13\n */\npublic class MultipleRegistryTestUtil {\n    public static ZookeeperRegistry getZookeeperRegistry(Collection<Registry> registryCollection) {\n        for (Registry registry : registryCollection) {\n            if (registry instanceof ListenerRegistryWrapper) {\n                registry = ((ListenerRegistryWrapper) registry).getRegistry();\n            }\n            if (registry instanceof ZookeeperRegistry) {\n                return (ZookeeperRegistry) registry;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * copy from @org.apache.dubbo.registry.integration.RegistryDirectory#notify(java.util.List)\n     *\n     * @param urls\n     * @return\n     */\n    public static List<URL> getProviderURLsFromNotifyURLS(List<URL> urls) {\n        Map<String, List<URL>> categoryUrls = urls.stream()\n                .filter(Objects::nonNull)\n                .filter(MultipleRegistryTestUtil::isValidCategory)\n                .filter(MultipleRegistryTestUtil::isNotCompatibleFor26x)\n                .collect(Collectors.groupingBy(url -> {\n                    if (UrlUtils.isConfigurator(url)) {\n                        return CONFIGURATORS_CATEGORY;\n                    } else if (UrlUtils.isRoute(url)) {\n                        return ROUTERS_CATEGORY;\n                    } else if (UrlUtils.isProvider(url)) {\n                        return PROVIDERS_CATEGORY;\n                    }\n                    return \"\";\n                }));\n\n        // providers\n        List<URL> providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY, Collections.emptyList());\n        return providerURLs;\n    }\n\n    private static boolean isValidCategory(URL url) {\n        String category = url.getCategory(DEFAULT_CATEGORY);\n        if ((ROUTERS_CATEGORY.equals(category) || ROUTE_PROTOCOL.equals(url.getProtocol()))\n                || PROVIDERS_CATEGORY.equals(category)\n                || CONFIGURATORS_CATEGORY.equals(category)\n                || DYNAMIC_CONFIGURATORS_CATEGORY.equals(category)\n                || APP_DYNAMIC_CONFIGURATORS_CATEGORY.equals(category)) {\n            return true;\n        }\n        return false;\n    }\n\n    private static boolean isNotCompatibleFor26x(URL url) {\n        return StringUtils.isEmpty(url.getParameter(COMPATIBLE_CONFIG_KEY));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscoveryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.multiple;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.metadata.MetadataInfo;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.google.common.collect.Sets;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;\n\npublic class MultipleServiceDiscoveryTest {\n\n    private static String mockZkAddress = \"zookeeper://mock-zk:2181?check=false\";\n\n    @Test\n    public void testOnEvent() {\n        try {\n            String metadata_111 = \"{\\\"app\\\":\\\"app1\\\",\\\"revision\\\":\\\"111\\\",\\\"services\\\":{\"\n                    + \"\\\"org.apache.dubbo.demo.DemoService:dubbo\\\":{\\\"name\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"protocol\\\":\\\"dubbo\\\",\\\"path\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"params\\\":{\\\"side\\\":\\\"provider\\\",\\\"release\\\":\\\"\\\",\\\"methods\\\":\\\"sayHello,sayHelloAsync\\\",\\\"deprecated\\\":\\\"false\\\",\\\"dubbo\\\":\\\"2.0.2\\\",\\\"pid\\\":\\\"72723\\\",\\\"interface\\\":\\\"org.apache.dubbo.demo.DemoService\\\",\\\"service-name-mapping\\\":\\\"true\\\",\\\"timeout\\\":\\\"3000\\\",\\\"generic\\\":\\\"false\\\",\\\"metadata-type\\\":\\\"remote\\\",\\\"delay\\\":\\\"5000\\\",\\\"application\\\":\\\"app1\\\",\\\"dynamic\\\":\\\"true\\\",\\\"REGISTRY_CLUSTER\\\":\\\"registry1\\\",\\\"anyhost\\\":\\\"true\\\",\\\"timestamp\\\":\\\"1625800233446\\\"}}\"\n                    + \"}}\";\n            MetadataInfo metadataInfo = JsonUtils.toJavaObject(metadata_111, MetadataInfo.class);\n            ApplicationModel applicationModel = ApplicationModel.defaultModel();\n            applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(\"app2\"));\n            String multipleUrl = String.format(\n                    \"multiple://mock-registry:2181?reference-registry=%s&child.a1=%s&check=false\",\n                    mockZkAddress, mockZkAddress);\n            URL url = URL.valueOf(multipleUrl);\n            url.setScopeModel(applicationModel);\n            MultipleServiceDiscovery multipleServiceDiscovery = new MultipleServiceDiscovery(url);\n            Class<MultipleServiceDiscovery> msdClass = MultipleServiceDiscovery.class;\n            Field serviceDiscoveriesField = msdClass.getDeclaredField(\"serviceDiscoveries\");\n            serviceDiscoveriesField.setAccessible(true);\n            ServiceDiscovery mockServiceDiscovery = Mockito.mock(ServiceDiscovery.class);\n            Mockito.when(mockServiceDiscovery.getRemoteMetadata(Mockito.anyString(), Mockito.anyList()))\n                    .thenReturn(metadataInfo);\n            Map<String, ServiceDiscovery> mockServiceDiscoveries = new HashMap<>();\n            mockServiceDiscoveries.put(\"child.a1\", mockServiceDiscovery);\n            serviceDiscoveriesField.set(multipleServiceDiscovery, mockServiceDiscoveries);\n            MultipleServiceDiscovery.MultiServiceInstancesChangedListener listener =\n                    (MultipleServiceDiscovery.MultiServiceInstancesChangedListener)\n                            multipleServiceDiscovery.createListener(Sets.newHashSet(\"app1\"));\n            multipleServiceDiscovery.addServiceInstancesChangedListener(listener);\n\n            MultipleServiceDiscovery.SingleServiceInstancesChangedListener singleListener =\n                    listener.getAndComputeIfAbsent(\"child.a1\", (a1) -> null);\n            Assert.notNull(singleListener, \"singleServiceInstancesChangedListener can not be null\");\n\n            List<Object> urlsSameRevision = new ArrayList<>();\n            urlsSameRevision.add(\"127.0.0.1:20880?revision=111\");\n            urlsSameRevision.add(\"127.0.0.2:20880?revision=111\");\n            urlsSameRevision.add(\"127.0.0.3:20880?revision=111\");\n            singleListener.onEvent(new ServiceInstancesChangedEvent(\"app1\", buildInstances(urlsSameRevision)));\n            Mockito.verify(mockServiceDiscovery, Mockito.times(1))\n                    .getRemoteMetadata(Mockito.anyString(), Mockito.anyList());\n            Field serviceUrlsField = ServiceInstancesChangedListener.class.getDeclaredField(\"serviceUrls\");\n            serviceUrlsField.setAccessible(true);\n            Map<String, List<ServiceInstancesChangedListener.ProtocolServiceKeyWithUrls>> map =\n                    (Map<String, List<ServiceInstancesChangedListener.ProtocolServiceKeyWithUrls>>)\n                            serviceUrlsField.get(listener);\n            Assert.assertTrue(!CollectionUtils.isEmptyMap(map), \"url can not be empty\");\n        } catch (NoSuchFieldException e) {\n            throw new RuntimeException(e);\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    static List<ServiceInstance> buildInstances(List<Object> rawURls) {\n        List<ServiceInstance> instances = new ArrayList<>();\n\n        for (Object obj : rawURls) {\n            String rawURL = (String) obj;\n            DefaultServiceInstance instance = new DefaultServiceInstance();\n            final URL dubboUrl = URL.valueOf(rawURL);\n            instance.setRawAddress(rawURL);\n            instance.setHost(dubboUrl.getHost());\n            instance.setEnabled(true);\n            instance.setHealthy(true);\n            instance.setPort(dubboUrl.getPort());\n            instance.setRegistryCluster(\"default\");\n            instance.setApplicationModel(ApplicationModel.defaultModel());\n\n            Map<String, String> metadata = new HashMap<>();\n            if (StringUtils.isNotEmpty(dubboUrl.getParameter(REVISION_KEY))) {\n                metadata.put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, dubboUrl.getParameter(REVISION_KEY));\n            }\n            instance.setMetadata(metadata);\n\n            instances.add(instance);\n        }\n\n        return instances;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-registry</artifactId>\n    <version>${revision}</version>\n  </parent>\n\n  <artifactId>dubbo-registry-nacos</artifactId>\n  <name>${project.artifactId}</name>\n  <description>The Nacos registry module of Dubbo project</description>\n\n  <dependencies>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-api</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>com.alibaba.nacos</groupId>\n      <artifactId>nacos-client</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-fastjson2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-dubbo</artifactId>\n      <version>${project.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-netty4</artifactId>\n      <version>${project.version}</version>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- REST support dependencies -->\n    <dependency>\n      <groupId>org.springframework</groupId>\n      <artifactId>spring-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosAggregateListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.registry.NotifyListener;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.nacos.api.naming.pojo.Instance;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_NACOS_SUB_LEGACY;\n\npublic class NacosAggregateListener {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(NacosAggregateListener.class);\n    private final NotifyListener notifyListener;\n    private final Set<String> serviceNames = new ConcurrentHashSet<>();\n    private final Map<String, List<Instance>> serviceInstances = new ConcurrentHashMap<>();\n    private final AtomicBoolean warned = new AtomicBoolean(false);\n    private static final Pattern SPLITTED_PATTERN = Pattern.compile(\".*:.*:.*:.*\");\n\n    public NacosAggregateListener(NotifyListener notifyListener) {\n        this.notifyListener = notifyListener;\n    }\n\n    public List<Instance> saveAndAggregateAllInstances(String serviceName, List<Instance> instances) {\n        serviceNames.add(serviceName);\n        if (instances == null) {\n            serviceInstances.remove(serviceName);\n        } else {\n            serviceInstances.put(serviceName, instances);\n        }\n        if (isLegacyName(serviceName)\n                && instances != null\n                && !instances.isEmpty()\n                && warned.compareAndSet(false, true)) {\n            logger.error(\n                    REGISTRY_NACOS_SUB_LEGACY,\n                    \"\",\n                    \"\",\n                    \"Received not empty notification for legacy service name: \" + serviceName + \", \" + \"instances: [\"\n                            + instances.stream().map(Instance::getIp).collect(Collectors.joining(\" ,\")) + \"]. \"\n                            + \"Please upgrade these Dubbo client(lower than 2.7.3) to the latest version. \"\n                            + \"Dubbo will remove the support for legacy service name in the future.\");\n        }\n        return serviceInstances.values().stream().flatMap(List::stream).collect(Collectors.toList());\n    }\n\n    private static boolean isLegacyName(String serviceName) {\n        return !SPLITTED_PATTERN.matcher(serviceName).matches();\n    }\n\n    public NotifyListener getNotifyListener() {\n        return notifyListener;\n    }\n\n    public Set<String> getServiceNames() {\n        return serviceNames;\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        NacosAggregateListener that = (NacosAggregateListener) o;\n        return Objects.equals(notifyListener, that.notifyListener)\n                && Objects.equals(serviceNames, that.serviceNames)\n                && Objects.equals(serviceInstances, that.serviceInstances);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(notifyListener);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosConnectionManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.concurrent.ThreadLocalRandom;\n\nimport com.alibaba.nacos.api.NacosFactory;\nimport com.alibaba.nacos.api.PropertyKeyConst;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\n\nimport static com.alibaba.nacos.api.PropertyKeyConst.PASSWORD;\nimport static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;\nimport static com.alibaba.nacos.api.PropertyKeyConst.USERNAME;\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP;\nimport static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_INTERRUPTED;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION;\nimport static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;\nimport static org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of;\n\npublic class NacosConnectionManager {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(NacosNamingServiceUtils.class);\n\n    private final URL connectionURL;\n\n    private final List<NamingService> namingServiceList = new LinkedList<>();\n\n    private final int retryTimes;\n\n    private final int sleepMsBetweenRetries;\n\n    private final boolean check;\n\n    private final Properties nacosProperties;\n\n    public NacosConnectionManager(URL connectionURL, boolean check, int retryTimes, int sleepMsBetweenRetries) {\n        this.connectionURL = connectionURL;\n        this.check = check;\n        this.retryTimes = retryTimes;\n        this.sleepMsBetweenRetries = sleepMsBetweenRetries;\n        this.nacosProperties = buildNacosProperties(this.connectionURL);\n        // create default one\n        this.namingServiceList.add(createNamingService());\n    }\n\n    /**\n     * @deprecated for ut only\n     */\n    @Deprecated\n    protected NacosConnectionManager(NamingService namingService) {\n        this.connectionURL = null;\n        this.retryTimes = 0;\n        this.sleepMsBetweenRetries = 0;\n        this.check = false;\n        this.nacosProperties = null;\n        // create default one\n        this.namingServiceList.add(namingService);\n    }\n\n    public synchronized NamingService getNamingService() {\n        if (namingServiceList.isEmpty()) {\n            this.namingServiceList.add(createNamingService());\n        }\n        return namingServiceList.get(ThreadLocalRandom.current().nextInt(namingServiceList.size()));\n    }\n\n    public synchronized NamingService getNamingService(Set<NamingService> selected) {\n        List<NamingService> copyOfNamingService = new LinkedList<>(namingServiceList);\n        copyOfNamingService.removeAll(selected);\n        if (copyOfNamingService.isEmpty()) {\n            this.namingServiceList.add(createNamingService());\n            return getNamingService(selected);\n        }\n        return copyOfNamingService.get(ThreadLocalRandom.current().nextInt(copyOfNamingService.size()));\n    }\n\n    public synchronized void shutdownAll() {\n        for (NamingService namingService : namingServiceList) {\n            try {\n                namingService.shutDown();\n            } catch (Exception e) {\n                logger.warn(REGISTRY_NACOS_EXCEPTION, \"\", \"\", \"Unable to shutdown nacos naming service\", e);\n            }\n        }\n        this.namingServiceList.clear();\n    }\n\n    /**\n     * Create an instance of {@link NamingService} from specified {@link URL connection url}\n     *\n     * @return {@link NamingService}\n     */\n    protected NamingService createNamingService() {\n        NamingService namingService = null;\n        try {\n            for (int i = 0; i < retryTimes + 1; i++) {\n                namingService = NacosFactory.createNamingService(nacosProperties);\n                String serverStatus = namingService.getServerStatus();\n                boolean namingServiceAvailable = testNamingService(namingService);\n                if (!check || (UP.equals(serverStatus) && namingServiceAvailable)) {\n                    break;\n                } else {\n                    logger.warn(\n                            LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION,\n                            \"\",\n                            \"\",\n                            \"Failed to connect to nacos naming server. \" + \"Server status: \"\n                                    + serverStatus + \". \" + \"Naming Service Available: \"\n                                    + namingServiceAvailable + \". \"\n                                    + (i < retryTimes\n                                            ? \"Dubbo will try to retry in \" + sleepMsBetweenRetries + \". \"\n                                            : \"Exceed retry max times.\")\n                                    + \"Try times: \"\n                                    + (i + 1));\n                }\n                namingService.shutDown();\n                namingService = null;\n                Thread.sleep(sleepMsBetweenRetries);\n            }\n        } catch (NacosException e) {\n            if (logger.isErrorEnabled()) {\n                logger.error(REGISTRY_NACOS_EXCEPTION, \"\", \"\", e.getErrMsg(), e);\n            }\n        } catch (InterruptedException e) {\n            logger.error(INTERNAL_INTERRUPTED, \"\", \"\", \"Interrupted when creating nacos naming service client.\", e);\n            Thread.currentThread().interrupt();\n            throw new IllegalStateException(e);\n        }\n\n        if (namingService == null) {\n            logger.error(\n                    REGISTRY_NACOS_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Failed to create nacos naming service client. Reason: server status check failed.\");\n            throw new IllegalStateException(\n                    \"Failed to create nacos naming service client. Reason: server status check failed.\");\n        }\n\n        return namingService;\n    }\n\n    private boolean testNamingService(NamingService namingService) {\n        try {\n            namingService.getAllInstances(\"Dubbo-Nacos-Test\", false);\n            return true;\n        } catch (NacosException e) {\n            return false;\n        }\n    }\n\n    private Properties buildNacosProperties(URL url) {\n        Properties properties = new Properties();\n        if (StringUtils.isEmpty(url.getHost())) {\n            return properties;\n        }\n        setServerAddr(url, properties);\n        setProperties(url, properties);\n        return properties;\n    }\n\n    private void setServerAddr(URL url, Properties properties) {\n        StringBuilder serverAddrBuilder = new StringBuilder(url.getHost()) // Host\n                .append(':')\n                .append(url.getPort()); // Port\n\n        // Append backup parameter as other servers\n        String backup = url.getParameter(BACKUP_KEY);\n        if (StringUtils.isNotEmpty(backup)) {\n            serverAddrBuilder.append(',').append(backup);\n        }\n\n        String serverAddr = serverAddrBuilder.toString();\n        properties.put(SERVER_ADDR, serverAddr);\n    }\n\n    private void setProperties(URL url, Properties properties) {\n        putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME, null);\n\n        // @since 2.7.8 : Refactoring\n        // Get the parameters from constants\n        Map<String, String> parameters = url.getParameters(of(PropertyKeyConst.class));\n        // Put all parameters\n        properties.putAll(parameters);\n        if (StringUtils.isNotEmpty(url.getUsername())) {\n            properties.put(USERNAME, url.getUsername());\n        }\n        if (StringUtils.isNotEmpty(url.getPassword())) {\n            properties.put(PASSWORD, url.getPassword());\n        }\n    }\n\n    private void putPropertyIfAbsent(URL url, Properties properties, String propertyName, String defaultValue) {\n        String propertyValue = url.getParameter(propertyName);\n        if (StringUtils.isNotEmpty(propertyValue)) {\n            properties.setProperty(propertyName, propertyValue);\n        } else {\n            // when defaultValue is empty, we should not set empty value\n            if (StringUtils.isNotEmpty(defaultValue)) {\n                properties.setProperty(propertyName, defaultValue);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.constants.LoggerCodeConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.MethodUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.nacos.function.NacosConsumer;\nimport org.apache.dubbo.registry.nacos.function.NacosFunction;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.listener.EventListener;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport com.alibaba.nacos.api.naming.pojo.ListView;\n\npublic class NacosNamingServiceWrapper {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(NacosNamingServiceWrapper.class);\n\n    private static final String INNERCLASS_SYMBOL = \"$\";\n\n    private static final String INNERCLASS_COMPATIBLE_SYMBOL = \"___\";\n\n    private final NacosConnectionManager nacosConnectionManager;\n\n    private final int retryTimes;\n\n    private final int sleepMsBetweenRetries;\n\n    private final boolean isSupportBatchRegister;\n\n    private final ConcurrentMap<InstanceId, InstancesInfo> registerStatus = new ConcurrentHashMap<>();\n    private final ConcurrentMap<SubscribeInfo, NamingService> subscribeStatus = new ConcurrentHashMap<>();\n\n    public NacosNamingServiceWrapper(\n            NacosConnectionManager nacosConnectionManager, int retryTimes, int sleepMsBetweenRetries) {\n        this.nacosConnectionManager = nacosConnectionManager;\n        this.isSupportBatchRegister = MethodUtils.findMethod(\n                        NamingService.class, \"batchRegisterInstance\", String.class, String.class, List.class)\n                != null;\n        logger.info(\"Nacos batch register enable: \" + isSupportBatchRegister);\n        this.retryTimes = Math.max(retryTimes, 0);\n        this.sleepMsBetweenRetries = sleepMsBetweenRetries;\n    }\n\n    /**\n     * @deprecated for uts only\n     */\n    @Deprecated\n    protected NacosNamingServiceWrapper(\n            NacosConnectionManager nacosConnectionManager,\n            boolean isSupportBatchRegister,\n            int retryTimes,\n            int sleepMsBetweenRetries) {\n        this.nacosConnectionManager = nacosConnectionManager;\n        this.isSupportBatchRegister = isSupportBatchRegister;\n        this.retryTimes = Math.max(retryTimes, 0);\n        this.sleepMsBetweenRetries = sleepMsBetweenRetries;\n    }\n\n    public String getServerStatus() {\n        return nacosConnectionManager.getNamingService().getServerStatus();\n    }\n\n    public void subscribe(String serviceName, String group, EventListener eventListener) throws NacosException {\n        String nacosServiceName = handleInnerSymbol(serviceName);\n        SubscribeInfo subscribeInfo = new SubscribeInfo(nacosServiceName, group, eventListener);\n        NamingService namingService = ConcurrentHashMapUtils.computeIfAbsent(\n                subscribeStatus, subscribeInfo, info -> nacosConnectionManager.getNamingService());\n        accept(() -> namingService.subscribe(nacosServiceName, group, eventListener));\n    }\n\n    public void unsubscribe(String serviceName, String group, EventListener eventListener) throws NacosException {\n        String nacosServiceName = handleInnerSymbol(serviceName);\n        SubscribeInfo subscribeInfo = new SubscribeInfo(nacosServiceName, group, eventListener);\n        NamingService namingService = subscribeStatus.get(subscribeInfo);\n        if (namingService != null) {\n            accept(() -> namingService.unsubscribe(nacosServiceName, group, eventListener));\n            subscribeStatus.remove(subscribeInfo);\n        }\n    }\n\n    public List<Instance> getAllInstancesWithoutSubscription(String serviceName, String group) throws NacosException {\n        return apply(() -> nacosConnectionManager\n                .getNamingService()\n                .getAllInstances(handleInnerSymbol(serviceName), group, false));\n    }\n\n    public void registerInstance(String serviceName, String group, Instance instance) throws NacosException {\n        String nacosServiceName = handleInnerSymbol(serviceName);\n        InstancesInfo instancesInfo = ConcurrentHashMapUtils.computeIfAbsent(\n                registerStatus, new InstanceId(nacosServiceName, group), id -> new InstancesInfo());\n\n        try {\n            instancesInfo.lock();\n            if (!instancesInfo.isValid()) {\n                registerInstance(serviceName, group, instance);\n                return;\n            }\n            if (instancesInfo.getInstances().isEmpty()) {\n                // directly register\n                NamingService namingService = nacosConnectionManager.getNamingService();\n                accept(() -> namingService.registerInstance(nacosServiceName, group, instance));\n                instancesInfo.getInstances().add(new InstanceInfo(instance, namingService));\n                return;\n            }\n\n            if (instancesInfo.getInstances().size() == 1 && isSupportBatchRegister) {\n                InstanceInfo previous = instancesInfo.getInstances().get(0);\n                List<Instance> instanceListToRegister = new ArrayList<>();\n\n                NamingService namingService = previous.getNamingService();\n                instanceListToRegister.add(previous.getInstance());\n                instanceListToRegister.add(instance);\n\n                try {\n                    accept(() -> namingService.batchRegisterInstance(nacosServiceName, group, instanceListToRegister));\n                    instancesInfo.getInstances().add(new InstanceInfo(instance, namingService));\n                    instancesInfo.setBatchRegistered(true);\n                    return;\n                } catch (NacosException e) {\n                    logger.info(\"Failed to batch register to nacos. Service Name: \" + serviceName\n                            + \". Maybe nacos server not support. Will fallback to multi connection register.\");\n                    // ignore\n                }\n            }\n\n            if (instancesInfo.isBatchRegistered()) {\n                NamingService namingService =\n                        instancesInfo.getInstances().get(0).getNamingService();\n                List<Instance> instanceListToRegister = new ArrayList<>();\n                for (InstanceInfo instanceInfo : instancesInfo.getInstances()) {\n                    instanceListToRegister.add(instanceInfo.getInstance());\n                }\n                instanceListToRegister.add(instance);\n                accept(() -> namingService.batchRegisterInstance(nacosServiceName, group, instanceListToRegister));\n                instancesInfo.getInstances().add(new InstanceInfo(instance, namingService));\n                return;\n            }\n\n            // fallback to register one by one\n            Set<NamingService> selectedNamingServices = instancesInfo.getInstances().stream()\n                    .map(InstanceInfo::getNamingService)\n                    .collect(Collectors.toSet());\n            NamingService namingService = nacosConnectionManager.getNamingService(selectedNamingServices);\n            accept(() -> namingService.registerInstance(nacosServiceName, group, instance));\n            instancesInfo.getInstances().add(new InstanceInfo(instance, namingService));\n        } finally {\n            instancesInfo.unlock();\n        }\n    }\n\n    public void updateInstance(String serviceName, String group, Instance oldInstance, Instance newInstance)\n            throws NacosException {\n        String nacosServiceName = handleInnerSymbol(serviceName);\n        InstancesInfo instancesInfo = ConcurrentHashMapUtils.computeIfAbsent(\n                registerStatus, new InstanceId(nacosServiceName, group), id -> new InstancesInfo());\n\n        try {\n            instancesInfo.lock();\n            if (!instancesInfo.isValid() || instancesInfo.getInstances().isEmpty()) {\n                throw new IllegalArgumentException(serviceName + \" has not been registered to nacos.\");\n            }\n\n            Optional<InstanceInfo> optional = instancesInfo.getInstances().stream()\n                    .filter(instanceInfo -> instanceInfo.getInstance().equals(oldInstance))\n                    .findAny();\n\n            if (!optional.isPresent()) {\n                throw new IllegalArgumentException(oldInstance + \" has not been registered to nacos.\");\n            }\n\n            InstanceInfo oldInstanceInfo = optional.get();\n            instancesInfo.getInstances().remove(oldInstanceInfo);\n            instancesInfo.getInstances().add(new InstanceInfo(newInstance, oldInstanceInfo.getNamingService()));\n\n            if (isSupportBatchRegister && instancesInfo.isBatchRegistered()) {\n                NamingService namingService = oldInstanceInfo.getNamingService();\n                List<Instance> instanceListToRegister = instancesInfo.getInstances().stream()\n                        .map(InstanceInfo::getInstance)\n                        .collect(Collectors.toList());\n\n                accept(() -> namingService.batchRegisterInstance(nacosServiceName, group, instanceListToRegister));\n                return;\n            }\n\n            // fallback to register one by one\n            accept(() -> oldInstanceInfo.getNamingService().registerInstance(nacosServiceName, group, newInstance));\n        } finally {\n            instancesInfo.unlock();\n        }\n    }\n\n    public void deregisterInstance(String serviceName, String group, String ip, int port) throws NacosException {\n        String nacosServiceName = handleInnerSymbol(serviceName);\n        InstancesInfo instancesInfo = ConcurrentHashMapUtils.computeIfAbsent(\n                registerStatus, new InstanceId(nacosServiceName, group), id -> new InstancesInfo());\n\n        try {\n            instancesInfo.lock();\n\n            List<Instance> instances = instancesInfo.getInstances().stream()\n                    .map(InstanceInfo::getInstance)\n                    .filter(instance -> Objects.equals(instance.getIp(), ip) && instance.getPort() == port)\n                    .collect(Collectors.toList());\n            for (Instance instance : instances) {\n                deregisterInstance(serviceName, group, instance);\n            }\n        } finally {\n            instancesInfo.unlock();\n        }\n    }\n\n    public void deregisterInstance(String serviceName, String group, Instance instance) throws NacosException {\n        String nacosServiceName = handleInnerSymbol(serviceName);\n        InstancesInfo instancesInfo = ConcurrentHashMapUtils.computeIfAbsent(\n                registerStatus, new InstanceId(nacosServiceName, group), id -> new InstancesInfo());\n\n        try {\n            instancesInfo.lock();\n            Optional<InstanceInfo> optional = instancesInfo.getInstances().stream()\n                    .filter(instanceInfo -> instanceInfo.getInstance().equals(instance))\n                    .findAny();\n            if (!optional.isPresent()) {\n                return;\n            }\n            InstanceInfo instanceInfo = optional.get();\n            instancesInfo.getInstances().remove(instanceInfo);\n\n            if (instancesInfo.getInstances().isEmpty()) {\n                registerStatus.remove(new InstanceId(nacosServiceName, group));\n                instancesInfo.setValid(false);\n            }\n\n            // only one registered\n            if (instancesInfo.getInstances().isEmpty()) {\n                // directly unregister\n                accept(() -> instanceInfo.getNamingService().deregisterInstance(nacosServiceName, group, instance));\n                instancesInfo.setBatchRegistered(false);\n                return;\n            }\n\n            if (instancesInfo.isBatchRegistered()) {\n                // register the rest instances\n                List<Instance> instanceListToRegister = new ArrayList<>();\n                for (InstanceInfo info : instancesInfo.getInstances()) {\n                    instanceListToRegister.add(info.getInstance());\n                }\n                accept(() -> instanceInfo\n                        .getNamingService()\n                        .batchRegisterInstance(nacosServiceName, group, instanceListToRegister));\n            } else {\n                // unregister one\n                accept(() -> instanceInfo.getNamingService().deregisterInstance(nacosServiceName, group, instance));\n            }\n        } finally {\n            instancesInfo.unlock();\n        }\n    }\n\n    public ListView<String> getServicesOfServer(int pageNo, int pageSize, String group) throws NacosException {\n        return apply(() -> nacosConnectionManager.getNamingService().getServicesOfServer(pageNo, pageSize, group));\n    }\n\n    public List<Instance> selectInstances(String serviceName, String group, boolean healthy) throws NacosException {\n        return apply(() -> nacosConnectionManager\n                .getNamingService()\n                .selectInstances(handleInnerSymbol(serviceName), group, healthy));\n    }\n\n    public void shutdown() throws NacosException {\n        this.nacosConnectionManager.shutdownAll();\n    }\n\n    /**\n     * see https://github.com/apache/dubbo/issues/7129\n     * nacos service name just support `0-9a-zA-Z-._:`, grpc interface is inner interface, need compatible.\n     */\n    private String handleInnerSymbol(String serviceName) {\n        if (StringUtils.isEmpty(serviceName)) {\n            return null;\n        }\n        return serviceName.replace(INNERCLASS_SYMBOL, INNERCLASS_COMPATIBLE_SYMBOL);\n    }\n\n    protected static class InstanceId {\n        private final String serviceName;\n        private final String group;\n\n        public InstanceId(String serviceName, String group) {\n            this.serviceName = serviceName;\n            this.group = group;\n        }\n\n        public String getServiceName() {\n            return serviceName;\n        }\n\n        public String getGroup() {\n            return group;\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            InstanceId that = (InstanceId) o;\n            return Objects.equals(serviceName, that.serviceName) && Objects.equals(group, that.group);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(serviceName, group);\n        }\n    }\n\n    protected static class InstancesInfo {\n        private final Lock lock = new ReentrantLock();\n        private final List<InstanceInfo> instances = new ArrayList<>();\n        private volatile boolean batchRegistered = false;\n        private volatile boolean valid = true;\n\n        public void lock() {\n            lock.lock();\n        }\n\n        public void unlock() {\n            lock.unlock();\n        }\n\n        public List<InstanceInfo> getInstances() {\n            return instances;\n        }\n\n        public boolean isBatchRegistered() {\n            return batchRegistered;\n        }\n\n        public void setBatchRegistered(boolean batchRegistered) {\n            this.batchRegistered = batchRegistered;\n        }\n\n        public boolean isValid() {\n            return valid;\n        }\n\n        public void setValid(boolean valid) {\n            this.valid = valid;\n        }\n    }\n\n    protected static class InstanceInfo {\n        private final Instance instance;\n        private final NamingService namingService;\n\n        public InstanceInfo(Instance instance, NamingService namingService) {\n            this.instance = instance;\n            this.namingService = namingService;\n        }\n\n        public Instance getInstance() {\n            return instance;\n        }\n\n        public NamingService getNamingService() {\n            return namingService;\n        }\n    }\n\n    private static class SubscribeInfo {\n        private final String serviceName;\n        private final String group;\n        private final EventListener eventListener;\n\n        public SubscribeInfo(String serviceName, String group, EventListener eventListener) {\n            this.serviceName = serviceName;\n            this.group = group;\n            this.eventListener = eventListener;\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            SubscribeInfo that = (SubscribeInfo) o;\n            return Objects.equals(serviceName, that.serviceName)\n                    && Objects.equals(group, that.group)\n                    && Objects.equals(eventListener, that.eventListener);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(serviceName, group, eventListener);\n        }\n    }\n\n    /**\n     * @deprecated for uts only\n     */\n    @Deprecated\n    protected Map<InstanceId, InstancesInfo> getRegisterStatus() {\n        return registerStatus;\n    }\n\n    private <R> R apply(NacosFunction<R> command) throws NacosException {\n        NacosException le = null;\n        R result = null;\n        int times = 0;\n        for (; times < retryTimes + 1; times++) {\n            try {\n                result = command.apply();\n                le = null;\n                break;\n            } catch (NacosException e) {\n                le = e;\n                logger.warn(\n                        LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Failed to request nacos naming server. \"\n                                + (times < retryTimes\n                                        ? \"Dubbo will try to retry in \" + sleepMsBetweenRetries + \". \"\n                                        : \"Exceed retry max times.\")\n                                + \"Try times: \"\n                                + (times + 1),\n                        e);\n                if (times < retryTimes) {\n                    try {\n                        Thread.sleep(sleepMsBetweenRetries);\n                    } catch (InterruptedException ex) {\n                        logger.warn(\n                                LoggerCodeConstants.INTERNAL_INTERRUPTED,\n                                \"\",\n                                \"\",\n                                \"Interrupted when waiting to retry.\",\n                                ex);\n                        Thread.currentThread().interrupt();\n                    }\n                }\n            }\n        }\n        if (le != null) {\n            throw le;\n        }\n        if (times > 1) {\n            logger.info(\"Failed to request nacos naming server for \" + (times - 1) + \" times and finally success. \"\n                    + \"This may caused by high stress of nacos server.\");\n        }\n        return result;\n    }\n\n    private void accept(NacosConsumer command) throws NacosException {\n        NacosException le = null;\n        int times = 0;\n        for (; times < retryTimes + 1; times++) {\n            try {\n                command.accept();\n                le = null;\n                break;\n            } catch (NacosException e) {\n                le = e;\n                logger.warn(\n                        LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Failed to request nacos naming server. \"\n                                + (times < retryTimes\n                                        ? \"Dubbo will try to retry in \" + sleepMsBetweenRetries + \". \"\n                                        : \"Exceed retry max times.\")\n                                + \"Try times: \"\n                                + (times + 1),\n                        e);\n                if (times < retryTimes) {\n                    try {\n                        Thread.sleep(sleepMsBetweenRetries);\n                    } catch (InterruptedException ex) {\n                        logger.warn(\n                                LoggerCodeConstants.INTERNAL_INTERRUPTED,\n                                \"\",\n                                \"\",\n                                \"Interrupted when waiting to retry.\",\n                                ex);\n                        Thread.currentThread().interrupt();\n                    }\n                }\n            }\n        }\n        if (le != null) {\n            throw le;\n        }\n        if (times > 1) {\n            logger.info(\"Failed to request nacos naming server for \" + (times - 1) + \" times and finally success. \"\n                    + \"This may caused by high stress of nacos server.\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.URLBuilder;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.url.component.DubboServiceAddressURL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryNotifier;\nimport org.apache.dubbo.registry.support.FailbackRegistry;\nimport org.apache.dubbo.registry.support.SkipFailbackWrapperException;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.nacos.api.common.Constants;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.listener.Event;\nimport com.alibaba.nacos.api.naming.listener.EventListener;\nimport com.alibaba.nacos.api.naming.listener.NamingEvent;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport com.alibaba.nacos.api.naming.pojo.ListView;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;\nimport static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_ENABLE_EMPTY_PROTECTION;\nimport static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.NACOS_REGISTER_COMPATIBLE;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_CONSUMER_URL_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;\nimport static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL;\nimport static org.apache.dubbo.registry.nacos.NacosServiceName.NAME_SEPARATOR;\nimport static org.apache.dubbo.registry.nacos.NacosServiceName.valueOf;\n\n/**\n * Nacos {@link Registry}\n *\n * @see #SERVICE_NAME_SEPARATOR\n * @see #PAGINATION_SIZE\n * @see #LOOKUP_INTERVAL\n * @since 2.6.5\n */\npublic class NacosRegistry extends FailbackRegistry {\n\n    /**\n     * All supported categories\n     */\n    private static final List<String> ALL_SUPPORTED_CATEGORIES =\n            Arrays.asList(PROVIDERS_CATEGORY, CONSUMERS_CATEGORY, ROUTERS_CATEGORY, CONFIGURATORS_CATEGORY);\n\n    private static final int CATEGORY_INDEX = 0;\n\n    private static final int SERVICE_INTERFACE_INDEX = 1;\n\n    private static final int SERVICE_VERSION_INDEX = 2;\n\n    private static final int SERVICE_GROUP_INDEX = 3;\n\n    private static final String WILDCARD = \"*\";\n\n    private static final String UP = \"UP\";\n\n    /**\n     * The separator for service name Change a constant to be configurable, it's designed for Windows file name that is\n     * compatible with old Nacos binary release(< 0.6.1)\n     */\n    private static final String SERVICE_NAME_SEPARATOR = SystemPropertyConfigUtils.getSystemProperty(\n            CommonConstants.ThirdPartyProperty.NACOS_SERVICE_NAME_SEPARATOR, \":\");\n\n    /**\n     * The pagination size of query for Nacos service names(only for Dubbo-OPS)\n     */\n    private static final int PAGINATION_SIZE = Integer.getInteger(\"nacos.service.names.pagination.size\", 100);\n\n    /**\n     * The interval in second of lookup Nacos service names(only for Dubbo-OPS)\n     */\n    private static final long LOOKUP_INTERVAL = Long.getLong(\"nacos.service.names.lookup.interval\", 30);\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(NacosRegistry.class);\n    private final NacosNamingServiceWrapper namingService;\n    /**\n     * {@link ScheduledExecutorService} lookup Nacos service names(only for Dubbo-OPS)\n     */\n    private volatile ScheduledExecutorService scheduledExecutorService;\n\n    private final Map<URL, Map<NotifyListener, NacosAggregateListener>> originToAggregateListener =\n            new ConcurrentHashMap<>();\n\n    private final ConcurrentHashMap<\n                    URL, ConcurrentHashMap<NacosAggregateListener, ConcurrentHashMap<String, EventListener>>>\n            nacosListeners = new ConcurrentHashMap<>();\n    private final boolean supportLegacyServiceName;\n\n    public NacosRegistry(URL url, NacosNamingServiceWrapper namingService) {\n        super(url);\n        this.namingService = namingService;\n        this.supportLegacyServiceName = url.getParameter(\"nacos.subscribe.legacy-name\", false);\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return UP.equals(namingService.getServerStatus());\n    }\n\n    @Override\n    public List<URL> lookup(final URL url) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"lookup url == null\");\n        }\n        try {\n            List<URL> urls = new LinkedList<>();\n            Set<String> serviceNames = getServiceNames(url, null);\n            for (String serviceName : serviceNames) {\n                List<Instance> instances = namingService.getAllInstancesWithoutSubscription(\n                        serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP));\n                urls.addAll(buildURLs(url, instances));\n            }\n            return urls;\n        } catch (SkipFailbackWrapperException exception) {\n            throw exception;\n        } catch (Exception cause) {\n            throw new RpcException(\n                    \"Failed to lookup \" + url + \" from nacos \" + getUrl() + \", cause: \" + cause.getMessage(), cause);\n        }\n    }\n\n    @Override\n    public void doRegister(URL url) {\n        try {\n            if (PROVIDER_SIDE.equals(url.getSide()) || getUrl().getParameter(REGISTER_CONSUMER_URL_KEY, false)) {\n                Instance instance = createInstance(url);\n\n                Set<String> serviceNames = new HashSet<>();\n                // by default servicename is \"org.apache.dubbo.xxService:1.0.0:\"\n                String serviceName = getServiceName(url, false);\n                serviceNames.add(serviceName);\n\n                // in https://github.com/apache/dubbo/issues/14075\n                if (getUrl().getParameter(NACOS_REGISTER_COMPATIBLE, false)) {\n                    // servicename is \"org.apache.dubbo.xxService:1.0.0\"\n                    String compatibleServiceName = getServiceName(url, true);\n                    serviceNames.add(compatibleServiceName);\n                }\n\n                /**\n                 *  namingService.registerInstance with\n                 *  {@link org.apache.dubbo.registry.support.AbstractRegistry#registryUrl}\n                 *  default {@link DEFAULT_GROUP}\n                 *\n                 * in https://github.com/apache/dubbo/issues/5978\n                 */\n                for (String service : serviceNames) {\n                    namingService.registerInstance(service, getUrl().getGroup(Constants.DEFAULT_GROUP), instance);\n                }\n            } else {\n                logger.info(\"Please set 'dubbo.registry.parameters.register-consumer-url=true' to turn on consumer \"\n                        + \"url registration.\");\n            }\n        } catch (SkipFailbackWrapperException exception) {\n            throw exception;\n        } catch (Exception cause) {\n            throw new RpcException(\n                    \"Failed to register \" + url + \" to nacos \" + getUrl() + \", cause: \" + cause.getMessage(), cause);\n        }\n    }\n\n    @Override\n    public void doUnregister(final URL url) {\n        try {\n            Instance instance = createInstance(url);\n\n            Set<String> serviceNames = new HashSet<>();\n            // by default servicename is \"org.apache.dubbo.xxService:1.0.0:\"\n            String serviceName = getServiceName(url, false);\n            serviceNames.add(serviceName);\n\n            // in https://github.com/apache/dubbo/issues/14075\n            if (getUrl().getParameter(NACOS_REGISTER_COMPATIBLE, false)) {\n                // servicename is \"org.apache.dubbo.xxService:1.0.0\"\n                String serviceName1 = getServiceName(url, true);\n                serviceNames.add(serviceName1);\n            }\n\n            for (String service : serviceNames) {\n                namingService.deregisterInstance(\n                        service, getUrl().getGroup(Constants.DEFAULT_GROUP), instance.getIp(), instance.getPort());\n            }\n        } catch (SkipFailbackWrapperException exception) {\n            throw exception;\n        } catch (Exception cause) {\n            throw new RpcException(\n                    \"Failed to unregister \" + url + \" to nacos \" + getUrl() + \", cause: \" + cause.getMessage(), cause);\n        }\n    }\n\n    @Override\n    public void doSubscribe(final URL url, final NotifyListener listener) {\n        NacosAggregateListener nacosAggregateListener = new NacosAggregateListener(listener);\n        originToAggregateListener\n                .computeIfAbsent(url, k -> new ConcurrentHashMap<>())\n                .put(listener, nacosAggregateListener);\n\n        Set<String> serviceNames = getServiceNames(url, nacosAggregateListener);\n\n        doSubscribe(url, nacosAggregateListener, serviceNames);\n    }\n\n    private void doSubscribe(final URL url, final NacosAggregateListener listener, final Set<String> serviceNames) {\n        try {\n            if (isServiceNamesWithCompatibleMode(url)) {\n\n                /**\n                 * Get all instances with serviceNames to avoid instance overwrite and but with empty instance mentioned\n                 * in https://github.com/apache/dubbo/issues/5885 and https://github.com/apache/dubbo/issues/5899\n                 *\n                 * namingService.getAllInstances with\n                 * {@link org.apache.dubbo.registry.support.AbstractRegistry#registryUrl}\n                 * default {@link DEFAULT_GROUP}\n                 *\n                 * in https://github.com/apache/dubbo/issues/5978\n                 */\n                for (String serviceName : serviceNames) {\n                    List<Instance> instances = namingService.getAllInstancesWithoutSubscription(\n                            serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP));\n                    notifySubscriber(url, serviceName, listener, instances);\n                }\n                for (String serviceName : serviceNames) {\n                    subscribeEventListener(serviceName, url, listener);\n                }\n            } else {\n                for (String serviceName : serviceNames) {\n                    List<Instance> instances = new LinkedList<>();\n                    instances.addAll(namingService.getAllInstancesWithoutSubscription(\n                            serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP)));\n                    String serviceInterface = serviceName;\n                    String[] segments = serviceName.split(SERVICE_NAME_SEPARATOR, -1);\n                    if (segments.length == 4) {\n                        serviceInterface = segments[SERVICE_INTERFACE_INDEX];\n                    }\n                    URL subscriberURL = url.setPath(serviceInterface)\n                            .addParameters(\n                                    INTERFACE_KEY,\n                                    serviceInterface,\n                                    CommonConstants.APPLICATION_KEY,\n                                    url.getApplication(),\n                                    CHECK_KEY,\n                                    String.valueOf(false));\n                    notifySubscriber(subscriberURL, serviceName, listener, instances);\n                    subscribeEventListener(serviceName, subscriberURL, listener);\n                }\n            }\n        } catch (SkipFailbackWrapperException exception) {\n            throw exception;\n        } catch (Throwable cause) {\n            throw new RpcException(\n                    \"Failed to subscribe \" + url + \" to nacos \" + getUrl() + \", cause: \" + cause.getMessage(), cause);\n        }\n    }\n\n    /**\n     * Since 2.7.6 the legacy service name will be added to serviceNames to fix bug with\n     * https://github.com/apache/dubbo/issues/5442\n     *\n     * @param url\n     * @return\n     */\n    private boolean isServiceNamesWithCompatibleMode(final URL url) {\n        return !isAdminProtocol(url) && createServiceName(url).isConcrete();\n    }\n\n    @Override\n    public void doUnsubscribe(URL url, NotifyListener listener) {\n        if (isAdminProtocol(url)) {\n            shutdownServiceNamesLookup();\n        } else {\n            Map<NotifyListener, NacosAggregateListener> listenerMap = originToAggregateListener.get(url);\n            if (listenerMap == null) {\n                logger.warn(\n                        REGISTRY_NACOS_EXCEPTION,\n                        \"\",\n                        \"\",\n                        String.format(\n                                \"No aggregate listener found for url %s, \"\n                                        + \"this service might have already been unsubscribed.\",\n                                url));\n                return;\n            }\n            NacosAggregateListener nacosAggregateListener = listenerMap.remove(listener);\n            if (nacosAggregateListener != null) {\n                Set<String> serviceNames = nacosAggregateListener.getServiceNames();\n                try {\n                    doUnsubscribe(url, nacosAggregateListener, serviceNames);\n                } catch (NacosException e) {\n                    logger.error(\n                            REGISTRY_NACOS_EXCEPTION,\n                            \"\",\n                            \"\",\n                            \"Failed to unsubscribe \" + url + \" to nacos \" + getUrl() + \", cause: \" + e.getMessage(),\n                            e);\n                }\n            }\n            if (listenerMap.isEmpty()) {\n                originToAggregateListener.remove(url);\n            }\n        }\n    }\n\n    private void doUnsubscribe(\n            final URL url, final NacosAggregateListener nacosAggregateListener, final Set<String> serviceNames)\n            throws NacosException {\n        for (String serviceName : serviceNames) {\n            unsubscribeEventListener(serviceName, url, nacosAggregateListener);\n        }\n    }\n\n    private void shutdownServiceNamesLookup() {\n        if (scheduledExecutorService != null) {\n            scheduledExecutorService.shutdown();\n        }\n    }\n\n    /**\n     * Get the service names from the specified {@link URL url}\n     *\n     * @param url      {@link URL}\n     * @param listener {@link NotifyListener}\n     * @return non-null\n     */\n    private Set<String> getServiceNames(URL url, NacosAggregateListener listener) {\n        if (isAdminProtocol(url)) {\n            scheduleServiceNamesLookup(url, listener);\n            return getServiceNamesForOps(url);\n        } else {\n            return getServiceNames0(url);\n        }\n    }\n\n    private Set<String> getServiceNames0(URL url) {\n        NacosServiceName serviceName = createServiceName(url);\n\n        final Set<String> serviceNames;\n\n        if (serviceName.isConcrete()) { // is the concrete service name\n            serviceNames = new LinkedHashSet<>();\n            serviceNames.add(serviceName.toString());\n            if (supportLegacyServiceName) {\n                // Add the legacy service name since 2.7.6\n                String legacySubscribedServiceName = getLegacySubscribedServiceName(url);\n                if (!serviceName.toString().equals(legacySubscribedServiceName)) {\n                    // avoid duplicated service names\n                    serviceNames.add(legacySubscribedServiceName);\n                }\n            }\n        } else {\n            serviceNames = filterServiceNames(serviceName);\n        }\n\n        return serviceNames;\n    }\n\n    private Set<String> filterServiceNames(NacosServiceName serviceName) {\n        try {\n            Set<String> serviceNames = new LinkedHashSet<>();\n            serviceNames.addAll(\n                    namingService\n                            .getServicesOfServer(1, Integer.MAX_VALUE, getUrl().getGroup(Constants.DEFAULT_GROUP))\n                            .getData()\n                            .stream()\n                            .filter(this::isConformRules)\n                            .map(NacosServiceName::new)\n                            .filter(serviceName::isCompatible)\n                            .map(NacosServiceName::toString)\n                            .collect(Collectors.toList()));\n            return serviceNames;\n        } catch (SkipFailbackWrapperException exception) {\n            throw exception;\n        } catch (Throwable cause) {\n            throw new RpcException(\n                    \"Failed to filter serviceName from nacos, url: \" + getUrl() + \", serviceName: \" + serviceName\n                            + \", cause: \" + cause.getMessage(),\n                    cause);\n        }\n    }\n\n    /**\n     * Verify whether it is a dubbo service\n     *\n     * @param serviceName\n     * @return\n     * @since 2.7.12\n     */\n    private boolean isConformRules(String serviceName) {\n        return serviceName.split(NAME_SEPARATOR, -1).length == 4;\n    }\n\n    /**\n     * Get the legacy subscribed service name for compatible with Dubbo 2.7.3 and below\n     *\n     * @param url {@link URL}\n     * @return non-null\n     * @since 2.7.6\n     */\n    private String getLegacySubscribedServiceName(URL url) {\n        StringBuilder serviceNameBuilder = new StringBuilder(DEFAULT_CATEGORY);\n        appendIfPresent(serviceNameBuilder, url, INTERFACE_KEY);\n        appendIfPresent(serviceNameBuilder, url, VERSION_KEY);\n        appendIfPresent(serviceNameBuilder, url, GROUP_KEY);\n        return serviceNameBuilder.toString();\n    }\n\n    private void appendIfPresent(StringBuilder target, URL url, String parameterName) {\n        String parameterValue = url.getParameter(parameterName);\n        if (!StringUtils.isBlank(parameterValue)) {\n            target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);\n        }\n    }\n\n    private boolean isAdminProtocol(URL url) {\n        return ADMIN_PROTOCOL.equals(url.getProtocol());\n    }\n\n    private void scheduleServiceNamesLookup(final URL url, final NacosAggregateListener listener) {\n        if (scheduledExecutorService == null) {\n            scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();\n            scheduledExecutorService.scheduleAtFixedRate(\n                    () -> {\n                        Set<String> serviceNames = getAllServiceNames();\n                        filterData(serviceNames, serviceName -> {\n                            boolean accepted = false;\n                            for (String category : ALL_SUPPORTED_CATEGORIES) {\n                                String prefix = category + SERVICE_NAME_SEPARATOR;\n                                if (serviceName != null && serviceName.startsWith(prefix)) {\n                                    accepted = true;\n                                    break;\n                                }\n                            }\n                            return accepted;\n                        });\n                        doSubscribe(url, listener, serviceNames);\n                    },\n                    LOOKUP_INTERVAL,\n                    LOOKUP_INTERVAL,\n                    TimeUnit.SECONDS);\n        }\n    }\n\n    /**\n     * Get the service names for Dubbo OPS\n     *\n     * @param url {@link URL}\n     * @return non-null\n     */\n    private Set<String> getServiceNamesForOps(URL url) {\n        Set<String> serviceNames = getAllServiceNames();\n        filterServiceNames(serviceNames, url);\n        return serviceNames;\n    }\n\n    private Set<String> getAllServiceNames() {\n        try {\n            final Set<String> serviceNames = new LinkedHashSet<>();\n            int pageIndex = 1;\n            ListView<String> listView = namingService.getServicesOfServer(\n                    pageIndex, PAGINATION_SIZE, getUrl().getGroup(Constants.DEFAULT_GROUP));\n            // First page data\n            List<String> firstPageData = listView.getData();\n            // Append first page into list\n            serviceNames.addAll(firstPageData);\n            // the total count\n            int count = listView.getCount();\n            // the number of pages\n            int pageNumbers = count / PAGINATION_SIZE;\n            int remainder = count % PAGINATION_SIZE;\n            // remain\n            if (remainder > 0) {\n                pageNumbers += 1;\n            }\n            // If more than 1 page\n            while (pageIndex < pageNumbers) {\n                listView = namingService.getServicesOfServer(\n                        ++pageIndex, PAGINATION_SIZE, getUrl().getGroup(Constants.DEFAULT_GROUP));\n                serviceNames.addAll(listView.getData());\n            }\n            return serviceNames;\n        } catch (SkipFailbackWrapperException exception) {\n            throw exception;\n        } catch (Throwable cause) {\n            throw new RpcException(\n                    \"Failed to get all serviceName from nacos, url: \" + getUrl() + \", cause: \" + cause.getMessage(),\n                    cause);\n        }\n    }\n\n    private void filterServiceNames(Set<String> serviceNames, URL url) {\n\n        final List<String> categories = getCategories(url);\n\n        final String targetServiceInterface = url.getServiceInterface();\n\n        final String targetVersion = url.getVersion(\"\");\n\n        final String targetGroup = url.getGroup(\"\");\n\n        filterData(serviceNames, serviceName -> {\n            // split service name to segments\n            // (required) segments[0] = category\n            // (required) segments[1] = serviceInterface\n            // (optional) segments[2] = version\n            // (optional) segments[3] = group\n            String[] segments = serviceName.split(SERVICE_NAME_SEPARATOR, -1);\n            int length = segments.length;\n            if (length != 4) { // must present 4 segments\n                return false;\n            }\n\n            String category = segments[CATEGORY_INDEX];\n            if (!categories.contains(category)) { // no match category\n                return false;\n            }\n\n            String serviceInterface = segments[SERVICE_INTERFACE_INDEX];\n            // no match service interface\n            if (!WILDCARD.equals(targetServiceInterface)\n                    && !StringUtils.isEquals(targetServiceInterface, serviceInterface)) {\n                return false;\n            }\n\n            // no match service version\n            String version = segments[SERVICE_VERSION_INDEX];\n            if (!WILDCARD.equals(targetVersion) && !StringUtils.isEquals(targetVersion, version)) {\n                return false;\n            }\n\n            String group = segments[SERVICE_GROUP_INDEX];\n            return group == null || WILDCARD.equals(targetGroup) || StringUtils.isEquals(targetGroup, group);\n        });\n    }\n\n    private <T> void filterData(Collection<T> collection, NacosDataFilter<T> filter) {\n        // remove if not accept\n        collection.removeIf(data -> !filter.accept(data));\n    }\n\n    @Deprecated\n    private List<String> doGetServiceNames(URL url) {\n        List<String> categories = getCategories(url);\n        List<String> serviceNames = new ArrayList<>(categories.size());\n        for (String category : categories) {\n            final String serviceName = getServiceName(url, category);\n            serviceNames.add(serviceName);\n        }\n        return serviceNames;\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n        try {\n            this.namingService.shutdown();\n        } catch (NacosException e) {\n            logger.warn(REGISTRY_NACOS_EXCEPTION, \"\", \"\", \"Unable to shutdown nacos naming service\", e);\n        }\n        this.nacosListeners.clear();\n    }\n\n    private List<URL> toUrlWithEmpty(URL consumerURL, Collection<Instance> instances) {\n        consumerURL = removeParamsFromConsumer(consumerURL);\n        List<URL> urls = buildURLs(consumerURL, instances);\n        // Nacos does not support configurators and routers from registry, so all notifications are of providers type.\n        if (urls.size() == 0 && !getUrl().getParameter(ENABLE_EMPTY_PROTECTION_KEY, DEFAULT_ENABLE_EMPTY_PROTECTION)) {\n            logger.warn(\n                    REGISTRY_NACOS_EXCEPTION,\n                    \"\",\n                    \"\",\n                    \"Received empty url address list and empty protection is \"\n                            + \"disabled, will clear current available addresses\");\n            URL empty = URLBuilder.from(consumerURL)\n                    .setProtocol(EMPTY_PROTOCOL)\n                    .addParameter(CATEGORY_KEY, DEFAULT_CATEGORY)\n                    .build();\n            urls.add(empty);\n        }\n        return urls;\n    }\n\n    private List<URL> buildURLs(URL consumerURL, Collection<Instance> instances) {\n        List<URL> urls = new LinkedList<>();\n        if (instances != null && !instances.isEmpty()) {\n            for (Instance instance : instances) {\n                URL url = buildURL(consumerURL, instance);\n                if (UrlUtils.isMatch(consumerURL, url)) {\n                    urls.add(url);\n                }\n            }\n        }\n        return urls;\n    }\n\n    private void subscribeEventListener(String serviceName, final URL url, final NacosAggregateListener listener)\n            throws NacosException {\n        ConcurrentHashMap<NacosAggregateListener, ConcurrentHashMap<String, EventListener>> listeners =\n                ConcurrentHashMapUtils.computeIfAbsent(nacosListeners, url, k -> new ConcurrentHashMap<>());\n\n        ConcurrentHashMap<String, EventListener> eventListeners =\n                ConcurrentHashMapUtils.computeIfAbsent(listeners, listener, k -> new ConcurrentHashMap<>());\n\n        EventListener eventListener = ConcurrentHashMapUtils.computeIfAbsent(\n                eventListeners, serviceName, k -> new RegistryChildListenerImpl(serviceName, url, listener));\n\n        namingService.subscribe(serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP), eventListener);\n    }\n\n    private void unsubscribeEventListener(String serviceName, final URL url, final NacosAggregateListener listener)\n            throws NacosException {\n        ConcurrentHashMap<NacosAggregateListener, ConcurrentHashMap<String, EventListener>> listenerToServiceEvent =\n                nacosListeners.get(url);\n        if (listenerToServiceEvent == null) {\n            return;\n        }\n        Map<String, EventListener> serviceToEventMap = listenerToServiceEvent.get(listener);\n        if (serviceToEventMap == null) {\n            return;\n        }\n        EventListener eventListener = serviceToEventMap.remove(serviceName);\n        if (eventListener == null) {\n            return;\n        }\n        namingService.unsubscribe(\n                serviceName, getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP), eventListener);\n        if (serviceToEventMap.isEmpty()) {\n            listenerToServiceEvent.remove(listener);\n        }\n        if (listenerToServiceEvent.isEmpty()) {\n            nacosListeners.remove(url);\n        }\n    }\n\n    /**\n     * Notify the Enabled {@link Instance instances} to subscriber.\n     *\n     * @param url       {@link URL}\n     * @param listener  {@link NotifyListener}\n     * @param instances all {@link Instance instances}\n     */\n    private void notifySubscriber(\n            URL url, String serviceName, NacosAggregateListener listener, Collection<Instance> instances) {\n        List<Instance> enabledInstances = new LinkedList<>(instances);\n        if (enabledInstances.size() > 0) {\n            //  Instances\n            filterEnabledInstances(enabledInstances);\n        }\n        List<URL> aggregatedUrls =\n                toUrlWithEmpty(url, listener.saveAndAggregateAllInstances(serviceName, enabledInstances));\n        NacosRegistry.this.notify(url, listener.getNotifyListener(), aggregatedUrls);\n    }\n\n    /**\n     * Get the categories from {@link URL}\n     *\n     * @param url {@link URL}\n     * @return non-null array\n     */\n    private List<String> getCategories(URL url) {\n        return ANY_VALUE.equals(url.getServiceInterface()) ? ALL_SUPPORTED_CATEGORIES : Arrays.asList(DEFAULT_CATEGORY);\n    }\n\n    private URL buildURL(URL consumerURL, Instance instance) {\n        Map<String, String> metadata = instance.getMetadata();\n        String protocol = metadata.get(PROTOCOL_KEY);\n        String path = metadata.get(PATH_KEY);\n        URL url = new ServiceConfigURL(protocol, instance.getIp(), instance.getPort(), path, instance.getMetadata());\n        return new DubboServiceAddressURL(url.getUrlAddress(), url.getUrlParam(), consumerURL, null);\n    }\n\n    private Instance createInstance(URL url) {\n        // Append default category if absent\n        String category = url.getCategory(DEFAULT_CATEGORY);\n        URL newURL = url.addParameter(CATEGORY_KEY, category);\n        newURL = newURL.addParameter(PROTOCOL_KEY, url.getProtocol());\n        newURL = newURL.addParameter(PATH_KEY, url.getPath());\n        String ip = url.getHost();\n        int port = url.getPort();\n        Instance instance = new Instance();\n        instance.setIp(ip);\n        instance.setPort(port);\n        instance.setMetadata(new HashMap<>(newURL.getParameters()));\n        return instance;\n    }\n\n    private NacosServiceName createServiceName(URL url) {\n        return valueOf(url);\n    }\n\n    private String getServiceName(URL url, boolean needCompatible) {\n        if (needCompatible) {\n            return getCompatibleServiceName(url, url.getCategory(DEFAULT_CATEGORY));\n        }\n        return getServiceName(url, url.getCategory(DEFAULT_CATEGORY));\n    }\n\n    private String getServiceName(URL url, String category) {\n        return category + SERVICE_NAME_SEPARATOR + url.getColonSeparatedKey();\n    }\n\n    private String getCompatibleServiceName(URL url, String category) {\n        return category + SERVICE_NAME_SEPARATOR + url.getCompatibleColonSeparatedKey();\n    }\n\n    private void filterEnabledInstances(Collection<Instance> instances) {\n        filterData(instances, Instance::isEnabled);\n    }\n\n    /**\n     * A filter for Nacos data\n     *\n     * @since 2.6.5\n     */\n    private interface NacosDataFilter<T> {\n\n        /**\n         * Tests whether or not the specified data should be accepted.\n         *\n         * @param data The data to be tested\n         * @return <code>true</code> if and only if <code>data</code>\n         * should be accepted\n         */\n        boolean accept(T data);\n    }\n\n    private class RegistryChildListenerImpl implements EventListener {\n        private final RegistryNotifier notifier;\n\n        private final String serviceName;\n\n        private final URL consumerUrl;\n\n        private final NacosAggregateListener listener;\n\n        public RegistryChildListenerImpl(String serviceName, URL consumerUrl, NacosAggregateListener listener) {\n            this.serviceName = serviceName;\n            this.consumerUrl = consumerUrl;\n            this.listener = listener;\n            this.notifier = new RegistryNotifier(getUrl(), NacosRegistry.this.getDelay()) {\n                @Override\n                protected void doNotify(Object rawAddresses) {\n                    List<Instance> instances = (List<Instance>) rawAddresses;\n                    NacosRegistry.this.notifySubscriber(consumerUrl, serviceName, listener, instances);\n                }\n            };\n        }\n\n        @Override\n        public void onEvent(Event event) {\n            if (event instanceof NamingEvent) {\n                NamingEvent e = (NamingEvent) event;\n                notifier.notify(e.getInstances());\n            }\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            RegistryChildListenerImpl that = (RegistryChildListenerImpl) o;\n            return Objects.equals(serviceName, that.serviceName)\n                    && Objects.equals(consumerUrl, that.consumerUrl)\n                    && Objects.equals(listener, that.listener);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(serviceName, consumerUrl, listener);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.RegistryFactory;\nimport org.apache.dubbo.registry.support.AbstractRegistryFactory;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONFIG_NAMESPACE_KEY;\nimport static org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils.createNamingService;\n\n/**\n * Nacos {@link RegistryFactory}\n *\n * @since 2.6.5\n */\npublic class NacosRegistryFactory extends AbstractRegistryFactory {\n\n    @Override\n    protected String createRegistryCacheKey(URL url) {\n        String namespace = url.getParameter(CONFIG_NAMESPACE_KEY);\n        url = URL.valueOf(url.toServiceStringWithoutResolving());\n        if (StringUtils.isNotEmpty(namespace)) {\n            url = url.addParameter(CONFIG_NAMESPACE_KEY, namespace);\n        }\n\n        return url.toFullString();\n    }\n\n    @Override\n    protected Registry createRegistry(URL url) {\n        return new NacosRegistry(url, createNamingService(url));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.function.ThrowableFunction;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collectors;\n\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.listener.Event;\nimport com.alibaba.nacos.api.naming.listener.EventListener;\nimport com.alibaba.nacos.api.naming.listener.NamingEvent;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport com.alibaba.nacos.api.naming.pojo.ListView;\n\nimport static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_NACOS_EXCEPTION;\nimport static org.apache.dubbo.common.function.ThrowableConsumer.execute;\nimport static org.apache.dubbo.metadata.RevisionResolver.EMPTY_REVISION;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getExportedServicesRevision;\nimport static org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils.createNamingService;\nimport static org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils.getGroup;\nimport static org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils.toInstance;\nimport static org.apache.dubbo.rpc.RpcException.REGISTRY_EXCEPTION;\n\n/**\n * Nacos {@link ServiceDiscovery} implementation\n *\n * @see ServiceDiscovery\n * @since 2.7.5\n */\npublic class NacosServiceDiscovery extends AbstractServiceDiscovery {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private final String group;\n\n    private final NacosNamingServiceWrapper namingService;\n\n    private static final String NACOS_SD_USE_DEFAULT_GROUP_KEY = \"dubbo.nacos-service-discovery.use-default-group\";\n\n    private final ConcurrentHashMap<String, NacosEventListener> eventListeners = new ConcurrentHashMap<>();\n\n    public NacosServiceDiscovery(ApplicationModel applicationModel, URL registryURL) {\n        super(applicationModel, registryURL);\n        this.namingService = createNamingService(registryURL);\n        // backward compatibility for 3.0.x\n        this.group = Boolean.parseBoolean(\n                        ConfigurationUtils.getProperty(applicationModel, NACOS_SD_USE_DEFAULT_GROUP_KEY, \"false\"))\n                ? DEFAULT_GROUP\n                : getGroup(registryURL);\n    }\n\n    @Override\n    public void doDestroy() throws Exception {\n        this.namingService.shutdown();\n        this.eventListeners.clear();\n    }\n\n    @Override\n    public void doRegister(ServiceInstance serviceInstance) {\n        execute(namingService, service -> {\n            Instance instance = toInstance(serviceInstance);\n            service.registerInstance(instance.getServiceName(), group, instance);\n        });\n    }\n\n    @Override\n    public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException {\n        execute(namingService, service -> {\n            Instance instance = toInstance(serviceInstance);\n            service.deregisterInstance(instance.getServiceName(), group, instance);\n        });\n    }\n\n    @Override\n    protected void doUpdate(ServiceInstance oldServiceInstance, ServiceInstance newServiceInstance)\n            throws RuntimeException {\n        if (EMPTY_REVISION.equals(getExportedServicesRevision(newServiceInstance))\n                || EMPTY_REVISION.equals(\n                        oldServiceInstance.getMetadata().get(EXPORTED_SERVICES_REVISION_PROPERTY_NAME))) {\n            super.doUpdate(oldServiceInstance, newServiceInstance);\n            return;\n        }\n\n        if (!Objects.equals(newServiceInstance.getHost(), oldServiceInstance.getHost())\n                || !Objects.equals(newServiceInstance.getPort(), oldServiceInstance.getPort())) {\n            // Ignore if id changed. Should unregister first.\n            super.doUpdate(oldServiceInstance, newServiceInstance);\n            return;\n        }\n\n        Instance oldInstance = toInstance(oldServiceInstance);\n        Instance newInstance = toInstance(newServiceInstance);\n\n        try {\n            this.serviceInstance = newServiceInstance;\n            reportMetadata(newServiceInstance.getServiceMetadata());\n            execute(namingService, service -> {\n                Instance instance = toInstance(serviceInstance);\n                service.updateInstance(instance.getServiceName(), group, oldInstance, newInstance);\n            });\n        } catch (Exception e) {\n            throw new RpcException(REGISTRY_EXCEPTION, \"Failed register instance \" + newServiceInstance.toString(), e);\n        }\n    }\n\n    @Override\n    public Set<String> getServices() {\n        return ThrowableFunction.execute(namingService, service -> {\n            ListView<String> view = service.getServicesOfServer(0, Integer.MAX_VALUE, group);\n            return new LinkedHashSet<>(view.getData());\n        });\n    }\n\n    @Override\n    public List<ServiceInstance> getInstances(String serviceName) throws NullPointerException {\n        return ThrowableFunction.execute(\n                namingService, service -> service.selectInstances(serviceName, group, true).stream()\n                        .map((i) -> NacosNamingServiceUtils.toServiceInstance(registryURL, i))\n                        .collect(Collectors.toList()));\n    }\n\n    @Override\n    public void addServiceInstancesChangedListener(ServiceInstancesChangedListener listener)\n            throws NullPointerException, IllegalArgumentException {\n        // check if listener has already been added through another interface/service\n        if (!instanceListeners.add(listener)) {\n            return;\n        }\n        for (String serviceName : listener.getServiceNames()) {\n            NacosEventListener nacosEventListener = eventListeners.get(serviceName);\n            if (nacosEventListener != null) {\n                nacosEventListener.addListener(listener);\n            } else {\n                try {\n                    nacosEventListener = new NacosEventListener();\n                    nacosEventListener.addListener(listener);\n                    namingService.subscribe(serviceName, group, nacosEventListener);\n                    eventListeners.put(serviceName, nacosEventListener);\n                } catch (NacosException e) {\n                    logger.error(\n                            REGISTRY_NACOS_EXCEPTION, \"\", \"\", \"add nacos service instances changed listener fail \", e);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void removeServiceInstancesChangedListener(ServiceInstancesChangedListener listener)\n            throws IllegalArgumentException {\n        if (!instanceListeners.remove(listener)) {\n            return;\n        }\n        for (String serviceName : listener.getServiceNames()) {\n            NacosEventListener nacosEventListener = eventListeners.get(serviceName);\n            if (nacosEventListener != null) {\n                nacosEventListener.removeListener(listener);\n                if (nacosEventListener.isEmpty()) {\n                    eventListeners.remove(serviceName);\n                    try {\n                        namingService.unsubscribe(serviceName, group, nacosEventListener);\n                    } catch (NacosException e) {\n                        logger.error(\n                                REGISTRY_NACOS_EXCEPTION,\n                                \"\",\n                                \"\",\n                                \"remove nacos service instances changed listener fail \",\n                                e);\n                    }\n                }\n            }\n        }\n    }\n\n    public class NacosEventListener implements EventListener {\n        private final Set<ServiceInstancesChangedListener> listeners = new ConcurrentHashSet<>();\n\n        @Override\n        public void onEvent(Event e) {\n            if (e instanceof NamingEvent) {\n                for (ServiceInstancesChangedListener listener : listeners) {\n                    NamingEvent event = (NamingEvent) e;\n                    handleEvent(event, listener);\n                }\n            }\n        }\n\n        public void addListener(ServiceInstancesChangedListener listener) {\n            listeners.add(listener);\n        }\n\n        public void removeListener(ServiceInstancesChangedListener listener) {\n            listeners.remove(listener);\n        }\n\n        public boolean isEmpty() {\n            return listeners.isEmpty();\n        }\n    }\n\n    @Override\n    public URL getUrl() {\n        return registryURL;\n    }\n\n    private void handleEvent(NamingEvent event, ServiceInstancesChangedListener listener) {\n        String serviceName = event.getServiceName();\n        List<ServiceInstance> serviceInstances = event.getInstances().stream()\n                .map((i) -> NacosNamingServiceUtils.toServiceInstance(registryURL, i))\n                .collect(Collectors.toList());\n        listener.onEvent(new ServiceInstancesChangedEvent(serviceName, serviceInstances));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscoveryFactory;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CONFIG_NAMESPACE_KEY;\n\npublic class NacosServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory {\n\n    @Override\n    protected String createRegistryCacheKey(URL url) {\n        String namespace = url.getParameter(CONFIG_NAMESPACE_KEY);\n        url = URL.valueOf(url.toServiceStringWithoutResolving());\n        if (StringUtils.isNotEmpty(namespace)) {\n            url = url.addParameter(CONFIG_NAMESPACE_KEY, namespace);\n        }\n\n        return url.toFullString();\n    }\n\n    @Override\n    protected ServiceDiscovery createDiscovery(URL registryURL) {\n        return new NacosServiceDiscovery(applicationModel, registryURL);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceName.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;\nimport static org.apache.dubbo.common.utils.StringUtils.isBlank;\n\n/**\n * The service name of Nacos\n *\n * @since 2.7.3\n */\npublic class NacosServiceName {\n\n    public static final String NAME_SEPARATOR = \":\";\n\n    public static final String VALUE_SEPARATOR = \",\";\n\n    public static final String WILDCARD = \"*\";\n\n    public static final String DEFAULT_PARAM_VALUE = \"\";\n\n    private static final int CATEGORY_INDEX = 0;\n\n    private static final int SERVICE_INTERFACE_INDEX = 1;\n\n    private static final int SERVICE_VERSION_INDEX = 2;\n\n    private static final int SERVICE_GROUP_INDEX = 3;\n\n    private String category;\n\n    private String serviceInterface;\n\n    private String version;\n\n    private String group;\n\n    private String value;\n\n    public NacosServiceName() {}\n\n    public NacosServiceName(URL url) {\n        serviceInterface = url.getParameter(INTERFACE_KEY);\n        category = isConcrete(serviceInterface) ? DEFAULT_CATEGORY : url.getCategory();\n        version = url.getVersion(DEFAULT_PARAM_VALUE);\n        group = url.getGroup(DEFAULT_PARAM_VALUE);\n        value = toValue();\n    }\n\n    public NacosServiceName(String value) {\n        this.value = value;\n        String[] segments = value.split(NAME_SEPARATOR, -1);\n        this.category = segments[CATEGORY_INDEX];\n        this.serviceInterface = segments[SERVICE_INTERFACE_INDEX];\n        this.version = segments[SERVICE_VERSION_INDEX];\n        this.group = segments[SERVICE_GROUP_INDEX];\n    }\n\n    /**\n     * Build an instance of {@link NacosServiceName}\n     *\n     * @param url\n     * @return\n     */\n    public static NacosServiceName valueOf(URL url) {\n        return new NacosServiceName(url);\n    }\n\n    /**\n     * Is the concrete service name or not\n     *\n     * @return if concrete , return <code>true</code>, or <code>false</code>\n     */\n    public boolean isConcrete() {\n        return isConcrete(serviceInterface) && isConcrete(version) && isConcrete(group);\n    }\n\n    public boolean isCompatible(NacosServiceName concreteServiceName) {\n\n        if (!concreteServiceName.isConcrete()) { // The argument must be the concrete NacosServiceName\n            return false;\n        }\n\n        // Not match comparison\n        if (!StringUtils.isEquals(this.category, concreteServiceName.category)\n                && !matchRange(this.category, concreteServiceName.category)) {\n            return false;\n        }\n\n        if (!StringUtils.isEquals(this.serviceInterface, concreteServiceName.serviceInterface)) {\n            return false;\n        }\n\n        // wildcard condition\n        if (isWildcard(this.version)) {\n            return true;\n        }\n\n        if (isWildcard(this.group)) {\n            return true;\n        }\n\n        // range condition\n        if (!StringUtils.isEquals(this.version, concreteServiceName.version)\n                && !matchRange(this.version, concreteServiceName.version)) {\n            return false;\n        }\n\n        if (!StringUtils.isEquals(this.group, concreteServiceName.group)\n                && !matchRange(this.group, concreteServiceName.group)) {\n            return false;\n        }\n\n        return true;\n    }\n\n    private boolean matchRange(String range, String value) {\n        if (isBlank(range)) {\n            return true;\n        }\n        if (!isRange(range)) {\n            return false;\n        }\n        String[] values = range.split(VALUE_SEPARATOR);\n        return Arrays.asList(values).contains(value);\n    }\n\n    private boolean isConcrete(String value) {\n        return !isWildcard(value) && !isRange(value);\n    }\n\n    private boolean isWildcard(String value) {\n        return WILDCARD.equals(value);\n    }\n\n    private boolean isRange(String value) {\n        return value != null && value.indexOf(VALUE_SEPARATOR) > -1 && value.split(VALUE_SEPARATOR).length > 1;\n    }\n\n    public String getCategory() {\n        return category;\n    }\n\n    public void setCategory(String category) {\n        this.category = category;\n    }\n\n    public String getServiceInterface() {\n        return serviceInterface;\n    }\n\n    public void setServiceInterface(String serviceInterface) {\n        this.serviceInterface = serviceInterface;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public String getValue() {\n        if (value == null) {\n            value = toValue();\n        }\n        return value;\n    }\n\n    private String toValue() {\n        return new StringBuilder(category)\n                .append(NAME_SEPARATOR)\n                .append(serviceInterface)\n                .append(NAME_SEPARATOR)\n                .append(version)\n                .append(NAME_SEPARATOR)\n                .append(group)\n                .toString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (!(o instanceof NacosServiceName)) {\n            return false;\n        }\n        NacosServiceName that = (NacosServiceName) o;\n        return Objects.equals(getValue(), that.getValue());\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(getValue());\n    }\n\n    @Override\n    public String toString() {\n        return getValue();\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/aot/NacosReflectionTypeDescriberRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos.aot;\n\nimport org.apache.dubbo.aot.api.MemberCategory;\nimport org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;\nimport org.apache.dubbo.aot.api.TypeDescriber;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport com.alibaba.nacos.api.PropertyKeyConst;\nimport com.alibaba.nacos.api.ability.ClientAbilities;\nimport com.alibaba.nacos.api.config.ability.ClientConfigAbility;\nimport com.alibaba.nacos.api.config.remote.request.AbstractConfigRequest;\nimport com.alibaba.nacos.api.config.remote.request.ConfigBatchListenRequest;\nimport com.alibaba.nacos.api.config.remote.request.ConfigBatchListenRequest.ConfigListenContext;\nimport com.alibaba.nacos.api.config.remote.request.ConfigPublishRequest;\nimport com.alibaba.nacos.api.config.remote.request.ConfigQueryRequest;\nimport com.alibaba.nacos.api.config.remote.response.ConfigChangeBatchListenResponse;\nimport com.alibaba.nacos.api.config.remote.response.ConfigChangeBatchListenResponse.ConfigContext;\nimport com.alibaba.nacos.api.config.remote.response.ConfigPublishResponse;\nimport com.alibaba.nacos.api.config.remote.response.ConfigQueryResponse;\nimport com.alibaba.nacos.api.grpc.auto.Metadata;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.ability.ClientNamingAbility;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport com.alibaba.nacos.api.naming.pojo.ServiceInfo;\nimport com.alibaba.nacos.api.naming.remote.request.AbstractNamingRequest;\nimport com.alibaba.nacos.api.naming.remote.request.InstanceRequest;\nimport com.alibaba.nacos.api.naming.remote.request.NotifySubscriberRequest;\nimport com.alibaba.nacos.api.naming.remote.request.ServiceQueryRequest;\nimport com.alibaba.nacos.api.naming.remote.request.SubscribeServiceRequest;\nimport com.alibaba.nacos.api.naming.remote.response.InstanceResponse;\nimport com.alibaba.nacos.api.naming.remote.response.NotifySubscriberResponse;\nimport com.alibaba.nacos.api.naming.remote.response.QueryServiceResponse;\nimport com.alibaba.nacos.api.naming.remote.response.SubscribeServiceResponse;\nimport com.alibaba.nacos.api.remote.ability.ClientRemoteAbility;\nimport com.alibaba.nacos.api.remote.request.ConnectionSetupRequest;\nimport com.alibaba.nacos.api.remote.request.HealthCheckRequest;\nimport com.alibaba.nacos.api.remote.request.InternalRequest;\nimport com.alibaba.nacos.api.remote.request.Request;\nimport com.alibaba.nacos.api.remote.request.ServerCheckRequest;\nimport com.alibaba.nacos.api.remote.request.ServerRequest;\nimport com.alibaba.nacos.api.remote.response.HealthCheckResponse;\nimport com.alibaba.nacos.api.remote.response.Response;\nimport com.alibaba.nacos.api.remote.response.ServerCheckResponse;\nimport com.alibaba.nacos.client.auth.impl.NacosClientAuthServiceImpl;\nimport com.alibaba.nacos.client.auth.ram.RamClientAuthServiceImpl;\nimport com.alibaba.nacos.client.config.NacosConfigService;\nimport com.alibaba.nacos.client.naming.NacosNamingService;\nimport com.alibaba.nacos.common.notify.DefaultPublisher;\nimport com.alibaba.nacos.common.remote.TlsConfig;\nimport com.alibaba.nacos.common.remote.client.RpcClientTlsConfig;\nimport com.alibaba.nacos.shaded.com.google.common.util.concurrent.AbstractFuture;\nimport com.alibaba.nacos.shaded.com.google.protobuf.Any;\nimport com.alibaba.nacos.shaded.com.google.protobuf.ExtensionRegistry;\nimport com.alibaba.nacos.shaded.io.grpc.internal.DnsNameResolverProvider;\nimport com.alibaba.nacos.shaded.io.grpc.internal.PickFirstLoadBalancerProvider;\nimport com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.buffer.AbstractByteBufAllocator;\nimport com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.buffer.AbstractReferenceCountedByteBuf;\nimport com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.channel.ChannelDuplexHandler;\nimport com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.channel.ChannelInboundHandlerAdapter;\nimport com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.channel.socket.nio.NioSocketChannel;\nimport com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.handler.codec.ByteToMessageDecoder;\nimport com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler;\nimport com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.util.ReferenceCountUtil;\n\npublic class NacosReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {\n\n    @Override\n    public List<TypeDescriber> getTypeDescribers() {\n        List<TypeDescriber> typeDescribers = new ArrayList<>();\n        Class[] classesWithDeclared = {\n            ClientAbilities.class,\n            ClientConfigAbility.class,\n            AbstractConfigRequest.class,\n            ConfigBatchListenRequest.class,\n            ConfigListenContext.class,\n            ConfigPublishRequest.class,\n            ConfigQueryRequest.class,\n            ConfigChangeBatchListenResponse.class,\n            ConfigContext.class,\n            ConfigPublishResponse.class,\n            ConfigQueryResponse.class,\n            ClientNamingAbility.class,\n            Instance.class,\n            ServiceInfo.class,\n            AbstractNamingRequest.class,\n            InstanceRequest.class,\n            NotifySubscriberRequest.class,\n            ServiceQueryRequest.class,\n            SubscribeServiceRequest.class,\n            InstanceResponse.class,\n            NotifySubscriberResponse.class,\n            QueryServiceResponse.class,\n            SubscribeServiceResponse.class,\n            ClientRemoteAbility.class,\n            ConnectionSetupRequest.class,\n            HealthCheckRequest.class,\n            InternalRequest.class,\n            Request.class,\n            ServerCheckRequest.class,\n            ServerRequest.class,\n            HealthCheckResponse.class,\n            Response.class,\n            ServerCheckResponse.class,\n            TlsConfig.class,\n            RpcClientTlsConfig.class\n        };\n        Class[] classesWithMethods = {\n            Metadata.class,\n            com.alibaba.nacos.api.grpc.auto.Metadata.Builder.class,\n            com.alibaba.nacos.api.grpc.auto.Payload.class,\n            com.alibaba.nacos.api.grpc.auto.Payload.Builder.class,\n            NamingService.class,\n            com.alibaba.nacos.api.remote.Payload.class,\n            NacosClientAuthServiceImpl.class,\n            RamClientAuthServiceImpl.class,\n            NacosConfigService.class,\n            NacosNamingService.class,\n            DefaultPublisher.class,\n            Any.class,\n            com.alibaba.nacos.shaded.com.google.protobuf.Any.Builder.class,\n            ExtensionRegistry.class,\n            AbstractByteBufAllocator.class,\n            ChannelDuplexHandler.class,\n            ChannelInboundHandlerAdapter.class,\n            NioSocketChannel.class,\n            ByteToMessageDecoder.class,\n            Http2ConnectionHandler.class,\n            ReferenceCountUtil.class\n        };\n        Class[] classesWithFields = {PropertyKeyConst.class, AbstractFuture.class, AbstractReferenceCountedByteBuf.class\n        };\n        Class[] classesWithDefault = {DnsNameResolverProvider.class, PickFirstLoadBalancerProvider.class};\n        String[] privateClasses = {\n            \"com.alibaba.nacos.shaded.com.google.common.util.concurrent.AbstractFuture.Waiter\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.grpc.netty.AbstractNettyHandler\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.grpc.netty.NettyClientHandler\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.grpc.netty.WriteBufferingAndExceptionHandler\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.channel.DefaultChannelPipeline.HeadContext\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.channel.DefaultChannelPipeline.TailContext\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueConsumerIndexField\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueProducerIndexField\",\n            \"com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueProducerLimitField\"\n        };\n        for (Class className : classesWithDeclared) {\n            typeDescribers.add(buildTypeDescriberWithDeclared(className));\n        }\n        for (Class className : classesWithMethods) {\n            typeDescribers.add(buildTypeDescriberWithMethods(className));\n        }\n        for (Class className : classesWithFields) {\n            typeDescribers.add(buildTypeDescriberWithFields(className));\n        }\n        for (Class className : classesWithDefault) {\n            typeDescribers.add(buildTypeDescriberWithDefault(className));\n        }\n        for (String className : privateClasses) {\n            typeDescribers.add(buildTypeDescriberWithDeclared(className));\n        }\n        return typeDescribers;\n    }\n\n    private TypeDescriber buildTypeDescriberWithDeclared(Class<?> cl) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_METHODS);\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n        memberCategories.add(MemberCategory.DECLARED_FIELDS);\n        return new TypeDescriber(\n                cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n\n    private TypeDescriber buildTypeDescriberWithFields(Class<?> cl) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.DECLARED_FIELDS);\n        return new TypeDescriber(\n                cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n\n    private TypeDescriber buildTypeDescriberWithMethods(Class<?> cl) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_METHODS);\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n        return new TypeDescriber(\n                cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n\n    private TypeDescriber buildTypeDescriberWithDefault(Class<?> cl) {\n        return new TypeDescriber(\n                cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), new HashSet<>());\n    }\n\n    private TypeDescriber buildTypeDescriberWithDeclared(String className) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_METHODS);\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n        memberCategories.add(MemberCategory.DECLARED_FIELDS);\n        return new TypeDescriber(className, null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n\n    private TypeDescriber buildTypeDescriberWithFields(String className) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.DECLARED_FIELDS);\n        return new TypeDescriber(className, null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n\n    private TypeDescriber buildTypeDescriberWithMethods(String className) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_METHODS);\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n        return new TypeDescriber(className, null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n\n    private TypeDescriber buildTypeDescriberWithDefault(String className) {\n        return new TypeDescriber(className, null, new HashSet<>(), new HashSet<>(), new HashSet<>(), new HashSet<>());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/function/NacosConsumer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos.function;\n\nimport java.util.function.Function;\n\nimport com.alibaba.nacos.api.exception.NacosException;\n\n/**\n * A function interface for action with {@link NacosException}\n *\n * @see Function\n * @see NacosException\n * @since 3.1.5\n */\n@FunctionalInterface\npublic interface NacosConsumer {\n\n    /**\n     * Applies this function to the given argument.\n     *\n     * @throws NacosException if met with any error\n     */\n    void accept() throws NacosException;\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/function/NacosFunction.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos.function;\n\nimport java.util.function.Function;\n\nimport com.alibaba.nacos.api.exception.NacosException;\n\n/**\n * A function interface for action with {@link NacosException}\n *\n * @see Function\n * @see NacosException\n * @since 3.1.5\n */\n@FunctionalInterface\npublic interface NacosFunction<R> {\n\n    /**\n     * Applies this function to the given argument.\n     *\n     * @return the function result\n     * @throws NacosException if met with any error\n     */\n    R apply() throws NacosException;\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos.util;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.nacos.NacosConnectionManager;\nimport org.apache.dubbo.registry.nacos.NacosNamingServiceWrapper;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport com.alibaba.nacos.api.naming.utils.NamingUtils;\n\nimport static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\n\n/**\n * The utilities class for {@link NamingService}\n *\n * @since 2.7.5\n */\npublic class NacosNamingServiceUtils {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(NacosNamingServiceUtils.class);\n    private static final String NACOS_GROUP_KEY = \"nacos.group\";\n\n    private static final String NACOS_RETRY_KEY = \"nacos.retry\";\n\n    private static final String NACOS_RETRY_WAIT_KEY = \"nacos.retry-wait\";\n\n    private static final String NACOS_CHECK_KEY = \"nacos.check\";\n\n    private NacosNamingServiceUtils() {\n        throw new IllegalStateException(\"NacosNamingServiceUtils should not be instantiated\");\n    }\n\n    /**\n     * Convert the {@link ServiceInstance} to {@link Instance}\n     *\n     * @param serviceInstance {@link ServiceInstance}\n     * @return non-null\n     * @since 2.7.5\n     */\n    public static Instance toInstance(ServiceInstance serviceInstance) {\n        Instance instance = new Instance();\n        instance.setServiceName(serviceInstance.getServiceName());\n        instance.setIp(serviceInstance.getHost());\n        instance.setPort(serviceInstance.getPort());\n        instance.setMetadata(serviceInstance.getSortedMetadata());\n        instance.setEnabled(serviceInstance.isEnabled());\n        instance.setHealthy(serviceInstance.isHealthy());\n        return instance;\n    }\n\n    /**\n     * Convert the {@link Instance} to {@link ServiceInstance}\n     *\n     * @param instance {@link Instance}\n     * @return non-null\n     * @since 2.7.5\n     */\n    public static ServiceInstance toServiceInstance(URL registryUrl, Instance instance) {\n        DefaultServiceInstance serviceInstance = new DefaultServiceInstance(\n                NamingUtils.getServiceName(instance.getServiceName()),\n                instance.getIp(),\n                instance.getPort(),\n                ScopeModelUtil.getApplicationModel(registryUrl.getScopeModel()));\n        serviceInstance.setMetadata(instance.getMetadata());\n        serviceInstance.setEnabled(instance.isEnabled());\n        serviceInstance.setHealthy(instance.isHealthy());\n        return serviceInstance;\n    }\n\n    /**\n     * The group of {@link NamingService} to register\n     *\n     * @param connectionURL {@link URL connection url}\n     * @return non-null, \"default\" as default\n     * @since 2.7.5\n     */\n    public static String getGroup(URL connectionURL) {\n        // Compatible with nacos grouping via group.\n        String group = connectionURL.getParameter(GROUP_KEY, DEFAULT_GROUP);\n        return connectionURL.getParameter(NACOS_GROUP_KEY, group);\n    }\n\n    /**\n     * Create an instance of {@link NamingService} from specified {@link URL connection url}\n     *\n     * @param connectionURL {@link URL connection url}\n     * @return {@link NamingService}\n     * @since 2.7.5\n     */\n    public static NacosNamingServiceWrapper createNamingService(URL connectionURL) {\n        boolean check = connectionURL.getParameter(NACOS_CHECK_KEY, true);\n        int retryTimes = connectionURL.getPositiveParameter(NACOS_RETRY_KEY, 10);\n        int sleepMsBetweenRetries = connectionURL.getPositiveParameter(NACOS_RETRY_WAIT_KEY, 10);\n        if (check && !UrlUtils.isCheck(connectionURL)) {\n            check = false;\n        }\n        NacosConnectionManager nacosConnectionManager =\n                new NacosConnectionManager(connectionURL, check, retryTimes, sleepMsBetweenRetries);\n        return new NacosNamingServiceWrapper(nacosConnectionManager, retryTimes, sleepMsBetweenRetries);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar",
    "content": "nacos=org.apache.dubbo.registry.nacos.aot.NacosReflectionTypeDescriberRegistrar\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory",
    "content": "nacos=org.apache.dubbo.registry.nacos.NacosRegistryFactory"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory",
    "content": "nacos=org.apache.dubbo.registry.nacos.NacosServiceDiscoveryFactory"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/MockNamingService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport java.util.List;\n\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.listener.EventListener;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport com.alibaba.nacos.api.naming.pojo.ListView;\nimport com.alibaba.nacos.api.naming.pojo.ServiceInfo;\nimport com.alibaba.nacos.api.naming.selector.NamingSelector;\nimport com.alibaba.nacos.api.selector.AbstractSelector;\n\npublic class MockNamingService implements NamingService {\n    @Override\n    public void registerInstance(String serviceName, String ip, int port) {}\n\n    @Override\n    public void registerInstance(String serviceName, String groupName, String ip, int port) {}\n\n    @Override\n    public void registerInstance(String serviceName, String ip, int port, String clusterName) {}\n\n    @Override\n    public void registerInstance(String serviceName, String groupName, String ip, int port, String clusterName) {}\n\n    @Override\n    public void registerInstance(String serviceName, Instance instance) {}\n\n    @Override\n    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {}\n\n    @Override\n    public void batchRegisterInstance(String serviceName, String groupName, List<Instance> instances) {}\n\n    @Override\n    public void deregisterInstance(String serviceName, String ip, int port) {}\n\n    @Override\n    public void deregisterInstance(String serviceName, String groupName, String ip, int port) {}\n\n    @Override\n    public void deregisterInstance(String serviceName, String ip, int port, String clusterName) {}\n\n    @Override\n    public void deregisterInstance(String serviceName, String groupName, String ip, int port, String clusterName) {}\n\n    @Override\n    public void deregisterInstance(String serviceName, Instance instance) {}\n\n    @Override\n    public void deregisterInstance(String serviceName, String groupName, Instance instance) {}\n\n    @Override\n    public void batchDeregisterInstance(String s, String s1, List<Instance> list) throws NacosException {}\n\n    @Override\n    public List<Instance> getAllInstances(String serviceName) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> getAllInstances(String serviceName, String groupName) throws NacosException {\n        return null;\n    }\n\n    @Override\n    public List<Instance> getAllInstances(String serviceName, boolean subscribe) throws NacosException {\n        return null;\n    }\n\n    @Override\n    public List<Instance> getAllInstances(String serviceName, String groupName, boolean subscribe)\n            throws NacosException {\n        return null;\n    }\n\n    @Override\n    public List<Instance> getAllInstances(String serviceName, List<String> clusters) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> getAllInstances(String serviceName, List<String> clusters, boolean subscribe) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> getAllInstances(\n            String serviceName, String groupName, List<String> clusters, boolean subscribe) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> selectInstances(String serviceName, boolean healthy) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> selectInstances(String serviceName, String groupName, boolean healthy) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> selectInstances(String serviceName, boolean healthy, boolean subscribe) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> selectInstances(String serviceName, String groupName, boolean healthy, boolean subscribe) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> selectInstances(\n            String serviceName, String groupName, List<String> clusters, boolean healthy) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> selectInstances(\n            String serviceName, List<String> clusters, boolean healthy, boolean subscribe) {\n        return null;\n    }\n\n    @Override\n    public List<Instance> selectInstances(\n            String serviceName, String groupName, List<String> clusters, boolean healthy, boolean subscribe) {\n        return null;\n    }\n\n    @Override\n    public Instance selectOneHealthyInstance(String serviceName) {\n        return null;\n    }\n\n    @Override\n    public Instance selectOneHealthyInstance(String serviceName, String groupName) {\n        return null;\n    }\n\n    @Override\n    public Instance selectOneHealthyInstance(String serviceName, boolean subscribe) {\n        return null;\n    }\n\n    @Override\n    public Instance selectOneHealthyInstance(String serviceName, String groupName, boolean subscribe) {\n        return null;\n    }\n\n    @Override\n    public Instance selectOneHealthyInstance(String serviceName, List<String> clusters) {\n        return null;\n    }\n\n    @Override\n    public Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters) {\n        return null;\n    }\n\n    @Override\n    public Instance selectOneHealthyInstance(String serviceName, List<String> clusters, boolean subscribe) {\n        return null;\n    }\n\n    @Override\n    public Instance selectOneHealthyInstance(\n            String serviceName, String groupName, List<String> clusters, boolean subscribe) {\n        return null;\n    }\n\n    @Override\n    public void subscribe(String serviceName, EventListener listener) throws NacosException {}\n\n    @Override\n    public void subscribe(String serviceName, String groupName, EventListener listener) throws NacosException {}\n\n    @Override\n    public void subscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException {}\n\n    @Override\n    public void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener)\n            throws NacosException {}\n\n    @Override\n    public void unsubscribe(String serviceName, EventListener listener) {}\n\n    @Override\n    public void unsubscribe(String serviceName, String groupName, EventListener listener) {}\n\n    @Override\n    public void unsubscribe(String serviceName, List<String> clusters, EventListener listener) {}\n\n    @Override\n    public void unsubscribe(String serviceName, String groupName, List<String> clusters, EventListener listener) {}\n\n    @Override\n    public ListView<String> getServicesOfServer(int pageNo, int pageSize) {\n        return null;\n    }\n\n    @Override\n    public ListView<String> getServicesOfServer(int pageNo, int pageSize, String groupName) {\n        return null;\n    }\n\n    @Override\n    public ListView<String> getServicesOfServer(int pageNo, int pageSize, AbstractSelector selector) {\n        return null;\n    }\n\n    @Override\n    public ListView<String> getServicesOfServer(int pageNo, int pageSize, String groupName, AbstractSelector selector) {\n        return null;\n    }\n\n    @Override\n    public List<ServiceInfo> getSubscribeServices() {\n        return null;\n    }\n\n    @Override\n    public String getServerStatus() {\n        return null;\n    }\n\n    @Override\n    public void shutDown() {}\n\n    @Override\n    public void subscribe(String s, NamingSelector namingSelector, EventListener eventListener) throws NacosException {}\n\n    @Override\n    public void subscribe(String s, String s1, NamingSelector namingSelector, EventListener eventListener)\n            throws NacosException {}\n\n    @Override\n    public void unsubscribe(String s, NamingSelector namingSelector, EventListener eventListener)\n            throws NacosException {}\n\n    @Override\n    public void unsubscribe(String s, String s1, NamingSelector namingSelector, EventListener eventListener)\n            throws NacosException {}\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosConnectionsManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.alibaba.nacos.api.NacosFactory;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.DOWN;\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP;\nimport static org.mockito.ArgumentMatchers.any;\n\npublic class NacosConnectionsManagerTest {\n    @Test\n    public void testGet() {\n        NamingService namingService = Mockito.mock(NamingService.class);\n        NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(namingService);\n        Assertions.assertEquals(namingService, nacosConnectionManager.getNamingService());\n        Assertions.assertEquals(namingService, nacosConnectionManager.getNamingService());\n        Assertions.assertEquals(namingService, nacosConnectionManager.getNamingService());\n    }\n\n    @Test\n    public void testCreate() {\n        List<NamingService> namingServiceList = new ArrayList<>();\n        NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf(\"\"), false, 0, 0) {\n            @Override\n            protected NamingService createNamingService() {\n                NamingService namingService = Mockito.mock(NamingService.class);\n                namingServiceList.add(namingService);\n                return namingService;\n            }\n        };\n\n        Assertions.assertEquals(1, namingServiceList.size());\n        Assertions.assertEquals(namingServiceList.get(0), nacosConnectionManager.getNamingService());\n        Assertions.assertEquals(namingServiceList.get(0), nacosConnectionManager.getNamingService());\n        Assertions.assertEquals(namingServiceList.get(0), nacosConnectionManager.getNamingService());\n        Assertions.assertEquals(namingServiceList.get(0), nacosConnectionManager.getNamingService());\n\n        LinkedList<NamingService> copy = new LinkedList<>(namingServiceList);\n        Assertions.assertFalse(copy.contains(nacosConnectionManager.getNamingService(new HashSet<>(copy))));\n        copy = new LinkedList<>(namingServiceList);\n        Assertions.assertFalse(copy.contains(nacosConnectionManager.getNamingService(new HashSet<>(copy))));\n        copy = new LinkedList<>(namingServiceList);\n        Assertions.assertFalse(copy.contains(nacosConnectionManager.getNamingService(new HashSet<>(copy))));\n        copy = new LinkedList<>(namingServiceList);\n        Assertions.assertFalse(copy.contains(nacosConnectionManager.getNamingService(new HashSet<>(copy))));\n\n        Assertions.assertEquals(5, namingServiceList.size());\n\n        copy = new LinkedList<>(namingServiceList);\n        for (int i = 0; i < 1000; i++) {\n            if (copy.size() == 0) {\n                break;\n            }\n            copy.remove(nacosConnectionManager.getNamingService());\n        }\n\n        Assertions.assertTrue(copy.isEmpty());\n\n        nacosConnectionManager.shutdownAll();\n        copy = new LinkedList<>(namingServiceList);\n        Assertions.assertFalse(copy.contains(nacosConnectionManager.getNamingService()));\n    }\n\n    @Test\n    void testRetryCreate() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            AtomicInteger atomicInteger = new AtomicInteger(0);\n            NamingService mock = new MockNamingService() {\n                @Override\n                public String getServerStatus() {\n                    return atomicInteger.incrementAndGet() > 10 ? UP : DOWN;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createNamingService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\");\n            Assertions.assertThrows(IllegalStateException.class, () -> new NacosConnectionManager(url, true, 5, 10));\n\n            try {\n                new NacosConnectionManager(url, true, 5, 10);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n\n    @Test\n    void testNoCheck() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            NamingService mock = new MockNamingService() {\n                @Override\n                public String getServerStatus() {\n                    return DOWN;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createNamingService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\");\n\n            try {\n                new NacosConnectionManager(url, false, 5, 10);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n\n    @Test\n    void testDisable() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            NamingService mock = new MockNamingService() {\n                @Override\n                public String getServerStatus() {\n                    return DOWN;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createNamingService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10)\n                    .addParameter(\"nacos.check\", \"false\");\n            try {\n                new NacosConnectionManager(url, false, 5, 10);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n\n    @Test\n    void testRequest() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            AtomicInteger atomicInteger = new AtomicInteger(0);\n            NamingService mock = new MockNamingService() {\n                @Override\n                public List<Instance> getAllInstances(String serviceName, boolean subscribe) throws NacosException {\n                    if (atomicInteger.incrementAndGet() > 10) {\n                        return null;\n                    } else {\n                        throw new NacosException();\n                    }\n                }\n\n                @Override\n                public String getServerStatus() {\n                    return UP;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createNamingService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10);\n            Assertions.assertThrows(IllegalStateException.class, () -> new NacosConnectionManager(url, true, 5, 10));\n\n            try {\n                new NacosConnectionManager(url, true, 5, 10);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapperTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.listener.EventListener;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass NacosNamingServiceWrapperTest {\n    @Test\n    void testSubscribe() throws NacosException {\n        NacosConnectionManager connectionManager = Mockito.mock(NacosConnectionManager.class);\n        NamingService namingService = Mockito.mock(NamingService.class);\n        Mockito.when(connectionManager.getNamingService()).thenReturn(namingService);\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper = new NacosNamingServiceWrapper(connectionManager, 0, 0);\n\n        EventListener eventListener = Mockito.mock(EventListener.class);\n        nacosNamingServiceWrapper.subscribe(\"service_name\", \"test\", eventListener);\n        Mockito.verify(namingService, Mockito.times(1)).subscribe(\"service_name\", \"test\", eventListener);\n\n        nacosNamingServiceWrapper.subscribe(\"service_name\", \"test\", eventListener);\n        Mockito.verify(namingService, Mockito.times(2)).subscribe(\"service_name\", \"test\", eventListener);\n\n        nacosNamingServiceWrapper.unsubscribe(\"service_name\", \"test\", eventListener);\n        Mockito.verify(namingService, Mockito.times(1)).unsubscribe(\"service_name\", \"test\", eventListener);\n\n        nacosNamingServiceWrapper.unsubscribe(\"service_name\", \"test\", eventListener);\n        Mockito.verify(namingService, Mockito.times(1)).unsubscribe(\"service_name\", \"test\", eventListener);\n\n        nacosNamingServiceWrapper.unsubscribe(\"service_name\", \"mock\", eventListener);\n        Mockito.verify(namingService, Mockito.times(0)).unsubscribe(\"service_name\", \"mock\", eventListener);\n    }\n\n    @Test\n    void testSubscribeMultiManager() throws NacosException {\n        NacosConnectionManager connectionManager = Mockito.mock(NacosConnectionManager.class);\n        NamingService namingService1 = Mockito.mock(NamingService.class);\n        NamingService namingService2 = Mockito.mock(NamingService.class);\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper = new NacosNamingServiceWrapper(connectionManager, 0, 0);\n\n        EventListener eventListener = Mockito.mock(EventListener.class);\n        Mockito.when(connectionManager.getNamingService()).thenReturn(namingService1);\n        nacosNamingServiceWrapper.subscribe(\"service_name\", \"test\", eventListener);\n        Mockito.verify(namingService1, Mockito.times(1)).subscribe(\"service_name\", \"test\", eventListener);\n\n        Mockito.when(connectionManager.getNamingService()).thenReturn(namingService2);\n        nacosNamingServiceWrapper.subscribe(\"service_name\", \"test\", eventListener);\n        Mockito.verify(namingService1, Mockito.times(2)).subscribe(\"service_name\", \"test\", eventListener);\n\n        nacosNamingServiceWrapper.unsubscribe(\"service_name\", \"test\", eventListener);\n        Mockito.verify(namingService1, Mockito.times(1)).unsubscribe(\"service_name\", \"test\", eventListener);\n\n        nacosNamingServiceWrapper.unsubscribe(\"service_name\", \"test\", eventListener);\n        Mockito.verify(namingService1, Mockito.times(1)).unsubscribe(\"service_name\", \"test\", eventListener);\n\n        nacosNamingServiceWrapper.unsubscribe(\"service_name\", \"mock\", eventListener);\n        Mockito.verify(namingService1, Mockito.times(0)).unsubscribe(\"service_name\", \"mock\", eventListener);\n        Mockito.verify(namingService2, Mockito.times(0)).unsubscribe(\"service_name\", \"mock\", eventListener);\n    }\n\n    @Test\n    void testRegisterNacos2_0_x() throws NacosException {\n        List<NamingService> namingServiceList = new LinkedList<>();\n        NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf(\"\"), false, 0, 0) {\n            @Override\n            protected NamingService createNamingService() {\n                NamingService namingService = Mockito.mock(NamingService.class);\n                namingServiceList.add(namingService);\n                return namingService;\n            }\n        };\n\n        Assertions.assertEquals(1, namingServiceList.size());\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(nacosConnectionManager, false, 0, 0);\n\n        Instance instance1 = new Instance();\n        instance1.setIp(\"ip1\");\n        instance1.setPort(1);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance1);\n\n        Instance instance2 = new Instance();\n        instance2.setIp(\"ip2\");\n        instance2.setPort(2);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Assertions.assertEquals(2, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(1), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance2);\n\n        Instance instance3 = new Instance();\n        instance3.setIp(\"ip3\");\n        instance3.setPort(3);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance3);\n        Assertions.assertEquals(3, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(1), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(2), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance3);\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .deregisterInstance(\"service_name\", \"test\", instance1);\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(1), Mockito.times(1))\n                .deregisterInstance(\"service_name\", \"test\", instance2);\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance3);\n        Mockito.verify(namingServiceList.get(2), Mockito.times(1))\n                .deregisterInstance(\"service_name\", \"test\", instance3);\n    }\n\n    @Test\n    void testRegisterNacos2_1_xClient2_0_xServer() throws NacosException {\n        List<NamingService> namingServiceList = new LinkedList<>();\n        NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf(\"\"), false, 0, 0) {\n            @Override\n            protected NamingService createNamingService() {\n                NamingService namingService = Mockito.mock(NamingService.class);\n                try {\n                    Mockito.doThrow(new NacosException())\n                            .when(namingService)\n                            .batchRegisterInstance(Mockito.anyString(), Mockito.anyString(), Mockito.any(List.class));\n                } catch (NacosException e) {\n                    throw new RuntimeException(e);\n                }\n                namingServiceList.add(namingService);\n                return namingService;\n            }\n        };\n\n        Assertions.assertEquals(1, namingServiceList.size());\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(nacosConnectionManager, true, 0, 0);\n\n        Instance instance1 = new Instance();\n        instance1.setIp(\"ip1\");\n        instance1.setPort(1);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance1);\n\n        Instance instance2 = new Instance();\n        instance2.setIp(\"ip2\");\n        instance2.setPort(2);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Assertions.assertEquals(2, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(1), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance2);\n\n        Instance instance3 = new Instance();\n        instance3.setIp(\"ip3\");\n        instance3.setPort(3);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance3);\n        Assertions.assertEquals(3, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(1), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(2), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance3);\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .deregisterInstance(\"service_name\", \"test\", instance1);\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(1), Mockito.times(1))\n                .deregisterInstance(\"service_name\", \"test\", instance2);\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .registerInstance(Mockito.eq(\"service_name\"), Mockito.eq(\"test\"), Mockito.any());\n        Mockito.verify(namingServiceList.get(1), Mockito.times(2))\n                .registerInstance(Mockito.eq(\"service_name\"), Mockito.eq(\"test\"), Mockito.any());\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance1);\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .deregisterInstance(Mockito.eq(\"service_name\"), Mockito.eq(\"test\"), Mockito.any());\n        Mockito.verify(namingServiceList.get(1), Mockito.times(2))\n                .deregisterInstance(Mockito.eq(\"service_name\"), Mockito.eq(\"test\"), Mockito.any());\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance3);\n        Mockito.verify(namingServiceList.get(2), Mockito.times(1))\n                .deregisterInstance(\"service_name\", \"test\", instance3);\n    }\n\n    @Test\n    void testRegisterNacos2_1_xClient2_1_xServer() throws NacosException {\n        List<NamingService> namingServiceList = new LinkedList<>();\n        NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf(\"\"), false, 0, 0) {\n            @Override\n            protected NamingService createNamingService() {\n                NamingService namingService = Mockito.mock(NamingService.class);\n                namingServiceList.add(namingService);\n                return namingService;\n            }\n        };\n\n        Assertions.assertEquals(1, namingServiceList.size());\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(nacosConnectionManager, true, 0, 0);\n\n        Instance instance1 = new Instance();\n        instance1.setIp(\"ip1\");\n        instance1.setPort(1);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance1);\n\n        Instance instance2 = new Instance();\n        instance2.setIp(\"ip2\");\n        instance2.setPort(2);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance1, instance2))));\n\n        Instance instance3 = new Instance();\n        instance3.setIp(\"ip3\");\n        instance3.setPort(3);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance3);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance1, instance2, instance3))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance2, instance3))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(Collections.singletonList(instance3)));\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance1))));\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance1, instance2))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance2))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(Collections.singletonList(instance3)));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance3);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .deregisterInstance(\"service_name\", \"test\", instance3);\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance3);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .deregisterInstance(\"service_name\", \"test\", instance3);\n\n        // rerun\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2)).registerInstance(\"service_name\", \"test\", instance1);\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance1, instance2))));\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance3);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance1, instance2, instance3))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance2, instance3))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(3))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(Collections.singletonList(instance3)));\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance1))));\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance1, instance2))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance2))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(4))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(Collections.singletonList(instance3)));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance3);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .deregisterInstance(\"service_name\", \"test\", instance3);\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance3);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .deregisterInstance(\"service_name\", \"test\", instance3);\n    }\n\n    @Test\n    void testUnregister() throws NacosException {\n        List<NamingService> namingServiceList = new LinkedList<>();\n        NacosConnectionManager nacosConnectionManager = new NacosConnectionManager(URL.valueOf(\"\"), false, 0, 0) {\n            @Override\n            protected NamingService createNamingService() {\n                NamingService namingService = Mockito.mock(NamingService.class);\n                namingServiceList.add(namingService);\n                return namingService;\n            }\n        };\n\n        Assertions.assertEquals(1, namingServiceList.size());\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(nacosConnectionManager, true, 0, 0);\n\n        Instance instance1 = new Instance();\n        instance1.setIp(\"ip1\");\n        instance1.setPort(1);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1)).registerInstance(\"service_name\", \"test\", instance1);\n\n        Instance instance2 = new Instance();\n        instance2.setIp(\"ip2\");\n        instance2.setPort(2);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance1, instance2))));\n\n        Instance instance3 = new Instance();\n        instance3.setIp(\"ip3\");\n        instance3.setPort(3);\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance3);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance1, instance2, instance3))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance1);\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance2, instance3))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance2);\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance2);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(Collections.singletonList(instance3)));\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance1))));\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance1, instance2))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip2\", 1);\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip1\", 2);\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip1\", 1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance2))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip2\", 2);\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip2\", 2);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(Collections.singletonList(instance3)));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip3\", 3);\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip3\", 3);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(1))\n                .deregisterInstance(\"service_name\", \"test\", instance3);\n\n        // rerun\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2)).registerInstance(\"service_name\", \"test\", instance1);\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance1, instance2))));\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance3);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance1, instance2, instance3))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip1\", 1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance2, instance3))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip2\", 2);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(3))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(Collections.singletonList(instance3)));\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance1);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance1))));\n\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance2);\n        Assertions.assertEquals(1, namingServiceList.size());\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance1, instance2))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip1\", 1);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(new ArrayList<>(Arrays.asList(instance3, instance2))));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip2\", 2);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(4))\n                .batchRegisterInstance(\n                        Mockito.eq(\"service_name\"),\n                        Mockito.eq(\"test\"),\n                        Mockito.eq(Collections.singletonList(instance3)));\n\n        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", \"ip3\", 3);\n        Mockito.verify(namingServiceList.get(0), Mockito.times(2))\n                .deregisterInstance(\"service_name\", \"test\", instance3);\n    }\n\n    @Test\n    void testConcurrency() throws NacosException, InterruptedException {\n        NacosConnectionManager connectionManager = Mockito.mock(NacosConnectionManager.class);\n\n        CountDownLatch startLatch = new CountDownLatch(1);\n        CountDownLatch stopLatch = new CountDownLatch(1);\n        NamingService namingService = Mockito.mock(NamingService.class);\n        Mockito.when(connectionManager.getNamingService()).thenReturn(namingService);\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(connectionManager, false, 0, 0);\n\n        Instance instance = new Instance();\n        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance);\n\n        NacosNamingServiceWrapper.InstancesInfo instancesInfo = nacosNamingServiceWrapper\n                .getRegisterStatus()\n                .get(new NacosNamingServiceWrapper.InstanceId(\"service_name\", \"test\"));\n        Assertions.assertEquals(1, instancesInfo.getInstances().size());\n\n        nacosNamingServiceWrapper\n                .getRegisterStatus()\n                .put(\n                        new NacosNamingServiceWrapper.InstanceId(\"service_name\", \"test\"),\n                        new NacosNamingServiceWrapper.InstancesInfo() {\n                            private final NacosNamingServiceWrapper.InstancesInfo delegate = instancesInfo;\n\n                            @Override\n                            public void lock() {\n                                delegate.lock();\n                            }\n\n                            @Override\n                            public void unlock() {\n                                delegate.unlock();\n                            }\n\n                            @Override\n                            public List<NacosNamingServiceWrapper.InstanceInfo> getInstances() {\n                                try {\n                                    if (startLatch.getCount() > 0) {\n                                        Thread.sleep(1000);\n                                        startLatch.countDown();\n                                        Thread.sleep(1000);\n                                    }\n                                } catch (InterruptedException e) {\n                                    throw new RuntimeException(e);\n                                }\n                                return delegate.getInstances();\n                            }\n\n                            @Override\n                            public boolean isBatchRegistered() {\n                                return delegate.isBatchRegistered();\n                            }\n\n                            @Override\n                            public void setBatchRegistered(boolean batchRegistered) {\n                                delegate.setBatchRegistered(batchRegistered);\n                            }\n\n                            @Override\n                            public boolean isValid() {\n                                return delegate.isValid();\n                            }\n\n                            @Override\n                            public void setValid(boolean valid) {\n                                delegate.setValid(valid);\n                            }\n                        });\n\n        new Thread(() -> {\n                    try {\n                        startLatch.await();\n                        nacosNamingServiceWrapper.registerInstance(\"service_name\", \"test\", instance);\n                        stopLatch.countDown();\n                    } catch (Exception e) {\n                        throw new RuntimeException(e);\n                    }\n                })\n                .start();\n\n        new Thread(() -> {\n                    try {\n                        nacosNamingServiceWrapper.deregisterInstance(\"service_name\", \"test\", instance);\n                    } catch (NacosException e) {\n                        throw new RuntimeException(e);\n                    }\n                })\n                .start();\n\n        stopLatch.await();\n        NacosNamingServiceWrapper.InstancesInfo instancesInfoNew = nacosNamingServiceWrapper\n                .getRegisterStatus()\n                .get(new NacosNamingServiceWrapper.InstanceId(\"service_name\", \"test\"));\n        Assertions.assertEquals(1, instancesInfoNew.getInstances().size());\n\n        Assertions.assertNotEquals(instancesInfo, instancesInfoNew);\n    }\n\n    @Test\n    void testSuccess() {\n        NamingService namingService = new MockNamingService() {\n            @Override\n            public void registerInstance(String serviceName, String groupName, Instance instance) {}\n\n            @Override\n            public List<Instance> getAllInstances(String serviceName, String groupName, boolean subscribe) {\n                return null;\n            }\n        };\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(new NacosConnectionManager(namingService), 0, 0);\n        try {\n            nacosNamingServiceWrapper.registerInstance(\"Test\", \"Test\", null);\n        } catch (NacosException e) {\n            Assertions.fail(e);\n        }\n        try {\n            nacosNamingServiceWrapper.getAllInstancesWithoutSubscription(\"Test\", \"Test\");\n        } catch (NacosException e) {\n            Assertions.fail(e);\n        }\n    }\n\n    @Test\n    void testFailNoRetry() {\n        NamingService namingService = new MockNamingService() {\n            @Override\n            public void registerInstance(String serviceName, String groupName, Instance instance)\n                    throws NacosException {\n                throw new NacosException();\n            }\n\n            @Override\n            public List<Instance> getAllInstances(String serviceName, String groupName, boolean subscribe)\n                    throws NacosException {\n                throw new NacosException();\n            }\n        };\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(new NacosConnectionManager(namingService), 0, 0);\n        Assertions.assertThrows(\n                NacosException.class, () -> nacosNamingServiceWrapper.registerInstance(\"Test\", \"Test\", null));\n        Assertions.assertThrows(\n                NacosException.class,\n                () -> nacosNamingServiceWrapper.getAllInstancesWithoutSubscription(\"Test\", \"Test\"));\n    }\n\n    @Test\n    void testFailRetry() {\n        NamingService namingService = new MockNamingService() {\n            private final AtomicInteger count1 = new AtomicInteger(0);\n            private final AtomicInteger count2 = new AtomicInteger(0);\n\n            @Override\n            public void registerInstance(String serviceName, String groupName, Instance instance)\n                    throws NacosException {\n                if (count1.incrementAndGet() < 10) {\n                    throw new NacosException();\n                }\n            }\n\n            @Override\n            public List<Instance> getAllInstances(String serviceName, String groupName, boolean subscribe)\n                    throws NacosException {\n                if (count2.incrementAndGet() < 10) {\n                    throw new NacosException();\n                }\n                return null;\n            }\n        };\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(new NacosConnectionManager(namingService), 5, 10);\n        Assertions.assertThrows(\n                NacosException.class, () -> nacosNamingServiceWrapper.registerInstance(\"Test\", \"Test\", null));\n        try {\n            nacosNamingServiceWrapper.registerInstance(\"Test\", \"Test\", null);\n        } catch (NacosException e) {\n            Assertions.fail(e);\n        }\n\n        Assertions.assertThrows(\n                NacosException.class,\n                () -> nacosNamingServiceWrapper.getAllInstancesWithoutSubscription(\"Test\", \"Test\"));\n        try {\n            nacosNamingServiceWrapper.getAllInstancesWithoutSubscription(\"Test\", \"Test\");\n        } catch (NacosException e) {\n            Assertions.fail(e);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosRegistryFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * Test for NacosRegistryFactory\n */\nclass NacosRegistryFactoryTest {\n\n    private NacosRegistryFactory nacosRegistryFactory;\n\n    @BeforeEach\n    public void setup() {\n        nacosRegistryFactory = new NacosRegistryFactory();\n    }\n\n    @AfterEach\n    public void teardown() {}\n\n    @Test\n    void testCreateRegistryCacheKey() {\n        URL url = URL.valueOf(\"dubbo://\" + NetUtils.getLocalAddress().getHostAddress() + \":8080?nacos.check=false\");\n        String registryCacheKey1 = nacosRegistryFactory.createRegistryCacheKey(url);\n        String registryCacheKey2 = nacosRegistryFactory.createRegistryCacheKey(url);\n        Assertions.assertEquals(registryCacheKey1, registryCacheKey2);\n    }\n\n    @Test\n    void testCreateRegistryCacheKeyWithNamespace() {\n        URL url = URL.valueOf(\n                \"dubbo://\" + NetUtils.getLocalAddress().getHostAddress() + \":8080?namespace=test&nacos.check=false\");\n        String registryCacheKey1 = nacosRegistryFactory.createRegistryCacheKey(url);\n        String registryCacheKey2 = nacosRegistryFactory.createRegistryCacheKey(url);\n        Assertions.assertEquals(registryCacheKey1, registryCacheKey2);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.registry.NotifyListener;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.alibaba.nacos.api.common.Constants;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport com.alibaba.nacos.api.naming.pojo.ListView;\nimport com.alibaba.nacos.client.naming.NacosNamingService;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.Mockito.doNothing;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\n/**\n * Test for NacosRegistry\n */\nclass NacosRegistryTest {\n\n    private static final String serviceInterface = \"org.apache.dubbo.registry.nacos.NacosService\";\n\n    private final URL serviceUrl =\n            URL.valueOf(\"nacos://127.0.0.1:3333/\" + serviceInterface + \"?interface=\" + serviceInterface\n                    + \"&notify=false&methods=test1,test2&category=providers&version=1.0.0&group=default&side=provider\");\n\n    private NacosRegistryFactory nacosRegistryFactory;\n\n    private NacosRegistry nacosRegistry;\n\n    private URL registryUrl;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n\n        int nacosServerPort = NetUtils.getAvailablePort();\n\n        this.registryUrl = URL.valueOf(\"nacos://localhost:\" + nacosServerPort + \"?nacos.check=false\");\n\n        this.nacosRegistryFactory = new NacosRegistryFactory();\n\n        this.nacosRegistry = (NacosRegistry) nacosRegistryFactory.createRegistry(registryUrl);\n    }\n\n    @AfterEach\n    public void tearDown() throws Exception {}\n\n    @Test\n    void testRegister() {\n        NamingService namingService = mock(NacosNamingService.class);\n        try {\n\n            String serviceName = \"providers:org.apache.dubbo.registry.nacos.NacosService:1.0.0:default\";\n            String category = this.serviceUrl.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);\n            URL newUrl = this.serviceUrl.addParameter(CATEGORY_KEY, category);\n            newUrl = newUrl.addParameter(PROTOCOL_KEY, this.serviceUrl.getProtocol());\n            newUrl = newUrl.addParameter(PATH_KEY, this.serviceUrl.getPath());\n            String ip = newUrl.getHost();\n            int port = newUrl.getPort();\n            Instance instance = new Instance();\n            instance.setIp(ip);\n            instance.setPort(port);\n            instance.setMetadata(new HashMap<>(newUrl.getParameters()));\n            doNothing().when(namingService).registerInstance(serviceName, Constants.DEFAULT_GROUP, instance);\n        } catch (NacosException e) {\n            // ignore\n        }\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(new NacosConnectionManager(namingService), 0, 0);\n        nacosRegistry = new NacosRegistry(this.registryUrl, nacosNamingServiceWrapper);\n\n        Set<URL> registered;\n        for (int i = 0; i < 2; i++) {\n            nacosRegistry.register(serviceUrl);\n            registered = nacosRegistry.getRegistered();\n            assertThat(registered.contains(serviceUrl), is(true));\n        }\n\n        registered = nacosRegistry.getRegistered();\n        Assertions.assertEquals(1, registered.size());\n    }\n\n    @Test\n    void testUnRegister() {\n        NamingService namingService = mock(NacosNamingService.class);\n\n        try {\n\n            String serviceName = \"providers:org.apache.dubbo.registry.nacos.NacosService:1.0.0:default\";\n            String category = this.serviceUrl.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);\n            URL newUrl = this.serviceUrl.addParameter(CATEGORY_KEY, category);\n            newUrl = newUrl.addParameter(PROTOCOL_KEY, this.serviceUrl.getProtocol());\n            newUrl = newUrl.addParameter(PATH_KEY, this.serviceUrl.getPath());\n            String ip = newUrl.getHost();\n            int port = newUrl.getPort();\n            Instance instance = new Instance();\n            instance.setIp(ip);\n            instance.setPort(port);\n            instance.setMetadata(new HashMap<>(newUrl.getParameters()));\n            doNothing().when(namingService).registerInstance(serviceName, Constants.DEFAULT_GROUP, instance);\n\n            doNothing().when(namingService).deregisterInstance(serviceName, Constants.DEFAULT_GROUP, ip, port);\n        } catch (NacosException e) {\n            // ignore\n        }\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(new NacosConnectionManager(namingService), 0, 0);\n        nacosRegistry = new NacosRegistry(this.registryUrl, nacosNamingServiceWrapper);\n\n        nacosRegistry.register(serviceUrl);\n        Set<URL> registered = nacosRegistry.getRegistered();\n\n        assertThat(registered.contains(serviceUrl), is(true));\n        Assertions.assertEquals(1, registered.size());\n\n        nacosRegistry.unregister(serviceUrl);\n        Assertions.assertFalse(registered.contains(serviceUrl));\n        Assertions.assertEquals(0, registered.size());\n    }\n\n    @Test\n    void testSubscribe() {\n        NamingService namingService = mock(NacosNamingService.class);\n\n        try {\n\n            String serviceName = \"providers:org.apache.dubbo.registry.nacos.NacosService:1.0.0:default\";\n            String category = this.serviceUrl.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);\n            URL newUrl = this.serviceUrl.addParameter(CATEGORY_KEY, category);\n            newUrl = newUrl.addParameter(PROTOCOL_KEY, this.serviceUrl.getProtocol());\n            newUrl = newUrl.addParameter(PATH_KEY, this.serviceUrl.getPath());\n            String ip = newUrl.getHost();\n            int port = newUrl.getPort();\n            Instance instance = new Instance();\n            instance.setIp(ip);\n            instance.setPort(port);\n            instance.setMetadata(new HashMap<>(newUrl.getParameters()));\n\n            List<Instance> instances = new ArrayList<>();\n            instances.add(instance);\n            when(namingService.getAllInstances(\n                            serviceName, this.registryUrl.getParameter(GROUP_KEY, Constants.DEFAULT_GROUP)))\n                    .thenReturn(instances);\n        } catch (NacosException e) {\n            // ignore\n        }\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(new NacosConnectionManager(namingService), 0, 0);\n        nacosRegistry = new NacosRegistry(this.registryUrl, nacosNamingServiceWrapper);\n\n        NotifyListener listener = mock(NotifyListener.class);\n        nacosRegistry.subscribe(serviceUrl, listener);\n\n        Map<URL, Set<NotifyListener>> subscribed = nacosRegistry.getSubscribed();\n        Assertions.assertEquals(1, subscribed.size());\n        Assertions.assertEquals(1, subscribed.get(serviceUrl).size());\n    }\n\n    @Test\n    void testUnSubscribe() {\n        NamingService namingService = mock(NacosNamingService.class);\n\n        try {\n\n            String serviceName = \"providers:org.apache.dubbo.registry.nacos.NacosService:1.0.0:default\";\n            String category = this.serviceUrl.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);\n            URL newUrl = this.serviceUrl.addParameter(CATEGORY_KEY, category);\n            newUrl = newUrl.addParameter(PROTOCOL_KEY, this.serviceUrl.getProtocol());\n            newUrl = newUrl.addParameter(PATH_KEY, this.serviceUrl.getPath());\n            String ip = newUrl.getHost();\n            int port = newUrl.getPort();\n            Instance instance = new Instance();\n            instance.setIp(ip);\n            instance.setPort(port);\n            instance.setMetadata(new HashMap<>(newUrl.getParameters()));\n\n            List<Instance> instances = new ArrayList<>();\n            instances.add(instance);\n            when(namingService.getAllInstances(\n                            serviceName, this.registryUrl.getParameter(GROUP_KEY, Constants.DEFAULT_GROUP)))\n                    .thenReturn(instances);\n\n        } catch (NacosException e) {\n            // ignore\n        }\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(new NacosConnectionManager(namingService), 0, 0);\n        nacosRegistry = new NacosRegistry(this.registryUrl, nacosNamingServiceWrapper);\n\n        NotifyListener listener = mock(NotifyListener.class);\n        nacosRegistry.subscribe(serviceUrl, listener);\n\n        Map<URL, Set<NotifyListener>> subscribed = nacosRegistry.getSubscribed();\n        Assertions.assertEquals(1, subscribed.size());\n        Assertions.assertEquals(1, subscribed.get(serviceUrl).size());\n\n        nacosRegistry.unsubscribe(serviceUrl, listener);\n        subscribed = nacosRegistry.getSubscribed();\n        Assertions.assertEquals(1, subscribed.size());\n        Assertions.assertEquals(0, subscribed.get(serviceUrl).size());\n    }\n\n    @Test\n    void testIsConformRules() {\n        NamingService namingService = mock(NacosNamingService.class);\n        URL serviceUrlWithoutCategory = URL.valueOf(\"nacos://127.0.0.1:3333/\" + serviceInterface + \"?interface=\"\n                + serviceInterface + \"&notify=false&methods=test1,test2&version=1.0.0&group=default\");\n        try {\n            String serviceName = \"providers:org.apache.dubbo.registry.nacos.NacosService:1.0.0:default\";\n            String category = this.serviceUrl.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);\n            URL newUrl = this.serviceUrl.addParameter(CATEGORY_KEY, category);\n            newUrl = newUrl.addParameter(PROTOCOL_KEY, this.serviceUrl.getProtocol());\n            newUrl = newUrl.addParameter(PATH_KEY, this.serviceUrl.getPath());\n            String ip = newUrl.getHost();\n            int port = newUrl.getPort();\n            Instance instance = new Instance();\n            instance.setIp(ip);\n            instance.setPort(port);\n            instance.setMetadata(new HashMap<>(newUrl.getParameters()));\n\n            List<Instance> instances = new ArrayList<>();\n            instances.add(instance);\n            when(namingService.getAllInstances(\n                            serviceName, this.registryUrl.getParameter(GROUP_KEY, Constants.DEFAULT_GROUP)))\n                    .thenReturn(instances);\n\n            String serviceNameWithoutVersion = \"providers:org.apache.dubbo.registry.nacos.NacosService:default\";\n            String serviceName1 = \"providers:org.apache.dubbo.registry.nacos.NacosService:1.0.0:default\";\n            List<String> serviceNames = new ArrayList<>();\n            serviceNames.add(serviceNameWithoutVersion);\n            serviceNames.add(serviceName1);\n            ListView<String> result = new ListView<>();\n            result.setData(serviceNames);\n            when(namingService.getServicesOfServer(\n                            1, Integer.MAX_VALUE, registryUrl.getParameter(GROUP_KEY, Constants.DEFAULT_GROUP)))\n                    .thenReturn(result);\n        } catch (NacosException e) {\n            // ignore\n        }\n\n        NacosNamingServiceWrapper nacosNamingServiceWrapper =\n                new NacosNamingServiceWrapper(new NacosConnectionManager(namingService), 0, 0);\n        nacosRegistry = new NacosRegistry(this.registryUrl, nacosNamingServiceWrapper);\n\n        Set<URL> registered;\n        nacosRegistry.register(this.serviceUrl);\n        nacosRegistry.register(serviceUrlWithoutCategory);\n        registered = nacosRegistry.getRegistered();\n        Assertions.assertTrue(registered.contains(serviceUrl));\n        Assertions.assertTrue(registered.contains(serviceUrlWithoutCategory));\n        Assertions.assertEquals(2, registered.size());\n\n        URL serviceUrlWithWildcard = URL.valueOf(\"nacos://127.0.0.1:3333/\" + serviceInterface\n                + \"?interface=org.apache.dubbo.registry.nacos.NacosService\"\n                + \"&notify=false&methods=test1,test2&category=providers&version=*&group=default\");\n\n        URL serviceUrlWithOutWildcard = URL.valueOf(\"nacos://127.0.0.1:3333/\" + serviceInterface\n                + \"?interface=org.apache.dubbo.registry.nacos.NacosService\"\n                + \"&notify=false&methods=test1,test2&category=providers&version=1.0.0&group=default\");\n\n        NotifyListener listener = mock(NotifyListener.class);\n        nacosRegistry.subscribe(serviceUrlWithWildcard, listener);\n        nacosRegistry.subscribe(serviceUrlWithOutWildcard, listener);\n\n        Map<URL, Set<NotifyListener>> subscribed = nacosRegistry.getSubscribed();\n\n        Assertions.assertEquals(2, registered.size());\n        Assertions.assertEquals(1, subscribed.get(serviceUrlWithOutWildcard).size());\n\n        Assertions.assertEquals(2, registered.size());\n        Assertions.assertEquals(1, subscribed.get(serviceUrlWithWildcard).size());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\n/**\n * Test for NacosServiceDiscoveryFactory\n */\nclass NacosServiceDiscoveryFactoryTest {\n\n    private NacosServiceDiscoveryFactory nacosServiceDiscoveryFactory;\n\n    @BeforeEach\n    public void setup() {\n        nacosServiceDiscoveryFactory = new NacosServiceDiscoveryFactory();\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        applicationModel\n                .getApplicationConfigManager()\n                .setApplication(new ApplicationConfig(\"NacosServiceDiscoveryFactoryTest\"));\n        nacosServiceDiscoveryFactory.setApplicationModel(applicationModel);\n    }\n\n    @Test\n    void testGetServiceDiscoveryWithCache() {\n        URL url = URL.valueOf(\"dubbo://test:8080?nacos.check=false\");\n        ServiceDiscovery discovery = nacosServiceDiscoveryFactory.createDiscovery(url);\n\n        Assertions.assertTrue(discovery instanceof NacosServiceDiscovery);\n    }\n\n    @AfterEach\n    public void tearDown() {\n        ApplicationModel.defaultModel().destroy();\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceDiscoveryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Set;\n\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport com.alibaba.nacos.api.naming.pojo.ListView;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.internal.util.collections.Sets;\n\nimport static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyInt;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n/**\n * Test for NacosServiceDiscovery\n */\nclass NacosServiceDiscoveryTest {\n\n    private static final String SERVICE_NAME = \"NACOS_SERVICE\";\n\n    private static final String LOCALHOST = \"127.0.0.1\";\n\n    protected URL registryUrl = URL.valueOf(\"nacos://127.0.0.1:\" + NetUtils.getAvailablePort() + \"?nacos.check=false\");\n\n    private NacosServiceDiscovery nacosServiceDiscovery;\n\n    private NacosNamingServiceWrapper namingServiceWrapper;\n\n    protected String group = DEFAULT_GROUP;\n\n    private DefaultServiceInstance createServiceInstance(String serviceName, String host, int port) {\n        return new DefaultServiceInstance(\n                serviceName, host, port, ScopeModelUtil.getApplicationModel(registryUrl.getScopeModel()));\n    }\n\n    public static class NacosServiceDiscoveryGroupTest1 extends NacosServiceDiscoveryTest {\n        public NacosServiceDiscoveryGroupTest1() {\n            super();\n            group = \"test-group1\";\n            registryUrl = URL.valueOf(\"nacos://127.0.0.1:\" + NetUtils.getAvailablePort() + \"?nacos.check=false\")\n                    .addParameter(\"group\", group);\n        }\n    }\n\n    public static class NacosServiceDiscoveryGroupTest2 extends NacosServiceDiscoveryTest {\n        public NacosServiceDiscoveryGroupTest2() {\n            super();\n            group = \"test-group2\";\n            registryUrl = URL.valueOf(\"nacos://127.0.0.1:\" + NetUtils.getAvailablePort() + \"?nacos.check=false\")\n                    .addParameter(\"group\", group);\n        }\n    }\n\n    public static class NacosServiceDiscoveryGroupTest3 extends NacosServiceDiscoveryTest {\n        public NacosServiceDiscoveryGroupTest3() {\n            super();\n            group = DEFAULT_GROUP;\n            registryUrl = URL.valueOf(\"nacos://127.0.0.1:\" + NetUtils.getAvailablePort() + \"?nacos.check=false\")\n                    .addParameter(\"group\", \"test-group3\");\n        }\n\n        @BeforeAll\n        public static void beforeClass() {\n            System.setProperty(\"dubbo.nacos-service-discovery.use-default-group\", \"true\");\n        }\n\n        @AfterAll\n        public static void afterClass() {\n            System.clearProperty(\"dubbo.nacos-service-discovery.use-default-group\");\n        }\n    }\n\n    @BeforeEach\n    public void init() throws Exception {\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(SERVICE_NAME));\n\n        registryUrl.setScopeModel(applicationModel);\n\n        //        this.nacosServiceDiscovery = new NacosServiceDiscovery(SERVICE_NAME, registryUrl);\n        this.nacosServiceDiscovery = new NacosServiceDiscovery(applicationModel, registryUrl);\n        Field namingService = nacosServiceDiscovery.getClass().getDeclaredField(\"namingService\");\n        namingService.setAccessible(true);\n        namingServiceWrapper = mock(NacosNamingServiceWrapper.class);\n        namingService.set(nacosServiceDiscovery, namingServiceWrapper);\n    }\n\n    @AfterEach\n    public void destroy() throws Exception {\n        ApplicationModel.defaultModel().destroy();\n        nacosServiceDiscovery.destroy();\n    }\n\n    @Test\n    void testDoRegister() throws NacosException {\n        DefaultServiceInstance serviceInstance =\n                createServiceInstance(SERVICE_NAME, LOCALHOST, NetUtils.getAvailablePort());\n        // register\n        nacosServiceDiscovery.doRegister(serviceInstance);\n\n        ArgumentCaptor<Instance> instanceCaptor = ArgumentCaptor.forClass(Instance.class);\n        verify(namingServiceWrapper, times(1)).registerInstance(any(), eq(group), instanceCaptor.capture());\n\n        Instance capture = instanceCaptor.getValue();\n        assertEquals(SERVICE_NAME, capture.getServiceName());\n        assertEquals(LOCALHOST, capture.getIp());\n        assertEquals(serviceInstance.getPort(), capture.getPort());\n    }\n\n    @Test\n    void testDoUnRegister() throws NacosException {\n        // register\n        DefaultServiceInstance serviceInstance =\n                createServiceInstance(SERVICE_NAME, LOCALHOST, NetUtils.getAvailablePort());\n        // register\n        nacosServiceDiscovery.doRegister(serviceInstance);\n\n        // unRegister\n        nacosServiceDiscovery.doUnregister(serviceInstance);\n\n        ArgumentCaptor<Instance> instanceCaptor = ArgumentCaptor.forClass(Instance.class);\n        verify(namingServiceWrapper, times(1)).deregisterInstance(any(), eq(group), instanceCaptor.capture());\n\n        Instance capture = instanceCaptor.getValue();\n        assertEquals(SERVICE_NAME, capture.getServiceName());\n        assertEquals(LOCALHOST, capture.getIp());\n        assertEquals(serviceInstance.getPort(), capture.getPort());\n    }\n\n    @Test\n    void testGetServices() throws NacosException {\n        DefaultServiceInstance serviceInstance =\n                createServiceInstance(SERVICE_NAME, LOCALHOST, NetUtils.getAvailablePort());\n        // register\n        nacosServiceDiscovery.doRegister(serviceInstance);\n\n        ArgumentCaptor<Instance> instance = ArgumentCaptor.forClass(Instance.class);\n        verify(namingServiceWrapper, times(1)).registerInstance(any(), eq(group), instance.capture());\n\n        String serviceNameWithoutVersion = \"providers:org.apache.dubbo.registry.nacos.NacosService:default\";\n        String serviceName = \"providers:org.apache.dubbo.registry.nacos.NacosService:1.0.0:default\";\n        List<String> serviceNames = new ArrayList<>();\n        serviceNames.add(serviceNameWithoutVersion);\n        serviceNames.add(serviceName);\n        ListView<String> result = new ListView<>();\n        result.setData(serviceNames);\n        when(namingServiceWrapper.getServicesOfServer(anyInt(), anyInt(), eq(group)))\n                .thenReturn(result);\n        Set<String> services = nacosServiceDiscovery.getServices();\n        assertEquals(2, services.size());\n    }\n\n    @Test\n    void testAddServiceInstancesChangedListener() {\n        List<ServiceInstance> serviceInstances = new LinkedList<>();\n        // Add Listener\n        nacosServiceDiscovery.addServiceInstancesChangedListener(\n                new ServiceInstancesChangedListener(Sets.newSet(SERVICE_NAME), nacosServiceDiscovery) {\n                    @Override\n                    public void onEvent(ServiceInstancesChangedEvent event) {\n                        serviceInstances.addAll(event.getServiceInstances());\n                    }\n                });\n\n        nacosServiceDiscovery.register();\n        nacosServiceDiscovery.update();\n        nacosServiceDiscovery.unregister();\n\n        assertTrue(serviceInstances.isEmpty());\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.nacos.util;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.nacos.MockNamingService;\nimport org.apache.dubbo.registry.nacos.NacosNamingServiceWrapper;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.alibaba.nacos.api.NacosFactory;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.DOWN;\nimport static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test for NacosNamingServiceUtils\n */\nclass NacosNamingServiceUtilsTest {\n    private static MetadataReport metadataReport = Mockito.mock(MetadataReport.class);\n\n    @Test\n    void testToInstance() {\n        ServiceInstance serviceInstance = mock(ServiceInstance.class);\n        Instance instance = NacosNamingServiceUtils.toInstance(serviceInstance);\n        Assertions.assertNotNull(instance);\n    }\n\n    @Test\n    void testToServiceInstance() {\n        URL registryUrl = URL.valueOf(\"nacos://127.0.0.1:8080/test\");\n        Instance instance = new Instance();\n        instance.setServiceName(\"serviceName\");\n        instance.setIp(\"1.1.1.1\");\n        instance.setPort(800);\n        instance.setWeight(2);\n        instance.setHealthy(Boolean.TRUE);\n        instance.setEnabled(Boolean.TRUE);\n        Map<String, String> map = new HashMap<String, String>();\n        map.put(\"netType\", \"external\");\n        map.put(\"version\", \"2.0\");\n        instance.setMetadata(map);\n\n        ServiceInstance serviceInstance = NacosNamingServiceUtils.toServiceInstance(registryUrl, instance);\n        Assertions.assertNotNull(serviceInstance);\n        Assertions.assertEquals(serviceInstance.isEnabled(), Boolean.TRUE);\n        Assertions.assertEquals(serviceInstance.getServiceName(), \"serviceName\");\n    }\n\n    @Test\n    void testCreateNamingService() {\n        URL url = URL.valueOf(\"nacos://127.0.0.1:8080/test?backup=127.0.0.1&nacos.check=false\");\n        NacosNamingServiceWrapper namingService = NacosNamingServiceUtils.createNamingService(url);\n        Assertions.assertNotNull(namingService);\n    }\n\n    @Test\n    void testRetryCreate() throws NacosException {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            AtomicInteger atomicInteger = new AtomicInteger(0);\n            NamingService mock = new MockNamingService() {\n                @Override\n                public String getServerStatus() {\n                    return atomicInteger.incrementAndGet() > 10 ? UP : DOWN;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createNamingService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10);\n            Assertions.assertThrows(\n                    IllegalStateException.class, () -> NacosNamingServiceUtils.createNamingService(url));\n\n            try {\n                NacosNamingServiceUtils.createNamingService(url);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n\n    @Test\n    void testDisable() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            NamingService mock = new MockNamingService() {\n                @Override\n                public String getServerStatus() {\n                    return DOWN;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createNamingService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10)\n                    .addParameter(\"nacos.check\", \"false\");\n            try {\n                NacosNamingServiceUtils.createNamingService(url);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n\n    @Test\n    void testRequest() {\n        try (MockedStatic<NacosFactory> nacosFactoryMockedStatic = Mockito.mockStatic(NacosFactory.class)) {\n            AtomicInteger atomicInteger = new AtomicInteger(0);\n            NamingService mock = new MockNamingService() {\n                @Override\n                public List<Instance> getAllInstances(String serviceName, boolean subscribe) throws NacosException {\n                    if (atomicInteger.incrementAndGet() > 10) {\n                        return null;\n                    } else {\n                        throw new NacosException();\n                    }\n                }\n\n                @Override\n                public String getServerStatus() {\n                    return UP;\n                }\n            };\n            nacosFactoryMockedStatic\n                    .when(() -> NacosFactory.createNamingService((Properties) any()))\n                    .thenReturn(mock);\n\n            URL url = URL.valueOf(\"nacos://127.0.0.1:8848\")\n                    .addParameter(\"nacos.retry\", 5)\n                    .addParameter(\"nacos.retry-wait\", 10);\n            Assertions.assertThrows(\n                    IllegalStateException.class, () -> NacosNamingServiceUtils.createNamingService(url));\n\n            try {\n                NacosNamingServiceUtils.createNamingService(url);\n            } catch (Throwable t) {\n                Assertions.fail(t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-nacos/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-registry</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-registry-zookeeper</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The zookeeper registry module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-registry-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-zookeeper-curator5</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.curator</groupId>\n      <artifactId>curator-x-discovery</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperInstance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Represents the default payload of a registered service in Zookeeper.\n * <p>\n * It's compatible with Spring Cloud\n *\n * @since 2.7.5\n */\npublic class ZookeeperInstance {\n\n    private String id;\n\n    private String name;\n\n    private Map<String, String> metadata = new HashMap<>();\n\n    @SuppressWarnings(\"unused\")\n    private ZookeeperInstance() {}\n\n    public ZookeeperInstance(String id, String name, Map<String, String> metadata) {\n        this.id = id;\n        this.name = name;\n        this.metadata = metadata;\n    }\n\n    public String getId() {\n        return this.id;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Map<String, String> getMetadata() {\n        return this.metadata;\n    }\n\n    public void setMetadata(Map<String, String> metadata) {\n        this.metadata = metadata;\n    }\n\n    @Override\n    public String toString() {\n        return \"ZookeeperInstance{\" + \"id='\" + this.id + '\\'' + \", name='\" + this.name + '\\'' + \", metadata=\"\n                + this.metadata + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.registry.support.CacheableFailbackRegistry;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ChildListener;\nimport org.apache.dubbo.remoting.zookeeper.curator5.StateListener;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClient;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClientManager;\nimport org.apache.dubbo.rpc.RpcException;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.CountDownLatch;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_ERROR_DESERIALIZE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_ZOOKEEPER_EXCEPTION;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;\nimport static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;\n\npublic class ZookeeperRegistry extends CacheableFailbackRegistry {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ZookeeperRegistry.class);\n\n    private static final String DEFAULT_ROOT = \"dubbo\";\n\n    private final String root;\n\n    private final Set<String> anyServices = new ConcurrentHashSet<>();\n\n    private final ConcurrentMap<URL, ConcurrentMap<NotifyListener, ChildListener>> zkListeners =\n            new ConcurrentHashMap<>();\n\n    private ZookeeperClient zkClient;\n\n    public ZookeeperRegistry(URL url, ZookeeperClientManager zookeeperClientManager) {\n        super(url);\n\n        if (url.isAnyHost()) {\n            throw new IllegalStateException(\"registry address == null\");\n        }\n\n        String group = url.getGroup(DEFAULT_ROOT);\n        if (!group.startsWith(PATH_SEPARATOR)) {\n            group = PATH_SEPARATOR + group;\n        }\n\n        this.root = group;\n        this.zkClient = zookeeperClientManager.connect(url);\n\n        this.zkClient.addStateListener((state) -> {\n            if (state == StateListener.RECONNECTED) {\n                logger.warn(\n                        REGISTRY_ZOOKEEPER_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Trying to fetch the latest urls, in case there are provider changes during connection loss.\\n\"\n                                + \" Since ephemeral ZNode will not get deleted for a connection lose, \"\n                                + \"there's no need to re-register url of this instance.\");\n                ZookeeperRegistry.this.fetchLatestAddresses();\n            } else if (state == StateListener.NEW_SESSION_CREATED) {\n                logger.warn(\n                        REGISTRY_ZOOKEEPER_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Trying to re-register urls and re-subscribe listeners of this instance to registry...\");\n\n                try {\n                    ZookeeperRegistry.this.recover();\n                } catch (Exception e) {\n                    logger.error(REGISTRY_ZOOKEEPER_EXCEPTION, \"\", \"\", e.getMessage(), e);\n                }\n            } else if (state == StateListener.SESSION_LOST) {\n                logger.warn(\n                        REGISTRY_ZOOKEEPER_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Url of this instance will be deleted from registry soon. \"\n                                + \"Dubbo client will try to re-register once a new session is created.\");\n            } else if (state == StateListener.SUSPENDED) {\n\n            } else if (state == StateListener.CONNECTED) {\n\n            }\n        });\n    }\n\n    @Override\n    public boolean isAvailable() {\n        return zkClient != null && zkClient.isConnected();\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n\n        // remove child listener\n        Set<URL> urls = zkListeners.keySet();\n        for (URL url : urls) {\n            ConcurrentMap<NotifyListener, ChildListener> map = zkListeners.get(url);\n            if (CollectionUtils.isEmptyMap(map)) {\n                continue;\n            }\n            Collection<ChildListener> childListeners = map.values();\n            if (CollectionUtils.isEmpty(childListeners)) {\n                continue;\n            }\n            if (ANY_VALUE.equals(url.getServiceInterface())) {\n                String root = toRootPath();\n                childListeners.stream().forEach(childListener -> zkClient.removeChildListener(root, childListener));\n            } else {\n                for (String path : toCategoriesPath(url)) {\n                    childListeners.stream().forEach(childListener -> zkClient.removeChildListener(path, childListener));\n                }\n            }\n        }\n        zkListeners.clear();\n\n        // Just release zkClient reference, but can not close zk client here for zk client is shared somewhere else.\n        // See org.apache.dubbo.remoting.zookeeper.AbstractZookeeperTransporter#destroy()\n        zkClient = null;\n    }\n\n    private void checkDestroyed() {\n        if (zkClient == null) {\n            throw new IllegalStateException(\"registry is destroyed\");\n        }\n    }\n\n    @Override\n    public void doRegister(URL url) {\n        try {\n            checkDestroyed();\n            zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true), true);\n        } catch (Throwable e) {\n            throw new RpcException(\n                    \"Failed to register \" + url + \" to zookeeper \" + getUrl() + \", cause: \" + e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public void doUnregister(URL url) {\n        try {\n            checkDestroyed();\n            zkClient.delete(toUrlPath(url));\n        } catch (Throwable e) {\n            throw new RpcException(\n                    \"Failed to unregister \" + url + \" to zookeeper \" + getUrl() + \", cause: \" + e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public void doSubscribe(final URL url, final NotifyListener listener) {\n        try {\n            checkDestroyed();\n            if (ANY_VALUE.equals(url.getServiceInterface())) {\n                String root = toRootPath();\n                boolean check = url.getParameter(CHECK_KEY, false);\n                ConcurrentMap<NotifyListener, ChildListener> listeners =\n                        ConcurrentHashMapUtils.computeIfAbsent(zkListeners, url, k -> new ConcurrentHashMap<>());\n\n                ChildListener zkListener = ConcurrentHashMapUtils.computeIfAbsent(\n                        listeners, listener, k -> (parentPath, currentChildren) -> {\n                            for (String child : currentChildren) {\n                                try {\n                                    child = URL.decode(child);\n                                    if (!(JsonUtils.checkJson(child))) {\n                                        throw new Exception(\"dubbo-admin subscribe \" + child + \" failed, because \"\n                                                + child + \"is root path in \" + url);\n                                    }\n                                } catch (Exception e) {\n                                    logger.warn(PROTOCOL_ERROR_DESERIALIZE, \"\", \"\", e.getMessage());\n                                }\n                                if (!anyServices.contains(child)) {\n                                    anyServices.add(child);\n                                    subscribe(\n                                            url.setPath(child)\n                                                    .addParameters(\n                                                            INTERFACE_KEY,\n                                                            child,\n                                                            Constants.CHECK_KEY,\n                                                            String.valueOf(check)),\n                                            k);\n                                }\n                            }\n                        });\n\n                zkClient.create(root, false, true);\n\n                List<String> services = zkClient.addChildListener(root, zkListener);\n                if (CollectionUtils.isNotEmpty(services)) {\n                    for (String service : services) {\n                        service = URL.decode(service);\n                        anyServices.add(service);\n                        subscribe(\n                                url.setPath(service)\n                                        .addParameters(\n                                                INTERFACE_KEY, service, Constants.CHECK_KEY, String.valueOf(check)),\n                                listener);\n                    }\n                }\n            } else {\n                CountDownLatch latch = new CountDownLatch(1);\n\n                try {\n                    List<URL> urls = new ArrayList<>();\n\n                    /*\n                        Iterate over the category value in URL.\n                        With default settings, the path variable can be when url is a consumer URL:\n\n                            /dubbo/[service name]/providers,\n                            /dubbo/[service name]/configurators\n                            /dubbo/[service name]/routers\n                    */\n                    for (String path : toCategoriesPath(url)) {\n                        ConcurrentMap<NotifyListener, ChildListener> listeners = ConcurrentHashMapUtils.computeIfAbsent(\n                                zkListeners, url, k -> new ConcurrentHashMap<>());\n                        ChildListener zkListener = ConcurrentHashMapUtils.computeIfAbsent(\n                                listeners, listener, k -> new RegistryChildListenerImpl(url, k, latch));\n\n                        if (zkListener instanceof RegistryChildListenerImpl) {\n                            ((RegistryChildListenerImpl) zkListener).setLatch(latch);\n                        }\n\n                        // create \"directories\".\n                        zkClient.create(path, false, true);\n\n                        // Add children (i.e. service items).\n                        List<String> children = zkClient.addChildListener(path, zkListener);\n                        if (children != null) {\n                            // The invocation point that may cause 1-1.\n                            urls.addAll(toUrlsWithEmpty(url, path, children));\n                        }\n                    }\n\n                    notify(url, listener, urls);\n                } finally {\n                    // tells the listener to run only after the sync notification of main thread finishes.\n                    latch.countDown();\n                }\n            }\n        } catch (Throwable e) {\n            throw new RpcException(\n                    \"Failed to subscribe \" + url + \" to zookeeper \" + getUrl() + \", cause: \" + e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public void doUnsubscribe(URL url, NotifyListener listener) {\n        super.doUnsubscribe(url, listener);\n        checkDestroyed();\n        ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);\n        if (listeners != null) {\n            ChildListener zkListener = listeners.remove(listener);\n            if (zkListener != null) {\n                if (ANY_VALUE.equals(url.getServiceInterface())) {\n                    String root = toRootPath();\n                    zkClient.removeChildListener(root, zkListener);\n                } else {\n                    for (String path : toCategoriesPath(url)) {\n                        zkClient.removeChildListener(path, zkListener);\n                    }\n                }\n            }\n\n            if (listeners.isEmpty()) {\n                zkListeners.remove(url);\n            }\n        }\n    }\n\n    @Override\n    public List<URL> lookup(URL url) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"lookup url == null\");\n        }\n        try {\n            checkDestroyed();\n            List<String> providers = new ArrayList<>();\n            for (String path : toCategoriesPath(url)) {\n                List<String> children = zkClient.getChildren(path);\n                if (children != null) {\n                    providers.addAll(children);\n                }\n            }\n            return toUrlsWithoutEmpty(url, providers);\n        } catch (Throwable e) {\n            throw new RpcException(\n                    \"Failed to lookup \" + url + \" from zookeeper \" + getUrl() + \", cause: \" + e.getMessage(), e);\n        }\n    }\n\n    private String toRootDir() {\n        if (root.equals(PATH_SEPARATOR)) {\n            return root;\n        }\n        return root + PATH_SEPARATOR;\n    }\n\n    private String toRootPath() {\n        return root;\n    }\n\n    private String toServicePath(URL url) {\n        String name = url.getServiceInterface();\n        if (ANY_VALUE.equals(name)) {\n            return toRootPath();\n        }\n        return toRootDir() + URL.encode(name);\n    }\n\n    private String[] toCategoriesPath(URL url) {\n        String[] categories;\n        if (ANY_VALUE.equals(url.getCategory())) {\n            categories =\n                    new String[] {PROVIDERS_CATEGORY, CONSUMERS_CATEGORY, ROUTERS_CATEGORY, CONFIGURATORS_CATEGORY};\n        } else {\n            categories = url.getCategory(new String[] {DEFAULT_CATEGORY});\n        }\n        String[] paths = new String[categories.length];\n        for (int i = 0; i < categories.length; i++) {\n            paths[i] = toServicePath(url) + PATH_SEPARATOR + categories[i];\n        }\n        return paths;\n    }\n\n    private String toCategoryPath(URL url) {\n        return toServicePath(url) + PATH_SEPARATOR + url.getCategory(DEFAULT_CATEGORY);\n    }\n\n    private String toUrlPath(URL url) {\n        return toCategoryPath(url) + PATH_SEPARATOR + URL.encode(url.toFullString());\n    }\n\n    /**\n     * When zookeeper connection recovered from a connection loss, it needs to fetch the latest provider list.\n     * re-register watcher is only a side effect and is not mandate.\n     */\n    private void fetchLatestAddresses() {\n        // subscribe\n        Map<URL, Set<NotifyListener>> recoverSubscribed = new HashMap<>(getSubscribed());\n        if (!recoverSubscribed.isEmpty()) {\n            if (logger.isInfoEnabled()) {\n                logger.info(\"Fetching the latest urls of \" + recoverSubscribed.keySet());\n            }\n            for (Map.Entry<URL, Set<NotifyListener>> entry : recoverSubscribed.entrySet()) {\n                URL url = entry.getKey();\n                for (NotifyListener listener : entry.getValue()) {\n                    removeFailedSubscribed(url, listener);\n                    addFailedSubscribed(url, listener);\n                }\n            }\n        }\n    }\n\n    @Override\n    protected boolean isMatch(URL subscribeUrl, URL providerUrl) {\n        return UrlUtils.isMatch(subscribeUrl, providerUrl);\n    }\n\n    /**\n     * Triggered when children get changed. It will be invoked by implementation of CuratorWatcher.\n     * <p>\n     * 'org.apache.dubbo.remoting.zookeeper.curator5.Curator5ZookeeperClient.CuratorWatcherImpl' (Curator 5)\n     */\n    private class RegistryChildListenerImpl implements ChildListener {\n        private final ZookeeperRegistryNotifier notifier;\n        private volatile CountDownLatch latch;\n\n        public RegistryChildListenerImpl(URL consumerUrl, NotifyListener listener, CountDownLatch latch) {\n            this.latch = latch;\n            this.notifier = new ZookeeperRegistryNotifier(consumerUrl, listener, ZookeeperRegistry.this.getDelay());\n        }\n\n        public void setLatch(CountDownLatch latch) {\n            this.latch = latch;\n        }\n\n        @Override\n        public void childChanged(String path, List<String> children) {\n            // Notify 'notifiers' one by one.\n            try {\n                latch.await();\n            } catch (InterruptedException e) {\n                logger.warn(\n                        REGISTRY_ZOOKEEPER_EXCEPTION,\n                        \"\",\n                        \"\",\n                        \"Zookeeper children listener thread was interrupted unexpectedly, may cause race condition with the main thread.\");\n            }\n\n            notifier.notify(path, children);\n        }\n    }\n\n    /**\n     * Customized Registry Notifier for zookeeper registry.\n     */\n    public class ZookeeperRegistryNotifier {\n        private long lastExecuteTime;\n        private final URL consumerUrl;\n        private final NotifyListener listener;\n        private final long delayTime;\n\n        public ZookeeperRegistryNotifier(URL consumerUrl, NotifyListener listener, long delayTime) {\n            this.consumerUrl = consumerUrl;\n            this.listener = listener;\n            this.delayTime = delayTime;\n        }\n\n        public void notify(String path, Object rawAddresses) {\n            // notify immediately if it's notification of governance rules.\n            if (path.endsWith(CONFIGURATORS_CATEGORY) || path.endsWith(ROUTERS_CATEGORY)) {\n                this.doNotify(path, rawAddresses);\n            }\n\n            // if address notification, check if delay is necessary.\n            if (delayTime <= 0) {\n                this.doNotify(path, rawAddresses);\n            } else {\n                long interval = delayTime - (System.currentTimeMillis() - lastExecuteTime);\n                if (interval > 0) {\n                    try {\n                        Thread.sleep(interval);\n                    } catch (InterruptedException e) {\n                        // ignore\n                    }\n                }\n                lastExecuteTime = System.currentTimeMillis();\n                this.doNotify(path, rawAddresses);\n            }\n        }\n\n        protected void doNotify(String path, Object rawAddresses) {\n            ZookeeperRegistry.this.notify(\n                    consumerUrl, listener, ZookeeperRegistry.this.toUrlsWithEmpty(consumerUrl, path, (List<String>)\n                            rawAddresses));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperRegistryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.DisableInject;\nimport org.apache.dubbo.registry.Registry;\nimport org.apache.dubbo.registry.support.AbstractRegistryFactory;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClientManager;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\n/**\n * ZookeeperRegistryFactory.\n */\npublic class ZookeeperRegistryFactory extends AbstractRegistryFactory {\n\n    private ZookeeperClientManager zookeeperClientManager;\n\n    // for compatible usage\n    public ZookeeperRegistryFactory() {\n        this(ApplicationModel.defaultModel());\n    }\n\n    public ZookeeperRegistryFactory(ApplicationModel applicationModel) {\n        this.applicationModel = applicationModel;\n        this.zookeeperClientManager = ZookeeperClientManager.getInstance(applicationModel);\n    }\n\n    @DisableInject\n    public void setZookeeperTransporter(ZookeeperClientManager zookeeperClientManager) {\n        this.zookeeperClientManager = zookeeperClientManager;\n    }\n\n    @Override\n    public Registry createRegistry(URL url) {\n        return new ZookeeperRegistry(url, zookeeperClientManager);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscovery.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.function.ThrowableConsumer;\nimport org.apache.dubbo.common.function.ThrowableFunction;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.io.IOException;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.api.CuratorWatcher;\nimport org.apache.curator.x.discovery.ServiceCache;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_ZOOKEEPER_EXCEPTION;\nimport static org.apache.dubbo.common.function.ThrowableFunction.execute;\nimport static org.apache.dubbo.metadata.RevisionResolver.EMPTY_REVISION;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getExportedServicesRevision;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkUtils.build;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkUtils.buildCuratorFramework;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkUtils.buildServiceDiscovery;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkUtils.getRootPath;\nimport static org.apache.dubbo.rpc.RpcException.REGISTRY_EXCEPTION;\n\n/**\n * Zookeeper {@link ServiceDiscovery} implementation based on\n * <a href=\"https://curator.apache.org/curator-x-discovery/index.html\">Apache Curator X Discovery</a>\n * <p>\n * TODO, replace curator CuratorFramework with dubbo ZookeeperClient\n */\npublic class ZookeeperServiceDiscovery extends AbstractServiceDiscovery {\n\n    private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    public static final String DEFAULT_GROUP = \"/services\";\n\n    private final CuratorFramework curatorFramework;\n\n    private final String rootPath;\n\n    private final org.apache.curator.x.discovery.ServiceDiscovery<ZookeeperInstance> serviceDiscovery;\n\n    /**\n     * The Key is watched Zookeeper path, the value is an instance of {@link CuratorWatcher}\n     */\n    private final ConcurrentHashMap<String, ZookeeperServiceDiscoveryChangeWatcher> watcherCaches =\n            new ConcurrentHashMap<>();\n\n    public ZookeeperServiceDiscovery(ApplicationModel applicationModel, URL registryURL) {\n        super(applicationModel, registryURL);\n        try {\n            this.curatorFramework = buildCuratorFramework(registryURL, this);\n            this.rootPath = getRootPath(registryURL);\n            this.serviceDiscovery = buildServiceDiscovery(curatorFramework, rootPath);\n            this.serviceDiscovery.start();\n        } catch (Exception e) {\n            throw new IllegalStateException(\"Create zookeeper service discovery failed.\", e);\n        }\n    }\n\n    @Override\n    public void doDestroy() throws Exception {\n        serviceDiscovery.close();\n        curatorFramework.close();\n        watcherCaches.clear();\n    }\n\n    @Override\n    public void doRegister(ServiceInstance serviceInstance) {\n        try {\n            serviceDiscovery.registerService(build(serviceInstance));\n        } catch (Exception e) {\n            throw new RpcException(REGISTRY_EXCEPTION, \"Failed register instance \" + serviceInstance.toString(), e);\n        }\n    }\n\n    @Override\n    public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException {\n        if (serviceInstance != null) {\n            doInServiceRegistry(serviceDiscovery -> serviceDiscovery.unregisterService(build(serviceInstance)));\n        }\n    }\n\n    @Override\n    protected void doUpdate(ServiceInstance oldServiceInstance, ServiceInstance newServiceInstance)\n            throws RuntimeException {\n        if (EMPTY_REVISION.equals(getExportedServicesRevision(newServiceInstance))\n                || EMPTY_REVISION.equals(\n                        oldServiceInstance.getMetadata().get(EXPORTED_SERVICES_REVISION_PROPERTY_NAME))) {\n            super.doUpdate(oldServiceInstance, newServiceInstance);\n            return;\n        }\n\n        org.apache.curator.x.discovery.ServiceInstance<ZookeeperInstance> oldInstance = build(oldServiceInstance);\n        org.apache.curator.x.discovery.ServiceInstance<ZookeeperInstance> newInstance = build(newServiceInstance);\n        if (!Objects.equals(newInstance.getName(), oldInstance.getName())\n                || !Objects.equals(newInstance.getId(), oldInstance.getId())) {\n            // Ignore if id changed. Should unregister first.\n            super.doUpdate(oldServiceInstance, newServiceInstance);\n            return;\n        }\n\n        try {\n            this.serviceInstance = newServiceInstance;\n            reportMetadata(newServiceInstance.getServiceMetadata());\n            serviceDiscovery.updateService(newInstance);\n        } catch (Exception e) {\n            throw new RpcException(REGISTRY_EXCEPTION, \"Failed register instance \" + newServiceInstance.toString(), e);\n        }\n    }\n\n    @Override\n    public Set<String> getServices() {\n        return doInServiceDiscovery(s -> new LinkedHashSet<>(s.queryForNames()));\n    }\n\n    @Override\n    public List<ServiceInstance> getInstances(String serviceName) throws NullPointerException {\n        return doInServiceDiscovery(s -> build(registryURL, s.queryForInstances(serviceName)));\n    }\n\n    @Override\n    public void addServiceInstancesChangedListener(ServiceInstancesChangedListener listener)\n            throws NullPointerException, IllegalArgumentException {\n        // check if listener has already been added through another interface/service\n        if (!instanceListeners.add(listener)) {\n            return;\n        }\n        listener.getServiceNames().forEach(serviceName -> registerServiceWatcher(serviceName, listener));\n    }\n\n    @Override\n    public void removeServiceInstancesChangedListener(ServiceInstancesChangedListener listener)\n            throws IllegalArgumentException {\n        if (!instanceListeners.remove(listener)) {\n            return;\n        }\n        listener.getServiceNames().forEach(serviceName -> {\n            ZookeeperServiceDiscoveryChangeWatcher watcher = watcherCaches.get(serviceName);\n            if (watcher != null) {\n                watcher.getListeners().remove(listener);\n                if (watcher.getListeners().isEmpty()) {\n                    watcherCaches.remove(serviceName);\n                    try {\n                        watcher.getCacheInstance().close();\n                    } catch (IOException e) {\n                        logger.error(\n                                REGISTRY_ZOOKEEPER_EXCEPTION,\n                                \"curator stop watch failed\",\n                                \"\",\n                                \"Curator Stop service discovery watch failed. Service Name: \" + serviceName);\n                    }\n                }\n            }\n        });\n    }\n\n    @Override\n    public boolean isAvailable() {\n        // Fix the issue of timeout for all calls to the isAvailable method after the zookeeper is disconnected\n        return !isDestroy() && isConnected() && CollectionUtils.isNotEmpty(getServices());\n    }\n\n    private boolean isConnected() {\n        if (curatorFramework == null || curatorFramework.getZookeeperClient() == null) {\n            return false;\n        }\n        return curatorFramework.getZookeeperClient().isConnected();\n    }\n\n    private void doInServiceRegistry(ThrowableConsumer<org.apache.curator.x.discovery.ServiceDiscovery> consumer) {\n        ThrowableConsumer.execute(serviceDiscovery, s -> consumer.accept(s));\n    }\n\n    private <R> R doInServiceDiscovery(ThrowableFunction<org.apache.curator.x.discovery.ServiceDiscovery, R> function) {\n        return execute(serviceDiscovery, function);\n    }\n\n    protected void registerServiceWatcher(String serviceName, ServiceInstancesChangedListener listener) {\n        CountDownLatch latch = new CountDownLatch(1);\n\n        ZookeeperServiceDiscoveryChangeWatcher watcher =\n                ConcurrentHashMapUtils.computeIfAbsent(watcherCaches, serviceName, name -> {\n                    ServiceCache<ZookeeperInstance> serviceCache =\n                            serviceDiscovery.serviceCacheBuilder().name(name).build();\n                    ZookeeperServiceDiscoveryChangeWatcher newer =\n                            new ZookeeperServiceDiscoveryChangeWatcher(this, serviceCache, name, latch);\n                    serviceCache.addListener(newer);\n\n                    try {\n                        serviceCache.start();\n                    } catch (Exception e) {\n                        throw new RpcException(REGISTRY_EXCEPTION, \"Failed subscribe service: \" + name, e);\n                    }\n\n                    return newer;\n                });\n\n        watcher.addListener(listener);\n        listener.onEvent(new ServiceInstancesChangedEvent(serviceName, this.getInstances(serviceName)));\n        latch.countDown();\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryChangeWatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper;\n\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.registry.RegistryNotifier;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.api.CuratorWatcher;\nimport org.apache.curator.framework.state.ConnectionState;\nimport org.apache.curator.x.discovery.ServiceCache;\nimport org.apache.curator.x.discovery.details.ServiceCacheListener;\nimport org.apache.zookeeper.Watcher;\n\n/**\n * Zookeeper {@link ServiceDiscovery} Change {@link CuratorWatcher watcher} only interests in\n * {@link Watcher.Event.EventType#NodeChildrenChanged} and {@link Watcher.Event.EventType#NodeDataChanged} event types,\n * which will multicast a {@link ServiceInstancesChangedEvent} when the service node has been changed.\n *\n * @since 2.7.5\n */\npublic class ZookeeperServiceDiscoveryChangeWatcher implements ServiceCacheListener {\n    private final Set<ServiceInstancesChangedListener> listeners = new ConcurrentHashSet<>();\n\n    private final ServiceCache<ZookeeperInstance> cacheInstance;\n\n    private final ZookeeperServiceDiscovery zookeeperServiceDiscovery;\n\n    private final RegistryNotifier notifier;\n\n    private final String serviceName;\n\n    private final CountDownLatch latch;\n\n    public ZookeeperServiceDiscoveryChangeWatcher(\n            ZookeeperServiceDiscovery zookeeperServiceDiscovery,\n            ServiceCache<ZookeeperInstance> cacheInstance,\n            String serviceName,\n            CountDownLatch latch) {\n        this.zookeeperServiceDiscovery = zookeeperServiceDiscovery;\n        this.cacheInstance = cacheInstance;\n        this.serviceName = serviceName;\n        this.notifier =\n                new RegistryNotifier(\n                        zookeeperServiceDiscovery.getUrl(),\n                        zookeeperServiceDiscovery.getDelay(),\n                        ScopeModelUtil.getFrameworkModel(\n                                        zookeeperServiceDiscovery.getUrl().getScopeModel())\n                                .getBeanFactory()\n                                .getBean(FrameworkExecutorRepository.class)\n                                .getServiceDiscoveryAddressNotificationExecutor()) {\n                    @Override\n                    protected void doNotify(Object rawAddresses) {\n                        listeners.forEach(listener -> listener.onEvent((ServiceInstancesChangedEvent) rawAddresses));\n                    }\n                };\n        this.latch = latch;\n    }\n\n    @Override\n    public void cacheChanged() {\n        try {\n            latch.await();\n        } catch (InterruptedException ignore) {\n            Thread.currentThread().interrupt();\n        }\n\n        List<ServiceInstance> instanceList = zookeeperServiceDiscovery.getInstances(serviceName);\n        notifier.notify(new ServiceInstancesChangedEvent(serviceName, instanceList));\n    }\n\n    @Override\n    public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {\n        // ignore: taken care by curator ServiceDiscovery\n    }\n\n    public ServiceCache<ZookeeperInstance> getCacheInstance() {\n        return cacheInstance;\n    }\n\n    public Set<ServiceInstancesChangedListener> getListeners() {\n        return listeners;\n    }\n\n    public void addListener(ServiceInstancesChangedListener listener) {\n        listeners.add(listener);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.AbstractServiceDiscoveryFactory;\nimport org.apache.dubbo.registry.client.ServiceDiscovery;\n\npublic class ZookeeperServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory {\n\n    @Override\n    protected ServiceDiscovery createDiscovery(URL registryURL) {\n        return new ZookeeperServiceDiscovery(applicationModel, registryURL);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/aot/ZookeeperReflectionTypeDescriberRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper.aot;\n\nimport org.apache.dubbo.aot.api.MemberCategory;\nimport org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar;\nimport org.apache.dubbo.aot.api.TypeDescriber;\nimport org.apache.dubbo.registry.zookeeper.ZookeeperInstance;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class ZookeeperReflectionTypeDescriberRegistrar implements ReflectionTypeDescriberRegistrar {\n\n    @Override\n    public List<TypeDescriber> getTypeDescribers() {\n        List<TypeDescriber> typeDescribers = new ArrayList<>();\n        typeDescribers.add(buildTypeDescriberWithDeclared(ZookeeperInstance.class));\n\n        return typeDescribers;\n    }\n\n    private TypeDescriber buildTypeDescriberWithDeclared(Class<?> cl) {\n        Set<MemberCategory> memberCategories = new HashSet<>();\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_METHODS);\n        memberCategories.add(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n        memberCategories.add(MemberCategory.DECLARED_FIELDS);\n        return new TypeDescriber(\n                cl.getName(), null, new HashSet<>(), new HashSet<>(), new HashSet<>(), memberCategories);\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/util/CuratorFrameworkParams.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper.util;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.client.ServiceInstance;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Function;\n\nimport org.apache.curator.framework.CuratorFramework;\n\nimport static org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery.DEFAULT_GROUP;\n\n/**\n * The enumeration for the parameters  of {@link CuratorFramework}\n *\n * @see CuratorFramework\n * @since 2.7.5\n */\npublic enum CuratorFrameworkParams {\n    /**\n     * The root path of Dubbo Service\n     */\n    ROOT_PATH(\"rootPath\", DEFAULT_GROUP, value -> value),\n\n    GROUP_PATH(\"group\", DEFAULT_GROUP, value -> value),\n\n    /**\n     * The host of current {@link ServiceInstance service instance} that will be registered\n     */\n    INSTANCE_HOST(\"instanceHost\", null, value -> value),\n\n    /**\n     * The port of current {@link ServiceInstance service instance} that will be registered\n     */\n    INSTANCE_PORT(\"instancePort\", null, value -> value),\n\n    /**\n     * Initial amount of time to wait between retries\n     */\n    BASE_SLEEP_TIME(\"baseSleepTimeMs\", 50, Integer::valueOf),\n\n    /**\n     * Max number of times to retry.\n     */\n    MAX_RETRIES(\"maxRetries\", 10, Integer::valueOf),\n\n    /**\n     * Max time in ms to sleep on each retry.\n     */\n    MAX_SLEEP(\"maxSleepMs\", 500, Integer::valueOf),\n\n    /**\n     * Wait time to block on connection to Zookeeper.\n     */\n    BLOCK_UNTIL_CONNECTED_WAIT(\"blockUntilConnectedWait\", 10, Integer::valueOf),\n\n    /**\n     * The unit of time related to blocking on connection to Zookeeper.\n     */\n    BLOCK_UNTIL_CONNECTED_UNIT(\"blockUntilConnectedUnit\", TimeUnit.SECONDS, TimeUnit::valueOf),\n    ;\n\n    private final String name;\n\n    private final Object defaultValue;\n\n    private final Function<String, Object> converter;\n\n    <T> CuratorFrameworkParams(String name, T defaultValue, Function<String, T> converter) {\n        this.name = name;\n        this.defaultValue = defaultValue;\n        this.converter = (Function<String, Object>) converter;\n    }\n\n    /**\n     * Get the parameter value from the specified {@link URL}\n     *\n     * @param url the Dubbo registry {@link URL}\n     * @param <T> the type of value\n     * @return the parameter value if present, or return <code>null</code>\n     */\n    public <T> T getParameterValue(URL url) {\n        String param = url.getParameter(name);\n        Object value = param != null ? converter.apply(param) : defaultValue;\n        return (T) value;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/util/CuratorFrameworkUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper.util;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.UrlUtils;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.zookeeper.ZookeeperInstance;\nimport org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.lang.reflect.Method;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.apache.curator.RetryPolicy;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.framework.CuratorFrameworkFactory.Builder;\nimport org.apache.curator.framework.api.ACLProvider;\nimport org.apache.curator.framework.imps.CuratorFrameworkState;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.x.discovery.ServiceDiscovery;\nimport org.apache.curator.x.discovery.ServiceDiscoveryBuilder;\nimport org.apache.curator.x.discovery.ServiceInstanceBuilder;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.data.ACL;\n\nimport static org.apache.curator.x.discovery.ServiceInstance.builder;\nimport static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.SESSION_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ZOOKEEPER_ENSEMBLE_TRACKER_KEY;\nimport static org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery.DEFAULT_GROUP;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkParams.BASE_SLEEP_TIME;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkParams.BLOCK_UNTIL_CONNECTED_UNIT;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkParams.BLOCK_UNTIL_CONNECTED_WAIT;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkParams.GROUP_PATH;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkParams.MAX_RETRIES;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkParams.MAX_SLEEP;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkParams.ROOT_PATH;\n\n/**\n * Curator Framework Utilities Class\n *\n * @since 2.7.5\n */\npublic abstract class CuratorFrameworkUtils {\n\n    protected static int DEFAULT_SESSION_TIMEOUT_MS = 60 * 1000;\n\n    public static ServiceDiscovery<ZookeeperInstance> buildServiceDiscovery(\n            CuratorFramework curatorFramework, String basePath) {\n        return ServiceDiscoveryBuilder.builder(ZookeeperInstance.class)\n                .client(curatorFramework)\n                .basePath(basePath)\n                .build();\n    }\n\n    public static CuratorFramework buildCuratorFramework(URL connectionURL, ZookeeperServiceDiscovery serviceDiscovery)\n            throws Exception {\n        int sessionTimeoutMs = connectionURL.getParameter(SESSION_KEY, DEFAULT_SESSION_TIMEOUT_MS);\n        CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()\n                .connectString(connectionURL.getBackupAddress())\n                .sessionTimeoutMs(sessionTimeoutMs)\n                .retryPolicy(buildRetryPolicy(connectionURL));\n        try {\n            // use reflect to check method exist to compatibility with curator4, can remove in dubbo3.3 and direct call\n            // the method because 3.3 only supported curator5\n            Class<? extends Builder> builderClass = builder.getClass();\n            Method ignore = builderClass.getMethod(\"ensembleTracker\", boolean.class);\n            boolean ensembleTrackerFlag = connectionURL.getParameter(ZOOKEEPER_ENSEMBLE_TRACKER_KEY, true);\n            builder.ensembleTracker(ensembleTrackerFlag);\n        } catch (Throwable ignore) {\n        }\n\n        String userInformation = connectionURL.getUserInformation();\n        if (StringUtils.isNotEmpty(userInformation)) {\n            builder = builder.authorization(\"digest\", userInformation.getBytes(StandardCharsets.UTF_8));\n            builder.aclProvider(new ACLProvider() {\n                @Override\n                public List<ACL> getDefaultAcl() {\n                    return ZooDefs.Ids.CREATOR_ALL_ACL;\n                }\n\n                @Override\n                public List<ACL> getAclForPath(String path) {\n                    return ZooDefs.Ids.CREATOR_ALL_ACL;\n                }\n            });\n        }\n        CuratorFramework curatorFramework = builder.build();\n\n        curatorFramework.start();\n        curatorFramework.blockUntilConnected(\n                BLOCK_UNTIL_CONNECTED_WAIT.getParameterValue(connectionURL),\n                BLOCK_UNTIL_CONNECTED_UNIT.getParameterValue(connectionURL));\n\n        if (!curatorFramework.getState().equals(CuratorFrameworkState.STARTED)) {\n            throw new IllegalStateException(\"zookeeper client initialization failed\");\n        }\n\n        boolean check = UrlUtils.isCheck(connectionURL);\n        if (check && !curatorFramework.getZookeeperClient().isConnected()) {\n            throw new IllegalStateException(\"failed to connect to zookeeper server\");\n        }\n\n        return curatorFramework;\n    }\n\n    public static RetryPolicy buildRetryPolicy(URL connectionURL) {\n        int baseSleepTimeMs = BASE_SLEEP_TIME.getParameterValue(connectionURL);\n        int maxRetries = MAX_RETRIES.getParameterValue(connectionURL);\n        int getMaxSleepMs = MAX_SLEEP.getParameterValue(connectionURL);\n        return new ExponentialBackoffRetry(baseSleepTimeMs, maxRetries, getMaxSleepMs);\n    }\n\n    public static List<ServiceInstance> build(\n            URL registryUrl, Collection<org.apache.curator.x.discovery.ServiceInstance<ZookeeperInstance>> instances) {\n        return instances.stream().map((i) -> build(registryUrl, i)).collect(Collectors.toList());\n    }\n\n    public static ServiceInstance build(\n            URL registryUrl, org.apache.curator.x.discovery.ServiceInstance<ZookeeperInstance> instance) {\n        String name = instance.getName();\n        String host = instance.getAddress();\n        int port = instance.getPort();\n        ZookeeperInstance zookeeperInstance = instance.getPayload();\n        DefaultServiceInstance serviceInstance = new DefaultServiceInstance(\n                name, host, port, ScopeModelUtil.getApplicationModel(registryUrl.getScopeModel()));\n        serviceInstance.setMetadata(zookeeperInstance.getMetadata());\n        return serviceInstance;\n    }\n\n    public static org.apache.curator.x.discovery.ServiceInstance<ZookeeperInstance> build(\n            ServiceInstance serviceInstance) {\n        ServiceInstanceBuilder builder;\n        String serviceName = serviceInstance.getServiceName();\n        String host = serviceInstance.getHost();\n        int port = serviceInstance.getPort();\n        Map<String, String> metadata = serviceInstance.getSortedMetadata();\n        String id = generateId(host, port);\n        ZookeeperInstance zookeeperInstance = new ZookeeperInstance(id, serviceName, metadata);\n        try {\n            builder =\n                    builder().id(id).name(serviceName).address(host).port(port).payload(zookeeperInstance);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n        return builder.build();\n    }\n\n    public static String generateId(String host, int port) {\n        return host + \":\" + port;\n    }\n\n    public static String getRootPath(URL registryURL) {\n        String group = ROOT_PATH.getParameterValue(registryURL);\n        if (group.equalsIgnoreCase(DEFAULT_GROUP)) {\n            group = GROUP_PATH.getParameterValue(registryURL);\n            if (!group.startsWith(PATH_SEPARATOR)) {\n                group = PATH_SEPARATOR + group;\n            }\n        }\n        return group;\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.aot.api.ReflectionTypeDescriberRegistrar",
    "content": "zookeeper=org.apache.dubbo.registry.zookeeper.aot.ZookeeperReflectionTypeDescriberRegistrar\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory",
    "content": "zookeeper=org.apache.dubbo.registry.zookeeper.ZookeeperRegistryFactory"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory",
    "content": "zookeeper=org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscoveryFactory"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/ZookeeperRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.registry.NotifyListener;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClient;\nimport org.apache.dubbo.remoting.zookeeper.curator5.ZookeeperClientManager;\nimport org.apache.dubbo.rpc.RpcException;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\n\nimport com.google.common.collect.Lists;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyBoolean;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass ZookeeperRegistryTest {\n    private static String zookeeperConnectionAddress1;\n    private ZookeeperRegistry zookeeperRegistry;\n    private String service = \"org.apache.dubbo.test.injvmServie\";\n    private String url = \"zookeeper://zookeeper/\" + service + \"?notify=false&methods=test1,test2\";\n    private URL serviceUrl = URL.valueOf(url);\n    private URL anyUrl = URL.valueOf(\"zookeeper://zookeeper/*\");\n    private URL registryUrl;\n    private ZookeeperRegistryFactory zookeeperRegistryFactory;\n    private NotifyListener listener;\n\n    // mock object\n    private static ZookeeperClientManager mockZookeeperClientManager;\n    private static ZookeeperClient mockZookeeperClient;\n\n    @BeforeAll\n    public static void beforeAll() {\n        zookeeperConnectionAddress1 = \"zookeeper://localhost:\" + \"2181\";\n    }\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        mockZookeeperClientManager = mock(ZookeeperClientManager.class);\n        mockZookeeperClient = mock(ZookeeperClient.class);\n        this.registryUrl = URL.valueOf(zookeeperConnectionAddress1);\n        zookeeperRegistryFactory = new ZookeeperRegistryFactory(ApplicationModel.defaultModel());\n        zookeeperRegistryFactory.setZookeeperTransporter(mockZookeeperClientManager);\n        when(mockZookeeperClientManager.connect(registryUrl)).thenReturn(mockZookeeperClient);\n        this.zookeeperRegistry = (ZookeeperRegistry) zookeeperRegistryFactory.createRegistry(registryUrl);\n    }\n\n    @Test\n    void testAnyHost() {\n        Assertions.assertThrows(IllegalStateException.class, () -> {\n            URL errorUrl = URL.valueOf(\"multicast://0.0.0.0/\");\n            new ZookeeperRegistryFactory(ApplicationModel.defaultModel()).createRegistry(errorUrl);\n        });\n    }\n\n    @Test\n    void testRegister() {\n        Set<URL> registered;\n\n        for (int i = 0; i < 2; i++) {\n            zookeeperRegistry.register(serviceUrl);\n            registered = zookeeperRegistry.getRegistered();\n            assertThat(registered.contains(serviceUrl), is(true));\n        }\n\n        registered = zookeeperRegistry.getRegistered();\n        assertThat(registered.size(), is(1));\n    }\n\n    @Test\n    void testSubscribe() {\n        NotifyListener listener = mock(NotifyListener.class);\n        zookeeperRegistry.subscribe(serviceUrl, listener);\n\n        Map<URL, Set<NotifyListener>> subscribed = zookeeperRegistry.getSubscribed();\n        assertThat(subscribed.size(), is(1));\n        assertThat(subscribed.get(serviceUrl).size(), is(1));\n\n        zookeeperRegistry.unsubscribe(serviceUrl, listener);\n        subscribed = zookeeperRegistry.getSubscribed();\n        assertThat(subscribed.size(), is(1));\n        assertThat(subscribed.get(serviceUrl).size(), is(0));\n    }\n\n    @Test\n    void testAvailable() {\n        zookeeperRegistry.register(serviceUrl);\n        when(mockZookeeperClient.isConnected()).thenReturn(true);\n        assertThat(zookeeperRegistry.isAvailable(), is(true));\n\n        zookeeperRegistry.destroy();\n        assertThat(zookeeperRegistry.isAvailable(), is(false));\n    }\n\n    @Test\n    void testLookup() {\n        when(mockZookeeperClient.getChildren(any())).thenReturn(Lists.newArrayList(url));\n        List<URL> lookup = zookeeperRegistry.lookup(serviceUrl);\n        assertThat(lookup.size(), is(1));\n\n        zookeeperRegistry.register(serviceUrl);\n        lookup = zookeeperRegistry.lookup(serviceUrl);\n        assertThat(lookup.size(), is(1));\n    }\n\n    @Test\n    void testLookupIllegalUrl() {\n        try {\n            zookeeperRegistry.lookup(null);\n            fail();\n        } catch (IllegalArgumentException expected) {\n            assertThat(expected.getMessage(), containsString(\"lookup url == null\"));\n        }\n    }\n\n    @Test\n    void testLookupWithException() {\n        URL errorUrl = URL.valueOf(\"multicast://0.0.0.0/\");\n        when(mockZookeeperClient.getChildren(any())).thenThrow(new IllegalStateException());\n        Assertions.assertThrows(RpcException.class, () -> zookeeperRegistry.lookup(errorUrl));\n    }\n\n    @Test\n    void testSubscribeAnyValue() throws InterruptedException {\n        final CountDownLatch latch = new CountDownLatch(1);\n        zookeeperRegistry.register(serviceUrl);\n        zookeeperRegistry.subscribe(anyUrl, urls -> latch.countDown());\n        doAnswer(invocationOnMock -> {\n                    latch.countDown();\n                    return null;\n                })\n                .when(mockZookeeperClient)\n                .create(any(), anyBoolean(), anyBoolean());\n        zookeeperRegistry.register(serviceUrl);\n        latch.await();\n    }\n\n    @Test\n    void testDestroy() {\n        zookeeperRegistry.destroy();\n        assertThat(zookeeperRegistry.isAvailable(), is(false));\n    }\n\n    @Test\n    void testDoRegisterWithException() {\n        doThrow(new IllegalStateException()).when(mockZookeeperClient).create(any(), anyBoolean(), anyBoolean());\n        Assertions.assertThrows(RpcException.class, () -> {\n            URL errorUrl = URL.valueOf(\"multicast://0.0.0.0/\");\n            zookeeperRegistry.doRegister(errorUrl);\n        });\n    }\n\n    @Test\n    void testDoUnregisterWithException() {\n        doThrow(new IllegalStateException()).when(mockZookeeperClient).delete(any());\n        Assertions.assertThrows(RpcException.class, () -> {\n            URL errorUrl = URL.valueOf(\"multicast://0.0.0.0/\");\n            zookeeperRegistry.doUnregister(errorUrl);\n        });\n    }\n\n    @Test\n    void testDoSubscribeWithException() {\n        Assertions.assertThrows(RpcException.class, () -> zookeeperRegistry.doSubscribe(anyUrl, listener));\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.config.ApplicationConfig;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;\nimport org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\n\nimport com.google.common.collect.Lists;\nimport org.apache.curator.CuratorZookeeperClient;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.framework.imps.CuratorFrameworkState;\nimport org.apache.curator.x.discovery.ServiceCache;\nimport org.apache.curator.x.discovery.ServiceCacheBuilder;\nimport org.apache.curator.x.discovery.ServiceDiscovery;\nimport org.apache.curator.x.discovery.ServiceDiscoveryBuilder;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.mockito.MockedStatic;\nimport org.mockito.internal.util.collections.Sets;\n\nimport static java.util.Arrays.asList;\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.doReturn;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.mockStatic;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.when;\n\n/**\n * {@link ZookeeperServiceDiscovery} Test\n *\n * @since 2.7.5\n */\n@DisabledForJreRange(min = JRE.JAVA_16)\nclass ZookeeperServiceDiscoveryTest {\n\n    private static final String SERVICE_NAME = \"A\";\n\n    private static final String LOCALHOST = \"127.0.0.1\";\n\n    private URL registryUrl;\n\n    private ZookeeperServiceDiscovery discovery;\n    private static String zookeeperConnectionAddress1;\n    private static MockedStatic<CuratorFrameworkFactory> curatorFrameworkFactoryMockedStatic;\n    private static MockedStatic<ServiceDiscoveryBuilder> serviceDiscoveryBuilderMockedStatic;\n\n    private CuratorFramework mockCuratorFramework;\n    private CuratorZookeeperClient mockCuratorZookeeperClient;\n    private ServiceDiscoveryBuilder mockServiceDiscoveryBuilder;\n    private ServiceDiscovery mockServiceDiscovery;\n    private ServiceCacheBuilder mockServiceCacheBuilder;\n    private ServiceCache mockServiceCache;\n    private static final CuratorFrameworkFactory.Builder spyBuilder = spy(CuratorFrameworkFactory.builder());\n\n    @BeforeAll\n    public static void beforeAll() {\n        zookeeperConnectionAddress1 = \"zookeeper://localhost:\" + \"2181\";\n        curatorFrameworkFactoryMockedStatic = mockStatic(CuratorFrameworkFactory.class);\n        curatorFrameworkFactoryMockedStatic\n                .when(CuratorFrameworkFactory::builder)\n                .thenReturn(spyBuilder);\n        serviceDiscoveryBuilderMockedStatic = mockStatic(ServiceDiscoveryBuilder.class);\n    }\n\n    @BeforeEach\n    public void init() throws Exception {\n        mockServiceDiscoveryBuilder = mock(ServiceDiscoveryBuilder.class);\n        mockServiceDiscovery = mock(ServiceDiscovery.class);\n        mockServiceCacheBuilder = mock(ServiceCacheBuilder.class);\n        mockCuratorFramework = mock(CuratorFramework.class);\n        mockServiceCache = mock(ServiceCache.class);\n\n        serviceDiscoveryBuilderMockedStatic\n                .when(() -> ServiceDiscoveryBuilder.builder(any()))\n                .thenReturn(mockServiceDiscoveryBuilder);\n        when(mockServiceDiscoveryBuilder.client(any())).thenReturn(mockServiceDiscoveryBuilder);\n        when(mockServiceDiscoveryBuilder.basePath(any())).thenReturn(mockServiceDiscoveryBuilder);\n        when(mockServiceDiscoveryBuilder.build()).thenReturn(mockServiceDiscovery);\n        when(mockServiceDiscovery.serviceCacheBuilder()).thenReturn(mockServiceCacheBuilder);\n        when(mockServiceCacheBuilder.name(any())).thenReturn(mockServiceCacheBuilder);\n        when(mockServiceCacheBuilder.build()).thenReturn(mockServiceCache);\n        doReturn(mockCuratorFramework).when(spyBuilder).build();\n        mockCuratorZookeeperClient = mock(CuratorZookeeperClient.class);\n        // mock default is started. If method need other status please replace in test method.\n        when(mockCuratorFramework.getZookeeperClient()).thenReturn(mockCuratorZookeeperClient);\n        when(mockCuratorFramework.getState()).thenReturn(CuratorFrameworkState.STARTED);\n        when(mockCuratorZookeeperClient.isConnected()).thenReturn(true);\n\n        this.registryUrl = URL.valueOf(zookeeperConnectionAddress1);\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(SERVICE_NAME));\n        registryUrl.setScopeModel(applicationModel);\n        this.discovery = new ZookeeperServiceDiscovery(applicationModel, registryUrl);\n    }\n\n    @AfterEach\n    public void close() throws Exception {\n        discovery.destroy();\n    }\n\n    @Test\n    void testRegistration() throws Exception {\n\n        CountDownLatch latch = new CountDownLatch(1);\n\n        // Add Listener\n        discovery.addServiceInstancesChangedListener(\n                new ServiceInstancesChangedListener(Sets.newSet(SERVICE_NAME), discovery) {\n                    @Override\n                    public void onEvent(ServiceInstancesChangedEvent event) {\n                        latch.countDown();\n                    }\n                });\n\n        discovery.register();\n        latch.await();\n        List<ServiceInstance> serviceInstances = discovery.getInstances(SERVICE_NAME);\n        assertEquals(0, serviceInstances.size());\n\n        discovery.register(URL.valueOf(\"dubbo://1.1.2.3:20880/DemoService\"));\n        discovery.register();\n\n        DefaultServiceInstance serviceInstance = (DefaultServiceInstance) discovery.getLocalInstance();\n        List<org.apache.curator.x.discovery.ServiceInstance> lists =\n                Lists.newArrayList(org.apache.curator.x.discovery.ServiceInstance.builder()\n                        .name(SERVICE_NAME)\n                        .address(\n                                URL.valueOf(\"dubbo://1.1.2.3:20880/DemoService\").getHost())\n                        .port(20880)\n                        .payload(new ZookeeperInstance(\n                                \"\", serviceInstance.getServiceName(), serviceInstance.getMetadata()))\n                        .build());\n        when(mockServiceDiscovery.queryForInstances(any())).thenReturn(lists);\n        serviceInstances = discovery.getInstances(SERVICE_NAME);\n\n        assertTrue(serviceInstances.contains(serviceInstance));\n        assertEquals(asList(serviceInstance), serviceInstances);\n\n        Map<String, String> metadata = new HashMap<>();\n        metadata.put(\"message\", \"Hello,World\");\n        serviceInstance.setMetadata(metadata);\n\n        discovery.register(URL.valueOf(\"dubbo://1.1.2.3:20880/DemoService1\"));\n        discovery.update();\n\n        lists = Lists.newArrayList(org.apache.curator.x.discovery.ServiceInstance.builder()\n                .name(SERVICE_NAME)\n                .address(URL.valueOf(\"dubbo://1.1.2.3:20880/DemoService\").getHost())\n                .port(20880)\n                .payload(new ZookeeperInstance(\"\", serviceInstance.getServiceName(), metadata))\n                .build());\n\n        when(mockServiceDiscovery.queryForInstances(any())).thenReturn(lists);\n        serviceInstances = discovery.getInstances(SERVICE_NAME);\n\n        assertEquals(serviceInstance, serviceInstances.get(0));\n\n        discovery.unregister();\n\n        when(mockServiceDiscovery.queryForInstances(any())).thenReturn(new ArrayList<>());\n        serviceInstances = discovery.getInstances(SERVICE_NAME);\n\n        assertTrue(serviceInstances.isEmpty());\n    }\n\n    @Test\n    void testRegistryCheckConnectDefault() {\n        when(mockCuratorZookeeperClient.isConnected()).thenReturn(false);\n\n        URL registryUrl = URL.valueOf(zookeeperConnectionAddress1);\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        registryUrl.setScopeModel(applicationModel);\n\n        Assertions.assertThrowsExactly(IllegalStateException.class, () -> {\n            new ZookeeperServiceDiscovery(applicationModel, registryUrl);\n        });\n    }\n\n    @Test\n    void testRegistryNotCheckConnect() {\n        when(mockCuratorZookeeperClient.isConnected()).thenReturn(false);\n\n        URL registryUrl = URL.valueOf(zookeeperConnectionAddress1).addParameter(CHECK_KEY, false);\n        ApplicationModel applicationModel = ApplicationModel.defaultModel();\n        registryUrl.setScopeModel(applicationModel);\n\n        Assertions.assertDoesNotThrow(() -> {\n            new ZookeeperServiceDiscovery(applicationModel, registryUrl);\n        });\n    }\n\n    @AfterAll\n    public static void afterAll() throws Exception {\n        if (curatorFrameworkFactoryMockedStatic != null) {\n            curatorFrameworkFactoryMockedStatic.close();\n        }\n        if (serviceDiscoveryBuilderMockedStatic != null) {\n            serviceDiscoveryBuilderMockedStatic.close();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/util/CuratorFrameworkUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.registry.zookeeper.util;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.metadata.report.MetadataReport;\nimport org.apache.dubbo.registry.client.DefaultServiceInstance;\nimport org.apache.dubbo.registry.client.ServiceInstance;\nimport org.apache.dubbo.registry.zookeeper.ZookeeperInstance;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.curator.CuratorZookeeperClient;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.framework.imps.CuratorFrameworkState;\nimport org.apache.curator.x.discovery.ServiceDiscovery;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.MockedStatic;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;\nimport static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_STORAGE_TYPE_PROPERTY_NAME;\nimport static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkParams.ROOT_PATH;\nimport static org.mockito.Mockito.doReturn;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.mockStatic;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.when;\n\n/**\n * {@link CuratorFrameworkUtils} Test\n */\nclass CuratorFrameworkUtilsTest {\n    private static URL registryUrl;\n    private static String zookeeperConnectionAddress1;\n    private static MetadataReport metadataReport;\n    private static MockedStatic<CuratorFrameworkFactory> curatorFrameworkFactoryMockedStatic;\n    CuratorFrameworkFactory.Builder spyBuilder = CuratorFrameworkFactory.builder();\n    private CuratorFramework mockCuratorFramework;\n    private CuratorZookeeperClient mockCuratorZookeeperClient;\n\n    @BeforeAll\n    public static void init() throws Exception {\n        zookeeperConnectionAddress1 = \"zookeeper://localhost:\" + \"2181\";\n\n        registryUrl = URL.valueOf(zookeeperConnectionAddress1);\n        registryUrl.setScopeModel(ApplicationModel.defaultModel());\n\n        metadataReport = Mockito.mock(MetadataReport.class);\n\n        // mock begin\n        // create mock bean begin\n        CuratorFrameworkFactory.Builder realBuilder = CuratorFrameworkFactory.builder();\n        CuratorFrameworkFactory.Builder spyBuilder = spy(realBuilder);\n\n        curatorFrameworkFactoryMockedStatic = mockStatic(CuratorFrameworkFactory.class);\n        curatorFrameworkFactoryMockedStatic\n                .when(CuratorFrameworkFactory::builder)\n                .thenReturn(spyBuilder);\n    }\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        mockCuratorFramework = mock(CuratorFramework.class);\n        doReturn(mockCuratorFramework).when(spyBuilder).build();\n        mockCuratorZookeeperClient = mock(CuratorZookeeperClient.class);\n        // mock default is started. If method need other status please replace in test method.\n        when(mockCuratorFramework.getZookeeperClient()).thenReturn(mockCuratorZookeeperClient);\n        when(mockCuratorFramework.getState()).thenReturn(CuratorFrameworkState.STARTED);\n        when(mockCuratorZookeeperClient.isConnected()).thenReturn(true);\n    }\n\n    @Test\n    void testBuildCuratorFramework() throws Exception {\n        CuratorFramework curatorFramework = CuratorFrameworkUtils.buildCuratorFramework(registryUrl, null);\n        Assertions.assertNotNull(curatorFramework);\n        Assertions.assertTrue(curatorFramework.getZookeeperClient().isConnected());\n        curatorFramework.getZookeeperClient().close();\n    }\n\n    @Test\n    void testBuildServiceDiscovery() throws Exception {\n        CuratorFramework curatorFramework = CuratorFrameworkUtils.buildCuratorFramework(registryUrl, null);\n        ServiceDiscovery<ZookeeperInstance> discovery =\n                CuratorFrameworkUtils.buildServiceDiscovery(curatorFramework, ROOT_PATH.getParameterValue(registryUrl));\n        Assertions.assertNotNull(discovery);\n        curatorFramework.getZookeeperClient().close();\n    }\n\n    @Test\n    void testBuildCuratorFrameworkCheckConnectDefault() {\n        when(mockCuratorZookeeperClient.isConnected()).thenReturn(false);\n        Assertions.assertThrowsExactly(IllegalStateException.class, () -> {\n            CuratorFramework curatorFramework = CuratorFrameworkUtils.buildCuratorFramework(registryUrl, null);\n            curatorFramework.getZookeeperClient().close();\n        });\n    }\n\n    @Test\n    void testBuildCuratorFrameworkNotCheckConnect() {\n        when(mockCuratorZookeeperClient.isConnected()).thenReturn(false);\n        URL url = registryUrl.addParameter(CHECK_KEY, false);\n        Assertions.assertDoesNotThrow(() -> {\n            CuratorFramework curatorFramework = CuratorFrameworkUtils.buildCuratorFramework(url, null);\n            curatorFramework.getZookeeperClient().close();\n        });\n    }\n\n    @Test\n    void testBuild() {\n        ServiceInstance dubboServiceInstance =\n                new DefaultServiceInstance(\"A\", \"127.0.0.1\", 8888, ApplicationModel.defaultModel());\n        Map<String, String> metadata = dubboServiceInstance.getMetadata();\n        metadata.put(METADATA_STORAGE_TYPE_PROPERTY_NAME, \"remote\");\n        metadata.put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, \"111\");\n        metadata.put(\"site\", \"dubbo\");\n\n        // convert {org.apache.dubbo.registry.client.ServiceInstance} to\n        // {org.apache.curator.x.discovery.ServiceInstance<ZookeeperInstance>}\n        org.apache.curator.x.discovery.ServiceInstance<ZookeeperInstance> curatorServiceInstance =\n                CuratorFrameworkUtils.build(dubboServiceInstance);\n        Assertions.assertEquals(curatorServiceInstance.getId(), dubboServiceInstance.getAddress());\n        Assertions.assertEquals(curatorServiceInstance.getName(), dubboServiceInstance.getServiceName());\n        Assertions.assertEquals(curatorServiceInstance.getAddress(), dubboServiceInstance.getHost());\n        Assertions.assertEquals(curatorServiceInstance.getPort(), dubboServiceInstance.getPort());\n\n        ZookeeperInstance payload = curatorServiceInstance.getPayload();\n        Assertions.assertNotNull(payload);\n        Assertions.assertEquals(payload.getMetadata(), metadata);\n        Assertions.assertEquals(payload.getName(), dubboServiceInstance.getServiceName());\n\n        // convert {org.apache.curator.x.discovery.ServiceInstance<ZookeeperInstance>} to\n        // {org.apache.dubbo.registry.client.ServiceInstance}\n        ServiceInstance serviceInstance = CuratorFrameworkUtils.build(registryUrl, curatorServiceInstance);\n        Assertions.assertEquals(serviceInstance, dubboServiceInstance);\n\n        // convert {Collection<org.apache.curator.x.discovery.ServiceInstance<ZookeeperInstance>>} to\n        // {List<org.apache.dubbo.registry.client.ServiceInstance>}\n        List<ServiceInstance> serviceInstances =\n                CuratorFrameworkUtils.build(registryUrl, Arrays.asList(curatorServiceInstance));\n        Assertions.assertNotNull(serviceInstances);\n        Assertions.assertEquals(serviceInstances.get(0), dubboServiceInstance);\n    }\n\n    @AfterAll\n    public static void afterAll() throws Exception {\n        if (curatorFrameworkFactoryMockedStatic != null) {\n            curatorFrameworkFactoryMockedStatic.close();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-registry/dubbo-registry-zookeeper/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-registry/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-parent</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-registry</artifactId>\n  <packaging>pom</packaging>\n  <name>${project.artifactId}</name>\n  <description>The registry module of dubbo project</description>\n  <modules>\n    <module>dubbo-registry-api</module>\n    <module>dubbo-registry-multicast</module>\n    <module>dubbo-registry-zookeeper</module>\n    <module>dubbo-registry-nacos</module>\n    <module>dubbo-registry-multiple</module>\n  </modules>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n</project>\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-remoting</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-remoting-api</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The remoting module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-hessian2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-serialization-fastjson2</artifactId>\n      <version>${project.parent.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Channel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport java.net.InetSocketAddress;\n\n/**\n * Channel. (API/SPI, Prototype, ThreadSafe)\n *\n * @see org.apache.dubbo.remoting.Client\n * @see RemotingServer#getChannels()\n * @see RemotingServer#getChannel(InetSocketAddress)\n */\npublic interface Channel extends Endpoint {\n\n    /**\n     * get remote address.\n     *\n     * @return remote address.\n     */\n    InetSocketAddress getRemoteAddress();\n\n    /**\n     * is connected.\n     *\n     * @return connected\n     */\n    boolean isConnected();\n\n    /**\n     * has attribute.\n     *\n     * @param key key.\n     * @return has or has not.\n     */\n    boolean hasAttribute(String key);\n\n    /**\n     * get attribute.\n     *\n     * @param key key.\n     * @return value.\n     */\n    Object getAttribute(String key);\n\n    /**\n     * set attribute.\n     *\n     * @param key   key.\n     * @param value value.\n     */\n    void setAttribute(String key, Object value);\n\n    /**\n     * remove attribute.\n     *\n     * @param key key.\n     */\n    void removeAttribute(String key);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/ChannelEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\n/**\n * Channel event that can be fired to channels.\n * <p>\n * This interface represents a custom event that can be fired to all connected channels\n * through the {@link RemotingServer#fireChannelEvent(ChannelEvent)} method.\n * Different protocols can interpret and handle these events in their own way,\n * providing a generic mechanism for sending custom events across protocols.\n * </p>\n *\n * <h3>Built-in Events</h3>\n * <ul>\n *   <li>{@link org.apache.dubbo.remoting.event.ReadOnlyEvent} - Notifies clients that the server is entering\n *       read-only mode (typically for graceful shutdown)</li>\n *   <li>{@link org.apache.dubbo.remoting.event.WriteableEvent} - Notifies clients that the server is resuming\n *       normal operation (cancelling graceful shutdown)</li>\n * </ul>\n *\n * <h3>Protocol-specific Handling</h3>\n * <table border=\"1\">\n *   <tr><th>Protocol</th><th>ReadOnlyEvent</th><th>WriteableEvent</th></tr>\n *   <tr><td>Dubbo</td><td>Sends READONLY_EVENT request</td><td>Sends WRITEABLE_EVENT request</td></tr>\n *   <tr><td>Triple (HTTP/2)</td><td>Sends GOAWAY frame</td><td>Not supported (GOAWAY is irreversible)</td></tr>\n * </table>\n *\n * @see RemotingServer#fireChannelEvent(ChannelEvent)\n * @see org.apache.dubbo.remoting.event.ReadOnlyEvent\n * @see org.apache.dubbo.remoting.event.WriteableEvent\n * @since 3.3\n */\npublic interface ChannelEvent {}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/ChannelHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * ChannelHandler. (API, Prototype, ThreadSafe)\n *\n * @see org.apache.dubbo.remoting.Transporter#bind(org.apache.dubbo.common.URL, ChannelHandler)\n * @see org.apache.dubbo.remoting.Transporter#connect(org.apache.dubbo.common.URL, ChannelHandler)\n */\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface ChannelHandler {\n\n    /**\n     * on channel connected.\n     *\n     * @param channel channel.\n     */\n    void connected(Channel channel) throws RemotingException;\n\n    /**\n     * on channel disconnected.\n     *\n     * @param channel channel.\n     */\n    void disconnected(Channel channel) throws RemotingException;\n\n    /**\n     * on message sent.\n     *\n     * @param channel channel.\n     * @param message message.\n     */\n    void sent(Channel channel, Object message) throws RemotingException;\n\n    /**\n     * on message received.\n     *\n     * @param channel channel.\n     * @param message message.\n     */\n    void received(Channel channel, Object message) throws RemotingException;\n\n    /**\n     * on exception caught.\n     *\n     * @param channel   channel.\n     * @param exception exception.\n     */\n    void caught(Channel channel, Throwable exception) throws RemotingException;\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Client.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.Resetable;\n\n/**\n * Remoting Client. (API/SPI, Prototype, ThreadSafe)\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Client%E2%80%93server_model\">Client/Server</a>\n *\n * @see org.apache.dubbo.remoting.Transporter#connect(org.apache.dubbo.common.URL, ChannelHandler)\n */\npublic interface Client extends Endpoint, Channel, Resetable, IdleSensible {\n\n    /**\n     * reconnect.\n     */\n    void reconnect() throws RemotingException;\n\n    @Deprecated\n    void reset(org.apache.dubbo.common.Parameters parameters);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Codec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Codec. (SPI, Singleton, ThreadSafe)\n */\n@Deprecated\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface Codec {\n\n    /**\n     * Need more input poison.\n     *\n     * @see #decode(Channel, InputStream)\n     */\n    Object NEED_MORE_INPUT = new Object();\n\n    /**\n     * Encode message.\n     *\n     * @param channel channel.\n     * @param output  output stream.\n     * @param message message.\n     */\n    @Adaptive({Constants.CODEC_KEY})\n    void encode(Channel channel, OutputStream output, Object message) throws IOException;\n\n    /**\n     * Decode message.\n     *\n     * @param channel channel.\n     * @param input   input stream.\n     * @return message or <code>NEED_MORE_INPUT</code> poison.\n     * @see #NEED_MORE_INPUT\n     */\n    @Adaptive({Constants.CODEC_KEY})\n    Object decode(Channel channel, InputStream input) throws IOException;\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Codec2.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffer;\n\nimport java.io.IOException;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface Codec2 {\n\n    @Adaptive({Constants.CODEC_KEY})\n    void encode(Channel channel, ChannelBuffer buffer, Object message) throws IOException;\n\n    @Adaptive({Constants.CODEC_KEY})\n    Object decode(Channel channel, ChannelBuffer buffer) throws IOException;\n\n    enum DecodeResult {\n        NEED_MORE_INPUT,\n        SKIP_SOME_INPUT\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Constants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic interface Constants {\n\n    String BUFFER_KEY = \"buffer\";\n\n    /**\n     * default buffer size is 8k.\n     */\n    int DEFAULT_BUFFER_SIZE = 8 * 1024;\n\n    int MAX_BUFFER_SIZE = 16 * 1024;\n\n    int MIN_BUFFER_SIZE = 1 * 1024;\n\n    String IDLE_TIMEOUT_KEY = \"idle.timeout\";\n\n    int DEFAULT_IDLE_TIMEOUT = 600 * 1000;\n    /**\n     * max size of channel. default value is zero that means unlimited.\n     */\n    String ACCEPTS_KEY = \"accepts\";\n\n    int DEFAULT_ACCEPTS = 0;\n\n    String CONNECT_QUEUE_CAPACITY = \"connect.queue.capacity\";\n\n    String CONNECT_QUEUE_WARNING_SIZE = \"connect.queue.warning.size\";\n\n    int DEFAULT_CONNECT_QUEUE_WARNING_SIZE = 1000;\n\n    String CHARSET_KEY = \"charset\";\n\n    String DEFAULT_CHARSET = \"UTF-8\";\n\n    /**\n     * Every heartbeat duration / HEARTBEAT_CHECK_TICK, check if a heartbeat should be sent. Every heartbeat timeout\n     * duration / HEARTBEAT_CHECK_TICK, check if a connection should be closed on server side, and if reconnect on\n     * client side\n     */\n    int HEARTBEAT_CHECK_TICK = 3;\n\n    /**\n     * the least heartbeat during is 1000 ms.\n     */\n    long LEAST_HEARTBEAT_DURATION = 1000;\n\n    /**\n     * the least reconnect during is 60000 ms.\n     */\n    long LEAST_RECONNECT_DURATION = 60000;\n\n    String LEAST_RECONNECT_DURATION_KEY = \"dubbo.application.least-reconnect-duration\";\n\n    /**\n     * ticks per wheel.\n     */\n    int TICKS_PER_WHEEL = 128;\n\n    String PAYLOAD_KEY = \"payload\";\n    /**\n     * 8M\n     */\n    int DEFAULT_PAYLOAD = 8 * 1024 * 1024;\n\n    String CONNECT_TIMEOUT_KEY = \"connect.timeout\";\n\n    int DEFAULT_CONNECT_TIMEOUT = 3000;\n\n    String SERIALIZATION_KEY = \"serialization\";\n\n    /**\n     * Prefer serialization\n     */\n    String PREFER_SERIALIZATION_KEY = \"prefer.serialization\";\n\n    String CODEC_KEY = \"codec\";\n\n    String CODEC_VERSION_KEY = \"codec.version\";\n\n    String SERVER_KEY = \"server\";\n\n    String IS_PU_SERVER_KEY = \"ispuserver\";\n\n    String CLIENT_KEY = \"client\";\n\n    String DEFAULT_REMOTING_CLIENT = \"netty\";\n\n    String TRANSPORTER_KEY = \"transporter\";\n\n    String DEFAULT_TRANSPORTER = \"netty\";\n\n    String EXCHANGER_KEY = \"exchanger\";\n\n    String DEFAULT_EXCHANGER = \"header\";\n\n    String DISPACTHER_KEY = \"dispacther\";\n\n    int DEFAULT_IO_THREADS = Math.min(Runtime.getRuntime().availableProcessors() + 1, 32);\n\n    String EVENT_LOOP_BOSS_POOL_NAME = \"NettyServerBoss\";\n\n    String EVENT_LOOP_WORKER_POOL_NAME = \"NettyServerWorker\";\n\n    String BIND_IP_KEY = \"bind.ip\";\n\n    String BIND_PORT_KEY = \"bind.port\";\n\n    String BIND_RETRY_TIMES = \"bind.retry.times\";\n\n    String BIND_RETRY_INTERVAL = \"bind.retry.interval\";\n\n    String SENT_KEY = \"sent\";\n\n    String DISPATCHER_KEY = \"dispatcher\";\n\n    String CHANNEL_ATTRIBUTE_READONLY_KEY = \"channel.readonly\";\n\n    String CHANNEL_READONLYEVENT_SENT_KEY = \"channel.readonly.sent\";\n\n    String CHANNEL_SEND_READONLYEVENT_KEY = \"channel.readonly.send\";\n\n    String RECONNECT_KEY = \"reconnect\";\n\n    int DEFAULT_RECONNECT_PERIOD = 2000;\n\n    String CHANNEL_SHUTDOWN_TIMEOUT_KEY = \"channel.shutdown.timeout\";\n\n    String SEND_RECONNECT_KEY = \"send.reconnect\";\n\n    String CHECK_KEY = \"check\";\n\n    String PROMPT_KEY = \"prompt\";\n\n    String DEFAULT_PROMPT = \"dubbo>\";\n    String TELNET_KEY = \"telnet\";\n    String HEARTBEAT_KEY = \"heartbeat\";\n    int DEFAULT_HEARTBEAT = 60 * 1000;\n    String HEARTBEAT_TIMEOUT_KEY = \"heartbeat.timeout\";\n    String CLOSE_TIMEOUT_KEY = \"close.timeout\";\n    String CONNECTIONS_KEY = \"connections\";\n\n    int DEFAULT_BACKLOG = 1024;\n\n    String CONNECTION = \"Connection\";\n\n    String KEEP_ALIVE = \"keep-alive\";\n\n    String KEEP_ALIVE_HEADER = \"Keep-Alive\";\n\n    String OK_HTTP = \"ok-http\";\n    String URL_CONNECTION = \"url-connection\";\n    String APACHE_HTTP_CLIENT = \"apache-http-client\";\n    String PORT_UNIFICATION_NETTY4_SERVER = \"netty4\";\n\n    List<String> REST_SERVER = Arrays.asList(\"jetty\", \"tomcat\", \"netty\");\n    String CONTENT_LENGTH_KEY = \"content-length\";\n    String SSL_SESSION_KEY = \"ssl-session\";\n\n    String CONNECTION_HANDLER_NAME = \"connectionHandler\";\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Decodeable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\npublic interface Decodeable {\n\n    void decode() throws Exception;\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Dispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.remoting.transport.dispatcher.all.AllDispatcher;\n\n/**\n * ChannelHandlerWrapper (SPI, Singleton, ThreadSafe)\n */\n@SPI(value = AllDispatcher.NAME, scope = ExtensionScope.FRAMEWORK)\npublic interface Dispatcher {\n\n    /**\n     * dispatch the message to threadpool.\n     *\n     * @param handler\n     * @param url\n     * @return channel handler\n     */\n    @Adaptive({Constants.DISPATCHER_KEY, \"dispather\", \"channel.handler\"})\n    // The last two parameters are reserved for compatibility with the old configuration\n    ChannelHandler dispatch(ChannelHandler handler, URL url);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Endpoint.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.URL;\n\nimport java.net.InetSocketAddress;\n\n/**\n * Endpoint. (API/SPI, Prototype, ThreadSafe)\n *\n *\n * @see org.apache.dubbo.remoting.Channel\n * @see org.apache.dubbo.remoting.Client\n * @see RemotingServer\n */\npublic interface Endpoint {\n\n    /**\n     * get url.\n     *\n     * @return url\n     */\n    URL getUrl();\n\n    /**\n     * get channel handler.\n     *\n     * @return channel handler\n     */\n    ChannelHandler getChannelHandler();\n\n    /**\n     * get local address.\n     *\n     * @return local address.\n     */\n    InetSocketAddress getLocalAddress();\n\n    /**\n     * send message.\n     *\n     * @param message\n     * @throws RemotingException\n     */\n    void send(Object message) throws RemotingException;\n\n    /**\n     * send message.\n     *\n     * @param message\n     * @param sent    already sent to socket?\n     */\n    void send(Object message, boolean sent) throws RemotingException;\n\n    /**\n     * close the channel.\n     */\n    void close();\n\n    /**\n     * Graceful close the channel.\n     */\n    void close(int timeout);\n\n    void startClose();\n\n    /**\n     * is closed.\n     *\n     * @return closed\n     */\n    boolean isClosed();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/ExecutionException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport java.net.InetSocketAddress;\n\n/**\n * ReceiveException\n *\n * @export\n */\npublic class ExecutionException extends RemotingException {\n\n    private static final long serialVersionUID = -2531085236111056860L;\n\n    private final Object request;\n\n    public ExecutionException(Object request, Channel channel, String message, Throwable cause) {\n        super(channel, message, cause);\n        this.request = request;\n    }\n\n    public ExecutionException(Object request, Channel channel, String msg) {\n        super(channel, msg);\n        this.request = request;\n    }\n\n    public ExecutionException(Object request, Channel channel, Throwable cause) {\n        super(channel, cause);\n        this.request = request;\n    }\n\n    public ExecutionException(\n            Object request,\n            InetSocketAddress localAddress,\n            InetSocketAddress remoteAddress,\n            String message,\n            Throwable cause) {\n        super(localAddress, remoteAddress, message, cause);\n        this.request = request;\n    }\n\n    public ExecutionException(\n            Object request, InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message) {\n        super(localAddress, remoteAddress, message);\n        this.request = request;\n    }\n\n    public ExecutionException(\n            Object request, InetSocketAddress localAddress, InetSocketAddress remoteAddress, Throwable cause) {\n        super(localAddress, remoteAddress, cause);\n        this.request = request;\n    }\n\n    public Object getRequest() {\n        return request;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/IdleSensible.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\n/**\n * Indicate whether the implementation (for both server and client) has the ability to sense and handle idle connection.\n * If the server has the ability to handle idle connection, it should close the connection when it happens, and if\n * the client has the ability to handle idle connection, it should send the heartbeat to the server.\n */\npublic interface IdleSensible {\n    /**\n     * Whether the implementation can sense and handle the idle connection. By default, it's false, the implementation\n     * relies on dedicated timer to take care of idle connection.\n     *\n     * @return whether it has the ability to handle idle connection\n     */\n    default boolean canHandleIdle() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/RemotingException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport java.net.InetSocketAddress;\n\n/**\n * RemotingException. (API, Prototype, ThreadSafe)\n *\n * @export\n * @see org.apache.dubbo.remoting.exchange.support.DefaultFuture#get()\n * @see org.apache.dubbo.remoting.Channel#send(Object, boolean)\n * @see org.apache.dubbo.remoting.exchange.ExchangeChannel#request(Object)\n * @see org.apache.dubbo.remoting.exchange.ExchangeChannel#request(Object, int)\n * @see org.apache.dubbo.remoting.Transporter#bind(org.apache.dubbo.common.URL, ChannelHandler)\n * @see org.apache.dubbo.remoting.Transporter#connect(org.apache.dubbo.common.URL, ChannelHandler)\n */\npublic class RemotingException extends Exception {\n\n    private static final long serialVersionUID = -3160452149606778709L;\n\n    private InetSocketAddress localAddress;\n\n    private InetSocketAddress remoteAddress;\n\n    public RemotingException(Channel channel, String msg) {\n        this(\n                channel == null ? null : channel.getLocalAddress(),\n                channel == null ? null : channel.getRemoteAddress(),\n                msg);\n    }\n\n    public RemotingException(InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message) {\n        super(message);\n\n        this.localAddress = localAddress;\n        this.remoteAddress = remoteAddress;\n    }\n\n    public RemotingException(Channel channel, Throwable cause) {\n        this(\n                channel == null ? null : channel.getLocalAddress(),\n                channel == null ? null : channel.getRemoteAddress(),\n                cause);\n    }\n\n    public RemotingException(InetSocketAddress localAddress, InetSocketAddress remoteAddress, Throwable cause) {\n        super(cause);\n\n        this.localAddress = localAddress;\n        this.remoteAddress = remoteAddress;\n    }\n\n    public RemotingException(Channel channel, String message, Throwable cause) {\n        this(\n                channel == null ? null : channel.getLocalAddress(),\n                channel == null ? null : channel.getRemoteAddress(),\n                message,\n                cause);\n    }\n\n    public RemotingException(\n            InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message, Throwable cause) {\n        super(message, cause);\n\n        this.localAddress = localAddress;\n        this.remoteAddress = remoteAddress;\n    }\n\n    public InetSocketAddress getLocalAddress() {\n        return localAddress;\n    }\n\n    public InetSocketAddress getRemoteAddress() {\n        return remoteAddress;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/RemotingServer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.Resetable;\n\nimport java.net.InetSocketAddress;\nimport java.util.Collection;\n\n/**\n * Remoting Server. (API/SPI, Prototype, ThreadSafe)\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Client%E2%80%93server_model\">Client/Server</a>\n *\n * @see org.apache.dubbo.remoting.Transporter#bind(org.apache.dubbo.common.URL, ChannelHandler)\n */\npublic interface RemotingServer extends Endpoint, Resetable, IdleSensible {\n\n    /**\n     * is bound.\n     *\n     * @return bound\n     */\n    boolean isBound();\n\n    /**\n     * get channels.\n     *\n     * @return channels\n     */\n    Collection<Channel> getChannels();\n\n    /**\n     * Fire a custom event to all connected channels.\n     * <p>\n     * Different protocols can interpret and handle these events in their own way.\n     *\n     * @param event the event to fire\n     */\n    void fireChannelEvent(ChannelEvent event);\n\n    /**\n     * get channel.\n     *\n     * @param remoteAddress\n     * @return channel\n     */\n    Channel getChannel(InetSocketAddress remoteAddress);\n\n    @Deprecated\n    void reset(org.apache.dubbo.common.Parameters parameters);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/TimeoutException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport java.net.InetSocketAddress;\n\n/**\n * TimeoutException. (API, Prototype, ThreadSafe)\n *\n * @export\n * @see org.apache.dubbo.remoting.exchange.support.DefaultFuture#get()\n */\npublic class TimeoutException extends RemotingException {\n\n    public static final int CLIENT_SIDE = 0;\n    public static final int SERVER_SIDE = 1;\n    private static final long serialVersionUID = 3122966731958222692L;\n    private final int phase;\n\n    public TimeoutException(boolean serverSide, Channel channel, String message) {\n        super(channel, message);\n        this.phase = serverSide ? SERVER_SIDE : CLIENT_SIDE;\n    }\n\n    public TimeoutException(\n            boolean serverSide, InetSocketAddress localAddress, InetSocketAddress remoteAddress, String message) {\n        super(localAddress, remoteAddress, message);\n        this.phase = serverSide ? SERVER_SIDE : CLIENT_SIDE;\n    }\n\n    public int getPhase() {\n        return phase;\n    }\n\n    public boolean isServerSide() {\n        return phase == 1;\n    }\n\n    public boolean isClientSide() {\n        return phase == 0;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Transporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\n\n/**\n * Transporter. (SPI, Singleton, ThreadSafe)\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Transport_Layer\">Transport Layer</a>\n * <a href=\"http://en.wikipedia.org/wiki/Client%E2%80%93server_model\">Client/Server</a>\n *\n * @see org.apache.dubbo.remoting.Transporters\n */\n@SPI(value = \"netty\", scope = ExtensionScope.FRAMEWORK)\npublic interface Transporter {\n\n    /**\n     * Bind a server.\n     *\n     * @param url     server url\n     * @param handler\n     * @return server\n     * @throws RemotingException\n     * @see org.apache.dubbo.remoting.Transporters#bind(URL, ChannelHandler...)\n     */\n    @Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})\n    RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException;\n\n    /**\n     * Connect to a server.\n     *\n     * @param url     server url\n     * @param handler\n     * @return client\n     * @throws RemotingException\n     * @see org.apache.dubbo.remoting.Transporters#connect(URL, ChannelHandler...)\n     */\n    @Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})\n    Client connect(URL url, ChannelHandler handler) throws RemotingException;\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Transporters.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.transport.ChannelHandlerAdapter;\nimport org.apache.dubbo.remoting.transport.ChannelHandlerDispatcher;\n\n/**\n * Transporter facade. (API, Static, ThreadSafe)\n */\npublic class Transporters {\n\n    private Transporters() {}\n\n    public static RemotingServer bind(String url, ChannelHandler... handler) throws RemotingException {\n        return bind(URL.valueOf(url), handler);\n    }\n\n    public static RemotingServer bind(URL url, ChannelHandler... handlers) throws RemotingException {\n        if (url == null) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n        if (handlers == null || handlers.length == 0) {\n            throw new IllegalArgumentException(\"handlers == null\");\n        }\n        ChannelHandler handler;\n        if (handlers.length == 1) {\n            handler = handlers[0];\n        } else {\n            handler = new ChannelHandlerDispatcher(handlers);\n        }\n        return getTransporter(url).bind(url, handler);\n    }\n\n    public static Client connect(String url, ChannelHandler... handler) throws RemotingException {\n        return connect(URL.valueOf(url), handler);\n    }\n\n    public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException {\n        if (url == null) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n        ChannelHandler handler;\n        if (handlers == null || handlers.length == 0) {\n            handler = new ChannelHandlerAdapter();\n        } else if (handlers.length == 1) {\n            handler = handlers[0];\n        } else {\n            handler = new ChannelHandlerDispatcher(handlers);\n        }\n        return getTransporter(url).connect(url, handler);\n    }\n\n    public static Transporter getTransporter(URL url) {\n        return url.getOrDefaultFrameworkModel()\n                .getExtensionLoader(Transporter.class)\n                .getAdaptiveExtension();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/AbstractWireProtocol.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.api.pu.ChannelOperator;\nimport org.apache.dubbo.remoting.api.ssl.ContextOperator;\n\npublic abstract class AbstractWireProtocol implements WireProtocol {\n\n    private final ProtocolDetector detector;\n\n    public AbstractWireProtocol(ProtocolDetector detector) {\n        this.detector = detector;\n    }\n\n    @Override\n    public ProtocolDetector detector() {\n        return detector;\n    }\n\n    @Override\n    public void configClientPipeline(URL url, ChannelOperator operator, ContextOperator contextOperator) {}\n\n    @Override\n    public void close() {}\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/ProtocolDetector.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api;\n\nimport org.apache.dubbo.remoting.buffer.ChannelBuffer;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Determine incoming bytes belong to the specific protocol.\n */\npublic interface ProtocolDetector {\n\n    Result detect(ChannelBuffer in);\n\n    class Result {\n\n        private final Flag flag;\n\n        private final Map<String, String> detectContext = new HashMap<>(4);\n\n        private Result(Flag flag) {\n            this.flag = flag;\n        }\n\n        public void setAttribute(String key, String value) {\n            this.detectContext.put(key, value);\n        }\n\n        public String getAttribute(String key) {\n            return this.detectContext.get(key);\n        }\n\n        public void removeAttribute(String key) {\n            this.detectContext.remove(key);\n        }\n\n        public Flag flag() {\n            return flag;\n        }\n\n        public static Result recognized() {\n            return new Result(Flag.RECOGNIZED);\n        }\n\n        public static Result unrecognized() {\n            return new Result(Flag.UNRECOGNIZED);\n        }\n\n        public static Result needMoreData() {\n            return new Result(Flag.NEED_MORE_DATA);\n        }\n\n        @Override\n        public int hashCode() {\n            return flag.hashCode();\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            return obj instanceof Result && flag == ((Result) obj).flag;\n        }\n    }\n\n    enum Flag {\n        RECOGNIZED,\n        UNRECOGNIZED,\n        NEED_MORE_DATA\n    }\n\n    default int getByteByIndex(ChannelBuffer buffer, int index) {\n        return buffer.getByte(buffer.readerIndex() + index);\n    }\n\n    default boolean prefixMatch(char[][] prefixes, ChannelBuffer buffer, int length) {\n\n        int[] ints = new int[length];\n        for (int i = 0; i < length; i++) {\n            ints[i] = getByteByIndex(buffer, i);\n        }\n\n        // prefix match\n        for (char[] prefix : prefixes) {\n\n            boolean matched = true;\n            for (int j = 0; j < length; j++) {\n                if (prefix[j] != ints[j]) {\n                    matched = false;\n                    break;\n                }\n            }\n\n            if (matched) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/WireProtocol.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.remoting.api.pu.ChannelOperator;\nimport org.apache.dubbo.remoting.api.ssl.ContextOperator;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface WireProtocol {\n\n    ProtocolDetector detector();\n\n    void configServerProtocolHandler(URL url, ChannelOperator operator);\n\n    void configClientPipeline(URL url, ChannelOperator operator, ContextOperator contextOperator);\n\n    void close();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/AbstractConnectionClient.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.connection;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.api.WireProtocol;\nimport org.apache.dubbo.remoting.transport.AbstractClient;\n\nimport java.net.InetSocketAddress;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLongFieldUpdater;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_ERROR_CLOSE_CLIENT;\n\npublic abstract class AbstractConnectionClient extends AbstractClient {\n\n    protected WireProtocol protocol;\n\n    protected InetSocketAddress remote;\n\n    protected AtomicBoolean init;\n\n    protected static final Object CONNECTED_OBJECT = new Object();\n\n    private volatile long counter;\n\n    private static final AtomicLongFieldUpdater<AbstractConnectionClient> COUNTER_UPDATER =\n            AtomicLongFieldUpdater.newUpdater(AbstractConnectionClient.class, \"counter\");\n\n    protected AbstractConnectionClient(URL url, ChannelHandler handler) throws RemotingException {\n        super(url, handler);\n    }\n\n    protected AbstractConnectionClient() {}\n\n    public final void increase() {\n        COUNTER_UPDATER.set(this, 1L);\n    }\n\n    /**\n     * Increments the reference count by 1.\n     */\n    public final boolean retain() {\n        long oldCount = COUNTER_UPDATER.getAndIncrement(this);\n        if (oldCount <= 0) {\n            COUNTER_UPDATER.getAndDecrement(this);\n            logger.info(\n                    \"Retain failed, because connection \" + remote\n                            + \" has been destroyed but not yet removed, will create a new one instead.\"\n                            + \" Check logs below to confirm that this connection finally gets removed to make sure there's no potential memory leak!\");\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Decreases the reference count by 1 and calls {@link this#destroy} if the reference count reaches 0.\n     */\n    public boolean release() {\n        long remainingCount = COUNTER_UPDATER.decrementAndGet(this);\n\n        if (remainingCount == 0) {\n            logger.info(\"Destroying connection to {}, because the reference count reaches 0\", remote);\n            destroy();\n            return true;\n        } else if (remainingCount <= -1) {\n            logger.warn(PROTOCOL_ERROR_CLOSE_CLIENT, \"\", \"\", \"This instance has been destroyed\");\n            return false;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * init config and attribute.\n     */\n    protected abstract void initConnectionClient();\n\n    /**\n     * connection is available.\n     *\n     * @return boolean\n     */\n    public abstract boolean isAvailable();\n\n    /**\n     * add a listener that will be executed when a connection is established.\n     *\n     * @param func execute function\n     */\n    public abstract void addConnectedListener(Runnable func);\n\n    /**\n     * Add a listener that will be executed when the connection is disconnected.\n     *\n     * @param func execute function\n     */\n    public abstract void addDisconnectedListener(Runnable func);\n\n    /**\n     * add a listener that will be executed when the connection is closed.\n     *\n     * @param func execute function\n     */\n    public abstract void addCloseListener(Runnable func);\n\n    /**\n     * when connected, callback.\n     *\n     * @param channel Channel\n     */\n    public abstract void onConnected(Object channel);\n\n    /**\n     * when goaway, callback.\n     *\n     * @param channel Channel\n     */\n    public abstract void onGoaway(Object channel);\n\n    /**\n     * This method will be invoked when counter reaches 0, override this method to destroy materials related to the specific resource.\n     */\n    public abstract void destroy();\n\n    /**\n     * if generalizable, return NIOChannel\n     * else return Dubbo Channel\n     *\n     * @param generalizable generalizable\n     * @return Dubbo Channel or NIOChannel such as NettyChannel\n     */\n    public abstract <T> T getChannel(Boolean generalizable);\n\n    /**\n     * Get counter\n     */\n    public long getCounter() {\n        return COUNTER_UPDATER.get(this);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/ConnectionHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.connection;\n\npublic interface ConnectionHandler {\n\n    /**\n     * when server close connection gracefully.\n     *\n     * @param channel Channel\n     */\n    void onGoAway(Object channel);\n\n    /**\n     * reconnect\n     *\n     * @param channel Channel\n     */\n    void reconnect(Object channel);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/ConnectionManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.connection;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.remoting.ChannelHandler;\n\nimport java.util.function.Consumer;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface ConnectionManager {\n\n    AbstractConnectionClient connect(URL url, ChannelHandler handler);\n\n    void forEachConnection(Consumer<AbstractConnectionClient> connectionConsumer);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/MultiplexProtocolConnectionManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.connection;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.function.Consumer;\n\npublic class MultiplexProtocolConnectionManager implements ConnectionManager {\n    public static final String NAME = \"multiple\";\n\n    private final ConcurrentMap<String, ConnectionManager> protocols = new ConcurrentHashMap<>(1);\n\n    private FrameworkModel frameworkModel;\n\n    public MultiplexProtocolConnectionManager(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public AbstractConnectionClient connect(URL url, ChannelHandler handler) {\n        final ConnectionManager manager = ConcurrentHashMapUtils.computeIfAbsent(\n                protocols, url.getProtocol(), this::createSingleProtocolConnectionManager);\n        return manager.connect(url, handler);\n    }\n\n    @Override\n    public void forEachConnection(Consumer<AbstractConnectionClient> connectionConsumer) {\n        protocols.values().forEach(p -> p.forEachConnection(connectionConsumer));\n    }\n\n    private ConnectionManager createSingleProtocolConnectionManager(String protocol) {\n        return frameworkModel\n                .getExtensionLoader(ConnectionManager.class)\n                .getExtension(SingleProtocolConnectionManager.NAME);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/SingleProtocolConnectionManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.connection;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.function.Consumer;\n\npublic class SingleProtocolConnectionManager implements ConnectionManager {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(SingleProtocolConnectionManager.class);\n\n    public static final String NAME = \"single\";\n\n    private final ConcurrentMap<String, AbstractConnectionClient> connections = new ConcurrentHashMap<>(16);\n\n    private FrameworkModel frameworkModel;\n\n    public SingleProtocolConnectionManager(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    @Override\n    public AbstractConnectionClient connect(URL url, ChannelHandler handler) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n        return connections.compute(url.getAddress(), (address, conn) -> {\n            String transport = url.getParameter(Constants.TRANSPORTER_KEY, \"netty4\");\n            if (conn == null) {\n                return createAbstractConnectionClient(url, handler, address, transport);\n            } else {\n                boolean shouldReuse = conn.retain();\n                if (!shouldReuse) {\n                    logger.info(\"Trying to create a new connection for {}.\", address);\n                    return createAbstractConnectionClient(url, handler, address, transport);\n                }\n                return conn;\n            }\n        });\n    }\n\n    private AbstractConnectionClient createAbstractConnectionClient(\n            URL url, ChannelHandler handler, String address, String transport) {\n        ConnectionManager manager =\n                frameworkModel.getExtensionLoader(ConnectionManager.class).getExtension(transport);\n        final AbstractConnectionClient connectionClient = manager.connect(url, handler);\n        connectionClient.addCloseListener(() -> {\n            logger.info(\n                    \"Remove closed connection (with reference count==0) for address {}, a new one will be created for upcoming RPC requests routing to this address.\",\n                    address);\n            connections.remove(address, connectionClient);\n        });\n        return connectionClient;\n    }\n\n    @Override\n    public void forEachConnection(Consumer<AbstractConnectionClient> connectionConsumer) {\n        connections.values().forEach(connectionConsumer);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/pu/AbstractPortUnificationServer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.pu;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.api.WireProtocol;\nimport org.apache.dubbo.remoting.transport.AbstractServer;\n\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;\nimport static org.apache.dubbo.common.constants.CommonConstants.EXT_PROTOCOL;\n\npublic abstract class AbstractPortUnificationServer extends AbstractServer {\n\n    /**\n     * extension name -> activate WireProtocol\n     */\n    private volatile Map<String, WireProtocol> protocols;\n\n    /*\n    protocol name --> URL object\n    wire protocol will get url object to config server pipeline for channel\n     */\n    private Map<String, URL> supportedUrls;\n\n    /*\n    protocol name --> ChannelHandler object\n    wire protocol will get handler to config server pipeline for channel\n    (for triple protocol, it's a default handler that do nothing)\n     */\n    private Map<String, ChannelHandler> supportedHandlers;\n\n    public AbstractPortUnificationServer(URL url, ChannelHandler handler) throws RemotingException {\n        super(url, handler);\n    }\n\n    public Map<String, WireProtocol> getProtocols() {\n        return protocols;\n    }\n\n    @Override\n    protected final void doOpen() {\n        // initialize supportedUrls and supportedHandlers before potential usage to avoid NPE.\n        supportedUrls = new ConcurrentHashMap<>();\n        supportedHandlers = new ConcurrentHashMap<>();\n\n        ExtensionLoader<WireProtocol> loader =\n                getUrl().getOrDefaultFrameworkModel().getExtensionLoader(WireProtocol.class);\n        Map<String, WireProtocol> protocols = loader.getActivateExtension(getUrl(), new String[0]).stream()\n                .collect(Collectors.toConcurrentMap(loader::getExtensionName, Function.identity()));\n        // load extra protocols\n        String extraProtocols = getUrl().getParameter(EXT_PROTOCOL);\n        if (StringUtils.isNotEmpty(extraProtocols)) {\n            Arrays.stream(extraProtocols.split(COMMA_SEPARATOR)).forEach(p -> {\n                protocols.put(p, loader.getExtension(p));\n            });\n        }\n        this.protocols = protocols;\n        doOpen0();\n    }\n\n    protected abstract void doOpen0();\n\n    /*\n    This method registers URL object and corresponding channel handler to pu server.\n    In PuServerExchanger.bind, this method is called with ConcurrentHashMap.computeIfPresent to register messages to\n    this supportedUrls and supportedHandlers\n     */\n    public void addSupportedProtocol(URL url, ChannelHandler handler) {\n        this.supportedUrls.put(url.getProtocol(), url);\n        this.supportedHandlers.put(url.getProtocol(), handler);\n    }\n\n    protected Map<String, URL> getSupportedUrls() {\n        // this getter is just used by implementation of this class\n        return supportedUrls;\n    }\n\n    public Map<String, ChannelHandler> getSupportedHandlers() {\n        // this getter is just used by implementation of this class\n        return supportedHandlers;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/pu/ChannelHandlerPretender.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.pu;\n\nimport org.apache.dubbo.remoting.transport.ChannelHandlerAdapter;\n\npublic class ChannelHandlerPretender extends ChannelHandlerAdapter {\n    private final Object realHandler;\n\n    public ChannelHandlerPretender(Object realHandler) {\n        this.realHandler = realHandler;\n    }\n\n    public Object getRealHandler() {\n        return realHandler;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/pu/ChannelOperator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.pu;\n\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.api.ProtocolDetector;\n\nimport java.util.List;\n\npublic interface ChannelOperator {\n    void configChannelHandler(List<ChannelHandler> handlerList);\n\n    ProtocolDetector.Result detectResult();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/pu/DefaultCodec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.pu;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Codec2;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffer;\n\nimport java.io.IOException;\n\npublic class DefaultCodec implements Codec2 {\n    @Override\n    public void encode(Channel channel, ChannelBuffer buffer, Object message) throws IOException {}\n\n    @Override\n    public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/pu/DefaultPuHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.pu;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\n\npublic class DefaultPuHandler implements ChannelHandler {\n    @Override\n    public void connected(Channel channel) throws RemotingException {}\n\n    @Override\n    public void disconnected(Channel channel) throws RemotingException {}\n\n    @Override\n    public void sent(Channel channel, Object message) throws RemotingException {}\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {}\n\n    @Override\n    public void caught(Channel channel, Throwable exception) throws RemotingException {}\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/pu/PortUnificationTransporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.pu;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.api.connection.AbstractConnectionClient;\n\n@SPI(value = \"netty4\", scope = ExtensionScope.FRAMEWORK)\npublic interface PortUnificationTransporter {\n\n    @Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})\n    AbstractPortUnificationServer bind(URL url, ChannelHandler handler) throws RemotingException;\n\n    @Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})\n    AbstractConnectionClient connect(URL url, ChannelHandler handler) throws RemotingException;\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/ssl/ContextOperator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api.ssl;\n\npublic interface ContextOperator {\n    Object buildContext();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/AbstractChannelBuffer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\n\npublic abstract class AbstractChannelBuffer implements ChannelBuffer {\n\n    private int readerIndex;\n\n    private int writerIndex;\n\n    private int markedReaderIndex;\n\n    private int markedWriterIndex;\n\n    @Override\n    public int readerIndex() {\n        return readerIndex;\n    }\n\n    @Override\n    public void readerIndex(int readerIndex) {\n        if (readerIndex < 0 || readerIndex > writerIndex) {\n            throw new IndexOutOfBoundsException();\n        }\n        this.readerIndex = readerIndex;\n    }\n\n    @Override\n    public int writerIndex() {\n        return writerIndex;\n    }\n\n    @Override\n    public void writerIndex(int writerIndex) {\n        if (writerIndex < readerIndex || writerIndex > capacity()) {\n            throw new IndexOutOfBoundsException();\n        }\n        this.writerIndex = writerIndex;\n    }\n\n    @Override\n    public void setIndex(int readerIndex, int writerIndex) {\n        if (readerIndex < 0 || readerIndex > writerIndex || writerIndex > capacity()) {\n            throw new IndexOutOfBoundsException();\n        }\n        this.readerIndex = readerIndex;\n        this.writerIndex = writerIndex;\n    }\n\n    @Override\n    public void clear() {\n        readerIndex = writerIndex = 0;\n    }\n\n    @Override\n    public boolean readable() {\n        return readableBytes() > 0;\n    }\n\n    @Override\n    public boolean writable() {\n        return writableBytes() > 0;\n    }\n\n    @Override\n    public int readableBytes() {\n        return writerIndex - readerIndex;\n    }\n\n    @Override\n    public int writableBytes() {\n        return capacity() - writerIndex;\n    }\n\n    @Override\n    public void markReaderIndex() {\n        markedReaderIndex = readerIndex;\n    }\n\n    @Override\n    public void resetReaderIndex() {\n        readerIndex(markedReaderIndex);\n    }\n\n    @Override\n    public void markWriterIndex() {\n        markedWriterIndex = writerIndex;\n    }\n\n    @Override\n    public void resetWriterIndex() {\n        writerIndex = markedWriterIndex;\n    }\n\n    @Override\n    public void discardReadBytes() {\n        if (readerIndex == 0) {\n            return;\n        }\n        setBytes(0, this, readerIndex, writerIndex - readerIndex);\n        writerIndex -= readerIndex;\n        markedReaderIndex = Math.max(markedReaderIndex - readerIndex, 0);\n        markedWriterIndex = Math.max(markedWriterIndex - readerIndex, 0);\n        readerIndex = 0;\n    }\n\n    @Override\n    public void ensureWritableBytes(int writableBytes) {\n        if (writableBytes > writableBytes()) {\n            throw new IndexOutOfBoundsException();\n        }\n    }\n\n    @Override\n    public void getBytes(int index, byte[] dst) {\n        getBytes(index, dst, 0, dst.length);\n    }\n\n    @Override\n    public void getBytes(int index, ChannelBuffer dst) {\n        getBytes(index, dst, dst.writableBytes());\n    }\n\n    @Override\n    public void getBytes(int index, ChannelBuffer dst, int length) {\n        if (length > dst.writableBytes()) {\n            throw new IndexOutOfBoundsException();\n        }\n        getBytes(index, dst, dst.writerIndex(), length);\n        dst.writerIndex(dst.writerIndex() + length);\n    }\n\n    @Override\n    public void setBytes(int index, byte[] src) {\n        setBytes(index, src, 0, src.length);\n    }\n\n    @Override\n    public void setBytes(int index, ChannelBuffer src) {\n        setBytes(index, src, src.readableBytes());\n    }\n\n    @Override\n    public void setBytes(int index, ChannelBuffer src, int length) {\n        if (length > src.readableBytes()) {\n            throw new IndexOutOfBoundsException();\n        }\n        setBytes(index, src, src.readerIndex(), length);\n        src.readerIndex(src.readerIndex() + length);\n    }\n\n    @Override\n    public byte readByte() {\n        if (readerIndex == writerIndex) {\n            throw new IndexOutOfBoundsException();\n        }\n        return getByte(readerIndex++);\n    }\n\n    @Override\n    public ChannelBuffer readBytes(int length) {\n        checkReadableBytes(length);\n        if (length == 0) {\n            return ChannelBuffers.EMPTY_BUFFER;\n        }\n        ChannelBuffer buf = factory().getBuffer(length);\n        buf.writeBytes(this, readerIndex, length);\n        readerIndex += length;\n        return buf;\n    }\n\n    @Override\n    public void readBytes(byte[] dst, int dstIndex, int length) {\n        checkReadableBytes(length);\n        getBytes(readerIndex, dst, dstIndex, length);\n        readerIndex += length;\n    }\n\n    @Override\n    public void readBytes(byte[] dst) {\n        readBytes(dst, 0, dst.length);\n    }\n\n    @Override\n    public void readBytes(ChannelBuffer dst) {\n        readBytes(dst, dst.writableBytes());\n    }\n\n    @Override\n    public void readBytes(ChannelBuffer dst, int length) {\n        if (length > dst.writableBytes()) {\n            throw new IndexOutOfBoundsException();\n        }\n        readBytes(dst, dst.writerIndex(), length);\n        dst.writerIndex(dst.writerIndex() + length);\n    }\n\n    @Override\n    public void readBytes(ChannelBuffer dst, int dstIndex, int length) {\n        checkReadableBytes(length);\n        getBytes(readerIndex, dst, dstIndex, length);\n        readerIndex += length;\n    }\n\n    @Override\n    public void readBytes(ByteBuffer dst) {\n        int length = dst.remaining();\n        checkReadableBytes(length);\n        getBytes(readerIndex, dst);\n        readerIndex += length;\n    }\n\n    @Override\n    public void readBytes(OutputStream out, int length) throws IOException {\n        checkReadableBytes(length);\n        getBytes(readerIndex, out, length);\n        readerIndex += length;\n    }\n\n    @Override\n    public void skipBytes(int length) {\n        int newReaderIndex = readerIndex + length;\n        if (newReaderIndex > writerIndex) {\n            throw new IndexOutOfBoundsException();\n        }\n        readerIndex = newReaderIndex;\n    }\n\n    @Override\n    public void writeByte(int value) {\n        setByte(writerIndex++, value);\n    }\n\n    @Override\n    public void writeBytes(byte[] src, int srcIndex, int length) {\n        setBytes(writerIndex, src, srcIndex, length);\n        writerIndex += length;\n    }\n\n    @Override\n    public void writeBytes(byte[] src) {\n        writeBytes(src, 0, src.length);\n    }\n\n    @Override\n    public void writeBytes(ChannelBuffer src) {\n        writeBytes(src, src.readableBytes());\n    }\n\n    @Override\n    public void writeBytes(ChannelBuffer src, int length) {\n        if (length > src.readableBytes()) {\n            throw new IndexOutOfBoundsException();\n        }\n        writeBytes(src, src.readerIndex(), length);\n        src.readerIndex(src.readerIndex() + length);\n    }\n\n    @Override\n    public void writeBytes(ChannelBuffer src, int srcIndex, int length) {\n        setBytes(writerIndex, src, srcIndex, length);\n        writerIndex += length;\n    }\n\n    @Override\n    public void writeBytes(ByteBuffer src) {\n        int length = src.remaining();\n        setBytes(writerIndex, src);\n        writerIndex += length;\n    }\n\n    @Override\n    public int writeBytes(InputStream in, int length) throws IOException {\n        int writtenBytes = setBytes(writerIndex, in, length);\n        if (writtenBytes > 0) {\n            writerIndex += writtenBytes;\n        }\n        return writtenBytes;\n    }\n\n    @Override\n    public ChannelBuffer copy() {\n        return copy(readerIndex, readableBytes());\n    }\n\n    @Override\n    public ByteBuffer toByteBuffer() {\n        return toByteBuffer(readerIndex, readableBytes());\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        return o instanceof ChannelBuffer && ChannelBuffers.equals(this, (ChannelBuffer) o);\n    }\n\n    @Override\n    public int hashCode() {\n        return ChannelBuffers.hasCode(this);\n    }\n\n    @Override\n    public int compareTo(ChannelBuffer that) {\n        return ChannelBuffers.compare(this, that);\n    }\n\n    @Override\n    public String toString() {\n        return getClass().getSimpleName() + '(' + \"ridx=\"\n                + readerIndex + \", \" + \"widx=\"\n                + writerIndex + \", \" + \"cap=\"\n                + capacity() + ')';\n    }\n\n    protected void checkReadableBytes(int minimumReadableBytes) {\n        if (readableBytes() < minimumReadableBytes) {\n            throw new IndexOutOfBoundsException();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/ByteBufferBackedChannelBuffer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\n\npublic class ByteBufferBackedChannelBuffer extends AbstractChannelBuffer {\n\n    private final ByteBuffer buffer;\n\n    private final int capacity;\n\n    public ByteBufferBackedChannelBuffer(ByteBuffer buffer) {\n        if (buffer == null) {\n            throw new NullPointerException(\"buffer\");\n        }\n\n        this.buffer = buffer.slice();\n        capacity = buffer.remaining();\n        writerIndex(capacity);\n    }\n\n    public ByteBufferBackedChannelBuffer(ByteBufferBackedChannelBuffer buffer) {\n        this.buffer = buffer.buffer;\n        capacity = buffer.capacity;\n        setIndex(buffer.readerIndex(), buffer.writerIndex());\n    }\n\n    @Override\n    public ChannelBufferFactory factory() {\n        if (buffer.isDirect()) {\n            return DirectChannelBufferFactory.getInstance();\n        } else {\n            return HeapChannelBufferFactory.getInstance();\n        }\n    }\n\n    @Override\n    public int capacity() {\n        return capacity;\n    }\n\n    @Override\n    public ChannelBuffer copy(int index, int length) {\n        ByteBuffer src;\n        try {\n            src = (ByteBuffer) buffer.duplicate().position(index).limit(index + length);\n        } catch (IllegalArgumentException e) {\n            throw new IndexOutOfBoundsException();\n        }\n\n        ByteBuffer dst = buffer.isDirect() ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length);\n        dst.put(src);\n        dst.clear();\n        return new ByteBufferBackedChannelBuffer(dst);\n    }\n\n    @Override\n    public byte getByte(int index) {\n        return buffer.get(index);\n    }\n\n    @Override\n    public void getBytes(int index, byte[] dst, int dstIndex, int length) {\n        ByteBuffer data = buffer.duplicate();\n        try {\n            data.limit(index + length).position(index);\n        } catch (IllegalArgumentException e) {\n            throw new IndexOutOfBoundsException();\n        }\n        data.get(dst, dstIndex, length);\n    }\n\n    @Override\n    public void getBytes(int index, ByteBuffer dst) {\n        ByteBuffer data = buffer.duplicate();\n        int bytesToCopy = Math.min(capacity() - index, dst.remaining());\n        try {\n            data.limit(index + bytesToCopy).position(index);\n        } catch (IllegalArgumentException e) {\n            throw new IndexOutOfBoundsException();\n        }\n        dst.put(data);\n    }\n\n    @Override\n    public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {\n        if (dst instanceof ByteBufferBackedChannelBuffer) {\n            ByteBufferBackedChannelBuffer bbdst = (ByteBufferBackedChannelBuffer) dst;\n            ByteBuffer data = bbdst.buffer.duplicate();\n\n            data.limit(dstIndex + length).position(dstIndex);\n            getBytes(index, data);\n        } else if (buffer.hasArray()) {\n            dst.setBytes(dstIndex, buffer.array(), index + buffer.arrayOffset(), length);\n        } else {\n            dst.setBytes(dstIndex, this, index, length);\n        }\n    }\n\n    @Override\n    public void getBytes(int index, OutputStream out, int length) throws IOException {\n        if (length == 0) {\n            return;\n        }\n\n        if (buffer.hasArray()) {\n            out.write(buffer.array(), index + buffer.arrayOffset(), length);\n        } else {\n            byte[] tmp = new byte[length];\n            ((ByteBuffer) buffer.duplicate().position(index)).get(tmp);\n            out.write(tmp);\n        }\n    }\n\n    @Override\n    public boolean isDirect() {\n        return buffer.isDirect();\n    }\n\n    @Override\n    public void setByte(int index, int value) {\n        buffer.put(index, (byte) value);\n    }\n\n    @Override\n    public void setBytes(int index, byte[] src, int srcIndex, int length) {\n        ByteBuffer data = buffer.duplicate();\n        data.limit(index + length).position(index);\n        data.put(src, srcIndex, length);\n    }\n\n    @Override\n    public void setBytes(int index, ByteBuffer src) {\n        ByteBuffer data = buffer.duplicate();\n        data.limit(index + src.remaining()).position(index);\n        data.put(src);\n    }\n\n    @Override\n    public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {\n        if (src instanceof ByteBufferBackedChannelBuffer) {\n            ByteBufferBackedChannelBuffer bbsrc = (ByteBufferBackedChannelBuffer) src;\n            ByteBuffer data = bbsrc.buffer.duplicate();\n\n            data.limit(srcIndex + length).position(srcIndex);\n            setBytes(index, data);\n        } else if (buffer.hasArray()) {\n            src.getBytes(srcIndex, buffer.array(), index + buffer.arrayOffset(), length);\n        } else {\n            src.getBytes(srcIndex, this, index, length);\n        }\n    }\n\n    @Override\n    public ByteBuffer toByteBuffer(int index, int length) {\n        if (index == 0 && length == capacity()) {\n            return buffer.duplicate();\n        } else {\n            return ((ByteBuffer) buffer.duplicate().position(index).limit(index + length)).slice();\n        }\n    }\n\n    @Override\n    public int setBytes(int index, InputStream in, int length) throws IOException {\n        int readBytes = 0;\n\n        if (buffer.hasArray()) {\n            index += buffer.arrayOffset();\n            do {\n                int localReadBytes = in.read(buffer.array(), index, length);\n                if (localReadBytes < 0) {\n                    if (readBytes == 0) {\n                        return -1;\n                    } else {\n                        break;\n                    }\n                }\n                readBytes += localReadBytes;\n                index += localReadBytes;\n                length -= localReadBytes;\n            } while (length > 0);\n        } else {\n            byte[] tmp = new byte[length];\n            int i = 0;\n            do {\n                int localReadBytes = in.read(tmp, i, tmp.length - i);\n                if (localReadBytes < 0) {\n                    if (readBytes == 0) {\n                        return -1;\n                    } else {\n                        break;\n                    }\n                }\n                readBytes += localReadBytes;\n                i += readBytes;\n            } while (i < tmp.length);\n            ((ByteBuffer) buffer.duplicate().position(index)).put(tmp);\n        }\n\n        return readBytes;\n    }\n\n    @Override\n    public byte[] array() {\n        return buffer.array();\n    }\n\n    @Override\n    public boolean hasArray() {\n        return buffer.hasArray();\n    }\n\n    @Override\n    public int arrayOffset() {\n        return buffer.arrayOffset();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/ChannelBuffer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\n\n/**\n * A random and sequential accessible sequence of zero or more bytes (octets).\n * This interface provides an abstract view for one or more primitive byte\n * arrays ({@code byte[]}) and {@linkplain ByteBuffer NIO buffers}.\n * <p/>\n * <h3>Creation of a buffer</h3>\n * <p/>\n * It is recommended to create a new buffer using the helper methods in {@link\n * ChannelBuffers} rather than calling an individual implementation's\n * constructor.\n * <p/>\n * <h3>Random Access Indexing</h3>\n * <p/>\n * Just like an ordinary primitive byte array, {@link ChannelBuffer} uses <a\n * href=\"http://en.wikipedia.org/wiki/Index_(information_technology)#Array_element_identifier\">zero-based\n * indexing</a>. It means the index of the first byte is always {@code 0} and\n * the index of the last byte is always {@link #capacity() capacity - 1}.  For\n * example, to iterate all bytes of a buffer, you can do the following,\n * regardless of its internal implementation:\n * <p/>\n * <pre>\n * {@link ChannelBuffer} buffer = ...;\n * for (int i = 0; i &lt; buffer.capacity(); i ++</strong>) {\n *     byte b = buffer.getByte(i);\n *     System.out.println((char) b);\n * }\n * </pre>\n * <p/>\n * <h3>Sequential Access Indexing</h3>\n * <p/>\n * {@link ChannelBuffer} provides two pointer variables to support sequential\n * read and write operations - {@link #readerIndex() readerIndex} for a read\n * operation and {@link #writerIndex() writerIndex} for a write operation\n * respectively.  The following diagram shows how a buffer is segmented into\n * three areas by the two pointers:\n * <p/>\n * <pre>\n *      +-------------------+------------------+------------------+\n *      | discardable bytes |  readable bytes  |  writable bytes  |\n *      |                   |     (CONTENT)    |                  |\n *      +-------------------+------------------+------------------+\n *      |                   |                  |                  |\n *      0      <=      readerIndex   <=   writerIndex    <=    capacity\n * </pre>\n * <p/>\n * <h4>Readable bytes (the actual content)</h4>\n * <p/>\n * This segment is where the actual data is stored.  Any operation whose name\n * starts with {@code read} or {@code skip} will get or skip the data at the\n * current {@link #readerIndex() readerIndex} and increase it by the number of\n * read bytes.  If the argument of the read operation is also a {@link\n * ChannelBuffer} and no destination index is specified, the specified buffer's\n * {@link #readerIndex() readerIndex} is increased together.\n * <p/>\n * If there's not enough content left, {@link IndexOutOfBoundsException} is\n * raised.  The default value of newly allocated, wrapped or copied buffer's\n * {@link #readerIndex() readerIndex} is {@code 0}.\n * <p/>\n * <pre>\n * // Iterates the readable bytes of a buffer.\n * {@link ChannelBuffer} buffer = ...;\n * while (buffer.readable()) {\n *     System.out.println(buffer.readByte());\n * }\n * </pre>\n * <p/>\n * <h4>Writable bytes</h4>\n * <p/>\n * This segment is a undefined space which needs to be filled.  Any operation\n * whose name ends with {@code write} will write the data at the current {@link\n * #writerIndex() writerIndex} and increase it by the number of written bytes.\n * If the argument of the write operation is also a {@link ChannelBuffer}, and\n * no source index is specified, the specified buffer's {@link #readerIndex()\n * readerIndex} is increased together.\n * <p/>\n * If there's not enough writable bytes left, {@link IndexOutOfBoundsException}\n * is raised.  The default value of newly allocated buffer's {@link\n * #writerIndex() writerIndex} is {@code 0}.  The default value of wrapped or\n * copied buffer's {@link #writerIndex() writerIndex} is the {@link #capacity()\n * capacity} of the buffer.\n * <p/>\n * <pre>\n * // Fills the writable bytes of a buffer with random integers.\n * {@link ChannelBuffer} buffer = ...;\n * while (buffer.writableBytes() >= 4) {\n *     buffer.writeInt(random.nextInt());\n * }\n * </pre>\n * <p/>\n * <h4>Discardable bytes</h4>\n * <p/>\n * This segment contains the bytes which were read already by a read operation.\n * Initially, the size of this segment is {@code 0}, but its size increases up\n * to the {@link #writerIndex() writerIndex} as read operations are executed.\n * The read bytes can be discarded by calling {@link #discardReadBytes()} to\n * reclaim unused area as depicted by the following diagram:\n * <p/>\n * <pre>\n *  BEFORE discardReadBytes()\n *\n *      +-------------------+------------------+------------------+\n *      | discardable bytes |  readable bytes  |  writable bytes  |\n *      +-------------------+------------------+------------------+\n *      |                   |                  |                  |\n *      0      <=      readerIndex   <=   writerIndex    <=    capacity\n *\n *\n *  AFTER discardReadBytes()\n *\n *      +------------------+--------------------------------------+\n *      |  readable bytes  |    writable bytes (got more space)   |\n *      +------------------+--------------------------------------+\n *      |                  |                                      |\n * readerIndex (0) <= writerIndex (decreased)        <=        capacity\n * </pre>\n * <p/>\n * Please note that there is no guarantee about the content of writable bytes\n * after calling {@link #discardReadBytes()}.  The writable bytes will not be\n * moved in most cases and could even be filled with completely different data\n * depending on the underlying buffer implementation.\n * <p/>\n * <h4>Clearing the buffer indexes</h4>\n * <p/>\n * You can set both {@link #readerIndex() readerIndex} and {@link #writerIndex()\n * writerIndex} to {@code 0} by calling {@link #clear()}. It does not clear the\n * buffer content (e.g. filling with {@code 0}) but just clears the two\n * pointers.  Please also note that the semantic of this operation is different\n * from {@link ByteBuffer#clear()}.\n * <p/>\n * <pre>\n *  BEFORE clear()\n *\n *      +-------------------+------------------+------------------+\n *      | discardable bytes |  readable bytes  |  writable bytes  |\n *      +-------------------+------------------+------------------+\n *      |                   |                  |                  |\n *      0      <=      readerIndex   <=   writerIndex    <=    capacity\n *\n *\n *  AFTER clear()\n *\n *      +---------------------------------------------------------+\n *      |             writable bytes (got more space)             |\n *      +---------------------------------------------------------+\n *      |                                                         |\n *      0 = readerIndex = writerIndex            <=            capacity\n * </pre>\n * <p/>\n * <h3>Mark and reset</h3>\n * <p/>\n * There are two marker indexes in every buffer. One is for storing {@link\n * #readerIndex() readerIndex} and the other is for storing {@link\n * #writerIndex() writerIndex}.  You can always reposition one of the two\n * indexes by calling a reset method.  It works in a similar fashion to the mark\n * and reset methods in {@link InputStream} except that there's no {@code\n * readlimit}.\n * <p/>\n * <h3>Conversion to existing JDK types</h3>\n * <p/>\n * <h4>Byte array</h4>\n * <p/>\n * If a {@link ChannelBuffer} is backed by a byte array (i.e. {@code byte[]}),\n * you can access it directly via the {@link #array()} method.  To determine if\n * a buffer is backed by a byte array, {@link #hasArray()} should be used.\n * <p/>\n * <h4>NIO Buffers</h4>\n * <p/>\n * Various {@link #toByteBuffer()}  methods convert a {@link ChannelBuffer} into\n * one or more NIO buffers.  These methods avoid buffer allocation and memory\n * copy whenever possible, but there's no guarantee that memory copy will not be\n * involved.\n * <p/>\n * <h4>I/O Streams</h4>\n * <p/>\n * Please refer to {@link ChannelBufferInputStream} and {@link\n * ChannelBufferOutputStream}.\n *\n *\n */\npublic interface ChannelBuffer extends Comparable<ChannelBuffer> {\n\n    /**\n     * Returns the number of bytes (octets) this buffer can contain.\n     */\n    int capacity();\n\n    /**\n     * Sets the {@code readerIndex} and {@code writerIndex} of this buffer to\n     * {@code 0}. This method is identical to {@link #setIndex(int, int)\n     * setIndex(0, 0)}.\n     * <p/>\n     * Please note that the behavior of this method is different from that of\n     * NIO buffer, which sets the {@code limit} to the {@code capacity} of the\n     * buffer.\n     */\n    void clear();\n\n    /**\n     * Returns a copy of this buffer's readable bytes.  Modifying the content of\n     * the returned buffer or this buffer does not affect each other at all.\n     * This method is identical to {@code buf.copy(buf.readerIndex(),\n     * buf.readableBytes())}. This method does not modify {@code readerIndex} or\n     * {@code writerIndex} of this buffer.\n     */\n    ChannelBuffer copy();\n\n    /**\n     * Returns a copy of this buffer's sub-region.  Modifying the content of the\n     * returned buffer or this buffer does not affect each other at all. This\n     * method does not modify {@code readerIndex} or {@code writerIndex} of this\n     * buffer.\n     */\n    ChannelBuffer copy(int index, int length);\n\n    /**\n     * Discards the bytes between the 0th index and {@code readerIndex}. It\n     * moves the bytes between {@code readerIndex} and {@code writerIndex} to\n     * the 0th index, and sets {@code readerIndex} and {@code writerIndex} to\n     * {@code 0} and {@code oldWriterIndex - oldReaderIndex} respectively.\n     * <p/>\n     * Please refer to the class documentation for more detailed explanation.\n     */\n    void discardReadBytes();\n\n    /**\n     * Makes sure the number of {@linkplain #writableBytes() the writable bytes}\n     * is equal to or greater than the specified value.  If there is enough\n     * writable bytes in this buffer, this method returns with no side effect.\n     * Otherwise: <ul> <li>a non-dynamic buffer will throw an {@link\n     * IndexOutOfBoundsException}.</li> <li>a dynamic buffer will expand its\n     * capacity so that the number of the {@link #writableBytes() writable\n     * bytes} becomes equal to or greater than the specified value. The\n     * expansion involves the reallocation of the internal buffer and\n     * consequently memory copy.</li> </ul>\n     *\n     * @param writableBytes the expected minimum number of writable bytes\n     * @throws IndexOutOfBoundsException if {@linkplain #writableBytes() the\n     *                                   writable bytes} of this buffer is less\n     *                                   than the specified value and if this\n     *                                   buffer is not a dynamic buffer\n     */\n    void ensureWritableBytes(int writableBytes);\n\n    /**\n     * Determines if the content of the specified buffer is identical to the\n     * content of this array.  'Identical' here means: <ul> <li>the size of the\n     * contents of the two buffers are same and</li> <li>every single byte of\n     * the content of the two buffers are same.</li> </ul> Please note that it\n     * does not compare {@link #readerIndex()} nor {@link #writerIndex()}.  This\n     * method also returns {@code false} for {@code null} and an object which is\n     * not an instance of {@link ChannelBuffer} type.\n     */\n    @Override\n    boolean equals(Object o);\n\n    /**\n     * Returns the factory which creates a {@link ChannelBuffer} whose type and\n     * default {@link java.nio.ByteOrder} are same with this buffer.\n     */\n    ChannelBufferFactory factory();\n\n    /**\n     * Gets a byte at the specified absolute {@code index} in this buffer. This\n     * method does not modify {@code readerIndex} or {@code writerIndex} of this\n     * buffer.\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0} or {@code index + 1} is\n     *                                   greater than {@code this.capacity}\n     */\n    byte getByte(int index);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * specified absolute {@code index}. This method does not modify {@code\n     * readerIndex} or {@code writerIndex} of this buffer\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0} or if {@code index +\n     *                                   dst.length} is greater than {@code\n     *                                   this.capacity}\n     */\n    void getBytes(int index, byte[] dst);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * specified absolute {@code index}. This method does not modify {@code\n     * readerIndex} or {@code writerIndex} of this buffer.\n     *\n     * @param dstIndex the first index of the destination\n     * @param length   the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0}, if the specified {@code\n     *                                   dstIndex} is less than {@code 0}, if\n     *                                   {@code index + length} is greater than\n     *                                   {@code this.capacity}, or if {@code\n     *                                   dstIndex + length} is greater than\n     *                                   {@code dst.length}\n     */\n    void getBytes(int index, byte[] dst, int dstIndex, int length);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * specified absolute {@code index} until the destination's position reaches\n     * its limit. This method does not modify {@code readerIndex} or {@code\n     * writerIndex} of this buffer while the destination's {@code position} will\n     * be increased.\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0} or if {@code index +\n     *                                   dst.remaining()} is greater than {@code\n     *                                   this.capacity}\n     */\n    void getBytes(int index, ByteBuffer dst);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * specified absolute {@code index} until the destination becomes\n     * non-writable.  This method is basically same with {@link #getBytes(int,\n     * ChannelBuffer, int, int)}, except that this method increases the {@code\n     * writerIndex} of the destination by the number of the transferred bytes\n     * while {@link #getBytes(int, ChannelBuffer, int, int)} does not. This\n     * method does not modify {@code readerIndex} or {@code writerIndex} of the\n     * source buffer (i.e. {@code this}).\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0} or if {@code index +\n     *                                   dst.writableBytes} is greater than\n     *                                   {@code this.capacity}\n     */\n    void getBytes(int index, ChannelBuffer dst);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * specified absolute {@code index}.  This method is basically same with\n     * {@link #getBytes(int, ChannelBuffer, int, int)}, except that this method\n     * increases the {@code writerIndex} of the destination by the number of the\n     * transferred bytes while {@link #getBytes(int, ChannelBuffer, int, int)}\n     * does not. This method does not modify {@code readerIndex} or {@code\n     * writerIndex} of the source buffer (i.e. {@code this}).\n     *\n     * @param length the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0}, if {@code index +\n     *                                   length} is greater than {@code\n     *                                   this.capacity}, or if {@code length} is\n     *                                   greater than {@code dst.writableBytes}\n     */\n    void getBytes(int index, ChannelBuffer dst, int length);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * specified absolute {@code index}. This method does not modify {@code\n     * readerIndex} or {@code writerIndex} of both the source (i.e. {@code\n     * this}) and the destination.\n     *\n     * @param dstIndex the first index of the destination\n     * @param length   the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0}, if the specified {@code\n     *                                   dstIndex} is less than {@code 0}, if\n     *                                   {@code index + length} is greater than\n     *                                   {@code this.capacity}, or if {@code\n     *                                   dstIndex + length} is greater than\n     *                                   {@code dst.capacity}\n     */\n    void getBytes(int index, ChannelBuffer dst, int dstIndex, int length);\n\n    /**\n     * Transfers this buffer's data to the specified stream starting at the\n     * specified absolute {@code index}. This method does not modify {@code\n     * readerIndex} or {@code writerIndex} of this buffer.\n     *\n     * @param length the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0} or if {@code index +\n     *                                   length} is greater than {@code\n     *                                   this.capacity}\n     * @throws IOException               if the specified stream threw an\n     *                                   exception during I/O\n     */\n    void getBytes(int index, OutputStream dst, int length) throws IOException;\n\n    /**\n     * Returns {@code true} if and only if this buffer is backed by an NIO\n     * direct buffer.\n     */\n    boolean isDirect();\n\n    /**\n     * Marks the current {@code readerIndex} in this buffer.  You can reposition\n     * the current {@code readerIndex} to the marked {@code readerIndex} by\n     * calling {@link #resetReaderIndex()}. The initial value of the marked\n     * {@code readerIndex} is {@code 0}.\n     */\n    void markReaderIndex();\n\n    /**\n     * Marks the current {@code writerIndex} in this buffer.  You can reposition\n     * the current {@code writerIndex} to the marked {@code writerIndex} by\n     * calling {@link #resetWriterIndex()}. The initial value of the marked\n     * {@code writerIndex} is {@code 0}.\n     */\n    void markWriterIndex();\n\n    /**\n     * Returns {@code true} if and only if {@code (this.writerIndex -\n     * this.readerIndex)} is greater than {@code 0}.\n     */\n    boolean readable();\n\n    /**\n     * Returns the number of readable bytes which is equal to {@code\n     * (this.writerIndex - this.readerIndex)}.\n     */\n    int readableBytes();\n\n    /**\n     * Gets a byte at the current {@code readerIndex} and increases the {@code\n     * readerIndex} by {@code 1} in this buffer.\n     *\n     * @throws IndexOutOfBoundsException if {@code this.readableBytes} is less\n     *                                   than {@code 1}\n     */\n    byte readByte();\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * current {@code readerIndex} and increases the {@code readerIndex} by the\n     * number of the transferred bytes (= {@code dst.length}).\n     *\n     * @throws IndexOutOfBoundsException if {@code dst.length} is greater than\n     *                                   {@code this.readableBytes}\n     */\n    void readBytes(byte[] dst);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * current {@code readerIndex} and increases the {@code readerIndex} by the\n     * number of the transferred bytes (= {@code length}).\n     *\n     * @param dstIndex the first index of the destination\n     * @param length   the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if the specified {@code dstIndex} is\n     *                                   less than {@code 0}, if {@code length}\n     *                                   is greater than {@code this.readableBytes},\n     *                                   or if {@code dstIndex + length} is\n     *                                   greater than {@code dst.length}\n     */\n    void readBytes(byte[] dst, int dstIndex, int length);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * current {@code readerIndex} until the destination's position reaches its\n     * limit, and increases the {@code readerIndex} by the number of the\n     * transferred bytes.\n     *\n     * @throws IndexOutOfBoundsException if {@code dst.remaining()} is greater\n     *                                   than {@code this.readableBytes}\n     */\n    void readBytes(ByteBuffer dst);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * current {@code readerIndex} until the destination becomes non-writable,\n     * and increases the {@code readerIndex} by the number of the transferred\n     * bytes.  This method is basically same with {@link\n     * #readBytes(ChannelBuffer, int, int)}, except that this method increases\n     * the {@code writerIndex} of the destination by the number of the\n     * transferred bytes while {@link #readBytes(ChannelBuffer, int, int)} does\n     * not.\n     *\n     * @throws IndexOutOfBoundsException if {@code dst.writableBytes} is greater\n     *                                   than {@code this.readableBytes}\n     */\n    void readBytes(ChannelBuffer dst);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * current {@code readerIndex} and increases the {@code readerIndex} by the\n     * number of the transferred bytes (= {@code length}).  This method is\n     * basically same with {@link #readBytes(ChannelBuffer, int, int)}, except\n     * that this method increases the {@code writerIndex} of the destination by\n     * the number of the transferred bytes (= {@code length}) while {@link\n     * #readBytes(ChannelBuffer, int, int)} does not.\n     *\n     * @throws IndexOutOfBoundsException if {@code length} is greater than\n     *                                   {@code this.readableBytes} or if {@code\n     *                                   length} is greater than {@code\n     *                                   dst.writableBytes}\n     */\n    void readBytes(ChannelBuffer dst, int length);\n\n    /**\n     * Transfers this buffer's data to the specified destination starting at the\n     * current {@code readerIndex} and increases the {@code readerIndex} by the\n     * number of the transferred bytes (= {@code length}).\n     *\n     * @param dstIndex the first index of the destination\n     * @param length   the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if the specified {@code dstIndex} is\n     *                                   less than {@code 0}, if {@code length}\n     *                                   is greater than {@code this.readableBytes},\n     *                                   or if {@code dstIndex + length} is\n     *                                   greater than {@code dst.capacity}\n     */\n    void readBytes(ChannelBuffer dst, int dstIndex, int length);\n\n    /**\n     * Transfers this buffer's data to a newly created buffer starting at the\n     * current {@code readerIndex} and increases the {@code readerIndex} by the\n     * number of the transferred bytes (= {@code length}). The returned buffer's\n     * {@code readerIndex} and {@code writerIndex} are {@code 0} and {@code\n     * length} respectively.\n     *\n     * @param length the number of bytes to transfer\n     * @return the newly created buffer which contains the transferred bytes\n     * @throws IndexOutOfBoundsException if {@code length} is greater than\n     *                                   {@code this.readableBytes}\n     */\n    ChannelBuffer readBytes(int length);\n\n    /**\n     * Repositions the current {@code readerIndex} to the marked {@code\n     * readerIndex} in this buffer.\n     *\n     * @throws IndexOutOfBoundsException if the current {@code writerIndex} is\n     *                                   less than the marked {@code\n     *                                   readerIndex}\n     */\n    void resetReaderIndex();\n\n    /**\n     * Marks the current {@code writerIndex} in this buffer.  You can reposition\n     * the current {@code writerIndex} to the marked {@code writerIndex} by\n     * calling {@link #resetWriterIndex()}. The initial value of the marked\n     * {@code writerIndex} is {@code 0}.\n     */\n    void resetWriterIndex();\n\n    /**\n     * Returns the {@code readerIndex} of this buffer.\n     */\n    int readerIndex();\n\n    /**\n     * Sets the {@code readerIndex} of this buffer.\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code readerIndex} is\n     *                                   less than {@code 0} or greater than\n     *                                   {@code this.writerIndex}\n     */\n    void readerIndex(int readerIndex);\n\n    /**\n     * Transfers this buffer's data to the specified stream starting at the\n     * current {@code readerIndex}.\n     *\n     * @param length the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if {@code length} is greater than\n     *                                   {@code this.readableBytes}\n     * @throws IOException               if the specified stream threw an\n     *                                   exception during I/O\n     */\n    void readBytes(OutputStream dst, int length) throws IOException;\n\n    /**\n     * Sets the specified byte at the specified absolute {@code index} in this\n     * buffer.  The 24 high-order bits of the specified value are ignored. This\n     * method does not modify {@code readerIndex} or {@code writerIndex} of this\n     * buffer.\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0} or {@code index + 1} is\n     *                                   greater than {@code this.capacity}\n     */\n    void setByte(int index, int value);\n\n    /**\n     * Transfers the specified source array's data to this buffer starting at\n     * the specified absolute {@code index}. This method does not modify {@code\n     * readerIndex} or {@code writerIndex} of this buffer.\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0} or if {@code index +\n     *                                   src.length} is greater than {@code\n     *                                   this.capacity}\n     */\n    void setBytes(int index, byte[] src);\n\n    /**\n     * Transfers the specified source array's data to this buffer starting at\n     * the specified absolute {@code index}. This method does not modify {@code\n     * readerIndex} or {@code writerIndex} of this buffer.\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0}, if the specified {@code\n     *                                   srcIndex} is less than {@code 0}, if\n     *                                   {@code index + length} is greater than\n     *                                   {@code this.capacity}, or if {@code\n     *                                   srcIndex + length} is greater than\n     *                                   {@code src.length}\n     */\n    void setBytes(int index, byte[] src, int srcIndex, int length);\n\n    /**\n     * Transfers the specified source buffer's data to this buffer starting at\n     * the specified absolute {@code index} until the source buffer's position\n     * reaches its limit. This method does not modify {@code readerIndex} or\n     * {@code writerIndex} of this buffer.\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0} or if {@code index +\n     *                                   src.remaining()} is greater than {@code\n     *                                   this.capacity}\n     */\n    void setBytes(int index, ByteBuffer src);\n\n    /**\n     * Transfers the specified source buffer's data to this buffer starting at\n     * the specified absolute {@code index} until the source buffer becomes\n     * unreadable.  This method is basically same with {@link #setBytes(int,\n     * ChannelBuffer, int, int)}, except that this method increases the {@code\n     * readerIndex} of the source buffer by the number of the transferred bytes\n     * while {@link #setBytes(int, ChannelBuffer, int, int)} does not. This\n     * method does not modify {@code readerIndex} or {@code writerIndex} of the\n     * source buffer (i.e. {@code this}).\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0} or if {@code index +\n     *                                   src.readableBytes} is greater than\n     *                                   {@code this.capacity}\n     */\n    void setBytes(int index, ChannelBuffer src);\n\n    /**\n     * Transfers the specified source buffer's data to this buffer starting at\n     * the specified absolute {@code index}.  This method is basically same with\n     * {@link #setBytes(int, ChannelBuffer, int, int)}, except that this method\n     * increases the {@code readerIndex} of the source buffer by the number of\n     * the transferred bytes while {@link #setBytes(int, ChannelBuffer, int,\n     * int)} does not. This method does not modify {@code readerIndex} or {@code\n     * writerIndex} of the source buffer (i.e. {@code this}).\n     *\n     * @param length the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0}, if {@code index +\n     *                                   length} is greater than {@code\n     *                                   this.capacity}, or if {@code length} is\n     *                                   greater than {@code src.readableBytes}\n     */\n    void setBytes(int index, ChannelBuffer src, int length);\n\n    /**\n     * Transfers the specified source buffer's data to this buffer starting at\n     * the specified absolute {@code index}. This method does not modify {@code\n     * readerIndex} or {@code writerIndex} of both the source (i.e. {@code\n     * this}) and the destination.\n     *\n     * @param srcIndex the first index of the source\n     * @param length   the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0}, if the specified {@code\n     *                                   srcIndex} is less than {@code 0}, if\n     *                                   {@code index + length} is greater than\n     *                                   {@code this.capacity}, or if {@code\n     *                                   srcIndex + length} is greater than\n     *                                   {@code src.capacity}\n     */\n    void setBytes(int index, ChannelBuffer src, int srcIndex, int length);\n\n    /**\n     * Transfers the content of the specified source stream to this buffer\n     * starting at the specified absolute {@code index}. This method does not\n     * modify {@code readerIndex} or {@code writerIndex} of this buffer.\n     *\n     * @param length the number of bytes to transfer\n     * @return the actual number of bytes read in from the specified channel.\n     * {@code -1} if the specified channel is closed.\n     * @throws IndexOutOfBoundsException if the specified {@code index} is less\n     *                                   than {@code 0} or if {@code index +\n     *                                   length} is greater than {@code\n     *                                   this.capacity}\n     * @throws IOException               if the specified stream threw an\n     *                                   exception during I/O\n     */\n    int setBytes(int index, InputStream src, int length) throws IOException;\n\n    /**\n     * Sets the {@code readerIndex} and {@code writerIndex} of this buffer in\n     * one shot.  This method is useful when you have to worry about the\n     * invocation order of {@link #readerIndex(int)} and {@link\n     * #writerIndex(int)} methods.  For example, the following code will fail:\n     * <p/>\n     * <pre>\n     * // Create a buffer whose readerIndex, writerIndex and capacity are\n     * // 0, 0 and 8 respectively.\n     * {@link ChannelBuffer} buf = {@link ChannelBuffers}.buffer(8);\n     *\n     * // IndexOutOfBoundsException is thrown because the specified\n     * // readerIndex (2) cannot be greater than the current writerIndex (0).\n     * buf.readerIndex(2);\n     * buf.writerIndex(4);\n     * </pre>\n     * <p/>\n     * The following code will also fail:\n     * <p/>\n     * <pre>\n     * // Create a buffer whose readerIndex, writerIndex and capacity are\n     * // 0, 8 and 8 respectively.\n     * {@link ChannelBuffer} buf = {@link ChannelBuffers}.wrappedBuffer(new\n     * byte[8]);\n     *\n     * // readerIndex becomes 8.\n     * buf.readLong();\n     *\n     * // IndexOutOfBoundsException is thrown because the specified\n     * // writerIndex (4) cannot be less than the current readerIndex (8).\n     * buf.writerIndex(4);\n     * buf.readerIndex(2);\n     * </pre>\n     * <p/>\n     * By contrast, {@link #setIndex(int, int)} guarantees that it never throws\n     * an {@link IndexOutOfBoundsException} as long as the specified indexes\n     * meet basic constraints, regardless what the current index values of the\n     * buffer are:\n     * <p/>\n     * <pre>\n     * // No matter what the current state of the buffer is, the following\n     * // call always succeeds as long as the capacity of the buffer is not\n     * // less than 4.\n     * buf.setIndex(2, 4);\n     * </pre>\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code readerIndex} is\n     *                                   less than 0, if the specified {@code\n     *                                   writerIndex} is less than the specified\n     *                                   {@code readerIndex} or if the specified\n     *                                   {@code writerIndex} is greater than\n     *                                   {@code this.capacity}\n     */\n    void setIndex(int readerIndex, int writerIndex);\n\n    /**\n     * Increases the current {@code readerIndex} by the specified {@code length}\n     * in this buffer.\n     *\n     * @throws IndexOutOfBoundsException if {@code length} is greater than\n     *                                   {@code this.readableBytes}\n     */\n    void skipBytes(int length);\n\n    /**\n     * Converts this buffer's readable bytes into a NIO buffer.  The returned\n     * buffer might or might not share the content with this buffer, while they\n     * have separate indexes and marks.  This method is identical to {@code\n     * buf.toByteBuffer(buf.readerIndex(), buf.readableBytes())}. This method\n     * does not modify {@code readerIndex} or {@code writerIndex} of this\n     * buffer.\n     */\n    ByteBuffer toByteBuffer();\n\n    /**\n     * Converts this buffer's sub-region into a NIO buffer.  The returned buffer\n     * might or might not share the content with this buffer, while they have\n     * separate indexes and marks. This method does not modify {@code\n     * readerIndex} or {@code writerIndex} of this buffer.\n     */\n    ByteBuffer toByteBuffer(int index, int length);\n\n    /**\n     * Returns {@code true} if and only if {@code (this.capacity -\n     * this.writerIndex)} is greater than {@code 0}.\n     */\n    boolean writable();\n\n    /**\n     * Returns the number of writable bytes which is equal to {@code\n     * (this.capacity - this.writerIndex)}.\n     */\n    int writableBytes();\n\n    /**\n     * Sets the specified byte at the current {@code writerIndex} and increases\n     * the {@code writerIndex} by {@code 1} in this buffer. The 24 high-order\n     * bits of the specified value are ignored.\n     *\n     * @throws IndexOutOfBoundsException if {@code this.writableBytes} is less\n     *                                   than {@code 1}\n     */\n    void writeByte(int value);\n\n    /**\n     * Transfers the specified source array's data to this buffer starting at\n     * the current {@code writerIndex} and increases the {@code writerIndex} by\n     * the number of the transferred bytes (= {@code src.length}).\n     *\n     * @throws IndexOutOfBoundsException if {@code src.length} is greater than\n     *                                   {@code this.writableBytes}\n     */\n    void writeBytes(byte[] src);\n\n    /**\n     * Transfers the specified source array's data to this buffer starting at\n     * the current {@code writerIndex} and increases the {@code writerIndex} by\n     * the number of the transferred bytes (= {@code length}).\n     *\n     * @param index  the first index of the source\n     * @param length the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if the specified {@code srcIndex} is\n     *                                   less than {@code 0}, if {@code srcIndex\n     *                                   + length} is greater than {@code\n     *                                   src.length}, or if {@code length} is\n     *                                   greater than {@code this.writableBytes}\n     */\n    void writeBytes(byte[] src, int index, int length);\n\n    /**\n     * Transfers the specified source buffer's data to this buffer starting at\n     * the current {@code writerIndex} until the source buffer's position\n     * reaches its limit, and increases the {@code writerIndex} by the number of\n     * the transferred bytes.\n     *\n     * @throws IndexOutOfBoundsException if {@code src.remaining()} is greater\n     *                                   than {@code this.writableBytes}\n     */\n    void writeBytes(ByteBuffer src);\n\n    /**\n     * Transfers the specified source buffer's data to this buffer starting at\n     * the current {@code writerIndex} until the source buffer becomes\n     * unreadable, and increases the {@code writerIndex} by the number of the\n     * transferred bytes.  This method is basically same with {@link\n     * #writeBytes(ChannelBuffer, int, int)}, except that this method increases\n     * the {@code readerIndex} of the source buffer by the number of the\n     * transferred bytes while {@link #writeBytes(ChannelBuffer, int, int)} does\n     * not.\n     *\n     * @throws IndexOutOfBoundsException if {@code src.readableBytes} is greater\n     *                                   than {@code this.writableBytes}\n     */\n    void writeBytes(ChannelBuffer src);\n\n    /**\n     * Transfers the specified source buffer's data to this buffer starting at\n     * the current {@code writerIndex} and increases the {@code writerIndex} by\n     * the number of the transferred bytes (= {@code length}).  This method is\n     * basically same with {@link #writeBytes(ChannelBuffer, int, int)}, except\n     * that this method increases the {@code readerIndex} of the source buffer\n     * by the number of the transferred bytes (= {@code length}) while {@link\n     * #writeBytes(ChannelBuffer, int, int)} does not.\n     *\n     * @param length the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if {@code length} is greater than\n     *                                   {@code this.writableBytes} or if {@code\n     *                                   length} is greater then {@code\n     *                                   src.readableBytes}\n     */\n    void writeBytes(ChannelBuffer src, int length);\n\n    /**\n     * Transfers the specified source buffer's data to this buffer starting at\n     * the current {@code writerIndex} and increases the {@code writerIndex} by\n     * the number of the transferred bytes (= {@code length}).\n     *\n     * @param srcIndex the first index of the source\n     * @param length   the number of bytes to transfer\n     * @throws IndexOutOfBoundsException if the specified {@code srcIndex} is\n     *                                   less than {@code 0}, if {@code srcIndex\n     *                                   + length} is greater than {@code\n     *                                   src.capacity}, or if {@code length} is\n     *                                   greater than {@code this.writableBytes}\n     */\n    void writeBytes(ChannelBuffer src, int srcIndex, int length);\n\n    /**\n     * Transfers the content of the specified stream to this buffer starting at\n     * the current {@code writerIndex} and increases the {@code writerIndex} by\n     * the number of the transferred bytes.\n     *\n     * @param length the number of bytes to transfer\n     * @return the actual number of bytes read in from the specified stream\n     * @throws IndexOutOfBoundsException if {@code length} is greater than\n     *                                   {@code this.writableBytes}\n     * @throws IOException               if the specified stream threw an\n     *                                   exception during I/O\n     */\n    int writeBytes(InputStream src, int length) throws IOException;\n\n    /**\n     * Returns the {@code writerIndex} of this buffer.\n     */\n    int writerIndex();\n\n    /**\n     * Sets the {@code writerIndex} of this buffer.\n     *\n     * @throws IndexOutOfBoundsException if the specified {@code writerIndex} is\n     *                                   less than {@code this.readerIndex} or\n     *                                   greater than {@code this.capacity}\n     */\n    void writerIndex(int writerIndex);\n\n    /**\n     * Returns the backing byte array of this buffer.\n     *\n     * @throws UnsupportedOperationException if there is no accessible backing byte\n     *                                       array\n     */\n    byte[] array();\n\n    /**\n     * Returns {@code true} if and only if this buffer has a backing byte array.\n     * If this method returns true, you can safely call {@link #array()} and\n     * {@link #arrayOffset()}.\n     */\n    boolean hasArray();\n\n    /**\n     * Returns the offset of the first byte within the backing byte array of\n     * this buffer.\n     *\n     * @throws UnsupportedOperationException if there is no accessible backing byte\n     *                                       array\n     */\n    int arrayOffset();\n\n    /**\n     * If this buffer is backed by an NIO direct buffer,\n     * in some scenarios it may be necessary to manually release.\n     */\n    default void release() {}\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/ChannelBufferFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.nio.ByteBuffer;\n\npublic interface ChannelBufferFactory {\n\n    ChannelBuffer getBuffer(int capacity);\n\n    ChannelBuffer getBuffer(byte[] array, int offset, int length);\n\n    ChannelBuffer getBuffer(ByteBuffer nioBuffer);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/ChannelBufferInputStream.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\npublic class ChannelBufferInputStream extends InputStream {\n\n    private final ChannelBuffer buffer;\n    private final int startIndex;\n    private final int endIndex;\n\n    public ChannelBufferInputStream(ChannelBuffer buffer) {\n        this(buffer, buffer.readableBytes());\n    }\n\n    public ChannelBufferInputStream(ChannelBuffer buffer, int length) {\n        if (buffer == null) {\n            throw new NullPointerException(\"buffer\");\n        }\n        if (length < 0) {\n            throw new IllegalArgumentException(\"length: \" + length);\n        }\n        if (length > buffer.readableBytes()) {\n            throw new IndexOutOfBoundsException();\n        }\n\n        this.buffer = buffer;\n        startIndex = buffer.readerIndex();\n        endIndex = startIndex + length;\n        buffer.markReaderIndex();\n    }\n\n    public int readBytes() {\n        return buffer.readerIndex() - startIndex;\n    }\n\n    @Override\n    public int available() throws IOException {\n        return endIndex - buffer.readerIndex();\n    }\n\n    @Override\n    public synchronized void mark(int readLimit) {\n        buffer.markReaderIndex();\n    }\n\n    @Override\n    public boolean markSupported() {\n        return true;\n    }\n\n    @Override\n    public int read() throws IOException {\n        if (!buffer.readable()) {\n            return -1;\n        }\n        return buffer.readByte() & 0xff;\n    }\n\n    @Override\n    public int read(byte[] b, int off, int len) throws IOException {\n        int available = available();\n        if (available == 0) {\n            return -1;\n        }\n\n        len = Math.min(available, len);\n        buffer.readBytes(b, off, len);\n        return len;\n    }\n\n    @Override\n    public synchronized void reset() throws IOException {\n        buffer.resetReaderIndex();\n    }\n\n    @Override\n    public long skip(long n) throws IOException {\n        if (n > Integer.MAX_VALUE) {\n            return skipBytes(Integer.MAX_VALUE);\n        } else {\n            return skipBytes((int) n);\n        }\n    }\n\n    private int skipBytes(int n) throws IOException {\n        int nBytes = Math.min(available(), n);\n        buffer.skipBytes(nBytes);\n        return nBytes;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/ChannelBufferOutputStream.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\npublic class ChannelBufferOutputStream extends OutputStream {\n\n    private final ChannelBuffer buffer;\n    private final int startIndex;\n\n    public ChannelBufferOutputStream(ChannelBuffer buffer) {\n        if (buffer == null) {\n            throw new NullPointerException(\"buffer\");\n        }\n        this.buffer = buffer;\n        startIndex = buffer.writerIndex();\n    }\n\n    public int writtenBytes() {\n        return buffer.writerIndex() - startIndex;\n    }\n\n    @Override\n    public void write(byte[] b, int off, int len) throws IOException {\n        if (len == 0) {\n            return;\n        }\n\n        buffer.writeBytes(b, off, len);\n    }\n\n    @Override\n    public void write(byte[] b) throws IOException {\n        buffer.writeBytes(b);\n    }\n\n    @Override\n    public void write(int b) throws IOException {\n        buffer.writeByte((byte) b);\n    }\n\n    public ChannelBuffer buffer() {\n        return buffer;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/ChannelBuffers.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.nio.ByteBuffer;\n\npublic final class ChannelBuffers {\n\n    public static final ChannelBuffer EMPTY_BUFFER = new HeapChannelBuffer(0);\n\n    public static final int DEFAULT_CAPACITY = 256;\n\n    private ChannelBuffers() {}\n\n    public static ChannelBuffer dynamicBuffer() {\n        return dynamicBuffer(DEFAULT_CAPACITY);\n    }\n\n    public static ChannelBuffer dynamicBuffer(int capacity) {\n        return new DynamicChannelBuffer(capacity);\n    }\n\n    public static ChannelBuffer dynamicBuffer(int capacity, ChannelBufferFactory factory) {\n        return new DynamicChannelBuffer(capacity, factory);\n    }\n\n    public static ChannelBuffer buffer(int capacity) {\n        if (capacity < 0) {\n            throw new IllegalArgumentException(\"capacity can not be negative\");\n        }\n        if (capacity == 0) {\n            return EMPTY_BUFFER;\n        }\n        return new HeapChannelBuffer(capacity);\n    }\n\n    public static ChannelBuffer wrappedBuffer(byte[] array, int offset, int length) {\n        if (array == null) {\n            throw new NullPointerException(\"array == null\");\n        }\n        byte[] dest = new byte[length];\n        System.arraycopy(array, offset, dest, 0, length);\n        return wrappedBuffer(dest);\n    }\n\n    public static ChannelBuffer wrappedBuffer(byte[] array) {\n        if (array == null) {\n            throw new NullPointerException(\"array == null\");\n        }\n        if (array.length == 0) {\n            return EMPTY_BUFFER;\n        }\n        return new HeapChannelBuffer(array);\n    }\n\n    public static ChannelBuffer wrappedBuffer(ByteBuffer buffer) {\n        if (!buffer.hasRemaining()) {\n            return EMPTY_BUFFER;\n        }\n        if (buffer.hasArray()) {\n            return wrappedBuffer(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());\n        } else {\n            return new ByteBufferBackedChannelBuffer(buffer);\n        }\n    }\n\n    public static ChannelBuffer directBuffer(int capacity) {\n        if (capacity == 0) {\n            return EMPTY_BUFFER;\n        }\n\n        ChannelBuffer buffer = new ByteBufferBackedChannelBuffer(ByteBuffer.allocateDirect(capacity));\n        buffer.clear();\n        return buffer;\n    }\n\n    public static boolean equals(ChannelBuffer bufferA, ChannelBuffer bufferB) {\n        final int aLen = bufferA.readableBytes();\n        if (aLen != bufferB.readableBytes()) {\n            return false;\n        }\n\n        final int byteCount = aLen & 7;\n\n        int aIndex = bufferA.readerIndex();\n        int bIndex = bufferB.readerIndex();\n\n        for (int i = byteCount; i > 0; i--) {\n            if (bufferA.getByte(aIndex) != bufferB.getByte(bIndex)) {\n                return false;\n            }\n            aIndex++;\n            bIndex++;\n        }\n\n        return true;\n    }\n\n    // prefix\n    public static boolean prefixEquals(ChannelBuffer bufferA, ChannelBuffer bufferB, int count) {\n        final int aLen = bufferA.readableBytes();\n        final int bLen = bufferB.readableBytes();\n        if (aLen < count || bLen < count) {\n            return false;\n        }\n\n        int aIndex = bufferA.readerIndex();\n        int bIndex = bufferB.readerIndex();\n\n        for (int i = count; i > 0; i--) {\n            if (bufferA.getByte(aIndex) != bufferB.getByte(bIndex)) {\n                return false;\n            }\n            aIndex++;\n            bIndex++;\n        }\n\n        return true;\n    }\n\n    public static int hasCode(ChannelBuffer buffer) {\n        final int aLen = buffer.readableBytes();\n        final int byteCount = aLen & 7;\n\n        int hashCode = 1;\n        int arrayIndex = buffer.readerIndex();\n\n        for (int i = byteCount; i > 0; i--) {\n            hashCode = 31 * hashCode + buffer.getByte(arrayIndex++);\n        }\n\n        if (hashCode == 0) {\n            hashCode = 1;\n        }\n\n        return hashCode;\n    }\n\n    public static int compare(ChannelBuffer bufferA, ChannelBuffer bufferB) {\n        final int aLen = bufferA.readableBytes();\n        final int bLen = bufferB.readableBytes();\n        final int minLength = Math.min(aLen, bLen);\n\n        int aIndex = bufferA.readerIndex();\n        int bIndex = bufferB.readerIndex();\n\n        for (int i = minLength; i > 0; i--) {\n            byte va = bufferA.getByte(aIndex);\n            byte vb = bufferB.getByte(bIndex);\n            if (va > vb) {\n                return 1;\n            } else if (va < vb) {\n                return -1;\n            }\n            aIndex++;\n            bIndex++;\n        }\n\n        return aLen - bLen;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/DirectChannelBufferFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.nio.ByteBuffer;\n\npublic class DirectChannelBufferFactory implements ChannelBufferFactory {\n\n    private static final DirectChannelBufferFactory INSTANCE = new DirectChannelBufferFactory();\n\n    public DirectChannelBufferFactory() {\n        super();\n    }\n\n    public static ChannelBufferFactory getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public ChannelBuffer getBuffer(int capacity) {\n        if (capacity < 0) {\n            throw new IllegalArgumentException(\"capacity: \" + capacity);\n        }\n        if (capacity == 0) {\n            return ChannelBuffers.EMPTY_BUFFER;\n        }\n        return ChannelBuffers.directBuffer(capacity);\n    }\n\n    @Override\n    public ChannelBuffer getBuffer(byte[] array, int offset, int length) {\n        if (array == null) {\n            throw new NullPointerException(\"array\");\n        }\n        if (offset < 0) {\n            throw new IndexOutOfBoundsException(\"offset: \" + offset);\n        }\n        if (length == 0) {\n            return ChannelBuffers.EMPTY_BUFFER;\n        }\n        if (offset + length > array.length) {\n            throw new IndexOutOfBoundsException(\"length: \" + length);\n        }\n\n        ChannelBuffer buf = getBuffer(length);\n        buf.writeBytes(array, offset, length);\n        return buf;\n    }\n\n    @Override\n    public ChannelBuffer getBuffer(ByteBuffer nioBuffer) {\n        if (!nioBuffer.isReadOnly() && nioBuffer.isDirect()) {\n            return ChannelBuffers.wrappedBuffer(nioBuffer);\n        }\n\n        ChannelBuffer buf = getBuffer(nioBuffer.remaining());\n        int pos = nioBuffer.position();\n        buf.writeBytes(nioBuffer);\n        nioBuffer.position(pos);\n        return buf;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/DynamicChannelBuffer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\n\npublic class DynamicChannelBuffer extends AbstractChannelBuffer {\n\n    private final ChannelBufferFactory factory;\n\n    private ChannelBuffer buffer;\n\n    public DynamicChannelBuffer(int estimatedLength) {\n        this(estimatedLength, HeapChannelBufferFactory.getInstance());\n    }\n\n    public DynamicChannelBuffer(int estimatedLength, ChannelBufferFactory factory) {\n        if (estimatedLength < 0) {\n            throw new IllegalArgumentException(\"estimatedLength: \" + estimatedLength);\n        }\n        if (factory == null) {\n            throw new NullPointerException(\"factory\");\n        }\n        this.factory = factory;\n        this.buffer = factory.getBuffer(estimatedLength);\n    }\n\n    @Override\n    public void ensureWritableBytes(int minWritableBytes) {\n        if (minWritableBytes <= writableBytes()) {\n            return;\n        }\n\n        int newCapacity = capacity() == 0 ? 1 : capacity();\n        int minNewCapacity = writerIndex() + minWritableBytes;\n        while (newCapacity < minNewCapacity) {\n            newCapacity <<= 1;\n        }\n\n        ChannelBuffer newBuffer = factory().getBuffer(newCapacity);\n        newBuffer.writeBytes(buffer, 0, writerIndex());\n        buffer = newBuffer;\n    }\n\n    @Override\n    public int capacity() {\n        return buffer.capacity();\n    }\n\n    @Override\n    public ChannelBuffer copy(int index, int length) {\n        DynamicChannelBuffer copiedBuffer = new DynamicChannelBuffer(Math.max(length, 64), factory());\n        copiedBuffer.buffer = buffer.copy(index, length);\n        copiedBuffer.setIndex(0, length);\n        return copiedBuffer;\n    }\n\n    @Override\n    public ChannelBufferFactory factory() {\n        return factory;\n    }\n\n    @Override\n    public byte getByte(int index) {\n        return buffer.getByte(index);\n    }\n\n    @Override\n    public void getBytes(int index, byte[] dst, int dstIndex, int length) {\n        buffer.getBytes(index, dst, dstIndex, length);\n    }\n\n    @Override\n    public void getBytes(int index, ByteBuffer dst) {\n        buffer.getBytes(index, dst);\n    }\n\n    @Override\n    public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {\n        buffer.getBytes(index, dst, dstIndex, length);\n    }\n\n    @Override\n    public void getBytes(int index, OutputStream dst, int length) throws IOException {\n        buffer.getBytes(index, dst, length);\n    }\n\n    @Override\n    public boolean isDirect() {\n        return buffer.isDirect();\n    }\n\n    @Override\n    public void setByte(int index, int value) {\n        buffer.setByte(index, value);\n    }\n\n    @Override\n    public void setBytes(int index, byte[] src, int srcIndex, int length) {\n        buffer.setBytes(index, src, srcIndex, length);\n    }\n\n    @Override\n    public void setBytes(int index, ByteBuffer src) {\n        buffer.setBytes(index, src);\n    }\n\n    @Override\n    public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {\n        buffer.setBytes(index, src, srcIndex, length);\n    }\n\n    @Override\n    public int setBytes(int index, InputStream src, int length) throws IOException {\n        return buffer.setBytes(index, src, length);\n    }\n\n    @Override\n    public ByteBuffer toByteBuffer(int index, int length) {\n        return buffer.toByteBuffer(index, length);\n    }\n\n    @Override\n    public void writeByte(int value) {\n        ensureWritableBytes(1);\n        super.writeByte(value);\n    }\n\n    @Override\n    public void writeBytes(byte[] src, int srcIndex, int length) {\n        ensureWritableBytes(length);\n        super.writeBytes(src, srcIndex, length);\n    }\n\n    @Override\n    public void writeBytes(ChannelBuffer src, int srcIndex, int length) {\n        ensureWritableBytes(length);\n        super.writeBytes(src, srcIndex, length);\n    }\n\n    @Override\n    public void writeBytes(ByteBuffer src) {\n        ensureWritableBytes(src.remaining());\n        super.writeBytes(src);\n    }\n\n    @Override\n    public int writeBytes(InputStream in, int length) throws IOException {\n        ensureWritableBytes(length);\n        return super.writeBytes(in, length);\n    }\n\n    @Override\n    public byte[] array() {\n        return buffer.array();\n    }\n\n    @Override\n    public boolean hasArray() {\n        return buffer.hasArray();\n    }\n\n    @Override\n    public int arrayOffset() {\n        return buffer.arrayOffset();\n    }\n\n    @Override\n    public void release() {\n        buffer.release();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/HeapChannelBuffer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.ClosedChannelException;\nimport java.nio.channels.GatheringByteChannel;\nimport java.nio.channels.ScatteringByteChannel;\n\npublic class HeapChannelBuffer extends AbstractChannelBuffer {\n\n    /**\n     * The underlying heap byte array that this buffer is wrapping.\n     */\n    protected final byte[] array;\n\n    /**\n     * Creates a new heap buffer with a newly allocated byte array.\n     *\n     * @param length the length of the new byte array\n     */\n    public HeapChannelBuffer(int length) {\n        this(new byte[length], 0, 0);\n    }\n\n    /**\n     * Creates a new heap buffer with an existing byte array.\n     *\n     * @param array the byte array to wrap\n     */\n    public HeapChannelBuffer(byte[] array) {\n        this(array, 0, array.length);\n    }\n\n    /**\n     * Creates a new heap buffer with an existing byte array.\n     *\n     * @param array       the byte array to wrap\n     * @param readerIndex the initial reader index of this buffer\n     * @param writerIndex the initial writer index of this buffer\n     */\n    protected HeapChannelBuffer(byte[] array, int readerIndex, int writerIndex) {\n        if (array == null) {\n            throw new NullPointerException(\"array\");\n        }\n        this.array = array;\n        setIndex(readerIndex, writerIndex);\n    }\n\n    @Override\n    public boolean isDirect() {\n        return false;\n    }\n\n    @Override\n    public int capacity() {\n        return array.length;\n    }\n\n    @Override\n    public boolean hasArray() {\n        return true;\n    }\n\n    @Override\n    public byte[] array() {\n        return array;\n    }\n\n    @Override\n    public int arrayOffset() {\n        return 0;\n    }\n\n    @Override\n    public byte getByte(int index) {\n        return array[index];\n    }\n\n    @Override\n    public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {\n        if (dst instanceof HeapChannelBuffer) {\n            getBytes(index, ((HeapChannelBuffer) dst).array, dstIndex, length);\n        } else {\n            dst.setBytes(dstIndex, array, index, length);\n        }\n    }\n\n    @Override\n    public void getBytes(int index, byte[] dst, int dstIndex, int length) {\n        System.arraycopy(array, index, dst, dstIndex, length);\n    }\n\n    @Override\n    public void getBytes(int index, ByteBuffer dst) {\n        dst.put(array, index, Math.min(capacity() - index, dst.remaining()));\n    }\n\n    @Override\n    public void getBytes(int index, OutputStream out, int length) throws IOException {\n        out.write(array, index, length);\n    }\n\n    public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {\n        return out.write(ByteBuffer.wrap(array, index, length));\n    }\n\n    @Override\n    public void setByte(int index, int value) {\n        array[index] = (byte) value;\n    }\n\n    @Override\n    public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {\n        if (src instanceof HeapChannelBuffer) {\n            setBytes(index, ((HeapChannelBuffer) src).array, srcIndex, length);\n        } else {\n            src.getBytes(srcIndex, array, index, length);\n        }\n    }\n\n    @Override\n    public void setBytes(int index, byte[] src, int srcIndex, int length) {\n        System.arraycopy(src, srcIndex, array, index, length);\n    }\n\n    @Override\n    public void setBytes(int index, ByteBuffer src) {\n        src.get(array, index, src.remaining());\n    }\n\n    @Override\n    public int setBytes(int index, InputStream in, int length) throws IOException {\n        int readBytes = 0;\n        do {\n            int localReadBytes = in.read(array, index, length);\n            if (localReadBytes < 0) {\n                if (readBytes == 0) {\n                    return -1;\n                } else {\n                    break;\n                }\n            }\n            readBytes += localReadBytes;\n            index += localReadBytes;\n            length -= localReadBytes;\n        } while (length > 0);\n\n        return readBytes;\n    }\n\n    public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {\n        ByteBuffer buf = ByteBuffer.wrap(array, index, length);\n        int readBytes = 0;\n\n        do {\n            int localReadBytes;\n            try {\n                localReadBytes = in.read(buf);\n            } catch (ClosedChannelException e) {\n                localReadBytes = -1;\n            }\n            if (localReadBytes < 0) {\n                if (readBytes == 0) {\n                    return -1;\n                } else {\n                    break;\n                }\n            } else if (localReadBytes == 0) {\n                break;\n            }\n            readBytes += localReadBytes;\n        } while (readBytes < length);\n\n        return readBytes;\n    }\n\n    @Override\n    public ChannelBuffer copy(int index, int length) {\n        if (index < 0 || length < 0 || index + length > array.length) {\n            throw new IndexOutOfBoundsException();\n        }\n\n        byte[] copiedArray = new byte[length];\n        System.arraycopy(array, index, copiedArray, 0, length);\n        return new HeapChannelBuffer(copiedArray);\n    }\n\n    @Override\n    public ChannelBufferFactory factory() {\n        return HeapChannelBufferFactory.getInstance();\n    }\n\n    @Override\n    public ByteBuffer toByteBuffer(int index, int length) {\n        return ByteBuffer.wrap(array, index, length);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/HeapChannelBufferFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.nio.ByteBuffer;\n\npublic class HeapChannelBufferFactory implements ChannelBufferFactory {\n\n    private static final HeapChannelBufferFactory INSTANCE = new HeapChannelBufferFactory();\n\n    public HeapChannelBufferFactory() {\n        super();\n    }\n\n    public static ChannelBufferFactory getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public ChannelBuffer getBuffer(int capacity) {\n        return ChannelBuffers.buffer(capacity);\n    }\n\n    @Override\n    public ChannelBuffer getBuffer(byte[] array, int offset, int length) {\n        return ChannelBuffers.wrappedBuffer(array, offset, length);\n    }\n\n    @Override\n    public ChannelBuffer getBuffer(ByteBuffer nioBuffer) {\n        if (nioBuffer.hasArray()) {\n            return ChannelBuffers.wrappedBuffer(nioBuffer);\n        }\n\n        ChannelBuffer buf = getBuffer(nioBuffer.remaining());\n        int pos = nioBuffer.position();\n        buf.writeBytes(nioBuffer);\n        nioBuffer.position(pos);\n        return buf;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/event/ReadOnlyEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.event;\n\nimport org.apache.dubbo.remoting.ChannelEvent;\n\n/**\n * Read-only event for graceful shutdown.\n * <p>\n * This event indicates that the server is entering read-only mode and will not accept\n * new requests. It is typically fired during graceful shutdown to notify connected clients\n * that they should switch to other available providers.\n * </p>\n *\n * <h3>Protocol-specific Behavior</h3>\n * <p>When this event is fired to a channel:</p>\n * <ul>\n *   <li><b>Dubbo protocol:</b> Sends a READONLY_EVENT request to the client.\n *       The client will mark this provider as unavailable and prefer other providers for new requests.</li>\n *   <li><b>Triple protocol (HTTP/2):</b> Sends an HTTP/2 GOAWAY frame with NO_ERROR code.\n *       The GOAWAY frame indicates that the server will not accept new streams (requests)\n *       but existing streams can continue until completion.</li>\n * </ul>\n *\n * <h3>Usage</h3>\n * <p>This is a singleton class. Use {@link #INSTANCE} to get the instance.</p>\n *\n * @see org.apache.dubbo.remoting.RemotingServer#fireChannelEvent(ChannelEvent)\n * @see WriteableEvent\n * @see org.apache.dubbo.rpc.GracefulShutdown#readonly()\n * @since 3.3\n */\npublic class ReadOnlyEvent implements ChannelEvent {\n\n    /**\n     * The singleton instance of ReadOnlyEvent.\n     */\n    public static final ReadOnlyEvent INSTANCE = new ReadOnlyEvent();\n\n    /**\n     * Private constructor to enforce singleton pattern.\n     */\n    private ReadOnlyEvent() {}\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/event/WriteableEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.event;\n\nimport org.apache.dubbo.remoting.ChannelEvent;\n\n/**\n * Writeable event to resume normal operation after graceful shutdown is cancelled.\n * <p>\n * This event indicates that the server is resuming normal operation and can accept\n * new requests again. It is typically fired when a graceful shutdown is cancelled\n * before completion.\n * </p>\n *\n * <h3>Protocol-specific Behavior</h3>\n * <p>When this event is fired to a channel:</p>\n * <ul>\n *   <li><b>Dubbo protocol:</b> Sends a WRITEABLE_EVENT request to the client.\n *       The client will mark this provider as available again and can use it for new requests.</li>\n *   <li><b>Triple protocol (HTTP/2):</b> <em>Not supported.</em> HTTP/2 GOAWAY frame is a one-way\n *       notification that cannot be reversed. Once a GOAWAY frame is sent, the connection\n *       is in graceful shutdown mode and cannot be resumed.</li>\n * </ul>\n *\n * <h3>Usage</h3>\n * <p>This is a singleton class. Use {@link #INSTANCE} to get the instance.</p>\n *\n * @see org.apache.dubbo.remoting.RemotingServer#fireChannelEvent(ChannelEvent)\n * @see ReadOnlyEvent\n * @see org.apache.dubbo.rpc.GracefulShutdown#writeable()\n * @since 3.3\n */\npublic class WriteableEvent implements ChannelEvent {\n\n    /**\n     * The singleton instance of WriteableEvent.\n     */\n    public static final WriteableEvent INSTANCE = new WriteableEvent();\n\n    /**\n     * Private constructor to enforce singleton pattern.\n     */\n    private WriteableEvent() {}\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/ExchangeChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutorService;\n\n/**\n * ExchangeChannel. (API/SPI, Prototype, ThreadSafe)\n */\npublic interface ExchangeChannel extends Channel {\n\n    /**\n     * send request.\n     *\n     * @param request\n     * @return response future\n     * @throws RemotingException\n     */\n    @Deprecated\n    CompletableFuture<Object> request(Object request) throws RemotingException;\n\n    /**\n     * send request.\n     *\n     * @param request\n     * @param timeout\n     * @return response future\n     * @throws RemotingException\n     */\n    @Deprecated\n    CompletableFuture<Object> request(Object request, int timeout) throws RemotingException;\n\n    /**\n     * send request.\n     *\n     * @param request\n     * @return response future\n     * @throws RemotingException\n     */\n    CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException;\n\n    /**\n     * send request.\n     *\n     * @param request\n     * @param timeout\n     * @return response future\n     * @throws RemotingException\n     */\n    CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException;\n\n    /**\n     * get message handler.\n     *\n     * @return message handler\n     */\n    ExchangeHandler getExchangeHandler();\n\n    /**\n     * graceful close.\n     *\n     * @param timeout\n     */\n    @Override\n    void close(int timeout);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/ExchangeClient.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.apache.dubbo.remoting.Client;\n\n/**\n * ExchangeClient. (API/SPI, Prototype, ThreadSafe)\n *\n *\n */\npublic interface ExchangeClient extends Client, ExchangeChannel {}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/ExchangeHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\n\nimport java.util.concurrent.CompletableFuture;\n\n/**\n * ExchangeHandler. (API, Prototype, ThreadSafe)\n */\npublic interface ExchangeHandler extends ChannelHandler, TelnetHandler {\n\n    /**\n     * reply.\n     *\n     * @param channel\n     * @param request\n     * @return response\n     * @throws RemotingException\n     */\n    CompletableFuture<Object> reply(ExchangeChannel channel, Object request) throws RemotingException;\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/ExchangeServer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.apache.dubbo.remoting.RemotingServer;\n\nimport java.net.InetSocketAddress;\nimport java.util.Collection;\n\n/**\n * ExchangeServer. (API/SPI, Prototype, ThreadSafe)\n */\npublic interface ExchangeServer extends RemotingServer {\n\n    /**\n     * get channels.\n     *\n     * @return channels\n     */\n    Collection<ExchangeChannel> getExchangeChannels();\n\n    /**\n     * get channel.\n     *\n     * @param remoteAddress\n     * @return channel\n     */\n    ExchangeChannel getExchangeChannel(InetSocketAddress remoteAddress);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/Exchanger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.Adaptive;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.support.header.HeaderExchanger;\n\n/**\n * Exchanger. (SPI, Singleton, ThreadSafe)\n * <p>\n * <a href=\"http://en.wikipedia.org/wiki/Message_Exchange_Pattern\">Message Exchange Pattern</a>\n * <a href=\"http://en.wikipedia.org/wiki/Request-response\">Request-Response</a>\n */\n@SPI(value = HeaderExchanger.NAME, scope = ExtensionScope.FRAMEWORK)\npublic interface Exchanger {\n\n    /**\n     * bind.\n     *\n     * @param url\n     * @param handler\n     * @return message server\n     */\n    @Adaptive({Constants.EXCHANGER_KEY})\n    ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException;\n\n    /**\n     * connect.\n     *\n     * @param url\n     * @param handler\n     * @return message channel\n     */\n    @Adaptive({Constants.EXCHANGER_KEY})\n    ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException;\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/Exchangers.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.support.ExchangeHandlerDispatcher;\nimport org.apache.dubbo.remoting.exchange.support.Replier;\nimport org.apache.dubbo.remoting.transport.ChannelHandlerAdapter;\n\n/**\n * Exchanger facade. (API, Static, ThreadSafe)\n */\npublic class Exchangers {\n    private Exchangers() {}\n\n    public static ExchangeServer bind(String url, Replier<?> replier) throws RemotingException {\n        return bind(URL.valueOf(url), replier);\n    }\n\n    public static ExchangeServer bind(URL url, Replier<?> replier) throws RemotingException {\n        return bind(url, new ChannelHandlerAdapter(), replier);\n    }\n\n    public static ExchangeServer bind(String url, ChannelHandler handler, Replier<?> replier) throws RemotingException {\n        return bind(URL.valueOf(url), handler, replier);\n    }\n\n    public static ExchangeServer bind(URL url, ChannelHandler handler, Replier<?> replier) throws RemotingException {\n        return bind(url, new ExchangeHandlerDispatcher(url.getOrDefaultFrameworkModel(), replier, handler));\n    }\n\n    public static ExchangeServer bind(String url, ExchangeHandler handler) throws RemotingException {\n        return bind(URL.valueOf(url), handler);\n    }\n\n    public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {\n        if (url == null) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n        if (handler == null) {\n            throw new IllegalArgumentException(\"handler == null\");\n        }\n        url = url.addParameterIfAbsent(Constants.CODEC_KEY, \"exchange\");\n        return getExchanger(url).bind(url, handler);\n    }\n\n    public static ExchangeClient connect(String url) throws RemotingException {\n        return connect(URL.valueOf(url));\n    }\n\n    public static ExchangeClient connect(URL url) throws RemotingException {\n        return connect(url, new ChannelHandlerAdapter(), null);\n    }\n\n    public static ExchangeClient connect(String url, Replier<?> replier) throws RemotingException {\n        return connect(URL.valueOf(url), new ChannelHandlerAdapter(), replier);\n    }\n\n    public static ExchangeClient connect(URL url, Replier<?> replier) throws RemotingException {\n        return connect(url, new ChannelHandlerAdapter(), replier);\n    }\n\n    public static ExchangeClient connect(String url, ChannelHandler handler, Replier<?> replier)\n            throws RemotingException {\n        return connect(URL.valueOf(url), handler, replier);\n    }\n\n    public static ExchangeClient connect(URL url, ChannelHandler handler, Replier<?> replier) throws RemotingException {\n        return connect(url, new ExchangeHandlerDispatcher(url.getOrDefaultFrameworkModel(), replier, handler));\n    }\n\n    public static ExchangeClient connect(String url, ExchangeHandler handler) throws RemotingException {\n        return connect(URL.valueOf(url), handler);\n    }\n\n    public static ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {\n        if (url == null) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n        if (handler == null) {\n            throw new IllegalArgumentException(\"handler == null\");\n        }\n        return getExchanger(url).connect(url, handler);\n    }\n\n    public static Exchanger getExchanger(URL url) {\n        String type = url.getParameter(Constants.EXCHANGER_KEY, Constants.DEFAULT_EXCHANGER);\n        return url.getOrDefaultFrameworkModel()\n                .getExtensionLoader(Exchanger.class)\n                .getExtension(type);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/HeartBeatRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\npublic class HeartBeatRequest extends Request {\n    private byte proto;\n\n    public HeartBeatRequest(long id) {\n        super(id);\n    }\n\n    public byte getProto() {\n        return proto;\n    }\n\n    public void setProto(byte proto) {\n        this.proto = proto;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/HeartBeatResponse.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\npublic class HeartBeatResponse extends Response {\n    private byte proto;\n\n    public HeartBeatResponse(long id, String version) {\n        super(id, version);\n    }\n\n    public byte getProto() {\n        return proto;\n    }\n\n    public void setProto(byte proto) {\n        this.proto = proto;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/PortUnificationExchanger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.RemotingServer;\nimport org.apache.dubbo.remoting.api.connection.AbstractConnectionClient;\nimport org.apache.dubbo.remoting.api.pu.AbstractPortUnificationServer;\nimport org.apache.dubbo.remoting.api.pu.PortUnificationTransporter;\n\nimport java.util.ArrayList;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_ERROR_CLOSE_SERVER;\n\npublic class PortUnificationExchanger {\n\n    private static final ErrorTypeAwareLogger log =\n            LoggerFactory.getErrorTypeAwareLogger(PortUnificationExchanger.class);\n    private static final ConcurrentMap<String, RemotingServer> servers = new ConcurrentHashMap<>();\n\n    public static RemotingServer bind(URL url, ChannelHandler handler) {\n        ConcurrentHashMapUtils.computeIfAbsent(servers, url.getAddress(), addr -> {\n            final AbstractPortUnificationServer server;\n            try {\n                server = getTransporter(url).bind(url, handler);\n            } catch (RemotingException e) {\n                throw new RuntimeException(e);\n            }\n            // server.bind();\n            return server;\n        });\n\n        servers.computeIfPresent(url.getAddress(), (addr, server) -> {\n            ((AbstractPortUnificationServer) server).addSupportedProtocol(url, handler);\n            return server;\n        });\n        return servers.get(url.getAddress());\n    }\n\n    public static AbstractConnectionClient connect(URL url, ChannelHandler handler) {\n        final AbstractConnectionClient connectionClient;\n        try {\n            connectionClient = getTransporter(url).connect(url, handler);\n        } catch (RemotingException e) {\n            throw new RuntimeException(e);\n        }\n        return connectionClient;\n    }\n\n    public static void close() {\n        final ArrayList<RemotingServer> toClose = new ArrayList<>(servers.values());\n        servers.clear();\n        for (RemotingServer server : toClose) {\n            try {\n                server.close();\n            } catch (Throwable throwable) {\n                log.error(PROTOCOL_ERROR_CLOSE_SERVER, \"\", \"\", \"Close all port unification server failed\", throwable);\n            }\n        }\n    }\n\n    // for test\n    public static ConcurrentMap<String, RemotingServer> getServers() {\n        return servers;\n    }\n\n    public static PortUnificationTransporter getTransporter(URL url) {\n        return url.getOrDefaultFrameworkModel()\n                .getExtensionLoader(PortUnificationTransporter.class)\n                .getAdaptiveExtension();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/Request.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.security.SecureRandom;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DubboProperty.DUBBO_USE_SECURE_RANDOM_ID;\nimport static org.apache.dubbo.common.constants.CommonConstants.HEARTBEAT_EVENT;\n\n/**\n * Request.\n */\npublic class Request {\n\n    private static final AtomicLong INVOKE_ID;\n\n    private final long mId;\n\n    private String mVersion;\n\n    private boolean mTwoWay = true;\n\n    private boolean mEvent = false;\n\n    private boolean mBroken = false;\n\n    private int mPayload;\n\n    private Object mData;\n\n    public Request() {\n        mId = newId();\n    }\n\n    public Request(long id) {\n        mId = id;\n    }\n\n    static {\n        long startID = ThreadLocalRandom.current().nextLong();\n        if (Boolean.parseBoolean(SystemPropertyConfigUtils.getSystemProperty(DUBBO_USE_SECURE_RANDOM_ID, \"false\"))) {\n            try {\n                SecureRandom rand = new SecureRandom(SecureRandom.getSeed(20));\n                startID = rand.nextLong();\n            } catch (Throwable ignore) {\n            }\n        }\n        INVOKE_ID = new AtomicLong(startID);\n    }\n\n    private static long newId() {\n        // getAndIncrement() When it grows to MAX_VALUE, it will grow to MIN_VALUE, and the negative can be used as ID\n        return INVOKE_ID.getAndIncrement();\n    }\n\n    private static String safeToString(Object data) {\n        if (data == null) {\n            return null;\n        }\n\n        try {\n            return data.toString();\n        } catch (Exception e) {\n            return \"<Fail toString of \" + data.getClass() + \", cause: \" + StringUtils.toString(e) + \">\";\n        }\n    }\n\n    public long getId() {\n        return mId;\n    }\n\n    public String getVersion() {\n        return mVersion;\n    }\n\n    public void setVersion(String version) {\n        mVersion = version;\n    }\n\n    public boolean isTwoWay() {\n        return mTwoWay;\n    }\n\n    public void setTwoWay(boolean twoWay) {\n        mTwoWay = twoWay;\n    }\n\n    public boolean isEvent() {\n        return mEvent;\n    }\n\n    public void setEvent(String event) {\n        this.mEvent = true;\n        this.mData = event;\n    }\n\n    public void setEvent(boolean mEvent) {\n        this.mEvent = mEvent;\n    }\n\n    public boolean isBroken() {\n        return mBroken;\n    }\n\n    public void setBroken(boolean mBroken) {\n        this.mBroken = mBroken;\n    }\n\n    public int getPayload() {\n        return mPayload;\n    }\n\n    public void setPayload(int mPayload) {\n        this.mPayload = mPayload;\n    }\n\n    public Object getData() {\n        return mData;\n    }\n\n    public void setData(Object msg) {\n        mData = msg;\n    }\n\n    public boolean isHeartbeat() {\n        return mEvent && HEARTBEAT_EVENT == mData;\n    }\n\n    public void setHeartbeat(boolean isHeartbeat) {\n        if (isHeartbeat) {\n            setEvent(HEARTBEAT_EVENT);\n        }\n    }\n\n    public Request copy() {\n        Request copy = new Request(mId);\n        copy.mVersion = this.mVersion;\n        copy.mTwoWay = this.mTwoWay;\n        copy.mEvent = this.mEvent;\n        copy.mBroken = this.mBroken;\n        copy.mPayload = this.mPayload;\n        copy.mData = this.mData;\n        return copy;\n    }\n\n    public Request copyWithoutData() {\n        Request copy = new Request(mId);\n        copy.mVersion = this.mVersion;\n        copy.mTwoWay = this.mTwoWay;\n        copy.mEvent = this.mEvent;\n        copy.mBroken = this.mBroken;\n        copy.mPayload = this.mPayload;\n        return copy;\n    }\n\n    @Override\n    public String toString() {\n        return \"Request [id=\" + mId + \", version=\" + mVersion + \", twoWay=\" + mTwoWay + \", event=\" + mEvent\n                + \", broken=\" + mBroken + \", mPayload=\" + mPayload + \", data=\"\n                + (mData == this ? \"this\" : safeToString(mData)) + \"]\";\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/Response.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.HEARTBEAT_EVENT;\n\npublic class Response {\n\n    /**\n     * ok.\n     */\n    public static final byte OK = 20;\n\n    /**\n     * serialization error\n     */\n    public static final byte SERIALIZATION_ERROR = 25;\n\n    /**\n     * client side timeout.\n     */\n    public static final byte CLIENT_TIMEOUT = 30;\n\n    /**\n     * server side timeout.\n     */\n    public static final byte SERVER_TIMEOUT = 31;\n\n    /**\n     * channel inactive, directly return the unfinished requests.\n     */\n    public static final byte CHANNEL_INACTIVE = 35;\n\n    /**\n     * request format error.\n     */\n    public static final byte BAD_REQUEST = 40;\n\n    /**\n     * response format error.\n     */\n    public static final byte BAD_RESPONSE = 50;\n\n    /**\n     * service not found.\n     */\n    public static final byte SERVICE_NOT_FOUND = 60;\n\n    /**\n     * service error.\n     */\n    public static final byte SERVICE_ERROR = 70;\n\n    /**\n     * internal server error.\n     */\n    public static final byte SERVER_ERROR = 80;\n\n    /**\n     * internal server error.\n     */\n    public static final byte CLIENT_ERROR = 90;\n\n    /**\n     * server side threadpool exhausted and quick return.\n     */\n    public static final byte SERVER_THREADPOOL_EXHAUSTED_ERROR = 100;\n\n    private long mId = 0;\n\n    private String mVersion;\n\n    private byte mStatus = OK;\n\n    private boolean mEvent = false;\n\n    private String mErrorMsg;\n\n    private Object mResult;\n\n    public Response() {}\n\n    public Response(long id) {\n        mId = id;\n    }\n\n    public Response(long id, String version) {\n        mId = id;\n        mVersion = version;\n    }\n\n    public long getId() {\n        return mId;\n    }\n\n    public void setId(long id) {\n        mId = id;\n    }\n\n    public String getVersion() {\n        return mVersion;\n    }\n\n    public void setVersion(String version) {\n        mVersion = version;\n    }\n\n    public byte getStatus() {\n        return mStatus;\n    }\n\n    public void setStatus(byte status) {\n        mStatus = status;\n    }\n\n    public boolean isEvent() {\n        return mEvent;\n    }\n\n    public void setEvent(String event) {\n        mEvent = true;\n        mResult = event;\n    }\n\n    public void setEvent(boolean mEvent) {\n        this.mEvent = mEvent;\n    }\n\n    public boolean isHeartbeat() {\n        return mEvent && HEARTBEAT_EVENT == mResult;\n    }\n\n    @Deprecated\n    public void setHeartbeat(boolean isHeartbeat) {\n        if (isHeartbeat) {\n            setEvent(HEARTBEAT_EVENT);\n        }\n    }\n\n    public Object getResult() {\n        return mResult;\n    }\n\n    public void setResult(Object msg) {\n        mResult = msg;\n    }\n\n    public String getErrorMessage() {\n        return mErrorMsg;\n    }\n\n    public void setErrorMessage(String msg) {\n        mErrorMsg = msg;\n    }\n\n    @Override\n    public String toString() {\n        return \"Response [id=\" + mId + \", version=\" + mVersion + \", status=\" + mStatus + \", event=\" + mEvent\n                + \", error=\" + mErrorMsg + \", result=\" + (mResult == this ? \"this\" : mResult) + \"]\";\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/codec/ExchangeCodec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.codec;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.io.Bytes;\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.Cleanable;\nimport org.apache.dubbo.common.serialize.ObjectInput;\nimport org.apache.dubbo.common.serialize.ObjectOutput;\nimport org.apache.dubbo.common.serialize.Serialization;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffer;\nimport org.apache.dubbo.remoting.buffer.ChannelBufferInputStream;\nimport org.apache.dubbo.remoting.buffer.ChannelBufferOutputStream;\nimport org.apache.dubbo.remoting.exchange.HeartBeatRequest;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\nimport org.apache.dubbo.remoting.exchange.support.DefaultFuture;\nimport org.apache.dubbo.remoting.telnet.codec.TelnetCodec;\nimport org.apache.dubbo.remoting.transport.CodecSupport;\nimport org.apache.dubbo.remoting.transport.ExceedPayloadLimitException;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_TIMEOUT_SERVER;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_EXCEED_PAYLOAD_LIMIT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RESPONSE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_SKIP_UNUSED_STREAM;\n\n/**\n * ExchangeCodec.\n */\npublic class ExchangeCodec extends TelnetCodec {\n\n    // header length.\n    protected static final int HEADER_LENGTH = 16;\n    // magic header.\n    protected static final short MAGIC = (short) 0xdabb;\n    protected static final byte MAGIC_HIGH = Bytes.short2bytes(MAGIC)[0];\n    protected static final byte MAGIC_LOW = Bytes.short2bytes(MAGIC)[1];\n    // message flag.\n    protected static final byte FLAG_REQUEST = (byte) 0x80;\n    protected static final byte FLAG_TWOWAY = (byte) 0x40;\n    protected static final byte FLAG_EVENT = (byte) 0x20;\n    protected static final int SERIALIZATION_MASK = 0x1f;\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ExchangeCodec.class);\n\n    public Short getMagicCode() {\n        return MAGIC;\n    }\n\n    @Override\n    public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException {\n        if (msg instanceof Request) {\n            encodeRequest(channel, buffer, (Request) msg);\n        } else if (msg instanceof Response) {\n            encodeResponse(channel, buffer, (Response) msg);\n        } else {\n            super.encode(channel, buffer, msg);\n        }\n    }\n\n    @Override\n    public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {\n        int readable = buffer.readableBytes();\n        byte[] header = new byte[Math.min(readable, HEADER_LENGTH)];\n        buffer.readBytes(header);\n        return decode(channel, buffer, readable, header);\n    }\n\n    @Override\n    protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header) throws IOException {\n        // check magic number.\n        if (readable > 0 && header[0] != MAGIC_HIGH || readable > 1 && header[1] != MAGIC_LOW) {\n            int length = header.length;\n            if (header.length < readable) {\n                header = Bytes.copyOf(header, readable);\n                buffer.readBytes(header, length, readable - length);\n            }\n            for (int i = 1; i < header.length - 1; i++) {\n                if (header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) {\n                    buffer.readerIndex(buffer.readerIndex() - header.length + i);\n                    header = Bytes.copyOf(header, i);\n                    break;\n                }\n            }\n            return super.decode(channel, buffer, readable, header);\n        }\n        // check length.\n        if (readable < HEADER_LENGTH) {\n            return DecodeResult.NEED_MORE_INPUT;\n        }\n\n        // get data length.\n        int len = Bytes.bytes2int(header, 12);\n\n        // When receiving response, how to exceed the length, then directly construct a response to the client.\n        // see more detail from https://github.com/apache/dubbo/issues/7021.\n        Object obj = finishRespWhenOverPayload(channel, len, header);\n        if (null != obj) {\n            return obj;\n        }\n\n        int tt = len + HEADER_LENGTH;\n        if (readable < tt) {\n            return DecodeResult.NEED_MORE_INPUT;\n        }\n\n        // limit input stream.\n        ChannelBufferInputStream is = new ChannelBufferInputStream(buffer, len);\n\n        try {\n            return decodeBody(channel, is, header);\n        } finally {\n            if (is.available() > 0) {\n                try {\n                    if (logger.isWarnEnabled()) {\n                        logger.warn(TRANSPORT_SKIP_UNUSED_STREAM, \"\", \"\", \"Skip input stream \" + is.available());\n                    }\n                    StreamUtils.skipUnusedStream(is);\n                } catch (IOException e) {\n                    logger.warn(TRANSPORT_SKIP_UNUSED_STREAM, \"\", \"\", e.getMessage(), e);\n                }\n            }\n        }\n    }\n\n    protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {\n        byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK);\n        // get request id.\n        long id = Bytes.bytes2long(header, 4);\n        if ((flag & FLAG_REQUEST) == 0) {\n            // decode response.\n            Response res = new Response(id);\n            if ((flag & FLAG_EVENT) != 0) {\n                res.setEvent(true);\n            }\n            // get status.\n            byte status = header[3];\n            res.setStatus(status);\n            try {\n                if (status == Response.OK) {\n                    Object data;\n                    if (res.isEvent()) {\n                        byte[] eventPayload = CodecSupport.getPayload(is);\n                        if (CodecSupport.isHeartBeat(eventPayload, proto)) {\n                            // heart beat response data is always null;\n                            data = null;\n                        } else {\n                            data = decodeEventData(\n                                    channel,\n                                    CodecSupport.deserialize(\n                                            channel.getUrl(), new ByteArrayInputStream(eventPayload), proto),\n                                    eventPayload);\n                        }\n                    } else {\n                        data = decodeResponseData(\n                                channel,\n                                CodecSupport.deserialize(channel.getUrl(), is, proto),\n                                getRequestData(channel, res, id));\n                    }\n                    res.setResult(data);\n                } else {\n                    res.setErrorMessage(CodecSupport.deserialize(channel.getUrl(), is, proto)\n                            .readUTF());\n                }\n            } catch (Throwable t) {\n                res.setStatus(Response.CLIENT_ERROR);\n                res.setErrorMessage(StringUtils.toString(t));\n            }\n            return res;\n        } else {\n            // decode request.\n            Request req;\n            try {\n                Object data;\n                if ((flag & FLAG_EVENT) != 0) {\n                    byte[] eventPayload = CodecSupport.getPayload(is);\n                    if (CodecSupport.isHeartBeat(eventPayload, proto)) {\n                        // heart beat response data is always null;\n                        req = new HeartBeatRequest(id);\n                        ((HeartBeatRequest) req).setProto(proto);\n                        data = null;\n                    } else {\n                        req = new Request(id);\n                        data = decodeEventData(\n                                channel,\n                                CodecSupport.deserialize(\n                                        channel.getUrl(), new ByteArrayInputStream(eventPayload), proto),\n                                eventPayload);\n                    }\n                    req.setEvent(true);\n                } else {\n                    req = new Request(id);\n                    data = decodeRequestData(channel, CodecSupport.deserialize(channel.getUrl(), is, proto));\n                }\n                req.setData(data);\n            } catch (Throwable t) {\n                // bad request\n                req = new Request(id);\n                req.setBroken(true);\n                req.setData(t);\n            }\n            req.setVersion(Version.getProtocolVersion());\n            req.setTwoWay((flag & FLAG_TWOWAY) != 0);\n            return req;\n        }\n    }\n\n    protected Object getRequestData(Channel channel, Response response, long id) {\n        DefaultFuture future = DefaultFuture.getFuture(id);\n        if (future != null) {\n            Request req = future.getRequest();\n            if (req != null) {\n                return req.getData();\n            }\n        }\n\n        logger.warn(\n                PROTOCOL_TIMEOUT_SERVER,\n                \"\",\n                \"\",\n                \"The timeout response finally returned at \"\n                        + (new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\").format(new Date()))\n                        + \", response status is \" + response.getStatus() + \", response id is \" + response.getId()\n                        + (channel == null\n                                ? \"\"\n                                : \", channel: \" + channel.getLocalAddress() + \" -> \" + channel.getRemoteAddress())\n                        + \", please check provider side for detailed result.\");\n        throw new IllegalArgumentException(\"Failed to find any request match the response, response id: \" + id);\n    }\n\n    protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req) throws IOException {\n        Serialization serialization = getSerialization(channel, req);\n        // header.\n        byte[] header = new byte[HEADER_LENGTH];\n        // set magic number.\n        Bytes.short2bytes(MAGIC, header);\n\n        // set request and serialization flag.\n        header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId());\n\n        if (req.isTwoWay()) {\n            header[2] |= FLAG_TWOWAY;\n        }\n        if (req.isEvent()) {\n            header[2] |= FLAG_EVENT;\n        }\n\n        // set request id.\n        Bytes.long2bytes(req.getId(), header, 4);\n\n        // encode request data.\n        int savedWriteIndex = buffer.writerIndex();\n        buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);\n        ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);\n\n        if (req.isHeartbeat()) {\n            // heartbeat request data is always null\n            bos.write(CodecSupport.getNullBytesOf(serialization));\n        } else {\n            ObjectOutput out = serialization.serialize(channel.getUrl(), bos);\n            if (req.isEvent()) {\n                encodeEventData(channel, out, req.getData());\n            } else {\n                encodeRequestData(channel, out, req.getData(), req.getVersion());\n            }\n            out.flushBuffer();\n            if (out instanceof Cleanable) {\n                ((Cleanable) out).cleanup();\n            }\n        }\n\n        bos.flush();\n        bos.close();\n        int len = bos.writtenBytes();\n        checkPayload(channel, req.getPayload(), len);\n        Bytes.int2bytes(len, header, 12);\n\n        // write\n        buffer.writerIndex(savedWriteIndex);\n        buffer.writeBytes(header); // write header.\n        buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);\n    }\n\n    protected void encodeResponse(Channel channel, ChannelBuffer buffer, Response res) throws IOException {\n        int savedWriteIndex = buffer.writerIndex();\n        try {\n            Serialization serialization = getSerialization(channel, res);\n            // header.\n            byte[] header = new byte[HEADER_LENGTH];\n            // set magic number.\n            Bytes.short2bytes(MAGIC, header);\n            // set request and serialization flag.\n            header[2] = serialization.getContentTypeId();\n            if (res.isHeartbeat()) {\n                header[2] |= FLAG_EVENT;\n            }\n            // set response status.\n            byte status = res.getStatus();\n            header[3] = status;\n            // set request id.\n            Bytes.long2bytes(res.getId(), header, 4);\n\n            buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);\n            int len;\n            try (ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer)) {\n\n                // encode response data or error message.\n                if (status == Response.OK) {\n                    if (res.isHeartbeat()) {\n                        // heartbeat response data is always null\n                        bos.write(CodecSupport.getNullBytesOf(serialization));\n                    } else {\n                        ObjectOutput out = serialization.serialize(channel.getUrl(), bos);\n                        if (res.isEvent()) {\n                            encodeEventData(channel, out, res.getResult());\n                        } else {\n                            encodeResponseData(channel, out, res.getResult(), res.getVersion());\n                        }\n                        out.flushBuffer();\n                        if (out instanceof Cleanable) {\n                            ((Cleanable) out).cleanup();\n                        }\n                    }\n                } else {\n                    ObjectOutput out = serialization.serialize(channel.getUrl(), bos);\n                    out.writeUTF(res.getErrorMessage());\n                    out.flushBuffer();\n                    if (out instanceof Cleanable) {\n                        ((Cleanable) out).cleanup();\n                    }\n                }\n\n                bos.flush();\n                len = bos.writtenBytes();\n            }\n\n            checkPayload(channel, len);\n            Bytes.int2bytes(len, header, 12);\n            // write\n            buffer.writerIndex(savedWriteIndex);\n            buffer.writeBytes(header); // write header.\n            buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);\n        } catch (Throwable t) {\n            // clear buffer\n            buffer.writerIndex(savedWriteIndex);\n            // send error message to Consumer, otherwise, Consumer will wait till timeout.\n            if (!res.isEvent() && res.getStatus() != Response.BAD_RESPONSE) {\n                Response r = new Response(res.getId(), res.getVersion());\n                r.setStatus(Response.BAD_RESPONSE);\n\n                if (t instanceof ExceedPayloadLimitException) {\n                    logger.warn(TRANSPORT_EXCEED_PAYLOAD_LIMIT, \"\", \"\", t.getMessage(), t);\n                    try {\n                        r.setErrorMessage(t.getMessage());\n                        r.setStatus(Response.SERIALIZATION_ERROR);\n                        channel.send(r);\n                        return;\n                    } catch (RemotingException e) {\n                        logger.warn(\n                                TRANSPORT_FAILED_RESPONSE,\n                                \"\",\n                                \"\",\n                                \"Failed to send bad_response info back: \" + t.getMessage() + \", cause: \"\n                                        + e.getMessage(),\n                                e);\n                    }\n                } else {\n                    // FIXME log error message in Codec and handle in caught() of IoHanndler?\n                    logger.warn(\n                            TRANSPORT_FAILED_RESPONSE,\n                            \"\",\n                            \"\",\n                            \"Fail to encode response: \" + res + \", send bad_response info instead, cause: \"\n                                    + t.getMessage(),\n                            t);\n                    try {\n                        r.setErrorMessage(\"Failed to send response: \" + res + \", cause: \" + StringUtils.toString(t));\n                        channel.send(r);\n                        return;\n                    } catch (RemotingException e) {\n                        logger.warn(\n                                TRANSPORT_FAILED_RESPONSE,\n                                \"\",\n                                \"\",\n                                \"Failed to send bad_response info back: \" + res + \", cause: \" + e.getMessage(),\n                                e);\n                    }\n                }\n            }\n\n            // Rethrow exception\n            if (t instanceof IOException) {\n                throw (IOException) t;\n            } else if (t instanceof RuntimeException) {\n                throw (RuntimeException) t;\n            } else if (t instanceof Error) {\n                throw (Error) t;\n            } else {\n                throw new RuntimeException(t.getMessage(), t);\n            }\n        }\n    }\n\n    @Override\n    protected Object decodeData(ObjectInput in) throws IOException {\n        return decodeRequestData(in);\n    }\n\n    protected Object decodeRequestData(ObjectInput in) throws IOException {\n        try {\n            return in.readObject();\n        } catch (ClassNotFoundException e) {\n            throw new IOException(StringUtils.toString(\"Read object failed.\", e));\n        }\n    }\n\n    protected Object decodeResponseData(ObjectInput in) throws IOException {\n        try {\n            return in.readObject();\n        } catch (ClassNotFoundException e) {\n            throw new IOException(StringUtils.toString(\"Read object failed.\", e));\n        }\n    }\n\n    @Override\n    protected void encodeData(ObjectOutput out, Object data) throws IOException {\n        encodeRequestData(out, data);\n    }\n\n    private void encodeEventData(ObjectOutput out, Object data) throws IOException {\n        out.writeEvent((String) data);\n    }\n\n    @Deprecated\n    protected void encodeHeartbeatData(ObjectOutput out, Object data) throws IOException {\n        encodeEventData(out, data);\n    }\n\n    protected void encodeRequestData(ObjectOutput out, Object data) throws IOException {\n        out.writeObject(data);\n    }\n\n    protected void encodeResponseData(ObjectOutput out, Object data) throws IOException {\n        out.writeObject(data);\n    }\n\n    @Override\n    protected Object decodeData(Channel channel, ObjectInput in) throws IOException {\n        return decodeRequestData(channel, in);\n    }\n\n    protected Object decodeEventData(Channel channel, ObjectInput in, byte[] eventBytes) throws IOException {\n        try {\n            if (eventBytes != null) {\n                int dataLen = eventBytes.length;\n                int threshold = ConfigurationUtils.getSystemConfiguration(\n                                channel.getUrl().getScopeModel())\n                        .getInt(\"deserialization.event.size\", 15);\n                if (dataLen > threshold) {\n                    throw new IllegalArgumentException(\"Event data too long, actual size \" + threshold + \", threshold \"\n                            + threshold + \" rejected for security consideration.\");\n                }\n            }\n            return in.readEvent();\n        } catch (IOException | ClassNotFoundException e) {\n            throw new IOException(StringUtils.toString(\"Decode dubbo protocol event failed.\", e));\n        }\n    }\n\n    protected Object decodeRequestData(Channel channel, ObjectInput in) throws IOException {\n        return decodeRequestData(in);\n    }\n\n    protected Object decodeResponseData(Channel channel, ObjectInput in) throws IOException {\n        return decodeResponseData(in);\n    }\n\n    protected Object decodeResponseData(Channel channel, ObjectInput in, Object requestData) throws IOException {\n        return decodeResponseData(channel, in);\n    }\n\n    @Override\n    protected void encodeData(Channel channel, ObjectOutput out, Object data) throws IOException {\n        encodeRequestData(channel, out, data);\n    }\n\n    private void encodeEventData(Channel channel, ObjectOutput out, Object data) throws IOException {\n        encodeEventData(out, data);\n    }\n\n    @Deprecated\n    protected void encodeHeartbeatData(Channel channel, ObjectOutput out, Object data) throws IOException {\n        encodeHeartbeatData(out, data);\n    }\n\n    protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException {\n        encodeRequestData(out, data);\n    }\n\n    protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException {\n        encodeResponseData(out, data);\n    }\n\n    protected void encodeRequestData(Channel channel, ObjectOutput out, Object data, String version)\n            throws IOException {\n        encodeRequestData(out, data);\n    }\n\n    protected void encodeResponseData(Channel channel, ObjectOutput out, Object data, String version)\n            throws IOException {\n        encodeResponseData(out, data);\n    }\n\n    private Object finishRespWhenOverPayload(Channel channel, long size, byte[] header) {\n        byte flag = header[2];\n        if ((flag & FLAG_REQUEST) == 0) {\n            int payload = getPayload(channel);\n            boolean overPayload = isOverPayload(payload, size);\n            if (overPayload) {\n                long reqId = Bytes.bytes2long(header, 4);\n                Response res = new Response(reqId);\n                if ((flag & FLAG_EVENT) != 0) {\n                    res.setEvent(true);\n                }\n                res.setStatus(Response.CLIENT_ERROR);\n                String errorMsg =\n                        \"Data length too large: \" + size + \", max payload: \" + payload + \", channel: \" + channel;\n                logger.error(TRANSPORT_EXCEED_PAYLOAD_LIMIT, \"\", \"\", errorMsg);\n                res.setErrorMessage(errorMsg);\n                return res;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/DefaultFuture.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.resource.GlobalResourceInitializer;\nimport org.apache.dubbo.common.serialize.SerializationException;\nimport org.apache.dubbo.common.threadpool.ThreadlessExecutor;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.common.timer.Timeout;\nimport org.apache.dubbo.common.timer.Timer;\nimport org.apache.dubbo.common.timer.TimerTask;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.TimeoutException;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_TIMEOUT_SERVER;\n\n/**\n * DefaultFuture.\n */\npublic class DefaultFuture extends CompletableFuture<Object> {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DefaultFuture.class);\n\n    /**\n     * in-flight channels\n     */\n    private static final Map<Long, Channel> CHANNELS = new ConcurrentHashMap<>();\n\n    /**\n     * in-flight requests\n     */\n    private static final Map<Long, DefaultFuture> FUTURES = new ConcurrentHashMap<>();\n\n    private static final GlobalResourceInitializer<Timer> TIME_OUT_TIMER = new GlobalResourceInitializer<>(\n            () -> new HashedWheelTimer(new NamedThreadFactory(\"dubbo-future-timeout\", true), 30, TimeUnit.MILLISECONDS),\n            DefaultFuture::destroy);\n\n    // invoke id.\n    private final Long id;\n\n    private final Channel channel;\n\n    private final Request request;\n\n    private final int timeout;\n\n    private final long start = System.currentTimeMillis();\n\n    private volatile long sent;\n\n    private Timeout timeoutCheckTask;\n\n    private ExecutorService executor;\n\n    public ExecutorService getExecutor() {\n        return executor;\n    }\n\n    public void setExecutor(ExecutorService executor) {\n        this.executor = executor;\n    }\n\n    private DefaultFuture(Channel channel, Request request, int timeout) {\n        this.channel = channel;\n        this.request = request;\n        this.id = request.getId();\n        this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);\n        // put into waiting map.\n        FUTURES.put(id, this);\n        CHANNELS.put(id, channel);\n    }\n\n    /**\n     * check time out of the future\n     */\n    private static void timeoutCheck(DefaultFuture future) {\n        TimeoutCheckTask task = new TimeoutCheckTask(future.getId());\n        future.timeoutCheckTask = TIME_OUT_TIMER.get().newTimeout(task, future.getTimeout(), TimeUnit.MILLISECONDS);\n    }\n\n    public static void destroy() {\n        TIME_OUT_TIMER.remove(Timer::stop);\n        FUTURES.clear();\n        CHANNELS.clear();\n    }\n\n    /**\n     * init a DefaultFuture\n     * 1.init a DefaultFuture\n     * 2.timeout check\n     *\n     * @param channel channel\n     * @param request the request\n     * @param timeout timeout\n     * @return a new DefaultFuture\n     */\n    public static DefaultFuture newFuture(Channel channel, Request request, int timeout, ExecutorService executor) {\n        final DefaultFuture future = new DefaultFuture(channel, request, timeout);\n        future.setExecutor(executor);\n        // timeout check\n        timeoutCheck(future);\n        return future;\n    }\n\n    public static DefaultFuture getFuture(long id) {\n        return FUTURES.get(id);\n    }\n\n    public static boolean hasFuture(Channel channel) {\n        return CHANNELS.containsValue(channel);\n    }\n\n    public static void sent(Channel channel, Request request) {\n        DefaultFuture future = FUTURES.get(request.getId());\n        if (future != null) {\n            future.doSent();\n        }\n    }\n\n    /**\n     * close a channel when a channel is inactive\n     * directly return the unfinished requests.\n     *\n     * @param channel channel to close\n     */\n    public static void closeChannel(Channel channel, long timeout) {\n        long deadline = timeout > 0 ? System.currentTimeMillis() + timeout : 0;\n        for (Map.Entry<Long, Channel> entry : CHANNELS.entrySet()) {\n            if (channel.equals(entry.getValue())) {\n                DefaultFuture future = getFuture(entry.getKey());\n                if (future != null && !future.isDone()) {\n                    long restTime = deadline - System.currentTimeMillis();\n                    if (restTime > 0) {\n                        try {\n                            future.get(restTime, TimeUnit.MILLISECONDS);\n                        } catch (java.util.concurrent.TimeoutException ignore) {\n                            logger.warn(\n                                    PROTOCOL_TIMEOUT_SERVER,\n                                    \"\",\n                                    \"\",\n                                    \"Trying to close channel \" + channel + \", but response is not received in \"\n                                            + timeout + \"ms, and the request id is \" + future.id);\n                        } catch (Throwable ignore) {\n                        }\n                    }\n                    if (!future.isDone()) {\n                        respInactive(channel, future);\n                    }\n                }\n            }\n        }\n    }\n\n    private static void respInactive(Channel channel, DefaultFuture future) {\n        Response disconnectResponse = new Response(future.getId());\n        disconnectResponse.setStatus(Response.CHANNEL_INACTIVE);\n        disconnectResponse.setErrorMessage(\"Channel \" + channel\n                + \" is inactive. Directly return the unFinished request : \"\n                + (logger.isDebugEnabled()\n                        ? future.getRequest()\n                        : future.getRequest().copyWithoutData()));\n        DefaultFuture.received(channel, disconnectResponse);\n    }\n\n    public static void received(Channel channel, Response response) {\n        received(channel, response, false);\n    }\n\n    public static void received(Channel channel, Response response, boolean timeout) {\n        try {\n            DefaultFuture future = FUTURES.remove(response.getId());\n            if (future != null) {\n                Timeout t = future.timeoutCheckTask;\n                if (!timeout) {\n                    // decrease Time\n                    t.cancel();\n                }\n                future.doReceived(response);\n                shutdownExecutorIfNeeded(future);\n            } else {\n                logger.warn(\n                        PROTOCOL_TIMEOUT_SERVER,\n                        \"\",\n                        \"\",\n                        \"The timeout response finally returned at \"\n                                + (new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\").format(new Date()))\n                                + \", response status is \" + response.getStatus()\n                                + (channel == null\n                                        ? \"\"\n                                        : \", channel: \" + channel.getLocalAddress() + \" -> \"\n                                                + channel.getRemoteAddress())\n                                + \", please check provider side for detailed result.\");\n            }\n        } finally {\n            CHANNELS.remove(response.getId());\n        }\n    }\n\n    @Override\n    public boolean cancel(boolean mayInterruptIfRunning) {\n        Response errorResult = new Response(id);\n        errorResult.setStatus(Response.CLIENT_ERROR);\n        errorResult.setErrorMessage(\"request future has been canceled.\");\n        this.doReceived(errorResult);\n        DefaultFuture future = FUTURES.remove(id);\n        shutdownExecutorIfNeeded(future);\n        CHANNELS.remove(id);\n        timeoutCheckTask.cancel();\n        return true;\n    }\n\n    private static void shutdownExecutorIfNeeded(DefaultFuture future) {\n        ExecutorService executor = future.getExecutor();\n        if (executor instanceof ThreadlessExecutor && !executor.isShutdown()) {\n            executor.shutdownNow();\n        }\n    }\n\n    public void cancel() {\n        this.cancel(true);\n    }\n\n    private void doReceived(Response res) {\n        if (res == null) {\n            throw new IllegalStateException(\"response cannot be null\");\n        }\n        if (res.getStatus() == Response.OK) {\n            this.complete(res.getResult());\n        } else if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {\n            this.completeExceptionally(\n                    new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage()));\n        } else if (res.getStatus() == Response.SERIALIZATION_ERROR) {\n            this.completeExceptionally(new SerializationException(res.getErrorMessage()));\n        } else {\n            this.completeExceptionally(new RemotingException(channel, res.getErrorMessage()));\n        }\n    }\n\n    private long getId() {\n        return id;\n    }\n\n    private Channel getChannel() {\n        return channel;\n    }\n\n    private boolean isSent() {\n        return sent > 0;\n    }\n\n    public Request getRequest() {\n        return request;\n    }\n\n    private int getTimeout() {\n        return timeout;\n    }\n\n    private void doSent() {\n        sent = System.currentTimeMillis();\n    }\n\n    private String getTimeoutMessage(boolean scan) {\n        long nowTimestamp = System.currentTimeMillis();\n        return (sent > 0 && sent - start < timeout\n                        ? \"Waiting server-side response timeout\"\n                        : \"Sending request timeout in client-side\")\n                + (scan ? \" by scan timer\" : \"\") + \". start time: \"\n                + (new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\").format(new Date(start))) + \", end time: \"\n                + (new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\").format(new Date(nowTimestamp))) + \",\"\n                + (sent > 0\n                        ? \" client elapsed: \" + (sent - start) + \" ms, server elapsed: \" + (nowTimestamp - sent)\n                        : \" elapsed: \" + (nowTimestamp - start))\n                + \" ms, timeout: \"\n                + timeout + \" ms, request: \" + (logger.isDebugEnabled() ? request : request.copyWithoutData())\n                + \", channel: \" + channel.getLocalAddress()\n                + \" -> \" + channel.getRemoteAddress();\n    }\n\n    private static class TimeoutCheckTask implements TimerTask {\n\n        private final Long requestID;\n\n        TimeoutCheckTask(Long requestID) {\n            this.requestID = requestID;\n        }\n\n        @Override\n        public void run(Timeout timeout) {\n            DefaultFuture future = DefaultFuture.getFuture(requestID);\n            if (future == null || future.isDone()) {\n                return;\n            }\n\n            ExecutorService executor = future.getExecutor();\n            if (executor != null && !executor.isShutdown()) {\n                try {\n                    executor.execute(() -> notifyTimeout(future));\n                } catch (RejectedExecutionException e) {\n                    notifyExecutionError(future, e);\n                    throw e;\n                }\n            } else {\n                notifyTimeout(future);\n            }\n        }\n\n        private void notifyTimeout(DefaultFuture future) {\n            // create exception response.\n            Response timeoutResponse = new Response(future.getId());\n            // set timeout status.\n            timeoutResponse.setStatus(future.isSent() ? Response.SERVER_TIMEOUT : Response.CLIENT_TIMEOUT);\n            timeoutResponse.setErrorMessage(future.getTimeoutMessage(true));\n            // handle response.\n            DefaultFuture.received(future.getChannel(), timeoutResponse, true);\n        }\n\n        private void notifyExecutionError(DefaultFuture future, Throwable e) {\n            // create exception response.\n            Response errorResponse = new Response(future.getId());\n            // set error status\n            errorResponse.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);\n            // set detailed error message\n            errorResponse.setErrorMessage(\"Executor rejected the task for handling timeout notification: \"\n                    + e.getClass().getSimpleName() + \" - \" + e.getMessage());\n            // handle response.\n            DefaultFuture.received(future.getChannel(), errorResponse, true);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/ExchangeHandlerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support;\n\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.exchange.ExchangeHandler;\nimport org.apache.dubbo.remoting.telnet.support.TelnetHandlerAdapter;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic abstract class ExchangeHandlerAdapter extends TelnetHandlerAdapter implements ExchangeHandler {\n    public ExchangeHandlerAdapter(FrameworkModel frameworkModel) {\n        super(frameworkModel);\n    }\n\n    @Override\n    public CompletableFuture<Object> reply(ExchangeChannel channel, Object msg) throws RemotingException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/ExchangeHandlerDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.exchange.ExchangeHandler;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.remoting.telnet.support.TelnetHandlerAdapter;\nimport org.apache.dubbo.remoting.transport.ChannelHandlerDispatcher;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic class ExchangeHandlerDispatcher implements ExchangeHandler {\n\n    private final ReplierDispatcher replierDispatcher;\n\n    private final ChannelHandlerDispatcher handlerDispatcher;\n\n    private final TelnetHandler telnetHandler;\n\n    public ExchangeHandlerDispatcher() {\n        this(FrameworkModel.defaultModel(), null, (ChannelHandler) null);\n    }\n\n    public ExchangeHandlerDispatcher(Replier<?> replier) {\n        this(FrameworkModel.defaultModel(), replier, (ChannelHandler) null);\n    }\n\n    public ExchangeHandlerDispatcher(ChannelHandler... handlers) {\n        this(FrameworkModel.defaultModel(), null, handlers);\n    }\n\n    public ExchangeHandlerDispatcher(FrameworkModel frameworkModel, Replier<?> replier, ChannelHandler... handlers) {\n        replierDispatcher = new ReplierDispatcher(replier);\n        handlerDispatcher = new ChannelHandlerDispatcher(handlers);\n        telnetHandler = new TelnetHandlerAdapter(frameworkModel);\n    }\n\n    public ExchangeHandlerDispatcher addChannelHandler(ChannelHandler handler) {\n        handlerDispatcher.addChannelHandler(handler);\n        return this;\n    }\n\n    public ExchangeHandlerDispatcher removeChannelHandler(ChannelHandler handler) {\n        handlerDispatcher.removeChannelHandler(handler);\n        return this;\n    }\n\n    public <T> ExchangeHandlerDispatcher addReplier(Class<T> type, Replier<T> replier) {\n        replierDispatcher.addReplier(type, replier);\n        return this;\n    }\n\n    public <T> ExchangeHandlerDispatcher removeReplier(Class<T> type) {\n        replierDispatcher.removeReplier(type);\n        return this;\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public CompletableFuture<Object> reply(ExchangeChannel channel, Object request) throws RemotingException {\n        return CompletableFuture.completedFuture(((Replier) replierDispatcher).reply(channel, request));\n    }\n\n    @Override\n    public void connected(Channel channel) {\n        handlerDispatcher.connected(channel);\n    }\n\n    @Override\n    public void disconnected(Channel channel) {\n        handlerDispatcher.disconnected(channel);\n    }\n\n    @Override\n    public void sent(Channel channel, Object message) {\n        handlerDispatcher.sent(channel, message);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) {\n        handlerDispatcher.received(channel, message);\n    }\n\n    @Override\n    public void caught(Channel channel, Throwable exception) {\n        handlerDispatcher.caught(channel, exception);\n    }\n\n    @Override\n    public String telnet(Channel channel, String message) throws RemotingException {\n        return telnetHandler.telnet(channel, message);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/ExchangeServerDelegate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelEvent;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.exchange.ExchangeServer;\n\nimport java.net.InetSocketAddress;\nimport java.util.Collection;\n\npublic class ExchangeServerDelegate implements ExchangeServer {\n\n    private transient ExchangeServer server;\n\n    public ExchangeServerDelegate() {}\n\n    public ExchangeServerDelegate(ExchangeServer server) {\n        setServer(server);\n    }\n\n    public ExchangeServer getServer() {\n        return server;\n    }\n\n    public void setServer(ExchangeServer server) {\n        this.server = server;\n    }\n\n    @Override\n    public boolean isBound() {\n        return server.isBound();\n    }\n\n    @Override\n    public void reset(URL url) {\n        server.reset(url);\n    }\n\n    @Override\n    @Deprecated\n    public void reset(org.apache.dubbo.common.Parameters parameters) {\n        reset(getUrl().addParameters(parameters.getParameters()));\n    }\n\n    @Override\n    public Collection<Channel> getChannels() {\n        return server.getChannels();\n    }\n\n    @Override\n    public void fireChannelEvent(ChannelEvent event) {\n        server.fireChannelEvent(event);\n    }\n\n    @Override\n    public Channel getChannel(InetSocketAddress remoteAddress) {\n        return server.getChannel(remoteAddress);\n    }\n\n    @Override\n    public URL getUrl() {\n        return server.getUrl();\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        return server.getChannelHandler();\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return server.getLocalAddress();\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        server.send(message);\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        server.send(message, sent);\n    }\n\n    @Override\n    public void close() {\n        server.close();\n    }\n\n    @Override\n    public boolean isClosed() {\n        return server.isClosed();\n    }\n\n    @Override\n    public Collection<ExchangeChannel> getExchangeChannels() {\n        return server.getExchangeChannels();\n    }\n\n    @Override\n    public ExchangeChannel getExchangeChannel(InetSocketAddress remoteAddress) {\n        return server.getExchangeChannel(remoteAddress);\n    }\n\n    @Override\n    public void close(int timeout) {\n        server.close(timeout);\n    }\n\n    @Override\n    public void startClose() {\n        server.startClose();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/MultiMessage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * @see org.apache.dubbo.remoting.transport.MultiMessageHandler\n */\npublic final class MultiMessage implements Iterable {\n\n    private final List messages = new ArrayList();\n\n    private MultiMessage() {}\n\n    public static MultiMessage createFromCollection(Collection collection) {\n        MultiMessage result = new MultiMessage();\n        result.addMessages(collection);\n        return result;\n    }\n\n    public static MultiMessage createFromArray(Object... args) {\n        return createFromCollection(Arrays.asList(args));\n    }\n\n    public static MultiMessage create() {\n        return new MultiMessage();\n    }\n\n    public void addMessage(Object msg) {\n        messages.add(msg);\n    }\n\n    public void addMessages(Collection collection) {\n        messages.addAll(collection);\n    }\n\n    public Collection getMessages() {\n        return Collections.unmodifiableCollection(messages);\n    }\n\n    public int size() {\n        return messages.size();\n    }\n\n    public Object get(int index) {\n        return messages.get(index);\n    }\n\n    public boolean isEmpty() {\n        return messages.isEmpty();\n    }\n\n    public Collection removeMessages() {\n        Collection result = Collections.unmodifiableCollection(messages);\n        messages.clear();\n        return result;\n    }\n\n    @Override\n    public Iterator iterator() {\n        return messages.iterator();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/Replier.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support;\n\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\n\n/**\n * Replier. (API, Prototype, ThreadSafe)\n */\npublic interface Replier<T> {\n\n    /**\n     * reply.\n     *\n     * @param channel\n     * @param request\n     * @return response\n     * @throws RemotingException\n     */\n    Object reply(ExchangeChannel channel, T request) throws RemotingException;\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/ReplierDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class ReplierDispatcher implements Replier<Object> {\n\n    private final Replier<?> defaultReplier;\n\n    private final Map<Class<?>, Replier<?>> repliers = new ConcurrentHashMap<>();\n\n    public ReplierDispatcher() {\n        this(null, null);\n    }\n\n    public ReplierDispatcher(Replier<?> defaultReplier) {\n        this(defaultReplier, null);\n    }\n\n    public ReplierDispatcher(Replier<?> defaultReplier, Map<Class<?>, Replier<?>> repliers) {\n        this.defaultReplier = defaultReplier;\n        if (CollectionUtils.isNotEmptyMap(repliers)) {\n            this.repliers.putAll(repliers);\n        }\n    }\n\n    public <T> ReplierDispatcher addReplier(Class<T> type, Replier<T> replier) {\n        repliers.put(type, replier);\n        return this;\n    }\n\n    public <T> ReplierDispatcher removeReplier(Class<T> type) {\n        repliers.remove(type);\n        return this;\n    }\n\n    private Replier<?> getReplier(Class<?> type) {\n        for (Map.Entry<Class<?>, Replier<?>> entry : repliers.entrySet()) {\n            if (entry.getKey().isAssignableFrom(type)) {\n                return entry.getValue();\n            }\n        }\n        if (defaultReplier != null) {\n            return defaultReplier;\n        }\n        throw new IllegalStateException(\"Replier not found, Unsupported message object: \" + type);\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public Object reply(ExchangeChannel channel, Object request) throws RemotingException {\n        return ((Replier) getReplier(request.getClass())).reply(channel, request);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/AbstractTimerTask.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.common.timer.Timeout;\nimport org.apache.dubbo.common.timer.TimerTask;\nimport org.apache.dubbo.remoting.Channel;\n\nimport java.util.Collection;\nimport java.util.concurrent.TimeUnit;\n\npublic abstract class AbstractTimerTask implements TimerTask {\n\n    private final ChannelProvider channelProvider;\n    private final HashedWheelTimer hashedWheelTimer;\n\n    private final Long tick;\n\n    protected volatile boolean cancel = false;\n\n    private volatile Timeout timeout;\n\n    AbstractTimerTask(ChannelProvider channelProvider, HashedWheelTimer hashedWheelTimer, Long tick) {\n        if (channelProvider == null || hashedWheelTimer == null || tick == null) {\n            throw new IllegalArgumentException();\n        }\n        this.channelProvider = channelProvider;\n        this.hashedWheelTimer = hashedWheelTimer;\n        this.tick = tick;\n        // do not start here because inheritor should set additional timeout parameters before doing task.\n    }\n\n    static Long lastRead(Channel channel) {\n        return (Long) channel.getAttribute(HeartbeatHandler.KEY_READ_TIMESTAMP);\n    }\n\n    static Long lastWrite(Channel channel) {\n        return (Long) channel.getAttribute(HeartbeatHandler.KEY_WRITE_TIMESTAMP);\n    }\n\n    static Long now() {\n        return System.currentTimeMillis();\n    }\n\n    protected void start() {\n        this.timeout = hashedWheelTimer.newTimeout(this, tick, TimeUnit.MILLISECONDS);\n    }\n\n    public synchronized void cancel() {\n        this.cancel = true;\n        this.timeout.cancel();\n    }\n\n    private synchronized void reput(Timeout timeout) {\n        if (timeout == null) {\n            throw new IllegalArgumentException();\n        }\n\n        if (cancel) {\n            return;\n        }\n\n        if (hashedWheelTimer.isStop() || timeout.isCancelled()) {\n            return;\n        }\n\n        this.timeout = hashedWheelTimer.newTimeout(timeout.task(), tick, TimeUnit.MILLISECONDS);\n    }\n\n    @Override\n    public synchronized void run(Timeout timeout) throws Exception {\n        Collection<Channel> channels = channelProvider.getChannels();\n        for (Channel channel : channels) {\n            if (!channel.isClosed()) {\n                doTask(channel);\n            }\n        }\n        reput(timeout);\n    }\n\n    protected abstract void doTask(Channel channel);\n\n    interface ChannelProvider {\n        Collection<Channel> getChannels();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/CloseTimerTask.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.remoting.Channel;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_RESPONSE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CLOSE;\n\npublic class CloseTimerTask extends AbstractTimerTask {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(CloseTimerTask.class);\n\n    private final int closeTimeout;\n\n    public CloseTimerTask(\n            ChannelProvider channelProvider, HashedWheelTimer hashedWheelTimer, Long tick, int closeTimeout) {\n        super(channelProvider, hashedWheelTimer, tick);\n        this.closeTimeout = closeTimeout;\n        start();\n    }\n\n    @Override\n    protected void doTask(Channel channel) {\n        try {\n            Long lastRead = lastRead(channel);\n            Long lastWrite = lastWrite(channel);\n            Long now = now();\n            // check ping & pong at server\n            if ((lastRead != null && now - lastRead > closeTimeout)\n                    || (lastWrite != null && now - lastWrite > closeTimeout)) {\n                logger.warn(\n                        PROTOCOL_FAILED_RESPONSE,\n                        \"\",\n                        \"\",\n                        \"Close channel \" + channel + \", because idleCheck timeout: \" + closeTimeout + \"ms\");\n                channel.close();\n            }\n        } catch (Throwable t) {\n            logger.warn(\n                    TRANSPORT_FAILED_CLOSE,\n                    \"\",\n                    \"\",\n                    \"Exception when close remote channel \" + channel.getRemoteAddress(),\n                    t);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.exchange.ExchangeHandler;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\nimport org.apache.dubbo.remoting.exchange.support.DefaultFuture;\n\nimport java.net.InetSocketAddress;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutorService;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CLOSE;\n\n/**\n * ExchangeReceiver\n */\nfinal class HeaderExchangeChannel implements ExchangeChannel {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(HeaderExchangeChannel.class);\n\n    private static final String CHANNEL_KEY = HeaderExchangeChannel.class.getName() + \".CHANNEL\";\n\n    private final Channel channel;\n\n    private final int shutdownTimeout;\n\n    private volatile boolean closed = false;\n\n    HeaderExchangeChannel(Channel channel) {\n        if (channel == null) {\n            throw new IllegalArgumentException(\"channel == null\");\n        }\n        this.channel = channel;\n        this.shutdownTimeout = Optional.ofNullable(channel.getUrl())\n                .map(URL::getOrDefaultApplicationModel)\n                .map(ConfigurationUtils::getServerShutdownTimeout)\n                .orElse(DEFAULT_TIMEOUT);\n    }\n\n    static HeaderExchangeChannel getOrAddChannel(Channel ch) {\n        if (ch == null) {\n            return null;\n        }\n        HeaderExchangeChannel ret = (HeaderExchangeChannel) ch.getAttribute(CHANNEL_KEY);\n        if (ret == null) {\n            ret = new HeaderExchangeChannel(ch);\n            if (ch.isConnected()) {\n                ch.setAttribute(CHANNEL_KEY, ret);\n            }\n        }\n        return ret;\n    }\n\n    static void removeChannelIfDisconnected(Channel ch) {\n        if (ch != null && !ch.isConnected()) {\n            ch.removeAttribute(CHANNEL_KEY);\n        }\n    }\n\n    static void removeChannel(Channel ch) {\n        if (ch != null) {\n            ch.removeAttribute(CHANNEL_KEY);\n        }\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        send(message, false);\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        if (closed) {\n            throw new RemotingException(\n                    this.getLocalAddress(),\n                    null,\n                    \"Failed to send message \" + message + \", cause: The channel \" + this + \" is closed!\");\n        }\n        if (message instanceof Request || message instanceof Response || message instanceof String) {\n            channel.send(message, sent);\n        } else {\n            Request request = new Request();\n            request.setVersion(Version.getProtocolVersion());\n            request.setTwoWay(false);\n            request.setData(message);\n            channel.send(request, sent);\n        }\n    }\n\n    @Override\n    public CompletableFuture<Object> request(Object request) throws RemotingException {\n        return request(request, null);\n    }\n\n    @Override\n    public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {\n        return request(request, timeout, null);\n    }\n\n    @Override\n    public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {\n        return request(request, channel.getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT), executor);\n    }\n\n    @Override\n    public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor)\n            throws RemotingException {\n        if (closed) {\n            throw new RemotingException(\n                    this.getLocalAddress(),\n                    null,\n                    \"Failed to send request \" + request + \", cause: The channel \" + this + \" is closed!\");\n        }\n        Request req;\n        if (request instanceof Request) {\n            req = (Request) request;\n        } else {\n            // create request.\n            req = new Request();\n            req.setVersion(Version.getProtocolVersion());\n            req.setTwoWay(true);\n            req.setData(request);\n        }\n        DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout, executor);\n        try {\n            channel.send(req);\n        } catch (RemotingException e) {\n            future.cancel();\n            throw e;\n        }\n        return future;\n    }\n\n    @Override\n    public boolean isClosed() {\n        return closed;\n    }\n\n    @Override\n    public void close() {\n        if (closed) {\n            return;\n        }\n        closed = true;\n        try {\n            // graceful close\n            DefaultFuture.closeChannel(channel, ConfigurationUtils.reCalShutdownTime(shutdownTimeout));\n        } catch (Exception e) {\n            logger.warn(TRANSPORT_FAILED_CLOSE, \"\", \"\", e.getMessage(), e);\n        }\n\n        try {\n            channel.close();\n        } catch (Exception e) {\n            logger.warn(TRANSPORT_FAILED_CLOSE, \"\", \"\", e.getMessage(), e);\n        }\n    }\n\n    // graceful close\n    @Override\n    public void close(int timeout) {\n        if (closed) {\n            return;\n        }\n        if (timeout > 0) {\n            long start = System.currentTimeMillis();\n            while (DefaultFuture.hasFuture(channel) && System.currentTimeMillis() - start < timeout) {\n                try {\n                    Thread.sleep(10);\n                } catch (InterruptedException e) {\n                    logger.warn(TRANSPORT_FAILED_CLOSE, \"\", \"\", e.getMessage(), e);\n                }\n            }\n        }\n        close();\n    }\n\n    @Override\n    public void startClose() {\n        channel.startClose();\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return channel.getLocalAddress();\n    }\n\n    @Override\n    public InetSocketAddress getRemoteAddress() {\n        return channel.getRemoteAddress();\n    }\n\n    @Override\n    public URL getUrl() {\n        return channel.getUrl();\n    }\n\n    @Override\n    public boolean isConnected() {\n        return channel.isConnected();\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        return channel.getChannelHandler();\n    }\n\n    @Override\n    public ExchangeHandler getExchangeHandler() {\n        return (ExchangeHandler) channel.getChannelHandler();\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        return channel.getAttribute(key);\n    }\n\n    @Override\n    public void setAttribute(String key, Object value) {\n        channel.setAttribute(key, value);\n    }\n\n    @Override\n    public void removeAttribute(String key) {\n        channel.removeAttribute(key);\n    }\n\n    @Override\n    public boolean hasAttribute(String key) {\n        return channel.hasAttribute(key);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + channel.hashCode();\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        HeaderExchangeChannel other = (HeaderExchangeChannel) obj;\n        return channel.equals(other.channel);\n    }\n\n    @Override\n    public String toString() {\n        return channel.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.resource.GlobalResourceInitializer;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Client;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.exchange.ExchangeClient;\nimport org.apache.dubbo.remoting.exchange.ExchangeHandler;\n\nimport java.net.InetSocketAddress;\nimport java.util.Collections;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.remoting.Constants.HEARTBEAT_CHECK_TICK;\nimport static org.apache.dubbo.remoting.Constants.LEAST_HEARTBEAT_DURATION;\nimport static org.apache.dubbo.remoting.Constants.LEAST_RECONNECT_DURATION;\nimport static org.apache.dubbo.remoting.Constants.LEAST_RECONNECT_DURATION_KEY;\nimport static org.apache.dubbo.remoting.Constants.TICKS_PER_WHEEL;\nimport static org.apache.dubbo.remoting.utils.UrlUtils.getHeartbeat;\nimport static org.apache.dubbo.remoting.utils.UrlUtils.getIdleTimeout;\n\n/**\n * DefaultMessageClient\n */\npublic class HeaderExchangeClient implements ExchangeClient {\n\n    private final Client client;\n    private final ExchangeChannel channel;\n\n    public static GlobalResourceInitializer<HashedWheelTimer> IDLE_CHECK_TIMER = new GlobalResourceInitializer<>(\n            () -> new HashedWheelTimer(\n                    new NamedThreadFactory(\"dubbo-client-heartbeat-reconnect\", true),\n                    1,\n                    TimeUnit.SECONDS,\n                    TICKS_PER_WHEEL),\n            HashedWheelTimer::stop);\n\n    private ReconnectTimerTask reconnectTimerTask;\n    private HeartbeatTimerTask heartBeatTimerTask;\n    private final int idleTimeout;\n\n    public HeaderExchangeClient(Client client, boolean startTimer) {\n        Assert.notNull(client, \"Client can't be null\");\n        this.client = client;\n        this.channel = new HeaderExchangeChannel(client);\n\n        if (startTimer) {\n            URL url = client.getUrl();\n            idleTimeout = getIdleTimeout(url);\n            startReconnectTask(url);\n            startHeartBeatTask(url);\n        } else {\n            idleTimeout = 0;\n        }\n    }\n\n    @Override\n    public CompletableFuture<Object> request(Object request) throws RemotingException {\n        return channel.request(request);\n    }\n\n    @Override\n    public URL getUrl() {\n        return channel.getUrl();\n    }\n\n    @Override\n    public InetSocketAddress getRemoteAddress() {\n        return channel.getRemoteAddress();\n    }\n\n    @Override\n    public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {\n        return channel.request(request, timeout);\n    }\n\n    @Override\n    public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {\n        return channel.request(request, executor);\n    }\n\n    @Override\n    public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor)\n            throws RemotingException {\n        return channel.request(request, timeout, executor);\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        return channel.getChannelHandler();\n    }\n\n    @Override\n    public boolean isConnected() {\n        if (channel.isConnected()) {\n            if (idleTimeout <= 0) {\n                return true;\n            }\n            Long lastRead = (Long) channel.getAttribute(HeartbeatHandler.KEY_READ_TIMESTAMP);\n            Long now = System.currentTimeMillis();\n\n            return lastRead == null || now - lastRead < idleTimeout;\n        }\n        return false;\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return channel.getLocalAddress();\n    }\n\n    @Override\n    public ExchangeHandler getExchangeHandler() {\n        return channel.getExchangeHandler();\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        channel.send(message);\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        channel.send(message, sent);\n    }\n\n    @Override\n    public boolean isClosed() {\n        return channel.isClosed();\n    }\n\n    @Override\n    public synchronized void close() {\n        doClose();\n        channel.close();\n    }\n\n    @Override\n    public void close(int timeout) {\n        // Mark the client into the closure process\n        startClose();\n        doClose();\n        channel.close(timeout);\n    }\n\n    @Override\n    public void startClose() {\n        channel.startClose();\n    }\n\n    @Override\n    public void reset(URL url) {\n        client.reset(url);\n        // FIXME, should cancel and restart timer tasks if parameters in the new URL are different?\n    }\n\n    @Override\n    @Deprecated\n    public void reset(org.apache.dubbo.common.Parameters parameters) {\n        reset(getUrl().addParameters(parameters.getParameters()));\n    }\n\n    @Override\n    public synchronized void reconnect() throws RemotingException {\n        client.reconnect();\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        return channel.getAttribute(key);\n    }\n\n    @Override\n    public void setAttribute(String key, Object value) {\n        channel.setAttribute(key, value);\n    }\n\n    @Override\n    public void removeAttribute(String key) {\n        channel.removeAttribute(key);\n    }\n\n    @Override\n    public boolean hasAttribute(String key) {\n        return channel.hasAttribute(key);\n    }\n\n    private void startHeartBeatTask(URL url) {\n        if (!client.canHandleIdle()) {\n            int heartbeat = getHeartbeat(url);\n            long heartbeatTick = calculateLeastDuration(heartbeat);\n            heartBeatTimerTask = new HeartbeatTimerTask(\n                    () -> Collections.singleton(this), IDLE_CHECK_TIMER.get(), heartbeatTick, heartbeat);\n        }\n    }\n\n    private void startReconnectTask(URL url) {\n        if (shouldReconnect(url)) {\n            long heartbeatTimeoutTick = calculateLeastDuration(idleTimeout);\n            reconnectTimerTask = new ReconnectTimerTask(\n                    () -> Collections.singleton(this),\n                    IDLE_CHECK_TIMER.get(),\n                    calculateReconnectDuration(url, heartbeatTimeoutTick),\n                    idleTimeout);\n        }\n    }\n\n    private void doClose() {\n        if (heartBeatTimerTask != null) {\n            heartBeatTimerTask.cancel();\n            heartBeatTimerTask = null;\n        }\n        if (reconnectTimerTask != null) {\n            reconnectTimerTask.cancel();\n            reconnectTimerTask = null;\n        }\n    }\n\n    /**\n     * Each interval cannot be less than 1000ms.\n     */\n    private long calculateLeastDuration(int time) {\n        if (time / HEARTBEAT_CHECK_TICK <= 0) {\n            return LEAST_HEARTBEAT_DURATION;\n        } else {\n            return time / HEARTBEAT_CHECK_TICK;\n        }\n    }\n\n    private long calculateReconnectDuration(URL url, long tick) {\n        long leastReconnectDuration = url.getParameter(LEAST_RECONNECT_DURATION_KEY, LEAST_RECONNECT_DURATION);\n        return Math.max(leastReconnectDuration, tick);\n    }\n\n    protected boolean shouldReconnect(URL url) {\n        return !Boolean.FALSE.toString().equalsIgnoreCase(url.getParameter(Constants.RECONNECT_KEY));\n    }\n\n    @Override\n    public String toString() {\n        return \"HeaderExchangeClient [channel=\" + channel + \"]\";\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.ExecutionException;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.exchange.ExchangeHandler;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\nimport org.apache.dubbo.remoting.exchange.support.DefaultFuture;\nimport org.apache.dubbo.remoting.exchange.support.MultiMessage;\nimport org.apache.dubbo.remoting.transport.ChannelHandlerDelegate;\n\nimport java.net.InetSocketAddress;\nimport java.util.concurrent.CompletionStage;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.READONLY_EVENT;\nimport static org.apache.dubbo.common.constants.CommonConstants.WRITEABLE_EVENT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RESPONSE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_UNSUPPORTED_MESSAGE;\n\n/**\n * ExchangeReceiver\n */\npublic class HeaderExchangeHandler implements ChannelHandlerDelegate {\n\n    protected static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(HeaderExchangeHandler.class);\n\n    private final ExchangeHandler handler;\n\n    public HeaderExchangeHandler(ExchangeHandler handler) {\n        if (handler == null) {\n            throw new IllegalArgumentException(\"handler == null\");\n        }\n        this.handler = handler;\n    }\n\n    static void handleResponse(Channel channel, Response response) throws RemotingException {\n        if (response != null && !response.isHeartbeat()) {\n            DefaultFuture.received(channel, response);\n        }\n    }\n\n    private static boolean isClientSide(Channel channel) {\n        InetSocketAddress address = channel.getRemoteAddress();\n        URL url = channel.getUrl();\n        return url.getPort() == address.getPort()\n                && NetUtils.filterLocalHost(url.getIp())\n                        .equals(NetUtils.filterLocalHost(address.getAddress().getHostAddress()));\n    }\n\n    void handlerEvent(Channel channel, Request req) throws RemotingException {\n        if (req.getData() != null && req.getData().equals(READONLY_EVENT)) {\n            channel.setAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY, Boolean.TRUE);\n            logger.info(\"ChannelReadOnly set true for channel: \" + channel);\n        }\n        if (req.getData() != null && req.getData().equals(WRITEABLE_EVENT)) {\n            channel.removeAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY);\n            logger.info(\"ChannelReadOnly set false for channel: \" + channel);\n        }\n    }\n\n    void handleRequest(final ExchangeChannel channel, Request req) throws RemotingException {\n        Response res = new Response(req.getId(), req.getVersion());\n        if (req.isBroken()) {\n            Object data = req.getData();\n\n            String msg;\n            if (data == null) {\n                msg = null;\n            } else if (data instanceof Throwable) {\n                msg = StringUtils.toString((Throwable) data);\n            } else {\n                msg = data.toString();\n            }\n            res.setErrorMessage(\"Fail to decode request due to: \" + msg);\n            res.setStatus(Response.BAD_REQUEST);\n\n            channel.send(res);\n            return;\n        }\n        // find handler by message class.\n        Object msg = req.getData();\n        try {\n            CompletionStage<Object> future = handler.reply(channel, msg);\n            future.whenComplete((appResult, t) -> {\n                try {\n                    if (t == null) {\n                        res.setStatus(Response.OK);\n                        res.setResult(appResult);\n                    } else {\n                        res.setStatus(Response.SERVICE_ERROR);\n                        res.setErrorMessage(StringUtils.toString(t));\n                    }\n                    channel.send(res);\n                } catch (RemotingException e) {\n                    logger.warn(\n                            TRANSPORT_FAILED_RESPONSE,\n                            \"\",\n                            \"\",\n                            \"Send result to consumer failed, channel is \" + channel + \", msg is \" + e);\n                }\n            });\n        } catch (Throwable e) {\n            res.setStatus(Response.SERVICE_ERROR);\n            res.setErrorMessage(StringUtils.toString(e));\n            channel.send(res);\n        }\n    }\n\n    @Override\n    public void connected(Channel channel) throws RemotingException {\n        ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);\n        handler.connected(exchangeChannel);\n        channel.setAttribute(\n                Constants.CHANNEL_SHUTDOWN_TIMEOUT_KEY,\n                ConfigurationUtils.getServerShutdownTimeout(channel.getUrl().getOrDefaultApplicationModel()));\n    }\n\n    @Override\n    public void disconnected(Channel channel) throws RemotingException {\n        ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);\n        try {\n            handler.disconnected(exchangeChannel);\n        } finally {\n            int shutdownTimeout = 0;\n            Object timeoutObj = channel.getAttribute(Constants.CHANNEL_SHUTDOWN_TIMEOUT_KEY);\n            if (timeoutObj instanceof Integer) {\n                shutdownTimeout = (Integer) timeoutObj;\n            }\n            DefaultFuture.closeChannel(channel, ConfigurationUtils.reCalShutdownTime(shutdownTimeout));\n            HeaderExchangeChannel.removeChannel(channel);\n        }\n    }\n\n    @Override\n    public void sent(Channel channel, Object message) throws RemotingException {\n        Throwable exception = null;\n        try {\n            ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);\n            handler.sent(exchangeChannel, message);\n        } catch (Throwable t) {\n            exception = t;\n            HeaderExchangeChannel.removeChannelIfDisconnected(channel);\n        }\n        if (message instanceof Request) {\n            Request request = (Request) message;\n            DefaultFuture.sent(channel, request);\n        }\n        if (message instanceof MultiMessage) {\n            MultiMessage multiMessage = (MultiMessage) message;\n            for (Object single : multiMessage) {\n                if (single instanceof Request) {\n                    DefaultFuture.sent(channel, ((Request) single));\n                }\n            }\n        }\n        if (exception != null) {\n            if (exception instanceof RuntimeException) {\n                throw (RuntimeException) exception;\n            } else if (exception instanceof RemotingException) {\n                throw (RemotingException) exception;\n            } else {\n                throw new RemotingException(\n                        channel.getLocalAddress(), channel.getRemoteAddress(), exception.getMessage(), exception);\n            }\n        }\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        final ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);\n        if (message instanceof Request) {\n            // handle request.\n            Request request = (Request) message;\n            if (request.isEvent()) {\n                handlerEvent(channel, request);\n            } else {\n                if (request.isTwoWay()) {\n                    handleRequest(exchangeChannel, request);\n                } else {\n                    handler.received(exchangeChannel, request.getData());\n                }\n            }\n        } else if (message instanceof Response) {\n            handleResponse(channel, (Response) message);\n        } else if (message instanceof String) {\n            if (isClientSide(channel)) {\n                Exception e = new Exception(\"Dubbo client can not supported string message: \" + message\n                        + \" in channel: \" + channel + \", url: \" + channel.getUrl());\n                logger.error(TRANSPORT_UNSUPPORTED_MESSAGE, \"\", \"\", e.getMessage(), e);\n            } else {\n                String echo = handler.telnet(channel, (String) message);\n                if (StringUtils.isNotEmpty(echo)) {\n                    channel.send(echo);\n                }\n            }\n        } else {\n            handler.received(exchangeChannel, message);\n        }\n    }\n\n    @Override\n    public void caught(Channel channel, Throwable exception) throws RemotingException {\n        if (exception instanceof ExecutionException) {\n            ExecutionException e = (ExecutionException) exception;\n            Object msg = e.getRequest();\n            if (msg instanceof Request) {\n                Request req = (Request) msg;\n                if (req.isTwoWay() && !req.isHeartbeat()) {\n                    Response res = new Response(req.getId(), req.getVersion());\n                    res.setStatus(Response.SERVER_ERROR);\n                    res.setErrorMessage(StringUtils.toString(e));\n                    channel.send(res);\n                    return;\n                }\n            }\n        }\n        ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);\n        try {\n            handler.caught(exchangeChannel, exception);\n        } finally {\n            HeaderExchangeChannel.removeChannelIfDisconnected(channel);\n        }\n    }\n\n    @Override\n    public ChannelHandler getHandler() {\n        if (handler instanceof ChannelHandlerDelegate) {\n            return ((ChannelHandlerDelegate) handler).getHandler();\n        } else {\n            return handler;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.resource.GlobalResourceInitializer;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelEvent;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.RemotingServer;\nimport org.apache.dubbo.remoting.event.ReadOnlyEvent;\nimport org.apache.dubbo.remoting.event.WriteableEvent;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.exchange.ExchangeServer;\nimport org.apache.dubbo.remoting.exchange.Request;\n\nimport java.net.InetSocketAddress;\nimport java.nio.channels.ClosedChannelException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport static java.util.Collections.unmodifiableCollection;\nimport static org.apache.dubbo.common.constants.CommonConstants.READONLY_EVENT;\nimport static org.apache.dubbo.common.constants.CommonConstants.WRITEABLE_EVENT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CLOSE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RESPONSE;\nimport static org.apache.dubbo.remoting.Constants.HEARTBEAT_CHECK_TICK;\nimport static org.apache.dubbo.remoting.Constants.LEAST_HEARTBEAT_DURATION;\nimport static org.apache.dubbo.remoting.Constants.TICKS_PER_WHEEL;\nimport static org.apache.dubbo.remoting.utils.UrlUtils.getCloseTimeout;\n\n/**\n * ExchangeServerImpl\n */\npublic class HeaderExchangeServer implements ExchangeServer {\n\n    protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private final RemotingServer server;\n\n    private final AtomicBoolean closed = new AtomicBoolean(false);\n\n    public static GlobalResourceInitializer<HashedWheelTimer> IDLE_CHECK_TIMER = new GlobalResourceInitializer<>(\n            () -> new HashedWheelTimer(\n                    new NamedThreadFactory(\"dubbo-server-idleCheck\", true), 1, TimeUnit.SECONDS, TICKS_PER_WHEEL),\n            HashedWheelTimer::stop);\n\n    private CloseTimerTask closeTimer;\n\n    public HeaderExchangeServer(RemotingServer server) {\n        Assert.notNull(server, \"server == null\");\n        this.server = server;\n        startIdleCheckTask(getUrl());\n    }\n\n    public RemotingServer getServer() {\n        return server;\n    }\n\n    @Override\n    public boolean isClosed() {\n        return server.isClosed();\n    }\n\n    private boolean isRunning() {\n        // If there are any client connections,\n        // our server should be running.\n        return getChannels().stream().anyMatch(Channel::isConnected);\n    }\n\n    @Override\n    public void close() {\n        if (!closed.compareAndSet(false, true)) {\n            return;\n        }\n        doClose();\n        server.close();\n    }\n\n    @Override\n    public void close(final int timeout) {\n        if (!closed.compareAndSet(false, true)) {\n            return;\n        }\n        startClose();\n        if (timeout > 0) {\n            final long start = System.currentTimeMillis();\n            if (getUrl().getParameter(Constants.CHANNEL_SEND_READONLYEVENT_KEY, true)) {\n                sendChannelEvent(READONLY_EVENT);\n            }\n            while (HeaderExchangeServer.this.isRunning() && System.currentTimeMillis() - start < (long) timeout) {\n                try {\n                    Thread.sleep(10);\n                } catch (InterruptedException e) {\n                    logger.warn(TRANSPORT_FAILED_CLOSE, \"\", \"\", e.getMessage(), e);\n                }\n            }\n        }\n        doClose();\n        server.close(timeout);\n    }\n\n    @Override\n    public void startClose() {\n        server.startClose();\n    }\n\n    private void sendChannelEvent(String event) {\n        Request request = new Request();\n        request.setEvent(event);\n        request.setTwoWay(false);\n        request.setVersion(Version.getProtocolVersion());\n\n        Collection<Channel> channels = getChannels();\n        for (Channel channel : channels) {\n            try {\n                if (channel.isConnected()) {\n                    channel.send(request, getUrl().getParameter(Constants.CHANNEL_READONLYEVENT_SENT_KEY, true));\n                }\n            } catch (RemotingException e) {\n                if (closed.get() && e.getCause() instanceof ClosedChannelException) {\n                    // ignore ClosedChannelException which means the connection has been closed.\n                    continue;\n                }\n                logger.warn(TRANSPORT_FAILED_RESPONSE, \"\", \"\", \"send cannot write message error.\", e);\n            }\n        }\n    }\n\n    private void doClose() {\n        cancelCloseTask();\n    }\n\n    private void cancelCloseTask() {\n        if (closeTimer != null) {\n            closeTimer.cancel();\n        }\n    }\n\n    @Override\n    public Collection<ExchangeChannel> getExchangeChannels() {\n        Collection<ExchangeChannel> exchangeChannels = new ArrayList<>();\n        Collection<Channel> channels = server.getChannels();\n        if (CollectionUtils.isNotEmpty(channels)) {\n            for (Channel channel : channels) {\n                exchangeChannels.add(HeaderExchangeChannel.getOrAddChannel(channel));\n            }\n        }\n        return exchangeChannels;\n    }\n\n    @Override\n    public ExchangeChannel getExchangeChannel(InetSocketAddress remoteAddress) {\n        Channel channel = server.getChannel(remoteAddress);\n        return HeaderExchangeChannel.getOrAddChannel(channel);\n    }\n\n    @Override\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public Collection<Channel> getChannels() {\n        return (Collection) getExchangeChannels();\n    }\n\n    @Override\n    public Channel getChannel(InetSocketAddress remoteAddress) {\n        return getExchangeChannel(remoteAddress);\n    }\n\n    @Override\n    public boolean isBound() {\n        return server.isBound();\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return server.getLocalAddress();\n    }\n\n    @Override\n    public URL getUrl() {\n        return server.getUrl();\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        return server.getChannelHandler();\n    }\n\n    @Override\n    public void reset(URL url) {\n        server.reset(url);\n        try {\n            int currCloseTimeout = getCloseTimeout(getUrl());\n            int closeTimeout = getCloseTimeout(url);\n            if (closeTimeout != currCloseTimeout) {\n                cancelCloseTask();\n                startIdleCheckTask(url);\n            }\n        } catch (Throwable t) {\n            logger.error(INTERNAL_ERROR, \"unknown error in remoting module\", \"\", t.getMessage(), t);\n        }\n    }\n\n    @Override\n    @Deprecated\n    public void reset(org.apache.dubbo.common.Parameters parameters) {\n        reset(getUrl().addParameters(parameters.getParameters()));\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        if (closed.get()) {\n            throw new RemotingException(\n                    this.getLocalAddress(),\n                    null,\n                    \"Failed to send message \" + message + \", cause: The server \" + getLocalAddress() + \" is closed!\");\n        }\n        server.send(message);\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        if (closed.get()) {\n            throw new RemotingException(\n                    this.getLocalAddress(),\n                    null,\n                    \"Failed to send message \" + message + \", cause: The server \" + getLocalAddress() + \" is closed!\");\n        }\n        server.send(message, sent);\n    }\n\n    /**\n     * Each interval cannot be less than 1000ms.\n     */\n    private long calculateLeastDuration(int time) {\n        if (time / HEARTBEAT_CHECK_TICK <= 0) {\n            return LEAST_HEARTBEAT_DURATION;\n        } else {\n            return time / HEARTBEAT_CHECK_TICK;\n        }\n    }\n\n    private void startIdleCheckTask(URL url) {\n        if (!server.canHandleIdle()) {\n            AbstractTimerTask.ChannelProvider cp =\n                    () -> unmodifiableCollection(HeaderExchangeServer.this.getChannels());\n            int closeTimeout = getCloseTimeout(url);\n            long closeTimeoutTick = calculateLeastDuration(closeTimeout);\n            this.closeTimer = new CloseTimerTask(cp, IDLE_CHECK_TIMER.get(), closeTimeoutTick, closeTimeout);\n        }\n    }\n\n    @Override\n    public void fireChannelEvent(ChannelEvent event) {\n        if (event instanceof ReadOnlyEvent) {\n            sendChannelEvent(READONLY_EVENT);\n        } else if (event instanceof WriteableEvent) {\n            sendChannelEvent(WRITEABLE_EVENT);\n        } else {\n            // For other events, delegate to the underlying server\n            server.fireChannelEvent(event);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchanger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.Transporters;\nimport org.apache.dubbo.remoting.exchange.ExchangeClient;\nimport org.apache.dubbo.remoting.exchange.ExchangeHandler;\nimport org.apache.dubbo.remoting.exchange.ExchangeServer;\nimport org.apache.dubbo.remoting.exchange.Exchanger;\nimport org.apache.dubbo.remoting.exchange.PortUnificationExchanger;\nimport org.apache.dubbo.remoting.transport.DecodeHandler;\n\nimport static org.apache.dubbo.remoting.Constants.IS_PU_SERVER_KEY;\n\n/**\n * DefaultMessenger\n *\n *\n */\npublic class HeaderExchanger implements Exchanger {\n\n    public static final String NAME = \"header\";\n\n    @Override\n    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {\n        return new HeaderExchangeClient(\n                Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);\n    }\n\n    @Override\n    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {\n        ExchangeServer server;\n        boolean isPuServerKey = url.getParameter(IS_PU_SERVER_KEY, false);\n        if (isPuServerKey) {\n            server = new HeaderExchangeServer(\n                    PortUnificationExchanger.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));\n        } else {\n            server = new HeaderExchangeServer(\n                    Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));\n        }\n        return server;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeartbeatHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.HeartBeatRequest;\nimport org.apache.dubbo.remoting.exchange.HeartBeatResponse;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\nimport org.apache.dubbo.remoting.transport.AbstractChannelHandlerDelegate;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.HEARTBEAT_EVENT;\n\npublic class HeartbeatHandler extends AbstractChannelHandlerDelegate {\n\n    private static final Logger logger = LoggerFactory.getLogger(HeartbeatHandler.class);\n\n    public static final String KEY_READ_TIMESTAMP = \"READ_TIMESTAMP\";\n\n    public static final String KEY_WRITE_TIMESTAMP = \"WRITE_TIMESTAMP\";\n\n    public HeartbeatHandler(ChannelHandler handler) {\n        super(handler);\n    }\n\n    @Override\n    public void connected(Channel channel) throws RemotingException {\n        setReadTimestamp(channel);\n        setWriteTimestamp(channel);\n        handler.connected(channel);\n    }\n\n    @Override\n    public void disconnected(Channel channel) throws RemotingException {\n        clearReadTimestamp(channel);\n        clearWriteTimestamp(channel);\n        handler.disconnected(channel);\n    }\n\n    @Override\n    public void sent(Channel channel, Object message) throws RemotingException {\n        setWriteTimestamp(channel);\n        handler.sent(channel, message);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        setReadTimestamp(channel);\n        if (isHeartbeatRequest(message)) {\n            HeartBeatRequest req = (HeartBeatRequest) message;\n            if (req.isTwoWay()) {\n                HeartBeatResponse res;\n                res = new HeartBeatResponse(req.getId(), req.getVersion());\n                res.setEvent(HEARTBEAT_EVENT);\n                res.setProto(req.getProto());\n                channel.send(res);\n                if (logger.isDebugEnabled()) {\n                    int heartbeat = channel.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);\n                    logger.debug(\"Received heartbeat from remote channel \" + channel.getRemoteAddress()\n                            + \", cause: The channel has no data-transmission exceeds a heartbeat period\"\n                            + (heartbeat > 0 ? \": \" + heartbeat + \"ms\" : \"\"));\n                }\n            }\n            return;\n        }\n        if (isHeartbeatResponse(message)) {\n            if (logger.isDebugEnabled()) {\n                logger.debug(\"Receive heartbeat response in thread \"\n                        + Thread.currentThread().getName());\n            }\n            return;\n        }\n        handler.received(channel, message);\n    }\n\n    private void setReadTimestamp(Channel channel) {\n        channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());\n    }\n\n    private void setWriteTimestamp(Channel channel) {\n        channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis());\n    }\n\n    private void clearReadTimestamp(Channel channel) {\n        channel.removeAttribute(KEY_READ_TIMESTAMP);\n    }\n\n    private void clearWriteTimestamp(Channel channel) {\n        channel.removeAttribute(KEY_WRITE_TIMESTAMP);\n    }\n\n    private boolean isHeartbeatRequest(Object message) {\n        return message instanceof HeartBeatRequest && ((Request) message).isHeartbeat();\n    }\n\n    private boolean isHeartbeatResponse(Object message) {\n        return message instanceof Response && ((Response) message).isHeartbeat();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeartbeatTimerTask.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.exchange.Request;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.HEARTBEAT_EVENT;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RESPONSE;\n\npublic class HeartbeatTimerTask extends AbstractTimerTask {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(HeartbeatTimerTask.class);\n\n    private final int heartbeat;\n\n    HeartbeatTimerTask(\n            ChannelProvider channelProvider, HashedWheelTimer hashedWheelTimer, Long heartbeatTick, int heartbeat) {\n        super(channelProvider, hashedWheelTimer, heartbeatTick);\n        this.heartbeat = heartbeat;\n        start();\n    }\n\n    @Override\n    protected void doTask(Channel channel) {\n        try {\n            Long lastRead = lastRead(channel);\n            Long lastWrite = lastWrite(channel);\n            Long now = now();\n            if ((lastRead != null && now - lastRead > heartbeat)\n                    || (lastWrite != null && now - lastWrite > heartbeat)) {\n                Request req = new Request();\n                req.setVersion(Version.getProtocolVersion());\n                req.setTwoWay(true);\n                req.setEvent(HEARTBEAT_EVENT);\n                channel.send(req);\n                if (logger.isDebugEnabled()) {\n                    logger.debug(\"Send heartbeat to remote channel \" + channel.getRemoteAddress()\n                            + \", cause: The channel has no data-transmission exceeds a heartbeat period: \"\n                            + heartbeat + \"ms\");\n                }\n            }\n        } catch (Throwable t) {\n            logger.warn(\n                    TRANSPORT_FAILED_RESPONSE,\n                    \"\",\n                    \"\",\n                    \"Exception when heartbeat to remote channel \" + channel.getRemoteAddress(),\n                    t);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/ReconnectTimerTask.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Client;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RECONNECT;\n\npublic class ReconnectTimerTask extends AbstractTimerTask {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ReconnectTimerTask.class);\n\n    private final int idleTimeout;\n\n    public ReconnectTimerTask(\n            ChannelProvider channelProvider,\n            HashedWheelTimer hashedWheelTimer,\n            Long heartbeatTimeoutTick,\n            int idleTimeout) {\n        super(channelProvider, hashedWheelTimer, heartbeatTimeoutTick);\n        this.idleTimeout = idleTimeout;\n        start();\n    }\n\n    @Override\n    protected void doTask(Channel channel) {\n        try {\n            Long lastRead = lastRead(channel);\n            Long now = now();\n\n            // Rely on reconnect timer to reconnect when AbstractClient.doConnect fails to init the connection\n            if (!channel.isConnected()) {\n                try {\n                    logger.info(\"Initial connection to \" + channel);\n                    ((Client) channel).reconnect();\n                } catch (Exception e) {\n                    logger.error(TRANSPORT_FAILED_RECONNECT, \"\", \"\", \"Fail to connect to\" + channel, e);\n                }\n                // check pong at client\n            } else if (lastRead != null && now - lastRead > idleTimeout) {\n                logger.warn(\n                        TRANSPORT_FAILED_RECONNECT,\n                        \"\",\n                        \"\",\n                        \"Reconnect to channel \" + channel + \", because heartbeat read idle time out: \" + idleTimeout\n                                + \"ms\");\n                try {\n                    ((Client) channel).reconnect();\n                } catch (Exception e) {\n                    logger.error(TRANSPORT_FAILED_RECONNECT, \"\", \"\", channel + \"reconnect failed during idle time.\", e);\n                }\n            }\n        } catch (Throwable t) {\n            logger.warn(\n                    INTERNAL_ERROR,\n                    \"unknown error in remoting module\",\n                    \"\",\n                    \"Exception when reconnect to remote channel \" + channel.getRemoteAddress(),\n                    t);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/TelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface TelnetHandler {\n\n    /**\n     * telnet.\n     *\n     * @param channel\n     * @param message\n     */\n    String telnet(Channel channel, String message) throws RemotingException;\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/codec/TelnetCodec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.codec;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffer;\nimport org.apache.dubbo.remoting.transport.codec.TransportCodec;\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_UNSUPPORTED_CHARSET;\nimport static org.apache.dubbo.remoting.Constants.CHARSET_KEY;\nimport static org.apache.dubbo.remoting.Constants.DEFAULT_CHARSET;\n\npublic class TelnetCodec extends TransportCodec {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(TelnetCodec.class);\n\n    private static final String HISTORY_LIST_KEY = \"telnet.history.list\";\n\n    private static final String HISTORY_INDEX_KEY = \"telnet.history.index\";\n\n    private static final byte[] UP = new byte[] {27, 91, 65};\n\n    private static final byte[] DOWN = new byte[] {27, 91, 66};\n\n    private static final List<?> ENTER =\n            Arrays.asList(new byte[] {'\\r', '\\n'} /* Windows Enter */, new byte[] {'\\n'} /* Linux Enter */);\n\n    private static final List<?> EXIT = Arrays.asList(\n            new byte[] {3} /* Windows Ctrl+C */,\n            new byte[] {-1, -12, -1, -3, 6} /* Linux Ctrl+C */,\n            new byte[] {-1, -19, -1, -3, 6} /* Linux Pause */);\n\n    private static Charset getCharset(Channel channel) {\n        if (channel != null) {\n            Object attribute = channel.getAttribute(CHARSET_KEY);\n            if (attribute instanceof String) {\n                try {\n                    return Charset.forName((String) attribute);\n                } catch (Throwable t) {\n                    logger.warn(TRANSPORT_UNSUPPORTED_CHARSET, \"\", \"\", t.getMessage(), t);\n                }\n            } else if (attribute instanceof Charset) {\n                return (Charset) attribute;\n            }\n            URL url = channel.getUrl();\n            if (url != null) {\n                String parameter = url.getParameter(CHARSET_KEY);\n                if (StringUtils.isNotEmpty(parameter)) {\n                    try {\n                        return Charset.forName(parameter);\n                    } catch (Throwable t) {\n                        logger.warn(TRANSPORT_UNSUPPORTED_CHARSET, \"\", \"\", t.getMessage(), t);\n                    }\n                }\n            }\n        }\n        try {\n            return Charset.forName(DEFAULT_CHARSET);\n        } catch (Throwable t) {\n            logger.warn(TRANSPORT_UNSUPPORTED_CHARSET, \"\", \"\", t.getMessage(), t);\n        }\n        return Charset.defaultCharset();\n    }\n\n    private static String toString(byte[] message, Charset charset) throws UnsupportedEncodingException {\n        byte[] copy = new byte[message.length];\n        int index = 0;\n        for (int i = 0; i < message.length; i++) {\n            byte b = message[i];\n            if (b == '\\b') { // backspace\n                if (index > 0) {\n                    index--;\n                }\n                if (i > 2 && message[i - 2] < 0) { // double byte char\n                    if (index > 0) {\n                        index--;\n                    }\n                }\n            } else if (b == 27) { // escape\n                if (i < message.length - 4 && message[i + 4] == 126) {\n                    i = i + 4;\n                } else if (i < message.length - 3 && message[i + 3] == 126) {\n                    i = i + 3;\n                } else if (i < message.length - 2) {\n                    i = i + 2;\n                }\n            } else if (b == -1\n                    && i < message.length - 2\n                    && (message[i + 1] == -3 || message[i + 1] == -5)) { // handshake\n                i = i + 2;\n            } else {\n                copy[index++] = message[i];\n            }\n        }\n        if (index == 0) {\n            return \"\";\n        }\n        return new String(copy, 0, index, charset.name()).trim();\n    }\n\n    private static boolean isEquals(byte[] message, byte[] command) throws IOException {\n        return message.length == command.length && endsWith(message, command);\n    }\n\n    private static boolean endsWith(byte[] message, byte[] command) throws IOException {\n        if (message.length < command.length) {\n            return false;\n        }\n        int offset = message.length - command.length;\n        for (int i = command.length - 1; i >= 0; i--) {\n            if (message[offset + i] != command[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public void encode(Channel channel, ChannelBuffer buffer, Object message) throws IOException {\n        if (message instanceof String) {\n            if (isClientSide(channel)) {\n                message = message + \"\\r\\n\";\n            }\n            byte[] msgData = ((String) message).getBytes(getCharset(channel).name());\n            buffer.writeBytes(msgData);\n        } else {\n            super.encode(channel, buffer, message);\n        }\n    }\n\n    @Override\n    public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {\n        int readable = buffer.readableBytes();\n        byte[] message = new byte[readable];\n        buffer.readBytes(message);\n        return decode(channel, buffer, readable, message);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] message) throws IOException {\n        if (isClientSide(channel)) {\n            return toString(message, getCharset(channel));\n        }\n        checkPayload(channel, readable);\n        if (message == null || message.length == 0) {\n            return DecodeResult.NEED_MORE_INPUT;\n        }\n\n        if (message[message.length - 1] == '\\b') { // Windows backspace echo\n            try {\n                boolean isDoubleChar = message.length >= 3 && message[message.length - 3] < 0; // double byte char\n                channel.send(new String(\n                        isDoubleChar ? new byte[] {32, 32, 8, 8} : new byte[] {32, 8},\n                        getCharset(channel).name()));\n            } catch (RemotingException e) {\n                throw new IOException(StringUtils.toString(e));\n            }\n            return DecodeResult.NEED_MORE_INPUT;\n        }\n\n        for (Object command : EXIT) {\n            if (isEquals(message, (byte[]) command)) {\n                if (logger.isInfoEnabled()) {\n                    logger.info(new Exception(\n                            \"Close channel \" + channel + \" on exit command: \" + Arrays.toString((byte[]) command)));\n                }\n                channel.close();\n                return null;\n            }\n        }\n\n        boolean up = endsWith(message, UP);\n        boolean down = endsWith(message, DOWN);\n        if (up || down) {\n            LinkedList<String> history = (LinkedList<String>) channel.getAttribute(HISTORY_LIST_KEY);\n            if (CollectionUtils.isEmpty(history)) {\n                return DecodeResult.NEED_MORE_INPUT;\n            }\n            Integer index = (Integer) channel.getAttribute(HISTORY_INDEX_KEY);\n            Integer old = index;\n            if (index == null) {\n                index = history.size() - 1;\n            } else {\n                if (up) {\n                    index = index - 1;\n                    if (index < 0) {\n                        index = history.size() - 1;\n                    }\n                } else {\n                    index = index + 1;\n                    if (index > history.size() - 1) {\n                        index = 0;\n                    }\n                }\n            }\n            if (old == null || !old.equals(index)) {\n                channel.setAttribute(HISTORY_INDEX_KEY, index);\n                String value = history.get(index);\n                if (old != null && old >= 0 && old < history.size()) {\n                    String ov = history.get(old);\n                    StringBuilder buf = new StringBuilder();\n                    for (int i = 0; i < ov.length(); i++) {\n                        buf.append('\\b');\n                    }\n                    for (int i = 0; i < ov.length(); i++) {\n                        buf.append(' ');\n                    }\n                    for (int i = 0; i < ov.length(); i++) {\n                        buf.append('\\b');\n                    }\n                    value = buf + value;\n                }\n                try {\n                    channel.send(value);\n                } catch (RemotingException e) {\n                    throw new IOException(StringUtils.toString(e));\n                }\n            }\n            return DecodeResult.NEED_MORE_INPUT;\n        }\n        for (Object command : EXIT) {\n            if (isEquals(message, (byte[]) command)) {\n                if (logger.isInfoEnabled()) {\n                    logger.info(new Exception(\"Close channel \" + channel + \" on exit command \" + command));\n                }\n                channel.close();\n                return null;\n            }\n        }\n        byte[] enter = null;\n        for (Object command : ENTER) {\n            if (endsWith(message, (byte[]) command)) {\n                enter = (byte[]) command;\n                break;\n            }\n        }\n        if (enter == null) {\n            return DecodeResult.NEED_MORE_INPUT;\n        }\n        LinkedList<String> history = (LinkedList<String>) channel.getAttribute(HISTORY_LIST_KEY);\n        Integer index = (Integer) channel.getAttribute(HISTORY_INDEX_KEY);\n        channel.removeAttribute(HISTORY_INDEX_KEY);\n        if (CollectionUtils.isNotEmpty(history) && index != null && index >= 0 && index < history.size()) {\n            String value = history.get(index);\n            if (value != null) {\n                byte[] b1 = value.getBytes(StandardCharsets.UTF_8);\n                byte[] b2 = new byte[b1.length + message.length];\n                System.arraycopy(b1, 0, b2, 0, b1.length);\n                System.arraycopy(message, 0, b2, b1.length, message.length);\n                message = b2;\n            }\n        }\n        String result = toString(message, getCharset(channel));\n        if (result.trim().length() > 0) {\n            if (history == null) {\n                history = new LinkedList<>();\n                channel.setAttribute(HISTORY_LIST_KEY, history);\n            }\n            if (history.isEmpty()) {\n                history.addLast(result);\n            } else if (!result.equals(history.getLast())) {\n                history.remove(result);\n                history.addLast(result);\n                if (history.size() > 10) {\n                    history.removeFirst();\n                }\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/Help.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Help\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE})\npublic @interface Help {\n\n    String parameter() default \"\";\n\n    String summary();\n\n    String detail() default \"\";\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/TelnetHandlerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.remoting.transport.ChannelHandlerAdapter;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.remoting.Constants.TELNET_KEY;\n\npublic class TelnetHandlerAdapter extends ChannelHandlerAdapter implements TelnetHandler {\n\n    private final ExtensionLoader<TelnetHandler> extensionLoader;\n\n    public TelnetHandlerAdapter(FrameworkModel frameworkModel) {\n        extensionLoader = frameworkModel.getExtensionLoader(TelnetHandler.class);\n    }\n\n    @Override\n    public String telnet(Channel channel, String message) throws RemotingException {\n        String prompt = channel.getUrl().getParameterAndDecoded(Constants.PROMPT_KEY, Constants.DEFAULT_PROMPT);\n        boolean noprompt = message.contains(\"--no-prompt\");\n        message = message.replace(\"--no-prompt\", \"\");\n        StringBuilder buf = new StringBuilder();\n        message = message.trim();\n        String command;\n        if (message.length() > 0) {\n            int i = message.indexOf(' ');\n            if (i > 0) {\n                command = message.substring(0, i).trim();\n                message = message.substring(i + 1).trim();\n            } else {\n                command = message;\n                message = \"\";\n            }\n        } else {\n            command = \"\";\n        }\n        if (command.length() > 0) {\n            if (extensionLoader.hasExtension(command)) {\n                if (commandEnabled(channel.getUrl(), command)) {\n                    try {\n                        String result = extensionLoader.getExtension(command).telnet(channel, message);\n                        if (result == null) {\n                            return null;\n                        }\n                        buf.append(result);\n                    } catch (Throwable t) {\n                        buf.append(t.getMessage());\n                    }\n                } else {\n                    buf.append(\"Command: \");\n                    buf.append(command);\n                    buf.append(\n                            \" disabled for security reasons, please enable support by listing the commands through 'telnet'\");\n                }\n            } else {\n                buf.append(\"Unsupported command: \");\n                buf.append(command);\n            }\n        }\n        if (buf.length() > 0) {\n            buf.append(\"\\r\\n\");\n        }\n        if (StringUtils.isNotEmpty(prompt) && !noprompt) {\n            buf.append(prompt);\n        }\n        return buf.toString();\n    }\n\n    private boolean commandEnabled(URL url, String command) {\n        String supportCommands = url.getParameter(TELNET_KEY);\n        if (StringUtils.isEmpty(supportCommands)) {\n            return false;\n        }\n        String[] commands = COMMA_SPLIT_PATTERN.split(supportCommands);\n        for (String c : commands) {\n            if (command.equals(c)) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/TelnetUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class TelnetUtils {\n\n    public static String toList(List<List<String>> table) {\n        int[] widths = new int[table.get(0).size()];\n        for (int j = 0; j < widths.length; j++) {\n            for (List<String> row : table) {\n                widths[j] = Math.max(widths[j], row.get(j).length());\n            }\n        }\n        StringBuilder buf = new StringBuilder();\n        for (List<String> row : table) {\n            if (buf.length() > 0) {\n                buf.append(\"\\r\\n\");\n            }\n            for (int j = 0; j < widths.length; j++) {\n                if (j > 0) {\n                    buf.append(\" - \");\n                }\n                String value = row.get(j);\n                buf.append(value);\n                if (j < widths.length - 1) {\n                    int pad = widths[j] - value.length();\n                    if (pad > 0) {\n                        for (int k = 0; k < pad; k++) {\n                            buf.append(' ');\n                        }\n                    }\n                }\n            }\n        }\n        return buf.toString();\n    }\n\n    public static String toTable(String[] header, List<List<String>> table) {\n        return toTable(Arrays.asList(header), table);\n    }\n\n    public static String toTable(List<String> header, List<List<String>> table) {\n        int totalWidth = 0;\n        int[] widths = new int[header.size()];\n        int maxwidth = 70;\n        int maxcountbefore = 0;\n        for (int j = 0; j < widths.length; j++) {\n            widths[j] = Math.max(widths[j], header.get(j).length());\n        }\n        for (List<String> row : table) {\n            int countbefore = 0;\n            for (int j = 0; j < widths.length; j++) {\n                widths[j] = Math.max(widths[j], row.get(j).length());\n                totalWidth = (totalWidth + widths[j]) > maxwidth ? maxwidth : (totalWidth + widths[j]);\n                if (j < widths.length - 1) {\n                    countbefore = countbefore + widths[j];\n                }\n            }\n            maxcountbefore = Math.max(countbefore, maxcountbefore);\n        }\n        widths[widths.length - 1] = Math.min(widths[widths.length - 1], maxwidth - maxcountbefore);\n        StringBuilder buf = new StringBuilder();\n        // line\n        buf.append('+');\n        for (int j = 0; j < widths.length; j++) {\n            for (int k = 0; k < widths[j] + 2; k++) {\n                buf.append('-');\n            }\n            buf.append('+');\n        }\n        buf.append(\"\\r\\n\");\n        // header\n        buf.append('|');\n        for (int j = 0; j < widths.length; j++) {\n            String cell = header.get(j);\n            buf.append(' ');\n            buf.append(cell);\n            int pad = widths[j] - cell.length();\n            if (pad > 0) {\n                for (int k = 0; k < pad; k++) {\n                    buf.append(' ');\n                }\n            }\n            buf.append(\" |\");\n        }\n        buf.append(\"\\r\\n\");\n        // line\n        buf.append('+');\n        for (int j = 0; j < widths.length; j++) {\n            for (int k = 0; k < widths[j] + 2; k++) {\n                buf.append('-');\n            }\n            buf.append('+');\n        }\n        buf.append(\"\\r\\n\");\n        // content\n        for (List<String> row : table) {\n            StringBuilder rowbuf = new StringBuilder();\n            rowbuf.append('|');\n            for (int j = 0; j < widths.length; j++) {\n                String cell = row.get(j);\n                rowbuf.append(' ');\n                int remaining = cell.length();\n                while (remaining > 0) {\n\n                    if (rowbuf.length() >= totalWidth) {\n                        buf.append(rowbuf.toString());\n                        rowbuf = new StringBuilder();\n                        //                        for(int m = 0;m < maxcountbefore && maxcountbefore < totalWidth ;\n                        // m++){\n                        //                            rowbuf.append(\" \");\n                        //                        }\n                    }\n\n                    rowbuf.append(cell, cell.length() - remaining, cell.length() - remaining + 1);\n                    remaining--;\n                }\n                int pad = widths[j] - cell.length();\n                if (pad > 0) {\n                    for (int k = 0; k < pad; k++) {\n                        rowbuf.append(' ');\n                    }\n                }\n                rowbuf.append(\" |\");\n            }\n            buf.append(rowbuf).append(\"\\r\\n\");\n        }\n        // line\n        buf.append('+');\n        for (int j = 0; j < widths.length; j++) {\n            for (int k = 0; k < widths[j] + 2; k++) {\n                buf.append('-');\n            }\n            buf.append('+');\n        }\n        buf.append(\"\\r\\n\");\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/ClearTelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support.command;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.remoting.telnet.support.Help;\n\n@Activate\n@Help(parameter = \"[lines]\", summary = \"Clear screen.\", detail = \"Clear screen.\")\npublic class ClearTelnetHandler implements TelnetHandler {\n    private static final int MAX_LINES = 1000;\n\n    @Override\n    public String telnet(Channel channel, String message) {\n        int lines = 100;\n        if (message.length() > 0) {\n            if (!StringUtils.isNumber(message)) {\n                return \"Illegal lines \" + message + \", must be integer.\";\n            }\n            lines = Math.min(MAX_LINES, Integer.parseInt(message));\n        }\n        StringBuilder buf = new StringBuilder();\n        for (int i = 0; i < lines; i++) {\n            buf.append(\"\\r\\n\");\n        }\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/ExitTelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support.command;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.remoting.telnet.support.Help;\n\n@Activate\n@Help(summary = \"Exit the telnet.\", detail = \"Exit the telnet.\")\npublic class ExitTelnetHandler implements TelnetHandler {\n\n    @Override\n    public String telnet(Channel channel, String message) {\n        channel.close();\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/HelpTelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support.command;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.remoting.telnet.support.Help;\nimport org.apache.dubbo.remoting.telnet.support.TelnetUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.WeakHashMap;\n\n@Activate\n@Help(parameter = \"[command]\", summary = \"Show help.\", detail = \"Show help.\")\npublic class HelpTelnetHandler implements TelnetHandler {\n\n    private final ExtensionLoader<TelnetHandler> extensionLoader;\n\n    private static final String MAIN_HELP = \"mainHelp\";\n\n    private static Map<String, String> processedTable = new WeakHashMap<>();\n\n    public HelpTelnetHandler(FrameworkModel frameworkModel) {\n        extensionLoader = frameworkModel.getExtensionLoader(TelnetHandler.class);\n    }\n\n    @Override\n    public String telnet(Channel channel, String message) {\n        if (message.length() > 0) {\n            return processedTable.computeIfAbsent(message, commandName -> generateForOneCommand(commandName));\n        } else {\n            return processedTable.computeIfAbsent(MAIN_HELP, commandName -> generateForAllCommand(channel));\n        }\n    }\n\n    private String generateForOneCommand(String message) {\n        if (!extensionLoader.hasExtension(message)) {\n            return \"No such command \" + message;\n        }\n        TelnetHandler handler = extensionLoader.getExtension(message);\n        Help help = handler.getClass().getAnnotation(Help.class);\n        StringBuilder buf = new StringBuilder();\n        buf.append(\"Command:\\r\\n    \");\n        buf.append(message + \" \" + help.parameter().replace(\"\\r\\n\", \" \").replace(\"\\n\", \" \"));\n        buf.append(\"\\r\\nSummary:\\r\\n    \");\n        buf.append(help.summary().replace(\"\\r\\n\", \" \").replace(\"\\n\", \" \"));\n        buf.append(\"\\r\\nDetail:\\r\\n    \");\n        buf.append(help.detail().replace(\"\\r\\n\", \"    \\r\\n\").replace(\"\\n\", \"    \\n\"));\n        return buf.toString();\n    }\n\n    private String generateForAllCommand(Channel channel) {\n        List<List<String>> table = new ArrayList<>();\n        List<TelnetHandler> handlers = extensionLoader.getActivateExtension(channel.getUrl(), \"telnet\");\n        if (CollectionUtils.isNotEmpty(handlers)) {\n            for (TelnetHandler handler : handlers) {\n                Help help = handler.getClass().getAnnotation(Help.class);\n                List<String> row = new ArrayList<>();\n                String parameter = \" \" + extensionLoader.getExtensionName(handler) + \" \"\n                        + (help != null ? help.parameter().replace(\"\\r\\n\", \" \").replace(\"\\n\", \" \") : \"\");\n                row.add(parameter.length() > 55 ? parameter.substring(0, 55) + \"...\" : parameter);\n                String summary =\n                        help != null ? help.summary().replace(\"\\r\\n\", \" \").replace(\"\\n\", \" \") : \"\";\n                row.add(summary.length() > 55 ? summary.substring(0, 55) + \"...\" : summary);\n                table.add(row);\n            }\n        }\n        return \"Please input \\\"help [command]\\\" show detail.\\r\\n\" + TelnetUtils.toList(table);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support.command;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.remoting.telnet.support.Help;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n@Activate\n@Help(parameter = \"level\", summary = \"Change log level or show log \", detail = \"Change log level or show log\")\npublic class LogTelnetHandler implements TelnetHandler {\n\n    public static final String SERVICE_KEY = \"telnet.log\";\n\n    @Override\n    public String telnet(Channel channel, String message) {\n        long size = 0;\n        File file = LoggerFactory.getFile();\n        StringBuilder buf = new StringBuilder();\n        if (message == null || message.trim().length() == 0) {\n            buf.append(\"EXAMPLE: log error / log 100\");\n        } else {\n            String[] str = message.split(\" \");\n            if (!StringUtils.isNumber(str[0])) {\n                LoggerFactory.setLevel(Level.valueOf(message.toUpperCase()));\n            } else {\n                int showLogLength = Integer.parseInt(str[0]);\n\n                if (file != null && file.exists()) {\n                    try {\n                        try (FileInputStream fis = new FileInputStream(file)) {\n                            try (FileChannel filechannel = fis.getChannel()) {\n                                size = filechannel.size();\n                                ByteBuffer bb;\n                                if (size <= showLogLength) {\n                                    bb = ByteBuffer.allocate((int) size);\n                                    filechannel.read(bb, 0);\n                                } else {\n                                    int pos = (int) (size - showLogLength);\n                                    bb = ByteBuffer.allocate(showLogLength);\n                                    filechannel.read(bb, pos);\n                                }\n                                bb.flip();\n                                String content = new String(bb.array())\n                                        .replace(\"<\", \"&lt;\")\n                                        .replace(\">\", \"&gt;\")\n                                        .replace(\"\\n\", \"<br/><br/>\");\n                                buf.append(\"\\r\\ncontent:\" + content);\n\n                                buf.append(\"\\r\\nmodified:\"\n                                        + (new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\")\n                                                .format(new Date(file.lastModified()))));\n                                buf.append(\"\\r\\nsize:\" + size + \"\\r\\n\");\n                            }\n                        }\n                    } catch (Exception e) {\n                        buf.append(e.getMessage());\n                    }\n                } else {\n                    size = 0;\n                    buf.append(\"\\r\\nMESSAGE: log file not exists or log appender is console .\");\n                }\n            }\n        }\n        buf.append(\"\\r\\nCURRENT LOG LEVEL:\" + LoggerFactory.getLevel())\n                .append(\"\\r\\nCURRENT LOG APPENDER:\" + (file == null ? \"console\" : file.getAbsolutePath()));\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/StatusTelnetHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support.command;\n\nimport org.apache.dubbo.common.extension.Activate;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.status.Status;\nimport org.apache.dubbo.common.status.StatusChecker;\nimport org.apache.dubbo.common.status.support.StatusUtils;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.TelnetHandler;\nimport org.apache.dubbo.remoting.telnet.support.Help;\nimport org.apache.dubbo.remoting.telnet.support.TelnetUtils;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\nimport org.apache.dubbo.rpc.model.ScopeModelUtil;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;\nimport static org.apache.dubbo.config.Constants.STATUS_KEY;\n\n@Activate\n@Help(parameter = \"[-l]\", summary = \"Show status.\", detail = \"Show status.\")\npublic class StatusTelnetHandler implements TelnetHandler {\n\n    @Override\n    public String telnet(Channel channel, String message) {\n        ApplicationModel applicationModel =\n                ScopeModelUtil.getApplicationModel(channel.getUrl().getScopeModel());\n        ExtensionLoader<StatusChecker> extensionLoader = applicationModel.getExtensionLoader(StatusChecker.class);\n        if (\"-l\".equals(message)) {\n            List<StatusChecker> checkers = extensionLoader.getActivateExtension(channel.getUrl(), STATUS_KEY);\n            String[] header = new String[] {\"resource\", \"status\", \"message\"};\n            List<List<String>> table = new ArrayList<>();\n            Map<String, Status> statuses = new HashMap<>();\n            if (CollectionUtils.isNotEmpty(checkers)) {\n                for (StatusChecker checker : checkers) {\n                    String name = extensionLoader.getExtensionName(checker);\n                    Status stat;\n                    try {\n                        stat = checker.check();\n                    } catch (Throwable t) {\n                        stat = new Status(Status.Level.ERROR, t.getMessage());\n                    }\n                    statuses.put(name, stat);\n                    if (stat.getLevel() != null && stat.getLevel() != Status.Level.UNKNOWN) {\n                        List<String> row = new ArrayList<>();\n                        row.add(name);\n                        row.add(String.valueOf(stat.getLevel()));\n                        row.add(stat.getMessage() == null ? \"\" : stat.getMessage());\n                        table.add(row);\n                    }\n                }\n            }\n            Status stat = StatusUtils.getSummaryStatus(statuses);\n            List<String> row = new ArrayList<>();\n            row.add(\"summary\");\n            row.add(String.valueOf(stat.getLevel()));\n            row.add(stat.getMessage());\n            table.add(row);\n            return TelnetUtils.toTable(header, table);\n        } else if (message.length() > 0) {\n            return \"Unsupported parameter \" + message + \" for status.\";\n        }\n        String status = channel.getUrl().getParameter(\"status\");\n        Map<String, Status> statuses = new HashMap<>();\n        if (StringUtils.isNotEmpty(status)) {\n            String[] ss = COMMA_SPLIT_PATTERN.split(status);\n            for (String s : ss) {\n                StatusChecker handler = extensionLoader.getExtension(s);\n                Status stat;\n                try {\n                    stat = handler.check();\n                } catch (Throwable t) {\n                    stat = new Status(Status.Level.ERROR, t.getMessage());\n                }\n                statuses.put(s, stat);\n            }\n        }\n        Status stat = StatusUtils.getSummaryStatus(statuses);\n        return String.valueOf(stat.getLevel());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.utils.PayloadDropper;\n\npublic abstract class AbstractChannel extends AbstractPeer implements Channel {\n\n    public AbstractChannel(URL url, ChannelHandler handler) {\n        super(url, handler);\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        if (isClosed()) {\n            throw new RemotingException(\n                    this,\n                    \"Failed to send message \"\n                            + (message == null ? \"\" : message.getClass().getName()) + \":\"\n                            + PayloadDropper.getRequestWithoutData(message)\n                            + \", cause: Channel closed. channel: \" + getLocalAddress() + \" -> \" + getRemoteAddress());\n        }\n    }\n\n    @Override\n    public String toString() {\n        return getLocalAddress() + \" -> \" + getRemoteAddress();\n    }\n\n    @Override\n    protected void setUrl(URL url) {\n        super.setUrl(url);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractChannelHandlerDelegate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\n\npublic abstract class AbstractChannelHandlerDelegate implements ChannelHandlerDelegate {\n\n    protected ChannelHandler handler;\n\n    protected AbstractChannelHandlerDelegate(ChannelHandler handler) {\n        Assert.notNull(handler, \"handler == null\");\n        this.handler = handler;\n    }\n\n    @Override\n    public ChannelHandler getHandler() {\n        if (handler instanceof ChannelHandlerDelegate) {\n            return ((ChannelHandlerDelegate) handler).getHandler();\n        }\n        return handler;\n    }\n\n    @Override\n    public void connected(Channel channel) throws RemotingException {\n        handler.connected(channel);\n    }\n\n    @Override\n    public void disconnected(Channel channel) throws RemotingException {\n        handler.disconnected(channel);\n    }\n\n    @Override\n    public void sent(Channel channel, Object message) throws RemotingException {\n        handler.sent(channel, message);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        handler.received(channel, message);\n    }\n\n    @Override\n    public void caught(Channel channel, Throwable exception) throws RemotingException {\n        handler.caught(channel, exception);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Client;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelHandlers;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.net.InetSocketAddress;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CLIENT_THREADPOOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.LAZY_CONNECT_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CLOSE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CONNECT_PROVIDER;\nimport static org.apache.dubbo.config.Constants.CLIENT_THREAD_POOL_NAME;\nimport static org.apache.dubbo.remoting.Constants.HEARTBEAT_CHECK_TICK;\nimport static org.apache.dubbo.remoting.Constants.LEAST_HEARTBEAT_DURATION;\nimport static org.apache.dubbo.remoting.Constants.LEAST_RECONNECT_DURATION;\nimport static org.apache.dubbo.remoting.Constants.LEAST_RECONNECT_DURATION_KEY;\nimport static org.apache.dubbo.remoting.utils.UrlUtils.getIdleTimeout;\n\npublic abstract class AbstractClient extends AbstractEndpoint implements Client {\n\n    private Lock connectLock;\n\n    private final boolean needReconnect;\n\n    private final FrameworkModel frameworkModel;\n\n    protected volatile ExecutorService executor;\n\n    protected volatile ScheduledExecutorService connectivityExecutor;\n\n    protected long reconnectDuration;\n\n    public AbstractClient(URL url, ChannelHandler handler) throws RemotingException {\n        super(url, handler);\n\n        // initialize connectLock before calling connect()\n        connectLock = new ReentrantLock();\n\n        // set default needReconnect true when channel is not connected\n        needReconnect = url.getParameter(Constants.SEND_RECONNECT_KEY, true);\n\n        frameworkModel = url.getOrDefaultFrameworkModel();\n\n        initExecutor(url);\n\n        reconnectDuration = getReconnectDuration(url);\n\n        try {\n            doOpen();\n        } catch (Throwable t) {\n            close();\n            throw new RemotingException(\n                    url.toInetSocketAddress(),\n                    null,\n                    \"Failed to start \" + getClass().getSimpleName() + \" \" + NetUtils.getLocalAddress()\n                            + \" connect to the server \" + getRemoteAddress() + \", cause: \" + t.getMessage(),\n                    t);\n        }\n\n        try {\n            // connect.\n            connect();\n            if (logger.isInfoEnabled()) {\n                logger.info(\"Start \" + getClass().getSimpleName() + \" \" + NetUtils.getLocalAddress()\n                        + \" connect to the server \" + getRemoteAddress());\n            }\n        } catch (RemotingException t) {\n            // If lazy connect client fails to establish a connection, the client instance will still be created,\n            // and the reconnection will be initiated by ReconnectTask, so there is no need to throw an exception\n            if (url.getParameter(LAZY_CONNECT_KEY, false)) {\n                logger.warn(\n                        TRANSPORT_FAILED_CONNECT_PROVIDER,\n                        \"\",\n                        \"\",\n                        \"Failed to start \" + getClass().getSimpleName() + \" \" + NetUtils.getLocalAddress()\n                                + \" connect to the server \"\n                                + getRemoteAddress()\n                                + \" (the connection request is initiated by lazy connect client, ignore and retry later!), cause: \"\n                                + t.getMessage(),\n                        t);\n                return;\n            }\n\n            if (url.getParameter(Constants.CHECK_KEY, true)) {\n                close();\n                throw t;\n            } else {\n                logger.warn(\n                        TRANSPORT_FAILED_CONNECT_PROVIDER,\n                        \"\",\n                        \"\",\n                        \"Failed to start \" + getClass().getSimpleName() + \" \" + NetUtils.getLocalAddress()\n                                + \" connect to the server \" + getRemoteAddress()\n                                + \" (check == false, ignore and retry later!), cause: \" + t.getMessage(),\n                        t);\n            }\n        } catch (Throwable t) {\n            close();\n            throw new RemotingException(\n                    url.toInetSocketAddress(),\n                    null,\n                    \"Failed to start \" + getClass().getSimpleName() + \" \" + NetUtils.getLocalAddress()\n                            + \" connect to the server \" + getRemoteAddress() + \", cause: \" + t.getMessage(),\n                    t);\n        }\n    }\n\n    protected AbstractClient() {\n        needReconnect = false;\n        frameworkModel = null;\n    }\n\n    private void initExecutor(URL url) {\n        ExecutorRepository executorRepository = ExecutorRepository.getInstance(url.getOrDefaultApplicationModel());\n\n        /*\n         * Consumer's executor is shared globally, provider ip doesn't need to be part of the thread name.\n         *\n         * Instance of url is InstanceAddressURL, so addParameter actually adds parameters into ServiceInstance,\n         * which means params are shared among different services. Since client is shared among services this is currently not a problem.\n         */\n        url = url.addParameter(THREAD_NAME_KEY, CLIENT_THREAD_POOL_NAME)\n                .addParameterIfAbsent(THREADPOOL_KEY, DEFAULT_CLIENT_THREADPOOL);\n        executor = executorRepository.createExecutorIfAbsent(url);\n\n        connectivityExecutor = frameworkModel\n                .getBeanFactory()\n                .getBean(FrameworkExecutorRepository.class)\n                .getConnectivityScheduledExecutor();\n    }\n\n    protected static ChannelHandler wrapChannelHandler(URL url, ChannelHandler handler) {\n        return ChannelHandlers.wrap(handler, url);\n    }\n\n    public InetSocketAddress getConnectAddress() {\n        return new InetSocketAddress(NetUtils.filterLocalHost(getUrl().getHost()), getUrl().getPort());\n    }\n\n    @Override\n    public InetSocketAddress getRemoteAddress() {\n        Channel channel = getChannel();\n        if (channel == null) {\n            return getUrl().toInetSocketAddress();\n        }\n        return channel.getRemoteAddress();\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        Channel channel = getChannel();\n        if (channel == null) {\n            return InetSocketAddress.createUnresolved(NetUtils.getLocalHost(), 0);\n        }\n        return channel.getLocalAddress();\n    }\n\n    @Override\n    public boolean isConnected() {\n        Channel channel = getChannel();\n        if (channel == null) {\n            return false;\n        }\n        return channel.isConnected();\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        Channel channel = getChannel();\n        if (channel == null) {\n            return null;\n        }\n        return channel.getAttribute(key);\n    }\n\n    @Override\n    public void setAttribute(String key, Object value) {\n        Channel channel = getChannel();\n        if (channel == null) {\n            return;\n        }\n        channel.setAttribute(key, value);\n    }\n\n    @Override\n    public void removeAttribute(String key) {\n        Channel channel = getChannel();\n        if (channel == null) {\n            return;\n        }\n        channel.removeAttribute(key);\n    }\n\n    @Override\n    public boolean hasAttribute(String key) {\n        Channel channel = getChannel();\n        if (channel == null) {\n            return false;\n        }\n        return channel.hasAttribute(key);\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        if (needReconnect && !isConnected()) {\n            connect();\n        }\n        Channel channel = getChannel();\n        // TODO Can the value returned by getChannel() be null? need improvement.\n        if (channel == null || !channel.isConnected()) {\n            throw new RemotingException(this, \"message can not send, because channel is closed . url:\" + getUrl());\n        }\n        channel.send(message, sent);\n    }\n\n    protected void connect() throws RemotingException {\n        connectLock.lock();\n\n        try {\n            if (isConnected()) {\n                return;\n            }\n\n            if (isClosed() || isClosing()) {\n                logger.warn(\n                        TRANSPORT_FAILED_CONNECT_PROVIDER,\n                        \"\",\n                        \"\",\n                        \"No need to connect to server \" + getRemoteAddress() + \" from \"\n                                + getClass().getSimpleName() + \" \" + NetUtils.getLocalHost() + \" using dubbo version \"\n                                + Version.getVersion() + \", cause: client status is closed or closing.\");\n                return;\n            }\n\n            doConnect();\n\n            if (!isConnected()) {\n                throw new RemotingException(\n                        this,\n                        \"Failed to connect to server \" + getRemoteAddress() + \" from \"\n                                + getClass().getSimpleName() + \" \"\n                                + NetUtils.getLocalHost() + \" using dubbo version \" + Version.getVersion()\n                                + \", cause: Connect wait timeout: \" + getConnectTimeout() + \"ms.\");\n\n            } else {\n                if (logger.isInfoEnabled()) {\n                    logger.info(\"Successfully connect to server \" + getRemoteAddress() + \" from \"\n                            + getClass().getSimpleName() + \" \"\n                            + NetUtils.getLocalHost() + \" using dubbo version \" + Version.getVersion()\n                            + \", channel is \" + this.getChannel());\n                }\n            }\n\n        } catch (RemotingException e) {\n            throw e;\n\n        } catch (Throwable e) {\n            throw new RemotingException(\n                    this,\n                    \"Failed to connect to server \" + getRemoteAddress() + \" from \"\n                            + getClass().getSimpleName() + \" \"\n                            + NetUtils.getLocalHost() + \" using dubbo version \" + Version.getVersion()\n                            + \", cause: \" + e.getMessage(),\n                    e);\n\n        } finally {\n            connectLock.unlock();\n        }\n    }\n\n    public void disconnect() {\n        connectLock.lock();\n        try {\n            try {\n                Channel channel = getChannel();\n                if (channel != null) {\n                    channel.close();\n                }\n            } catch (Throwable e) {\n                logger.warn(TRANSPORT_FAILED_CLOSE, \"\", \"\", e.getMessage(), e);\n            }\n            try {\n                doDisConnect();\n            } catch (Throwable e) {\n                logger.warn(TRANSPORT_FAILED_CLOSE, \"\", \"\", e.getMessage(), e);\n            }\n        } finally {\n            connectLock.unlock();\n        }\n    }\n\n    private long getReconnectDuration(URL url) {\n        int idleTimeout = getIdleTimeout(url);\n        long heartbeatTimeoutTick = calculateLeastDuration(idleTimeout);\n        return calculateReconnectDuration(url, heartbeatTimeoutTick);\n    }\n\n    private long calculateLeastDuration(int time) {\n        if (time / HEARTBEAT_CHECK_TICK <= 0) {\n            return LEAST_HEARTBEAT_DURATION;\n        } else {\n            return time / HEARTBEAT_CHECK_TICK;\n        }\n    }\n\n    private long calculateReconnectDuration(URL url, long tick) {\n        long leastReconnectDuration = url.getParameter(LEAST_RECONNECT_DURATION_KEY, LEAST_RECONNECT_DURATION);\n        return Math.max(leastReconnectDuration, tick);\n    }\n\n    @Override\n    public void reconnect() throws RemotingException {\n        connectLock.lock();\n        try {\n            disconnect();\n            connect();\n        } finally {\n            connectLock.unlock();\n        }\n    }\n\n    @Override\n    public void close() {\n        if (isClosed()) {\n            logger.warn(\n                    TRANSPORT_FAILED_CONNECT_PROVIDER,\n                    \"\",\n                    \"\",\n                    \"No need to close connection to server \" + getRemoteAddress() + \" from \"\n                            + getClass().getSimpleName() + \" \" + NetUtils.getLocalHost() + \" using dubbo version \"\n                            + Version.getVersion() + \", cause: the client status is closed.\");\n            return;\n        }\n\n        connectLock.lock();\n        try {\n            if (isClosed()) {\n                logger.warn(\n                        TRANSPORT_FAILED_CONNECT_PROVIDER,\n                        \"\",\n                        \"\",\n                        \"No need to close connection to server \" + getRemoteAddress() + \" from \"\n                                + getClass().getSimpleName() + \" \" + NetUtils.getLocalHost() + \" using dubbo version \"\n                                + Version.getVersion() + \", cause: the client status is closed.\");\n                return;\n            }\n\n            try {\n                super.close();\n            } catch (Throwable e) {\n                logger.warn(TRANSPORT_FAILED_CLOSE, \"\", \"\", e.getMessage(), e);\n            }\n\n            try {\n                disconnect();\n            } catch (Throwable e) {\n                logger.warn(TRANSPORT_FAILED_CLOSE, \"\", \"\", e.getMessage(), e);\n            }\n\n            try {\n                doClose();\n            } catch (Throwable e) {\n                logger.warn(TRANSPORT_FAILED_CLOSE, \"\", \"\", e.getMessage(), e);\n            }\n\n        } finally {\n            connectLock.unlock();\n        }\n    }\n\n    @Override\n    public void close(int timeout) {\n        close();\n    }\n\n    @Override\n    public String toString() {\n        return getClass().getName() + \" [\" + getLocalAddress() + \" -> \" + getRemoteAddress() + \"]\";\n    }\n\n    /**\n     * Open client.\n     */\n    protected abstract void doOpen() throws Throwable;\n\n    /**\n     * Close client.\n     */\n    protected abstract void doClose() throws Throwable;\n\n    /**\n     * Connect to server.\n     */\n    protected abstract void doConnect() throws Throwable;\n\n    /**\n     * disConnect to server.\n     */\n    protected abstract void doDisConnect() throws Throwable;\n\n    /**\n     * Get the connected channel.\n     */\n    protected abstract Channel getChannel();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractCodec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.Serialization;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Codec2;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\nimport org.apache.dubbo.rpc.model.ScopeModelAware;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_EXCEED_PAYLOAD_LIMIT;\n\npublic abstract class AbstractCodec implements Codec2, ScopeModelAware {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractCodec.class);\n\n    private static final String CLIENT_SIDE = \"client\";\n\n    private static final String SERVER_SIDE = \"server\";\n    protected FrameworkModel frameworkModel;\n\n    @Override\n    public void setFrameworkModel(FrameworkModel frameworkModel) {\n        this.frameworkModel = frameworkModel;\n    }\n\n    protected static void checkPayload(Channel channel, long size) throws IOException {\n        int payload = getPayload(channel);\n        boolean overPayload = isOverPayload(payload, size);\n        if (overPayload) {\n            ExceedPayloadLimitException e = new ExceedPayloadLimitException(\n                    \"Data length too large: \" + size + \", max payload: \" + payload + \", channel: \" + channel);\n            logger.error(TRANSPORT_EXCEED_PAYLOAD_LIMIT, \"\", \"\", e.getMessage(), e);\n            throw e;\n        }\n    }\n\n    protected static void checkPayload(Channel channel, int payload, long size) throws IOException {\n        if (payload <= 0) {\n            payload = getPayload(channel);\n        }\n        boolean overPayload = isOverPayload(payload, size);\n        if (overPayload) {\n            ExceedPayloadLimitException e = new ExceedPayloadLimitException(\n                    \"Data length too large: \" + size + \", max payload: \" + payload + \", channel: \" + channel);\n            logger.error(TRANSPORT_EXCEED_PAYLOAD_LIMIT, \"\", \"\", e.getMessage(), e);\n            throw e;\n        }\n    }\n\n    protected static int getPayload(Channel channel) {\n        if (channel != null && channel.getUrl() != null) {\n            return channel.getUrl().getParameter(Constants.PAYLOAD_KEY, Constants.DEFAULT_PAYLOAD);\n        }\n        return Constants.DEFAULT_PAYLOAD;\n    }\n\n    protected static boolean isOverPayload(int payload, long size) {\n        return payload > 0 && size > payload;\n    }\n\n    protected Serialization getSerialization(Channel channel, Request req) {\n        return CodecSupport.getSerialization(channel.getUrl());\n    }\n\n    protected Serialization getSerialization(Channel channel, Response res) {\n        return CodecSupport.getSerialization(channel.getUrl());\n    }\n\n    protected Serialization getSerialization(Channel channel) {\n        return CodecSupport.getSerialization(channel.getUrl());\n    }\n\n    protected boolean isClientSide(Channel channel) {\n        String side = (String) channel.getAttribute(SIDE_KEY);\n        if (CLIENT_SIDE.equals(side)) {\n            return true;\n        } else if (SERVER_SIDE.equals(side)) {\n            return false;\n        } else {\n            InetSocketAddress address = channel.getRemoteAddress();\n            URL url = channel.getUrl();\n            boolean isClient = url.getPort() == address.getPort()\n                    && NetUtils.filterLocalHost(url.getIp())\n                            .equals(NetUtils.filterLocalHost(\n                                    address.getAddress().getHostAddress()));\n            channel.setAttribute(SIDE_KEY, isClient ? CLIENT_SIDE : SERVER_SIDE);\n            return isClient;\n        }\n    }\n\n    protected boolean isServerSide(Channel channel) {\n        return !isClientSide(channel);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractEndpoint.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.Resetable;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Codec;\nimport org.apache.dubbo.remoting.Codec2;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.transport.codec.CodecAdapter;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.rpc.model.ScopeModelUtil.getFrameworkModel;\n\npublic abstract class AbstractEndpoint extends AbstractPeer implements Resetable {\n\n    protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());\n\n    private Codec2 codec;\n\n    private int connectTimeout;\n\n    public AbstractEndpoint(URL url, ChannelHandler handler) {\n        super(url, handler);\n        this.codec = getChannelCodec(url);\n        this.connectTimeout =\n                url.getPositiveParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT);\n    }\n\n    protected AbstractEndpoint() {}\n\n    protected static Codec2 getChannelCodec(URL url) {\n        String codecName = url.getParameter(Constants.CODEC_KEY);\n        if (StringUtils.isEmpty(codecName)) {\n            // codec extension name must stay the same with protocol name\n            codecName = url.getProtocol();\n        }\n        FrameworkModel frameworkModel = getFrameworkModel(url.getScopeModel());\n        if (frameworkModel.getExtensionLoader(Codec2.class).hasExtension(codecName)) {\n            return frameworkModel.getExtensionLoader(Codec2.class).getExtension(codecName);\n        } else if (frameworkModel.getExtensionLoader(Codec.class).hasExtension(codecName)) {\n            return new CodecAdapter(\n                    frameworkModel.getExtensionLoader(Codec.class).getExtension(codecName));\n        } else {\n            return frameworkModel.getExtensionLoader(Codec2.class).getExtension(\"default\");\n        }\n    }\n\n    @Override\n    public void reset(URL url) {\n        if (isClosed()) {\n            throw new IllegalStateException(\n                    \"Failed to reset parameters \" + url + \", cause: Channel closed. channel: \" + getLocalAddress());\n        }\n\n        try {\n            if (url.hasParameter(Constants.CONNECT_TIMEOUT_KEY)) {\n                int t = url.getParameter(Constants.CONNECT_TIMEOUT_KEY, 0);\n                if (t > 0) {\n                    this.connectTimeout = t;\n                }\n            }\n        } catch (Throwable t) {\n            logger.error(INTERNAL_ERROR, \"\", \"\", t.getMessage(), t);\n        }\n\n        try {\n            if (url.hasParameter(Constants.CODEC_KEY)) {\n                this.codec = getChannelCodec(url);\n            }\n        } catch (Throwable t) {\n            logger.error(INTERNAL_ERROR, \"unknown error in remoting module\", \"\", t.getMessage(), t);\n        }\n    }\n\n    @Deprecated\n    public void reset(org.apache.dubbo.common.Parameters parameters) {\n        reset(getUrl().addParameters(parameters.getParameters()));\n    }\n\n    protected Codec2 getCodec() {\n        return codec;\n    }\n\n    protected int getConnectTimeout() {\n        return connectTimeout;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractPeer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.Endpoint;\nimport org.apache.dubbo.remoting.RemotingException;\n\npublic abstract class AbstractPeer implements Endpoint, ChannelHandler {\n\n    private final ChannelHandler handler;\n\n    private volatile URL url;\n\n    // closing closed means the process is being closed and close is finished\n    private volatile boolean closing;\n\n    private volatile boolean closed;\n\n    public AbstractPeer(URL url, ChannelHandler handler) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n        if (handler == null) {\n            throw new IllegalArgumentException(\"handler == null\");\n        }\n        this.url = url;\n        this.handler = handler;\n    }\n\n    protected AbstractPeer() {\n        handler = null;\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        send(message, url.getParameter(Constants.SENT_KEY, false));\n    }\n\n    @Override\n    public void close() {\n        closed = true;\n    }\n\n    @Override\n    public void close(int timeout) {\n        close();\n    }\n\n    @Override\n    public void startClose() {\n        if (isClosed()) {\n            return;\n        }\n        closing = true;\n    }\n\n    @Override\n    public URL getUrl() {\n        return url;\n    }\n\n    protected void setUrl(URL url) {\n        if (url == null) {\n            throw new IllegalArgumentException(\"url == null\");\n        }\n        this.url = url;\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        if (handler instanceof ChannelHandlerDelegate) {\n            return ((ChannelHandlerDelegate) handler).getHandler();\n        } else {\n            return handler;\n        }\n    }\n\n    /**\n     * @return ChannelHandler\n     */\n    @Deprecated\n    public ChannelHandler getHandler() {\n        return getDelegateHandler();\n    }\n\n    /**\n     * Return the final handler (which may have been wrapped). This method should be distinguished with getChannelHandler() method\n     *\n     * @return ChannelHandler\n     */\n    public ChannelHandler getDelegateHandler() {\n        return handler;\n    }\n\n    @Override\n    public boolean isClosed() {\n        return closed;\n    }\n\n    public boolean isClosing() {\n        return closing && !closed;\n    }\n\n    @Override\n    public void connected(Channel ch) throws RemotingException {\n        if (closed) {\n            return;\n        }\n        handler.connected(ch);\n    }\n\n    @Override\n    public void disconnected(Channel ch) throws RemotingException {\n        handler.disconnected(ch);\n    }\n\n    @Override\n    public void sent(Channel ch, Object msg) throws RemotingException {\n        if (closed) {\n            return;\n        }\n        handler.sent(ch, msg);\n    }\n\n    @Override\n    public void received(Channel ch, Object msg) throws RemotingException {\n        if (closed) {\n            return;\n        }\n        handler.received(ch, msg);\n    }\n\n    @Override\n    public void caught(Channel ch, Throwable ex) throws RemotingException {\n        handler.caught(ch, ex);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractServer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.common.utils.ExecutorUtil;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelEvent;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.RemotingServer;\n\nimport java.net.InetSocketAddress;\nimport java.util.Collection;\nimport java.util.Set;\nimport java.util.concurrent.ExecutorService;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.config.Constants.SERVER_THREAD_POOL_NAME;\nimport static org.apache.dubbo.remoting.Constants.ACCEPTS_KEY;\nimport static org.apache.dubbo.remoting.Constants.DEFAULT_ACCEPTS;\n\npublic abstract class AbstractServer extends AbstractEndpoint implements RemotingServer {\n\n    private Set<ExecutorService> executors = new ConcurrentHashSet<>();\n    private InetSocketAddress localAddress;\n    private InetSocketAddress bindAddress;\n    private int accepts;\n\n    private ExecutorRepository executorRepository;\n\n    public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {\n        super(url, handler);\n        executorRepository = ExecutorRepository.getInstance(url.getOrDefaultApplicationModel());\n        localAddress = getUrl().toInetSocketAddress();\n\n        String bindIp = getUrl().getParameter(Constants.BIND_IP_KEY, getUrl().getHost());\n        int bindPort = getUrl().getParameter(Constants.BIND_PORT_KEY, getUrl().getPort());\n        if (url.getParameter(ANYHOST_KEY, false) || NetUtils.isInvalidLocalHost(bindIp)) {\n            bindIp = ANYHOST_VALUE;\n        }\n        bindAddress = new InetSocketAddress(bindIp, bindPort);\n        this.accepts = url.getParameter(ACCEPTS_KEY, DEFAULT_ACCEPTS);\n        try {\n            doOpen();\n            if (logger.isInfoEnabled()) {\n                logger.info(\"[SERVICE_PUBLISH][METADATA_REGISTER] Start \"\n                        + getClass().getSimpleName() + \" bind \" + getBindAddress() + \", export \" + getLocalAddress());\n            }\n        } catch (Throwable t) {\n            throw new RemotingException(\n                    url.toInetSocketAddress(),\n                    null,\n                    \"Failed to bind \" + getClass().getSimpleName() + \" on \" + bindAddress + \", cause: \"\n                            + t.getMessage(),\n                    t);\n        }\n        executors.add(\n                executorRepository.createExecutorIfAbsent(ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));\n    }\n\n    protected abstract void doOpen() throws Throwable;\n\n    protected abstract void doClose() throws Throwable;\n\n    protected abstract int getChannelsSize();\n\n    @Override\n    public void reset(URL url) {\n        if (url == null) {\n            return;\n        }\n\n        try {\n            if (url.hasParameter(ACCEPTS_KEY)) {\n                int a = url.getParameter(ACCEPTS_KEY, 0);\n                if (a > 0) {\n                    this.accepts = a;\n                }\n            }\n        } catch (Throwable t) {\n            logger.error(INTERNAL_ERROR, \"unknown error in remoting module\", \"\", t.getMessage(), t);\n        }\n\n        ExecutorService executor =\n                executorRepository.createExecutorIfAbsent(ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME));\n        executors.add(executor);\n        executorRepository.updateThreadpool(url, executor);\n        super.setUrl(getUrl().addParameters(url.getParameters()));\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        Collection<Channel> channels = getChannels();\n        for (Channel channel : channels) {\n            if (channel.isConnected()) {\n                channel.send(message, sent);\n            }\n        }\n    }\n\n    @Override\n    public void close() {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Close \" + getClass().getSimpleName() + \" bind \" + getBindAddress() + \", export \"\n                    + getLocalAddress());\n        }\n\n        for (ExecutorService executor : executors) {\n            ExecutorUtil.shutdownNow(executor, 100);\n        }\n\n        try {\n            super.close();\n        } catch (Throwable e) {\n            logger.warn(INTERNAL_ERROR, \"unknown error in remoting module\", \"\", e.getMessage(), e);\n        }\n\n        try {\n            doClose();\n        } catch (Throwable e) {\n            logger.warn(INTERNAL_ERROR, \"unknown error in remoting module\", \"\", e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public void close(int timeout) {\n        for (ExecutorService executor : executors) {\n            ExecutorUtil.gracefulShutdown(executor, timeout);\n        }\n        close();\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return localAddress;\n    }\n\n    public InetSocketAddress getBindAddress() {\n        return bindAddress;\n    }\n\n    public int getAccepts() {\n        return accepts;\n    }\n\n    @Override\n    public void connected(Channel ch) throws RemotingException {\n        // If the server has entered the shutdown process, reject any new connection\n        if (this.isClosing() || this.isClosed()) {\n            logger.warn(\n                    INTERNAL_ERROR,\n                    \"unknown error in remoting module\",\n                    \"\",\n                    \"Close new channel \" + ch\n                            + \", cause: server is closing or has been closed. For example, receive a new connect request while in shutdown process.\");\n            ch.close();\n            return;\n        }\n\n        if (accepts > 0 && getChannelsSize() > accepts) {\n            logger.error(\n                    INTERNAL_ERROR,\n                    \"unknown error in remoting module\",\n                    \"\",\n                    \"Close channel \" + ch + \", cause: The server \" + ch.getLocalAddress()\n                            + \" connections greater than max config \" + accepts);\n            ch.close();\n            return;\n        }\n        super.connected(ch);\n    }\n\n    @Override\n    public void disconnected(Channel ch) throws RemotingException {\n        if (getChannelsSize() == 0) {\n            logger.info(\n                    \"All clients has disconnected from \" + ch.getLocalAddress() + \". You can graceful shutdown now.\");\n        }\n        super.disconnected(ch);\n    }\n\n    @Override\n    public void fireChannelEvent(ChannelEvent event) {\n        // Default implementation does nothing.\n        // Subclasses can override this method to implement protocol-specific event handling.\n        logger.warn(\n                INTERNAL_ERROR,\n                \"unknown error in remoting module\",\n                \"\",\n                \"The fireChannelEvent method is not implemented for \"\n                        + getClass().getName() + \", event: \" + event);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/ChannelDelegate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\n\nimport java.net.InetSocketAddress;\n\npublic class ChannelDelegate implements Channel {\n\n    private transient Channel channel;\n\n    public ChannelDelegate() {}\n\n    public ChannelDelegate(Channel channel) {\n        setChannel(channel);\n    }\n\n    public Channel getChannel() {\n        return channel;\n    }\n\n    public void setChannel(Channel channel) {\n        if (channel == null) {\n            throw new IllegalArgumentException(\"channel == null\");\n        }\n        this.channel = channel;\n    }\n\n    @Override\n    public URL getUrl() {\n        return channel.getUrl();\n    }\n\n    @Override\n    public InetSocketAddress getRemoteAddress() {\n        return channel.getRemoteAddress();\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        return channel.getChannelHandler();\n    }\n\n    @Override\n    public boolean isConnected() {\n        return channel.isConnected();\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return channel.getLocalAddress();\n    }\n\n    @Override\n    public boolean hasAttribute(String key) {\n        return channel.hasAttribute(key);\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        channel.send(message);\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        return channel.getAttribute(key);\n    }\n\n    @Override\n    public void setAttribute(String key, Object value) {\n        channel.setAttribute(key, value);\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        channel.send(message, sent);\n    }\n\n    @Override\n    public void removeAttribute(String key) {\n        channel.removeAttribute(key);\n    }\n\n    @Override\n    public void close() {\n        channel.close();\n    }\n\n    @Override\n    public void close(int timeout) {\n        channel.close(timeout);\n    }\n\n    @Override\n    public void startClose() {\n        channel.startClose();\n    }\n\n    @Override\n    public boolean isClosed() {\n        return channel.isClosed();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/ChannelHandlerAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\n\n/**\n * ChannelHandlerAdapter.\n */\npublic class ChannelHandlerAdapter implements ChannelHandler {\n\n    @Override\n    public void connected(Channel channel) throws RemotingException {}\n\n    @Override\n    public void disconnected(Channel channel) throws RemotingException {}\n\n    @Override\n    public void sent(Channel channel, Object message) throws RemotingException {}\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {}\n\n    @Override\n    public void caught(Channel channel, Throwable exception) throws RemotingException {}\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/ChannelHandlerDelegate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.remoting.ChannelHandler;\n\npublic interface ChannelHandlerDelegate extends ChannelHandler {\n    ChannelHandler getHandler();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/ChannelHandlerDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Objects;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.stream.Collectors;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\n\n/**\n * ChannelListenerDispatcher\n */\npublic class ChannelHandlerDispatcher implements ChannelHandler {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ChannelHandlerDispatcher.class);\n\n    private final Collection<ChannelHandler> channelHandlers = new CopyOnWriteArraySet<>();\n\n    public ChannelHandlerDispatcher() {}\n\n    public ChannelHandlerDispatcher(ChannelHandler... handlers) {\n        // if varargs is used, the type of handlers is ChannelHandler[] and it is not null\n        // so we should filter the null object\n        this(handlers == null ? null : Arrays.asList(handlers));\n    }\n\n    public ChannelHandlerDispatcher(Collection<ChannelHandler> handlers) {\n        if (CollectionUtils.isNotEmpty(handlers)) {\n            // filter null object\n            this.channelHandlers.addAll(\n                    handlers.stream().filter(Objects::nonNull).collect(Collectors.toSet()));\n        }\n    }\n\n    public Collection<ChannelHandler> getChannelHandlers() {\n        return channelHandlers;\n    }\n\n    public ChannelHandlerDispatcher addChannelHandler(ChannelHandler handler) {\n        this.channelHandlers.add(handler);\n        return this;\n    }\n\n    public ChannelHandlerDispatcher removeChannelHandler(ChannelHandler handler) {\n        this.channelHandlers.remove(handler);\n        return this;\n    }\n\n    @Override\n    public void connected(Channel channel) {\n        for (ChannelHandler listener : channelHandlers) {\n            try {\n                listener.connected(channel);\n            } catch (Throwable t) {\n                logger.error(INTERNAL_ERROR, \"unknown error in remoting module\", \"\", t.getMessage(), t);\n            }\n        }\n    }\n\n    @Override\n    public void disconnected(Channel channel) {\n        for (ChannelHandler listener : channelHandlers) {\n            try {\n                listener.disconnected(channel);\n            } catch (Throwable t) {\n                logger.error(INTERNAL_ERROR, \"unknown error in remoting module\", \"\", t.getMessage(), t);\n            }\n        }\n    }\n\n    @Override\n    public void sent(Channel channel, Object message) {\n        for (ChannelHandler listener : channelHandlers) {\n            try {\n                listener.sent(channel, message);\n            } catch (Throwable t) {\n                logger.error(INTERNAL_ERROR, \"unknown error in remoting module\", \"\", t.getMessage(), t);\n            }\n        }\n    }\n\n    @Override\n    public void received(Channel channel, Object message) {\n        for (ChannelHandler listener : channelHandlers) {\n            try {\n                listener.received(channel, message);\n            } catch (Throwable t) {\n                logger.error(INTERNAL_ERROR, \"unknown error in remoting module\", \"\", t.getMessage(), t);\n            }\n        }\n    }\n\n    @Override\n    public void caught(Channel channel, Throwable exception) {\n        for (ChannelHandler listener : channelHandlers) {\n            try {\n                listener.caught(channel, exception);\n            } catch (Throwable t) {\n                logger.error(INTERNAL_ERROR, \"unknown error in remoting module\", \"\", t.getMessage(), t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/ClientDelegate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Client;\nimport org.apache.dubbo.remoting.RemotingException;\n\nimport java.net.InetSocketAddress;\n\npublic class ClientDelegate implements Client {\n\n    private transient Client client;\n\n    public ClientDelegate() {}\n\n    public ClientDelegate(Client client) {\n        setClient(client);\n    }\n\n    public Client getClient() {\n        return client;\n    }\n\n    public void setClient(Client client) {\n        if (client == null) {\n            throw new IllegalArgumentException(\"client == null\");\n        }\n        this.client = client;\n    }\n\n    @Override\n    public void reset(URL url) {\n        client.reset(url);\n    }\n\n    @Override\n    @Deprecated\n    public void reset(org.apache.dubbo.common.Parameters parameters) {\n        reset(getUrl().addParameters(parameters.getParameters()));\n    }\n\n    @Override\n    public URL getUrl() {\n        return client.getUrl();\n    }\n\n    @Override\n    public InetSocketAddress getRemoteAddress() {\n        return client.getRemoteAddress();\n    }\n\n    @Override\n    public void reconnect() throws RemotingException {\n        client.reconnect();\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        return client.getChannelHandler();\n    }\n\n    @Override\n    public boolean isConnected() {\n        return client.isConnected();\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return client.getLocalAddress();\n    }\n\n    @Override\n    public boolean hasAttribute(String key) {\n        return client.hasAttribute(key);\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        client.send(message);\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        return client.getAttribute(key);\n    }\n\n    @Override\n    public void setAttribute(String key, Object value) {\n        client.setAttribute(key, value);\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        client.send(message, sent);\n    }\n\n    @Override\n    public void removeAttribute(String key) {\n        client.removeAttribute(key);\n    }\n\n    @Override\n    public void close() {\n        client.close();\n    }\n\n    @Override\n    public void close(int timeout) {\n        client.close(timeout);\n    }\n\n    @Override\n    public void startClose() {\n        client.startClose();\n    }\n\n    @Override\n    public boolean isClosed() {\n        return client.isClosed();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/CodecSupport.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.ObjectInput;\nimport org.apache.dubbo.common.serialize.ObjectOutput;\nimport org.apache.dubbo.common.serialize.Serialization;\nimport org.apache.dubbo.common.utils.ConcurrentHashMapUtils;\nimport org.apache.dubbo.remoting.utils.UrlUtils;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_SERIALIZATION;\n\npublic class CodecSupport {\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(CodecSupport.class);\n    private static Map<Byte, Serialization> ID_SERIALIZATION_MAP = new HashMap<>();\n    private static Map<Byte, String> ID_SERIALIZATIONNAME_MAP = new HashMap<>();\n    private static Map<String, Byte> SERIALIZATIONNAME_ID_MAP = new HashMap<>();\n    // Cache null object serialize results, for heartbeat request/response serialize use.\n    private static ConcurrentMap<Byte, byte[]> ID_NULLBYTES_MAP = new ConcurrentHashMap<>();\n\n    private static final ThreadLocal<byte[]> TL_BUFFER = ThreadLocal.withInitial(() -> new byte[1024]);\n\n    static {\n        ExtensionLoader<Serialization> extensionLoader =\n                FrameworkModel.defaultModel().getExtensionLoader(Serialization.class);\n        Set<String> supportedExtensions = extensionLoader.getSupportedExtensions();\n        for (String name : supportedExtensions) {\n            Serialization serialization = extensionLoader.getExtension(name);\n            byte idByte = serialization.getContentTypeId();\n            if (ID_SERIALIZATION_MAP.containsKey(idByte)) {\n                logger.error(\n                        TRANSPORT_FAILED_SERIALIZATION,\n                        \"\",\n                        \"\",\n                        \"Serialization extension \" + serialization.getClass().getName()\n                                + \" has duplicate id to Serialization extension \"\n                                + ID_SERIALIZATION_MAP.get(idByte).getClass().getName()\n                                + \", ignore this Serialization extension\");\n                continue;\n            }\n            ID_SERIALIZATION_MAP.put(idByte, serialization);\n            ID_SERIALIZATIONNAME_MAP.put(idByte, name);\n            SERIALIZATIONNAME_ID_MAP.put(name, idByte);\n        }\n    }\n\n    private CodecSupport() {}\n\n    public static Serialization getSerializationById(Byte id) {\n        return ID_SERIALIZATION_MAP.get(id);\n    }\n\n    public static Byte getIDByName(String name) {\n        return SERIALIZATIONNAME_ID_MAP.get(name);\n    }\n\n    public static Serialization getSerialization(URL url) {\n        return url.getOrDefaultFrameworkModel()\n                .getExtensionLoader(Serialization.class)\n                .getExtension(UrlUtils.serializationOrDefault(url));\n    }\n\n    public static Serialization getSerialization(Byte id) throws IOException {\n        Serialization result = getSerializationById(id);\n        if (result == null) {\n            throw new IOException(\"Unrecognized serialize type from consumer: \" + id);\n        }\n        return result;\n    }\n\n    public static ObjectInput deserialize(URL url, InputStream is, byte proto) throws IOException {\n        Serialization s = getSerialization(proto);\n        return s.deserialize(url, is);\n    }\n\n    /**\n     * Get the null object serialize result byte[] of Serialization from the cache,\n     * if not, generate it first.\n     *\n     * @param s Serialization Instances\n     * @return serialize result of null object\n     */\n    public static byte[] getNullBytesOf(Serialization s) {\n        return ConcurrentHashMapUtils.computeIfAbsent(ID_NULLBYTES_MAP, s.getContentTypeId(), k -> {\n            // Pre-generated Null object bytes\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            byte[] nullBytes = new byte[0];\n            try {\n                ObjectOutput out = s.serialize(null, baos);\n                out.writeObject(null);\n                out.flushBuffer();\n                nullBytes = baos.toByteArray();\n                baos.close();\n            } catch (Exception e) {\n                logger.warn(\n                        TRANSPORT_FAILED_SERIALIZATION,\n                        \"\",\n                        \"\",\n                        \"Serialization extension \" + s.getClass().getName()\n                                + \" not support serializing null object, return an empty bytes instead.\");\n            }\n            return nullBytes;\n        });\n    }\n\n    /**\n     * Read all payload to byte[]\n     *\n     * @param is\n     * @return\n     * @throws IOException\n     */\n    public static byte[] getPayload(InputStream is) throws IOException {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        byte[] buffer = getBuffer(is.available());\n        int len;\n        while ((len = is.read(buffer)) > -1) {\n            baos.write(buffer, 0, len);\n        }\n        baos.flush();\n        return baos.toByteArray();\n    }\n\n    private static byte[] getBuffer(int size) {\n        byte[] bytes = TL_BUFFER.get();\n        if (size <= bytes.length) {\n            return bytes;\n        }\n        return new byte[size];\n    }\n\n    /**\n     * Check if payload is null object serialize result byte[] of serialization\n     *\n     * @param payload\n     * @param proto\n     * @return\n     */\n    public static boolean isHeartBeat(byte[] payload, byte proto) {\n        return Arrays.equals(payload, getNullBytesOf(getSerializationById(proto)));\n    }\n\n    public static void checkSerialization(String requestSerializeName, URL url) throws IOException {\n        Collection<String> all = UrlUtils.allSerializations(url);\n        checkSerialization(requestSerializeName, all);\n    }\n\n    public static void checkSerialization(String requestSerializeName, Collection<String> allSerializeName)\n            throws IOException {\n        for (String serialization : allSerializeName) {\n            if (serialization.equals(requestSerializeName)) {\n                return;\n            }\n        }\n        throw new IOException(\"Unexpected serialization type:\" + requestSerializeName\n                + \" received from network, please check if the peer send the right id.\");\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/DecodeHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Decodeable;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_DECODE;\n\npublic class DecodeHandler extends AbstractChannelHandlerDelegate {\n\n    private static final ErrorTypeAwareLogger log = LoggerFactory.getErrorTypeAwareLogger(DecodeHandler.class);\n\n    public DecodeHandler(ChannelHandler handler) {\n        super(handler);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        if (message instanceof Decodeable) {\n            decode(message);\n        }\n\n        if (message instanceof Request) {\n            decode(((Request) message).getData());\n        }\n\n        if (message instanceof Response) {\n            decode(((Response) message).getResult());\n        }\n\n        handler.received(channel, message);\n    }\n\n    private void decode(Object message) {\n        if (!(message instanceof Decodeable)) {\n            return;\n        }\n\n        try {\n            ((Decodeable) message).decode();\n            if (log.isDebugEnabled()) {\n                log.debug(\"Decode decodeable message \" + message.getClass().getName());\n            }\n        } catch (Throwable e) {\n            if (log.isWarnEnabled()) {\n                log.warn(TRANSPORT_FAILED_DECODE, \"\", \"\", \"Call Decodeable.decode failed: \" + e.getMessage(), e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/ExceedPayloadLimitException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport java.io.IOException;\n\npublic class ExceedPayloadLimitException extends IOException {\n    private static final long serialVersionUID = -1112322085391551410L;\n\n    public ExceedPayloadLimitException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/MultiMessageHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.support.MultiMessage;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\n\n/**\n * @see MultiMessage\n */\npublic class MultiMessageHandler extends AbstractChannelHandlerDelegate {\n\n    protected static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(MultiMessageHandler.class);\n\n    public MultiMessageHandler(ChannelHandler handler) {\n        super(handler);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        if (message instanceof MultiMessage) {\n            MultiMessage list = (MultiMessage) message;\n            for (Object obj : list) {\n                try {\n                    handler.received(channel, obj);\n                } catch (Throwable t) {\n                    logger.error(\n                            INTERNAL_ERROR,\n                            \"unknown error in remoting module\",\n                            \"\",\n                            \"MultiMessageHandler received fail.\",\n                            t);\n                    try {\n                        handler.caught(channel, t);\n                    } catch (Throwable t1) {\n                        logger.error(\n                                INTERNAL_ERROR,\n                                \"unknown error in remoting module\",\n                                \"\",\n                                \"MultiMessageHandler caught fail.\",\n                                t1);\n                    }\n                }\n            }\n        } else {\n            handler.received(channel, message);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/ServerDelegate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelEvent;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.RemotingServer;\n\nimport java.net.InetSocketAddress;\nimport java.util.Collection;\n\n/**\n * ServerDelegate\n *\n *\n */\npublic class ServerDelegate implements RemotingServer {\n\n    private transient RemotingServer server;\n\n    public ServerDelegate() {}\n\n    public ServerDelegate(RemotingServer server) {\n        setServer(server);\n    }\n\n    public RemotingServer getServer() {\n        return server;\n    }\n\n    public void setServer(RemotingServer server) {\n        this.server = server;\n    }\n\n    @Override\n    public boolean isBound() {\n        return server.isBound();\n    }\n\n    @Override\n    public void reset(URL url) {\n        server.reset(url);\n    }\n\n    @Override\n    @Deprecated\n    public void reset(org.apache.dubbo.common.Parameters parameters) {\n        reset(getUrl().addParameters(parameters.getParameters()));\n    }\n\n    @Override\n    public Collection<Channel> getChannels() {\n        return server.getChannels();\n    }\n\n    @Override\n    public Channel getChannel(InetSocketAddress remoteAddress) {\n        return server.getChannel(remoteAddress);\n    }\n\n    @Override\n    public URL getUrl() {\n        return server.getUrl();\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        return server.getChannelHandler();\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return server.getLocalAddress();\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        server.send(message);\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        server.send(message, sent);\n    }\n\n    @Override\n    public void close() {\n        server.close();\n    }\n\n    @Override\n    public void close(int timeout) {\n        server.close(timeout);\n    }\n\n    @Override\n    public void startClose() {\n        server.startClose();\n    }\n\n    @Override\n    public boolean isClosed() {\n        return server.isClosed();\n    }\n\n    @Override\n    public void fireChannelEvent(ChannelEvent event) {\n        server.fireChannelEvent(event);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/codec/CodecAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.codec;\n\nimport org.apache.dubbo.common.io.UnsafeByteArrayInputStream;\nimport org.apache.dubbo.common.io.UnsafeByteArrayOutputStream;\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Codec;\nimport org.apache.dubbo.remoting.Codec2;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffer;\n\nimport java.io.IOException;\n\npublic class CodecAdapter implements Codec2 {\n\n    private Codec codec;\n\n    public CodecAdapter(Codec codec) {\n        Assert.notNull(codec, \"codec == null\");\n        this.codec = codec;\n    }\n\n    @Override\n    public void encode(Channel channel, ChannelBuffer buffer, Object message) throws IOException {\n        UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(1024);\n        codec.encode(channel, os, message);\n        buffer.writeBytes(os.toByteArray());\n    }\n\n    @Override\n    public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {\n        byte[] bytes = new byte[buffer.readableBytes()];\n        int savedReaderIndex = buffer.readerIndex();\n        buffer.readBytes(bytes);\n        UnsafeByteArrayInputStream is = new UnsafeByteArrayInputStream(bytes);\n        Object result = codec.decode(channel, is);\n        buffer.readerIndex(savedReaderIndex + is.position());\n        return result == Codec.NEED_MORE_INPUT ? DecodeResult.NEED_MORE_INPUT : result;\n    }\n\n    public Codec getCodec() {\n        return codec;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/codec/TransportCodec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.codec;\n\nimport org.apache.dubbo.common.serialize.Cleanable;\nimport org.apache.dubbo.common.serialize.ObjectInput;\nimport org.apache.dubbo.common.serialize.ObjectOutput;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffer;\nimport org.apache.dubbo.remoting.buffer.ChannelBufferInputStream;\nimport org.apache.dubbo.remoting.buffer.ChannelBufferOutputStream;\nimport org.apache.dubbo.remoting.transport.AbstractCodec;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Subclasses {@link org.apache.dubbo.remoting.telnet.codec.TelnetCodec} and {@link org.apache.dubbo.remoting.exchange.codec.ExchangeCodec}\n * both override all the methods declared in this class.\n */\n@Deprecated\npublic class TransportCodec extends AbstractCodec {\n\n    @Override\n    public void encode(Channel channel, ChannelBuffer buffer, Object message) throws IOException {\n        OutputStream output = new ChannelBufferOutputStream(buffer);\n        ObjectOutput objectOutput = getSerialization(channel).serialize(channel.getUrl(), output);\n        encodeData(channel, objectOutput, message);\n        objectOutput.flushBuffer();\n        if (objectOutput instanceof Cleanable) {\n            ((Cleanable) objectOutput).cleanup();\n        }\n    }\n\n    @Override\n    public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {\n        InputStream input = new ChannelBufferInputStream(buffer);\n        ObjectInput objectInput = getSerialization(channel).deserialize(channel.getUrl(), input);\n        Object object = decodeData(channel, objectInput);\n        if (objectInput instanceof Cleanable) {\n            ((Cleanable) objectInput).cleanup();\n        }\n        return object;\n    }\n\n    protected void encodeData(Channel channel, ObjectOutput output, Object message) throws IOException {\n        encodeData(output, message);\n    }\n\n    protected Object decodeData(Channel channel, ObjectInput input) throws IOException {\n        return decodeData(input);\n    }\n\n    protected void encodeData(ObjectOutput output, Object message) throws IOException {\n        output.writeObject(message);\n    }\n\n    protected Object decodeData(ObjectInput input) throws IOException {\n        try {\n            return input.readObject();\n        } catch (ClassNotFoundException e) {\n            throw new IOException(\"ClassNotFoundException: \" + StringUtils.toString(e));\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/ChannelEventRunnable.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.threadlocal.InternalThreadLocalMap;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\n\npublic class ChannelEventRunnable implements Runnable {\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(ChannelEventRunnable.class);\n\n    private final ChannelHandler handler;\n    private final Channel channel;\n    private final ChannelState state;\n    private final Throwable exception;\n    private final Object message;\n\n    public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state) {\n        this(channel, handler, state, null);\n    }\n\n    public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Object message) {\n        this(channel, handler, state, message, null);\n    }\n\n    public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Throwable t) {\n        this(channel, handler, state, null, t);\n    }\n\n    public ChannelEventRunnable(\n            Channel channel, ChannelHandler handler, ChannelState state, Object message, Throwable exception) {\n        this.channel = channel;\n        this.handler = handler;\n        this.state = state;\n        this.message = message;\n        this.exception = exception;\n    }\n\n    @Override\n    public void run() {\n        InternalThreadLocalMap internalThreadLocalMap = InternalThreadLocalMap.getAndRemove();\n        try {\n            if (state == ChannelState.RECEIVED) {\n                try {\n                    handler.received(channel, message);\n                } catch (Exception e) {\n                    logger.warn(\n                            INTERNAL_ERROR,\n                            \"unknown error in remoting module\",\n                            \"\",\n                            \"ChannelEventRunnable handle \" + state + \" operation error, channel is \" + channel\n                                    + \", message is \" + message,\n                            e);\n                }\n            } else {\n                switch (state) {\n                    case CONNECTED:\n                        try {\n                            handler.connected(channel);\n                        } catch (Exception e) {\n                            logger.warn(\n                                    INTERNAL_ERROR,\n                                    \"unknown error in remoting module\",\n                                    \"\",\n                                    \"ChannelEventRunnable handle \" + state + \" operation error, channel is \" + channel,\n                                    e);\n                        }\n                        break;\n                    case DISCONNECTED:\n                        try {\n                            handler.disconnected(channel);\n                        } catch (Exception e) {\n                            logger.warn(\n                                    INTERNAL_ERROR,\n                                    \"unknown error in remoting module\",\n                                    \"\",\n                                    \"ChannelEventRunnable handle \" + state + \" operation error, channel is \" + channel,\n                                    e);\n                        }\n                        break;\n                    case SENT:\n                        try {\n                            handler.sent(channel, message);\n                        } catch (Exception e) {\n                            logger.warn(\n                                    INTERNAL_ERROR,\n                                    \"unknown error in remoting module\",\n                                    \"\",\n                                    \"ChannelEventRunnable handle \" + state + \" operation error, channel is \" + channel\n                                            + \", message is \" + message,\n                                    e);\n                        }\n                        break;\n                    case CAUGHT:\n                        try {\n                            handler.caught(channel, exception);\n                        } catch (Exception e) {\n                            logger.warn(\n                                    INTERNAL_ERROR,\n                                    \"unknown error in remoting module\",\n                                    \"\",\n                                    \"ChannelEventRunnable handle \" + state + \" operation error, channel is \" + channel\n                                            + \", message is: \" + message + \", exception is \" + exception,\n                                    e);\n                        }\n                        break;\n                    default:\n                        logger.warn(\n                                INTERNAL_ERROR,\n                                \"unknown error in remoting module\",\n                                \"\",\n                                \"unknown state: \" + state + \", message is \" + message);\n                }\n            }\n        } finally {\n            InternalThreadLocalMap.set(internalThreadLocalMap);\n        }\n    }\n\n    /**\n     * ChannelState\n     */\n    public enum ChannelState {\n\n        /**\n         * CONNECTED\n         */\n        CONNECTED,\n\n        /**\n         * DISCONNECTED\n         */\n        DISCONNECTED,\n\n        /**\n         * SENT\n         */\n        SENT,\n\n        /**\n         * RECEIVED\n         */\n        RECEIVED,\n\n        /**\n         * CAUGHT\n         */\n        CAUGHT\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/ChannelHandlers.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Dispatcher;\nimport org.apache.dubbo.remoting.exchange.support.header.HeartbeatHandler;\nimport org.apache.dubbo.remoting.transport.MultiMessageHandler;\n\npublic class ChannelHandlers {\n\n    private static ChannelHandlers INSTANCE = new ChannelHandlers();\n\n    protected ChannelHandlers() {}\n\n    public static ChannelHandler wrap(ChannelHandler handler, URL url) {\n        return ChannelHandlers.getInstance().wrapInternal(handler, url);\n    }\n\n    public static ChannelHandlers getInstance() {\n        return INSTANCE;\n    }\n\n    static void setTestingChannelHandlers(ChannelHandlers instance) {\n        INSTANCE = instance;\n    }\n\n    protected ChannelHandler wrapInternal(ChannelHandler handler, URL url) {\n        return new MultiMessageHandler(new HeartbeatHandler(url.getOrDefaultFrameworkModel()\n                .getExtensionLoader(Dispatcher.class)\n                .getAdaptiveExtension()\n                .dispatch(handler, url)));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/WrappedChannelHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.resource.GlobalResourcesRepository;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\nimport org.apache.dubbo.remoting.exchange.support.DefaultFuture;\nimport org.apache.dubbo.remoting.transport.ChannelHandlerDelegate;\nimport org.apache.dubbo.rpc.executor.ExecutorSupport;\nimport org.apache.dubbo.rpc.model.ApplicationModel;\n\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.ExecutorService;\n\npublic class WrappedChannelHandler implements ChannelHandlerDelegate {\n\n    protected static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(WrappedChannelHandler.class);\n\n    protected final ChannelHandler handler;\n\n    protected final URL url;\n\n    protected final ExecutorSupport executorSupport;\n\n    public WrappedChannelHandler(ChannelHandler handler, URL url) {\n        this.handler = handler;\n        this.url = url;\n        this.executorSupport = ExecutorRepository.getInstance(url.getOrDefaultApplicationModel())\n                .getExecutorSupport(url);\n    }\n\n    public void close() {}\n\n    @Override\n    public void connected(Channel channel) throws RemotingException {\n        handler.connected(channel);\n    }\n\n    @Override\n    public void disconnected(Channel channel) throws RemotingException {\n        handler.disconnected(channel);\n    }\n\n    @Override\n    public void sent(Channel channel, Object message) throws RemotingException {\n        handler.sent(channel, message);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        handler.received(channel, message);\n    }\n\n    @Override\n    public void caught(Channel channel, Throwable exception) throws RemotingException {\n        handler.caught(channel, exception);\n    }\n\n    protected void sendFeedback(Channel channel, Request request, Throwable t) throws RemotingException {\n\n        if (!request.isTwoWay()) {\n            return;\n        }\n\n        String msg = \"Server side(\" + url.getIp() + \",\" + url.getPort() + \") thread pool is exhausted, detail msg:\"\n                + t.getMessage();\n\n        Response response = new Response(request.getId(), request.getVersion());\n        response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);\n        response.setErrorMessage(msg);\n\n        channel.send(response);\n    }\n\n    @Override\n    public ChannelHandler getHandler() {\n        if (handler instanceof ChannelHandlerDelegate) {\n            return ((ChannelHandlerDelegate) handler).getHandler();\n        } else {\n            return handler;\n        }\n    }\n\n    public URL getUrl() {\n        return url;\n    }\n\n    /**\n     * Currently, this method is mainly customized to facilitate the thread model on consumer side.\n     * 1. Use ThreadlessExecutor, aka., delegate callback directly to the thread initiating the call.\n     * 2. Use shared executor to execute the callback.\n     *\n     * @param msg\n     * @return\n     */\n    public ExecutorService getPreferredExecutorService(Object msg) {\n        if (msg instanceof Response) {\n            Response response = (Response) msg;\n            DefaultFuture responseFuture = DefaultFuture.getFuture(response.getId());\n            // a typical scenario is the response returned after timeout, the timeout response may have completed the\n            // future\n            if (responseFuture == null) {\n                return getSharedExecutorService();\n            } else {\n                ExecutorService executor = responseFuture.getExecutor();\n                if (executor == null || executor.isShutdown()) {\n                    executor = getSharedExecutorService(msg);\n                }\n                return executor;\n            }\n        } else {\n            return getSharedExecutorService(msg);\n        }\n    }\n\n    /**\n     * @param msg  msg is the network message body, executorSupport.getExecutor needs it, and gets important information from it to get executor\n     * @return\n     */\n    public ExecutorService getSharedExecutorService(Object msg) {\n        Executor executor = executorSupport.getExecutor(msg);\n        return executor != null ? (ExecutorService) executor : getSharedExecutorService();\n    }\n\n    /**\n     * get the shared executor for current Server or Client\n     *\n     * @return\n     */\n    public ExecutorService getSharedExecutorService() {\n        // Application may be destroyed before channel disconnected, avoid create new application model\n        // see https://github.com/apache/dubbo/issues/9127\n        if (url.getApplicationModel() == null || url.getApplicationModel().isDestroyed()) {\n            return GlobalResourcesRepository.getGlobalExecutorService();\n        }\n\n        // note: url.getOrDefaultApplicationModel() may create new application model\n        ApplicationModel applicationModel = url.getOrDefaultApplicationModel();\n\n        ExecutorRepository executorRepository = ExecutorRepository.getInstance(applicationModel);\n\n        ExecutorService executor = executorRepository.getExecutor(url);\n\n        if (executor == null) {\n            executor = executorRepository.createExecutorIfAbsent(url);\n        }\n\n        return executor;\n    }\n\n    @Deprecated\n    public ExecutorService getExecutorService() {\n        return getSharedExecutorService();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/all/AllChannelHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher.all;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.ExecutionException;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;\nimport org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.RejectedExecutionException;\n\npublic class AllChannelHandler extends WrappedChannelHandler {\n\n    public AllChannelHandler(ChannelHandler handler, URL url) {\n        super(handler, url);\n    }\n\n    @Override\n    public void connected(Channel channel) throws RemotingException {\n        ExecutorService executor = getSharedExecutorService();\n        try {\n            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.CONNECTED));\n        } catch (Throwable t) {\n            throw new ExecutionException(\n                    \"connect event\", channel, getClass() + \" error when process connected event .\", t);\n        }\n    }\n\n    @Override\n    public void disconnected(Channel channel) throws RemotingException {\n        ExecutorService executor = getSharedExecutorService();\n        try {\n            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.DISCONNECTED));\n        } catch (Throwable t) {\n            throw new ExecutionException(\n                    \"disconnect event\", channel, getClass() + \" error when process disconnected event .\", t);\n        }\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        ExecutorService executor = getPreferredExecutorService(message);\n        try {\n            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));\n        } catch (Throwable t) {\n            if (message instanceof Request && t instanceof RejectedExecutionException) {\n                sendFeedback(channel, (Request) message, t);\n                return;\n            }\n            throw new ExecutionException(message, channel, getClass() + \" error when process received event .\", t);\n        }\n    }\n\n    @Override\n    public void caught(Channel channel, Throwable exception) throws RemotingException {\n        ExecutorService executor = getSharedExecutorService();\n        try {\n            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.CAUGHT, exception));\n        } catch (Throwable t) {\n            throw new ExecutionException(\"caught event\", channel, getClass() + \" error when process caught event .\", t);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/all/AllDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher.all;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Dispatcher;\n\n/**\n * default thread pool configure\n */\npublic class AllDispatcher implements Dispatcher {\n\n    public static final String NAME = \"all\";\n\n    @Override\n    public ChannelHandler dispatch(ChannelHandler handler, URL url) {\n        return new AllChannelHandler(handler, url);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/connection/ConnectionOrderedChannelHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher.connection;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport;\nimport org.apache.dubbo.common.utils.NamedThreadFactory;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.ExecutionException;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;\nimport org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREAD_NAME;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_CONNECTION_LIMIT_EXCEED;\nimport static org.apache.dubbo.remoting.Constants.CONNECT_QUEUE_CAPACITY;\nimport static org.apache.dubbo.remoting.Constants.CONNECT_QUEUE_WARNING_SIZE;\nimport static org.apache.dubbo.remoting.Constants.DEFAULT_CONNECT_QUEUE_WARNING_SIZE;\n\npublic class ConnectionOrderedChannelHandler extends WrappedChannelHandler {\n\n    protected final ThreadPoolExecutor connectionExecutor;\n    private final int queueWarningLimit;\n\n    public ConnectionOrderedChannelHandler(ChannelHandler handler, URL url) {\n        super(handler, url);\n        String threadName = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);\n        connectionExecutor = new ThreadPoolExecutor(\n                1,\n                1,\n                0L,\n                TimeUnit.MILLISECONDS,\n                new LinkedBlockingQueue<>(url.getPositiveParameter(CONNECT_QUEUE_CAPACITY, Integer.MAX_VALUE)),\n                new NamedThreadFactory(threadName, true),\n                new AbortPolicyWithReport(threadName, url)); // FIXME There's no place to release connectionExecutor!\n        queueWarningLimit = url.getParameter(CONNECT_QUEUE_WARNING_SIZE, DEFAULT_CONNECT_QUEUE_WARNING_SIZE);\n    }\n\n    @Override\n    public void connected(Channel channel) throws RemotingException {\n        try {\n            checkQueueLength();\n            connectionExecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.CONNECTED));\n        } catch (Throwable t) {\n            throw new ExecutionException(\n                    \"connect event\", channel, getClass() + \" error when process connected event .\", t);\n        }\n    }\n\n    @Override\n    public void disconnected(Channel channel) throws RemotingException {\n        try {\n            checkQueueLength();\n            connectionExecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.DISCONNECTED));\n        } catch (Throwable t) {\n            throw new ExecutionException(\n                    \"disconnected event\", channel, getClass() + \" error when process disconnected event .\", t);\n        }\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        ExecutorService executor = getPreferredExecutorService(message);\n        try {\n            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));\n        } catch (Throwable t) {\n            if (message instanceof Request && t instanceof RejectedExecutionException) {\n                sendFeedback(channel, (Request) message, t);\n                return;\n            }\n            throw new ExecutionException(message, channel, getClass() + \" error when process received event .\", t);\n        }\n    }\n\n    @Override\n    public void caught(Channel channel, Throwable exception) throws RemotingException {\n        ExecutorService executor = getSharedExecutorService();\n        try {\n            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.CAUGHT, exception));\n        } catch (Throwable t) {\n            throw new ExecutionException(\"caught event\", channel, getClass() + \" error when process caught event .\", t);\n        }\n    }\n\n    private void checkQueueLength() {\n        if (connectionExecutor.getQueue().size() > queueWarningLimit) {\n            logger.warn(\n                    TRANSPORT_CONNECTION_LIMIT_EXCEED,\n                    \"\",\n                    \"\",\n                    \"connectionordered channel handler queue size: \"\n                            + connectionExecutor.getQueue().size() + \" exceed the warning limit number :\"\n                            + queueWarningLimit);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/connection/ConnectionOrderedDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher.connection;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Dispatcher;\n\n/**\n * connect disconnect ensure the order\n */\npublic class ConnectionOrderedDispatcher implements Dispatcher {\n\n    public static final String NAME = \"connection\";\n\n    @Override\n    public ChannelHandler dispatch(ChannelHandler handler, URL url) {\n        return new ConnectionOrderedChannelHandler(handler, url);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/direct/DirectChannelHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher.direct;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadpool.ThreadlessExecutor;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.ExecutionException;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;\nimport org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;\n\nimport java.util.concurrent.ExecutorService;\n\npublic class DirectChannelHandler extends WrappedChannelHandler {\n\n    public DirectChannelHandler(ChannelHandler handler, URL url) {\n        super(handler, url);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        ExecutorService executor = getPreferredExecutorService(message);\n        if (executor instanceof ThreadlessExecutor) {\n            try {\n                executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));\n            } catch (Throwable t) {\n                throw new ExecutionException(message, channel, getClass() + \" error when process received event .\", t);\n            }\n        } else {\n            handler.received(channel, message);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/direct/DirectDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher.direct;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Dispatcher;\n\n/**\n * Direct dispatcher\n */\npublic class DirectDispatcher implements Dispatcher {\n\n    public static final String NAME = \"direct\";\n\n    @Override\n    public ChannelHandler dispatch(ChannelHandler handler, URL url) {\n        return new DirectChannelHandler(handler, url);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/execution/ExecutionChannelHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher.execution;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.threadpool.ThreadlessExecutor;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.ExecutionException;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;\nimport org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.RejectedExecutionException;\n\n/**\n * Only request message will be dispatched to thread pool. Other messages like response, connect, disconnect,\n * heartbeat will be directly executed by I/O thread.\n */\npublic class ExecutionChannelHandler extends WrappedChannelHandler {\n\n    public ExecutionChannelHandler(ChannelHandler handler, URL url) {\n        super(handler, url);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        ExecutorService executor = getPreferredExecutorService(message);\n\n        if (message instanceof Request) {\n            try {\n                executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));\n            } catch (Throwable t) {\n                // FIXME: when the thread pool is full, SERVER_THREADPOOL_EXHAUSTED_ERROR cannot return properly,\n                // therefore the consumer side has to wait until gets timeout. This is a temporary solution to prevent\n                // this scenario from happening, but a better solution should be considered later.\n                if (t instanceof RejectedExecutionException) {\n                    sendFeedback(channel, (Request) message, t);\n                }\n                throw new ExecutionException(message, channel, getClass() + \" error when process received event.\", t);\n            }\n        } else if (executor instanceof ThreadlessExecutor) {\n            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));\n        } else {\n            handler.received(channel, message);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/execution/ExecutionDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher.execution;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Dispatcher;\n\n/**\n * In addition to sending all the use thread pool processing\n */\npublic class ExecutionDispatcher implements Dispatcher {\n\n    public static final String NAME = \"execution\";\n\n    @Override\n    public ChannelHandler dispatch(ChannelHandler handler, URL url) {\n        return new ExecutionChannelHandler(handler, url);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/message/MessageOnlyChannelHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher.message;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.ExecutionException;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;\nimport org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;\nimport org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.RejectedExecutionException;\n\npublic class MessageOnlyChannelHandler extends WrappedChannelHandler {\n\n    public MessageOnlyChannelHandler(ChannelHandler handler, URL url) {\n        super(handler, url);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        ExecutorService executor = getPreferredExecutorService(message);\n        try {\n            executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));\n        } catch (Throwable t) {\n            if (message instanceof Request && t instanceof RejectedExecutionException) {\n                sendFeedback(channel, (Request) message, t);\n                return;\n            }\n            throw new ExecutionException(message, channel, getClass() + \" error when process received event .\", t);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/dispatcher/message/MessageOnlyDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher.message;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Dispatcher;\n\n/**\n * Only message receive uses the thread pool.\n */\npublic class MessageOnlyDispatcher implements Dispatcher {\n\n    public static final String NAME = \"message\";\n\n    @Override\n    public ChannelHandler dispatch(ChannelHandler handler, URL url) {\n        return new MessageOnlyChannelHandler(handler, url);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/utils/PayloadDropper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.utils;\n\nimport org.apache.dubbo.common.logger.Logger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\n\npublic class PayloadDropper {\n    private static Logger logger = LoggerFactory.getLogger(PayloadDropper.class);\n\n    /**\n     * only log body in debugger mode for size & security consideration.\n     *\n     * @param message\n     * @return\n     */\n    public static Object getRequestWithoutData(Object message) {\n        if (logger.isDebugEnabled()) {\n            return message;\n        }\n        if (message instanceof Request) {\n            Request request = (Request) message;\n            request.setData(null);\n            return request;\n        } else if (message instanceof Response) {\n            Response response = (Response) message;\n            response.setResult(null);\n            return response;\n        }\n        return message;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/utils/UrlUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.utils;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.serialize.support.DefaultSerializationSelector;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.transport.CodecSupport;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport static org.apache.dubbo.remoting.Constants.PREFER_SERIALIZATION_KEY;\nimport static org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY;\n\npublic class UrlUtils {\n    private static final String ALLOWED_SERIALIZATION_KEY = \"allowedSerialization\";\n\n    public static int getCloseTimeout(URL url) {\n        String configuredCloseTimeout = SystemPropertyConfigUtils.getSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLOSE_TIMEOUT_CONFIG_KEY);\n        int defaultCloseTimeout = -1;\n        if (StringUtils.isNotEmpty(configuredCloseTimeout)) {\n            try {\n                defaultCloseTimeout = Integer.parseInt(configuredCloseTimeout);\n            } catch (NumberFormatException e) {\n                // use default heartbeat\n            }\n        }\n        if (defaultCloseTimeout < 0) {\n            defaultCloseTimeout = getIdleTimeout(url);\n        }\n        int closeTimeout = url.getParameter(Constants.CLOSE_TIMEOUT_KEY, defaultCloseTimeout);\n        int heartbeat = getHeartbeat(url);\n        if (closeTimeout < heartbeat * 2) {\n            throw new IllegalStateException(\"closeTimeout < heartbeatInterval * 2\");\n        }\n        return closeTimeout;\n    }\n\n    public static int getIdleTimeout(URL url) {\n        int heartBeat = getHeartbeat(url);\n        // idleTimeout should be at least more than twice heartBeat because possible retries of client.\n        int idleTimeout = url.getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartBeat * 3);\n        if (idleTimeout < heartBeat * 2) {\n            throw new IllegalStateException(\"idleTimeout < heartbeatInterval * 2\");\n        }\n        return idleTimeout;\n    }\n\n    public static int getHeartbeat(URL url) {\n        String configuredHeartbeat =\n                SystemPropertyConfigUtils.getSystemProperty(CommonConstants.DubboProperty.DUBBO_HEARTBEAT_CONFIG_KEY);\n        int defaultHeartbeat = Constants.DEFAULT_HEARTBEAT;\n        if (StringUtils.isNotEmpty(configuredHeartbeat)) {\n            try {\n                defaultHeartbeat = Integer.parseInt(configuredHeartbeat);\n            } catch (NumberFormatException e) {\n                // use default heartbeat\n            }\n        }\n        return url.getParameter(Constants.HEARTBEAT_KEY, defaultHeartbeat);\n    }\n\n    /**\n     * Get the serialization id\n     *\n     * @param url url\n     * @return {@link Byte}\n     */\n    public static Byte serializationId(URL url) {\n        Byte serializationId;\n        // Obtain the value from prefer_serialization. Such as.fastjson2,hessian2\n        List<String> preferSerials = preferSerialization(url);\n        for (String preferSerial : preferSerials) {\n            if ((serializationId = CodecSupport.getIDByName(preferSerial)) != null) {\n                return serializationId;\n            }\n        }\n\n        // Secondly, obtain the value from serialization\n        if ((serializationId = CodecSupport.getIDByName(url.getParameter(SERIALIZATION_KEY))) != null) {\n            return serializationId;\n        }\n\n        // Finally, use the default serialization type\n        return CodecSupport.getIDByName(DefaultSerializationSelector.getDefaultRemotingSerialization());\n    }\n\n    /**\n     * Get the serialization or default serialization\n     *\n     * @param url url\n     * @return {@link String}\n     */\n    public static String serializationOrDefault(URL url) {\n        // noinspection OptionalGetWithoutIsPresent\n        Optional<String> serializations = allSerializations(url).stream().findFirst();\n        return serializations.orElseGet(DefaultSerializationSelector::getDefaultRemotingSerialization);\n    }\n\n    /**\n     * Get the all serializations,ensure insertion order\n     *\n     * @param url url\n     * @return {@link List}<{@link String}>\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static Collection<String> allSerializations(URL url) {\n        // preferSerialization -> serialization -> default serialization\n        Set<String> serializations = new LinkedHashSet<>(preferSerialization(url));\n        Optional.ofNullable(url.getParameter(SERIALIZATION_KEY))\n                .filter(StringUtils::isNotBlank)\n                .ifPresent(serializations::add);\n        serializations.add(DefaultSerializationSelector.getDefaultRemotingSerialization());\n        return Collections.unmodifiableSet(serializations);\n    }\n\n    /**\n     * Prefer Serialization\n     *\n     * @param url url\n     * @return {@link List}<{@link String}>\n     */\n    public static List<String> preferSerialization(URL url) {\n        String preferSerialization = url.getParameter(PREFER_SERIALIZATION_KEY);\n        if (StringUtils.isNotBlank(preferSerialization)) {\n            return Collections.unmodifiableList(StringUtils.splitToList(preferSerialization, ','));\n        }\n        return Collections.emptyList();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.Codec2",
    "content": "transport=org.apache.dubbo.remoting.transport.codec.TransportCodec\ntelnet=org.apache.dubbo.remoting.telnet.codec.TelnetCodec\nexchange=org.apache.dubbo.remoting.exchange.codec.ExchangeCodec\ndefault=org.apache.dubbo.remoting.api.pu.DefaultCodec\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.Dispatcher",
    "content": "all=org.apache.dubbo.remoting.transport.dispatcher.all.AllDispatcher\ndirect=org.apache.dubbo.remoting.transport.dispatcher.direct.DirectDispatcher\nmessage=org.apache.dubbo.remoting.transport.dispatcher.message.MessageOnlyDispatcher\nexecution=org.apache.dubbo.remoting.transport.dispatcher.execution.ExecutionDispatcher\nconnection=org.apache.dubbo.remoting.transport.dispatcher.connection.ConnectionOrderedDispatcher"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.api.connection.ConnectionManager",
    "content": "multiple=org.apache.dubbo.remoting.api.connection.MultiplexProtocolConnectionManager\nsingle=org.apache.dubbo.remoting.api.connection.SingleProtocolConnectionManager\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger",
    "content": "header=org.apache.dubbo.remoting.exchange.support.header.HeaderExchanger"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler",
    "content": "clear=org.apache.dubbo.remoting.telnet.support.command.ClearTelnetHandler\nexit=org.apache.dubbo.remoting.telnet.support.command.ExitTelnetHandler\nhelp=org.apache.dubbo.remoting.telnet.support.command.HelpTelnetHandler\nstatus=org.apache.dubbo.remoting.telnet.support.command.StatusTelnetHandler\nlog=org.apache.dubbo.remoting.telnet.support.command.LogTelnetHandler"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/ChannelHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.support.DefaultSerializationSelector;\nimport org.apache.dubbo.remoting.exchange.ExchangeClient;\nimport org.apache.dubbo.remoting.exchange.Exchangers;\nimport org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNDEFINED_ARGUMENT;\n\n/**\n * ChannelHandlerTest\n * <p>\n * mvn clean test -Dtest=*PerformanceClientTest -Dserver=10.20.153.187:9911\n */\nclass ChannelHandlerTest {\n\n    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ChannelHandlerTest.class);\n\n    public static ExchangeClient initClient(String url) {\n        // Create client and build connection\n        ExchangeClient exchangeClient = null;\n        PeformanceTestHandler handler = new PeformanceTestHandler(url);\n        boolean run = true;\n        while (run) {\n            try {\n                exchangeClient = Exchangers.connect(url, handler);\n            } catch (Throwable t) {\n\n                if (t != null\n                        && t.getCause() != null\n                        && t.getCause().getClass() != null\n                        && (t.getCause().getClass() == java.net.ConnectException.class\n                                || t.getCause().getClass() == java.net.ConnectException.class)) {\n\n                } else {\n                    t.printStackTrace();\n                }\n\n                try {\n                    Thread.sleep(50);\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            }\n            if (exchangeClient != null) {\n                run = false;\n            }\n        }\n        return exchangeClient;\n    }\n\n    public static void closeClient(ExchangeClient client) {\n        if (client.isConnected()) {\n            client.close();\n        }\n    }\n\n    @Test\n    void testClient() throws Throwable {\n        // read server info from property\n        if (PerformanceUtils.getProperty(\"server\", null) == null) {\n            logger.warn(CONFIG_UNDEFINED_ARGUMENT, \"\", \"\", \"Please set -Dserver=127.0.0.1:9911\");\n            return;\n        }\n        final String server = System.getProperty(\"server\", \"127.0.0.1:9911\");\n        final String transporter =\n                PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER);\n        final String serialization = PerformanceUtils.getProperty(\n                Constants.SERIALIZATION_KEY, DefaultSerializationSelector.getDefaultRemotingSerialization());\n        final int timeout = PerformanceUtils.getIntProperty(TIMEOUT_KEY, DEFAULT_TIMEOUT);\n        int sleep = PerformanceUtils.getIntProperty(\"sleep\", 60 * 1000 * 60);\n\n        final String url = \"exchange://\" + server + \"?transporter=\" + transporter + \"&serialization=\" + serialization\n                + \"&timeout=\" + timeout;\n        ExchangeClient exchangeClient = initClient(url);\n        Thread.sleep(sleep);\n        closeClient(exchangeClient);\n    }\n\n    static class PeformanceTestHandler extends ExchangeHandlerAdapter {\n        String url = \"\";\n\n        /**\n         * @param url\n         */\n        public PeformanceTestHandler(String url) {\n            super(FrameworkModel.defaultModel());\n            this.url = url;\n        }\n\n        @Override\n        public void connected(Channel channel) throws RemotingException {\n            logger.info(\"connected event,channel;\" + channel);\n        }\n\n        @Override\n        public void disconnected(Channel channel) throws RemotingException {\n            logger.info(\"disconnected event,channel;\" + channel);\n            initClient(url);\n        }\n\n        /* (non-Javadoc)\n         * @see org.apache.dubbo.remoting.transport.support.ChannelHandlerAdapter#caught(org.apache.dubbo.remoting.Channel, java.lang.Throwable)\n         */\n        @Override\n        public void caught(Channel channel, Throwable exception) throws RemotingException {}\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/MockTransporter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.URL;\n\nimport org.mockito.Mockito;\n\npublic class MockTransporter implements Transporter {\n    private RemotingServer server = Mockito.mock(RemotingServer.class);\n    private Client client = Mockito.mock(Client.class);\n\n    @Override\n    public RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException {\n        return server;\n    }\n\n    @Override\n    public Client connect(URL url, ChannelHandler handler) throws RemotingException {\n        return client;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/PerformanceClientCloseTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.support.DefaultSerializationSelector;\nimport org.apache.dubbo.remoting.exchange.ExchangeClient;\nimport org.apache.dubbo.remoting.exchange.Exchangers;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNDEFINED_ARGUMENT;\n\n/**\n * ProformanceClient\n * The test class will report abnormal thread pool, because the judgment on the thread pool concurrency problems produced in DefaultChannelHandler (connected event has been executed asynchronously, judgment, then closed the thread pool, thread pool and execution error, this problem can be specified through the Constants.CHANNEL_HANDLER_KEY=connection.)\n */\nclass PerformanceClientCloseTest {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(PerformanceClientCloseTest.class);\n\n    @Test\n    void testClient() throws Throwable {\n        // read server info from property\n        if (PerformanceUtils.getProperty(\"server\", null) == null) {\n            logger.warn(CONFIG_UNDEFINED_ARGUMENT, \"\", \"\", \"Please set -Dserver=127.0.0.1:9911\");\n            return;\n        }\n        final String server = System.getProperty(\"server\", \"127.0.0.1:9911\");\n        final String transporter =\n                PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER);\n        final String serialization = PerformanceUtils.getProperty(\n                Constants.SERIALIZATION_KEY, DefaultSerializationSelector.getDefaultRemotingSerialization());\n        final int timeout = PerformanceUtils.getIntProperty(TIMEOUT_KEY, DEFAULT_TIMEOUT);\n        final int concurrent = PerformanceUtils.getIntProperty(\"concurrent\", 1);\n        final int runs = PerformanceUtils.getIntProperty(\"runs\", Integer.MAX_VALUE);\n        final String onerror = PerformanceUtils.getProperty(\"onerror\", \"continue\");\n\n        final String url = \"exchange://\" + server + \"?transporter=\" + transporter\n                + \"&serialization=\" + serialization\n                //            + \"&\"+Constants.CHANNEL_HANDLER_KEY+\"=connection\"\n                + \"&timeout=\" + timeout;\n\n        final AtomicInteger count = new AtomicInteger();\n        final AtomicInteger error = new AtomicInteger();\n        for (int n = 0; n < concurrent; n++) {\n            new Thread(new Runnable() {\n                        public void run() {\n                            for (int i = 0; i < runs; i++) {\n                                ExchangeClient client = null;\n                                try {\n                                    client = Exchangers.connect(url);\n                                    int c = count.incrementAndGet();\n                                    if (c % 100 == 0) {\n                                        logger.info(\"count: {}, error: {}\", count.get(), error.get());\n                                    }\n                                } catch (Exception e) {\n                                    error.incrementAndGet();\n                                    e.printStackTrace();\n                                    logger.info(\"count: {}, error: {}\", count.get(), error.get());\n                                    if (\"exit\".equals(onerror)) {\n                                        System.exit(-1);\n                                    } else if (\"break\".equals(onerror)) {\n                                        break;\n                                    } else if (\"sleep\".equals(onerror)) {\n                                        try {\n                                            Thread.sleep(30000);\n                                        } catch (InterruptedException e1) {\n                                        }\n                                    }\n                                } finally {\n                                    if (client != null) {\n                                        client.close();\n                                    }\n                                }\n                            }\n                        }\n                    })\n                    .start();\n        }\n        synchronized (PerformanceServerTest.class) {\n            while (true) {\n                try {\n                    PerformanceServerTest.class.wait();\n                } catch (InterruptedException e) {\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/PerformanceClientFixedTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.support.DefaultSerializationSelector;\nimport org.apache.dubbo.remoting.exchange.ExchangeClient;\nimport org.apache.dubbo.remoting.exchange.Exchangers;\n\nimport java.util.ArrayList;\nimport java.util.Random;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNDEFINED_ARGUMENT;\nimport static org.apache.dubbo.remoting.Constants.CONNECTIONS_KEY;\n\nclass PerformanceClientFixedTest {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(PerformanceClientTest.class);\n\n    @Test\n    void testClient() throws Exception {\n        // read the parameters\n        if (PerformanceUtils.getProperty(\"server\", null) == null) {\n            logger.warn(CONFIG_UNDEFINED_ARGUMENT, \"\", \"\", \"Please set -Dserver=127.0.0.1:9911\");\n            return;\n        }\n        final String server = System.getProperty(\"server\", \"127.0.0.1:9911\");\n        final String transporter =\n                PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER);\n        final String serialization = PerformanceUtils.getProperty(\n                Constants.SERIALIZATION_KEY, DefaultSerializationSelector.getDefaultRemotingSerialization());\n        final int timeout = PerformanceUtils.getIntProperty(TIMEOUT_KEY, DEFAULT_TIMEOUT);\n        // final int length = PerformanceUtils.getIntProperty(\"length\", 1024);\n        final int connectionCount = PerformanceUtils.getIntProperty(CONNECTIONS_KEY, 1);\n        // final int concurrent = PerformanceUtils.getIntProperty(\"concurrent\", 100);\n        // int r = PerformanceUtils.getIntProperty(\"runs\", 10000);\n        // final int runs = r > 0 ? r : Integer.MAX_VALUE;\n        // final String onerror = PerformanceUtils.getProperty(\"onerror\", \"continue\");\n        final String url = \"exchange://\" + server + \"?transporter=\" + transporter + \"&serialization=\" + serialization\n                + \"&timeout=\" + timeout;\n\n        // int idx = server.indexOf(':');\n        Random rd = new Random(connectionCount);\n        ArrayList<ExchangeClient> arrays = new ArrayList<ExchangeClient>();\n        String oneKBlock = null;\n        String messageBlock = null;\n        int s = 0;\n        int f = 0;\n        logger.info(\"initialize arrays \" + url);\n        while (s < connectionCount) {\n            ExchangeClient client = null;\n            try {\n                logger.info(\"open connection \" + s + \" \" + url + arrays.size());\n\n                client = Exchangers.connect(url);\n\n                logger.info(\"run after open\");\n\n                if (client.isConnected()) {\n                    arrays.add(client);\n                    s++;\n                    logger.info(\"open client success \" + s);\n                } else {\n                    logger.info(\"open client failed, try again.\");\n                }\n            } catch (Throwable t) {\n                t.printStackTrace();\n            } finally {\n                if (client != null && !client.isConnected()) {\n                    f++;\n                    logger.info(\"open client failed, try again \" + f);\n                    client.close();\n                }\n            }\n        }\n\n        StringBuilder sb1 = new StringBuilder();\n        Random rd2 = new Random();\n        char[] numbersAndLetters =\n                (\"0123456789abcdefghijklmnopqrstuvwxyz\" + \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\").toCharArray();\n        int size1 = numbersAndLetters.length;\n        for (int j = 0; j < 1024; j++) {\n            sb1.append(numbersAndLetters[rd2.nextInt(size1)]);\n        }\n        oneKBlock = sb1.toString();\n\n        for (int j = 0; j < Integer.MAX_VALUE; j++) {\n            try {\n                String size = \"10\";\n\n                int request_size = 10;\n                try {\n                    request_size = Integer.parseInt(size);\n                } catch (Throwable t) {\n                    request_size = 10;\n                }\n\n                if (messageBlock == null) {\n                    StringBuilder sb = new StringBuilder();\n                    for (int i = 0; i < request_size; i++) {\n                        sb.append(oneKBlock);\n                    }\n                    messageBlock = sb.toString();\n\n                    logger.info(\"set messageBlock to \" + messageBlock);\n                }\n                int index = rd.nextInt(connectionCount);\n                ExchangeClient client = arrays.get(index);\n                // ExchangeClient client = arrays.get(0);\n                String output = (String) client.request(messageBlock).get();\n\n                if (output.lastIndexOf(messageBlock) < 0) {\n                    logger.info(\"send messageBlock;get \" + output);\n                    throw new Throwable(\"return results invalid\");\n                } else {\n                    if (j % 100 == 0) logger.info(\"OK: \" + j);\n                }\n            } catch (Throwable t) {\n                t.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/PerformanceClientMain.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\npublic class PerformanceClientMain {\n\n    public static void main(String[] args) throws Throwable {\n        new PerformanceClientTest().testClient();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/PerformanceClientTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.support.DefaultSerializationSelector;\nimport org.apache.dubbo.remoting.exchange.ExchangeClient;\nimport org.apache.dubbo.remoting.exchange.Exchangers;\nimport org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.text.DecimalFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;\nimport static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNDEFINED_ARGUMENT;\nimport static org.apache.dubbo.remoting.Constants.CONNECTIONS_KEY;\n\n/**\n * PerformanceClientTest\n * <p>\n * mvn clean test -Dtest=*PerformanceClientTest -Dserver=10.20.153.187:9911\n */\nclass PerformanceClientTest {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(PerformanceClientTest.class);\n\n    @Test\n    @SuppressWarnings(\"unchecked\")\n    public void testClient() throws Throwable {\n        // read server info from property\n        if (PerformanceUtils.getProperty(\"server\", null) == null) {\n            logger.warn(CONFIG_UNDEFINED_ARGUMENT, \"\", \"\", \"Please set -Dserver=127.0.0.1:9911\");\n            return;\n        }\n        final String server = System.getProperty(\"server\", \"127.0.0.1:9911\");\n        final String transporter =\n                PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER);\n        final String serialization = PerformanceUtils.getProperty(\n                Constants.SERIALIZATION_KEY, DefaultSerializationSelector.getDefaultRemotingSerialization());\n        final int timeout = PerformanceUtils.getIntProperty(TIMEOUT_KEY, DEFAULT_TIMEOUT);\n        final int length = PerformanceUtils.getIntProperty(\"length\", 1024);\n        final int connections = PerformanceUtils.getIntProperty(CONNECTIONS_KEY, 1);\n        final int concurrent = PerformanceUtils.getIntProperty(\"concurrent\", 100);\n        int r = PerformanceUtils.getIntProperty(\"runs\", 10000);\n        final int runs = r > 0 ? r : Integer.MAX_VALUE;\n        final String onerror = PerformanceUtils.getProperty(\"onerror\", \"continue\");\n\n        final String url = \"exchange://\" + server + \"?transporter=\" + transporter + \"&serialization=\" + serialization\n                + \"&timeout=\" + timeout;\n        // Create clients and build connections\n        final ExchangeClient[] exchangeClients = new ExchangeClient[connections];\n        for (int i = 0; i < connections; i++) {\n            // exchangeClients[i] = Exchangers.connect(url,handler);\n            exchangeClients[i] = Exchangers.connect(url);\n        }\n\n        List<String> serverEnvironment =\n                (List<String>) exchangeClients[0].request(\"environment\").get();\n        List<String> serverScene =\n                (List<String>) exchangeClients[0].request(\"scene\").get();\n\n        // Create some data for test\n        StringBuilder buf = new StringBuilder(length);\n        for (int i = 0; i < length; i++) {\n            buf.append('A');\n        }\n        final String data = buf.toString();\n\n        // counters\n        final AtomicLong count = new AtomicLong();\n        final AtomicLong error = new AtomicLong();\n        final AtomicLong time = new AtomicLong();\n        final AtomicLong all = new AtomicLong();\n\n        // Start multiple threads\n        final CountDownLatch latch = new CountDownLatch(concurrent);\n        for (int i = 0; i < concurrent; i++) {\n            new Thread(new Runnable() {\n                        public void run() {\n                            try {\n                                AtomicInteger index = new AtomicInteger();\n                                long init = System.currentTimeMillis();\n                                for (int i = 0; i < runs; i++) {\n                                    try {\n                                        count.incrementAndGet();\n                                        ExchangeClient client = exchangeClients[index.getAndIncrement() % connections];\n                                        long start = System.currentTimeMillis();\n                                        String result =\n                                                (String) client.request(data).get();\n                                        long end = System.currentTimeMillis();\n                                        if (!data.equals(result)) {\n                                            throw new IllegalStateException(\"Invalid result \" + result);\n                                        }\n                                        time.addAndGet(end - start);\n                                    } catch (Exception e) {\n                                        error.incrementAndGet();\n                                        e.printStackTrace();\n                                        if (\"exit\".equals(onerror)) {\n                                            System.exit(-1);\n                                        } else if (\"break\".equals(onerror)) {\n                                            break;\n                                        } else if (\"sleep\".equals(onerror)) {\n                                            try {\n                                                Thread.sleep(30000);\n                                            } catch (InterruptedException e1) {\n                                            }\n                                        }\n                                    }\n                                }\n                                all.addAndGet(System.currentTimeMillis() - init);\n                            } finally {\n                                latch.countDown();\n                            }\n                        }\n                    })\n                    .start();\n        }\n\n        // Output, tps is not for accuracy, but it reflects the situation to a certain extent.\n        new Thread(new Runnable() {\n                    public void run() {\n                        try {\n                            SimpleDateFormat dateFormat = new SimpleDateFormat(\"HH:mm:ss\");\n                            long lastCount = count.get();\n                            long sleepTime = 2000;\n                            long elapsd = sleepTime / 1000;\n                            boolean bfirst = true;\n                            while (latch.getCount() > 0) {\n                                long c = count.get() - lastCount;\n                                if (!bfirst) // The first time is inaccurate.\n                                logger.info(\"[\" + dateFormat.format(new Date()) + \"] count: \" + count.get()\n                                        + \", error: \" + error.get() + \",tps:\" + (c / elapsd));\n\n                                bfirst = false;\n                                lastCount = count.get();\n                                Thread.sleep(sleepTime);\n                            }\n                        } catch (Exception e) {\n                            e.printStackTrace();\n                        }\n                    }\n                })\n                .start();\n\n        latch.await();\n\n        for (ExchangeClient client : exchangeClients) {\n            if (client.isConnected()) {\n                client.close();\n            }\n        }\n\n        long total = count.get();\n        long failed = error.get();\n        long succeeded = total - failed;\n        long elapsed = time.get();\n        long allElapsed = all.get();\n        long clientElapsed = allElapsed - elapsed;\n        long art = 0;\n        long qps = 0;\n        long throughput = 0;\n        if (elapsed > 0) {\n            art = elapsed / succeeded;\n            qps = concurrent * succeeded * 1000 / elapsed;\n            throughput = concurrent * succeeded * length * 2 * 1000 / elapsed;\n        }\n\n        PerformanceUtils.printBorder();\n        PerformanceUtils.printHeader(\"Dubbo Remoting Performance Test Report\");\n        PerformanceUtils.printBorder();\n        PerformanceUtils.printHeader(\"Test Environment\");\n        PerformanceUtils.printSeparator();\n        for (String item : serverEnvironment) {\n            PerformanceUtils.printBody(\"Server \" + item);\n        }\n        PerformanceUtils.printSeparator();\n        List<String> clientEnvironment = PerformanceUtils.getEnvironment();\n        for (String item : clientEnvironment) {\n            PerformanceUtils.printBody(\"Client \" + item);\n        }\n        PerformanceUtils.printSeparator();\n        PerformanceUtils.printHeader(\"Test Scene\");\n        PerformanceUtils.printSeparator();\n        for (String item : serverScene) {\n            PerformanceUtils.printBody(\"Server \" + item);\n        }\n        PerformanceUtils.printBody(\"Client Transporter: \" + transporter);\n        PerformanceUtils.printBody(\"Serialization: \" + serialization);\n        PerformanceUtils.printBody(\"Response Timeout: \" + timeout + \" ms\");\n        PerformanceUtils.printBody(\"Data Length: \" + length + \" bytes\");\n        PerformanceUtils.printBody(\"Client Shared Connections: \" + connections);\n        PerformanceUtils.printBody(\"Client Concurrent Threads: \" + concurrent);\n        PerformanceUtils.printBody(\"Run Times Per Thread: \" + runs);\n        PerformanceUtils.printSeparator();\n        PerformanceUtils.printHeader(\"Test Result\");\n        PerformanceUtils.printSeparator();\n        PerformanceUtils.printBody(\n                \"Succeeded Requests: \" + DecimalFormat.getIntegerInstance().format(succeeded));\n        PerformanceUtils.printBody(\"Failed Requests: \" + failed);\n        PerformanceUtils.printBody(\"Client Elapsed Time: \" + clientElapsed + \" ms\");\n        PerformanceUtils.printBody(\"Average Response Time: \" + art + \" ms\");\n        PerformanceUtils.printBody(\"Requests Per Second: \" + qps + \"/s\");\n        PerformanceUtils.printBody(\n                \"Throughput Per Second: \" + DecimalFormat.getIntegerInstance().format(throughput) + \" bytes/s\");\n        PerformanceUtils.printBorder();\n    }\n\n    static class PeformanceTestHandler extends ExchangeHandlerAdapter {\n        public PeformanceTestHandler() {\n            super(FrameworkModel.defaultModel());\n        }\n\n        @Override\n        public void connected(Channel channel) throws RemotingException {\n            logger.info(\"connected event,channel;\" + channel);\n        }\n\n        @Override\n        public void disconnected(Channel channel) throws RemotingException {\n            logger.info(\"disconnected event,channel;\" + channel);\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/PerformanceServerMain.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\npublic class PerformanceServerMain {\n\n    public static void main(String[] args) throws Exception {\n        new PerformanceServerTest().testServer();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/PerformanceServerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.support.DefaultSerializationSelector;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.exchange.ExchangeServer;\nimport org.apache.dubbo.remoting.exchange.Exchangers;\nimport org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter;\nimport org.apache.dubbo.remoting.transport.dispatcher.execution.ExecutionDispatcher;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREADPOOL;\nimport static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREADS;\nimport static org.apache.dubbo.common.constants.CommonConstants.IO_THREADS_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;\nimport static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNDEFINED_ARGUMENT;\nimport static org.apache.dubbo.remoting.Constants.BUFFER_KEY;\nimport static org.apache.dubbo.remoting.Constants.DEFAULT_BUFFER_SIZE;\n\n/**\n * PerformanceServer\n * <p>\n * mvn clean test -Dtest=*PerformanceServerTest -Dport=9911\n */\nclass PerformanceServerTest {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(PerformanceServerTest.class);\n    private static ExchangeServer server = null;\n\n    private static void restartServer(int times, int alive, int sleep) throws Exception {\n        if (server != null && !server.isClosed()) {\n            server.close();\n            Thread.sleep(100);\n        }\n\n        for (int i = 0; i < times; i++) {\n            logger.info(\"restart times:\" + i);\n            server = statServer();\n            if (alive > 0) Thread.sleep(alive);\n            server.close();\n            if (sleep > 0) Thread.sleep(sleep);\n        }\n\n        server = statServer();\n    }\n\n    private static ExchangeServer statServer() throws Exception {\n        final int port = PerformanceUtils.getIntProperty(\"port\", 9911);\n        final String transporter =\n                PerformanceUtils.getProperty(Constants.TRANSPORTER_KEY, Constants.DEFAULT_TRANSPORTER);\n        final String serialization = PerformanceUtils.getProperty(\n                Constants.SERIALIZATION_KEY, DefaultSerializationSelector.getDefaultRemotingSerialization());\n        final String threadpool = PerformanceUtils.getProperty(THREADPOOL_KEY, DEFAULT_THREADPOOL);\n        final int threads = PerformanceUtils.getIntProperty(THREADS_KEY, DEFAULT_THREADS);\n        final int iothreads = PerformanceUtils.getIntProperty(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS);\n        final int buffer = PerformanceUtils.getIntProperty(BUFFER_KEY, DEFAULT_BUFFER_SIZE);\n        final String channelHandler = PerformanceUtils.getProperty(Constants.DISPATCHER_KEY, ExecutionDispatcher.NAME);\n\n        // Start server\n        ExchangeServer server = Exchangers.bind(\n                \"exchange://0.0.0.0:\" + port + \"?transporter=\"\n                        + transporter + \"&serialization=\"\n                        + serialization + \"&threadpool=\" + threadpool\n                        + \"&threads=\" + threads + \"&iothreads=\" + iothreads + \"&buffer=\" + buffer + \"&channel.handler=\"\n                        + channelHandler,\n                new ExchangeHandlerAdapter(FrameworkModel.defaultModel()) {\n                    public String telnet(Channel channel, String message) throws RemotingException {\n                        return \"echo: \" + message + \"\\r\\ntelnet> \";\n                    }\n\n                    public CompletableFuture<Object> reply(ExchangeChannel channel, Object request)\n                            throws RemotingException {\n                        if (\"environment\".equals(request)) {\n                            return CompletableFuture.completedFuture(PerformanceUtils.getEnvironment());\n                        }\n                        if (\"scene\".equals(request)) {\n                            List<String> scene = new ArrayList<String>();\n                            scene.add(\"Transporter: \" + transporter);\n                            scene.add(\"Service Threads: \" + threads);\n                            return CompletableFuture.completedFuture(scene);\n                        }\n                        return CompletableFuture.completedFuture(request);\n                    }\n                });\n\n        return server;\n    }\n\n    private static ExchangeServer statTelnetServer(int port) throws Exception {\n        // Start server\n        ExchangeServer telnetserver = Exchangers.bind(\n                \"exchange://0.0.0.0:\" + port, new ExchangeHandlerAdapter(FrameworkModel.defaultModel()) {\n                    public String telnet(Channel channel, String message) throws RemotingException {\n                        if (message.equals(\"help\")) {\n                            return \"support cmd: \\r\\n\\tstart \\r\\n\\tstop \\r\\n\\tshutdown \\r\\n\\trestart times [alive] [sleep] \\r\\ntelnet>\";\n                        } else if (message.equals(\"stop\")) {\n                            logger.info(\"server closed:\" + server);\n                            server.close();\n                            return \"stop server\\r\\ntelnet>\";\n                        } else if (message.startsWith(\"start\")) {\n                            try {\n                                restartServer(0, 0, 0);\n                            } catch (Exception e) {\n                                e.printStackTrace();\n                            }\n                            return \"start server\\r\\ntelnet>\";\n                        } else if (message.startsWith(\"shutdown\")) {\n                            System.exit(0);\n                            return \"start server\\r\\ntelnet>\";\n                        } else if (message.startsWith(\"channels\")) {\n                            return \"server.getExchangeChannels():\"\n                                    + server.getExchangeChannels().size() + \"\\r\\ntelnet>\";\n                        } else if (message.startsWith(\"restart \")) { // r times [sleep] r 10 or r 10 100\n                            String[] args = message.split(\" \");\n                            int times = Integer.parseInt(args[1]);\n                            int alive = args.length > 2 ? Integer.parseInt(args[2]) : 0;\n                            int sleep = args.length > 3 ? Integer.parseInt(args[3]) : 100;\n                            try {\n                                restartServer(times, alive, sleep);\n                            } catch (Exception e) {\n                                e.printStackTrace();\n                            }\n\n                            return \"restart server,times:\" + times + \" stop alive time: \" + alive + \",sleep time: \"\n                                    + sleep + \" usage:r times [alive] [sleep] \\r\\ntelnet>\";\n                        } else {\n                            return \"echo: \" + message + \"\\r\\ntelnet> \";\n                        }\n                    }\n                });\n\n        return telnetserver;\n    }\n\n    @Test\n    void testServer() throws Exception {\n        // Read port from property\n        if (PerformanceUtils.getProperty(\"port\", null) == null) {\n            logger.warn(CONFIG_UNDEFINED_ARGUMENT, \"\", \"\", \"Please set -Dport=9911\");\n            return;\n        }\n        final int port = PerformanceUtils.getIntProperty(\"port\", 9911);\n        final boolean telnet = PerformanceUtils.getBooleanProperty(\"telnet\", true);\n        if (telnet) statTelnetServer(port + 1);\n        server = statServer();\n\n        synchronized (PerformanceServerTest.class) {\n            while (true) {\n                try {\n                    PerformanceServerTest.class.wait();\n                } catch (InterruptedException e) {\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/PerformanceUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.text.DecimalFormat;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\n\npublic class PerformanceUtils {\n\n    private static final int WIDTH = 64;\n\n    public static String getProperty(String key, String defaultValue) {\n        String value = System.getProperty(key);\n        if (value == null || value.trim().length() == 0 || value.startsWith(\"$\")) {\n            return defaultValue;\n        }\n        return value.trim();\n    }\n\n    public static int getIntProperty(String key, int defaultValue) {\n        String value = System.getProperty(key);\n        if (value == null || value.trim().length() == 0 || value.startsWith(\"$\")) {\n            return defaultValue;\n        }\n        return Integer.parseInt(value.trim());\n    }\n\n    public static boolean getBooleanProperty(String key, boolean defaultValue) {\n        String value = System.getProperty(key);\n        if (value == null || value.trim().length() == 0 || value.startsWith(\"$\")) {\n            return defaultValue;\n        }\n        return Boolean.parseBoolean(value.trim());\n    }\n\n    public static List<String> getEnvironment() {\n        List<String> environment = new ArrayList<String>();\n        environment.add(\"OS: \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.SYSTEM_OS_NAME) + \" \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.SYSTEM_OS_VERSION) + \" \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.OS_ARCH, \"\"));\n        environment.add(\"CPU: \" + Runtime.getRuntime().availableProcessors() + \" cores\");\n        environment.add(\"JVM: \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_VM_NAME) + \" \"\n                + SystemPropertyConfigUtils.getSystemProperty(CommonConstants.SystemProperty.JAVA_RUNTIME_VERSION));\n        environment.add(\"Memory: \"\n                + DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().totalMemory()) + \" bytes (Max: \"\n                + DecimalFormat.getIntegerInstance().format(Runtime.getRuntime().maxMemory()) + \" bytes)\");\n        NetworkInterface ni = PerformanceUtils.getNetworkInterface();\n        if (ni != null) {\n            environment.add(\"Network: \" + ni.getDisplayName());\n        }\n        return environment;\n    }\n\n    public static void printSeparator() {\n        StringBuilder pad = new StringBuilder();\n        for (int i = 0; i < WIDTH; i++) {\n            pad.append('-');\n        }\n    }\n\n    public static void printBorder() {\n        StringBuilder pad = new StringBuilder();\n        for (int i = 0; i < WIDTH; i++) {\n            pad.append('=');\n        }\n    }\n\n    public static void printBody(String msg) {\n        StringBuilder pad = new StringBuilder();\n        int len = WIDTH - msg.length() - 1;\n        if (len > 0) {\n            for (int i = 0; i < len; i++) {\n                pad.append(' ');\n            }\n        }\n    }\n\n    public static void printHeader(String msg) {\n        StringBuilder pad = new StringBuilder();\n        int len = WIDTH - msg.length();\n        if (len > 0) {\n            int half = len / 2;\n            for (int i = 0; i < half; i++) {\n                pad.append(' ');\n            }\n        }\n    }\n\n    public static NetworkInterface getNetworkInterface() {\n        try {\n            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();\n            if (interfaces != null) {\n                while (interfaces.hasMoreElements()) {\n                    try {\n                        return interfaces.nextElement();\n                    } catch (Throwable e) {\n                    }\n                }\n            }\n        } catch (SocketException e) {\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/TelnetServer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.remoting.transport.ChannelHandlerAdapter;\n\npublic class TelnetServer {\n\n    public static void main(String[] args) throws Exception {\n        Transporters.bind(\"telnet://0.0.0.0:23\", new ChannelHandlerAdapter() {\n            @Override\n            public void connected(Channel channel) throws RemotingException {\n                channel.send(\"telnet> \");\n            }\n\n            @Override\n            public void received(Channel channel, Object message) throws RemotingException {\n                channel.send(\"Echo: \" + message + \"\\r\\n\");\n                channel.send(\"telnet> \");\n            }\n        });\n        // Prevent JVM from exiting\n        synchronized (TelnetServer.class) {\n            while (true) {\n                try {\n                    TelnetServer.class.wait();\n                } catch (InterruptedException e) {\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/TransportersTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting;\n\nimport org.apache.dubbo.common.URL;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass TransportersTest {\n    private String url = \"dubbo://127.0.0.1:12345?transporter=mockTransporter\";\n    private ChannelHandler channel = Mockito.mock(ChannelHandler.class);\n\n    @Test\n    void testBind() throws RemotingException {\n        Assertions.assertThrows(RuntimeException.class, () -> Transporters.bind((String) null));\n        Assertions.assertThrows(RuntimeException.class, () -> Transporters.bind((URL) null));\n        Assertions.assertThrows(RuntimeException.class, () -> Transporters.bind(url));\n        Assertions.assertNotNull(Transporters.bind(url, channel));\n        Assertions.assertNotNull(Transporters.bind(url, channel, channel));\n    }\n\n    @Test\n    void testConnect() throws RemotingException {\n        Assertions.assertThrows(RuntimeException.class, () -> Transporters.connect((String) null));\n        Assertions.assertThrows(RuntimeException.class, () -> Transporters.connect((URL) null));\n        Assertions.assertNotNull(Transporters.connect(url));\n        Assertions.assertNotNull(Transporters.connect(url, channel));\n        Assertions.assertNotNull(Transporters.connect(url, channel, channel));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/api/EmptyProtocol.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.api;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.api.pu.ChannelOperator;\nimport org.apache.dubbo.remoting.api.ssl.ContextOperator;\n\npublic class EmptyProtocol implements WireProtocol {\n    @Override\n    public ProtocolDetector detector() {\n        return null;\n    }\n\n    @Override\n    public void configServerProtocolHandler(URL url, ChannelOperator operator) {}\n\n    @Override\n    public void configClientPipeline(URL url, ChannelOperator operator, ContextOperator contextOperator) {}\n\n    @Override\n    public void close() {}\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/AbstractChannelBufferTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.nio.ByteBuffer;\nimport java.util.Arrays;\nimport java.util.Random;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.remoting.buffer.ChannelBuffers.directBuffer;\nimport static org.apache.dubbo.remoting.buffer.ChannelBuffers.wrappedBuffer;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.junit.jupiter.api.Assertions.fail;\n\npublic abstract class AbstractChannelBufferTest {\n\n    private static final int CAPACITY = 4096; // Must be even\n    private static final int BLOCK_SIZE = 128;\n\n    private long seed;\n    private Random random;\n    private ChannelBuffer buffer;\n\n    protected abstract ChannelBuffer newBuffer(int capacity);\n\n    protected abstract ChannelBuffer[] components();\n\n    protected boolean discardReadBytesDoesNotMoveWritableBytes() {\n        return true;\n    }\n\n    @BeforeEach\n    public void init() {\n        buffer = newBuffer(CAPACITY);\n        seed = System.currentTimeMillis();\n        random = new Random(seed);\n    }\n\n    @AfterEach\n    public void dispose() {\n        buffer = null;\n    }\n\n    @Test\n    void initialState() {\n        assertEquals(CAPACITY, buffer.capacity());\n        assertEquals(0, buffer.readerIndex());\n    }\n\n    @Test\n    void readerIndexBoundaryCheck1() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            try {\n                buffer.writerIndex(0);\n            } catch (IndexOutOfBoundsException e) {\n                fail();\n            }\n            buffer.readerIndex(-1);\n        });\n    }\n\n    @Test\n    void readerIndexBoundaryCheck2() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            try {\n                buffer.writerIndex(buffer.capacity());\n            } catch (IndexOutOfBoundsException e) {\n                fail();\n            }\n            buffer.readerIndex(buffer.capacity() + 1);\n        });\n    }\n\n    @Test\n    void readerIndexBoundaryCheck3() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            try {\n                buffer.writerIndex(CAPACITY / 2);\n            } catch (IndexOutOfBoundsException e) {\n                fail();\n            }\n            buffer.readerIndex(CAPACITY * 3 / 2);\n        });\n    }\n\n    @Test\n    void readerIndexBoundaryCheck4() {\n        buffer.writerIndex(0);\n        buffer.readerIndex(0);\n        buffer.writerIndex(buffer.capacity());\n        buffer.readerIndex(buffer.capacity());\n    }\n\n    @Test\n    void writerIndexBoundaryCheck1() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            buffer.writerIndex(-1);\n        });\n    }\n\n    @Test\n    void writerIndexBoundaryCheck2() {\n\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            try {\n                buffer.writerIndex(CAPACITY);\n                buffer.readerIndex(CAPACITY);\n            } catch (IndexOutOfBoundsException e) {\n                fail();\n            }\n            buffer.writerIndex(buffer.capacity() + 1);\n        });\n    }\n\n    @Test\n    void writerIndexBoundaryCheck3() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {\n            try {\n                buffer.writerIndex(CAPACITY);\n                buffer.readerIndex(CAPACITY / 2);\n            } catch (IndexOutOfBoundsException e) {\n                fail();\n            }\n            buffer.writerIndex(CAPACITY / 4);\n        });\n    }\n\n    @Test\n    void writerIndexBoundaryCheck4() {\n        buffer.writerIndex(0);\n        buffer.readerIndex(0);\n        buffer.writerIndex(CAPACITY);\n    }\n\n    @Test\n    void getByteBoundaryCheck1() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.getByte(-1));\n    }\n\n    @Test\n    void getByteBoundaryCheck2() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.getByte(buffer.capacity()));\n    }\n\n    @Test\n    void getByteArrayBoundaryCheck1() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.getBytes(-1, new byte[0]));\n    }\n\n    @Test\n    void getByteArrayBoundaryCheck2() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.getBytes(-1, new byte[0], 0, 0));\n    }\n\n    @Test\n    void getByteBufferBoundaryCheck() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.getBytes(-1, ByteBuffer.allocate(0)));\n    }\n\n    @Test\n    void copyBoundaryCheck1() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.copy(-1, 0));\n    }\n\n    @Test\n    void copyBoundaryCheck2() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.copy(0, buffer.capacity() + 1));\n    }\n\n    @Test\n    void copyBoundaryCheck3() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.copy(buffer.capacity() + 1, 0));\n    }\n\n    @Test\n    void copyBoundaryCheck4() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.copy(buffer.capacity(), 1));\n    }\n\n    @Test\n    void setIndexBoundaryCheck1() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.setIndex(-1, CAPACITY));\n    }\n\n    @Test\n    void setIndexBoundaryCheck2() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.setIndex(CAPACITY / 2, CAPACITY / 4));\n    }\n\n    @Test\n    void setIndexBoundaryCheck3() {\n        Assertions.assertThrows(IndexOutOfBoundsException.class, () -> buffer.setIndex(0, CAPACITY + 1));\n    }\n\n    @Test\n    void getByteBufferState() {\n        ByteBuffer dst = ByteBuffer.allocate(4);\n        dst.position(1);\n        dst.limit(3);\n\n        buffer.setByte(0, (byte) 1);\n        buffer.setByte(1, (byte) 2);\n        buffer.setByte(2, (byte) 3);\n        buffer.setByte(3, (byte) 4);\n        buffer.getBytes(1, dst);\n\n        assertEquals(3, dst.position());\n        assertEquals(3, dst.limit());\n\n        dst.clear();\n        assertEquals(0, dst.get(0));\n        assertEquals(2, dst.get(1));\n        assertEquals(3, dst.get(2));\n        assertEquals(0, dst.get(3));\n    }\n\n    @Test\n    void getDirectByteBufferBoundaryCheck() {\n        Assertions.assertThrows(\n                IndexOutOfBoundsException.class, () -> buffer.getBytes(-1, ByteBuffer.allocateDirect(0)));\n    }\n\n    @Test\n    void getDirectByteBufferState() {\n        ByteBuffer dst = ByteBuffer.allocateDirect(4);\n        dst.position(1);\n        dst.limit(3);\n\n        buffer.setByte(0, (byte) 1);\n        buffer.setByte(1, (byte) 2);\n        buffer.setByte(2, (byte) 3);\n        buffer.setByte(3, (byte) 4);\n        buffer.getBytes(1, dst);\n\n        assertEquals(3, dst.position());\n        assertEquals(3, dst.limit());\n\n        dst.clear();\n        assertEquals(0, dst.get(0));\n        assertEquals(2, dst.get(1));\n        assertEquals(3, dst.get(2));\n        assertEquals(0, dst.get(3));\n    }\n\n    @Test\n    void testRandomByteAccess() {\n        for (int i = 0; i < buffer.capacity(); i++) {\n            byte value = (byte) random.nextInt();\n            buffer.setByte(i, value);\n        }\n\n        random.setSeed(seed);\n        for (int i = 0; i < buffer.capacity(); i++) {\n            byte value = (byte) random.nextInt();\n            assertEquals(value, buffer.getByte(i));\n        }\n    }\n\n    @Test\n    void testSequentialByteAccess() {\n        buffer.writerIndex(0);\n        for (int i = 0; i < buffer.capacity(); i++) {\n            byte value = (byte) random.nextInt();\n            assertEquals(i, buffer.writerIndex());\n            assertTrue(buffer.writable());\n            buffer.writeByte(value);\n        }\n\n        assertEquals(0, buffer.readerIndex());\n        assertEquals(buffer.capacity(), buffer.writerIndex());\n        assertFalse(buffer.writable());\n\n        random.setSeed(seed);\n        for (int i = 0; i < buffer.capacity(); i++) {\n            byte value = (byte) random.nextInt();\n            assertEquals(i, buffer.readerIndex());\n            assertTrue(buffer.readable());\n            assertEquals(value, buffer.readByte());\n        }\n\n        assertEquals(buffer.capacity(), buffer.readerIndex());\n        assertEquals(buffer.capacity(), buffer.writerIndex());\n        assertFalse(buffer.readable());\n        assertFalse(buffer.writable());\n    }\n\n    @Test\n    void testByteArrayTransfer() {\n        byte[] value = new byte[BLOCK_SIZE * 2];\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(value);\n            buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE);\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValue = new byte[BLOCK_SIZE * 2];\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValue);\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            buffer.getBytes(i, value, valueOffset, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue[j], value[j]);\n            }\n        }\n    }\n\n    @Test\n    void testRandomByteArrayTransfer1() {\n        byte[] value = new byte[BLOCK_SIZE];\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(value);\n            buffer.setBytes(i, value);\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValueContent = new byte[BLOCK_SIZE];\n        ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValueContent);\n            buffer.getBytes(i, value);\n            for (int j = 0; j < BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value[j]);\n            }\n        }\n    }\n\n    @Test\n    void testRandomByteArrayTransfer2() {\n        byte[] value = new byte[BLOCK_SIZE * 2];\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(value);\n            buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE);\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValueContent);\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            buffer.getBytes(i, value, valueOffset, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value[j]);\n            }\n        }\n    }\n\n    @Test\n    void testRandomHeapBufferTransfer1() {\n        byte[] valueContent = new byte[BLOCK_SIZE];\n        ChannelBuffer value = wrappedBuffer(valueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(valueContent);\n            value.setIndex(0, BLOCK_SIZE);\n            buffer.setBytes(i, value);\n            assertEquals(BLOCK_SIZE, value.readerIndex());\n            assertEquals(BLOCK_SIZE, value.writerIndex());\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValueContent = new byte[BLOCK_SIZE];\n        ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValueContent);\n            value.clear();\n            buffer.getBytes(i, value);\n            assertEquals(0, value.readerIndex());\n            assertEquals(BLOCK_SIZE, value.writerIndex());\n            for (int j = 0; j < BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value.getByte(j));\n            }\n        }\n    }\n\n    @Test\n    void testRandomHeapBufferTransfer2() {\n        byte[] valueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer value = wrappedBuffer(valueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(valueContent);\n            buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE);\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValueContent);\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            buffer.getBytes(i, value, valueOffset, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value.getByte(j));\n            }\n        }\n    }\n\n    @Test\n    void testRandomDirectBufferTransfer() {\n        byte[] tmp = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer value = directBuffer(BLOCK_SIZE * 2);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(tmp);\n            value.setBytes(0, tmp, 0, value.capacity());\n            buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE);\n        }\n\n        random.setSeed(seed);\n        ChannelBuffer expectedValue = directBuffer(BLOCK_SIZE * 2);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(tmp);\n            expectedValue.setBytes(0, tmp, 0, expectedValue.capacity());\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            buffer.getBytes(i, value, valueOffset, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value.getByte(j));\n            }\n        }\n    }\n\n    @Test\n    void testRandomByteBufferTransfer() {\n        ByteBuffer value = ByteBuffer.allocate(BLOCK_SIZE * 2);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(value.array());\n            value.clear().position(random.nextInt(BLOCK_SIZE));\n            value.limit(value.position() + BLOCK_SIZE);\n            buffer.setBytes(i, value);\n        }\n\n        random.setSeed(seed);\n        ByteBuffer expectedValue = ByteBuffer.allocate(BLOCK_SIZE * 2);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValue.array());\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            value.clear().position(valueOffset).limit(valueOffset + BLOCK_SIZE);\n            buffer.getBytes(i, value);\n            assertEquals(valueOffset + BLOCK_SIZE, value.position());\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.get(j), value.get(j));\n            }\n        }\n    }\n\n    @Test\n    void testSequentialByteArrayTransfer1() {\n        byte[] value = new byte[BLOCK_SIZE];\n        buffer.writerIndex(0);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(value);\n            assertEquals(0, buffer.readerIndex());\n            assertEquals(i, buffer.writerIndex());\n            buffer.writeBytes(value);\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValue = new byte[BLOCK_SIZE];\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValue);\n            assertEquals(i, buffer.readerIndex());\n            assertEquals(CAPACITY, buffer.writerIndex());\n            buffer.readBytes(value);\n            for (int j = 0; j < BLOCK_SIZE; j++) {\n                assertEquals(expectedValue[j], value[j]);\n            }\n        }\n    }\n\n    @Test\n    void testSequentialByteArrayTransfer2() {\n        byte[] value = new byte[BLOCK_SIZE * 2];\n        buffer.writerIndex(0);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(value);\n            assertEquals(0, buffer.readerIndex());\n            assertEquals(i, buffer.writerIndex());\n            int readerIndex = random.nextInt(BLOCK_SIZE);\n            buffer.writeBytes(value, readerIndex, BLOCK_SIZE);\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValue = new byte[BLOCK_SIZE * 2];\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValue);\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            assertEquals(i, buffer.readerIndex());\n            assertEquals(CAPACITY, buffer.writerIndex());\n            buffer.readBytes(value, valueOffset, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue[j], value[j]);\n            }\n        }\n    }\n\n    @Test\n    void testSequentialHeapBufferTransfer1() {\n        byte[] valueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer value = wrappedBuffer(valueContent);\n        buffer.writerIndex(0);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(valueContent);\n            assertEquals(0, buffer.readerIndex());\n            assertEquals(i, buffer.writerIndex());\n            buffer.writeBytes(value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE);\n            assertEquals(0, value.readerIndex());\n            assertEquals(valueContent.length, value.writerIndex());\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValueContent);\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            assertEquals(i, buffer.readerIndex());\n            assertEquals(CAPACITY, buffer.writerIndex());\n            buffer.readBytes(value, valueOffset, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value.getByte(j));\n            }\n            assertEquals(0, value.readerIndex());\n            assertEquals(valueContent.length, value.writerIndex());\n        }\n    }\n\n    @Test\n    void testSequentialHeapBufferTransfer2() {\n        byte[] valueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer value = wrappedBuffer(valueContent);\n        buffer.writerIndex(0);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(valueContent);\n            assertEquals(0, buffer.readerIndex());\n            assertEquals(i, buffer.writerIndex());\n            int readerIndex = random.nextInt(BLOCK_SIZE);\n            value.readerIndex(readerIndex);\n            value.writerIndex(readerIndex + BLOCK_SIZE);\n            buffer.writeBytes(value);\n            assertEquals(readerIndex + BLOCK_SIZE, value.writerIndex());\n            assertEquals(value.writerIndex(), value.readerIndex());\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValueContent);\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            assertEquals(i, buffer.readerIndex());\n            assertEquals(CAPACITY, buffer.writerIndex());\n            value.readerIndex(valueOffset);\n            value.writerIndex(valueOffset);\n            buffer.readBytes(value, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value.getByte(j));\n            }\n            assertEquals(valueOffset, value.readerIndex());\n            assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex());\n        }\n    }\n\n    @Test\n    void testSequentialDirectBufferTransfer1() {\n        byte[] valueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer value = directBuffer(BLOCK_SIZE * 2);\n        buffer.writerIndex(0);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(valueContent);\n            value.setBytes(0, valueContent);\n            assertEquals(0, buffer.readerIndex());\n            assertEquals(i, buffer.writerIndex());\n            buffer.writeBytes(value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE);\n            assertEquals(0, value.readerIndex());\n            assertEquals(0, value.writerIndex());\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValueContent);\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            value.setBytes(0, valueContent);\n            assertEquals(i, buffer.readerIndex());\n            assertEquals(CAPACITY, buffer.writerIndex());\n            buffer.readBytes(value, valueOffset, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value.getByte(j));\n            }\n            assertEquals(0, value.readerIndex());\n            assertEquals(0, value.writerIndex());\n        }\n    }\n\n    @Test\n    void testSequentialDirectBufferTransfer2() {\n        byte[] valueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer value = directBuffer(BLOCK_SIZE * 2);\n        buffer.writerIndex(0);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(valueContent);\n            value.setBytes(0, valueContent);\n            assertEquals(0, buffer.readerIndex());\n            assertEquals(i, buffer.writerIndex());\n            int readerIndex = random.nextInt(BLOCK_SIZE);\n            value.readerIndex(0);\n            value.writerIndex(readerIndex + BLOCK_SIZE);\n            value.readerIndex(readerIndex);\n            buffer.writeBytes(value);\n            assertEquals(readerIndex + BLOCK_SIZE, value.writerIndex());\n            assertEquals(value.writerIndex(), value.readerIndex());\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValueContent);\n            value.setBytes(0, valueContent);\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            assertEquals(i, buffer.readerIndex());\n            assertEquals(CAPACITY, buffer.writerIndex());\n            value.readerIndex(valueOffset);\n            value.writerIndex(valueOffset);\n            buffer.readBytes(value, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value.getByte(j));\n            }\n            assertEquals(valueOffset, value.readerIndex());\n            assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex());\n        }\n    }\n\n    @Test\n    void testSequentialByteBufferBackedHeapBufferTransfer1() {\n        byte[] valueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer value = wrappedBuffer(ByteBuffer.allocate(BLOCK_SIZE * 2));\n        value.writerIndex(0);\n        buffer.writerIndex(0);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(valueContent);\n            value.setBytes(0, valueContent);\n            assertEquals(0, buffer.readerIndex());\n            assertEquals(i, buffer.writerIndex());\n            buffer.writeBytes(value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE);\n            assertEquals(0, value.readerIndex());\n            assertEquals(0, value.writerIndex());\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValueContent);\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            value.setBytes(0, valueContent);\n            assertEquals(i, buffer.readerIndex());\n            assertEquals(CAPACITY, buffer.writerIndex());\n            buffer.readBytes(value, valueOffset, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value.getByte(j));\n            }\n            assertEquals(0, value.readerIndex());\n            assertEquals(0, value.writerIndex());\n        }\n    }\n\n    @Test\n    void testSequentialByteBufferBackedHeapBufferTransfer2() {\n        byte[] valueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer value = wrappedBuffer(ByteBuffer.allocate(BLOCK_SIZE * 2));\n        value.writerIndex(0);\n        buffer.writerIndex(0);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(valueContent);\n            value.setBytes(0, valueContent);\n            assertEquals(0, buffer.readerIndex());\n            assertEquals(i, buffer.writerIndex());\n            int readerIndex = random.nextInt(BLOCK_SIZE);\n            value.readerIndex(0);\n            value.writerIndex(readerIndex + BLOCK_SIZE);\n            value.readerIndex(readerIndex);\n            buffer.writeBytes(value);\n            assertEquals(readerIndex + BLOCK_SIZE, value.writerIndex());\n            assertEquals(value.writerIndex(), value.readerIndex());\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValueContent = new byte[BLOCK_SIZE * 2];\n        ChannelBuffer expectedValue = wrappedBuffer(expectedValueContent);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValueContent);\n            value.setBytes(0, valueContent);\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            assertEquals(i, buffer.readerIndex());\n            assertEquals(CAPACITY, buffer.writerIndex());\n            value.readerIndex(valueOffset);\n            value.writerIndex(valueOffset);\n            buffer.readBytes(value, BLOCK_SIZE);\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.getByte(j), value.getByte(j));\n            }\n            assertEquals(valueOffset, value.readerIndex());\n            assertEquals(valueOffset + BLOCK_SIZE, value.writerIndex());\n        }\n    }\n\n    @Test\n    void testSequentialByteBufferTransfer() {\n        buffer.writerIndex(0);\n        ByteBuffer value = ByteBuffer.allocate(BLOCK_SIZE * 2);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(value.array());\n            value.clear().position(random.nextInt(BLOCK_SIZE));\n            value.limit(value.position() + BLOCK_SIZE);\n            buffer.writeBytes(value);\n        }\n\n        random.setSeed(seed);\n        ByteBuffer expectedValue = ByteBuffer.allocate(BLOCK_SIZE * 2);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValue.array());\n            int valueOffset = random.nextInt(BLOCK_SIZE);\n            value.clear().position(valueOffset).limit(valueOffset + BLOCK_SIZE);\n            buffer.readBytes(value);\n            assertEquals(valueOffset + BLOCK_SIZE, value.position());\n            for (int j = valueOffset; j < valueOffset + BLOCK_SIZE; j++) {\n                assertEquals(expectedValue.get(j), value.get(j));\n            }\n        }\n    }\n\n    @Test\n    void testSequentialCopiedBufferTransfer1() {\n        buffer.writerIndex(0);\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            byte[] value = new byte[BLOCK_SIZE];\n            random.nextBytes(value);\n            assertEquals(0, buffer.readerIndex());\n            assertEquals(i, buffer.writerIndex());\n            buffer.writeBytes(value);\n        }\n\n        random.setSeed(seed);\n        byte[] expectedValue = new byte[BLOCK_SIZE];\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            random.nextBytes(expectedValue);\n            assertEquals(i, buffer.readerIndex());\n            assertEquals(CAPACITY, buffer.writerIndex());\n            ChannelBuffer actualValue = buffer.readBytes(BLOCK_SIZE);\n            assertEquals(wrappedBuffer(expectedValue), actualValue);\n\n            // Make sure if it is a copied buffer.\n            actualValue.setByte(0, (byte) (actualValue.getByte(0) + 1));\n            assertFalse(buffer.getByte(i) == actualValue.getByte(0));\n        }\n    }\n\n    @Test\n    void testStreamTransfer1() throws Exception {\n        byte[] expected = new byte[buffer.capacity()];\n        random.nextBytes(expected);\n\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            ByteArrayInputStream in = new ByteArrayInputStream(expected, i, BLOCK_SIZE);\n            assertEquals(BLOCK_SIZE, buffer.setBytes(i, in, BLOCK_SIZE));\n            assertEquals(-1, buffer.setBytes(i, in, 0));\n        }\n\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            buffer.getBytes(i, out, BLOCK_SIZE);\n        }\n\n        assertTrue(Arrays.equals(expected, out.toByteArray()));\n    }\n\n    @Test\n    void testStreamTransfer2() throws Exception {\n        byte[] expected = new byte[buffer.capacity()];\n        random.nextBytes(expected);\n        buffer.clear();\n\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            ByteArrayInputStream in = new ByteArrayInputStream(expected, i, BLOCK_SIZE);\n            assertEquals(i, buffer.writerIndex());\n            buffer.writeBytes(in, BLOCK_SIZE);\n            assertEquals(i + BLOCK_SIZE, buffer.writerIndex());\n        }\n\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            assertEquals(i, buffer.readerIndex());\n            buffer.readBytes(out, BLOCK_SIZE);\n            assertEquals(i + BLOCK_SIZE, buffer.readerIndex());\n        }\n\n        assertTrue(Arrays.equals(expected, out.toByteArray()));\n    }\n\n    @Test\n    void testCopy() {\n        for (int i = 0; i < buffer.capacity(); i++) {\n            byte value = (byte) random.nextInt();\n            buffer.setByte(i, value);\n        }\n\n        final int readerIndex = CAPACITY / 3;\n        final int writerIndex = CAPACITY * 2 / 3;\n        buffer.setIndex(readerIndex, writerIndex);\n\n        // Make sure all properties are copied.\n        ChannelBuffer copy = buffer.copy();\n        assertEquals(0, copy.readerIndex());\n        assertEquals(buffer.readableBytes(), copy.writerIndex());\n        assertEquals(buffer.readableBytes(), copy.capacity());\n        for (int i = 0; i < copy.capacity(); i++) {\n            assertEquals(buffer.getByte(i + readerIndex), copy.getByte(i));\n        }\n\n        // Make sure the buffer content is independent from each other.\n        buffer.setByte(readerIndex, (byte) (buffer.getByte(readerIndex) + 1));\n        assertTrue(buffer.getByte(readerIndex) != copy.getByte(0));\n        copy.setByte(1, (byte) (copy.getByte(1) + 1));\n        assertTrue(buffer.getByte(readerIndex + 1) != copy.getByte(1));\n    }\n\n    @Test\n    void testToByteBuffer1() {\n        byte[] value = new byte[buffer.capacity()];\n        random.nextBytes(value);\n        buffer.clear();\n        buffer.writeBytes(value);\n\n        assertEquals(ByteBuffer.wrap(value), buffer.toByteBuffer());\n    }\n\n    @Test\n    void testToByteBuffer2() {\n        byte[] value = new byte[buffer.capacity()];\n        random.nextBytes(value);\n        buffer.clear();\n        buffer.writeBytes(value);\n\n        for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {\n            assertEquals(ByteBuffer.wrap(value, i, BLOCK_SIZE), buffer.toByteBuffer(i, BLOCK_SIZE));\n        }\n    }\n\n    @Test\n    void testSkipBytes1() {\n        buffer.setIndex(CAPACITY / 4, CAPACITY / 2);\n\n        buffer.skipBytes(CAPACITY / 4);\n        assertEquals(CAPACITY / 4 * 2, buffer.readerIndex());\n\n        try {\n            buffer.skipBytes(CAPACITY / 4 + 1);\n            fail();\n        } catch (IndexOutOfBoundsException e) {\n            // Expected\n        }\n\n        // Should remain unchanged.\n        assertEquals(CAPACITY / 4 * 2, buffer.readerIndex());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/ByteBufferBackedChannelBufferTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.nio.ByteBuffer;\n\nclass ByteBufferBackedChannelBufferTest extends AbstractChannelBufferTest {\n\n    private ChannelBuffer buffer;\n\n    @Override\n    protected ChannelBuffer newBuffer(int capacity) {\n        buffer = new ByteBufferBackedChannelBuffer(ByteBuffer.allocate(capacity));\n        return buffer;\n    }\n\n    @Override\n    protected ChannelBuffer[] components() {\n        return new ChannelBuffer[] {buffer};\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/ChannelBufferFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.nio.ByteBuffer;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link DirectChannelBufferFactory}\n * {@link HeapChannelBufferFactory}\n */\nclass ChannelBufferFactoryTest {\n\n    @Test\n    void test() {\n        ChannelBufferFactory directChannelBufferFactory = DirectChannelBufferFactory.getInstance();\n        ChannelBufferFactory heapChannelBufferFactory = HeapChannelBufferFactory.getInstance();\n\n        ChannelBuffer directBuffer1 = directChannelBufferFactory.getBuffer(16);\n        ChannelBuffer directBuffer2 = directChannelBufferFactory.getBuffer(ByteBuffer.allocate(16));\n        ChannelBuffer directBuffer3 = directChannelBufferFactory.getBuffer(new byte[] {1}, 0, 1);\n        Assertions.assertTrue(directBuffer1.isDirect());\n        Assertions.assertTrue(directBuffer2.isDirect());\n        Assertions.assertTrue(directBuffer3.isDirect());\n\n        ChannelBuffer heapBuffer1 = heapChannelBufferFactory.getBuffer(16);\n        ChannelBuffer heapBuffer2 = heapChannelBufferFactory.getBuffer(ByteBuffer.allocate(16));\n        ChannelBuffer heapBuffer3 = heapChannelBufferFactory.getBuffer(new byte[] {1}, 0, 1);\n        Assertions.assertTrue(heapBuffer1.hasArray());\n        Assertions.assertTrue(heapBuffer2.hasArray());\n        Assertions.assertTrue(heapBuffer3.hasArray());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/ChannelBufferStreamTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertSame;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.mock;\n\nclass ChannelBufferStreamTest {\n\n    @Test\n    void testChannelBufferOutputStreamWithNull() {\n        assertThrows(NullPointerException.class, () -> new ChannelBufferOutputStream(null));\n    }\n\n    @Test\n    void testChannelBufferInputStreamWithNull() {\n        assertThrows(NullPointerException.class, () -> new ChannelBufferInputStream(null));\n    }\n\n    @Test\n    void testChannelBufferInputStreamWithNullAndLength() {\n        assertThrows(NullPointerException.class, () -> new ChannelBufferInputStream(null, 0));\n    }\n\n    @Test\n    void testChannelBufferInputStreamWithBadLength() {\n        assertThrows(IllegalArgumentException.class, () -> new ChannelBufferInputStream(mock(ChannelBuffer.class), -1));\n    }\n\n    @Test\n    void testChannelBufferInputStreamWithOutOfBounds() {\n        assertThrows(IndexOutOfBoundsException.class, () -> {\n            ChannelBuffer buf = mock(ChannelBuffer.class);\n            new ChannelBufferInputStream(buf, buf.capacity() + 1);\n        });\n    }\n\n    @Test\n    void testChannelBufferWriteOutAndReadIn() {\n        ChannelBuffer buf = ChannelBuffers.dynamicBuffer();\n        testChannelBufferOutputStream(buf);\n        testChannelBufferInputStream(buf);\n    }\n\n    public void testChannelBufferOutputStream(final ChannelBuffer buf) {\n        try (ChannelBufferOutputStream out = new ChannelBufferOutputStream(buf)) {\n            assertSame(buf, out.buffer());\n            write(out);\n        } catch (IOException ioe) {\n            // ignored\n        }\n    }\n\n    private void write(final ChannelBufferOutputStream out) throws IOException {\n        out.write(new byte[0]);\n        out.write(new byte[] {1, 2, 3, 4});\n        out.write(new byte[] {1, 3, 3, 4}, 0, 0);\n    }\n\n    public void testChannelBufferInputStream(final ChannelBuffer buf) {\n        try (ChannelBufferInputStream in = new ChannelBufferInputStream(buf)) {\n            assertTrue(in.markSupported());\n            in.mark(Integer.MAX_VALUE);\n\n            assertEquals(buf.writerIndex(), in.skip(Long.MAX_VALUE));\n            assertFalse(buf.readable());\n\n            in.reset();\n            assertEquals(0, buf.readerIndex());\n            assertEquals(4, in.skip(4));\n            assertEquals(4, buf.readerIndex());\n            in.reset();\n\n            readBytes(in);\n\n            assertEquals(buf.readerIndex(), in.readBytes());\n        } catch (IOException ioe) {\n            // ignored\n        }\n    }\n\n    private void readBytes(ChannelBufferInputStream in) throws IOException {\n        byte[] tmp = new byte[13];\n        in.read(tmp);\n\n        assertEquals(1, tmp[0]);\n        assertEquals(2, tmp[1]);\n        assertEquals(3, tmp[2]);\n        assertEquals(4, tmp[3]);\n\n        assertEquals(-1, in.read());\n        assertEquals(-1, in.read(tmp));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/ChannelBuffersTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.nio.ByteBuffer;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.remoting.buffer.ChannelBuffers.DEFAULT_CAPACITY;\nimport static org.apache.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;\n\n/**\n * {@link ChannelBuffers}\n */\nclass ChannelBuffersTest {\n    @Test\n    void testDynamicBuffer() {\n        ChannelBuffer channelBuffer = ChannelBuffers.dynamicBuffer();\n        Assertions.assertTrue(channelBuffer instanceof DynamicChannelBuffer);\n        Assertions.assertEquals(channelBuffer.capacity(), DEFAULT_CAPACITY);\n\n        channelBuffer = ChannelBuffers.dynamicBuffer(32, DirectChannelBufferFactory.getInstance());\n        Assertions.assertTrue(channelBuffer instanceof DynamicChannelBuffer);\n        Assertions.assertTrue(channelBuffer.isDirect());\n        Assertions.assertEquals(channelBuffer.capacity(), 32);\n    }\n\n    @Test\n    void testPrefixEquals() {\n        ChannelBuffer bufA = ChannelBuffers.wrappedBuffer(\"abcedfaf\".getBytes());\n        ChannelBuffer bufB = ChannelBuffers.wrappedBuffer(\"abcedfaa\".getBytes());\n        Assertions.assertTrue(ChannelBuffers.equals(bufA, bufB));\n        Assertions.assertTrue(ChannelBuffers.prefixEquals(bufA, bufB, 7));\n        Assertions.assertFalse(ChannelBuffers.prefixEquals(bufA, bufB, 8));\n    }\n\n    @Test\n    void testBuffer() {\n        ChannelBuffer channelBuffer = ChannelBuffers.buffer(DEFAULT_CAPACITY);\n        Assertions.assertTrue(channelBuffer instanceof HeapChannelBuffer);\n        channelBuffer = ChannelBuffers.buffer(0);\n        Assertions.assertEquals(channelBuffer, EMPTY_BUFFER);\n    }\n\n    @Test\n    void testWrappedBuffer() {\n        byte[] bytes = new byte[16];\n        ChannelBuffer channelBuffer = ChannelBuffers.wrappedBuffer(bytes, 0, 15);\n        Assertions.assertTrue(channelBuffer instanceof HeapChannelBuffer);\n        Assertions.assertEquals(channelBuffer.capacity(), 15);\n\n        channelBuffer = ChannelBuffers.wrappedBuffer(new byte[] {});\n        Assertions.assertEquals(channelBuffer, EMPTY_BUFFER);\n\n        ByteBuffer byteBuffer = ByteBuffer.allocate(16);\n        channelBuffer = ChannelBuffers.wrappedBuffer(byteBuffer);\n        Assertions.assertTrue(channelBuffer instanceof HeapChannelBuffer);\n\n        byteBuffer = ByteBuffer.allocateDirect(16);\n        channelBuffer = ChannelBuffers.wrappedBuffer(byteBuffer);\n        Assertions.assertTrue(channelBuffer instanceof ByteBufferBackedChannelBuffer);\n\n        byteBuffer.position(byteBuffer.limit());\n        channelBuffer = ChannelBuffers.wrappedBuffer(byteBuffer);\n        Assertions.assertEquals(channelBuffer, EMPTY_BUFFER);\n    }\n\n    @Test\n    void testDirectBuffer() {\n        ChannelBuffer channelBuffer = ChannelBuffers.directBuffer(0);\n        Assertions.assertEquals(channelBuffer, EMPTY_BUFFER);\n\n        channelBuffer = ChannelBuffers.directBuffer(16);\n        Assertions.assertTrue(channelBuffer instanceof ByteBufferBackedChannelBuffer);\n    }\n\n    @Test\n    void testEqualsHashCodeCompareMethod() {\n        ChannelBuffer buffer1 = ChannelBuffers.buffer(4);\n        byte[] bytes1 = new byte[] {1, 2, 3, 4};\n        buffer1.writeBytes(bytes1);\n\n        ChannelBuffer buffer2 = ChannelBuffers.buffer(4);\n        byte[] bytes2 = new byte[] {1, 2, 3, 4};\n        buffer2.writeBytes(bytes2);\n\n        ChannelBuffer buffer3 = ChannelBuffers.buffer(3);\n        byte[] bytes3 = new byte[] {1, 2, 3};\n        buffer3.writeBytes(bytes3);\n\n        ChannelBuffer buffer4 = ChannelBuffers.buffer(4);\n        byte[] bytes4 = new byte[] {1, 2, 3, 5};\n        buffer4.writeBytes(bytes4);\n\n        Assertions.assertTrue(ChannelBuffers.equals(buffer1, buffer2));\n        Assertions.assertFalse(ChannelBuffers.equals(buffer1, buffer3));\n        Assertions.assertFalse(ChannelBuffers.equals(buffer1, buffer4));\n\n        Assertions.assertTrue(ChannelBuffers.compare(buffer1, buffer2) == 0);\n        Assertions.assertTrue(ChannelBuffers.compare(buffer1, buffer3) > 0);\n        Assertions.assertTrue(ChannelBuffers.compare(buffer1, buffer4) < 0);\n\n        Assertions.assertEquals(ChannelBuffers.hasCode(buffer1), ChannelBuffers.hasCode(buffer2));\n        Assertions.assertNotEquals(ChannelBuffers.hasCode(buffer1), ChannelBuffers.hasCode(buffer3));\n        Assertions.assertNotEquals(ChannelBuffers.hasCode(buffer1), ChannelBuffers.hasCode(buffer4));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/DirectChannelBufferTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport org.junit.jupiter.api.Assertions;\n\nclass DirectChannelBufferTest extends AbstractChannelBufferTest {\n\n    private ChannelBuffer buffer;\n\n    @Override\n    protected ChannelBuffer newBuffer(int capacity) {\n        buffer = ChannelBuffers.directBuffer(capacity);\n        Assertions.assertEquals(0, buffer.writerIndex());\n        return buffer;\n    }\n\n    @Override\n    protected ChannelBuffer[] components() {\n        return new ChannelBuffer[] {buffer};\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/DynamicChannelBufferTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport java.util.Random;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass DynamicChannelBufferTest extends AbstractChannelBufferTest {\n\n    private ChannelBuffer buffer;\n\n    @Override\n    protected ChannelBuffer newBuffer(int length) {\n        buffer = ChannelBuffers.dynamicBuffer(length);\n\n        assertEquals(0, buffer.readerIndex());\n        assertEquals(0, buffer.writerIndex());\n        assertEquals(length, buffer.capacity());\n\n        return buffer;\n    }\n\n    @Override\n    protected ChannelBuffer[] components() {\n        return new ChannelBuffer[] {buffer};\n    }\n\n    @Test\n    void shouldNotFailOnInitialIndexUpdate() {\n        new DynamicChannelBuffer(10).setIndex(0, 10);\n    }\n\n    @Test\n    void shouldNotFailOnInitialIndexUpdate2() {\n        new DynamicChannelBuffer(10).writerIndex(10);\n    }\n\n    @Test\n    void shouldNotFailOnInitialIndexUpdate3() {\n        ChannelBuffer buf = new DynamicChannelBuffer(10);\n        buf.writerIndex(10);\n        buf.readerIndex(10);\n    }\n\n    @Test\n    void ensureWritableBytes() {\n        ChannelBuffer buf = new DynamicChannelBuffer(16);\n        buf.ensureWritableBytes(30);\n        Assertions.assertEquals(buf.capacity(), 32);\n\n        Random random = new Random();\n        byte[] bytes = new byte[126];\n        random.nextBytes(bytes);\n        buf.writeBytes(bytes);\n        Assertions.assertEquals(buf.capacity(), 128);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/HeapChannelBufferTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.buffer;\n\nimport org.hamcrest.MatcherAssert;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.not;\n\nclass HeapChannelBufferTest extends AbstractChannelBufferTest {\n\n    private ChannelBuffer buffer;\n\n    @Override\n    protected ChannelBuffer newBuffer(int capacity) {\n        buffer = ChannelBuffers.buffer(capacity);\n        Assertions.assertEquals(0, buffer.writerIndex());\n        return buffer;\n    }\n\n    @Override\n    protected ChannelBuffer[] components() {\n        return new ChannelBuffer[] {buffer};\n    }\n\n    @Test\n    void testEqualsAndHashcode() {\n        HeapChannelBuffer b1 = new HeapChannelBuffer(\"hello-world\".getBytes());\n        HeapChannelBuffer b2 = new HeapChannelBuffer(\"hello-world\".getBytes());\n\n        MatcherAssert.assertThat(b1.equals(b2), is(true));\n        MatcherAssert.assertThat(b1.hashCode(), is(b2.hashCode()));\n\n        b1 = new HeapChannelBuffer(\"hello-world\".getBytes());\n        b2 = new HeapChannelBuffer(\"hello-worldd\".getBytes());\n\n        MatcherAssert.assertThat(b1.equals(b2), is(false));\n        MatcherAssert.assertThat(b1.hashCode(), not(b2.hashCode()));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/codec/AbstractMockChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.codec;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\n\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class AbstractMockChannel implements Channel {\n    public static final String LOCAL_ADDRESS = \"local\";\n    public static final String REMOTE_ADDRESS = \"remote\";\n    public static final String ERROR_WHEN_SEND = \"error_when_send\";\n    InetSocketAddress localAddress;\n    InetSocketAddress remoteAddress;\n    private URL remoteUrl;\n    private ChannelHandler handler;\n    private boolean isClosed;\n    private volatile boolean closing;\n    private Map<String, Object> attributes = new HashMap<String, Object>(1);\n    private volatile Object receivedMessage = null;\n\n    public AbstractMockChannel() {}\n\n    public AbstractMockChannel(URL remoteUrl) {\n        this.remoteUrl = remoteUrl;\n        this.remoteAddress = NetUtils.toAddress(remoteUrl.getParameter(REMOTE_ADDRESS));\n        this.localAddress = NetUtils.toAddress(remoteUrl.getParameter(LOCAL_ADDRESS));\n    }\n\n    public AbstractMockChannel(ChannelHandler handler) {\n        this.handler = handler;\n    }\n\n    @Override\n    public URL getUrl() {\n        return remoteUrl;\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        return handler;\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return localAddress;\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        if (remoteUrl.getParameter(ERROR_WHEN_SEND, Boolean.FALSE)) {\n            receivedMessage = null;\n            throw new RemotingException(localAddress, remoteAddress, \"mock error\");\n        } else {\n            receivedMessage = message;\n        }\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        send(message);\n    }\n\n    @Override\n    public void close() {\n        close(0);\n    }\n\n    @Override\n    public void close(int timeout) {\n        isClosed = true;\n    }\n\n    @Override\n    public void startClose() {\n        closing = true;\n    }\n\n    @Override\n    public boolean isClosed() {\n        return isClosed;\n    }\n\n    @Override\n    public InetSocketAddress getRemoteAddress() {\n        return remoteAddress;\n    }\n\n    @Override\n    public boolean isConnected() {\n        return isClosed;\n    }\n\n    @Override\n    public boolean hasAttribute(String key) {\n        return attributes.containsKey(key);\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        return attributes.get(key);\n    }\n\n    @Override\n    public void setAttribute(String key, Object value) {\n        attributes.put(key, value);\n    }\n\n    @Override\n    public void removeAttribute(String key) {\n        attributes.remove(key);\n    }\n\n    public Object getReceivedMessage() {\n        return receivedMessage;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/codec/CodecAdapterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.codec;\n\nimport org.apache.dubbo.remoting.transport.codec.CodecAdapter;\n\nimport org.junit.jupiter.api.BeforeEach;\n\nclass CodecAdapterTest extends ExchangeCodecTest {\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        codec = new CodecAdapter(new DeprecatedExchangeCodec());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/codec/DeprecatedExchangeCodec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.codec;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.io.Bytes;\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.common.io.UnsafeByteArrayInputStream;\nimport org.apache.dubbo.common.io.UnsafeByteArrayOutputStream;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.ObjectInput;\nimport org.apache.dubbo.common.serialize.ObjectOutput;\nimport org.apache.dubbo.common.serialize.Serialization;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Codec;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\nimport org.apache.dubbo.remoting.exchange.support.DefaultFuture;\nimport org.apache.dubbo.remoting.transport.CodecSupport;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RESPONSE;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_SKIP_UNUSED_STREAM;\n\nfinal class DeprecatedExchangeCodec extends DeprecatedTelnetCodec implements Codec {\n\n    // header length.\n    protected static final int HEADER_LENGTH = 16;\n    // magic header.\n    protected static final short MAGIC = (short) 0xdabb;\n    protected static final byte MAGIC_HIGH = Bytes.short2bytes(MAGIC)[0];\n    protected static final byte MAGIC_LOW = Bytes.short2bytes(MAGIC)[1];\n    // message flag.\n    protected static final byte FLAG_REQUEST = (byte) 0x80;\n    protected static final byte FLAG_TWOWAY = (byte) 0x40;\n    protected static final byte FLAG_EVENT = (byte) 0x20;\n    protected static final int SERIALIZATION_MASK = 0x1f;\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DeprecatedExchangeCodec.class);\n\n    public Short getMagicCode() {\n        return MAGIC;\n    }\n\n    public void encode(Channel channel, OutputStream os, Object msg) throws IOException {\n        if (msg instanceof Request) {\n            encodeRequest(channel, os, (Request) msg);\n        } else if (msg instanceof Response) {\n            encodeResponse(channel, os, (Response) msg);\n        } else {\n            super.encode(channel, os, msg);\n        }\n    }\n\n    public Object decode(Channel channel, InputStream is) throws IOException {\n        int readable = is.available();\n        byte[] header = new byte[Math.min(readable, HEADER_LENGTH)];\n        is.read(header);\n        return decode(channel, is, readable, header);\n    }\n\n    protected Object decode(Channel channel, InputStream is, int readable, byte[] header) throws IOException {\n        // check magic number.\n        if (readable > 0 && header[0] != MAGIC_HIGH || readable > 1 && header[1] != MAGIC_LOW) {\n            int length = header.length;\n            if (header.length < readable) {\n                header = Bytes.copyOf(header, readable);\n                is.read(header, length, readable - length);\n            }\n            for (int i = 1; i < header.length - 1; i++) {\n                if (header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) {\n                    UnsafeByteArrayInputStream bis = ((UnsafeByteArrayInputStream) is);\n                    bis.position(bis.position() - header.length + i);\n                    header = Bytes.copyOf(header, i);\n                    break;\n                }\n            }\n            return super.decode(channel, is, readable, header);\n        }\n        // check length.\n        if (readable < HEADER_LENGTH) {\n            return NEED_MORE_INPUT;\n        }\n\n        // get data length.\n        int len = Bytes.bytes2int(header, 12);\n        checkPayload(channel, len);\n\n        int tt = len + HEADER_LENGTH;\n        if (readable < tt) {\n            return NEED_MORE_INPUT;\n        }\n\n        // limit input stream.\n        if (readable != tt) is = StreamUtils.limitedInputStream(is, len);\n\n        try {\n            return decodeBody(channel, is, header);\n        } finally {\n            if (is.available() > 0) {\n                try {\n                    if (logger.isWarnEnabled()) {\n                        logger.warn(TRANSPORT_SKIP_UNUSED_STREAM, \"\", \"\", \"Skip input stream \" + is.available());\n                    }\n                    StreamUtils.skipUnusedStream(is);\n                } catch (IOException e) {\n                    logger.warn(TRANSPORT_SKIP_UNUSED_STREAM, \"\", \"\", e.getMessage(), e);\n                }\n            }\n        }\n    }\n\n    protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {\n        byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK);\n        // get request id.\n        long id = Bytes.bytes2long(header, 4);\n        if ((flag & FLAG_REQUEST) == 0) {\n            // decode response.\n            Response res = new Response(id);\n            if ((flag & FLAG_EVENT) != 0) {\n                res.setEvent(true);\n            }\n            // get status.\n            byte status = header[3];\n            res.setStatus(status);\n            try {\n                ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);\n                if (status == Response.OK) {\n                    Object data;\n                    if (res.isHeartbeat()) {\n                        data = decodeHeartbeatData(channel, in);\n                    } else if (res.isEvent()) {\n                        data = decodeEventData(channel, in);\n                    } else {\n                        data = decodeResponseData(channel, in, getRequestData(id));\n                    }\n                    res.setResult(data);\n                } else {\n                    res.setErrorMessage(in.readUTF());\n                }\n            } catch (Throwable t) {\n                res.setStatus(Response.CLIENT_ERROR);\n                res.setErrorMessage(StringUtils.toString(t));\n            }\n            return res;\n        } else {\n            // decode request.\n            Request req = new Request(id);\n            req.setVersion(Version.getProtocolVersion());\n            req.setTwoWay((flag & FLAG_TWOWAY) != 0);\n            if ((flag & FLAG_EVENT) != 0) {\n                req.setEvent(true);\n            }\n            try {\n                ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);\n                Object data;\n                if (req.isHeartbeat()) {\n                    data = decodeHeartbeatData(channel, in);\n                } else if (req.isEvent()) {\n                    data = decodeEventData(channel, in);\n                } else {\n                    data = decodeRequestData(channel, in);\n                }\n                req.setData(data);\n            } catch (Throwable t) {\n                // bad request\n                req.setBroken(true);\n                req.setData(t);\n            }\n            return req;\n        }\n    }\n\n    protected Object getRequestData(long id) {\n        DefaultFuture future = DefaultFuture.getFuture(id);\n        if (future == null) return null;\n        Request req = future.getRequest();\n        if (req == null) return null;\n        return req.getData();\n    }\n\n    protected void encodeRequest(Channel channel, OutputStream os, Request req) throws IOException {\n        Serialization serialization = CodecSupport.getSerialization(channel.getUrl());\n        // header.\n        byte[] header = new byte[HEADER_LENGTH];\n        // set magic number.\n        Bytes.short2bytes(MAGIC, header);\n\n        // set request and serialization flag.\n        header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId());\n\n        if (req.isTwoWay()) header[2] |= FLAG_TWOWAY;\n        if (req.isEvent()) header[2] |= FLAG_EVENT;\n\n        // set request id.\n        Bytes.long2bytes(req.getId(), header, 4);\n\n        // encode request data.\n        UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024);\n        ObjectOutput out = serialization.serialize(channel.getUrl(), bos);\n        if (req.isEvent()) {\n            encodeEventData(channel, out, req.getData());\n        } else {\n            encodeRequestData(channel, out, req.getData());\n        }\n        out.flushBuffer();\n        bos.flush();\n        bos.close();\n        byte[] data = bos.toByteArray();\n        checkPayload(channel, data.length);\n        Bytes.int2bytes(data.length, header, 12);\n\n        // write\n        os.write(header); // write header.\n        os.write(data); // write data.\n    }\n\n    protected void encodeResponse(Channel channel, OutputStream os, Response res) throws IOException {\n        try {\n            Serialization serialization = CodecSupport.getSerialization(channel.getUrl());\n            // header.\n            byte[] header = new byte[HEADER_LENGTH];\n            // set magic number.\n            Bytes.short2bytes(MAGIC, header);\n            // set request and serialization flag.\n            header[2] = serialization.getContentTypeId();\n            if (res.isHeartbeat()) header[2] |= FLAG_EVENT;\n            // set response status.\n            byte status = res.getStatus();\n            header[3] = status;\n            // set request id.\n            Bytes.long2bytes(res.getId(), header, 4);\n\n            UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024);\n            ObjectOutput out = serialization.serialize(channel.getUrl(), bos);\n            // encode response data or error message.\n            if (status == Response.OK) {\n                if (res.isHeartbeat()) {\n                    encodeHeartbeatData(channel, out, res.getResult());\n                } else {\n                    encodeResponseData(channel, out, res.getResult());\n                }\n            } else out.writeUTF(res.getErrorMessage());\n            out.flushBuffer();\n            bos.flush();\n            bos.close();\n\n            byte[] data = bos.toByteArray();\n            checkPayload(channel, data.length);\n            Bytes.int2bytes(data.length, header, 12);\n            // write\n            os.write(header); // write header.\n            os.write(data); // write data.\n        } catch (Throwable t) {\n            // send error message to Consumer, otherwise, Consumer will wait until timeout.\n            if (!res.isEvent() && res.getStatus() != Response.BAD_RESPONSE) {\n                try {\n                    // FIXME log error info in Codec and put all error handle logic in IoHanndler?\n                    logger.warn(\n                            TRANSPORT_FAILED_RESPONSE,\n                            \"\",\n                            \"\",\n                            \"Fail to encode response: \" + res + \", send bad_response info instead, cause: \"\n                                    + t.getMessage(),\n                            t);\n\n                    Response r = new Response(res.getId(), res.getVersion());\n                    if (t instanceof IOException) {\n                        r.setStatus(Response.SERIALIZATION_ERROR);\n                    } else {\n                        r.setStatus(Response.BAD_RESPONSE);\n                    }\n                    r.setErrorMessage(\"Failed to send response: \" + res + \", cause: \" + StringUtils.toString(t));\n                    channel.send(r);\n\n                    return;\n                } catch (RemotingException e) {\n                    logger.warn(\n                            TRANSPORT_FAILED_RESPONSE,\n                            \"\",\n                            \"\",\n                            \"Failed to send bad_response info back: \" + res + \", cause: \" + e.getMessage(),\n                            e);\n                }\n            }\n\n            // Rethrow exception\n            if (t instanceof IOException) {\n                throw (IOException) t;\n            } else if (t instanceof RuntimeException) {\n                throw (RuntimeException) t;\n            } else if (t instanceof Error) {\n                throw (Error) t;\n            } else {\n                throw new RuntimeException(t.getMessage(), t);\n            }\n        }\n    }\n\n    protected Object decodeData(ObjectInput in) throws IOException {\n        return decodeRequestData(in);\n    }\n\n    @Deprecated\n    protected Object decodeHeartbeatData(ObjectInput in) throws IOException {\n        try {\n            return in.readObject();\n        } catch (ClassNotFoundException e) {\n            throw new IOException(StringUtils.toString(\"Read object failed.\", e));\n        }\n    }\n\n    protected Object decodeRequestData(ObjectInput in) throws IOException {\n        try {\n            return in.readObject();\n        } catch (ClassNotFoundException e) {\n            throw new IOException(StringUtils.toString(\"Read object failed.\", e));\n        }\n    }\n\n    protected Object decodeResponseData(ObjectInput in) throws IOException {\n        try {\n            return in.readObject();\n        } catch (ClassNotFoundException e) {\n            throw new IOException(StringUtils.toString(\"Read object failed.\", e));\n        }\n    }\n\n    protected void encodeData(ObjectOutput out, Object data) throws IOException {\n        encodeRequestData(out, data);\n    }\n\n    private void encodeEventData(ObjectOutput out, Object data) throws IOException {\n        out.writeObject(data);\n    }\n\n    @Deprecated\n    protected void encodeHeartbeatData(ObjectOutput out, Object data) throws IOException {\n        encodeEventData(out, data);\n    }\n\n    protected void encodeRequestData(ObjectOutput out, Object data) throws IOException {\n        out.writeObject(data);\n    }\n\n    protected void encodeResponseData(ObjectOutput out, Object data) throws IOException {\n        out.writeObject(data);\n    }\n\n    protected Object decodeData(Channel channel, ObjectInput in) throws IOException {\n        return decodeRequestData(channel, in);\n    }\n\n    protected Object decodeEventData(Channel channel, ObjectInput in) throws IOException {\n        try {\n            return in.readObject();\n        } catch (ClassNotFoundException e) {\n            throw new IOException(StringUtils.toString(\"Read object failed.\", e));\n        }\n    }\n\n    @Deprecated\n    protected Object decodeHeartbeatData(Channel channel, ObjectInput in) throws IOException {\n        try {\n            return in.readObject();\n        } catch (ClassNotFoundException e) {\n            throw new IOException(StringUtils.toString(\"Read object failed.\", e));\n        }\n    }\n\n    protected Object decodeRequestData(Channel channel, ObjectInput in) throws IOException {\n        return decodeRequestData(in);\n    }\n\n    protected Object decodeResponseData(Channel channel, ObjectInput in) throws IOException {\n        return decodeResponseData(in);\n    }\n\n    protected Object decodeResponseData(Channel channel, ObjectInput in, Object requestData) throws IOException {\n        return decodeResponseData(channel, in);\n    }\n\n    protected void encodeData(Channel channel, ObjectOutput out, Object data) throws IOException {\n        encodeRequestData(channel, out, data);\n    }\n\n    private void encodeEventData(Channel channel, ObjectOutput out, Object data) throws IOException {\n        encodeEventData(out, data);\n    }\n\n    @Deprecated\n    protected void encodeHeartbeatData(Channel channel, ObjectOutput out, Object data) throws IOException {\n        encodeHeartbeatData(out, data);\n    }\n\n    protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException {\n        encodeRequestData(out, data);\n    }\n\n    protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException {\n        encodeResponseData(out, data);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/codec/DeprecatedTelnetCodec.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.codec;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.logger.LoggerFactory;\nimport org.apache.dubbo.common.serialize.ObjectOutput;\nimport org.apache.dubbo.common.utils.NetUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Codec;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.transport.CodecSupport;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_EXCEED_PAYLOAD_LIMIT;\nimport static org.apache.dubbo.remoting.Constants.CHARSET_KEY;\n\npublic class DeprecatedTelnetCodec implements Codec {\n\n    private static final ErrorTypeAwareLogger logger =\n            LoggerFactory.getErrorTypeAwareLogger(DeprecatedTelnetCodec.class);\n\n    private static final String HISTORY_LIST_KEY = \"telnet.history.list\";\n\n    private static final String HISTORY_INDEX_KEY = \"telnet.history.index\";\n\n    private static final byte[] UP = new byte[] {27, 91, 65};\n\n    private static final byte[] DOWN = new byte[] {27, 91, 66};\n\n    private static final List<?> ENTER = Arrays.asList(\n            new Object[] {new byte[] {'\\r', '\\n'} /* Windows Enter */, new byte[] {'\\n'} /* Linux Enter */});\n\n    private static final List<?> EXIT = Arrays.asList(new Object[] {\n        new byte[] {3} /* Windows Ctrl+C */,\n        new byte[] {-1, -12, -1, -3, 6} /* Linux Ctrl+C */,\n        new byte[] {-1, -19, -1, -3, 6} /* Linux Pause */\n    });\n\n    static void checkPayload(Channel channel, long size) throws IOException {\n        int payload = Constants.DEFAULT_PAYLOAD;\n        if (channel != null && channel.getUrl() != null) {\n            payload = channel.getUrl().getPositiveParameter(Constants.PAYLOAD_KEY, Constants.DEFAULT_PAYLOAD);\n        }\n        if (size > payload) {\n            IOException e = new IOException(\n                    \"Data length too large: \" + size + \", max payload: \" + payload + \", channel: \" + channel);\n            logger.error(TRANSPORT_EXCEED_PAYLOAD_LIMIT, \"\", \"\", e.getMessage(), e);\n            throw e;\n        }\n    }\n\n    private static Charset getCharset(Channel channel) {\n        if (channel != null) {\n            Object attribute = channel.getAttribute(CHARSET_KEY);\n            if (attribute instanceof String) {\n                try {\n                    return Charset.forName((String) attribute);\n                } catch (Throwable t) {\n                    logger.warn(t.getMessage(), t);\n                }\n            } else if (attribute instanceof Charset) {\n                return (Charset) attribute;\n            }\n            URL url = channel.getUrl();\n            if (url != null) {\n                String parameter = url.getParameter(CHARSET_KEY);\n                if (StringUtils.isNotEmpty(parameter)) {\n                    try {\n                        return Charset.forName(parameter);\n                    } catch (Throwable t) {\n                        logger.warn(t.getMessage(), t);\n                    }\n                }\n            }\n        }\n        try {\n            return Charset.forName(\"GBK\");\n        } catch (Throwable t) {\n            logger.warn(t.getMessage(), t);\n        }\n        return Charset.defaultCharset();\n    }\n\n    private static String toString(byte[] message, Charset charset) throws UnsupportedEncodingException {\n        byte[] copy = new byte[message.length];\n        int index = 0;\n        for (int i = 0; i < message.length; i++) {\n            byte b = message[i];\n            if (b == '\\b') { // backspace\n                if (index > 0) {\n                    index--;\n                }\n                if (i > 2 && message[i - 2] < 0) { // double byte char\n                    if (index > 0) {\n                        index--;\n                    }\n                }\n            } else if (b == 27) { // escape\n                if (i < message.length - 4 && message[i + 4] == 126) {\n                    i = i + 4;\n                } else if (i < message.length - 3 && message[i + 3] == 126) {\n                    i = i + 3;\n                } else if (i < message.length - 2) {\n                    i = i + 2;\n                }\n            } else if (b == -1\n                    && i < message.length - 2\n                    && (message[i + 1] == -3 || message[i + 1] == -5)) { // handshake\n                i = i + 2;\n            } else {\n                copy[index++] = message[i];\n            }\n        }\n        if (index == 0) {\n            return \"\";\n        }\n        return new String(copy, 0, index, charset.name()).trim();\n    }\n\n    private static boolean isEquals(byte[] message, byte[] command) throws IOException {\n        return message.length == command.length && endsWith(message, command);\n    }\n\n    private static boolean endsWith(byte[] message, byte[] command) throws IOException {\n        if (message.length < command.length) {\n            return false;\n        }\n        int offset = message.length - command.length;\n        for (int i = command.length - 1; i >= 0; i--) {\n            if (message[offset + i] != command[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    protected boolean isClientSide(Channel channel) {\n        String side = (String) channel.getAttribute(SIDE_KEY);\n        if (\"client\".equals(side)) {\n            return true;\n        } else if (\"server\".equals(side)) {\n            return false;\n        } else {\n            InetSocketAddress address = channel.getRemoteAddress();\n            URL url = channel.getUrl();\n            boolean client = url.getPort() == address.getPort()\n                    && NetUtils.filterLocalHost(url.getIp())\n                            .equals(NetUtils.filterLocalHost(\n                                    address.getAddress().getHostAddress()));\n            channel.setAttribute(SIDE_KEY, client ? \"client\" : \"server\");\n            return client;\n        }\n    }\n\n    public void encode(Channel channel, OutputStream output, Object message) throws IOException {\n        if (message instanceof String) {\n            if (isClientSide(channel)) {\n                message = message + \"\\r\\n\";\n            }\n            byte[] msgData = ((String) message).getBytes(getCharset(channel).name());\n            output.write(msgData);\n            output.flush();\n        } else {\n            ObjectOutput objectOutput =\n                    CodecSupport.getSerialization(channel.getUrl()).serialize(channel.getUrl(), output);\n            objectOutput.writeObject(message);\n            objectOutput.flushBuffer();\n        }\n    }\n\n    public Object decode(Channel channel, InputStream is) throws IOException {\n        int readable = is.available();\n        byte[] message = new byte[readable];\n        is.read(message);\n        return decode(channel, is, readable, message);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    protected Object decode(Channel channel, InputStream is, int readable, byte[] message) throws IOException {\n        if (isClientSide(channel)) {\n            return toString(message, getCharset(channel));\n        }\n        checkPayload(channel, readable);\n        if (message == null || message.length == 0) {\n            return NEED_MORE_INPUT;\n        }\n\n        if (message[message.length - 1] == '\\b') { // Windows backspace echo\n            try {\n                boolean doublechar = message.length >= 3 && message[message.length - 3] < 0; // double byte char\n                channel.send(new String(\n                        doublechar ? new byte[] {32, 32, 8, 8} : new byte[] {32, 8},\n                        getCharset(channel).name()));\n            } catch (RemotingException e) {\n                throw new IOException(StringUtils.toString(e));\n            }\n            return NEED_MORE_INPUT;\n        }\n\n        for (Object command : EXIT) {\n            if (isEquals(message, (byte[]) command)) {\n                if (logger.isInfoEnabled()) {\n                    logger.info(new Exception(\n                            \"Close channel \" + channel + \" on exit command: \" + Arrays.toString((byte[]) command)));\n                }\n                channel.close();\n                return null;\n            }\n        }\n\n        boolean up = endsWith(message, UP);\n        boolean down = endsWith(message, DOWN);\n        if (up || down) {\n            LinkedList<String> history = (LinkedList<String>) channel.getAttribute(HISTORY_LIST_KEY);\n            if (history == null || history.size() == 0) {\n                return NEED_MORE_INPUT;\n            }\n            Integer index = (Integer) channel.getAttribute(HISTORY_INDEX_KEY);\n            Integer old = index;\n            if (index == null) {\n                index = history.size() - 1;\n            } else {\n                if (up) {\n                    index = index - 1;\n                    if (index < 0) {\n                        index = history.size() - 1;\n                    }\n                } else {\n                    index = index + 1;\n                    if (index > history.size() - 1) {\n                        index = 0;\n                    }\n                }\n            }\n            if (old == null || !old.equals(index)) {\n                channel.setAttribute(HISTORY_INDEX_KEY, index);\n                String value = history.get(index);\n                if (old != null && old >= 0 && old < history.size()) {\n                    String ov = history.get(old);\n                    StringBuilder buf = new StringBuilder();\n                    for (int i = 0; i < ov.length(); i++) {\n                        buf.append('\\b');\n                    }\n                    for (int i = 0; i < ov.length(); i++) {\n                        buf.append(' ');\n                    }\n                    for (int i = 0; i < ov.length(); i++) {\n                        buf.append('\\b');\n                    }\n                    value = buf.toString() + value;\n                }\n                try {\n                    channel.send(value);\n                } catch (RemotingException e) {\n                    throw new IOException(StringUtils.toString(e));\n                }\n            }\n            return NEED_MORE_INPUT;\n        }\n        for (Object command : EXIT) {\n            if (isEquals(message, (byte[]) command)) {\n                if (logger.isInfoEnabled()) {\n                    logger.info(new Exception(\"Close channel \" + channel + \" on exit command \" + command));\n                }\n                channel.close();\n                return null;\n            }\n        }\n        byte[] enter = null;\n        for (Object command : ENTER) {\n            if (endsWith(message, (byte[]) command)) {\n                enter = (byte[]) command;\n                break;\n            }\n        }\n        if (enter == null) {\n            return NEED_MORE_INPUT;\n        }\n        LinkedList<String> history = (LinkedList<String>) channel.getAttribute(HISTORY_LIST_KEY);\n        Integer index = (Integer) channel.getAttribute(HISTORY_INDEX_KEY);\n        channel.removeAttribute(HISTORY_INDEX_KEY);\n        if (history != null && history.size() > 0 && index != null && index >= 0 && index < history.size()) {\n            String value = history.get(index);\n            if (value != null) {\n                byte[] b1 = value.getBytes(StandardCharsets.UTF_8);\n                if (message != null && message.length > 0) {\n                    byte[] b2 = new byte[b1.length + message.length];\n                    System.arraycopy(b1, 0, b2, 0, b1.length);\n                    System.arraycopy(message, 0, b2, b1.length, message.length);\n                    message = b2;\n                } else {\n                    message = b1;\n                }\n            }\n        }\n        String result = toString(message, getCharset(channel));\n        if (result != null && result.trim().length() > 0) {\n            if (history == null) {\n                history = new LinkedList<String>();\n                channel.setAttribute(HISTORY_LIST_KEY, history);\n            }\n            if (history.size() == 0) {\n                history.addLast(result);\n            } else if (!result.equals(history.getLast())) {\n                history.remove(result);\n                history.addLast(result);\n                if (history.size() > 10) {\n                    history.removeFirst();\n                }\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/codec/ExchangeCodecTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.codec;\n\nimport org.apache.dubbo.common.Version;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.io.Bytes;\nimport org.apache.dubbo.common.io.UnsafeByteArrayOutputStream;\nimport org.apache.dubbo.common.serialize.ObjectOutput;\nimport org.apache.dubbo.common.serialize.Serialization;\nimport org.apache.dubbo.common.serialize.support.DefaultSerializationSelector;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffer;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffers;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\nimport org.apache.dubbo.remoting.exchange.codec.ExchangeCodec;\nimport org.apache.dubbo.remoting.exchange.support.DefaultFuture;\nimport org.apache.dubbo.remoting.telnet.codec.TelnetCodec;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.READONLY_EVENT;\n\n/**\n *\n *         byte 16\n *         0-1 magic code\n *         2 flag\n *         8 - 1-request/0-response\n *         7 - two way\n *         6 - heartbeat\n *         1-5 serialization id\n *         3 status\n *         20 ok\n *         90 error?\n *         4-11 id (long)\n *         12 -15 datalength\n */\nclass ExchangeCodecTest extends TelnetCodecTest {\n    // magic header.\n    private static final short MAGIC = (short) 0xdabb;\n    private static final byte MAGIC_HIGH = (byte) Bytes.short2bytes(MAGIC)[0];\n    private static final byte MAGIC_LOW = (byte) Bytes.short2bytes(MAGIC)[1];\n    Serialization serialization = getSerialization(DefaultSerializationSelector.getDefaultRemotingSerialization());\n    private static final byte SERIALIZATION_BYTE = FrameworkModel.defaultModel()\n            .getExtension(Serialization.class, DefaultSerializationSelector.getDefaultRemotingSerialization())\n            .getContentTypeId();\n\n    private static Serialization getSerialization(String name) {\n        Serialization serialization =\n                ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(name);\n        return serialization;\n    }\n\n    private Object decode(byte[] request) throws IOException {\n        ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(request);\n        AbstractMockChannel channel = getServerSideChannel(url);\n        // decode\n        Object obj = codec.decode(channel, buffer);\n        return obj;\n    }\n\n    private byte[] getRequestBytes(Object obj, byte[] header) throws IOException {\n        // encode request data.\n        UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024);\n        ObjectOutput out = serialization.serialize(url, bos);\n        out.writeObject(obj);\n\n        out.flushBuffer();\n        bos.flush();\n        bos.close();\n        byte[] data = bos.toByteArray();\n        byte[] len = Bytes.int2bytes(data.length);\n        System.arraycopy(len, 0, header, 12, 4);\n        byte[] request = join(header, data);\n        return request;\n    }\n\n    private byte[] getReadonlyEventRequestBytes(Object obj, byte[] header) throws IOException {\n        // encode request data.\n        UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024);\n        ObjectOutput out = serialization.serialize(url, bos);\n        out.writeObject(obj);\n\n        out.flushBuffer();\n        bos.flush();\n        bos.close();\n        byte[] data = bos.toByteArray();\n        //        byte[] len = Bytes.int2bytes(data.length);\n        System.arraycopy(data, 0, header, 12, data.length);\n        byte[] request = join(header, data);\n        return request;\n    }\n\n    private byte[] assemblyDataProtocol(byte[] header) {\n        Person request = new Person();\n        byte[] newbuf = join(header, objectToByte(request));\n        return newbuf;\n    }\n    // ===================================================================================\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        codec = new ExchangeCodec();\n    }\n\n    @Test\n    void test_Decode_Error_MagicNum() throws IOException {\n        HashMap<byte[], Object> inputBytes = new HashMap<byte[], Object>();\n        inputBytes.put(new byte[] {0}, TelnetCodec.DecodeResult.NEED_MORE_INPUT);\n        inputBytes.put(new byte[] {MAGIC_HIGH, 0}, TelnetCodec.DecodeResult.NEED_MORE_INPUT);\n        inputBytes.put(new byte[] {0, MAGIC_LOW}, TelnetCodec.DecodeResult.NEED_MORE_INPUT);\n\n        for (Map.Entry<byte[], Object> entry : inputBytes.entrySet()) {\n            testDecode_assertEquals(assemblyDataProtocol(entry.getKey()), entry.getValue());\n        }\n    }\n\n    @Test\n    void test_Decode_Error_Length() throws IOException {\n        DefaultFuture future = DefaultFuture.newFuture(Mockito.mock(Channel.class), new Request(0), 100000, null);\n\n        byte[] header = new byte[] {MAGIC_HIGH, MAGIC_LOW, SERIALIZATION_BYTE, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n        Person person = new Person();\n        byte[] request = getRequestBytes(person, header);\n\n        Channel channel = getServerSideChannel(url);\n        byte[] baddata = new byte[] {1, 2};\n        ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(join(request, baddata));\n        Response obj = (Response) codec.decode(channel, buffer);\n        Assertions.assertEquals(person, obj.getResult());\n        // only decode necessary bytes\n        Assertions.assertEquals(request.length, buffer.readerIndex());\n\n        future.cancel();\n    }\n\n    @Test\n    void test_Decode_Error_Response_Object() throws IOException {\n        // 00000010-response/oneway/heartbeat=true |20-stats=ok|id=0|length=0\n        byte[] header = new byte[] {MAGIC_HIGH, MAGIC_LOW, SERIALIZATION_BYTE, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n        Person person = new Person();\n        byte[] request = getRequestBytes(person, header);\n        // bad object\n        byte[] badbytes = new byte[] {-1, -2, -3, -4, -3, -4, -3, -4, -3, -4, -3, -4};\n        System.arraycopy(badbytes, 0, request, 21, badbytes.length);\n\n        Response obj = (Response) decode(request);\n        Assertions.assertEquals(90, obj.getStatus());\n    }\n\n    @Test\n    void testInvalidSerializaitonId() throws Exception {\n        byte[] header = new byte[] {MAGIC_HIGH, MAGIC_LOW, (byte) 0x8F, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n        Object obj = decode(header);\n        Assertions.assertTrue(obj instanceof Request);\n        Request request = (Request) obj;\n        Assertions.assertTrue(request.isBroken());\n        Assertions.assertTrue(request.getData() instanceof IOException);\n        header = new byte[] {MAGIC_HIGH, MAGIC_LOW, (byte) 0x1F, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n\n        obj = decode(header);\n        Assertions.assertTrue(obj instanceof Response);\n        Response response = (Response) obj;\n        Assertions.assertEquals(response.getStatus(), Response.CLIENT_ERROR);\n        Assertions.assertTrue(response.getErrorMessage().contains(\"IOException\"));\n    }\n\n    @Test\n    void test_Decode_Check_Payload() throws IOException {\n        byte[] header = new byte[] {MAGIC_HIGH, MAGIC_LOW, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};\n        byte[] request = assemblyDataProtocol(header);\n\n        try {\n            Channel channel = getServerSideChannel(url);\n            ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(request);\n            Object obj = codec.decode(channel, buffer);\n\n            Assertions.assertTrue(obj instanceof Response);\n            Assertions.assertTrue(((Response) obj)\n                    .getErrorMessage()\n                    .startsWith(\"Data length too large: \" + Bytes.bytes2int(new byte[] {1, 1, 1, 1})));\n        } catch (IOException expected) {\n            Assertions.assertTrue(expected.getMessage()\n                    .startsWith(\"Data length too large: \" + Bytes.bytes2int(new byte[] {1, 1, 1, 1})));\n        }\n    }\n\n    @Test\n    void test_Decode_Header_Need_Readmore() throws IOException {\n        byte[] header = new byte[] {MAGIC_HIGH, MAGIC_LOW, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n        testDecode_assertEquals(header, TelnetCodec.DecodeResult.NEED_MORE_INPUT);\n    }\n\n    @Test\n    void test_Decode_Body_Need_Readmore() throws IOException {\n        byte[] header = new byte[] {MAGIC_HIGH, MAGIC_LOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 'a', 'a'};\n        testDecode_assertEquals(header, TelnetCodec.DecodeResult.NEED_MORE_INPUT);\n    }\n\n    @Test\n    void test_Decode_MigicCodec_Contain_ExchangeHeader() throws IOException {\n        byte[] header = new byte[] {0, 0, MAGIC_HIGH, MAGIC_LOW, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n\n        Channel channel = getServerSideChannel(url);\n        ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(header);\n        Object obj = codec.decode(channel, buffer);\n        Assertions.assertEquals(TelnetCodec.DecodeResult.NEED_MORE_INPUT, obj);\n        // If the telnet data and request data are in the same data packet, we should guarantee that the receipt of\n        // request data won't be affected by the factor that telnet does not have an end characters.\n        Assertions.assertEquals(2, buffer.readerIndex());\n    }\n\n    @Test\n    void test_Decode_Return_Response_Person() throws IOException {\n        DefaultFuture future = DefaultFuture.newFuture(Mockito.mock(Channel.class), new Request(0), 100000, null);\n\n        // 00000010-response/oneway/heartbeat=false/hessian |20-stats=ok|id=0|length=0\n        byte[] header = new byte[] {MAGIC_HIGH, MAGIC_LOW, SERIALIZATION_BYTE, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n        Person person = new Person();\n        byte[] request = getRequestBytes(person, header);\n\n        Response obj = (Response) decode(request);\n        Assertions.assertEquals(20, obj.getStatus());\n        Assertions.assertEquals(person, obj.getResult());\n\n        future.cancel();\n    }\n\n    @Test // The status input has a problem, and the read information is wrong when the serialization is serialized.\n    public void test_Decode_Return_Response_Error() throws IOException {\n        byte[] header = new byte[] {MAGIC_HIGH, MAGIC_LOW, SERIALIZATION_BYTE, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n        String errorString = \"encode request data error \";\n        byte[] request = getRequestBytes(errorString, header);\n        Response obj = (Response) decode(request);\n        Assertions.assertEquals(90, obj.getStatus());\n        Assertions.assertEquals(errorString, obj.getErrorMessage());\n    }\n\n    @Test\n    @Disabled(\"Event should not be object.\")\n    void test_Decode_Return_Request_Event_Object() throws IOException {\n        // |10011111|20-stats=ok|id=0|length=0\n        byte[] header = new byte[] {\n            MAGIC_HIGH, MAGIC_LOW, (byte) (SERIALIZATION_BYTE | (byte) 0xe0), 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n        };\n        Person person = new Person();\n        byte[] request = getRequestBytes(person, header);\n\n        System.setProperty(\"deserialization.event.size\", \"100\");\n        Request obj = (Request) decode(request);\n        Assertions.assertEquals(person, obj.getData());\n        Assertions.assertTrue(obj.isTwoWay());\n        Assertions.assertTrue(obj.isEvent());\n        Assertions.assertEquals(Version.getProtocolVersion(), obj.getVersion());\n        System.clearProperty(\"deserialization.event.size\");\n    }\n\n    @Test\n    void test_Decode_Return_Request_Event_String() throws IOException {\n        // |10011111|20-stats=ok|id=0|length=0\n        byte[] header = new byte[] {\n            MAGIC_HIGH, MAGIC_LOW, (byte) (SERIALIZATION_BYTE | (byte) 0xe0), 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n        };\n        String event = READONLY_EVENT;\n        byte[] request = getRequestBytes(event, header);\n\n        Request obj = (Request) decode(request);\n        Assertions.assertEquals(event, obj.getData());\n        Assertions.assertTrue(obj.isTwoWay());\n        Assertions.assertTrue(obj.isEvent());\n        Assertions.assertEquals(Version.getProtocolVersion(), obj.getVersion());\n    }\n\n    @Test\n    void test_Decode_Return_Request_Heartbeat_Object() throws IOException {\n        // |10011111|20-stats=ok|id=0|length=0\n        byte[] header = new byte[] {\n            MAGIC_HIGH, MAGIC_LOW, (byte) (SERIALIZATION_BYTE | (byte) 0xe0), 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n        };\n        byte[] request = getRequestBytes(null, header);\n        Request obj = (Request) decode(request);\n        Assertions.assertNull(obj.getData());\n        Assertions.assertTrue(obj.isTwoWay());\n        Assertions.assertTrue(obj.isHeartbeat());\n        Assertions.assertEquals(Version.getProtocolVersion(), obj.getVersion());\n    }\n\n    @Test\n    @Disabled(\"Event should not be object.\")\n    void test_Decode_Return_Request_Object() throws IOException {\n        // |10011111|20-stats=ok|id=0|length=0\n        byte[] header = new byte[] {\n            MAGIC_HIGH, MAGIC_LOW, (byte) (SERIALIZATION_BYTE | (byte) 0xe0), 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n        };\n        Person person = new Person();\n        byte[] request = getRequestBytes(person, header);\n\n        System.setProperty(\"deserialization.event.size\", \"100\");\n        Request obj = (Request) decode(request);\n        Assertions.assertEquals(person, obj.getData());\n        Assertions.assertTrue(obj.isTwoWay());\n        Assertions.assertFalse(obj.isHeartbeat());\n        Assertions.assertEquals(Version.getProtocolVersion(), obj.getVersion());\n        System.clearProperty(\"deserialization.event.size\");\n    }\n\n    @Test\n    void test_Decode_Error_Request_Object() throws IOException {\n        // 00000010-response/oneway/heartbeat=true |20-stats=ok|id=0|length=0\n        byte[] header = new byte[] {\n            MAGIC_HIGH, MAGIC_LOW, (byte) (SERIALIZATION_BYTE | (byte) 0xe0), 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n        };\n        Person person = new Person();\n        byte[] request = getRequestBytes(person, header);\n        // bad object\n        byte[] badbytes = new byte[] {-1, -2, -3, -4, -3, -4, -3, -4, -3, -4, -3, -4};\n        System.arraycopy(badbytes, 0, request, 21, badbytes.length);\n\n        Request obj = (Request) decode(request);\n        Assertions.assertTrue(obj.isBroken());\n        Assertions.assertTrue(obj.getData() instanceof Throwable);\n    }\n\n    @Test\n    void test_Header_Response_NoSerializationFlag() throws IOException {\n        DefaultFuture future = DefaultFuture.newFuture(Mockito.mock(Channel.class), new Request(0), 100000, null);\n\n        // 00000010-response/oneway/heartbeat=false/noset |20-stats=ok|id=0|length=0\n        byte[] header = new byte[] {MAGIC_HIGH, MAGIC_LOW, SERIALIZATION_BYTE, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n        Person person = new Person();\n        byte[] request = getRequestBytes(person, header);\n\n        Response obj = (Response) decode(request);\n        Assertions.assertEquals(20, obj.getStatus());\n        Assertions.assertEquals(person, obj.getResult());\n\n        future.cancel();\n    }\n\n    @Test\n    void test_Header_Response_Heartbeat() throws IOException {\n        DefaultFuture future = DefaultFuture.newFuture(Mockito.mock(Channel.class), new Request(0), 100000, null);\n\n        // 00000010-response/oneway/heartbeat=true |20-stats=ok|id=0|length=0\n        byte[] header = new byte[] {MAGIC_HIGH, MAGIC_LOW, SERIALIZATION_BYTE, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n        Person person = new Person();\n        byte[] request = getRequestBytes(person, header);\n\n        Response obj = (Response) decode(request);\n        Assertions.assertEquals(20, obj.getStatus());\n        Assertions.assertEquals(person, obj.getResult());\n\n        future.cancel();\n    }\n\n    @Test\n    void test_Encode_Request() throws IOException {\n        ChannelBuffer encodeBuffer = ChannelBuffers.dynamicBuffer(2014);\n        Channel channel = getClientSideChannel(url);\n        Request request = new Request();\n        Person person = new Person();\n        request.setData(person);\n\n        codec.encode(channel, encodeBuffer, request);\n\n        // encode resault check need decode\n        byte[] data = new byte[encodeBuffer.writerIndex()];\n        encodeBuffer.readBytes(data);\n        ChannelBuffer decodeBuffer = ChannelBuffers.wrappedBuffer(data);\n        Request obj = (Request) codec.decode(channel, decodeBuffer);\n        Assertions.assertEquals(request.isBroken(), obj.isBroken());\n        Assertions.assertEquals(request.isHeartbeat(), obj.isHeartbeat());\n        Assertions.assertEquals(request.isTwoWay(), obj.isTwoWay());\n        Assertions.assertEquals(person, obj.getData());\n    }\n\n    @Test\n    @Disabled(\"Event should not be object.\")\n    void test_Encode_Response() throws IOException {\n        DefaultFuture future = DefaultFuture.newFuture(Mockito.mock(Channel.class), new Request(1001), 100000, null);\n\n        ChannelBuffer encodeBuffer = ChannelBuffers.dynamicBuffer(1024);\n        Channel channel = getClientSideChannel(url);\n        Response response = new Response();\n        response.setHeartbeat(true);\n        response.setId(1001L);\n        response.setStatus((byte) 20);\n        response.setVersion(\"11\");\n        Person person = new Person();\n        response.setResult(person);\n\n        codec.encode(channel, encodeBuffer, response);\n        byte[] data = new byte[encodeBuffer.writerIndex()];\n        encodeBuffer.readBytes(data);\n\n        // encode resault check need decode\n        ChannelBuffer decodeBuffer = ChannelBuffers.wrappedBuffer(data);\n        Response obj = (Response) codec.decode(channel, decodeBuffer);\n\n        Assertions.assertEquals(response.getId(), obj.getId());\n        Assertions.assertEquals(response.getStatus(), obj.getStatus());\n        Assertions.assertEquals(response.isHeartbeat(), obj.isHeartbeat());\n        Assertions.assertEquals(person, obj.getResult());\n        // encode response version ??\n        //        Assertions.assertEquals(response.getProtocolVersion(), obj.getVersion());\n\n        future.cancel();\n    }\n\n    @Test\n    void test_Encode_Error_Response() throws IOException {\n        ChannelBuffer encodeBuffer = ChannelBuffers.dynamicBuffer(1024);\n        Channel channel = getClientSideChannel(url);\n        Response response = new Response();\n        response.setHeartbeat(true);\n        response.setId(1001L);\n        response.setStatus((byte) 10);\n        response.setVersion(\"11\");\n        String badString = \"bad\";\n        response.setErrorMessage(badString);\n        Person person = new Person();\n        response.setResult(person);\n\n        codec.encode(channel, encodeBuffer, response);\n        byte[] data = new byte[encodeBuffer.writerIndex()];\n        encodeBuffer.readBytes(data);\n\n        // encode resault check need decode\n        ChannelBuffer decodeBuffer = ChannelBuffers.wrappedBuffer(data);\n        Response obj = (Response) codec.decode(channel, decodeBuffer);\n        Assertions.assertEquals(response.getId(), obj.getId());\n        Assertions.assertEquals(response.getStatus(), obj.getStatus());\n        Assertions.assertEquals(response.isHeartbeat(), obj.isHeartbeat());\n        Assertions.assertEquals(badString, obj.getErrorMessage());\n        Assertions.assertNull(obj.getResult());\n        //        Assertions.assertEquals(response.getProtocolVersion(), obj.getVersion());\n    }\n\n    @Test\n    void testMessageLengthGreaterThanMessageActualLength() throws Exception {\n        Channel channel = getClientSideChannel(url);\n        Request request = new Request(1L);\n        request.setVersion(Version.getProtocolVersion());\n        Date date = new Date();\n        request.setData(date);\n        ChannelBuffer encodeBuffer = ChannelBuffers.dynamicBuffer(1024);\n        codec.encode(channel, encodeBuffer, request);\n        byte[] bytes = new byte[encodeBuffer.writerIndex()];\n        encodeBuffer.readBytes(bytes);\n        int len = Bytes.bytes2int(bytes, 12);\n        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);\n        out.write(bytes, 0, 12);\n        /*\n         * The fill length can not be less than 256, because by default, hessian reads 256 bytes from the stream each time.\n         * Refer Hessian2Input.readBuffer for more details\n         */\n        int padding = 512;\n        out.write(Bytes.int2bytes(len + padding));\n        out.write(bytes, 16, bytes.length - 16);\n        for (int i = 0; i < padding; i++) {\n            out.write(1);\n        }\n        out.write(bytes);\n        /* request|1111...|request */\n        ChannelBuffer decodeBuffer = ChannelBuffers.wrappedBuffer(out.toByteArray());\n        Request decodedRequest = (Request) codec.decode(channel, decodeBuffer);\n        Assertions.assertEquals(date, decodedRequest.getData());\n        Assertions.assertEquals(bytes.length + padding, decodeBuffer.readerIndex());\n        decodedRequest = (Request) codec.decode(channel, decodeBuffer);\n        Assertions.assertEquals(date, decodedRequest.getData());\n    }\n\n    @Test\n    void testMessageLengthExceedPayloadLimitWhenEncode() throws Exception {\n        Request request = new Request(1L);\n        request.setData(\"hello\");\n        ChannelBuffer encodeBuffer = ChannelBuffers.dynamicBuffer(512);\n        AbstractMockChannel channel = getClientSideChannel(url.addParameter(Constants.PAYLOAD_KEY, 4));\n        try {\n            codec.encode(channel, encodeBuffer, request);\n            Assertions.fail();\n        } catch (IOException e) {\n            Assertions.assertTrue(e.getMessage().startsWith(\"Data length too large: \"));\n            Assertions.assertTrue(e.getMessage()\n                    .contains(\"max payload: 4, channel: org.apache.dubbo.remoting.codec.AbstractMockChannel\"));\n        }\n\n        Response response = new Response(1L);\n        response.setResult(\"hello\");\n        encodeBuffer = ChannelBuffers.dynamicBuffer(512);\n        channel = getServerSideChannel(url.addParameter(Constants.PAYLOAD_KEY, 4));\n        codec.encode(channel, encodeBuffer, response);\n        Assertions.assertTrue(channel.getReceivedMessage() instanceof Response);\n        Response receiveMessage = (Response) channel.getReceivedMessage();\n        Assertions.assertEquals(Response.SERIALIZATION_ERROR, receiveMessage.getStatus());\n        Assertions.assertTrue(receiveMessage.getErrorMessage().contains(\"Data length too large: \"));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/codec/TelnetCodecTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.codec;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Codec2;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffer;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffers;\nimport org.apache.dubbo.remoting.telnet.codec.TelnetCodec;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.io.Serializable;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nclass TelnetCodecTest {\n    protected Codec2 codec;\n    byte[] UP = new byte[] {27, 91, 65};\n    byte[] DOWN = new byte[] {27, 91, 66};\n    // ======================================================\n    URL url = URL.valueOf(\"dubbo://10.20.30.40:20880\");\n\n    /**\n     * @throws java.lang.Exception\n     */\n    @BeforeEach\n    public void setUp() throws Exception {\n        codec = new TelnetCodec();\n    }\n\n    protected AbstractMockChannel getServerSideChannel(URL url) {\n        url = url.addParameter(AbstractMockChannel.LOCAL_ADDRESS, url.getAddress())\n                .addParameter(AbstractMockChannel.REMOTE_ADDRESS, \"127.0.0.1:12345\");\n        AbstractMockChannel channel = new AbstractMockChannel(url);\n        return channel;\n    }\n\n    protected AbstractMockChannel getClientSideChannel(URL url) {\n        url = url.addParameter(AbstractMockChannel.LOCAL_ADDRESS, \"127.0.0.1:12345\")\n                .addParameter(AbstractMockChannel.REMOTE_ADDRESS, url.getAddress());\n        AbstractMockChannel channel = new AbstractMockChannel(url);\n        return channel;\n    }\n\n    protected byte[] join(byte[] in1, byte[] in2) {\n        byte[] ret = new byte[in1.length + in2.length];\n        System.arraycopy(in1, 0, ret, 0, in1.length);\n        System.arraycopy(in2, 0, ret, in1.length, in2.length);\n        return ret;\n    }\n\n    protected byte[] objectToByte(Object obj) {\n        byte[] bytes;\n        if (obj instanceof String) {\n            bytes = ((String) obj).getBytes(StandardCharsets.UTF_8);\n        } else if (obj instanceof byte[]) {\n            bytes = (byte[]) obj;\n        } else {\n            try {\n                // object to bytearray\n                ByteArrayOutputStream bo = new ByteArrayOutputStream();\n                ObjectOutputStream oo = new ObjectOutputStream(bo);\n                oo.writeObject(obj);\n                bytes = bo.toByteArray();\n                bo.close();\n                oo.close();\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return bytes;\n    }\n\n    protected Object byteToObject(byte[] objBytes) throws Exception {\n        if (objBytes == null || objBytes.length == 0) {\n            return null;\n        }\n        ByteArrayInputStream bi = new ByteArrayInputStream(objBytes);\n        ObjectInputStream oi = new ObjectInputStream(bi);\n        return oi.readObject();\n    }\n\n    protected void testDecode_assertEquals(byte[] request, Object ret) throws IOException {\n        testDecode_assertEquals(request, ret, true);\n    }\n\n    protected void testDecode_assertEquals(byte[] request, Object ret, boolean isServerside) throws IOException {\n        // init channel\n        Channel channel = isServerside ? getServerSideChannel(url) : getClientSideChannel(url);\n        // init request string\n        ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(request);\n\n        // decode\n        Object obj = codec.decode(channel, buffer);\n        Assertions.assertEquals(ret, obj);\n    }\n\n    protected void testEecode_assertEquals(Object request, byte[] ret, boolean isServerside) throws IOException {\n        // init channel\n        Channel channel = isServerside ? getServerSideChannel(url) : getClientSideChannel(url);\n\n        ChannelBuffer buffer = ChannelBuffers.dynamicBuffer(1024);\n\n        codec.encode(channel, buffer, request);\n        byte[] data = new byte[buffer.readableBytes()];\n        buffer.readBytes(data);\n\n        Assertions.assertEquals(ret.length, data.length);\n        for (int i = 0; i < ret.length; i++) {\n            if (ret[i] != data[i]) {\n                Assertions.fail();\n            }\n        }\n    }\n\n    protected void testDecode_assertEquals(Object request, Object ret) throws IOException {\n        testDecode_assertEquals(request, ret, null);\n    }\n\n    private void testDecode_assertEquals(Object request, Object ret, Object channelReceive) throws IOException {\n        testDecode_assertEquals(null, request, ret, channelReceive);\n    }\n\n    private void testDecode_assertEquals(\n            AbstractMockChannel channel, Object request, Object expectRet, Object channelReceive) throws IOException {\n        // init channel\n        if (channel == null) {\n            channel = getServerSideChannel(url);\n        }\n\n        byte[] buf = objectToByte(request);\n        ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(buf);\n\n        // decode\n        Object obj = codec.decode(channel, buffer);\n        Assertions.assertEquals(expectRet, obj);\n        Assertions.assertEquals(channelReceive, channel.getReceivedMessage());\n    }\n\n    private void testDecode_PersonWithEnterByte(byte[] enterBytes, boolean isNeedMore) throws IOException {\n        // init channel\n        Channel channel = getServerSideChannel(url);\n        // init request string\n        Person request = new Person();\n        byte[] newBuf = join(objectToByte(request), enterBytes);\n        ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(newBuf);\n\n        // decode\n        Object obj = codec.decode(channel, buffer);\n        if (isNeedMore) {\n            Assertions.assertEquals(Codec2.DecodeResult.NEED_MORE_INPUT, obj);\n        } else {\n            Assertions.assertTrue(obj instanceof String, \"return must string \");\n        }\n    }\n\n    private void testDecode_WithExitByte(byte[] exitbytes, boolean isChannelClose) throws IOException {\n        // init channel\n        Channel channel = getServerSideChannel(url);\n        ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(exitbytes);\n\n        // decode\n        codec.decode(channel, buffer);\n        Assertions.assertEquals(isChannelClose, channel.isClosed());\n    }\n\n    @Test\n    void testDecode_String_ClientSide() throws IOException {\n        testDecode_assertEquals(\"aaa\".getBytes(), \"aaa\", false);\n    }\n\n    @Test\n    void testDecode_BlankMessage() throws IOException {\n        testDecode_assertEquals(new byte[] {}, Codec2.DecodeResult.NEED_MORE_INPUT);\n    }\n\n    @Test\n    void testDecode_String_NoEnter() throws IOException {\n        testDecode_assertEquals(\"aaa\", Codec2.DecodeResult.NEED_MORE_INPUT);\n    }\n\n    @Test\n    void testDecode_String_WithEnter() throws IOException {\n        testDecode_assertEquals(\"aaa\\n\", \"aaa\");\n    }\n\n    @Test\n    void testDecode_String_MiddleWithEnter() throws IOException {\n        testDecode_assertEquals(\"aaa\\r\\naaa\", Codec2.DecodeResult.NEED_MORE_INPUT);\n    }\n\n    @Test\n    void testDecode_Person_ObjectOnly() throws IOException {\n        testDecode_assertEquals(new Person(), Codec2.DecodeResult.NEED_MORE_INPUT);\n    }\n\n    @Test\n    void testDecode_Person_WithEnter() throws IOException {\n        testDecode_PersonWithEnterByte(new byte[] {'\\r', '\\n'}, false); // windows end\n        testDecode_PersonWithEnterByte(new byte[] {'\\n', '\\r'}, true);\n        testDecode_PersonWithEnterByte(new byte[] {'\\n'}, false); // linux end\n        testDecode_PersonWithEnterByte(new byte[] {'\\r'}, true);\n        testDecode_PersonWithEnterByte(new byte[] {'\\r', 100}, true);\n    }\n\n    @Test\n    void testDecode_WithExitByte() throws IOException {\n        HashMap<byte[], Boolean> exitBytes = new HashMap<byte[], Boolean>();\n        exitBytes.put(new byte[] {3}, true); /* Windows Ctrl+C */\n        exitBytes.put(new byte[] {1, 3}, false); // must equal the bytes\n        exitBytes.put(new byte[] {-1, -12, -1, -3, 6}, true); /* Linux Ctrl+C */\n        exitBytes.put(new byte[] {1, -1, -12, -1, -3, 6}, false); // must equal the bytes\n        exitBytes.put(new byte[] {-1, -19, -1, -3, 6}, true); /* Linux Pause */\n\n        for (Map.Entry<byte[], Boolean> entry : exitBytes.entrySet()) {\n            testDecode_WithExitByte(entry.getKey(), entry.getValue());\n        }\n    }\n\n    @Test\n    void testDecode_Backspace() throws IOException {\n        // 32 8 first add space and then add backspace.\n        testDecode_assertEquals(new byte[] {'\\b'}, Codec2.DecodeResult.NEED_MORE_INPUT, new String(new byte[] {32, 8}));\n\n        // test chinese\n        byte[] chineseBytes = \"中\".getBytes(StandardCharsets.UTF_8);\n        byte[] request = join(chineseBytes, new byte[] {'\\b'});\n        testDecode_assertEquals(request, Codec2.DecodeResult.NEED_MORE_INPUT, new String(new byte[] {32, 32, 8, 8}));\n        // There may be some problem handling chinese (negative number recognition). Ignoring this problem, the\n        // backspace key is only meaningfully input in a real telnet program.\n        testDecode_assertEquals(\n                new byte[] {'a', 'x', -1, 'x', '\\b'},\n                Codec2.DecodeResult.NEED_MORE_INPUT,\n                new String(new byte[] {32, 32, 8, 8}));\n    }\n\n    @Test\n    void testDecode_Backspace_WithError() throws IOException {\n        Assertions.assertThrows(IOException.class, () -> {\n            url = url.addParameter(AbstractMockChannel.ERROR_WHEN_SEND, Boolean.TRUE.toString());\n            testDecode_Backspace();\n            url = url.removeParameter(AbstractMockChannel.ERROR_WHEN_SEND);\n        });\n    }\n\n    @Test\n    void testDecode_History_UP() throws IOException {\n        // init channel\n        AbstractMockChannel channel = getServerSideChannel(url);\n\n        testDecode_assertEquals(channel, UP, Codec2.DecodeResult.NEED_MORE_INPUT, null);\n\n        String request1 = \"aaa\\n\";\n        Object expected1 = \"aaa\";\n        // init history\n        testDecode_assertEquals(channel, request1, expected1, null);\n\n        testDecode_assertEquals(channel, UP, Codec2.DecodeResult.NEED_MORE_INPUT, expected1);\n    }\n\n    @Test\n    void testDecode_UPorDOWN_WithError() throws IOException {\n        Assertions.assertThrows(IOException.class, () -> {\n            url = url.addParameter(AbstractMockChannel.ERROR_WHEN_SEND, Boolean.TRUE.toString());\n\n            // init channel\n            AbstractMockChannel channel = getServerSideChannel(url);\n\n            testDecode_assertEquals(channel, UP, Codec2.DecodeResult.NEED_MORE_INPUT, null);\n\n            String request1 = \"aaa\\n\";\n            Object expected1 = \"aaa\";\n            // init history\n            testDecode_assertEquals(channel, request1, expected1, null);\n\n            testDecode_assertEquals(channel, UP, Codec2.DecodeResult.NEED_MORE_INPUT, expected1);\n\n            url = url.removeParameter(AbstractMockChannel.ERROR_WHEN_SEND);\n        });\n    }\n\n    // =============================================================================================================================\n    @Test\n    void testEncode_String_ClientSide() throws IOException {\n        testEecode_assertEquals(\"aaa\", \"aaa\\r\\n\".getBytes(), false);\n    }\n\n    /*@Test\n    public void testDecode_History_UP_DOWN_MULTI() throws IOException{\n        AbstractMockChannel channel = getServerSideChannel(url);\n\n        String request1 = \"aaa\\n\";\n        Object expected1 = request1.replace(\"\\n\", \"\");\n        //init history\n        testDecode_assertEquals(channel, request1, expected1, null);\n\n        String request2 = \"bbb\\n\";\n        Object expected2 = request2.replace(\"\\n\", \"\");\n        //init history\n        testDecode_assertEquals(channel, request2, expected2, null);\n\n        String request3 = \"ccc\\n\";\n        Object expected3= request3.replace(\"\\n\", \"\");\n        //init history\n        testDecode_assertEquals(channel, request3, expected3, null);\n\n        byte[] UP = new byte[] {27, 91, 65};\n        byte[] DOWN = new byte[] {27, 91, 66};\n        //history[aaa,bbb,ccc]\n        testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected3);\n        testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3);\n        testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected2);\n        testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1);\n        testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1);\n        testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1);\n        testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected2);\n        testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3);\n        testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3);\n        testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3);\n        testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected2);\n    }*/\n\n    // ======================================================\n    public static class Person implements Serializable {\n        private static final long serialVersionUID = 3362088148941547337L;\n        public String name;\n        public String sex;\n\n        @Override\n        public int hashCode() {\n            final int prime = 31;\n            int result = 1;\n            result = prime * result + ((name == null) ? 0 : name.hashCode());\n            result = prime * result + ((sex == null) ? 0 : sex.hashCode());\n            return result;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) return true;\n            if (obj == null) return false;\n            if (getClass() != obj.getClass()) return false;\n            Person other = (Person) obj;\n            if (name == null) {\n                if (other.name != null) return false;\n            } else if (!name.equals(other.name)) return false;\n            if (sex == null) {\n                if (other.sex != null) return false;\n            } else if (!sex.equals(other.sex)) return false;\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/ExchangersTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.support.ExchangeHandlerDispatcher;\nimport org.apache.dubbo.remoting.exchange.support.Replier;\nimport org.apache.dubbo.remoting.transport.ChannelHandlerAdapter;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass ExchangersTest {\n\n    @Test\n    void testBind() throws RemotingException {\n        String url = \"dubbo://127.0.0.1:12345?exchanger=mockExchanger\";\n        Exchangers.bind(url, Mockito.mock(Replier.class));\n        Exchangers.bind(url, new ChannelHandlerAdapter(), Mockito.mock(Replier.class));\n        Exchangers.bind(url, new ExchangeHandlerDispatcher());\n\n        Assertions.assertThrows(\n                RuntimeException.class, () -> Exchangers.bind((URL) null, new ExchangeHandlerDispatcher()));\n        Assertions.assertThrows(RuntimeException.class, () -> Exchangers.bind(url, (ExchangeHandlerDispatcher) null));\n    }\n\n    @Test\n    void testConnect() throws RemotingException {\n        String url = \"dubbo://127.0.0.1:12345?exchanger=mockExchanger\";\n        Exchangers.connect(url);\n        Exchangers.connect(url, Mockito.mock(Replier.class));\n        Exchangers.connect(URL.valueOf(url), Mockito.mock(Replier.class));\n        Exchangers.connect(url, new ChannelHandlerAdapter(), Mockito.mock(Replier.class));\n        Exchangers.connect(url, new ExchangeHandlerDispatcher());\n\n        Assertions.assertThrows(\n                RuntimeException.class, () -> Exchangers.connect((URL) null, new ExchangeHandlerDispatcher()));\n        Assertions.assertThrows(\n                RuntimeException.class, () -> Exchangers.connect(url, (ExchangeHandlerDispatcher) null));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/MockExchanger.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.RemotingException;\n\nimport org.mockito.Mockito;\n\npublic class MockExchanger implements Exchanger {\n    private ExchangeServer exchangeServer = Mockito.mock(ExchangeServer.class);\n    private ExchangeClient exchangeClient = Mockito.mock(ExchangeClient.class);\n\n    @Override\n    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {\n        return exchangeServer;\n    }\n\n    @Override\n    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {\n        return exchangeClient;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/RequestTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass RequestTest {\n\n    @Test\n    void test() {\n        Request requestStart = new Request();\n\n        Request request = new Request();\n        request.setTwoWay(true);\n        request.setBroken(true);\n        request.setVersion(\"1.0.0\");\n        request.setEvent(true);\n        request.setData(\"data\");\n        request.setPayload(1024);\n\n        Assertions.assertTrue(request.isTwoWay());\n        Assertions.assertTrue(request.isBroken());\n        Assertions.assertTrue(request.isEvent());\n        Assertions.assertEquals(request.getVersion(), \"1.0.0\");\n        Assertions.assertEquals(request.getData(), \"data\");\n        Assertions.assertEquals(requestStart.getId() + 1, request.getId());\n        Assertions.assertEquals(1024, request.getPayload());\n\n        request.setHeartbeat(true);\n        Assertions.assertTrue(request.isHeartbeat());\n\n        Request copiedRequest = request.copy();\n        Assertions.assertEquals(copiedRequest.toString(), request.toString());\n\n        Request copyWithoutData = request.copyWithoutData();\n        Assertions.assertNull(copyWithoutData.getData());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/ResponseTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.HEARTBEAT_EVENT;\n\nclass ResponseTest {\n    @Test\n    void test() {\n        Response response = new Response();\n        response.setStatus(Response.OK);\n        response.setId(1);\n        response.setVersion(\"1.0.0\");\n        response.setResult(\"test\");\n        response.setEvent(HEARTBEAT_EVENT);\n        response.setErrorMessage(\"errorMsg\");\n\n        Assertions.assertTrue(response.isEvent());\n        Assertions.assertTrue(response.isHeartbeat());\n        Assertions.assertEquals(response.getVersion(), \"1.0.0\");\n        Assertions.assertEquals(response.getId(), 1);\n        Assertions.assertEquals(response.getResult(), HEARTBEAT_EVENT);\n        Assertions.assertEquals(response.getErrorMessage(), \"errorMsg\");\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/DefaultFutureTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.threadpool.ThreadlessExecutor;\nimport org.apache.dubbo.common.threadpool.manager.ExecutorRepository;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.TimeoutException;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.handler.MockedChannel;\n\nimport java.time.LocalDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nclass DefaultFutureTest {\n    private static final Logger logger = LoggerFactory.getLogger(DefaultFutureTest.class);\n\n    private static final AtomicInteger index = new AtomicInteger();\n\n    @Test\n    void newFuture() {\n        DefaultFuture future = defaultFuture(3000);\n        Assertions.assertNotNull(future, \"new future return null\");\n    }\n\n    @Test\n    void isDone() {\n        DefaultFuture future = defaultFuture(3000);\n        Assertions.assertTrue(!future.isDone(), \"init future is finished!\");\n\n        // cancel a future\n        future.cancel();\n        Assertions.assertTrue(future.isDone(), \"cancel a future failed!\");\n    }\n\n    /**\n     * for example, it will print like this:\n     * before a future is create , time is : 2018-06-21 15:06:17\n     * after a future is timeout , time is : 2018-06-21 15:06:22\n     * <p>\n     * The exception info print like:\n     * Sending request timeout in client-side by scan timer.\n     * start time: 2018-06-21 15:13:02.215, end time: 2018-06-21 15:13:07.231...\n     */\n    @Test\n    @Disabled\n    public void timeoutNotSend() throws Exception {\n        final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\");\n        logger.info(\n                \"before a future is create , time is : {}\", LocalDateTime.now().format(formatter));\n        // timeout after 5 seconds.\n        DefaultFuture f = defaultFuture(5000);\n        while (!f.isDone()) {\n            // spin\n            Thread.sleep(100);\n        }\n        logger.info(\n                \"after a future is timeout , time is : {}\", LocalDateTime.now().format(formatter));\n\n        // get operate will throw a timeout exception, because the future is timeout.\n        try {\n            f.get();\n        } catch (Exception e) {\n            Assertions.assertTrue(\n                    e.getCause() instanceof TimeoutException, \"catch exception is not timeout exception!\");\n            logger.error(e.getMessage());\n        }\n    }\n\n    /**\n     * for example, it will print like this:\n     * before a future is created, time is : 2023-09-03 18:20:14.535\n     * after a future is timeout, time is : 2023-09-03 18:20:14.669\n     * <p>\n     * The exception info print like:\n     * Sending request timeout in client-side by scan timer.\n     * start time: 2023-09-03 18:20:14.544, end time: 2023-09-03 18:20:14.598...\n     */\n    @Test\n    public void clientTimeoutSend() throws Exception {\n        final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss.SSS\");\n        logger.info(\n                \"before a future is create , time is : {}\", LocalDateTime.now().format(formatter));\n        // timeout after 5 milliseconds.\n        Channel channel = new MockedChannel();\n        Request request = new Request(10);\n        DefaultFuture f = DefaultFuture.newFuture(channel, request, 5, null);\n        System.gc(); // events such as Full GC will increase the time required to send messages.\n\n        // mark the future is sent\n        DefaultFuture.sent(channel, request);\n        while (!f.isDone()) {\n            // spin\n            Thread.sleep(100);\n        }\n        logger.info(\n                \"after a future is timeout , time is : {}\", LocalDateTime.now().format(formatter));\n\n        // get operate will throw a timeout exception, because the future is timeout.\n        try {\n            f.get();\n        } catch (Exception e) {\n            Assertions.assertTrue(\n                    e.getCause() instanceof TimeoutException, \"catch exception is not timeout exception!\");\n            logger.error(e.getMessage());\n            Assertions.assertTrue(e.getMessage()\n                    .startsWith(\n                            e.getCause().getClass().getCanonicalName() + \": Sending request timeout in client-side\"));\n        }\n    }\n\n    /**\n     * for example, it will print like this:\n     * before a future is create , time is : 2018-06-21 15:11:31\n     * after a future is timeout , time is : 2018-06-21 15:11:36\n     * <p>\n     * The exception info print like:\n     * Waiting server-side response timeout by scan timer.\n     * start time: 2018-06-21 15:12:38.337, end time: 2018-06-21 15:12:43.354...\n     */\n    @Test\n    @Disabled\n    public void timeoutSend() throws Exception {\n        final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\");\n        logger.info(\n                \"before a future is create , time is : {}\", LocalDateTime.now().format(formatter));\n        // timeout after 5 seconds.\n        Channel channel = new MockedChannel();\n        Request request = new Request(10);\n        DefaultFuture f = DefaultFuture.newFuture(channel, request, 5000, null);\n        // mark the future is sent\n        DefaultFuture.sent(channel, request);\n        while (!f.isDone()) {\n            // spin\n            Thread.sleep(100);\n        }\n        logger.info(\n                \"after a future is timeout , time is : {}\", LocalDateTime.now().format(formatter));\n\n        // get operate will throw a timeout exception, because the future is timeout.\n        try {\n            f.get();\n        } catch (Exception e) {\n            Assertions.assertTrue(\n                    e.getCause() instanceof TimeoutException, \"catch exception is not timeout exception!\");\n            logger.error(e.getMessage());\n        }\n    }\n    /**\n     * for example, it will print like this:\n     * before a future is created , time is : 2021-01-22 10:55:03\n     * null\n     * after a future is timeout , time is : 2021-01-22 10:55:05\n     */\n    @Test\n    void interruptSend() throws Exception {\n        final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\");\n        logger.info(\n                \"before a future is create , time is : {}\", LocalDateTime.now().format(formatter));\n        // timeout after 1 seconds.\n        Channel channel = new MockedChannel();\n        int channelId = 10;\n        Request request = new Request(channelId);\n        ThreadlessExecutor executor = new ThreadlessExecutor();\n        DefaultFuture f = DefaultFuture.newFuture(channel, request, 1000, executor);\n        // mark the future is sent\n        DefaultFuture.sent(channel, request);\n        // get operate will throw a interrupted exception, because the thread is interrupted.\n        try {\n            new InterruptThread(Thread.currentThread()).start();\n            while (!f.isDone()) {\n                executor.waitAndDrain(Long.MAX_VALUE);\n            }\n            f.get();\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof InterruptedException, \"catch exception is not interrupted exception!\");\n            logger.error(e.getMessage());\n        } finally {\n            executor.shutdown();\n        }\n        // waiting timeout check task finished\n        Thread.sleep(1500);\n        logger.info(\n                \"after a future is timeout , time is : {}\", LocalDateTime.now().format(formatter));\n\n        DefaultFuture future = DefaultFuture.getFuture(channelId);\n        // waiting future should be removed by time out check task\n        Assertions.assertNull(future);\n    }\n\n    @Test\n    void testClose1() {\n        Channel channel = new MockedChannel();\n        Request request = new Request(123);\n        ExecutorService executor = ExtensionLoader.getExtensionLoader(ExecutorRepository.class)\n                .getDefaultExtension()\n                .createExecutorIfAbsent(URL.valueOf(\"dubbo://127.0.0.1:23456\"));\n        DefaultFuture.newFuture(channel, request, 1000, executor);\n        DefaultFuture.closeChannel(channel, 0);\n        Assertions.assertFalse(executor.isTerminated());\n    }\n\n    @Test\n    void testTimeoutWithRejectedExecution() throws Exception {\n        // Create a ThreadPoolExecutor with a queue capacity of 1\n        ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(\n                1, // corePoolSize\n                1, // maxPoolSize\n                60L,\n                TimeUnit.SECONDS,\n                new ArrayBlockingQueue<>(1), // queue capacity is 1\n                new ThreadPoolExecutor.AbortPolicy() // default rejection policy: throws exception\n                );\n        // Submit two tasks to occupy the thread and the queue\n        customExecutor.submit(() -> {\n            try {\n                Thread.sleep(500); // occupy the thread for a while\n            } catch (InterruptedException ignored) {\n            }\n        });\n        customExecutor.submit(() -> {\n            try {\n                Thread.sleep(500); // occupy the queue\n            } catch (InterruptedException ignored) {\n            }\n        });\n        // Create a Dubbo Mock Channel and a request\n        Channel channel = new MockedChannel();\n        Request request = new Request(999);\n        // Use Dubbo's newFuture and pass in the custom thread pool\n        DefaultFuture future = DefaultFuture.newFuture(channel, request, 100, customExecutor);\n        // Mark the request as sent\n        DefaultFuture.sent(channel, request);\n        // Wait for the timeout task to trigger\n        Thread.sleep(300);\n        Assertions.assertNull(DefaultFuture.getFuture(999), \"Future should be removed from FUTURES after timeout\");\n        customExecutor.shutdown();\n    }\n\n    @Test\n    void testClose2() {\n        Channel channel = new MockedChannel();\n        Request request = new Request(123);\n        ThreadlessExecutor threadlessExecutor = new ThreadlessExecutor();\n        DefaultFuture.newFuture(channel, request, 1000, threadlessExecutor);\n        DefaultFuture.closeChannel(channel, 0);\n        Assertions.assertTrue(threadlessExecutor.isTerminated());\n    }\n\n    /**\n     * mock a default future\n     */\n    private DefaultFuture defaultFuture(int timeout) {\n        Channel channel = new MockedChannel();\n        Request request = new Request(index.getAndIncrement());\n        return DefaultFuture.newFuture(channel, request, timeout, null);\n    }\n\n    /**\n     * mock a thread interrupt another thread which is waiting waitAndDrain() to return.\n     */\n    static class InterruptThread extends Thread {\n        private Thread parent;\n\n        public InterruptThread(Thread parent) {\n            this.parent = parent;\n        }\n\n        @Override\n        public void run() {\n            super.run();\n            try {\n                // interrupt waiting thread before timeout\n                Thread.sleep(500);\n                parent.interrupt();\n            } catch (InterruptedException e) {\n                logger.error(e.getMessage());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/ExchangeHandlerDispatcherTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.telnet.support.TelnetHandlerAdapter;\n\nimport java.lang.reflect.Field;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass ExchangeHandlerDispatcherTest {\n\n    @Test\n    void test() throws Exception {\n        ExchangeHandlerDispatcher exchangeHandlerDispatcher = new ExchangeHandlerDispatcher();\n\n        ChannelHandler channelHandler = Mockito.mock(ChannelHandler.class);\n        Replier replier = Mockito.mock(Replier.class);\n        TelnetHandlerAdapter telnetHandlerAdapter = Mockito.mock(TelnetHandlerAdapter.class);\n        exchangeHandlerDispatcher.addChannelHandler(channelHandler);\n        exchangeHandlerDispatcher.addReplier(ExchangeHandlerDispatcherTest.class, replier);\n        Field telnetHandlerField = exchangeHandlerDispatcher.getClass().getDeclaredField(\"telnetHandler\");\n        telnetHandlerField.setAccessible(true);\n        telnetHandlerField.set(exchangeHandlerDispatcher, telnetHandlerAdapter);\n\n        Channel channel = Mockito.mock(Channel.class);\n        ExchangeChannel exchangeChannel = Mockito.mock(ExchangeChannel.class);\n        exchangeHandlerDispatcher.connected(channel);\n        exchangeHandlerDispatcher.disconnected(channel);\n        exchangeHandlerDispatcher.sent(channel, null);\n        exchangeHandlerDispatcher.received(channel, null);\n        exchangeHandlerDispatcher.caught(channel, null);\n        ExchangeHandlerDispatcherTest obj = new ExchangeHandlerDispatcherTest();\n        exchangeHandlerDispatcher.reply(exchangeChannel, obj);\n        exchangeHandlerDispatcher.telnet(channel, null);\n\n        Mockito.verify(channelHandler, Mockito.times(1)).connected(channel);\n        Mockito.verify(channelHandler, Mockito.times(1)).disconnected(channel);\n        Mockito.verify(channelHandler, Mockito.times(1)).sent(channel, null);\n        Mockito.verify(channelHandler, Mockito.times(1)).received(channel, null);\n        Mockito.verify(channelHandler, Mockito.times(1)).caught(channel, null);\n        Mockito.verify(replier, Mockito.times(1)).reply(exchangeChannel, obj);\n        Mockito.verify(telnetHandlerAdapter, Mockito.times(1)).telnet(channel, null);\n\n        exchangeHandlerDispatcher.removeChannelHandler(channelHandler);\n        exchangeHandlerDispatcher.removeReplier(ExchangeHandlerDispatcherTest.class);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/MultiMessageTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Iterator;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\n/**\n * {@link MultiMessage}\n */\nclass MultiMessageTest {\n\n    @Test\n    void test() {\n        MultiMessage multiMessage = MultiMessage.create();\n        Assertions.assertTrue(multiMessage instanceof Iterable);\n\n        multiMessage.addMessage(\"test1\");\n        multiMessage.addMessages(Arrays.asList(\"test2\", \"test3\"));\n        Assertions.assertEquals(multiMessage.size(), 3);\n        Assertions.assertFalse(multiMessage.isEmpty());\n        Assertions.assertEquals(multiMessage.get(0), \"test1\");\n        Assertions.assertEquals(multiMessage.get(1), \"test2\");\n        Assertions.assertEquals(multiMessage.get(2), \"test3\");\n\n        Collection messages = multiMessage.getMessages();\n        Assertions.assertTrue(messages.contains(\"test1\"));\n        Assertions.assertTrue(messages.contains(\"test2\"));\n        Assertions.assertTrue(messages.contains(\"test3\"));\n\n        Iterator iterator = messages.iterator();\n        Assertions.assertTrue(iterator.hasNext());\n        Assertions.assertEquals(iterator.next(), \"test1\");\n        Assertions.assertEquals(iterator.next(), \"test2\");\n        Assertions.assertEquals(iterator.next(), \"test3\");\n\n        Collection removedCollection = multiMessage.removeMessages();\n        Assertions.assertArrayEquals(removedCollection.toArray(), messages.toArray());\n        messages = multiMessage.getMessages();\n        Assertions.assertTrue(messages.isEmpty());\n\n        MultiMessage multiMessage1 = MultiMessage.createFromCollection(Arrays.asList(\"test1\", \"test2\"));\n        MultiMessage multiMessage2 = MultiMessage.createFromArray(\"test1\", \"test2\");\n        Assertions.assertArrayEquals(\n                multiMessage1.getMessages().toArray(),\n                multiMessage2.getMessages().toArray());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/header/CloseTimerTaskTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.remoting.Channel;\n\nimport java.util.Collections;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.remoting.Constants.HEARTBEAT_CHECK_TICK;\n\n/**\n * {@link CloseTimerTask}\n */\nclass CloseTimerTaskTest {\n\n    private URL url = URL.valueOf(\"dubbo://localhost:20880\");\n\n    private MockChannel channel;\n\n    private CloseTimerTask closeTimerTask;\n    private HashedWheelTimer closeTimer;\n\n    @BeforeEach\n    public void setup() throws Exception {\n        long tickDuration = 1000;\n        closeTimer = new HashedWheelTimer(tickDuration / HEARTBEAT_CHECK_TICK, TimeUnit.MILLISECONDS);\n        channel = new MockChannel() {\n            @Override\n            public URL getUrl() {\n                return url;\n            }\n        };\n\n        AbstractTimerTask.ChannelProvider cp = () -> Collections.<Channel>singletonList(channel);\n        closeTimerTask = new CloseTimerTask(cp, closeTimer, tickDuration / HEARTBEAT_CHECK_TICK, (int) tickDuration);\n    }\n\n    @AfterEach\n    public void teardown() {\n        closeTimerTask.cancel();\n    }\n\n    @Test\n    void testClose() throws Exception {\n        long now = System.currentTimeMillis();\n\n        url = url.addParameter(DUBBO_VERSION_KEY, \"2.1.1\");\n        channel.setAttribute(HeartbeatHandler.KEY_READ_TIMESTAMP, now - 1000);\n        channel.setAttribute(HeartbeatHandler.KEY_WRITE_TIMESTAMP, now - 1000);\n\n        closeTimer.newTimeout(closeTimerTask, 250, TimeUnit.MILLISECONDS);\n\n        Thread.sleep(2000L);\n        Assertions.assertTrue(channel.isClosed());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeChannelTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.support.DefaultFuture;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\n\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nclass HeaderExchangeChannelTest {\n\n    private HeaderExchangeChannel header;\n    private MockChannel channel;\n    private URL url = URL.valueOf(\"dubbo://localhost:20880\");\n    private static final String CHANNEL_KEY = HeaderExchangeChannel.class.getName() + \".CHANNEL\";\n\n    @BeforeEach\n    public void setup() {\n        channel = new MockChannel() {\n            @Override\n            public URL getUrl() {\n                return url;\n            }\n        };\n\n        header = new HeaderExchangeChannel(channel);\n    }\n\n    @Test\n    void getOrAddChannelTest00() {\n        channel.setAttribute(\"CHANNEL_KEY\", \"attribute\");\n        HeaderExchangeChannel ret = HeaderExchangeChannel.getOrAddChannel(channel);\n        Assertions.assertNotNull(ret);\n    }\n\n    @Test\n    void getOrAddChannelTest01() {\n        channel = new MockChannel() {\n            @Override\n            public URL getUrl() {\n                return url;\n            }\n\n            @Override\n            public boolean isConnected() {\n                return true;\n            }\n        };\n        Assertions.assertNull(channel.getAttribute(CHANNEL_KEY));\n        HeaderExchangeChannel ret = HeaderExchangeChannel.getOrAddChannel(channel);\n        Assertions.assertNotNull(ret);\n        Assertions.assertNotNull(channel.getAttribute(CHANNEL_KEY));\n        Assertions.assertEquals(channel.getAttribute(CHANNEL_KEY).getClass(), HeaderExchangeChannel.class);\n    }\n\n    @Test\n    void getOrAddChannelTest02() {\n        channel = null;\n        HeaderExchangeChannel ret = HeaderExchangeChannel.getOrAddChannel(channel);\n        Assertions.assertNull(ret);\n    }\n\n    @Test\n    void removeChannelIfDisconnectedTest() {\n        Assertions.assertNull(channel.getAttribute(CHANNEL_KEY));\n        channel.setAttribute(CHANNEL_KEY, header);\n        channel.close();\n        HeaderExchangeChannel.removeChannelIfDisconnected(channel);\n        Assertions.assertNull(channel.getAttribute(CHANNEL_KEY));\n    }\n\n    @Test\n    void sendTest00() {\n        boolean sent = true;\n        String message = \"this is a test message\";\n        try {\n            header.close(1);\n            header.send(message, sent);\n        } catch (Exception e) {\n            Assertions.assertTrue(e instanceof RemotingException);\n        }\n    }\n\n    @Test\n    void sendTest01() throws RemotingException {\n        boolean sent = true;\n        String message = \"this is a test message\";\n        header.send(message, sent);\n        List<Object> objects = channel.getSentObjects();\n        Assertions.assertEquals(objects.get(0), \"this is a test message\");\n    }\n\n    @Test\n    void sendTest02() throws RemotingException {\n        boolean sent = true;\n        int message = 1;\n        header.send(message, sent);\n        List<Object> objects = channel.getSentObjects();\n        Assertions.assertEquals(objects.get(0).getClass(), Request.class);\n        Request request = (Request) objects.get(0);\n        Assertions.assertEquals(request.getVersion(), \"2.0.2\");\n    }\n\n    @Test\n    void sendTest04() throws RemotingException {\n        String message = \"this is a test message\";\n        header.send(message);\n        List<Object> objects = channel.getSentObjects();\n        Assertions.assertEquals(objects.get(0), \"this is a test message\");\n    }\n\n    @Test\n    void requestTest01() throws RemotingException {\n        Assertions.assertThrows(RemotingException.class, () -> {\n            header.close(1000);\n            Object requestObject = new Object();\n            header.request(requestObject);\n        });\n    }\n\n    @Test\n    void requestTest02() throws RemotingException {\n        Channel channel = Mockito.mock(MockChannel.class);\n        header = new HeaderExchangeChannel(channel);\n        when(channel.getUrl()).thenReturn(url);\n        Object requestObject = new Object();\n        header.request(requestObject);\n        ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);\n        verify(channel, times(1)).send(argumentCaptor.capture());\n        Assertions.assertEquals(argumentCaptor.getValue().getData(), requestObject);\n    }\n\n    @Test\n    void requestTest03() throws RemotingException {\n        Assertions.assertThrows(RemotingException.class, () -> {\n            channel = new MockChannel() {\n                @Override\n                public void send(Object req) throws RemotingException {\n                    throw new RemotingException(channel.getLocalAddress(), channel.getRemoteAddress(), \"throw error\");\n                }\n            };\n            header = new HeaderExchangeChannel(channel);\n            Object requestObject = new Object();\n            header.request(requestObject, 1000);\n        });\n    }\n\n    @Test\n    void isClosedTest() {\n        Assertions.assertFalse(header.isClosed());\n    }\n\n    @Test\n    void closeTest() {\n        Assertions.assertFalse(channel.isClosed());\n        header.close();\n        Assertions.assertTrue(channel.isClosed());\n    }\n\n    @Test\n    void closeWithTimeoutTest02() {\n        Assertions.assertFalse(channel.isClosed());\n        Request request = new Request();\n        DefaultFuture.newFuture(channel, request, 100, null);\n        header.close(100);\n        // return directly\n        header.close(1000);\n    }\n\n    @Test\n    void startCloseTest() {\n        try {\n            boolean isClosing = channel.isClosing();\n            Assertions.assertFalse(isClosing);\n            header.startClose();\n            isClosing = channel.isClosing();\n            Assertions.assertTrue(isClosing);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Test\n    void getLocalAddressTest() {\n        Assertions.assertNull(header.getLocalAddress());\n    }\n\n    @Test\n    void getRemoteAddressTest() {\n        Assertions.assertNull(header.getRemoteAddress());\n    }\n\n    @Test\n    void getUrlTest() {\n        Assertions.assertEquals(header.getUrl(), URL.valueOf(\"dubbo://localhost:20880\"));\n    }\n\n    @Test\n    void isConnectedTest() {\n        Assertions.assertFalse(header.isConnected());\n    }\n\n    @Test\n    void getChannelHandlerTest() {\n        Assertions.assertNull(header.getChannelHandler());\n    }\n\n    @Test\n    void getExchangeHandlerTest() {\n        Assertions.assertNull(header.getExchangeHandler());\n    }\n\n    @Test\n    void getAttributeAndSetAttributeTest() {\n        header.setAttribute(\"test\", \"test\");\n        Assertions.assertEquals(header.getAttribute(\"test\"), \"test\");\n        Assertions.assertTrue(header.hasAttribute(\"test\"));\n    }\n\n    @Test\n    void removeAttributeTest() {\n        header.setAttribute(\"test\", \"test\");\n        Assertions.assertEquals(header.getAttribute(\"test\"), \"test\");\n        header.removeAttribute(\"test\");\n        Assertions.assertFalse(header.hasAttribute(\"test\"));\n    }\n\n    @Test\n    void hasAttributeTest() {\n        Assertions.assertFalse(header.hasAttribute(\"test\"));\n        header.setAttribute(\"test\", \"test\");\n        Assertions.assertTrue(header.hasAttribute(\"test\"));\n    }\n\n    @Test\n    void hashCodeTest() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((channel == null) ? 0 : channel.hashCode());\n\n        Assertions.assertEquals(header.hashCode(), result);\n    }\n\n    @Test\n    void equalsTest() {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> {\n            Assertions.assertEquals(header, new HeaderExchangeChannel(channel));\n            header = new HeaderExchangeChannel(null);\n            Assertions.assertNotEquals(header, new HeaderExchangeChannel(channel));\n        });\n    }\n\n    @Test\n    void toStringTest() {\n        Assertions.assertEquals(header.toString(), channel.toString());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClientTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Client;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\npublic class HeaderExchangeClientTest {\n    @Test\n    void testReconnect() {\n        HeaderExchangeClient headerExchangeClient = new HeaderExchangeClient(Mockito.mock(Client.class), false);\n\n        Assertions.assertTrue(headerExchangeClient.shouldReconnect(URL.valueOf(\"localhost\")));\n        Assertions.assertTrue(headerExchangeClient.shouldReconnect(URL.valueOf(\"localhost?reconnect=true\")));\n        Assertions.assertTrue(headerExchangeClient.shouldReconnect(URL.valueOf(\"localhost?reconnect=tRue\")));\n        Assertions.assertTrue(headerExchangeClient.shouldReconnect(URL.valueOf(\"localhost?reconnect=30000\")));\n        Assertions.assertTrue(headerExchangeClient.shouldReconnect(URL.valueOf(\"localhost?reconnect=0\")));\n        Assertions.assertTrue(headerExchangeClient.shouldReconnect(URL.valueOf(\"localhost?reconnect=-1\")));\n        Assertions.assertFalse(headerExchangeClient.shouldReconnect(URL.valueOf(\"localhost?reconnect=false\")));\n        Assertions.assertFalse(headerExchangeClient.shouldReconnect(URL.valueOf(\"localhost?reconnect=FALSE\")));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.url.component.ServiceConfigURL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.RemotingServer;\n\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\n/**\n * {@link HeaderExchangeServer}\n */\nclass HeaderExchangeServerTest {\n\n    @Test\n    void test() throws InterruptedException, RemotingException {\n        RemotingServer server = Mockito.mock(RemotingServer.class);\n        URL url = new ServiceConfigURL(\"dubbo\", \"127.0.0.1\", 20881);\n        Mockito.when(server.getUrl()).thenReturn(url);\n        Mockito.when(server.canHandleIdle()).thenReturn(false);\n        HeaderExchangeServer headerExchangeServer = new HeaderExchangeServer(server);\n        Assertions.assertEquals(headerExchangeServer.getServer(), server);\n        Assertions.assertEquals(headerExchangeServer.getUrl(), url);\n\n        // test getChannels() and getExchangeChannels()\n        Channel channel1 = Mockito.mock(Channel.class);\n        Channel channel2 = Mockito.mock(Channel.class);\n        Channel exchangeChannel1 = new HeaderExchangeChannel(channel1);\n        Channel exchangeChannel2 = new HeaderExchangeChannel(channel2);\n        Mockito.when(channel1.getAttribute(HeaderExchangeChannel.class.getName() + \".CHANNEL\"))\n                .thenReturn(exchangeChannel1);\n        Mockito.when(channel2.getAttribute(HeaderExchangeChannel.class.getName() + \".CHANNEL\"))\n                .thenReturn(exchangeChannel2);\n        Collection<Channel> exChannels = Arrays.asList(exchangeChannel1, exchangeChannel2);\n        Mockito.when(server.getChannels()).thenReturn(Arrays.asList(channel1, channel2));\n        Assertions.assertEquals(headerExchangeServer.getChannels(), exChannels);\n        Assertions.assertEquals(headerExchangeServer.getExchangeChannels(), exChannels);\n\n        // test getChannel(InetSocketAddress) and getExchangeChannel(InetSocketAddress)\n        InetSocketAddress address1 = Mockito.mock(InetSocketAddress.class);\n        InetSocketAddress address2 = Mockito.mock(InetSocketAddress.class);\n        Mockito.when(server.getChannel(Mockito.eq(address1))).thenReturn(channel1);\n        Mockito.when(server.getChannel(Mockito.eq(address2))).thenReturn(channel2);\n        Assertions.assertEquals(headerExchangeServer.getChannel(address1), exchangeChannel1);\n        Assertions.assertEquals(headerExchangeServer.getChannel(address2), exchangeChannel2);\n        Assertions.assertEquals(headerExchangeServer.getExchangeChannel(address1), exchangeChannel1);\n        Assertions.assertEquals(headerExchangeServer.getExchangeChannel(address2), exchangeChannel2);\n\n        // test send(Object message) and send(Object message, boolean sent)\n        headerExchangeServer.send(\"test\");\n        Mockito.verify(server, Mockito.times(1)).send(\"test\");\n        headerExchangeServer.send(\"test\", true);\n        Mockito.verify(server, Mockito.times(1)).send(\"test\", true);\n\n        // test reset(URL url)\n        url = url.addParameter(Constants.HEARTBEAT_KEY, 3000).addParameter(Constants.HEARTBEAT_TIMEOUT_KEY, 3000 * 3);\n        headerExchangeServer.reset(url);\n\n        // test close(int timeout)\n        Mockito.when(exchangeChannel1.isConnected()).thenReturn(true);\n        headerExchangeServer.close(1000);\n        Mockito.verify(server, Mockito.times(1)).startClose();\n        Thread.sleep(1000);\n        Mockito.verify(server, Mockito.times(1)).close(1000);\n        Assertions.assertThrows(RemotingException.class, () -> headerExchangeServer.send(\"test\"));\n        Assertions.assertThrows(RemotingException.class, () -> headerExchangeServer.send(\"test\", true));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/header/HeartBeatTaskTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\nimport org.apache.dubbo.remoting.exchange.Request;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.remoting.Constants.HEARTBEAT_CHECK_TICK;\n\nclass HeartBeatTaskTest {\n\n    private URL url = URL.valueOf(\"dubbo://localhost:20880\");\n\n    private MockChannel channel;\n\n    private HeartbeatTimerTask heartbeatTimerTask;\n    private HashedWheelTimer heartbeatTimer;\n\n    @BeforeEach\n    public void setup() throws Exception {\n        long tickDuration = 1000;\n        heartbeatTimer = new HashedWheelTimer(tickDuration / HEARTBEAT_CHECK_TICK, TimeUnit.MILLISECONDS);\n\n        channel = new MockChannel() {\n\n            @Override\n            public URL getUrl() {\n                return url;\n            }\n        };\n\n        heartbeatTimerTask = new HeartbeatTimerTask(\n                () -> Collections.singleton(channel), heartbeatTimer, tickDuration / HEARTBEAT_CHECK_TICK, (int)\n                        tickDuration);\n    }\n\n    @AfterEach\n    public void teardown() {\n        heartbeatTimerTask.cancel();\n    }\n\n    @Test\n    void testHeartBeat() throws Exception {\n        long now = System.currentTimeMillis();\n\n        url = url.addParameter(DUBBO_VERSION_KEY, \"2.1.1\");\n        channel.setAttribute(HeartbeatHandler.KEY_READ_TIMESTAMP, now);\n        channel.setAttribute(HeartbeatHandler.KEY_WRITE_TIMESTAMP, now);\n\n        Thread.sleep(2000L);\n        List<Object> objects = channel.getSentObjects();\n        Assertions.assertTrue(objects.size() > 0);\n        Object obj = objects.get(0);\n        Assertions.assertTrue(obj instanceof Request);\n        Request request = (Request) obj;\n        Assertions.assertTrue(request.isHeartbeat());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/header/MockChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.Parameters;\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Client;\nimport org.apache.dubbo.remoting.RemotingException;\n\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class MockChannel implements Channel, Client {\n\n    private Map<String, Object> attributes = new HashMap<String, Object>();\n\n    private volatile boolean closed = false;\n    private volatile boolean closing = false;\n    private volatile int reconnectCount = 0;\n    private List<Object> sentObjects = new ArrayList<Object>();\n\n    @Override\n    public InetSocketAddress getRemoteAddress() {\n        return null;\n    }\n\n    @Override\n    public boolean isConnected() {\n        return false;\n    }\n\n    @Override\n    public boolean hasAttribute(String key) {\n        return attributes.containsKey(key);\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        return attributes.get(key);\n    }\n\n    @Override\n    public void setAttribute(String key, Object value) {\n        attributes.put(key, value);\n    }\n\n    @Override\n    public void removeAttribute(String key) {\n        attributes.remove(key);\n    }\n\n    @Override\n    public URL getUrl() {\n        return null;\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n        return null;\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n        return null;\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {\n        sentObjects.add(message);\n    }\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        sentObjects.add(message);\n    }\n\n    @Override\n    public void close() {\n        closed = true;\n    }\n\n    @Override\n    public void close(int timeout) {\n        closed = true;\n    }\n\n    @Override\n    public void startClose() {\n        closing = true;\n    }\n\n    @Override\n    public boolean isClosed() {\n        return closed;\n    }\n\n    public List<Object> getSentObjects() {\n        return Collections.unmodifiableList(sentObjects);\n    }\n\n    public boolean isClosing() {\n        return closing;\n    }\n\n    @Override\n    public void reset(URL url) {}\n\n    @Override\n    public void reconnect() throws RemotingException {\n        reconnectCount++;\n    }\n\n    @Override\n    public void reset(Parameters parameters) {}\n\n    public int getReconnectCount() {\n        return reconnectCount;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/exchange/support/header/ReconnectTimerTaskTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.exchange.support.header;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.timer.HashedWheelTimer;\n\nimport java.util.Collections;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;\nimport static org.apache.dubbo.remoting.Constants.HEARTBEAT_CHECK_TICK;\n\nclass ReconnectTimerTaskTest {\n\n    private URL url = URL.valueOf(\"dubbo://localhost:20880\");\n\n    private MockChannel channel;\n\n    private ReconnectTimerTask reconnectTimerTask;\n    private HashedWheelTimer reconnectTimer;\n    private boolean isConnected = false;\n\n    @BeforeEach\n    public void setup() throws Exception {\n        long tickDuration = 1000;\n        reconnectTimer = new HashedWheelTimer(tickDuration / HEARTBEAT_CHECK_TICK, TimeUnit.MILLISECONDS);\n        channel = new MockChannel() {\n            @Override\n            public URL getUrl() {\n                return url;\n            }\n\n            @Override\n            public boolean isConnected() {\n                return isConnected;\n            }\n        };\n\n        reconnectTimerTask = new ReconnectTimerTask(\n                () -> Collections.singleton(channel), reconnectTimer, tickDuration / HEARTBEAT_CHECK_TICK, (int)\n                        tickDuration);\n    }\n\n    @AfterEach\n    public void teardown() {\n        reconnectTimerTask.cancel();\n    }\n\n    @Test\n    void testReconnect() throws Exception {\n        long now = System.currentTimeMillis();\n\n        url = url.addParameter(DUBBO_VERSION_KEY, \"2.1.1\");\n        channel.setAttribute(HeartbeatHandler.KEY_READ_TIMESTAMP, now - 1000);\n        channel.setAttribute(HeartbeatHandler.KEY_WRITE_TIMESTAMP, now - 1000);\n\n        Thread.sleep(2000L);\n        Assertions.assertTrue(channel.getReconnectCount() > 0);\n        isConnected = true;\n        Thread.sleep(2000L);\n        Assertions.assertTrue(channel.getReconnectCount() > 1);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/handler/HeaderExchangeHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.handler;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.Constants;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.remoting.exchange.ExchangeChannel;\nimport org.apache.dubbo.remoting.exchange.ExchangeHandler;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\nimport org.apache.dubbo.remoting.exchange.support.DefaultFuture;\nimport org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport static org.apache.dubbo.common.constants.CommonConstants.HEARTBEAT_EVENT;\nimport static org.apache.dubbo.common.constants.CommonConstants.READONLY_EVENT;\n\n// TODO response test\nclass HeaderExchangeHandlerTest {\n\n    @Test\n    void testReceivedRequestOneway() throws RemotingException {\n        final Channel mockChannel = new MockedChannel();\n\n        final Person requestData = new Person(\"charles\");\n        Request request = new Request();\n        request.setTwoWay(false);\n        request.setData(requestData);\n\n        ExchangeHandler exHandler = new MockedExchangeHandler() {\n            @Override\n            public void received(Channel channel, Object message) throws RemotingException {\n                Assertions.assertEquals(requestData, message);\n            }\n        };\n        HeaderExchangeHandler headExHandler = new HeaderExchangeHandler(exHandler);\n        headExHandler.received(mockChannel, request);\n    }\n\n    @Test\n    void testReceivedRequestTwoway() throws RemotingException {\n        final Person requestData = new Person(\"charles\");\n        final Request request = new Request();\n        request.setTwoWay(true);\n        request.setData(requestData);\n\n        final AtomicInteger count = new AtomicInteger(0);\n        final Channel mockChannel = new MockedChannel() {\n            @Override\n            public void send(Object message) throws RemotingException {\n                Response res = (Response) message;\n                Assertions.assertEquals(request.getId(), res.getId());\n                Assertions.assertEquals(request.getVersion(), res.getVersion());\n                Assertions.assertEquals(Response.OK, res.getStatus());\n                Assertions.assertEquals(requestData, res.getResult());\n                Assertions.assertNull(res.getErrorMessage());\n                count.incrementAndGet();\n            }\n        };\n        ExchangeHandler exHandler = new MockedExchangeHandler() {\n            @Override\n            public CompletableFuture<Object> reply(ExchangeChannel channel, Object request) throws RemotingException {\n                return CompletableFuture.completedFuture(request);\n            }\n\n            @Override\n            public void received(Channel channel, Object message) throws RemotingException {\n                Assertions.fail();\n            }\n        };\n        HeaderExchangeHandler headerExchangeHandler = new HeaderExchangeHandler(exHandler);\n        headerExchangeHandler.received(mockChannel, request);\n        Assertions.assertEquals(1, count.get());\n    }\n\n    @Test\n    void testReceivedRequestTwowayErrorWithNullHandler() throws RemotingException {\n        Assertions.assertThrows(IllegalArgumentException.class, () -> new HeaderExchangeHandler(null));\n    }\n\n    @Test\n    void testReceivedRequestTwowayErrorReply() throws RemotingException {\n        final Person requestData = new Person(\"charles\");\n        final Request request = new Request();\n        request.setTwoWay(true);\n        request.setData(requestData);\n\n        final AtomicInteger count = new AtomicInteger(0);\n        final Channel mockChannel = new MockedChannel() {\n            @Override\n            public void send(Object message) throws RemotingException {\n                Response res = (Response) message;\n                Assertions.assertEquals(request.getId(), res.getId());\n                Assertions.assertEquals(request.getVersion(), res.getVersion());\n                Assertions.assertEquals(Response.SERVICE_ERROR, res.getStatus());\n                Assertions.assertNull(res.getResult());\n                Assertions.assertTrue(res.getErrorMessage().contains(BizException.class.getName()));\n                count.incrementAndGet();\n            }\n        };\n        ExchangeHandler exHandler = new MockedExchangeHandler() {\n            @Override\n            public CompletableFuture<Object> reply(ExchangeChannel channel, Object request) throws RemotingException {\n                throw new BizException();\n            }\n        };\n        HeaderExchangeHandler headerExchangeHandler = new HeaderExchangeHandler(exHandler);\n        headerExchangeHandler.received(mockChannel, request);\n        Assertions.assertEquals(1, count.get());\n    }\n\n    @Test\n    void testReceivedRequestTwowayErrorRequestBroken() throws RemotingException {\n        final Request request = new Request();\n        request.setTwoWay(true);\n        request.setData(new BizException());\n        request.setBroken(true);\n\n        final AtomicInteger count = new AtomicInteger(0);\n        final Channel mockChannel = new MockedChannel() {\n            @Override\n            public void send(Object message) throws RemotingException {\n                Response res = (Response) message;\n                Assertions.assertEquals(request.getId(), res.getId());\n                Assertions.assertEquals(request.getVersion(), res.getVersion());\n                Assertions.assertEquals(Response.BAD_REQUEST, res.getStatus());\n                Assertions.assertNull(res.getResult());\n                Assertions.assertTrue(res.getErrorMessage().contains(BizException.class.getName()));\n                count.incrementAndGet();\n            }\n        };\n        HeaderExchangeHandler headerExchangeHandler = new HeaderExchangeHandler(new MockedExchangeHandler());\n        headerExchangeHandler.received(mockChannel, request);\n        Assertions.assertEquals(1, count.get());\n    }\n\n    @Test\n    void testReceivedRequestEventReadonly() throws RemotingException {\n        final Request request = new Request();\n        request.setTwoWay(true);\n        request.setEvent(READONLY_EVENT);\n\n        final Channel mockChannel = new MockedChannel();\n        HeaderExchangeHandler headerExchangeHandler = new HeaderExchangeHandler(new MockedExchangeHandler());\n        headerExchangeHandler.received(mockChannel, request);\n        Assertions.assertTrue(mockChannel.hasAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY));\n    }\n\n    @Test\n    void testReceivedRequestEventOtherDiscard() throws RemotingException {\n        final Request request = new Request();\n        request.setTwoWay(true);\n        request.setEvent(\"my event\");\n\n        final Channel mockChannel = new MockedChannel() {\n            @Override\n            public void send(Object message) throws RemotingException {\n                Assertions.fail();\n            }\n        };\n        HeaderExchangeHandler headerExchangeHandler = new HeaderExchangeHandler(new MockedExchangeHandler() {\n\n            @Override\n            public CompletableFuture<Object> reply(ExchangeChannel channel, Object request) throws RemotingException {\n                Assertions.fail();\n                throw new RemotingException(channel, \"\");\n            }\n\n            @Override\n            public void received(Channel channel, Object message) throws RemotingException {\n                Assertions.fail();\n                throw new RemotingException(channel, \"\");\n            }\n        });\n        headerExchangeHandler.received(mockChannel, request);\n    }\n\n    @Test\n    void testReceivedResponseHeartbeatEvent() throws Exception {\n        Channel mockChannel = new MockedChannel();\n        HeaderExchangeHandler headerExchangeHandler = new HeaderExchangeHandler(new MockedExchangeHandler());\n        Response response = new Response(1);\n        response.setStatus(Response.OK);\n        response.setEvent(true);\n        response.setResult(HEARTBEAT_EVENT);\n        headerExchangeHandler.received(mockChannel, response);\n    }\n\n    @Test\n    void testReceivedResponse() throws Exception {\n        Request request = new Request(1);\n        request.setTwoWay(true);\n        Channel mockChannel = new MockedChannel();\n        DefaultFuture future = DefaultFuture.newFuture(mockChannel, request, 5000, null);\n\n        HeaderExchangeHandler headerExchangeHandler = new HeaderExchangeHandler(new MockedExchangeHandler());\n        Response response = new Response(1);\n        response.setStatus(Response.OK);\n        response.setResult(\"MOCK_DATA\");\n        headerExchangeHandler.received(mockChannel, response);\n\n        Object result = future.get();\n        Assertions.assertEquals(result.toString(), \"MOCK_DATA\");\n    }\n\n    private class BizException extends RuntimeException {\n        private static final long serialVersionUID = 1L;\n    }\n\n    private class MockedExchangeHandler extends MockedChannelHandler implements ExchangeHandler {\n\n        public String telnet(Channel channel, String message) throws RemotingException {\n            throw new UnsupportedOperationException();\n        }\n\n        public CompletableFuture<Object> reply(ExchangeChannel channel, Object request) throws RemotingException {\n            throw new UnsupportedOperationException();\n        }\n    }\n\n    private class Person {\n        private String name;\n\n        public Person(String name) {\n            super();\n            this.name = name;\n        }\n\n        @Override\n        public String toString() {\n            return \"Person [name=\" + name + \"]\";\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/handler/MockedChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.handler;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\n\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class MockedChannel implements Channel {\n    private boolean isClosed;\n    private volatile boolean closing = false;\n    private URL url;\n    private ChannelHandler handler;\n    private Map<String, Object> map = new HashMap<String, Object>();\n\n    public MockedChannel() {\n        super();\n    }\n\n    @Override\n    public URL getUrl() {\n        return url;\n    }\n\n    @Override\n    public ChannelHandler getChannelHandler() {\n\n        return this.handler;\n    }\n\n    @Override\n    public InetSocketAddress getLocalAddress() {\n\n        return null;\n    }\n\n    @Override\n    public void send(Object message) throws RemotingException {}\n\n    @Override\n    public void send(Object message, boolean sent) throws RemotingException {\n        this.send(message);\n    }\n\n    @Override\n    public void close() {\n        isClosed = true;\n    }\n\n    @Override\n    public void close(int timeout) {\n        this.close();\n    }\n\n    @Override\n    public void startClose() {\n        closing = true;\n    }\n\n    @Override\n    public boolean isClosed() {\n        return isClosed;\n    }\n\n    @Override\n    public InetSocketAddress getRemoteAddress() {\n        return null;\n    }\n\n    @Override\n    public boolean isConnected() {\n        return false;\n    }\n\n    @Override\n    public boolean hasAttribute(String key) {\n        return map.containsKey(key);\n    }\n\n    @Override\n    public Object getAttribute(String key) {\n        return map.get(key);\n    }\n\n    @Override\n    public void setAttribute(String key, Object value) {\n        map.put(key, value);\n    }\n\n    @Override\n    public void removeAttribute(String key) {\n        map.remove(key);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/handler/MockedChannelHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.handler;\n\nimport org.apache.dubbo.common.utils.ConcurrentHashSet;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\n\nimport java.util.Collections;\nimport java.util.Set;\n\npublic class MockedChannelHandler implements ChannelHandler {\n    //    ConcurrentMap<String, Channel> channels = new ConcurrentHashMap<String, Channel>();\n    ConcurrentHashSet<Channel> channels = new ConcurrentHashSet<Channel>();\n\n    @Override\n    public void connected(Channel channel) throws RemotingException {\n        channels.add(channel);\n    }\n\n    @Override\n    public void disconnected(Channel channel) throws RemotingException {\n        channels.remove(channel);\n    }\n\n    @Override\n    public void sent(Channel channel, Object message) throws RemotingException {\n        channel.send(message);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        // echo\n        channel.send(message);\n    }\n\n    @Override\n    public void caught(Channel channel, Throwable exception) throws RemotingException {\n        throw new RemotingException(channel, exception);\n    }\n\n    public Set<Channel> getChannels() {\n        return Collections.unmodifiableSet(channels);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/TelnetUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet;\n\nimport org.apache.dubbo.remoting.telnet.support.TelnetUtils;\n\nimport java.util.Arrays;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass TelnetUtilsTest {\n\n    /**\n     * abc - abc - abc\n     * 1   - 2   - 3\n     * x   - y   - z\n     */\n    @Test\n    void testToList() {\n        List<List<String>> table = new LinkedList<>();\n        table.add(Arrays.asList(\"abc\", \"abc\", \"abc\"));\n        table.add(Arrays.asList(\"1\", \"2\", \"3\"));\n        table.add(Arrays.asList(\"x\", \"y\", \"z\"));\n\n        String toList = TelnetUtils.toList(table);\n\n        Assertions.assertTrue(toList.contains(\"abc - abc - abc\"));\n        Assertions.assertTrue(toList.contains(\"1   - 2   - 3\"));\n        Assertions.assertTrue(toList.contains(\"x   - y   - z\"));\n    }\n\n    /**\n     * +-----+-----+-----+\n     * | A   | B   | C   |\n     * +-----+-----+-----+\n     * | abc | abc | abc |\n     * | 1   | 2   | 3   |\n     * | x   | y   | z   |\n     * +-----+-----+-----+\n     */\n    @Test\n    void testToTable() {\n        List<List<String>> table = new LinkedList<>();\n        table.add(Arrays.asList(\"abc\", \"abc\", \"abc\"));\n        table.add(Arrays.asList(\"1\", \"2\", \"3\"));\n        table.add(Arrays.asList(\"x\", \"y\", \"z\"));\n\n        String toTable = TelnetUtils.toTable(new String[] {\"A\", \"B\", \"C\"}, table);\n\n        Assertions.assertTrue(toTable.contains(\"| A   | B   | C   |\"));\n        Assertions.assertTrue(toTable.contains(\"| abc | abc | abc |\"));\n        Assertions.assertTrue(toTable.contains(\"| 1   | 2   | 3   |\"));\n        Assertions.assertTrue(toTable.contains(\"| x   | y   | z   |\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/ClearTelnetHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.support.command.ClearTelnetHandler;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass ClearTelnetHandlerTest {\n\n    @Test\n    void test() {\n        StringBuilder buf = new StringBuilder();\n        for (int i = 0; i < 50; i++) {\n            buf.append(\"\\r\\n\");\n        }\n\n        ClearTelnetHandler telnetHandler = new ClearTelnetHandler();\n        Assertions.assertEquals(buf.toString(), telnetHandler.telnet(Mockito.mock(Channel.class), \"50\"));\n\n        // Illegal Input\n        Assertions.assertTrue(\n                telnetHandler.telnet(Mockito.mock(Channel.class), \"Illegal\").contains(\"Illegal\"));\n\n        for (int i = 0; i < 50; i++) {\n            buf.append(\"\\r\\n\");\n        }\n        Assertions.assertEquals(buf.toString(), telnetHandler.telnet(Mockito.mock(Channel.class), \"\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/ExitTelnetHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.support.command.ExitTelnetHandler;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nclass ExitTelnetHandlerTest {\n    @Test\n    void test() {\n        Channel channel = Mockito.mock(Channel.class);\n\n        ExitTelnetHandler exitTelnetHandler = new ExitTelnetHandler();\n        exitTelnetHandler.telnet(channel, null);\n\n        verify(channel, times(1)).close();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/HelpTelnetHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.support.command.HelpTelnetHandler;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass HelpTelnetHandlerTest {\n    @Test\n    void test() {\n        Channel channel = Mockito.mock(Channel.class);\n        Mockito.when(channel.getUrl()).thenReturn(URL.valueOf(\"dubbo://127.0.0.1:12345\"));\n\n        HelpTelnetHandler helpTelnetHandler = new HelpTelnetHandler(FrameworkModel.defaultModel());\n        // default output\n        String prompt = \"Please input \\\"help [command]\\\" show detail.\\r\\n\";\n        Assertions.assertTrue(helpTelnetHandler.telnet(channel, \"\").contains(prompt));\n\n        // \"help\" command output\n        String demoOutput = \"Command:\\r\\n\" + \"    help [command]\\r\\n\"\n                + \"Summary:\\r\\n\"\n                + \"    Show help.\\r\\n\"\n                + \"Detail:\\r\\n\"\n                + \"    Show help.\";\n        Assertions.assertEquals(helpTelnetHandler.telnet(channel, \"help\"), demoOutput);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/StatusTelnetHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.telnet.support.command.StatusTelnetHandler;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass StatusTelnetHandlerTest {\n    @Test\n    void test() {\n        Channel channel = Mockito.mock(Channel.class);\n        Mockito.when(channel.getUrl()).thenReturn(URL.valueOf(\"dubbo://127.0.0.1:12345\"));\n\n        StatusTelnetHandler statusTelnetHandler = new StatusTelnetHandler();\n        Assertions.assertNotNull(statusTelnetHandler.telnet(channel, \"\"));\n        Assertions.assertNotNull(statusTelnetHandler.telnet(channel, \"-l\"));\n\n        String errorPrompt = \"Unsupported parameter \";\n        Assertions.assertTrue(statusTelnetHandler.telnet(channel, \"other\").contains(errorPrompt));\n\n        Mockito.when(channel.getUrl()).thenReturn(URL.valueOf(\"dubbo://127.0.0.1:12345?status=load,memory\"));\n        Assertions.assertNotNull(statusTelnetHandler.telnet(channel, \"\"));\n        Assertions.assertNotNull(statusTelnetHandler.telnet(channel, \"-l\"));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/telnet/support/TelnetHandlerAdapterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.telnet.support;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.RemotingException;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass TelnetHandlerAdapterTest {\n\n    @Test\n    void testTelnet() throws RemotingException {\n\n        Channel channel = Mockito.mock(Channel.class);\n        Map<String, String> param = new HashMap<>();\n        param.put(\"telnet\", \"status\");\n        URL url = new URL(\"p1\", \"127.0.0.1\", 12345, \"path1\", param);\n        Mockito.when(channel.getUrl()).thenReturn(url);\n        TelnetHandlerAdapter telnetHandlerAdapter = new TelnetHandlerAdapter(FrameworkModel.defaultModel());\n\n        String message = \"--no-prompt status \";\n        String expectedResult = \"OK\\r\\n\";\n        Assertions.assertEquals(expectedResult, telnetHandlerAdapter.telnet(channel, message));\n\n        message = \"--no-prompt status test\";\n        expectedResult = \"Unsupported parameter test for status.\\r\\n\";\n        Assertions.assertEquals(expectedResult, telnetHandlerAdapter.telnet(channel, message));\n\n        message = \"--no-prompt test\";\n        expectedResult = \"Unsupported command: test\\r\\n\";\n        Assertions.assertEquals(expectedResult, telnetHandlerAdapter.telnet(channel, message));\n\n        message = \"--no-prompt help\";\n        expectedResult =\n                \"Command: help disabled for security reasons, please enable support by listing the commands through 'telnet'\\r\\n\";\n        Assertions.assertEquals(expectedResult, telnetHandlerAdapter.telnet(channel, message));\n\n        message = \"--no-prompt\";\n        expectedResult = StringUtils.EMPTY_STRING;\n        Assertions.assertEquals(expectedResult, telnetHandlerAdapter.telnet(channel, message));\n\n        message = \"help\";\n        expectedResult =\n                \"Command: help disabled for security reasons, please enable support by listing the commands through 'telnet'\\r\\ndubbo>\";\n        Assertions.assertEquals(expectedResult, telnetHandlerAdapter.telnet(channel, message));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/transport/AbstractCodecTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.buffer.ChannelBuffer;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.internal.verification.VerificationModeFactory;\n\nimport static org.hamcrest.CoreMatchers.allOf;\nimport static org.hamcrest.CoreMatchers.containsString;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\n\nclass AbstractCodecTest {\n\n    @Test\n    void testCheckPayloadDefault8M() throws Exception {\n        Channel channel = mock(Channel.class);\n        given(channel.getUrl()).willReturn(URL.valueOf(\"dubbo://1.1.1.1\"));\n\n        AbstractCodec.checkPayload(channel, 1 * 1024 * 1024);\n\n        try {\n            AbstractCodec.checkPayload(channel, 15 * 1024 * 1024);\n        } catch (IOException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    allOf(\n                            containsString(\"Data length too large: \"),\n                            containsString(\"max payload: \" + 8 * 1024 * 1024)));\n        }\n\n        verify(channel, VerificationModeFactory.atLeastOnce()).getUrl();\n    }\n\n    @Test\n    void testCheckProviderPayload() throws Exception {\n        Channel channel = mock(Channel.class);\n        given(channel.getUrl()).willReturn(URL.valueOf(\"dubbo://1.1.1.1\"));\n\n        AbstractCodec.checkPayload(channel, 1024 * 1024 + 1, 1024 * 1024);\n\n        try {\n            AbstractCodec.checkPayload(channel, 1024 * 1024, 1024 * 1024);\n        } catch (IOException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    allOf(containsString(\"Data length too large: \"), containsString(\"max payload: \" + 1024 * 1024)));\n        }\n\n        try {\n            AbstractCodec.checkPayload(channel, 0, 15 * 1024 * 1024);\n        } catch (IOException expected) {\n            assertThat(\n                    expected.getMessage(),\n                    allOf(\n                            containsString(\"Data length too large: \"),\n                            containsString(\"max payload: \" + 8 * 1024 * 1024)));\n        }\n\n        verify(channel, VerificationModeFactory.atLeastOnce()).getUrl();\n    }\n\n    @Test\n    void tesCheckPayloadMinusPayloadNoLimit() throws Exception {\n        Channel channel = mock(Channel.class);\n        given(channel.getUrl()).willReturn(URL.valueOf(\"dubbo://1.1.1.1?payload=-1\"));\n\n        AbstractCodec.checkPayload(channel, 15 * 1024 * 1024);\n\n        verify(channel, VerificationModeFactory.atLeastOnce()).getUrl();\n    }\n\n    @Test\n    void testIsClientSide() {\n        AbstractCodec codec = getAbstractCodec();\n\n        Channel channel = mock(Channel.class);\n        given(channel.getRemoteAddress()).willReturn(new InetSocketAddress(\"172.24.157.13\", 9103));\n        given(channel.getUrl()).willReturn(URL.valueOf(\"dubbo://172.24.157.13:9103\"));\n        assertThat(codec.isClientSide(channel), is(true));\n        assertThat(codec.isServerSide(channel), is(false));\n\n        given(channel.getRemoteAddress()).willReturn(new InetSocketAddress(\"172.24.157.14\", 9103));\n        given(channel.getUrl()).willReturn(URL.valueOf(\"dubbo://172.24.157.13:9103\"));\n        assertThat(codec.isClientSide(channel), is(false));\n        assertThat(codec.isServerSide(channel), is(true));\n    }\n\n    private AbstractCodec getAbstractCodec() {\n        AbstractCodec codec = new AbstractCodec() {\n            @Override\n            public void encode(Channel channel, ChannelBuffer buffer, Object message) {}\n\n            @Override\n            public Object decode(Channel channel, ChannelBuffer buffer) {\n                return null;\n            }\n        };\n        return codec;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/transport/ChannelHandlerDispatcherTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.RemotingException;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nclass ChannelHandlerDispatcherTest {\n\n    @AfterEach\n    public void tearDown() {\n        MockChannelHandler.reset();\n    }\n\n    @Test\n    void test() {\n        ChannelHandlerDispatcher channelHandlerDispatcher = new ChannelHandlerDispatcher();\n        MockChannelHandler channelHandler1 = new MockChannelHandler();\n        MockChannelHandler channelHandler2 = new MockChannelHandler();\n        channelHandlerDispatcher.addChannelHandler(channelHandler1);\n        channelHandlerDispatcher.addChannelHandler(channelHandler2);\n        Collection<ChannelHandler> channelHandlers = channelHandlerDispatcher.getChannelHandlers();\n        Assertions.assertTrue(channelHandlers.contains(channelHandler1));\n        Assertions.assertTrue(channelHandlers.contains(channelHandler2));\n\n        Channel channel = Mockito.mock(Channel.class);\n        channelHandlerDispatcher.sent(channel, \"test\");\n        channelHandlerDispatcher.connected(channel);\n        channelHandlerDispatcher.disconnected(channel);\n        channelHandlerDispatcher.caught(channel, null);\n        channelHandlerDispatcher.received(channel, \"test\");\n\n        Assertions.assertEquals(MockChannelHandler.getSentCount(), 2);\n        Assertions.assertEquals(MockChannelHandler.getConnectedCount(), 2);\n        Assertions.assertEquals(MockChannelHandler.getDisconnectedCount(), 2);\n        Assertions.assertEquals(MockChannelHandler.getCaughtCount(), 2);\n        Assertions.assertEquals(MockChannelHandler.getReceivedCount(), 2);\n\n        channelHandlerDispatcher = channelHandlerDispatcher.removeChannelHandler(channelHandler1);\n        Assertions.assertFalse(channelHandlerDispatcher.getChannelHandlers().contains(channelHandler1));\n    }\n\n    @Test\n    void constructorNullObjectTest() {\n        ChannelHandlerDispatcher channelHandlerDispatcher = new ChannelHandlerDispatcher(null, null);\n        Assertions.assertEquals(0, channelHandlerDispatcher.getChannelHandlers().size());\n        ChannelHandlerDispatcher channelHandlerDispatcher1 = new ChannelHandlerDispatcher((MockChannelHandler) null);\n        Assertions.assertEquals(\n                0, channelHandlerDispatcher1.getChannelHandlers().size());\n        ChannelHandlerDispatcher channelHandlerDispatcher2 =\n                new ChannelHandlerDispatcher(null, new MockChannelHandler());\n        Assertions.assertEquals(\n                1, channelHandlerDispatcher2.getChannelHandlers().size());\n        ChannelHandlerDispatcher channelHandlerDispatcher3 =\n                new ChannelHandlerDispatcher(Collections.singleton(new MockChannelHandler()));\n        Assertions.assertEquals(\n                1, channelHandlerDispatcher3.getChannelHandlers().size());\n        Collection<ChannelHandler> mockChannelHandlers = new HashSet<>();\n        mockChannelHandlers.add(new MockChannelHandler());\n        mockChannelHandlers.add(null);\n        ChannelHandlerDispatcher channelHandlerDispatcher4 = new ChannelHandlerDispatcher(mockChannelHandlers);\n        Assertions.assertEquals(\n                1, channelHandlerDispatcher4.getChannelHandlers().size());\n    }\n}\n\nclass MockChannelHandler extends ChannelHandlerAdapter {\n    private static int sentCount = 0;\n    private static int connectedCount = 0;\n    private static int disconnectedCount = 0;\n    private static int receivedCount = 0;\n    private static int caughtCount = 0;\n\n    @Override\n    public void connected(Channel channel) throws RemotingException {\n        connectedCount++;\n        super.connected(channel);\n    }\n\n    @Override\n    public void disconnected(Channel channel) throws RemotingException {\n        disconnectedCount++;\n        super.disconnected(channel);\n    }\n\n    @Override\n    public void sent(Channel channel, Object message) throws RemotingException {\n        sentCount++;\n        super.sent(channel, message);\n    }\n\n    @Override\n    public void received(Channel channel, Object message) throws RemotingException {\n        receivedCount++;\n        super.received(channel, message);\n    }\n\n    @Override\n    public void caught(Channel channel, Throwable exception) throws RemotingException {\n        caughtCount++;\n        super.caught(channel, exception);\n    }\n\n    public static int getSentCount() {\n        return sentCount;\n    }\n\n    public static int getConnectedCount() {\n        return connectedCount;\n    }\n\n    public static int getDisconnectedCount() {\n        return disconnectedCount;\n    }\n\n    public static int getReceivedCount() {\n        return receivedCount;\n    }\n\n    public static int getCaughtCount() {\n        return caughtCount;\n    }\n\n    public static void reset() {\n        sentCount = 0;\n        connectedCount = 0;\n        disconnectedCount = 0;\n        receivedCount = 0;\n        caughtCount = 0;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/transport/CodecSupportTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.common.serialize.ObjectOutput;\nimport org.apache.dubbo.common.serialize.Serialization;\nimport org.apache.dubbo.common.serialize.support.DefaultSerializationSelector;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.InputStream;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass CodecSupportTest {\n\n    @Test\n    void testHeartbeat() throws Exception {\n        Byte proto = CodecSupport.getIDByName(DefaultSerializationSelector.getDefaultRemotingSerialization());\n        Serialization serialization = CodecSupport.getSerializationById(proto);\n        byte[] nullBytes = CodecSupport.getNullBytesOf(serialization);\n\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        ObjectOutput out = serialization.serialize(null, baos);\n        out.writeObject(null);\n        out.flushBuffer();\n        InputStream is = new ByteArrayInputStream(baos.toByteArray());\n        baos.close();\n        byte[] payload = CodecSupport.getPayload(is);\n\n        Assertions.assertArrayEquals(nullBytes, payload);\n        Assertions.assertTrue(CodecSupport.isHeartBeat(payload, proto));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/transport/DecodeHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.Decodeable;\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\n/**\n * {@link DecodeHandler}\n */\nclass DecodeHandlerTest {\n\n    @Test\n    void test() throws Exception {\n        ChannelHandler handler = Mockito.mock(ChannelHandler.class);\n        Channel channel = Mockito.mock(Channel.class);\n        DecodeHandler decodeHandler = new DecodeHandler(handler);\n\n        MockData mockData = new MockData();\n        decodeHandler.received(channel, mockData);\n        Assertions.assertTrue(mockData.isDecoded());\n\n        MockData mockRequestData = new MockData();\n        Request request = new Request(1);\n        request.setData(mockRequestData);\n        decodeHandler.received(channel, request);\n        Assertions.assertTrue(mockRequestData.isDecoded());\n\n        MockData mockResponseData = new MockData();\n        Response response = new Response(1);\n        response.setResult(mockResponseData);\n        decodeHandler.received(channel, response);\n        Assertions.assertTrue(mockResponseData.isDecoded());\n\n        mockData.setThrowEx(true);\n        decodeHandler.received(channel, mockData);\n    }\n\n    class MockData implements Decodeable {\n\n        private boolean isDecoded = false;\n\n        private boolean throwEx = false;\n\n        @Override\n        public void decode() throws Exception {\n            if (throwEx) {\n                throw new RuntimeException();\n            }\n            isDecoded = true;\n        }\n\n        public boolean isDecoded() {\n            return isDecoded;\n        }\n\n        public void setThrowEx(boolean throwEx) {\n            this.throwEx = throwEx;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/transport/MultiMessageHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\nimport org.apache.dubbo.remoting.exchange.support.MultiMessage;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\n\n/**\n * {@link MultiMessageHandler}\n */\nclass MultiMessageHandlerTest {\n\n    @Test\n    void test() throws Exception {\n        ChannelHandler handler = Mockito.mock(ChannelHandler.class);\n        Channel channel = Mockito.mock(Channel.class);\n        MultiMessageHandler multiMessageHandler = new MultiMessageHandler(handler);\n\n        MultiMessage multiMessage = MultiMessage.createFromArray(\"test1\", \"test2\");\n        multiMessageHandler.received(channel, multiMessage);\n        // verify\n        ArgumentCaptor<Channel> channelArgumentCaptor = ArgumentCaptor.forClass(Channel.class);\n        ArgumentCaptor<Object> objectArgumentCaptor = ArgumentCaptor.forClass(Object.class);\n        Mockito.verify(handler, Mockito.times(2))\n                .received(channelArgumentCaptor.capture(), objectArgumentCaptor.capture());\n        Assertions.assertEquals(objectArgumentCaptor.getAllValues().get(0), \"test1\");\n        Assertions.assertEquals(objectArgumentCaptor.getAllValues().get(1), \"test2\");\n        Assertions.assertEquals(channelArgumentCaptor.getValue(), channel);\n\n        Object obj = new Object();\n        multiMessageHandler.received(channel, obj);\n        // verify\n        Mockito.verify(handler, Mockito.times(3))\n                .received(channelArgumentCaptor.capture(), objectArgumentCaptor.capture());\n        Assertions.assertEquals(objectArgumentCaptor.getValue(), obj);\n        Assertions.assertEquals(channelArgumentCaptor.getValue(), channel);\n\n        RuntimeException runtimeException = new RuntimeException();\n        Mockito.doThrow(runtimeException).when(handler).received(Mockito.any(), Mockito.any());\n        multiMessageHandler.received(channel, multiMessage);\n        // verify\n        ArgumentCaptor<Throwable> throwableArgumentCaptor = ArgumentCaptor.forClass(Throwable.class);\n        Mockito.verify(handler, Mockito.times(2))\n                .caught(channelArgumentCaptor.capture(), throwableArgumentCaptor.capture());\n        Assertions.assertEquals(throwableArgumentCaptor.getAllValues().get(0), runtimeException);\n        Assertions.assertEquals(throwableArgumentCaptor.getAllValues().get(1), runtimeException);\n        Assertions.assertEquals(channelArgumentCaptor.getValue(), channel);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/transport/dispatcher/ChannelEventRunnableTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.transport.dispatcher;\n\nimport org.apache.dubbo.remoting.Channel;\nimport org.apache.dubbo.remoting.ChannelHandler;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\n\n/**\n * {@link ChannelEventRunnable}\n */\nclass ChannelEventRunnableTest {\n\n    @Test\n    void test() throws Exception {\n        ChannelEventRunnable.ChannelState[] values = ChannelEventRunnable.ChannelState.values();\n        Assertions.assertEquals(Arrays.toString(values), \"[CONNECTED, DISCONNECTED, SENT, RECEIVED, CAUGHT]\");\n\n        Channel channel = Mockito.mock(Channel.class);\n        ChannelHandler handler = Mockito.mock(ChannelHandler.class);\n        ChannelEventRunnable connectRunnable =\n                new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.CONNECTED);\n        ChannelEventRunnable disconnectRunnable =\n                new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.DISCONNECTED);\n        ChannelEventRunnable sentRunnable =\n                new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.SENT);\n        ChannelEventRunnable receivedRunnable =\n                new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.RECEIVED, \"\");\n        ChannelEventRunnable caughtRunnable = new ChannelEventRunnable(\n                channel, handler, ChannelEventRunnable.ChannelState.CAUGHT, new RuntimeException());\n\n        connectRunnable.run();\n        disconnectRunnable.run();\n        sentRunnable.run();\n        receivedRunnable.run();\n        caughtRunnable.run();\n\n        ArgumentCaptor<Channel> channelArgumentCaptor = ArgumentCaptor.forClass(Channel.class);\n        ArgumentCaptor<Throwable> throwableArgumentCaptor = ArgumentCaptor.forClass(Throwable.class);\n        ArgumentCaptor<Object> objectArgumentCaptor = ArgumentCaptor.forClass(Object.class);\n        Mockito.verify(handler, Mockito.times(1)).connected(channelArgumentCaptor.capture());\n        Mockito.verify(handler, Mockito.times(1)).disconnected(channelArgumentCaptor.capture());\n        Mockito.verify(handler, Mockito.times(1)).sent(channelArgumentCaptor.capture(), Mockito.any());\n        Mockito.verify(handler, Mockito.times(1))\n                .received(channelArgumentCaptor.capture(), objectArgumentCaptor.capture());\n        Mockito.verify(handler, Mockito.times(1))\n                .caught(channelArgumentCaptor.capture(), throwableArgumentCaptor.capture());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/utils/PayloadDropperTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.utils;\n\nimport org.apache.dubbo.remoting.exchange.Request;\nimport org.apache.dubbo.remoting.exchange.Response;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass PayloadDropperTest {\n    @Test\n    void test() {\n        Request request = new Request(1);\n        request.setData(new Object());\n        Request requestWithoutData = (Request) PayloadDropper.getRequestWithoutData(request);\n        Assertions.assertEquals(requestWithoutData.getId(), request.getId());\n        Assertions.assertNull(requestWithoutData.getData());\n\n        Response response = new Response(1);\n        response.setResult(new Object());\n        Response responseWithoutData = (Response) PayloadDropper.getRequestWithoutData(response);\n        Assertions.assertEquals(responseWithoutData.getId(), response.getId());\n        Assertions.assertNull(responseWithoutData.getResult());\n\n        Object object = new Object();\n        Assertions.assertEquals(object, PayloadDropper.getRequestWithoutData(object));\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/utils/UrlUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.utils;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.utils.SystemPropertyConfigUtils;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nclass UrlUtilsTest {\n    @Test\n    void testGetIdleTimeout() {\n        URL url1 = URL.valueOf(\"dubbo://127.0.0.1:12345?heartbeat=10000\");\n        URL url2 = URL.valueOf(\"dubbo://127.0.0.1:12345?heartbeat=10000&heartbeat.timeout=50000\");\n        URL url3 = URL.valueOf(\"dubbo://127.0.0.1:12345?heartbeat=10000&heartbeat.timeout=10000\");\n        Assertions.assertEquals(UrlUtils.getIdleTimeout(url1), 30000);\n        Assertions.assertEquals(UrlUtils.getIdleTimeout(url2), 50000);\n        Assertions.assertThrows(RuntimeException.class, () -> UrlUtils.getIdleTimeout(url3));\n    }\n\n    @Test\n    void testGetHeartbeat() {\n        URL url = URL.valueOf(\"dubbo://127.0.0.1:12345?heartbeat=10000\");\n        Assertions.assertEquals(UrlUtils.getHeartbeat(url), 10000);\n    }\n\n    @Test\n    void testConfiguredHeartbeat() {\n        SystemPropertyConfigUtils.setSystemProperty(CommonConstants.DubboProperty.DUBBO_HEARTBEAT_CONFIG_KEY, \"200\");\n        URL url = URL.valueOf(\"dubbo://127.0.0.1:12345\");\n        Assertions.assertEquals(200, UrlUtils.getHeartbeat(url));\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_HEARTBEAT_CONFIG_KEY);\n    }\n\n    @Test\n    void testGetCloseTimeout() {\n        URL url1 = URL.valueOf(\"dubbo://127.0.0.1:12345?heartbeat=10000\");\n        URL url2 = URL.valueOf(\"dubbo://127.0.0.1:12345?heartbeat=10000&heartbeat.timeout=50000\");\n        URL url3 = URL.valueOf(\"dubbo://127.0.0.1:12345?heartbeat=10000&heartbeat.timeout=10000\");\n        URL url4 = URL.valueOf(\"dubbo://127.0.0.1:12345?close.timeout=30000&heartbeat=10000&heartbeat.timeout=10000\");\n        URL url5 = URL.valueOf(\"dubbo://127.0.0.1:12345?close.timeout=40000&heartbeat=10000&heartbeat.timeout=50000\");\n        URL url6 = URL.valueOf(\"dubbo://127.0.0.1:12345?close.timeout=10000&heartbeat=10000&heartbeat.timeout=10000\");\n        Assertions.assertEquals(30000, UrlUtils.getCloseTimeout(url1));\n        Assertions.assertEquals(50000, UrlUtils.getCloseTimeout(url2));\n        Assertions.assertThrows(RuntimeException.class, () -> UrlUtils.getCloseTimeout(url3));\n        Assertions.assertThrows(RuntimeException.class, () -> UrlUtils.getCloseTimeout(url4));\n        Assertions.assertEquals(40000, UrlUtils.getCloseTimeout(url5));\n        Assertions.assertThrows(RuntimeException.class, () -> UrlUtils.getCloseTimeout(url6));\n    }\n\n    @Test\n    void testConfiguredClose() {\n        SystemPropertyConfigUtils.setSystemProperty(\n                CommonConstants.DubboProperty.DUBBO_CLOSE_TIMEOUT_CONFIG_KEY, \"180000\");\n        URL url = URL.valueOf(\"dubbo://127.0.0.1:12345\");\n        Assertions.assertEquals(180000, UrlUtils.getCloseTimeout(url));\n        SystemPropertyConfigUtils.clearSystemProperty(CommonConstants.DubboProperty.DUBBO_CLOSE_TIMEOUT_CONFIG_KEY);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.Transporter",
    "content": "mockTransporter = org.apache.dubbo.remoting.MockTransporter"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.api.WireProtocol",
    "content": "empty=org.apache.dubbo.remoting.api.EmptyProtocol\ntri=org.apache.dubbo.remoting.api.EmptyProtocol"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.exchange.Exchanger",
    "content": "mockExchanger = org.apache.dubbo.remoting.exchange.MockExchanger"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/resources/dubbo.properties",
    "content": "dubbo.application.enable-file-cache=false\ndubbo.service.shutdown.wait=200\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n<Configuration status=\"WARN\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}\" charset=\"UTF-8\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-api/src/test/resources/security/serialize.allowlist",
    "content": "#\n#\n#   Licensed to the Apache Software Foundation (ASF) under one or more\n#   contributor license agreements.  See the NOTICE file distributed with\n#   this work for additional information regarding copyright ownership.\n#   The ASF licenses this file to You under the Apache License, Version 2.0\n#   (the \"License\"); you may not use this file except in compliance with\n#   the License.  You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n#\n#\n\norg.apache.dubbo\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one or more\n  contributor license agreements.  See the NOTICE file distributed with\n  this work for additional information regarding copyright ownership.\n  The ASF licenses this file to You under the Apache License, Version 2.0\n  (the \"License\"); you may not use this file except in compliance with\n  the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.apache.dubbo</groupId>\n    <artifactId>dubbo-remoting</artifactId>\n    <version>${revision}</version>\n    <relativePath>../pom.xml</relativePath>\n  </parent>\n  <artifactId>dubbo-remoting-http12</artifactId>\n  <packaging>jar</packaging>\n  <name>${project.artifactId}</name>\n  <description>The http1/2 remoting module of dubbo project</description>\n  <properties>\n    <skip_maven_deploy>false</skip_maven_deploy>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-rpc-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-common</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.apache.dubbo</groupId>\n      <artifactId>dubbo-remoting-api</artifactId>\n      <version>${project.parent.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>io.netty</groupId>\n      <artifactId>netty-transport</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>io.netty</groupId>\n      <artifactId>netty-codec-http2</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java-util</artifactId>\n      <scope>provided</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>javax.xml.bind</groupId>\n      <artifactId>jaxb-api</artifactId>\n      <scope>provided</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.glassfish.jaxb</groupId>\n      <artifactId>jaxb-runtime</artifactId>\n      <scope>provided</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.yaml</groupId>\n      <artifactId>snakeyaml</artifactId>\n      <scope>provided</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.apache.logging.log4j</groupId>\n      <artifactId>log4j-slf4j-impl</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.common.logger.ErrorTypeAwareLogger;\nimport org.apache.dubbo.common.utils.JsonUtils;\nimport org.apache.dubbo.remoting.http12.exception.HttpStatusException;\nimport org.apache.dubbo.remoting.http12.message.HttpMessageEncoder;\nimport org.apache.dubbo.rpc.RpcContext;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\n\nimport static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;\nimport static org.apache.dubbo.common.logger.LoggerFactory.getErrorTypeAwareLogger;\n\npublic abstract class AbstractServerHttpChannelObserver<H extends HttpChannel> implements ServerHttpChannelObserver<H> {\n\n    private static final ErrorTypeAwareLogger LOGGER = getErrorTypeAwareLogger(AbstractServerHttpChannelObserver.class);\n\n    private final H httpChannel;\n\n    private List<BiConsumer<HttpHeaders, Throwable>> headersCustomizers;\n\n    private List<BiConsumer<HttpHeaders, Throwable>> trailersCustomizers;\n\n    private Function<Throwable, ?> exceptionCustomizer;\n\n    private HttpMessageEncoder responseEncoder;\n\n    private boolean headerSent;\n\n    private boolean completed;\n\n    private boolean closed;\n\n    protected AbstractServerHttpChannelObserver(H httpChannel) {\n        this.httpChannel = httpChannel;\n    }\n\n    @Override\n    public H getHttpChannel() {\n        return httpChannel;\n    }\n\n    @Override\n    public void addHeadersCustomizer(BiConsumer<HttpHeaders, Throwable> headersCustomizer) {\n        if (headersCustomizers == null) {\n            headersCustomizers = new ArrayList<>();\n        }\n        headersCustomizers.add(headersCustomizer);\n    }\n\n    @Override\n    public void addTrailersCustomizer(BiConsumer<HttpHeaders, Throwable> trailersCustomizer) {\n        if (trailersCustomizers == null) {\n            trailersCustomizers = new ArrayList<>();\n        }\n        trailersCustomizers.add(trailersCustomizer);\n    }\n\n    @Override\n    public void setExceptionCustomizer(Function<Throwable, ?> exceptionCustomizer) {\n        this.exceptionCustomizer = exceptionCustomizer;\n    }\n\n    public HttpMessageEncoder getResponseEncoder() {\n        return responseEncoder;\n    }\n\n    public void setResponseEncoder(HttpMessageEncoder responseEncoder) {\n        this.responseEncoder = responseEncoder;\n    }\n\n    @Override\n    public final void onNext(Object data) {\n        if (closed) {\n            return;\n        }\n        try {\n            doOnNext(data);\n        } catch (Throwable t) {\n            LOGGER.warn(INTERNAL_ERROR, \"\", \"\", \"Error while doOnNext\", t);\n            Throwable throwable = t;\n            try {\n                doOnError(throwable);\n            } catch (Throwable t1) {\n                LOGGER.warn(INTERNAL_ERROR, \"\", \"\", \"Error while doOnError, original error: \" + throwable, t1);\n                throwable = t1;\n            }\n            onCompleted(throwable);\n        }\n    }\n\n    @Override\n    public final void onError(Throwable throwable) {\n        if (closed) {\n            return;\n        }\n        try {\n            throwable = customizeError(throwable);\n            if (throwable == null) {\n                return;\n            }\n        } catch (Throwable t) {\n            LOGGER.warn(INTERNAL_ERROR, \"\", \"\", \"Error while handleError, original error: \" + throwable, t);\n            throwable = t;\n        }\n\n        try {\n            doOnError(throwable);\n        } catch (Throwable t) {\n            LOGGER.warn(INTERNAL_ERROR, \"\", \"\", \"Error while doOnError, original error: \" + throwable, t);\n            throwable = t;\n        }\n        onCompleted(throwable);\n    }\n\n    @Override\n    public final void onCompleted() {\n        if (closed) {\n            return;\n        }\n        onCompleted(null);\n    }\n\n    protected void doOnNext(Object data) throws Throwable {\n        int statusCode = resolveStatusCode(data);\n        if (!headerSent) {\n            sendMetadata(buildMetadata(statusCode, data, null, HttpOutputMessage.EMPTY_MESSAGE));\n        }\n        sendMessage(buildMessage(statusCode, data)).whenComplete((unused, throwable) -> {\n            if (throwable != null) {\n                LOGGER.error(INTERNAL_ERROR, \"\", \"\", \"Failed to send message on channel \" + httpChannel, throwable);\n            }\n        });\n    }\n\n    protected final int resolveStatusCode(Object data) {\n        if (data instanceof HttpResult) {\n            int status = ((HttpResult<?>) data).getStatus();\n            if (status >= 100) {\n                return status;\n            }\n        }\n        return HttpStatus.OK.getCode();\n    }\n\n    protected final HttpMetadata buildMetadata(\n            int statusCode, Object data, Throwable throwable, HttpOutputMessage message) {\n        HttpResponse response = RpcContext.getServiceContext().getResponse(HttpResponse.class);\n        HttpMetadata metadata = encodeHttpMetadata(message == null);\n        HttpHeaders headers = metadata.headers();\n        if (response != null && response.headers() != null) {\n            headers.set(response.headers());\n        }\n        headers.set(HttpHeaderNames.STATUS.getKey(), HttpUtils.toStatusString(statusCode));\n        if (message != null) {\n            headers.set(HttpHeaderNames.CONTENT_TYPE.getKey(), responseEncoder.contentType());\n        }\n        customizeHeaders(headers, throwable, message);\n        if (data instanceof HttpResult) {\n            HttpResult<?> result = (HttpResult<?>) data;\n            if (result.getHeaders() != null) {\n                headers.set(result.getHeaders());\n            }\n        }\n        return metadata;\n    }\n\n    protected abstract HttpMetadata encodeHttpMetadata(boolean endStream);\n\n    protected void customizeHeaders(HttpHeaders headers, Throwable throwable, HttpOutputMessage message) {\n        List<BiConsumer<HttpHeaders, Throwable>> headersCustomizers = this.headersCustomizers;\n        if (headersCustomizers != null) {\n            for (int i = 0, size = headersCustomizers.size(); i < size; i++) {\n                headersCustomizers.get(i).accept(headers, throwable);\n            }\n        }\n    }\n\n    protected final void sendMetadata(HttpMetadata metadata) {\n        if (headerSent) {\n            return;\n        }\n        getHttpChannel().writeHeader(metadata);\n        headerSent = true;\n        if (LOGGER.isDebugEnabled()) {\n            LOGGER.debug(\"Http response headers sent: \" + metadata.headers());\n        }\n    }\n\n    protected HttpOutputMessage buildMessage(int statusCode, Object data) throws Throwable {\n        if (statusCode < 200 || statusCode == 204 || statusCode == 304) {\n            return null;\n        }\n        if (data instanceof HttpResult) {\n            data = ((HttpResult<?>) data).getBody();\n        }\n        if (data == null && statusCode != 200) {\n            return null;\n        }\n\n        if (LOGGER.isDebugEnabled()) {\n            try {\n                String text;\n                if (data instanceof byte[]) {\n                    text = new String((byte[]) data, StandardCharsets.UTF_8);\n                } else {\n                    text = JsonUtils.toJson(data);\n                }\n                LOGGER.debug(\"Http response body sent: '{}' by [{}]\", text, httpChannel);\n            } catch (Throwable ignored) {\n            }\n        }\n        HttpOutputMessage message = encodeHttpOutputMessage(data);\n        try {\n            preOutputMessage(message);\n            responseEncoder.encode(message.getBody(), data);\n        } catch (Throwable t) {\n            message.close();\n            throw t;\n        }\n        return message;\n    }\n\n    protected HttpOutputMessage encodeHttpOutputMessage(Object data) {\n        return getHttpChannel().newOutputMessage();\n    }\n\n    protected CompletableFuture<Void> sendMessage(HttpOutputMessage message) throws Throwable {\n        if (message == null) {\n            return CompletableFuture.completedFuture(null);\n        }\n        CompletableFuture<Void> future = getHttpChannel().writeMessage(message);\n        postOutputMessage(message);\n        return future;\n    }\n\n    protected void preOutputMessage(HttpOutputMessage message) throws Throwable {}\n\n    protected void postOutputMessage(HttpOutputMessage message) throws Throwable {}\n\n    protected Throwable customizeError(Throwable throwable) {\n        if (exceptionCustomizer == null) {\n            return throwable;\n        }\n        Object result = exceptionCustomizer.apply(throwable);\n        if (result == null) {\n            return throwable;\n        }\n        if (result instanceof Throwable) {\n            return (Throwable) result;\n        }\n        onNext(result);\n        return null;\n    }\n\n    protected void doOnError(Throwable throwable) throws Throwable {\n        int statusCode = resolveErrorStatusCode(throwable);\n        Object data = buildErrorResponse(statusCode, throwable);\n        if (!headerSent) {\n            sendMetadata(buildMetadata(statusCode, data, throwable, HttpOutputMessage.EMPTY_MESSAGE));\n        }\n        sendMessage(buildMessage(statusCode, data)).whenComplete((unused, t) -> {\n            if (t != null) {\n                LOGGER.error(INTERNAL_ERROR, \"\", \"\", \"Failed to send error message on channel \" + httpChannel, t);\n            }\n        });\n    }\n\n    protected final int resolveErrorStatusCode(Throwable throwable) {\n        if (throwable == null) {\n            return HttpStatus.OK.getCode();\n        }\n        if (throwable instanceof HttpStatusException) {\n            return ((HttpStatusException) throwable).getStatusCode();\n        }\n        return HttpStatus.INTERNAL_SERVER_ERROR.getCode();\n    }\n\n    protected final ErrorResponse buildErrorResponse(int statusCode, Throwable throwable) {\n        ErrorResponse errorResponse = new ErrorResponse();\n        errorResponse.setStatus(HttpUtils.toStatusString(statusCode));\n        if (throwable instanceof HttpStatusException) {\n            errorResponse.setMessage(((HttpStatusException) throwable).getDisplayMessage());\n        } else {\n            errorResponse.setMessage(getDisplayMessage(throwable));\n        }\n        return errorResponse;\n    }\n\n    protected String getDisplayMessage(Throwable throwable) {\n        return \"Internal Server Error\";\n    }\n\n    protected void onCompleted(Throwable throwable) {\n        if (completed) {\n            return;\n        }\n        doOnCompleted(throwable);\n        completed = true;\n    }\n\n    protected void doOnCompleted(Throwable throwable) {\n        HttpMetadata trailerMetadata = encodeTrailers(throwable);\n        if (trailerMetadata == null) {\n            return;\n        }\n        HttpHeaders headers = trailerMetadata.headers();\n        if (!headerSent) {\n            headers.set(HttpHeaderNames.STATUS.getKey(), HttpUtils.toStatusString(resolveErrorStatusCode(throwable)));\n            headers.set(HttpHeaderNames.CONTENT_TYPE.getKey(), getContentType());\n        }\n        customizeTrailers(headers, throwable);\n        getHttpChannel().writeHeader(trailerMetadata);\n        if (LOGGER.isDebugEnabled()) {\n            LOGGER.debug(\"Http response trailers sent: \" + headers);\n        }\n    }\n\n    protected HttpMetadata encodeTrailers(Throwable throwable) {\n        return null;\n    }\n\n    protected String getContentType() {\n        return responseEncoder.contentType();\n    }\n\n    protected boolean isHeaderSent() {\n        return headerSent;\n    }\n\n    protected void customizeTrailers(HttpHeaders headers, Throwable throwable) {\n        List<BiConsumer<HttpHeaders, Throwable>> trailersCustomizers = this.trailersCustomizers;\n        if (trailersCustomizers != null) {\n            for (int i = 0, size = trailersCustomizers.size(); i < size; i++) {\n                trailersCustomizers.get(i).accept(headers, throwable);\n            }\n        }\n    }\n\n    @Override\n    public void close() {\n        closed();\n    }\n\n    protected final void closed() {\n        closed = true;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/CompositeInputStream.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.remoting.http12.exception.DecodeException;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Queue;\nimport java.util.concurrent.ConcurrentLinkedQueue;\n\npublic class CompositeInputStream extends InputStream {\n\n    private final Queue<InputStream> inputStreams = new ConcurrentLinkedQueue<>();\n\n    private int totalAvailable = 0;\n\n    private int readIndex = 0;\n\n    public void addInputStream(InputStream inputStream) {\n        inputStreams.offer(inputStream);\n        try {\n            totalAvailable += inputStream.available();\n        } catch (IOException e) {\n            throw new DecodeException(e);\n        }\n    }\n\n    @Override\n    public int read() throws IOException {\n        InputStream inputStream;\n        while ((inputStream = inputStreams.peek()) != null) {\n            int available = inputStream.available();\n            if (available == 0) {\n                releaseHeadStream();\n                continue;\n            }\n            int read = inputStream.read();\n            if (read != -1) {\n                ++readIndex;\n                releaseIfNecessary(inputStream);\n                return read;\n            }\n            releaseHeadStream();\n        }\n        return -1;\n    }\n\n    @Override\n    public int read(byte[] b, int off, int len) throws IOException {\n        if (b == null) {\n            throw new NullPointerException();\n        } else if (off < 0 || len < 0 || len > b.length - off) {\n            throw new IndexOutOfBoundsException();\n        } else if (len == 0) {\n            return 0;\n        }\n\n        int total = 0;\n        InputStream inputStream;\n        while ((inputStream = inputStreams.peek()) != null) {\n            int available = inputStream.available();\n            if (available == 0) {\n                releaseHeadStream();\n                continue;\n            }\n\n            int read = inputStream.read(b, off + total, Math.min(len - total, available));\n            if (read != -1) {\n                total += read;\n                readIndex += read;\n                releaseIfNecessary(inputStream);\n\n                if (total == len) {\n                    return total;\n                }\n            } else {\n                releaseHeadStream();\n            }\n        }\n\n        return total > 0 ? total : -1;\n    }\n\n    @Override\n    public int available() {\n        return totalAvailable - readIndex;\n    }\n\n    @Override\n    public void close() throws IOException {\n        InputStream inputStream;\n        while ((inputStream = inputStreams.poll()) != null) {\n            inputStream.close();\n        }\n    }\n\n    private void releaseHeadStream() {\n        InputStream removeStream = inputStreams.poll();\n        if (removeStream != null) {\n            try {\n                removeStream.close();\n            } catch (IOException ignore) {\n                // ignore\n            }\n        }\n    }\n\n    private void releaseIfNecessary(InputStream inputStream) throws IOException {\n        int available = inputStream.available();\n        if (available == 0) {\n            releaseHeadStream();\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/ErrorCodeHolder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\npublic interface ErrorCodeHolder {\n\n    long getErrorCode();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/ErrorResponse.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.common.utils.ToStringUtils;\n\nimport java.io.Serializable;\n\npublic class ErrorResponse implements Serializable {\n\n    private static final long serialVersionUID = 6828386002146790334L;\n\n    private String status;\n\n    private String message;\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    @Override\n    public String toString() {\n        return ToStringUtils.printToString(this);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/ExceptionHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.common.logger.Level;\nimport org.apache.dubbo.rpc.model.MethodDescriptor;\n\n/**\n * Interface for customize exception handling.\n *\n * @param <E> the type of exception to handle\n * @param <T> the type of result returned\n */\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface ExceptionHandler<E extends Throwable, T> {\n\n    /**\n     * Resolves the log level for a given throwable.\n     *\n     * @param throwable the exception\n     * @return the log level, or null to ignore this extension\n     */\n    default Level resolveLogLevel(E throwable) {\n        return null;\n    }\n\n    /**\n     * Resolves the gRPC status for a given throwable.\n     *\n     * @param headers    the response headers\n     * @param throwable  the exception\n     * @param metadata   the request metadata, may be null\n     * @param descriptor the method descriptor, may be null\n     */\n    default boolean resolveGrpcStatus(\n            E throwable, HttpHeaders headers, RequestMetadata metadata, MethodDescriptor descriptor) {\n        return false;\n    }\n\n    /**\n     * Handle the exception and return a result.\n     *\n     * @param throwable  the exception\n     * @param metadata   the request metadata, may be null\n     * @param descriptor the method descriptor, may be null\n     * @return a result of type T, or null to ignore this extension\n     */\n    default T handle(E throwable, RequestMetadata metadata, MethodDescriptor descriptor) {\n        return null;\n    }\n\n    /**\n     * Handles the exception and return a result for gRPC protocol.\n     *\n     * @param throwable  the exception\n     * @param metadata   the request metadata, may be null\n     * @param descriptor the method descriptor, may be null\n     * @return a result of type T, or null to ignore this extension\n     */\n    default T handleGrpc(E throwable, RequestMetadata metadata, MethodDescriptor descriptor) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/FlowControlStreamObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\n\npublic interface FlowControlStreamObserver<T> extends StreamObserver<T> {\n\n    /**\n     * Requests the peer to produce {@code count} more messages to be delivered to the 'inbound'\n     * {@link StreamObserver}.\n     *\n     * <p>This method is safe to call from multiple threads without external synchronization.\n     *\n     * @param count more messages\n     */\n    void request(int count);\n\n    boolean isAutoRequestN();\n\n    /**\n     * Swaps to manual flow control where no message will be delivered to {@link\n     * StreamObserver#onNext(Object)} unless it is {@link #request request()}ed. Since {@code\n     * request()} may not be called before the call is started, a number of initial requests may be\n     * specified.\n     */\n    void disableAutoFlowControl();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport java.net.SocketAddress;\nimport java.util.concurrent.CompletableFuture;\n\npublic interface HttpChannel {\n\n    CompletableFuture<Void> writeHeader(HttpMetadata httpMetadata);\n\n    CompletableFuture<Void> writeMessage(HttpOutputMessage httpOutputMessage);\n\n    HttpOutputMessage newOutputMessage();\n\n    SocketAddress remoteAddress();\n\n    SocketAddress localAddress();\n\n    void flush();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpChannelHolder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\npublic interface HttpChannelHolder {\n\n    HttpChannel getHttpChannel();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\npublic final class HttpConstants {\n\n    public static final String TRAILERS = \"trailers\";\n\n    public static final String CHUNKED = \"chunked\";\n\n    public static final String NO_CACHE = \"no-cache\";\n\n    public static final String X_FORWARDED_PROTO = \"x-forwarded-proto\";\n    public static final String X_FORWARDED_HOST = \"x-forwarded-host\";\n    public static final String X_FORWARDED_PORT = \"x-forwarded-port\";\n\n    public static final String HTTPS = \"https\";\n    public static final String HTTP = \"http\";\n\n    private HttpConstants() {}\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpCookie.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.common.utils.Assert;\nimport org.apache.dubbo.common.utils.StringUtils;\n\npublic final class HttpCookie {\n\n    private final String name;\n    private String value;\n    private String domain;\n    private String path;\n    private long maxAge = Long.MIN_VALUE;\n    private boolean secure;\n    private boolean httpOnly;\n    private String sameSite;\n\n    public HttpCookie(String name, String value) {\n        name = StringUtils.trim(name);\n        Assert.notEmptyString(name, \"name is required\");\n        this.name = name;\n        setValue(value);\n    }\n\n    public String name() {\n        return name;\n    }\n\n    public String value() {\n        return value;\n    }\n\n    public void setValue(String value) {\n        Assert.notNull(name, \"value can not be null\");\n        this.value = value;\n    }\n\n    public String domain() {\n        return domain;\n    }\n\n    public void setDomain(String domain) {\n        this.domain = domain;\n    }\n\n    public String path() {\n        return path;\n    }\n\n    public void setPath(String path) {\n        this.path = path;\n    }\n\n    public long maxAge() {\n        return maxAge;\n    }\n\n    public void setMaxAge(long maxAge) {\n        this.maxAge = maxAge;\n    }\n\n    public boolean secure() {\n        return secure;\n    }\n\n    public void setSecure(boolean secure) {\n        this.secure = secure;\n    }\n\n    public boolean httpOnly() {\n        return httpOnly;\n    }\n\n    public void setHttpOnly(boolean httpOnly) {\n        this.httpOnly = httpOnly;\n    }\n\n    public String sameSite() {\n        return sameSite;\n    }\n\n    public void setSameSite(String sameSite) {\n        this.sameSite = sameSite;\n    }\n\n    public String toString() {\n        StringBuilder buf = new StringBuilder(name).append('=').append(value);\n        if (domain != null) {\n            buf.append(\", domain=\").append(domain);\n        }\n        if (path != null) {\n            buf.append(\", path=\").append(path);\n        }\n        if (maxAge >= 0) {\n            buf.append(\", maxAge=\").append(maxAge).append('s');\n        }\n        if (secure) {\n            buf.append(\", secure\");\n        }\n        if (httpOnly) {\n            buf.append(\", HTTPOnly\");\n        }\n        if (sameSite != null) {\n            buf.append(\", SameSite=\").append(sameSite);\n        }\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaderNames.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport io.netty.handler.codec.http2.Http2Headers.PseudoHeaderName;\nimport io.netty.util.AsciiString;\n\npublic enum HttpHeaderNames {\n    STATUS(PseudoHeaderName.STATUS.value()),\n\n    PATH(PseudoHeaderName.PATH.value()),\n\n    METHOD(PseudoHeaderName.METHOD.value()),\n\n    ACCEPT(io.netty.handler.codec.http.HttpHeaderNames.ACCEPT),\n\n    CONTENT_TYPE(io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE),\n\n    CONTENT_LENGTH(io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH),\n\n    CONTENT_LANGUAGE(io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LANGUAGE),\n\n    TRANSFER_ENCODING(io.netty.handler.codec.http.HttpHeaderNames.TRANSFER_ENCODING),\n\n    CACHE_CONTROL(io.netty.handler.codec.http.HttpHeaderNames.CACHE_CONTROL),\n\n    LOCATION(io.netty.handler.codec.http.HttpHeaderNames.LOCATION),\n\n    HOST(io.netty.handler.codec.http.HttpHeaderNames.HOST),\n\n    COOKIE(io.netty.handler.codec.http.HttpHeaderNames.COOKIE),\n\n    SET_COOKIE(io.netty.handler.codec.http.HttpHeaderNames.SET_COOKIE),\n\n    LAST_MODIFIED(io.netty.handler.codec.http.HttpHeaderNames.LAST_MODIFIED),\n\n    TE(io.netty.handler.codec.http.HttpHeaderNames.TE),\n\n    CONNECTION(io.netty.handler.codec.http.HttpHeaderNames.CONNECTION),\n\n    ALT_SVC(\"alt-svc\");\n\n    private final String name;\n    private final CharSequence key;\n\n    HttpHeaderNames(String name) {\n        this.name = name;\n        key = AsciiString.cached(name);\n    }\n\n    HttpHeaderNames(CharSequence key) {\n        name = key.toString();\n        this.key = key;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public CharSequence getKey() {\n        return key;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaders.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.remoting.http12.message.DefaultHttpHeaders;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\n\npublic interface HttpHeaders extends Iterable<Entry<CharSequence, String>> {\n\n    int size();\n\n    boolean isEmpty();\n\n    boolean containsKey(CharSequence key);\n\n    String getFirst(CharSequence name);\n\n    List<String> get(CharSequence key);\n\n    HttpHeaders add(CharSequence name, String value);\n\n    HttpHeaders add(CharSequence name, Iterable<String> value);\n\n    HttpHeaders add(CharSequence name, String... value);\n\n    HttpHeaders add(Map<? extends CharSequence, ? extends Iterable<String>> map);\n\n    HttpHeaders add(HttpHeaders headers);\n\n    HttpHeaders set(CharSequence name, String value);\n\n    HttpHeaders set(CharSequence name, Iterable<String> value);\n\n    HttpHeaders set(CharSequence name, String... value);\n\n    HttpHeaders set(Map<? extends CharSequence, ? extends Iterable<String>> map);\n\n    HttpHeaders set(HttpHeaders headers);\n\n    List<String> remove(CharSequence key);\n\n    void clear();\n\n    Set<String> names();\n\n    Set<CharSequence> nameSet();\n\n    Map<String, List<String>> asMap();\n\n    @Override\n    Iterator<Entry<CharSequence, String>> iterator();\n\n    default Map<String, List<String>> toMap() {\n        Map<String, List<String>> map = CollectionUtils.newLinkedHashMap(size());\n        for (Entry<CharSequence, String> entry : this) {\n            map.computeIfAbsent(entry.getKey().toString(), k -> new ArrayList<>(1))\n                    .add(entry.getValue());\n        }\n        return map;\n    }\n\n    default void forEach(BiConsumer<String, String> action) {\n        for (Entry<CharSequence, String> entry : this) {\n            action.accept(entry.getKey().toString(), entry.getValue());\n        }\n    }\n\n    static HttpHeaders create() {\n        return new DefaultHttpHeaders();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpInputMessage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\npublic interface HttpInputMessage extends AutoCloseable {\n\n    InputStream getBody();\n\n    @Override\n    default void close() throws IOException {\n        getBody().close();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpJsonUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.common.config.Configuration;\nimport org.apache.dubbo.common.config.ConfigurationUtils;\nimport org.apache.dubbo.common.json.JsonUtil;\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.rpc.Constants;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\nimport java.lang.reflect.Type;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\npublic final class HttpJsonUtils {\n\n    private final JsonUtil jsonUtil;\n\n    public HttpJsonUtils(FrameworkModel frameworkModel) {\n        Configuration configuration = ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication());\n        JsonUtil jsonUtil;\n        String name = configuration.getString(Constants.H2_SETTINGS_JSON_FRAMEWORK_NAME, null);\n        if (name == null) {\n            jsonUtil = CollectionUtils.first(frameworkModel.getActivateExtensions(JsonUtil.class));\n        } else {\n            try {\n                jsonUtil = frameworkModel.getExtension(JsonUtil.class, name);\n            } catch (Exception e) {\n                throw new IllegalStateException(\"Failed to load json framework: \" + name, e);\n            }\n        }\n\n        this.jsonUtil = Objects.requireNonNull(jsonUtil, \"Dubbo unable to find out any json framework\");\n    }\n\n    public <T> T toJavaObject(String json, Type type) {\n        return jsonUtil.toJavaObject(json, type);\n    }\n\n    public <T> List<T> toJavaList(String json, Class<T> clazz) {\n        return jsonUtil.toJavaList(json, clazz);\n    }\n\n    public String toJson(Object obj) {\n        return jsonUtil.toJson(obj);\n    }\n\n    public String toPrettyJson(Object obj) {\n        return jsonUtil.toPrettyJson(obj);\n    }\n\n    public Object convertObject(Object obj, Type targetType) {\n        return jsonUtil.convertObject(obj, targetType);\n    }\n\n    public Object convertObject(Object obj, Class<?> targetType) {\n        return jsonUtil.convertObject(obj, targetType);\n    }\n\n    public String getString(Map<String, ?> obj, String key) {\n        return jsonUtil.getString(obj, key);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMetadata.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\npublic interface HttpMetadata {\n\n    HttpHeaders headers();\n\n    default String contentType() {\n        return header(HttpHeaderNames.CONTENT_TYPE.getKey());\n    }\n\n    default String header(CharSequence name) {\n        return headers().getFirst(name);\n    }\n\n    default HttpMetadata header(CharSequence name, String value) {\n        headers().set(name, value);\n        return this;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport java.nio.charset.StandardCharsets;\n\npublic enum HttpMethods {\n    GET,\n    HEAD,\n    POST,\n    PUT,\n    PATCH,\n    DELETE,\n    OPTIONS,\n    TRACE;\n\n    public static final byte[][] HTTP_METHODS_BYTES;\n\n    static {\n        HttpMethods[] methods = values();\n        int len = methods.length;\n        HTTP_METHODS_BYTES = new byte[len][];\n        for (int i = 0; i < len; i++) {\n            HTTP_METHODS_BYTES[i] = methods[i].name().getBytes(StandardCharsets.ISO_8859_1);\n        }\n    }\n\n    public boolean is(String name) {\n        return name().equals(name);\n    }\n\n    public boolean supportBody() {\n        return this == POST || this == PUT || this == PATCH;\n    }\n\n    @SuppressWarnings(\"StringEquality\")\n    public static HttpMethods of(String name) {\n        // fast-path\n        if (name == GET.name()) {\n            return GET;\n        } else if (name == POST.name()) {\n            return POST;\n        }\n        return valueOf(name);\n    }\n\n    public static boolean isGet(String name) {\n        return GET.name().equals(name);\n    }\n\n    public static boolean isPost(String name) {\n        return POST.name().equals(name);\n    }\n\n    public static boolean supportBody(String name) {\n        return name.charAt(0) == 'P';\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpOutputMessage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\npublic interface HttpOutputMessage extends AutoCloseable {\n\n    HttpOutputMessage EMPTY_MESSAGE = new HttpOutputMessage() {\n\n        private final OutputStream INPUT_STREAM = new ByteArrayOutputStream(0);\n\n        @Override\n        public OutputStream getBody() {\n            return INPUT_STREAM;\n        }\n\n        @Override\n        public int messageSize() {\n            return 0;\n        }\n    };\n\n    OutputStream getBody();\n\n    /**\n     * Returns the size of the message body in bytes.\n     *\n     * @return the size of the message body, or 0 if unknown\n     */\n    int messageSize();\n\n    @Override\n    default void close() throws IOException {\n        getBody().close();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport java.io.InputStream;\nimport java.nio.charset.Charset;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic interface HttpRequest extends RequestMetadata {\n\n    boolean isHttp2();\n\n    String method();\n\n    void setMethod(String method);\n\n    String uri();\n\n    void setUri(String uri);\n\n    String path();\n\n    String rawPath();\n\n    String query();\n\n    String header(CharSequence name);\n\n    List<String> headerValues(CharSequence name);\n\n    Date dateHeader(CharSequence name);\n\n    boolean hasHeader(CharSequence name);\n\n    Collection<String> headerNames();\n\n    HttpHeaders headers();\n\n    void setHeader(CharSequence name, String value);\n\n    void setHeader(CharSequence name, List<String> values);\n\n    void setHeader(CharSequence name, Date value);\n\n    Collection<HttpCookie> cookies();\n\n    HttpCookie cookie(String name);\n\n    int contentLength();\n\n    String contentType();\n\n    void setContentType(String contentType);\n\n    String mediaType();\n\n    String charset();\n\n    Charset charsetOrDefault();\n\n    void setCharset(String charset);\n\n    String accept();\n\n    Locale locale();\n\n    List<Locale> locales();\n\n    String scheme();\n\n    String serverHost();\n\n    String serverName();\n\n    int serverPort();\n\n    String remoteHost();\n\n    String remoteAddr();\n\n    int remotePort();\n\n    String localHost();\n\n    String localAddr();\n\n    int localPort();\n\n    String parameter(String name);\n\n    String parameter(String name, String defaultValue);\n\n    List<String> parameterValues(String name);\n\n    String queryParameter(String name);\n\n    List<String> queryParameterValues(String name);\n\n    Collection<String> queryParameterNames();\n\n    Map<String, List<String>> queryParameters();\n\n    String formParameter(String name);\n\n    List<String> formParameterValues(String name);\n\n    Collection<String> formParameterNames();\n\n    boolean hasParameter(String name);\n\n    Collection<String> parameterNames();\n\n    Collection<FileUpload> parts();\n\n    FileUpload part(String name);\n\n    <T> T attribute(String name);\n\n    void removeAttribute(String name);\n\n    void setAttribute(String name, Object value);\n\n    boolean hasAttribute(String name);\n\n    Collection<String> attributeNames();\n\n    Map<String, Object> attributes();\n\n    InputStream inputStream();\n\n    void setInputStream(InputStream is);\n\n    interface FileUpload {\n\n        String name();\n\n        String filename();\n\n        String contentType();\n\n        int size();\n\n        InputStream inputStream();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpResponse.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport java.io.OutputStream;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.List;\n\npublic interface HttpResponse {\n\n    int status();\n\n    void setStatus(int status);\n\n    String header(CharSequence name);\n\n    Date dateHeader(CharSequence name);\n\n    List<String> headerValues(CharSequence name);\n\n    boolean hasHeader(CharSequence name);\n\n    Collection<String> headerNames();\n\n    HttpHeaders headers();\n\n    void addHeader(CharSequence name, String value);\n\n    void addHeader(CharSequence name, Date value);\n\n    void setHeader(CharSequence name, String value);\n\n    void setHeader(CharSequence name, Date value);\n\n    void setHeader(CharSequence name, List<String> value);\n\n    void addCookie(HttpCookie cookie);\n\n    String contentType();\n\n    void setContentType(String contentType);\n\n    String mediaType();\n\n    String charset();\n\n    void setCharset(String charset);\n\n    String locale();\n\n    void setLocale(String locale);\n\n    Object body();\n\n    void setBody(Object body);\n\n    OutputStream outputStream();\n\n    void setOutputStream(OutputStream os);\n\n    void sendRedirect(String location);\n\n    void sendError(int status);\n\n    void sendError(int status, String message);\n\n    boolean isEmpty();\n\n    boolean isContentEmpty();\n\n    boolean isCommitted();\n\n    void commit();\n\n    void setCommitted(boolean committed);\n\n    void reset();\n\n    void resetBuffer();\n\n    HttpResult<Object> toHttpResult();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpResult.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException;\nimport org.apache.dubbo.remoting.http12.message.DefaultHttpResult.Builder;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\npublic interface HttpResult<T> extends Serializable {\n\n    int getStatus();\n\n    Map<String, List<String>> getHeaders();\n\n    T getBody();\n\n    default HttpResultPayloadException toPayload() {\n        return new HttpResultPayloadException(this);\n    }\n\n    static <T> Builder<T> builder() {\n        return new Builder<>();\n    }\n\n    static <T> HttpResult<T> of(T body) {\n        return new Builder<T>().body(body).build();\n    }\n\n    static <T> HttpResult<T> of(int status, T body) {\n        if (body instanceof String) {\n            if (status == HttpStatus.MOVED_PERMANENTLY.getCode()) {\n                return moved((String) body);\n            } else if (status == HttpStatus.FOUND.getCode()) {\n                return found((String) body);\n            }\n        }\n        return new Builder<T>().status(status).body(body).build();\n    }\n\n    static <T> HttpResult<T> of(HttpStatus status, T body) {\n        return of(status.getCode(), body);\n    }\n\n    static <T> HttpResult<T> status(int status) {\n        return new Builder<T>().status(status).build();\n    }\n\n    static <T> HttpResult<T> status(HttpStatus status) {\n        return status(status.getCode());\n    }\n\n    static <T> HttpResult<T> ok() {\n        return new Builder<T>().status(HttpStatus.OK).build();\n    }\n\n    static <T> HttpResult<T> moved(String url) {\n        return new Builder<T>().moved(url).build();\n    }\n\n    static <T> HttpResult<T> found(String url) {\n        return new Builder<T>().found(url).build();\n    }\n\n    static <T> HttpResult<T> badRequest() {\n        return new Builder<T>().status(HttpStatus.BAD_REQUEST).build();\n    }\n\n    static <T> HttpResult<T> notFound() {\n        return new Builder<T>().status(HttpStatus.NOT_FOUND).build();\n    }\n\n    static HttpResult<String> error() {\n        return new Builder<String>().status(HttpStatus.INTERNAL_SERVER_ERROR).build();\n    }\n\n    static HttpResult<String> error(String message) {\n        return error(HttpStatus.INTERNAL_SERVER_ERROR, message);\n    }\n\n    static HttpResult<String> error(int status, String message) {\n        return new Builder<String>().status(status).body(message).build();\n    }\n\n    static HttpResult<String> error(HttpStatus status, String message) {\n        return new Builder<String>().status(status).body(message).build();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpStatus.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\npublic enum HttpStatus {\n    OK(200),\n    CREATED(201),\n    ACCEPTED(202),\n    NO_CONTENT(204),\n    MOVED_PERMANENTLY(301),\n    FOUND(302),\n    BAD_REQUEST(400),\n    UNAUTHORIZED(401),\n    FORBIDDEN(403),\n    NOT_FOUND(404),\n    METHOD_NOT_ALLOWED(405),\n    NOT_ACCEPTABLE(406),\n    REQUEST_TIMEOUT(408),\n    CONFLICT(409),\n    UNSUPPORTED_MEDIA_TYPE(415),\n    INTERNAL_SERVER_ERROR(500);\n\n    private final int code;\n\n    private final String statusString;\n\n    HttpStatus(int code) {\n        this.code = code;\n        this.statusString = String.valueOf(code);\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getStatusString() {\n        return statusString;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpTransportListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\npublic interface HttpTransportListener<HEADER extends HttpMetadata, MESSAGE extends HttpInputMessage> {\n\n    void onMetadata(HEADER metadata);\n\n    void onData(MESSAGE message);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.common.constants.CommonConstants;\nimport org.apache.dubbo.common.io.StreamUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.exception.DecodeException;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.ByteBufAllocator;\nimport io.netty.buffer.ByteBufInputStream;\nimport io.netty.buffer.ByteBufOutputStream;\nimport io.netty.buffer.UnpooledByteBufAllocator;\nimport io.netty.handler.codec.http.DefaultFullHttpRequest;\nimport io.netty.handler.codec.http.DefaultHttpHeaders;\nimport io.netty.handler.codec.http.HttpHeaders;\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.handler.codec.http.HttpVersion;\nimport io.netty.handler.codec.http.cookie.Cookie;\nimport io.netty.handler.codec.http.cookie.CookieHeaderNames.SameSite;\nimport io.netty.handler.codec.http.cookie.DefaultCookie;\nimport io.netty.handler.codec.http.cookie.ServerCookieDecoder;\nimport io.netty.handler.codec.http.cookie.ServerCookieEncoder;\nimport io.netty.handler.codec.http.multipart.Attribute;\nimport io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;\nimport io.netty.handler.codec.http.multipart.FileUpload;\nimport io.netty.handler.codec.http.multipart.HttpDataFactory;\nimport io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;\nimport io.netty.handler.codec.http.multipart.InterfaceHttpData;\n\npublic final class HttpUtils {\n\n    public static final ByteBufAllocator HEAP_ALLOC = new UnpooledByteBufAllocator(false, false);\n    public static final HttpDataFactory DATA_FACTORY = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);\n    public static final String CHARSET_PREFIX = \"charset=\";\n\n    private HttpUtils() {}\n\n    public static String getStatusMessage(int status) {\n        return HttpResponseStatus.valueOf(status).reasonPhrase();\n    }\n\n    public static String toStatusString(int statusCode) {\n        if (statusCode == 200) {\n            return HttpStatus.OK.getStatusString();\n        }\n        if (statusCode == 500) {\n            return HttpStatus.INTERNAL_SERVER_ERROR.getStatusString();\n        }\n        return Integer.toString(statusCode);\n    }\n\n    public static List<HttpCookie> decodeCookies(String value) {\n        List<HttpCookie> cookies = new ArrayList<>();\n        if (StringUtils.isEmpty(value)) {\n            return cookies;\n        }\n        for (Cookie c : ServerCookieDecoder.LAX.decodeAll(value)) {\n            cookies.add(new HttpCookie(c.name(), c.value()));\n        }\n        return cookies;\n    }\n\n    public static String parseCharset(String contentType) {\n        String charset = null;\n        if (contentType == null) {\n            charset = StringUtils.EMPTY_STRING;\n        } else {\n            int index = contentType.lastIndexOf(CHARSET_PREFIX);\n            if (index == -1) {\n                charset = StringUtils.EMPTY_STRING;\n            } else {\n                charset = contentType.substring(index + CHARSET_PREFIX.length()).trim();\n                int splits = charset.indexOf(CommonConstants.SEMICOLON_SEPARATOR);\n                if (splits == -1) {\n                    return charset;\n                } else {\n                    return charset.substring(0, splits).trim();\n                }\n            }\n        }\n        return charset;\n    }\n\n    public static String encodeCookie(HttpCookie cookie) {\n        DefaultCookie c = new DefaultCookie(cookie.name(), cookie.value());\n        c.setPath(cookie.path());\n        c.setDomain(cookie.domain());\n        c.setMaxAge(cookie.maxAge());\n        c.setSecure(cookie.secure());\n        c.setHttpOnly(cookie.httpOnly());\n        c.setSameSite(SameSite.valueOf(cookie.sameSite()));\n        return ServerCookieEncoder.LAX.encode(c);\n    }\n\n    public static List<String> parseAccept(String header) {\n        if (header == null) {\n            return new ArrayList<>();\n        }\n        List<Item<String>> mediaTypes = new ArrayList<>();\n        for (String item : StringUtils.tokenize(header, ',')) {\n            int index = item.indexOf(';');\n            mediaTypes.add(new Item<>(StringUtils.substring(item, 0, index), parseQuality(item, index)));\n        }\n        return Item.sortAndGet(mediaTypes);\n    }\n\n    public static float parseQuality(String expr, int index) {\n        float quality = 1.0F;\n        if (index != -1) {\n            int qStart = expr.indexOf(\"q=\", index + 1);\n            if (qStart != -1) {\n                qStart += 2;\n                int qEnd = expr.indexOf(',', qStart);\n                String qString = qEnd == -1\n                        ? expr.substring(qStart)\n                        : expr.substring(qStart, qEnd).trim();\n                try {\n                    quality = Float.parseFloat(qString);\n                } catch (NumberFormatException ignored) {\n                }\n            }\n        }\n        return quality;\n    }\n\n    public static List<Locale> parseAcceptLanguage(String header) {\n        if (header == null) {\n            return new ArrayList<>();\n        }\n        List<Item<Locale>> locales = new ArrayList<>();\n        for (String item : StringUtils.tokenize(header, ',')) {\n            String[] pair = StringUtils.tokenize(item, ';');\n            locales.add(new Item<>(parseLocale(pair[0]), pair.length > 1 ? Float.parseFloat(pair[1]) : 1.0F));\n        }\n        return Item.sortAndGet(locales);\n    }\n\n    public static List<Locale> parseContentLanguage(String header) {\n        if (header == null) {\n            return new ArrayList<>();\n        }\n        List<Locale> locales = new ArrayList<>();\n        for (String item : StringUtils.tokenize(header, ',')) {\n            locales.add(parseLocale(item));\n        }\n        return locales;\n    }\n\n    public static Locale parseLocale(String locale) {\n        String[] parts = StringUtils.tokenize(locale, '-', '_');\n        switch (parts.length) {\n            case 2:\n                return new Locale(parts[0], parts[1]);\n            case 3:\n                return new Locale(parts[0], parts[1], parts[2]);\n            default:\n                return new Locale(parts[0]);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static HttpPostRequestDecoder createPostRequestDecoder(\n            HttpRequest request, InputStream inputStream, String charset) {\n        ByteBuf data;\n        boolean canMark = inputStream.markSupported();\n        try {\n            if (canMark) {\n                inputStream.mark(Integer.MAX_VALUE);\n            }\n            if (inputStream.available() == 0) {\n                return null;\n            } else {\n                data = HEAP_ALLOC.buffer();\n                ByteBufOutputStream os = new ByteBufOutputStream(data);\n                StreamUtils.copy(inputStream, os);\n            }\n        } catch (IOException e) {\n            throw new DecodeException(\"Error while reading post data: \" + e.getMessage(), e);\n        } finally {\n            try {\n                if (canMark) {\n                    inputStream.reset();\n                } else {\n                    inputStream.close();\n                }\n            } catch (IOException ignored) {\n            }\n        }\n        DefaultFullHttpRequest nRequest = new DefaultFullHttpRequest(\n                HttpVersion.HTTP_1_1,\n                HttpMethod.POST,\n                request.uri(),\n                data,\n                new DefaultHttpHeaders(false),\n                new DefaultHttpHeaders(false));\n        HttpHeaders headers = nRequest.headers();\n        request.headers().forEach(e -> headers.add(e.getKey(), e.getValue()));\n\n        if (charset == null) {\n            return new HttpPostRequestDecoder(DATA_FACTORY, nRequest);\n        } else {\n            return new HttpPostRequestDecoder(DATA_FACTORY, nRequest, Charset.forName(charset));\n        }\n    }\n\n    public static String readPostValue(InterfaceHttpData item) {\n        try {\n            return ((Attribute) item).getValue();\n        } catch (IOException e) {\n            throw new DecodeException(\"Error while reading post value: \" + e.getMessage(), e);\n        }\n    }\n\n    public static HttpRequest.FileUpload readUpload(InterfaceHttpData item) {\n        return new DefaultFileUploadAdapter((FileUpload) item);\n    }\n\n    private static final class DefaultFileUploadAdapter implements HttpRequest.FileUpload {\n        private final FileUpload fu;\n        private InputStream inputStream;\n\n        DefaultFileUploadAdapter(FileUpload fu) {\n            this.fu = fu;\n        }\n\n        @Override\n        public String name() {\n            return fu.getName();\n        }\n\n        @Override\n        public String filename() {\n            return fu.getFilename();\n        }\n\n        @Override\n        public String contentType() {\n            return fu.getContentType();\n        }\n\n        @Override\n        public int size() {\n            return (int) fu.length();\n        }\n\n        @Override\n        public InputStream inputStream() {\n            if (inputStream == null) {\n                inputStream = new ByteBufInputStream(fu.content());\n            }\n            return inputStream;\n        }\n    }\n\n    private static final class Item<V> implements Comparable<Item<V>> {\n        private final V value;\n        private final float q;\n\n        public Item(V value, float q) {\n            this.value = value;\n            this.q = q;\n        }\n\n        @Override\n        public int compareTo(Item<V> o) {\n            return Float.compare(o.q, q);\n        }\n\n        public static <T> List<T> sortAndGet(List<Item<T>> items) {\n            int size = items.size();\n            if (size == 0) {\n                return Collections.emptyList();\n            }\n            if (size == 1) {\n                return Collections.singletonList(items.get(0).value);\n            }\n            Collections.sort(items);\n            List<T> values = new ArrayList<>(size);\n            for (int i = 0; i < size; i++) {\n                values.add(items.get(i).value);\n            }\n            return values;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpVersion.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\npublic enum HttpVersion {\n    HTTP1(\"http1\", \"HTTP/1.1\"),\n    HTTP2(\"http2\", \"HTTP/2.0\");\n\n    private final String version;\n    private final String protocol;\n\n    HttpVersion(String version, String protocol) {\n        this.version = version;\n        this.protocol = protocol;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public String getProtocol() {\n        return protocol;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/LimitedByteArrayOutputStream.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.remoting.http12.exception.HttpOverPayloadException;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\npublic class LimitedByteArrayOutputStream extends ByteArrayOutputStream {\n\n    private final int capacity;\n\n    public LimitedByteArrayOutputStream(int capacity) {\n        super();\n        this.capacity = capacity == 0 ? Integer.MAX_VALUE : capacity;\n    }\n\n    public LimitedByteArrayOutputStream(int size, int capacity) {\n        super(size);\n        this.capacity = capacity == 0 ? Integer.MAX_VALUE : capacity;\n    }\n\n    @Override\n    public void write(int b) {\n        ensureCapacity(1);\n        super.write(b);\n    }\n\n    @Override\n    public void write(byte[] b) throws IOException {\n        ensureCapacity(b.length);\n        super.write(b);\n    }\n\n    @Override\n    public void write(byte[] b, int off, int len) {\n        ensureCapacity(len);\n        super.write(b, off, len);\n    }\n\n    private void ensureCapacity(int len) {\n        if (size() + len > capacity) {\n            throw new HttpOverPayloadException(\"Response Entity Too Large\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/LimitedByteBufOutputStream.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.remoting.http12.exception.HttpOverPayloadException;\n\nimport java.io.IOException;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.ByteBufOutputStream;\n\npublic class LimitedByteBufOutputStream extends ByteBufOutputStream {\n\n    private final int capacity;\n\n    public LimitedByteBufOutputStream(ByteBuf byteBuf, int capacity) {\n        super(byteBuf);\n        this.capacity = capacity == 0 ? Integer.MAX_VALUE : capacity;\n    }\n\n    @Override\n    public void write(int b) throws IOException {\n        ensureCapacity(1);\n        super.write(b);\n    }\n\n    @Override\n    public void write(byte[] b) throws IOException {\n        ensureCapacity(b.length);\n        super.write(b);\n    }\n\n    @Override\n    public void write(byte[] b, int off, int len) throws IOException {\n        ensureCapacity(len);\n        super.write(b, off, len);\n    }\n\n    private void ensureCapacity(int len) {\n        if (writtenBytes() + len > capacity) {\n            throw new HttpOverPayloadException(\"Response Entity Too Large\");\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/RequestMetadata.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\npublic interface RequestMetadata extends HttpMetadata {\n\n    String method();\n\n    String path();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/ServerHttpChannelObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\n\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\n\npublic interface ServerHttpChannelObserver<H extends HttpChannel> extends StreamObserver<Object>, AutoCloseable {\n\n    H getHttpChannel();\n\n    void addHeadersCustomizer(BiConsumer<HttpHeaders, Throwable> headersCustomizer);\n\n    void addTrailersCustomizer(BiConsumer<HttpHeaders, Throwable> trailersCustomizer);\n\n    void setExceptionCustomizer(Function<Throwable, ?> exceptionCustomizer);\n\n    void close();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/DataQueueCommand.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.command;\n\nimport org.apache.dubbo.remoting.http12.HttpOutputMessage;\n\npublic class DataQueueCommand extends HttpChannelQueueCommand {\n\n    private final HttpOutputMessage httpOutputMessage;\n\n    public DataQueueCommand(HttpOutputMessage httpMessage) {\n        this.httpOutputMessage = httpMessage;\n    }\n\n    @Override\n    public void run() {\n        getHttpChannel().writeMessage(httpOutputMessage).whenComplete((unused, throwable) -> {\n            if (throwable != null) {\n                completeExceptionally(throwable);\n            } else {\n                complete(unused);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HeaderQueueCommand.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.command;\n\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\n\npublic class HeaderQueueCommand extends HttpChannelQueueCommand {\n\n    private final HttpMetadata httpMetadata;\n\n    public HeaderQueueCommand(HttpMetadata httpMetadata) {\n        this.httpMetadata = httpMetadata;\n    }\n\n    @Override\n    public void run() {\n        getHttpChannel().writeHeader(httpMetadata).whenComplete((unused, throwable) -> {\n            if (throwable != null) {\n                completeExceptionally(throwable);\n            } else {\n                complete(unused);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HttpChannelQueueCommand.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.command;\n\nimport org.apache.dubbo.remoting.http12.HttpChannel;\nimport org.apache.dubbo.remoting.http12.HttpChannelHolder;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic abstract class HttpChannelQueueCommand extends CompletableFuture<Void>\n        implements QueueCommand, HttpChannelHolder {\n\n    private HttpChannelHolder httpChannelHolder;\n\n    public void setHttpChannel(HttpChannelHolder httpChannelHolder) {\n        this.httpChannelHolder = httpChannelHolder;\n    }\n\n    public HttpChannel getHttpChannel() {\n        return httpChannelHolder.getHttpChannel();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/HttpWriteQueue.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.command;\n\nimport org.apache.dubbo.common.BatchExecutorQueue;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.Executor;\n\npublic class HttpWriteQueue extends BatchExecutorQueue<HttpChannelQueueCommand> {\n\n    private final Executor executor;\n\n    public HttpWriteQueue(Executor executor) {\n        this.executor = executor;\n    }\n\n    public CompletableFuture<Void> enqueue(HttpChannelQueueCommand cmd) {\n        this.enqueue(cmd, this.executor);\n        return cmd;\n    }\n\n    @Override\n    protected void prepare(HttpChannelQueueCommand item) {\n        item.run();\n    }\n\n    @Override\n    protected void flush(HttpChannelQueueCommand item) {\n        item.run();\n        item.getHttpChannel().flush();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/command/QueueCommand.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.command;\n\npublic interface QueueCommand extends Runnable {}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/DecodeException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.exception;\n\npublic class DecodeException extends HttpStatusException {\n\n    private static final long serialVersionUID = 1L;\n\n    public DecodeException() {\n        super(500);\n    }\n\n    public DecodeException(String message) {\n        super(500, message);\n    }\n\n    public DecodeException(Throwable cause) {\n        super(500, cause);\n    }\n\n    public DecodeException(String message, Throwable cause) {\n        super(500, message, cause);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/EncodeException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.exception;\n\npublic class EncodeException extends HttpStatusException {\n\n    private static final long serialVersionUID = 1L;\n\n    public EncodeException(String message) {\n        super(500, message);\n    }\n\n    public EncodeException(String message, Throwable cause) {\n        super(500, message);\n    }\n\n    public EncodeException(Throwable cause) {\n        super(500, cause);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/HttpOverPayloadException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.exception;\n\npublic class HttpOverPayloadException extends HttpStatusException {\n\n    private static final long serialVersionUID = 1L;\n\n    public HttpOverPayloadException(String message) {\n        super(500, message);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/HttpRequestTimeout.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.exception;\n\nimport org.apache.dubbo.remoting.http12.HttpStatus;\n\npublic class HttpRequestTimeout extends HttpStatusException {\n\n    private static final long serialVersionUID = 1L;\n\n    private final String side;\n\n    private HttpRequestTimeout(String side) {\n        super(HttpStatus.REQUEST_TIMEOUT.getCode());\n        this.side = side;\n    }\n\n    public String getSide() {\n        return side;\n    }\n\n    public static HttpRequestTimeout serverSide() {\n        return new HttpRequestTimeout(\"server\");\n    }\n\n    public static HttpRequestTimeout clientSide() {\n        return new HttpRequestTimeout(\"client\");\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/HttpResultPayloadException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.exception;\n\nimport org.apache.dubbo.remoting.http12.HttpResult;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\n\npublic class HttpResultPayloadException extends HttpStatusException {\n\n    private static final long serialVersionUID = 1L;\n\n    private final HttpResult<?> result;\n\n    public HttpResultPayloadException(HttpResult<?> result) {\n        super(result.getStatus());\n        this.result = result;\n    }\n\n    public HttpResultPayloadException(int statusCode, Object body) {\n        super(statusCode);\n        result = HttpResult.of(statusCode, body);\n    }\n\n    public HttpResultPayloadException(Object body) {\n        this(HttpStatus.OK.getCode(), body);\n    }\n\n    @Override\n    public synchronized Throwable fillInStackTrace() {\n        return this;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> HttpResult<T> getResult() {\n        return (HttpResult<T>) result;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> T getBody() {\n        return (T) result.getBody();\n    }\n\n    @Override\n    public String getMessage() {\n        return String.valueOf(result);\n    }\n\n    @Override\n    public String toString() {\n        return \"HttpResultPayloadException{result=\" + result + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/HttpStatusException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.exception;\n\nimport org.apache.dubbo.remoting.http12.HttpUtils;\n\npublic class HttpStatusException extends RuntimeException {\n\n    private static final long serialVersionUID = 1L;\n\n    private final int statusCode;\n\n    public HttpStatusException(int statusCode) {\n        super(HttpUtils.getStatusMessage(statusCode));\n        this.statusCode = statusCode;\n    }\n\n    public HttpStatusException(int statusCode, String message) {\n        super(message);\n        this.statusCode = statusCode;\n    }\n\n    public HttpStatusException(int statusCode, Throwable cause) {\n        super(HttpUtils.getStatusMessage(statusCode), cause);\n        this.statusCode = statusCode;\n    }\n\n    public HttpStatusException(int statusCode, String message, Throwable cause) {\n        super(message, cause);\n        this.statusCode = statusCode;\n    }\n\n    public int getStatusCode() {\n        return statusCode;\n    }\n\n    public String getDisplayMessage() {\n        return getMessage();\n    }\n\n    @Override\n    public String toString() {\n        return getClass().getName() + \": status=\" + statusCode + \", \" + getMessage();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/UnimplementedException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.exception;\n\npublic class UnimplementedException extends HttpStatusException {\n\n    private static final long serialVersionUID = 1L;\n\n    private final String unimplemented;\n\n    public UnimplementedException(String unimplemented) {\n        super(500, \"unimplemented \" + unimplemented);\n        this.unimplemented = unimplemented;\n    }\n\n    public String getUnimplemented() {\n        return unimplemented;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/exception/UnsupportedMediaTypeException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.exception;\n\npublic class UnsupportedMediaTypeException extends HttpStatusException {\n\n    private static final long serialVersionUID = 1L;\n\n    private final String mediaType;\n\n    public UnsupportedMediaTypeException(String mediaType) {\n        super(415, \"Unsupported Media Type '\" + mediaType + \"'\");\n        this.mediaType = mediaType;\n    }\n\n    public String getMediaType() {\n        return mediaType;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/DefaultHttp1Request.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h1;\n\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.HttpInputMessage;\nimport org.apache.dubbo.remoting.http12.RequestMetadata;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\npublic final class DefaultHttp1Request implements Http1Request {\n\n    private final RequestMetadata httpMetadata;\n\n    private final HttpInputMessage httpInputMessage;\n\n    public DefaultHttp1Request(RequestMetadata httpMetadata, HttpInputMessage httpInputMessage) {\n        this.httpMetadata = httpMetadata;\n        this.httpInputMessage = httpInputMessage;\n    }\n\n    @Override\n    public InputStream getBody() {\n        return httpInputMessage.getBody();\n    }\n\n    @Override\n    public HttpHeaders headers() {\n        return httpMetadata.headers();\n    }\n\n    @Override\n    public String method() {\n        return httpMetadata.method();\n    }\n\n    @Override\n    public String path() {\n        return httpMetadata.path();\n    }\n\n    @Override\n    public void close() throws IOException {\n        httpInputMessage.close();\n    }\n\n    @Override\n    public String toString() {\n        return \"Http1Request{method='\" + method() + '\\'' + \", path='\" + path() + '\\'' + \", contentType='\"\n                + contentType() + \"'}\";\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/DefaultHttp1Response.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h1;\n\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.HttpInputMessage;\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\npublic final class DefaultHttp1Response implements HttpMetadata, HttpInputMessage {\n\n    private final HttpMetadata httpMetadata;\n\n    private final HttpInputMessage httpInputMessage;\n\n    public DefaultHttp1Response(HttpMetadata httpMetadata, HttpInputMessage httpInputMessage) {\n        this.httpMetadata = httpMetadata;\n        this.httpInputMessage = httpInputMessage;\n    }\n\n    @Override\n    public InputStream getBody() {\n        return httpInputMessage.getBody();\n    }\n\n    @Override\n    public HttpHeaders headers() {\n        return httpMetadata.headers();\n    }\n\n    @Override\n    public void close() throws IOException {\n        httpInputMessage.close();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1InputMessage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h1;\n\nimport org.apache.dubbo.remoting.http12.HttpInputMessage;\n\nimport java.io.InputStream;\n\npublic final class Http1InputMessage implements HttpInputMessage {\n\n    private final InputStream body;\n\n    public Http1InputMessage(InputStream body) {\n        this.body = body;\n    }\n\n    @Override\n    public InputStream getBody() {\n        return body;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1Metadata.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h1;\n\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\n\npublic final class Http1Metadata implements HttpMetadata {\n\n    private final HttpHeaders headers;\n\n    public Http1Metadata(HttpHeaders headers) {\n        this.headers = headers;\n    }\n\n    @Override\n    public HttpHeaders headers() {\n        return headers;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1OutputMessage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h1;\n\nimport org.apache.dubbo.remoting.http12.HttpOutputMessage;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport io.netty.buffer.ByteBufOutputStream;\n\npublic final class Http1OutputMessage implements HttpOutputMessage {\n\n    private final OutputStream outputStream;\n\n    public Http1OutputMessage(OutputStream outputStream) {\n        this.outputStream = outputStream;\n    }\n\n    @Override\n    public OutputStream getBody() {\n        return outputStream;\n    }\n\n    @Override\n    public void close() throws IOException {\n        if (outputStream instanceof ByteBufOutputStream) {\n            ((ByteBufOutputStream) outputStream).buffer().release();\n        }\n        outputStream.close();\n    }\n\n    @Override\n    public int messageSize() {\n        if (outputStream instanceof ByteBufOutputStream) {\n            return ((ByteBufOutputStream) outputStream).buffer().readableBytes();\n        }\n        return 0;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1Request.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h1;\n\nimport org.apache.dubbo.remoting.http12.HttpInputMessage;\nimport org.apache.dubbo.remoting.http12.RequestMetadata;\n\npublic interface Http1Request extends RequestMetadata, HttpInputMessage {}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1RequestMetadata.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h1;\n\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.RequestMetadata;\n\npublic final class Http1RequestMetadata implements RequestMetadata {\n\n    private final HttpHeaders headers;\n\n    private final String method;\n\n    private final String path;\n\n    public Http1RequestMetadata(HttpHeaders headers, String method, String path) {\n        this.headers = headers;\n        this.method = method;\n        this.path = path;\n    }\n\n    @Override\n    public HttpHeaders headers() {\n        return headers;\n    }\n\n    @Override\n    public String method() {\n        return method;\n    }\n\n    @Override\n    public String path() {\n        return path;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerChannelObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h1;\n\nimport org.apache.dubbo.remoting.http12.AbstractServerHttpChannelObserver;\nimport org.apache.dubbo.remoting.http12.HttpChannel;\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\nimport org.apache.dubbo.remoting.http12.HttpOutputMessage;\nimport org.apache.dubbo.remoting.http12.netty4.h1.NettyHttp1HttpHeaders;\n\npublic class Http1ServerChannelObserver extends AbstractServerHttpChannelObserver<HttpChannel> {\n\n    public Http1ServerChannelObserver(HttpChannel httpChannel) {\n        super(httpChannel);\n    }\n\n    @Override\n    protected HttpMetadata encodeHttpMetadata(boolean endStream) {\n        return new Http1Metadata(new NettyHttp1HttpHeaders());\n    }\n\n    @Override\n    protected void doOnCompleted(Throwable throwable) {\n        getHttpChannel().writeMessage(HttpOutputMessage.EMPTY_MESSAGE);\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerTransportListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h1;\n\nimport org.apache.dubbo.remoting.http12.HttpInputMessage;\nimport org.apache.dubbo.remoting.http12.HttpTransportListener;\nimport org.apache.dubbo.remoting.http12.RequestMetadata;\n\npublic interface Http1ServerTransportListener extends HttpTransportListener<RequestMetadata, HttpInputMessage> {}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerTransportListenerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h1;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.remoting.http12.HttpChannel;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface Http1ServerTransportListenerFactory {\n\n    Http1ServerTransportListener newInstance(HttpChannel httpChannel, URL url, FrameworkModel frameworkModel);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/CancelStreamException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.remoting.http12.ErrorCodeHolder;\n\npublic class CancelStreamException extends RuntimeException implements ErrorCodeHolder {\n\n    private static final long serialVersionUID = 1L;\n\n    private final boolean cancelByRemote;\n    private final long errorCode;\n\n    private CancelStreamException(boolean cancelByRemote, long errorCode) {\n        this.cancelByRemote = cancelByRemote;\n        this.errorCode = errorCode;\n    }\n\n    public boolean isCancelByRemote() {\n        return cancelByRemote;\n    }\n\n    public static CancelStreamException fromRemote(long errorCode) {\n        return new CancelStreamException(true, errorCode);\n    }\n\n    public static CancelStreamException fromLocal(long errorCode) {\n        return new CancelStreamException(false, errorCode);\n    }\n\n    @Override\n    public long getErrorCode() {\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/CancelableTransportListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.remoting.http12.HttpInputMessage;\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\nimport org.apache.dubbo.remoting.http12.HttpTransportListener;\n\npublic interface CancelableTransportListener<HEADER extends HttpMetadata, MESSAGE extends HttpInputMessage>\n        extends HttpTransportListener<HEADER, MESSAGE> {\n\n    void cancelByRemote(long errorCode);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/H2StreamChannel.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.remoting.http12.HttpChannel;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic interface H2StreamChannel extends HttpChannel {\n\n    CompletableFuture<Void> writeResetFrame(long errorCode);\n\n    @Override\n    default Http2OutputMessage newOutputMessage() {\n        return this.newOutputMessage(false);\n    }\n\n    Http2OutputMessage newOutputMessage(boolean endStream);\n\n    /**\n     * Consume bytes from the local flow controller to trigger WINDOW_UPDATE frames.\n     * This method should be called when data has been processed and more data can be received.\n     *\n     * @param numBytes the number of bytes to consume\n     * @throws Exception if an error occurs during consumption\n     */\n    void consumeBytes(int numBytes) throws Exception;\n\n    /**\n     * Returns whether the stream is ready for writing. If false, the caller should avoid\n     * calling {@link #writeMessage(org.apache.dubbo.remoting.http12.HttpOutputMessage)}\n     * to avoid blocking or excessive buffering.\n     *\n     * <p>This method is used for outgoing flow control / backpressure. When the underlying\n     * transport buffer is full, this returns false.\n     *\n     * @return true if the stream is ready for writing\n     */\n    boolean isReady();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2CancelableStreamObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.common.stream.StreamObserver;\nimport org.apache.dubbo.rpc.CancellationContext;\n\npublic interface Http2CancelableStreamObserver<T> extends StreamObserver<T> {\n\n    void setCancellationContext(CancellationContext cancellationContext);\n\n    CancellationContext getCancellationContext();\n\n    void cancel(Throwable throwable);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ChannelDelegate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\nimport org.apache.dubbo.remoting.http12.HttpOutputMessage;\n\nimport java.net.SocketAddress;\nimport java.util.concurrent.CompletableFuture;\n\npublic class Http2ChannelDelegate implements H2StreamChannel {\n\n    private final H2StreamChannel h2StreamChannel;\n\n    public Http2ChannelDelegate(H2StreamChannel h2StreamChannel) {\n        this.h2StreamChannel = h2StreamChannel;\n    }\n\n    public H2StreamChannel getH2StreamChannel() {\n        return h2StreamChannel;\n    }\n\n    @Override\n    public CompletableFuture<Void> writeHeader(HttpMetadata httpMetadata) {\n        return h2StreamChannel.writeHeader(httpMetadata);\n    }\n\n    @Override\n    public CompletableFuture<Void> writeMessage(HttpOutputMessage httpOutputMessage) {\n        return h2StreamChannel.writeMessage(httpOutputMessage);\n    }\n\n    @Override\n    public SocketAddress remoteAddress() {\n        return h2StreamChannel.remoteAddress();\n    }\n\n    @Override\n    public SocketAddress localAddress() {\n        return h2StreamChannel.localAddress();\n    }\n\n    @Override\n    public void flush() {\n        h2StreamChannel.flush();\n    }\n\n    @Override\n    public CompletableFuture<Void> writeResetFrame(long errorCode) {\n        return h2StreamChannel.writeResetFrame(errorCode);\n    }\n\n    @Override\n    public Http2OutputMessage newOutputMessage(boolean endStream) {\n        return h2StreamChannel.newOutputMessage(endStream);\n    }\n\n    @Override\n    public void consumeBytes(int numBytes) throws Exception {\n        h2StreamChannel.consumeBytes(numBytes);\n    }\n\n    @Override\n    public boolean isReady() {\n        return h2StreamChannel.isReady();\n    }\n\n    @Override\n    public String toString() {\n        return \"Http2ChannelDelegate{\" + \"h2StreamChannel=\" + h2StreamChannel + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2Header.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.remoting.http12.RequestMetadata;\n\npublic interface Http2Header extends RequestMetadata, Http2StreamFrame {\n\n    @Override\n    default String name() {\n        return \"HEADER\";\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2InputMessage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.remoting.http12.HttpInputMessage;\n\npublic interface Http2InputMessage extends HttpInputMessage, Http2StreamFrame {}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2InputMessageFrame.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.common.utils.ClassUtils;\n\nimport java.io.InputStream;\n\npublic final class Http2InputMessageFrame implements Http2InputMessage {\n\n    private final long streamId;\n\n    private final InputStream body;\n\n    private final boolean endStream;\n\n    public Http2InputMessageFrame(InputStream body, boolean endStream) {\n        this(-1L, body, endStream);\n    }\n\n    public Http2InputMessageFrame(long streamId, InputStream body, boolean endStream) {\n        this.streamId = streamId;\n        this.body = body;\n        this.endStream = endStream;\n    }\n\n    @Override\n    public InputStream getBody() {\n        return body;\n    }\n\n    @Override\n    public String name() {\n        return \"DATA\";\n    }\n\n    @Override\n    public long id() {\n        return streamId;\n    }\n\n    @Override\n    public boolean isEndStream() {\n        return endStream;\n    }\n\n    @Override\n    public String toString() {\n        return \"Http2InputMessageFrame{body=\" + ClassUtils.toShortString(body) + \", body=\" + streamId + \", endStream=\"\n                + endStream + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2MetadataFrame.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\n\nimport io.netty.handler.codec.http2.Http2Headers.PseudoHeaderName;\n\npublic final class Http2MetadataFrame implements Http2Header {\n\n    private final long streamId;\n\n    private final HttpHeaders headers;\n\n    private final boolean endStream;\n\n    public Http2MetadataFrame(HttpHeaders headers) {\n        this(-1L, headers, false);\n    }\n\n    public Http2MetadataFrame(HttpHeaders headers, boolean endStream) {\n        this(-1L, headers, endStream);\n    }\n\n    public Http2MetadataFrame(long streamId, HttpHeaders headers, boolean endStream) {\n        this.streamId = streamId;\n        this.headers = headers;\n        this.endStream = endStream;\n    }\n\n    @Override\n    public HttpHeaders headers() {\n        return headers;\n    }\n\n    @Override\n    public String method() {\n        return headers.getFirst(PseudoHeaderName.METHOD.value());\n    }\n\n    @Override\n    public String path() {\n        return headers.getFirst(PseudoHeaderName.PATH.value());\n    }\n\n    @Override\n    public long id() {\n        return streamId;\n    }\n\n    @Override\n    public boolean isEndStream() {\n        return endStream;\n    }\n\n    @Override\n    public String toString() {\n        return \"Http2MetadataFrame{method='\" + method() + '\\'' + \", path='\" + path() + '\\'' + \", contentType='\"\n                + contentType() + \"', streamId=\" + streamId + \", endStream=\"\n                + endStream + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2OutputMessage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.remoting.http12.HttpOutputMessage;\n\npublic interface Http2OutputMessage extends HttpOutputMessage, Http2StreamFrame {\n\n    @Override\n    default String name() {\n        return \"DATA\";\n    }\n\n    @Override\n    default long id() {\n        return -1;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2OutputMessageFrame.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport io.netty.buffer.ByteBufOutputStream;\n\npublic final class Http2OutputMessageFrame implements Http2OutputMessage {\n\n    private final OutputStream body;\n\n    private final boolean endStream;\n\n    public Http2OutputMessageFrame(OutputStream body, boolean endStream) {\n        this.body = body;\n        this.endStream = endStream;\n    }\n\n    @Override\n    public OutputStream getBody() {\n        return body;\n    }\n\n    @Override\n    public void close() throws IOException {\n        if (body instanceof ByteBufOutputStream) {\n            ((ByteBufOutputStream) body).buffer().release();\n        }\n        body.close();\n    }\n\n    @Override\n    public boolean isEndStream() {\n        return endStream;\n    }\n\n    @Override\n    public int messageSize() {\n        if (body instanceof ByteBufOutputStream) {\n            return ((ByteBufOutputStream) body).buffer().readableBytes();\n        }\n        return 0;\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ServerChannelObserver.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.common.stream.ServerCallStreamObserver;\nimport org.apache.dubbo.remoting.http12.AbstractServerHttpChannelObserver;\nimport org.apache.dubbo.remoting.http12.ErrorCodeHolder;\nimport org.apache.dubbo.remoting.http12.FlowControlStreamObserver;\nimport org.apache.dubbo.remoting.http12.HttpConstants;\nimport org.apache.dubbo.remoting.http12.HttpHeaderNames;\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\nimport org.apache.dubbo.remoting.http12.HttpOutputMessage;\nimport org.apache.dubbo.remoting.http12.message.StreamingDecoder;\nimport org.apache.dubbo.remoting.http12.netty4.NettyHttpHeaders;\nimport org.apache.dubbo.rpc.CancellationContext;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport io.netty.handler.codec.http2.DefaultHttp2Headers;\n\n/**\n * HTTP/2 server-side stream observer with flow control and backpressure support.\n * <p>\n * Backpressure is implemented using a byte-counting strategy. Outbound messages are\n * tracked in {@code numSentBytesQueued}, which represents the approximate number of\n * bytes that have been queued but not yet acknowledged as sent.\n * <p>\n * The {@code ON_READY_THRESHOLD} (32KB) defines when this observer is considered \"ready\":\n * <ul>\n *     <li>{@link #isReady()} returns {@code true} when {@code numSentBytesQueued < ON_READY_THRESHOLD}</li>\n *     <li>When the queued byte count drops from at or above the threshold to below it,\n *         the registered {@code onReadyHandler} is invoked to signal that more data can be sent</li>\n * </ul>\n */\npublic class Http2ServerChannelObserver extends AbstractServerHttpChannelObserver<H2StreamChannel>\n        implements FlowControlStreamObserver<Object>,\n                Http2CancelableStreamObserver<Object>,\n                ServerCallStreamObserver<Object> {\n\n    /**\n     * Number of bytes currently queued, waiting to be sent.\n     * When this falls below ON_READY_THRESHOLD, onReady will be triggered.\n     */\n    private final AtomicLong numSentBytesQueued = new AtomicLong(0);\n\n    /**\n     * The threshold below which isReady() returns true (32KB).\n     */\n    protected static final long ON_READY_THRESHOLD = 32 * 1024;\n\n    private CancellationContext cancellationContext;\n\n    private StreamingDecoder streamingDecoder;\n\n    private boolean autoRequestN = true;\n\n    private volatile Runnable onReadyHandler;\n\n    private volatile Executor executor = Runnable::run;\n\n    public Http2ServerChannelObserver(H2StreamChannel h2StreamChannel) {\n        super(h2StreamChannel);\n    }\n\n    /**\n     * Sets the executor for async dispatch of callbacks.\n     */\n    public void setExecutor(Executor executor) {\n        this.executor = executor;\n    }\n\n    /**\n     * Returns whether the stream is ready for writing.\n     * <p>\n     * Ready state is determined by byte counting: returns {@code true} when the number\n     * of queued bytes is below the threshold (32KB). If {@code false}, the caller should\n     * avoid calling {@code onNext} to prevent excessive buffering.\n     *\n     * @return {@code true} if the stream is ready for more data, {@code false} otherwise\n     */\n    public boolean isReady() {\n        H2StreamChannel channel = getHttpChannel();\n        if (channel == null) {\n            return false;\n        }\n        return numSentBytesQueued.get() < ON_READY_THRESHOLD;\n    }\n\n    /**\n     * Sets a callback to be invoked when the stream becomes ready for writing.\n     */\n    public void setOnReadyHandler(Runnable onReadyHandler) {\n        this.onReadyHandler = onReadyHandler;\n    }\n\n    /**\n     * Called by the transport layer when the underlying channel's writability changes.\n     * <p>\n     * This serves as an additional trigger point for notifying the {@code onReadyHandler}\n     * when the channel becomes writable again. The actual ready state is still determined\n     * by the byte counting mechanism in {@link #isReady()}.\n     */\n    public void onWritabilityChanged() {\n        if (isReady()) {\n            notifyOnReady();\n        }\n    }\n\n    public void setStreamingDecoder(StreamingDecoder streamingDecoder) {\n        this.streamingDecoder = streamingDecoder;\n    }\n\n    /**\n     * Override to add byte counting for backpressure support.\n     */\n    @Override\n    protected CompletableFuture<Void> sendMessage(HttpOutputMessage message) throws Throwable {\n        if (message == null) {\n            return CompletableFuture.completedFuture(null);\n        }\n\n        int messageSize = message.messageSize();\n        onSendingBytes(messageSize);\n\n        CompletableFuture<Void> future = super.sendMessage(message);\n\n        future.whenComplete((v, t) -> {\n            if (t == null) {\n                onSentBytes(messageSize);\n            } else {\n                rollbackSendingBytes(messageSize);\n            }\n        });\n\n        return future;\n    }\n\n    /**\n     * Called before bytes are sent to track pending bytes.\n     */\n    protected void onSendingBytes(int numBytes) {\n        numSentBytesQueued.addAndGet(numBytes);\n    }\n\n    /**\n     * Called when sending fails to rollback the pending bytes count.\n     */\n    protected void rollbackSendingBytes(int numBytes) {\n        numSentBytesQueued.addAndGet(-numBytes);\n    }\n\n    /**\n     * Called when bytes have been successfully sent to the remote endpoint.\n     */\n    protected void onSentBytes(int numBytes) {\n        long oldValue = numSentBytesQueued.getAndAdd(-numBytes);\n        long newValue = oldValue - numBytes;\n        // Trigger onReady when transitioning from \"not ready\" to \"ready\"\n        if (oldValue >= ON_READY_THRESHOLD && newValue < ON_READY_THRESHOLD) {\n            notifyOnReady();\n        }\n    }\n\n    /**\n     * Returns the number of bytes currently queued for sending.\n     * Visible for testing.\n     */\n    protected long getNumSentBytesQueued() {\n        return numSentBytesQueued.get();\n    }\n\n    /**\n     * Notify the onReadyHandler that the stream is ready for writing.\n     */\n    protected void notifyOnReady() {\n        Runnable handler = this.onReadyHandler;\n        if (handler == null) {\n            return;\n        }\n        executor.execute(handler);\n    }\n\n    @Override\n    protected HttpMetadata encodeHttpMetadata(boolean endStream) {\n        HttpHeaders headers = new NettyHttpHeaders<>(new DefaultHttp2Headers(false, 8));\n        headers.set(HttpHeaderNames.TE.getKey(), HttpConstants.TRAILERS);\n        return new Http2MetadataFrame(headers, endStream);\n    }\n\n    @Override\n    protected HttpMetadata encodeTrailers(Throwable throwable) {\n        return new Http2MetadataFrame(new NettyHttpHeaders<>(new DefaultHttp2Headers(false, 4)), true);\n    }\n\n    @Override\n    public void setCancellationContext(CancellationContext cancellationContext) {\n        this.cancellationContext = cancellationContext;\n    }\n\n    @Override\n    public CancellationContext getCancellationContext() {\n        return cancellationContext;\n    }\n\n    @Override\n    public void cancel(Throwable throwable) {\n        if (throwable instanceof CancelStreamException) {\n            if (((CancelStreamException) throwable).isCancelByRemote()) {\n                closed();\n            }\n        }\n        if (cancellationContext != null) {\n            cancellationContext.cancel(throwable);\n        }\n        long errorCode = 0;\n        if (throwable instanceof ErrorCodeHolder) {\n            errorCode = ((ErrorCodeHolder) throwable).getErrorCode();\n        }\n        getHttpChannel().writeResetFrame(errorCode);\n    }\n\n    @Override\n    public void request(int count) {\n        streamingDecoder.request(count);\n    }\n\n    @Override\n    public void setCompression(String compression) {\n        // not supported yet\n    }\n\n    @Override\n    public void disableAutoFlowControl() {\n        autoRequestN = false;\n    }\n\n    @Override\n    public boolean isAutoRequestN() {\n        return autoRequestN;\n    }\n\n    @Override\n    public void close() {\n        super.close();\n        streamingDecoder.onStreamClosed();\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2ServerTransportListenerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\nimport org.apache.dubbo.common.URL;\nimport org.apache.dubbo.common.extension.ExtensionScope;\nimport org.apache.dubbo.common.extension.SPI;\nimport org.apache.dubbo.rpc.model.FrameworkModel;\n\n@SPI(scope = ExtensionScope.FRAMEWORK)\npublic interface Http2ServerTransportListenerFactory {\n\n    Http2TransportListener newInstance(H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel);\n\n    boolean supportContentType(String contentType);\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2StreamFrame.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\npublic interface Http2StreamFrame {\n\n    long id();\n\n    String name();\n\n    boolean isEndStream();\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h2/Http2TransportListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.h2;\n\npublic interface Http2TransportListener extends CancelableTransportListener<Http2Header, Http2InputMessage> {\n\n    void close();\n\n    /**\n     * Called when the channel writability changes.\n     * This is used for backpressure support via isReady/setOnReadyHandler.\n     */\n    default void onWritabilityChanged() {}\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/CodecMediaType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.message;\n\npublic interface CodecMediaType {\n\n    MediaType mediaType();\n\n    default boolean supports(String mediaType) {\n        return mediaType.startsWith(mediaType().getName());\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.message;\n\nimport org.apache.dubbo.common.utils.CollectionUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.HttpChannel;\nimport org.apache.dubbo.remoting.http12.HttpConstants;\nimport org.apache.dubbo.remoting.http12.HttpCookie;\nimport org.apache.dubbo.remoting.http12.HttpHeaderNames;\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.HttpMetadata;\nimport org.apache.dubbo.remoting.http12.HttpMethods;\nimport org.apache.dubbo.remoting.http12.HttpRequest;\nimport org.apache.dubbo.remoting.http12.HttpUtils;\nimport org.apache.dubbo.remoting.http12.RequestMetadata;\nimport org.apache.dubbo.remoting.http12.h2.Http2Header;\n\nimport java.io.InputStream;\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.netty.handler.codec.DateFormatter;\nimport io.netty.handler.codec.http.QueryStringDecoder;\nimport io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;\nimport io.netty.handler.codec.http.multipart.InterfaceHttpData;\nimport io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;\nimport io.netty.handler.codec.http2.Http2Headers.PseudoHeaderName;\n\npublic class DefaultHttpRequest implements HttpRequest {\n\n    private final HttpMetadata metadata;\n    private final HttpChannel channel;\n    private final HttpHeaders headers;\n\n    private String method;\n    private String uri;\n    private String contentType;\n    private String charset;\n    private List<HttpCookie> cookies;\n    private List<Locale> locales;\n    private QueryStringDecoder decoder;\n    private HttpPostRequestDecoder postDecoder;\n    private boolean postParsed;\n    private Map<String, Object> attributes;\n    private InputStream inputStream;\n\n    public DefaultHttpRequest(HttpMetadata metadata, HttpChannel channel) {\n        this.metadata = metadata;\n        this.channel = channel;\n        headers = metadata.headers();\n        if (metadata instanceof RequestMetadata) {\n            RequestMetadata requestMetadata = (RequestMetadata) metadata;\n            method = requestMetadata.method();\n            uri = requestMetadata.path();\n        } else {\n            throw new UnsupportedOperationException();\n        }\n    }\n\n    public HttpMetadata getMetadata() {\n        return metadata;\n    }\n\n    @Override\n    public boolean isHttp2() {\n        return metadata instanceof Http2Header;\n    }\n\n    @Override\n    public String method() {\n        return method;\n    }\n\n    @Override\n    public void setMethod(String method) {\n        this.method = method;\n    }\n\n    @Override\n    public String uri() {\n        return uri;\n    }\n\n    @Override\n    public void setUri(String uri) {\n        this.uri = uri;\n        decoder = null;\n    }\n\n    @Override\n    public String path() {\n        return getDecoder().path();\n    }\n\n    @Override\n    public String rawPath() {\n        return getDecoder().rawPath();\n    }\n\n    @Override\n    public String query() {\n        return getDecoder().rawQuery();\n    }\n\n    @Override\n    public String header(CharSequence name) {\n        return headers.getFirst(name);\n    }\n\n    @Override\n    public List<String> headerValues(CharSequence name) {\n        return headers.get(name);\n    }\n\n    @Override\n    public Date dateHeader(CharSequence name) {\n        String value = headers.getFirst(name);\n        return StringUtils.isEmpty(value) ? null : DateFormatter.parseHttpDate(value);\n    }\n\n    @Override\n    public boolean hasHeader(CharSequence name) {\n        return headers.containsKey(name);\n    }\n\n    @Override\n    public Collection<String> headerNames() {\n        return headers.names();\n    }\n\n    @Override\n    public HttpHeaders headers() {\n        return headers;\n    }\n\n    @Override\n    public void setHeader(CharSequence name, String value) {\n        headers.set(name, value);\n    }\n\n    @Override\n    public void setHeader(CharSequence name, Date value) {\n        headers.set(name, DateFormatter.format(value));\n    }\n\n    @Override\n    public void setHeader(CharSequence name, List<String> values) {\n        headers.set(name, values);\n    }\n\n    @Override\n    public Collection<HttpCookie> cookies() {\n        List<HttpCookie> cookies = this.cookies;\n        if (cookies == null) {\n            cookies = HttpUtils.decodeCookies(header(HttpHeaderNames.COOKIE.getKey()));\n            this.cookies = cookies;\n        }\n        return cookies;\n    }\n\n    @Override\n    public HttpCookie cookie(String name) {\n        List<HttpCookie> cookies = this.cookies;\n        if (cookies == null) {\n            cookies = HttpUtils.decodeCookies(header(HttpHeaderNames.COOKIE.getKey()));\n            this.cookies = cookies;\n        }\n        for (int i = 0, size = cookies.size(); i < size; i++) {\n            HttpCookie cookie = cookies.get(i);\n            if (cookie.name().equals(name)) {\n                return cookie;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public int contentLength() {\n        String value = headers.getFirst(HttpHeaderNames.CONTENT_LENGTH.getKey());\n        return value == null ? 0 : Integer.parseInt(value);\n    }\n\n    @Override\n    public String contentType() {\n        String contentType = this.contentType;\n        if (contentType == null) {\n            contentType = headers.getFirst(HttpHeaderNames.CONTENT_TYPE.getKey());\n            contentType = contentType == null ? StringUtils.EMPTY_STRING : contentType.trim();\n            this.contentType = contentType;\n        }\n        return contentType.isEmpty() ? null : contentType;\n    }\n\n    @Override\n    public void setContentType(String contentType) {\n        setContentType0(contentType == null ? StringUtils.EMPTY_STRING : contentType.trim());\n        charset = null;\n    }\n\n    private void setContentType0(String contentType) {\n        this.contentType = contentType;\n        headers.set(HttpHeaderNames.CONTENT_TYPE.getKey(), contentType());\n    }\n\n    @Override\n    public String mediaType() {\n        String contentType = contentType();\n        if (contentType == null) {\n            return null;\n        }\n        int index = contentType.indexOf(';');\n        return index == -1 ? contentType : contentType.substring(0, index);\n    }\n\n    @Override\n    public String charset() {\n        String charset = this.charset;\n        if (charset == null) {\n            String contentType = contentType();\n            charset = HttpUtils.parseCharset(contentType);\n            this.charset = charset;\n        }\n        return charset.isEmpty() ? null : charset;\n    }\n\n    @Override\n    public Charset charsetOrDefault() {\n        String charset = charset();\n        return charset == null ? StandardCharsets.UTF_8 : Charset.forName(charset);\n    }\n\n    @Override\n    public void setCharset(String charset) {\n        String contentType = contentType();\n        if (contentType != null) {\n            setContentType0(contentType + \"; \" + HttpUtils.CHARSET_PREFIX + charset);\n        }\n        this.charset = charset;\n    }\n\n    @Override\n    public String accept() {\n        return headers.getFirst(HttpHeaderNames.ACCEPT.getKey());\n    }\n\n    @Override\n    public Locale locale() {\n        return locales().get(0);\n    }\n\n    @Override\n    public List<Locale> locales() {\n        List<Locale> locales = this.locales;\n        if (locales == null) {\n            locales = HttpUtils.parseAcceptLanguage(headers.getFirst(HttpHeaderNames.CONTENT_LANGUAGE.getKey()));\n            if (locales.isEmpty()) {\n                locales = Collections.singletonList(Locale.getDefault());\n            }\n            this.locales = locales;\n        }\n        return locales;\n    }\n\n    @Override\n    public String scheme() {\n        String scheme = headers.getFirst(HttpConstants.X_FORWARDED_PROTO);\n        if (isHttp2()) {\n            scheme = headers.getFirst(PseudoHeaderName.SCHEME.value());\n        }\n        return scheme == null ? HttpConstants.HTTP : scheme;\n    }\n\n    @Override\n    public String serverHost() {\n        String host = getHost0();\n        return host == null ? localHost() + ':' + localPort() : host;\n    }\n\n    @Override\n    public String serverName() {\n        String host = headers.getFirst(HttpConstants.X_FORWARDED_HOST);\n        if (host != null) {\n            return host;\n        }\n        host = getHost0();\n        if (host != null) {\n            int index = host.lastIndexOf(':');\n            return index == -1 ? host : host.substring(0, index);\n        }\n        return localHost();\n    }\n\n    @Override\n    public int serverPort() {\n        String port = headers.getFirst(HttpConstants.X_FORWARDED_PORT);\n        if (port != null) {\n            return Integer.parseInt(port);\n        }\n        String host = getHost0();\n        if (host != null) {\n            int index = host.lastIndexOf(':');\n            return index == -1 ? -1 : Integer.parseInt(host.substring(0, index));\n        }\n        return localPort();\n    }\n\n    private String getHost0() {\n        return headers.getFirst(isHttp2() ? PseudoHeaderName.AUTHORITY.value() : HttpHeaderNames.HOST.getKey());\n    }\n\n    @Override\n    public String remoteHost() {\n        return getRemoteAddress().getHostString();\n    }\n\n    @Override\n    public String remoteAddr() {\n        return getRemoteAddress().getAddress().getHostAddress();\n    }\n\n    @Override\n    public int remotePort() {\n        return getRemoteAddress().getPort();\n    }\n\n    private InetSocketAddress getRemoteAddress() {\n        return (InetSocketAddress) channel.remoteAddress();\n    }\n\n    @Override\n    public String localHost() {\n        return getLocalAddress().getHostString();\n    }\n\n    @Override\n    public String localAddr() {\n        return getLocalAddress().getAddress().getHostAddress();\n    }\n\n    @Override\n    public int localPort() {\n        return getLocalAddress().getPort();\n    }\n\n    private InetSocketAddress getLocalAddress() {\n        return (InetSocketAddress) channel.localAddress();\n    }\n\n    @Override\n    public String parameter(String name) {\n        List<String> values = getDecoder().parameters().get(name);\n        if (CollectionUtils.isNotEmpty(values)) {\n            return values.get(0);\n        }\n        HttpPostRequestDecoder postDecoder = getPostDecoder();\n        if (postDecoder == null) {\n            return null;\n        }\n        List<InterfaceHttpData> items = postDecoder.getBodyHttpDatas(name);\n        if (items == null) {\n            return null;\n        }\n        for (int i = 0, size = items.size(); i < size; i++) {\n            InterfaceHttpData item = items.get(i);\n            if (item.getHttpDataType() == HttpDataType.Attribute) {\n                return HttpUtils.readPostValue(item);\n            }\n        }\n        return formParameter(name);\n    }\n\n    @Override\n    public String parameter(String name, String defaultValue) {\n        String value = parameter(name);\n        return value == null ? defaultValue : value;\n    }\n\n    @Override\n    public List<String> parameterValues(String name) {\n        List<String> values = getDecoder().parameters().get(name);\n        HttpPostRequestDecoder postDecoder = getPostDecoder();\n        if (postDecoder == null) {\n            return values;\n        }\n        List<InterfaceHttpData> items = postDecoder.getBodyHttpDatas(name);\n        if (items == null) {\n            return values;\n        }\n        for (int i = 0, size = items.size(); i < size; i++) {\n            InterfaceHttpData item = items.get(i);\n            if (item.getHttpDataType() == HttpDataType.Attribute) {\n                if (values == null) {\n                    values = new ArrayList<>();\n                }\n                values.add(HttpUtils.readPostValue(item));\n            }\n        }\n        return values;\n    }\n\n    @Override\n    public String queryParameter(String name) {\n        return CollectionUtils.first(queryParameterValues(name));\n    }\n\n    @Override\n    public List<String> queryParameterValues(String name) {\n        return getDecoder().parameters().get(name);\n    }\n\n    @Override\n    public Collection<String> queryParameterNames() {\n        return getDecoder().parameters().keySet();\n    }\n\n    @Override\n    public Map<String, List<String>> queryParameters() {\n        return getDecoder().parameters();\n    }\n\n    @Override\n    public String formParameter(String name) {\n        HttpPostRequestDecoder postDecoder = getPostDecoder();\n        if (postDecoder == null) {\n            return null;\n        }\n        List<InterfaceHttpData> items = postDecoder.getBodyHttpDatas(name);\n        if (items == null) {\n            return null;\n        }\n        for (int i = 0, size = items.size(); i < size; i++) {\n            InterfaceHttpData item = items.get(i);\n            if (item.getHttpDataType() == HttpDataType.Attribute) {\n                return HttpUtils.readPostValue(item);\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public List<String> formParameterValues(String name) {\n        HttpPostRequestDecoder postDecoder = getPostDecoder();\n        if (postDecoder == null) {\n            return null;\n        }\n        List<InterfaceHttpData> items = postDecoder.getBodyHttpDatas(name);\n        if (items == null) {\n            return null;\n        }\n        List<String> values = null;\n        for (int i = 0, size = items.size(); i < size; i++) {\n            InterfaceHttpData item = items.get(i);\n            if (item.getHttpDataType() == HttpDataType.Attribute) {\n                if (values == null) {\n                    values = new ArrayList<>();\n                }\n                values.add(HttpUtils.readPostValue(item));\n            }\n        }\n        return values == null ? Collections.emptyList() : values;\n    }\n\n    @Override\n    public Collection<String> formParameterNames() {\n        HttpPostRequestDecoder postDecoder = getPostDecoder();\n        if (postDecoder == null) {\n            return Collections.emptyList();\n        }\n        List<InterfaceHttpData> items = postDecoder.getBodyHttpDatas();\n        if (items == null) {\n            return Collections.emptyList();\n        }\n        Set<String> names = null;\n        for (int i = 0, size = items.size(); i < size; i++) {\n            InterfaceHttpData item = items.get(i);\n            if (item.getHttpDataType() == HttpDataType.Attribute) {\n                if (names == null) {\n                    names = new LinkedHashSet<>();\n                }\n                names.add(item.getName());\n            }\n        }\n        return names == null ? Collections.emptyList() : names;\n    }\n\n    @Override\n    public boolean hasParameter(String name) {\n        if (getDecoder().parameters().containsKey(name)) {\n            return true;\n        }\n        HttpPostRequestDecoder postDecoder = getPostDecoder();\n        if (postDecoder == null) {\n            return false;\n        }\n        List<InterfaceHttpData> items = postDecoder.getBodyHttpDatas(name);\n        if (items == null) {\n            return false;\n        }\n        for (int i = 0, size = items.size(); i < size; i++) {\n            InterfaceHttpData item = items.get(i);\n            if (item.getHttpDataType() == HttpDataType.Attribute) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public Collection<String> parameterNames() {\n        Set<String> names = getDecoder().parameters().keySet();\n        HttpPostRequestDecoder postDecoder = getPostDecoder();\n        if (postDecoder == null) {\n            return names;\n        }\n        List<InterfaceHttpData> items = postDecoder.getBodyHttpDatas();\n        if (items == null) {\n            return names;\n        }\n        Set<String> allNames = null;\n        for (int i = 0, size = items.size(); i < size; i++) {\n            InterfaceHttpData item = items.get(i);\n            if (item.getHttpDataType() == HttpDataType.Attribute) {\n                if (allNames == null) {\n                    allNames = new LinkedHashSet<>(names);\n                }\n                allNames.add(item.getName());\n            }\n        }\n        return allNames == null ? Collections.emptyList() : allNames;\n    }\n\n    @Override\n    public Collection<FileUpload> parts() {\n        HttpPostRequestDecoder postDecoder = getPostDecoder();\n        if (postDecoder == null) {\n            return Collections.emptyList();\n        }\n        List<InterfaceHttpData> items = postDecoder.getBodyHttpDatas();\n        if (items == null) {\n            return Collections.emptyList();\n        }\n        List<FileUpload> fileUploads = new ArrayList<>();\n        for (int i = 0, size = items.size(); i < size; i++) {\n            InterfaceHttpData item = items.get(i);\n            if (item.getHttpDataType() == HttpDataType.FileUpload) {\n                fileUploads.add(HttpUtils.readUpload(item));\n            }\n        }\n        return fileUploads;\n    }\n\n    @Override\n    public FileUpload part(String name) {\n        HttpPostRequestDecoder postDecoder = getPostDecoder();\n        if (postDecoder == null) {\n            return null;\n        }\n        List<InterfaceHttpData> items = postDecoder.getBodyHttpDatas(name);\n        if (items == null) {\n            return null;\n        }\n\n        for (int i = 0, size = items.size(); i < size; i++) {\n            InterfaceHttpData item = items.get(i);\n            if (item.getHttpDataType() == HttpDataType.FileUpload) {\n                return HttpUtils.readUpload(item);\n            }\n        }\n        return null;\n    }\n\n    private QueryStringDecoder getDecoder() {\n        if (decoder == null) {\n            String charset = charset();\n            if (charset == null) {\n                decoder = new QueryStringDecoder(uri);\n            } else {\n                decoder = new QueryStringDecoder(uri, Charset.forName(charset));\n            }\n        }\n        return decoder;\n    }\n\n    private HttpPostRequestDecoder getPostDecoder() {\n        HttpPostRequestDecoder postDecoder = this.postDecoder;\n        if (postDecoder == null) {\n            if (postParsed) {\n                return null;\n            }\n            if (inputStream != null && HttpMethods.supportBody(method)) {\n                postDecoder = HttpUtils.createPostRequestDecoder(this, inputStream, charset());\n                this.postDecoder = postDecoder;\n            }\n            postParsed = true;\n        }\n        return postDecoder;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> T attribute(String name) {\n        return (T) getAttributes().get(name);\n    }\n\n    @Override\n    public void removeAttribute(String name) {\n        getAttributes().remove(name);\n    }\n\n    @Override\n    public void setAttribute(String name, Object value) {\n        getAttributes().put(name, value);\n    }\n\n    @Override\n    public boolean hasAttribute(String name) {\n        return attributes != null && attributes.containsKey(name);\n    }\n\n    @Override\n    public Collection<String> attributeNames() {\n        return getAttributes().keySet();\n    }\n\n    @Override\n    public Map<String, Object> attributes() {\n        return getAttributes();\n    }\n\n    private Map<String, Object> getAttributes() {\n        Map<String, Object> attributes = this.attributes;\n        if (attributes == null) {\n            attributes = new HashMap<>();\n            this.attributes = attributes;\n        }\n        return attributes;\n    }\n\n    @Override\n    public InputStream inputStream() {\n        return inputStream;\n    }\n\n    @Override\n    public void setInputStream(InputStream is) {\n        inputStream = is;\n        if (HttpMethods.isPost(method)) {\n            postDecoder = null;\n            postParsed = false;\n        }\n    }\n\n    @Override\n    public String toString() {\n        return \"DefaultHttpRequest{\" + fieldToString() + '}';\n    }\n\n    protected final String fieldToString() {\n        return \"method='\" + method + '\\'' + \", uri='\" + uri + '\\'' + \", contentType='\" + contentType() + '\\'';\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.message;\n\nimport org.apache.dubbo.common.utils.DateUtils;\nimport org.apache.dubbo.common.utils.StringUtils;\nimport org.apache.dubbo.remoting.http12.HttpHeaderNames;\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\nimport org.apache.dubbo.remoting.http12.HttpResult;\nimport org.apache.dubbo.remoting.http12.HttpStatus;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\npublic class DefaultHttpResult<T> implements HttpResult<T> {\n\n    private static final long serialVersionUID = 1L;\n\n    private int status;\n    private Map<String, List<String>> headers;\n    private T body;\n\n    @Override\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    @Override\n    public Map<String, List<String>> getHeaders() {\n        return headers;\n    }\n\n    public void setHeaders(Map<String, List<String>> headers) {\n        this.headers = headers;\n    }\n\n    @Override\n    public T getBody() {\n        return body;\n    }\n\n    public void setBody(T body) {\n        this.body = body;\n    }\n\n    @Override\n    public String toString() {\n        return \"DefaultHttpResult{\" + \"status=\" + status + \", headers=\" + headers + \", body=\" + body + '}';\n    }\n\n    public static final class Builder<T> {\n\n        private int status;\n        private Map<String, List<String>> headers;\n        private T body;\n\n        public Builder<T> status(int status) {\n            this.status = status;\n            return this;\n        }\n\n        public Builder<T> status(HttpStatus status) {\n            this.status = status.getCode();\n            return this;\n        }\n\n        public Builder<T> ok() {\n            return status(HttpStatus.OK.getCode());\n        }\n\n        public Builder<T> moved(String url) {\n            return status(HttpStatus.MOVED_PERMANENTLY).header(HttpHeaderNames.LOCATION.getName(), url);\n        }\n\n        public Builder<T> found(String url) {\n            return status(HttpStatus.FOUND).header(HttpHeaderNames.LOCATION.getName(), url);\n        }\n\n        public Builder<T> error() {\n            return status(HttpStatus.INTERNAL_SERVER_ERROR);\n        }\n\n        public Builder<T> headers(Map<String, List<String>> headers) {\n            if (headers == null || headers.isEmpty()) {\n                return this;\n            }\n            Map<String, List<String>> hrs = this.headers;\n            if (hrs == null) {\n                this.headers = new LinkedHashMap<>(headers);\n            } else {\n                hrs.putAll(headers);\n            }\n            return this;\n        }\n\n        public Builder<T> headers(HttpHeaders headers) {\n            if (headers == null || headers.isEmpty()) {\n                return this;\n            }\n            Map<String, List<String>> hrs = this.headers;\n            if (hrs == null) {\n                this.headers = hrs = new LinkedHashMap<>(headers.size());\n            }\n            for (Entry<CharSequence, String> entry : headers) {\n                CharSequence key = entry.getKey();\n                if (HttpHeaderNames.SET_COOKIE.getKey().equals(key)) {\n                    hrs.computeIfAbsent(key.toString(), k -> new ArrayList<>(1)).add(entry.getValue());\n                } else {\n                    hrs.put(key.toString(), Collections.singletonList(entry.getValue()));\n                }\n            }\n            return this;\n        }\n\n        public Builder<T> header(String key, List<String> values) {\n            headers().put(key, values);\n            return this;\n        }\n\n        public Builder<T> header(String key, String... values) {\n            headers().put(key, Arrays.asList(values));\n            return this;\n        }\n\n        public Builder<T> header(String key, String value) {\n            headers().put(key, Collections.singletonList(value));\n            return this;\n        }\n\n        public Builder<T> headerIf(String key, String value) {\n            return StringUtils.isEmpty(value) ? this : header(key, value);\n        }\n\n        public Builder<T> header(String key, Date value) {\n            return header(key, DateUtils.formatHeader(value));\n        }\n\n        public Builder<T> header(String key, Object value) {\n            return header(key, String.valueOf(value));\n        }\n\n        public Builder<T> headerIf(String key, Object value) {\n            return value == null ? this : header(key, value);\n        }\n\n        public Builder<T> addHeader(String key, String value) {\n            headers().computeIfAbsent(key, k -> new ArrayList<>()).add(value);\n            return this;\n        }\n\n        public Builder<T> contentType(String value) {\n            return headerIf(HttpHeaderNames.CONTENT_TYPE.getName(), value);\n        }\n\n        public Builder<T> from(HttpResult<T> result) {\n            status = result.getStatus();\n            headers = result.getHeaders() == null ? null : new LinkedHashMap<>(result.getHeaders());\n            body = result.getBody();\n            return this;\n        }\n\n        private Map<String, List<String>> headers() {\n            Map<String, List<String>> headers = this.headers;\n            if (headers == null) {\n                this.headers = headers = new LinkedHashMap<>();\n            }\n            return headers;\n        }\n\n        public Builder<T> body(T body) {\n            this.body = body;\n            return this;\n        }\n\n        public DefaultHttpResult<T> build() {\n            DefaultHttpResult<T> result = new DefaultHttpResult<>();\n            result.setStatus(status);\n            result.setHeaders(headers);\n            result.setBody(body);\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpHeadersMapAdapter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.dubbo.remoting.http12.message;\n\nimport org.apache.dubbo.remoting.http12.HttpHeaders;\n\nimport java.util.AbstractCollection;\nimport java.util.AbstractSet;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\npublic final class HttpHeadersMapAdapter implements Map<String, List<String>> {\n\n    private final HttpHeaders headers;\n\n    public HttpHeadersMapAdapter(HttpHeaders headers) {\n        this.headers = headers;\n    }\n\n    @Override\n    public int size() {\n        return headers.size();\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return headers.isEmpty();\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        return key instanceof CharSequence && headers.containsKey((CharSequence) key);\n    }\n\n    @Override\n    public boolean containsValue(Object value) {\n        for (Entry<CharSequence, String> entry : headers) {\n            if (Objects.equals(value, entry.getValue())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public List<String> get(Object key) {\n        return key instanceof CharSequence ? headers.get((CharSequence) key) : Collections.emptyList();\n    }\n\n    @Override\n    public List<String> put(String key, List<String> value) {\n        List<String> all = headers.get(key);\n        headers.set(key, value);\n        return all;\n    }\n\n    @Override\n    public List<String> remove(Object key) {\n        return key instanceof CharSequence ? headers.remove((CharSequence) key) : Collections.emptyList();\n    }\n\n    @Override\n    public void putAll(Map<? extends String, ? extends List<String>> m) {\n        headers.set(m);\n    }\n\n    @Override\n    public void clear() {\n        headers.clear();\n    }\n\n    @Override\n    public Set<String> keySet() {\n        return headers.names();\n    }\n\n    @Override\n    public Collection<List<String>> values() {\n        Set<CharSequence> names = headers.nameSet();\n        return new AbstractCollection<List<String>>() {\n            @Override\n            public Iterator<List<String>> iterator() {\n                Iterator<CharSequence> it = names.iterator();\n                return new Iterator<List<String>>() {\n                    @Override\n                    public boolean hasNext() {\n                        return it.hasNext();\n                    }\n\n                    @Override\n                    public List<String> next() {\n                        CharSequence next = it.next();\n                        return next == null ? Collections.emptyList() : headers.get(next);\n                    }\n                };\n            }\n\n            @Override\n            public int size() {\n                return names.size();\n            }\n        };\n    }\n\n    @Override\n    public Set<Entry<String, List<String>>> entrySet() {\n        Set<CharSequence> names = headers.nameSet();\n        return new AbstractSet<Entry<String, List<String>>>() {\n            @Override\n            public Iterator<Entry<String, List<String>>> iterator() {\n                Iterator<CharSequence> it = names.iterator();\n                return new Iterator<Entry<String, List<String>>>() {\n                    @Override\n                    public boolean hasNext() {\n                        return it.hasNext();\n                    }\n\n                    @Override\n                    public Entry<String, List<String>> next() {\n                        CharSequence next = it.next();\n                        return new Entry<String, List<String>>() {\n                            @Override\n                            public String getKey() {\n                                return next == null ? null : next.toString();\n                            }\n\n                            @Override\n                            public List<String> getValue() {\n                                return next == null ? Collections.emptyList() : get(next);\n                            }\n\n                            @Override\n                            public List<String> setValue(List<String> value) {\n                                if (next == null) {\n                                    return Collections.emptyList();\n                                }\n                                List<String> values = get(next);\n                                headers.set(next, value);\n                                return values;\n                            }\n                        };\n                    }\n                };\n            }\n\n            @Override\n            public int size() {\n                return names.size();\n            }\n        };\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        return obj instanceof HttpHeadersMapAdapter && headers.equals(((HttpHeadersMapAdapter) obj).headers);\n    }\n\n    @Override\n    public int hashCode() {\n        return headers.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return \"HttpHeadersMapAdapter{\" + \"headers=\" + headers + '}';\n    }\n}\n"
  },
  {
    "path": "dubbo-rpc/dubbo-rpc-triple/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter",
    "content": ""
  }
]